--- /dev/null
+#!/usr/bin/env python3
+#
+# SPDX-License-Identifier: LGPLv3+
+# Copyright (C) 2022 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
+# 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")
+
# 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:
# .. 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
# 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):
# 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):
# 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
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()
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
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)
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))
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)
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<<wr_index)
with m.Elif(m_in.tlbld):
tlb = TLBRecord("tlb_wrport")
- comb += tlb.tag.eq(m_in.addr[TLB_LG_PGSZ + TLB_BITS:64])
+ comb += tlb.tag.eq(m_in.addr[self.TLB_LG_PGSZ + self.TL_BITS:64])
comb += tlb.pte.eq(m_in.pte)
comb += wr_tlb.en.eq(1)
comb += wr_tlb.addr.eq(wr_index)
flush_in, stall_out = self.flush_in, self.stall_out
is_hit = Signal()
- hit_way = Signal(WAY_BITS)
+ hit_way = Signal(self.WAY_BITS)
# i_in.sequential means that i_in.nia this cycle is 4 more than
# last cycle. If we read more than 32 bits at a time, had a
# cache hit last cycle, and we don't want the first 32-bit chunk
# then we can keep the data we read last cycle and just use that.
- with m.If(i_in.nia[2:INSN_BITS+2] != 0):
+ with m.If(i_in.nia[2:self.INSN_BITS+2] != 0):
comb += use_previous.eq(i_in.sequential & r.hit_valid)
# Extract line, row and tag from request
# Calculate address of beginning of cache row, will be
# used for cache miss processing if needed
comb += req_laddr.eq(Cat(
- Const(0, ROW_OFF_BITS),
- real_addr[ROW_OFF_BITS:REAL_ADDR_BITS],
+ Const(0, self.ROW_OFF_BITS),
+ real_addr[self.ROW_OFF_BITS:self.REAL_ADDR_BITS],
))
# Test if pending request is a hit on any way
hitcond = Signal()
comb += hitcond.eq((r.state == State.WAIT_ACK)
& (req_index == r.store_index)
- & r.rows_valid[req_row % ROW_PER_LINE]
+ & r.rows_valid[req_row % self.ROW_PER_LINE]
)
# i_in.req asserts Decoder active
- cvb = Signal(NUM_WAYS)
- ctag = Signal(TAG_RAM_WIDTH)
+ cvb = Signal(self.NUM_WAYS)
+ ctag = Signal(self.TAG_RAM_WIDTH)
comb += rd_tag.addr.eq(req_index)
comb += ctag.eq(rd_tag.data)
- comb += cvb.eq(cache_valids.q.word_select(req_index, NUM_WAYS))
- m.submodules.store_way_e = se = Decoder(NUM_WAYS)
+ comb += cvb.eq(cache_valids.q.word_select(req_index, self.NUM_WAYS))
+ m.submodules.store_way_e = se = Decoder(self.NUM_WAYS)
comb += se.i.eq(r.store_way)
comb += se.n.eq(~i_in.req)
- for i in range(NUM_WAYS):
- tagi = Signal(TAG_BITS, name="tag_i%d" % i)
+ for i in range(self.NUM_WAYS):
+ tagi = Signal(self.TAG_BITS, name="tag_i%d" % i)
hit_test = Signal(name="hit_test%d" % i)
is_tag_hit = Signal(name="is_tag_hit_%d" % i)
comb += tagi.eq(read_tag(i, ctag))
i_in = self.i_in
# Reset per-row valid flags, only used in WAIT_ACK
- for i in range(ROW_PER_LINE):
+ for i in range(self.ROW_PER_LINE):
sync += r.rows_valid[i].eq(0)
# We need to read a cache line
replace_way, req_tag, real_addr)
# Keep track of our index and way for subsequent stores
- st_row = Signal(ROW_BITS)
+ st_row = Signal(self.ROW_BITS)
comb += st_row.eq(get_row(req_laddr))
sync += r.store_index.eq(req_index)
sync += r.store_row.eq(st_row)
comb = m.d.comb
sync = m.d.sync
m.submodules.wr_tag = wr_tag = self.tagmem.write_port(
- granularity=TAG_BITS)
+ granularity=self.TAG_BITS)
# Get victim way from plru
sync += r.store_way.eq(replace_way)
# Force misses on that way while reloading that line
- idx = req_index*NUM_WAYS + replace_way # 2D index, 1st dim: NUM_WAYS
+ idx = req_index*self.NUM_WAYS + replace_way # 2D index, 1st dim: self.NUM_WAYS
comb += cache_valids.r.eq(1<<idx)
# use write-port "granularity" to select the tag to write to
# TODO: the Memory should be multipled-up (by NUM_TAGS)
- tagset = Signal(TAG_RAM_WIDTH)
- comb += tagset.eq(r.store_tag << (replace_way*TAG_BITS))
+ tagset = Signal(self.TAG_RAM_WIDTH)
+ comb += tagset.eq(r.store_tag << (replace_way*self.TAG_BITS))
comb += wr_tag.en.eq(1<<replace_way)
comb += wr_tag.addr.eq(r.store_index)
comb += wr_tag.data.eq(tagset)
comb += stbs_done.eq(1)
# Calculate the next row address
- rarange = Signal(LINE_OFF_BITS - ROW_OFF_BITS)
- comb += rarange.eq(r.req_adr[ROW_OFF_BITS:LINE_OFF_BITS] + 1)
- sync += r.req_adr[ROW_OFF_BITS:LINE_OFF_BITS].eq(rarange)
+ rarange = Signal(self.LINE_OFF_BITS - self.ROW_OFF_BITS)
+ comb += rarange.eq(r.req_adr[self.ROW_OFF_BITS:self.LINE_OFF_BITS] + 1)
+ sync += r.req_adr[self.ROW_OFF_BITS:self.LINE_OFF_BITS].eq(rarange)
sync += Display("RARANGE r.req_adr:%x rarange:%x "
"stbs_zero:%x stbs_done:%x",
r.req_adr, rarange, stbs_zero, stbs_done)
"stbs_done:%x",
bus.dat_r, stbs_zero, stbs_done)
- sync += r.rows_valid[r.store_row % ROW_PER_LINE].eq(1)
+ sync += r.rows_valid[r.store_row % self.ROW_PER_LINE].eq(1)
# Check for completion
with m.If(stbs_done & is_last_row(r.store_row, r.end_row_ix)):
sync += r.req_adr.eq(0)
# Cache line is now valid
- idx = r.store_index*NUM_WAYS + replace_way # 2D index again
+ idx = r.store_index*self.NUM_WAYS + replace_way # 2D index again
valid = r.store_valid & ~inval_in
comb += cache_valids.s.eq(1<<idx)
sync += r.state.eq(State.IDLE)
# Output data to logger
for i in range(LOG_LENGTH):
log_data = Signal(54)
- lway = Signal(WAY_BITS)
+ lway = Signal(self.WAY_BITS)
wstate = Signal()
sync += lway.eq(req_hit_way)
# Cache-Ways "valid" indicators. this is a 2D Signal, by the
# number of ways and the number of lines.
- vec = SRLatch(sync=True, llen=NUM_WAYS*NUM_LINES, name="cachevalids")
+ vec = SRLatch(sync=True, llen=self.NUM_WAYS*self.NUM_LINE, name="cachevalids")
m.submodules.cache_valids = cache_valids = vec
# TLB Array
itlb = TLBArray()
- vec = SRLatch(sync=False, llen=TLB_SIZE, name="tlbvalids")
+ vec = SRLatch(sync=False, llen=self.TLB_SIZE, name="tlbvalids")
m.submodules.itlb_valids = itlb_valid = vec
# TODO to be passed to nmigen as ram attributes
r = RegInternal()
# Async signal on incoming request
- req_index = Signal(INDEX_BITS)
- req_row = Signal(ROW_BITS)
- req_hit_way = Signal(WAY_BITS)
- req_tag = Signal(TAG_BITS)
+ req_index = Signal(self.INDEX_BITS)
+ req_row = Signal(self.ROW_BITS)
+ req_hit_way = Signal(self.WAY_BITS)
+ req_tag = Signal(self.TAG_BITS)
req_is_hit = Signal()
req_is_miss = Signal()
req_laddr = Signal(64)
- tlb_req_index = Signal(TLB_BITS)
- real_addr = Signal(REAL_ADDR_BITS)
+ tlb_req_index = Signal(self.TL_BITS)
+ real_addr = Signal(self.REAL_ADDR_BITS)
ra_valid = Signal()
priv_fault = Signal()
access_ok = Signal()
use_previous = Signal()
- cache_out_row = Signal(ROW_SIZE_BITS)
+ cache_out_row = Signal(self.ROW_SIZE_BITS)
- plru_victim = Signal(WAY_BITS)
- replace_way = Signal(WAY_BITS)
+ plru_victim = Signal(self.WAY_BITS)
+ replace_way = Signal(self.WAY_BITS)
- self.tlbmem = Memory(depth=TLB_SIZE, width=TLB_EA_TAG_BITS+TLB_PTE_BITS)
- self.tagmem = Memory(depth=NUM_LINES, width=TAG_RAM_WIDTH)
+ self.tlbmem = Memory(depth=self.TLB_SIZE, width=self.TLB_EA_TAG_BITS+self.TLB_PTE_BITS)
+ self.tagmem = Memory(depth=self.NUM_LINE, width=self.TAG_RAM_WIDTH)
# call sub-functions putting everything together,
# using shared signals established above