From: Florent Kermarrec Date: Fri, 22 Feb 2013 13:28:05 +0000 (+0100) Subject: - reworking WIP X-Git-Tag: 24jan2021_ls180~2575^2~121 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=e95e8b03b7dd00e8b6cbe687b8e1f03a37940527;p=litex.git - reworking WIP --- diff --git a/README b/README index 3f61f70a..222df2b8 100644 --- a/README +++ b/README @@ -6,32 +6,31 @@ Copyright 2012 / Florent Kermarrec / florent@enjoy-digital.fr - migScope + miscope -------------------------------------------------------------------------------- -[> migScope +[> miscope ------------ -migScope is a small logic analyzer to be embedded in an FPGA. +miscope is a small logic analyzer to be embedded in an FPGA. While free vendor toolchains are generally used by beginners or for prototyping -(situations where having a logic analyser in the design is generally very -helpful) free toolchains are always provided without the proprietary logic +(situations where having a logic analyser in the design is generally very +helpful) free toolchains are always provided without the proprietary logic analyzer solution... :( -Based on Migen, migScope aims to provide a free, portable and flexible +Based on Migen, miscope aims to provide a free, portable and flexible alternative to vendor's solutions! [> Specification: -migScope provides Migen cores to be embedded in the design and Python drivers to -control the logic analyzer from the Host. migScope automatically interconnects -all cores tothe CSR bus. When using Python on the Host, no needs to worry about -cores register mapping, importing migScope project gives you direct access to +miscope provides Migen cores to be embedded in the design and Python drivers to +control the logic analyzer from the Host. miscope automatically interconnects +all cores to the CSR bus. When using Python on the Host, no needs to worry about +cores register mapping, importing miscope project gives you direct access to all the cores! -migScope produces.vcd output files to be analyzed in your favorite waveform -viewer. +miscope produces.vcd output files to be analyzed in your favorite waveform viewer. [> Status: Complete flow tested on board with a classic Term. RangeDetector, EdgeDetector diff --git a/doc/migScope.rst b/doc/migScope.rst deleted file mode 100644 index 50f46094..00000000 --- a/doc/migScope.rst +++ /dev/null @@ -1,218 +0,0 @@ -.. image:: Illustrations/migscope_logo.png - -Introduction -############ - -MigScope is a small logic analyzer to be embedded in an FPGA. - -While free vendor toolchains are generally used by beginners or for prototyping (situations where having a logic analyser in the design is generally very helpful) free toolchains are always provided without the proprietary logic analyzer solution. . . :( - -Based on Migen, MigScope aims to provide a free and portable / flexible alternative to vendor's solutions. - -About Migen -*********** -Migen is a Python-based tool that aims at automating further the VLSI design process. [*]_ - -.. [*] More information on Migen on : http://github.com/milkymist/migen - -Migen makes it possible to apply modern software concepts such as object-oriented programming and metaprogramming to design hardware. This results in more elegant and easily maintained designs and reduces the incidence of human errors. - -Installing MigScope -******************* -Either run the setup.py installation script or simply set PYTHONPATH to the root of the source directory. - -Feedback -******** -Feedback concerning MigScope or this manual should be sent to florent@enjoy-digital.fr - - -The MigScope Structure -###################### - -Migscope provides two kinds of cores: - - - MigIo : the virtual Input / Output core - - MigLa : the virtual Logic Analyser core - -A CSR bus controls the MigIo and MigLa cores. The CSR bus is a very simple bus originally used to control peripheral registers in milkymist Soc.[*]_ - -.. [*] More information on Milkymist on : http://github.com/milkymist/milkymist-ng - -Because of its simplicity, it can be adapted very easily to a wide range of interfaces: Wishbone, Uart, Spi, I2C, Ethernet... - -MigScope uses CSR library from Migen to inter-connect the cores. MigScope provides a Spi2Csr Bridge and is tested with an external Spi Interface. Support for others externals interfaces will be added in future versions. - -Because Migen is a Python-based tool, using Python to control MigScope gives lot's of advantages : Python classes can provide the HDL description **AND** driver functions! - -.. image:: Illustrations/migscope_structure.png - -MigIo -##### - -Description ------------ - -The MigIo is simply an internal GPIO equivalent. It provides N (configurable) inputs and/or outputs and can be used for lots of purposes: - - - stimulation of a core's parameters in a design where external control interface is not yet developped or still under developpement. - - update of a Look-Up-Table or a Ram. - - read an internal / external bus. - - ... - -.. image:: Illustrations/migIo.png - - -Instanciation -------------- -:: - - MIGIO_ADDR = 0x0000 - migIo0 = migIo.MigIo(MIGIO_ADDR, 8, "IO") - -MigIo parameters are: - - - CSR address : core base Address - - Bus width : size of input / output buses. **(a power of two)** - - mode : "I" for input, "O" for output, "IO" for both - -Driver ------- -To use drivers functions, an interface is defined:: - - csr = Uart2Spi(1,115200) - migIo0 = migIo.MigIo(MIGIO_ADDR, 8, "IO", csr) - -MigIo drivers functions will now use our csr interface. Note that it's only useful to define the migIo interface in the Python code that will be executed on the Host, the code that will be translated in HDL don't need it. - -Write Method:: - - migIo0.write(0x1234, 0x5A) -Write parameters are: - - - CSR Address - - Data - -Read Method:: - - migIo0.read(0x1234) - -Read parameters are: - - - CSR Address - -Examples Design ---------------- - -de0_nano and de1 examples instanciate a MigIo Core. - -The HDL Code is in examples/deX/top.py - -The Host Code is in examples/deX/client/test_MigIo.py - -MigLa -##### - -Description ------------ - -The MigLa is the Logic Analyser core, it provides N (configurable) Trigger bits and M (Configurable) Data bits: - -.. image:: Illustrations/migLa.png - -Each MigLa instance is composed of a Trigger and a Recorder controlled by the CSR Bus: - -.. image:: Illustrations/migLa_structure.png - -The Trigger is configured by the user to detect particular events on the N Trigger bits. Once detected, the hit signal rise. - -The Recorder is armed by the user and is waiting for the hit signal to rise to store the M Data bits bus. - -Trigger Description -------------------- - -.. image:: Illustrations/Trigger_structure.png - - -The Trigger is an assembly of customized modules: - - - Term : Hit when Trigger bus = (Value* & Mask*) - - Range Detector : Hit when Range Min* < Trigger Bus < Range Max* - - Edge Detector : Hit when : - - (Trigger Bus & Rising Mask*) is Rising - - or (Trigger Bus & Falling Mask*) is Falling - - or (Trigger Bus & Both Mask*) is Both Rising or Falling - -(* dynamically configurable by CSR Bus) - -Each module has a Hit Output that is connected to the Sum. - -The Sum module is a LUT that is configured by the user and define the logical equation between the triggers elements. - -Recorder Description --------------------- - -.. image:: Illustrations/Recorder_structure.png - -The Sequencer is armed by the user and generate a record window for the Storage module. - -The window offset and size can be dynamically configured (use of a circular buffer) - -Instanciation -------------- - -:: - - term0 = trigger.Term(trig0_width) - trigger0 = trigger.Trigger(trig0_width, [term0]) - recorder0 = recorder.Recorder(dat0_width, record_size) - - migLa0 = migLa.MigLa(MIGLA0_ADDR, trigger0, recorder0) - -This example above describes a MigLa instance with 1 trig element (Term term0) - -Term parameters are: - - - Trigger Width - -Trigger parameters are: - - - Trigger Width - - List if trig elements to use in trigger - -Recorder parameters are: - - - Data Width - - Maximum size of Record - -MigLa parameters are: - - - CSR address : core base Address - - Trigger object to use - - Recorder object to use - -Driver ------- - -To use drivers functions, an interface is defined:: - - csr = Uart2Spi(1,115200,debug=False) - - [...] - - migLa0 = migLa.MigLa(MIGLA_ADDR, trigger0, recorder0, csr) - -MigLa drivers functions will now use our csr interface. Note that it's only useful to define the migLa interface in the Python code that will be executed on the Host, the code that will be translated in HDL don't need it - -Examples Design ---------------- - -de0_nano and de1 examples instanciate a MigLa Core. - -The HDL Code is in examples/deX/top.py - -The Host Code is in examples/deX/client/test_MigLa_0.py and test_MigLa_1.py - -Examples Design -############### - -[To be done] diff --git a/doc/miscope.rst b/doc/miscope.rst new file mode 100644 index 00000000..50f46094 --- /dev/null +++ b/doc/miscope.rst @@ -0,0 +1,218 @@ +.. image:: Illustrations/migscope_logo.png + +Introduction +############ + +MigScope is a small logic analyzer to be embedded in an FPGA. + +While free vendor toolchains are generally used by beginners or for prototyping (situations where having a logic analyser in the design is generally very helpful) free toolchains are always provided without the proprietary logic analyzer solution. . . :( + +Based on Migen, MigScope aims to provide a free and portable / flexible alternative to vendor's solutions. + +About Migen +*********** +Migen is a Python-based tool that aims at automating further the VLSI design process. [*]_ + +.. [*] More information on Migen on : http://github.com/milkymist/migen + +Migen makes it possible to apply modern software concepts such as object-oriented programming and metaprogramming to design hardware. This results in more elegant and easily maintained designs and reduces the incidence of human errors. + +Installing MigScope +******************* +Either run the setup.py installation script or simply set PYTHONPATH to the root of the source directory. + +Feedback +******** +Feedback concerning MigScope or this manual should be sent to florent@enjoy-digital.fr + + +The MigScope Structure +###################### + +Migscope provides two kinds of cores: + + - MigIo : the virtual Input / Output core + - MigLa : the virtual Logic Analyser core + +A CSR bus controls the MigIo and MigLa cores. The CSR bus is a very simple bus originally used to control peripheral registers in milkymist Soc.[*]_ + +.. [*] More information on Milkymist on : http://github.com/milkymist/milkymist-ng + +Because of its simplicity, it can be adapted very easily to a wide range of interfaces: Wishbone, Uart, Spi, I2C, Ethernet... + +MigScope uses CSR library from Migen to inter-connect the cores. MigScope provides a Spi2Csr Bridge and is tested with an external Spi Interface. Support for others externals interfaces will be added in future versions. + +Because Migen is a Python-based tool, using Python to control MigScope gives lot's of advantages : Python classes can provide the HDL description **AND** driver functions! + +.. image:: Illustrations/migscope_structure.png + +MigIo +##### + +Description +----------- + +The MigIo is simply an internal GPIO equivalent. It provides N (configurable) inputs and/or outputs and can be used for lots of purposes: + + - stimulation of a core's parameters in a design where external control interface is not yet developped or still under developpement. + - update of a Look-Up-Table or a Ram. + - read an internal / external bus. + - ... + +.. image:: Illustrations/migIo.png + + +Instanciation +------------- +:: + + MIGIO_ADDR = 0x0000 + migIo0 = migIo.MigIo(MIGIO_ADDR, 8, "IO") + +MigIo parameters are: + + - CSR address : core base Address + - Bus width : size of input / output buses. **(a power of two)** + - mode : "I" for input, "O" for output, "IO" for both + +Driver +------ +To use drivers functions, an interface is defined:: + + csr = Uart2Spi(1,115200) + migIo0 = migIo.MigIo(MIGIO_ADDR, 8, "IO", csr) + +MigIo drivers functions will now use our csr interface. Note that it's only useful to define the migIo interface in the Python code that will be executed on the Host, the code that will be translated in HDL don't need it. + +Write Method:: + + migIo0.write(0x1234, 0x5A) +Write parameters are: + + - CSR Address + - Data + +Read Method:: + + migIo0.read(0x1234) + +Read parameters are: + + - CSR Address + +Examples Design +--------------- + +de0_nano and de1 examples instanciate a MigIo Core. + +The HDL Code is in examples/deX/top.py + +The Host Code is in examples/deX/client/test_MigIo.py + +MigLa +##### + +Description +----------- + +The MigLa is the Logic Analyser core, it provides N (configurable) Trigger bits and M (Configurable) Data bits: + +.. image:: Illustrations/migLa.png + +Each MigLa instance is composed of a Trigger and a Recorder controlled by the CSR Bus: + +.. image:: Illustrations/migLa_structure.png + +The Trigger is configured by the user to detect particular events on the N Trigger bits. Once detected, the hit signal rise. + +The Recorder is armed by the user and is waiting for the hit signal to rise to store the M Data bits bus. + +Trigger Description +------------------- + +.. image:: Illustrations/Trigger_structure.png + + +The Trigger is an assembly of customized modules: + + - Term : Hit when Trigger bus = (Value* & Mask*) + - Range Detector : Hit when Range Min* < Trigger Bus < Range Max* + - Edge Detector : Hit when : + - (Trigger Bus & Rising Mask*) is Rising + - or (Trigger Bus & Falling Mask*) is Falling + - or (Trigger Bus & Both Mask*) is Both Rising or Falling + +(* dynamically configurable by CSR Bus) + +Each module has a Hit Output that is connected to the Sum. + +The Sum module is a LUT that is configured by the user and define the logical equation between the triggers elements. + +Recorder Description +-------------------- + +.. image:: Illustrations/Recorder_structure.png + +The Sequencer is armed by the user and generate a record window for the Storage module. + +The window offset and size can be dynamically configured (use of a circular buffer) + +Instanciation +------------- + +:: + + term0 = trigger.Term(trig0_width) + trigger0 = trigger.Trigger(trig0_width, [term0]) + recorder0 = recorder.Recorder(dat0_width, record_size) + + migLa0 = migLa.MigLa(MIGLA0_ADDR, trigger0, recorder0) + +This example above describes a MigLa instance with 1 trig element (Term term0) + +Term parameters are: + + - Trigger Width + +Trigger parameters are: + + - Trigger Width + - List if trig elements to use in trigger + +Recorder parameters are: + + - Data Width + - Maximum size of Record + +MigLa parameters are: + + - CSR address : core base Address + - Trigger object to use + - Recorder object to use + +Driver +------ + +To use drivers functions, an interface is defined:: + + csr = Uart2Spi(1,115200,debug=False) + + [...] + + migLa0 = migLa.MigLa(MIGLA_ADDR, trigger0, recorder0, csr) + +MigLa drivers functions will now use our csr interface. Note that it's only useful to define the migLa interface in the Python code that will be executed on the Host, the code that will be translated in HDL don't need it + +Examples Design +--------------- + +de0_nano and de1 examples instanciate a MigLa Core. + +The HDL Code is in examples/deX/top.py + +The Host Code is in examples/deX/client/test_MigLa_0.py and test_MigLa_1.py + +Examples Design +############### + +[To be done] diff --git a/migScope/__init__.py b/migScope/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/migScope/migIo.py b/migScope/migIo.py deleted file mode 100644 index 5e4ff4fa..00000000 --- a/migScope/migIo.py +++ /dev/null @@ -1,42 +0,0 @@ -from migen.fhdl.structure import * -from migen.bus import csr -from migen.bank import description, csrgen -from migen.bank.description import * - - -class MigIo: - # - # Definition - # - def __init__(self,address, width, mode = "IO", interface=None): - self.address = address - self.width = width - self.mode = mode - self.interface = interface - self.words = int(2**bits_for(width-1)/8) - if "I" in self.mode: - self.i = Signal(self.width) - self.ireg = description.RegisterField("i", self.width, READ_ONLY, WRITE_ONLY) - self.ireg.field.w.name_override = "inputs" - if "O" in self.mode: - self.o = Signal(self.width) - self.oreg = description.RegisterField("o", self.width) - self.oreg.field.r.name_override = "ouptuts" - self.bank = csrgen.Bank([self.oreg, self.ireg], address=self.address) - - def get_fragment(self): - comb = [] - if "I" in self.mode: - comb += [self.ireg.field.w.eq(self.i)] - if "O" in self.mode: - comb += [self.o.eq(self.oreg.field.r)] - return Fragment(comb=comb) + self.bank.get_fragment() - # - #Driver - # - def write(self, data): - self.interface.write_n(self.address, data, self.width) - - def read(self): - r = self.interface.read_n(self.address + self.words, self.width) - return r \ No newline at end of file diff --git a/migScope/migLa.py b/migScope/migLa.py deleted file mode 100644 index 781ccb35..00000000 --- a/migScope/migLa.py +++ /dev/null @@ -1,36 +0,0 @@ -from migen.fhdl.structure import * -from migen.bus import csr -from migen.bank import description, csrgen -from migen.bank.description import * - -import sys -sys.path.append("../") - -from migScope import trigger, recorder - -class MigLa: - def __init__(self,address, trig, rec, interface=None): - self.address = address - self.trig = trig - self.rec = rec - self.interface = interface - - self.in_trig = Signal(self.trig.trig_width) - self.in_dat = Signal(self.trig.trig_width) - - self.trig.set_address(self.address) - self.rec.set_address(self.address + 0x0200) - - self.trig.set_interface(self.interface) - self.rec.set_interface(self.interface) - - def get_fragment(self): - comb = [] - comb += [ - self.trig.in_trig.eq(self.in_trig), - ] - comb += [ - self.rec.trig_dat.eq(self.in_dat), - self.rec.trig_hit.eq(self.trig.hit) - ] - return Fragment(comb=comb) \ No newline at end of file diff --git a/migScope/recorder.py b/migScope/recorder.py deleted file mode 100644 index ebfc9d43..00000000 --- a/migScope/recorder.py +++ /dev/null @@ -1,245 +0,0 @@ -from migen.fhdl.structure import * -from migen.bus import csr -from migen.bank import description, csrgen -from migen.bank.description import * -from migen.corelogic.misc import optree - -class Storage: - # - # Definition - # - def __init__(self, width, depth): - self.width = width - self.depth = depth - self.depth_width = bits_for(self.depth) - #Control - self.rst = Signal() - self.start = Signal() - self.offset = Signal(self.depth_width) - self.size = Signal(self.depth_width) - self.done = Signal() - self.run = Signal() - - #Others - self._mem = Memory(self.width, self.depth) - - #Write Path - self.put = Signal() - self.put_dat = Signal(self.width) - self._put_ptr = Signal(self.depth_width) - self._put_ptr_stop = Signal(self.depth_width) - self._put_port = self._mem.get_port(write_capable=True) - - #Read Path - self.get = Signal() - self.get_dat = Signal(self.width) - self._get_ptr = Signal(self.depth_width) - self._get_port = self._mem.get_port(has_re=True) - - - def get_fragment(self): - comb = [] - sync = [] - memories = [self._mem] - comb += [ - self._get_port.adr.eq(self._get_ptr), - self._get_port.re.eq(self.get), - self.get_dat.eq(self._get_port.dat_r), - - self._put_port.adr.eq(self._put_ptr), - self._put_port.we.eq(self.put), - self._put_port.dat_w.eq(self.put_dat) - ] - - size_minus_offset = Signal(self.depth_width) - comb += [size_minus_offset.eq(self.size-self.offset)] - - #Control - sync += [ - If(self.rst, - self.run.eq(0), - self._put_ptr.eq(0) - ).Elif(self.start & ~self.run, - self.run.eq(1), - self._put_ptr_stop.eq(self._put_ptr + self.size - self.offset) - ).Elif(self.done, - self.run.eq(0) - ), - - If(self.put & ~self.done, - self._put_ptr.eq(self._put_ptr+1) - ), - - If(self.rst, - self.done.eq(0) - ).Elif((self._put_ptr == self._put_ptr_stop) & self.run, - self.done.eq(1) - ), - - If(self.rst, - self._get_ptr.eq(0) - ).Elif(self.start & ~self.run, - self._get_ptr.eq(self._put_ptr-self.offset-1) - ).Elif(self.get, - self._get_ptr.eq(self._get_ptr+1) - ) - ] - return Fragment(comb=comb, sync=sync, memories=memories) - -class Sequencer: - # - # Definition - # - def __init__(self,depth): - self.depth = depth - self.depth_width = bits_for(self.depth) - # Controller interface - self.ctl_rst = Signal() - self.ctl_offset = Signal(self.depth_width) - self.ctl_size = Signal(self.depth_width) - self.ctl_arm = Signal() - self.ctl_done = Signal() - self._ctl_arm_d = Signal() - # Triggers interface - self.trig_hit = Signal() - self._trig_hit_d = Signal() - # Recorder interface - self.rec_offset = Signal(self.depth_width) - self.rec_size = Signal(self.depth_width) - self.rec_start = Signal() - self.rec_done = Signal() - # Others - self.enable = Signal() - - def get_fragment(self): - comb = [] - sync = [] - #Control - sync += [ - If(self.ctl_rst, - self.enable.eq(0) - ).Elif(self.ctl_arm & ~self._ctl_arm_d, - self.enable.eq(1) - ).Elif(self.rec_done, - self.enable.eq(0) - ), - self._ctl_arm_d.eq(self.ctl_arm) - ] - sync += [self._trig_hit_d.eq(self.trig_hit)] - comb += [ - self.rec_offset.eq(self.ctl_offset), - self.rec_size.eq(self.ctl_size), - self.rec_start.eq(self.enable & (self.trig_hit & ~self._trig_hit_d)), - self.ctl_done.eq(~self.enable) - ] - return Fragment(comb=comb, sync=sync) - -class Recorder: - # - # Definition - # - def __init__(self, width, depth, address = 0x0000, interface = None): - self.address = address - self.width = width - self.depth = depth - self.depth_width = bits_for(self.depth) - self.interface = interface - - self.storage = Storage(self.width, self.depth) - self.sequencer = Sequencer(self.depth) - - # Csr interface - self._rst = RegisterField("rst", reset=1) - self._arm = RegisterField("arm", reset=0) - self._done = RegisterField("done", reset=0, access_bus=READ_ONLY, access_dev=WRITE_ONLY) - - self._size = RegisterField("size", self.depth_width, reset=1) - self._offset = RegisterField("offset", self.depth_width, reset=1) - - self._get = RegisterField("get", reset=0) - self._get_dat = RegisterField("get_dat", self.width, reset=1, access_bus=READ_ONLY, access_dev=WRITE_ONLY) - - self.regs = [self._rst, self._arm, self._done, - self._size, self._offset, - self._get, self._get_dat] - - self.bank = csrgen.Bank(self.regs,address=self.address) - - # Trigger Interface - self.trig_hit = Signal() - self.trig_dat = Signal(self.width) - - def set_address(self, address): - self.address = address - self.bank = csrgen.Bank(self.regs,address=self.address) - - def set_interface(self, interface): - self.interface = interface - - def get_fragment(self): - comb = [] - sync = [] - - _get_d = Signal() - _get_rising = Signal() - - sync += [ - _get_d.eq(self._get.field.r), - _get_rising.eq(self._get.field.r & ~_get_d) - ] - - #Bank <--> Storage / Sequencer - comb += [ - self.sequencer.ctl_rst.eq(self._rst.field.r), - self.storage.rst.eq(self._rst.field.r), - self.sequencer.ctl_offset.eq(self._offset.field.r), - self.sequencer.ctl_size.eq(self._size.field.r), - self.sequencer.ctl_arm.eq(self._arm.field.r), - self._done.field.w.eq(self.sequencer.ctl_done), - self.storage.get.eq(_get_rising), - self._get_dat.field.w.eq(self.storage.get_dat) - ] - - #Storage <--> Sequencer <--> Trigger - comb += [ - self.storage.offset.eq(self.sequencer.rec_offset), - self.storage.size.eq(self.sequencer.rec_size), - self.storage.start.eq(self.sequencer.rec_start), - self.sequencer.rec_done.eq(self.storage.done), - self.sequencer.trig_hit.eq(self.trig_hit), - self.storage.put.eq(self.sequencer.enable), - self.storage.put_dat.eq(self.trig_dat) - - ] - - return self.bank.get_fragment()+\ - self.storage.get_fragment()+self.sequencer.get_fragment()+\ - Fragment(comb=comb, sync=sync) - - # - #Driver - # - def reset(self): - self.interface.write(self.address + 0x00, 1) - self.interface.write(self.address + 0x00, 0) - - def arm(self): - self.interface.write(self.address + 0x01, 1) - self.interface.write(self.address + 0x01, 0) - - def is_done(self): - return self.interface.read(self.address + 0x02) == 1 - - def size(self, dat): - self.interface.write_n(self.address + 0x03, dat, 16) - - def offset(self, dat): - self.interface.write_n(self.address + 0x05, dat, 16) - - def read(self, size): - r = [] - for i in range(size): - self.interface.write(self.address+7, 1) - self.interface.write(self.address+7, 0) - r.append(self.interface.read_n(self.address+8,self.width)) - return r diff --git a/migScope/tools/__init__.py b/migScope/tools/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/migScope/tools/conv.py b/migScope/tools/conv.py deleted file mode 100644 index 66b88db8..00000000 --- a/migScope/tools/conv.py +++ /dev/null @@ -1,11 +0,0 @@ -def dec2bin(d, nb=0): - if d=="x": - return "x"*nb - elif d==0: - b="0" - else: - b="" - while d!=0: - b="01"[d&1]+b - d=d>>1 - return b.zfill(nb) diff --git a/migScope/tools/truthtable.py b/migScope/tools/truthtable.py deleted file mode 100644 index 14ce7969..00000000 --- a/migScope/tools/truthtable.py +++ /dev/null @@ -1,47 +0,0 @@ -import os -import re -import sys - -def is_number(x): - try: - _ = float(x) - except ValueError: - return False - return True - -def remove_numbers(seq): - return [ x for x in seq if not is_number(x)] - -def remove_duplicates(seq): - seen = set() - seen_add = seen.add - return [ x for x in seq if x not in seen and not seen_add(x)] - -def get_operands(s): - operands = re.findall("[A-z0-9_]+", s) - operands = remove_duplicates(operands) - operands = remove_numbers(operands) - return sorted(operands) - -def gen_truth_table(s): - operands = get_operands(s) - width = len(operands) - stim = [] - for i in range(width): - stim_op = [] - for j in range(2**width): - stim_op.append((int(j/(2**i)))%2) - stim.append(stim_op) - - truth_table = [] - for i in range(2**width): - for j in range(width): - exec("%s = stim[j][i]" %operands[j]) - truth_table.append(eval(s) != 0) - return truth_table - -def main(): - print(gen_truth_table("(A&B&C)|D")) - -if __name__ == '__main__': - main() diff --git a/migScope/tools/vcd.py b/migScope/tools/vcd.py deleted file mode 100644 index c66811b3..00000000 --- a/migScope/tools/vcd.py +++ /dev/null @@ -1,188 +0,0 @@ -import sys -import datetime - -sys.path.append("../../") -from migScope.tools.conv import * - -def get_bits(values, width, low, high =None): - r = [] - for val in values: - t = dec2bin(val,width)[::-1] - if high == None: - t = t[low] - else: - t = t[low:high] - t = t[::1] - t = int(t,2) - r.append(t) - return r - -class Var: - def __init__(self,type , width , name, values=[], default="x"): - self.type = type - self.width = width - self.name = name - self.val = default - self.values = values - self.vcd_id = None - - def set_vcd_id(self, s): - self.vcd_id = s - - def __len__(self): - return len(self.values) - - def change(self, cnt): - r = "" - try : - if self.values[cnt+1] != self.val: - r += "b" - r += dec2bin(self.values[cnt+1], self.width) - r += " " - r += self.vcd_id - r += "\n" - return r - except : - return r - return r - - -class Vcd: - def __init__(self,timescale = "1ps", comment = ""): - self.timescale = timescale - self.comment = comment - self.vars = [] - self.vcd_id = "!" - self.cnt = -1 - - def add(self, var): - var.set_vcd_id(self.vcd_id) - self.vcd_id = chr(ord(self.vcd_id)+1) - self.vars.append(var) - - def __len__(self): - l = 0 - for var in self.vars: - l = max(len(var),l) - return l - - def change(self): - r = "" - c = "" - for var in self.vars: - c += var.change(self.cnt) - if c != "": - r += "#" - r += str(self.cnt+1) - r += "\n" - r += c - return r - - - def p_date(self): - now = datetime.datetime.now() - r = "$date\n" - r += "\t" - r += now.strftime("%Y-%m-%d %H:%M") - r += "\n" - r += "$end\n" - return r - - def p_version(self): - r = "$version\n" - r += "\tmiscope VCD dump\n" - r += "$end\n" - return r - - def p_comment(self): - r = "$comment\n" - r += self.comment - r += "\n$end\n" - return r - - def p_timescale(self): - r = "$timescale " - r += self.timescale - r += " $end\n" - return r - - def p_scope(self): - r = "$scope " - r += self.timescale - r += " $end\n" - return r - def p_vars(self): - r = "" - for var in self.vars: - r += "$var " - r += var.type - r += " " - r += str(var.width) - r += " " - r += var.vcd_id - r += " " - r += var.name - r += " $end\n" - return r - - def p_unscope(self): - r = "$unscope " - r += " $end\n" - return r - - def p_enddefinitions(self): - r = "$enddefinitions " - r += " $end\n" - return r - - def p_dumpvars(self): - r = "$dumpvars\n" - for var in self.vars: - r += "b" - r += dec2bin(var.val, var.width) - r += " " - r += var.vcd_id - r+= "\n" - r += "$end\n" - return r - - def p_valuechange(self): - r = "" - for i in range(len(self)): - r += self.change() - self.cnt += 1 - return r - - - def __repr__(self): - r = "" - r += self.p_date() - r += self.p_version() - r += self.p_comment() - r += self.p_timescale() - r += self.p_scope() - r += self.p_vars() - r += self.p_unscope() - r += self.p_enddefinitions() - r += self.p_dumpvars() - r += self.p_valuechange() - return r - - def write(self, filename): - f = open(filename, "w") - f.write(str(self)) - f.close() - -def main(): - myvcd = Vcd() - myvcd.add(Var("wire", 1, "foo1", [0,1,0,1,0,1])) - myvcd.add(Var("wire", 2, "foo2", [1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0])) - myvcd.add(Var("wire", 3, "foo3")) - myvcd.add(Var("wire", 4, "foo4")) - ramp = [i%128 for i in range(1024)] - myvcd.add(Var("wire", 16, "ramp", ramp)) - print(myvcd) - -if __name__ == '__main__': - main() - diff --git a/migScope/trigger.py b/migScope/trigger.py deleted file mode 100644 index cde9890d..00000000 --- a/migScope/trigger.py +++ /dev/null @@ -1,387 +0,0 @@ -from migen.fhdl.structure import * -from migen.bus import csr -from migen.bank import description, csrgen -from migen.bank.description import * -from migen.corelogic.misc import optree - -class Term: - # - # Definition - # - def __init__(self, width, pipe=False): - self.width = width - self.pipe = pipe - self.interface = None - - self.reg_name = "term_reg" - self.reg_base = 0 - self.reg_size = 2*width - self.words = int(2**bits_for(width-1)/8) - - self.i = Signal(self.width) - self.t = Signal(self.width) - self.m = Signal(self.width) - self.o = Signal() - - def get_fragment(self): - frag = [ - self.o.eq((self.m & self.i) == self.t) - ] - if self.pipe: - return Fragment(sync=frag) - else: - return Fragment(comb=frag) - - def connect_to_reg(self, reg): - comb = [] - comb += [self.t.eq(reg.field.r[0*self.width:1*self.width])] - comb += [self.m.eq(reg.field.r[1*self.width:2*self.width])] - return comb - # - #Driver - # - def write(self, dat, mask = None): - if mask == None: - mask = (2**self.width)-1 - self.interface.write_n(self.reg_base + self.words, dat ,self.width) - self.interface.write_n(self.reg_base, mask ,self.width) - -class RangeDetector: - # - # Definition - # - def __init__(self, width, pipe=False): - self.width = width - self.pipe = pipe - self.interface = None - - self.reg_name = "range_reg" - self.reg_base = 0 - self.reg_size = 2*width - self.words = int(2**bits_for(width-1)/8) - - self.i = Signal(self.width) - self.low = Signal(self.width) - self.high = Signal(self.width) - self.o = Signal() - - def get_fragment(self): - frag = [ - self.o.eq((self.i >= self.low) & ((self.i <= self.high))) - ] - if self.pipe: - return Fragment(sync=frag) - else: - return Fragment(comb=frag) - - def connect_to_reg(self, reg): - comb = [] - comb += [self.low.eq(reg.field.r[0*self.width:1*self.width])] - comb += [self.low.eq(reg.field.r[1*self.width:2*self.width])] - return comb - # - #Driver - # - def write_low(self, dat): - self.interface.write_n(self.reg_base, dat ,self.width) - - def write_high(self, dat): - self.interface.write_n(self.reg_base + self.words, dat ,self.width) - -class EdgeDetector: - # - # Definition - # - def __init__(self, width, pipe=False, mode = "RFB"): - self.width = width - self.pipe = pipe - self.mode = mode - self.interface = None - - self.reg_name = "edge_reg" - self.reg_base = 0 - self.reg_size = len(self.mode)*width - - self.i = Signal(self.width) - self.i_d = Signal(self.width) - if "R" in self.mode: - self.r_mask = Signal(self.width) - self.ro = Signal() - if "F" in self.mode: - self.f_mask = Signal(self.width) - self.fo = Signal() - if "B" in self.mode: - self.b_mask = Signal(self.width) - self.bo = Signal() - self.o = Signal() - - def get_fragment(self): - comb = [] - sync = [] - sync += [self.i_d.eq(self.i)] - # Rising Edge - if "R" in self.mode: - r_eq = [self.ro.eq(self.r_mask & self.i & (~self.i_d))] - if self.pipe: - sync += r_eq - else: - comb += r_eq - else: - comb += [self.ro.eq(0)] - # Falling Edge - if "F" in self.mode: - f_eq = [self.fo.eq(self.f_mask & (~ self.i) & self.i_d)] - if self.pipe: - sync += f_eq - else: - comb += f_eq - else: - comb += [self.fo.eq(0)] - # Both - if "B" in self.mode: - b_eq = [self.bo.eq(self.b_mask & self.i != self.i_d)] - if self.pipe: - sync += b_eq - else: - comb += b_eq - else: - comb += [self.bo.eq(0)] - #Output - comb += [self.o.eq(self.ro | self.fo | self.bo)] - - return Fragment(comb, sync) - - def connect_to_reg(self, reg): - comb = [] - i = 0 - if "R" in self.mode: - comb += [self.r_mask.eq(reg.field.r[i*self.width:(i+1)*self.width])] - i += 1 - if "F" in self.mode: - comb += [self.f_mask.eq(reg.field.r[i*self.width:(i+1)*self.width])] - i += 1 - if "B" in self.mode: - comb += [self.b_mask.eq(reg.field.r[i*self.width:(i+1)*self.width])] - i += 1 - return comb - - # - #Driver - # - - def get_offset(self, type): - if type == "R": - r = 0 - r = r+self.words if "F" in self.mode else r - r = r+self.words if "B" in self.mode else r - return r - elif type == "F": - r = 0 - r = r+self.words if "B" in self.mode else r - return r - elif type == "B": - r = 0 - return r - return 0 - - def write_r(self, dat): - self.interface.write_n(self.reg_base + self.get_offset("R"), dat ,self.width) - - def write_f(self, dat): - self.interface.write_n(self.reg_base + self.get_offset("F"), dat ,self.width) - - def write_b(self, dat): - self.interface.write_n(self.reg_base + self.get_offset("B"), dat ,self.width) - -class Timer: - # - # Definition - # - def __init__(self, width): - self.width = width - self.interface = None - - self.start = Signal() - self.stop = Signal() - self.clear = Signal() - - self.enable = Signal() - self.cnt = Signal(self.width) - self.cnt_max = Signal(self.width) - - self.o = Signal() - - def get_fragment(self): - comb = [] - sync = [] - sync += [ - If(self.stop, - self.enable.eq(0), - self.cnt.eq(0), - self.o.eq(0) - ).Elif(self.clear, - self.cnt.eq(0), - self.o.eq(0) - ).Elif(self.start, - self.enable.eq(1) - ).Elif(self.enable, - If(self.cnt <= self.cnt_max, - self.cnt.eq(self.cnt+1) - ).Else( - self.o.eq(1) - ) - ), - If(self.enable, - self.enable.eq(0), - self.cnt.eq(0) - ).Elif(self.clear, - self.cnt.eq(0) - ).Elif(self.start, - self.enable.eq(1) - ) - - ] - - return Fragment(comb, sync) - -class Sum: - # - # Definition - # - def __init__(self,width=4,pipe=False): - self.width = width - self.pipe = pipe - self.interface = None - - self._mem = Memory(1, 2**self.width) - - self.i = Signal(self.width) - self._o = Signal() - self.o = Signal() - self._lut_port = self._mem.get_port() - - self.reg_name = "sum_reg" - self.reg_base = 0 - self.reg_size = 32 - - self.prog = Signal() - self.prog_adr = Signal(width) - self.prog_dat = Signal() - self._prog_port = self._mem.get_port(write_capable=True) - - - def get_fragment(self): - comb = [] - sync = [] - memories = [self._mem] - comb += [ - self._lut_port.adr.eq(self.i), - self._o.eq(self._lut_port.dat_r), - - self._prog_port.adr.eq(self.prog_adr), - self._prog_port.we.eq(self.prog), - self._prog_port.dat_w.eq(self.prog_dat) - ] - - - if self.pipe: - sync += [self.o.eq(self._o)] - else: - comb += [self.o.eq(self._o)] - return Fragment(comb=comb, sync=sync, memories=memories) - - def connect_to_reg(self, reg): - comb = [] - comb += [ - self.prog_adr.eq(reg.field.r[0:16]), - self.prog_dat.eq(reg.field.r[16]), - self.prog.eq(reg.field.r[17]) - ] - return comb - - # - #Driver - # - def write(self, truth_table): - for i in range(len(truth_table)): - val = truth_table[i] - we = 1<<17 - dat = val<<16 - addr = i - self.interface.write_n(self.reg_base, we + dat + addr,self.reg_size) - self.interface.write_n(self.reg_base, dat + addr, self.reg_size) - -class Trigger: - # - # Definition - # - def __init__(self, trig_width, ports, address = 0x0000, interface = None): - self.address = address - self.trig_width = trig_width - self.ports = ports - self.interface = interface - self.sum = Sum(len(self.ports)) - - self.in_trig = Signal(self.trig_width) - - self.hit = Signal() - - # Update port reg_name - for i in range(len(self.ports)): - self.ports[i].reg_name += "_%d"%i - - # Csr interface - for port in self.ports: - setattr(self,port.reg_name,RegisterField(port.reg_name, port.reg_size, reset=0, - access_bus=WRITE_ONLY, access_dev=READ_ONLY)) - self.sum_reg = RegisterField(self.sum.reg_name, self.sum.reg_size, reset=0, access_bus=WRITE_ONLY, access_dev=READ_ONLY) - - self.regs = [] - objects = self.__dict__ - for object in sorted(objects): - if "_reg" in object: - self.regs.append(objects[object]) - self.bank = csrgen.Bank(self.regs,address=self.address) - - # Update base addr - self.set_address(self.address) - - # Update interface - self.set_interface(self.interface) - - def set_address(self, address): - self.address = address - self.bank = csrgen.Bank(self.regs,address=self.address) - for port in self.ports: - port.reg_base = self.bank.get_base(port.reg_name) - self.sum.reg_base = self.bank.get_base(self.sum.reg_name) - - def set_interface(self, interface): - self.interface = interface - for port in self.ports: - port.interface = self.interface - self.sum.interface = self.interface - - def get_fragment(self): - comb = [] - sync = [] - # Connect in_trig to input of trig elements - comb+= [port.i.eq(self.in_trig) for port in self.ports] - - # Connect output of trig elements to sum - comb+= [self.sum.i[j].eq(self.ports[j].o) for j in range(len(self.ports))] - - # Connect sum ouput to hit - comb+= [self.hit.eq(self.sum.o)] - - # Add ports & sum to frag - frag = self.bank.get_fragment() - frag += self.sum.get_fragment() - for port in self.ports: - frag += port.get_fragment() - - #Connect Registers - for port in self.ports: - comb += port.connect_to_reg(getattr(self, port.reg_name)) - comb += self.sum.connect_to_reg(self.sum_reg) - return frag + Fragment(comb=comb, sync=sync) diff --git a/miscope/__init__.py b/miscope/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/miscope/miio.py b/miscope/miio.py new file mode 100644 index 00000000..a65f6fb6 --- /dev/null +++ b/miscope/miio.py @@ -0,0 +1,47 @@ +from migen.fhdl.structure import * +from migen.bus import csr +from migen.bank import description, csrgen +from migen.bank.description import * + +class MiIo: + # + # Definition + # + def __init__(self, address, width, mode = "IO", interface=None): + self.address = address + self.width = width + self.mode = mode + self.interface = interface + self.words = int(2**bits_for(width-1)/8) + + if "I" in self.mode: + self.i = Signal(self.width) + self.ireg = description.RegisterField("i", self.width, READ_ONLY, WRITE_ONLY) + self.ireg.field.w.name_override = "inputs" + + if "O" in self.mode: + self.o = Signal(self.width) + self.oreg = description.RegisterField("o", self.width) + self.oreg.field.r.name_override = "ouptuts" + + self.bank = csrgen.Bank([self.oreg, self.ireg], address=self.address) + + def get_fragment(self): + comb = [] + + if "I" in self.mode: + comb += [self.ireg.field.w.eq(self.i)] + + if "O" in self.mode: + comb += [self.o.eq(self.oreg.field.r)] + + return Fragment(comb) + self.bank.get_fragment() + # + #Driver + # + def write(self, data): + self.interface.write_n(self.address, data, self.width) + + def read(self): + r = self.interface.read_n(self.address + self.words, self.width) + return r \ No newline at end of file diff --git a/miscope/mila.py b/miscope/mila.py new file mode 100644 index 00000000..e49887ba --- /dev/null +++ b/miscope/mila.py @@ -0,0 +1,38 @@ +from migen.fhdl.structure import * +from migen.bus import csr +from migen.bank import description, csrgen +from migen.bank.description import * + +from miscope import trigger, recorder + +class MiLa: + def __init__(self, address, trigger, recorder, interface=None): + + self.trigger = trigger + self.recorder = recorder + self.interface = interface + + self.trig = Signal(self.trigger.trig_w) + self.dat = Signal(self.trigger.trig_w) + + self.set_address(address) + self.set_interface(interface) + + def set_interface(self, i): + self.interface = i + self.trigger.set_interface(i) + self.recorder.set_interface(i) + + def set_address(self, i): + self.address = address + self.trigger.set_address(self.address) + self.recorder.set_address(self.address + 0x0200) + + def get_fragment(self): + comb =[ + self.trigger.trig.eq(self.trig), + + self.recorder.dat.eq(self.dat), + self.recorder.hit.eq(self.trigger.hit) + ] + return Fragment(comb) \ No newline at end of file diff --git a/miscope/recorder.py b/miscope/recorder.py new file mode 100644 index 00000000..022596d2 --- /dev/null +++ b/miscope/recorder.py @@ -0,0 +1,284 @@ +from migen.fhdl.structure import * +from migen.bus import csr +from migen.bank import description, csrgen +from migen.bank.description import * +from migen.corelogic.misc import optree + +class Storage: + # + # Definition + # + def __init__(self, width, depth): + self.width = width + self.depth = depth + self.depth_width = bits_for(self.depth) + + # Control + self.rst = Signal() + self.start = Signal() + self.offset = Signal(self.depth_width) + self.size = Signal(self.depth_width) + self.done = Signal() + + # Push Path + self.push_stb = Signal() + self.push_dat = Signal(self.width) + self._push_ptr = Signal(self.depth_width) + self._push_ptr_stop = Signal(self.depth_width) + + # Pull Path + self.pull_stb = Signal() + self.pull_dat = Signal(self.width) + self._pull_ptr = Signal(self.depth_width) + + # Memory + self._mem = Memory(self.width, self.depth) + self._push_port = self._mem.get_port(write_capable=True) + self._pull_port = self._mem.get_port(has_re=True) + + def get_fragment(self): + comb = [ + self._push_port.adr.eq(self._push_ptr), + self._push_port.we.eq(self.push), + self._push_port.dat_w.eq(self.push_dat), + + self._pull_port.adr.eq(self._pull_ptr), + self._pull_port.re.eq(self.pull_stb), + self.pull_dat.eq(self._pull_port.dat_r) + ] + + size_minus_offset = Signal(self.depth_width) + comb += [size_minus_offset.eq(self.size-self.offset)] + + idle_rising = Signal() + idle_ongoing = Signal() + active_rising = Signal() + active_ongoing = Signal() + + # FSM + fsm = FSM("IDLE", "ACTIVE") + + # Idle + fsm.act(fsm.IDLE, + If(self.start, + fsm.next_state(fsm.PUSH), + active_rising.eq(1) + ), + idle_ongoing.eq(1) + ) + + # Active + fsm.act(fsm.ACTIVE, + If(self.done | self.rst, + fsm.next_state(fsm.IDLE), + idle_rising.eq(1) + ), + active_ongoing.eq(1) + ) + + sync +=[ + If(active_rising, + self._push_ptr_stop.eq(self._push_ptr + self.size - self.offset), + self._pull_ptr.eq(self._push_ptr-self.offset-1) + ).Else( + If(self.pull_stb, self._pull_ptr.eq(self._pull_ptr+1)) + ), + If(self.push_stb, self._push_ptr.eq(self._push_ptr+1)), + ] + comb +=[self.done.eq((self._put_ptr == self._put_ptr_stop) & active_ongoing)] + + return Fragment(comb, sync, memories=self._mem) + +class Sequencer: + # + # Definition + # + def __init__(self,depth): + self.depth = depth + self.depth_width = bits_for(self.depth) + + # Controller interface + self.ctl_rst = Signal() + self.ctl_offset = Signal(self.depth_width) + self.ctl_size = Signal(self.depth_width) + self.ctl_arm = Signal() + self.ctl_done = Signal() + self._ctl_arm_d = Signal() + + # Trigger interface + self.hit = Signal() + + # Recorder interface + self.rec_offset = Signal(self.depth_width) + self.rec_size = Signal(self.depth_width) + self.rec_start = Signal() + self.rec_done = Signal() + + # Others + self.enable = Signal() + + def get_fragment(self): + + idle_rising = Signal() + idle_ongoing = Signal() + active_rising = Signal() + active_ongoing = Signal() + + # FSM + fsm = FSM("IDLE", "ACTIVE") + + # Idle + fsm.act(fsm.IDLE, + If(self.ctl_arm, + fsm.next_state(fsm.PUSH), + active_rising.eq(1) + ), + idle_ongoing.eq(1) + ) + + # Active + fsm.act(fsm.ACTIVE, + If(self.rec_done | self.rst, + fsm.next_state(fsm.IDLE), + idle_rising.eq(1) + ), + active_ongoing.eq(1) + ) + comb +=[self.enable.eq(active_ongoing)] + + # trig_hit rising_edge + _hit_d = Signal() + _hit_rising = Signal() + sync +=[_hit_d.eq(self.hit)] + comb +=[_hit_rising.eq(self.hit & ~_hit_d] + + # connexion + comb = [ + self.rec_offset.eq(self.ctl_offset), + self.rec_size.eq(self.ctl_size), + self.rec_start.eq(self.enable & _hit_rising), + self.ctl_done.eq(~self.enable) + ] + return Fragment(comb, sync) + + +REC_RST_BASE = 0x00 +REC_ARM_BASE = 0x01 +REC_DONE_BASE = 0x02 +REC_SIZE_BASE = 0x03 +REC_OFFSET_BASE = 0x05 +REC_READ_BASE = 0x07 +REC_READ_DATA_BASE = 0x09 + +class Recorder: + # + # Definition + # + def __init__(self, width, depth, address = 0x0000, interface = None): + self.width = width + self.depth = depth + self.depth_width = bits_for(self.depth) + + self.storage = Storage(self.width, self.depth) + self.sequencer = Sequencer(self.depth) + + # csr interface + self._rst = RegisterField("rst", reset=1) + self._arm = RegisterField("arm", reset=0) + self._done = RegisterField("done", reset=0, access_bus=READ_ONLY, + access_dev=WRITE_ONLY) + + self._size = RegisterField("size", self.depth_width, reset=1) + self._offset = RegisterField("offset", self.depth_width, reset=1) + + self._pull_stb = RegisterField("pull_stb", reset=0) + self._pull_dat = RegisterField("pull_dat", self.width, reset=1, + access_bus=READ_ONLY, access_dev=WRITE_ONLY) + + self.regs = [self._rst, self._arm, self._done, self._size, self._offset, + self._get, self._get_dat] + + self.bank = csrgen.Bank(self.regs, address=address) + + # set address / interface + self.set_address(address) + self.set_interface(interface) + + # trigger Interface + self.hit = Signal() + self.dat = Signal(self.width) + + def set_address(self, address): + self.address = address + self.bank = csrgen.Bank(self.regs,address=self.address) + + def set_interface(self, interface): + self.interface = interface + + def get_fragment(self): + _pull_d = Signal() + _pull_rising = Signal() + + sync = [ + _pull_d.eq(self._pull.field.r), + _pull_rising.eq(self._pull.field.r & ~_pull_d) + ] + + # Bank <--> Storage / Sequencer + comb = [ + self.sequencer.ctl_rst.eq(self._rst.field.r), + self.storage.rst.eq(self._rst.field.r), + + self.sequencer.ctl_offset.eq(self._offset.field.r), + self.sequencer.ctl_size.eq(self._size.field.r), + self.sequencer.ctl_arm.eq(self._arm.field.r), + + self._done.field.w.eq(self.sequencer.ctl_done), + + self.storage.pull_stb.eq(_pull_rising), + self._pull_dat.field.w.eq(self.storage.pull_dat) + ] + + # Storage <--> Sequencer <--> Trigger + comb += [ + self.storage.offset.eq(self.sequencer.rec_offset), + self.storage.size.eq(self.sequencer.rec_size), + self.storage.start.eq(self.sequencer.rec_start), + + self.sequencer.rec_done.eq(self.storage.done), + self.sequencer.hit.eq(self.hit), + + self.storage.put_stb.eq(self.sequencer.enable), + self.storage.put_dat.eq(self.dat) + ] + + return self.bank.get_fragment() + Fragment(comb, sync) +\ + self.storage.get_fragment() + self.sequencer.get_fragment() + + # + #Driver + # + def reset(self): + self.interface.write(self.address + REC_RST_BASE, 1) + self.interface.write(self.address + REC_RST_BASE, 0) + + def arm(self): + self.interface.write(self.address + REC_ARM_BASE, 1) + self.interface.write(self.address + REC_ARM_BASE, 0) + + def is_done(self): + return self.interface.read(self.address + REC_DONE_BASE) == 1 + + def size(self, dat): + self.interface.write_n(self.address + REC_SIZE_BASE, dat, 16) + + def offset(self, dat): + self.interface.write_n(self.address + REC_OFFSET_BASE, dat, 16) + + def read(self, size): + r = [] + for i in range(size): + self.interface.write(self.address + REC_READ_BASE, 1) + self.interface.write(self.address + REC_READ_BASE, 0) + r.append(self.interface.read_n(self.address + REC_READ_DATA_BASE, self.width)) + return r diff --git a/miscope/tools/__init__.py b/miscope/tools/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/miscope/tools/conv.py b/miscope/tools/conv.py new file mode 100644 index 00000000..66b88db8 --- /dev/null +++ b/miscope/tools/conv.py @@ -0,0 +1,11 @@ +def dec2bin(d, nb=0): + if d=="x": + return "x"*nb + elif d==0: + b="0" + else: + b="" + while d!=0: + b="01"[d&1]+b + d=d>>1 + return b.zfill(nb) diff --git a/miscope/tools/truthtable.py b/miscope/tools/truthtable.py new file mode 100644 index 00000000..14ce7969 --- /dev/null +++ b/miscope/tools/truthtable.py @@ -0,0 +1,47 @@ +import os +import re +import sys + +def is_number(x): + try: + _ = float(x) + except ValueError: + return False + return True + +def remove_numbers(seq): + return [ x for x in seq if not is_number(x)] + +def remove_duplicates(seq): + seen = set() + seen_add = seen.add + return [ x for x in seq if x not in seen and not seen_add(x)] + +def get_operands(s): + operands = re.findall("[A-z0-9_]+", s) + operands = remove_duplicates(operands) + operands = remove_numbers(operands) + return sorted(operands) + +def gen_truth_table(s): + operands = get_operands(s) + width = len(operands) + stim = [] + for i in range(width): + stim_op = [] + for j in range(2**width): + stim_op.append((int(j/(2**i)))%2) + stim.append(stim_op) + + truth_table = [] + for i in range(2**width): + for j in range(width): + exec("%s = stim[j][i]" %operands[j]) + truth_table.append(eval(s) != 0) + return truth_table + +def main(): + print(gen_truth_table("(A&B&C)|D")) + +if __name__ == '__main__': + main() diff --git a/miscope/tools/vcd.py b/miscope/tools/vcd.py new file mode 100644 index 00000000..c66811b3 --- /dev/null +++ b/miscope/tools/vcd.py @@ -0,0 +1,188 @@ +import sys +import datetime + +sys.path.append("../../") +from migScope.tools.conv import * + +def get_bits(values, width, low, high =None): + r = [] + for val in values: + t = dec2bin(val,width)[::-1] + if high == None: + t = t[low] + else: + t = t[low:high] + t = t[::1] + t = int(t,2) + r.append(t) + return r + +class Var: + def __init__(self,type , width , name, values=[], default="x"): + self.type = type + self.width = width + self.name = name + self.val = default + self.values = values + self.vcd_id = None + + def set_vcd_id(self, s): + self.vcd_id = s + + def __len__(self): + return len(self.values) + + def change(self, cnt): + r = "" + try : + if self.values[cnt+1] != self.val: + r += "b" + r += dec2bin(self.values[cnt+1], self.width) + r += " " + r += self.vcd_id + r += "\n" + return r + except : + return r + return r + + +class Vcd: + def __init__(self,timescale = "1ps", comment = ""): + self.timescale = timescale + self.comment = comment + self.vars = [] + self.vcd_id = "!" + self.cnt = -1 + + def add(self, var): + var.set_vcd_id(self.vcd_id) + self.vcd_id = chr(ord(self.vcd_id)+1) + self.vars.append(var) + + def __len__(self): + l = 0 + for var in self.vars: + l = max(len(var),l) + return l + + def change(self): + r = "" + c = "" + for var in self.vars: + c += var.change(self.cnt) + if c != "": + r += "#" + r += str(self.cnt+1) + r += "\n" + r += c + return r + + + def p_date(self): + now = datetime.datetime.now() + r = "$date\n" + r += "\t" + r += now.strftime("%Y-%m-%d %H:%M") + r += "\n" + r += "$end\n" + return r + + def p_version(self): + r = "$version\n" + r += "\tmiscope VCD dump\n" + r += "$end\n" + return r + + def p_comment(self): + r = "$comment\n" + r += self.comment + r += "\n$end\n" + return r + + def p_timescale(self): + r = "$timescale " + r += self.timescale + r += " $end\n" + return r + + def p_scope(self): + r = "$scope " + r += self.timescale + r += " $end\n" + return r + def p_vars(self): + r = "" + for var in self.vars: + r += "$var " + r += var.type + r += " " + r += str(var.width) + r += " " + r += var.vcd_id + r += " " + r += var.name + r += " $end\n" + return r + + def p_unscope(self): + r = "$unscope " + r += " $end\n" + return r + + def p_enddefinitions(self): + r = "$enddefinitions " + r += " $end\n" + return r + + def p_dumpvars(self): + r = "$dumpvars\n" + for var in self.vars: + r += "b" + r += dec2bin(var.val, var.width) + r += " " + r += var.vcd_id + r+= "\n" + r += "$end\n" + return r + + def p_valuechange(self): + r = "" + for i in range(len(self)): + r += self.change() + self.cnt += 1 + return r + + + def __repr__(self): + r = "" + r += self.p_date() + r += self.p_version() + r += self.p_comment() + r += self.p_timescale() + r += self.p_scope() + r += self.p_vars() + r += self.p_unscope() + r += self.p_enddefinitions() + r += self.p_dumpvars() + r += self.p_valuechange() + return r + + def write(self, filename): + f = open(filename, "w") + f.write(str(self)) + f.close() + +def main(): + myvcd = Vcd() + myvcd.add(Var("wire", 1, "foo1", [0,1,0,1,0,1])) + myvcd.add(Var("wire", 2, "foo2", [1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0])) + myvcd.add(Var("wire", 3, "foo3")) + myvcd.add(Var("wire", 4, "foo4")) + ramp = [i%128 for i in range(1024)] + myvcd.add(Var("wire", 16, "ramp", ramp)) + print(myvcd) + +if __name__ == '__main__': + main() + diff --git a/miscope/trigger.py b/miscope/trigger.py new file mode 100644 index 00000000..f6dcddb9 --- /dev/null +++ b/miscope/trigger.py @@ -0,0 +1,309 @@ +from migen.fhdl.structure import * +from migen.bus import csr +from migen.bank import description, csrgen +from migen.bank.description import * +from migen.corelogic.misc import optree + + +class RegParams: + def __init__(self, name, base, width, nb): + self.name = name + self.base = base + self.width = width + self.nb = nb + + self.size = nb*width + self.words = int(2**bits_for(self.width-1)/8) + +def list_regs(objects): + r = [] + for object in objects: + if "_reg" in object: + r.append(objects[object]) + return r + +class Term: + # + # Definition + # + def __init__(self, width): + self.width = width + self.interface = None + + self.i = Signal(width) + self.t = Signal(width) + self.m = Signal(width) + self.o = Signal() + + self.reg_p = RegParams("term_reg", 0, width, 2) + + def get_registers(self, reg): + comb = [self.t.eq(reg.field.r[0*self.width:1*self.width])] + comb += [self.m.eq(reg.field.r[1*self.width:2*self.width])] + return comb + + def get_fragment(self, reg): + comb = [self.o.eq((self.m & self.i) == self.t)] + comb += self.get_registers(reg) + return Fragment(comb) + + # + # Driver + # + def write(self, dat, mask=None): + if mask is None: + mask = (2**self.width)-1 + self.interface.write_n(self.reg_p.base + self.reg_p.words, dat, self.width) + self.interface.write_n(self.reg_p.base, mask, self.width) + +class RangeDetector: + # + # Definition + # + def __init__(self, width): + self.width = width + self.pipe = pipe + self.interface = None + + self.reg_p = RegParams("range_reg", 0, width, 2) + + self.i = Signal(width) + self.low = Signal(width) + self.high = Signal(width) + self.o = Signal() + + def get_registers(self, reg): + comb = [self.low.eq(reg.field.r[0*self.width:1*self.width])] + comb += [self.low.eq(reg.field.r[1*self.width:2*self.width])] + return comb + + def get_fragment(self, reg): + comb = [self.o.eq((self.i >= self.low) & (self.i <= self.high))] + comb += self.get_registers(reg) + return Fragment(comb) + # + # Driver + # + def write_low(self, dat): + self.interface.write_n(self.reg_p.base, dat ,self.width) + + def write_high(self, dat): + self.interface.write_n(self.reg_p.base + self.reg_p.words, dat ,self.width) + +class EdgeDetector: + # + # Definition + # + def __init__(self, width, mode = "RFB"): + self.width = width + self.mode = mode + self.interface = None + + self.reg_p = RegParams("edge_reg", 0, width, len(self.mode) + + self.i = Signal(self.width) + self.i_d = Signal(self.width) + if "R" in self.mode: + self.r_mask = Signal(self.width) + self.ro = Signal() + if "F" in self.mode: + self.f_mask = Signal(self.width) + self.fo = Signal() + if "B" in self.mode: + self.b_mask = Signal(self.width) + self.bo = Signal() + self.o = Signal() + + def get_registers(self, reg): + comb = [] + i = 0 + if "R" in self.mode: + comb += [self.r_mask.eq(reg.field.r[i*self.width:(i+1)*self.width])] + i += 1 + if "F" in self.mode: + comb += [self.f_mask.eq(reg.field.r[i*self.width:(i+1)*self.width])] + i += 1 + if "B" in self.mode: + comb += [self.b_mask.eq(reg.field.r[i*self.width:(i+1)*self.width])] + i += 1 + return comb + + def get_fragment(self, reg): + comb = [] + sync = [self.i_d.eq(self.i)] + + # Rising Edge + if "R" in self.mode: + comb += [self.ro.eq(self.r_mask & self.i & (~self.i_d))] + else: + comb += [self.ro.eq(0)] + + # Falling Edge + if "F" in self.mode: + comb += [self.fo.eq(self.f_mask & (~ self.i) & self.i_d)] + else: + comb += [self.fo.eq(0)] + + # Both + if "B" in self.mode: + comb += [self.bo.eq(self.b_mask & self.i != self.i_d)] + else: + comb += [self.bo.eq(0)] + + # Output + comb += [self.o.eq(self.ro | self.fo | self.bo)] + + # Registers + comb += self.get_registers(reg) + + return Fragment(comb, sync) + + # + # Driver + # + def get_offset(self, type): + if type == "R": + r = 0 + r = r + self.words if "F" in self.mode else r + r = r + self.words if "B" in self.mode else r + return r + elif type == "F": + r = 0 + r = r + self.words if "B" in self.mode else r + return r + elif type == "B": + r = 0 + return r + return 0 + + def write_r(self, dat): + self.interface.write_n(self.reg_p.base + self.get_offset("R"), dat ,self.width) + + def write_f(self, dat): + self.interface.write_n(self.reg_p.base + self.get_offset("F"), dat ,self.width) + + def write_b(self, dat): + self.interface.write_n(self.reg_p.base + self.get_offset("B"), dat ,self.width) + +class Sum: + # + # Definition + # + def __init__(self, width=4): + self.width = width + self.interface = None + + + + self.i = Signal(self.width) + self._o = Signal() + self.o = Signal() + + self.reg_p = RegParams("sum_reg", 0, 8, 4) + + self.prog_stb = Signal() + self.prog_adr = Signal(width) + self.prog_dat = Signal() + + self._mem = Memory(1, 2**self.width) + self._lut_port = self._mem.get_port() + self._prog_port = self._mem.get_port(write_capable=True) + + def get_registers(self, reg): + comb = [ + self.prog_adr.eq(reg.field.r[0:16]), + self.prog_dat.eq(reg.field.r[16]), + self.prog_stb.eq(reg.field.r[17]) + ] + return comb + + def get_fragment(self, reg): + comb = [ + self._lut_port.adr.eq(self.i), + self._o.eq(self._lut_port.dat_r), + + self._prog_port.adr.eq(self.prog_adr), + self._prog_port.we.eq(self.prog_stb), + self._prog_port.dat_w.eq(self.prog_dat) + + self.o.eq(self._o) + ] + comb += get_registers(reg) + return Fragment(comb, sync, memories=self._mem) + + # + #Driver + # + def write(self, truth_table): + for i in range(len(truth_table)): + val = truth_table[i] + we = 1<<17 + dat = val<<16 + addr = i + self.interface.write_n(self.reg_p.base, we + dat + addr, self.reg_size) + self.interface.write_n(self.reg_p.base, dat + addr, self.reg_size) + +class Trigger: + # + # Definition + # + def __init__(self, trig_w, ports, address=0x0000, interface=None): + self.trig_w = trig_w + self.ports = ports + + self.sum = Sum(len(ports)) + self.trig = Signal(self.trig_w) + self.hit = Signal() + + # insert port number in port reg name + for i in range(len(self.ports)): + self.ports[i].reg_p.name += "_%d"%i + + # generate ports csr registers fields + for port in self.ports: + rf = RegisterField(port.reg_p.name, port.reg_p.size, reset=0, + access_bus=WRITE_ONLY, access_dev=READ_ONLY) + setattr(self, port.reg_name, rf) + + # generate sum csr registers fields + self.sum_reg = RegisterField(self.sum.reg_p.name, self.sum.reg_p.size, reset=0, + access_bus=WRITE_ONLY, access_dev=READ_ONLY) + + # generate registers + self.regs = list_regs(self.__dict__) + self.bank = csrgen.Bank(self.regs, address=address) + + # update base addr & interface + self.set_address(self.address) + self.set_interface(self.interface) + + def set_address(self, address): + self.address = address + self.bank = csrgen.Bank(self.regs,address=self.address) + for port in self.ports: + port.reg_p.base = self.bank.get_base(port.reg_p.name) + self.sum.reg_p.base = self.bank.get_base(self.sum.reg_p.name) + + def set_interface(self, interface): + self.interface = interface + for port in self.ports: + port.interface = self.interface + self.sum.interface = self.interface + + def get_fragment(self): + # connect trig to input of each trig element + comb = [port.i.eq(self.in_trig) for port in self.ports] + + # connect output of trig elements to sum + comb += [self.sum.i[j].eq(self.ports[j].o) for j in range(len(self.ports))] + + # connect sum ouput to hit + comb += [self.hit.eq(self.sum.o)] + + # add ports & sum to frag + frag = self.bank.get_fragment() + frag += self.sum.get_fragment(self.sum_reg) + for port in self.ports: + frag += port.get_fragment(getattr(self, port.reg_name)) + + return frag + Fragment(comb) diff --git a/setup.py b/setup.py index ab62935c..de34491d 100644 --- a/setup.py +++ b/setup.py @@ -9,18 +9,18 @@ README = open(os.path.join(here, "README")).read() required_version = (3, 1) if sys.version_info < required_version: - raise SystemExit("MigScope requires python {0} or greater".format( + raise SystemExit("Migscope requires python {0} or greater".format( ".".join(map(str, required_version)))) setup( - name="migscope", + name="miscope", version="unknown", description="Migen based Fpga logic analyzer", long_description=README, author="Florent Kermarrec", author_email="florent@enjoy-digital.fr", url="http://enjoy-digital.fr", - download_url="https://github.com/Florent-Kermarrec/migScope", + download_url="https://github.com/Florent-Kermarrec/miscope", packages=find_packages(here), license="GPL", platforms=["Any"], diff --git a/sim/tb_Migscope.py b/sim/tb_Migscope.py deleted file mode 100644 index b27d4c61..00000000 --- a/sim/tb_Migscope.py +++ /dev/null @@ -1,178 +0,0 @@ -from migen.fhdl.structure import * -from migen.fhdl import verilog, autofragment -from migen.bus import csr -from migen.sim.generic import Simulator, PureSimulable, TopLevel -from migen.sim.icarus import Runner -from migen.bus.transactions import * - -import sys -sys.path.append("../") - -from migScope import trigger, recorder -from migScope.tools.truthtable import * -from migScope.tools.vcd import * - -TRIGGER_ADDR = 0x0000 -RECORDER_ADDR = 0x0200 - -rec_done = False -dat_rdy = False - -dat_vcd = [] - -def term_prog(off, dat): - for i in range(4): - yield TWrite(off+3-i, (dat>>(8*i))&0xFF) - - -def sum_prog(off, addr, dat): - we = 2 - yield TWrite(off+3, addr%0xFF) - yield TWrite(off+2, (addr>>8)%0xFF) - yield TWrite(off+1, we+dat) - yield TWrite(off+0, 0) - for i in range(4): - yield TWrite(off+i,0) - -def csr_transactions(trigger0, recorder0): - - # Trigger Prog - ############################## - - # Term Prog - term_trans = [] - term_trans += [term_prog(trigger0.ports[0].reg_base, 0x00000000)] - term_trans += [term_prog(trigger0.ports[1].reg_base, 0x00000004)] - term_trans += [term_prog(trigger0.ports[2].reg_base, 0x00000008)] - term_trans += [term_prog(trigger0.ports[3].reg_base, 0x0000000C)] - for t in term_trans: - for r in t: - yield r - - # Sum Prog - sum_tt = gen_truth_table("term0 | term1 | term2 | term3") - sum_trans = [] - for i in range(len(sum_tt)): - sum_trans.append(sum_prog(trigger0.sum.reg_base, i, sum_tt[i])) - for t in sum_trans: - for r in t: - yield r - - # Recorder Prog - ############################## - #Reset - yield TWrite(recorder0.address + 0, 1) - yield TWrite(recorder0.address + 0, 0) - - #Size - yield TWrite(recorder0.address + 3, 0) - yield TWrite(recorder0.address + 4, 64) - - #Offset - yield TWrite(recorder0.address + 5, 0) - yield TWrite(recorder0.address + 6, 16) - - #Arm - yield TWrite(recorder0.address + 1, 1) - - # Wait Record to be done - ############################## - global rec_done - while not rec_done: - yield None - - # Read recorded data - ############################## - global dat_rdy - for t in range(64): - yield TWrite(recorder0.address + 7, 1) - dat_rdy = False - yield TWrite(recorder0.address + 7, 0) - yield TRead(recorder0.address + 8) - yield TRead(recorder0.address + 9) - yield TRead(recorder0.address + 10) - yield TRead(recorder0.address + 11) - dat_rdy = True - - dat_rdy = False - - for t in range(512): - yield None - - -trig_sig_val = 0 - - -def main(): - - # Trigger - term0 = trigger.Term(32) - term1 = trigger.Term(32) - term2 = trigger.Term(32) - term3 = trigger.Term(32) - trigger0 = trigger.Trigger(TRIGGER_ADDR, 32, 64, [term0, term1, term2, term3]) - - # Recorder - recorder0 = recorder.Recorder(RECORDER_ADDR, 32, 1024) - - # Csr Master - csr_master0 = csr.Initiator(csr_transactions(trigger0, recorder0)) - - # Csr Interconnect - csrcon0 = csr.Interconnect(csr_master0.bus, - [ - trigger0.bank.interface, - recorder0.bank.interface - ]) - - trig_sig = Signal(32) - comb = [] - comb +=[ - trigger0.in_trig.eq(trig_sig) - ] - - comb += [ - recorder0.trig_dat.eq(trig_sig), - recorder0.trig_hit.eq(trigger0.hit) - ] - # Term Test - def term_stimuli(s): - global trig_sig_val - s.wr(trig_sig,trig_sig_val) - trig_sig_val += 1 - trig_sig_val = trig_sig_val % 256 - - # Recorder Data - def recorder_data(s): - global rec_done - if s.rd(recorder0.sequencer.rec_done) == 1: - rec_done = True - - global dat_rdy - if dat_rdy: - print("%08X" %s.rd(recorder0._get_dat.field.w)) - global dat_vcd - dat_vcd.append(s.rd(recorder0._get_dat.field.w)) - - - # Simulation - def end_simulation(s): - s.interrupt = csr_master0.done - myvcd = Vcd() - myvcd.add(Var("wire", 32, "trig_dat", dat_vcd)) - f = open("tb_Miscope_Out.vcd", "w") - f.write(str(myvcd)) - f.close() - - - fragment = autofragment.from_local() - fragment += Fragment(comb=comb) - fragment += Fragment(sim=[term_stimuli]) - fragment += Fragment(sim=[recorder_data]) - fragment += Fragment(sim=[end_simulation]) - - sim = Simulator(fragment, Runner(),TopLevel("tb_MigScope.vcd")) - sim.run(2000) - -main() -input() diff --git a/sim/tb_migcope.py b/sim/tb_migcope.py new file mode 100644 index 00000000..b27d4c61 --- /dev/null +++ b/sim/tb_migcope.py @@ -0,0 +1,178 @@ +from migen.fhdl.structure import * +from migen.fhdl import verilog, autofragment +from migen.bus import csr +from migen.sim.generic import Simulator, PureSimulable, TopLevel +from migen.sim.icarus import Runner +from migen.bus.transactions import * + +import sys +sys.path.append("../") + +from migScope import trigger, recorder +from migScope.tools.truthtable import * +from migScope.tools.vcd import * + +TRIGGER_ADDR = 0x0000 +RECORDER_ADDR = 0x0200 + +rec_done = False +dat_rdy = False + +dat_vcd = [] + +def term_prog(off, dat): + for i in range(4): + yield TWrite(off+3-i, (dat>>(8*i))&0xFF) + + +def sum_prog(off, addr, dat): + we = 2 + yield TWrite(off+3, addr%0xFF) + yield TWrite(off+2, (addr>>8)%0xFF) + yield TWrite(off+1, we+dat) + yield TWrite(off+0, 0) + for i in range(4): + yield TWrite(off+i,0) + +def csr_transactions(trigger0, recorder0): + + # Trigger Prog + ############################## + + # Term Prog + term_trans = [] + term_trans += [term_prog(trigger0.ports[0].reg_base, 0x00000000)] + term_trans += [term_prog(trigger0.ports[1].reg_base, 0x00000004)] + term_trans += [term_prog(trigger0.ports[2].reg_base, 0x00000008)] + term_trans += [term_prog(trigger0.ports[3].reg_base, 0x0000000C)] + for t in term_trans: + for r in t: + yield r + + # Sum Prog + sum_tt = gen_truth_table("term0 | term1 | term2 | term3") + sum_trans = [] + for i in range(len(sum_tt)): + sum_trans.append(sum_prog(trigger0.sum.reg_base, i, sum_tt[i])) + for t in sum_trans: + for r in t: + yield r + + # Recorder Prog + ############################## + #Reset + yield TWrite(recorder0.address + 0, 1) + yield TWrite(recorder0.address + 0, 0) + + #Size + yield TWrite(recorder0.address + 3, 0) + yield TWrite(recorder0.address + 4, 64) + + #Offset + yield TWrite(recorder0.address + 5, 0) + yield TWrite(recorder0.address + 6, 16) + + #Arm + yield TWrite(recorder0.address + 1, 1) + + # Wait Record to be done + ############################## + global rec_done + while not rec_done: + yield None + + # Read recorded data + ############################## + global dat_rdy + for t in range(64): + yield TWrite(recorder0.address + 7, 1) + dat_rdy = False + yield TWrite(recorder0.address + 7, 0) + yield TRead(recorder0.address + 8) + yield TRead(recorder0.address + 9) + yield TRead(recorder0.address + 10) + yield TRead(recorder0.address + 11) + dat_rdy = True + + dat_rdy = False + + for t in range(512): + yield None + + +trig_sig_val = 0 + + +def main(): + + # Trigger + term0 = trigger.Term(32) + term1 = trigger.Term(32) + term2 = trigger.Term(32) + term3 = trigger.Term(32) + trigger0 = trigger.Trigger(TRIGGER_ADDR, 32, 64, [term0, term1, term2, term3]) + + # Recorder + recorder0 = recorder.Recorder(RECORDER_ADDR, 32, 1024) + + # Csr Master + csr_master0 = csr.Initiator(csr_transactions(trigger0, recorder0)) + + # Csr Interconnect + csrcon0 = csr.Interconnect(csr_master0.bus, + [ + trigger0.bank.interface, + recorder0.bank.interface + ]) + + trig_sig = Signal(32) + comb = [] + comb +=[ + trigger0.in_trig.eq(trig_sig) + ] + + comb += [ + recorder0.trig_dat.eq(trig_sig), + recorder0.trig_hit.eq(trigger0.hit) + ] + # Term Test + def term_stimuli(s): + global trig_sig_val + s.wr(trig_sig,trig_sig_val) + trig_sig_val += 1 + trig_sig_val = trig_sig_val % 256 + + # Recorder Data + def recorder_data(s): + global rec_done + if s.rd(recorder0.sequencer.rec_done) == 1: + rec_done = True + + global dat_rdy + if dat_rdy: + print("%08X" %s.rd(recorder0._get_dat.field.w)) + global dat_vcd + dat_vcd.append(s.rd(recorder0._get_dat.field.w)) + + + # Simulation + def end_simulation(s): + s.interrupt = csr_master0.done + myvcd = Vcd() + myvcd.add(Var("wire", 32, "trig_dat", dat_vcd)) + f = open("tb_Miscope_Out.vcd", "w") + f.write(str(myvcd)) + f.close() + + + fragment = autofragment.from_local() + fragment += Fragment(comb=comb) + fragment += Fragment(sim=[term_stimuli]) + fragment += Fragment(sim=[recorder_data]) + fragment += Fragment(sim=[end_simulation]) + + sim = Simulator(fragment, Runner(),TopLevel("tb_MigScope.vcd")) + sim.run(2000) + +main() +input()