Z80 bus + I/O mapping redux

Ask anything your want about Megadrive/Genesis programming.

Moderator: BigEvilCorporation

Post Reply
byuu
Very interested
Posts: 94
Joined: Thu Feb 28, 2008 4:45 pm

Z80 bus + I/O mapping redux

Post by byuu » Fri Apr 26, 2019 1:42 pm

Found conflicting information, wanted to clarify what's current and ask some more.

References:
* viewtopic.php?t=347
* http://www.sega-16.com/forum/showthread ... ng-Sega-CD
* http://www.tmeeco.eu/BitShit/CMDHW.TXT

bgvanbur states the Z80 can write to 68K main-CPU RAM (e00000-ffffff), but reads return 0xff.
It's further comments that reads return different values on different systems.

Stef finds that writes do not work. Steve Snake says they used to on the earliest models.
I wonder Stef tested this by reading back what the Z80 wrote from the 68K. If not, that'd explain why writes appeared to fail.
But it's still pathological why writes would succeed, but reads would fail.

Even more surprising is that a100xx accesses seem to work, as long as the Z80 acquires the bus first.
You probably see where I'm going, but then ... what happens if the Z80 accesses a0xxxx (eg the Z80 region)?
Thankfully from the CPU perspective, a08000-a0ffff mirrors a00000-a07fff, otherwise you could create an infinite loop in emulators.
But I wonder if that would really work? Can the Z80 read from $8000, with the bank select set so it reads from the 68K $a00000, which would then read from the Z80 $0000, which would then return Z80 RAM?

While I'm on this topic ... does anyone have non-conflicting answers for the axxxxx region? Currently, I have:
* a00000-a0ffff => [8-bit bus] Z80 (A15 is ignored)
* a10000-a10fff => [8-bit bus] Peripherals (A8-A15 is ignored)
** a10002,a10004,a10006 => (controller 1, controller 2, extension) port data
** a10008,a1000a,a1000c => (controller 1, controller 2, extension) port control
* a11000-a11fff => [8-bit bus] Z80 enable/disable (A0-A7 is ignored)
** a11100 => APU request
** a11200 => APU enable
* a12000-a12fff => [bus size depends on the hardware, 8-bit for Sega CD] Expansion port (Sega CD)
* a13000-a13fff => [bus size depends on the hardware, 8-bit for all cartridges I know of] Cartridge (mappers usually)
* c00000-dfffff => [16-bit bus] VDP (when A4=0) + [8-bit bus] PSG (when A4=1)
** if any bits in A5-A7 or A16-A18 are set, the machine deadlocks
** A8-A15 are ignored (mirrors)
** reading with A4 set (PSG) deadlocks the machine
** writing to the VDP counters deadlocks the machine
* a14000-a14fff => [8-bit bus] TMSS
** a14000 and a14002 enable the VDP by writing 'SEGA' to them
** a14100.d0=1 disables TMSS and enables the ROM

Sometimes I read that a10000-a10fff (12-bit range) is really just a10000-a100ff (8-bit range.) Might these blocks go further and fill in bxxxxx as well?

Charles MacDonald went into lots of detail on even-byte, odd-byte, word reads/writes to the c00000-dfffff region. But what about the a00000-bfffff region? Say a game writes a byte to a10003, D0-D7 goes to controller port 1 data, great. But if a game writes to byte to a10002, what happens? The 68K used in the Genesis per 68000UM.pdf states that D8-D15=D0-D7 for byte writes, and that A0 isn't used. Do the I/O ports bother to check /LDS and ignore even byte writes? Or do they just silently go through? What about word writes? I presume those will work fine and pass through D0-D7.

And the really big question ... how exactly do unaligned 16-bit accesses work? I'm told it throws a bus error exception. But how does that work on a bus access? If you're in the middle of executing an instruction, does it just abort the whole instruction instantly and jump the PC to the exception vector address? If not, then does the bus just return bad data until the instruction completes, and then it throws the exception?

