start refactoring and change name to LiteScope
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Thu, 22 Jan 2015 20:40:07 +0000 (21:40 +0100)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Thu, 22 Jan 2015 23:02:53 +0000 (00:02 +0100)
41 files changed:
LICENSE [new file with mode: 0644]
README
litesata-version.txt [new file with mode: 0644]
litescope/__init__.py [new file with mode: 0644]
litescope/bridge/uart2wb.py [new file with mode: 0644]
litescope/common.py [new file with mode: 0644]
litescope/core/storage.py [new file with mode: 0644]
litescope/core/trigger.py [new file with mode: 0644]
litescope/frontend/io.py [new file with mode: 0644]
litescope/frontend/la.py [new file with mode: 0644]
litescope/host/__init__.py [new file with mode: 0644]
litescope/host/cpuif.py [new file with mode: 0644]
litescope/host/driver.py [new file with mode: 0644]
litescope/host/dump.py [new file with mode: 0644]
litescope/host/reg.py [new file with mode: 0644]
litescope/host/truthtable.py [new file with mode: 0644]
make.py [new file with mode: 0644]
miscope/__init__.py [deleted file]
miscope/host/__init__.py [deleted file]
miscope/host/cpuif.py [deleted file]
miscope/host/drivers.py [deleted file]
miscope/host/dump.py [deleted file]
miscope/host/regs.py [deleted file]
miscope/host/truthtable.py [deleted file]
miscope/host/uart2wishbone.py [deleted file]
miscope/miio.py [deleted file]
miscope/mila.py [deleted file]
miscope/std.py [deleted file]
miscope/storage.py [deleted file]
miscope/trigger.py [deleted file]
miscope/uart2wishbone.py [deleted file]
setup.py
sim/cpuif.py [deleted file]
sim/tb_recorder_csr.py [deleted file]
sim/tb_rle.py [deleted file]
sim/tb_trigger_csr.py [deleted file]
targets/__init__.py [new file with mode: 0644]
targets/simple.py [new file with mode: 0644]
test/Makefile [new file with mode: 0644]
test/config.py [new file with mode: 0644]
test/test_regs.py [new file with mode: 0644]

diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..95ac4a6
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,28 @@
+Unless otherwise noted, LiteScope is copyright (C) 2015 Florent Kermarrec.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+   list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+   this list of conditions and the following disclaimer in the documentation
+   and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+Other authors retain ownership of their contributions. If a submission can
+reasonably be considered independently copyrightable, it's yours and we
+encourage you to claim it with appropriate copyright notices. This submission
+then falls under the "otherwise noted" category. All submissions are strongly
+encouraged to use the two-clause BSD license reproduced above.
diff --git a/README b/README
index a2239f92af50c10dac9e0f8268047a83b92c36fa..fd6827770236745503c48dde330b064674dc7786 100644 (file)
--- a/README
+++ b/README
-             _____       _            ____  _     _ _       _ 
-            |   __|___  |_|___ _ _   |    \|_|___|_| |_ ___| |
-            |   __|   | | | . | | |  |  |  | | . | |  _| .'| |
-            |_____|_|_|_| |___|_  |  |____/|_|_  |_|_| |__,|_|
-                      |___|   |___|          |___|
-       Copyright 2012-2014 / Florent Kermarrec / florent@enjoy-digital.fr
-                                 Miscope
---------------------------------------------------------------------------------
-
-[> Miscope
-------------
-
-Miscope is a small logic analyzer to embed in an FPGA.
-
-While free vendor toolchains are generally used by beginners or for prototyping 
-(situations where having a logic analyzer in the design is generally helpful) 
-free toolchains are always provided without the proprietary logic analyzer 
-solution... :(
-
-Baseid on Migen, Miscope aims to provide a free, portable and flexible 
+             __   _ __      ____
+            / /  (_) /____ / __/______  ___  ___
+           / /__/ / __/ -_)\ \/ __/ _ \/ _ \/ -_)
+          /____/_/\__/\__/___/\__/\___/ .__/\__/
+                                     /_/
+           Copyright 2012-2015 / EnjoyDigital
+                florent@enjoy-digital.fr
+
+       A small footprint and configurable embedded FPGA
+             logic analyzer core by EnjoyDigital
+
+[> Intro
+---------
+LiteScope small footprint and configurable embedded logic analyzer that you
+can use in your FPGA and aims to provide a a free, portable and flexible
 alternatve to vendor's solutions!
 
-[> Specification:
+LiteScope is part of LiteX libraries whose aims is to lower entry level of complex
+FPGA IP cores by providing simple, elegant and efficient implementations of
+components used in today's SoC such as Ethernet, SATA, PCIe, SDRAM Controller...
+
+The core uses simple and specific streaming buses and will provides in the future
+adapters to use standardized AXI or Avalon-ST streaming buses.
+
+Since Python is used to describe the HDL, the core is highly and easily
+configurable.
+
+LiteScope uses technologies developed in partnership with M-Labs Ltd:
+ - Migen enables generating HDL with Python in an efficient way.
+ - MiSoC provides the basic blocks to build a powerful and small footprint SoC.
+
+LiteScope can be used as a Migen/MiSoC library (by simply installing  it
+with the provided setup.py) or can be integrated with your standard design flow
+by generating the verilog rtl that you will use as a standard core.
+
+LiteScope produces "vcd" files that can be read in your regular waveforms viewer.
+
+Since LiteScope also provides an UART <--> Wishbone brige you only need 2 external
+Rx/Tx pins to be ready to debug or control all your Wishbone peripherals!
+
+[> Features
+-----------
+- IO peek and poke with LiteScopeIO.
+- Logic analyser with LiteScopeLA:
+  - Various triggering modules: Term, Range, Edge (add yours! :)
+  - Run Length Encoder to "compress" data and increase recording depth
+  - Data storage in block rams
+
+
+[> Possibles improvements
+-------------------------
+- add standardized interfaces (AXI, Avalon-ST)
+- add storage in DRAM
+- add storage in HDD with LiteSATA core (https://github.com/enjoy-digital/litesata)
+- add Ethernet Wishbone bridge
+- add PCIe Wishbone bridge with LitePCIe (to be released soon!)
+- ... See below Support and Consulting :)
+
+If you want to support these features, please contact us at florent [AT]
+enjoy-digital.fr. You can also contact our partner on the public mailing list
+devel [AT] lists.m-labs.hk.
+
+
+[> Getting started
+------------------
+1. Install Python3 and Xilinx's Vivado software
+
+2. Obtain Migen and install it:
+  git clone https://github.com/m-labs/migen
+  cd migen
+  python3 setup.py install
+  cd ..
+
+3. Obtain Miscope and install it:
+  git clone https://github.com/m-labs/miscope
+  cd miscope
+  python3 setup.py install
+  cd ..
+
+4. Obtain MiSoC:
+  git clone https://github.com/m-labs/misoc --recursive
+  XXX add setup.py to MiSoC for external use of misoclib?
+
+5. Obtain LiteScope
+  git clone https://github.com/enjoy-digital/litescope
+
+6. Build and load test design (only for KC705 for now):
+  python3 make.py -s [platform] all
+  Supported platform are the supported platform of Mibuild:
+  de0nano, m1, mixxeo, kc705, zedboard...
+
+7. Test design:
+  go to ./test directory and run:
+  python3 test_io.py
+  python3 test_la.py
+
+[> Simulations:
+       XXX convert simulations
+
+[> Tests :
+       XXX convert tests
 
-Miscope provides Migen cores to embed in the design and Python drivers to control
-the logic analyzer from the Host. Miscope automatically interconnects all cores 
-to a 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!
+[> License
+-----------
+LiteScope is released under the very permissive two-clause BSD license. Under the
+terms of this license, you are authorized to use LiteScope for closed-source
+proprietary designs.
+Even though we do not require you to do so, those things are awesome, so please
+do them if possible:
+ - tell us that you are using LiteScope
+ - cite LiteScope in publications related to research it has helped
+ - send us feedback and suggestions for improvements
+ - send us bug reports when something goes wrong
+ - send us the modifications and improvements you have done to LiteScope.
 
-Miscope produces .vcd output files to be analyzed in your favorite waveform viewer.
+[> Support and Consulting
+--------------------------
+We love open-source hardware and like sharing our designs with others.
 
-Since Miscope also provides an Uart2Wishbone bridge, you only need 2 external Rx/Tx
-pins to be ready to debug!
+LiteScope is developed and maintained by EnjoyDigital.
 
-[> Status:
-MiIo & Mila working on board with standard term.
-RLE working on board.
-RangeDetector and EdgeDector terms not tested.
+If you would like to know more about LiteScope or if you are already a happy user
+and would like to extend it for your needs, EnjoyDigital can provide standard
+commercial support as well as consulting services.
 
-[> Examples:
-Have a look at http://github.com/Florent-Kermarrec/misoc-de0nano
-test_miio.py : Led & Switch Test controlled by Python Host.
-test_mila.py : Logic Analyzer controlled by Python Host.
+So feel free to contact us, we'd love to work with you! (and eventually shorten
+the list of the possible improvements :)
 
 [> Contact
-E-mail: florent@enjoy-digital.fr
+E-mail: florent [AT] enjoy-digital.fr
\ No newline at end of file
diff --git a/litesata-version.txt b/litesata-version.txt
new file mode 100644 (file)
index 0000000..eba3340
--- /dev/null
@@ -0,0 +1,2 @@
+0.9.0
+
diff --git a/litescope/__init__.py b/litescope/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/litescope/bridge/uart2wb.py b/litescope/bridge/uart2wb.py
new file mode 100644 (file)
index 0000000..697843b
--- /dev/null
@@ -0,0 +1,197 @@
+from migen.fhdl.std import *
+from migen.genlib.record import *
+from migen.genlib.fsm import FSM, NextState
+from migen.genlib.misc import chooser
+from migen.bank.description import *
+from migen.bus import wishbone
+
+from misoclib.uart import UARTRX, UARTTX
+
+from litescope.common import *
+
+class UART(Module, AutoCSR):
+       def __init__(self, pads, clk_freq, baud=115200):
+               self._tuning_word = CSRStorage(32, reset=int((baud/clk_freq)*2**32))
+               tuning_word = self._tuning_word.storage
+
+               ###
+
+               self.rx = UARTRX(pads, tuning_word)
+               self.tx = UARTTX(pads, tuning_word)
+               self.submodules += self.rx, self.tx
+
+class UARTPads:
+       def __init__(self):
+               self.rx = Signal()
+               self.tx = Signal()
+
+class UARTMux(Module):
+       def __init__(self, pads):
+               self.sel = Signal(max=2)
+               self.shared_pads = UARTPads()
+               self.bridge_pads = UARTPads()
+
+       ###
+               # Route rx pad:
+               # when sel==0, route it to shared rx and bridge rx
+               # when sel==1, route it only to bridge rx
+               self.comb += \
+                       If(self.sel==0,
+                               self.shared_pads.rx.eq(pads.rx),
+                               self.bridge_pads.rx.eq(pads.rx)
+                       ).Else(
+                               self.bridge_pads.rx.eq(pads.rx)
+                       )
+
+               # Route tx:
+               # when sel==0, route shared tx to pads tx
+               # when sel==1, route bridge tx to pads tx
+               self.comb += \
+                       If(self.sel==0,
+                               pads.tx.eq(self.shared_pads.tx)
+                       ).Else(
+                               pads.tx.eq(self.bridge_pads.tx)
+                       )
+
+class LiteScopeUART2WB(Module, AutoCSR):
+       cmds = {
+               "write" : 0x01,
+               "read"  : 0x02
+       }
+       def __init__(self, pads, clk_freq, baud=115200, share_uart=False):
+               self.wishbone = wishbone.Interface()
+               if share_uart:
+                       self._sel = CSRStorage()
+               ###
+               if share_uart:
+                       uart_mux = UARTMux(pads)
+                       uart = UART(uart_mux.bridge_pads, clk_freq, baud)
+                       self.submodules += uart_mux, uart
+                       self.shared_pads = uart_mux.shared_pads
+                       self.comb += uart_mux.sel.eq(self._sel.storage)
+               else:
+                       uart = UART(pads, clk_freq, baud)
+                       self.submodules += uart
+
+               byte_counter = Counter(bits_sign=3)
+               word_counter = Counter(bits_sign=8)
+               self.submodules += byte_counter, word_counter
+
+               cmd = Signal(8)
+               cmd_ce = Signal()
+
+               length = Signal(8)
+               length_ce = Signal()
+
+               address = Signal(32)
+               address_ce = Signal()
+
+               data = Signal(32)
+               rx_data_ce = Signal()
+               tx_data_ce = Signal()
+
+               self.sync += [
+                       If(cmd_ce, cmd.eq(uart.rx.source.d)),
+                       If(length_ce, length.eq(uart.rx.source.d)),
+                       If(address_ce, address.eq(Cat(uart.rx.source.d, address[0:24]))),
+                       If(rx_data_ce,
+                               data.eq(Cat(uart.rx.source.d, data[0:24]))
+                       ).Elif(tx_data_ce,
+                               data.eq(self.wishbone.dat_r)
+                       )
+               ]
+
+               ###
+               fsm = InsertReset(FSM(reset_state="IDLE"))
+               timeout = Timeout(clk_freq//10)
+               self.submodules += fsm, timeout
+               self.comb += [
+                       timeout.ce.eq(1),
+                       fsm.reset.eq(timeout.reached)
+               ]
+               fsm.act("IDLE",
+                       timeout.reset.eq(1),
+                       If(uart.rx.source.stb,
+                               cmd_ce.eq(1),
+                               If(     (uart.rx.source.d == self.cmds["write"]) |
+                                       (uart.rx.source.d == self.cmds["read"]),
+                                       NextState("RECEIVE_LENGTH")
+                               ),
+                               byte_counter.reset.eq(1),
+                               word_counter.reset.eq(1)
+                       )
+               )
+               fsm.act("RECEIVE_LENGTH",
+                       If(uart.rx.source.stb,
+                               length_ce.eq(1),
+                               NextState("RECEIVE_ADDRESS")
+                       )
+               )
+               fsm.act("RECEIVE_ADDRESS",
+                       If(uart.rx.source.stb,
+                               address_ce.eq(1),
+                               byte_counter.ce.eq(1),
+                               If(byte_counter.value == 3,
+                                       If(cmd == self.cmds["write"],
+                                               NextState("RECEIVE_DATA")
+                                       ).Elif(cmd == self.cmds["read"],
+                                               NextState("READ_DATA")
+                                       ),
+                                       byte_counter.reset.eq(1),
+                               )
+                       )
+               )
+               fsm.act("RECEIVE_DATA",
+                       If(uart.rx.source.stb,
+                               rx_data_ce.eq(1),
+                               byte_counter.ce.eq(1),
+                               If(byte_counter.value == 3,
+                                       NextState("WRITE_DATA"),
+                                       byte_counter.reset.eq(1)
+                               )
+                       )
+               )
+               self.comb += [
+                       self.wishbone.adr.eq(address + word_counter.value),
+                       self.wishbone.dat_w.eq(data),
+                       self.wishbone.sel.eq(2**flen(self.wishbone.sel)-1)
+               ]
+               fsm.act("WRITE_DATA",
+                       self.wishbone.stb.eq(1),
+                       self.wishbone.we.eq(1),
+                       self.wishbone.cyc.eq(1),
+                       If(self.wishbone.ack,
+                               word_counter.ce.eq(1),
+                               If(word_counter.value == (length-1),
+                                       NextState("IDLE")
+                               ).Else(
+                                       NextState("RECEIVE_DATA")
+                               )
+                       )
+               )
+               fsm.act("READ_DATA",
+                       self.wishbone.stb.eq(1),
+                       self.wishbone.we.eq(0),
+                       self.wishbone.cyc.eq(1),
+                       If(self.wishbone.ack,
+                               tx_data_ce.eq(1),
+                               NextState("SEND_DATA")
+                       )
+               )
+               self.comb += \
+                       chooser(data, byte_counter.value, uart.tx.sink.d, n=4, reverse=True)
+               fsm.act("SEND_DATA",
+                       uart.tx.sink.stb.eq(1),
+                       If(uart.tx.sink.ack,
+                               byte_counter.ce.eq(1),
+                               If(byte_counter.value == 3,
+                                       word_counter.ce.eq(1),
+                                       If(word_counter.value == (length-1),
+                                               NextState("IDLE")
+                                       ).Else(
+                                               NextState("READ_DATA"),
+                                               byte_counter.reset.eq(1)
+                                       )
+                               )
+                       )
+               )
diff --git a/litescope/common.py b/litescope/common.py
new file mode 100644 (file)
index 0000000..b6bc372
--- /dev/null
@@ -0,0 +1,36 @@
+from migen.genlib.record import *
+
+def dat_layout(dw):
+       return [
+               ("stb", 1, DIR_M_TO_S),
+               ("dat", dw, DIR_M_TO_S)
+       ]
+
+def hit_layout():
+       return [
+               ("stb", 1, DIR_M_TO_S),
+               ("hit", 1, DIR_M_TO_S)
+       ]
+
+@DecorateModule(InsertReset)
+@DecorateModule(InsertCE)
+class Counter(Module):
+       def __init__(self, signal=None, **kwargs):
+               if signal is None:
+                       self.value = Signal(**kwargs)
+               else:
+                       self.value = signal
+               self.width = flen(self.value)
+               self.sync += self.value.eq(self.value+1)
+
+@DecorateModule(InsertReset)
+@DecorateModule(InsertCE)
+class Timeout(Module):
+       def __init__(self, length):
+               self.reached = Signal()
+               ###
+               value = Signal(max=length)
+               self.sync += value.eq(value+1)
+               self.comb += [
+                       self.reached.eq(value == length)
+               ]
diff --git a/litescope/core/storage.py b/litescope/core/storage.py
new file mode 100644 (file)
index 0000000..cbd14c9
--- /dev/null
@@ -0,0 +1,114 @@
+from migen.fhdl.std import *
+from migen.bank.description import *
+from migen.genlib.fifo import SyncFIFOBuffered as SyncFIFO
+from migen.genlib.fsm import FSM, NextState
+from migen.genlib.record import *
+
+from litescope.common import *
+
+class LiteScopeRunLengthEncoder(Module, AutoCSR):
+       def __init__(self, width, length=1024):
+               self.width = width
+               self.length = length
+
+               self.sink = Record(dat_layout(width))
+               self.source = Record(dat_layout(width))
+
+               self._enable = CSRStorage()
+
+               ###
+
+               enable = self._enable.storage
+
+               sink_d = Record(dat_layout(width))
+               self.sync += If(self.sink.stb, sink_d.eq(self.sink))
+
+               cnt = Signal(max=length)
+               cnt_inc = Signal()
+               cnt_reset = Signal()
+               cnt_max = Signal()
+
+               self.sync += \
+                       If(cnt_reset,
+                               cnt.eq(1),
+                       ).Elif(cnt_inc,
+                               cnt.eq(cnt+1)
+                       )
+               self.comb += cnt_max.eq(cnt == length)
+
+               change = Signal()
+               self.comb += change.eq(self.sink.stb & (self.sink.dat != sink_d.dat))
+
+               fsm = FSM(reset_state="BYPASS")
+               self.submodules += fsm
+
+               fsm.act("BYPASS",
+                       sink_d.connect(self.source),
+                       cnt_reset.eq(1),
+                       If(enable & ~change & self.sink.stb, NextState("COUNT"))
+               )
+
+               fsm.act("COUNT",
+                       cnt_inc.eq(self.sink.stb),
+                       If(change | cnt_max | ~enable,
+                               self.source.stb.eq(1),
+                               self.source.dat[width-1].eq(1), # Set RLE bit
+                               self.source.dat[:flen(cnt)].eq(cnt),
+                               NextState("BYPASS")
+                       )
+               ),
+
+class LiteScopeRecorder(Module, AutoCSR):
+       def __init__(self, width, depth):
+               self.width = width
+
+               self.trig_sink = Record(hit_layout())
+               self.dat_sink = Record(dat_layout(width))
+
+               self._trigger = CSR()
+               self._length = CSRStorage(bits_for(depth))
+               self._offset = CSRStorage(bits_for(depth))
+               self._done = CSRStatus()
+
+               self._read_en = CSR()
+               self._read_empty = CSRStatus()
+               self._read_dat = CSRStatus(width)
+
+               ###
+
+               fifo = InsertReset(SyncFIFO(width, depth))
+               self.submodules += fifo
+
+               fsm = FSM(reset_state="IDLE")
+               self.submodules += fsm
+
+
+               self.comb += [
+                       self._read_empty.status.eq(~fifo.readable),
+                       self._read_dat.status.eq(fifo.dout),
+               ]
+
+               fsm.act("IDLE",
+                       If(self._trigger.re & self._trigger.r,
+                               NextState("PRE_HIT_RECORDING"),
+                               fifo.reset.eq(1),
+                       ),
+                       fifo.re.eq(self._read_en.re & self._read_en.r),
+                       self._done.status.eq(1)
+               )
+
+               fsm.act("PRE_HIT_RECORDING",
+                       fifo.we.eq(self.dat_sink.stb),
+                       fifo.din.eq(self.dat_sink.dat),
+
+                       fifo.re.eq(fifo.level >= self._offset.storage),
+
+                       If(self.trig_sink.stb & self.trig_sink.hit, NextState("POST_HIT_RECORDING"))
+               )
+
+               fsm.act("POST_HIT_RECORDING",
+                       fifo.we.eq(self.dat_sink.stb),
+                       fifo.din.eq(self.dat_sink.dat),
+
+                       If(~fifo.writable | (fifo.level >= self._length.storage), NextState("IDLE"))
+               )
diff --git a/litescope/core/trigger.py b/litescope/core/trigger.py
new file mode 100644 (file)
index 0000000..f9b792b
--- /dev/null
@@ -0,0 +1,140 @@
+from migen.fhdl.std import *
+from migen.fhdl.specials import Memory
+from migen.bank.description import *
+from migen.genlib.record import *
+
+from litescope.common import *
+
+class LiteScopeTerm(Module, AutoCSR):
+       def __init__(self, width):
+               self.width = width
+
+               self.sink = Record(dat_layout(width))
+               self.source = Record(hit_layout())
+
+               self._trig = CSRStorage(width)
+               self._mask = CSRStorage(width)
+
+       ###
+
+               trig = self._trig.storage
+               mask = self._mask.storage
+               dat = self.sink.dat
+               hit = self.source.hit
+
+               self.comb += [
+                       hit.eq((dat & mask) == trig),
+                       self.source.stb.eq(self.sink.stb)
+               ]
+
+class LiteScopeRangeDetector(Module, AutoCSR):
+       def __init__(self, width):
+               self.width = width
+
+               self.sink = Record(dat_layout(width))
+               self.source = Record(hit_layout())
+
+               self._low = CSRStorage(width)
+               self._high = CSRStorage(width)
+
+       ###
+
+               low = self._low.storage
+               high = self._high.storage
+               dat = self.sink.dat
+               hit = self.source.hit
+
+               self.comb += [
+                       hit.eq((dat >= low) & (dat <= high)),
+                       self.source.stb.eq(self.sink.stb)
+               ]
+
+class LiteScopeEdgeDetector(Module, AutoCSR):
+       def __init__(self, width):
+               self.width = width
+
+               self.sink = Record(dat_layout(width))
+               self.source = Record(hit_layout())
+
+               self._rising_mask = CSRStorage(width)
+               self._falling_mask = CSRStorage(width)
+               self._both_mask = CSRStorage(width)
+
+       ###
+
+               rising_mask = self._rising_mask.storage
+               falling_mask = self._falling_mask.storage
+               both_mask = self._both_mask.storage
+
+               dat = self.sink.dat
+               dat_d = Signal(width)
+               rising_hit = Signal()
+               falling_hit = Signal()
+               both_hit = Signal()
+               hit = self.source.hit
+
+               self.sync += dat_d.eq(dat)
+
+               self.comb += [
+                       rising_hit.eq(rising_mask & dat & ~dat_d),
+                       falling_hit.eq(rising_mask & ~dat & dat_d),
+                       both_hit.eq((both_mask & dat) != (both_mask & dat_d)),
+                       hit.eq(rising_hit | falling_hit | both_hit),
+                       self.source.stb.eq(self.sink.stb)
+               ]
+
+class LiteScopeSum(Module, AutoCSR):
+       def __init__(self, ports=4):
+
+               self.sinks = [Record(hit_layout()) for p in range(ports)]
+               self.source = Record(hit_layout())
+
+               self._prog_we = CSRStorage()
+               self._prog_adr = CSRStorage(ports) #FIXME
+               self._prog_dat = CSRStorage()
+
+               mem = Memory(1, 2**ports)
+               lut_port = mem.get_port()
+               prog_port = mem.get_port(write_capable=True)
+
+               self.specials += mem, lut_port, prog_port
+
+               ###
+
+               # Lut prog
+               self.comb += [
+                       prog_port.we.eq(self._prog_we.storage),
+                       prog_port.adr.eq(self._prog_adr.storage),
+                       prog_port.dat_w.eq(self._prog_dat.storage)
+               ]
+
+               # Lut read
+               for i, sink in enumerate(self.sinks):
+                       self.comb += lut_port.adr[i].eq(sink.hit)
+
+               # Drive source
+               self.comb += [
+                       self.source.stb.eq(optree("&", [sink.stb for sink in self.sinks])),
+                       self.source.hit.eq(lut_port.dat_r),
+               ]
+
+
+class LiteScopeTrigger(Module, AutoCSR):
+       def __init__(self, width, ports):
+               self.width = width
+               self.ports = ports
+
+               self.submodules.sum = LiteScopeSum(len(ports))
+               for i, port in enumerate(ports):
+                       setattr(self.submodules, "port"+str(i), port)
+
+               self.sink   = Record(dat_layout(width))
+               self.source = self.sum.source
+
+               ###
+
+               for i, port in enumerate(ports):
+                       self.comb += [
+                               self.sink.connect(port.sink),
+                               port.source.connect(self.sum.sinks[i])
+                       ]
diff --git a/litescope/frontend/io.py b/litescope/frontend/io.py
new file mode 100644 (file)
index 0000000..3fb2d31
--- /dev/null
@@ -0,0 +1,10 @@
+from migen.fhdl.structure import *
+from migen.bank.description import *
+
+class LiteScopeIO(Module, AutoCSR):
+       def __init__(self, width):
+               self._r_i = CSRStatus(width)
+               self._r_o = CSRStorage(width)
+
+               self.i = self._r_i.status
+               self.o = self._r_o.storage
diff --git a/litescope/frontend/la.py b/litescope/frontend/la.py
new file mode 100644 (file)
index 0000000..a69f749
--- /dev/null
@@ -0,0 +1,98 @@
+from migen.fhdl.std import *
+from migen.fhdl import verilog
+from migen.bank.description import *
+from migen.actorlib.fifo import AsyncFIFO
+
+from litescope.common import *
+from litescope.core.trigger import LiteScopeTrigger
+from litescope.core.storage import LiteScopeRecorder, LiteScopeRunLengthEncoder
+
+from mibuild.tools import write_to_file
+
+def _getattr_all(l, attr):
+       it = iter(l)
+       r = getattr(next(it), attr)
+       for e in it:
+               if getattr(e, attr) != r:
+                       raise ValueError
+       return r
+
+class LiteScopeLA(Module, AutoCSR):
+       def __init__(self, depth, dat, with_rle=False, clk_domain="sys", pipe=False):
+               self.depth = depth
+               self.with_rle = with_rle
+               self.clk_domain = clk_domain
+               self.pipe = pipe
+               self.ports = []
+               self.width = flen(dat)
+
+               self.stb = Signal(reset=1)
+               self.dat = dat
+
+       def add_port(self, port_class):
+               port = port_class(self.width)
+               self.ports.append(port)
+
+       def do_finalize(self):
+               stb = self.stb
+               dat = self.dat
+               if self.pipe:
+                       sync = getattr(self.sync, self.clk_domain)
+                       stb_new = Signal()
+                       dat_new = Signal(flen(dat))
+                       sync += [
+                               stb_new.eq(stb),
+                               dat_new.eq(dat)
+                       ]
+                       stb = stb_new
+                       dat = dat_new
+
+               if self.clk_domain is not "sys":
+                       fifo = AsyncFIFO([("dat", self.width)], 32)
+                       self.submodules += RenameClockDomains(fifo, {"write": self.clk_domain, "read": "sys"})
+                       self.comb += [
+                               fifo.sink.stb.eq(stb),
+                               fifo.sink.dat.eq(dat)
+                       ]
+                       sink = Record(dat_layout(self.width))
+                       self.comb += [
+                               sink.stb.eq(fifo.source.stb),
+                               sink.dat.eq(fifo.source.dat),
+                               fifo.source.ack.eq(1)
+                       ]
+               else:
+                       sink = Record(dat_layout(self.width))
+                       self.comb += [
+                               sink.stb.eq(stb),
+                               sink.dat.eq(dat)
+                       ]
+
+               self.submodules.trigger = trigger = LiteScopeTrigger(self.width, self.ports)
+               self.submodules.recorder = recorder = LiteScopeRecorder(self.width, self.depth)
+               self.comb += [
+                       sink.connect(trigger.sink),
+                       trigger.source.connect(recorder.trig_sink)
+               ]
+
+               if self.with_rle:
+                       self.submodules.rle = rle = LiteScopeRunLengthEncoder(self.width)
+                       self.comb += [
+                               sink.connect(rle.sink),
+                               rle.source.connect(recorder.dat_sink)
+                       ]
+               else:
+                       self.comb += sink.connect(recorder.dat_sink)
+
+       def export(self, design, layout, filename):
+               ret, ns = verilog.convert(design, return_ns=True)
+               r = ""
+               def format_line(*args):
+                       return ",".join(args) + "\n"
+
+               r += format_line("config", "width", str(self.width))
+               r += format_line("config", "depth", str(self.depth))
+               r += format_line("config", "with_rle", str(int(self.with_rle)))
+
+               for e in layout:
+                       r += format_line("layout", ns.get_name(e), str(flen(e)))
+               write_to_file(filename, r)
diff --git a/litescope/host/__init__.py b/litescope/host/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/litescope/host/cpuif.py b/litescope/host/cpuif.py
new file mode 100644 (file)
index 0000000..6a0ed40
--- /dev/null
@@ -0,0 +1,11 @@
+from migen.bank.description import CSRStatus
+
+def get_csr_csv(csr_base, bank_array):
+       r = ""
+       for name, csrs, mapaddr, rmap in bank_array.banks:
+               reg_base = csr_base + 0x800*mapaddr
+               for csr in csrs:
+                       nr = (csr.size + 7)//8
+                       r += "{}_{},0x{:08x},{},{}\n".format(name, csr.name, reg_base, nr, "ro" if isinstance(csr, CSRStatus) else "rw")
+                       reg_base += 4*nr
+       return r
diff --git a/litescope/host/driver.py b/litescope/host/driver.py
new file mode 100644 (file)
index 0000000..3164519
--- /dev/null
@@ -0,0 +1,230 @@
+import csv
+import time
+import sys
+import string
+import serial
+from struct import *
+from migen.fhdl.structure import *
+from litescope.host.reg import *
+from litescope.host.dump import *
+from litescope.host.truthtable import *
+
+def write_b(uart, data):
+       uart.write(pack('B',data))
+
+class LiteScopeUART2WBDriver:
+       WRITE_CMD  = 0x01
+       READ_CMD   = 0x02
+       def __init__(self, port, baudrate=115200, addrmap=None, busword=8, debug=False):
+               self.port = port
+               self.baudrate = str(baudrate)
+               self.debug = debug
+               self.uart = serial.Serial(port, baudrate, timeout=0.25)
+               self.regs = build_map(addrmap, busword, self.read, self.write)
+
+       def open(self):
+               self.uart.flushOutput()
+               self.uart.close()
+               self.uart.open()
+               self.uart.flushInput()
+               try:
+                       self.regs.uart2wb_sel.write(1)
+               except:
+                       pass
+
+       def close(self):
+               try:
+                       self.regs.uart2wb_sel.write(0)
+               except:
+                       pass
+               self.uart.flushOutput()
+               self.uart.close()
+
+       def read(self, addr, burst_length=1):
+               self.uart.flushInput()
+               write_b(self.uart, self.READ_CMD)
+               write_b(self.uart, burst_length)
+               addr = addr//4
+               write_b(self.uart, (addr & 0xff000000) >> 24)
+               write_b(self.uart, (addr & 0x00ff0000) >> 16)
+               write_b(self.uart, (addr & 0x0000ff00) >> 8)
+               write_b(self.uart, (addr & 0x000000ff))
+               values = []
+               for i in range(burst_length):
+                       val = 0
+                       for j in range(4):
+                               val = val << 8
+                               val |= ord(self.uart.read())
+                       if self.debug:
+                               print("RD %08X @ %08X" %(val, (addr+i)*4))
+                       values.append(val)
+               if burst_length == 1:
+                       return values[0]
+               else:
+                       return values
+
+       def write(self, addr, data):
+               if isinstance(data, list):
+                       burst_length = len(data)
+               else:
+                       burst_length = 1
+               write_b(self.uart, self.WRITE_CMD)
+               write_b(self.uart, burst_length)
+               addr = addr//4
+               write_b(self.uart, (addr & 0xff000000) >> 24)
+               write_b(self.uart, (addr & 0x00ff0000) >> 16)
+               write_b(self.uart, (addr & 0x0000ff00) >> 8)
+               write_b(self.uart, (addr & 0x000000ff))
+               if isinstance(data, list):
+                       for i in range(len(data)):
+                               dat = data[i]
+                               for j in range(4):
+                                       write_b(self.uart, (dat & 0xff000000) >> 24)
+                                       dat = dat << 8
+                               if self.debug:
+                                       print("WR %08X @ %08X" %(data[i], (addr + i)*4))
+               else:
+                       dat = data
+                       for j in range(4):
+                               write_b(self.uart, (dat & 0xff000000) >> 24)
+                               dat = dat << 8
+                       if self.debug:
+                               print("WR %08X @ %08X" %(data, (addr * 4)))
+
+class LiteScopeIODriver():
+       def __init__(self, regs, name):
+               self.regs = regs
+               self.name = name
+               self.build()
+
+       def build(self):
+               for key, value in self.regs.d.items():
+                       if self.name in key:
+                               key.replace(self.name +"_")
+                               setattr(self, key, value)
+
+       def write(self, value):
+               self.o.write(value)
+
+       def read(self):
+               return self.i.read()
+
+class LiteScopeLADriver():
+       def __init__(self, regs, name, config_csv=None, use_rle=False):
+               self.regs = regs
+               self.name = name
+               self.use_rle = use_rle
+               if config_csv is None:
+                       self.config_csv = name + ".csv"
+               self.get_config()
+               self.get_layout()
+               self.build()
+               self.dat = Dat(self.width)
+
+       def get_config(self):
+               csv_reader = csv.reader(open(self.config_csv), delimiter=',', quotechar='#')
+               for item in csv_reader:
+                       t, n, v = item
+                       if t == "config":
+                               setattr(self, n, int(v))
+
+       def get_layout(self):
+               self.layout = []
+               csv_reader = csv.reader(open(self.config_csv), delimiter=',', quotechar='#')
+               for item in csv_reader:
+                       t, n, v = item
+                       if t == "layout":
+                               self.layout.append((n, int(v)))
+
+       def build(self):
+               for key, value in self.regs.d.items():
+                       if self.name == key[:len(self.name)]:
+                               key.replace(self.name + "_")
+                               setattr(self, key, value)
+               value = 1
+               for name, length in self.layout:
+                       setattr(self, name + "_o", value)
+                       value = value*(2**length)
+               value = 0
+               for name, length in self.layout:
+                       setattr(self, name + "_m", (2**length-1) << value)
+                       value += length
+
+       def show_state(self, s):
+               print(s, end="|")
+               sys.stdout.flush()
+
+       def prog_term(self, port, trigger=0, mask=0, cond=None):
+               if cond is not None:
+                       for k, v in cond.items():
+                               trigger |= getattr(self, k + "_o")*v
+                               mask |= getattr(self, k + "_m")
+               t = getattr(self, "trigger_port{d}_trig".format(d=int(port)))
+               m = getattr(self, "trigger_port{d}_mask".format(d=int(port)))
+               t.write(trigger)
+               m.write(mask)
+
+       def prog_range_detector(self, port, low, high):
+               l = getattr(self, "trigger_port{d}_low".format(d=int(port)))
+               h = getattr(self, "trigger_port{d}_high".format(d=int(port)))
+               l.write(low)
+               h.write(high)
+
+       def prog_edge_detector(self, port, rising_mask, falling_mask, both_mask):
+               rm = getattr(self, "trigger_port{d}_rising_mask".format(d=int(port)))
+               fm = getattr(self, "trigger_port{d}_falling_mask".format(d=int(port)))
+               bm = getattr(self, "trigger_port{d}_both_mask".format(d=int(port)))
+               rm.write(rising_mask)
+               fm.write(falling_mask)
+               bm.write(both_mask)
+
+       def prog_sum(self, equation):
+               datas = gen_truth_table(equation)
+               for adr, dat in enumerate(datas):
+                       self.trigger_sum_prog_adr.write(adr)
+                       self.trigger_sum_prog_dat.write(dat)
+                       self.trigger_sum_prog_we.write(1)
+
+       def config_rle(self, v):
+               self.rle_enable.write(v)
+
+       def is_done(self):
+               return self.recorder_done.read()
+
+       def wait_done(self):
+               self.show_state("WAIT HIT")
+               while(not self.is_done()):
+                       time.sleep(0.1)
+
+       def trigger(self, offset, length):
+               self.show_state("TRIG")
+               if self.with_rle:
+                       self.config_rle(self.use_rle)
+               self.recorder_offset.write(offset)
+               self.recorder_length.write(length)
+               self.recorder_trigger.write(1)
+
+       def read(self):
+               self.show_state("READ")
+               empty = self.recorder_read_empty.read()
+               while(not empty):
+                       self.dat.append(self.recorder_read_dat.read())
+                       empty = self.recorder_read_empty.read()
+                       self.recorder_read_en.write(1)
+               if self.with_rle:
+                       if self.use_rle:
+                               self.dat = self.dat.decode_rle()
+               return self.dat
+
+       def export(self, export_fn=None):
+               self.show_state("EXPORT")
+               dump = Dump()
+               dump.add_from_layout(self.layout, self.dat)
+               if ".vcd" in export_fn:
+                       VCDExport(dump).write(export_fn)
+               elif ".csv" in export_fn:
+                       CSVExport(dump).write(export_fn)
+               elif ".py" in export_fn:
+                       PYExport(dump).write(export_fn)
+               else:
+                       raise NotImplementedError
diff --git a/litescope/host/dump.py b/litescope/host/dump.py
new file mode 100644 (file)
index 0000000..77a6e30
--- /dev/null
@@ -0,0 +1,311 @@
+import sys
+import datetime
+
+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)
+
+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 Dat(list):
+       def __init__(self, width):
+               self.width = width
+
+       def __getitem__(self, key):
+               if isinstance(key, int):
+                       return get_bits(self, self.width, key)
+               elif isinstance(key, slice):
+                       if key.start != None:
+                               start = key.start
+                       else:
+                               start = 0
+                       if key.stop != None:
+                               stop = key.stop
+                       else:
+                               stop = self.width
+                       if stop > self.width:
+                               stop = self.width
+                       if key.step != None:
+                               raise KeyError
+                       return get_bits(self, self.width, start, stop)
+               else:
+                       raise KeyError
+
+       def decode_rle(self):
+               rle_bit = self[-1]
+               rle_dat = self[:self.width-1]
+
+               dat = Dat(self.width)
+               i=0
+               last = 0
+               for d in self:
+                       if rle_bit[i]:
+                               if len(dat) >= 1:
+                                       # FIX ME... why is rle_dat in reverse order...
+                                       for j in range(int(dec2bin(rle_dat[i])[::-1],2)):
+                                               dat.append(last)
+                       else:
+                               dat.append(d)
+                               last = d
+                       i +=1
+               return dat
+
+class Var:
+       def __init__(self, name, width, values=[], type="wire", 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 Dump:
+       def __init__(self):
+               self.vars = []
+               self.vcd_id = "!"
+               
+       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 add_from_layout(self, layout, var):
+               i=0
+               for s, n in layout:
+                       self.add(Var(s, n, var[i:i+n]))
+                       i += n
+       
+       def __len__(self):
+               l = 0
+               for var in self.vars:
+                       l = max(len(var),l)
+               return l
+
+class VCDExport():
+       def __init__(self, dump, timescale="1ps", comment=""):
+               self.dump = dump
+               self.timescale = timescale
+               self.comment = comment
+               self.cnt = -1
+
+       def change(self):
+               r = ""
+               c = ""
+               for var in self.dump.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.dump.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.dump.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.dump)):
+                       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()
+
+class CSVExport():
+       def __init__(self, dump):
+               self.dump = dump
+
+       def  p_vars(self):
+               r = ""
+               for var in self.dump.vars:
+                       r += var.name
+                       r += ","
+               r += "\n"
+               for var in self.dump.vars:
+                       r += str(var.width)
+                       r += ","
+               r += "\n"
+               return r
+
+       def p_dumpvars(self):
+               r  = ""
+               for i in range(len(self.dump)):
+                       for var in self.dump.vars:
+                               try:
+                                       var.val = var.values[i]
+                               except:
+                                       pass
+                               if var.val == "x":
+                                       r += "x"
+                               else:
+                                       r += dec2bin(var.val, var.width)
+                               r += ", "
+                       r+= "\n"
+               return r
+
+       def __repr__(self):
+               r = ""
+               r += self.p_vars()
+               r += self.p_dumpvars()
+               return r
+
+       def write(self, filename):
+               f = open(filename, "w")
+               f.write(str(self))
+               f.close()
+
+class PYExport():
+       def __init__(self, dump):
+               self.dump = dump
+
+       def __repr__(self):
+               r = "dump = {\n"
+               for var in self.dump.vars:
+                       r += "\"" + var.name + "\""
+                       r += " : "
+                       r += str(var.values)
+                       r += ",\n"
+               r += "}"
+               return r
+
+       def write(self, filename):
+               f = open(filename, "w")
+               f.write(str(self))
+               f.close()
+
+def main():
+       dump = Dump()
+       dump.add(Var("foo1", 1, [0,1,0,1,0,1]))
+       dump.add(Var("foo2", 2, [1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0]))
+       ramp = [i%128 for i in range(1024)]
+       dump.add(Var("ramp", 16, ramp))
+       
+       VCDExport(dump).write("mydump.vcd")
+       CSVExport(dump).write("mydump.csv")
+       PYExport(dump).write("mydump.py")
+
+if __name__ == '__main__':
+  main()
+
diff --git a/litescope/host/reg.py b/litescope/host/reg.py
new file mode 100644 (file)
index 0000000..16a98d9
--- /dev/null
@@ -0,0 +1,48 @@
+import csv
+
+class MappedReg:
+       def __init__(self, readfn, writefn, name, addr, length, busword, mode):
+               self.readfn = readfn
+               self.writefn = writefn
+               self.addr = addr
+               self.length = length
+               self.busword = busword
+               self.mode = mode
+
+       def read(self):
+               if self.mode not in ["rw", "ro"]:
+                       raise KeyError(name + "register not readable")
+               r = 0
+               for i in range(self.length):
+                       r |= self.readfn(self.addr + 4*i)
+                       if i != (self.length-1):
+                               r <<= self.busword
+               return r
+
+       def write(self, value):
+               if self.mode not in ["rw", "wo"]:
+                       raise KeyError(name + "register not writable")
+               for i in range(self.length):
+                       dat = (value >> ((self.length-1-i)*self.busword)) & (2**self.busword-1)
+                       self.writefn(self.addr + 4*i, dat)
+
+class MappedRegs:
+       def __init__(self, d):
+               self.d = d
+
+       def __getattr__(self, attr):
+               try:
+                       return self.__dict__['d'][attr]
+               except KeyError:
+                       pass
+               raise KeyError("No such register " + attr)
+
+def    build_map(addrmap, busword, readfn, writefn):
+       csv_reader = csv.reader(open(addrmap), delimiter=',', quotechar='#')
+       d = {}
+       for item in csv_reader:
+               name, addr, length, mode = item
+               addr = int(addr.replace("0x", ""), 16)
+               length = int(length)
+               d[name] = MappedReg(readfn, writefn, name, addr, length, busword, mode)
+       return MappedRegs(d)
\ No newline at end of file
diff --git a/litescope/host/truthtable.py b/litescope/host/truthtable.py
new file mode 100644 (file)
index 0000000..319eaee
--- /dev/null
@@ -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/make.py b/make.py
new file mode 100644 (file)
index 0000000..987f450
--- /dev/null
+++ b/make.py
@@ -0,0 +1,124 @@
+#!/usr/bin/env python3
+
+import sys, os, argparse, subprocess, struct, importlib
+
+from mibuild.tools import write_to_file
+from migen.util.misc import autotype
+from migen.fhdl import verilog, edif
+from migen.fhdl.structure import _Fragment
+from mibuild import tools
+from mibuild.xilinx_common import *
+
+from misoclib.gensoc import cpuif
+
+from litesata.common import *
+
+def _import(default, name):
+       return importlib.import_module(default + "." + name)
+
+def _get_args():
+       parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
+               description="""\
+LiteScope - based on Migen.
+
+This program builds and/or loads LiteSATA components.
+One or several actions can be specified:
+
+clean           delete previous build(s).
+build-rtl       build verilog rtl.
+build-bitstream build-bitstream build FPGA bitstream.
+build-csr-csv   save CSR map into CSV file.
+
+load-bitstream  load bitstream into volatile storage.
+
+all             clean, build-csr-csv, build-bitstream, load-bitstream.
+""")
+
+       parser.add_argument("-t", "--target", default="simple", help="Core type to build")
+       parser.add_argument("-s", "--sub-target", default="", help="variant of the Core type to build")
+       parser.add_argument("-p", "--platform", default=None, help="platform to build for")
+       parser.add_argument("-Ot", "--target-option", default=[], nargs=2, action="append", help="set target-specific option")
+       parser.add_argument("-Op", "--platform-option", default=[], nargs=2, action="append", help="set platform-specific option")
+       parser.add_argument("--csr_csv", default="./test/csr.csv", help="CSV file to save the CSR map into")
+
+       parser.add_argument("action", nargs="+", help="specify an action")
+
+       return parser.parse_args()
+
+# Note: misoclib need to be installed as a python library
+
+if __name__ == "__main__":
+       args = _get_args()
+
+       # create top-level Core object
+       target_module = _import("targets", args.target)
+       if args.sub_target:
+               top_class = getattr(target_module, args.sub_target)
+       else:
+               top_class = target_module.default_subtarget
+
+       if args.platform is None:
+               platform_name = top_class.default_platform
+       else:
+               platform_name = args.platform
+       platform_module = _import("mibuild.platforms", platform_name)
+       platform_kwargs = dict((k, autotype(v)) for k, v in args.platform_option)
+       platform = platform_module.Platform(**platform_kwargs)
+
+       build_name = top_class.__name__.lower() +  "-" + platform_name
+       top_kwargs = dict((k, autotype(v)) for k, v in args.target_option)
+       soc = top_class(platform, **top_kwargs)
+       soc.finalize()
+
+       # decode actions
+       action_list = ["clean", "build-csr-csv", "build-bitstream", "load-bitstream", "all"]
+       actions = {k: False for k in action_list}
+       for action in args.action:
+               if action in actions:
+                       actions[action] = True
+               else:
+                       print("Unknown action: "+action+". Valid actions are:")
+                       for a in action_list:
+                               print("  "+a)
+                       sys.exit(1)
+
+       print("""
+      __   _ __      ____
+     / /  (_) /____ / __/______  ___  ___
+    / /__/ / __/ -_)\ \/ __/ _ \/ _ \/ -_)
+   /____/_/\__/\__/___/\__/\___/ .__/\__/
+                              /_/
+
+   A small footprint and configurable embedded FPGA
+            based in Migen/MiSoC
+
+====== Building options: ======
+===============================""".format()
+)
+
+       # dependencies
+       if actions["all"]:
+               actions["clean"] = True
+               actions["build-csr-csv"] = True
+               actions["build-bitstream"] = True
+               actions["load-bitstream"] = True
+
+       if actions["build-bitstream"]:
+               actions["clean"] = True
+               actions["build-csr-csv"] = True
+               actions["build-bitstream"] = True
+               actions["load-bitstream"] = True
+
+       if actions["clean"]:
+               subprocess.call(["rm", "-rf", "build/*"])
+
+       if actions["build-csr-csv"]:
+               csr_csv = cpuif.get_csr_csv(soc.cpu_csr_regions)
+               write_to_file(args.csr_csv, csr_csv)
+
+       if actions["build-bitstream"]:
+               platform.build(soc, build_name=build_name)
+
+       if actions["load-bitstream"]:
+               prog = platform.create_programmer()
+               prog.load_bitstream("build/" + build_name + platform.bitstream_ext)
diff --git a/miscope/__init__.py b/miscope/__init__.py
deleted file mode 100644 (file)
index 03249cd..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-try:
-       from miscope.miio import MiIo
-       from miscope.mila import MiLa
-       from miscope.trigger import Term, RangeDetector, EdgeDetector
-       from miscope.uart2wishbone import UART2Wishbone
-except:
-       pass
\ No newline at end of file
diff --git a/miscope/host/__init__.py b/miscope/host/__init__.py
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/miscope/host/cpuif.py b/miscope/host/cpuif.py
deleted file mode 100644 (file)
index 6a0ed40..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-from migen.bank.description import CSRStatus
-
-def get_csr_csv(csr_base, bank_array):
-       r = ""
-       for name, csrs, mapaddr, rmap in bank_array.banks:
-               reg_base = csr_base + 0x800*mapaddr
-               for csr in csrs:
-                       nr = (csr.size + 7)//8
-                       r += "{}_{},0x{:08x},{},{}\n".format(name, csr.name, reg_base, nr, "ro" if isinstance(csr, CSRStatus) else "rw")
-                       reg_base += 4*nr
-       return r
diff --git a/miscope/host/drivers.py b/miscope/host/drivers.py
deleted file mode 100644 (file)
index 4408464..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-import csv
-import time
-import sys
-from miscope.host.dump import *
-from miscope.host.truthtable import *
-
-class MiIoDriver():
-       def __init__(self, regs, name):
-               self.regs = regs
-               self.name = name
-               self.build_miio()
-
-       def build_miio(self):
-               for key, value in self.regs.d.items():
-                       if self.name in key:
-                               key.replace(self.name, "miio")
-                               setattr(self, key, value)
-
-       def write(self, value):
-               self.miio_o.write(value)
-
-       def read(self):
-               return self.miio_i.read()
-
-class MiLaDriver():
-       def __init__(self, regs, name, config_csv=None, use_rle=False):
-               self.regs = regs
-               self.name = name
-               self.use_rle = use_rle
-               if config_csv is None:
-                       self.config_csv = name + ".csv"
-               self.get_config()
-               self.get_layout()
-               self.build_mila()
-               self.dat = Dat(self.width)
-
-       def get_config(self):
-               csv_reader = csv.reader(open(self.config_csv), delimiter=',', quotechar='#')
-               for item in csv_reader:
-                       t, n, v = item
-                       if t == "config":
-                               setattr(self, n, int(v))
-
-       def get_layout(self):
-               self.layout = []
-               csv_reader = csv.reader(open(self.config_csv), delimiter=',', quotechar='#')
-               for item in csv_reader:
-                       t, n, v = item
-                       if t == "layout":
-                               self.layout.append((n, int(v)))
-
-       def build_mila(self):
-               for key, value in self.regs.d.items():
-                       if self.name == key[:len(self.name)]:
-                               key.replace(self.name, "mila")
-                               setattr(self, key, value)
-               value = 1
-               for name, length in self.layout:
-                       setattr(self, name+"_o", value)
-                       value = value*(2**length)
-               value = 0
-               for name, length in self.layout:
-                       setattr(self, name+"_m", (2**length-1) << value)
-                       value += length
-
-       def show_state(self, s):
-               print(s, end="|")
-               sys.stdout.flush()
-
-       def prog_term(self, port, trigger=0, mask=0, cond=None):
-               if cond is not None:
-                       for k, v in cond.items():
-                               trigger |= getattr(self, k+"_o")*v
-                               mask |= getattr(self, k+"_m")
-               t = getattr(self, "mila_trigger_port{d}_trig".format(d=int(port)))
-               m = getattr(self, "mila_trigger_port{d}_mask".format(d=int(port)))
-               t.write(trigger)
-               m.write(mask)
-
-       def prog_range_detector(self, port, low, high):
-               l = getattr(self, "mila_trigger_port{d}_low".format(d=int(port)))
-               h = getattr(self, "mila_trigger_port{d}_high".format(d=int(port)))
-               l.write(low)
-               h.write(high)
-
-       def prog_edge_detector(self, port, rising_mask, falling_mask, both_mask):
-               rm = getattr(self, "mila_trigger_port{d}_rising_mask".format(d=int(port)))
-               fm = getattr(self, "mila_trigger_port{d}_falling_mask".format(d=int(port)))
-               bm = getattr(self, "mila_trigger_port{d}_both_mask".format(d=int(port)))
-               rm.write(rising_mask)
-               fm.write(falling_mask)
-               bm.write(both_mask)
-
-       def prog_sum(self, equation):
-               datas = gen_truth_table(equation)
-               for adr, dat in enumerate(datas):
-                       self.mila_trigger_sum_prog_adr.write(adr)
-                       self.mila_trigger_sum_prog_dat.write(dat)
-                       self.mila_trigger_sum_prog_we.write(1)
-
-       def config_rle(self, v):
-               self.mila_rle_enable.write(v)
-
-       def is_done(self):
-               return self.mila_recorder_done.read()
-
-       def wait_done(self):
-               self.show_state("WAIT HIT")
-               while(not self.is_done()):
-                       time.sleep(0.1)
-
-       def trigger(self, offset, length):
-               self.show_state("TRIG")
-               if self.with_rle:
-                       self.config_rle(self.use_rle)
-               self.mila_recorder_offset.write(offset)
-               self.mila_recorder_length.write(length)
-               self.mila_recorder_trigger.write(1)
-
-       def read(self):
-               self.show_state("READ")
-               empty = self.mila_recorder_read_empty.read()
-               while(not empty):
-                       self.dat.append(self.mila_recorder_read_dat.read())
-                       empty = self.mila_recorder_read_empty.read()
-                       self.mila_recorder_read_en.write(1)
-               if self.with_rle:
-                       if self.use_rle:
-                               self.dat = self.dat.decode_rle()
-               return self.dat
-
-       def export(self, export_fn=None):
-               self.show_state("EXPORT")
-               dump = Dump()
-               dump.add_from_layout(self.layout, self.dat)
-               if ".vcd" in export_fn:
-                       VCDExport(dump).write(export_fn)
-               elif ".csv" in export_fn:
-                       CSVExport(dump).write(export_fn)
-               elif ".py" in export_fn:
-                       PYExport(dump).write(export_fn)
-               else:
-                       raise NotImplementedError
diff --git a/miscope/host/dump.py b/miscope/host/dump.py
deleted file mode 100644 (file)
index 77a6e30..0000000
+++ /dev/null
@@ -1,311 +0,0 @@
-import sys
-import datetime
-
-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)
-
-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 Dat(list):
-       def __init__(self, width):
-               self.width = width
-
-       def __getitem__(self, key):
-               if isinstance(key, int):
-                       return get_bits(self, self.width, key)
-               elif isinstance(key, slice):
-                       if key.start != None:
-                               start = key.start
-                       else:
-                               start = 0
-                       if key.stop != None:
-                               stop = key.stop
-                       else:
-                               stop = self.width
-                       if stop > self.width:
-                               stop = self.width
-                       if key.step != None:
-                               raise KeyError
-                       return get_bits(self, self.width, start, stop)
-               else:
-                       raise KeyError
-
-       def decode_rle(self):
-               rle_bit = self[-1]
-               rle_dat = self[:self.width-1]
-
-               dat = Dat(self.width)
-               i=0
-               last = 0
-               for d in self:
-                       if rle_bit[i]:
-                               if len(dat) >= 1:
-                                       # FIX ME... why is rle_dat in reverse order...
-                                       for j in range(int(dec2bin(rle_dat[i])[::-1],2)):
-                                               dat.append(last)
-                       else:
-                               dat.append(d)
-                               last = d
-                       i +=1
-               return dat
-
-class Var:
-       def __init__(self, name, width, values=[], type="wire", 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 Dump:
-       def __init__(self):
-               self.vars = []
-               self.vcd_id = "!"
-               
-       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 add_from_layout(self, layout, var):
-               i=0
-               for s, n in layout:
-                       self.add(Var(s, n, var[i:i+n]))
-                       i += n
-       
-       def __len__(self):
-               l = 0
-               for var in self.vars:
-                       l = max(len(var),l)
-               return l
-
-class VCDExport():
-       def __init__(self, dump, timescale="1ps", comment=""):
-               self.dump = dump
-               self.timescale = timescale
-               self.comment = comment
-               self.cnt = -1
-
-       def change(self):
-               r = ""
-               c = ""
-               for var in self.dump.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.dump.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.dump.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.dump)):
-                       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()
-
-class CSVExport():
-       def __init__(self, dump):
-               self.dump = dump
-
-       def  p_vars(self):
-               r = ""
-               for var in self.dump.vars:
-                       r += var.name
-                       r += ","
-               r += "\n"
-               for var in self.dump.vars:
-                       r += str(var.width)
-                       r += ","
-               r += "\n"
-               return r
-
-       def p_dumpvars(self):
-               r  = ""
-               for i in range(len(self.dump)):
-                       for var in self.dump.vars:
-                               try:
-                                       var.val = var.values[i]
-                               except:
-                                       pass
-                               if var.val == "x":
-                                       r += "x"
-                               else:
-                                       r += dec2bin(var.val, var.width)
-                               r += ", "
-                       r+= "\n"
-               return r
-
-       def __repr__(self):
-               r = ""
-               r += self.p_vars()
-               r += self.p_dumpvars()
-               return r
-
-       def write(self, filename):
-               f = open(filename, "w")
-               f.write(str(self))
-               f.close()
-
-class PYExport():
-       def __init__(self, dump):
-               self.dump = dump
-
-       def __repr__(self):
-               r = "dump = {\n"
-               for var in self.dump.vars:
-                       r += "\"" + var.name + "\""
-                       r += " : "
-                       r += str(var.values)
-                       r += ",\n"
-               r += "}"
-               return r
-
-       def write(self, filename):
-               f = open(filename, "w")
-               f.write(str(self))
-               f.close()
-
-def main():
-       dump = Dump()
-       dump.add(Var("foo1", 1, [0,1,0,1,0,1]))
-       dump.add(Var("foo2", 2, [1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0]))
-       ramp = [i%128 for i in range(1024)]
-       dump.add(Var("ramp", 16, ramp))
-       
-       VCDExport(dump).write("mydump.vcd")
-       CSVExport(dump).write("mydump.csv")
-       PYExport(dump).write("mydump.py")
-
-if __name__ == '__main__':
-  main()
-
diff --git a/miscope/host/regs.py b/miscope/host/regs.py
deleted file mode 100644 (file)
index 16a98d9..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-import csv
-
-class MappedReg:
-       def __init__(self, readfn, writefn, name, addr, length, busword, mode):
-               self.readfn = readfn
-               self.writefn = writefn
-               self.addr = addr
-               self.length = length
-               self.busword = busword
-               self.mode = mode
-
-       def read(self):
-               if self.mode not in ["rw", "ro"]:
-                       raise KeyError(name + "register not readable")
-               r = 0
-               for i in range(self.length):
-                       r |= self.readfn(self.addr + 4*i)
-                       if i != (self.length-1):
-                               r <<= self.busword
-               return r
-
-       def write(self, value):
-               if self.mode not in ["rw", "wo"]:
-                       raise KeyError(name + "register not writable")
-               for i in range(self.length):
-                       dat = (value >> ((self.length-1-i)*self.busword)) & (2**self.busword-1)
-                       self.writefn(self.addr + 4*i, dat)
-
-class MappedRegs:
-       def __init__(self, d):
-               self.d = d
-
-       def __getattr__(self, attr):
-               try:
-                       return self.__dict__['d'][attr]
-               except KeyError:
-                       pass
-               raise KeyError("No such register " + attr)
-
-def    build_map(addrmap, busword, readfn, writefn):
-       csv_reader = csv.reader(open(addrmap), delimiter=',', quotechar='#')
-       d = {}
-       for item in csv_reader:
-               name, addr, length, mode = item
-               addr = int(addr.replace("0x", ""), 16)
-               length = int(length)
-               d[name] = MappedReg(readfn, writefn, name, addr, length, busword, mode)
-       return MappedRegs(d)
\ No newline at end of file
diff --git a/miscope/host/truthtable.py b/miscope/host/truthtable.py
deleted file mode 100644 (file)
index 319eaee..0000000
+++ /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/miscope/host/uart2wishbone.py b/miscope/host/uart2wishbone.py
deleted file mode 100644 (file)
index e959086..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-import string
-import serial
-from struct import *
-from migen.fhdl.structure import *
-from miscope.host.regs import *
-
-def write_b(uart, data):
-       uart.write(pack('B',data))
-
-class Uart2Wishbone:
-       WRITE_CMD  = 0x01
-       READ_CMD   = 0x02
-       def __init__(self, port, baudrate=115200, addrmap=None, busword=8, debug=False):
-               self.port = port
-               self.baudrate = str(baudrate)
-               self.debug = debug
-               self.uart = serial.Serial(port, baudrate, timeout=0.25)
-               self.regs = build_map(addrmap, busword, self.read, self.write)
-
-       def open(self):
-               self.uart.flushOutput()
-               self.uart.close()
-               self.uart.open()
-               self.uart.flushInput()
-               try:
-                       self.regs.uart2wb_sel.write(1)
-               except:
-                       pass
-
-       def close(self):
-               try:
-                       self.regs.uart2wb_sel.write(0)
-               except:
-                       pass
-               self.uart.flushOutput()
-               self.uart.close()
-
-       def read(self, addr, burst_length=1):
-               self.uart.flushInput()
-               write_b(self.uart, self.READ_CMD)
-               write_b(self.uart, burst_length)
-               addr = addr//4
-               write_b(self.uart, (addr & 0xff000000) >> 24)
-               write_b(self.uart, (addr & 0x00ff0000) >> 16)
-               write_b(self.uart, (addr & 0x0000ff00) >> 8)
-               write_b(self.uart, (addr & 0x000000ff))
-               values = [] 
-               for i in range(burst_length):
-                       val = 0
-                       for j in range(4):
-                               val = val << 8
-                               val |= ord(self.uart.read())
-                       if self.debug:
-                               print("RD %08X @ %08X" %(val, (addr+i)*4))
-                       values.append(val)
-               if burst_length == 1:
-                       return values[0]
-               else:
-                       return values
-
-       def write(self, addr, data):
-               if isinstance(data, list):
-                       burst_length = len(data)
-               else:
-                       burst_length = 1
-               write_b(self.uart, self.WRITE_CMD)
-               write_b(self.uart, burst_length)
-               addr = addr//4
-               write_b(self.uart, (addr & 0xff000000) >> 24)
-               write_b(self.uart, (addr & 0x00ff0000) >> 16)
-               write_b(self.uart, (addr & 0x0000ff00) >> 8)
-               write_b(self.uart, (addr & 0x000000ff))
-               if isinstance(data, list):
-                       for i in range(len(data)):
-                               dat = data[i]
-                               for j in range(4):
-                                       write_b(self.uart, (dat & 0xff000000) >> 24)
-                                       dat = dat << 8
-                               if self.debug:
-                                       print("WR %08X @ %08X" %(data[i], (addr + i)*4))
-               else:
-                       dat = data
-                       for j in range(4):
-                               write_b(self.uart, (dat & 0xff000000) >> 24)
-                               dat = dat << 8
-                       if self.debug:
-                               print("WR %08X @ %08X" %(data, (addr * 4)))
diff --git a/miscope/miio.py b/miscope/miio.py
deleted file mode 100644 (file)
index a78c056..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-from migen.fhdl.structure import *
-from migen.bank.description import *
-
-class MiIo(Module, AutoCSR):
-       def __init__(self, width):
-               self._r_i = CSRStatus(width)
-               self._r_o = CSRStorage(width)
-
-               self.i = self._r_i.status
-               self.o = self._r_o.storage
diff --git a/miscope/mila.py b/miscope/mila.py
deleted file mode 100644 (file)
index abf8e79..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-from migen.fhdl.std import *
-from migen.fhdl import verilog
-from migen.bank.description import *
-from migen.actorlib.fifo import AsyncFIFO
-
-from miscope.std import *
-from miscope.trigger import Trigger
-from miscope.storage import Recorder, RunLengthEncoder
-
-from mibuild.tools import write_to_file
-
-def _getattr_all(l, attr):
-       it = iter(l)
-       r = getattr(next(it), attr)
-       for e in it:
-               if getattr(e, attr) != r:
-                       raise ValueError
-       return r
-
-class MiLa(Module, AutoCSR):
-       def __init__(self, depth, dat, with_rle=False, clk_domain="sys", pipe=False):
-               self.depth = depth
-               self.with_rle = with_rle
-               self.clk_domain = clk_domain
-               self.pipe = pipe
-               self.ports = []
-               self.width = flen(dat)
-
-               self.stb = Signal(reset=1)
-               self.dat = dat
-
-       def add_port(self, port_class):
-               port = port_class(self.width)
-               self.ports.append(port)
-
-       def do_finalize(self):
-               stb = self.stb
-               dat = self.dat
-               if self.pipe:
-                       sync = getattr(self.sync, self.clk_domain)
-                       stb_new = Signal()
-                       dat_new = Signal(flen(dat))
-                       sync += [
-                               stb_new.eq(stb),
-                               dat_new.eq(dat)
-                       ]
-                       stb = stb_new
-                       dat = dat_new
-
-               if self.clk_domain is not "sys":
-                       fifo = AsyncFIFO([("dat", self.width)], 32)
-                       self.submodules += RenameClockDomains(fifo, {"write": self.clk_domain, "read": "sys"})
-                       self.comb += [
-                               fifo.sink.stb.eq(stb),
-                               fifo.sink.dat.eq(dat)
-                       ]
-                       sink = Record(dat_layout(self.width))
-                       self.comb += [
-                               sink.stb.eq(fifo.source.stb),
-                               sink.dat.eq(fifo.source.dat),
-                               fifo.source.ack.eq(1)
-                       ]
-               else:
-                       sink = Record(dat_layout(self.width))
-                       self.comb += [
-                               sink.stb.eq(stb),
-                               sink.dat.eq(dat)
-                       ]
-
-               self.submodules.trigger = trigger = Trigger(self.width, self.ports)
-               self.submodules.recorder = recorder = Recorder(self.width, self.depth)
-               self.comb += [
-                       sink.connect(trigger.sink),
-                       trigger.source.connect(recorder.trig_sink)
-               ]
-
-               if self.with_rle:
-                       self.submodules.rle = rle = RunLengthEncoder(self.width)
-                       self.comb += [
-                               sink.connect(rle.sink),
-                               rle.source.connect(recorder.dat_sink)
-                       ]
-               else:
-                       self.comb += sink.connect(recorder.dat_sink)
-
-       def export(self, design, layout, filename):
-               ret, ns = verilog.convert(design, return_ns=True)
-               r = ""
-               def format_line(*args):
-                       return ",".join(args) + "\n"
-
-               r += format_line("config", "width", str(self.width))
-               r += format_line("config", "depth", str(self.depth))
-               r += format_line("config", "with_rle", str(int(self.with_rle)))
-
-               for e in layout:
-                       r += format_line("layout", ns.get_name(e), str(flen(e)))
-               write_to_file(filename, r)
diff --git a/miscope/std.py b/miscope/std.py
deleted file mode 100644 (file)
index d7ffc7e..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-from migen.genlib.record import *
-
-def dat_layout(dw):
-       return [
-               ("stb", 1, DIR_M_TO_S),
-               ("dat", dw, DIR_M_TO_S)
-       ]
-
-def hit_layout():
-       return [
-               ("stb", 1, DIR_M_TO_S),
-               ("hit", 1, DIR_M_TO_S)
-       ]
diff --git a/miscope/storage.py b/miscope/storage.py
deleted file mode 100644 (file)
index 3179704..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-from migen.fhdl.std import *
-from migen.bank.description import *
-from migen.genlib.fifo import SyncFIFOBuffered as SyncFIFO
-from migen.genlib.fsm import FSM, NextState
-from migen.genlib.record import *
-
-from miscope.std import *
-
-class RunLengthEncoder(Module, AutoCSR):
-       def __init__(self, width, length=1024):
-               self.width = width
-               self.length = length
-
-               self.sink = Record(dat_layout(width))
-               self.source = Record(dat_layout(width))
-
-               self._enable = CSRStorage()
-
-               ###
-
-               enable = self._enable.storage
-
-               sink_d = Record(dat_layout(width))
-               self.sync += If(self.sink.stb, sink_d.eq(self.sink))
-
-               cnt = Signal(max=length)
-               cnt_inc = Signal()
-               cnt_reset = Signal()
-               cnt_max = Signal()
-
-               self.sync += \
-                       If(cnt_reset,
-                               cnt.eq(1),
-                       ).Elif(cnt_inc,
-                               cnt.eq(cnt+1)
-                       )
-               self.comb += cnt_max.eq(cnt == length)
-
-               change = Signal()
-               self.comb += change.eq(self.sink.stb & (self.sink.dat != sink_d.dat))
-
-               fsm = FSM(reset_state="BYPASS")
-               self.submodules += fsm
-
-               fsm.act("BYPASS",
-                       sink_d.connect(self.source),
-                       cnt_reset.eq(1),
-                       If(enable & ~change & self.sink.stb, NextState("COUNT"))
-               )
-
-               fsm.act("COUNT",
-                       cnt_inc.eq(self.sink.stb),
-                       If(change | cnt_max | ~enable,
-                               self.source.stb.eq(1),
-                               self.source.dat[width-1].eq(1), # Set RLE bit
-                               self.source.dat[:flen(cnt)].eq(cnt),
-                               NextState("BYPASS")
-                       )
-               ),
-
-class Recorder(Module, AutoCSR):
-       def __init__(self, width, depth):
-               self.width = width
-
-               self.trig_sink = Record(hit_layout())
-               self.dat_sink = Record(dat_layout(width))
-
-               self._trigger = CSR()
-               self._length = CSRStorage(bits_for(depth))
-               self._offset = CSRStorage(bits_for(depth))
-               self._done = CSRStatus()
-
-               self._read_en = CSR()
-               self._read_empty = CSRStatus()
-               self._read_dat = CSRStatus(width)
-
-               ###
-
-               fifo = InsertReset(SyncFIFO(width, depth))
-               self.submodules += fifo
-
-               fsm = FSM(reset_state="IDLE")
-               self.submodules += fsm
-
-
-               self.comb += [
-                       self._read_empty.status.eq(~fifo.readable),
-                       self._read_dat.status.eq(fifo.dout),
-               ]
-
-               fsm.act("IDLE",
-                       If(self._trigger.re & self._trigger.r,
-                               NextState("PRE_HIT_RECORDING"),
-                               fifo.reset.eq(1),
-                       ),
-                       fifo.re.eq(self._read_en.re & self._read_en.r),
-                       self._done.status.eq(1)
-               )
-
-               fsm.act("PRE_HIT_RECORDING",
-                       fifo.we.eq(self.dat_sink.stb),
-                       fifo.din.eq(self.dat_sink.dat),
-
-                       fifo.re.eq(fifo.level >= self._offset.storage),
-
-                       If(self.trig_sink.stb & self.trig_sink.hit, NextState("POST_HIT_RECORDING"))
-               )
-
-               fsm.act("POST_HIT_RECORDING",
-                       fifo.we.eq(self.dat_sink.stb),
-                       fifo.din.eq(self.dat_sink.dat),
-
-                       If(~fifo.writable | (fifo.level >= self._length.storage), NextState("IDLE"))
-               )
diff --git a/miscope/trigger.py b/miscope/trigger.py
deleted file mode 100644 (file)
index 6e795f5..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-from migen.fhdl.std import *
-from migen.fhdl.specials import Memory
-from migen.bank.description import *
-from migen.genlib.record import *
-
-from miscope.std import *
-
-class Term(Module, AutoCSR):
-       def __init__(self, width):
-               self.width = width
-
-               self.sink = Record(dat_layout(width))
-               self.source = Record(hit_layout())
-
-               self._trig = CSRStorage(width)
-               self._mask = CSRStorage(width)
-
-       ###
-
-               trig = self._trig.storage
-               mask = self._mask.storage
-               dat = self.sink.dat
-               hit = self.source.hit
-
-               self.comb += [
-                       hit.eq((dat & mask) == trig),
-                       self.source.stb.eq(self.sink.stb)
-               ]
-
-class RangeDetector(Module, AutoCSR):
-       def __init__(self, width):
-               self.width = width
-
-               self.sink = Record(dat_layout(width))
-               self.source = Record(hit_layout())
-
-               self._low = CSRStorage(width)
-               self._high = CSRStorage(width)
-
-       ###
-
-               low = self._low.storage
-               high = self._high.storage
-               dat = self.sink.dat
-               hit = self.source.hit
-
-               self.comb += [
-                       hit.eq((dat >= low) & (dat <= high)),
-                       self.source.stb.eq(self.sink.stb)
-               ]
-
-class EdgeDetector(Module, AutoCSR):
-       def __init__(self, width):
-               self.width = width
-
-               self.sink = Record(dat_layout(width))
-               self.source = Record(hit_layout())
-
-               self._rising_mask = CSRStorage(width)
-               self._falling_mask = CSRStorage(width)
-               self._both_mask = CSRStorage(width)
-
-       ###
-
-               rising_mask = self._rising_mask.storage
-               falling_mask = self._falling_mask.storage
-               both_mask = self._both_mask.storage
-
-               dat = self.sink.dat
-               dat_d = Signal(width)
-               rising_hit = Signal()
-               falling_hit = Signal()
-               both_hit = Signal()
-               hit = self.source.hit
-
-               self.sync += dat_d.eq(dat)
-
-               self.comb += [
-                       rising_hit.eq(rising_mask & dat & ~dat_d),
-                       falling_hit.eq(rising_mask & ~dat & dat_d),
-                       both_hit.eq((both_mask & dat) != (both_mask & dat_d)),
-                       hit.eq(rising_hit | falling_hit | both_hit),
-                       self.source.stb.eq(self.sink.stb)
-               ]
-
-class Sum(Module, AutoCSR):
-       def __init__(self, ports=4):
-
-               self.sinks = [Record(hit_layout()) for p in range(ports)]
-               self.source = Record(hit_layout())
-
-               self._prog_we = CSRStorage()
-               self._prog_adr = CSRStorage(ports) #FIXME
-               self._prog_dat = CSRStorage()
-
-               mem = Memory(1, 2**ports)
-               lut_port = mem.get_port()
-               prog_port = mem.get_port(write_capable=True)
-
-               self.specials += mem, lut_port, prog_port
-
-               ###
-
-               # Lut prog
-               self.comb += [
-                       prog_port.we.eq(self._prog_we.storage),
-                       prog_port.adr.eq(self._prog_adr.storage),
-                       prog_port.dat_w.eq(self._prog_dat.storage)
-               ]
-
-               # Lut read
-               for i, sink in enumerate(self.sinks):
-                       self.comb += lut_port.adr[i].eq(sink.hit)
-
-               # Drive source
-               self.comb += [
-                       self.source.stb.eq(optree("&", [sink.stb for sink in self.sinks])),
-                       self.source.hit.eq(lut_port.dat_r),
-               ]
-
-
-class Trigger(Module, AutoCSR):
-       def __init__(self, width, ports):
-               self.width = width
-               self.ports = ports
-
-               self.submodules.sum = Sum(len(ports))
-               for i, port in enumerate(ports):
-                       setattr(self.submodules, "port"+str(i), port)
-
-               self.sink   = Record(dat_layout(width))
-               self.source = self.sum.source
-
-               ###
-
-               for i, port in enumerate(ports):
-                       self.comb += [
-                               self.sink.connect(port.sink),
-                               port.source.connect(self.sum.sinks[i])
-                       ]
diff --git a/miscope/uart2wishbone.py b/miscope/uart2wishbone.py
deleted file mode 100644 (file)
index e8e773f..0000000
+++ /dev/null
@@ -1,219 +0,0 @@
-from migen.fhdl.std import *
-from migen.genlib.record import *
-from migen.genlib.fsm import FSM, NextState
-from migen.genlib.misc import chooser
-from migen.bank.description import *
-from migen.bus import wishbone
-
-from misoclib.uart import UARTRX, UARTTX
-
-@DecorateModule(InsertReset)
-@DecorateModule(InsertCE)
-class Counter(Module):
-       def __init__(self, signal=None, **kwargs):
-               if signal is None:
-                       self.value = Signal(**kwargs)
-               else:
-                       self.value = signal
-               self.width = flen(self.value)
-               self.sync += self.value.eq(self.value+1)
-
-@DecorateModule(InsertReset)
-@DecorateModule(InsertCE)
-class Timeout(Module):
-       def __init__(self, length):
-               self.reached = Signal()
-               ###
-               value = Signal(max=length)
-               self.sync += value.eq(value+1)
-               self.comb += [
-                       self.reached.eq(value == length)
-               ]
-
-class UART(Module, AutoCSR):
-       def __init__(self, pads, clk_freq, baud=115200):
-               self._tuning_word = CSRStorage(32, reset=int((baud/clk_freq)*2**32))
-               tuning_word = self._tuning_word.storage
-
-               ###
-
-               self.rx = UARTRX(pads, tuning_word)
-               self.tx = UARTTX(pads, tuning_word)
-               self.submodules += self.rx, self.tx
-
-class UARTPads:
-       def __init__(self):
-               self.rx = Signal()
-               self.tx = Signal()
-
-class UARTMux(Module):
-       def __init__(self, pads):
-               self.sel = Signal(max=2)
-               self.shared_pads = UARTPads()
-               self.bridge_pads = UARTPads()
-
-       ###
-               # Route rx pad:
-               # when sel==0, route it to shared rx and bridge rx
-               # when sel==1, route it only to bridge rx
-               self.comb += \
-                       If(self.sel==0,
-                               self.shared_pads.rx.eq(pads.rx),
-                               self.bridge_pads.rx.eq(pads.rx)
-                       ).Else(
-                               self.bridge_pads.rx.eq(pads.rx)
-                       )
-
-               # Route tx:
-               # when sel==0, route shared tx to pads tx
-               # when sel==1, route bridge tx to pads tx
-               self.comb += \
-                       If(self.sel==0,
-                               pads.tx.eq(self.shared_pads.tx)
-                       ).Else(
-                               pads.tx.eq(self.bridge_pads.tx)
-                       )
-
-class UART2Wishbone(Module, AutoCSR):
-       cmds = {
-               "write" : 0x01,
-               "read"  : 0x02
-       }
-       def __init__(self, pads, clk_freq, baud=115200, share_uart=False):
-               self.wishbone = wishbone.Interface()
-               if share_uart:
-                       self._sel = CSRStorage()
-               ###
-               if share_uart:
-                       self.uart_mux = UARTMux(pads)
-                       uart = UART(self.uart_mux.bridge_pads, clk_freq, baud)
-                       self.shared_pads = self.uart_mux.shared_pads
-                       self.comb += self.uart_mux.sel.eq(self._sel.storage)
-               else:
-                       uart = UART(pads, clk_freq, baud)
-               self.submodules += uart
-
-               byte_counter = Counter(bits_sign=3)
-               word_counter = Counter(bits_sign=8)
-               self.submodules += byte_counter, word_counter
-
-
-               cmd = Signal(8)
-               cmd_ce = Signal()
-
-               length = Signal(8)
-               length_ce = Signal()
-
-               address = Signal(32)
-               address_ce = Signal()
-
-               data = Signal(32)
-               rx_data_ce = Signal()
-               tx_data_ce = Signal()
-
-               self.sync += [
-                       If(cmd_ce, cmd.eq(uart.rx.source.d)),
-                       If(length_ce, length.eq(uart.rx.source.d)),
-                       If(address_ce, address.eq(Cat(uart.rx.source.d, address[0:24]))),
-                       If(rx_data_ce,
-                               data.eq(Cat(uart.rx.source.d, data[0:24]))
-                       ).Elif(tx_data_ce,
-                               data.eq(self.wishbone.dat_r)
-                       )
-               ]
-
-               ###
-               fsm = InsertReset(FSM(reset_state="IDLE"))
-               timeout = Timeout(clk_freq//10)
-               self.submodules += fsm, timeout
-
-               self.comb += [
-                       timeout.ce.eq(1),
-                       fsm.reset.eq(timeout.reached)
-               ]
-               fsm.act("IDLE",
-                       timeout.reset.eq(1),
-                       If(uart.rx.source.stb,
-                               cmd_ce.eq(1),
-                               If(     (uart.rx.source.d == self.cmds["write"]) |
-                                       (uart.rx.source.d == self.cmds["read"]),
-                                       NextState("RECEIVE_LENGTH")
-                               ),
-                               byte_counter.reset.eq(1),
-                               word_counter.reset.eq(1)
-                       )
-               )
-               fsm.act("RECEIVE_LENGTH",
-                       If(uart.rx.source.stb,
-                               length_ce.eq(1),
-                               NextState("RECEIVE_ADDRESS")
-                       )
-               )
-               fsm.act("RECEIVE_ADDRESS",
-                       If(uart.rx.source.stb,
-                               address_ce.eq(1),
-                               byte_counter.ce.eq(1),
-                               If(byte_counter.value == 3,
-                                       If(cmd == self.cmds["write"],
-                                               NextState("RECEIVE_DATA")
-                                       ).Elif(cmd == self.cmds["read"],
-                                               NextState("READ_DATA")
-                                       ),
-                                       byte_counter.reset.eq(1),
-                               )
-                       )
-               )
-               fsm.act("RECEIVE_DATA",
-                       If(uart.rx.source.stb,
-                               rx_data_ce.eq(1),
-                               byte_counter.ce.eq(1),
-                               If(byte_counter.value == 3,
-                                       NextState("WRITE_DATA"),
-                                       byte_counter.reset.eq(1)
-                               )
-                       )
-               )
-               self.comb += [
-                       self.wishbone.adr.eq(address + word_counter.value),
-                       self.wishbone.dat_w.eq(data),
-                       self.wishbone.sel.eq(2**flen(self.wishbone.sel)-1)
-               ]
-               fsm.act("WRITE_DATA",
-                       self.wishbone.stb.eq(1),
-                       self.wishbone.we.eq(1),
-                       self.wishbone.cyc.eq(1),
-                       If(self.wishbone.ack,
-                               word_counter.ce.eq(1),
-                               If(word_counter.value == (length-1),
-                                       NextState("IDLE")
-                               ).Else(
-                                       NextState("RECEIVE_DATA")
-                               )
-                       )
-               )
-               fsm.act("READ_DATA",
-                       self.wishbone.stb.eq(1),
-                       self.wishbone.we.eq(0),
-                       self.wishbone.cyc.eq(1),
-                       If(self.wishbone.ack,
-                               tx_data_ce.eq(1),
-                               NextState("SEND_DATA")
-                       )
-               )
-               self.comb += \
-                       chooser(data, byte_counter.value, uart.tx.sink.d, n=4, reverse=True)
-               fsm.act("SEND_DATA",
-                       uart.tx.sink.stb.eq(1),
-                       If(uart.tx.sink.ack,
-                               byte_counter.ce.eq(1),
-                               If(byte_counter.value == 3,
-                                       word_counter.ce.eq(1),
-                                       If(word_counter.value == (length-1),
-                                               NextState("IDLE")
-                                       ).Else(
-                                               NextState("READ_DATA"),
-                                               byte_counter.reset.eq(1)
-                                       )
-                               )
-                       )
-               )
index 740be67b2e85c323e5dbf99b6767b9be4eb985da..979c1655d12b357315bb9a71867b9a822241d7f8 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -9,18 +9,18 @@ README = open(os.path.join(here, "README")).read()
 
 required_version = (3, 3)
 if sys.version_info < required_version:
-       raise SystemExit("Migscope requires python {0} or greater".format(
+       raise SystemExit("LiteScope requires python {0} or greater".format(
                ".".join(map(str, required_version))))
 
 setup(
-       name="miscope",
+       name="litescope",
        version="unknown",
-       description="Migen based Fpga logic analyzer",
+       description="small footprint and configurable embedded 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/miscope",
+       download_url="https://github.com/Florent-Kermarrec/litescope",
        packages=find_packages(here),
        license="GPL",
        platforms=["Any"],
diff --git a/sim/cpuif.py b/sim/cpuif.py
deleted file mode 100644 (file)
index 6a0ed40..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-from migen.bank.description import CSRStatus
-
-def get_csr_csv(csr_base, bank_array):
-       r = ""
-       for name, csrs, mapaddr, rmap in bank_array.banks:
-               reg_base = csr_base + 0x800*mapaddr
-               for csr in csrs:
-                       nr = (csr.size + 7)//8
-                       r += "{}_{},0x{:08x},{},{}\n".format(name, csr.name, reg_base, nr, "ro" if isinstance(csr, CSRStatus) else "rw")
-                       reg_base += 4*nr
-       return r
diff --git a/sim/tb_recorder_csr.py b/sim/tb_recorder_csr.py
deleted file mode 100644 (file)
index 368bb80..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-from migen.fhdl.std import *
-from migen.fhdl import verilog
-from migen.bus import csr
-from migen.sim.generic import run_simulation
-from migen.bus.transactions import *
-
-from miscope.std import *
-from miscope.storage import *
-
-from mibuild.tools import write_to_file
-from miscope.tools.regs import *
-from miscope.tools.truthtable import *
-
-from cpuif import *
-
-class Csr2Trans():
-       def __init__(self):
-               self.t = []
-
-       def write_csr(self, adr, value):
-               self.t.append(TWrite(adr//4, value))
-
-       def read_csr(self, adr):
-               self.t.append(TRead(adr//4))
-               return 0
-
-
-triggered = False
-dat = 0
-
-rec_done = False
-
-dat_rdy = False
-
-rec_length = 128
-
-def csr_configure(bus, regs):
-       # Length
-       regs.recorder_length.write(rec_length)
-
-       # Offset
-       regs.recorder_offset.write(0)
-
-       # Trigger
-       regs.recorder_trigger.write(1)
-
-       return bus.t
-
-def csr_read_data(bus, regs):
-       for i in range(rec_length+100):
-               regs.recorder_read_dat.read()
-               regs.recorder_read_en.write(1)
-       return bus.t
-
-def csr_transactions(bus, regs):
-       for t in csr_configure(bus, regs):
-               yield t
-
-       for t in range(100):
-               yield None
-
-       global triggered
-       triggered = True
-
-       for t in range(512):
-               yield None
-
-       for t in csr_read_data(bus, regs):
-               yield t
-
-       for t in range(100):
-               yield None
-
-
-class TB(Module):
-       csr_base = 0
-       csr_map = {
-               "recorder": 1,
-       }
-       def __init__(self, addrmap=None):
-               self.csr_base = 0
-
-               # Recorder
-               self.submodules.recorder = Recorder(32, 1024)
-       
-               # Csr
-               self.submodules.csrbankarray = csrgen.BankArray(self, 
-                       lambda name, memory: self.csr_map[name if memory is None else name + "_" + memory.name_override])
-
-               # Csr Master
-               csr_header = get_csr_csv(self.csr_base, self.csrbankarray)
-               write_to_file("csr.csv", csr_header)
-
-               bus = Csr2Trans()
-               regs = build_map(addrmap, bus.read_csr, bus.write_csr)
-               self.submodules.master = csr.Initiator(csr_transactions(bus, regs))
-
-               self.submodules.csrcon = csr.Interconnect(self.master.bus,      self.csrbankarray.get_buses())
-
-       # Recorder Data
-       def recorder_data(self, selfp):
-               selfp.recorder.dat_sink.stb = 1
-               if not hasattr(self, "cnt"):
-                       self.cnt = 0
-               self.cnt += 1   
-
-               selfp.recorder.dat_sink.dat =  self.cnt
-
-               global triggered
-               if triggered:
-                       selfp.recorder.trig_sink.stb = 1
-                       selfp.recorder.trig_sink.hit = 1
-                       triggered = False
-               else:
-                       selfp.recorder.trig_sink.stb = 0
-                       selfp.recorder.trig_sink.hit = 0
-
-       # Simulation
-       def end_simulation(self, selfp):
-               if self.master.done:
-                       raise StopSimulation
-
-       def do_simulation(self, selfp):
-               self.recorder_data(selfp)
-               self.end_simulation(selfp)
-
-
-def main():
-       tb = TB(addrmap="csr.csv")
-       run_simulation(tb, ncycles=2000, vcd_name="tb_recorder_csr.vcd")
-       print("Sim Done")
-       input()
-
-main()
\ No newline at end of file
diff --git a/sim/tb_rle.py b/sim/tb_rle.py
deleted file mode 100644 (file)
index 1dd8e75..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-from migen.fhdl.std import *
-from migen.sim.generic import run_simulation
-
-from miscope import storage
-
-rle_test_seq = iter(
-       [       0x00AA,
-               0x00AB,
-               0x00AC,
-               0x00AC,
-               0x00AC,
-               0x00AC,
-               0x00AD,
-               0x00AE,
-               0x00AE,
-               0x00AE,
-               0x00AE,
-               0x00AE,
-               0x00AE,
-               0x00AE,
-               0x00AE
-       ]*10
-)
-
-class TB(Module):
-       def __init__(self):
-
-               # Rle
-               self.submodules.rle = storage.RunLengthEncoder(16, 32)
-
-       def do_simulation(self, selfp):
-               selfp.rle._r_enable.storage = 1
-               selfp.rle.sink.stb = 1
-               try:
-                       selfp.rle.sink.dat = next(rle_test_seq)
-               except:
-                       pass
-
-def main():
-       tb = TB()
-       run_simulation(tb, ncycles=8000, vcd_name="tb_rle.vcd")
-       print("Sim Done")
-       input()
-
-main()
diff --git a/sim/tb_trigger_csr.py b/sim/tb_trigger_csr.py
deleted file mode 100644 (file)
index ef74703..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-from migen.fhdl.std import *
-from migen.fhdl import verilog
-from migen.bus import csr
-from migen.sim.generic import run_simulation
-from migen.bus.transactions import *
-
-from miscope.std import *
-from miscope.trigger import *
-
-from mibuild.tools import write_to_file
-from miscope.tools.regs import *
-from miscope.tools.truthtable import *
-
-from cpuif import *
-
-class Csr2Trans():
-       def __init__(self):
-               self.t = []
-
-       def write_csr(self, adr, value):
-               self.t.append(TWrite(adr//4, value))
-
-       def read_csr(self, adr):
-               self.t.append(TRead(adr//4))
-
-def csr_prog_mila(bus, regs):
-       regs.trigger_port0_mask.write(0xFFFFFFFF)
-       regs.trigger_port0_trig.write(0xDEADBEEF)
-       regs.trigger_port1_mask.write(0xFFFFFFFF)
-       regs.trigger_port1_trig.write(0xCAFEFADE)
-       regs.trigger_port2_mask.write(0xFFFFFFFF)
-       regs.trigger_port2_trig.write(0xDEADBEEF)
-       regs.trigger_port3_mask.write(0xFFFFFFFF)
-       regs.trigger_port3_trig.write(0xCAFEFADE)
-
-       sum_tt = gen_truth_table("i1 & i2 & i3 & i4")
-       sum_trans = []
-       for i in range(len(sum_tt)):
-               regs.trigger_sum_prog_adr.write(i)
-               regs.trigger_sum_prog_dat.write(sum_tt[i])
-               regs.trigger_sum_prog_we.write(1)
-
-       return bus.t
-
-
-csr_done = False
-
-def csr_transactions(bus, regs):
-       for t in csr_prog_mila(bus, regs):
-               yield t
-       global csr_done
-       csr_done = True
-       for t in range(100):
-               yield None
-
-class TB(Module):
-       csr_base = 0
-       csr_map = {
-               "trigger": 1,
-       }
-       def __init__(self, addrmap=None):
-               self.csr_base = 0
-
-               # Trigger
-               term0 = Term(32)
-               term1 = Term(32)
-               term2 = Term(32)
-               term3 = Term(32)
-               self.submodules.trigger = Trigger(32, [term0, term1, term2, term3])
-
-               # Csr
-               self.submodules.csrbankarray = csrgen.BankArray(self, 
-                       lambda name, memory: self.csr_map[name if memory is None else name + "_" + memory.name_override])
-
-               # Csr Master
-               csr_header = get_csr_csv(self.csr_base, self.csrbankarray)
-               write_to_file("csr.csv", csr_header)
-
-               bus = Csr2Trans()
-               regs = build_map(addrmap, bus.read_csr, bus.write_csr)
-               self.submodules.master = csr.Initiator(csr_transactions(bus, regs))
-
-               self.submodules.csrcon = csr.Interconnect(self.master.bus,      self.csrbankarray.get_buses())
-
-               self.terms = [term0, term1, term2, term3]
-
-       def do_simulation(self, selfp):
-               for term in selfp.terms:
-                       term.sink.stb = 1
-               if csr_done:
-                       selfp.terms[0].sink.dat = 0xDEADBEEF
-                       selfp.terms[1].sink.dat = 0xCAFEFADE
-                       selfp.terms[2].sink.dat = 0xDEADBEEF
-                       selfp.terms[3].sink.dat = 0xCAFEFADE
-
-def main():
-       tb = TB(addrmap="csr.csv")
-       run_simulation(tb, ncycles=2000, vcd_name="tb_trigger_csr.vcd")
-       print("Sim Done")
-       input()
-
-main()
diff --git a/targets/__init__.py b/targets/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/targets/simple.py b/targets/simple.py
new file mode 100644 (file)
index 0000000..40c9993
--- /dev/null
@@ -0,0 +1,83 @@
+import os
+
+from migen.bank import csrgen
+from migen.bus import wishbone, csr
+from migen.bus import wishbone2csr
+from migen.genlib.cdc import *
+from migen.genlib.resetsync import AsyncResetSynchronizer
+from migen.bank.description import *
+
+from misoclib import identifier
+
+from litescope.common import *
+from litescope.bridge.uart2wb import LiteScopeUART2WB
+
+class _CRG(Module):
+       def __init__(self, clk_in):
+               self.clock_domains.cd_sys = ClockDomain()
+               self.clock_domains.cd_por = ClockDomain(reset_less=True)
+
+               # Power on Reset (vendor agnostic)
+               rst_n = Signal()
+               self.sync.por += rst_n.eq(1)
+               self.comb += [
+                       self.cd_sys.clk.eq(clk_in),
+                       self.cd_por.clk.eq(clk_in),
+                       self.cd_sys.rst.eq(~rst_n)
+               ]
+
+class GenSoC(Module):
+       csr_base = 0x00000000
+       csr_data_width = 32
+       csr_map = {
+               "bridge":                       0,
+               "identifier":           1,
+       }
+       interrupt_map = {}
+       cpu_type = None
+       def __init__(self, platform, clk_freq):
+               self.clk_freq = clk_freq
+               # UART <--> Wishbone bridge
+               self.submodules.uart2wb = LiteScopeUART2WB(platform.request("serial"), clk_freq, baud=115200)
+
+               # CSR bridge   0x00000000 (shadow @0x00000000)
+               self.submodules.wishbone2csr = wishbone2csr.WB2CSR(bus_csr=csr.Interface(self.csr_data_width))
+               self._wb_masters = [self.uart2wb.wishbone]
+               self._wb_slaves = [(lambda a: a[23:25] == 0, self.wishbone2csr.wishbone)]
+               self.cpu_csr_regions = [] # list of (name, origin, busword, csr_list/Memory)
+
+               # CSR
+               self.submodules.identifier = identifier.Identifier(0, int(clk_freq), 0)
+
+       def add_cpu_memory_region(self, name, origin, length):
+               self.cpu_memory_regions.append((name, origin, length))
+
+       def add_cpu_csr_region(self, name, origin, busword, obj):
+               self.cpu_csr_regions.append((name, origin, busword, obj))
+
+       def do_finalize(self):
+               # Wishbone
+               self.submodules.wishbonecon = wishbone.InterconnectShared(self._wb_masters,
+                       self._wb_slaves, register=True)
+
+               # CSR
+               self.submodules.csrbankarray = csrgen.BankArray(self,
+                       lambda name, memory: self.csr_map[name if memory is None else name + "_" + memory.name_override],
+                       data_width=self.csr_data_width)
+               self.submodules.csrcon = csr.Interconnect(self.wishbone2csr.csr, self.csrbankarray.get_buses())
+               for name, csrs, mapaddr, rmap in self.csrbankarray.banks:
+                       self.add_cpu_csr_region(name, 0xe0000000+0x800*mapaddr, flen(rmap.bus.dat_w), csrs)
+               for name, memory, mapaddr, mmap in self.csrbankarray.srams:
+                       self.add_cpu_csr_region(name, 0xe0000000+0x800*mapaddr, flen(rmap.bus.dat_w), memory)
+
+class LiteScopeSoC(GenSoC, AutoCSR):
+       default_platform = "de0nano"
+       csr_map = {}
+       csr_map.update(GenSoC.csr_map)
+
+       def __init__(self, platform, export_mila=False):
+               clk_freq = 50*1000000
+               GenSoC.__init__(self, platform, clk_freq)
+               self.submodules.crg = _CRG(platform.request("clk50"))
+
+default_subtarget = LiteScopeSoC
diff --git a/test/Makefile b/test/Makefile
new file mode 100644 (file)
index 0000000..6d23bdc
--- /dev/null
@@ -0,0 +1,7 @@
+LSDIR = ../
+PYTHON = python3
+
+CMD = PYTHONPATH=$(LSDIR) $(PYTHON)
+
+test_regs:
+       $(CMD) test_regs.py
diff --git a/test/config.py b/test/config.py
new file mode 100644 (file)
index 0000000..7fc5706
--- /dev/null
@@ -0,0 +1,9 @@
+from litescope.host.driver import LiteScopeUART2WBDriver
+
+csr_csv_file = "./csr.csv"
+busword = 32
+debug_wb = False
+
+com = 3
+baud = 115200
+wb = LiteScopeUART2WBDriver(com, baud, csr_csv_file, busword, debug_wb)
\ No newline at end of file
diff --git a/test/test_regs.py b/test/test_regs.py
new file mode 100644 (file)
index 0000000..bb59b64
--- /dev/null
@@ -0,0 +1,11 @@
+from config import *
+
+wb.open()
+regs = wb.regs
+###
+print("sysid     : 0x%04x" %regs.identifier_sysid.read())
+print("revision  : 0x%04x" %regs.identifier_revision.read())
+print("frequency : %d MHz" %(regs.identifier_frequency.read()/1000000))
+print("l2_size   : %d" %regs.identifier_l2_size.read())
+###
+wb.close()