Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate internal CSR FIFOS (via python params); Add CSRs APB, AXI, AXIL support; Remove default pc-emul sources. #48

Merged
merged 6 commits into from
Sep 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 7 additions & 61 deletions py2hwsw/lib/hardware/csrs/csrs.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import sys
import os
import copy

# Add csrs scripts folder to python path
sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), "scripts"))

import reg_gen
from iob_csr import create_csr_group
from fifos import append_fifos_csrs, create_fifos_instances

interrupt_csrs = {
"name": "interrupt_csrs",
Expand Down Expand Up @@ -42,60 +42,9 @@
],
}

fifo_csrs = {
"name": "fifo_csrs",
"descr": "FIFO control and status registers",
"regs": [
{
"name": "data",
"type": "RW",
"n_bits": 32,
"rst_val": 0,
"log2n_items": 0,
"autoreg": True,
"descr": "Read/write data from/to FIFO.",
},
{
"name": "thresh",
"type": "W",
"n_bits": 32,
"rst_val": 0,
"log2n_items": 0,
"autoreg": True,
"descr": "Interrupt upper level threshold: an interrupt is triggered when the number of words in the FIFO reaches this upper level threshold.",
},
{
"name": "empty",
"type": "R",
"n_bits": 1,
"rst_val": 1,
"log2n_items": 0,
"autoreg": True,
"descr": "Empty (1) or non-empty (0).",
},
{
"name": "full",
"type": "R",
"n_bits": 1,
"rst_val": 0,
"log2n_items": 0,
"autoreg": True,
"descr": "Full (1), or non-full (0).",
},
{
"name": "level",
"type": "R",
"n_bits": 32,
"rst_val": 0,
"log2n_items": 0,
"autoreg": True,
"descr": "Number of words in FIFO.",
},
],
}


def setup(py_params_dict):
"""Standard Py2HWSW setup function"""
params = {
"name": py_params_dict["instantiator"]["name"] + "_csrs",
"version": "1.0",
Expand All @@ -107,8 +56,9 @@ def setup(py_params_dict):
"build_dir": "",
# Auto-add interrupt csrs: status, mask, clear
"interrupt_csrs": False,
# List of FIFO names. Will auto-add each FIFO csrs: full, empty, level, etc
"fifo_csrs": [],
# Lists of FIFO names. Will auto-add each FIFO csrs: full, empty, level, etc
"fifos": [],
"async_fifos": [],
}

# Update params with values from py_params_dict
Expand Down Expand Up @@ -184,12 +134,8 @@ def setup(py_params_dict):
# Auto-add csrs
if params["interrupt_csrs"]:
csrs_obj_list.append(interrupt_csrs)
for fifo_name in params["fifo_csrs"]:
local_fifo_csrs = copy.deepcopy(fifo_csrs)
local_fifo_csrs["name"] = fifo_name + "_" + fifo_csrs["name"]
for reg in local_fifo_csrs["regs"]:
reg["name"] = fifo_name + "_" + reg["name"]
csrs_obj_list.append(local_fifo_csrs)
append_fifos_csrs(csrs_obj_list, params["fifos"] + params["async_fifos"])
create_fifos_instances(attributes_dict, params["fifos"], params["async_fifos"])

