mirror of https://github.com/VLSIDA/OpenRAM.git
Replace data flops depending on channel width
This commit is contained in:
parent
2ccf3aea3b
commit
a36e89e103
|
|
@ -10,6 +10,8 @@ from vector import vector
|
||||||
from sram_base import sram_base
|
from sram_base import sram_base
|
||||||
from contact import m2_via
|
from contact import m2_via
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
|
import channel_route
|
||||||
|
|
||||||
|
|
||||||
class sram_1bank(sram_base):
|
class sram_1bank(sram_base):
|
||||||
"""
|
"""
|
||||||
|
|
@ -58,12 +60,14 @@ class sram_1bank(sram_base):
|
||||||
# the sense amps/column mux and cell array)
|
# the sense amps/column mux and cell array)
|
||||||
# The x-coordinate is placed to allow a single clock wire (plus an extra pitch)
|
# The x-coordinate is placed to allow a single clock wire (plus an extra pitch)
|
||||||
# up to the row address DFFs.
|
# up to the row address DFFs.
|
||||||
control_pos = [None] * len(self.all_ports)
|
self.control_pos = [None] * len(self.all_ports)
|
||||||
row_addr_pos = [None] * len(self.all_ports)
|
self.row_addr_pos = [None] * len(self.all_ports)
|
||||||
col_addr_pos = [None] * len(self.all_ports)
|
|
||||||
wmask_pos = [None] * len(self.all_ports)
|
# DFFs are placd on their own
|
||||||
spare_wen_pos = [None] * len(self.all_ports)
|
self.col_addr_pos = [None] * len(self.all_ports)
|
||||||
data_pos = [None] * len(self.all_ports)
|
self.wmask_pos = [None] * len(self.all_ports)
|
||||||
|
self.spare_wen_pos = [None] * len(self.all_ports)
|
||||||
|
self.data_pos = [None] * len(self.all_ports)
|
||||||
|
|
||||||
# These positions utilize the channel route sizes.
|
# These positions utilize the channel route sizes.
|
||||||
# FIXME: Auto-compute these rather than manual computation.
|
# FIXME: Auto-compute these rather than manual computation.
|
||||||
|
|
@ -75,9 +79,11 @@ class sram_1bank(sram_base):
|
||||||
# Spare wen are on a separate layer so not included
|
# Spare wen are on a separate layer so not included
|
||||||
# Start with 1 track minimum
|
# Start with 1 track minimum
|
||||||
self.data_bus_size = [1] * len(self.all_ports)
|
self.data_bus_size = [1] * len(self.all_ports)
|
||||||
|
self.col_addr_bus_size = [1] * len(self.all_ports)
|
||||||
for port in self.all_ports:
|
for port in self.all_ports:
|
||||||
|
# The column address wires are routed separately from the data bus and will always be smaller.
|
||||||
# All ports need the col addr flops
|
# All ports need the col addr flops
|
||||||
self.data_bus_size[port] += self.col_addr_size
|
self.col_addr_bus_size[port] = self.col_addr_size * self.m4_nonpref_pitch
|
||||||
# Write ports need the data input flops and write mask flops
|
# Write ports need the data input flops and write mask flops
|
||||||
if port in self.write_ports:
|
if port in self.write_ports:
|
||||||
self.data_bus_size[port] += self.num_wmasks + self.word_size
|
self.data_bus_size[port] += self.num_wmasks + self.word_size
|
||||||
|
|
@ -89,119 +95,146 @@ class sram_1bank(sram_base):
|
||||||
self.data_bus_size[port] *= self.m4_nonpref_pitch
|
self.data_bus_size[port] *= self.m4_nonpref_pitch
|
||||||
# Add the gap in unit length
|
# Add the gap in unit length
|
||||||
self.data_bus_size[port] += self.data_bus_gap
|
self.data_bus_size[port] += self.data_bus_gap
|
||||||
|
|
||||||
# Port 0
|
|
||||||
port = 0
|
|
||||||
|
|
||||||
# This includes 2 M2 pitches for the row addr clock line.
|
# The control and row addr flops are independent of any bus widths.
|
||||||
# The delay line is aligned with the bitcell array while the control logic is aligned with the port_data
|
self.place_control()
|
||||||
# using the control_logic_center value.
|
self.place_row_addr_dffs()
|
||||||
control_pos[port] = vector(-self.control_logic_insts[port].width - 2 * self.m2_pitch,
|
|
||||||
self.bank.bank_array_ll.y - self.control_logic_insts[port].mod.control_logic_center.y)
|
# Place with an initial wide channel (from above)
|
||||||
self.control_logic_insts[port].place(control_pos[port])
|
self.place_dffs()
|
||||||
|
# Route the channel and set to the new data bus size
|
||||||
|
self.route_dffs(add_routes=False)
|
||||||
|
# Re-place with the new channel size
|
||||||
|
self.place_dffs()
|
||||||
|
# Now route the channel
|
||||||
|
self.route_dffs()
|
||||||
|
|
||||||
|
def place_row_addr_dffs(self):
|
||||||
|
"""
|
||||||
|
Must be run after place control logic.
|
||||||
|
"""
|
||||||
|
port = 0
|
||||||
# The row address bits are placed above the control logic aligned on the right.
|
# The row address bits are placed above the control logic aligned on the right.
|
||||||
x_offset = self.control_logic_insts[port].rx() - self.row_addr_dff_insts[port].width
|
x_offset = self.control_logic_insts[port].rx() - self.row_addr_dff_insts[port].width
|
||||||
# It is above the control logic but below the top of the bitcell array
|
# It is above the control logic but below the top of the bitcell array
|
||||||
y_offset = max(self.control_logic_insts[port].uy(), self.bank_inst.uy() - self.row_addr_dff_insts[port].height)
|
y_offset = max(self.control_logic_insts[port].uy(), self.bank_inst.uy() - self.row_addr_dff_insts[port].height)
|
||||||
row_addr_pos[port] = vector(x_offset, y_offset)
|
self.row_addr_pos[port] = vector(x_offset, y_offset)
|
||||||
self.row_addr_dff_insts[port].place(row_addr_pos[port])
|
self.row_addr_dff_insts[port].place(self.row_addr_pos[port])
|
||||||
|
|
||||||
|
if len(self.all_ports)>1:
|
||||||
|
port = 1
|
||||||
|
# The row address bits are placed above the control logic aligned on the left.
|
||||||
|
x_offset = self.control_pos[port].x - self.control_logic_insts[port].width + self.row_addr_dff_insts[port].width
|
||||||
|
# It is below the control logic but below the bottom of the bitcell array
|
||||||
|
y_offset = min(self.control_logic_insts[port].by(), self.bank_inst.by() + self.row_addr_dff_insts[port].height)
|
||||||
|
self.row_addr_pos[port] = vector(x_offset, y_offset)
|
||||||
|
self.row_addr_dff_insts[port].place(self.row_addr_pos[port], mirror="XY")
|
||||||
|
|
||||||
|
def place_control(self):
|
||||||
|
port = 0
|
||||||
|
|
||||||
|
# This includes 2 M2 pitches for the row addr clock line.
|
||||||
|
# The delay line is aligned with the bitcell array while the control logic is aligned with the port_data
|
||||||
|
# using the control_logic_center value.
|
||||||
|
self.control_pos[port] = vector(-self.control_logic_insts[port].width - 2 * self.m2_pitch,
|
||||||
|
self.bank.bank_array_ll.y - self.control_logic_insts[port].mod.control_logic_center.y)
|
||||||
|
self.control_logic_insts[port].place(self.control_pos[port])
|
||||||
|
if len(self.all_ports) > 1:
|
||||||
|
port = 1
|
||||||
|
# This includes 2 M2 pitches for the row addr clock line
|
||||||
|
# The delay line is aligned with the bitcell array while the control logic is aligned with the port_data
|
||||||
|
# using the control_logic_center value.
|
||||||
|
self.control_pos[port] = vector(self.bank_inst.rx() + self.control_logic_insts[port].width + 2 * self.m2_pitch,
|
||||||
|
self.bank.bank_array_ur.y
|
||||||
|
+ self.control_logic_insts[port].height
|
||||||
|
- self.control_logic_insts[port].height
|
||||||
|
+ self.control_logic_insts[port].mod.control_logic_center.y)
|
||||||
|
self.control_logic_insts[port].place(self.control_pos[port], mirror="XY")
|
||||||
|
|
||||||
|
def place_dffs(self):
|
||||||
|
"""
|
||||||
|
Place the col addr, data, wmask, and spare data DFFs.
|
||||||
|
This can be run more than once after we recompute the channel width.
|
||||||
|
"""
|
||||||
|
|
||||||
|
port = 0
|
||||||
# Add the col address flops below the bank to the right of the control logic
|
# Add the col address flops below the bank to the right of the control logic
|
||||||
x_offset = self.control_logic_insts[port].rx() + self.dff.width
|
x_offset = self.control_logic_insts[port].rx() + self.dff.width
|
||||||
y_offset = - self.data_bus_size[port] - self.dff.height
|
y_offset = - self.data_bus_size[port] - self.dff.height
|
||||||
if self.col_addr_dff:
|
if self.col_addr_dff:
|
||||||
col_addr_pos[port] = vector(x_offset,
|
self.col_addr_pos[port] = vector(x_offset,
|
||||||
y_offset)
|
y_offset)
|
||||||
self.col_addr_dff_insts[port].place(col_addr_pos[port])
|
self.col_addr_dff_insts[port].place(self.col_addr_pos[port])
|
||||||
x_offset = self.col_addr_dff_insts[port].rx()
|
x_offset = self.col_addr_dff_insts[port].rx()
|
||||||
else:
|
else:
|
||||||
col_addr_pos[port] = vector(x_offset, 0)
|
self.col_addr_pos[port] = vector(x_offset, 0)
|
||||||
|
|
||||||
if port in self.write_ports:
|
if port in self.write_ports:
|
||||||
if self.write_size:
|
if self.write_size:
|
||||||
# Add the write mask flops below the write mask AND array.
|
# Add the write mask flops below the write mask AND array.
|
||||||
wmask_pos[port] = vector(x_offset,
|
self.wmask_pos[port] = vector(x_offset,
|
||||||
y_offset)
|
y_offset)
|
||||||
self.wmask_dff_insts[port].place(wmask_pos[port])
|
self.wmask_dff_insts[port].place(self.wmask_pos[port])
|
||||||
x_offset = self.wmask_dff_insts[port].rx()
|
x_offset = self.wmask_dff_insts[port].rx()
|
||||||
|
|
||||||
# Add the data flops below the write mask flops.
|
# Add the data flops below the write mask flops.
|
||||||
data_pos[port] = vector(x_offset,
|
self.data_pos[port] = vector(x_offset,
|
||||||
y_offset)
|
y_offset)
|
||||||
self.data_dff_insts[port].place(data_pos[port])
|
self.data_dff_insts[port].place(self.data_pos[port])
|
||||||
x_offset = self.data_dff_insts[port].rx()
|
x_offset = self.data_dff_insts[port].rx()
|
||||||
|
|
||||||
# Add spare write enable flops to the right of data flops since the spare columns
|
# Add spare write enable flops to the right of data flops since the spare columns
|
||||||
# will be on the right
|
# will be on the right
|
||||||
if self.num_spare_cols:
|
if self.num_spare_cols:
|
||||||
spare_wen_pos[port] = vector(x_offset,
|
self.spare_wen_pos[port] = vector(x_offset,
|
||||||
y_offset)
|
y_offset)
|
||||||
self.spare_wen_dff_insts[port].place(spare_wen_pos[port])
|
self.spare_wen_dff_insts[port].place(self.spare_wen_pos[port])
|
||||||
x_offset = self.spare_wen_dff_insts[port].rx()
|
x_offset = self.spare_wen_dff_insts[port].rx()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
wmask_pos[port] = vector(x_offset, y_offset)
|
self.wmask_pos[port] = vector(x_offset, y_offset)
|
||||||
data_pos[port] = vector(x_offset, y_offset)
|
self.data_pos[port] = vector(x_offset, y_offset)
|
||||||
spare_wen_pos[port] = vector(x_offset, y_offset)
|
self.spare_wen_pos[port] = vector(x_offset, y_offset)
|
||||||
|
|
||||||
if len(self.all_ports)>1:
|
if len(self.all_ports) > 1:
|
||||||
# Port 1
|
|
||||||
port = 1
|
port = 1
|
||||||
|
|
||||||
# This includes 2 M2 pitches for the row addr clock line
|
|
||||||
# The delay line is aligned with the bitcell array while the control logic is aligned with the port_data
|
|
||||||
# using the control_logic_center value.
|
|
||||||
control_pos[port] = vector(self.bank_inst.rx() + self.control_logic_insts[port].width + 2 * self.m2_pitch,
|
|
||||||
self.bank.bank_array_ur.y
|
|
||||||
+ self.control_logic_insts[port].height
|
|
||||||
- self.control_logic_insts[port].height
|
|
||||||
+ self.control_logic_insts[port].mod.control_logic_center.y)
|
|
||||||
self.control_logic_insts[port].place(control_pos[port], mirror="XY")
|
|
||||||
|
|
||||||
# The row address bits are placed above the control logic aligned on the left.
|
|
||||||
x_offset = control_pos[port].x - self.control_logic_insts[port].width + self.row_addr_dff_insts[port].width
|
|
||||||
# It is below the control logic but below the bottom of the bitcell array
|
|
||||||
y_offset = min(self.control_logic_insts[port].by(), self.bank_inst.by() + self.row_addr_dff_insts[port].height)
|
|
||||||
row_addr_pos[port] = vector(x_offset, y_offset)
|
|
||||||
self.row_addr_dff_insts[port].place(row_addr_pos[port], mirror="XY")
|
|
||||||
|
|
||||||
# Add the col address flops below the bank to the right of the control logic
|
# Add the col address flops below the bank to the right of the control logic
|
||||||
x_offset = self.control_logic_insts[port].lx() - 2 * self.dff.width
|
x_offset = self.control_logic_insts[port].lx() - 2 * self.dff.width
|
||||||
y_offset = self.bank.height + self.data_bus_size[port] + self.dff.height
|
y_offset = self.bank.height + self.data_bus_size[port] + self.dff.height
|
||||||
if self.col_addr_dff:
|
if self.col_addr_dff:
|
||||||
col_addr_pos[port] = vector(x_offset,
|
self.col_addr_pos[port] = vector(x_offset,
|
||||||
y_offset)
|
y_offset)
|
||||||
self.col_addr_dff_insts[port].place(col_addr_pos[port], mirror="XY")
|
self.col_addr_dff_insts[port].place(self.col_addr_pos[port], mirror="XY")
|
||||||
x_offset = self.col_addr_dff_insts[port].lx() - self.col_addr_dff_insts[port].width
|
x_offset = self.col_addr_dff_insts[port].lx() - self.col_addr_dff_insts[port].width
|
||||||
else:
|
else:
|
||||||
col_addr_pos[port] = vector(x_offset, y_offset)
|
self.col_addr_pos[port] = vector(x_offset, y_offset)
|
||||||
|
|
||||||
if port in self.write_ports:
|
if port in self.write_ports:
|
||||||
# Add spare write enable flops to the right of the data flops since the spare
|
# Add spare write enable flops to the right of the data flops since the spare
|
||||||
# columns will be on the left
|
# columns will be on the left
|
||||||
if self.num_spare_cols:
|
if self.num_spare_cols:
|
||||||
spare_wen_pos[port] = vector(x_offset - self.spare_wen_dff_insts[port].width,
|
self.spare_wen_pos[port] = vector(x_offset - self.spare_wen_dff_insts[port].width,
|
||||||
y_offset)
|
y_offset)
|
||||||
self.spare_wen_dff_insts[port].place(spare_wen_pos[port], mirror="MX")
|
self.spare_wen_dff_insts[port].place(self.spare_wen_pos[port], mirror="MX")
|
||||||
x_offset = self.spare_wen_dff_insts[port].lx()
|
x_offset = self.spare_wen_dff_insts[port].lx()
|
||||||
|
|
||||||
if self.write_size:
|
if self.write_size:
|
||||||
# Add the write mask flops below the write mask AND array.
|
# Add the write mask flops below the write mask AND array.
|
||||||
wmask_pos[port] = vector(x_offset - self.wmask_dff_insts[port].width,
|
self.wmask_pos[port] = vector(x_offset - self.wmask_dff_insts[port].width,
|
||||||
y_offset)
|
y_offset)
|
||||||
self.wmask_dff_insts[port].place(wmask_pos[port], mirror="MX")
|
self.wmask_dff_insts[port].place(self.wmask_pos[port], mirror="MX")
|
||||||
x_offset = self.wmask_dff_insts[port].lx()
|
x_offset = self.wmask_dff_insts[port].lx()
|
||||||
|
|
||||||
# Add the data flops below the write mask flops.
|
# Add the data flops below the write mask flops.
|
||||||
data_pos[port] = vector(x_offset - self.data_dff_insts[port].width,
|
self.data_pos[port] = vector(x_offset - self.data_dff_insts[port].width,
|
||||||
y_offset)
|
y_offset)
|
||||||
self.data_dff_insts[port].place(data_pos[port], mirror="MX")
|
self.data_dff_insts[port].place(self.data_pos[port], mirror="MX")
|
||||||
else:
|
else:
|
||||||
wmask_pos[port] = vector(x_offset, y_offset)
|
self.wmask_pos[port] = vector(x_offset, y_offset)
|
||||||
data_pos[port] = vector(x_offset, y_offset)
|
self.data_pos[port] = vector(x_offset, y_offset)
|
||||||
spare_wen_pos[port] = vector(x_offset, y_offset)
|
self.spare_wen_pos[port] = vector(x_offset, y_offset)
|
||||||
|
|
||||||
def add_layout_pins(self):
|
def add_layout_pins(self):
|
||||||
"""
|
"""
|
||||||
Add the top-level pins for a single bank SRAM with control.
|
Add the top-level pins for a single bank SRAM with control.
|
||||||
|
|
@ -343,10 +376,12 @@ class sram_1bank(sram_base):
|
||||||
|
|
||||||
self.route_row_addr_dff()
|
self.route_row_addr_dff()
|
||||||
|
|
||||||
|
def route_dffs(self, add_routes=True):
|
||||||
|
|
||||||
for port in self.all_ports:
|
for port in self.all_ports:
|
||||||
self.route_dff(port)
|
self.route_dff(port, add_routes)
|
||||||
|
|
||||||
def route_dff(self, port):
|
def route_dff(self, port, add_routes):
|
||||||
|
|
||||||
route_map = []
|
route_map = []
|
||||||
|
|
||||||
|
|
@ -366,12 +401,16 @@ class sram_1bank(sram_base):
|
||||||
offset = vector(0,
|
offset = vector(0,
|
||||||
self.bank.height + 2 * self.m1_space)
|
self.bank.height + 2 * self.m1_space)
|
||||||
|
|
||||||
self.create_horizontal_channel_route(netlist=route_map,
|
cr = channel_route.channel_route(netlist=route_map,
|
||||||
offset=offset,
|
offset=offset,
|
||||||
layer_stack=self.m1_stack)
|
layer_stack=self.m1_stack,
|
||||||
|
parent=self)
|
||||||
|
if add_routes:
|
||||||
|
self.add_inst("hc", cr)
|
||||||
|
self.connect_inst([])
|
||||||
|
else:
|
||||||
|
self.col_addr_bus_size[port] = cr.height
|
||||||
|
|
||||||
|
|
||||||
route_map = []
|
route_map = []
|
||||||
|
|
||||||
# wmask dff
|
# wmask dff
|
||||||
|
|
@ -407,31 +446,39 @@ class sram_1bank(sram_base):
|
||||||
bank_names = ["bank_spare_wen{0}_{1}".format(port, x) for x in range(self.num_spare_cols)]
|
bank_names = ["bank_spare_wen{0}_{1}".format(port, x) for x in range(self.num_spare_cols)]
|
||||||
bank_pins = [self.bank_inst.get_pin(x) for x in bank_names]
|
bank_pins = [self.bank_inst.get_pin(x) for x in bank_names]
|
||||||
route_map.extend(list(zip(bank_pins, dff_pins)))
|
route_map.extend(list(zip(bank_pins, dff_pins)))
|
||||||
|
|
||||||
if self.num_wmasks > 0 and port in self.write_ports:
|
|
||||||
layer_stack = self.m3_stack
|
|
||||||
else:
|
|
||||||
layer_stack = self.m1_stack
|
|
||||||
|
|
||||||
if len(route_map) > 0:
|
if len(route_map) > 0:
|
||||||
|
|
||||||
|
if self.num_wmasks > 0 and port in self.write_ports:
|
||||||
|
layer_stack = self.m3_stack
|
||||||
|
else:
|
||||||
|
layer_stack = self.m1_stack
|
||||||
|
|
||||||
if port == 0:
|
if port == 0:
|
||||||
offset = vector(self.control_logic_insts[port].rx() + self.dff.width,
|
offset = vector(self.control_logic_insts[port].rx() + self.dff.width,
|
||||||
- self.data_bus_size[port] + 2 * self.m1_pitch)
|
- self.data_bus_size[port] + 2 * self.m1_pitch)
|
||||||
import channel_route
|
|
||||||
cr = channel_route.channel_route(netlist=route_map,
|
cr = channel_route.channel_route(netlist=route_map,
|
||||||
offset=offset,
|
offset=offset,
|
||||||
layer_stack=layer_stack,
|
layer_stack=layer_stack,
|
||||||
parent=self)
|
parent=self)
|
||||||
self.add_inst("hc", cr)
|
if add_routes:
|
||||||
self.connect_inst([])
|
self.add_inst("hc", cr)
|
||||||
|
self.connect_inst([])
|
||||||
|
else:
|
||||||
|
self.data_bus_size[port] = max(cr.height, self.col_addr_bus_size[port])
|
||||||
else:
|
else:
|
||||||
offset = vector(0,
|
offset = vector(0,
|
||||||
self.bank.height + 2 * self.m1_space)
|
self.bank.height + 2 * self.m1_space)
|
||||||
self.create_horizontal_channel_route(netlist=route_map,
|
cr = channel_route.channel_route(netlist=route_map,
|
||||||
offset=offset,
|
offset=offset,
|
||||||
layer_stack=layer_stack)
|
layer_stack=layer_stack,
|
||||||
|
parent=self)
|
||||||
|
if add_routes:
|
||||||
|
self.add_inst("hc", cr)
|
||||||
|
self.connect_inst([])
|
||||||
|
else:
|
||||||
|
self.data_bus_size[port] = max(cr.height, self.col_addr_bus_size[port])
|
||||||
|
|
||||||
def route_clk(self):
|
def route_clk(self):
|
||||||
""" Route the clock network """
|
""" Route the clock network """
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue