Neo Geo Pocket emulation

Discussion of development of software for any "obsolete" computer or video game system. See the WSdev wiki and ObscureDev wiki for more information on certain platforms.
Near
Founder of higan project
Posts: 1553
Joined: Mon Mar 27, 2006 5:23 pm

Neo Geo Pocket emulation

Post by Near »

I'm still trying to create a Neo Geo Pocket emulator; figured I could pool the information here in case anyone else ever wants to try emulating this system.

Current questions:

I can get to this part of the NGPC BIOS:

Code: Select all

	00FF1E8A : 0606          : EI 6
	00FF1E8C : E961          : INC 1,XBC
	00FF1E8E : E9CFFFFF0200  : CP XBC,0x0002FFFF
	00FF1E94 : 6611          : JR Z,0x00FF1EA7			====> Done
	00FF1E96 : F1896FCF      : BIT 7,(0x006F89)
	00FF1E9A : 6EF0          : JR NZ,0x00FF1E8C			===> Loop
	00FF1E9C : F1616C0000    : LD (0x006C61),0x00
	00FF1EA1 : 59            : POP XBC
	00FF1EA2 : 48            : POP WA
	00FF1EA3 : 0607          : DI
	00FF1EA5 : 03            : POP SR
	00FF1EA6 : 0E            : RET

	===>

	00FF1EA7 : F1806F020000  : LDW (0x006F80),0x0000
	00FF1EAD : F1616C0000    : LD (0x006C61),0x00
	00FF1EB2 : 59            : POP XBC
	00FF1EB3 : 48            : POP WA
	00FF1EB4 : 0607          : DI
	00FF1EB6 : 03            : POP SR
	00FF1EB7 : 0E            : RET
My code ends up taking the branch to FF1EA7, whereas MAME returns at FF1E9C.

The BIOS runs in a deadloop polling 6F89.d7, which is an undocumented system RAM variable.

The only interrupt that modifies this variable to bypass this loop is at FFFF70, which is INTAD, or apparently some kind of analog to digital conversion interrupt? What is this interrupt, and what causes it to fire?

...

Reading through MAME, I see how the Z80 can trigger TLCS900H interrupts, but for the TLCS900H to trigger Z80 interrupts, it apparently happens on writes to "porta". What are these ports? The MAME core has ports 1,2,5,6,7,8,9,a,b,c,d,e.

On the topic of the Z80 ... is the port at 0xBC just a single byte that both the TLCS900H and Z80 can read and write to? Or is it more like the SNES where each side gets its own port values? MAME's code makes it look like the former.

Is the shared Z80 RAM truly shared (with some kind of bus conflict handler or access cycle interleaving in place), or is it the case where only one CPU can access it at any given moment? If the latter, it would seem you'd have to stop and restart the CPU in order to share RAM, since the Z80 only has the little 4K RAM block and that's it to execute code out of ...

...

Hblank IRQs are said to share the TIO interrupt, which is timer 0 ... but which interrupt is that from 0xffffxx in the BIOS? Eg Vblank / INT4 is FFFF2C. The APU->CPU interrupt is INT5 / FFFF30.

...

The TMP95C061 manual states that on power-on, the CPU reads the reset vector from FFFF00, but this does not point at FF1800. Yet MAME starts execution at FF1800 anyway (from its debugger), even though tlcs900.c does read from FFFF00. Not sure which is more correct as a result.

...

Still at a total loss as to how micro DMA is supposed to work. For starters, does this DMA run in parallel with the CPU, or does it take precedence over executing CPU instructions (eg blocks the CPU until the DMA transfer has completed.)

...

On the whole, MAME's emulation of the TLCS900H is *terrifyingly* low-level, beyond anything I've seen in a CPU core before. It's filled with around 100+ internal registers that do all kinds of bit-twiddling all over the core.

Are these things documented somewhere? The values like this:

Code: Select all

#define TMP95C061_P7FC        0x17
#define TMP95C061_P8          0x18
#define TMP95C061_P9          0x19
#define TMP95C061_P8CR        0x1a
#define TMP95C061_P8FC        0x1b
#define TMP95C061_PA          0x1e
#define TMP95C061_PB          0x1f
#define TMP95C061_TRUN        0x20
#define TMP95C061_TREG0       0x22
#define TMP95C061_TREG1       0x23
#define TMP95C061_T01MOD      0x24
#define TMP95C061_TFFCR       0x25
#define TMP95C061_TREG2       0x26
#define TMP95C061_TREG3       0x27
#define TMP95C061_T23MOD      0x28
#define TMP95C061_TRDC        0x29
#define TMP95C061_PACR        0x2c
#define TMP95C061_PAFC 0x2d
They seem to be related to the CPU memory map addresses 00-7f.

