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)
#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',
# 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
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)
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)
# 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':
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)
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])
dbg_sync = ClockDomain(self.dbg_domain)
m.domains += dbg_sync
+ # create a delay, but remember it is in the power-on-reset clock domain!
ti_rst = Signal(reset_less=True)
delay = Signal(range(4), reset=3)
+ stop_delay = Signal(range(16), reset=5)
with m.If(delay != 0):
- m.d.por += delay.eq(delay - 1)
+ m.d.por += delay.eq(delay - 1) # decrement... in POR domain!
+ with m.If(stop_delay != 0):
+ m.d.por += stop_delay.eq(stop_delay - 1) # likewise
comb += cd_por.clk.eq(ClockSignal())
# power-on reset delay
else:
with m.If(delay != 0 | dbg.core_rst_o):
comb += core_rst.eq(1)
+ with m.If(stop_delay != 0):
+ # run DMI core-stop as well but on an extra couple of cycles
+ comb += dbg.core_stopped_i.eq(1)
# connect external reset signal to DMI Reset
if self.dbg_domain != "sync":
comb += pdecode2.dec.bigendian.eq(self.core_bigendian_i)
# temporary hack: says "go" immediately for both address gen and ST
+ # XXX: st.go_i is set to 1 cycle delay to reduce combinatorial chains
l0 = core.l0
ldst = core.fus.fus['ldst0']
st_go_edge = rising_edge(m, ldst.st.rel_o)
# link addr-go direct to rel
m.d.comb += ldst.ad.go_i.eq(ldst.ad.rel_o)
- m.d.comb += ldst.st.go_i.eq(st_go_edge) # link store-go to rising rel
+ m.d.sync += ldst.st.go_i.eq(st_go_edge) # link store-go to rising rel
def do_dmi(self, m, dbg):
"""deals with DMI debug requests
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
# 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
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'
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
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():
# 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()
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
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"):
with m.FSM(name='fetch_fsm'):
+ # 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 & ~core_rst):
+ m.next = "IDLE"
+
# waiting (zzz)
with m.State("IDLE"):
# fetch allowed if not failed and stopped but not stepping
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
# 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)
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.
# 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():
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
# 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):
# 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)
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