Skip to content

Commit

Permalink
wip: actually working now i swear
Browse files Browse the repository at this point in the history
  • Loading branch information
whitequark committed Mar 27, 2024
1 parent 9af6fcc commit 635ae2b
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 41 deletions.
56 changes: 34 additions & 22 deletions software/glasgow/gateware/hyperram.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,12 @@ def p(self):


class _IOBufferWithEn(wiring.Component):
def __init__(self, pins):
def __init__(self, pins, *, pin_type=C(0b1101_00, 6)):
self.pins = pins
self.pin_type = pin_type

super().__init__(Signature({
"en" : In(1, reset=1), # clock enable (for both input and output)
"en" : In(1), # clock enable (for both input and output)
"oe" : In(1), # output enable
"o" : Out(len(self.pins)), # output
"i" : In(len(self.pins)), # input
Expand All @@ -48,7 +49,7 @@ def elaborate(self, platform):
m = Module()
for index, pin in enumerate(self.pins):
m.submodules += Instance("SB_IO",
p_PIN_TYPE=C(0b1101_00, 6),
p_PIN_TYPE=self.pin_type,
i_INPUT_CLK=ClockSignal(),
i_OUTPUT_CLK=ClockSignal(),
i_CLOCK_ENABLE=self.en,
Expand Down Expand Up @@ -126,12 +127,23 @@ def elaborate(self, platform):
# the positive polarity may be used), driven as source synchronous DDR output. This clock
# idles low and toggles whenever the FSM transitions, at 90° phase offset referenced to
# DQ[7:0]. The I/O buffer is configured as DDR to introduce the phase offset.
m.d.comb += pins.ck_p.o_clk.eq(ClockSignal())
m.d.comb += pins.ck_n.o_clk.eq(ClockSignal())

# CS#[`cs_count`-1:0] are a set of output pins.
m.submodules.pins_cs_n = pins_cs_n = self.pins_cs_n = _IOBufferWithEn(pins.cs)
m.d.comb += pins_cs_n.oe.eq(1)
m.d.comb += [
pins.ck_p.o_clk.eq(ClockSignal()),
pins.ck_n.o_clk.eq(ClockSignal()),
]

# CS#[`cs_count`-1:0] are a set of output pins. They use the same type of IO buffer because
# iCE40 has packing constraints on clock enables in adjacent SB_IO cells (same diffpair).
# For the same reason the enable of CS# must be tied to that of RWDS, which requires this
# awkward bit of logic to add a register not tied to RWDS enable.
m.submodules.pins_cs_n = pins_cs_n = self.pins_cs_n = \
_IOBufferWithEn(pins.cs, pin_type=C(0b0110_01, 6)) # Cat(PIN_INPUT, PIN_OUTPUT)
pins_cs_o_n_reg = Signal.like(pins_cs_n.o, reset=~0)
pins_cs_o = Signal.like(pins_cs_n.o)
pins_cs_o_en = Signal()
m.d.comb += pins_cs_n.o.eq(pins_cs_o_n_reg)
with m.If(pins_cs_o_en):
m.d.sync += pins_cs_o_n_reg.eq(~pins_cs_o)

# RWDS is an input/output pin. It has three distinct functions:
# - During command/address phase, RWDS is a memory output and FPGA input indicating whether
Expand All @@ -144,6 +156,7 @@ def elaborate(self, platform):
# with data output by the memory, indicating a pause in data transfer when the address
# crosses page boundaries.
m.submodules.pins_rwds = pins_rwds = self.pins_rwds = _IOBufferWithEn(pins.rwds)
m.d.comb += pins_cs_n.en.eq(pins_rwds.en) # oh, iCE40...
pins_rwds_i_regl = Signal.like(pins_rwds.i)
pins_rwds_i_regh = Signal.like(pins_rwds.i)

Expand All @@ -168,18 +181,19 @@ def elaborate(self, platform):
]

with m.State("Select/Deselect"):
m.d.comb += [
pins_cs_o_en.eq(1),
# Release DQ and RWDS if the last operation was a write.
pins_dq.oe.eq(0),
pins_dq.en.eq(1),
pins_rwds.oe.eq(0),
pins_rwds.en.eq(1),
]
m.d.sync += clocked.eq(0)
with m.If(self.o.valid & (self.o.p.mode == PHYMode.Select)):
m.d.comb += self.o.ready.eq(1)
cs_decoded = Cat(self.o.p.data == n for n in range(1, self.cs_count + 1))
m.d.comb += [
pins_cs_n.o.eq(~cs_decoded),
pins_cs_n.en.eq(1),
pins_dq.oe.eq(0),
pins_dq.en.eq(1),
pins_rwds.oe.eq(0),
pins_rwds.en.eq(1),
self.o.ready.eq(1),
]
m.d.comb += pins_cs_o.eq(cs_decoded)
with m.If(cs_decoded != 0):
m.next = "Sample-Latency"

Expand Down Expand Up @@ -426,8 +440,7 @@ def elaborate(self, platform):
phy.o.valid.eq(1),
self.write.ready.eq(phy.o.ready),
]
# with m.If(self.control.valid):
with m.If(self.write.valid & self.write.ready):
with m.If(self.control.valid):
m.next = "Deselect"

with m.State("Latency-Read"):
Expand All @@ -452,8 +465,7 @@ def elaborate(self, platform):
phy.o.valid.eq(1),
]
wiring.connect(m, wiring.flipped(self.read), phy.i)
# with m.If(self.control.valid):
with m.If(self.read.valid & self.read.ready):
with m.If(self.control.valid):
m.next = "Deselect"

with m.State("Deselect"):
Expand Down
46 changes: 27 additions & 19 deletions software/tests/gateware/test_hyperram.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ def elaborate(self, platform):
seq.control.payload.cmd_addr.burst_type.eq(hyperram.BurstType.Linear),
seq.control.payload.cmd_addr.address_space.eq(self.space),
seq.control.payload.cmd_addr.operation.eq(self.mode),
# seq.control.payload.cmd_addr.eq(0x800000000001),
seq.control.payload.latency.eq(self.latency),
]

