summaryrefslogtreecommitdiff
path: root/pyscv/InstructionSets
diff options
context:
space:
mode:
authorEkaitz Zarraga <ekaitz@elenq.tech>2021-07-23 20:49:14 +0200
committerEkaitz Zarraga <ekaitz@elenq.tech>2021-07-23 20:49:14 +0200
commit681036ddc3891904f13c84197cd90e2472cb3e1c (patch)
tree080b9580c14274698d1848e7640cba0cc47a53a6 /pyscv/InstructionSets
parent309d36182ef32a1bc5bff84f39e9e81db0ddb9a6 (diff)
Change folder nameHEADmaster
Diffstat (limited to 'pyscv/InstructionSets')
-rw-r--r--pyscv/InstructionSets/RV32C.py29
-rw-r--r--pyscv/InstructionSets/RV32D.py0
-rw-r--r--pyscv/InstructionSets/RV32F.py0
-rw-r--r--pyscv/InstructionSets/RV32I.py466
-rw-r--r--pyscv/InstructionSets/RV64I.py63
-rw-r--r--pyscv/InstructionSets/__init__.py0
-rw-r--r--pyscv/InstructionSets/instructions.py36
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")