start refactoring and change name to LiteScope
This commit is contained in:
parent
609f8f9abb
commit
f35f93a7c5
|
@ -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.
|
156
README
156
README
|
@ -1,48 +1,130 @@
|
||||||
_____ _ ____ _ _ _ _
|
__ _ __ ____
|
||||||
| __|___ |_|___ _ _ | \|_|___|_| |_ ___| |
|
/ / (_) /____ / __/______ ___ ___
|
||||||
| __| | | | . | | | | | | | . | | _| .'| |
|
/ /__/ / __/ -_)\ \/ __/ _ \/ _ \/ -_)
|
||||||
|_____|_|_|_| |___|_ | |____/|_|_ |_|_| |__,|_|
|
/____/_/\__/\__/___/\__/\___/ .__/\__/
|
||||||
|___| |___| |___|
|
/_/
|
||||||
|
Copyright 2012-2015 / EnjoyDigital
|
||||||
|
florent@enjoy-digital.fr
|
||||||
|
|
||||||
Copyright 2012-2014 / Florent Kermarrec / florent@enjoy-digital.fr
|
A small footprint and configurable embedded FPGA
|
||||||
|
logic analyzer core by EnjoyDigital
|
||||||
|
|
||||||
Miscope
|
[> Intro
|
||||||
--------------------------------------------------------------------------------
|
---------
|
||||||
|
LiteScope small footprint and configurable embedded logic analyzer that you
|
||||||
[> Miscope
|
can use in your FPGA and aims to provide a a free, portable and flexible
|
||||||
------------
|
|
||||||
|
|
||||||
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
|
|
||||||
alternatve to vendor's solutions!
|
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...
|
||||||
|
|
||||||
Miscope provides Migen cores to embed in the design and Python drivers to control
|
The core uses simple and specific streaming buses and will provides in the future
|
||||||
the logic analyzer from the Host. Miscope automatically interconnects all cores
|
adapters to use standardized AXI or Avalon-ST streaming buses.
|
||||||
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!
|
|
||||||
|
|
||||||
Miscope produces .vcd output files to be analyzed in your favorite waveform viewer.
|
Since Python is used to describe the HDL, the core is highly and easily
|
||||||
|
configurable.
|
||||||
|
|
||||||
Since Miscope also provides an Uart2Wishbone bridge, you only need 2 external Rx/Tx
|
LiteScope uses technologies developed in partnership with M-Labs Ltd:
|
||||||
pins to be ready to debug!
|
- Migen enables generating HDL with Python in an efficient way.
|
||||||
|
- MiSoC provides the basic blocks to build a powerful and small footprint SoC.
|
||||||
|
|
||||||
[> Status:
|
LiteScope can be used as a Migen/MiSoC library (by simply installing it
|
||||||
MiIo & Mila working on board with standard term.
|
with the provided setup.py) or can be integrated with your standard design flow
|
||||||
RLE working on board.
|
by generating the verilog rtl that you will use as a standard core.
|
||||||
RangeDetector and EdgeDector terms not tested.
|
|
||||||
|
|
||||||
[> Examples:
|
LiteScope produces "vcd" files that can be read in your regular waveforms viewer.
|
||||||
Have a look at http://github.com/Florent-Kermarrec/misoc-de0nano
|
|
||||||
test_miio.py : Led & Switch Test controlled by Python Host.
|
Since LiteScope also provides an UART <--> Wishbone brige you only need 2 external
|
||||||
test_mila.py : Logic Analyzer controlled by Python Host.
|
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
|
||||||
|
|
||||||
|
[> 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.
|
||||||
|
|
||||||
|
[> Support and Consulting
|
||||||
|
--------------------------
|
||||||
|
We love open-source hardware and like sharing our designs with others.
|
||||||
|
|
||||||
|
LiteScope is developed and maintained by EnjoyDigital.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
So feel free to contact us, we'd love to work with you! (and eventually shorten
|
||||||
|
the list of the possible improvements :)
|
||||||
|
|
||||||
[> Contact
|
[> Contact
|
||||||
E-mail: florent@enjoy-digital.fr
|
E-mail: florent [AT] enjoy-digital.fr
|
|
@ -0,0 +1,2 @@
|
||||||
|
0.9.0
|
||||||
|
|
|
@ -7,28 +7,7 @@ from migen.bus import wishbone
|
||||||
|
|
||||||
from misoclib.uart import UARTRX, UARTTX
|
from misoclib.uart import UARTRX, UARTTX
|
||||||
|
|
||||||
@DecorateModule(InsertReset)
|
from litescope.common import *
|
||||||
@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):
|
class UART(Module, AutoCSR):
|
||||||
def __init__(self, pads, clk_freq, baud=115200):
|
def __init__(self, pads, clk_freq, baud=115200):
|
||||||
|
@ -74,7 +53,7 @@ class UARTMux(Module):
|
||||||
pads.tx.eq(self.bridge_pads.tx)
|
pads.tx.eq(self.bridge_pads.tx)
|
||||||
)
|
)
|
||||||
|
|
||||||
class UART2Wishbone(Module, AutoCSR):
|
class LiteScopeUART2WB(Module, AutoCSR):
|
||||||
cmds = {
|
cmds = {
|
||||||
"write" : 0x01,
|
"write" : 0x01,
|
||||||
"read" : 0x02
|
"read" : 0x02
|
||||||
|
@ -85,10 +64,11 @@ class UART2Wishbone(Module, AutoCSR):
|
||||||
self._sel = CSRStorage()
|
self._sel = CSRStorage()
|
||||||
###
|
###
|
||||||
if share_uart:
|
if share_uart:
|
||||||
self.uart_mux = UARTMux(pads)
|
uart_mux = UARTMux(pads)
|
||||||
uart = UART(self.uart_mux.bridge_pads, clk_freq, baud)
|
uart = UART(uart_mux.bridge_pads, clk_freq, baud)
|
||||||
self.shared_pads = self.uart_mux.shared_pads
|
self.submodules += uart_mux, uart
|
||||||
self.comb += self.uart_mux.sel.eq(self._sel.storage)
|
self.shared_pads = uart_mux.shared_pads
|
||||||
|
self.comb += uart_mux.sel.eq(self._sel.storage)
|
||||||
else:
|
else:
|
||||||
uart = UART(pads, clk_freq, baud)
|
uart = UART(pads, clk_freq, baud)
|
||||||
self.submodules += uart
|
self.submodules += uart
|
||||||
|
@ -97,7 +77,6 @@ class UART2Wishbone(Module, AutoCSR):
|
||||||
word_counter = Counter(bits_sign=8)
|
word_counter = Counter(bits_sign=8)
|
||||||
self.submodules += byte_counter, word_counter
|
self.submodules += byte_counter, word_counter
|
||||||
|
|
||||||
|
|
||||||
cmd = Signal(8)
|
cmd = Signal(8)
|
||||||
cmd_ce = Signal()
|
cmd_ce = Signal()
|
||||||
|
|
||||||
|
@ -126,7 +105,6 @@ class UART2Wishbone(Module, AutoCSR):
|
||||||
fsm = InsertReset(FSM(reset_state="IDLE"))
|
fsm = InsertReset(FSM(reset_state="IDLE"))
|
||||||
timeout = Timeout(clk_freq//10)
|
timeout = Timeout(clk_freq//10)
|
||||||
self.submodules += fsm, timeout
|
self.submodules += fsm, timeout
|
||||||
|
|
||||||
self.comb += [
|
self.comb += [
|
||||||
timeout.ce.eq(1),
|
timeout.ce.eq(1),
|
||||||
fsm.reset.eq(timeout.reached)
|
fsm.reset.eq(timeout.reached)
|
|
@ -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)
|
||||||
|
]
|
|
@ -4,9 +4,9 @@ from migen.genlib.fifo import SyncFIFOBuffered as SyncFIFO
|
||||||
from migen.genlib.fsm import FSM, NextState
|
from migen.genlib.fsm import FSM, NextState
|
||||||
from migen.genlib.record import *
|
from migen.genlib.record import *
|
||||||
|
|
||||||
from miscope.std import *
|
from litescope.common import *
|
||||||
|
|
||||||
class RunLengthEncoder(Module, AutoCSR):
|
class LiteScopeRunLengthEncoder(Module, AutoCSR):
|
||||||
def __init__(self, width, length=1024):
|
def __init__(self, width, length=1024):
|
||||||
self.width = width
|
self.width = width
|
||||||
self.length = length
|
self.length = length
|
||||||
|
@ -58,7 +58,7 @@ class RunLengthEncoder(Module, AutoCSR):
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
||||||
class Recorder(Module, AutoCSR):
|
class LiteScopeRecorder(Module, AutoCSR):
|
||||||
def __init__(self, width, depth):
|
def __init__(self, width, depth):
|
||||||
self.width = width
|
self.width = width
|
||||||
|
|
|
@ -3,9 +3,9 @@ from migen.fhdl.specials import Memory
|
||||||
from migen.bank.description import *
|
from migen.bank.description import *
|
||||||
from migen.genlib.record import *
|
from migen.genlib.record import *
|
||||||
|
|
||||||
from miscope.std import *
|
from litescope.common import *
|
||||||
|
|
||||||
class Term(Module, AutoCSR):
|
class LiteScopeTerm(Module, AutoCSR):
|
||||||
def __init__(self, width):
|
def __init__(self, width):
|
||||||
self.width = width
|
self.width = width
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ class Term(Module, AutoCSR):
|
||||||
self.source.stb.eq(self.sink.stb)
|
self.source.stb.eq(self.sink.stb)
|
||||||
]
|
]
|
||||||
|
|
||||||
class RangeDetector(Module, AutoCSR):
|
class LiteScopeRangeDetector(Module, AutoCSR):
|
||||||
def __init__(self, width):
|
def __init__(self, width):
|
||||||
self.width = width
|
self.width = width
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ class RangeDetector(Module, AutoCSR):
|
||||||
self.source.stb.eq(self.sink.stb)
|
self.source.stb.eq(self.sink.stb)
|
||||||
]
|
]
|
||||||
|
|
||||||
class EdgeDetector(Module, AutoCSR):
|
class LiteScopeEdgeDetector(Module, AutoCSR):
|
||||||
def __init__(self, width):
|
def __init__(self, width):
|
||||||
self.width = width
|
self.width = width
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ class EdgeDetector(Module, AutoCSR):
|
||||||
self.source.stb.eq(self.sink.stb)
|
self.source.stb.eq(self.sink.stb)
|
||||||
]
|
]
|
||||||
|
|
||||||
class Sum(Module, AutoCSR):
|
class LiteScopeSum(Module, AutoCSR):
|
||||||
def __init__(self, ports=4):
|
def __init__(self, ports=4):
|
||||||
|
|
||||||
self.sinks = [Record(hit_layout()) for p in range(ports)]
|
self.sinks = [Record(hit_layout()) for p in range(ports)]
|
||||||
|
@ -119,12 +119,12 @@ class Sum(Module, AutoCSR):
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class Trigger(Module, AutoCSR):
|
class LiteScopeTrigger(Module, AutoCSR):
|
||||||
def __init__(self, width, ports):
|
def __init__(self, width, ports):
|
||||||
self.width = width
|
self.width = width
|
||||||
self.ports = ports
|
self.ports = ports
|
||||||
|
|
||||||
self.submodules.sum = Sum(len(ports))
|
self.submodules.sum = LiteScopeSum(len(ports))
|
||||||
for i, port in enumerate(ports):
|
for i, port in enumerate(ports):
|
||||||
setattr(self.submodules, "port"+str(i), port)
|
setattr(self.submodules, "port"+str(i), port)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from migen.fhdl.structure import *
|
from migen.fhdl.structure import *
|
||||||
from migen.bank.description import *
|
from migen.bank.description import *
|
||||||
|
|
||||||
class MiIo(Module, AutoCSR):
|
class LiteScopeIO(Module, AutoCSR):
|
||||||
def __init__(self, width):
|
def __init__(self, width):
|
||||||
self._r_i = CSRStatus(width)
|
self._r_i = CSRStatus(width)
|
||||||
self._r_o = CSRStorage(width)
|
self._r_o = CSRStorage(width)
|
|
@ -3,9 +3,9 @@ from migen.fhdl import verilog
|
||||||
from migen.bank.description import *
|
from migen.bank.description import *
|
||||||
from migen.actorlib.fifo import AsyncFIFO
|
from migen.actorlib.fifo import AsyncFIFO
|
||||||
|
|
||||||
from miscope.std import *
|
from litescope.common import *
|
||||||
from miscope.trigger import Trigger
|
from litescope.core.trigger import LiteScopeTrigger
|
||||||
from miscope.storage import Recorder, RunLengthEncoder
|
from litescope.core.storage import LiteScopeRecorder, LiteScopeRunLengthEncoder
|
||||||
|
|
||||||
from mibuild.tools import write_to_file
|
from mibuild.tools import write_to_file
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ def _getattr_all(l, attr):
|
||||||
raise ValueError
|
raise ValueError
|
||||||
return r
|
return r
|
||||||
|
|
||||||
class MiLa(Module, AutoCSR):
|
class LiteScopeLA(Module, AutoCSR):
|
||||||
def __init__(self, depth, dat, with_rle=False, clk_domain="sys", pipe=False):
|
def __init__(self, depth, dat, with_rle=False, clk_domain="sys", pipe=False):
|
||||||
self.depth = depth
|
self.depth = depth
|
||||||
self.with_rle = with_rle
|
self.with_rle = with_rle
|
||||||
|
@ -67,15 +67,15 @@ class MiLa(Module, AutoCSR):
|
||||||
sink.dat.eq(dat)
|
sink.dat.eq(dat)
|
||||||
]
|
]
|
||||||
|
|
||||||
self.submodules.trigger = trigger = Trigger(self.width, self.ports)
|
self.submodules.trigger = trigger = LiteScopeTrigger(self.width, self.ports)
|
||||||
self.submodules.recorder = recorder = Recorder(self.width, self.depth)
|
self.submodules.recorder = recorder = LiteScopeRecorder(self.width, self.depth)
|
||||||
self.comb += [
|
self.comb += [
|
||||||
sink.connect(trigger.sink),
|
sink.connect(trigger.sink),
|
||||||
trigger.source.connect(recorder.trig_sink)
|
trigger.source.connect(recorder.trig_sink)
|
||||||
]
|
]
|
||||||
|
|
||||||
if self.with_rle:
|
if self.with_rle:
|
||||||
self.submodules.rle = rle = RunLengthEncoder(self.width)
|
self.submodules.rle = rle = LiteScopeRunLengthEncoder(self.width)
|
||||||
self.comb += [
|
self.comb += [
|
||||||
sink.connect(rle.sink),
|
sink.connect(rle.sink),
|
||||||
rle.source.connect(recorder.dat_sink)
|
rle.source.connect(recorder.dat_sink)
|
|
@ -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
|
|
@ -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)
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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)))
|
|
|
@ -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)
|
|
||||||
]
|
|
8
setup.py
8
setup.py
|
@ -9,18 +9,18 @@ README = open(os.path.join(here, "README")).read()
|
||||||
|
|
||||||
required_version = (3, 3)
|
required_version = (3, 3)
|
||||||
if sys.version_info < required_version:
|
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))))
|
".".join(map(str, required_version))))
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="miscope",
|
name="litescope",
|
||||||
version="unknown",
|
version="unknown",
|
||||||
description="Migen based Fpga logic analyzer",
|
description="small footprint and configurable embedded FPGA logic analyzer",
|
||||||
long_description=README,
|
long_description=README,
|
||||||
author="Florent Kermarrec",
|
author="Florent Kermarrec",
|
||||||
author_email="florent@enjoy-digital.fr",
|
author_email="florent@enjoy-digital.fr",
|
||||||
url="http://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),
|
packages=find_packages(here),
|
||||||
license="GPL",
|
license="GPL",
|
||||||
platforms=["Any"],
|
platforms=["Any"],
|
||||||
|
|
11
sim/cpuif.py
11
sim/cpuif.py
|
@ -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
|
|
|
@ -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()
|
|
|
@ -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()
|
|
|
@ -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()
|
|
|
@ -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
|
|
@ -0,0 +1,7 @@
|
||||||
|
LSDIR = ../
|
||||||
|
PYTHON = python3
|
||||||
|
|
||||||
|
CMD = PYTHONPATH=$(LSDIR) $(PYTHON)
|
||||||
|
|
||||||
|
test_regs:
|
||||||
|
$(CMD) test_regs.py
|
|
@ -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)
|
|
@ -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()
|
Loading…
Reference in New Issue