X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fsoc%2Fsimple%2Fissuer.py;h=15bd1760a5ab93f233d8cb7cdff813d7b0833096;hb=HEAD;hp=cfad831a3fa76a92c71464fbd95dc0554b8328d0;hpb=cc9d98a1dcc6c307c4a716fab0bbddb11ac9be39;p=soc.git diff --git a/src/soc/simple/issuer.py b/src/soc/simple/issuer.py index cfad831a..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 @@ -615,6 +637,10 @@ class TestIssuerBase(Elaboratable): # reset current state if core reset requested 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) # check halted condition: requested PC to execute matches DMI stop addr # and immediately stop. address of 0xffff_ffff_ffff_ffff can never @@ -679,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' @@ -690,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 @@ -727,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(): @@ -747,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() @@ -792,7 +832,7 @@ class TestIssuerInternal(TestIssuerBase): easy understanding) come later. """ - def fetch_fsm(self, m, dbg, core, pc, msr, svstate, 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 @@ -806,6 +846,7 @@ class TestIssuerInternal(TestIssuerBase): pdecode2 = self.pdecode2 cur_state = self.cur_state dec_opcode_i = pdecode2.dec.raw_opcode_in # raw opcode + pc, msr, svstate = cur_state.pc, cur_state.msr, cur_state.svstate # also note instruction fetch failed if hasattr(core, "icache"): @@ -825,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) @@ -843,11 +884,6 @@ class TestIssuerInternal(TestIssuerBase): comb += self.imem.a_pc_i.eq(pc) comb += self.imem.a_i_valid.eq(1) comb += self.imem.f_i_valid.eq(1) - # transfer state to output - sync += cur_state.pc.eq(pc) - sync += cur_state.svstate.eq(svstate) # and svstate - sync += cur_state.msr.eq(msr) # and msr - m.next = "INSN_READ" # move to "wait for bus" phase # dummy pause to find out why simulation is not keeping up @@ -906,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) @@ -1175,8 +1211,14 @@ class TestIssuerInternal(TestIssuerBase): fetch_failed = Const(0, 1) flush_needed = False + sync += fetch_pc_i_valid.eq(0) + 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. @@ -1186,7 +1228,10 @@ class TestIssuerInternal(TestIssuerBase): # wait on "core stop" release, before next fetch # need to do this here, in case we are in a VL==0 loop with m.If(~dbg.core_stop_o & ~core_rst): - comb += fetch_pc_i_valid.eq(1) # tell fetch to start + sync += fetch_pc_i_valid.eq(1) # tell fetch to start + sync += cur_state.pc.eq(dbg.state.pc) + sync += cur_state.svstate.eq(dbg.state.svstate) + sync += cur_state.msr.eq(dbg.state.msr) with m.If(fetch_pc_o_ready): # fetch acknowledged us m.next = "INSN_WAIT" with m.Else(): @@ -1460,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 @@ -1485,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): @@ -1583,8 +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, dbg.state.pc, dbg.state.msr, - dbg.state.svstate, 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) @@ -1606,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