Skip to content

Instantly share code, notes, and snippets.

@enjoy-digital
Last active July 22, 2021 20:28
Show Gist options
  • Save enjoy-digital/529a4d9994f0cc95e45382e4eb253b09 to your computer and use it in GitHub Desktop.
Save enjoy-digital/529a4d9994f0cc95e45382e4eb253b09 to your computer and use it in GitHub Desktop.
DRAM initialization through Wishbone FSM.
#!/usr/bin/env python3
from migen import *
from wb_master import *
from wb_master import _WRITE_CMD, _WAIT_CMD, _DONE_CMD
dfii_control_sel = 0x01
dfii_control_cke = 0x02
dfii_control_odt = 0x04
dfii_control_reset_n = 0x08
dfii_command_cs = 0x01
dfii_command_we = 0x02
dfii_command_cas = 0x04
dfii_command_ras = 0x08
dfii_command_wrdata = 0x10
dfii_command_rddata = 0x20
# /!\ keep up to date with csr /!\
sdram_dfii_control = 0xe0004000
sdram_dfii_pi0_address = 0xe000400c
sdram_dfii_pi0_baddress = 0xe0004010
sdram_dfii_pi0_command = 0xe0004004
sdram_dfii_pi0_command_issue = 0xe0004008
ddrphy_dly_sel = 0xe0008000
ddrphy_rdly_dq_rst = 0xe0008004
ddrphy_rdly_dq_inc = 0xe0008008
ddrphy_rdly_dq_bitslip = 0xe000800c
def period_to_cycles(sys_clk_freq, period):
return int(period*sys_clk_freq)
def sdram_init_instructions(sys_clk_freq):
return [
_WAIT_CMD | period_to_cycles(sys_clk_freq, 0.1),
# software control
_WRITE_CMD, sdram_dfii_control, 0,
# release reset
_WRITE_CMD, sdram_dfii_pi0_address, 0x0,
_WRITE_CMD, sdram_dfii_pi0_baddress, 0,
_WRITE_CMD, sdram_dfii_control, dfii_control_odt|dfii_control_reset_n,
_WAIT_CMD | period_to_cycles(sys_clk_freq, 0.1),
# bring cke high
_WRITE_CMD, sdram_dfii_pi0_address, 0x0,
_WRITE_CMD, sdram_dfii_pi0_baddress, 0,
_WRITE_CMD, sdram_dfii_control, dfii_control_cke|dfii_control_odt|dfii_control_reset_n,
_WAIT_CMD | period_to_cycles(sys_clk_freq, 0.1),
# load mode register 2
_WRITE_CMD, sdram_dfii_pi0_address, 0x408,
_WRITE_CMD, sdram_dfii_pi0_baddress, 2,
_WRITE_CMD, sdram_dfii_pi0_command, dfii_command_ras|dfii_command_cas|dfii_command_we|dfii_command_cs,
_WRITE_CMD, sdram_dfii_pi0_command_issue, 1,
# load mode register 3
_WRITE_CMD, sdram_dfii_pi0_address, 0x0,
_WRITE_CMD, sdram_dfii_pi0_baddress, 3,
_WRITE_CMD, sdram_dfii_pi0_command, dfii_command_ras|dfii_command_cas|dfii_command_we|dfii_command_cs,
_WRITE_CMD, sdram_dfii_pi0_command_issue, 1,
# load mode register 1
_WRITE_CMD, sdram_dfii_pi0_address, 0x6,
_WRITE_CMD, sdram_dfii_pi0_baddress, 1,
_WRITE_CMD, sdram_dfii_pi0_command, dfii_command_ras|dfii_command_cas|dfii_command_we|dfii_command_cs,
_WRITE_CMD, sdram_dfii_pi0_command_issue, 1,
# load mode register 0, cl=7, bl=8
_WRITE_CMD, sdram_dfii_pi0_address, 0x930,
_WRITE_CMD, sdram_dfii_pi0_baddress, 0,
_WRITE_CMD, sdram_dfii_pi0_command, dfii_command_ras|dfii_command_cas|dfii_command_we|dfii_command_cs,
_WRITE_CMD, sdram_dfii_pi0_command_issue, 1,
_WAIT_CMD | period_to_cycles(sys_clk_freq, 0.1),
# zq calibration
_WRITE_CMD, sdram_dfii_pi0_address, 0x400,
_WRITE_CMD, sdram_dfii_pi0_baddress, 0,
_WRITE_CMD, sdram_dfii_pi0_command, dfii_command_we|dfii_command_cs,
_WRITE_CMD, sdram_dfii_pi0_command_issue, 1,
_WAIT_CMD | period_to_cycles(sys_clk_freq, 0.1),
# hardware control
_WRITE_CMD, sdram_dfii_control, dfii_control_sel,
]
def sdram_config_instructions(bitslip, delay):
r = []
for module in range(2):
r += [_WRITE_CMD, ddrphy_dly_sel, 1<<module]
r += [_WRITE_CMD, ddrphy_rdly_dq_rst, 1]
for i in range(bitslip):
# 7-series SERDES in DDR mode needs 3 pulses for 1 bitslip
for j in range(3):
r += [_WRITE_CMD, ddrphy_rdly_dq_bitslip, 1]
for i in range(delay):
r += [_WRITE_CMD, ddrphy_rdly_dq_inc, 1]
return r
class SDRAMInit(WishboneMaster):
def __init__(self, sys_clk_freq, bitslip, delay):
WishboneMaster.__init__(self,
sdram_init_instructions(sys_clk_freq) +
sdram_config_instructions(bitslip, delay) +
[_DONE_CMD])
# SDRAM Initialization (to integrate in LiteX SoC)
sdram_init = SDRAMInit(sys_clk_freq, bitslip=3, delay=14)
self.submodules += sdram_init
self.bus.add_master(sdram_init.bus)
self.comb += [
platform.request("init_done").eq(sdram_init.done),
platform.request("init_error").eq(sdram_init.error)
]
#!/usr/bin/env python3
import sys
import time
from litex import RemoteClient
from sdram_init import *
wb = RemoteClient(debug=False)
wb.open()
# # #
# software control
wb.regs.sdram_dfii_control.write(0)
# sdram initialization
for i, (comment, a, ba, cmd, delay) in enumerate(init_sequence):
print(comment)
wb.regs.sdram_dfii_pi0_address.write(a)
wb.regs.sdram_dfii_pi0_baddress.write(ba)
if i < 2:
wb.regs.sdram_dfii_control.write(cmd)
else:
wb.regs.sdram_dfii_pi0_command.write(cmd)
wb.regs.sdram_dfii_pi0_command_issue.write(1)
# hardware control
wb.regs.sdram_dfii_control.write(dfii_control_sel)
def seed_to_data(seed, random=True):
if random:
return (1664525*seed + 1013904223) & 0xffffffff
else:
return seed
def write_pattern(length):
for i in range(length):
wb.write(wb.mems.main_ram.base + 4*i, seed_to_data(i))
def check_pattern(length, debug=False):
errors = 0
for i in range(length):
error = 0
if wb.read(wb.mems.main_ram.base + 4*i) != seed_to_data(i):
error = 1
if debug:
print("{}: 0x{:08x}, 0x{:08x} KO".format(i, wb.read(wb.mems.main_ram.base + 4*i), seed_to_data(i)))
else:
if debug:
print("{}: 0x{:08x}, 0x{:08x} OK".format(i, wb.read(wb.mems.main_ram.base + 4*i), seed_to_data(i)))
errors += error
return errors
# find working bitslips and delays
nbitslips = 8
ndelays = 32
nmodules = 2
nwords = 16
for bitslip in range(nbitslips):
print("bitslip {:d}: |".format(bitslip), end="")
for delay in range(ndelays):
for module in range(nmodules):
wb.regs.ddrphy_dly_sel.write(1<<module)
wb.regs.ddrphy_rdly_dq_rst.write(1)
wb.regs.ddrphy_rdly_dq_bitslip_rst.write(1)
for i in range(bitslip):
wb.regs.ddrphy_rdly_dq_bitslip.write(1)
for i in range(delay):
wb.regs.ddrphy_rdly_dq_inc.write(1)
write_pattern(nwords)
errors = check_pattern(nwords)
if errors:
print("..|", end="")
else:
print("{:02d}|".format(delay), end="")
sys.stdout.flush()
print("")
# # #
wb.close()
#!/usr/bin/env python3
from migen import *
from litex.soc.interconnect import wishbone
_WRITE_CMD = 0x10000000
_WAIT_CMD = 0x20000000
_DONE_CMD = 0x30000000
def cmd_decoder(instruction, cmd):
return instruction[28:] == (cmd >> 28)
class WishboneMaster(Module):
def __init__(self, instructions):
self.bus = bus = wishbone.Interface()
self.run = Signal()
self.done = Signal()
self.error = Signal()
# # #
mem = Memory(32, len(instructions), init=instructions)
port = mem.get_port(async_read=True)
self.specials += mem, port
wait_counter = Signal(32)
fsm = FSM(reset_state="IDLE")
self.submodules += fsm
fsm.act("IDLE",
self.run.eq(1),
NextState("CMD")
)
fsm.act("CMD",
self.run.eq(1),
If(cmd_decoder(port.dat_r, _WRITE_CMD),
NextValue(port.adr, port.adr + 1),
NextState("WRITE_ADR")
).Elif(cmd_decoder(port.dat_r, _WAIT_CMD),
NextValue(wait_counter, port.dat_r[:28]),
NextState("WAIT")
).Elif(cmd_decoder(port.dat_r, _DONE_CMD),
NextState("DONE")
).Else(
NextState("ERROR")
)
)
fsm.act("WAIT",
self.run.eq(1),
NextValue(wait_counter, wait_counter - 1),
If(wait_counter == 0,
NextValue(port.adr, port.adr + 1),
NextState("CMD")
)
)
fsm.act("WRITE_ADR",
self.run.eq(1),
NextValue(bus.adr, port.dat_r[2:]),
NextValue(port.adr, port.adr + 1),
NextState("WRITE_DATA")
)
fsm.act("WRITE_DATA",
self.run.eq(1),
NextValue(bus.dat_w, port.dat_r),
NextValue(port.adr, port.adr + 1),
NextState("WRITE")
)
fsm.act("WRITE",
self.run.eq(1),
bus.stb.eq(1),
bus.cyc.eq(1),
bus.we.eq(1),
bus.sel.eq(0xf),
If(bus.ack,
If(bus.err,
NextState("ERROR"),
).Else(
NextState("CMD")
)
)
)
fsm.act("ERROR", self.error.eq(1))
fsm.act("DONE", self.done.eq(1))
if __name__ == "__main__":
instructions = [
_WRITE_CMD,
0x12340000,
0x0000A5A5,
_WAIT_CMD | 0x20,
_WRITE_CMD,
0x00001234,
0xDEADBEEF,
_DONE_CMD
]
dut = WishboneMaster(instructions)
def dut_tb(dut):
yield dut.bus.ack.eq(1)
for i in range(1024):
yield
run_simulation(dut, dut_tb(dut), vcd_name="wb_master.vcd")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment