X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fsoc%2Fsimple%2Fissuer.py;h=27afb68ed4546c2751f87f35db7373f845c7464b;hb=50adde0faa929c2c1e9f305357cbae6d9f0deae7;hp=558ee51ed92c1727fcc2fdac1fefd419cc09e5e6;hpb=146dd2e838c85ed023a1e857381108c74beaf76f;p=soc.git diff --git a/src/soc/simple/issuer.py b/src/soc/simple/issuer.py index 558ee51e..27afb68e 100644 --- a/src/soc/simple/issuer.py +++ b/src/soc/simple/issuer.py @@ -2,7 +2,7 @@ not in any way intended for production use. this runs a FSM that: -* reads the Program Counter from FastRegs +* 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 @@ -21,28 +21,73 @@ 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 +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 FastRegs +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 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.clock.select import ClockSelect, DummyPLL + from nmutil.util import rising_edge -class TestIssuer(Elaboratable): +class TestIssuerInternal(Elaboratable): """TestIssuer - reads instructions from TestMemory and issues them efficiency and speed is not the main goal here: functional correctness is. """ def __init__(self, pspec): - # main instruction core + + # JTAG interface. add this right at the start because if it's + # added it *modifies* the pspec, by adding enable/disable signals + # for parts of the rest of the core + self.jtag_en = hasattr(pspec, "debug") and pspec.debug == 'jtag' + if self.jtag_en: + subset = {'uart', 'mtwi', 'eint', 'gpio', 'mspi0', 'mspi1', + 'pwm', 'sd0', 'sdr'} + self.jtag = JTAG(get_pinspecs(subset=subset)) + # add signals to pspec to enable/disable icache and dcache + # (or data and intstruction wishbone if icache/dcache not included) + # https://bugs.libre-soc.org/show_bug.cgi?id=520 + # TODO: do we actually care if these are not domain-synchronised? + # honestly probably not. + pspec.wb_icache_en = self.jtag.wb_icache_en + pspec.wb_dcache_en = self.jtag.wb_dcache_en + + # add interrupt controller? + self.xics = hasattr(pspec, "xics") and pspec.xics == True + if self.xics: + self.xics_icp = XICS_ICP() + self.xics_ics = XICS_ICS() + self.int_level_i = self.xics_ics.int_level_i + + # add GPIO peripheral? + self.gpio = hasattr(pspec, "gpio") and pspec.gpio == True + if self.gpio: + self.simple_gpio = SimpleGPIO() + self.gpio_o = self.simple_gpio.gpio_o + + # main instruction core25 self.core = core = NonProductionCore(pspec) + # instruction decoder. goes into Trap Record + pdecode = create_pdecode() + self.cur_state = CoreState("cur") # current state (MSR/PC/EINT) + self.pdecode2 = PowerDecode2(pdecode, state=self.cur_state, + opkls=IssuerDecode2ToOperand) + # Test Instruction memory self.imem = ConfigFetchUnit(pspec).fu # one-row cache of instruction read @@ -59,17 +104,23 @@ class TestIssuer(Elaboratable): self.busy_o = Signal(reset_less=True) self.memerr_o = Signal(reset_less=True) - # FAST regfile read /write ports for PC and MSR - self.fast_r_pc = self.core.regs.rf['fast'].r_ports['cia'] # PC rd - self.fast_w_pc = self.core.regs.rf['fast'].w_ports['d_wr1'] # PC wr - self.fast_r_msr = self.core.regs.rf['fast'].r_ports['msr'] # MSR rd + # FAST regfile read /write ports for PC, MSR, DEC/TB + staterf = self.core.regs.rf['state'] + self.state_r_pc = staterf.r_ports['cia'] # PC rd + self.state_w_pc = staterf.w_ports['d_wr1'] # PC wr + self.state_r_msr = staterf.r_ports['msr'] # MSR rd # DMI interface access - self.int_r = self.core.regs.rf['int'].r_ports['dmi'] # INT read + intrf = self.core.regs.rf['int'] + crrf = self.core.regs.rf['cr'] + xerrf = self.core.regs.rf['xer'] + self.int_r = intrf.r_ports['dmi'] # INT read + self.cr_r = crrf.r_ports['full_cr_dbg'] # CR read + self.xer_r = xerrf.r_ports['full_xer'] # XER read # hack method of keeping an eye on whether branch/trap set the PC - self.fast_nia = self.core.regs.rf['fast'].w_ports['nia'] - self.fast_nia.wen.name = 'fast_nia_wen' + self.state_nia = self.core.regs.rf['state'].w_ports['nia'] + self.state_nia.wen.name = 'state_nia_wen' def elaborate(self, platform): m = Module() @@ -78,10 +129,38 @@ class TestIssuer(Elaboratable): m.submodules.core = core = DomainRenamer("coresync")(self.core) m.submodules.imem = imem = self.imem m.submodules.dbg = dbg = self.dbg + if self.jtag_en: + m.submodules.jtag = jtag = self.jtag + # TODO: UART2GDB mux, here, from external pin + # see https://bugs.libre-soc.org/show_bug.cgi?id=499 + sync += dbg.dmi.connect_to(jtag.dmi) + + cur_state = self.cur_state + + # XICS interrupt handler + if self.xics: + m.submodules.xics_icp = icp = self.xics_icp + m.submodules.xics_ics = ics = self.xics_ics + comb += icp.ics_i.eq(ics.icp_o) # connect ICS to ICP + sync += cur_state.eint.eq(icp.core_irq_o) # connect ICP to core + + # GPIO test peripheral + if self.gpio: + m.submodules.simple_gpio = simple_gpio = 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 + # (but works with verilator sim *sigh*) + #if self.gpio and self.xics: + # comb += self.int_level_i[15].eq(simple_gpio.gpio_o[0]) + + # instruction decoder + pdecode = create_pdecode() + m.submodules.dec2 = pdecode2 = self.pdecode2 # convenience - dmi = dbg.dmi - d_reg = dbg.dbg_gpr + dmi, d_reg, d_cr, d_xer, = dbg.dmi, dbg.d_gpr, dbg.d_cr, dbg.d_xer + intrf = self.core.regs.rf['int'] # clock delay power-on reset cd_por = ClockDomain(reset_less=True) @@ -89,20 +168,20 @@ class TestIssuer(Elaboratable): core_sync = ClockDomain("coresync") m.domains += cd_por, cd_sync, core_sync - delay = Signal(range(4), reset=1) + ti_rst = Signal(reset_less=True) + delay = Signal(range(4), reset=3) with m.If(delay != 0): m.d.por += delay.eq(delay - 1) comb += cd_por.clk.eq(ClockSignal()) - comb += core_sync.clk.eq(ClockSignal()) - # XXX TODO: power-on reset delay (later) - #comb += core.core_reset_i.eq(delay != 0 | dbg.core_rst_o) + + # power-on reset delay + core_rst = ResetSignal("coresync") + comb += ti_rst.eq(delay != 0 | dbg.core_rst_o | ResetSignal()) + comb += core_rst.eq(ti_rst) # busy/halted signals from core comb += self.busy_o.eq(core.busy_o) - comb += core.bigendian_i.eq(self.core_bigendian_i) - - # current state (MSR/PC at the moment - cur_state = CoreState("cur") + comb += pdecode2.dec.bigendian.eq(self.core_bigendian_i) # temporary hack: says "go" immediately for both address gen and ST l0 = core.l0 @@ -112,7 +191,6 @@ class TestIssuer(Elaboratable): m.d.comb += ldst.st.go_i.eq(st_go_edge) # link store-go to rising rel # PC and instruction from I-Memory - current_insn = Signal(32) # current fetched instruction (note sync) pc_changed = Signal() # note write to PC comb += self.pc_o.eq(cur_state.pc) ilatch = Signal(32) @@ -123,34 +201,40 @@ class TestIssuer(Elaboratable): # read the PC pc = Signal(64, reset_less=True) + pc_ok_delay = Signal() + sync += pc_ok_delay.eq(~self.pc_i.ok) with m.If(self.pc_i.ok): # incoming override (start from pc_i) comb += pc.eq(self.pc_i.data) with m.Else(): - # otherwise read FastRegs regfile for PC - comb += self.fast_r_pc.ren.eq(1<