X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fsoc%2Fsimple%2Fissuer.py;h=15bd1760a5ab93f233d8cb7cdff813d7b0833096;hb=HEAD;hp=176264efefed53534f19c0b00bf34d4c6f36ce28;hpb=b263f3f6f134c2f1d9be78d69b1799b3fbd90b4d;p=soc.git diff --git a/src/soc/simple/issuer.py b/src/soc/simple/issuer.py index 176264ef..15bd1760 100644 --- a/src/soc/simple/issuer.py +++ b/src/soc/simple/issuer.py @@ -169,6 +169,21 @@ class TestIssuerBase(Elaboratable): self.microwatt_compat = (hasattr(pspec, "microwatt_compat") and (pspec.microwatt_compat == True)) self.alt_reset = Signal(reset_less=True) # not connected yet (microwatt) + # test if fabric compatibility is to be enabled + self.fabric_compat = (hasattr(pspec, "fabric_compat") and + (pspec.fabric_compat == True)) + + if self.microwatt_compat or self.fabric_compat: + + if hasattr(pspec, "microwatt_old"): + self.microwatt_old = pspec.microwatt_old + else: + self.microwatt_old = True # PLEASE DO NOT ALTER THIS + + if hasattr(pspec, "microwatt_debug"): + self.microwatt_debug = pspec.microwatt_debug + else: + self.microwatt_debug = True # set to False when using an FPGA # test is SVP64 is to be enabled self.svp64_en = hasattr(pspec, "svp64") and (pspec.svp64 == True) @@ -194,7 +209,7 @@ class TestIssuerBase(Elaboratable): #self.dbg_domain = "sync" # sigh "dbgsunc" too problematic self.dbg_domain = "dbgsync" # domain for DMI/JTAG clock if self.jtag_en: - # XXX MUST keep this up-to-date with litex, and + # XXX MUST keep this up-to-date with fabric, and # soc-cocotb-sim, and err.. all needs sorting out, argh subset = ['uart', 'mtwi', @@ -307,7 +322,7 @@ class TestIssuerBase(Elaboratable): # hack method of keeping an eye on whether branch/trap set the PC self.state_nia = self.core.regs.rf['state'].w_ports['nia'] self.state_nia.wen.name = 'state_nia_wen' - # and whether SPR pipeline sets DEC or TB + # and whether SPR pipeline sets DEC or TB (fu/spr/main_stage.py) self.state_spr = self.core.regs.rf['state'].w_ports['state1'] # pulse to synchronize the simulator at instruction end @@ -321,14 +336,15 @@ class TestIssuerBase(Elaboratable): self.srcmask = Signal(64) self.dstmask = Signal(64) - # sigh, the wishbone addresses are not wishbone-compliant in microwatt - if self.microwatt_compat: + # sigh, the wishbone addresses are not wishbone-compliant + # in old versions of microwatt, tplaten_3d_game is a new one + if self.microwatt_compat or self.fabric_compat: self.ibus_adr = Signal(32, name='wishbone_insn_out.adr') self.dbus_adr = Signal(32, name='wishbone_data_out.adr') # add an output of the PC and instruction, and whether it was requested # this is for verilator debug purposes - if self.microwatt_compat: + if self.microwatt_compat or self.fabric_compat: self.nia = Signal(64) self.msr_o = Signal(64) self.nia_req = Signal(1) @@ -351,7 +367,7 @@ class TestIssuerBase(Elaboratable): csd = DomainRenamer(self.core_domain) dbd = DomainRenamer(self.dbg_domain) - if self.microwatt_compat: + if self.microwatt_compat or self.fabric_compat: m.submodules.core = core = self.core else: m.submodules.core = core = csd(self.core) @@ -372,7 +388,7 @@ class TestIssuerBase(Elaboratable): # fixup the clocks in microwatt-compat mode (but leave resets alone # so that microwatt soc.vhdl can pull a reset on the core or DMI # can do it, just like in TestIssuer) - if self.microwatt_compat: + if self.microwatt_compat or self.fabric_compat: intclk = ClockSignal(self.core_domain) dbgclk = ClockSignal(self.dbg_domain) if self.core_domain != 'sync': @@ -380,21 +396,26 @@ class TestIssuerBase(Elaboratable): if self.dbg_domain != 'sync': comb += dbgclk.eq(ClockSignal()) + # if using old version of microwatt # drop the first 3 bits of the incoming wishbone addresses - # this can go if using later versions of microwatt (not now) - if self.microwatt_compat: + if self.microwatt_compat or self.fabric_compat: ibus = self.imem.ibus dbus = self.core.l0.cmpi.wb_bus() - comb += self.ibus_adr.eq(Cat(Const(0, 3), ibus.adr)) - comb += self.dbus_adr.eq(Cat(Const(0, 3), dbus.adr)) - # microwatt verilator debug purposes - pi = self.core.l0.cmpi.pi.pi - comb += self.ldst_req.eq(pi.addr_ok_o) - comb += self.ldst_addr.eq(pi.addr) + if self.microwatt_old: + comb += self.ibus_adr.eq(Cat(Const(0, 3), ibus.adr)) + comb += self.dbus_adr.eq(Cat(Const(0, 3), dbus.adr)) + else: + comb += self.ibus_adr.eq(ibus.adr) + comb += self.dbus_adr.eq(dbus.adr) + if self.microwatt_debug: + # microwatt verilator debug purposes + pi = self.core.l0.cmpi.pi.pi + comb += self.ldst_req.eq(pi.addr_ok_o) + comb += self.ldst_addr.eq(pi.addr) cur_state = self.cur_state - # 4x 4k SRAM blocks. these simply "exist", they get routed in litex + # 4x 4k SRAM blocks. these simply "exist", they get routed in fabric if self.sram4x4k: for i, sram in enumerate(self.sram4k): m.submodules["sram4k_%d" % i] = csd(sram) @@ -414,7 +435,7 @@ class TestIssuerBase(Elaboratable): m.submodules.simple_gpio = simple_gpio = csd(self.simple_gpio) # connect one GPIO output to ICS bit 15 (like in microwatt soc.vhdl) - # XXX causes litex ECP5 test to get wrong idea about input and output + # XXX causes fabric ECP5 test to get wrong idea about input and output # (but works with verilator sim *sigh*) # if self.gpio and self.xics: # comb += self.int_level_i[15].eq(simple_gpio.gpio_o[0]) @@ -555,6 +576,7 @@ class TestIssuerBase(Elaboratable): state_r_dectb = state_rf.r_ports['issue'] # DEC/TB state_w_dectb = state_rf.w_ports['issue'] # DEC/TB + with m.FSM() as fsm: # initiates read of current DEC @@ -616,6 +638,7 @@ class TestIssuerBase(Elaboratable): with m.If(core_rst): m.d.sync += self.cur_state.eq(0) # and, sigh, set configured values, which are also done in regfile + # XXX ??? what the hell is the shift for?? m.d.sync += self.cur_state.pc.eq(self.core.pc_at_reset) m.d.sync += self.cur_state.msr.eq(self.core.msr_at_reset) @@ -682,7 +705,7 @@ class TestIssuerBase(Elaboratable): sync += self.sv_changed.eq(1) # start renaming some of the ports to match microwatt - if self.microwatt_compat: + if self.microwatt_compat or self.fabric_compat: self.core.o.core_terminate_o.name = "terminated_out" # names of DMI interface self.dbg.dmi.addr_i.name = 'dmi_addr' @@ -693,26 +716,28 @@ class TestIssuerBase(Elaboratable): self.dbg.dmi.ack_o.name = 'dmi_ack' # wishbone instruction bus ibus = self.imem.ibus - ibus.adr.name = 'wishbone_insn_out.adr' - ibus.dat_w.name = 'wishbone_insn_out.dat' - ibus.sel.name = 'wishbone_insn_out.sel' - ibus.cyc.name = 'wishbone_insn_out.cyc' - ibus.stb.name = 'wishbone_insn_out.stb' - ibus.we.name = 'wishbone_insn_out.we' - ibus.dat_r.name = 'wishbone_insn_in.dat' - ibus.ack.name = 'wishbone_insn_in.ack' - ibus.stall.name = 'wishbone_insn_in.stall' + if self.microwatt_compat: + ibus.adr.name = 'wishbone_insn_out.adr' + ibus.dat_w.name = 'wishbone_insn_out.dat' + ibus.sel.name = 'wishbone_insn_out.sel' + ibus.cyc.name = 'wishbone_insn_out.cyc' + ibus.stb.name = 'wishbone_insn_out.stb' + ibus.we.name = 'wishbone_insn_out.we' + ibus.dat_r.name = 'wishbone_insn_in.dat' + ibus.ack.name = 'wishbone_insn_in.ack' + ibus.stall.name = 'wishbone_insn_in.stall' # wishbone data bus dbus = self.core.l0.cmpi.wb_bus() - dbus.adr.name = 'wishbone_data_out.adr' - dbus.dat_w.name = 'wishbone_data_out.dat' - dbus.sel.name = 'wishbone_data_out.sel' - dbus.cyc.name = 'wishbone_data_out.cyc' - dbus.stb.name = 'wishbone_data_out.stb' - dbus.we.name = 'wishbone_data_out.we' - dbus.dat_r.name = 'wishbone_data_in.dat' - dbus.ack.name = 'wishbone_data_in.ack' - dbus.stall.name = 'wishbone_data_in.stall' + if self.microwatt_compat: + dbus.adr.name = 'wishbone_data_out.adr' + dbus.dat_w.name = 'wishbone_data_out.dat' + dbus.sel.name = 'wishbone_data_out.sel' + dbus.cyc.name = 'wishbone_data_out.cyc' + dbus.stb.name = 'wishbone_data_out.stb' + dbus.we.name = 'wishbone_data_out.we' + dbus.dat_r.name = 'wishbone_data_in.dat' + dbus.ack.name = 'wishbone_data_in.ack' + dbus.stall.name = 'wishbone_data_in.stall' return m @@ -730,15 +755,24 @@ class TestIssuerBase(Elaboratable): return list(self) def external_ports(self): - if self.microwatt_compat: - ports = [self.core.o.core_terminate_o, - self.ext_irq, - self.alt_reset, # not connected yet - self.nia, self.insn, self.nia_req, self.msr_o, - self.ldst_req, self.ldst_addr, - ClockSignal(), - ResetSignal(), - ] + if self.microwatt_compat or self.fabric_compat: + if self.fabric_compat: + ports = [self.core.o.core_terminate_o, + self.alt_reset, # not connected yet + self.nia, self.insn, self.nia_req, self.msr_o, + self.ldst_req, self.ldst_addr, + ClockSignal(), + ResetSignal(), + ] + else: + ports = [self.core.o.core_terminate_o, + self.ext_irq, + self.alt_reset, # not connected yet + self.nia, self.insn, self.nia_req, self.msr_o, + self.ldst_req, self.ldst_addr, + ClockSignal(), + ResetSignal(), + ] ports += list(self.dbg.dmi.ports()) # for dbus/ibus microwatt, exclude err btw and cti for name, sig in self.imem.ibus.fields.items(): @@ -750,7 +784,10 @@ class TestIssuerBase(Elaboratable): # microwatt non-compliant with wishbone ports.append(self.ibus_adr) ports.append(self.dbus_adr) - return ports + + if self.microwatt_compat: + # Ignore the remaining ports in microwatt compat mode + return ports ports = self.pc_i.ports() ports = self.msr_i.ports() @@ -795,7 +832,7 @@ class TestIssuerInternal(TestIssuerBase): easy understanding) come later. """ - def fetch_fsm(self, m, dbg, core, nia, is_svp64_mode, + def fetch_fsm(self, m, dbg, core, core_rst, nia, is_svp64_mode, fetch_pc_o_ready, fetch_pc_i_valid, fetch_insn_o_valid, fetch_insn_i_ready): """fetch FSM @@ -829,7 +866,7 @@ class TestIssuerInternal(TestIssuerBase): # allow fetch to not run at startup due to I-Cache reset not # having time to settle. power-on-reset holds dbg.core_stopped_i with m.State("PRE_IDLE"): - with m.If(~dbg.core_stopped_i & ~dbg.core_stop_o): + with m.If(~dbg.core_stopped_i & ~dbg.core_stop_o & ~core_rst): m.next = "IDLE" # waiting (zzz) @@ -905,7 +942,7 @@ class TestIssuerInternal(TestIssuerBase): # not SVP64 - 32-bit only sync += nia.eq(cur_state.pc + 4) sync += dec_opcode_i.eq(insn) - if self.microwatt_compat: + if self.microwatt_compat or self.fabric_compat: # for verilator debug purposes comb += self.insn.eq(insn) comb += self.nia.eq(cur_state.pc) @@ -1178,6 +1215,10 @@ class TestIssuerInternal(TestIssuerBase): with m.FSM(name="issue_fsm"): + with m.State("PRE_IDLE"): + with m.If(~dbg.core_stop_o & ~core_rst): + m.next = "ISSUE_START" + # sync with the "fetch" phase which is reading the instruction # at this point, there is no instruction running, that # could inadvertently update the PC. @@ -1464,6 +1505,7 @@ class TestIssuerInternal(TestIssuerBase): sync = m.d.sync dbg = self.dbg pdecode2 = self.pdecode2 + cur_state = self.cur_state # temporaries core_busy_o = core.n.o_data.busy_o # core is busy @@ -1489,18 +1531,26 @@ class TestIssuerInternal(TestIssuerBase): # instruction started: must wait till it finishes with m.State("INSN_ACTIVE"): - # note changes to MSR, PC and SVSTATE, and DEC/TB - # these last two are done together, and passed to the - # DEC/TB FSM + # note changes to MSR, PC and SVSTATE with m.If(self.state_nia.wen & (1 << StateRegs.SVSTATE)): sync += self.sv_changed.eq(1) with m.If(self.state_nia.wen & (1 << StateRegs.MSR)): sync += self.msr_changed.eq(1) with m.If(self.state_nia.wen & (1 << StateRegs.PC)): sync += self.pc_changed.eq(1) - with m.If((self.state_spr.wen & - ((1 << StateRegs.DEC) | (1 << StateRegs.TB))).bool()): + # and note changes to DEC/TB, to be passed to DEC/TB FSM + with m.If(self.state_spr.wen & (1 << StateRegs.TB)): + comb += self.pause_dec_tb.eq(1) + # but also zero-out the cur_state DEC so that, on + # the next instruction, if it is "enable interrupt" + # the delay between the DEC/TB FSM reading and updating + # cur_state.dec doesn't trigger a spurious interrupt. + # the DEC/TB FSM will read the regfile and update to + # the correct value, so having cur_state.dec set to zero + # for a while is no big deal. + with m.If(self.state_spr.wen & (1 << StateRegs.DEC)): comb += self.pause_dec_tb.eq(1) + sync += cur_state.dec.eq(0) # only needs top bit clear with m.If(~core_busy_o): # instruction done! comb += exec_pc_o_valid.eq(1) with m.If(exec_pc_i_ready): @@ -1587,7 +1637,7 @@ class TestIssuerInternal(TestIssuerBase): # Issue is where the VL for-loop # lives. the ready/valid # signalling is used to communicate between the four. - self.fetch_fsm(m, dbg, core, nia, is_svp64_mode, + self.fetch_fsm(m, dbg, core, core_rst, nia, is_svp64_mode, fetch_pc_o_ready, fetch_pc_i_valid, fetch_insn_o_valid, fetch_insn_i_ready) @@ -1609,9 +1659,10 @@ class TestIssuerInternal(TestIssuerBase): exec_insn_i_valid, exec_insn_o_ready, exec_pc_o_valid, exec_pc_i_ready) - # whatever was done above, over-ride it if core reset is held + # whatever was done above, over-ride it if core reset is held. + # set NIA to pc_at_reset with m.If(core_rst): - sync += nia.eq(0) + sync += nia.eq(self.core.pc_at_reset) return m