+++ /dev/null
-# This file is Copyright (c) 2019 Antti Lukats <antti.lukats@gmail.com>
-# This file is Copyright (c) 2019 Florent Kermarrec <florent@enjoy-digital.fr>
-# License: BSD
-
-from migen import *
-from migen.genlib.misc import timeline
-
-from litex.build.io import DifferentialOutput
-
-from litex.soc.interconnect import wishbone
-
-# HyperRAM -----------------------------------------------------------------------------------------
-
-class HyperRAM(Module):
- """HyperRAM
-
- Provides a very simple/minimal HyperRAM core that should work with all FPGA/HyperRam chips:
- - FPGA vendor agnostic.
- - no setup/chip configuration (use default latency).
-
- This core favrors portability and ease of use over performance.
- """
- def __init__(self, pads):
- self.pads = pads
- self.bus = bus = wishbone.Interface()
-
- # # #
-
- clk = Signal()
- clk_phase = Signal(2)
- cs = Signal()
- ca = Signal(48)
- sr = Signal(48)
- dq = self.add_tristate(pads.dq) if not hasattr(pads.dq, "oe") else pads.dq
- rwds = self.add_tristate(pads.rwds) if not hasattr(pads.rwds, "oe") else pads.rwds
-
- # Drive rst_n, cs_n, clk from internal signals ---------------------------------------------
- if hasattr(pads, "rst_n"):
- self.comb += pads.rst_n.eq(1)
- self.comb += pads.cs_n[0].eq(~cs)
- assert len(pads.cs_n) <= 2
- if len(pads.cs_n) == 2:
- self.comb += pads.cs_n[1].eq(1)
- if hasattr(pads, "clk"):
- self.comb += pads.clk.eq(clk)
- else:
- self.specials += DifferentialOutput(clk, pads.clk_p, pads.clk_n)
-
- # Clock Generation (sys_clk/4) -------------------------------------------------------------
- self.sync += clk_phase.eq(clk_phase + 1)
- cases = {}
- cases[1] = clk.eq(cs) # Set pads clk on 90° (if cs is set)
- cases[3] = clk.eq(0) # Clear pads clk on 270°
- self.sync += Case(clk_phase, cases)
-
- # Data Shift Register (for write and read) -------------------------------------------------
- dqi = Signal(8)
- self.sync += dqi.eq(dq.i) # Sample on 90° and 270°
- cases = {}
- cases[0] = sr.eq(Cat(dqi, sr[:-8])) # Shift on 0°
- cases[2] = sr.eq(Cat(dqi, sr[:-8])) # Shift on 180°
- self.sync += Case(clk_phase, cases)
- self.comb += [
- bus.dat_r.eq(sr), # To Wisbone
- dq.o.eq(sr[-8:]), # To HyperRAM
- ]
-
- # Command generation -----------------------------------------------------------------------
- self.comb += [
- ca[47].eq(~self.bus.we), # R/W#
- ca[45].eq(1), # Burst Type (Linear)
- ca[16:35].eq(self.bus.adr[2:21]), # Row & Upper Column Address
- ca[1:3].eq(self.bus.adr[0:2]), # Lower Column Address
- ca[0].eq(0), # Lower Column Address
- ]
-
- # Sequencer --------------------------------------------------------------------------------
- dt_seq = [
- # DT, Action
- (3, []),
- (12, [cs.eq(1), dq.oe.eq(1), sr.eq(ca)]), # Command: 6 clk
- (44, [dq.oe.eq(0)]), # Latency(default): 2*6 clk
- (2, [dq.oe.eq(self.bus.we), # Write/Read data byte: 2 clk
- sr[:16].eq(0),
- sr[16:].eq(self.bus.dat_w),
- rwds.oe.eq(self.bus.we),
- rwds.o.eq(~bus.sel[0])]),
- (2, [rwds.o.eq(~bus.sel[1])]), # Write/Read data byte: 2 clk
- (2, [rwds.o.eq(~bus.sel[2])]), # Write/Read data byte: 2 clk
- (2, [rwds.o.eq(~bus.sel[3])]), # Write/Read data byte: 2 clk
- (2, [cs.eq(0), rwds.oe.eq(0), dq.oe.eq(0)]),
- (1, [bus.ack.eq(1)]),
- (1, [bus.ack.eq(0)]),
- (0, []),
- ]
- # Convert delta-time sequencer to time sequencer
- t_seq = []
- t_seq_start = (clk_phase == 1)
- t = 0
- for dt, a in dt_seq:
- t_seq.append((t, a))
- t += dt
- self.sync += timeline(bus.cyc & bus.stb & t_seq_start, t_seq)
-
- def add_tristate(self, pad):
- t = TSTriple(len(pad))
- self.specials += t.get_tristate(pad)
- return t
("litescope", ("https://github.com/enjoy-digital/", False, True, None)),
("litejesd204b", ("https://github.com/enjoy-digital/", False, True, None)),
("litespi", ("https://github.com/litex-hub/", False, True, None)),
+ ("litehyperbus", ("https://github.com/litex-hub/", False, True, None)),
# LiteX boards support
("litex-boards", ("https://github.com/litex-hub/", False, True, None)),
+++ /dev/null
-# This file is Copyright (c) 2019 Florent Kermarrec <florent@enjoy-digital.fr>
-# License: BSD
-
-import unittest
-
-from migen import *
-
-from litex.soc.cores.hyperbus import HyperRAM
-
-def c2bool(c):
- return {"-": 1, "_": 0}[c]
-
-
-class Pads: pass
-
-
-class HyperRamPads:
- def __init__(self):
- self.clk = Signal()
- self.cs_n = Signal()
- self.dq = Record([("oe", 1), ("o", 8), ("i", 8)])
- self.rwds = Record([("oe", 1), ("o", 1), ("i", 1)])
-
-
-class TestHyperBus(unittest.TestCase):
- def test_hyperram_syntax(self):
- pads = Record([("clk", 1), ("cs_n", 1), ("dq", 8), ("rwds", 1)])
- hyperram = HyperRAM(pads)
-
- pads = Record([("clk_p", 1), ("clk_n", 1), ("cs_n", 1), ("dq", 8), ("rwds", 1)])
- hyperram = HyperRAM(pads)
-
- def test_hyperram_write(self):
- def fpga_gen(dut):
- yield from dut.bus.write(0x1234, 0xdeadbeef)
- yield
-
- def hyperram_gen(dut):
- clk = "___--__--__--__--__--__--__--__--__--__--__--__--__--__--__--__--_______"
- cs_n = "--________________________________________________________________------"
- dq_oe = "__------------____________________________________________--------______"
- dq_o = "002000048d000000000000000000000000000000000000000000000000deadbeef000000"
- rwds_oe = "__________________________________________________________--------______"
- rwds_o = "________________________________________________________________________"
- for i in range(3):
- yield
- for i in range(len(clk)):
- self.assertEqual(c2bool(clk[i]), (yield dut.pads.clk))
- self.assertEqual(c2bool(cs_n[i]), (yield dut.pads.cs_n))
- self.assertEqual(c2bool(dq_oe[i]), (yield dut.pads.dq.oe))
- self.assertEqual(int(dq_o[2*(i//2):2*(i//2)+2], 16), (yield dut.pads.dq.o))
- self.assertEqual(c2bool(rwds_oe[i]), (yield dut.pads.rwds.oe))
- self.assertEqual(c2bool(rwds_o[i]), (yield dut.pads.rwds.o))
- yield
-
- dut = HyperRAM(HyperRamPads())
- run_simulation(dut, [fpga_gen(dut), hyperram_gen(dut)])
-
- def test_hyperram_read(self):
- def fpga_gen(dut):
- dat = yield from dut.bus.read(0x1234)
- self.assertEqual(dat, 0xdeadbeef)
-
- def hyperram_gen(dut):
- clk = "___--__--__--__--__--__--__--__--__--__--__--__--__--__--__--__--_______"
- cs_n = "--________________________________________________________________------"
- dq_oe = "__------------__________________________________________________________"
- dq_o = "00a000048d00000000000000000000000000000000000000000000000000000000000000"
- dq_i = "0000000000000000000000000000000000000000000000000000000000deadbeef000000"
- rwds_oe = "________________________________________________________________________"
- for i in range(3):
- yield
- for i in range(len(clk)):
- yield dut.pads.dq.i.eq(int(dq_i[2*(i//2):2*(i//2)+2], 16))
- self.assertEqual(c2bool(clk[i]), (yield dut.pads.clk))
- self.assertEqual(c2bool(cs_n[i]), (yield dut.pads.cs_n))
- self.assertEqual(c2bool(dq_oe[i]), (yield dut.pads.dq.oe))
- self.assertEqual(int(dq_o[2*(i//2):2*(i//2)+2], 16), (yield dut.pads.dq.o))
- self.assertEqual(c2bool(rwds_oe[i]), (yield dut.pads.rwds.oe))
- yield
-
- dut = HyperRAM(HyperRamPads())
- run_simulation(dut, [fpga_gen(dut), hyperram_gen(dut)])