-Subproject commit 71d70e4c753d1171c1fb83e1b9f9d78c9372f8d1
+Subproject commit 1970241a6db97d4ace1e053e72f2a3d9462e98b2
# decode Fast-SPR based on instruction type
op = self.dec.op
# BC or BCREG: potential implicit register (CTR) NOTE: same in DecodeOut
- with m.If((op.internal_op == InternalOp.OP_BC) |
- (op.internal_op == InternalOp.OP_BCREG)):
- with m.If(~self.dec.BO[2] | # 3.0B p38 BO2=0, use CTR reg
- self.dec.FormXL.XO[9]): # 3.0B p38 top bit of XO
+ with m.If(op.internal_op == InternalOp.OP_BC):
+ with m.If(~self.dec.BO[2]): # 3.0B p38 BO2=0, use CTR reg
+ comb += self.fast_out.data.eq(FastRegs.CTR) # constant: CTR
+ comb += self.fast_out.ok.eq(1)
+ with m.Elif(op.internal_op == InternalOp.OP_BCREG):
+ xo9 = self.dec.FormXL.XO[9] # 3.0B p38 top bit of XO
+ xo5 = self.dec.FormXL.XO[5] # 3.0B p38
+ with m.If(xo9 & ~xo5):
comb += self.fast_out.data.eq(FastRegs.CTR) # constant: CTR
comb += self.fast_out.ok.eq(1)
# decode SPR2 based on instruction type
op = self.dec.op
- # BCREG implicitly uses LR or TAR for 2nd reg (TODO: TAR)
+ # BCREG implicitly uses LR or TAR for 2nd reg
# CTR however is already in fast_spr1 *not* 2.
- with m.If((op.internal_op == InternalOp.OP_BC) |
- (op.internal_op == InternalOp.OP_BCREG)):
- with m.If(~self.dec.FormXL.XO[9]): # 3.0B p38 top bit of XO
+ with m.If(op.internal_op == InternalOp.OP_BCREG):
+ xo9 = self.dec.FormXL.XO[9] # 3.0B p38 top bit of XO
+ xo5 = self.dec.FormXL.XO[5] # 3.0B p38
+ with m.If(~xo9):
comb += self.fast_out.data.eq(FastRegs.LR)
comb += self.fast_out.ok.eq(1)
+ with m.Elif(xo5):
+ comb += self.fast_out.data.eq(FastRegs.TAR)
+ comb += self.fast_out.ok.eq(1)
return m
def __init__(self, dec):
self.dec = dec
self.sel_in = Signal(OutSel, reset_less=True)
+ self.lk = Signal(reset_less=True)
self.insn_in = Signal(32, reset_less=True)
self.reg_out = Data(5, "reg_o")
self.fast_out = Data(3, "fast_o")
op = self.dec.op
with m.If((op.internal_op == InternalOp.OP_BC) |
(op.internal_op == InternalOp.OP_BCREG)):
- with m.If(self.dec.op.lk & self.dec.LK): # "link" mode
+ with m.If(self.lk): # "link" mode
comb += self.fast_out.data.eq(FastRegs.LR) # constant: LR
comb += self.fast_out.ok.eq(1)
comb += dec_c.sel_in.eq(self.dec.op.in3_sel)
comb += dec_o.sel_in.eq(self.dec.op.out_sel)
comb += dec_o2.sel_in.eq(self.dec.op.out_sel)
+ comb += dec_o2.lk.eq(self.e.lk)
comb += dec_rc.sel_in.eq(self.dec.op.rc_sel)
comb += dec_oe.sel_in.eq(self.dec.op.rc_sel) # XXX should be OE sel
comb += dec_cr_in.sel_in.eq(self.dec.op.cr_in)
to Function Unit port regfiles (read-enable, read regnum, write regnum)
regfile and regname arguments are fields 1 and 2 from a given regspec.
"""
- return regspec_decode(self, regfile, regname)
+ return regspec_decode(self.e, regfile, regname)
+
+ def rdflags(self, cu):
+ rdl = []
+ for idx in range(cu.n_src):
+ regfile, regname, _ = cu.get_in_spec(idx)
+ rdflag, read, write = self.regspecmap(regfile, regname)
+ rdl.append(rdflag)
+ print ("rdflags", rdl)
+ return Cat(*rdl)
if __name__ == '__main__':
"""
from nmigen import Const
from soc.regfile.regfiles import XERRegs, FastRegs
+from soc.decoder.power_enums import CryIn
def regspec_decode(e, regfile, name):
CA = 1<<XERRegs.CA
OV = 1<<XERRegs.OV
if name == 'xer_so':
- return e.oe.oe & e.oe.oe_ok, SO, SO
+ return e.oe.oe[0] & e.oe.oe_ok, SO, SO
if name == 'xer_ov':
- return e.oe.oe & e.oe.oe_ok, OV, OV
+ return e.oe.oe[0] & e.oe.oe_ok, OV, OV
if name == 'xer_ca':
- return e.input_carry, CA, CA
+ return (e.input_carry == CryIn.CA.value), CA, CA
if regfile == 'FAST':
# FAST register numbering is *unary* encoded
return Const(1), MSR, MS # TODO: detect read-conditions
# TODO: remap the SPR numbers to FAST regs
if name == 'spr1':
- return e.read_spr1.ok, 1<<e.read_spr1.data, 1<<e.write_fast1.data
+ return e.read_fast1.ok, 1<<e.read_fast1.data, 1<<e.write_fast1.data
if name == 'spr2':
- return e.read_spr2.ok, 1<<e.read_spr2.data, 1<<e.write_fast2.data
+ return e.read_fast2.ok, 1<<e.read_fast2.data, 1<<e.write_fast2.data
- assert False, "regspec not found %s %d" % (repr(regspec), idx)
+ if regfile == 'SPR':
+ assert False, "regfile TODO %s %s %d" % (refgile, repr(regspec), idx)
+ assert False, "regspec not found %s %s %d" % (refgile, repr(regspec), idx)
m.d.comb += wr_any.eq(self.wr.go.bool())
m.d.comb += req_done.eq(wr_any & ~self.alu.n.ready_i & \
((req_l.q & self.wrmask) == 0))
+ # argh, complicated hack: if there are no regs to write,
+ # instead of waiting for regs that are never going to happen,
+ # we indicate "done" when the ALU is "done"
+ with m.If((self.wrmask == 0) & \
+ self.alu.n.ready_i & self.alu.n.valid_o & self.busy_o):
+ m.d.comb += req_done.eq(1)
# shadow/go_die
reset = Signal(reset_less=True)
self.op = 0
self.inv_a = self.zero_a = 0
self.imm = self.imm_ok = 0
+ self.imm_control = (0, 0)
self.rdmaskn = (0, 0)
# input data:
- self.a = self.b = 0
+ self.operands = (0, 0)
+
+ # Indicates completion of the sub-processes
+ self.rd_complete = [False, False]
def driver(self):
print("Begin parallel test.")
def operation(self, a, b, op, inv_a=0, imm=0, imm_ok=0, zero_a=0,
rdmaskn=(0, 0)):
# store data for the operation
- self.a = a
- self.b = b
+ self.operands = (a, b)
self.op = op
self.inv_a = inv_a
self.imm = imm
self.imm_ok = imm_ok
self.zero_a = zero_a
+ self.imm_control = (zero_a, imm_ok)
self.rdmaskn = rdmaskn
+ # Initialize completion flags
+ self.rd_complete = [False, False]
+
# trigger operation cycle
yield from self.issue()
+ # check that the sub-processes completed, before the busy_o cycle ended
+ for completion in self.rd_complete:
+ assert completion
+
def issue(self):
# issue_i starts inactive
yield self.dut.issue_i.eq(0)
# likewise, if the read mask is active
# TODO: don't exit the process, monitor rd instead to ensure it
# doesn't rise on its own
- if self.rdmaskn[rd_idx] \
- or (rd_idx == 0 and self.zero_a) \
- or (rd_idx == 1 and self.imm_ok):
+ if self.rdmaskn[rd_idx] or self.imm_control[rd_idx]:
+ self.rd_complete[rd_idx] = True
return
# issue_i has risen. rel must rise on the next cycle
rel = yield self.dut.rd.rel[rd_idx]
assert rel
- # assert go for one cycle
+ # assert go for one cycle, passing along the operand value
yield self.dut.rd.go[rd_idx].eq(1)
+ yield self.dut.src_i[rd_idx].eq(self.operands[rd_idx])
+ # check that the operand was sent to the alu
+ # TODO: Properly check the alu protocol
+ yield Settle()
+ alu_input = yield self.dut.get_in(rd_idx)
+ assert alu_input == self.operands[rd_idx]
yield
# rel must keep high, since go was inactive in the last cycle
# finish the go one-clock pulse
yield self.dut.rd.go[rd_idx].eq(0)
+ yield self.dut.src_i[rd_idx].eq(0)
yield
# rel must have gone low in response to go being high
rel = yield self.dut.rd.rel[rd_idx]
assert not rel
- # TODO: also when dut.rd.go is set, put the expected value into
- # the src_i. use dut.get_in[rd_idx] to do so
+ self.rd_complete[rd_idx] = True
+
+ # TODO: check that rel doesn't rise again until the end of the
+ # busy_o cycle
def wr(self, wr_idx):
# monitor self.dut.wr.req[rd_idx] and sets dut.wr.go[idx] for one cycle
class ALUPipeSpec(CommonPipeSpec):
regspec = (ALUInputData.regspec, ALUOutputData.regspec)
opsubsetkls = CompALUOpSubset
- def rdflags(self, e): # in order of regspec
- reg1_ok = e.read_reg1.ok # RA
- reg2_ok = e.read_reg2.ok # RB
- return Cat(reg1_ok, reg2_ok, 1, 1) # RA RB CA SO
from soc.decoder.isa.caller import ISACaller, special_sprs
from soc.decoder.power_decoder import (create_pdecode)
from soc.decoder.power_decoder2 import (PowerDecode2)
-from soc.decoder.power_enums import (XER_bits, Function, InternalOp)
+from soc.decoder.power_enums import (XER_bits, Function, InternalOp, CryIn)
from soc.decoder.selectable_int import SelectableInt
from soc.simulator.program import Program
from soc.decoder.isa.all import ISA
self.name = name
-def set_alu_inputs(alu, dec2, sim):
- # TODO: see https://bugs.libre-soc.org/show_bug.cgi?id=305#c43
- # detect the immediate here (with m.If(self.i.ctx.op.imm_data.imm_ok))
- # and place it into data_i.b
+def get_cu_inputs(dec2, sim):
+ """naming (res) must conform to ALUFunctionUnit input regspec
+ """
+ res = {}
+ # RA (or RC)
reg1_ok = yield dec2.e.read_reg1.ok
if reg1_ok:
data1 = yield dec2.e.read_reg1.data
- data1 = sim.gpr(data1).value
- else:
- data1 = 0
+ res['ra'] = sim.gpr(data1).value
+
+ # RB (or immediate)
+ reg2_ok = yield dec2.e.read_reg2.ok
+ if reg2_ok:
+ data2 = yield dec2.e.read_reg2.data
+ res['rb'] = sim.gpr(data2).value
+
+ # XER.ca
+ cry_in = yield dec2.e.input_carry
+ if cry_in == CryIn.CA.value:
+ carry = 1 if sim.spr['XER'][XER_bits['CA']] else 0
+ carry32 = 1 if sim.spr['XER'][XER_bits['CA32']] else 0
+ res['xer_ca'] = carry | (carry32<<1)
+
+ # XER.so
+ oe = yield dec2.e.oe.data[0] & dec2.e.oe.ok
+ if oe:
+ so = 1 if sim.spr['XER'][XER_bits['SO']] else 0
+ res['xer_so'] = so
+
+ return res
+
- yield alu.p.data_i.a.eq(data1)
+
+def set_alu_inputs(alu, dec2, sim):
+ # TODO: see https://bugs.libre-soc.org/show_bug.cgi?id=305#c43
+ # detect the immediate here (with m.If(self.i.ctx.op.imm_data.imm_ok))
+ # and place it into data_i.b
+
+ inp = yield from get_cu_inputs(dec2, sim)
+ if 'ra' in inp:
+ yield alu.p.data_i.a.eq(inp['ra'])
+ if 'rb' in inp:
+ yield alu.p.data_i.b.eq(inp['rb'])
# If there's an immediate, set the B operand to that
- reg2_ok = yield dec2.e.read_reg2.ok
imm_ok = yield dec2.e.imm_data.imm_ok
if imm_ok:
data2 = yield dec2.e.imm_data.imm
- elif reg2_ok:
- data2 = yield dec2.e.read_reg2.data
- data2 = sim.gpr(data2).value
- else:
- data2 = 0
- yield alu.p.data_i.b.eq(data2)
-
-
+ yield alu.p.data_i.b.eq(data2)
-def set_extra_alu_inputs(alu, dec2, sim):
- carry = 1 if sim.spr['XER'][XER_bits['CA']] else 0
- carry32 = 1 if sim.spr['XER'][XER_bits['CA32']] else 0
- yield alu.p.data_i.xer_ca[0].eq(carry)
- yield alu.p.data_i.xer_ca[1].eq(carry32)
- so = 1 if sim.spr['XER'][XER_bits['SO']] else 0
- yield alu.p.data_i.xer_so.eq(so)
+ if 'xer_ca' in inp:
+ yield alu.p.data_i.xer_ca.eq(inp['xer_ca'])
+ print ("extra inputs: CA/32", bin(inp['xer_ca']))
+ if 'xer_so' in inp:
+ so = inp['xer_so']
+ print ("extra inputs: so", so)
+ yield alu.p.data_i.xer_so.eq(so)
# This test bench is a bit different than is usual. Initially when I
fn_unit = yield pdecode2.e.fn_unit
self.assertEqual(fn_unit, Function.ALU.value)
yield from set_alu_inputs(alu, pdecode2, simulator)
- yield from set_extra_alu_inputs(alu, pdecode2, simulator)
yield
opname = code.split(' ')[0]
yield from simulator.call(opname)
comb += br_addr.eq(br_imm_addr + cia)
# fields for conditional branches (BO and BI are same for BC and BCREG)
- # NOTE: here, BO and BI we would like be treated as CR regfile
- # selectors (similar to RA, RB, RS, RT). see comment here:
- # https://bugs.libre-soc.org/show_bug.cgi?id=313#c2
b_fields = self.fields.FormB
BO = b_fields.BO[0:-1]
- BI = b_fields.BI[0:-1][0:2]
+ BI = b_fields.BI[0:-1][0:2] # CR0-7 selected already in PowerDecode2.
- cr_bits = Array([cr[3-i] for i in range(4)])
+ cr_bits = Array([cr[3-i] for i in range(4)]) # invert. Because POWER.
# The bit of CR selected by BI
+ bi = Signal(2, reset_less=True)
cr_bit = Signal(reset_less=True)
- comb += cr_bit.eq(cr_bits[BI])
+ comb += bi.eq(BI) # reduces gate-count due to pmux
+ comb += cr_bit.eq(cr_bits[bi])
# Whether ctr is written to on a conditional branch
ctr_write = Signal(reset_less=True)
comb += ctr_o.ok.eq(ctr_write)
#### branch conditional reg ####
with m.Case(InternalOp.OP_BCREG):
- comb += br_imm_addr.eq(Cat(Const(0, 2), spr2[2:]))
+ xo = self.fields.FormXL.XO[0:-1]
+ with m.If(xo[9] & ~xo[5]):
+ comb += br_imm_addr.eq(Cat(Const(0, 2), spr1[2:]))
+ with m.Else():
+ comb += br_imm_addr.eq(Cat(Const(0, 2), spr2[2:]))
comb += br_taken.eq(bc_taken)
comb += ctr_o.ok.eq(ctr_write)
class BranchPipeSpec(CommonPipeSpec):
regspec = (BranchInputData.regspec, BranchOutputData.regspec)
opsubsetkls = CompBROpSubset
- def rdflags(self, e): # in order of regspec
- cr1_en = e.read_cr1.ok # CR A
- fast1_ok = e.read_fast1.ok # SPR1
- fast2_ok = e.read_fast2.ok # SPR2
- return Cat(fast1_ok, fast2_ok, cr1_en, 1) # SPR1 SPR2 CR CIA
from soc.fu.branch.pipe_data import BranchPipeSpec
import random
+from soc.regfile.util import fast_reg_to_spr # HACK!
class TestCase:
def __init__(self, program, regs, sprs, cr, name):
test_data = []
+def get_cu_inputs(dec2, sim):
+ """naming (res) must conform to BranchFunctionUnit input regspec
+ """
+ res = {}
+
+ # CIA (PC)
+ res['cia'] = sim.pc.CIA.value
+
+ fast1_en = yield dec2.e.read_fast1.ok
+ if fast1_en:
+ fast1_sel = yield dec2.e.read_fast1.data
+ spr1_sel = fast_reg_to_spr(fast1_sel)
+ spr1_data = sim.spr[spr1_sel].value
+ res['spr1'] = spr1_data
+
+ fast2_en = yield dec2.e.read_fast2.ok
+ if fast2_en:
+ fast2_sel = yield dec2.e.read_fast2.data
+ spr2_sel = fast_reg_to_spr(fast2_sel)
+ spr2_data = sim.spr[spr2_sel].value
+ res['spr2'] = spr2_data
+
+ cr_en = yield dec2.e.read_cr1.ok
+ if cr_en:
+ cr_sel = yield dec2.e.read_cr1.data
+ cr = sim.crl[cr_sel].get_range().value
+ res['cr_a'] = cr
+
+ print ("get inputs", res)
+ return res
+
+
class BranchTestCase(FHDLTestCase):
def __init__(self, name):
super().__init__(name)
initial_sprs=initial_sprs,
initial_cr=cr)
-
+
def test_ilang(self):
pspec = BranchPipeSpec(id_wid=2)
# ask the decoder to decode this binary data (endian'd)
yield pdecode2.dec.bigendian.eq(0) # little / big?
yield instruction.eq(ins) # raw binary instr.
- yield branch.p.data_i.cia.eq(simulator.pc.CIA.value)
# note, here, the op will need further decoding in order
# to set the correct SPRs on SPR1/2/3. op_bc* require
# spr1 to be set to CTR, op_bctar require spr2 to be
print(f"real: {branch_addr:x}, sim: {sim.pc.CIA.value:x}")
self.assertEqual(branch_addr, sim.pc.CIA.value, code)
+ # TODO: check write_fast1 as well (should contain CTR)
+
+ # TODO: this should be checking write_fast2
lk = yield dec2.e.lk
branch_lk = yield branch.n.data_o.lr.ok
self.assertEqual(lk, branch_lk, code)
self.assertEqual(sim.spr['LR'], branch_lr, code)
def set_inputs(self, branch, dec2, sim):
- yield branch.p.data_i.spr1.eq(sim.spr['CTR'].value)
print(f"cr0: {sim.crl[0].get_range()}")
- insn_type = yield dec2.e.insn_type
- if insn_type == InternalOp.OP_BCREG.value:
- xo9 = yield dec2.dec.FormXL.XO[9]
- xo5 = yield dec2.dec.FormXL.XO[5]
- if xo9 == 0:
- yield branch.p.data_i.spr2.eq(sim.spr['LR'].value)
- elif xo5 == 1:
- yield branch.p.data_i.spr2.eq(sim.spr['TAR'].value)
- else:
- yield branch.p.data_i.spr2.eq(sim.spr['CTR'].value)
-
- cr_en = yield dec2.e.read_cr1.ok
- if cr_en:
- cr_sel = yield dec2.e.read_cr1.data
- cr = sim.crl[cr_sel].get_range().value
- yield branch.p.data_i.cr.eq(cr)
- full_cr = sim.cr.get_range().value
- print(f"full cr: {full_cr:x}, sel: {cr_sel}, cr: {cr:x}")
+ inp = yield from get_cu_inputs(dec2, sim)
+
+ if 'cia' in inp:
+ yield branch.p.data_i.cia.eq(inp['cia'])
+ if 'spr1' in inp:
+ yield branch.p.data_i.spr1.eq(inp['spr1'])
+ if 'spr2' in inp:
+ yield branch.p.data_i.spr2.eq(inp['spr2'])
+ if 'cr_a' in inp:
+ yield branch.p.data_i.cr.eq(inp['cr_a'])
if __name__ == "__main__":
"""
+# imports
+
from nmigen import Cat
from nmigen.cli import rtlil
from soc.experiment.compalu_multi import MultiCompUnit
alu = pipekls(pspec) # create actual NNNBasePipe
super().__init__(regspec, alu, opsubset) # pass to MultiCompUnit
- def rdflags(self, e):
- print (dir(self.alu))
- return self.alu.pspec.rdflags(e)
-
##############################################################
# TODO: ReservationStations-based (FunctionUnitBaseConcurrent)
from soc.decoder.power_enums import (XER_bits, Function)
# XXX bad practice: use of global variables
+from soc.fu.alu.test.test_pipe_caller import get_cu_inputs
from soc.fu.alu.test.test_pipe_caller import ALUTestCase # creates the tests
from soc.fu.alu.test.test_pipe_caller import test_data # imports the data
def get_cu_inputs(self, dec2, sim):
"""naming (res) must conform to ALUFunctionUnit input regspec
"""
- res = {}
-
- # RA (or RC)
- reg1_ok = yield dec2.e.read_reg1.ok
- if reg1_ok:
- data1 = yield dec2.e.read_reg1.data
- res['ra'] = sim.gpr(data1).value
-
- # RB (or immediate)
- reg2_ok = yield dec2.e.read_reg2.ok
- if reg2_ok:
- data2 = yield dec2.e.read_reg2.data
- res['rb'] = sim.gpr(data2).value
-
- # XER.ca
- carry = 1 if sim.spr['XER'][XER_bits['CA']] else 0
- carry32 = 1 if sim.spr['XER'][XER_bits['CA32']] else 0
- res['xer_ca'] = carry | (carry32<<1)
-
- # XER.so
- so = 1 if sim.spr['XER'][XER_bits['SO']] else 0
- res['xer_so'] = so
-
+ res = yield from get_cu_inputs(dec2, sim)
return res
def check_cu_outputs(self, res, dec2, sim, code):
from soc.decoder.power_enums import (XER_bits, Function, spr_dict, SPR)
# XXX bad practice: use of global variables
-from soc.fu.branch.test.test_pipe_caller import BranchTestCase
+from soc.fu.branch.test.test_pipe_caller import BranchTestCase, get_cu_inputs
from soc.fu.branch.test.test_pipe_caller import test_data
from soc.fu.compunits.compunits import BranchFunctionUnit
from soc.fu.compunits.test.test_compunit import TestRunner
-from soc.regfile.regfiles import FastRegs
+from soc.regfile.util import fast_reg_to_spr # HACK!
"""
def assert_outputs(self, branch, dec2, sim, prev_nia, code):
"""
-def fast_reg_to_spr(spr_num):
- if spr_num == FastRegs.CTR:
- return SPR.CTR.value
- elif spr_num == FastRegs.LR:
- return SPR.LR.value
- elif spr_num == FastRegs.TAR:
- return SPR.TAR.value
-
class BranchTestRunner(TestRunner):
def __init__(self, test_data):
def get_cu_inputs(self, dec2, sim):
"""naming (res) must conform to BranchFunctionUnit input regspec
"""
- res = {}
- full_reg = yield dec2.e.read_cr_whole
-
- # CIA (PC)
- res['cia'] = sim.pc.CIA.value
-
- # CR A
- cr1_en = yield dec2.e.read_cr1.ok
- if cr1_en:
- cr1_sel = yield dec2.e.read_cr1.data
- res['cr_a'] = sim.crl[cr1_sel].get_range().value
-
- # Fast1
- spr_ok = yield dec2.e.read_fast1.ok
- spr_num = yield dec2.e.read_fast1.data
- # HACK
- spr_num = fast_reg_to_spr(spr_num)
- if spr_ok:
- res['spr1'] = sim.spr[spr_dict[spr_num].SPR].value
-
- # SPR2
- spr_ok = yield dec2.e.read_fast2.ok
- spr_num = yield dec2.e.read_fast2.data
- # HACK
- spr_num = fast_reg_to_spr(spr_num)
- if spr_ok:
- res['spr2'] = sim.spr[spr_dict[spr_num].SPR].value
-
- print ("get inputs", res)
+ res = yield from get_cu_inputs(dec2, sim)
return res
def check_cu_outputs(self, res, dec2, sim, code):
inp = get_inp_indexed(cu, iname)
# reset read-operand mask
- rdmask = cu.rdflags(pdecode2.e)
+ rdmask = pdecode2.rdflags(cu)
+ #print ("hardcoded rdmask", cu.rdflags(pdecode2.e))
+ #print ("decoder rdmask", rdmask)
yield cu.rdmaskn.eq(~rdmask)
# reset write-operand mask
fname = find_ok(wrok.fields)
yield getattr(wrok, fname).eq(0)
- # first set inputs to zero
- for idx in range(cu.n_src):
- cu_in = cu.get_in(idx)
- yield cu_in.eq(0)
+ yield Settle()
# set inputs into CU
rd_rel_o = yield cu.rd.rel
wr_rel_o = yield cu.wr.rel
print ("before inputs, rd_rel, wr_rel: ",
bin(rd_rel_o), bin(wr_rel_o))
+ assert wr_rel_o == 0, "wr.rel %s must be zero. "\
+ "previous instr not written all regs\n"\
+ "respec %s" % \
+ (bin(wr_rel_o), cu.rwid[1])
yield from set_cu_inputs(cu, inp)
yield
rd_rel_o = yield cu.rd.rel
yield from sim.call(opname)
index = sim.pc.CIA.value//4
+ yield Settle()
# get all outputs (one by one, just "because")
res = yield from get_cu_outputs(cu, code)
from soc.decoder.power_enums import (XER_bits, Function)
# XXX bad practice: use of global variables
-from soc.fu.logical.test.test_pipe_caller import LogicalTestCase
+from soc.fu.logical.test.test_pipe_caller import LogicalTestCase, get_cu_inputs
from soc.fu.logical.test.test_pipe_caller import test_data
from soc.fu.compunits.compunits import LogicalFunctionUnit
def get_cu_inputs(self, dec2, sim):
"""naming (res) must conform to LogicalFunctionUnit input regspec
"""
- res = {}
-
- # RA (or RC)
- reg1_ok = yield dec2.e.read_reg1.ok
- if reg1_ok:
- data1 = yield dec2.e.read_reg1.data
- res['ra'] = sim.gpr(data1).value
-
- # RB (or immediate)
- reg2_ok = yield dec2.e.read_reg2.ok
- if reg2_ok:
- data2 = yield dec2.e.read_reg2.data
- res['rb'] = sim.gpr(data2).value
-
+ res = yield from get_cu_inputs(dec2, sim)
return res
def check_cu_outputs(self, res, dec2, sim, code):
from soc.fu.compunits.compunits import ShiftRotFunctionUnit
from soc.fu.compunits.test.test_compunit import TestRunner
+from soc.decoder.power_enums import CryIn
+
class ShiftRotTestRunner(TestRunner):
def __init__(self, test_data):
res['rc'] = sim.gpr(data3).value
# XER.ca
- carry = 1 if sim.spr['XER'][XER_bits['CA']] else 0
- carry32 = 1 if sim.spr['XER'][XER_bits['CA32']] else 0
- res['xer_ca'] = carry | (carry32<<1)
+ cry_in = yield dec2.e.input_carry
+ if cry_in == CryIn.CA.value:
+ carry = 1 if sim.spr['XER'][XER_bits['CA']] else 0
+ carry32 = 1 if sim.spr['XER'][XER_bits['CA32']] else 0
+ res['xer_ca'] = carry | (carry32<<1)
print ("inputs", res)
class CRPipeSpec(CommonPipeSpec):
regspec = (CRInputData.regspec, CROutputData.regspec)
opsubsetkls = CompCROpSubset
- def rdflags(self, e): # in order of regspec
- reg1_ok = e.read_reg1.ok # RA/RC
- reg2_ok = e.read_reg2.ok # RB
- full_reg = e.read_cr_whole # full CR
- cr1_en = e.read_cr1.ok # CR A
- cr2_en = e.read_cr2.ok # CR B
- cr3_en = e.read_cr3.ok # CR C
- return Cat(reg1_ok, reg2_ok, full_reg, cr1_en, cr2_en, cr3_en)
class LogicalPipeSpec(CommonPipeSpec):
regspec = (LogicalInputData.regspec, LogicalOutputData.regspec)
opsubsetkls = CompLogicalOpSubset
- def rdflags(self, e): # in order of regspec
- reg1_ok = e.read_reg1.ok # RA
- reg2_ok = e.read_reg2.ok # RB
- return Cat(reg1_ok, reg2_ok) # RA RB
self.sprs = sprs
self.name = name
+def get_cu_inputs(dec2, sim):
+ """naming (res) must conform to LogicalFunctionUnit input regspec
+ """
+ res = {}
-def set_alu_inputs(alu, dec2, sim):
- # TODO: see https://bugs.libre-soc.org/show_bug.cgi?id=305#c43
- # detect the immediate here (with m.If(self.i.ctx.op.imm_data.imm_ok))
- # and place it into data_i.b
-
+ # RA (or RC)
reg1_ok = yield dec2.e.read_reg1.ok
if reg1_ok:
data1 = yield dec2.e.read_reg1.data
- data1 = sim.gpr(data1).value
- else:
- data1 = 0
+ res['ra'] = sim.gpr(data1).value
- yield alu.p.data_i.a.eq(data1)
-
- # If there's an immediate, set the B operand to that
+ # RB (or immediate)
reg2_ok = yield dec2.e.read_reg2.ok
+ #imm_ok = yield dec2.e.imm_data.imm_ok
+ if reg2_ok:
+ data2 = yield dec2.e.read_reg2.data
+ data2 = sim.gpr(data2).value
+ res['rb'] = data2
+ #elif imm_ok:
+ # data2 = yield dec2.e.imm_data.imm
+ # res['rb'] = data2
+
+ return res
+
+
+def set_alu_inputs(alu, dec2, sim):
+ # TODO: see https://bugs.libre-soc.org/show_bug.cgi?id=305#c43
+ # detect the immediate here (with m.If(self.i.ctx.op.imm_data.imm_ok))
+ # and place it into data_i.b
+
+ inp = yield from get_cu_inputs(dec2, sim)
+ if 'ra' in inp:
+ yield alu.p.data_i.a.eq(inp['ra'])
+ if 'rb' in inp:
+ yield alu.p.data_i.b.eq(inp['rb'])
imm_ok = yield dec2.e.imm_data.imm_ok
if imm_ok:
data2 = yield dec2.e.imm_data.imm
- elif reg2_ok:
- data2 = yield dec2.e.read_reg2.data
- data2 = sim.gpr(data2).value
- else:
- data2 = 0
- yield alu.p.data_i.b.eq(data2)
+ yield alu.p.data_i.b.eq(data2)
# This test bench is a bit different than is usual. Initially when I
self.rwid = rwid
self.alu = alu # actual ALU - set as a "submodule" of the CU
+ def get_in_spec(self, i):
+ return self.rwid[0][i]
+
+ def get_out_spec(self, i):
+ return self.rwid[1][i]
+
def get_in_name(self, i):
- return self.rwid[0][i][1]
+ return self.get_in_spec(i)[1]
def get_out_name(self, i):
- return self.rwid[1][i][1]
+ return self.get_out_spec(i)[1]
def get_out(self, i):
if isinstance(self.rwid, int): # old - testing - API (rwid is int)
class ShiftRotPipeSpec(CommonPipeSpec):
regspec = (ShiftRotInputData.regspec, LogicalOutputData.regspec)
opsubsetkls = CompSROpSubset
- def rdflags(self, e): # in order of regspec input
- reg1_ok = e.read_reg1.ok # RA
- reg2_ok = e.read_reg2.ok # RB
- reg3_ok = e.read_reg3.ok # RS
- return Cat(reg1_ok, reg2_ok, reg3_ok, 1) # RA RB RC CA
class SPRInputData(IntegerData):
- regspec = [('INT', 'a', '0:63'),
+ regspec = [('INT', 'ra', '0:63'),
('SPR', 'spr1', '0:63'),
('FAST', 'spr2', '0:63'),
('XER', 'xer_so', '32'),
('XER', 'xer_ca', '34,45')]
def __init__(self, pspec):
super().__init__(pspec)
- self.a = Signal(64, reset_less=True) # RA
+ self.ra = Signal(64, reset_less=True) # RA
self.spr1 = Signal(64, reset_less=True) # SPR (slow)
self.spr2 = Signal(64, reset_less=True) # SPR (fast: MSR, LR, CTR etc)
self.xer_so = Signal(reset_less=True) # XER bit 32: SO
self.xer_ca = Signal(2, reset_less=True) # XER bit 34/45: CA/CA32
self.xer_ov = Signal(2, reset_less=True) # bit0: ov, bit1: ov32
+ # convenience
+ self.a = self.ra
def __iter__(self):
yield from super().__iter__()
- yield self.a
+ yield self.ra
yield self.spr1
yield self.spr2
yield self.xer_ca
def eq(self, i):
lst = super().eq(i)
- return lst + [self.a.eq(i.a), self.reg.eq(i.reg),
+ return lst + [self.ra.eq(i.ra), self.reg.eq(i.reg),
self.spr1.eq(i.spr1), self.spr2.eq(i.spr2),
self.xer_ca.eq(i.xer_ca),
self.xer_ov.eq(i.xer_ov),
from nmutil.pipemodbase import PipeModBase
from nmutil.extend import exts
from soc.fu.trap.pipe_data import TrapInputData, TrapOutputData
+from soc.fu.branch.main_stage import br_ext
from soc.decoder.power_enums import InternalOp
from soc.decoder.power_fields import DecodeFields
from soc.decoder.power_fieldsn import SignalBitRange
# TODO at some point move these to their own module (for use elsewhere)
+# TODO: turn these into python constants (just "MSR_SF = 63-0 # comment" etc.)
"""
+ Listed in V3.0B Book III Chap 4.2.1
-- MSR bit numbers
constant MSR_SF : integer := (63 - 0); -- Sixty-Four bit mode
+ constant MSR_HV : integer := (63 - 3); -- Hypervisor state
+ constant MSR_S : integer := (63 - 41); -- Secure state
constant MSR_EE : integer := (63 - 48); -- External interrupt Enable
constant MSR_PR : integer := (63 - 49); -- PRoblem state
+ constant MSR_FP : integer := (63 - 50); -- FP available
+ constant MSR_ME : integer := (63 - 51); -- Machine Check int enable
constant MSR_IR : integer := (63 - 58); -- Instruction Relocation
constant MSR_DR : integer := (63 - 59); -- Data Relocation
+ constant MSR_PMM : integer := (63 - 60); -- Performance Monitor Mark
constant MSR_RI : integer := (63 - 62); -- Recoverable Interrupt
constant MSR_LE : integer := (63 - 63); -- Little Endian
"""
with m.Case(InternalOp.OP_MTMSR):
# TODO: some of the bits need zeroing?
"""
- if e_in.insn(16) = '1' then
+ if e_in.insn(16) = '1' then <-- this is X-form field "L".
-- just update EE and RI
ctrl_tmp.msr(MSR_EE) <= c_in(MSR_EE);
ctrl_tmp.msr(MSR_RI) <= c_in(MSR_RI);
ctrl_tmp.msr(MSR_IR) <= '1';
ctrl_tmp.msr(MSR_DR) <= '1';
"""
- comb += self.o.msr.data.eq(a)
+ L = self.fields.FormX.L[0:-1]
+ with m.If(L):
+ comb += self.o.msr[MSR_EE].eq(self.i.msr[MSR_EE])
+ comb += self.o.msr[MSR_RI].eq(self.i.msr[MSR_RI])
+
+ with m.Else():
+ for stt, end in [(1,12), (13, 60), (61, 64)]:
+ comb += self.o.msr.data[stt:end].eq(a[stt:end])
+ with m.If(a[MSR_PR]):
+ self.o.msr[MSR_EE].eq(1)
+ self.o.msr[MSR_IR].eq(1)
+ self.o.msr[MSR_DR].eq(1)
comb += self.o.msr.ok.eq(1)
# move from SPR
comb += self.o.o.data.eq(self.i.msr)
comb += self.o.o.ok.eq(1)
- # TODO
with m.Case(InternalOp.OP_RFID):
"""
# XXX f_out.virt_mode <= b_in(MSR_IR) or b_in(MSR_PR);
ctrl_tmp.msr(MSR_DR) <= '1';
end if;
"""
- pass
+ comb += self.o.nia.data.eq(br_ext(a[63:1] & 0))
+ comb += self.o.nia.ok.eq(1)
+ for stt, end in [(0,16), (22, 27), (31, 64)]:
+ comb += self.o.msr.data[stt:end].eq(a[stt:end])
+ with m.If(a[MSR_PR]):
+ self.o.msr[MSR_EE].eq(1)
+ self.o.msr[MSR_IR].eq(1)
+ self.o.msr[MSR_DR].eq(1)
+ comb += self.o.msr.ok.eq(1)
- # TODO
with m.Case(InternalOp.OP_SC):
"""
# TODO: scv must generate illegal instruction. this is
ctrl_tmp.irq_nia <= std_logic_vector(to_unsigned(16#C00#, 64));
ctrl_tmp.srr1 <= msr_copy(ctrl.msr);
"""
- pass
+ comb += self.o.nia.eq(0xC00) # trap address
+ comb += self.o.nia.ok.eq(1)
+ comb += self.o.srr1.data.eq(self.i.msr)
+ comb += self.o.srr1.ok.eq(1)
+ # TODO (later)
#with m.Case(InternalOp.OP_ADDPCIS):
# pass
--- /dev/null
+from soc.regfile.regfiles import FastRegs
+from soc.decoder.power_enums import SPR
+
+def fast_reg_to_spr(spr_num):
+ if spr_num == FastRegs.CTR:
+ return SPR.CTR.value
+ elif spr_num == FastRegs.LR:
+ return SPR.LR.value
+ elif spr_num == FastRegs.TAR:
+ return SPR.TAR.value