Last visit was: Sun Nov 28, 2021 12:21 pm It is currently Sun Nov 28, 2021 12:21 pm

 Page 1 of 1 [ 2 posts ]
The RAMON5 CPU Architecture (homebrew)
Author Message

Joined: Fri Jun 09, 2017 10:36 am
Posts: 1
N.B. I've copied the original topic from the 6502 forum, as it was inappropriate where it was. Originally I was only posting from the point of view of replying to BigEd's request, but now I know about this place, I'm actually quite keen to get feedback from y'all.

Alarm Siren wrote:
I'm posting this at BigEd's request. Nevertheless, and as always, all questions, comments and criticisms are welcome.

RAMON5 Architecture
Summary
RAMON5 is a simple 8-bit architecture of my own design. To the best of my belief, it is turing complete (with all the normal provisos attached to that statement).

It has the following specifications:
• Harvard Architecture
• 11 registers (8 general purpose)
• 9-bit address space for RAM (divided equally into general purpose and stack)
• 12-bit address space for Instruction ROM
• Single interrupt pin with acknowledgement
• Eight 8-bit I/O ports
• Either 32 or 46 instructions (depending on how you count them)

Instructions
All available instructions are listed in the table below. Some non-obvious notation I've used for the Action column:
• All actions are carried out sequentially left to right and separated by a semicolon ";".
• Equals sign "=" represents both assignment and equality depending on context.
• << and >> are left and right logical shift of the left-hand operand by the number on the right-hand.
• +, -, &, ^, ~ and | are addition, subtraction, bitwise AND, XOR, NOT and OR respectively.
• xF means Flag x
• A single capital letter R or I on its own is a reference to the Register or Immediate Value, respectively, as found in the Opcode Syntax
• \$x means Register x (fixed)
• y[x] means reading or writing to the location indirectly addressed by x within address space y.

Code:
Opcode Syntax               Mnemonic    Description         Action
00000RRR                    LACC        Load Accumulator    \$0 = R
00001RRR                    SACC        Store Accumulator   R = \$0
00010RRR                    PUSH        Push to Stack       Stack[\$SP] = R; \$SP = \$SP + 1
00011RRR                    POP         Pop from Stack      \$SP = \$SP - 1; R = Stack[\$SP]
00100RRR                    PUT         Write to Memory     Memory[R] = \$0
00101RRR                    GET         Read from Memory    \$0 = Memory[R]
00110III                    OUT         Write I/O Port      Port[I] = \$0
00111III                    IN          Read I/O Port       \$0 = Port[I]

01001RRR                    ADC         Add w/Carry         \$0 = \$0 + R + CF; CF = Carry Out; VF = Overflow out
01010RRR                    SUB         Subtract            \$0 = \$0 - R
01011RRR                    SBC         Subtract w/Carry    \$0 = \$0 - R - 1 + CF; CF = Carry Out; VF = Overflow out
01100RRR                    AND         Bitwise And         \$0 = \$0 & R
01101RRR                    NOR         Bitwise Nor         \$0 = ~(\$0 | R)  (Implement using \$0 = (\$0 | R) ^ 0xFF)
01110RRR                    XOR         Bitwise Xor         \$0 = \$0 ^ R
01111RRR                    XACC        Exchange Accumul.   (temp) = \$0; \$0 = R; R = (temp)

10001RRR IIIIIIII           ADCI        Add Imm. w/Carry    R = R + Immediate[I] + CF; CF = Carry Out; VF = Overflow Out
10010xxx IIIIxxxx           CLRF        Clear Flags         \$FL = \$FL & Immediate[I]
10011xxx IIIIxxxx           SETF        Set Flags           \$FL = \$FL | Immediate[I]
10100III                    RSH         Right Shift         \$0 = \$0 >> Immediate[I], bit-shifted in = 0.
10101III                    LSH         Left Shift          \$0 = \$0 << Immediate[I], bit-shifted in = 0.
10110III                    RSHC        Right Shift w/Carry \$0 = \$0 >> Immediate[I], bit-shifted in = CF; CF = Carry out; VF = 0
10111III                    LSHC        Left Shift w/Carry  \$0 = \$0 << Immediate[I], bit-shifted in = CF; CF = Carry out; VF = 0

