bram: integrate into SoC using Wishbone bus, and note alignment

This commit is contained in:
Peter McGoron 2024-01-21 04:38:34 +00:00
parent 63a347a18f
commit 9db87cb8ee
2 changed files with 48 additions and 20 deletions

View File

@ -6,12 +6,9 @@ m4_changecom(⟨/*⟩, ⟨*/⟩)
* For license terms, refer to the files in `doc/copying` in the Upsilon * For license terms, refer to the files in `doc/copying` in the Upsilon
* source distribution. * source distribution.
* *
* BRAM to Wishbone interface. * This BRAM can only handle aligned accesses.
*/ */
module bram_interface #( module bram #(
/* This is the last INDEX of the word array, which is indexed in
* words, not octets. */
parameter [WORD_AMNT_WID-1:0] WORD_AMNT = 2047,
/* Width of the memory bus */ /* Width of the memory bus */
parameter BUS_WID = 32, parameter BUS_WID = 32,
/* Width of a request. */ /* Width of a request. */
@ -26,37 +23,45 @@ module bram_interface #(
input wb_we, input wb_we,
input [4-1:0] wb_sel, input [4-1:0] wb_sel,
input [BUS_WID-1:0] wb_addr, input [BUS_WID-1:0] wb_addr,
input [BUS_WID-1:0] wb_data_i, input [BUS_WID-1:0] wb_dat_w,
output reg wb_ack, output reg wb_ack,
output wb_stall, output reg [BUS_WID-1:0] wb_dat_r,
output reg [BUS_WID-1:0] wb_data_o,
); );
assign wb_stall = wb_ack; /* When the size of the memory is a power of 2, the mask is the
* last addressable index in the array.
*
* Since this buffer stores words, this is divided by 4 (32 bits).
* When accessing a single byte, the address
* 0b......Xab
* is shifted to the right by two bits, throwing away "ab". This indexes
* the 32 bit word that contains the address. This applies to halfwords
* and words as long as the accesses are aligned.
*/
reg [WORD_WID-1:0] buffer [(ADDR_MASK >> 2):0];
reg [BUS_WID-1:0] buffer [WORD_AMNT:0]; /* Current index into the buffer. */
wire [13-1:0] ind = (wb_addr & ADDR_MASK) >> 2;
m4_define(⟨bufwrite⟩, ⟨begin m4_define(⟨bufwrite⟩, ⟨begin
buffer[mem_addr & ADDR_MASK] <= buffer[ind] <= (buffer[ind] & $1) | wb_dat_w[$2];
(buffer[wb_addr & ADDR_MASK] & $1)
| wb_data_i[$2];
end⟩) end⟩)
always @ (posedge clk) if (wb_cyc && wb_stb && !wb_ack) always @ (posedge clk) if (wb_cyc && wb_stb && !wb_ack)
if (!wb_we) begin if (!wb_we) begin
wb_data_o <= buffer[wb_addr & ADDR_MASK]; wb_dat_r <= buffer[ind];
wb_ack <= 1; wb_ack <= 1;
end else begin end else begin
wb_ack <= 1; wb_ack <= 1;
case (wb_sel) case (wb_sel)
4'b1111: buffer[wb_addr & ADDR_MASK] <= wb_data_o; 4'b1111: buffer[ind] <= wb_dat_w;
4'b0011: bufwrite(32'hFFFF0000, 15:0)
4'b1100: bufwrite(32'h0000FFFF, 31:16)
4'b0001: bufwrite(32'hFFFFFF00, 7:0) 4'b0001: bufwrite(32'hFFFFFF00, 7:0)
4'b0010: bufwrite(32'hFFFF00FF, 15:8) 4'b0010: bufwrite(32'hFFFF00FF, 15:8)
4'b0011: bufwrite(32'hFFFF0000, 15:0)
4'b0100: bufwrite(32'hFF00FFFF, 23:16) 4'b0100: bufwrite(32'hFF00FFFF, 23:16)
4'b1000: bufwrite(32'h00FFFFFF, 31:24) 4'b1000: bufwrite(32'h00FFFFFF, 31:24)
4'b1100: bufwrite(32'h0000FFFF, 31:16) default: ;
default: mem_ready <= 1;
endcase endcase
end end
else if (!wb_stb) begin else if (!wb_stb) begin

