Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: GlasgowEmbedded/glasgow
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 2f1743a4fe73
Choose a base ref
...
head repository: GlasgowEmbedded/glasgow
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: e5f9ea99d233
Choose a head ref
  • 3 commits
  • 4 files changed
  • 1 contributor

Commits on Mar 18, 2019

  1. Copy the full SHA
    b906631 View commit details
  2. applet.interface.spi_master: use ClockGen.

    This makes clear the limitations of the current SERDES engine (i.e.
    that the maximum clock rate is 1/4 of applet clock) and handles edge
    conditions reliably. It could also enable higher rates in the future.
    whitequark committed Mar 18, 2019
    Copy the full SHA
    cf47a3a View commit details
  3. firmware: use PF instead of EF/FF and INFM1/OEP1. "NFCI."

    This allows us greater freedom in changing the latency of the FX2
    arbiter for IN and OUT transfers alike.
    
    This is a fairly significant change that could lead to corruption of
    data in transit and hangs, but it seems OK based on testing with
    the following applets:
      * benchmark
      * memory-25x
      * video-rgb-input
    
    Also, gruetzkopf has verified this according to documentation and
    silicon behavior and it also appears fully equivalent.
    whitequark committed Mar 18, 2019
    Copy the full SHA
    e5f9ea9 View commit details
Showing with 65 additions and 37 deletions.
  1. +36 −14 firmware/fifo.c
  2. +1 −1 software/glasgow/applet/__init__.py
  3. +27 −21 software/glasgow/applet/interface/spi_master/__init__.py
  4. +1 −1 software/glasgow/gateware/clockgen.py
