Skip to content
VLSI Mentor

sed Part IV · Module 9 · RTL and Filelist Maintenance

Safe RTL Refactoring Boundaries

Chapter 9.2 renamed an identifier as carefully as sed allows: audited first, word boundaries, a file list derived from content, and a compile at the end. This chapter is about what that still cannot reach. The difference is not skill with regular expressions — it is that sed matches characters while a compiler resolves meaning, and in a hardware language the same characters mean different things depending on where they sit. The same rename from the last chapter produces four distinct outcomes on one small tree. One of them stops the build, which is the good case. The other three compile perfectly and are wrong.

Advanced20 min readsedPart IVRTLRefactoringTool Selection

Part IV · Module 9 · Chapter 9.3 · Safe RTL Refactoring Boundaries

1. Characters Versus Meaning

sed decides what to change by looking at characters. A compiler decides what things are by resolving them: this identifier is a port of this module, that one is a macro, this run of characters is inside a string literal, that one is a comment.

Those two views agree most of the time, which is why Chapter 9.2's procedure works on most renames. This chapter is about the cases where they disagree, and the uncomfortable property they share: sed is not wrong in any of them. It matched what you asked for. The mismatch is between what you asked for and what you meant.

2. One Rename, Four Outcomes

Everything below uses the tree from Chapter 9.2 and the same rename — axi_awvalid to m_axi_awvalid, with word boundaries, applied across the files that contain it.

The baseline is that the design builds:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
iverilog -g2012 -I work -o /tmp/alu.out  work/alu.sv
iverilog -g2012 -I work -o /tmp/fifo.out work/fifo.sv
iverilog -g2012 -I work -o /tmp/mu.out   work/macro_user.sv
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet

Three commands, no output, exit status 0 each.

3. The Four Blind Spots

Four paired rows. In each, the left box is the text sed matches and the right box is what that text actually is. Row one, an identifier in code, is a signal, and renaming it is correct. Row two, an identifier in another module, is a different signal. Row three, an identifier inside a string, is simulation output. Row four, an identifier in a comment, is documentation.In codesed matches the textA signalrenaming is correctIn another modulesed matches the textA different signalrenaming is wrongInside a stringsed matches the textSimulation outputrenaming changes behaviourInside a commentsed matches the textDocumentationrenaming is noise12
Figure 1 — the same characters, two readings. On the left is what sed matches; on the right is what the compiler resolves it to. Only the top row is a case where the two agree and a rename is safe. Each arrow is one reading of one piece of text, and the rows are independent — there is no flow between them.

A fifth case — a macro — is not on the diagram because it is not a misreading of one piece of text. It is the identifier being reachable under a second name, and it is the one the compiler catches.

4. The Loud One — a Macro

