+++ /dev/null
-from functools import reduce
-from operator import or_
-from itertools import tee
-
-from nmigen import Elaboratable, Module, Record, Mux, Const, Signal, Memory
-from nmigen.lib.coding import PriorityEncoder
-
-from soc.minerva.stage import Stage
-from soc.minerva.csr import CSRFile
-from soc.minerva.units.adder import Adder
-from soc.minerva.units.compare import CompareUnit
-from soc.minerva.units.debug import DebugUnit
-from soc.minerva.units.decoder import InstructionDecoder
-from soc.minerva.units.divider import Divider, DummyDivider
-from soc.minerva.units.exception import ExceptionUnit
-from soc.minerva.units.fetch import BareFetchUnit, CachedFetchUnit, PCSelector
-from soc.minerva.units.rvficon import RVFIController, rvfi_layout
-from soc.minerva.units.loadstore import (BareLoadStoreUnit, CachedLoadStoreUnit,
- DataSelector)
-from soc.minerva.units.logic import LogicUnit
-from soc.minerva.units.multiplier import DummyMultiplier, Multiplier
-from soc.minerva.units.predict import BranchPredictor
-from soc.minerva.units.shifter import Shifter
-from soc.minerva.units.trigger import TriggerUnit
-
-from soc.minerva.units.debug.jtag import jtag_layout
-from soc.minerva.wishbone import wishbone_layout
-
-
-__all__ = ["Minerva"]
-
-
-_af_layout = [
- ("pc", (33, True)),
-]
-
-
-_fd_layout = [
- ("pc", 32),
- ("instruction", 32),
- ("fetch_error", 1),
- ("fetch_badaddr", 30)
-]
-
-
-_dx_layout = [
- ("pc", 32),
- ("instruction", 32),
- ("fetch_error", 1),
- ("fetch_badaddr", 30),
- ("illegal", 1),
- ("rd", 5),
- ("rs1", 5),
- ("rd_we", 1),
- ("rs1_re", 1),
- ("src1", 32),
- ("src2", 32),
- ("immediate", 32),
- ("bypass_x", 1),
- ("bypass_m", 1),
- ("funct3", 3),
- ("load", 1),
- ("store", 1),
- ("adder", 1),
- ("adder_sub", 1),
- ("logic", 1),
- ("multiply", 1),
- ("divide", 1),
- ("shift", 1),
- ("direction", 1),
- ("sext", 1),
- ("jump", 1),
- ("compare", 1),
- ("branch", 1),
- ("branch_target", 32),
- ("branch_predict_taken", 1),
- ("fence_i", 1),
- ("csr", 1),
- ("csr_adr", 12),
- ("csr_we", 1),
- ("ecall", 1),
- ("ebreak", 1),
- ("mret", 1),
-]
-
-
-_xm_layout = [
- ("pc", 32),
- ("instruction", 32),
- ("fetch_error", 1),
- ("fetch_badaddr", 30),
- ("illegal", 1),
- ("loadstore_misaligned", 1),
- ("ecall", 1),
- ("ebreak", 1),
- ("rd", 5),
- ("rd_we", 1),
- ("bypass_m", 1),
- ("funct3", 3),
- ("result", 32),
- ("shift", 1),
- ("load", 1),
- ("store", 1),
- ("store_data", 32),
- ("compare", 1),
- ("multiply", 1),
- ("divide", 1),
- ("condition_met", 1),
- ("branch_target", 32),
- ("branch_taken", 1),
- ("branch_predict_taken", 1),
- ("csr", 1),
- ("csr_adr", 12),
- ("csr_we", 1),
- ("csr_result", 32),
- ("mret", 1),
- ("exception", 1)
-]
-
-
-_mw_layout = [
- ("pc", 32),
- ("rd", 5),
- ("rd_we", 1),
- ("funct3", 3),
- ("result", 32),
- ("load", 1),
- ("load_data", 32),
- ("multiply", 1),
- ("exception", 1)
-]
-
-
-class Minerva(Elaboratable):
- def __init__(self, reset_address=0x00000000,
- with_icache=False,
- icache_nways=1, icache_nlines=256, icache_nwords=8, icache_base=0, icache_limit=2**31,
- with_dcache=False,
- dcache_nways=1, dcache_nlines=256, dcache_nwords=8, dcache_base=0, dcache_limit=2**31,
- with_muldiv=False,
- with_debug=False,
- with_trigger=False, nb_triggers=8,
- with_rvfi=False):
- self.external_interrupt = Signal(32)
- self.timer_interrupt = Signal()
- self.software_interrupt = Signal()
- self.ibus = Record(wishbone_layout)
- self.dbus = Record(wishbone_layout)
-
- if with_debug:
- self.jtag = Record(jtag_layout)
-
- if with_rvfi:
- self.rvfi = Record(rvfi_layout)
-
- self.reset_address = reset_address
- self.with_icache = with_icache
- self.icache_args = icache_nways, icache_nlines, icache_nwords, icache_base, icache_limit
- self.with_dcache = with_dcache
- self.dcache_args = dcache_nways, dcache_nlines, dcache_nwords, dcache_base, dcache_limit
- self.with_muldiv = with_muldiv
- self.with_debug = with_debug
- self.with_trigger = with_trigger
- self.nb_triggers = nb_triggers
- self.with_rvfi = with_rvfi
-
- def elaborate(self, platform):
- cpu = Module()
-
- # pipeline stages
-
- a = cpu.submodules.a = Stage(None, _af_layout)
- f = cpu.submodules.f = Stage(_af_layout, _fd_layout)
- d = cpu.submodules.d = Stage(_fd_layout, _dx_layout)
- x = cpu.submodules.x = Stage(_dx_layout, _xm_layout)
- m = cpu.submodules.m = Stage(_xm_layout, _mw_layout)
- w = cpu.submodules.w = Stage(_mw_layout, None)
- stages = a, f, d, x, m, w
-
- sources, sinks = tee(stages)
- next(sinks)
- for s1, s2 in zip(sources, sinks):
- cpu.d.comb += s1.source.connect(s2.sink)
-
- a.source.pc.reset = self.reset_address - 4
- cpu.d.comb += a.valid.eq(Const(1))
-
- # units
-
- pc_sel = cpu.submodules.pc_sel = PCSelector()
- data_sel = cpu.submodules.data_sel = DataSelector()
- adder = cpu.submodules.adder = Adder()
- compare = cpu.submodules.compare = CompareUnit()
- decoder = cpu.submodules.decoder = InstructionDecoder(self.with_muldiv)
- exception = cpu.submodules.exception = ExceptionUnit()
- logic = cpu.submodules.logic = LogicUnit()
- predict = cpu.submodules.predict = BranchPredictor()
- shifter = cpu.submodules.shifter = Shifter()
-
- if self.with_icache:
- fetch = cpu.submodules.fetch = CachedFetchUnit(*self.icache_args)
- else:
- fetch = cpu.submodules.fetch = BareFetchUnit()
-
- if self.with_dcache:
- loadstore = cpu.submodules.loadstore = CachedLoadStoreUnit(
- *self.dcache_args)
- else:
- loadstore = cpu.submodules.loadstore = BareLoadStoreUnit()
-
- if self.with_muldiv:
- multiplier = Multiplier() if not self.with_rvfi else DummyMultiplier()
- divider = Divider() if not self.with_rvfi else DummyDivider()
- cpu.submodules.multiplier = multiplier
- cpu.submodules.divider = divider
-
- if self.with_debug:
- debug = cpu.submodules.debug = DebugUnit()
-
- if self.with_trigger:
- trigger = cpu.submodules.trigger = TriggerUnit(self.nb_triggers)
-
- if self.with_rvfi:
- rvficon = cpu.submodules.rvficon = RVFIController()
-
- # register files
-
- gprf = Memory(width=32, depth=32)
- gprf_rp1 = gprf.read_port()
- gprf_rp2 = gprf.read_port()
- gprf_wp = gprf.write_port()
- cpu.submodules += gprf_rp1, gprf_rp2, gprf_wp
-
- csrf = cpu.submodules.csrf = CSRFile()
- csrf_rp = csrf.read_port()
- csrf_wp = csrf.write_port()
-
- csrf.add_csrs(exception.iter_csrs())
- if self.with_debug:
- csrf.add_csrs(debug.iter_csrs())
- if self.with_trigger:
- csrf.add_csrs(trigger.iter_csrs())
-
- # pipeline logic
-
- cpu.d.comb += [
- pc_sel.f_pc.eq(f.sink.pc),
- pc_sel.d_pc.eq(d.sink.pc),
- pc_sel.d_branch_predict_taken.eq(
- predict.d_branch_taken & ~predict.d_fetch_misaligned),
- pc_sel.d_branch_target.eq(predict.d_branch_target),
- pc_sel.d_valid.eq(d.valid),
- pc_sel.x_pc.eq(x.sink.pc),
- pc_sel.x_fence_i.eq(x.sink.fence_i),
- pc_sel.x_valid.eq(x.valid),
- pc_sel.m_branch_predict_taken.eq(m.sink.branch_predict_taken),
- pc_sel.m_branch_taken.eq(m.sink.branch_taken),
- pc_sel.m_branch_target.eq(m.sink.branch_target),
- pc_sel.m_exception.eq(exception.m_raise),
- pc_sel.m_mret.eq(m.sink.mret),
- pc_sel.m_valid.eq(m.valid),
- pc_sel.mtvec_r_base.eq(exception.mtvec.r.base),
- pc_sel.mepc_r_base.eq(exception.mepc.r.base)
- ]
-
- cpu.d.comb += [
- fetch.a_pc.eq(pc_sel.a_pc),
- fetch.a_stall.eq(a.stall),
- fetch.a_valid.eq(a.valid),
- fetch.f_stall.eq(f.stall),
- fetch.f_valid.eq(f.valid),
- fetch.ibus.connect(self.ibus)
- ]
-
- m.stall_on(fetch.a_busy & a.valid)
- m.stall_on(fetch.f_busy & f.valid)
-
- if self.with_icache:
- flush_icache = x.sink.fence_i & x.valid & ~x.stall
- if self.with_debug:
- flush_icache |= debug.resumereq
-
- cpu.d.comb += [
- fetch.a_flush.eq(flush_icache),
- fetch.f_pc.eq(f.sink.pc)
- ]
-
- cpu.d.comb += [
- decoder.instruction.eq(d.sink.instruction)
- ]
-
- if self.with_debug:
- with cpu.If(debug.halt & debug.halted):
- cpu.d.comb += gprf_rp1.addr.eq(debug.gprf_addr)
- with cpu.Elif(~d.stall):
- cpu.d.comb += gprf_rp1.addr.eq(fetch.f_instruction[15:20])
- with cpu.Else():
- cpu.d.comb += gprf_rp1.addr.eq(decoder.rs1)
-
- cpu.d.comb += debug.gprf_dat_r.eq(gprf_rp1.data)
- else:
- with cpu.If(~d.stall):
- cpu.d.comb += gprf_rp1.addr.eq(fetch.f_instruction[15:20])
- with cpu.Else():
- cpu.d.comb += gprf_rp1.addr.eq(decoder.rs1)
-
- with cpu.If(~d.stall):
- cpu.d.comb += gprf_rp2.addr.eq(fetch.f_instruction[20:25])
- with cpu.Else():
- cpu.d.comb += gprf_rp2.addr.eq(decoder.rs2)
-
- with cpu.If(~f.stall):
- cpu.d.sync += csrf_rp.addr.eq(fetch.f_instruction[20:32])
- cpu.d.comb += csrf_rp.en.eq(decoder.csr & d.valid)
-
- # CSR set/clear instructions are translated to logic operations.
- x_csr_set_clear = x.sink.funct3[1]
- x_csr_clear = x_csr_set_clear & x.sink.funct3[0]
- x_csr_fmt_i = x.sink.funct3[2]
- x_csr_src1 = Mux(x_csr_fmt_i, x.sink.rs1, x.sink.src1)
- x_csr_src1 = Mux(x_csr_clear, ~x_csr_src1, x_csr_src1)
- x_csr_logic_op = x.sink.funct3 | 0b100
-
- cpu.d.comb += [
- logic.op.eq(Mux(x.sink.csr, x_csr_logic_op, x.sink.funct3)),
- logic.src1.eq(Mux(x.sink.csr, x_csr_src1, x.sink.src1)),
- logic.src2.eq(x.sink.src2)
- ]
-
- cpu.d.comb += [
- adder.sub.eq(x.sink.adder & x.sink.adder_sub |
- x.sink.compare | x.sink.branch),
- adder.src1.eq(x.sink.src1),
- adder.src2.eq(Mux(x.sink.store, x.sink.immediate, x.sink.src2))
- ]
-
- if self.with_muldiv:
- cpu.d.comb += [
- multiplier.x_op.eq(x.sink.funct3),
- multiplier.x_src1.eq(x.sink.src1),
- multiplier.x_src2.eq(x.sink.src2),
- multiplier.x_stall.eq(x.stall),
- multiplier.m_stall.eq(m.stall)
- ]
-
- cpu.d.comb += [
- divider.x_op.eq(x.sink.funct3),
- divider.x_src1.eq(x.sink.src1),
- divider.x_src2.eq(x.sink.src2),
- divider.x_valid.eq(x.sink.valid),
- divider.x_stall.eq(x.stall)
- ]
-
- m.stall_on(divider.m_busy)
-
- cpu.d.comb += [
- shifter.x_direction.eq(x.sink.direction),
- shifter.x_sext.eq(x.sink.sext),
- shifter.x_shamt.eq(x.sink.src2),
- shifter.x_src1.eq(x.sink.src1),
- shifter.x_stall.eq(x.stall)
- ]
-
- cpu.d.comb += [
- # compare.op is shared by compare and branch instructions.
- compare.op.eq(
- Mux(x.sink.compare, x.sink.funct3 << 1, x.sink.funct3)),
- compare.zero.eq(x.sink.src1 == x.sink.src2),
- compare.negative.eq(adder.result[-1]),
- compare.overflow.eq(adder.overflow),
- compare.carry.eq(adder.carry)
- ]
-
- cpu.d.comb += [
- exception.external_interrupt.eq(self.external_interrupt),
- exception.timer_interrupt.eq(self.timer_interrupt),
- exception.software_interrupt.eq(self.software_interrupt),
- exception.m_fetch_misaligned.eq(
- m.sink.branch_taken & m.sink.branch_target[:2].bool()),
- exception.m_fetch_error.eq(m.sink.fetch_error),
- exception.m_fetch_badaddr.eq(m.sink.fetch_badaddr),
- exception.m_load_misaligned.eq(
- m.sink.load & m.sink.loadstore_misaligned),
- exception.m_load_error.eq(loadstore.m_load_error),
- exception.m_store_misaligned.eq(
- m.sink.store & m.sink.loadstore_misaligned),
- exception.m_store_error.eq(loadstore.m_store_error),
- exception.m_loadstore_badaddr.eq(loadstore.m_badaddr),
- exception.m_branch_target.eq(m.sink.branch_target),
- exception.m_illegal.eq(m.sink.illegal),
- exception.m_ecall.eq(m.sink.ecall),
- exception.m_pc.eq(m.sink.pc),
- exception.m_instruction.eq(m.sink.instruction),
- exception.m_result.eq(m.sink.result),
- exception.m_mret.eq(m.sink.mret),
- exception.m_stall.eq(m.sink.stall),
- exception.m_valid.eq(m.valid)
- ]
-
- m_ebreak = m.sink.ebreak
- if self.with_debug:
- # If dcsr.ebreakm is set, EBREAK instructions enter Debug Mode.
- # We do not want to raise an exception in this case because Debug Mode
- # should be invisible to software execution.
- m_ebreak &= ~debug.dcsr_ebreakm
- if self.with_trigger:
- m_ebreak |= trigger.trap
- cpu.d.comb += exception.m_ebreak.eq(m_ebreak)
-
- m.kill_on(m.source.exception & m.source.valid)
-
- cpu.d.comb += [
- data_sel.x_offset.eq(adder.result[:2]),
- data_sel.x_funct3.eq(x.sink.funct3),
- data_sel.x_store_operand.eq(x.sink.src2),
- data_sel.w_offset.eq(w.sink.result[:2]),
- data_sel.w_funct3.eq(w.sink.funct3),
- data_sel.w_load_data.eq(w.sink.load_data)
- ]
-
- cpu.d.comb += [
- loadstore.x_addr.eq(adder.result),
- loadstore.x_mask.eq(data_sel.x_mask),
- loadstore.x_load.eq(x.sink.load),
- loadstore.x_store.eq(x.sink.store),
- loadstore.x_store_data.eq(data_sel.x_store_data),
- loadstore.x_stall.eq(x.stall),
- loadstore.x_valid.eq(x.valid),
- loadstore.m_stall.eq(m.stall),
- loadstore.m_valid.eq(m.valid)
- ]
-
- m.stall_on(loadstore.x_busy & x.valid)
- m.stall_on(loadstore.m_busy & m.valid)
-
- if self.with_dcache:
- if self.with_debug:
- cpu.d.comb += loadstore.x_flush.eq(debug.resumereq)
-
- cpu.d.comb += [
- loadstore.x_fence_i.eq(x.sink.fence_i),
- loadstore.m_addr.eq(m.sink.result),
- loadstore.m_load.eq(m.sink.load),
- loadstore.m_store.eq(m.sink.store),
- ]
-
- x.stall_on(loadstore.x_busy & x.valid)
-
- for s in a, f:
- s.kill_on(x.sink.fence_i & x.valid)
-
- if self.with_debug:
- with cpu.If(debug.halt & debug.halted):
- cpu.d.comb += debug.dbus.connect(self.dbus)
- with cpu.Else():
- cpu.d.comb += loadstore.dbus.connect(self.dbus)
- else:
- cpu.d.comb += loadstore.dbus.connect(self.dbus)
-
- # RAW hazard management
-
- x_raw_rs1 = Signal()
- m_raw_rs1 = Signal()
- w_raw_rs1 = Signal()
- x_raw_rs2 = Signal()
- m_raw_rs2 = Signal()
- w_raw_rs2 = Signal()
-
- x_raw_csr = Signal()
- m_raw_csr = Signal()
-
- x_lock = Signal()
- m_lock = Signal()
-
- cpu.d.comb += [
- x_raw_rs1.eq((x.sink.rd != 0) & (
- x.sink.rd == decoder.rs1) & x.sink.rd_we),
- m_raw_rs1.eq((m.sink.rd != 0) & (
- m.sink.rd == decoder.rs1) & m.sink.rd_we),
- w_raw_rs1.eq((w.sink.rd != 0) & (
- w.sink.rd == decoder.rs1) & w.sink.rd_we),
-
- x_raw_rs2.eq((x.sink.rd != 0) & (
- x.sink.rd == decoder.rs2) & x.sink.rd_we),
- m_raw_rs2.eq((m.sink.rd != 0) & (
- m.sink.rd == decoder.rs2) & m.sink.rd_we),
- w_raw_rs2.eq((w.sink.rd != 0) & (
- w.sink.rd == decoder.rs2) & w.sink.rd_we),
-
- x_raw_csr.eq((x.sink.csr_adr == decoder.immediate)
- & x.sink.csr_we),
- m_raw_csr.eq((m.sink.csr_adr == decoder.immediate)
- & m.sink.csr_we),
-
- x_lock.eq(~x.sink.bypass_x & (decoder.rs1_re & x_raw_rs1 |
- decoder.rs2_re & x_raw_rs2) | decoder.csr & x_raw_csr),
- m_lock.eq(~m.sink.bypass_m & (decoder.rs1_re & m_raw_rs1 |
- decoder.rs2_re & m_raw_rs2) | decoder.csr & m_raw_csr)
- ]
-
- if self.with_debug:
- d.stall_on((x_lock & x.valid | m_lock & m.valid)
- & d.valid & ~debug.dcsr_step)
- else:
- d.stall_on((x_lock & x.valid | m_lock & m.valid) & d.valid)
-
- # result selection
-
- x_result = Signal(32)
- m_result = Signal(32)
- w_result = Signal(32)
- x_csr_result = Signal(32)
-
- with cpu.If(x.sink.jump):
- cpu.d.comb += x_result.eq(x.sink.pc + 4)
- with cpu.Elif(x.sink.logic):
- cpu.d.comb += x_result.eq(logic.result)
- with cpu.Elif(x.sink.csr):
- cpu.d.comb += x_result.eq(x.sink.src2)
- with cpu.Else():
- cpu.d.comb += x_result.eq(adder.result)
-
- with cpu.If(m.sink.compare):
- cpu.d.comb += m_result.eq(m.sink.condition_met)
- if self.with_muldiv:
- with cpu.Elif(m.sink.divide):
- cpu.d.comb += m_result.eq(divider.m_result)
- with cpu.Elif(m.sink.shift):
- cpu.d.comb += m_result.eq(shifter.m_result)
- with cpu.Else():
- cpu.d.comb += m_result.eq(m.sink.result)
-
- with cpu.If(w.sink.load):
- cpu.d.comb += w_result.eq(data_sel.w_load_result)
- if self.with_muldiv:
- with cpu.Elif(w.sink.multiply):
- cpu.d.comb += w_result.eq(multiplier.w_result)
- with cpu.Else():
- cpu.d.comb += w_result.eq(w.sink.result)
-
- with cpu.If(x_csr_set_clear):
- cpu.d.comb += x_csr_result.eq(logic.result)
- with cpu.Else():
- cpu.d.comb += x_csr_result.eq(x_csr_src1)
-
- cpu.d.comb += [
- csrf_wp.en.eq(m.sink.csr & m.sink.csr_we & m.valid &
- ~exception.m_raise & ~m.stall),
- csrf_wp.addr.eq(m.sink.csr_adr),
- csrf_wp.data.eq(m.sink.csr_result)
- ]
-
- if self.with_debug:
- with cpu.If(debug.halt & debug.halted):
- cpu.d.comb += [
- gprf_wp.addr.eq(debug.gprf_addr),
- gprf_wp.en.eq(debug.gprf_we),
- gprf_wp.data.eq(debug.gprf_dat_w)
- ]
- with cpu.Else():
- cpu.d.comb += [
- gprf_wp.en.eq((w.sink.rd != 0) & w.sink.rd_we &
- w.valid & ~w.sink.exception),
- gprf_wp.addr.eq(w.sink.rd),
- gprf_wp.data.eq(w_result)
- ]
- else:
- cpu.d.comb += [
- gprf_wp.en.eq((w.sink.rd != 0) & w.sink.rd_we & w.valid),
- gprf_wp.addr.eq(w.sink.rd),
- gprf_wp.data.eq(w_result)
- ]
-
- # D stage operand selection
-
- d_src1 = Signal(32)
- d_src2 = Signal(32)
-
- with cpu.If(decoder.lui):
- cpu.d.comb += d_src1.eq(0)
- with cpu.Elif(decoder.auipc):
- cpu.d.comb += d_src1.eq(d.sink.pc)
- with cpu.Elif(decoder.rs1_re & (decoder.rs1 == 0)):
- cpu.d.comb += d_src1.eq(0)
- with cpu.Elif(x_raw_rs1 & x.valid):
- cpu.d.comb += d_src1.eq(x_result)
- with cpu.Elif(m_raw_rs1 & m.valid):
- cpu.d.comb += d_src1.eq(m_result)
- with cpu.Elif(w_raw_rs1 & w.valid):
- cpu.d.comb += d_src1.eq(w_result)
- with cpu.Else():
- cpu.d.comb += d_src1.eq(gprf_rp1.data)
-
- with cpu.If(decoder.csr):
- cpu.d.comb += d_src2.eq(csrf_rp.data)
- with cpu.Elif(~decoder.rs2_re):
- cpu.d.comb += d_src2.eq(decoder.immediate)
- with cpu.Elif(decoder.rs2 == 0):
- cpu.d.comb += d_src2.eq(0)
- with cpu.Elif(x_raw_rs2 & x.valid):
- cpu.d.comb += d_src2.eq(x_result)
- with cpu.Elif(m_raw_rs2 & m.valid):
- cpu.d.comb += d_src2.eq(m_result)
- with cpu.Elif(w_raw_rs2 & w.valid):
- cpu.d.comb += d_src2.eq(w_result)
- with cpu.Else():
- cpu.d.comb += d_src2.eq(gprf_rp2.data)
-
- # branch prediction
-
- cpu.d.comb += [
- predict.d_branch.eq(decoder.branch),
- predict.d_jump.eq(decoder.jump),
- predict.d_offset.eq(decoder.immediate),
- predict.d_pc.eq(d.sink.pc),
- predict.d_rs1_re.eq(decoder.rs1_re)
- ]
-
- a.kill_on(predict.d_branch_taken & ~
- predict.d_fetch_misaligned & d.valid)
- for s in a, f:
- s.kill_on(m.sink.branch_predict_taken & ~
- m.sink.branch_taken & m.valid)
- for s in a, f, d:
- s.kill_on(~m.sink.branch_predict_taken &
- m.sink.branch_taken & m.valid)
- s.kill_on((exception.m_raise | m.sink.mret) & m.valid)
-
- # debug unit
-
- if self.with_debug:
- cpu.d.comb += [
- debug.jtag.connect(self.jtag),
- debug.x_pc.eq(x.sink.pc),
- debug.x_ebreak.eq(x.sink.ebreak),
- debug.x_stall.eq(x.stall),
- debug.m_branch_taken.eq(m.sink.branch_taken),
- debug.m_branch_target.eq(m.sink.branch_target),
- debug.m_mret.eq(m.sink.mret),
- debug.m_exception.eq(exception.m_raise),
- debug.m_pc.eq(m.sink.pc),
- debug.m_valid.eq(m.valid),
- debug.mepc_r_base.eq(exception.mepc.r.base),
- debug.mtvec_r_base.eq(exception.mtvec.r.base)
- ]
-
- if self.with_trigger:
- cpu.d.comb += debug.trigger_haltreq.eq(trigger.haltreq)
- else:
- cpu.d.comb += debug.trigger_haltreq.eq(Const(0))
-
- csrf_debug_rp = csrf.read_port()
- csrf_debug_wp = csrf.write_port()
- cpu.d.comb += [
- csrf_debug_rp.addr.eq(debug.csrf_addr),
- csrf_debug_rp.en.eq(debug.csrf_re),
- debug.csrf_dat_r.eq(csrf_debug_rp.data),
- csrf_debug_wp.addr.eq(debug.csrf_addr),
- csrf_debug_wp.en.eq(debug.csrf_we),
- csrf_debug_wp.data.eq(debug.csrf_dat_w)
- ]
-
- x.stall_on(debug.halt)
- m.stall_on(debug.dcsr_step & m.valid & ~debug.halt)
- for s in a, f, d, x:
- s.kill_on(debug.killall)
-
- halted = x.stall & ~reduce(or_, (s.valid for s in (m, w)))
- cpu.d.sync += debug.halted.eq(halted)
-
- with cpu.If(debug.resumereq):
- with cpu.If(~debug.dbus_busy):
- cpu.d.comb += debug.resumeack.eq(1)
- cpu.d.sync += a.source.pc.eq(debug.dpc_value - 4)
-
- if self.with_trigger:
- cpu.d.comb += [
- trigger.x_pc.eq(x.sink.pc),
- trigger.x_valid.eq(x.valid),
- ]
-
- if self.with_rvfi:
- cpu.d.comb += [
- rvficon.d_insn.eq(decoder.instruction),
- rvficon.d_rs1_addr.eq(Mux(decoder.rs1_re, decoder.rs1, 0)),
- rvficon.d_rs2_addr.eq(Mux(decoder.rs2_re, decoder.rs2, 0)),
- rvficon.d_rs1_rdata.eq(Mux(decoder.rs1_re, d_src1, 0)),
- rvficon.d_rs2_rdata.eq(Mux(decoder.rs2_re, d_src2, 0)),
- rvficon.d_stall.eq(d.stall),
- rvficon.x_mem_addr.eq(loadstore.x_addr[2:] << 2),
- rvficon.x_mem_wmask.eq(
- Mux(loadstore.x_store, loadstore.x_mask, 0)),
- rvficon.x_mem_rmask.eq(
- Mux(loadstore.x_load, loadstore.x_mask, 0)),
- rvficon.x_mem_wdata.eq(loadstore.x_store_data),
- rvficon.x_stall.eq(x.stall),
- rvficon.m_mem_rdata.eq(loadstore.m_load_data),
- rvficon.m_fetch_misaligned.eq(exception.m_fetch_misaligned),
- rvficon.m_illegal_insn.eq(m.sink.illegal),
- rvficon.m_load_misaligned.eq(exception.m_load_misaligned),
- rvficon.m_store_misaligned.eq(exception.m_store_misaligned),
- rvficon.m_exception.eq(exception.m_raise),
- rvficon.m_mret.eq(m.sink.mret),
- rvficon.m_branch_taken.eq(m.sink.branch_taken),
- rvficon.m_branch_target.eq(m.sink.branch_target),
- rvficon.m_pc_rdata.eq(m.sink.pc),
- rvficon.m_stall.eq(m.stall),
- rvficon.m_valid.eq(m.valid),
- rvficon.w_rd_addr.eq(Mux(gprf_wp.en, gprf_wp.addr, 0)),
- rvficon.w_rd_wdata.eq(Mux(gprf_wp.en, gprf_wp.data, 0)),
- rvficon.mtvec_r_base.eq(exception.mtvec.r.base),
- rvficon.mepc_r_value.eq(exception.mepc.r),
- rvficon.rvfi.connect(self.rvfi)
- ]
-
- # pipeline registers
-
- # A/F
- with cpu.If(~a.stall):
- cpu.d.sync += a.source.pc.eq(fetch.a_pc)
-
- # F/D
- with cpu.If(~f.stall):
- cpu.d.sync += [
- f.source.pc.eq(f.sink.pc),
- f.source.instruction.eq(fetch.f_instruction),
- f.source.fetch_error.eq(fetch.f_fetch_error),
- f.source.fetch_badaddr.eq(fetch.f_badaddr)
- ]
-
- # D/X
- with cpu.If(~d.stall):
- cpu.d.sync += [
- d.source.pc.eq(d.sink.pc),
- d.source.instruction.eq(d.sink.instruction),
- d.source.fetch_error.eq(d.sink.fetch_error),
- d.source.fetch_badaddr.eq(d.sink.fetch_badaddr),
- d.source.illegal.eq(decoder.illegal),
- d.source.rd.eq(decoder.rd),
- d.source.rs1.eq(decoder.rs1),
- d.source.rd_we.eq(decoder.rd_we),
- d.source.rs1_re.eq(decoder.rs1_re),
- d.source.immediate.eq(decoder.immediate),
- d.source.bypass_x.eq(decoder.bypass_x),
- d.source.bypass_m.eq(decoder.bypass_m),
- d.source.funct3.eq(decoder.funct3),
- d.source.load.eq(decoder.load),
- d.source.store.eq(decoder.store),
- d.source.adder.eq(decoder.adder),
- d.source.adder_sub.eq(decoder.adder_sub),
- d.source.compare.eq(decoder.compare),
- d.source.logic.eq(decoder.logic),
- d.source.shift.eq(decoder.shift),
- d.source.direction.eq(decoder.direction),
- d.source.sext.eq(decoder.sext),
- d.source.jump.eq(decoder.jump),
- d.source.branch.eq(decoder.branch),
- d.source.fence_i.eq(decoder.fence_i),
- d.source.csr.eq(decoder.csr),
- d.source.csr_adr.eq(decoder.immediate),
- d.source.csr_we.eq(decoder.csr_we),
- d.source.ecall.eq(decoder.ecall),
- d.source.ebreak.eq(decoder.ebreak),
- d.source.mret.eq(decoder.mret),
- d.source.src1.eq(d_src1),
- d.source.src2.eq(d_src2),
- d.source.branch_predict_taken.eq(
- predict.d_branch_taken & ~predict.d_fetch_misaligned),
- d.source.branch_target.eq(predict.d_branch_target)
- ]
- if self.with_muldiv:
- cpu.d.sync += [
- d.source.multiply.eq(decoder.multiply),
- d.source.divide.eq(decoder.divide)
- ]
-
- # X/M
- with cpu.If(~x.stall):
- cpu.d.sync += [
- x.source.pc.eq(x.sink.pc),
- x.source.instruction.eq(x.sink.instruction),
- x.source.fetch_error.eq(x.sink.fetch_error),
- x.source.fetch_badaddr.eq(x.sink.fetch_badaddr),
- x.source.illegal.eq(x.sink.illegal),
- x.source.loadstore_misaligned.eq(data_sel.x_misaligned),
- x.source.ecall.eq(x.sink.ecall),
- x.source.ebreak.eq(x.sink.ebreak),
- x.source.rd.eq(x.sink.rd),
- x.source.rd_we.eq(x.sink.rd_we),
- x.source.bypass_m.eq(x.sink.bypass_m | x.sink.bypass_x),
- x.source.funct3.eq(x.sink.funct3),
- x.source.load.eq(x.sink.load),
- x.source.store.eq(x.sink.store),
- x.source.store_data.eq(loadstore.x_store_data),
- x.source.compare.eq(x.sink.compare),
- x.source.shift.eq(x.sink.shift),
- x.source.mret.eq(x.sink.mret),
- x.source.condition_met.eq(compare.condition_met),
- x.source.branch_taken.eq(
- x.sink.jump | x.sink.branch & compare.condition_met),
- x.source.branch_target.eq(
- Mux(x.sink.jump & x.sink.rs1_re, adder.result[1:] << 1, x.sink.branch_target)),
- x.source.branch_predict_taken.eq(x.sink.branch_predict_taken),
- x.source.csr.eq(x.sink.csr),
- x.source.csr_adr.eq(x.sink.csr_adr),
- x.source.csr_we.eq(x.sink.csr_we),
- x.source.csr_result.eq(x_csr_result),
- x.source.result.eq(x_result)
- ]
- if self.with_muldiv:
- cpu.d.sync += [
- x.source.multiply.eq(x.sink.multiply),
- x.source.divide.eq(x.sink.divide)
- ]
-
- # M/W
- with cpu.If(~m.stall):
- cpu.d.sync += [
- m.source.pc.eq(m.sink.pc),
- m.source.rd.eq(m.sink.rd),
- m.source.load.eq(m.sink.load),
- m.source.funct3.eq(m.sink.funct3),
- m.source.load_data.eq(loadstore.m_load_data),
- m.source.rd_we.eq(m.sink.rd_we),
- m.source.result.eq(m_result),
- m.source.exception.eq(exception.m_raise)
- ]
- if self.with_muldiv:
- cpu.d.sync += [
- m.source.multiply.eq(m.sink.multiply)
- ]
-
- return cpu
+++ /dev/null
-from enum import Enum
-from collections import OrderedDict
-
-from nmigen import (Const, Elaboratable, Module, Mux,
- Record, Signal,)
-from nmigen.utils import bits_for
-
-
-__all__ = ["CSRAccess", "CSR", "AutoCSR", "CSRFile"]
-
-
-CSRAccess = Enum("CSRAccess", ("WIRI", "WPRI", "WLRL", "WARL"))
-
-
-class CSR():
- def __init__(self, addr, description, name):
- fields = []
- mask = 0
- offset = 0
- for name, shape, access in description:
- if isinstance(shape, int):
- shape = shape, False
- nbits, signed = shape
- fields.append((name, shape))
- if access in {CSRAccess.WLRL, CSRAccess.WARL}:
- mask |= ((1 << nbits) - 1) << offset
- offset += nbits
-
- self.addr = addr
- self.rmask = self.wmask = Const(mask)
- self.r = Record(fields)
- self.w = Record(fields)
- self.re = Signal()
- self.we = Signal()
-
-
-class AutoCSR():
- def iter_csrs(self):
- for v in vars(self).values():
- if isinstance(v, CSR):
- yield v
- elif hasattr(v, "iter_csrs"):
- yield from v.iter_csrs()
-
-
-class CSRFile(Elaboratable):
- def __init__(self, width=32, depth=2**12):
- self.width = width
- self.depth = depth
- self._csr_map = OrderedDict()
- self._read_ports = []
- self._write_ports = []
-
- def add_csrs(self, csrs):
- for csr in csrs:
- if not isinstance(csr, CSR):
- raise TypeError("Object {!r} is not a CSR".format(csr))
- if csr.addr in self._csr_map:
- raise ValueError("CSR address 0x{:x} has already been allocated"
- .format(csr.addr))
- self._csr_map[csr.addr] = csr
-
- def read_port(self):
- port = Record([("addr", bits_for(self.depth)), ("en", 1), ("data", self.width)])
- self._read_ports.append(port)
- return port
-
- def write_port(self):
- port = Record([("addr", bits_for(self.depth)), ("en", 1), ("data", self.width)])
- self._write_ports.append(port)
- return port
-
- def elaborate(self, platform):
- m = Module()
-
- for rp in self._read_ports:
- with m.Switch(rp.addr):
- for addr, csr in self._csr_map.items():
- with m.Case(addr):
- m.d.comb += [
- csr.re.eq(rp.en),
- rp.data.eq(csr.r & csr.rmask)
- ]
-
- for wp in self._write_ports:
- with m.Switch(wp.addr):
- for addr, csr in self._csr_map.items():
- with m.Case(addr):
- m.d.comb += [
- csr.we.eq(wp.en),
- csr.w.eq(wp.data & csr.wmask)
- ]
-
- return m
+++ /dev/null
-from soc.minerva.csr import CSRAccess
-
-
-__all__ = [
- "Opcode", "Funct3", "Funct7", "Funct12", "CSRIndex", "Cause",
- "flat_layout", "misa_layout", "mstatus_layout", "mtvec_layout", "mepc_layout",
- "mip_layout", "mie_layout", "mcause_layout", "dcsr_layout", "tdata1_layout"
-]
-
-class Opcode:
- LUI = 0b01101
- AUIPC = 0b00101
- JAL = 0b11011
- JALR = 0b11001
- BRANCH = 0b11000
- LOAD = 0b00000
- STORE = 0b01000
- OP_IMM_32 = 0b00100
- OP_32 = 0b01100
- MISC_MEM = 0b00011
- SYSTEM = 0b11100
-
-
-class Funct3:
- BEQ = B = ADD = FENCE = PRIV = MUL = 0b000
- BNE = H = SLL = FENCEI = CSRRW = MULH = 0b001
- _ = W = SLT = _ = CSRRS = MULHSU = 0b010
- _ = _ = SLTU = _ = CSRRC = MULHU = 0b011
- BLT = BU = XOR = _ = _ = DIV = 0b100
- BGE = HU = SR = _ = CSRRWI = DIVU = 0b101
- BLTU = _ = OR = _ = CSRRSI = REM = 0b110
- BGEU = _ = AND = _ = CSRRCI = REMU = 0b111
-
-
-class Funct7:
- SRL = ADD = 0b0000000
- MULDIV = 0b0000001
- SRA = SUB = 0b0100000
-
-
-class Funct12:
- ECALL = 0b000000000000
- EBREAK = 0b000000000001
- MRET = 0b001100000010
- WFI = 0b000100000101
-
-
-class CSRIndex:
- MVENDORID = 0xF11
- MARCHID = 0xF12
- MIMPID = 0xF13
- MHARTID = 0xF14
- MSTATUS = 0x300
- MISA = 0x301
- MEDELEG = 0x302
- MIDELEG = 0x303
- MIE = 0x304
- MTVEC = 0x305
- MCOUTEREN = 0x306
- MSCRATCH = 0x340
- MEPC = 0x341
- MCAUSE = 0x342
- MTVAL = 0x343
- MIP = 0x344
- # µarch specific
- IRQ_MASK = 0x330
- IRQ_PENDING = 0x360
- # trigger module
- TSELECT = 0x7a0
- TDATA1 = 0x7a1
- TDATA2 = 0x7a2
- TDATA3 = 0x7a3
- TINFO = 0x7a4
- MCONTEXT = 0x7a8
- # debug module
- DCSR = 0x7b0
- DPC = 0x7b1
-
-
-class Cause:
- FETCH_MISALIGNED = 0
- FETCH_ACCESS_FAULT = 1
- ILLEGAL_INSTRUCTION = 2
- BREAKPOINT = 3
- LOAD_MISALIGNED = 4
- LOAD_ACCESS_FAULT = 5
- STORE_MISALIGNED = 6
- STORE_ACCESS_FAULT = 7
- ECALL_FROM_U = 8
- ECALL_FROM_S = 9
- ECALL_FROM_M = 11
- FETCH_PAGE_FAULT = 12
- LOAD_PAGE_FAULT = 13
- STORE_PAGE_FAULT = 15
- # interrupts
- U_SOFTWARE_INTERRUPT = 0
- S_SOFTWARE_INTERRUPT = 1
- M_SOFTWARE_INTERRUPT = 3
- U_TIMER_INTERRUPT = 4
- S_TIMER_INTERRUPT = 5
- M_TIMER_INTERRUPT = 7
- U_EXTERNAL_INTERRUPT = 8
- S_EXTERNAL_INTERRUPT = 9
- M_EXTERNAL_INTERRUPT = 11
-
-
-# CSR layouts
-
-flat_layout = [
- ("value", 32, CSRAccess.WARL)
-]
-
-
-misa_layout = [
- ("extensions", 26, CSRAccess.WARL),
- ("wiri0", 4, CSRAccess.WIRI),
- ("mxl", 2, CSRAccess.WARL)
-]
-
-
-mstatus_layout = [
- ("uie", 1, CSRAccess.WARL), # User Interrupt Enable
- ("sie", 1, CSRAccess.WARL), # Supervisor Interrupt Enable
- ("wpri0", 1, CSRAccess.WPRI),
- ("mie", 1, CSRAccess.WARL), # Machine Interrupt Enable
- ("upie", 1, CSRAccess.WARL), # User Previous Interrupt Enable
- ("spie", 1, CSRAccess.WARL), # Supervisor Previous Interrupt Enable
- ("wpri1", 1, CSRAccess.WPRI),
- ("mpie", 1, CSRAccess.WARL), # Machine Previous Interrupt Enable
- ("spp", 1, CSRAccess.WARL), # Supervisor Previous Privilege
- ("wpri2", 2, CSRAccess.WPRI),
- ("mpp", 2, CSRAccess.WARL), # Machine Previous Privilege
- ("fs", 2, CSRAccess.WARL), # FPU Status
- ("xs", 2, CSRAccess.WARL), # user-mode eXtensions Status
- ("mprv", 1, CSRAccess.WARL), # Modify PRiVilege
- ("sum", 1, CSRAccess.WARL), # Supervisor User Memory access
- ("mxr", 1, CSRAccess.WARL), # Make eXecutable Readable
- ("tvm", 1, CSRAccess.WARL), # Trap Virtual Memory
- ("tw", 1, CSRAccess.WARL), # Timeout Wait
- ("tsr", 1, CSRAccess.WARL), # Trap SRET
- ("wpri3", 8, CSRAccess.WPRI),
- ("sd", 1, CSRAccess.WARL) # State Dirty (set if XS or FS are set to dirty)
-]
-
-
-mtvec_layout = [
- ("mode", 2, CSRAccess.WARL),
- ("base", 30, CSRAccess.WARL)
-]
-
-
-mepc_layout = [
- ("zero", 2, CSRAccess.WIRI), # 16-bit instructions are not supported
- ("base", 30, CSRAccess.WARL)
-]
-
-
-mip_layout = [
- ("usip", 1, CSRAccess.WARL),
- ("ssip", 1, CSRAccess.WARL),
- ("wiri0", 1, CSRAccess.WIRI),
- ("msip", 1, CSRAccess.WARL),
- ("utip", 1, CSRAccess.WARL),
- ("stip", 1, CSRAccess.WARL),
- ("wiri1", 1, CSRAccess.WIRI),
- ("mtip", 1, CSRAccess.WARL),
- ("ueip", 1, CSRAccess.WARL),
- ("seip", 1, CSRAccess.WARL),
- ("wiri2", 1, CSRAccess.WIRI),
- ("meip", 1, CSRAccess.WARL),
- ("wiri3", 20, CSRAccess.WIRI)
-]
-
-
-mie_layout = [
- ("usie", 1, CSRAccess.WARL),
- ("ssie", 1, CSRAccess.WARL),
- ("wpri0", 1, CSRAccess.WPRI),
- ("msie", 1, CSRAccess.WARL),
- ("utie", 1, CSRAccess.WARL),
- ("stie", 1, CSRAccess.WARL),
- ("wpri1", 1, CSRAccess.WPRI),
- ("mtie", 1, CSRAccess.WARL),
- ("ueie", 1, CSRAccess.WARL),
- ("seie", 1, CSRAccess.WARL),
- ("wpri2", 1, CSRAccess.WPRI),
- ("meie", 1, CSRAccess.WARL),
- ("wpri3", 20, CSRAccess.WPRI)
-]
-
-
-mcause_layout = [
- ("ecode", 31, CSRAccess.WARL),
- ("interrupt", 1, CSRAccess.WARL)
-]
-
-
-dcsr_layout = [
- ("prv", 2, CSRAccess.WARL), # Privilege level before Debug Mode was entered
- ("step", 1, CSRAccess.WARL), # Execute a single instruction and re-enter Debug Mode
- ("nmip", 1, CSRAccess.WLRL), # A non-maskable interrupt is pending
- ("mprven", 1, CSRAccess.WARL), # Use mstatus.mprv in Debug Mode
- ("zero0", 1, CSRAccess.WPRI),
- ("cause", 3, CSRAccess.WLRL), # Explains why Debug Mode was entered
- ("stoptime", 1, CSRAccess.WARL), # Stop timer increment during Debug Mode
- ("stopcount", 1, CSRAccess.WARL), # Stop counter increment during Debug Mode
- ("stepie", 1, CSRAccess.WARL), # Enable interrupts during single stepping
- ("ebreaku", 1, CSRAccess.WARL), # EBREAKs in U-mode enter Debug Mode
- ("ebreaks", 1, CSRAccess.WARL), # EBREAKs in S-mode enter Debug Mode
- ("zero1", 1, CSRAccess.WPRI),
- ("ebreakm", 1, CSRAccess.WARL), # EBREAKs in M-mode enter Debug Mode
- ("zero2", 12, CSRAccess.WPRI),
- ("xdebugver", 4, CSRAccess.WLRL) # External Debug specification version
-]
-
-
-tdata1_layout = [
- ("data", 27, CSRAccess.WARL),
- ("dmode", 1, CSRAccess.WARL),
- ("type", 4, CSRAccess.WARL)
-]
+++ /dev/null
-from functools import reduce
-from operator import or_
-
-from nmigen import Elaboratable, Module, Mux, Record, Signal
-from nmigen.hdl.rec import DIR_FANIN, DIR_FANOUT, DIR_NONE
-
-
-__all__ = ["Stage"]
-
-
-def _make_m2s(layout):
- r = []
- for f in layout:
- if isinstance(f[1], (int, tuple)):
- r.append((f[0], f[1], DIR_FANOUT))
- else:
- r.append((f[0], _make_m2s(f[1])))
- return r
-
-
-class _EndpointDescription:
- def __init__(self, payload_layout):
- self.payload_layout = payload_layout
-
- def get_full_layout(self):
- reserved = {"valid", "stall", "kill"}
- attributed = set()
- for f in self.payload_layout:
- if f[0] in attributed:
- raise ValueError(f[0] + " already attributed in payload layout")
- if f[0] in reserved:
- raise ValueError(f[0] + " cannot be used in endpoint layout")
- attributed.add(f[0])
-
- full_layout = [
- ("valid", 1, DIR_FANOUT),
- ("stall", 1, DIR_FANIN),
- ("kill", 1, DIR_FANOUT),
- ("payload", _make_m2s(self.payload_layout))
- ]
- return full_layout
-
-
-class _Endpoint(Record):
- def __init__(self, layout):
- self.description = _EndpointDescription(layout)
- super().__init__(self.description.get_full_layout())
-
- def __getattr__(self, name):
- try:
- return super().__getattr__(name)
- except AttributeError:
- return self.fields["payload"][name]
-
-
-class Stage(Elaboratable):
- def __init__(self, sink_layout, source_layout):
- self.kill = Signal()
- self.stall = Signal()
- self.valid = Signal()
-
- if sink_layout is None and source_layout is None:
- raise ValueError
- if sink_layout is not None:
- self.sink = _Endpoint(sink_layout)
- if source_layout is not None:
- self.source = _Endpoint(source_layout)
-
- self._kill_sources = []
- self._stall_sources = []
-
- def kill_on(self, cond):
- self._kill_sources.append(cond)
-
- def stall_on(self, cond):
- self._stall_sources.append(cond)
-
- def elaborate(self, platform):
- m = Module()
-
- if hasattr(self, "sink"):
- m.d.comb += [
- self.valid.eq(self.sink.valid & ~self.sink.kill),
- self.sink.stall.eq(self.stall)
- ]
-
- if hasattr(self, "source"):
- with m.If(~self.stall):
- m.d.sync += self.source.valid.eq(self.valid)
- with m.Elif(~self.source.stall | self.kill):
- m.d.sync += self.source.valid.eq(0)
- self.stall_on(self.source.stall)
- m.d.comb += [
- self.source.kill.eq(self.kill),
- self.kill.eq(reduce(or_, self._kill_sources, 0))
- ]
-
- m.d.comb += self.stall.eq(reduce(or_, self._stall_sources, 0))
-
- return m
+++ /dev/null
-from nmigen import *
-from nmigen.back.pysim import *
-from nmigen.test.utils import *
-
-from ..units.divider import *
-from ..isa import Funct3
-
-
-def tst_op(funct3, src1, src2, result):
- def test(self):
- with Simulator(self.dut) as sim:
- def process():
- yield self.dut.x_op.eq(funct3)
- yield self.dut.x_src1.eq(src1)
- yield self.dut.x_src2.eq(src2)
- yield self.dut.x_valid.eq(1)
- yield self.dut.x_stall.eq(0)
- yield Tick()
- yield self.dut.x_valid.eq(0)
- yield Tick()
- while (yield self.dut.m_busy):
- yield Tick()
- self.assertEqual((yield self.dut.m_result), result)
- sim.add_clock(1e-6)
- sim.add_sync_process(process)
- sim.run()
- return test
-
-
-class DividerTestCase(FHDLTestCase):
- def setUp(self):
- self.dut = Divider()
-
- # Test cases are taken from the riscv-compliance testbench:
- # https://github.com/riscv/riscv-compliance/tree/master/riscv-test-suite/rv32im
-
- # DIV ------------------------------------------------------------------------
-
- test_div_0 = tst_op(Funct3.DIV, 0x00000000, 0x00000000, result=0xffffffff)
- test_div_1 = tst_op(Funct3.DIV, 0x00000000, 0x00000001, result=0x00000000)
- test_div_2 = tst_op(Funct3.DIV, 0x00000000, 0xffffffff, result=0x00000000)
- test_div_3 = tst_op(Funct3.DIV, 0x00000000, 0x7fffffff, result=0x00000000)
- test_div_4 = tst_op(Funct3.DIV, 0x00000000, 0x80000000, result=0x00000000)
-
- test_div_5 = tst_op(Funct3.DIV, 0x00000001, 0x00000000, result=0xffffffff)
- test_div_6 = tst_op(Funct3.DIV, 0x00000001, 0x00000001, result=0x00000001)
- test_div_7 = tst_op(Funct3.DIV, 0x00000001, 0xffffffff, result=0xffffffff)
- test_div_8 = tst_op(Funct3.DIV, 0x00000001, 0x7fffffff, result=0x00000000)
- test_div_9 = tst_op(Funct3.DIV, 0x00000001, 0x80000000, result=0x00000000)
-
- test_div_10 = tst_op(Funct3.DIV, 0xffffffff,
- 0x00000000, result=0xffffffff)
- test_div_11 = tst_op(Funct3.DIV, 0xffffffff,
- 0x00000001, result=0xffffffff)
- test_div_12 = tst_op(Funct3.DIV, 0xffffffff,
- 0xffffffff, result=0x00000001)
- test_div_13 = tst_op(Funct3.DIV, 0xffffffff,
- 0x7fffffff, result=0x00000000)
- test_div_14 = tst_op(Funct3.DIV, 0xffffffff,
- 0x80000000, result=0x00000000)
-
- test_div_15 = tst_op(Funct3.DIV, 0x7fffffff,
- 0x00000000, result=0xffffffff)
- test_div_16 = tst_op(Funct3.DIV, 0x7fffffff,
- 0x00000001, result=0x7fffffff)
- test_div_17 = tst_op(Funct3.DIV, 0x7fffffff,
- 0xffffffff, result=0x80000001)
- test_div_18 = tst_op(Funct3.DIV, 0x7fffffff,
- 0x7fffffff, result=0x00000001)
- test_div_19 = tst_op(Funct3.DIV, 0x7fffffff,
- 0x80000000, result=0x00000000)
-
- test_div_20 = tst_op(Funct3.DIV, 0x80000000,
- 0x00000000, result=0xffffffff)
- test_div_21 = tst_op(Funct3.DIV, 0x80000000,
- 0x00000001, result=0x80000000)
- test_div_22 = tst_op(Funct3.DIV, 0x80000000,
- 0xffffffff, result=0x80000000)
- test_div_23 = tst_op(Funct3.DIV, 0x80000000,
- 0x7fffffff, result=0xffffffff)
- test_div_24 = tst_op(Funct3.DIV, 0x80000000,
- 0x80000000, result=0x00000001)
-
- # DIVU -----------------------------------------------------------------------
-
- test_divu_0 = tst_op(Funct3.DIVU, 0x00000000,
- 0x00000000, result=0xffffffff)
- test_divu_1 = tst_op(Funct3.DIVU, 0x00000000,
- 0x00000001, result=0x00000000)
- test_divu_2 = tst_op(Funct3.DIVU, 0x00000000,
- 0xffffffff, result=0x00000000)
- test_divu_3 = tst_op(Funct3.DIVU, 0x00000000,
- 0x7fffffff, result=0x00000000)
- test_divu_4 = tst_op(Funct3.DIVU, 0x00000000,
- 0x80000000, result=0x00000000)
-
- test_divu_5 = tst_op(Funct3.DIVU, 0x00000001,
- 0x00000000, result=0xffffffff)
- test_divu_6 = tst_op(Funct3.DIVU, 0x00000001,
- 0x00000001, result=0x00000001)
- test_divu_7 = tst_op(Funct3.DIVU, 0x00000001,
- 0xffffffff, result=0x00000000)
- test_divu_8 = tst_op(Funct3.DIVU, 0x00000001,
- 0x7fffffff, result=0x00000000)
- test_divu_9 = tst_op(Funct3.DIVU, 0x00000001,
- 0x80000000, result=0x00000000)
-
- test_divu_10 = tst_op(Funct3.DIVU, 0xffffffff,
- 0x00000000, result=0xffffffff)
- test_divu_11 = tst_op(Funct3.DIVU, 0xffffffff,
- 0x00000001, result=0xffffffff)
- test_divu_12 = tst_op(Funct3.DIVU, 0xffffffff,
- 0xffffffff, result=0x00000001)
- test_divu_13 = tst_op(Funct3.DIVU, 0xffffffff,
- 0x7fffffff, result=0x00000002)
- test_divu_14 = tst_op(Funct3.DIVU, 0xffffffff,
- 0x80000000, result=0x00000001)
-
- test_divu_15 = tst_op(Funct3.DIVU, 0x7fffffff,
- 0x00000000, result=0xffffffff)
- test_divu_16 = tst_op(Funct3.DIVU, 0x7fffffff,
- 0x00000001, result=0x7fffffff)
- test_divu_17 = tst_op(Funct3.DIVU, 0x7fffffff,
- 0xffffffff, result=0x00000000)
- test_divu_18 = tst_op(Funct3.DIVU, 0x7fffffff,
- 0x7fffffff, result=0x00000001)
- test_divu_19 = tst_op(Funct3.DIVU, 0x7fffffff,
- 0x80000000, result=0x00000000)
-
- test_divu_20 = tst_op(Funct3.DIVU, 0x80000000,
- 0x00000000, result=0xffffffff)
- test_divu_21 = tst_op(Funct3.DIVU, 0x80000000,
- 0x00000001, result=0x80000000)
- test_divu_22 = tst_op(Funct3.DIVU, 0x80000000,
- 0xffffffff, result=0x00000000)
- test_divu_23 = tst_op(Funct3.DIVU, 0x80000000,
- 0x7fffffff, result=0x00000001)
- test_divu_24 = tst_op(Funct3.DIVU, 0x80000000,
- 0x80000000, result=0x00000001)
-
- # REM ------------------------------------------------------------------------
-
- test_rem_0 = tst_op(Funct3.REM, 0x00000000, 0x00000000, result=0x00000000)
- test_rem_1 = tst_op(Funct3.REM, 0x00000000, 0x00000001, result=0x00000000)
- test_rem_2 = tst_op(Funct3.REM, 0x00000000, 0xffffffff, result=0x00000000)
- test_rem_3 = tst_op(Funct3.REM, 0x00000000, 0x7fffffff, result=0x00000000)
- test_rem_4 = tst_op(Funct3.REM, 0x00000000, 0x80000000, result=0x00000000)
-
- test_rem_5 = tst_op(Funct3.REM, 0x00000001, 0x00000000, result=0x00000001)
- test_rem_6 = tst_op(Funct3.REM, 0x00000001, 0x00000001, result=0x00000000)
- test_rem_7 = tst_op(Funct3.REM, 0x00000001, 0xffffffff, result=0x00000000)
- test_rem_8 = tst_op(Funct3.REM, 0x00000001, 0x7fffffff, result=0x00000001)
- test_rem_9 = tst_op(Funct3.REM, 0x00000001, 0x80000000, result=0x00000001)
-
- test_rem_10 = tst_op(Funct3.REM, 0xffffffff,
- 0x00000000, result=0xffffffff)
- test_rem_11 = tst_op(Funct3.REM, 0xffffffff,
- 0x00000001, result=0x00000000)
- test_rem_12 = tst_op(Funct3.REM, 0xffffffff,
- 0xffffffff, result=0x00000000)
- test_rem_13 = tst_op(Funct3.REM, 0xffffffff,
- 0x7fffffff, result=0xffffffff)
- test_rem_14 = tst_op(Funct3.REM, 0xffffffff,
- 0x80000000, result=0xffffffff)
-
- test_rem_15 = tst_op(Funct3.REM, 0x7fffffff,
- 0x00000000, result=0x7fffffff)
- test_rem_16 = tst_op(Funct3.REM, 0x7fffffff,
- 0x00000001, result=0x00000000)
- test_rem_17 = tst_op(Funct3.REM, 0x7fffffff,
- 0xffffffff, result=0x00000000)
- test_rem_18 = tst_op(Funct3.REM, 0x7fffffff,
- 0x7fffffff, result=0x00000000)
- test_rem_19 = tst_op(Funct3.REM, 0x7fffffff,
- 0x80000000, result=0x7fffffff)
-
- test_rem_20 = tst_op(Funct3.REM, 0x80000000,
- 0x00000000, result=0x80000000)
- test_rem_21 = tst_op(Funct3.REM, 0x80000000,
- 0x00000001, result=0x00000000)
- test_rem_22 = tst_op(Funct3.REM, 0x80000000,
- 0xffffffff, result=0x00000000)
- test_rem_23 = tst_op(Funct3.REM, 0x80000000,
- 0x7fffffff, result=0xffffffff)
- test_rem_24 = tst_op(Funct3.REM, 0x80000000,
- 0x80000000, result=0x00000000)
-
- # REMU -----------------------------------------------------------------------
-
- test_remu_0 = tst_op(Funct3.REMU, 0x00000000,
- 0x00000000, result=0x00000000)
- test_remu_1 = tst_op(Funct3.REMU, 0x00000000,
- 0x00000001, result=0x00000000)
- test_remu_2 = tst_op(Funct3.REMU, 0x00000000,
- 0xffffffff, result=0x00000000)
- test_remu_3 = tst_op(Funct3.REMU, 0x00000000,
- 0x7fffffff, result=0x00000000)
- test_remu_4 = tst_op(Funct3.REMU, 0x00000000,
- 0x80000000, result=0x00000000)
-
- test_remu_5 = tst_op(Funct3.REMU, 0x00000001,
- 0x00000000, result=0x00000001)
- test_remu_6 = tst_op(Funct3.REMU, 0x00000001,
- 0x00000001, result=0x00000000)
- test_remu_7 = tst_op(Funct3.REMU, 0x00000001,
- 0xffffffff, result=0x00000001)
- test_remu_8 = tst_op(Funct3.REMU, 0x00000001,
- 0x7fffffff, result=0x00000001)
- test_remu_9 = tst_op(Funct3.REMU, 0x00000001,
- 0x80000000, result=0x00000001)
-
- test_remu_10 = tst_op(Funct3.REMU, 0xffffffff,
- 0x00000000, result=0xffffffff)
- test_remu_11 = tst_op(Funct3.REMU, 0xffffffff,
- 0x00000001, result=0x00000000)
- test_remu_12 = tst_op(Funct3.REMU, 0xffffffff,
- 0xffffffff, result=0x00000000)
- test_remu_13 = tst_op(Funct3.REMU, 0xffffffff,
- 0x7fffffff, result=0x00000001)
- test_remu_14 = tst_op(Funct3.REMU, 0xffffffff,
- 0x80000000, result=0x7fffffff)
-
- test_remu_15 = tst_op(Funct3.REMU, 0x7fffffff,
- 0x00000000, result=0x7fffffff)
- test_remu_16 = tst_op(Funct3.REMU, 0x7fffffff,
- 0x00000001, result=0x00000000)
- test_remu_17 = tst_op(Funct3.REMU, 0x7fffffff,
- 0xffffffff, result=0x7fffffff)
- test_remu_18 = tst_op(Funct3.REMU, 0x7fffffff,
- 0x7fffffff, result=0x00000000)
- test_remu_19 = tst_op(Funct3.REMU, 0x7fffffff,
- 0x80000000, result=0x7fffffff)
-
- test_remu_20 = tst_op(Funct3.REMU, 0x80000000,
- 0x00000000, result=0x80000000)
- test_remu_21 = tst_op(Funct3.REMU, 0x80000000,
- 0x00000001, result=0x00000000)
- test_remu_22 = tst_op(Funct3.REMU, 0x80000000,
- 0xffffffff, result=0x80000000)
- test_remu_23 = tst_op(Funct3.REMU, 0x80000000,
- 0x7fffffff, result=0x00000001)
- test_remu_24 = tst_op(Funct3.REMU, 0x80000000,
- 0x80000000, result=0x00000000)
+++ /dev/null
-from nmigen import *
-from nmigen.back.pysim import *
-from nmigen.test.utils import *
-
-from ..units.multiplier import *
-from ..isa import Funct3
-
-
-def tst_op(funct3, src1, src2, result):
- def test(self):
- with Simulator(self.dut) as sim:
- def process():
- yield self.dut.x_op.eq(funct3)
- yield self.dut.x_src1.eq(src1)
- yield self.dut.x_src2.eq(src2)
- yield self.dut.x_stall.eq(0)
- yield Tick()
- yield self.dut.m_stall.eq(0)
- yield Tick()
- yield Tick()
- self.assertEqual((yield self.dut.w_result), result)
- sim.add_clock(1e-6)
- sim.add_sync_process(process)
- sim.run()
- return test
-
-
-class MultiplierTestCase(FHDLTestCase):
- def setUp(self):
- self.dut = Multiplier()
-
- # Test cases are taken from the riscv-compliance testbench:
- # https://github.com/riscv/riscv-compliance/tree/master/riscv-test-suite/rv32im
-
- # MUL ----------------------------------------------------------------------------
-
- test_mul_0 = tst_op(Funct3.MUL, 0x00000000,
- 0x00000000, result=0x00000000)
- test_mul_1 = tst_op(Funct3.MUL, 0x00000000,
- 0x00000001, result=0x00000000)
- test_mul_2 = tst_op(Funct3.MUL, 0x00000000,
- 0xffffffff, result=0x00000000)
- test_mul_3 = tst_op(Funct3.MUL, 0x00000000,
- 0x7fffffff, result=0x00000000)
- test_mul_4 = tst_op(Funct3.MUL, 0x00000000,
- 0x80000000, result=0x00000000)
-
- test_mul_5 = tst_op(Funct3.MUL, 0x00000001,
- 0x00000000, result=0x00000000)
- test_mul_6 = tst_op(Funct3.MUL, 0x00000001,
- 0x00000001, result=0x00000001)
- test_mul_7 = tst_op(Funct3.MUL, 0x00000001,
- 0xffffffff, result=0xffffffff)
- test_mul_8 = tst_op(Funct3.MUL, 0x00000001,
- 0x7fffffff, result=0x7fffffff)
- test_mul_9 = tst_op(Funct3.MUL, 0x00000001,
- 0x80000000, result=0x80000000)
-
- test_mul_10 = tst_op(Funct3.MUL, 0xffffffff,
- 0x00000000, result=0x00000000)
- test_mul_11 = tst_op(Funct3.MUL, 0xffffffff,
- 0x00000001, result=0xffffffff)
- test_mul_12 = tst_op(Funct3.MUL, 0xffffffff,
- 0xffffffff, result=0x00000001)
- test_mul_13 = tst_op(Funct3.MUL, 0xffffffff,
- 0x7fffffff, result=0x80000001)
- test_mul_14 = tst_op(Funct3.MUL, 0xffffffff,
- 0x80000000, result=0x80000000)
-
- test_mul_15 = tst_op(Funct3.MUL, 0x7fffffff,
- 0x00000000, result=0x00000000)
- test_mul_16 = tst_op(Funct3.MUL, 0x7fffffff,
- 0x00000001, result=0x7fffffff)
- test_mul_17 = tst_op(Funct3.MUL, 0x7fffffff,
- 0xffffffff, result=0x80000001)
- test_mul_18 = tst_op(Funct3.MUL, 0x7fffffff,
- 0x7fffffff, result=0x00000001)
- test_mul_19 = tst_op(Funct3.MUL, 0x7fffffff,
- 0x80000000, result=0x80000000)
-
- test_mul_20 = tst_op(Funct3.MUL, 0x80000000,
- 0x00000000, result=0x00000000)
- test_mul_21 = tst_op(Funct3.MUL, 0x80000000,
- 0x00000001, result=0x80000000)
- test_mul_22 = tst_op(Funct3.MUL, 0x80000000,
- 0xffffffff, result=0x80000000)
- test_mul_23 = tst_op(Funct3.MUL, 0x80000000,
- 0x7fffffff, result=0x80000000)
- test_mul_24 = tst_op(Funct3.MUL, 0x80000000,
- 0x80000000, result=0x00000000)
-
- # MULH ---------------------------------------------------------------------------
-
- test_mulh_0 = tst_op(Funct3.MULH, 0x00000000,
- 0x00000000, result=0x00000000)
- test_mulh_1 = tst_op(Funct3.MULH, 0x00000000,
- 0x00000001, result=0x00000000)
- test_mulh_2 = tst_op(Funct3.MULH, 0x00000000,
- 0xffffffff, result=0x00000000)
- test_mulh_3 = tst_op(Funct3.MULH, 0x00000000,
- 0x7fffffff, result=0x00000000)
- test_mulh_4 = tst_op(Funct3.MULH, 0x00000000,
- 0x80000000, result=0x00000000)
-
- test_mulh_5 = tst_op(Funct3.MULH, 0x00000001,
- 0x00000000, result=0x00000000)
- test_mulh_6 = tst_op(Funct3.MULH, 0x00000001,
- 0x00000001, result=0x00000000)
- test_mulh_7 = tst_op(Funct3.MULH, 0x00000001,
- 0xffffffff, result=0xffffffff)
- test_mulh_8 = tst_op(Funct3.MULH, 0x00000001,
- 0x7fffffff, result=0x00000000)
- test_mulh_9 = tst_op(Funct3.MULH, 0x00000001,
- 0x80000000, result=0xffffffff)
-
- test_mulh_10 = tst_op(Funct3.MULH, 0xffffffff,
- 0x00000000, result=0x00000000)
- test_mulh_11 = tst_op(Funct3.MULH, 0xffffffff,
- 0x00000001, result=0xffffffff)
- test_mulh_12 = tst_op(Funct3.MULH, 0xffffffff,
- 0xffffffff, result=0x00000000)
- test_mulh_13 = tst_op(Funct3.MULH, 0xffffffff,
- 0x7fffffff, result=0xffffffff)
- test_mulh_14 = tst_op(Funct3.MULH, 0xffffffff,
- 0x80000000, result=0x00000000)
-
- test_mulh_15 = tst_op(Funct3.MULH, 0x7fffffff,
- 0x00000000, result=0x00000000)
- test_mulh_16 = tst_op(Funct3.MULH, 0x7fffffff,
- 0x00000001, result=0x00000000)
- test_mulh_17 = tst_op(Funct3.MULH, 0x7fffffff,
- 0xffffffff, result=0xffffffff)
- test_mulh_18 = tst_op(Funct3.MULH, 0x7fffffff,
- 0x7fffffff, result=0x3fffffff)
- test_mulh_19 = tst_op(Funct3.MULH, 0x7fffffff,
- 0x80000000, result=0xc0000000)
-
- test_mulh_20 = tst_op(Funct3.MULH, 0x80000000,
- 0x00000000, result=0x00000000)
- test_mulh_21 = tst_op(Funct3.MULH, 0x80000000,
- 0x00000001, result=0xffffffff)
- test_mulh_22 = tst_op(Funct3.MULH, 0x80000000,
- 0xffffffff, result=0x00000000)
- test_mulh_23 = tst_op(Funct3.MULH, 0x80000000,
- 0x7fffffff, result=0xc0000000)
- test_mulh_24 = tst_op(Funct3.MULH, 0x80000000,
- 0x80000000, result=0x40000000)
-
- # MULHSU -------------------------------------------------------------------------
-
- test_mulhsu_0 = tst_op(Funct3.MULHSU, 0x00000000,
- 0x00000000, result=0x00000000)
- test_mulhsu_1 = tst_op(Funct3.MULHSU, 0x00000000,
- 0x00000001, result=0x00000000)
- test_mulhsu_2 = tst_op(Funct3.MULHSU, 0x00000000,
- 0xffffffff, result=0x00000000)
- test_mulhsu_3 = tst_op(Funct3.MULHSU, 0x00000000,
- 0x7fffffff, result=0x00000000)
- test_mulhsu_4 = tst_op(Funct3.MULHSU, 0x00000000,
- 0x80000000, result=0x00000000)
-
- test_mulhsu_5 = tst_op(Funct3.MULHSU, 0x00000001,
- 0x00000000, result=0x00000000)
- test_mulhsu_6 = tst_op(Funct3.MULHSU, 0x00000001,
- 0x00000001, result=0x00000000)
- test_mulhsu_7 = tst_op(Funct3.MULHSU, 0x00000001,
- 0xffffffff, result=0x00000000)
- test_mulhsu_8 = tst_op(Funct3.MULHSU, 0x00000001,
- 0x7fffffff, result=0x00000000)
- test_mulhsu_9 = tst_op(Funct3.MULHSU, 0x00000001,
- 0x80000000, result=0x00000000)
-
- test_mulhsu_10 = tst_op(Funct3.MULHSU, 0xffffffff,
- 0x00000000, result=0x00000000)
- test_mulhsu_11 = tst_op(Funct3.MULHSU, 0xffffffff,
- 0x00000001, result=0xffffffff)
- test_mulhsu_12 = tst_op(Funct3.MULHSU, 0xffffffff,
- 0xffffffff, result=0xffffffff)
- test_mulhsu_13 = tst_op(Funct3.MULHSU, 0xffffffff,
- 0x7fffffff, result=0xffffffff)
- test_mulhsu_14 = tst_op(Funct3.MULHSU, 0xffffffff,
- 0x80000000, result=0xffffffff)
-
- test_mulhsu_15 = tst_op(Funct3.MULHSU, 0x7fffffff,
- 0x00000000, result=0x00000000)
- test_mulhsu_16 = tst_op(Funct3.MULHSU, 0x7fffffff,
- 0x00000001, result=0x00000000)
- test_mulhsu_17 = tst_op(Funct3.MULHSU, 0x7fffffff,
- 0xffffffff, result=0x7ffffffe)
- test_mulhsu_18 = tst_op(Funct3.MULHSU, 0x7fffffff,
- 0x7fffffff, result=0x3fffffff)
- test_mulhsu_19 = tst_op(Funct3.MULHSU, 0x7fffffff,
- 0x80000000, result=0x3fffffff)
-
- test_mulhsu_20 = tst_op(Funct3.MULHSU, 0x80000000,
- 0x00000000, result=0x00000000)
- test_mulhsu_21 = tst_op(Funct3.MULHSU, 0x80000000,
- 0x00000001, result=0xffffffff)
- test_mulhsu_22 = tst_op(Funct3.MULHSU, 0x80000000,
- 0xffffffff, result=0x80000000)
- test_mulhsu_23 = tst_op(Funct3.MULHSU, 0x80000000,
- 0x7fffffff, result=0xc0000000)
- test_mulhsu_24 = tst_op(Funct3.MULHSU, 0x80000000,
- 0x80000000, result=0xc0000000)
-
- # MULHU --------------------------------------------------------------------------
-
- test_mulhu_0 = tst_op(Funct3.MULHU, 0x00000000,
- 0x00000000, result=0x00000000)
- test_mulhu_1 = tst_op(Funct3.MULHU, 0x00000000,
- 0x00000001, result=0x00000000)
- test_mulhu_2 = tst_op(Funct3.MULHU, 0x00000000,
- 0xffffffff, result=0x00000000)
- test_mulhu_3 = tst_op(Funct3.MULHU, 0x00000000,
- 0x7fffffff, result=0x00000000)
- test_mulhu_4 = tst_op(Funct3.MULHU, 0x00000000,
- 0x80000000, result=0x00000000)
-
- test_mulhu_5 = tst_op(Funct3.MULHU, 0x00000001,
- 0x00000000, result=0x00000000)
- test_mulhu_6 = tst_op(Funct3.MULHU, 0x00000001,
- 0x00000001, result=0x00000000)
- test_mulhu_7 = tst_op(Funct3.MULHU, 0x00000001,
- 0xffffffff, result=0x00000000)
- test_mulhu_8 = tst_op(Funct3.MULHU, 0x00000001,
- 0x7fffffff, result=0x00000000)
- test_mulhu_9 = tst_op(Funct3.MULHU, 0x00000001,
- 0x80000000, result=0x00000000)
-
- test_mulhu_10 = tst_op(Funct3.MULHU, 0xffffffff,
- 0x00000000, result=0x00000000)
- test_mulhu_11 = tst_op(Funct3.MULHU, 0xffffffff,
- 0x00000001, result=0x00000000)
- test_mulhu_12 = tst_op(Funct3.MULHU, 0xffffffff,
- 0xffffffff, result=0xfffffffe)
- test_mulhu_13 = tst_op(Funct3.MULHU, 0xffffffff,
- 0x7fffffff, result=0x7ffffffe)
- test_mulhu_14 = tst_op(Funct3.MULHU, 0xffffffff,
- 0x80000000, result=0x7fffffff)
-
- test_mulhu_15 = tst_op(Funct3.MULHU, 0x7fffffff,
- 0x00000000, result=0x00000000)
- test_mulhu_16 = tst_op(Funct3.MULHU, 0x7fffffff,
- 0x00000001, result=0x00000000)
- test_mulhu_17 = tst_op(Funct3.MULHU, 0x7fffffff,
- 0xffffffff, result=0x7ffffffe)
- test_mulhu_18 = tst_op(Funct3.MULHU, 0x7fffffff,
- 0x7fffffff, result=0x3fffffff)
- test_mulhu_19 = tst_op(Funct3.MULHU, 0x7fffffff,
- 0x80000000, result=0x3fffffff)
-
- test_mulhu_20 = tst_op(Funct3.MULHU, 0x80000000,
- 0x00000000, result=0x00000000)
- test_mulhu_21 = tst_op(Funct3.MULHU, 0x80000000,
- 0x00000001, result=0x00000000)
- test_mulhu_22 = tst_op(Funct3.MULHU, 0x80000000,
- 0xffffffff, result=0x7fffffff)
- test_mulhu_23 = tst_op(Funct3.MULHU, 0x80000000,
- 0x7fffffff, result=0x3fffffff)
- test_mulhu_24 = tst_op(Funct3.MULHU, 0x80000000,
- 0x80000000, result=0x40000000)
+++ /dev/null
-from nmigen import Elaboratable, Module, Signal, Cat
-
-
-__all__ = ["Adder"]
-
-
-class Adder(Elaboratable):
- def __init__(self):
- self.sub = Signal()
- self.src1 = Signal(32)
- self.src2 = Signal(32)
-
- self.result = Signal(32)
- self.carry = Signal()
- self.overflow = Signal()
-
- def elaborate(self, platform):
- m = Module()
-
- with m.If(self.sub):
- m.d.comb += [
- Cat(self.result, self.carry).eq(self.src1 - self.src2),
- self.overflow.eq((self.src1[-1] != self.src2[-1]) & (self.result[-1] == self.src2[-1]))
- ]
- with m.Else():
- m.d.comb += [
- Cat(self.result, self.carry).eq(self.src1 + self.src2),
- self.overflow.eq(~self.src1[-1] & self.src2[-1] & self.result[-1])
- ]
-
- return m
+++ /dev/null
-from nmigen import Elaboratable, Module, Signal
-
-from ..isa import Funct3
-
-
-__all__ = ["CompareUnit"]
-
-
-class CompareUnit(Elaboratable):
- def __init__(self):
- self.op = Signal(3)
- self.zero = Signal()
- self.negative = Signal()
- self.overflow = Signal()
- self.carry = Signal()
-
- self.condition_met = Signal()
-
- def elaborate(self, platform):
- m = Module()
-
- with m.Switch(self.op):
- 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.zero & (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.zero & self.carry)
- with m.Case(Funct3.BGEU):
- m.d.comb += self.condition_met.eq(~self.carry)
-
- return m
+++ /dev/null
-from functools import reduce
-from itertools import starmap
-from operator import or_
-
-from nmigen import Elaboratable, Module, Signal, Cat
-
-from ..isa import Opcode, Funct3, Funct7, Funct12
-
-
-__all__ = ["InstructionDecoder"]
-
-
-class Type:
- R = 0
- I = 1
- S = 2
- B = 3
- U = 4
- J = 5
-
-
-class InstructionDecoder(Elaboratable):
- def __init__(self, with_muldiv):
- self.with_muldiv = with_muldiv
-
- self.instruction = Signal(32)
-
- self.rd = Signal(5)
- self.rd_we = Signal()
- self.rs1 = Signal(5)
- self.rs1_re = Signal()
- self.rs2 = Signal(5)
- self.rs2_re = Signal()
- self.immediate = Signal((32, True))
- self.bypass_x = Signal()
- self.bypass_m = Signal()
- self.load = Signal()
- self.store = Signal()
- self.fence_i = Signal()
- self.adder = Signal()
- self.adder_sub = Signal()
- self.logic = Signal()
- self.multiply = Signal()
- self.divide = Signal()
- self.shift = Signal()
- self.direction = Signal()
- self.sext = Signal()
- self.lui = Signal()
- self.auipc = Signal()
- self.jump = Signal()
- self.branch = Signal()
- self.compare = Signal()
- self.csr = Signal()
- self.csr_we = Signal()
- self.privileged = Signal()
- self.ecall = Signal()
- self.ebreak = Signal()
- self.mret = Signal()
- self.funct3 = Signal(3)
- self.illegal = Signal()
-
- def elaborate(self, platform):
- m = Module()
-
- opcode = Signal(5)
- funct3 = Signal(3)
- funct7 = Signal(7)
- funct12 = Signal(12)
-
- iimm12 = Signal((12, True))
- simm12 = Signal((12, True))
- bimm12 = Signal((13, True))
- uimm20 = Signal(20)
- jimm20 = Signal((21, True))
-
- insn = self.instruction
- fmt = Signal(range(Type.J + 1))
-
- m.d.comb += [
- opcode.eq(insn[2:7]),
- funct3.eq(insn[12:15]),
- funct7.eq(insn[25:32]),
- funct12.eq(insn[20:32]),
-
- iimm12.eq(insn[20:32]),
- simm12.eq(Cat(insn[7:12], insn[25:32])),
- bimm12.eq(Cat(0, insn[8:12], insn[25:31], insn[7], insn[31])),
- uimm20.eq(insn[12:32]),
- jimm20.eq(Cat(0, insn[21:31], insn[20], insn[12:20], insn[31])),
- ]
-
- with m.Switch(opcode):
- with m.Case(Opcode.LUI):
- m.d.comb += fmt.eq(Type.U)
- with m.Case(Opcode.AUIPC):
- m.d.comb += fmt.eq(Type.U)
- with m.Case(Opcode.JAL):
- m.d.comb += fmt.eq(Type.J)
- with m.Case(Opcode.JALR):
- m.d.comb += fmt.eq(Type.I)
- with m.Case(Opcode.BRANCH):
- m.d.comb += fmt.eq(Type.B)
- with m.Case(Opcode.LOAD):
- m.d.comb += fmt.eq(Type.I)
- with m.Case(Opcode.STORE):
- m.d.comb += fmt.eq(Type.S)
- with m.Case(Opcode.OP_IMM_32):
- m.d.comb += fmt.eq(Type.I)
- with m.Case(Opcode.OP_32):
- m.d.comb += fmt.eq(Type.R)
- with m.Case(Opcode.MISC_MEM):
- m.d.comb += fmt.eq(Type.I)
- with m.Case(Opcode.SYSTEM):
- m.d.comb += fmt.eq(Type.I)
-
- with m.Switch(fmt):
- with m.Case(Type.I):
- m.d.comb += self.immediate.eq(iimm12)
- with m.Case(Type.S):
- m.d.comb += self.immediate.eq(simm12)
- with m.Case(Type.B):
- m.d.comb += self.immediate.eq(bimm12)
- with m.Case(Type.U):
- m.d.comb += self.immediate.eq(uimm20 << 12)
- with m.Case(Type.J):
- m.d.comb += self.immediate.eq(jimm20)
-
- m.d.comb += [
- self.rd.eq(insn[7:12]),
- self.rs1.eq(insn[15:20]),
- self.rs2.eq(insn[20:25]),
-
- self.rd_we.eq(reduce(or_, (fmt == T for T in (Type.R, Type.I, Type.U, Type.J)))),
- self.rs1_re.eq(reduce(or_, (fmt == T for T in (Type.R, Type.I, Type.S, Type.B)))),
- self.rs2_re.eq(reduce(or_, (fmt == T for T in (Type.R, Type.S, Type.B)))),
-
- self.funct3.eq(funct3)
- ]
-
- def matcher(encodings):
- return reduce(or_, starmap(
- lambda opc, f3=None, f7=None, f12=None:
- (opcode == opc if opc is not None else 1) \
- & (funct3 == f3 if f3 is not None else 1) \
- & (funct7 == f7 if f7 is not None else 1) \
- & (funct12 == f12 if f12 is not None else 1),
- encodings))
-
- m.d.comb += [
- self.compare.eq(matcher([
- (Opcode.OP_IMM_32, Funct3.SLT, None), # slti
- (Opcode.OP_IMM_32, Funct3.SLTU, None), # sltiu
- (Opcode.OP_32, Funct3.SLT, 0), # slt
- (Opcode.OP_32, Funct3.SLTU, 0) # sltu
- ])),
- self.branch.eq(matcher([
- (Opcode.BRANCH, Funct3.BEQ, None), # beq
- (Opcode.BRANCH, Funct3.BNE, None), # bne
- (Opcode.BRANCH, Funct3.BLT, None), # blt
- (Opcode.BRANCH, Funct3.BGE, None), # bge
- (Opcode.BRANCH, Funct3.BLTU, None), # bltu
- (Opcode.BRANCH, Funct3.BGEU, None) # bgeu
- ])),
-
- self.adder.eq(matcher([
- (Opcode.OP_IMM_32, Funct3.ADD, None), # addi
- (Opcode.OP_32, Funct3.ADD, Funct7.ADD), # add
- (Opcode.OP_32, Funct3.ADD, Funct7.SUB) # sub
- ])),
- self.adder_sub.eq(self.rs2_re & (funct7 == Funct7.SUB)),
-
- self.logic.eq(matcher([
- (Opcode.OP_IMM_32, Funct3.XOR, None), # xori
- (Opcode.OP_IMM_32, Funct3.OR, None), # ori
- (Opcode.OP_IMM_32, Funct3.AND, None), # andi
- (Opcode.OP_32, Funct3.XOR, 0), # xor
- (Opcode.OP_32, Funct3.OR, 0), # or
- (Opcode.OP_32, Funct3.AND, 0) # and
- ])),
- ]
-
- if self.with_muldiv:
- m.d.comb += [
- self.multiply.eq(matcher([
- (Opcode.OP_32, Funct3.MUL, Funct7.MULDIV), # mul
- (Opcode.OP_32, Funct3.MULH, Funct7.MULDIV), # mulh
- (Opcode.OP_32, Funct3.MULHSU, Funct7.MULDIV), # mulhsu
- (Opcode.OP_32, Funct3.MULHU, Funct7.MULDIV), # mulhu
- ])),
-
- self.divide.eq(matcher([
- (Opcode.OP_32, Funct3.DIV, Funct7.MULDIV), # div
- (Opcode.OP_32, Funct3.DIVU, Funct7.MULDIV), # divu
- (Opcode.OP_32, Funct3.REM, Funct7.MULDIV), # rem
- (Opcode.OP_32, Funct3.REMU, Funct7.MULDIV) # remu
- ])),
- ]
-
- m.d.comb += [
- self.shift.eq(matcher([
- (Opcode.OP_IMM_32, Funct3.SLL, 0), # slli
- (Opcode.OP_IMM_32, Funct3.SR, Funct7.SRL), # srli
- (Opcode.OP_IMM_32, Funct3.SR, Funct7.SRA), # srai
- (Opcode.OP_32, Funct3.SLL, 0), # sll
- (Opcode.OP_32, Funct3.SR, Funct7.SRL), # srl
- (Opcode.OP_32, Funct3.SR, Funct7.SRA) # sra
- ])),
- self.direction.eq(funct3 == Funct3.SR),
- self.sext.eq(funct7 == Funct7.SRA),
-
- self.lui.eq(opcode == Opcode.LUI),
- self.auipc.eq(opcode == Opcode.AUIPC),
-
- self.jump.eq(matcher([
- (Opcode.JAL, None), # jal
- (Opcode.JALR, 0) # jalr
- ])),
-
- self.load.eq(matcher([
- (Opcode.LOAD, Funct3.B), # lb
- (Opcode.LOAD, Funct3.BU), # lbu
- (Opcode.LOAD, Funct3.H), # lh
- (Opcode.LOAD, Funct3.HU), # lhu
- (Opcode.LOAD, Funct3.W) # lw
- ])),
- self.store.eq(matcher([
- (Opcode.STORE, Funct3.B), # sb
- (Opcode.STORE, Funct3.H), # sh
- (Opcode.STORE, Funct3.W) # sw
- ])),
-
- self.fence_i.eq(matcher([
- (Opcode.MISC_MEM, Funct3.FENCEI) # fence.i
- ])),
-
- self.csr.eq(matcher([
- (Opcode.SYSTEM, Funct3.CSRRW), # csrrw
- (Opcode.SYSTEM, Funct3.CSRRS), # csrrs
- (Opcode.SYSTEM, Funct3.CSRRC), # csrrc
- (Opcode.SYSTEM, Funct3.CSRRWI), # csrrwi
- (Opcode.SYSTEM, Funct3.CSRRSI), # csrrsi
- (Opcode.SYSTEM, Funct3.CSRRCI) # csrrci
- ])),
- self.csr_we.eq(~funct3[1] | (self.rs1 != 0)),
-
- self.privileged.eq((opcode == Opcode.SYSTEM) & (funct3 == Funct3.PRIV)),
- self.ecall.eq(self.privileged & (funct12 == Funct12.ECALL)),
- self.ebreak.eq(self.privileged & (funct12 == Funct12.EBREAK)),
- self.mret.eq(self.privileged & (funct12 == Funct12.MRET)),
-
- self.bypass_x.eq(self.adder | self.logic | self.lui | self.auipc | self.csr),
- self.bypass_m.eq(self.compare | self.divide | self.shift),
-
- self.illegal.eq((self.instruction[:2] != 0b11) | ~reduce(or_, (
- self.compare, self.branch, self.adder, self.logic, self.multiply, self.divide, self.shift,
- self.lui, self.auipc, self.jump, self.load, self.store,
- self.csr, self.ecall, self.ebreak, self.mret
- )))
- ]
-
- return m
+++ /dev/null
-from nmigen import Elaboratable, Module, Signal, Mux, Cat, C
-
-from ..isa import Funct3
-
-
-__all__ = ["DividerInterface", "Divider", "DummyDivider"]
-
-
-class DividerInterface:
- def __init__(self):
- self.x_op = Signal(3)
- self.x_src1 = Signal(32)
- self.x_src2 = Signal(32)
- self.x_valid = Signal()
- self.x_stall = Signal()
-
- self.m_result = Signal(32)
- self.m_busy = Signal()
-
-
-class Divider(DividerInterface, Elaboratable):
- def elaborate(self, platform):
- m = Module()
-
- x_enable = Signal()
- x_modulus = Signal()
- x_signed = Signal()
-
- with m.Switch(self.x_op):
- with m.Case(Funct3.DIV):
- m.d.comb += x_enable.eq(1), x_signed.eq(1)
- with m.Case(Funct3.DIVU):
- m.d.comb += x_enable.eq(1)
- with m.Case(Funct3.REM):
- m.d.comb += x_enable.eq(1), x_modulus.eq(1), x_signed.eq(1)
- with m.Case(Funct3.REMU):
- m.d.comb += x_enable.eq(1), x_modulus.eq(1)
-
- x_negative = Signal()
- with m.If(x_modulus):
- m.d.comb += x_negative.eq(x_signed & self.x_src1[31])
- with m.Else():
- m.d.comb += x_negative.eq(x_signed & (self.x_src1[31] ^ self.x_src2[31]))
-
- x_dividend = Signal(32)
- x_divisor = Signal(32)
- m.d.comb += [
- x_dividend.eq(Mux(x_signed & self.x_src1[31], -self.x_src1, self.x_src1)),
- x_divisor.eq(Mux(x_signed & self.x_src2[31], -self.x_src2, self.x_src2))
- ]
-
- m_modulus = Signal()
- m_negative = Signal()
-
- timer = Signal(range(33), reset=32)
- quotient = Signal(32)
- divisor = Signal(32)
- remainder = Signal(32)
- difference = Signal(33)
-
- with m.FSM() as fsm:
- with m.State("IDLE"):
- with m.If(x_enable & self.x_valid & ~self.x_stall):
- m.d.sync += [
- m_modulus.eq(x_modulus),
- m_negative.eq(x_negative)
- ]
- with m.If(x_divisor == 0):
- # Division by zero
- m.d.sync += [
- quotient.eq(-1),
- remainder.eq(self.x_src1)
- ]
- with m.Elif(x_signed & (self.x_src1 == -2**31) & (self.x_src2 == -1)):
- # Signed overflow
- m.d.sync += [
- quotient.eq(self.x_src1),
- remainder.eq(0)
- ]
- with m.Elif(x_dividend == 0):
- m.d.sync += [
- quotient.eq(0),
- remainder.eq(0)
- ]
- with m.Else():
- m.d.sync += [
- quotient.eq(x_dividend),
- remainder.eq(0),
- divisor.eq(x_divisor),
- timer.eq(timer.reset)
- ]
- m.next = "DIVIDE"
-
- with m.State("DIVIDE"):
- m.d.comb += self.m_busy.eq(1)
- with m.If(timer != 0):
- m.d.sync += timer.eq(timer - 1)
- m.d.comb += difference.eq(Cat(quotient[31], remainder) - divisor)
- with m.If(difference[32]):
- m.d.sync += [
- remainder.eq(Cat(quotient[31], remainder)),
- quotient.eq(Cat(0, quotient))
- ]
- with m.Else():
- m.d.sync += [
- remainder.eq(difference),
- quotient.eq(Cat(1, quotient))
- ]
- with m.Else():
- m.d.sync += [
- quotient.eq(Mux(m_negative, -quotient, quotient)),
- remainder.eq(Mux(m_negative, -remainder, remainder))
- ]
- m.next = "IDLE"
-
- m.d.comb += self.m_result.eq(Mux(m_modulus, remainder, quotient))
-
- return m
-
-
-class DummyDivider(DividerInterface, Elaboratable):
- def elaborate(self, platform):
- m = Module()
-
- x_result = Signal.like(self.m_result)
-
- with m.Switch(self.x_op):
- # As per the RVFI specification (§ "Alternative Arithmetic Operations").
- # https://github.com/SymbioticEDA/riscv-formal/blob/master/docs/rvfi.md
- with m.Case(Funct3.DIV):
- m.d.comb += x_result.eq((self.x_src1 - self.x_src2) ^ C(0x7f8529ec))
- with m.Case(Funct3.DIVU):
- m.d.comb += x_result.eq((self.x_src1 - self.x_src2) ^ C(0x10e8fd70))
- with m.Case(Funct3.REM):
- m.d.comb += x_result.eq((self.x_src1 - self.x_src2) ^ C(0x8da68fa5))
- with m.Case(Funct3.REMU):
- m.d.comb += x_result.eq((self.x_src1 - self.x_src2) ^ C(0x3138d0e1))
-
- with m.If(~self.x_stall):
- m.d.sync += self.m_result.eq(x_result)
-
- m.d.comb += self.m_busy.eq(C(0))
-
- return m
+++ /dev/null
-from nmigen import Elaboratable, Module, Signal
-from nmigen.lib.coding import PriorityEncoder
-
-from ..csr import AutoCSR, CSR
-from ..isa import (Cause,
- mstatus_layout, misa_layout, mie_layout,
- mtvec_layout, flat_layout, mepc_layout, mcause_layout,
- flat_layout, mip_layout, flat_layout)
-
-
-__all__ = ["ExceptionUnit"]
-
-
-class ExceptionUnit(Elaboratable, AutoCSR):
- def __init__(self):
- self.mstatus = CSR(0x300, mstatus_layout, name="mstatus")
- self.misa = CSR(0x301, misa_layout, name="misa") # FIXME move elsewhere
- self.mie = CSR(0x304, mie_layout, name="mie")
- self.mtvec = CSR(0x305, mtvec_layout, name="mtvec")
- self.mscratch = CSR(0x340, flat_layout, name="mscratch") # FIXME move elsewhere
- self.mepc = CSR(0x341, mepc_layout, name="mepc")
- self.mcause = CSR(0x342, mcause_layout, name="mcause")
- self.mtval = CSR(0x343, flat_layout, name="mtval")
- self.mip = CSR(0x344, mip_layout, name="mip")
- self.irq_mask = CSR(0x330, flat_layout, name="irq_mask")
- self.irq_pending = CSR(0x360, flat_layout, name="irq_pending")
-
- self.external_interrupt = Signal(32)
- self.timer_interrupt = Signal()
- self.software_interrupt = Signal()
-
- self.m_fetch_misaligned = Signal()
- self.m_fetch_error = Signal()
- self.m_fetch_badaddr = Signal(30)
- self.m_load_misaligned = Signal()
- self.m_load_error = Signal()
- self.m_store_misaligned = Signal()
- self.m_store_error = Signal()
- self.m_loadstore_badaddr = Signal(30)
- self.m_branch_target = Signal(32)
- self.m_illegal = Signal()
- self.m_ebreak = Signal()
- self.m_ecall = Signal()
- self.m_pc = Signal(32)
- self.m_instruction = Signal(32)
- self.m_result = Signal(32)
- self.m_mret = Signal()
- self.m_stall = Signal()
- self.m_valid = Signal()
-
- self.m_raise = Signal()
-
- def elaborate(self, platform):
- m = Module()
-
- for csr in self.iter_csrs():
- with m.If(csr.we):
- m.d.sync += csr.r.eq(csr.w)
-
- trap_pe = m.submodules.trap_pe = PriorityEncoder(16)
- m.d.comb += [
- trap_pe.i[Cause.FETCH_MISALIGNED ].eq(self.m_fetch_misaligned),
- trap_pe.i[Cause.FETCH_ACCESS_FAULT ].eq(self.m_fetch_error),
- trap_pe.i[Cause.ILLEGAL_INSTRUCTION].eq(self.m_illegal),
- trap_pe.i[Cause.BREAKPOINT ].eq(self.m_ebreak),
- trap_pe.i[Cause.LOAD_MISALIGNED ].eq(self.m_load_misaligned),
- trap_pe.i[Cause.LOAD_ACCESS_FAULT ].eq(self.m_load_error),
- trap_pe.i[Cause.STORE_MISALIGNED ].eq(self.m_store_misaligned),
- trap_pe.i[Cause.STORE_ACCESS_FAULT ].eq(self.m_store_error),
- trap_pe.i[Cause.ECALL_FROM_M ].eq(self.m_ecall)
- ]
-
- m.d.sync += [
- self.irq_pending.r.eq(self.external_interrupt & self.irq_mask.r),
- self.mip.r.msip.eq(self.software_interrupt),
- self.mip.r.mtip.eq(self.timer_interrupt),
- self.mip.r.meip.eq(self.irq_pending.r.bool())
- ]
-
- interrupt_pe = m.submodules.interrupt_pe = PriorityEncoder(16)
- m.d.comb += [
- interrupt_pe.i[Cause.M_SOFTWARE_INTERRUPT].eq(self.mip.r.msip & self.mie.r.msie),
- interrupt_pe.i[Cause.M_TIMER_INTERRUPT ].eq(self.mip.r.mtip & self.mie.r.mtie),
- interrupt_pe.i[Cause.M_EXTERNAL_INTERRUPT].eq(self.mip.r.meip & self.mie.r.meie)
- ]
-
- m.d.comb += self.m_raise.eq(~trap_pe.n | ~interrupt_pe.n & self.mstatus.r.mie)
-
- with m.If(self.m_valid & ~self.m_stall):
- with m.If(self.m_raise):
- m.d.sync += [
- self.mstatus.r.mpie.eq(self.mstatus.r.mie),
- self.mstatus.r.mie.eq(0),
- self.mepc.r.base.eq(self.m_pc[2:])
- ]
- with m.If(~trap_pe.n):
- m.d.sync += [
- self.mcause.r.ecode.eq(trap_pe.o),
- self.mcause.r.interrupt.eq(0)
- ]
- with m.Switch(trap_pe.o):
- with m.Case(Cause.FETCH_MISALIGNED):
- m.d.sync += self.mtval.r.eq(self.m_branch_target)
- with m.Case(Cause.FETCH_ACCESS_FAULT):
- m.d.sync += self.mtval.r.eq(self.m_fetch_badaddr << 2)
- with m.Case(Cause.ILLEGAL_INSTRUCTION):
- m.d.sync += self.mtval.r.eq(self.m_instruction)
- with m.Case(Cause.BREAKPOINT):
- m.d.sync += self.mtval.r.eq(self.m_pc)
- with m.Case(Cause.LOAD_MISALIGNED, Cause.STORE_MISALIGNED):
- m.d.sync += self.mtval.r.eq(self.m_result)
- with m.Case(Cause.LOAD_ACCESS_FAULT, Cause.STORE_ACCESS_FAULT):
- m.d.sync += self.mtval.r.eq(self.m_loadstore_badaddr << 2)
- with m.Case():
- m.d.sync += self.mtval.r.eq(0)
- with m.Else():
- m.d.sync += [
- self.mcause.r.ecode.eq(interrupt_pe.o),
- self.mcause.r.interrupt.eq(1)
- ]
- with m.Elif(self.m_mret):
- m.d.sync += self.mstatus.r.mie.eq(self.mstatus.r.mpie)
-
- return m
+++ /dev/null
-from nmigen import Elaboratable, Module, Signal
-
-from ..isa import Funct3
-
-
-__all__ = ["LogicUnit"]
-
-
-class LogicUnit(Elaboratable):
- def __init__(self):
- self.op = Signal(3)
- self.src1 = Signal(32)
- self.src2 = Signal(32)
-
- self.result = Signal(32)
-
- def elaborate(self, platform):
- m = Module()
-
- with m.Switch(self.op):
- with m.Case(Funct3.XOR):
- m.d.comb += self.result.eq(self.src1 ^ self.src2)
- with m.Case(Funct3.OR):
- m.d.comb += self.result.eq(self.src1 | self.src2)
- with m.Case(Funct3.AND):
- m.d.comb += self.result.eq(self.src1 & self.src2)
-
- return m
+++ /dev/null
-from nmigen import Elaboratable, Module, Signal, Cat, Mux, C, signed
-
-from ..isa import Funct3
-
-
-__all__ = ["MultiplierInterface", "Multiplier", "DummyMultiplier"]
-
-
-class MultiplierInterface:
- def __init__(self):
- self.x_op = Signal(3)
- self.x_src1 = Signal(32)
- self.x_src2 = Signal(32)
- self.x_stall = Signal()
- self.m_stall = Signal()
-
- self.w_result = Signal(32)
-
-
-class Multiplier(MultiplierInterface, Elaboratable):
- def elaborate(self, platform):
- m = Module()
-
- x_low = Signal()
- x_src1_signed = Signal()
- x_src2_signed = Signal()
-
- m.d.comb += [
- x_low.eq(self.x_op == Funct3.MUL),
- x_src1_signed.eq((self.x_op == Funct3.MULH) |
- (self.x_op == Funct3.MULHSU)),
- x_src2_signed.eq(self.x_op == Funct3.MULH)
- ]
-
- x_src1 = Signal(signed(33))
- x_src2 = Signal(signed(33))
-
- m.d.comb += [
- x_src1.eq(Cat(self.x_src1, x_src1_signed & self.x_src1[31])),
- x_src2.eq(Cat(self.x_src2, x_src2_signed & self.x_src2[31]))
- ]
-
- m_low = Signal()
- m_prod = Signal(signed(66))
-
- with m.If(~self.x_stall):
- m.d.sync += [
- m_low.eq(x_low),
- m_prod.eq(x_src1 * x_src2)
- ]
-
- with m.If(~self.m_stall):
- m.d.sync += self.w_result.eq(Mux(m_low, m_prod[:32], m_prod[32:]))
-
- return m
-
-
-class DummyMultiplier(MultiplierInterface, Elaboratable):
- def elaborate(self, platform):
- m = Module()
-
- x_result = Signal.like(self.w_result)
- m_result = Signal.like(self.w_result)
-
- with m.Switch(self.x_op):
- # As per the RVFI specification (§ "Alternative Arithmetic Operations").
- # https://github.com/SymbioticEDA/riscv-formal/blob/master/docs/rvfi.md
- with m.Case(Funct3.MUL):
- m.d.comb += x_result.eq((self.x_src1 +
- self.x_src2) ^ C(0x5876063e))
- with m.Case(Funct3.MULH):
- m.d.comb += x_result.eq((self.x_src1 +
- self.x_src2) ^ C(0xf6583fb7))
- with m.Case(Funct3.MULHSU):
- m.d.comb += x_result.eq((self.x_src1 -
- self.x_src2) ^ C(0xecfbe137))
- with m.Case(Funct3.MULHU):
- m.d.comb += x_result.eq((self.x_src1 +
- self.x_src2) ^ C(0x949ce5e8))
-
- with m.If(~self.x_stall):
- m.d.sync += m_result.eq(x_result)
- with m.If(~self.m_stall):
- m.d.sync += self.w_result.eq(m_result)
-
- return m
+++ /dev/null
-from nmigen import Elaboratable, Module, Signal, Mux, Repl, Cat
-
-
-__all__ = ["Shifter"]
-
-
-class Shifter(Elaboratable):
- def __init__(self):
- self.x_direction = Signal()
- self.x_sext = Signal()
- self.x_shamt = Signal(5)
- self.x_src1 = Signal(32)
- self.x_stall = Signal()
-
- self.m_result = Signal(32)
-
- def elaborate(self, platform):
- m = Module()
-
- x_operand = Signal(32)
- x_filler = Signal()
- m_direction = Signal()
- m_result = Signal(32)
-
- m.d.comb += [
- # left shifts are equivalent to right shifts with reversed bits
- x_operand.eq(Mux(self.x_direction, self.x_src1, self.x_src1[::-1])),
- x_filler.eq(Mux(self.x_direction & self.x_sext, self.x_src1[-1], 0))
- ]
-
- with m.If(~self.x_stall):
- m.d.sync += [
- m_direction.eq(self.x_direction),
- m_result.eq(Cat(x_operand, Repl(x_filler, 32)) >> self.x_shamt)
- ]
-
- m.d.comb += self.m_result.eq(Mux(m_direction, m_result, m_result[::-1]))
-
- return m
+++ /dev/null
-from functools import reduce
-from operator import or_
-
-from nmigen import Elaboratable, Module, Signal, Record
-
-from ..csr import AutoCSR, CSR
-from ..isa import flat_layout, tdata1_layout
-
-
-__all__ = ["TriggerUnit"]
-
-
-class Type:
- NOP = 0
- LEGACY = 1
- MATCH = 2
- INSN_COUNT = 3
- INTERRUPT = 4
- EXCEPTION = 5
-
-
-mcontrol_layout = [
- ("load", 1),
- ("store", 1),
- ("execute", 1),
- ("u", 1),
- ("s", 1),
- ("zero0", 1),
- ("m", 1),
- ("match", 4),
- ("chain", 1),
- ("action", 4),
- ("size", 2),
- ("timing", 1),
- ("select", 1),
- ("hit", 1),
- ("maskmax", 6)
-]
-
-
-class TriggerUnit(Elaboratable, AutoCSR):
- def __init__(self, nb_triggers):
- self.nb_triggers = nb_triggers
-
- self.tselect = CSR(0x7a0, flat_layout, name="tselect")
- self.tdata1 = CSR(0x7a1, tdata1_layout, name="tdata1")
- self.tdata2 = CSR(0x7a2, flat_layout, name="tdata2")
-
- self.x_pc = Signal(32)
- self.x_valid = Signal()
-
- self.haltreq = Signal()
- self.trap = Signal()
-
- def elaborate(self, platform):
- m = Module()
-
- triggers = [Record.like(self.tdata1.r) for _ in range(self.nb_triggers)]
- for t in triggers:
- # We only support address/data match triggers.
- m.d.comb += t.type.eq(Type.MATCH)
-
- def do_trigger_update(trigger):
- m.d.sync += trigger.dmode.eq(self.tdata1.w.dmode)
- mcontrol = Record([("i", mcontrol_layout), ("o", mcontrol_layout)])
- m.d.comb += [
- mcontrol.i.eq(self.tdata1.w.data),
- mcontrol.o.execute.eq(mcontrol.i.execute),
- mcontrol.o.m.eq(mcontrol.i.m),
- mcontrol.o.action.eq(mcontrol.i.action),
- ]
- m.d.sync += trigger.data.eq(mcontrol.o)
-
- with m.Switch(self.tselect.r.value):
- for i, t in enumerate(triggers):
- with m.Case(i):
- m.d.comb += self.tdata1.r.eq(t)
- with m.If(self.tdata1.we):
- do_trigger_update(t)
-
- with m.If(self.tselect.we):
- with m.If(self.tselect.w.value < self.nb_triggers):
- m.d.sync += self.tselect.r.value.eq(self.tselect.w.value)
-
- with m.If(self.tdata2.we):
- m.d.sync += self.tdata2.r.eq(self.tdata2.w)
-
- hit = Signal()
- halt = Signal()
-
- with m.Switch(self.tdata1.r.type):
- with m.Case(Type.MATCH):
- mcontrol = Record(mcontrol_layout)
- m.d.comb += mcontrol.eq(self.tdata1.r.data)
- match = Signal()
- with m.If(mcontrol.execute):
- m.d.comb += match.eq(self.tdata2.r == self.x_pc & self.x_valid)
- m.d.comb += [
- hit.eq(match & mcontrol.m),
- halt.eq(mcontrol.action)
- ]
-
- with m.If(hit):
- with m.If(halt):
- m.d.comb += self.haltreq.eq(self.tdata1.r.dmode)
- with m.Else():
- m.d.comb += self.trap.eq(1)
-
- return m