💾 Archived View for envs.net › ~ae › gemlog › designing-simple-isa.gmi captured on 2023-05-24 at 18:05:43. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2022-04-28)
-=-=-=-=-=-=-
Last edited: 04/12/2022
I've already mentioned this idea on my Mastodon account a while ago, but I feel like it's time to actually start working on it, now that I have very little schoolwork to do.
The main idea behind the project is to design a simple 16-bit RISC instruction set architecture that I will one day implement in hardware. Here are the design goals:
So, with that in mind, here are the basic specification:
The ISA is generally meant to be as simple as possible, with every instruction doing exclusively one thing. And by that, I mean /really/ only one thing: the only way to write constants into registers is the pl instruction, every other instruction only takes registers.
Here are the basic instructions (%W means word-sized register, %B means a byte-sized one, and $B and %W mean an integer constant):
Code Mnemonic and usage Encoding (in hex) Action ----------------------------------------------------------------------------------------------------------------------------------- 00 nop 00 00 00 00 Nothing, it does nothing. 01 plw $W, %W 01 $---$ %W Place the constant into a word-sized register. 02 plb $B, %B 02 $ %B 00 Place the constant into a byte-sized register. 03 stw %W, %W 03 %W %W 00 Store the contents of the first register to the address in the other. 04 stb %B, %W 04 %B %B 00 Same as above, but storing only a byte. 05 ldw %W, %W 05 %W %W 00 Load a word from the address in the first register into the second. 06 ldb %W, %B 06 %W %B 00 Same as above, but loading only a byte. 07 cpw %W, %W 07 %W %W 00 Copy the contents of the first register into the second. 08 cpb %B, %B 08 %B %B 00 Same as above, but copy an 8-bit register. 09 eqw %W, %W 09 %W %W 00 Compare two words and set or unset the EQ flag. 0A eqb %B, %B 0A %B %B 00 Same as above, but with bytes. 0B gtw %W, %W 0B %W %W 00 Compare two words and set the GT flag if the first value is bigger. 0C gtb %B, %B 0C %B %B 00 Same as above, but with bytes. 0D ltw %W, %W 0D %W %W 00 Same as above, with words and the LT flag. 0E ltb %B, %B 0E %B %B 00 Same as above, with bytes. 0F c0w %W 0F %W 00 00 Set the ZR flag if the register is all zeros. 10 c0b %B 10 %B 00 00 Same as above, but with bytes. 11 adw %W, %W 11 %W %W 00 Add a word to another word, store the result in the second register. 12 adb %B, %B 12 %B %B 00 Same as above, with bytes. 13 sbw %W, %W 13 %W %W 00 Subtract the first value from the second, store the result in the second. 14 sbb %B, %B 14 %B %B 00 The same thing with bytes. 15 skz 15 00 00 00 Skip the next instruction if ZR is set. 22 skn 22 00 00 00 Skip the next instruction if ZR is /not/ set. 16 skg 16 00 00 00 Skip the next instruction if GT is set. 17 skl 17 00 00 00 Skip the next instruction if LT is set. 18 skq 18 00 00 00 Skip the next instruction if EQ is set. 19 cns %W, %B, %B 19 %W %B %B Fill the word by concatenating the two bytes together (first byte goes first). 1A rdl %W, %B 1A %W %B 00 Read the first byte of the word into the register. 1B rdh %W, %B 1B %W %B 00 Same, but with the second byte. 1C anw %W, %W 1C %W %W 00 AND the two words together, store the result in the first. 1D anb %B, %B 1D %B %B 00 Same, with bytes. 1E xow %W, %W 1E %W %W 00 XOR the two words and store the result in the first. 1F xob %B, %B 1F %B %B 00 Same with bytes. 20 orw %W, %W 20 %W %W 00 OR two words together, store the result in the first. 21 orb %B, %B 21 %B %B 00 Same with bytes. 23 ngw %W 23 %W 00 00 Negate (bit by bit) the word. 24 ngb %B 24 %B 00 00 Same with bytes.
As you've probably noticed, there's no conditional jump. That's because there's no need for one: you can just use plw to set the ip to whatever you need.
Also, here's a table of the registers and flags:
The ID is decimal this time ID Name ---------- 00 ip 01 w1 02 w2 03 w3 ... 14 w14 15 sp 16 b1 ... 31 b15 Flags (one bit each): LT: lesser than GT: greater than EQ: equal ZR: zero <unallocated> <unallocated> <unallocated> <unallocated> The unallocated bits may be used for any purpose.
Technically, the stack pointer is also just a general purpose register, but it gets a special name to help prevent chaos. It can be used as a general purpose register if you want, though.
I'm still gonna work on this, it's not done yet. I promise I'll make it work soon-ish.