From: Sebastien Bourdeauducq Date: Sat, 9 Nov 2013 14:27:32 +0000 (+0100) Subject: rename milkymist-ng to MiSoC X-Git-Tag: 24jan2021_ls180~2826 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=0b881d934ff8a7d88e3c2de35c5974b8d225176a;p=litex.git rename milkymist-ng to MiSoC --- diff --git a/.gitignore b/.gitignore index 61fe22b2..cea03fad 100644 --- a/.gitignore +++ b/.gitignore @@ -6,9 +6,8 @@ build/* *.elf *.bin *.fbi -tools/bin2hex tools/flterm -tools/mkmmimg +tools/mkmscimg tools/byteswap software/include/hw/csr.h software/include/hw/sdram_phy.h diff --git a/LICENSE b/LICENSE index 541a9dcd..70a79f87 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -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, diff --git a/README b/README index 70d4d25e..7c49085a 100644 --- a/README +++ b/README @@ -1,17 +1,10 @@ -[> 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) -------------------------- @@ -53,28 +46,29 @@ Once this is done, build the bitstream with: This will generate the build/soc-.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. diff --git a/make.py b/make.py index f70b6d6c..fc8548ff 100755 --- a/make.py +++ b/make.py @@ -4,8 +4,8 @@ import argparse, os, importlib, subprocess 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): @@ -57,7 +57,7 @@ TIMESPEC "TSise_sucks2" = FROM "GRPsys_clk" TO "GRPvga_clk" TIG; 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") diff --git a/milkymist/__init__.py b/milkymist/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/milkymist/counteradc/__init__.py b/milkymist/counteradc/__init__.py deleted file mode 100644 index 9df83c35..00000000 --- a/milkymist/counteradc/__init__.py +++ /dev/null @@ -1,61 +0,0 @@ -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) - ) - ) diff --git a/milkymist/cpuif.py b/milkymist/cpuif.py deleted file mode 100644 index b2467741..00000000 --- a/milkymist/cpuif.py +++ /dev/null @@ -1,64 +0,0 @@ -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 \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 diff --git a/milkymist/dfii/__init__.py b/milkymist/dfii/__init__.py deleted file mode 100644 index 22a5bcd5..00000000 --- a/milkymist/dfii/__init__.py +++ /dev/null @@ -1,55 +0,0 @@ -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] diff --git a/milkymist/dvisampler/__init__.py b/milkymist/dvisampler/__init__.py deleted file mode 100644 index c0227c12..00000000 --- a/milkymist/dvisampler/__init__.py +++ /dev/null @@ -1,79 +0,0 @@ -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"} diff --git a/milkymist/dvisampler/analysis.py b/milkymist/dvisampler/analysis.py deleted file mode 100644 index c7d24786..00000000 --- a/milkymist/dvisampler/analysis.py +++ /dev/null @@ -1,183 +0,0 @@ -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) - ) - ] diff --git a/milkymist/dvisampler/chansync.py b/milkymist/dvisampler/chansync.py deleted file mode 100644 index 272408e1..00000000 --- a/milkymist/dvisampler/chansync.py +++ /dev/null @@ -1,88 +0,0 @@ -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) diff --git a/milkymist/dvisampler/charsync.py b/milkymist/dvisampler/charsync.py deleted file mode 100644 index 92e38e9f..00000000 --- a/milkymist/dvisampler/charsync.py +++ /dev/null @@ -1,53 +0,0 @@ -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) diff --git a/milkymist/dvisampler/clocking.py b/milkymist/dvisampler/clocking.py deleted file mode 100644 index bcfca52b..00000000 --- a/milkymist/dvisampler/clocking.py +++ /dev/null @@ -1,57 +0,0 @@ -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) diff --git a/milkymist/dvisampler/common.py b/milkymist/dvisampler/common.py deleted file mode 100644 index f053237f..00000000 --- a/milkymist/dvisampler/common.py +++ /dev/null @@ -1,3 +0,0 @@ -control_tokens = [0b1101010100, 0b0010101011, 0b0101010100, 0b1010101011] -channel_layout = [("d", 8), ("c", 2), ("de", 1)] -frame_layout = [("parity", 1), ("r", 8), ("g", 8), ("b", 8)] diff --git a/milkymist/dvisampler/datacapture.py b/milkymist/dvisampler/datacapture.py deleted file mode 100644 index d7888433..00000000 --- a/milkymist/dvisampler/datacapture.py +++ /dev/null @@ -1,186 +0,0 @@ -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) diff --git a/milkymist/dvisampler/debug.py b/milkymist/dvisampler/debug.py deleted file mode 100644 index 39326640..00000000 --- a/milkymist/dvisampler/debug.py +++ /dev/null @@ -1,46 +0,0 @@ -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) - ] diff --git a/milkymist/dvisampler/decoding.py b/milkymist/dvisampler/decoding.py deleted file mode 100644 index 034f4543..00000000 --- a/milkymist/dvisampler/decoding.py +++ /dev/null @@ -1,24 +0,0 @@ -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) diff --git a/milkymist/dvisampler/dma.py b/milkymist/dvisampler/dma.py deleted file mode 100644 index d1cfce55..00000000 --- a/milkymist/dvisampler/dma.py +++ /dev/null @@ -1,156 +0,0 @@ -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() diff --git a/milkymist/dvisampler/edid.py b/milkymist/dvisampler/edid.py deleted file mode 100644 index b4afb4eb..00000000 --- a/milkymist/dvisampler/edid.py +++ /dev/null @@ -1,189 +0,0 @@ -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"))) diff --git a/milkymist/dvisampler/wer.py b/milkymist/dvisampler/wer.py deleted file mode 100644 index 89d89a0e..00000000 --- a/milkymist/dvisampler/wer.py +++ /dev/null @@ -1,59 +0,0 @@ -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)) diff --git a/milkymist/framebuffer/__init__.py b/milkymist/framebuffer/__init__.py deleted file mode 100644 index eb64208f..00000000 --- a/milkymist/framebuffer/__init__.py +++ /dev/null @@ -1,110 +0,0 @@ -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) diff --git a/milkymist/framebuffer/dvi.py b/milkymist/framebuffer/dvi.py deleted file mode 100644 index 9c085079..00000000 --- a/milkymist/framebuffer/dvi.py +++ /dev/null @@ -1,219 +0,0 @@ -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)) diff --git a/milkymist/framebuffer/format.py b/milkymist/framebuffer/format.py deleted file mode 100644 index 7e422453..00000000 --- a/milkymist/framebuffer/format.py +++ /dev/null @@ -1,113 +0,0 @@ -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)) - ) - ] diff --git a/milkymist/framebuffer/phy.py b/milkymist/framebuffer/phy.py deleted file mode 100644 index 0fbc65d7..00000000 --- a/milkymist/framebuffer/phy.py +++ /dev/null @@ -1,197 +0,0 @@ -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) - ] diff --git a/milkymist/gpio/__init__.py b/milkymist/gpio/__init__.py deleted file mode 100644 index d02332ec..00000000 --- a/milkymist/gpio/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -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) diff --git a/milkymist/identifier/__init__.py b/milkymist/identifier/__init__.py deleted file mode 100644 index ca792fd1..00000000 --- a/milkymist/identifier/__init__.py +++ /dev/null @@ -1,29 +0,0 @@ -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) - ] diff --git a/milkymist/lasmicon/__init__.py b/milkymist/lasmicon/__init__.py deleted file mode 100644 index 2e32d683..00000000 --- a/milkymist/lasmicon/__init__.py +++ /dev/null @@ -1,52 +0,0 @@ -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() diff --git a/milkymist/lasmicon/bankmachine.py b/milkymist/lasmicon/bankmachine.py deleted file mode 100644 index 6db44d19..00000000 --- a/milkymist/lasmicon/bankmachine.py +++ /dev/null @@ -1,144 +0,0 @@ -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) diff --git a/milkymist/lasmicon/multiplexer.py b/milkymist/lasmicon/multiplexer.py deleted file mode 100644 index 2f023ac7..00000000 --- a/milkymist/lasmicon/multiplexer.py +++ /dev/null @@ -1,210 +0,0 @@ -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) diff --git a/milkymist/lasmicon/perf.py b/milkymist/lasmicon/perf.py deleted file mode 100644 index ec09c79c..00000000 --- a/milkymist/lasmicon/perf.py +++ /dev/null @@ -1,44 +0,0 @@ -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) - ) - ] diff --git a/milkymist/lasmicon/refresher.py b/milkymist/lasmicon/refresher.py deleted file mode 100644 index d22271c0..00000000 --- a/milkymist/lasmicon/refresher.py +++ /dev/null @@ -1,68 +0,0 @@ -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")) - ) diff --git a/milkymist/lm32/__init__.py b/milkymist/lm32/__init__.py deleted file mode 100644 index 35cf81ca..00000000 --- a/milkymist/lm32/__init__.py +++ /dev/null @@ -1,53 +0,0 @@ -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:]) - ] diff --git a/milkymist/memtest/__init__.py b/milkymist/memtest/__init__.py deleted file mode 100644 index 92522295..00000000 --- a/milkymist/memtest/__init__.py +++ /dev/null @@ -1,118 +0,0 @@ -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() diff --git a/milkymist/minimac3/__init__.py b/milkymist/minimac3/__init__.py deleted file mode 100644 index 37efdd49..00000000 --- a/milkymist/minimac3/__init__.py +++ /dev/null @@ -1,81 +0,0 @@ -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)) diff --git a/milkymist/mxcrg/__init__.py b/milkymist/mxcrg/__init__.py deleted file mode 100644 index ab110018..00000000 --- a/milkymist/mxcrg/__init__.py +++ /dev/null @@ -1,48 +0,0 @@ -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)) diff --git a/milkymist/norflash/__init__.py b/milkymist/norflash/__init__.py deleted file mode 100644 index 241d6acf..00000000 --- a/milkymist/norflash/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -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)]) - ]) diff --git a/milkymist/s6ddrphy/__init__.py b/milkymist/s6ddrphy/__init__.py deleted file mode 100644 index 119f9779..00000000 --- a/milkymist/s6ddrphy/__init__.py +++ /dev/null @@ -1,388 +0,0 @@ -# 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]), - ] diff --git a/milkymist/s6ddrphy/initsequence.py b/milkymist/s6ddrphy/initsequence.py deleted file mode 100644 index 3c4c65bf..00000000 --- a/milkymist/s6ddrphy/initsequence.py +++ /dev/null @@ -1,146 +0,0 @@ -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 \n#include \n#include \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 diff --git a/milkymist/timer/__init__.py b/milkymist/timer/__init__.py deleted file mode 100644 index 3d1ab705..00000000 --- a/milkymist/timer/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -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) diff --git a/milkymist/uart/__init__.py b/milkymist/uart/__init__.py deleted file mode 100644 index 25530d62..00000000 --- a/milkymist/uart/__init__.py +++ /dev/null @@ -1,99 +0,0 @@ -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)) - ) - ) - ) - ) - ] diff --git a/misoclib/__init__.py b/misoclib/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/misoclib/counteradc/__init__.py b/misoclib/counteradc/__init__.py new file mode 100644 index 00000000..9df83c35 --- /dev/null +++ b/misoclib/counteradc/__init__.py @@ -0,0 +1,61 @@ +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) + ) + ) diff --git a/misoclib/cpuif.py b/misoclib/cpuif.py new file mode 100644 index 00000000..b2467741 --- /dev/null +++ b/misoclib/cpuif.py @@ -0,0 +1,64 @@ +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 \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 diff --git a/misoclib/dfii/__init__.py b/misoclib/dfii/__init__.py new file mode 100644 index 00000000..22a5bcd5 --- /dev/null +++ b/misoclib/dfii/__init__.py @@ -0,0 +1,55 @@ +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] diff --git a/misoclib/dvisampler/__init__.py b/misoclib/dvisampler/__init__.py new file mode 100644 index 00000000..fb1bbb88 --- /dev/null +++ b/misoclib/dvisampler/__init__.py @@ -0,0 +1,79 @@ +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"} diff --git a/misoclib/dvisampler/analysis.py b/misoclib/dvisampler/analysis.py new file mode 100644 index 00000000..17579f70 --- /dev/null +++ b/misoclib/dvisampler/analysis.py @@ -0,0 +1,183 @@ +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) + ) + ] diff --git a/misoclib/dvisampler/chansync.py b/misoclib/dvisampler/chansync.py new file mode 100644 index 00000000..270ef40e --- /dev/null +++ b/misoclib/dvisampler/chansync.py @@ -0,0 +1,88 @@ +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) diff --git a/misoclib/dvisampler/charsync.py b/misoclib/dvisampler/charsync.py new file mode 100644 index 00000000..99ea9aaa --- /dev/null +++ b/misoclib/dvisampler/charsync.py @@ -0,0 +1,53 @@ +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) diff --git a/misoclib/dvisampler/clocking.py b/misoclib/dvisampler/clocking.py new file mode 100644 index 00000000..bcfca52b --- /dev/null +++ b/misoclib/dvisampler/clocking.py @@ -0,0 +1,57 @@ +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) diff --git a/misoclib/dvisampler/common.py b/misoclib/dvisampler/common.py new file mode 100644 index 00000000..f053237f --- /dev/null +++ b/misoclib/dvisampler/common.py @@ -0,0 +1,3 @@ +control_tokens = [0b1101010100, 0b0010101011, 0b0101010100, 0b1010101011] +channel_layout = [("d", 8), ("c", 2), ("de", 1)] +frame_layout = [("parity", 1), ("r", 8), ("g", 8), ("b", 8)] diff --git a/misoclib/dvisampler/datacapture.py b/misoclib/dvisampler/datacapture.py new file mode 100644 index 00000000..d7888433 --- /dev/null +++ b/misoclib/dvisampler/datacapture.py @@ -0,0 +1,186 @@ +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) diff --git a/misoclib/dvisampler/debug.py b/misoclib/dvisampler/debug.py new file mode 100644 index 00000000..555d3eea --- /dev/null +++ b/misoclib/dvisampler/debug.py @@ -0,0 +1,46 @@ +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) + ] diff --git a/misoclib/dvisampler/decoding.py b/misoclib/dvisampler/decoding.py new file mode 100644 index 00000000..73a6718a --- /dev/null +++ b/misoclib/dvisampler/decoding.py @@ -0,0 +1,24 @@ +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) diff --git a/misoclib/dvisampler/dma.py b/misoclib/dvisampler/dma.py new file mode 100644 index 00000000..f98f97eb --- /dev/null +++ b/misoclib/dvisampler/dma.py @@ -0,0 +1,156 @@ +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() diff --git a/misoclib/dvisampler/edid.py b/misoclib/dvisampler/edid.py new file mode 100644 index 00000000..b4afb4eb --- /dev/null +++ b/misoclib/dvisampler/edid.py @@ -0,0 +1,189 @@ +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"))) diff --git a/misoclib/dvisampler/wer.py b/misoclib/dvisampler/wer.py new file mode 100644 index 00000000..6be35abf --- /dev/null +++ b/misoclib/dvisampler/wer.py @@ -0,0 +1,59 @@ +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)) diff --git a/misoclib/framebuffer/__init__.py b/misoclib/framebuffer/__init__.py new file mode 100644 index 00000000..ec49dba2 --- /dev/null +++ b/misoclib/framebuffer/__init__.py @@ -0,0 +1,110 @@ +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) diff --git a/misoclib/framebuffer/dvi.py b/misoclib/framebuffer/dvi.py new file mode 100644 index 00000000..9c085079 --- /dev/null +++ b/misoclib/framebuffer/dvi.py @@ -0,0 +1,219 @@ +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)) diff --git a/misoclib/framebuffer/format.py b/misoclib/framebuffer/format.py new file mode 100644 index 00000000..7e422453 --- /dev/null +++ b/misoclib/framebuffer/format.py @@ -0,0 +1,113 @@ +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)) + ) + ] diff --git a/misoclib/framebuffer/phy.py b/misoclib/framebuffer/phy.py new file mode 100644 index 00000000..ff71e690 --- /dev/null +++ b/misoclib/framebuffer/phy.py @@ -0,0 +1,197 @@ +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) + ] diff --git a/misoclib/gpio/__init__.py b/misoclib/gpio/__init__.py new file mode 100644 index 00000000..d02332ec --- /dev/null +++ b/misoclib/gpio/__init__.py @@ -0,0 +1,19 @@ +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) diff --git a/misoclib/identifier/__init__.py b/misoclib/identifier/__init__.py new file mode 100644 index 00000000..ca792fd1 --- /dev/null +++ b/misoclib/identifier/__init__.py @@ -0,0 +1,29 @@ +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) + ] diff --git a/misoclib/lasmicon/__init__.py b/misoclib/lasmicon/__init__.py new file mode 100644 index 00000000..60819cc8 --- /dev/null +++ b/misoclib/lasmicon/__init__.py @@ -0,0 +1,52 @@ +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() diff --git a/misoclib/lasmicon/bankmachine.py b/misoclib/lasmicon/bankmachine.py new file mode 100644 index 00000000..a9568118 --- /dev/null +++ b/misoclib/lasmicon/bankmachine.py @@ -0,0 +1,144 @@ +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) diff --git a/misoclib/lasmicon/multiplexer.py b/misoclib/lasmicon/multiplexer.py new file mode 100644 index 00000000..2ca99c1e --- /dev/null +++ b/misoclib/lasmicon/multiplexer.py @@ -0,0 +1,210 @@ +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) diff --git a/misoclib/lasmicon/perf.py b/misoclib/lasmicon/perf.py new file mode 100644 index 00000000..ec09c79c --- /dev/null +++ b/misoclib/lasmicon/perf.py @@ -0,0 +1,44 @@ +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) + ) + ] diff --git a/misoclib/lasmicon/refresher.py b/misoclib/lasmicon/refresher.py new file mode 100644 index 00000000..aa493aed --- /dev/null +++ b/misoclib/lasmicon/refresher.py @@ -0,0 +1,68 @@ +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")) + ) diff --git a/misoclib/lm32/__init__.py b/misoclib/lm32/__init__.py new file mode 100644 index 00000000..35cf81ca --- /dev/null +++ b/misoclib/lm32/__init__.py @@ -0,0 +1,53 @@ +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:]) + ] diff --git a/misoclib/memtest/__init__.py b/misoclib/memtest/__init__.py new file mode 100644 index 00000000..92522295 --- /dev/null +++ b/misoclib/memtest/__init__.py @@ -0,0 +1,118 @@ +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() diff --git a/misoclib/minimac3/__init__.py b/misoclib/minimac3/__init__.py new file mode 100644 index 00000000..37efdd49 --- /dev/null +++ b/misoclib/minimac3/__init__.py @@ -0,0 +1,81 @@ +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)) diff --git a/misoclib/mxcrg/__init__.py b/misoclib/mxcrg/__init__.py new file mode 100644 index 00000000..ab110018 --- /dev/null +++ b/misoclib/mxcrg/__init__.py @@ -0,0 +1,48 @@ +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)) diff --git a/misoclib/norflash/__init__.py b/misoclib/norflash/__init__.py new file mode 100644 index 00000000..241d6acf --- /dev/null +++ b/misoclib/norflash/__init__.py @@ -0,0 +1,24 @@ +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)]) + ]) diff --git a/misoclib/s6ddrphy/__init__.py b/misoclib/s6ddrphy/__init__.py new file mode 100644 index 00000000..cb0aa33a --- /dev/null +++ b/misoclib/s6ddrphy/__init__.py @@ -0,0 +1,388 @@ +# 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]), + ] diff --git a/misoclib/s6ddrphy/initsequence.py b/misoclib/s6ddrphy/initsequence.py new file mode 100644 index 00000000..3c4c65bf --- /dev/null +++ b/misoclib/s6ddrphy/initsequence.py @@ -0,0 +1,146 @@ +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 \n#include \n#include \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 diff --git a/misoclib/timer/__init__.py b/misoclib/timer/__init__.py new file mode 100644 index 00000000..3d1ab705 --- /dev/null +++ b/misoclib/timer/__init__.py @@ -0,0 +1,33 @@ +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) diff --git a/misoclib/uart/__init__.py b/misoclib/uart/__init__.py new file mode 100644 index 00000000..25530d62 --- /dev/null +++ b/misoclib/uart/__init__.py @@ -0,0 +1,99 @@ +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)) + ) + ) + ) + ) + ] diff --git a/software/bios/Makefile b/software/bios/Makefile index 9a7ef979..f6d45b87 100644 --- a/software/bios/Makefile +++ b/software/bios/Makefile @@ -1,5 +1,5 @@ -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 @@ -9,20 +9,20 @@ all: bios.bin -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 $@ @@ -36,9 +36,9 @@ main.o: main.c $(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 diff --git a/software/bios/main.c b/software/bios/main.c index c3e9a9a4..50f4897e 100644 --- a/software/bios/main.c +++ b/software/bios/main.c @@ -307,7 +307,7 @@ static void dfs(char *baseaddr) 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"); @@ -402,7 +402,7 @@ static void crcbios(void) } 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" diff --git a/software/common.mak b/software/common.mak index adc7c936..825a88e5 100644 --- a/software/common.mak +++ b/software/common.mak @@ -38,7 +38,7 @@ endif # 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 diff --git a/software/include/base/stdlib.h b/software/include/base/stdlib.h index 790e4eb0..da67b4e2 100644 --- a/software/include/base/stdlib.h +++ b/software/include/base/stdlib.h @@ -1,5 +1,5 @@ /* - * Milkymist SoC (Software) + * MiSoC * Copyright (C) 2007, 2008, 2009, 2011 Sebastien Bourdeauducq * Copyright (C) Linux kernel developers * diff --git a/software/include/base/string.h b/software/include/base/string.h index 9a4c22fe..4d0716be 100644 --- a/software/include/base/string.h +++ b/software/include/base/string.h @@ -1,5 +1,5 @@ /* - * Milkymist SoC (Software) + * MiSoC * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq * Copyright (C) Linus Torvalds and Linux kernel developers * diff --git a/software/libbase/Makefile b/software/libbase/Makefile index b9b9a7ab..f8a90b1a 100644 --- a/software/libbase/Makefile +++ b/software/libbase/Makefile @@ -1,5 +1,5 @@ -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 diff --git a/software/libbase/id.c b/software/libbase/id.c index bbb927da..03382966 100644 --- a/software/libbase/id.c +++ b/software/libbase/id.c @@ -43,5 +43,5 @@ void id_print(void) 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); } diff --git a/software/libbase/libc.c b/software/libbase/libc.c index 876e195d..e45a79da 100644 --- a/software/libbase/libc.c +++ b/software/libbase/libc.c @@ -1,5 +1,5 @@ /* - * Milkymist SoC (Software) + * MiSoC * Copyright (C) 2007, 2008, 2009, 2010, 2011 Sebastien Bourdeauducq * Copyright (C) Linus Torvalds and Linux kernel developers * diff --git a/software/libbase/vsnprintf.c b/software/libbase/vsnprintf.c index d23f66a7..2192974d 100644 --- a/software/libbase/vsnprintf.c +++ b/software/libbase/vsnprintf.c @@ -1,5 +1,5 @@ /* - * Milkymist SoC (Software) + * MiSoC * Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq * Copyright (C) Linux kernel developers * diff --git a/software/libcompiler-rt/Makefile b/software/libcompiler-rt/Makefile index 4bc33fe4..feeeb69c 100644 --- a/software/libcompiler-rt/Makefile +++ b/software/libcompiler-rt/Makefile @@ -1,5 +1,5 @@ -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 diff --git a/software/libnet/Makefile b/software/libnet/Makefile index e0f35a13..ad6a0473 100644 --- a/software/libnet/Makefile +++ b/software/libnet/Makefile @@ -1,5 +1,5 @@ -M2DIR=../.. -include $(M2DIR)/software/common.mak +MSCDIR=../.. +include $(MSCDIR)/software/common.mak OBJECTS=microudp.o tftp.o diff --git a/software/memtest/Makefile b/software/memtest/Makefile index 5647d32a..0a06503c 100644 --- a/software/memtest/Makefile +++ b/software/memtest/Makefile @@ -1,5 +1,5 @@ -M2DIR=../.. -include $(M2DIR)/software/common.mak +MSCDIR=../.. +include $(MSCDIR)/software/common.mak OBJECTS=isr.o main.o @@ -16,12 +16,12 @@ memtest.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 $@ @@ -35,12 +35,12 @@ main.o: main.c $(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: diff --git a/software/videomixer/Makefile b/software/videomixer/Makefile index 9742ac9d..9ec2f718 100644 --- a/software/videomixer/Makefile +++ b/software/videomixer/Makefile @@ -1,5 +1,5 @@ -M2DIR=../.. -include $(M2DIR)/software/common.mak +MSCDIR=../.. +include $(MSCDIR)/software/common.mak OBJECTS=isr.o fb.o dvisampler0.o dvisampler1.o main.o @@ -13,18 +13,18 @@ all: videomixer.bin videomixer.fbi 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 $@ @@ -62,12 +62,12 @@ dvisampler0.o: dvisampler0.h 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 diff --git a/tb/dvisampler/chansync.py b/tb/dvisampler/chansync.py index 9a8fbf77..4327d2d3 100644 --- a/tb/dvisampler/chansync.py +++ b/tb/dvisampler/chansync.py @@ -1,7 +1,7 @@ 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): diff --git a/tb/framebuffer/framebuffer.py b/tb/framebuffer/framebuffer.py index bddde1be..9d8d1da1 100644 --- a/tb/framebuffer/framebuffer.py +++ b/tb/framebuffer/framebuffer.py @@ -2,7 +2,7 @@ from migen.fhdl.std import * 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) diff --git a/tb/lasmicon/bankmachine.py b/tb/lasmicon/bankmachine.py index 3564183a..3a45daee 100644 --- a/tb/lasmicon/bankmachine.py +++ b/tb/lasmicon/bankmachine.py @@ -2,7 +2,7 @@ from migen.fhdl.std import * 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 diff --git a/tb/lasmicon/common.py b/tb/lasmicon/common.py index d7acd5c1..74bf579a 100644 --- a/tb/lasmicon/common.py +++ b/tb/lasmicon/common.py @@ -4,7 +4,7 @@ from math import ceil 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 diff --git a/tb/lasmicon/lasmicon.py b/tb/lasmicon/lasmicon.py index e64ece39..69156938 100644 --- a/tb/lasmicon/lasmicon.py +++ b/tb/lasmicon/lasmicon.py @@ -2,7 +2,7 @@ from migen.fhdl.std import * 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 diff --git a/tb/lasmicon/lasmicon_df.py b/tb/lasmicon/lasmicon_df.py index 054e1b66..c34c8fad 100644 --- a/tb/lasmicon/lasmicon_df.py +++ b/tb/lasmicon/lasmicon_df.py @@ -3,7 +3,7 @@ from migen.bus import lasmibus 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 diff --git a/tb/lasmicon/lasmicon_wb.py b/tb/lasmicon/lasmicon_wb.py index 4d6e2476..ad2f429b 100644 --- a/tb/lasmicon/lasmicon_wb.py +++ b/tb/lasmicon/lasmicon_wb.py @@ -3,7 +3,7 @@ from migen.bus import wishbone, wishbone2lasmi, lasmibus 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 diff --git a/tb/lasmicon/refresher.py b/tb/lasmicon/refresher.py index 72a527a3..daa86530 100644 --- a/tb/lasmicon/refresher.py +++ b/tb/lasmicon/refresher.py @@ -3,7 +3,7 @@ from random import Random 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 diff --git a/tools/Makefile b/tools/Makefile index 216e33d7..85212499 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -1,4 +1,4 @@ -TARGETS=mkmmimg flterm byteswap +TARGETS=mkmscimg flterm byteswap CC=gcc RM ?= rm -f @@ -7,7 +7,7 @@ all: $(TARGETS) %: %.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 $^ diff --git a/tools/byteswap.c b/tools/byteswap.c index 8d12b632..3e16236b 100644 --- a/tools/byteswap.c +++ b/tools/byteswap.c @@ -1,5 +1,5 @@ /* - * Milkymist SoC + * MiSoC * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq * * This program is free software: you can redistribute it and/or modify diff --git a/tools/flterm.c b/tools/flterm.c index 604ba5d7..2a1c7107 100644 --- a/tools/flterm.c +++ b/tools/flterm.c @@ -1,5 +1,5 @@ /* - * Milkymist SoC + * MiSoC * Copyright (C) 2007, 2008, 2009, 2010, 2011 Sebastien Bourdeauducq * Copyright (C) 2011 Michael Walle * Copyright (C) 2004 MontaVista Software, Inc @@ -645,7 +645,7 @@ static const struct option options[] = { 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"); diff --git a/tools/mkmmimg.c b/tools/mkmmimg.c deleted file mode 100644 index e3ad7309..00000000 --- a/tools/mkmmimg.c +++ /dev/null @@ -1,172 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include -#include -#include - -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 [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; -} diff --git a/tools/mkmscimg.c b/tools/mkmscimg.c new file mode 100644 index 00000000..49830feb --- /dev/null +++ b/tools/mkmscimg.c @@ -0,0 +1,172 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + +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 [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; +} diff --git a/top.py b/top.py index d25a95af..67022bef 100644 --- a/top.py +++ b/top.py @@ -8,7 +8,7 @@ from migen.bus import wishbone2lasmi, wishbone2csr 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"