mirror of
https://github.com/TinyTapeout/tt-support-tools.git
synced 2026-11-03 04:36:09 +01:00
feat: Chip ROM auto generation with OpenLane 2
So we can generate the ROM while building the shuttle's GDS
This commit is contained in:
+1
-1
@@ -244,7 +244,7 @@ if __name__ == '__main__':
|
|||||||
shuttle.configure_mux()
|
shuttle.configure_mux()
|
||||||
if args.test:
|
if args.test:
|
||||||
shuttle.write_gl_config()
|
shuttle.write_gl_config()
|
||||||
#rom.write_rom()
|
rom.write_rom()
|
||||||
if not args.test:
|
if not args.test:
|
||||||
docs.build_index()
|
docs.build_index()
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
import git
|
import git
|
||||||
|
import os
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
|
MAX_ROM_TEXT_SIZE = 92
|
||||||
|
|
||||||
segment_font = {
|
segment_font = {
|
||||||
" ": 0b00000000,
|
" ": 0b00000000,
|
||||||
@@ -30,7 +34,8 @@ class ROMFile:
|
|||||||
self.config = config
|
self.config = config
|
||||||
|
|
||||||
def get_git_remote(self):
|
def get_git_remote(self):
|
||||||
return list(git.Repo(".").remotes[0].urls)[0]
|
repo_url = list(git.Repo(".").remotes[0].urls)[0]
|
||||||
|
return urlparse(repo_url).path[1:]
|
||||||
|
|
||||||
def get_git_commit_hash(self):
|
def get_git_commit_hash(self):
|
||||||
return git.Repo(".").commit().hexsha
|
return git.Repo(".").commit().hexsha
|
||||||
@@ -39,18 +44,25 @@ class ROMFile:
|
|||||||
rom = bytearray(256)
|
rom = bytearray(256)
|
||||||
short_sha = self.get_git_commit_hash()[:8]
|
short_sha = self.get_git_commit_hash()[:8]
|
||||||
|
|
||||||
rom_text = f"shuttle={self.config['name']}\n"
|
rom_text = f"shuttle={self.config['id']}\n"
|
||||||
rom_text += f"repo={self.get_git_remote()}\n"
|
rom_text += f"repo={self.get_git_remote()}\n"
|
||||||
rom_text += f"commit={short_sha}\n"
|
rom_text += f"commit={short_sha}\n"
|
||||||
|
|
||||||
assert len(rom_text) < 96, "ROM text too long"
|
print(f"\nROM text: {len(rom_text)} bytes (max={MAX_ROM_TEXT_SIZE})\n")
|
||||||
|
print(" " + "\n ".join(rom_text.split("\n")))
|
||||||
|
|
||||||
rom[0:4] = map(segment_char, "tt04")
|
assert len(rom_text) < MAX_ROM_TEXT_SIZE, "ROM text too long"
|
||||||
|
|
||||||
|
rom[0:4] = map(segment_char, self.config['id'])
|
||||||
rom[8:16] = map(segment_char, short_sha.upper())
|
rom[8:16] = map(segment_char, short_sha.upper())
|
||||||
rom[32 : 32 + len(rom_text)] = rom_text.encode("ascii")
|
rom[32 : 32 + len(rom_text)] = rom_text.encode("ascii")
|
||||||
|
|
||||||
# build complete list of filenames for sim
|
with open(os.path.join(os.path.dirname(__file__), "rom/rom.vmem"), "w") as fh:
|
||||||
with open("verilog/includes/rom_tile.vmem", "w") as fh:
|
for line in rom_text.split("\n"):
|
||||||
|
if len(line) == 0:
|
||||||
|
continue
|
||||||
|
fh.write(f"// {line}\n")
|
||||||
|
fh.write("\n")
|
||||||
for line in range(0, len(rom), 16):
|
for line in range(0, len(rom), 16):
|
||||||
for byte in range(0, 16):
|
for byte in range(0, 16):
|
||||||
fh.write("{:02x} ".format(rom[line + byte]))
|
fh.write("{:02x} ".format(rom[line + byte]))
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
runs
|
||||||
|
rom.vmem
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"DESIGN_NAME": "tt_um_chip_rom",
|
||||||
|
"VERILOG_FILES": "dir::tt_um_chip_rom.v",
|
||||||
|
|
||||||
|
"FP_SIZING": "absolute",
|
||||||
|
"DIE_AREA": "0 0 168.36 111.52",
|
||||||
|
"FP_DEF_TEMPLATE": "ref::$DESIGN_DIR/../def/tt_block_1x1.def",
|
||||||
|
|
||||||
|
"FP_IO_HLENGTH": 2,
|
||||||
|
"FP_IO_VLENGTH": 2,
|
||||||
|
|
||||||
|
"//": "use alternative efabless decap cells to solve LI density issue",
|
||||||
|
"DECAP_CELL": "sky130_fd_sc_hd__decap_3 sky130_fd_sc_hd__decap_4 sky130_fd_sc_hd__decap_6 sky130_fd_sc_hd__decap_8 sky130_ef_sc_hd__decap_12",
|
||||||
|
|
||||||
|
"//": "period is in ns, so 20ns == 50mHz",
|
||||||
|
"CLOCK_PERIOD": 20,
|
||||||
|
"CLOCK_PORT": "clk",
|
||||||
|
|
||||||
|
"//": "don't use power rings or met5",
|
||||||
|
"DESIGN_IS_CORE": false,
|
||||||
|
"RT_MAX_LAYER": "met4",
|
||||||
|
|
||||||
|
"//": "save some time",
|
||||||
|
"RUN_KLAYOUT_XOR": false,
|
||||||
|
|
||||||
|
"//": "reduce wasted space",
|
||||||
|
"TOP_MARGIN_MULT": 1,
|
||||||
|
"BOTTOM_MARGIN_MULT": 1,
|
||||||
|
"LEFT_MARGIN_MULT": 6,
|
||||||
|
"RIGHT_MARGIN_MULT": 6
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* tt_um_chip_rom.v
|
||||||
|
*
|
||||||
|
* ROM module for Tiny Tapeout chips
|
||||||
|
*
|
||||||
|
* Author: Uri Shaked
|
||||||
|
*/
|
||||||
|
|
||||||
|
`default_nettype none
|
||||||
|
|
||||||
|
module tt_um_chip_rom (
|
||||||
|
input wire [7:0] ui_in, // Dedicated inputs
|
||||||
|
output wire [7:0] uo_out, // Dedicated outputs
|
||||||
|
input wire [7:0] uio_in, // IOs: Input path
|
||||||
|
output wire [7:0] uio_out,// IOs: Output path
|
||||||
|
output wire [7:0] uio_oe, // IOs: Enable path (active high: 0=input, 1=output)
|
||||||
|
input wire ena,
|
||||||
|
input wire clk,
|
||||||
|
input wire rst_n
|
||||||
|
);
|
||||||
|
|
||||||
|
reg [7:0] rom_data [0:255];
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
$readmemh("rom.vmem", rom_data);
|
||||||
|
end
|
||||||
|
|
||||||
|
assign uo_out = rom_data[ui_in];
|
||||||
|
assign uio_out = 8'h00;
|
||||||
|
assign uio_oe = 8'h00;
|
||||||
|
|
||||||
|
endmodule // tt_um_chip_rom
|
||||||
+3
-1
@@ -100,6 +100,8 @@ class ShuttleConfig():
|
|||||||
|
|
||||||
def find_last_run(self, macro: str):
|
def find_last_run(self, macro: str):
|
||||||
runs = f"tt-multiplexer/ol2/{macro}/runs/"
|
runs = f"tt-multiplexer/ol2/{macro}/runs/"
|
||||||
|
if macro == "tt_um_chip_rom":
|
||||||
|
runs = "tt/rom/runs/"
|
||||||
runlist = sorted(
|
runlist = sorted(
|
||||||
[r for r in os.listdir(runs) if r.startswith("RUN_") and os.path.isdir(os.path.join(runs, r))]
|
[r for r in os.listdir(runs) if r.startswith("RUN_") and os.path.isdir(os.path.join(runs, r))]
|
||||||
)
|
)
|
||||||
@@ -115,7 +117,7 @@ class ShuttleConfig():
|
|||||||
copy_print_glob("projects/*/*.gds", "tt-multiplexer/ol2/tt_top/gds")
|
copy_print_glob("projects/*/*.gds", "tt-multiplexer/ol2/tt_top/gds")
|
||||||
copy_print_glob("projects/*/*.lef", "tt-multiplexer/ol2/tt_top/lef")
|
copy_print_glob("projects/*/*.lef", "tt-multiplexer/ol2/tt_top/lef")
|
||||||
copy_print_glob("projects/*/*.v", "tt-multiplexer/ol2/tt_top/verilog")
|
copy_print_glob("projects/*/*.v", "tt-multiplexer/ol2/tt_top/verilog")
|
||||||
macros = ["tt_ctrl", "tt_mux"]
|
macros = ["tt_um_chip_rom", "tt_ctrl", "tt_mux"]
|
||||||
for macro in macros:
|
for macro in macros:
|
||||||
lastrun = self.find_last_run(macro)
|
lastrun = self.find_last_run(macro)
|
||||||
copy_print(f"{lastrun}/final/gds/{macro}.gds", f"tt-multiplexer/ol2/tt_top/gds/{macro}.gds")
|
copy_print(f"{lastrun}/final/gds/{macro}.gds", f"tt-multiplexer/ol2/tt_top/gds/{macro}.gds")
|
||||||
|
|||||||
Reference in New Issue
Block a user