self.bigendian_i = self.pdecode2.dec.bigendian
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=1) # indicates stopped
+
def elaborate(self, platform):
m = Module()
regs = self.regs
fus = self.fus.fus
- fu_bitdict = self.connect_instruction(m)
+ # core start/stopped state
+ core_stopped = Signal(reset=1) # begins in stopped state
+
+ # start/stop signalling
+ with m.If(self.core_start_i):
+ m.d.sync += core_stopped.eq(1)
+ with m.If(self.core_stop_i):
+ m.d.sync += core_stopped.eq(0)
+ 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)
self.connect_rdports(m, fu_bitdict)
self.connect_wrports(m, fu_bitdict)
return m
- def connect_instruction(self, m):
+ def connect_instruction(self, m, core_stopped):
comb, sync = m.d.comb, m.d.sync
fus = self.fus.fus
dec2 = self.pdecode2
for i, funame in enumerate(fus.keys()):
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)
+
# connect up instructions. only one is enabled at any given time
for funame, fu in fus.items():
fnunit = fu.fnunit.value
enable = Signal(name="en_%s" % funame, reset_less=True)
- comb += enable.eq(self.ivalid_i &
- (dec2.e.do.fn_unit & fnunit).bool())
+ comb += enable.eq((dec2.e.do.fn_unit & fnunit).bool() & can_run)
+
+ # run this FunctionUnit if enabled, except if the instruction
+ # is "attn" in which case we HALT.
with m.If(enable):
- comb += fu.oper_i.eq_from_execute1(dec2.e)
- comb += fu.issue_i.eq(self.issue_i)
- comb += self.busy_o.eq(fu.busy_o)
- rdmask = dec2.rdflags(fu)
- comb += fu.rdmaskn.eq(~rdmask)
- comb += fu_bitdict[funame].eq(enable)
+ with m.If(dec2.e.op.internal_op == InternalOp.OP_ATTN):
+ # check for ATTN: halt if true
+ m.d.sync += core_stopped.eq(1)
+ with m.Else():
+ # route operand, issue, busy, read flags and mask to FU
+ comb += fu.oper_i.eq_from_execute1(dec2.e)
+ comb += fu.issue_i.eq(self.issue_i)
+ comb += self.busy_o.eq(fu.busy_o)
+ rdmask = dec2.rdflags(fu)
+ comb += fu.rdmaskn.eq(~rdmask)
+ comb += fu_bitdict[funame].eq(enable)
return fu_bitdict
# PC and instruction from I-Memory
current_insn = Signal(32) # current fetched instruction (note sync)
- current_pc = Signal(64) # current PC (note it is reset/sync)
+ cur_pc = Signal(64) # current PC (note it is reset/sync)
pc_changed = Signal() # note write to PC
- comb += self.pc_o.eq(current_pc)
+ comb += self.pc_o.eq(cur_pc)
ilatch = Signal(32)
# next instruction (+4 on current)
nia = Signal(64, reset_less=True)
- comb += nia.eq(current_pc + 4)
+ comb += nia.eq(cur_pc + 4)
# temporaries
core_busy_o = core.busy_o # core is busy
core_be_i = core.bigendian_i # bigendian mode
core_opcode_i = core.raw_opcode_i # raw opcode
- # actually use a nmigen FSM for the first time (w00t)
- 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)
+ # only run if not in halted state
+ with m.If(~core.core_terminated_o):
+
+ # actually use a nmigen FSM for the first time (w00t)
+ 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_rd1.ren.eq(1<<FastRegs.PC)
+ comb += pc.eq(self.fast_rd1.data_o)
+ # 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_pc.eq(pc)
+ m.next = "INSN_READ" # move to "wait for bus" phase
+
+ # waiting for instruction bus (stays there until not busy)
+ with m.State("INSN_READ"):
+ 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():
- # otherwise read FastRegs regfile for PC
- comb += self.fast_rd1.ren.eq(1<<FastRegs.PC)
- comb += pc.eq(self.fast_rd1.data_o)
- # 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 += current_pc.eq(pc)
- m.next = "INSN_READ" # move to "wait for bus" phase
-
- # waiting for instruction bus (stays there until not busy)
- with m.State("INSN_READ"):
- 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
- insn = self.imem.f_instr_o.word_select(current_pc[2], 32)
- comb += current_insn.eq(insn)
+ # not busy: instruction fetched
+ insn = self.imem.f_instr_o.word_select(cur_pc[2], 32)
+ comb += current_insn.eq(insn)
+ comb += core_ivalid_i.eq(1) # say instruction is valid
+ comb += core_issue_i.eq(1) # and issued
+ comb += core_be_i.eq(0) # little-endian mode
+ comb += core_opcode_i.eq(current_insn) # actual opcode
+ sync += ilatch.eq(current_insn)
+ m.next = "INSN_ACTIVE" # move to "wait completion"
+
+ # instruction started: must wait till it finishes
+ with m.State("INSN_ACTIVE"):
comb += core_ivalid_i.eq(1) # say instruction is valid
- comb += core_issue_i.eq(1) # and issued (ivalid redundant)
- comb += core_be_i.eq(0) # little-endian mode
- comb += core_opcode_i.eq(current_insn) # actual opcode
- sync += ilatch.eq(current_insn)
- m.next = "INSN_ACTIVE" # move to "wait for completion" phase
-
- # instruction started: must wait till it finishes
- with m.State("INSN_ACTIVE"):
- comb += core_ivalid_i.eq(1) # say instruction is valid
- comb += core_opcode_i.eq(ilatch) # actual opcode
- #sync += core_issue_i.eq(0) # issue raises for only one cycle
- with m.If(self.fast_nia.wen):
- sync += pc_changed.eq(1)
- with m.If(~core_busy_o): # instruction done!
- #sync += core_ivalid_i.eq(0) # say instruction is invalid
- #sync += core_opcode_i.eq(0) # clear out (no good reason)
- # ok here we are not reading the branch unit. TODO
- # this just blithely overwrites whatever pipeline updated
- # the PC
- with m.If(~pc_changed):
- comb += self.fast_wr1.wen.eq(1<<FastRegs.PC)
- comb += self.fast_wr1.data_i.eq(nia)
- m.next = "IDLE" # back to idle
+ comb += core_opcode_i.eq(ilatch) # actual opcode
+ with m.If(self.fast_nia.wen):
+ sync += pc_changed.eq(1)
+ with m.If(~core_busy_o): # instruction done!
+ # ok here we are not reading the branch unit. TODO
+ # this just blithely overwrites whatever pipeline
+ # updated the PC
+ with m.If(~pc_changed):
+ comb += self.fast_wr1.wen.eq(1<<FastRegs.PC)
+ comb += self.fast_wr1.data_i.eq(nia)
+ m.next = "IDLE" # back to idle
return m
pdecode2 = core.pdecode2
l0 = core.l0
+ # get core going
+ yield core.core_start_i.eq(1)
+ yield
+ yield core.core_start_i.eq(0)
+
comb += issuer.pc_i.data.eq(pc_i)
comb += issuer.go_insn_i.eq(go_insn_i)
unittest.main(exit=False)
suite = unittest.TestSuite()
suite.addTest(TestRunner(GeneralTestCases.test_data))
- suite.addTest(TestRunner(LDSTTestCase.test_data))
- suite.addTest(TestRunner(CRTestCase.test_data))
- suite.addTest(TestRunner(ShiftRotTestCase.test_data))
- suite.addTest(TestRunner(LogicalTestCase.test_data))
- suite.addTest(TestRunner(ALUTestCase.test_data))
- suite.addTest(TestRunner(BranchTestCase.test_data))
- suite.addTest(TestRunner(SPRTestCase.test_data))
+ #suite.addTest(TestRunner(LDSTTestCase.test_data))
+ #suite.addTest(TestRunner(CRTestCase.test_data))
+ #suite.addTest(TestRunner(ShiftRotTestCase.test_data))
+ #suite.addTest(TestRunner(LogicalTestCase.test_data))
+ #suite.addTest(TestRunner(ALUTestCase.test_data))
+ #suite.addTest(TestRunner(BranchTestCase.test_data))
+ #suite.addTest(TestRunner(SPRTestCase.test_data))
runner = unittest.TextTestRunner()
runner.run(suite)