self.state_nia = self.core.regs.rf['state'].w_ports['nia']
self.state_nia.wen.name = 'state_nia_wen'
+ def fetch_fsm(self, m, core, dbg, pc, nia,
+ core_rst, cur_state,
+ fetch_pc_ready_o, fetch_pc_valid_i,
+ fetch_insn_valid_o, fetch_insn_ready_i,
+ msr_read, sv_read,
+ fetch_insn_o):
+ """fetch FSM
+ this FSM performs fetch of raw instruction data, partial-decodes
+ it 32-bit at a time to detect SVP64 prefixes, and will optionally
+ read a 2nd 32-bit quantity if that occurs.
+ """
+ comb = m.d.comb
+ sync = m.d.sync
+ pdecode2 = self.pdecode2
+ svp64 = self.svp64
+
+ with m.FSM(name='fetch_fsm'):
+
+ # waiting (zzz)
+ with m.State("IDLE"):
+ with m.If(~dbg.core_stop_o & ~core_rst):
+ 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/SVSTATE. arrives one clock later
+ comb += self.state_r_msr.ren.eq(1 << StateRegs.MSR)
+ comb += self.state_r_sv.ren.eq(1 << StateRegs.SVSTATE)
+ sync += msr_read.eq(0)
+ sync += sv_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)
+
+ # dummy pause to find out why simulation is not keeping up
+ with m.State("INSN_READ"):
+ # one cycle later, msr/sv read arrives. valid only once.
+ with m.If(~msr_read):
+ sync += msr_read.eq(1) # yeah don't read it again
+ sync += cur_state.msr.eq(self.state_r_msr.data_o)
+ with m.If(~sv_read):
+ sync += sv_read.eq(1) # yeah don't read it again
+ sync += cur_state.svstate.eq(self.state_r_sv.data_o)
+ 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 = get_insn(self.imem.f_instr_o, cur_state.pc)
+ # 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
+ insn = get_insn(self.imem.f_instr_o, cur_state.pc+4)
+ 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"
+
def elaborate(self, platform):
m = Module()
comb, sync = m.d.comb, m.d.sync
# PC and instruction from I-Memory
pc_changed = Signal() # note write to PC
comb += self.pc_o.eq(cur_state.pc)
- ilatch = Signal(32)
# address of the next instruction, in the absence of a branch
# depends on the instruction size
# (as opposed to using sync - which would be on a clock's delay)
# this includes the actual opcode, valid flags and so on.
- # this FSM performs fetch of raw instruction data, partial-decodes
- # it 32-bit at a time to detect SVP64 prefixes, and will optionally
- # read a 2nd 32-bit quantity if that occurs.
-
- with m.FSM(name='fetch_fsm'):
-
- # waiting (zzz)
- with m.State("IDLE"):
- with m.If(~dbg.core_stop_o & ~core_rst):
- 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/SVSTATE. arrives one clock later
- comb += self.state_r_msr.ren.eq(1 << StateRegs.MSR)
- comb += self.state_r_sv.ren.eq(1 << StateRegs.SVSTATE)
- sync += msr_read.eq(0)
- sync += sv_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)
-
- # dummy pause to find out why simulation is not keeping up
- with m.State("INSN_READ"):
- # one cycle later, msr/sv read arrives. valid only once.
- with m.If(~msr_read):
- sync += msr_read.eq(1) # yeah don't read it again
- sync += cur_state.msr.eq(self.state_r_msr.data_o)
- with m.If(~sv_read):
- sync += sv_read.eq(1) # yeah don't read it again
- sync += cur_state.svstate.eq(self.state_r_sv.data_o)
- 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 = get_insn(self.imem.f_instr_o, cur_state.pc)
- # 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
- insn = get_insn(self.imem.f_instr_o, cur_state.pc+4)
- 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"
+ self.fetch_fsm(m, core, dbg, pc, nia,
+ core_rst, cur_state,
+ fetch_pc_ready_o, fetch_pc_valid_i,
+ fetch_insn_valid_o, fetch_insn_ready_i,
+ msr_read, sv_read,
+ fetch_insn_o)
# decode / issue / execute FSM. this interacts with the "fetch" FSM
# through fetch_pc_ready/valid (incoming) and fetch_insn_ready/valid
sync += core.state.eq(cur_state)
sync += core.raw_insn_i.eq(dec_opcode_i)
sync += core.bigendian_i.eq(self.core_bigendian_i)
- sync += ilatch.eq(insn) # latch current insn
# also drop PC and MSR into decode "state"
m.next = "INSN_START" # move to "start"