diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2df69733..6a7cd73b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: export OPENRAM_HOME="`pwd`/compiler" export OPENRAM_TECH="`pwd`/technology:/software/PDKs/skywater-tech" export OPENRAM_TMP="`pwd`/scn4me_subm" - python3-coverage run -p $OPENRAM_HOME/tests/regress.py -j 20 -t scn4m_subm + python3-coverage run -p $OPENRAM_HOME/tests/regress.py -j 48 -t scn4m_subm - name: Archive if: ${{ failure() }} uses: actions/upload-artifact@v2 @@ -30,7 +30,7 @@ jobs: export OPENRAM_HOME="`pwd`/compiler" export OPENRAM_TECH="`pwd`/technology:/software/PDKs/skywater-tech" export OPENRAM_TMP="`pwd`/freepdk45" - python3-coverage run -p $OPENRAM_HOME/tests/regress.py -j 20 -t freepdk45 + python3-coverage run -p $OPENRAM_HOME/tests/regress.py -j 48 -t freepdk45 - name: Archive if: ${{ failure() }} uses: actions/upload-artifact@v2 diff --git a/.gitignore b/.gitignore index 3d6e4f92..e31298d6 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ **/model_data outputs technology/freepdk45/ncsu_basekit +.idea diff --git a/README.md b/README.md index dd7055e0..da68361b 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,9 @@ [![License: BSD 3-clause](./images/license_badge.svg)](./LICENSE) Master: -[![Pipeline Status](https://scone.soe.ucsc.edu:8888/mrg/OpenRAM/badges/master/pipeline.svg)](https://github.com/VLSIDA/OpenRAM/commits/master) -![Coverage](https://scone.soe.ucsc.edu:8888/mrg/OpenRAM/badges/master/coverage.svg) [![Download](./images/download-stable-blue.svg)](https://github.com/VLSIDA/OpenRAM/archive/master.zip) Dev: -[![Pipeline Status](https://scone.soe.ucsc.edu:8888/mrg/OpenRAM/badges/dev/pipeline.svg)](https://github.com/VLSIDA/OpenRAM/commits/dev) -![Coverage](https://scone.soe.ucsc.edu:8888/mrg/OpenRAM/badges/dev/coverage.svg) [![Download](./images/download-unstable-blue.svg)](https://github.com/VLSIDA/OpenRAM/archive/dev.zip) An open-source static random access memory (SRAM) compiler. diff --git a/compiler/base/geometry.py b/compiler/base/geometry.py index 1b42f51e..d2f4e98e 100644 --- a/compiler/base/geometry.py +++ b/compiler/base/geometry.py @@ -359,7 +359,9 @@ class instance(geometry): for offset in range(len(normalized_br_offsets)): for port in range(len(br_names)): cell_br_meta.append([br_names[offset], row, col, port]) - + + if normalized_storage_nets == []: + debug.error("normalized storage nets should not be empty! Check if the GDS labels Q and Q_bar are correctly set on M1 of the cell",1) Q_x = normalized_storage_nets[0][0] Q_y = normalized_storage_nets[0][1] diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py index 081400a7..296027c2 100644 --- a/compiler/characterizer/delay.py +++ b/compiler/characterizer/delay.py @@ -170,10 +170,10 @@ class delay(simulation): meas.targ_name_no_port)) self.dout_volt_meas[-1].meta_str = meas.meta_str - if not OPTS.use_pex: - self.sen_meas = delay_measure("delay_sen", self.clk_frmt, self.sen_name + "{}", "FALL", "RISE", measure_scale=1e9) - else: + if OPTS.use_pex and OPTS.pex_exe[0] != 'calibre': self.sen_meas = delay_measure("delay_sen", self.clk_frmt, self.sen_name, "FALL", "RISE", measure_scale=1e9) + else: + self.sen_meas = delay_measure("delay_sen", self.clk_frmt, self.sen_name + "{}", "FALL", "RISE", measure_scale=1e9) self.sen_meas.meta_str = sram_op.READ_ZERO self.sen_meas.meta_add_delay = True @@ -220,13 +220,13 @@ class delay(simulation): storage_names = cell_inst.mod.get_storage_net_names() debug.check(len(storage_names) == 2, ("Only inverting/non-inverting storage nodes" "supported for characterization. Storage nets={}").format(storage_names)) - if not OPTS.use_pex or OPTS.calibre_pex: - q_name = cell_name + '.' + str(storage_names[0]) - qbar_name = cell_name + '.' + str(storage_names[1]) - else: + if OPTS.use_pex and OPTS.pex_exe[0] != "calibre": bank_num = self.sram.get_bank_num(self.sram.name, bit_row, bit_col) q_name = "bitcell_Q_b{0}_r{1}_c{2}".format(bank_num, bit_row, bit_col) qbar_name = "bitcell_Q_bar_b{0}_r{1}_c{2}".format(bank_num, bit_row, bit_col) + else: + q_name = cell_name + '.' + str(storage_names[0]) + qbar_name = cell_name + '.' + str(storage_names[1]) # Bit measures, measurements times to be defined later. The measurement names must be unique # but they is enforced externally. {} added to names to differentiate between ports allow the diff --git a/compiler/characterizer/lib.py b/compiler/characterizer/lib.py index ea9c3dac..d37119a9 100644 --- a/compiler/characterizer/lib.py +++ b/compiler/characterizer/lib.py @@ -236,10 +236,9 @@ class lib: self.lib.write(" slew_lower_threshold_pct_rise : 10.0 ;\n") self.lib.write(" slew_upper_threshold_pct_rise : 90.0 ;\n\n") - self.lib.write(" nom_voltage : {};\n".format(tech.spice["nom_supply_voltage"])) - self.lib.write(" nom_temperature : {};\n".format(tech.spice["nom_temperature"])) - self.lib.write(" nom_process : {};\n".format(1.0)) - + self.lib.write(" nom_voltage : {};\n".format(self.voltage)) + self.lib.write(" nom_temperature : {};\n".format(self.temperature)) + self.lib.write(" nom_process : 1.0;\n") self.lib.write(" default_cell_leakage_power : 0.0 ;\n") self.lib.write(" default_leakage_power_density : 0.0 ;\n") self.lib.write(" default_input_pin_cap : 1.0 ;\n") @@ -250,7 +249,7 @@ class lib: self.lib.write(" default_max_fanout : 4.0 ;\n") self.lib.write(" default_connection_class : universal ;\n\n") - self.lib.write(" voltage_map ( VDD, {} );\n".format(tech.spice["nom_supply_voltage"])) + self.lib.write(" voltage_map ( VDD, {} );\n".format(self.voltage)) self.lib.write(" voltage_map ( GND, 0 );\n\n") def create_list(self,values): diff --git a/compiler/characterizer/simulation.py b/compiler/characterizer/simulation.py index 6327348f..0afe2459 100644 --- a/compiler/characterizer/simulation.py +++ b/compiler/characterizer/simulation.py @@ -467,7 +467,7 @@ class simulation(): """ port = self.read_ports[0] - if not OPTS.use_pex or OPTS.calibre_pex: # pex names handled post extraction + if not OPTS.use_pex or (OPTS.use_pex and OPTS.pex_exe[0] == "calibre"): self.graph.get_all_paths('{}{}'.format("clk", port), '{}{}_{}'.format(self.dout_name, port, self.probe_data)) @@ -523,7 +523,7 @@ class simulation(): debug.check(len(sa_mods) == 1, "Only expected one type of Sense Amp. Cannot perform s_en checks.") enable_name = sa_mods[0].get_enable_name() sen_name = self.get_alias_in_path(paths, enable_name, sa_mods[0]) - if OPTS.use_pex and not OPTS.calibre_pex: + if OPTS.use_pex and OPTS.pex_exe[0] != "calibre": sen_name = sen_name.split('.')[-1] return sen_name @@ -581,7 +581,7 @@ class simulation(): exclude_set = self.get_bl_name_search_exclusions() for int_net in [cell_bl, cell_br]: bl_names.append(self.get_alias_in_path(paths, int_net, cell_mod, exclude_set)) - if OPTS.use_pex and not OPTS.calibre_pex: + if OPTS.use_pex and OPTS.pex_exe[0] != "calibre": for i in range(len(bl_names)): bl_names[i] = bl_names[i].split('.')[-1] return bl_names[0], bl_names[1] diff --git a/compiler/characterizer/stimuli.py b/compiler/characterizer/stimuli.py index 4ab1fe4f..c6ef0fa5 100644 --- a/compiler/characterizer/stimuli.py +++ b/compiler/characterizer/stimuli.py @@ -52,7 +52,7 @@ class stimuli(): def inst_model(self, pins, model_name): """ Function to instantiate a generic model with a set of pins """ - if OPTS.use_pex and not OPTS.calibre_pex: + if OPTS.use_pex and OPTS.pex_exe[0] != "calibre": self.inst_pex_model(pins, model_name) else: self.sf.write("X{0} ".format(model_name)) diff --git a/compiler/example_configs/riscv-freepdk45-8kbyte.py b/compiler/example_configs/riscv_freepdk45_8kbyte.py similarity index 100% rename from compiler/example_configs/riscv-freepdk45-8kbyte.py rename to compiler/example_configs/riscv_freepdk45_8kbyte.py diff --git a/compiler/example_configs/riscv-scn4m_subm-16kbyte-1rw1r.py b/compiler/example_configs/riscv_scn4m_subm_16kbyte_1rw1r.py similarity index 100% rename from compiler/example_configs/riscv-scn4m_subm-16kbyte-1rw1r.py rename to compiler/example_configs/riscv_scn4m_subm_16kbyte_1rw1r.py diff --git a/compiler/example_configs/riscv-scn4m_subm-1kbyte-1rw1r.py b/compiler/example_configs/riscv_scn4m_subm_1kbyte_1rw1r.py similarity index 100% rename from compiler/example_configs/riscv-scn4m_subm-1kbyte-1rw1r.py rename to compiler/example_configs/riscv_scn4m_subm_1kbyte_1rw1r.py diff --git a/compiler/example_configs/riscv-scn4m_subm-2kbyte-1rw1r.py b/compiler/example_configs/riscv_scn4m_subm_2skbyte_1rw1r.py similarity index 100% rename from compiler/example_configs/riscv-scn4m_subm-2kbyte-1rw1r.py rename to compiler/example_configs/riscv_scn4m_subm_2skbyte_1rw1r.py diff --git a/compiler/example_configs/riscv-scn4m_subm-32kbyte.py b/compiler/example_configs/riscv_scn4m_subm_32kbyte_1rw1r.py similarity index 100% rename from compiler/example_configs/riscv-scn4m_subm-32kbyte.py rename to compiler/example_configs/riscv_scn4m_subm_32kbyte_1rw1r.py diff --git a/compiler/example_configs/riscv-scn4m_subm-4kbyte-1rw1r.py b/compiler/example_configs/riscv_scn4m_subm_4kbyte_1rw1r.py similarity index 100% rename from compiler/example_configs/riscv-scn4m_subm-4kbyte-1rw1r.py rename to compiler/example_configs/riscv_scn4m_subm_4kbyte_1rw1r.py diff --git a/compiler/example_configs/riscv-scn4m_subm-8kbyte-1rw1r.py b/compiler/example_configs/riscv_scn4m_subm_8kbyte_1rw1r.py similarity index 100% rename from compiler/example_configs/riscv-scn4m_subm-8kbyte-1rw1r.py rename to compiler/example_configs/riscv_scn4m_subm_8kbyte_1rw1r.py diff --git a/compiler/example_configs/riscv-sky130-1kbyte-1rw.py b/compiler/example_configs/riscv_sky130_1kbyte_1rw.py similarity index 100% rename from compiler/example_configs/riscv-sky130-1kbyte-1rw.py rename to compiler/example_configs/riscv_sky130_1kbyte_1rw.py diff --git a/compiler/example_configs/riscv-sky130-1kbyte-1rw1r.py b/compiler/example_configs/riscv_sky130_1kbyte_1rw1r.py similarity index 90% rename from compiler/example_configs/riscv-sky130-1kbyte-1rw1r.py rename to compiler/example_configs/riscv_sky130_1kbyte_1rw1r.py index 20463a99..d0b47857 100644 --- a/compiler/example_configs/riscv-sky130-1kbyte-1rw1r.py +++ b/compiler/example_configs/riscv_sky130_1kbyte_1rw1r.py @@ -2,7 +2,7 @@ word_size = 32 num_words = 256 write_size = 8 -local_array_size = 16 +#local_array_size = 16 num_rw_ports = 1 num_r_ports = 1 @@ -11,9 +11,9 @@ num_w_ports = 0 tech_name = "sky130" nominal_corner_only = True -route_supplies = False +#route_supplies = False check_lvsdrc = True -perimeter_pins = False +#perimeter_pins = False #netlist_only = True #analytical_delay = False output_name = "sram_{0}rw{1}r{2}w_{3}_{4}_{5}".format(num_rw_ports, diff --git a/compiler/example_configs/riscv-sky130-2kbyte-1rw.py b/compiler/example_configs/riscv_sky130_2kbyte_1rw.py similarity index 100% rename from compiler/example_configs/riscv-sky130-2kbyte-1rw.py rename to compiler/example_configs/riscv_sky130_2kbyte_1rw.py diff --git a/compiler/example_configs/riscv-sky130-2kbyte-1rw1r.py b/compiler/example_configs/riscv_sky130_2kbyte_1rw1r.py similarity index 100% rename from compiler/example_configs/riscv-sky130-2kbyte-1rw1r.py rename to compiler/example_configs/riscv_sky130_2kbyte_1rw1r.py diff --git a/compiler/example_configs/riscv-sky130-4kbyte-1rw.py b/compiler/example_configs/riscv_sky130_4kbyte_1rw.py similarity index 100% rename from compiler/example_configs/riscv-sky130-4kbyte-1rw.py rename to compiler/example_configs/riscv_sky130_4kbyte_1rw.py diff --git a/compiler/example_configs/riscv-sky130-4kbyte-1rw1r.py b/compiler/example_configs/riscv_sky130_4kbyte_1rw1r.py similarity index 100% rename from compiler/example_configs/riscv-sky130-4kbyte-1rw1r.py rename to compiler/example_configs/riscv_sky130_4kbyte_1rw1r.py diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index 58f6e83f..0c9d50bf 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -636,7 +636,7 @@ class control_logic(design.design): self.w_en_gate_inst = self.add_inst(name="w_en_and", mod=self.wen_and) # Only drive the writes in the second half of the clock cycle during a write operation. - self.connect_inst([input_name, "rbl_bl_delay", "gated_clk_bar", "w_en", "vdd", "gnd"]) + self.connect_inst([input_name, "rbl_bl_delay_bar", "gated_clk_bar", "w_en", "vdd", "gnd"]) def place_wen_row(self, row): x_offset = self.control_x_offset @@ -652,7 +652,7 @@ class control_logic(design.design): # No we for write-only reports, so use cs input_name = "cs" - wen_map = zip(["A", "B", "C"], [input_name, "rbl_bl_delay", "gated_clk_bar"]) + wen_map = zip(["A", "B", "C"], [input_name, "rbl_bl_delay_bar", "gated_clk_bar"]) self.connect_vertical_bus(wen_map, self.w_en_gate_inst, self.input_bus) self.connect_output(self.w_en_gate_inst, "Z", "w_en") diff --git a/compiler/sram/sram_base.py b/compiler/sram/sram_base.py index 852eca46..868b2059 100644 --- a/compiler/sram/sram_base.py +++ b/compiler/sram/sram_base.py @@ -196,12 +196,13 @@ class sram_base(design, verilog, lef): self.add_lvs_correspondence_points() - #self.offset_all_coordinates() + # self.offset_all_coordinates() highest_coord = self.find_highest_coords() self.width = highest_coord[0] self.height = highest_coord[1] - if OPTS.use_pex and not OPTS.calibre_pex: + if OPTS.use_pex and OPTS.pex_exe[0] != "calibre": + debug.info(2, "adding global pex labels") self.add_global_pex_labels() self.add_boundary(ll=vector(0, 0), ur=vector(self.width, self.height)) diff --git a/compiler/tests/30_openram_back_end_test.py b/compiler/tests/30_openram_back_end_test.py index af8773a2..c2060656 100755 --- a/compiler/tests/30_openram_back_end_test.py +++ b/compiler/tests/30_openram_back_end_test.py @@ -46,7 +46,15 @@ class openram_back_end_test(openram_test): if OPTS.spice_name: options += " -s {}".format(OPTS.spice_name) - exe_name = "{0}{1}/openram.py ".format(OPTS.coverage_exe, OPENRAM_HOME) + if OPTS.tech_name: + options += " -t {}".format(OPTS.tech_name) + + # Always perform code coverage + if OPTS.coverage == 0: + debug.warning("Failed to find coverage installation. This can be installed with pip3 install coverage") + exe_name = "{0}/openram.py ".format(OPENRAM_HOME) + else: + exe_name = "{0}{1}/openram.py ".format(OPTS.coverage_exe, OPENRAM_HOME) config_name = "{0}/tests/configs/config_back_end.py".format(OPENRAM_HOME) cmd = "{0} -o {1} -p {2} {3} {4} 2>&1 > {5}/output.log".format(exe_name, out_file, diff --git a/compiler/tests/30_openram_front_end_test.py b/compiler/tests/30_openram_front_end_test.py index b80c6d7d..1c190840 100755 --- a/compiler/tests/30_openram_front_end_test.py +++ b/compiler/tests/30_openram_front_end_test.py @@ -46,7 +46,15 @@ class openram_front_end_test(openram_test): if OPTS.spice_name: options += " -s {}".format(OPTS.spice_name) - exe_name = "{0}{1}/openram.py ".format(OPTS.coverage_exe, OPENRAM_HOME) + if OPTS.tech_name: + options += " -t {}".format(OPTS.tech_name) + + # Always perform code coverage + if OPTS.coverage == 0: + debug.warning("Failed to find coverage installation. This can be installed with pip3 install coverage") + exe_name = "{0}/openram.py ".format(OPENRAM_HOME) + else: + exe_name = "{0}{1}/openram.py ".format(OPTS.coverage_exe, OPENRAM_HOME) config_name = "{0}/tests/configs/config_front_end.py".format(OPENRAM_HOME) cmd = "{0} -n -o {1} -p {2} {3} {4} 2>&1 > {5}/output.log".format(exe_name, out_file, diff --git a/compiler/verify/calibre.py b/compiler/verify/calibre.py index 053ee916..53b2f167 100644 --- a/compiler/verify/calibre.py +++ b/compiler/verify/calibre.py @@ -142,7 +142,7 @@ def write_pex_script(cell_name, extract, output, final_verification=False, outpu if not output_path: output_path = OPTS.openram_temp - if output == None: + if not output: output = cell_name + ".pex.sp" # check if lvs report has been done @@ -186,12 +186,73 @@ def write_pex_script(cell_name, extract, output, final_verification=False, outpu f.write("*{0}: {1}\n".format(k, pex_runset[k])) f.close() + # write the rules file + f = open(output_path + "pex_rules", "w") + f.write('// Rules file, created by OpenRAM, (c) Bob Vanhoof\n') + f.write('\n') + f.write('LAYOUT PATH "' + output_path + cell_name + '.gds"\n') + f.write('LAYOUT PRIMARY ' + cell_name + '\n') + f.write('LAYOUT SYSTEM GDSII\n') + f.write('\n') + f.write('SOURCE PATH "' + output_path + cell_name + '.sp"\n') + f.write('SOURCE PRIMARY ' + cell_name +'\n') + f.write('SOURCE SYSTEM SPICE\n') + f.write('SOURCE CASE YES\n') + f.write('\n') + f.write('MASK SVDB DIRECTORY "svdb" QUERY XRC\n') + f.write('\n') + f.write('LVS REPORT "' + output_path + cell_name + '.pex.report"\n') + f.write('LVS REPORT OPTION NONE\n') + f.write('LVS FILTER UNUSED OPTION NONE SOURCE\n') + f.write('LVS FILTER UNUSED OPTION NONE LAYOUT\n') + f.write('LVS POWER NAME vdd\n') + f.write('LVS GROUND NAME gnd\n') + f.write('LVS RECOGNIZE GATES ALL\n') + f.write('LVS CELL SUPPLY YES\n') + f.write('LVS PUSH DEVICES SEPARATE PROPERTIES YES\n') + f.write('\n') + f.write('PEX NETLIST "' + output + '" HSPICE 1 SOURCENAMES GROUND gnd\n') + f.write('PEX REDUCE ANALOG NO\n') + f.write('PEX NETLIST UPPERCASE KEYWORDS NO\n') + f.write('PEX NETLIST VIRTUAL CONNECT YES\n') + f.write('PEX NETLIST NOXREF NET NAMES YES\n') + f.write('PEX NETLIST MUTUAL RESISTANCE YES\n') + f.write('PEX NETLIST EXPORT PORTS YES\n') + f.write('PEX PROBE FILE "probe_file"\n') + f.write('\n') + f.write('VIRTUAL CONNECT COLON NO\n') + f.write('VIRTUAL CONNECT REPORT NO\n') + f.write('VIRTUAL CONNECT NAME vdd gnd\n') + f.write('\n') + f.write('DRC ICSTATION YES\n') + f.write('\n') + f.write('INCLUDE "'+ pex_rules +'"\n') + f.close() + + # write probe file + # TODO: get from cell name + f = open(output_path + "probe_file", "w") + f.write('CELL cell_1rw\n') + f.write(' Q 0.100 0.510 11\n') + f.write(' Q_bar 0.520 0.510 11\n') + f.close() + # Create an auxiliary script to run calibre with the runset run_file = output_path + "run_pex.sh" f = open(run_file, "w") f.write("#!/bin/sh\n") - cmd = "{0} -gui -pex pex_runset -batch".format(OPTS.pex_exe[1]) - + cmd = "{0} -lvs -hier -genhcells -spice svdb/{1}.sp -turbo -hyper cmp {2}".format(OPTS.pex_exe[1], + cell_name, + 'pex_rules') + f.write(cmd) + f.write("\n") + cmd = "sed '/dummy/d' svdb/{0}.hcells | sed '/replica_column/d' | sed '/replica_cell/d' > hcell_file".format(cell_name) + f.write(cmd) + f.write("\n") + cmd = "{0} -xrc -pdb -turbo -xcell hcell_file -full -rc {1}".format(OPTS.pex_exe[1], 'pex_rules') + f.write(cmd) + f.write("\n") + cmd = "{0} -xrc -fmt -full {1}".format(OPTS.pex_exe[1], 'pex_rules') f.write(cmd) f.write("\n") f.close()