Mask of Destiny
Very interested
Posts: 591
Joined: Thu Nov 30, 2006 6:30 am

Re: Z80 bus + I/O mapping redux

Post by Mask of Destiny » Fri Apr 26, 2019 3:18 pm

byuu wrote:
Fri Apr 26, 2019 1:42 pm
bgvanbur states the Z80 can write to 68K main-CPU RAM (e00000-ffffff), but reads return 0xff.
It's further comments that reads return different values on different systems.

Stef finds that writes do not work. Steve Snake says they used to on the earliest models.
For what it's worth, I have a test ROM that checks whether Z80 reads and writes work and as best I can remember, there were no surprises when I tested it on different machines. In other words, writes always worked and reads always failed. I seem to remember someone (TmEE maybe) figured out the reason why reads don't work and IIRC it was something that was easily correctable.
byuu wrote:
Fri Apr 26, 2019 1:42 pm
Even more surprising is that a100xx accesses seem to work, as long as the Z80 acquires the bus first.
You probably see where I'm going, but then ... what happens if the Z80 accesses a0xxxx (eg the Z80 region)?
I was under the impression that Z80 access to the IO region (both actual IO ports and bank access) did not work at all, though I don't remember the way in which it fails.

Need to head off to work now. I'll follow up on the rest of this and post my test ROM either after work tonight or this weekend.

Stef
Very interested
Posts: 2994
Joined: Thu Nov 30, 2006 9:46 pm
Location: France - Sevres
Contact:

Re: Z80 bus + I/O mapping redux

Post by Stef » Fri Apr 26, 2019 7:55 pm

Oh that is really old information, i completely forgot about this topic ^^ i don't know how i tested that back in time but i does confirm today that Z80 writes to 68K RAM indeed work (i wrote it somewhere else later probably then) but not read.
As Mask of Destiny i always though Z80/IO regions (afaik A0xxxx / A1xxxx) access from Z80 would result in lockup of the system. I don't think a single game rely on that...

Sik
Very interested
Posts: 901
Joined: Thu Apr 10, 2008 3:03 pm
Contact:

Re: Z80 bus + I/O mapping redux

Post by Sik » Sat Apr 27, 2019 3:34 am

byuu wrote:
Fri Apr 26, 2019 1:42 pm
Sometimes I read that a10000-a10fff (12-bit range) is really just a10000-a100ff (8-bit range.) Might these blocks go further and fill in bxxxxx as well?
It doesn't, $B00000-$BFFFFF hang up the bus access (unless the cartridge itself decides to assert /DTACK to let it proceed).
Sik is pronounced as "seek", not as "sick".

Eke
Very interested
Posts: 856
Joined: Wed Feb 28, 2007 2:57 pm
Contact:

Re: Z80 bus + I/O mapping redux

Post by Eke » Sat Apr 27, 2019 6:42 am

That's a lot of questions and they adress so many different things... I guess I will pick this one
But if a game writes to byte to a10002, what happens? The 68K used in the Genesis per 68000UM.pdf states that D8-D15=D0-D7 for byte writes, and that A0 isn't used. Do the I/O ports bother to check /LDS and ignore even byte writes? Or do they just silently go through? What about word writes? I presume those will work fine and pass through D0-D7.
As you can see on available schematics (https://console5.com/wiki/File:Mega_Dri ... -_Main.png), I/O chip only got /LWR so it only reacts to byte-wide writes to low (odd) addresses or word-wide writes. In case of word-wide writes, LSB (D0-D7) is being used when accessing I/O registers.

Afaik, only VA1-VA4 are used by I/O chip to decode register index (16 available registers) so $A10020-$A100FF area is mirror of $A10000-$A1001F but I'm not 100% sure (it might be possible full VA1-VA7 range is used, with unused indexes simply being ignored, I don't think this was ever tested).

NB: /LWR (resp. /UWR) is made of /LDS (resp. /UDS) and R/W signals coming from 68K

