2013-02-22 08:28:05 -05:00
|
|
|
from migen.fhdl.structure import *
|
2013-02-28 19:09:00 -05:00
|
|
|
from migen.fhdl.specials import Memory
|
2013-02-22 08:28:05 -05:00
|
|
|
from migen.bus import csr
|
|
|
|
from migen.bank import description, csrgen
|
|
|
|
from migen.bank.description import *
|
2013-02-28 19:09:00 -05:00
|
|
|
from migen.genlib.misc import optree
|
|
|
|
from migen.genlib.fsm import *
|
2013-02-22 08:28:05 -05:00
|
|
|
|
2013-03-21 07:23:44 -04:00
|
|
|
from miscope.tools.misc import RisingEdge
|
|
|
|
|
2013-02-22 08:28:05 -05:00
|
|
|
class Storage:
|
|
|
|
#
|
|
|
|
# Definition
|
|
|
|
#
|
|
|
|
def __init__(self, width, depth):
|
|
|
|
self.width = width
|
|
|
|
self.depth = depth
|
|
|
|
self.depth_width = bits_for(self.depth)
|
|
|
|
|
|
|
|
# Control
|
|
|
|
self.rst = Signal()
|
|
|
|
self.start = Signal()
|
|
|
|
self.offset = Signal(self.depth_width)
|
|
|
|
self.size = Signal(self.depth_width)
|
|
|
|
self.done = Signal()
|
|
|
|
|
|
|
|
# Push Path
|
|
|
|
self.push_stb = Signal()
|
|
|
|
self.push_dat = Signal(self.width)
|
|
|
|
self._push_ptr = Signal(self.depth_width)
|
|
|
|
self._push_ptr_stop = Signal(self.depth_width)
|
|
|
|
|
|
|
|
# Pull Path
|
|
|
|
self.pull_stb = Signal()
|
|
|
|
self.pull_dat = Signal(self.width)
|
|
|
|
self._pull_ptr = Signal(self.depth_width)
|
|
|
|
|
|
|
|
# Memory
|
|
|
|
self._mem = Memory(self.width, self.depth)
|
|
|
|
self._push_port = self._mem.get_port(write_capable=True)
|
|
|
|
self._pull_port = self._mem.get_port(has_re=True)
|
|
|
|
|
|
|
|
def get_fragment(self):
|
|
|
|
comb = [
|
|
|
|
self._push_port.adr.eq(self._push_ptr),
|
2013-02-27 18:32:42 -05:00
|
|
|
self._push_port.we.eq(self.push_stb),
|
2013-02-22 08:28:05 -05:00
|
|
|
self._push_port.dat_w.eq(self.push_dat),
|
|
|
|
|
|
|
|
self._pull_port.adr.eq(self._pull_ptr),
|
|
|
|
self._pull_port.re.eq(self.pull_stb),
|
|
|
|
self.pull_dat.eq(self._pull_port.dat_r)
|
|
|
|
]
|
|
|
|
|
|
|
|
# FSM
|
|
|
|
fsm = FSM("IDLE", "ACTIVE")
|
|
|
|
|
|
|
|
# Idle
|
|
|
|
fsm.act(fsm.IDLE,
|
|
|
|
If(self.start,
|
2013-02-27 18:32:42 -05:00
|
|
|
fsm.next_state(fsm.ACTIVE),
|
2013-03-21 07:23:44 -04:00
|
|
|
)
|
2013-02-22 08:28:05 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
# Active
|
|
|
|
fsm.act(fsm.ACTIVE,
|
|
|
|
If(self.done | self.rst,
|
|
|
|
fsm.next_state(fsm.IDLE),
|
2013-03-21 07:23:44 -04:00
|
|
|
)
|
2013-02-22 08:28:05 -05:00
|
|
|
)
|
|
|
|
|
2013-02-27 18:32:42 -05:00
|
|
|
sync =[
|
2013-03-21 07:23:44 -04:00
|
|
|
If(fsm.entering(fsm.ACTIVE),
|
2013-02-22 08:28:05 -05:00
|
|
|
self._push_ptr_stop.eq(self._push_ptr + self.size - self.offset),
|
2013-03-23 07:26:22 -04:00
|
|
|
self._pull_ptr.eq(self._push_ptr - self.offset - 1)
|
2013-02-22 08:28:05 -05:00
|
|
|
).Else(
|
2013-03-21 07:23:44 -04:00
|
|
|
If(self.pull_stb, self._pull_ptr.eq(self._pull_ptr + 1))
|
2013-02-22 08:28:05 -05:00
|
|
|
),
|
2013-03-21 07:23:44 -04:00
|
|
|
If(self.push_stb, self._push_ptr.eq(self._push_ptr + 1)),
|
2013-02-22 08:28:05 -05:00
|
|
|
]
|
2013-03-21 07:23:44 -04:00
|
|
|
comb +=[self.done.eq((self._push_ptr == self._push_ptr_stop) & fsm.ongoing(fsm.ACTIVE))]
|
2013-02-22 08:28:05 -05:00
|
|
|
|
2013-03-21 07:23:44 -04:00
|
|
|
return Fragment(comb, sync, specials={self._mem}) + fsm.get_fragment()
|
2013-02-22 08:28:05 -05:00
|
|
|
|
|
|
|
class Sequencer:
|
|
|
|
#
|
|
|
|
# Definition
|
|
|
|
#
|
2013-03-23 07:26:22 -04:00
|
|
|
def __init__(self):
|
2013-02-22 08:28:05 -05:00
|
|
|
|
|
|
|
# Controller interface
|
2013-03-23 07:26:22 -04:00
|
|
|
self.rst = Signal()
|
|
|
|
self.arm = Signal()
|
2013-02-22 08:28:05 -05:00
|
|
|
|
|
|
|
# Trigger interface
|
|
|
|
self.hit = Signal()
|
|
|
|
|
|
|
|
# Recorder interface
|
2013-03-23 07:26:22 -04:00
|
|
|
self.start = Signal()
|
|
|
|
self.done = Signal()
|
2013-02-22 08:28:05 -05:00
|
|
|
|
|
|
|
# Others
|
|
|
|
self.enable = Signal()
|
|
|
|
|
|
|
|
def get_fragment(self):
|
|
|
|
|
|
|
|
# FSM
|
|
|
|
fsm = FSM("IDLE", "ACTIVE")
|
|
|
|
|
|
|
|
# Idle
|
|
|
|
fsm.act(fsm.IDLE,
|
2013-03-23 07:26:22 -04:00
|
|
|
If(self.arm,
|
2013-02-27 18:32:42 -05:00
|
|
|
fsm.next_state(fsm.ACTIVE),
|
2013-03-21 07:23:44 -04:00
|
|
|
)
|
2013-02-22 08:28:05 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
# Active
|
|
|
|
fsm.act(fsm.ACTIVE,
|
2013-03-23 07:26:22 -04:00
|
|
|
If(self.done | self.rst,
|
2013-02-22 08:28:05 -05:00
|
|
|
fsm.next_state(fsm.IDLE),
|
|
|
|
),
|
2013-03-21 07:23:44 -04:00
|
|
|
self.enable.eq(1)
|
2013-02-22 08:28:05 -05:00
|
|
|
)
|
|
|
|
|
2013-03-23 07:26:22 -04:00
|
|
|
# Start
|
2013-03-21 07:23:44 -04:00
|
|
|
hit_rising = RisingEdge(self.hit)
|
2013-03-23 07:26:22 -04:00
|
|
|
comb =[self.start.eq(self.enable & hit_rising.o)]
|
|
|
|
|
2013-03-21 07:23:44 -04:00
|
|
|
return Fragment(comb) + fsm.get_fragment() + hit_rising.get_fragment()
|
2013-02-22 08:28:05 -05:00
|
|
|
|
|
|
|
|
2013-03-21 07:23:44 -04:00
|
|
|
REC_RST_BASE = 0x00
|
|
|
|
REC_ARM_BASE = 0x01
|
|
|
|
REC_DONE_BASE = 0x02
|
|
|
|
REC_SIZE_BASE = 0x03
|
|
|
|
REC_OFFSET_BASE = 0x05
|
|
|
|
REC_READ_BASE = 0x07
|
|
|
|
REC_READ_DATA_BASE = 0x08
|
2013-02-22 08:28:05 -05:00
|
|
|
|
|
|
|
class Recorder:
|
|
|
|
#
|
|
|
|
# Definition
|
|
|
|
#
|
2013-03-21 07:23:44 -04:00
|
|
|
def __init__(self, width, depth, address=0x0000, interface=None):
|
2013-02-22 08:28:05 -05:00
|
|
|
self.width = width
|
|
|
|
self.depth = depth
|
2013-03-21 07:23:44 -04:00
|
|
|
self.depth_width = bits_for(self.depth-1)
|
2013-02-22 08:28:05 -05:00
|
|
|
|
|
|
|
self.storage = Storage(self.width, self.depth)
|
2013-03-23 07:26:22 -04:00
|
|
|
self.sequencer = Sequencer()
|
2013-02-22 08:28:05 -05:00
|
|
|
|
|
|
|
# csr interface
|
|
|
|
self._rst = RegisterField("rst", reset=1)
|
|
|
|
self._arm = RegisterField("arm", reset=0)
|
|
|
|
self._done = RegisterField("done", reset=0, access_bus=READ_ONLY,
|
2013-03-21 07:23:44 -04:00
|
|
|
access_dev=WRITE_ONLY)
|
2013-02-22 08:28:05 -05:00
|
|
|
|
|
|
|
self._size = RegisterField("size", self.depth_width, reset=1)
|
|
|
|
self._offset = RegisterField("offset", self.depth_width, reset=1)
|
|
|
|
|
|
|
|
self._pull_stb = RegisterField("pull_stb", reset=0)
|
|
|
|
self._pull_dat = RegisterField("pull_dat", self.width, reset=1,
|
2013-03-21 07:23:44 -04:00
|
|
|
access_bus=READ_ONLY, access_dev=WRITE_ONLY)
|
2013-02-22 08:28:05 -05:00
|
|
|
|
|
|
|
self.regs = [self._rst, self._arm, self._done, self._size, self._offset,
|
2013-03-21 07:23:44 -04:00
|
|
|
self._pull_stb, self._pull_dat]
|
2013-02-22 08:28:05 -05:00
|
|
|
|
|
|
|
# set address / interface
|
|
|
|
self.set_address(address)
|
|
|
|
self.set_interface(interface)
|
|
|
|
|
|
|
|
# trigger Interface
|
|
|
|
self.hit = Signal()
|
|
|
|
self.dat = Signal(self.width)
|
|
|
|
|
|
|
|
def set_address(self, address):
|
|
|
|
self.address = address
|
2013-03-21 07:23:44 -04:00
|
|
|
self.bank = csrgen.Bank(self.regs, address=self.address)
|
2013-02-22 08:28:05 -05:00
|
|
|
|
|
|
|
def set_interface(self, interface):
|
|
|
|
self.interface = interface
|
|
|
|
|
2013-02-27 18:32:42 -05:00
|
|
|
def get_fragment(self):
|
2013-03-21 07:23:44 -04:00
|
|
|
|
|
|
|
_pull_stb_rising = RisingEdge(self._pull_stb.field.r)
|
2013-02-22 08:28:05 -05:00
|
|
|
|
|
|
|
# Bank <--> Storage / Sequencer
|
|
|
|
comb = [
|
2013-03-23 07:26:22 -04:00
|
|
|
self.sequencer.rst.eq(self._rst.field.r),
|
2013-02-22 08:28:05 -05:00
|
|
|
self.storage.rst.eq(self._rst.field.r),
|
|
|
|
|
2013-03-23 07:26:22 -04:00
|
|
|
self.sequencer.arm.eq(self._arm.field.r),
|
|
|
|
self.storage.offset.eq(self._offset.field.r),
|
|
|
|
self.storage.size.eq(self._size.field.r),
|
|
|
|
|
|
|
|
self._done.field.w.eq(~self.sequencer.enable),
|
2013-02-22 08:28:05 -05:00
|
|
|
|
2013-03-21 07:23:44 -04:00
|
|
|
self.storage.pull_stb.eq(_pull_stb_rising.o),
|
2013-02-22 08:28:05 -05:00
|
|
|
self._pull_dat.field.w.eq(self.storage.pull_dat)
|
|
|
|
]
|
|
|
|
|
|
|
|
# Storage <--> Sequencer <--> Trigger
|
|
|
|
comb += [
|
2013-03-23 07:26:22 -04:00
|
|
|
self.storage.start.eq(self.sequencer.start),
|
|
|
|
self.sequencer.done.eq(self.storage.done),
|
2013-02-22 08:28:05 -05:00
|
|
|
self.sequencer.hit.eq(self.hit),
|
|
|
|
|
2013-02-27 18:32:42 -05:00
|
|
|
self.storage.push_stb.eq(self.sequencer.enable),
|
|
|
|
self.storage.push_dat.eq(self.dat)
|
2013-02-22 08:28:05 -05:00
|
|
|
]
|
|
|
|
|
2013-03-21 07:23:44 -04:00
|
|
|
return self.bank.get_fragment() + Fragment(comb) +\
|
|
|
|
self.storage.get_fragment() + self.sequencer.get_fragment() +\
|
|
|
|
_pull_stb_rising.get_fragment()
|
2013-02-22 08:28:05 -05:00
|
|
|
|
|
|
|
#
|
2013-03-22 07:35:12 -04:00
|
|
|
# Driver
|
2013-02-22 08:28:05 -05:00
|
|
|
#
|
|
|
|
def reset(self):
|
2013-03-21 07:23:44 -04:00
|
|
|
self.interface.write(self.bank.get_base() + REC_RST_BASE, 1)
|
|
|
|
self.interface.write(self.bank.get_base() + REC_RST_BASE, 0)
|
2013-02-22 08:28:05 -05:00
|
|
|
|
|
|
|
def arm(self):
|
2013-03-21 07:23:44 -04:00
|
|
|
self.interface.write(self.bank.get_base() + REC_ARM_BASE, 1)
|
|
|
|
self.interface.write(self.bank.get_base() + REC_ARM_BASE, 0)
|
2013-02-22 08:28:05 -05:00
|
|
|
|
|
|
|
def is_done(self):
|
2013-03-21 07:23:44 -04:00
|
|
|
return self.interface.read(self.bank.get_base() + REC_DONE_BASE) == 1
|
2013-02-22 08:28:05 -05:00
|
|
|
|
2013-03-22 07:35:12 -04:00
|
|
|
def set_size(self, dat):
|
2013-03-21 07:23:44 -04:00
|
|
|
self.interface.write_n(self.bank.get_base() + REC_SIZE_BASE, dat, 16)
|
2013-02-22 08:28:05 -05:00
|
|
|
|
2013-03-22 07:35:12 -04:00
|
|
|
def set_offset(self, dat):
|
2013-03-21 07:23:44 -04:00
|
|
|
self.interface.write_n(self.bank.get_base() + REC_OFFSET_BASE, dat, 16)
|
2013-02-22 08:28:05 -05:00
|
|
|
|
2013-03-22 07:35:12 -04:00
|
|
|
def pull(self, size):
|
2013-02-22 08:28:05 -05:00
|
|
|
r = []
|
|
|
|
for i in range(size):
|
2013-03-21 07:23:44 -04:00
|
|
|
self.interface.write(self.bank.get_base() + REC_READ_BASE, 1)
|
|
|
|
self.interface.write(self.bank.get_base() + REC_READ_BASE, 0)
|
|
|
|
r.append(self.interface.read_n(self.bank.get_base() + REC_READ_DATA_BASE, self.width))
|
2013-02-22 08:28:05 -05:00
|
|
|
return r
|