X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fsoc%2Fsimple%2Fissuer.py;h=c231702f49f10fbac273da58e8da5f6e97ce50d2;hb=c38e0b65982eb3d8c671ec953da6dfb8f138b8db;hp=2d7ae5e0f582e2a2f53856d8fa30136e24809f41;hpb=303d692d202f74ee5caa963dfc34d9bca8af6295;p=soc.git diff --git a/src/soc/simple/issuer.py b/src/soc/simple/issuer.py index 2d7ae5e0..c231702f 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 @@ -15,166 +15,515 @@ way, and to at provide something that can be further incrementally improved. """ -from nmigen import Elaboratable, Module, Signal +from nmigen import (Elaboratable, Module, Signal, ClockSignal, ResetSignal, + ClockDomain, DomainRenamer) 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 InternalOp +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 +from soc.clock.dummypll import DummyPLL -class TestIssuer(Elaboratable): +from nmutil.util import rising_edge + + +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 self.iline = Signal(64) # one instruction line self.iprev_adr = Signal(64) # previous address: if different, do read + # DMI interface + self.dbg = CoreDebug() + # instruction go/monitor - self.go_insn_i = Signal(reset_less=True) self.pc_o = Signal(64, reset_less=True) - self.pc_i = Data(64, "pc") # set "ok" to indicate "please change me" - self.busy_o = core.busy_o + self.pc_i = Data(64, "pc_i") # set "ok" to indicate "please change me" + self.core_bigendian_i = Signal() + self.busy_o = Signal(reset_less=True) self.memerr_o = Signal(reset_less=True) - # FAST regfile read /write ports - self.fast_rd1 = self.core.regs.rf['fast'].r_ports['d_rd1'] - self.fast_wr1 = self.core.regs.rf['fast'].w_ports['d_wr1'] + # 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 + 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() comb, sync = m.d.comb, m.d.sync - m.submodules.core = core = self.core + 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, 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) + cd_sync = ClockDomain() + core_sync = ClockDomain("coresync") + m.domains += cd_por, cd_sync, core_sync + + 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()) + + # 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 += pdecode2.dec.bigendian.eq(self.core_bigendian_i) # temporary hack: says "go" immediately for both address gen and ST l0 = core.l0 ldst = core.fus.fus['ldst0'] - m.d.comb += ldst.ad.go.eq(ldst.ad.rel) # link addr-go direct to rel - m.d.comb += ldst.st.go.eq(ldst.st.rel) # link store-go direct to rel + st_go_edge = rising_edge(m, ldst.st.rel_o) + m.d.comb += ldst.ad.go_i.eq(ldst.ad.rel_o) # link addr-go direct to rel + 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) - cur_pc = Signal(64) # current PC (note it is reset/sync) pc_changed = Signal() # note write to PC - comb += self.pc_o.eq(cur_pc) + comb += self.pc_o.eq(cur_state.pc) ilatch = Signal(32) # next instruction (+4 on current) nia = Signal(64, reset_less=True) - comb += nia.eq(cur_pc + 4) + comb += nia.eq(cur_state.pc + 4) + + # 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 StateRegs regfile for PC... + comb += self.state_r_pc.ren.eq(1<