11000xxx xxxxIIII IIIIIIII  JMP         Jump                \$IP = Immediate[I]
11001RRR xxxxIIII IIIIIIII  JMPO        Jump w/Offset       \$IP = Immediate[I] + R
11010xxx xxxxIIII IIIIIIII  CALL        Call Subroutine     Stack[\$SP] = (\$IP >> 8) | (\$FL << 4); \$SP = \$SP + 1; Stack[\$SP] = (\$IP & 0xFF); \$SP = \$SP + 1; \$IP = Immediate[I]
11011xxx IIIIIIII           RET         Return from Sub     \$SP = \$SP - Immediate[I] - 1; \$IP = Stack[\$SP]; \$SP = \$SP - 1; \$FL = Stack[\$SP] >> 4; \$IP = \$IP | Stack[\$SP] << 8
11100xxx IIIIIIII           SKIP        Skip Forward        \$IP = \$IP + Immediate[I]
11101xxx IIIIIIII           RWND        Skip Backward       \$IP = \$IP - Immediate[I]
11110000 IIIIIIII           SKIPNC      Skip if CF Clear    If (CF = 0) Then { \$IP = \$IP + Immediate[I] }
11110001 IIIIIIII           SKIPNV      Skip if VF Clear    If (VF = 0) Then { \$IP = \$IP + Immediate[I] }
11110010 IIIIIIII           SKIPNI      Skip if IF Clear    If (IF = 0) Then { \$IP = \$IP + Immediate[I] }
11110011 IIIIIIII           SKIPNU      Skip if UF Clear    If (UF = 0) Then { \$IP = \$IP + Immediate[I] }
11110100 IIIIIIII           SKIPC       Skip if CF Set      If (CF = 1) Then { \$IP = \$IP + Immediate[I] }
11110101 IIIIIIII           SKIPV       Skip if VF Set      If (VF = 1) Then { \$IP = \$IP + Immediate[I] }
11110110 IIIIIIII           SKIPI       Skip if IF Set      If (IF = 1) Then { \$IP = \$IP + Immediate[I] }
11110111 IIIIIIII           SKIPU       Skip if UF Set      If (UF = 1) Then { \$IP = \$IP + Immediate[I] }
11111000 IIIIIIII           RWNDNC      Skip if CF Clear    If (CF = 0) Then { \$IP = \$IP - Immediate[I] }
11111001 IIIIIIII           RWNDNV      Skip if VF Clear    If (VF = 0) Then { \$IP = \$IP - Immediate[I] }
11111010 IIIIIIII           RWNDNI      Skip if IF Clear    If (IF = 0) Then { \$IP = \$IP - Immediate[I] }
11111011 IIIIIIII           RWNDNU      Skip if UF Clear    If (UF = 0) Then { \$IP = \$IP - Immediate[I] }
11111100 IIIIIIII           RWNDC       Skip if CF Set      If (CF = 1) Then { \$IP = \$IP - Immediate[I] }
11111101 IIIIIIII           RWNDV       Skip if VF Set      If (VF = 1) Then { \$IP = \$IP - Immediate[I] }
11111110 IIIIIIII           RWNDI       Skip if IF Set      If (IF = 1) Then { \$IP = \$IP - Immediate[I] }
11111111 IIIIIIII           RWNDU       Skip if UF Set      If (UF = 1) Then { \$IP = \$IP - Immediate[I] }

