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

Further Verilator lint fixes #22

Merged
merged 16 commits into from
Mar 4, 2024
Merged

Conversation

marnovandermaas
Copy link
Contributor

Found these issues while compiling CHERIoT Ibex with Verilator. It mainly fixes width mismatches and unused variables.

This PR does not remove all unused variables, there is one remaining width issue and two unoptimized flat issues.

@marnovandermaas marnovandermaas force-pushed the lint_fixes branch 2 times, most recently from cbf7fc7 to 1533e71 Compare February 20, 2024 15:50
Copy link
Contributor

@kliuMsft kliuMsft left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a lot of changes - and I am not super sure the behavior stays the same (e.g. line 347). Generally, could we do a LEC before/after such chnages? If you have already done that please do let me know. Thanks,

@marnovandermaas
Copy link
Contributor Author

This is a lot of changes - and I am not super sure the behavior stays the same (e.g. line 347). Generally, could we do a LEC before/after such chnages? If you have already done that please do let me know. Thanks,

I'm used to making these changes through code review. I'll mark this PR as draft until I get a chance to resolve the conflicts and look at equivalence checking.

@kliuMsft
Copy link
Contributor

Thanks, I appreciate it. And I agree normally it would be done early in the design phase after code review, etc. However we are pretty late in the game already in this case and a little extra caution is probably a good thing.

@marnovandermaas
Copy link
Contributor Author

marnovandermaas commented Feb 22, 2024

Ok, I ran JasperGold's Sequential Equivalence Checker on the ibexc_top module before and after the fixes. It says that from an interface point of view they are the same. The only differences it detected were output pins that are undriven before the changes but connected by my fixes: alert_major_bus_o, alert_major_internal_o, alert_minor_o and scramble_req_o. I don't have access to any other equivalence checking tools unfortunately.

This is the output of the check:

   Interface Check Summary
=============================
primary_input       - PASSED
primary_output      - PASSED
user_bbox_input     - PASSED
user_bbox_output    - PASSED
auto_bbox_input     - PASSED
auto_bbox_output    - PASSED
user_task_stopat    - PASSED
user_env_stopat     - PASSED
setup_stopat        - PASSED
internal_undriven   - PASSED
x_assignment        - PASSED
x_default_assignment- PASSED
x_index_out_of_range- PASSED
x_divide_by_zero    - PASSED
x_misc_undriven     - PASSED
x_low_power         - PASSED
x_bus_contention    - PASSED
x_bus_floating      - PASSED
reset_x             - PASSED
imp_assumptions     - PASSED
=============================
Overall interface check result - PASSED

@kliuMsft
Copy link
Contributor

That's excellent, thanks. Will approve and merge then.

@kliuMsft
Copy link
Contributor

I noticed the PR is still in draft status - any remaining conflict?

@marnovandermaas marnovandermaas marked this pull request as ready for review February 23, 2024 13:21
@marnovandermaas
Copy link
Contributor Author

I noticed the PR is still in draft status - any remaining conflict?

No conflicts as far as I'm aware, just forgot to mark as ready to review yesterday.

Copy link
Contributor

@kliuMsft kliuMsft left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

About 'int typecasting (range_ok in cheri_trvk_stage) and cheri_regfile - why are we casting those to int (which I think is signed by default)? The intention in both places is to do unsigned math. It may not matter here is the data width is less than 32-bit however it seems unnecessary confusion to me.

@marnovandermaas
Copy link
Contributor Author

About 'int typecasting (range_ok in cheri_trvk_stage) and cheri_regfile - why are we casting those to int (which I think is signed by default)? The intention in both places is to do unsigned math. It may not matter here is the data width is less than 32-bit however it seems unnecessary confusion to me.

Yes, you are right. SystemVerilog makes it a bit difficult to do casting to compound types like int unsigned. I've pushed an example solution:

diff --git a/rtl/cheri_pkg.sv b/rtl/cheri_pkg.sv
index 8ca19314..0ef0c0d3 100644
--- a/rtl/cheri_pkg.sv
+++ b/rtl/cheri_pkg.sv
@@ -42,6 +42,9 @@ package cheri_pkg;
   parameter logic [2:0] OTYPE_SENTRY     = 3'd1;
   parameter logic [2:0] OTYPE_UNSEALED   = 3'd0;
 
