From 0c5ef8574092e925e3dacb667cbca81ee558c2c4 Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Mon, 3 Aug 2020 18:02:52 +0100 Subject: [PATCH] change over to DMI debug start/stop interface --- src/soc/simple/core.py | 29 ++-- src/soc/simple/issuer.py | 206 +++++++++++++++-------------- src/soc/simple/test/test_core.py | 14 +- src/soc/simple/test/test_issuer.py | 58 ++++++-- src/soc/simulator/test_sim.py | 4 +- 5 files changed, 171 insertions(+), 140 deletions(-) diff --git a/src/soc/simple/core.py b/src/soc/simple/core.py index 075ca557..3b195d24 100644 --- a/src/soc/simple/core.py +++ b/src/soc/simple/core.py @@ -19,7 +19,7 @@ and consequently it is safer to wait for the Function Unit to complete before allowing a new instruction to proceed. """ -from nmigen import Elaboratable, Module, Signal +from nmigen import Elaboratable, Module, Signal, ResetSignal from nmigen.cli import rtlil from nmutil.picker import PriorityPicker @@ -84,9 +84,9 @@ class NonProductionCore(Elaboratable): self.raw_opcode_i = self.pdecode2.dec.raw_opcode_in # start/stop and terminated signalling - self.core_start_i = Signal(reset_less=True) - self.core_stop_i = Signal(reset_less=True) - self.core_terminated_o = Signal(reset=0) # indicates stopped + self.core_stopped_i = Signal(reset_less=True) + self.core_reset_i = Signal() + self.core_terminate_o = Signal(reset=0) # indicates stopped def elaborate(self, platform): m = Module() @@ -98,24 +98,17 @@ class NonProductionCore(Elaboratable): regs = self.regs fus = self.fus.fus - # core start/stopped state - core_stopped = Signal(reset=0) # begins in running state - - # start/stop signalling - with m.If(self.core_start_i): - m.d.sync += core_stopped.eq(0) - with m.If(self.core_stop_i): - m.d.sync += core_stopped.eq(1) - m.d.comb += self.core_terminated_o.eq(core_stopped) - # connect up Function Units, then read/write ports - fu_bitdict = self.connect_instruction(m, core_stopped) + fu_bitdict = self.connect_instruction(m) self.connect_rdports(m, fu_bitdict) self.connect_wrports(m, fu_bitdict) + # connect up reset + m.d.comb += ResetSignal().eq(self.core_reset_i) + return m - def connect_instruction(self, m, core_stopped): + def connect_instruction(self, m): """connect_instruction uses decoded (from PowerOp) function unit information from CSV files @@ -138,7 +131,7 @@ class NonProductionCore(Elaboratable): fu_bitdict[funame] = fu_enable[i] # only run when allowed and when instruction is valid can_run = Signal(reset_less=True) - comb += can_run.eq(self.ivalid_i & ~core_stopped) + comb += can_run.eq(self.ivalid_i & ~self.core_stopped_i) # enable the required Function Unit based on the opcode decode # note: this *only* works correctly for simple core when one and @@ -159,7 +152,7 @@ class NonProductionCore(Elaboratable): with m.Switch(dec2.e.do.insn_type): # check for ATTN: halt if true with m.Case(MicrOp.OP_ATTN): - m.d.sync += core_stopped.eq(1) + m.d.sync += self.core_terminate_o.eq(1) with m.Case(MicrOp.OP_NOP): sync += counter.eq(2) diff --git a/src/soc/simple/issuer.py b/src/soc/simple/issuer.py index a273fd16..e625b8dd 100644 --- a/src/soc/simple/issuer.py +++ b/src/soc/simple/issuer.py @@ -15,7 +15,8 @@ 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 @@ -27,6 +28,7 @@ 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 class TestIssuer(Elaboratable): @@ -44,15 +46,15 @@ class TestIssuer(Elaboratable): self.iline = Signal(64) # one instruction line self.iprev_adr = Signal(64) # previous address: if different, do read + # DMI interface + self.dbg = CoreDebug() + self.dmi = self.dbg.dmi + # instruction go/monitor - self.go_insn_i = Signal() self.pc_o = Signal(64, reset_less=True) self.pc_i = Data(64, "pc_i") # set "ok" to indicate "please change me" - self.core_start_i = Signal() - self.core_stop_i = Signal() self.core_bigendian_i = Signal() self.busy_o = Signal(reset_less=True) - self.halted_o = Signal(reset_less=True) self.memerr_o = Signal(reset_less=True) # FAST regfile read /write ports for PC and MSR @@ -68,14 +70,27 @@ class TestIssuer(Elaboratable): 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 + + # 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 + + delay = Signal(range(4), reset=1) + 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) + comb += core.core_reset_i.eq(dbg.core_rst_o) # busy/halted signals from core comb += self.busy_o.eq(core.busy_o) - comb += self.halted_o.eq(core.core_terminated_o) - comb += core.core_start_i.eq(self.core_start_i) - comb += core.core_stop_i.eq(self.core_stop_i) comb += core.bigendian_i.eq(self.core_bigendian_i) # temporary hack: says "go" immediately for both address gen and ST @@ -99,6 +114,12 @@ class TestIssuer(Elaboratable): nia = Signal(64, reset_less=True) comb += nia.eq(cur_pc + 4) + # connect up debug signals + comb += core.core_stopped_i.eq(dbg.core_stop_o) + # TODO comb += core.reset_i.eq(dbg.core_rst_o) + # TODO comb += core.icache_rst_i.eq(dbg.icache_rst_o) + comb += dbg.terminate_i.eq(core.core_terminate_o) + # temporaries core_busy_o = core.busy_o # core is busy core_ivalid_i = core.ivalid_i # instruction is valid @@ -110,121 +131,106 @@ class TestIssuer(Elaboratable): insn_msr = core.pdecode2.msr insn_cia = core.pdecode2.cia - # only run if not in halted state - with m.If(~core.core_terminated_o): - - # actually use a nmigen FSM for the first time (w00t) - # this FSM is perhaps unusual in that it detects conditions - # then "holds" information, combinatorially, for the core - # (as opposed to using sync - which would be on a clock's delay) - # this includes the actual opcode, valid flags and so on. - with m.FSM() as fsm: - - # waiting (zzz) - with m.State("IDLE"): - sync += pc_changed.eq(0) - with m.If(self.go_insn_i): - # instruction allowed to go: start by reading the PC - pc = Signal(64, reset_less=True) - 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<