I've updated the specification to 0.2j. At this point I'm satisfied with the specification, and barring the discovery of additional errors, I don't see anything changing. Progress on the emulator has been slow, but as of this morning I have the entire thing implemented in software, except for the RTC, Hardware bus, and raising the 'UnPriv Opcode' interrupt while in User mode.
In this update are a complete specification for the RTC, updates to the MMU, and new instructions that will help with changing the context of the processor.
I added 'P' present and 'A' accessed bits to help with bank management.
2.F.3. THE MMU CACHE wrote:
Code:
A - Access flag:
This bit is set every time this bank is written to.
P - Not present flag:
If this bit is set, any access to this bank will raise a bank fault.
I specified the state of the U, W, and E bits on bank fault:
2.F.5. BANK FAULTS wrote:
Code:
When a bank fault is raised, the processor status bits U, W, and E will describe
the operation that caused the bank fault:
U W E Bank Fault Type
0 0 0 Bank not present
0 0 1 Attempted execution of execute-protected memory.
0 1 0 Attempted supervisor write of write-protected memory.
1 0 0 Attempted user read of supervisor-only memory.
1 1 0 Attempted user write of supervisor-only memory.
Note that writes to ROM banks will fail silently unless the MMU is enabled and
the write-protect bit is set, which will generate a bank fault.
Specification for the RTC. You get the current time using the HWQ instruction, and can enable/disable the interrupt, as well as specify the interrupt frequency of the CLOCK interrupt.
2.H. The Real Time Clock wrote:
Code:
The processor contains an integrated Real Time Clock (RTC). The RTC maintains
and updates its internal time data indefinitely, even when the processor is
powered down. The processor can query the RTC for the current time.
The clock provides time data with the following precision:
Year: 8 bits (0-255)
Month: 4 bits (0-11)
Day: 5 bits (0-31)
Hour: 5 bits (0-23)
Minute: 6 bits (0-59)
Second: 6 bits (0-59)
Tick: 16 bits (0-65535)
The RTC also provides a CLOCK interrupt, which can be enabled, disabled, and the
frequency of which can be specified. When the RTC interrupt is enabled, the RTC
will raise the CLOCK interrupt at an interval which is specified by the
processor. The RESET interrupt disables the RTC.
The new 'JCX' instruction allows the processor to change the entirety of the memory space and jump into user mode:
3.H. Jump & Call Instructions wrote:
Code:
JCX Unconditional Jump and change Context
1. A pointer to a 32-word array of MMU data is popped from the stack.
2. The MMU is loaded with the data in the 32-word array.
3. The value iPS is popped from the stack.
4. The remaining registers are popped from the stack in this order:
SP, R6, R5, R4, R3, R2, R1, R0, FL, PC
5. PS is set to iPS.
6. Execution continues.
NOTE: The following operations are the equivalent of 'save context':
PSH R7, R6, R5, R4, R3, R2, R1, R0, FL, PC
TSR R0, PS
PSH R0
; determine the address where the 32-word MMU cache will be saved.
LOD R0, {Address of 32-word MMU cache store location}
MML R0
PSH R0
One other big change: I've though a ton about how interrupts should work. The supervisor memory state should be switched into memory so it can handle the interrupt, but the previous memory state should be maintained. Here's my solution:
On an interrupt, the processor saves the current PS, enters supervisor mode, and disables the MMU. The memory space is as follows:
Code:
While the 'Memory Banking' status bit is clear, the MMU is disabled, and the
processor's address space is mapped as follows:[quote="2.F.1. ADDRESS SPACE WHEN THE MMU IS DISABLED"][code] Bank $0 - If R status bit is clear, Internal ROM Bank $00
If R statis bit is set, Internal RAM Bank $00
Bank $1 - Internal RAM Bank $01
Bank $2 - Internal RAM Bank $02
...
Bank $E - Internal RAM Bank $0E
Bank $F - Internal RAM Bank $0F
Because this is a known state, the OS can plan out what data and routines it needs to have in memory to handle interrupts - and has the entire address space available to put this data in. Because the MMU cache hasn't been changed, the processor can either leave it unchanged and the pre-interrupt memory space will be 100% restored when the M status bit is set again, or save the MMU cache (easy to do with MML/MMS) if the OS needs to load different memory space.