Still a few base instructions to go, but those are waiting on the privileged implementation. My game plan: - implement privileged spec (M-only), adding way to handle traps - finish implementing last of the base instructions - add in exceptions that have been ignored in all instructions - clean up main memory interface, mmaybe add some caching, at least some instruction cache.
79 lines
3.2 KiB
Python
79 lines
3.2 KiB
Python
from nmigen import *
|
|
from opcodes import Opcodes
|
|
|
|
class InstructionDecoder(Elaboratable):
|
|
def __init__(self):
|
|
#### Input
|
|
self.instr = Signal(unsigned(32))
|
|
|
|
#### Output
|
|
self.opcode = Signal(Opcodes)
|
|
self.funct3 = Signal(unsigned(3))
|
|
self.funct7 = Signal(unsigned(7))
|
|
self.imm = Signal(32)
|
|
self.immu = Signal(unsigned(32))
|
|
# Register selection
|
|
self.src1 = Signal(unsigned(5))
|
|
self.src2 = Signal(unsigned(5))
|
|
self.dest = Signal(unsigned(5))
|
|
self.base = Signal(unsigned(5))
|
|
|
|
def ports(self) -> tuple:
|
|
return (self.instr, self.opcode, self.funct3, self.imm, self.immu, self.src1, self.dest, self.base)
|
|
|
|
def elaborate(self, platform):
|
|
m = Module()
|
|
|
|
m.d.comb += self.opcode.eq(self.instr[0:6])
|
|
# Default immediate to 0 whenever we can
|
|
m.d.comb += self.imm.eq(0)
|
|
m.d.comb += self.immu.eq(0)
|
|
m.d.comb += self.dest.eq(self.instr[7:11]) # TODO will likely move back into the switch
|
|
|
|
with m.Switch(self.opcode):
|
|
# I-Type Instructions
|
|
with m.Case(Opcodes.OP_IMM, Opcodes.JALR, Opcodes.LOAD, Opcodes.MISC_MEM):
|
|
# TODO does this sign-extend?
|
|
m.d.comb += self.imm.eq(self.instr[20:31].as_signed())
|
|
m.d.comb += self.immu.eq(self.instr[20:31])
|
|
|
|
m.d.comb += self.funct3.eq(self.instr[12:14])
|
|
m.d.comb += self.src1.eq(self.instr[15:19])
|
|
|
|
# U-Type Instructions
|
|
with m.Case(Opcodes.LUI, Opcodes.AUIPC):
|
|
m.d.comb += self.imm[12:31].eq(self.instr[12:31].as_signed())
|
|
m.d.comb += self.immu[12:31].eq(self.instr[12:31])
|
|
|
|
# R-Type Instructions
|
|
with m.Case(Opcodes.OP):
|
|
m.d.comb += self.funct3.eq(self.instr[12:14])
|
|
m.d.comb += self.funct7.eq(self.instr[25:31])
|
|
m.d.comb += self.src1.eq(self.instr[15:19])
|
|
m.d.comb += self.src2.eq(self.instr[20:24])
|
|
|
|
# J-Type Instructions
|
|
with m.Case(Opcodes.JAL):
|
|
imm = Cat(Const(0, shape=1), self.instr[21:30], self.instr[20], self.instr[12:19], self.instr[31])
|
|
m.d.comb += self.imm.eq(imm.as_signed())
|
|
m.d.comb += self.immu.eq(imm.as_unsigned())
|
|
|
|
# B-Type Instructions
|
|
with m.Case(Opcodes.BRANCH):
|
|
imm = Cat(Const(0, shape=1), self.instr[8:11], self.instr[25:30], self.instr[7], self.instr[31])
|
|
m.d.comb += self.imm.eq(imm.as_signed())
|
|
m.d.comb += self.immu.eq(imm.as_unsigned())
|
|
m.d.comb += self.funct3.eq(self.instr[12:14])
|
|
m.d.comb += self.src1.eq(self.instr[15:19])
|
|
m.d.comb += self.src2.eq(self.instr[20:24])
|
|
|
|
# S-Type Instructions
|
|
with m.Case(Opcodes.STORE):
|
|
m.d.comb += self.funct3.eq(self.instr[12:14])
|
|
m.d.comb += self.base.eq(self.instr[15:19])
|
|
m.d.comb += self.src1.eq(self.instr[20:24])
|
|
m.d.comb += self.imm.eq(Cat(self.instr[7:11], self.instr[25:31]).as_signed())
|
|
m.d.comb += self.immu.eq(Cat(self.instr[7:11], self.instr[25:31]).as_unsigned())
|
|
|
|
return m
|