"""simple core issuer not in any way intended for production use. this runs a FSM that: * reads the Program Counter from StateRegs * reads an instruction from a fixed-size Test Memory * issues it to the Simple Core * waits for it to complete * increments the PC * does it all over again the purpose of this module is to verify the functional correctness of the Function Units in the absolute simplest and clearest possible way, and to at provide something that can be further incrementally improved. """ from nmigen import (Elaboratable, Module, Signal, ClockSignal, ResetSignal, ClockDomain, DomainRenamer, Mux, Const) from nmigen.cli import rtlil from nmigen.cli import main import sys from soc.decoder.power_decoder import create_pdecode from soc.decoder.power_decoder2 import PowerDecode2, SVP64PrefixDecoder from soc.decoder.decode2execute1 import IssuerDecode2ToOperand from soc.decoder.decode2execute1 import Data from soc.experiment.testmem import TestMemory # test only for instructions from soc.regfile.regfiles import StateRegs, FastRegs from soc.simple.core import NonProductionCore from soc.config.test.test_loadstore import TestMemPspec from soc.config.ifetch import ConfigFetchUnit from soc.decoder.power_enums import MicrOp, SVP64PredInt, SVP64PredCR from soc.debug.dmi import CoreDebug, DMIInterface from soc.debug.jtag import JTAG from soc.config.pinouts import get_pinspecs from soc.config.state import CoreState from soc.interrupts.xics import XICS_ICP, XICS_ICS from soc.bus.simple_gpio import SimpleGPIO from soc.bus.SPBlock512W64B8W import SPBlock512W64B8W from soc.clock.select import ClockSelect from soc.clock.dummypll import DummyPLL from soc.sv.svstate import SVSTATERec from nmutil.util import rising_edge def get_insn(f_instr_o, pc): if f_instr_o.width == 32: return f_instr_o else: # 64-bit: bit 2 of pc decides which word to select return f_instr_o.word_select(pc[2], 32) # gets state input or reads from state regfile def state_get(m, state_i, name, regfile, regnum): comb = m.d.comb sync = m.d.sync # read the PC res = Signal(64, reset_less=True, name=name) res_ok_delay = Signal(name="%s_ok_delay" % name) sync += res_ok_delay.eq(~state_i.ok) with m.If(state_i.ok): # incoming override (start from pc_i) comb += res.eq(state_i.data) with m.Else(): # otherwise read StateRegs regfile for PC... comb += regfile.ren.eq(1<1 loop with m.If(~dbg.core_stop_o & ~core_rst): comb += exec_pc_ready_i.eq(1) with m.If(exec_pc_valid_o): # was this the last loop iteration? is_last = Signal() cur_vl = cur_state.svstate.vl comb += is_last.eq(next_srcstep == cur_vl) # if either PC or SVSTATE were changed by the previous # instruction, go directly back to Fetch, without # updating either PC or SVSTATE with m.If(pc_changed | sv_changed): m.next = "ISSUE_START" # also return to Fetch, when no output was a vector # (regardless of SRCSTEP and VL), or when the last # instruction was really the last one of the VL loop with m.Elif((~pdecode2.loop_continue) | is_last): # before going back to fetch, update the PC state # register with the NIA. # ok here we are not reading the branch unit. # TODO: this just blithely overwrites whatever # pipeline updated the PC comb += self.state_w_pc.wen.eq(1 << StateRegs.PC) comb += self.state_w_pc.data_i.eq(nia) # reset SRCSTEP before returning to Fetch with m.If(pdecode2.loop_continue): comb += new_svstate.srcstep.eq(0) comb += new_svstate.dststep.eq(0) comb += update_svstate.eq(1) m.next = "ISSUE_START" # returning to Execute? then, first update SRCSTEP with m.Else(): comb += new_svstate.srcstep.eq(next_srcstep) comb += new_svstate.dststep.eq(next_dststep) comb += update_svstate.eq(1) m.next = "DECODE_SV" with m.Else(): comb += core.core_stopped_i.eq(1) comb += dbg.core_stopped_i.eq(1) # while stopped, allow updating the PC and SVSTATE with m.If(self.pc_i.ok): comb += self.state_w_pc.wen.eq(1 << StateRegs.PC) comb += self.state_w_pc.data_i.eq(self.pc_i.data) sync += pc_changed.eq(1) with m.If(self.svstate_i.ok): comb += new_svstate.eq(self.svstate_i.data) comb += update_svstate.eq(1) sync += sv_changed.eq(1) # need to decode the instruction again, after updating SRCSTEP # in the previous state. # mostly a copy of INSN_WAIT, but without the actual wait with m.State("DECODE_SV"): # decode the instruction sync += core.e.eq(pdecode2.e) sync += core.state.eq(cur_state) sync += core.bigendian_i.eq(self.core_bigendian_i) sync += core.sv_a_nz.eq(pdecode2.sv_a_nz) m.next = "INSN_EXECUTE" # move to "execute" # check if svstate needs updating: if so, write it to State Regfile with m.If(update_svstate): comb += self.state_w_sv.wen.eq(1<