diff --git a/build/Makefile b/build/Makefile index 1197ca7..12272e0 100644 --- a/build/Makefile +++ b/build/Makefile @@ -49,7 +49,6 @@ hardware-get: docker cp upsilon-hardware:/home/user/upsilon/gateware/arty.dtb ../boot/ docker cp upsilon-hardware:/home/user/upsilon/gateware/mmio.py ../boot/ docker cp upsilon-hardware:/home/user/upsilon/gateware/csr.json ../boot/ - docker cp upsilon-hardware:/home/user/upsilon/gateware/csr_bitwidth.json ../boot/ hardware-clean: -docker container stop upsilon-hardware -docker container rm upsilon-hardware diff --git a/gateware/csr2mp.py b/gateware/csr2mp.py index 9f9e86e..5613566 100644 --- a/gateware/csr2mp.py +++ b/gateware/csr2mp.py @@ -15,59 +15,23 @@ import collections import argparse import json import sys - -class MMIORegister: - def __init__(self, name, read_only=False, number=1, exntype=None): - """ - Describes a MMIO register. - :param name: The name of the MMIO register, excluding the prefix - defining its module (i.e. ``base_``) and excluding its - numerical suffix. - :param read_only: True if the register is read only. Defaults to - ``False``. - :param number: The number of MMIO registers with the same name - and number suffixes. The number suffixes must go from 0 - to ``number - 1`` with no gaps. - """ - self.name = name - self.read_only = read_only - self.number = number - self.exntype = exntype - - # These are filled in by the CSR file. - self.size = None - -def mmio_factory(num, exntype): - """ - Return a function that simplifies the creation of instances of - :py:class:`MMIORegister` with the same number and exception type. - - :param num: Number of registers with the same name (minus suffix). - :param exntype: MicroPython exception type. - :return: A function ``f(name, read_only=False)``. Each argument is - the same as the one in the initializer of py:class:`MMIORegister`. - """ - def f(name, read_only=False): - return MMIORegister(name, read_only, number=num, exntype=exntype) - return f +import mmio_descr class CSRHandler: """ Class that wraps the CSR file and fills in registers with information from those files. """ - def __init__(self, csrjson, bitwidthjson, registers): + def __init__(self, csrjson, registers): """ Reads in the CSR files. :param csrjson: Filename of a LiteX "csr.json" file. - :param bitwidthjson: Filename of an Upsilon "bitwidthjson" file. - :param registers: A list of :py:class:`MMIORegister`s. + :param registers: A list of ``mmio_descr`` ``Descr``s. :param outf: Output file. """ self.registers = registers self.csrs = json.load(open(csrjson)) - self.bws = json.load(open(bitwidthjson)) def update_reg(self, reg): """ @@ -76,17 +40,19 @@ class CSRHandler: :param reg: The register. :raises Exception: When the bit width exceeds 64. """ - b = self.bws[reg.name] + regsize = None + b = reg.blen if b <= 8: - reg.size = 8 + regsize = 8 elif b <= 16: - reg.size = 16 + regsize = 16 elif b <= 32: - reg.size = 32 + regsize = 32 elif b <= 64: - reg.size = 64 + regsize = 64 else: raise Exception(f"unsupported width {b} in {reg.name}") + setattr(reg, "regsize", regsize) def get_reg_addr(self, reg, num=None): """ @@ -135,7 +101,7 @@ class InterfaceGenerator: self.print(self.header()) for r in self.csr.registers: self.print(self.fun(r, "read")) - if not r.read_only: + if not r.rwperm != "read-only": self.print(self.fun(r, "write")) class MicropythonGenerator(InterfaceGenerator): @@ -144,9 +110,9 @@ class MicropythonGenerator(InterfaceGenerator): def get_accessor(self, reg, num): addr = self.csr.get_reg_addr(reg, num) - if reg.size in [8, 16, 32]: - return [f"machine.mem{reg.size}[{addr}]"] - return [f"machine.mem32[{addr}]", f"machine.mem32[{addr + 4}]"] + if reg.regsize in [8, 16, 32]: + return [f"machine.mem{reg.regsize}[{addr}]"] + return [f"machine.mem32[{addr + 4}]", f"machine.mem32[{addr}]"] def print_write_register(self, indent, varname, reg, num): acc = self.get_accessor(reg, num) @@ -181,16 +147,16 @@ class MicropythonGenerator(InterfaceGenerator): else: pfun = self.print_read_register - if reg.number != 1: + if reg.num != 1: if printed_argument: a(', ') a('num') a('):\n') - if reg.number == 1: + if reg.num == 1: a(pfun('\t', 'val', reg, None)) else: - for i in range(0,reg.number): + for i in range(0,reg.num): if i == 0: a(f'\tif ') else: @@ -198,46 +164,16 @@ class MicropythonGenerator(InterfaceGenerator): a(f'num == {i}:\n') a(pfun('\t\t', 'val', reg, i)) a(f'\telse:\n') - a(f'\t\traise {r.exntype}(regnum)\n') + a(f'\t\traise Exception(regnum)\n') a('\n') return rs def header(self): - return """import machine -class InvalidDACException(Exception): - pass -class InvalidADCException(Exception): - pass -""" + return "import machine\n" if __name__ == "__main__": - dac_num = 8 - adc_num = 8 - dac_reg = mmio_factory(dac_num, "InvalidDACException") - adc_reg = mmio_factory(adc_num, "InvalidADCException") - - registers = [ - dac_reg("dac_sel"), - dac_reg("dac_finished", read_only=True), - dac_reg("dac_arm"), - dac_reg("dac_recv_buf", read_only=True), - dac_reg("dac_send_buf"), - - adc_reg("adc_finished", read_only=True), - adc_reg("adc_arm"), - adc_reg("adc_recv_buf", read_only=True), - adc_reg("adc_sel"), - - MMIORegister("cl_in_loop", read_only=True), - MMIORegister("cl_cmd"), - MMIORegister("cl_word_in"), - MMIORegister("cl_word_out", read_only=True), - MMIORegister("cl_start_cmd"), - MMIORegister("cl_finish_cmd", read_only=True), - MMIORegister("cl_z_report", read_only=True), - ] - csrh = CSRHandler(sys.argv[1], sys.argv[2], registers) - for r in registers: + csrh = CSRHandler(sys.argv[1], mmio_descr.registers) + for r in mmio_descr.registers: csrh.update_reg(r) MicropythonGenerator(csrh, sys.stdout).print_file() diff --git a/gateware/mmio_descr.py b/gateware/mmio_descr.py index 9c4a69f..e8635c7 100644 --- a/gateware/mmio_descr.py +++ b/gateware/mmio_descr.py @@ -11,15 +11,15 @@ class Descr: """ self.name = name self.blen = blen - self.doc = textwrap.deindent(descr) + self.doc = textwrap.dedent(descr) self.num =num - self.read_only = read_only == "read-only" + self.rwperm = rwperm @classmethod def from_dict(cls, jsdict, name): return cls(name, jsdict[name]["len"], jsdict[name]["ro"], jsdict[name]["num"], jsdict[name]["doc"]) def store_to_dict(self, d): - d[self.name = { + d[self.name] = { "len": self.blen, "doc": self.doc, "num": self.num, @@ -27,7 +27,7 @@ class Descr: } registers = [ - Descr("adc_sel", 3, "read-write", """\ + Descr("adc_sel", 3, "read-write", 8, """\ Select which on-FPGA SPI master controls the ADC. Valid settings: @@ -36,7 +36,7 @@ registers = [ * ``0b10``: ADC is controlled by MMIO registers, but conversion is disabled. This is used to flush output from an out-of-sync ADC. * ``0b100``: ADC 0 only. ADC is controlled by control loop."""), - Descr("adc_finished", "read-only", """\ + Descr("adc_finished", 1, "read-only", 8, """\ Signals that an ADC master has finished an SPI cycle. Values: @@ -47,9 +47,8 @@ registers = [ This flag is on only when ``adc_arm`` is high. The flag does not mean that data has been received successfully, only that the master - has finished it's SPI transfer. - """), - Descr("adc_arm", "read-write", """\ + has finished it's SPI transfer."""), + Descr("adc_arm", 1, "read-write", 8, """\ Start a DAC master SPI transfer. If ``adc_arm`` is raised from and the master is currently not in a SPI @@ -84,7 +83,7 @@ registers = [ If ``adc_sel`` is not set to 0 then the transfer will proceed as normal, but no data will be received from the ADC."""), - Descr("adc_recv_buf", "read-only", """\ + Descr("adc_recv_buf", 18, "read-only", 8, """\ ADC Master receive buffer. This buffer is stable if there is no ADC transfer caused by ``adc_arm`` @@ -94,14 +93,14 @@ registers = [ registers. SPI transfers by other masters will not affect this register. buffer."""), - Descr("dac_sel", 2, "read-write", """\ + Descr("dac_sel", 2, "read-write", 8, """\ Select which on-FPGA SPI master controls the DAC. Valid settings: * ``0``: DAC is controlled by MMIO registers. * ``0b10``: DAC 0 only. DAC is controlled by control loop."""), - Descr("dac_finished", 1, "read-only", """\ + Descr("dac_finished", 1, "read-only", 8, """\ Signals that the DAC master has finished transmitting data. Values: @@ -113,7 +112,7 @@ registers = [ This flag is on only when ``dac_arm`` is high. The flag does not mean that data has been received or transmitted successfully, only that the master has finished it's SPI transfer."""), - Descr("dac_arm", 1, "read-write", """\ + Descr("dac_arm", 1, "read-write", 8, """\ Start a DAC master SPI transfer. If ``dac_arm`` is raised from and the master is currently not in a SPI @@ -138,7 +137,7 @@ registers = [ If ``dac_sel`` is set to another master then the transfer will proceed as normal, but no data will be sent to or received from the DAC."""), - Descr("dac_recv_buf", 24, "read-only", """\ + Descr("dac_recv_buf", 24, "read-only", 8, """\ DAC master receive buffer. This buffer is stable if there is no DAC transfer caused by ``dac_arm`` @@ -147,7 +146,7 @@ registers = [ This register only changes if an SPI transfer is triggered by the MMIO registers. SPI transfers by other masters will not affect this register. buffer."""), - Descr("dac_send_buf, 24, "read-write", """\ + Descr("dac_send_buf", 24, "read-write", 8, """\ DAC master send buffer. Fill this buffer with a 24 bit Analog Devices DAC command. Updating @@ -158,7 +157,7 @@ registers = [ Modifying this buffer during a transfer does not disrupt an in-process transfer."""), - Descr("cl_assert_change", 1, "read-write", """\ + Descr("cl_assert_change", 1, "read-write", 1, """\ Flush parameter changes to control loop. When this bit is raised from low to high, this signals the control @@ -168,21 +167,23 @@ registers = [ When this bit is raised from high to low before ``cl_change_made`` is asserted by the control loop, nothing happens."""), - Descr("cl_change_made", 1, "read-only", """\ + Descr("cl_change_made", 1, "read-only", 1, """\ Signal from the control loop that the parameters have been applied. This signal goes high only while ``cl_assert_change`` is high. No change will be applied afterwards while both are high."""), - Descr("cl_in_loop_in", 1, "read-only", """\ + Descr("cl_in_loop", 1, "read-only", 1, """\ This bit is high if the control loop is running."""), - Descr("cl_setpt_in", 18, "read-write", """\ + Descr("cl_run_loop_in", 1, "read-write", 1, """\ + Set this bit high to start the control loop."""), + Descr("cl_setpt_in", 18, "read-write", 1, """\ Setpoint of the control loop. This is a twos-complement number in ADC units. This is a parameter: see ``cl_assert_change``."""), - Descr("cl_P_in", 64, "read-write", """\ + Descr("cl_P_in", 64, "read-write", 1, """\ Proportional parameter of the control loop. This is a twos-complement fixed point number with 21 whole @@ -190,7 +191,7 @@ registers = [ in DAC units. This is a parameter: see ``cl_assert_change``."""), - Descr("cl_I_in", 64, "read-write", """\ + Descr("cl_I_in", 64, "read-write", 1, """\ Integral parameter of the control loop. This is a twos-complement fixed point number with 21 whole @@ -198,7 +199,7 @@ registers = [ in DAC units. This is a parameter: see ``cl_assert_change``."""), - Descr("cl_delay_in", 16, "read-write", """\ + Descr("cl_delay_in", 16, "read-write", 1, """\ Delay parameter of the loop. This is an unsigned number denoting the number of cycles @@ -206,15 +207,15 @@ registers = [ This is a parameter: see ``cl_assert_change``."""), - Descr("cl_cycle_count", 18, "read-only", """\ + Descr("cl_cycle_count", 18, "read-only", 1, """\ Delay parameter of the loop. This is an unsigned number denoting the number of cycles the loop should wait between loop executions."""), - Descr("cl_z_pos", 20, "read-only", """\ + Descr("cl_z_pos", 20, "read-only", 1, """\ Control loop DAC Z position. """), - Descr("cl_z_measured", 18, "read-only", """\ + Descr("cl_z_measured", 18, "read-only", 1, """\ Control loop ADC Z position. """), ] diff --git a/gateware/rtl/base/base.v.m4 b/gateware/rtl/base/base.v.m4 index aed5053..2c328f4 100644 --- a/gateware/rtl/base/base.v.m4 +++ b/gateware/rtl/base/base.v.m4 @@ -292,6 +292,7 @@ m4_define(CL_DATA_WID, CL_CONSTS_WID) input cl_assert_change, output cl_change_made, + output cl_in_loop, input cl_run_loop_in, input [ADC_TYPE1_WID-1:0] cl_setpt_in, @@ -299,9 +300,9 @@ m4_define(CL_DATA_WID, CL_CONSTS_WID) input [CL_DATA_WID-1:0] cl_I_in, input [CL_DELAY_WID-1:0] cl_delay_in, - output [CYCLE_COUNT_WID-1:0] cl_cycle_count, + output [CL_CYCLE_COUNT_WID-1:0] cl_cycle_count, output [DAC_DATA_WID-1:0] cl_z_pos, - output [ADC_WID-1:0] cl_z_measured + output [ADC_TYPE1_WID-1:0] cl_z_measured ); assign set_low = 0; diff --git a/gateware/soc.py b/gateware/soc.py index 132c43f..a942342 100644 --- a/gateware/soc.py +++ b/gateware/soc.py @@ -87,80 +87,80 @@ If there is more than one pin in the Pins string, the resulting name will be a vector of pins. """ io = [ - ("differntial_output_low", 0, Pins("J17 J18 K15 J15 U14 V14 T13 U13 B6 E5 A3"), IOStandard("LVCMOS33")), - ("dac_ss_L", 0, Pins("G13 D13 E15 F5 U12 D7 D4 E2"), IOStandard("LVCMOS33")), - ("dac_mosi", 0, Pins("B11 B18 E16 D8 V12 D5 D3 D2"), IOStandard("LVCMOS33")), - ("dac_miso", 0, Pins("A11 A18 D15 C7 V10 B7 F4 H2"), IOStandard("LVCMOS33")), - ("dac_sck", 0, Pins("D12 K16 C15 E7 V11 E6 F3 G2"), IOStandard("LVCMOS33")), - ("adc_conv", 0, Pins("V15 T11 N15 U18 U11 R10 R16 U17"), IOStandard("LVCMOS33")), - ("adc_sck", 0, Pins("U16 R12 M16 R17 V16 R11 N16 T18"), IOStandard("LVCMOS33")), - ("adc_sdo", 0, Pins("P14 T14 V17 P17 M13 R13 N14 R18"), IOStandard("LVCMOS33")), - ("module_reset", 0, Pins("D9"), IOStandard("LVCMOS33")), - ("test_clock", 0, Pins("P18"), IOStandard("LVCMOS33")) + ("differntial_output_low", 0, Pins("J17 J18 K15 J15 U14 V14 T13 U13 B6 E5 A3"), IOStandard("LVCMOS33")), + ("dac_ss_L", 0, Pins("G13 D13 E15 F5 U12 D7 D4 E2"), IOStandard("LVCMOS33")), + ("dac_mosi", 0, Pins("B11 B18 E16 D8 V12 D5 D3 D2"), IOStandard("LVCMOS33")), + ("dac_miso", 0, Pins("A11 A18 D15 C7 V10 B7 F4 H2"), IOStandard("LVCMOS33")), + ("dac_sck", 0, Pins("D12 K16 C15 E7 V11 E6 F3 G2"), IOStandard("LVCMOS33")), + ("adc_conv", 0, Pins("V15 T11 N15 U18 U11 R10 R16 U17"), IOStandard("LVCMOS33")), + ("adc_sck", 0, Pins("U16 R12 M16 R17 V16 R11 N16 T18"), IOStandard("LVCMOS33")), + ("adc_sdo", 0, Pins("P14 T14 V17 P17 M13 R13 N14 R18"), IOStandard("LVCMOS33")), + ("module_reset", 0, Pins("D9"), IOStandard("LVCMOS33")), + ("test_clock", 0, Pins("P18"), IOStandard("LVCMOS33")) ] # TODO: Assign widths to ADCs here using parameters class Base(Module, AutoCSR): - """ The subclass AutoCSR will automatically make CSRs related - to this class when those CSRs are attributes (i.e. accessed by - `self.csr_name`) of instances of this class. (CSRs are MMIO, + """ The subclass AutoCSR will automatically make CSRs related + to this class when those CSRs are attributes (i.e. accessed by + `self.csr_name`) of instances of this class. (CSRs are MMIO, they are NOT RISC-V CSRs!) - Since there are a lot of input and output wires, the CSRs are - assigned using `setattr()`. + Since there are a lot of input and output wires, the CSRs are + assigned using `setattr()`. - CSRs are for input wires (`CSRStorage`) or output wires - (`CSRStatus`). The first argument to the CSR constructor is - the amount of bits the CSR takes. The `name` keyword argument - is required since the constructor needs the name of the attribute. - The `description` keyword is used for documentation. + CSRs are for input wires (`CSRStorage`) or output wires + (`CSRStatus`). The first argument to the CSR constructor is + the amount of bits the CSR takes. The `name` keyword argument + is required since the constructor needs the name of the attribute. + The `description` keyword is used for documentation. - In LiteX, modules in separate Verilog files are instantiated as - self.specials += Instance( - "module_name", - PARAMETER_NAME=value, - i_input = input_port, - o_output = output_port, - ... - ) + In LiteX, modules in separate Verilog files are instantiated as + self.specials += Instance( + "module_name", + PARAMETER_NAME=value, + i_input = input_port, + o_output = output_port, + ... + ) - Since the "base" module has a bunch of repeated input and output - pins that have to be connected to CSRs, the LiteX wrapper uses - keyword arguments to pass all the arguments. - """ + Since the "base" module has a bunch of repeated input and output + pins that have to be connected to CSRs, the LiteX wrapper uses + keyword arguments to pass all the arguments. + """ - def _make_csr(self, reg, num=None): - """ Add a CSR for a pin `f"{name}_{num}".` + def _make_csr(self, reg, num=None): + """ Add a CSR for a pin `f"{name}_{num}".` :param name: Name of the MMIO register without prefixes or numerical suffix. :param num: Numerical suffix of this MMIO register. This is the only parameter that should change when adding multiple CSRs of the same name. - """ + """ name = reg.name - if num is not None: - name = f"{name}_{num}" + if num is not None: + name = f"{name}_{num}" - if self.ro == "read-only": + if reg.rwperm == "read-only": csrclass = CSRStatus else: csrclass = CSRStorage - csr = csrclass(reg.blen, name=name, description=None) - setattr(self, name, csr) + csr = csrclass(reg.blen, name=name, description=None) + setattr(self, name, csr) - if csrclass is CSRStorage: - self.kwargs[f'i_{name}'] = csr.storage - elif csrclass is CSRStatus: - self.kwargs[f'o_{name}'] = csr.status - else: - raise Exception(f"Unknown class {csrclass}") + if csrclass is CSRStorage: + self.kwargs[f'i_{name}'] = csr.storage + elif csrclass is CSRStatus: + self.kwargs[f'o_{name}'] = csr.status + else: + raise Exception(f"Unknown class {csrclass}") - def __init__(self, clk, sdram, platform): - self.kwargs = {} + def __init__(self, clk, sdram, platform): + self.kwargs = {} for reg in mmio_descr.registers: if reg.num > 1: @@ -169,133 +169,133 @@ class Base(Module, AutoCSR): else: self._make_csr(reg) - self.kwargs["i_clk"] = clk - self.kwargs["i_rst_L"] = ~platform.request("module_reset") - self.kwargs["i_dac_miso"] = platform.request("dac_miso") - self.kwargs["o_dac_mosi"] = platform.request("dac_mosi") - self.kwargs["o_dac_sck"] = platform.request("dac_sck") - self.kwargs["o_dac_ss_L"] = platform.request("dac_ss_L") - self.kwargs["o_adc_conv"] = platform.request("adc_conv") - self.kwargs["i_adc_sdo"] = platform.request("adc_sdo") - self.kwargs["o_adc_sck"] = platform.request("adc_sck") - self.kwargs["o_set_low"] = platform.request("differntial_output_low") + self.kwargs["i_clk"] = clk + self.kwargs["i_rst_L"] = ~platform.request("module_reset") + self.kwargs["i_dac_miso"] = platform.request("dac_miso") + self.kwargs["o_dac_mosi"] = platform.request("dac_mosi") + self.kwargs["o_dac_sck"] = platform.request("dac_sck") + self.kwargs["o_dac_ss_L"] = platform.request("dac_ss_L") + self.kwargs["o_adc_conv"] = platform.request("adc_conv") + self.kwargs["i_adc_sdo"] = platform.request("adc_sdo") + self.kwargs["o_adc_sck"] = platform.request("adc_sck") + self.kwargs["o_set_low"] = platform.request("differntial_output_low") - self.specials += Instance("base", **self.kwargs) + self.specials += Instance("base", **self.kwargs) # Clock and Reset Generator # I don't know how this works, I only know that it does. class _CRG(Module): - def __init__(self, platform, sys_clk_freq, with_dram, rst_pin): - self.rst = Signal() - self.clock_domains.cd_sys = ClockDomain() - self.clock_domains.cd_eth = ClockDomain() - if with_dram: - self.clock_domains.cd_sys4x = ClockDomain() - self.clock_domains.cd_sys4x_dqs = ClockDomain() - self.clock_domains.cd_idelay = ClockDomain() + def __init__(self, platform, sys_clk_freq, with_dram, rst_pin): + self.rst = Signal() + self.clock_domains.cd_sys = ClockDomain() + self.clock_domains.cd_eth = ClockDomain() + if with_dram: + self.clock_domains.cd_sys4x = ClockDomain() + self.clock_domains.cd_sys4x_dqs = ClockDomain() + self.clock_domains.cd_idelay = ClockDomain() - # Clk/Rst. - clk100 = platform.request("clk100") - rst = ~rst_pin if rst_pin is not None else 0 + # Clk/Rst. + clk100 = platform.request("clk100") + rst = ~rst_pin if rst_pin is not None else 0 - # PLL. - self.submodules.pll = pll = S7PLL(speedgrade=-1) - self.comb += pll.reset.eq(rst | self.rst) - pll.register_clkin(clk100, 100e6) - pll.create_clkout(self.cd_sys, sys_clk_freq) - pll.create_clkout(self.cd_eth, 25e6) - self.comb += platform.request("eth_ref_clk").eq(self.cd_eth.clk) - platform.add_false_path_constraints(self.cd_sys.clk, pll.clkin) # Ignore sys_clk to pll.clkin path created by SoC's rst. - if with_dram: - pll.create_clkout(self.cd_sys4x, 4*sys_clk_freq) - pll.create_clkout(self.cd_sys4x_dqs, 4*sys_clk_freq, phase=90) - pll.create_clkout(self.cd_idelay, 200e6) + # PLL. + self.submodules.pll = pll = S7PLL(speedgrade=-1) + self.comb += pll.reset.eq(rst | self.rst) + pll.register_clkin(clk100, 100e6) + pll.create_clkout(self.cd_sys, sys_clk_freq) + pll.create_clkout(self.cd_eth, 25e6) + self.comb += platform.request("eth_ref_clk").eq(self.cd_eth.clk) + platform.add_false_path_constraints(self.cd_sys.clk, pll.clkin) # Ignore sys_clk to pll.clkin path created by SoC's rst. + if with_dram: + pll.create_clkout(self.cd_sys4x, 4*sys_clk_freq) + pll.create_clkout(self.cd_sys4x_dqs, 4*sys_clk_freq, phase=90) + pll.create_clkout(self.cd_idelay, 200e6) - # IdelayCtrl. - if with_dram: - self.submodules.idelayctrl = S7IDELAYCTRL(self.cd_idelay) + # IdelayCtrl. + if with_dram: + self.submodules.idelayctrl = S7IDELAYCTRL(self.cd_idelay) class UpsilonSoC(SoCCore): - def __init__(self, variant): - sys_clk_freq = int(100e6) - platform = board_spec.Platform(variant=variant, toolchain="f4pga") - rst = platform.request("cpu_reset") - self.submodules.crg = _CRG(platform, sys_clk_freq, True, rst) - """ - These source files need to be sorted so that modules - that rely on another module come later. For instance, - `control_loop` depends on `control_loop_math`, so - control_loop_math.v comes before control_loop.v + def __init__(self, variant): + sys_clk_freq = int(100e6) + platform = board_spec.Platform(variant=variant, toolchain="f4pga") + rst = platform.request("cpu_reset") + self.submodules.crg = _CRG(platform, sys_clk_freq, True, rst) + """ + These source files need to be sorted so that modules + that rely on another module come later. For instance, + `control_loop` depends on `control_loop_math`, so + control_loop_math.v comes before control_loop.v - If you want to add a new verilog file to the design, look at the - modules that it refers to and place it the files with those modules. + If you want to add a new verilog file to the design, look at the + modules that it refers to and place it the files with those modules. - Since Yosys doesn't support modern Verilog, only put preprocessed - (if applicable) files here. - """ - platform.add_source("rtl/spi/spi_switch_preprocessed.v") - platform.add_source("rtl/spi/spi_master_preprocessed.v") - platform.add_source("rtl/spi/spi_master_no_write_preprocessed.v") - platform.add_source("rtl/spi/spi_master_no_read_preprocessed.v") - platform.add_source("rtl/spi/spi_master_ss_preprocessed.v") - platform.add_source("rtl/spi/spi_master_ss_no_write_preprocessed.v") - platform.add_source("rtl/spi/spi_master_ss_no_read_preprocessed.v") - platform.add_source("rtl/control_loop/sign_extend.v") - platform.add_source("rtl/control_loop/intsat.v") - platform.add_source("rtl/control_loop/boothmul_preprocessed.v") - platform.add_source("rtl/control_loop/control_loop_math.v") - platform.add_source("rtl/control_loop/control_loop.v") -# platform.add_source("rtl/waveform/bram_interface_preprocessed.v") -# platform.add_source("rtl/waveform/waveform_preprocessed.v") - platform.add_source("rtl/base/base.v") + Since Yosys doesn't support modern Verilog, only put preprocessed + (if applicable) files here. + """ + platform.add_source("rtl/spi/spi_switch_preprocessed.v") + platform.add_source("rtl/spi/spi_master_preprocessed.v") + platform.add_source("rtl/spi/spi_master_no_write_preprocessed.v") + platform.add_source("rtl/spi/spi_master_no_read_preprocessed.v") + platform.add_source("rtl/spi/spi_master_ss_preprocessed.v") + platform.add_source("rtl/spi/spi_master_ss_no_write_preprocessed.v") + platform.add_source("rtl/spi/spi_master_ss_no_read_preprocessed.v") + platform.add_source("rtl/control_loop/sign_extend.v") + platform.add_source("rtl/control_loop/intsat.v") + platform.add_source("rtl/control_loop/boothmul_preprocessed.v") + platform.add_source("rtl/control_loop/control_loop_math.v") + platform.add_source("rtl/control_loop/control_loop.v") +# platform.add_source("rtl/waveform/bram_interface_preprocessed.v") +# platform.add_source("rtl/waveform/waveform_preprocessed.v") + platform.add_source("rtl/base/base.v") - # SoCCore does not have sane defaults (no integrated rom) - SoCCore.__init__(self, - clk_freq=sys_clk_freq, - toolchain="symbiflow", - platform = platform, - bus_standard = "wishbone", - ident = f"Arty-{variant} F4PGA LiteX VexRiscV Zephyr - Upsilon", - bus_data_width = 32, - bus_address_width = 32, - bus_timeout = int(1e6), - cpu_type = "vexriscv_smp", + # SoCCore does not have sane defaults (no integrated rom) + SoCCore.__init__(self, + clk_freq=sys_clk_freq, + toolchain="symbiflow", + platform = platform, + bus_standard = "wishbone", + ident = f"Arty-{variant} F4PGA LiteX VexRiscV Zephyr - Upsilon", + bus_data_width = 32, + bus_address_width = 32, + bus_timeout = int(1e6), + cpu_type = "vexriscv_smp", cpu_count = 1, cpu_variant="linux", - integrated_rom_size=0x20000, - integrated_sram_size = 0x2000, - csr_data_width=32, - csr_address_width=14, - csr_paging=0x800, - csr_ordering="big", - local_ip='192.168.1.50', - remote_ip='192.168.1.100', - timer_uptime = True) - # This initializes the connection to the physical DRAM interface. - self.submodules.ddrphy = s7ddrphy.A7DDRPHY(platform.request("ddram"), - memtype = "DDR3", - nphases = 4, - sys_clk_freq = sys_clk_freq) - # Synchronous dynamic ram. This is what controls all access to RAM. - # This houses the "crossbar", which negotiates all RAM accesses to different - # modules, including the verilog interfaces (waveforms etc.) - self.add_sdram("sdram", - phy = self.ddrphy, - module = MT41K128M16(sys_clk_freq, "1:4"), - l2_cache_size = 8192 - ) - self.submodules.ethphy = LiteEthPHYMII( - clock_pads = platform.request("eth_clocks"), - pads = platform.request("eth")) - self.add_ethernet(phy=self.ethphy, dynamic_ip=True) + integrated_rom_size=0x20000, + integrated_sram_size = 0x2000, + csr_data_width=32, + csr_address_width=14, + csr_paging=0x800, + csr_ordering="big", + local_ip='192.168.1.50', + remote_ip='192.168.1.100', + timer_uptime = True) + # This initializes the connection to the physical DRAM interface. + self.submodules.ddrphy = s7ddrphy.A7DDRPHY(platform.request("ddram"), + memtype = "DDR3", + nphases = 4, + sys_clk_freq = sys_clk_freq) + # Synchronous dynamic ram. This is what controls all access to RAM. + # This houses the "crossbar", which negotiates all RAM accesses to different + # modules, including the verilog interfaces (waveforms etc.) + self.add_sdram("sdram", + phy = self.ddrphy, + module = MT41K128M16(sys_clk_freq, "1:4"), + l2_cache_size = 8192 + ) + self.submodules.ethphy = LiteEthPHYMII( + clock_pads = platform.request("eth_clocks"), + pads = platform.request("eth")) + self.add_ethernet(phy=self.ethphy, dynamic_ip=True) - platform.add_extension(io) - self.submodules.base = Base(ClockSignal(), self.sdram, platform) + platform.add_extension(io) + self.submodules.base = Base(ClockSignal(), self.sdram, platform) def main(): - soc =UpsilonSoC("a7-100") - builder = Builder(soc, csr_json="csr.json", compile_software=True) - builder.build() + soc =UpsilonSoC("a7-100") + builder = Builder(soc, csr_json="csr.json", compile_software=True) + builder.build() if __name__ == "__main__": - main() + main()