Apply the rename to the SystemVerilog sources:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
sed -i '' 's/[[:<:]]axi_awvalid[[:>:]]/m_axi_awvalid/g' work/*.sv
iverilog -g2012 -I work -o /tmp/mu.out work/macro_user.sv
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
work/macro_user.sv:3: error: Unable to bind wire/reg/memory `axi_awvalid' in `macro_user'
work/macro_user.sv:3: error: Unable to elaborate r-value: axi_awvalid
2 error(s) during elaboration.

Exit status 2. The port became m_axi_awvalid; the header still says:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
cat -n work/defs.svh
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
     1	`define AXI_VLD m_axi_awvalid
     2	`define DBG 1

— after it was included in the rename. Before that it read `define AXI_VLD axi_awvalid, and line 3 of macro_user.sv referenced a signal that no longer existed.

This is the case to be grateful for. A macro is an indirection the compiler must resolve, so when the two halves disagree, elaboration fails loudly with a file and a line. Chapter 9.2 covered the mechanics; the point here is the category: a boundary that breaks the build is not the dangerous kind.

What makes macros genuinely hard is only partly this. `define AXI_VLD axi_awvalid is a simple alias, so renaming both sides works. A macro that builds an identifier — `define PORT(n) axi_n_valid — constructs names that never appear as text anywhere, and no amount of searching will find them.

5. The Silent One — Scope

Here is the second module:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
cat -n work/fifo.sv
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
     1	module fifo (
     2	    input logic clk,
     3	    input logic m_axi_awvalid
     4	);
     5	  // NOTE: m_axi_awvalid here is a LOCAL port, unrelated to alu's
     6	  initial $display("fifo: m_axi_awvalid wired");
     7	endmodule

That is after the rename. Before it, line 3 declared a port called axi_awvalid — a completely separate signal that happens to share a name with alu's, as the comment on line 5 was there to tell you.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
iverilog -g2012 -I work -o /tmp/fifo.out work/fifo.sv
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet

Exit status 0. It compiles. Of course it does — renaming a port and its uses consistently within a module is always valid. The design is still correct; it is just not the change you asked for.

sed cannot know these are different signals, because they are the same characters. Identity in a hardware language comes from scope — which module, which block, which generate branch — and scope is a property the compiler builds and a text matcher does not have.

6. The Other Silent Ones — Strings and Comments

Both are visible in the fifo.sv listing above, and both compiled.

The string. Line 6 was $display("fifo: axi_awvalid wired") and is now $display("fifo: m_axi_awvalid wired"). The design is unchanged; what the simulation prints is not.

That matters more than it sounds, because log text is frequently load-bearing. A regression checker that greps for a known message, a scoreboard that parses $display output, a waveform annotation, a message a verification engineer searches for by hand — all of them key on the literal text. The rename silently moved the goalposts, and the failure arrives later as "the checker stopped finding its line", with nothing connecting it to a signal rename from last week.

The comment. Line 5 said axi_awvalid here is a LOCAL port and now says m_axi_awvalid. Harmless to the build, and it is now documentation describing a signal under a name that — in this module — is at best confusing.

The comment case is the mildest and the most common. It is usually what you want: if the signal is renamed, references to it in prose probably should be too. The trouble is that sed cannot distinguish a comment about this signal from a comment that merely mentions the string, so it is right by luck rather than by analysis.

7. The Decision Rule

A rename is a sed job when all three of these hold, and each is one command:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   1. the identifier is unique — no other name shares its prefix
      grep -oh 'name[a-z_0-9]*' -r rtl/ | sort -u        expect one line

   2. it has no macro alias
      grep -rn '`define.*\bname\b' rtl/                  expect nothing

   3. it appears in no string you depend on
      grep -rn '"[^"]*name' rtl/                         read every hit

If any of them fails, you are in one of two situations:

  • A syntax-aware tool. An HDL-aware editor or linter that resolves scope can rename a signal properly. If you have one, this is not a sed job and never was.
  • A compile-and-review loop. Run the rename, compile every target, read the entire diff rather than skimming it, and treat each string and comment hit as a decision rather than a side effect. That is defensible for a small tree and does not scale to a large one.

And a fourth case worth naming: do not rename it. A signal name that is merely unfashionable, in a block that is stable and verified, is not worth the risk this chapter describes. The question "what does this change buy" deserves an answer before the question "how do I make the change".

8. What This Does Not Apply To

The boundaries here are properties of source code: scope, macros, strings, comments. They exist because RTL is a language with a compiler.

The rest of Part IV mostly is not that. A simulation log, a synthesis report, a timing report — these are tool output. They are flat, line-oriented, generated rather than authored, and nobody compiles them. That puts them back in exactly the territory Chapter 9.1's filelist occupied, and it is why sed remains the right tool for them.

Module 10 — Simulation and Verification Automation starts there, and the distinction is worth carrying: editing what a tool reads needs this chapter's caution; editing what a tool wrote usually does not.

9. Think It Through

1. Why is the macro failure the best of the four?

Because it stops the build with a file and a line number. The compiler has to resolve a macro, so a half-applied rename is a contradiction it cannot ignore — exit 2, immediately. The other three compile cleanly, which means the only thing standing between them and a release is somebody reading a diff.

2. Two modules have a signal with the same name. Why can sed not keep them apart?

Because they are the same characters. Identity in a hardware language comes from scope, and scope is something a compiler constructs by parsing the design. A text matcher has no notion of which module it is inside — it has a line, and the line looks identical in both files.

3. Your rename compiled everywhere and a regression started failing a week later. What is the likely cause?

A string. Section 6's $display text changed, so anything keying on that literal — a checker, a log scraper, a grep in a run script — stopped matching. It compiles because the design is fine; the breakage is in the agreement between the design's output and something that reads it.

4. Write the three checks that say whether a rename is a sed job.

Uniqueness: grep -oh 'name[a-z_0-9]*' -r rtl/ | sort -u should return one line. No macro alias: grep -rn '`define.*name' rtl/ should return nothing. No load-bearing strings: grep -rn '"[^"]*name' rtl/ should return nothing you depend on. All three pass, and Chapter 9.2's procedure is sufficient.

5. Can you write a pattern that skips comments?

For whole-line comments, yes — a negated address. For a trailing comment on a line of code, no: the line is half code and half prose, and sed's unit is the line. Strings are harder still, because recognising one means tracking quote state, which is parsing. Chapter 8.4's third question sends parsing to a parser.

6. Which parts of Part IV does this chapter's caution apply to?

The parts that edit source. A simulation log, a synthesis report and a timing report are tool output — flat, generated, uncompiled — and they have none of these properties, which is why the rest of Part IV can use sed freely. The rule is whether something compiles what you are editing.

10. Summary

  • sed matches characters; a compiler resolves meaning. Every boundary here is a place where the two disagree, and in none of them is sed wrong.
  • One rename on one small tree produced four different outcomes.
  • A macro breaks the build — Unable to bind wire/reg/memory 'axi_awvalid', exit 2. This is the good case: loud, located, unmissable. A macro that constructs an identifier is worse, because the name never appears as text.
  • Scope fails silently. A second module's identically-named port was renamed too; iverilog exit 0. The result is a valid design that is not the one you asked for, and nothing records it.
  • A string fails silently and changes behaviour. $display("fifo: axi_awvalid wired") now prints a different name, so anything keying on that text stops matching — later, with no link back to the rename.
  • A comment fails silently and harmlessly, and is usually what you wanted — by luck, not analysis.
  • You cannot exclude strings and comments with a pattern. Whole-line comments yield to an address; a trailing comment does not, and a string needs parsing.
  • Three checks decide it: the identifier is unique, has no macro alias, and appears in no string you depend on. One command each.
  • If a check fails: a syntax-aware tool, or a compile-and-review loop, or do not rename it at all.
  • This caution applies to source, not to tool output — which is why the rest of Part IV is sed territory again.

That closes Module 9 and the source-editing half of Part IV. You can migrate a filelist, rename an identifier about as well as a text tool permits, and say precisely where that stops. Module 10 — Simulation and Verification Automation moves from what the tools read to what they write: updating run scripts across VCS, Xcelium and Questa, and turning UVM logs and whole regressions into something comparable.

Where this fits

Part of the sed curriculum.