From: Sebastien Bourdeauducq Date: Thu, 4 Jul 2013 17:19:39 +0000 (+0200) Subject: Mixxeo support X-Git-Tag: 24jan2021_ls180~2886 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=4cd360e6e14540b52e2a71425324715c6e81359e;p=litex.git Mixxeo support --- diff --git a/Makefile b/Makefile deleted file mode 100644 index 0e60158a..00000000 --- a/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -RM ?= rm -f - -all: build/soc.bit build/soc.fpg - -build/soc.bit build/soc.bin: - ./build.py - -build/soc.fpg: build/soc.bin - $(MAKE) -C tools - tools/byteswap $< $@ - -load: build/soc.bit - jtag -n load.jtag - -flash: build/soc.fpg - m1nor-ng build/soc.fpg - -clean: - $(RM) -r build/* - -.PHONY: all load clean flash diff --git a/README b/README index 183d6114..1475e615 100644 --- a/README +++ b/README @@ -2,17 +2,16 @@ ------------------------------ This is the next-generation Milkymist(tm) system-on-chip design, -introducing two key innovations: +introducing two key features: * Built on the powerful Migen VLSI logic design system. - * Increased system memory performance thanks to a new architecture - (ASMI) containing a transaction-reordering and superscalar controller. + * Increased system memory performance thanks to LASMI. -The Milkymist-NG SoC supports the Milkymist One board. Obtain yours at: - http://milkymist.org +This translates to more development productivity, better video resolution +and quality, ease of designing complex hardware accelerators, and much +more flexibility in hardware designs. -Note that the -NG version is still experimental work in progress. For the -production version of Milkymist SoC, visit: - https://github.com/milkymist/milkymist +The Milkymist-NG SoC supports the Mixxeo and the Milkymist One. +Obtain yours at http://milkymist.org [> Instructions (software) -------------------------- @@ -50,15 +49,11 @@ First, download and install Migen from: https://github.com/milkymist/migen Once this is done, build the bitstream with: - make -This will generate the build/soc.bit programming file. -Use: - make load -to load it with UrJTAG. + ./make.py [-p ] -l +This will generate the build/soc-.bit programming file +and load it with UrJTAG. -The SoC expects a bootloader to be located in flash at 0x860000, just -like the legacy SoC did. However, there is no binary compatibility and a -new BIOS needs to be built and flashed for the -NG SoC. +A new BIOS needs to be built and flashed for the -NG SoC. Enjoy! diff --git a/build.py b/build.py deleted file mode 100755 index dc9edce8..00000000 --- a/build.py +++ /dev/null @@ -1,77 +0,0 @@ -#!/usr/bin/env python3 - -import os - -from mibuild.platforms import m1 -from mibuild.tools import write_to_file - -from milkymist import cif - -import top - -def main(): - platform = m1.Platform() - soc = top.SoC(platform) - - platform.add_platform_command(""" -NET "{clk50}" TNM_NET = "GRPclk50"; -TIMESPEC "TSclk50" = PERIOD "GRPclk50" 20 ns HIGH 50%; -""", clk50=platform.lookup_request("clk50")) - - platform.add_platform_command(""" -INST "m1crg/wr_bufpll" LOC = "BUFPLL_X0Y2"; -INST "m1crg/rd_bufpll" LOC = "BUFPLL_X0Y3"; - -PIN "m1crg/bufg_x1.O" CLOCK_DEDICATED_ROUTE = FALSE; -""") - - if hasattr(soc, "fb"): - platform.add_platform_command(""" -NET "vga_clk" TNM_NET = "GRPvga_clk"; -NET "sys_clk" TNM_NET = "GRPsys_clk"; -TIMESPEC "TSise_sucks1" = FROM "GRPvga_clk" TO "GRPsys_clk" TIG; -TIMESPEC "TSise_sucks2" = FROM "GRPsys_clk" TO "GRPvga_clk" TIG; -""") - - if hasattr(soc, "minimac"): - platform.add_platform_command(""" -NET "{phy_rx_clk}" TNM_NET = "GRPphy_rx_clk"; -NET "{phy_tx_clk}" TNM_NET = "GRPphy_tx_clk"; -TIMESPEC "TSphy_rx_clk" = PERIOD "GRPphy_rx_clk" 40 ns HIGH 50%; -TIMESPEC "TSphy_tx_clk" = PERIOD "GRPphy_tx_clk" 40 ns HIGH 50%; -TIMESPEC "TSphy_tx_clk_io" = FROM "GRPphy_tx_clk" TO "PADS" 10 ns; -TIMESPEC "TSphy_rx_clk_io" = FROM "PADS" TO "GRPphy_rx_clk" 10 ns; -""", - phy_rx_clk=platform.lookup_request("eth_clocks").rx, - phy_tx_clk=platform.lookup_request("eth_clocks").tx,) - - if hasattr(soc, "dvisampler0"): - platform.add_platform_command(""" -NET "{dviclk0}" TNM_NET = "GRPdviclk0"; -NET "{dviclk0}" CLOCK_DEDICATED_ROUTE = FALSE; -TIMESPEC "TSdviclk0" = PERIOD "GRPdviclk0" 26.7 ns HIGH 50%; -""", dviclk0=platform.lookup_request("dvi_in", 0).clk) - if hasattr(soc, "dvisampler1"): - platform.add_platform_command(""" -NET "{dviclk1}" TNM_NET = "GRPdviclk1"; -NET "{dviclk1}" CLOCK_DEDICATED_ROUTE = FALSE; -TIMESPEC "TSdviclk1" = PERIOD "GRPdviclk1" 26.7 ns HIGH 50%; -""", dviclk1=platform.lookup_request("dvi_in", 1).clk) - - for d in ["m1crg", "s6ddrphy", "minimac3"]: - platform.add_source_dir(os.path.join("verilog", d)) - platform.add_sources(os.path.join("verilog", "lm32", "submodule", "rtl"), - "lm32_cpu.v", "lm32_instruction_unit.v", "lm32_decoder.v", - "lm32_load_store_unit.v", "lm32_adder.v", "lm32_addsub.v", "lm32_logic_op.v", - "lm32_shifter.v", "lm32_multiplier.v", "lm32_mc_arithmetic.v", - "lm32_interrupt.v", "lm32_ram.v", "lm32_dp_ram.v", "lm32_icache.v", - "lm32_dcache.v", "lm32_top.v", "lm32_debug.v", "lm32_jtag.v", "jtag_cores.v", - "jtag_tap_spartan6.v", "lm32_itlb.v", "lm32_dtlb.v") - platform.add_sources(os.path.join("verilog", "lm32"), "lm32_config.v") - - platform.build_cmdline(soc, build_name="soc") - csr_header = cif.get_csr_header(soc.csr_base, soc.csrbankarray, soc.interrupt_map) - write_to_file("software/include/hw/csr.h", csr_header) - -if __name__ == "__main__": - main() diff --git a/jtag.py b/jtag.py new file mode 100644 index 00000000..6aeaf45a --- /dev/null +++ b/jtag.py @@ -0,0 +1,14 @@ +import subprocess + +def load(bitstream): + cmds = """cable milkymist +detect +pld load {bitstream} +quit +""".format(bitstream=bitstream) + process = subprocess.Popen("jtag", stdin=subprocess.PIPE) + process.stdin.write(cmds.encode("ASCII")) + process.communicate() + +def flash(bitstream): + subprocess.call(["m1nor-ng", bitstream]) diff --git a/load.jtag b/load.jtag deleted file mode 100644 index c20825fb..00000000 --- a/load.jtag +++ /dev/null @@ -1,3 +0,0 @@ -cable milkymist -detect -pld load build/soc.bit diff --git a/make.py b/make.py new file mode 100755 index 00000000..236a9f13 --- /dev/null +++ b/make.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 + +import argparse, os, importlib, subprocess + +from mibuild.tools import write_to_file + +from milkymist import cif +import top, jtag + +def build(platform_name, build_bitstream, build_header): + platform_module = importlib.import_module("mibuild.platforms."+platform_name) + platform = platform_module.Platform() + soc = top.SoC(platform, platform_name) + + platform.add_platform_command(""" +INST "mxcrg/wr_bufpll" LOC = "BUFPLL_X0Y2"; +INST "mxcrg/rd_bufpll" LOC = "BUFPLL_X0Y3"; + +PIN "mxcrg/bufg_x1.O" CLOCK_DEDICATED_ROUTE = FALSE; +""") + + if hasattr(soc, "fb"): + platform.add_platform_command(""" +NET "vga_clk" TNM_NET = "GRPvga_clk"; +NET "sys_clk" TNM_NET = "GRPsys_clk"; +TIMESPEC "TSise_sucks1" = FROM "GRPvga_clk" TO "GRPsys_clk" TIG; +TIMESPEC "TSise_sucks2" = FROM "GRPsys_clk" TO "GRPvga_clk" TIG; +""") + + for d in ["mxcrg", "s6ddrphy", "minimac3"]: + platform.add_source_dir(os.path.join("verilog", d)) + platform.add_sources(os.path.join("verilog", "lm32", "submodule", "rtl"), + "lm32_cpu.v", "lm32_instruction_unit.v", "lm32_decoder.v", + "lm32_load_store_unit.v", "lm32_adder.v", "lm32_addsub.v", "lm32_logic_op.v", + "lm32_shifter.v", "lm32_multiplier.v", "lm32_mc_arithmetic.v", + "lm32_interrupt.v", "lm32_ram.v", "lm32_dp_ram.v", "lm32_icache.v", + "lm32_dcache.v", "lm32_top.v", "lm32_debug.v", "lm32_jtag.v", "jtag_cores.v", + "jtag_tap_spartan6.v", "lm32_itlb.v", "lm32_dtlb.v") + platform.add_sources(os.path.join("verilog", "lm32"), "lm32_config.v") + + if build_bitstream: + build_name = "soc-"+platform_name + platform.build(soc, build_name=build_name) + subprocess.call(["tools/byteswap", build_name+".bin", build_name+".fpg"]) + else: + soc.finalize() + if build_header: + csr_header = cif.get_csr_header(soc.csr_base, soc.csrbankarray, soc.interrupt_map) + write_to_file("software/include/hw/csr.h", csr_header) + +def main(): + parser = argparse.ArgumentParser(description="milkymist-ng - a high performance SoC built on Migen technology.") + 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 file with CSR/IRQ defs") + parser.add_argument("-l", "--load", default=False, action="store_true", help="load bitstream to SRAM") + parser.add_argument("-f", "--flash", default=False, action="store_true", help="load bitstream to flash") + args = parser.parse_args() + + build(args.platform, not args.no_bitstream, not args.no_header) + if args.load: + jtag.load("build/soc-"+args.platform+".bit") + if args.flash: + jtag.flash("build/soc-"+args.platform+".fpg") + +if __name__ == "__main__": + main() diff --git a/milkymist/m1crg/__init__.py b/milkymist/m1crg/__init__.py deleted file mode 100644 index e163c1bf..00000000 --- a/milkymist/m1crg/__init__.py +++ /dev/null @@ -1,96 +0,0 @@ -from fractions import Fraction - -from migen.fhdl.std import * -from migen.bank.description import * - -class M1CRG(Module, AutoCSR): - def __init__(self, pads, outfreq1x): - self.clock_domains.cd_sys = ClockDomain() - self.clock_domains.cd_sys2x_270 = ClockDomain() - self.clock_domains.cd_sys4x_wr = ClockDomain() - self.clock_domains.cd_sys4x_rd = ClockDomain() - self.clock_domains.cd_eth_rx = ClockDomain() - self.clock_domains.cd_eth_tx = ClockDomain() - self.clock_domains.cd_vga = ClockDomain(reset_less=True) - - self.clk4x_wr_strb = Signal() - self.clk4x_rd_strb = Signal() - - self._r_cmd_data = CSRStorage(10) - self._r_send_cmd_data = CSR() - self._r_send_go = CSR() - self._r_status = CSRStatus(3) - - ### - - infreq = 50*1000000 - ratio = Fraction(outfreq1x)/Fraction(infreq) - in_period = float(Fraction(1000000000)/Fraction(infreq)) - - vga_progdata = Signal() - vga_progen = Signal() - vga_progdone = Signal() - vga_locked = Signal() - - self.specials += Instance("m1crg", - 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_sys2x_270.clk), - Instance.Output("clk4x_wr", self.cd_sys4x_wr.clk), - Instance.Output("clk4x_rd", self.cd_sys4x_rd.clk), - Instance.Output("eth_rx_clk", self.cd_eth_rx.clk), - Instance.Output("eth_tx_clk", self.cd_eth_tx.clk), - Instance.Output("vga_clk", self.cd_vga.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), - Instance.Output("vga_clk_pad", pads.vga_clk), - - Instance.Input("vga_progclk", ClockSignal()), - Instance.Input("vga_progdata", vga_progdata), - Instance.Input("vga_progen", vga_progen), - Instance.Output("vga_progdone", vga_progdone), - Instance.Output("vga_locked", vga_locked)) - - 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 += [ - vga_progdata.eq(transmitting & sr[0]), - vga_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) - ) - - self.comb += self._r_status.status.eq(Cat(busy, vga_progdone, vga_locked)) diff --git a/milkymist/mxcrg/__init__.py b/milkymist/mxcrg/__init__.py new file mode 100644 index 00000000..7107d023 --- /dev/null +++ b/milkymist/mxcrg/__init__.py @@ -0,0 +1,96 @@ +from fractions import Fraction + +from migen.fhdl.std import * +from migen.bank.description import * + +class MXCRG(Module, AutoCSR): + def __init__(self, pads, outfreq1x): + self.clock_domains.cd_sys = ClockDomain() + self.clock_domains.cd_sys2x_270 = ClockDomain() + self.clock_domains.cd_sys4x_wr = ClockDomain() + self.clock_domains.cd_sys4x_rd = ClockDomain() + self.clock_domains.cd_eth_rx = ClockDomain() + self.clock_domains.cd_eth_tx = ClockDomain() + self.clock_domains.cd_vga = ClockDomain(reset_less=True) + + self.clk4x_wr_strb = Signal() + self.clk4x_rd_strb = Signal() + + self._r_cmd_data = CSRStorage(10) + self._r_send_cmd_data = CSR() + self._r_send_go = CSR() + self._r_status = CSRStatus(3) + + ### + + infreq = 50*1000000 + ratio = Fraction(outfreq1x)/Fraction(infreq) + in_period = float(Fraction(1000000000)/Fraction(infreq)) + + vga_progdata = Signal() + vga_progen = Signal() + vga_progdone = Signal() + vga_locked = Signal() + + 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_sys2x_270.clk), + Instance.Output("clk4x_wr", self.cd_sys4x_wr.clk), + Instance.Output("clk4x_rd", self.cd_sys4x_rd.clk), + Instance.Output("eth_rx_clk", self.cd_eth_rx.clk), + Instance.Output("eth_tx_clk", self.cd_eth_tx.clk), + Instance.Output("vga_clk", self.cd_vga.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), + Instance.Output("vga_clk_pad", pads.vga_clk), + + Instance.Input("vga_progclk", ClockSignal()), + Instance.Input("vga_progdata", vga_progdata), + Instance.Input("vga_progen", vga_progen), + Instance.Output("vga_progdone", vga_progdone), + Instance.Output("vga_locked", vga_locked)) + + 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 += [ + vga_progdata.eq(transmitting & sr[0]), + vga_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) + ) + + self.comb += self._r_status.status.eq(Cat(busy, vga_progdone, vga_locked)) diff --git a/top.py b/top.py index 25fa2ea8..4935d26f 100644 --- a/top.py +++ b/top.py @@ -6,8 +6,9 @@ from migen.fhdl.std import * from migen.bus import wishbone, csr, lasmibus, dfi from migen.bus import wishbone2lasmi, wishbone2csr from migen.bank import csrgen +from mibuild.generic_platform import ConstraintError -from milkymist import m1crg, lm32, norflash, uart, s6ddrphy, dfii, lasmicon, \ +from milkymist import mxcrg, lm32, norflash, uart, s6ddrphy, dfii, lasmicon, \ identifier, timer, minimac3, framebuffer, dvisampler, \ counteradc, gpio from milkymist.cif import get_macros @@ -51,10 +52,14 @@ sdram_timing = lasmicon.TimingSettings( write_time=16 ) -class M1ClockPads: +class MXClockPads: def __init__(self, platform): self.clk50 = platform.request("clk50") - self.trigger_reset = platform.request("user_btn", 1) + self.trigger_reset = 0 + try: + self.trigger_reset = platform.request("user_btn", 1) + except ConstraintError: + pass self.norflash_rst_n = platform.request("norflash_rst_n") self.vga_clk = platform.request("vga_clock") ddram_clock = platform.request("ddram_clock") @@ -93,7 +98,7 @@ class SoC(Module): "dvisampler1": 4, } - def __init__(self, platform): + def __init__(self, platform, platform_name): # # LASMI # @@ -142,18 +147,19 @@ class SoC(Module): # # CSR # - self.submodules.crg = m1crg.M1CRG(M1ClockPads(platform), clk_freq) + self.submodules.crg = mxcrg.MXCRG(MXClockPads(platform), clk_freq) self.submodules.uart = uart.UART(platform.request("serial"), clk_freq, baud=115200) self.submodules.identifier = identifier.Identifier(0x4D31, version, int(clk_freq)) self.submodules.timer0 = timer.Timer() self.submodules.fb = framebuffer.MixFramebuffer(platform.request("vga"), lasmim_fb0, lasmim_fb1) self.submodules.dvisampler0 = dvisampler.DVISampler(platform.request("dvi_in", 0), lasmim_dvi0) self.submodules.dvisampler1 = dvisampler.DVISampler(platform.request("dvi_in", 1), lasmim_dvi1) - pots_pads = platform.request("dvi_pots") - self.submodules.pots = counteradc.CounterADC(pots_pads.charge, - [pots_pads.blackout, pots_pads.crossfade]) - self.submodules.buttons = gpio.GPIOIn(Cat(platform.request("user_btn", 0), platform.request("user_btn", 2))) - self.submodules.leds = gpio.GPIOOut(Cat(*[platform.request("user_led", i) for i in range(2)])) + if platform_name == "m1": + pots_pads = platform.request("dvi_pots") + self.submodules.pots = counteradc.CounterADC(pots_pads.charge, + [pots_pads.blackout, pots_pads.crossfade]) + self.submodules.buttons = gpio.GPIOIn(Cat(platform.request("user_btn", 0), platform.request("user_btn", 2))) + self.submodules.leds = gpio.GPIOOut(Cat(*[platform.request("user_led", i) for i in range(2)])) self.submodules.csrbankarray = csrgen.BankArray(self, lambda name, memory: self.csr_map[name if memory is None else name + "_" + memory.name_override]) diff --git a/verilog/m1crg/m1crg.v b/verilog/m1crg/m1crg.v deleted file mode 100644 index 10e30e04..00000000 --- a/verilog/m1crg/m1crg.v +++ /dev/null @@ -1,311 +0,0 @@ -module m1crg #( - parameter in_period = 0.0, - parameter f_mult = 0, - parameter f_div = 0, - parameter clk2x_period = (in_period*f_div)/(2.0*f_mult) -) ( - input clk50_pad, - input trigger_reset, - - output sys_clk, - output reg sys_rst, - - /* Reset NOR flash */ - output norflash_rst_n, - - /* DDR PHY clocks */ - output clk2x_270, - output clk4x_wr, - output clk4x_wr_strb, - output clk4x_rd, - output clk4x_rd_strb, - - /* DDR off-chip clocking */ - output ddr_clk_pad_p, - output ddr_clk_pad_n, - - /* Ethernet PHY clocks */ - output reg eth_phy_clk_pad, - input eth_rx_clk_pad, - input eth_tx_clk_pad, - output eth_rx_clk, - output eth_tx_clk, - - /* VGA clock */ - output vga_clk, /* < buffered, to internal clock network */ - output vga_clk_pad, /* < forwarded through ODDR2, to I/O */ - - /* VGA clock control */ - input vga_progclk, - input vga_progdata, - input vga_progen, - output vga_progdone, - output vga_locked -); - -/* - * Reset - */ - -reg [19:0] rst_debounce; -always @(posedge sys_clk) begin - if(trigger_reset) - rst_debounce <= 20'hFFFFF; - else if(rst_debounce != 20'd0) - rst_debounce <= rst_debounce - 20'd1; - sys_rst <= rst_debounce != 20'd0; -end - -/* - * We must release the Flash reset before the system reset - * because the Flash needs some time to come out of reset - * and the CPU begins fetching instructions from it - * as soon as the system reset is released. - * From datasheet, minimum reset pulse width is 100ns - * and reset-to-read time is 150ns. - */ - -reg [7:0] flash_rstcounter; - -always @(posedge sys_clk) begin - if(trigger_reset) - flash_rstcounter <= 8'd0; - else if(~flash_rstcounter[7]) - flash_rstcounter <= flash_rstcounter + 8'd1; -end - -assign norflash_rst_n = flash_rstcounter[7]; - -/* - * Clock management. Inspired by the NWL reference design. - */ - -wire sdr_clk50; -wire clkdiv; - -IBUF #( - .IOSTANDARD("DEFAULT") -) clk2_iob ( - .I(clk50_pad), - .O(sdr_clk50) -); - -BUFIO2 #( - .DIVIDE(1), - .DIVIDE_BYPASS("FALSE"), - .I_INVERT("FALSE") -) bufio2_inst2 ( - .I(sdr_clk50), - .IOCLK(), - .DIVCLK(clkdiv), - .SERDESSTROBE() -); - -wire pll_lckd; -wire buf_pll_fb_out; -wire pllout0; -wire pllout1; -wire pllout2; -wire pllout3; -wire pllout4; -wire pllout5; - -PLL_ADV #( - .BANDWIDTH("OPTIMIZED"), - .CLKFBOUT_MULT(4*f_mult), - .CLKFBOUT_PHASE(0.0), - .CLKIN1_PERIOD(in_period), - .CLKIN2_PERIOD(in_period), - - .CLKOUT0_DIVIDE(f_div), - .CLKOUT0_DUTY_CYCLE(0.5), - .CLKOUT0_PHASE(0.0), - - .CLKOUT1_DIVIDE(f_div), - .CLKOUT1_DUTY_CYCLE(0.5), - .CLKOUT1_PHASE(0.0), - - .CLKOUT2_DIVIDE(2*f_div), - .CLKOUT2_DUTY_CYCLE(0.5), - .CLKOUT2_PHASE(270.0), - - .CLKOUT3_DIVIDE(4*f_div), - .CLKOUT3_DUTY_CYCLE(0.5), - .CLKOUT3_PHASE(0.0), - - .CLKOUT4_DIVIDE(4*f_mult), - .CLKOUT4_DUTY_CYCLE(0.5), - .CLKOUT4_PHASE(0.0), - - .CLKOUT5_DIVIDE(2*f_div), - .CLKOUT5_DUTY_CYCLE(0.5), - .CLKOUT5_PHASE(250.0), - - .COMPENSATION("INTERNAL"), - .DIVCLK_DIVIDE(1), - .REF_JITTER(0.100), - .CLK_FEEDBACK("CLKFBOUT"), - .SIM_DEVICE("SPARTAN6") -) pll ( - .CLKFBDCM(), - .CLKFBOUT(buf_pll_fb_out), - .CLKOUT0(pllout0), /* < x4 clock for writes */ - .CLKOUT1(pllout1), /* < x4 clock for reads */ - .CLKOUT2(pllout2), /* < x2 270 clock for DQS, memory address and control signals */ - .CLKOUT3(pllout3), /* < x1 clock for system and memory controller */ - .CLKOUT4(pllout4), /* < buffered clk50 */ - .CLKOUT5(pllout5), /* < x2 clock to off-chip DDR */ - .CLKOUTDCM0(), - .CLKOUTDCM1(), - .CLKOUTDCM2(), - .CLKOUTDCM3(), - .CLKOUTDCM4(), - .CLKOUTDCM5(), - .DO(), - .DRDY(), - .LOCKED(pll_lckd), - .CLKFBIN(buf_pll_fb_out), - .CLKIN1(clkdiv), - .CLKIN2(1'b0), - .CLKINSEL(1'b1), - .DADDR(5'b00000), - .DCLK(1'b0), - .DEN(1'b0), - .DI(16'h0000), - .DWE(1'b0), - .RST(1'b0), - .REL(1'b0) -); - -BUFPLL #( - .DIVIDE(4) -) wr_bufpll ( - .PLLIN(pllout0), - .GCLK(sys_clk), - .LOCKED(pll_lckd), - .IOCLK(clk4x_wr), - .LOCK(), - .SERDESSTROBE(clk4x_wr_strb) -); - -BUFPLL #( - .DIVIDE(4) -) rd_bufpll ( - .PLLIN(pllout1), - .GCLK(sys_clk), - .LOCKED(pll_lckd), - .IOCLK(clk4x_rd), - .LOCK(), - .SERDESSTROBE(clk4x_rd_strb) -); - -BUFG bufg_x2_2( - .I(pllout2), - .O(clk2x_270) -); - -BUFG bufg_x1( - .I(pllout3), - .O(sys_clk) -); - -wire clk50g; -BUFG bufg_50( - .I(pllout4), - .O(clk50g) -); - -wire clk2x_off; -BUFG bufg_x2_offclk( - .I(pllout5), - .O(clk2x_off) -); - - -/* - * SDRAM clock - */ - -ODDR2 #( - .DDR_ALIGNMENT("NONE"), - .INIT(1'b0), - .SRTYPE("SYNC") -) sd_clk_forward_p ( - .Q(ddr_clk_pad_p), - .C0(clk2x_off), - .C1(~clk2x_off), - .CE(1'b1), - .D0(1'b1), - .D1(1'b0), - .R(1'b0), - .S(1'b0) -); -ODDR2 #( - .DDR_ALIGNMENT("NONE"), - .INIT(1'b0), - .SRTYPE("SYNC") -) sd_clk_forward_n ( - .Q(ddr_clk_pad_n), - .C0(clk2x_off), - .C1(~clk2x_off), - .CE(1'b1), - .D0(1'b0), - .D1(1'b1), - .R(1'b0), - .S(1'b0) -); - -/* - * Ethernet PHY - */ - -always @(posedge clk50g) - eth_phy_clk_pad <= ~eth_phy_clk_pad; - -/* Let the synthesizer insert the appropriate buffers */ -assign eth_rx_clk = eth_rx_clk_pad; -assign eth_tx_clk = eth_tx_clk_pad; - -/* - * VGA clock - */ - -DCM_CLKGEN #( - .CLKFXDV_DIVIDE(2), - .CLKFX_DIVIDE(4), - .CLKFX_MD_MAX(3.0), - .CLKFX_MULTIPLY(2), - .CLKIN_PERIOD(20.0), - .SPREAD_SPECTRUM("NONE"), - .STARTUP_WAIT("FALSE") -) vga_clock_gen ( - .CLKFX(vga_clk), - .CLKFX180(), - .CLKFXDV(), - .STATUS(), - .CLKIN(clk50g), - .FREEZEDCM(1'b0), - .PROGCLK(vga_progclk), - .PROGDATA(vga_progdata), - .PROGEN(vga_progen), - .PROGDONE(vga_progdone), - .LOCKED(vga_locked), - .RST(~pll_lckd | sys_rst) -); - -ODDR2 #( - .DDR_ALIGNMENT("NONE"), - .INIT(1'b0), - .SRTYPE("SYNC") -) vga_clock_forward ( - .Q(vga_clk_pad), - .C0(vga_clk), - .C1(~vga_clk), - .CE(1'b1), - .D0(1'b1), - .D1(1'b0), - .R(1'b0), - .S(1'b0) -); - -endmodule diff --git a/verilog/mxcrg/mxcrg.v b/verilog/mxcrg/mxcrg.v new file mode 100644 index 00000000..a7dee56a --- /dev/null +++ b/verilog/mxcrg/mxcrg.v @@ -0,0 +1,315 @@ +module mxcrg #( + parameter in_period = 0.0, + parameter f_mult = 0, + parameter f_div = 0, + parameter clk2x_period = (in_period*f_div)/(2.0*f_mult) +) ( + input clk50_pad, + input trigger_reset, + + output sys_clk, + output reg sys_rst, + + /* Reset NOR flash */ + output norflash_rst_n, + + /* DDR PHY clocks */ + output clk2x_270, + output clk4x_wr, + output clk4x_wr_strb, + output clk4x_rd, + output clk4x_rd_strb, + + /* DDR off-chip clocking */ + output ddr_clk_pad_p, + output ddr_clk_pad_n, + + /* Ethernet PHY clocks */ + output reg eth_phy_clk_pad, + input eth_rx_clk_pad, + input eth_tx_clk_pad, + output eth_rx_clk, + output eth_tx_clk, + + /* VGA clock */ + output vga_clk, /* < buffered, to internal clock network */ + output vga_clk_pad, /* < forwarded through ODDR2, to I/O */ + + /* VGA clock control */ + input vga_progclk, + input vga_progdata, + input vga_progen, + output vga_progdone, + output vga_locked +); + +/* + * Reset + */ + +reg [19:0] rst_debounce; +always @(posedge sys_clk) begin + if(trigger_reset) + rst_debounce <= 20'hFFFFF; + else if(rst_debounce != 20'd0) + rst_debounce <= rst_debounce - 20'd1; + sys_rst <= rst_debounce != 20'd0; +end + +initial rst_debounce <= 20'hFFFFF; + +/* + * We must release the Flash reset before the system reset + * because the Flash needs some time to come out of reset + * and the CPU begins fetching instructions from it + * as soon as the system reset is released. + * From datasheet, minimum reset pulse width is 100ns + * and reset-to-read time is 150ns. + */ + +reg [7:0] flash_rstcounter; + +always @(posedge sys_clk) begin + if(trigger_reset) + flash_rstcounter <= 8'd0; + else if(~flash_rstcounter[7]) + flash_rstcounter <= flash_rstcounter + 8'd1; +end + +initial flash_rstcounter <= 8'd0; + +assign norflash_rst_n = flash_rstcounter[7]; + +/* + * Clock management. Inspired by the NWL reference design. + */ + +wire sdr_clk50; +wire clkdiv; + +IBUF #( + .IOSTANDARD("DEFAULT") +) clk2_iob ( + .I(clk50_pad), + .O(sdr_clk50) +); + +BUFIO2 #( + .DIVIDE(1), + .DIVIDE_BYPASS("FALSE"), + .I_INVERT("FALSE") +) bufio2_inst2 ( + .I(sdr_clk50), + .IOCLK(), + .DIVCLK(clkdiv), + .SERDESSTROBE() +); + +wire pll_lckd; +wire buf_pll_fb_out; +wire pllout0; +wire pllout1; +wire pllout2; +wire pllout3; +wire pllout4; +wire pllout5; + +PLL_ADV #( + .BANDWIDTH("OPTIMIZED"), + .CLKFBOUT_MULT(4*f_mult), + .CLKFBOUT_PHASE(0.0), + .CLKIN1_PERIOD(in_period), + .CLKIN2_PERIOD(in_period), + + .CLKOUT0_DIVIDE(f_div), + .CLKOUT0_DUTY_CYCLE(0.5), + .CLKOUT0_PHASE(0.0), + + .CLKOUT1_DIVIDE(f_div), + .CLKOUT1_DUTY_CYCLE(0.5), + .CLKOUT1_PHASE(0.0), + + .CLKOUT2_DIVIDE(2*f_div), + .CLKOUT2_DUTY_CYCLE(0.5), + .CLKOUT2_PHASE(270.0), + + .CLKOUT3_DIVIDE(4*f_div), + .CLKOUT3_DUTY_CYCLE(0.5), + .CLKOUT3_PHASE(0.0), + + .CLKOUT4_DIVIDE(4*f_mult), + .CLKOUT4_DUTY_CYCLE(0.5), + .CLKOUT4_PHASE(0.0), + + .CLKOUT5_DIVIDE(2*f_div), + .CLKOUT5_DUTY_CYCLE(0.5), + .CLKOUT5_PHASE(250.0), + + .COMPENSATION("INTERNAL"), + .DIVCLK_DIVIDE(1), + .REF_JITTER(0.100), + .CLK_FEEDBACK("CLKFBOUT"), + .SIM_DEVICE("SPARTAN6") +) pll ( + .CLKFBDCM(), + .CLKFBOUT(buf_pll_fb_out), + .CLKOUT0(pllout0), /* < x4 clock for writes */ + .CLKOUT1(pllout1), /* < x4 clock for reads */ + .CLKOUT2(pllout2), /* < x2 270 clock for DQS, memory address and control signals */ + .CLKOUT3(pllout3), /* < x1 clock for system and memory controller */ + .CLKOUT4(pllout4), /* < buffered clk50 */ + .CLKOUT5(pllout5), /* < x2 clock to off-chip DDR */ + .CLKOUTDCM0(), + .CLKOUTDCM1(), + .CLKOUTDCM2(), + .CLKOUTDCM3(), + .CLKOUTDCM4(), + .CLKOUTDCM5(), + .DO(), + .DRDY(), + .LOCKED(pll_lckd), + .CLKFBIN(buf_pll_fb_out), + .CLKIN1(clkdiv), + .CLKIN2(1'b0), + .CLKINSEL(1'b1), + .DADDR(5'b00000), + .DCLK(1'b0), + .DEN(1'b0), + .DI(16'h0000), + .DWE(1'b0), + .RST(1'b0), + .REL(1'b0) +); + +BUFPLL #( + .DIVIDE(4) +) wr_bufpll ( + .PLLIN(pllout0), + .GCLK(sys_clk), + .LOCKED(pll_lckd), + .IOCLK(clk4x_wr), + .LOCK(), + .SERDESSTROBE(clk4x_wr_strb) +); + +BUFPLL #( + .DIVIDE(4) +) rd_bufpll ( + .PLLIN(pllout1), + .GCLK(sys_clk), + .LOCKED(pll_lckd), + .IOCLK(clk4x_rd), + .LOCK(), + .SERDESSTROBE(clk4x_rd_strb) +); + +BUFG bufg_x2_2( + .I(pllout2), + .O(clk2x_270) +); + +BUFG bufg_x1( + .I(pllout3), + .O(sys_clk) +); + +wire clk50g; +BUFG bufg_50( + .I(pllout4), + .O(clk50g) +); + +wire clk2x_off; +BUFG bufg_x2_offclk( + .I(pllout5), + .O(clk2x_off) +); + + +/* + * SDRAM clock + */ + +ODDR2 #( + .DDR_ALIGNMENT("NONE"), + .INIT(1'b0), + .SRTYPE("SYNC") +) sd_clk_forward_p ( + .Q(ddr_clk_pad_p), + .C0(clk2x_off), + .C1(~clk2x_off), + .CE(1'b1), + .D0(1'b1), + .D1(1'b0), + .R(1'b0), + .S(1'b0) +); +ODDR2 #( + .DDR_ALIGNMENT("NONE"), + .INIT(1'b0), + .SRTYPE("SYNC") +) sd_clk_forward_n ( + .Q(ddr_clk_pad_n), + .C0(clk2x_off), + .C1(~clk2x_off), + .CE(1'b1), + .D0(1'b0), + .D1(1'b1), + .R(1'b0), + .S(1'b0) +); + +/* + * Ethernet PHY + */ + +always @(posedge clk50g) + eth_phy_clk_pad <= ~eth_phy_clk_pad; + +/* Let the synthesizer insert the appropriate buffers */ +assign eth_rx_clk = eth_rx_clk_pad; +assign eth_tx_clk = eth_tx_clk_pad; + +/* + * VGA clock + */ + +DCM_CLKGEN #( + .CLKFXDV_DIVIDE(2), + .CLKFX_DIVIDE(4), + .CLKFX_MD_MAX(3.0), + .CLKFX_MULTIPLY(2), + .CLKIN_PERIOD(20.0), + .SPREAD_SPECTRUM("NONE"), + .STARTUP_WAIT("FALSE") +) vga_clock_gen ( + .CLKFX(vga_clk), + .CLKFX180(), + .CLKFXDV(), + .STATUS(), + .CLKIN(clk50g), + .FREEZEDCM(1'b0), + .PROGCLK(vga_progclk), + .PROGDATA(vga_progdata), + .PROGEN(vga_progen), + .PROGDONE(vga_progdone), + .LOCKED(vga_locked), + .RST(~pll_lckd | sys_rst) +); + +ODDR2 #( + .DDR_ALIGNMENT("NONE"), + .INIT(1'b0), + .SRTYPE("SYNC") +) vga_clock_forward ( + .Q(vga_clk_pad), + .C0(vga_clk), + .C1(~vga_clk), + .CE(1'b1), + .D0(1'b1), + .D1(1'b0), + .R(1'b0), + .S(1'b0) +); + +endmodule