assert Funct3.SRL == Funct3.SRLI assert Funct3.SRA == Funct3.SRAI m = Module() with m.Switch(self.funct3): with m.Case(Funct3.SLL): m.d.comb += self.res.eq(self.src1 << self.shift) with m.Case(Funct3.SRL): assert Funct3.SRL == Funct3.SRA assert Funct7.SRL != Funct7.SRA with m.If(self.funct7 == Funct7.SRL): m.d.comb += self.res.eq(self.src1 >> self.shift) with m.Elif(self.funct7 == Funct7.SRA): m.d.comb += [ self.src1signed.eq(self.src1), self.res.eq(self.src1signed >> self.shift), ] return m match_shifter_unit = matcher( [ (InstrType.OP_IMM, Funct3.SLLI, Funct7.SLLI), (InstrType.OP_IMM, Funct3.SRLI, Funct7.SRLI), (InstrType.OP_IMM, Funct3.SRAI, Funct7.SRAI), (InstrType.ALU, Funct3.SRA, Funct7.SRA), (InstrType.ALU, Funct3.SRL, Funct7.SRL), (InstrType.ALU, Funct3.SLL, Funct7.SLL), ] )
from mtkcpu.utils.common import matcher from mtkcpu.cpu.isa import InstrType match_lui = matcher([ (InstrType.LUI, ), ]) match_auipc = matcher([ (InstrType.AUIPC, ), ])
with m.Switch(self.funct3): with m.Case(Funct3.SLT): m.d.comb += self.condition_met.eq(self.negative | self.overflow) with m.Case(Funct3.SLTU): m.d.comb += self.condition_met.eq(self.carry) with m.Case(Funct3.BEQ): m.d.comb += self.condition_met.eq(self.zero) with m.Case(Funct3.BNE): m.d.comb += self.condition_met.eq(~self.zero) with m.Case(Funct3.BLT): m.d.comb += self.condition_met.eq(self.negative ^ self.overflow) with m.Case(Funct3.BGE): m.d.comb += self.condition_met.eq(~(self.negative ^ self.overflow)) with m.Case(Funct3.BLTU): m.d.comb += self.condition_met.eq(self.carry) with m.Case(Funct3.BGEU): m.d.comb += self.condition_met.eq(~self.carry) return m match_compare_unit = matcher([ (InstrType.ALU, Funct3.SLT), (InstrType.ALU, Funct3.SLTU), (InstrType.OP_IMM, Funct3.SLT), (InstrType.OP_IMM, Funct3.SLTU), ])
from mtkcpu.units.exception import ExceptionUnit from mtkcpu.utils.common import CODE_START_ADDR, EBRMemConfig from mtkcpu.units.adder import AdderUnit, match_adder_unit from mtkcpu.units.compare import CompareUnit, match_compare_unit from mtkcpu.units.loadstore import (MemoryArbiter, MemoryUnit, match_load, match_loadstore_unit) from mtkcpu.units.logic import LogicUnit, match_logic_unit from mtkcpu.units.shifter import ShifterUnit, match_shifter_unit from mtkcpu.units.upper import match_auipc, match_lui from mtkcpu.utils.common import matcher from mtkcpu.cpu.isa import Funct3, InstrType, Funct7 from mtkcpu.units.debug.top import DebugUnit from mtkcpu.cpu.priv_isa import IrqCause, TrapCause, PrivModeBits match_jal = matcher([ (InstrType.JAL, ), ]) match_jalr = matcher([ (InstrType.JALR, Funct3.JALR), ]) match_branch = matcher([ (InstrType.BRANCH, Funct3.BEQ), (InstrType.BRANCH, Funct3.BNE), (InstrType.BRANCH, Funct3.BLT), (InstrType.BRANCH, Funct3.BGE), (InstrType.BRANCH, Funct3.BLTU), (InstrType.BRANCH, Funct3.BGEU), ])
self.carry = Signal(name="adder_carry") def elaborate(self, platform): m = Module() # neat way of setting carry flag res_and_carry = Cat(self.res, self.carry) m.d.comb += res_and_carry.eq( Mux(self.sub, self.src1 - self.src2, self.src1 + self.src2)) with m.If(self.sub): with m.If((self.src1[-1] != self.src2[-1]) & (self.src1[-1] != self.res[-1])): m.d.comb += self.overflow.eq(1) with m.Else(): # add with m.If((self.src1[-1] == self.src2[-1]) & (self.src1[-1] != self.res[-1])): m.d.comb += self.overflow.eq(1) return m match_adder_unit = matcher([ (InstrType.ALU, Funct3.ADD, Funct7.ADD), (InstrType.ALU, Funct3.SUB, Funct7.SUB), (InstrType.OP_IMM, Funct3.ADD), (InstrType.OP_IMM, Funct3.SUB), ])
class LogicUnit(Elaboratable): def __init__(self): self.src1 = Signal(32, name="logic_src1") self.src2 = Signal(32, name="logic_src2") self.res = Signal(32, name="logic_res") self.funct3 = Signal(Funct3) def elaborate(self, platform): m = Module() with m.Switch(self.funct3): with m.Case(Funct3.OR): m.d.comb += self.res.eq(self.src1 | self.src2) with m.Case(Funct3.AND): m.d.comb += self.res.eq(self.src1 & self.src2) with m.Case(Funct3.XOR): m.d.comb += self.res.eq(self.src1 ^ self.src2) return m match_logic_unit = matcher( [ (InstrType.ALU, Funct3.OR, 0b0000000), (InstrType.ALU, Funct3.AND, 0b0000000), (InstrType.ALU, Funct3.XOR, 0b0000000), (InstrType.OP_IMM, Funct3.XOR), (InstrType.OP_IMM, Funct3.OR), (InstrType.OP_IMM, Funct3.AND), ] )
with m.Else(): # covers all non-waiting paths. m.next = "FINISH" with m.If(_is(func3_latch, [Funct3.CSRRS, Funct3.CSRRC])): with m.If(rs1_latch != 0): reg.handle_write() comb += need_wait.eq(1) with m.Else(): reg.handle_write() comb += need_wait.eq(1) with m.State("FINISH"): m.next = "IDLE" comb += [ self.vld.eq(1) ] return m match_csr = matcher( [ (InstrType.SYSTEM, Funct3.CSRRW), (InstrType.SYSTEM, Funct3.CSRRS), (InstrType.SYSTEM, Funct3.CSRRC), (InstrType.SYSTEM, Funct3.CSRRWI), (InstrType.SYSTEM, Funct3.CSRRSI), (InstrType.SYSTEM, Funct3.CSRRCI), ] )
def port(self, priority): if priority < 0: raise ValueError(f"Negative priority passed! {priority} < 0.") if priority in self.ports: raise ValueError( f"Conflicting priority passed to MemoryArbiter.port(): {priority}" ) port = self.ports[priority] = LoadStoreInterface() return port match_load = matcher([ (InstrType.LOAD, Funct3.W), (InstrType.LOAD, Funct3.B), (InstrType.LOAD, Funct3.BU), (InstrType.LOAD, Funct3.H), (InstrType.LOAD, Funct3.HU), ]) match_store = matcher([ (InstrType.STORE, Funct3.W), (InstrType.STORE, Funct3.B), # (InstrType.STORE, Funct3.BU), # it doesn't exist (InstrType.STORE, Funct3.H), # (InstrType.STORE, Funct3.HU), # it doesn't exist ]) def match_loadstore_unit(op, f3, f7): return match_load(op, f3, f7) | match_store(op, f3, f7)