diff --git a/compiler/base/verilog.py b/compiler/base/verilog.py index a2978925..2c91cbba 100644 --- a/compiler/base/verilog.py +++ b/compiler/base/verilog.py @@ -7,7 +7,7 @@ # import math from tech import spice -import verilog_template +from verilog_template import verilog_template class verilog: diff --git a/compiler/sram/multibank_template.v b/compiler/sram/multibank_template.v deleted file mode 100644 index d5724cb6..00000000 --- a/compiler/sram/multibank_template.v +++ /dev/null @@ -1,73 +0,0 @@ - -module multibank # ( - DATA_WIDTH = 32, - ADDR_WIDTH= 8, - NUM_BANKS=2 -)( -#RW_PORTS -#R_PORTS - ); - - parameter RAM_DEPTH = 1 << ADDR_WIDTH; - parameter BANK_SEL = (NUM_BANKS <= 2)? 1 : - (NUM_BANKS <= 4)? 2 : - (NUM_BANKS <= 8)? 3 : - (NUM_BANKS <= 16)? 4 : 5; - - input clk; - input [ADDR_WIDTH -1 : 0] addr; - input [DATA_WIDTH - 1: 0] din; - input csb; - input web; - output reg [DATA_WIDTH - 1 : 0] dout; - -#!PORT_NUM!0# -#BANK_DEFS - -#!PORT_NUM!0# -#BANK_RW_PORTS - ); -#>BANK_INIT - -always @(posedge clk) begin - case (addr[ADDR_WIDTH - 1 : ADDR_WIDTH - BANK_SEL]) -#!PORT_NUM!0# -#BANK_CASE - endcase -end - -endmodule diff --git a/compiler/sram/sram.py b/compiler/sram/sram.py index 90855d8e..9f460c7a 100644 --- a/compiler/sram/sram.py +++ b/compiler/sram/sram.py @@ -37,14 +37,15 @@ class sram(): self.name = name - if self.num_banks == 1: - from sram_1bank import sram_1bank as sram - elif self.num_banks == 2: - from sram_2bank import sram_2bank as sram - else: - debug.error("Invalid number of banks.", -1) + from sram_1bank import sram_1bank as sram self.s = sram(name, sram_config) + + if self.num_banks != 1: + from sram_multibank import sram_multibank + mb = sram_multibank(s) + mb.verilog_write() + self.s.create_netlist() if not OPTS.netlist_only: self.s.create_layout() diff --git a/compiler/sram/sram_2bank.py b/compiler/sram/sram_2bank.py deleted file mode 100644 index 421641ac..00000000 --- a/compiler/sram/sram_2bank.py +++ /dev/null @@ -1,240 +0,0 @@ -# See LICENSE for licensing information. -# -# Copyright (c) 2016-2021 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 -from tech import drc, spice -import debug -from math import log,sqrt,ceil -import datetime -import getpass -from vector import vector -from globals import OPTS, print_time - -from sram_base import sram_base -from bank import bank -from dff_buf_array import dff_buf_array -from dff_array import dff_array - -class sram_2bank(sram_base): - """ - Procedures specific to a two bank SRAM. - """ - def __init__(self, name, sram_config): - sram_base.__init__(self, name, sram_config) - - def compute_bank_offsets(self): - """ Compute the overall offsets for a two bank SRAM """ - - # In 2 bank SRAM, the height is determined by the control bus which is higher than the msb address - self.vertical_bus_height = self.bank.height + 2*self.bank_to_bus_distance + self.data_bus_height + self.control_bus_height - # The address bus extends down through the power rails, but control and bank_sel bus don't - self.addr_bus_height = self.vertical_bus_height - - self.vertical_bus_offset = vector(self.bank.width + self.bank_to_bus_distance, 0) - self.data_bus_offset = vector(0, self.bank.height + self.bank_to_bus_distance) - self.supply_bus_offset = vector(0, self.data_bus_offset.y + self.data_bus_height) - self.control_bus_offset = vector(0, self.supply_bus_offset.y + self.supply_bus_height) - self.bank_sel_bus_offset = self.vertical_bus_offset + vector(self.m2_pitch*self.control_size,0) - self.addr_bus_offset = self.bank_sel_bus_offset.scale(1,0) + vector(self.m2_pitch*self.num_banks,0) - - # Control is placed at the top above the control bus and everything - self.control_logic_position = vector(0, self.control_bus_offset.y + self.control_bus_height + self.m1_pitch) - - # Bank select flops get put to the right of control logic above bank1 and the buses - # Leave a pitch to get the vdd rails up to M2 - self.msb_address_position = vector(self.bank_inst[1].lx() + 3*self.supply_rail_pitch, - self.supply_bus_offset.y + self.supply_bus_height \ - + 2*self.m1_pitch + self.msb_address.width) - - def add_modules(self): - """ Adds the modules and the buses to the top level """ - - self.compute_bus_sizes() - - self.add_banks() - - self.compute_bank_offsets() - - self.add_busses() - - self.add_logic() - - self.width = self.bank_inst[1].ur().x - self.height = self.control_logic_inst.uy() - - - - def add_banks(self): - # Placement of bank 0 (left) - bank_position_0 = vector(self.bank.width, - self.bank.height) - self.bank_inst=[self.add_bank(0, bank_position_0, -1, -1)] - - # Placement of bank 1 (right) - x_off = self.bank.width + self.vertical_bus_width + 2*self.bank_to_bus_distance - bank_position_1 = vector(x_off, bank_position_0.y) - self.bank_inst.append(self.add_bank(1, bank_position_1, -1, 1)) - - def add_logic(self): - """ Add the control and MSB logic """ - - self.add_control_logic(position=self.control_logic_position) - - self.msb_address_inst = self.add_inst(name="msb_address", - mod=self.msb_address, - offset=self.msb_address_position, - rotate=270) - self.msb_bank_sel_addr = "addr[{}]".format(self.addr_size-1) - self.connect_inst([self.msb_bank_sel_addr,"bank_sel[1]","bank_sel[0]","clk_buf", "vdd", "gnd"]) - - - def route_shared_banks(self): - """ Route the shared signals for two and four bank configurations. """ - - # create the input control pins - for n in self.control_logic_inputs + ["clk"]: - self.copy_layout_pin(self.control_logic_inst, n) - - # connect the control logic to the control bus - for n in self.control_logic_outputs + ["vdd", "gnd"]: - pins = self.control_logic_inst.get_pins(n) - for pin in pins: - if pin.layer=="m2": - pin_pos = pin.bc() - break - rail_pos = vector(pin_pos.x,self.horz_control_bus_positions[n].y) - self.add_path("m2",[pin_pos,rail_pos]) - self.add_via_center(self.m1_stack,rail_pos) - - # connect the control logic cross bar - for n in self.control_logic_outputs: - cross_pos = vector(self.vert_control_bus_positions[n].x,self.horz_control_bus_positions[n].y) - self.add_via_center(self.m1_stack,cross_pos) - - # connect the bank select signals to the vertical bus - for i in range(self.num_banks): - pin = self.bank_inst[i].get_pin("bank_sel") - pin_pos = pin.rc() if i==0 else pin.lc() - rail_pos = vector(self.vert_control_bus_positions["bank_sel[{}]".format(i)].x,pin_pos.y) - self.add_path("m3",[pin_pos,rail_pos]) - self.add_via_center(self.m2_stack,rail_pos) - - def route_single_msb_address(self): - """ Route one MSB address bit for 2-bank SRAM """ - - # connect the bank MSB flop supplies - vdd_pins = self.msb_address_inst.get_pins("vdd") - for vdd_pin in vdd_pins: - if vdd_pin.layer != "m1": continue - vdd_pos = vdd_pin.bc() - down_pos = vdd_pos - vector(0,self.m1_pitch) - rail_pos = vector(vdd_pos.x,self.horz_control_bus_positions["vdd"].y) - self.add_path("m1",[vdd_pos,down_pos]) - self.add_via_center(self.m1_stack,down_pos,rotate=90) - self.add_path("m2",[down_pos,rail_pos]) - self.add_via_center(self.m1_stack,rail_pos) - - gnd_pins = self.msb_address_inst.get_pins("gnd") - # Only add the ground connection to the lowest metal2 rail in the flop array - # FIXME: SCMOS doesn't have a vertical rail in the cell, or we could use those - lowest_y = None - for gnd_pin in gnd_pins: - if gnd_pin.layer != "m2": continue - if lowest_y==None or gnd_pin.by() 1: - expanded = expanded * self.repeat - - return expanded - - -class verilog_template: - - def __init__(self, template): - self.template = template - self.sections = {} - self.textDict = {} - self.baseSection = None - self.expanded = None - - def readTemplate(self): - lines = [] - with open(self.template, 'r') as f: - lines = f.readlines() - self.baseSection = text_section('base', None) - currentSection = self.baseSection - for line in lines: - if line[:2] == '#<': - section = text_section(line[2:].strip('\n'), currentSection) - currentSection.addSection(section) - currentSection = section - elif line[:2] == '#>' and line[2:].strip('\n') == currentSection.name: - self.sections[currentSection.name] = currentSection - currentSection = currentSection.parent - else: - currentSection.addLine(line) - - def expand(self): - self.expanded = self.baseSection.expand() - - def postProcess(self): - text = "" - for line in self.expanded: - if '#$' in line: - while True: - indStart = line.find('#$') - if indStart == -1: - break - indEnd = line.find('$#') - line = line[:indStart] + str(self.textDict[line[indStart + 2:indEnd]]) + line[indEnd + 2:] - text += line - elif '#!' in line: - indLabelStart = line.find('#!') + 2 - indLabelEnd = line.find('!', indLabelStart) - label = line[indLabelStart:indLabelEnd] - self.textDict[label] = eval(line[indLabelEnd + 1:-1], self.textDict) - else: - text += line - return text - - def generate(self, filename): - self.expand() - text = self.postProcess() - with open(filename, 'w') as f: - f.write(text) - - def setSectionRepeat(self, name, repeat): - self.sections[name].repeat = repeat - - def setTextDict(self, label, value): - self.textDict[label] = value - - def cloneSection(self, name, cloneName): - self.sections[name].clone(cloneName)