Skip to content

Commit

Permalink
feat(csrs): Add regfile to generated CSRs
Browse files Browse the repository at this point in the history
If user sets a write register with 'log2n_items' > 0, then csrs.py will
generate the regfile inside the csrs module.
All registers from regfile can be read in parallel. A port signal is created for each register in the regfile.
Example, if we create a CSR, named 'reg', with 'log2n_items' = 2, then the following
port signals will be available in the csrs module:
reg_0_wr
reg_1_wr
reg_2_wr
reg_3_wr

If the user creates a CSR with `autoreg = False`, then the regfile is not generated.
The csrs module continues to generate a single port for this
regfile, since the signals come from the CPU, and the CPU can only
address one register at a time.

If the user creates a CSR of type "R" (read register), then the regfile is not
generated. This is because read registers should always be implemented by
user logic. The csrs module only generates wires to read from the user
logic's regfile.

Note 1: If we have `autoreg = True`, and type "RW", then the csrs module will
generate the regfile for the write part, but will continue to have
normal wires for the read part.

Note 2: The user logic can find out which register from the regfile is being addressed
by using the `iob` output port of the csrs module. (The `iob` output port is
always available to user logic, even if csr_if is set to another interface).

Related to issues:
IObundle#33
IObundle/iob-soc#719
  • Loading branch information
arturum1 committed Sep 11, 2024
1 parent 31e3ea9 commit 0fc91ac
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 55 deletions.
84 changes: 31 additions & 53 deletions py2hwsw/lib/hardware/csrs/scripts/csr_gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,13 @@ def gen_wr_reg(self, row):
lines += f" assign {name}_addressed_w = (waddr >= {addr}) && (waddr < ({addr}+(2**({addr_w}))));\n"

if auto: # generate register
n_items = 2**eval_param_expression_from_config(log2n_items, self.config, "max")
# Create addressed signal for each reg in regfile
if n_items > 1:
for idx in range(n_items):
name_idx = f"{name}_{idx}"
lines += f" assign {name_idx}_addressed_w = (waddr >= {addr+idx*addr_w}) && (waddr < ({addr+(idx+1)*addr_w}));\n"

# fill remaining bits with 0s
if isinstance(n_bits, str):
if rst_val != 0:
Expand All @@ -202,19 +209,21 @@ def gen_wr_reg(self, row):
rst_val_str = "{" + str(n_bits) + "{1'd0}}"
else:
rst_val_str = str(n_bits) + "'d" + str(rst_val)
lines += f" wire {name}_wen;\n"
lines += f" assign {name}_wen = (internal_iob_valid & internal_iob_ready) & ((|internal_iob_wstrb) & {name}_addressed_w);\n"
lines += " iob_reg_e #(\n"
lines += f" .DATA_W({n_bits}),\n"
lines += f" .RST_VAL({rst_val_str})\n"
lines += f" ) {name}_datareg (\n"
lines += " .clk_i (clk_i),\n"
lines += " .cke_i (cke_i),\n"
lines += " .arst_i (arst_i),\n"
lines += f" .en_i ({name}_wen),\n"
lines += f" .data_i ({name}_wdata),\n"
lines += f" .data_o ({name}_o)\n"
lines += " );\n"
for idx in range(n_items):
name_idx = f"{name}_{idx}" if n_items > 1 else name
lines += f" wire {name_idx}_wen;\n"
lines += f" assign {name_idx}_wen = (internal_iob_valid & internal_iob_ready) & ((|internal_iob_wstrb) & {name_idx}_addressed_w);\n"
lines += " iob_reg_e #(\n"
lines += f" .DATA_W({n_bits}),\n"
lines += f" .RST_VAL({rst_val_str})\n"
lines += f" ) {name_idx}_datareg (\n"
lines += " .clk_i (clk_i),\n"
lines += " .cke_i (cke_i),\n"
lines += " .arst_i (arst_i),\n"
lines += f" .en_i ({name_idx}_wen),\n"
lines += f" .data_i ({name}_wdata),\n"
lines += f" .data_o ({name_idx}_o)\n"
lines += " );\n\n"
else: # compute wen
lines += f" assign {name}_wen_o = ({name}_addressed_w & (internal_iob_valid & internal_iob_ready))? |internal_iob_wstrb: 1'b0;\n"
lines += f" assign {name}_wdata_o = {name}_wdata;\n"
Expand Down Expand Up @@ -243,41 +252,6 @@ def gen_rd_reg(self, row):

return lines

# generate ports for csrs module
def gen_port(self, table, f):
for row in table:
name = row.name
n_bits = row.n_bits
auto = row.autoreg

# version is not a register, it is an internal constant
if name != "version":
if "W" in row.type:
if auto:
f.write(
f" output [{self.verilog_max(n_bits,1)}-1:0] {name}_o,\n"
)
else:
f.write(
f" output [{self.verilog_max(n_bits,1)}-1:0] {name}_wdata_o,\n"
)
f.write(f" output {name}_wen_o,\n")
f.write(f" input {name}_wready_i,\n")
if "R" in row.type:
if auto:
f.write(
f" input [{self.verilog_max(n_bits,1)}-1:0] {name}_i,\n"
)
else:
f.write(
f"""
input [{self.verilog_max(n_bits, 1)}-1:0] {name}_rdata_i,
input {name}_rvalid_i,
output {name}_ren_o,
input {name}_rready_i,
"""
)

# auxiliar read register case name
def aux_read_reg_case_name(self, row):
aux_read_reg_case_name = ""
Expand Down Expand Up @@ -364,6 +338,7 @@ def gen_ports(self, table):
name = row.name
auto = row.autoreg
n_bits = row.n_bits
log2n_items = row.log2n_items
register_signals = []

# version is not a register, it is an internal constant
Expand All @@ -372,11 +347,14 @@ def gen_ports(self, table):

if "W" in row.type:
if auto:
register_signals.append({
"name": name,
"direction": "output",
"width": self.verilog_max(n_bits, 1),
})
n_items = 2**eval_param_expression_from_config(log2n_items, self.config, "max")
for idx in range(n_items):
name_idx = f"{name}_{idx}" if n_items > 1 else name
register_signals.append({
"name": name_idx,
"direction": "output",
"width": self.verilog_max(n_bits, 1),
})
else:
register_signals += [
{
Expand Down
2 changes: 1 addition & 1 deletion py2hwsw/lib/hardware/csrs/scripts/fifos.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
def find_and_update_fifo_csrs(csrs_dict):
"""Given a dictionary of CSRs, find the fifo CSRs group and update the dictionary
accordingly.
User should provide a CSRs of type "*FIFO". This CSR will be replaced by fifo_csrs.
User should provide a CSR of type "*FIFO". This CSR will be replaced by fifo_csrs.
"""
csr_group_ref = None
csr_ref = None
Expand Down
2 changes: 1 addition & 1 deletion py2hwsw/lib/hardware/csrs/scripts/interrupts.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
def find_and_update_interrupt_csrs(csrs_dict):
"""Given a dictionary of CSRs, find the interrupt CSRs group and update the dictionary
accordingly.
User should provide a CSRs of type "INTERRUPT". This CSR will be replaced by interrupt_csrs.
User should provide a CSR of type "INTERRUPT". This CSR will be replaced by interrupt_csrs.
"""
csr_group_ref = None
csr_ref = None
Expand Down

0 comments on commit 0fc91ac

Please sign in to comment.