Mask of Destiny
Very interested
Posts: 591
Joined: Thu Nov 30, 2006 6:30 am

Re: Z80 bus + I/O mapping redux

Post by Mask of Destiny » Sun Apr 28, 2019 4:06 pm

As promised, here's that test ROM and here's the source.

byuu wrote:
Fri Apr 26, 2019 1:42 pm
* a00000-a0ffff => [8-bit bus] Z80 (A15 is ignored)
So this is actually a funny one. On the 68K side, all 16 data lines are connected (via the IO chip because apparently they ran out of pins on the bus arbiter, lol), but the bus being connected on the other side is only 8-bit. This means that you don't have to skip the even bytes or the odd bytes like you normally do with an 8-bit region, but word access doesn't really work right (the test ROM I posted tests word access).
byuu wrote:
Fri Apr 26, 2019 1:42 pm
* a10000-a10fff => [8-bit bus] Peripherals (A8-A15 is ignored)
I'm actually uncertain about the mirroring/full range here. Selection of the IO chip for an address range is handled by the bus arbiter which gets address bits A23-A8 which allows it to do decoding with 256 byte granularity. According to others, the /TIME region (a13000) is only enabled for a 256-byte region so I would guess the same is true for the IO chip.

byuu wrote:
Fri Apr 26, 2019 1:42 pm
* a11000-a11fff => [8-bit bus] Z80 enable/disable (A0-A7 is ignored)
A1-A7 are not physically connected to the bus arbiter so they are definitely ignored. A0 does not exist as an external signal, but is important because as I mentioned on Twitter only one bit of the data bus (d8) is actually connected. This means that byte access generally needs to occur to even addresses and not odd ones. It's possible that writes to odd addresses work because, IIRC, the 68K actually duplicates the byte being written to both halves of the bus so whether this works depends on whether this portion of the arbiter responds to both data strobes or not (it gets both UDS and LDS from the 68K).
byuu wrote:
Fri Apr 26, 2019 1:42 pm
* a12000-a12fff => [bus size depends on the hardware, 8-bit for Sega CD] Expansion port (Sega CD)
The gate array is 16-bits wide.
byuu wrote:
Fri Apr 26, 2019 1:42 pm
* a13000-a13fff => [bus size depends on the hardware, 8-bit for all cartridges I know of] Cartridge (mappers usually)
I've been told that the /TIME signal that the carts use to respond to this area is only active for a 256 byte region. So this is only a13000-a130ff.
byuu wrote:
Fri Apr 26, 2019 1:42 pm
Might these blocks go further and fill in bxxxxx as well?
Nothing asserts /DTACK for this region on a standard Mega Drive so accesses to these addresses will lock the machine. The Teradrive uses this address range for access to the PC side memory space
byuu wrote:
Fri Apr 26, 2019 1:42 pm
And the really big question ... how exactly do unaligned 16-bit accesses work? I'm told it throws a bus error exception. But how does that work on a bus access? If you're in the middle of executing an instruction, does it just abort the whole instruction instantly and jump the PC to the exception vector address?
Yes. Well it pushes some stuff to the stack first before reading the vector table, but the process of exception processing begins without finishing the current instruction. There's some more in depth discussion of address error in this thread, but it's not an easy read.

EDIT: Removed leftover quote stuff
Last edited by Mask of Destiny on Sun Apr 28, 2019 6:06 pm, edited 1 time in total.

byuu
Very interested
Posts: 94
Joined: Thu Feb 28, 2008 4:45 pm

Re: Z80 bus + I/O mapping redux

Post by byuu » Sun Apr 28, 2019 5:51 pm

Thanks for all of the insightful responses! Hopefully I've implemented it correctly ...

To fill out the bus range completely, I am now chaining all of the I/O handlers, so everything that needs an I/O handler has the chance to act on the read/write bus activities:

