def gen_model(real_type): # create mixed-signal model model = MixedSignalModel('model', build_dir=BUILD_DIR, real_type=real_type) model.add_digital_input('in_', width=N_BITS) model.add_analog_output('out') model.add_digital_input('clk') model.add_digital_input('rst') # create function domain = [map_f(0), map_f((1 << N_BITS) - 1)] real_func = model.make_function( lambda x: inv_cdf(unmap_f(x) / (1 << (N_BITS + 1))), domain=domain, order=1, numel=512) # apply function mapped = compress_uint(model.in_) model.set_from_sync_func(model.out, real_func, mapped, clk=model.clk, rst=model.rst) # write the model return model.compile_to_file(VerilogGenerator())
def main(cap=1e-12, res=600, n_array=47): ctrl = ExampleControl() # define ports m = MixedSignalModel('current_switch_array', dt=ctrl.dt) m.add_digital_input('ctrl', n_array) m.add_analog_input('v_in') m.add_analog_output('v_out', init=0) # can change initial value if desired # find number of zeros m.immediate_assign( 'n_on', n_array - sum_op([m.ctrl[k] for k in range(m.ctrl.width)])) # compute the unit current m.immediate_assign('i_unit', (m.v_in - m.v_out) / res) # compute the array current m.immediate_assign('i_array', m.n_on * m.i_unit) # define the voltage update on the cap m.next_cycle_assign(m.v_out, m.v_out + m.i_array / (n_array * cap) * ctrl.dt) # write model ctrl.write_model(m)
def main(tau=1e-6): print('Running model generator...') # parse command line arguments parser = ArgumentParser() parser.add_argument('-o', '--output', type=str) parser.add_argument('--dt', type=float) args = parser.parse_args() # create the model m = MixedSignalModel('filter', dt=args.dt) m.add_analog_input('v_in') m.add_analog_output('v_out') c = m.make_circuit() gnd = c.make_ground() c.voltage('net_v_in', gnd, m.v_in) c.diode('net_v_in', 'net_v_x', vf=0) c.resistor('net_v_x', 'net_v_out', 1e3) v_out = c.capacitor('net_v_out', gnd, 1e-9, voltage_range=1.5) m.set_this_cycle(m.v_out, v_out) # determine the output filename filename = os.path.join(get_full_path(args.output), f'{m.module_name}.sv') print('Model will be written to: ' + filename) # generate the model m.compile_to_file(VerilogGenerator(), filename)
def gen_model(mean=0.0, std=1.0, num_sigma=6.0, order=1, numel=512, real_type=RealType.FixedPoint): # create mixed-signal model model = MixedSignalModel('model', build_dir=BUILD_DIR, real_type=real_type) model.add_digital_input('clk') model.add_digital_input('rst') model.add_analog_output('real_out') # compute the inverse CDF of the distribution (truncated to 0, 1 domain) inv_cdf = lambda x: truncnorm.ppf( x, -num_sigma, +num_sigma, loc=mean, scale=std) # create the function object inv_cdf_func = model.make_function(inv_cdf, domain=[0.0, 1.0], order=order, numel=numel) model.set_this_cycle( model.real_out, model.arbitrary_noise(inv_cdf_func, clk=model.clk, rst=model.rst)) # write the model return model.compile_to_file(VerilogGenerator())
def gen_model(real_vals, sint_vals, uint_vals, addr_bits, sint_bits, uint_bits, real_type): # create mixed-signal model model = MixedSignalModel('model', build_dir=BUILD_DIR, real_type=real_type) model.add_digital_input('addr', width=addr_bits) model.add_digital_input('clk') model.add_analog_output('real_out') model.add_digital_output('sint_out', width=sint_bits) model.add_digital_output('uint_out', width=uint_bits) # create tables real_table = model.make_real_table(real_vals) sint_table = model.make_sint_table(sint_vals) uint_table = model.make_uint_table(uint_vals) # assign values model.set_from_sync_rom(model.real_out, real_table, model.addr, clk=model.clk) model.set_from_sync_rom(model.sint_out, sint_table, model.addr, clk=model.clk) model.set_from_sync_rom(model.uint_out, uint_table, model.addr, clk=model.clk) # write the model return model.compile_to_file(VerilogGenerator())
def gen_model(myfunc, order=0, numel=512, real_type=RealType.FixedPoint, func_mode='sync'): # create mixed-signal model model = MixedSignalModel('model', build_dir=BUILD_DIR, real_type=real_type) model.add_analog_input('in_') model.add_analog_output('out') model.add_digital_input('clk') model.add_digital_input('rst') # create function write_tables = (func_mode in {'sync'}) real_func = model.make_function(myfunc, domain=[-DOMAIN, +DOMAIN], order=order, numel=numel, write_tables=write_tables) # apply function model.set_from_func(model.out, real_func, model.in_, clk=model.clk, rst=model.rst, func_mode=func_mode) # write the model return model.compile_to_file(VerilogGenerator())
def __init__(self, filename=None, **system_values): # set a fixed random seed for repeatability np.random.seed(2) module_name = Path(filename).stem build_dir = Path(filename).parent print(f'Running model generator for {module_name}...') assert (all([req_val in system_values for req_val in self.required_values()])), \ f'Cannot build {module_name}, Missing parameter in config file' m = MixedSignalModel(module_name, dt=system_values['dt'], build_dir=build_dir, real_type=get_dragonphy_real_type()) m.add_real_param('t_del', 0) m.add_digital_input('emu_rst') m.add_digital_input('emu_clk') m.add_analog_input('t_lo') m.add_analog_input('t_hi') m.add_analog_input('emu_dt') m.add_analog_output('dt_req', init=m.t_del) m.add_digital_output('clk_val') # determine if the request was granted m.bind_name('req_grant', m.dt_req == m.emu_dt) # update the clock value m.add_digital_state('prev_clk_val') m.set_next_cycle(m.prev_clk_val, m.clk_val, clk=m.emu_clk, rst=m.emu_rst) m.set_this_cycle(m.clk_val, if_(m.req_grant, ~m.prev_clk_val, m.prev_clk_val)) # determine arguments for formating time steps # TODO: clean this up dt_fmt_kwargs = dict( range_=m.emu_dt.format_.range_, width=m.emu_dt.format_.width, exponent=m.emu_dt.format_.exponent ) array_fmt_kwargs = deepcopy(dt_fmt_kwargs) array_fmt_kwargs['real_range_hint'] = m.emu_dt.format_.range_ del array_fmt_kwargs['range_'] # determine the next period dt_req_next_array = array([m.t_hi, m.t_lo], m.prev_clk_val, **array_fmt_kwargs) m.bind_name('dt_req_next', dt_req_next_array, **dt_fmt_kwargs) # increment the time request m.bind_name('dt_req_incr', m.dt_req - m.emu_dt, **dt_fmt_kwargs) # determine the next period dt_req_imm_array = array([m.dt_req_incr, m.dt_req_next], m.req_grant, **array_fmt_kwargs) m.bind_name('dt_req_imm', dt_req_imm_array, **dt_fmt_kwargs) m.set_next_cycle(m.dt_req, m.dt_req_imm, clk=m.emu_clk, rst=m.emu_rst) # generate the model m.compile_to_file(VerilogGenerator()) self.generated_files = [filename]
def main(): tau = 1e-6 dt = 0.1e-6 model = MixedSignalModel('model', dt=dt) model.add_analog_input('v_in') model.add_analog_output('v_out', init=1.23) model.add_eqn_sys([Deriv(model.v_out) == (model.v_in - model.v_out)/tau]) model.compile_and_print(VerilogGenerator())
def main(): dt = 0.1e-6 m = MixedSignalModel('model', dt=dt) m.add_analog_input('v_in') m.add_analog_output('v_out') m.add_eqn_sys([m.v_out == 0.123 * m.v_in]) m.compile_and_print(VerilogGenerator())
def main(): dt = 0.1e-6 num = (1e12,) den = (1, 8e5, 1e12,) model = MixedSignalModel('model', dt=dt) model.add_analog_input('v_in') model.add_analog_output('v_out') model.set_tf(input_=model.v_in, output=model.v_out, tf=(num, den)) model.compile_and_print(VerilogGenerator())
def gen_model(tau, dt, real_type): model = MixedSignalModel('model', dt=dt, real_type=real_type) model.add_analog_input('v_in') model.add_analog_output('v_out') model.add_digital_input('clk') model.add_digital_input('rst') model.add_eqn_sys([Deriv(model.v_out) == (model.v_in - model.v_out) / tau], clk=model.clk, rst=model.rst) BUILD_DIR.mkdir(parents=True, exist_ok=True) model_file = BUILD_DIR / 'model.sv' model.compile_to_file(VerilogGenerator(), filename=model_file) return model_file
def main(): tau = 1e-6 dt = 0.1e-6 model = MixedSignalModel('model', dt=dt) model.add_analog_input('v_in') model.add_analog_output('v_out') model.add_digital_input('ctrl') model.add_eqn_sys([ Deriv( model.v_out) == eqn_case([0, 1 / tau], [model.ctrl]) * model.v_in - model.v_out / tau ]) model.compile_and_print(VerilogGenerator())
def main(): tau_det_fast = 1e-9 tau_det_slow = 360e-9 dt = 4.6e-9 m = MixedSignalModel('model', dt=dt) m.add_analog_input('v_in') m.add_analog_output('v_out') m.bind_name('in_gt_out', m.v_in > m.v_out) # detector dynamics m.add_eqn_sys([ Deriv(m.v_out) == eqn_case([0, 1 / tau_det_fast], [m.in_gt_out]) * (m.v_in - m.v_out) - (m.v_out / tau_det_slow) ]) m.compile_and_print(VerilogGenerator())
def gen_model(real_type, gen_type): # create mixed-signal model model = MixedSignalModel('model', build_dir=BUILD_DIR, real_type=real_type) model.add_digital_input('clk') model.add_digital_input('rst') model.add_analog_input('mean_in') model.add_analog_input('std_in') model.add_analog_output('real_out') # apply noise model.set_gaussian_noise(model.real_out, std=model.std_in, mean=model.mean_in, clk=model.clk, rst=model.rst, gen_type=gen_type) # write the model return model.compile_to_file(VerilogGenerator())
def main(): dt = 0.1e-6 res = 1e3 cap = 1e-9 m = MixedSignalModel('model', dt=dt) m.add_analog_input('v_in') m.add_analog_output('v_out') c = m.make_circuit() gnd = c.make_ground() c.capacitor('net_v_out', gnd, cap, voltage_range=RangeOf(m.v_out)) c.resistor('net_v_in', 'net_v_out', res) c.voltage('net_v_in', gnd, m.v_in) c.add_eqns(AnalogSignal('net_v_out') == m.v_out) m.compile_and_print(VerilogGenerator())
def main(): model = MixedSignalModel('model') model.add_analog_input('a_in') model.add_digital_output('d_out', width=8) model.add_analog_output('a_out') model.add_digital_input('d_in', width=8) # DAC from 0 to 1V as the input code varies from 0-255 clamped = clamp(to_sint(model.a_in * 255, width=model.d_out.width + 1), 0, 255) model.set_this_cycle(model.d_out, to_uint(clamped, width=model.d_out.width)) # ADC code goes from 0-255 as input voltage goes from 0 to 1V model.set_this_cycle(model.a_out, model.d_in / 255) model.compile_and_print(VerilogGenerator())
def __init__(self, filename=None, **system_values): # set a fixed random seed for repeatability np.random.seed(4) module_name = Path(filename).stem build_dir = Path(filename).parent #This is a wonky way of validating this.. :( assert (all([req_val in system_values for req_val in self.required_values()])), \ f'Cannot build {module_name}, Missing parameter in config file' m = MixedSignalModel(module_name, dt=system_values['dt'], build_dir=build_dir, real_type=get_dragonphy_real_type()) m.add_digital_input('in_') m.add_analog_output('out') m.add_digital_input('cke') m.add_digital_input('clk') m.add_digital_input('rst') # save previous value of cke m.add_digital_state('cke_prev', init=0) m.set_next_cycle(m.cke_prev, m.cke, clk=m.clk, rst=m.rst) # detect positive edge of cke m.add_digital_signal('cke_posedge') m.set_this_cycle(m.cke_posedge, m.cke & (~m.cke_prev)) # define model behavior vp, vn = system_values['vp'], system_values['vn'] m.set_next_cycle(m.out, if_(m.in_, vp, vn), clk=m.clk, rst=m.rst, ce=m.cke_posedge) # generate the model m.compile_to_file(VerilogGenerator()) self.generated_files = [filename]
def main(cap=1e-12, res=600): ctrl = ExampleControl() # define ports m = MixedSignalModel('current_switch', dt=ctrl.dt) m.add_digital_input('ctrl') m.add_analog_input('v_in') m.add_analog_output('v_out') # define the circuit c = m.make_circuit() gnd = c.make_ground() c.switch('net_v_in', 'net_v_out', m.ctrl, r_on=res, r_off=10e3 * res) c.capacitor('net_v_out', gnd, cap, voltage_range=RangeOf(m.v_out)) c.voltage('net_v_in', gnd, m.v_in) c.add_eqns(m.v_out == AnalogSignal('net_v_out')) # write model ctrl.write_model(m)
def main(): dt = 0.01e-6 cap = 0.16e-6 ind = 0.16e-6 res = 0.1 model = MixedSignalModel('model', dt=dt) model.add_analog_input('v_in') model.add_analog_output('v_out') model.add_analog_state('i_ind', 100) v_l = AnalogSignal('v_l') v_r = AnalogSignal('v_r') eqns = [ Deriv(model.i_ind) == v_l / ind, Deriv(model.v_out) == model.i_ind / cap, v_r == model.i_ind * res, model.v_in == model.v_out + v_l + v_r ] model.add_eqn_sys(eqns) model.compile_and_print(VerilogGenerator())
def main(): dt = 1e-9 m = MixedSignalModel('model', dt=dt) m.add_analog_input('v_in') m.add_analog_output('v_out') m.add_digital_input('sw1') m.add_digital_input('sw2') c = m.make_circuit() gnd = c.make_ground() c.voltage('net_v_in', gnd, m.v_in) c.switch('net_v_in', 'net_v_x', m.sw1) c.switch('net_v_x', gnd, m.sw2) c.inductor('net_v_in', 'net_v_x', 1, current_range=100) c.add_eqns(AnalogSignal('net_v_x') == m.v_out) m.compile_and_print(VerilogGenerator())
def gen_model(order, numel, build_dir): # settings: # order=0, numel=512 => rms_error <= 0.0105 # order=1, numel=128 => rms_error <= 0.000318 # order=2, numel= 32 => rms_error <= 0.000232 # create mixed-signal model m = MixedSignalModel('model', build_dir=build_dir) m.add_analog_input('in_') m.add_analog_output('out') # create function real_func = m.make_function(myfunc, domain=[-np.pi, +np.pi], order=order, numel=numel) # apply function m.set_from_sync_func(m.out, real_func, m.in_) # write the model return m.compile_to_file(VerilogGenerator())
def main(): dt = 0.1e-6 m = MixedSignalModel('model', dt=dt) m.add_analog_input('v_in') m.add_analog_output('v_out') m.add_digital_input('sw1') m.add_digital_input('sw2') c = m.make_circuit() gnd = c.make_ground() c.voltage('net_v_in', gnd, m.v_in) c.switch('net_v_in', 'net_v_x', m.sw1, r_on=1.0, r_off=2.0) c.switch('net_v_x', gnd, m.sw2, r_on=3.0, r_off=4.0) c.add_eqns( AnalogSignal('net_v_x') == m.v_out ) m.compile_and_print(VerilogGenerator())
def gen_model(placeholder, real_type, addr_bits, data_bits): # create mixed-signal model model = MixedSignalModel('model', build_dir=BUILD_DIR, real_type=real_type) model.add_analog_input('in_') model.add_analog_output('out') model.add_digital_input('clk') model.add_digital_input('rst') model.add_digital_input('wdata0', width=data_bits, signed=True) model.add_digital_input('wdata1', width=data_bits, signed=True) model.add_digital_input('waddr', width=addr_bits) model.add_digital_input('we') # apply function model.set_from_sync_func(model.out, placeholder, model.in_, clk=model.clk, rst=model.rst, wdata=[model.wdata0, model.wdata1], waddr=model.waddr, we=model.we) # write the model return model.compile_to_file(VerilogGenerator())
def main(): print('Running model generator...') # parse command line arguments parser = ArgumentParser() parser.add_argument('-o', '--output', type=str, default='build') parser.add_argument('--dt', type=float, default=0.1e-6) parser.add_argument('--tau', type=float, default=1.0e-6) a = parser.parse_args() # create the model m = MixedSignalModel('model', dt=a.dt) m.add_analog_input('v_in') m.add_analog_output('v_out') # apply dynamics m.set_next_cycle(m.v_out, m.v_out*exp(-a.dt/a.tau) + m.v_in*(1-exp(-a.dt/a.tau))) # determine the output filename filename = Path(a.output).resolve() / f'{m.module_name}.sv' print(f'Model will be written to: {filename}') # generate the model m.compile_to_file(VerilogGenerator(), filename)
def __init__(self, filename=None, **system_values): # set a fixed random seed for repeatability np.random.seed(1) module_name = Path(filename).stem build_dir = Path(filename).parent #This is a wonky way of validating this.. :( assert (all([req_val in system_values for req_val in self.required_values()])), \ f'Cannot build {module_name}, Missing parameter in config file' # instantiate model m = MixedSignalModel(module_name, dt=system_values['dt'], build_dir=build_dir) # main I/O: delay code and gain m.add_digital_input('code', width=system_values['n_bits']) m.add_digital_input('clk_i_val') m.add_digital_output('clk_o_val') # timestep control: DT request and response m.add_analog_output('dt_req') m.add_analog_input('emu_dt') # emulator clock and reset m.add_digital_input('emu_clk') m.add_digital_input('emu_rst') # additional input: maximum timestep # TODO: clean this up m.add_analog_input('dt_req_max') # jitter control m.add_digital_input('jitter_seed', width=32) m.add_analog_input('jitter_rms') # compute the delay (with no jitter) m.bind_name('delay_amt_pre', m.code * (system_values['t_per'] / (2.0 ** system_values['n_bits']))) # add jitter to the delay amount (which might possibly yield a negative value) m.set_gaussian_noise('t_jitter', std=m.jitter_rms, clk=m.emu_clk, rst=m.emu_rst, lfsr_init=m.jitter_seed) m.bind_name('delay_amt_noisy', m.delay_amt_pre + m.t_jitter) # make the delay amount non-negative m.bind_name('delay_amt', if_(m.delay_amt_noisy >= 0.0, m.delay_amt_noisy, 0.0)) # determine when the clock value has changed m.add_digital_state('clk_i_val_prev') m.set_next_cycle(m.clk_i_val_prev, m.clk_i_val, clk=m.emu_clk, rst=m.emu_rst) m.bind_name('clk_edge', m.clk_i_val ^ m.clk_i_val_prev) # create pointer that advances each time there is a clock edge depth = system_values['depth'] dbits = int(ceil(log2(depth))) m.add_digital_state('addr', width=dbits) m.add_digital_state('next_addr', width=dbits) m.set_this_cycle(m.next_addr, if_(m.addr == (depth-1), 0, m.addr+1)) m.set_next_cycle(m.addr, m.next_addr, clk=m.emu_clk, rst=m.emu_rst, ce=m.clk_edge) # convenience function for formatting DT signals def add_dt_state(*args, range_=m.emu_dt.format_.range_, width=m.emu_dt.format_.width, exponent=m.emu_dt.format_.exponent, **kwargs): return m.add_analog_state(*args, range_=range_, width=width, exponent=exponent, **kwargs) # convenience function for formatting DT signals def dt_array(*args, real_range_hint=m.emu_dt.format_.range_, width=m.emu_dt.format_.width, exponent=m.emu_dt.format_.exponent, **kwargs): return array(*args, real_range_hint=real_range_hint, width=width, exponent=exponent, **kwargs) # instantiate delay "units" that each keep track of one edge dt_req = [] req_data = [] req_grant = [] req_valid = [] for k in range(depth): # should load data if there is a clock edge and this slice is selected load_data = m.bind_name(f'load_data_{k}', m.clk_edge & (k == m.addr)) # handle update of dt_req dt_req.append(add_dt_state(f'dt_req_{k}')) m.set_next_cycle( dt_req[-1], if_(load_data, m.delay_amt, dt_req[-1] - m.emu_dt), clk=m.emu_clk, rst=m.emu_rst ) # handle update of req_data req_data.append(m.add_digital_state(f'req_data_{k}')) m.set_next_cycle(req_data[-1], m.clk_i_val, ce=load_data, clk=m.emu_clk, rst=m.emu_rst) # handle update of req_grant req_grant.append(m.bind_name(f'req_grant_{k}', dt_req[-1] == m.emu_dt)) # handle update of req_valid req_valid.append(m.add_digital_state(f'req_valid_{k}')) m.set_next_cycle(req_valid[-1], (req_valid[-1] & (~req_grant[-1])) | load_data, clk=m.emu_clk, rst=m.emu_rst) # replace dt_req with dt_req_max for invalid requests dt_req_mux = [] for k in range(depth): dt_req_mux.append( m.bind_name( f'dt_req_mux_{k}', dt_array( [m.dt_req_max, dt_req[k]], req_valid[k], ) ) ) # convenience function to find the minimum DT request using a tree structure counter = count() def tree_min(data): # check cases if len(data) == 0: raise Exception("This shouldn't happen...") elif len(data) == 1: return data[0] else: val0 = tree_min(data[:len(data)//2]) val1 = tree_min(data[len(data)//2:]) return m.bind_name( f'dt_intern_{next(counter)}', dt_array( [val0, val1], val1 < val0, ) ) # set the "dt_req" output to the minimum time request (where invalid requests # are replaced with "dt_req_max" m.set_this_cycle(m.dt_req, tree_min(dt_req_mux)) # determine if the output should be set or cleared set_out = req_grant[0] & req_valid[0] & req_data[0] clr_out = req_grant[0] & req_valid[0] & (~req_data[0]) for k in range(1, depth): set_out = set_out | (req_grant[k] & req_valid[k] & req_data[k]) clr_out = clr_out | (req_grant[k] & req_valid[k] & (~req_data[k])) m.bind_name('set_out', set_out) m.bind_name('clr_out', clr_out) # set output, clear output, or keep it the same m.add_digital_state('clk_o_val_prev') m.set_next_cycle(m.clk_o_val_prev, m.clk_o_val, clk=m.emu_clk, rst=m.emu_rst) m.set_this_cycle(m.clk_o_val, (m.clk_o_val_prev & (~m.clr_out)) | (m.set_out)) # generate the model m.compile_to_file(VerilogGenerator()) self.generated_files = [filename]
def __init__(self, filename=None, **system_values): # set a fixed random seed for repeatability np.random.seed(0) module_name = Path(filename).stem build_dir = Path(filename).parent #This is a wonky way of validating this.. :( assert (all([req_val in system_values for req_val in self.required_values()])), \ f'Cannot build {module_name}, Missing parameter in config file' m = MixedSignalModel(module_name, dt=system_values['dt'], build_dir=build_dir, real_type=get_dragonphy_real_type()) m.add_analog_input('in_') m.add_analog_output('out') m.add_analog_input('dt_sig') m.add_digital_input('clk') m.add_digital_input('cke') m.add_digital_input('rst') # Create "placeholder function" that can be updated # at runtime with the channel function chan_func = PlaceholderFunction( domain=system_values['func_domain'], order=system_values['func_order'], numel=system_values['func_numel'], coeff_widths=system_values['func_widths'], coeff_exps=system_values['func_exps']) # Check the function on a representative test case chan = Filter.from_file(get_file('build/chip_src/adapt_fir/chan.npy')) self.check_func_error(chan_func, chan.interp) # Add digital inputs that will be used to reconfigure the function at runtime wdata, waddr, we = add_placeholder_inputs(m=m, f=chan_func) # create a history of past inputs cke_d = m.add_digital_state('cke_d') m.set_next_cycle(cke_d, m.cke, clk=m.clk, rst=m.rst) value_hist = m.make_history(m.in_, system_values['num_terms'] + 1, clk=m.clk, rst=m.rst, ce=cke_d) # create a history times in the past when the input changed time_incr = [] time_mux = [] for k in range(system_values['num_terms'] + 1): if k == 0: time_incr.append(m.dt_sig) time_mux.append(None) else: # create the signal mem_sig = AnalogState(name=f'time_mem_{k}', range_=m.dt_sig.format_.range_, width=m.dt_sig.format_.width, exponent=m.dt_sig.format_.exponent, init=0.0) m.add_signal(mem_sig) # increment time by dt_sig (this is the output from the current tap) incr_sig = m.bind_name(f'time_incr_{k}', mem_sig + m.dt_sig) time_incr.append(incr_sig) # mux input of DFF between current and previous memory value mux_sig = m.bind_name( f'time_mux_{k}', if_(m.cke_d, time_incr[k - 1], time_incr[k])) time_mux.append(mux_sig) # delayed assignment m.set_next_cycle(signal=mem_sig, expr=mux_sig, clk=m.clk, rst=m.rst) # evaluate step response function step = [] for k in range(system_values['num_terms']): step_sig = m.set_from_sync_func(f'step_{k}', chan_func, time_mux[k + 1], clk=m.clk, rst=m.rst, wdata=wdata, waddr=waddr, we=we) step.append(step_sig) # compute the products to be summed prod = [] for k in range(system_values['num_terms']): if k == 0: prod_sig = m.bind_name(f'prod_{k}', value_hist[k + 1] * step[k]) else: prod_sig = m.bind_name( f'prod_{k}', value_hist[k + 1] * (step[k] - step[k - 1])) prod.append(prod_sig) # define model behavior m.set_this_cycle(m.out, sum_op(prod)) # generate the model m.compile_to_file(VerilogGenerator()) self.generated_files = [filename]