Source code for gateware.comm

# Copyright 2013-2015 Robert Jordens <jordens@gmail.com>
#
# This file is part of pdq2.
#
# pdq2 is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pdq2 is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with pdq2.  If not, see <http://www.gnu.org/licenses/>.

from migen.fhdl.std import *
from migen.flow.actor import Sink
from migen.actorlib.structuring import Cast, Pack, pack_layout
from migen.genlib.fsm import FSM, NextState
from migen.genlib.cdc import MultiReg

from .escape import Unescaper
from .ft245r import bus_layout


mem_layout = [("data", 16)]


[docs]class MemWriter(Module): """Handles the memory write protocol and writes data to the channel memories. Args: board (Value): Address of this board. dacs (list): List of :mod:`gateware.dac.Dac`. Attributes: sink (Sink[mem_layout]): 16 bit data sink. """ def __init__(self, board, dacs): self.sink = Sink(mem_layout) ### mems = [dac.parser.mem.get_port(write_capable=True) for dac in dacs] self.specials += mems dac = Signal(max=len(dacs)) adr = Signal(16) end = Signal(16) listen = Signal() we = Signal() inc = Signal() pd = self.sink.payload.data self.sink.ack.reset = 1 self.comb += Array(m.we for m in mems)[dac].eq(we) for mem in mems: self.comb += [ mem.adr.eq(adr), mem.dat_w.eq(pd) ] self.submodules.fsm = fsm = FSM(reset_state="DEV") fsm.act("DEV", If(self.sink.stb, NextState("START") ) ) fsm.act("START", If(self.sink.stb, NextState("END") ) ) fsm.act("END", If(self.sink.stb, NextState("DATA") ) ) fsm.act("DATA", If(self.sink.stb, we.eq(listen), inc.eq(1), If(adr == end, NextState("DEV") ) ) ) self.sync += [ If(fsm.ongoing("DEV"), dac.eq(pd[:4]), listen.eq(pd[4:4+flen(board)] == board), ), If(fsm.ongoing("START"), adr.eq(pd) ), If(fsm.ongoing("END"), end.eq(pd) ), If(fsm.ongoing("DATA"), If(inc, adr.eq(adr + 1) ) ) ]
[docs]class ResetGen(Module): """Reset generator. Asserts :attr:`reset` for a given number of cycles when triggered. Args: n (int): number of cycles. Attributes: trigger (Signal): Trigger input. reset (Signal): Reset output. Active high. """ def __init__(self, n=1<<7): self.trigger = Signal() self.reset = Signal() ### self.clock_domains.cd_no_rst = ClockDomain(reset_less=True) counter = Signal(max=n) self.comb += [ self.cd_no_rst.clk.eq(ClockSignal()), self.reset.eq(counter != n - 1) ] self.sync.no_rst += [ If(self.trigger, counter.eq(0) ).Elif(self.reset, counter.eq(counter + 1) ), ]
[docs]class Ctrl(Module): """Control command handler. Controls the input and output TTL signals, handled the excaped control commands. Args: pads (Record): Pads containing the TTL input and output control signals dacs (list): List of :mod:`gateware.dac.Dac`. Attributes: reset (Signal): Reset output from :class:`ResetGen`. Active high. dcm_sel (Signal): DCM slock select. Enable clock doubler. Output. sink (Sink[bus_layout]): 8 bit control data sink. Input. """ def __init__(self, pads, dacs): self.reset = Signal() self.dcm_sel = Signal() self.sink = Sink(bus_layout) ### self.sink.ack.reset = 1 self.submodules.rg = ResetGen() # two stage synchronizer for inputs frame = Signal.like(pads.frame) trigger = Signal() arm = Signal() start = Signal() soft_trigger = Signal() self.specials += MultiReg(pads.trigger, trigger) self.sync += [ frame.eq(pads.frame), pads.aux.eq(Cat(*(dac.out.aux for dac in dacs)) != 0), #pads.go2_out.eq( # Cat(*(dac.out.sink.stb for dac in dacs)) != 0), #pads.go2_out.eq(pads.go2_in), # loop #pads.go2_out.eq(0), ] self.comb += [ self.reset.eq(self.rg.reset), pads.reset.eq(ResetSignal()), ] for dac in dacs: self.sync += [ dac.parser.frame.eq(frame), dac.out.trigger.eq(arm & (trigger | soft_trigger)), dac.out.arm.eq(arm), dac.parser.arm.eq(arm), dac.parser.start.eq(start), ] self.sync += [ If(self.sink.stb, Case(self.sink.payload.data, { 0x00: self.rg.trigger.eq(1), #0x01: self.rg.trigger.eq(0), 0x02: soft_trigger.eq(1), 0x03: soft_trigger.eq(0), 0x04: arm.eq(1), 0x05: arm.eq(0), 0x06: self.dcm_sel.eq(1), 0x07: self.dcm_sel.eq(0), 0x08: start.eq(1), 0x09: start.eq(0), }) ) ]
[docs]class Comm(Module): """USB Protocol handler. Args: ctrl_pads (Record): Control signal pads. dacs (list): List of :mod:`gateware.dac.Dac`. Attributes: sink (Sink[bus_layout]): 8 bit data sink containing both the control sequencences and the data stream. """ def __init__(self, ctrl_pads, dacs): self.submodules.unescaper = Unescaper(bus_layout, 0xa5) self.sink = self.unescaper.sink self.submodules.pack = Pack(bus_layout, 2) self.submodules.cast = Cast(pack_layout(bus_layout, 2), mem_layout) self.submodules.memwriter = MemWriter(~ctrl_pads.adr, dacs) # adr active low self.submodules.ctrl = Ctrl(ctrl_pads, dacs) ### self.comb += [ self.pack.sink.connect(self.unescaper.source_a), self.cast.sink.connect(self.pack.source), self.memwriter.sink.connect(self.cast.source), self.ctrl.sink.connect(self.unescaper.source_b), ]