diff --git a/Makefile b/Makefile index aedf2202..18768dd4 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,9 @@ include $(TOP_DIR)/openram.mk .DEFAULT_GOAL := install +# Set the shell here +SHELL := /bin/bash + # Skywater PDK SRAM library SRAM_LIB_DIR ?= $(PDK_ROOT)/sky130_fd_bd_sram # Use this for release @@ -10,7 +13,7 @@ SRAM_LIB_GIT_REPO ?= https://github.com/vlsida/sky130_fd_bd_sram.git # Use this for development #SRAM_LIB_GIT_REPO ?= git@github.com:VLSIDA/sky130_fd_bd_sram.git #SRAM_LIB_GIT_REPO ?= https://github.com/google/skywater-pdk-libs-sky130_fd_bd_sram.git -SRAM_LIB_GIT_COMMIT ?= a83b6468c48434d927b90058b22047843c58027b +SRAM_LIB_GIT_COMMIT ?= 060f3638be6269dd9aa82cfbbdfd9525943c1582 # Open PDKs OPEN_PDKS_DIR ?= $(PDK_ROOT)/open_pdks @@ -94,6 +97,7 @@ $(SRAM_LIB_DIR): check-pdk-root @echo "Cloning SRAM library..." @[ -d $(SRAM_LIB_DIR) ] || \ git clone $(SRAM_LIB_GIT_REPO) $(SRAM_LIB_DIR) + @git -C $(SRAM_LIB_DIR) fetch @git -C $(SRAM_LIB_DIR) checkout $(SRAM_LIB_GIT_COMMIT) install: $(SRAM_LIB_DIR) diff --git a/README.md b/README.md index 4ffd94ad..45d8edae 100644 --- a/README.md +++ b/README.md @@ -57,13 +57,13 @@ OpenRAM is licensed under the [BSD 3-Clause License](./LICENSE). # Publications + [M. R. Guthaus, J. E. Stine, S. Ataei, B. Chen, B. Wu, M. Sarwar, "OpenRAM: An Open-Source Memory Compiler," Proceedings of the 35th International Conference on Computer-Aided Design (ICCAD), 2016.](https://escholarship.org/content/qt8x19c778/qt8x19c778_noSplash_b2b3fbbb57f1269f86d0de77865b0691.pdf) -+ [S. Ataei, J. Stine, M. Guthaus, “A 64 kb differential single-port 12T SRAM design with a bit-interleaving scheme for low-voltage operation in 32 nm SOI CMOS,” International Conference on Computer Design (ICCD), 2016, pp. 499-506.](https://escholarship.org/uc/item/99f6q9c9) -+ [E. Ebrahimi, M. Guthaus, J. Renau, “Timing Speculative SRAM”, IEEE International Symposium on Circuits and Systems (ISCAS), 2017.](https://escholarship.org/content/qt7nn0j5x3/qt7nn0j5x3_noSplash_172457455e1aceba20694c3d7aa489b4.pdf) -+ [B. Wu, J.E. Stine, M.R. Guthaus, "Fast and Area-Efficient Word-Line Optimization", IEEE International Symposium on Circuits and Systems (ISCAS), 2019.](https://escholarship.org/content/qt98s4c1hp/qt98s4c1hp_noSplash_753dcc3e218f60aafff98ef77fb56384.pdf) -+ [B. Wu, M. Guthaus, "Bottom Up Approach for High Speed SRAM Word-line Buffer Insertion Optimization", IFIP/IEEE International Conference on Very Large Scale Integration (VLSI-SoC), 2019.](https://ieeexplore.ieee.org/document/8920325) -+ [H. Nichols, M. Grimes, J. Sowash, J. Cirimelli-Low, M. Guthaus "Automated Synthesis of Multi-Port Memories and Control", IFIP/IEEE International Conference on Very Large Scale Integration (VLSI-SoC), 2019.](https://escholarship.org/content/qt7047n3k0/qt7047n3k0.pdf?t=q4gcij) -+ [H. Nichols, "Statistical Modeling of SRAMs", M.S. Thesis, UCSC, 2022.](https://escholarship.org/content/qt7vx9n089/qt7vx9n089_noSplash_cfc4ba479d8eb1b6ec25d7c92357bc18.pdf?t=ra9wzr) -+ [M. Guthaus, H. Nichols, J. Cirimelli-Low, J. Kunzler, B. Wu, "Enabling Design Technology Co-Optimization of SRAMs though Open-Source Software", IEEE International Electron Devices Meeting (IEDM), 2020.](https://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=9372047) ++ [S. Ataei, J. Stine, M. Guthaus, "A 64 kb differential single-port 12T SRAM design with a bit-interleaving scheme for low-voltage operation in 32 nm SOI CMOS," International Conference on Computer Design (ICCD), 2016, pp. 499-506.](https://escholarship.org/uc/item/99f6q9c9) ++ [E. Ebrahimi, M. Guthaus, J. Renau, "Timing Speculative SRAM," IEEE International Symposium on Circuits and Systems (ISCAS), 2017.](https://escholarship.org/content/qt7nn0j5x3/qt7nn0j5x3_noSplash_172457455e1aceba20694c3d7aa489b4.pdf) ++ [B. Wu, J.E. Stine, M.R. Guthaus, "Fast and Area-Efficient Word-Line Optimization," IEEE International Symposium on Circuits and Systems (ISCAS), 2019.](https://escholarship.org/content/qt98s4c1hp/qt98s4c1hp_noSplash_753dcc3e218f60aafff98ef77fb56384.pdf) ++ [B. Wu, M. Guthaus, "Bottom Up Approach for High Speed SRAM Word-line Buffer Insertion Optimization," IFIP/IEEE International Conference on Very Large Scale Integration (VLSI-SoC), 2019.](https://ieeexplore.ieee.org/document/8920325) ++ [H. Nichols, M. Grimes, J. Sowash, J. Cirimelli-Low, M. Guthaus "Automated Synthesis of Multi-Port Memories and Control," IFIP/IEEE International Conference on Very Large Scale Integration (VLSI-SoC), 2019.](https://escholarship.org/content/qt7047n3k0/qt7047n3k0.pdf?t=q4gcij) ++ [M. Guthaus, H. Nichols, J. Cirimelli-Low, J. Kunzler, B. Wu, "Enabling Design Technology Co-Optimization of SRAMs though Open-Source Software," IEEE International Electron Devices Meeting (IEDM), 2020.](https://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=9372047) ++ [H. Nichols, "Statistical Modeling of SRAMs," M.S. Thesis, UCSC, 2022.](https://escholarship.org/content/qt7vx9n089/qt7vx9n089_noSplash_cfc4ba479d8eb1b6ec25d7c92357bc18.pdf?t=ra9wzr) diff --git a/VERSION b/VERSION index 1fc5b820..9a83513a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.2.15 +1.2.22 diff --git a/compiler/base/__init__.py b/compiler/base/__init__.py index df14d00d..3c5d5212 100644 --- a/compiler/base/__init__.py +++ b/compiler/base/__init__.py @@ -16,6 +16,7 @@ from .lef import * from .logical_effort import * from .pin_layout import * from .power_data import * +from .rom_verilog import * from .route import * from .timing_graph import * from .utils import * diff --git a/compiler/base/hierarchy_spice.py b/compiler/base/hierarchy_spice.py index 5d92ab25..fe5d3a8a 100644 --- a/compiler/base/hierarchy_spice.py +++ b/compiler/base/hierarchy_spice.py @@ -68,7 +68,7 @@ class spice(): self.trim_insts = set() # Keep track of any comments to add the the spice try: - self.commments + self.comments except AttributeError: self.comments = [] @@ -82,7 +82,7 @@ class spice(): """ Add a comment to the spice file """ try: - self.commments + self.comments except AttributeError: self.comments = [] diff --git a/compiler/base/rom_verilog.py b/compiler/base/rom_verilog.py new file mode 100644 index 00000000..f914b539 --- /dev/null +++ b/compiler/base/rom_verilog.py @@ -0,0 +1,173 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import math +from openram.tech import spice + + +class rom_verilog: + """ + Create a behavioral Verilog file for simulation. + This is inherited by the rom_base class. + """ + def __init__(self): + pass + + def verilog_write(self, verilog_name): + """ Write a behavioral Verilog model. """ + self.vf = open(verilog_name, "w") + + self.vf.write("// OpenROM ROM model\n") + + #basic info + self.vf.write("// Words: {0}\n".format(self.num_words)) + self.vf.write("// Word size: {0}\n".format(self.word_size)) + self.vf.write("// Word per Row: {0}\n".format(self.words_per_row)) + self.vf.write("// Data Type: {0}\n".format(self.data_type)) + self.vf.write("// Data File: {0}\n".format(self.rom_data)) + + self.vf.write("\n") + + try: + self.vdd_name = spice["power"] + except KeyError: + self.vdd_name = "vdd" + try: + self.gnd_name = spice["ground"] + except KeyError: + self.gnd_name = "gnd" + + #add multiple banks later + self.vf.write("module {0}(\n".format(self.name)) + self.vf.write("`ifdef USE_POWER_PINS\n") + self.vf.write(" {},\n".format(self.vdd_name)) + self.vf.write(" {},\n".format(self.gnd_name)) + self.vf.write("`endif\n") + + for port in self.all_ports: + if port in self.read_ports: + self.vf.write("// Port {0}: R\n".format(port)) + self.vf.write(" clk{0},csb{0},addr{0},dout{0}".format(port)) + # Continue for every port on a new line + if port != self.all_ports[-1]: + self.vf.write(",\n") + self.vf.write("\n );\n\n") + + self.vf.write(" parameter DATA_WIDTH = {0} ;\n".format(self.word_size)) + self.vf.write(" parameter ADDR_WIDTH = {0} ;\n".format(math.ceil(math.log(self.num_words,2)))) + self.vf.write(" parameter ROM_DEPTH = 1 << ADDR_WIDTH;\n") + self.vf.write(" // FIXME: This delay is arbitrary.\n") + self.vf.write(" parameter DELAY = 3 ;\n") + self.vf.write(" parameter VERBOSE = 1 ; //Set to 0 to only display warnings\n") + self.vf.write(" parameter T_HOLD = 1 ; //Delay to hold dout value after posedge. Value is arbitrary\n") + self.vf.write("\n") + + self.vf.write("`ifdef USE_POWER_PINS\n") + self.vf.write(" inout {};\n".format(self.vdd_name)) + self.vf.write(" inout {};\n".format(self.gnd_name)) + self.vf.write("`endif\n") + + for port in self.all_ports: + self.add_inputs_outputs(port) + + self.vf.write("\n") + + # This is the memory array itself + self.vf.write(" reg [DATA_WIDTH-1:0] mem [0:ROM_DEPTH-1];\n\n") + + #write memory init here + self.vf.write(f" initial begin\n") + if self.data_type == "bin": + self.vf.write(f" $readmemb(\"{self.rom_data}\",mem,0,ROM_DEPTH-1);\n") + elif self.data_type == "hex": + self.vf.write(f" $readmemh(\"{self.rom_data}\",mem,0, ROM_DEPTH-1);\n") + else: + raise ValueError(f"Data type: {self.data_type} is not supported!") + self.vf.write(f" end\n\n") + + for port in self.all_ports: + self.register_inputs(port) + + for port in self.all_ports: + if port in self.read_ports: + self.add_read_block(port) + + self.vf.write("\n") + self.vf.write("endmodule\n") + self.vf.close() + + def register_inputs(self, port): + """ + Register the control signal, address and data inputs. + """ + self.add_regs(port) + self.add_flops(port) + + def add_regs(self, port): + """ + Create the input regs for the given port. + """ + self.vf.write(" reg csb{0}_reg;\n".format(port)) + self.vf.write(" reg [ADDR_WIDTH-1:0] addr{0}_reg;\n".format(port)) + if port in self.read_ports: + self.vf.write(" reg [DATA_WIDTH-1:0] dout{0};\n".format(port)) + + + def add_flops(self, port): + """ + Add the flop behavior logic for a port. + """ + self.vf.write("\n") + self.vf.write(" // All inputs are registers\n") + self.vf.write(" always @(posedge clk{0})\n".format(port)) + self.vf.write(" begin\n") + self.vf.write(" csb{0}_reg = csb{0};\n".format(port)) + self.vf.write(" addr{0}_reg = addr{0};\n".format(port)) + if port in self.read_ports: + self.add_write_read_checks(port) + + if port in self.read_ports: + self.vf.write(" #(T_HOLD) dout{0} = {1}'bx;\n".format(port, self.word_size)) + self.vf.write(" if ( !csb{0}_reg && VERBOSE ) \n".format(port)) + self.vf.write(" $display($time,\" Reading %m addr{0}=%b dout{0}=%b\",addr{0}_reg,mem[addr{0}_reg]);\n".format(port)) + + self.vf.write(" end\n\n") + + def add_inputs_outputs(self, port): + """ + Add the module input and output declaration for a port. + """ + self.vf.write(" input clk{0}; // clock\n".format(port)) + self.vf.write(" input csb{0}; // active low chip select\n".format(port)) + + self.vf.write(" input [ADDR_WIDTH-1:0] addr{0};\n".format(port)) + if port in self.read_ports: + self.vf.write(" output [DATA_WIDTH-1:0] dout{0};\n".format(port)) + + def add_write_block(self, port): + """ + ROM does not take writes thus this function does nothing + """ + self.vf.write("\n") + def add_read_block(self, port): + """ + Add a read port block. + """ + self.vf.write("\n") + self.vf.write(" // Memory Read Block Port {0}\n".format(port)) + self.vf.write(" // Read Operation : When web{0} = 1, csb{0} = 0\n".format(port)) + self.vf.write(" always @ (negedge clk{0})\n".format(port)) + self.vf.write(" begin : MEM_READ{0}\n".format(port)) + self.vf.write(" if (!csb{0}_reg)\n".format(port)) + self.vf.write(" dout{0} <= #(DELAY) mem[addr{0}_reg];\n".format(port)) + self.vf.write(" end\n") + + def add_write_read_checks(self, rport): + """ + Since ROMs dont have write ports this does nothing + """ + pass diff --git a/compiler/base/wire_spice_model.py b/compiler/base/wire_spice_model.py index b7001965..55ef040d 100644 --- a/compiler/base/wire_spice_model.py +++ b/compiler/base/wire_spice_model.py @@ -18,6 +18,7 @@ class wire_spice_model(): def cal_wire_c(self, wire_length, wire_width): from openram.tech import spice # Convert the F/um^2 to fF/um^2 then multiple by width and length + # FIXME: shouldn't it be 1e15? total_c = (spice["wire_unit_c"]*1e12) * wire_length * wire_width wire_c = total_c / self.lump_num return wire_c diff --git a/compiler/characterizer/simulation.py b/compiler/characterizer/simulation.py index f798267e..770aeb1a 100644 --- a/compiler/characterizer/simulation.py +++ b/compiler/characterizer/simulation.py @@ -595,7 +595,7 @@ class simulation(): for path in paths: aliases = self.sram.find_aliases(self.sram_instance_name, self.pins, path, internal_net, mod, exclusion_set) if net_found and len(aliases) >= 1: - debug.error('Found multiple paths with {} net.'.format(internal_net), 1) + pass #debug.error('Found multiple paths with {} net.'.format(internal_net), 1) elif len(aliases) > 1: debug.error('Found multiple {} nets in single path.'.format(internal_net), 1) elif not net_found and len(aliases) == 1: diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 8cf92961..561d68c3 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -85,7 +85,8 @@ class bank(design): for bit in range(self.word_size + self.num_spare_cols): self.add_pin("dout{0}_{1}".format(port, bit), "OUTPUT") for port in self.all_ports: - self.add_pin("rbl_bl_{0}_{0}".format(port), "OUTPUT") + if self.has_rbl: + self.add_pin("rbl_bl_{0}_{0}".format(port), "OUTPUT") for port in self.write_ports: for bit in range(self.word_size + self.num_spare_cols): self.add_pin("din{0}_{1}".format(port, bit), "INPUT") @@ -114,11 +115,10 @@ class bank(design): """ Create routing amoung the modules """ self.route_central_bus() - self.route_unused_wordlines() - for port in self.all_ports: self.route_bitlines(port) - self.route_rbl(port) + if self.has_rbl: + self.route_rbl(port) self.route_port_address(port) self.route_column_address_lines(port) self.route_control_lines(port) @@ -360,6 +360,18 @@ class bank(design): def add_modules(self): """ Add all the modules using the class loader """ + # delay control logic does not have RBLs + if OPTS.control_logic != "control_logic_delay": + self.has_rbl = True + rbl = [1, 1 if len(self.all_ports)>1 else 0] + left_rbl = [0] + right_rbl = [1] if len(self.all_ports)>1 else [] + else: + self.has_rbl = False + rbl = [0, 0] + left_rbl = [] + right_rbl = [] + local_array_size = OPTS.local_array_size if local_array_size > 0: @@ -372,21 +384,25 @@ class bank(design): cols.append(local_array_size + final_size) self.bitcell_array = factory.create(module_type="global_bitcell_array", cols=cols, - rows=self.num_rows) + rows=self.num_rows, + rbl=rbl, + left_rbl=left_rbl, + right_rbl=right_rbl) else: self.bitcell_array = factory.create(module_type="capped_replica_bitcell_array", cols=self.num_cols + self.num_spare_cols, rows=self.num_rows, - rbl=[1, 1 if len(self.all_ports)>1 else 0], - left_rbl=[0], - right_rbl=[1] if len(self.all_ports)>1 else []) + rbl=rbl, + left_rbl=left_rbl, + right_rbl=right_rbl) self.port_address = [] for port in self.all_ports: self.port_address.append(factory.create(module_type="port_address", cols=self.num_cols + self.num_spare_cols, rows=self.num_rows, - port=port)) + port=port, + has_rbl=self.has_rbl)) self.port_data = [] self.bit_offsets = self.get_column_offsets() @@ -394,6 +410,7 @@ class bank(design): self.port_data.append(factory.create(module_type="port_data", sram_config=self.sram_config, port=port, + has_rbl=self.has_rbl, bit_offsets=self.bit_offsets)) def create_bitcell_array(self): @@ -407,9 +424,10 @@ class bank(design): # gnd temp = self.bitcell_array.get_inouts() - temp.append("rbl_wl0") + if self.has_rbl: + temp.append("rbl_wl0") temp.extend(self.bitcell_array.get_wordline_names()) - if len(self.all_ports) > 1: + if len(self.all_ports) > 1 and self.has_rbl: temp.append("rbl_wl1") temp.append("vdd") @@ -432,7 +450,8 @@ class bank(design): mod=self.port_data[port]) temp = [] - temp.extend(["rbl_bl_{0}_{0}".format(port), "rbl_br_{0}_{0}".format(port)]) + if self.has_rbl: + temp.extend(["rbl_bl_{0}_{0}".format(port), "rbl_br_{0}_{0}".format(port)]) temp.extend(self.bitcell_array.get_bitline_names(port)) if port in self.read_ports: for bit in range(self.word_size + self.num_spare_cols): @@ -480,7 +499,8 @@ class bank(design): temp.append("wl_en{}".format(port)) wordline_names = self.bitcell_array.get_wordline_names(port) temp.extend(wordline_names) - temp.append("rbl_wl{}".format(port)) + if self.has_rbl: + temp.append("rbl_wl{}".format(port)) temp.extend(["vdd", "gnd"]) self.connect_inst(temp) @@ -719,8 +739,9 @@ class bank(design): inst2_br_name=inst2_br_name) # Connect the replica bitlines - for (array_name, data_name) in zip(["rbl_bl_{0}_{0}".format(port), "rbl_br_{0}_{0}".format(port)], ["rbl_bl", "rbl_br"]): - self.connect_bitline(inst1, inst2, array_name, data_name) + if self.has_rbl: + for (array_name, data_name) in zip(["rbl_bl_{0}_{0}".format(port), "rbl_br_{0}_{0}".format(port)], ["rbl_bl", "rbl_br"]): + self.connect_bitline(inst1, inst2, array_name, data_name) def route_port_data_out(self, port): """ Add pins for the port data out """ @@ -841,8 +862,13 @@ class bank(design): def route_port_address_out(self, port, side="left"): """ Connecting Wordline driver output to Bitcell WL connection """ - driver_names = ["wl_{}".format(x) for x in range(self.num_rows)] + ["rbl_wl"] - rbl_wl_name = self.bitcell_array.get_rbl_wordline_names(port)[port] + driver_names = ["wl_{}".format(x) for x in range(self.num_rows)] + if self.has_rbl: + driver_names = driver_names + ["rbl_wl"] + rbl_wl_name = self.bitcell_array.get_rbl_wordline_names(port)[port] + else: + rbl_wl_name = None + # rbl_wl in next line will be ignored by zip once driver_names is exhausted in the no rbl case for (driver_name, array_name) in zip(driver_names, self.bitcell_array.get_wordline_names(port) + [rbl_wl_name]): # The mid guarantees we exit the input cell to the right. driver_wl_pin = self.port_address_inst[port].get_pin(driver_name) @@ -875,7 +901,10 @@ class bank(design): def route_port_address_right(self, port): """ Connecting Wordline driver output to Bitcell WL connection """ - driver_names = ["wl_{}".format(x) for x in range(self.num_rows)] + ["rbl_wl"] + driver_names = ["wl_{}".format(x) for x in range(self.num_rows)] + if self.has_rbl: + driver_names = driver_names + ["rbl_wl"] + # rbl_wl in next two lines will be ignored by zip once driver_names is exhausted in the no rbl case rbl_wl_name = self.bitcell_array.get_rbl_wordline_names(port)[port] for (driver_name, array_name) in zip(driver_names, self.bitcell_array.get_wordline_names(port) + [rbl_wl_name]): # The mid guarantees we exit the input cell to the right. @@ -971,36 +1000,6 @@ class bank(design): # layer="m1", # offset=data_pin.center()) - def route_unused_wordlines(self): - """ Connect the unused RBL and dummy wordlines to gnd """ - gnd_wl_names = [] - return - # Connect unused RBL WL to gnd - # All RBL WL names - array_rbl_names = set(self.bitcell_array.get_rbl_wordline_names()) - # List of used RBL WL names - rbl_wl_names = set() - for port in self.all_ports: - rbl_wl_names.add(self.bitcell_array.get_rbl_wordline_names(port)[port]) - gnd_wl_names = list((array_rbl_names - rbl_wl_names)) - - for wl_name in gnd_wl_names: - pin = self.bitcell_array_inst.get_pin(wl_name) - pin_layer = pin.layer - layer_pitch = 1.5 * getattr(self, "{}_pitch".format(pin_layer)) - left_pin_loc = pin.lc() - right_pin_loc = pin.rc() - - # Place the pins a track outside of the array - left_loc = left_pin_loc - vector(layer_pitch, 0) - right_loc = right_pin_loc + vector(layer_pitch, 0) - self.add_power_pin("gnd", left_loc, directions=("H", "H")) - self.add_power_pin("gnd", right_loc, directions=("H", "H")) - - # Add a path to connect to the array - self.add_path(pin_layer, [left_loc, left_pin_loc]) - self.add_path(pin_layer, [right_loc, right_pin_loc]) - def route_control_lines(self, port): """ Route the control lines of the entire bank """ diff --git a/compiler/modules/capped_replica_bitcell_array.py b/compiler/modules/capped_replica_bitcell_array.py index 65193bab..8e1395d1 100644 --- a/compiler/modules/capped_replica_bitcell_array.py +++ b/compiler/modules/capped_replica_bitcell_array.py @@ -33,7 +33,10 @@ class capped_replica_bitcell_array(bitcell_base_array): self.column_size = cols self.row_size = rows # This is how many RBLs are in all the arrays - self.rbl = rbl + if rbl is not None: + self.rbl = rbl + else: + self.rbl = [0] * len(self.all_ports) # This specifies which RBL to put on the left or right by port number # This could be an empty list if left_rbl is not None: @@ -64,28 +67,7 @@ class capped_replica_bitcell_array(bitcell_base_array): self.create_instances() def add_modules(self): - """ Array and dummy/replica columns - - d or D = dummy cell (caps to distinguish grouping) - r or R = replica cell (caps to distinguish grouping) - b or B = bitcell - replica columns 1 - v v - bdDDDDDDDDDDDDDDdb <- Dummy row - bdDDDDDDDDDDDDDDrb <- Dummy row - br--------------rb - br| Array |rb - br| row x col |rb - br--------------rb - brDDDDDDDDDDDDDDdb <- Dummy row - bdDDDDDDDDDDDDDDdb <- Dummy row - - ^^^^^^^^^^^^^^^ - dummy rows cols x 1 - - ^ dummy columns ^ - 1 x (rows + 4) - """ + """ Array and cap rows/columns """ self.replica_bitcell_array = factory.create(module_type="replica_bitcell_array", cols=self.column_size, @@ -132,7 +114,7 @@ class capped_replica_bitcell_array(bitcell_base_array): # + right replica column(s) column_offset=1 + len(self.left_rbl) + self.column_size + self.rbl[0], rows=self.row_size + self.extra_rows, - mirror=(self.rbl[0] + 1) %2) + mirror=(self.rbl[0] + 1) % 2) def add_pins(self): @@ -219,6 +201,7 @@ class capped_replica_bitcell_array(bitcell_base_array): # row-based or column based power and ground lines. self.vertical_pitch = 1.1 * getattr(self, "{}_pitch".format(self.supply_stack[0])) self.horizontal_pitch = 1.1 * getattr(self, "{}_pitch".format(self.supply_stack[2])) + # FIXME: custom sky130 replica module has a better version of this offset self.unused_offset = vector(0.25, 0.25) # This is a bitcell x bitcell offset to scale diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index ce1a7601..be8281ef 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -118,8 +118,6 @@ class control_logic(control_logic_base): # list of output control signals (for making a vertical bus) if self.port_type == "rw": self.internal_bus_list = ["rbl_bl_delay_bar", "rbl_bl_delay", "gated_clk_bar", "gated_clk_buf", "we", "we_bar", "clk_buf", "cs"] - elif self.port_type == "r": - self.internal_bus_list = ["rbl_bl_delay_bar", "rbl_bl_delay", "gated_clk_bar", "gated_clk_buf", "clk_buf", "cs_bar", "cs"] else: self.internal_bus_list = ["rbl_bl_delay_bar", "rbl_bl_delay", "gated_clk_bar", "gated_clk_buf", "clk_buf", "cs"] # leave space for the bus plus one extra space diff --git a/compiler/modules/control_logic_base.py b/compiler/modules/control_logic_base.py index c3509121..83739055 100644 --- a/compiler/modules/control_logic_base.py +++ b/compiler/modules/control_logic_base.py @@ -328,8 +328,6 @@ class control_logic_base(design): def route_dffs(self): if self.port_type == "rw": dff_out_map = zip(["dout_bar_0", "dout_bar_1", "dout_1"], ["cs", "we", "we_bar"]) - elif self.port_type == "r": - dff_out_map = zip(["dout_bar_0", "dout_0"], ["cs", "cs_bar"]) else: dff_out_map = zip(["dout_bar_0"], ["cs"]) self.connect_vertical_bus(dff_out_map, self.ctrl_dff_inst, self.input_bus, self.m2_stack[::-1]) diff --git a/compiler/modules/control_logic_delay.py b/compiler/modules/control_logic_delay.py new file mode 100644 index 00000000..b980d9eb --- /dev/null +++ b/compiler/modules/control_logic_delay.py @@ -0,0 +1,469 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# + +import math +from openram import debug +from openram import OPTS +from openram.base import design +from openram.base import vector +from openram.base import logical_effort, convert_farad_to_relative_c +from openram.tech import drc, spice +from openram.sram_factory import factory +from .control_logic_base import control_logic_base + + +class control_logic_delay(control_logic_base): + """ + Dynamically generated Control logic for the total SRAM circuit. + Variant: delay-based + """ + + def __init__(self, num_rows, words_per_row, word_size, spare_columns=None, sram=None, port_type="rw", name=""): + """ Constructor """ + super().__init__(num_rows, words_per_row, word_size, spare_columns, sram, port_type, name) + + def add_pins(self): + """ Add the pins to the control logic module. """ + self.add_pin_list(self.input_list + ["clk"], "INPUT") + self.add_pin_list(self.output_list, "OUTPUT") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") + + def add_modules(self): + """ Add all the required modules """ + + self.dff = factory.create(module_type="dff_buf") + dff_height = self.dff.height + + self.ctrl_dff_array = factory.create(module_type="dff_buf_array", + rows=self.num_control_signals, + columns=1) + + self.and2 = factory.create(module_type="pand2", + size=12, + height=dff_height) + + # clk_buf drives a flop for every address + addr_flops = math.log(self.num_words, 2) + math.log(self.words_per_row, 2) + # plus data flops and control flops + num_flops = addr_flops + self.word_size + self.num_spare_cols + self.num_control_signals + # each flop internally has a FO 5 approximately + # plus about 5 fanouts for the control logic + clock_fanout = 5 * num_flops + 5 + self.clk_buf_driver = factory.create(module_type="pdriver", + fanout=clock_fanout, + height=dff_height) + + # We will use the maximum since this same value is used to size the wl_en + # and the p_en_bar drivers + # max_fanout = max(self.num_rows, self.num_cols) + + # wl_en drives every row in the bank + # this calculation is from the rbl control logic, it may not be optimal in this circuit + size_list = [max(int(self.num_rows / 9), 1), max(int(self.num_rows / 3), 1)] + self.wl_en_driver = factory.create(module_type="pdriver", + size_list=size_list, + height=dff_height) + + # this is the weak timing signal that feeds wl_en_driver + self.wl_en_and = factory.create(module_type="pand2", + size=1, + height=dff_height) + + # w_en drives every write driver + self.wen_and = factory.create(module_type="pand3", + size=self.word_size + 8, + height=dff_height) + + # s_en drives every sense amp + self.sen_and3 = factory.create(module_type="pand3", + size=self.word_size + self.num_spare_cols, + height=dff_height) + + # used to generate inverted signals with low fanout + self.inv = factory.create(module_type="pinv", + size=1, + height=dff_height) + + # p_en_bar drives every column in the bitcell array + # but it is sized the same as the wl_en driver with + # prepended 3 inverter stages to guarantee it is slower and odd polarity + self.p_en_bar_driver = factory.create(module_type="pdriver", + fanout=self.num_cols, + height=dff_height) + + self.nand2 = factory.create(module_type="pnand2", + height=dff_height) + + self.compute_delay_chain_size() + self.delay_chain = factory.create(module_type="multi_delay_chain", + fanout_list=self.delay_chain_fanout_list, + pinout_list=self.delay_chain_pinout_list) + + def compute_delay_chain_size(self): + """ + calculate the pinouts needed for the delay chain based on + wordline, bitline, and precharge delays + delays 0 & 1 need to be even for polarity + delays 2 - 4 need to be odd for polarity + """ + bitcell = factory.create(module_type=OPTS.bitcell) + # TODO: check that these spice values are up to date in tech files and if not figure out how to update them + # 2 access tx gate per cell + wordline_area = bitcell.width * drc("minwidth_m1") + wordline_cap_ff = self.num_cols * (2 * spice["min_tx_gate_c"] + spice["wire_unit_c"] * 1e15 * wordline_area) + wordline_cap = convert_farad_to_relative_c(wordline_cap_ff) + # 1 access tx drain per cell + bitline_area = bitcell.height * drc("minwidth_m2") + bitline_cap_ff = self.num_rows * (spice["min_tx_drain_c"] + spice["wire_unit_c"] * 1e15 * bitline_area) + bitline_cap = convert_farad_to_relative_c(bitline_cap_ff) + # 3 pmos gate per cell + pen_cap_ff = self.num_cols * (3 * spice["min_tx_gate_c"] + spice["wire_unit_c"] * 1e15 * wordline_area) + pen_cap = convert_farad_to_relative_c(pen_cap_ff) + # number of stages in the p_en driver + pen_stages = self.p_en_bar_driver.num_stages + + inverter_stage_delay = logical_effort("inv", 1, 1, OPTS.delay_chain_fanout_per_stage, 1, True).get_absolute_delay() + # model precharge as a minimum sized inverter with the bitline as its load + precharge_delay = logical_effort("precharge", 1, 1, bitline_cap, 1, True).get_absolute_delay() + # exponential horn delay from logical effort paper (converted to absolute delay) + pen_signal_delay = logical_effort.tau * (pen_stages * (pen_cap ** (1 / pen_stages) + 1)) + # size is a pessimistic version of wordline_driver module's FO4 sizing + wordline_driver_size = int(self.num_cols / 4) + 1 + wordline_delay = logical_effort("wordline", wordline_driver_size, 1, wordline_cap, 1, True).get_absolute_delay() + # wl_en driver is always two stages so add each independently? + wlen_signal_delay = logical_effort("wlen_driver", self.wl_en_driver.size_list[0], 1, self.wl_en_driver.size_list[1], 1, True).get_absolute_delay() + wlen_signal_delay += logical_effort("wlen_driver", self.wl_en_driver.size_list[1], 1, wordline_driver_size * self.num_rows, 1, True).get_absolute_delay() + # time for bitline to drop from vdd by threshold voltage once wordline enabled + bitline_vth_swing = (spice["nom_supply_voltage"] - spice["nom_threshold"]) / spice["nom_supply_voltage"] + bitline_vth_delay = abs(math.log(1 - bitline_vth_swing)) * spice["wire_unit_r"] * bitline_area * bitline_cap_ff + # print("delays: delay_stage {} precharge {} pen {} wl {} wlen {} vth {}".format(inverter_stage_delay, precharge_delay, pen_signal_delay, wordline_delay, wlen_signal_delay, bitline_vth_delay)) + + delays = [None] * 5 + # keepout between p_en rising and wl_en falling + delays[0] = (wlen_signal_delay + wordline_delay) / inverter_stage_delay # could possibly subtract pen_signal_delay? + delays[0] = int(delays[0] * OPTS.delay_control_scaling_factor) + # round up to nearest even integer + delays[0] += delays[0] % 2 + delays[2] = delays[0] + (pen_signal_delay + precharge_delay) / inverter_stage_delay + delays[2] *= OPTS.delay_control_scaling_factor + # round up to nearest odd integer + delays[2] = int(1 - (2 * ((1 - delays[2]) // 2))) + # delays[1] can be any even value less than delays[2] + delays[1] = delays[2] - 1 + # keepout between p_en falling and wl_en rising + delays[3] = delays[2] + pen_signal_delay / inverter_stage_delay + delays[3] *= OPTS.delay_control_scaling_factor + delays[3] = int(1 - (2 * ((1 - delays[3]) // 2))) + delays[4] = delays[3] + (wlen_signal_delay + wordline_delay + bitline_vth_delay) / inverter_stage_delay + delays[4] *= OPTS.delay_control_scaling_factor + delays[4] = int(1 - (2 * ((1 - delays[4]) // 2))) + self.delay_chain_pinout_list = delays + # FIXME: fanout should be used to control delay chain height + # for now, use default/user-defined fanout constant + self.delay_chain_fanout_list = self.delay_chain_pinout_list[-1] * [OPTS.delay_chain_fanout_per_stage] + + def setup_signal_busses(self): + """ Setup bus names, determine the size of the busses etc """ + + # List of input control signals + if self.port_type == "rw": + self.input_list = ["csb", "web"] + else: + self.input_list = ["csb"] + + if self.port_type == "rw": + self.dff_output_list = ["cs_bar", "cs", "we_bar", "we"] + else: + self.dff_output_list = ["cs_bar", "cs"] + + # list of output control signals (for making a vertical bus) + if self.port_type == "rw": + self.internal_bus_list = ["glitch1", "glitch2", "delay0", "delay1", "delay2", "delay3", "delay4", "gated_clk_bar", "gated_clk_buf", "we", "we_bar", "clk_buf", "cs"] + else: + self.internal_bus_list = ["glitch1", "glitch2", "delay0", "delay1", "delay2", "delay3", "delay4", "gated_clk_bar", "gated_clk_buf", "clk_buf", "cs"] + # leave space for the bus plus one extra space + self.internal_bus_width = (len(self.internal_bus_list) + 1) * self.m2_pitch + + # Outputs to the bank + if self.port_type == "rw": + self.output_list = ["s_en", "w_en"] + elif self.port_type == "r": + self.output_list = ["s_en"] + else: + self.output_list = ["w_en"] + self.output_list.append("p_en_bar") + self.output_list.append("wl_en") + self.output_list.append("clk_buf") + + self.supply_list = ["vdd", "gnd"] + + def create_instances(self): + """ Create all the instances """ + self.create_dffs() + self.create_clk_buf_row() + self.create_gated_clk_bar_row() + self.create_gated_clk_buf_row() + self.create_delay() + self.create_glitches() + self.create_wlen_row() + if (self.port_type == "rw") or (self.port_type == "w"): + self.create_wen_row() + if (self.port_type == "rw") or (self.port_type == "r"): + self.create_sen_row() + self.create_pen_row() + + def place_logic_rows(self): + row = 0 + self.place_clk_buf_row(row) + row += 1 + self.place_gated_clk_bar_row(row) + row += 1 + self.place_gated_clk_buf_row(row) + row += 1 + if (self.port_type == "rw") or (self.port_type == "r"): + self.place_sen_row(row) + row += 1 + if (self.port_type == "rw") or (self.port_type == "w"): + self.place_wen_row(row) + row += 1 + self.place_pen_row(row) + row += 1 + self.place_wlen_row(row) + row += 1 + self.place_glitch1_row(row) + row += 1 + self.place_glitch2_row(row) + + self.control_center_y = self.glitch2_nand_inst.uy() + self.m3_pitch + + def route_all(self): + """ Routing between modules """ + self.route_rails() + self.route_dffs() + self.route_wlen() + if (self.port_type == "rw") or (self.port_type == "w"): + self.route_wen() + if (self.port_type == "rw") or (self.port_type == "r"): + self.route_sen() + self.route_delay() + self.route_pen() + self.route_glitches() + self.route_clk_buf() + self.route_gated_clk_bar() + self.route_gated_clk_buf() + self.route_supplies() + + def create_delay(self): + """ Create the delay chain """ + self.delay_inst=self.add_inst(name="multi_delay_chain", + mod=self.delay_chain) + self.connect_inst(["gated_clk_buf", "delay0", "delay1", "delay2", "delay3", "delay4", "vdd", "gnd"]) + + def route_delay(self): + # this is a bit of a hack because I would prefer to just name these pins delay in the layout + # instead I have this which duplicates the out_pin naming logic from multi_delay_chain.py + out_pins = ["out{}".format(str(pin)) for pin in self.delay_chain.pinout_list] + delay_map = zip(["in", out_pins[0], out_pins[1], out_pins[2], out_pins[3], out_pins[4]], \ + ["gated_clk_buf", "delay0", "delay1", "delay2", "delay3", "delay4"]) + + self.connect_vertical_bus(delay_map, + self.delay_inst, + self.input_bus, + self.m2_stack[::-1]) + + # glitch{0-2} are internal timing signals based on different in/out + # points on the delay chain for adjustable start time and duration + def create_glitches(self): + self.glitch0_nand_inst = self.add_inst(name="nand2_glitch0", + mod=self.nand2) + self.connect_inst(["delay0", "delay2", "glitch0", "vdd", "gnd"]) + + self.glitch1_nand_inst = self.add_inst(name="nand2_glitch1", + mod=self.nand2) + self.connect_inst(["gated_clk_buf", "delay3", "glitch1", "vdd", "gnd"]) + + self.glitch2_nand_inst = self.add_inst(name="nand2_glitch2", + mod=self.nand2) + self.connect_inst(["delay1", "delay4", "glitch2", "vdd", "gnd"]) + + # glitch0 is placed in place_pen_row() + + def place_glitch1_row(self, row): + x_offset = self.control_x_offset + + x_offset = self.place_util(self.glitch1_nand_inst, x_offset, row) + + self.row_end_inst.append(self.glitch1_nand_inst) + + def place_glitch2_row(self, row): + x_offset = self.control_x_offset + + x_offset = self.place_util(self.glitch2_nand_inst, x_offset, row) + + self.row_end_inst.append(self.glitch2_nand_inst) + + def route_glitches(self): + glitch1_map = zip(["A", "B", "Z"], ["gated_clk_buf", "delay3", "glitch1"]) + + self.connect_vertical_bus(glitch1_map, self.glitch1_nand_inst, self.input_bus) + + glitch2_map = zip(["A", "B", "Z"], ["delay1", "delay4", "glitch2"]) + + self.connect_vertical_bus(glitch2_map, self.glitch2_nand_inst, self.input_bus) + + def create_wlen_row(self): + self.wl_en_unbuf_and_inst = self.add_inst(name="and_wl_en_unbuf", + mod=self.wl_en_and) + self.connect_inst(["cs", "glitch1", "wl_en_unbuf", "vdd", "gnd"]) + + self.wl_en_driver_inst=self.add_inst(name="buf_wl_en", + mod=self.wl_en_driver) + self.connect_inst(["wl_en_unbuf", "wl_en", "vdd", "gnd"]) + + def place_wlen_row(self, row): + x_offset = self.control_x_offset + + x_offset = self.place_util(self.wl_en_unbuf_and_inst, x_offset, row) + x_offset = self.place_util(self.wl_en_driver_inst, x_offset, row) + + self.row_end_inst.append(self.wl_en_driver_inst) + + def route_wlen(self): + in_map = zip(["A", "B"], ["cs", "glitch1"]) + self.connect_vertical_bus(in_map, self.wl_en_unbuf_and_inst, self.input_bus) + + out_pin = self.wl_en_unbuf_and_inst.get_pin("Z") + out_pos = out_pin.center() + in_pin = self.wl_en_driver_inst.get_pin("A") + in_pos = in_pin.center() + mid1 = vector(out_pos.x, in_pos.y) + self.add_path(out_pin.layer, [out_pos, mid1, in_pos]) + self.add_via_stack_center(from_layer=out_pin.layer, + to_layer=in_pin.layer, + offset=in_pin.center()) + self.connect_output(self.wl_en_driver_inst, "Z", "wl_en") + + def create_pen_row(self): + self.p_en_bar_driver_inst=self.add_inst(name="buf_p_en_bar", + mod=self.p_en_bar_driver) + self.connect_inst(["glitch0", "p_en_bar", "vdd", "gnd"]) + + def place_pen_row(self, row): + x_offset = self.control_x_offset + + x_offset = self.place_util(self.glitch0_nand_inst, x_offset, row) + x_offset = self.place_util(self.p_en_bar_driver_inst, x_offset, row) + + self.row_end_inst.append(self.p_en_bar_driver_inst) + + def route_pen(self): + in_map = zip(["A", "B"], ["delay0", "delay2"]) + self.connect_vertical_bus(in_map, self.glitch0_nand_inst, self.input_bus) + + out_pin = self.glitch0_nand_inst.get_pin("Z") # same code here as wl_en, refactor? + out_pos = out_pin.center() + in_pin = self.p_en_bar_driver_inst.get_pin("A") + in_pos = in_pin.center() + mid1 = vector(in_pos.x, out_pos.y) + self.add_path(out_pin.layer, [out_pos, mid1, in_pos]) + self.add_via_stack_center(from_layer=out_pin.layer, + to_layer=in_pin.layer, + offset=in_pin.center()) + + self.connect_output(self.p_en_bar_driver_inst, "Z", "p_en_bar") + + def create_sen_row(self): + if self.port_type=="rw": + input_name = "we_bar" + else: + input_name = "cs" + + self.s_en_gate_inst = self.add_inst(name="and_s_en", + mod=self.sen_and3) + self.connect_inst(["glitch2", "gated_clk_bar", input_name, "s_en", "vdd", "gnd"]) + + def place_sen_row(self, row): + x_offset = self.control_x_offset + + x_offset = self.place_util(self.s_en_gate_inst, x_offset, row) + + self.row_end_inst.append(self.s_en_gate_inst) + + def route_sen(self): + + if self.port_type=="rw": # this is repeated many times in here, refactor? + input_name = "we_bar" + else: + input_name = "cs" + + sen_map = zip(["A", "B", "C"], ["glitch2", "gated_clk_bar", input_name]) + self.connect_vertical_bus(sen_map, self.s_en_gate_inst, self.input_bus) + + self.connect_output(self.s_en_gate_inst, "Z", "s_en") + + def create_wen_row(self): + self.glitch2_bar_inv_inst = self.add_inst(name="inv_glitch2_bar", + mod=self.inv) + self.connect_inst(["glitch2", "glitch2_bar", "vdd", "gnd"]) + + if self.port_type == "rw": + input_name = "we" + else: + input_name = "cs" + + self.w_en_gate_inst = self.add_inst(name="and_w_en", + mod=self.wen_and) + self.connect_inst([input_name, "glitch1", "glitch2_bar", "w_en", "vdd", "gnd"]) + + def place_wen_row(self, row): + x_offset = self.control_x_offset + + x_offset = self.place_util(self.glitch2_bar_inv_inst, x_offset, row) + x_offset = self.place_util(self.w_en_gate_inst, x_offset, row) + + self.row_end_inst.append(self.w_en_gate_inst) + + def route_wen(self): # w_en comes from a 3and but one of the inputs needs to be inverted + glitch2_map = zip(["A"], ["glitch2"]) + self.connect_vertical_bus(glitch2_map, self.glitch2_bar_inv_inst, self.input_bus) + + out_pin = self.glitch2_bar_inv_inst.get_pin("Z") + out_pos = out_pin.center() + in_pin = self.w_en_gate_inst.get_pin("C") + in_pos = in_pin.center() + mid1 = vector(in_pos.x, out_pos.y) + self.add_path(out_pin.layer, [out_pos, mid1, in_pos]) + self.add_via_stack_center(from_layer=out_pin.layer, + to_layer=in_pin.layer, + offset=in_pos) + + if self.port_type == "rw": + input_name = "we" + else: + input_name = "cs" + + # This is the second gate over, so it needs to be on M3 + wen_map = zip(["A", "B"], [input_name, "glitch1"]) + self.connect_vertical_bus(wen_map, + self.w_en_gate_inst, + self.input_bus, + self.m2_stack[::-1]) + + # The pins are on M1, so we need more vias as well + a_pin = self.w_en_gate_inst.get_pin("A") + self.add_via_stack_center(from_layer=a_pin.layer, + to_layer="m3", + offset=a_pin.center()) + + b_pin = self.w_en_gate_inst.get_pin("B") + self.add_via_stack_center(from_layer=b_pin.layer, + to_layer="m3", + offset=b_pin.center()) + + self.connect_output(self.w_en_gate_inst, "Z", "w_en") diff --git a/compiler/modules/global_bitcell_array.py b/compiler/modules/global_bitcell_array.py index be50037f..e75f537d 100644 --- a/compiler/modules/global_bitcell_array.py +++ b/compiler/modules/global_bitcell_array.py @@ -20,14 +20,31 @@ class global_bitcell_array(bitcell_base_array): Rows is an integer number for all local arrays. Cols is a list of the array widths. """ - def __init__(self, rows, cols, name=""): + def __init__(self, rows, cols, rbl=None, left_rbl=None, right_rbl=None, name=""): # The total of all columns will be the number of columns super().__init__(name=name, rows=rows, cols=sum(cols), column_offset=0) self.column_sizes = cols self.col_offsets = [0] + list(cumsum(cols)[:-1]) - debug.check(len(self.all_ports)<=2, "Only support dual port or less in global bitcell array.") - self.rbl = [1, 1 if len(self.all_ports)>1 else 0] + debug.check(len(self.all_ports) < 3, "Only support dual port or less in global bitcell array.") + + # This is how many RBLs are in all the arrays + if rbl is not None: + self.rbl = rbl + else: + self.rbl = [0] * len(self.all_ports) + # This specifies which RBL to put on the left or right by port number + # This could be an empty list + if left_rbl is not None: + self.left_rbl = left_rbl + else: + self.left_rbl = [] + # This could be an empty list + if right_rbl is not None: + self.right_rbl = right_rbl + else: + self.right_rbl=[] + self.rbls = self.left_rbl + self.right_rbl self.create_netlist() if not OPTS.netlist_only: @@ -56,14 +73,13 @@ class global_bitcell_array(bitcell_base_array): self.local_mods = [] # Special case of a single local array - # so it should contain the left and possibly right RBL if len(self.column_sizes) == 1: la = factory.create(module_type="local_bitcell_array", rows=self.row_size, cols=self.column_sizes[0], rbl=self.rbl, - left_rbl=[0], - right_rbl=[1] if len(self.all_ports) > 1 else []) + left_rbl=self.left_rbl, + right_rbl=self.right_rbl) self.local_mods.append(la) return @@ -74,14 +90,14 @@ class global_bitcell_array(bitcell_base_array): rows=self.row_size, cols=cols, rbl=self.rbl, - left_rbl=[0]) - # Add the right RBL to the last subarray - elif i == len(self.column_sizes) - 1 and len(self.all_ports) > 1: + left_rbl=self.left_rbl) + # Add the right RBLs to the last subarray + elif i == len(self.column_sizes) - 1: la = factory.create(module_type="local_bitcell_array", rows=self.row_size, cols=cols, rbl=self.rbl, - right_rbl=[1]) + right_rbl=self.right_rbl) # Middle subarrays do not have any RBLs else: la = factory.create(module_type="local_bitcell_array", @@ -100,13 +116,16 @@ class global_bitcell_array(bitcell_base_array): self.add_pin("gnd", "GROUND") def add_bitline_pins(self): + # FIXME: aren't these already defined via inheritence by bitcell base array? self.bitline_names = [[] for x in self.all_ports] self.rbl_bitline_names = [[] for x in self.all_ports] - for port in self.all_ports: - self.rbl_bitline_names[0].append("rbl_bl_{}_0".format(port)) - for port in self.all_ports: - self.rbl_bitline_names[0].append("rbl_br_{}_0".format(port)) + # The bit is which port the RBL is for + for bit in self.rbls: + for port in self.all_ports: + self.rbl_bitline_names[bit].append("rbl_bl_{0}_{1}".format(port, bit)) + for port in self.all_ports: + self.rbl_bitline_names[bit].append("rbl_br_{0}_{1}".format(port, bit)) for col in range(self.column_size): for port in self.all_ports: @@ -114,21 +133,16 @@ class global_bitcell_array(bitcell_base_array): for port in self.all_ports: self.bitline_names[port].append("br_{0}_{1}".format(port, col)) - if len(self.all_ports) > 1: - for port in self.all_ports: - self.rbl_bitline_names[1].append("rbl_bl_{}_1".format(port)) - for port in self.all_ports: - self.rbl_bitline_names[1].append("rbl_br_{}_1".format(port)) - # Make a flat list too self.all_bitline_names = [x for sl in zip(*self.bitline_names) for x in sl] # Make a flat list too self.all_rbl_bitline_names = [x for sl in zip(*self.rbl_bitline_names) for x in sl] - self.add_pin_list(self.rbl_bitline_names[0], "INOUT") + for port in self.left_rbl: + self.add_pin_list(self.rbl_bitline_names[port], "INOUT") self.add_pin_list(self.all_bitline_names, "INOUT") - if len(self.all_ports) > 1: - self.add_pin_list(self.rbl_bitline_names[1], "INOUT") + for port in self.right_rbl: + self.add_pin_list(self.rbl_bitline_names[port], "INOUT") def add_wordline_pins(self): @@ -137,6 +151,8 @@ class global_bitcell_array(bitcell_base_array): self.wordline_names = [[] for x in self.all_ports] for bit in self.all_ports: + if self.rbl[bit] == 0: + continue for port in self.all_ports: self.rbl_wordline_names[port].append("rbl_wl_{0}_{1}".format(port, bit)) @@ -239,17 +255,18 @@ class global_bitcell_array(bitcell_base_array): start=left_pin.lc(), end=right_pin.rc()) - # Replica bitlines - self.copy_layout_pin(self.local_insts[0], "rbl_bl_0_0") - self.copy_layout_pin(self.local_insts[0], "rbl_br_0_0") + if len(self.rbls) > 0: + # Replica bitlines + self.copy_layout_pin(self.local_insts[0], "rbl_bl_0_0") + self.copy_layout_pin(self.local_insts[0], "rbl_br_0_0") - if len(self.all_ports) > 1: - self.copy_layout_pin(self.local_insts[0], "rbl_bl_1_0") - self.copy_layout_pin(self.local_insts[0], "rbl_br_1_0") - self.copy_layout_pin(self.local_insts[-1], "rbl_bl_0_1") - self.copy_layout_pin(self.local_insts[-1], "rbl_br_0_1") - self.copy_layout_pin(self.local_insts[-1], "rbl_bl_1_1") - self.copy_layout_pin(self.local_insts[-1], "rbl_br_1_1") + if len(self.all_ports) > 1: + self.copy_layout_pin(self.local_insts[0], "rbl_bl_1_0") + self.copy_layout_pin(self.local_insts[0], "rbl_br_1_0") + self.copy_layout_pin(self.local_insts[-1], "rbl_bl_0_1") + self.copy_layout_pin(self.local_insts[-1], "rbl_br_0_1") + self.copy_layout_pin(self.local_insts[-1], "rbl_bl_1_1") + self.copy_layout_pin(self.local_insts[-1], "rbl_br_1_1") for inst in self.insts: self.copy_power_pins(inst, "vdd") diff --git a/compiler/modules/local_bitcell_array.py b/compiler/modules/local_bitcell_array.py index f2bb8022..d0399801 100644 --- a/compiler/modules/local_bitcell_array.py +++ b/compiler/modules/local_bitcell_array.py @@ -31,7 +31,10 @@ class local_bitcell_array(bitcell_base_array): self.rows = rows self.cols = cols # This is how many RBLs are in all the arrays - self.rbl = rbl + if rbl is not None: + self.rbl = rbl + else: + self.rbl = [0] * len(self.all_ports) # This specifies which RBL to put on the left or right by port number # This could be an empty list if left_rbl is not None: @@ -84,8 +87,11 @@ class local_bitcell_array(bitcell_base_array): left_rbl=self.left_rbl, right_rbl=self.right_rbl) + # FIXME: this won't allow asymetric configurations such as rbl=[0, 1] + # but neither does a lot of this code... + rows = self.rows + (sum(self.rbl) != 0) self.wl_array = factory.create(module_type="wordline_buffer_array", - rows=self.rows + 1, + rows=rows, cols=self.cols) def add_pins(self): @@ -136,7 +142,8 @@ class local_bitcell_array(bitcell_base_array): self.wl_insts.append(self.add_inst(name="wl_driver{}".format(port), mod=self.wl_array)) temp = [] - temp += [self.get_rbl_wordline_names(port)[port]] + if self.rbl[port] != 0: + temp += [self.get_rbl_wordline_names(port)[port]] if port == 0: temp += self.get_wordline_names(port) else: @@ -180,8 +187,9 @@ class local_bitcell_array(bitcell_base_array): self.bitcell_array_inst.place(bitcell_array_offset) if len(self.all_ports) > 1: + rbl_wl_adder = self.cell.height * (self.rbl[1] != 0) wl_offset = vector(self.bitcell_array_inst.rx() + self.wl_array.width + driver_to_array_spacing, - self.bitcell_array.get_replica_bottom() + self.wl_array.height + self.cell.height) + self.bitcell_array.get_replica_bottom() + self.wl_array.height + rbl_wl_adder) self.wl_insts[1].place(wl_offset, mirror="XY") @@ -209,10 +217,16 @@ class local_bitcell_array(bitcell_base_array): # Route the global wordlines for port in self.all_ports: - if port == 0: - wordline_names = [self.get_rbl_wordline_names(port)[port]] + self.get_wordline_names(port) + if self.rbl[port] != 0: + if port == 0: + wordline_names = [self.get_rbl_wordline_names(port)[port]] + self.get_wordline_names(port) + else: + wordline_names = [self.get_rbl_wordline_names(port)[port]] + self.get_wordline_names(port)[::-1] else: - wordline_names = [self.get_rbl_wordline_names(port)[port]] + self.get_wordline_names(port)[::-1] + if port == 0: + wordline_names = self.get_wordline_names(port) + else: + wordline_names = self.get_wordline_names(port)[::-1] wordline_pins = self.wl_array.get_inputs() diff --git a/compiler/modules/multi_delay_chain.py b/compiler/modules/multi_delay_chain.py new file mode 100644 index 00000000..57b7f153 --- /dev/null +++ b/compiler/modules/multi_delay_chain.py @@ -0,0 +1,229 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +from openram import debug +from openram.base import design +from openram.base import vector +from openram.sram_factory import factory +from openram import OPTS + + +class multi_delay_chain(design): + """ + Generate a delay chain with the given number of stages, fanout, and output pins. + Fanout list contains the electrical effort (fanout) of each stage. + Usually, this will be constant, but it could have varied fanout. + Pinout list contains the inverter stages which have an output pin attached. + Supplying an empty pinout list will result in an output only on the last stage. + """ + + def __init__(self, name, fanout_list, pinout_list=None): + """init function""" + super().__init__(name) + debug.info(1, "creating delay chain with {0}".format("fanouts: " + str(fanout_list) + " pinouts: " + str(pinout_list))) + self.add_comment("fanouts: {0}".format(str(fanout_list))) + self.add_comment("pinouts: {0}".format(str(pinout_list))) + + # Two fanouts are needed so that we can route the vdd/gnd connections + for f in fanout_list: + debug.check(f>=2, "Must have >=2 fanouts for each stage.") + + # number of inverters including any fanout loads. + self.fanout_list = fanout_list + self.rows = len(self.fanout_list) + + # defaults to signle output at end of delay chain + if not pinout_list: + self.pinout_list = [self.rows] # TODO: check for off-by-one here + else: + self.pinout_list = pinout_list + + # TODO: would like to sort and check pinout list for valid format but don't have time now + # Check pinout bounds + # debug.check(self.pinout_list[-1] <= self.rows, + # "Ouput pin cannot exceed delay chain length.") + # debug.check(self.pinout_list[0] > 0, + # "Delay chain output pin numbers must be positive") + + self.create_netlist() + if not OPTS.netlist_only: + self.create_layout() + + def create_netlist(self): + self.add_modules() + self.add_pins() + self.create_inverters() + + def create_layout(self): + # Each stage is a row + self.height = self.rows * self.inv.height + + # The width is determined by the largest fanout plus the driver + self.width = (max(self.fanout_list) + 1) * self.inv.width + + self.place_inverters() + self.route_inverters() + self.route_supplies() + self.add_layout_pins() + self.add_boundary() + self.DRC_LVS() + + def add_pins(self): + """ Add the pins of the delay chain""" + self.add_pin("in", "INPUT") + for pin_stage in self.pinout_list: + self.add_pin("out{}".format(pin_stage), "OUTPUT") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") + + def add_modules(self): + + self.dff = factory.create(module_type="dff_buf") + dff_height = self.dff.height + + self.inv = factory.create(module_type="pinv", + height=dff_height) + + def create_inverters(self): + """ Create the inverters and connect them based on the stage list """ + self.driver_inst_list = [] + self.load_inst_map = {} + for stage_num, fanout_size in zip(range(self.rows), self.fanout_list): + # Add the inverter + cur_driver=self.add_inst(name="dinv{}".format(stage_num), + mod=self.inv) + # keep track of the inverter instances so we can use them to get the pins + self.driver_inst_list.append(cur_driver) + + # Hook up the driver + stageout_name = "out{}".format(stage_num + 1) # TODO: check for off-by-one here + if stage_num == 0: + stagein_name = "in" + else: + stagein_name = "out{}".format(stage_num) + self.connect_inst([stagein_name, stageout_name, "vdd", "gnd"]) + + # Now add the dummy loads to the right + self.load_inst_map[cur_driver]=[] + for i in range(fanout_size): + cur_load=self.add_inst(name="dload_{0}_{1}".format(stage_num, i), + mod=self.inv) + # Fanout stage is always driven by driver and output is disconnected + disconnect_name = "n_{0}_{1}".format(stage_num, i) + self.connect_inst([stageout_name, disconnect_name, "vdd", "gnd"]) + + # Keep track of all the loads to connect their inputs as a load + self.load_inst_map[cur_driver].append(cur_load) + + def place_inverters(self): + """ Place the inverters and connect them based on the stage list """ + for stage_num, fanout_size in zip(range(self.rows), self.fanout_list): + if stage_num % 2: + inv_mirror = "MX" + inv_offset = vector(0, (stage_num + 1) * self.inv.height) + else: + inv_mirror = "R0" + inv_offset = vector(0, stage_num * self.inv.height) + + # Add the inverter + cur_driver=self.driver_inst_list[stage_num] + cur_driver.place(offset=inv_offset, + mirror=inv_mirror) + + # Now add the dummy loads to the right + load_list = self.load_inst_map[cur_driver] + for i in range(fanout_size): + inv_offset += vector(self.inv.width, 0) + load_list[i].place(offset=inv_offset, + mirror=inv_mirror) + + def add_route(self, pin1, pin2): + """ This guarantees that we route from the top to bottom row correctly. """ + pin1_pos = pin1.center() + pin2_pos = pin2.center() + if pin1_pos.y == pin2_pos.y: + self.add_path("m2", [pin1_pos, pin2_pos]) + else: + mid_point = vector(pin2_pos.x, 0.5 * (pin1_pos.y + pin2_pos.y)) + # Written this way to guarantee it goes right first if we are switching rows + self.add_path("m2", [pin1_pos, vector(pin1_pos.x, mid_point.y), mid_point, vector(mid_point.x, pin2_pos.y), pin2_pos]) + + def route_inverters(self): + """ Add metal routing for each of the fanout stages """ + + for i in range(len(self.driver_inst_list)): + inv = self.driver_inst_list[i] + for load in self.load_inst_map[inv]: + # Drop a via on each A pin + a_pin = load.get_pin("A") + self.add_via_stack_center(from_layer=a_pin.layer, + to_layer="m3", + offset=a_pin.center()) + + # Route an M3 horizontal wire to the furthest + z_pin = inv.get_pin("Z") + a_pin = inv.get_pin("A") + a_max = self.load_inst_map[inv][-1].get_pin("A") + self.add_via_stack_center(from_layer=a_pin.layer, + to_layer="m2", + offset=a_pin.center()) + self.add_via_stack_center(from_layer=z_pin.layer, + to_layer="m3", + offset=z_pin.center()) + self.add_path("m3", [z_pin.center(), a_max.center()]) + + # Route Z to the A of the next stage + if i + 1 < len(self.driver_inst_list): + z_pin = inv.get_pin("Z") + next_inv = self.driver_inst_list[i + 1] + next_a_pin = next_inv.get_pin("A") + y_mid = (z_pin.cy() + next_a_pin.cy()) / 2 + mid1_point = vector(z_pin.cx(), y_mid) + mid2_point = vector(next_a_pin.cx(), y_mid) + self.add_path("m2", [z_pin.center(), mid1_point, mid2_point, next_a_pin.center()]) + + def route_supplies(self): + # Add power and ground to all the cells except: + # the fanout driver, the right-most load + # The routing to connect the loads is over the first and last cells + # We have an even number of drivers and must only do every other + # supply rail + + for inst in self.driver_inst_list: + load_list = self.load_inst_map[inst] + for pin_name in ["vdd", "gnd"]: + pin = load_list[0].get_pin(pin_name) + self.copy_power_pin(pin, loc=pin.rc() - vector(self.m1_pitch, 0)) + + pin = load_list[-2].get_pin(pin_name) + self.copy_power_pin(pin, loc=pin.rc() - vector(self.m1_pitch, 0)) + + def add_layout_pins(self): + # input is A pin of first inverter + # It gets routed down a bit to prevent overlapping adjacent + # M3 when connecting to vertical bus + a_pin = self.driver_inst_list[0].get_pin("A") + mid_loc = vector(a_pin.cx(), a_pin.cy() - self.m3_pitch) + self.add_via_stack_center(from_layer=a_pin.layer, + to_layer="m3", + offset=mid_loc) + self.add_path("m2", [a_pin.center(), mid_loc]) + + self.add_layout_pin_rect_center(text="in", + layer="m3", + offset=mid_loc) + + for pin_number in self.pinout_list: + # pin is A pin of right-most load/fanout inverter + output_driver_inst = self.driver_inst_list[pin_number - 1] + a_pin = self.load_inst_map[output_driver_inst][-1].get_pin("A") + self.add_via_stack_center(from_layer=a_pin.layer, + to_layer="m3", + offset=a_pin.center()) + self.add_layout_pin_rect_center(text="out{}".format(str(pin_number)), + layer="m3", + offset=a_pin.center()) diff --git a/compiler/modules/port_address.py b/compiler/modules/port_address.py index 1621f7cf..ffe605c7 100644 --- a/compiler/modules/port_address.py +++ b/compiler/modules/port_address.py @@ -18,11 +18,12 @@ class port_address(design): Create the address port (row decoder and wordline driver).. """ - def __init__(self, cols, rows, port, name=""): + def __init__(self, cols, rows, port, has_rbl, name=""): self.num_cols = cols self.num_rows = rows self.port = port + self.has_rbl = has_rbl self.addr_size = ceil(log(self.num_rows, 2)) if name == "": @@ -41,7 +42,8 @@ class port_address(design): self.add_modules() self.create_row_decoder() self.create_wordline_driver() - self.create_rbl_driver() + if self.has_rbl: + self.create_rbl_driver() def create_layout(self): if "li" in layer: @@ -63,7 +65,8 @@ class port_address(design): for bit in range(self.num_rows): self.add_pin("wl_{0}".format(bit), "OUTPUT") - self.add_pin("rbl_wl", "OUTPUT") + if self.has_rbl: + self.add_pin("rbl_wl", "OUTPUT") self.add_pin("vdd", "POWER") self.add_pin("gnd", "GROUND") @@ -76,12 +79,13 @@ class port_address(design): def route_supplies(self): """ Propagate all vdd/gnd pins up to this level for all modules """ - if layer_props.wordline_driver.vertical_supply: - self.copy_layout_pin(self.rbl_driver_inst, "vdd") - else: - rbl_pos = self.rbl_driver_inst.get_pin("vdd").rc() - self.add_power_pin("vdd", rbl_pos) - self.add_path("m4", [rbl_pos, self.wordline_driver_array_inst.get_pins("vdd")[0].rc()]) + if self.has_rbl: + if layer_props.wordline_driver.vertical_supply: + self.copy_layout_pin(self.rbl_driver_inst, "vdd") + else: + rbl_pos = self.rbl_driver_inst.get_pin("vdd").rc() + self.add_power_pin("vdd", rbl_pos) + self.add_path("m4", [rbl_pos, self.wordline_driver_array_inst.get_pins("vdd")[0].rc()]) self.copy_layout_pin(self.wordline_driver_array_inst, "vdd") self.copy_layout_pin(self.wordline_driver_array_inst, "gnd") @@ -90,11 +94,12 @@ class port_address(design): self.copy_layout_pin(self.row_decoder_inst, "gnd") # Also connect the B input of the RBL and_dec to vdd - if OPTS.local_array_size == 0: - rbl_b_pin = self.rbl_driver_inst.get_pin("B") - rbl_loc = rbl_b_pin.center() - vector(3 * self.m1_pitch, 0) - self.add_path(rbl_b_pin.layer, [rbl_b_pin.center(), rbl_loc]) - self.add_power_pin("vdd", rbl_loc, start_layer=rbl_b_pin.layer) + if self.has_rbl: + if OPTS.local_array_size == 0: + rbl_b_pin = self.rbl_driver_inst.get_pin("B") + rbl_loc = rbl_b_pin.center() - vector(3 * self.m1_pitch, 0) + self.add_path(rbl_b_pin.layer, [rbl_b_pin.center(), rbl_loc]) + self.add_power_pin("vdd", rbl_loc, start_layer=rbl_b_pin.layer) def route_pins(self): for row in range(self.addr_size): @@ -105,7 +110,8 @@ class port_address(design): driver_name = "wl_{}".format(row) self.copy_layout_pin(self.wordline_driver_array_inst, driver_name) - self.copy_layout_pin(self.rbl_driver_inst, "Z", "rbl_wl") + if self.has_rbl: + self.copy_layout_pin(self.rbl_driver_inst, "Z", "rbl_wl") def route_internal(self): for row in range(self.num_rows): @@ -130,19 +136,25 @@ class port_address(design): en_pos = en_pin.bc() else: en_pos = en_pin.uc() - rbl_in_pin = self.rbl_driver_inst.get_pin("A") - rbl_in_pos = rbl_in_pin.center() - self.add_via_stack_center(from_layer=rbl_in_pin.layer, - to_layer=en_pin.layer, - offset=rbl_in_pos) - self.add_zjog(layer=en_pin.layer, - start=rbl_in_pos, - end=en_pos, - first_direction="V") + if self.has_rbl: + rbl_in_pin = self.rbl_driver_inst.get_pin("A") + rbl_in_pos = rbl_in_pin.center() + wl_en_offset = rbl_in_pos + + self.add_via_stack_center(from_layer=rbl_in_pin.layer, + to_layer=en_pin.layer, + offset=rbl_in_pos) + self.add_zjog(layer=en_pin.layer, + start=rbl_in_pos, + end=en_pos, + first_direction="V") + else: + wl_en_offset = en_pos + self.add_layout_pin_rect_center(text="wl_en", layer=en_pin.layer, - offset=rbl_in_pos) + offset=wl_en_offset) def add_modules(self): @@ -164,16 +176,17 @@ class port_address(design): # to compensate for the local array inverters b = factory.create(module_type=OPTS.bitcell) - if local_array_size > 0: - # The local wordline driver will change the polarity - self.rbl_driver = factory.create(module_type="inv_dec", - size=driver_size, - height=b.height) - else: - # There is no local wordline driver - self.rbl_driver = factory.create(module_type="and2_dec", - size=driver_size, - height=b.height) + if self.has_rbl: + if local_array_size > 0: + # The local wordline driver will change the polarity + self.rbl_driver = factory.create(module_type="inv_dec", + size=driver_size, + height=b.height) + else: + # There is no local wordline driver + self.rbl_driver = factory.create(module_type="and2_dec", + size=driver_size, + height=b.height) def create_row_decoder(self): """ Create the hierarchical row decoder """ @@ -231,16 +244,17 @@ class port_address(design): wordline_driver_array_offset = vector(self.row_decoder_inst.rx(), 0) self.wordline_driver_array_inst.place(wordline_driver_array_offset) - # This m4_pitch corresponds to the offset space for jog routing in the - # wordline_driver_array - rbl_driver_offset = wordline_driver_array_offset + vector(2 * self.m4_pitch, 0) + if self.has_rbl: + # This m4_pitch corresponds to the offset space for jog routing in the + # wordline_driver_array + rbl_driver_offset = wordline_driver_array_offset + vector(2 * self.m4_pitch, 0) - if self.port == 0: - self.rbl_driver_inst.place(rbl_driver_offset, "MX") - else: - rbl_driver_offset += vector(0, - self.wordline_driver_array.height) - self.rbl_driver_inst.place(rbl_driver_offset) + if self.port == 0: + self.rbl_driver_inst.place(rbl_driver_offset, "MX") + else: + rbl_driver_offset += vector(0, + self.wordline_driver_array.height) + self.rbl_driver_inst.place(rbl_driver_offset) # Pass this up self.predecoder_height = self.row_decoder.predecoder_height diff --git a/compiler/modules/port_data.py b/compiler/modules/port_data.py index 37b6b76d..aef91b7c 100644 --- a/compiler/modules/port_data.py +++ b/compiler/modules/port_data.py @@ -18,13 +18,14 @@ from openram import OPTS class port_data(design): """ Create the data port (column mux, sense amps, write driver, etc.) for the given port number. - Port 0 always has the RBL on the left while port 1 is on the right. + When RBLs present: port 0 always has the RBL on the left while port 1 is on the right. """ - def __init__(self, sram_config, port, num_spare_cols=None, bit_offsets=None, name="",): + def __init__(self, sram_config, port, has_rbl, num_spare_cols=None, bit_offsets=None, name="",): sram_config.set_local_config(self) self.port = port + self.has_rbl = has_rbl if self.write_size != self.word_size: self.num_wmasks = int(math.ceil(self.word_size / self.write_size)) else: @@ -115,8 +116,9 @@ class port_data(design): def add_pins(self): """ Adding pins for port data module""" - self.add_pin("rbl_bl", "INOUT") - self.add_pin("rbl_br", "INOUT") + if self.has_rbl: + self.add_pin("rbl_bl", "INOUT") + self.add_pin("rbl_br", "INOUT") for bit in range(self.num_cols): self.add_pin("bl_{0}".format(bit), "INOUT") self.add_pin("br_{0}".format(bit), "INOUT") @@ -202,15 +204,19 @@ class port_data(design): precharge_width = cell.width + strap.width else: precharge_width = cell.width - if self.port == 0: - # Append an offset on the left - precharge_bit_offsets = [self.bit_offsets[0] - precharge_width] + self.bit_offsets + if self.has_rbl: + if self.port == 0: + # Append an offset on the left + precharge_bit_offsets = [self.bit_offsets[0] - precharge_width] + self.bit_offsets + else: + # Append an offset on the right + precharge_bit_offsets = self.bit_offsets + [self.bit_offsets[-1] + precharge_width] else: - # Append an offset on the right - precharge_bit_offsets = self.bit_offsets + [self.bit_offsets[-1] + precharge_width] + precharge_bit_offsets = self.bit_offsets + # has_rbl is a boolean treated as 1 if true 0 if false typical python self.precharge_array = factory.create(module_type="precharge_array", - columns=self.num_cols + self.num_spare_cols + 1, + columns=self.num_cols + self.num_spare_cols + self.has_rbl, offsets=precharge_bit_offsets, bitcell_bl=self.bl_names[self.port], bitcell_br=self.br_names[self.port], @@ -294,7 +300,7 @@ class port_data(design): mod=self.precharge_array) temp = [] # Use left BLs for RBL - if self.port==0: + if self.port==0 and self.has_rbl: temp.append("rbl_bl") temp.append("rbl_br") for bit in range(self.num_cols): @@ -306,7 +312,7 @@ class port_data(design): temp.append("sparebr_{0}".format(bit)) # Use right BLs for RBL - if self.port==1: + if self.port==1 and self.has_rbl: temp.append("rbl_bl") temp.append("rbl_br") temp.extend(["p_en_bar", "vdd"]) @@ -537,7 +543,7 @@ class port_data(design): if self.col_addr_size==0: return - start_bit = 1 if self.port == 0 else 0 + start_bit = 1 if self.port == 0 and self.has_rbl else 0 self.connect_bitlines(inst1=self.column_mux_array_inst, inst2=self.precharge_array_inst, @@ -558,7 +564,7 @@ class port_data(design): inst1 = self.precharge_array_inst inst1_bls_templ="{inst}_{bit}" - if self.port==0: + if self.port==0 and self.has_rbl: start_bit=1 else: start_bit=0 @@ -683,11 +689,11 @@ class port_data(design): """ Add the bitline pins for the given port """ # Connect one bitline to the RBL and offset the indices for the other BLs - if self.port==0: + if self.port==0 and self.has_rbl: self.copy_layout_pin(self.precharge_array_inst, "bl_0", "rbl_bl") self.copy_layout_pin(self.precharge_array_inst, "br_0", "rbl_br") bit_offset=1 - elif self.port==1: + elif self.port==1 and self.has_rbl: self.copy_layout_pin(self.precharge_array_inst, "bl_{}".format(self.num_cols + self.num_spare_cols), "rbl_bl") self.copy_layout_pin(self.precharge_array_inst, "br_{}".format(self.num_cols + self.num_spare_cols), "rbl_br") bit_offset=0 diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index 87a96827..b3661aff 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -16,11 +16,11 @@ from .bitcell_base_array import bitcell_base_array class replica_bitcell_array(bitcell_base_array): """ Creates a bitcell array of cols x rows and then adds the replica - and dummy columns and rows. Replica columns are on the left and + columns and dummy rows. Replica columns are on the left and right, respectively and connected to the given bitcell ports. - Dummy are the outside columns/rows with WL and BL tied to gnd. - Requires a regular bitcell array, replica bitcell, and dummy - bitcell (BL/BR disconnected). + Dummy rows are on the top and bottom passing through the RBL WLs. + Requires a regular bitcell array and (if using replica topology) + replica bitcell and dummy bitcell (BL/BR disconnected). """ def __init__(self, rows, cols, rbl=None, left_rbl=None, right_rbl=None, name=""): super().__init__(name=name, rows=rows, cols=cols, column_offset=0) @@ -36,22 +36,29 @@ class replica_bitcell_array(bitcell_base_array): self.column_size = cols self.row_size = rows # This is how many RBLs are in all the arrays - self.rbl = rbl - # This specifies which RBL to put on the left or right by port number - # This could be an empty list + # Even if the RBL is not placed in this array, the module still needs + # to place dummy rows with rbl wordlines so that they will have the same + # load as the regular wordlines (and so the arrays are the same size) + if rbl is not None: + self.rbl = rbl + else: + self.rbl = [0] * len(self.all_ports) + # This specifies how many RBLs to put on the left by port number. + # For example, left_rbl = [0, 1] means there will be two + # RBLs on the left, one for port 0 and another for port 1. if left_rbl is not None: self.left_rbl = left_rbl else: self.left_rbl = [] - # This could be an empty list + # Similar to left_rbl but on the right side of the array if right_rbl is not None: self.right_rbl = right_rbl else: - self.right_rbl=[] + self.right_rbl = [] self.rbls = self.left_rbl + self.right_rbl debug.check(sum(self.rbl) >= len(self.left_rbl) + len(self.right_rbl), - "Invalid number of RBLs for port configuration.") + "Cannot have more left + right RBLs than total RBLs") self.create_netlist() if not OPTS.netlist_only: @@ -64,28 +71,7 @@ class replica_bitcell_array(bitcell_base_array): self.create_instances() def add_modules(self): - """ Array and dummy/replica columns - - d or D = dummy cell (caps to distinguish grouping) - r or R = replica cell (caps to distinguish grouping) - b or B = bitcell - replica columns 1 - v v - bdDDDDDDDDDDDDDDdb <- Dummy row - bdDDDDDDDDDDDDDDrb <- Dummy row - br--------------rb - br| Array |rb - br| row x col |rb - br--------------rb - brDDDDDDDDDDDDDDdb <- Dummy row - bdDDDDDDDDDDDDDDdb <- Dummy row - - ^^^^^^^^^^^^^^^ - dummy rows cols x 1 - - ^ dummy columns ^ - 1 x (rows + 4) - """ + """ Array and dummy/replica columns """ # Bitcell array self.bitcell_array = factory.create(module_type="bitcell_array", column_offset=1 + len(self.left_rbl), @@ -96,18 +82,14 @@ class replica_bitcell_array(bitcell_base_array): self.replica_columns = {} for port in self.all_ports: + # We will always have self.rbl[0] dummy rows below the array + # for the replica wordlines. if port in self.left_rbl: - # We will always have self.rbl[0] rows of replica wordlines below - # the array. - # These go from the top (where the bitcell array starts ) down + # These go top down starting from the bottom of the bitcell array. replica_bit = self.rbl[0] - port - 1 column_offset = len(self.left_rbl) - elif port in self.right_rbl: - - # We will always have self.rbl[0] rows of replica wordlines below - # the array. - # These go from the bottom up + # These go bottom up starting from the top of the bitcell array. replica_bit = self.rbl[0] + self.row_size + port - 1 column_offset = len(self.left_rbl) + self.column_size + 1 else: @@ -119,11 +101,13 @@ class replica_bitcell_array(bitcell_base_array): column_offset=column_offset, replica_bit=replica_bit) - # Dummy row + # Dummy row (for replica wordlines) self.dummy_row = factory.create(module_type="dummy_array", cols=self.column_size, rows=1, - # dummy column + left replica column + # cap column + left replica column + # FIXME: these col offsets should really start at 0 because + # this is the left edge of the array... but changing them all is work column_offset=1 + len(self.left_rbl), mirror=0) @@ -148,7 +132,7 @@ class replica_bitcell_array(bitcell_base_array): self.add_pin("gnd", "GROUND") def add_bitline_pins(self): - # The bit is which port the RBL is for + # The bit represents which port the RBL is for for bit in self.rbls: for port in self.all_ports: self.rbl_bitline_names[bit].append("rbl_bl_{0}_{1}".format(port, bit)) @@ -175,6 +159,8 @@ class replica_bitcell_array(bitcell_base_array): self.unused_wordline_names = [] for port in self.all_ports: + if self.rbl[port] == 0: + continue # TODO: there's probably a better way to do this check for bit in self.all_ports: self.rbl_wordline_names[port].append("rbl_wl_{0}_{1}".format(port, bit)) if bit != port: @@ -225,9 +211,12 @@ class replica_bitcell_array(bitcell_base_array): self.dummy_row_replica_insts = [] # Note, this is the number of left and right even if we aren't adding the columns to this bitcell array! for port in self.all_ports: # TODO: tie to self.rbl or whatever - self.dummy_row_replica_insts.append(self.add_inst(name="dummy_row_{}".format(port), - mod=self.dummy_row)) - self.connect_inst(self.all_bitline_names + self.rbl_wordline_names[port] + self.supplies) + if self.rbl[port] != 0: + self.dummy_row_replica_insts.append(self.add_inst(name="dummy_row_{}".format(port), + mod=self.dummy_row)) + self.connect_inst(self.all_bitline_names + self.rbl_wordline_names[port] + self.supplies) + else: + self.dummy_row_replica_insts.append(None) def create_layout(self): @@ -249,8 +238,8 @@ class replica_bitcell_array(bitcell_base_array): # Array was at (0, 0) but move everything so it is at the lower left # We move DOWN the number of left RBL even if we didn't add the column to this bitcell array # Note that this doesn't include the row/col cap - array_offset = self.bitcell_offset.scale(len(self.left_rbl), self.rbl[0]) - self.translate_all(array_offset.scale(-1, -1)) + array_offset = self.bitcell_offset.scale(-len(self.left_rbl), -self.rbl[0]) + self.translate_all(array_offset) self.add_layout_pins() @@ -359,7 +348,7 @@ class replica_bitcell_array(bitcell_base_array): height=self.height) def route_supplies(self): - + """ just copy supply pins from all instances """ for inst in self.insts: for pin_name in ["vdd", "gnd"]: self.copy_layout_pin(inst, pin_name) diff --git a/compiler/modules/rom_bank.py b/compiler/modules/rom_bank.py index f4940338..e4d22f1c 100644 --- a/compiler/modules/rom_bank.py +++ b/compiler/modules/rom_bank.py @@ -10,13 +10,14 @@ import datetime from math import ceil, log from openram.base import vector from openram.base import design +from openram.base import rom_verilog from openram import OPTS, print_time from openram.sram_factory import factory from openram.tech import drc, layer, parameter from openram.router import router_tech -class rom_bank(design): +class rom_bank(design,rom_verilog): """ Rom data bank with row and column decoder + control logic @@ -509,4 +510,4 @@ class rom_bank(design): rtr=router(layers=self.m3_stack, design=self, bbox=bbox) - rtr.escape_route(pins_to_route) \ No newline at end of file + rtr.escape_route(pins_to_route) diff --git a/compiler/modules/sram_1bank.py b/compiler/modules/sram_1bank.py index 8cc7cd8c..89d7a058 100644 --- a/compiler/modules/sram_1bank.py +++ b/compiler/modules/sram_1bank.py @@ -28,7 +28,6 @@ class sram_1bank(design, verilog, lef): design.__init__(self, name) lef.__init__(self, ["m1", "m2", "m3", "m4"]) verilog.__init__(self) - self.sram_config = sram_config sram_config.set_local_config(self) @@ -50,6 +49,9 @@ class sram_1bank(design, verilog, lef): # Route a M3/M4 grid self.supply_stack = self.m3_stack + # delay control logic does not have RBLs + self.has_rbl = OPTS.control_logic != "control_logic_delay" + def add_pins(self): """ Add pins for entire SRAM. """ @@ -517,8 +519,9 @@ class sram_1bank(design, verilog, lef): for port in self.read_ports: for bit in range(self.word_size + self.num_spare_cols): temp.append("dout{0}[{1}]".format(port, bit)) - for port in self.all_ports: - temp.append("rbl_bl{0}".format(port)) + if self.has_rbl: + for port in self.all_ports: + temp.append("rbl_bl{0}".format(port)) for port in self.write_ports: for bit in range(self.word_size + self.num_spare_cols): temp.append("bank_din{0}_{1}".format(port, bit)) @@ -693,7 +696,8 @@ class sram_1bank(design, verilog, lef): if port in self.readwrite_ports: temp.append("web{}".format(port)) temp.append("clk{}".format(port)) - temp.append("rbl_bl{}".format(port)) + if self.has_rbl: + temp.append("rbl_bl{}".format(port)) # Outputs if port in self.read_ports: @@ -1292,18 +1296,19 @@ class sram_1bank(design, verilog, lef): dest_pin = self.bank_inst.get_pin(signal + "{}".format(port)) self.connect_vbus(src_pin, dest_pin) - for port in self.all_ports: - # Only input (besides pins) is the replica bitline - src_pin = self.control_logic_insts[port].get_pin("rbl_bl") - dest_pin = self.bank_inst.get_pin("rbl_bl_{0}_{0}".format(port)) - self.add_wire(self.m3_stack, - [src_pin.center(), vector(src_pin.cx(), dest_pin.cy()), dest_pin.rc()]) - self.add_via_stack_center(from_layer=src_pin.layer, - to_layer="m4", - offset=src_pin.center()) - self.add_via_stack_center(from_layer=dest_pin.layer, - to_layer="m3", - offset=dest_pin.center()) + if self.has_rbl: + for port in self.all_ports: + # Only input (besides pins) is the replica bitline + src_pin = self.control_logic_insts[port].get_pin("rbl_bl") + dest_pin = self.bank_inst.get_pin("rbl_bl_{0}_{0}".format(port)) + self.add_wire(self.m3_stack, + [src_pin.center(), vector(src_pin.cx(), dest_pin.cy()), dest_pin.rc()]) + self.add_via_stack_center(from_layer=src_pin.layer, + to_layer="m4", + offset=src_pin.center()) + self.add_via_stack_center(from_layer=dest_pin.layer, + to_layer="m3", + offset=dest_pin.center()) def route_row_addr_dff(self): """ diff --git a/compiler/options.py b/compiler/options.py index 56526a32..4a5f7dde 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -58,6 +58,7 @@ class options(optparse.Values): ################### rom_endian = "little" rom_data = None + data_type = "bin" strap_spacing = 8 scramble_bits = True @@ -67,9 +68,13 @@ class options(optparse.Values): # Approximate percentage of delay compared to bitlines rbl_delay_percentage = 0.5 - # Allow manual adjustment of the delay chain over automatic - auto_delay_chain_sizing = False + # delay chain is automatically sized in delay based control logic + # this multiplier can be used to add a guard band to the standard timing + # lowering it can improve performance but may cause sram to fail + delay_control_scaling_factor = 1.0 + # stages for delay chain in rbl control logic only delay_chain_stages = 9 + # fanout per stage for any control logic delay_chain_fanout_per_stage = 4 accuracy_requirement = 0.75 diff --git a/compiler/rom.py b/compiler/rom.py index b4f41889..b997f088 100644 --- a/compiler/rom.py +++ b/compiler/rom.py @@ -26,7 +26,8 @@ class rom(): words_per_row=OPTS.words_per_row, rom_endian=OPTS.rom_endian, scramble_bits=OPTS.scramble_bits, - strap_spacing=OPTS.strap_spacing) + strap_spacing=OPTS.strap_spacing, + data_type=OPTS.data_type) if name is None: name = OPTS.output_name @@ -38,7 +39,7 @@ class rom(): from openram.base import design design.name_map=[] - debug.info(2, "create rom of size {0} with {1} num of words".format(self.word_size, + debug.print_raw("create rom of word size {0} with {1} num of words".format(self.word_size, self.num_words)) start_time = datetime.datetime.now() @@ -137,20 +138,22 @@ class rom(): # Write the config file + # Should also save the provided data file start_time = datetime.datetime.now() from shutil import copyfile copyfile(OPTS.config_file, OPTS.output_path + OPTS.output_name + '.py') + copyfile(self.rom_data, OPTS.output_path + self.rom_data) debug.print_raw("Config: Writing to {0}".format(OPTS.output_path + OPTS.output_name + '.py')) print_time("Config", datetime.datetime.now(), start_time) # TODO: Write the datasheet - # TODO: Write a verilog model - # start_time = datetime.datetime.now() - # vname = OPTS.output_path + self.r.name + '.v' - # debug.print_raw("Verilog: Writing to {0}".format(vname)) - # self.verilog_write(vname) - # print_time("Verilog", datetime.datetime.now(), start_time) + #Write a verilog model + start_time = datetime.datetime.now() + vname = OPTS.output_path + self.r.name + '.v' + debug.print_raw("Verilog: Writing to {0}".format(vname)) + self.verilog_write(vname) + print_time("Verilog", datetime.datetime.now(), start_time) # Write out options if specified if OPTS.output_extended_config: diff --git a/compiler/rom_config.py b/compiler/rom_config.py index 9e67e37a..eba190fd 100644 --- a/compiler/rom_config.py +++ b/compiler/rom_config.py @@ -16,14 +16,14 @@ from openram import OPTS class rom_config: """ This is a structure that is used to hold the ROM configuration options. """ - def __init__(self, word_size, rom_data, words_per_row=None, rom_endian="little", scramble_bits=True, strap_spacing=8): + def __init__(self, word_size, rom_data, words_per_row=None, rom_endian="little", scramble_bits=True, strap_spacing=8, data_type="hex"): self.word_size = word_size self.word_bits = self.word_size * 8 self.rom_data = rom_data self.strap_spacing = strap_spacing # TODO: This currently does nothing. It should change the behavior of the chunk funciton. self.endian = rom_endian - + self.data_type = data_type # This should pretty much always be true. If you want to make silicon art you might set to false self.scramble_bits = scramble_bits # This will get over-written when we determine the organization @@ -57,18 +57,12 @@ class rom_config: def compute_sizes(self): """ Computes the organization of the memory using data size by trying to make it a rectangle.""" - # Read data as hexidecimal text file - hex_file = open(self.rom_data, 'r') - hex_data = hex_file.read() - - # Convert from hex into an int - data_int = int(hex_data, 16) - # Then from int into a right aligned, zero padded string - bin_string = bin(data_int)[2:].zfill(len(hex_data) * 4) - - # Then turn the string into a list of ints - bin_data = list(bin_string) - raw_data = [int(x) for x in bin_data] + if self.data_type == "hex": + raw_data = self.read_data_hex() + elif self.data_type == "bin": + raw_data = self.read_data_bin() + else: + debug.error(f"Invalid input data type: {self.data_type}", -1) # data size in bytes data_size = len(raw_data) / 8 @@ -93,6 +87,35 @@ class rom_config: OPTS.words_per_row = self.words_per_row debug.info(1, "Read rom data file: length {0} bytes, {1} words, set number of cols to {2}, rows to {3}, with {4} words per row".format(data_size, self.num_words, self.cols, self.rows, self.words_per_row)) + def read_data_hex(self) -> List[int]: + # Read data as hexidecimal text file + with open(self.rom_data, 'r') as hex_file: + hex_data = hex_file.read() + + # Convert from hex into an int + data_int = int(hex_data, 16) + # Then from int into a right aligned, zero padded string + bin_string = bin(data_int)[2:].zfill(len(hex_data) * 4) + + # Then turn the string into a list of ints + bin_data = list(bin_string) + raw_data = [int(x) for x in bin_data] + return raw_data + + def read_data_bin(self) -> List[int]: + + # Read data as a binary file + with open(self.rom_data, 'rb') as bin_file: + bin_data = bin_file.read() + + # Convert from a list of bytes to a single string of bits + bin_string = "".join(f"{n:08b}" for n in bin_data) + + # Then turn the string into a list of ints + bin_data = list(bin_string) + raw_data = [int(x) for x in bin_data] + return raw_data + def chunk_data(self, raw_data: List[int]): """ diff --git a/compiler/tests/14_capped_replica_bitcell_array_bothrbl_1rw_1r_test.py b/compiler/tests/14_capped_replica_bitcell_array_bothrbl_1rw_1r_test.py index a2f57e45..2237a21f 100755 --- a/compiler/tests/14_capped_replica_bitcell_array_bothrbl_1rw_1r_test.py +++ b/compiler/tests/14_capped_replica_bitcell_array_bothrbl_1rw_1r_test.py @@ -14,7 +14,7 @@ from openram.sram_factory import factory from openram import OPTS -class capped_replica_bitcell_array_1rw_1r_test(openram_test): +class capped_replica_bitcell_array_bothrbl_1rw_1r_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) @@ -25,13 +25,8 @@ class capped_replica_bitcell_array_1rw_1r_test(openram_test): OPTS.num_w_ports = 0 openram.setup_bitcell() - debug.info(2, "Testing 4x4 array left and right replica for dp cell") - a = factory.create(module_type="capped_replica_bitcell_array", - cols=4, - rows=4, - rbl=[1, 1], - left_rbl=[0], - right_rbl=[1]) + debug.info(2, "Testing 4x4 capped replica array for 1rw1r cell with both replica columns") + a = factory.create(module_type="capped_replica_bitcell_array", cols=4, rows=4, rbl=[1, 1], left_rbl=[0], right_rbl=[1]) self.local_check(a) openram.end_openram() diff --git a/compiler/tests/14_capped_replica_bitcell_array_dummies_1rw_1r_test.py b/compiler/tests/14_capped_replica_bitcell_array_dummies_1rw_1r_test.py new file mode 100755 index 00000000..f361b4af --- /dev/null +++ b/compiler/tests/14_capped_replica_bitcell_array_dummies_1rw_1r_test.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz +# All rights reserved. +# +import sys, os +import unittest +from testutils import * + +import openram +from openram import debug +from openram.sram_factory import factory +from openram import OPTS + + +class capped_replica_bitcell_array_dummies_1rw_1r_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + openram.init_openram(config_file, is_unit_test=True) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + openram.setup_bitcell() + + debug.info(2, "Testing 4x4 capped replica array for 1rw1r cell with dummy rows only") + a = factory.create(module_type="capped_replica_bitcell_array", cols=4, rows=4, rbl=[1, 1]) + self.local_check(a) + + openram.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/14_capped_replica_bitcell_array_dummies_1rw_test.py b/compiler/tests/14_capped_replica_bitcell_array_dummies_1rw_test.py new file mode 100755 index 00000000..c0ff770f --- /dev/null +++ b/compiler/tests/14_capped_replica_bitcell_array_dummies_1rw_test.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz +# All rights reserved. +# +import sys, os +import unittest +from testutils import * + +import openram +from openram import debug +from openram.sram_factory import factory +from openram import OPTS + + +class capped_replica_bitcell_array_dummies_1rw_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + openram.init_openram(config_file, is_unit_test=True) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 0 + OPTS.num_w_ports = 0 + openram.setup_bitcell() + + debug.info(2, "Testing 7x5 capped replica array for 1rw cell with dummy row only") + a = factory.create(module_type="capped_replica_bitcell_array", cols=7, rows=5, rbl=[1, 0]) + self.local_check(a) + + openram.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/14_capped_replica_bitcell_array_leftrbl_1rw_1r_test.py b/compiler/tests/14_capped_replica_bitcell_array_leftrbl_1rw_1r_test.py index 3e1bd805..53b4231b 100755 --- a/compiler/tests/14_capped_replica_bitcell_array_leftrbl_1rw_1r_test.py +++ b/compiler/tests/14_capped_replica_bitcell_array_leftrbl_1rw_1r_test.py @@ -14,7 +14,7 @@ from openram.sram_factory import factory from openram import OPTS -class capped_replica_bitcell_array_1rw_1r_test(openram_test): +class capped_replica_bitcell_array_leftrbl_1rw_1r_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) @@ -25,16 +25,13 @@ class capped_replica_bitcell_array_1rw_1r_test(openram_test): OPTS.num_w_ports = 0 openram.setup_bitcell() - debug.info(2, "Testing 4x4 left replica array for dp cell") - a = factory.create(module_type="capped_replica_bitcell_array", - cols=4, - rows=4, - rbl=[1, 1], - left_rbl=[0]) + debug.info(2, "Testing 4x4 capped replica array for 1rw1r cell with left replica column") + a = factory.create(module_type="capped_replica_bitcell_array", cols=4, rows=4, rbl=[1, 1], left_rbl=[0]) self.local_check(a) openram.end_openram() + # run the test from the command line if __name__ == "__main__": (OPTS, args) = openram.parse_args() diff --git a/compiler/tests/14_capped_replica_bitcell_array_leftrbl_1rw_test.py b/compiler/tests/14_capped_replica_bitcell_array_leftrbl_1rw_test.py index 61464b9b..7ed5fdf9 100755 --- a/compiler/tests/14_capped_replica_bitcell_array_leftrbl_1rw_test.py +++ b/compiler/tests/14_capped_replica_bitcell_array_leftrbl_1rw_test.py @@ -14,7 +14,7 @@ from openram.sram_factory import factory from openram import OPTS -class capped_replica_bitcell_array_test(openram_test): +class capped_replica_bitcell_array_leftrbl_1rw_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) @@ -23,8 +23,9 @@ class capped_replica_bitcell_array_test(openram_test): OPTS.num_rw_ports = 1 OPTS.num_r_ports = 0 OPTS.num_w_ports = 0 + openram.setup_bitcell() - debug.info(2, "Testing 4x4 array for bitcell") + debug.info(2, "Testing 7x5 capped replica array for 1rw cell with left replica column") a = factory.create(module_type="capped_replica_bitcell_array", cols=7, rows=5, rbl=[1, 0], left_rbl=[0]) self.local_check(a) diff --git a/compiler/tests/14_capped_replica_bitcell_array_norbl_1rw_1r_test.py b/compiler/tests/14_capped_replica_bitcell_array_norbl_1rw_1r_test.py index bc432c6b..c1ea6516 100755 --- a/compiler/tests/14_capped_replica_bitcell_array_norbl_1rw_1r_test.py +++ b/compiler/tests/14_capped_replica_bitcell_array_norbl_1rw_1r_test.py @@ -14,7 +14,7 @@ from openram.sram_factory import factory from openram import OPTS -class capped_replica_bitcell_array_1rw_1r_test(openram_test): +class capped_replica_bitcell_array_norbl_1rw_1r_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) @@ -25,11 +25,8 @@ class capped_replica_bitcell_array_1rw_1r_test(openram_test): OPTS.num_w_ports = 0 openram.setup_bitcell() - debug.info(2, "Testing 4x4 non-replica array for dp cell") - a = factory.create(module_type="capped_replica_bitcell_array", - cols=4, - rows=4, - rbl=[1, 1]) + debug.info(2, "Testing 4x4 capped replica array for 1rw1r cell without replica columns or dummy rows") + a = factory.create(module_type="capped_replica_bitcell_array", cols=4, rows=4, rbl=[0, 0]) self.local_check(a) openram.end_openram() diff --git a/compiler/tests/14_capped_replica_bitcell_array_norbl_1rw_test.py b/compiler/tests/14_capped_replica_bitcell_array_norbl_1rw_test.py index 070404ac..56080536 100755 --- a/compiler/tests/14_capped_replica_bitcell_array_norbl_1rw_test.py +++ b/compiler/tests/14_capped_replica_bitcell_array_norbl_1rw_test.py @@ -14,7 +14,7 @@ from openram.sram_factory import factory from openram import OPTS -class capped_replica_bitcell_array_test(openram_test): +class capped_replica_bitcell_array_norbl_1rw_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) @@ -23,9 +23,10 @@ class capped_replica_bitcell_array_test(openram_test): OPTS.num_rw_ports = 1 OPTS.num_r_ports = 0 OPTS.num_w_ports = 0 + openram.setup_bitcell() - debug.info(2, "Testing 4x4 array for bitcell") - a = factory.create(module_type="capped_replica_bitcell_array", cols=7, rows=5, rbl=[1, 0]) + debug.info(2, "Testing 7x5 capped replica array for 1rw cell without replica column or dummy row") + a = factory.create(module_type="capped_replica_bitcell_array", cols=7, rows=5, rbl=[0, 0]) self.local_check(a) openram.end_openram() diff --git a/compiler/tests/14_capped_replica_bitcell_array_rightrbl_1rw_1r_test.py b/compiler/tests/14_capped_replica_bitcell_array_rightrbl_1rw_1r_test.py index deac7075..c8d322c4 100755 --- a/compiler/tests/14_capped_replica_bitcell_array_rightrbl_1rw_1r_test.py +++ b/compiler/tests/14_capped_replica_bitcell_array_rightrbl_1rw_1r_test.py @@ -14,7 +14,7 @@ from openram.sram_factory import factory from openram import OPTS -class capped_replica_bitcell_array_1rw_1r_test(openram_test): +class capped_replica_bitcell_array_rightrbl_1rw_1r_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) @@ -25,16 +25,13 @@ class capped_replica_bitcell_array_1rw_1r_test(openram_test): OPTS.num_w_ports = 0 openram.setup_bitcell() - debug.info(2, "Testing 4x4 left replica array for dp cell") - a = factory.create(module_type="capped_replica_bitcell_array", - cols=4, - rows=4, - rbl=[1, 1], - right_rbl=[1]) + debug.info(2, "Testing 4x4 capped replica array for 1rw1r cell with right replica column") + a = factory.create(module_type="capped_replica_bitcell_array", cols=4, rows=4, rbl=[1, 1], right_rbl=[1]) self.local_check(a) openram.end_openram() + # run the test from the command line if __name__ == "__main__": (OPTS, args) = openram.parse_args() diff --git a/compiler/tests/14_replica_bitcell_array_bothrbl_1rw_1r_test.py b/compiler/tests/14_replica_bitcell_array_bothrbl_1rw_1r_test.py index d6e075a4..504e0390 100755 --- a/compiler/tests/14_replica_bitcell_array_bothrbl_1rw_1r_test.py +++ b/compiler/tests/14_replica_bitcell_array_bothrbl_1rw_1r_test.py @@ -14,7 +14,7 @@ from openram.sram_factory import factory from openram import OPTS -class replica_bitcell_array_1rw_1r_test(openram_test): +class replica_bitcell_array_bothrbl_1rw_1r_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) @@ -25,13 +25,8 @@ class replica_bitcell_array_1rw_1r_test(openram_test): OPTS.num_w_ports = 0 openram.setup_bitcell() - debug.info(2, "Testing 4x4 array left and right replica for dp cell") - a = factory.create(module_type="replica_bitcell_array", - cols=4, - rows=4, - rbl=[1, 1], - left_rbl=[0], - right_rbl=[1]) + debug.info(2, "Testing 4x4 replica array for 1rw1r cell with both replica columns") + a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, rbl=[1, 1], left_rbl=[0], right_rbl=[1]) self.local_check(a) openram.end_openram() diff --git a/compiler/tests/14_replica_bitcell_array_dummies_1rw_1r_test.py b/compiler/tests/14_replica_bitcell_array_dummies_1rw_1r_test.py new file mode 100755 index 00000000..13e0169a --- /dev/null +++ b/compiler/tests/14_replica_bitcell_array_dummies_1rw_1r_test.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz +# All rights reserved. +# +import sys, os +import unittest +from testutils import * + +import openram +from openram import debug +from openram.sram_factory import factory +from openram import OPTS + + +class replica_bitcell_array_dummies_1rw_1r_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + openram.init_openram(config_file, is_unit_test=True) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + openram.setup_bitcell() + + debug.info(2, "Testing 4x4 replica array for 1rw1r cell with dummy rows only") + a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, rbl=[1, 1]) + self.local_check(a) + + openram.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/14_replica_bitcell_array_dummies_1rw_test.py b/compiler/tests/14_replica_bitcell_array_dummies_1rw_test.py new file mode 100755 index 00000000..f5a2a3e1 --- /dev/null +++ b/compiler/tests/14_replica_bitcell_array_dummies_1rw_test.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz +# All rights reserved. +# +import sys, os +import unittest +from testutils import * + +import openram +from openram import debug +from openram.sram_factory import factory +from openram import OPTS + + +class replica_bitcell_array_dummies_1rw_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + openram.init_openram(config_file, is_unit_test=True) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 0 + OPTS.num_w_ports = 0 + openram.setup_bitcell() + + debug.info(2, "Testing 7x5 replica array for 1rw cell with dummy row only") + a = factory.create(module_type="replica_bitcell_array", cols=7, rows=5, rbl=[1, 0]) + self.local_check(a) + + openram.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/14_replica_bitcell_array_leftrbl_1rw_1r_test.py b/compiler/tests/14_replica_bitcell_array_leftrbl_1rw_1r_test.py index 36254cb5..8f091ada 100755 --- a/compiler/tests/14_replica_bitcell_array_leftrbl_1rw_1r_test.py +++ b/compiler/tests/14_replica_bitcell_array_leftrbl_1rw_1r_test.py @@ -14,7 +14,7 @@ from openram.sram_factory import factory from openram import OPTS -class replica_bitcell_array_1rw_1r_test(openram_test): +class replica_bitcell_array_leftrbl_1rw_1r_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) @@ -25,16 +25,13 @@ class replica_bitcell_array_1rw_1r_test(openram_test): OPTS.num_w_ports = 0 openram.setup_bitcell() - debug.info(2, "Testing 4x4 left replica array for dp cell") - a = factory.create(module_type="replica_bitcell_array", - cols=4, - rows=4, - rbl=[1, 1], - left_rbl=[0]) + debug.info(2, "Testing 4x4 replica array for 1rw1r cell with left replica column") + a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, rbl=[1, 1], left_rbl=[0]) self.local_check(a) openram.end_openram() + # run the test from the command line if __name__ == "__main__": (OPTS, args) = openram.parse_args() diff --git a/compiler/tests/14_replica_bitcell_array_leftrbl_1rw_test.py b/compiler/tests/14_replica_bitcell_array_leftrbl_1rw_test.py index b8d5e5ed..1a4944bf 100755 --- a/compiler/tests/14_replica_bitcell_array_leftrbl_1rw_test.py +++ b/compiler/tests/14_replica_bitcell_array_leftrbl_1rw_test.py @@ -14,7 +14,7 @@ from openram.sram_factory import factory from openram import OPTS -class replica_bitcell_array_test(openram_test): +class replica_bitcell_array_leftrbl_1rw_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) @@ -23,8 +23,9 @@ class replica_bitcell_array_test(openram_test): OPTS.num_rw_ports = 1 OPTS.num_r_ports = 0 OPTS.num_w_ports = 0 + openram.setup_bitcell() - debug.info(2, "Testing 4x4 array for bitcell") + debug.info(2, "Testing 7x5 replica array for 1rw cell with left replica column") a = factory.create(module_type="replica_bitcell_array", cols=7, rows=5, rbl=[1, 0], left_rbl=[0]) self.local_check(a) diff --git a/compiler/tests/14_replica_bitcell_array_norbl_1rw_1r_test.py b/compiler/tests/14_replica_bitcell_array_norbl_1rw_1r_test.py index ebdc9584..d2869183 100755 --- a/compiler/tests/14_replica_bitcell_array_norbl_1rw_1r_test.py +++ b/compiler/tests/14_replica_bitcell_array_norbl_1rw_1r_test.py @@ -14,7 +14,7 @@ from openram.sram_factory import factory from openram import OPTS -class replica_bitcell_array_1rw_1r_test(openram_test): +class replica_bitcell_array_norbl_1rw_1r_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) @@ -25,11 +25,8 @@ class replica_bitcell_array_1rw_1r_test(openram_test): OPTS.num_w_ports = 0 openram.setup_bitcell() - debug.info(2, "Testing 4x4 non-replica array for dp cell") - a = factory.create(module_type="replica_bitcell_array", - cols=4, - rows=4, - rbl=[1, 1]) + debug.info(2, "Testing 4x4 replica array for 1rw1r cell without replica columns or dummy rows") + a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, rbl=[0, 0]) self.local_check(a) openram.end_openram() diff --git a/compiler/tests/14_replica_bitcell_array_norbl_1rw_test.py b/compiler/tests/14_replica_bitcell_array_norbl_1rw_test.py index 219bd680..be19330f 100755 --- a/compiler/tests/14_replica_bitcell_array_norbl_1rw_test.py +++ b/compiler/tests/14_replica_bitcell_array_norbl_1rw_test.py @@ -14,7 +14,7 @@ from openram.sram_factory import factory from openram import OPTS -class replica_bitcell_array_test(openram_test): +class replica_bitcell_array_norbl_1rw_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) @@ -23,9 +23,10 @@ class replica_bitcell_array_test(openram_test): OPTS.num_rw_ports = 1 OPTS.num_r_ports = 0 OPTS.num_w_ports = 0 + openram.setup_bitcell() - debug.info(2, "Testing 4x4 array for bitcell") - a = factory.create(module_type="replica_bitcell_array", cols=7, rows=5, rbl=[1, 0]) + debug.info(2, "Testing 7x5 replica array for 1rw cell without replica column or dummy row") + a = factory.create(module_type="replica_bitcell_array", cols=7, rows=5, rbl=[0, 0]) self.local_check(a) openram.end_openram() diff --git a/compiler/tests/14_replica_bitcell_array_rightrbl_1rw_1r_test.py b/compiler/tests/14_replica_bitcell_array_rightrbl_1rw_1r_test.py index 8d1d8f23..6d3a73c5 100755 --- a/compiler/tests/14_replica_bitcell_array_rightrbl_1rw_1r_test.py +++ b/compiler/tests/14_replica_bitcell_array_rightrbl_1rw_1r_test.py @@ -14,7 +14,7 @@ from openram.sram_factory import factory from openram import OPTS -class replica_bitcell_array_1rw_1r_test(openram_test): +class replica_bitcell_array_rightrbl_1rw_1r_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) @@ -25,16 +25,13 @@ class replica_bitcell_array_1rw_1r_test(openram_test): OPTS.num_w_ports = 0 openram.setup_bitcell() - debug.info(2, "Testing 4x4 left replica array for dp cell") - a = factory.create(module_type="replica_bitcell_array", - cols=4, - rows=4, - rbl=[1, 1], - right_rbl=[1]) + debug.info(2, "Testing 4x4 replica array for 1rw1r cell with right replica column") + a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, rbl=[1, 1], right_rbl=[1]) self.local_check(a) openram.end_openram() + # run the test from the command line if __name__ == "__main__": (OPTS, args) = openram.parse_args() diff --git a/compiler/tests/15_global_bitcell_array_norbl_1rw_1r_test.py b/compiler/tests/15_global_bitcell_array_norbl_1rw_1r_test.py new file mode 100755 index 00000000..0c887e16 --- /dev/null +++ b/compiler/tests/15_global_bitcell_array_norbl_1rw_1r_test.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz +# All rights reserved. +# +import sys, os +import unittest +from testutils import * + +import openram +from openram import debug +from openram.sram_factory import factory +from openram import OPTS + + +class global_bitcell_array_norbl_1rw_1r_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + openram.init_openram(config_file, is_unit_test=True) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + openram.setup_bitcell() + + debug.info(2, "Testing 2 x 4x4 global bitcell array for 1rw1r cell without replica columns") + a = factory.create(module_type="global_bitcell_array", cols=[4, 4, 4], rows=4, rbl=[0, 0], left_rbl=[], right_rbl=[]) + self.local_check(a) + + openram.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/15_global_bitcell_array_norbl_1rw_test.py b/compiler/tests/15_global_bitcell_array_norbl_1rw_test.py new file mode 100755 index 00000000..e1dbffc4 --- /dev/null +++ b/compiler/tests/15_global_bitcell_array_norbl_1rw_test.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz +# All rights reserved. +# +import sys, os +import unittest +from testutils import * + +import openram +from openram import debug +from openram.sram_factory import factory +from openram import OPTS + + +class global_bitcell_array_norbl_1rw_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + openram.init_openram(config_file, is_unit_test=True) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 0 + OPTS.num_w_ports = 0 + openram.setup_bitcell() + + debug.info(2, "Testing 2 x 4x4 global bitcell array for 1rw cell without replica column") + a = factory.create(module_type="global_bitcell_array", cols=[4, 4], rows=4, rbl=[0, 0], left_rbl=[]) + self.local_check(a) + + openram.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/15_global_bitcell_array_rbl_1rw_1r_test.py b/compiler/tests/15_global_bitcell_array_rbl_1rw_1r_test.py new file mode 100755 index 00000000..c5ef0b92 --- /dev/null +++ b/compiler/tests/15_global_bitcell_array_rbl_1rw_1r_test.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz +# All rights reserved. +# +import sys, os +import unittest +from testutils import * + +import openram +from openram import debug +from openram.sram_factory import factory +from openram import OPTS + + +class global_bitcell_array_rbl_1rw_1r_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + openram.init_openram(config_file, is_unit_test=True) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + openram.setup_bitcell() + + debug.info(2, "Testing 2 x 4x4 global bitcell array for 1rw1r cell with replica columns") + a = factory.create(module_type="global_bitcell_array", cols=[4, 4, 4], rows=4, rbl=[1, 1], left_rbl=[0], right_rbl=[1]) + self.local_check(a) + + openram.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/15_global_bitcell_array_rbl_1rw_test.py b/compiler/tests/15_global_bitcell_array_rbl_1rw_test.py new file mode 100755 index 00000000..b86c2c84 --- /dev/null +++ b/compiler/tests/15_global_bitcell_array_rbl_1rw_test.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz +# All rights reserved. +# +import sys, os +import unittest +from testutils import * + +import openram +from openram import debug +from openram.sram_factory import factory +from openram import OPTS + + +class global_bitcell_array_rbl_1rw_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + openram.init_openram(config_file, is_unit_test=True) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 0 + OPTS.num_w_ports = 0 + openram.setup_bitcell() + + debug.info(2, "Testing 2 x 4x4 global bitcell array for 1rw cell with left replica column") + a = factory.create(module_type="global_bitcell_array", cols=[4, 4], rows=4, rbl=[1, 0], left_rbl=[0]) + self.local_check(a) + + openram.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/15_local_bitcell_array_1rw_1r_test.py b/compiler/tests/15_local_bitcell_array_1rw_1r_test.py deleted file mode 100755 index 07959a05..00000000 --- a/compiler/tests/15_local_bitcell_array_1rw_1r_test.py +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env python3 -# See LICENSE for licensing information. -# -# Copyright (c) 2016-2023 Regents of the University of California and The Board -# of Regents for the Oklahoma Agricultural and Mechanical College -# (acting for and on behalf of Oklahoma State University) -# All rights reserved. -# -import sys, os -import unittest -from testutils import * - -import openram -from openram import debug -from openram.sram_factory import factory -from openram import OPTS - - -# @unittest.skip("SKIPPING 05_local_bitcell_array_test") -class local_bitcell_array_1rw_1r_test(openram_test): - - def runTest(self): - config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) - openram.init_openram(config_file, is_unit_test=True) - - OPTS.num_rw_ports = 1 - OPTS.num_r_ports = 1 - OPTS.num_w_ports = 0 - openram.setup_bitcell() - - debug.info(2, "Testing 4x4 local bitcell array for cell_1rw_1r without replica") - a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 1]) - self.local_check(a) - - debug.info(2, "Testing 4x4 local bitcell array for cell_1rw_1r with replica column") - a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 1], right_rbl=[1]) - self.local_check(a) - - debug.info(2, "Testing 4x4 local bitcell array for cell_1rw_1r with replica column") - a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 1], left_rbl=[0]) - self.local_check(a) - - debug.info(2, "Testing 4x4 local bitcell array for cell_1rw_1r with replica column") - a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 1], left_rbl=[0], right_rbl=[1]) - self.local_check(a) - - openram.end_openram() - - -# run the test from the command line -if __name__ == "__main__": - (OPTS, args) = openram.parse_args() - del sys.argv[1:] - header(__file__, OPTS.tech_name) - unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/15_local_bitcell_array_bothrbl_1rw_1r_test.py b/compiler/tests/15_local_bitcell_array_bothrbl_1rw_1r_test.py new file mode 100755 index 00000000..08e4c5ee --- /dev/null +++ b/compiler/tests/15_local_bitcell_array_bothrbl_1rw_1r_test.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz +# All rights reserved. +# +import sys, os +import unittest +from testutils import * + +import openram +from openram import debug +from openram.sram_factory import factory +from openram import OPTS + + +class local_bitcell_array_bothrbl_1rw_1r_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + openram.init_openram(config_file, is_unit_test=True) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + openram.setup_bitcell() + + debug.info(2, "Testing 4x4 local bitcell array for 1rw1r cell with both replica columns") + a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 1], left_rbl=[0], right_rbl=[1]) + self.local_check(a) + + openram.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/15_local_bitcell_array_dummies_1rw_1r_test.py b/compiler/tests/15_local_bitcell_array_dummies_1rw_1r_test.py new file mode 100755 index 00000000..80667466 --- /dev/null +++ b/compiler/tests/15_local_bitcell_array_dummies_1rw_1r_test.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz +# All rights reserved. +# +import sys, os +import unittest +from testutils import * + +import openram +from openram import debug +from openram.sram_factory import factory +from openram import OPTS + + +class local_bitcell_array_dummies_1rw_1r_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + openram.init_openram(config_file, is_unit_test=True) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + openram.setup_bitcell() + + debug.info(2, "Testing 4x4 local bitcell array for 1rw1r cell with dummy rows only") + a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 1]) + self.local_check(a) + + openram.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/15_local_bitcell_array_dummies_1rw_test.py b/compiler/tests/15_local_bitcell_array_dummies_1rw_test.py new file mode 100755 index 00000000..20d2398e --- /dev/null +++ b/compiler/tests/15_local_bitcell_array_dummies_1rw_test.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz +# All rights reserved. +# +import sys, os +import unittest +from testutils import * + +import openram +from openram import debug +from openram.sram_factory import factory +from openram import OPTS + + +class local_bitcell_array_dummies_1rw_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + openram.init_openram(config_file, is_unit_test=True) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 0 + OPTS.num_w_ports = 0 + openram.setup_bitcell() + + debug.info(2, "Testing 7x5 local bitcell array for 1rw cell with dummy row only") + a = factory.create(module_type="local_bitcell_array", cols=7, rows=5, rbl=[1, 0]) + self.local_check(a) + + openram.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/15_local_bitcell_array_leftrbl_1rw_1r_test.py b/compiler/tests/15_local_bitcell_array_leftrbl_1rw_1r_test.py new file mode 100755 index 00000000..65be2de1 --- /dev/null +++ b/compiler/tests/15_local_bitcell_array_leftrbl_1rw_1r_test.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz +# All rights reserved. +# +import sys, os +import unittest +from testutils import * + +import openram +from openram import debug +from openram.sram_factory import factory +from openram import OPTS + + +class local_bitcell_array_leftrbl_1rw_1r_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + openram.init_openram(config_file, is_unit_test=True) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + openram.setup_bitcell() + + debug.info(2, "Testing 4x4 local bitcell array for 1rw1r cell with left replica column") + a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 1], left_rbl=[0]) + self.local_check(a) + + openram.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/15_local_bitcell_array_leftrbl_1rw_test.py b/compiler/tests/15_local_bitcell_array_leftrbl_1rw_test.py new file mode 100755 index 00000000..756da97e --- /dev/null +++ b/compiler/tests/15_local_bitcell_array_leftrbl_1rw_test.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz +# All rights reserved. +# +import sys, os +import unittest +from testutils import * + +import openram +from openram import debug +from openram.sram_factory import factory +from openram import OPTS + + +class local_bitcell_array_leftrbl_1rw_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + openram.init_openram(config_file, is_unit_test=True) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 0 + OPTS.num_w_ports = 0 + openram.setup_bitcell() + + debug.info(2, "Testing 7x5 local bitcell array for 1rw cell with left replica column") + a = factory.create(module_type="local_bitcell_array", cols=7, rows=5, rbl=[1, 0], left_rbl=[0]) + self.local_check(a) + + openram.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/15_local_bitcell_array_norbl_1rw_1r_test.py b/compiler/tests/15_local_bitcell_array_norbl_1rw_1r_test.py new file mode 100755 index 00000000..f86188c2 --- /dev/null +++ b/compiler/tests/15_local_bitcell_array_norbl_1rw_1r_test.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz +# All rights reserved. +# +import sys, os +import unittest +from testutils import * + +import openram +from openram import debug +from openram.sram_factory import factory +from openram import OPTS + + +class local_bitcell_array_norbl_1rw_1r_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + openram.init_openram(config_file, is_unit_test=True) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + openram.setup_bitcell() + + debug.info(2, "Testing 4x4 local bitcell array for 1rw1r cell without replica columns or dummy rows") + a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[0, 0]) + self.local_check(a) + + openram.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/15_local_bitcell_array_norbl_1rw_test.py b/compiler/tests/15_local_bitcell_array_norbl_1rw_test.py new file mode 100755 index 00000000..795fd14e --- /dev/null +++ b/compiler/tests/15_local_bitcell_array_norbl_1rw_test.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz +# All rights reserved. +# +import sys, os +import unittest +from testutils import * + +import openram +from openram import debug +from openram.sram_factory import factory +from openram import OPTS + + +class local_bitcell_array_norbl_1rw_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + openram.init_openram(config_file, is_unit_test=True) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 0 + OPTS.num_w_ports = 0 + openram.setup_bitcell() + + debug.info(2, "Testing 7x5 local bitcell array for 1rw cell without replica column or dummy row") + a = factory.create(module_type="local_bitcell_array", cols=7, rows=5, rbl=[0, 0]) + self.local_check(a) + + openram.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/15_local_bitcell_array_rightrbl_1rw_1r_test.py b/compiler/tests/15_local_bitcell_array_rightrbl_1rw_1r_test.py new file mode 100755 index 00000000..cc392587 --- /dev/null +++ b/compiler/tests/15_local_bitcell_array_rightrbl_1rw_1r_test.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz +# All rights reserved. +# +import sys, os +import unittest +from testutils import * + +import openram +from openram import debug +from openram.sram_factory import factory +from openram import OPTS + + +class local_bitcell_array_rightrbl_1rw_1r_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + openram.init_openram(config_file, is_unit_test=True) + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + openram.setup_bitcell() + + debug.info(2, "Testing 4x4 local bitcell array for 1rw1r cell with right replica column") + a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 1], right_rbl=[1]) + self.local_check(a) + + openram.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/16_control_logic_delay_multiport_test.py b/compiler/tests/16_control_logic_delay_multiport_test.py new file mode 100755 index 00000000..60bb9472 --- /dev/null +++ b/compiler/tests/16_control_logic_delay_multiport_test.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +""" +Run a regression test on a control_logic_delay +""" + +import sys, os +import unittest +from testutils import header,openram_test + +import openram +from openram import debug +from openram.sram_factory import factory +from openram import OPTS + + +class control_logic_delay_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + openram.init_openram(config_file, is_unit_test=True) + + # check control logic for multi-port + OPTS.bitcell = "pbitcell" + OPTS.replica_bitcell = "replica_pbitcell" + OPTS.num_rw_ports = 1 + OPTS.num_w_ports = 1 + OPTS.num_r_ports = 1 + + debug.info(1, "Testing sample for control_logic_delay for multiport, combined read-write control logic") + a = factory.create(module_type="control_logic_delay", num_rows=128, words_per_row=1, word_size=8, port_type="rw") + self.local_check(a) + + # OPTS.num_rw_ports = 0 + # OPTS.num_w_ports = 1 + debug.info(1, "Testing sample for control_logic_delay for multiport, only write control logic") + a = factory.create(module_type="control_logic_delay", num_rows=128, words_per_row=1, word_size=8, port_type="w") + self.local_check(a) + + # OPTS.num_w_ports = 0 + # OPTS.num_r_ports = 1 + debug.info(1, "Testing sample for control_logic_delay for multiport, only read control logic") + a = factory.create(module_type="control_logic_delay", num_rows=128, words_per_row=1, word_size=8, port_type="r") + self.local_check(a) + + openram.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main() diff --git a/compiler/tests/15_global_bitcell_array_test.py b/compiler/tests/16_control_logic_delay_r_test.py similarity index 66% rename from compiler/tests/15_global_bitcell_array_test.py rename to compiler/tests/16_control_logic_delay_r_test.py index 20f50735..6479269b 100755 --- a/compiler/tests/15_global_bitcell_array_test.py +++ b/compiler/tests/16_control_logic_delay_r_test.py @@ -11,29 +11,23 @@ import unittest from testutils import * import openram -from openram.sram_factory import factory from openram import debug +from openram.sram_factory import factory from openram import OPTS -# @unittest.skip("SKIPPING 05_global_bitcell_array_test") -class global_bitcell_array_test(openram_test): +class control_logic_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) openram.init_openram(config_file, is_unit_test=True) - # debug.info(2, "Testing 2 x 4x4 global bitcell array for 6t_cell") - # a = factory.create(module_type="global_bitcell_array", cols=[4, 4], rows=4) - # self.local_check(a) - - debug.info(2, "Testing 2 x 4x4 global bitcell array for 6t_cell") - a = factory.create(module_type="global_bitcell_array", cols=[10, 6], rows=4) + debug.info(1, "Testing sample for control_logic_r") + a = factory.create(module_type="control_logic_delay", num_rows=128, words_per_row=1, word_size=32, port_type="r") self.local_check(a) openram.end_openram() - # run the test from the command line if __name__ == "__main__": (OPTS, args) = openram.parse_args() diff --git a/compiler/tests/15_local_bitcell_array_test.py b/compiler/tests/16_control_logic_delay_rw_test.py similarity index 64% rename from compiler/tests/15_local_bitcell_array_test.py rename to compiler/tests/16_control_logic_delay_rw_test.py index 655b8c78..72f870e3 100755 --- a/compiler/tests/15_local_bitcell_array_test.py +++ b/compiler/tests/16_control_logic_delay_rw_test.py @@ -16,24 +16,18 @@ from openram.sram_factory import factory from openram import OPTS -# @unittest.skip("SKIPPING 05_local_bitcell_array_test") -class local_bitcell_array_test(openram_test): +class control_logic_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) openram.init_openram(config_file, is_unit_test=True) - debug.info(2, "Testing 4x4 local bitcell array for 6t_cell without replica") - a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 0]) - self.local_check(a) - - debug.info(2, "Testing 4x4 local bitcell array for 6t_cell with replica column") - a = factory.create(module_type="local_bitcell_array", cols=4, rows=4, rbl=[1, 0], left_rbl=[0]) + debug.info(1, "Testing sample for control_logic_rw") + a = factory.create(module_type="control_logic_delay", num_rows=128, words_per_row=1, word_size=32) self.local_check(a) openram.end_openram() - # run the test from the command line if __name__ == "__main__": (OPTS, args) = openram.parse_args() diff --git a/compiler/tests/16_control_logic_delay_w_test.py b/compiler/tests/16_control_logic_delay_w_test.py new file mode 100755 index 00000000..0a071f4e --- /dev/null +++ b/compiler/tests/16_control_logic_delay_w_test.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import sys, os +import unittest +from testutils import * + +import openram +from openram import debug +from openram.sram_factory import factory +from openram import OPTS + + +class control_logic_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + openram.init_openram(config_file, is_unit_test=True) + + debug.info(1, "Testing sample for control_logic_w") + a = factory.create(module_type="control_logic_delay", num_rows=128, words_per_row=1, word_size=32, port_type="w") + self.local_check(a) + + openram.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/16_control_logic_multiport_test.py b/compiler/tests/16_control_logic_multiport_test.py index 600740ba..daf25578 100755 --- a/compiler/tests/16_control_logic_multiport_test.py +++ b/compiler/tests/16_control_logic_multiport_test.py @@ -33,7 +33,7 @@ class control_logic_test(openram_test): OPTS.num_w_ports = 1 OPTS.num_r_ports = 1 - debug.info(1, "Testing sample for control_logic for multiport, only write control logic") + debug.info(1, "Testing sample for control_logic for multiport, combined read-write control logic") a = factory.create(module_type="control_logic", num_rows=128, words_per_row=1, word_size=8, port_type="rw") self.local_check(a) diff --git a/compiler/tests/18_port_address_16rows_1rw_1r_test.py b/compiler/tests/18_port_address_16rows_1rw_1r_test.py index dce0469f..b021f3e1 100755 --- a/compiler/tests/18_port_address_16rows_1rw_1r_test.py +++ b/compiler/tests/18_port_address_16rows_1rw_1r_test.py @@ -27,7 +27,7 @@ class port_address_1rw_1r_test(openram_test): openram.setup_bitcell() debug.info(1, "Port address 16 rows") - a = factory.create("port_address", cols=16, rows=16, port=0) + a = factory.create("port_address", cols=16, rows=16, port=0, has_rbl=True) self.local_check(a) openram.end_openram() diff --git a/compiler/tests/18_port_address_16rows_test.py b/compiler/tests/18_port_address_16rows_test.py index 52d32f31..5453e85f 100755 --- a/compiler/tests/18_port_address_16rows_test.py +++ b/compiler/tests/18_port_address_16rows_test.py @@ -21,7 +21,7 @@ class port_address_test(openram_test): openram.init_openram(config_file, is_unit_test=True) debug.info(1, "Port address 16 rows") - a = factory.create("port_address", cols=16, rows=16, port=0) + a = factory.create("port_address", cols=16, rows=16, port=0, has_rbl=True) self.local_check(a) openram.end_openram() diff --git a/compiler/tests/18_port_address_256rows_1rw_1r_test.py b/compiler/tests/18_port_address_256rows_1rw_1r_test.py index 28d14b33..c7a5d5b1 100755 --- a/compiler/tests/18_port_address_256rows_1rw_1r_test.py +++ b/compiler/tests/18_port_address_256rows_1rw_1r_test.py @@ -27,7 +27,7 @@ class port_address_1rw_1r_test(openram_test): openram.setup_bitcell() debug.info(1, "Port address 256 rows") - a = factory.create("port_address", cols=256, rows=256, port=1) + a = factory.create("port_address", cols=256, rows=256, port=1, has_rbl=True) self.local_check(a) openram.end_openram() diff --git a/compiler/tests/18_port_address_512rows_test.py b/compiler/tests/18_port_address_512rows_test.py index 5c1848b0..ff7070c2 100755 --- a/compiler/tests/18_port_address_512rows_test.py +++ b/compiler/tests/18_port_address_512rows_test.py @@ -21,7 +21,7 @@ class port_address_test(openram_test): openram.init_openram(config_file, is_unit_test=True) debug.info(1, "Port address 512 rows") - a = factory.create("port_address", cols=256, rows=512, port=0) + a = factory.create("port_address", cols=256, rows=512, port=0, has_rbl=True) self.local_check(a) openram.end_openram() diff --git a/compiler/tests/18_port_data_16mux_1rw_1r_test.py b/compiler/tests/18_port_data_16mux_1rw_1r_test.py index b4b50323..863dc37d 100755 --- a/compiler/tests/18_port_data_16mux_1rw_1r_test.py +++ b/compiler/tests/18_port_data_16mux_1rw_1r_test.py @@ -34,9 +34,9 @@ class port_data_1rw_1r_test(openram_test): c.words_per_row=16 c.recompute_sizes() debug.info(1, "Sixteen way column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) - a = factory.create("port_data", sram_config=c, port=1) + a = factory.create("port_data", sram_config=c, port=1, has_rbl=True) self.local_check(a) openram.end_openram() diff --git a/compiler/tests/18_port_data_16mux_test.py b/compiler/tests/18_port_data_16mux_test.py index 66d4c4bf..e46d1107 100755 --- a/compiler/tests/18_port_data_16mux_test.py +++ b/compiler/tests/18_port_data_16mux_test.py @@ -38,7 +38,7 @@ class port_data_test(openram_test): c.words_per_row=16 c.recompute_sizes() debug.info(1, "Sixteen way column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) openram.end_openram() diff --git a/compiler/tests/18_port_data_2mux_1rw_1r_test.py b/compiler/tests/18_port_data_2mux_1rw_1r_test.py index fc0d9243..a0f88622 100755 --- a/compiler/tests/18_port_data_2mux_1rw_1r_test.py +++ b/compiler/tests/18_port_data_2mux_1rw_1r_test.py @@ -33,9 +33,9 @@ class port_data_1rw_1r_test(openram_test): c.words_per_row=2 c.recompute_sizes() debug.info(1, "Two way column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) - a = factory.create("port_data", sram_config=c, port=1) + a = factory.create("port_data", sram_config=c, port=1, has_rbl=True) self.local_check(a) openram.end_openram() diff --git a/compiler/tests/18_port_data_2mux_test.py b/compiler/tests/18_port_data_2mux_test.py index 8eb29615..2864baee 100755 --- a/compiler/tests/18_port_data_2mux_test.py +++ b/compiler/tests/18_port_data_2mux_test.py @@ -37,7 +37,7 @@ class port_data_test(openram_test): c.words_per_row=2 c.recompute_sizes() debug.info(1, "Two way column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) openram.end_openram() diff --git a/compiler/tests/18_port_data_4mux_1rw_1r_test.py b/compiler/tests/18_port_data_4mux_1rw_1r_test.py index ac81e561..a19a9698 100755 --- a/compiler/tests/18_port_data_4mux_1rw_1r_test.py +++ b/compiler/tests/18_port_data_4mux_1rw_1r_test.py @@ -33,9 +33,9 @@ class port_data_1rw_1r_test(openram_test): c.words_per_row=4 c.recompute_sizes() debug.info(1, "Four way column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) - a = factory.create("port_data", sram_config=c, port=1) + a = factory.create("port_data", sram_config=c, port=1, has_rbl=True) self.local_check(a) openram.end_openram() diff --git a/compiler/tests/18_port_data_4mux_test.py b/compiler/tests/18_port_data_4mux_test.py index c3eae434..42d40335 100755 --- a/compiler/tests/18_port_data_4mux_test.py +++ b/compiler/tests/18_port_data_4mux_test.py @@ -37,7 +37,7 @@ class port_data_test(openram_test): c.words_per_row=4 c.recompute_sizes() debug.info(1, "Four way column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) openram.end_openram() diff --git a/compiler/tests/18_port_data_8mux_1rw_1r_test.py b/compiler/tests/18_port_data_8mux_1rw_1r_test.py index e57d12ef..add22345 100755 --- a/compiler/tests/18_port_data_8mux_1rw_1r_test.py +++ b/compiler/tests/18_port_data_8mux_1rw_1r_test.py @@ -34,9 +34,9 @@ class port_data_1rw_1r_test(openram_test): c.words_per_row=8 c.recompute_sizes() debug.info(1, "Eight way column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) - a = factory.create("port_data", sram_config=c, port=1) + a = factory.create("port_data", sram_config=c, port=1, has_rbl=True) self.local_check(a) openram.end_openram() diff --git a/compiler/tests/18_port_data_8mux_test.py b/compiler/tests/18_port_data_8mux_test.py index a8f82489..700a7b59 100755 --- a/compiler/tests/18_port_data_8mux_test.py +++ b/compiler/tests/18_port_data_8mux_test.py @@ -38,7 +38,7 @@ class port_data_test(openram_test): c.words_per_row=8 c.recompute_sizes() debug.info(1, "Eight way column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) openram.end_openram() diff --git a/compiler/tests/18_port_data_nomux_1rw_1r_test.py b/compiler/tests/18_port_data_nomux_1rw_1r_test.py index 8b887d9b..48b2ddee 100755 --- a/compiler/tests/18_port_data_nomux_1rw_1r_test.py +++ b/compiler/tests/18_port_data_nomux_1rw_1r_test.py @@ -32,9 +32,9 @@ class port_data_1rw_1r_test(openram_test): c.words_per_row=1 c.recompute_sizes() debug.info(1, "No column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) - a = factory.create("port_data", sram_config=c, port=1) + a = factory.create("port_data", sram_config=c, port=1, has_rbl=True) self.local_check(a) openram.end_openram() diff --git a/compiler/tests/18_port_data_nomux_test.py b/compiler/tests/18_port_data_nomux_test.py index e479de1f..ceeff4cf 100755 --- a/compiler/tests/18_port_data_nomux_test.py +++ b/compiler/tests/18_port_data_nomux_test.py @@ -36,7 +36,7 @@ class port_data_test(openram_test): c.words_per_row=1 c.recompute_sizes() debug.info(1, "No column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) openram.end_openram() diff --git a/compiler/tests/18_port_data_spare_cols_test.py b/compiler/tests/18_port_data_spare_cols_test.py index 0db34da0..ad05c64c 100755 --- a/compiler/tests/18_port_data_spare_cols_test.py +++ b/compiler/tests/18_port_data_spare_cols_test.py @@ -28,14 +28,14 @@ class port_data_spare_cols_test(openram_test): c.words_per_row=1 c.recompute_sizes() debug.info(1, "No column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) c.num_words=32 c.words_per_row=2 c.recompute_sizes() debug.info(1, "Two way column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) c.num_words=64 @@ -43,7 +43,7 @@ class port_data_spare_cols_test(openram_test): c.num_spare_cols=3 c.recompute_sizes() debug.info(1, "Four way column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) c.word_size=2 @@ -52,7 +52,7 @@ class port_data_spare_cols_test(openram_test): c.num_spare_cols=4 c.recompute_sizes() debug.info(1, "Eight way column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) OPTS.num_rw_ports = 0 @@ -64,27 +64,27 @@ class port_data_spare_cols_test(openram_test): c.words_per_row=1 c.recompute_sizes() debug.info(1, "No column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) - a = factory.create("port_data", sram_config=c, port=1) + a = factory.create("port_data", sram_config=c, port=1, has_rbl=True) self.local_check(a) c.num_words=32 c.words_per_row=2 c.recompute_sizes() debug.info(1, "Two way column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) - a = factory.create("port_data", sram_config=c, port=1) + a = factory.create("port_data", sram_config=c, port=1, has_rbl=True) self.local_check(a) c.num_words=64 c.words_per_row=4 c.recompute_sizes() debug.info(1, "Four way column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) - a = factory.create("port_data", sram_config=c, port=1) + a = factory.create("port_data", sram_config=c, port=1, has_rbl=True) self.local_check(a) c.word_size=2 @@ -92,9 +92,9 @@ class port_data_spare_cols_test(openram_test): c.words_per_row=8 c.recompute_sizes() debug.info(1, "Eight way column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) - a = factory.create("port_data", sram_config=c, port=1) + a = factory.create("port_data", sram_config=c, port=1, has_rbl=True) self.local_check(a) openram.end_openram() diff --git a/compiler/tests/18_port_data_wmask_1rw_1r_test.py b/compiler/tests/18_port_data_wmask_1rw_1r_test.py index b731a1d0..6aadd417 100755 --- a/compiler/tests/18_port_data_wmask_1rw_1r_test.py +++ b/compiler/tests/18_port_data_wmask_1rw_1r_test.py @@ -33,28 +33,28 @@ class port_data_wmask_1rw_1r_test(openram_test): c.words_per_row = 1 c.recompute_sizes() debug.info(1, "No column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) c.num_words = 32 c.words_per_row = 2 c.recompute_sizes() debug.info(1, "Two way column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) c.num_words = 64 c.words_per_row = 4 c.recompute_sizes() debug.info(1, "Four way column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) c.num_words = 128 c.words_per_row = 8 c.recompute_sizes() debug.info(1, "Eight way column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) OPTS.num_rw_ports = 0 @@ -66,27 +66,27 @@ class port_data_wmask_1rw_1r_test(openram_test): c.words_per_row = 1 c.recompute_sizes() debug.info(1, "No column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) - a = factory.create("port_data", sram_config=c, port=1) + a = factory.create("port_data", sram_config=c, port=1, has_rbl=True) self.local_check(a) # c.num_words = 32 c.words_per_row = 2 c.recompute_sizes() debug.info(1, "Two way column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) - a = factory.create("port_data", sram_config=c, port=1) + a = factory.create("port_data", sram_config=c, port=1, has_rbl=True) self.local_check(a) c.num_words = 64 c.words_per_row = 4 c.recompute_sizes() debug.info(1, "Four way column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) - a = factory.create("port_data", sram_config=c, port=1) + a = factory.create("port_data", sram_config=c, port=1, has_rbl=True) self.local_check(a) c.word_size = 8 @@ -94,9 +94,9 @@ class port_data_wmask_1rw_1r_test(openram_test): c.words_per_row = 8 c.recompute_sizes() debug.info(1, "Eight way column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) - a = factory.create("port_data", sram_config=c, port=1) + a = factory.create("port_data", sram_config=c, port=1, has_rbl=True) self.local_check(a) openram.end_openram() diff --git a/compiler/tests/18_port_data_wmask_test.py b/compiler/tests/18_port_data_wmask_test.py index 3db910c1..30565ba8 100755 --- a/compiler/tests/18_port_data_wmask_test.py +++ b/compiler/tests/18_port_data_wmask_test.py @@ -37,28 +37,28 @@ class port_data_wmask_test(openram_test): c.words_per_row = 1 c.recompute_sizes() debug.info(1, "No column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) c.num_words = 32 c.words_per_row = 2 c.recompute_sizes() debug.info(1, "Two way column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) c.num_words = 64 c.words_per_row = 4 c.recompute_sizes() debug.info(1, "Four way column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) c.num_words = 128 c.words_per_row = 8 c.recompute_sizes() debug.info(1, "Eight way column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) OPTS.num_rw_ports = 0 @@ -70,27 +70,27 @@ class port_data_wmask_test(openram_test): c.words_per_row = 1 c.recompute_sizes() debug.info(1, "No column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) - a = factory.create("port_data", sram_config=c, port=1) + a = factory.create("port_data", sram_config=c, port=1, has_rbl=True) self.local_check(a) # c.num_words = 32 c.words_per_row = 2 c.recompute_sizes() debug.info(1, "Two way column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) - a = factory.create("port_data", sram_config=c, port=1) + a = factory.create("port_data", sram_config=c, port=1, has_rbl=True) self.local_check(a) c.num_words = 64 c.words_per_row = 4 c.recompute_sizes() debug.info(1, "Four way column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) - a = factory.create("port_data", sram_config=c, port=1) + a = factory.create("port_data", sram_config=c, port=1, has_rbl=True) self.local_check(a) c.word_size = 8 @@ -98,9 +98,9 @@ class port_data_wmask_test(openram_test): c.words_per_row = 8 c.recompute_sizes() debug.info(1, "Eight way column mux") - a = factory.create("port_data", sram_config=c, port=0) + a = factory.create("port_data", sram_config=c, port=0, has_rbl=True) self.local_check(a) - a = factory.create("port_data", sram_config=c, port=1) + a = factory.create("port_data", sram_config=c, port=1, has_rbl=True) self.local_check(a) openram.end_openram() diff --git a/compiler/tests/15_global_bitcell_array_1rw_1r_test.py b/compiler/tests/19_single_bank_nomux_norbl_1rw_1r_test.py similarity index 67% rename from compiler/tests/15_global_bitcell_array_1rw_1r_test.py rename to compiler/tests/19_single_bank_nomux_norbl_1rw_1r_test.py index 480b8931..47ebfa7c 100755 --- a/compiler/tests/15_global_bitcell_array_1rw_1r_test.py +++ b/compiler/tests/19_single_bank_nomux_norbl_1rw_1r_test.py @@ -16,25 +16,27 @@ from openram.sram_factory import factory from openram import OPTS -# @unittest.skip("SKIPPING 05_global_bitcell_array_test") -class global_bitcell_array_test(openram_test): +class single_bank_nomux_norbl_1rw_1r_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) openram.init_openram(config_file, is_unit_test=True) + from openram import sram_config OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 OPTS.num_w_ports = 0 openram.setup_bitcell() - debug.info(2, "Testing 2 x 4x4 global bitcell array for cell_1rw_1r") - a = factory.create(module_type="global_bitcell_array", cols=[4, 4], rows=4) - self.local_check(a) + c = sram_config(word_size=4, + num_words=16) - # debug.info(2, "Testing 4x4 local bitcell array for 6t_cell with replica column") - # a = factory.create(module_type="local_bitcell_array", cols=4, left_rbl=1, rows=4, ports=[0]) - # self.local_check(a) + c.words_per_row=1 + OPTS.control_logic = "control_logic_delay" + c.recompute_sizes() + debug.info(1, "No column mux") + a = factory.create(module_type="bank", sram_config=c) + self.local_check(a) openram.end_openram() diff --git a/compiler/tests/19_single_bank_nomux_norbl_test.py b/compiler/tests/19_single_bank_nomux_norbl_test.py new file mode 100755 index 00000000..4f8eec1d --- /dev/null +++ b/compiler/tests/19_single_bank_nomux_norbl_test.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import sys, os +import unittest +from testutils import * + +import openram +from openram import debug +from openram.sram_factory import factory +from openram import OPTS + + +class single_bank_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + openram.init_openram(config_file, is_unit_test=True) + from openram import sram_config + + if OPTS.tech_name == "sky130": + num_spare_rows = 1 + num_spare_cols = 1 + else: + num_spare_rows = 0 + num_spare_cols = 0 + + c = sram_config(word_size=4, + num_words=16, + num_spare_cols=num_spare_cols, + num_spare_rows=num_spare_rows) + + c.words_per_row=1 + OPTS.control_logic = "control_logic_delay" + factory.reset() + c.recompute_sizes() + debug.info(1, "No column mux") + a = factory.create("bank", sram_config=c) + self.local_check(a) + + openram.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/20_sram_1bank_nomux_norbl_1rw_1r_test.py b/compiler/tests/20_sram_1bank_nomux_norbl_1rw_1r_test.py new file mode 100755 index 00000000..f883398c --- /dev/null +++ b/compiler/tests/20_sram_1bank_nomux_norbl_1rw_1r_test.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import sys, os +import unittest +from testutils import * + +import openram +from openram import debug +from openram.sram_factory import factory +from openram import OPTS + + +class sram_1bank_nomux_norbl_1rw_1r_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + openram.init_openram(config_file, is_unit_test=True) + from openram import sram_config + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + openram.setup_bitcell() + + c = sram_config(word_size=4, + num_words=16, + num_banks=1) + + c.words_per_row=1 + OPTS.control_logic = "control_logic_delay" + c.recompute_sizes() + debug.info(1, "Layout test for {}rw,{}r,{}w sram " + "with {} bit words, {} words, {} words per " + "row, {} banks".format(OPTS.num_rw_ports, + OPTS.num_r_ports, + OPTS.num_w_ports, + c.word_size, + c.num_words, + c.words_per_row, + c.num_banks)) + a = factory.create(module_type="sram", sram_config=c) + self.local_check(a, final_verification=True) + + openram.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/20_sram_1bank_nomux_norbl_test.py b/compiler/tests/20_sram_1bank_nomux_norbl_test.py new file mode 100755 index 00000000..aa1704e6 --- /dev/null +++ b/compiler/tests/20_sram_1bank_nomux_norbl_test.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import sys, os +import unittest +from testutils import * + +import openram +from openram import debug +from openram.sram_factory import factory +from openram import OPTS + + +class sram_1bank_nomux_norbl_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + openram.init_openram(config_file, is_unit_test=True) + from openram import sram_config + + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 0 + OPTS.num_w_ports = 0 + openram.setup_bitcell() + + c = sram_config(word_size=4, + num_words=16, + num_banks=1) + + c.words_per_row=1 + OPTS.control_logic = "control_logic_delay" + c.recompute_sizes() + debug.info(1, "Layout test for {}rw,{}r,{}w sram " + "with {} bit words, {} words, {} words per " + "row, {} banks".format(OPTS.num_rw_ports, + OPTS.num_r_ports, + OPTS.num_w_ports, + c.word_size, + c.num_words, + c.words_per_row, + c.num_banks)) + a = factory.create(module_type="sram", sram_config=c) + self.local_check(a, final_verification=True) + + openram.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index b832f9c0..7f1bef57 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -32,6 +32,7 @@ BROKEN_STAMPS = \ %/20_psram_1bank_2mux_test.ok \ %/21_hspice_delay_test.ok \ %/21_hspice_setuphold_test.ok \ + %/21_xyce_delay_test.ok \ %/22_psram_1bank_2mux_func_test.ok \ %/22_psram_1bank_4mux_func_test.ok \ %/22_psram_1bank_8mux_func_test.ok \ @@ -69,8 +70,11 @@ BROKEN_STAMPS = \ freepdk45/10_rom_wordline_driver_array_test.ok \ freepdk45/14_rom_array_test.ok \ freepdk45/16_rom_control_logic_test.ok \ + freepdk45/16_control_logic_delay_multiport_test.ok \ + freepdk45/16_control_logic_delay_rw_test.ok \ + freepdk45/16_control_logic_delay_r_test.ok \ + freepdk45/16_control_logic_delay_w_test.ok \ freepdk45/19_rom_bank_test.ok \ - freepdk45/21_xyce_delay_test.ok \ scn4m_subm/06_rom_decoder_test.ok \ scn4m_subm/07_rom_column_mux_array_test.ok \ scn4m_subm/08_rom_decoder_buffer_array_test.ok \ @@ -80,8 +84,8 @@ BROKEN_STAMPS = \ scn4m_subm/16_rom_control_logic_test.ok \ scn4m_subm/19_rom_bank_test.ok \ scn4m_subm/19_single_bank_global_bitline_test.ok \ - scn4m_subm/21_xyce_delay_test.ok \ sky130/01_library_test.ok \ + sky130/03_wire_test.ok \ sky130/04_column_mux_pbitcell_test.ok \ sky130/04_dummy_pbitcell_test.ok \ sky130/04_pbitcell_test.ok \ @@ -89,15 +93,78 @@ BROKEN_STAMPS = \ sky130/04_pand4_test.ok \ sky130/04_precharge_pbitcell_test.ok \ sky130/04_replica_pbitcell_test.ok \ + sky130/04_dummy_pbitcell_1rw1r1w_test.ok \ + sky130/04_dummy_pbitcell_1rw_test.ok \ + sky130/04_replica_pbitcell_1rw1r1w_test.ok \ + sky130/04_replica_pbitcell_1rw_test.ok \ sky130/05_pbitcell_array_test.ok \ sky130/05_bitcell_array_test.ok \ sky130/05_bitcell_array_1rw_1r_test.ok \ sky130/05_dummy_array_test.ok \ + sky130/06_hierarchical_decoder_132row_test.ok \ + sky130/06_hierarchical_decoder_512row_test.ok \ + sky130/06_hierarchical_decoder_64row_test.ok \ + sky130/06_hierarchical_decoder_pbitcell_test.ok \ sky130/07_column_mux_array_pbitcell_test.ok \ + sky130/10_write_driver_array_spare_cols_test.ok \ + sky130/10_write_driver_array_wmask_spare_cols_test.ok \ + sky130/14_capped_replica_bitcell_array_dummies_1rw_test.ok \ + sky130/14_capped_replica_bitcell_array_leftrbl_1rw_test.ok \ + sky130/14_capped_replica_bitcell_array_norbl_1rw_1r_test.ok \ + sky130/14_capped_replica_bitcell_array_norbl_1rw_test.ok \ + sky130/14_replica_bitcell_array_dummies_1rw_test.ok \ + sky130/14_replica_bitcell_array_leftrbl_1rw_test.ok \ + sky130/14_replica_bitcell_array_norbl_1rw_1r_test.ok \ + sky130/14_replica_bitcell_array_norbl_1rw_test.ok \ + sky130/14_replica_column_1rw_1r_test.ok \ + sky130/14_replica_column_1rw_test.ok \ + sky130/14_replica_pbitcell_1rw1r_array_test.ok \ + sky130/14_replica_pbitcell_1rw_array_test.ok \ + sky130/15_global_bitcell_array_norbl_1rw_1r_test.ok \ + sky130/15_global_bitcell_array_norbl_1rw_test.ok \ + sky130/15_global_bitcell_array_rbl_1rw_1r_test.ok \ + sky130/15_global_bitcell_array_rbl_1rw_test.ok \ + sky130/15_local_bitcell_array_dummies_1rw_test.ok \ + sky130/15_local_bitcell_array_leftrbl_1rw_test.ok \ + sky130/15_local_bitcell_array_norbl_1rw_1r_test.ok \ + sky130/15_local_bitcell_array_norbl_1rw_test.ok \ + sky130/16_control_logic_delay_multiport_test.ok \ + sky130/16_control_logic_delay_rw_test.ok \ + sky130/16_control_logic_delay_r_test.ok \ + sky130/16_control_logic_delay_w_test.ok \ + sky130/18_port_address_512rows_test.ok \ + sky130/18_port_data_spare_cols_test.ok \ + sky130/19_single_bank_2mux_test.ok \ + sky130/19_single_bank_4mux_test.ok \ + sky130/19_single_bank_8mux_test.ok \ + sky130/19_single_bank_global_bitline_test.ok \ + sky130/19_single_bank_nomux_test.ok \ + sky130/19_single_bank_nomux_norbl_1rw_1r_test.ok \ + sky130/19_single_bank_nomux_norbl_test.ok \ + sky130/19_single_bank_spare_cols_test.ok \ + sky130/19_single_bank_wmask_test.ok \ sky130/19_pmulti_bank_test.ok \ sky130/19_psingle_bank_test.ok \ sky130/19_bank_select_pbitcell_test.ok \ sky130/20_psram_1bank_4mux_1rw_1r_test.ok \ + sky130/20_sram_1bank_2mux_1rw_1r_spare_cols_test.ok \ + sky130/20_sram_1bank_2mux_1w_1r_spare_cols_test.ok \ + sky130/20_sram_1bank_2mux_global_test.ok \ + sky130/20_sram_1bank_2mux_test.ok \ + sky130/20_sram_1bank_2mux_wmask_spare_cols_test.ok \ + sky130/20_sram_1bank_2mux_wmask_test.ok \ + sky130/20_sram_1bank_4mux_test.ok \ + sky130/20_sram_1bank_8mux_test.ok \ + sky130/20_sram_1bank_nomux_norbl_1rw_1r_test.ok \ + sky130/20_sram_1bank_nomux_norbl_test.ok \ + sky130/20_sram_1bank_nomux_spare_cols_test.ok \ + sky130/20_sram_1bank_nomux_test.ok \ + sky130/20_sram_1bank_nomux_wmask_test.ok \ + sky130/20_sram_1bank_ring_test.ok \ + sky130/21_model_delay_test.ok \ + sky130/21_ngspice_delay_extra_rows_test.ok \ + sky130/21_ngspice_delay_test.ok \ + sky130/21_regression_delay_test.ok \ sky130/22_psram_1bank_2mux_func_test.ok \ sky130/22_psram_1bank_4mux_func_test.ok \ sky130/22_psram_1bank_8mux_func_test.ok \ @@ -107,54 +174,6 @@ BROKEN_STAMPS = \ sky130/23_lib_sram_model_test.ok \ sky130/23_lib_sram_prune_test.ok \ sky130/23_lib_sram_test.ok \ - sky130/03_wire_test.ok \ - sky130/04_dummy_pbitcell_1rw1r1w_test.ok \ - sky130/04_dummy_pbitcell_1rw_test.ok \ - sky130/04_replica_pbitcell_1rw1r1w_test.ok \ - sky130/04_replica_pbitcell_1rw_test.ok \ - sky130/06_hierarchical_decoder_132row_test.ok \ - sky130/06_hierarchical_decoder_512row_test.ok \ - sky130/06_hierarchical_decoder_64row_test.ok \ - sky130/06_hierarchical_decoder_pbitcell_test.ok \ - sky130/10_write_driver_array_spare_cols_test.ok \ - sky130/10_write_driver_array_wmask_spare_cols_test.ok \ - sky130/14_capped_replica_bitcell_array_leftrbl_1rw_test.ok \ - sky130/14_capped_replica_bitcell_array_norbl_1rw_test.ok \ - sky130/14_replica_bitcell_array_leftrbl_1rw_test.ok \ - sky130/14_replica_bitcell_array_norbl_1rw_test.ok \ - sky130/14_replica_column_1rw_1r_test.ok \ - sky130/14_replica_column_1rw_test.ok \ - sky130/14_replica_pbitcell_1rw1r_array_test.ok \ - sky130/14_replica_pbitcell_1rw_array_test.ok \ - sky130/15_global_bitcell_array_1rw_1r_test.ok \ - sky130/15_global_bitcell_array_test.ok \ - sky130/15_local_bitcell_array_test.ok \ - sky130/18_port_address_512rows_test.ok \ - sky130/18_port_data_spare_cols_test.ok \ - sky130/19_single_bank_2mux_test.ok \ - sky130/19_single_bank_4mux_test.ok \ - sky130/19_single_bank_8mux_test.ok \ - sky130/19_single_bank_global_bitline_test.ok \ - sky130/19_single_bank_nomux_test.ok \ - sky130/19_single_bank_spare_cols_test.ok \ - sky130/19_single_bank_wmask_test.ok \ - sky130/20_sram_1bank_2mux_1rw_1r_spare_cols_test.ok \ - sky130/20_sram_1bank_2mux_1w_1r_spare_cols_test.ok \ - sky130/20_sram_1bank_2mux_global_test.ok \ - sky130/20_sram_1bank_2mux_test.ok \ - sky130/20_sram_1bank_2mux_wmask_spare_cols_test.ok \ - sky130/20_sram_1bank_2mux_wmask_test.ok \ - sky130/20_sram_1bank_4mux_test.ok \ - sky130/20_sram_1bank_8mux_test.ok \ - sky130/20_sram_1bank_nomux_spare_cols_test.ok \ - sky130/20_sram_1bank_nomux_test.ok \ - sky130/20_sram_1bank_nomux_wmask_test.ok \ - sky130/20_sram_1bank_ring_test.ok \ - sky130/21_model_delay_test.ok \ - sky130/21_ngspice_delay_extra_rows_test.ok \ - sky130/21_ngspice_delay_test.ok \ - sky130/21_regression_delay_test.ok \ - sky130/21_xyce_delay_test.ok \ sky130/25_verilog_multibank_test.ok \ sky130/25_verilog_sram_test.ok \ sky130/30_openram_back_end_library_test.ok \ diff --git a/docs/source/architecture.md b/docs/source/architecture.md index 99dea80b..cbad0317 100644 --- a/docs/source/architecture.md +++ b/docs/source/architecture.md @@ -22,4 +22,14 @@ This page of the documentation explains the architecture of OpenRAM. * Write Driver(s) * Control Logic with Replica Bitline -![OpenRAM SRAM Architecture](../assets/images/architecture/sram_architecture.png) \ No newline at end of file +![OpenRAM SRAM Architecture](../assets/images/architecture/sram_architecture.png) + +## ROM Architecture +* Bit-cell Array + * 1T NAND Bitcell +* Row Address Decoder +* Wordline Driver(s) +* Column Multiplexer +* Column Pre-Decoder +* Bitline Precharge(s) +* Control Logic \ No newline at end of file diff --git a/docs/source/basic_rom_usage.md b/docs/source/basic_rom_usage.md new file mode 100644 index 00000000..07356862 --- /dev/null +++ b/docs/source/basic_rom_usage.md @@ -0,0 +1,99 @@ + +### [Go Back](./index.md#table-of-contents) + +# Basic Usage +This page of the documentation explains the basic usage of OpenRAM's ROM compiler (OpenROM). For usage of the RAM compiler see [here](./basic_usage.md#go-back) + + + +## Table of Contents +1. [Environment Variable Setup](#environment-variable-setup-assuming-bash) +1. [Command Line Usage](#command-line-usage) +1. [Script Usage](#script-usage) +1. [Configuration Files](#configuration-files) +1. [Common Configuration File Options](#common-configuration-file-options) +1. [Output Files](#output-files) + + + +## Environment Variable Setup (assuming bash) +Environment configuration is the same as described in [basic SRAM usage](./basic_usage#environment-variable-setup-assuming-bash) + + +## Accepted Data formats +OpenROM currently supports input data formatted as a binary file or a text file +of hexadecimal-encoded data. For hexadecimal data, the input file must contain +a single line of hexadecimal text. The data in any input file will be written +the ROM in the order it appears in the input file, ie. the first bit in the input +will be written to address 0. + +## Command Line Usage +Once you have defined the environment, you can run OpenROM from the command line +using a single configuration file written in Python. You can then run OpenROM by +executing: +``` +python3 $OPENRAM_HOME/../rom_compiler.py myconfig +``` +You can see all of the options for the configuration file in +$OPENRAM\_HOME/options.py + +To run macros, it is suggested to use, for example: +``` +cd OpenRAM/macros/rom_configs +make sky130_rom_1kbyte +``` + +* Common arguments: + * `-h` print all arguments + * `-t` specify technology (currently only sky130 is supported) + * `-v` increase verbosity of output + * `-n` don't run DRC/LVS + * `-d` don't purge /tmp directory contents + + +## Configuration Files +* Shares some configuration options with SRAM compiler. +* Complete configuration options are in `$OPENRAM_HOME/options.py` +* Some options can be specified on the command line as well + * Not recommended for replicating results +* Example configuration file: + ```python + + # Data word size + word_size = 2 + + # Enable LVS/DRC checking + check_lvsdrc = True + + # Path to input data. Either binary file or hex. + rom_data = "data_1kbyte.bin" + # Format type of input data + data_type = "bin" + + # Technology to use in $OPENRAM_TECH, currently only sky130 is supported + tech_name = "sky130" + + # Output directory for the results + output_path = "temp" + # Output file base name + output_name = "rom_1kbyte" + + # Only nominal process corner generation is currently supported + nominal_corner_only = True + + # Add a supply ring to the generated layout + route_supplies = "ring" + ``` + + +## Output Files +The output files are placed in the `output_dir` defined in the configuration +file. + +The base name is specified by `output_name` and suffixes are added. Currently only layout and schematic files are generated. + +The final results files are: +* GDS (.gds) +* SPICE (.sp) +* Log (.log) +* Configuration (.py) for replication of creation diff --git a/docs/source/basic_setup.md b/docs/source/basic_setup.md index 0e901e13..af73ae55 100644 --- a/docs/source/basic_setup.md +++ b/docs/source/basic_setup.md @@ -1,7 +1,7 @@ ### [Go Back](./index.md#table-of-contents) # Basic Setup -This page shows the basic setup for using OpenRAM. +This page shows the basic setup for using OpenRAM to generate an SRAM. diff --git a/docs/source/basic_usage.md b/docs/source/basic_usage.md index 7550137f..01523418 100644 --- a/docs/source/basic_usage.md +++ b/docs/source/basic_usage.md @@ -1,7 +1,7 @@ ### [Go Back](./index.md#table-of-contents) # Basic Usage -This page of the documentation explains the basic usage of OpenRAM. +This page of the documentation explains the basic usage of OpenRAM's SRAM compiler. For usage of the ROM compiler see [here](./basic_rom_usage.md#go-back) diff --git a/docs/source/index.md b/docs/source/index.md index 9687ae11..a1f7079a 100644 --- a/docs/source/index.md +++ b/docs/source/index.md @@ -11,7 +11,8 @@ navigate through the documentation. 1. [Supported Technologies](#supported-technologies) 1. [Online Playground](./OpenRAM.ipynb) 1. [Basic Setup](./basic_setup.md#go-back) -1. [Basic Usage](./basic_usage.md#go-back) +1. [Basic SRAM Usage](./basic_usage.md#go-back) +1. [Basic ROM Usage](./basic_rom_usage.md#go-back) 1. [Python Library](./python_library.md#go-back) 1. [Bitcells](./bitcells.md#go-back) 1. [Architecture](./architecture.md#go-back) @@ -115,4 +116,5 @@ Commercial tools (optional): * Tom Golubev * Marcelo Sero * Seokjoong Kim + * Sage Walker diff --git a/macros/Makefile b/macros/Makefile index e555f3a0..b50db045 100644 --- a/macros/Makefile +++ b/macros/Makefile @@ -6,6 +6,7 @@ include $(TOP_DIR)/openram.mk SKY130_PDK ?= $(PDK_ROOT)/sky130A +OPENRAM_DIR = $(MACRO_DIR) OPENRAM_OPTS := $(OPENRAM_OPTS) # Define `OPENRAM_FULL` in your environment to run a full characterize ifeq ($(OPENRAM_FULL),) @@ -27,6 +28,8 @@ ROM_SRCS=$(filter-out disabled-% %_common.py,$(sort $(notdir $(wildcard $(ROM_CO ROM_DIRS=$(basename $(ROM_SRCS)) ROM_STAMPS=$(addsuffix .ok,$(ROM_DIRS)) +DIRS=$(SRAM_DIRS) $(ROM_DIRS) + configs: @echo @echo "Using OpenRAM at $(OPENRAM_HOME)" @@ -40,7 +43,7 @@ configs: .PHONY: configs -BROKEN := +BROKEN := WORKING_SRAM_STAMPS=$(filter-out $(addsuffix .ok, $(BROKEN)), $(SRAM_STAMPS)) WORKING_ROM_STAMPS=$(filter-out $(addsuffix .ok, $(BROKEN)), $(ROM_STAMPS)) @@ -50,7 +53,7 @@ SKY130_STAMPS=$(filter sky130%, $(WORKING_SRAM_STAMPS)) $(filter sky130%, $(WORK FREEPDK45_STAMPS=$(filter freepdk45%, $(WORKING_STAMPS)) $(filter freepdk45%, $(WORKING_ROM_STAMPS)) SCN4M_SUBM_STAMPS=$(filter scn4m_subm%, $(WORKING_STAMPS)) $(filter scn4m_subm%, $(WORKING_ROM_STAMPS)) -all: | configs +all: | configs @echo @echo "Building following working configs" @for S in $(WORKING_STAMPS); do echo " - $$S"; done @@ -75,16 +78,16 @@ rom: $(WORKING_ROM_STAMPS) sram: $(WORKING_SRAM_STAMPS) .PHONY: sram - + %.ok: sram_configs/%.py @echo "Building $*" @mkdir -p $* - @python3 -u $(SRAM_COMPILER) $(OPENRAM_OPTS) -o $* -p $(MACRO_DIR)/$* $(MACRO_DIR)/$< && touch $@ + @OPENRAM_TMP=$*/tmp python3 -u $(SRAM_COMPILER) $(OPENRAM_OPTS) -o $* -p $(MACRO_DIR)/$* $(MACRO_DIR)/$< && touch $@ %.ok: rom_configs/%.py @echo "Building $*" @mkdir -p $* - @python3 -u $(ROM_COMPILER) $(OPENRAM_OPTS) -o $* -p $(MACRO_DIR)/$* $(MACRO_DIR)/$< && touch $@ + @OPENRAM_TMP=$*/tmp python3 -u $(ROM_COMPILER) $(OPENRAM_OPTS) -o $* -p $(MACRO_DIR)/$* $(MACRO_DIR)/$< && touch $@ .DELETE_ON_ERROR: $(WORKING_SRAM_STAMPS) $(WORKING_ROM_STAMPS) diff --git a/macros/rom_configs/example_1kbyte.bin b/macros/rom_configs/example_1kbyte.bin new file mode 100644 index 00000000..0cd121dd Binary files /dev/null and b/macros/rom_configs/example_1kbyte.bin differ diff --git a/macros/rom_configs/example_1kbyte.dat b/macros/rom_configs/example_1kbyte.hex similarity index 100% rename from macros/rom_configs/example_1kbyte.dat rename to macros/rom_configs/example_1kbyte.hex diff --git a/macros/rom_configs/sky130_rom_1kbyte.py b/macros/rom_configs/sky130_rom_1kbyte.py index 1f598070..55beed78 100644 --- a/macros/rom_configs/sky130_rom_1kbyte.py +++ b/macros/rom_configs/sky130_rom_1kbyte.py @@ -10,7 +10,8 @@ word_size = 1 check_lvsdrc = True -rom_data = "macros/rom_configs/example_1kbyte.dat" +rom_data = "rom_configs/example_1kbyte.bin" +data_type = "bin" output_name = "rom_1kbyte" output_path = "macro/{output_name}".format(**locals()) diff --git a/macros/rom_configs/sky130_rom_common.py b/macros/rom_configs/sky130_rom_common.py index d36887bf..40bc3666 100644 --- a/macros/rom_configs/sky130_rom_common.py +++ b/macros/rom_configs/sky130_rom_common.py @@ -1,4 +1,10 @@ - +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# tech_name = "sky130" nominal_corner_only = True diff --git a/technology/sky130/custom/sky130_capped_replica_bitcell_array.py b/technology/sky130/custom/sky130_capped_replica_bitcell_array.py index 86d9925c..ab79fce3 100644 --- a/technology/sky130/custom/sky130_capped_replica_bitcell_array.py +++ b/technology/sky130/custom/sky130_capped_replica_bitcell_array.py @@ -30,9 +30,19 @@ class sky130_capped_replica_bitcell_array(sky130_bitcell_base_array): self.add_comment("rows: {0} cols: {1}".format(rows, cols)) self.add_comment("rbl: {0} left_rbl: {1} right_rbl: {2}".format(rbl, left_rbl, right_rbl)) + # This is how many RBLs are in all the arrays self.rbl = rbl - self.left_rbl = left_rbl - self.right_rbl = right_rbl + # This specifies which RBL to put on the left or right by port number + # This could be an empty list + if left_rbl is not None: + self.left_rbl = left_rbl + else: + self.left_rbl = [] + # This could be an empty list + if right_rbl is not None: + self.right_rbl = right_rbl + else: + self.right_rbl = [] self.create_netlist() if not OPTS.netlist_only: