I encountered a problem with the reduction of the memory addresses in the uDMA subsystem. I noticed it on the SPI peripheral so I will describe it with this example.
Whenever a memory address is needed to be stored (e.g. the start address of a TX buffer) only the relevant bits should be stored not the whole 32 bit address to save some resources. The number of bits is given as L2_AWIDTH_NOAL in udma_subsystem.sv .
Currently it is defined as L2_AWIDTH_NOAL = L2_ADDR_WIDTH + 2;. L2_ADDR_WIDTH is passed from in pulp_soc.sv through soc_peripherals.sv as
L2_MEM_ADDR_WIDTH = $clog2(L2_BANK_SIZE * NB_L2_BANKS)
(actually L2_MEM_ADDR_WIDTH = $clog2(L2_BANK_SIZE * NB_L2_BANKS) - $clog2(NB_L2_BANKS);, but $clog2(NB_L2_BANKS) is added back again when passed to soc_peripherals)
The problem lies in the hardcoded L2_AWIDTH_NOAL = L2_ADDR_WIDTH + 2; which is only valid for the preset memory configuration. It is wrong when using following memory configuration for example:
Two shared memory banks of 1024 lines/32b-words and two private memory banks of 1024 lines
L2_MEM_ADDR_WIDTH becomes 11 bits. Therefore L2_AWIDTH_NOAL becomes 13 bits.
But the highest possible Address 0x4000 requires 14 bits, thus the peripheral can not access half of the memory.
I suggest defining L2_AWIDTH_NOAL as $clog2(L2_BANK_SIZE * NB_L2_BANKS * 4 + L2_BANK_SIZE_PRI * NB_L2_BANKS_PRI * 4),
which calculates the required bits for the highest memory address.
This could be done directly in pulp_soc, since all this
localparam L2_BANK_SIZE = 29184; // in 32-bit wordslocalparam L2_MEM_ADDR_WIDTH = $clog2(L2_BANK_SIZE * NB_L2_BANKS) - $clog2(NB_L2_BANKS);localparam NB_L2_BANKS_PRI = 2;
I encountered a problem with the reduction of the memory addresses in the uDMA subsystem. I noticed it on the SPI peripheral so I will describe it with this example.
Whenever a memory address is needed to be stored (e.g. the start address of a TX buffer) only the relevant bits should be stored not the whole 32 bit address to save some resources. The number of bits is given as L2_AWIDTH_NOAL in udma_subsystem.sv . Currently it is defined as
L2_AWIDTH_NOAL = L2_ADDR_WIDTH + 2;
. L2_ADDR_WIDTH is passed from in pulp_soc.sv through soc_peripherals.sv asL2_MEM_ADDR_WIDTH = $clog2(L2_BANK_SIZE * NB_L2_BANKS)
(actuallyL2_MEM_ADDR_WIDTH = $clog2(L2_BANK_SIZE * NB_L2_BANKS) - $clog2(NB_L2_BANKS);
, but $clog2(NB_L2_BANKS) is added back again when passed to soc_peripherals)The problem lies in the hardcoded
L2_AWIDTH_NOAL = L2_ADDR_WIDTH + 2;
which is only valid for the preset memory configuration. It is wrong when using following memory configuration for example:Two shared memory banks of 1024 lines/32b-words and two private memory banks of 1024 lines L2_MEM_ADDR_WIDTH becomes 11 bits. Therefore L2_AWIDTH_NOAL becomes 13 bits. But the highest possible Address 0x4000 requires 14 bits, thus the peripheral can not access half of the memory.
I suggest defining L2_AWIDTH_NOAL as
$clog2(L2_BANK_SIZE * NB_L2_BANKS * 4 + L2_BANK_SIZE_PRI * NB_L2_BANKS_PRI * 4)
, which calculates the required bits for the highest memory address.This could be done directly in pulp_soc, since all this
localparam L2_BANK_SIZE = 29184; // in 32-bit words
localparam L2_MEM_ADDR_WIDTH = $clog2(L2_BANK_SIZE * NB_L2_BANKS) - $clog2(NB_L2_BANKS);
localparam NB_L2_BANKS_PRI = 2;
is there only for the uDMA anyway..