sed Part IV · Module 9 · RTL and Filelist Maintenance
Signal, Module, and Define Renaming
Chapter 9.1 edited paths. This edits a language, and that changes everything. Renaming axi_awvalid across a design means axi_awvalid_d and axi_awvalid_q must not change, which needs a word boundary — and the word boundary is spelled one way on GNU sed and another on BSD, with one of those spellings failing silently on the other. So the only check you can trust is a number that comes out the same on every machine. The chapter runs the full procedure on a real RTL tree and then compiles it, because a claim about a hardware language deserves a compiler as its witness rather than a careful-sounding paragraph.
Advanced21 min readsedPart IVRTLRenamingPortability
Part IV · Module 9 · Chapter 9.2 · Signal, Module, and Define Renaming
1. The Design
A small tree, built so that every way a rename can go wrong is present:
cat -n rtl/alu.sv 1 `include "defs.svh"
2 module alu (
3 input logic clk,
4 input logic axi_awvalid,
5 output logic axi_awready,
6 input logic [31:0] axi_awaddr
7 );
8 logic axi_awvalid_d; // pipelined copy of axi_awvalid
9 logic axi_awvalid_q;
10 always_ff @(posedge clk) axi_awvalid_d <= axi_awvalid;
11 assign axi_awready = ~axi_awvalid_q;
12 endmoduleThe job: rename the port axi_awvalid to m_axi_awvalid. Lines 4 and 10 must change. Lines 8 and 9 declare different signals — the pipelined copies — and must not.
2. The Procedure
1. AUDIT what names exist, and which share a prefix?
2. COUNT how many lines should change?
3. DRY RUN the word-boundary rename, both spellings
4. APPLY over a file list you have read
5. COMPILE the only real proof3. Step 1 — Audit the Names
Start with what is in the tree rather than what you remember. The registered audit lists every module name:
sed -n -E 's/^[[:space:]]*module[[:space:]]+([a-z_][a-z0-9_]*).*/\1/p' rtl/*.sv | sort -ualu
fifo
macro_userThree modules. Now the identifier you are about to rename — and specifically, what else starts with it:
grep -oh 'axi_awvalid[a-z_0-9]*' rtl/*.sv | sort -uaxi_awvalid
axi_awvalid_d
axi_awvalid_qThree distinct identifiers share the prefix. That single command is the whole problem, discovered before anything is written. A naive s/axi_awvalid/m_axi_awvalid/g would rename all three, and _d and _q are different signals.
And which files are involved:
grep -rc 'axi_awvalid' rtl/ | grep -v ':0$'rtl/fifo.sv:3
rtl/macro_user.sv:1
rtl/alu.sv:5
rtl/defs.svh:1Four files, and note the fourth: defs.svh. Keep that in mind for section 6.
4. Step 2 and 3 — Count and Dry Run
The naive version, on alu.sv alone:
sed -n 's/axi_awvalid/m_axi_awvalid/gp' rtl/alu.sv input logic m_axi_awvalid,
logic m_axi_awvalid_d; // pipelined copy of m_axi_awvalid
logic m_axi_awvalid_q;
always_ff @(posedge clk) m_axi_awvalid_d <= m_axi_awvalid;
assign axi_awready = ~m_axi_awvalid_q;Five lines. m_axi_awvalid_d and m_axi_awvalid_q are signals that do not exist.
The word-boundary version, in the BSD/macOS spelling:
sed -n 's/[[:<:]]axi_awvalid[[:>:]]/m_axi_awvalid/gp' rtl/alu.sv input logic m_axi_awvalid,
logic axi_awvalid_d; // pipelined copy of m_axi_awvalid
always_ff @(posedge clk) axi_awvalid_d <= m_axi_awvalid;Three lines, and the declarations of _d and _q are intact. Line 9 is absent from the output entirely because nothing on it changed.
As counts:
sed -n 's/axi_awvalid/&/gp' rtl/alu.sv | wc -l 5sed -n 's/[[:<:]]axi_awvalid[[:>:]]/&/gp' rtl/alu.sv | wc -l 3Five versus three. The replacement is & in both, so these commands measure without editing — Chapter 7.3's trick.
5. Step 4 — Apply Across the Tree
The file list comes from the audit, not from a glob you typed from memory. Chapter 8.3's rules apply: read the list, then use it.
grep -rl --null 'axi_awvalid' rtl/ | xargs -0 -n1 echo read it first
grep -rl --null 'axi_awvalid' rtl/ | xargs -0 \
sed -i '' 's/[[:<:]]axi_awvalid[[:>:]]/m_axi_awvalid/g'Write --null in full — Chapter 8.3 measured -Z meaning something else entirely on two of the three greps available. And -i '' is the BSD spelling from Chapter 7.1.
Commit before this, per Chapter 7.2. The next section is why that matters more here than anywhere else in the track.
6. Step 5 — Compile, Because Nothing Else Is Proof
Every other chapter in this track proves its claims with sed's own output. Here the claim is about a hardware language, so the witness has to be a compiler.
Baseline — all three modules build before anything is touched:
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.svThree commands, no output, exit 0 each. Now apply the correct word-boundary rename to the SystemVerilog sources:
sed -i '' 's/[[:<:]]axi_awvalid[[:>:]]/m_axi_awvalid/g' work/*.svExit 0. The rename is right, the boundaries held, _d and _q are untouched. Compile again:
iverilog -g2012 -I work -o /tmp/mu.out work/macro_user.svwork/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 build is broken, by a rename that was correct in every way this chapter has described so far.
Look at what happened:
cat -n work/macro_user.sv 1 `include "defs.svh"
2 module macro_user (input logic clk, input logic m_axi_awvalid);
3 wire v = `AXI_VLD;
4 endmodulecat -n work/defs.svh 1 `define AXI_VLD axi_awvalid
2 `define DBG 1The port was renamed. The macro still expands to the old name, so line 3 references a signal that no longer exists.
Two independent causes, and both are worth separating:
- The glob missed the file.
work/*.svdoes not matchdefs.svh. Section 3's audit listed four files containing the name and this was the fourth. - The identifier is reached through a macro. Even with the file included,
AXI_VLDis a name for a name — sed sees two unrelated strings where the compiler sees one signal.
The first is fixable here. Include the header:
sed -i '' 's/[[:<:]]axi_awvalid[[:>:]]/m_axi_awvalid/g' work/defs.svh
cat -n work/defs.svh 1 `define AXI_VLD m_axi_awvalid
2 `define DBG 1iverilog -g2012 -I work -o /tmp/mu.out work/macro_user.svExit 0. Fixed.
7. The Audit That Would Have Prevented It
Section 3 already had the answer, which is the point of doing it first:
grep -rl 'axi_awvalid' rtl/ | sortrtl/alu.sv
rtl/defs.svh
rtl/fifo.sv
rtl/macro_user.svls rtl/*.svrtl/alu.sv
rtl/fifo.sv
rtl/macro_user.svFour files contain the name; *.sv matches three. The discrepancy is visible in two commands, before any edit, and it is the whole bug.
The general rule: derive the file list from the content, not from an extension. grep -rl --null 'name' rtl/ finds every file that mentions the identifier regardless of what it is called — .sv, .svh, .v, .vh, a filelist, a constraint file, a README. A glob encodes an assumption about naming; a content search does not.
8. Renaming a Module or a Define
The same procedure, with two differences worth stating.
A module name appears in its declaration and at every instantiation, and the instantiation looks nothing like the declaration:
module alu ( … ); the declaration
alu u_alu ( … ); an instantiation — the name is first on the lineBoth are caught by a word-boundary rename, but the audit matters more because an instance may live in a file that has no other reference to the module. Section 3's grep -rl is again the right list.
A define name has an extra hazard: the definition and the uses are in different files by design, and the uses are written with a backtick. `AXI_VLD and AXI_VLD are the same macro, so a pattern anchored on the backtick will miss the definition and a pattern without it will match both — which is usually what you want, and worth checking rather than assuming.
What neither of these changes is the ceiling. A rename that sed performs correctly can still be wrong, because the text it matched does not always mean what you think.
9. Think It Through
1. What single command tells you a naive rename is unsafe, before you run it?
grep -oh 'name[a-z_0-9]*' rtl/*.sv | sort -u. If it returns more than one line, other identifiers share your prefix and a plain substitution will catch them. Section 3 returned three.
2. Your rename script works on Linux and renames nothing on a Mac, exit 0. Why?
It uses GNU's \b, which BSD sed does not implement as a word boundary — section 4 measured zero lines changed, exit 0. Use the detection branch, and assert the expected count so a zero is a failure rather than a silent success.
3. The rename exits 0 and the build fails with "Unable to bind". What are the two things to check?
Which files were in the list, and whether the identifier is reached through a macro. Section 6 hit both at once: *.sv missed defs.svh, and that header defines a macro expanding to the old name. grep -rl versus your glob is the first check; grep -rn 'define.*name'` is the second.
4. Why derive the file list from grep -rl rather than from *.sv?
Because a glob encodes a guess about file extensions and the content search does not. Section 7 measured four files containing the identifier where *.sv matched three. The missing one was a header, and it broke the build.
5. You rename a module. What is different from renaming a signal?
The uses are instantiations, which may sit in files that mention the module nowhere else — so the audit matters more, and grep -rl is the only reliable way to find them. The substitution itself is the same word-boundary rename.
6. The rename compiled cleanly. Is it correct?
Not necessarily. A compile proves the design still elaborates; it does not prove you renamed the right things. This chapter's own fixture has a rename that compiles and is wrong — the identifier inside a $display string, which changes what the simulation prints without changing what it does. That is Chapter 9.3, and it is the reason this module has a third chapter.
10. Summary
- Audit before you edit.
grep -oh 'name[a-z_0-9]*' | sort -ureturned three identifiers sharing the prefix — the problem, found in one command. - A rename needs a word boundary. Naive: 5 lines changed on
alu.sv. Word-boundary: 3. Measured with&as the replacement, so neither command edited anything. - The spellings are not portable.
[[:<:]]/[[:>:]]work on BSD; GNU's\bchanged 0 lines and exited 0 here. Branch onsed --version, and assert the count. - Derive the file list from content, not from a glob. Four files contained the identifier;
*.svmatched three. - Compile as step 5. Baseline exit 0; after a correct-looking rename,
iveriloggaveUnable to bind wire/reg/memory 'axi_awvalid', exit 2 — because the glob misseddefs.svhand the signal is reached through a macro. - Renaming the header too restored exit 0, but only because the macro happened to be a simple alias.
- A module rename is the same procedure with a stronger need for the audit, since instantiations hide in unrelated files.
- A clean compile is not a correct rename. It proves elaboration, not intent.
The compile caught the macro. It did not catch the comment this rename rewrote, or the string inside $display that now prints a signal name the design no longer uses — both compile perfectly. Chapter 9.3 — Safe RTL Refactoring Boundaries is about exactly those: what text substitution cannot know, which renames therefore need a syntax-aware tool, and how to tell the difference before you start.
Where this fits
Part of the sed curriculum.
