Segmented memory on Z80

It might be interesting to think of a way to extend the Spectrum's memory using a segmented model similar to the 80x86 rather than manually keeping track of pages.

By decoding the address bus having at least three segments, Data, Code and Stack operation could be relatively transparent. The memory window might live in the top 32k of RAM and the device would monitor the MREQ and M! signals and decode the instruction on the bus. It would need to provide some additional instructions by using empty areas in the Z80 instruction set to select or switch segments.

This would all require that the device be able to decode Z80 instructions to decide which segment was going to be used but once that's done everything else should fall into place. Luckily, the Z80 instruction set is relatively easy to decode and should require the minimum of logic.

The easiest way to test this out would be to rig up something that would decode a small subset of instructions and see if it works.

It also needs to be decided what kind of granularity the segments are going to have. In the x86 it's 16 bytes, which extends the addressing range to 20 bits or one megabyte. Will that be enough for the Spectrum, or should we make it a definable register in the device?

Starting off I would stick with the code, data, stack and extended segment registers; CS, DS, SS and ES but we could always define additional ones if it was useful.

The plan then would be to be able to extend the assembler mnemonics so that you could write code such as the following (assuming the segments were aligned on 16-byte boundaries):

; Standard screen clearing routine
CLRSCR:
        LD    DS,$400
        LD    ES,DS
        LD    HL,0
        LD    DE,HL
        LD    BC,$1AFF
        INC   DE
        LD    (HL),L
        LDIR
        RET
; A faster screen clear routine
FASTCLR:
        LD    A,I                ; Get IFF2 into P/V flag
        PUSH  AF
        DI                       ; Disable interrupts
        LD    CS:(SPTMP+1),SP    ; Save SP
        LD    CS:(SSTMP+1),SS    ; Save SS
        LD    B,192+24
        LD    SS,$400
        LD    SP,$1B00
        LD    HL,0
    L0: PUSH  HL
        PUSH  HL
        PUSH  HL
        PUSH  HL
        PUSH  HL
        PUSH  HL
        PUSH  HL
        PUSH  HL
        PUSH  HL
        PUSH  HL
        PUSH  HL
        PUSH  HL
        PUSH  HL
        PUSH  HL
        PUSH  HL
        PUSH  HL
        DJNZ  L0
SSTMP:  LD    SS,0
SPTMP:  LD    SP,0
        POP   AF
        RET   P
        EI
    L1: RET
; Copy a screen buffer from $A0000 into the display file at $4000
CPYBUF:
        LD    ES,$A000
        LD    HL,0
        LD    DS,$400
        LD    DE,0
        LD    BC,1B00
        LDIR

Block move and related instructions would by default use ES as the source segment and DS as the destination segment, with HL as the source offset and DE as the destination offset as normal.

Theory of operation:

    1. Use the CLK signal to synchronise with the clock supplied to the Z80
    2. Monitor the M1 line to see when an instruction has been fetched
    3. Is WR active?
    4. If not. sniff the data bus to see what instruction is being taken out of RAM
    5. Is the instruction extendable or a prefixed opcode?
    6. If not, reset the segment override and go to #2
    7. Is it a segment override prefix?
    8. If so, set the segment override and go back to #2
    9. If the current instruction is a memory read provide the appropriate data on D0-D7
    10. If it's a store then take the value off D0-D7 and place in the correct memory location
    11. Go back to #2

Links

1) http://www.z80.info/decoding.htm