You end up with code like this:

Code: Select all

m_reg[TMP95C061_PACR] = 0x0c; // HACK ngpc needs this but should be zero
m_reg[TMP95C061_PAFC] = 0x0c; // HACK ngpc needs this but should be zero

void tmp95c061_device::update_porta()
{
	int fc = (m_to1 << 2) | (m_to3 << 3);

	m_porta_write(0, ((fc & m_reg[TMP95C061_PAFC]) | (m_reg[TMP95C061_PA] & ~m_reg[TMP95C061_PAFC])) & m_reg[TMP95C061_PACR], 0xff);
}
And ... oh boy >_>
JamesHall7
Posts: 4
Joined: Sat Mar 09, 2019 1:54 am

Re: Neo Geo Pocket emulation

Post by JamesHall7 »

byuu wrote:It's filled with around 100+ internal registers that do all kinds of bit-twiddling all over the core. Are these things documented somewhere?
When going through datasheets for the TLCS900H, I found that the addresses of the CPU's internal registers were inconsistent between different datasheets. (I can't recall if the names or bits were also different in some cases.)
A datasheet that seemed to match MAME can be found at http://pdf.datasheetcatalog.com/datashe ... 1434_1.pdf
byuu wrote:The only interrupt that modifies this variable to bypass this loop is at FFFF70, which is INTAD, or apparently some kind of analog to digital conversion interrupt? What is this interrupt, and what causes it to fire?
Information about the A/D converter is on page 148 of the PDF I linked above. I think it can fire either 160 or 320 states (adjustable by bit 3 of 0x6D) after A/D conversion is started (by setting bit 2 of 0x6D).
The SNK "SYSTEM PROGRAM REFERENCE MANUAL" states that an A/D channel is used for power management. The battery voltage is available at 0x6F80, and it appears that this is what it is sampling:

Code: Select all

FF2DDC : D06020           : ld WA,(0x60)		;0x60 ADREG0L - "AD Result Reg 0 low" (0x61 is ADREG0H - "AD Result Reg 0 high")
FF2DDF : D8EF06           : srl 0x06,WA
FF2DE2 : F1806F50         : ld (0x6F80),WA
byuu wrote:The TMP95C061 manual states that on power-on, the CPU reads the reset vector from FFFF00, but this does not point at FF1800. Yet MAME starts execution at FF1800 anyway (from its debugger), even though tlcs900.c does read from FFFF00. Not sure which is more correct as a result.
When starting the NGPC in MAME for the first time (or without the NVRAM file), it will use the reset vector. Once there is an NVRAM file, MAME will ignore the vector and start execution at FF1800 (see ngp_state::machine_reset()).

