From 6d6063ef4eeb4cf3715afbfd4312e273d0c3fe67 Mon Sep 17 00:00:00 2001 From: Bugra Onal Date: Thu, 9 Jun 2022 21:40:19 -0700 Subject: [PATCH] modified template engine & sram multibank class --- compiler/base/verilog.py | 2 +- compiler/modules/sram.py | 13 +- compiler/modules/sram_2bank.py | 240 ------------------- compiler/modules/sram_config.py | 4 +- compiler/modules/sram_multibank.py | 27 +++ compiler/modules/sram_multibank_template.v | 146 +++++++++++ compiler/sram/multibank_template.v | 73 ------ compiler/verilogTemplate/template.py | 72 ++++++ compiler/verilogTemplate/test.py | 29 ++- compiler/verilogTemplate/test.v | 65 ----- compiler/verilogTemplate/verilog_template.py | 115 --------- 11 files changed, 273 insertions(+), 513 deletions(-) delete mode 100644 compiler/modules/sram_2bank.py create mode 100644 compiler/modules/sram_multibank.py create mode 100644 compiler/modules/sram_multibank_template.v delete mode 100644 compiler/sram/multibank_template.v create mode 100644 compiler/verilogTemplate/template.py delete mode 100644 compiler/verilogTemplate/test.v delete mode 100644 compiler/verilogTemplate/verilog_template.py 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/modules/sram.py b/compiler/modules/sram.py index 70d8afce..4d620e1e 100644 --- a/compiler/modules/sram.py +++ b/compiler/modules/sram.py @@ -36,14 +36,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/modules/sram_2bank.py b/compiler/modules/sram_2bank.py deleted file mode 100644 index 69ecb496..00000000 --- a/compiler/modules/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 base import vector -from globals import OPTS, print_time - -from .sram_base import sram_base -from modules import bank -from modules import dff_buf_array -from modules 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()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/verilogTemplate/template.py b/compiler/verilogTemplate/template.py new file mode 100644 index 00000000..d48321b5 --- /dev/null +++ b/compiler/verilogTemplate/template.py @@ -0,0 +1,72 @@ +import re + +class baseSection: + children = [] + + def expand(self, dict, fd): + for c in self.children: + c.expand(dict, fd) + +class loopSection(baseSection): + + def __init__(self, var, key): + self.children = [] + self.var = var + self.key = key + + def expand(self, dict, fd): + for ind in dict[self.key]: + dict[self.var] = ind + for c in self.children: + c.expand(dict, fd) + if self.var in dict: + del dict[self.var] + +class textSection(baseSection): + + def __init__(self, text): + self.text = text + + def expand(self, dict): + var_re = re.compile('\{\{ (\S*) \}\}') + vars = var_re.finditer(self.text) + newText = self.text + for var in vars: + newText = newText.replace('{{ ' + var.group(1) + ' }}', str(dict[var.group(1)])) + print(newText, end='', file=fd) + +class template: + + def __init__(self, template, dict): + self.template = template + self.dict = dict + + def readTemplate(self): + lines = [] + with open(self.template, 'r') as f: + lines = f.readlines() + + self.baseSectionSection = baseSection() + sections = [] + context = [self.baseSectionSection] + for_re = re.compile('\{% for (\S*) in (\S*) %\}') + end_re = re.compile('\{% endfor %\}') + for line in lines: + m = for_re.match(line) + if m: + section = loopSection(m.group(1), m.group(2)) + sections.append(section) + context[-1].children.append(section) + context.append(section) + continue + if end_re.match(line): + context.pop() + else: + context[-1].children.append(textSection(line)) + + def write(self, filename): + fd = open(filename, 'w') + self.readTemplate() + self.baseSectionSection.expand(self.dict, fd) + fd.close() + diff --git a/compiler/verilogTemplate/test.py b/compiler/verilogTemplate/test.py index 73033914..228b5042 100644 --- a/compiler/verilogTemplate/test.py +++ b/compiler/verilogTemplate/test.py @@ -1,13 +1,20 @@ -from verilog_template import verilog_template +from template import template -t = verilog_template('../sram/multibank_template.v') -t.readTemplate() -t.setSectionRepeat('RW_PORTS', 1) -t.setSectionRepeat('R_PORTS', 0) -t.setSectionRepeat('BANK_DEFS', 2) -t.setSectionRepeat('BANK_INIT', 2) -t.setSectionRepeat('BANK_CASE', 2) -t.setTextDict('PORT_NUM', 0) +dict = { + 'module_name': 'sram_1kbyte_32b_2bank', + 'bank_module_name': 'sram_1kbyte_32b_2bank_1bank', + 'vdd': 'vdd', + 'gnd': 'gnd', + 'ports': [0, 1], + 'rw_ports': [0], + 'r_ports': [1], + 'w_ports': [], + 'banks': [0, 1], + 'data_width': 32, + 'addr_width': 8, + 'bank_sel': 1, + 'num_wmask': 4 + } +t = template('../sram/sram_multibank_template.v', dict) +t.write(dict['module_name'] + '.v') - -t.generate('test.v') diff --git a/compiler/verilogTemplate/test.v b/compiler/verilogTemplate/test.v deleted file mode 100644 index 390f9f47..00000000 --- a/compiler/verilogTemplate/test.v +++ /dev/null @@ -1,65 +0,0 @@ - -module multibank # ( - DATA_WIDTH = 32, - ADDR_WIDTH= 8, - NUM_BANKS=2 -)( - clk, - addr, - din, - csb, - web, - dout - ); - - 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; - - reg csb0; - reg web0; - reg [DATA_WIDTH - 1 : 0] dout0; - reg csb1; - reg web1; - reg [DATA_WIDTH - 1 : 0] dout1; - - bank #(DATA_WIDTH, ADDR_WIDTH) bank0 ( - .clk(clk), - .addr(addr[ADDR_WIDTH - BANK_SEL - 1 : 0]), - .din(din), - .csb(csb0), - .web(web0), - .dout(dout0) - ); - bank #(DATA_WIDTH, ADDR_WIDTH) bank1 ( - .clk(clk), - .addr(addr[ADDR_WIDTH - BANK_SEL - 1 : 0]), - .din(din), - .csb(csb1), - .web(web1), - .dout(dout1) - ); - -always @(posedge clk) begin - case (addr[ADDR_WIDTH - 1 : ADDR_WIDTH - BANK_SEL]) - 0: begin - dout <= dout0; - web0 <= web; - end - 1: begin - dout <= dout1; - web1 <= web; - end - endcase -end - -endmodule diff --git a/compiler/verilogTemplate/verilog_template.py b/compiler/verilogTemplate/verilog_template.py deleted file mode 100644 index f1945f54..00000000 --- a/compiler/verilogTemplate/verilog_template.py +++ /dev/null @@ -1,115 +0,0 @@ - -class text_section: - - def __init__(self, name, parent): - self.name = name - self.parent = parent - self.lines = [] - self.sections = [] - self.sectionPos = [] - self.lineNum = 0 - self.repeat = 1 - self.index = -1 - - def addLine(self, line): - self.lines.append(line) - self.lineNum+= 1 - - def addSection(self, section): - self.sections.append(section) - self.sectionPos.append(self.lineNum) - section.index = len(self.sections) - 1 - - def clone(self, cloneName): - other = text_section(cloneName, self.parent) - other.sections = self.sections.copy() - other.sectionPos = self.sectionPos.copy() - other.repeat = self.repeat - self.parent.sections.insert(self.index + 1, other) - - def expand(self): - expanded = [] - pos = 0 - if self.repeat == 0: - return [] - if len(self.sections) == 0: - return self.lines * self.repeat - - for s, sPos in zip(self.sections, self.sectionPos): - if pos < sPos: - expanded += self.lines[pos:sPos] - pos = sPos - expanded += s.expand() - - if pos < self.lineNum: - expanded += self.lines[pos:] - - if self.repeat > 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)