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
* source distribution.
*
* BRAM to Wishbone interface.
* This BRAM can only handle aligned accesses.
*/
module bram_interface #(
/* 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,
module bram #(
/* Width of the memory bus */
parameter BUS_WID = 32,
/* Width of a request. */
@ -26,37 +23,45 @@ module bram_interface #(
input wb_we,
input [4-1:0] wb_sel,
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 wb_stall,
output reg [BUS_WID-1:0] wb_data_o,
output reg [BUS_WID-1:0] wb_dat_r,
);
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
buffer[mem_addr & ADDR_MASK] <=
(buffer[wb_addr & ADDR_MASK] & $1)
| wb_data_i[$2];
buffer[ind] <= (buffer[ind] & $1) | wb_dat_w[$2];
end⟩)
always @ (posedge clk) if (wb_cyc && wb_stb && !wb_ack)
if (!wb_we) begin
wb_data_o <= buffer[wb_addr & ADDR_MASK];
wb_dat_r <= buffer[ind];
wb_ack <= 1;
end else begin
wb_ack <= 1;
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'b0010: bufwrite(32'hFFFF00FF, 15:8)
4'b0011: bufwrite(32'hFFFF0000, 15:0)
4'b0100: bufwrite(32'hFF00FFFF, 23:16)
4'b1000: bufwrite(32'h00FFFFFF, 31:24)
4'b1100: bufwrite(32'h0000FFFF, 31:16)
default: mem_ready <= 1;
default: ;
endcase
end
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.cores.clock import S7PLL, S7IDELAYCTRL
from litex.soc.interconnect.csr import AutoCSR, Module, CSRStorage, CSRStatus
from litex.soc.interconnect.wishbone import Interface
from litedram.phy import s7ddrphy
from litedram.modules import MT41K128M16
@ -183,6 +184,25 @@ class Base(Module, AutoCSR):
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
# I don't know how this works, I only know that it does.
class _CRG(Module):
@ -222,6 +242,8 @@ class UpsilonSoC(SoCCore):
self.add_constant(f"{ip_name}{seg_num}", int(ip_byte))
def add_bram(self, region_name):
self.bus.add_region(region_name, SoCRegion(size=0x2000, cached=False))
# TODO: special name
self.submodules.bram0 = BRAM(ClockSignal())
def __init__(self,
variant="a7-100",
@ -259,7 +281,8 @@ class UpsilonSoC(SoCCore):
platform.add_source("rtl/control_loop/control_loop.v")
# platform.add_source("rtl/waveform/bram_interface_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")
# SoCCore does not have sane defaults (no integrated rom)
@ -307,7 +330,7 @@ class UpsilonSoC(SoCCore):
self.add_ip(remote_ip, "REMOTEIP")
self.add_constant("TFTP_SERVER_PORT", tftp_port)
self.add_bram("BRAM0")
self.add_bram("bram0")
# Add pins
platform.add_extension(io)