Add an hacked no we memory for Efinix

Efinity synthesizer cannot infer RAM blocks with write enable.
In order to workaround this (at least for the Litex SoC intergrated
RAM/ROM) a dirty modified Memory class has been created.

This class needs to be rewrite !
This commit is contained in:
Franck Jullien 2021-09-22 09:47:47 +02:00
parent bd71dc663f
commit b24475b07d
5 changed files with 191 additions and 9 deletions

175
litex/gen/fhdl/memory.py Normal file
View File

@ -0,0 +1,175 @@
from migen.fhdl.structure import *
from migen.fhdl.module import *
from migen.fhdl.bitcontainer import bits_for
from migen.fhdl.tools import *
from migen.fhdl.tracer import get_obj_var_name
from migen.fhdl.verilog import _printexpr as verilog_printexpr
from migen.fhdl.specials import Special, _MemoryPort, _MemoryLocation
(READ_FIRST, WRITE_FIRST, NO_CHANGE) = range(3)
class Memory(Special):
def __init__(self, width, depth, init=None, name=None):
Special.__init__(self)
self.width = width
self.depth = depth
self.ports = []
self.init = init
self.name_override = get_obj_var_name(name, "mem")
def __getitem__(self, index):
# simulation only
return _MemoryLocation(self, index)
def get_port(self, write_capable=False, async_read=False,
has_re=False, we_granularity=0, mode=WRITE_FIRST,
clock_domain="sys"):
if we_granularity >= self.width:
we_granularity = 0
adr = Signal(max=self.depth)
dat_r = Signal(self.width)
if write_capable:
if we_granularity:
we = Signal(self.width//we_granularity)
else:
we = Signal()
dat_w = Signal(self.width)
else:
we = None
dat_w = None
if has_re:
re = Signal()
else:
re = None
mp = _MemoryPort(adr, dat_r, we, dat_w,
async_read, re, we_granularity, mode,
clock_domain)
self.ports.append(mp)
return mp
@staticmethod
def emit_verilog(memory, ns, add_data_file):
r = ""
def gn(e):
if isinstance(e, Memory):
return ns.get_name(e)
else:
return verilog_printexpr(ns, e)[0]
adrbits = bits_for(memory.depth-1)
for i in range(memory.width // 8):
r += "reg [" + str((memory.width//4)-1) + ":0] " \
+ gn(memory) + '_' + str(i) \
+ "[0:" + str(memory.depth-1) + "];\n"
adr_regs = {}
data_regs = {}
for port in memory.ports:
if not port.async_read:
if port.mode == WRITE_FIRST:
adr_reg = Signal(name_override="memadr")
r += "reg [" + str(adrbits-1) + ":0] " \
+ gn(adr_reg) + ";\n"
adr_regs[id(port)] = adr_reg
else:
data_reg = Signal(name_override="memdat")
r += "reg [" + str(memory.width-1) + ":0] " \
+ gn(data_reg) + ";\n"
data_regs[id(port)] = data_reg
for port in memory.ports:
r += "always @(posedge " + gn(port.clock) + ") begin\n"
if port.we is not None:
if port.we_granularity:
n = memory.width//port.we_granularity
for i in range(n):
if (i > 0):
r += "always @(posedge " + gn(port.clock) + ") begin\n"
m = i*port.we_granularity
M = (i+1)*port.we_granularity-1
sl = "[" + str(M) + ":" + str(m) + "]"
r += "\tif (" + gn(port.we) + "[" + str(i) + "])\n"
r += "\t\t" + gn(memory) + '_' + str(i) + "[" + gn(port.adr) + "]" + " <= " + gn(port.dat_w) + sl + ";\n"
r += "end\n"
else:
r += "\tif (" + gn(port.we) + ")\n"
r += "\t\t" + gn(memory) + "[" + gn(port.adr) + "] <= " + gn(port.dat_w) + ";\n"
if not port.async_read:
if port.mode == WRITE_FIRST:
r += "always @(posedge " + gn(port.clock) + ") begin\n"
rd = "\t" + gn(adr_regs[id(port)]) + " <= " + gn(port.adr) + ";\n"
else:
bassign = ""
for i in range(memory.width // 8):
m = i*port.we_granularity
M = (i+1)*port.we_granularity-1
sl = "[" + str(M) + ":" + str(m) + "]"
bassign += gn(data_regs[id(port)]) + sl + " <= " + gn(memory) + "_" + str(i) + "[" + gn(port.adr) + "];\n"
if port.mode == READ_FIRST:
rd = "\t" + bassign
elif port.mode == NO_CHANGE:
rd = "\tif (!" + gn(port.we) + ")\n" \
+ "\t\t" + bassign
if port.re is None:
r += rd
else:
r += "\tif (" + gn(port.re) + ")\n"
r += "\t" + rd.replace("\n\t", "\n\t\t")
r += "end\n\n"
for port in memory.ports:
if port.async_read:
r += "assign " + gn(port.dat_r) + " = " + gn(memory) + "[" + gn(port.adr) + "];\n"
else:
if port.mode == WRITE_FIRST:
for i in range(memory.width // 8):
m = i*port.we_granularity
M = (i+1)*port.we_granularity-1
sl = "[" + str(M) + ":" + str(m) + "]"
r += "assign " + gn(port.dat_r) + sl + " = " + gn(memory) + "_" + str(i) + "[" + gn(adr_regs[id(port)]) + "];\n"
else:
r += "assign " + gn(port.dat_r) + " = " + gn(data_regs[id(port)]) + ";\n"
r += "\n"
if memory.init is not None:
content_7_0 = ""
content_15_8 = ""
content_23_16 = ""
content_31_24 = ""
formatter = "{:0" + str(int(memory.width / 4)) + "X}\n"
init_7_0 = []
init_15_8 = []
init_23_16 = []
init_31_24 = []
for w in memory.init:
init_7_0.append(w & 0xff)
init_15_8.append((w >> 8) & 0xff)
init_23_16.append((w >> 16) & 0xff)
init_31_24.append((w >> 24) & 0xff)
for d in init_7_0:
content_7_0 += formatter.format(d)
for d in init_15_8:
content_15_8 += formatter.format(d)
for d in init_23_16:
content_23_16 += formatter.format(d)
for d in init_31_24:
content_31_24 += formatter.format(d)
memory_filename1 = add_data_file(gn(memory) + "1.init", content_7_0)
memory_filename2 = add_data_file(gn(memory) + "2.init", content_15_8)
memory_filename3 = add_data_file(gn(memory) + "3.init", content_23_16)
memory_filename4 = add_data_file(gn(memory) + "4.init", content_31_24)
r += "initial begin\n"
r += "\t$readmemh(\"" + memory_filename1 + "\", " + gn(memory)+ "_0" + ");\n"
r += "\t$readmemh(\"" + memory_filename2 + "\", " + gn(memory)+ "_1" + ");\n"
r += "\t$readmemh(\"" + memory_filename3 + "\", " + gn(memory)+ "_2" + ");\n"
r += "\t$readmemh(\"" + memory_filename4 + "\", " + gn(memory)+ "_3" + ");\n"
r += "end\n\n"
return r

View File

@ -815,7 +815,7 @@ class SoC(Module):
self.check_if_exists(name) self.check_if_exists(name)
setattr(self.submodules, name, SoCController(**kwargs)) setattr(self.submodules, name, SoCController(**kwargs))
def add_ram(self, name, origin, size, contents=[], mode="rw"): def add_ram(self, name, origin, size, contents=[], mode="rw", no_we=False):
ram_cls = { ram_cls = {
"wishbone": wishbone.SRAM, "wishbone": wishbone.SRAM,
"axi-lite": axi.AXILiteSRAM, "axi-lite": axi.AXILiteSRAM,
@ -825,7 +825,7 @@ class SoC(Module):
"axi-lite": axi.AXILiteInterface, "axi-lite": axi.AXILiteInterface,
}[self.bus.standard] }[self.bus.standard]
ram_bus = interface_cls(data_width=self.bus.data_width) ram_bus = interface_cls(data_width=self.bus.data_width)
ram = ram_cls(size, bus=ram_bus, init=contents, read_only=(mode == "r")) ram = ram_cls(size, bus=ram_bus, init=contents, read_only=(mode == "r"), no_we=no_we)
self.bus.add_slave(name, ram.bus, SoCRegion(origin=origin, size=size, mode=mode)) self.bus.add_slave(name, ram.bus, SoCRegion(origin=origin, size=size, mode=mode))
self.check_if_exists(name) self.check_if_exists(name)
self.logger.info("RAM {} {} {}.".format( self.logger.info("RAM {} {} {}.".format(
@ -834,8 +834,8 @@ class SoC(Module):
self.bus.regions[name])) self.bus.regions[name]))
setattr(self.submodules, name, ram) setattr(self.submodules, name, ram)
def add_rom(self, name, origin, size, contents=[], mode="r"): def add_rom(self, name, origin, size, contents=[], mode="r", no_we=False):
self.add_ram(name, origin, size, contents, mode=mode) self.add_ram(name, origin, size, contents, mode=mode, no_we=no_we)
def init_rom(self, name, contents=[], auto_size=True): def init_rom(self, name, contents=[], auto_size=True):
self.logger.info("Initializing ROM {} with contents (Size: {}).".format( self.logger.info("Initializing ROM {} with contents (Size: {}).".format(

View File

@ -79,10 +79,12 @@ class SoCCore(LiteXSoC):
integrated_rom_size = 0, integrated_rom_size = 0,
integrated_rom_mode = "r", integrated_rom_mode = "r",
integrated_rom_init = [], integrated_rom_init = [],
integrated_rom_no_we = False,
# SRAM parameters # SRAM parameters
integrated_sram_size = 0x2000, integrated_sram_size = 0x2000,
integrated_sram_init = [], integrated_sram_init = [],
integrated_sram_no_we = False,
# MAIN_RAM parameters # MAIN_RAM parameters
integrated_main_ram_size = 0, integrated_main_ram_size = 0,
@ -197,11 +199,11 @@ class SoCCore(LiteXSoC):
# Add integrated ROM # Add integrated ROM
if integrated_rom_size: if integrated_rom_size:
self.add_rom("rom", self.cpu.reset_address, integrated_rom_size, integrated_rom_init, integrated_rom_mode) self.add_rom("rom", self.cpu.reset_address, integrated_rom_size, integrated_rom_init, integrated_rom_mode, no_we=integrated_rom_no_we)
# Add integrated SRAM # Add integrated SRAM
if integrated_sram_size: if integrated_sram_size:
self.add_ram("sram", self.mem_map["sram"], integrated_sram_size) self.add_ram("sram", self.mem_map["sram"], integrated_sram_size, no_we=integrated_sram_no_we)
# Add integrated MAIN_RAM (only useful when no external SRAM/SDRAM is available) # Add integrated MAIN_RAM (only useful when no external SRAM/SDRAM is available)
if integrated_main_ram_size: if integrated_main_ram_size:

View File

@ -783,7 +783,7 @@ class AXILite2CSR(Module):
# AXILite SRAM ------------------------------------------------------------------------------------- # AXILite SRAM -------------------------------------------------------------------------------------
class AXILiteSRAM(Module): class AXILiteSRAM(Module):
def __init__(self, mem_or_size, read_only=None, init=None, bus=None): def __init__(self, mem_or_size, read_only=None, init=None, bus=None, no_we=False):
if bus is None: if bus is None:
bus = AXILiteInterface() bus = AXILiteInterface()
self.bus = bus self.bus = bus

View File

@ -329,7 +329,7 @@ class Converter(Module):
# Wishbone SRAM ------------------------------------------------------------------------------------ # Wishbone SRAM ------------------------------------------------------------------------------------
class SRAM(Module): class SRAM(Module):
def __init__(self, mem_or_size, read_only=None, init=None, bus=None): def __init__(self, mem_or_size, read_only=None, init=None, bus=None, no_we=False):
if bus is None: if bus is None:
bus = Interface() bus = Interface()
self.bus = bus self.bus = bus
@ -338,7 +338,12 @@ class SRAM(Module):
assert(mem_or_size.width <= bus_data_width) assert(mem_or_size.width <= bus_data_width)
self.mem = mem_or_size self.mem = mem_or_size
else: else:
self.mem = Memory(bus_data_width, mem_or_size//(bus_data_width//8), init=init) if no_we:
from litex.gen.fhdl.memory import Memory as NoWeMemory
self.mem = NoWeMemory(bus_data_width, mem_or_size//(bus_data_width//8), init=init)
else:
self.mem = Memory(bus_data_width, mem_or_size//(bus_data_width//8), init=init)
if read_only is None: if read_only is None:
if hasattr(self.mem, "bus_read_only"): if hasattr(self.mem, "bus_read_only"):
read_only = self.mem.bus_read_only read_only = self.mem.bus_read_only