|
| 1 | +#!/usr/bin/env python3 |
| 2 | +# |
| 3 | +# Copyright (c) 2021 Hans Baier <[email protected]> |
| 4 | +# SPDX-License-Identifier: CERN-OHL-W-2.0 |
| 5 | +import os |
| 6 | +import code |
| 7 | + |
| 8 | +from amaranth import * |
| 9 | +from amaranth.lib.fifo import SyncFIFOBuffered |
| 10 | +from amaranth.lib.cdc import ResetSynchronizer |
| 11 | +from amaranth.build import * |
| 12 | + |
| 13 | +from amaranth_boards.resources import * |
| 14 | +from amaranth_boards.hpc_xc7k420t import HPCStoreXC7K420TPlatform |
| 15 | + |
| 16 | +from amlib.debug.ila import StreamILA, ILACoreParameters |
| 17 | +from amlib.stream import connect_stream_to_fifo, connect_fifo_to_stream |
| 18 | + |
| 19 | +from fractalmanager import FractalManager |
| 20 | + |
| 21 | +from hspi import HSPITransmitter, HSPIReceiver |
| 22 | + |
| 23 | +odd_pins = list(range(1, 75, 2)) |
| 24 | +even_pins = list(range(2, 76, 2)) |
| 25 | + |
| 26 | +GND = None |
| 27 | +btb_odd = [GND, None, None, |
| 28 | + GND, "HD12", "HD13", "HD14", "HD15", |
| 29 | + GND, "HD16", "HD17", "HD18", "HD19", |
| 30 | + GND, "HD20", "HD21", "HD22", "HD23", |
| 31 | + GND, "HD24", "HD25", "HD26", "HD27", |
| 32 | + GND, "HD28", "HD29", "HD30", "HD31", |
| 33 | + GND, "LED1", "LED2"] |
| 34 | + |
| 35 | +btb_even = [GND, "HD10", "HD11", |
| 36 | + GND, "HRCLK", "HRACT", "HRVLD", "HTRDY", |
| 37 | + GND, "HD0", "HD1", "HD2", "HD3", |
| 38 | + GND, "HD4", "HD5", "HD6", "HD7", |
| 39 | + GND, "HD8", "HD9", "HTVLD", "HTREQ", |
| 40 | + GND, "HTACK", "HTCLK"] |
| 41 | + |
| 42 | +even = list(zip(btb_even, even_pins)) |
| 43 | +odd = list(zip(btb_odd, odd_pins)) |
| 44 | + |
| 45 | +pinmap = dict(filter(lambda t: t[0] != None, even + odd)) |
| 46 | +hd_pins = " ".join([f"BTB_0:{pinmap[pin]}" for pin in [f"HD{i}" for i in range(0, 32)]]) |
| 47 | +control_pin = lambda pin: "BTB_0:" + str(pinmap[pin]) |
| 48 | + |
| 49 | +#code.interact(local=locals()) |
| 50 | + |
| 51 | +class KintexMandelbrotPlatform(HPCStoreXC7K420TPlatform): |
| 52 | + def __init__(self, io_voltage="3.3V", toolchain="Vivado"): |
| 53 | + self.resources += [ |
| 54 | + # HSPI |
| 55 | + Resource("hspi", 0, |
| 56 | + Subsignal("hd", Pins(hd_pins, dir="io")), |
| 57 | + |
| 58 | + Subsignal("tx_ack", Pins(control_pin('HTRDY'), dir="o")), |
| 59 | + Subsignal("tx_ready", Pins(control_pin('HTACK'), dir="i")), |
| 60 | + |
| 61 | + Subsignal("tx_req", Pins(control_pin('HRACT'), dir="o")), |
| 62 | + Subsignal("rx_act", Pins(control_pin('HTREQ'), dir="i")), |
| 63 | + |
| 64 | + Subsignal("tx_valid", Pins(control_pin('HRVLD'), dir="o")), |
| 65 | + Subsignal("rx_valid", Pins(control_pin('HTVLD'), dir="i")), |
| 66 | + Attrs(IOSTANDARD="LVCMOS33") |
| 67 | + ), |
| 68 | + Resource("hspi-clocks", 0, |
| 69 | + Subsignal("tx_clk", Pins(control_pin('HRCLK'), dir="o")), |
| 70 | + Subsignal("rx_clk", Pins(control_pin('HTCLK'), dir="i")), |
| 71 | + Attrs(IOSTANDARD="LVCMOS33") |
| 72 | + ), |
| 73 | + ] |
| 74 | + super().__init__(io_voltage, toolchain) |
| 75 | + |
| 76 | + @property |
| 77 | + def file_templates(self): |
| 78 | + templates = super().file_templates |
| 79 | + templates["{{name}}.xdc"] += "\nset_property CLOCK_DEDICATED_ROUTE FALSE [get_nets pin_hspi-clocks_0__rx_clk/crg_hspi-clocks_0__rx_clk__i]" |
| 80 | + return templates |
| 81 | + |
| 82 | +class Xilinx7SeriesClockDomainGenerator(Elaboratable): |
| 83 | + DUTY_CYCLE = 0.5 |
| 84 | + NO_PHASE_SHIFT = 0 |
| 85 | + |
| 86 | + def wire_up_reset(self, m, reset): |
| 87 | + m.submodules.reset_sync_sync = ResetSynchronizer(reset, domain="sync") |
| 88 | + m.submodules.reset_sync_hspi = ResetSynchronizer(reset, domain="hspi") |
| 89 | + |
| 90 | + def __init__(self): |
| 91 | + pass |
| 92 | + |
| 93 | + def elaborate(self, platform): |
| 94 | + m = Module() |
| 95 | + |
| 96 | + # Create our domains |
| 97 | + m.domains.sync = ClockDomain("sync") |
| 98 | + m.domains.hspi = ClockDomain("hspi") |
| 99 | + |
| 100 | + clk = platform.request(platform.default_clk) |
| 101 | + |
| 102 | + hspi_clocks = platform.request("hspi-clocks", 0) |
| 103 | + main_clock = Signal() |
| 104 | + main_locked = Signal() |
| 105 | + hspi_clock = Signal() |
| 106 | + hspi_locked = Signal() |
| 107 | + reset = Signal() |
| 108 | + |
| 109 | + mainpll_feedback = Signal() |
| 110 | + hspipll_feedback = Signal() |
| 111 | + |
| 112 | + mainpll_led = platform.request("led", 0) |
| 113 | + hspipll_led = platform.request("led", 1) |
| 114 | + pol_led = platform.request("led", 2) |
| 115 | + |
| 116 | + m.submodules.mainpll = Instance("PLLE2_ADV", |
| 117 | + p_CLKIN1_PERIOD = 10, |
| 118 | + p_BANDWIDTH = "OPTIMIZED", |
| 119 | + p_COMPENSATION = "ZHOLD", |
| 120 | + p_STARTUP_WAIT = "FALSE", |
| 121 | + |
| 122 | + p_DIVCLK_DIVIDE = 1, |
| 123 | + p_CLKFBOUT_MULT = 12, |
| 124 | + p_CLKFBOUT_PHASE = self.NO_PHASE_SHIFT, |
| 125 | + |
| 126 | + # 100MHz |
| 127 | + p_CLKOUT0_DIVIDE = 12, |
| 128 | + p_CLKOUT0_PHASE = self.NO_PHASE_SHIFT, |
| 129 | + p_CLKOUT0_DUTY_CYCLE = self.DUTY_CYCLE, |
| 130 | + |
| 131 | + i_CLKFBIN = mainpll_feedback, |
| 132 | + o_CLKFBOUT = mainpll_feedback, |
| 133 | + i_CLKIN1 = clk, |
| 134 | + o_CLKOUT0 = main_clock, |
| 135 | + o_LOCKED = main_locked, |
| 136 | + ) |
| 137 | + |
| 138 | + m.submodules.hspipll = Instance("PLLE2_ADV", |
| 139 | + p_CLKIN1_PERIOD = 10.416666666, # 96MHz |
| 140 | + p_BANDWIDTH = "OPTIMIZED", |
| 141 | + p_COMPENSATION = "ZHOLD", |
| 142 | + p_STARTUP_WAIT = "FALSE", |
| 143 | + |
| 144 | + p_DIVCLK_DIVIDE = 1, |
| 145 | + p_CLKFBOUT_MULT = 12, |
| 146 | + p_CLKFBOUT_PHASE = self.NO_PHASE_SHIFT, |
| 147 | + |
| 148 | + # 96MHz |
| 149 | + p_CLKOUT0_DIVIDE = 12, |
| 150 | + p_CLKOUT0_PHASE = self.NO_PHASE_SHIFT, |
| 151 | + p_CLKOUT0_DUTY_CYCLE = self.DUTY_CYCLE, |
| 152 | + |
| 153 | + i_CLKFBIN = hspipll_feedback, |
| 154 | + o_CLKFBOUT = hspipll_feedback, |
| 155 | + i_CLKIN1 = hspi_clocks.rx_clk, |
| 156 | + o_CLKOUT0 = hspi_clock, |
| 157 | + o_LOCKED = hspi_locked, |
| 158 | + ) |
| 159 | + |
| 160 | + m.d.comb += [ |
| 161 | + reset.eq(~(main_locked & hspi_locked)), |
| 162 | + ClockSignal("sync").eq(main_clock), |
| 163 | + ClockSignal("hspi").eq(hspi_clock), |
| 164 | + mainpll_led.eq(main_locked), |
| 165 | + hspipll_led.eq(hspi_locked), |
| 166 | + pol_led.eq(0), |
| 167 | + ] |
| 168 | + |
| 169 | + self.wire_up_reset(m, reset) |
| 170 | + |
| 171 | + return m |
| 172 | + |
| 173 | +class MandelbrotAccelerator(Elaboratable): |
| 174 | + def elaborate(self, platform): |
| 175 | + m = Module() |
| 176 | + m.submodules.crg = Xilinx7SeriesClockDomainGenerator() |
| 177 | + |
| 178 | + hspi_pads = platform.request("hspi", 0) |
| 179 | + |
| 180 | + m.submodules.hspi_tx = hspi_tx = HSPITransmitter(domain="hspi") |
| 181 | + m.submodules.hspi_rx = hspi_rx = HSPIReceiver(domain="hspi") |
| 182 | + m.submodules.output_fifo = output_fifo = DomainRenamer("hspi")(SyncFIFOBuffered(width=34, depth=4096)) |
| 183 | + |
| 184 | + m.d.comb += [ |
| 185 | + ## connect HSPI receiver |
| 186 | + *hspi_rx.connect_to_pads(hspi_pads), |
| 187 | + |
| 188 | + ## connect HSPI transmitter |
| 189 | + hspi_tx.user_id0_in.eq(0x3ABCDEF), |
| 190 | + hspi_tx.user_id1_in.eq(0x3456789), |
| 191 | + hspi_tx.tll_2b_in.eq(0b11), |
| 192 | + hspi_tx.sequence_nr_in.eq(hspi_rx.sequence_nr_out), |
| 193 | + |
| 194 | + *hspi_tx.connect_to_pads(hspi_pads), |
| 195 | + hspi_tx.send_ack.eq(0), |
| 196 | + |
| 197 | + *connect_stream_to_fifo(hspi_rx.stream_out, output_fifo, firstBit=-2, lastBit=-1), |
| 198 | + *connect_fifo_to_stream(output_fifo, hspi_tx.stream_in, firstBit=-2, lastBit=-1), |
| 199 | + ] |
| 200 | + |
| 201 | + return m |
| 202 | + |
| 203 | +if __name__ == "__main__": |
| 204 | + top = MandelbrotAccelerator() |
| 205 | + KintexMandelbrotPlatform(toolchain="Vivado").build(top, do_program=False) |
0 commit comments