Code: Select all

  if(address >= 0xa10000 && address <= 0xbfffff) {
    data = cartridge.readIO(upper, lower, address, data);  //responds to a130xx
    data = expansion.readIO(upper, lower, address, data);  //responds to a120xx
    data = readIO(upper, lower, address, data);  //responds to a100xx, a11xxx, a14xxx
    return data;  //whatever the response was, or open bus (next CPU instruction fetch)
    //I am aware bxxxxx was said to be unmapped and will lock the system.
    //system deadlocks from bad address reads not emulated yet, but when they are,
    //I'll reduce the address range tested above and then deadlock on the entire bxxxxx region.
  }
For the existing cartridge mappers (SSF, PS4, etc), I am not doing any mirroring. I am only acknowledging word writes and writes to /LDS (odd addresses.) Game Genie support is incredibly hacky, but I really don't care.

For the Mega CD, I am listening to a120xx, but ignoring A6-A7, so a12040-a120ff mirrors a12000-a1203f.
I was not able to find the portion of the Mega CD dev manual that states which registers are word-write only.
I am also still curious what happens if you do a byte-write anyway. Does it just reject it if either /UDS or /LDS are logic high?

For TMSS, I am mapping a14000 + a14002 and only recognizing word writes. No mirroring is done.
For TMSS a14100, I recognize word writes and byte writes to /LDS, taking only d0. No mirroring here either.
TMSS is almost certainly not correct ...

For peripherals, I am mapping a10000-a100ff, and I am ignoring A5-A7, so that a10020-a100ff mirrors a10000-a1001f.
I am honoring word accesses and byte accesses to /LDS only.

For the Z80, it's screwy. I am mapping a11100-a111ff to the bus request. I am rejecting byte accesses to /LDS this time (!!), but accepting byte accesses to /UDS and word accesses via d8 (my 68K core populates D8-D15 for /UDS byte accesses, so this is fine.) For reads, I am clearing D9-D15 to zero, setting D8 to the bus granted bit (inverted, 0 = granted), and leaving D0-D7 as open bus (next instruction prefetch.)

I am also mapping a11200-a112ff to the Z80 enable bit in D8. Same logic as a11100. I am not currently doing anything on reads, but it sounds like D8-D15 should be zero, and D0-D7 should be open bus.

I don't know how to emulate a11000 yet (ROM/DRAM cartridge select), and I don't know what happens on reads, or how it affects timings. For now, it doesn't seem super important to worry about.

I am also not mapping a115xx (SVP) registers yet.
Last edited by byuu on Mon Apr 29, 2019 7:22 am, edited 1 time in total.

Sik
Very interested
Posts: 901
Joined: Thu Apr 10, 2008 3:03 pm
Contact:

Re: Z80 bus + I/O mapping redux

Post by Sik » Mon Apr 29, 2019 4:00 am

byuu wrote:
Sun Apr 28, 2019 5:51 pm
For TMSS, I am mapping a11400 + a11402 and only recognizing word writes. No mirroring is done.
$A14000 and $A14002 :​P
byuu wrote:
Sun Apr 28, 2019 5:51 pm
I don't know how to emulate a11000 yet (ROM/DRAM cartridge select), and I don't know what happens on reads, or how it affects timings. For now, it doesn't seem super important to worry about.
We keep arguing about this all the time because once we did a test but now it keeps getting refuted? Gah. But basically:

1) It's not used in any commercial game (it was only meant for use with a specific development cartridge)
2) It only works on a few revisions, from memory

I recall it slowed down the CPU a lot in the cases it worked, implying it was doing a lot more of refreshes than usual. I don't remember if we had ever examined the exact pattern of the refreshes though (but considering how the CPU would lose like 1/3 or so of its speed, I wouldn't be surprised if it was refreshing after every access — again, that's guesswork).

That it wasn't implemented in all revisions means that you could implement it as a no-op and it technically be correct for some cases :​v
Sik is pronounced as "seek", not as "sick".

Post Reply