[03-NOV-26] Design documents for the RMC5.
Chronological record of the development and production of the Reduced Instruction Set Microcontroller, Five-Bit Operands (RMC5).
[28-OCT-26] We consider again if we can put some kind of processor in the LCMXO2-256ZE. We use the Lattice Diamond IPExpress tool to tell us how many LUTs various components will consume. Let's call it the RISC Micro-Controller, Five-Bit (RMC5) where the "five-bit" refers to the size of the op-codes. We begin with a 128-location instruction memory made of distributed SPRAM and initialized to hold the microcontroller program with writing to the memory disabled. Each location is 12 bits, the instruction memory takes 40 LUTs. The top five bits of each instruction are an opcode and the bottom seven bits are an operand. We choose thirty-two instructions that together will do everything that the OSR8V5 will do. The instructions refer to an accumulator, A, and the operand, n, as well as flags Z for zero, C for carry, and I for disable interrupts.
push A ; Push A onto the stack pop A ; Pop A off the stack push F ; Push flags onto stack pop F ; Pop flags off of stack ld A,(nn) ; Load A with contents of address nn ld (nn),A ; Load address nn with A ld IX,nn ; Load index register with nn ld (IX),A ; Load address IX with A ld A,(IX) ; Load A with contents of address IX inc IX ; Increment IX dec IX ; Decrement IX add A,(nn) ; Add (nn) to A and put result in A, no carry in, sets C and Z adc A,(nn) ; Add (nn) to A and put result in A, with carry in, sets C and Z sub A,(nn) ; Subtract (nn) from A and put result in A, no carry in, sets C and Z sbc A,(nn) ; Subtract (nn) from A and put result in A, with carry, sets C and Z clf ; Clear flags Z and C rl A ; Rotate A left, C into bit 0, bit 7 into C rr A ; Rotate A right, C into bit 7, bit 0 into C and A,(nn) ; Logical and A and (nn), result in A, sets Z xor A,(nn) ; Logical xor of A, result in A, sets Z or A,(nn) ; Logical or of A, result in A, sets Z jp n ; Jump to location n in instruction memory jp z,nn ; If Z flag set, jump to n jp nz,nn ; If Z flag not set, jump to n jp c,nn ; If C flag set, jump to n jp nc,nn ; If C flag not set, jump to n call nn ; Call subroutine at instruction location n seti ; Set the I flag to disable interrupts clri ; Clear the I flag to enable interrupts ret ; Return from subroutine rti ; Return from interrupt nop ; No operation
Each instruction completes in one clock cycles. The microcontroller reads the instruction on the rising edge of the clock and performs all writes on the next rising edge. The instruction memory is asynchronous. The process memory has synchronous write but asynchronous read. The instruction processor decodes the five-bit opcode into thirty-two different actions. The 8-bit accumulator can rotate itself in either direction, XOR, OR, and AND itself with a memory value, and is accompanied by an adder-subtractor. The processor stack can take either address or data values. Upon interrupt, the microcontroller pushes the program counter onto the stack and loads the program counter with a default interrupt vector. Instead of including data constants in instructions, we load them into process memory locations during FPGA configuration. We store constants 0x00, 0xFF, and 0x01 in the memory. Thus we can implement negation of A with xor A,(ones), increment A with "add A,(unity)", decrement A with "sub A,(unity)", and so on. We include in memory various masks to isolate bits. If RAM occupies half the process address space, the other half of the address space will be available for its hardware interface. Here is an eight-bit multiplier for the RCM5.
; mult_8
; Unsigned 8 x 8 -> 16-bit product.
;
; Input:
; M Multiplicand, 8 bits
; Q Multiplier, 8 bits
;
; Output:
; HI:Q Product, 16 bits
;
; Workspace:
; COUNT Iteration counter
;
; Constants:
; ZERO = 0, ONE = 1, EIGHT = 8
;
; Uses carry as ninth bit of partial product.
mult_8:
ld A,(ZERO)
ld (HI),A
ld A,(EIGHT)
ld (COUNT),A
mult_8_loop:
ld A,(Q)
and A,(ONE)
jp z,mult_8_noadd
ld A,(HI)
add A,(M)
ld (HI),A
jp mult_8_shift
mult_8_noadd:
clf ; No addition: carry = 0
mult_8_shift:
ld A,(HI)
rr A ; C:HI -> HI, bit 0 -> C
ld (HI),A
ld A,(Q)
rr A ; Previous HI bit 0 -> Q bit 7
ld (Q),A
ld A,(COUNT)
sub A,(ONE)
ld (COUNT),A
jp nz,mult_8_loop
ret
[30-OCT-26] We have built the RCM5 in VHDL with its own demonstration repository RMC5. The number of opcode bits is fixed at 5, but the number of address bits is variable, but by default 7. We have the same address space for instruction and process memory. The RMC5 entity contains its own stack, separate from process and instruction memory. This stack is wide enough to accommodate data and address values. When we use distributed ROM for the instruction memory, the compiler can eliminate unused functions from the RCM5 by looking at the program. We write a program that uses all classes of instruction and load into a 64-byte distributed ROM. We keep the process memory external to the target device. We let the stack height be 8 locations. The compiled code is 229 LUTs. It is too large to fit in the LCMXO2-256ZE. We adapt our OSR8_Assembler for the RMC5 and rename as the Assembler tool, which can compile for both RMC5 and OSR8.
[03-NOV-26] Although the RMC5 fails to fit in its target FPGA, it remains an attractive microcontroller for future implants. It is much smaller than the OSR8, which is currently running at about 700 LUTs. The use of memory location for all data bytes other than the accumulator allows us to manipulate memory locations quickly. We can use memory locations as registers. We can push these registers onto the stack in two operations "ld A,(reg_B); push A" and pop them in the same way "pop A; ld (reg_b),A".