summaryrefslogtreecommitdiff
path: root/pyscv/InstructionSets/RV32I.py
diff options
context:
space:
mode:
Diffstat (limited to 'pyscv/InstructionSets/RV32I.py')
-rw-r--r--pyscv/InstructionSets/RV32I.py466
1 files changed, 466 insertions, 0 deletions
diff --git a/pyscv/InstructionSets/RV32I.py b/pyscv/InstructionSets/RV32I.py
new file mode 100644
index 0000000..3fa02ad
--- /dev/null
+++ b/pyscv/InstructionSets/RV32I.py
@@ -0,0 +1,466 @@
+from .instructions import Instruction, InstructionSet
+from ctypes import c_uint32
+
+RV32I = InstructionSet()
+
+class R(Instruction):
+ funct3 = None
+ funct7 = None
+ opcode = None
+ def __init__(self, rd, rs1, rs2):
+ self.rd = rd
+ self.rs1 = rs1
+ self.rs2 = rs2
+
+ def compile(self):
+ # TODO: ensure sizes and convert register names to number...
+ return c_uint32(
+ (self.funct7 << 25) +\
+ (self.rs2 << 20) +\
+ (self.rs1 << 15) +\
+ (self.funct3 << 12) +\
+ (self.rd << 7) +\
+ self.opcode
+ )
+
+class I(Instruction):
+ funct3 = None
+ opcode = None
+
+ def __init__(self, rd, rs, imm):
+ self.rd = rd
+ self.rs = rs
+ self.imm = imm
+
+ def compile(self):
+ return c_uint32(
+ (self.imm << 20) +\
+ (self.rs << 15) +\
+ (self.funct3 << 12) +\
+ (self.rd << 7) +\
+ self.opcode
+ )
+
+class S(Instruction):
+ funct3 = None
+ opcode = None
+
+ def __init__(self, rs1, rs2, imm):
+ self.rs1 = rs1
+ self.rs2 = rs2
+ self.imm = imm
+
+ def compile(self):
+ imm_0_4 = self.imm & 0x1F
+ imm_5_11 = (self.imm & 0xFE0)>>5
+ return c_uint32(
+ (imm_5_11 << 25) +\
+ (self.rs1 << 20) +\
+ (self.rs2 << 15) +\
+ (self.funct3 << 12) +\
+ (imm_0_4 << 7) +\
+ self.opcode
+ )
+
+class B(Instruction):
+ funct3 = None
+ opcode = None
+
+ def __init__(self, rs1, rs2, imm):
+ self.rs1 = rs1
+ self.rs2 = rs2
+ self.imm = imm
+
+ def compile(self):
+ # NOTE: The lowest bit of the imm is always 0 because instructions
+ # are at least 16 bits wide, so it's not used, that's why this
+ # instruction looks that weird
+ imm_12 = (self.imm & 0b1000000000000)>>12
+ imm_11 = (self.imm & 0b0100000000000)>>11
+ imm_5_10 = (self.imm & 0b0011111100000)>>5
+ imm_1_4 = (self.imm & 0b0000000011110)>>1
+ return c_uint32(
+ (imm_12 << 31) +\
+ (imm_5_10 << 25) +\
+ (self.rs2 << 20) +\
+ (self.rs1 << 15) +\
+ (self.funct3 << 12) +\
+ (imm_1_4 << 8) +\
+ (imm_11 << 7) +\
+ self.opcode
+ )
+
+ def patch(imm):
+ self.imm = imm
+
+
+class U(Instruction):
+ opcode = None
+ def __init__(self, rd, imm):
+ self.rd = rd
+ self.imm = imm
+
+ def compile(self):
+ # NOTE: U Type is for AUIPC and LUI that only use the high part of the
+ # immediate
+ imm_12_32 = (self.imm & 0xFFFFF000)>>12
+ return c_uint32(
+ (imm_12_32 << 12) +\
+ (self.rd << 7) +\
+ self.opcode
+ )
+
+class J(Instruction):
+ opcode = None
+
+ def __init__(self, rd, imm):
+ self.rd = rd
+ self.imm = imm
+
+ def compile(self):
+ # NOTE: Jumps are also weird
+ imm_20 = (self.imm & 0x100000)>>20
+ imm_12_19 = (self.imm & 0x0FF000)>>12
+ imm_11 = (self.imm & 0x000800)>>11
+ imm_1_10 = (self.imm & 0x0007FE)>>1
+ return c_uint32(
+ (imm_20 << 31) +\
+ (imm_1_10 << 21) +\
+ (imm_11 << 20) +\
+ (imm_12_19 << 12) +\
+ (self.rd << 7) +\
+ self.opcode
+ )
+
+ def patch(imm):
+ self.imm = imm
+
+
+
+@RV32I.instruction
+class lui(U):
+ name = "lui"
+ opcode = 0b0110111
+
+@RV32I.instruction
+class auipc(U):
+ name = "auipc"
+ opcode = 0b0010111
+
+@RV32I.instruction
+class jal(J):
+ name = "jal"
+ opcode = 0b1101111
+
+ def execute(self, pc):
+ # TODO
+ # - Save current pc in rd
+ # - Make pc from `imm`
+ # - Return new pc
+ return pc
+
+@RV32I.instruction
+class jalr(I):
+ name = "jalr"
+ opcode = 0b1100111
+ funct3 = 0b000
+
+@RV32I.instruction
+class beq(B):
+ name = "beq"
+ opcode = 0b1100011
+ funct3 = 0b000
+
+@RV32I.instruction
+class bne(B):
+ name = "bne"
+ opcode = 0b1100011
+ funct3 = 0b001
+
+@RV32I.instruction
+class blt(B):
+ name = "blt"
+ opcode = 0b1100011
+ funct3 = 0b100
+
+@RV32I.instruction
+class bge(B):
+ name = "bge"
+ opcode = 0b1100011
+ funct3 = 0b101
+
+@RV32I.instruction
+class bltu(B):
+ name = "bltu"
+ opcode = 0b1100011
+ funct3 = 0b110
+
+@RV32I.instruction
+class bgeu(B):
+ name = "bgeu"
+ opcode = 0b1100011
+ funct3 = 0b111
+
+@RV32I.instruction
+class lb(I):
+ name = "lb"
+ opcode = 0b0000011
+ funct3 = 0b000
+
+@RV32I.instruction
+class lh(I):
+ name = "lh"
+ opcode = 0b0000011
+ funct3 = 0b001
+
+@RV32I.instruction
+class lw(I):
+ name = "lw"
+ opcode = 0b0000011
+ funct3 = 0b010
+
+@RV32I.instruction
+class lbu(I):
+ name = "lbu"
+ opcode = 0b0000011
+ funct3 = 0b100
+
+@RV32I.instruction
+class lhu(I):
+ name = "lhu"
+ opcode = 0b0000011
+ funct3 = 0b101
+
+
+@RV32I.instruction
+class sb(S):
+ name = "sb"
+ opcode = 0b0100011
+ funct3 = 0b000
+
+@RV32I.instruction
+class sh(S):
+ name = "sh"
+ opcode = 0b0100011
+ funct3 = 0b001
+
+@RV32I.instruction
+class sw(S):
+ name = "sw"
+ opcode = 0b0100011
+ funct3 = 0b010
+
+@RV32I.instruction
+class addi(I):
+ name = "addi"
+ opcode = 0b0010011
+ funct3 = 0b000
+
+ def execute(self, pc):
+ # TODO
+ return pc + self.size
+
+@RV32I.instruction
+class slti(I):
+ name = "slti"
+ opcode = 0b0010011
+ funct3 = 0b010
+
+@RV32I.instruction
+class sltiu(I):
+ name = "sltiu"
+ opcode = 0b0010011
+ funct3 = 0b011
+
+@RV32I.instruction
+class xori(I):
+ name = "xori"
+ opcode = 0b0010011
+ funct3 = 0b100
+
+@RV32I.instruction
+class ori(I):
+ name = "ori"
+ opcode = 0b0010011
+ funct3 = 0b110
+
+@RV32I.instruction
+class andi(I):
+ name = "andi"
+ opcode = 0b0010011
+ funct3 = 0b111
+
+
+class ShiftImm(I):
+ # NOTE: This is an special type used for shifting operations because they
+ # have 7 bits left after the maximum shift (5bits -> 32 rotations)
+ # they can apply.
+ # In RV64I they can indicate rotation with 1 bit more (64 rotations) so
+ # they use a funct6 instead.
+ funct7 = None
+ funct3 = None
+ opcode = None
+
+ def __init__(self, rd, rs, imm):
+ self.rd = rd
+ self.rs = rs
+ self.imm = imm
+
+ def compile(self):
+ return c_uint32(
+ (self.funct7 << 25) +\
+ (self.imm << 20) +\
+ (self.rs << 15) +\
+ (self.funct3 << 12) +\
+ (self.rd << 7) +\
+ self.opcode
+ )
+
+@RV32I.instruction
+class slli(ShiftImm):
+ name = "slli"
+ opcode = 0b0010011
+ funct3 = 0b001
+ funct7 = 0b0000000
+
+@RV32I.instruction
+class srli(ShiftImm):
+ name = "srli"
+ opcode = 0b0010011
+ funct3 = 0b101
+ funct7 = 0b0000000
+
+@RV32I.instruction
+class srai(ShiftImm):
+ name = "srai"
+ opcode = 0b0010011
+ funct3 = 0b101
+ funct7 = 0b0100000
+
+
+@RV32I.instruction
+class add(R):
+ name = "add"
+ opcode = 0b0110011
+ funct3 = 0b000
+ funct7 = 0b0000000
+
+ def execute(self, pc):
+ # TODO
+ return pc + self.size
+
+@RV32I.instruction
+class sub(R):
+ name = "sub"
+ opcode = 0b0110011
+ funct3 = 0b000
+ funct7 = 0b0100000
+
+@RV32I.instruction
+class sll(R):
+ name = "sll"
+ opcode = 0b0110011
+ funct3 = 0b001
+ funct7 = 0b0000000
+
+@RV32I.instruction
+class slt(R):
+ name = "slt"
+ opcode = 0b0110011
+ funct3 = 0b010
+ funct7 = 0b0000000
+
+@RV32I.instruction
+class sltu(R):
+ name = "sltu"
+ opcode = 0b0110011
+ funct3 = 0b011
+ funct7 = 0b0000000
+
+@RV32I.instruction
+class xor(R):
+ name = "xor"
+ opcode = 0b0110011
+ funct3 = 0b100
+ funct7 = 0b0000000
+
+@RV32I.instruction
+class srl(R):
+ name = "srl"
+ opcode = 0b0110011
+ funct3 = 0b101
+ funct7 = 0b0000000
+
+@RV32I.instruction
+class sra(R):
+ name = "sra"
+ opcode = 0b0110011
+ funct3 = 0b101
+ funct7 = 0b0100000
+
+@RV32I.instruction
+class _or(R):
+ name = "or"
+ opcode = 0b0110011
+ funct3 = 0b110
+ funct7 = 0b0000000
+
+@RV32I.instruction
+class _and(R):
+ name = "and"
+ opcode = 0b0110011
+ funct3 = 0b111
+ funct7 = 0b0000000
+
+@RV32I.instruction
+class ecall(I):
+ name = "ecall"
+ opcode = 0b1110011
+ funct3 = 0b000
+
+ def __init__(self):
+ # NOTE: ecall is a I-type instruction but doesn't get any arg and sets
+ # every field to 0
+ self.rd = 0b00000
+ self.rs = 0b00000
+ self.imm = 0b000000000000
+
+
+@RV32I.instruction
+class ebreak(I):
+ name = "ebreak"
+ opcode = 0b1110011
+ funct3 = 0b000
+
+ def __init__(self):
+ # NOTE: ebreak is a I-type instruction but doesn't get any arg and pre-
+ # -sets every field to a fixed value
+ self.rd = 0b00000
+ self.rs = 0b00000
+ self.imm = 0b000000000001
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+@RV32I.pseudoinstruction
+class j(J):
+ name = "j"
+ def __new__(cls, imm):
+ return jal("x0", imm)
+
+
+if __name__ == "__main__":
+ print(RV32I)
+ print(RV32I.instructions)