Repository navigation
synth: delete make memory, mem_dump.py and mem.json #4750
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| # Log every inferred memory with its dimensions. With mock set, shrink each | ||
| # memory over max_bits to one row, kept as a module when keep_mocked is set; | ||
| # otherwise stop with an error naming every memory over max_bits that has a | ||
| # write port. Returns the mocked memories as a list of {module width size}. | ||
| proc synth_memory_max_bits { max_bits mock keep_mocked } { | ||
| memory_collect | ||
| set mocked {} | ||
| set over {} | ||
| foreach path [split [string trim [tee -q -s result.string select -list t:\$mem_v2]] "\n"] { | ||
| set index [string first "/" $path] | ||
| set module [string range $path 0 [expr { $index - 1 }]] | ||
| set instance [string range $path [expr { $index + 1 }] end] | ||
|
|
||
| set width [rtlil::get_param -uint $module $instance WIDTH] | ||
| set size [rtlil::get_param -uint $module $instance SIZE] | ||
| set rom [expr { [rtlil::get_param -uint $module $instance WR_PORTS] == 0 }] | ||
| set nbits [expr { $width * $size }] | ||
| puts "Memory $path has dimensions $size x $width = $nbits[expr { $rom ? ", a ROM" : "" }]" | ||
| if { $nbits <= $max_bits } { | ||
| continue | ||
| } | ||
| if { $mock } { | ||
| rtlil::set_param -uint $module $instance SIZE 1 | ||
| puts "Shrunk memory $path from $size rows to 1" | ||
| lappend mocked [list $module $width $size] | ||
| if { $keep_mocked } { | ||
| select -module $module | ||
| setattr -mod -set keep_hierarchy 1 | ||
| select -clear | ||
| } | ||
| } elseif { !$rom } { | ||
| lappend over "$path $size x $width = $nbits" | ||
| } | ||
| } | ||
| if { [llength $over] > 0 } { | ||
| error "Memories over SYNTH_MEMORY_MAX_BITS=$max_bits, which would go into\ | ||
| flip-flops: [join $over {, }]. Put them in macros (AUTO_MEMORIES,\ | ||
| fakeram), mock them (SYNTH_MOCK_LARGE_MEMORIES=1) or raise the limit." | ||
| } | ||
| return $mocked | ||
| } | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,101 @@ | ||||||||
| #!/usr/bin/env python3 | ||||||||
| """SYNTH_MEMORY_MAX_BITS stops synthesis on a read/write memory over the | ||||||||
| limit, and lets a ROM of the same size through. | ||||||||
|
|
||||||||
| synth_memory_max_bits logs every memory yosys inferred and stops with an | ||||||||
| error naming each read/write memory over the limit. A ROM, a $mem_v2 with | ||||||||
| no write port, holds constants that synthesis maps to logic: it is logged, | ||||||||
| marked as a ROM, and not counted. With SYNTH_MOCK_LARGE_MEMORIES, a memory | ||||||||
| over the limit is shrunk to one row instead. | ||||||||
|
|
||||||||
| Skipped when no yosys is available: YOSYS_EXE or yosys on PATH. | ||||||||
| """ | ||||||||
|
|
||||||||
| import os | ||||||||
| import shutil | ||||||||
| import subprocess | ||||||||
| import tempfile | ||||||||
| import unittest | ||||||||
|
|
||||||||
| MAX_BITS_TCL = os.path.join( | ||||||||
| os.path.dirname(os.path.abspath(__file__)), | ||||||||
| "..", | ||||||||
| "scripts", | ||||||||
| "memories", | ||||||||
| "max_bits.tcl", | ||||||||
| ) | ||||||||
|
|
||||||||
| # A RAM with one write port, 32 x 128 = 4096 bits, and a ROM twice its size, | ||||||||
| # 64 x 128 = 8192 bits | ||||||||
| DESIGN = """\ | ||||||||
| module ram (input clk, input we, input [4:0] addr, input [127:0] d, | ||||||||
| output reg [127:0] q); | ||||||||
| reg [127:0] mem [0:31]; | ||||||||
| always @(posedge clk) begin | ||||||||
| if (we) mem[addr] <= d; | ||||||||
| q <= mem[addr]; | ||||||||
| end | ||||||||
| endmodule | ||||||||
| module rom (input clk, input [5:0] addr, output reg [127:0] q); | ||||||||
| reg [127:0] mem [0:63]; | ||||||||
| integer i; | ||||||||
| initial for (i = 0; i < 64; i = i + 1) mem[i] = {4{i * 32'h9e3779b9}}; | ||||||||
| always @(posedge clk) q <= mem[addr]; | ||||||||
| endmodule | ||||||||
| module top (input clk, input we, input [5:0] addr, input [127:0] d, | ||||||||
| output [127:0] q0, q1); | ||||||||
| ram u_ram (.clk, .we, .addr(addr[4:0]), .d, .q(q0)); | ||||||||
| rom u_rom (.clk, .addr, .q(q1)); | ||||||||
| endmodule | ||||||||
| """ | ||||||||
|
|
||||||||
|
|
||||||||
| class TestMemoryMaxBits(unittest.TestCase): | ||||||||
| def run_check(self, max_bits, mock=0): | ||||||||
| yosys = os.environ.get("YOSYS_EXE") or shutil.which("yosys") | ||||||||
| if not yosys: | ||||||||
| self.skipTest("no yosys") | ||||||||
| with tempfile.TemporaryDirectory() as tmp: | ||||||||
| design = os.path.join(tmp, "top.v") | ||||||||
| with open(design, "w") as f: | ||||||||
| f.write(DESIGN) | ||||||||
| script = os.path.join(tmp, "check.tcl") | ||||||||
| with open(script, "w") as f: | ||||||||
| f.write( | ||||||||
| "yosys -import\n" | ||||||||
| f"source {{{MAX_BITS_TCL}}}\n" | ||||||||
| f"yosys read_verilog -sv {{{design}}}\n" | ||||||||
| "yosys hierarchy -top top\n" | ||||||||
| "yosys proc\n" | ||||||||
| "yosys memory -nomap\n" | ||||||||
| f'puts "mocked: [synth_memory_max_bits {max_bits} {mock} 0]"\n' | ||||||||
| ) | ||||||||
| result = subprocess.run( | ||||||||
| [yosys, "-q", "-c", script], capture_output=True, text=True | ||||||||
| ) | ||||||||
| return result.returncode, result.stdout + result.stderr | ||||||||
|
|
||||||||
| def test_ram_over_limit_stops(self): | ||||||||
| returncode, output = self.run_check(2048) | ||||||||
| self.assertNotEqual(returncode, 0, output) | ||||||||
| error = output.split("over SYNTH_MEMORY_MAX_BITS=2048")[1] | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the test fails for an unexpected reason (e.g., Yosys syntax error or file not found), the output will not contain the string
Suggested change
|
||||||||
| self.assertRegex(error, r"ram/\S+ 32 x 128 = 4096") | ||||||||
| self.assertNotIn("rom/", error) | ||||||||
|
|
||||||||
| def test_rom_over_limit_passes(self): | ||||||||
| returncode, output = self.run_check(4096) | ||||||||
| self.assertEqual(returncode, 0, output) | ||||||||
| self.assertRegex( | ||||||||
| output, r"Memory rom/\S+ has dimensions 64 x 128 = 8192, a ROM\n" | ||||||||
| ) | ||||||||
| self.assertRegex(output, r"Memory ram/\S+ has dimensions 32 x 128 = 4096\n") | ||||||||
|
|
||||||||
| def test_mock_shrinks_instead_of_stopping(self): | ||||||||
| returncode, output = self.run_check(2048, mock=1) | ||||||||
| self.assertEqual(returncode, 0, output) | ||||||||
| self.assertRegex(output, r"Shrunk memory ram/\S+ from 32 rows to 1") | ||||||||
| self.assertIn("{ram 128 32}", output) | ||||||||
|
|
||||||||
|
|
||||||||
| if __name__ == "__main__": | ||||||||
| unittest.main() | ||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If
select -listreturns any unexpected output (such as warnings, info messages, or empty lines), the path may not contain a/character. In such cases,string firstwill return-1, which causesstring rangeto extract invalid module and instance names, leading to a hard crash inrtlil::get_param. Adding a defensive check to skip paths without a/ensures robustness against unexpected output.