mirror of https://github.com/VLSIDA/OpenRAM.git
Move delay-specific stimulus commands to delay.py. Keep stimuli.py generic.
This commit is contained in:
parent
ed194ad47b
commit
5c4999d4cc
|
|
@ -82,27 +82,25 @@ class delay():
|
||||||
self.sf.write("* Generation of data and address signals\n")
|
self.sf.write("* Generation of data and address signals\n")
|
||||||
for i in range(self.word_size):
|
for i in range(self.word_size):
|
||||||
if i == self.probe_data:
|
if i == self.probe_data:
|
||||||
stimuli.gen_data(stim_file=self.sf,
|
self.gen_data(clk_times=self.cycle_times,
|
||||||
clk_times=self.cycle_times,
|
sig_name="data[{0}]".format(i),
|
||||||
sig_name="data[{0}]".format(i),
|
period=period,
|
||||||
period=period,
|
slew=slew)
|
||||||
slew=slew)
|
|
||||||
else:
|
else:
|
||||||
stimuli.gen_constant(stim_file=self.sf,
|
stimuli.gen_constant(stim_file=self.sf,
|
||||||
sig_name="d[{0}]".format(i),
|
sig_name="d[{0}]".format(i),
|
||||||
v_val=self.gnd)
|
v_val=self.gnd)
|
||||||
|
|
||||||
stimuli.gen_addr(self.sf,
|
self.gen_addr(clk_times=self.cycle_times,
|
||||||
clk_times=self.cycle_times,
|
|
||||||
addr=self.probe_address,
|
addr=self.probe_address,
|
||||||
period=period,
|
period=period,
|
||||||
slew=slew)
|
slew=slew)
|
||||||
|
|
||||||
# generate control signals
|
# generate control signals
|
||||||
self.sf.write("* Generation of control signals\n")
|
self.sf.write("* Generation of control signals\n")
|
||||||
stimuli.gen_csb(self.sf, self.cycle_times, period, slew)
|
self.gen_csb(self.cycle_times, period, slew)
|
||||||
stimuli.gen_web(self.sf, self.cycle_times, period, slew)
|
self.gen_web(self.cycle_times, period, slew)
|
||||||
stimuli.gen_oeb(self.sf, self.cycle_times, period, slew)
|
self.gen_oeb(self.cycle_times, period, slew)
|
||||||
|
|
||||||
self.sf.write("* Generation of global clock signal\n")
|
self.sf.write("* Generation of global clock signal\n")
|
||||||
stimuli.gen_pulse(stim_file=self.sf,
|
stimuli.gen_pulse(stim_file=self.sf,
|
||||||
|
|
@ -404,54 +402,95 @@ class delay():
|
||||||
and does not need a rising edge."""
|
and does not need a rising edge."""
|
||||||
|
|
||||||
self.cycle_comments = []
|
self.cycle_comments = []
|
||||||
# idle cycle, no operation
|
|
||||||
t_current = period
|
|
||||||
self.cycle_times = []
|
self.cycle_times = []
|
||||||
# cycle0: W data 1 address 1111 to initialize cell to a value
|
t_current = 0
|
||||||
|
|
||||||
|
# idle cycle, no operation
|
||||||
|
msg = "Idle cycle (no clock)"
|
||||||
|
self.cycle_comments.append("Cycle{0}\t{1}ns:\t{2}".format(0,
|
||||||
|
t_current,
|
||||||
|
msg))
|
||||||
self.cycle_times.append(t_current)
|
self.cycle_times.append(t_current)
|
||||||
self.cycle_comments.append("Cycle0 {}ns: W data 1 address 11..11 to initialize cell".format(t_current))
|
|
||||||
t_current += period
|
t_current += period
|
||||||
|
|
||||||
# cycle1: W data 0 address 1111 (to ensure a write of value works)
|
# One period
|
||||||
|
msg = "W data 1 address 11..11 to initialize cell"
|
||||||
self.cycle_times.append(t_current)
|
self.cycle_times.append(t_current)
|
||||||
self.write0_cycle=1
|
self.cycle_comments.append("Cycle{0}\t{1}ns:\t{2}".format(len(self.cycle_times)-1,
|
||||||
self.cycle_comments.append("Cycle1 {}ns: W data 0 address 11..11 (to ensure a write of value works)".format(t_current))
|
t_current,
|
||||||
|
msg))
|
||||||
|
t_current += period
|
||||||
|
|
||||||
|
# One period
|
||||||
|
msg = "W data 0 address 11..11 (to ensure a write of value works)"
|
||||||
|
self.cycle_times.append(t_current)
|
||||||
|
self.write0_cycle=len(self.cycle_times)-1
|
||||||
|
self.cycle_comments.append("Cycle{0}\t{1}ns:\t{2}".format(len(self.cycle_times)-1,
|
||||||
|
t_current,
|
||||||
|
msg))
|
||||||
t_current += period
|
t_current += period
|
||||||
|
|
||||||
# cycle2: W data 1 address 0000 (to clear the data bus cap)
|
# One period
|
||||||
|
msg = "W data 1 address 00..00 (to clear bus caps)"
|
||||||
self.cycle_times.append(t_current)
|
self.cycle_times.append(t_current)
|
||||||
self.cycle_comments.append("Cycle2 {}ns: W data 1 address 00..00 (to clear bus caps)".format(t_current))
|
self.cycle_comments.append("Cycle{0}\t{1}ns:\t{2}".format(len(self.cycle_times)-1,
|
||||||
|
t_current,
|
||||||
|
msg))
|
||||||
t_current += period
|
t_current += period
|
||||||
|
|
||||||
# cycle3: R data 0 address 1111 to check W0 works
|
# One period
|
||||||
|
msg = "R data 0 address 11..11 to check W0 worked"
|
||||||
self.cycle_times.append(t_current)
|
self.cycle_times.append(t_current)
|
||||||
self.read0_cycle=3
|
self.read0_cycle=len(self.cycle_times)-1
|
||||||
self.cycle_comments.append("Cycle3 {}ns: R data 0 address 11..11 to check W0 worked".format(t_current))
|
self.cycle_comments.append("Cycle{0}\t{1}ns:\t{2}".format(len(self.cycle_times)-1,
|
||||||
|
t_current,
|
||||||
|
msg))
|
||||||
t_current += period
|
t_current += period
|
||||||
|
|
||||||
# cycle4: W data 1 address 1111 (to ensure a write of value works)
|
# One period
|
||||||
|
msg = "Idle cycle"
|
||||||
|
self.cycle_comments.append("Cycle{0}\t{1}ns:\t{2}".format(len(self.cycle_times)-1,
|
||||||
|
t_current,
|
||||||
|
msg))
|
||||||
self.cycle_times.append(t_current)
|
self.cycle_times.append(t_current)
|
||||||
self.write1_cycle=4
|
|
||||||
self.cycle_comments.append("Cycle4 {}ns: W data 1 address 11..11 (to ensure a write of value worked)".format(t_current))
|
|
||||||
t_current += period
|
t_current += period
|
||||||
|
|
||||||
# cycle5: W data 0 address 0000 (to clear the data bus cap)
|
# One period
|
||||||
|
msg = "W data 1 address 11..11 (to ensure a write of value worked)"
|
||||||
self.cycle_times.append(t_current)
|
self.cycle_times.append(t_current)
|
||||||
self.cycle_comments.append("Cycle5 {}ns: W data 0 address 00..00 (to clear bus caps)".format(t_current))
|
self.write1_cycle=len(self.cycle_times)-1
|
||||||
|
self.cycle_comments.append("Cycle{0}\t{1}ns:\t{2}".format(len(self.cycle_times)-1,
|
||||||
|
t_current,
|
||||||
|
msg))
|
||||||
|
t_current += period
|
||||||
|
|
||||||
|
# One period
|
||||||
|
msg = "W data 0 address 00..00 (to clear bus caps)"
|
||||||
|
self.cycle_times.append(t_current)
|
||||||
|
self.cycle_comments.append("Cycle{0}\t{1}ns:\t{2}".format(len(self.cycle_times)-1,
|
||||||
|
t_current,
|
||||||
|
msg))
|
||||||
t_current += period
|
t_current += period
|
||||||
|
|
||||||
# cycle6: R data 1 address 1111 to check W1 works
|
# One period
|
||||||
|
msg = "R data 1 address 11..11 to check W1 worked"
|
||||||
self.cycle_times.append(t_current)
|
self.cycle_times.append(t_current)
|
||||||
self.read1_cycle=6
|
self.read1_cycle=len(self.cycle_times)-1
|
||||||
self.cycle_comments.append("Cycle6 {}ns: R data 1 address 11..11 to check W1 worked".format(t_current))
|
self.cycle_comments.append("Cycle{0}\t{1}ns:\t{2}".format(len(self.cycle_times)-1,
|
||||||
|
t_current,
|
||||||
|
msg))
|
||||||
t_current += period
|
t_current += period
|
||||||
|
|
||||||
# cycle7: wait a clock period to end the simulation
|
# One period
|
||||||
|
msg = "Idle cycle"
|
||||||
|
self.cycle_comments.append("Cycle{0}\t{1}ns:\t{2}".format(len(self.cycle_times)-1,
|
||||||
|
t_current,
|
||||||
|
msg))
|
||||||
self.cycle_times.append(t_current)
|
self.cycle_times.append(t_current)
|
||||||
self.cycle_comments.append("Cycle7 {}ns: Idle period to end simulation".format(t_current))
|
|
||||||
t_current += period
|
t_current += period
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def analytical_model(self,sram, slews, loads):
|
def analytical_model(self,sram, slews, loads):
|
||||||
""" Just return the analytical model results for the SRAM.
|
""" Just return the analytical model results for the SRAM.
|
||||||
"""
|
"""
|
||||||
|
|
@ -480,3 +519,53 @@ class delay():
|
||||||
}
|
}
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
def gen_data(self, clk_times, sig_name, period, slew):
|
||||||
|
"""Generates the PWL data inputs for a simulation timing test."""
|
||||||
|
# values for NOP, W1, W0, W1, R0, NOP, W1, W0, R1, NOP
|
||||||
|
# we are asserting the opposite value on the other side of the tx gate during
|
||||||
|
# the read to be "worst case". Otherwise, it can actually assist the read.
|
||||||
|
values = [0, 1, 0, 1, 1, 1, 1, 0, 0, 0 ]
|
||||||
|
stimuli.gen_pwl(self.sf, sig_name, clk_times, values, period, slew, 0.05)
|
||||||
|
|
||||||
|
def gen_addr(self, clk_times, addr, period, slew):
|
||||||
|
"""Generates the address inputs for a simulation timing test.
|
||||||
|
One cycle is different to clear the bus
|
||||||
|
"""
|
||||||
|
|
||||||
|
zero_values = [0, 0, 0, 1, 0, 0, 0, 1, 0, 0 ]
|
||||||
|
ones_values = [1, 1, 1, 0, 1, 0, 1, 0, 1, 1 ]
|
||||||
|
|
||||||
|
for i in range(len(addr)):
|
||||||
|
sig_name = "A[{0}]".format(i)
|
||||||
|
if addr[i]=="1":
|
||||||
|
stimuli.gen_pwl(self.sf, sig_name, clk_times, ones_values, period, slew, 0.05)
|
||||||
|
else:
|
||||||
|
stimuli.gen_pwl(self.sf, sig_name, clk_times, zero_values, period, slew, 0.05)
|
||||||
|
|
||||||
|
|
||||||
|
def gen_csb(self, clk_times, period, slew):
|
||||||
|
""" Generates the PWL CSb signal"""
|
||||||
|
# values for NOP, W1, W0, W1, R0, NOP, W1, W0, R1, NOP
|
||||||
|
# Keep CSb asserted in NOP for measuring >1 period
|
||||||
|
values = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||||
|
stimuli.gen_pwl(self.sf, "csb", clk_times, values, period, slew, 0.05)
|
||||||
|
|
||||||
|
def gen_web(self, clk_times, period, slew):
|
||||||
|
""" Generates the PWL WEb signal"""
|
||||||
|
# values for NOP, W1, W0, W1, R0, NOP, W1, W0, R1, NOP
|
||||||
|
# Keep WEb deasserted in NOP for measuring >1 period
|
||||||
|
values = [1, 0, 0, 0, 1, 1, 0, 0, 1, 1]
|
||||||
|
stimuli.gen_pwl(self.sf, "web", clk_times, values, period, slew, 0.05)
|
||||||
|
|
||||||
|
# Keep acc_en deasserted in NOP for measuring >1 period
|
||||||
|
values = [1, 0, 0, 0, 1, 1, 0, 0, 1, 1]
|
||||||
|
stimuli.gen_pwl(self.sf, "acc_en", clk_times, values, period, slew, 0)
|
||||||
|
values = [0, 1, 1, 1, 0, 0, 1, 1, 0, 0]
|
||||||
|
stimuli.gen_pwl(self.sf, "acc_en_inv", clk_times, values, period, slew, 0)
|
||||||
|
|
||||||
|
def gen_oeb(self, clk_times, period, slew):
|
||||||
|
""" Generates the PWL WEb signal"""
|
||||||
|
# values for NOP, W1, W0, W1, R0, W1, W0, R1, NOP
|
||||||
|
# Keep OEb asserted in NOP for measuring >1 period
|
||||||
|
values = [1, 1, 1, 1, 0, 0, 1, 1, 0, 0]
|
||||||
|
stimuli.gen_pwl(self.sf, "oeb", clk_times, values, period, slew, 0.05)
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,5 @@
|
||||||
import os
|
import os,sys,re,shutil
|
||||||
import sys
|
|
||||||
import re
|
|
||||||
import debug
|
import debug
|
||||||
import tech
|
|
||||||
import math
|
import math
|
||||||
import setup_hold
|
import setup_hold
|
||||||
import delay
|
import delay
|
||||||
|
|
@ -34,7 +31,9 @@ class lib:
|
||||||
self.sram.word_size)
|
self.sram.word_size)
|
||||||
else:
|
else:
|
||||||
# Else, use the non-reduced netlist file for simulation
|
# Else, use the non-reduced netlist file for simulation
|
||||||
self.sim_sp_file = self.sp_file
|
self.sim_sp_file = "{}sram.sp".format(OPTS.openram_temp)
|
||||||
|
# Make a copy in temp for debugging
|
||||||
|
shutil.copy(self.sp_file, self.sim_sp_file)
|
||||||
|
|
||||||
# These are the parameters to determine the table sizes
|
# These are the parameters to determine the table sizes
|
||||||
#self.load_scales = np.array([0.1, 0.25, 0.5, 1, 2, 4, 8])
|
#self.load_scales = np.array([0.1, 0.25, 0.5, 1, 2, 4, 8])
|
||||||
|
|
|
||||||
|
|
@ -134,71 +134,25 @@ def gen_pulse(stim_file, sig_name, v1=gnd_voltage, v2=vdd_voltage, offset=0, per
|
||||||
|
|
||||||
def gen_pwl(stim_file, sig_name, clk_times, data_values, period, slew, setup):
|
def gen_pwl(stim_file, sig_name, clk_times, data_values, period, slew, setup):
|
||||||
# the initial value is not a clock time
|
# the initial value is not a clock time
|
||||||
debug.check(len(clk_times)+1==len(data_values),"Clock and data value lengths don't match.")
|
debug.check(len(clk_times)==len(data_values),"Clock and data value lengths don't match.")
|
||||||
|
|
||||||
# shift signal times earlier for setup time
|
# shift signal times earlier for setup time
|
||||||
times = np.array(clk_times) - setup*period
|
times = np.array(clk_times) - setup*period
|
||||||
values = np.array(data_values) * vdd_voltage
|
values = np.array(data_values) * vdd_voltage
|
||||||
half_slew = 0.5 * slew
|
half_slew = 0.5 * slew
|
||||||
stim_file.write("V{0} {0} 0 PWL (0n {1}v ".format(sig_name, values[0]))
|
stim_file.write("V{0} {0} 0 PWL (0n {1}v ".format(sig_name, values[0]))
|
||||||
for i in range(len(times)):
|
for i in range(1,len(times)-1):
|
||||||
stim_file.write("{0}n {1}v {2}n {3}v ".format(times[i]-half_slew,
|
stim_file.write("{0}n {1}v {2}n {3}v ".format(times[i]-half_slew,
|
||||||
values[i],
|
values[i-1],
|
||||||
times[i]+half_slew,
|
times[i]+half_slew,
|
||||||
values[i+1]))
|
values[i]))
|
||||||
stim_file.write(")\n")
|
stim_file.write(")\n")
|
||||||
|
|
||||||
def gen_data(stim_file, clk_times, sig_name, period, slew):
|
|
||||||
"""Generates the PWL data inputs for a simulation timing test."""
|
|
||||||
# values for NOP, W1, W0, W1, R0, W1, W0, R1, NOP
|
|
||||||
# we are asserting the opposite value on the other side of the tx gate during
|
|
||||||
# the read to be "worst case". Otherwise, it can actually assist the read.
|
|
||||||
values = [0, 1, 0, 1, 1, 1, 0, 0, 0 ]
|
|
||||||
gen_pwl(stim_file, sig_name, clk_times, values, period, slew, 0.05)
|
|
||||||
|
|
||||||
|
|
||||||
def gen_addr(stim_file, clk_times, addr, period, slew):
|
|
||||||
"""Generates the address inputs for a simulation timing test.
|
|
||||||
One cycle is different to clear the bus
|
|
||||||
"""
|
|
||||||
|
|
||||||
zero_values = [0, 0, 0, 1, 0, 0, 1, 0, 0 ]
|
|
||||||
ones_values = [1, 1, 1, 0, 1, 1, 0, 1, 1 ]
|
|
||||||
|
|
||||||
for i in range(len(addr)):
|
|
||||||
sig_name = "A[{0}]".format(i)
|
|
||||||
if addr[i]=="1":
|
|
||||||
gen_pwl(stim_file, sig_name, clk_times, ones_values, period, slew, 0.05)
|
|
||||||
else:
|
|
||||||
gen_pwl(stim_file, sig_name, clk_times, zero_values, period, slew, 0.05)
|
|
||||||
|
|
||||||
def gen_constant(stim_file, sig_name, v_val):
|
def gen_constant(stim_file, sig_name, v_val):
|
||||||
"""Generates a constant signal with reference voltage and the voltage value"""
|
"""Generates a constant signal with reference voltage and the voltage value"""
|
||||||
stim_file.write("V{0} {0} 0 DC {1}\n".format(sig_name, v_val))
|
stim_file.write("V{0} {0} 0 DC {1}\n".format(sig_name, v_val))
|
||||||
|
|
||||||
def gen_csb(stim_file, clk_times, period, slew):
|
|
||||||
""" Generates the PWL CSb signal"""
|
|
||||||
# values for NOP, W1, W0, W1, R0, W1, W0, R1, NOP
|
|
||||||
values = [1, 0, 0, 0, 0, 0, 0, 0, 1]
|
|
||||||
gen_pwl(stim_file, "csb", clk_times, values, period, slew, 0.05)
|
|
||||||
|
|
||||||
def gen_web(stim_file, clk_times, period, slew):
|
|
||||||
""" Generates the PWL WEb signal"""
|
|
||||||
# values for NOP, W1, W0, W1, R0, W1, W0, R1, NOP
|
|
||||||
values = [1, 0, 0, 0, 1, 0, 0, 1, 1]
|
|
||||||
gen_pwl(stim_file, "web", clk_times, values, period, slew, 0.05)
|
|
||||||
|
|
||||||
values = [1, 0, 0, 0, 1, 0, 0, 1, 1]
|
|
||||||
gen_pwl(stim_file, "acc_en", clk_times, values, period, slew, 0)
|
|
||||||
values = [0, 1, 1, 1, 0, 1, 1, 0, 0]
|
|
||||||
gen_pwl(stim_file, "acc_en_inv", clk_times, values, period, slew, 0)
|
|
||||||
|
|
||||||
def gen_oeb(stim_file, clk_times, period, slew):
|
|
||||||
""" Generates the PWL WEb signal"""
|
|
||||||
# values for NOP, W1, W0, W1, R0, W1, W0, R1, NOP
|
|
||||||
values = [1, 1, 1, 1, 0, 1, 1, 0, 1]
|
|
||||||
gen_pwl(stim_file, "oeb", clk_times, values, period, slew, 0.05)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_inverse_voltage(value):
|
def get_inverse_voltage(value):
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,8 @@ class trim_spice():
|
||||||
self.remove_insts("bitcell_array",[wl_name,bl_name])
|
self.remove_insts("bitcell_array",[wl_name,bl_name])
|
||||||
|
|
||||||
# 2. Keep sense amps basd on BL
|
# 2. Keep sense amps basd on BL
|
||||||
self.remove_insts("sense_amp_array",[bl_name])
|
# FIXME: The bit lines are not indexed the same in sense_amp_array
|
||||||
|
#self.remove_insts("sense_amp_array",[bl_name])
|
||||||
|
|
||||||
# 3. Keep column muxes basd on BL
|
# 3. Keep column muxes basd on BL
|
||||||
self.remove_insts("column_mux_array",[bl_name])
|
self.remove_insts("column_mux_array",[bl_name])
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue