The project progresses a lot !
The http://src.ygrec8.com/YGREC8/Manual/Y8-Manual.html is slowly getting more precise and pertinent thanks to help from @alcim.dev , Lionel and Kanna. The assembler is getting better but the simulator is the goal and it is obvious that certain core registers can't be accessed as usual, so they must be mapped to the IO registers space.
I have been cautious to not overdefine or over-allocate this pristine area, so far, but now is the time to start somewhere.
The basic model requires at least 4 8-bit registers:
- Data RAM port 1 Bank (an 8-bit extension to the A1 register)
- Data RAM port 2 Bank (extends the A2 register)
- Current_Overlay (read-only, use the OVL opcode)
- Flags (3) and Prefix (5)
Since they uniquely define the whole CPU state, they need "shadow" versions that are automatically saved during an interrupt or exception/trap. That makes 4*2=8 addresses that are mapped in the "negative" addresses, when bit 8 is set:
.EQU A1BANK -1 ; r/w .EQU A2BANK -2 ; r/w .EQU CURROVL -3 ; ro .EQU FLAGS -4 ; rw .EQU SHADOW_A1BANK -5 ; ro .EQU SHADOW_A2BANK -6 ; ro .EQU SHADOW_CURROVL -7 ; ro .EQU SHADOW_FLAGS -8 ; ro
OK this doesn't seem practical because -8 falls outside of a 3-bit range (it amounts to 0). So let's offset things a bit with 7 other scratch registers, used to spill and/or save an interrupted state:
.EQU SCRATCH_A1 -1h ; r/w .EQU SCRATCH_A2 -2h ; r/w .EQU SCRATCH_R1 -3h ; r/w .EQU SCRATCH_R2 -4h ; r/w .EQU SCRATCH_R3 -5h ; r/w .EQU SCRATCH -6h ; r/w .EQU A1BANK -7h ; r/w .EQU A2BANK -8h ; r/w .EQU FLAGS -Ah ; r/w .EQU CURROVL -9h ; ro (use the OVL opcode) .EQU SHADOW_PC -Bh ; ro .EQU SHADOW_A1BANK -Ch ; ro .EQU SHADOW_A2BANK -Dh ; ro .EQU SHADOW_FLAGS -Eh ; ro .EQU SHADOW_CURROVL -Fh ; ro
This better version now includes a copy of the PC, as well as scratch registers that are used by a handler to save the state of a currently running program. One extra scratch register is provided, D1 and D2 are not saved because once you set the A1 and A2 registers, as well as the A1BANK and A2BANK registers, you can restore D1 and D2.
9 registers are read-write (including the A1BANK, A2BANK and FLAGS), the other 6 are read-only (for now). During a context save cyle:
A1BANK => SHADOW_A1BANK A2BANK => SHADOW_A2BANK FLAGS => SHADOW_FLAGS CURROVL => SHADOW_CURROVL PC => SHADOW_PC
Maybe one day there will be an instruction or other method to restore the registers back from their shadow. Yet so far, only A1BANK, A2BANK, FLAGS and CURROVL are strictly required for a basic implementation.
Beware : First restore the AxBANK then only the Ax registers, to trigger a re-load of the Dx registers. Similarly, when changing the AxBANK, don't forget to update the Ax otherwise the Dx will contain data cached from writing to a different bank.
We need other registers to provide more awareness and flexibility. For example, the cause of arriving at address 0 of an overlay:
.EQU IO_A0CAUSE -10h ; read, clear by writing 1s ; it's a bitfield: .EQU CAUSE_RESET 1h; .EQU CAUSE_OVL 2h; .EQU CAUSE_TRAP 4h; .EQU CAUSE_IRQ 8h; .EQU CAUSE_INV 10h; .EQU CAUSE_WATCHDOG 20h; .EQU CAUSE_DOUBLEFAULT 40h; .EQU CAUSE_OTHER 80h;
Another convenient feature for later is to address the IO space in sequence. The address is 9 bits wide so there is a need for 2 byte registers for the address, one with 7 unused bits. The choice is different: take a data register for the one half of the addressing space, another register for the other half.
.EQU IO_INDIRECT_PTR -11h ; r/w, simple presetable counter .EQU IO_INDIRECT_SYS -12h ; r/w .EQU IO_INDIRECT_USR -13h ; r/w
Now we also need to define what these extended condition bits test: let's just allocate one whole 8-bit register for each condition, which can control a multiplexer or whatever.
.EQU IO_CONDITION_B0 -14h; .EQU IO_CONDITION_B1 -15h; .EQU IO_CONDITION_B2 -16h; .EQU IO_CONDITION_B3 -17h;
The timers/counters will need much more registers than that, I don't even get started on the interrupt controller...
Concerning the rough allocation of the addresses:
Addresses 0 and above are left untouched for now.
So far we see the IO space split in two halves : the positive range (MSB=0) for user purpose and actual interfacing, with an open-ended and user-defined structure (where you put the GPIO, the serial links...), and the negative range will be more rigid and system-oriented (as above).
For simulations, we might want to read and write dummy data, for now it will go to address 42.