+  // For ease of casting
+  typedef int unsigned u_int_t;
+
   // Compressed (regFile) capability type
   typedef struct packed {
     logic                valid;
diff --git a/rtl/cheri_regfile.sv b/rtl/cheri_regfile.sv
index 5ab1d81d..199e3e5c 100644
--- a/rtl/cheri_regfile.sv
+++ b/rtl/cheri_regfile.sv
@@ -142,8 +142,8 @@ module cheri_regfile import cheri_pkg::*; #(
     assign rf_cap[i] = rf_cap_q[i];
   end
 
-  assign rcap_a = (int'(raddr_a_i) < NCAPS) ? rf_cap[raddr_a_i] : NULL_REG_CAP;
-  assign rcap_b = (int'(raddr_b_i) < NCAPS) ? rf_cap[raddr_b_i] : NULL_REG_CAP;
+  assign rcap_a = (u_int_t'(raddr_a_i) < NCAPS) ? rf_cap[raddr_a_i] : NULL_REG_CAP;
+  assign rcap_b = (u_int_t'(raddr_b_i) < NCAPS) ? rf_cap[raddr_b_i] : NULL_REG_CAP;
 
   if (CheriPPLBC) begin : g_regrdy
 
diff --git a/rtl/cheri_trvk_stage.sv b/rtl/cheri_trvk_stage.sv
index 78cf24dd..0025f549 100644
--- a/rtl/cheri_trvk_stage.sv
+++ b/rtl/cheri_trvk_stage.sv
@@ -61,7 +61,7 @@ module cheri_trvk_stage #(
   assign tsmap_addr_o  = tsmap_ptr[15:5];
 
   // not a sealling cap and pointing to valid TSMAP range
-  assign range_ok      = (int'(tsmap_ptr[31:5]) <= TSMapSize) &&
+  assign range_ok      = (u_int_t'(tsmap_ptr[31:5]) <= TSMapSize) &&
                          ~((in_cap_q.cperms[4:3]==2'b00) && (|in_cap_q.cperms[2:0]));
   assign tsmap_cs_o    = (cpu_op_valid_q[0] | tbre_op_valid_q[0]) & cap_good_q[0];

What do you think? It does add an extra typedef to cheri_pkg.

@kliuMsft
Copy link
Contributor

That should work. However, why do we need typecasting in those cases? Does it help resolve any ambiguities (I can't quite see it) or there is some kind of blanket lint policy regarding arithmetics? If not I'd rather have less code..

@marnovandermaas
Copy link
Contributor Author

That should work. However, why do we need typecasting in those cases? Does it help resolve any ambiguities (I can't quite see it) or there is some kind of blanket lint policy regarding arithmetics? If not I'd rather have less code..

I'm not sure if it resolves any ambiguities but it stops Verilator from complaining that we are comparing two values of different bit width. Unsigned integers are 32 bits while raddr_x_i and tsmap_ptr are less.

@marnovandermaas
Copy link
Contributor Author

I force pushed to resolve the conflicts in rtl/ibex_controller.sv.

@kliuMsft
Copy link
Contributor

Hopefully not trying to be obnoxious here.. But I am disagreeing with enforcing this linting rule. verilog/sv is fairly clear about the behavior in this case (0-expand to the widest operand first then perform comparison). As such, the change is unnecessary and would make the code more complex and less readable.

@kliuMsft
Copy link
Contributor

@marnovandermaas, also if we really want to match width explicitly, wouldn't something like 32'({tsmap_ptr[31:5]}) work? That way at least we stay unsigned and don't have to define a new type..

These cause width lint errors from Verilator
This fixes a lint error from Verilator
This fixes a lint error in Verilator
This fixes an unused lint error in Verilator
These outputs include the alert outputs and the scramble request.
This fixes undriven output lint errors in Verilator.
@marnovandermaas
Copy link
Contributor Author

Hopefully not trying to be obnoxious here.. But I am disagreeing with enforcing this linting rule. verilog/sv is fairly clear about the behavior in this case (0-expand to the widest operand first then perform comparison). As such, the change is unnecessary and would make the code more complex and less readable.

Ok, I've removed these changes. I can always add some lint waivers for these particular cases.

@kliuMsft kliuMsft merged commit a0053e3 into microsoft:main Mar 4, 2024
2 checks passed
@kliuMsft
Copy link
Contributor

kliuMsft commented Mar 4, 2024

Thanks - should be merged into main now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants