bram: integrate into SoC using Wishbone bus, and note alignment
This commit is contained in:
parent
63a347a18f
commit
9db87cb8ee
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue