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 analyser in the design is generally helpful)
+(situations where having a logic analyzer in the design is generally helpful)
free toolchains are always provided without the proprietary logic analyzer
solution... :(
-Based on Migen, Miscope aims to provide a free, portable and flexible
-alternative to vendor's solutions!
+Baseid on Migen, Miscope aims to provide a free, portable and flexible
+alternatve to vendor's solutions!
[> Specification:
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 aboutcores register
+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.
pins to be ready to debug!
[> Status:
-Miio & Mila working on board with standard term.
+MiIo & Mila working on board with standard term.
RLE working on board.
RangeDetector and EdgeDector terms not tested.
[> Examples:
Have a look at http://github.com/Florent-Kermarrec/misoc-de0nano
-miscope_miio.py : Led & Switch Test controlled by Python Host.
-miscope_mila.py : Logic Analyzer controlled by Python Host.
+miio.py : Led & Switch Test controlled by Python Host.
+mila.py : Logic Analyzer controlled by Python Host.
[> Contact
E-mail: florent@enjoy-digital.fr
dat.append(d)
last = d
i +=1
- return dat
+ return dat
class Var:
def __init__(self, name, width, values=[], type="wire", default="x"):
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 += 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+= "\n"
r += "$end\n"
return r
-
+
def p_valuechange(self):
r = ""
for i in range(len(self.dump)):
r += ","
r += "\n"
return r
-
+
def p_dumpvars(self):
r = ""
for i in range(len(self.dump)):
def write(self, filename):
f = open(filename, "w")
f.write(str(self))
- f.close()
+ f.close()
def main():
dump = Dump()
VCDExport(dump).write("mydump.vcd")
CSVExport(dump).write("mydump.csv")
PYExport(dump).write("mydump.py")
-
+
if __name__ == '__main__':
main()
return self.__dict__['d'][attr]
except KeyError:
pass
-
raise KeyError("No such register " + attr)
def build_map(addrmap, busword, readfn, writefn):
import sys
def is_number(x):
- try:
- _ = float(x)
- except ValueError:
- return False
- return True
+ try:
+ _ = float(x)
+ except ValueError:
+ return False
+ return True
def remove_numbers(seq):
- return [ x for x in seq if not is_number(x)]
+ 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)]
+ 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)
self.regs.uart2wb_sel.write(1)
except:
pass
-
+
def close(self):
try:
self.regs.uart2wb_sel.write(0)
self._r_i = CSRStatus(width)
self._r_o = CSRStorage(width)
- self.sync +=[
+ self.sync += [
self._r_i.status.eq(self.i),
self.o.eq(self._r_o.storage)
- ]
\ No newline at end of file
+ ]
from migen.fhdl.structure import *
from migen.bank.description import *
+from migen.genlib.record import *
from miscope.std import *
from miscope.trigger import Trigger
self.with_rle = with_rle
self.ports = ports
- self.sink = rec_dat(width)
+ self.sink = Record(dat_layout(width))
trigger = Trigger(width, ports)
recorder = Recorder(width, depth)
self.submodules.trigger = trigger
self.submodules.recorder = recorder
- sink_d = rec_dat(width)
+ sink_d = Record(dat_layout(width))
self.sync += sink_d.eq(self.sink)
self.comb += [
from migen.genlib.record import *
-def rec_dat(width):
- layout = [
- ("stb", 1, DIR_M_TO_S),
- ("dat", width, DIR_M_TO_S)
- ]
- return Record(layout)
+def dat_layout(dw):
+ return [
+ ("stb", 1, DIR_M_TO_S),
+ ("dat", dw, DIR_M_TO_S)
+ ]
-def rec_hit():
- layout = [
- ("stb", 1, DIR_M_TO_S),
- ("hit", 1, DIR_M_TO_S)
- ]
- return Record(layout)
-
-def rec_dat_hit(width):
- layout = [
- ("stb", 1, DIR_M_TO_S),
- ("hit", 1, DIR_M_TO_S),
- ("dat", width, DIR_M_TO_S)
- ]
- return Record(layout)
\ No newline at end of file
+def hit_layout():
+ return [
+ ("stb", 1, DIR_M_TO_S),
+ ("hit", 1, DIR_M_TO_S)
+ ]
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 *
self.width = width
self.length = length
- self.sink = rec_dat(width)
- self.source = rec_dat(width)
+ self.sink = Record(dat_layout(width))
+ self.source = Record(dat_layout(width))
self._r_enable = CSRStorage()
enable = self._r_enable.storage
- sink_d = rec_dat(width)
+ sink_d = Record(dat_layout(width))
self.sync += If(self.sink.stb, sink_d.eq(self.sink))
cnt = Signal(max=length)
def __init__(self, width, depth):
self.width = width
- self.trig_sink = rec_hit()
- self.dat_sink = rec_dat(width)
+ self.trig_sink = Record(hit_layout())
+ self.dat_sink = Record(dat_layout(width))
self._r_trigger = CSR()
self._r_length = CSRStorage(bits_for(depth))
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 *
def __init__(self, width):
self.width = width
- self.sink = rec_dat(width)
- self.source = rec_hit()
+ self.sink = Record(dat_layout(width))
+ self.source = Record(hit_layout())
self._r_trig = CSRStorage(width)
self._r_mask = CSRStorage(width)
dat = self.sink.dat
hit = self.source.hit
- self.comb +=[
+ self.comb += [
hit.eq((dat & mask) == trig),
self.source.stb.eq(self.sink.stb)
]
def __init__(self, width):
self.width = width
- self.sink = rec_dat(width)
- self.source = rec_hit()
+ self.sink = Record(dat_layout(width))
+ self.source = Record(hit_layout())
self._r_low = CSRStorage(width)
self._r_high = CSRStorage(width)
dat = self.sink.dat
hit = self.source.hit
- self.comb +=[
+ 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 = rec_dat(width)
- self.source = rec_hit()
+ self.sink = Record(dat_layout(width))
+ self.source = Record(hit_layout())
self._r_rising_mask = CSRStorage(width)
self._r_falling_mask = CSRStorage(width)
self.sync += dat_d.eq(dat)
- self.comb +=[
+ 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)),
class Sum(Module, AutoCSR):
def __init__(self, ports=4):
-
- self.sinks = [rec_hit() for p in range(ports)]
- self.source = rec_hit()
+
+ self.sinks = [Record(hit_layout()) for p in range(ports)]
+ self.source = Record(hit_layout())
self._r_prog_we = CSRStorage()
self._r_prog_adr = CSRStorage(ports) #FIXME
###
# Lut prog
- self.comb +=[
+ self.comb += [
prog_port.we.eq(self._r_prog_we.storage),
prog_port.adr.eq(self._r_prog_adr.storage),
prog_port.dat_w.eq(self._r_prog_dat.storage)
self.comb += lut_port.adr[i].eq(sink.hit)
# Drive source
- self.comb +=[
+ self.comb += [
self.source.stb.eq(optree("&", [sink.stb for sink in self.sinks])),
self.source.hit.eq(lut_port.dat_r),
]
def __init__(self, width, ports):
self.width = width
self.ports = ports
-
- self.submodules.sum = Sum(len(ports))
- # FIXME : when self.submodules += is used,
- # get_csrs() is not called
+ self.submodules.sum = Sum(len(ports))
for i, port in enumerate(ports):
- tmp = "self.submodules.port"+str(i)+" = port"
- exec(tmp)
+ setattr(self.submodules, "port"+str(i), port)
- self.sink = rec_dat(width)
+ self.sink = Record(dat_layout(width))
self.source = self.sum.source
- self.busy = Signal()
###
+
for i, port in enumerate(ports):
- self.comb +=[
+ self.comb += [
self.sink.connect(port.sink),
port.source.connect(self.sum.sinks[i])
- ]
\ No newline at end of file
+ ]
from migen.bank.description import *
from migen.bus import wishbone
-
-# Todo
-# ----
-# - implement timeout in fsm to prevent deadlocks
-
-def rec_rx():
- layout = [
+def rx_layout():
+ return [
("stb", 1, DIR_M_TO_S),
("dat", 8, DIR_M_TO_S)
- ]
- return Record(layout)
+ ]
-def rec_tx():
- layout = [
+def tx_layout():
+ return [
("stb", 1, DIR_M_TO_S),
("ack", 1, DIR_S_TO_M),
("dat", 8, DIR_M_TO_S)
- ]
- return Record(layout)
+ ]
class UART(Module):
def __init__(self, pads, clk_freq, baud=115200):
-
- self.rx = rec_rx()
- self.tx = rec_tx()
+ self.rx = Record(rx_layout())
+ self.tx = Record(tx_layout())
self.divisor = Signal(16, reset=int(clk_freq/baud/16))
pads.tx.reset = 1
-
+
###
enable16 = Signal()
If(enable16,
enable16_counter.eq(self.divisor - 1))
]
-
+
# TX
tx_reg = Signal(8)
tx_bitcount = Signal(4)
)
)
]
-
+
# RX
rx = Signal()
self.specials += MultiReg(pads.rx, rx, "sys")
pads_tx = [self.pads[i].tx for i in range(nb)]
self.comb += chooser(Cat(pads_tx), self.sel, pads.tx, n=nb)
-
class UART2Wishbone(Module, AutoCSR):
WRITE_CMD = 0x01
READ_CMD = 0x02
).Elif(fsm.ongoing("READ_DATA") & self.wishbone.stb & self.wishbone.ack,
data.eq(self.wishbone.dat_r)
)
-