When MAME starts without the NVRAM file, nothing gets displayed and the CPU ends up in a deadloop at 0xFF1128 (I don't know why 0xFF1128 is shown executing here):

Code: Select all

FF110D: ld XSP,0x00006c00
FF1112: ei 0x05
FF1114: set 2,(0xb3)
FF1117: ld (0x6c7a),0xa5a5
FF111D: ld (0x6e95),0x4e50
FF1123: ld (0xb4),0x00a0
FF1127: halt
FF1128: res 7,(0x6f86)
FF1128: res 7,(0x6f86)
I imagine that setting the PC to 0xFF1800 is a hack to get around this.
byuu wrote:Hblank IRQs are said to share the TIO interrupt, which is timer 0 ... but which interrupt is that from 0xffffxx in the BIOS? Eg Vblank / INT4 is FFFF2C. The APU->CPU interrupt is INT5 / FFFF30.
Timer 0 is at 0xFFFF40.
In case it is handy to have... (interrupt sources gleaned from MAME)

Code: Select all

NGPC
	handlerAddress	vectorAddress	irq
	FF204A			FFFF00			Reset or [SWI0] instruction
	FF2772			FFFF04			[SW1] instruction
	FF2305			FFFF08			Illegal or [SW2] instruction
	FF2202			FFFF0C			[SW3] instruction
	FF220B			FFFF10			[SW4] instruction
	FF2214			FFFF14			[SW5] instruction
	FF221D			FFFF18			[SW6] instruction
	FF2226			FFFF1C			[SW7] instruction
	FF1898			FFFF20			NMI    : /NMI Pin (Power Button)
	FF2D98			FFFF24			INTWD  : Watchdog timer
	FF2856			FFFF28			INT0   : INT0 Pin (Alarm/RTC)
	FF2163			FFFF2C			INT4   : INT4 Pin (VBlank)
	FF2282			FFFF30			INT5   : INT5 Pin (Z80)
	FF2B25			FFFF34			INT6   : INT6 Pin
	FF2DB6			FFFF38			INT7   : INT7 Pin
	FF22A4			FFFF3C			(Reserved)
	FF22A5			FFFF40			INTT0  : 8-bit Timer 0 (HBlank)
	FF22AE			FFFF44			INTT1  : 8-bit Timer 1
	FF22B7			FFFF48			INTT2  : 8-bit Timer 2
	FF22C0			FFFF4C			INTT3  : 8-bit Timer 3
	FF22C9			FFFF50			INTTR4 : 16-bit Timer 4 (TREG4)
	FF22CA			FFFF54			INTTR5 : 16-bit Timer 4 (TREG5)
	FF22CB			FFFF58			INTTR6 : 16-bit Timer 5 (TREG6)
	FF22CC			FFFF5C			INTTR7 : 16-bit Timer 5 (TREG7)
	FF22CD			FFFF60			INTRX0 : Serial RX (Channel 0) (Serial RX)
	FF22D6			FFFF64			INTTX0 : Serial TX (Channel 0) (Serial TX)
	FF22DF			FFFF68			INTRX1 : Serial RX (Channel 1)
	FF22E0			FFFF6C			INTTX1 : Serial TX (Channel 1)
	FF2DCE			FFFF70			INTAD  : A/D Conversion End
	FF22E1			FFFF74			INTTC0 : Micro DMA End (Ch. 0)
	FF22EA			FFFF78			INTTC1 : Micro DMA End (Ch. 1)
	FF22F3			FFFF7C			INTTC2 : Micro DMA End (Ch. 2)
	FF22FC			FFFF80			INTTC3 : Micro DMA End (Ch. 3)

NGP
	handlerAddress	vectorAddress	irq
	FF1DE8			FFFF00			Reset or [SWI0] instruction
	FF2426			FFFF04			[SW1] instruction
	FF200F			FFFF08			Illegal or [SW2] instruction
	FF1F31			FFFF0C			[SW3] instruction
	FF1F3A			FFFF10			[SW4] instruction
	FF1F43			FFFF14			[SW5] instruction
	FF1F4C			FFFF18			[SW6] instruction
	FF1F55			FFFF1C			[SW7] instruction
	FF1898			FFFF20			NMI    : /NMI Pin (Power Button)
	FF29BE			FFFF24			INTWD  : Watchdog timer
	FF24E3			FFFF28			INT0   : INT0 Pin (Alarm/RTC)
	FF1E92			FFFF2C			INT4   : INT4 Pin (VBlank)
	FF1F8C			FFFF30			INT5   : INT5 Pin (Z80)
	FF274B			FFFF34			INT6   : INT6 Pin
	FF29D7			FFFF38			INT7   : INT7 Pin
	FF1FAE			FFFF3C			(Reserved)
	FF1FAF			FFFF40			INTT0  : 8-bit Timer 0 (HBlank)
	FF1FB8			FFFF44			INTT1  : 8-bit Timer 1
	FF1FC1			FFFF48			INTT2  : 8-bit Timer 2
	FF1FCA			FFFF4C			INTT3  : 8-bit Timer 3
	FF1FD3			FFFF50			INTTR4 : 16-bit Timer 4 (TREG4)
	FF1FD4			FFFF54			INTTR5 : 16-bit Timer 4 (TREG5)
	FF1FD5			FFFF58			INTTR6 : 16-bit Timer 5 (TREG6)
	FF1FD6			FFFF5C			INTTR7 : 16-bit Timer 5 (TREG7)
	FF1FD7			FFFF60			INTRX0 : Serial RX (Channel 0) (Serial RX)
	FF1FE0			FFFF64			INTTX0 : Serial TX (Channel 0) (Serial TX)
	FF1FE9			FFFF68			INTRX1 : Serial RX (Channel 1)
	FF1FEA			FFFF6C			INTTX1 : Serial TX (Channel 1)
	FF29EF			FFFF70			INTAD  : A/D Conversion End
	FF1FEB			FFFF74			INTTC0 : Micro DMA End (Ch. 0)
	FF1FF4			FFFF78			INTTC1 : Micro DMA End (Ch. 1)
	FF1FFD			FFFF7C			INTTC2 : Micro DMA End (Ch. 2)
	FF2006			FFFF80			INTTC3 : Micro DMA End (Ch. 3)
[/size]
Near
Founder of higan project
Posts: 1553
Joined: Mon Mar 27, 2006 5:23 pm

Re: Neo Geo Pocket emulation

Post by Near »

Oh wow, thank you so much! This helps a ton.
I found that the addresses of the CPU's internal registers were inconsistent between different datasheets. (I can't recall if the names or bits were also different in some cases.)
Yeah, these appear to be little SoC-like devices. MAME tries to support both the TMP95C061 (NGP/C) and TMP95C063 (Taito Type-Zero), but I'm guessing the latter is only barely supported since it's just an I/O controller. Probably the best real way to emulate the TLCS900(/H,/H2) is to have a each model inherit from a base TLCS900 class. Emulating MIN mode is probably not worth it since no game systems use it.
When starting the NGPC in MAME for the first time (or without the NVRAM file), it will use the reset vector. Once there is an NVRAM file, MAME will ignore the vector and start execution at FF1800 (see ngp_state::machine_reset()).

