Source code for hwtLib.spi.intf

from collections import deque

from hwt.bitmask import selectBit, mask
from hwt.hdl.constants import DIRECTION
from hwt.interfaces.std import Clk, Signal, VectSignal
from hwt.interfaces.tristate import TristateSig
from hwt.simulator.agentBase import SyncAgentBase, AgentBase
from hwt.simulator.shortcuts import OnFallingCallbackLoop, OnRisingCallbackLoop
from hwt.simulator.types.simBits import simBitsT
from hwt.synthesizer.interface import Interface
from hwt.synthesizer.param import Param


[docs]class SpiAgent(SyncAgentBase): """ Simulation agent for SPI interface :ivar txData: data to transceive container :ivar rxData: received data :ivar chipSelects: values of chip select chipSelects, rxData and txData are lists of integers """ BITS_IN_WORD = 8
[docs] def __init__(self, intf, allowNoReset=False): AgentBase.__init__(self, intf) self.txData = deque() self.rxData = deque() self.chipSelects = deque() self._txBitBuff = deque() self._rxBitBuff = deque() self.csMask = mask(intf.cs._dtype.bit_length()) self.slaveEn = False # resolve clk and rstn self.clk = self.intf._getAssociatedClk()._sigInside self._discoverReset(allowNoReset=allowNoReset) # read on rising edge write on falling self.monitorRx = OnRisingCallbackLoop(self.clk, self.monitorRx, self.getEnable) self.monitorTx = OnFallingCallbackLoop(self.clk, self.monitorTx, self.getEnable) self.driverRx = OnFallingCallbackLoop(self.clk, self.driverRx, self.getEnable) self.driverTx = OnRisingCallbackLoop(self.clk, self.driverTx, self.getEnable)
[docs] def setEnable(self, en): self._enabled = en self.monitorRx.setEnable(en) self.monitorTx.setEnable(en) self.driverRx.setEnable(en) self.driverTx.setEnable(en)
[docs] def splitBits(self, v): return deque([selectBit(v, i) for i in range(self.BITS_IN_WORD - 1, -1, -1)])
[docs] def mergeBits(self, bits): t = simBitsT(self.BITS_IN_WORD, False) val = 0 vldMask = 0 time = -1 for v in bits: val <<= 1 val |= v.val vldMask <<= 1 vldMask |= v.vldMask time = max(time, v.updateTime) return t.getValueCls()(val, t, vldMask, time)
[docs] def readRxSig(self, sim, sig): d = sim.read(sig) bits = self._rxBitBuff bits.append(d) if len(bits) == self.BITS_IN_WORD: self.rxData.append(self.mergeBits(bits)) self._rxBitBuff = []
[docs] def writeTxSig(self, sim, sig): bits = self._txBitBuff if not bits: if not self.txData: return d = self.txData.popleft() bits = self._txBitBuff = self.splitBits(d) sim.write(bits.popleft(), sig)
[docs] def monitorRx(self, sim): yield sim.waitOnCombUpdate() cs = sim.read(self.intf.cs) if self.notReset(sim): assert cs._isFullVld() if cs.val != self.csMask: # if any slave is enabled self.readRxSig(sim, self.intf.mosi) if not self._rxBitBuff: self.chipSelects.append(cs)
[docs] def monitorTx(self, sim): cs = sim.read(self.intf.cs) if self.notReset(sim): assert cs._isFullVld() if cs.val != self.csMask: self.writeTxSig(sim, self.intf.miso)
[docs] def driverRx(self, sim): yield sim.waitOnCombUpdate() if self.notReset(sim) and self.slaveEn: self.readRxSig(sim, self.intf.miso)
[docs] def driverTx(self, s): if self.notReset(s): if not self._txBitBuff: try: cs = self.chipSelects.popleft() except IndexError: self.slaveEn = False s.write(self.csMask, self.intf.cs) return self.slaveEn = True s.write(cs, self.intf.cs) self.writeTxSig(s, self.intf.mosi)
[docs] def getDrivers(self): return [self.driverRx, self.driverTx]
[docs] def getMonitors(self): return [self.monitorRx, self.monitorTx]
# http://www.corelis.com/education/SPI_Tutorial.htm
[docs]class Spi(Interface): """ Bare SPI interface (Serial peripheral interface) """
[docs] def _config(self): self.SLAVE_CNT = Param(1)
[docs] def _declr(self): self.clk = Clk() self.mosi = Signal() # master out slave in self.miso = Signal(masterDir=DIRECTION.IN) # master in slave out self.cs = VectSignal(self.SLAVE_CNT) # chip select self._associatedClk = self.clk
[docs] def _initSimAgent(self): self._ag = SpiAgent(self)
[docs]class SpiTristate(Spi): """ SPI interface where mosi and miso signal are merged into one tristate wire """
[docs] def _config(self): Spi._config(self) self.DATA_WIDTH = Param(1)
[docs] def _declr(self): self.clk = Clk() with self._paramsShared(): self.io = TristateSig() # mosi and miso in one wire self.cs = VectSignal(self.SLAVE_CNT) # chip select self._associatedClk = self.clk
[docs]class QSPI(SpiTristate): """ SPI interface with 4 tristate data wires """
[docs] def _config(self): Spi._config(self) self.DATA_WIDTH = Param(4)