*.elf
*.bin
*.fbi
-tools/bin2hex
tools/flterm
-tools/mkmmimg
+tools/mkmscimg
tools/byteswap
software/include/hw/csr.h
software/include/hw/sdram_phy.h
-Unless otherwise noted, milkymist-ng is copyright (C) 2011-2013 Sebastien Bourdeauducq.
+Unless otherwise noted, MiSoC is copyright (C) 2011-2013 Sebastien Bourdeauducq.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
-[> Milkymist-ng system-on-chip
+[> MiSoC system-on-chip
------------------------------
-This is the next-generation Milkymist(tm) system-on-chip design,
-introducing two key features:
- * Built on the powerful Migen VLSI logic design system.
- * Increased system memory performance thanks to LASMI.
+A high performance system-on-chip design based on Migen.
-This translates to more development productivity, better video resolution
-and quality, ease of designing complex hardware accelerators, and much
-more flexibility in hardware designs.
-
-The milkymist-ng SoC supports the Mixxeo and the Milkymist One.
-Obtain yours at http://milkymist.org
+MiSoC supports the Mixxeo and the Milkymist One.
+Obtain your development system at http://milkymist.org
[> Instructions (software)
--------------------------
This will generate the build/soc-<platform>.bit programming file
and load it with UrJTAG.
-A new BIOS needs to be built and flashed for the -ng SoC.
+A new BIOS needs to be built and flashed for MiSoC.
+There is no compatibility with Milkymist SoC.
Enjoy!
[> Misc
-------
Code repository:
- https://github.com/milkymist/milkymist-ng
+ https://github.com/milkymist/misoc
Send questions, comments and patches to devel [AT] lists.milkymist.org
We are also on IRC: #milkymist on the Freenode network.
-Milkymist-ng is released under the very permissive two-clause BSD license. Under
-the terms of this license, you are authorized to use milkymist-ng for
+MiSoC is released under the very permissive two-clause BSD license. Under
+the terms of this license, you are authorized to use MiSoC for
closed-source proprietary designs.
Even though we do not require you to do so, those things are awesome, so please
do them if possible:
- * tell us that you are using milkymist-ng
- * cite milkymist-ng in publications related to research it has helped
+ * tell us that you are using MiSoC
+ * cite MiSoC in publications related to research it has helped
* send us feedback and suggestions for improvements
* send us bug reports when something goes wrong
- * send us the modifications and improvements you have done to milkymist-ng.
+ * send us the modifications and improvements you have done to MiSoC.
The use of "git format-patch" is recommended. If your submission is large and
complex and/or you are not sure how to proceed, feel free to discuss it on
the mailing list or IRC (#milkymist on Freenode) beforehand.
from mibuild.tools import write_to_file
-from milkymist import cpuif
-from milkymist.s6ddrphy import initsequence
+from misoclib import cpuif
+from misoclib.s6ddrphy import initsequence
import top, jtag
def build(platform_name, build_bitstream, build_header, csr_csv_filename, *soc_args, **soc_kwargs):
write_to_file(csr_csv_filename, csr_csv)
def main():
- parser = argparse.ArgumentParser(description="milkymist-ng - a high performance SoC built on Migen technology.")
+ parser = argparse.ArgumentParser(description="MiSoC - a high performance SoC based on Migen.")
parser.add_argument("-p", "--platform", default="mixxeo", help="platform to build for")
parser.add_argument("-B", "--no-bitstream", default=False, action="store_true", help="do not build bitstream file")
parser.add_argument("-H", "--no-header", default=False, action="store_true", help="do not build C header files with CSR/IRQ/SDRAM_PHY defs")
+++ /dev/null
-import collections
-
-from migen.fhdl.std import *
-from migen.bank.description import *
-from migen.genlib.misc import optree
-from migen.genlib.cdc import MultiReg
-
-class CounterADC(Module, AutoCSR):
- def __init__(self, charge, sense, width=24):
- if not isinstance(sense, collections.Iterable):
- sense = [sense]
-
- channels = len(sense)
-
- self._start_busy = CSR()
- self._overflow = CSRStatus(channels)
- self._polarity = CSRStorage()
-
- count = Signal(width)
- busy = Signal(channels)
-
- res = []
- for i in range(channels):
- res.append(CSRStatus(width, name="res"+str(i)))
- setattr(self, "_res"+str(i), res[-1])
-
- any_busy = Signal()
- self.comb += [
- any_busy.eq(optree("|",
- [busy[i] for i in range(channels)])),
- self._start_busy.w.eq(any_busy)
- ]
-
- carry = Signal()
-
- self.sync += [
- If(self._start_busy.re,
- count.eq(0),
- busy.eq((1 << channels)-1),
- self._overflow.status.eq(0),
- charge.eq(~self._polarity.storage)
- ).Elif(any_busy,
- Cat(count, carry).eq(count + 1),
- If(carry,
- self._overflow.status.eq(busy),
- busy.eq(0)
- )
- ).Else(
- charge.eq(self._polarity.storage)
- )
- ]
-
- for i in range(channels):
- sense_synced = Signal()
- self.specials += MultiReg(sense[i], sense_synced)
- self.sync += If(busy[i],
- If(sense_synced != self._polarity.storage,
- res[i].status.eq(count),
- busy[i].eq(0)
- )
- )
+++ /dev/null
-from migen.bank.description import CSRStatus
-
-def _get_rw_functions(reg_name, reg_base, size, read_only):
- r = ""
- if size > 8:
- raise NotImplementedError("Register too large")
- elif size > 4:
- ctype = "unsigned long long int"
- elif size > 2:
- ctype = "unsigned int"
- elif size > 1:
- ctype = "unsigned short int"
- else:
- ctype = "unsigned char"
-
- r += "static inline "+ctype+" "+reg_name+"_read(void) {\n"
- if size > 1:
- r += "\t"+ctype+" r = MMPTR("+hex(reg_base)+");\n"
- for byte in range(1, size):
- r += "\tr <<= 8;\n\tr |= MMPTR("+hex(reg_base+4*byte)+");\n"
- r += "\treturn r;\n}\n"
- else:
- r += "\treturn MMPTR("+hex(reg_base)+");\n}\n"
-
- if not read_only:
- r += "static inline void "+reg_name+"_write("+ctype+" value) {\n"
- for byte in range(size):
- shift = (size-byte-1)*8
- if shift:
- value_shifted = "value >> "+str(shift)
- else:
- value_shifted = "value"
- r += "\tMMPTR("+hex(reg_base+4*byte)+") = "+value_shifted+";\n"
- r += "}\n"
- return r
-
-def get_csr_header(csr_base, bank_array, interrupt_map):
- r = "#ifndef __HW_CSR_H\n#define __HW_CSR_H\n#include <hw/common.h>\n"
- for name, csrs, mapaddr, rmap in bank_array.banks:
- r += "\n/* "+name+" */\n"
- reg_base = csr_base + 0x800*mapaddr
- r += "#define "+name.upper()+"_BASE "+hex(reg_base)+"\n"
- for csr in csrs:
- nr = (csr.size + 7)//8
- r += _get_rw_functions(name + "_" + csr.name, reg_base, nr, isinstance(csr, CSRStatus))
- reg_base += 4*nr
- try:
- interrupt_nr = interrupt_map[name]
- except KeyError:
- pass
- else:
- r += "#define "+name.upper()+"_INTERRUPT "+str(interrupt_nr)+"\n"
- r += "\n#endif\n"
- return r
-
-def get_csr_csv(csr_base, bank_array):
- r = ""
- for name, csrs, mapaddr, rmap in bank_array.banks:
- reg_base = csr_base + 0x800*mapaddr
- for csr in csrs:
- nr = (csr.size + 7)//8
- r += "{}_{},0x{:08x},{},{}\n".format(name, csr.name, reg_base, nr, "ro" if isinstance(csr, CSRStatus) else "rw")
- reg_base += 4*nr
- return r
+++ /dev/null
-from migen.fhdl.std import *
-from migen.bus import dfi
-from migen.bank.description import *
-
-class PhaseInjector(Module, AutoCSR):
- def __init__(self, phase):
- self._command = CSRStorage(6) # cs, we, cas, ras, wren, rden
- self._command_issue = CSR()
- self._address = CSRStorage(flen(phase.address))
- self._baddress = CSRStorage(flen(phase.bank))
- self._wrdata = CSRStorage(flen(phase.wrdata))
- self._rddata = CSRStatus(flen(phase.rddata))
-
- ###
-
- self.comb += [
- If(self._command_issue.re,
- phase.cs_n.eq(~self._command.storage[0]),
- phase.we_n.eq(~self._command.storage[1]),
- phase.cas_n.eq(~self._command.storage[2]),
- phase.ras_n.eq(~self._command.storage[3])
- ).Else(
- phase.cs_n.eq(1),
- phase.we_n.eq(1),
- phase.cas_n.eq(1),
- phase.ras_n.eq(1)
- ),
- phase.address.eq(self._address.storage),
- phase.bank.eq(self._baddress.storage),
- phase.wrdata_en.eq(self._command_issue.re & self._command.storage[4]),
- phase.rddata_en.eq(self._command_issue.re & self._command.storage[5]),
- phase.wrdata.eq(self._wrdata.storage),
- phase.wrdata_mask.eq(0)
- ]
- self.sync += If(phase.rddata_valid, self._rddata.status.eq(phase.rddata))
-
-class DFIInjector(Module, AutoCSR):
- def __init__(self, a, ba, d, nphases=1):
- inti = dfi.Interface(a, ba, d, nphases)
- self.slave = dfi.Interface(a, ba, d, nphases)
- self.master = dfi.Interface(a, ba, d, nphases)
-
- self._control = CSRStorage(2) # sel, cke
-
- for n, phase in enumerate(inti.phases):
- setattr(self.submodules, "pi" + str(n), PhaseInjector(phase))
-
- ###
-
- self.comb += If(self._control.storage[0],
- self.slave.connect(self.master)
- ).Else(
- inti.connect(self.master)
- )
- self.comb += [phase.cke.eq(self._control.storage[1]) for phase in inti.phases]
+++ /dev/null
-from migen.fhdl.std import *
-from migen.bank.description import AutoCSR
-
-from milkymist.dvisampler.edid import EDID
-from milkymist.dvisampler.clocking import Clocking
-from milkymist.dvisampler.datacapture import DataCapture
-from milkymist.dvisampler.charsync import CharSync
-from milkymist.dvisampler.wer import WER
-from milkymist.dvisampler.decoding import Decoding
-from milkymist.dvisampler.chansync import ChanSync
-from milkymist.dvisampler.analysis import SyncPolarity, ResolutionDetection, FrameExtraction
-from milkymist.dvisampler.dma import DMA
-
-class DVISampler(Module, AutoCSR):
- def __init__(self, pads, asmiport, n_dma_slots=2):
- self.submodules.edid = EDID(pads)
- self.submodules.clocking = Clocking(pads)
-
- for datan in range(3):
- name = "data" + str(datan)
-
- cap = DataCapture(getattr(pads, name + "_p"), getattr(pads, name + "_n"), 8)
- setattr(self.submodules, name + "_cap", cap)
- self.comb += cap.serdesstrobe.eq(self.clocking.serdesstrobe)
-
- charsync = CharSync()
- setattr(self.submodules, name + "_charsync", charsync)
- self.comb += charsync.raw_data.eq(cap.d)
-
- wer = WER()
- setattr(self.submodules, name + "_wer", wer)
- self.comb += wer.data.eq(charsync.data)
-
- decoding = Decoding()
- setattr(self.submodules, name + "_decod", decoding)
- self.comb += [
- decoding.valid_i.eq(charsync.synced),
- decoding.input.eq(charsync.data)
- ]
-
- self.submodules.chansync = ChanSync()
- self.comb += [
- self.chansync.valid_i.eq(self.data0_decod.valid_o & \
- self.data1_decod.valid_o & self.data2_decod.valid_o),
- self.chansync.data_in0.eq(self.data0_decod.output),
- self.chansync.data_in1.eq(self.data1_decod.output),
- self.chansync.data_in2.eq(self.data2_decod.output),
- ]
-
- self.submodules.syncpol = SyncPolarity()
- self.comb += [
- self.syncpol.valid_i.eq(self.chansync.chan_synced),
- self.syncpol.data_in0.eq(self.chansync.data_out0),
- self.syncpol.data_in1.eq(self.chansync.data_out1),
- self.syncpol.data_in2.eq(self.chansync.data_out2)
- ]
-
- self.submodules.resdetection = ResolutionDetection()
- self.comb += [
- self.resdetection.valid_i.eq(self.syncpol.valid_o),
- self.resdetection.de.eq(self.syncpol.de),
- self.resdetection.vsync.eq(self.syncpol.vsync)
- ]
-
- self.submodules.frame = FrameExtraction()
- self.comb += [
- self.frame.valid_i.eq(self.syncpol.valid_o),
- self.frame.de.eq(self.syncpol.de),
- self.frame.vsync.eq(self.syncpol.vsync),
- self.frame.r.eq(self.syncpol.r),
- self.frame.g.eq(self.syncpol.g),
- self.frame.b.eq(self.syncpol.b)
- ]
-
- self.submodules.dma = DMA(asmiport, n_dma_slots)
- self.comb += self.frame.frame.connect(self.dma.frame)
- self.ev = self.dma.ev
-
- autocsr_exclude = {"ev"}
+++ /dev/null
-from migen.fhdl.std import *
-from migen.genlib.cdc import MultiReg, PulseSynchronizer
-from migen.genlib.fifo import AsyncFIFO
-from migen.genlib.record import Record
-from migen.bank.description import *
-from migen.flow.actor import *
-
-from milkymist.dvisampler.common import channel_layout, frame_layout
-
-class SyncPolarity(Module):
- def __init__(self):
- self.valid_i = Signal()
- self.data_in0 = Record(channel_layout)
- self.data_in1 = Record(channel_layout)
- self.data_in2 = Record(channel_layout)
-
- self.valid_o = Signal()
- self.de = Signal()
- self.hsync = Signal()
- self.vsync = Signal()
- self.r = Signal(8)
- self.g = Signal(8)
- self.b = Signal(8)
-
- ###
-
- de = self.data_in0.de
- de_r = Signal()
- c = self.data_in0.c
- c_polarity = Signal(2)
- c_out = Signal(2)
-
- self.comb += [
- self.de.eq(de_r),
- self.hsync.eq(c_out[0]),
- self.vsync.eq(c_out[1])
- ]
-
- self.sync.pix += [
- self.valid_o.eq(self.valid_i),
- self.r.eq(self.data_in2.d),
- self.g.eq(self.data_in1.d),
- self.b.eq(self.data_in0.d),
-
- de_r.eq(de),
- If(de_r & ~de,
- c_polarity.eq(c),
- c_out.eq(0)
- ).Else(
- c_out.eq(c ^ c_polarity)
- )
- ]
-
-class ResolutionDetection(Module, AutoCSR):
- def __init__(self, nbits=11):
- self.valid_i = Signal()
- self.vsync = Signal()
- self.de = Signal()
-
- self._hres = CSRStatus(nbits)
- self._vres = CSRStatus(nbits)
-
- ###
-
- # Detect DE transitions
- de_r = Signal()
- pn_de = Signal()
- self.sync.pix += de_r.eq(self.de)
- self.comb += pn_de.eq(~self.de & de_r)
-
- # HRES
- hcounter = Signal(nbits)
- self.sync.pix += If(self.valid_i & self.de,
- hcounter.eq(hcounter + 1)
- ).Else(
- hcounter.eq(0)
- )
-
- hcounter_st = Signal(nbits)
- self.sync.pix += If(self.valid_i,
- If(pn_de, hcounter_st.eq(hcounter))
- ).Else(
- hcounter_st.eq(0)
- )
- self.specials += MultiReg(hcounter_st, self._hres.status)
-
- # VRES
- vsync_r = Signal()
- p_vsync = Signal()
- self.sync.pix += vsync_r.eq(self.vsync),
- self.comb += p_vsync.eq(self.vsync & ~vsync_r)
-
- vcounter = Signal(nbits)
- self.sync.pix += If(self.valid_i & p_vsync,
- vcounter.eq(0)
- ).Elif(pn_de,
- vcounter.eq(vcounter + 1)
- )
-
- vcounter_st = Signal(nbits)
- self.sync.pix += If(self.valid_i,
- If(p_vsync, vcounter_st.eq(vcounter))
- ).Else(
- vcounter_st.eq(0)
- )
- self.specials += MultiReg(vcounter_st, self._vres.status)
-
-class FrameExtraction(Module, AutoCSR):
- def __init__(self):
- # in pix clock domain
- self.valid_i = Signal()
- self.vsync = Signal()
- self.de = Signal()
- self.r = Signal(8)
- self.g = Signal(8)
- self.b = Signal(8)
-
- # in sys clock domain
- self.frame = Source(frame_layout)
- self.busy = Signal()
-
- self._r_overflow = CSR()
-
- ###
-
- fifo_stb = Signal()
- fifo_in = Record(frame_layout)
- self.comb += [
- fifo_stb.eq(self.valid_i & self.de),
- fifo_in.r.eq(self.r),
- fifo_in.g.eq(self.g),
- fifo_in.b.eq(self.b),
- ]
- vsync_r = Signal()
- self.sync.pix += [
- If(self.vsync & ~vsync_r, fifo_in.parity.eq(~fifo_in.parity)),
- vsync_r.eq(self.vsync)
- ]
-
- fifo = RenameClockDomains(AsyncFIFO(layout_len(frame_layout), 512),
- {"write": "pix", "read": "sys"})
- self.submodules += fifo
- self.comb += [
- fifo.we.eq(fifo_stb),
- fifo.din.eq(fifo_in.raw_bits()),
- self.frame.stb.eq(fifo.readable),
- self.frame.payload.raw_bits().eq(fifo.dout),
- fifo.re.eq(self.frame.ack),
- self.busy.eq(0)
- ]
-
- # overflow detection
- pix_overflow = Signal()
- pix_overflow_reset = Signal()
- self.sync.pix += [
- If(fifo.we & ~fifo.writable,
- pix_overflow.eq(1)
- ).Elif(pix_overflow_reset,
- pix_overflow.eq(0)
- )
- ]
-
- sys_overflow = Signal()
- self.specials += MultiReg(pix_overflow, sys_overflow)
- self.submodules.overflow_reset = PulseSynchronizer("sys", "pix")
- self.submodules.overflow_reset_ack = PulseSynchronizer("pix", "sys")
- self.comb += [
- pix_overflow_reset.eq(self.overflow_reset.o),
- self.overflow_reset_ack.i.eq(pix_overflow_reset)
- ]
-
- overflow_mask = Signal()
- self.comb += [
- self._r_overflow.w.eq(sys_overflow & ~overflow_mask),
- self.overflow_reset.i.eq(self._r_overflow.re)
- ]
- self.sync += [
- If(self._r_overflow.re,
- overflow_mask.eq(1)
- ).Elif(self.overflow_reset_ack.o,
- overflow_mask.eq(0)
- )
- ]
+++ /dev/null
-from migen.fhdl.std import *
-from migen.genlib.cdc import MultiReg
-from migen.genlib.fifo import _inc
-from migen.genlib.record import Record, layout_len
-from migen.genlib.misc import optree
-from migen.bank.description import *
-
-from milkymist.dvisampler.common import channel_layout
-
-class _SyncBuffer(Module):
- def __init__(self, width, depth):
- self.din = Signal(width)
- self.dout = Signal(width)
- self.re = Signal()
-
- ###
-
- produce = Signal(max=depth)
- consume = Signal(max=depth)
- storage = Memory(width, depth)
- self.specials += storage
-
- wrport = storage.get_port(write_capable=True)
- self.specials += wrport
- self.comb += [
- wrport.adr.eq(produce),
- wrport.dat_w.eq(self.din),
- wrport.we.eq(1)
- ]
- self.sync += _inc(produce, depth)
-
- rdport = storage.get_port(async_read=True)
- self.specials += rdport
- self.comb += [
- rdport.adr.eq(consume),
- self.dout.eq(rdport.dat_r)
- ]
- self.sync += If(self.re, _inc(consume, depth))
-
-class ChanSync(Module, AutoCSR):
- def __init__(self, nchan=3, depth=8):
- self.valid_i = Signal()
- self.chan_synced = Signal()
-
- self._r_channels_synced = CSRStatus()
-
- lst_control = []
- all_control = Signal()
- for i in range(nchan):
- name = "data_in" + str(i)
- data_in = Record(channel_layout, name=name)
- setattr(self, name, data_in)
- name = "data_out" + str(i)
- data_out = Record(channel_layout, name=name)
- setattr(self, name, data_out)
-
- ###
-
- syncbuffer = RenameClockDomains(_SyncBuffer(layout_len(channel_layout), depth), "pix")
- self.submodules += syncbuffer
- self.comb += [
- syncbuffer.din.eq(data_in.raw_bits()),
- data_out.raw_bits().eq(syncbuffer.dout)
- ]
- is_control = Signal()
- self.comb += [
- is_control.eq(~data_out.de),
- syncbuffer.re.eq(~is_control | all_control)
- ]
- lst_control.append(is_control)
-
- some_control = Signal()
- self.comb += [
- all_control.eq(optree("&", lst_control)),
- some_control.eq(optree("|", lst_control))
- ]
- self.sync.pix += If(~self.valid_i,
- self.chan_synced.eq(0)
- ).Else(
- If(some_control,
- If(all_control,
- self.chan_synced.eq(1)
- ).Else(
- self.chan_synced.eq(0)
- )
- )
- )
- self.specials += MultiReg(self.chan_synced, self._r_channels_synced.status)
+++ /dev/null
-from migen.fhdl.std import *
-from migen.genlib.cdc import MultiReg
-from migen.genlib.misc import optree
-from migen.bank.description import *
-
-from milkymist.dvisampler.common import control_tokens
-
-class CharSync(Module, AutoCSR):
- def __init__(self, required_controls=8):
- self.raw_data = Signal(10)
- self.synced = Signal()
- self.data = Signal(10)
-
- self._r_char_synced = CSRStatus()
- self._r_ctl_pos = CSRStatus(bits_for(9))
-
- ###
-
- raw_data1 = Signal(10)
- self.sync.pix += raw_data1.eq(self.raw_data)
- raw = Signal(20)
- self.comb += raw.eq(Cat(raw_data1, self.raw_data))
-
- found_control = Signal()
- control_position = Signal(max=10)
- self.sync.pix += found_control.eq(0)
- for i in range(10):
- self.sync.pix += If(optree("|", [raw[i:i+10] == t for t in control_tokens]),
- found_control.eq(1),
- control_position.eq(i)
- )
-
- control_counter = Signal(max=required_controls)
- previous_control_position = Signal(max=10)
- word_sel = Signal(max=10)
- self.sync.pix += [
- If(found_control & (control_position == previous_control_position),
- If(control_counter == (required_controls - 1),
- control_counter.eq(0),
- self.synced.eq(1),
- word_sel.eq(control_position)
- ).Else(
- control_counter.eq(control_counter + 1)
- )
- ).Else(
- control_counter.eq(0)
- ),
- previous_control_position.eq(control_position)
- ]
- self.specials += MultiReg(self.synced, self._r_char_synced.status)
- self.specials += MultiReg(word_sel, self._r_ctl_pos.status)
-
- self.sync.pix += self.data.eq(raw >> word_sel)
+++ /dev/null
-from migen.fhdl.std import *
-from migen.genlib.cdc import MultiReg
-from migen.bank.description import *
-
-class Clocking(Module, AutoCSR):
- def __init__(self, pads):
- self._r_pll_reset = CSRStorage(reset=1)
- self._r_locked = CSRStatus()
-
- self.locked = Signal()
- self.serdesstrobe = Signal()
- self.clock_domains._cd_pix = ClockDomain()
- self.clock_domains._cd_pix2x = ClockDomain()
- self.clock_domains._cd_pix10x = ClockDomain(reset_less=True)
-
- ###
-
- clk_se = Signal()
- self.specials += Instance("IBUFDS", i_I=pads.clk_p, i_IB=pads.clk_n, o_O=clk_se)
-
- clkfbout = Signal()
- pll_locked = Signal()
- pll_clk0 = Signal()
- pll_clk1 = Signal()
- pll_clk2 = Signal()
- self.specials += Instance("PLL_BASE",
- p_CLKIN_PERIOD=26.7,
- p_CLKFBOUT_MULT=20,
- p_CLKOUT0_DIVIDE=2, # pix10x
- p_CLKOUT1_DIVIDE=10, # pix2x
- p_CLKOUT2_DIVIDE=20, # pix
- p_COMPENSATION="INTERNAL",
-
- i_CLKIN=clk_se,
- o_CLKOUT0=pll_clk0, o_CLKOUT1=pll_clk1, o_CLKOUT2=pll_clk2,
- o_CLKFBOUT=clkfbout, i_CLKFBIN=clkfbout,
- o_LOCKED=pll_locked, i_RST=self._r_pll_reset.storage)
-
- locked_async = Signal()
- self.specials += [
- Instance("BUFPLL", p_DIVIDE=5,
- i_PLLIN=pll_clk0, i_GCLK=ClockSignal("pix2x"), i_LOCKED=pll_locked,
- o_IOCLK=self._cd_pix10x.clk, o_LOCK=locked_async, o_SERDESSTROBE=self.serdesstrobe),
- Instance("BUFG", i_I=pll_clk1, o_O=self._cd_pix2x.clk),
- Instance("BUFG", i_I=pll_clk2, o_O=self._cd_pix.clk),
- MultiReg(locked_async, self.locked, "sys")
- ]
- self.comb += self._r_locked.status.eq(self.locked)
-
- # sychronize pix+pix2x reset
- pix_rst_n = 1
- for i in range(2):
- new_pix_rst_n = Signal()
- self.specials += Instance("FDCE", i_D=pix_rst_n, i_CE=1, i_C=ClockSignal("pix"),
- i_CLR=~locked_async, o_Q=new_pix_rst_n)
- pix_rst_n = new_pix_rst_n
- self.comb += self._cd_pix.rst.eq(~pix_rst_n), self._cd_pix2x.rst.eq(~pix_rst_n)
+++ /dev/null
-control_tokens = [0b1101010100, 0b0010101011, 0b0101010100, 0b1010101011]
-channel_layout = [("d", 8), ("c", 2), ("de", 1)]
-frame_layout = [("parity", 1), ("r", 8), ("g", 8), ("b", 8)]
+++ /dev/null
-from migen.fhdl.std import *
-from migen.genlib.cdc import MultiReg, PulseSynchronizer
-from migen.bank.description import *
-
-class DataCapture(Module, AutoCSR):
- def __init__(self, pad_p, pad_n, ntbits):
- self.serdesstrobe = Signal()
- self.d = Signal(10)
-
- self._r_dly_ctl = CSR(6)
- self._r_dly_busy = CSRStatus(2)
- self._r_phase = CSRStatus(2)
- self._r_phase_reset = CSR()
-
- ###
-
- # IO
- pad_se = Signal()
- self.specials += Instance("IBUFDS", i_I=pad_p, i_IB=pad_n, o_O=pad_se)
-
- pad_delayed_master = Signal()
- pad_delayed_slave = Signal()
- delay_inc = Signal()
- delay_ce = Signal()
- delay_master_cal = Signal()
- delay_master_rst = Signal()
- delay_master_busy = Signal()
- delay_slave_cal = Signal()
- delay_slave_rst = Signal()
- delay_slave_busy = Signal()
- self.specials += Instance("IODELAY2",
- p_SERDES_MODE="MASTER",
- p_DELAY_SRC="IDATAIN", p_IDELAY_TYPE="DIFF_PHASE_DETECTOR",
- p_COUNTER_WRAPAROUND="STAY_AT_LIMIT", p_DATA_RATE="SDR",
-
- i_IDATAIN=pad_se, o_DATAOUT=pad_delayed_master,
- i_CLK=ClockSignal("pix2x"), i_IOCLK0=ClockSignal("pix10x"),
-
- i_INC=delay_inc, i_CE=delay_ce,
- i_CAL=delay_master_cal, i_RST=delay_master_rst, o_BUSY=delay_master_busy,
- i_T=1)
- self.specials += Instance("IODELAY2",
- p_SERDES_MODE="SLAVE",
- p_DELAY_SRC="IDATAIN", p_IDELAY_TYPE="DIFF_PHASE_DETECTOR",
- p_COUNTER_WRAPAROUND="WRAPAROUND", p_DATA_RATE="SDR",
-
- i_IDATAIN=pad_se, o_DATAOUT=pad_delayed_slave,
- i_CLK=ClockSignal("pix2x"), i_IOCLK0=ClockSignal("pix10x"),
-
- i_INC=delay_inc, i_CE=delay_ce,
- i_CAL=delay_slave_cal, i_RST=delay_slave_rst, o_BUSY=delay_slave_busy,
- i_T=1)
-
- dsr2 = Signal(5)
- pd_valid = Signal()
- pd_incdec = Signal()
- pd_edge = Signal()
- pd_cascade = Signal()
- self.specials += Instance("ISERDES2",
- p_SERDES_MODE="MASTER",
- p_BITSLIP_ENABLE="FALSE", p_DATA_RATE="SDR", p_DATA_WIDTH=5,
- p_INTERFACE_TYPE="RETIMED",
-
- i_D=pad_delayed_master,
- o_Q4=dsr2[4], o_Q3=dsr2[3], o_Q2=dsr2[2], o_Q1=dsr2[1],
-
- i_BITSLIP=0, i_CE0=1, i_RST=0,
- i_CLK0=ClockSignal("pix10x"), i_CLKDIV=ClockSignal("pix2x"),
- i_IOCE=self.serdesstrobe,
-
- o_VALID=pd_valid, o_INCDEC=pd_incdec,
- i_SHIFTIN=pd_edge, o_SHIFTOUT=pd_cascade)
- self.specials += Instance("ISERDES2",
- p_SERDES_MODE="SLAVE",
- p_BITSLIP_ENABLE="FALSE", p_DATA_RATE="SDR", p_DATA_WIDTH=5,
- p_INTERFACE_TYPE="RETIMED",
-
- i_D=pad_delayed_slave,
- o_Q4=dsr2[0],
-
- i_BITSLIP=0, i_CE0=1, i_RST=0,
- i_CLK0=ClockSignal("pix10x"), i_CLKDIV=ClockSignal("pix2x"),
- i_IOCE=self.serdesstrobe,
-
- i_SHIFTIN=pd_cascade, o_SHIFTOUT=pd_edge)
-
- # Phase error accumulator
- lateness = Signal(ntbits, reset=2**(ntbits - 1))
- too_late = Signal()
- too_early = Signal()
- reset_lateness = Signal()
- self.comb += [
- too_late.eq(lateness == (2**ntbits - 1)),
- too_early.eq(lateness == 0)
- ]
- self.sync.pix2x += [
- If(reset_lateness,
- lateness.eq(2**(ntbits - 1))
- ).Elif(~delay_master_busy & ~delay_slave_busy & ~too_late & ~too_early,
- If(pd_valid & pd_incdec, lateness.eq(lateness - 1)),
- If(pd_valid & ~pd_incdec, lateness.eq(lateness + 1))
- )
- ]
-
- # Delay control
- self.submodules.delay_master_done = PulseSynchronizer("pix2x", "sys")
- delay_master_pending = Signal()
- self.sync.pix2x += [
- self.delay_master_done.i.eq(0),
- If(~delay_master_pending,
- If(delay_master_cal | delay_ce, delay_master_pending.eq(1))
- ).Else(
- If(~delay_master_busy,
- self.delay_master_done.i.eq(1),
- delay_master_pending.eq(0)
- )
- )
- ]
- self.submodules.delay_slave_done = PulseSynchronizer("pix2x", "sys")
- delay_slave_pending = Signal()
- self.sync.pix2x += [
- self.delay_slave_done.i.eq(0),
- If(~delay_slave_pending,
- If(delay_slave_cal | delay_ce, delay_slave_pending.eq(1))
- ).Else(
- If(~delay_slave_busy,
- self.delay_slave_done.i.eq(1),
- delay_slave_pending.eq(0)
- )
- )
- ]
-
- self.submodules.do_delay_master_cal = PulseSynchronizer("sys", "pix2x")
- self.submodules.do_delay_master_rst = PulseSynchronizer("sys", "pix2x")
- self.submodules.do_delay_slave_cal = PulseSynchronizer("sys", "pix2x")
- self.submodules.do_delay_slave_rst = PulseSynchronizer("sys", "pix2x")
- self.submodules.do_delay_inc = PulseSynchronizer("sys", "pix2x")
- self.submodules.do_delay_dec = PulseSynchronizer("sys", "pix2x")
- self.comb += [
- delay_master_cal.eq(self.do_delay_master_cal.o),
- delay_master_rst.eq(self.do_delay_master_rst.o),
- delay_slave_cal.eq(self.do_delay_slave_cal.o),
- delay_slave_rst.eq(self.do_delay_slave_rst.o),
- delay_inc.eq(self.do_delay_inc.o),
- delay_ce.eq(self.do_delay_inc.o | self.do_delay_dec.o),
- ]
-
- sys_delay_master_pending = Signal()
- self.sync += [
- If(self.do_delay_master_cal.i | self.do_delay_inc.i | self.do_delay_dec.i,
- sys_delay_master_pending.eq(1)
- ).Elif(self.delay_master_done.o,
- sys_delay_master_pending.eq(0)
- )
- ]
- sys_delay_slave_pending = Signal()
- self.sync += [
- If(self.do_delay_slave_cal.i | self.do_delay_inc.i | self.do_delay_dec.i,
- sys_delay_slave_pending.eq(1)
- ).Elif(self.delay_slave_done.o,
- sys_delay_slave_pending.eq(0)
- )
- ]
-
- self.comb += [
- self.do_delay_master_cal.i.eq(self._r_dly_ctl.re & self._r_dly_ctl.r[0]),
- self.do_delay_master_rst.i.eq(self._r_dly_ctl.re & self._r_dly_ctl.r[1]),
- self.do_delay_slave_cal.i.eq(self._r_dly_ctl.re & self._r_dly_ctl.r[2]),
- self.do_delay_slave_rst.i.eq(self._r_dly_ctl.re & self._r_dly_ctl.r[3]),
- self.do_delay_inc.i.eq(self._r_dly_ctl.re & self._r_dly_ctl.r[4]),
- self.do_delay_dec.i.eq(self._r_dly_ctl.re & self._r_dly_ctl.r[5]),
- self._r_dly_busy.status.eq(Cat(sys_delay_master_pending, sys_delay_slave_pending))
- ]
-
- # Phase detector control
- self.specials += MultiReg(Cat(too_late, too_early), self._r_phase.status)
- self.submodules.do_reset_lateness = PulseSynchronizer("sys", "pix2x")
- self.comb += [
- reset_lateness.eq(self.do_reset_lateness.o),
- self.do_reset_lateness.i.eq(self._r_phase_reset.re)
- ]
-
- # 5:10 deserialization
- dsr = Signal(10)
- self.sync.pix2x += dsr.eq(Cat(dsr[5:], dsr2))
- self.sync.pix += self.d.eq(dsr)
+++ /dev/null
-from migen.fhdl.std import *
-from migen.genlib.fifo import AsyncFIFO
-from migen.genlib.record import layout_len
-from migen.bank.description import AutoCSR
-from migen.actorlib import structuring, dma_lasmi, spi
-
-from milkymist.dvisampler.edid import EDID
-from milkymist.dvisampler.clocking import Clocking
-from milkymist.dvisampler.datacapture import DataCapture
-
-class RawDVISampler(Module, AutoCSR):
- def __init__(self, pads, asmiport):
- self.submodules.edid = EDID(pads)
- self.submodules.clocking = Clocking(pads)
-
- invert = False
- try:
- s = getattr(pads, "data0")
- except AttributeError:
- s = getattr(pads, "data0_n")
- invert = True
- self.submodules.data0_cap = DataCapture(8, invert)
- self.comb += [
- self.data0_cap.pad.eq(s),
- self.data0_cap.serdesstrobe.eq(self.clocking.serdesstrobe)
- ]
-
- fifo = RenameClockDomains(AsyncFIFO(10, 256),
- {"write": "pix", "read": "sys"})
- self.submodules += fifo
- self.comb += [
- fifo.din.eq(self.data0_cap.d),
- fifo.we.eq(1)
- ]
-
- pack_factor = asmiport.hub.dw//16
- self.submodules.packer = structuring.Pack([("word", 10), ("pad", 6)], pack_factor)
- self.submodules.cast = structuring.Cast(self.packer.source.payload.layout, asmiport.hub.dw)
- self.submodules.dma = spi.DMAWriteController(dma_lasmi.Writer(lasmim), spi.MODE_SINGLE_SHOT)
- self.comb += [
- self.packer.sink.stb.eq(fifo.readable),
- fifo.re.eq(self.packer.sink.ack),
- self.packer.sink.payload.word.eq(fifo.dout),
- self.packer.source.connect_flat(self.cast.sink),
- self.cast.source.connect_flat(self.dma.data)
- ]
+++ /dev/null
-from migen.fhdl.std import *
-from migen.genlib.record import Record
-
-from milkymist.dvisampler.common import control_tokens, channel_layout
-
-class Decoding(Module):
- def __init__(self):
- self.valid_i = Signal()
- self.input = Signal(10)
- self.valid_o = Signal()
- self.output = Record(channel_layout)
-
- ###
-
- self.sync.pix += self.output.de.eq(1)
- for i, t in enumerate(control_tokens):
- self.sync.pix += If(self.input == t,
- self.output.de.eq(0),
- self.output.c.eq(i)
- )
- self.sync.pix += self.output.d[0].eq(self.input[0] ^ self.input[9])
- for i in range(1, 8):
- self.sync.pix += self.output.d[i].eq(self.input[i] ^ self.input[i-1] ^ ~self.input[8])
- self.sync.pix += self.valid_o.eq(self.valid_i)
+++ /dev/null
-from migen.fhdl.std import *
-from migen.genlib.fsm import FSM, NextState
-from migen.bank.description import *
-from migen.bank.eventmanager import *
-from migen.flow.actor import *
-from migen.actorlib import dma_lasmi
-
-from milkymist.dvisampler.common import frame_layout
-
-# Slot status: EMPTY=0 LOADED=1 PENDING=2
-class _Slot(Module, AutoCSR):
- def __init__(self, addr_bits, alignment_bits):
- self.ev_source = EventSourceLevel()
- self.address = Signal(addr_bits)
- self.address_valid = Signal()
- self.address_done = Signal()
-
- self._r_status = CSRStorage(2, write_from_dev=True)
- self._r_address = CSRStorage(addr_bits + alignment_bits, alignment_bits=alignment_bits)
-
- ###
-
- self.comb += [
- self.address.eq(self._r_address.storage),
- self.address_valid.eq(self._r_status.storage[0]),
- self._r_status.dat_w.eq(2),
- self._r_status.we.eq(self.address_done),
- self.ev_source.trigger.eq(self._r_status.storage[1])
- ]
-
-class _SlotArray(Module, AutoCSR):
- def __init__(self, nslots, addr_bits, alignment_bits):
- self.submodules.ev = EventManager()
- self.address = Signal(addr_bits)
- self.address_valid = Signal()
- self.address_done = Signal()
-
- ###
-
- slots = [_Slot(addr_bits, alignment_bits) for i in range(nslots)]
- for n, slot in enumerate(slots):
- setattr(self.submodules, "slot"+str(n), slot)
- setattr(self.ev, "slot"+str(n), slot.ev_source)
- self.ev.finalize()
-
- change_slot = Signal()
- current_slot = Signal(max=nslots)
- self.sync += If(change_slot, [If(slot.address_valid, current_slot.eq(n)) for n, slot in reversed(list(enumerate(slots)))])
- self.comb += change_slot.eq(~self.address_valid | self.address_done)
-
- self.comb += [
- self.address.eq(Array(slot.address for slot in slots)[current_slot]),
- self.address_valid.eq(Array(slot.address_valid for slot in slots)[current_slot])
- ]
- self.comb += [slot.address_done.eq(self.address_done & (current_slot == n)) for n, slot in enumerate(slots)]
-
-class DMA(Module):
- def __init__(self, lasmim, nslots):
- bus_aw = lasmim.aw
- bus_dw = lasmim.dw
- alignment_bits = bits_for(bus_dw//8) - 1
-
- self.frame = Sink(frame_layout)
- self._r_frame_size = CSRStorage(bus_aw + alignment_bits, alignment_bits=alignment_bits)
- self.submodules._slot_array = _SlotArray(nslots, bus_aw, alignment_bits)
- self.ev = self._slot_array.ev
-
- ###
-
- # start of frame detection
- sof = Signal()
- parity_r = Signal()
- self.sync += If(self.frame.stb & self.frame.ack, parity_r.eq(self.frame.payload.parity))
- self.comb += sof.eq(parity_r ^ self.frame.payload.parity)
-
- # address generator + maximum memory word count to prevent DMA buffer overrun
- reset_words = Signal()
- count_word = Signal()
- last_word = Signal()
- current_address = Signal(bus_aw)
- mwords_remaining = Signal(bus_aw)
- self.comb += last_word.eq(mwords_remaining == 1)
- self.sync += [
- If(reset_words,
- current_address.eq(self._slot_array.address),
- mwords_remaining.eq(self._r_frame_size.storage)
- ).Elif(count_word,
- current_address.eq(current_address + 1),
- mwords_remaining.eq(mwords_remaining - 1)
- )
- ]
-
- # pack pixels into memory words
- write_pixel = Signal()
- last_pixel = Signal()
- cur_memory_word = Signal(bus_dw)
- encoded_pixel = Signal(32)
- self.comb += [
- encoded_pixel.eq(Cat(
- self.frame.payload.b[6:], self.frame.payload.b,
- self.frame.payload.g[6:], self.frame.payload.g,
- self.frame.payload.r[6:], self.frame.payload.r))
- ]
- pack_factor = bus_dw//32
- assert(pack_factor & (pack_factor - 1) == 0) # only support powers of 2
- pack_counter = Signal(max=pack_factor)
- self.comb += last_pixel.eq(pack_counter == (pack_factor - 1))
- self.sync += If(write_pixel,
- [If(pack_counter == (pack_factor-i-1),
- cur_memory_word[32*i:32*(i+1)].eq(encoded_pixel)) for i in range(pack_factor)],
- pack_counter.eq(pack_counter + 1)
- )
-
- # bus accessor
- self.submodules._bus_accessor = dma_lasmi.Writer(lasmim)
- self.comb += [
- self._bus_accessor.address_data.payload.a.eq(current_address),
- self._bus_accessor.address_data.payload.d.eq(cur_memory_word)
- ]
-
- # control FSM
- fsm = FSM()
- self.submodules += fsm
-
- fsm.act("WAIT_SOF",
- reset_words.eq(1),
- self.frame.ack.eq(~self._slot_array.address_valid | ~sof),
- If(self._slot_array.address_valid & sof & self.frame.stb, NextState("TRANSFER_PIXEL"))
- )
- fsm.act("TRANSFER_PIXEL",
- self.frame.ack.eq(1),
- If(self.frame.stb,
- write_pixel.eq(1),
- If(last_pixel, NextState("TO_MEMORY"))
- )
- )
- fsm.act("TO_MEMORY",
- self._bus_accessor.address_data.stb.eq(1),
- If(self._bus_accessor.address_data.ack,
- count_word.eq(1),
- If(last_word,
- NextState("EOF")
- ).Else(
- NextState("TRANSFER_PIXEL")
- )
- )
- )
- fsm.act("EOF",
- If(~self._bus_accessor.busy,
- self._slot_array.address_done.eq(1),
- NextState("WAIT_SOF")
- )
- )
-
- def get_csrs(self):
- return [self._r_frame_size] + self._slot_array.get_csrs()
+++ /dev/null
-from migen.fhdl.std import *
-from migen.fhdl.specials import Tristate
-from migen.genlib.cdc import MultiReg
-from migen.genlib.fsm import FSM, NextState
-from migen.genlib.misc import chooser
-from migen.bank.description import CSRStorage, CSRStatus, AutoCSR
-
-_default_edid = [
- 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x3D, 0x17, 0x32, 0x12, 0x2A, 0x6A, 0xBF, 0x00,
- 0x05, 0x17, 0x01, 0x03, 0x80, 0x28, 0x1E, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xB2, 0x0C, 0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x18, 0x88,
- 0x36, 0x00, 0x28, 0x1E, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x4D, 0x31, 0x20,
- 0x44, 0x56, 0x49, 0x20, 0x6D, 0x69, 0x78, 0x65, 0x72, 0x0A, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34,
-]
-
-class EDID(Module, AutoCSR):
- def __init__(self, pads, default=_default_edid):
- self._r_hpd_notif = CSRStatus()
- self._r_hpd_en = CSRStorage()
- self.specials.mem = Memory(8, 128, init=default)
-
- ###
-
- # HPD
- if hasattr(pads, "hpd_notif"):
- self.specials += MultiReg(pads.hpd_notif, self._r_hpd_notif.status)
- else:
- self.comb += self._r_hpd_notif.status.eq(1)
- if hasattr(pads, "hpd_en"):
- self.comb += pads.hpd_en.eq(self._r_hpd_en.storage)
-
- # EDID
- scl_raw = Signal()
- sda_i = Signal()
- sda_drv = Signal()
- _sda_drv_reg = Signal()
- _sda_i_async = Signal()
- self.sync += _sda_drv_reg.eq(sda_drv)
- self.specials += [
- MultiReg(pads.scl, scl_raw),
- Tristate(pads.sda, 0, _sda_drv_reg, _sda_i_async),
- MultiReg(_sda_i_async, sda_i)
- ]
-
- scl_i = Signal()
- samp_count = Signal(6)
- samp_carry = Signal()
- self.sync += [
- Cat(samp_count, samp_carry).eq(samp_count + 1),
- If(samp_carry, scl_i.eq(scl_raw))
- ]
-
- scl_r = Signal()
- sda_r = Signal()
- scl_rising = Signal()
- sda_rising = Signal()
- sda_falling = Signal()
- self.sync += [
- scl_r.eq(scl_i),
- sda_r.eq(sda_i)
- ]
- self.comb += [
- scl_rising.eq(scl_i & ~scl_r),
- sda_rising.eq(sda_i & ~sda_r),
- sda_falling.eq(~sda_i & sda_r)
- ]
-
- start = Signal()
- self.comb += start.eq(scl_i & sda_falling)
-
- din = Signal(8)
- counter = Signal(max=9)
- self.sync += [
- If(start, counter.eq(0)),
- If(scl_rising,
- If(counter == 8,
- counter.eq(0)
- ).Else(
- counter.eq(counter + 1),
- din.eq(Cat(sda_i, din[:7]))
- )
- )
- ]
-
- is_read = Signal()
- update_is_read = Signal()
- self.sync += If(update_is_read, is_read.eq(din[0]))
-
- offset_counter = Signal(max=128)
- oc_load = Signal()
- oc_inc = Signal()
- self.sync += [
- If(oc_load,
- offset_counter.eq(din)
- ).Elif(oc_inc,
- offset_counter.eq(offset_counter + 1)
- )
- ]
- rdport = self.mem.get_port()
- self.specials += rdport
- self.comb += rdport.adr.eq(offset_counter)
- data_bit = Signal()
-
- zero_drv = Signal()
- data_drv = Signal()
- self.comb += If(zero_drv, sda_drv.eq(1)).Elif(data_drv, sda_drv.eq(~data_bit))
-
- data_drv_en = Signal()
- data_drv_stop = Signal()
- self.sync += If(data_drv_en, data_drv.eq(1)).Elif(data_drv_stop, data_drv.eq(0))
- self.sync += If(data_drv_en, chooser(rdport.dat_r, counter, data_bit, 8, reverse=True))
-
- fsm = FSM()
- self.submodules += fsm
-
- fsm.act("WAIT_START")
- fsm.act("RCV_ADDRESS",
- If(counter == 8,
- If(din[1:] == 0x50,
- update_is_read.eq(1),
- NextState("ACK_ADDRESS0")
- ).Else(
- NextState("WAIT_START")
- )
- )
- )
- fsm.act("ACK_ADDRESS0",
- If(~scl_i, NextState("ACK_ADDRESS1"))
- )
- fsm.act("ACK_ADDRESS1",
- zero_drv.eq(1),
- If(scl_i, NextState("ACK_ADDRESS2"))
- )
- fsm.act("ACK_ADDRESS2",
- zero_drv.eq(1),
- If(~scl_i,
- If(is_read,
- NextState("READ")
- ).Else(
- NextState("RCV_OFFSET")
- )
- )
- )
-
- fsm.act("RCV_OFFSET",
- If(counter == 8,
- oc_load.eq(1),
- NextState("ACK_OFFSET0")
- )
- )
- fsm.act("ACK_OFFSET0",
- If(~scl_i, NextState("ACK_OFFSET1"))
- )
- fsm.act("ACK_OFFSET1",
- zero_drv.eq(1),
- If(scl_i, NextState("ACK_OFFSET2"))
- )
- fsm.act("ACK_OFFSET2",
- zero_drv.eq(1),
- If(~scl_i, NextState("RCV_ADDRESS"))
- )
-
- fsm.act("READ",
- If(~scl_i,
- If(counter == 8,
- data_drv_stop.eq(1),
- NextState("ACK_READ")
- ).Else(
- data_drv_en.eq(1)
- )
- )
- )
- fsm.act("ACK_READ",
- If(scl_rising,
- oc_inc.eq(1),
- If(sda_i,
- NextState("WAIT_START")
- ).Else(
- NextState("READ")
- )
- )
- )
-
- for state in fsm.actions.keys():
- fsm.act(state, If(start, NextState("RCV_ADDRESS")))
- fsm.act(state, If(~self._r_hpd_en.storage, NextState("WAIT_START")))
+++ /dev/null
-from migen.fhdl.std import *
-from migen.bank.description import *
-from migen.genlib.misc import optree
-from migen.genlib.cdc import PulseSynchronizer
-
-from milkymist.dvisampler.common import control_tokens
-
-class WER(Module, AutoCSR):
- def __init__(self, period_bits=24):
- self.data = Signal(10)
- self._r_update = CSR()
- self._r_value = CSRStatus(period_bits)
-
- ###
-
- # pipeline stage 1
- # we ignore the 10th (inversion) bit, as it is independent of the transition minimization
- data_r = Signal(9)
- self.sync.pix += data_r.eq(self.data[:9])
-
- # pipeline stage 2
- transitions = Signal(8)
- self.comb += [transitions[i].eq(data_r[i] ^ data_r[i+1]) for i in range(8)]
- transition_count = Signal(max=9)
- self.sync.pix += transition_count.eq(optree("+", [transitions[i] for i in range(8)]))
-
- is_control = Signal()
- self.sync.pix += is_control.eq(optree("|", [data_r == ct for ct in control_tokens]))
-
- # pipeline stage 3
- is_error = Signal()
- self.sync.pix += is_error.eq((transition_count > 4) & ~is_control)
-
- # counter
- period_counter = Signal(period_bits)
- period_done = Signal()
- self.sync.pix += Cat(period_counter, period_done).eq(period_counter + 1)
-
- wer_counter = Signal(period_bits)
- wer_counter_r = Signal(period_bits)
- wer_counter_r_updated = Signal()
- self.sync.pix += [
- wer_counter_r_updated.eq(period_done),
- If(period_done,
- wer_counter_r.eq(wer_counter),
- wer_counter.eq(0)
- ).Elif(is_error,
- wer_counter.eq(wer_counter + 1)
- )
- ]
-
- # sync to system clock domain
- wer_counter_sys = Signal(period_bits)
- self.submodules.ps_counter = PulseSynchronizer("pix", "sys")
- self.comb += self.ps_counter.i.eq(wer_counter_r_updated)
- self.sync += If(self.ps_counter.o, wer_counter_sys.eq(wer_counter_r))
-
- # register interface
- self.sync += If(self._r_update.re, self._r_value.status.eq(wer_counter_sys))
+++ /dev/null
-from migen.fhdl.std import *
-from migen.flow.actor import *
-from migen.flow.network import *
-from migen.bank.description import CSRStorage, AutoCSR
-from migen.actorlib import dma_lasmi, structuring, sim, spi
-
-from milkymist.framebuffer.format import bpp, pixel_layout, FrameInitiator, VTG
-from milkymist.framebuffer.phy import Driver
-
-class Framebuffer(Module, AutoCSR):
- def __init__(self, pads_vga, pads_dvi, lasmim, simulation=False):
- pack_factor = lasmim.dw//(2*bpp)
- packed_pixels = structuring.pack_layout(pixel_layout, pack_factor)
-
- self._enable = CSRStorage()
- self.fi = FrameInitiator()
- self.dma = spi.DMAReadController(dma_lasmi.Reader(lasmim), spi.MODE_EXTERNAL, length_reset=640*480*4)
- self.driver = Driver(pads_vga, pads_dvi)
-
- cast = structuring.Cast(lasmim.dw, packed_pixels, reverse_to=True)
- unpack = structuring.Unpack(pack_factor, pixel_layout)
- vtg = VTG()
-
- g = DataFlowGraph()
- g.add_connection(self.fi, vtg, sink_ep="timing")
- g.add_connection(self.dma, cast)
- g.add_connection(cast, unpack)
- g.add_connection(unpack, vtg, sink_ep="pixels")
- g.add_connection(vtg, self.driver)
- self.submodules += CompositeActor(g)
-
- self.comb += [
- self.fi.trigger.eq(self._enable.storage),
- self.dma.generator.trigger.eq(self._enable.storage),
- ]
-
-class Blender(PipelinedActor, AutoCSR):
- def __init__(self, nimages, latency):
- sink_layout = [("i"+str(i), pixel_layout) for i in range(nimages)]
- self.sink = Sink(sink_layout)
- self.source = Source(pixel_layout)
- factors = []
- for i in range(nimages):
- name = "f"+str(i)
- csr = CSRStorage(8, name=name)
- setattr(self, name, csr)
- factors.append(csr.storage)
- PipelinedActor.__init__(self, latency)
-
- ###
-
- sink_registered = Record(sink_layout)
- self.sync += If(self.pipe_ce, sink_registered.eq(self.sink.payload))
-
- imgs = [getattr(sink_registered, "i"+str(i)) for i in range(nimages)]
- outval = Record(pixel_layout)
- for e in pixel_layout:
- name = e[0]
- inpixs = [getattr(img, name) for img in imgs]
- outpix = getattr(outval, name)
- for component in ["r", "g", "b"]:
- incomps = [getattr(pix, component) for pix in inpixs]
- outcomp = getattr(outpix, component)
- outcomp_full = Signal(19)
- self.comb += [
- outcomp_full.eq(sum(incomp*factor for incomp, factor in zip(incomps, factors))),
- If(outcomp_full[18],
- outcomp.eq(2**10 - 1) # saturate on overflow
- ).Else(
- outcomp.eq(outcomp_full[8:18])
- )
- ]
-
- pipe_stmts = []
- for i in range(latency-1):
- new_outval = Record(pixel_layout)
- pipe_stmts.append(new_outval.eq(outval))
- outval = new_outval
- self.sync += If(self.pipe_ce, pipe_stmts)
- self.comb += self.source.payload.eq(outval)
-
-class MixFramebuffer(Module, AutoCSR):
- def __init__(self, pads_vga, pads_dvi, *lasmims, blender_latency=5):
- pack_factor = lasmims[0].dw//(2*bpp)
- packed_pixels = structuring.pack_layout(pixel_layout, pack_factor)
-
- self._enable = CSRStorage()
- self.fi = FrameInitiator()
- self.blender = Blender(len(lasmims), blender_latency)
- self.driver = Driver(pads_vga, pads_dvi)
- self.comb += self.fi.trigger.eq(self._enable.storage)
-
- g = DataFlowGraph()
- for n, lasmim in enumerate(lasmims):
- dma = spi.DMAReadController(dma_lasmi.Reader(lasmim), spi.MODE_EXTERNAL, length_reset=640*480*4)
- cast = structuring.Cast(lasmim.dw, packed_pixels, reverse_to=True)
- unpack = structuring.Unpack(pack_factor, pixel_layout)
-
- g.add_connection(dma, cast)
- g.add_connection(cast, unpack)
- g.add_connection(unpack, self.blender, sink_subr=["i"+str(n)])
-
- self.comb += dma.generator.trigger.eq(self._enable.storage)
- setattr(self, "dma"+str(n), dma)
-
- vtg = VTG()
- g.add_connection(self.fi, vtg, sink_ep="timing")
- g.add_connection(self.blender, vtg, sink_ep="pixels")
- g.add_connection(vtg, self.driver)
- self.submodules += CompositeActor(g)
+++ /dev/null
-from migen.fhdl.std import *
-from migen.genlib.misc import optree
-
-control_tokens = [0b1101010100, 0b0010101011, 0b0101010100, 0b1010101011]
-
-class Encoder(Module):
- def __init__(self):
- self.d = Signal(8)
- self.c = Signal(2)
- self.de = Signal()
-
- self.out = Signal(10)
-
- ###
-
- # stage 1 - count number of 1s in data
- d = Signal(8)
- n1d = Signal(max=9)
- self.sync += [
- n1d.eq(optree("+", [self.d[i] for i in range(8)])),
- d.eq(self.d)
- ]
-
- # stage 2 - add 9th bit
- q_m = Signal(9)
- q_m8_n = Signal()
- self.comb += q_m8_n.eq((n1d > 4) | ((n1d == 4) & ~d[0]))
- for i in range(8):
- if i:
- curval = curval ^ d[i] ^ q_m8_n
- else:
- curval = d[0]
- self.sync += q_m[i].eq(curval)
- self.sync += q_m[8].eq(~q_m8_n)
-
- # stage 3 - count number of 1s and 0s in q_m[:8]
- q_m_r = Signal(9)
- n0q_m = Signal(max=9)
- n1q_m = Signal(max=9)
- self.sync += [
- n0q_m.eq(optree("+", [~q_m[i] for i in range(8)])),
- n1q_m.eq(optree("+", [q_m[i] for i in range(8)])),
- q_m_r.eq(q_m)
- ]
-
- # stage 4 - final encoding
- cnt = Signal((6, True))
-
- s_c = self.c
- s_de = self.de
- for p in range(3):
- new_c = Signal(2)
- new_de = Signal()
- self.sync += new_c.eq(s_c), new_de.eq(s_de)
- s_c, s_de = new_c, new_de
-
- self.sync += If(s_de,
- If((cnt == 0) | (n1q_m == n0q_m),
- self.out[9].eq(~q_m_r[8]),
- self.out[8].eq(q_m_r[8]),
- If(q_m_r[8],
- self.out[:8].eq(q_m_r[:8]),
- cnt.eq(cnt + n1q_m - n0q_m)
- ).Else(
- self.out[:8].eq(~q_m_r[:8]),
- cnt.eq(cnt + n0q_m - n1q_m)
- )
- ).Else(
- If((~cnt[5] & (n1q_m > n0q_m)) | (cnt[5] & (n0q_m > n1q_m)),
- self.out[9].eq(1),
- self.out[8].eq(q_m_r[8]),
- self.out[:8].eq(~q_m_r[:8]),
- cnt.eq(cnt + Cat(0, q_m_r[8]) + n0q_m - n1q_m)
- ).Else(
- self.out[9].eq(0),
- self.out[8].eq(q_m_r[8]),
- self.out[:8].eq(q_m_r[:8]),
- cnt.eq(cnt - Cat(0, ~q_m_r[8]) + n1q_m - n0q_m)
- )
- )
- ).Else(
- self.out.eq(Array(control_tokens)[s_c]),
- cnt.eq(0)
- )
-
-class _EncoderSerializer(Module):
- def __init__(self, serdesstrobe, pad_p, pad_n):
- self.submodules.encoder = RenameClockDomains(Encoder(), "pix")
- self.d, self.c, self.de = self.encoder.d, self.encoder.c, self.encoder.de
-
- ###
-
- # 2X soft serialization
- ed_2x = Signal(5)
- self.sync.pix2x += ed_2x.eq(Mux(ClockSignal("pix"), self.encoder.out[:5], self.encoder.out[5:]))
-
- # 5X hard serialization
- cascade_di = Signal()
- cascade_do = Signal()
- cascade_ti = Signal()
- cascade_to = Signal()
- pad_se = Signal()
- self.specials += [
- Instance("OSERDES2",
- p_DATA_WIDTH=5, p_DATA_RATE_OQ="SDR", p_DATA_RATE_OT="SDR",
- p_SERDES_MODE="MASTER", p_OUTPUT_MODE="DIFFERENTIAL",
-
- o_OQ=pad_se,
- i_OCE=1, i_IOCE=serdesstrobe, i_RST=0,
- i_CLK0=ClockSignal("pix10x"), i_CLK1=0, i_CLKDIV=ClockSignal("pix2x"),
- i_D1=ed_2x[4], i_D2=0, i_D3=0, i_D4=0,
- i_T1=0, i_T2=0, i_T3=0, i_T4=0,
- i_TRAIN=0, i_TCE=1,
- i_SHIFTIN1=1, i_SHIFTIN2=1,
- i_SHIFTIN3=cascade_do, i_SHIFTIN4=cascade_to,
- o_SHIFTOUT1=cascade_di, o_SHIFTOUT2=cascade_ti),
- Instance("OSERDES2",
- p_DATA_WIDTH=5, p_DATA_RATE_OQ="SDR", p_DATA_RATE_OT="SDR",
- p_SERDES_MODE="SLAVE", p_OUTPUT_MODE="DIFFERENTIAL",
-
- i_OCE=1, i_IOCE=serdesstrobe, i_RST=0,
- i_CLK0=ClockSignal("pix10x"), i_CLK1=0, i_CLKDIV=ClockSignal("pix2x"),
- i_D1=ed_2x[0], i_D2=ed_2x[1], i_D3=ed_2x[2], i_D4=ed_2x[3],
- i_T1=0, i_T2=0, i_T3=0, i_T4=0,
- i_TRAIN=0, i_TCE=1,
- i_SHIFTIN1=cascade_di, i_SHIFTIN2=cascade_ti,
- i_SHIFTIN3=1, i_SHIFTIN4=1,
- o_SHIFTOUT3=cascade_do, o_SHIFTOUT4=cascade_to),
- Instance("OBUFDS", i_I=pad_se, o_O=pad_p, o_OB=pad_n)
- ]
-
-
-class PHY(Module):
- def __init__(self, serdesstrobe, pads):
- self.hsync = Signal()
- self.vsync = Signal()
- self.de = Signal()
- self.r = Signal(8)
- self.g = Signal(8)
- self.b = Signal(8)
-
- ###
-
- self.submodules.es0 = _EncoderSerializer(serdesstrobe, pads.data0_p, pads.data0_n)
- self.submodules.es1 = _EncoderSerializer(serdesstrobe, pads.data1_p, pads.data1_n)
- self.submodules.es2 = _EncoderSerializer(serdesstrobe, pads.data2_p, pads.data2_n)
- self.comb += [
- self.es0.d.eq(self.r),
- self.es1.d.eq(self.g),
- self.es2.d.eq(self.b),
- self.es0.c.eq(Cat(self.hsync, self.vsync)),
- self.es1.c.eq(0),
- self.es2.c.eq(0),
- self.es0.de.eq(self.de),
- self.es1.de.eq(self.de),
- self.es2.de.eq(self.de),
- ]
-
-class _EncoderTB(Module):
- def __init__(self, inputs):
- self.outs = []
- self._iter_inputs = iter(inputs)
- self._end_cycle = None
- self.submodules.dut = Encoder()
- self.comb += self.dut.de.eq(1)
-
- def do_simulation(self, s):
- if self._end_cycle is None:
- try:
- nv = next(self._iter_inputs)
- except StopIteration:
- self._end_cycle = s.cycle_counter + 4
- else:
- s.wr(self.dut.d, nv)
- if s.cycle_counter == self._end_cycle:
- s.interrupt = True
- if s.cycle_counter > 4:
- self.outs.append(s.rd(self.dut.out))
-
-def _bit(i, n):
- return (i >> n) & 1
-
-def _decode_tmds(b):
- try:
- c = control_tokens.index(b)
- de = False
- except ValueError:
- c = 0
- de = True
- vsync = bool(c & 2)
- hsync = bool(c & 1)
-
- value = _bit(b, 0) ^ _bit(b, 9)
- for i in range(1, 8):
- value |= (_bit(b, i) ^ _bit(b, i-1) ^ (~_bit(b, 8) & 1)) << i
-
- return de, hsync, vsync, value
-
-if __name__ == "__main__":
- from migen.sim.generic import Simulator
- from random import Random
-
- rng = Random(788)
- test_list = [rng.randrange(256) for i in range(500)]
- tb = _EncoderTB(test_list)
- Simulator(tb).run()
-
- check = [_decode_tmds(out)[3] for out in tb.outs]
- assert(check == test_list)
-
- nb0 = 0
- nb1 = 0
- for out in tb.outs:
- for i in range(10):
- if _bit(out, i):
- nb1 += 1
- else:
- nb0 += 1
- print("0/1: {}/{} ({:.2f})".format(nb0, nb1, nb0/nb1))
+++ /dev/null
-from migen.fhdl.std import *
-from migen.flow.actor import *
-from migen.bank.description import CSRStorage
-from migen.actorlib import spi
-
-_hbits = 11
-_vbits = 12
-
-bpp = 32
-bpc = 10
-pixel_layout_s = [
- ("pad", bpp-3*bpc),
- ("r", bpc),
- ("g", bpc),
- ("b", bpc)
-]
-pixel_layout = [
- ("p0", pixel_layout_s),
- ("p1", pixel_layout_s)
-]
-
-bpc_phy = 8
-phy_layout_s = [
- ("r", bpc_phy),
- ("g", bpc_phy),
- ("b", bpc_phy)
-]
-phy_layout = [
- ("hsync", 1),
- ("vsync", 1),
- ("de", 1),
- ("p0", phy_layout_s),
- ("p1", phy_layout_s)
-]
-
-class FrameInitiator(spi.SingleGenerator):
- def __init__(self):
- layout = [
- ("hres", _hbits, 640, 1),
- ("hsync_start", _hbits, 656, 1),
- ("hsync_end", _hbits, 752, 1),
- ("hscan", _hbits, 800, 1),
-
- ("vres", _vbits, 480),
- ("vsync_start", _vbits, 492),
- ("vsync_end", _vbits, 494),
- ("vscan", _vbits, 525)
- ]
- spi.SingleGenerator.__init__(self, layout, spi.MODE_EXTERNAL)
-
-class VTG(Module):
- def __init__(self):
- self.timing = Sink([
- ("hres", _hbits),
- ("hsync_start", _hbits),
- ("hsync_end", _hbits),
- ("hscan", _hbits),
- ("vres", _vbits),
- ("vsync_start", _vbits),
- ("vsync_end", _vbits),
- ("vscan", _vbits)])
- self.pixels = Sink(pixel_layout)
- self.phy = Source(phy_layout)
- self.busy = Signal()
-
- hactive = Signal()
- vactive = Signal()
- active = Signal()
-
- generate_en = Signal()
- hcounter = Signal(_hbits)
- vcounter = Signal(_vbits)
-
- skip = bpc - bpc_phy
- self.comb += [
- active.eq(hactive & vactive),
- If(active,
- [getattr(getattr(self.phy.payload, p), c).eq(getattr(getattr(self.pixels.payload, p), c)[skip:])
- for p in ["p0", "p1"] for c in ["r", "g", "b"]],
- self.phy.payload.de.eq(1)
- ),
-
- generate_en.eq(self.timing.stb & (~active | self.pixels.stb)),
- self.pixels.ack.eq(self.phy.ack & active),
- self.phy.stb.eq(generate_en),
- self.busy.eq(generate_en)
- ]
- tp = self.timing.payload
- self.sync += [
- self.timing.ack.eq(0),
- If(generate_en & self.phy.ack,
- hcounter.eq(hcounter + 1),
-
- If(hcounter == 0, hactive.eq(1)),
- If(hcounter == tp.hres, hactive.eq(0)),
- If(hcounter == tp.hsync_start, self.phy.payload.hsync.eq(1)),
- If(hcounter == tp.hsync_end, self.phy.payload.hsync.eq(0)),
- If(hcounter == tp.hscan,
- hcounter.eq(0),
- If(vcounter == tp.vscan,
- vcounter.eq(0),
- self.timing.ack.eq(1)
- ).Else(
- vcounter.eq(vcounter + 1)
- )
- ),
-
- If(vcounter == 0, vactive.eq(1)),
- If(vcounter == tp.vres, vactive.eq(0)),
- If(vcounter == tp.vsync_start, self.phy.payload.vsync.eq(1)),
- If(vcounter == tp.vsync_end, self.phy.payload.vsync.eq(0))
- )
- ]
+++ /dev/null
-from migen.fhdl.std import *
-from migen.genlib.fifo import AsyncFIFO
-from migen.genlib.cdc import MultiReg
-from migen.bank.description import *
-from migen.flow.actor import *
-
-from milkymist.framebuffer.format import bpc_phy, phy_layout
-from milkymist.framebuffer import dvi
-
-class _FIFO(Module):
- def __init__(self):
- self.phy = Sink(phy_layout)
- self.busy = Signal()
-
- self.pix_hsync = Signal()
- self.pix_vsync = Signal()
- self.pix_de = Signal()
- self.pix_r = Signal(bpc_phy)
- self.pix_g = Signal(bpc_phy)
- self.pix_b = Signal(bpc_phy)
-
- ###
-
- fifo = RenameClockDomains(AsyncFIFO(phy_layout, 512),
- {"write": "sys", "read": "pix"})
- self.submodules += fifo
- self.comb += [
- self.phy.ack.eq(fifo.writable),
- fifo.we.eq(self.phy.stb),
- fifo.din.eq(self.phy.payload),
- self.busy.eq(0)
- ]
-
- pix_parity = Signal()
- self.sync.pix += [
- pix_parity.eq(~pix_parity),
- self.pix_hsync.eq(fifo.dout.hsync),
- self.pix_vsync.eq(fifo.dout.vsync),
- self.pix_de.eq(fifo.dout.de),
- If(pix_parity,
- self.pix_r.eq(fifo.dout.p1.r),
- self.pix_g.eq(fifo.dout.p1.g),
- self.pix_b.eq(fifo.dout.p1.b)
- ).Else(
- self.pix_r.eq(fifo.dout.p0.r),
- self.pix_g.eq(fifo.dout.p0.g),
- self.pix_b.eq(fifo.dout.p0.b)
- )
- ]
- self.comb += fifo.re.eq(pix_parity)
-
-# This assumes a 50MHz base clock
-class _Clocking(Module, AutoCSR):
- def __init__(self, pads_vga, pads_dvi):
- self._r_cmd_data = CSRStorage(10)
- self._r_send_cmd_data = CSR()
- self._r_send_go = CSR()
- self._r_status = CSRStatus(4)
-
- self.clock_domains.cd_pix = ClockDomain(reset_less=True)
- if pads_dvi is not None:
- self.clock_domains.cd_pix2x = ClockDomain(reset_less=True)
- self.clock_domains.cd_pix10x = ClockDomain(reset_less=True)
- self.serdesstrobe = Signal()
-
- ###
-
- # Generate 1x pixel clock
- clk_pix_unbuffered = Signal()
- pix_progdata = Signal()
- pix_progen = Signal()
- pix_progdone = Signal()
- pix_locked = Signal()
- self.specials += Instance("DCM_CLKGEN",
- p_CLKFXDV_DIVIDE=2, p_CLKFX_DIVIDE=4, p_CLKFX_MD_MAX=1.0, p_CLKFX_MULTIPLY=2,
- p_CLKIN_PERIOD=20.0, p_SPREAD_SPECTRUM="NONE", p_STARTUP_WAIT="FALSE",
-
- i_CLKIN=ClockSignal("base50"), o_CLKFX=clk_pix_unbuffered,
- i_PROGCLK=ClockSignal(), i_PROGDATA=pix_progdata, i_PROGEN=pix_progen,
- o_PROGDONE=pix_progdone, o_LOCKED=pix_locked,
- i_FREEZEDCM=0, i_RST=ResetSignal())
-
- remaining_bits = Signal(max=11)
- transmitting = Signal()
- self.comb += transmitting.eq(remaining_bits != 0)
- sr = Signal(10)
- self.sync += [
- If(self._r_send_cmd_data.re,
- remaining_bits.eq(10),
- sr.eq(self._r_cmd_data.storage)
- ).Elif(transmitting,
- remaining_bits.eq(remaining_bits - 1),
- sr.eq(sr[1:])
- )
- ]
- self.comb += [
- pix_progdata.eq(transmitting & sr[0]),
- pix_progen.eq(transmitting | self._r_send_go.re)
- ]
-
- # enforce gap between commands
- busy_counter = Signal(max=14)
- busy = Signal()
- self.comb += busy.eq(busy_counter != 0)
- self.sync += If(self._r_send_cmd_data.re,
- busy_counter.eq(13)
- ).Elif(busy,
- busy_counter.eq(busy_counter - 1)
- )
-
- mult_locked = Signal()
- self.comb += self._r_status.status.eq(Cat(busy, pix_progdone, pix_locked, mult_locked))
-
- # Clock multiplication and buffering
- if pads_dvi is None:
- # Just buffer 1x pixel clock
- self.specials += Instance("BUFG", i_I=clk_pix_unbuffered, o_O=self.cd_pix.clk)
- self.comb += mult_locked.eq(pix_locked)
- else:
- # Route unbuffered 1x pixel clock to PLL
- # Generate 1x, 2x and 10x IO pixel clocks
- clkfbout = Signal()
- pll_locked = Signal()
- pll_clk0 = Signal()
- pll_clk1 = Signal()
- pll_clk2 = Signal()
- locked_async = Signal()
- self.specials += [
- Instance("PLL_BASE",
- p_CLKIN_PERIOD=26.7,
- p_CLKFBOUT_MULT=20,
- p_CLKOUT0_DIVIDE=2, # pix10x
- p_CLKOUT1_DIVIDE=10, # pix2x
- p_CLKOUT2_DIVIDE=20, # pix
- p_COMPENSATION="INTERNAL",
-
- i_CLKIN=clk_pix_unbuffered,
- o_CLKOUT0=pll_clk0, o_CLKOUT1=pll_clk1, o_CLKOUT2=pll_clk2,
- o_CLKFBOUT=clkfbout, i_CLKFBIN=clkfbout,
- o_LOCKED=pll_locked, i_RST=~pix_locked),
- Instance("BUFPLL", p_DIVIDE=5,
- i_PLLIN=pll_clk0, i_GCLK=ClockSignal("pix2x"), i_LOCKED=pll_locked,
- o_IOCLK=self.cd_pix10x.clk, o_LOCK=locked_async, o_SERDESSTROBE=self.serdesstrobe),
- Instance("BUFG", i_I=pll_clk1, o_O=self.cd_pix2x.clk),
- Instance("BUFG", name="dviout_pix_bufg", i_I=pll_clk2, o_O=self.cd_pix.clk),
- MultiReg(locked_async, mult_locked, "sys")
- ]
-
- # Drive VGA/DVI clock pads
- if pads_vga is not None:
- self.specials += Instance("ODDR2",
- p_DDR_ALIGNMENT="NONE", p_INIT=0, p_SRTYPE="SYNC",
- o_Q=pads_vga.clk,
- i_C0=ClockSignal("pix"),
- i_C1=~ClockSignal("pix"),
- i_CE=1, i_D0=1, i_D1=0,
- i_R=0, i_S=0)
- if pads_dvi is not None:
- dvi_clk_se = Signal()
- self.specials += Instance("ODDR2",
- p_DDR_ALIGNMENT="NONE", p_INIT=0, p_SRTYPE="SYNC",
- o_Q=dvi_clk_se,
- i_C0=ClockSignal("pix"),
- i_C1=~ClockSignal("pix"),
- i_CE=1, i_D0=1, i_D1=0,
- i_R=0, i_S=0)
- self.specials += Instance("OBUFDS", i_I=dvi_clk_se,
- o_O=pads_dvi.clk_p, o_OB=pads_dvi.clk_n)
-
-class Driver(Module, AutoCSR):
- def __init__(self, pads_vga, pads_dvi):
- fifo = _FIFO()
- self.submodules += fifo
- self.phy = fifo.phy
- self.busy = fifo.busy
-
- self.submodules.clocking = _Clocking(pads_vga, pads_dvi)
-
- if pads_vga is not None:
- self.comb += [
- pads_vga.hsync_n.eq(~fifo.pix_hsync),
- pads_vga.vsync_n.eq(~fifo.pix_vsync),
- pads_vga.r.eq(fifo.pix_r),
- pads_vga.g.eq(fifo.pix_g),
- pads_vga.b.eq(fifo.pix_b),
- pads_vga.psave_n.eq(1)
- ]
- if pads_dvi is not None:
- self.submodules.dvi_phy = dvi.PHY(self.clocking.serdesstrobe, pads_dvi)
- self.comb += [
- self.dvi_phy.hsync.eq(fifo.pix_hsync),
- self.dvi_phy.vsync.eq(fifo.pix_vsync),
- self.dvi_phy.de.eq(fifo.pix_de),
- self.dvi_phy.r.eq(fifo.pix_r),
- self.dvi_phy.g.eq(fifo.pix_g),
- self.dvi_phy.b.eq(fifo.pix_b)
- ]
+++ /dev/null
-from migen.fhdl.std import *
-from migen.genlib.cdc import MultiReg
-from migen.bank.description import *
-
-class GPIOIn(Module, AutoCSR):
- def __init__(self, signal):
- self._r_in = CSRStatus(flen(signal))
- self.specials += MultiReg(signal, self._r_in.status)
-
-class GPIOOut(Module, AutoCSR):
- def __init__(self, signal):
- self._r_out = CSRStorage(flen(signal))
- self.comb += signal.eq(self._r_out.storage)
-
-class Blinker(Module):
- def __init__(self, signal, divbits=26):
- counter = Signal(divbits)
- self.comb += signal.eq(counter[divbits-1])
- self.sync += counter.eq(counter + 1)
+++ /dev/null
-import re
-
-from migen.fhdl.std import *
-from migen.bank.description import *
-
-def encode_version(version):
- match = re.match("(\d+)\.(\d+)(\.(\d+))?(rc(\d+))?", version, re.IGNORECASE)
- r = (int(match.group(1)) << 12) | (int(match.group(2)) << 8)
- subminor = match.group(4)
- rc = match.group(6)
- if subminor:
- r |= int(subminor) << 4
- if rc:
- r |= int(rc)
- return r
-
-class Identifier(Module, AutoCSR):
- def __init__(self, sysid, version, frequency):
- self._r_sysid = CSRStatus(16)
- self._r_version = CSRStatus(16)
- self._r_frequency = CSRStatus(32)
-
- ###
-
- self.comb += [
- self._r_sysid.status.eq(sysid),
- self._r_version.status.eq(encode_version(version)),
- self._r_frequency.status.eq(frequency)
- ]
+++ /dev/null
-from collections import namedtuple
-
-from migen.fhdl.std import *
-from migen.bus import dfi, lasmibus
-
-from milkymist.lasmicon.refresher import *
-from milkymist.lasmicon.bankmachine import *
-from milkymist.lasmicon.multiplexer import *
-
-PhySettings = namedtuple("PhySettings", "memtype dfi_d nphases rdphase wrphase rdcmdphase wrcmdphase cl read_latency write_latency")
-
-class GeomSettings(namedtuple("_GeomSettings", "bank_a row_a col_a")):
- def __init__(self, *args, **kwargs):
- self.mux_a = max(self.row_a, self.col_a)
-
-TimingSettings = namedtuple("TimingSettings", "tRP tRCD tWR tWTR tREFI tRFC" \
- " req_queue_size read_time write_time")
-
-class LASMIcon(Module):
- def __init__(self, phy_settings, geom_settings, timing_settings):
- if phy_settings.memtype in ["SDR"]:
- burst_length = phy_settings.nphases*1 # command multiplication*SDR
- elif phy_settings.memtype in ["DDR", "LPDDR", "DDR2", "DDR3"]:
- burst_length = phy_settings.nphases*2 # command multiplication*DDR
- address_align = log2_int(burst_length)
-
- self.dfi = dfi.Interface(geom_settings.mux_a,
- geom_settings.bank_a,
- phy_settings.dfi_d,
- phy_settings.nphases)
- self.lasmic = lasmibus.Interface(
- aw=geom_settings.row_a + geom_settings.col_a - address_align,
- dw=phy_settings.dfi_d*phy_settings.nphases,
- nbanks=2**geom_settings.bank_a,
- req_queue_size=timing_settings.req_queue_size,
- read_latency=phy_settings.read_latency+1,
- write_latency=phy_settings.write_latency+1)
- self.nrowbits = geom_settings.col_a - address_align
-
- ###
-
- self.submodules.refresher = Refresher(geom_settings.mux_a, geom_settings.bank_a,
- timing_settings.tRP, timing_settings.tREFI, timing_settings.tRFC)
- self.submodules.bank_machines = [BankMachine(geom_settings, timing_settings, address_align, i,
- getattr(self.lasmic, "bank"+str(i)))
- for i in range(2**geom_settings.bank_a)]
- self.submodules.multiplexer = Multiplexer(phy_settings, geom_settings, timing_settings,
- self.bank_machines, self.refresher,
- self.dfi, self.lasmic)
-
- def get_csrs(self):
- return self.multiplexer.get_csrs()
+++ /dev/null
-from migen.fhdl.std import *
-from migen.genlib.roundrobin import *
-from migen.genlib.fsm import FSM, NextState
-from migen.genlib.misc import optree
-from migen.genlib.fifo import SyncFIFO
-
-from milkymist.lasmicon.multiplexer import *
-
-class _AddressSlicer:
- def __init__(self, col_a, address_align):
- self.col_a = col_a
- self.address_align = address_align
-
- def row(self, address):
- split = self.col_a - self.address_align
- if isinstance(address, int):
- return address >> split
- else:
- return address[split:]
-
- def col(self, address):
- split = self.col_a - self.address_align
- if isinstance(address, int):
- return (address & (2**split - 1)) << self.address_align
- else:
- return Cat(Replicate(0, self.address_align), address[:split])
-
-class BankMachine(Module):
- def __init__(self, geom_settings, timing_settings, address_align, bankn, req):
- self.refresh_req = Signal()
- self.refresh_gnt = Signal()
- self.cmd = CommandRequestRW(geom_settings.mux_a, geom_settings.bank_a)
-
- ###
-
- # Request FIFO
- self.submodules.req_fifo = SyncFIFO([("we", 1), ("adr", flen(req.adr))], timing_settings.req_queue_size)
- self.comb += [
- self.req_fifo.din.we.eq(req.we),
- self.req_fifo.din.adr.eq(req.adr),
- self.req_fifo.we.eq(req.stb),
- req.req_ack.eq(self.req_fifo.writable),
-
- self.req_fifo.re.eq(req.dat_ack),
- req.lock.eq(self.req_fifo.readable)
- ]
- reqf = self.req_fifo.dout
-
- slicer = _AddressSlicer(geom_settings.col_a, address_align)
-
- # Row tracking
- has_openrow = Signal()
- openrow = Signal(geom_settings.row_a)
- hit = Signal()
- self.comb += hit.eq(openrow == slicer.row(reqf.adr))
- track_open = Signal()
- track_close = Signal()
- self.sync += [
- If(track_open,
- has_openrow.eq(1),
- openrow.eq(slicer.row(reqf.adr))
- ),
- If(track_close,
- has_openrow.eq(0)
- )
- ]
-
- # Address generation
- s_row_adr = Signal()
- self.comb += [
- self.cmd.ba.eq(bankn),
- If(s_row_adr,
- self.cmd.a.eq(slicer.row(reqf.adr))
- ).Else(
- self.cmd.a.eq(slicer.col(reqf.adr))
- )
- ]
-
- # Respect write-to-precharge specification
- precharge_ok = Signal()
- t_unsafe_precharge = 2 + timing_settings.tWR - 1
- unsafe_precharge_count = Signal(max=t_unsafe_precharge+1)
- self.comb += precharge_ok.eq(unsafe_precharge_count == 0)
- self.sync += [
- If(self.cmd.stb & self.cmd.ack & self.cmd.is_write,
- unsafe_precharge_count.eq(t_unsafe_precharge)
- ).Elif(~precharge_ok,
- unsafe_precharge_count.eq(unsafe_precharge_count-1)
- )
- ]
-
- # Control and command generation FSM
- fsm = FSM()
- self.submodules += fsm
- fsm.act("REGULAR",
- If(self.refresh_req,
- NextState("REFRESH")
- ).Elif(self.req_fifo.readable,
- If(has_openrow,
- If(hit,
- # NB: write-to-read specification is enforced by multiplexer
- self.cmd.stb.eq(1),
- req.dat_ack.eq(self.cmd.ack),
- self.cmd.is_read.eq(~reqf.we),
- self.cmd.is_write.eq(reqf.we),
- self.cmd.cas_n.eq(0),
- self.cmd.we_n.eq(~reqf.we)
- ).Else(
- NextState("PRECHARGE")
- )
- ).Else(
- NextState("ACTIVATE")
- )
- )
- )
- fsm.act("PRECHARGE",
- # Notes:
- # 1. we are presenting the column address, A10 is always low
- # 2. since we always go to the ACTIVATE state, we do not need
- # to assert track_close.
- If(precharge_ok,
- self.cmd.stb.eq(1),
- If(self.cmd.ack, NextState("TRP")),
- self.cmd.ras_n.eq(0),
- self.cmd.we_n.eq(0),
- self.cmd.is_cmd.eq(1)
- )
- )
- fsm.act("ACTIVATE",
- s_row_adr.eq(1),
- track_open.eq(1),
- self.cmd.stb.eq(1),
- self.cmd.is_cmd.eq(1),
- If(self.cmd.ack, NextState("TRCD")),
- self.cmd.ras_n.eq(0)
- )
- fsm.act("REFRESH",
- self.refresh_gnt.eq(precharge_ok),
- track_close.eq(1),
- self.cmd.is_cmd.eq(1),
- If(~self.refresh_req, NextState("REGULAR"))
- )
- fsm.delayed_enter("TRP", "ACTIVATE", timing_settings.tRP-1)
- fsm.delayed_enter("TRCD", "REGULAR", timing_settings.tRCD-1)
+++ /dev/null
-from migen.fhdl.std import *
-from migen.genlib.roundrobin import *
-from migen.genlib.misc import optree
-from migen.genlib.fsm import FSM, NextState
-from migen.bank.description import AutoCSR
-
-from milkymist.lasmicon.perf import Bandwidth
-
-class CommandRequest:
- def __init__(self, a, ba):
- self.a = Signal(a)
- self.ba = Signal(ba)
- self.cas_n = Signal(reset=1)
- self.ras_n = Signal(reset=1)
- self.we_n = Signal(reset=1)
-
-class CommandRequestRW(CommandRequest):
- def __init__(self, a, ba):
- CommandRequest.__init__(self, a, ba)
- self.stb = Signal()
- self.ack = Signal()
- self.is_cmd = Signal()
- self.is_read = Signal()
- self.is_write = Signal()
-
-class _CommandChooser(Module):
- def __init__(self, requests):
- self.want_reads = Signal()
- self.want_writes = Signal()
- self.want_cmds = Signal()
- # NB: cas_n/ras_n/we_n are 1 when stb is inactive
- self.cmd = CommandRequestRW(flen(requests[0].a), flen(requests[0].ba))
-
- ###
-
- rr = RoundRobin(len(requests), SP_CE)
- self.submodules += rr
-
- self.comb += [rr.request[i].eq(req.stb & ((req.is_cmd & self.want_cmds) | ((req.is_read == self.want_reads) | (req.is_write == self.want_writes))))
- for i, req in enumerate(requests)]
-
- stb = Signal()
- self.comb += stb.eq(Array(req.stb for req in requests)[rr.grant])
- for name in ["a", "ba", "is_read", "is_write", "is_cmd"]:
- choices = Array(getattr(req, name) for req in requests)
- self.comb += getattr(self.cmd, name).eq(choices[rr.grant])
- for name in ["cas_n", "ras_n", "we_n"]:
- # we should only assert those signals when stb is 1
- choices = Array(getattr(req, name) for req in requests)
- self.comb += If(self.cmd.stb, getattr(self.cmd, name).eq(choices[rr.grant]))
- self.comb += self.cmd.stb.eq(stb \
- & ((self.cmd.is_cmd & self.want_cmds) | ((self.cmd.is_read == self.want_reads) \
- & (self.cmd.is_write == self.want_writes))))
-
- self.comb += [If(self.cmd.stb & self.cmd.ack & (rr.grant == i), req.ack.eq(1))
- for i, req in enumerate(requests)]
- self.comb += rr.ce.eq(self.cmd.ack)
-
-class _Steerer(Module):
- def __init__(self, commands, dfi):
- ncmd = len(commands)
- nph = len(dfi.phases)
- self.sel = [Signal(max=ncmd) for i in range(nph)]
-
- ###
-
- def stb_and(cmd, attr):
- if not hasattr(cmd, "stb"):
- return 0
- else:
- return cmd.stb & getattr(cmd, attr)
- for phase, sel in zip(dfi.phases, self.sel):
- self.comb += [
- phase.cke.eq(1),
- phase.cs_n.eq(0)
- ]
- self.sync += [
- phase.address.eq(Array(cmd.a for cmd in commands)[sel]),
- phase.bank.eq(Array(cmd.ba for cmd in commands)[sel]),
- phase.cas_n.eq(Array(cmd.cas_n for cmd in commands)[sel]),
- phase.ras_n.eq(Array(cmd.ras_n for cmd in commands)[sel]),
- phase.we_n.eq(Array(cmd.we_n for cmd in commands)[sel]),
- phase.rddata_en.eq(Array(stb_and(cmd, "is_read") for cmd in commands)[sel]),
- phase.wrdata_en.eq(Array(stb_and(cmd, "is_write") for cmd in commands)[sel])
- ]
-
-class Multiplexer(Module, AutoCSR):
- def __init__(self, phy_settings, geom_settings, timing_settings, bank_machines, refresher, dfi, lasmic):
- assert(phy_settings.nphases == len(dfi.phases))
-
- # Command choosing
- requests = [bm.cmd for bm in bank_machines]
- choose_cmd = _CommandChooser(requests)
- choose_req = _CommandChooser(requests)
- self.comb += [
- choose_cmd.want_reads.eq(0),
- choose_cmd.want_writes.eq(0)
- ]
- if phy_settings.nphases == 1:
- self.comb += [
- choose_cmd.want_cmds.eq(1),
- choose_req.want_cmds.eq(1)
- ]
- self.submodules += choose_cmd, choose_req
-
- # Command steering
- nop = CommandRequest(geom_settings.mux_a, geom_settings.bank_a)
- commands = [nop, choose_cmd.cmd, choose_req.cmd, refresher.cmd] # nop must be 1st
- (STEER_NOP, STEER_CMD, STEER_REQ, STEER_REFRESH) = range(4)
- steerer = _Steerer(commands, dfi)
- self.submodules += steerer
-
- # Read/write turnaround
- read_available = Signal()
- write_available = Signal()
- self.comb += [
- read_available.eq(optree("|", [req.stb & req.is_read for req in requests])),
- write_available.eq(optree("|", [req.stb & req.is_write for req in requests]))
- ]
-
- def anti_starvation(timeout):
- en = Signal()
- max_time = Signal()
- if timeout:
- t = timeout - 1
- time = Signal(max=t+1)
- self.comb += max_time.eq(time == 0)
- self.sync += If(~en,
- time.eq(t)
- ).Elif(~max_time,
- time.eq(time - 1)
- )
- else:
- self.comb += max_time.eq(0)
- return en, max_time
- read_time_en, max_read_time = anti_starvation(timing_settings.read_time)
- write_time_en, max_write_time = anti_starvation(timing_settings.write_time)
-
- # Refresh
- self.comb += [bm.refresh_req.eq(refresher.req) for bm in bank_machines]
- go_to_refresh = Signal()
- self.comb += go_to_refresh.eq(optree("&", [bm.refresh_gnt for bm in bank_machines]))
-
- # Datapath
- all_rddata = [p.rddata for p in dfi.phases]
- all_wrdata = [p.wrdata for p in dfi.phases]
- all_wrdata_mask = [p.wrdata_mask for p in dfi.phases]
- self.comb += [
- lasmic.dat_r.eq(Cat(*all_rddata)),
- Cat(*all_wrdata).eq(lasmic.dat_w),
- Cat(*all_wrdata_mask).eq(~lasmic.dat_we)
- ]
-
- # Control FSM
- fsm = FSM()
- self.submodules += fsm
-
- def steerer_sel(steerer, phy_settings, r_w_n):
- r = []
- for i in range(phy_settings.nphases):
- s = steerer.sel[i].eq(STEER_NOP)
- if r_w_n == "read":
- if i == phy_settings.rdphase:
- s = steerer.sel[i].eq(STEER_REQ)
- elif i == phy_settings.rdcmdphase:
- s = steerer.sel[i].eq(STEER_CMD)
- elif r_w_n == "write":
- if i == phy_settings.wrphase:
- s = steerer.sel[i].eq(STEER_REQ)
- elif i == phy_settings.wrcmdphase:
- s = steerer.sel[i].eq(STEER_CMD)
- else:
- raise ValueError
- r.append(s)
- return r
-
- fsm.act("READ",
- read_time_en.eq(1),
- choose_req.want_reads.eq(1),
- choose_cmd.cmd.ack.eq(1),
- choose_req.cmd.ack.eq(1),
- steerer_sel(steerer, phy_settings, "read"),
- If(write_available,
- # TODO: switch only after several cycles of ~read_available?
- If(~read_available | max_read_time, NextState("RTW"))
- ),
- If(go_to_refresh, NextState("REFRESH"))
- )
- fsm.act("WRITE",
- write_time_en.eq(1),
- choose_req.want_writes.eq(1),
- choose_cmd.cmd.ack.eq(1),
- choose_req.cmd.ack.eq(1),
- steerer_sel(steerer, phy_settings, "write"),
- If(read_available,
- If(~write_available | max_write_time, NextState("WTR"))
- ),
- If(go_to_refresh, NextState("REFRESH"))
- )
- fsm.act("REFRESH",
- steerer.sel[0].eq(STEER_REFRESH),
- If(~refresher.req, NextState("READ"))
- )
- fsm.delayed_enter("RTW", "WRITE", phy_settings.read_latency-1) # FIXME: reduce this, actual limit is around (cl+1)/nphases
- fsm.delayed_enter("WTR", "READ", timing_settings.tWTR-1)
- # FIXME: workaround for zero-delay loop simulation problem with Icarus Verilog
- fsm.finalize()
- self.comb += refresher.ack.eq(fsm.state == fsm.encoding["REFRESH"])
-
- self.submodules.bandwidth = Bandwidth(choose_req.cmd)
+++ /dev/null
-from migen.fhdl.std import *
-from migen.bank.description import *
-
-class Bandwidth(Module, AutoCSR):
- def __init__(self, cmd, period_bits=24):
- self._r_update = CSR()
- self._r_nreads = CSRStatus(period_bits)
- self._r_nwrites = CSRStatus(period_bits)
-
- ###
-
- cmd_stb = Signal()
- cmd_ack = Signal()
- cmd_is_read = Signal()
- cmd_is_write = Signal()
- self.sync += [
- cmd_stb.eq(cmd.stb),
- cmd_ack.eq(cmd.ack),
- cmd_is_read.eq(cmd.is_read),
- cmd_is_write.eq(cmd.is_write)
- ]
-
- counter = Signal(period_bits)
- period = Signal()
- nreads = Signal(period_bits)
- nwrites = Signal(period_bits)
- nreads_r = Signal(period_bits)
- nwrites_r = Signal(period_bits)
- self.sync += [
- Cat(counter, period).eq(counter + 1),
- If(period,
- nreads_r.eq(nreads),
- nwrites_r.eq(nwrites),
- nreads.eq(0),
- nwrites.eq(0)
- ).Elif(cmd_stb & cmd_ack,
- If(cmd_is_read, nreads.eq(nreads + 1)),
- If(cmd_is_write, nwrites.eq(nwrites + 1)),
- ),
- If(self._r_update.re,
- self._r_nreads.status.eq(nreads_r),
- self._r_nwrites.status.eq(nwrites_r)
- )
- ]
+++ /dev/null
-from migen.fhdl.std import *
-from migen.genlib.misc import timeline
-from migen.genlib.fsm import FSM
-
-from milkymist.lasmicon.multiplexer import *
-
-class Refresher(Module):
- def __init__(self, a, ba, tRP, tREFI, tRFC):
- self.req = Signal()
- self.ack = Signal() # 1st command 1 cycle after assertion of ack
- self.cmd = CommandRequest(a, ba)
-
- ###
-
- # Refresh sequence generator:
- # PRECHARGE ALL --(tRP)--> AUTO REFRESH --(tRFC)--> done
- seq_start = Signal()
- seq_done = Signal()
- self.sync += [
- self.cmd.a.eq(2**10),
- self.cmd.ba.eq(0),
- self.cmd.cas_n.eq(1),
- self.cmd.ras_n.eq(1),
- self.cmd.we_n.eq(1),
- seq_done.eq(0)
- ]
- self.sync += timeline(seq_start, [
- (1, [
- self.cmd.ras_n.eq(0),
- self.cmd.we_n.eq(0)
- ]),
- (1+tRP, [
- self.cmd.cas_n.eq(0),
- self.cmd.ras_n.eq(0)
- ]),
- (1+tRP+tRFC, [
- seq_done.eq(1)
- ])
- ])
-
- # Periodic refresh counter
- counter = Signal(max=tREFI)
- start = Signal()
- self.sync += [
- start.eq(0),
- If(counter == 0,
- start.eq(1),
- counter.eq(tREFI - 1)
- ).Else(
- counter.eq(counter - 1)
- )
- ]
-
- # Control FSM
- fsm = FSM()
- self.submodules += fsm
- fsm.act("IDLE", If(start, NextState("WAIT_GRANT")))
- fsm.act("WAIT_GRANT",
- self.req.eq(1),
- If(self.ack,
- seq_start.eq(1),
- NextState("WAIT_SEQ")
- )
- )
- fsm.act("WAIT_SEQ",
- self.req.eq(1),
- If(seq_done, NextState("IDLE"))
- )
+++ /dev/null
-from migen.fhdl.std import *
-from migen.bus import wishbone
-
-class LM32(Module):
- def __init__(self):
- self.ibus = i = wishbone.Interface()
- self.dbus = d = wishbone.Interface()
- self.interrupt = Signal(32)
- self.ext_break = Signal()
-
- ###
-
- i_adr_o = Signal(32)
- d_adr_o = Signal(32)
- self.specials += Instance("lm32_top",
- Instance.Input("clk_i", ClockSignal()),
- Instance.Input("rst_i", ResetSignal()),
-
- Instance.Input("interrupt", self.interrupt),
- #Instance.Input("ext_break", self.ext_break),
-
- Instance.Output("I_ADR_O", i_adr_o),
- Instance.Output("I_DAT_O", i.dat_w),
- Instance.Output("I_SEL_O", i.sel),
- Instance.Output("I_CYC_O", i.cyc),
- Instance.Output("I_STB_O", i.stb),
- Instance.Output("I_WE_O", i.we),
- Instance.Output("I_CTI_O", i.cti),
- Instance.Output("I_LOCK_O"),
- Instance.Output("I_BTE_O", i.bte),
- Instance.Input("I_DAT_I", i.dat_r),
- Instance.Input("I_ACK_I", i.ack),
- Instance.Input("I_ERR_I", i.err),
- Instance.Input("I_RTY_I", 0),
-
- Instance.Output("D_ADR_O", d_adr_o),
- Instance.Output("D_DAT_O", d.dat_w),
- Instance.Output("D_SEL_O", d.sel),
- Instance.Output("D_CYC_O", d.cyc),
- Instance.Output("D_STB_O", d.stb),
- Instance.Output("D_WE_O", d.we),
- Instance.Output("D_CTI_O", d.cti),
- Instance.Output("D_LOCK_O"),
- Instance.Output("D_BTE_O", d.bte),
- Instance.Input("D_DAT_I", d.dat_r),
- Instance.Input("D_ACK_I", d.ack),
- Instance.Input("D_ERR_I", d.err),
- Instance.Input("D_RTY_I", 0))
-
- self.comb += [
- self.ibus.adr.eq(i_adr_o[2:]),
- self.dbus.adr.eq(d_adr_o[2:])
- ]
+++ /dev/null
-from migen.fhdl.std import *
-from migen.genlib.misc import optree
-from migen.bank.description import *
-from migen.actorlib import dma_lasmi
-from migen.actorlib.spi import *
-
-@DecorateModule(InsertReset)
-@DecorateModule(InsertCE)
-class LFSR(Module):
- def __init__(self, n_out, n_state=31, taps=[27, 30]):
- self.o = Signal(n_out)
-
- ###
-
- state = Signal(n_state)
- curval = [state[i] for i in range(n_state)]
- curval += [0]*(n_out - n_state)
- for i in range(n_out):
- nv = ~optree("^", [curval[tap] for tap in taps])
- curval.insert(0, nv)
- curval.pop()
-
- self.sync += [
- state.eq(Cat(*curval[:n_state])),
- self.o.eq(Cat(*curval))
- ]
-
-def _print_lfsr_code():
- from migen.fhdl import verilog
- dut = LFSR(3, 4, [3, 2])
- print(verilog.convert(dut, ios={dut.ce, dut.reset, dut.o}))
-
-class _LFSRTB(Module):
- def __init__(self, *args, **kwargs):
- self.submodules.lfsr = LFSR(*args, **kwargs)
- self.comb += self.lfsr.ce.eq(1)
-
- def do_simulation(self, s):
- print("{0:032x}".format(s.rd(self.lfsr.o)))
-
-def _sim_lfsr():
- from migen.sim.generic import Simulator
- tb = _LFSRTB(128)
- sim = Simulator(tb)
- sim.run(20)
-
-memtest_magic = 0x361f
-
-class MemtestWriter(Module):
- def __init__(self, lasmim):
- self._r_magic = CSRStatus(16)
- self._r_reset = CSR()
- self._r_shoot = CSR()
- self.submodules._dma = DMAWriteController(dma_lasmi.Writer(lasmim), MODE_EXTERNAL)
-
- ###
-
- self.comb += self._r_magic.status.eq(memtest_magic)
-
- lfsr = LFSR(lasmim.dw)
- self.submodules += lfsr
- self.comb += lfsr.reset.eq(self._r_reset.re)
-
- en = Signal()
- en_counter = Signal(lasmim.aw)
- self.comb += en.eq(en_counter != 0)
- self.sync += [
- If(self._r_shoot.re,
- en_counter.eq(self._dma.length)
- ).Elif(lfsr.ce,
- en_counter.eq(en_counter - 1)
- )
- ]
-
- self.comb += [
- self._dma.trigger.eq(self._r_shoot.re),
- self._dma.data.stb.eq(en),
- lfsr.ce.eq(en & self._dma.data.ack),
- self._dma.data.payload.d.eq(lfsr.o)
- ]
-
- def get_csrs(self):
- return [self._r_magic, self._r_reset, self._r_shoot] + self._dma.get_csrs()
-
-class MemtestReader(Module):
- def __init__(self, lasmim):
- self._r_magic = CSRStatus(16)
- self._r_reset = CSR()
- self._r_error_count = CSRStatus(lasmim.aw)
- self.submodules._dma = DMAReadController(dma_lasmi.Reader(lasmim), MODE_SINGLE_SHOT)
-
- ###
-
- self.comb += self._r_magic.status.eq(memtest_magic)
-
- lfsr = LFSR(lasmim.dw)
- self.submodules += lfsr
- self.comb += lfsr.reset.eq(self._r_reset.re)
-
- self.comb += [
- lfsr.ce.eq(self._dma.data.stb),
- self._dma.data.ack.eq(1)
- ]
- err_cnt = self._r_error_count.status
- self.sync += [
- If(self._r_reset.re,
- err_cnt.eq(0)
- ).Elif(self._dma.data.stb,
- If(self._dma.data.payload.d != lfsr.o, err_cnt.eq(err_cnt + 1))
- )
- ]
-
- def get_csrs(self):
- return [self._r_magic, self._r_reset, self._r_error_count] + self._dma.get_csrs()
-
-if __name__ == "__main__":
- _print_lfsr_code()
- _sim_lfsr()
+++ /dev/null
-from migen.fhdl.std import *
-from migen.bank.description import *
-from migen.bank.eventmanager import *
-from migen.bus import wishbone
-
-_count_width = 11
-
-class MiniMAC(Module, AutoCSR):
- def __init__(self, pads):
- # CPU interface
- self._phy_reset = CSRStorage(reset=1)
- self._rx_count_0 = CSRStatus(_count_width)
- self._rx_count_1 = CSRStatus(_count_width)
- self._tx_count = CSRStorage(_count_width, write_from_dev=True)
- self._tx_start = CSR()
-
- self.submodules.ev = EventManager()
- self.ev.rx0 = EventSourcePulse()
- self.ev.rx1 = EventSourcePulse()
- self.ev.tx = EventSourcePulse()
- self.ev.finalize()
-
- self.membus = wishbone.Interface()
-
- ###
-
- init = Signal(reset=1)
- self.sync += init.eq(0)
- rx_ready_0 = Signal()
- rx_ready_1 = Signal()
- rx_pending_0 = self.ev.rx0.pending
- rx_pending_1 = self.ev.rx1.pending
- rx_pending_0_r = Signal()
- rx_pending_1_r = Signal()
- self.comb += [
- pads.rst_n.eq(~self._phy_reset.storage),
-
- rx_ready_0.eq(init | (rx_pending_0_r & ~rx_pending_0)),
- rx_ready_1.eq(init | (rx_pending_1_r & ~rx_pending_1)),
-
- self._tx_count.dat_w.eq(0),
- self._tx_count.we.eq(self.ev.tx.trigger)
- ]
- self.sync += [
- rx_pending_0_r.eq(rx_pending_0),
- rx_pending_1_r.eq(rx_pending_1)
- ]
- self.specials += Instance("minimac3",
- Instance.Input("sys_clk", ClockSignal()),
- Instance.Input("sys_rst", ResetSignal()),
-
- Instance.Output("rx_done_0", self.ev.rx0.trigger),
- Instance.Output("rx_count_0", self._rx_count_0.status),
- Instance.Output("rx_done_1", self.ev.rx1.trigger),
- Instance.Output("rx_count_1", self._rx_count_1.status),
- Instance.Input("rx_ready_0", rx_ready_0),
- Instance.Input("rx_ready_1", rx_ready_1),
-
- Instance.Input("tx_start", self._tx_start.re),
- Instance.Input("tx_count", self._tx_count.storage),
- Instance.Output("tx_done", self.ev.tx.trigger),
-
- Instance.Input("wb_adr_i", self.membus.adr),
- Instance.Input("wb_dat_i", self.membus.dat_w),
- Instance.Input("wb_sel_i", self.membus.sel),
- Instance.Input("wb_stb_i", self.membus.stb),
- Instance.Input("wb_cyc_i", self.membus.cyc),
- Instance.Input("wb_we_i", self.membus.we),
- Instance.Output("wb_dat_o", self.membus.dat_r),
- Instance.Output("wb_ack_o", self.membus.ack),
-
- Instance.Input("phy_tx_clk", ClockSignal("eth_tx")),
- Instance.Output("phy_tx_data", pads.tx_data),
- Instance.Output("phy_tx_en", pads.tx_en),
- Instance.Output("phy_tx_er", pads.tx_er),
- Instance.Input("phy_rx_clk", ClockSignal("eth_rx")),
- Instance.Input("phy_rx_data", pads.rx_data),
- Instance.Input("phy_dv", pads.dv),
- Instance.Input("phy_rx_er", pads.rx_er),
- Instance.Input("phy_col", pads.col),
- Instance.Input("phy_crs", pads.crs))
+++ /dev/null
-from fractions import Fraction
-
-from migen.fhdl.std import *
-
-class MXCRG(Module):
- def __init__(self, pads, outfreq1x):
- self.clock_domains.cd_sys = ClockDomain()
- self.clock_domains.cd_sdram_half = ClockDomain()
- self.clock_domains.cd_sdram_full_wr = ClockDomain()
- self.clock_domains.cd_sdram_full_rd = ClockDomain()
- self.clock_domains.cd_eth_rx = ClockDomain()
- self.clock_domains.cd_eth_tx = ClockDomain()
- self.clock_domains.cd_base50 = ClockDomain(reset_less=True)
-
- self.clk4x_wr_strb = Signal()
- self.clk4x_rd_strb = Signal()
-
- ###
-
- infreq = 50*1000000
- ratio = Fraction(outfreq1x)/Fraction(infreq)
- in_period = float(Fraction(1000000000)/Fraction(infreq))
-
- self.specials += Instance("mxcrg",
- Instance.Parameter("in_period", in_period),
- Instance.Parameter("f_mult", ratio.numerator),
- Instance.Parameter("f_div", ratio.denominator),
- Instance.Input("clk50_pad", pads.clk50),
- Instance.Input("trigger_reset", pads.trigger_reset),
-
- Instance.Input("eth_rx_clk_pad", pads.eth_rx_clk),
- Instance.Input("eth_tx_clk_pad", pads.eth_tx_clk),
-
- Instance.Output("sys_clk", self.cd_sys.clk),
- Instance.Output("sys_rst", self.cd_sys.rst),
- Instance.Output("clk2x_270", self.cd_sdram_half.clk),
- Instance.Output("clk4x_wr", self.cd_sdram_full_wr.clk),
- Instance.Output("clk4x_rd", self.cd_sdram_full_rd.clk),
- Instance.Output("eth_rx_clk", self.cd_eth_rx.clk),
- Instance.Output("eth_tx_clk", self.cd_eth_tx.clk),
- Instance.Output("base50_clk", self.cd_base50.clk),
-
- Instance.Output("clk4x_wr_strb", self.clk4x_wr_strb),
- Instance.Output("clk4x_rd_strb", self.clk4x_rd_strb),
- Instance.Output("norflash_rst_n", pads.norflash_rst_n),
- Instance.Output("ddr_clk_pad_p", pads.ddr_clk_p),
- Instance.Output("ddr_clk_pad_n", pads.ddr_clk_n),
- Instance.Output("eth_phy_clk_pad", pads.eth_phy_clk))
+++ /dev/null
-from migen.fhdl.std import *
-from migen.bus import wishbone
-from migen.genlib.misc import timeline
-
-class NorFlash(Module):
- def __init__(self, pads, rd_timing):
- self.bus = wishbone.Interface()
-
- ###
-
- adr_width = flen(pads.adr) + 1
- self.comb += [pads.oe_n.eq(0), pads.we_n.eq(1),
- pads.ce_n.eq(0)]
- self.sync += timeline(self.bus.cyc & self.bus.stb, [
- (0, [pads.adr.eq(Cat(0, self.bus.adr[:adr_width-2]))]),
- (rd_timing, [
- self.bus.dat_r[16:].eq(pads.d),
- pads.adr.eq(Cat(1, self.bus.adr[:adr_width-2]))]),
- (2*rd_timing, [
- self.bus.dat_r[:16].eq(pads.d),
- self.bus.ack.eq(1)]),
- (2*rd_timing + 1, [
- self.bus.ack.eq(0)])
- ])
+++ /dev/null
-# 1:2 frequency-ratio DDR / LPDDR / DDR2 PHY for
-# Spartan-6
-#
-# Assert dfi_wrdata_en and present the data
-# on dfi_wrdata_mask/dfi_wrdata in the same
-# cycle as the write command.
-#
-# Assert dfi_rddata_en in the same cycle as the read
-# command. The data will come back on dfi_rddata
-# 5 cycles later, along with the assertion
-# of dfi_rddata_valid.
-#
-# This PHY only supports CAS Latency 3.
-# Read commands must be sent on phase 0.
-# Write commands must be sent on phase 1.
-#
-
-# Todo:
-# - use CSR for bitslip?
-# - add configurable CAS Latency
-# - automatically determines wrphase / rdphase / latencies
-
-from migen.fhdl.std import *
-from migen.bus.dfi import *
-from migen.genlib.record import *
-
-from milkymist import lasmicon
-
-class S6DDRPHY(Module):
- def __init__(self, pads, memtype, nphases, cl, rd_bitslip, wr_bitslip, dqs_ddr_alignment):
- if memtype not in ["DDR", "LPDDR", "DDR2"]:
- raise NotImplementedError("S6DDRPHY only supports DDR, LPDDR and DDR2")
- if cl != 3:
- raise NotImplementedError("S6DDRPHY only supports CAS LATENCY 3")
- a = flen(pads.a)
- ba = flen(pads.ba)
- d = flen(pads.dq)
-
- self.phy_settings = lasmicon.PhySettings(
- memtype=memtype,
- dfi_d=2*d,
- nphases=nphases,
- rdphase=0,
- wrphase=1,
- rdcmdphase=1,
- wrcmdphase=0,
- cl=cl,
- read_latency=5,
- write_latency=0
- )
-
- self.dfi = Interface(a, ba, nphases*d, nphases)
- self.clk4x_wr_strb = Signal()
- self.clk4x_rd_strb = Signal()
-
- ###
-
- # sys_clk : system clk, used for dfi interface
- # sdram_half_clk : half rate sdram clk
- # sdram_full_wr_clk : full rate sdram write clk
- # sdram_full_rd_clk : full rate sdram write clk
- sd_sys = getattr(self.sync, "sys")
- sd_sdram_half = getattr(self.sync, "sdram_half")
-
- sys_clk = ClockSignal("sys")
- sdram_half_clk = ClockSignal("sdram_half")
- sdram_full_wr_clk = ClockSignal("sdram_full_wr")
- sdram_full_rd_clk = ClockSignal("sdram_full_rd")
-
- #
- # Command/address
- #
-
- # select active phase
- # sys_clk ----____----____
- # phase_sel(nphases=1) 0 0
- # phase_sel(nphases=2) 0 1 0 1
- # phase_sel(nphases=4) 0 1 2 3 0 1 2 3
- phase_sel = Signal(log2_int(nphases))
- sys_clk_d = Signal()
-
- sd_sdram_half += [
- If(sys_clk & ~sys_clk_d, phase_sel.eq(0)
- ).Else(phase_sel.eq(phase_sel+1)),
- sys_clk_d.eq(sys_clk)
- ]
-
- # register dfi cmds on half_rate clk
- r_dfi = Array(Record(phase_cmd_description(a, ba)) for i in range(nphases))
- for n, phase in enumerate(self.dfi.phases):
- sd_sdram_half +=[
- r_dfi[n].address.eq(phase.address),
- r_dfi[n].bank.eq(phase.bank),
- r_dfi[n].cs_n.eq(phase.cs_n),
- r_dfi[n].cke.eq(phase.cke),
- r_dfi[n].cas_n.eq(phase.cas_n),
- r_dfi[n].ras_n.eq(phase.ras_n),
- r_dfi[n].we_n.eq(phase.we_n)
- ]
-
- # output cmds
- sd_sdram_half += [
- pads.a.eq(r_dfi[phase_sel].address),
- pads.ba.eq(r_dfi[phase_sel].bank),
- pads.cke.eq(r_dfi[phase_sel].cke),
- pads.ras_n.eq(r_dfi[phase_sel].ras_n),
- pads.cas_n.eq(r_dfi[phase_sel].cas_n),
- pads.we_n.eq(r_dfi[phase_sel].we_n)
- ]
- if hasattr(pads, "cs_n"):
- sd_sdram_half += pads.cs_n.eq(r_dfi[phase_sel].cs_n)
-
- #
- # Bitslip
- #
- bitslip_cnt = Signal(4)
- bitslip_inc = Signal()
-
- sd_sys += [
- If(bitslip_cnt == rd_bitslip,
- bitslip_inc.eq(0)
- ).Else(
- bitslip_cnt.eq(bitslip_cnt+1),
- bitslip_inc.eq(1)
- )
- ]
-
- #
- # DQ/DQS/DM data
- #
- sdram_half_clk_n = Signal()
- self.comb += sdram_half_clk_n.eq(~sdram_half_clk)
-
- postamble = Signal()
- drive_dqs = Signal()
- dqs_t_d0 = Signal()
- dqs_t_d1 = Signal()
-
- dqs_o = Signal(d//8)
- dqs_t = Signal(d//8)
-
- self.comb += [
- dqs_t_d0.eq(~(drive_dqs | postamble)),
- dqs_t_d1.eq(~drive_dqs),
- ]
-
- for i in range(d//8):
- # DQS output
- self.specials += Instance("ODDR2",
- Instance.Parameter("DDR_ALIGNMENT", dqs_ddr_alignment),
- Instance.Parameter("INIT", 0),
- Instance.Parameter("SRTYPE", "ASYNC"),
-
- Instance.Input("C0", sdram_half_clk),
- Instance.Input("C1", sdram_half_clk_n),
-
- Instance.Input("CE", 1),
- Instance.Input("D0", 0),
- Instance.Input("D1", 1),
- Instance.Input("R", 0),
- Instance.Input("S", 0),
-
- Instance.Output("Q", dqs_o[i])
- )
-
- # DQS tristate cmd
- self.specials += Instance("ODDR2",
- Instance.Parameter("DDR_ALIGNMENT", dqs_ddr_alignment),
- Instance.Parameter("INIT", 0),
- Instance.Parameter("SRTYPE", "ASYNC"),
-
- Instance.Input("C0", sdram_half_clk),
- Instance.Input("C1", sdram_half_clk_n),
-
- Instance.Input("CE", 1),
- Instance.Input("D0", dqs_t_d0),
- Instance.Input("D1", dqs_t_d1),
- Instance.Input("R", 0),
- Instance.Input("S", 0),
-
- Instance.Output("Q", dqs_t[i])
- )
-
- # DQS tristate buffer
- if hasattr(pads, "dqs_n"):
- self.specials += Instance("OBUFTDS",
- Instance.Input("I", dqs_o[i]),
- Instance.Input("T", dqs_t[i]),
-
- Instance.Output("O", pads.dqs[i]),
- Instance.Output("OB", pads.dqs_n[i]),
- )
- else:
- self.specials += Instance("OBUFT",
- Instance.Input("I", dqs_o[i]),
- Instance.Input("T", dqs_t[i]),
-
- Instance.Output("O", pads.dqs[i])
- )
-
- sd_sdram_half += postamble.eq(drive_dqs)
-
- d_dfi = [Record(phase_wrdata_description(nphases*d)+phase_rddata_description(nphases*d))
- for i in range(2*nphases)]
-
- for n, phase in enumerate(self.dfi.phases):
- self.comb += [
- d_dfi[n].wrdata.eq(phase.wrdata),
- d_dfi[n].wrdata_mask.eq(phase.wrdata_mask),
- d_dfi[n].wrdata_en.eq(phase.wrdata_en),
- d_dfi[n].rddata_en.eq(phase.rddata_en),
- ]
- sd_sys += [
- d_dfi[nphases+n].wrdata.eq(phase.wrdata),
- d_dfi[nphases+n].wrdata_mask.eq(phase.wrdata_mask)
- ]
-
-
- drive_dq = Signal()
- drive_dq_n = [Signal() for i in range(2)]
- self.comb += drive_dq_n[0].eq(~drive_dq)
- sd_sys += drive_dq_n[1].eq(drive_dq_n[0])
-
- dq_t = Signal(d)
- dq_o = Signal(d)
- dq_i = Signal(d)
-
- dq_wrdata = []
- for i in range(2):
- for j in reversed(range(nphases)):
- dq_wrdata.append(d_dfi[i*nphases+j].wrdata[:d])
- dq_wrdata.append(d_dfi[i*nphases+j].wrdata[d:])
-
- for i in range(d):
- # Data serializer
- self.specials += Instance("OSERDES2",
- Instance.Parameter("DATA_WIDTH", 4),
- Instance.Parameter("DATA_RATE_OQ", "SDR"),
- Instance.Parameter("DATA_RATE_OT", "SDR"),
- Instance.Parameter("SERDES_MODE", "NONE"),
- Instance.Parameter("OUTPUT_MODE", "SINGLE_ENDED"),
-
- Instance.Output("OQ", dq_o[i]),
- Instance.Input("OCE", 1),
- Instance.Input("CLK0", sdram_full_wr_clk),
- Instance.Input("CLK1", 0),
- Instance.Input("IOCE", self.clk4x_wr_strb),
- Instance.Input("RST", 0),
- Instance.Input("CLKDIV", sys_clk),
-
- Instance.Input("D1", dq_wrdata[wr_bitslip+3][i]),
- Instance.Input("D2", dq_wrdata[wr_bitslip+2][i]),
- Instance.Input("D3", dq_wrdata[wr_bitslip+1][i]),
- Instance.Input("D4", dq_wrdata[wr_bitslip+0][i]),
-
- Instance.Output("TQ", dq_t[i]),
- Instance.Input("T1", drive_dq_n[(wr_bitslip+3)//4]),
- Instance.Input("T2", drive_dq_n[(wr_bitslip+2)//4]),
- Instance.Input("T3", drive_dq_n[(wr_bitslip+1)//4]),
- Instance.Input("T4", drive_dq_n[(wr_bitslip+0)//4]),
- Instance.Input("TRAIN", 0),
- Instance.Input("TCE", 1),
- Instance.Input("SHIFTIN1", 0),
- Instance.Input("SHIFTIN2", 0),
- Instance.Input("SHIFTIN3", 0),
- Instance.Input("SHIFTIN4", 0),
-
- Instance.Output("SHIFTOUT1"),
- Instance.Output("SHIFTOUT2"),
- Instance.Output("SHIFTOUT3"),
- Instance.Output("SHIFTOUT4"),
- )
-
- # Data deserializer
- self.specials += Instance("ISERDES2",
- Instance.Parameter("DATA_WIDTH", 4),
- Instance.Parameter("DATA_RATE", "SDR"),
- Instance.Parameter("BITSLIP_ENABLE", "TRUE"),
- Instance.Parameter("SERDES_MODE", "NONE"),
- Instance.Parameter("INTERFACE_TYPE", "RETIMED"),
-
- Instance.Input("D", dq_i[i]),
- Instance.Input("CE0", 1),
- Instance.Input("CLK0", sdram_full_rd_clk),
- Instance.Input("CLK1", 0),
- Instance.Input("IOCE", self.clk4x_rd_strb),
- Instance.Input("RST", ResetSignal()),
- Instance.Input("CLKDIV", sys_clk),
- Instance.Output("SHIFTIN"),
- Instance.Input("BITSLIP", bitslip_inc),
- Instance.Output("FABRICOUT"),
-
- Instance.Output("Q1", d_dfi[0*nphases+0].rddata[i+d]),
- Instance.Output("Q2", d_dfi[0*nphases+0].rddata[i]),
- Instance.Output("Q3", d_dfi[0*nphases+1].rddata[i+d]),
- Instance.Output("Q4", d_dfi[0*nphases+1].rddata[i]),
-
- Instance.Output("DFB"),
- Instance.Output("CFB0"),
- Instance.Output("CFB1"),
- Instance.Output("VALID"),
- Instance.Output("INCDEC"),
- Instance.Output("SHIFTOUT")
- )
-
- # Data buffer
- self.specials += Instance("IOBUF",
- Instance.Input("I", dq_o[i]),
- Instance.Output("O", dq_i[i]),
- Instance.Input("T", dq_t[i]),
- Instance.InOut("IO", pads.dq[i])
- )
-
- dq_wrdata_mask = []
- for i in range(2):
- for j in reversed(range(nphases)):
- dq_wrdata_mask.append(d_dfi[i*nphases+j].wrdata_mask[:d//8])
- dq_wrdata_mask.append(d_dfi[i*nphases+j].wrdata_mask[d//8:])
-
- for i in range(d//8):
- # Mask serializer
- self.specials += Instance("OSERDES2",
- Instance.Parameter("DATA_WIDTH", 4),
- Instance.Parameter("DATA_RATE_OQ", "SDR"),
- Instance.Parameter("DATA_RATE_OT", "SDR"),
- Instance.Parameter("SERDES_MODE", "NONE"),
- Instance.Parameter("OUTPUT_MODE", "SINGLE_ENDED"),
-
- Instance.Output("OQ", pads.dm[i]),
- Instance.Input("OCE", 1),
- Instance.Input("CLK0", sdram_full_wr_clk),
- Instance.Input("CLK1", 0),
- Instance.Input("IOCE", self.clk4x_wr_strb),
- Instance.Input("RST", 0),
- Instance.Input("CLKDIV", sys_clk),
-
- Instance.Input("D1", dq_wrdata_mask[wr_bitslip+3][i]),
- Instance.Input("D2", dq_wrdata_mask[wr_bitslip+2][i]),
- Instance.Input("D3", dq_wrdata_mask[wr_bitslip+1][i]),
- Instance.Input("D4", dq_wrdata_mask[wr_bitslip+0][i]),
-
- Instance.Output("TQ"),
- Instance.Input("T1"),
- Instance.Input("T2"),
- Instance.Input("T3"),
- Instance.Input("T4"),
- Instance.Input("TRAIN", 0),
- Instance.Input("TCE", 0),
- Instance.Input("SHIFTIN1", 0),
- Instance.Input("SHIFTIN2", 0),
- Instance.Input("SHIFTIN3", 0),
- Instance.Input("SHIFTIN4", 0),
-
- Instance.Output("SHIFTOUT1"),
- Instance.Output("SHIFTOUT2"),
- Instance.Output("SHIFTOUT3"),
- Instance.Output("SHIFTOUT4"),
- )
-
- #
- # ODT
- #
- # ODT not yet supported
- if hasattr(pads, "odt"):
- self.comb += pads.odt.eq(0)
-
- #
- # DQ/DQS/DM control
- #
- self.comb += drive_dq.eq(d_dfi[self.phy_settings.wrphase].wrdata_en)
-
- d_dfi_wrdata_en = Signal()
- sd_sys += d_dfi_wrdata_en.eq(d_dfi[self.phy_settings.wrphase].wrdata_en)
-
- r_dfi_wrdata_en = Signal(2)
- sd_sdram_half += r_dfi_wrdata_en.eq(Cat(d_dfi_wrdata_en, r_dfi_wrdata_en[0]))
-
- self.comb += drive_dqs.eq(r_dfi_wrdata_en[1])
-
- rddata_sr = Signal(self.phy_settings.read_latency)
- sd_sys += rddata_sr.eq(Cat(rddata_sr[1:self.phy_settings.read_latency],
- d_dfi[self.phy_settings.rdphase].rddata_en))
-
- for n, phase in enumerate(self.dfi.phases):
- self.comb += [
- phase.rddata.eq(d_dfi[n].rddata),
- phase.rddata_valid.eq(rddata_sr[0]),
- ]
+++ /dev/null
-from migen.fhdl.std import log2_int
-
-def get_sdram_phy_header(sdram_phy):
- if sdram_phy.phy_settings.memtype not in ["SDR", "DDR", "LPDDR", "DDR2"]:
- raise NotImplementedError("The SDRAM PHY header generator only supports SDR, DDR, LPDDR and DDR2")
-
- r = "#ifndef __HW_SDRAM_PHY_H\n#define __HW_SDRAM_PHY_H\n"
- r += "#include <hw/common.h>\n#include <hw/csr.h>\n#include <hw/flags.h>\n\n"
-
- r += "static void cdelay(int i);\n"
-
- #
- # commands_px functions
- #
- for n in range(sdram_phy.phy_settings.nphases):
- r += """
-static void command_p{n}(int cmd)
-{{
- dfii_pi{n}_command_write(cmd);
- dfii_pi{n}_command_issue_write(1);
-}}""".format(n=str(n))
- r += "\n\n"
-
- #
- # rd/wr access macros
- #
- r += """
-#define dfii_pird_address_write(X) dfii_pi{rdphase}_address_write(X)
-#define dfii_piwr_address_write(X) dfii_pi{wrphase}_address_write(X)
-
-#define dfii_pird_baddress_write(X) dfii_pi{rdphase}_baddress_write(X)
-#define dfii_piwr_baddress_write(X) dfii_pi{wrphase}_baddress_write(X)
-
-#define command_prd(X) command_p{rdphase}(X)
-#define command_pwr(X) command_p{wrphase}(X)
-""".format(rdphase=str(sdram_phy.phy_settings.rdphase), wrphase=str(sdram_phy.phy_settings.wrphase))
- r +="\n"
-
- #
- # init sequence
- #
- cmds = {
- "PRECHARGE_ALL" : "DFII_COMMAND_RAS|DFII_COMMAND_WE|DFII_COMMAND_CS",
- "MODE_REGISTER" : "DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS",
- "AUTO_REFRESH" : "DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_CS",
- "CKE" : "DFII_CONTROL_CKE"
- }
-
- def gen_cmd(comment, a, ba, cmd, delay):
- r = "\t/* {0} */\n".format(comment)
- r += "\tdfii_pi0_address_write({0:#x});\n".format(a)
- r += "\tdfii_pi0_baddress_write({0:d});\n".format(ba)
- if "CKE" in cmd:
- r += "\tdfii_control_write({0});\n".format(cmd)
- else:
- r += "\tcommand_p0({0});\n".format(cmd)
- r += "\tcdelay({0:d});\n".format(delay)
- r += "\n"
- return r
-
-
- r += "static void init_sequence(void)\n{\n"
-
- cl = sdram_phy.phy_settings.cl
-
- if sdram_phy.phy_settings.memtype == "SDR":
- bl = 1*sdram_phy.phy_settings.nphases
- mr = log2_int(bl) + (cl << 4)
- reset_dll = 1 << 8
-
- init_sequence = [
- ("Bring CKE high", 0x0000, 0, cmds["CKE"], 2000),
- ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0),
- ("Load Mode Register / Reset DLL, CL={0:d}, BL={1:d}".format(cl, bl), mr + reset_dll, 0, cmds["MODE_REGISTER"], 200),
- ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0),
- ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4),
- ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4),
- ("Load Mode Register / CL={0:d}, BL={1:d}".format(cl, bl), mr, 0, cmds["MODE_REGISTER"], 200)
- ]
-
- elif sdram_phy.phy_settings.memtype == "DDR":
- bl = 2*sdram_phy.phy_settings.nphases
- mr = log2_int(bl) + (cl << 4)
- emr = 0
- reset_dll = 1 << 8
-
- init_sequence = [
- ("Bring CKE high", 0x0000, 0, cmds["CKE"], 2000),
- ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0),
- ("Load Extended Mode Register", emr, 1, cmds["MODE_REGISTER"], 0),
- ("Load Mode Register / Reset DLL, CL={0:d}, BL={1:d}".format(cl, bl), mr + reset_dll, 0, cmds["MODE_REGISTER"], 200),
- ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0),
- ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4),
- ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4),
- ("Load Mode Register / CL={0:d}, BL={1:d}".format(cl, bl), mr, 0, cmds["MODE_REGISTER"], 200)
- ]
-
- elif sdram_phy.phy_settings.memtype == "LPDDR":
- bl = 2*sdram_phy.phy_settings.nphases
- mr = log2_int(bl) + (cl << 4)
- emr = 0
- reset_dll = 1 << 8
-
- init_sequence = [
- ("Bring CKE high", 0x0000, 0, cmds["CKE"], 2000),
- ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0),
- ("Load Extended Mode Register", emr, 2, cmds["MODE_REGISTER"], 0),
- ("Load Mode Register / Reset DLL, CL={0:d}, BL={1:d}".format(cl, bl), mr + reset_dll, 0, cmds["MODE_REGISTER"], 200),
- ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0),
- ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4),
- ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4),
- ("Load Mode Register / CL={0:d}, BL={1:d}".format(cl, bl), mr, 0, cmds["MODE_REGISTER"], 200)
- ]
-
- elif sdram_phy.phy_settings.memtype == "DDR2":
- bl = 2*sdram_phy.phy_settings.nphases
- wr = 2
- mr = log2_int(bl) + (cl << 4) + (wr << 9)
- emr = 0
- emr2 = 0
- emr3 = 0
- reset_dll = 1 << 8
- ocd = 7 << 7
-
- init_sequence = [
- ("Bring CKE high", 0x0000, 0, cmds["CKE"], 2000),
- ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0),
- ("Load Extended Mode Register 3", emr3, 3, cmds["MODE_REGISTER"], 0),
- ("Load Extended Mode Register 2", emr2, 2, cmds["MODE_REGISTER"], 0),
- ("Load Extended Mode Register", emr, 1, cmds["MODE_REGISTER"], 0),
- ("Load Mode Register / Reset DLL, CL={0:d}, BL={1:d}".format(cl, bl), mr + reset_dll, 0, cmds["MODE_REGISTER"], 200),
- ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0),
- ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4),
- ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4),
- ("Load Mode Register / CL={0:d}, BL={1:d}".format(cl, bl), mr, 0, cmds["MODE_REGISTER"], 200),
- ("Load Extended Mode Register / OCD Default", emr+ocd, 1, cmds["MODE_REGISTER"], 0),
- ("Load Extended Mode Register / OCD Exit", emr, 1, cmds["MODE_REGISTER"], 0),
- ]
-
- for comment, a, ba, cmd, delay in init_sequence:
- r += gen_cmd(comment, a, ba, cmd, delay)
-
- r += "}\n"
- r += "#endif\n"
-
- return r
+++ /dev/null
-from migen.fhdl.std import *
-from migen.bank.description import *
-from migen.bank.eventmanager import *
-
-class Timer(Module, AutoCSR):
- def __init__(self, width=32):
- self._load = CSRStorage(width)
- self._reload = CSRStorage(width)
- self._en = CSRStorage()
- self._update_value = CSR()
- self._value = CSRStatus(width)
-
- self.submodules.ev = EventManager()
- self.ev.zero = EventSourceProcess()
- self.ev.finalize()
-
- ###
-
- value = Signal(width)
- self.sync += [
- If(self._en.storage,
- If(value == 0,
- # set reload to 0 to disable reloading
- value.eq(self._reload.storage)
- ).Else(
- value.eq(value - 1)
- )
- ).Else(
- value.eq(self._load.storage)
- ),
- If(self._update_value.re, self._value.status.eq(value))
- ]
- self.comb += self.ev.zero.trigger.eq(value != 0)
+++ /dev/null
-from migen.fhdl.std import *
-from migen.genlib.cdc import MultiReg
-from migen.bank.description import *
-from migen.bank.eventmanager import *
-
-class UART(Module, AutoCSR):
- def __init__(self, pads, clk_freq, baud=115200):
- self._rxtx = CSR(8)
- self._divisor = CSRStorage(16, reset=int(clk_freq/baud/16))
-
- self.submodules.ev = EventManager()
- self.ev.tx = EventSourceProcess()
- self.ev.rx = EventSourcePulse()
- self.ev.finalize()
-
- ###
-
- pads.tx.reset = 1
-
- enable16 = Signal()
- enable16_counter = Signal(16)
- self.comb += enable16.eq(enable16_counter == 0)
- self.sync += [
- enable16_counter.eq(enable16_counter - 1),
- If(enable16,
- enable16_counter.eq(self._divisor.storage - 1))
- ]
-
- # TX
- tx_reg = Signal(8)
- tx_bitcount = Signal(4)
- tx_count16 = Signal(4)
- tx_busy = self.ev.tx.trigger
- self.sync += [
- If(self._rxtx.re,
- tx_reg.eq(self._rxtx.r),
- tx_bitcount.eq(0),
- tx_count16.eq(1),
- tx_busy.eq(1),
- pads.tx.eq(0)
- ).Elif(enable16 & tx_busy,
- tx_count16.eq(tx_count16 + 1),
- If(tx_count16 == 0,
- tx_bitcount.eq(tx_bitcount + 1),
- If(tx_bitcount == 8,
- pads.tx.eq(1)
- ).Elif(tx_bitcount == 9,
- pads.tx.eq(1),
- tx_busy.eq(0)
- ).Else(
- pads.tx.eq(tx_reg[0]),
- tx_reg.eq(Cat(tx_reg[1:], 0))
- )
- )
- )
- ]
-
- # RX
- rx = Signal()
- self.specials += MultiReg(pads.rx, rx)
- rx_r = Signal()
- rx_reg = Signal(8)
- rx_bitcount = Signal(4)
- rx_count16 = Signal(4)
- rx_busy = Signal()
- rx_done = self.ev.rx.trigger
- rx_data = self._rxtx.w
- self.sync += [
- rx_done.eq(0),
- If(enable16,
- rx_r.eq(rx),
- If(~rx_busy,
- If(~rx & rx_r, # look for start bit
- rx_busy.eq(1),
- rx_count16.eq(7),
- rx_bitcount.eq(0)
- )
- ).Else(
- rx_count16.eq(rx_count16 + 1),
- If(rx_count16 == 0,
- rx_bitcount.eq(rx_bitcount + 1),
-
- If(rx_bitcount == 0,
- If(rx, # verify start bit
- rx_busy.eq(0)
- )
- ).Elif(rx_bitcount == 9,
- rx_busy.eq(0),
- If(rx, # verify stop bit
- rx_data.eq(rx_reg),
- rx_done.eq(1)
- )
- ).Else(
- rx_reg.eq(Cat(rx_reg[1:], rx))
- )
- )
- )
- )
- ]
--- /dev/null
+import collections
+
+from migen.fhdl.std import *
+from migen.bank.description import *
+from migen.genlib.misc import optree
+from migen.genlib.cdc import MultiReg
+
+class CounterADC(Module, AutoCSR):
+ def __init__(self, charge, sense, width=24):
+ if not isinstance(sense, collections.Iterable):
+ sense = [sense]
+
+ channels = len(sense)
+
+ self._start_busy = CSR()
+ self._overflow = CSRStatus(channels)
+ self._polarity = CSRStorage()
+
+ count = Signal(width)
+ busy = Signal(channels)
+
+ res = []
+ for i in range(channels):
+ res.append(CSRStatus(width, name="res"+str(i)))
+ setattr(self, "_res"+str(i), res[-1])
+
+ any_busy = Signal()
+ self.comb += [
+ any_busy.eq(optree("|",
+ [busy[i] for i in range(channels)])),
+ self._start_busy.w.eq(any_busy)
+ ]
+
+ carry = Signal()
+
+ self.sync += [
+ If(self._start_busy.re,
+ count.eq(0),
+ busy.eq((1 << channels)-1),
+ self._overflow.status.eq(0),
+ charge.eq(~self._polarity.storage)
+ ).Elif(any_busy,
+ Cat(count, carry).eq(count + 1),
+ If(carry,
+ self._overflow.status.eq(busy),
+ busy.eq(0)
+ )
+ ).Else(
+ charge.eq(self._polarity.storage)
+ )
+ ]
+
+ for i in range(channels):
+ sense_synced = Signal()
+ self.specials += MultiReg(sense[i], sense_synced)
+ self.sync += If(busy[i],
+ If(sense_synced != self._polarity.storage,
+ res[i].status.eq(count),
+ busy[i].eq(0)
+ )
+ )
--- /dev/null
+from migen.bank.description import CSRStatus
+
+def _get_rw_functions(reg_name, reg_base, size, read_only):
+ r = ""
+ if size > 8:
+ raise NotImplementedError("Register too large")
+ elif size > 4:
+ ctype = "unsigned long long int"
+ elif size > 2:
+ ctype = "unsigned int"
+ elif size > 1:
+ ctype = "unsigned short int"
+ else:
+ ctype = "unsigned char"
+
+ r += "static inline "+ctype+" "+reg_name+"_read(void) {\n"
+ if size > 1:
+ r += "\t"+ctype+" r = MMPTR("+hex(reg_base)+");\n"
+ for byte in range(1, size):
+ r += "\tr <<= 8;\n\tr |= MMPTR("+hex(reg_base+4*byte)+");\n"
+ r += "\treturn r;\n}\n"
+ else:
+ r += "\treturn MMPTR("+hex(reg_base)+");\n}\n"
+
+ if not read_only:
+ r += "static inline void "+reg_name+"_write("+ctype+" value) {\n"
+ for byte in range(size):
+ shift = (size-byte-1)*8
+ if shift:
+ value_shifted = "value >> "+str(shift)
+ else:
+ value_shifted = "value"
+ r += "\tMMPTR("+hex(reg_base+4*byte)+") = "+value_shifted+";\n"
+ r += "}\n"
+ return r
+
+def get_csr_header(csr_base, bank_array, interrupt_map):
+ r = "#ifndef __HW_CSR_H\n#define __HW_CSR_H\n#include <hw/common.h>\n"
+ for name, csrs, mapaddr, rmap in bank_array.banks:
+ r += "\n/* "+name+" */\n"
+ reg_base = csr_base + 0x800*mapaddr
+ r += "#define "+name.upper()+"_BASE "+hex(reg_base)+"\n"
+ for csr in csrs:
+ nr = (csr.size + 7)//8
+ r += _get_rw_functions(name + "_" + csr.name, reg_base, nr, isinstance(csr, CSRStatus))
+ reg_base += 4*nr
+ try:
+ interrupt_nr = interrupt_map[name]
+ except KeyError:
+ pass
+ else:
+ r += "#define "+name.upper()+"_INTERRUPT "+str(interrupt_nr)+"\n"
+ r += "\n#endif\n"
+ return r
+
+def get_csr_csv(csr_base, bank_array):
+ r = ""
+ for name, csrs, mapaddr, rmap in bank_array.banks:
+ reg_base = csr_base + 0x800*mapaddr
+ for csr in csrs:
+ nr = (csr.size + 7)//8
+ r += "{}_{},0x{:08x},{},{}\n".format(name, csr.name, reg_base, nr, "ro" if isinstance(csr, CSRStatus) else "rw")
+ reg_base += 4*nr
+ return r
--- /dev/null
+from migen.fhdl.std import *
+from migen.bus import dfi
+from migen.bank.description import *
+
+class PhaseInjector(Module, AutoCSR):
+ def __init__(self, phase):
+ self._command = CSRStorage(6) # cs, we, cas, ras, wren, rden
+ self._command_issue = CSR()
+ self._address = CSRStorage(flen(phase.address))
+ self._baddress = CSRStorage(flen(phase.bank))
+ self._wrdata = CSRStorage(flen(phase.wrdata))
+ self._rddata = CSRStatus(flen(phase.rddata))
+
+ ###
+
+ self.comb += [
+ If(self._command_issue.re,
+ phase.cs_n.eq(~self._command.storage[0]),
+ phase.we_n.eq(~self._command.storage[1]),
+ phase.cas_n.eq(~self._command.storage[2]),
+ phase.ras_n.eq(~self._command.storage[3])
+ ).Else(
+ phase.cs_n.eq(1),
+ phase.we_n.eq(1),
+ phase.cas_n.eq(1),
+ phase.ras_n.eq(1)
+ ),
+ phase.address.eq(self._address.storage),
+ phase.bank.eq(self._baddress.storage),
+ phase.wrdata_en.eq(self._command_issue.re & self._command.storage[4]),
+ phase.rddata_en.eq(self._command_issue.re & self._command.storage[5]),
+ phase.wrdata.eq(self._wrdata.storage),
+ phase.wrdata_mask.eq(0)
+ ]
+ self.sync += If(phase.rddata_valid, self._rddata.status.eq(phase.rddata))
+
+class DFIInjector(Module, AutoCSR):
+ def __init__(self, a, ba, d, nphases=1):
+ inti = dfi.Interface(a, ba, d, nphases)
+ self.slave = dfi.Interface(a, ba, d, nphases)
+ self.master = dfi.Interface(a, ba, d, nphases)
+
+ self._control = CSRStorage(2) # sel, cke
+
+ for n, phase in enumerate(inti.phases):
+ setattr(self.submodules, "pi" + str(n), PhaseInjector(phase))
+
+ ###
+
+ self.comb += If(self._control.storage[0],
+ self.slave.connect(self.master)
+ ).Else(
+ inti.connect(self.master)
+ )
+ self.comb += [phase.cke.eq(self._control.storage[1]) for phase in inti.phases]
--- /dev/null
+from migen.fhdl.std import *
+from migen.bank.description import AutoCSR
+
+from misoclib.dvisampler.edid import EDID
+from misoclib.dvisampler.clocking import Clocking
+from misoclib.dvisampler.datacapture import DataCapture
+from misoclib.dvisampler.charsync import CharSync
+from misoclib.dvisampler.wer import WER
+from misoclib.dvisampler.decoding import Decoding
+from misoclib.dvisampler.chansync import ChanSync
+from misoclib.dvisampler.analysis import SyncPolarity, ResolutionDetection, FrameExtraction
+from misoclib.dvisampler.dma import DMA
+
+class DVISampler(Module, AutoCSR):
+ def __init__(self, pads, asmiport, n_dma_slots=2):
+ self.submodules.edid = EDID(pads)
+ self.submodules.clocking = Clocking(pads)
+
+ for datan in range(3):
+ name = "data" + str(datan)
+
+ cap = DataCapture(getattr(pads, name + "_p"), getattr(pads, name + "_n"), 8)
+ setattr(self.submodules, name + "_cap", cap)
+ self.comb += cap.serdesstrobe.eq(self.clocking.serdesstrobe)
+
+ charsync = CharSync()
+ setattr(self.submodules, name + "_charsync", charsync)
+ self.comb += charsync.raw_data.eq(cap.d)
+
+ wer = WER()
+ setattr(self.submodules, name + "_wer", wer)
+ self.comb += wer.data.eq(charsync.data)
+
+ decoding = Decoding()
+ setattr(self.submodules, name + "_decod", decoding)
+ self.comb += [
+ decoding.valid_i.eq(charsync.synced),
+ decoding.input.eq(charsync.data)
+ ]
+
+ self.submodules.chansync = ChanSync()
+ self.comb += [
+ self.chansync.valid_i.eq(self.data0_decod.valid_o & \
+ self.data1_decod.valid_o & self.data2_decod.valid_o),
+ self.chansync.data_in0.eq(self.data0_decod.output),
+ self.chansync.data_in1.eq(self.data1_decod.output),
+ self.chansync.data_in2.eq(self.data2_decod.output),
+ ]
+
+ self.submodules.syncpol = SyncPolarity()
+ self.comb += [
+ self.syncpol.valid_i.eq(self.chansync.chan_synced),
+ self.syncpol.data_in0.eq(self.chansync.data_out0),
+ self.syncpol.data_in1.eq(self.chansync.data_out1),
+ self.syncpol.data_in2.eq(self.chansync.data_out2)
+ ]
+
+ self.submodules.resdetection = ResolutionDetection()
+ self.comb += [
+ self.resdetection.valid_i.eq(self.syncpol.valid_o),
+ self.resdetection.de.eq(self.syncpol.de),
+ self.resdetection.vsync.eq(self.syncpol.vsync)
+ ]
+
+ self.submodules.frame = FrameExtraction()
+ self.comb += [
+ self.frame.valid_i.eq(self.syncpol.valid_o),
+ self.frame.de.eq(self.syncpol.de),
+ self.frame.vsync.eq(self.syncpol.vsync),
+ self.frame.r.eq(self.syncpol.r),
+ self.frame.g.eq(self.syncpol.g),
+ self.frame.b.eq(self.syncpol.b)
+ ]
+
+ self.submodules.dma = DMA(asmiport, n_dma_slots)
+ self.comb += self.frame.frame.connect(self.dma.frame)
+ self.ev = self.dma.ev
+
+ autocsr_exclude = {"ev"}
--- /dev/null
+from migen.fhdl.std import *
+from migen.genlib.cdc import MultiReg, PulseSynchronizer
+from migen.genlib.fifo import AsyncFIFO
+from migen.genlib.record import Record
+from migen.bank.description import *
+from migen.flow.actor import *
+
+from misoclib.dvisampler.common import channel_layout, frame_layout
+
+class SyncPolarity(Module):
+ def __init__(self):
+ self.valid_i = Signal()
+ self.data_in0 = Record(channel_layout)
+ self.data_in1 = Record(channel_layout)
+ self.data_in2 = Record(channel_layout)
+
+ self.valid_o = Signal()
+ self.de = Signal()
+ self.hsync = Signal()
+ self.vsync = Signal()
+ self.r = Signal(8)
+ self.g = Signal(8)
+ self.b = Signal(8)
+
+ ###
+
+ de = self.data_in0.de
+ de_r = Signal()
+ c = self.data_in0.c
+ c_polarity = Signal(2)
+ c_out = Signal(2)
+
+ self.comb += [
+ self.de.eq(de_r),
+ self.hsync.eq(c_out[0]),
+ self.vsync.eq(c_out[1])
+ ]
+
+ self.sync.pix += [
+ self.valid_o.eq(self.valid_i),
+ self.r.eq(self.data_in2.d),
+ self.g.eq(self.data_in1.d),
+ self.b.eq(self.data_in0.d),
+
+ de_r.eq(de),
+ If(de_r & ~de,
+ c_polarity.eq(c),
+ c_out.eq(0)
+ ).Else(
+ c_out.eq(c ^ c_polarity)
+ )
+ ]
+
+class ResolutionDetection(Module, AutoCSR):
+ def __init__(self, nbits=11):
+ self.valid_i = Signal()
+ self.vsync = Signal()
+ self.de = Signal()
+
+ self._hres = CSRStatus(nbits)
+ self._vres = CSRStatus(nbits)
+
+ ###
+
+ # Detect DE transitions
+ de_r = Signal()
+ pn_de = Signal()
+ self.sync.pix += de_r.eq(self.de)
+ self.comb += pn_de.eq(~self.de & de_r)
+
+ # HRES
+ hcounter = Signal(nbits)
+ self.sync.pix += If(self.valid_i & self.de,
+ hcounter.eq(hcounter + 1)
+ ).Else(
+ hcounter.eq(0)
+ )
+
+ hcounter_st = Signal(nbits)
+ self.sync.pix += If(self.valid_i,
+ If(pn_de, hcounter_st.eq(hcounter))
+ ).Else(
+ hcounter_st.eq(0)
+ )
+ self.specials += MultiReg(hcounter_st, self._hres.status)
+
+ # VRES
+ vsync_r = Signal()
+ p_vsync = Signal()
+ self.sync.pix += vsync_r.eq(self.vsync),
+ self.comb += p_vsync.eq(self.vsync & ~vsync_r)
+
+ vcounter = Signal(nbits)
+ self.sync.pix += If(self.valid_i & p_vsync,
+ vcounter.eq(0)
+ ).Elif(pn_de,
+ vcounter.eq(vcounter + 1)
+ )
+
+ vcounter_st = Signal(nbits)
+ self.sync.pix += If(self.valid_i,
+ If(p_vsync, vcounter_st.eq(vcounter))
+ ).Else(
+ vcounter_st.eq(0)
+ )
+ self.specials += MultiReg(vcounter_st, self._vres.status)
+
+class FrameExtraction(Module, AutoCSR):
+ def __init__(self):
+ # in pix clock domain
+ self.valid_i = Signal()
+ self.vsync = Signal()
+ self.de = Signal()
+ self.r = Signal(8)
+ self.g = Signal(8)
+ self.b = Signal(8)
+
+ # in sys clock domain
+ self.frame = Source(frame_layout)
+ self.busy = Signal()
+
+ self._r_overflow = CSR()
+
+ ###
+
+ fifo_stb = Signal()
+ fifo_in = Record(frame_layout)
+ self.comb += [
+ fifo_stb.eq(self.valid_i & self.de),
+ fifo_in.r.eq(self.r),
+ fifo_in.g.eq(self.g),
+ fifo_in.b.eq(self.b),
+ ]
+ vsync_r = Signal()
+ self.sync.pix += [
+ If(self.vsync & ~vsync_r, fifo_in.parity.eq(~fifo_in.parity)),
+ vsync_r.eq(self.vsync)
+ ]
+
+ fifo = RenameClockDomains(AsyncFIFO(layout_len(frame_layout), 512),
+ {"write": "pix", "read": "sys"})
+ self.submodules += fifo
+ self.comb += [
+ fifo.we.eq(fifo_stb),
+ fifo.din.eq(fifo_in.raw_bits()),
+ self.frame.stb.eq(fifo.readable),
+ self.frame.payload.raw_bits().eq(fifo.dout),
+ fifo.re.eq(self.frame.ack),
+ self.busy.eq(0)
+ ]
+
+ # overflow detection
+ pix_overflow = Signal()
+ pix_overflow_reset = Signal()
+ self.sync.pix += [
+ If(fifo.we & ~fifo.writable,
+ pix_overflow.eq(1)
+ ).Elif(pix_overflow_reset,
+ pix_overflow.eq(0)
+ )
+ ]
+
+ sys_overflow = Signal()
+ self.specials += MultiReg(pix_overflow, sys_overflow)
+ self.submodules.overflow_reset = PulseSynchronizer("sys", "pix")
+ self.submodules.overflow_reset_ack = PulseSynchronizer("pix", "sys")
+ self.comb += [
+ pix_overflow_reset.eq(self.overflow_reset.o),
+ self.overflow_reset_ack.i.eq(pix_overflow_reset)
+ ]
+
+ overflow_mask = Signal()
+ self.comb += [
+ self._r_overflow.w.eq(sys_overflow & ~overflow_mask),
+ self.overflow_reset.i.eq(self._r_overflow.re)
+ ]
+ self.sync += [
+ If(self._r_overflow.re,
+ overflow_mask.eq(1)
+ ).Elif(self.overflow_reset_ack.o,
+ overflow_mask.eq(0)
+ )
+ ]
--- /dev/null
+from migen.fhdl.std import *
+from migen.genlib.cdc import MultiReg
+from migen.genlib.fifo import _inc
+from migen.genlib.record import Record, layout_len
+from migen.genlib.misc import optree
+from migen.bank.description import *
+
+from misoclib.dvisampler.common import channel_layout
+
+class _SyncBuffer(Module):
+ def __init__(self, width, depth):
+ self.din = Signal(width)
+ self.dout = Signal(width)
+ self.re = Signal()
+
+ ###
+
+ produce = Signal(max=depth)
+ consume = Signal(max=depth)
+ storage = Memory(width, depth)
+ self.specials += storage
+
+ wrport = storage.get_port(write_capable=True)
+ self.specials += wrport
+ self.comb += [
+ wrport.adr.eq(produce),
+ wrport.dat_w.eq(self.din),
+ wrport.we.eq(1)
+ ]
+ self.sync += _inc(produce, depth)
+
+ rdport = storage.get_port(async_read=True)
+ self.specials += rdport
+ self.comb += [
+ rdport.adr.eq(consume),
+ self.dout.eq(rdport.dat_r)
+ ]
+ self.sync += If(self.re, _inc(consume, depth))
+
+class ChanSync(Module, AutoCSR):
+ def __init__(self, nchan=3, depth=8):
+ self.valid_i = Signal()
+ self.chan_synced = Signal()
+
+ self._r_channels_synced = CSRStatus()
+
+ lst_control = []
+ all_control = Signal()
+ for i in range(nchan):
+ name = "data_in" + str(i)
+ data_in = Record(channel_layout, name=name)
+ setattr(self, name, data_in)
+ name = "data_out" + str(i)
+ data_out = Record(channel_layout, name=name)
+ setattr(self, name, data_out)
+
+ ###
+
+ syncbuffer = RenameClockDomains(_SyncBuffer(layout_len(channel_layout), depth), "pix")
+ self.submodules += syncbuffer
+ self.comb += [
+ syncbuffer.din.eq(data_in.raw_bits()),
+ data_out.raw_bits().eq(syncbuffer.dout)
+ ]
+ is_control = Signal()
+ self.comb += [
+ is_control.eq(~data_out.de),
+ syncbuffer.re.eq(~is_control | all_control)
+ ]
+ lst_control.append(is_control)
+
+ some_control = Signal()
+ self.comb += [
+ all_control.eq(optree("&", lst_control)),
+ some_control.eq(optree("|", lst_control))
+ ]
+ self.sync.pix += If(~self.valid_i,
+ self.chan_synced.eq(0)
+ ).Else(
+ If(some_control,
+ If(all_control,
+ self.chan_synced.eq(1)
+ ).Else(
+ self.chan_synced.eq(0)
+ )
+ )
+ )
+ self.specials += MultiReg(self.chan_synced, self._r_channels_synced.status)
--- /dev/null
+from migen.fhdl.std import *
+from migen.genlib.cdc import MultiReg
+from migen.genlib.misc import optree
+from migen.bank.description import *
+
+from misoclib.dvisampler.common import control_tokens
+
+class CharSync(Module, AutoCSR):
+ def __init__(self, required_controls=8):
+ self.raw_data = Signal(10)
+ self.synced = Signal()
+ self.data = Signal(10)
+
+ self._r_char_synced = CSRStatus()
+ self._r_ctl_pos = CSRStatus(bits_for(9))
+
+ ###
+
+ raw_data1 = Signal(10)
+ self.sync.pix += raw_data1.eq(self.raw_data)
+ raw = Signal(20)
+ self.comb += raw.eq(Cat(raw_data1, self.raw_data))
+
+ found_control = Signal()
+ control_position = Signal(max=10)
+ self.sync.pix += found_control.eq(0)
+ for i in range(10):
+ self.sync.pix += If(optree("|", [raw[i:i+10] == t for t in control_tokens]),
+ found_control.eq(1),
+ control_position.eq(i)
+ )
+
+ control_counter = Signal(max=required_controls)
+ previous_control_position = Signal(max=10)
+ word_sel = Signal(max=10)
+ self.sync.pix += [
+ If(found_control & (control_position == previous_control_position),
+ If(control_counter == (required_controls - 1),
+ control_counter.eq(0),
+ self.synced.eq(1),
+ word_sel.eq(control_position)
+ ).Else(
+ control_counter.eq(control_counter + 1)
+ )
+ ).Else(
+ control_counter.eq(0)
+ ),
+ previous_control_position.eq(control_position)
+ ]
+ self.specials += MultiReg(self.synced, self._r_char_synced.status)
+ self.specials += MultiReg(word_sel, self._r_ctl_pos.status)
+
+ self.sync.pix += self.data.eq(raw >> word_sel)
--- /dev/null
+from migen.fhdl.std import *
+from migen.genlib.cdc import MultiReg
+from migen.bank.description import *
+
+class Clocking(Module, AutoCSR):
+ def __init__(self, pads):
+ self._r_pll_reset = CSRStorage(reset=1)
+ self._r_locked = CSRStatus()
+
+ self.locked = Signal()
+ self.serdesstrobe = Signal()
+ self.clock_domains._cd_pix = ClockDomain()
+ self.clock_domains._cd_pix2x = ClockDomain()
+ self.clock_domains._cd_pix10x = ClockDomain(reset_less=True)
+
+ ###
+
+ clk_se = Signal()
+ self.specials += Instance("IBUFDS", i_I=pads.clk_p, i_IB=pads.clk_n, o_O=clk_se)
+
+ clkfbout = Signal()
+ pll_locked = Signal()
+ pll_clk0 = Signal()
+ pll_clk1 = Signal()
+ pll_clk2 = Signal()
+ self.specials += Instance("PLL_BASE",
+ p_CLKIN_PERIOD=26.7,
+ p_CLKFBOUT_MULT=20,
+ p_CLKOUT0_DIVIDE=2, # pix10x
+ p_CLKOUT1_DIVIDE=10, # pix2x
+ p_CLKOUT2_DIVIDE=20, # pix
+ p_COMPENSATION="INTERNAL",
+
+ i_CLKIN=clk_se,
+ o_CLKOUT0=pll_clk0, o_CLKOUT1=pll_clk1, o_CLKOUT2=pll_clk2,
+ o_CLKFBOUT=clkfbout, i_CLKFBIN=clkfbout,
+ o_LOCKED=pll_locked, i_RST=self._r_pll_reset.storage)
+
+ locked_async = Signal()
+ self.specials += [
+ Instance("BUFPLL", p_DIVIDE=5,
+ i_PLLIN=pll_clk0, i_GCLK=ClockSignal("pix2x"), i_LOCKED=pll_locked,
+ o_IOCLK=self._cd_pix10x.clk, o_LOCK=locked_async, o_SERDESSTROBE=self.serdesstrobe),
+ Instance("BUFG", i_I=pll_clk1, o_O=self._cd_pix2x.clk),
+ Instance("BUFG", i_I=pll_clk2, o_O=self._cd_pix.clk),
+ MultiReg(locked_async, self.locked, "sys")
+ ]
+ self.comb += self._r_locked.status.eq(self.locked)
+
+ # sychronize pix+pix2x reset
+ pix_rst_n = 1
+ for i in range(2):
+ new_pix_rst_n = Signal()
+ self.specials += Instance("FDCE", i_D=pix_rst_n, i_CE=1, i_C=ClockSignal("pix"),
+ i_CLR=~locked_async, o_Q=new_pix_rst_n)
+ pix_rst_n = new_pix_rst_n
+ self.comb += self._cd_pix.rst.eq(~pix_rst_n), self._cd_pix2x.rst.eq(~pix_rst_n)
--- /dev/null
+control_tokens = [0b1101010100, 0b0010101011, 0b0101010100, 0b1010101011]
+channel_layout = [("d", 8), ("c", 2), ("de", 1)]
+frame_layout = [("parity", 1), ("r", 8), ("g", 8), ("b", 8)]
--- /dev/null
+from migen.fhdl.std import *
+from migen.genlib.cdc import MultiReg, PulseSynchronizer
+from migen.bank.description import *
+
+class DataCapture(Module, AutoCSR):
+ def __init__(self, pad_p, pad_n, ntbits):
+ self.serdesstrobe = Signal()
+ self.d = Signal(10)
+
+ self._r_dly_ctl = CSR(6)
+ self._r_dly_busy = CSRStatus(2)
+ self._r_phase = CSRStatus(2)
+ self._r_phase_reset = CSR()
+
+ ###
+
+ # IO
+ pad_se = Signal()
+ self.specials += Instance("IBUFDS", i_I=pad_p, i_IB=pad_n, o_O=pad_se)
+
+ pad_delayed_master = Signal()
+ pad_delayed_slave = Signal()
+ delay_inc = Signal()
+ delay_ce = Signal()
+ delay_master_cal = Signal()
+ delay_master_rst = Signal()
+ delay_master_busy = Signal()
+ delay_slave_cal = Signal()
+ delay_slave_rst = Signal()
+ delay_slave_busy = Signal()
+ self.specials += Instance("IODELAY2",
+ p_SERDES_MODE="MASTER",
+ p_DELAY_SRC="IDATAIN", p_IDELAY_TYPE="DIFF_PHASE_DETECTOR",
+ p_COUNTER_WRAPAROUND="STAY_AT_LIMIT", p_DATA_RATE="SDR",
+
+ i_IDATAIN=pad_se, o_DATAOUT=pad_delayed_master,
+ i_CLK=ClockSignal("pix2x"), i_IOCLK0=ClockSignal("pix10x"),
+
+ i_INC=delay_inc, i_CE=delay_ce,
+ i_CAL=delay_master_cal, i_RST=delay_master_rst, o_BUSY=delay_master_busy,
+ i_T=1)
+ self.specials += Instance("IODELAY2",
+ p_SERDES_MODE="SLAVE",
+ p_DELAY_SRC="IDATAIN", p_IDELAY_TYPE="DIFF_PHASE_DETECTOR",
+ p_COUNTER_WRAPAROUND="WRAPAROUND", p_DATA_RATE="SDR",
+
+ i_IDATAIN=pad_se, o_DATAOUT=pad_delayed_slave,
+ i_CLK=ClockSignal("pix2x"), i_IOCLK0=ClockSignal("pix10x"),
+
+ i_INC=delay_inc, i_CE=delay_ce,
+ i_CAL=delay_slave_cal, i_RST=delay_slave_rst, o_BUSY=delay_slave_busy,
+ i_T=1)
+
+ dsr2 = Signal(5)
+ pd_valid = Signal()
+ pd_incdec = Signal()
+ pd_edge = Signal()
+ pd_cascade = Signal()
+ self.specials += Instance("ISERDES2",
+ p_SERDES_MODE="MASTER",
+ p_BITSLIP_ENABLE="FALSE", p_DATA_RATE="SDR", p_DATA_WIDTH=5,
+ p_INTERFACE_TYPE="RETIMED",
+
+ i_D=pad_delayed_master,
+ o_Q4=dsr2[4], o_Q3=dsr2[3], o_Q2=dsr2[2], o_Q1=dsr2[1],
+
+ i_BITSLIP=0, i_CE0=1, i_RST=0,
+ i_CLK0=ClockSignal("pix10x"), i_CLKDIV=ClockSignal("pix2x"),
+ i_IOCE=self.serdesstrobe,
+
+ o_VALID=pd_valid, o_INCDEC=pd_incdec,
+ i_SHIFTIN=pd_edge, o_SHIFTOUT=pd_cascade)
+ self.specials += Instance("ISERDES2",
+ p_SERDES_MODE="SLAVE",
+ p_BITSLIP_ENABLE="FALSE", p_DATA_RATE="SDR", p_DATA_WIDTH=5,
+ p_INTERFACE_TYPE="RETIMED",
+
+ i_D=pad_delayed_slave,
+ o_Q4=dsr2[0],
+
+ i_BITSLIP=0, i_CE0=1, i_RST=0,
+ i_CLK0=ClockSignal("pix10x"), i_CLKDIV=ClockSignal("pix2x"),
+ i_IOCE=self.serdesstrobe,
+
+ i_SHIFTIN=pd_cascade, o_SHIFTOUT=pd_edge)
+
+ # Phase error accumulator
+ lateness = Signal(ntbits, reset=2**(ntbits - 1))
+ too_late = Signal()
+ too_early = Signal()
+ reset_lateness = Signal()
+ self.comb += [
+ too_late.eq(lateness == (2**ntbits - 1)),
+ too_early.eq(lateness == 0)
+ ]
+ self.sync.pix2x += [
+ If(reset_lateness,
+ lateness.eq(2**(ntbits - 1))
+ ).Elif(~delay_master_busy & ~delay_slave_busy & ~too_late & ~too_early,
+ If(pd_valid & pd_incdec, lateness.eq(lateness - 1)),
+ If(pd_valid & ~pd_incdec, lateness.eq(lateness + 1))
+ )
+ ]
+
+ # Delay control
+ self.submodules.delay_master_done = PulseSynchronizer("pix2x", "sys")
+ delay_master_pending = Signal()
+ self.sync.pix2x += [
+ self.delay_master_done.i.eq(0),
+ If(~delay_master_pending,
+ If(delay_master_cal | delay_ce, delay_master_pending.eq(1))
+ ).Else(
+ If(~delay_master_busy,
+ self.delay_master_done.i.eq(1),
+ delay_master_pending.eq(0)
+ )
+ )
+ ]
+ self.submodules.delay_slave_done = PulseSynchronizer("pix2x", "sys")
+ delay_slave_pending = Signal()
+ self.sync.pix2x += [
+ self.delay_slave_done.i.eq(0),
+ If(~delay_slave_pending,
+ If(delay_slave_cal | delay_ce, delay_slave_pending.eq(1))
+ ).Else(
+ If(~delay_slave_busy,
+ self.delay_slave_done.i.eq(1),
+ delay_slave_pending.eq(0)
+ )
+ )
+ ]
+
+ self.submodules.do_delay_master_cal = PulseSynchronizer("sys", "pix2x")
+ self.submodules.do_delay_master_rst = PulseSynchronizer("sys", "pix2x")
+ self.submodules.do_delay_slave_cal = PulseSynchronizer("sys", "pix2x")
+ self.submodules.do_delay_slave_rst = PulseSynchronizer("sys", "pix2x")
+ self.submodules.do_delay_inc = PulseSynchronizer("sys", "pix2x")
+ self.submodules.do_delay_dec = PulseSynchronizer("sys", "pix2x")
+ self.comb += [
+ delay_master_cal.eq(self.do_delay_master_cal.o),
+ delay_master_rst.eq(self.do_delay_master_rst.o),
+ delay_slave_cal.eq(self.do_delay_slave_cal.o),
+ delay_slave_rst.eq(self.do_delay_slave_rst.o),
+ delay_inc.eq(self.do_delay_inc.o),
+ delay_ce.eq(self.do_delay_inc.o | self.do_delay_dec.o),
+ ]
+
+ sys_delay_master_pending = Signal()
+ self.sync += [
+ If(self.do_delay_master_cal.i | self.do_delay_inc.i | self.do_delay_dec.i,
+ sys_delay_master_pending.eq(1)
+ ).Elif(self.delay_master_done.o,
+ sys_delay_master_pending.eq(0)
+ )
+ ]
+ sys_delay_slave_pending = Signal()
+ self.sync += [
+ If(self.do_delay_slave_cal.i | self.do_delay_inc.i | self.do_delay_dec.i,
+ sys_delay_slave_pending.eq(1)
+ ).Elif(self.delay_slave_done.o,
+ sys_delay_slave_pending.eq(0)
+ )
+ ]
+
+ self.comb += [
+ self.do_delay_master_cal.i.eq(self._r_dly_ctl.re & self._r_dly_ctl.r[0]),
+ self.do_delay_master_rst.i.eq(self._r_dly_ctl.re & self._r_dly_ctl.r[1]),
+ self.do_delay_slave_cal.i.eq(self._r_dly_ctl.re & self._r_dly_ctl.r[2]),
+ self.do_delay_slave_rst.i.eq(self._r_dly_ctl.re & self._r_dly_ctl.r[3]),
+ self.do_delay_inc.i.eq(self._r_dly_ctl.re & self._r_dly_ctl.r[4]),
+ self.do_delay_dec.i.eq(self._r_dly_ctl.re & self._r_dly_ctl.r[5]),
+ self._r_dly_busy.status.eq(Cat(sys_delay_master_pending, sys_delay_slave_pending))
+ ]
+
+ # Phase detector control
+ self.specials += MultiReg(Cat(too_late, too_early), self._r_phase.status)
+ self.submodules.do_reset_lateness = PulseSynchronizer("sys", "pix2x")
+ self.comb += [
+ reset_lateness.eq(self.do_reset_lateness.o),
+ self.do_reset_lateness.i.eq(self._r_phase_reset.re)
+ ]
+
+ # 5:10 deserialization
+ dsr = Signal(10)
+ self.sync.pix2x += dsr.eq(Cat(dsr[5:], dsr2))
+ self.sync.pix += self.d.eq(dsr)
--- /dev/null
+from migen.fhdl.std import *
+from migen.genlib.fifo import AsyncFIFO
+from migen.genlib.record import layout_len
+from migen.bank.description import AutoCSR
+from migen.actorlib import structuring, dma_lasmi, spi
+
+from misoclib.dvisampler.edid import EDID
+from misoclib.dvisampler.clocking import Clocking
+from misoclib.dvisampler.datacapture import DataCapture
+
+class RawDVISampler(Module, AutoCSR):
+ def __init__(self, pads, asmiport):
+ self.submodules.edid = EDID(pads)
+ self.submodules.clocking = Clocking(pads)
+
+ invert = False
+ try:
+ s = getattr(pads, "data0")
+ except AttributeError:
+ s = getattr(pads, "data0_n")
+ invert = True
+ self.submodules.data0_cap = DataCapture(8, invert)
+ self.comb += [
+ self.data0_cap.pad.eq(s),
+ self.data0_cap.serdesstrobe.eq(self.clocking.serdesstrobe)
+ ]
+
+ fifo = RenameClockDomains(AsyncFIFO(10, 256),
+ {"write": "pix", "read": "sys"})
+ self.submodules += fifo
+ self.comb += [
+ fifo.din.eq(self.data0_cap.d),
+ fifo.we.eq(1)
+ ]
+
+ pack_factor = asmiport.hub.dw//16
+ self.submodules.packer = structuring.Pack([("word", 10), ("pad", 6)], pack_factor)
+ self.submodules.cast = structuring.Cast(self.packer.source.payload.layout, asmiport.hub.dw)
+ self.submodules.dma = spi.DMAWriteController(dma_lasmi.Writer(lasmim), spi.MODE_SINGLE_SHOT)
+ self.comb += [
+ self.packer.sink.stb.eq(fifo.readable),
+ fifo.re.eq(self.packer.sink.ack),
+ self.packer.sink.payload.word.eq(fifo.dout),
+ self.packer.source.connect_flat(self.cast.sink),
+ self.cast.source.connect_flat(self.dma.data)
+ ]
--- /dev/null
+from migen.fhdl.std import *
+from migen.genlib.record import Record
+
+from misoclib.dvisampler.common import control_tokens, channel_layout
+
+class Decoding(Module):
+ def __init__(self):
+ self.valid_i = Signal()
+ self.input = Signal(10)
+ self.valid_o = Signal()
+ self.output = Record(channel_layout)
+
+ ###
+
+ self.sync.pix += self.output.de.eq(1)
+ for i, t in enumerate(control_tokens):
+ self.sync.pix += If(self.input == t,
+ self.output.de.eq(0),
+ self.output.c.eq(i)
+ )
+ self.sync.pix += self.output.d[0].eq(self.input[0] ^ self.input[9])
+ for i in range(1, 8):
+ self.sync.pix += self.output.d[i].eq(self.input[i] ^ self.input[i-1] ^ ~self.input[8])
+ self.sync.pix += self.valid_o.eq(self.valid_i)
--- /dev/null
+from migen.fhdl.std import *
+from migen.genlib.fsm import FSM, NextState
+from migen.bank.description import *
+from migen.bank.eventmanager import *
+from migen.flow.actor import *
+from migen.actorlib import dma_lasmi
+
+from misoclib.dvisampler.common import frame_layout
+
+# Slot status: EMPTY=0 LOADED=1 PENDING=2
+class _Slot(Module, AutoCSR):
+ def __init__(self, addr_bits, alignment_bits):
+ self.ev_source = EventSourceLevel()
+ self.address = Signal(addr_bits)
+ self.address_valid = Signal()
+ self.address_done = Signal()
+
+ self._r_status = CSRStorage(2, write_from_dev=True)
+ self._r_address = CSRStorage(addr_bits + alignment_bits, alignment_bits=alignment_bits)
+
+ ###
+
+ self.comb += [
+ self.address.eq(self._r_address.storage),
+ self.address_valid.eq(self._r_status.storage[0]),
+ self._r_status.dat_w.eq(2),
+ self._r_status.we.eq(self.address_done),
+ self.ev_source.trigger.eq(self._r_status.storage[1])
+ ]
+
+class _SlotArray(Module, AutoCSR):
+ def __init__(self, nslots, addr_bits, alignment_bits):
+ self.submodules.ev = EventManager()
+ self.address = Signal(addr_bits)
+ self.address_valid = Signal()
+ self.address_done = Signal()
+
+ ###
+
+ slots = [_Slot(addr_bits, alignment_bits) for i in range(nslots)]
+ for n, slot in enumerate(slots):
+ setattr(self.submodules, "slot"+str(n), slot)
+ setattr(self.ev, "slot"+str(n), slot.ev_source)
+ self.ev.finalize()
+
+ change_slot = Signal()
+ current_slot = Signal(max=nslots)
+ self.sync += If(change_slot, [If(slot.address_valid, current_slot.eq(n)) for n, slot in reversed(list(enumerate(slots)))])
+ self.comb += change_slot.eq(~self.address_valid | self.address_done)
+
+ self.comb += [
+ self.address.eq(Array(slot.address for slot in slots)[current_slot]),
+ self.address_valid.eq(Array(slot.address_valid for slot in slots)[current_slot])
+ ]
+ self.comb += [slot.address_done.eq(self.address_done & (current_slot == n)) for n, slot in enumerate(slots)]
+
+class DMA(Module):
+ def __init__(self, lasmim, nslots):
+ bus_aw = lasmim.aw
+ bus_dw = lasmim.dw
+ alignment_bits = bits_for(bus_dw//8) - 1
+
+ self.frame = Sink(frame_layout)
+ self._r_frame_size = CSRStorage(bus_aw + alignment_bits, alignment_bits=alignment_bits)
+ self.submodules._slot_array = _SlotArray(nslots, bus_aw, alignment_bits)
+ self.ev = self._slot_array.ev
+
+ ###
+
+ # start of frame detection
+ sof = Signal()
+ parity_r = Signal()
+ self.sync += If(self.frame.stb & self.frame.ack, parity_r.eq(self.frame.payload.parity))
+ self.comb += sof.eq(parity_r ^ self.frame.payload.parity)
+
+ # address generator + maximum memory word count to prevent DMA buffer overrun
+ reset_words = Signal()
+ count_word = Signal()
+ last_word = Signal()
+ current_address = Signal(bus_aw)
+ mwords_remaining = Signal(bus_aw)
+ self.comb += last_word.eq(mwords_remaining == 1)
+ self.sync += [
+ If(reset_words,
+ current_address.eq(self._slot_array.address),
+ mwords_remaining.eq(self._r_frame_size.storage)
+ ).Elif(count_word,
+ current_address.eq(current_address + 1),
+ mwords_remaining.eq(mwords_remaining - 1)
+ )
+ ]
+
+ # pack pixels into memory words
+ write_pixel = Signal()
+ last_pixel = Signal()
+ cur_memory_word = Signal(bus_dw)
+ encoded_pixel = Signal(32)
+ self.comb += [
+ encoded_pixel.eq(Cat(
+ self.frame.payload.b[6:], self.frame.payload.b,
+ self.frame.payload.g[6:], self.frame.payload.g,
+ self.frame.payload.r[6:], self.frame.payload.r))
+ ]
+ pack_factor = bus_dw//32
+ assert(pack_factor & (pack_factor - 1) == 0) # only support powers of 2
+ pack_counter = Signal(max=pack_factor)
+ self.comb += last_pixel.eq(pack_counter == (pack_factor - 1))
+ self.sync += If(write_pixel,
+ [If(pack_counter == (pack_factor-i-1),
+ cur_memory_word[32*i:32*(i+1)].eq(encoded_pixel)) for i in range(pack_factor)],
+ pack_counter.eq(pack_counter + 1)
+ )
+
+ # bus accessor
+ self.submodules._bus_accessor = dma_lasmi.Writer(lasmim)
+ self.comb += [
+ self._bus_accessor.address_data.payload.a.eq(current_address),
+ self._bus_accessor.address_data.payload.d.eq(cur_memory_word)
+ ]
+
+ # control FSM
+ fsm = FSM()
+ self.submodules += fsm
+
+ fsm.act("WAIT_SOF",
+ reset_words.eq(1),
+ self.frame.ack.eq(~self._slot_array.address_valid | ~sof),
+ If(self._slot_array.address_valid & sof & self.frame.stb, NextState("TRANSFER_PIXEL"))
+ )
+ fsm.act("TRANSFER_PIXEL",
+ self.frame.ack.eq(1),
+ If(self.frame.stb,
+ write_pixel.eq(1),
+ If(last_pixel, NextState("TO_MEMORY"))
+ )
+ )
+ fsm.act("TO_MEMORY",
+ self._bus_accessor.address_data.stb.eq(1),
+ If(self._bus_accessor.address_data.ack,
+ count_word.eq(1),
+ If(last_word,
+ NextState("EOF")
+ ).Else(
+ NextState("TRANSFER_PIXEL")
+ )
+ )
+ )
+ fsm.act("EOF",
+ If(~self._bus_accessor.busy,
+ self._slot_array.address_done.eq(1),
+ NextState("WAIT_SOF")
+ )
+ )
+
+ def get_csrs(self):
+ return [self._r_frame_size] + self._slot_array.get_csrs()
--- /dev/null
+from migen.fhdl.std import *
+from migen.fhdl.specials import Tristate
+from migen.genlib.cdc import MultiReg
+from migen.genlib.fsm import FSM, NextState
+from migen.genlib.misc import chooser
+from migen.bank.description import CSRStorage, CSRStatus, AutoCSR
+
+_default_edid = [
+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x3D, 0x17, 0x32, 0x12, 0x2A, 0x6A, 0xBF, 0x00,
+ 0x05, 0x17, 0x01, 0x03, 0x80, 0x28, 0x1E, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xB2, 0x0C, 0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x18, 0x88,
+ 0x36, 0x00, 0x28, 0x1E, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x4D, 0x31, 0x20,
+ 0x44, 0x56, 0x49, 0x20, 0x6D, 0x69, 0x78, 0x65, 0x72, 0x0A, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34,
+]
+
+class EDID(Module, AutoCSR):
+ def __init__(self, pads, default=_default_edid):
+ self._r_hpd_notif = CSRStatus()
+ self._r_hpd_en = CSRStorage()
+ self.specials.mem = Memory(8, 128, init=default)
+
+ ###
+
+ # HPD
+ if hasattr(pads, "hpd_notif"):
+ self.specials += MultiReg(pads.hpd_notif, self._r_hpd_notif.status)
+ else:
+ self.comb += self._r_hpd_notif.status.eq(1)
+ if hasattr(pads, "hpd_en"):
+ self.comb += pads.hpd_en.eq(self._r_hpd_en.storage)
+
+ # EDID
+ scl_raw = Signal()
+ sda_i = Signal()
+ sda_drv = Signal()
+ _sda_drv_reg = Signal()
+ _sda_i_async = Signal()
+ self.sync += _sda_drv_reg.eq(sda_drv)
+ self.specials += [
+ MultiReg(pads.scl, scl_raw),
+ Tristate(pads.sda, 0, _sda_drv_reg, _sda_i_async),
+ MultiReg(_sda_i_async, sda_i)
+ ]
+
+ scl_i = Signal()
+ samp_count = Signal(6)
+ samp_carry = Signal()
+ self.sync += [
+ Cat(samp_count, samp_carry).eq(samp_count + 1),
+ If(samp_carry, scl_i.eq(scl_raw))
+ ]
+
+ scl_r = Signal()
+ sda_r = Signal()
+ scl_rising = Signal()
+ sda_rising = Signal()
+ sda_falling = Signal()
+ self.sync += [
+ scl_r.eq(scl_i),
+ sda_r.eq(sda_i)
+ ]
+ self.comb += [
+ scl_rising.eq(scl_i & ~scl_r),
+ sda_rising.eq(sda_i & ~sda_r),
+ sda_falling.eq(~sda_i & sda_r)
+ ]
+
+ start = Signal()
+ self.comb += start.eq(scl_i & sda_falling)
+
+ din = Signal(8)
+ counter = Signal(max=9)
+ self.sync += [
+ If(start, counter.eq(0)),
+ If(scl_rising,
+ If(counter == 8,
+ counter.eq(0)
+ ).Else(
+ counter.eq(counter + 1),
+ din.eq(Cat(sda_i, din[:7]))
+ )
+ )
+ ]
+
+ is_read = Signal()
+ update_is_read = Signal()
+ self.sync += If(update_is_read, is_read.eq(din[0]))
+
+ offset_counter = Signal(max=128)
+ oc_load = Signal()
+ oc_inc = Signal()
+ self.sync += [
+ If(oc_load,
+ offset_counter.eq(din)
+ ).Elif(oc_inc,
+ offset_counter.eq(offset_counter + 1)
+ )
+ ]
+ rdport = self.mem.get_port()
+ self.specials += rdport
+ self.comb += rdport.adr.eq(offset_counter)
+ data_bit = Signal()
+
+ zero_drv = Signal()
+ data_drv = Signal()
+ self.comb += If(zero_drv, sda_drv.eq(1)).Elif(data_drv, sda_drv.eq(~data_bit))
+
+ data_drv_en = Signal()
+ data_drv_stop = Signal()
+ self.sync += If(data_drv_en, data_drv.eq(1)).Elif(data_drv_stop, data_drv.eq(0))
+ self.sync += If(data_drv_en, chooser(rdport.dat_r, counter, data_bit, 8, reverse=True))
+
+ fsm = FSM()
+ self.submodules += fsm
+
+ fsm.act("WAIT_START")
+ fsm.act("RCV_ADDRESS",
+ If(counter == 8,
+ If(din[1:] == 0x50,
+ update_is_read.eq(1),
+ NextState("ACK_ADDRESS0")
+ ).Else(
+ NextState("WAIT_START")
+ )
+ )
+ )
+ fsm.act("ACK_ADDRESS0",
+ If(~scl_i, NextState("ACK_ADDRESS1"))
+ )
+ fsm.act("ACK_ADDRESS1",
+ zero_drv.eq(1),
+ If(scl_i, NextState("ACK_ADDRESS2"))
+ )
+ fsm.act("ACK_ADDRESS2",
+ zero_drv.eq(1),
+ If(~scl_i,
+ If(is_read,
+ NextState("READ")
+ ).Else(
+ NextState("RCV_OFFSET")
+ )
+ )
+ )
+
+ fsm.act("RCV_OFFSET",
+ If(counter == 8,
+ oc_load.eq(1),
+ NextState("ACK_OFFSET0")
+ )
+ )
+ fsm.act("ACK_OFFSET0",
+ If(~scl_i, NextState("ACK_OFFSET1"))
+ )
+ fsm.act("ACK_OFFSET1",
+ zero_drv.eq(1),
+ If(scl_i, NextState("ACK_OFFSET2"))
+ )
+ fsm.act("ACK_OFFSET2",
+ zero_drv.eq(1),
+ If(~scl_i, NextState("RCV_ADDRESS"))
+ )
+
+ fsm.act("READ",
+ If(~scl_i,
+ If(counter == 8,
+ data_drv_stop.eq(1),
+ NextState("ACK_READ")
+ ).Else(
+ data_drv_en.eq(1)
+ )
+ )
+ )
+ fsm.act("ACK_READ",
+ If(scl_rising,
+ oc_inc.eq(1),
+ If(sda_i,
+ NextState("WAIT_START")
+ ).Else(
+ NextState("READ")
+ )
+ )
+ )
+
+ for state in fsm.actions.keys():
+ fsm.act(state, If(start, NextState("RCV_ADDRESS")))
+ fsm.act(state, If(~self._r_hpd_en.storage, NextState("WAIT_START")))
--- /dev/null
+from migen.fhdl.std import *
+from migen.bank.description import *
+from migen.genlib.misc import optree
+from migen.genlib.cdc import PulseSynchronizer
+
+from misoclib.dvisampler.common import control_tokens
+
+class WER(Module, AutoCSR):
+ def __init__(self, period_bits=24):
+ self.data = Signal(10)
+ self._r_update = CSR()
+ self._r_value = CSRStatus(period_bits)
+
+ ###
+
+ # pipeline stage 1
+ # we ignore the 10th (inversion) bit, as it is independent of the transition minimization
+ data_r = Signal(9)
+ self.sync.pix += data_r.eq(self.data[:9])
+
+ # pipeline stage 2
+ transitions = Signal(8)
+ self.comb += [transitions[i].eq(data_r[i] ^ data_r[i+1]) for i in range(8)]
+ transition_count = Signal(max=9)
+ self.sync.pix += transition_count.eq(optree("+", [transitions[i] for i in range(8)]))
+
+ is_control = Signal()
+ self.sync.pix += is_control.eq(optree("|", [data_r == ct for ct in control_tokens]))
+
+ # pipeline stage 3
+ is_error = Signal()
+ self.sync.pix += is_error.eq((transition_count > 4) & ~is_control)
+
+ # counter
+ period_counter = Signal(period_bits)
+ period_done = Signal()
+ self.sync.pix += Cat(period_counter, period_done).eq(period_counter + 1)
+
+ wer_counter = Signal(period_bits)
+ wer_counter_r = Signal(period_bits)
+ wer_counter_r_updated = Signal()
+ self.sync.pix += [
+ wer_counter_r_updated.eq(period_done),
+ If(period_done,
+ wer_counter_r.eq(wer_counter),
+ wer_counter.eq(0)
+ ).Elif(is_error,
+ wer_counter.eq(wer_counter + 1)
+ )
+ ]
+
+ # sync to system clock domain
+ wer_counter_sys = Signal(period_bits)
+ self.submodules.ps_counter = PulseSynchronizer("pix", "sys")
+ self.comb += self.ps_counter.i.eq(wer_counter_r_updated)
+ self.sync += If(self.ps_counter.o, wer_counter_sys.eq(wer_counter_r))
+
+ # register interface
+ self.sync += If(self._r_update.re, self._r_value.status.eq(wer_counter_sys))
--- /dev/null
+from migen.fhdl.std import *
+from migen.flow.actor import *
+from migen.flow.network import *
+from migen.bank.description import CSRStorage, AutoCSR
+from migen.actorlib import dma_lasmi, structuring, sim, spi
+
+from misoclib.framebuffer.format import bpp, pixel_layout, FrameInitiator, VTG
+from misoclib.framebuffer.phy import Driver
+
+class Framebuffer(Module, AutoCSR):
+ def __init__(self, pads_vga, pads_dvi, lasmim, simulation=False):
+ pack_factor = lasmim.dw//(2*bpp)
+ packed_pixels = structuring.pack_layout(pixel_layout, pack_factor)
+
+ self._enable = CSRStorage()
+ self.fi = FrameInitiator()
+ self.dma = spi.DMAReadController(dma_lasmi.Reader(lasmim), spi.MODE_EXTERNAL, length_reset=640*480*4)
+ self.driver = Driver(pads_vga, pads_dvi)
+
+ cast = structuring.Cast(lasmim.dw, packed_pixels, reverse_to=True)
+ unpack = structuring.Unpack(pack_factor, pixel_layout)
+ vtg = VTG()
+
+ g = DataFlowGraph()
+ g.add_connection(self.fi, vtg, sink_ep="timing")
+ g.add_connection(self.dma, cast)
+ g.add_connection(cast, unpack)
+ g.add_connection(unpack, vtg, sink_ep="pixels")
+ g.add_connection(vtg, self.driver)
+ self.submodules += CompositeActor(g)
+
+ self.comb += [
+ self.fi.trigger.eq(self._enable.storage),
+ self.dma.generator.trigger.eq(self._enable.storage),
+ ]
+
+class Blender(PipelinedActor, AutoCSR):
+ def __init__(self, nimages, latency):
+ sink_layout = [("i"+str(i), pixel_layout) for i in range(nimages)]
+ self.sink = Sink(sink_layout)
+ self.source = Source(pixel_layout)
+ factors = []
+ for i in range(nimages):
+ name = "f"+str(i)
+ csr = CSRStorage(8, name=name)
+ setattr(self, name, csr)
+ factors.append(csr.storage)
+ PipelinedActor.__init__(self, latency)
+
+ ###
+
+ sink_registered = Record(sink_layout)
+ self.sync += If(self.pipe_ce, sink_registered.eq(self.sink.payload))
+
+ imgs = [getattr(sink_registered, "i"+str(i)) for i in range(nimages)]
+ outval = Record(pixel_layout)
+ for e in pixel_layout:
+ name = e[0]
+ inpixs = [getattr(img, name) for img in imgs]
+ outpix = getattr(outval, name)
+ for component in ["r", "g", "b"]:
+ incomps = [getattr(pix, component) for pix in inpixs]
+ outcomp = getattr(outpix, component)
+ outcomp_full = Signal(19)
+ self.comb += [
+ outcomp_full.eq(sum(incomp*factor for incomp, factor in zip(incomps, factors))),
+ If(outcomp_full[18],
+ outcomp.eq(2**10 - 1) # saturate on overflow
+ ).Else(
+ outcomp.eq(outcomp_full[8:18])
+ )
+ ]
+
+ pipe_stmts = []
+ for i in range(latency-1):
+ new_outval = Record(pixel_layout)
+ pipe_stmts.append(new_outval.eq(outval))
+ outval = new_outval
+ self.sync += If(self.pipe_ce, pipe_stmts)
+ self.comb += self.source.payload.eq(outval)
+
+class MixFramebuffer(Module, AutoCSR):
+ def __init__(self, pads_vga, pads_dvi, *lasmims, blender_latency=5):
+ pack_factor = lasmims[0].dw//(2*bpp)
+ packed_pixels = structuring.pack_layout(pixel_layout, pack_factor)
+
+ self._enable = CSRStorage()
+ self.fi = FrameInitiator()
+ self.blender = Blender(len(lasmims), blender_latency)
+ self.driver = Driver(pads_vga, pads_dvi)
+ self.comb += self.fi.trigger.eq(self._enable.storage)
+
+ g = DataFlowGraph()
+ for n, lasmim in enumerate(lasmims):
+ dma = spi.DMAReadController(dma_lasmi.Reader(lasmim), spi.MODE_EXTERNAL, length_reset=640*480*4)
+ cast = structuring.Cast(lasmim.dw, packed_pixels, reverse_to=True)
+ unpack = structuring.Unpack(pack_factor, pixel_layout)
+
+ g.add_connection(dma, cast)
+ g.add_connection(cast, unpack)
+ g.add_connection(unpack, self.blender, sink_subr=["i"+str(n)])
+
+ self.comb += dma.generator.trigger.eq(self._enable.storage)
+ setattr(self, "dma"+str(n), dma)
+
+ vtg = VTG()
+ g.add_connection(self.fi, vtg, sink_ep="timing")
+ g.add_connection(self.blender, vtg, sink_ep="pixels")
+ g.add_connection(vtg, self.driver)
+ self.submodules += CompositeActor(g)
--- /dev/null
+from migen.fhdl.std import *
+from migen.genlib.misc import optree
+
+control_tokens = [0b1101010100, 0b0010101011, 0b0101010100, 0b1010101011]
+
+class Encoder(Module):
+ def __init__(self):
+ self.d = Signal(8)
+ self.c = Signal(2)
+ self.de = Signal()
+
+ self.out = Signal(10)
+
+ ###
+
+ # stage 1 - count number of 1s in data
+ d = Signal(8)
+ n1d = Signal(max=9)
+ self.sync += [
+ n1d.eq(optree("+", [self.d[i] for i in range(8)])),
+ d.eq(self.d)
+ ]
+
+ # stage 2 - add 9th bit
+ q_m = Signal(9)
+ q_m8_n = Signal()
+ self.comb += q_m8_n.eq((n1d > 4) | ((n1d == 4) & ~d[0]))
+ for i in range(8):
+ if i:
+ curval = curval ^ d[i] ^ q_m8_n
+ else:
+ curval = d[0]
+ self.sync += q_m[i].eq(curval)
+ self.sync += q_m[8].eq(~q_m8_n)
+
+ # stage 3 - count number of 1s and 0s in q_m[:8]
+ q_m_r = Signal(9)
+ n0q_m = Signal(max=9)
+ n1q_m = Signal(max=9)
+ self.sync += [
+ n0q_m.eq(optree("+", [~q_m[i] for i in range(8)])),
+ n1q_m.eq(optree("+", [q_m[i] for i in range(8)])),
+ q_m_r.eq(q_m)
+ ]
+
+ # stage 4 - final encoding
+ cnt = Signal((6, True))
+
+ s_c = self.c
+ s_de = self.de
+ for p in range(3):
+ new_c = Signal(2)
+ new_de = Signal()
+ self.sync += new_c.eq(s_c), new_de.eq(s_de)
+ s_c, s_de = new_c, new_de
+
+ self.sync += If(s_de,
+ If((cnt == 0) | (n1q_m == n0q_m),
+ self.out[9].eq(~q_m_r[8]),
+ self.out[8].eq(q_m_r[8]),
+ If(q_m_r[8],
+ self.out[:8].eq(q_m_r[:8]),
+ cnt.eq(cnt + n1q_m - n0q_m)
+ ).Else(
+ self.out[:8].eq(~q_m_r[:8]),
+ cnt.eq(cnt + n0q_m - n1q_m)
+ )
+ ).Else(
+ If((~cnt[5] & (n1q_m > n0q_m)) | (cnt[5] & (n0q_m > n1q_m)),
+ self.out[9].eq(1),
+ self.out[8].eq(q_m_r[8]),
+ self.out[:8].eq(~q_m_r[:8]),
+ cnt.eq(cnt + Cat(0, q_m_r[8]) + n0q_m - n1q_m)
+ ).Else(
+ self.out[9].eq(0),
+ self.out[8].eq(q_m_r[8]),
+ self.out[:8].eq(q_m_r[:8]),
+ cnt.eq(cnt - Cat(0, ~q_m_r[8]) + n1q_m - n0q_m)
+ )
+ )
+ ).Else(
+ self.out.eq(Array(control_tokens)[s_c]),
+ cnt.eq(0)
+ )
+
+class _EncoderSerializer(Module):
+ def __init__(self, serdesstrobe, pad_p, pad_n):
+ self.submodules.encoder = RenameClockDomains(Encoder(), "pix")
+ self.d, self.c, self.de = self.encoder.d, self.encoder.c, self.encoder.de
+
+ ###
+
+ # 2X soft serialization
+ ed_2x = Signal(5)
+ self.sync.pix2x += ed_2x.eq(Mux(ClockSignal("pix"), self.encoder.out[:5], self.encoder.out[5:]))
+
+ # 5X hard serialization
+ cascade_di = Signal()
+ cascade_do = Signal()
+ cascade_ti = Signal()
+ cascade_to = Signal()
+ pad_se = Signal()
+ self.specials += [
+ Instance("OSERDES2",
+ p_DATA_WIDTH=5, p_DATA_RATE_OQ="SDR", p_DATA_RATE_OT="SDR",
+ p_SERDES_MODE="MASTER", p_OUTPUT_MODE="DIFFERENTIAL",
+
+ o_OQ=pad_se,
+ i_OCE=1, i_IOCE=serdesstrobe, i_RST=0,
+ i_CLK0=ClockSignal("pix10x"), i_CLK1=0, i_CLKDIV=ClockSignal("pix2x"),
+ i_D1=ed_2x[4], i_D2=0, i_D3=0, i_D4=0,
+ i_T1=0, i_T2=0, i_T3=0, i_T4=0,
+ i_TRAIN=0, i_TCE=1,
+ i_SHIFTIN1=1, i_SHIFTIN2=1,
+ i_SHIFTIN3=cascade_do, i_SHIFTIN4=cascade_to,
+ o_SHIFTOUT1=cascade_di, o_SHIFTOUT2=cascade_ti),
+ Instance("OSERDES2",
+ p_DATA_WIDTH=5, p_DATA_RATE_OQ="SDR", p_DATA_RATE_OT="SDR",
+ p_SERDES_MODE="SLAVE", p_OUTPUT_MODE="DIFFERENTIAL",
+
+ i_OCE=1, i_IOCE=serdesstrobe, i_RST=0,
+ i_CLK0=ClockSignal("pix10x"), i_CLK1=0, i_CLKDIV=ClockSignal("pix2x"),
+ i_D1=ed_2x[0], i_D2=ed_2x[1], i_D3=ed_2x[2], i_D4=ed_2x[3],
+ i_T1=0, i_T2=0, i_T3=0, i_T4=0,
+ i_TRAIN=0, i_TCE=1,
+ i_SHIFTIN1=cascade_di, i_SHIFTIN2=cascade_ti,
+ i_SHIFTIN3=1, i_SHIFTIN4=1,
+ o_SHIFTOUT3=cascade_do, o_SHIFTOUT4=cascade_to),
+ Instance("OBUFDS", i_I=pad_se, o_O=pad_p, o_OB=pad_n)
+ ]
+
+
+class PHY(Module):
+ def __init__(self, serdesstrobe, pads):
+ self.hsync = Signal()
+ self.vsync = Signal()
+ self.de = Signal()
+ self.r = Signal(8)
+ self.g = Signal(8)
+ self.b = Signal(8)
+
+ ###
+
+ self.submodules.es0 = _EncoderSerializer(serdesstrobe, pads.data0_p, pads.data0_n)
+ self.submodules.es1 = _EncoderSerializer(serdesstrobe, pads.data1_p, pads.data1_n)
+ self.submodules.es2 = _EncoderSerializer(serdesstrobe, pads.data2_p, pads.data2_n)
+ self.comb += [
+ self.es0.d.eq(self.r),
+ self.es1.d.eq(self.g),
+ self.es2.d.eq(self.b),
+ self.es0.c.eq(Cat(self.hsync, self.vsync)),
+ self.es1.c.eq(0),
+ self.es2.c.eq(0),
+ self.es0.de.eq(self.de),
+ self.es1.de.eq(self.de),
+ self.es2.de.eq(self.de),
+ ]
+
+class _EncoderTB(Module):
+ def __init__(self, inputs):
+ self.outs = []
+ self._iter_inputs = iter(inputs)
+ self._end_cycle = None
+ self.submodules.dut = Encoder()
+ self.comb += self.dut.de.eq(1)
+
+ def do_simulation(self, s):
+ if self._end_cycle is None:
+ try:
+ nv = next(self._iter_inputs)
+ except StopIteration:
+ self._end_cycle = s.cycle_counter + 4
+ else:
+ s.wr(self.dut.d, nv)
+ if s.cycle_counter == self._end_cycle:
+ s.interrupt = True
+ if s.cycle_counter > 4:
+ self.outs.append(s.rd(self.dut.out))
+
+def _bit(i, n):
+ return (i >> n) & 1
+
+def _decode_tmds(b):
+ try:
+ c = control_tokens.index(b)
+ de = False
+ except ValueError:
+ c = 0
+ de = True
+ vsync = bool(c & 2)
+ hsync = bool(c & 1)
+
+ value = _bit(b, 0) ^ _bit(b, 9)
+ for i in range(1, 8):
+ value |= (_bit(b, i) ^ _bit(b, i-1) ^ (~_bit(b, 8) & 1)) << i
+
+ return de, hsync, vsync, value
+
+if __name__ == "__main__":
+ from migen.sim.generic import Simulator
+ from random import Random
+
+ rng = Random(788)
+ test_list = [rng.randrange(256) for i in range(500)]
+ tb = _EncoderTB(test_list)
+ Simulator(tb).run()
+
+ check = [_decode_tmds(out)[3] for out in tb.outs]
+ assert(check == test_list)
+
+ nb0 = 0
+ nb1 = 0
+ for out in tb.outs:
+ for i in range(10):
+ if _bit(out, i):
+ nb1 += 1
+ else:
+ nb0 += 1
+ print("0/1: {}/{} ({:.2f})".format(nb0, nb1, nb0/nb1))
--- /dev/null
+from migen.fhdl.std import *
+from migen.flow.actor import *
+from migen.bank.description import CSRStorage
+from migen.actorlib import spi
+
+_hbits = 11
+_vbits = 12
+
+bpp = 32
+bpc = 10
+pixel_layout_s = [
+ ("pad", bpp-3*bpc),
+ ("r", bpc),
+ ("g", bpc),
+ ("b", bpc)
+]
+pixel_layout = [
+ ("p0", pixel_layout_s),
+ ("p1", pixel_layout_s)
+]
+
+bpc_phy = 8
+phy_layout_s = [
+ ("r", bpc_phy),
+ ("g", bpc_phy),
+ ("b", bpc_phy)
+]
+phy_layout = [
+ ("hsync", 1),
+ ("vsync", 1),
+ ("de", 1),
+ ("p0", phy_layout_s),
+ ("p1", phy_layout_s)
+]
+
+class FrameInitiator(spi.SingleGenerator):
+ def __init__(self):
+ layout = [
+ ("hres", _hbits, 640, 1),
+ ("hsync_start", _hbits, 656, 1),
+ ("hsync_end", _hbits, 752, 1),
+ ("hscan", _hbits, 800, 1),
+
+ ("vres", _vbits, 480),
+ ("vsync_start", _vbits, 492),
+ ("vsync_end", _vbits, 494),
+ ("vscan", _vbits, 525)
+ ]
+ spi.SingleGenerator.__init__(self, layout, spi.MODE_EXTERNAL)
+
+class VTG(Module):
+ def __init__(self):
+ self.timing = Sink([
+ ("hres", _hbits),
+ ("hsync_start", _hbits),
+ ("hsync_end", _hbits),
+ ("hscan", _hbits),
+ ("vres", _vbits),
+ ("vsync_start", _vbits),
+ ("vsync_end", _vbits),
+ ("vscan", _vbits)])
+ self.pixels = Sink(pixel_layout)
+ self.phy = Source(phy_layout)
+ self.busy = Signal()
+
+ hactive = Signal()
+ vactive = Signal()
+ active = Signal()
+
+ generate_en = Signal()
+ hcounter = Signal(_hbits)
+ vcounter = Signal(_vbits)
+
+ skip = bpc - bpc_phy
+ self.comb += [
+ active.eq(hactive & vactive),
+ If(active,
+ [getattr(getattr(self.phy.payload, p), c).eq(getattr(getattr(self.pixels.payload, p), c)[skip:])
+ for p in ["p0", "p1"] for c in ["r", "g", "b"]],
+ self.phy.payload.de.eq(1)
+ ),
+
+ generate_en.eq(self.timing.stb & (~active | self.pixels.stb)),
+ self.pixels.ack.eq(self.phy.ack & active),
+ self.phy.stb.eq(generate_en),
+ self.busy.eq(generate_en)
+ ]
+ tp = self.timing.payload
+ self.sync += [
+ self.timing.ack.eq(0),
+ If(generate_en & self.phy.ack,
+ hcounter.eq(hcounter + 1),
+
+ If(hcounter == 0, hactive.eq(1)),
+ If(hcounter == tp.hres, hactive.eq(0)),
+ If(hcounter == tp.hsync_start, self.phy.payload.hsync.eq(1)),
+ If(hcounter == tp.hsync_end, self.phy.payload.hsync.eq(0)),
+ If(hcounter == tp.hscan,
+ hcounter.eq(0),
+ If(vcounter == tp.vscan,
+ vcounter.eq(0),
+ self.timing.ack.eq(1)
+ ).Else(
+ vcounter.eq(vcounter + 1)
+ )
+ ),
+
+ If(vcounter == 0, vactive.eq(1)),
+ If(vcounter == tp.vres, vactive.eq(0)),
+ If(vcounter == tp.vsync_start, self.phy.payload.vsync.eq(1)),
+ If(vcounter == tp.vsync_end, self.phy.payload.vsync.eq(0))
+ )
+ ]
--- /dev/null
+from migen.fhdl.std import *
+from migen.genlib.fifo import AsyncFIFO
+from migen.genlib.cdc import MultiReg
+from migen.bank.description import *
+from migen.flow.actor import *
+
+from misoclib.framebuffer.format import bpc_phy, phy_layout
+from misoclib.framebuffer import dvi
+
+class _FIFO(Module):
+ def __init__(self):
+ self.phy = Sink(phy_layout)
+ self.busy = Signal()
+
+ self.pix_hsync = Signal()
+ self.pix_vsync = Signal()
+ self.pix_de = Signal()
+ self.pix_r = Signal(bpc_phy)
+ self.pix_g = Signal(bpc_phy)
+ self.pix_b = Signal(bpc_phy)
+
+ ###
+
+ fifo = RenameClockDomains(AsyncFIFO(phy_layout, 512),
+ {"write": "sys", "read": "pix"})
+ self.submodules += fifo
+ self.comb += [
+ self.phy.ack.eq(fifo.writable),
+ fifo.we.eq(self.phy.stb),
+ fifo.din.eq(self.phy.payload),
+ self.busy.eq(0)
+ ]
+
+ pix_parity = Signal()
+ self.sync.pix += [
+ pix_parity.eq(~pix_parity),
+ self.pix_hsync.eq(fifo.dout.hsync),
+ self.pix_vsync.eq(fifo.dout.vsync),
+ self.pix_de.eq(fifo.dout.de),
+ If(pix_parity,
+ self.pix_r.eq(fifo.dout.p1.r),
+ self.pix_g.eq(fifo.dout.p1.g),
+ self.pix_b.eq(fifo.dout.p1.b)
+ ).Else(
+ self.pix_r.eq(fifo.dout.p0.r),
+ self.pix_g.eq(fifo.dout.p0.g),
+ self.pix_b.eq(fifo.dout.p0.b)
+ )
+ ]
+ self.comb += fifo.re.eq(pix_parity)
+
+# This assumes a 50MHz base clock
+class _Clocking(Module, AutoCSR):
+ def __init__(self, pads_vga, pads_dvi):
+ self._r_cmd_data = CSRStorage(10)
+ self._r_send_cmd_data = CSR()
+ self._r_send_go = CSR()
+ self._r_status = CSRStatus(4)
+
+ self.clock_domains.cd_pix = ClockDomain(reset_less=True)
+ if pads_dvi is not None:
+ self.clock_domains.cd_pix2x = ClockDomain(reset_less=True)
+ self.clock_domains.cd_pix10x = ClockDomain(reset_less=True)
+ self.serdesstrobe = Signal()
+
+ ###
+
+ # Generate 1x pixel clock
+ clk_pix_unbuffered = Signal()
+ pix_progdata = Signal()
+ pix_progen = Signal()
+ pix_progdone = Signal()
+ pix_locked = Signal()
+ self.specials += Instance("DCM_CLKGEN",
+ p_CLKFXDV_DIVIDE=2, p_CLKFX_DIVIDE=4, p_CLKFX_MD_MAX=1.0, p_CLKFX_MULTIPLY=2,
+ p_CLKIN_PERIOD=20.0, p_SPREAD_SPECTRUM="NONE", p_STARTUP_WAIT="FALSE",
+
+ i_CLKIN=ClockSignal("base50"), o_CLKFX=clk_pix_unbuffered,
+ i_PROGCLK=ClockSignal(), i_PROGDATA=pix_progdata, i_PROGEN=pix_progen,
+ o_PROGDONE=pix_progdone, o_LOCKED=pix_locked,
+ i_FREEZEDCM=0, i_RST=ResetSignal())
+
+ remaining_bits = Signal(max=11)
+ transmitting = Signal()
+ self.comb += transmitting.eq(remaining_bits != 0)
+ sr = Signal(10)
+ self.sync += [
+ If(self._r_send_cmd_data.re,
+ remaining_bits.eq(10),
+ sr.eq(self._r_cmd_data.storage)
+ ).Elif(transmitting,
+ remaining_bits.eq(remaining_bits - 1),
+ sr.eq(sr[1:])
+ )
+ ]
+ self.comb += [
+ pix_progdata.eq(transmitting & sr[0]),
+ pix_progen.eq(transmitting | self._r_send_go.re)
+ ]
+
+ # enforce gap between commands
+ busy_counter = Signal(max=14)
+ busy = Signal()
+ self.comb += busy.eq(busy_counter != 0)
+ self.sync += If(self._r_send_cmd_data.re,
+ busy_counter.eq(13)
+ ).Elif(busy,
+ busy_counter.eq(busy_counter - 1)
+ )
+
+ mult_locked = Signal()
+ self.comb += self._r_status.status.eq(Cat(busy, pix_progdone, pix_locked, mult_locked))
+
+ # Clock multiplication and buffering
+ if pads_dvi is None:
+ # Just buffer 1x pixel clock
+ self.specials += Instance("BUFG", i_I=clk_pix_unbuffered, o_O=self.cd_pix.clk)
+ self.comb += mult_locked.eq(pix_locked)
+ else:
+ # Route unbuffered 1x pixel clock to PLL
+ # Generate 1x, 2x and 10x IO pixel clocks
+ clkfbout = Signal()
+ pll_locked = Signal()
+ pll_clk0 = Signal()
+ pll_clk1 = Signal()
+ pll_clk2 = Signal()
+ locked_async = Signal()
+ self.specials += [
+ Instance("PLL_BASE",
+ p_CLKIN_PERIOD=26.7,
+ p_CLKFBOUT_MULT=20,
+ p_CLKOUT0_DIVIDE=2, # pix10x
+ p_CLKOUT1_DIVIDE=10, # pix2x
+ p_CLKOUT2_DIVIDE=20, # pix
+ p_COMPENSATION="INTERNAL",
+
+ i_CLKIN=clk_pix_unbuffered,
+ o_CLKOUT0=pll_clk0, o_CLKOUT1=pll_clk1, o_CLKOUT2=pll_clk2,
+ o_CLKFBOUT=clkfbout, i_CLKFBIN=clkfbout,
+ o_LOCKED=pll_locked, i_RST=~pix_locked),
+ Instance("BUFPLL", p_DIVIDE=5,
+ i_PLLIN=pll_clk0, i_GCLK=ClockSignal("pix2x"), i_LOCKED=pll_locked,
+ o_IOCLK=self.cd_pix10x.clk, o_LOCK=locked_async, o_SERDESSTROBE=self.serdesstrobe),
+ Instance("BUFG", i_I=pll_clk1, o_O=self.cd_pix2x.clk),
+ Instance("BUFG", name="dviout_pix_bufg", i_I=pll_clk2, o_O=self.cd_pix.clk),
+ MultiReg(locked_async, mult_locked, "sys")
+ ]
+
+ # Drive VGA/DVI clock pads
+ if pads_vga is not None:
+ self.specials += Instance("ODDR2",
+ p_DDR_ALIGNMENT="NONE", p_INIT=0, p_SRTYPE="SYNC",
+ o_Q=pads_vga.clk,
+ i_C0=ClockSignal("pix"),
+ i_C1=~ClockSignal("pix"),
+ i_CE=1, i_D0=1, i_D1=0,
+ i_R=0, i_S=0)
+ if pads_dvi is not None:
+ dvi_clk_se = Signal()
+ self.specials += Instance("ODDR2",
+ p_DDR_ALIGNMENT="NONE", p_INIT=0, p_SRTYPE="SYNC",
+ o_Q=dvi_clk_se,
+ i_C0=ClockSignal("pix"),
+ i_C1=~ClockSignal("pix"),
+ i_CE=1, i_D0=1, i_D1=0,
+ i_R=0, i_S=0)
+ self.specials += Instance("OBUFDS", i_I=dvi_clk_se,
+ o_O=pads_dvi.clk_p, o_OB=pads_dvi.clk_n)
+
+class Driver(Module, AutoCSR):
+ def __init__(self, pads_vga, pads_dvi):
+ fifo = _FIFO()
+ self.submodules += fifo
+ self.phy = fifo.phy
+ self.busy = fifo.busy
+
+ self.submodules.clocking = _Clocking(pads_vga, pads_dvi)
+
+ if pads_vga is not None:
+ self.comb += [
+ pads_vga.hsync_n.eq(~fifo.pix_hsync),
+ pads_vga.vsync_n.eq(~fifo.pix_vsync),
+ pads_vga.r.eq(fifo.pix_r),
+ pads_vga.g.eq(fifo.pix_g),
+ pads_vga.b.eq(fifo.pix_b),
+ pads_vga.psave_n.eq(1)
+ ]
+ if pads_dvi is not None:
+ self.submodules.dvi_phy = dvi.PHY(self.clocking.serdesstrobe, pads_dvi)
+ self.comb += [
+ self.dvi_phy.hsync.eq(fifo.pix_hsync),
+ self.dvi_phy.vsync.eq(fifo.pix_vsync),
+ self.dvi_phy.de.eq(fifo.pix_de),
+ self.dvi_phy.r.eq(fifo.pix_r),
+ self.dvi_phy.g.eq(fifo.pix_g),
+ self.dvi_phy.b.eq(fifo.pix_b)
+ ]
--- /dev/null
+from migen.fhdl.std import *
+from migen.genlib.cdc import MultiReg
+from migen.bank.description import *
+
+class GPIOIn(Module, AutoCSR):
+ def __init__(self, signal):
+ self._r_in = CSRStatus(flen(signal))
+ self.specials += MultiReg(signal, self._r_in.status)
+
+class GPIOOut(Module, AutoCSR):
+ def __init__(self, signal):
+ self._r_out = CSRStorage(flen(signal))
+ self.comb += signal.eq(self._r_out.storage)
+
+class Blinker(Module):
+ def __init__(self, signal, divbits=26):
+ counter = Signal(divbits)
+ self.comb += signal.eq(counter[divbits-1])
+ self.sync += counter.eq(counter + 1)
--- /dev/null
+import re
+
+from migen.fhdl.std import *
+from migen.bank.description import *
+
+def encode_version(version):
+ match = re.match("(\d+)\.(\d+)(\.(\d+))?(rc(\d+))?", version, re.IGNORECASE)
+ r = (int(match.group(1)) << 12) | (int(match.group(2)) << 8)
+ subminor = match.group(4)
+ rc = match.group(6)
+ if subminor:
+ r |= int(subminor) << 4
+ if rc:
+ r |= int(rc)
+ return r
+
+class Identifier(Module, AutoCSR):
+ def __init__(self, sysid, version, frequency):
+ self._r_sysid = CSRStatus(16)
+ self._r_version = CSRStatus(16)
+ self._r_frequency = CSRStatus(32)
+
+ ###
+
+ self.comb += [
+ self._r_sysid.status.eq(sysid),
+ self._r_version.status.eq(encode_version(version)),
+ self._r_frequency.status.eq(frequency)
+ ]
--- /dev/null
+from collections import namedtuple
+
+from migen.fhdl.std import *
+from migen.bus import dfi, lasmibus
+
+from misoclib.lasmicon.refresher import *
+from misoclib.lasmicon.bankmachine import *
+from misoclib.lasmicon.multiplexer import *
+
+PhySettings = namedtuple("PhySettings", "memtype dfi_d nphases rdphase wrphase rdcmdphase wrcmdphase cl read_latency write_latency")
+
+class GeomSettings(namedtuple("_GeomSettings", "bank_a row_a col_a")):
+ def __init__(self, *args, **kwargs):
+ self.mux_a = max(self.row_a, self.col_a)
+
+TimingSettings = namedtuple("TimingSettings", "tRP tRCD tWR tWTR tREFI tRFC" \
+ " req_queue_size read_time write_time")
+
+class LASMIcon(Module):
+ def __init__(self, phy_settings, geom_settings, timing_settings):
+ if phy_settings.memtype in ["SDR"]:
+ burst_length = phy_settings.nphases*1 # command multiplication*SDR
+ elif phy_settings.memtype in ["DDR", "LPDDR", "DDR2", "DDR3"]:
+ burst_length = phy_settings.nphases*2 # command multiplication*DDR
+ address_align = log2_int(burst_length)
+
+ self.dfi = dfi.Interface(geom_settings.mux_a,
+ geom_settings.bank_a,
+ phy_settings.dfi_d,
+ phy_settings.nphases)
+ self.lasmic = lasmibus.Interface(
+ aw=geom_settings.row_a + geom_settings.col_a - address_align,
+ dw=phy_settings.dfi_d*phy_settings.nphases,
+ nbanks=2**geom_settings.bank_a,
+ req_queue_size=timing_settings.req_queue_size,
+ read_latency=phy_settings.read_latency+1,
+ write_latency=phy_settings.write_latency+1)
+ self.nrowbits = geom_settings.col_a - address_align
+
+ ###
+
+ self.submodules.refresher = Refresher(geom_settings.mux_a, geom_settings.bank_a,
+ timing_settings.tRP, timing_settings.tREFI, timing_settings.tRFC)
+ self.submodules.bank_machines = [BankMachine(geom_settings, timing_settings, address_align, i,
+ getattr(self.lasmic, "bank"+str(i)))
+ for i in range(2**geom_settings.bank_a)]
+ self.submodules.multiplexer = Multiplexer(phy_settings, geom_settings, timing_settings,
+ self.bank_machines, self.refresher,
+ self.dfi, self.lasmic)
+
+ def get_csrs(self):
+ return self.multiplexer.get_csrs()
--- /dev/null
+from migen.fhdl.std import *
+from migen.genlib.roundrobin import *
+from migen.genlib.fsm import FSM, NextState
+from migen.genlib.misc import optree
+from migen.genlib.fifo import SyncFIFO
+
+from misoclib.lasmicon.multiplexer import *
+
+class _AddressSlicer:
+ def __init__(self, col_a, address_align):
+ self.col_a = col_a
+ self.address_align = address_align
+
+ def row(self, address):
+ split = self.col_a - self.address_align
+ if isinstance(address, int):
+ return address >> split
+ else:
+ return address[split:]
+
+ def col(self, address):
+ split = self.col_a - self.address_align
+ if isinstance(address, int):
+ return (address & (2**split - 1)) << self.address_align
+ else:
+ return Cat(Replicate(0, self.address_align), address[:split])
+
+class BankMachine(Module):
+ def __init__(self, geom_settings, timing_settings, address_align, bankn, req):
+ self.refresh_req = Signal()
+ self.refresh_gnt = Signal()
+ self.cmd = CommandRequestRW(geom_settings.mux_a, geom_settings.bank_a)
+
+ ###
+
+ # Request FIFO
+ self.submodules.req_fifo = SyncFIFO([("we", 1), ("adr", flen(req.adr))], timing_settings.req_queue_size)
+ self.comb += [
+ self.req_fifo.din.we.eq(req.we),
+ self.req_fifo.din.adr.eq(req.adr),
+ self.req_fifo.we.eq(req.stb),
+ req.req_ack.eq(self.req_fifo.writable),
+
+ self.req_fifo.re.eq(req.dat_ack),
+ req.lock.eq(self.req_fifo.readable)
+ ]
+ reqf = self.req_fifo.dout
+
+ slicer = _AddressSlicer(geom_settings.col_a, address_align)
+
+ # Row tracking
+ has_openrow = Signal()
+ openrow = Signal(geom_settings.row_a)
+ hit = Signal()
+ self.comb += hit.eq(openrow == slicer.row(reqf.adr))
+ track_open = Signal()
+ track_close = Signal()
+ self.sync += [
+ If(track_open,
+ has_openrow.eq(1),
+ openrow.eq(slicer.row(reqf.adr))
+ ),
+ If(track_close,
+ has_openrow.eq(0)
+ )
+ ]
+
+ # Address generation
+ s_row_adr = Signal()
+ self.comb += [
+ self.cmd.ba.eq(bankn),
+ If(s_row_adr,
+ self.cmd.a.eq(slicer.row(reqf.adr))
+ ).Else(
+ self.cmd.a.eq(slicer.col(reqf.adr))
+ )
+ ]
+
+ # Respect write-to-precharge specification
+ precharge_ok = Signal()
+ t_unsafe_precharge = 2 + timing_settings.tWR - 1
+ unsafe_precharge_count = Signal(max=t_unsafe_precharge+1)
+ self.comb += precharge_ok.eq(unsafe_precharge_count == 0)
+ self.sync += [
+ If(self.cmd.stb & self.cmd.ack & self.cmd.is_write,
+ unsafe_precharge_count.eq(t_unsafe_precharge)
+ ).Elif(~precharge_ok,
+ unsafe_precharge_count.eq(unsafe_precharge_count-1)
+ )
+ ]
+
+ # Control and command generation FSM
+ fsm = FSM()
+ self.submodules += fsm
+ fsm.act("REGULAR",
+ If(self.refresh_req,
+ NextState("REFRESH")
+ ).Elif(self.req_fifo.readable,
+ If(has_openrow,
+ If(hit,
+ # NB: write-to-read specification is enforced by multiplexer
+ self.cmd.stb.eq(1),
+ req.dat_ack.eq(self.cmd.ack),
+ self.cmd.is_read.eq(~reqf.we),
+ self.cmd.is_write.eq(reqf.we),
+ self.cmd.cas_n.eq(0),
+ self.cmd.we_n.eq(~reqf.we)
+ ).Else(
+ NextState("PRECHARGE")
+ )
+ ).Else(
+ NextState("ACTIVATE")
+ )
+ )
+ )
+ fsm.act("PRECHARGE",
+ # Notes:
+ # 1. we are presenting the column address, A10 is always low
+ # 2. since we always go to the ACTIVATE state, we do not need
+ # to assert track_close.
+ If(precharge_ok,
+ self.cmd.stb.eq(1),
+ If(self.cmd.ack, NextState("TRP")),
+ self.cmd.ras_n.eq(0),
+ self.cmd.we_n.eq(0),
+ self.cmd.is_cmd.eq(1)
+ )
+ )
+ fsm.act("ACTIVATE",
+ s_row_adr.eq(1),
+ track_open.eq(1),
+ self.cmd.stb.eq(1),
+ self.cmd.is_cmd.eq(1),
+ If(self.cmd.ack, NextState("TRCD")),
+ self.cmd.ras_n.eq(0)
+ )
+ fsm.act("REFRESH",
+ self.refresh_gnt.eq(precharge_ok),
+ track_close.eq(1),
+ self.cmd.is_cmd.eq(1),
+ If(~self.refresh_req, NextState("REGULAR"))
+ )
+ fsm.delayed_enter("TRP", "ACTIVATE", timing_settings.tRP-1)
+ fsm.delayed_enter("TRCD", "REGULAR", timing_settings.tRCD-1)
--- /dev/null
+from migen.fhdl.std import *
+from migen.genlib.roundrobin import *
+from migen.genlib.misc import optree
+from migen.genlib.fsm import FSM, NextState
+from migen.bank.description import AutoCSR
+
+from misoclib.lasmicon.perf import Bandwidth
+
+class CommandRequest:
+ def __init__(self, a, ba):
+ self.a = Signal(a)
+ self.ba = Signal(ba)
+ self.cas_n = Signal(reset=1)
+ self.ras_n = Signal(reset=1)
+ self.we_n = Signal(reset=1)
+
+class CommandRequestRW(CommandRequest):
+ def __init__(self, a, ba):
+ CommandRequest.__init__(self, a, ba)
+ self.stb = Signal()
+ self.ack = Signal()
+ self.is_cmd = Signal()
+ self.is_read = Signal()
+ self.is_write = Signal()
+
+class _CommandChooser(Module):
+ def __init__(self, requests):
+ self.want_reads = Signal()
+ self.want_writes = Signal()
+ self.want_cmds = Signal()
+ # NB: cas_n/ras_n/we_n are 1 when stb is inactive
+ self.cmd = CommandRequestRW(flen(requests[0].a), flen(requests[0].ba))
+
+ ###
+
+ rr = RoundRobin(len(requests), SP_CE)
+ self.submodules += rr
+
+ self.comb += [rr.request[i].eq(req.stb & ((req.is_cmd & self.want_cmds) | ((req.is_read == self.want_reads) | (req.is_write == self.want_writes))))
+ for i, req in enumerate(requests)]
+
+ stb = Signal()
+ self.comb += stb.eq(Array(req.stb for req in requests)[rr.grant])
+ for name in ["a", "ba", "is_read", "is_write", "is_cmd"]:
+ choices = Array(getattr(req, name) for req in requests)
+ self.comb += getattr(self.cmd, name).eq(choices[rr.grant])
+ for name in ["cas_n", "ras_n", "we_n"]:
+ # we should only assert those signals when stb is 1
+ choices = Array(getattr(req, name) for req in requests)
+ self.comb += If(self.cmd.stb, getattr(self.cmd, name).eq(choices[rr.grant]))
+ self.comb += self.cmd.stb.eq(stb \
+ & ((self.cmd.is_cmd & self.want_cmds) | ((self.cmd.is_read == self.want_reads) \
+ & (self.cmd.is_write == self.want_writes))))
+
+ self.comb += [If(self.cmd.stb & self.cmd.ack & (rr.grant == i), req.ack.eq(1))
+ for i, req in enumerate(requests)]
+ self.comb += rr.ce.eq(self.cmd.ack)
+
+class _Steerer(Module):
+ def __init__(self, commands, dfi):
+ ncmd = len(commands)
+ nph = len(dfi.phases)
+ self.sel = [Signal(max=ncmd) for i in range(nph)]
+
+ ###
+
+ def stb_and(cmd, attr):
+ if not hasattr(cmd, "stb"):
+ return 0
+ else:
+ return cmd.stb & getattr(cmd, attr)
+ for phase, sel in zip(dfi.phases, self.sel):
+ self.comb += [
+ phase.cke.eq(1),
+ phase.cs_n.eq(0)
+ ]
+ self.sync += [
+ phase.address.eq(Array(cmd.a for cmd in commands)[sel]),
+ phase.bank.eq(Array(cmd.ba for cmd in commands)[sel]),
+ phase.cas_n.eq(Array(cmd.cas_n for cmd in commands)[sel]),
+ phase.ras_n.eq(Array(cmd.ras_n for cmd in commands)[sel]),
+ phase.we_n.eq(Array(cmd.we_n for cmd in commands)[sel]),
+ phase.rddata_en.eq(Array(stb_and(cmd, "is_read") for cmd in commands)[sel]),
+ phase.wrdata_en.eq(Array(stb_and(cmd, "is_write") for cmd in commands)[sel])
+ ]
+
+class Multiplexer(Module, AutoCSR):
+ def __init__(self, phy_settings, geom_settings, timing_settings, bank_machines, refresher, dfi, lasmic):
+ assert(phy_settings.nphases == len(dfi.phases))
+
+ # Command choosing
+ requests = [bm.cmd for bm in bank_machines]
+ choose_cmd = _CommandChooser(requests)
+ choose_req = _CommandChooser(requests)
+ self.comb += [
+ choose_cmd.want_reads.eq(0),
+ choose_cmd.want_writes.eq(0)
+ ]
+ if phy_settings.nphases == 1:
+ self.comb += [
+ choose_cmd.want_cmds.eq(1),
+ choose_req.want_cmds.eq(1)
+ ]
+ self.submodules += choose_cmd, choose_req
+
+ # Command steering
+ nop = CommandRequest(geom_settings.mux_a, geom_settings.bank_a)
+ commands = [nop, choose_cmd.cmd, choose_req.cmd, refresher.cmd] # nop must be 1st
+ (STEER_NOP, STEER_CMD, STEER_REQ, STEER_REFRESH) = range(4)
+ steerer = _Steerer(commands, dfi)
+ self.submodules += steerer
+
+ # Read/write turnaround
+ read_available = Signal()
+ write_available = Signal()
+ self.comb += [
+ read_available.eq(optree("|", [req.stb & req.is_read for req in requests])),
+ write_available.eq(optree("|", [req.stb & req.is_write for req in requests]))
+ ]
+
+ def anti_starvation(timeout):
+ en = Signal()
+ max_time = Signal()
+ if timeout:
+ t = timeout - 1
+ time = Signal(max=t+1)
+ self.comb += max_time.eq(time == 0)
+ self.sync += If(~en,
+ time.eq(t)
+ ).Elif(~max_time,
+ time.eq(time - 1)
+ )
+ else:
+ self.comb += max_time.eq(0)
+ return en, max_time
+ read_time_en, max_read_time = anti_starvation(timing_settings.read_time)
+ write_time_en, max_write_time = anti_starvation(timing_settings.write_time)
+
+ # Refresh
+ self.comb += [bm.refresh_req.eq(refresher.req) for bm in bank_machines]
+ go_to_refresh = Signal()
+ self.comb += go_to_refresh.eq(optree("&", [bm.refresh_gnt for bm in bank_machines]))
+
+ # Datapath
+ all_rddata = [p.rddata for p in dfi.phases]
+ all_wrdata = [p.wrdata for p in dfi.phases]
+ all_wrdata_mask = [p.wrdata_mask for p in dfi.phases]
+ self.comb += [
+ lasmic.dat_r.eq(Cat(*all_rddata)),
+ Cat(*all_wrdata).eq(lasmic.dat_w),
+ Cat(*all_wrdata_mask).eq(~lasmic.dat_we)
+ ]
+
+ # Control FSM
+ fsm = FSM()
+ self.submodules += fsm
+
+ def steerer_sel(steerer, phy_settings, r_w_n):
+ r = []
+ for i in range(phy_settings.nphases):
+ s = steerer.sel[i].eq(STEER_NOP)
+ if r_w_n == "read":
+ if i == phy_settings.rdphase:
+ s = steerer.sel[i].eq(STEER_REQ)
+ elif i == phy_settings.rdcmdphase:
+ s = steerer.sel[i].eq(STEER_CMD)
+ elif r_w_n == "write":
+ if i == phy_settings.wrphase:
+ s = steerer.sel[i].eq(STEER_REQ)
+ elif i == phy_settings.wrcmdphase:
+ s = steerer.sel[i].eq(STEER_CMD)
+ else:
+ raise ValueError
+ r.append(s)
+ return r
+
+ fsm.act("READ",
+ read_time_en.eq(1),
+ choose_req.want_reads.eq(1),
+ choose_cmd.cmd.ack.eq(1),
+ choose_req.cmd.ack.eq(1),
+ steerer_sel(steerer, phy_settings, "read"),
+ If(write_available,
+ # TODO: switch only after several cycles of ~read_available?
+ If(~read_available | max_read_time, NextState("RTW"))
+ ),
+ If(go_to_refresh, NextState("REFRESH"))
+ )
+ fsm.act("WRITE",
+ write_time_en.eq(1),
+ choose_req.want_writes.eq(1),
+ choose_cmd.cmd.ack.eq(1),
+ choose_req.cmd.ack.eq(1),
+ steerer_sel(steerer, phy_settings, "write"),
+ If(read_available,
+ If(~write_available | max_write_time, NextState("WTR"))
+ ),
+ If(go_to_refresh, NextState("REFRESH"))
+ )
+ fsm.act("REFRESH",
+ steerer.sel[0].eq(STEER_REFRESH),
+ If(~refresher.req, NextState("READ"))
+ )
+ fsm.delayed_enter("RTW", "WRITE", phy_settings.read_latency-1) # FIXME: reduce this, actual limit is around (cl+1)/nphases
+ fsm.delayed_enter("WTR", "READ", timing_settings.tWTR-1)
+ # FIXME: workaround for zero-delay loop simulation problem with Icarus Verilog
+ fsm.finalize()
+ self.comb += refresher.ack.eq(fsm.state == fsm.encoding["REFRESH"])
+
+ self.submodules.bandwidth = Bandwidth(choose_req.cmd)
--- /dev/null
+from migen.fhdl.std import *
+from migen.bank.description import *
+
+class Bandwidth(Module, AutoCSR):
+ def __init__(self, cmd, period_bits=24):
+ self._r_update = CSR()
+ self._r_nreads = CSRStatus(period_bits)
+ self._r_nwrites = CSRStatus(period_bits)
+
+ ###
+
+ cmd_stb = Signal()
+ cmd_ack = Signal()
+ cmd_is_read = Signal()
+ cmd_is_write = Signal()
+ self.sync += [
+ cmd_stb.eq(cmd.stb),
+ cmd_ack.eq(cmd.ack),
+ cmd_is_read.eq(cmd.is_read),
+ cmd_is_write.eq(cmd.is_write)
+ ]
+
+ counter = Signal(period_bits)
+ period = Signal()
+ nreads = Signal(period_bits)
+ nwrites = Signal(period_bits)
+ nreads_r = Signal(period_bits)
+ nwrites_r = Signal(period_bits)
+ self.sync += [
+ Cat(counter, period).eq(counter + 1),
+ If(period,
+ nreads_r.eq(nreads),
+ nwrites_r.eq(nwrites),
+ nreads.eq(0),
+ nwrites.eq(0)
+ ).Elif(cmd_stb & cmd_ack,
+ If(cmd_is_read, nreads.eq(nreads + 1)),
+ If(cmd_is_write, nwrites.eq(nwrites + 1)),
+ ),
+ If(self._r_update.re,
+ self._r_nreads.status.eq(nreads_r),
+ self._r_nwrites.status.eq(nwrites_r)
+ )
+ ]
--- /dev/null
+from migen.fhdl.std import *
+from migen.genlib.misc import timeline
+from migen.genlib.fsm import FSM
+
+from misoclib.lasmicon.multiplexer import *
+
+class Refresher(Module):
+ def __init__(self, a, ba, tRP, tREFI, tRFC):
+ self.req = Signal()
+ self.ack = Signal() # 1st command 1 cycle after assertion of ack
+ self.cmd = CommandRequest(a, ba)
+
+ ###
+
+ # Refresh sequence generator:
+ # PRECHARGE ALL --(tRP)--> AUTO REFRESH --(tRFC)--> done
+ seq_start = Signal()
+ seq_done = Signal()
+ self.sync += [
+ self.cmd.a.eq(2**10),
+ self.cmd.ba.eq(0),
+ self.cmd.cas_n.eq(1),
+ self.cmd.ras_n.eq(1),
+ self.cmd.we_n.eq(1),
+ seq_done.eq(0)
+ ]
+ self.sync += timeline(seq_start, [
+ (1, [
+ self.cmd.ras_n.eq(0),
+ self.cmd.we_n.eq(0)
+ ]),
+ (1+tRP, [
+ self.cmd.cas_n.eq(0),
+ self.cmd.ras_n.eq(0)
+ ]),
+ (1+tRP+tRFC, [
+ seq_done.eq(1)
+ ])
+ ])
+
+ # Periodic refresh counter
+ counter = Signal(max=tREFI)
+ start = Signal()
+ self.sync += [
+ start.eq(0),
+ If(counter == 0,
+ start.eq(1),
+ counter.eq(tREFI - 1)
+ ).Else(
+ counter.eq(counter - 1)
+ )
+ ]
+
+ # Control FSM
+ fsm = FSM()
+ self.submodules += fsm
+ fsm.act("IDLE", If(start, NextState("WAIT_GRANT")))
+ fsm.act("WAIT_GRANT",
+ self.req.eq(1),
+ If(self.ack,
+ seq_start.eq(1),
+ NextState("WAIT_SEQ")
+ )
+ )
+ fsm.act("WAIT_SEQ",
+ self.req.eq(1),
+ If(seq_done, NextState("IDLE"))
+ )
--- /dev/null
+from migen.fhdl.std import *
+from migen.bus import wishbone
+
+class LM32(Module):
+ def __init__(self):
+ self.ibus = i = wishbone.Interface()
+ self.dbus = d = wishbone.Interface()
+ self.interrupt = Signal(32)
+ self.ext_break = Signal()
+
+ ###
+
+ i_adr_o = Signal(32)
+ d_adr_o = Signal(32)
+ self.specials += Instance("lm32_top",
+ Instance.Input("clk_i", ClockSignal()),
+ Instance.Input("rst_i", ResetSignal()),
+
+ Instance.Input("interrupt", self.interrupt),
+ #Instance.Input("ext_break", self.ext_break),
+
+ Instance.Output("I_ADR_O", i_adr_o),
+ Instance.Output("I_DAT_O", i.dat_w),
+ Instance.Output("I_SEL_O", i.sel),
+ Instance.Output("I_CYC_O", i.cyc),
+ Instance.Output("I_STB_O", i.stb),
+ Instance.Output("I_WE_O", i.we),
+ Instance.Output("I_CTI_O", i.cti),
+ Instance.Output("I_LOCK_O"),
+ Instance.Output("I_BTE_O", i.bte),
+ Instance.Input("I_DAT_I", i.dat_r),
+ Instance.Input("I_ACK_I", i.ack),
+ Instance.Input("I_ERR_I", i.err),
+ Instance.Input("I_RTY_I", 0),
+
+ Instance.Output("D_ADR_O", d_adr_o),
+ Instance.Output("D_DAT_O", d.dat_w),
+ Instance.Output("D_SEL_O", d.sel),
+ Instance.Output("D_CYC_O", d.cyc),
+ Instance.Output("D_STB_O", d.stb),
+ Instance.Output("D_WE_O", d.we),
+ Instance.Output("D_CTI_O", d.cti),
+ Instance.Output("D_LOCK_O"),
+ Instance.Output("D_BTE_O", d.bte),
+ Instance.Input("D_DAT_I", d.dat_r),
+ Instance.Input("D_ACK_I", d.ack),
+ Instance.Input("D_ERR_I", d.err),
+ Instance.Input("D_RTY_I", 0))
+
+ self.comb += [
+ self.ibus.adr.eq(i_adr_o[2:]),
+ self.dbus.adr.eq(d_adr_o[2:])
+ ]
--- /dev/null
+from migen.fhdl.std import *
+from migen.genlib.misc import optree
+from migen.bank.description import *
+from migen.actorlib import dma_lasmi
+from migen.actorlib.spi import *
+
+@DecorateModule(InsertReset)
+@DecorateModule(InsertCE)
+class LFSR(Module):
+ def __init__(self, n_out, n_state=31, taps=[27, 30]):
+ self.o = Signal(n_out)
+
+ ###
+
+ state = Signal(n_state)
+ curval = [state[i] for i in range(n_state)]
+ curval += [0]*(n_out - n_state)
+ for i in range(n_out):
+ nv = ~optree("^", [curval[tap] for tap in taps])
+ curval.insert(0, nv)
+ curval.pop()
+
+ self.sync += [
+ state.eq(Cat(*curval[:n_state])),
+ self.o.eq(Cat(*curval))
+ ]
+
+def _print_lfsr_code():
+ from migen.fhdl import verilog
+ dut = LFSR(3, 4, [3, 2])
+ print(verilog.convert(dut, ios={dut.ce, dut.reset, dut.o}))
+
+class _LFSRTB(Module):
+ def __init__(self, *args, **kwargs):
+ self.submodules.lfsr = LFSR(*args, **kwargs)
+ self.comb += self.lfsr.ce.eq(1)
+
+ def do_simulation(self, s):
+ print("{0:032x}".format(s.rd(self.lfsr.o)))
+
+def _sim_lfsr():
+ from migen.sim.generic import Simulator
+ tb = _LFSRTB(128)
+ sim = Simulator(tb)
+ sim.run(20)
+
+memtest_magic = 0x361f
+
+class MemtestWriter(Module):
+ def __init__(self, lasmim):
+ self._r_magic = CSRStatus(16)
+ self._r_reset = CSR()
+ self._r_shoot = CSR()
+ self.submodules._dma = DMAWriteController(dma_lasmi.Writer(lasmim), MODE_EXTERNAL)
+
+ ###
+
+ self.comb += self._r_magic.status.eq(memtest_magic)
+
+ lfsr = LFSR(lasmim.dw)
+ self.submodules += lfsr
+ self.comb += lfsr.reset.eq(self._r_reset.re)
+
+ en = Signal()
+ en_counter = Signal(lasmim.aw)
+ self.comb += en.eq(en_counter != 0)
+ self.sync += [
+ If(self._r_shoot.re,
+ en_counter.eq(self._dma.length)
+ ).Elif(lfsr.ce,
+ en_counter.eq(en_counter - 1)
+ )
+ ]
+
+ self.comb += [
+ self._dma.trigger.eq(self._r_shoot.re),
+ self._dma.data.stb.eq(en),
+ lfsr.ce.eq(en & self._dma.data.ack),
+ self._dma.data.payload.d.eq(lfsr.o)
+ ]
+
+ def get_csrs(self):
+ return [self._r_magic, self._r_reset, self._r_shoot] + self._dma.get_csrs()
+
+class MemtestReader(Module):
+ def __init__(self, lasmim):
+ self._r_magic = CSRStatus(16)
+ self._r_reset = CSR()
+ self._r_error_count = CSRStatus(lasmim.aw)
+ self.submodules._dma = DMAReadController(dma_lasmi.Reader(lasmim), MODE_SINGLE_SHOT)
+
+ ###
+
+ self.comb += self._r_magic.status.eq(memtest_magic)
+
+ lfsr = LFSR(lasmim.dw)
+ self.submodules += lfsr
+ self.comb += lfsr.reset.eq(self._r_reset.re)
+
+ self.comb += [
+ lfsr.ce.eq(self._dma.data.stb),
+ self._dma.data.ack.eq(1)
+ ]
+ err_cnt = self._r_error_count.status
+ self.sync += [
+ If(self._r_reset.re,
+ err_cnt.eq(0)
+ ).Elif(self._dma.data.stb,
+ If(self._dma.data.payload.d != lfsr.o, err_cnt.eq(err_cnt + 1))
+ )
+ ]
+
+ def get_csrs(self):
+ return [self._r_magic, self._r_reset, self._r_error_count] + self._dma.get_csrs()
+
+if __name__ == "__main__":
+ _print_lfsr_code()
+ _sim_lfsr()
--- /dev/null
+from migen.fhdl.std import *
+from migen.bank.description import *
+from migen.bank.eventmanager import *
+from migen.bus import wishbone
+
+_count_width = 11
+
+class MiniMAC(Module, AutoCSR):
+ def __init__(self, pads):
+ # CPU interface
+ self._phy_reset = CSRStorage(reset=1)
+ self._rx_count_0 = CSRStatus(_count_width)
+ self._rx_count_1 = CSRStatus(_count_width)
+ self._tx_count = CSRStorage(_count_width, write_from_dev=True)
+ self._tx_start = CSR()
+
+ self.submodules.ev = EventManager()
+ self.ev.rx0 = EventSourcePulse()
+ self.ev.rx1 = EventSourcePulse()
+ self.ev.tx = EventSourcePulse()
+ self.ev.finalize()
+
+ self.membus = wishbone.Interface()
+
+ ###
+
+ init = Signal(reset=1)
+ self.sync += init.eq(0)
+ rx_ready_0 = Signal()
+ rx_ready_1 = Signal()
+ rx_pending_0 = self.ev.rx0.pending
+ rx_pending_1 = self.ev.rx1.pending
+ rx_pending_0_r = Signal()
+ rx_pending_1_r = Signal()
+ self.comb += [
+ pads.rst_n.eq(~self._phy_reset.storage),
+
+ rx_ready_0.eq(init | (rx_pending_0_r & ~rx_pending_0)),
+ rx_ready_1.eq(init | (rx_pending_1_r & ~rx_pending_1)),
+
+ self._tx_count.dat_w.eq(0),
+ self._tx_count.we.eq(self.ev.tx.trigger)
+ ]
+ self.sync += [
+ rx_pending_0_r.eq(rx_pending_0),
+ rx_pending_1_r.eq(rx_pending_1)
+ ]
+ self.specials += Instance("minimac3",
+ Instance.Input("sys_clk", ClockSignal()),
+ Instance.Input("sys_rst", ResetSignal()),
+
+ Instance.Output("rx_done_0", self.ev.rx0.trigger),
+ Instance.Output("rx_count_0", self._rx_count_0.status),
+ Instance.Output("rx_done_1", self.ev.rx1.trigger),
+ Instance.Output("rx_count_1", self._rx_count_1.status),
+ Instance.Input("rx_ready_0", rx_ready_0),
+ Instance.Input("rx_ready_1", rx_ready_1),
+
+ Instance.Input("tx_start", self._tx_start.re),
+ Instance.Input("tx_count", self._tx_count.storage),
+ Instance.Output("tx_done", self.ev.tx.trigger),
+
+ Instance.Input("wb_adr_i", self.membus.adr),
+ Instance.Input("wb_dat_i", self.membus.dat_w),
+ Instance.Input("wb_sel_i", self.membus.sel),
+ Instance.Input("wb_stb_i", self.membus.stb),
+ Instance.Input("wb_cyc_i", self.membus.cyc),
+ Instance.Input("wb_we_i", self.membus.we),
+ Instance.Output("wb_dat_o", self.membus.dat_r),
+ Instance.Output("wb_ack_o", self.membus.ack),
+
+ Instance.Input("phy_tx_clk", ClockSignal("eth_tx")),
+ Instance.Output("phy_tx_data", pads.tx_data),
+ Instance.Output("phy_tx_en", pads.tx_en),
+ Instance.Output("phy_tx_er", pads.tx_er),
+ Instance.Input("phy_rx_clk", ClockSignal("eth_rx")),
+ Instance.Input("phy_rx_data", pads.rx_data),
+ Instance.Input("phy_dv", pads.dv),
+ Instance.Input("phy_rx_er", pads.rx_er),
+ Instance.Input("phy_col", pads.col),
+ Instance.Input("phy_crs", pads.crs))
--- /dev/null
+from fractions import Fraction
+
+from migen.fhdl.std import *
+
+class MXCRG(Module):
+ def __init__(self, pads, outfreq1x):
+ self.clock_domains.cd_sys = ClockDomain()
+ self.clock_domains.cd_sdram_half = ClockDomain()
+ self.clock_domains.cd_sdram_full_wr = ClockDomain()
+ self.clock_domains.cd_sdram_full_rd = ClockDomain()
+ self.clock_domains.cd_eth_rx = ClockDomain()
+ self.clock_domains.cd_eth_tx = ClockDomain()
+ self.clock_domains.cd_base50 = ClockDomain(reset_less=True)
+
+ self.clk4x_wr_strb = Signal()
+ self.clk4x_rd_strb = Signal()
+
+ ###
+
+ infreq = 50*1000000
+ ratio = Fraction(outfreq1x)/Fraction(infreq)
+ in_period = float(Fraction(1000000000)/Fraction(infreq))
+
+ self.specials += Instance("mxcrg",
+ Instance.Parameter("in_period", in_period),
+ Instance.Parameter("f_mult", ratio.numerator),
+ Instance.Parameter("f_div", ratio.denominator),
+ Instance.Input("clk50_pad", pads.clk50),
+ Instance.Input("trigger_reset", pads.trigger_reset),
+
+ Instance.Input("eth_rx_clk_pad", pads.eth_rx_clk),
+ Instance.Input("eth_tx_clk_pad", pads.eth_tx_clk),
+
+ Instance.Output("sys_clk", self.cd_sys.clk),
+ Instance.Output("sys_rst", self.cd_sys.rst),
+ Instance.Output("clk2x_270", self.cd_sdram_half.clk),
+ Instance.Output("clk4x_wr", self.cd_sdram_full_wr.clk),
+ Instance.Output("clk4x_rd", self.cd_sdram_full_rd.clk),
+ Instance.Output("eth_rx_clk", self.cd_eth_rx.clk),
+ Instance.Output("eth_tx_clk", self.cd_eth_tx.clk),
+ Instance.Output("base50_clk", self.cd_base50.clk),
+
+ Instance.Output("clk4x_wr_strb", self.clk4x_wr_strb),
+ Instance.Output("clk4x_rd_strb", self.clk4x_rd_strb),
+ Instance.Output("norflash_rst_n", pads.norflash_rst_n),
+ Instance.Output("ddr_clk_pad_p", pads.ddr_clk_p),
+ Instance.Output("ddr_clk_pad_n", pads.ddr_clk_n),
+ Instance.Output("eth_phy_clk_pad", pads.eth_phy_clk))
--- /dev/null
+from migen.fhdl.std import *
+from migen.bus import wishbone
+from migen.genlib.misc import timeline
+
+class NorFlash(Module):
+ def __init__(self, pads, rd_timing):
+ self.bus = wishbone.Interface()
+
+ ###
+
+ adr_width = flen(pads.adr) + 1
+ self.comb += [pads.oe_n.eq(0), pads.we_n.eq(1),
+ pads.ce_n.eq(0)]
+ self.sync += timeline(self.bus.cyc & self.bus.stb, [
+ (0, [pads.adr.eq(Cat(0, self.bus.adr[:adr_width-2]))]),
+ (rd_timing, [
+ self.bus.dat_r[16:].eq(pads.d),
+ pads.adr.eq(Cat(1, self.bus.adr[:adr_width-2]))]),
+ (2*rd_timing, [
+ self.bus.dat_r[:16].eq(pads.d),
+ self.bus.ack.eq(1)]),
+ (2*rd_timing + 1, [
+ self.bus.ack.eq(0)])
+ ])
--- /dev/null
+# 1:2 frequency-ratio DDR / LPDDR / DDR2 PHY for
+# Spartan-6
+#
+# Assert dfi_wrdata_en and present the data
+# on dfi_wrdata_mask/dfi_wrdata in the same
+# cycle as the write command.
+#
+# Assert dfi_rddata_en in the same cycle as the read
+# command. The data will come back on dfi_rddata
+# 5 cycles later, along with the assertion
+# of dfi_rddata_valid.
+#
+# This PHY only supports CAS Latency 3.
+# Read commands must be sent on phase 0.
+# Write commands must be sent on phase 1.
+#
+
+# Todo:
+# - use CSR for bitslip?
+# - add configurable CAS Latency
+# - automatically determines wrphase / rdphase / latencies
+
+from migen.fhdl.std import *
+from migen.bus.dfi import *
+from migen.genlib.record import *
+
+from misoclib import lasmicon
+
+class S6DDRPHY(Module):
+ def __init__(self, pads, memtype, nphases, cl, rd_bitslip, wr_bitslip, dqs_ddr_alignment):
+ if memtype not in ["DDR", "LPDDR", "DDR2"]:
+ raise NotImplementedError("S6DDRPHY only supports DDR, LPDDR and DDR2")
+ if cl != 3:
+ raise NotImplementedError("S6DDRPHY only supports CAS LATENCY 3")
+ a = flen(pads.a)
+ ba = flen(pads.ba)
+ d = flen(pads.dq)
+
+ self.phy_settings = lasmicon.PhySettings(
+ memtype=memtype,
+ dfi_d=2*d,
+ nphases=nphases,
+ rdphase=0,
+ wrphase=1,
+ rdcmdphase=1,
+ wrcmdphase=0,
+ cl=cl,
+ read_latency=5,
+ write_latency=0
+ )
+
+ self.dfi = Interface(a, ba, nphases*d, nphases)
+ self.clk4x_wr_strb = Signal()
+ self.clk4x_rd_strb = Signal()
+
+ ###
+
+ # sys_clk : system clk, used for dfi interface
+ # sdram_half_clk : half rate sdram clk
+ # sdram_full_wr_clk : full rate sdram write clk
+ # sdram_full_rd_clk : full rate sdram write clk
+ sd_sys = getattr(self.sync, "sys")
+ sd_sdram_half = getattr(self.sync, "sdram_half")
+
+ sys_clk = ClockSignal("sys")
+ sdram_half_clk = ClockSignal("sdram_half")
+ sdram_full_wr_clk = ClockSignal("sdram_full_wr")
+ sdram_full_rd_clk = ClockSignal("sdram_full_rd")
+
+ #
+ # Command/address
+ #
+
+ # select active phase
+ # sys_clk ----____----____
+ # phase_sel(nphases=1) 0 0
+ # phase_sel(nphases=2) 0 1 0 1
+ # phase_sel(nphases=4) 0 1 2 3 0 1 2 3
+ phase_sel = Signal(log2_int(nphases))
+ sys_clk_d = Signal()
+
+ sd_sdram_half += [
+ If(sys_clk & ~sys_clk_d, phase_sel.eq(0)
+ ).Else(phase_sel.eq(phase_sel+1)),
+ sys_clk_d.eq(sys_clk)
+ ]
+
+ # register dfi cmds on half_rate clk
+ r_dfi = Array(Record(phase_cmd_description(a, ba)) for i in range(nphases))
+ for n, phase in enumerate(self.dfi.phases):
+ sd_sdram_half +=[
+ r_dfi[n].address.eq(phase.address),
+ r_dfi[n].bank.eq(phase.bank),
+ r_dfi[n].cs_n.eq(phase.cs_n),
+ r_dfi[n].cke.eq(phase.cke),
+ r_dfi[n].cas_n.eq(phase.cas_n),
+ r_dfi[n].ras_n.eq(phase.ras_n),
+ r_dfi[n].we_n.eq(phase.we_n)
+ ]
+
+ # output cmds
+ sd_sdram_half += [
+ pads.a.eq(r_dfi[phase_sel].address),
+ pads.ba.eq(r_dfi[phase_sel].bank),
+ pads.cke.eq(r_dfi[phase_sel].cke),
+ pads.ras_n.eq(r_dfi[phase_sel].ras_n),
+ pads.cas_n.eq(r_dfi[phase_sel].cas_n),
+ pads.we_n.eq(r_dfi[phase_sel].we_n)
+ ]
+ if hasattr(pads, "cs_n"):
+ sd_sdram_half += pads.cs_n.eq(r_dfi[phase_sel].cs_n)
+
+ #
+ # Bitslip
+ #
+ bitslip_cnt = Signal(4)
+ bitslip_inc = Signal()
+
+ sd_sys += [
+ If(bitslip_cnt == rd_bitslip,
+ bitslip_inc.eq(0)
+ ).Else(
+ bitslip_cnt.eq(bitslip_cnt+1),
+ bitslip_inc.eq(1)
+ )
+ ]
+
+ #
+ # DQ/DQS/DM data
+ #
+ sdram_half_clk_n = Signal()
+ self.comb += sdram_half_clk_n.eq(~sdram_half_clk)
+
+ postamble = Signal()
+ drive_dqs = Signal()
+ dqs_t_d0 = Signal()
+ dqs_t_d1 = Signal()
+
+ dqs_o = Signal(d//8)
+ dqs_t = Signal(d//8)
+
+ self.comb += [
+ dqs_t_d0.eq(~(drive_dqs | postamble)),
+ dqs_t_d1.eq(~drive_dqs),
+ ]
+
+ for i in range(d//8):
+ # DQS output
+ self.specials += Instance("ODDR2",
+ Instance.Parameter("DDR_ALIGNMENT", dqs_ddr_alignment),
+ Instance.Parameter("INIT", 0),
+ Instance.Parameter("SRTYPE", "ASYNC"),
+
+ Instance.Input("C0", sdram_half_clk),
+ Instance.Input("C1", sdram_half_clk_n),
+
+ Instance.Input("CE", 1),
+ Instance.Input("D0", 0),
+ Instance.Input("D1", 1),
+ Instance.Input("R", 0),
+ Instance.Input("S", 0),
+
+ Instance.Output("Q", dqs_o[i])
+ )
+
+ # DQS tristate cmd
+ self.specials += Instance("ODDR2",
+ Instance.Parameter("DDR_ALIGNMENT", dqs_ddr_alignment),
+ Instance.Parameter("INIT", 0),
+ Instance.Parameter("SRTYPE", "ASYNC"),
+
+ Instance.Input("C0", sdram_half_clk),
+ Instance.Input("C1", sdram_half_clk_n),
+
+ Instance.Input("CE", 1),
+ Instance.Input("D0", dqs_t_d0),
+ Instance.Input("D1", dqs_t_d1),
+ Instance.Input("R", 0),
+ Instance.Input("S", 0),
+
+ Instance.Output("Q", dqs_t[i])
+ )
+
+ # DQS tristate buffer
+ if hasattr(pads, "dqs_n"):
+ self.specials += Instance("OBUFTDS",
+ Instance.Input("I", dqs_o[i]),
+ Instance.Input("T", dqs_t[i]),
+
+ Instance.Output("O", pads.dqs[i]),
+ Instance.Output("OB", pads.dqs_n[i]),
+ )
+ else:
+ self.specials += Instance("OBUFT",
+ Instance.Input("I", dqs_o[i]),
+ Instance.Input("T", dqs_t[i]),
+
+ Instance.Output("O", pads.dqs[i])
+ )
+
+ sd_sdram_half += postamble.eq(drive_dqs)
+
+ d_dfi = [Record(phase_wrdata_description(nphases*d)+phase_rddata_description(nphases*d))
+ for i in range(2*nphases)]
+
+ for n, phase in enumerate(self.dfi.phases):
+ self.comb += [
+ d_dfi[n].wrdata.eq(phase.wrdata),
+ d_dfi[n].wrdata_mask.eq(phase.wrdata_mask),
+ d_dfi[n].wrdata_en.eq(phase.wrdata_en),
+ d_dfi[n].rddata_en.eq(phase.rddata_en),
+ ]
+ sd_sys += [
+ d_dfi[nphases+n].wrdata.eq(phase.wrdata),
+ d_dfi[nphases+n].wrdata_mask.eq(phase.wrdata_mask)
+ ]
+
+
+ drive_dq = Signal()
+ drive_dq_n = [Signal() for i in range(2)]
+ self.comb += drive_dq_n[0].eq(~drive_dq)
+ sd_sys += drive_dq_n[1].eq(drive_dq_n[0])
+
+ dq_t = Signal(d)
+ dq_o = Signal(d)
+ dq_i = Signal(d)
+
+ dq_wrdata = []
+ for i in range(2):
+ for j in reversed(range(nphases)):
+ dq_wrdata.append(d_dfi[i*nphases+j].wrdata[:d])
+ dq_wrdata.append(d_dfi[i*nphases+j].wrdata[d:])
+
+ for i in range(d):
+ # Data serializer
+ self.specials += Instance("OSERDES2",
+ Instance.Parameter("DATA_WIDTH", 4),
+ Instance.Parameter("DATA_RATE_OQ", "SDR"),
+ Instance.Parameter("DATA_RATE_OT", "SDR"),
+ Instance.Parameter("SERDES_MODE", "NONE"),
+ Instance.Parameter("OUTPUT_MODE", "SINGLE_ENDED"),
+
+ Instance.Output("OQ", dq_o[i]),
+ Instance.Input("OCE", 1),
+ Instance.Input("CLK0", sdram_full_wr_clk),
+ Instance.Input("CLK1", 0),
+ Instance.Input("IOCE", self.clk4x_wr_strb),
+ Instance.Input("RST", 0),
+ Instance.Input("CLKDIV", sys_clk),
+
+ Instance.Input("D1", dq_wrdata[wr_bitslip+3][i]),
+ Instance.Input("D2", dq_wrdata[wr_bitslip+2][i]),
+ Instance.Input("D3", dq_wrdata[wr_bitslip+1][i]),
+ Instance.Input("D4", dq_wrdata[wr_bitslip+0][i]),
+
+ Instance.Output("TQ", dq_t[i]),
+ Instance.Input("T1", drive_dq_n[(wr_bitslip+3)//4]),
+ Instance.Input("T2", drive_dq_n[(wr_bitslip+2)//4]),
+ Instance.Input("T3", drive_dq_n[(wr_bitslip+1)//4]),
+ Instance.Input("T4", drive_dq_n[(wr_bitslip+0)//4]),
+ Instance.Input("TRAIN", 0),
+ Instance.Input("TCE", 1),
+ Instance.Input("SHIFTIN1", 0),
+ Instance.Input("SHIFTIN2", 0),
+ Instance.Input("SHIFTIN3", 0),
+ Instance.Input("SHIFTIN4", 0),
+
+ Instance.Output("SHIFTOUT1"),
+ Instance.Output("SHIFTOUT2"),
+ Instance.Output("SHIFTOUT3"),
+ Instance.Output("SHIFTOUT4"),
+ )
+
+ # Data deserializer
+ self.specials += Instance("ISERDES2",
+ Instance.Parameter("DATA_WIDTH", 4),
+ Instance.Parameter("DATA_RATE", "SDR"),
+ Instance.Parameter("BITSLIP_ENABLE", "TRUE"),
+ Instance.Parameter("SERDES_MODE", "NONE"),
+ Instance.Parameter("INTERFACE_TYPE", "RETIMED"),
+
+ Instance.Input("D", dq_i[i]),
+ Instance.Input("CE0", 1),
+ Instance.Input("CLK0", sdram_full_rd_clk),
+ Instance.Input("CLK1", 0),
+ Instance.Input("IOCE", self.clk4x_rd_strb),
+ Instance.Input("RST", ResetSignal()),
+ Instance.Input("CLKDIV", sys_clk),
+ Instance.Output("SHIFTIN"),
+ Instance.Input("BITSLIP", bitslip_inc),
+ Instance.Output("FABRICOUT"),
+
+ Instance.Output("Q1", d_dfi[0*nphases+0].rddata[i+d]),
+ Instance.Output("Q2", d_dfi[0*nphases+0].rddata[i]),
+ Instance.Output("Q3", d_dfi[0*nphases+1].rddata[i+d]),
+ Instance.Output("Q4", d_dfi[0*nphases+1].rddata[i]),
+
+ Instance.Output("DFB"),
+ Instance.Output("CFB0"),
+ Instance.Output("CFB1"),
+ Instance.Output("VALID"),
+ Instance.Output("INCDEC"),
+ Instance.Output("SHIFTOUT")
+ )
+
+ # Data buffer
+ self.specials += Instance("IOBUF",
+ Instance.Input("I", dq_o[i]),
+ Instance.Output("O", dq_i[i]),
+ Instance.Input("T", dq_t[i]),
+ Instance.InOut("IO", pads.dq[i])
+ )
+
+ dq_wrdata_mask = []
+ for i in range(2):
+ for j in reversed(range(nphases)):
+ dq_wrdata_mask.append(d_dfi[i*nphases+j].wrdata_mask[:d//8])
+ dq_wrdata_mask.append(d_dfi[i*nphases+j].wrdata_mask[d//8:])
+
+ for i in range(d//8):
+ # Mask serializer
+ self.specials += Instance("OSERDES2",
+ Instance.Parameter("DATA_WIDTH", 4),
+ Instance.Parameter("DATA_RATE_OQ", "SDR"),
+ Instance.Parameter("DATA_RATE_OT", "SDR"),
+ Instance.Parameter("SERDES_MODE", "NONE"),
+ Instance.Parameter("OUTPUT_MODE", "SINGLE_ENDED"),
+
+ Instance.Output("OQ", pads.dm[i]),
+ Instance.Input("OCE", 1),
+ Instance.Input("CLK0", sdram_full_wr_clk),
+ Instance.Input("CLK1", 0),
+ Instance.Input("IOCE", self.clk4x_wr_strb),
+ Instance.Input("RST", 0),
+ Instance.Input("CLKDIV", sys_clk),
+
+ Instance.Input("D1", dq_wrdata_mask[wr_bitslip+3][i]),
+ Instance.Input("D2", dq_wrdata_mask[wr_bitslip+2][i]),
+ Instance.Input("D3", dq_wrdata_mask[wr_bitslip+1][i]),
+ Instance.Input("D4", dq_wrdata_mask[wr_bitslip+0][i]),
+
+ Instance.Output("TQ"),
+ Instance.Input("T1"),
+ Instance.Input("T2"),
+ Instance.Input("T3"),
+ Instance.Input("T4"),
+ Instance.Input("TRAIN", 0),
+ Instance.Input("TCE", 0),
+ Instance.Input("SHIFTIN1", 0),
+ Instance.Input("SHIFTIN2", 0),
+ Instance.Input("SHIFTIN3", 0),
+ Instance.Input("SHIFTIN4", 0),
+
+ Instance.Output("SHIFTOUT1"),
+ Instance.Output("SHIFTOUT2"),
+ Instance.Output("SHIFTOUT3"),
+ Instance.Output("SHIFTOUT4"),
+ )
+
+ #
+ # ODT
+ #
+ # ODT not yet supported
+ if hasattr(pads, "odt"):
+ self.comb += pads.odt.eq(0)
+
+ #
+ # DQ/DQS/DM control
+ #
+ self.comb += drive_dq.eq(d_dfi[self.phy_settings.wrphase].wrdata_en)
+
+ d_dfi_wrdata_en = Signal()
+ sd_sys += d_dfi_wrdata_en.eq(d_dfi[self.phy_settings.wrphase].wrdata_en)
+
+ r_dfi_wrdata_en = Signal(2)
+ sd_sdram_half += r_dfi_wrdata_en.eq(Cat(d_dfi_wrdata_en, r_dfi_wrdata_en[0]))
+
+ self.comb += drive_dqs.eq(r_dfi_wrdata_en[1])
+
+ rddata_sr = Signal(self.phy_settings.read_latency)
+ sd_sys += rddata_sr.eq(Cat(rddata_sr[1:self.phy_settings.read_latency],
+ d_dfi[self.phy_settings.rdphase].rddata_en))
+
+ for n, phase in enumerate(self.dfi.phases):
+ self.comb += [
+ phase.rddata.eq(d_dfi[n].rddata),
+ phase.rddata_valid.eq(rddata_sr[0]),
+ ]
--- /dev/null
+from migen.fhdl.std import log2_int
+
+def get_sdram_phy_header(sdram_phy):
+ if sdram_phy.phy_settings.memtype not in ["SDR", "DDR", "LPDDR", "DDR2"]:
+ raise NotImplementedError("The SDRAM PHY header generator only supports SDR, DDR, LPDDR and DDR2")
+
+ r = "#ifndef __HW_SDRAM_PHY_H\n#define __HW_SDRAM_PHY_H\n"
+ r += "#include <hw/common.h>\n#include <hw/csr.h>\n#include <hw/flags.h>\n\n"
+
+ r += "static void cdelay(int i);\n"
+
+ #
+ # commands_px functions
+ #
+ for n in range(sdram_phy.phy_settings.nphases):
+ r += """
+static void command_p{n}(int cmd)
+{{
+ dfii_pi{n}_command_write(cmd);
+ dfii_pi{n}_command_issue_write(1);
+}}""".format(n=str(n))
+ r += "\n\n"
+
+ #
+ # rd/wr access macros
+ #
+ r += """
+#define dfii_pird_address_write(X) dfii_pi{rdphase}_address_write(X)
+#define dfii_piwr_address_write(X) dfii_pi{wrphase}_address_write(X)
+
+#define dfii_pird_baddress_write(X) dfii_pi{rdphase}_baddress_write(X)
+#define dfii_piwr_baddress_write(X) dfii_pi{wrphase}_baddress_write(X)
+
+#define command_prd(X) command_p{rdphase}(X)
+#define command_pwr(X) command_p{wrphase}(X)
+""".format(rdphase=str(sdram_phy.phy_settings.rdphase), wrphase=str(sdram_phy.phy_settings.wrphase))
+ r +="\n"
+
+ #
+ # init sequence
+ #
+ cmds = {
+ "PRECHARGE_ALL" : "DFII_COMMAND_RAS|DFII_COMMAND_WE|DFII_COMMAND_CS",
+ "MODE_REGISTER" : "DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS",
+ "AUTO_REFRESH" : "DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_CS",
+ "CKE" : "DFII_CONTROL_CKE"
+ }
+
+ def gen_cmd(comment, a, ba, cmd, delay):
+ r = "\t/* {0} */\n".format(comment)
+ r += "\tdfii_pi0_address_write({0:#x});\n".format(a)
+ r += "\tdfii_pi0_baddress_write({0:d});\n".format(ba)
+ if "CKE" in cmd:
+ r += "\tdfii_control_write({0});\n".format(cmd)
+ else:
+ r += "\tcommand_p0({0});\n".format(cmd)
+ r += "\tcdelay({0:d});\n".format(delay)
+ r += "\n"
+ return r
+
+
+ r += "static void init_sequence(void)\n{\n"
+
+ cl = sdram_phy.phy_settings.cl
+
+ if sdram_phy.phy_settings.memtype == "SDR":
+ bl = 1*sdram_phy.phy_settings.nphases
+ mr = log2_int(bl) + (cl << 4)
+ reset_dll = 1 << 8
+
+ init_sequence = [
+ ("Bring CKE high", 0x0000, 0, cmds["CKE"], 2000),
+ ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0),
+ ("Load Mode Register / Reset DLL, CL={0:d}, BL={1:d}".format(cl, bl), mr + reset_dll, 0, cmds["MODE_REGISTER"], 200),
+ ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0),
+ ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4),
+ ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4),
+ ("Load Mode Register / CL={0:d}, BL={1:d}".format(cl, bl), mr, 0, cmds["MODE_REGISTER"], 200)
+ ]
+
+ elif sdram_phy.phy_settings.memtype == "DDR":
+ bl = 2*sdram_phy.phy_settings.nphases
+ mr = log2_int(bl) + (cl << 4)
+ emr = 0
+ reset_dll = 1 << 8
+
+ init_sequence = [
+ ("Bring CKE high", 0x0000, 0, cmds["CKE"], 2000),
+ ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0),
+ ("Load Extended Mode Register", emr, 1, cmds["MODE_REGISTER"], 0),
+ ("Load Mode Register / Reset DLL, CL={0:d}, BL={1:d}".format(cl, bl), mr + reset_dll, 0, cmds["MODE_REGISTER"], 200),
+ ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0),
+ ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4),
+ ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4),
+ ("Load Mode Register / CL={0:d}, BL={1:d}".format(cl, bl), mr, 0, cmds["MODE_REGISTER"], 200)
+ ]
+
+ elif sdram_phy.phy_settings.memtype == "LPDDR":
+ bl = 2*sdram_phy.phy_settings.nphases
+ mr = log2_int(bl) + (cl << 4)
+ emr = 0
+ reset_dll = 1 << 8
+
+ init_sequence = [
+ ("Bring CKE high", 0x0000, 0, cmds["CKE"], 2000),
+ ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0),
+ ("Load Extended Mode Register", emr, 2, cmds["MODE_REGISTER"], 0),
+ ("Load Mode Register / Reset DLL, CL={0:d}, BL={1:d}".format(cl, bl), mr + reset_dll, 0, cmds["MODE_REGISTER"], 200),
+ ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0),
+ ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4),
+ ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4),
+ ("Load Mode Register / CL={0:d}, BL={1:d}".format(cl, bl), mr, 0, cmds["MODE_REGISTER"], 200)
+ ]
+
+ elif sdram_phy.phy_settings.memtype == "DDR2":
+ bl = 2*sdram_phy.phy_settings.nphases
+ wr = 2
+ mr = log2_int(bl) + (cl << 4) + (wr << 9)
+ emr = 0
+ emr2 = 0
+ emr3 = 0
+ reset_dll = 1 << 8
+ ocd = 7 << 7
+
+ init_sequence = [
+ ("Bring CKE high", 0x0000, 0, cmds["CKE"], 2000),
+ ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0),
+ ("Load Extended Mode Register 3", emr3, 3, cmds["MODE_REGISTER"], 0),
+ ("Load Extended Mode Register 2", emr2, 2, cmds["MODE_REGISTER"], 0),
+ ("Load Extended Mode Register", emr, 1, cmds["MODE_REGISTER"], 0),
+ ("Load Mode Register / Reset DLL, CL={0:d}, BL={1:d}".format(cl, bl), mr + reset_dll, 0, cmds["MODE_REGISTER"], 200),
+ ("Precharge All", 0x0400, 0, cmds["PRECHARGE_ALL"], 0),
+ ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4),
+ ("Auto Refresh", 0x0, 0, cmds["AUTO_REFRESH"], 4),
+ ("Load Mode Register / CL={0:d}, BL={1:d}".format(cl, bl), mr, 0, cmds["MODE_REGISTER"], 200),
+ ("Load Extended Mode Register / OCD Default", emr+ocd, 1, cmds["MODE_REGISTER"], 0),
+ ("Load Extended Mode Register / OCD Exit", emr, 1, cmds["MODE_REGISTER"], 0),
+ ]
+
+ for comment, a, ba, cmd, delay in init_sequence:
+ r += gen_cmd(comment, a, ba, cmd, delay)
+
+ r += "}\n"
+ r += "#endif\n"
+
+ return r
--- /dev/null
+from migen.fhdl.std import *
+from migen.bank.description import *
+from migen.bank.eventmanager import *
+
+class Timer(Module, AutoCSR):
+ def __init__(self, width=32):
+ self._load = CSRStorage(width)
+ self._reload = CSRStorage(width)
+ self._en = CSRStorage()
+ self._update_value = CSR()
+ self._value = CSRStatus(width)
+
+ self.submodules.ev = EventManager()
+ self.ev.zero = EventSourceProcess()
+ self.ev.finalize()
+
+ ###
+
+ value = Signal(width)
+ self.sync += [
+ If(self._en.storage,
+ If(value == 0,
+ # set reload to 0 to disable reloading
+ value.eq(self._reload.storage)
+ ).Else(
+ value.eq(value - 1)
+ )
+ ).Else(
+ value.eq(self._load.storage)
+ ),
+ If(self._update_value.re, self._value.status.eq(value))
+ ]
+ self.comb += self.ev.zero.trigger.eq(value != 0)
--- /dev/null
+from migen.fhdl.std import *
+from migen.genlib.cdc import MultiReg
+from migen.bank.description import *
+from migen.bank.eventmanager import *
+
+class UART(Module, AutoCSR):
+ def __init__(self, pads, clk_freq, baud=115200):
+ self._rxtx = CSR(8)
+ self._divisor = CSRStorage(16, reset=int(clk_freq/baud/16))
+
+ self.submodules.ev = EventManager()
+ self.ev.tx = EventSourceProcess()
+ self.ev.rx = EventSourcePulse()
+ self.ev.finalize()
+
+ ###
+
+ pads.tx.reset = 1
+
+ enable16 = Signal()
+ enable16_counter = Signal(16)
+ self.comb += enable16.eq(enable16_counter == 0)
+ self.sync += [
+ enable16_counter.eq(enable16_counter - 1),
+ If(enable16,
+ enable16_counter.eq(self._divisor.storage - 1))
+ ]
+
+ # TX
+ tx_reg = Signal(8)
+ tx_bitcount = Signal(4)
+ tx_count16 = Signal(4)
+ tx_busy = self.ev.tx.trigger
+ self.sync += [
+ If(self._rxtx.re,
+ tx_reg.eq(self._rxtx.r),
+ tx_bitcount.eq(0),
+ tx_count16.eq(1),
+ tx_busy.eq(1),
+ pads.tx.eq(0)
+ ).Elif(enable16 & tx_busy,
+ tx_count16.eq(tx_count16 + 1),
+ If(tx_count16 == 0,
+ tx_bitcount.eq(tx_bitcount + 1),
+ If(tx_bitcount == 8,
+ pads.tx.eq(1)
+ ).Elif(tx_bitcount == 9,
+ pads.tx.eq(1),
+ tx_busy.eq(0)
+ ).Else(
+ pads.tx.eq(tx_reg[0]),
+ tx_reg.eq(Cat(tx_reg[1:], 0))
+ )
+ )
+ )
+ ]
+
+ # RX
+ rx = Signal()
+ self.specials += MultiReg(pads.rx, rx)
+ rx_r = Signal()
+ rx_reg = Signal(8)
+ rx_bitcount = Signal(4)
+ rx_count16 = Signal(4)
+ rx_busy = Signal()
+ rx_done = self.ev.rx.trigger
+ rx_data = self._rxtx.w
+ self.sync += [
+ rx_done.eq(0),
+ If(enable16,
+ rx_r.eq(rx),
+ If(~rx_busy,
+ If(~rx & rx_r, # look for start bit
+ rx_busy.eq(1),
+ rx_count16.eq(7),
+ rx_bitcount.eq(0)
+ )
+ ).Else(
+ rx_count16.eq(rx_count16 + 1),
+ If(rx_count16 == 0,
+ rx_bitcount.eq(rx_bitcount + 1),
+
+ If(rx_bitcount == 0,
+ If(rx, # verify start bit
+ rx_busy.eq(0)
+ )
+ ).Elif(rx_bitcount == 9,
+ rx_busy.eq(0),
+ If(rx, # verify stop bit
+ rx_data.eq(rx_reg),
+ rx_done.eq(1)
+ )
+ ).Else(
+ rx_reg.eq(Cat(rx_reg[1:], rx))
+ )
+ )
+ )
+ )
+ ]
-M2DIR=../..
-include $(M2DIR)/software/common.mak
+MSCDIR=../..
+include $(MSCDIR)/software/common.mak
OBJECTS=isr.o sdram.o main.o boot-helper.o boot.o dataflow.o
-include $(OBJECTS:.o=.d)
%.bin: %.elf
- $(MAKE) -C $(M2DIR)/tools
+ $(MAKE) -C $(MSCDIR)/tools
$(OBJCOPY) -O binary $< $@
chmod -x $@
- $(M2DIR)/tools/mkmmimg $@ write
+ $(MSCDIR)/tools/mkmscimg $@ write
bios.elf: linker.ld $(OBJECTS) libs
%.elf:
$(LD) $(LDFLAGS) -T $< -N -o $@ \
- $(M2DIR)/software/libbase/crt0.o \
+ $(MSCDIR)/software/libbase/crt0.o \
$(OBJECTS) \
- -L$(M2DIR)/software/libnet \
- -L$(M2DIR)/software/libbase \
- -L$(M2DIR)/software/libcompiler-rt \
+ -L$(MSCDIR)/software/libnet \
+ -L$(MSCDIR)/software/libbase \
+ -L$(MSCDIR)/software/libcompiler-rt \
-lnet -lbase-nofloat -lcompiler-rt
chmod -x $@
$(assemble)
libs:
- $(MAKE) -C $(M2DIR)/software/libcompiler-rt
- $(MAKE) -C $(M2DIR)/software/libbase
- $(MAKE) -C $(M2DIR)/software/libnet
+ $(MAKE) -C $(MSCDIR)/software/libcompiler-rt
+ $(MAKE) -C $(MSCDIR)/software/libbase
+ $(MAKE) -C $(MSCDIR)/software/libnet
flash: bios.bin
m1nor-ng bios.bin
static void help(void)
{
- puts("Milkymist(tm) BIOS");
+ puts("MiSoC BIOS");
puts("Don't know what to do? Try 'flashboot'.\n");
puts("Available commands:");
puts("mr - read address space");
}
static const char banner[] =
- "\nMILKYMIST(tm) v"VERSION" BIOS http://www.milkymist.org\n"
+ "\nMiSoC(tm) v"VERSION" BIOS http://www.milkymist.org\n"
"(c) Copyright 2007-2013 Sebastien Bourdeauducq\n"
"Built "__DATE__" "__TIME__"\n\n"
"This program is free software: you can redistribute it and/or modify\n"
# Toolchain options
#
-INCLUDES = -I$(M2DIR)/software/include/base -I$(M2DIR)/software/include -I$(M2DIR)/common
+INCLUDES = -I$(MSCDIR)/software/include/base -I$(MSCDIR)/software/include -I$(MSCDIR)/common
COMMONFLAGS = -O3 -mbarrel-shift-enabled -mmultiply-enabled -mdivide-enabled -msign-extend-enabled \
-Wall -fno-builtin -nostdinc $(INCLUDES)
CFLAGS = $(COMMONFLAGS) -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes
/*
- * Milkymist SoC (Software)
+ * MiSoC
* Copyright (C) 2007, 2008, 2009, 2011 Sebastien Bourdeauducq
* Copyright (C) Linux kernel developers
*
/*
- * Milkymist SoC (Software)
+ * MiSoC
* Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
* Copyright (C) Linus Torvalds and Linux kernel developers
*
-M2DIR=../..
-include $(M2DIR)/software/common.mak
+MSCDIR=../..
+include $(MSCDIR)/software/common.mak
OBJECTS=setjmp.o libc.o errno.o crc16.o crc32.o console.o system.o id.o uart.o time.o qsort.o strtod.o
get_soc_version_formatted(soc_version);
get_sysid_formatted(sysid);
- printf("Running on Milkymist-ng SoC %s (sysid:%s) at %dMHz\n", soc_version, sysid, identifier_frequency_read()/1000000);
+ printf("Running on MiSoC %s (sysid:%s) at %dMHz\n", soc_version, sysid, identifier_frequency_read()/1000000);
}
/*
- * Milkymist SoC (Software)
+ * MiSoC
* Copyright (C) 2007, 2008, 2009, 2010, 2011 Sebastien Bourdeauducq
* Copyright (C) Linus Torvalds and Linux kernel developers
*
/*
- * Milkymist SoC (Software)
+ * MiSoC
* Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq
* Copyright (C) Linux kernel developers
*
-M2DIR=../..
-include $(M2DIR)/software/common.mak
+MSCDIR=../..
+include $(MSCDIR)/software/common.mak
CFLAGS+=-D_YUGA_LITTLE_ENDIAN=0 -D_YUGA_BIG_ENDIAN=1 -Wno-missing-prototypes
-M2DIR=../..
-include $(M2DIR)/software/common.mak
+MSCDIR=../..
+include $(MSCDIR)/software/common.mak
OBJECTS=microudp.o tftp.o
-M2DIR=../..
-include $(M2DIR)/software/common.mak
+MSCDIR=../..
+include $(MSCDIR)/software/common.mak
OBJECTS=isr.o main.o
%.elf:
$(LD) $(LDFLAGS) \
- -T $(M2DIR)/software/libbase/linker-sdram.ld \
+ -T $(MSCDIR)/software/libbase/linker-sdram.ld \
-N -o $@ \
- $(M2DIR)/software/libbase/crt0.o \
+ $(MSCDIR)/software/libbase/crt0.o \
$(OBJECTS) \
- -L$(M2DIR)/software/libbase \
- -L$(M2DIR)/software/libcompiler-rt \
+ -L$(MSCDIR)/software/libbase \
+ -L$(MSCDIR)/software/libcompiler-rt \
-lbase -lcompiler-rt
chmod -x $@
$(assemble)
libs:
- $(MAKE) -C $(M2DIR)/software/libcompiler-rt
- $(MAKE) -C $(M2DIR)/software/libbase
+ $(MAKE) -C $(MSCDIR)/software/libcompiler-rt
+ $(MAKE) -C $(MSCDIR)/software/libbase
load: memtest.bin
- $(MAKE) -C $(M2DIR)/tools
- $(M2DIR)/tools/flterm --port /dev/ttyUSB0 --kernel memtest.bin
+ $(MAKE) -C $(MSCDIR)/tools
+ $(MSCDIR)/tools/flterm --port /dev/ttyUSB0 --kernel memtest.bin
clean:
-M2DIR=../..
-include $(M2DIR)/software/common.mak
+MSCDIR=../..
+include $(MSCDIR)/software/common.mak
OBJECTS=isr.o fb.o dvisampler0.o dvisampler1.o main.o
chmod -x $@
%.fbi: %.bin
- $(M2DIR)/tools/mkmmimg $< write $@
+ $(MSCDIR)/tools/mkmscimg $< write $@
videomixer.elf: $(OBJECTS) libs
%.elf:
$(LD) $(LDFLAGS) \
- -T $(M2DIR)/software/libbase/linker-sdram.ld \
+ -T $(MSCDIR)/software/libbase/linker-sdram.ld \
-N -o $@ \
- $(M2DIR)/software/libbase/crt0.o \
+ $(MSCDIR)/software/libbase/crt0.o \
$(OBJECTS) \
- -L$(M2DIR)/software/libbase \
- -L$(M2DIR)/software/libcompiler-rt \
+ -L$(MSCDIR)/software/libbase \
+ -L$(MSCDIR)/software/libcompiler-rt \
-lbase -lcompiler-rt
chmod -x $@
dvisampler1.o: dvisampler1.h
libs:
- $(MAKE) -C $(M2DIR)/software/libcompiler-rt
- $(MAKE) -C $(M2DIR)/software/libbase
+ $(MAKE) -C $(MSCDIR)/software/libcompiler-rt
+ $(MAKE) -C $(MSCDIR)/software/libbase
load: videomixer.bin
- $(MAKE) -C $(M2DIR)/tools
- $(M2DIR)/tools/flterm --port /dev/ttyUSB0 --kernel videomixer.bin
+ $(MAKE) -C $(MSCDIR)/tools
+ $(MSCDIR)/tools/flterm --port /dev/ttyUSB0 --kernel videomixer.bin
flash: videomixer.fbi
m1nor-ng videomixer.fbi
from migen.fhdl.std import *
from migen.sim.generic import *
-from milkymist.dvisampler.chansync import ChanSync
+from misoclib.dvisampler.chansync import ChanSync
class TB(Module):
def __init__(self, test_seq_it):
from migen.bus import asmibus
from migen.sim.generic import Simulator
-from milkymist.framebuffer import *
+from misoclib.framebuffer import *
def main():
hub = asmibus.Hub(16, 128)
from migen.bus.lasmibus import *
from migen.sim.generic import Simulator, TopLevel
-from milkymist.lasmicon.bankmachine import *
+from misoclib.lasmicon.bankmachine import *
from common import sdram_geom, sdram_timing, CommandLogger
from migen.fhdl.std import *
from migen.sim.generic import Proxy
-from milkymist import lasmicon
+from misoclib import lasmicon
MHz = 1000000
clk_freq = (83 + Fraction(1, 3))*MHz
from migen.bus.lasmibus import *
from migen.sim.generic import Simulator, TopLevel
-from milkymist.lasmicon import *
+from misoclib.lasmicon import *
from common import sdram_phy, sdram_geom, sdram_timing, DFILogger
from migen.actorlib import dma_lasmi
from migen.sim.generic import Simulator, TopLevel, Proxy
-from milkymist.lasmicon import *
+from misoclib.lasmicon import *
from common import sdram_phy, sdram_geom, sdram_timing, DFILogger
from migen.bus.transactions import *
from migen.sim.generic import Simulator, TopLevel
-from milkymist.lasmicon import *
+from misoclib.lasmicon import *
from common import sdram_phy, sdram_geom, sdram_timing, DFILogger
from migen.fhdl.std import *
from migen.sim.generic import Simulator, TopLevel
-from milkymist.lasmicon.refresher import *
+from misoclib.lasmicon.refresher import *
from common import CommandLogger
-TARGETS=mkmmimg flterm byteswap
+TARGETS=mkmscimg flterm byteswap
CC=gcc
RM ?= rm -f
%: %.c
$(CC) -O2 -Wall -I../common -s -o $@ $<
-install: mkmmimg flterm
+install: mkmscimg flterm
install -d /usr/local/bin
install -m755 -t /usr/local/bin $^
/*
- * Milkymist SoC
+ * MiSoC
* Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq
*
* This program is free software: you can redistribute it and/or modify
/*
- * Milkymist SoC
+ * MiSoC
* Copyright (C) 2007, 2008, 2009, 2010, 2011 Sebastien Bourdeauducq
* Copyright (C) 2011 Michael Walle
* Copyright (C) 2004 MontaVista Software, Inc
static void print_usage()
{
- fprintf(stderr, "Serial boot program for Milkymist SoC - v. 2.3\n");
+ fprintf(stderr, "Serial boot program for MiSoC - v. 2.4\n");
fprintf(stderr, "Copyright (C) 2007, 2008, 2009, 2010, 2011 Sebastien Bourdeauducq\n");
fprintf(stderr, "Copyright (C) 2011 Michael Walle\n");
fprintf(stderr, "Copyright (C) 2004 MontaVista Software, Inc\n\n");
+++ /dev/null
-/*
- * CRC32 computation tool and Milkymist image file writer
- * (c) 2009, 2010, 2012 Sebastien Bourdeauducq
- * Released under GNU GPL v3
- * This file is part of Milkymist.
- */
-
-/* crc32.c -- compute the CRC-32 of a data stream
- * Copyright (C) 1995-1998 Mark Adler
- * For conditions of distribution and use, see copyright notice in zlib.h
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <string.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-const unsigned int crc_table[256] = {
- 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
- 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
- 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
- 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
- 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
- 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
- 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
- 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
- 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
- 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
- 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
- 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
- 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
- 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
- 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
- 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
- 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
- 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
- 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
- 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
- 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
- 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
- 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
- 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
- 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
- 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
- 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
- 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
- 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
- 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
- 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
- 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
- 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
- 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
- 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
- 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
- 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
- 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
- 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
- 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
- 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
- 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
- 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
- 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
- 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
- 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
- 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
- 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
- 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
- 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
- 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
- 0x2d02ef8dL
-};
-
-#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
-#define DO2(buf) DO1(buf); DO1(buf);
-#define DO4(buf) DO2(buf); DO2(buf);
-#define DO8(buf) DO4(buf); DO4(buf);
-
-static unsigned int crc32(const unsigned char *buffer, unsigned int len)
-{
- unsigned int crc;
- crc = 0;
- crc = crc ^ 0xffffffffL;
- while(len >= 8) {
- DO8(buffer);
- len -= 8;
- }
- if(len) do {
- DO1(buffer);
- } while(--len);
- return crc ^ 0xffffffffL;
-}
-
-int main(int argc, char *argv[])
-{
- int fd, fd_out;
- unsigned char *buffer;
- unsigned int length;
- unsigned int crc;
-
- if(((argc != 2) && (argc != 3) && (argc != 4))
- || ((argc > 2) && (strcmp(argv[2], "write")))) {
- fprintf(stderr, "Usage: mkmmimg <filename> [write] [dest]\n");
- return 1;
- }
-
- fd = open(argv[1], O_RDONLY);
- if(fd == -1) {
- perror("open");
- return 1;
- }
-
- length = lseek(fd, 0, SEEK_END);
- lseek(fd, 0, SEEK_SET);
-
- buffer = mmap(NULL, length, PROT_READ, MAP_SHARED, fd, 0);
- if(!buffer) {
- perror("mmap");
- close(fd);
- return 1;
- }
- crc = crc32(buffer, length);
- printf("CRC32 (%s): %08x\n", argv[1], crc);
-
- if(argc == 3) {
- /* Write the CRC32 in big endian at the end of the file */
- char b[4];
-
- fd_out = open(argv[1], O_WRONLY|O_APPEND);
- if(fd_out == -1) {
- perror("open");
- return 1;
- }
- b[0] = (crc & 0xff000000) >> 24;
- b[1] = (crc & 0x00ff0000) >> 16;
- b[2] = (crc & 0x0000ff00) >> 8;
- b[3] = (crc & 0x000000ff) >> 0;
- write(fd_out, &b[0], 4);
- close(fd_out);
- }
-
- if(argc == 4) {
- /* Write a new file prepended with the size and CRC */
- char b[4];
-
- fd_out = open(argv[3], O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
- if(fd_out == -1) {
- perror("open");
- return 1;
- }
- b[0] = (length & 0xff000000) >> 24;
- b[1] = (length & 0x00ff0000) >> 16;
- b[2] = (length & 0x0000ff00) >> 8;
- b[3] = (length & 0x000000ff) >> 0;
- write(fd_out, &b[0], 4);
- b[0] = (crc & 0xff000000) >> 24;
- b[1] = (crc & 0x00ff0000) >> 16;
- b[2] = (crc & 0x0000ff00) >> 8;
- b[3] = (crc & 0x000000ff) >> 0;
- write(fd_out, &b[0], 4);
- write(fd_out, buffer, length);
- close(fd_out);
- }
-
- munmap(buffer, length);
- close(fd);
-
- return 0;
-}
--- /dev/null
+/*
+ * CRC32 computation tool and MiSoC image file writer
+ * (c) 2009, 2010, 2012 Sebastien Bourdeauducq
+ * Released under GNU GPL v3
+ * This file is part of MiSoC.
+ */
+
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-1998 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+const unsigned int crc_table[256] = {
+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+ 0x2d02ef8dL
+};
+
+#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
+#define DO2(buf) DO1(buf); DO1(buf);
+#define DO4(buf) DO2(buf); DO2(buf);
+#define DO8(buf) DO4(buf); DO4(buf);
+
+static unsigned int crc32(const unsigned char *buffer, unsigned int len)
+{
+ unsigned int crc;
+ crc = 0;
+ crc = crc ^ 0xffffffffL;
+ while(len >= 8) {
+ DO8(buffer);
+ len -= 8;
+ }
+ if(len) do {
+ DO1(buffer);
+ } while(--len);
+ return crc ^ 0xffffffffL;
+}
+
+int main(int argc, char *argv[])
+{
+ int fd, fd_out;
+ unsigned char *buffer;
+ unsigned int length;
+ unsigned int crc;
+
+ if(((argc != 2) && (argc != 3) && (argc != 4))
+ || ((argc > 2) && (strcmp(argv[2], "write")))) {
+ fprintf(stderr, "Usage: mkmscimg <filename> [write] [dest]\n");
+ return 1;
+ }
+
+ fd = open(argv[1], O_RDONLY);
+ if(fd == -1) {
+ perror("open");
+ return 1;
+ }
+
+ length = lseek(fd, 0, SEEK_END);
+ lseek(fd, 0, SEEK_SET);
+
+ buffer = mmap(NULL, length, PROT_READ, MAP_SHARED, fd, 0);
+ if(!buffer) {
+ perror("mmap");
+ close(fd);
+ return 1;
+ }
+ crc = crc32(buffer, length);
+ printf("CRC32 (%s): %08x\n", argv[1], crc);
+
+ if(argc == 3) {
+ /* Write the CRC32 in big endian at the end of the file */
+ char b[4];
+
+ fd_out = open(argv[1], O_WRONLY|O_APPEND);
+ if(fd_out == -1) {
+ perror("open");
+ return 1;
+ }
+ b[0] = (crc & 0xff000000) >> 24;
+ b[1] = (crc & 0x00ff0000) >> 16;
+ b[2] = (crc & 0x0000ff00) >> 8;
+ b[3] = (crc & 0x000000ff) >> 0;
+ write(fd_out, &b[0], 4);
+ close(fd_out);
+ }
+
+ if(argc == 4) {
+ /* Write a new file prepended with the size and CRC */
+ char b[4];
+
+ fd_out = open(argv[3], O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+ if(fd_out == -1) {
+ perror("open");
+ return 1;
+ }
+ b[0] = (length & 0xff000000) >> 24;
+ b[1] = (length & 0x00ff0000) >> 16;
+ b[2] = (length & 0x0000ff00) >> 8;
+ b[3] = (length & 0x000000ff) >> 0;
+ write(fd_out, &b[0], 4);
+ b[0] = (crc & 0xff000000) >> 24;
+ b[1] = (crc & 0x00ff0000) >> 16;
+ b[2] = (crc & 0x0000ff00) >> 8;
+ b[3] = (crc & 0x000000ff) >> 0;
+ write(fd_out, &b[0], 4);
+ write(fd_out, buffer, length);
+ close(fd_out);
+ }
+
+ munmap(buffer, length);
+ close(fd);
+
+ return 0;
+}
from migen.bank import csrgen
from mibuild.generic_platform import ConstraintError
-from milkymist import mxcrg, lm32, norflash, uart, s6ddrphy, dfii, lasmicon, \
+from misoclib import mxcrg, lm32, norflash, uart, s6ddrphy, dfii, lasmicon, \
identifier, timer, minimac3, framebuffer, dvisampler, gpio, memtest
version = "2.0"