X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fsoc%2Fsimple%2Fissuer.py;h=7b55939d6219ade633de52809997cd542c24f107;hb=8c0a56c349b0d5650026e0ce9031272104cdc39a;hp=f1e197eac06e7f2faa043993fb66b6d4a9f38df2;hpb=3ab66da614173dfcd34f9c7047295cabbe0fa4b3;p=soc.git diff --git a/src/soc/simple/issuer.py b/src/soc/simple/issuer.py index f1e197ea..156fce3c 100644 --- a/src/soc/simple/issuer.py +++ b/src/soc/simple/issuer.py @@ -16,35 +16,43 @@ improved. """ from nmigen import (Elaboratable, Module, Signal, ClockSignal, ResetSignal, - ClockDomain, DomainRenamer, Mux, Const) + ClockDomain, DomainRenamer, Mux, Const, Repl, Cat) 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, SVP64PrefixDecoder -from soc.decoder.decode2execute1 import IssuerDecode2ToOperand -from soc.decoder.decode2execute1 import Data -from soc.experiment.testmem import TestMemory # test only for instructions +from nmutil.singlepipe import ControlBase +from soc.simple.core_data import FetchOutput, FetchInput + +from nmigen.lib.coding import PriorityEncoder + +from openpower.decoder.power_decoder import create_pdecode +from openpower.decoder.power_decoder2 import PowerDecode2, SVP64PrefixDecoder +from openpower.decoder.decode2execute1 import IssuerDecode2ToOperand +from openpower.decoder.decode2execute1 import Data +from openpower.decoder.power_enums import (MicrOp, SVP64PredInt, SVP64PredCR, + SVP64PredMode) +from openpower.state import CoreState +from openpower.consts import (CR, SVP64CROffs, MSR) +from soc.experiment.testmem import TestMemory # test only for instructions 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.bus.SPBlock512W64B8W import SPBlock512W64B8W from soc.clock.select import ClockSelect from soc.clock.dummypll import DummyPLL -from soc.sv.svstate import SVSTATERec - +from openpower.sv.svstate import SVSTATERec +from soc.experiment.icache import ICache from nmutil.util import rising_edge + def get_insn(f_instr_o, pc): if f_instr_o.width == 32: return f_instr_o @@ -52,22 +60,145 @@ def get_insn(f_instr_o, pc): # 64-bit: bit 2 of pc decides which word to select return f_instr_o.word_select(pc[2], 32) +# gets state input or reads from state regfile -class TestIssuerInternal(Elaboratable): - """TestIssuer - reads instructions from TestMemory and issues them - efficiency and speed is not the main goal here: functional correctness is. +def state_get(m, res, core_rst, state_i, name, regfile, regnum): + comb = m.d.comb + sync = m.d.sync + # read the {insert state variable here} + res_ok_delay = Signal(name="%s_ok_delay" % name) + with m.If(~core_rst): + sync += res_ok_delay.eq(~state_i.ok) + with m.If(state_i.ok): + # incoming override (start from pc_i) + comb += res.eq(state_i.data) + with m.Else(): + # otherwise read StateRegs regfile for {insert state here}... + comb += regfile.ren.eq(1 << regnum) + # ... but on a 1-clock delay + with m.If(res_ok_delay): + comb += res.eq(regfile.o_data) + + +def get_predint(m, mask, name): + """decode SVP64 predicate integer mask field to reg number and invert + this is identical to the equivalent function in ISACaller except that + it doesn't read the INT directly, it just decodes "what needs to be done" + i.e. which INT reg, whether it is shifted and whether it is bit-inverted. + + * all1s is set to indicate that no mask is to be applied. + * regread indicates the GPR register number to be read + * invert is set to indicate that the register value is to be inverted + * unary indicates that the contents of the register is to be shifted 1<> srcstep) + sync += self.dstmask.eq(new_dstmask >> dststep) + m.next = "FETCH_PRED_DONE" + + with m.State("FETCH_PRED_DONE"): + comb += pred_mask_o_valid.eq(1) + with m.If(pred_mask_i_ready): + m.next = "FETCH_PRED_IDLE" + + def issue_fsm(self, m, core, nia, + dbg, core_rst, is_svp64_mode, + fetch_pc_o_ready, fetch_pc_i_valid, + fetch_insn_o_valid, fetch_insn_i_ready, + pred_insn_i_valid, pred_insn_o_ready, + pred_mask_o_valid, pred_mask_i_ready, + exec_insn_i_valid, exec_insn_o_ready, + exec_pc_o_valid, exec_pc_i_ready): + """issue FSM + + decode / issue FSM. this interacts with the "fetch" FSM + through fetch_insn_ready/valid (incoming) and fetch_pc_ready/valid + (outgoing). also interacts with the "execute" FSM + through exec_insn_ready/valid (outgoing) and exec_pc_ready/valid + (incoming). + SVP64 RM prefixes have already been set up by the + "fetch" phase, so execute is fairly straightforward. + """ + + comb = m.d.comb + sync = m.d.sync + pdecode2 = self.pdecode2 + cur_state = self.cur_state + new_svstate = self.new_svstate + + # temporaries + dec_opcode_i = pdecode2.dec.raw_opcode_in # raw opcode + + # for updating svstate (things like srcstep etc.) + comb += new_svstate.eq(cur_state.svstate) + + # precalculate srcstep+1 and dststep+1 + cur_srcstep = cur_state.svstate.srcstep + cur_dststep = cur_state.svstate.dststep + next_srcstep = Signal.like(cur_srcstep) + next_dststep = Signal.like(cur_dststep) + comb += next_srcstep.eq(cur_state.svstate.srcstep+1) + comb += next_dststep.eq(cur_state.svstate.dststep+1) + + # note if an exception happened. in a pipelined or OoO design + # this needs to be accompanied by "shadowing" (or stalling) + exc_happened = self.core.o.exc_happened + # also note instruction fetch failed + if hasattr(core, "icache"): + fetch_failed = core.icache.i_out.fetch_failed + flush_needed = True + # set to fault in decoder + # update (highest priority) instruction fault + rising_fetch_failed = rising_edge(m, fetch_failed) + with m.If(rising_fetch_failed): + sync += pdecode2.instr_fault.eq(1) + else: + fetch_failed = Const(0, 1) + flush_needed = False + + with m.FSM(name="issue_fsm"): + + # sync with the "fetch" phase which is reading the instruction + # at this point, there is no instruction running, that + # could inadvertently update the PC. + with m.State("ISSUE_START"): + # reset instruction fault + sync += pdecode2.instr_fault.eq(0) + # 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 + with m.If(fetch_pc_o_ready): # fetch acknowledged us + m.next = "INSN_WAIT" + with m.Else(): + # tell core it's stopped, and acknowledge debug handshake + comb += dbg.core_stopped_i.eq(1) + # while stopped, allow updating SVSTATE + with m.If(self.svstate_i.ok): + comb += new_svstate.eq(self.svstate_i.data) + comb += self.update_svstate.eq(1) + sync += self.sv_changed.eq(1) + + # wait for an instruction to arrive from Fetch + with m.State("INSN_WAIT"): + if self.allow_overlap: + stopping = dbg.stopping_o + else: + stopping = Const(0) + with m.If(stopping): + # stopping: jump back to idle + m.next = "ISSUE_START" + if flush_needed: + # request the icache to stop asserting "failed" + comb += core.icache.flush_in.eq(1) + # stop instruction fault + sync += pdecode2.instr_fault.eq(0) + with m.Else(): + comb += fetch_insn_i_ready.eq(1) + with m.If(fetch_insn_o_valid): + # loop into ISSUE_START if it's a SVP64 instruction + # and VL == 0. this because VL==0 is a for-loop + # from 0 to 0 i.e. always, always a NOP. + cur_vl = cur_state.svstate.vl + with m.If(is_svp64_mode & (cur_vl == 0)): + # update the PC before fetching the next instruction + # since we are in a VL==0 loop, no instruction was + # executed that we could be overwriting + comb += self.state_w_pc.wen.eq(1 << StateRegs.PC) + comb += self.state_w_pc.i_data.eq(nia) + comb += self.insn_done.eq(1) + m.next = "ISSUE_START" + with m.Else(): + if self.svp64_en: + m.next = "PRED_START" # fetching predicate + else: + m.next = "DECODE_SV" # skip predication + + with m.State("PRED_START"): + comb += pred_insn_i_valid.eq(1) # tell fetch_pred to start + with m.If(pred_insn_o_ready): # fetch_pred acknowledged us + m.next = "MASK_WAIT" + + with m.State("MASK_WAIT"): + comb += pred_mask_i_ready.eq(1) # ready to receive the masks + with m.If(pred_mask_o_valid): # predication masks are ready + m.next = "PRED_SKIP" + + # skip zeros in predicate + with m.State("PRED_SKIP"): + with m.If(~is_svp64_mode): + m.next = "DECODE_SV" # nothing to do + with m.Else(): + if self.svp64_en: + pred_src_zero = pdecode2.rm_dec.pred_sz + pred_dst_zero = pdecode2.rm_dec.pred_dz + + # new srcstep, after skipping zeros + skip_srcstep = Signal.like(cur_srcstep) + # value to be added to the current srcstep + src_delta = Signal.like(cur_srcstep) + # add leading zeros to srcstep, if not in zero mode + with m.If(~pred_src_zero): + # priority encoder (count leading zeros) + # append guard bit, in case the mask is all zeros + pri_enc_src = PriorityEncoder(65) + m.submodules.pri_enc_src = pri_enc_src + comb += pri_enc_src.i.eq(Cat(self.srcmask, + Const(1, 1))) + comb += src_delta.eq(pri_enc_src.o) + # apply delta to srcstep + comb += skip_srcstep.eq(cur_srcstep + src_delta) + # shift-out all leading zeros from the mask + # plus the leading "one" bit + # TODO count leading zeros and shift-out the zero + # bits, in the same step, in hardware + sync += self.srcmask.eq(self.srcmask >> (src_delta+1)) + + # same as above, but for dststep + skip_dststep = Signal.like(cur_dststep) + dst_delta = Signal.like(cur_dststep) + with m.If(~pred_dst_zero): + pri_enc_dst = PriorityEncoder(65) + m.submodules.pri_enc_dst = pri_enc_dst + comb += pri_enc_dst.i.eq(Cat(self.dstmask, + Const(1, 1))) + comb += dst_delta.eq(pri_enc_dst.o) + comb += skip_dststep.eq(cur_dststep + dst_delta) + sync += self.dstmask.eq(self.dstmask >> (dst_delta+1)) + + # TODO: initialize mask[VL]=1 to avoid passing past VL + with m.If((skip_srcstep >= cur_vl) | + (skip_dststep >= cur_vl)): + # end of VL loop. Update PC and reset src/dst step + comb += self.state_w_pc.wen.eq(1 << StateRegs.PC) + comb += self.state_w_pc.i_data.eq(nia) + comb += new_svstate.srcstep.eq(0) + comb += new_svstate.dststep.eq(0) + comb += self.update_svstate.eq(1) + # synchronize with the simulator + comb += self.insn_done.eq(1) + # go back to Issue + m.next = "ISSUE_START" + with m.Else(): + # update new src/dst step + comb += new_svstate.srcstep.eq(skip_srcstep) + comb += new_svstate.dststep.eq(skip_dststep) + comb += self.update_svstate.eq(1) + # proceed to Decode + m.next = "DECODE_SV" + + # pass predicate mask bits through to satellite decoders + # TODO: for SIMD this will be *multiple* bits + sync += core.i.sv_pred_sm.eq(self.srcmask[0]) + sync += core.i.sv_pred_dm.eq(self.dstmask[0]) + + # after src/dst step have been updated, we are ready + # to decode the instruction + with m.State("DECODE_SV"): + # decode the instruction + with m.If(~fetch_failed): + sync += pdecode2.instr_fault.eq(0) + sync += core.i.e.eq(pdecode2.e) + sync += core.i.state.eq(cur_state) + sync += core.i.raw_insn_i.eq(dec_opcode_i) + sync += core.i.bigendian_i.eq(self.core_bigendian_i) + if self.svp64_en: + sync += core.i.sv_rm.eq(pdecode2.sv_rm) + # set RA_OR_ZERO detection in satellite decoders + sync += core.i.sv_a_nz.eq(pdecode2.sv_a_nz) + # and svp64 detection + sync += core.i.is_svp64_mode.eq(is_svp64_mode) + # and svp64 bit-rev'd ldst mode + ldst_dec = pdecode2.use_svp64_ldst_dec + sync += core.i.use_svp64_ldst_dec.eq(ldst_dec) + # after decoding, reset any previous exception condition, + # allowing it to be set again during the next execution + sync += pdecode2.ldst_exc.eq(0) + + m.next = "INSN_EXECUTE" # move to "execute" + + # handshake with execution FSM, move to "wait" once acknowledged + with m.State("INSN_EXECUTE"): + comb += exec_insn_i_valid.eq(1) # trigger execute + with m.If(exec_insn_o_ready): # execute acknowledged us + m.next = "EXECUTE_WAIT" + + with m.State("EXECUTE_WAIT"): + # wait on "core stop" release, at instruction end + # need to do this here, in case we are in a VL>1 loop + with m.If(~dbg.core_stop_o & ~core_rst): + comb += exec_pc_i_ready.eq(1) + # see https://bugs.libre-soc.org/show_bug.cgi?id=636 + # the exception info needs to be blatted into + # pdecode.ldst_exc, and the instruction "re-run". + # when ldst_exc.happened is set, the PowerDecoder2 + # reacts very differently: it re-writes the instruction + # with a "trap" (calls PowerDecoder2.trap()) which + # will *overwrite* whatever was requested and jump the + # PC to the exception address, as well as alter MSR. + # nothing else needs to be done other than to note + # the change of PC and MSR (and, later, SVSTATE) + with m.If(exc_happened): + mmu = core.fus.get_exc("mmu0") + ldst = core.fus.get_exc("ldst0") + if mmu is not None: + with m.If(fetch_failed): + # instruction fetch: exception is from MMU + # reset instr_fault (highest priority) + sync += pdecode2.ldst_exc.eq(mmu) + sync += pdecode2.instr_fault.eq(0) + if flush_needed: + # request icache to stop asserting "failed" + comb += core.icache.flush_in.eq(1) + with m.If(~fetch_failed): + # otherwise assume it was a LDST exception + sync += pdecode2.ldst_exc.eq(ldst) + + with m.If(exec_pc_o_valid): + + # was this the last loop iteration? + is_last = Signal() + cur_vl = cur_state.svstate.vl + comb += is_last.eq(next_srcstep == cur_vl) + + with m.If(pdecode2.instr_fault): + # reset instruction fault, try again + sync += pdecode2.instr_fault.eq(0) + m.next = "ISSUE_START" + + # return directly to Decode if Execute generated an + # exception. + with m.Elif(pdecode2.ldst_exc.happened): + m.next = "DECODE_SV" + + # if MSR, PC or SVSTATE were changed by the previous + # instruction, go directly back to Fetch, without + # updating either MSR PC or SVSTATE + with m.Elif(self.msr_changed | self.pc_changed | + self.sv_changed): + m.next = "ISSUE_START" + + # also return to Fetch, when no output was a vector + # (regardless of SRCSTEP and VL), or when the last + # instruction was really the last one of the VL loop + with m.Elif((~pdecode2.loop_continue) | is_last): + # before going back to fetch, update the PC state + # register with the NIA. + # ok here we are not reading the branch unit. + # TODO: this just blithely overwrites whatever + # pipeline updated the PC + comb += self.state_w_pc.wen.eq(1 << StateRegs.PC) + comb += self.state_w_pc.i_data.eq(nia) + # reset SRCSTEP before returning to Fetch + if self.svp64_en: + with m.If(pdecode2.loop_continue): + comb += new_svstate.srcstep.eq(0) + comb += new_svstate.dststep.eq(0) + comb += self.update_svstate.eq(1) + else: + comb += new_svstate.srcstep.eq(0) + comb += new_svstate.dststep.eq(0) + comb += self.update_svstate.eq(1) + m.next = "ISSUE_START" + + # returning to Execute? then, first update SRCSTEP + with m.Else(): + comb += new_svstate.srcstep.eq(next_srcstep) + comb += new_svstate.dststep.eq(next_dststep) + comb += self.update_svstate.eq(1) + # return to mask skip loop + m.next = "PRED_SKIP" + + with m.Else(): + comb += dbg.core_stopped_i.eq(1) + if flush_needed: + # request the icache to stop asserting "failed" + comb += core.icache.flush_in.eq(1) + # stop instruction fault + sync += pdecode2.instr_fault.eq(0) + + # check if svstate needs updating: if so, write it to State Regfile + with m.If(self.update_svstate): + sync += cur_state.svstate.eq(self.new_svstate) # for next clock + + def execute_fsm(self, m, core, + exec_insn_i_valid, exec_insn_o_ready, + exec_pc_o_valid, exec_pc_i_ready): + """execute FSM + + execute FSM. this interacts with the "issue" FSM + through exec_insn_ready/valid (incoming) and exec_pc_ready/valid + (outgoing). SVP64 RM prefixes have already been set up by the + "issue" phase, so execute is fairly straightforward. + """ + + comb = m.d.comb + sync = m.d.sync + pdecode2 = self.pdecode2 + + # temporaries + core_busy_o = core.n.o_data.busy_o # core is busy + core_ivalid_i = core.p.i_valid # instruction is valid + + if hasattr(core, "icache"): + fetch_failed = core.icache.i_out.fetch_failed + else: + fetch_failed = Const(0, 1) + + with m.FSM(name="exec_fsm"): + + # waiting for instruction bus (stays there until not busy) + with m.State("INSN_START"): + comb += exec_insn_o_ready.eq(1) + with m.If(exec_insn_i_valid): + comb += core_ivalid_i.eq(1) # instruction is valid/issued + sync += self.sv_changed.eq(0) + sync += self.pc_changed.eq(0) + sync += self.msr_changed.eq(0) + with m.If(core.p.o_ready): # only move if accepted + m.next = "INSN_ACTIVE" # move to "wait completion" + + # instruction started: must wait till it finishes + with m.State("INSN_ACTIVE"): + # note changes to MSR, PC and SVSTATE + # XXX oops, really must monitor *all* State Regfile write + # ports looking for changes! + 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(~core_busy_o): # instruction done! + comb += exec_pc_o_valid.eq(1) + with m.If(exec_pc_i_ready): + # when finished, indicate "done". + # however, if there was an exception, the instruction + # is *not* yet done. this is an implementation + # detail: we choose to implement exceptions by + # taking the exception information from the LDST + # unit, putting that *back* into the PowerDecoder2, + # and *re-running the entire instruction*. + # if we erroneously indicate "done" here, it is as if + # there were *TWO* instructions: + # 1) the failed LDST 2) a TRAP. + with m.If(~pdecode2.ldst_exc.happened & + ~pdecode2.instr_fault): + comb += self.insn_done.eq(1) + m.next = "INSN_START" # back to fetch + + def elaborate(self, platform): + m = super().elaborate(platform) + # convenience + comb, sync = m.d.comb, m.d.sync + cur_state = self.cur_state + pdecode2 = self.pdecode2 + dbg = self.dbg + core = self.core + + # set up peripherals and core + core_rst = self.core_rst + + # indicate to outside world if any FU is still executing + comb += self.any_busy.eq(core.n.o_data.any_busy_o) # any FU executing + + # address of the next instruction, in the absence of a branch + # depends on the instruction size + nia = Signal(64) + + # connect up debug signals + with m.If(core.o.core_terminate_o): + comb += dbg.terminate_i.eq(1) + + # pass the prefix mode from Fetch to Issue, so the latter can loop + # on VL==0 + is_svp64_mode = Signal() + + # there are *THREE^WFOUR-if-SVP64-enabled* FSMs, fetch (32/64-bit) + # issue, decode/execute, now joined by "Predicate fetch/calculate". + # these are the handshake signals between each + + # fetch FSM can run as soon as the PC is valid + fetch_pc_i_valid = Signal() # Execute tells Fetch "start next read" + fetch_pc_o_ready = Signal() # Fetch Tells SVSTATE "proceed" + + # fetch FSM hands over the instruction to be decoded / issued + fetch_insn_o_valid = Signal() + fetch_insn_i_ready = Signal() + + # predicate fetch FSM decodes and fetches the predicate + pred_insn_i_valid = Signal() + pred_insn_o_ready = Signal() + + # predicate fetch FSM delivers the masks + pred_mask_o_valid = Signal() + pred_mask_i_ready = Signal() + + # issue FSM delivers the instruction to the be executed + exec_insn_i_valid = Signal() + exec_insn_o_ready = Signal() + + # execute FSM, hands over the PC/SVSTATE back to the issue FSM + exec_pc_o_valid = Signal() + exec_pc_i_ready = Signal() + + # the FSMs here are perhaps unusual in that they detect conditions + # then "hold" 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. + + # Fetch, then predicate fetch, then Issue, then Execute. + # Issue is where the VL for-loop # lives. the ready/valid + # signalling is used to communicate between the four. + + # set up Fetch FSM + fetch = FetchFSM(self.allow_overlap, self.svp64_en, + self.imem, core_rst, pdecode2, cur_state, + dbg, core, + dbg.state.svstate, # combinatorially same + nia, is_svp64_mode) + m.submodules.fetch = fetch + # connect up in/out data to existing Signals + comb += fetch.p.i_data.pc.eq(dbg.state.pc) # combinatorially same + comb += fetch.p.i_data.msr.eq(dbg.state.msr) # combinatorially same + # and the ready/valid signalling + comb += fetch_pc_o_ready.eq(fetch.p.o_ready) + comb += fetch.p.i_valid.eq(fetch_pc_i_valid) + comb += fetch_insn_o_valid.eq(fetch.n.o_valid) + comb += fetch.n.i_ready.eq(fetch_insn_i_ready) + + self.issue_fsm(m, core, nia, + dbg, core_rst, is_svp64_mode, + fetch_pc_o_ready, fetch_pc_i_valid, + fetch_insn_o_valid, fetch_insn_i_ready, + pred_insn_i_valid, pred_insn_o_ready, + pred_mask_o_valid, pred_mask_i_ready, + exec_insn_i_valid, exec_insn_o_ready, + exec_pc_o_valid, exec_pc_i_ready) + + if self.svp64_en: + self.fetch_predicate_fsm(m, + pred_insn_i_valid, pred_insn_o_ready, + pred_mask_o_valid, pred_mask_i_ready) + + self.execute_fsm(m, core, + exec_insn_i_valid, exec_insn_o_ready, + exec_pc_o_valid, exec_pc_i_ready) + + return m + + class TestIssuer(Elaboratable): def __init__(self, pspec): self.ti = TestIssuerInternal(pspec) + # XXX TODO: make this a command-line selectable option from pspec + #from soc.simple.inorder import TestIssuerInternalInOrder + #self.ti = TestIssuerInternalInOrder(pspec) + self.pll = DummyPLL(instance=True) - self.pll = DummyPLL() + self.dbg_rst_i = Signal(reset_less=True) # PLL direct clock or not self.pll_en = hasattr(pspec, "use_pll") and pspec.use_pll if self.pll_en: - self.pll_18_o = Signal(reset_less=True) + self.pll_test_o = Signal(reset_less=True) + self.pll_vco_o = Signal(reset_less=True) + self.clk_sel_i = Signal(2, reset_less=True) + self.ref_clk = ClockSignal() # can't rename it but that's ok + self.pllclk_clk = ClockSignal("pllclk") def elaborate(self, platform): m = Module() comb = m.d.comb - # TestIssuer runs at direct clock + # TestIssuer nominally runs at main clock, actually it is + # all combinatorial internally except for coresync'd components m.submodules.ti = ti = self.ti - cd_int = ClockDomain("coresync") if self.pll_en: # ClockSelect runs at PLL output internal clock rate - m.submodules.pll = pll = self.pll + m.submodules.wrappll = pll = self.pll # add clock domains from PLL cd_pll = ClockDomain("pllclk") @@ -730,14 +1533,17 @@ class TestIssuer(Elaboratable): # PLL clock established. has the side-effect of running clklsel # at the PLL's speed (see DomainRenamer("pllclk") above) - pllclk = ClockSignal("pllclk") + pllclk = self.pllclk_clk comb += pllclk.eq(pll.clk_pll_o) # wire up external 24mhz to PLL - comb += pll.clk_24_i.eq(ClockSignal()) + #comb += pll.clk_24_i.eq(self.ref_clk) + # output 18 mhz PLL test signal, and analog oscillator out + comb += self.pll_test_o.eq(pll.pll_test_o) + comb += self.pll_vco_o.eq(pll.pll_vco_o) - # output 18 mhz PLL test signal - comb += self.pll_18_o.eq(pll.pll_18_o) + # input to pll clock selection + comb += pll.clk_sel_i.eq(self.clk_sel_i) # now wire up ResetSignals. don't mind them being in this domain pll_rst = ResetSignal("pllclk") @@ -745,26 +1551,43 @@ class TestIssuer(Elaboratable): # internal clock is set to selector clock-out. has the side-effect of # running TestIssuer at this speed (see DomainRenamer("intclk") above) - intclk = ClockSignal("coresync") + # debug clock runs at coresync internal clock + if self.ti.dbg_domain != 'sync': + cd_dbgsync = ClockDomain("dbgsync") + intclk = ClockSignal(self.ti.core_domain) + dbgclk = ClockSignal(self.ti.dbg_domain) + # XXX BYPASS PLL XXX + # XXX BYPASS PLL XXX + # XXX BYPASS PLL XXX if self.pll_en: - comb += intclk.eq(pll.clk_pll_o) + comb += intclk.eq(self.ref_clk) + assert self.ti.core_domain != 'sync', \ + "cannot set core_domain to sync and use pll at the same time" else: - comb += intclk.eq(ClockSignal()) + if self.ti.core_domain != 'sync': + comb += intclk.eq(ClockSignal()) + if self.ti.dbg_domain != 'sync': + dbgclk = ClockSignal(self.ti.dbg_domain) + comb += dbgclk.eq(intclk) + comb += self.ti.dbg_rst_i.eq(self.dbg_rst_i) return m def ports(self): return list(self.ti.ports()) + list(self.pll.ports()) + \ - [ClockSignal(), ResetSignal()] + [ClockSignal(), ResetSignal()] def external_ports(self): ports = self.ti.external_ports() ports.append(ClockSignal()) ports.append(ResetSignal()) if self.pll_en: - ports.append(self.pll.clk_sel_i) - ports.append(self.pll_18_o) - ports.append(self.pll.pll_lck_o) + ports.append(self.clk_sel_i) + ports.append(self.pll.clk_24_i) + ports.append(self.pll_test_o) + ports.append(self.pll_vco_o) + ports.append(self.pllclk_clk) + ports.append(self.ref_clk) return ports @@ -774,7 +1597,7 @@ if __name__ == '__main__': 'div': 1, 'mul': 1, 'shiftrot': 1 - } + } pspec = TestMemPspec(ldst_ifacetype='bare_wb', imem_ifacetype='bare_wb', addr_wid=48,