attributes_with_csrs = attributes_dict | {
"csrs": csrs_obj_list,
Expand Down
135 changes: 119 additions & 16 deletions py2hwsw/lib/hardware/csrs/scripts/csr_gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ def gen_wr_reg(self, row):

# compute wdata with only the needed bits
lines += f" wire [{self.verilog_max(n_bits, 1)}-1:0] {name}_wdata; \n"
lines += f" assign {name}_wdata = iob_wdata_i[{self.boffset(addr,self.cpu_n_bytes)}+:{self.verilog_max(n_bits,1)}];\n"
lines += f" assign {name}_wdata = internal_iob_wdata[{self.boffset(addr,self.cpu_n_bytes)}+:{self.verilog_max(n_bits,1)}];\n"

# signal to indicate if the register is addressed
lines += f" wire {name}_addressed_w;\n"
Expand Down Expand Up @@ -203,7 +203,7 @@ def gen_wr_reg(self, row):
else:
rst_val_str = str(n_bits) + "'d" + str(rst_val)
lines += f" wire {name}_wen;\n"
lines += f" assign {name}_wen = (iob_valid_i & iob_ready_o) & ((|iob_wstrb_i) & {name}_addressed_w);\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"
Expand All @@ -216,7 +216,7 @@ def gen_wr_reg(self, row):
lines += f" .data_o ({name}_o)\n"
lines += " );\n"
else: # compute wen
lines += f" assign {name}_wen_o = ({name}_addressed_w & (iob_valid_i & iob_ready_o))? |iob_wstrb_i: 1'b0;\n"
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"

return lines
Expand All @@ -238,8 +238,8 @@ def gen_rd_reg(self, row):

if not auto: # output read enable
lines += f" wire {name}_addressed_r;\n"
lines += f" assign {name}_addressed_r = (iob_addr_i >= {addr}) && (iob_addr_i < ({addr}+(2**({addr_w}))));\n"
lines += f" assign {name}_ren_o = {name}_addressed_r & (iob_valid_i & iob_ready_o) & (~|iob_wstrb_i);\n"
lines += f" assign {name}_addressed_r = (internal_iob_addr >= {addr}) && (internal_iob_addr < ({addr}+(2**({addr_w}))));\n"
lines += f" assign {name}_ren_o = {name}_addressed_r & (internal_iob_valid & internal_iob_ready) & (~|internal_iob_wstrb);\n"

return lines

Expand Down Expand Up @@ -451,6 +451,21 @@ def write_hwcode(self, table, core_attributes):
""" Generates and appends verilog code to core "snippets" list.
"""

ports = [
{
"name": "csrs_iob_output",
"descr": "Give user logic access to csrs internal IOb signals",
"signals": [
{"name": "csrs_iob_valid", "direction": "output", "width": 1},
{"name": "csrs_iob_addr", "direction": "output", "width": "ADDR_W"},
{"name": "csrs_iob_wdata", "direction": "output", "width": "DATA_W"},
{"name": "csrs_iob_wstrb", "direction": "output", "width": "DATA_W/8"},
{"name": "csrs_iob_rvalid", "direction": "output", "width": 1},
{"name": "csrs_iob_rdata", "direction": "output", "width": "DATA_W"},
{"name": "csrs_iob_ready", "direction": "output", "width": 1},
],
}
]
wires = []
blocks = []
snippet = ""
Expand All @@ -469,6 +484,16 @@ def write_hwcode(self, table, core_attributes):
localparam WAIT_RVALID = 1'd1;
"""
wires += [
{
"name": "internal_iob",
"descr": "Internal iob interface",
"interface": {
"type": "iob",
"wire_prefix": "internal_",
"ADDR_W": "ADDR_W",
"DATA_W": "DATA_W",
},
},
{
"name": "state",
"descr": "",
Expand Down Expand Up @@ -501,16 +526,93 @@ def write_hwcode(self, table, core_attributes):
}
)

# Connect internal IOb signals to output port for user logic
snippet += """
assign csrs_iob_valid_o = internal_iob_valid;
assign csrs_iob_addr_o = internal_iob_addr;
assign csrs_iob_wdata_o = internal_iob_wdata;
assign csrs_iob_wstrb_o = internal_iob_wstrb;
assign csrs_iob_rvalid_o = internal_iob_rvalid;
assign csrs_iob_rdata_o = internal_iob_rdata;
assign csrs_iob_ready_o = internal_iob_ready;
"""

if core_attributes["csr_if"] == "iob":
# "IOb" CSR_IF
snippet += """
assign internal_iob_valid = iob_valid_i;
assign internal_iob_addr = iob_addr_i;
assign internal_iob_wdata = iob_wdata_i;
assign internal_iob_wstrb = iob_wstrb_i;
assign iob_rvalid_o = internal_iob_rvalid;
assign iob_rdata_o = internal_iob_rdata;
assign iob_ready_o = internal_iob_ready;
"""
elif core_attributes["csr_if"] == "apb":
# "APB" CSR_IF
blocks.append(
{
"core_name": "apb2iob",
"instance_name": "apb2iob_coverter",
"instance_description": "Convert APB port into internal IOb interface",
"parameters": {
"APB_ADDR_W": "ADDR_W",
"APB_DATA_W": "DATA_W",
},
"connect": {
"clk_en_rst": "clk_en_rst",
"apb": "control_if",
"iob": "internal_iob",
},
}
)
elif core_attributes["csr_if"] == "axil":
# "AXI_Lite" CSR_IF
blocks.append(
{
"core_name": "axil2iob",
"instance_name": "axil2iob_coverter",
"instance_description": "Convert AXI-Lite port into internal IOb interface",
"parameters": {
"ADDR_W": "ADDR_W",
"DATA_W": "DATA_W",
},
"connect": {
"clk_en_rst": "clk_en_rst",
"axil": "control_if",
"iob": "internal_iob",
},
}
)
elif core_attributes["csr_if"] == "axi":
# "AXI" CSR_IF
blocks.append(
{
"core_name": "axi2iob",
"instance_name": "axi2iob_coverter",
"instance_description": "Convert AXI port into internal IOb interface",
"parameters": {
"ADDR_WIDTH": "ADDR_W",
"DATA_WIDTH": "DATA_W",
},
"connect": {
"clk_en_rst": "clk_en_rst",
"axi": "control_if",
"iob": "internal_iob",
},
}
)

# write address
snippet += "\n //write address\n"

# extract address byte offset
snippet += " wire [($clog2(WSTRB_W)+1)-1:0] byte_offset;\n"
snippet += " iob_ctls #(.W(WSTRB_W), .MODE(0), .SYMBOL(0)) bo_inst (.data_i(iob_wstrb_i), .count_o(byte_offset));\n"
snippet += " iob_ctls #(.W(WSTRB_W), .MODE(0), .SYMBOL(0)) bo_inst (.data_i(internal_iob_wstrb), .count_o(byte_offset));\n"

# compute write address
snippet += " wire [ADDR_W-1:0] waddr;\n"
snippet += " assign waddr = `IOB_WORD_ADDR(iob_addr_i) + byte_offset;\n"
snippet += " assign waddr = `IOB_WORD_ADDR(internal_iob_addr) + byte_offset;\n"

# insert write register logic
for row in table:
Expand All @@ -529,9 +631,9 @@ def write_hwcode(self, table, core_attributes):

# use variables to compute response
snippet += """
assign iob_rvalid_o = rvalid;
assign iob_rdata_o = rdata;
assign iob_ready_o = ready;
assign internal_iob_rvalid = rvalid;
assign internal_iob_rdata = rdata;
assign internal_iob_ready = ready;

"""
wires += [
Expand Down Expand Up @@ -664,7 +766,7 @@ def write_hwcode(self, table, core_attributes):
snippet += f"""
always @* begin
rdata_nxt = {8*self.cpu_n_bytes}'d0;
rvalid_int = (iob_valid_i & iob_ready_o) & (~(|iob_wstrb_i));
rvalid_int = (internal_iob_valid & internal_iob_ready) & (~(|internal_iob_wstrb));
rready_int = 1'b1;
wready_int = 1'b1;

Expand Down Expand Up @@ -701,10 +803,10 @@ def write_hwcode(self, table, core_attributes):
if self.bfloor(addr, addr_w_base) == self.bfloor(
addr_last, addr_w_base
):
snippet += f" {aux_read_reg} = (`IOB_WORD_ADDR(iob_addr_i) == {self.bfloor(addr, addr_w_base)});\n"
snippet += f" {aux_read_reg} = (`IOB_WORD_ADDR(internal_iob_addr) == {self.bfloor(addr, addr_w_base)});\n"
snippet += f" if({aux_read_reg}) "
else:
snippet += f" {aux_read_reg} = ((`IOB_WORD_ADDR(iob_addr_i) >= {self.bfloor(addr, addr_w_base)}) && (`IOB_WORD_ADDR(iob_addr_i) < {self.bfloor(addr_last, addr_w_base)}));\n"
snippet += f" {aux_read_reg} = ((`IOB_WORD_ADDR(internal_iob_addr) >= {self.bfloor(addr, addr_w_base)}) && (`IOB_WORD_ADDR(internal_iob_addr) < {self.bfloor(addr_last, addr_w_base)}));\n"
snippet += f" if({aux_read_reg}) "
snippet += f"begin\n"
if name == "version":
Expand Down Expand Up @@ -751,10 +853,10 @@ def write_hwcode(self, table, core_attributes):
//FSM state machine
case(state)
WAIT_REQ: begin
if(iob_valid_i & (!iob_ready_o)) begin // Wait for a valid request
ready_nxt = |iob_wstrb_i ? wready_int : rready_int;
if(internal_iob_valid & (!internal_iob_ready)) begin // Wait for a valid request
ready_nxt = |internal_iob_wstrb ? wready_int : rready_int;
// If is read and ready, go to WAIT_RVALID
if (ready_nxt && (!(|iob_wstrb_i))) begin
if (ready_nxt && (!(|internal_iob_wstrb))) begin
state_nxt = WAIT_RVALID;
end
end
Expand All @@ -771,6 +873,7 @@ def write_hwcode(self, table, core_attributes):
end //always @*
"""

core_attributes["ports"] += ports
core_attributes["wires"] += wires
core_attributes["blocks"] += blocks
core_attributes["snippets"] += [
Expand Down
Loading