Expand Down Expand Up @@ -267,24 +266,33 @@ async def write_mem(start, data, *, latency):
await read_reg(0x000000) # ID0 == 0c86
await read_reg(0x000001) # ID1 == 0001

await read_reg(0x000800) # CR0 == 8f2f
await write_reg(0x000800, 0x8f1f)
await read_reg(0x000800)
await write_reg(0x400800, 0x8f1f)
await read_reg(0x400800)

await read_reg(0x000801) # CR1 == ffc1

await read_mem(0x00000000, 1)
await read_mem(0x00000001, 1)
await write_mem(0x00000000, [0xaabb], latency=6)
await write_mem(0x00000001, [0xccdd], latency=6)
await read_mem(0x00000000, 1)
await read_mem(0x00000001, 1)
await write_mem(0x00000000, [0], latency=6)
await write_mem(0x00000001, [0], latency=6)
await read_mem(0x00000000, 1)
await read_mem(0x00000001, 1)
await write_mem(0x00000000, [0x0000, 0x0000, 0x0000], latency=7)
await read_mem( 0x00000000, 1)
await read_mem( 0x00000001, 1)
await read_mem( 0x00000002, 1)
await write_mem(0x00000000, [0x1234, 0x5678, 0xabcd], latency=7)
await read_mem( 0x00000000, 1)
await read_mem( 0x00000001, 1)
await read_mem( 0x00000002, 1)

# await read_reg(0x000800) # CR0 == 8f2f
# await write_reg(0x000800, 0x8f1f)
# await read_reg(0x000800)
# await write_reg(0x400800, 0x8f1f)
# await read_reg(0x400800)

# await read_reg(0x000801) # CR1 == ffc1

# await read_mem(0x00000000, 1)
# await read_mem(0x00000001, 1)
# await write_mem(0x00000000, [0xaabb], latency=6)
# await write_mem(0x00000001, [0xccdd], latency=6)
# await read_mem(0x00000000, 1)
# await read_mem(0x00000001, 1)
# await write_mem(0x00000000, [0], latency=6)
# await write_mem(0x00000001, [0], latency=6)
# await read_mem(0x00000000, 1)
# await read_mem(0x00000001, 1)

# await read_reg(0x400000) # ID0 == 0c86
# await read_reg(0x400001) # ID1 == 0001
Expand Down

0 comments on commit 635ae2b

Please sign in to comment.