mirror of
https://github.com/TinyTapeout/tt-support-tools.git
synced 2026-11-03 04:36:09 +01:00
Update submission tools for mux
1. don't generate user_project_wrapper.v, as it's now static 2. don't generate macros.cfg, as gen_macro_cfg.py does it (eventually, we'll want to integrate it into tt-support-tools) 3. don't generate PDN hooks config. Instead, we're using a wildcard to match all user macros. 4. remove the "layout" section from config.yaml, and scanchain related stuff from generate config.json
This commit is contained in:
+1
-191
@@ -11,97 +11,14 @@ class CaravelConfig():
|
||||
self.num_projects = num_projects
|
||||
self.script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
# co-ords are bottom left corner
|
||||
def place_macro(self, x, y, instance, rotate, fh):
|
||||
c = self.config['layout']
|
||||
if not rotate:
|
||||
# scanchain first
|
||||
orientation = 'N'
|
||||
macro_instance = self.projects[instance].get_scanchain_instance()
|
||||
fh.write(f"{macro_instance} {x:<4} {y:<4} {orientation}\n")
|
||||
|
||||
macro_instance = self.projects[instance].get_macro_instance()
|
||||
x = x + c['scanchain_w'] + c['scanchain_spc']
|
||||
fh.write(f"{macro_instance} {x:<4} {y:<4} {orientation}\n")
|
||||
else:
|
||||
# macro first
|
||||
orientation = 'S'
|
||||
macro_instance = self.projects[instance].get_macro_instance()
|
||||
fh.write(f"{macro_instance} {x:<4} {y:<4} {orientation}\n")
|
||||
|
||||
macro_instance = self.projects[instance].get_scanchain_instance()
|
||||
x = x + c['module_w'] + c['scanchain_spc']
|
||||
y = y + c['module_h'] - c['scanchain_h']
|
||||
fh.write(f"{macro_instance} {x:<4} {y:<4} {orientation}\n")
|
||||
|
||||
# create macro file & positions, power hooks
|
||||
# update caravel config
|
||||
def create_macro_config(self):
|
||||
# array size
|
||||
c = self.config['layout']
|
||||
|
||||
pos_x = 2
|
||||
pos_y = 0
|
||||
dir_x = 1
|
||||
dir_y = 1
|
||||
|
||||
# macro.cfg: where macros are placed
|
||||
logging.info("creating macro.cfg")
|
||||
with open("openlane/user_project_wrapper/macro.cfg", 'w') as fh:
|
||||
fh.write(f"scan_controller {c['scan_control_x']} {c['scan_control_y']} N\n")
|
||||
for i in range(self.num_projects):
|
||||
logging.debug(f"Block {i:d} at ({pos_x:d}, {pos_y:d})")
|
||||
# calculate 0, 0 point
|
||||
macro_x = c['start_x'] + pos_x * (c['module_w'] + c['scanchain_w'] + c['scanchain_spc'] + c['space_x'])
|
||||
macro_y = c['start_y'] + pos_y * (c['module_h'] + c['space_y'])
|
||||
|
||||
# rotated?
|
||||
if dir_x == 1:
|
||||
rotate = False
|
||||
else:
|
||||
rotate = True
|
||||
|
||||
self.place_macro(macro_x, macro_y, i, rotate, fh)
|
||||
|
||||
# next position
|
||||
pos_x += 2 * dir_x
|
||||
|
||||
if pos_x >= c['cols']:
|
||||
pos_x = c['cols'] - 1
|
||||
pos_y += dir_y
|
||||
dir_x = - dir_x
|
||||
|
||||
elif pos_x < 0:
|
||||
pos_x = 0
|
||||
pos_y += dir_y
|
||||
dir_x = - dir_x
|
||||
|
||||
if pos_y >= c['rows']:
|
||||
pos_y = c['rows'] - 1
|
||||
dir_y = - dir_y
|
||||
|
||||
logging.info(f"total user macros placed: {self.num_projects}")
|
||||
|
||||
with open(os.path.join(self.script_dir, 'caravel_template', 'upw_config.json')) as fh:
|
||||
caravel_config = json.load(fh)
|
||||
|
||||
power_domains = "vccd1 vssd1 vccd1 vssd1"
|
||||
power_config = []
|
||||
logging.info("creating macro hooks")
|
||||
|
||||
for i in range(self.num_projects):
|
||||
power_config.append(f"{self.projects[i].get_scanchain_instance()} {power_domains},")
|
||||
power_config.append(f"{self.projects[i].get_macro_instance()} {power_domains},")
|
||||
power_config.append(f"scan_controller {power_domains}") # no trailing comma
|
||||
|
||||
caravel_config["FP_PDN_MACRO_HOOKS"] = power_config
|
||||
|
||||
logging.info("GDS and LEF")
|
||||
lef_prefix = "dir::../../lef/"
|
||||
gds_prefix = "dir::../../gds/"
|
||||
caravel_config["EXTRA_LEFS"].append(lef_prefix + "scan_controller.lef")
|
||||
caravel_config["EXTRA_LEFS"].append(lef_prefix + "scanchain.lef")
|
||||
caravel_config["EXTRA_GDS_FILES"].append(gds_prefix + "scan_controller.gds")
|
||||
caravel_config["EXTRA_GDS_FILES"].append(gds_prefix + "scanchain.gds")
|
||||
for project in self.projects:
|
||||
if not project.is_fill():
|
||||
caravel_config["EXTRA_LEFS"].append(lef_prefix + project.get_macro_lef_filename())
|
||||
@@ -112,115 +29,8 @@ class CaravelConfig():
|
||||
|
||||
# instantiate inside user_project_wrapper
|
||||
def instantiate(self):
|
||||
logging.info("instantiating designs in user_project_wrapper.v")
|
||||
|
||||
# NOTE: The user project wrapper initially used vectored signals for clk,
|
||||
# scan, and latch signals. However, this leads to atrocious sim
|
||||
# performance, as any change within the vectored signal is
|
||||
# interpreted as a trigger condition for re-evaluating logic (at
|
||||
# least this is the case under Icarus and Verilator). Therefore
|
||||
# single bit signals are used between stages to limit the impact
|
||||
# of any wire changing.
|
||||
|
||||
# Instance the scan controller
|
||||
body = [
|
||||
"",
|
||||
"wire sc_clk_out, sc_data_out, sc_latch_out, sc_scan_out;",
|
||||
"wire sc_clk_in, sc_data_in;",
|
||||
"",
|
||||
f"scan_controller #(.NUM_DESIGNS({self.num_projects})) scan_controller (",
|
||||
" .clk (wb_clk_i),",
|
||||
" .reset (wb_rst_i),",
|
||||
" .active_select (io_in[20:12]),",
|
||||
" .inputs (io_in[28:21]),",
|
||||
" .outputs (io_out[36:29]),",
|
||||
" .ready (io_out[37]),",
|
||||
" .slow_clk (io_out[10]),",
|
||||
" .set_clk_div (io_in[11]),",
|
||||
"",
|
||||
" .scan_clk_out (sc_clk_out),",
|
||||
" .scan_clk_in (sc_clk_in),",
|
||||
" .scan_data_out (sc_data_out),",
|
||||
" .scan_data_in (sc_data_in),",
|
||||
" .scan_select (sc_scan_out),",
|
||||
" .scan_latch_en (sc_latch_out),",
|
||||
"",
|
||||
" .la_scan_clk_in (la_data_in[0]),",
|
||||
" .la_scan_data_in (la_data_in[1]),",
|
||||
" .la_scan_data_out (la_data_out[0]),",
|
||||
" .la_scan_select (la_data_in[2]),",
|
||||
" .la_scan_latch_en (la_data_in[3]),",
|
||||
"",
|
||||
" .driver_sel (io_in[9:8]),",
|
||||
"",
|
||||
" .oeb (io_oeb)",
|
||||
");",
|
||||
]
|
||||
|
||||
# Instance every design on the scan chain
|
||||
for idx in range(self.num_projects):
|
||||
# First design driven by scan controller, all others are chained
|
||||
pfx = f"sw_{idx:03d}"
|
||||
prev_pfx = f"sw_{idx-1:03d}" if idx > 0 else "sc"
|
||||
# Pickup the Wokwi design ID and github URL for the project
|
||||
giturl = self.projects[idx].get_git_url()
|
||||
|
||||
# Append the instance to the body
|
||||
body += [
|
||||
"",
|
||||
f"// [{idx:03d}] {giturl}",
|
||||
f"wire {pfx}_clk_out, {pfx}_data_out, {pfx}_scan_out, {pfx}_latch_out;",
|
||||
f"wire [7:0] {pfx}_module_data_in;",
|
||||
f"wire [7:0] {pfx}_module_data_out;",
|
||||
f"scanchain #(.NUM_IOS(8)) {self.projects[idx].get_scanchain_instance()} (",
|
||||
f" .clk_in ({prev_pfx}_clk_out),",
|
||||
f" .data_in ({prev_pfx}_data_out),",
|
||||
f" .scan_select_in ({prev_pfx}_scan_out),",
|
||||
f" .latch_enable_in ({prev_pfx}_latch_out),",
|
||||
f" .clk_out ({pfx}_clk_out),",
|
||||
f" .data_out ({pfx}_data_out),",
|
||||
f" .scan_select_out ({pfx}_scan_out),",
|
||||
f" .latch_enable_out({pfx}_latch_out),",
|
||||
f" .module_data_in ({pfx}_module_data_in),",
|
||||
f" .module_data_out ({pfx}_module_data_out)",
|
||||
");"
|
||||
]
|
||||
|
||||
# Append the user module to the body
|
||||
body += [
|
||||
"",
|
||||
f"{self.projects[idx].get_macro_name()} {self.projects[idx].get_macro_instance()} (",
|
||||
f" .io_in ({pfx}_module_data_in),",
|
||||
f" .io_out ({pfx}_module_data_out)",
|
||||
");"
|
||||
|
||||
]
|
||||
|
||||
# Link the final design back to the scan controller
|
||||
body += [
|
||||
"",
|
||||
"// Connect final signals back to the scan controller",
|
||||
f"assign sc_clk_in = sw_{idx:03d}_clk_out;",
|
||||
f"assign sc_data_in = sw_{idx:03d}_data_out;",
|
||||
"",
|
||||
""
|
||||
]
|
||||
|
||||
# Write to file
|
||||
with open('verilog/rtl/user_project_wrapper.v', 'w') as fh:
|
||||
# Insert the Caravel preamble
|
||||
with open(os.path.join(self.script_dir, 'caravel_template', 'upw_pre.v')) as fh_pre:
|
||||
fh.write(fh_pre.read())
|
||||
# Indent, join, and insert the module instances
|
||||
fh.write("\n".join([(" " + x).rstrip() for x in body]))
|
||||
# Insert the Caravel postamble
|
||||
with open(os.path.join(self.script_dir, 'caravel_template', 'upw_post.v')) as fh_post:
|
||||
fh.write(fh_post.read())
|
||||
|
||||
# build the blackbox_project_includes.v file - used for blackboxing when building the GDS
|
||||
with open('verilog/blackbox_project_includes.v', 'w') as fh:
|
||||
fh.write('`include "rtl/scan_controller/scan_controller.v"\n')
|
||||
fh.write('`include "rtl/scanchain/scanchain.v"\n')
|
||||
for project in self.projects:
|
||||
if not project.is_fill():
|
||||
fh.write(f'`include "gl/{project.get_gl_verilog_filename()}"\n')
|
||||
|
||||
@@ -2,23 +2,38 @@
|
||||
"DESIGN_NAME": "user_project_wrapper",
|
||||
"VERILOG_FILES": [
|
||||
"dir::../../verilog/rtl/defines.v",
|
||||
"dir::../../verilog/rtl/user_project_wrapper.v"
|
||||
"dir::../../verilog/rtl/user_project_wrapper.v",
|
||||
"dir::../../tt-multiplexer/proto/tt_top.v",
|
||||
"dir::../../tt-multiplexer/proto/tt_user_module.v"
|
||||
],
|
||||
"VERILOG_FILES_BLACKBOX": [
|
||||
"dir::../../tt-multiplexer/proto/tt_mux.v",
|
||||
"dir::../../tt-multiplexer/proto/tt_ctrl.v",
|
||||
"dir::../../tt-multiplexer/proto/tt_um_test.v",
|
||||
"dir::../../verilog/blackbox_project_includes.v"
|
||||
],
|
||||
"ROUTING_CORES": 8,
|
||||
"CLOCK_PERIOD": 25,
|
||||
"CLOCK_PORT": "wb_clk_i",
|
||||
"CLOCK_NET": "mprj.clk",
|
||||
"FP_PDN_MACRO_HOOKS": [],
|
||||
"FP_PDN_MACRO_HOOKS": [
|
||||
"tt_top1\\.ctrl_I vccd1 vssd1 vccd1 vssd1,",
|
||||
"tt_top1\\..*mux_I vccd1 vssd1 vccd1 vssd1,",
|
||||
"tt_top1\\..*tt_um_I vccd1 vssd1 vccd1 vssd1"
|
||||
],
|
||||
"MACRO_PLACEMENT_CFG": "dir::macro.cfg",
|
||||
"PDN_CFG": "dir::pdn_cfg.tcl",
|
||||
"MAGIC_DEF_LABELS": 0,
|
||||
"VERILOG_FILES_BLACKBOX": [
|
||||
"dir::../../verilog/rtl/defines.v",
|
||||
"dir::../../verilog/blackbox_project_includes.v"
|
||||
"EXTRA_LEFS": [
|
||||
"dir::../../lef/tt_ctrl.lef",
|
||||
"dir::../../lef/tt_mux.lef",
|
||||
"dir::../../lef/tt_um_test.lef"
|
||||
],
|
||||
"EXTRA_GDS_FILES": [
|
||||
"dir::../../gds/tt_ctrl.gds",
|
||||
"dir::../../gds/tt_mux.gds",
|
||||
"dir::../../gds/tt_um_test.gds"
|
||||
],
|
||||
"EXTRA_LEFS": [],
|
||||
"EXTRA_GDS_FILES": [],
|
||||
"BASE_SDC_FILE": "dir::base_user_project_wrapper.sdc",
|
||||
"RUN_KLAYOUT_XOR": 0,
|
||||
"RUN_KLAYOUT_DRC": 0,
|
||||
"RUN_MAGIC_DRC": 0,
|
||||
@@ -31,15 +46,17 @@
|
||||
"PL_RESIZER_DESIGN_OPTIMIZATIONS": 0,
|
||||
"PL_RESIZER_TIMING_OPTIMIZATIONS": 0,
|
||||
"PL_RESIZER_BUFFER_INPUT_PORTS": 0,
|
||||
"SYNTH_FLAT_TOP": 1,
|
||||
"FP_PDN_ENABLE_RAILS": 0,
|
||||
"DIODE_INSERTION_STRATEGY": 0,
|
||||
"RUN_FILL_INSERTION": 0,
|
||||
"RUN_TAP_DECAP_INSERTION": 0,
|
||||
"FP_PDN_VPITCH": 140,
|
||||
"FP_PDN_VOFFSET": 186,
|
||||
"FP_PDN_HPITCH": 185,
|
||||
"FP_PDN_HPITCH": 50,
|
||||
"FP_PDN_HOFFSET": 160,
|
||||
"CLOCK_TREE_SYNTH": 0,
|
||||
"QUIT_ON_LVS_ERROR": "0",
|
||||
"MAGIC_ZEROIZE_ORIGIN": 0,
|
||||
"FP_SIZING": "absolute",
|
||||
"RUN_CVC": 0,
|
||||
@@ -106,4 +123,4 @@
|
||||
"DIODE_INSERTION_STRATEGY": 0,
|
||||
"MAGIC_WRITE_FULL_LEF": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
// end of module instantiation
|
||||
|
||||
endmodule // user_project_wrapper
|
||||
`default_nettype wire
|
||||
@@ -1,84 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2020 Efabless Corporation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
`default_nettype none
|
||||
/*
|
||||
*-------------------------------------------------------------
|
||||
*
|
||||
* user_project_wrapper
|
||||
*
|
||||
* This wrapper enumerates all of the pins available to the
|
||||
* user for the user project.
|
||||
*
|
||||
* An example user project is provided in this wrapper. The
|
||||
* example should be removed and replaced with the actual
|
||||
* user project.
|
||||
*
|
||||
* THIS FILE HAS BEEN GENERATED USING multi_tools_project CODEGEN
|
||||
* IF YOU NEED TO MAKE EDITS TO IT, EDIT codegen/caravel_iface_header.txt
|
||||
*
|
||||
*-------------------------------------------------------------
|
||||
*/
|
||||
|
||||
module user_project_wrapper #(
|
||||
parameter BITS = 32
|
||||
)(
|
||||
`ifdef USE_POWER_PINS
|
||||
inout vdda1, // User area 1 3.3V supply
|
||||
inout vdda2, // User area 2 3.3V supply
|
||||
inout vssa1, // User area 1 analog ground
|
||||
inout vssa2, // User area 2 analog ground
|
||||
inout vccd1, // User area 1 1.8V supply
|
||||
inout vccd2, // User area 2 1.8v supply
|
||||
inout vssd1, // User area 1 digital ground
|
||||
inout vssd2, // User area 2 digital ground
|
||||
`endif
|
||||
|
||||
// Wishbone Slave ports (WB MI A)
|
||||
input wb_clk_i,
|
||||
input wb_rst_i,
|
||||
input wbs_stb_i,
|
||||
input wbs_cyc_i,
|
||||
input wbs_we_i,
|
||||
input [3:0] wbs_sel_i,
|
||||
input [31:0] wbs_dat_i,
|
||||
input [31:0] wbs_adr_i,
|
||||
output wbs_ack_o,
|
||||
output [31:0] wbs_dat_o,
|
||||
|
||||
// Logic Analyzer Signals
|
||||
input [127:0] la_data_in,
|
||||
output [127:0] la_data_out,
|
||||
input [127:0] la_oenb,
|
||||
|
||||
// IOs
|
||||
input [`MPRJ_IO_PADS-1:0] io_in,
|
||||
output [`MPRJ_IO_PADS-1:0] io_out,
|
||||
output [`MPRJ_IO_PADS-1:0] io_oeb,
|
||||
|
||||
// Analog (direct connection to GPIO pad---use with caution)
|
||||
// Note that analog I/O is not available on the 7 lowest-numbered
|
||||
// GPIO pads, and so the analog_io indexing is offset from the
|
||||
// GPIO indexing by 7 (also upper 2 GPIOs do not have analog_io).
|
||||
inout [`MPRJ_IO_PADS-10:0] analog_io,
|
||||
|
||||
// Independent clock (on independent integer divider)
|
||||
input user_clock2,
|
||||
|
||||
// User maskable interrupt signals
|
||||
output [2:0] user_irq
|
||||
);
|
||||
|
||||
// start of module instantiation
|
||||
@@ -228,8 +228,6 @@ if __name__ == '__main__':
|
||||
|
||||
with open('config.yaml') as fh:
|
||||
config = yaml.safe_load(fh)
|
||||
# default max projects is row * col - 2 (scan controller takes first 2 slots)
|
||||
config['num_projects'] = config['layout']['rows'] * config['layout']['cols'] - 2
|
||||
|
||||
parser.add_argument('--update-orders', help="update the order config file", action="store_const", const=True)
|
||||
parser.add_argument('--list', help="list projects", action='store_const', const=True)
|
||||
|
||||
+13
-3
@@ -54,12 +54,22 @@ class Project():
|
||||
os.unlink(json_file)
|
||||
|
||||
module_ports = ports['modules'][top]['ports']
|
||||
for port in ['io_in', 'io_out']:
|
||||
required_ports = [
|
||||
['clk', 1],
|
||||
['ena', 1],
|
||||
['rst_n', 1],
|
||||
['ui_in', 8],
|
||||
['uio_in', 8],
|
||||
['uio_oe', 8],
|
||||
['uio_out', 8],
|
||||
['uo_out', 8],
|
||||
]
|
||||
for port, bits in required_ports:
|
||||
if port not in module_ports:
|
||||
logging.error(f"{self} {port} not found in top")
|
||||
exit(1)
|
||||
if len(module_ports[port]['bits']) != 8:
|
||||
logging.error(f"{self} {port} doesn't have 8 bits")
|
||||
if len(module_ports[port]['bits']) != bits:
|
||||
logging.error(f"{self} {port} doesn't have {bits} bits")
|
||||
exit(1)
|
||||
|
||||
def check_num_cells(self):
|
||||
|
||||
Reference in New Issue
Block a user