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
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
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);
}