From 83f98eac357043f8940984eeeaf8d29072c32cb4 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Sun, 5 Apr 2020 17:12:20 -0700 Subject: [PATCH] almost all tests work --- .gitlab-ci.yml | 2 + src/soc/TLB/AddressEncoder.py | 4 +- src/soc/TLB/Cam.py | 33 +- src/soc/TLB/MemorySet.py | 8 +- src/soc/TLB/PermissionValidator.py | 16 +- src/soc/TLB/SetAssociativeCache.py | 48 +-- src/soc/TLB/TLB.py | 50 +-- src/soc/TLB/ariane/test/test_plru.py | 8 +- src/soc/TLB/ariane/test/test_ptw.py | 19 +- src/soc/TLB/ariane/test/test_tlb.py | 9 +- src/soc/TLB/ariane/test/test_tlb_content.py | 60 ++-- src/soc/TLB/ariane/tlb.py | 61 ++-- src/soc/TLB/ariane/tlb_content.py | 104 +++--- src/soc/TLB/test/test_LFSR2.py | 5 +- src/soc/TLB/test/test_address_encoder.py | 17 +- src/soc/TLB/test/test_cam.py | 18 +- src/soc/TLB/test/test_cam_entry.py | 15 +- src/soc/TLB/test/test_permission_validator.py | 12 +- src/soc/TLB/test/test_pte_entry.py | 18 +- .../TLB/test/test_set_associative_cache.py | 11 +- src/soc/TLB/test/test_tlb.py | 70 ++-- src/soc/decoder/isa/.gitignore | 14 + src/soc/decoder/isa/test_caller.py | 8 +- src/soc/decoder/pseudo/parser.py | 86 ++--- src/soc/experiment/compldst.py | 120 ++++--- src/soc/experiment/cscore.py | 133 +++---- src/soc/experiment/score6600.py | 264 +++++++------- src/soc/iommu/axi_rab/ram_tp_no_change.py | 2 +- src/soc/iommu/axi_rab/ram_tp_write_first.py | 2 +- src/soc/minerva/core.py | 146 ++++---- src/soc/minerva/test/.gitignore | 1 + src/soc/minerva/test/test_units_divider.py | 314 ++++++++++------ src/soc/minerva/test/test_units_multiplier.py | 334 ++++++++++++------ src/soc/minerva/units/debug/top.py | 22 +- src/soc/minerva/units/multiplier.py | 27 +- src/soc/scoreboard/fn_unit.py | 74 ++-- src/soc/scoreboard/ldst_matrix.py | 27 +- src/soc/scoreboard/test_mem2_fu_matrix.py | 157 ++++---- src/soc/scoreboard/test_mem_fu_matrix.py | 183 +++++----- src/soc/simulator/test_sim.py | 12 +- 40 files changed, 1419 insertions(+), 1095 deletions(-) create mode 100644 src/soc/decoder/isa/.gitignore create mode 100644 src/soc/minerva/test/.gitignore diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d39c2ada..75269804 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -13,6 +13,7 @@ build: build-essential git python3-dev python3-pip python3-setuptools python3-wheel pkg-config tcl-dev libreadline-dev bison flex libffi-dev ccache python3-venv + binutils-powerpc64-linux-gnu binutils-powerpc64le-linux-gnu - export PATH="/usr/lib/ccache:$PATH" - export CCACHE_BASEDIR="$PWD" - export CCACHE_DIR="$PWD/ccache" @@ -68,4 +69,5 @@ build: - popd - python setup.py develop + - python src/soc/decoder/pseudo/pywriter.py - nosetests -v --processes=-1 diff --git a/src/soc/TLB/AddressEncoder.py b/src/soc/TLB/AddressEncoder.py index 128f2c97..49da8197 100644 --- a/src/soc/TLB/AddressEncoder.py +++ b/src/soc/TLB/AddressEncoder.py @@ -1,6 +1,7 @@ from nmigen import Module, Signal, Elaboratable from nmigen.lib.coding import Encoder, PriorityEncoder + class AddressEncoder(Elaboratable): """Address Encoder @@ -15,6 +16,7 @@ class AddressEncoder(Elaboratable): The output is valid when either single or multiple match is high. Otherwise output is 0. """ + def __init__(self, width): """ Arguments: * width: The desired length of the input vector @@ -29,7 +31,7 @@ class AddressEncoder(Elaboratable): # Output self.single_match = Signal(1) self.multiple_match = Signal(1) - self.o = Signal(max=width) + self.o = Signal(range(width)) def elaborate(self, platform=None): m = Module() diff --git a/src/soc/TLB/Cam.py b/src/soc/TLB/Cam.py index e7d901ff..c5fd0699 100644 --- a/src/soc/TLB/Cam.py +++ b/src/soc/TLB/Cam.py @@ -1,6 +1,6 @@ from nmigen import Array, Cat, Module, Signal, Elaboratable from nmigen.lib.coding import Decoder -from nmigen.cli import main #, verilog +from nmigen.cli import main # , verilog from .CamEntry import CamEntry from .AddressEncoder import AddressEncoder @@ -44,15 +44,17 @@ class Cam(Elaboratable): # Input self.enable = Signal(1) self.write_enable = Signal(1) - self.data_in = Signal(data_size) # The data to be written - self.data_mask = Signal(data_size) # mask for ternary writes - self.address_in = Signal(max=cam_size) # address of CAM Entry to write + self.data_in = Signal(data_size) # The data to be written + self.data_mask = Signal(data_size) # mask for ternary writes + # address of CAM Entry to write + self.address_in = Signal(range(cam_size)) # Output - self.read_warning = Signal(1) # High when a read interrupts a write - self.single_match = Signal(1) # High when there is only one match - self.multiple_match = Signal(1) # High when there at least two matches - self.match_address = Signal(max=cam_size) # The lowest address matched + self.read_warning = Signal(1) # High when a read interrupts a write + self.single_match = Signal(1) # High when there is only one match + self.multiple_match = Signal(1) # High when there at least two matches + # The lowest address matched + self.match_address = Signal(range(cam_size)) def elaborate(self, platform=None): m = Module() @@ -104,22 +106,21 @@ class Cam(Elaboratable): # If the CAM is not enabled set all outputs to 0 with m.Else(): m.d.comb += [ - self.read_warning.eq(0), - self.single_match.eq(0), - self.multiple_match.eq(0), - self.match_address.eq(0) + self.read_warning.eq(0), + self.single_match.eq(0), + self.multiple_match.eq(0), + self.match_address.eq(0) ] return m def ports(self): return [self.enable, self.write_enable, - self.data_in, self.data_mask, - self.read_warning, self.single_match, - self.multiple_match, self.match_address] + self.data_in, self.data_mask, + self.read_warning, self.single_match, + self.multiple_match, self.match_address] if __name__ == '__main__': cam = Cam(4, 4) main(cam, ports=cam.ports()) - diff --git a/src/soc/TLB/MemorySet.py b/src/soc/TLB/MemorySet.py index ea61bdf5..11890edf 100644 --- a/src/soc/TLB/MemorySet.py +++ b/src/soc/TLB/MemorySet.py @@ -6,19 +6,19 @@ from nmigen.cli import verilog, rtlil class MemorySet(Elaboratable): def __init__(self, data_size, tag_size, set_count, active): self.active = active - input_size = tag_size + data_size # Size of the input data - memory_width = input_size + 1 # The width of the cache memory + input_size = tag_size + data_size # Size of the input data + memory_width = input_size + 1 # The width of the cache memory self.active = active self.data_size = data_size self.tag_size = tag_size # XXX TODO, use rd-enable and wr-enable? - self.mem = Memory(memory_width, set_count) + self.mem = Memory(width=memory_width, depth=set_count) self.r = self.mem.read_port() self.w = self.mem.write_port() # inputs (address) - self.cset = Signal(max=set_count) # The set to be checked + self.cset = Signal(range(set_count)) # The set to be checked self.tag = Signal(tag_size) # The tag to find self.data_i = Signal(data_size) # Incoming data diff --git a/src/soc/TLB/PermissionValidator.py b/src/soc/TLB/PermissionValidator.py index 0107c0e9..5bc90b2f 100644 --- a/src/soc/TLB/PermissionValidator.py +++ b/src/soc/TLB/PermissionValidator.py @@ -1,7 +1,7 @@ from nmigen import Module, Signal, Elaboratable from nmigen.cli import main -from TLB.PteEntry import PteEntry +from soc.TLB.PteEntry import PteEntry class PermissionValidator(Elaboratable): @@ -25,14 +25,14 @@ class PermissionValidator(Elaboratable): self.pte_entry = PteEntry(asid_size, pte_size) # Input - self.data = Signal(asid_size + pte_size); - self.xwr = Signal(3) # Execute, Write, Read - self.super_mode = Signal(1) # Supervisor Mode - self.super_access = Signal(1) # Supervisor Access - self.asid = Signal(15) # Address Space IDentifier (ASID) + self.data = Signal(asid_size + pte_size) + self.xwr = Signal(3) # Execute, Write, Read + self.super_mode = Signal(1) # Supervisor Mode + self.super_access = Signal(1) # Supervisor Access + self.asid = Signal(15) # Address Space IDentifier (ASID) # Output - self.valid = Signal(1) # Denotes if the permissions are correct + self.valid = Signal(1) # Denotes if the permissions are correct def elaborate(self, platform=None): m = Module() @@ -53,7 +53,7 @@ class PermissionValidator(Elaboratable): # Valid if entry is not in user mode or supervisor # has Supervisor User Memory (SUM) access via the # SUM bit in the sstatus register - m.d.comb += self.valid.eq((~self.pte_entry.u) \ + m.d.comb += self.valid.eq((~self.pte_entry.u) | self.super_access) # User logic with m.Else(): diff --git a/src/soc/TLB/SetAssociativeCache.py b/src/soc/TLB/SetAssociativeCache.py index 70c075da..30ad8090 100644 --- a/src/soc/TLB/SetAssociativeCache.py +++ b/src/soc/TLB/SetAssociativeCache.py @@ -21,9 +21,9 @@ from .MemorySet import MemorySet from .ariane.plru import PLRU from .LFSR import LFSR, LFSR_POLY_24 -SA_NA = "00" # no action (none) -SA_RD = "01" # read -SA_WR = "10" # write +SA_NA = "00" # no action (none) +SA_RD = "01" # read +SA_WR = "10" # write class SetAssociativeCache(Elaboratable): @@ -35,6 +35,7 @@ class SetAssociativeCache(Elaboratable): while the ASID provides the tag (still to be decided). """ + def __init__(self, tag_size, data_size, set_count, way_count, lfsr=False): """ Arguments * tag_size (bits): The bit count of the tag @@ -52,7 +53,7 @@ class SetAssociativeCache(Elaboratable): self.data_size = data_size # The bit count of the data to be stored # set up Memory array - self.mem_array = Array() # memory array + self.mem_array = Array() # memory array for i in range(way_count): ms = MemorySet(data_size, tag_size, set_count, active=0) self.mem_array.append(ms) @@ -66,24 +67,26 @@ class SetAssociativeCache(Elaboratable): self.lfsr = LFSR(LFSR_POLY_24) else: # PLRU mode - self.plru = PLRU(way_count) # One block to handle plru calculations - self.plru_array = Array() # PLRU data on each set + # One block to handle plru calculations + self.plru = PLRU(way_count) + self.plru_array = Array() # PLRU data on each set for i in range(set_count): - name="plru%d" % i + name = "plru%d" % i self.plru_array.append(Signal(self.plru.TLBSZ, name=name)) # Input self.enable = Signal(1) # Whether the cache is enabled self.command = Signal(2) # 00=None, 01=Read, 10=Write (see SA_XX) - self.cset = Signal(max=set_count) # The set to be checked + self.cset = Signal(range(set_count)) # The set to be checked self.tag = Signal(tag_size) # The tag to find self.data_i = Signal(data_size) # The input data # Output - self.ready = Signal(1) # 0 => Processing 1 => Ready for commands + self.ready = Signal(1) # 0 => Processing 1 => Ready for commands self.hit = Signal(1) # Tag matched one way in the given set - self.multiple_hit = Signal(1) # Tag matched many ways in the given set - self.data_o = Signal(data_size) # The data linked to the matched tag + # Tag matched many ways in the given set + self.multiple_hit = Signal(1) + self.data_o = Signal(data_size) # The data linked to the matched tag def check_tags(self, m): """ Validate the tags in the selected set. If one and only one @@ -152,17 +155,17 @@ class SetAssociativeCache(Elaboratable): def write_entry(self, m): if not self.lfsr_mode: - m.d.comb += [# set cset (mem address) into PLRU - self.plru.plru_tree.eq(self.plru_array[self.cset]), - # and connect plru to encoder for write - self.encoder.i.eq(self.plru.replace_en_o) - ] + m.d.comb += [ # set cset (mem address) into PLRU + self.plru.plru_tree.eq(self.plru_array[self.cset]), + # and connect plru to encoder for write + self.encoder.i.eq(self.plru.replace_en_o) + ] write_port = self.mem_array[self.encoder.o].w else: # use the LFSR to generate a random(ish) one of the mem array - lfsr_output = Signal(max=self.way_count) - lfsr_random = Signal(max=self.way_count) - m.d.comb += lfsr_output.eq(self.lfsr.state) # lose some bits + lfsr_output = Signal(range(self.way_count)) + lfsr_random = Signal(range(self.way_count)) + m.d.comb += lfsr_output.eq(self.lfsr.state) # lose some bits # address too big, limit to range of array m.d.comb += lfsr_random.eq(Mux(lfsr_output > self.way_count, lfsr_output - self.way_count, @@ -182,7 +185,7 @@ class SetAssociativeCache(Elaboratable): with m.State("READY"): m.d.comb += self.ready.eq(0) self.write_entry(m) - m.next ="FINISHED_WRITE" + m.next = "FINISHED_WRITE" with m.State("FINISHED_WRITE"): m.d.comb += self.ready.eq(1) if not self.lfsr_mode: @@ -190,7 +193,6 @@ class SetAssociativeCache(Elaboratable): m.d.sync += plru_entry.eq(self.plru.plru_tree_o) m.next = "READY" - def elaborate(self, platform=None): m = Module() @@ -236,8 +238,8 @@ class SetAssociativeCache(Elaboratable): m.d.comb += [mem.cset.eq(self.cset), mem.tag.eq(self.tag), mem.data_i.eq(self.data_i), - write_port.en.eq(0), # default: disable write - ] + write_port.en.eq(0), # default: disable write + ] # ---- # Commands: READ/WRITE/TODO # ---- diff --git a/src/soc/TLB/TLB.py b/src/soc/TLB/TLB.py index 98c9af72..a3c02247 100644 --- a/src/soc/TLB/TLB.py +++ b/src/soc/TLB/TLB.py @@ -11,6 +11,7 @@ from nmigen.cli import main from .PermissionValidator import PermissionValidator from .Cam import Cam + class TLB(Elaboratable): def __init__(self, asid_size, vma_size, pte_size, L1_size): """ Arguments @@ -28,26 +29,27 @@ class TLB(Elaboratable): self.state = 0 # L1 Cache Modules self.cam_L1 = Cam(vma_size, L1_size) - self.mem_L1 = Memory(asid_size + pte_size, L1_size) + self.mem_L1 = Memory(width=asid_size + pte_size, depth=L1_size) # Permission Validator self.perm_validator = PermissionValidator(asid_size, pte_size) # Inputs - self.supermode = Signal(1) # Supervisor Mode - self.super_access = Signal(1) # Supervisor Access - self.command = Signal(2) # 00=None, 01=Search, 10=Write L1, 11=Write L2 - self.xwr = Signal(3) # Execute, Write, Read - self.mode = Signal(4) # 4 bits for access to Sv48 on Rv64 - self.address_L1 = Signal(max=L1_size) - self.asid = Signal(asid_size) # Address Space IDentifier (ASID) - self.vma = Signal(vma_size) # Virtual Memory Address (VMA) - self.pte_in = Signal(pte_size) # To be saved Page Table Entry (PTE) + self.supermode = Signal(1) # Supervisor Mode + self.super_access = Signal(1) # Supervisor Access + # 00=None, 01=Search, 10=Write L1, 11=Write L2 + self.command = Signal(2) + self.xwr = Signal(3) # Execute, Write, Read + self.mode = Signal(4) # 4 bits for access to Sv48 on Rv64 + self.address_L1 = Signal(range(L1_size)) + self.asid = Signal(asid_size) # Address Space IDentifier (ASID) + self.vma = Signal(vma_size) # Virtual Memory Address (VMA) + self.pte_in = Signal(pte_size) # To be saved Page Table Entry (PTE) # Outputs - self.hit = Signal(1) # Denotes if the VMA had a mapped PTE - self.perm_valid = Signal(1) # Denotes if the permissions are correct - self.pte_out = Signal(pte_size) # PTE that was mapped to by the VMA + self.hit = Signal(1) # Denotes if the VMA had a mapped PTE + self.perm_valid = Signal(1) # Denotes if the permissions are correct + self.pte_out = Signal(pte_size) # PTE that was mapped to by the VMA def search(self, m, read_L1, write_L1): """ searches the TLB @@ -60,7 +62,7 @@ class TLB(Elaboratable): # Match found in L1 CAM match_found = Signal(reset_less=True) m.d.comb += match_found.eq(self.cam_L1.single_match - | self.cam_L1.multiple_match) + | self.cam_L1.multiple_match) with m.If(match_found): # Memory shortcut variables mem_address = self.cam_L1.match_address @@ -116,9 +118,9 @@ class TLB(Elaboratable): # CAM_L1 Logic m.d.comb += [ self.cam_L1.write_enable.eq(1), - self.cam_L1.data_in.eq(self.vma), #data_in is sent to all entries + self.cam_L1.data_in.eq(self.vma), # data_in is sent to all entries # self.cam_L1.address_in.eq(todo) # a CAM entry needs to be selected - + ] def elaborate(self, platform): @@ -128,7 +130,7 @@ class TLB(Elaboratable): m.submodules.cam_L1 = self.cam_L1 m.submodules.read_L1 = read_L1 = self.mem_L1.read_port() m.submodules.write_L1 = write_L1 = self.mem_L1.write_port() - + # Permission Validator Submodule m.submodules.perm_valididator = self.perm_validator @@ -152,7 +154,7 @@ class TLB(Elaboratable): self.write_l1(m, read_L1, write_L1) # TODO - #with m.Case("11"): + # with m.Case("11"): # When disabled with m.Else(): @@ -160,7 +162,7 @@ class TLB(Elaboratable): self.cam_L1.enable.eq(0), # XXX TODO - self.reg_file.enable.eq(0), self.hit.eq(0), - self.perm_valid.eq(0), # XXX TODO, check this + self.perm_valid.eq(0), # XXX TODO, check this self.pte_out.eq(0) ] return m @@ -168,8 +170,8 @@ class TLB(Elaboratable): if __name__ == '__main__': tlb = TLB(15, 36, 64, 4) - main(tlb, ports=[ tlb.supermode, tlb.super_access, tlb.command, - tlb.xwr, tlb.mode, tlb.address_L1, tlb.asid, - tlb.vma, tlb.pte_in, - tlb.hit, tlb.perm_valid, tlb.pte_out, - ] + tlb.cam_L1.ports()) + main(tlb, ports=[tlb.supermode, tlb.super_access, tlb.command, + tlb.xwr, tlb.mode, tlb.address_L1, tlb.asid, + tlb.vma, tlb.pte_in, + tlb.hit, tlb.perm_valid, tlb.pte_out, + ] + tlb.cam_L1.ports()) diff --git a/src/soc/TLB/ariane/test/test_plru.py b/src/soc/TLB/ariane/test/test_plru.py index 68dcfa58..9222d796 100644 --- a/src/soc/TLB/ariane/test/test_plru.py +++ b/src/soc/TLB/ariane/test/test_plru.py @@ -1,14 +1,12 @@ import sys -sys.path.append("../src") -sys.path.append("../../../TestUtil") - -from TLB.ariane.plru import PLRU - +from soc.TLB.ariane.plru import PLRU from nmigen.compat.sim import run_simulation + def tbench(dut): yield + if __name__ == "__main__": dut = PLRU(4) run_simulation(dut, tbench(dut), vcd_name="test_plru.vcd") diff --git a/src/soc/TLB/ariane/test/test_ptw.py b/src/soc/TLB/ariane/test/test_ptw.py index b5deb28b..39697566 100644 --- a/src/soc/TLB/ariane/test/test_ptw.py +++ b/src/soc/TLB/ariane/test/test_ptw.py @@ -1,24 +1,20 @@ -import sys -sys.path.append("../src") -sys.path.append("../../../TestUtil") - from nmigen.compat.sim import run_simulation - -from TLB.ariane.ptw import PTW, PTE +from soc.TLB.ariane.ptw import PTW, PTE # unit was changed, test needs to be changed + def tbench(dut): addr = 0x8000000 #pte = PTE() - #yield pte.v.eq(1) - #yield pte.r.eq(1) + # yield pte.v.eq(1) + # yield pte.r.eq(1) yield dut.req_port_i.data_gnt.eq(1) yield dut.req_port_i.data_rvalid.eq(1) - yield dut.req_port_i.data_rdata.eq(0x43)#pte.flatten()) + yield dut.req_port_i.data_rdata.eq(0x43) # pte.flatten()) # data lookup yield dut.en_ld_st_translation_i.eq(1) @@ -56,7 +52,8 @@ def tbench(dut): yield dut.mxr_i.eq(0x1) yield dut.req_port_i.data_gnt.eq(1) yield dut.req_port_i.data_rvalid.eq(1) - yield dut.req_port_i.data_rdata.eq(0x41 | (addr>>12)<<10)#pte.flatten()) + # pte.flatten()) + yield dut.req_port_i.data_rdata.eq(0x41 | (addr >> 12) << 10) yield dut.en_ld_st_translation_i.eq(1) yield dut.asid_i.eq(1) @@ -86,7 +83,6 @@ def tbench(dut): yield yield - # instruction lookup yield dut.en_ld_st_translation_i.eq(0) yield dut.enable_translation_i.eq(1) @@ -126,5 +122,6 @@ def test_ptw(): run_simulation(dut, tbench(dut), vcd_name="test_ptw.vcd") print("PTW Unit Test Success") + if __name__ == "__main__": test_ptw() diff --git a/src/soc/TLB/ariane/test/test_tlb.py b/src/soc/TLB/ariane/test/test_tlb.py index b94438ff..e1b17b8b 100644 --- a/src/soc/TLB/ariane/test/test_tlb.py +++ b/src/soc/TLB/ariane/test/test_tlb.py @@ -1,14 +1,11 @@ -import sys -sys.path.append("../src") -sys.path.append("../../../TestUtil") - from nmigen.compat.sim import run_simulation -from TLB.ariane.tlb import TLB +from soc.TLB.ariane.tlb import TLB + def set_vaddr(addr): yield dut.lu_vaddr_i.eq(addr) - yield dut.update_i.vpn.eq(addr>>12) + yield dut.update_i.vpn.eq(addr >> 12) def tbench(dut): diff --git a/src/soc/TLB/ariane/test/test_tlb_content.py b/src/soc/TLB/ariane/test/test_tlb_content.py index 145ded7d..1bc60d88 100644 --- a/src/soc/TLB/ariane/test/test_tlb_content.py +++ b/src/soc/TLB/ariane/test/test_tlb_content.py @@ -1,13 +1,10 @@ -import sys -sys.path.append("../src") -sys.path.append("../../../TestUtil") - from nmigen.compat.sim import run_simulation -from TLB.ariane.tlb_content import TLBContent -from TestUtil.test_helper import assert_op, assert_eq +from soc.TLB.ariane.tlb_content import TLBContent +from soc.TestUtil.test_helper import assert_op, assert_eq + -def update(dut,a,t,g,m): +def update(dut, a, t, g, m): yield dut.replace_en_i.eq(1) yield dut.update_i.valid.eq(1) yield dut.update_i.is_512G.eq(t) @@ -17,47 +14,50 @@ def update(dut,a,t,g,m): yield yield -def check_hit(dut,hit,pagesize): + +def check_hit(dut, hit, pagesize): hit_d = yield dut.lu_hit_o assert_eq("hit", hit_d, hit) if(hit): - if(pagesize=="t"): + if(pagesize == "t"): hitp = yield dut.lu_is_512G_o assert_eq("lu_is_512G_o", hitp, 1) - elif(pagesize=="g"): + elif(pagesize == "g"): hitp = yield dut.lu_is_1G_o assert_eq("lu_is_1G_o", hitp, 1) - elif(pagesize=="m"): + elif(pagesize == "m"): hitp = yield dut.lu_is_2M_o assert_eq("lu_is_2M_o", hitp, 1) -def addr(a,b,c,d): - return a | b << 9 | c << 18 | d << 27 - + +def addr(a, b, c, d): + return a | b << 9 | c << 18 | d << 27 + + def tbench(dut): yield dut.vpn0.eq(0x0A) yield dut.vpn1.eq(0x0B) yield dut.vpn2.eq(0x0C) yield dut.vpn3.eq(0x0D) - yield from update(dut,addr(0xFF,0xFF,0xFF,0x0D),1,0,0) - yield from check_hit(dut,1,"t") - - yield from update(dut,addr(0xFF,0xFF,0x0C,0x0D),0,1,0) - yield from check_hit(dut,1,"g") - - yield from update(dut,addr(0xFF,0x0B,0x0C,0x0D),0,0,1) - yield from check_hit(dut,1,"m") - - yield from update(dut,addr(0x0A,0x0B,0x0C,0x0D),0,0,0) - yield from check_hit(dut,1,"") - - yield from update(dut,addr(0xAA,0xBB,0xCC,0xDD),0,0,0) - yield from check_hit(dut,0,"miss") - + yield from update(dut, addr(0xFF, 0xFF, 0xFF, 0x0D), 1, 0, 0) + yield from check_hit(dut, 1, "t") + + yield from update(dut, addr(0xFF, 0xFF, 0x0C, 0x0D), 0, 1, 0) + yield from check_hit(dut, 1, "g") + + yield from update(dut, addr(0xFF, 0x0B, 0x0C, 0x0D), 0, 0, 1) + yield from check_hit(dut, 1, "m") + + yield from update(dut, addr(0x0A, 0x0B, 0x0C, 0x0D), 0, 0, 0) + yield from check_hit(dut, 1, "") + + yield from update(dut, addr(0xAA, 0xBB, 0xCC, 0xDD), 0, 0, 0) + yield from check_hit(dut, 0, "miss") + if __name__ == "__main__": - dut = TLBContent(4,4) + dut = TLBContent(4, 4) # run_simulation(dut, tbench(dut), vcd_name="test_tlb_content.vcd") print("TLBContent Unit Test Success") diff --git a/src/soc/TLB/ariane/tlb.py b/src/soc/TLB/ariane/tlb.py index cf4af57a..72b67a2d 100644 --- a/src/soc/TLB/ariane/tlb.py +++ b/src/soc/TLB/ariane/tlb.py @@ -29,12 +29,13 @@ from nmigen import Signal, Module, Cat, Const, Array, Elaboratable from nmigen.cli import verilog, rtlil from nmigen.lib.coding import Encoder -from TLB.ariane.ptw import TLBUpdate, PTE, ASID_WIDTH -from TLB.ariane.plru import PLRU -from TLB.ariane.tlb_content import TLBContent +from soc.TLB.ariane.ptw import TLBUpdate, PTE, ASID_WIDTH +from soc.TLB.ariane.plru import PLRU +from soc.TLB.ariane.tlb_content import TLBContent TLB_ENTRIES = 8 + class TLB(Elaboratable): def __init__(self, tlb_entries=8, asid_width=8): self.tlb_entries = tlb_entries @@ -57,21 +58,21 @@ class TLB(Elaboratable): def elaborate(self, platform): m = Module() - vpn3 = Signal(9) #FIXME unused signal + vpn3 = Signal(9) # FIXME unused signal vpn2 = Signal(9) vpn1 = Signal(9) vpn0 = Signal(9) - #------------- + # ------------- # Translation - #------------- + # ------------- # SV48 defines four levels of page tables - m.d.comb += [ vpn0.eq(self.lu_vaddr_i[12:21]), - vpn1.eq(self.lu_vaddr_i[21:30]), - vpn2.eq(self.lu_vaddr_i[30:39]), - vpn3.eq(self.lu_vaddr_i[39:48]), ### FIXME - ] + m.d.comb += [vpn0.eq(self.lu_vaddr_i[12:21]), + vpn1.eq(self.lu_vaddr_i[21:30]), + vpn2.eq(self.lu_vaddr_i[30:39]), + vpn3.eq(self.lu_vaddr_i[39:48]), # FIXME + ] tc = [] for i in range(self.tlb_entries): @@ -85,13 +86,13 @@ class TLB(Elaboratable): tlc.vpn2.eq(vpn2), # TODO 4th tlc.flush_i.eq(self.flush_i), - #tlc.update_i.eq(self.update_i), + # tlc.update_i.eq(self.update_i), tlc.lu_asid_i.eq(self.lu_asid_i)] tc = Array(tc) - #-------------- + # -------------- # Select hit - #-------------- + # -------------- # use Encoder to select hit index # XXX TODO: assert that there's only one valid entry (one lu_hit) @@ -101,23 +102,23 @@ class TLB(Elaboratable): hits = [] for i in range(self.tlb_entries): hits.append(tc[i].lu_hit_o) - m.d.comb += hitsel.i.eq(Cat(*hits)) # (goes into plru as well) + m.d.comb += hitsel.i.eq(Cat(*hits)) # (goes into plru as well) idx = hitsel.o active = Signal(reset_less=True) m.d.comb += active.eq(~hitsel.n) with m.If(active): # active hit, send selected as output - m.d.comb += [ self.lu_is_512G_o.eq(tc[idx].lu_is_512G_o), - self.lu_is_1G_o.eq(tc[idx].lu_is_1G_o), - self.lu_is_2M_o.eq(tc[idx].lu_is_2M_o), - self.lu_hit_o.eq(1), - self.lu_content_o.flatten().eq(tc[idx].lu_content_o), - ] - - #-------------- + m.d.comb += [self.lu_is_512G_o.eq(tc[idx].lu_is_512G_o), + self.lu_is_1G_o.eq(tc[idx].lu_is_1G_o), + self.lu_is_2M_o.eq(tc[idx].lu_is_2M_o), + self.lu_hit_o.eq(1), + self.lu_content_o.flatten().eq(tc[idx].lu_content_o), + ] + + # -------------- # PLRU. - #-------------- + # -------------- p = PLRU(self.tlb_entries) plru_tree = Signal(p.TLBSZ) @@ -128,15 +129,15 @@ class TLB(Elaboratable): en = [] for i in range(self.tlb_entries): en.append(tc[i].replace_en_i) - m.d.comb += [Cat(*en).eq(p.replace_en_o), # output from PLRU into tags + m.d.comb += [Cat(*en).eq(p.replace_en_o), # output from PLRU into tags p.lu_hit.eq(hitsel.i), p.lu_access_i.eq(self.lu_access_i), p.plru_tree.eq(plru_tree)] m.d.sync += plru_tree.eq(p.plru_tree_o) - #-------------- + # -------------- # Sanity checks - #-------------- + # -------------- assert (self.tlb_entries % 2 == 0) and (self.tlb_entries > 1), \ "TLB size must be a multiple of 2 and greater than 1" @@ -163,13 +164,13 @@ class TLB(Elaboratable): def ports(self): return [self.flush_i, self.lu_access_i, - self.lu_asid_i, self.lu_vaddr_i, - self.lu_is_2M_o, self.lu_1G_o, self.lu_is_512G_o, self.lu_hit_o + self.lu_asid_i, self.lu_vaddr_i, + self.lu_is_2M_o, self.lu_1G_o, self.lu_is_512G_o, self.lu_hit_o ] + self.lu_content_o.ports() + self.update_i.ports() + if __name__ == '__main__': tlb = TLB() vl = rtlil.convert(tlb, ports=tlb.ports()) with open("test_tlb.il", "w") as f: f.write(vl) - diff --git a/src/soc/TLB/ariane/tlb_content.py b/src/soc/TLB/ariane/tlb_content.py index 3384c885..bfd17c13 100644 --- a/src/soc/TLB/ariane/tlb_content.py +++ b/src/soc/TLB/ariane/tlb_content.py @@ -1,21 +1,21 @@ from nmigen import Signal, Module, Cat, Const, Elaboratable -from TLB.ariane.ptw import TLBUpdate, PTE +from soc.TLB.ariane.ptw import TLBUpdate, PTE class TLBEntry: def __init__(self, asid_width): - self.asid = Signal(asid_width,name="ent_asid") + self.asid = Signal(asid_width, name="ent_asid") # SV48 defines four levels of page tables - self.vpn0 = Signal(9,name="ent_vpn0") - self.vpn1 = Signal(9,name="ent_vpn1") - self.vpn2 = Signal(9,name="ent_vpn2") - self.vpn3 = Signal(9,name="ent_vpn3") + self.vpn0 = Signal(9, name="ent_vpn0") + self.vpn1 = Signal(9, name="ent_vpn1") + self.vpn2 = Signal(9, name="ent_vpn2") + self.vpn3 = Signal(9, name="ent_vpn3") self.is_2M = Signal(name="ent_is_2M") self.is_1G = Signal(name="ent_is_1G") self.is_512G = Signal(name="ent_is_512G") self.valid = Signal(name="ent_valid") - + def flatten(self): return Cat(*self.ports()) @@ -25,7 +25,7 @@ class TLBEntry: def ports(self): return [self.asid, self.vpn0, self.vpn1, self.vpn2, self.is_2M, self.is_1G, self.valid] - + class TLBContent(Elaboratable): def __init__(self, pte_width, asid_width): @@ -38,8 +38,8 @@ class TLBContent(Elaboratable): self.vpn2 = Signal(9) self.vpn1 = Signal(9) self.vpn0 = Signal(9) - self.replace_en_i = Signal() # replace the following entry, - # set by replacement strategy + self.replace_en_i = Signal() # replace the following entry, + # set by replacement strategy # Lookup signals self.lu_asid_i = Signal(asid_width) self.lu_content_o = Signal(pte_width) @@ -52,8 +52,7 @@ class TLBContent(Elaboratable): m = Module() tags = TLBEntry(self.asid_width) - - + content = Signal(self.pte_width) m.d.comb += [self.lu_hit_o.eq(0), @@ -72,40 +71,39 @@ class TLBContent(Elaboratable): #tags_2M = Signal(reset_less=True) vpn0_or_2M = Signal(reset_less=True) - + m.d.comb += [ - #compare asid and vpn* - asid_ok.eq(tags.asid == self.lu_asid_i), - vpn3_ok.eq(tags.vpn3 == self.vpn3), - vpn2_ok.eq(tags.vpn2 == self.vpn2), - vpn1_ok.eq(tags.vpn1 == self.vpn1), - vpn0_ok.eq(tags.vpn0 == self.vpn0), - vpn0_or_2M.eq(tags.is_2M | vpn0_ok) + # compare asid and vpn* + asid_ok.eq(tags.asid == self.lu_asid_i), + vpn3_ok.eq(tags.vpn3 == self.vpn3), + vpn2_ok.eq(tags.vpn2 == self.vpn2), + vpn1_ok.eq(tags.vpn1 == self.vpn1), + vpn0_ok.eq(tags.vpn0 == self.vpn0), + vpn0_or_2M.eq(tags.is_2M | vpn0_ok) ] - - + with m.If(asid_ok & tags.valid): # first level, only vpn3 needs to match - with m.If (tags.is_512G & vpn3_ok): - m.d.comb += [ self.lu_content_o.eq(content), - self.lu_is_512G_o.eq(1), - self.lu_hit_o.eq(1), - ] + with m.If(tags.is_512G & vpn3_ok): + m.d.comb += [self.lu_content_o.eq(content), + self.lu_is_512G_o.eq(1), + self.lu_hit_o.eq(1), + ] # second level , second level vpn2 and vpn3 need to match - with m.Elif (tags.is_1G & vpn2_ok & vpn3_ok): - m.d.comb += [ self.lu_content_o.eq(content), - self.lu_is_1G_o.eq(1), - self.lu_hit_o.eq(1), - ] + with m.Elif(tags.is_1G & vpn2_ok & vpn3_ok): + m.d.comb += [self.lu_content_o.eq(content), + self.lu_is_1G_o.eq(1), + self.lu_hit_o.eq(1), + ] # not a giga page hit nor a tera page hit so check further with m.Elif(vpn1_ok): # this could be a 2 mega page hit or a 4 kB hit # output accordingly with m.If(vpn0_or_2M): - m.d.comb += [ self.lu_content_o.eq(content), - self.lu_is_2M_o.eq(tags.is_2M), - self.lu_hit_o.eq(1), - ] + m.d.comb += [self.lu_content_o.eq(content), + self.lu_is_2M_o.eq(tags.is_2M), + self.lu_hit_o.eq(1), + ] # ------------------ # Update or Flush # ------------------ @@ -115,31 +113,31 @@ class TLBContent(Elaboratable): m.d.comb += replace_valid.eq(self.update_i.valid & self.replace_en_i) # flush - with m.If (self.flush_i): + with m.If(self.flush_i): # invalidate (flush) conditions: all if zero or just this ASID - with m.If (self.lu_asid_i == Const(0, self.asid_width) | + with m.If(self.lu_asid_i == Const(0, self.asid_width) | (self.lu_asid_i == tags.asid)): m.d.sync += tags.valid.eq(0) # normal replacement with m.Elif(replace_valid): - m.d.sync += [ # update tag array - tags.asid.eq(self.update_i.asid), - tags.vpn3.eq(self.update_i.vpn[27:36]), - tags.vpn2.eq(self.update_i.vpn[18:27]), - tags.vpn1.eq(self.update_i.vpn[9:18]), - tags.vpn0.eq(self.update_i.vpn[0:9]), - tags.is_512G.eq(self.update_i.is_512G), - tags.is_1G.eq(self.update_i.is_1G), - tags.is_2M.eq(self.update_i.is_2M), - tags.valid.eq(1), - # and content as well - content.eq(self.update_i.content.flatten()) - ] + m.d.sync += [ # update tag array + tags.asid.eq(self.update_i.asid), + tags.vpn3.eq(self.update_i.vpn[27:36]), + tags.vpn2.eq(self.update_i.vpn[18:27]), + tags.vpn1.eq(self.update_i.vpn[9:18]), + tags.vpn0.eq(self.update_i.vpn[0:9]), + tags.is_512G.eq(self.update_i.is_512G), + tags.is_1G.eq(self.update_i.is_1G), + tags.is_2M.eq(self.update_i.is_2M), + tags.valid.eq(1), + # and content as well + content.eq(self.update_i.content.flatten()) + ] return m def ports(self): return [self.flush_i, - self.lu_asid_i, - self.lu_is_2M_o, self.lu_is_1G_o,self.lu_is_512G_o, self.lu_hit_o, + self.lu_asid_i, + self.lu_is_2M_o, self.lu_is_1G_o, self.lu_is_512G_o, self.lu_hit_o, ] + self.update_i.content.ports() + self.update_i.ports() diff --git a/src/soc/TLB/test/test_LFSR2.py b/src/soc/TLB/test/test_LFSR2.py index c05f55b7..33208f83 100644 --- a/src/soc/TLB/test/test_LFSR2.py +++ b/src/soc/TLB/test/test_LFSR2.py @@ -1,6 +1,6 @@ # SPDX-License-Identifier: LGPL-2.1-or-later # See Notices.txt for copyright information -from TLB.LFSR import LFSR, LFSRPolynomial, LFSR_POLY_3 +from soc.TLB.LFSR import LFSR, LFSRPolynomial, LFSR_POLY_3 from nmigen.back.pysim import Simulator, Delay, Tick import unittest @@ -32,7 +32,7 @@ class TestLFSR(unittest.TestCase): vcd_file=open("Waveforms/test_LFSR2.vcd", "w"), gtkw_file=open("Waveforms/test_LFSR2.gtkw", "w"), traces=traces) as sim: - sim.add_clock(1e-6, 0.25e-6) + sim.add_clock(1e-6, phase=0.25e-6) delay = Delay(1e-7) def async_process(): @@ -67,4 +67,3 @@ class TestLFSR(unittest.TestCase): sim.add_process(async_process) sim.run() - diff --git a/src/soc/TLB/test/test_address_encoder.py b/src/soc/TLB/test/test_address_encoder.py index 0aad35b4..70d435d6 100644 --- a/src/soc/TLB/test/test_address_encoder.py +++ b/src/soc/TLB/test/test_address_encoder.py @@ -1,6 +1,6 @@ from nmigen.compat.sim import run_simulation -from TLB.AddressEncoder import AddressEncoder -from TestUtil.test_helper import assert_eq, assert_ne, assert_op +from soc.TLB.AddressEncoder import AddressEncoder +from soc.TestUtil.test_helper import assert_eq, assert_ne, assert_op # This function allows for the easy setting of values to the AddressEncoder @@ -16,6 +16,8 @@ def set_encoder(dut, i): # dut: The AddressEncoder being tested # sm (Single Match): The expected match result # op (Operation): (0 => ==), (1 => !=) + + def check_single_match(dut, sm, op): out_sm = yield dut.single_match assert_op("Single Match", out_sm, sm, op) @@ -25,6 +27,8 @@ def check_single_match(dut, sm, op): # dut: The AddressEncoder being tested # mm (Multiple Match): The expected match result # op (Operation): (0 => ==), (1 => !=) + + def check_multiple_match(dut, mm, op): out_mm = yield dut.multiple_match assert_op("Multiple Match", out_mm, mm, op) @@ -34,6 +38,8 @@ def check_multiple_match(dut, mm, op): # dut: The AddressEncoder being tested # o (Output): The expected output # op (Operation): (0 => ==), (1 => !=) + + def check_output(dut, o, op): out_o = yield dut.o assert_op("Output", out_o, o, op) @@ -47,11 +53,14 @@ def check_output(dut, o, op): # ss_op (Operation): Operation for the match assertion (0 => ==), (1 => !=) # mm_op (Operation): Operation for the match assertion (0 => ==), (1 => !=) # o_op (Operation): Operation for the match assertion (0 => ==), (1 => !=) + + def check_all(dut, sm, mm, o, sm_op, mm_op, o_op): yield from check_single_match(dut, sm, sm_op) yield from check_multiple_match(dut, mm, mm_op) yield from check_output(dut, o, o_op) + def tbench(dut): # Check invalid input in_val = 0b000 @@ -95,11 +104,13 @@ def tbench(dut): yield from set_encoder(dut, in_val) yield from check_all(dut, single_match, multiple_match, output, 0, 0, 0) + def test_addr(): dut = AddressEncoder(4) - run_simulation(dut, tbench(dut), + run_simulation(dut, tbench(dut), vcd_name="Waveforms/test_address_encoder.vcd") print("AddressEncoder Unit Test Success") + if __name__ == "__main__": test_addr() diff --git a/src/soc/TLB/test/test_cam.py b/src/soc/TLB/test/test_cam.py index f11c48ad..d11cd974 100644 --- a/src/soc/TLB/test/test_cam.py +++ b/src/soc/TLB/test/test_cam.py @@ -1,8 +1,8 @@ from nmigen.compat.sim import run_simulation -from TLB.Cam import Cam +from soc.TLB.Cam import Cam -from TestUtil.test_helper import assert_eq, assert_ne, assert_op +from soc.TestUtil.test_helper import assert_eq, assert_ne, assert_op # This function allows for the easy setting of values to the Cam # Arguments: @@ -11,6 +11,8 @@ from TestUtil.test_helper import assert_eq, assert_ne, assert_op # we (Write Enable): Whether the Cam will write on the next cycle # a (Address): Where the data will be written if write enable is high # d (Data): Either what we are looking for or will write to the address + + def set_cam(dut, e, we, a, d): yield dut.enable.eq(e) yield dut.write_enable.eq(we) @@ -23,6 +25,8 @@ def set_cam(dut, e, we, a, d): # dut: The Cam being tested # mm (Multiple Match): The expected match result # op (Operation): (0 => ==), (1 => !=) + + def check_multiple_match(dut, mm, op): out_mm = yield dut.multiple_match assert_op("Multiple Match", out_mm, mm, op) @@ -32,6 +36,8 @@ def check_multiple_match(dut, mm, op): # dut: The Cam being tested # sm (Single Match): The expected match result # op (Operation): (0 => ==), (1 => !=) + + def check_single_match(dut, sm, op): out_sm = yield dut.single_match assert_op("Single Match", out_sm, sm, op) @@ -41,6 +47,8 @@ def check_single_match(dut, sm, op): # dut: The Cam being tested # ma (Match Address): The expected match result # op (Operation): (0 => ==), (1 => !=) + + def check_match_address(dut, ma, op): out_ma = yield dut.match_address assert_op("Match Address", out_ma, ma, op) @@ -54,11 +62,14 @@ def check_match_address(dut, ma, op): # ss_op (Operation): Operation for the match assertion (0 => ==), (1 => !=) # mm_op (Operation): Operation for the match assertion (0 => ==), (1 => !=) # ma_op (Operation): Operation for the address assertion (0 => ==), (1 => !=) + + def check_all(dut, mm, sm, ma, mm_op, sm_op, ma_op): yield from check_multiple_match(dut, mm, mm_op) yield from check_single_match(dut, sm, sm_op) yield from check_match_address(dut, ma, ma_op) + def tbench(dut): # NA enable = 0 @@ -170,7 +181,7 @@ def tbench(dut): single_match = 0 yield from set_cam(dut, enable, write_enable, address, data) yield - yield from check_all(dut, multiple_match, single_match, address,0,0,0) + yield from check_all(dut, multiple_match, single_match, address, 0, 0, 0) # Verify read_warning is not caused # Write Entry 0 @@ -202,5 +213,6 @@ def test_cam(): run_simulation(dut, tbench(dut), vcd_name="Waveforms/test_cam.vcd") print("Cam Unit Test Success") + if __name__ == "__main__": test_cam() diff --git a/src/soc/TLB/test/test_cam_entry.py b/src/soc/TLB/test/test_cam_entry.py index 43b699d2..961445b6 100644 --- a/src/soc/TLB/test/test_cam_entry.py +++ b/src/soc/TLB/test/test_cam_entry.py @@ -1,13 +1,15 @@ from nmigen.compat.sim import run_simulation -from TestUtil.test_helper import assert_eq, assert_ne, assert_op -from TLB.CamEntry import CamEntry +from soc.TestUtil.test_helper import assert_eq, assert_ne, assert_op +from soc.TLB.CamEntry import CamEntry # This function allows for the easy setting of values to the Cam Entry # Arguments: # dut: The CamEntry being tested # c (command): NA (0), Read (1), Write (2), Reserve (3) # d (data): The data to be set + + def set_cam_entry(dut, c, d): # Write desired values yield dut.command.eq(c) @@ -23,6 +25,8 @@ def set_cam_entry(dut, c, d): # dut: The CamEntry being tested # d (Data): The expected data # op (Operation): (0 => ==), (1 => !=) + + def check_data(dut, d, op): out_d = yield dut.data assert_op("Data", out_d, d, op) @@ -32,6 +36,8 @@ def check_data(dut, d, op): # dut: The CamEntry being tested # m (Match): The expected match # op (Operation): (0 => ==), (1 => !=) + + def check_match(dut, m, op): out_m = yield dut.match assert_op("Match", out_m, m, op) @@ -43,6 +49,8 @@ def check_match(dut, m, op): # m (match): The expected match # d_op (Operation): Operation for the data assertion (0 => ==), (1 => !=) # m_op (Operation): Operation for the match assertion (0 => ==), (1 => !=) + + def check_all(dut, d, m, d_op, m_op): yield from check_data(dut, d, d_op) yield from check_match(dut, m, m_op) @@ -51,6 +59,8 @@ def check_all(dut, d, m, d_op, m_op): # It is done by writing and then reading various combinations of key/data pairs # and reading the results with varying keys to verify the resulting stored # data is correct. + + def tbench(dut): # Check write command = 2 @@ -107,4 +117,3 @@ def test_camentry(): if __name__ == "__main__": test_camentry() - diff --git a/src/soc/TLB/test/test_permission_validator.py b/src/soc/TLB/test/test_permission_validator.py index 81873d79..b52b5459 100644 --- a/src/soc/TLB/test/test_permission_validator.py +++ b/src/soc/TLB/test/test_permission_validator.py @@ -1,8 +1,8 @@ from nmigen.compat.sim import run_simulation -from TLB.PermissionValidator import PermissionValidator +from soc.TLB.PermissionValidator import PermissionValidator -from TestUtil.test_helper import assert_op +from soc.TestUtil.test_helper import assert_op def set_validator(dut, d, xwr, sm, sa, asid): @@ -13,10 +13,12 @@ def set_validator(dut, d, xwr, sm, sa, asid): yield dut.asid.eq(asid) yield + def check_valid(dut, v, op): out_v = yield dut.valid assert_op("Valid", out_v, v, op) + def tbench(dut): # 80 bits represented. Ignore the MSB as it will be truncated # ASID is bits first 4 hex values (bits 64 - 78) @@ -138,9 +140,11 @@ def tbench(dut): def test_permv(): - dut = PermissionValidator(15, 64); - run_simulation(dut, tbench(dut), vcd_name="Waveforms/test_permission_validator.vcd") + dut = PermissionValidator(15, 64) + run_simulation(dut, tbench( + dut), vcd_name="Waveforms/test_permission_validator.vcd") print("PermissionValidator Unit Test Success") + if __name__ == "__main__": test_permv() diff --git a/src/soc/TLB/test/test_pte_entry.py b/src/soc/TLB/test/test_pte_entry.py index 5c0c34dc..51b3dcf0 100644 --- a/src/soc/TLB/test/test_pte_entry.py +++ b/src/soc/TLB/test/test_pte_entry.py @@ -1,45 +1,55 @@ from nmigen.compat.sim import run_simulation -from TLB.PteEntry import PteEntry +from soc.TLB.PteEntry import PteEntry + +from soc.TestUtil.test_helper import assert_op -from TestUtil.test_helper import assert_op def set_entry(dut, i): yield dut.i.eq(i) yield + def check_dirty(dut, d, op): out_d = yield dut.d assert_op("Dirty", out_d, d, op) + def check_accessed(dut, a, op): out_a = yield dut.a assert_op("Accessed", out_a, a, op) + def check_global(dut, o, op): out = yield dut.g assert_op("Global", out, o, op) + def check_user(dut, o, op): out = yield dut.u assert_op("User Mode", out, o, op) + def check_xwr(dut, o, op): out = yield dut.xwr assert_op("XWR", out, o, op) + def check_asid(dut, o, op): out = yield dut.asid assert_op("ASID", out, o, op) + def check_pte(dut, o, op): out = yield dut.pte assert_op("ASID", out, o, op) + def check_valid(dut, v, op): out_v = yield dut.v assert_op("Valid", out_v, v, op) + def check_all(dut, d, a, g, u, xwr, v, asid, pte): yield from check_dirty(dut, d, 0) yield from check_accessed(dut, a, 0) @@ -50,6 +60,7 @@ def check_all(dut, d, a, g, u, xwr, v, asid, pte): yield from check_pte(dut, pte, 0) yield from check_valid(dut, v, 0) + def tbench(dut): # 80 bits represented. Ignore the MSB as it will be truncated # ASID is bits first 4 hex values (bits 64 - 78) @@ -94,9 +105,10 @@ def tbench(dut): def test_pteentry(): - dut = PteEntry(15, 64); + dut = PteEntry(15, 64) run_simulation(dut, tbench(dut), vcd_name="Waveforms/test_pte_entry.vcd") print("PteEntry Unit Test Success") + if __name__ == "__main__": test_pteentry() diff --git a/src/soc/TLB/test/test_set_associative_cache.py b/src/soc/TLB/test/test_set_associative_cache.py index 0641b556..edec055b 100644 --- a/src/soc/TLB/test/test_set_associative_cache.py +++ b/src/soc/TLB/test/test_set_associative_cache.py @@ -1,8 +1,9 @@ from nmigen.compat.sim import run_simulation -from TLB.SetAssociativeCache import SetAssociativeCache +from soc.TLB.SetAssociativeCache import SetAssociativeCache + +from soc.TestUtil.test_helper import assert_eq, assert_ne, assert_op -from TestUtil.test_helper import assert_eq, assert_ne, assert_op def set_sac(dut, e, c, s, t, d): yield dut.enable.eq(e) @@ -12,6 +13,7 @@ def set_sac(dut, e, c, s, t, d): yield dut.data_i.eq(d) yield + def tbench(dut): enable = 1 command = 2 @@ -29,10 +31,13 @@ def tbench(dut): yield from set_sac(dut, enable, command, cset, tag, data) yield + def test_assoc_cache(): dut = SetAssociativeCache(4, 4, 4, 4) - run_simulation(dut, tbench(dut), vcd_name="Waveforms/test_set_associative_cache.vcd") + run_simulation(dut, tbench( + dut), vcd_name="Waveforms/test_set_associative_cache.vcd") print("Set Associative Cache Unit Test Success") + if __name__ == "__main__": test_assoc_cache() diff --git a/src/soc/TLB/test/test_tlb.py b/src/soc/TLB/test/test_tlb.py index e9cc9d69..38656623 100644 --- a/src/soc/TLB/test/test_tlb.py +++ b/src/soc/TLB/test/test_tlb.py @@ -1,55 +1,61 @@ #import tracemalloc -#tracemalloc.start() +# tracemalloc.start() from nmigen.compat.sim import run_simulation -from TLB.TLB import TLB +from soc.TLB.TLB import TLB -from TestUtil.test_helper import assert_op, assert_eq +from soc.TestUtil.test_helper import assert_op, assert_eq -#self.supermode = Signal(1) # Supervisor Mode -#self.super_access = Signal(1) # Supervisor Access -#self.command = Signal(2) # 00=None, 01=Search, 10=Write L1, 11=Write L2 -#self.xwr = Signal(3) # Execute, Write, Read -#self.mode = Signal(4) # 4 bits for access to Sv48 on Rv64 -#self.address_L1 = Signal(max=L1_size) -#self.asid = Signal(asid_size) # Address Space IDentifier (ASID) -#self.vma = Signal(vma_size) # Virtual Memory Address (VMA) -#self.pte_in = Signal(pte_size) # To be saved Page Table Entry (PTE) +# self.supermode = Signal(1) # Supervisor Mode +# self.super_access = Signal(1) # Supervisor Access +# self.command = Signal(2) # 00=None, 01=Search, 10=Write L1, 11=Write L2 +# self.xwr = Signal(3) # Execute, Write, Read +# self.mode = Signal(4) # 4 bits for access to Sv48 on Rv64 +#self.address_L1 = Signal(range(L1_size)) +# self.asid = Signal(asid_size) # Address Space IDentifier (ASID) +# self.vma = Signal(vma_size) # Virtual Memory Address (VMA) +# self.pte_in = Signal(pte_size) # To be saved Page Table Entry (PTE) # -#self.hit = Signal(1) # Denotes if the VMA had a mapped PTE -#self.perm_valid = Signal(1) # Denotes if the permissions are correct -#self.pte_out = Signal(pte_size) # PTE that was mapped to by the VMA +# self.hit = Signal(1) # Denotes if the VMA had a mapped PTE +# self.perm_valid = Signal(1) # Denotes if the permissions are correct +# self.pte_out = Signal(pte_size) # PTE that was mapped to by the VMA -COMMAND_READ=1 -COMMAND_WRITE_L1=2 +COMMAND_READ = 1 +COMMAND_WRITE_L1 = 2 # Checks the data state of the CAM entry # Arguments: # dut: The CamEntry being tested # d (Data): The expected data # op (Operation): (0 => ==), (1 => !=) + + def check_hit(dut, d): hit_d = yield dut.hit #assert_eq("hit", hit_d, d) -def test_command(dut,cmd,xwr,cycles): + +def tst_command(dut, cmd, xwr, cycles): yield dut.command.eq(cmd) yield dut.xwr.eq(xwr) - for i in range(0,cycles): + for i in range(0, cycles): yield -def test_write_L1(dut,vma,address_L1,asid,pte_in): + +def tst_write_L1(dut, vma, address_L1, asid, pte_in): yield dut.address_L1.eq(address_L1) yield dut.asid.eq(asid) yield dut.vma.eq(vma) yield dut.pte_in.eq(pte_in) - yield from test_command(dut,COMMAND_WRITE_L1,7,2) + yield from tst_command(dut, COMMAND_WRITE_L1, 7, 2) -def test_search(dut,vma,found): + +def tst_search(dut, vma, found): yield dut.vma.eq(vma) - yield from test_command(dut,COMMAND_READ,7,1) - yield from check_hit(dut,found) + yield from tst_command(dut, COMMAND_READ, 7, 1) + yield from check_hit(dut, found) + def zero(dut): yield dut.supermode.eq(0) @@ -60,21 +66,21 @@ def zero(dut): yield dut.vma.eq(0) yield dut.pte_in.eq(0) + def tbench(dut): yield from zero(dut) - yield dut.mode.eq(0xF) # enable TLB - #test hit - yield from test_write_L1(dut,0xFEEDFACE,0,0xFFFF,0xF0F0) - yield from test_search(dut,0xFEEDFACE,1) - yield from test_search(dut,0xFACEFEED,0) - + yield dut.mode.eq(0xF) # enable TLB + # test hit + yield from tst_write_L1(dut, 0xFEEDFACE, 0, 0xFFFF, 0xF0F0) + yield from tst_search(dut, 0xFEEDFACE, 1) + yield from tst_search(dut, 0xFACEFEED, 0) - def test_tlb(): - dut = TLB(15,36,64,8) + dut = TLB(15, 36, 64, 8) run_simulation(dut, tbench(dut), vcd_name="Waveforms/test_tlb.vcd") print("TLB Unit Test Success") + if __name__ == "__main__": test_tlb() diff --git a/src/soc/decoder/isa/.gitignore b/src/soc/decoder/isa/.gitignore new file mode 100644 index 00000000..38b48b3e --- /dev/null +++ b/src/soc/decoder/isa/.gitignore @@ -0,0 +1,14 @@ +/all.py +/bcd.py +/branch.py +/comparefixed.py +/condition.py +/fixedarith.py +/fixedload.py +/fixedlogical.py +/fixedshift.py +/fixedstore.py +/fixedtrap.py +/sprset.py +/stringldst.py +/system.py diff --git a/src/soc/decoder/isa/test_caller.py b/src/soc/decoder/isa/test_caller.py index bcc9a551..55dcc673 100644 --- a/src/soc/decoder/isa/test_caller.py +++ b/src/soc/decoder/isa/test_caller.py @@ -57,7 +57,7 @@ class DecoderTestCase(FHDLTestCase): initial_regs[3] = 0x1234 initial_regs[2] = 0x4321 with Program(lst) as program: - sim = self.run_test_program(program, initial_regs) + sim = self.run_tst_program(program, initial_regs) self.assertEqual(sim.gpr(1), SelectableInt(0x5555, 64)) def test_addi(self): @@ -65,7 +65,7 @@ class DecoderTestCase(FHDLTestCase): "addi 2, 0, 0x4321", "add 1, 3, 2"] with Program(lst) as program: - sim = self.run_test_program(program) + sim = self.run_tst_program(program) print(sim.gpr(1)) self.assertEqual(sim.gpr(1), SelectableInt(0x5555, 64)) @@ -75,11 +75,11 @@ class DecoderTestCase(FHDLTestCase): "stw 2, 0(1)", "lwz 3, 0(1)"] with Program(lst) as program: - sim = self.run_test_program(program) + sim = self.run_tst_program(program) print(sim.gpr(1)) self.assertEqual(sim.gpr(3), SelectableInt(0x1234, 64)) - def run_test_program(self, prog, initial_regs=[0] * 32): + def run_tst_program(self, prog, initial_regs=[0] * 32): simulator = self.run_tst(prog, initial_regs) simulator.gpr.dump() return simulator diff --git a/src/soc/decoder/pseudo/parser.py b/src/soc/decoder/pseudo/parser.py index 6ccbe96c..664cc2f7 100644 --- a/src/soc/decoder/pseudo/parser.py +++ b/src/soc/decoder/pseudo/parser.py @@ -54,7 +54,7 @@ def Assign(left, right, iea_mode): else: ls = (lower, upper, step) ls = ast.Tuple(ls) - return ast.Call(ast.Name("selectassign"), + return ast.Call(ast.Name("selectassign", ast.Load()), [left.value, ls, right], []) else: print("Assign fail") @@ -141,7 +141,7 @@ def check_concat(node): # checks if the comparison is already a concat print("func", node.func.id) if node.func.id != 'concat': return [node] - if node.keywords: # a repeated list-constant, don't optimise + if node.keywords: # a repeated list-constant, don't optimise return [node] return node.args @@ -149,16 +149,16 @@ def check_concat(node): # checks if the comparison is already a concat # identify SelectableInt pattern [something] * N # must return concat(something, repeat=N) def identify_sint_mul_pattern(p): - if p[2] != '*': # multiply + if p[2] != '*': # multiply return False - if not isinstance(p[3], ast.Constant): # rhs = Num + if not isinstance(p[3], ast.Constant): # rhs = Num return False - if not isinstance(p[1], ast.List): # lhs is a list + if not isinstance(p[1], ast.List): # lhs is a list return False l = p[1].elts - if len(l) != 1: # lhs is a list of length 1 + if len(l) != 1: # lhs is a list of length 1 return False - return True # yippee! + return True # yippee! def apply_trailer(atom, trailer): @@ -214,6 +214,7 @@ def apply_trailer(atom, trailer): # or Boolean OR # lambda Lambda expression + class PowerParser: precedence = ( @@ -229,14 +230,14 @@ class PowerParser: def __init__(self, form): self.gprs = {} form = self.sd.sigforms[form] - print (form) + print(form) formkeys = form._asdict().keys() for rname in ['RA', 'RB', 'RC', 'RT', 'RS']: self.gprs[rname] = None self.available_op_fields = set() for k in formkeys: if k not in self.gprs: - if k == 'SPR': # sigh, lower-case to not conflict + if k == 'SPR': # sigh, lower-case to not conflict k = k.lower() self.available_op_fields.add(k) self.op_fields = OrderedSet() @@ -362,18 +363,18 @@ class PowerParser: print(astor.dump_tree(p[1])) # replace GPR(x) with GPR[x] idx = p[1].args[0] - p[1] = ast.Subscript(p[1].func, idx) + p[1] = ast.Subscript(p[1].func, idx, ast.Load()) elif isinstance(p[1], ast.Call) and p[1].func.id == 'MEM': - print ("mem assign") + print("mem assign") print(astor.dump_tree(p[1])) - p[1].func.id = "memassign" # change function name to set + p[1].func.id = "memassign" # change function name to set p[1].args.append(p[3]) p[0] = p[1] - print ("mem rewrite") + print("mem rewrite") print(astor.dump_tree(p[0])) return else: - print ("help, help") + print("help, help") print(astor.dump_tree(p[1])) print("expr assign", name, p[1]) if name and name in self.gprs: @@ -410,7 +411,7 @@ class PowerParser: # auto-add-one (sigh) due to python range start = p[4] end = ast.BinOp(p[6], ast.Add(), ast.Constant(1)) - it = ast.Call(ast.Name("range"), [start, end], []) + it = ast.Call(ast.Name("range", ast.Load()), [start, end], []) p[0] = ast.For(p[2], it, p[8], []) def p_while_stmt(self, p): @@ -430,35 +431,35 @@ class PowerParser: print(astor.dump_tree(p[1])) cases = [] - current_cases = [] # for deferral + current_cases = [] # for deferral for (case, suite) in p[8]: - print ("for", case, suite) + print("for", case, suite) if suite is None: for c in case: current_cases.append(ast.Num(c)) continue - if case == 'default': # last + if case == 'default': # last break for c in case: current_cases.append(ast.Num(c)) - print ("cases", current_cases) + print("cases", current_cases) compare = ast.Compare(switchon, [ast.In()], - [ast.List(current_cases)]) + [ast.List(current_cases, ast.Load())]) current_cases = [] cases.append((compare, suite)) - print ("ended", case, current_cases) + print("ended", case, current_cases) if case == 'default': if current_cases: compare = ast.Compare(switchon, [ast.In()], - [ast.List(current_cases)]) + [ast.List(current_cases, ast.Load())]) cases.append((compare, suite)) cases.append((None, suite)) cases.reverse() res = [] for compare, suite in cases: - print ("after rev", compare, suite) + print("after rev", compare, suite) if compare is None: assert len(res) == 0, "last case should be default" res = suite @@ -562,18 +563,18 @@ class PowerParser: if len(p) == 4: print(list(p)) if p[2] == 'u': - p[0] = ast.Call(ast.Name("gtu"), (p[1], p[3]), []) + p[0] = ast.Call(ast.Name("gtu", ast.Load()), (p[1], p[3]), []) elif p[2] == '||': l = check_concat(p[1]) + check_concat(p[3]) - p[0] = ast.Call(ast.Name("concat"), l, []) + p[0] = ast.Call(ast.Name("concat", ast.Load()), l, []) elif p[2] in ['<', '>', '=', '<=', '>=', '!=']: p[0] = binary_ops[p[2]]((p[1], p[3])) elif identify_sint_mul_pattern(p): - keywords=[ast.keyword(arg='repeat', value=p[3])] + keywords = [ast.keyword(arg='repeat', value=p[3])] l = p[1].elts - p[0] = ast.Call(ast.Name("concat"), l, keywords) + p[0] = ast.Call(ast.Name("concat", ast.Load()), l, keywords) else: p[0] = ast.BinOp(p[1], binary_ops[p[2]], p[3]) elif len(p) == 3: @@ -624,9 +625,9 @@ class PowerParser: | test """ if len(p) == 2: - p[0] = ast.List([p[1]]) + p[0] = ast.List([p[1]], ast.Load()) else: - p[0] = ast.List([p[1]] + p[3].nodes) + p[0] = ast.List([p[1]] + p[3].nodes, ast.Load()) def p_atom_tuple(self, p): """atom : LPAR testlist RPAR""" @@ -639,23 +640,24 @@ class PowerParser: print("tuple name", name) if name in self.gprs: self.read_regs.add(name) # add to list of regs to read - #p[0] = ast.Subscript(ast.Name("GPR"), ast.Str(p[2].id)) + #p[0] = ast.Subscript(ast.Name("GPR", ast.Load()), ast.Str(p[2].id)) # return p[0] = p[2] elif isinstance(p[2], ast.BinOp): if isinstance(p[2].left, ast.Name) and \ isinstance(p[2].right, ast.Constant) and \ - p[2].right.value == 0 and \ - p[2].left.id in self.gprs: - rid = p[2].left.id - self.read_regs.add(rid) # add to list of regs to read - # create special call to GPR.getz - gprz = ast.Name("GPR") - gprz = ast.Attribute(gprz, "getz") # get testzero function - # *sigh* see class GPR. we need index itself not reg value - ridx = ast.Name("_%s" % rid) - p[0] = ast.Call(gprz, [ridx], []) - print("tree", astor.dump_tree(p[0])) + p[2].right.value == 0 and \ + p[2].left.id in self.gprs: + rid = p[2].left.id + self.read_regs.add(rid) # add to list of regs to read + # create special call to GPR.getz + gprz = ast.Name("GPR", ast.Load()) + # get testzero function + gprz = ast.Attribute(gprz, "getz", ast.Load()) + # *sigh* see class GPR. we need index itself not reg value + ridx = ast.Name("_%s" % rid, ast.Load()) + p[0] = ast.Call(gprz, [ridx], []) + print("tree", astor.dump_tree(p[0])) else: p[0] = p[2] else: diff --git a/src/soc/experiment/compldst.py b/src/soc/experiment/compldst.py index 206f4487..651267bd 100644 --- a/src/soc/experiment/compldst.py +++ b/src/soc/experiment/compldst.py @@ -24,7 +24,7 @@ from nmigen import Module, Signal, Mux, Cat, Elaboratable from nmutil.latch import SRLatch, latchregister -from testmem import TestMemory +from .testmem import TestMemory # internal opcodes. hypothetically this could do more combinations. # meanings: @@ -32,18 +32,17 @@ from testmem import TestMemory # * bit 1: 0 = src1, 1 = IMM # * bit 2: 1 = LD # * bit 3: 1 = ST -BIT0_ADD = 0 -BIT1_SRC = 1 -BIT2_ST = 2 -BIT3_LD = 3 +BIT0_ADD = 0 +BIT1_SRC = 1 +BIT2_ST = 2 +BIT3_LD = 3 # convenience thingies. -LDST_OP_ADD = 0b0000 # plain ADD (src1 + src2) - use this ALU as an ADD -LDST_OP_SUB = 0b0001 # plain SUB (src1 - src2) - use this ALU as a SUB -LDST_OP_ADDI = 0b0010 # immed ADD (imm + src1) -LDST_OP_SUBI = 0b0011 # immed SUB (imm - src1) -LDST_OP_ST = 0b0110 # immed ADD plus LD op. ADD result is address -LDST_OP_LD = 0b1010 # immed ADD plus ST op. ADD result is address - +LDST_OP_ADD = 0b0000 # plain ADD (src1 + src2) - use this ALU as an ADD +LDST_OP_SUB = 0b0001 # plain SUB (src1 - src2) - use this ALU as a SUB +LDST_OP_ADDI = 0b0010 # immed ADD (imm + src1) +LDST_OP_SUBI = 0b0011 # immed SUB (imm - src1) +LDST_OP_ST = 0b0110 # immed ADD plus LD op. ADD result is address +LDST_OP_LD = 0b1010 # immed ADD plus ST op. ADD result is address class LDSTCompUnit(Elaboratable): @@ -91,6 +90,7 @@ class LDSTCompUnit(Elaboratable): * :data_o: Dest out (LD or ALU) * :addr_o: Address out (LD or ST) """ + def __init__(self, rwid, opwid, alu, mem): self.opwid = opwid self.rwid = rwid @@ -98,34 +98,34 @@ class LDSTCompUnit(Elaboratable): self.mem = mem self.counter = Signal(4) - self.go_rd_i = Signal(reset_less=True) # go read in - self.go_ad_i = Signal(reset_less=True) # go address in - self.go_wr_i = Signal(reset_less=True) # go write in - self.go_st_i = Signal(reset_less=True) # go store in - self.issue_i = Signal(reset_less=True) # fn issue in - self.isalu_i = Signal(reset_less=True) # fn issue as ALU in - self.shadown_i = Signal(reset=1) # shadow function, defaults to ON - self.go_die_i = Signal() # go die (reset) - - self.oper_i = Signal(opwid, reset_less=True) # opcode in - self.imm_i = Signal(rwid, reset_less=True) # immediate in - self.src1_i = Signal(rwid, reset_less=True) # oper1 in - self.src2_i = Signal(rwid, reset_less=True) # oper2 in + self.go_rd_i = Signal(reset_less=True) # go read in + self.go_ad_i = Signal(reset_less=True) # go address in + self.go_wr_i = Signal(reset_less=True) # go write in + self.go_st_i = Signal(reset_less=True) # go store in + self.issue_i = Signal(reset_less=True) # fn issue in + self.isalu_i = Signal(reset_less=True) # fn issue as ALU in + self.shadown_i = Signal(reset=1) # shadow function, defaults to ON + self.go_die_i = Signal() # go die (reset) + + self.oper_i = Signal(opwid, reset_less=True) # opcode in + self.imm_i = Signal(rwid, reset_less=True) # immediate in + self.src1_i = Signal(rwid, reset_less=True) # oper1 in + self.src2_i = Signal(rwid, reset_less=True) # oper2 in self.busy_o = Signal(reset_less=True) # fn busy out - self.rd_rel_o = Signal(reset_less=True) # request src1/src2 - self.adr_rel_o = Signal(reset_less=True) # request address (from mem) - self.sto_rel_o = Signal(reset_less=True) # request store (to mem) - self.req_rel_o = Signal(reset_less=True) # request write (result) - self.done_o = Signal(reset_less=True) # final release signal - self.data_o = Signal(rwid, reset_less=True) # Dest out (LD or ALU) - self.addr_o = Signal(rwid, reset_less=True) # Address out (LD or ST) + self.rd_rel_o = Signal(reset_less=True) # request src1/src2 + self.adr_rel_o = Signal(reset_less=True) # request address (from mem) + self.sto_rel_o = Signal(reset_less=True) # request store (to mem) + self.req_rel_o = Signal(reset_less=True) # request write (result) + self.done_o = Signal(reset_less=True) # final release signal + self.data_o = Signal(rwid, reset_less=True) # Dest out (LD or ALU) + self.addr_o = Signal(rwid, reset_less=True) # Address out (LD or ST) # hmm... TODO... move these to outside of LDSTCompUnit? - self.load_mem_o = Signal(reset_less=True) # activate memory LOAD - self.stwd_mem_o = Signal(reset_less=True) # activate memory STORE - self.ld_o = Signal(reset_less=True) # operation is a LD - self.st_o = Signal(reset_less=True) # operation is a ST + self.load_mem_o = Signal(reset_less=True) # activate memory LOAD + self.stwd_mem_o = Signal(reset_less=True) # activate memory STORE + self.ld_o = Signal(reset_less=True) # operation is a LD + self.st_o = Signal(reset_less=True) # operation is a ST def elaborate(self, platform): m = Module() @@ -146,13 +146,14 @@ class LDSTCompUnit(Elaboratable): reset_a = Signal(reset_less=True) reset_s = Signal(reset_less=True) reset_r = Signal(reset_less=True) - comb += reset_b.eq(self.go_st_i|self.go_wr_i|self.go_ad_i|self.go_die_i) + comb += reset_b.eq(self.go_st_i | self.go_wr_i | + self.go_ad_i | self.go_die_i) comb += reset_w.eq(self.go_wr_i | self.go_die_i) comb += reset_s.eq(self.go_st_i | self.go_die_i) comb += reset_r.eq(self.go_rd_i | self.go_die_i) # this one is slightly different, issue_alu_i selects go_wr_i) a_sel = Mux(self.isalu_i, self.go_wr_i, self.go_ad_i) - comb += reset_a.eq(a_sel| self.go_die_i) + comb += reset_a.eq(a_sel | self.go_die_i) # opcode decode op_alu = Signal(reset_less=True) @@ -176,8 +177,8 @@ class LDSTCompUnit(Elaboratable): # NOTE: use sync to stop combinatorial loops. # opcode latch - inverted so that busy resets to 0 - sync += opc_l.s.eq(issue_i) # XXX NOTE: INVERTED FROM book! - sync += opc_l.r.eq(reset_b) # XXX NOTE: INVERTED FROM book! + sync += opc_l.s.eq(issue_i) # XXX NOTE: INVERTED FROM book! + sync += opc_l.r.eq(reset_b) # XXX NOTE: INVERTED FROM book! # src operand latch sync += src_l.s.eq(issue_i) @@ -188,17 +189,17 @@ class LDSTCompUnit(Elaboratable): sync += adr_l.r.eq(reset_a) # dest operand latch - sync += req_l.s.eq(self.go_ad_i|self.go_st_i|self.go_wr_i) + sync += req_l.s.eq(self.go_ad_i | self.go_st_i | self.go_wr_i) sync += req_l.r.eq(reset_w) # store latch - sync += sto_l.s.eq(self.go_rd_i) # XXX not sure which + sync += sto_l.s.eq(self.go_rd_i) # XXX not sure which sync += sto_l.r.eq(reset_s) # outputs: busy and release signals busy_o = self.busy_o - comb += self.busy_o.eq(opc_l.q) # busy out - comb += self.rd_rel_o.eq(src_l.q & busy_o) # src1/src2 req rel + comb += self.busy_o.eq(opc_l.q) # busy out + comb += self.rd_rel_o.eq(src_l.q & busy_o) # src1/src2 req rel comb += self.sto_rel_o.eq(sto_l.q & busy_o & self.shadown_i & op_is_st) # request release enabled based on if op is a LD/ST or a plain ALU @@ -207,7 +208,7 @@ class LDSTCompUnit(Elaboratable): comb += wr_q.eq(req_l.q & (~op_ldst | op_is_ld)) alulatch = Signal(reset_less=True) - comb += alulatch.eq((op_ldst & self.adr_rel_o) | \ + comb += alulatch.eq((op_ldst & self.adr_rel_o) | (~op_ldst & self.req_rel_o)) # select immediate if opcode says so. however also change the latch @@ -221,18 +222,18 @@ class LDSTCompUnit(Elaboratable): latchregister(m, src2_or_imm, self.alu.b, src_sel, name="imm_r") # create a latch/register for the operand - oper_r = Signal(self.opwid, reset_less=True) # Dest register + oper_r = Signal(self.opwid, reset_less=True) # Dest register latchregister(m, self.oper_i, oper_r, self.issue_i, name="operi_r") - alu_op = Cat(op_alu, 0, op_is_imm) # using alu_hier, here. + alu_op = Cat(op_alu, 0, op_is_imm) # using alu_hier, here. comb += self.alu.op.eq(alu_op) # and one for the output from the ALU - data_r = Signal(self.rwid, reset_less=True) # Dest register + data_r = Signal(self.rwid, reset_less=True) # Dest register latchregister(m, self.alu.o, data_r, alulatch, "aluo_r") # decode bits of operand (latched) comb += op_alu.eq(oper_r[BIT0_ADD]) # ADD/SUB - comb += op_is_imm.eq(oper_r[BIT1_SRC]) # IMMED/reg + comb += op_is_imm.eq(oper_r[BIT1_SRC]) # IMMED/reg comb += op_is_st.eq(oper_r[BIT2_ST]) # OP is ST comb += op_is_ld.eq(oper_r[BIT3_LD]) # OP is LD comb += op_ldst.eq(op_is_ld | op_is_st) @@ -246,18 +247,19 @@ class LDSTCompUnit(Elaboratable): # go_read is only valid for one clock! with m.If(self.go_rd_i): # src operands ready, GO! with m.If(~self.alu.p_ready_o): # no ACK yet - m.d.comb += self.alu.p_valid_i.eq(1) # so indicate valid + m.d.comb += self.alu.p_valid_i.eq(1) # so indicate valid # only proceed if ALU says its output is valid with m.If(self.alu.n_valid_o): # write req release out. waits until shadow is dropped. comb += self.req_rel_o.eq(wr_q & busy_o & self.shadown_i) # address release only happens on LD/ST, and is shadowed. - comb += self.adr_rel_o.eq(adr_l.q & op_ldst & busy_o & \ + comb += self.adr_rel_o.eq(adr_l.q & op_ldst & busy_o & self.shadown_i) # when output latch is ready, and ALU says ready, accept ALU output with m.If(self.req_rel_o): - m.d.comb += self.alu.n_ready_i.eq(1) # tells ALU "thanks got it" + # tells ALU "thanks got it" + m.d.comb += self.alu.n_ready_i.eq(1) # provide "done" signal: select req_rel for non-LD/ST, adr_rel for LD/ST comb += self.done_o.eq((self.req_rel_o & ~op_ldst) | @@ -317,16 +319,18 @@ class LDSTCompUnit(Elaboratable): def ports(self): return list(self) + def wait_for(sig): v = (yield sig) - print ("wait for", sig, v) + print("wait for", sig, v) while True: yield v = (yield sig) - print (v) + print(v) if v: break + def store(dut, src1, src2, imm): yield dut.oper_i.eq(LDST_OP_ST) yield dut.src1_i.eq(src1) @@ -365,11 +369,11 @@ def load(dut, src1, src2, imm): yield data = (yield dut.data_o) yield dut.go_ad_i.eq(0) - #wait_for(dut.stwd_mem_o) + # wait_for(dut.stwd_mem_o) return data -def add(dut, src1, src2, imm, imm_mode = False): +def add(dut, src1, src2, imm, imm_mode=False): yield dut.oper_i.eq(LDST_OP_ADDI if imm_mode else LDST_OP_ADD) yield dut.src1_i.eq(src1) yield dut.src2_i.eq(src2) @@ -388,9 +392,10 @@ def add(dut, src1, src2, imm, imm_mode = False): data = (yield dut.data_o) yield dut.go_wr_i.eq(0) yield - #wait_for(dut.stwd_mem_o) + # wait_for(dut.stwd_mem_o) return data + def scoreboard_sim(dut): # two STs (different addresses) yield from store(dut, 4, 3, 2) @@ -435,5 +440,6 @@ def test_scoreboard(): run_simulation(dut, scoreboard_sim(dut), vcd_name='test_ldst_comp.vcd') + if __name__ == '__main__': test_scoreboard() diff --git a/src/soc/experiment/cscore.py b/src/soc/experiment/cscore.py index 18b71c80..187918c0 100644 --- a/src/soc/experiment/cscore.py +++ b/src/soc/experiment/cscore.py @@ -33,12 +33,12 @@ class Scoreboard(Elaboratable): self.fpregs = RegFileArray(rwid, n_regs) # inputs - self.int_store_i = Signal(reset_less=True) # instruction is a store - self.int_dest_i = Signal(max=n_regs, reset_less=True) # Dest R# in - self.int_src1_i = Signal(max=n_regs, reset_less=True) # oper1 R# in - self.int_src2_i = Signal(max=n_regs, reset_less=True) # oper2 R# in + self.int_store_i = Signal(reset_less=True) # instruction is a store + self.int_dest_i = Signal(range(n_regs), reset_less=True) # Dest R# in + self.int_src1_i = Signal(range(n_regs), reset_less=True) # oper1 R# in + self.int_src2_i = Signal(range(n_regs), reset_less=True) # oper2 R# in - self.issue_o = Signal(reset_less=True) # instruction was accepted + self.issue_o = Signal(reset_less=True) # instruction was accepted def elaborate(self, platform): m = Module() @@ -62,8 +62,8 @@ class Scoreboard(Elaboratable): m.submodules.comp2 = comp2 = ComputationUnitNoDelay(self.rwid, 1, sub) int_alus = [comp1, comp2] - m.d.comb += comp1.oper_i.eq(Const(0)) # temporary/experiment: op=add - m.d.comb += comp2.oper_i.eq(Const(1)) # temporary/experiment: op=sub + m.d.comb += comp1.oper_i.eq(Const(0)) # temporary/experiment: op=add + m.d.comb += comp2.oper_i.eq(Const(1)) # temporary/experiment: op=sub # Int FUs if_l = [] @@ -85,9 +85,9 @@ class Scoreboard(Elaboratable): # Count of number of FUs n_int_fus = len(if_l) - n_fp_fus = 0 # for now + n_fp_fus = 0 # for now - n_fus = n_int_fus + n_fp_fus # plus FP FUs + n_fus = n_int_fus + n_fp_fus # plus FP FUs # XXX replaced by array of FUs? *FnUnit # # Integer FU-FU Dep Matrix @@ -97,7 +97,7 @@ class Scoreboard(Elaboratable): # m.submodules.intregdeps = intregdeps # Integer Priority Picker 1: Adder + Subtractor - intpick1 = GroupPicker(2) # picks between add and sub + intpick1 = GroupPicker(2) # picks between add and sub m.submodules.intpick1 = intpick1 # Global Pending Vectors (INT and FP) @@ -121,24 +121,24 @@ class Scoreboard(Elaboratable): intfudeps = FUFUDepMatrix(n_int_fus, n_int_fus) m.submodules.intfudeps = intfudeps - #--------- + # --------- # ok start wiring things together... # "now hear de word of de looord... dem bones dem bones dem dryy bones" # https://www.youtube.com/watch?v=pYb8Wm6-QfA - #--------- + # --------- - #--------- + # --------- # Issue Unit is where it starts. set up some in/outs for this module - #--------- + # --------- m.d.comb += [issueunit.i.store_i.eq(self.int_store_i), regdecode.dest_i.eq(self.int_dest_i), regdecode.src1_i.eq(self.int_src1_i), regdecode.src2_i.eq(self.int_src2_i), regdecode.enable_i.eq(1), self.issue_o.eq(issueunit.issue_o), - issueunit.i.dest_i.eq(regdecode.dest_o), - ] - self.int_insn_i = issueunit.i.insn_i # enabled by instruction decode + issueunit.i.dest_i.eq(regdecode.dest_o), + ] + self.int_insn_i = issueunit.i.insn_i # enabled by instruction decode # connect global rd/wr pending vectors m.d.comb += issueunit.i.g_wr_pend_i.eq(g_int_wr_pend_v.g_pend_o) @@ -157,20 +157,20 @@ class Scoreboard(Elaboratable): # XXX sync, so as to stop a simulation infinite loop m.d.comb += issueunit.i.busy_i[i].eq(fu.busy_o) - #--------- + # --------- # connect Function Units - #--------- + # --------- # Group Picker... done manually for now. TODO: cat array of pick sigs - m.d.comb += if_l[0].go_rd_i.eq(intpick1.go_rd_o[0]) # add rd - m.d.comb += if_l[0].go_wr_i.eq(intpick1.go_wr_o[0]) # add wr + m.d.comb += if_l[0].go_rd_i.eq(intpick1.go_rd_o[0]) # add rd + m.d.comb += if_l[0].go_wr_i.eq(intpick1.go_wr_o[0]) # add wr - m.d.comb += if_l[1].go_rd_i.eq(intpick1.go_rd_o[1]) # subtract rd - m.d.comb += if_l[1].go_wr_i.eq(intpick1.go_wr_o[1]) # subtract wr + m.d.comb += if_l[1].go_rd_i.eq(intpick1.go_rd_o[1]) # subtract rd + m.d.comb += if_l[1].go_wr_i.eq(intpick1.go_wr_o[1]) # subtract wr # create read-pending FU-FU vectors - intfu_rd_pend_v = Signal(n_int_fus, reset_less = True) - intfu_wr_pend_v = Signal(n_int_fus, reset_less = True) + intfu_rd_pend_v = Signal(n_int_fus, reset_less=True) + intfu_wr_pend_v = Signal(n_int_fus, reset_less=True) for i in range(n_int_fus): #m.d.comb += intfu_rd_pend_v[i].eq(if_l[i].int_rd_pend_o.bool()) #m.d.comb += intfu_wr_pend_v[i].eq(if_l[i].int_wr_pend_o.bool()) @@ -192,25 +192,25 @@ class Scoreboard(Elaboratable): m.d.comb += intfudeps.go_wr_i[i].eq(intpick1.go_wr_o[i]) # Connect Picker (note connection to FU-FU) - #--------- + # --------- readable_o = intfudeps.readable_o writable_o = intfudeps.writable_o m.d.comb += intpick1.rd_rel_i[0].eq(int_alus[0].rd_rel_o) m.d.comb += intpick1.rd_rel_i[1].eq(int_alus[1].rd_rel_o) m.d.comb += intpick1.req_rel_i[0].eq(int_alus[0].req_rel_o) m.d.comb += intpick1.req_rel_i[1].eq(int_alus[1].req_rel_o) - m.d.comb += intpick1.readable_i[0].eq(readable_o[0]) # add rd - m.d.comb += intpick1.writable_i[0].eq(writable_o[0]) # add wr - m.d.comb += intpick1.readable_i[1].eq(readable_o[1]) # sub rd - m.d.comb += intpick1.writable_i[1].eq(writable_o[1]) # sub wr + m.d.comb += intpick1.readable_i[0].eq(readable_o[0]) # add rd + m.d.comb += intpick1.writable_i[0].eq(writable_o[0]) # add wr + m.d.comb += intpick1.readable_i[1].eq(readable_o[1]) # sub rd + m.d.comb += intpick1.writable_i[1].eq(writable_o[1]) # sub wr - #--------- + # --------- # Connect Register File(s) - #--------- - #with m.If(if_l[0].go_wr_i | if_l[1].go_wr_i): + # --------- + # with m.If(if_l[0].go_wr_i | if_l[1].go_wr_i): m.d.sync += int_dest.wen.eq(g_int_wr_pend_v.g_pend_o) - #with m.If(intpick1.go_rd_o): - #with m.If(if_l[0].go_rd_i | if_l[1].go_rd_i): + # with m.If(intpick1.go_rd_o): + # with m.If(if_l[0].go_rd_i | if_l[1].go_rd_i): m.d.sync += int_src1.ren.eq(g_int_src1_pend_v.g_pend_o) m.d.sync += int_src2.ren.eq(g_int_src2_pend_v.g_pend_o) @@ -224,14 +224,13 @@ class Scoreboard(Elaboratable): m.d.comb += alu.go_rd_i.eq(intpick1.go_rd_o[i]) m.d.comb += alu.go_wr_i.eq(intpick1.go_wr_o[i]) m.d.comb += alu.issue_i.eq(fn_issue_l[i]) - #m.d.comb += fn_busy_l[i].eq(alu.busy_o) # XXX ignore, use fnissue + # m.d.comb += fn_busy_l[i].eq(alu.busy_o) # XXX ignore, use fnissue m.d.comb += alu.src1_i.eq(int_src1.data_o) m.d.comb += alu.src2_i.eq(int_src2.data_o) - m.d.comb += if_l[i].req_rel_i.eq(alu.req_rel_o) # pipe out ready + m.d.comb += if_l[i].req_rel_i.eq(alu.req_rel_o) # pipe out ready return m - def __iter__(self): yield from self.intregs yield from self.fpregs @@ -240,20 +239,22 @@ class Scoreboard(Elaboratable): yield self.int_src1_i yield self.int_src2_i yield self.issue_o - #yield from self.int_src1 - #yield from self.int_dest - #yield from self.int_src1 - #yield from self.int_src2 - #yield from self.fp_dest - #yield from self.fp_src1 - #yield from self.fp_src2 + # yield from self.int_src1 + # yield from self.int_dest + # yield from self.int_src1 + # yield from self.int_src2 + # yield from self.fp_dest + # yield from self.fp_src1 + # yield from self.fp_src2 def ports(self): return list(self) + IADD = 0 ISUB = 1 + class RegSim: def __init__(self, rwidth, nregs): self.rwidth = rwidth @@ -263,9 +264,9 @@ class RegSim: src1 = self.regs[src1] src2 = self.regs[src2] if op == IADD: - val = (src1 + src2) & ((1<<(self.rwidth))-1) + val = (src1 + src2) & ((1 << (self.rwidth))-1) elif op == ISUB: - val = (src1 - src2) & ((1<<(self.rwidth))-1) + val = (src1 - src2) & ((1 << (self.rwidth))-1) self.regs[dest] = val def setval(self, dest, val): @@ -285,6 +286,7 @@ class RegSim: yield from self.dump(dut) assert False + def int_instr(dut, alusim, op, src1, src2, dest): for i in range(len(dut.int_insn_i)): yield dut.int_insn_i[i].eq(0) @@ -301,7 +303,7 @@ def print_reg(dut, rnums): reg = yield dut.intregs.regs[rnum].reg rs.append("%x" % reg) rnums = map(str, rnums) - print ("reg %s: %s" % (','.join(rnums), ','.join(rs))) + print("reg %s: %s" % (','.join(rnums), ','.join(rs))) def scoreboard_sim(dut, alusim): @@ -313,21 +315,21 @@ def scoreboard_sim(dut, alusim): if False: yield from int_instr(dut, alusim, IADD, 4, 3, 5) - yield from print_reg(dut, [3,4,5]) + yield from print_reg(dut, [3, 4, 5]) yield yield from int_instr(dut, alusim, IADD, 5, 2, 5) - yield from print_reg(dut, [3,4,5]) + yield from print_reg(dut, [3, 4, 5]) yield yield from int_instr(dut, alusim, ISUB, 5, 1, 3) - yield from print_reg(dut, [3,4,5]) + yield from print_reg(dut, [3, 4, 5]) yield for i in range(len(dut.int_insn_i)): yield dut.int_insn_i[i].eq(0) - yield from print_reg(dut, [3,4,5]) + yield from print_reg(dut, [3, 4, 5]) yield - yield from print_reg(dut, [3,4,5]) + yield from print_reg(dut, [3, 4, 5]) yield - yield from print_reg(dut, [3,4,5]) + yield from print_reg(dut, [3, 4, 5]) yield yield from alusim.check(dut) @@ -369,32 +371,31 @@ def scoreboard_sim(dut, alusim): #op = (i+1) % 2 op = i - print ("random %d: %d %d %d %d\n" % (i, op, src1, src2, dest)) + print("random %d: %d %d %d %d\n" % (i, op, src1, src2, dest)) yield from int_instr(dut, alusim, op, src1, src2, dest) - yield from print_reg(dut, [3,4,5]) + yield from print_reg(dut, [3, 4, 5]) while True: yield issue_o = yield dut.issue_o if issue_o: - yield from print_reg(dut, [3,4,5]) + yield from print_reg(dut, [3, 4, 5]) for i in range(len(dut.int_insn_i)): yield dut.int_insn_i[i].eq(0) break - print ("busy",) - yield from print_reg(dut, [3,4,5]) + print("busy",) + yield from print_reg(dut, [3, 4, 5]) yield yield yield - yield - yield from print_reg(dut, [3,4,5]) + yield from print_reg(dut, [3, 4, 5]) yield - yield from print_reg(dut, [3,4,5]) + yield from print_reg(dut, [3, 4, 5]) yield - yield from print_reg(dut, [3,4,5]) + yield from print_reg(dut, [3, 4, 5]) yield - yield from print_reg(dut, [3,4,5]) + yield from print_reg(dut, [3, 4, 5]) yield yield yield @@ -417,7 +418,7 @@ def explore_groups(dut): groups = LHSGroupAnalyzer()(fragment._statements) - print (groups) + print(groups) def test_scoreboard(): @@ -428,7 +429,7 @@ def test_scoreboard(): f.write(vl) run_simulation(dut, scoreboard_sim(dut, alusim), - vcd_name='test_scoreboard.vcd') + vcd_name='test_scoreboard.vcd') if __name__ == '__main__': diff --git a/src/soc/experiment/score6600.py b/src/soc/experiment/score6600.py index c98ac04a..cef0c866 100644 --- a/src/soc/experiment/score6600.py +++ b/src/soc/experiment/score6600.py @@ -13,11 +13,11 @@ from soc.scoreboard.shadow import ShadowMatrix, BranchSpeculationRecord from soc.scoreboard.instruction_q import Instruction, InstructionQ from soc.scoreboard.memfu import MemFunctionUnits -from compalu import ComputationUnitNoDelay -from compldst import LDSTCompUnit -from testmem import TestMemory +from .compalu import ComputationUnitNoDelay +from .compldst import LDSTCompUnit +from .testmem import TestMemory -from alu_hier import ALU, BranchALU +from .alu_hier import ALU, BranchALU from nmutil.latch import SRLatch from nmutil.nmoperator import eq @@ -54,6 +54,7 @@ class CompUnitsBase(Elaboratable): Computation Unit" as defined by Mitch Alsup (see section 11.4.9.3) """ + def __init__(self, rwid, units, ldstmode=False): """ Inputs: @@ -89,8 +90,8 @@ class CompUnitsBase(Elaboratable): self.req_rel_o = Signal(n_units, reset_less=True) self.done_o = Signal(n_units, reset_less=True) if ldstmode: - self.ld_o = Signal(n_units, reset_less=True) # op is LD - self.st_o = Signal(n_units, reset_less=True) # op is ST + self.ld_o = Signal(n_units, reset_less=True) # op is LD + self.st_o = Signal(n_units, reset_less=True) # op is ST self.adr_rel_o = Signal(n_units, reset_less=True) self.sto_rel_o = Signal(n_units, reset_less=True) self.load_mem_o = Signal(n_units, reset_less=True) @@ -206,7 +207,7 @@ class CompUnitLDSTs(CompUnitsBase): units = [] for alu in self.alus: - aluopwid = 4 # see compldst.py for "internal" opcode + aluopwid = 4 # see compldst.py for "internal" opcode units.append(LDSTCompUnit(rwid, aluopwid, alu, mem)) CompUnitsBase.__init__(self, rwid, units, ldstmode=True) @@ -245,7 +246,7 @@ class CompUnitALUs(CompUnitsBase): units = [] for alu in alus: - aluopwid = 3 # extra bit for immediate mode + aluopwid = 3 # extra bit for immediate mode units.append(ComputationUnitNoDelay(rwid, aluopwid, alu)) CompUnitsBase.__init__(self, rwid, units) @@ -281,7 +282,7 @@ class CompUnitBR(CompUnitsBase): # Branch ALU and CU self.bgt = BranchALU(rwid) - aluopwid = 3 # extra bit for immediate mode + aluopwid = 3 # extra bit for immediate mode self.br1 = ComputationUnitNoDelay(rwid, aluopwid, self.bgt) CompUnitsBase.__init__(self, rwid, [self.br1]) @@ -303,16 +304,16 @@ class FunctionUnits(Elaboratable): self.n_regs = n_regs self.n_int_alus = n_int_alus - self.dest_i = Signal(n_regs, reset_less=True) # Dest R# in - self.src1_i = Signal(n_regs, reset_less=True) # oper1 R# in - self.src2_i = Signal(n_regs, reset_less=True) # oper2 R# in + self.dest_i = Signal(n_regs, reset_less=True) # Dest R# in + self.src1_i = Signal(n_regs, reset_less=True) # oper1 R# in + self.src2_i = Signal(n_regs, reset_less=True) # oper2 R# in self.g_int_rd_pend_o = Signal(n_regs, reset_less=True) self.g_int_wr_pend_o = Signal(n_regs, reset_less=True) - self.dest_rsel_o = Signal(n_regs, reset_less=True) # dest reg (bot) - self.src1_rsel_o = Signal(n_regs, reset_less=True) # src1 reg (bot) - self.src2_rsel_o = Signal(n_regs, reset_less=True) # src2 reg (bot) + self.dest_rsel_o = Signal(n_regs, reset_less=True) # dest reg (bot) + self.src1_rsel_o = Signal(n_regs, reset_less=True) # src1 reg (bot) + self.src2_rsel_o = Signal(n_regs, reset_less=True) # src2 reg (bot) self.readable_o = Signal(n_int_alus, reset_less=True) self.writable_o = Signal(n_int_alus, reset_less=True) @@ -346,7 +347,7 @@ class FunctionUnits(Elaboratable): comb += intfudeps.rd_pend_i.eq(intregdeps.rd_pend_o) comb += intfudeps.wr_pend_i.eq(intregdeps.wr_pend_o) - self.wr_pend_o = intregdeps.wr_pend_o # also output for use in WaWGrid + self.wr_pend_o = intregdeps.wr_pend_o # also output for use in WaWGrid comb += intfudeps.issue_i.eq(self.fn_issue_i) comb += intfudeps.go_rd_i.eq(self.go_rd_i) @@ -387,7 +388,7 @@ class Scoreboard(Elaboratable): self.fpregs = RegFileArray(rwid, n_regs) # Memory (test for now) - self.mem = TestMemory(self.rwid, 8) # not too big, takes too long + self.mem = TestMemory(self.rwid, 8) # not too big, takes too long # issue q needs to get at these self.aluissue = IssueUnitGroup(2) @@ -402,14 +403,14 @@ class Scoreboard(Elaboratable): self.ls_imm_i = Signal(rwid, reset_less=True) # inputs - self.int_dest_i = Signal(range(n_regs), reset_less=True) # Dest R# in - self.int_src1_i = Signal(range(n_regs), reset_less=True) # oper1 R# in - self.int_src2_i = Signal(range(n_regs), reset_less=True) # oper2 R# in - self.reg_enable_i = Signal(reset_less=True) # enable reg decode + self.int_dest_i = Signal(range(n_regs), reset_less=True) # Dest R# in + self.int_src1_i = Signal(range(n_regs), reset_less=True) # oper1 R# in + self.int_src2_i = Signal(range(n_regs), reset_less=True) # oper2 R# in + self.reg_enable_i = Signal(reset_less=True) # enable reg decode # outputs - self.issue_o = Signal(reset_less=True) # instruction was accepted - self.busy_o = Signal(reset_less=True) # at least one CU is busy + self.issue_o = Signal(reset_less=True) # instruction was accepted + self.busy_o = Signal(reset_less=True) # at least one CU is busy # for branch speculation experiment. branch_direction = 0 if # the branch hasn't been met yet. 1 indicates "success", 2 is "fail" @@ -440,7 +441,7 @@ class Scoreboard(Elaboratable): # Int ALUs and BR ALUs n_int_alus = 5 cua = CompUnitALUs(self.rwid, 3, n_alus=self.aluissue.n_insns) - cub = CompUnitBR(self.rwid, 3) # 1 BR ALUs + cub = CompUnitBR(self.rwid, 3) # 1 BR ALUs # LDST Comp Units n_ldsts = 2 @@ -448,7 +449,7 @@ class Scoreboard(Elaboratable): # Comp Units m.submodules.cu = cu = CompUnitsBase(self.rwid, [cua, cul, cub]) - bgt = cub.bgt # get at the branch computation unit + bgt = cub.bgt # get at the branch computation unit br1 = cub.br1 # Int FUs @@ -458,15 +459,17 @@ class Scoreboard(Elaboratable): m.submodules.memfus = memfus = MemFunctionUnits(n_ldsts, 5) # Memory Priority Picker 1: one gateway per memory port - mempick1 = GroupPicker(n_ldsts) # picks 1 reader and 1 writer to intreg + # picks 1 reader and 1 writer to intreg + mempick1 = GroupPicker(n_ldsts) m.submodules.mempick1 = mempick1 # Count of number of FUs n_intfus = n_int_alus - n_fp_fus = 0 # for now + n_fp_fus = 0 # for now # Integer Priority Picker 1: Adder + Subtractor (and LD/ST) - intpick1 = GroupPicker(n_intfus) # picks 1 reader and 1 writer to intreg + # picks 1 reader and 1 writer to intreg + intpick1 = GroupPicker(n_intfus) m.submodules.intpick1 = intpick1 # INT/FP Issue Unit @@ -489,21 +492,21 @@ class Scoreboard(Elaboratable): # allow/cancel can be issued as appropriate. m.submodules.specrec = bspec = BranchSpeculationRecord(n_intfus) - #--------- + # --------- # ok start wiring things together... # "now hear de word of de looord... dem bones dem bones dem dryy bones" # https://www.youtube.com/watch?v=pYb8Wm6-QfA - #--------- + # --------- - #--------- + # --------- # Issue Unit is where it starts. set up some in/outs for this module - #--------- - comb += [ regdecode.dest_i.eq(self.int_dest_i), - regdecode.src1_i.eq(self.int_src1_i), - regdecode.src2_i.eq(self.int_src2_i), - regdecode.enable_i.eq(self.reg_enable_i), - self.issue_o.eq(issueunit.issue_o) - ] + # --------- + comb += [regdecode.dest_i.eq(self.int_dest_i), + regdecode.src1_i.eq(self.int_src1_i), + regdecode.src2_i.eq(self.int_src2_i), + regdecode.enable_i.eq(self.reg_enable_i), + self.issue_o.eq(issueunit.issue_o) + ] # take these to outside (issue needs them) comb += cua.oper_i.eq(self.alu_oper_i) @@ -526,24 +529,24 @@ class Scoreboard(Elaboratable): comb += issueunit.busy_i.eq(cu.busy_o) comb += self.busy_o.eq(cu.busy_o.bool()) - #--------- + # --------- # Memory Function Unit - #--------- + # --------- reset_b = Signal(cul.n_units, reset_less=True) sync += reset_b.eq(cul.go_st_i | cul.go_wr_i | cul.go_die_i) - comb += memfus.fn_issue_i.eq(cul.issue_i) # Comp Unit Issue -> Mem FUs - comb += memfus.addr_en_i.eq(cul.adr_rel_o) # Match enable on adr rel - comb += memfus.addr_rs_i.eq(reset_b) # reset same as LDSTCompUnit + comb += memfus.fn_issue_i.eq(cul.issue_i) # Comp Unit Issue -> Mem FUs + comb += memfus.addr_en_i.eq(cul.adr_rel_o) # Match enable on adr rel + comb += memfus.addr_rs_i.eq(reset_b) # reset same as LDSTCompUnit # LD/STs have to accumulate prior LD/STs (TODO: multi-issue as well, # in a transitive fashion). This cycle activates based on LDSTCompUnit # issue_i. multi-issue gets a bit more complex but not a lot. prior_ldsts = Signal(cul.n_units, reset_less=True) sync += prior_ldsts.eq(memfus.g_int_ld_pend_o | memfus.g_int_st_pend_o) - with m.If(self.ls_oper_i[3]): # LD bit of operand + with m.If(self.ls_oper_i[3]): # LD bit of operand comb += memfus.ld_i.eq(cul.issue_i | prior_ldsts) - with m.If(self.ls_oper_i[2]): # ST bit of operand + with m.If(self.ls_oper_i[2]): # ST bit of operand comb += memfus.st_i.eq(cul.issue_i | prior_ldsts) # TODO: adr_rel_o needs to go into L1 Cache. for now, @@ -558,10 +561,10 @@ class Scoreboard(Elaboratable): # XXX should only be done when the memory ld/st has actually happened! go_st_i = Signal(cul.n_units, reset_less=True) go_ld_i = Signal(cul.n_units, reset_less=True) - comb += go_ld_i.eq(memfus.loadable_o & memfus.addr_nomatch_o &\ - cul.adr_rel_o & cul.ld_o) - comb += go_st_i.eq(memfus.storable_o & memfus.addr_nomatch_o &\ - cul.sto_rel_o & cul.st_o) + comb += go_ld_i.eq(memfus.loadable_o & memfus.addr_nomatch_o & + cul.adr_rel_o & cul.ld_o) + comb += go_st_i.eq(memfus.storable_o & memfus.addr_nomatch_o & + cul.sto_rel_o & cul.st_o) comb += memfus.go_ld_i.eq(go_ld_i) comb += memfus.go_st_i.eq(go_st_i) #comb += cul.go_wr_i.eq(go_ld_i) @@ -571,9 +574,9 @@ class Scoreboard(Elaboratable): #comb += cu.go_wr_i[0:n_intfus].eq(go_wr_o[0:n_intfus]) #comb += cu.issue_i[0:n_intfus].eq(fn_issue_o[0:n_intfus]) - #--------- + # --------- # merge shadow matrices outputs - #--------- + # --------- # these are explained in ShadowMatrix docstring, and are to be # connected to the FUReg and FUFU Matrices, to get them to reset @@ -584,9 +587,9 @@ class Scoreboard(Elaboratable): comb += anydie.eq(shadows.go_die_o | bshadow.go_die_o) comb += shreset.eq(bspec.match_g_o | bspec.match_f_o) - #--------- + # --------- # connect fu-fu matrix - #--------- + # --------- # Group Picker... done manually for now. go_rd_o = intpick1.go_rd_o @@ -595,12 +598,12 @@ class Scoreboard(Elaboratable): go_wr_i = intfus.go_wr_i go_die_i = intfus.go_die_i # NOTE: connect to the shadowed versions so that they can "die" (reset) - comb += go_rd_i[0:n_intfus].eq(go_rd_o[0:n_intfus]) # rd - comb += go_wr_i[0:n_intfus].eq(go_wr_o[0:n_intfus]) # wr - comb += go_die_i[0:n_intfus].eq(anydie[0:n_intfus]) # die + comb += go_rd_i[0:n_intfus].eq(go_rd_o[0:n_intfus]) # rd + comb += go_wr_i[0:n_intfus].eq(go_wr_o[0:n_intfus]) # wr + comb += go_die_i[0:n_intfus].eq(anydie[0:n_intfus]) # die # Connect Picker - #--------- + # --------- comb += intpick1.rd_rel_i[0:n_intfus].eq(cu.rd_rel_o[0:n_intfus]) comb += intpick1.req_rel_i[0:n_intfus].eq(cu.done_o[0:n_intfus]) int_rd_o = intfus.readable_o @@ -608,14 +611,14 @@ class Scoreboard(Elaboratable): comb += intpick1.readable_i[0:n_intfus].eq(int_rd_o[0:n_intfus]) comb += intpick1.writable_i[0:n_intfus].eq(int_wr_o[0:n_intfus]) - #--------- + # --------- # Shadow Matrix - #--------- + # --------- comb += shadows.issue_i.eq(fn_issue_o) #comb += shadows.reset_i[0:n_intfus].eq(bshadow.go_die_o[0:n_intfus]) comb += shadows.reset_i[0:n_intfus].eq(bshadow.go_die_o[0:n_intfus]) - #--------- + # --------- # NOTE; this setup is for the instruction order preservation... # connect shadows / go_dies to Computation Units @@ -636,7 +639,7 @@ class Scoreboard(Elaboratable): for i in range(n_intfus): comb += shadows.shadow_i[i][0:n_intfus].eq(prev_shadow) - #--------- + # --------- # ... and this is for branch speculation. it uses the extra bit # tacked onto the ShadowMatrix (hence shadow_wid=n_intfus+1) # only needs to set shadow_i, s_fail_i and s_good_i @@ -651,7 +654,7 @@ class Scoreboard(Elaboratable): with m.If(bactive & (self.branch_succ_i | self.branch_fail_i)): comb += bshadow.issue_i.eq(fn_issue_o) for i in range(n_intfus): - with m.If(fn_issue_o & (Const(1< 1: - self.rfile_sel_i = Signal(max=n_dests, reset_less=True) + self.rfile_sel_i = Signal(range(n_dests), reset_less=True) else: - self.rfile_sel_i = Const(0) # no selection. gets Array[0] - self.dest_i = Signal(max=wid, reset_less=True) # Dest R# in (top) - self.src1_i = Signal(max=wid, reset_less=True) # oper1 R# in (top) - self.src2_i = Signal(max=wid, reset_less=True) # oper2 R# in (top) + self.rfile_sel_i = Const(0) # no selection. gets Array[0] + self.dest_i = Signal(range(wid), reset_less=True) # Dest R# in (top) + self.src1_i = Signal(range(wid), reset_less=True) # oper1 R# in (top) + self.src2_i = Signal(range(wid), reset_less=True) # oper2 R# in (top) self.issue_i = Signal(reset_less=True) # Issue in (top) - self.go_wr_i = Signal(reset_less=True) # Go Write in (left) + self.go_wr_i = Signal(reset_less=True) # Go Write in (left) self.go_rd_i = Signal(reset_less=True) # Go Read in (left) self.req_rel_i = Signal(reset_less=True) # request release (left) - self.g_xx_pend_i = Array(Signal(wid, reset_less=True, name="g_pend_i") \ - for i in range(n_dests)) # global rd (right) - self.g_wr_pend_i = Signal(wid, reset_less=True) # global wr (right) + self.g_xx_pend_i = Array(Signal(wid, reset_less=True, name="g_pend_i") + for i in range(n_dests)) # global rd (right) + self.g_wr_pend_i = Signal(wid, reset_less=True) # global wr (right) if shadow_wid: self.shadow_i = Signal(shadow_wid, reset_less=True) - self.s_fail_i = Signal(shadow_wid, reset_less=True) - self.s_good_i = Signal(shadow_wid, reset_less=True) - self.go_die_o = Signal(reset_less=True) + self.s_fail_i = Signal(shadow_wid, reset_less=True) + self.s_good_i = Signal(shadow_wid, reset_less=True) + self.go_die_o = Signal(reset_less=True) # outputs - self.readable_o = Signal(reset_less=True) # Readable out (right) - self.writable_o = Array(Signal(reset_less=True, name="writable_o") \ - for i in range(n_dests)) # writable out (right) - self.busy_o = Signal(reset_less=True) # busy out (left) + self.readable_o = Signal(reset_less=True) # Readable out (right) + self.writable_o = Array(Signal(reset_less=True, name="writable_o") + for i in range(n_dests)) # writable out (right) + self.busy_o = Signal(reset_less=True) # busy out (left) - self.src1_pend_o = Signal(wid, reset_less=True) # src1 pending - self.src2_pend_o = Signal(wid, reset_less=True) # src1 pending - self.rd_pend_o = Signal(wid, reset_less=True) # rd pending (right) - self.xx_pend_o = Array(Signal(wid, reset_less=True, name="pend_o") \ - for i in range(n_dests))# wr pending (right) + self.src1_pend_o = Signal(wid, reset_less=True) # src1 pending + self.src2_pend_o = Signal(wid, reset_less=True) # src1 pending + self.rd_pend_o = Signal(wid, reset_less=True) # rd pending (right) + self.xx_pend_o = Array(Signal(wid, reset_less=True, name="pend_o") + for i in range(n_dests)) # wr pending (right) def elaborate(self, platform): m = Module() @@ -102,8 +103,8 @@ class FnUnit(Elaboratable): for i in range(self.n_dests): m.d.comb += self.xx_pend_o[i].eq(0) # initialise all array - m.d.comb += self.writable_o[i].eq(0) # to zero - m.d.comb += self.readable_o.eq(0) # to zero + m.d.comb += self.writable_o[i].eq(0) # to zero + m.d.comb += self.readable_o.eq(0) # to zero # go_wr latch: reset on go_wr HI, set on issue m.d.comb += wr_l.s.eq(self.issue_i) @@ -114,25 +115,25 @@ class FnUnit(Elaboratable): m.d.comb += rd_l.r.eq(self.go_rd_i | recover) # latch/registers for dest / src1 / src2 - dest_r = Signal(max=self.reg_width, reset_less=True) - src1_r = Signal(max=self.reg_width, reset_less=True) - src2_r = Signal(max=self.reg_width, reset_less=True) + dest_r = Signal(range(self.reg_width), reset_less=True) + src1_r = Signal(range(self.reg_width), reset_less=True) + src2_r = Signal(range(self.reg_width), reset_less=True) # XXX latch based on *issue* rather than !latch (as in book) - latchregister(m, self.dest_i, dest_r, self.issue_i) #wr_l.qn) - latchregister(m, self.src1_i, src1_r, self.issue_i) #wr_l.qn) - latchregister(m, self.src2_i, src2_r, self.issue_i) #wr_l.qn) + latchregister(m, self.dest_i, dest_r, self.issue_i) # wr_l.qn) + latchregister(m, self.src1_i, src1_r, self.issue_i) # wr_l.qn) + latchregister(m, self.src2_i, src2_r, self.issue_i) # wr_l.qn) # dest decoder (use dest reg as input): write-pending out m.d.comb += dest_d.i.eq(dest_r) - m.d.comb += dest_d.n.eq(wr_l.qn) # decode is inverted - m.d.comb += self.busy_o.eq(wr_l.q) # busy if set + m.d.comb += dest_d.n.eq(wr_l.qn) # decode is inverted + m.d.comb += self.busy_o.eq(wr_l.q) # busy if set m.d.comb += xx_pend_o.eq(dest_d.o) # src1/src2 decoder (use src1/2 regs as input): read-pending out m.d.comb += src1_d.i.eq(src1_r) - m.d.comb += src1_d.n.eq(rd_l.qn) # decode is inverted + m.d.comb += src1_d.n.eq(rd_l.qn) # decode is inverted m.d.comb += src2_d.i.eq(src2_r) - m.d.comb += src2_d.n.eq(rd_l.qn) # decode is inverted + m.d.comb += src2_d.n.eq(rd_l.qn) # decode is inverted m.d.comb += self.src1_pend_o.eq(src1_d.o) m.d.comb += self.src2_pend_o.eq(src2_d.o) m.d.comb += self.rd_pend_o.eq(src1_d.o | src2_d.o) @@ -224,6 +225,7 @@ class LDFnUnit(FnUnit): * when rfile_sel_i == 0, int_wr_pend_o is set * when rfile_sel_i == 1, fp_wr_pend_o is set """ + def __init__(self, wid, shadow_wid=0): FnUnit.__init__(self, wid, shadow_wid, n_dests=2) self.int_rd_pend_o = self.rd_pend_o @@ -254,10 +256,11 @@ class STFnUnit(FnUnit): * when rfile_sel_i == 1, fp_wr_pend_o is set * """ + def __init__(self, wid, shadow_wid=0): FnUnit.__init__(self, wid, shadow_wid, n_dests=2, wr_pend=True) self.int_rd_pend_o = self.rd_pend_o # 1st int read-pending vector - self.int2_rd_pend_o = self.xx_pend_o[0] # 2nd int read-pending vector + self.int2_rd_pend_o = self.xx_pend_o[0] # 2nd int read-pending vector self.fp_rd_pend_o = self.xx_pend_o[1] # 1x FP read-pending vector # yes overwrite FnUnit base class g_wr_pend_i vector self.g_int_wr_pend_i = self.g_wr_pend_i = self.g_xx_pend_i[0] @@ -276,7 +279,6 @@ class STFnUnit(FnUnit): self.fp_writable_o.name = "fp_writable_o" - def int_fn_unit_sim(dut): yield dut.dest_i.eq(1) yield dut.issue_i.eq(1) @@ -299,6 +301,7 @@ def int_fn_unit_sim(dut): yield dut.go_wr_i.eq(0) yield + def test_int_fn_unit(): dut = FnUnit(32, 2, 2) vl = rtlil.convert(dut, ports=dut.ports()) @@ -317,5 +320,6 @@ def test_int_fn_unit(): run_simulation(dut, int_fn_unit_sim(dut), vcd_name='test_fn_unit.vcd') + if __name__ == '__main__': test_int_fn_unit() diff --git a/src/soc/scoreboard/ldst_matrix.py b/src/soc/scoreboard/ldst_matrix.py index 1bb75b03..e8911241 100644 --- a/src/soc/scoreboard/ldst_matrix.py +++ b/src/soc/scoreboard/ldst_matrix.py @@ -34,7 +34,7 @@ from nmigen.compat.sim import run_simulation from nmigen.cli import verilog, rtlil from nmigen import Module, Signal, Elaboratable, Array, Cat, Const -from ldst_dep_cell import LDSTDepCell +from .ldst_dep_cell import LDSTDepCell class LDSTDepMatrix(Elaboratable): @@ -45,19 +45,23 @@ class LDSTDepMatrix(Elaboratable): fashion, ORing together. the OR gate from the dependency cell is here. """ + def __init__(self, n_ldst): self.n_ldst = n_ldst # X and Y (FUs) self.ld_pend_i = Signal(n_ldst, reset_less=True) # load pending in self.st_pend_i = Signal(n_ldst, reset_less=True) # store pending in - self.issue_i = Signal(n_ldst, reset_less=True) # Issue in - self.go_die_i = Signal(n_ldst, reset_less=True) # Die/Reset in + self.issue_i = Signal(n_ldst, reset_less=True) # Issue in + self.go_die_i = Signal(n_ldst, reset_less=True) # Die/Reset in - self.load_hit_i = Signal(n_ldst, reset_less=True) # load hit in - self.stwd_hit_i = Signal(n_ldst, reset_less=True) # store w/data hit in + self.load_hit_i = Signal(n_ldst, reset_less=True) # load hit in + self.stwd_hit_i = Signal( + n_ldst, reset_less=True) # store w/data hit in # outputs - self.ld_hold_st_o = Signal(n_ldst, reset_less=True) # load holds st out - self.st_hold_ld_o = Signal(n_ldst, reset_less=True) # st holds load out + self.ld_hold_st_o = Signal( + n_ldst, reset_less=True) # load holds st out + self.st_hold_ld_o = Signal( + n_ldst, reset_less=True) # st holds load out def elaborate(self, platform): m = Module() @@ -92,12 +96,12 @@ class LDSTDepMatrix(Elaboratable): dc.stwd_hit_i.eq(self.stwd_hit_i), dc.load_v_i.eq(self.ld_pend_i), dc.stor_v_i.eq(self.st_pend_i), - ] + ] # connect cell inputs using Cat(*list_of_stuff) m.d.comb += [Cat(*issue_l).eq(self.issue_i), Cat(*go_die_l).eq(self.go_die_i), - ] + ] # connect the load-hold-store / store-hold-load OR-accumulated outputs m.d.comb += self.ld_hold_st_o.eq(Cat(*lhs_l)) m.d.comb += self.st_hold_ld_o.eq(Cat(*shl_l)) @@ -112,7 +116,7 @@ class LDSTDepMatrix(Elaboratable): stor_h_l.append(dc.stor_h_i) m.d.comb += [Cat(*load_h_l).eq(self.ld_pend_i), Cat(*stor_h_l).eq(self.st_pend_i), - ] + ] return m @@ -129,6 +133,7 @@ class LDSTDepMatrix(Elaboratable): def ports(self): return list(self) + def d_matrix_sim(dut): """ XXX TODO """ @@ -151,6 +156,7 @@ def d_matrix_sim(dut): yield dut.go_wr_i.eq(0) yield + def test_d_matrix(): dut = LDSTDepMatrix(n_ldst=4) vl = rtlil.convert(dut, ports=dut.ports()) @@ -159,5 +165,6 @@ def test_d_matrix(): run_simulation(dut, d_matrix_sim(dut), vcd_name='test_ld_st_matrix.vcd') + if __name__ == '__main__': test_d_matrix() diff --git a/src/soc/scoreboard/test_mem2_fu_matrix.py b/src/soc/scoreboard/test_mem2_fu_matrix.py index ed52394c..6090cae2 100644 --- a/src/soc/scoreboard/test_mem2_fu_matrix.py +++ b/src/soc/scoreboard/test_mem2_fu_matrix.py @@ -2,7 +2,7 @@ from nmigen.compat.sim import run_simulation from nmigen.cli import verilog, rtlil from nmigen import Module, Const, Signal, Array, Cat, Elaboratable -from regfile.regfile import RegFileArray, treereduce +from soc.regfile.regfile import RegFileArray, treereduce from soc.scoreboard.global_pending import GlobalPending from soc.scoreboard.group_picker import GroupPicker from soc.scoreboard.issue_unit import IssueUnitGroup, IssueUnitArray, RegDecode @@ -15,23 +15,26 @@ from random import randint, seed from copy import deepcopy from math import log +# FIXME: fixed up imports +from ..experiment.score6600 import IssueToScoreboard, RegSim, instr_q, wait_for_busy_clear, wait_for_issue, CompUnitALUs, CompUnitBR, CompUnitsBase + class Memory(Elaboratable): def __init__(self, regwid, addrw): self.ddepth = regwid/8 - depth = (1<>self.ddepth] + return self.mem[addr >> self.ddepth] def st(self, addr, data): - self.mem[addr>>self.ddepth] = data & ((1<> self.ddepth] = data & ((1 << self.regwid)-1) class Scoreboard(Elaboratable): @@ -78,14 +81,14 @@ class Scoreboard(Elaboratable): self.br_imm_i = Signal(rwid, reset_less=True) # inputs - self.int_dest_i = Signal(max=n_regs, reset_less=True) # Dest R# in - self.int_src1_i = Signal(max=n_regs, reset_less=True) # oper1 R# in - self.int_src2_i = Signal(max=n_regs, reset_less=True) # oper2 R# in - self.reg_enable_i = Signal(reset_less=True) # enable reg decode + self.int_dest_i = Signal(range(n_regs), reset_less=True) # Dest R# in + self.int_src1_i = Signal(range(n_regs), reset_less=True) # oper1 R# in + self.int_src2_i = Signal(range(n_regs), reset_less=True) # oper2 R# in + self.reg_enable_i = Signal(reset_less=True) # enable reg decode # outputs - self.issue_o = Signal(reset_less=True) # instruction was accepted - self.busy_o = Signal(reset_less=True) # at least one CU is busy + self.issue_o = Signal(reset_less=True) # instruction was accepted + self.busy_o = Signal(reset_less=True) # at least one CU is busy # for branch speculation experiment. branch_direction = 0 if # the branch hasn't been met yet. 1 indicates "success", 2 is "fail" @@ -117,7 +120,7 @@ class Scoreboard(Elaboratable): cua = CompUnitALUs(self.rwid, 3) cub = CompUnitBR(self.rwid, 3) m.submodules.cu = cu = CompUnitsBase(self.rwid, [cua, cub]) - bgt = cub.bgt # get at the branch computation unit + bgt = cub.bgt # get at the branch computation unit br1 = cub.br1 # Int FUs @@ -125,10 +128,10 @@ class Scoreboard(Elaboratable): # Count of number of FUs n_intfus = n_int_alus - n_fp_fus = 0 # for now + n_fp_fus = 0 # for now # Integer Priority Picker 1: Adder + Subtractor - intpick1 = GroupPicker(n_intfus) # picks between add, sub, mul and shf + intpick1 = GroupPicker(n_intfus) # picks between add, sub, mul and shf m.submodules.intpick1 = intpick1 # INT/FP Issue Unit @@ -151,21 +154,21 @@ class Scoreboard(Elaboratable): # allow/cancel can be issued as appropriate. m.submodules.specrec = bspec = BranchSpeculationRecord(n_intfus) - #--------- + # --------- # ok start wiring things together... # "now hear de word of de looord... dem bones dem bones dem dryy bones" # https://www.youtube.com/watch?v=pYb8Wm6-QfA - #--------- + # --------- - #--------- + # --------- # Issue Unit is where it starts. set up some in/outs for this module - #--------- - comb += [ regdecode.dest_i.eq(self.int_dest_i), - regdecode.src1_i.eq(self.int_src1_i), - regdecode.src2_i.eq(self.int_src2_i), - regdecode.enable_i.eq(self.reg_enable_i), - self.issue_o.eq(issueunit.issue_o) - ] + # --------- + comb += [regdecode.dest_i.eq(self.int_dest_i), + regdecode.src1_i.eq(self.int_src1_i), + regdecode.src2_i.eq(self.int_src2_i), + regdecode.enable_i.eq(self.reg_enable_i), + self.issue_o.eq(issueunit.issue_o) + ] # take these to outside (issue needs them) comb += cua.oper_i.eq(self.alu_oper_i) @@ -186,9 +189,9 @@ class Scoreboard(Elaboratable): comb += issueunit.busy_i.eq(cu.busy_o) comb += self.busy_o.eq(cu.busy_o.bool()) - #--------- + # --------- # merge shadow matrices outputs - #--------- + # --------- # these are explained in ShadowMatrix docstring, and are to be # connected to the FUReg and FUFU Matrices, to get them to reset @@ -199,9 +202,9 @@ class Scoreboard(Elaboratable): comb += anydie.eq(shadows.go_die_o | bshadow.go_die_o) comb += shreset.eq(bspec.match_g_o | bspec.match_f_o) - #--------- + # --------- # connect fu-fu matrix - #--------- + # --------- # Group Picker... done manually for now. go_rd_o = intpick1.go_rd_o @@ -210,12 +213,12 @@ class Scoreboard(Elaboratable): go_wr_i = intfus.go_wr_i go_die_i = intfus.go_die_i # NOTE: connect to the shadowed versions so that they can "die" (reset) - comb += go_rd_i[0:n_intfus].eq(go_rd_o[0:n_intfus]) # rd - comb += go_wr_i[0:n_intfus].eq(go_wr_o[0:n_intfus]) # wr - comb += go_die_i[0:n_intfus].eq(anydie[0:n_intfus]) # die + comb += go_rd_i[0:n_intfus].eq(go_rd_o[0:n_intfus]) # rd + comb += go_wr_i[0:n_intfus].eq(go_wr_o[0:n_intfus]) # wr + comb += go_die_i[0:n_intfus].eq(anydie[0:n_intfus]) # die # Connect Picker - #--------- + # --------- comb += intpick1.rd_rel_i[0:n_intfus].eq(cu.rd_rel_o[0:n_intfus]) comb += intpick1.req_rel_i[0:n_intfus].eq(cu.req_rel_o[0:n_intfus]) int_rd_o = intfus.readable_o @@ -223,14 +226,14 @@ class Scoreboard(Elaboratable): comb += intpick1.readable_i[0:n_intfus].eq(int_rd_o[0:n_intfus]) comb += intpick1.writable_i[0:n_intfus].eq(int_wr_o[0:n_intfus]) - #--------- + # --------- # Shadow Matrix - #--------- + # --------- comb += shadows.issue_i.eq(fn_issue_o) #comb += shadows.reset_i[0:n_intfus].eq(bshadow.go_die_o[0:n_intfus]) comb += shadows.reset_i[0:n_intfus].eq(bshadow.go_die_o[0:n_intfus]) - #--------- + # --------- # NOTE; this setup is for the instruction order preservation... # connect shadows / go_dies to Computation Units @@ -252,7 +255,7 @@ class Scoreboard(Elaboratable): for i in range(n_intfus): comb += shadows.shadow_i[i][0:n_intfus].eq(prev_shadow) - #--------- + # --------- # ... and this is for branch speculation. it uses the extra bit # tacked onto the ShadowMatrix (hence shadow_wid=n_intfus+1) # only needs to set shadow_i, s_fail_i and s_good_i @@ -267,7 +270,7 @@ class Scoreboard(Elaboratable): with m.If(bactive & (self.branch_succ_i | self.branch_fail_i)): comb += bshadow.issue_i.eq(fn_issue_o) for i in range(n_intfus): - with m.If(fn_issue_o & (Const(1<>self.ddepth] + return self.mem[addr >> self.ddepth] def st(self, addr, data): - self.mem[addr>>self.ddepth] = data & ((1<> self.ddepth] = data & ((1 << self.regwid)-1) class MemFunctionUnits(Elaboratable): @@ -61,19 +65,19 @@ class MemFunctionUnits(Elaboratable): def __init__(self, n_int_alus): self.n_int_alus = n_int_alus - self.ld_i = Signal(n_int_alus, reset_less=True) # Dest R# in - self.st_i = Signal(n_int_alus, reset_less=True) # oper1 R# in + self.ld_i = Signal(n_int_alus, reset_less=True) # Dest R# in + self.st_i = Signal(n_int_alus, reset_less=True) # oper1 R# in - self.load_hit_i = Signal(n_int_alus, reset_less=True) # Load Hit - self.stwd_hit_i = Signal(n_int_alus, reset_less=True) # Store Hit + self.load_hit_i = Signal(n_int_alus, reset_less=True) # Load Hit + self.stwd_hit_i = Signal(n_int_alus, reset_less=True) # Store Hit #self.g_int_st_pend_o = Signal(n_int_alus, reset_less=True) #self.g_int_ld_pend_o = Signal(n_int_alus, reset_less=True) - #self.ld_rsel_o = Signal(n_int_alus, reset_less=True) # dest reg (bot) - #self.st_rsel_o = Signal(n_int_alus, reset_less=True) # src1 reg (bot) + # self.ld_rsel_o = Signal(n_int_alus, reset_less=True) # dest reg (bot) + # self.st_rsel_o = Signal(n_int_alus, reset_less=True) # src1 reg (bot) - self.req_rel_i = Signal(n_int_alus, reset_less = True) + self.req_rel_i = Signal(n_int_alus, reset_less=True) self.loadable_o = Signal(n_int_alus, reset_less=True) self.storable_o = Signal(n_int_alus, reset_less=True) @@ -107,7 +111,7 @@ class MemFunctionUnits(Elaboratable): #comb += ldstdeps.st_pend_i.eq(fumemdeps.st_pend_o) #comb += ldstdeps.ld_pend_i.eq(fumemdeps.ld_pend_o) - #self.ld_pend_o = fumemdeps.ld_pend_o # also output for use in WaWGrid + # self.ld_pend_o = fumemdeps.ld_pend_o # also output for use in WaWGrid comb += ldstdeps.ld_pend_i.eq(self.ld_i) comb += ldstdeps.st_pend_i.eq(self.st_i) @@ -135,10 +139,10 @@ class MemFunctionUnits(Elaboratable): def __iter__(self): yield self.ld_i yield self.st_i - #yield self.g_int_st_pend_o - #yield self.g_int_ld_pend_o - #yield self.ld_rsel_o - #yield self.st_rsel_o + # yield self.g_int_st_pend_o + # yield self.g_int_ld_pend_o + # yield self.ld_rsel_o + # yield self.st_rsel_o yield self.req_rel_i yield self.loadable_o yield self.storable_o @@ -178,14 +182,14 @@ class Scoreboard(Elaboratable): self.br_imm_i = Signal(rwid, reset_less=True) # inputs - self.int_dest_i = Signal(max=n_regs, reset_less=True) # Dest R# in - self.int_src1_i = Signal(max=n_regs, reset_less=True) # oper1 R# in - self.int_src2_i = Signal(max=n_regs, reset_less=True) # oper2 R# in - self.reg_enable_i = Signal(reset_less=True) # enable reg decode + self.int_dest_i = Signal(range(n_regs), reset_less=True) # Dest R# in + self.int_src1_i = Signal(range(n_regs), reset_less=True) # oper1 R# in + self.int_src2_i = Signal(range(n_regs), reset_less=True) # oper2 R# in + self.reg_enable_i = Signal(reset_less=True) # enable reg decode # outputs - self.issue_o = Signal(reset_less=True) # instruction was accepted - self.busy_o = Signal(reset_less=True) # at least one CU is busy + self.issue_o = Signal(reset_less=True) # instruction was accepted + self.busy_o = Signal(reset_less=True) # at least one CU is busy # for branch speculation experiment. branch_direction = 0 if # the branch hasn't been met yet. 1 indicates "success", 2 is "fail" @@ -217,7 +221,7 @@ class Scoreboard(Elaboratable): cua = CompUnitALUs(self.rwid, 3) cub = CompUnitBR(self.rwid, 3) m.submodules.cu = cu = CompUnitsBase(self.rwid, [cua, cub]) - bgt = cub.bgt # get at the branch computation unit + bgt = cub.bgt # get at the branch computation unit br1 = cub.br1 # Int FUs @@ -225,10 +229,10 @@ class Scoreboard(Elaboratable): # Count of number of FUs n_intfus = n_int_alus - n_fp_fus = 0 # for now + n_fp_fus = 0 # for now # Integer Priority Picker 1: Adder + Subtractor - intpick1 = GroupPicker(n_intfus) # picks between add, sub, mul and shf + intpick1 = GroupPicker(n_intfus) # picks between add, sub, mul and shf m.submodules.intpick1 = intpick1 # INT/FP Issue Unit @@ -251,21 +255,21 @@ class Scoreboard(Elaboratable): # allow/cancel can be issued as appropriate. m.submodules.specrec = bspec = BranchSpeculationRecord(n_intfus) - #--------- + # --------- # ok start wiring things together... # "now hear de word of de looord... dem bones dem bones dem dryy bones" # https://www.youtube.com/watch?v=pYb8Wm6-QfA - #--------- + # --------- - #--------- + # --------- # Issue Unit is where it starts. set up some in/outs for this module - #--------- - comb += [ regdecode.dest_i.eq(self.int_dest_i), - regdecode.src1_i.eq(self.int_src1_i), - regdecode.src2_i.eq(self.int_src2_i), - regdecode.enable_i.eq(self.reg_enable_i), - self.issue_o.eq(issueunit.issue_o) - ] + # --------- + comb += [regdecode.dest_i.eq(self.int_dest_i), + regdecode.src1_i.eq(self.int_src1_i), + regdecode.src2_i.eq(self.int_src2_i), + regdecode.enable_i.eq(self.reg_enable_i), + self.issue_o.eq(issueunit.issue_o) + ] # take these to outside (issue needs them) comb += cua.oper_i.eq(self.alu_oper_i) @@ -286,9 +290,9 @@ class Scoreboard(Elaboratable): comb += issueunit.busy_i.eq(cu.busy_o) comb += self.busy_o.eq(cu.busy_o.bool()) - #--------- + # --------- # merge shadow matrices outputs - #--------- + # --------- # these are explained in ShadowMatrix docstring, and are to be # connected to the FUReg and FUFU Matrices, to get them to reset @@ -299,9 +303,9 @@ class Scoreboard(Elaboratable): comb += anydie.eq(shadows.go_die_o | bshadow.go_die_o) comb += shreset.eq(bspec.match_g_o | bspec.match_f_o) - #--------- + # --------- # connect fu-fu matrix - #--------- + # --------- # Group Picker... done manually for now. go_rd_o = intpick1.go_rd_o @@ -310,12 +314,12 @@ class Scoreboard(Elaboratable): go_wr_i = intfus.go_wr_i go_die_i = intfus.go_die_i # NOTE: connect to the shadowed versions so that they can "die" (reset) - comb += go_rd_i[0:n_intfus].eq(go_rd_o[0:n_intfus]) # rd - comb += go_wr_i[0:n_intfus].eq(go_wr_o[0:n_intfus]) # wr - comb += go_die_i[0:n_intfus].eq(anydie[0:n_intfus]) # die + comb += go_rd_i[0:n_intfus].eq(go_rd_o[0:n_intfus]) # rd + comb += go_wr_i[0:n_intfus].eq(go_wr_o[0:n_intfus]) # wr + comb += go_die_i[0:n_intfus].eq(anydie[0:n_intfus]) # die # Connect Picker - #--------- + # --------- comb += intpick1.rd_rel_i[0:n_intfus].eq(cu.rd_rel_o[0:n_intfus]) comb += intpick1.req_rel_i[0:n_intfus].eq(cu.req_rel_o[0:n_intfus]) int_rd_o = intfus.readable_o @@ -323,14 +327,14 @@ class Scoreboard(Elaboratable): comb += intpick1.readable_i[0:n_intfus].eq(int_rd_o[0:n_intfus]) comb += intpick1.writable_i[0:n_intfus].eq(int_wr_o[0:n_intfus]) - #--------- + # --------- # Shadow Matrix - #--------- + # --------- comb += shadows.issue_i.eq(fn_issue_o) #comb += shadows.reset_i[0:n_intfus].eq(bshadow.go_die_o[0:n_intfus]) comb += shadows.reset_i[0:n_intfus].eq(bshadow.go_die_o[0:n_intfus]) - #--------- + # --------- # NOTE; this setup is for the instruction order preservation... # connect shadows / go_dies to Computation Units @@ -352,7 +356,7 @@ class Scoreboard(Elaboratable): for i in range(n_intfus): comb += shadows.shadow_i[i][0:n_intfus].eq(prev_shadow) - #--------- + # --------- # ... and this is for branch speculation. it uses the extra bit # tacked onto the ShadowMatrix (hence shadow_wid=n_intfus+1) # only needs to set shadow_i, s_fail_i and s_good_i @@ -367,7 +371,7 @@ class Scoreboard(Elaboratable): with m.If(bactive & (self.branch_succ_i | self.branch_fail_i)): comb += bshadow.issue_i.eq(fn_issue_o) for i in range(n_intfus): - with m.If(fn_issue_o & (Const(1<