When MAME starts without the NVRAM file, nothing gets displayed and the CPU ends up in a deadloop at 0xFF1128 (I don't know why 0xFF1128 is shown executing here):
Ah, I thought MAME wasn't working at first because all I got was a solid white screen on first run. How peculiar. It feels like MAME should force FF1800 then, or if (FFFF00) does some critical setup, then there's a bug there that it won't reach FF1800.

On my real NGPC, the CR2032 is dead, and so when I put in batteries and run it, it goes right into the setup screen like you get when MAME runs from FF1800.
Timer 0 is at 0xFFFF40.
Ah, thank you. So Hblank IRQs share the same (FFFF40) vector as timer 0 (TIO), then? Seems a strangely conservative choice given the obscene number of IRQs this chip has available.
JamesHall7
Posts: 4
Joined: Sat Mar 09, 2019 1:54 am

Re: Neo Geo Pocket emulation

Post by JamesHall7 »

You're welcome! I'm glad that it was helpful.
byuu wrote:So Hblank IRQs share the same (FFFF40) vector as timer 0 (TIO), then? Seems a strangely conservative choice given the obscene number of IRQs this chip has available.
If you have the SNK "8 BIT TIMER REFERENCE MANUAL", they give an example at the end of how to set up the timer for usage as an Hblank IRQ.
What they do is set timer 0 to use an external clock (which happens to be the Hblank interrupt from the graphic controller), then set the counter to the desired number of lines between each interrupt. Timer 0 is the only timer that can use an external clock.
JamesHall7
Posts: 4
Joined: Sat Mar 09, 2019 1:54 am

Re: Neo Geo Pocket emulation

Post by JamesHall7 »

JamesHall7 wrote:When MAME starts without the NVRAM file, nothing gets displayed and the CPU ends up in a deadloop at 0xFF1128
It just dawned on me why the deadloop at 0xFF1128 occurs: When the NGPC is off, the CPU seems to park there while waiting for the NMI from the power button.
Pressing the power button in MAME will make it toggle between regular operation and staying in that loop.
(also, I get a strong feeling that MAME is showing inaccurate information here -- it would make far more sense to me if it was stopped at 0xFF1127 (halt))
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Neo Geo Pocket emulation

Post by tepples »

If the program counter is already incremented after fetching the halt, the CPU will halt with PC pointed at the next instruction to execute.
Near
Founder of higan project
Posts: 1553
Joined: Mon Mar 27, 2006 5:23 pm

Re: Neo Geo Pocket emulation

Post by Near »

I got the NGP and NGPC BIOSes running. I'm ignoring sprite priorities, Hblank interrupts, timers, micro/H DMA, ports, interrupt internal register settings, CPU instruction timings, the RTC, etc, but ... oh well.

It currently hangs at the last BIOS screen, the logo keeps fading in and out. Wish I knew what was causing that ... if I can get in-game, then I can start running through Hidden Asbestos' test ROMs.

I'm still just floored that I've gotten this far with only one CPU bug so far.

...

There's some real craziness right now with sprite coordinates needing to be offset by 7 ... I must be doing something wrong.
spritePos-screenPos should get me a value from 0-7 when in range, but it seems to be backward and so I have to invert the tile flipping logic as well.

Code: Select all

auto VPU::renderSprite() -> maybe<uint12> {
  maybe<Sprite&> p;
  for(auto& s : sprites) {
    s.x = s.hoffset;
    s.y = s.voffset;
    if(s.hchain && p) s.x += p->x;
    if(s.vchain && p) s.y += p->y;
    p = s;

    uint8 x = 7 + s.x + sprite.hscroll - io.hcounter;  //hcounter = 0-159
    if(x >= 8) continue;  //out of range?
    uint8 y = 7 + s.y + sprite.vscroll - io.vcounter;  //vcounter = 0-151
    if(y >= 8) continue;  //out of range?

    if(s.hflip == 1) x ^= 7;
    if(s.vflip == 0) y ^= 7;
It just dawned on me why the deadloop at 0xFF1128 occurs: When the NGPC is off, the CPU seems to park there while waiting for the NMI from the power button.
Yeah. It sets (0xb3).d2 which seems to need INT0/NMI to fire (it's the only interrupt that's been configured), and then it polls the battery level and power button repeatedly.

The Neo Geo Pocket breaks even my newer, more extreme tree-based emulation core design by being a system that's technically always on, but just idling. My GUI expects to have a toggle to power the system on and off, not a button that triggers an NMI. I don't yet know how I'm going to handle this one. I would prefer the system to not be running before you power on the system in the menu.

Also, there are a ton of registers in the 0x80-0xff space that are being written to, but not emulated at all in MAME. Fun. I get it, they're all undocumented.
Last edited by Near on Thu Apr 08, 2021 3:32 am, edited 1 time in total.
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Neo Geo Pocket emulation

Post by tepples »

Off: make a save state and halt emulation
On: restore the save state and fire an NMI
TascoDLX
Posts: 1
Joined: Sat Mar 09, 2019 1:12 pm

Re: Neo Geo Pocket emulation

Post by TascoDLX »

FYI, 0xFF1800 is the prescribed point of entry when using SNK's dev tools (the debugger):

Image

Also, if you're not already aware, you may want to check out this book:

http://bitsavers.trailing-edge.com/comp ... roller.pdf

Despite it being for the TLCS-900 (not the 900/H), it's very comprehensive in its coverage of the 900 series' register set and functionality. An equivalent data book for the 900/H should exist, but I wasn't able to find it in my admittedly brief search.
Near
Founder of higan project
Posts: 1553
Joined: Mon Mar 27, 2006 5:23 pm

Re: Neo Geo Pocket emulation

Post by Near »

I have some games running now, but most games hang right away, and only DAC sound works.

I'm currently missing: proper TLCS900H instruction timings, micro DMA, internal I/O ports, serial communication, and some undocumented registers between 0x80 and 0xff.

The Z80 gets far enough to run instructions and do a few initializing writes to the PSG, but then nothing. It's either the missing micro DMA, or my timers are broken, or the interrupt mechanism between the CPU and Z80 cores is broken.

The timers on this system ... oh my god. Of the ~20ish systems I emulate, nothing even comes remotely close to this level of complexity. Not even a little. Four 8-bit ports that can be lined into sets of two. Or you can use programmable pulse generation mode, or pulse width modulation mode (which has its own frequency setting, and a value of 0 is undocumented.) You can clock them off of a prescaler against the main oscillator (which you can disable) at various frequencies, or off of an external pin (hblank for this system). The timer firing goes through flip-flops (which you can drive manually or choose which timers can toggle them) which can drive timer out pins that are multiplexed with interrupt and port lines. There's a double-buffering system to reload comparators on PPG/PWM events. So you can use this to acknowledge Z80 interrupts, for example.

Then there's two more 16-bit counters, this time with one pin taking in vblank. These timers work completely differently. There's two comparators and two capture registers for each timer. You can set the counters to clear on a comparator match or not. You can configure whether INT4 fires on rising or falling edges of INT1/INT6 input (which is multiplexed with TI4/TI6.) There's a manual counter capture method. Both timers have a very configurable flip-flop that can optionally trigger on either/both comparator matches or when the counters are latched into either/both of the capture registers. They both have double-buffering as well. You can end up implementing all of the functionality (PPG, PWM) of the 8-bit counters through these anyway, but in completely different ways. Plus you can implement event counters, one-shot timers, frequency measurements, pulse width measurements, time difference measurements, etc. Then finally there's PG0T/PG1T, that selects "shift triggers" based on timers 0/1 or 4 (PG0) or timers 2/3 or 5 (PG1), and a mystery T45CR.d7 bit that even this elaborate 200-page manual just says "always write zero, and it always reads as zero." so ... who knows what happens if you write 1 there.

PG0T/PG1T powers a stepping motor control / pattern generator that outputs to port 7. I haven't implemented this yet, but with gems in the manual like, (circuit diagram) "Figure 3.10 (8). Output Waveforms of 4-Phase 1-Step Excitation (Normal Rotation and Reverse Rotation)", I know I'm in for a really good time.

As for the FF1800 thing: it's basically the case that you don't turn this system off. It starts at (FFFF00) and soon goes into HALT state. The only thing that wakes it up from there is pressing down the power button to trigger an NMI. Since it's /NMI, the value in the I/O port and the NMI line value seem to be inverted. MAME's code doesn't show this is the case, but things just don't work at all if the I/O port treats the power button being pressed as 1 like the other buttons. Once the NMI fires, the system boots up. To turn the system off, you have to hold the power button for a few seconds. The last problem I'm having is that, when I set the sub-battery failure bit, it shows the warning only for a brief second and then turns the system off anyway. On my real NGPC, you have to press another button to acknowledge it, so as always, more research needed there.

An important BIOS discovery for any future emudevs: it reads back the K1GE palette colors (0x8103, etc) and doesn't mask the unmapped bits. The manual doesn't specify what those return, and being used to floating high systems, I returned 1s. This was wrong and needs to be 0s. I don't know if the general case should be 1s or 0s, but at least for these registers, d3-d7=0.

Well, I guess people who implement I/O registers as RAM blocks will neatly avoid the issue, but then there are a lot of write-only bits that always read back 1s per the dev manuals.
Shonumi
Posts: 342
Joined: Sun Jan 26, 2014 9:31 am

Re: Neo Geo Pocket emulation

Post by Shonumi »

Just stopping by to say it's great that you're taking a serious swing at the NGP. It's about time someone took a closer, finer look at how this handheld works. I looked into it late last year out of boredom, and I share the sentiments about system complexity. Your progress looks awesome so far, so keep it up!

I did have a question for you, byuu. Any interest in emulating some of the additional hardware for the NGP? Of particular note would be the Wireless Communication Unit. It looks quite exotic, but I'm guessing it boils down to simply transmitting the correct bytes back to the game via the link port, so nothing too extreme (once you understand how the Wireless Communication Unit works, of course). General emulation of the link port and link cable would be outstanding as well, as no current NGP emulator seems to support multiplayer. If I recall correctly, however, that you're not too keen on network programming, right? So not pursuing netplay is completely understandable. I'm pretty sure the Setsuzoku Cable (NGP-to-Dreamcast Cable) is probably too much to hope for at this time, since it sounds like a lot of work (needing at least 1 or 2 people pretty familiar with NGP and/or DC emulation and willing to bridge together two emulators), but I'll mention it anyway. You know, just in case, maybe one day... :wink:

Even if you don't implement any of the above or even dream about touching them, it'd still be immensely helpful to have solid NGP emulation in Higan, should anyone want to tackle those devices on their own. I'll admit, the only reason I took an interest in the NGP was to gauge how feasible emulating its obscure hardware would be. Making sure weird and otherwise forgotten gaming hardware is preserved through emulation has become a bit of an obsession of mine, and it's already spreading beyond the Game Boy.

Anyway, good luck!
Near
Founder of higan project
Posts: 1553
Joined: Mon Mar 27, 2006 5:23 pm

Re: Neo Geo Pocket emulation

Post by Near »

Audio works. The callbacks trigger Z80 IRQs. There is also a separate Z80 NMI trigger, of course. But mostly IRQs are used.

I implemented the RTC, and it works, and yet ... as soon as the "set time and date" BIOS screen appears, it seems to auto-activate the default January 1st, 1999 00:00 time. I'm suspecting it's not an RTC nor an input bug, but possibly a CPU bug.

Lots of games were hanging because I missed the register fetch for ld to and from control registers, whoops.

I am now saving the CPU RAM to disk and loading it on startup, but it still goes into the BIOS setup every single time. Not sure what's wrong. MAME has the same problem, and nothing else emulates the BIOS at all.

I added ports 1, 2, A, and B. Although ports 1 (d8-d15) and 2 (a16-a23) are ... strange. They're likely emulated very wrong. I don't even understand how one can change the direction of the data bus. I'm ... suspecting that ports have their own latch values, but the manual isn't very clear on this. Also not sure how I'm going to implement most ports, like the analog input port pins into the ADC. But I can at least stop ADC from working if you reverse the port direction like it would on real hardware.

I implemented the memory and bus chip select components and their associated waitstates. This one's kind of cool. We say 200000-3fffff is cartridge flash chip 1, and 800000-9fffff is cartridge flash chip 2. But in actuality, you can configure them to appear anywhere you want on the bus, and be any size you want (well, sort of ... it's like x86 MTRR in a way.) There's also two other chip selects that aren't used by the NGPC. Then there's wait state timing for "external chip selects", which is anything not matched by /CS0-3 but ... it is unclear to me what happens when it's an internal access, eg CPU RAM, APU RAM, VRAM, I/O registers, BIOS reads, etc. If that *doesn't* use external chip select wait states, then ... what does? Unmapped addresses?

Still lots more to do.

> It's about time someone took a closer, finer look at how this handheld works.

Much appreciated. I confess I knew nothing about it before. When I saw the TLCS900/H in the past, I nope'd strongly out of it.

I'd been told MAME had really faithful emulation of it, but in actuality most games don't run at all. It was the only one that could run the BIOS, and the only one to really attempt to have a go at the internal SoC registers, but it's extremely incomplete.

Of all the systems I've emulated, this one is by far the least well emulated to date. Nothing else even comes close.

> Any interest in emulating some of the additional hardware for the NGP?

I'm always up for emulating anything and everything possible. I adore all your work on strange peripherals.

The problem is just my limited time and too many systems.

Just offering ... if you ever feel like you want to work on peripherals, but don't want to dive into the absolute insanity that is the NGPC CPU core, I'd fully welcome you to work with me on emulating this system ^-^

> Wireless Communication Unit

"Dousing" to scan radio frequencies to give you cards ... wow. Not quite fish sonar, but ... move over, Soul Dollz and Barcode Battler. Sounds cool!

> General emulation of the link port and link cable would be outstanding as well, as no current NGP emulator seems to support multiplayer.

That is currently missing from every handheld system in higan (and the SGB2.)

I'm very open to it, but I'm not sure how to go about writing the IPC necessary. higan's cores can't be instantiated, so you can't have two instances in the same process. Plus, ideally we'd want to allow it to work over LAN anyway (I understand over the internet is impractical due to them expecting super fast responses.)

I don't know that I have the time to do it, but if anyone were interested, I'd wholly welcome teaming up with them to make this happen.

> I'm pretty sure the Setsuzoku Cable (NGP-to-Dreamcast Cable) is probably too much to hope for at this time

I always wanted to be able to link up with Dolphin for GBA emulation, but my GBA core is just too slow I guess.

NGP<>Dreamcast is similarly a really cool idea. Are there ... active open source Dreamcast emulators, currently? I don't keep up with the more modern gen emulators.

It would be really fun to devise some kind of inter-community standard for all emulators to talk to other emulators for things like GBA<>GC and NGP<>DC, and perhaps even GB<>GB. How cool would it be to link higan and mGBA together?

> it'd still be immensely helpful to have solid NGP emulation in Higan

The main issue right now is my NGP core is rather demanding, about on par with the SNES accuracy core, because of the ridiculous ADC and 26-interrupts that are nested and have priorities. And the lack of clear CPU timings so the MIPS rating is probably 4-8x higher than it should be. And of course, like all my stuff, it has a pixel-based renderer.

I've always been willing to put more care into non-SNES cores, it just never worked out that way. I really thought with the WonderSwan I might get there, but my WS efforts have been pretty much ignored by the world. If NGP support ends up being popular with people like my SNES support is, I'd be willing to add in a scanline video renderer, and to break it out to a standalone GUI ala bsnes (so I guess, calling dibs on bngp now?)

> Making sure weird and otherwise forgotten gaming hardware is preserved through emulation has become a bit of an obsession of mine

You're an absolute hero for that. Thank you so much for your efforts!
Shonumi
Posts: 342
Joined: Sun Jan 26, 2014 9:31 am

Re: Neo Geo Pocket emulation

Post by Shonumi »

I'd definitely want to help Higan emulate those peripherals. That would probably have to be one of those "eventually" kinda plans. I just have so much on my plate right now and in the short-term future, but the NGP has really caught my eye. When I saw a video of the Wireless Communication Unit in action, I just couldn't get it out of my head. Working with an existing emulator would the best path forward (least resistance), so I'm all for teaming up once the time comes. I believe you once said that getting emudevs together was like 'herding cats', and endrift recently said something to the effect that we all basically work in "silos", so it may be time to break that cycle (at least, I'm guilty of doing it myself).

Thanks for the kind words as well! I'll be watching what happens from here on out. You've already posted a lot of interesting development notes, which have been fascinating to read so far. Like I said, keep it up, this is great work!
Near
Founder of higan project
Posts: 1553
Joined: Mon Mar 27, 2006 5:23 pm

Re: Neo Geo Pocket emulation

Post by Near »

> it may be time to break that cycle (at least, I'm guilty of doing it myself)

Myself as well.

The temptation is really high to be in control of decisions, and for these older systems it's very possible for one person to implement the entire systems alone. It's also a great learning experience, and really rewarding.

But when groups are required to do things, you can watch the progress of Dolphin, Yuzu, Citra, RPCS3, etc and just kind of feel in awe as to the amount of great work they are doing. It makes me envious to imagine the kinds of 2D emulators we could have if we all worked together like that.

While emulating an entire 2D system alone is practical for one person, emulating every mapper variant, every obscure peripheral, every coprocessor, every new test ROM gitch, etc ... is not. Then throw on needing to have a good solid GUI on every major OS, to have a great understanding of multipass pixel shaders, audio filtering and DRC, etc. That can easily take ten years to do. There's a few people like us so the NES, SNES, Game Boy gets done. But there's just not nearly enough of us for systems like the PC Engine, Neo Geo Pocket, WonderSwan, and Virtual Boy.

In my own case, I've always had great difficulty working in teams and not getting my way on things. It's a habit I am going to try my best to work on. I think if I ever work on a 3D system, it will be as part of a team. Presuming anyone would have me, hahah ^^;
Near
Founder of higan project
Posts: 1553
Joined: Mon Mar 27, 2006 5:23 pm

Re: Neo Geo Pocket emulation

Post by Near »

If (0x6c14)=0xdd, (0x6c15)=0x00, then the NGP(C) BIOSes boot without going through the setup procedures again.
They're 0xff,0xff normally with MAME and higan.

I actually found this by a fluke. I think what has to happen is you have to power off the system with the system button to trigger the NMI in order to actually write out that the setup completed? Not entirely sure yet.

Still having issues with turning the system back on after having turned it off, it doesn't seem to want to boot correctly again after that.

Not being able to set the BIOS RTC time was due to a bug in ZCF. It's not CF=ZF, it's CF=!ZF.

The ports on this CPU are truly insane. You can literally force certain address/data bus lines to certain values on a bit-by-bit basis if you want. Every single port is for a totally different, totally insane to emulate function.

The BIOS seems to read and write (0xb4) and (0xb5) internal registers, but I've no idea what they are since they're not documented.

...

Non-bump edit:

I implemented all instruction cycle timings, along with all penalties for the ALU shifter, memory addressing modes, interrupts, and HDMA. Also improved an issue that was preventing INTTCx from firing repeatedly. That gets http://jiggawatt.org/badc0de/nymp.html running, but unfortunately the audio runs about twice as fast as it should. The pitch is correct though, so anything easy like halving the interrupt firing rate or somesuch will throw off the pitch. Not sure what's going on here, and I can't really get a trace log of this running somewhere else to compare it to. Shoot.

...

Another non-bump edit:

Fixed a major CPU bug in "ld xix,(xix+)". It loads (xix), then increments xix, then stores the loaded value into xix. Pretty standard, just missed it before. That fixes corrupt graphics in Card Fighters.

Also, it turns out incw #3,r and incl #3,r will not update flags, but incw #3,(mem) will. What the hell. That fixes input in Sonic Pocket Adventure and Rockman Battle Fighters.

The sound chip in the Neo Geo Pocket is quite weird. Turns out only the volume registers are unique, and the tone/noise pitch/control registers are unique. They took the time to decouple the sharing of tone 2 pitch and noise period as well, cool. Supposedly it's a 15-bit LFSR with taps on d0 and d2, although that's apparently not 100% right either. Doesn't seem anyone knows exactly how it works. I'm not even sure how anyone was able to analyze it since the registers are write-only, and there's no digital audio output.

There's a few serious bugs here and there still, but overall things are progressing quite nicely now. I did implement the two 16-bit timers because they tie into Vblank interrupts and the BIOS configures them as such, but I don't know if I want to attempt to support the stepping motor, DRAM refresh, or using ports as outputs to control things like chip select, address/data bus bits. The serial interface is definitely not happening until I figure out how to do linking between multiple higan instances.

I couldn't find any games that use the "D" button (from the SNK manual), so I unmapped binding it as an input for now, since having it would mean that "Option" would have to be named either "C" or "C/Option", both of which are super ugly.

Nymp still doesn't sound nice. I have a feeling that it's not synchronizing the DAC value generation and the NGPC audio playback, and is instead cycle timing things perfectly. If that's the case, then being off at all would result in the two desyncing and the CPU code overwriting DAC samples before they are played. So short of some heroic third-party assistance, it looks like this one's going to sadly remain out of reach for now.
Post Reply