import numpy as np from kyupy.wave_sim4 import WaveSim, wave_eval, TMIN, TMAX from kyupy.logic_sim import LogicSim from kyupy import verilog, sdf, logic, bench from kyupy.logic import MVArray, BPArray from kyupy.sim import SimPrim def test_nand_delays(): op = (SimPrim.NAND4, 4, 0, 1, 2, 3) #op = (0b0111, 4, 0, 1) c = np.full((5*16, 1), TMAX) # 5 waveforms of capacity 16 vat = np.zeros((5, 3), dtype='int') for i in range(5): vat[i] = i*16, 16, 0 # 1:1 mapping # SDF specifies IOPATH delays with respect to output polarity # SDF pulse rejection value is determined by IOPATH causing last transition and polarity of last transition line_times = np.zeros((5, 2, 2)) line_times[0, 0, 0] = 0.1 # A -> Z rise delay line_times[0, 0, 1] = 0.2 # A -> Z fall delay line_times[0, 1, 0] = 0.1 # A -> Z negative pulse limit (terminate in rising Z) line_times[0, 1, 1] = 0.2 # A -> Z positive pulse limit line_times[1, :, 0] = 0.3 # as above for B -> Z line_times[1, :, 1] = 0.4 line_times[2, :, 0] = 0.5 # as above for C -> Z line_times[2, :, 1] = 0.6 line_times[3, :, 0] = 0.7 # as above for D -> Z line_times[3, :, 1] = 0.8 sdata = np.asarray([1, -1, 0, 0], dtype='float32') def wave_assert(inputs, output): for i, a in zip(inputs, c.reshape(-1,16)): a[:len(i)] = i wave_eval(op, c, vat, 0, line_times, sdata) for i, v in enumerate(output): np.testing.assert_allclose(c.reshape(-1,16)[4,i], v) wave_assert([[TMAX,TMAX],[TMAX,TMAX],[TMIN,TMAX],[TMIN,TMAX]], [TMIN,TMAX]) # NAND(0,0,1,1) => 1 wave_assert([[TMIN,TMAX],[TMAX,TMAX],[TMIN,TMAX],[TMIN,TMAX]], [TMIN,TMAX]) # NAND(1,0,1,1) => 1 wave_assert([[TMIN,TMAX],[TMIN,TMAX],[TMIN,TMAX],[TMIN,TMAX]], [TMAX]) # NAND(1,1,1,1) => 0 # Keep inputs C=1 and D=1. wave_assert([[1,TMAX],[2,TMAX]], [TMIN,2.4,TMAX]) # _/⎺⎺⎺ NAND __/⎺⎺ => ⎺⎺⎺\___ (B->Z fall delay) wave_assert([[TMIN,TMAX],[TMIN,2,TMAX]], [2.3,TMAX]) # ⎺⎺⎺⎺⎺ NAND ⎺⎺\__ => ___/⎺⎺⎺ (B->Z rise delay) wave_assert([[TMIN,TMAX],[TMIN,2,2.35,TMAX]], [2.3,2.75,TMAX]) # ⎺⎺⎺⎺⎺ NAND ⎺\_/⎺ => __/⎺⎺\_ (pos pulse, .35@B -> .45@Z) wave_assert([[TMIN,TMAX],[TMIN,2,2.25,TMAX]], [TMAX]) # ⎺⎺⎺⎺⎺ NAND ⎺\_/⎺ => _______ (pos pulse, .25@B -> .35@Z, filtered) wave_assert([[TMIN,TMAX],[2,2.45,TMAX]], [TMIN,2.4,2.75,TMAX]) # ⎺⎺⎺⎺⎺ NAND _/⎺\_ => ⎺⎺\_/⎺⎺ (neg pulse, .45@B -> .35@Z) wave_assert([[TMIN,TMAX],[2,2.35,TMAX]], [TMIN,TMAX]) # ⎺⎺⎺⎺⎺ NAND _/⎺\_ => ⎺⎺⎺⎺⎺⎺⎺ (neg pulse, .35@B -> .25@Z, filtered) def test_tiny_circuit(): c = bench.parse('input(x, y) output(a, o, n) a=and(x,y) o=or(x,y) n=not(x)') lt = np.zeros((len(c.lines), 2, 2)) lt[:,0,:] = 1.0 # unit delay for all lines wsim = WaveSim(c, lt) print(wsim.prim_counts) assert len(wsim.s) == 5 # values for x wsim.s[0,0,:3] = 0, 0.1, 0 wsim.s[0,1,:3] = 0, 0.2, 1 wsim.s[0,2,:3] = 1, 0.3, 0 wsim.s[0,3,:3] = 1, 0.4, 1 # values for y wsim.s[1,0,:3] = 1, 0.5, 0 wsim.s[1,1,:3] = 1, 0.6, 0 wsim.s[1,2,:3] = 1, 0.7, 0 wsim.s[1,3,:3] = 0, 0.8, 1 wsim.s_to_c() x_c_loc = wsim.vat[wsim.ppi_offset+0, 0] # check x waveforms np.testing.assert_allclose(wsim.c[x_c_loc:x_c_loc+3, 0], [TMAX, TMAX, TMAX]) np.testing.assert_allclose(wsim.c[x_c_loc:x_c_loc+3, 1], [0.2, TMAX, TMAX]) np.testing.assert_allclose(wsim.c[x_c_loc:x_c_loc+3, 2], [TMIN, 0.3, TMAX]) np.testing.assert_allclose(wsim.c[x_c_loc:x_c_loc+3, 3], [TMIN, TMAX, TMAX]) y_c_loc = wsim.vat[wsim.ppi_offset+1, 0] # check y waveforms np.testing.assert_allclose(wsim.c[y_c_loc:y_c_loc+3, 0], [TMIN, 0.5, TMAX]) np.testing.assert_allclose(wsim.c[y_c_loc:y_c_loc+3, 1], [TMIN, 0.6, TMAX]) np.testing.assert_allclose(wsim.c[y_c_loc:y_c_loc+3, 2], [TMIN, 0.7, TMAX]) np.testing.assert_allclose(wsim.c[y_c_loc:y_c_loc+3, 3], [0.8, TMAX, TMAX]) wsim.c_prop() a_c_loc = wsim.vat[wsim.ppo_offset+2, 0] # check a waveforms np.testing.assert_allclose(wsim.c[a_c_loc:a_c_loc+3, 0], [TMAX, TMAX, TMAX]) np.testing.assert_allclose(wsim.c[a_c_loc:a_c_loc+3, 1], [1.2, 1.6, TMAX]) np.testing.assert_allclose(wsim.c[a_c_loc:a_c_loc+3, 2], [TMIN, 1.3, TMAX]) np.testing.assert_allclose(wsim.c[a_c_loc:a_c_loc+3, 3], [1.8, TMAX, TMAX]) o_c_loc = wsim.vat[wsim.ppo_offset+3, 0] # check o waveforms np.testing.assert_allclose(wsim.c[o_c_loc:o_c_loc+3, 0], [TMIN, 1.5, TMAX]) np.testing.assert_allclose(wsim.c[o_c_loc:o_c_loc+3, 1], [TMIN, TMAX, TMAX]) np.testing.assert_allclose(wsim.c[o_c_loc:o_c_loc+3, 2], [TMIN, 1.7, TMAX]) np.testing.assert_allclose(wsim.c[o_c_loc:o_c_loc+3, 3], [TMIN, TMAX, TMAX]) n_c_loc = wsim.vat[wsim.ppo_offset+4, 0] # check n waveforms np.testing.assert_allclose(wsim.c[n_c_loc:n_c_loc+3, 0], [TMIN, TMAX, TMAX]) np.testing.assert_allclose(wsim.c[n_c_loc:n_c_loc+3, 1], [TMIN, 1.2, TMAX]) np.testing.assert_allclose(wsim.c[n_c_loc:n_c_loc+3, 2], [1.3, TMAX, TMAX]) np.testing.assert_allclose(wsim.c[n_c_loc:n_c_loc+3, 3], [TMAX, TMAX, TMAX]) wsim.c_to_s() # check a captures np.testing.assert_allclose(wsim.s[2, 0, 3:7], [0, TMAX, TMIN, 0]) np.testing.assert_allclose(wsim.s[2, 1, 3:7], [0, 1.2, 1.6, 0]) np.testing.assert_allclose(wsim.s[2, 2, 3:7], [1, 1.3, 1.3, 0]) np.testing.assert_allclose(wsim.s[2, 3, 3:7], [0, 1.8, 1.8, 1]) # check o captures np.testing.assert_allclose(wsim.s[3, 0, 3:7], [1, 1.5, 1.5, 0]) np.testing.assert_allclose(wsim.s[3, 1, 3:7], [1, TMAX, TMIN, 1]) np.testing.assert_allclose(wsim.s[3, 2, 3:7], [1, 1.7, 1.7, 0]) np.testing.assert_allclose(wsim.s[3, 3, 3:7], [1, TMAX, TMIN, 1]) # check o captures np.testing.assert_allclose(wsim.s[4, 0, 3:7], [1, TMAX, TMIN, 1]) np.testing.assert_allclose(wsim.s[4, 1, 3:7], [1, 1.2, 1.2, 0]) np.testing.assert_allclose(wsim.s[4, 2, 3:7], [0, 1.3, 1.3, 1]) np.testing.assert_allclose(wsim.s[4, 3, 3:7], [0, TMAX, TMIN, 0]) def compare_to_logic_sim(wsim: WaveSim): tests = MVArray((len(wsim.s_nodes), wsim.sims)) choices = np.asarray([logic.ZERO, logic.ONE, logic.RISE, logic.FALL], dtype=np.uint8) rng = np.random.default_rng(10) tests.data[...] = rng.choice(choices, tests.data.shape) wsim.s[..., 0] = (tests.data & 2) >> 1 wsim.s[..., 3] = (tests.data & 2) >> 1 wsim.s[..., 1] = 0.0 wsim.s[..., 2] = tests.data & 1 wsim.s[..., 6] = tests.data & 1 wsim.s_to_c() wsim.c_prop() wsim.c_to_s() resp = MVArray(tests) resp.data[...] = wsim.s[..., 6].astype(np.uint8) | (wsim.s[..., 3].astype(np.uint8)<<1) resp.data |= ((resp.data ^ (resp.data >> 1)) & 1) << 2 # transitions tests_bp = BPArray(tests) lsim = LogicSim(wsim.circuit, len(tests_bp)) lsim.assign(tests_bp) lsim.propagate() exp_bp = BPArray(tests_bp) lsim.capture(exp_bp) exp = MVArray(exp_bp) for i in range(8): exp_str = exp[i].replace('P', '0').replace('N', '1') res_str = resp[i].replace('P', '0').replace('N', '1') assert res_str == exp_str def test_b14(mydir): c = verilog.load(mydir / 'b14.v.gz', branchforks=True) df = sdf.load(mydir / 'b14.sdf.gz') lt = df.annotation(c) wsim = WaveSim(c, lt, 8) compare_to_logic_sim(wsim) def test_b14_strip_forks(mydir): c = verilog.load(mydir / 'b14.v.gz', branchforks=True) df = sdf.load(mydir / 'b14.sdf.gz') lt = df.annotation(c) wsim = WaveSim(c, lt, 8, strip_forks=True) compare_to_logic_sim(wsim)