A few questions ....
1) Why no Memory Mapped $Dxxx I/O for Z80 ? Please note the following examples.
Example 1 - Store any 8-bit value into $FF00 ACCEPTABLE, FUNCTIONAL
ld a,#$xx (LDA #$xx) Acceptable
ld ($ff00),a (STA $ff00) .. $FF00 is visible in all configurations, we can use ld ($ff00),a
Example 2 - Store any 8-bit value into $DXXX UNACCEPTABLE, NON-FUNCTIONAL
ld a,#$xx (LDA #$xx) $d000-dfff is the block of addresses where I/O sits.
ld ($dxxx),a (STA $dxxx) simple store here falls through to RAM sharing the same addresses as I/O.
Example 3 - Store any 8-bit value into $DXXX ACCEPTABLE, FUNCTIONAL with OUT instruction.
ld a,#$xx (LDA #$xx) Load 8-bit value into Accumulator (a)
ld bc,$dxxx Load $dxxx into registers b and c
out (c),a Put value in (a) into I/O ($dxxx) not RAM ($dxxx)
Example 4 - Changing 40 column (VIC-II) Background Color to Black
Z80 using OUT
ld a,0
ld bc,$d021
out (c),a .....3 instructions to finish this task
8502
LDA #$00
STA $d021 .....2 instructions to finish this task
BASIC
POKE 53281,0
Access to $FF00 is load/store. Why did CBM go "by the book" with $Dxxx? Why no MMIO there with simple load/stores? I would have preferred MMIO while reserving IN/OUT for accessing the ram "under" the I/O block.
--
2) As per the literature, the Z80 rom is physically located at the $Dxxx I/O block and Z80 sees this rom at $0000--. How is this done? Does this "relocation" play a role with respect to the IN/OUT requirement for I/O access?
--
3) The z80 bios rom startup, as follows:
ADDR Bytes on disk Z80 code PSEUDO-6502 Equivalent and Comments
---- ---------------------------------------------------------------------------------
0000: 3E 3E LD A,$3E LDA #$3E
0002: 32 00 FF LD ($FF00),A STA $FF00 nothing new here
0005: C3 3B 00 JP $003B JMP $003B jump to $003B
[..........]
003B: 01 2F D0 LD BC,$D02F ye olde XSCAN (extended keyboard)
003E: 11 FC FF LD DE,$FFFC LDX #$FF and LDY #$FC
0041: ED 51 OUT (C),D STX $D02F write #$FF (11111111), set output lines high.. why? maybe we'll find out later in the rom...
0043: 03 INC BC now BC=d030 -- ye olde CLKRATE
0044: ED 59 OUT (C),E STY $D030 write $FC (11111100), bit0 to (1 MHz-Mode), bit1 (test-bit, interlace) to 0.
Without even thinking about "Why the #$FF to $D02F?", why does #$FF-> $D02F happen --before-- the system is forced to 1 MHz? ...$D02F is at VIC IIe, so why fiddle with this register before making sure VIC is "safe" @ 1 MHz?
--
4) and finally....
Z80 using OUT
ld a,0
ld bc,$d021
out (c),a
Why does it seem as if every bit of Z80 documentation characterizes the OUT instruction as if it only holds the lower byte (c) instead of the proper/full two-byte address (bc) ?! I would expect source code to read as follows: OUT (bc),a for two byte address, and OUT (c),a for one byte address.
--
XmX
I can only attempt to answer your first question. My guess is that if I/O was mapped to the $Dxxx range the C128's Z80 memory map would probably be incompatible with CP/M. Being able to run CP/M was after all the reason for having the Z80 in there.
I think they used I/O commands to make PLA (or MMU) design simpler. There is a brief comment relating to this somewhere in the C128 Programmer's Reference Guide.
Also it means you can run Z80 software in $dxxx region and still access I/O registers. But it seems you know this.
As for ROM location, this is not important unless you want to burn your own KERNAL. Then you will need to put the Z80 code between Editor ($C000~$CFFF) and main KERNAL ($E000~$FFFF).