Skip to content

Commit

Permalink
tmp
Browse files Browse the repository at this point in the history
  • Loading branch information
whitequark committed Mar 8, 2024
1 parent 8978b7e commit 1c9015d
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 37 deletions.
46 changes: 25 additions & 21 deletions software/glasgow/gateware/hyperram.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,6 @@ class PHYx1(wiring.Component):
All of the inputs and outputs are registered, with one cycle of latency.
"""

gearing = 1

def __init__(self, resource, *, cs_count=1):
if not isinstance(cs_count, int) or not cs_count >= 1:
raise ValueError(f"CS# count must be a positive integer, not {cs_count!r}")
Expand Down Expand Up @@ -174,20 +172,16 @@ def elaborate(self, platform):
pins_cs_n.o.eq(~Cat(self.select == n for n in range(1, self.cs_count + 1))),
pins_rwds.oe.eq(self.rwds.oe),
pins_rwds.o.eq(self.rwds.o[1]),
self.rwds.i.eq(Cat(reg_rwds_i0, reg_rwds_i1)),
self.rwds.i.eq(Cat(reg_rwds_i0, pins_rwds.i)),
pins_dq.oe.eq(self.data.oe),
pins_dq.o.eq(self.data.o[8:]),
self.data.i.eq(Cat(reg_dq_i0, reg_dq_i1)),
self.data.i.eq(Cat(reg_dq_i0, pins_dq.i)),
]
m.d.sync += [
reg_rwds_oe.eq(self.rwds.oe),
reg_rwds_o.eq(self.rwds.o[0]),
reg_dq_oe.eq(self.data.oe),
reg_dq_o.eq(self.data.o[:8]),
reg_rwds_i0.eq(pins_rwds.i),
reg_rwds_i1.eq(reg_rwds_i0),
reg_dq_i0.eq(pins_dq.i),
reg_dq_i1.eq(reg_dq_i0),
]
m.d.comb += [
self.ready.eq(1),
Expand All @@ -198,6 +192,10 @@ def elaborate(self, platform):
pins_cs_n.en.eq(1),
]
with m.If(self.valid):
m.d.sync += [
reg_rwds_i1.eq(pins_rwds.i),
reg_dq_i1.eq(pins_dq.i),
]
m.d.comb += [
pins_rwds.en.eq(1),
pins_dq.en.eq(1),
Expand All @@ -207,13 +205,6 @@ def elaborate(self, platform):
pins.ck_n.o1.eq(0),
]
m.next = "Falling"
with m.Else():
m.d.comb += [
pins.ck_p.o0.eq(0),
pins.ck_p.o1.eq(0),
pins.ck_n.o0.eq(1),
pins.ck_n.o1.eq(1),
]

with m.State("Falling"):
m.d.comb += [
Expand All @@ -224,15 +215,13 @@ def elaborate(self, platform):
pins_dq.o.eq(reg_dq_o),
self.data.i.eq(Cat(reg_dq_i0, reg_dq_i1)),
]
# The HyperBus specification forbids pausing or stopping the clock in the non-idle
# state, so after the rising edge is generated, this state machine unconditionally
# falls through to generating the falling edge.
m.d.sync += [
reg_rwds_i0.eq(pins_rwds.i),
reg_rwds_i1.eq(reg_rwds_i0),
reg_dq_i0.eq(pins_dq.i),
reg_dq_i1.eq(reg_dq_i0),
]
# The HyperBus specification forbids pausing or stopping the clock in the non-idle
# state, so after the rising edge is generated, this state machine unconditionally
# falls through to generating the falling edge.
m.d.comb += [
pins_rwds.en.eq(1),
pins_dq.en.eq(1),
Expand Down Expand Up @@ -409,13 +398,28 @@ def elaborate(self, platform):
with m.If(cycle == 3):
m.next = "Read"

# with m.State("Read1"):
# m.d.comb += [
# phy.valid.eq(1),
# phy.select.eq(select),
# ]
# with m.If(phy.ready & (phy.rwds.i == Cat(0, 1))):
# m.next = "Read"

with m.State("Read"):
m.d.comb += [
phy.valid.eq(self.read.ready),
phy.select.eq(select),
self.read.payload.data.eq(phy.data.i),
self.read.valid.eq(phy.ready & (phy.rwds.i == Cat(0, 1))), # im snbity :|3
self.read.valid.eq(phy.ready),
]
# with m.If(phy.ready & (phy.rwds.i != Cat(0, 1))): # im snbity :|3
# # 'Prime' the memory by clocking it until it outputs the next data word
# # whenever it responds with a latency cycle.
# m.d.comb += [
# phy.valid.eq(1),
# self.read.valid.eq(0),
# ]
with m.If(self.control.valid):
m.next = "Idle"

Expand Down
87 changes: 71 additions & 16 deletions software/tests/gateware/test_hyperram.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ class HyperRAMSequencerTestbench(wiring.Component):
# - target? (sometimes it's source)
# - ?

def __init__(self, *, out_fifo, in_fifo):
def __init__(self, *, out_fifo, in_fifo, ila_fifo):
self.out_fifo = out_fifo
self.in_fifo = in_fifo
self.ila_fifo = ila_fifo

super().__init__()

Expand All @@ -29,7 +30,7 @@ def elaborate(self, platform):

m = Module()

m.submodules.phy = phy = hyperram.PHYx1(resource=("hyperram", 0))
m.submodules.phy = Fragment.get(phy := hyperram.PHYx1(resource=("hyperram", 0)), platform)
m.submodules.seq = seq = hyperram.Sequencer(phy)

trigger_r = Signal.like(self.trigger)
Expand All @@ -40,8 +41,9 @@ def elaborate(self, platform):
Cat(seq.control.payload.cmd_addr.address_low,
seq.control.payload.cmd_addr.address_high).eq(self.first),
seq.control.payload.cmd_addr.burst_type.eq(hyperram.BurstType.Linear),
seq.control.payload.cmd_addr.address_space.eq(hyperram.AddressSpace.Register),
seq.control.payload.cmd_addr.address_space.eq(hyperram.AddressSpace.Memory),
seq.control.payload.cmd_addr.operation.eq(self.mode),
# seq.control.payload.cmd_addr.eq(0x800000000001),
seq.control.payload.latency.eq(7), # FIXME: configurable?
seq.control.valid.eq(~trigger_r & self.trigger),
]
Expand All @@ -55,7 +57,7 @@ def elaborate(self, platform):
m.d.comb += [
self.out_fifo.r_en.eq(1),
]
with m.If(self.out_fifo.r_rdy):
with m.If(self.out_fifo.r_rdy & self.out_fifo.r_en):
m.next = "LSB"

with m.State("LSB"):
Expand All @@ -65,16 +67,17 @@ def elaborate(self, platform):
seq.write.valid.eq(self.out_fifo.r_rdy),
self.out_fifo.r_en.eq(seq.write.ready),
]
with m.If(self.out_fifo.r_rdy):
with m.If(self.out_fifo.r_rdy & self.out_fifo.r_en):
m.next = "MSB"

with m.FSM(name="read_fsm"):
with m.State("MSB"):
m.d.comb += [
self.in_fifo.w_data.eq(seq.read.payload.data[8:]),
self.in_fifo.w_en.eq(seq.read.valid),
seq.read.ready.eq(0),
]
with m.If(seq.read.valid & self.in_fifo.w_rdy):
with m.If(self.in_fifo.w_rdy & self.in_fifo.w_en):
m.next = "LSB"

# moth m.State("LSB"): # moth state bc transient
Expand All @@ -84,9 +87,47 @@ def elaborate(self, platform):
self.in_fifo.w_en.eq(1),
seq.read.ready.eq(self.in_fifo.w_rdy),
]
with m.If(self.in_fifo.w_rdy):
with m.If(self.in_fifo.w_rdy & self.in_fifo.w_en):
m.next = "MSB"

m.submodules.ila_mem = ila_mem = fifo.SyncFIFOBuffered(depth=256, width=16)

with m.FSM() as ila_upload_fsm:
with m.State("MSB"):
m.d.comb += [
self.ila_fifo.w_data.eq(ila_mem.r_data[8:]),
self.ila_fifo.w_en.eq(ila_mem.r_rdy),
ila_mem.r_en.eq(0),
]
with m.If(self.ila_fifo.w_rdy & self.ila_fifo.w_en):
m.next = "LSB"

with m.State("LSB"):
m.d.comb += [
self.ila_fifo.w_data.eq(ila_mem.r_data[:8]),
self.ila_fifo.w_en.eq(1),
ila_mem.r_en.eq(self.ila_fifo.w_rdy),
]
with m.If(self.ila_fifo.w_rdy & self.ila_fifo.w_en):
m.next = "MSB"

with m.FSM() as ila_sample_fsm:
with m.State("Idle"):
with m.If(self.trigger):
m.next = "Sampling"
with m.State("Sampling"):
with m.If(~ila_mem.w_rdy):
m.next = "Done"
with m.State("Done"):
pass

m.d.comb += [
# ila_mem.w_data.eq(Cat(phy.pins_dq.i, phy.pins_rwds.i, phy.pins_cs_n.i)),
# ila_mem.w_data.eq(seq.read.payload),
ila_mem.w_data.eq(Cat(phy.data.i[:12], 0, 0, 0, phy.ready)),
ila_mem.w_en.eq(ila_sample_fsm.ongoing("Sampling")),
]

return m


Expand All @@ -105,38 +146,52 @@ async def main():
target.add_submodule(testbench := ResetInserter(reset)(
HyperRAMSequencerTestbench(
out_fifo=target.fx2_crossbar.get_out_fifo(0, reset=reset),
in_fifo=target.fx2_crossbar.get_in_fifo(0, reset=reset, auto_flush=True))))
in_fifo=target.fx2_crossbar.get_in_fifo(0, reset=reset, auto_flush=False),
ila_fifo=target.fx2_crossbar.get_in_fifo(1, reset=reset, auto_flush=False))))
mode_addr = target.registers.add_existing_rw(testbench.mode)
first_addr = target.registers.add_existing_rw(testbench.first)
count_addr = target.registers.add_existing_rw(testbench.count)
trigger_addr = target.registers.add_existing_rw(testbench.trigger)
await device.download_target(target.build_plan())

print("Running...")
device.usb_handle.setConfiguration(1)
device.usb_handle.claimInterface(0)
device.usb_handle.claimInterface(1)
device.usb_handle.setInterfaceAltSetting(0, 1)
device.usb_handle.setInterfaceAltSetting(1, 1)

async def download_ila():
for index, (word,) in enumerate(struct.iter_unpack(">H", await device.bulk_read(0x88, 512))):
print(f"{word>>8:02x}.{word&0xff:02x}", end="\n" if index % 16 == 15 else " ")

async def prepare(mode, first, count):
# reset testbench and clear FIFOs
await device.write_register(reset_addr, 1)
await device.write_register(trigger_addr, 0)
device.usb_handle.setInterfaceAltSetting(0, 1)
device.usb_handle.setInterfaceAltSetting(1, 1)
await device.write_register(reset_addr, 0)

await device.write_register(mode_addr, mode)
await device.write_register(first_addr, first)
await device.write_register(count_addr, count)
await device.write_register(trigger_addr, 0)
await device.write_register(trigger_addr, 1)
await device.write_register(mode_addr, mode.value)
await device.write_register(first_addr, first, width=3)
await device.write_register(count_addr, count, width=3)

async def read(first, count):
await prepare(hyperram.Operation.Read, first, count)
return list(struct.iter_unpack(">H", await device.bulk_read(0x86, count * 2)))
await device.write_register(trigger_addr, 1)
await download_ila()
data = await device.bulk_read(0x86, 512)
return [n for (n,) in struct.iter_unpack(">H", data[:count * 2])]

async def write(first, data):
await prepare(hyperram.Operation.Write, first, len(data))
await device.bulk_write(0x82, b"".join(struct.pack(">H", n) for n in data)) # lolficiency
await device.bulk_write(0x02, b"".join(struct.pack(">H", n) for n in data)) # lolficiency
await device.write_register(trigger_addr, 1)
await download_ila()

print(await read(0, 8))
await write(0, list(range(0x5510, 0x5520)))
print(await read(0, 16))


# class HyperRAMHardwareTestbench(Elaboratable):
Expand Down

0 comments on commit 1c9015d

Please sign in to comment.