View File

@ -51,6 +51,7 @@ from litex.soc.integration.soc_core import SoCCore
from litex.soc.integration.soc import SoCRegion from litex.soc.integration.soc import SoCRegion
from litex.soc.cores.clock import S7PLL, S7IDELAYCTRL from litex.soc.cores.clock import S7PLL, S7IDELAYCTRL
from litex.soc.interconnect.csr import AutoCSR, Module, CSRStorage, CSRStatus from litex.soc.interconnect.csr import AutoCSR, Module, CSRStorage, CSRStatus
from litex.soc.interconnect.wishbone import Interface
from litedram.phy import s7ddrphy from litedram.phy import s7ddrphy
from litedram.modules import MT41K128M16 from litedram.modules import MT41K128M16
@ -183,6 +184,25 @@ class Base(Module, AutoCSR):
self.specials += Instance("base", **self.kwargs) self.specials += Instance("base", **self.kwargs)
class BRAM(Module):
def __init__(self, clk):
self.bus = Interface(data_width=32, address_width=32, addressing="byte")
self.comb += [
self.bus.cti.eq(0),
self.bus.bte.eq(0),
]
self.specials += Instance("bram",
i_clk = clk,
i_wb_cyc = self.bus.cyc,
i_wb_stb = self.bus.stb,
i_wb_we = self.bus.we,
i_wb_sel = self.bus.sel,
i_wb_addr = self.bus.adr,
i_wb_dat_w = self.bus.dat_w,
o_wb_ack = self.bus.ack,
o_wb_dat_r = self.bus.dat_r,
)
# Clock and Reset Generator # Clock and Reset Generator
# I don't know how this works, I only know that it does. # I don't know how this works, I only know that it does.
class _CRG(Module): class _CRG(Module):
@ -222,6 +242,8 @@ class UpsilonSoC(SoCCore):
self.add_constant(f"{ip_name}{seg_num}", int(ip_byte)) self.add_constant(f"{ip_name}{seg_num}", int(ip_byte))
def add_bram(self, region_name): def add_bram(self, region_name):
self.bus.add_region(region_name, SoCRegion(size=0x2000, cached=False)) self.bus.add_region(region_name, SoCRegion(size=0x2000, cached=False))
# TODO: special name
self.submodules.bram0 = BRAM(ClockSignal())
def __init__(self, def __init__(self,
variant="a7-100", variant="a7-100",
@ -259,7 +281,8 @@ class UpsilonSoC(SoCCore):
platform.add_source("rtl/control_loop/control_loop.v") platform.add_source("rtl/control_loop/control_loop.v")
# platform.add_source("rtl/waveform/bram_interface_preprocessed.v") # platform.add_source("rtl/waveform/bram_interface_preprocessed.v")
# platform.add_source("rtl/waveform/waveform_preprocessed.v") # platform.add_source("rtl/waveform/waveform_preprocessed.v")
platform.add_source("rtl/bram/bram_preprocessed.v") # when SoC cannot find a source file, it will fail with a confusing error message
platform.add_source("rtl/bram/bram.v")
platform.add_source("rtl/base/base.v") platform.add_source("rtl/base/base.v")
# SoCCore does not have sane defaults (no integrated rom) # SoCCore does not have sane defaults (no integrated rom)
@ -307,7 +330,7 @@ class UpsilonSoC(SoCCore):
self.add_ip(remote_ip, "REMOTEIP") self.add_ip(remote_ip, "REMOTEIP")
self.add_constant("TFTP_SERVER_PORT", tftp_port) self.add_constant("TFTP_SERVER_PORT", tftp_port)
self.add_bram("BRAM0") self.add_bram("bram0")
# Add pins # Add pins
platform.add_extension(io) platform.add_extension(io)