AnyCPU http://anycpu.org/forum/ |
|
The RAMON5 CPU Architecture (homebrew) http://anycpu.org/forum/viewtopic.php?f=3&t=394 |
Page 1 of 1 |
Author: | Alarm Siren [ Fri Jun 09, 2017 10:40 am ] |
Post subject: | The RAMON5 CPU Architecture (homebrew) |
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:
Instructions All available instructions are listed in the table below. Some non-obvious notation I've used for the Action column:
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] 01000RRR ADD Add $0 = $0 + R 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) 10000RRR IIIIIIII ADDI Add Immediate R = R + Immediate[I] 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. |
Author: | BigEd [ Fri Jun 09, 2017 10:49 am ] |
Post subject: | Re: The RAMON5 CPU Architecture (homebrew) |
Welcome to our world! Thanks for bringing the extra bits of the thread over with you. |
Page 1 of 1 | All times are UTC |
Powered by phpBB® Forum Software © phpBB Group http://www.phpbb.com/ |