Our current CPU has many limitations, including on the register level. This post will look at how to improve the registers that handle memory or output addresses.
First, let's look at the current register capabilities:
- there are basically only two memory address registers : the Program Counter (PC) and the Memory Address Register MAR)
- these registers are 8-bit registers, therefore they can only address 256 bytes of memory or IO
- Only one provides the increment capability (the Program Counter) however it cannot directly address the memory and has to go through the MAR (memory address register)
- None can decrement
- There is no stack pointer
- There is no index register
So lets try to design a single General Purpose Address Register (GPAR) that would provide:
- 16 bits in order to address 64k words of memory space
- increment and decrement capability in order to serve also as PC (Program Counter) and SP (Stack Pointer) without the need of the ALU
- Read and Write capability from the databus which is only 8-bit, in order to access both MSB (Most Significant Byte, the byte of higher value of the 16-bits) and LSB (Least Significant Byte, the byte of lower value of the 16-bit)
- Write capability to the 16-bit address bus
Now what type of instruction these registers should be able to handle :
- LD PC-MSB, D2 : meanind load the MSB of the PC address register with the content of register D2
- LD D2, IX-LSB : meaning load D2 with the content of the LSB of the index pointer IX
- LD IX-LSB, IY-MSB : meaning load the LSB part of ix with the content of the MCB part of IY
- INC IX
This shows that at any given time, it must be possible to output any of the content of any part of the register ***AND*** input any other part of any other register.
Possibly even within the same register:
- LD IX-MSB, IX-LSB: meaning loar the the MSB part of IX with the LSB value of IX
We therefore need to separate the output action functions from the input action functions.
For output and reset:
- Publish MSB to data bus: -msb-out, asynchrounous
- Publish LSB to data bus : -lsb-out, asynchrounous
- Publish value to Adress bus : -add-out, asynchrounous
- Clear value : -clear, asynchrounous
For input and other:
- load MSB from data bus : -msb-in, on clock rising edge
- load LSB from data bus : -lsb-in, on clock rising edge
- Increment value : -inc, on clock rising edge
- decrement value : -dec, on clock rising edge
In the end we need:
- 3 bits to select the output register (value 0b000 serves as not selected)
- 2 bits to select the output/reset function (MSB, LSB, address bus or reset)
- 3 bits to select the input register (value 0b000 servers as not selected)
- 2 bits to select the input/other function (input MSB, input LSB, inc, dec)
With a total of 10 bits, we can perform any type of function on the General Purpose Address Registers.
Here is the naming convention for the register select bits:
- None: code 0b000
- Program Counter : PC, code 0b001
- Stack Pointer : SP, code 0b010
- Index Pointer 1 : IX, code 0b011
- Index Pointer 2 : IY, code 0b100
Here is the convention for the output action (all are asynchronous):
- Publish MSB to data bus: -msb-out, code 0b00
- Publish LSB to data bus: -lsb-out, code 0b01
- Publish value to Adress bus : -add-out, code 0b10
- Clear value : -clear, code 0b11
Here is the convention for the input/other functions (all are on the clock rising edge):
- load MSB from data bus: -msb-in, code 0b00
- load LSB from data bus: -lsb-in, code 0b01
- Increment value : -inc, code 0b10
- decrement value : -dec, code 0b11
Lets now review what the 10 bits would be for the instructions listed above:
- LD PC-MSB, D2
- select output register NONE: 0b000 (D2 is not consider as we are focusing on the GPAR only)
- select output function X : 0b0
- select input register PC : 0b001
- select input function -msb-in: 0b00
- Result is : 0b000000100
- LD D2, IX-LSB
- select output register IX: 0b011
- select output function -lsb-out: 0b0
- select input register NONE : 0b000
- select input function X: 0b00
- Result is : 0b011000000
- LD IX-LSB, IY-MSB
- select output register IY: 0b100
- select output function -msb-out: 0b1
- select input register IX : 0b011
- select input function -lsb-in: 0b01
- Result is : 0b100101101
- INC IX
- select output register NONE: 0b000
- select output function X: 0b0
- select input register IX : 0b011
- select input function -inc: 0b10
- Result is : 0b000001110
- LD IX-MSB, IX-LSB
- select output register IX: 0b011
- select output function -lsb-out: 0b0
- select input register IX : 0b011
- select input function -msb-in: 0b00
- Result is : 0b011001100
So what do we need to build such a register ?
- capability to store value
- capability to reset value
- capability to increment value
- capability to decrement value
- capability to scale up to 16 bits (including on the increment and decrement value)
- capability to select where to publish all (such as the full address) or part (such as the MSB) to a bus, with 3-state outputs
This can be built using 2 types of ICs:
- the 74HCT193 which is a binary 4-bit up/down cascadable counter, prestable, with reset. We will need 4 to store the 16 bit address
- the 74HCT245 wich is an octal, 3-state transceiver. We will need 4:
- 2 to publish the 16 bits to the address bus
- 1 to publish the MSB to the data bus
- 1 to publish the LSB to the data bus
As usual, LED bargraph will be used to display the current value of the counter. We will be be using 470ohm current limiting resistors to reduce the power consumption if the register.
Finaly, there is a need for decoding the actions signals:
- Two 74HCT138 will decode the register select value. Output Y0 is used to perform nothing, Y1 to Y4 to select which register, and it can be expanded to 3 more
- A bunch og logic gates to build the proper signal
Note that 4 actions need to be synchronized with the clock.
More to come soon on this topic.
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.