litex/migScope/recorder.py

234 lines
6.2 KiB
Python

from migen.fhdl.structure import *
from migen.bus import csr
from migen.bank import description, csrgen
from migen.bank.description import *
from migen.corelogic.misc import optree
class Storage:
#
# Definition
#
def __init__(self, width, depth):
self.width = width
self.depth = depth
self.depth_width = bits_for(self.depth)
#Control
self.rst = Signal()
self.start = Signal()
self.offset = Signal(BV(self.depth_width))
self.size = Signal(BV(self.depth_width))
self.done = Signal()
self.run = Signal()
#Write Path
self.put = Signal()
self.put_dat = Signal(BV(self.width))
self._put_ptr = Signal(BV(self.depth_width))
self._put_ptr_stop = Signal(BV(self.depth_width))
self._put_port = MemoryPort(adr=self._put_ptr, we=self.put, dat_w=self.put_dat)
#Read Path
self.get = Signal()
self.get_dat = Signal(BV(self.width))
self._get_ptr = Signal(BV(self.depth_width))
self._get_port = MemoryPort(adr=self._get_ptr, re=self.get, dat_r=self.get_dat)
#Others
self._mem = Memory(self.width, self.depth, self._put_port, self._get_port)
def get_fragment(self):
comb = []
sync = []
memories = [self._mem]
size_minus_offset = Signal(BV(self.depth_width))
comb += [size_minus_offset.eq(self.size-self.offset)]
#Control
sync += [
If(self.rst,
self.run.eq(0),
self._put_ptr.eq(0)
).Elif(self.start & ~self.run,
self.run.eq(1),
self._put_ptr_stop.eq(self._put_ptr + self.size - self.offset)
).Elif(self.done,
self.run.eq(0)
),
If(self.put & ~self.done,
self._put_ptr.eq(self._put_ptr+1)
),
If(self.rst,
self.done.eq(0)
).Elif((self._put_ptr == self._put_ptr_stop) & self.run,
self.done.eq(1)
),
If(self.rst,
self._get_ptr.eq(0)
).Elif(self.start & ~self.run,
self._get_ptr.eq(self._put_ptr-self.offset-1)
).Elif(self.get,
self._get_ptr.eq(self._get_ptr+1)
)
]
return Fragment(comb=comb, sync=sync, memories=memories)
class Sequencer:
#
# Definition
#
def __init__(self,depth):
self.depth = depth
self.depth_width = bits_for(self.depth)
# Controller interface
self.ctl_rst = Signal()
self.ctl_offset = Signal(BV(self.depth_width))
self.ctl_size = Signal(BV(self.depth_width))
self.ctl_arm = Signal()
self.ctl_done = Signal()
self._ctl_arm_d = Signal()
# Triggers interface
self.trig_hit = Signal()
self._trig_hit_d = Signal()
# Recorder interface
self.rec_offset = Signal(BV(self.depth_width))
self.rec_size = Signal(BV(self.depth_width))
self.rec_start = Signal()
self.rec_done = Signal()
# Others
self.enable = Signal()
def get_fragment(self):
comb = []
sync = []
#Control
sync += [
If(self.ctl_rst,
self.enable.eq(0)
).Elif(self.ctl_arm & ~self._ctl_arm_d,
self.enable.eq(1)
).Elif(self.rec_done,
self.enable.eq(0)
),
self._ctl_arm_d.eq(self.ctl_arm)
]
sync += [self._trig_hit_d.eq(self.trig_hit)]
comb += [
self.rec_offset.eq(self.ctl_offset),
self.rec_size.eq(self.ctl_size),
self.rec_start.eq(self.enable & (self.trig_hit & ~self._trig_hit_d)),
self.ctl_done.eq(~self.enable)
]
return Fragment(comb=comb, sync=sync)
class Recorder:
#
# Definition
#
def __init__(self, width, depth, address = 0x0000, interface = None):
self.address = address
self.width = width
self.depth = depth
self.depth_width = bits_for(self.depth)
self.interface = interface
self.storage = Storage(self.width, self.depth)
self.sequencer = Sequencer(self.depth)
# Csr interface
self._rst = RegisterField("rst", reset=1)
self._arm = RegisterField("arm", reset=0)
self._done = RegisterField("done", reset=0, access_bus=READ_ONLY, access_dev=WRITE_ONLY)
self._size = RegisterField("size", self.depth_width, reset=1)
self._offset = RegisterField("offset", self.depth_width, reset=1)
self._get = RegisterField("get", reset=0)
self._get_dat = RegisterField("get_dat", self.width, reset=1, access_bus=READ_ONLY, access_dev=WRITE_ONLY)
self.regs = [self._rst, self._arm, self._done,
self._size, self._offset,
self._get, self._get_dat]
self.bank = csrgen.Bank(self.regs,address=self.address)
# Trigger Interface
self.trig_hit = Signal()
self.trig_dat = Signal(BV(self.width))
def set_address(self, address):
self.address = address
self.bank = csrgen.Bank(self.regs,address=self.address)
def set_interface(self, interface):
self.interface = interface
def get_fragment(self):
comb = []
sync = []
_get_d = Signal()
_get_rising = Signal()
sync += [
_get_d.eq(self._get.field.r),
_get_rising.eq(self._get.field.r & ~_get_d)
]
#Bank <--> Storage / Sequencer
comb += [
self.sequencer.ctl_rst.eq(self._rst.field.r),
self.storage.rst.eq(self._rst.field.r),
self.sequencer.ctl_offset.eq(self._offset.field.r),
self.sequencer.ctl_size.eq(self._size.field.r),
self.sequencer.ctl_arm.eq(self._arm.field.r),
self._done.field.w.eq(self.sequencer.ctl_done),
self.storage.get.eq(_get_rising),
self._get_dat.field.w.eq(self.storage.get_dat)
]
#Storage <--> Sequencer <--> Trigger
comb += [
self.storage.offset.eq(self.sequencer.rec_offset),
self.storage.size.eq(self.sequencer.rec_size),
self.storage.start.eq(self.sequencer.rec_start),
self.sequencer.rec_done.eq(self.storage.done),
self.sequencer.trig_hit.eq(self.trig_hit),
self.storage.put.eq(self.sequencer.enable),
self.storage.put_dat.eq(self.trig_dat)
]
return self.bank.get_fragment()+\
self.storage.get_fragment()+self.sequencer.get_fragment()+\
Fragment(comb=comb, sync=sync)
#
#Driver
#
def reset(self):
self.interface.write(self.address + 0x00, 1)
self.interface.write(self.address + 0x00, 0)
def arm(self):
self.interface.write(self.address + 0x01, 1)
self.interface.write(self.address + 0x01, 0)
def is_done(self):
return self.interface.read(self.address + 0x02) == 1
def size(self, dat):
self.size = dat
self.interface.write_n(self.address + 0x03, dat, 16)
def offset(self, dat):
self.interface.write_n(self.address + 0x05, dat, 16)
def read(self, size):
r = []
for i in range(size):
self.interface.write(self.address+7, 1)
self.interface.write(self.address+7, 0)
r.append(self.interface.read_n(self.address+8,self.width))
return r