50 changes: 36 additions & 14 deletions firmware/fifo.c
Original file line number Diff line number Diff line change
@@ -16,15 +16,16 @@ void fifo_init() {

// Configure strobes and flags.
// All flags are configured as RDY; this means ~EF for OUT endpoints
// and ~FF for for IN endpoints.
// and ~FF for for IN endpoints. The actual flag is set as ~PF to allow
// for more flexibility in exact timings.
// SLRD and SLWR *must* be configured as active low; otherwise, glitches
// on these lines during reset cause spurious data in FIFOs.
SYNCDELAY;
FIFOPINPOLAR = 0;
SYNCDELAY;
PINFLAGSAB = 0b10011000; // FLAGA = EP2 ~EF, FLAGB = EP4 ~EF
PINFLAGSAB = 0b01010100; // FLAGA = EP2 ~PF, FLAGB = EP4 ~PF
SYNCDELAY;
PINFLAGSCD = 0b11111110; // FLAGC = EP6 ~FF, FLAGD = EP8 ~FF
PINFLAGSCD = 0b01110110; // FLAGC = EP6 ~PF, FLAGD = EP8 ~PF
SYNCDELAY;
PORTACFG |= _FLAGD; // PA7 is FLAGD

@@ -39,14 +40,19 @@ void fifo_init() {
EP8FIFOCFG &= ~_WORDWIDE;
}

#define OUT_THRESHOLD 1U
#define IN_THRESHOLD 510U

void fifo_configure(bool two_ep) {
uint8_t ep26buf, ep48valid;
uint8_t ep26buf, ep48valid, ep26pkts;
if(two_ep) {
ep26buf = 0; // quad buffered
ep48valid = 0; // invalid
ep26buf = 0; // quad buffered
ep48valid = 0; // invalid
ep26pkts = 0b011000; // 512B ×3
} else {
ep26buf = _BUF1; // double buffered
ep48valid = _VALID; // valid
ep26buf = _BUF1; // double buffered
ep48valid = _VALID; // valid
ep26pkts = 0b001000; // 512B ×1
}

// Disable all FIFOs.
@@ -56,26 +62,42 @@ void fifo_configure(bool two_ep) {
// Configure EP2.
SYNCDELAY;
EP2CFG = _VALID|_TYPE1|ep26buf; // OUT BULK 512B
SYNCDELAY;
EP2FIFOPFH = _DECIS|(OUT_THRESHOLD >> 8);
SYNCDELAY;
EP2FIFOPFL = OUT_THRESHOLD & 0xff;

// Configure EP4.
SYNCDELAY;
EP4CFG = ep48valid|_TYPE1; // OUT BULK 512B
SYNCDELAY;
EP4FIFOPFH = _DECIS|(OUT_THRESHOLD >> 8);
SYNCDELAY;
EP4FIFOPFL = OUT_THRESHOLD & 0xff;

// Configure EP6.
SYNCDELAY;
EP6CFG = _VALID|_DIR|_TYPE1|ep26buf; // IN BULK 512B
EP6CFG = _VALID|_DIR|_TYPE1|ep26buf; // IN BULK 512B ×2/×4
SYNCDELAY;
EP6AUTOINLENH = 512 >> 8;
SYNCDELAY;
EP6AUTOINLENL = 0;
EP6AUTOINLENL = 512 & 0xff;
SYNCDELAY;
EP6FIFOPFH = ep26pkts|(IN_THRESHOLD >> 8);
SYNCDELAY;
EP6FIFOPFL = IN_THRESHOLD & 0xff;

// Configure EP8.
SYNCDELAY;
EP8CFG = ep48valid|_DIR|_TYPE1; // IN BULK 512B
EP8CFG = ep48valid|_DIR|_TYPE1; // IN BULK 512B ×2
SYNCDELAY;
EP8AUTOINLENH = 512 >> 8;
SYNCDELAY;
EP8AUTOINLENL = 0;
EP8AUTOINLENL = 512 & 0xff;
SYNCDELAY;
EP8FIFOPFH = 0b001000|(IN_THRESHOLD >> 8);
SYNCDELAY;
EP8FIFOPFL = IN_THRESHOLD & 0xff;

// Reset and configure endpoints.
fifo_reset(two_ep, two_ep ? 0x1 : 0x3);
@@ -114,7 +136,7 @@ void fifo_reset(bool two_ep, uint8_t interfaces) {
SYNCDELAY;
FIFORESET |= 6;
SYNCDELAY;
EP6FIFOCFG = _AUTOIN|_ZEROLENIN|_INFM1;
EP6FIFOCFG = _AUTOIN|_ZEROLENIN;
}

if(interfaces & (1 << 1)) {
@@ -136,6 +158,6 @@ void fifo_reset(bool two_ep, uint8_t interfaces) {
SYNCDELAY;
FIFORESET |= 8;
SYNCDELAY;
EP8FIFOCFG = _AUTOIN|_ZEROLENIN|_INFM1;
EP8FIFOCFG = _AUTOIN|_ZEROLENIN;
}
}
2 changes: 1 addition & 1 deletion software/glasgow/applet/__init__.py
Original file line number Diff line number Diff line change
@@ -34,7 +34,7 @@ def add_build_arguments(cls, parser, access):

def derive_clock(self, *args, clock_name=None, **kwargs):
try:
return ClockGen.derive(*args, **kwargs, logger=self.logger, clock_name=None)
return ClockGen.derive(*args, **kwargs, logger=self.logger, clock_name=clock_name)
except ValueError as e:
if clock_name is None:
raise GlasgowAppletError(e)
48 changes: 27 additions & 21 deletions software/glasgow/applet/interface/spi_master/__init__.py
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@
from migen import *
from migen.genlib.cdc import *

from ....gateware.clockgen import *
from ... import *


@@ -69,16 +70,14 @@ def __init__(self, pads, out_fifo, in_fifo, period_cyc, delay_cyc,

###

half_cyc = period_cyc // 2
timer = Signal(max=max(half_cyc, delay_cyc))
self.submodules.clkgen = ResetInserter()(ClockGen(period_cyc))

cmd = Signal(8)
count = Signal(16)
bitno = Signal(max=8, reset=7)
oreg = Signal(8)
ireg = Signal(8)

self.comb += self.bus.mosi.eq(oreg[oreg.nbits - 1])
self.comb += [
self.bus.sck.eq(self.clkgen.clk),
self.bus.mosi.eq(oreg[oreg.nbits - 1]),
]
self.sync += [
If(self.bus.setup,
oreg[1:].eq(oreg)
@@ -87,6 +86,11 @@ def __init__(self, pads, out_fifo, in_fifo, period_cyc, delay_cyc,
)
]

cmd = Signal(8)
count = Signal(16)
bitno = Signal(max=8 + 1)
timer = Signal(max=delay_cyc)

self.submodules.fsm = FSM(reset_state="RECV-COMMAND")
self.fsm.act("RECV-COMMAND",
in_fifo.flush.eq(1),
@@ -138,22 +142,17 @@ def __init__(self, pads, out_fifo, in_fifo, period_cyc, delay_cyc,
),
If((cmd[:4] == CMD_READ) | out_fifo.readable,
NextValue(count, count - 1),
NextValue(timer, half_cyc - 1),
NextValue(bitno, 8),
NextState("TRANSFER")
)
)
self.comb += self.clkgen.reset.eq(~self.fsm.ongoing("TRANSFER")),
self.fsm.act("TRANSFER",
If(timer == 0,
NextValue(timer, half_cyc - 1),
NextValue(self.bus.sck, ~self.bus.sck),
If((self.bus.sck == (not sck_idle)),
NextValue(bitno, bitno - 1),
If(bitno == 0,
NextState("SEND-DATA")
)
)
).Else(
NextValue(timer, timer - 1)
If(self.clkgen.stb_f,
If(bitno == 0,
NextState("SEND-DATA")
),
NextValue(bitno, bitno - 1)
)
)
self.fsm.act("SEND-DATA",
@@ -311,8 +310,15 @@ def build(self, target, args, pins=__pins):
pads=iface.get_pads(args, pins=pins),
out_fifo=iface.get_out_fifo(),
in_fifo=iface.get_in_fifo(auto_flush=False),
period_cyc=math.ceil(target.sys_clk_freq / (args.bit_rate * 1000)),
delay_cyc=math.ceil(target.sys_clk_freq / 1e6),
period_cyc=self.derive_clock(input_hz=target.sys_clk_freq,
output_hz=args.bit_rate * 1000,
clock_name="master",
# 2 cyc MultiReg delay from SCK to MISO requires a 4 cyc
# period with current implementation of SERDES
min_cyc=4),
delay_cyc=self.derive_clock(input_hz=target.sys_clk_freq,
output_hz=1e6,
clock_name="delay"),
sck_idle=args.sck_idle,
sck_edge=args.sck_edge,
ss_active=args.ss_active,
2 changes: 1 addition & 1 deletion software/glasgow/gateware/clockgen.py
Original file line number Diff line number Diff line change
@@ -141,7 +141,7 @@ def derive(cls, input_hz, output_hz, max_deviation_ppm=None, min_cyc=None,
if clock_name is None:
clock = "clock"
else:
clock = "clock {}".format(clock)
clock = "clock {}".format(clock_name)
if cyc in (0, 1):
duty = 50
else: