From 2e3b1eaed4122461c936f923c8c91b73d7848819 Mon Sep 17 00:00:00 2001 From: Luke Kenneth Casson Leighton Date: Thu, 17 Feb 2022 17:09:21 +0000 Subject: [PATCH] add opencores SDRAM verilog wrapper --- src/soc/bus/sdr_ctrl.py | 206 ++++++++++++++++++++++ src/soc/experiment/icache.py | 322 ++++++++++++++++++----------------- 2 files changed, 369 insertions(+), 159 deletions(-) create mode 100644 src/soc/bus/sdr_ctrl.py diff --git a/src/soc/bus/sdr_ctrl.py b/src/soc/bus/sdr_ctrl.py new file mode 100644 index 00000000..ed3a94ea --- /dev/null +++ b/src/soc/bus/sdr_ctrl.py @@ -0,0 +1,206 @@ +#!/usr/bin/env python3 +# +# SPDX-License-Identifier: LGPLv3+ +# Copyright (C) 2022 Luke Kenneth Casson Leighton +# Sponsored by NLnet and NGI POINTER under EU Grants 871528 and 957073 +# Part of the Libre-SOC Project. +# +# this is a wrapper around the opencores verilog uart16550 module + +from nmigen import (Elaboratable, Cat, Module, Signal, ClockSignal, Instance, + ResetSignal) + +from nmigen_soc.wishbone.bus import Interface +from nmigen.cli import rtlil, verilog +import os + +__all__ = ["SDRAM"] + + +class SDRAM(Elaboratable): + """SDRAM controller from opencores, nmigen wrapper. remember to call + SDRAM.add_verilog_source. + + * the SDRAM IC will be accessible over the Wishbone Bus + * sdr_* signals must be wired to the IC + * cfg_* parameters must match those listed in the SDRAM IC's datasheet + """ + + def __init__(self, bus=None, features=None, name=None, + data_width=32, addr_width=26, + sdr_data_width=16, + pins=None): + if name is not None: + name = "sdram" + self.data_width = data_width + self.sdr_data_width = sdr_data_width + self.addr_width = addr_width + self.refresh_timer_sz = 12 + self.refresh_row_count = 3 + + # set up the wishbone bus + if features is None: + features = frozenset({'cti'}) + if bus is None: + bus = Interface(addr_width=addr_width, + data_width=data_width, + features=features, + granularity=8, + name=name) + self.bus = bus + assert len(self.bus.dat_r) == data_width, \ + "bus width must be %d" % data_width + + byte_width = sdr_data_width // 8 # for individual byte masks/enables + + # SDRAM signals + self.sdram_clk = Signal() # sdram phy clock + self.sdram_resetn = Signal(reset_less=True) # sdram reset (low) + self.sdr_cs_n = Signal() # chip select + self.sdr_cke = Signal() # clock-enable + self.sdr_ras_n = Signal() # read-address strobe + self.sdr_cas_n = Signal() # cas + self.sdr_we_n = Signal() # write-enable + self.sdr_dqm = Signal(byte_width) # data mask + self.sdr_ba = Signal(2) # bank enable + self.sdr_addr = Signal(13) # sdram address, 13 bits + # these combine to create a bi-direction inout, sdr_dq + # note, each bit of sdr_den_n covers a *byte* of sdr_din/sdr_dout + self.sdr_den_n = Signal(byte_width) + self.sdr_din = Signal(data_width) + self.sdr_dout = Signal(data_width) + + # configuration parameters, these need to match the SDRAM IC datasheet + self.sdr_init_done = Signal() # Indicate SDRAM init Done + self.cfg_req_depth = Signal(2) # max request accepted + self.cfg_sdr_en = Signal() # Enable SDRAM controller + self.cfg_sdr_mode_reg = Signal(13) + self.cfg_sdr_tras_d = Signal(4) # Active to precharge delay + self.cfg_sdr_trp_d = Signal(4) # Precharge to active delay + self.cfg_sdr_trcd_d = Signal(4) # Active to R/W delay + self.cfg_sdr_cas = Signal(3) # SDRAM CAS Latency + self.cfg_sdr_trcar_d = Signal(4) # Auto-refresh period + self.cfg_sdr_twr_d = Signal(4) # Write recovery delay + self.cfg_sdr_rfsh = Signal(self.refresh_timer_sz) + self.cfg_sdr_rfmax = Signal(self.refresh_row_count) + + # pins resource + self.pins = pins + + @classmethod + def add_verilog_source(cls, verilog_src_dir, platform): + # add each of the verilog sources, needed for when doing platform.build + for fname in [ './core/sdrc_bank_ctl.v', './core/sdrc_bank_fsm.v', + './core/sdrc_bs_convert.v', './core/sdrc_core.v', + './core/sdrc_req_gen.v', './core/sdrc_xfr_ctl.v', + './core/sdrc_define.v', + './lib/async_fifo.v', './lib/sync_fifo.v', + './top/sdrc_top.v', './wb2sdrc/wb2sdrc.v', + ]: + # prepend the src directory to each filename, add its contents + fullname = os.path.join(verilog_src_dir, fname) + with open(fullname) as f: + platform.add_file(fullname, f) + + def elaborate(self, platform): + m = Module() + comb = m.d.comb + + # create definition of external verilog 16550 uart here, so that # nmigen understands I/O directions (defined by i_ and o_ prefixes) + bus = self.bus + + params = { + # clock/reset (use DomainRenamer if needed) + 'i_wb_clk_i' : ClockSignal(), + 'i_wb_rst_i' : ResetSignal(), + + # wishbone bus signals + 'i_wb_adr_i' : bus.adr, + 'i_wb_dat_i' : bus.dat_w, + 'i_wb_sel_i' : bus.sel, + 'o_wb_dat_o' : bus.dat_r, + 'i_wb_we_i' : bus.we, + 'i_wb_stb_i' : bus.stb, + 'i_wb_cyc_i' : bus.cyc, + 'o_wb_ack_o' : bus.ack, + + # SDRAM signals + 'i_sdram_clk' : self.sdram_clk, + 'i_sdram_resetn' : self.sdram_resetn, + 'o_sdr_cs_n' : self.sdr_cs_n, + 'o_sdr_cke' : self.sdr_cke, + 'o_sdr_ras_n' : self.sdr_ras_n, + 'o_sdr_cas_n' : self.sdr_cas_n, + 'o_sdr_we_n' : self.sdr_we_n, + 'o_sdr_dqm' : self.sdr_dqm, + 'o_sdr_ba' : self.sdr_ba, + 'o_sdr_addr' : self.sdr_addr, + 'o_sdr_den_n' : self.sdr_den_n, + 'i_sdr_din' : self.sdr_din, + 'o_sdr_dout' : self.sdr_dout, + + # configuration parameters (from the SDRAM IC datasheet) + 'o_sdr_init_done' : self.sdr_init_done , + 'i_cfg_req_depth' : self.cfg_req_depth , + 'i_cfg_sdr_en' : self.cfg_sdr_en , + 'i_cfg_sdr_mode_reg' : self.cfg_sdr_mode_reg , + 'i_cfg_sdr_tras_d' : self.cfg_sdr_tras_d , + 'i_cfg_sdr_trp_d' : self.cfg_sdr_trp_d , + 'i_cfg_sdr_trcd_d' : self.cfg_sdr_trcd_d , + 'i_cfg_sdr_cas' : self.cfg_sdr_cas , + 'i_cfg_sdr_trcar_d' : self.cfg_sdr_trcar_d , + 'i_cfg_sdr_twr_d' : self.cfg_sdr_twr_d , + 'i_cfg_sdr_rfsh' : self.cfg_sdr_rfsh , + 'i_cfg_sdr_rfmax' : self.cfg_sdr_rfmax, + + # verilog parameters + 'p_APP_AW' : self.addr_width, # Application Address Width + 'p_APP_DW' : self.data_width, # Application Data Width + 'p_APP_BW' : self.addr_width//8, # Application Byte Width + 'p_APP_RW' : 9, # Application Request Width + 'p_SDR_DW' : self.sdr_data_width, # SDR Data Width + 'p_SDR_BW' : self.sdr_data_width//8, # SDR Byte Width + 'p_dw' : self.data_width, # data width + 'p_tw' : 8, # tag id width + 'p_bl' : 9, # burst_length_width + } + m.submodules['sdrc_top'] = Instance("sdrc_top", **params) + + return m + + if self.pins is not None: + comb += self.pins.tx.eq(self.tx_o) + comb += self.rx_i.eq(self.pins.rx) + + return m + + +def create_ilang(dut, ports, test_name): + vl = rtlil.convert(dut, name=test_name, ports=ports) + with open("%s.il" % test_name, "w") as f: + f.write(vl) + +def create_verilog(dut, ports, test_name): + vl = verilog.convert(dut, name=test_name, ports=ports) + with open("%s.v" % test_name, "w") as f: + f.write(vl) + + +if __name__ == "__main__": + sdram = SDRAM(name="sdram", data_width=8) + create_ilang(sdram, [sdram.bus.cyc, sdram.bus.stb, sdram.bus.ack, + sdram.bus.dat_r, sdram.bus.dat_w, sdram.bus.adr, + sdram.bus.we, sdram.bus.sel, + sdram.sdram_clk, sdram.sdram_resetn, + sdram.sdr_cs_n, sdram.sdr_cke, + sdram.sdr_ras_n, sdram.sdr_cas_n, sdram.sdr_we_n, + sdram.sdr_dqm, sdram.sdr_ba, sdram.sdr_addr, + sdram.sdr_den_n, sdram.sdr_din, sdram.sdr_dout, + sdram.sdr_init_done, sdram.cfg_req_depth, + sdram.cfg_sdr_en, sdram.cfg_sdr_mode_reg, + sdram.cfg_sdr_tras_d, sdram.cfg_sdr_trp_d, + sdram.cfg_sdr_trcd_d, sdram.cfg_sdr_cas, + sdram.cfg_sdr_trcar_d, sdram.cfg_sdr_twr_d, + sdram.cfg_sdr_rfsh, sdram.cfg_sdr_rfmax, + ], "sdram") + diff --git a/src/soc/experiment/icache.py b/src/soc/experiment/icache.py index 9c8cafd7..57b738c6 100644 --- a/src/soc/experiment/icache.py +++ b/src/soc/experiment/icache.py @@ -63,110 +63,114 @@ from nmigen.cli import main, rtlil # Also, check out the cxxsim nmigen branch, and latest yosys from git from nmutil.sim_tmp_alternative import Simulator, Settle +# from microwatt/utils.vhdl +def ispow2(n): + return n != 0 and (n & (n - 1)) == 0 SIM = 0 -LINE_SIZE = 64 +# Non-zero to enable log data collection +LOG_LENGTH = 0 + +class ICacheConfig: + def __init__(self, self.LINE_SIZE = 64 + self.NUM_LINE = 16 # Number of lines in a set + self.NUM_WAYS = 1, # Number of ways + self.TLB_SIZE = 64, # L1 ITLB number of entries + self.TLB_LG_PGSZ = 12): # L1 ITLB log_2(page_size) +self.LINE_SIZE = 64 +self.NUM_LINE = 16 # Number of lines in a set +self.NUM_WAYS = 1 # Number of ways +self.TLB_SIZE = 64 # L1 ITLB number of entries +self.TLB_LG_PGSZ = 12 # L1 ITLB log_2(page_size) + # BRAM organisation: We never access more than wishbone_data_bits # at a time so to save resources we make the array only that wide, # and use consecutive indices for to make a cache "line" # -# ROW_SIZE is the width in bytes of the BRAM (based on WB, so 64-bits) -ROW_SIZE = WB_DATA_BITS // 8 -# Number of lines in a set -NUM_LINES = 64 -# Number of ways -NUM_WAYS = 2 -# L1 ITLB number of entries (direct mapped) -TLB_SIZE = 64 -# L1 ITLB log_2(page_size) -TLB_LG_PGSZ = 12 +# self.ROW_SIZE is the width in bytes of the BRAM (based on WB, so 64-bits) +self.ROW_SIZE = WB_DATA_BITS // 8 # Number of real address bits that we store -REAL_ADDR_BITS = 56 -# Non-zero to enable log data collection -LOG_LENGTH = 0 +self.REAL_ADDR_BITS = 56 -ROW_SIZE_BITS = ROW_SIZE * 8 +self.ROW_SIZE_BITS = self.ROW_SIZE * 8 # ROW_PER_LINE is the number of row (wishbone) transactions in a line -ROW_PER_LINE = LINE_SIZE // ROW_SIZE -# BRAM_ROWS is the number of rows in BRAM needed to represent the full icache -BRAM_ROWS = NUM_LINES * ROW_PER_LINE +self.ROW_PER_LINE = self.LINE_SIZE // self.ROW_SIZE +# BRAM_ROWS is the number of rows in BRAM +# needed to represent the full icache +self.BRAM_ROWS = self.NUM_LINE * self.ROW_PER_LINE # INSN_PER_ROW is the number of 32bit instructions per BRAM row -INSN_PER_ROW = ROW_SIZE_BITS // 32 +self.INSN_PER_ROW = self.ROW_SIZE_BITS // 32 # Bit fields counts in the address # # INSN_BITS is the number of bits to select an instruction in a row -INSN_BITS = log2_int(INSN_PER_ROW) +self.INSN_BITS = log2_int(self.INSN_PER_ROW) # ROW_BITS is the number of bits to select a row -ROW_BITS = log2_int(BRAM_ROWS) +self.ROW_BITS = log2_int(self.BRAM_ROWS) # ROW_LINE_BITS is the number of bits to select a row within a line -ROW_LINE_BITS = log2_int(ROW_PER_LINE) +self.ROW_LINE_BITS = log2_int(self.ROW_PER_LINE) # LINE_OFF_BITS is the number of bits for the offset in a cache line -LINE_OFF_BITS = log2_int(LINE_SIZE) +self.LINE_OFF_BITS = log2_int(self.LINE_SIZE) # ROW_OFF_BITS is the number of bits for the offset in a row -ROW_OFF_BITS = log2_int(ROW_SIZE) +self.ROW_OFF_BITS = log2_int(self.ROW_SIZE) # INDEX_BITS is the number of bits to select a cache line -INDEX_BITS = log2_int(NUM_LINES) +self.INDEX_BITS = log2_int(self.NUM_LINE) # SET_SIZE_BITS is the log base 2 of the set size -SET_SIZE_BITS = LINE_OFF_BITS + INDEX_BITS +self.SET_SIZE_BITS = self.LINE_OFF_BITS + self.INDEX_BITS # TAG_BITS is the number of bits of the tag part of the address -TAG_BITS = REAL_ADDR_BITS - SET_SIZE_BITS +self.TAG_BITS = self.REAL_ADDR_BITS - self.SET_SIZE_BITS # TAG_WIDTH is the width in bits of each way of the tag RAM -TAG_WIDTH = TAG_BITS + 7 - ((TAG_BITS + 7) % 8) +self.TAG_WIDTH = self.TAG_BITS + 7 - ((self.TAG_BITS + 7) % 8) # WAY_BITS is the number of bits to select a way -WAY_BITS = log2_int(NUM_WAYS) -TAG_RAM_WIDTH = TAG_BITS * NUM_WAYS +self.WAY_BITS = log2_int(self.NUM_WAYS) +self.TAG_RAM_WIDTH = self.TAG_BITS * self.NUM_WAYS # L1 ITLB -TLB_BITS = log2_int(TLB_SIZE) -TLB_EA_TAG_BITS = 64 - (TLB_LG_PGSZ + TLB_BITS) -TLB_PTE_BITS = 64 - -print("BRAM_ROWS =", BRAM_ROWS) -print("INDEX_BITS =", INDEX_BITS) -print("INSN_BITS =", INSN_BITS) -print("INSN_PER_ROW =", INSN_PER_ROW) -print("LINE_SIZE =", LINE_SIZE) -print("LINE_OFF_BITS =", LINE_OFF_BITS) +self.TL_BITS = log2_int(self.TLB_SIZE) +self.TLB_EA_TAG_BITS = 64 - (self.TLB_LG_PGSZ + self.TL_BITS) +self.TLB_PTE_BITS = 64 + +print("self.BRAM_ROWS =", self.BRAM_ROWS) +print("self.INDEX_BITS =", self.INDEX_BITS) +print("self.INSN_BITS =", self.INSN_BITS) +print("self.INSN_PER_ROW =", self.INSN_PER_ROW) +print("self.LINE_SIZE =", self.LINE_SIZE) +print("self.LINE_OFF_BITS =", self.LINE_OFF_BITS) print("LOG_LENGTH =", LOG_LENGTH) -print("NUM_LINES =", NUM_LINES) -print("NUM_WAYS =", NUM_WAYS) -print("REAL_ADDR_BITS =", REAL_ADDR_BITS) -print("ROW_BITS =", ROW_BITS) -print("ROW_OFF_BITS =", ROW_OFF_BITS) -print("ROW_LINE_BITS =", ROW_LINE_BITS) -print("ROW_PER_LINE =", ROW_PER_LINE) -print("ROW_SIZE =", ROW_SIZE) -print("ROW_SIZE_BITS =", ROW_SIZE_BITS) -print("SET_SIZE_BITS =", SET_SIZE_BITS) +print("self.NUM_LINE =", self.NUM_LINE) +print("self.NUM_WAYS =", self.NUM_WAYS) +print("self.REAL_ADDR_BITS =", self.REAL_ADDR_BITS) +print("self.ROW_BITS =", self.ROW_BITS) +print("self.ROW_OFF_BITS =", self.ROW_OFF_BITS) +print("self.ROW_LINE_BITS =", self.ROW_LINE_BITS) +print("self.ROW_PER_LINE =", self.ROW_PER_LINE) +print("self.ROW_SIZE =", self.ROW_SIZE) +print("self.ROW_SIZE_BITS =", self.ROW_SIZE_BITS) +print("self.SET_SIZE_BITS =", self.SET_SIZE_BITS) print("SIM =", SIM) -print("TAG_BITS =", TAG_BITS) -print("TAG_RAM_WIDTH =", TAG_RAM_WIDTH) -print("TAG_BITS =", TAG_BITS) -print("TLB_BITS =", TLB_BITS) -print("TLB_EA_TAG_BITS =", TLB_EA_TAG_BITS) -print("TLB_LG_PGSZ =", TLB_LG_PGSZ) -print("TLB_PTE_BITS =", TLB_PTE_BITS) -print("TLB_SIZE =", TLB_SIZE) -print("WAY_BITS =", WAY_BITS) - -# from microwatt/utils.vhdl -def ispow2(n): - return n != 0 and (n & (n - 1)) == 0 - -assert LINE_SIZE % ROW_SIZE == 0 -assert ispow2(LINE_SIZE), "LINE_SIZE not power of 2" -assert ispow2(NUM_LINES), "NUM_LINES not power of 2" -assert ispow2(ROW_PER_LINE), "ROW_PER_LINE not power of 2" -assert ispow2(INSN_PER_ROW), "INSN_PER_ROW not power of 2" -assert (ROW_BITS == (INDEX_BITS + ROW_LINE_BITS)), \ +print("self.TAG_BITS =", self.TAG_BITS) +print("self.TAG_RAM_WIDTH =", self.TAG_RAM_WIDTH) +print("self.TAG_BITS =", self.TAG_BITS) +print("self.TL_BITS =", self.TL_BITS) +print("self.TLB_EA_TAG_BITS =", self.TLB_EA_TAG_BITS) +print("self.TLB_LG_PGSZ =", self.TLB_LG_PGSZ) +print("self.TLB_PTE_BITS =", self.TLB_PTE_BITS) +print("self.TLB_SIZE =", self.TLB_SIZE) +print("self.WAY_BITS =", self.WAY_BITS) + +assert self.LINE_SIZE % self.ROW_SIZE == 0 +assert ispow2(self.LINE_SIZE), "self.LINE_SIZE not power of 2" +assert ispow2(self.NUM_LINE), "self.NUM_LINE not power of 2" +assert ispow2(self.ROW_PER_LINE), "self.ROW_PER_LINE not power of 2" +assert ispow2(self.INSN_PER_ROW), "self.INSN_PER_ROW not power of 2" +assert (self.ROW_BITS == (self.INDEX_BITS + self.ROW_LINE_BITS)), \ "geometry bits don't add up" -assert (LINE_OFF_BITS == (ROW_OFF_BITS + ROW_LINE_BITS)), \ +assert (self.LINE_OFF_BITS == (self.ROW_OFF_BITS + self.ROW_LINE_BITS)), \ "geometry bits don't add up" -assert (REAL_ADDR_BITS == (TAG_BITS + INDEX_BITS + LINE_OFF_BITS)), \ +assert (self.REAL_ADDR_BITS == (self.TAG_BITS + self.INDEX_BITS + self.LINE_OFF_BITS)), \ "geometry bits don't add up" -assert (REAL_ADDR_BITS == (TAG_BITS + ROW_BITS + ROW_OFF_BITS)), \ +assert (self.REAL_ADDR_BITS == (self.TAG_BITS + self.ROW_BITS + self.ROW_OFF_BITS)), \ "geometry bits don't add up" # Example of layout for 32 lines of 64 bytes: @@ -174,20 +178,20 @@ assert (REAL_ADDR_BITS == (TAG_BITS + ROW_BITS + ROW_OFF_BITS)), \ # .. tag |index| line | # .. | row | | # .. | | | |00| zero (2) -# .. | | |-| | INSN_BITS (1) -# .. | |---| | ROW_LINE_BITS (3) -# .. | |--- - --| LINE_OFF_BITS (6) -# .. | |- --| ROW_OFF_BITS (3) -# .. |----- ---| | ROW_BITS (8) -# .. |-----| | INDEX_BITS (5) -# .. --------| | TAG_BITS (53) +# .. | | |-| | self.INSN_BITS (1) +# .. | |---| | self.ROW_LINE_BITS (3) +# .. | |--- - --| self.LINE_OFF_BITS (6) +# .. | |- --| self.ROW_OFF_BITS (3) +# .. |----- ---| | self.ROW_BITS (8) +# .. |-----| | self.INDEX_BITS (5) +# .. --------| | self.TAG_BITS (53) # The cache data BRAM organized as described above for each way -#subtype cache_row_t is std_ulogic_vector(ROW_SIZE_BITS-1 downto 0); +#subtype cache_row_t is std_ulogic_vector(self.ROW_SIZE_BITS-1 downto 0); # def RowPerLineValidArray(): return Array(Signal(name="rows_valid_%d" %x) \ - for x in range(ROW_PER_LINE)) + for x in range(self.ROW_PER_LINE)) # TODO to be passed to nigmen as ram attributes @@ -195,34 +199,34 @@ def RowPerLineValidArray(): # attribute ram_style of cache_tags : signal is "distributed"; def TLBRecord(name): - tlb_layout = [ ('tag', TLB_EA_TAG_BITS), - ('pte', TLB_PTE_BITS) + tlb_layout = [ ('tag', self.TLB_EA_TAG_BITS), + ('pte', self.TLB_PTE_BITS) ] return Record(tlb_layout, name=name) def TLBArray(): - return Array(TLBRecord("tlb%d" % x) for x in range(TLB_SIZE)) + return Array(TLBRecord("tlb%d" % x) for x in range(self.TLB_SIZE)) # PLRU output interface def PLRUOut(): - return Array(Signal(WAY_BITS, name="plru_out_%d" %x) \ - for x in range(NUM_LINES)) + return Array(Signal(self.WAY_BITS, name="plru_out_%d" %x) \ + for x in range(self.NUM_LINE)) # Return the cache line index (tag index) for an address def get_index(addr): - return addr[LINE_OFF_BITS:SET_SIZE_BITS] + return addr[self.LINE_OFF_BITS:self.SET_SIZE_BITS] # Return the cache row index (data memory) for an address def get_row(addr): - return addr[ROW_OFF_BITS:SET_SIZE_BITS] + return addr[self.ROW_OFF_BITS:self.SET_SIZE_BITS] # Return the index of a row within a line def get_row_of_line(row): - return row[:ROW_BITS][:ROW_LINE_BITS] + return row[:self.ROW_BITS][:self.ROW_LINE_BITS] # Returns whether this is the last row of a line def is_last_row_addr(addr, last): - return addr[ROW_OFF_BITS:LINE_OFF_BITS] == last + return addr[self.ROW_OFF_BITS:self.LINE_OFF_BITS] == last # Returns whether this is the last row of a line def is_last_row(row, last): @@ -232,22 +236,22 @@ def is_last_row(row, last): # function in order to limit the size of the generated adder to be # only the bits within a cache line (3 bits with default settings) def next_row(row): - row_v = row[0:ROW_LINE_BITS] + 1 - return Cat(row_v[:ROW_LINE_BITS], row[ROW_LINE_BITS:]) + row_v = row[0:self.ROW_LINE_BITS] + 1 + return Cat(row_v[:self.ROW_LINE_BITS], row[self.ROW_LINE_BITS:]) # Read the instruction word for the given address # in the current cache row def read_insn_word(addr, data): - word = addr[2:INSN_BITS+2] + word = addr[2:self.INSN_BITS+2] return data.word_select(word, 32) # Get the tag value from the address def get_tag(addr): - return addr[SET_SIZE_BITS:REAL_ADDR_BITS] + return addr[self.SET_SIZE_BITS:self.REAL_ADDR_BITS] # Read a tag from a tag memory row def read_tag(way, tagset): - return tagset.word_select(way, TAG_BITS) + return tagset.word_select(way, self.TAG_BITS) # Write a tag to tag memory row def write_tag(way, tagset, tag): @@ -255,9 +259,9 @@ def write_tag(way, tagset, tag): # Simple hash for direct-mapped TLB index def hash_ea(addr): - hsh = (addr[TLB_LG_PGSZ:TLB_LG_PGSZ + TLB_BITS] ^ - addr[TLB_LG_PGSZ + TLB_BITS:TLB_LG_PGSZ + 2 * TLB_BITS ] ^ - addr[TLB_LG_PGSZ + 2 * TLB_BITS:TLB_LG_PGSZ + 3 * TLB_BITS]) + hsh = (addr[self.TLB_LG_PGSZ:self.TLB_LG_PGSZ + self.TL_BITS] ^ + addr[self.TLB_LG_PGSZ + self.TL_BITS:self.TLB_LG_PGSZ + 2 * self.TL_BITS ] ^ + addr[self.TLB_LG_PGSZ + 2 * self.TL_BITS:self.TLB_LG_PGSZ + 3 * self.TL_BITS]) return hsh @@ -273,7 +277,7 @@ class RegInternal(RecordObject): def __init__(self): super().__init__() # Cache hit state (Latches for 1 cycle BRAM access) - self.hit_way = Signal(WAY_BITS) + self.hit_way = Signal(self.WAY_BITS) self.hit_nia = Signal(64) self.hit_smark = Signal() self.hit_valid = Signal() @@ -282,12 +286,12 @@ class RegInternal(RecordObject): self.state = Signal(State, reset=State.IDLE) self.wb = WBMasterOut("wb") self.req_adr = Signal(64) - self.store_way = Signal(WAY_BITS) - self.store_index = Signal(INDEX_BITS) - self.store_row = Signal(ROW_BITS) - self.store_tag = Signal(TAG_BITS) + self.store_way = Signal(self.WAY_BITS) + self.store_index = Signal(self.INDEX_BITS) + self.store_row = Signal(self.ROW_BITS) + self.store_tag = Signal(self.TAG_BITS) self.store_valid = Signal() - self.end_row_ix = Signal(ROW_LINE_BITS) + self.end_row_ix = Signal(self.ROW_LINE_BITS) self.rows_valid = RowPerLineValidArray() # TLB miss state @@ -337,25 +341,25 @@ class ICache(FetchUnitInterface, Elaboratable): do_read = Signal() comb += do_read.eq(~(stall_in | use_previous)) - rd_addr = Signal(ROW_BITS) - wr_addr = Signal(ROW_BITS) + rd_addr = Signal(self.ROW_BITS) + wr_addr = Signal(self.ROW_BITS) comb += rd_addr.eq(req_row) comb += wr_addr.eq(r.store_row) # binary-to-unary converters: replace-way enabled by bus.ack, # hit-way left permanently enabled - m.submodules.replace_way_e = re = Decoder(NUM_WAYS) - m.submodules.hit_way_e = he = Decoder(NUM_WAYS) + m.submodules.replace_way_e = re = Decoder(self.NUM_WAYS) + m.submodules.hit_way_e = he = Decoder(self.NUM_WAYS) comb += re.i.eq(replace_way) comb += re.n.eq(~bus.ack) comb += he.i.eq(r.hit_way) - for i in range(NUM_WAYS): + for i in range(self.NUM_WAYS): do_write = Signal(name="do_wr_%d" % i) - d_out = Signal(ROW_SIZE_BITS, name="d_out_%d" % i) - wr_sel = Signal(ROW_SIZE, name="wr_sel_%d" % i) + d_out = Signal(self.ROW_SIZE_BITS, name="d_out_%d" % i) + wr_sel = Signal(self.ROW_SIZE, name="wr_sel_%d" % i) - way = CacheRam(ROW_BITS, ROW_SIZE_BITS, TRACE=True, ram_num=i) + way = CacheRam(self.ROW_BITS, self.ROW_SIZE_BITS, TRACE=True, ram_num=i) m.submodules["cacheram_%d" % i] = way comb += way.rd_en.eq(do_read) @@ -377,17 +381,17 @@ class ICache(FetchUnitInterface, Elaboratable): sync += Display("cache read adr: %x data: %x", req_row, d_out) - comb += wr_sel.eq(Repl(do_write, ROW_SIZE)) + comb += wr_sel.eq(Repl(do_write, self.ROW_SIZE)) # Generate PLRUs def maybe_plrus(self, m, r, plru_victim): comb = m.d.comb - if NUM_WAYS == 0: + if self.NUM_WAYS == 0: return - m.submodules.plrus = plru = PLRUs(NUM_LINES, WAY_BITS) + m.submodules.plrus = plru = PLRUs(self.NUM_LINE, self.WAY_BITS) comb += plru.way.eq(r.hit_way) comb += plru.valid.eq(r.hit_valid) comb += plru.index.eq(get_index(r.hit_nia)) @@ -413,16 +417,16 @@ class ICache(FetchUnitInterface, Elaboratable): comb += tlb.eq(rd_tlb.data) with m.If(i_in.virt_mode): - comb += real_addr.eq(Cat(i_in.nia[:TLB_LG_PGSZ], - pte[TLB_LG_PGSZ:REAL_ADDR_BITS])) + comb += real_addr.eq(Cat(i_in.nia[:self.TLB_LG_PGSZ], + pte[self.TLB_LG_PGSZ:self.REAL_ADDR_BITS])) - with m.If(ttag == i_in.nia[TLB_LG_PGSZ + TLB_BITS:64]): + with m.If(ttag == i_in.nia[self.TLB_LG_PGSZ + self.TL_BITS:64]): comb += ra_valid.eq(itlb_valid.q.bit_select(tlb_req_index, 1)) comb += eaa_priv.eq(pte[3]) with m.Else(): - comb += real_addr.eq(i_in.nia[:REAL_ADDR_BITS]) + comb += real_addr.eq(i_in.nia[:self.REAL_ADDR_BITS]) comb += ra_valid.eq(1) comb += eaa_priv.eq(1) @@ -437,8 +441,8 @@ class ICache(FetchUnitInterface, Elaboratable): m_in = self.m_in - wr_index = Signal(TLB_BITS) - wr_unary = Signal(TLB_SIZE) + wr_index = Signal(self.TL_BITS) + wr_unary = Signal(self.TLB_SIZE) comb += wr_index.eq(hash_ea(m_in.addr)) comb += wr_unary.eq(1<