Additionally, there are some pre-defiend Virtual Instructions which are converted into real instruction(s) by the Assembler:
Code:
Mnemonic & Operands     Description                 Equivalent To
SUBI R, I               Subtract Immediate          ADDI R, (~I + 1)
SBCI R, I               Subtract Imm. w/Carry       ADCI R, (~I + 1)
NOOP                    No-operation                LACC \$0
HALT                    Wait for next Interrupt     RWND 2
BIT  I                  Bit Test Accumulator        RSHC I                  [CF=\$0's I-th bit; \$0 is modified.]
TZER R                  Test for Zero               CLRF C; ADCI R, 255     [CF=0 if Zero, else CF=1; R is modified.]
TEQU R                  Test for Equality           SUB R; TZER \$0          [Compares \$0 and R, if they equal eachother then CF=0, else CF=1. R is preserved, but \$0 is not]

Registers
Code:
Mnemonic    Description             Width   State On Reset
\$0          Accumulator             8       0
\$1          Data                    8       Undefined
\$2          Data                    8       Undefined
\$3          Data                    8       Undefined
\$4          Data                    8       Undefined
\$5          Data                    8       Undefined
\$6          Data                    8       Undefined
\$7          Data                    8       Undefined
\$FL         Flags                   4       0
\$SP         Stack Pointer           8       0
\$IP         Instruction Pointer     12      0

\$0 is the Accumulator. Many instructions implicitly use it as an operand.
\$1 through \$7 are general purpose data registers.
\$FL stores the four flags (see section below).
\$SP stores the current stack pointer. It cannot be directly accessed.
\$IP stores the address of the next instruction to be executed. It cannot be directly accessed.

Flags
Code:
Bit#    Mnemonic    Description
0       CF          Carry Flag
1       VF          Overflow Flag
2       IF          Interrupt Enable Flag
3       UF          User-Condition Flag

CF and VF are self-explanatory.
IF: see the Interrupts section below.
UF: Not used or changed by hardware, and the programmer is free to use it as a custom state flag, complete with its own branch instructions.

* Originally UF was planned to be a Zero Flag (ZF) but due to a quirk of the hardware design, it would not be possible to update UF/ZF during an arithmetic operation without also clearing IF.

Interrupts System
On seeing a High Level on the INT pin, if IF is also High, the processor will wait for the current instruction to complete,
then it will execute the equivalent of "CALL 3", except that \$FL will be completely cleared (the saved copy of \$FL on the stack will be as normal).
This is done to ensure that IF is low so that nested interrupts will not occur (unless explicitly permitted by the interrupt handler setting IF high again).
Additionally, the INTACK pin will be pulsed high for a clock cycle - this can optionally be used by the sending peripheral to clear its interrupt condition.

Reset System
A low level on !RST will immediately reset the processor. This will guarentee that \$FL, \$SP, \$IP and \$0 are zeroed. Execution will begin once !RST is raised high again. Contents of registers \$1-\$7, RAM and Ports are undefined.

Example Code
This is a very, very simple test program which outputs the numbers 0 to 9 on port 0 then loops.
The assembled bytecode is on the left, with "addresses" prefixed by a dot. This was assembled by hand and does work in the Simulator.
Code:
.00 00 00   .label %reset
C0 00 06        JMP %start      # Go straight to the start of the code.
.00 00 03   .label %isr
D8 00           RET 0           # We're not using the ISR so we'll NOOPify it.
00              NOOP
.00 00 06   .label %start
7F              XACC \$7         # Swap registers 0 and 7's values.
70              XOR \$0          # XOR Register 0 with itself = 0.
80 09           ADDI \$0, 9      # Add the immediate value 9 to register 0 = 9.
7F              XACC \$7         # Swap registers 0 and 7 => Reg7 = 9.
.00 00 0B   .label %repeat
07              LACC \$7         # Copy register 7's value into Register 0.
30              OUT 0           # Output register 0 onto port 0.
90 E0           CLRF C          # Ensure the carry flag is clear.
8F FF           SBCI \$7, 1      # Subtract with carry 1 from register 7.
FC 08           RWNDC %repeat   # If Reg7 >= 1 then CF=True, so go to %repeat to decrement again.
E8 10           RWND %start     # If Reg7 < 1 this will run, go back to start.
.00 00 15   .label %end

FAQ
What's with the name?
RAMON - Its a very long tale which I won't go into, but it originally stood for "Rexterran Administrator's Mechanical Oracle (New)". Suffice to say that nowadays I just name my CPU designs "RAMONx" where x is the iteration. This being the 5th iteration we get RAMON5.

Have you built it in hardware?
No, not yet. Though I have a design that uses (almost) exclusively 74xx series logic and in principle should be able to work in hardware, and intend to build it at some point in the indefinite future. I do have it running in a simulator.

What kind of hardware are we talking about?
Approximately 58 74xx series logic chips and five microcode ROMs which operate 40 control signals. The pinout has 40 signals: 8-bit bidirectional databus, 9-bit data address bus, 8-bit instruction databus, 12-bit instruction address bus, clock, !reset, interrupt, interrupt acknowledge, read/!write, !memory select and !port select.

What tools are there? Assembler? High-Level Compiler?
Nothing complete. I am working on an assembler called RASM, but I havn't got very far as yet. I'm have trouble with some aspects of it... I'm not a computer scientist and algorithms make my brain hurt.

BigEd wrote:
Interesting indeed - thanks for sharing. Would I be right in thinking that the busses are narrow - the address spaces are limited - not so much because of machine's capabilities, but because of a 40-pin periphery?

Alarm Siren wrote:
As it stands, no, it would be very difficult to expand the memory size of RAMON5 without a drastic redesign. Note that the only things which directly access memory use 8-bit registers as pointers. Making the registers 16-bit would require increasing the number of chips drastically - not that surprising, but I mean more than double the required chips, as the BSU would quadruple in terms of chips too... you'd end up needing something like 140 chips, which is impractical for homebrew construction methinks.

In principle the Instruction address space could be expanded fairly easily, though the longer the addresses the more bytes would be taken up in the already limited memory space each time you call a subroutine or interrupt, and the more cycles would be required to fetch each byte of the address in jump instructions.

I have toyed with making a RAMON6 architecture every now and then which is a 16-bit throughout machine, alieviating the memory space issues, but I've never been able to come up with something I like the feel of. I am also aware I could implement some kind of X/Y combined register scheme in an 8-bit machine as is very common (e.g. 8080) but I'm afraid that non-linear and/or segmented addressing gives me the heebee-jeebies and I'll do anything to avoid it. That includes the 6502's X&Y register addressing schemes. I know why they did it and I know its elegant in its own way, but its just a preference and I dislike it.

Fri Jun 09, 2017 10:40 am

Joined: Wed Jan 09, 2013 6:54 pm
Posts: 1644
Welcome to our world! Thanks for bringing the extra bits of the thread over with you.

Fri Jun 09, 2017 10:49 am
 Page 1 of 1 [ 2 posts ]

#### Who is online

Users browsing this forum: CCBot, PetalBot and 0 guests

 You cannot post new topics in this forumYou cannot reply to topics in this forumYou cannot edit your posts in this forumYou cannot delete your posts in this forumYou cannot post attachments in this forum

 Jump to:  Select a forum ------------------ General Discussions Newbies Software    General programming    Languages and tools    Kernels and operating systems Hardware    Hardware in general    CPU/MCU choices and designs    Implementation and Construction Programmable logic Simulation and emulation Nostalgia Projects Anycpu.org