A lot of progress was made over the past month on the software side of things. This is a very significant part of the overall system and has also been driving changes in the underlying hardware. A workable design is now in place and some details are covered in the following log.
First, some terminology
- Firmware is used to describe the code that is executed by the machine. This code resides in the ROM and is executed directly by the hardware.
- Software is used to describe the interpreted code that resides in the RAM. This code is read by the firmware and executed to emulate the operation of a virtual CPU.
The firmware is technically running on a RISC machine, except instructions take more than one clock cycle to execute. This is due to the limitation of 8-bit wide memory and putting both the firmware and ALU in the same ROM. The machine could operate at one instruction per clock by using a 16-bit wide memory for the firmware and a separate ROM for the ALU. However, the current design requires up to four cycles per instruction:
- Fetch - one or two process cycles
- Execute - one or two process cycles
Each process cycle consists of two machine cycles which alternate between access to the ROM and RAM. The fetch cycle provides a read access to the RAM and the execute cycle provides an optional write. This way every instruction can take the form: fetch, read, execute, write (the same read and write cycle is repeated when more than one cycle is needed to fetch and/or execute).
The software is interpreted by an emulator in firmware that also controls both the video display and serial communications. These systems are timing critical and maintaining synchronization is a significant part of the design challenge. One approach is tracking the number of cycles per instruction before the synchronized event and breaking when not enough cycles are left to guarantee the next instruction will execute in time. The other is to break the virtual instructions down in to fetch and execute cycles and use fixed cycle timing for each.
Cycle counting makes sense only if the complete instruction fetch/execution time is fairly small. After implementing instruction from various CPUs it appears cycle counting could result in only one instruction being executed between the horizontal sync events. This happens when the first instruction loaded is on the longer side and there isn't enough time left to execute another long instruction. The fixed fetch/execute timing has the ability to split instructions across the horizontal sync event and avoid wasting unusable cycles when longer instructions were executed.
The fixed fetch/execute timing is being used with a processing rate of 9600 cycles per second. This leads to the following counts for vertical video synchronization:
- VGA - 128 process cycles per field at 75 fields per second
- SVGA - 160 process cycles per field at 60 fields per second
Each process cycle consists of 4 lines and each line consists of 5 machine cycles (20 machine cycles per process cycle). One machine cycle is needed per line to perform the horizontal sync at a rate of 38.4 kHz. Three additional machine cycles are used every process cycle for other overheads including serial communication at 9600 baud. This leaves 13 machine cycles for the interpreter, which would equate to around 125k machine cycles per second (average 8 uS per machine cycle). This is equivalent to an RCA CDP1802 running at 1 MHz, or about half the processor speed of the COSMAC Elf.
The machine cycle is tracked using an 8-bit state machine in firmware. This state is combined with the fetched instruction to determine the code page to load via a decode function in the ALU. The state is also combined with the process cycle count via another ALU function to set the Scan Counter. Other custom ALU functions are used by the interpreter such as the Arithmetic Status (AS). This function returns two nibbles, one consisting of the status flags on addition and the other on subtraction. This can be used to update a status register in the absence of a real ALU with status flags built in.