How to add a new peripherial
This document details the steps needed to add a second BRAM on the IO NASTI bus.
A secondary BRAM
Below is the top-level connection of the BRAM to be added.
module nasti_bram (
input clk, rstn,
nasti_channel.slave nasti
);
Modify the global address map
Assuming the BRAM is 128KB and is readable, writable but not executable, we add a new entry named “extra_bram” into the address map at $TOP/src/main/scala/Configs.scala
:
# In class BaseConfig extends Config (
if (site(UseSPI)) {
entries += AddrMapEntry("spi", MemSize(1<<13, 1<<13, MemAttr(AddrMapProt.RW)))
Dump("ADD_SPI", true)
}
+ entries += AddrMapEntry("extra_bram", MemSize(1<<17, 1<<17, MemAttr(AddrMapProt.RW)))
new AddrMap(entries)
This should result in two extra macros defined in dev_map.h
:
#define DEV_MAP__io_ext_extra_bram__BASE 0x40020000
#define DEV_MAP__io_ext_extra_bram__MASK 0x1ffff
Connect the BRAM to the IO NASTI bus.
Finally, we need to add the BRAM in the SystemVerilog top-level connection at $TOP/src/main/verilog/chip_top.sv
:
+ // secondary BRAM
+
+ nasti_channel
+ #(
+ .ADDR_WIDTH ( `ROCKET_PADDR_WIDTH ),
+ .DATA_WIDTH ( `LOWRISC_IO_DAT_WIDTH ))
+ io_extra_bram_lite();
+
+ nasti_bram extra_bram
+ (
+ .*,
+ .nasti ( io_extra_bram_lite )
+ );
+
/////////////////////////////////////////////////////////////
// IO crossbar
- localparam NUM_DEVICE = 4;
+ localparam NUM_DEVICE = 5;
// output of the IO crossbar
nasti_channel
#(
.N_PORT ( NUM_DEVICE ),
.ADDR_WIDTH ( `ROCKET_PADDR_WIDTH ),
.DATA_WIDTH ( `LOWRISC_IO_DAT_WIDTH ))
io_cbo_lite();
- nasti_channel ios_dmm4(), ios_dmm5(), ios_dmm6(), ios_dmm7(); // dummy channels
+ nasti_channel ios_dmm5(), ios_dmm6(), ios_dmm7(); // dummy channels
nasti_channel_slicer #(NUM_DEVICE)
io_slicer (.s(io_cbo_lite), .m0(io_host_lite), .m1(io_uart_lite), .m2(io_spi_lite),
- .m3(io_bram_lite), .m4(ios_dmm4), .m5(ios_dmm5), .m6(ios_dmm6), .m7(ios_dmm7));
+ .m3(io_bram_lite), .m4(io_extra_bram_lite), .m5(ios_dmm5), .m6(ios_dmm6), .m7(ios_dmm7));
// the io crossbar
nasti_crossbar
#(
.N_INPUT ( 1 ),
.N_OUTPUT ( NUM_DEVICE ),
.IB_DEPTH ( 0 ),
.OB_DEPTH ( 1 ), // some IPs response only with data, which will cause deadlock in nasti_demux (no lock)
.W_MAX ( 1 ),
.R_MAX ( 1 ),
.ADDR_WIDTH ( `ROCKET_PADDR_WIDTH ),
.DATA_WIDTH ( `LOWRISC_IO_DAT_WIDTH ),
.LITE_MODE ( 1 )
)
io_crossbar
(
.*,
.s ( io_lite ),
.m ( io_cbo_lite )
);
`ifdef ADD_HOST
defparam io_crossbar.BASE0 = `DEV_MAP__io_ext_host__BASE ;
defparam io_crossbar.MASK0 = `DEV_MAP__io_ext_host__MASK ;
`endif
`ifdef ADD_UART
defparam io_crossbar.BASE1 = `DEV_MAP__io_ext_uart__BASE;
defparam io_crossbar.MASK1 = `DEV_MAP__io_ext_uart__MASK;
`endif
`ifdef ADD_SPI
defparam io_crossbar.BASE2 = `DEV_MAP__io_ext_spi__BASE;
defparam io_crossbar.MASK2 = `DEV_MAP__io_ext_spi__MASK;
`endif
`ifdef ADD_BRAM
defparam io_crossbar.BASE3 = `DEV_MAP__io_ext_bram__BASE;
defparam io_crossbar.MASK3 = `DEV_MAP__io_ext_bram__MASK;
`endif
+ defparam io_crossbar.BASE4 = `DEV_MAP__io_ext_extra_bram__BASE;
+ defparam io_crossbar.MASK4 = `DEV_MAP__io_ext_extra_bram__MASK;
That’s it! Now the secondary BRAM should be ready for use.