[util/reggen] Rework TL-UL to Register interaface
- Added tlul_adapter_reg.sv for converting TL-UL to reg_if
- Reduced one clock delay between the requests (#98)
- Re-created register top for all IPs
diff --git a/hw/ip/flash_ctrl/rtl/flash_ctrl_reg_top.sv b/hw/ip/flash_ctrl/rtl/flash_ctrl_reg_top.sv
index 6224ac4..8ed6772 100644
--- a/hw/ip/flash_ctrl/rtl/flash_ctrl_reg_top.sv
+++ b/hw/ip/flash_ctrl/rtl/flash_ctrl_reg_top.sv
@@ -25,27 +25,22 @@
import flash_ctrl_reg_pkg::* ;
localparam AW = 7;
- localparam IW = $bits(tl_i.a_source);
localparam DW = 32;
localparam DBW = DW/8; // Byte Width
localparam logic [$clog2($clog2(DBW)+1)-1:0] FSZ = $clog2(DBW); // Full Size 2^(FSZ) = DBW;
// register signals
- logic reg_we;
- logic reg_re;
- logic [AW-1:0] reg_addr;
- logic [DW-1:0] reg_wdata;
- logic reg_valid;
- logic [DW-1:0] reg_rdata;
- logic tl_malformed, tl_addrmiss;
+ logic reg_we;
+ logic reg_re;
+ logic [AW-1:0] reg_addr;
+ logic [DW-1:0] reg_wdata;
+ logic [DBW-1:0] reg_be;
+ logic [DW-1:0] reg_rdata;
+ logic reg_error;
- // Bus signals
- tlul_pkg::tl_d_op_e rsp_opcode; // AccessAck or AccessAckData
- logic reqready;
- logic [IW-1:0] reqid;
- logic [IW-1:0] rspid;
+ logic malformed, addrmiss;
- logic outstanding;
+ logic [DW-1:0] reg_rdata_next;
tlul_pkg::tl_h2d_t tl_reg_h2d;
tlul_pkg::tl_d2h_t tl_reg_d2h;
@@ -98,47 +93,37 @@
end
end
- // TODO(eunchan): Fix it after bus interface is finalized
- assign reg_we = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
- ((tl_reg_h2d.a_opcode == tlul_pkg::PutFullData) ||
- (tl_reg_h2d.a_opcode == tlul_pkg::PutPartialData));
- assign reg_re = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
- (tl_reg_h2d.a_opcode == tlul_pkg::Get);
- assign reg_addr = tl_reg_h2d.a_address[AW-1:0];
- assign reg_wdata = tl_reg_h2d.a_data;
+ tlul_adapter_reg #(
+ .RegAw(AW),
+ .RegDw(DW)
+ ) u_reg_if (
+ .clk_i,
+ .rst_ni,
- assign tl_reg_d2h.d_valid = reg_valid;
- assign tl_reg_d2h.d_opcode = rsp_opcode;
- assign tl_reg_d2h.d_param = '0;
- assign tl_reg_d2h.d_size = FSZ; // always Full Size
- assign tl_reg_d2h.d_source = rspid;
- assign tl_reg_d2h.d_sink = '0; // Used in TL-C
- assign tl_reg_d2h.d_data = reg_rdata;
- assign tl_reg_d2h.d_user = '0; // Doesn't allow additional features yet
- assign tl_reg_d2h.d_error = tl_malformed | tl_addrmiss;
+ .tl_i (tl_reg_h2d),
+ .tl_o (tl_reg_d2h),
- assign tl_reg_d2h.a_ready = reqready;
+ .we_o (reg_we),
+ .re_o (reg_re),
+ .addr_o (reg_addr),
+ .wdata_o (reg_wdata),
+ .be_o (reg_be),
+ .rdata_i (reg_rdata),
+ .error_i (reg_error)
+ );
- assign reqid = tl_reg_h2d.a_source;
+ assign reg_rdata = reg_rdata_next ;
+ assign reg_error = malformed | addrmiss ;
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- tl_malformed <= 1'b1;
- end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
- if ((tl_reg_h2d.a_opcode != tlul_pkg::Get) &&
- (tl_reg_h2d.a_opcode != tlul_pkg::PutFullData) &&
- (tl_reg_h2d.a_opcode != tlul_pkg::PutPartialData)) begin
- tl_malformed <= 1'b1;
- // Only allow Full Write with full mask
- end else if (tl_reg_h2d.a_size != FSZ || tl_reg_h2d.a_mask != {DBW{1'b1}}) begin
- tl_malformed <= 1'b1;
- end else if (tl_reg_h2d.a_user.parity_en == 1'b1) begin
- tl_malformed <= 1'b1;
- end else begin
- tl_malformed <= 1'b0;
- end
+ // Malformed request check only affects to the write access
+ always_comb begin : malformed_check
+ if (reg_we && (reg_be != '1)) begin
+ malformed = 1'b1;
+ end else begin
+ malformed = 1'b0;
end
end
+
// TODO(eunchan): Revise Register Interface logic after REG INTF finalized
// TODO(eunchan): Make concrete scenario
// 1. Write: No response, so that it can guarantee a request completes a clock after we
@@ -154,26 +139,6 @@
// d_ready ___________________/ \______
//
// Above example is fine but if r.b.r doesn't assert within two cycle, then it can be wrong.
- always_ff @(posedge clk_i or negedge rst_ni) begin
- // Not to accept new request when a request is handling
- // #Outstanding := 1
- if (!rst_ni) begin
- reqready <= 1'b0;
- end else if (reg_we || reg_re) begin
- reqready <= 1'b0;
- end else if (outstanding == 1'b0) begin
- reqready <= 1'b1;
- end
- end
-
- // Request/ Response ID
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- rspid <= '0;
- end else if (reg_we || reg_re) begin
- rspid <= reqid;
- end
- end
// Define SW related signals
// Format: <reg>_<field>_{wd|we|qs}
@@ -2668,9 +2633,9 @@
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
- tl_addrmiss <= 1'b0;
+ addrmiss <= 1'b0;
end else if (reg_re || reg_we) begin
- tl_addrmiss <= ~|addr_hit;
+ addrmiss <= ~|addr_hit;
end
end
@@ -2937,7 +2902,6 @@
assign fifo_lvl_rd_wd = reg_wdata[12:8];
// Read data return
- logic [DW-1:0] reg_rdata_next;
always_comb begin
reg_rdata_next = '0;
unique case (1'b1)
@@ -3093,41 +3057,11 @@
endcase
end
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- reg_valid <= 1'b0;
- reg_rdata <= '0;
- rsp_opcode <= tlul_pkg::AccessAck;
- end else if (reg_re || reg_we) begin
- // Guarantee to return data in a cycle
- reg_valid <= 1'b1;
- if (reg_re) begin
- reg_rdata <= reg_rdata_next;
- rsp_opcode <= tlul_pkg::AccessAckData;
- end else begin
- rsp_opcode <= tlul_pkg::AccessAck;
- end
- end else if (tl_reg_h2d.d_ready) begin
- reg_valid <= 1'b0;
- end
- end
-
- // Outstanding: 1 outstanding at a time. Identical to `reg_valid`
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- outstanding <= 1'b0;
- end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
- outstanding <= 1'b1;
- end else if (tl_reg_d2h.d_valid && tl_reg_h2d.d_ready) begin
- outstanding <= 1'b0;
- end
- end
-
// Assertions for Register Interface
`ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
`ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
- `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> reg_valid, clk_i, !rst_ni)
+ `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid, clk_i, !rst_ni)
`ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
diff --git a/hw/ip/gpio/rtl/gpio_reg_top.sv b/hw/ip/gpio/rtl/gpio_reg_top.sv
index e70b9c5..4c5a9c1 100644
--- a/hw/ip/gpio/rtl/gpio_reg_top.sv
+++ b/hw/ip/gpio/rtl/gpio_reg_top.sv
@@ -20,27 +20,22 @@
import gpio_reg_pkg::* ;
localparam AW = 6;
- localparam IW = $bits(tl_i.a_source);
localparam DW = 32;
localparam DBW = DW/8; // Byte Width
localparam logic [$clog2($clog2(DBW)+1)-1:0] FSZ = $clog2(DBW); // Full Size 2^(FSZ) = DBW;
// register signals
- logic reg_we;
- logic reg_re;
- logic [AW-1:0] reg_addr;
- logic [DW-1:0] reg_wdata;
- logic reg_valid;
- logic [DW-1:0] reg_rdata;
- logic tl_malformed, tl_addrmiss;
+ logic reg_we;
+ logic reg_re;
+ logic [AW-1:0] reg_addr;
+ logic [DW-1:0] reg_wdata;
+ logic [DBW-1:0] reg_be;
+ logic [DW-1:0] reg_rdata;
+ logic reg_error;
- // Bus signals
- tlul_pkg::tl_d_op_e rsp_opcode; // AccessAck or AccessAckData
- logic reqready;
- logic [IW-1:0] reqid;
- logic [IW-1:0] rspid;
+ logic malformed, addrmiss;
- logic outstanding;
+ logic [DW-1:0] reg_rdata_next;
tlul_pkg::tl_h2d_t tl_reg_h2d;
tlul_pkg::tl_d2h_t tl_reg_d2h;
@@ -48,47 +43,37 @@
assign tl_reg_h2d = tl_i;
assign tl_o = tl_reg_d2h;
- // TODO(eunchan): Fix it after bus interface is finalized
- assign reg_we = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
- ((tl_reg_h2d.a_opcode == tlul_pkg::PutFullData) ||
- (tl_reg_h2d.a_opcode == tlul_pkg::PutPartialData));
- assign reg_re = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
- (tl_reg_h2d.a_opcode == tlul_pkg::Get);
- assign reg_addr = tl_reg_h2d.a_address[AW-1:0];
- assign reg_wdata = tl_reg_h2d.a_data;
+ tlul_adapter_reg #(
+ .RegAw(AW),
+ .RegDw(DW)
+ ) u_reg_if (
+ .clk_i,
+ .rst_ni,
- assign tl_reg_d2h.d_valid = reg_valid;
- assign tl_reg_d2h.d_opcode = rsp_opcode;
- assign tl_reg_d2h.d_param = '0;
- assign tl_reg_d2h.d_size = FSZ; // always Full Size
- assign tl_reg_d2h.d_source = rspid;
- assign tl_reg_d2h.d_sink = '0; // Used in TL-C
- assign tl_reg_d2h.d_data = reg_rdata;
- assign tl_reg_d2h.d_user = '0; // Doesn't allow additional features yet
- assign tl_reg_d2h.d_error = tl_malformed | tl_addrmiss;
+ .tl_i (tl_reg_h2d),
+ .tl_o (tl_reg_d2h),
- assign tl_reg_d2h.a_ready = reqready;
+ .we_o (reg_we),
+ .re_o (reg_re),
+ .addr_o (reg_addr),
+ .wdata_o (reg_wdata),
+ .be_o (reg_be),
+ .rdata_i (reg_rdata),
+ .error_i (reg_error)
+ );
- assign reqid = tl_reg_h2d.a_source;
+ assign reg_rdata = reg_rdata_next ;
+ assign reg_error = malformed | addrmiss ;
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- tl_malformed <= 1'b1;
- end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
- if ((tl_reg_h2d.a_opcode != tlul_pkg::Get) &&
- (tl_reg_h2d.a_opcode != tlul_pkg::PutFullData) &&
- (tl_reg_h2d.a_opcode != tlul_pkg::PutPartialData)) begin
- tl_malformed <= 1'b1;
- // Only allow Full Write with full mask
- end else if (tl_reg_h2d.a_size != FSZ || tl_reg_h2d.a_mask != {DBW{1'b1}}) begin
- tl_malformed <= 1'b1;
- end else if (tl_reg_h2d.a_user.parity_en == 1'b1) begin
- tl_malformed <= 1'b1;
- end else begin
- tl_malformed <= 1'b0;
- end
+ // Malformed request check only affects to the write access
+ always_comb begin : malformed_check
+ if (reg_we && (reg_be != '1)) begin
+ malformed = 1'b1;
+ end else begin
+ malformed = 1'b0;
end
end
+
// TODO(eunchan): Revise Register Interface logic after REG INTF finalized
// TODO(eunchan): Make concrete scenario
// 1. Write: No response, so that it can guarantee a request completes a clock after we
@@ -104,26 +89,6 @@
// d_ready ___________________/ \______
//
// Above example is fine but if r.b.r doesn't assert within two cycle, then it can be wrong.
- always_ff @(posedge clk_i or negedge rst_ni) begin
- // Not to accept new request when a request is handling
- // #Outstanding := 1
- if (!rst_ni) begin
- reqready <= 1'b0;
- end else if (reg_we || reg_re) begin
- reqready <= 1'b0;
- end else if (outstanding == 1'b0) begin
- reqready <= 1'b1;
- end
- end
-
- // Request/ Response ID
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- rspid <= '0;
- end else if (reg_we || reg_re) begin
- rspid <= reqid;
- end
- end
// Define SW related signals
// Format: <reg>_<field>_{wd|we|qs}
@@ -604,9 +569,9 @@
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
- tl_addrmiss <= 1'b0;
+ addrmiss <= 1'b0;
end else if (reg_re || reg_we) begin
- tl_addrmiss <= ~|addr_hit;
+ addrmiss <= ~|addr_hit;
end
end
@@ -676,7 +641,6 @@
assign ctrl_en_input_filter_wd = reg_wdata[31:0];
// Read data return
- logic [DW-1:0] reg_rdata_next;
always_comb begin
reg_rdata_next = '0;
unique case (1'b1)
@@ -750,41 +714,11 @@
endcase
end
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- reg_valid <= 1'b0;
- reg_rdata <= '0;
- rsp_opcode <= tlul_pkg::AccessAck;
- end else if (reg_re || reg_we) begin
- // Guarantee to return data in a cycle
- reg_valid <= 1'b1;
- if (reg_re) begin
- reg_rdata <= reg_rdata_next;
- rsp_opcode <= tlul_pkg::AccessAckData;
- end else begin
- rsp_opcode <= tlul_pkg::AccessAck;
- end
- end else if (tl_reg_h2d.d_ready) begin
- reg_valid <= 1'b0;
- end
- end
-
- // Outstanding: 1 outstanding at a time. Identical to `reg_valid`
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- outstanding <= 1'b0;
- end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
- outstanding <= 1'b1;
- end else if (tl_reg_d2h.d_valid && tl_reg_h2d.d_ready) begin
- outstanding <= 1'b0;
- end
- end
-
// Assertions for Register Interface
`ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
`ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
- `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> reg_valid, clk_i, !rst_ni)
+ `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid, clk_i, !rst_ni)
`ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
diff --git a/hw/ip/hmac/rtl/hmac_reg_top.sv b/hw/ip/hmac/rtl/hmac_reg_top.sv
index 1a37c98..eb83373 100644
--- a/hw/ip/hmac/rtl/hmac_reg_top.sv
+++ b/hw/ip/hmac/rtl/hmac_reg_top.sv
@@ -25,27 +25,22 @@
import hmac_reg_pkg::* ;
localparam AW = 12;
- localparam IW = $bits(tl_i.a_source);
localparam DW = 32;
localparam DBW = DW/8; // Byte Width
localparam logic [$clog2($clog2(DBW)+1)-1:0] FSZ = $clog2(DBW); // Full Size 2^(FSZ) = DBW;
// register signals
- logic reg_we;
- logic reg_re;
- logic [AW-1:0] reg_addr;
- logic [DW-1:0] reg_wdata;
- logic reg_valid;
- logic [DW-1:0] reg_rdata;
- logic tl_malformed, tl_addrmiss;
+ logic reg_we;
+ logic reg_re;
+ logic [AW-1:0] reg_addr;
+ logic [DW-1:0] reg_wdata;
+ logic [DBW-1:0] reg_be;
+ logic [DW-1:0] reg_rdata;
+ logic reg_error;
- // Bus signals
- tlul_pkg::tl_d_op_e rsp_opcode; // AccessAck or AccessAckData
- logic reqready;
- logic [IW-1:0] reqid;
- logic [IW-1:0] rspid;
+ logic malformed, addrmiss;
- logic outstanding;
+ logic [DW-1:0] reg_rdata_next;
tlul_pkg::tl_h2d_t tl_reg_h2d;
tlul_pkg::tl_d2h_t tl_reg_d2h;
@@ -94,47 +89,37 @@
end
end
- // TODO(eunchan): Fix it after bus interface is finalized
- assign reg_we = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
- ((tl_reg_h2d.a_opcode == tlul_pkg::PutFullData) ||
- (tl_reg_h2d.a_opcode == tlul_pkg::PutPartialData));
- assign reg_re = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
- (tl_reg_h2d.a_opcode == tlul_pkg::Get);
- assign reg_addr = tl_reg_h2d.a_address[AW-1:0];
- assign reg_wdata = tl_reg_h2d.a_data;
+ tlul_adapter_reg #(
+ .RegAw(AW),
+ .RegDw(DW)
+ ) u_reg_if (
+ .clk_i,
+ .rst_ni,
- assign tl_reg_d2h.d_valid = reg_valid;
- assign tl_reg_d2h.d_opcode = rsp_opcode;
- assign tl_reg_d2h.d_param = '0;
- assign tl_reg_d2h.d_size = FSZ; // always Full Size
- assign tl_reg_d2h.d_source = rspid;
- assign tl_reg_d2h.d_sink = '0; // Used in TL-C
- assign tl_reg_d2h.d_data = reg_rdata;
- assign tl_reg_d2h.d_user = '0; // Doesn't allow additional features yet
- assign tl_reg_d2h.d_error = tl_malformed | tl_addrmiss;
+ .tl_i (tl_reg_h2d),
+ .tl_o (tl_reg_d2h),
- assign tl_reg_d2h.a_ready = reqready;
+ .we_o (reg_we),
+ .re_o (reg_re),
+ .addr_o (reg_addr),
+ .wdata_o (reg_wdata),
+ .be_o (reg_be),
+ .rdata_i (reg_rdata),
+ .error_i (reg_error)
+ );
- assign reqid = tl_reg_h2d.a_source;
+ assign reg_rdata = reg_rdata_next ;
+ assign reg_error = malformed | addrmiss ;
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- tl_malformed <= 1'b1;
- end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
- if ((tl_reg_h2d.a_opcode != tlul_pkg::Get) &&
- (tl_reg_h2d.a_opcode != tlul_pkg::PutFullData) &&
- (tl_reg_h2d.a_opcode != tlul_pkg::PutPartialData)) begin
- tl_malformed <= 1'b1;
- // Only allow Full Write with full mask
- end else if (tl_reg_h2d.a_size != FSZ || tl_reg_h2d.a_mask != {DBW{1'b1}}) begin
- tl_malformed <= 1'b1;
- end else if (tl_reg_h2d.a_user.parity_en == 1'b1) begin
- tl_malformed <= 1'b1;
- end else begin
- tl_malformed <= 1'b0;
- end
+ // Malformed request check only affects to the write access
+ always_comb begin : malformed_check
+ if (reg_we && (reg_be != '1)) begin
+ malformed = 1'b1;
+ end else begin
+ malformed = 1'b0;
end
end
+
// TODO(eunchan): Revise Register Interface logic after REG INTF finalized
// TODO(eunchan): Make concrete scenario
// 1. Write: No response, so that it can guarantee a request completes a clock after we
@@ -150,26 +135,6 @@
// d_ready ___________________/ \______
//
// Above example is fine but if r.b.r doesn't assert within two cycle, then it can be wrong.
- always_ff @(posedge clk_i or negedge rst_ni) begin
- // Not to accept new request when a request is handling
- // #Outstanding := 1
- if (!rst_ni) begin
- reqready <= 1'b0;
- end else if (reg_we || reg_re) begin
- reqready <= 1'b0;
- end else if (outstanding == 1'b0) begin
- reqready <= 1'b1;
- end
- end
-
- // Request/ Response ID
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- rspid <= '0;
- end else if (reg_we || reg_re) begin
- rspid <= reqid;
- end
- end
// Define SW related signals
// Format: <reg>_<field>_{wd|we|qs}
@@ -1012,9 +977,9 @@
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
- tl_addrmiss <= 1'b0;
+ addrmiss <= 1'b0;
end else if (reg_re || reg_we) begin
- tl_addrmiss <= ~|addr_hit;
+ addrmiss <= ~|addr_hit;
end
end
@@ -1108,7 +1073,6 @@
// Read data return
- logic [DW-1:0] reg_rdata_next;
always_comb begin
reg_rdata_next = '0;
unique case (1'b1)
@@ -1227,41 +1191,11 @@
endcase
end
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- reg_valid <= 1'b0;
- reg_rdata <= '0;
- rsp_opcode <= tlul_pkg::AccessAck;
- end else if (reg_re || reg_we) begin
- // Guarantee to return data in a cycle
- reg_valid <= 1'b1;
- if (reg_re) begin
- reg_rdata <= reg_rdata_next;
- rsp_opcode <= tlul_pkg::AccessAckData;
- end else begin
- rsp_opcode <= tlul_pkg::AccessAck;
- end
- end else if (tl_reg_h2d.d_ready) begin
- reg_valid <= 1'b0;
- end
- end
-
- // Outstanding: 1 outstanding at a time. Identical to `reg_valid`
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- outstanding <= 1'b0;
- end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
- outstanding <= 1'b1;
- end else if (tl_reg_d2h.d_valid && tl_reg_h2d.d_ready) begin
- outstanding <= 1'b0;
- end
- end
-
// Assertions for Register Interface
`ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
`ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
- `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> reg_valid, clk_i, !rst_ni)
+ `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid, clk_i, !rst_ni)
`ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
diff --git a/hw/ip/rv_plic/rtl/rv_plic_reg_top.sv b/hw/ip/rv_plic/rtl/rv_plic_reg_top.sv
index c392527..a91f3dd 100644
--- a/hw/ip/rv_plic/rtl/rv_plic_reg_top.sv
+++ b/hw/ip/rv_plic/rtl/rv_plic_reg_top.sv
@@ -20,27 +20,22 @@
import rv_plic_reg_pkg::* ;
localparam AW = 9;
- localparam IW = $bits(tl_i.a_source);
localparam DW = 32;
localparam DBW = DW/8; // Byte Width
localparam logic [$clog2($clog2(DBW)+1)-1:0] FSZ = $clog2(DBW); // Full Size 2^(FSZ) = DBW;
// register signals
- logic reg_we;
- logic reg_re;
- logic [AW-1:0] reg_addr;
- logic [DW-1:0] reg_wdata;
- logic reg_valid;
- logic [DW-1:0] reg_rdata;
- logic tl_malformed, tl_addrmiss;
+ logic reg_we;
+ logic reg_re;
+ logic [AW-1:0] reg_addr;
+ logic [DW-1:0] reg_wdata;
+ logic [DBW-1:0] reg_be;
+ logic [DW-1:0] reg_rdata;
+ logic reg_error;
- // Bus signals
- tlul_pkg::tl_d_op_e rsp_opcode; // AccessAck or AccessAckData
- logic reqready;
- logic [IW-1:0] reqid;
- logic [IW-1:0] rspid;
+ logic malformed, addrmiss;
- logic outstanding;
+ logic [DW-1:0] reg_rdata_next;
tlul_pkg::tl_h2d_t tl_reg_h2d;
tlul_pkg::tl_d2h_t tl_reg_d2h;
@@ -48,47 +43,37 @@
assign tl_reg_h2d = tl_i;
assign tl_o = tl_reg_d2h;
- // TODO(eunchan): Fix it after bus interface is finalized
- assign reg_we = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
- ((tl_reg_h2d.a_opcode == tlul_pkg::PutFullData) ||
- (tl_reg_h2d.a_opcode == tlul_pkg::PutPartialData));
- assign reg_re = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
- (tl_reg_h2d.a_opcode == tlul_pkg::Get);
- assign reg_addr = tl_reg_h2d.a_address[AW-1:0];
- assign reg_wdata = tl_reg_h2d.a_data;
+ tlul_adapter_reg #(
+ .RegAw(AW),
+ .RegDw(DW)
+ ) u_reg_if (
+ .clk_i,
+ .rst_ni,
- assign tl_reg_d2h.d_valid = reg_valid;
- assign tl_reg_d2h.d_opcode = rsp_opcode;
- assign tl_reg_d2h.d_param = '0;
- assign tl_reg_d2h.d_size = FSZ; // always Full Size
- assign tl_reg_d2h.d_source = rspid;
- assign tl_reg_d2h.d_sink = '0; // Used in TL-C
- assign tl_reg_d2h.d_data = reg_rdata;
- assign tl_reg_d2h.d_user = '0; // Doesn't allow additional features yet
- assign tl_reg_d2h.d_error = tl_malformed | tl_addrmiss;
+ .tl_i (tl_reg_h2d),
+ .tl_o (tl_reg_d2h),
- assign tl_reg_d2h.a_ready = reqready;
+ .we_o (reg_we),
+ .re_o (reg_re),
+ .addr_o (reg_addr),
+ .wdata_o (reg_wdata),
+ .be_o (reg_be),
+ .rdata_i (reg_rdata),
+ .error_i (reg_error)
+ );
- assign reqid = tl_reg_h2d.a_source;
+ assign reg_rdata = reg_rdata_next ;
+ assign reg_error = malformed | addrmiss ;
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- tl_malformed <= 1'b1;
- end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
- if ((tl_reg_h2d.a_opcode != tlul_pkg::Get) &&
- (tl_reg_h2d.a_opcode != tlul_pkg::PutFullData) &&
- (tl_reg_h2d.a_opcode != tlul_pkg::PutPartialData)) begin
- tl_malformed <= 1'b1;
- // Only allow Full Write with full mask
- end else if (tl_reg_h2d.a_size != FSZ || tl_reg_h2d.a_mask != {DBW{1'b1}}) begin
- tl_malformed <= 1'b1;
- end else if (tl_reg_h2d.a_user.parity_en == 1'b1) begin
- tl_malformed <= 1'b1;
- end else begin
- tl_malformed <= 1'b0;
- end
+ // Malformed request check only affects to the write access
+ always_comb begin : malformed_check
+ if (reg_we && (reg_be != '1)) begin
+ malformed = 1'b1;
+ end else begin
+ malformed = 1'b0;
end
end
+
// TODO(eunchan): Revise Register Interface logic after REG INTF finalized
// TODO(eunchan): Make concrete scenario
// 1. Write: No response, so that it can guarantee a request completes a clock after we
@@ -104,26 +89,6 @@
// d_ready ___________________/ \______
//
// Above example is fine but if r.b.r doesn't assert within two cycle, then it can be wrong.
- always_ff @(posedge clk_i or negedge rst_ni) begin
- // Not to accept new request when a request is handling
- // #Outstanding := 1
- if (!rst_ni) begin
- reqready <= 1'b0;
- end else if (reg_we || reg_re) begin
- reqready <= 1'b0;
- end else if (outstanding == 1'b0) begin
- reqready <= 1'b1;
- end
- end
-
- // Request/ Response ID
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- rspid <= '0;
- end else if (reg_we || reg_re) begin
- rspid <= reqid;
- end
- end
// Define SW related signals
// Format: <reg>_<field>_{wd|we|qs}
@@ -3910,9 +3875,9 @@
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
- tl_addrmiss <= 1'b0;
+ addrmiss <= 1'b0;
end else if (reg_re || reg_we) begin
- tl_addrmiss <= ~|addr_hit;
+ addrmiss <= ~|addr_hit;
end
end
@@ -4249,7 +4214,6 @@
assign msip0_wd = reg_wdata[0];
// Read data return
- logic [DW-1:0] reg_rdata_next;
always_comb begin
reg_rdata_next = '0;
unique case (1'b1)
@@ -4504,41 +4468,11 @@
endcase
end
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- reg_valid <= 1'b0;
- reg_rdata <= '0;
- rsp_opcode <= tlul_pkg::AccessAck;
- end else if (reg_re || reg_we) begin
- // Guarantee to return data in a cycle
- reg_valid <= 1'b1;
- if (reg_re) begin
- reg_rdata <= reg_rdata_next;
- rsp_opcode <= tlul_pkg::AccessAckData;
- end else begin
- rsp_opcode <= tlul_pkg::AccessAck;
- end
- end else if (tl_reg_h2d.d_ready) begin
- reg_valid <= 1'b0;
- end
- end
-
- // Outstanding: 1 outstanding at a time. Identical to `reg_valid`
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- outstanding <= 1'b0;
- end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
- outstanding <= 1'b1;
- end else if (tl_reg_d2h.d_valid && tl_reg_h2d.d_ready) begin
- outstanding <= 1'b0;
- end
- end
-
// Assertions for Register Interface
`ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
`ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
- `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> reg_valid, clk_i, !rst_ni)
+ `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid, clk_i, !rst_ni)
`ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
diff --git a/hw/ip/rv_timer/rtl/rv_timer_reg_top.sv b/hw/ip/rv_timer/rtl/rv_timer_reg_top.sv
index 96d65c8..6e37a4f 100644
--- a/hw/ip/rv_timer/rtl/rv_timer_reg_top.sv
+++ b/hw/ip/rv_timer/rtl/rv_timer_reg_top.sv
@@ -20,27 +20,22 @@
import rv_timer_reg_pkg::* ;
localparam AW = 9;
- localparam IW = $bits(tl_i.a_source);
localparam DW = 32;
localparam DBW = DW/8; // Byte Width
localparam logic [$clog2($clog2(DBW)+1)-1:0] FSZ = $clog2(DBW); // Full Size 2^(FSZ) = DBW;
// register signals
- logic reg_we;
- logic reg_re;
- logic [AW-1:0] reg_addr;
- logic [DW-1:0] reg_wdata;
- logic reg_valid;
- logic [DW-1:0] reg_rdata;
- logic tl_malformed, tl_addrmiss;
+ logic reg_we;
+ logic reg_re;
+ logic [AW-1:0] reg_addr;
+ logic [DW-1:0] reg_wdata;
+ logic [DBW-1:0] reg_be;
+ logic [DW-1:0] reg_rdata;
+ logic reg_error;
- // Bus signals
- tlul_pkg::tl_d_op_e rsp_opcode; // AccessAck or AccessAckData
- logic reqready;
- logic [IW-1:0] reqid;
- logic [IW-1:0] rspid;
+ logic malformed, addrmiss;
- logic outstanding;
+ logic [DW-1:0] reg_rdata_next;
tlul_pkg::tl_h2d_t tl_reg_h2d;
tlul_pkg::tl_d2h_t tl_reg_d2h;
@@ -48,47 +43,37 @@
assign tl_reg_h2d = tl_i;
assign tl_o = tl_reg_d2h;
- // TODO(eunchan): Fix it after bus interface is finalized
- assign reg_we = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
- ((tl_reg_h2d.a_opcode == tlul_pkg::PutFullData) ||
- (tl_reg_h2d.a_opcode == tlul_pkg::PutPartialData));
- assign reg_re = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
- (tl_reg_h2d.a_opcode == tlul_pkg::Get);
- assign reg_addr = tl_reg_h2d.a_address[AW-1:0];
- assign reg_wdata = tl_reg_h2d.a_data;
+ tlul_adapter_reg #(
+ .RegAw(AW),
+ .RegDw(DW)
+ ) u_reg_if (
+ .clk_i,
+ .rst_ni,
- assign tl_reg_d2h.d_valid = reg_valid;
- assign tl_reg_d2h.d_opcode = rsp_opcode;
- assign tl_reg_d2h.d_param = '0;
- assign tl_reg_d2h.d_size = FSZ; // always Full Size
- assign tl_reg_d2h.d_source = rspid;
- assign tl_reg_d2h.d_sink = '0; // Used in TL-C
- assign tl_reg_d2h.d_data = reg_rdata;
- assign tl_reg_d2h.d_user = '0; // Doesn't allow additional features yet
- assign tl_reg_d2h.d_error = tl_malformed | tl_addrmiss;
+ .tl_i (tl_reg_h2d),
+ .tl_o (tl_reg_d2h),
- assign tl_reg_d2h.a_ready = reqready;
+ .we_o (reg_we),
+ .re_o (reg_re),
+ .addr_o (reg_addr),
+ .wdata_o (reg_wdata),
+ .be_o (reg_be),
+ .rdata_i (reg_rdata),
+ .error_i (reg_error)
+ );
- assign reqid = tl_reg_h2d.a_source;
+ assign reg_rdata = reg_rdata_next ;
+ assign reg_error = malformed | addrmiss ;
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- tl_malformed <= 1'b1;
- end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
- if ((tl_reg_h2d.a_opcode != tlul_pkg::Get) &&
- (tl_reg_h2d.a_opcode != tlul_pkg::PutFullData) &&
- (tl_reg_h2d.a_opcode != tlul_pkg::PutPartialData)) begin
- tl_malformed <= 1'b1;
- // Only allow Full Write with full mask
- end else if (tl_reg_h2d.a_size != FSZ || tl_reg_h2d.a_mask != {DBW{1'b1}}) begin
- tl_malformed <= 1'b1;
- end else if (tl_reg_h2d.a_user.parity_en == 1'b1) begin
- tl_malformed <= 1'b1;
- end else begin
- tl_malformed <= 1'b0;
- end
+ // Malformed request check only affects to the write access
+ always_comb begin : malformed_check
+ if (reg_we && (reg_be != '1)) begin
+ malformed = 1'b1;
+ end else begin
+ malformed = 1'b0;
end
end
+
// TODO(eunchan): Revise Register Interface logic after REG INTF finalized
// TODO(eunchan): Make concrete scenario
// 1. Write: No response, so that it can guarantee a request completes a clock after we
@@ -104,26 +89,6 @@
// d_ready ___________________/ \______
//
// Above example is fine but if r.b.r doesn't assert within two cycle, then it can be wrong.
- always_ff @(posedge clk_i or negedge rst_ni) begin
- // Not to accept new request when a request is handling
- // #Outstanding := 1
- if (!rst_ni) begin
- reqready <= 1'b0;
- end else if (reg_we || reg_re) begin
- reqready <= 1'b0;
- end else if (outstanding == 1'b0) begin
- reqready <= 1'b1;
- end
- end
-
- // Request/ Response ID
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- rspid <= '0;
- end else if (reg_we || reg_re) begin
- rspid <= reqid;
- end
- end
// Define SW related signals
// Format: <reg>_<field>_{wd|we|qs}
@@ -435,9 +400,9 @@
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
- tl_addrmiss <= 1'b0;
+ addrmiss <= 1'b0;
end else if (reg_re || reg_we) begin
- tl_addrmiss <= ~|addr_hit;
+ addrmiss <= ~|addr_hit;
end
end
@@ -474,7 +439,6 @@
assign intr_test0_wd = reg_wdata[0];
// Read data return
- logic [DW-1:0] reg_rdata_next;
always_comb begin
reg_rdata_next = '0;
unique case (1'b1)
@@ -521,41 +485,11 @@
endcase
end
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- reg_valid <= 1'b0;
- reg_rdata <= '0;
- rsp_opcode <= tlul_pkg::AccessAck;
- end else if (reg_re || reg_we) begin
- // Guarantee to return data in a cycle
- reg_valid <= 1'b1;
- if (reg_re) begin
- reg_rdata <= reg_rdata_next;
- rsp_opcode <= tlul_pkg::AccessAckData;
- end else begin
- rsp_opcode <= tlul_pkg::AccessAck;
- end
- end else if (tl_reg_h2d.d_ready) begin
- reg_valid <= 1'b0;
- end
- end
-
- // Outstanding: 1 outstanding at a time. Identical to `reg_valid`
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- outstanding <= 1'b0;
- end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
- outstanding <= 1'b1;
- end else if (tl_reg_d2h.d_valid && tl_reg_h2d.d_ready) begin
- outstanding <= 1'b0;
- end
- end
-
// Assertions for Register Interface
`ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
`ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
- `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> reg_valid, clk_i, !rst_ni)
+ `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid, clk_i, !rst_ni)
`ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
diff --git a/hw/ip/spi_device/rtl/spi_device_reg_top.sv b/hw/ip/spi_device/rtl/spi_device_reg_top.sv
index c53da41..aa7d859 100644
--- a/hw/ip/spi_device/rtl/spi_device_reg_top.sv
+++ b/hw/ip/spi_device/rtl/spi_device_reg_top.sv
@@ -25,27 +25,22 @@
import spi_device_reg_pkg::* ;
localparam AW = 12;
- localparam IW = $bits(tl_i.a_source);
localparam DW = 32;
localparam DBW = DW/8; // Byte Width
localparam logic [$clog2($clog2(DBW)+1)-1:0] FSZ = $clog2(DBW); // Full Size 2^(FSZ) = DBW;
// register signals
- logic reg_we;
- logic reg_re;
- logic [AW-1:0] reg_addr;
- logic [DW-1:0] reg_wdata;
- logic reg_valid;
- logic [DW-1:0] reg_rdata;
- logic tl_malformed, tl_addrmiss;
+ logic reg_we;
+ logic reg_re;
+ logic [AW-1:0] reg_addr;
+ logic [DW-1:0] reg_wdata;
+ logic [DBW-1:0] reg_be;
+ logic [DW-1:0] reg_rdata;
+ logic reg_error;
- // Bus signals
- tlul_pkg::tl_d_op_e rsp_opcode; // AccessAck or AccessAckData
- logic reqready;
- logic [IW-1:0] reqid;
- logic [IW-1:0] rspid;
+ logic malformed, addrmiss;
- logic outstanding;
+ logic [DW-1:0] reg_rdata_next;
tlul_pkg::tl_h2d_t tl_reg_h2d;
tlul_pkg::tl_d2h_t tl_reg_d2h;
@@ -94,47 +89,37 @@
end
end
- // TODO(eunchan): Fix it after bus interface is finalized
- assign reg_we = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
- ((tl_reg_h2d.a_opcode == tlul_pkg::PutFullData) ||
- (tl_reg_h2d.a_opcode == tlul_pkg::PutPartialData));
- assign reg_re = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
- (tl_reg_h2d.a_opcode == tlul_pkg::Get);
- assign reg_addr = tl_reg_h2d.a_address[AW-1:0];
- assign reg_wdata = tl_reg_h2d.a_data;
+ tlul_adapter_reg #(
+ .RegAw(AW),
+ .RegDw(DW)
+ ) u_reg_if (
+ .clk_i,
+ .rst_ni,
- assign tl_reg_d2h.d_valid = reg_valid;
- assign tl_reg_d2h.d_opcode = rsp_opcode;
- assign tl_reg_d2h.d_param = '0;
- assign tl_reg_d2h.d_size = FSZ; // always Full Size
- assign tl_reg_d2h.d_source = rspid;
- assign tl_reg_d2h.d_sink = '0; // Used in TL-C
- assign tl_reg_d2h.d_data = reg_rdata;
- assign tl_reg_d2h.d_user = '0; // Doesn't allow additional features yet
- assign tl_reg_d2h.d_error = tl_malformed | tl_addrmiss;
+ .tl_i (tl_reg_h2d),
+ .tl_o (tl_reg_d2h),
- assign tl_reg_d2h.a_ready = reqready;
+ .we_o (reg_we),
+ .re_o (reg_re),
+ .addr_o (reg_addr),
+ .wdata_o (reg_wdata),
+ .be_o (reg_be),
+ .rdata_i (reg_rdata),
+ .error_i (reg_error)
+ );
- assign reqid = tl_reg_h2d.a_source;
+ assign reg_rdata = reg_rdata_next ;
+ assign reg_error = malformed | addrmiss ;
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- tl_malformed <= 1'b1;
- end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
- if ((tl_reg_h2d.a_opcode != tlul_pkg::Get) &&
- (tl_reg_h2d.a_opcode != tlul_pkg::PutFullData) &&
- (tl_reg_h2d.a_opcode != tlul_pkg::PutPartialData)) begin
- tl_malformed <= 1'b1;
- // Only allow Full Write with full mask
- end else if (tl_reg_h2d.a_size != FSZ || tl_reg_h2d.a_mask != {DBW{1'b1}}) begin
- tl_malformed <= 1'b1;
- end else if (tl_reg_h2d.a_user.parity_en == 1'b1) begin
- tl_malformed <= 1'b1;
- end else begin
- tl_malformed <= 1'b0;
- end
+ // Malformed request check only affects to the write access
+ always_comb begin : malformed_check
+ if (reg_we && (reg_be != '1)) begin
+ malformed = 1'b1;
+ end else begin
+ malformed = 1'b0;
end
end
+
// TODO(eunchan): Revise Register Interface logic after REG INTF finalized
// TODO(eunchan): Make concrete scenario
// 1. Write: No response, so that it can guarantee a request completes a clock after we
@@ -150,26 +135,6 @@
// d_ready ___________________/ \______
//
// Above example is fine but if r.b.r doesn't assert within two cycle, then it can be wrong.
- always_ff @(posedge clk_i or negedge rst_ni) begin
- // Not to accept new request when a request is handling
- // #Outstanding := 1
- if (!rst_ni) begin
- reqready <= 1'b0;
- end else if (reg_we || reg_re) begin
- reqready <= 1'b0;
- end else if (outstanding == 1'b0) begin
- reqready <= 1'b1;
- end
- end
-
- // Request/ Response ID
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- rspid <= '0;
- end else if (reg_we || reg_re) begin
- rspid <= reqid;
- end
- end
// Define SW related signals
// Format: <reg>_<field>_{wd|we|qs}
@@ -1184,9 +1149,9 @@
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
- tl_addrmiss <= 1'b0;
+ addrmiss <= 1'b0;
end else if (reg_re || reg_we) begin
- tl_addrmiss <= ~|addr_hit;
+ addrmiss <= ~|addr_hit;
end
end
@@ -1296,7 +1261,6 @@
assign txf_addr_limit_wd = reg_wdata[31:16];
// Read data return
- logic [DW-1:0] reg_rdata_next;
always_comb begin
reg_rdata_next = '0;
unique case (1'b1)
@@ -1380,41 +1344,11 @@
endcase
end
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- reg_valid <= 1'b0;
- reg_rdata <= '0;
- rsp_opcode <= tlul_pkg::AccessAck;
- end else if (reg_re || reg_we) begin
- // Guarantee to return data in a cycle
- reg_valid <= 1'b1;
- if (reg_re) begin
- reg_rdata <= reg_rdata_next;
- rsp_opcode <= tlul_pkg::AccessAckData;
- end else begin
- rsp_opcode <= tlul_pkg::AccessAck;
- end
- end else if (tl_reg_h2d.d_ready) begin
- reg_valid <= 1'b0;
- end
- end
-
- // Outstanding: 1 outstanding at a time. Identical to `reg_valid`
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- outstanding <= 1'b0;
- end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
- outstanding <= 1'b1;
- end else if (tl_reg_d2h.d_valid && tl_reg_h2d.d_ready) begin
- outstanding <= 1'b0;
- end
- end
-
// Assertions for Register Interface
`ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
`ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
- `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> reg_valid, clk_i, !rst_ni)
+ `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid, clk_i, !rst_ni)
`ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
diff --git a/hw/ip/tlul/adapter_reg.core b/hw/ip/tlul/adapter_reg.core
new file mode 100644
index 0000000..7c7ee71
--- /dev/null
+++ b/hw/ip/tlul/adapter_reg.core
@@ -0,0 +1,21 @@
+CAPI=2:
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+name: "lowrisc:tlul:adapter_reg:0.1"
+description: "TL-UL to Register interface adapter"
+
+filesets:
+ files_rtl:
+ depend:
+ - lowrisc:prim:all
+ - lowrisc:tlul:common
+ files:
+ - rtl/tlul_adapter_reg.sv
+ file_type: systemVerilogSource
+
+targets:
+ default: &default_target
+ filesets:
+ - files_rtl
+ toplevel: tlul_adapter_reg
diff --git a/hw/ip/tlul/rtl/tlul_adapter_reg.sv b/hw/ip/tlul/rtl/tlul_adapter_reg.sv
new file mode 100644
index 0000000..1790c1c
--- /dev/null
+++ b/hw/ip/tlul/rtl/tlul_adapter_reg.sv
@@ -0,0 +1,98 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+/**
+ * Tile-Link UL adapter for Register interface
+ */
+
+module tlul_adapter_reg import tlul_pkg::*; #(
+ parameter int RegAw = 8,
+ parameter int RegDw = 32, // Shall be matched with TL_DW
+ localparam int RegBw = RegDw/8
+) (
+ input clk_i,
+ input rst_ni,
+
+ // TL-UL interface
+ input tl_h2d_t tl_i,
+ output tl_d2h_t tl_o,
+
+ // Register interface
+ output logic re_o,
+ output logic we_o,
+ output logic [RegAw-1:0] addr_o,
+ output logic [RegDw-1:0] wdata_o,
+ output logic [RegBw-1:0] be_o,
+ input [RegDw-1:0] rdata_i,
+ input error_i
+);
+
+ localparam int IW = $bits(tl_i.a_source);
+ localparam int SZW = $bits(tl_i.a_size);
+
+ logic outstanding; // Indicates current request is pending
+ logic a_ack, d_ack;
+
+ logic [RegDw-1:0] rdata;
+ logic error;
+
+ logic [IW-1:0] reqid;
+ logic [SZW-1:0] reqsz;
+ tl_d_op_e rspop;
+
+ assign a_ack = tl_i.a_valid & tl_o.a_ready;
+ assign d_ack = tl_o.d_valid & tl_i.d_ready;
+ // Request signal
+ assign we_o = a_ack & ((tl_i.a_opcode == PutFullData) | (tl_i.a_opcode == PutPartialData));
+ assign re_o = a_ack & (tl_i.a_opcode == Get);
+ assign addr_o = tl_i.a_address[RegAw-1:0];
+ assign wdata_o = tl_i.a_data;
+ assign be_o = tl_i.a_mask;
+
+
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if (!rst_ni) outstanding <= 1'b0;
+ else if (a_ack) outstanding <= 1'b1;
+ else if (d_ack) outstanding <= 1'b0;
+ end
+
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if (!rst_ni) begin
+ reqid <= '0;
+ reqsz <= '0;
+ rspop <= AccessAck;
+ end else if (a_ack) begin
+ reqid <= tl_i.a_source;
+ reqsz <= tl_i.a_size;
+ rspop <= (re_o) ? AccessAckData : AccessAck ;
+ end
+ end
+
+ always_ff @(posedge clk_i or negedge rst_ni) begin
+ if (!rst_ni) begin
+ rdata <= '0;
+ error <= 1'b0;
+ end else if (a_ack) begin
+ rdata <= rdata_i;
+ error <= error_i | (tl_i.a_user.parity_en == 1'b1);
+ end
+ end
+
+ assign tl_o = '{
+ a_ready: ~outstanding,
+ d_valid: outstanding,
+ d_opcode: rspop,
+ d_param: '0,
+ d_size: reqsz,
+ d_source: reqid,
+ d_sink: '0,
+ d_data: rdata,
+ d_user: '0,
+ d_error: error
+ };
+
+
+ `ASSERT_INIT(MatchedWidthAssert, RegDw == top_pkg::TL_DW)
+
+endmodule
diff --git a/hw/ip/tlul/tlul.core b/hw/ip/tlul/tlul.core
index 414f80a..0cc42e0 100644
--- a/hw/ip/tlul/tlul.core
+++ b/hw/ip/tlul/tlul.core
@@ -11,6 +11,7 @@
- lowrisc:tlul:socket_1n
- lowrisc:tlul:socket_m1
- lowrisc:tlul:adapter_sram
+ - lowrisc:tlul:adapter_reg
- lowrisc:tlul:adapter_flash
- lowrisc:tlul:sram2tlul
diff --git a/hw/ip/uart/rtl/uart_reg_top.sv b/hw/ip/uart/rtl/uart_reg_top.sv
index 5d88300..570dedf 100644
--- a/hw/ip/uart/rtl/uart_reg_top.sv
+++ b/hw/ip/uart/rtl/uart_reg_top.sv
@@ -20,27 +20,22 @@
import uart_reg_pkg::* ;
localparam AW = 6;
- localparam IW = $bits(tl_i.a_source);
localparam DW = 32;
localparam DBW = DW/8; // Byte Width
localparam logic [$clog2($clog2(DBW)+1)-1:0] FSZ = $clog2(DBW); // Full Size 2^(FSZ) = DBW;
// register signals
- logic reg_we;
- logic reg_re;
- logic [AW-1:0] reg_addr;
- logic [DW-1:0] reg_wdata;
- logic reg_valid;
- logic [DW-1:0] reg_rdata;
- logic tl_malformed, tl_addrmiss;
+ logic reg_we;
+ logic reg_re;
+ logic [AW-1:0] reg_addr;
+ logic [DW-1:0] reg_wdata;
+ logic [DBW-1:0] reg_be;
+ logic [DW-1:0] reg_rdata;
+ logic reg_error;
- // Bus signals
- tlul_pkg::tl_d_op_e rsp_opcode; // AccessAck or AccessAckData
- logic reqready;
- logic [IW-1:0] reqid;
- logic [IW-1:0] rspid;
+ logic malformed, addrmiss;
- logic outstanding;
+ logic [DW-1:0] reg_rdata_next;
tlul_pkg::tl_h2d_t tl_reg_h2d;
tlul_pkg::tl_d2h_t tl_reg_d2h;
@@ -48,47 +43,37 @@
assign tl_reg_h2d = tl_i;
assign tl_o = tl_reg_d2h;
- // TODO(eunchan): Fix it after bus interface is finalized
- assign reg_we = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
- ((tl_reg_h2d.a_opcode == tlul_pkg::PutFullData) ||
- (tl_reg_h2d.a_opcode == tlul_pkg::PutPartialData));
- assign reg_re = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
- (tl_reg_h2d.a_opcode == tlul_pkg::Get);
- assign reg_addr = tl_reg_h2d.a_address[AW-1:0];
- assign reg_wdata = tl_reg_h2d.a_data;
+ tlul_adapter_reg #(
+ .RegAw(AW),
+ .RegDw(DW)
+ ) u_reg_if (
+ .clk_i,
+ .rst_ni,
- assign tl_reg_d2h.d_valid = reg_valid;
- assign tl_reg_d2h.d_opcode = rsp_opcode;
- assign tl_reg_d2h.d_param = '0;
- assign tl_reg_d2h.d_size = FSZ; // always Full Size
- assign tl_reg_d2h.d_source = rspid;
- assign tl_reg_d2h.d_sink = '0; // Used in TL-C
- assign tl_reg_d2h.d_data = reg_rdata;
- assign tl_reg_d2h.d_user = '0; // Doesn't allow additional features yet
- assign tl_reg_d2h.d_error = tl_malformed | tl_addrmiss;
+ .tl_i (tl_reg_h2d),
+ .tl_o (tl_reg_d2h),
- assign tl_reg_d2h.a_ready = reqready;
+ .we_o (reg_we),
+ .re_o (reg_re),
+ .addr_o (reg_addr),
+ .wdata_o (reg_wdata),
+ .be_o (reg_be),
+ .rdata_i (reg_rdata),
+ .error_i (reg_error)
+ );
- assign reqid = tl_reg_h2d.a_source;
+ assign reg_rdata = reg_rdata_next ;
+ assign reg_error = malformed | addrmiss ;
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- tl_malformed <= 1'b1;
- end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
- if ((tl_reg_h2d.a_opcode != tlul_pkg::Get) &&
- (tl_reg_h2d.a_opcode != tlul_pkg::PutFullData) &&
- (tl_reg_h2d.a_opcode != tlul_pkg::PutPartialData)) begin
- tl_malformed <= 1'b1;
- // Only allow Full Write with full mask
- end else if (tl_reg_h2d.a_size != FSZ || tl_reg_h2d.a_mask != {DBW{1'b1}}) begin
- tl_malformed <= 1'b1;
- end else if (tl_reg_h2d.a_user.parity_en == 1'b1) begin
- tl_malformed <= 1'b1;
- end else begin
- tl_malformed <= 1'b0;
- end
+ // Malformed request check only affects to the write access
+ always_comb begin : malformed_check
+ if (reg_we && (reg_be != '1)) begin
+ malformed = 1'b1;
+ end else begin
+ malformed = 1'b0;
end
end
+
// TODO(eunchan): Revise Register Interface logic after REG INTF finalized
// TODO(eunchan): Make concrete scenario
// 1. Write: No response, so that it can guarantee a request completes a clock after we
@@ -104,26 +89,6 @@
// d_ready ___________________/ \______
//
// Above example is fine but if r.b.r doesn't assert within two cycle, then it can be wrong.
- always_ff @(posedge clk_i or negedge rst_ni) begin
- // Not to accept new request when a request is handling
- // #Outstanding := 1
- if (!rst_ni) begin
- reqready <= 1'b0;
- end else if (reg_we || reg_re) begin
- reqready <= 1'b0;
- end else if (outstanding == 1'b0) begin
- reqready <= 1'b1;
- end
- end
-
- // Request/ Response ID
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- rspid <= '0;
- end else if (reg_we || reg_re) begin
- rspid <= reqid;
- end
- end
// Define SW related signals
// Format: <reg>_<field>_{wd|we|qs}
@@ -1457,9 +1422,9 @@
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
- tl_addrmiss <= 1'b0;
+ addrmiss <= 1'b0;
end else if (reg_re || reg_we) begin
- tl_addrmiss <= ~|addr_hit;
+ addrmiss <= ~|addr_hit;
end
end
@@ -1612,7 +1577,6 @@
assign timeout_ctrl_en_wd = reg_wdata[31];
// Read data return
- logic [DW-1:0] reg_rdata_next;
always_comb begin
reg_rdata_next = '0;
unique case (1'b1)
@@ -1710,41 +1674,11 @@
endcase
end
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- reg_valid <= 1'b0;
- reg_rdata <= '0;
- rsp_opcode <= tlul_pkg::AccessAck;
- end else if (reg_re || reg_we) begin
- // Guarantee to return data in a cycle
- reg_valid <= 1'b1;
- if (reg_re) begin
- reg_rdata <= reg_rdata_next;
- rsp_opcode <= tlul_pkg::AccessAckData;
- end else begin
- rsp_opcode <= tlul_pkg::AccessAck;
- end
- end else if (tl_reg_h2d.d_ready) begin
- reg_valid <= 1'b0;
- end
- end
-
- // Outstanding: 1 outstanding at a time. Identical to `reg_valid`
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- outstanding <= 1'b0;
- end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
- outstanding <= 1'b1;
- end else if (tl_reg_d2h.d_valid && tl_reg_h2d.d_ready) begin
- outstanding <= 1'b0;
- end
- end
-
// Assertions for Register Interface
`ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
`ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
- `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> reg_valid, clk_i, !rst_ni)
+ `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid, clk_i, !rst_ni)
`ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
diff --git a/hw/ip/usbuart/rtl/usbuart_reg_top.sv b/hw/ip/usbuart/rtl/usbuart_reg_top.sv
index 9b96ec5..06be81e 100644
--- a/hw/ip/usbuart/rtl/usbuart_reg_top.sv
+++ b/hw/ip/usbuart/rtl/usbuart_reg_top.sv
@@ -20,27 +20,22 @@
import usbuart_reg_pkg::* ;
localparam AW = 6;
- localparam IW = $bits(tl_i.a_source);
localparam DW = 32;
localparam DBW = DW/8; // Byte Width
localparam logic [$clog2($clog2(DBW)+1)-1:0] FSZ = $clog2(DBW); // Full Size 2^(FSZ) = DBW;
// register signals
- logic reg_we;
- logic reg_re;
- logic [AW-1:0] reg_addr;
- logic [DW-1:0] reg_wdata;
- logic reg_valid;
- logic [DW-1:0] reg_rdata;
- logic tl_malformed, tl_addrmiss;
+ logic reg_we;
+ logic reg_re;
+ logic [AW-1:0] reg_addr;
+ logic [DW-1:0] reg_wdata;
+ logic [DBW-1:0] reg_be;
+ logic [DW-1:0] reg_rdata;
+ logic reg_error;
- // Bus signals
- tlul_pkg::tl_d_op_e rsp_opcode; // AccessAck or AccessAckData
- logic reqready;
- logic [IW-1:0] reqid;
- logic [IW-1:0] rspid;
+ logic malformed, addrmiss;
- logic outstanding;
+ logic [DW-1:0] reg_rdata_next;
tlul_pkg::tl_h2d_t tl_reg_h2d;
tlul_pkg::tl_d2h_t tl_reg_d2h;
@@ -48,47 +43,37 @@
assign tl_reg_h2d = tl_i;
assign tl_o = tl_reg_d2h;
- // TODO(eunchan): Fix it after bus interface is finalized
- assign reg_we = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
- ((tl_reg_h2d.a_opcode == tlul_pkg::PutFullData) ||
- (tl_reg_h2d.a_opcode == tlul_pkg::PutPartialData));
- assign reg_re = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
- (tl_reg_h2d.a_opcode == tlul_pkg::Get);
- assign reg_addr = tl_reg_h2d.a_address[AW-1:0];
- assign reg_wdata = tl_reg_h2d.a_data;
+ tlul_adapter_reg #(
+ .RegAw(AW),
+ .RegDw(DW)
+ ) u_reg_if (
+ .clk_i,
+ .rst_ni,
- assign tl_reg_d2h.d_valid = reg_valid;
- assign tl_reg_d2h.d_opcode = rsp_opcode;
- assign tl_reg_d2h.d_param = '0;
- assign tl_reg_d2h.d_size = FSZ; // always Full Size
- assign tl_reg_d2h.d_source = rspid;
- assign tl_reg_d2h.d_sink = '0; // Used in TL-C
- assign tl_reg_d2h.d_data = reg_rdata;
- assign tl_reg_d2h.d_user = '0; // Doesn't allow additional features yet
- assign tl_reg_d2h.d_error = tl_malformed | tl_addrmiss;
+ .tl_i (tl_reg_h2d),
+ .tl_o (tl_reg_d2h),
- assign tl_reg_d2h.a_ready = reqready;
+ .we_o (reg_we),
+ .re_o (reg_re),
+ .addr_o (reg_addr),
+ .wdata_o (reg_wdata),
+ .be_o (reg_be),
+ .rdata_i (reg_rdata),
+ .error_i (reg_error)
+ );
- assign reqid = tl_reg_h2d.a_source;
+ assign reg_rdata = reg_rdata_next ;
+ assign reg_error = malformed | addrmiss ;
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- tl_malformed <= 1'b1;
- end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
- if ((tl_reg_h2d.a_opcode != tlul_pkg::Get) &&
- (tl_reg_h2d.a_opcode != tlul_pkg::PutFullData) &&
- (tl_reg_h2d.a_opcode != tlul_pkg::PutPartialData)) begin
- tl_malformed <= 1'b1;
- // Only allow Full Write with full mask
- end else if (tl_reg_h2d.a_size != FSZ || tl_reg_h2d.a_mask != {DBW{1'b1}}) begin
- tl_malformed <= 1'b1;
- end else if (tl_reg_h2d.a_user.parity_en == 1'b1) begin
- tl_malformed <= 1'b1;
- end else begin
- tl_malformed <= 1'b0;
- end
+ // Malformed request check only affects to the write access
+ always_comb begin : malformed_check
+ if (reg_we && (reg_be != '1)) begin
+ malformed = 1'b1;
+ end else begin
+ malformed = 1'b0;
end
end
+
// TODO(eunchan): Revise Register Interface logic after REG INTF finalized
// TODO(eunchan): Make concrete scenario
// 1. Write: No response, so that it can guarantee a request completes a clock after we
@@ -104,26 +89,6 @@
// d_ready ___________________/ \______
//
// Above example is fine but if r.b.r doesn't assert within two cycle, then it can be wrong.
- always_ff @(posedge clk_i or negedge rst_ni) begin
- // Not to accept new request when a request is handling
- // #Outstanding := 1
- if (!rst_ni) begin
- reqready <= 1'b0;
- end else if (reg_we || reg_re) begin
- reqready <= 1'b0;
- end else if (outstanding == 1'b0) begin
- reqready <= 1'b1;
- end
- end
-
- // Request/ Response ID
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- rspid <= '0;
- end else if (reg_we || reg_re) begin
- rspid <= reqid;
- end
- end
// Define SW related signals
// Format: <reg>_<field>_{wd|we|qs}
@@ -1569,9 +1534,9 @@
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
- tl_addrmiss <= 1'b0;
+ addrmiss <= 1'b0;
end else if (reg_re || reg_we) begin
- tl_addrmiss <= ~|addr_hit;
+ addrmiss <= ~|addr_hit;
end
end
@@ -1736,7 +1701,6 @@
assign usbparam_parity_req_re = addr_hit[13] && reg_re;
// Read data return
- logic [DW-1:0] reg_rdata_next;
always_comb begin
reg_rdata_next = '0;
unique case (1'b1)
@@ -1846,41 +1810,11 @@
endcase
end
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- reg_valid <= 1'b0;
- reg_rdata <= '0;
- rsp_opcode <= tlul_pkg::AccessAck;
- end else if (reg_re || reg_we) begin
- // Guarantee to return data in a cycle
- reg_valid <= 1'b1;
- if (reg_re) begin
- reg_rdata <= reg_rdata_next;
- rsp_opcode <= tlul_pkg::AccessAckData;
- end else begin
- rsp_opcode <= tlul_pkg::AccessAck;
- end
- end else if (tl_reg_h2d.d_ready) begin
- reg_valid <= 1'b0;
- end
- end
-
- // Outstanding: 1 outstanding at a time. Identical to `reg_valid`
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- outstanding <= 1'b0;
- end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
- outstanding <= 1'b1;
- end else if (tl_reg_d2h.d_valid && tl_reg_h2d.d_ready) begin
- outstanding <= 1'b0;
- end
- end
-
// Assertions for Register Interface
`ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
`ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
- `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> reg_valid, clk_i, !rst_ni)
+ `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid, clk_i, !rst_ni)
`ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
diff --git a/hw/top_earlgrey/rtl/rv_plic_reg_top.sv b/hw/top_earlgrey/rtl/rv_plic_reg_top.sv
index f64f327..ff7464c 100644
--- a/hw/top_earlgrey/rtl/rv_plic_reg_top.sv
+++ b/hw/top_earlgrey/rtl/rv_plic_reg_top.sv
@@ -20,27 +20,22 @@
import rv_plic_reg_pkg::* ;
localparam AW = 9;
- localparam IW = $bits(tl_i.a_source);
localparam DW = 32;
localparam DBW = DW/8; // Byte Width
localparam logic [$clog2($clog2(DBW)+1)-1:0] FSZ = $clog2(DBW); // Full Size 2^(FSZ) = DBW;
// register signals
- logic reg_we;
- logic reg_re;
- logic [AW-1:0] reg_addr;
- logic [DW-1:0] reg_wdata;
- logic reg_valid;
- logic [DW-1:0] reg_rdata;
- logic tl_malformed, tl_addrmiss;
+ logic reg_we;
+ logic reg_re;
+ logic [AW-1:0] reg_addr;
+ logic [DW-1:0] reg_wdata;
+ logic [DBW-1:0] reg_be;
+ logic [DW-1:0] reg_rdata;
+ logic reg_error;
- // Bus signals
- tlul_pkg::tl_d_op_e rsp_opcode; // AccessAck or AccessAckData
- logic reqready;
- logic [IW-1:0] reqid;
- logic [IW-1:0] rspid;
+ logic malformed, addrmiss;
- logic outstanding;
+ logic [DW-1:0] reg_rdata_next;
tlul_pkg::tl_h2d_t tl_reg_h2d;
tlul_pkg::tl_d2h_t tl_reg_d2h;
@@ -48,47 +43,37 @@
assign tl_reg_h2d = tl_i;
assign tl_o = tl_reg_d2h;
- // TODO(eunchan): Fix it after bus interface is finalized
- assign reg_we = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
- ((tl_reg_h2d.a_opcode == tlul_pkg::PutFullData) ||
- (tl_reg_h2d.a_opcode == tlul_pkg::PutPartialData));
- assign reg_re = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
- (tl_reg_h2d.a_opcode == tlul_pkg::Get);
- assign reg_addr = tl_reg_h2d.a_address[AW-1:0];
- assign reg_wdata = tl_reg_h2d.a_data;
+ tlul_adapter_reg #(
+ .RegAw(AW),
+ .RegDw(DW)
+ ) u_reg_if (
+ .clk_i,
+ .rst_ni,
- assign tl_reg_d2h.d_valid = reg_valid;
- assign tl_reg_d2h.d_opcode = rsp_opcode;
- assign tl_reg_d2h.d_param = '0;
- assign tl_reg_d2h.d_size = FSZ; // always Full Size
- assign tl_reg_d2h.d_source = rspid;
- assign tl_reg_d2h.d_sink = '0; // Used in TL-C
- assign tl_reg_d2h.d_data = reg_rdata;
- assign tl_reg_d2h.d_user = '0; // Doesn't allow additional features yet
- assign tl_reg_d2h.d_error = tl_malformed | tl_addrmiss;
+ .tl_i (tl_reg_h2d),
+ .tl_o (tl_reg_d2h),
- assign tl_reg_d2h.a_ready = reqready;
+ .we_o (reg_we),
+ .re_o (reg_re),
+ .addr_o (reg_addr),
+ .wdata_o (reg_wdata),
+ .be_o (reg_be),
+ .rdata_i (reg_rdata),
+ .error_i (reg_error)
+ );
- assign reqid = tl_reg_h2d.a_source;
+ assign reg_rdata = reg_rdata_next ;
+ assign reg_error = malformed | addrmiss ;
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- tl_malformed <= 1'b1;
- end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
- if ((tl_reg_h2d.a_opcode != tlul_pkg::Get) &&
- (tl_reg_h2d.a_opcode != tlul_pkg::PutFullData) &&
- (tl_reg_h2d.a_opcode != tlul_pkg::PutPartialData)) begin
- tl_malformed <= 1'b1;
- // Only allow Full Write with full mask
- end else if (tl_reg_h2d.a_size != FSZ || tl_reg_h2d.a_mask != {DBW{1'b1}}) begin
- tl_malformed <= 1'b1;
- end else if (tl_reg_h2d.a_user.parity_en == 1'b1) begin
- tl_malformed <= 1'b1;
- end else begin
- tl_malformed <= 1'b0;
- end
+ // Malformed request check only affects to the write access
+ always_comb begin : malformed_check
+ if (reg_we && (reg_be != '1)) begin
+ malformed = 1'b1;
+ end else begin
+ malformed = 1'b0;
end
end
+
// TODO(eunchan): Revise Register Interface logic after REG INTF finalized
// TODO(eunchan): Make concrete scenario
// 1. Write: No response, so that it can guarantee a request completes a clock after we
@@ -104,26 +89,6 @@
// d_ready ___________________/ \______
//
// Above example is fine but if r.b.r doesn't assert within two cycle, then it can be wrong.
- always_ff @(posedge clk_i or negedge rst_ni) begin
- // Not to accept new request when a request is handling
- // #Outstanding := 1
- if (!rst_ni) begin
- reqready <= 1'b0;
- end else if (reg_we || reg_re) begin
- reqready <= 1'b0;
- end else if (outstanding == 1'b0) begin
- reqready <= 1'b1;
- end
- end
-
- // Request/ Response ID
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- rspid <= '0;
- end else if (reg_we || reg_re) begin
- rspid <= reqid;
- end
- end
// Define SW related signals
// Format: <reg>_<field>_{wd|we|qs}
@@ -6219,9 +6184,9 @@
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
- tl_addrmiss <= 1'b0;
+ addrmiss <= 1'b0;
end else if (reg_re || reg_we) begin
- tl_addrmiss <= ~|addr_hit;
+ addrmiss <= ~|addr_hit;
end
end
@@ -6758,7 +6723,6 @@
assign msip0_wd = reg_wdata[0];
// Read data return
- logic [DW-1:0] reg_rdata_next;
always_comb begin
reg_rdata_next = '0;
unique case (1'b1)
@@ -7162,41 +7126,11 @@
endcase
end
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- reg_valid <= 1'b0;
- reg_rdata <= '0;
- rsp_opcode <= tlul_pkg::AccessAck;
- end else if (reg_re || reg_we) begin
- // Guarantee to return data in a cycle
- reg_valid <= 1'b1;
- if (reg_re) begin
- reg_rdata <= reg_rdata_next;
- rsp_opcode <= tlul_pkg::AccessAckData;
- end else begin
- rsp_opcode <= tlul_pkg::AccessAck;
- end
- end else if (tl_reg_h2d.d_ready) begin
- reg_valid <= 1'b0;
- end
- end
-
- // Outstanding: 1 outstanding at a time. Identical to `reg_valid`
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- outstanding <= 1'b0;
- end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
- outstanding <= 1'b1;
- end else if (tl_reg_d2h.d_valid && tl_reg_h2d.d_ready) begin
- outstanding <= 1'b0;
- end
- end
-
// Assertions for Register Interface
`ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
`ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
- `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> reg_valid, clk_i, !rst_ni)
+ `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid, clk_i, !rst_ni)
`ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)
diff --git a/util/reggen/reg_top.tpl.sv b/util/reggen/reg_top.tpl.sv
index d47c927..1c71ac5 100644
--- a/util/reggen/reg_top.tpl.sv
+++ b/util/reggen/reg_top.tpl.sv
@@ -31,27 +31,22 @@
import ${block.name}_reg_pkg::* ;
localparam AW = ${block.addr_width};
- localparam IW = $bits(tl_i.a_source);
localparam DW = ${block.width};
localparam DBW = DW/8; // Byte Width
localparam logic [$clog2($clog2(DBW)+1)-1:0] FSZ = $clog2(DBW); // Full Size 2^(FSZ) = DBW;
// register signals
- logic reg_we;
- logic reg_re;
- logic [AW-1:0] reg_addr;
- logic [DW-1:0] reg_wdata;
- logic reg_valid;
- logic [DW-1:0] reg_rdata;
- logic tl_malformed, tl_addrmiss;
+ logic reg_we;
+ logic reg_re;
+ logic [AW-1:0] reg_addr;
+ logic [DW-1:0] reg_wdata;
+ logic [DBW-1:0] reg_be;
+ logic [DW-1:0] reg_rdata;
+ logic reg_error;
- // Bus signals
- tlul_pkg::tl_d_op_e rsp_opcode; // AccessAck or AccessAckData
- logic reqready;
- logic [IW-1:0] reqid;
- logic [IW-1:0] rspid;
+ logic malformed, addrmiss;
- logic outstanding;
+ logic [DW-1:0] reg_rdata_next;
tlul_pkg::tl_h2d_t tl_reg_h2d;
tlul_pkg::tl_d2h_t tl_reg_d2h;
@@ -113,47 +108,37 @@
end
% endif
- // TODO(eunchan): Fix it after bus interface is finalized
- assign reg_we = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
- ((tl_reg_h2d.a_opcode == tlul_pkg::PutFullData) ||
- (tl_reg_h2d.a_opcode == tlul_pkg::PutPartialData));
- assign reg_re = tl_reg_h2d.a_valid && tl_reg_d2h.a_ready &&
- (tl_reg_h2d.a_opcode == tlul_pkg::Get);
- assign reg_addr = tl_reg_h2d.a_address[AW-1:0];
- assign reg_wdata = tl_reg_h2d.a_data;
+ tlul_adapter_reg #(
+ .RegAw(AW),
+ .RegDw(DW)
+ ) u_reg_if (
+ .clk_i,
+ .rst_ni,
- assign tl_reg_d2h.d_valid = reg_valid;
- assign tl_reg_d2h.d_opcode = rsp_opcode;
- assign tl_reg_d2h.d_param = '0;
- assign tl_reg_d2h.d_size = FSZ; // always Full Size
- assign tl_reg_d2h.d_source = rspid;
- assign tl_reg_d2h.d_sink = '0; // Used in TL-C
- assign tl_reg_d2h.d_data = reg_rdata;
- assign tl_reg_d2h.d_user = '0; // Doesn't allow additional features yet
- assign tl_reg_d2h.d_error = tl_malformed | tl_addrmiss;
+ .tl_i (tl_reg_h2d),
+ .tl_o (tl_reg_d2h),
- assign tl_reg_d2h.a_ready = reqready;
+ .we_o (reg_we),
+ .re_o (reg_re),
+ .addr_o (reg_addr),
+ .wdata_o (reg_wdata),
+ .be_o (reg_be),
+ .rdata_i (reg_rdata),
+ .error_i (reg_error)
+ );
- assign reqid = tl_reg_h2d.a_source;
+ assign reg_rdata = reg_rdata_next ;
+ assign reg_error = malformed | addrmiss ;
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- tl_malformed <= 1'b1;
- end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
- if ((tl_reg_h2d.a_opcode != tlul_pkg::Get) &&
- (tl_reg_h2d.a_opcode != tlul_pkg::PutFullData) &&
- (tl_reg_h2d.a_opcode != tlul_pkg::PutPartialData)) begin
- tl_malformed <= 1'b1;
- // Only allow Full Write with full mask
- end else if (tl_reg_h2d.a_size != FSZ || tl_reg_h2d.a_mask != {DBW{1'b1}}) begin
- tl_malformed <= 1'b1;
- end else if (tl_reg_h2d.a_user.parity_en == 1'b1) begin
- tl_malformed <= 1'b1;
- end else begin
- tl_malformed <= 1'b0;
- end
+ // Malformed request check only affects to the write access
+ always_comb begin : malformed_check
+ if (reg_we && (reg_be != '1)) begin
+ malformed = 1'b1;
+ end else begin
+ malformed = 1'b0;
end
end
+
// TODO(eunchan): Revise Register Interface logic after REG INTF finalized
// TODO(eunchan): Make concrete scenario
// 1. Write: No response, so that it can guarantee a request completes a clock after we
@@ -169,26 +154,6 @@
// d_ready ___________________/ \______
//
// Above example is fine but if r.b.r doesn't assert within two cycle, then it can be wrong.
- always_ff @(posedge clk_i or negedge rst_ni) begin
- // Not to accept new request when a request is handling
- // #Outstanding := 1
- if (!rst_ni) begin
- reqready <= 1'b0;
- end else if (reg_we || reg_re) begin
- reqready <= 1'b0;
- end else if (outstanding == 1'b0) begin
- reqready <= 1'b1;
- end
- end
-
- // Request/ Response ID
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- rspid <= '0;
- end else if (reg_we || reg_re) begin
- rspid <= reqid;
- end
- end
// Define SW related signals
// Format: <reg>_<field>_{wd|we|qs}
@@ -278,9 +243,9 @@
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
- tl_addrmiss <= 1'b0;
+ addrmiss <= 1'b0;
end else if (reg_re || reg_we) begin
- tl_addrmiss <= ~|addr_hit;
+ addrmiss <= ~|addr_hit;
end
end
@@ -315,7 +280,6 @@
% endfor
// Read data return
- logic [DW-1:0] reg_rdata_next;
always_comb begin
reg_rdata_next = '0;
unique case (1'b1)
@@ -355,41 +319,11 @@
endcase
end
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- reg_valid <= 1'b0;
- reg_rdata <= '0;
- rsp_opcode <= tlul_pkg::AccessAck;
- end else if (reg_re || reg_we) begin
- // Guarantee to return data in a cycle
- reg_valid <= 1'b1;
- if (reg_re) begin
- reg_rdata <= reg_rdata_next;
- rsp_opcode <= tlul_pkg::AccessAckData;
- end else begin
- rsp_opcode <= tlul_pkg::AccessAck;
- end
- end else if (tl_reg_h2d.d_ready) begin
- reg_valid <= 1'b0;
- end
- end
-
- // Outstanding: 1 outstanding at a time. Identical to `reg_valid`
- always_ff @(posedge clk_i or negedge rst_ni) begin
- if (!rst_ni) begin
- outstanding <= 1'b0;
- end else if (tl_reg_h2d.a_valid && tl_reg_d2h.a_ready) begin
- outstanding <= 1'b1;
- end else if (tl_reg_d2h.d_valid && tl_reg_h2d.d_ready) begin
- outstanding <= 1'b0;
- end
- end
-
// Assertions for Register Interface
`ASSERT_PULSE(wePulse, reg_we, clk_i, !rst_ni)
`ASSERT_PULSE(rePulse, reg_re, clk_i, !rst_ni)
- `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> reg_valid, clk_i, !rst_ni)
+ `ASSERT(reAfterRv, $rose(reg_re || reg_we) |=> tl_o.d_valid, clk_i, !rst_ni)
`ASSERT(en2addrHit, (reg_we || reg_re) |-> $onehot0(addr_hit), clk_i, !rst_ni)