diff options
Diffstat (limited to 'pyscv/InstructionSets')
-rw-r--r-- | pyscv/InstructionSets/RV32C.py | 29 | ||||
-rw-r--r-- | pyscv/InstructionSets/RV32D.py | 0 | ||||
-rw-r--r-- | pyscv/InstructionSets/RV32F.py | 0 | ||||
-rw-r--r-- | pyscv/InstructionSets/RV32I.py | 466 | ||||
-rw-r--r-- | pyscv/InstructionSets/RV64I.py | 63 | ||||
-rw-r--r-- | pyscv/InstructionSets/__init__.py | 0 | ||||
-rw-r--r-- | pyscv/InstructionSets/instructions.py | 36 |
7 files changed, 594 insertions, 0 deletions
diff --git a/pyscv/InstructionSets/RV32C.py b/pyscv/InstructionSets/RV32C.py new file mode 100644 index 0000000..e740ac4 --- /dev/null +++ b/pyscv/InstructionSets/RV32C.py @@ -0,0 +1,29 @@ +from instructions import Instruction, InstructionSet + +class Compressed(Instruction): + size = 2 + + +class CR(Compressed): + pass + +class CI(Compressed): + pass + +class CSS(Compressed): + pass + +class CIW(Compressed): + pass + +class CJ(Compressed): + pass + +class CB(Compressed): + pass + +class CL(Compressed): + pass + +class CS(Compressed): + pass diff --git a/pyscv/InstructionSets/RV32D.py b/pyscv/InstructionSets/RV32D.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/pyscv/InstructionSets/RV32D.py diff --git a/pyscv/InstructionSets/RV32F.py b/pyscv/InstructionSets/RV32F.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/pyscv/InstructionSets/RV32F.py 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) diff --git a/pyscv/InstructionSets/RV64I.py b/pyscv/InstructionSets/RV64I.py new file mode 100644 index 0000000..72b8bcb --- /dev/null +++ b/pyscv/InstructionSets/RV64I.py @@ -0,0 +1,63 @@ +from .instructions import Instruction, InstructionSet +from ctypes import c_uint32 +from .RV32I import * + +RV64I = InstructionSet() + +class ShiftImm64(ShiftImm): + # 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. + funct6 = 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.funct6 << 26) +\ + (self.imm << 20) +\ + (self.rs << 15) +\ + (self.funct3 << 12) +\ + (self.rd << 7) +\ + self.opcode + ) + +@RV64I.instruction +class slli(ShiftImm64): + name = "slli" + opcode = 0b0010011 + funct3 = 0b001 + funct6 = 0b000000 + +@RV64I.instruction +class srli(ShiftImm64): + name = "srli" + opcode = 0b0010011 + funct3 = 0b101 + funct6 = 0b000000 + +@RV64I.instruction +class srai(ShiftImm64): + name = "srai" + opcode = 0b0010011 + funct3 = 0b101 + funct6 = 0b010000 + +@RV64I.instruction +class sd(S): + name = "sd" + opcode = 0b0100011 + funct3 = 0b011 + +@RV64I.instruction +class ld(I): + name = "ld" + opcode = 0b0000011 + funct3 = 0b011 diff --git a/pyscv/InstructionSets/__init__.py b/pyscv/InstructionSets/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/pyscv/InstructionSets/__init__.py diff --git a/pyscv/InstructionSets/instructions.py b/pyscv/InstructionSets/instructions.py new file mode 100644 index 0000000..00a3146 --- /dev/null +++ b/pyscv/InstructionSets/instructions.py @@ -0,0 +1,36 @@ +from ctypes import c_uint32 + + +class Instruction: + size = 4 # Instruction size in bytes + + def __init__(self): + pass + + def compile(self): + # return the binstream of the instruction in a c_uint32 + pass + + def execute(self, pc): + # executes the instruction and returns the next program counter + return + +class InstructionSet: + + def __init__(self, init=None): + self.instructions = dict() + + def instruction(self, ins): + if ins.name not in self.instructions: + self.instructions[ins.name] = ins + return ins + + # NOTE: We don't need to treat pseudoinstructions in an special way yet, + # but we separate the decorator for clarity + pseudoinstruction = instruction + + +if __name__ == "__main__": + # TODO This is the interface i'd love to have + addins = add("x5","x2","zero") + j("labelName") |