You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is a project for self-learning, and is pretty much useless except for
anyone interested in how a simple processor could be implemented. That
said, I think it's cool.
This is of course a work in progress.
Summary of features
16 bit address and databuses
16 bit opcodes
Byte and word size memory accesses, with signed/unsigned extension on byte reads
Bus error signal on unaligned word transfers
Some opcodes (like LOADI, JUMPs, BRANCHes, ALUMI, CALLs) have one following immediate value/address
8 x 16 bit general purpose registers
16 bit Program Counter
Load an immediate 16 bit quantity at the following address
Load and store instructions operate either through a register, an immediate address or a register with an immediate displacement, or the program counter with an immediate displacement
Clear instruction
Simple status bits: zero, negative, carry
ALU operations including
add, add with carry, subtract, subtract with carry, signed and unsigned 8 bit to 16 bit multiply, increment, decrement, and, or, xor, not, shift left, shift right, copy, negation, etc
ALU operations are of the form DEST <= DEST op OPERAND, or DEST <= op DEST
ALUMI operates with an immediate operand, eg. add r0,#123
Conditional and uncoditional jumps and branches: always, on each flag set or clear with don't cares
Restricting ALU ops to byte wide values might be useful, but probably not
....
Better status bits: not currently settable via an opcode, nor are they changed on anything other then an ALU instruction
This unfortuantely includes the LOADRD and STORED opcodes, which is confusing and wrong
It should be possible to do a build without multiply support, as very small FPGAs will not have sufficent resources
Top level RTL diagram (OUT OF DATE)
Opcode map
Opcode
15
14
13
12
11
10
9
8
7
6
5
4
3
2
1
0
NOP
0b000000
-
Do nothing
JUMP
0b000010
-
Flag cares
Flag polariy
If (Flags AND Flag cares = Flag polarity) then PC ← IMMEDIATE
BRANCH
0b000011
-
Flag cares
Flag polariy
If (Flags AND Flag cares = Flag polarity) then PC ← PC + IMMEDIATE
CLEAR
0b001100
-
Reg
Reg ← 0
LOADI
0b000100
Byte
Signed
-
Dst reg
Dst reg ← IMMEDIATE
LOADM
0b001000
Byte
Signed
-
Dst reg
Dst reg ← [IMMEDIATE]
STOREM
0b001001
Byte
Signed
-
Src reg
[IMMEDIATE] ← Src reg
LOADR
0b001010
Byte
Signed
-
Src addr reg
Dst reg
Dst reg ← [Src addr reg]
STORER
0b001011
Byte
Signed
-
Dst addr reg
Src reg
[Dst addr reg] ← Src reg
LOADRD
0b011010
Byte
Signed
-
Src addr reg
Dst reg
Dst reg ← [Src addr reg + IMMEDIATE]
STORERD
0b011011
Byte
Signed
-
Dst addr reg
Src reg
[Dst addr reg + IMMEDIATE] ← Src reg
LOADPCD
0b011110
Byte
Signed
-
Dst reg
Dst reg ← [PC reg + IMMEDIATE]
STOREPCD
0b011111
Byte
Signed
-
Src reg
[PC reg + IMMEDIATE] ← Src reg
ALUM
0b001110
ALU multi op
Operand reg
Dst reg
Dst reg ← Dst reg ALU mlti op Src reg
ALUS
0b001111
ALU single op
-
Dst reg
Dst reg ← ALU single op Dst reg
ALUMI
0b011000
ALU multi op
-
Dst reg
Dst reg ← Dst reg ALU multi op IMMEDIATE
CALLJUMP *
0b010000
-
Stack reg
Stack reg
Stack reg ← Stack reg - 2 ; [Stack reg] ← PC ; PC ← IMMEDIATE
CALLBRANCH
0b010001
-
Stack reg
Stack reg
Stack reg ← Stack reg - 2 ; [Stack reg] ← PC ; PC ← PC + IMMEDIATE
RETURN
0b010010
-
Stack reg
Stack reg
PC ← [Stack reg] ; Stack reg ← Stack reg + 2
PUSHQUICK
0b010100
-
Stack reg
Src reg
Stack reg ← Stack reg - 2 ; [Stack reg] ← Src reg
POPQUICK
0b010101
-
Stack reg
Dst reg
Dst reg ← [Stack reg] ; Stack reg ← Stack reg + 2
Flag cares and flag polarity
2
1
0
Carry
Zero
Negative
Registers
0b000
r0
0b001
r1
0b010
r2
0b011
r3
0b100
r4
0b101
r5
0b110
r6
0b111
r7
ALU multi (destination and operand) operations
0b0000
Add
0b0001
Add with cary
0b0010
Subtract
0b0011
Subtract with cary
0b0100
Bitwise AND
0b0101
Bitwise OR
0b0110
Bitwise XOR
0b0111
Copy
0b1000
Compare
0b1001
Bitwise test
0b1010
Unsigned 8 bit to 16 bit multiply
0b1011
Signed 8 bit to 16 bit multiply
0b1100-0b1111
Unused
ALU single (destination only) operations
0b0000
Increment
0b0001
Decrement
0b0010
Double increment
0b0011
Double decrement
0b0100
Bitwise NOT
0b0101
Left shift
0b0110
Right shift
0b0111
Negation
0b1000
Byte swap
0b1001
Compare with zero
0b1010-0b1111
Unused
Sample code
The currently used CustomASM CPU definition makes it possible to
write very presentable assembly by, for example, combing LOADI, LOADM, LOADR and LOADRD into a single "load"
mnemonic with the width represented by .w, .bu or .bs. ALU operations are similarly represented.
; prints the messsge in r2 at row r0 coloumn r1printmsg: shiftleft r0 ; word wide address so shift load.w r0,(rowoffsets,r0) ; get the start of the rowadd r0,r1 ; add the column.loop: load.bu r1,(r2) ; get the chartest r1 ; checking for null branchz printmsgo ; done? store.b (r0),r1 ; output the charinc r2 ; move to next source charinc r0 ; move to next video addr branch .loop ; get moreprintmsgo: return ; done; polls the ps2 port for a byte, returning 0 in r0 if nothing is availablegetps2byte: load.bu r0,PS2_STATUS ; get from the status regtest r0 ; nothing? branchz .nothing ; keep waiting yet.... load.bu r0,PS2_SCANCODE ; get the scancode compare r0,#0xf0 ; break? branchz .nothing ; no, carry on store.w SEVENSEG,r0 ; display it for debug return ; done.nothing: clear r0 ; return 0 return ; done