def setUp(self): self.dut = self.instantiate_dut() self.sim = Simulator(self.dut) if self.USB_CLOCK_FREQUENCY: self.sim.add_clock(1 / self.USB_CLOCK_FREQUENCY, domain="usb") if self.SYNC_CLOCK_FREQUENCY: self.sim.add_clock(1 / self.SYNC_CLOCK_FREQUENCY, domain="sync") if self.FAST_CLOCK_FREQUENCY: self.sim.add_clock(1 / self.FAST_CLOCK_FREQUENCY, domain="fast")
def _resolve(self, expr): sim = Simulator(Module()) a = [] def testbench(): a.append((yield expr)) sim.add_process(testbench) sim.run() return a[0]
def testbench(): from nmigen.sim.pysim import Settle, Simulator unit = NotGate() def bench(): yield unit.input.eq(0) yield Settle() assert (yield unit.output) yield unit.input.eq(1) yield Settle() assert not (yield unit.output) sim = Simulator(unit) sim.add_process(bench) with sim.write_vcd("notgate.vcd", "notgate.gtkw", traces=[unit.input, unit.output]): sim.run()
def elaborate(self, platform): m = Module() m.submodules += [ self.timing, self.still, ] return m if __name__ == '__main__': color_depth = 4 image = gradient(color_depth=color_depth) timing = VgaTiming(resolutions[ResolutionName.VGA_640_480p_60hz]) dut = TestBench( timing, Still(timing, color_depth=color_depth, image=image), ) sim = Simulator(dut) def proc(): for _ in range(800 * 40): yield sim.add_clock(1e-6, domain='pixel') sim.add_sync_process(proc, domain='pixel') with sim.write_vcd('still.vcd'): sim.run()
from nmigen.sim.pysim import Simulator, Delay, Settle from ecp5_pcie.dllp import PCIeDLLPTransmitter from ecp5_pcie.serdes import PCIeSERDESInterface, Ctrl import random if __name__ == "__main__": m = Module() output = Signal(18) m.submodules.dllpt = dllpt = PCIeDLLPTransmitter() m.d.comb += dllpt.send.eq(1) m.d.comb += dllpt.source.ready.eq(1) m.d.comb += dllpt.send.eq(1) sim = Simulator(m) sim.add_clock(1 / 125e6, domain="rx") # The other two DLLPs received from the ROCKPro64 # Refer to layouts.py for the layout of the dllp record dllp_1 = 0b1000011100000001000000000100 dllp_2 = 0b1000000100000001000000000101 def process(): yield dllpt.dllp.eq(dllp_1) #yield dllpt.dllp.valid.eq(0) for _ in range(20): print(hex((yield dllpt.source.symbol[0])), end="\t") print(hex((yield dllpt.source.symbol[1])), end="\t") print(hex((yield dllpt.source.symbol[2])), end="\t") print(hex((yield dllpt.source.symbol[3])))
class LunaGatewareTestCase(unittest.TestCase): domain = 'sync' # Convenience property: if set, instantiate_dut will automatically create # the relevant fragment with FRAGMENT_ARGUMENTS. FRAGMENT_UNDER_TEST = None FRAGMENT_ARGUMENTS = {} # Convenience properties: if not None, a clock with the relevant frequency # will automatically be added. FAST_CLOCK_FREQUENCY = None SYNC_CLOCK_FREQUENCY = 120e6 USB_CLOCK_FREQUENCY = None def instantiate_dut(self): """ Basic-most function to instantiate a device-under-test. By default, instantiates FRAGMENT_UNDER_TEST. """ return self.FRAGMENT_UNDER_TEST(**self.FRAGMENT_ARGUMENTS) def get_vcd_name(self): """ Return the name to use for any VCDs generated by this class. """ return "test_{}".format(self.__class__.__name__) def setUp(self): self.dut = self.instantiate_dut() self.sim = Simulator(self.dut) if self.USB_CLOCK_FREQUENCY: self.sim.add_clock(1 / self.USB_CLOCK_FREQUENCY, domain="usb") if self.SYNC_CLOCK_FREQUENCY: self.sim.add_clock(1 / self.SYNC_CLOCK_FREQUENCY, domain="sync") if self.FAST_CLOCK_FREQUENCY: self.sim.add_clock(1 / self.FAST_CLOCK_FREQUENCY, domain="fast") def initialize_signals(self): """ Provide an opportunity for the test apparatus to initialize siganls. """ yield Signal() def traces_of_interest(self): """ Returns an interable of traces to include in any generated output. """ # Default to including all signals. return self.sim._signal_names def simulate(self, *, vcd_suffix=None): """ Runs our core simulation. """ # If we're generating VCDs, run the test under a VCD writer. if os.getenv('GENERATE_VCDS', default=False): # Figure out the name of our VCD files... vcd_name = self.get_vcd_name() if vcd_suffix: vcd_name = "{}_{}".format(vcd_name, vcd_suffix) # ... and run the simulation while writing them. traces = self.traces_of_interest() with self.sim.write_vcd(vcd_name + ".vcd", vcd_name + ".gtkw", traces=traces): self.sim.run() else: self.sim.run() @staticmethod def pulse(signal, *, step_after=True): """ Helper method that asserts a signal for a cycle. """ yield signal.eq(1) yield yield signal.eq(0) if step_after: yield @staticmethod def advance_cycles(cycles): """ Helper methods that waits for a given number of cycles. """ for _ in range(cycles): yield @staticmethod def wait_until(strobe, *, timeout=None): """ Helper method that advances time until a strobe signal becomes true. """ cycles_passed = 0 while not (yield strobe): yield cycles_passed += 1 if timeout and cycles_passed > timeout: raise RuntimeError( f"Timeout waiting for '{strobe.name}' to go high!") def _ensure_clocks_present(self): """ Function that validates that a clock is present for our simulation domain. """ frequencies = { 'sync': self.SYNC_CLOCK_FREQUENCY, 'usb': self.USB_CLOCK_FREQUENCY, 'fast': self.FAST_CLOCK_FREQUENCY, } self.assertIsNotNone( frequencies[self.domain], f"no frequency provied for `{self.domain}`-domain clock!") def wait(self, time): """ Helper method that waits for a given number of seconds in a *_test_case. """ # Figure out the period of the clock we want to work with... if self.domain == 'sync': period = 1 / self.SYNC_CLOCK_FREQUENCY elif self.domain == 'usb': period = 1 / self.USB_CLOCK_FREQUENCY elif self.domain == 'fast': period = 1 / self.FAST_CLOCK_FREQUENCY # ... and, accordingly, how many cycles we want to delay. cycles = math.ceil(time / period) print(cycles) # Finally, wait that many cycles. yield from self.advance_cycles(cycles)
""" from nmigen import Signal, Elaboratable, Module from nmigen.sim.pysim import Simulator class Top(Elaboratable): def __init__(self): self.counter = Signal(range(10)) def elaborate(self, platform): m = Module() m.d.sync += self.counter.eq(self.counter + 1) return m if __name__ == '__main__': def process(): for tick in range(10): print(f"counter = {(yield dut.counter)}") yield dut = Top() sim = Simulator(dut) sim.add_clock(1e-6) sim.add_sync_process(process) with sim.write_vcd(f"{__file__[:-3]}.vcd"): sim.run()
from nmigen import * from nmigen.build import * from nmigen.sim.pysim import Simulator, Delay, Settle from ecp5_pcie.crc import CRC from nmigen_boards.versa_ecp5_5g import VersaECP55GPlatform import random if __name__ == "__main__": m = Module() m.submodules.crc = crc = CRC(Signal(16), 0xFFFF, 0x100B, 16) sim = Simulator(m) sim.add_clock(1/125e6, domain="sync")# For NextPNR, set the maximum clock frequency such that errors are given def process(): # Simulate a DLLP which was received from the ROCKPro64 yield yield crc.reset.eq(1) yield yield crc.reset.eq(0) yield crc.input.eq(0x0060) yield print(hex((yield crc.output))) yield crc.input.eq(0x0000) yield print(hex((yield crc.output))) yield print() # Should output 0x92d8 print(hex((yield ~Cat(crc.output[::-1]))))
def test_sim_noiseshaper(self): fmt = Q(8, 18) input = fmt.Signal() dut = Noiseshaper(input, order=8, n_lev=64) sim = Simulator(dut) sim.add_clock(1 / 100e6) input_hist = [] output_hist = [] integrators_hist = [[] for _ in dut.stages] n = 8192 f_nyquist = int(np.ceil(n / (2. * dut.osr))) f_test = np.floor(2. / 3. * f_nyquist) u = dut.n_lev * 0.5 * np.sin(2 * np.pi * f_test / n * np.arange(n)) def testbench(): for x in u: yield input.eq(x) input_hist.append(fmt.to_float((yield input.value))) output_hist.append( fmt.to_float((yield dut.quantized_value.value))) for i, integrator in enumerate(dut.stages): integrators_hist[i].append( fmt.to_float((yield integrator.value))) yield sim.add_sync_process(testbench) sim.run() from matplotlib import pyplot as plt plt.plot(np.arange(n), output_hist, linewidth=1, label="output") plt.plot(np.arange(n), input_hist, label="input") plt.legend() plt.show() for i, integrator_hist in reversed(list(enumerate(integrators_hist))): plt.plot(np.arange(n), integrator_hist, linewidth=1, label="integrator {}".format(i)) plt.legend() plt.show() import deltasigma as ds f = np.linspace(0, 0.5, int(n / 2. + 1)) v, xn, xmax, y = ds.simulateDSM(u, dut.h, nlev=len(dut.quantization_values)) spec = np.fft.fft(v * ds.ds_hann(n)) / (n / 4) plt.plot(f, ds.dbv(spec[:int(n / 2. + 1)]), 'b', label='Simulation DS') spec = np.fft.fft(output_hist * ds.ds_hann(n)) / (n / 4) plt.plot(f, ds.dbv(spec[:int(n / 2. + 1)]), 'g', label='Simulation HW', alpha=0.7) ds.figureMagic([0, 0.5], 0.05, None, [-160, 0], 20, None, (16, 6), 'Output Spectrum') plt.xlabel('Normalized Frequency') plt.ylabel('dBFS') snr = ds.calculateSNR(spec[2:f_nyquist + 1], f_test - 2) plt.text(0.05, -10, 'SNR = %4.1fdB @ OSR = %d' % (snr, dut.osr), verticalalignment='center') NBW = 1.5 / n Sqq = 4 * ds.evalTF(dut.h, np.exp(2j * np.pi * f))**2 / 3. plt.plot(f, ds.dbp(Sqq * NBW), 'm', linewidth=2, label='Expected PSD') plt.text(0.49, -90, 'NBW = %4.1E x $f_s$' % NBW, horizontalalignment='right') plt.legend(loc=4) plt.show() pwm_out = py_pwm.modulate(np.array(output_hist) + 32, n_bits=6, oversampling_ratio=1) n = n * 64 f = np.linspace(0, 0.5, int(n / 2. + 1)) spec = np.fft.fft(pwm_out * ds.ds_hann(n)) / (n / 4) plt.plot(f, ds.dbv(spec[:int(n / 2. + 1)]), 'b', label='PWM') ds.figureMagic([0, 0.5], 0.05, None, [-160, 0], 20, None, (16, 6), 'Output Spectrum') plt.xlabel('Normalized Frequency') plt.ylabel('dBFS') snr = ds.calculateSNR(spec[2:f_nyquist + 1], f_test - 2) plt.text(0.05, -10, 'SNR = %4.1fdB @ OSR = %d' % (snr, dut.osr), verticalalignment='center') plt.legend(loc=4) plt.show()