"""
from nmigen import (Elaboratable, Module, Signal, ClockSignal, ResetSignal,
- ClockDomain, DomainRenamer)
+ ClockDomain, DomainRenamer, Mux)
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.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
self.cur_state = CoreState("cur") # current state (MSR/PC/EINT)
self.pdecode2 = PowerDecode2(pdecode, state=self.cur_state,
opkls=IssuerDecode2ToOperand)
+ self.svp64 = SVP64PrefixDecoder() # for decoding SVP64 prefix
# Test Instruction memory
self.imem = ConfigFetchUnit(pspec).fu
# instruction decoder
pdecode = create_pdecode()
m.submodules.dec2 = pdecode2 = self.pdecode2
+ m.submodules.svp64 = svp64 = self.svp64
# convenience
dmi, d_reg, d_cr, d_xer, = dbg.dmi, dbg.d_gpr, dbg.d_cr, dbg.d_xer
comb += self.pc_o.eq(cur_state.pc)
ilatch = Signal(32)
- # next instruction (+4 on current)
+ # address of the next instruction, in the absence of a branch
+ # depends on the instruction size
nia = Signal(64, reset_less=True)
- comb += nia.eq(cur_state.pc + 4)
# read the PC
pc = Signal(64, reset_less=True)
insn_type = core.e.do.insn_type
+ # handshake signals between fetch and decode/execute
+ # fetch FSM can run as soon as the PC is valid
+ fetch_pc_valid_i = Signal()
+ fetch_pc_ready_o = Signal()
+ # when done, deliver the instruction to the next FSM
+ fetch_insn_o = Signal(32, reset_less=True)
+ fetch_insn_valid_o = Signal()
+ fetch_insn_ready_i = Signal()
+
# 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:
+ with m.FSM(name='fetch_fsm'):
# waiting (zzz)
with m.State("IDLE"):
- sync += pc_changed.eq(0)
- sync += core.e.eq(0)
- sync += core.raw_insn_i.eq(0)
- sync += core.bigendian_i.eq(0)
with m.If(~dbg.core_stop_o & ~core_rst):
- # instruction allowed to go: start by reading the PC
- # capture the PC and also drop it into Insn Memory
- # we have joined a pair of combinatorial memory
- # lookups together. this is Generally Bad.
- comb += self.imem.a_pc_i.eq(pc)
- comb += self.imem.a_valid_i.eq(1)
- comb += self.imem.f_valid_i.eq(1)
- sync += cur_state.pc.eq(pc)
-
- # initiate read of MSR. arrives one clock later
- comb += self.state_r_msr.ren.eq(1<<StateRegs.MSR)
- sync += msr_read.eq(0)
-
- m.next = "INSN_READ" # move to "wait for bus" phase
+ comb += fetch_pc_ready_o.eq(1)
+ with m.If(fetch_pc_valid_i):
+ # instruction allowed to go: start by reading the PC
+ # capture the PC and also drop it into Insn Memory
+ # we have joined a pair of combinatorial memory
+ # lookups together. this is Generally Bad.
+ comb += self.imem.a_pc_i.eq(pc)
+ comb += self.imem.a_valid_i.eq(1)
+ comb += self.imem.f_valid_i.eq(1)
+ sync += cur_state.pc.eq(pc)
+
+ # initiate read of MSR. arrives one clock later
+ comb += self.state_r_msr.ren.eq(1 << StateRegs.MSR)
+ sync += msr_read.eq(0)
+
+ m.next = "INSN_READ" # move to "wait for bus" phase
with m.Else():
comb += core.core_stopped_i.eq(1)
comb += dbg.core_stopped_i.eq(1)
insn = f_instr_o
else:
insn = f_instr_o.word_select(cur_state.pc[2], 32)
- comb += dec_opcode_i.eq(insn) # actual opcode
+ # decode the SVP64 prefix, if any
+ comb += svp64.raw_opcode_in.eq(insn)
+ comb += svp64.bigendian.eq(self.core_bigendian_i)
+ # pass the decoded prefix (if any) to PowerDecoder2
+ sync += pdecode2.sv_rm.eq(svp64.svp64_rm)
+ # calculate the address of the following instruction
+ insn_size = Mux(svp64.is_svp64_mode, 8, 4)
+ sync += nia.eq(cur_state.pc + insn_size)
+ with m.If(~svp64.is_svp64_mode):
+ # with no prefix, store the instruction
+ # and hand it directly to the next FSM
+ sync += fetch_insn_o.eq(insn)
+ m.next = "INSN_READY"
+ with m.Else():
+ # fetch the rest of the instruction from memory
+ comb += self.imem.a_pc_i.eq(cur_state.pc + 4)
+ comb += self.imem.a_valid_i.eq(1)
+ comb += self.imem.f_valid_i.eq(1)
+ m.next = "INSN_READ2"
+
+ with m.State("INSN_READ2"):
+ with m.If(self.imem.f_busy_o): # zzz...
+ # busy: stay in wait-read
+ comb += self.imem.a_valid_i.eq(1)
+ comb += self.imem.f_valid_i.eq(1)
+ with m.Else():
+ # not busy: instruction fetched
+ f_instr_o = self.imem.f_instr_o
+ if f_instr_o.width == 32:
+ insn = f_instr_o
+ else:
+ insn = f_instr_o.word_select((cur_state.pc+4)[2], 32)
+ sync += fetch_insn_o.eq(insn)
+ m.next = "INSN_READY"
+
+ with m.State("INSN_READY"):
+ # hand over the instruction, to be decoded
+ comb += fetch_insn_valid_o.eq(1)
+ with m.If(fetch_insn_ready_i):
+ m.next = "IDLE"
+
+ # decode / issue / execute FSM
+ with m.FSM():
+
+ # go fetch the instruction at the current PC
+ # at this point, there is no instruction running, that
+ # could inadvertently update the PC.
+ with m.State("INSN_FETCH"):
+ comb += fetch_pc_valid_i.eq(1)
+ with m.If(fetch_pc_ready_o):
+ m.next = "INSN_WAIT"
+
+ # decode the instruction when it arrives
+ with m.State("INSN_WAIT"):
+ comb += fetch_insn_ready_i.eq(1)
+ with m.If(fetch_insn_valid_o):
+ # decode the instruction
+ # TODO, before issuing new instruction first
+ # check if it's SVP64. (svp64.is_svp64_mode set)
+ # if yes, record the svp64_rm, put that into
+ # pdecode2.sv_rm, then read another 32 bits (INSN_FETCH2?)
+ comb += dec_opcode_i.eq(fetch_insn_o) # actual opcode
sync += core.e.eq(pdecode2.e)
sync += core.state.eq(cur_state)
sync += core.raw_insn_i.eq(dec_opcode_i)
with m.State("INSN_START"):
comb += core_ivalid_i.eq(1) # instruction is valid
comb += core_issue_i.eq(1) # and issued
+ sync += pc_changed.eq(0)
m.next = "INSN_ACTIVE" # move to "wait completion"
sync += core.e.eq(0)
sync += core.raw_insn_i.eq(0)
sync += core.bigendian_i.eq(0)
- m.next = "IDLE" # back to idle
+ m.next = "INSN_FETCH" # back to fetch
# this bit doesn't have to be in the FSM: connect up to read
# regfiles on demand from DMI
# 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)
def elaborate(self, platform):
m = Module()
# wire up external 24mhz to PLL
comb += pll.clk_24_i.eq(ClockSignal())
+ # output 18 mhz PLL test signal
+ comb += self.pll_18_o.eq(pll.pll_18_o)
+
# now wire up ResetSignals. don't mind them being in this domain
pll_rst = ResetSignal("pllclk")
comb += pll_rst.eq(ResetSignal())
ports.append(ResetSignal())
if self.pll_en:
ports.append(self.pll.clk_sel_i)
- ports.append(self.pll.pll_18_o)
- ports.append(self.pll.clk_lck_o)
+ ports.append(self.pll_18_o)
+ ports.append(self.pll.pll_lck_o)
return ports