refactor compiles
This commit is contained in:
parent
054609a459
commit
cf95a0fd20
|
@ -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/arty.dtb ../boot/
|
||||||
docker cp upsilon-hardware:/home/user/upsilon/gateware/mmio.py ../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.json ../boot/
|
||||||
docker cp upsilon-hardware:/home/user/upsilon/gateware/csr_bitwidth.json ../boot/
|
|
||||||
hardware-clean:
|
hardware-clean:
|
||||||
-docker container stop upsilon-hardware
|
-docker container stop upsilon-hardware
|
||||||
-docker container rm upsilon-hardware
|
-docker container rm upsilon-hardware
|
||||||
|
|
|
@ -15,59 +15,23 @@ import collections
|
||||||
import argparse
|
import argparse
|
||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
|
import mmio_descr
|
||||||
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
|
|
||||||
|
|
||||||
class CSRHandler:
|
class CSRHandler:
|
||||||
"""
|
"""
|
||||||
Class that wraps the CSR file and fills in registers with information
|
Class that wraps the CSR file and fills in registers with information
|
||||||
from those files.
|
from those files.
|
||||||
"""
|
"""
|
||||||
def __init__(self, csrjson, bitwidthjson, registers):
|
def __init__(self, csrjson, registers):
|
||||||
"""
|
"""
|
||||||
Reads in the CSR files.
|
Reads in the CSR files.
|
||||||
|
|
||||||
:param csrjson: Filename of a LiteX "csr.json" file.
|
:param csrjson: Filename of a LiteX "csr.json" file.
|
||||||
:param bitwidthjson: Filename of an Upsilon "bitwidthjson" file.
|
:param registers: A list of ``mmio_descr`` ``Descr``s.
|
||||||
:param registers: A list of :py:class:`MMIORegister`s.
|
|
||||||
:param outf: Output file.
|
:param outf: Output file.
|
||||||
"""
|
"""
|
||||||
self.registers = registers
|
self.registers = registers
|
||||||
self.csrs = json.load(open(csrjson))
|
self.csrs = json.load(open(csrjson))
|
||||||
self.bws = json.load(open(bitwidthjson))
|
|
||||||
|
|
||||||
def update_reg(self, reg):
|
def update_reg(self, reg):
|
||||||
"""
|
"""
|
||||||
|
@ -76,17 +40,19 @@ class CSRHandler:
|
||||||
:param reg: The register.
|
:param reg: The register.
|
||||||
:raises Exception: When the bit width exceeds 64.
|
:raises Exception: When the bit width exceeds 64.
|
||||||
"""
|
"""
|
||||||
b = self.bws[reg.name]
|
regsize = None
|
||||||
|
b = reg.blen
|
||||||
if b <= 8:
|
if b <= 8:
|
||||||
reg.size = 8
|
regsize = 8
|
||||||
elif b <= 16:
|
elif b <= 16:
|
||||||
reg.size = 16
|
regsize = 16
|
||||||
elif b <= 32:
|
elif b <= 32:
|
||||||
reg.size = 32
|
regsize = 32
|
||||||
elif b <= 64:
|
elif b <= 64:
|
||||||
reg.size = 64
|
regsize = 64
|
||||||
else:
|
else:
|
||||||
raise Exception(f"unsupported width {b} in {reg.name}")
|
raise Exception(f"unsupported width {b} in {reg.name}")
|
||||||
|
setattr(reg, "regsize", regsize)
|
||||||
|
|
||||||
def get_reg_addr(self, reg, num=None):
|
def get_reg_addr(self, reg, num=None):
|
||||||
"""
|
"""
|
||||||
|
@ -135,7 +101,7 @@ class InterfaceGenerator:
|
||||||
self.print(self.header())
|
self.print(self.header())
|
||||||
for r in self.csr.registers:
|
for r in self.csr.registers:
|
||||||
self.print(self.fun(r, "read"))
|
self.print(self.fun(r, "read"))
|
||||||
if not r.read_only:
|
if not r.rwperm != "read-only":
|
||||||
self.print(self.fun(r, "write"))
|
self.print(self.fun(r, "write"))
|
||||||
|
|
||||||
class MicropythonGenerator(InterfaceGenerator):
|
class MicropythonGenerator(InterfaceGenerator):
|
||||||
|
@ -144,9 +110,9 @@ class MicropythonGenerator(InterfaceGenerator):
|
||||||
|
|
||||||
def get_accessor(self, reg, num):
|
def get_accessor(self, reg, num):
|
||||||
addr = self.csr.get_reg_addr(reg, num)
|
addr = self.csr.get_reg_addr(reg, num)
|
||||||
if reg.size in [8, 16, 32]:
|
if reg.regsize in [8, 16, 32]:
|
||||||
return [f"machine.mem{reg.size}[{addr}]"]
|
return [f"machine.mem{reg.regsize}[{addr}]"]
|
||||||
return [f"machine.mem32[{addr}]", f"machine.mem32[{addr + 4}]"]
|
return [f"machine.mem32[{addr + 4}]", f"machine.mem32[{addr}]"]
|
||||||
|
|
||||||
def print_write_register(self, indent, varname, reg, num):
|
def print_write_register(self, indent, varname, reg, num):
|
||||||
acc = self.get_accessor(reg, num)
|
acc = self.get_accessor(reg, num)
|
||||||
|
@ -181,16 +147,16 @@ class MicropythonGenerator(InterfaceGenerator):
|
||||||
else:
|
else:
|
||||||
pfun = self.print_read_register
|
pfun = self.print_read_register
|
||||||
|
|
||||||
if reg.number != 1:
|
if reg.num != 1:
|
||||||
if printed_argument:
|
if printed_argument:
|
||||||
a(', ')
|
a(', ')
|
||||||
a('num')
|
a('num')
|
||||||
a('):\n')
|
a('):\n')
|
||||||
|
|
||||||
if reg.number == 1:
|
if reg.num == 1:
|
||||||
a(pfun('\t', 'val', reg, None))
|
a(pfun('\t', 'val', reg, None))
|
||||||
else:
|
else:
|
||||||
for i in range(0,reg.number):
|
for i in range(0,reg.num):
|
||||||
if i == 0:
|
if i == 0:
|
||||||
a(f'\tif ')
|
a(f'\tif ')
|
||||||
else:
|
else:
|
||||||
|
@ -198,46 +164,16 @@ class MicropythonGenerator(InterfaceGenerator):
|
||||||
a(f'num == {i}:\n')
|
a(f'num == {i}:\n')
|
||||||
a(pfun('\t\t', 'val', reg, i))
|
a(pfun('\t\t', 'val', reg, i))
|
||||||
a(f'\telse:\n')
|
a(f'\telse:\n')
|
||||||
a(f'\t\traise {r.exntype}(regnum)\n')
|
a(f'\t\traise Exception(regnum)\n')
|
||||||
a('\n')
|
a('\n')
|
||||||
|
|
||||||
return rs
|
return rs
|
||||||
|
|
||||||
def header(self):
|
def header(self):
|
||||||
return """import machine
|
return "import machine\n"
|
||||||
class InvalidDACException(Exception):
|
|
||||||
pass
|
|
||||||
class InvalidADCException(Exception):
|
|
||||||
pass
|
|
||||||
"""
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
dac_num = 8
|
csrh = CSRHandler(sys.argv[1], mmio_descr.registers)
|
||||||
adc_num = 8
|
for r in mmio_descr.registers:
|
||||||
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.update_reg(r)
|
csrh.update_reg(r)
|
||||||
MicropythonGenerator(csrh, sys.stdout).print_file()
|
MicropythonGenerator(csrh, sys.stdout).print_file()
|
||||||
|
|
|
@ -11,15 +11,15 @@ class Descr:
|
||||||
"""
|
"""
|
||||||
self.name = name
|
self.name = name
|
||||||
self.blen = blen
|
self.blen = blen
|
||||||
self.doc = textwrap.deindent(descr)
|
self.doc = textwrap.dedent(descr)
|
||||||
self.num =num
|
self.num =num
|
||||||
self.read_only = read_only == "read-only"
|
self.rwperm = rwperm
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, jsdict, name):
|
def from_dict(cls, jsdict, name):
|
||||||
return cls(name, jsdict[name]["len"], jsdict[name]["ro"], jsdict[name]["num"], jsdict[name]["doc"])
|
return cls(name, jsdict[name]["len"], jsdict[name]["ro"], jsdict[name]["num"], jsdict[name]["doc"])
|
||||||
def store_to_dict(self, d):
|
def store_to_dict(self, d):
|
||||||
d[self.name = {
|
d[self.name] = {
|
||||||
"len": self.blen,
|
"len": self.blen,
|
||||||
"doc": self.doc,
|
"doc": self.doc,
|
||||||
"num": self.num,
|
"num": self.num,
|
||||||
|
@ -27,7 +27,7 @@ class Descr:
|
||||||
}
|
}
|
||||||
|
|
||||||
registers = [
|
registers = [
|
||||||
Descr("adc_sel", 3, "read-write", """\
|
Descr("adc_sel", 3, "read-write", 8, """\
|
||||||
Select which on-FPGA SPI master controls the ADC.
|
Select which on-FPGA SPI master controls the ADC.
|
||||||
|
|
||||||
Valid settings:
|
Valid settings:
|
||||||
|
@ -36,7 +36,7 @@ registers = [
|
||||||
* ``0b10``: ADC is controlled by MMIO registers, but conversion is
|
* ``0b10``: ADC is controlled by MMIO registers, but conversion is
|
||||||
disabled. This is used to flush output from an out-of-sync ADC.
|
disabled. This is used to flush output from an out-of-sync ADC.
|
||||||
* ``0b100``: ADC 0 only. ADC is controlled by control loop."""),
|
* ``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.
|
Signals that an ADC master has finished an SPI cycle.
|
||||||
|
|
||||||
Values:
|
Values:
|
||||||
|
@ -47,9 +47,8 @@ registers = [
|
||||||
|
|
||||||
This flag is on only when ``adc_arm`` is high. The flag does not
|
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
|
mean that data has been received successfully, only that the master
|
||||||
has finished it's SPI transfer.
|
has finished it's SPI transfer."""),
|
||||||
"""),
|
Descr("adc_arm", 1, "read-write", 8, """\
|
||||||
Descr("adc_arm", "read-write", """\
|
|
||||||
Start a DAC master SPI transfer.
|
Start a DAC master SPI transfer.
|
||||||
|
|
||||||
If ``adc_arm`` is raised from and the master is currently not in a SPI
|
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
|
If ``adc_sel`` is not set to 0 then the transfer will proceed
|
||||||
as normal, but no data will be received from the ADC."""),
|
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.
|
ADC Master receive buffer.
|
||||||
|
|
||||||
This buffer is stable if there is no ADC transfer caused by ``adc_arm``
|
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.
|
registers. SPI transfers by other masters will not affect this register.
|
||||||
buffer."""),
|
buffer."""),
|
||||||
|
|
||||||
Descr("dac_sel", 2, "read-write", """\
|
Descr("dac_sel", 2, "read-write", 8, """\
|
||||||
Select which on-FPGA SPI master controls the DAC.
|
Select which on-FPGA SPI master controls the DAC.
|
||||||
|
|
||||||
Valid settings:
|
Valid settings:
|
||||||
|
|
||||||
* ``0``: DAC is controlled by MMIO registers.
|
* ``0``: DAC is controlled by MMIO registers.
|
||||||
* ``0b10``: DAC 0 only. DAC is controlled by control loop."""),
|
* ``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.
|
Signals that the DAC master has finished transmitting data.
|
||||||
|
|
||||||
Values:
|
Values:
|
||||||
|
@ -113,7 +112,7 @@ registers = [
|
||||||
This flag is on only when ``dac_arm`` is high. The flag does not
|
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
|
mean that data has been received or transmitted successfully, only that
|
||||||
the master has finished it's SPI transfer."""),
|
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.
|
Start a DAC master SPI transfer.
|
||||||
|
|
||||||
If ``dac_arm`` is raised from and the master is currently not in a SPI
|
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
|
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."""),
|
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.
|
DAC master receive buffer.
|
||||||
|
|
||||||
This buffer is stable if there is no DAC transfer caused by ``dac_arm``
|
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
|
This register only changes if an SPI transfer is triggered by the MMIO
|
||||||
registers. SPI transfers by other masters will not affect this register.
|
registers. SPI transfers by other masters will not affect this register.
|
||||||
buffer."""),
|
buffer."""),
|
||||||
Descr("dac_send_buf, 24, "read-write", """\
|
Descr("dac_send_buf", 24, "read-write", 8, """\
|
||||||
DAC master send buffer.
|
DAC master send buffer.
|
||||||
|
|
||||||
Fill this buffer with a 24 bit Analog Devices DAC command. Updating
|
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
|
Modifying this buffer during a transfer does not disrupt an in-process
|
||||||
transfer."""),
|
transfer."""),
|
||||||
|
|
||||||
Descr("cl_assert_change", 1, "read-write", """\
|
Descr("cl_assert_change", 1, "read-write", 1, """\
|
||||||
Flush parameter changes to control loop.
|
Flush parameter changes to control loop.
|
||||||
|
|
||||||
When this bit is raised from low to high, this signals the control
|
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``
|
When this bit is raised from high to low before ``cl_change_made``
|
||||||
is asserted by the control loop, nothing happens."""),
|
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.
|
Signal from the control loop that the parameters have been applied.
|
||||||
|
|
||||||
This signal goes high only while ``cl_assert_change`` is high. No
|
This signal goes high only while ``cl_assert_change`` is high. No
|
||||||
change will be applied afterwards while both are high."""),
|
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."""),
|
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.
|
Setpoint of the control loop.
|
||||||
|
|
||||||
This is a twos-complement number in ADC units.
|
This is a twos-complement number in ADC units.
|
||||||
|
|
||||||
This is a parameter: see ``cl_assert_change``."""),
|
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.
|
Proportional parameter of the control loop.
|
||||||
|
|
||||||
This is a twos-complement fixed point number with 21 whole
|
This is a twos-complement fixed point number with 21 whole
|
||||||
|
@ -190,7 +191,7 @@ registers = [
|
||||||
in DAC units.
|
in DAC units.
|
||||||
|
|
||||||
This is a parameter: see ``cl_assert_change``."""),
|
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.
|
Integral parameter of the control loop.
|
||||||
|
|
||||||
This is a twos-complement fixed point number with 21 whole
|
This is a twos-complement fixed point number with 21 whole
|
||||||
|
@ -198,7 +199,7 @@ registers = [
|
||||||
in DAC units.
|
in DAC units.
|
||||||
|
|
||||||
This is a parameter: see ``cl_assert_change``."""),
|
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.
|
Delay parameter of the loop.
|
||||||
|
|
||||||
This is an unsigned number denoting the number of cycles
|
This is an unsigned number denoting the number of cycles
|
||||||
|
@ -206,15 +207,15 @@ registers = [
|
||||||
|
|
||||||
This is a parameter: see ``cl_assert_change``."""),
|
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.
|
Delay parameter of the loop.
|
||||||
|
|
||||||
This is an unsigned number denoting the number of cycles
|
This is an unsigned number denoting the number of cycles
|
||||||
the loop should wait between loop executions."""),
|
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.
|
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.
|
Control loop ADC Z position.
|
||||||
"""),
|
"""),
|
||||||
]
|
]
|
||||||
|
|
|
@ -292,6 +292,7 @@ m4_define(CL_DATA_WID, CL_CONSTS_WID)
|
||||||
|
|
||||||
input cl_assert_change,
|
input cl_assert_change,
|
||||||
output cl_change_made,
|
output cl_change_made,
|
||||||
|
output cl_in_loop,
|
||||||
|
|
||||||
input cl_run_loop_in,
|
input cl_run_loop_in,
|
||||||
input [ADC_TYPE1_WID-1:0] cl_setpt_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_DATA_WID-1:0] cl_I_in,
|
||||||
input [CL_DELAY_WID-1:0] cl_delay_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 [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;
|
assign set_low = 0;
|
||||||
|
|
316
gateware/soc.py
316
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.
|
name will be a vector of pins.
|
||||||
"""
|
"""
|
||||||
io = [
|
io = [
|
||||||
("differntial_output_low", 0, Pins("J17 J18 K15 J15 U14 V14 T13 U13 B6 E5 A3"), 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_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_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_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")),
|
("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_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_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")),
|
("adc_sdo", 0, Pins("P14 T14 V17 P17 M13 R13 N14 R18"), IOStandard("LVCMOS33")),
|
||||||
("module_reset", 0, Pins("D9"), IOStandard("LVCMOS33")),
|
("module_reset", 0, Pins("D9"), IOStandard("LVCMOS33")),
|
||||||
("test_clock", 0, Pins("P18"), IOStandard("LVCMOS33"))
|
("test_clock", 0, Pins("P18"), IOStandard("LVCMOS33"))
|
||||||
]
|
]
|
||||||
|
|
||||||
# TODO: Assign widths to ADCs here using parameters
|
# TODO: Assign widths to ADCs here using parameters
|
||||||
|
|
||||||
class Base(Module, AutoCSR):
|
class Base(Module, AutoCSR):
|
||||||
""" The subclass AutoCSR will automatically make CSRs related
|
""" The subclass AutoCSR will automatically make CSRs related
|
||||||
to this class when those CSRs are attributes (i.e. accessed by
|
to this class when those CSRs are attributes (i.e. accessed by
|
||||||
`self.csr_name`) of instances of this class. (CSRs are MMIO,
|
`self.csr_name`) of instances of this class. (CSRs are MMIO,
|
||||||
they are NOT RISC-V CSRs!)
|
they are NOT RISC-V CSRs!)
|
||||||
|
|
||||||
Since there are a lot of input and output wires, the CSRs are
|
Since there are a lot of input and output wires, the CSRs are
|
||||||
assigned using `setattr()`.
|
assigned using `setattr()`.
|
||||||
|
|
||||||
CSRs are for input wires (`CSRStorage`) or output wires
|
CSRs are for input wires (`CSRStorage`) or output wires
|
||||||
(`CSRStatus`). The first argument to the CSR constructor is
|
(`CSRStatus`). The first argument to the CSR constructor is
|
||||||
the amount of bits the CSR takes. The `name` keyword argument
|
the amount of bits the CSR takes. The `name` keyword argument
|
||||||
is required since the constructor needs the name of the attribute.
|
is required since the constructor needs the name of the attribute.
|
||||||
The `description` keyword is used for documentation.
|
The `description` keyword is used for documentation.
|
||||||
|
|
||||||
In LiteX, modules in separate Verilog files are instantiated as
|
In LiteX, modules in separate Verilog files are instantiated as
|
||||||
self.specials += Instance(
|
self.specials += Instance(
|
||||||
"module_name",
|
"module_name",
|
||||||
PARAMETER_NAME=value,
|
PARAMETER_NAME=value,
|
||||||
i_input = input_port,
|
i_input = input_port,
|
||||||
o_output = output_port,
|
o_output = output_port,
|
||||||
...
|
...
|
||||||
)
|
)
|
||||||
|
|
||||||
Since the "base" module has a bunch of repeated input and output
|
Since the "base" module has a bunch of repeated input and output
|
||||||
pins that have to be connected to CSRs, the LiteX wrapper uses
|
pins that have to be connected to CSRs, the LiteX wrapper uses
|
||||||
keyword arguments to pass all the arguments.
|
keyword arguments to pass all the arguments.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def _make_csr(self, reg, num=None):
|
def _make_csr(self, reg, num=None):
|
||||||
""" Add a CSR for a pin `f"{name}_{num}".`
|
""" Add a CSR for a pin `f"{name}_{num}".`
|
||||||
|
|
||||||
:param name: Name of the MMIO register without prefixes or numerical
|
:param name: Name of the MMIO register without prefixes or numerical
|
||||||
suffix.
|
suffix.
|
||||||
:param num: Numerical suffix of this MMIO register. This is the only
|
:param num: Numerical suffix of this MMIO register. This is the only
|
||||||
parameter that should change when adding multiple CSRs of the same
|
parameter that should change when adding multiple CSRs of the same
|
||||||
name.
|
name.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = reg.name
|
name = reg.name
|
||||||
if num is not None:
|
if num is not None:
|
||||||
name = f"{name}_{num}"
|
name = f"{name}_{num}"
|
||||||
|
|
||||||
if self.ro == "read-only":
|
if reg.rwperm == "read-only":
|
||||||
csrclass = CSRStatus
|
csrclass = CSRStatus
|
||||||
else:
|
else:
|
||||||
csrclass = CSRStorage
|
csrclass = CSRStorage
|
||||||
|
|
||||||
csr = csrclass(reg.blen, name=name, description=None)
|
csr = csrclass(reg.blen, name=name, description=None)
|
||||||
setattr(self, name, csr)
|
setattr(self, name, csr)
|
||||||
|
|
||||||
if csrclass is CSRStorage:
|
if csrclass is CSRStorage:
|
||||||
self.kwargs[f'i_{name}'] = csr.storage
|
self.kwargs[f'i_{name}'] = csr.storage
|
||||||
elif csrclass is CSRStatus:
|
elif csrclass is CSRStatus:
|
||||||
self.kwargs[f'o_{name}'] = csr.status
|
self.kwargs[f'o_{name}'] = csr.status
|
||||||
else:
|
else:
|
||||||
raise Exception(f"Unknown class {csrclass}")
|
raise Exception(f"Unknown class {csrclass}")
|
||||||
|
|
||||||
def __init__(self, clk, sdram, platform):
|
def __init__(self, clk, sdram, platform):
|
||||||
self.kwargs = {}
|
self.kwargs = {}
|
||||||
|
|
||||||
for reg in mmio_descr.registers:
|
for reg in mmio_descr.registers:
|
||||||
if reg.num > 1:
|
if reg.num > 1:
|
||||||
|
@ -169,133 +169,133 @@ class Base(Module, AutoCSR):
|
||||||
else:
|
else:
|
||||||
self._make_csr(reg)
|
self._make_csr(reg)
|
||||||
|
|
||||||
self.kwargs["i_clk"] = clk
|
self.kwargs["i_clk"] = clk
|
||||||
self.kwargs["i_rst_L"] = ~platform.request("module_reset")
|
self.kwargs["i_rst_L"] = ~platform.request("module_reset")
|
||||||
self.kwargs["i_dac_miso"] = platform.request("dac_miso")
|
self.kwargs["i_dac_miso"] = platform.request("dac_miso")
|
||||||
self.kwargs["o_dac_mosi"] = platform.request("dac_mosi")
|
self.kwargs["o_dac_mosi"] = platform.request("dac_mosi")
|
||||||
self.kwargs["o_dac_sck"] = platform.request("dac_sck")
|
self.kwargs["o_dac_sck"] = platform.request("dac_sck")
|
||||||
self.kwargs["o_dac_ss_L"] = platform.request("dac_ss_L")
|
self.kwargs["o_dac_ss_L"] = platform.request("dac_ss_L")
|
||||||
self.kwargs["o_adc_conv"] = platform.request("adc_conv")
|
self.kwargs["o_adc_conv"] = platform.request("adc_conv")
|
||||||
self.kwargs["i_adc_sdo"] = platform.request("adc_sdo")
|
self.kwargs["i_adc_sdo"] = platform.request("adc_sdo")
|
||||||
self.kwargs["o_adc_sck"] = platform.request("adc_sck")
|
self.kwargs["o_adc_sck"] = platform.request("adc_sck")
|
||||||
self.kwargs["o_set_low"] = platform.request("differntial_output_low")
|
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
|
# Clock and Reset Generator
|
||||||
# I don't know how this works, I only know that it does.
|
# I don't know how this works, I only know that it does.
|
||||||
class _CRG(Module):
|
class _CRG(Module):
|
||||||
def __init__(self, platform, sys_clk_freq, with_dram, rst_pin):
|
def __init__(self, platform, sys_clk_freq, with_dram, rst_pin):
|
||||||
self.rst = Signal()
|
self.rst = Signal()
|
||||||
self.clock_domains.cd_sys = ClockDomain()
|
self.clock_domains.cd_sys = ClockDomain()
|
||||||
self.clock_domains.cd_eth = ClockDomain()
|
self.clock_domains.cd_eth = ClockDomain()
|
||||||
if with_dram:
|
if with_dram:
|
||||||
self.clock_domains.cd_sys4x = ClockDomain()
|
self.clock_domains.cd_sys4x = ClockDomain()
|
||||||
self.clock_domains.cd_sys4x_dqs = ClockDomain()
|
self.clock_domains.cd_sys4x_dqs = ClockDomain()
|
||||||
self.clock_domains.cd_idelay = ClockDomain()
|
self.clock_domains.cd_idelay = ClockDomain()
|
||||||
|
|
||||||
# Clk/Rst.
|
# Clk/Rst.
|
||||||
clk100 = platform.request("clk100")
|
clk100 = platform.request("clk100")
|
||||||
rst = ~rst_pin if rst_pin is not None else 0
|
rst = ~rst_pin if rst_pin is not None else 0
|
||||||
|
|
||||||
# PLL.
|
# PLL.
|
||||||
self.submodules.pll = pll = S7PLL(speedgrade=-1)
|
self.submodules.pll = pll = S7PLL(speedgrade=-1)
|
||||||
self.comb += pll.reset.eq(rst | self.rst)
|
self.comb += pll.reset.eq(rst | self.rst)
|
||||||
pll.register_clkin(clk100, 100e6)
|
pll.register_clkin(clk100, 100e6)
|
||||||
pll.create_clkout(self.cd_sys, sys_clk_freq)
|
pll.create_clkout(self.cd_sys, sys_clk_freq)
|
||||||
pll.create_clkout(self.cd_eth, 25e6)
|
pll.create_clkout(self.cd_eth, 25e6)
|
||||||
self.comb += platform.request("eth_ref_clk").eq(self.cd_eth.clk)
|
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.
|
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:
|
if with_dram:
|
||||||
pll.create_clkout(self.cd_sys4x, 4*sys_clk_freq)
|
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_sys4x_dqs, 4*sys_clk_freq, phase=90)
|
||||||
pll.create_clkout(self.cd_idelay, 200e6)
|
pll.create_clkout(self.cd_idelay, 200e6)
|
||||||
|
|
||||||
# IdelayCtrl.
|
# IdelayCtrl.
|
||||||
if with_dram:
|
if with_dram:
|
||||||
self.submodules.idelayctrl = S7IDELAYCTRL(self.cd_idelay)
|
self.submodules.idelayctrl = S7IDELAYCTRL(self.cd_idelay)
|
||||||
|
|
||||||
class UpsilonSoC(SoCCore):
|
class UpsilonSoC(SoCCore):
|
||||||
def __init__(self, variant):
|
def __init__(self, variant):
|
||||||
sys_clk_freq = int(100e6)
|
sys_clk_freq = int(100e6)
|
||||||
platform = board_spec.Platform(variant=variant, toolchain="f4pga")
|
platform = board_spec.Platform(variant=variant, toolchain="f4pga")
|
||||||
rst = platform.request("cpu_reset")
|
rst = platform.request("cpu_reset")
|
||||||
self.submodules.crg = _CRG(platform, sys_clk_freq, True, rst)
|
self.submodules.crg = _CRG(platform, sys_clk_freq, True, rst)
|
||||||
"""
|
"""
|
||||||
These source files need to be sorted so that modules
|
These source files need to be sorted so that modules
|
||||||
that rely on another module come later. For instance,
|
that rely on another module come later. For instance,
|
||||||
`control_loop` depends on `control_loop_math`, so
|
`control_loop` depends on `control_loop_math`, so
|
||||||
control_loop_math.v comes before control_loop.v
|
control_loop_math.v comes before control_loop.v
|
||||||
|
|
||||||
If you want to add a new verilog file to the design, look at the
|
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.
|
modules that it refers to and place it the files with those modules.
|
||||||
|
|
||||||
Since Yosys doesn't support modern Verilog, only put preprocessed
|
Since Yosys doesn't support modern Verilog, only put preprocessed
|
||||||
(if applicable) files here.
|
(if applicable) files here.
|
||||||
"""
|
"""
|
||||||
platform.add_source("rtl/spi/spi_switch_preprocessed.v")
|
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_preprocessed.v")
|
||||||
platform.add_source("rtl/spi/spi_master_no_write_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_no_read_preprocessed.v")
|
||||||
platform.add_source("rtl/spi/spi_master_ss_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_write_preprocessed.v")
|
||||||
platform.add_source("rtl/spi/spi_master_ss_no_read_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/sign_extend.v")
|
||||||
platform.add_source("rtl/control_loop/intsat.v")
|
platform.add_source("rtl/control_loop/intsat.v")
|
||||||
platform.add_source("rtl/control_loop/boothmul_preprocessed.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_math.v")
|
||||||
platform.add_source("rtl/control_loop/control_loop.v")
|
platform.add_source("rtl/control_loop/control_loop.v")
|
||||||
# platform.add_source("rtl/waveform/bram_interface_preprocessed.v")
|
# platform.add_source("rtl/waveform/bram_interface_preprocessed.v")
|
||||||
# platform.add_source("rtl/waveform/waveform_preprocessed.v")
|
# platform.add_source("rtl/waveform/waveform_preprocessed.v")
|
||||||
platform.add_source("rtl/base/base.v")
|
platform.add_source("rtl/base/base.v")
|
||||||
|
|
||||||
# SoCCore does not have sane defaults (no integrated rom)
|
# SoCCore does not have sane defaults (no integrated rom)
|
||||||
SoCCore.__init__(self,
|
SoCCore.__init__(self,
|
||||||
clk_freq=sys_clk_freq,
|
clk_freq=sys_clk_freq,
|
||||||
toolchain="symbiflow",
|
toolchain="symbiflow",
|
||||||
platform = platform,
|
platform = platform,
|
||||||
bus_standard = "wishbone",
|
bus_standard = "wishbone",
|
||||||
ident = f"Arty-{variant} F4PGA LiteX VexRiscV Zephyr - Upsilon",
|
ident = f"Arty-{variant} F4PGA LiteX VexRiscV Zephyr - Upsilon",
|
||||||
bus_data_width = 32,
|
bus_data_width = 32,
|
||||||
bus_address_width = 32,
|
bus_address_width = 32,
|
||||||
bus_timeout = int(1e6),
|
bus_timeout = int(1e6),
|
||||||
cpu_type = "vexriscv_smp",
|
cpu_type = "vexriscv_smp",
|
||||||
cpu_count = 1,
|
cpu_count = 1,
|
||||||
cpu_variant="linux",
|
cpu_variant="linux",
|
||||||
integrated_rom_size=0x20000,
|
integrated_rom_size=0x20000,
|
||||||
integrated_sram_size = 0x2000,
|
integrated_sram_size = 0x2000,
|
||||||
csr_data_width=32,
|
csr_data_width=32,
|
||||||
csr_address_width=14,
|
csr_address_width=14,
|
||||||
csr_paging=0x800,
|
csr_paging=0x800,
|
||||||
csr_ordering="big",
|
csr_ordering="big",
|
||||||
local_ip='192.168.1.50',
|
local_ip='192.168.1.50',
|
||||||
remote_ip='192.168.1.100',
|
remote_ip='192.168.1.100',
|
||||||
timer_uptime = True)
|
timer_uptime = True)
|
||||||
# This initializes the connection to the physical DRAM interface.
|
# This initializes the connection to the physical DRAM interface.
|
||||||
self.submodules.ddrphy = s7ddrphy.A7DDRPHY(platform.request("ddram"),
|
self.submodules.ddrphy = s7ddrphy.A7DDRPHY(platform.request("ddram"),
|
||||||
memtype = "DDR3",
|
memtype = "DDR3",
|
||||||
nphases = 4,
|
nphases = 4,
|
||||||
sys_clk_freq = sys_clk_freq)
|
sys_clk_freq = sys_clk_freq)
|
||||||
# Synchronous dynamic ram. This is what controls all access to RAM.
|
# Synchronous dynamic ram. This is what controls all access to RAM.
|
||||||
# This houses the "crossbar", which negotiates all RAM accesses to different
|
# This houses the "crossbar", which negotiates all RAM accesses to different
|
||||||
# modules, including the verilog interfaces (waveforms etc.)
|
# modules, including the verilog interfaces (waveforms etc.)
|
||||||
self.add_sdram("sdram",
|
self.add_sdram("sdram",
|
||||||
phy = self.ddrphy,
|
phy = self.ddrphy,
|
||||||
module = MT41K128M16(sys_clk_freq, "1:4"),
|
module = MT41K128M16(sys_clk_freq, "1:4"),
|
||||||
l2_cache_size = 8192
|
l2_cache_size = 8192
|
||||||
)
|
)
|
||||||
self.submodules.ethphy = LiteEthPHYMII(
|
self.submodules.ethphy = LiteEthPHYMII(
|
||||||
clock_pads = platform.request("eth_clocks"),
|
clock_pads = platform.request("eth_clocks"),
|
||||||
pads = platform.request("eth"))
|
pads = platform.request("eth"))
|
||||||
self.add_ethernet(phy=self.ethphy, dynamic_ip=True)
|
self.add_ethernet(phy=self.ethphy, dynamic_ip=True)
|
||||||
|
|
||||||
platform.add_extension(io)
|
platform.add_extension(io)
|
||||||
self.submodules.base = Base(ClockSignal(), self.sdram, platform)
|
self.submodules.base = Base(ClockSignal(), self.sdram, platform)
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
soc =UpsilonSoC("a7-100")
|
soc =UpsilonSoC("a7-100")
|
||||||
builder = Builder(soc, csr_json="csr.json", compile_software=True)
|
builder = Builder(soc, csr_json="csr.json", compile_software=True)
|
||||||
builder.build()
|
builder.build()
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
Loading…
Reference in New Issue