mirror of https://github.com/m-labs/artiq.git
Merge branch 'master' into dataset-compression
This commit is contained in:
commit
1def0d98c5
|
@ -7,8 +7,7 @@ Reporting Issues/Bugs
|
||||||
|
|
||||||
Thanks for `reporting issues to ARTIQ
|
Thanks for `reporting issues to ARTIQ
|
||||||
<https://github.com/m-labs/artiq/issues/new>`_! You can also discuss issues and
|
<https://github.com/m-labs/artiq/issues/new>`_! You can also discuss issues and
|
||||||
ask questions on IRC (the `#m-labs channel on freenode
|
ask questions on IRC (the #m-labs channel on OFTC), the `Mattermost chat
|
||||||
<https://webchat.freenode.net/?channels=m-labs>`_), the `Mattermost chat
|
|
||||||
<https://chat.m-labs.hk>`_, or on the `forum <https://forum.m-labs.hk>`_.
|
<https://chat.m-labs.hk>`_, or on the `forum <https://forum.m-labs.hk>`_.
|
||||||
|
|
||||||
The best bug reports are those which contain sufficient information. With
|
The best bug reports are those which contain sufficient information. With
|
||||||
|
|
|
@ -4,3 +4,4 @@ include artiq/gui/logo*.svg
|
||||||
include versioneer.py
|
include versioneer.py
|
||||||
include artiq/_version.py
|
include artiq/_version.py
|
||||||
include artiq/coredevice/coredevice_generic.schema.json
|
include artiq/coredevice/coredevice_generic.schema.json
|
||||||
|
include artiq/compiler/kernel.ld
|
||||||
|
|
|
@ -20,7 +20,7 @@ Like any open source software ARTIQ can equally be built and installed directly
|
||||||
ARTIQ is supported by M-Labs and developed openly.
|
ARTIQ is supported by M-Labs and developed openly.
|
||||||
Components, features, fixes, improvements, and extensions are often `funded <https://m-labs.hk/experiment-control/funding/>`_ by and developed for the partnering research groups.
|
Components, features, fixes, improvements, and extensions are often `funded <https://m-labs.hk/experiment-control/funding/>`_ by and developed for the partnering research groups.
|
||||||
|
|
||||||
Core technologies employed include `Python <https://www.python.org/>`_, `Migen <https://github.com/m-labs/migen>`_, `Migen-AXI <https://github.com/peteut/migen-axi>`_, `Rust <https://www.rust-lang.org/>`_, `MiSoC <https://github.com/m-labs/misoc>`_/`mor1kx <https://github.com/openrisc/mor1kx>`_, `LLVM <https://llvm.org/>`_/`llvmlite <https://github.com/numba/llvmlite>`_, and `Qt5 <https://www.qt.io/>`_.
|
Core technologies employed include `Python <https://www.python.org/>`_, `Migen <https://github.com/m-labs/migen>`_, `Migen-AXI <https://github.com/peteut/migen-axi>`_, `Rust <https://www.rust-lang.org/>`_, `MiSoC <https://github.com/m-labs/misoc>`_/`VexRiscv <https://github.com/SpinalHDL/VexRiscv>`_, `LLVM <https://llvm.org/>`_/`llvmlite <https://github.com/numba/llvmlite>`_, and `Qt5 <https://www.qt.io/>`_.
|
||||||
|
|
||||||
Website: https://m-labs.hk/artiq
|
Website: https://m-labs.hk/artiq
|
||||||
|
|
||||||
|
|
|
@ -7,23 +7,48 @@ ARTIQ-7
|
||||||
-------
|
-------
|
||||||
|
|
||||||
Highlights:
|
Highlights:
|
||||||
|
|
||||||
|
* Support for Kasli-SoC, a new EEM carrier based on a Zynq SoC, enabling much faster kernel execution.
|
||||||
|
* Softcore targets now use the RISC-V architecture (VexRiscv) instead of OR1K (mor1kx).
|
||||||
* WRPLL
|
* WRPLL
|
||||||
* ``get()``, ``get_mu()``, ``get_att()``, and ``get_att_mu()`` functions added for AD9910 and AD9912
|
* Compiler:
|
||||||
|
- Supports kernel decorator with paths.
|
||||||
|
- Faster compilation for large arrays/lists.
|
||||||
* Phaser:
|
* Phaser:
|
||||||
- Improved documentation
|
- Improved documentation
|
||||||
- Expose the DAC coarse mixer and sif_sync
|
- Expose the DAC coarse mixer and ``sif_sync``
|
||||||
- Exposes upconverter calibration and enabling/disabling of upconverter LO & RF outputs.
|
- Exposes upconverter calibration and enabling/disabling of upconverter LO & RF outputs.
|
||||||
|
- Add helpers to align Phaser updates to the RTIO timeline (``get_next_frame_mu()``)
|
||||||
|
* ``get()``, ``get_mu()``, ``get_att()``, and ``get_att_mu()`` functions added for AD9910 and AD9912
|
||||||
|
* On Kasli, the number of FIFO lanes in the scalable events dispatcher (SED) can now be configured in
|
||||||
|
the JSON hardware description file.
|
||||||
|
* New hardware support:
|
||||||
|
- HVAMP_8CH 8 channel HV amplifier for Fastino / Zotino
|
||||||
|
* ``artiq_ddb_template`` generates edge-counter keys that start with the key of the corresponding
|
||||||
|
TTL device (e.g. ``"ttl_0_counter"`` for the edge counter on TTL device``"ttl_0"``)
|
||||||
|
* ``artiq_master`` now has an ``--experiment-subdir`` option to scan only a subdirectory of the
|
||||||
|
repository when building the list of experiments.
|
||||||
|
* The configuration entry ``rtio_clock`` supports multiple clocking settings, deprecating the usage
|
||||||
|
of compile-time options.
|
||||||
|
* DRTIO: added support for 100MHz clock.
|
||||||
|
* Previously detected RTIO async errors are reported to the host after each kernel terminates and a
|
||||||
|
warning is logged. The warning is additional to the one already printed in the core device log upon
|
||||||
|
detection of the error.
|
||||||
* HDF5 options can now be passed when creating datasets with ``set_dataset``. This allows
|
* HDF5 options can now be passed when creating datasets with ``set_dataset``. This allows
|
||||||
in particular to use transparent compression filters as follows:
|
in particular to use transparent compression filters as follows:
|
||||||
``set_dataset(name, value, hdf5_options={"compression": "gzip"})``.
|
``set_dataset(name, value, hdf5_options={"compression": "gzip"})``.
|
||||||
|
|
||||||
|
|
||||||
Breaking changes:
|
Breaking changes:
|
||||||
|
|
||||||
* Updated Phaser-Upconverter default frequency 2.875 GHz. The new default uses the target PFD
|
* Updated Phaser-Upconverter default frequency 2.875 GHz. The new default uses the target PFD
|
||||||
frequency of the hardware design.
|
frequency of the hardware design.
|
||||||
* `Phaser.init()` now disables all Kasli-oscillators. This avoids full power RF output being
|
* ``Phaser.init()`` now disables all Kasli-oscillators. This avoids full power RF output being
|
||||||
generated for some configurations.
|
generated for some configurations.
|
||||||
* Phaser: fixed coarse mixer frequency configuration
|
* Phaser: fixed coarse mixer frequency configuration
|
||||||
|
* Mirny: Added extra delays in ``ADF5356.sync()``. This avoids the need of an extra delay before
|
||||||
|
calling `ADF5356.init()`.
|
||||||
|
* DRTIO: Changed message alignment from 32-bits to 64-bits.
|
||||||
|
* The deprecated ``set_dataset(..., save=...)`` is no longer supported.
|
||||||
* The internal dataset representation was changed to support tracking HDF5 options like e.g.
|
* The internal dataset representation was changed to support tracking HDF5 options like e.g.
|
||||||
a compression method. This requires changes to code reading the dataset persistence file
|
a compression method. This requires changes to code reading the dataset persistence file
|
||||||
(``dataset_db.pyon``) and to custom applets.
|
(``dataset_db.pyon``) and to custom applets.
|
||||||
|
@ -37,7 +62,7 @@ Highlights:
|
||||||
* New hardware support:
|
* New hardware support:
|
||||||
- Phaser, a quad channel 1GS/s RF generator card with dual IQ upconverter and dual 5MS/s
|
- Phaser, a quad channel 1GS/s RF generator card with dual IQ upconverter and dual 5MS/s
|
||||||
ADC and FPGA.
|
ADC and FPGA.
|
||||||
- Zynq SoC core devices, enabling kernels to run on 1 GHz CPU core with a floating-point
|
- Zynq SoC core device (ZC706), enabling kernels to run on 1 GHz CPU core with a floating-point
|
||||||
unit for faster computations. This currently requires an external
|
unit for faster computations. This currently requires an external
|
||||||
repository (https://git.m-labs.hk/m-labs/artiq-zynq).
|
repository (https://git.m-labs.hk/m-labs/artiq-zynq).
|
||||||
- Mirny 4-channel wide-band PLL/VCO-based microwave frequency synthesiser
|
- Mirny 4-channel wide-band PLL/VCO-based microwave frequency synthesiser
|
||||||
|
@ -93,6 +118,9 @@ Breaking changes:
|
||||||
* ``quamash`` has been replaced with ``qasync``.
|
* ``quamash`` has been replaced with ``qasync``.
|
||||||
* Protocols are updated to use device endian.
|
* Protocols are updated to use device endian.
|
||||||
* Analyzer dump format includes a byte for device endianness.
|
* Analyzer dump format includes a byte for device endianness.
|
||||||
|
* To support variable numbers of Urukul cards in the future, the
|
||||||
|
``artiq.coredevice.suservo.SUServo`` constructor now accepts two device name lists,
|
||||||
|
``cpld_devices`` and ``dds_devices``, rather than four individual arguments.
|
||||||
* Experiment classes with underscore-prefixed names are now ignored when ``artiq_client``
|
* Experiment classes with underscore-prefixed names are now ignored when ``artiq_client``
|
||||||
determines which experiment to submit (consistent with ``artiq_run``).
|
determines which experiment to submit (consistent with ``artiq_run``).
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import PyQt5 # make sure pyqtgraph imports Qt5
|
import PyQt5 # make sure pyqtgraph imports Qt5
|
||||||
|
from PyQt5.QtCore import QTimer
|
||||||
import pyqtgraph
|
import pyqtgraph
|
||||||
|
|
||||||
from artiq.applets.simple import TitleApplet
|
from artiq.applets.simple import TitleApplet
|
||||||
|
@ -10,6 +11,9 @@ class HistogramPlot(pyqtgraph.PlotWidget):
|
||||||
def __init__(self, args):
|
def __init__(self, args):
|
||||||
pyqtgraph.PlotWidget.__init__(self)
|
pyqtgraph.PlotWidget.__init__(self)
|
||||||
self.args = args
|
self.args = args
|
||||||
|
self.timer = QTimer()
|
||||||
|
self.timer.setSingleShot(True)
|
||||||
|
self.timer.timeout.connect(self.length_warning)
|
||||||
|
|
||||||
def data_changed(self, data, mods, title):
|
def data_changed(self, data, mods, title):
|
||||||
try:
|
try:
|
||||||
|
@ -24,10 +28,20 @@ class HistogramPlot(pyqtgraph.PlotWidget):
|
||||||
x = list(range(len(y)+1))
|
x = list(range(len(y)+1))
|
||||||
|
|
||||||
if len(y) and len(x) == len(y) + 1:
|
if len(y) and len(x) == len(y) + 1:
|
||||||
|
self.timer.stop()
|
||||||
self.clear()
|
self.clear()
|
||||||
self.plot(x, y, stepMode=True, fillLevel=0,
|
self.plot(x, y, stepMode=True, fillLevel=0,
|
||||||
brush=(0, 0, 255, 150))
|
brush=(0, 0, 255, 150))
|
||||||
self.setTitle(title)
|
self.setTitle(title)
|
||||||
|
else:
|
||||||
|
if not self.timer.isActive():
|
||||||
|
self.timer.start(1000)
|
||||||
|
|
||||||
|
def length_warning(self):
|
||||||
|
self.clear()
|
||||||
|
text = "⚠️ dataset lengths mismatch:\n"\
|
||||||
|
"There should be one more bin boundaries than there are Y values"
|
||||||
|
self.addItem(pyqtgraph.TextItem(text))
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import PyQt5 # make sure pyqtgraph imports Qt5
|
import PyQt5 # make sure pyqtgraph imports Qt5
|
||||||
|
from PyQt5.QtCore import QTimer
|
||||||
import pyqtgraph
|
import pyqtgraph
|
||||||
|
|
||||||
from artiq.applets.simple import TitleApplet
|
from artiq.applets.simple import TitleApplet
|
||||||
|
@ -12,6 +13,12 @@ class XYPlot(pyqtgraph.PlotWidget):
|
||||||
def __init__(self, args):
|
def __init__(self, args):
|
||||||
pyqtgraph.PlotWidget.__init__(self)
|
pyqtgraph.PlotWidget.__init__(self)
|
||||||
self.args = args
|
self.args = args
|
||||||
|
self.timer = QTimer()
|
||||||
|
self.timer.setSingleShot(True)
|
||||||
|
self.timer.timeout.connect(self.length_warning)
|
||||||
|
self.mismatch = {'X values': False,
|
||||||
|
'Error bars': False,
|
||||||
|
'Fit values': False}
|
||||||
|
|
||||||
def data_changed(self, data, mods, title):
|
def data_changed(self, data, mods, title):
|
||||||
try:
|
try:
|
||||||
|
@ -25,16 +32,28 @@ class XYPlot(pyqtgraph.PlotWidget):
|
||||||
fit = data.get(self.args.fit, empty_dataset())["value"]
|
fit = data.get(self.args.fit, empty_dataset())["value"]
|
||||||
|
|
||||||
if not len(y) or len(y) != len(x):
|
if not len(y) or len(y) != len(x):
|
||||||
return
|
self.mismatch['X values'] = True
|
||||||
|
else:
|
||||||
|
self.mismatch['X values'] = False
|
||||||
if error is not None and hasattr(error, "__len__"):
|
if error is not None and hasattr(error, "__len__"):
|
||||||
if not len(error):
|
if not len(error):
|
||||||
error = None
|
error = None
|
||||||
elif len(error) != len(y):
|
elif len(error) != len(y):
|
||||||
return
|
self.mismatch['Error bars'] = True
|
||||||
|
else:
|
||||||
|
self.mismatch['Error bars'] = False
|
||||||
if fit is not None:
|
if fit is not None:
|
||||||
if not len(fit):
|
if not len(fit):
|
||||||
fit = None
|
fit = None
|
||||||
elif len(fit) != len(y):
|
elif len(fit) != len(y):
|
||||||
|
self.mismatch['Fit values'] = True
|
||||||
|
else:
|
||||||
|
self.mismatch['Fit values'] = False
|
||||||
|
if not any(self.mismatch.values()):
|
||||||
|
self.timer.stop()
|
||||||
|
else:
|
||||||
|
if not self.timer.isActive():
|
||||||
|
self.timer.start(1000)
|
||||||
return
|
return
|
||||||
|
|
||||||
self.clear()
|
self.clear()
|
||||||
|
@ -51,6 +70,13 @@ class XYPlot(pyqtgraph.PlotWidget):
|
||||||
xi = np.argsort(x)
|
xi = np.argsort(x)
|
||||||
self.plot(x[xi], fit[xi])
|
self.plot(x[xi], fit[xi])
|
||||||
|
|
||||||
|
def length_warning(self):
|
||||||
|
self.clear()
|
||||||
|
text = "⚠️ dataset lengths mismatch:\n"
|
||||||
|
errors = ', '.join([k for k, v in self.mismatch.items() if v])
|
||||||
|
text = ' '.join([errors, "should have the same length as Y values"])
|
||||||
|
self.addItem(pyqtgraph.TextItem(text))
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
applet = TitleApplet(XYPlot)
|
applet = TitleApplet(XYPlot)
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from PyQt5 import QtWidgets
|
from PyQt5 import QtWidgets
|
||||||
|
from PyQt5.QtCore import QTimer
|
||||||
import pyqtgraph
|
import pyqtgraph
|
||||||
|
|
||||||
from artiq.applets.simple import SimpleApplet
|
from artiq.applets.simple import SimpleApplet
|
||||||
|
@ -37,6 +38,10 @@ class XYHistPlot(QtWidgets.QSplitter):
|
||||||
self.hist_plot_data = None
|
self.hist_plot_data = None
|
||||||
|
|
||||||
self.args = args
|
self.args = args
|
||||||
|
self.timer = QTimer()
|
||||||
|
self.timer.setSingleShot(True)
|
||||||
|
self.timer.timeout.connect(self.length_warning)
|
||||||
|
self.mismatch = {'bins': False, 'xs': False}
|
||||||
|
|
||||||
def _set_full_data(self, xs, histogram_bins, histograms_counts):
|
def _set_full_data(self, xs, histogram_bins, histograms_counts):
|
||||||
self.xy_plot.clear()
|
self.xy_plot.clear()
|
||||||
|
@ -59,9 +64,9 @@ class XYHistPlot(QtWidgets.QSplitter):
|
||||||
point.histogram_index = index
|
point.histogram_index = index
|
||||||
point.histogram_counts = counts
|
point.histogram_counts = counts
|
||||||
|
|
||||||
self.hist_plot_data = self.hist_plot.plot(
|
text = "click on a data point at the left\n"\
|
||||||
stepMode=True, fillLevel=0,
|
"to see the corresponding histogram"
|
||||||
brush=(0, 0, 255, 150))
|
self.hist_plot.addItem(pyqtgraph.TextItem(text))
|
||||||
|
|
||||||
def _set_partial_data(self, xs, histograms_counts):
|
def _set_partial_data(self, xs, histograms_counts):
|
||||||
ys = _compute_ys(self.histogram_bins, histograms_counts)
|
ys = _compute_ys(self.histogram_bins, histograms_counts)
|
||||||
|
@ -87,6 +92,15 @@ class XYHistPlot(QtWidgets.QSplitter):
|
||||||
else:
|
else:
|
||||||
self.arrow.setPos(position)
|
self.arrow.setPos(position)
|
||||||
self.selected_index = spot_item.histogram_index
|
self.selected_index = spot_item.histogram_index
|
||||||
|
|
||||||
|
if self.hist_plot_data is None:
|
||||||
|
self.hist_plot.clear()
|
||||||
|
self.hist_plot_data = self.hist_plot.plot(
|
||||||
|
x=self.histogram_bins,
|
||||||
|
y=spot_item.histogram_counts,
|
||||||
|
stepMode=True, fillLevel=0,
|
||||||
|
brush=(0, 0, 255, 150))
|
||||||
|
else:
|
||||||
self.hist_plot_data.setData(x=self.histogram_bins,
|
self.hist_plot_data.setData(x=self.histogram_bins,
|
||||||
y=spot_item.histogram_counts)
|
y=spot_item.histogram_counts)
|
||||||
|
|
||||||
|
@ -117,11 +131,41 @@ class XYHistPlot(QtWidgets.QSplitter):
|
||||||
histograms_counts = data[self.args.histograms_counts]["value"]
|
histograms_counts = data[self.args.histograms_counts]["value"]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return
|
return
|
||||||
|
if len(xs) != histograms_counts.shape[0]:
|
||||||
|
self.mismatch['xs'] = True
|
||||||
|
else:
|
||||||
|
self.mismatch['xs'] = False
|
||||||
|
if histograms_counts.shape[1] != len(histogram_bins) - 1:
|
||||||
|
self.mismatch['bins'] = True
|
||||||
|
else:
|
||||||
|
self.mismatch['bins'] = False
|
||||||
|
if any(self.mismatch.values()):
|
||||||
|
if not self.timer.isActive():
|
||||||
|
self.timer.start(1000)
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
self.timer.stop()
|
||||||
if self._can_use_partial(mods):
|
if self._can_use_partial(mods):
|
||||||
self._set_partial_data(xs, histograms_counts)
|
self._set_partial_data(xs, histograms_counts)
|
||||||
else:
|
else:
|
||||||
self._set_full_data(xs, histogram_bins, histograms_counts)
|
self._set_full_data(xs, histogram_bins, histograms_counts)
|
||||||
|
|
||||||
|
def length_warning(self):
|
||||||
|
self.xy_plot.clear()
|
||||||
|
self.hist_plot.clear()
|
||||||
|
text = "⚠️ dataset lengths mismatch:\n\n"
|
||||||
|
if self.mismatch['bins']:
|
||||||
|
text = ''.join([text,
|
||||||
|
"bin boundaries should have the same length\n"
|
||||||
|
"as the first dimension of histogram counts."])
|
||||||
|
if self.mismatch['bins'] and self.mismatch['xs']:
|
||||||
|
text = ''.join([text, '\n\n'])
|
||||||
|
if self.mismatch['xs']:
|
||||||
|
text = ''.join([text,
|
||||||
|
"point abscissas should have the same length\n"
|
||||||
|
"as the second dimension of histogram counts."])
|
||||||
|
self.xy_plot.addItem(pyqtgraph.TextItem(text))
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
applet = SimpleApplet(XYHistPlot)
|
applet = SimpleApplet(XYHistPlot)
|
||||||
|
|
|
@ -2,6 +2,7 @@ import os
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from migen import *
|
from migen import *
|
||||||
|
from migen.build.platforms.sinara import kasli
|
||||||
from misoc.interconnect.csr import *
|
from misoc.interconnect.csr import *
|
||||||
from misoc.integration.builder import *
|
from misoc.integration.builder import *
|
||||||
|
|
||||||
|
@ -57,11 +58,17 @@ def build_artiq_soc(soc, argdict):
|
||||||
builder = Builder(soc, **argdict)
|
builder = Builder(soc, **argdict)
|
||||||
builder.software_packages = []
|
builder.software_packages = []
|
||||||
builder.add_software_package("bootloader", os.path.join(firmware_dir, "bootloader"))
|
builder.add_software_package("bootloader", os.path.join(firmware_dir, "bootloader"))
|
||||||
|
is_kasli_v1 = isinstance(soc.platform, kasli.Platform) and soc.platform.hw_rev in ("v1.0", "v1.1")
|
||||||
if isinstance(soc, AMPSoC):
|
if isinstance(soc, AMPSoC):
|
||||||
builder.add_software_package("libm")
|
kernel_cpu_type = "vexriscv" if is_kasli_v1 else "vexriscv-g"
|
||||||
builder.add_software_package("libprintf")
|
builder.add_software_package("libm", cpu_type=kernel_cpu_type)
|
||||||
|
builder.add_software_package("libprintf", cpu_type=kernel_cpu_type)
|
||||||
|
builder.add_software_package("libunwind", cpu_type=kernel_cpu_type)
|
||||||
|
builder.add_software_package("ksupport", os.path.join(firmware_dir, "ksupport"), cpu_type=kernel_cpu_type)
|
||||||
|
# Generate unwinder for soft float target (ARTIQ runtime)
|
||||||
|
# If the kernel lacks FPU, then the runtime unwinder is already generated
|
||||||
|
if not is_kasli_v1:
|
||||||
builder.add_software_package("libunwind")
|
builder.add_software_package("libunwind")
|
||||||
builder.add_software_package("ksupport", os.path.join(firmware_dir, "ksupport"))
|
|
||||||
builder.add_software_package("runtime", os.path.join(firmware_dir, "runtime"))
|
builder.add_software_package("runtime", os.path.join(firmware_dir, "runtime"))
|
||||||
else:
|
else:
|
||||||
# Assume DRTIO satellite.
|
# Assume DRTIO satellite.
|
||||||
|
|
|
@ -5,7 +5,7 @@ the references to the host objects and translates the functions
|
||||||
annotated as ``@kernel`` when they are referenced.
|
annotated as ``@kernel`` when they are referenced.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys, os, re, linecache, inspect, textwrap, types as pytypes, numpy
|
import os, re, linecache, inspect, textwrap, types as pytypes, numpy
|
||||||
from collections import OrderedDict, defaultdict
|
from collections import OrderedDict, defaultdict
|
||||||
|
|
||||||
from pythonparser import ast, algorithm, source, diagnostic, parse_buffer
|
from pythonparser import ast, algorithm, source, diagnostic, parse_buffer
|
||||||
|
@ -156,6 +156,67 @@ class ASTSynthesizer:
|
||||||
return source.Range(self.source_buffer, range_from, range_to,
|
return source.Range(self.source_buffer, range_from, range_to,
|
||||||
expanded_from=self.expanded_from)
|
expanded_from=self.expanded_from)
|
||||||
|
|
||||||
|
def fast_quote_list(self, value):
|
||||||
|
elts = [None] * len(value)
|
||||||
|
is_T = False
|
||||||
|
if len(value) > 0:
|
||||||
|
v = value[0]
|
||||||
|
is_T = True
|
||||||
|
if isinstance(v, int):
|
||||||
|
T = int
|
||||||
|
elif isinstance(v, float):
|
||||||
|
T = float
|
||||||
|
elif isinstance(v, numpy.int32):
|
||||||
|
T = numpy.int32
|
||||||
|
elif isinstance(v, numpy.int64):
|
||||||
|
T = numpy.int64
|
||||||
|
else:
|
||||||
|
is_T = False
|
||||||
|
if is_T:
|
||||||
|
for v in value:
|
||||||
|
if not isinstance(v, T):
|
||||||
|
is_T = False
|
||||||
|
break
|
||||||
|
if is_T:
|
||||||
|
is_int = T != float
|
||||||
|
if T == int:
|
||||||
|
typ = builtins.TInt()
|
||||||
|
elif T == float:
|
||||||
|
typ = builtins.TFloat()
|
||||||
|
elif T == numpy.int32:
|
||||||
|
typ = builtins.TInt32()
|
||||||
|
elif T == numpy.int64:
|
||||||
|
typ = builtins.TInt64()
|
||||||
|
else:
|
||||||
|
assert False
|
||||||
|
text = [repr(elt) for elt in value]
|
||||||
|
start = len(self.source)
|
||||||
|
self.source += ", ".join(text)
|
||||||
|
if is_int:
|
||||||
|
for i, (v, t) in enumerate(zip(value, text)):
|
||||||
|
l = len(t)
|
||||||
|
elts[i] = asttyped.NumT(
|
||||||
|
n=int(v), ctx=None, type=typ,
|
||||||
|
loc=source.Range(
|
||||||
|
self.source_buffer, start, start + l,
|
||||||
|
expanded_from=self.expanded_from))
|
||||||
|
start += l + 2
|
||||||
|
else:
|
||||||
|
for i, (v, t) in enumerate(zip(value, text)):
|
||||||
|
l = len(t)
|
||||||
|
elts[i] = asttyped.NumT(
|
||||||
|
n=v, ctx=None, type=typ,
|
||||||
|
loc=source.Range(
|
||||||
|
self.source_buffer, start, start + l,
|
||||||
|
expanded_from=self.expanded_from))
|
||||||
|
start += l + 2
|
||||||
|
else:
|
||||||
|
for index, elt in enumerate(value):
|
||||||
|
elts[index] = self.quote(elt)
|
||||||
|
if index < len(value) - 1:
|
||||||
|
self._add(", ")
|
||||||
|
return elts
|
||||||
|
|
||||||
def quote(self, value):
|
def quote(self, value):
|
||||||
"""Construct an AST fragment equal to `value`."""
|
"""Construct an AST fragment equal to `value`."""
|
||||||
if value is None:
|
if value is None:
|
||||||
|
@ -217,21 +278,14 @@ class ASTSynthesizer:
|
||||||
return asttyped.QuoteT(value=value, type=builtins.TByteArray(), loc=loc)
|
return asttyped.QuoteT(value=value, type=builtins.TByteArray(), loc=loc)
|
||||||
elif isinstance(value, list):
|
elif isinstance(value, list):
|
||||||
begin_loc = self._add("[")
|
begin_loc = self._add("[")
|
||||||
elts = []
|
elts = self.fast_quote_list(value)
|
||||||
for index, elt in enumerate(value):
|
|
||||||
elts.append(self.quote(elt))
|
|
||||||
if index < len(value) - 1:
|
|
||||||
self._add(", ")
|
|
||||||
end_loc = self._add("]")
|
end_loc = self._add("]")
|
||||||
return asttyped.ListT(elts=elts, ctx=None, type=builtins.TList(),
|
return asttyped.ListT(elts=elts, ctx=None, type=builtins.TList(),
|
||||||
begin_loc=begin_loc, end_loc=end_loc,
|
begin_loc=begin_loc, end_loc=end_loc,
|
||||||
loc=begin_loc.join(end_loc))
|
loc=begin_loc.join(end_loc))
|
||||||
elif isinstance(value, tuple):
|
elif isinstance(value, tuple):
|
||||||
begin_loc = self._add("(")
|
begin_loc = self._add("(")
|
||||||
elts = []
|
elts = self.fast_quote_list(value)
|
||||||
for index, elt in enumerate(value):
|
|
||||||
elts.append(self.quote(elt))
|
|
||||||
self._add(", ")
|
|
||||||
end_loc = self._add(")")
|
end_loc = self._add(")")
|
||||||
return asttyped.TupleT(elts=elts, ctx=None,
|
return asttyped.TupleT(elts=elts, ctx=None,
|
||||||
type=types.TTuple([e.type for e in elts]),
|
type=types.TTuple([e.type for e in elts]),
|
||||||
|
@ -683,6 +737,7 @@ class Stitcher:
|
||||||
|
|
||||||
self.embedding_map = EmbeddingMap()
|
self.embedding_map = EmbeddingMap()
|
||||||
self.value_map = defaultdict(lambda: [])
|
self.value_map = defaultdict(lambda: [])
|
||||||
|
self.definitely_changed = False
|
||||||
|
|
||||||
def stitch_call(self, function, args, kwargs, callback=None):
|
def stitch_call(self, function, args, kwargs, callback=None):
|
||||||
# We synthesize source code for the initial call so that
|
# We synthesize source code for the initial call so that
|
||||||
|
@ -703,14 +758,20 @@ class Stitcher:
|
||||||
old_attr_count = None
|
old_attr_count = None
|
||||||
while True:
|
while True:
|
||||||
inferencer.visit(self.typedtree)
|
inferencer.visit(self.typedtree)
|
||||||
|
if self.definitely_changed:
|
||||||
|
changed = True
|
||||||
|
self.definitely_changed = False
|
||||||
|
else:
|
||||||
typedtree_hash = typedtree_hasher.visit(self.typedtree)
|
typedtree_hash = typedtree_hasher.visit(self.typedtree)
|
||||||
attr_count = self.embedding_map.attribute_count()
|
attr_count = self.embedding_map.attribute_count()
|
||||||
|
changed = old_attr_count != attr_count or \
|
||||||
if old_typedtree_hash == typedtree_hash and old_attr_count == attr_count:
|
old_typedtree_hash != typedtree_hash
|
||||||
break
|
|
||||||
old_typedtree_hash = typedtree_hash
|
old_typedtree_hash = typedtree_hash
|
||||||
old_attr_count = attr_count
|
old_attr_count = attr_count
|
||||||
|
|
||||||
|
if not changed:
|
||||||
|
break
|
||||||
|
|
||||||
# After we've discovered every referenced attribute, check if any kernel_invariant
|
# After we've discovered every referenced attribute, check if any kernel_invariant
|
||||||
# specifications refers to ones we didn't encounter.
|
# specifications refers to ones we didn't encounter.
|
||||||
for host_type in self.embedding_map.type_map:
|
for host_type in self.embedding_map.type_map:
|
||||||
|
@ -837,6 +898,9 @@ class Stitcher:
|
||||||
return types.TVar()
|
return types.TVar()
|
||||||
|
|
||||||
def _quote_embedded_function(self, function, flags):
|
def _quote_embedded_function(self, function, flags):
|
||||||
|
# we are now parsing new functions... definitely changed the type
|
||||||
|
self.definitely_changed = True
|
||||||
|
|
||||||
if isinstance(function, SpecializedFunction):
|
if isinstance(function, SpecializedFunction):
|
||||||
host_function = function.host_function
|
host_function = function.host_function
|
||||||
else:
|
else:
|
||||||
|
@ -903,13 +967,11 @@ class Stitcher:
|
||||||
|
|
||||||
# Parse.
|
# Parse.
|
||||||
source_buffer = source.Buffer(source_code, filename, first_line)
|
source_buffer = source.Buffer(source_code, filename, first_line)
|
||||||
lexer = source_lexer.Lexer(source_buffer, version=sys.version_info[0:2],
|
lexer = source_lexer.Lexer(source_buffer, version=(3, 6), diagnostic_engine=self.engine)
|
||||||
diagnostic_engine=self.engine)
|
|
||||||
lexer.indent = [(initial_indent,
|
lexer.indent = [(initial_indent,
|
||||||
source.Range(source_buffer, 0, len(initial_whitespace)),
|
source.Range(source_buffer, 0, len(initial_whitespace)),
|
||||||
initial_whitespace)]
|
initial_whitespace)]
|
||||||
parser = source_parser.Parser(lexer, version=sys.version_info[0:2],
|
parser = source_parser.Parser(lexer, version=(3, 6), diagnostic_engine=self.engine)
|
||||||
diagnostic_engine=self.engine)
|
|
||||||
function_node = parser.file_input().body[0]
|
function_node = parser.file_input().body[0]
|
||||||
|
|
||||||
# Mangle the name, since we put everything into a single module.
|
# Mangle the name, since we put everything into a single module.
|
||||||
|
@ -949,6 +1011,31 @@ class Stitcher:
|
||||||
if annot is None:
|
if annot is None:
|
||||||
annot = builtins.TNone()
|
annot = builtins.TNone()
|
||||||
|
|
||||||
|
if isinstance(function, SpecializedFunction):
|
||||||
|
host_function = function.host_function
|
||||||
|
else:
|
||||||
|
host_function = function
|
||||||
|
|
||||||
|
if hasattr(host_function, 'artiq_embedded'):
|
||||||
|
embedded_function = host_function.artiq_embedded.function
|
||||||
|
else:
|
||||||
|
embedded_function = host_function
|
||||||
|
|
||||||
|
if isinstance(embedded_function, str):
|
||||||
|
embedded_function = host_function
|
||||||
|
|
||||||
|
if isinstance(annot, str):
|
||||||
|
try:
|
||||||
|
annot = eval(annot, embedded_function.__globals__)
|
||||||
|
except Exception:
|
||||||
|
diag = diagnostic.Diagnostic(
|
||||||
|
"error",
|
||||||
|
"type annotation for {kind}, {annot}, cannot be evaluated",
|
||||||
|
{"kind": kind, "annot": repr(annot)},
|
||||||
|
self._function_loc(function),
|
||||||
|
notes=self._call_site_note(call_loc, fn_kind))
|
||||||
|
self.engine.process(diag)
|
||||||
|
|
||||||
if not isinstance(annot, types.Type):
|
if not isinstance(annot, types.Type):
|
||||||
diag = diagnostic.Diagnostic("error",
|
diag = diagnostic.Diagnostic("error",
|
||||||
"type annotation for {kind}, '{annot}', is not an ARTIQ type",
|
"type annotation for {kind}, '{annot}', is not an ARTIQ type",
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
/* Force ld to make the ELF header as loadable. */
|
||||||
|
PHDRS
|
||||||
|
{
|
||||||
|
headers PT_LOAD FILEHDR PHDRS ;
|
||||||
|
text PT_LOAD ;
|
||||||
|
data PT_LOAD ;
|
||||||
|
dynamic PT_DYNAMIC ;
|
||||||
|
eh_frame PT_GNU_EH_FRAME ;
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
/* Push back .text section enough so that ld.lld not complain */
|
||||||
|
. = SIZEOF_HEADERS;
|
||||||
|
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
*(.text .text.*)
|
||||||
|
} : text
|
||||||
|
|
||||||
|
.rodata :
|
||||||
|
{
|
||||||
|
*(.rodata .rodata.*)
|
||||||
|
}
|
||||||
|
|
||||||
|
.eh_frame :
|
||||||
|
{
|
||||||
|
KEEP(*(.eh_frame))
|
||||||
|
} : text
|
||||||
|
|
||||||
|
.eh_frame_hdr :
|
||||||
|
{
|
||||||
|
KEEP(*(.eh_frame_hdr))
|
||||||
|
} : text : eh_frame
|
||||||
|
|
||||||
|
.data :
|
||||||
|
{
|
||||||
|
*(.data)
|
||||||
|
} : data
|
||||||
|
|
||||||
|
.dynamic :
|
||||||
|
{
|
||||||
|
*(.dynamic)
|
||||||
|
} : data : dynamic
|
||||||
|
|
||||||
|
.bss (NOLOAD) : ALIGN(4)
|
||||||
|
{
|
||||||
|
__bss_start = .;
|
||||||
|
*(.sbss .sbss.* .bss .bss.*);
|
||||||
|
. = ALIGN(4);
|
||||||
|
_end = .;
|
||||||
|
}
|
||||||
|
|
||||||
|
. = ALIGN(0x1000);
|
||||||
|
_sstack_guard = .;
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
import os, sys, tempfile, subprocess, io
|
import os, sys, tempfile, subprocess, io
|
||||||
from artiq.compiler import types, ir
|
from artiq.compiler import types, ir
|
||||||
from llvmlite_artiq import ir as ll, binding as llvm
|
from llvmlite import ir as ll, binding as llvm
|
||||||
|
|
||||||
llvm.initialize()
|
llvm.initialize()
|
||||||
llvm.initialize_all_targets()
|
llvm.initialize_all_targets()
|
||||||
|
@ -28,8 +28,10 @@ class RunTool:
|
||||||
for argument in self._pattern:
|
for argument in self._pattern:
|
||||||
cmdline.append(argument.format(**self._tempnames))
|
cmdline.append(argument.format(**self._tempnames))
|
||||||
|
|
||||||
|
# https://bugs.python.org/issue17023
|
||||||
|
windows = os.name == "nt"
|
||||||
process = subprocess.Popen(cmdline, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
process = subprocess.Popen(cmdline, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
||||||
universal_newlines=True)
|
universal_newlines=True, shell=windows)
|
||||||
stdout, stderr = process.communicate()
|
stdout, stderr = process.communicate()
|
||||||
if process.returncode != 0:
|
if process.returncode != 0:
|
||||||
raise Exception("{} invocation failed: {}".
|
raise Exception("{} invocation failed: {}".
|
||||||
|
@ -67,7 +69,7 @@ class Target:
|
||||||
generated by the ARTIQ compiler will be deployed.
|
generated by the ARTIQ compiler will be deployed.
|
||||||
|
|
||||||
:var triple: (string)
|
:var triple: (string)
|
||||||
LLVM target triple, e.g. ``"or1k"``
|
LLVM target triple, e.g. ``"riscv32"``
|
||||||
:var data_layout: (string)
|
:var data_layout: (string)
|
||||||
LLVM target data layout, e.g. ``"E-m:e-p:32:32-i64:32-f64:32-v64:32-v128:32-a:0:32-n32"``
|
LLVM target data layout, e.g. ``"E-m:e-p:32:32-i64:32-f64:32-v64:32-v128:32-a:0:32-n32"``
|
||||||
:var features: (list of string)
|
:var features: (list of string)
|
||||||
|
@ -75,9 +77,6 @@ class Target:
|
||||||
:var print_function: (string)
|
:var print_function: (string)
|
||||||
Name of a formatted print functions (with the signature of ``printf``)
|
Name of a formatted print functions (with the signature of ``printf``)
|
||||||
provided by the target, e.g. ``"printf"``.
|
provided by the target, e.g. ``"printf"``.
|
||||||
:var little_endian: (boolean)
|
|
||||||
Whether the code will be executed on a little-endian machine. This cannot be always
|
|
||||||
determined from data_layout due to JIT.
|
|
||||||
:var now_pinning: (boolean)
|
:var now_pinning: (boolean)
|
||||||
Whether the target implements the now-pinning RTIO optimization.
|
Whether the target implements the now-pinning RTIO optimization.
|
||||||
"""
|
"""
|
||||||
|
@ -85,7 +84,6 @@ class Target:
|
||||||
data_layout = ""
|
data_layout = ""
|
||||||
features = []
|
features = []
|
||||||
print_function = "printf"
|
print_function = "printf"
|
||||||
little_endian = False
|
|
||||||
now_pinning = True
|
now_pinning = True
|
||||||
|
|
||||||
tool_ld = "ld.lld"
|
tool_ld = "ld.lld"
|
||||||
|
@ -100,7 +98,8 @@ class Target:
|
||||||
lltarget = llvm.Target.from_triple(self.triple)
|
lltarget = llvm.Target.from_triple(self.triple)
|
||||||
llmachine = lltarget.create_target_machine(
|
llmachine = lltarget.create_target_machine(
|
||||||
features=",".join(["+{}".format(f) for f in self.features]),
|
features=",".join(["+{}".format(f) for f in self.features]),
|
||||||
reloc="pic", codemodel="default")
|
reloc="pic", codemodel="default",
|
||||||
|
abiname="ilp32d" if isinstance(self, RV32GTarget) else "")
|
||||||
llmachine.set_asm_verbosity(True)
|
llmachine.set_asm_verbosity(True)
|
||||||
return llmachine
|
return llmachine
|
||||||
|
|
||||||
|
@ -182,6 +181,7 @@ class Target:
|
||||||
def link(self, objects):
|
def link(self, objects):
|
||||||
"""Link the relocatable objects into a shared library for this target."""
|
"""Link the relocatable objects into a shared library for this target."""
|
||||||
with RunTool([self.tool_ld, "-shared", "--eh-frame-hdr"] +
|
with RunTool([self.tool_ld, "-shared", "--eh-frame-hdr"] +
|
||||||
|
["-T" + os.path.join(os.path.dirname(__file__), "kernel.ld")] +
|
||||||
["{{obj{}}}".format(index) for index in range(len(objects))] +
|
["{{obj{}}}".format(index) for index in range(len(objects))] +
|
||||||
["-x"] +
|
["-x"] +
|
||||||
["-o", "{output}"],
|
["-o", "{output}"],
|
||||||
|
@ -252,32 +252,39 @@ class NativeTarget(Target):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.triple = llvm.get_default_triple()
|
self.triple = llvm.get_default_triple()
|
||||||
host_data_layout = str(llvm.targets.Target.from_default_triple().create_target_machine().target_data)
|
host_data_layout = str(llvm.targets.Target.from_default_triple().create_target_machine().target_data)
|
||||||
assert host_data_layout[0] in "eE"
|
|
||||||
self.little_endian = host_data_layout[0] == "e"
|
|
||||||
|
|
||||||
class OR1KTarget(Target):
|
class RV32IMATarget(Target):
|
||||||
triple = "or1k-linux"
|
triple = "riscv32-unknown-linux"
|
||||||
data_layout = "E-m:e-p:32:32-i8:8:8-i16:16:16-i64:32:32-" \
|
data_layout = "e-m:e-p:32:32-i64:64-n32-S128"
|
||||||
"f64:32:32-v64:32:32-v128:32:32-a0:0:32-n32"
|
features = ["m", "a"]
|
||||||
features = ["mul", "div", "ffl1", "cmov", "addc"]
|
|
||||||
print_function = "core_log"
|
print_function = "core_log"
|
||||||
little_endian = False
|
|
||||||
now_pinning = True
|
now_pinning = True
|
||||||
|
|
||||||
tool_ld = "or1k-linux-ld"
|
tool_ld = "ld.lld"
|
||||||
tool_strip = "or1k-linux-strip"
|
tool_strip = "llvm-strip"
|
||||||
tool_addr2line = "or1k-linux-addr2line"
|
tool_addr2line = "llvm-addr2line"
|
||||||
tool_cxxfilt = "or1k-linux-c++filt"
|
tool_cxxfilt = "llvm-cxxfilt"
|
||||||
|
|
||||||
|
class RV32GTarget(Target):
|
||||||
|
triple = "riscv32-unknown-linux"
|
||||||
|
data_layout = "e-m:e-p:32:32-i64:64-n32-S128"
|
||||||
|
features = ["m", "a", "f", "d"]
|
||||||
|
print_function = "core_log"
|
||||||
|
now_pinning = True
|
||||||
|
|
||||||
|
tool_ld = "ld.lld"
|
||||||
|
tool_strip = "llvm-strip"
|
||||||
|
tool_addr2line = "llvm-addr2line"
|
||||||
|
tool_cxxfilt = "llvm-cxxfilt"
|
||||||
|
|
||||||
class CortexA9Target(Target):
|
class CortexA9Target(Target):
|
||||||
triple = "armv7-unknown-linux-gnueabihf"
|
triple = "armv7-unknown-linux-gnueabihf"
|
||||||
data_layout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
|
data_layout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
|
||||||
features = ["dsp", "fp16", "neon", "vfp3"]
|
features = ["dsp", "fp16", "neon", "vfp3"]
|
||||||
print_function = "core_log"
|
print_function = "core_log"
|
||||||
little_endian = True
|
|
||||||
now_pinning = False
|
now_pinning = False
|
||||||
|
|
||||||
tool_ld = "armv7-unknown-linux-gnueabihf-ld"
|
tool_ld = "ld.lld"
|
||||||
tool_strip = "armv7-unknown-linux-gnueabihf-strip"
|
tool_strip = "llvm-strip"
|
||||||
tool_addr2line = "armv7-unknown-linux-gnueabihf-addr2line"
|
tool_addr2line = "llvm-addr2line"
|
||||||
tool_cxxfilt = "armv7-unknown-linux-gnueabihf-c++filt"
|
tool_cxxfilt = "llvm-cxxfilt"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import os, sys, fileinput, ctypes
|
import os, sys, fileinput, ctypes
|
||||||
from pythonparser import diagnostic
|
from pythonparser import diagnostic
|
||||||
from llvmlite_artiq import binding as llvm
|
from llvmlite import binding as llvm
|
||||||
from ..module import Module, Source
|
from ..module import Module, Source
|
||||||
from ..targets import NativeTarget
|
from ..targets import NativeTarget
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import sys, fileinput
|
import sys, fileinput
|
||||||
from pythonparser import diagnostic
|
from pythonparser import diagnostic
|
||||||
from llvmlite_artiq import ir as ll
|
from llvmlite import ir as ll
|
||||||
from ..module import Module, Source
|
from ..module import Module, Source
|
||||||
from ..targets import NativeTarget
|
from ..targets import NativeTarget
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import sys, os
|
import sys, os
|
||||||
from pythonparser import diagnostic
|
from pythonparser import diagnostic
|
||||||
from ..module import Module, Source
|
from ..module import Module, Source
|
||||||
from ..targets import OR1KTarget
|
from ..targets import RV32GTarget
|
||||||
from . import benchmark
|
from . import benchmark
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
@ -30,7 +30,7 @@ def main():
|
||||||
benchmark(lambda: Module(source),
|
benchmark(lambda: Module(source),
|
||||||
"ARTIQ transforms and validators")
|
"ARTIQ transforms and validators")
|
||||||
|
|
||||||
benchmark(lambda: OR1KTarget().compile_and_link([module]),
|
benchmark(lambda: RV32GTarget().compile_and_link([module]),
|
||||||
"LLVM optimization and linking")
|
"LLVM optimization and linking")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
@ -5,7 +5,7 @@ from ...master.databases import DeviceDB, DatasetDB
|
||||||
from ...master.worker_db import DeviceManager, DatasetManager
|
from ...master.worker_db import DeviceManager, DatasetManager
|
||||||
from ..module import Module
|
from ..module import Module
|
||||||
from ..embedding import Stitcher
|
from ..embedding import Stitcher
|
||||||
from ..targets import OR1KTarget
|
from ..targets import RV32GTarget
|
||||||
from . import benchmark
|
from . import benchmark
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ def main():
|
||||||
|
|
||||||
stitcher = embed()
|
stitcher = embed()
|
||||||
module = Module(stitcher)
|
module = Module(stitcher)
|
||||||
target = OR1KTarget()
|
target = RV32GTarget()
|
||||||
llvm_ir = target.compile(module)
|
llvm_ir = target.compile(module)
|
||||||
elf_obj = target.assemble(llvm_ir)
|
elf_obj = target.assemble(llvm_ir)
|
||||||
elf_shlib = target.link([elf_obj])
|
elf_shlib = target.link([elf_obj])
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import sys, os
|
import sys, os
|
||||||
from pythonparser import diagnostic
|
from pythonparser import diagnostic
|
||||||
from ..module import Module, Source
|
from ..module import Module, Source
|
||||||
from ..targets import OR1KTarget
|
from ..targets import RV32GTarget
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
if not len(sys.argv) > 1:
|
if not len(sys.argv) > 1:
|
||||||
|
@ -20,7 +20,7 @@ def main():
|
||||||
for filename in sys.argv[1:]:
|
for filename in sys.argv[1:]:
|
||||||
modules.append(Module(Source.from_filename(filename, engine=engine)))
|
modules.append(Module(Source.from_filename(filename, engine=engine)))
|
||||||
|
|
||||||
llobj = OR1KTarget().compile_and_link(modules)
|
llobj = RV32GTarget().compile_and_link(modules)
|
||||||
|
|
||||||
basename, ext = os.path.splitext(sys.argv[-1])
|
basename, ext = os.path.splitext(sys.argv[-1])
|
||||||
with open(basename + ".so", "wb") as f:
|
with open(basename + ".so", "wb") as f:
|
||||||
|
|
|
@ -6,6 +6,7 @@ from collections import OrderedDict
|
||||||
from pythonparser import algorithm, diagnostic, ast
|
from pythonparser import algorithm, diagnostic, ast
|
||||||
from .. import asttyped, types, builtins
|
from .. import asttyped, types, builtins
|
||||||
from .typedtree_printer import TypedtreePrinter
|
from .typedtree_printer import TypedtreePrinter
|
||||||
|
from artiq.experiment import kernel
|
||||||
|
|
||||||
|
|
||||||
def is_nested_empty_list(node):
|
def is_nested_empty_list(node):
|
||||||
|
@ -1662,7 +1663,14 @@ class Inferencer(algorithm.Visitor):
|
||||||
|
|
||||||
def visit_FunctionDefT(self, node):
|
def visit_FunctionDefT(self, node):
|
||||||
for index, decorator in enumerate(node.decorator_list):
|
for index, decorator in enumerate(node.decorator_list):
|
||||||
if types.is_builtin(decorator.type, "kernel") or \
|
def eval_attr(attr):
|
||||||
|
if isinstance(attr.value, asttyped.QuoteT):
|
||||||
|
return getattr(attr.value.value, attr.attr)
|
||||||
|
return getattr(eval_attr(attr.value), attr.attr)
|
||||||
|
if isinstance(decorator, asttyped.AttributeT):
|
||||||
|
decorator = eval_attr(decorator)
|
||||||
|
if id(decorator) == id(kernel) or \
|
||||||
|
types.is_builtin(decorator.type, "kernel") or \
|
||||||
isinstance(decorator, asttyped.CallT) and \
|
isinstance(decorator, asttyped.CallT) and \
|
||||||
types.is_builtin(decorator.func.type, "kernel"):
|
types.is_builtin(decorator.func.type, "kernel"):
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -6,10 +6,11 @@ into LLVM intermediate representation.
|
||||||
import os, re, types as pytypes, numpy
|
import os, re, types as pytypes, numpy
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from pythonparser import ast, diagnostic
|
from pythonparser import ast, diagnostic
|
||||||
from llvmlite_artiq import ir as ll, binding as llvm
|
from llvmlite import ir as ll, binding as llvm
|
||||||
from ...language import core as language_core
|
from ...language import core as language_core
|
||||||
from .. import types, builtins, ir
|
from .. import types, builtins, ir
|
||||||
from ..embedding import SpecializedFunction
|
from ..embedding import SpecializedFunction
|
||||||
|
from artiq.compiler.targets import RV32GTarget
|
||||||
|
|
||||||
|
|
||||||
llvoid = ll.VoidType()
|
llvoid = ll.VoidType()
|
||||||
|
@ -37,93 +38,6 @@ def memoize(generator):
|
||||||
return result
|
return result
|
||||||
return memoized
|
return memoized
|
||||||
|
|
||||||
class DebugInfoEmitter:
|
|
||||||
def __init__(self, llmodule):
|
|
||||||
self.llmodule = llmodule
|
|
||||||
self.llcompileunit = None
|
|
||||||
self.cache = {}
|
|
||||||
|
|
||||||
llident = self.llmodule.add_named_metadata('llvm.ident')
|
|
||||||
llident.add(self.emit_metadata(["ARTIQ"]))
|
|
||||||
|
|
||||||
llflags = self.llmodule.add_named_metadata('llvm.module.flags')
|
|
||||||
llflags.add(self.emit_metadata([2, "Debug Info Version", 3]))
|
|
||||||
llflags.add(self.emit_metadata([2, "Dwarf Version", 4]))
|
|
||||||
|
|
||||||
def emit_metadata(self, operands):
|
|
||||||
def map_operand(operand):
|
|
||||||
if operand is None:
|
|
||||||
return ll.Constant(llmetadata, None)
|
|
||||||
elif isinstance(operand, str):
|
|
||||||
return ll.MetaDataString(self.llmodule, operand)
|
|
||||||
elif isinstance(operand, int):
|
|
||||||
return ll.Constant(lli32, operand)
|
|
||||||
elif isinstance(operand, (list, tuple)):
|
|
||||||
return self.emit_metadata(operand)
|
|
||||||
else:
|
|
||||||
assert isinstance(operand, ll.NamedValue)
|
|
||||||
return operand
|
|
||||||
return self.llmodule.add_metadata(list(map(map_operand, operands)))
|
|
||||||
|
|
||||||
def emit_debug_info(self, kind, operands, is_distinct=False):
|
|
||||||
return self.llmodule.add_debug_info(kind, operands, is_distinct)
|
|
||||||
|
|
||||||
@memoize
|
|
||||||
def emit_file(self, source_buffer):
|
|
||||||
source_dir, source_file = os.path.split(source_buffer.name)
|
|
||||||
return self.emit_debug_info("DIFile", {
|
|
||||||
"filename": source_file,
|
|
||||||
"directory": source_dir,
|
|
||||||
})
|
|
||||||
|
|
||||||
@memoize
|
|
||||||
def emit_compile_unit(self, source_buffer):
|
|
||||||
return self.emit_debug_info("DICompileUnit", {
|
|
||||||
"language": ll.DIToken("DW_LANG_Python"),
|
|
||||||
"file": self.emit_file(source_buffer),
|
|
||||||
"producer": "ARTIQ",
|
|
||||||
"runtimeVersion": 0,
|
|
||||||
"emissionKind": 2, # full=1, lines only=2
|
|
||||||
}, is_distinct=True)
|
|
||||||
|
|
||||||
@memoize
|
|
||||||
def emit_subroutine_type(self, typ):
|
|
||||||
return self.emit_debug_info("DISubroutineType", {
|
|
||||||
"types": self.emit_metadata([None])
|
|
||||||
})
|
|
||||||
|
|
||||||
@memoize
|
|
||||||
def emit_subprogram(self, func, llfunc):
|
|
||||||
source_buffer = func.loc.source_buffer
|
|
||||||
|
|
||||||
if self.llcompileunit is None:
|
|
||||||
self.llcompileunit = self.emit_compile_unit(source_buffer)
|
|
||||||
llcompileunits = self.llmodule.add_named_metadata('llvm.dbg.cu')
|
|
||||||
llcompileunits.add(self.llcompileunit)
|
|
||||||
|
|
||||||
display_name = "{}{}".format(func.name, types.TypePrinter().name(func.type))
|
|
||||||
return self.emit_debug_info("DISubprogram", {
|
|
||||||
"name": func.name,
|
|
||||||
"linkageName": llfunc.name,
|
|
||||||
"type": self.emit_subroutine_type(func.type),
|
|
||||||
"file": self.emit_file(source_buffer),
|
|
||||||
"line": func.loc.line(),
|
|
||||||
"unit": self.llcompileunit,
|
|
||||||
"scope": self.emit_file(source_buffer),
|
|
||||||
"scopeLine": func.loc.line(),
|
|
||||||
"isLocal": func.is_internal,
|
|
||||||
"isDefinition": True,
|
|
||||||
"variables": self.emit_metadata([])
|
|
||||||
}, is_distinct=True)
|
|
||||||
|
|
||||||
@memoize
|
|
||||||
def emit_loc(self, loc, scope):
|
|
||||||
return self.emit_debug_info("DILocation", {
|
|
||||||
"line": loc.line(),
|
|
||||||
"column": loc.column(),
|
|
||||||
"scope": scope
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
class ABILayoutInfo:
|
class ABILayoutInfo:
|
||||||
"""Caches DataLayout size/alignment lookup results.
|
"""Caches DataLayout size/alignment lookup results.
|
||||||
|
@ -170,16 +84,8 @@ class LLVMIRGenerator:
|
||||||
self.llmap = {}
|
self.llmap = {}
|
||||||
self.llobject_map = {}
|
self.llobject_map = {}
|
||||||
self.phis = []
|
self.phis = []
|
||||||
self.debug_info_emitter = DebugInfoEmitter(self.llmodule)
|
|
||||||
self.empty_metadata = self.llmodule.add_metadata([])
|
self.empty_metadata = self.llmodule.add_metadata([])
|
||||||
self.tbaa_tree = self.llmodule.add_metadata([
|
self.quote_fail_msg = None
|
||||||
ll.MetaDataString(self.llmodule, "ARTIQ TBAA")
|
|
||||||
])
|
|
||||||
self.tbaa_nowrite_call = self.llmodule.add_metadata([
|
|
||||||
ll.MetaDataString(self.llmodule, "ref-only function call"),
|
|
||||||
self.tbaa_tree,
|
|
||||||
ll.Constant(lli64, 1)
|
|
||||||
])
|
|
||||||
|
|
||||||
def needs_sret(self, lltyp, may_be_large=True):
|
def needs_sret(self, lltyp, may_be_large=True):
|
||||||
if isinstance(lltyp, ll.VoidType):
|
if isinstance(lltyp, ll.VoidType):
|
||||||
|
@ -658,10 +564,6 @@ class LLVMIRGenerator:
|
||||||
self.llbuilder = ll.IRBuilder()
|
self.llbuilder = ll.IRBuilder()
|
||||||
llblock_map = {}
|
llblock_map = {}
|
||||||
|
|
||||||
if not func.is_generated:
|
|
||||||
lldisubprogram = self.debug_info_emitter.emit_subprogram(func, self.llfunction)
|
|
||||||
self.llfunction.set_metadata('dbg', lldisubprogram)
|
|
||||||
|
|
||||||
# First, map arguments.
|
# First, map arguments.
|
||||||
if self.has_sret(func.type):
|
if self.has_sret(func.type):
|
||||||
llactualargs = self.llfunction.args[1:]
|
llactualargs = self.llfunction.args[1:]
|
||||||
|
@ -681,10 +583,6 @@ class LLVMIRGenerator:
|
||||||
for block in func.basic_blocks:
|
for block in func.basic_blocks:
|
||||||
self.llbuilder.position_at_end(self.llmap[block])
|
self.llbuilder.position_at_end(self.llmap[block])
|
||||||
for insn in block.instructions:
|
for insn in block.instructions:
|
||||||
if insn.loc is not None and not func.is_generated:
|
|
||||||
self.llbuilder.debug_metadata = \
|
|
||||||
self.debug_info_emitter.emit_loc(insn.loc, lldisubprogram)
|
|
||||||
|
|
||||||
llinsn = getattr(self, "process_" + type(insn).__name__)(insn)
|
llinsn = getattr(self, "process_" + type(insn).__name__)(insn)
|
||||||
assert llinsn is not None
|
assert llinsn is not None
|
||||||
self.llmap[insn] = llinsn
|
self.llmap[insn] = llinsn
|
||||||
|
@ -1198,19 +1096,30 @@ class LLVMIRGenerator:
|
||||||
return self.map(insn.operands[0])
|
return self.map(insn.operands[0])
|
||||||
elif insn.op == "now_mu":
|
elif insn.op == "now_mu":
|
||||||
if self.target.now_pinning:
|
if self.target.now_pinning:
|
||||||
return self.llbuilder.load(self.llbuiltin("now"), name=insn.name)
|
# Word swap now.old as CPU is little endian
|
||||||
|
# Most significant word is stored in lower address (see generated csr.rs)
|
||||||
|
csr_offset = 2 if isinstance(self.target, RV32GTarget) else 1
|
||||||
|
|
||||||
|
llnow_hiptr = self.llbuilder.bitcast(self.llbuiltin("now"), lli32.as_pointer())
|
||||||
|
llnow_loptr = self.llbuilder.gep(llnow_hiptr, [self.llindex(csr_offset)])
|
||||||
|
llnow_hi = self.llbuilder.load(llnow_hiptr, name="now.hi")
|
||||||
|
llnow_lo = self.llbuilder.load(llnow_loptr, name="now.lo")
|
||||||
|
llzext_hi = self.llbuilder.zext(llnow_hi, lli64)
|
||||||
|
llshifted_hi = self.llbuilder.shl(llzext_hi, ll.Constant(lli64, 32))
|
||||||
|
llzext_lo = self.llbuilder.zext(llnow_lo, lli64)
|
||||||
|
return self.llbuilder.or_(llshifted_hi, llzext_lo)
|
||||||
else:
|
else:
|
||||||
return self.llbuilder.call(self.llbuiltin("now_mu"), [])
|
return self.llbuilder.call(self.llbuiltin("now_mu"), [])
|
||||||
elif insn.op == "at_mu":
|
elif insn.op == "at_mu":
|
||||||
time, = insn.operands
|
time, = insn.operands
|
||||||
lltime = self.map(time)
|
lltime = self.map(time)
|
||||||
if self.target.now_pinning:
|
if self.target.now_pinning:
|
||||||
|
csr_offset = 2 if isinstance(self.target, RV32GTarget) else 1
|
||||||
|
|
||||||
lltime_hi = self.llbuilder.trunc(self.llbuilder.lshr(lltime, ll.Constant(lli64, 32)), lli32)
|
lltime_hi = self.llbuilder.trunc(self.llbuilder.lshr(lltime, ll.Constant(lli64, 32)), lli32)
|
||||||
lltime_lo = self.llbuilder.trunc(lltime, lli32)
|
lltime_lo = self.llbuilder.trunc(lltime, lli32)
|
||||||
llnow_hiptr = self.llbuilder.bitcast(self.llbuiltin("now"), lli32.as_pointer())
|
llnow_hiptr = self.llbuilder.bitcast(self.llbuiltin("now"), lli32.as_pointer())
|
||||||
llnow_loptr = self.llbuilder.gep(llnow_hiptr, [self.llindex(1)])
|
llnow_loptr = self.llbuilder.gep(llnow_hiptr, [self.llindex(csr_offset)])
|
||||||
if self.target.little_endian:
|
|
||||||
lltime_hi, lltime_lo = lltime_lo, lltime_hi
|
|
||||||
llstore_hi = self.llbuilder.store_atomic(lltime_hi, llnow_hiptr, ordering="seq_cst", align=4)
|
llstore_hi = self.llbuilder.store_atomic(lltime_hi, llnow_hiptr, ordering="seq_cst", align=4)
|
||||||
llstore_lo = self.llbuilder.store_atomic(lltime_lo, llnow_loptr, ordering="seq_cst", align=4)
|
llstore_lo = self.llbuilder.store_atomic(lltime_lo, llnow_loptr, ordering="seq_cst", align=4)
|
||||||
return llstore_lo
|
return llstore_lo
|
||||||
|
@ -1220,15 +1129,22 @@ class LLVMIRGenerator:
|
||||||
interval, = insn.operands
|
interval, = insn.operands
|
||||||
llinterval = self.map(interval)
|
llinterval = self.map(interval)
|
||||||
if self.target.now_pinning:
|
if self.target.now_pinning:
|
||||||
llnowptr = self.llbuiltin("now")
|
# Word swap now.old as CPU is little endian
|
||||||
llnow = self.llbuilder.load(llnowptr, name="now.old")
|
# Most significant word is stored in lower address (see generated csr.rs)
|
||||||
|
csr_offset = 2 if isinstance(self.target, RV32GTarget) else 1
|
||||||
|
|
||||||
|
llnow_hiptr = self.llbuilder.bitcast(self.llbuiltin("now"), lli32.as_pointer())
|
||||||
|
llnow_loptr = self.llbuilder.gep(llnow_hiptr, [self.llindex(csr_offset)])
|
||||||
|
llnow_hi = self.llbuilder.load(llnow_hiptr, name="now.hi")
|
||||||
|
llnow_lo = self.llbuilder.load(llnow_loptr, name="now.lo")
|
||||||
|
llzext_hi = self.llbuilder.zext(llnow_hi, lli64)
|
||||||
|
llshifted_hi = self.llbuilder.shl(llzext_hi, ll.Constant(lli64, 32))
|
||||||
|
llzext_lo = self.llbuilder.zext(llnow_lo, lli64)
|
||||||
|
llnow = self.llbuilder.or_(llshifted_hi, llzext_lo)
|
||||||
|
|
||||||
lladjusted = self.llbuilder.add(llnow, llinterval, name="now.new")
|
lladjusted = self.llbuilder.add(llnow, llinterval, name="now.new")
|
||||||
lladjusted_hi = self.llbuilder.trunc(self.llbuilder.lshr(lladjusted, ll.Constant(lli64, 32)), lli32)
|
lladjusted_hi = self.llbuilder.trunc(self.llbuilder.lshr(lladjusted, ll.Constant(lli64, 32)), lli32)
|
||||||
lladjusted_lo = self.llbuilder.trunc(lladjusted, lli32)
|
lladjusted_lo = self.llbuilder.trunc(lladjusted, lli32)
|
||||||
llnow_hiptr = self.llbuilder.bitcast(llnowptr, lli32.as_pointer())
|
|
||||||
llnow_loptr = self.llbuilder.gep(llnow_hiptr, [self.llindex(1)])
|
|
||||||
if self.target.little_endian:
|
|
||||||
lladjusted_hi, lladjusted_lo = lladjusted_lo, lladjusted_hi
|
|
||||||
llstore_hi = self.llbuilder.store_atomic(lladjusted_hi, llnow_hiptr, ordering="seq_cst", align=4)
|
llstore_hi = self.llbuilder.store_atomic(lladjusted_hi, llnow_hiptr, ordering="seq_cst", align=4)
|
||||||
llstore_lo = self.llbuilder.store_atomic(lladjusted_lo, llnow_loptr, ordering="seq_cst", align=4)
|
llstore_lo = self.llbuilder.store_atomic(lladjusted_lo, llnow_loptr, ordering="seq_cst", align=4)
|
||||||
return llstore_lo
|
return llstore_lo
|
||||||
|
@ -1258,26 +1174,32 @@ class LLVMIRGenerator:
|
||||||
else:
|
else:
|
||||||
llfun = self.map(insn.static_target_function)
|
llfun = self.map(insn.static_target_function)
|
||||||
llenv = self.llbuilder.extract_value(llclosure, 0, name="env.fun")
|
llenv = self.llbuilder.extract_value(llclosure, 0, name="env.fun")
|
||||||
return llfun, [llenv] + list(llargs)
|
return llfun, [llenv] + list(llargs), {}
|
||||||
|
|
||||||
def _prepare_ffi_call(self, insn):
|
def _prepare_ffi_call(self, insn):
|
||||||
llargs = []
|
llargs = []
|
||||||
byvals = []
|
llarg_attrs = {}
|
||||||
for i, arg in enumerate(insn.arguments()):
|
for i, arg in enumerate(insn.arguments()):
|
||||||
llarg = self.map(arg)
|
llarg = self.map(arg)
|
||||||
if isinstance(llarg.type, (ll.LiteralStructType, ll.IdentifiedStructType)):
|
if isinstance(llarg.type, (ll.LiteralStructType, ll.IdentifiedStructType)):
|
||||||
llslot = self.llbuilder.alloca(llarg.type)
|
llslot = self.llbuilder.alloca(llarg.type)
|
||||||
self.llbuilder.store(llarg, llslot)
|
self.llbuilder.store(llarg, llslot)
|
||||||
llargs.append(llslot)
|
llargs.append(llslot)
|
||||||
byvals.append(i)
|
llarg_attrs[i] = "byval"
|
||||||
else:
|
else:
|
||||||
llargs.append(llarg)
|
llargs.append(llarg)
|
||||||
|
|
||||||
|
llretty = self.llty_of_type(insn.type, for_return=True)
|
||||||
|
is_sret = self.needs_sret(llretty)
|
||||||
|
if is_sret:
|
||||||
|
llarg_attrs = {i + 1: a for (i, a) in llarg_attrs.items()}
|
||||||
|
llarg_attrs[0] = "sret"
|
||||||
|
|
||||||
llfunname = insn.target_function().type.name
|
llfunname = insn.target_function().type.name
|
||||||
llfun = self.llmodule.globals.get(llfunname)
|
llfun = self.llmodule.globals.get(llfunname)
|
||||||
if llfun is None:
|
if llfun is None:
|
||||||
llretty = self.llty_of_type(insn.type, for_return=True)
|
# Function has not been declared in the current LLVM module, do it now.
|
||||||
if self.needs_sret(llretty):
|
if is_sret:
|
||||||
llfunty = ll.FunctionType(llvoid, [llretty.as_pointer()] +
|
llfunty = ll.FunctionType(llvoid, [llretty.as_pointer()] +
|
||||||
[llarg.type for llarg in llargs])
|
[llarg.type for llarg in llargs])
|
||||||
else:
|
else:
|
||||||
|
@ -1285,15 +1207,14 @@ class LLVMIRGenerator:
|
||||||
|
|
||||||
llfun = ll.Function(self.llmodule, llfunty,
|
llfun = ll.Function(self.llmodule, llfunty,
|
||||||
insn.target_function().type.name)
|
insn.target_function().type.name)
|
||||||
if self.needs_sret(llretty):
|
for idx, attr in llarg_attrs.items():
|
||||||
llfun.args[0].add_attribute('sret')
|
llfun.args[idx].add_attribute(attr)
|
||||||
byvals = [i + 1 for i in byvals]
|
|
||||||
for i in byvals:
|
|
||||||
llfun.args[i].add_attribute('byval')
|
|
||||||
if 'nounwind' in insn.target_function().type.flags:
|
if 'nounwind' in insn.target_function().type.flags:
|
||||||
llfun.attributes.add('nounwind')
|
llfun.attributes.add('nounwind')
|
||||||
|
if 'nowrite' in insn.target_function().type.flags:
|
||||||
|
llfun.attributes.add('inaccessiblememonly')
|
||||||
|
|
||||||
return llfun, list(llargs)
|
return llfun, list(llargs), llarg_attrs
|
||||||
|
|
||||||
def _build_rpc(self, fun_loc, fun_type, args, llnormalblock, llunwindblock):
|
def _build_rpc(self, fun_loc, fun_type, args, llnormalblock, llunwindblock):
|
||||||
llservice = ll.Constant(lli32, fun_type.service)
|
llservice = ll.Constant(lli32, fun_type.service)
|
||||||
|
@ -1429,31 +1350,27 @@ class LLVMIRGenerator:
|
||||||
insn.arguments(),
|
insn.arguments(),
|
||||||
llnormalblock=None, llunwindblock=None)
|
llnormalblock=None, llunwindblock=None)
|
||||||
elif types.is_external_function(functiontyp):
|
elif types.is_external_function(functiontyp):
|
||||||
llfun, llargs = self._prepare_ffi_call(insn)
|
llfun, llargs, llarg_attrs = self._prepare_ffi_call(insn)
|
||||||
else:
|
else:
|
||||||
llfun, llargs = self._prepare_closure_call(insn)
|
llfun, llargs, llarg_attrs = self._prepare_closure_call(insn)
|
||||||
|
|
||||||
if self.has_sret(functiontyp):
|
if self.has_sret(functiontyp):
|
||||||
llstackptr = self.llbuilder.call(self.llbuiltin("llvm.stacksave"), [])
|
llstackptr = self.llbuilder.call(self.llbuiltin("llvm.stacksave"), [])
|
||||||
|
|
||||||
llresultslot = self.llbuilder.alloca(llfun.type.pointee.args[0].pointee)
|
llresultslot = self.llbuilder.alloca(llfun.type.pointee.args[0].pointee)
|
||||||
llcall = self.llbuilder.call(llfun, [llresultslot] + llargs)
|
self.llbuilder.call(llfun, [llresultslot] + llargs, arg_attrs=llarg_attrs)
|
||||||
llresult = self.llbuilder.load(llresultslot)
|
llresult = self.llbuilder.load(llresultslot)
|
||||||
|
|
||||||
self.llbuilder.call(self.llbuiltin("llvm.stackrestore"), [llstackptr])
|
self.llbuilder.call(self.llbuiltin("llvm.stackrestore"), [llstackptr])
|
||||||
else:
|
else:
|
||||||
llcall = llresult = self.llbuilder.call(llfun, llargs, name=insn.name)
|
llresult = self.llbuilder.call(llfun, llargs, name=insn.name,
|
||||||
|
arg_attrs=llarg_attrs)
|
||||||
|
|
||||||
if isinstance(llresult.type, ll.VoidType):
|
if isinstance(llresult.type, ll.VoidType):
|
||||||
# We have NoneType-returning functions return void, but None is
|
# We have NoneType-returning functions return void, but None is
|
||||||
# {} elsewhere.
|
# {} elsewhere.
|
||||||
llresult = ll.Constant(llunit, [])
|
llresult = ll.Constant(llunit, [])
|
||||||
|
|
||||||
# Never add TBAA nowrite metadata to a functon with sret!
|
|
||||||
# This leads to miscompilations.
|
|
||||||
if types.is_external_function(functiontyp) and 'nowrite' in functiontyp.flags:
|
|
||||||
llcall.set_metadata('tbaa', self.tbaa_nowrite_call)
|
|
||||||
|
|
||||||
return llresult
|
return llresult
|
||||||
|
|
||||||
def process_Invoke(self, insn):
|
def process_Invoke(self, insn):
|
||||||
|
@ -1466,16 +1383,17 @@ class LLVMIRGenerator:
|
||||||
insn.arguments(),
|
insn.arguments(),
|
||||||
llnormalblock, llunwindblock)
|
llnormalblock, llunwindblock)
|
||||||
elif types.is_external_function(functiontyp):
|
elif types.is_external_function(functiontyp):
|
||||||
llfun, llargs = self._prepare_ffi_call(insn)
|
llfun, llargs, llarg_attrs = self._prepare_ffi_call(insn)
|
||||||
else:
|
else:
|
||||||
llfun, llargs = self._prepare_closure_call(insn)
|
llfun, llargs, llarg_attrs = self._prepare_closure_call(insn)
|
||||||
|
|
||||||
if self.has_sret(functiontyp):
|
if self.has_sret(functiontyp):
|
||||||
llstackptr = self.llbuilder.call(self.llbuiltin("llvm.stacksave"), [])
|
llstackptr = self.llbuilder.call(self.llbuiltin("llvm.stacksave"), [])
|
||||||
|
|
||||||
llresultslot = self.llbuilder.alloca(llfun.type.pointee.args[0].pointee)
|
llresultslot = self.llbuilder.alloca(llfun.type.pointee.args[0].pointee)
|
||||||
llcall = self.llbuilder.invoke(llfun, [llresultslot] + llargs,
|
llcall = self.llbuilder.invoke(llfun, [llresultslot] + llargs,
|
||||||
llnormalblock, llunwindblock, name=insn.name)
|
llnormalblock, llunwindblock, name=insn.name,
|
||||||
|
arg_attrs=llarg_attrs)
|
||||||
|
|
||||||
self.llbuilder.position_at_start(llnormalblock)
|
self.llbuilder.position_at_start(llnormalblock)
|
||||||
llresult = self.llbuilder.load(llresultslot)
|
llresult = self.llbuilder.load(llresultslot)
|
||||||
|
@ -1483,7 +1401,7 @@ class LLVMIRGenerator:
|
||||||
self.llbuilder.call(self.llbuiltin("llvm.stackrestore"), [llstackptr])
|
self.llbuilder.call(self.llbuiltin("llvm.stackrestore"), [llstackptr])
|
||||||
else:
|
else:
|
||||||
llcall = self.llbuilder.invoke(llfun, llargs, llnormalblock, llunwindblock,
|
llcall = self.llbuilder.invoke(llfun, llargs, llnormalblock, llunwindblock,
|
||||||
name=insn.name)
|
name=insn.name, arg_attrs=llarg_attrs)
|
||||||
llresult = llcall
|
llresult = llcall
|
||||||
|
|
||||||
# The !tbaa metadata is not legal to use with the invoke instruction,
|
# The !tbaa metadata is not legal to use with the invoke instruction,
|
||||||
|
@ -1492,8 +1410,24 @@ class LLVMIRGenerator:
|
||||||
return llresult
|
return llresult
|
||||||
|
|
||||||
def _quote_listish_to_llglobal(self, value, elt_type, path, kind_name):
|
def _quote_listish_to_llglobal(self, value, elt_type, path, kind_name):
|
||||||
|
fail_msg = "at " + ".".join(path())
|
||||||
|
if len(value) > 0:
|
||||||
|
if builtins.is_int(elt_type):
|
||||||
|
int_typ = (int, numpy.int32, numpy.int64)
|
||||||
|
for v in value:
|
||||||
|
assert isinstance(v, int_typ), fail_msg
|
||||||
|
llty = self.llty_of_type(elt_type)
|
||||||
|
llelts = [ll.Constant(llty, int(v)) for v in value]
|
||||||
|
elif builtins.is_float(elt_type):
|
||||||
|
for v in value:
|
||||||
|
assert isinstance(v, float), fail_msg
|
||||||
|
llty = self.llty_of_type(elt_type)
|
||||||
|
llelts = [ll.Constant(llty, v) for v in value]
|
||||||
|
else:
|
||||||
llelts = [self._quote(value[i], elt_type, lambda: path() + [str(i)])
|
llelts = [self._quote(value[i], elt_type, lambda: path() + [str(i)])
|
||||||
for i in range(len(value))]
|
for i in range(len(value))]
|
||||||
|
else:
|
||||||
|
llelts = []
|
||||||
lleltsary = ll.Constant(ll.ArrayType(self.llty_of_type(elt_type), len(llelts)),
|
lleltsary = ll.Constant(ll.ArrayType(self.llty_of_type(elt_type), len(llelts)),
|
||||||
list(llelts))
|
list(llelts))
|
||||||
name = self.llmodule.scope.deduplicate("quoted.{}".format(kind_name))
|
name = self.llmodule.scope.deduplicate("quoted.{}".format(kind_name))
|
||||||
|
@ -1502,13 +1436,7 @@ class LLVMIRGenerator:
|
||||||
llglobal.linkage = "private"
|
llglobal.linkage = "private"
|
||||||
return llglobal.bitcast(lleltsary.type.element.as_pointer())
|
return llglobal.bitcast(lleltsary.type.element.as_pointer())
|
||||||
|
|
||||||
def _quote(self, value, typ, path):
|
def _quote_attributes(self, value, typ, path, value_id, llty):
|
||||||
value_id = id(value)
|
|
||||||
if value_id in self.llobject_map:
|
|
||||||
return self.llobject_map[value_id]
|
|
||||||
llty = self.llty_of_type(typ)
|
|
||||||
|
|
||||||
def _quote_attributes():
|
|
||||||
llglobal = None
|
llglobal = None
|
||||||
llfields = []
|
llfields = []
|
||||||
emit_as_constant = True
|
emit_as_constant = True
|
||||||
|
@ -1546,16 +1474,25 @@ class LLVMIRGenerator:
|
||||||
llglobal.linkage = "private"
|
llglobal.linkage = "private"
|
||||||
return llglobal
|
return llglobal
|
||||||
|
|
||||||
fail_msg = "at " + ".".join(path())
|
def _quote(self, value, typ, path):
|
||||||
|
value_id = id(value)
|
||||||
|
if value_id in self.llobject_map:
|
||||||
|
return self.llobject_map[value_id]
|
||||||
|
llty = self.llty_of_type(typ)
|
||||||
|
|
||||||
|
fail_msg = self.quote_fail_msg
|
||||||
|
if fail_msg == None:
|
||||||
|
self.quote_fail_msg = fail_msg = "at " + ".".join(path())
|
||||||
|
|
||||||
if types.is_constructor(typ) or types.is_instance(typ):
|
if types.is_constructor(typ) or types.is_instance(typ):
|
||||||
if types.is_instance(typ):
|
if types.is_instance(typ):
|
||||||
# Make sure the class functions are quoted, as this has the side effect of
|
# Make sure the class functions are quoted, as this has the side effect of
|
||||||
# initializing the global closures.
|
# initializing the global closures.
|
||||||
self._quote(type(value), typ.constructor,
|
self._quote(type(value), typ.constructor,
|
||||||
lambda: path() + ['__class__'])
|
lambda: path() + ['__class__'])
|
||||||
return _quote_attributes()
|
return self._quote_attributes(value, typ, path, value_id, llty)
|
||||||
elif types.is_module(typ):
|
elif types.is_module(typ):
|
||||||
return _quote_attributes()
|
return self._quote_attributes(value, typ, path, value_id, llty)
|
||||||
elif builtins.is_none(typ):
|
elif builtins.is_none(typ):
|
||||||
assert value is None, fail_msg
|
assert value is None, fail_msg
|
||||||
return ll.Constant.literal_struct([])
|
return ll.Constant.literal_struct([])
|
||||||
|
|
|
@ -3,6 +3,7 @@ The :mod:`types` module contains the classes describing the types
|
||||||
in :mod:`asttyped`.
|
in :mod:`asttyped`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import builtins
|
||||||
import string
|
import string
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from . import iodelay
|
from . import iodelay
|
||||||
|
@ -55,40 +56,39 @@ class TVar(Type):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.parent = self
|
self.parent = self
|
||||||
|
self.rank = 0
|
||||||
|
|
||||||
def find(self):
|
def find(self):
|
||||||
if self.parent is self:
|
parent = self.parent
|
||||||
|
if parent is self:
|
||||||
return self
|
return self
|
||||||
else:
|
else:
|
||||||
# The recursive find() invocation is turned into a loop
|
# The recursive find() invocation is turned into a loop
|
||||||
# because paths resulting from unification of large arrays
|
# because paths resulting from unification of large arrays
|
||||||
# can easily cause a stack overflow.
|
# can easily cause a stack overflow.
|
||||||
root = self
|
root = self
|
||||||
while root.__class__ == TVar:
|
while parent.__class__ == TVar and root is not parent:
|
||||||
if root is root.parent:
|
_, parent = root, root.parent = parent, parent.parent
|
||||||
break
|
return root.parent
|
||||||
else:
|
|
||||||
root = root.parent
|
|
||||||
|
|
||||||
# path compression
|
|
||||||
iter = self
|
|
||||||
while iter.__class__ == TVar:
|
|
||||||
if iter is root:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
iter, iter.parent = iter.parent, root
|
|
||||||
|
|
||||||
return root
|
|
||||||
|
|
||||||
def unify(self, other):
|
def unify(self, other):
|
||||||
if other is self:
|
if other is self:
|
||||||
return
|
return
|
||||||
other = other.find()
|
x = other.find()
|
||||||
|
y = self.find()
|
||||||
if self.parent is self:
|
if x is y:
|
||||||
self.parent = other
|
return
|
||||||
|
if y.__class__ == TVar:
|
||||||
|
if x.__class__ == TVar:
|
||||||
|
if x.rank < y.rank:
|
||||||
|
x, y = y, x
|
||||||
|
y.parent = x
|
||||||
|
if x.rank == y.rank:
|
||||||
|
x.rank += 1
|
||||||
else:
|
else:
|
||||||
self.find().unify(other)
|
y.parent = x
|
||||||
|
else:
|
||||||
|
y.unify(x)
|
||||||
|
|
||||||
def fold(self, accum, fn):
|
def fold(self, accum, fn):
|
||||||
if self.parent is self:
|
if self.parent is self:
|
||||||
|
@ -97,6 +97,8 @@ class TVar(Type):
|
||||||
return self.find().fold(accum, fn)
|
return self.find().fold(accum, fn)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
if getattr(builtins, "__in_sphinx__", False):
|
||||||
|
return str(self)
|
||||||
if self.parent is self:
|
if self.parent is self:
|
||||||
return "<artiq.compiler.types.TVar %d>" % id(self)
|
return "<artiq.compiler.types.TVar %d>" % id(self)
|
||||||
else:
|
else:
|
||||||
|
@ -143,6 +145,8 @@ class TMono(Type):
|
||||||
return fn(accum, self)
|
return fn(accum, self)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
if getattr(builtins, "__in_sphinx__", False):
|
||||||
|
return str(self)
|
||||||
return "artiq.compiler.types.TMono(%s, %s)" % (repr(self.name), repr(self.params))
|
return "artiq.compiler.types.TMono(%s, %s)" % (repr(self.name), repr(self.params))
|
||||||
|
|
||||||
def __getitem__(self, param):
|
def __getitem__(self, param):
|
||||||
|
@ -191,6 +195,8 @@ class TTuple(Type):
|
||||||
return fn(accum, self)
|
return fn(accum, self)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
if getattr(builtins, "__in_sphinx__", False):
|
||||||
|
return str(self)
|
||||||
return "artiq.compiler.types.TTuple(%s)" % repr(self.elts)
|
return "artiq.compiler.types.TTuple(%s)" % repr(self.elts)
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
|
@ -269,6 +275,8 @@ class TFunction(Type):
|
||||||
return fn(accum, self)
|
return fn(accum, self)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
if getattr(builtins, "__in_sphinx__", False):
|
||||||
|
return str(self)
|
||||||
return "artiq.compiler.types.TFunction({}, {}, {})".format(
|
return "artiq.compiler.types.TFunction({}, {}, {})".format(
|
||||||
repr(self.args), repr(self.optargs), repr(self.ret))
|
repr(self.args), repr(self.optargs), repr(self.ret))
|
||||||
|
|
||||||
|
@ -296,7 +304,7 @@ class TExternalFunction(TFunction):
|
||||||
mangling rules).
|
mangling rules).
|
||||||
:ivar flags: (set of str) function flags.
|
:ivar flags: (set of str) function flags.
|
||||||
Flag ``nounwind`` means the function never raises an exception.
|
Flag ``nounwind`` means the function never raises an exception.
|
||||||
Flag ``nowrite`` means the function never writes any memory
|
Flag ``nowrite`` means the function never accesses any memory
|
||||||
that the ARTIQ Python code can observe.
|
that the ARTIQ Python code can observe.
|
||||||
:ivar broadcast_across_arrays: (bool)
|
:ivar broadcast_across_arrays: (bool)
|
||||||
If True, the function is transparently applied element-wise when called
|
If True, the function is transparently applied element-wise when called
|
||||||
|
@ -362,6 +370,8 @@ class TRPC(Type):
|
||||||
return fn(accum, self)
|
return fn(accum, self)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
if getattr(builtins, "__in_sphinx__", False):
|
||||||
|
return str(self)
|
||||||
return "artiq.compiler.types.TRPC({})".format(repr(self.ret))
|
return "artiq.compiler.types.TRPC({})".format(repr(self.ret))
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
|
@ -399,6 +409,8 @@ class TBuiltin(Type):
|
||||||
return fn(accum, self)
|
return fn(accum, self)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
if getattr(builtins, "__in_sphinx__", False):
|
||||||
|
return str(self)
|
||||||
return "artiq.compiler.types.{}({})".format(type(self).__name__, repr(self.name))
|
return "artiq.compiler.types.{}({})".format(type(self).__name__, repr(self.name))
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
|
@ -459,6 +471,8 @@ class TInstance(TMono):
|
||||||
self.constant_attributes = set()
|
self.constant_attributes = set()
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
if getattr(builtins, "__in_sphinx__", False):
|
||||||
|
return str(self)
|
||||||
return "artiq.compiler.types.TInstance({}, {})".format(
|
return "artiq.compiler.types.TInstance({}, {})".format(
|
||||||
repr(self.name), repr(self.attributes))
|
repr(self.name), repr(self.attributes))
|
||||||
|
|
||||||
|
@ -474,6 +488,8 @@ class TModule(TMono):
|
||||||
self.constant_attributes = set()
|
self.constant_attributes = set()
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
if getattr(builtins, "__in_sphinx__", False):
|
||||||
|
return str(self)
|
||||||
return "artiq.compiler.types.TModule({}, {})".format(
|
return "artiq.compiler.types.TModule({}, {})".format(
|
||||||
repr(self.name), repr(self.attributes))
|
repr(self.name), repr(self.attributes))
|
||||||
|
|
||||||
|
@ -513,6 +529,8 @@ class TValue(Type):
|
||||||
return fn(accum, self)
|
return fn(accum, self)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
if getattr(builtins, "__in_sphinx__", False):
|
||||||
|
return str(self)
|
||||||
return "artiq.compiler.types.TValue(%s)" % repr(self.value)
|
return "artiq.compiler.types.TValue(%s)" % repr(self.value)
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
|
@ -571,6 +589,8 @@ class TDelay(Type):
|
||||||
return not (self == other)
|
return not (self == other)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
if getattr(builtins, "__in_sphinx__", False):
|
||||||
|
return str(self)
|
||||||
if self.duration is None:
|
if self.duration is None:
|
||||||
return "<{}.TIndeterminateDelay>".format(__name__)
|
return "<{}.TIndeterminateDelay>".format(__name__)
|
||||||
elif self.cause is None:
|
elif self.cause is None:
|
||||||
|
|
|
@ -127,9 +127,9 @@ class AD53xx:
|
||||||
transactions (default: 1)
|
transactions (default: 1)
|
||||||
:param div_write: SPI clock divider for write operations (default: 4,
|
:param div_write: SPI clock divider for write operations (default: 4,
|
||||||
50MHz max SPI clock with {t_high, t_low} >=8ns)
|
50MHz max SPI clock with {t_high, t_low} >=8ns)
|
||||||
:param div_read: SPI clock divider for read operations (default: 8, not
|
:param div_read: SPI clock divider for read operations (default: 16, not
|
||||||
optimized for speed, but cf data sheet t22: 25ns min SCLK edge to SDO
|
optimized for speed; datasheet says t22: 25ns min SCLK edge to SDO
|
||||||
valid)
|
valid, and suggests the SPI speed for reads should be <=20 MHz)
|
||||||
:param vref: DAC reference voltage (default: 5.)
|
:param vref: DAC reference voltage (default: 5.)
|
||||||
:param offset_dacs: Initial register value for the two offset DACs, device
|
:param offset_dacs: Initial register value for the two offset DACs, device
|
||||||
dependent and must be set correctly for correct voltage to mu
|
dependent and must be set correctly for correct voltage to mu
|
||||||
|
|
|
@ -324,7 +324,7 @@ class AD9910:
|
||||||
self.bus.write(data_low)
|
self.bus.write(data_low)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def write_ram(self, data: TList(int32)):
|
def write_ram(self, data: TList(TInt32)):
|
||||||
"""Write data to RAM.
|
"""Write data to RAM.
|
||||||
|
|
||||||
The profile to write to and the step, start, and end address
|
The profile to write to and the step, start, and end address
|
||||||
|
@ -345,7 +345,7 @@ class AD9910:
|
||||||
self.bus.write(data[len(data) - 1])
|
self.bus.write(data[len(data) - 1])
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def read_ram(self, data: TList(int32)):
|
def read_ram(self, data: TList(TInt32)):
|
||||||
"""Read data from RAM.
|
"""Read data from RAM.
|
||||||
|
|
||||||
The profile to read from and the step, start, and end address
|
The profile to read from and the step, start, and end address
|
||||||
|
@ -374,18 +374,25 @@ class AD9910:
|
||||||
data[(n - preload) + i] = self.bus.read()
|
data[(n - preload) + i] = self.bus.read()
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def set_cfr1(self, power_down: TInt32 = 0b0000,
|
def set_cfr1(self,
|
||||||
|
power_down: TInt32 = 0b0000,
|
||||||
phase_autoclear: TInt32 = 0,
|
phase_autoclear: TInt32 = 0,
|
||||||
drg_load_lrr: TInt32 = 0, drg_autoclear: TInt32 = 0,
|
drg_load_lrr: TInt32 = 0,
|
||||||
internal_profile: TInt32 = 0, ram_destination: TInt32 = 0,
|
drg_autoclear: TInt32 = 0,
|
||||||
ram_enable: TInt32 = 0, manual_osk_external: TInt32 = 0,
|
phase_clear: TInt32 = 0,
|
||||||
osk_enable: TInt32 = 0, select_auto_osk: TInt32 = 0):
|
internal_profile: TInt32 = 0,
|
||||||
|
ram_destination: TInt32 = 0,
|
||||||
|
ram_enable: TInt32 = 0,
|
||||||
|
manual_osk_external: TInt32 = 0,
|
||||||
|
osk_enable: TInt32 = 0,
|
||||||
|
select_auto_osk: TInt32 = 0):
|
||||||
"""Set CFR1. See the AD9910 datasheet for parameter meanings.
|
"""Set CFR1. See the AD9910 datasheet for parameter meanings.
|
||||||
|
|
||||||
This method does not pulse IO_UPDATE.
|
This method does not pulse IO_UPDATE.
|
||||||
|
|
||||||
:param power_down: Power down bits.
|
:param power_down: Power down bits.
|
||||||
:param phase_autoclear: Autoclear phase accumulator.
|
:param phase_autoclear: Autoclear phase accumulator.
|
||||||
|
:param phase_clear: Asynchronous, static reset of the phase accumulator.
|
||||||
:param drg_load_lrr: Load digital ramp generator LRR.
|
:param drg_load_lrr: Load digital ramp generator LRR.
|
||||||
:param drg_autoclear: Autoclear digital ramp generator.
|
:param drg_autoclear: Autoclear digital ramp generator.
|
||||||
:param internal_profile: Internal profile control.
|
:param internal_profile: Internal profile control.
|
||||||
|
@ -405,11 +412,41 @@ class AD9910:
|
||||||
(drg_load_lrr << 15) |
|
(drg_load_lrr << 15) |
|
||||||
(drg_autoclear << 14) |
|
(drg_autoclear << 14) |
|
||||||
(phase_autoclear << 13) |
|
(phase_autoclear << 13) |
|
||||||
|
(phase_clear << 11) |
|
||||||
(osk_enable << 9) |
|
(osk_enable << 9) |
|
||||||
(select_auto_osk << 8) |
|
(select_auto_osk << 8) |
|
||||||
(power_down << 4) |
|
(power_down << 4) |
|
||||||
2) # SDIO input only, MSB first
|
2) # SDIO input only, MSB first
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def set_cfr2(self,
|
||||||
|
asf_profile_enable: TInt32 = 1,
|
||||||
|
drg_enable: TInt32 = 0,
|
||||||
|
effective_ftw: TInt32 = 1,
|
||||||
|
sync_validation_disable: TInt32 = 0,
|
||||||
|
matched_latency_enable: TInt32 = 0):
|
||||||
|
"""Set CFR2. See the AD9910 datasheet for parameter meanings.
|
||||||
|
|
||||||
|
This method does not pulse IO_UPDATE.
|
||||||
|
|
||||||
|
:param asf_profile_enable: Enable amplitude scale from single tone profiles.
|
||||||
|
:param drg_enable: Digital ramp enable.
|
||||||
|
:param effective_ftw: Read effective FTW.
|
||||||
|
:param sync_validation_disable: Disable the SYNC_SMP_ERR pin indicating
|
||||||
|
(active high) detection of a synchronization pulse sampling error.
|
||||||
|
:param matched_latency_enable: Simultaneous application of amplitude,
|
||||||
|
phase, and frequency changes to the DDS arrive at the output
|
||||||
|
|
||||||
|
* matched_latency_enable = 0: in the order listed
|
||||||
|
* matched_latency_enable = 1: simultaneously.
|
||||||
|
"""
|
||||||
|
self.write32(_AD9910_REG_CFR2,
|
||||||
|
(asf_profile_enable << 24) |
|
||||||
|
(drg_enable << 19) |
|
||||||
|
(effective_ftw << 16) |
|
||||||
|
(matched_latency_enable << 7) |
|
||||||
|
(sync_validation_disable << 5))
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def init(self, blind: TBool = False):
|
def init(self, blind: TBool = False):
|
||||||
"""Initialize and configure the DDS.
|
"""Initialize and configure the DDS.
|
||||||
|
@ -442,7 +479,7 @@ class AD9910:
|
||||||
# enable amplitude scale from profiles
|
# enable amplitude scale from profiles
|
||||||
# read effective FTW
|
# read effective FTW
|
||||||
# sync timing validation disable (enabled later)
|
# sync timing validation disable (enabled later)
|
||||||
self.write32(_AD9910_REG_CFR2, 0x01010020)
|
self.set_cfr2(sync_validation_disable=1)
|
||||||
self.cpld.io_update.pulse(1 * us)
|
self.cpld.io_update.pulse(1 * us)
|
||||||
cfr3 = (0x0807c000 | (self.pll_vco << 24) |
|
cfr3 = (0x0807c000 | (self.pll_vco << 24) |
|
||||||
(self.pll_cp << 19) | (self.pll_en << 8) |
|
(self.pll_cp << 19) | (self.pll_en << 8) |
|
||||||
|
@ -465,7 +502,7 @@ class AD9910:
|
||||||
if i >= 100 - 1:
|
if i >= 100 - 1:
|
||||||
raise ValueError("PLL lock timeout")
|
raise ValueError("PLL lock timeout")
|
||||||
delay(10 * us) # slack
|
delay(10 * us) # slack
|
||||||
if self.sync_data.sync_delay_seed >= 0:
|
if self.sync_data.sync_delay_seed >= 0 and not blind:
|
||||||
self.tune_sync_delay(self.sync_data.sync_delay_seed)
|
self.tune_sync_delay(self.sync_data.sync_delay_seed)
|
||||||
delay(1 * ms)
|
delay(1 * ms)
|
||||||
|
|
||||||
|
@ -481,7 +518,7 @@ class AD9910:
|
||||||
@kernel
|
@kernel
|
||||||
def set_mu(self, ftw: TInt32, pow_: TInt32 = 0, asf: TInt32 = 0x3fff,
|
def set_mu(self, ftw: TInt32, pow_: TInt32 = 0, asf: TInt32 = 0x3fff,
|
||||||
phase_mode: TInt32 = _PHASE_MODE_DEFAULT,
|
phase_mode: TInt32 = _PHASE_MODE_DEFAULT,
|
||||||
ref_time_mu: TInt64 = int64(-1), profile: TInt32 = 0):
|
ref_time_mu: TInt64 = int64(-1), profile: TInt32 = 0) -> TInt32:
|
||||||
"""Set profile 0 data in machine units.
|
"""Set profile 0 data in machine units.
|
||||||
|
|
||||||
This uses machine units (FTW, POW, ASF). The frequency tuning word
|
This uses machine units (FTW, POW, ASF). The frequency tuning word
|
||||||
|
@ -786,7 +823,7 @@ class AD9910:
|
||||||
@kernel
|
@kernel
|
||||||
def set(self, frequency: TFloat, phase: TFloat = 0.0,
|
def set(self, frequency: TFloat, phase: TFloat = 0.0,
|
||||||
amplitude: TFloat = 1.0, phase_mode: TInt32 = _PHASE_MODE_DEFAULT,
|
amplitude: TFloat = 1.0, phase_mode: TInt32 = _PHASE_MODE_DEFAULT,
|
||||||
ref_time_mu: TInt64 = int64(-1), profile: TInt32 = 0):
|
ref_time_mu: TInt64 = int64(-1), profile: TInt32 = 0) -> TFloat:
|
||||||
"""Set profile 0 data in SI units.
|
"""Set profile 0 data in SI units.
|
||||||
|
|
||||||
.. seealso:: :meth:`set_mu`
|
.. seealso:: :meth:`set_mu`
|
||||||
|
@ -875,20 +912,26 @@ class AD9910:
|
||||||
self.cpld.cfg_sw(self.chip_select - 4, state)
|
self.cpld.cfg_sw(self.chip_select - 4, state)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def set_sync(self, in_delay: TInt32, window: TInt32):
|
def set_sync(self,
|
||||||
|
in_delay: TInt32,
|
||||||
|
window: TInt32,
|
||||||
|
en_sync_gen: TInt32 = 0):
|
||||||
"""Set the relevant parameters in the multi device synchronization
|
"""Set the relevant parameters in the multi device synchronization
|
||||||
register. See the AD9910 datasheet for details. The SYNC clock
|
register. See the AD9910 datasheet for details. The SYNC clock
|
||||||
generator preset value is set to zero, and the SYNC_OUT generator is
|
generator preset value is set to zero, and the SYNC_OUT generator is
|
||||||
disabled.
|
disabled by default.
|
||||||
|
|
||||||
:param in_delay: SYNC_IN delay tap (0-31) in steps of ~75ps
|
:param in_delay: SYNC_IN delay tap (0-31) in steps of ~75ps
|
||||||
:param window: Symmetric SYNC_IN validation window (0-15) in
|
:param window: Symmetric SYNC_IN validation window (0-15) in
|
||||||
steps of ~75ps for both hold and setup margin.
|
steps of ~75ps for both hold and setup margin.
|
||||||
|
:param en_sync_gen: Whether to enable the DDS-internal sync generator
|
||||||
|
(SYNC_OUT, cf. sync_sel == 1). Should be left off for the normal
|
||||||
|
use case, where the SYNC clock is supplied by the core device.
|
||||||
"""
|
"""
|
||||||
self.write32(_AD9910_REG_SYNC,
|
self.write32(_AD9910_REG_SYNC,
|
||||||
(window << 28) | # SYNC S/H validation delay
|
(window << 28) | # SYNC S/H validation delay
|
||||||
(1 << 27) | # SYNC receiver enable
|
(1 << 27) | # SYNC receiver enable
|
||||||
(0 << 26) | # SYNC generator disable
|
(en_sync_gen << 26) | # SYNC generator enable
|
||||||
(0 << 25) | # SYNC generator SYS rising edge
|
(0 << 25) | # SYNC generator SYS rising edge
|
||||||
(0 << 18) | # SYNC preset
|
(0 << 18) | # SYNC preset
|
||||||
(0 << 11) | # SYNC output delay
|
(0 << 11) | # SYNC output delay
|
||||||
|
@ -904,9 +947,10 @@ class AD9910:
|
||||||
|
|
||||||
Also modifies CFR2.
|
Also modifies CFR2.
|
||||||
"""
|
"""
|
||||||
self.write32(_AD9910_REG_CFR2, 0x01010020) # clear SMP_ERR
|
self.set_cfr2(sync_validation_disable=1) # clear SMP_ERR
|
||||||
self.cpld.io_update.pulse(1 * us)
|
self.cpld.io_update.pulse(1 * us)
|
||||||
self.write32(_AD9910_REG_CFR2, 0x01010000) # enable SMP_ERR
|
delay(10 * us) # slack
|
||||||
|
self.set_cfr2(sync_validation_disable=0) # enable SMP_ERR
|
||||||
self.cpld.io_update.pulse(1 * us)
|
self.cpld.io_update.pulse(1 * us)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
|
@ -984,7 +1028,7 @@ class AD9910:
|
||||||
# set up DRG
|
# set up DRG
|
||||||
self.set_cfr1(drg_load_lrr=1, drg_autoclear=1)
|
self.set_cfr1(drg_load_lrr=1, drg_autoclear=1)
|
||||||
# DRG -> FTW, DRG enable
|
# DRG -> FTW, DRG enable
|
||||||
self.write32(_AD9910_REG_CFR2, 0x01090000)
|
self.set_cfr2(drg_enable=1)
|
||||||
# no limits
|
# no limits
|
||||||
self.write64(_AD9910_REG_RAMP_LIMIT, -1, 0)
|
self.write64(_AD9910_REG_RAMP_LIMIT, -1, 0)
|
||||||
# DRCTL=0, dt=1 t_SYNC_CLK
|
# DRCTL=0, dt=1 t_SYNC_CLK
|
||||||
|
@ -1005,7 +1049,7 @@ class AD9910:
|
||||||
ftw = self.read32(_AD9910_REG_FTW) # read out effective FTW
|
ftw = self.read32(_AD9910_REG_FTW) # read out effective FTW
|
||||||
delay(100 * us) # slack
|
delay(100 * us) # slack
|
||||||
# disable DRG
|
# disable DRG
|
||||||
self.write32(_AD9910_REG_CFR2, 0x01010000)
|
self.set_cfr2(drg_enable=0)
|
||||||
self.cpld.io_update.pulse_mu(8)
|
self.cpld.io_update.pulse_mu(8)
|
||||||
return ftw & 1
|
return ftw & 1
|
||||||
|
|
||||||
|
|
|
@ -156,7 +156,7 @@ class AD9912:
|
||||||
return self.cpld.get_channel_att(self.chip_select - 4)
|
return self.cpld.get_channel_att(self.chip_select - 4)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def set_mu(self, ftw: TInt64, pow_: TInt32):
|
def set_mu(self, ftw: TInt64, pow_: TInt32 = 0):
|
||||||
"""Set profile 0 data in machine units.
|
"""Set profile 0 data in machine units.
|
||||||
|
|
||||||
After the SPI transfer, the shared IO update pin is pulsed to
|
After the SPI transfer, the shared IO update pin is pulsed to
|
||||||
|
|
|
@ -236,6 +236,7 @@ class ADF5356:
|
||||||
Write all registers to the device. Attempts to lock the PLL.
|
Write all registers to the device. Attempts to lock the PLL.
|
||||||
"""
|
"""
|
||||||
f_pfd = self.f_pfd()
|
f_pfd = self.f_pfd()
|
||||||
|
delay(200 * us) # Slack
|
||||||
|
|
||||||
if f_pfd <= 75.0 * MHz:
|
if f_pfd <= 75.0 * MHz:
|
||||||
for i in range(13, 0, -1):
|
for i in range(13, 0, -1):
|
||||||
|
@ -249,6 +250,7 @@ class ADF5356:
|
||||||
n, frac1, (frac2_msb, frac2_lsb), (mod2_msb, mod2_lsb) = calculate_pll(
|
n, frac1, (frac2_msb, frac2_lsb), (mod2_msb, mod2_lsb) = calculate_pll(
|
||||||
self.f_vco(), f_pfd >> 1
|
self.f_vco(), f_pfd >> 1
|
||||||
)
|
)
|
||||||
|
delay(200 * us) # Slack
|
||||||
|
|
||||||
self.write(
|
self.write(
|
||||||
13
|
13
|
||||||
|
|
|
@ -2,11 +2,11 @@ from artiq.language.core import *
|
||||||
from artiq.language.types import *
|
from artiq.language.types import *
|
||||||
|
|
||||||
|
|
||||||
@syscall(flags={"nounwind", "nowrite"})
|
@syscall(flags={"nounwind"})
|
||||||
def cache_get(key: TStr) -> TList(TInt32):
|
def cache_get(key: TStr) -> TList(TInt32):
|
||||||
raise NotImplementedError("syscall not simulated")
|
raise NotImplementedError("syscall not simulated")
|
||||||
|
|
||||||
@syscall(flags={"nowrite"})
|
@syscall
|
||||||
def cache_put(key: TStr, value: TList(TInt32)) -> TNone:
|
def cache_put(key: TStr, value: TList(TInt32)) -> TNone:
|
||||||
raise NotImplementedError("syscall not simulated")
|
raise NotImplementedError("syscall not simulated")
|
||||||
|
|
||||||
|
|
|
@ -621,6 +621,7 @@ class CommKernel:
|
||||||
function = self._read_string()
|
function = self._read_string()
|
||||||
|
|
||||||
backtrace = [self._read_int32() for _ in range(self._read_int32())]
|
backtrace = [self._read_int32() for _ in range(self._read_int32())]
|
||||||
|
self._process_async_error()
|
||||||
|
|
||||||
traceback = list(reversed(symbolizer(backtrace))) + \
|
traceback = list(reversed(symbolizer(backtrace))) + \
|
||||||
[(filename, line, column, *demangler([function]), None)]
|
[(filename, line, column, *demangler([function]), None)]
|
||||||
|
@ -635,6 +636,16 @@ class CommKernel:
|
||||||
python_exn.artiq_core_exception = core_exn
|
python_exn.artiq_core_exception = core_exn
|
||||||
raise python_exn
|
raise python_exn
|
||||||
|
|
||||||
|
def _process_async_error(self):
|
||||||
|
errors = self._read_int8()
|
||||||
|
if errors > 0:
|
||||||
|
map_name = lambda y, z: [f"{y}(s)"] if z else []
|
||||||
|
errors = map_name("collision", errors & 2 ** 0) + \
|
||||||
|
map_name("busy error", errors & 2 ** 1) + \
|
||||||
|
map_name("sequence error", errors & 2 ** 2)
|
||||||
|
logger.warning(f"{(', '.join(errors[:-1]) + ' and ') if len(errors) > 1 else ''}{errors[-1]} "
|
||||||
|
f"reported during kernel execution")
|
||||||
|
|
||||||
def serve(self, embedding_map, symbolizer, demangler):
|
def serve(self, embedding_map, symbolizer, demangler):
|
||||||
while True:
|
while True:
|
||||||
self._read_header()
|
self._read_header()
|
||||||
|
@ -646,4 +657,5 @@ class CommKernel:
|
||||||
raise exceptions.ClockFailure
|
raise exceptions.ClockFailure
|
||||||
else:
|
else:
|
||||||
self._read_expect(Reply.KernelFinished)
|
self._read_expect(Reply.KernelFinished)
|
||||||
|
self._process_async_error()
|
||||||
return
|
return
|
||||||
|
|
|
@ -20,11 +20,6 @@ class Request(Enum):
|
||||||
ConfigRemove = 14
|
ConfigRemove = 14
|
||||||
ConfigErase = 15
|
ConfigErase = 15
|
||||||
|
|
||||||
StartProfiler = 9
|
|
||||||
StopProfiler = 10
|
|
||||||
GetProfile = 11
|
|
||||||
|
|
||||||
Hotswap = 4
|
|
||||||
Reboot = 5
|
Reboot = 5
|
||||||
|
|
||||||
DebugAllocator = 8
|
DebugAllocator = 8
|
||||||
|
@ -39,8 +34,6 @@ class Reply(Enum):
|
||||||
|
|
||||||
ConfigData = 7
|
ConfigData = 7
|
||||||
|
|
||||||
Profile = 5
|
|
||||||
|
|
||||||
RebootImminent = 3
|
RebootImminent = 3
|
||||||
|
|
||||||
|
|
||||||
|
@ -190,45 +183,6 @@ class CommMgmt:
|
||||||
self._write_header(Request.ConfigErase)
|
self._write_header(Request.ConfigErase)
|
||||||
self._read_expect(Reply.Success)
|
self._read_expect(Reply.Success)
|
||||||
|
|
||||||
def start_profiler(self, interval, edges_size, hits_size):
|
|
||||||
self._write_header(Request.StartProfiler)
|
|
||||||
self._write_int32(interval)
|
|
||||||
self._write_int32(edges_size)
|
|
||||||
self._write_int32(hits_size)
|
|
||||||
self._read_expect(Reply.Success)
|
|
||||||
|
|
||||||
def stop_profiler(self):
|
|
||||||
self._write_header(Request.StopProfiler)
|
|
||||||
self._read_expect(Reply.Success)
|
|
||||||
|
|
||||||
def stop_profiler(self):
|
|
||||||
self._write_header(Request.StopProfiler)
|
|
||||||
self._read_expect(Reply.Success)
|
|
||||||
|
|
||||||
def get_profile(self):
|
|
||||||
self._write_header(Request.GetProfile)
|
|
||||||
self._read_expect(Reply.Profile)
|
|
||||||
|
|
||||||
hits = {}
|
|
||||||
for _ in range(self._read_int32()):
|
|
||||||
addr = self._read_int32()
|
|
||||||
count = self._read_int32()
|
|
||||||
hits[addr] = count
|
|
||||||
|
|
||||||
edges = {}
|
|
||||||
for _ in range(self._read_int32()):
|
|
||||||
caller = self._read_int32()
|
|
||||||
callee = self._read_int32()
|
|
||||||
count = self._read_int32()
|
|
||||||
edges[(caller, callee)] = count
|
|
||||||
|
|
||||||
return hits, edges
|
|
||||||
|
|
||||||
def hotswap(self, firmware):
|
|
||||||
self._write_header(Request.Hotswap)
|
|
||||||
self._write_bytes(firmware)
|
|
||||||
self._read_expect(Reply.RebootImminent)
|
|
||||||
|
|
||||||
def reboot(self):
|
def reboot(self):
|
||||||
self._write_header(Request.Reboot)
|
self._write_header(Request.Reboot)
|
||||||
self._read_expect(Reply.RebootImminent)
|
self._read_expect(Reply.RebootImminent)
|
||||||
|
|
|
@ -82,12 +82,12 @@ class CommMonInj:
|
||||||
if not ty:
|
if not ty:
|
||||||
return
|
return
|
||||||
if ty == b"\x00":
|
if ty == b"\x00":
|
||||||
payload = await self._reader.read(9)
|
payload = await self._reader.readexactly(9)
|
||||||
channel, probe, value = struct.unpack(
|
channel, probe, value = struct.unpack(
|
||||||
self.endian + "lbl", payload)
|
self.endian + "lbl", payload)
|
||||||
self.monitor_cb(channel, probe, value)
|
self.monitor_cb(channel, probe, value)
|
||||||
elif ty == b"\x01":
|
elif ty == b"\x01":
|
||||||
payload = await self._reader.read(6)
|
payload = await self._reader.readexactly(6)
|
||||||
channel, override, value = struct.unpack(
|
channel, override, value = struct.unpack(
|
||||||
self.endian + "lbb", payload)
|
self.endian + "lbb", payload)
|
||||||
self.injection_status_cb(channel, override, value)
|
self.injection_status_cb(channel, override, value)
|
||||||
|
|
|
@ -11,7 +11,7 @@ from artiq.language.units import *
|
||||||
|
|
||||||
from artiq.compiler.module import Module
|
from artiq.compiler.module import Module
|
||||||
from artiq.compiler.embedding import Stitcher
|
from artiq.compiler.embedding import Stitcher
|
||||||
from artiq.compiler.targets import OR1KTarget, CortexA9Target
|
from artiq.compiler.targets import RV32IMATarget, RV32GTarget, CortexA9Target
|
||||||
|
|
||||||
from artiq.coredevice.comm_kernel import CommKernel, CommKernelDummy
|
from artiq.coredevice.comm_kernel import CommKernel, CommKernelDummy
|
||||||
# Import for side effects (creating the exception classes).
|
# Import for side effects (creating the exception classes).
|
||||||
|
@ -71,11 +71,13 @@ class Core:
|
||||||
"core", "ref_period", "coarse_ref_period", "ref_multiplier",
|
"core", "ref_period", "coarse_ref_period", "ref_multiplier",
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, dmgr, host, ref_period, ref_multiplier=8, target="or1k"):
|
def __init__(self, dmgr, host, ref_period, ref_multiplier=8, target="rv32g"):
|
||||||
self.ref_period = ref_period
|
self.ref_period = ref_period
|
||||||
self.ref_multiplier = ref_multiplier
|
self.ref_multiplier = ref_multiplier
|
||||||
if target == "or1k":
|
if target == "rv32g":
|
||||||
self.target_cls = OR1KTarget
|
self.target_cls = RV32GTarget
|
||||||
|
elif target == "rv32ima":
|
||||||
|
self.target_cls = RV32IMATarget
|
||||||
elif target == "cortexa9":
|
elif target == "cortexa9":
|
||||||
self.target_cls = CortexA9Target
|
self.target_cls = CortexA9Target
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -64,6 +64,13 @@
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
},
|
},
|
||||||
|
"sed_lanes": {
|
||||||
|
"type": "number",
|
||||||
|
"minimum": 1,
|
||||||
|
"maximum": 32,
|
||||||
|
"default": 8,
|
||||||
|
"description": "Number of FIFOs in the SED, must be a power of 2"
|
||||||
|
},
|
||||||
"peripherals": {
|
"peripherals": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
|
@ -127,7 +134,7 @@
|
||||||
"properties": {
|
"properties": {
|
||||||
"type": {
|
"type": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["dio", "urukul", "novogorny", "sampler", "suservo", "zotino", "grabber", "mirny", "fastino", "phaser"]
|
"enum": ["dio", "urukul", "novogorny", "sampler", "suservo", "zotino", "grabber", "mirny", "fastino", "phaser", "hvamp"]
|
||||||
},
|
},
|
||||||
"board": {
|
"board": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
@ -455,6 +462,28 @@
|
||||||
},
|
},
|
||||||
"required": ["ports"]
|
"required": ["ports"]
|
||||||
}
|
}
|
||||||
|
}, {
|
||||||
|
"title": "HVAmp",
|
||||||
|
"if": {
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"const": "hvamp"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"then": {
|
||||||
|
"properties": {
|
||||||
|
"ports": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"minItems": 1,
|
||||||
|
"maxItems": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["ports"]
|
||||||
|
}
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ streaming DAC.
|
||||||
"""
|
"""
|
||||||
from numpy import int32
|
from numpy import int32
|
||||||
|
|
||||||
from artiq.language.core import kernel, portable, delay
|
from artiq.language.core import kernel, portable, delay, delay_mu
|
||||||
from artiq.coredevice.rtio import (rtio_output, rtio_output_wide,
|
from artiq.coredevice.rtio import (rtio_output, rtio_output_wide,
|
||||||
rtio_input_data)
|
rtio_input_data)
|
||||||
from artiq.language.units import us
|
from artiq.language.units import us
|
||||||
|
@ -191,3 +191,82 @@ class Fastino:
|
||||||
green LED.
|
green LED.
|
||||||
"""
|
"""
|
||||||
self.write(0x23, leds)
|
self.write(0x23, leds)
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def set_continuous(self, channel_mask):
|
||||||
|
"""Enable continuous DAC updates on channels regardless of new data
|
||||||
|
being submitted.
|
||||||
|
"""
|
||||||
|
self.write(0x25, channel_mask)
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def stage_cic_mu(self, rate_mantissa, rate_exponent, gain_exponent):
|
||||||
|
"""Stage machine unit CIC interpolator configuration.
|
||||||
|
"""
|
||||||
|
if rate_mantissa < 0 or rate_mantissa >= 1 << 6:
|
||||||
|
raise ValueError("rate_mantissa out of bounds")
|
||||||
|
if rate_exponent < 0 or rate_exponent >= 1 << 4:
|
||||||
|
raise ValueError("rate_exponent out of bounds")
|
||||||
|
if gain_exponent < 0 or gain_exponent >= 1 << 6:
|
||||||
|
raise ValueError("gain_exponent out of bounds")
|
||||||
|
config = rate_mantissa | (rate_exponent << 6) | (gain_exponent << 10)
|
||||||
|
self.write(0x26, config)
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def stage_cic(self, rate) -> TInt32:
|
||||||
|
"""Compute and stage interpolator configuration.
|
||||||
|
|
||||||
|
This method approximates the desired interpolation rate using a 10 bit
|
||||||
|
floating point representation (6 bit mantissa, 4 bit exponent) and
|
||||||
|
then determines an optimal interpolation gain compensation exponent
|
||||||
|
to avoid clipping. Gains for rates that are powers of two are accurately
|
||||||
|
compensated. Other rates lead to overall less than unity gain (but more
|
||||||
|
than 0.5 gain).
|
||||||
|
|
||||||
|
The overall gain including gain compensation is
|
||||||
|
`actual_rate**order/2**ceil(log2(actual_rate**order))`
|
||||||
|
where `order = 3`.
|
||||||
|
|
||||||
|
Returns the actual interpolation rate.
|
||||||
|
"""
|
||||||
|
if rate <= 0 or rate > 1 << 16:
|
||||||
|
raise ValueError("rate out of bounds")
|
||||||
|
rate_mantissa = rate
|
||||||
|
rate_exponent = 0
|
||||||
|
while rate_mantissa > 1 << 6:
|
||||||
|
rate_exponent += 1
|
||||||
|
rate_mantissa >>= 1
|
||||||
|
order = 3
|
||||||
|
gain = 1
|
||||||
|
for i in range(order):
|
||||||
|
gain *= rate_mantissa
|
||||||
|
gain_exponent = 0
|
||||||
|
while gain > 1 << gain_exponent:
|
||||||
|
gain_exponent += 1
|
||||||
|
gain_exponent += order*rate_exponent
|
||||||
|
assert gain_exponent <= order*16
|
||||||
|
self.stage_cic_mu(rate_mantissa - 1, rate_exponent, gain_exponent)
|
||||||
|
return rate_mantissa << rate_exponent
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def apply_cic(self, channel_mask):
|
||||||
|
"""Apply the staged interpolator configuration on the specified channels.
|
||||||
|
|
||||||
|
Each Fastino channel includes a fourth order (cubic) CIC interpolator with
|
||||||
|
variable rate change and variable output gain compensation (see
|
||||||
|
:meth:`stage_cic`).
|
||||||
|
|
||||||
|
Channels using non-unity interpolation rate should have
|
||||||
|
continous DAC updates enabled (see :meth:`set_continuous`) unless
|
||||||
|
their output is supposed to be constant.
|
||||||
|
|
||||||
|
This method resets and settles the affected interpolators. There will be
|
||||||
|
no output updates for the next `order = 3` input samples.
|
||||||
|
Affected channels will only accept one input sample per input sample
|
||||||
|
period. This method synchronizes the input sample period to the current
|
||||||
|
frame on the affected channels.
|
||||||
|
|
||||||
|
If application of new interpolator settings results in a change of the
|
||||||
|
overall gain, there will be a corresponding output step.
|
||||||
|
"""
|
||||||
|
self.write(0x27, channel_mask)
|
||||||
|
|
|
@ -40,9 +40,8 @@ class Mirny:
|
||||||
:param refclk: Reference clock (SMA, MMCX or on-board 100 MHz oscillator)
|
:param refclk: Reference clock (SMA, MMCX or on-board 100 MHz oscillator)
|
||||||
frequency in Hz
|
frequency in Hz
|
||||||
:param clk_sel: Reference clock selection.
|
:param clk_sel: Reference clock selection.
|
||||||
valid options are: "XO" - onboard crystal oscillator
|
Valid options are: "XO" - onboard crystal oscillator;
|
||||||
"SMA" - front-panel SMA connector
|
"SMA" - front-panel SMA connector; "MMCX" - internal MMCX connector.
|
||||||
"MMCX" - internal MMCX connector
|
|
||||||
Passing an integer writes it as ``clk_sel`` in the CPLD's register 1.
|
Passing an integer writes it as ``clk_sel`` in the CPLD's register 1.
|
||||||
The effect depends on the hardware revision.
|
The effect depends on the hardware revision.
|
||||||
:param core_device: Core device name (default: "core")
|
:param core_device: Core device name (default: "core")
|
||||||
|
|
|
@ -1,77 +0,0 @@
|
||||||
from .spr import mtspr, mfspr
|
|
||||||
from artiq.language.core import kernel
|
|
||||||
|
|
||||||
|
|
||||||
_MAX_SPRS_PER_GRP_BITS = 11
|
|
||||||
_SPRGROUP_PC = 7 << _MAX_SPRS_PER_GRP_BITS
|
|
||||||
_SPR_PCMR_CP = 0x00000001 # Counter present
|
|
||||||
_SPR_PCMR_CISM = 0x00000004 # Count in supervisor mode
|
|
||||||
_SPR_PCMR_CIUM = 0x00000008 # Count in user mode
|
|
||||||
_SPR_PCMR_LA = 0x00000010 # Load access event
|
|
||||||
_SPR_PCMR_SA = 0x00000020 # Store access event
|
|
||||||
_SPR_PCMR_IF = 0x00000040 # Instruction fetch event
|
|
||||||
_SPR_PCMR_DCM = 0x00000080 # Data cache miss event
|
|
||||||
_SPR_PCMR_ICM = 0x00000100 # Insn cache miss event
|
|
||||||
_SPR_PCMR_IFS = 0x00000200 # Insn fetch stall event
|
|
||||||
_SPR_PCMR_LSUS = 0x00000400 # LSU stall event
|
|
||||||
_SPR_PCMR_BS = 0x00000800 # Branch stall event
|
|
||||||
_SPR_PCMR_DTLBM = 0x00001000 # DTLB miss event
|
|
||||||
_SPR_PCMR_ITLBM = 0x00002000 # ITLB miss event
|
|
||||||
_SPR_PCMR_DDS = 0x00004000 # Data dependency stall event
|
|
||||||
_SPR_PCMR_WPE = 0x03ff8000 # Watchpoint events
|
|
||||||
|
|
||||||
|
|
||||||
@kernel(flags={"nowrite", "nounwind"})
|
|
||||||
def _PCCR(n):
|
|
||||||
return _SPRGROUP_PC + n
|
|
||||||
|
|
||||||
|
|
||||||
@kernel(flags={"nowrite", "nounwind"})
|
|
||||||
def _PCMR(n):
|
|
||||||
return _SPRGROUP_PC + 8 + n
|
|
||||||
|
|
||||||
|
|
||||||
class CorePCU:
|
|
||||||
"""Core device performance counter unit (PCU) access"""
|
|
||||||
def __init__(self, dmgr, core_device="core"):
|
|
||||||
self.core = dmgr.get(core_device)
|
|
||||||
|
|
||||||
@kernel
|
|
||||||
def start(self):
|
|
||||||
"""
|
|
||||||
Configure and clear the kernel CPU performance counters.
|
|
||||||
|
|
||||||
The eight counters are configured to count the following events:
|
|
||||||
* Load or store
|
|
||||||
* Instruction fetch
|
|
||||||
* Data cache miss
|
|
||||||
* Instruction cache miss
|
|
||||||
* Instruction fetch stall
|
|
||||||
* Load-store-unit stall
|
|
||||||
* Branch stall
|
|
||||||
* Data dependency stall
|
|
||||||
"""
|
|
||||||
for i in range(8):
|
|
||||||
if not mfspr(_PCMR(i)) & _SPR_PCMR_CP:
|
|
||||||
raise ValueError("counter not present")
|
|
||||||
mtspr(_PCMR(i), 0)
|
|
||||||
mtspr(_PCCR(i), 0)
|
|
||||||
mtspr(_PCMR(0), _SPR_PCMR_CISM | _SPR_PCMR_LA | _SPR_PCMR_SA)
|
|
||||||
mtspr(_PCMR(1), _SPR_PCMR_CISM | _SPR_PCMR_IF)
|
|
||||||
mtspr(_PCMR(2), _SPR_PCMR_CISM | _SPR_PCMR_DCM)
|
|
||||||
mtspr(_PCMR(3), _SPR_PCMR_CISM | _SPR_PCMR_ICM)
|
|
||||||
mtspr(_PCMR(4), _SPR_PCMR_CISM | _SPR_PCMR_IFS)
|
|
||||||
mtspr(_PCMR(5), _SPR_PCMR_CISM | _SPR_PCMR_LSUS)
|
|
||||||
mtspr(_PCMR(6), _SPR_PCMR_CISM | _SPR_PCMR_BS)
|
|
||||||
mtspr(_PCMR(7), _SPR_PCMR_CISM | _SPR_PCMR_DDS)
|
|
||||||
|
|
||||||
@kernel
|
|
||||||
def get(self, r):
|
|
||||||
"""
|
|
||||||
Read the performance counters and store the counts in the
|
|
||||||
array provided.
|
|
||||||
|
|
||||||
:param list[int] r: array to store the counter values
|
|
||||||
"""
|
|
||||||
for i in range(8):
|
|
||||||
r[i] = mfspr(_PCCR(i))
|
|
|
@ -1,7 +1,7 @@
|
||||||
from numpy import int32, int64
|
from numpy import int32, int64
|
||||||
|
|
||||||
from artiq.language.core import kernel, delay_mu, delay
|
from artiq.language.core import kernel, delay_mu, delay
|
||||||
from artiq.coredevice.rtio import rtio_output, rtio_input_data
|
from artiq.coredevice.rtio import rtio_output, rtio_input_data, rtio_input_timestamp
|
||||||
from artiq.language.units import us, ns, ms, MHz
|
from artiq.language.units import us, ns, ms, MHz
|
||||||
from artiq.language.types import TInt32
|
from artiq.language.types import TInt32
|
||||||
from artiq.coredevice.dac34h84 import DAC34H84
|
from artiq.coredevice.dac34h84 import DAC34H84
|
||||||
|
@ -92,7 +92,8 @@ class Phaser:
|
||||||
The latency/group delay from the RTIO events setting
|
The latency/group delay from the RTIO events setting
|
||||||
:class:`PhaserOscillator` or :class:`PhaserChannel` DUC parameters all the
|
:class:`PhaserOscillator` or :class:`PhaserChannel` DUC parameters all the
|
||||||
way to the DAC outputs is deterministic. This enables deterministic
|
way to the DAC outputs is deterministic. This enables deterministic
|
||||||
absolute phase with respect to other RTIO input and output events.
|
absolute phase with respect to other RTIO input and output events
|
||||||
|
(see `get_next_frame_mu()`).
|
||||||
|
|
||||||
The four analog DAC outputs are passed through anti-aliasing filters.
|
The four analog DAC outputs are passed through anti-aliasing filters.
|
||||||
|
|
||||||
|
@ -160,6 +161,7 @@ class Phaser:
|
||||||
# self.core.seconds_to_mu(10*8*4*ns) # unfortunately this returns 319
|
# self.core.seconds_to_mu(10*8*4*ns) # unfortunately this returns 319
|
||||||
assert self.core.ref_period == 1*ns
|
assert self.core.ref_period == 1*ns
|
||||||
self.t_frame = 10*8*4
|
self.t_frame = 10*8*4
|
||||||
|
self.frame_tstamp = int64(0)
|
||||||
self.clk_sel = clk_sel
|
self.clk_sel = clk_sel
|
||||||
self.tune_fifo_offset = tune_fifo_offset
|
self.tune_fifo_offset = tune_fifo_offset
|
||||||
self.sync_dly = sync_dly
|
self.sync_dly = sync_dly
|
||||||
|
@ -188,7 +190,7 @@ class Phaser:
|
||||||
|
|
||||||
gw_rev = self.read8(PHASER_ADDR_GW_REV)
|
gw_rev = self.read8(PHASER_ADDR_GW_REV)
|
||||||
if debug:
|
if debug:
|
||||||
print(gw_rev)
|
print("gw_rev:", gw_rev)
|
||||||
self.core.break_realtime()
|
self.core.break_realtime()
|
||||||
delay(.1*ms) # slack
|
delay(.1*ms) # slack
|
||||||
|
|
||||||
|
@ -197,6 +199,12 @@ class Phaser:
|
||||||
raise ValueError("large number of frame CRC errors")
|
raise ValueError("large number of frame CRC errors")
|
||||||
delay(.1*ms) # slack
|
delay(.1*ms) # slack
|
||||||
|
|
||||||
|
# determine the origin for frame-aligned timestamps
|
||||||
|
self.measure_frame_timestamp()
|
||||||
|
if self.frame_tstamp < 0:
|
||||||
|
raise ValueError("frame timestamp measurement timed out")
|
||||||
|
delay(.1*ms)
|
||||||
|
|
||||||
# reset
|
# reset
|
||||||
self.set_cfg(dac_resetb=0, dac_sleep=1, dac_txena=0,
|
self.set_cfg(dac_resetb=0, dac_sleep=1, dac_txena=0,
|
||||||
trf0_ps=1, trf1_ps=1,
|
trf0_ps=1, trf1_ps=1,
|
||||||
|
@ -262,7 +270,7 @@ class Phaser:
|
||||||
if self.tune_fifo_offset:
|
if self.tune_fifo_offset:
|
||||||
fifo_offset = self.dac_tune_fifo_offset()
|
fifo_offset = self.dac_tune_fifo_offset()
|
||||||
if debug:
|
if debug:
|
||||||
print(fifo_offset)
|
print("fifo_offset:", fifo_offset)
|
||||||
self.core.break_realtime()
|
self.core.break_realtime()
|
||||||
|
|
||||||
# self.dac_write(0x20, 0x0000) # stop fifo sync
|
# self.dac_write(0x20, 0x0000) # stop fifo sync
|
||||||
|
@ -274,7 +282,7 @@ class Phaser:
|
||||||
delay(.1*ms) # slack
|
delay(.1*ms) # slack
|
||||||
if alarms & ~0x0040: # ignore PLL alarms (see DS)
|
if alarms & ~0x0040: # ignore PLL alarms (see DS)
|
||||||
if debug:
|
if debug:
|
||||||
print(alarms)
|
print("alarms:", alarms)
|
||||||
self.core.break_realtime()
|
self.core.break_realtime()
|
||||||
# ignore alarms
|
# ignore alarms
|
||||||
else:
|
else:
|
||||||
|
@ -468,6 +476,27 @@ class Phaser:
|
||||||
"""
|
"""
|
||||||
return self.read8(PHASER_ADDR_CRC_ERR)
|
return self.read8(PHASER_ADDR_CRC_ERR)
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def measure_frame_timestamp(self):
|
||||||
|
"""Measure the timestamp of an arbitrary frame and store it in `self.frame_tstamp`.
|
||||||
|
|
||||||
|
To be used as reference for aligning updates to the FastLink frames.
|
||||||
|
See `get_next_frame_mu()`.
|
||||||
|
"""
|
||||||
|
rtio_output(self.channel_base << 8, 0) # read any register
|
||||||
|
self.frame_tstamp = rtio_input_timestamp(now_mu() + 4 * self.t_frame, self.channel_base)
|
||||||
|
delay(100 * us)
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def get_next_frame_mu(self):
|
||||||
|
"""Return the timestamp of the frame strictly after `now_mu()`.
|
||||||
|
|
||||||
|
Register updates (DUC, DAC, TRF, etc.) scheduled at this timestamp and multiples
|
||||||
|
of `self.t_frame` later will have deterministic latency to output.
|
||||||
|
"""
|
||||||
|
n = int64((now_mu() - self.frame_tstamp) / self.t_frame)
|
||||||
|
return self.frame_tstamp + (n + 1) * self.t_frame
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def set_sync_dly(self, dly):
|
def set_sync_dly(self, dly):
|
||||||
"""Set SYNC delay.
|
"""Set SYNC delay.
|
||||||
|
@ -860,7 +889,7 @@ class PhaserChannel:
|
||||||
|
|
||||||
By default, the new NCO phase applies on completion of the SPI
|
By default, the new NCO phase applies on completion of the SPI
|
||||||
transfer. This also causes a staged NCO frequency to be applied.
|
transfer. This also causes a staged NCO frequency to be applied.
|
||||||
Different triggers for applying nco settings may be configured through
|
Different triggers for applying NCO settings may be configured through
|
||||||
the `syncsel_mixerxx` fields in the `dac` configuration dictionary (see
|
the `syncsel_mixerxx` fields in the `dac` configuration dictionary (see
|
||||||
`__init__()`).
|
`__init__()`).
|
||||||
|
|
||||||
|
@ -878,7 +907,7 @@ class PhaserChannel:
|
||||||
|
|
||||||
By default, the new NCO phase applies on completion of the SPI
|
By default, the new NCO phase applies on completion of the SPI
|
||||||
transfer. This also causes a staged NCO frequency to be applied.
|
transfer. This also causes a staged NCO frequency to be applied.
|
||||||
Different triggers for applying nco settings may be configured through
|
Different triggers for applying NCO settings may be configured through
|
||||||
the `syncsel_mixerxx` fields in the `dac` configuration dictionary (see
|
the `syncsel_mixerxx` fields in the `dac` configuration dictionary (see
|
||||||
`__init__()`).
|
`__init__()`).
|
||||||
|
|
||||||
|
@ -1015,7 +1044,7 @@ class PhaserOscillator:
|
||||||
"""Phaser IQ channel oscillator (NCO/DDS).
|
"""Phaser IQ channel oscillator (NCO/DDS).
|
||||||
|
|
||||||
.. note:: Latencies between oscillators within a channel and between
|
.. note:: Latencies between oscillators within a channel and between
|
||||||
oscillator paramters (amplitude and phase/frequency) are deterministic
|
oscillator parameters (amplitude and phase/frequency) are deterministic
|
||||||
(with respect to the 25 MS/s sample clock) but not matched.
|
(with respect to the 25 MS/s sample clock) but not matched.
|
||||||
"""
|
"""
|
||||||
kernel_invariants = {"channel", "base_addr"}
|
kernel_invariants = {"channel", "base_addr"}
|
||||||
|
|
|
@ -1,92 +0,0 @@
|
||||||
from collections import defaultdict
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
|
|
||||||
class Symbolizer:
|
|
||||||
def __init__(self, binary, triple, demangle=True):
|
|
||||||
cmdline = [
|
|
||||||
triple + "-addr2line", "--exe=" + binary,
|
|
||||||
"--addresses", "--functions", "--inlines"
|
|
||||||
]
|
|
||||||
if demangle:
|
|
||||||
cmdline.append("--demangle=rust")
|
|
||||||
self._addr2line = subprocess.Popen(cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
|
|
||||||
universal_newlines=True)
|
|
||||||
|
|
||||||
def symbolize(self, addr):
|
|
||||||
self._addr2line.stdin.write("0x{:08x}\n0\n".format(addr))
|
|
||||||
self._addr2line.stdin.flush()
|
|
||||||
self._addr2line.stdout.readline() # 0x[addr]
|
|
||||||
|
|
||||||
result = []
|
|
||||||
while True:
|
|
||||||
function = self._addr2line.stdout.readline().rstrip()
|
|
||||||
|
|
||||||
# check for end marker
|
|
||||||
if function == "0x00000000": # 0x00000000
|
|
||||||
self._addr2line.stdout.readline() # ??
|
|
||||||
self._addr2line.stdout.readline() # ??:0
|
|
||||||
return result
|
|
||||||
|
|
||||||
file, line = self._addr2line.stdout.readline().rstrip().split(":")
|
|
||||||
|
|
||||||
result.append((function, file, line, addr))
|
|
||||||
|
|
||||||
|
|
||||||
class CallgrindWriter:
|
|
||||||
def __init__(self, output, binary, triple, compression=True, demangle=True):
|
|
||||||
self._output = output
|
|
||||||
self._binary = binary
|
|
||||||
self._current = defaultdict(lambda: None)
|
|
||||||
self._ids = defaultdict(lambda: {})
|
|
||||||
self._compression = compression
|
|
||||||
self._symbolizer = Symbolizer(binary, triple, demangle=demangle)
|
|
||||||
|
|
||||||
def _write(self, fmt, *args, **kwargs):
|
|
||||||
self._output.write(fmt.format(*args, **kwargs))
|
|
||||||
self._output.write("\n")
|
|
||||||
|
|
||||||
def _spec(self, spec, value):
|
|
||||||
if self._current[spec] == value:
|
|
||||||
return
|
|
||||||
self._current[spec] = value
|
|
||||||
|
|
||||||
if not self._compression or value == "??":
|
|
||||||
self._write("{}={}", spec, value)
|
|
||||||
return
|
|
||||||
|
|
||||||
spec_ids = self._ids[spec]
|
|
||||||
if value in spec_ids:
|
|
||||||
self._write("{}=({})", spec, spec_ids[value])
|
|
||||||
else:
|
|
||||||
spec_ids[value] = len(spec_ids) + 1
|
|
||||||
self._write("{}=({}) {}", spec, spec_ids[value], value)
|
|
||||||
|
|
||||||
def header(self):
|
|
||||||
self._write("# callgrind format")
|
|
||||||
self._write("version: 1")
|
|
||||||
self._write("creator: ARTIQ")
|
|
||||||
self._write("positions: instr line")
|
|
||||||
self._write("events: Hits")
|
|
||||||
self._write("")
|
|
||||||
self._spec("ob", self._binary)
|
|
||||||
self._spec("cob", self._binary)
|
|
||||||
|
|
||||||
def hit(self, addr, count):
|
|
||||||
for function, file, line, addr in self._symbolizer.symbolize(addr):
|
|
||||||
self._spec("fl", file)
|
|
||||||
self._spec("fn", function)
|
|
||||||
self._write("0x{:08x} {} {}", addr, line, count)
|
|
||||||
|
|
||||||
def edge(self, caller, callee, count):
|
|
||||||
edges = self._symbolizer.symbolize(callee) + self._symbolizer.symbolize(caller)
|
|
||||||
for (callee, caller) in zip(edges, edges[1:]):
|
|
||||||
function, file, line, addr = callee
|
|
||||||
self._spec("cfl", file)
|
|
||||||
self._spec("cfn", function)
|
|
||||||
self._write("calls={} 0x{:08x} {}", count, addr, line)
|
|
||||||
|
|
||||||
function, file, line, addr = caller
|
|
||||||
self._spec("fl", file)
|
|
||||||
self._spec("fn", function)
|
|
||||||
self._write("0x{:08x} {} {}", addr, line, count)
|
|
|
@ -1,12 +0,0 @@
|
||||||
from artiq.language.core import syscall
|
|
||||||
from artiq.language.types import TInt32, TNone
|
|
||||||
|
|
||||||
|
|
||||||
@syscall(flags={"nounwind", "nowrite"})
|
|
||||||
def mfspr(spr: TInt32) -> TInt32:
|
|
||||||
raise NotImplementedError("syscall not simulated")
|
|
||||||
|
|
||||||
|
|
||||||
@syscall(flags={"nowrite", "nowrite"})
|
|
||||||
def mtspr(spr: TInt32, value: TInt32) -> TNone:
|
|
||||||
raise NotImplementedError("syscall not simulated")
|
|
|
@ -57,32 +57,26 @@ class SUServo:
|
||||||
|
|
||||||
:param channel: RTIO channel number
|
:param channel: RTIO channel number
|
||||||
:param pgia_device: Name of the Sampler PGIA gain setting SPI bus
|
:param pgia_device: Name of the Sampler PGIA gain setting SPI bus
|
||||||
:param cpld0_device: Name of the first Urukul CPLD SPI bus
|
:param cpld_devices: Names of the Urukul CPLD SPI buses
|
||||||
:param cpld1_device: Name of the second Urukul CPLD SPI bus
|
:param dds_devices: Names of the AD9910 devices
|
||||||
:param dds0_device: Name of the AD9910 device for the DDS on the first
|
|
||||||
Urukul
|
|
||||||
:param dds1_device: Name of the AD9910 device for the DDS on the second
|
|
||||||
Urukul
|
|
||||||
:param gains: Initial value for PGIA gains shift register
|
:param gains: Initial value for PGIA gains shift register
|
||||||
(default: 0x0000). Knowledge of this state is not transferred
|
(default: 0x0000). Knowledge of this state is not transferred
|
||||||
between experiments.
|
between experiments.
|
||||||
:param core_device: Core device name
|
:param core_device: Core device name
|
||||||
"""
|
"""
|
||||||
kernel_invariants = {"channel", "core", "pgia", "cpld0", "cpld1",
|
kernel_invariants = {"channel", "core", "pgia", "cplds", "ddses",
|
||||||
"dds0", "dds1", "ref_period_mu"}
|
"ref_period_mu"}
|
||||||
|
|
||||||
def __init__(self, dmgr, channel, pgia_device,
|
def __init__(self, dmgr, channel, pgia_device,
|
||||||
cpld0_device, cpld1_device,
|
cpld_devices, dds_devices,
|
||||||
dds0_device, dds1_device,
|
|
||||||
gains=0x0000, core_device="core"):
|
gains=0x0000, core_device="core"):
|
||||||
|
|
||||||
self.core = dmgr.get(core_device)
|
self.core = dmgr.get(core_device)
|
||||||
self.pgia = dmgr.get(pgia_device)
|
self.pgia = dmgr.get(pgia_device)
|
||||||
self.pgia.update_xfer_duration_mu(div=4, length=16)
|
self.pgia.update_xfer_duration_mu(div=4, length=16)
|
||||||
self.dds0 = dmgr.get(dds0_device)
|
assert len(dds_devices) == len(cpld_devices)
|
||||||
self.dds1 = dmgr.get(dds1_device)
|
self.ddses = [dmgr.get(dds) for dds in dds_devices]
|
||||||
self.cpld0 = dmgr.get(cpld0_device)
|
self.cplds = [dmgr.get(cpld) for cpld in cpld_devices]
|
||||||
self.cpld1 = dmgr.get(cpld1_device)
|
|
||||||
self.channel = channel
|
self.channel = channel
|
||||||
self.gains = gains
|
self.gains = gains
|
||||||
self.ref_period_mu = self.core.seconds_to_mu(
|
self.ref_period_mu = self.core.seconds_to_mu(
|
||||||
|
@ -109,17 +103,15 @@ class SUServo:
|
||||||
sampler.SPI_CONFIG | spi.SPI_END,
|
sampler.SPI_CONFIG | spi.SPI_END,
|
||||||
16, 4, sampler.SPI_CS_PGIA)
|
16, 4, sampler.SPI_CS_PGIA)
|
||||||
|
|
||||||
self.cpld0.init(blind=True)
|
for i in range(len(self.cplds)):
|
||||||
cfg0 = self.cpld0.cfg_reg
|
cpld = self.cplds[i]
|
||||||
self.cpld0.cfg_write(cfg0 | (0xf << urukul.CFG_MASK_NU))
|
dds = self.ddses[i]
|
||||||
self.dds0.init(blind=True)
|
|
||||||
self.cpld0.cfg_write(cfg0)
|
|
||||||
|
|
||||||
self.cpld1.init(blind=True)
|
cpld.init(blind=True)
|
||||||
cfg1 = self.cpld1.cfg_reg
|
prev_cpld_cfg = cpld.cfg_reg
|
||||||
self.cpld1.cfg_write(cfg1 | (0xf << urukul.CFG_MASK_NU))
|
cpld.cfg_write(prev_cpld_cfg | (0xf << urukul.CFG_MASK_NU))
|
||||||
self.dds1.init(blind=True)
|
dds.init(blind=True)
|
||||||
self.cpld1.cfg_write(cfg1)
|
cpld.cfg_write(prev_cpld_cfg)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def write(self, addr, value):
|
def write(self, addr, value):
|
||||||
|
@ -257,9 +249,11 @@ class Channel:
|
||||||
self.servo = dmgr.get(servo_device)
|
self.servo = dmgr.get(servo_device)
|
||||||
self.core = self.servo.core
|
self.core = self.servo.core
|
||||||
self.channel = channel
|
self.channel = channel
|
||||||
# FIXME: this assumes the mem channel is right after the control
|
# This assumes the mem channel is right after the control channels
|
||||||
# channels
|
# Make sure this is always the case in eem.py
|
||||||
self.servo_channel = self.channel + 8 - self.servo.channel
|
self.servo_channel = (self.channel + 4 * len(self.servo.cplds) -
|
||||||
|
self.servo.channel)
|
||||||
|
self.dds = self.servo.ddses[self.servo_channel // 4]
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def set(self, en_out, en_iir=0, profile=0):
|
def set(self, en_out, en_iir=0, profile=0):
|
||||||
|
@ -311,12 +305,8 @@ class Channel:
|
||||||
see :meth:`dds_offset_to_mu`
|
see :meth:`dds_offset_to_mu`
|
||||||
:param phase: DDS phase in turns
|
:param phase: DDS phase in turns
|
||||||
"""
|
"""
|
||||||
if self.servo_channel < 4:
|
ftw = self.dds.frequency_to_ftw(frequency)
|
||||||
dds = self.servo.dds0
|
pow_ = self.dds.turns_to_pow(phase)
|
||||||
else:
|
|
||||||
dds = self.servo.dds1
|
|
||||||
ftw = dds.frequency_to_ftw(frequency)
|
|
||||||
pow_ = dds.turns_to_pow(phase)
|
|
||||||
offs = self.dds_offset_to_mu(offset)
|
offs = self.dds_offset_to_mu(offset)
|
||||||
self.set_dds_mu(profile, ftw, offs, pow_)
|
self.set_dds_mu(profile, ftw, offs, pow_)
|
||||||
|
|
||||||
|
|
|
@ -27,15 +27,15 @@ class Zotino(AD53xx):
|
||||||
:param clr_device: CLR RTIO TTLOut channel name.
|
:param clr_device: CLR RTIO TTLOut channel name.
|
||||||
:param div_write: SPI clock divider for write operations (default: 4,
|
:param div_write: SPI clock divider for write operations (default: 4,
|
||||||
50MHz max SPI clock)
|
50MHz max SPI clock)
|
||||||
:param div_read: SPI clock divider for read operations (default: 8, not
|
:param div_read: SPI clock divider for read operations (default: 16, not
|
||||||
optimized for speed, but cf data sheet t22: 25ns min SCLK edge to SDO
|
optimized for speed; datasheet says t22: 25ns min SCLK edge to SDO
|
||||||
valid)
|
valid, and suggests the SPI speed for reads should be <=20 MHz)
|
||||||
:param vref: DAC reference voltage (default: 5.)
|
:param vref: DAC reference voltage (default: 5.)
|
||||||
:param core_device: Core device name (default: "core")
|
:param core_device: Core device name (default: "core")
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, dmgr, spi_device, ldac_device=None, clr_device=None,
|
def __init__(self, dmgr, spi_device, ldac_device=None, clr_device=None,
|
||||||
div_write=4, div_read=8, vref=5., core="core"):
|
div_write=4, div_read=16, vref=5., core="core"):
|
||||||
AD53xx.__init__(self, dmgr=dmgr, spi_device=spi_device,
|
AD53xx.__init__(self, dmgr=dmgr, spi_device=spi_device,
|
||||||
ldac_device=ldac_device, clr_device=clr_device,
|
ldac_device=ldac_device, clr_device=clr_device,
|
||||||
chip_select=_SPI_CS_DAC, div_write=div_write,
|
chip_select=_SPI_CS_DAC, div_write=div_write,
|
||||||
|
|
|
@ -3,8 +3,9 @@ import logging
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from PyQt5 import QtCore, QtWidgets
|
from PyQt5 import QtCore, QtWidgets
|
||||||
|
from sipyco import pyon
|
||||||
|
|
||||||
from artiq.tools import short_format
|
from artiq.tools import short_format, exc_to_warning
|
||||||
from artiq.gui.tools import LayoutWidget, QRecursiveFilterProxyModel
|
from artiq.gui.tools import LayoutWidget, QRecursiveFilterProxyModel
|
||||||
from artiq.gui.models import DictSyncTreeSepModel
|
from artiq.gui.models import DictSyncTreeSepModel
|
||||||
from artiq.gui.scientific_spinbox import ScientificSpinBox
|
from artiq.gui.scientific_spinbox import ScientificSpinBox
|
||||||
|
@ -82,6 +83,68 @@ class StringEditor(Editor):
|
||||||
return self.edit_widget.text()
|
return self.edit_widget.text()
|
||||||
|
|
||||||
|
|
||||||
|
class Creator(QtWidgets.QDialog):
|
||||||
|
def __init__(self, parent, dataset_ctl):
|
||||||
|
QtWidgets.QDialog.__init__(self, parent=parent)
|
||||||
|
self.dataset_ctl = dataset_ctl
|
||||||
|
|
||||||
|
self.setWindowTitle("Create dataset")
|
||||||
|
grid = QtWidgets.QGridLayout()
|
||||||
|
grid.setRowMinimumHeight(1, 40)
|
||||||
|
grid.setColumnMinimumWidth(2, 60)
|
||||||
|
self.setLayout(grid)
|
||||||
|
|
||||||
|
grid.addWidget(QtWidgets.QLabel("Name:"), 0, 0)
|
||||||
|
self.name_widget = QtWidgets.QLineEdit()
|
||||||
|
grid.addWidget(self.name_widget, 0, 1)
|
||||||
|
|
||||||
|
grid.addWidget(QtWidgets.QLabel("Value:"), 1, 0)
|
||||||
|
self.value_widget = QtWidgets.QLineEdit()
|
||||||
|
self.value_widget.setPlaceholderText('PYON (Python)')
|
||||||
|
grid.addWidget(self.value_widget, 1, 1)
|
||||||
|
self.data_type = QtWidgets.QLabel("data type")
|
||||||
|
grid.addWidget(self.data_type, 1, 2)
|
||||||
|
self.value_widget.textChanged.connect(self.dtype)
|
||||||
|
|
||||||
|
grid.addWidget(QtWidgets.QLabel("Persist:"), 2, 0)
|
||||||
|
self.box_widget = QtWidgets.QCheckBox()
|
||||||
|
grid.addWidget(self.box_widget, 2, 1)
|
||||||
|
|
||||||
|
self.ok = QtWidgets.QPushButton('&Ok')
|
||||||
|
self.ok.setEnabled(False)
|
||||||
|
self.cancel = QtWidgets.QPushButton('&Cancel')
|
||||||
|
self.buttons = QtWidgets.QDialogButtonBox(self)
|
||||||
|
self.buttons.addButton(
|
||||||
|
self.ok, QtWidgets.QDialogButtonBox.AcceptRole)
|
||||||
|
self.buttons.addButton(
|
||||||
|
self.cancel, QtWidgets.QDialogButtonBox.RejectRole)
|
||||||
|
grid.setRowStretch(3, 1)
|
||||||
|
grid.addWidget(self.buttons, 4, 0, 1, 3)
|
||||||
|
self.buttons.accepted.connect(self.accept)
|
||||||
|
self.buttons.rejected.connect(self.reject)
|
||||||
|
|
||||||
|
def accept(self):
|
||||||
|
key = self.name_widget.text()
|
||||||
|
value = self.value_widget.text()
|
||||||
|
persist = self.box_widget.isChecked()
|
||||||
|
asyncio.ensure_future(exc_to_warning(self.dataset_ctl.set(
|
||||||
|
key, pyon.decode(value), persist)))
|
||||||
|
QtWidgets.QDialog.accept(self)
|
||||||
|
|
||||||
|
def dtype(self):
|
||||||
|
txt = self.value_widget.text()
|
||||||
|
try:
|
||||||
|
result = pyon.decode(txt)
|
||||||
|
except:
|
||||||
|
pixmap = self.style().standardPixmap(
|
||||||
|
QtWidgets.QStyle.SP_MessageBoxWarning)
|
||||||
|
self.data_type.setPixmap(pixmap)
|
||||||
|
self.ok.setEnabled(False)
|
||||||
|
else:
|
||||||
|
self.data_type.setText(type(result).__name__)
|
||||||
|
self.ok.setEnabled(True)
|
||||||
|
|
||||||
|
|
||||||
class Model(DictSyncTreeSepModel):
|
class Model(DictSyncTreeSepModel):
|
||||||
def __init__(self, init):
|
def __init__(self, init):
|
||||||
DictSyncTreeSepModel.__init__(
|
DictSyncTreeSepModel.__init__(
|
||||||
|
@ -120,6 +183,11 @@ class DatasetsDock(QtWidgets.QDockWidget):
|
||||||
grid.addWidget(self.table, 1, 0)
|
grid.addWidget(self.table, 1, 0)
|
||||||
|
|
||||||
self.table.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
|
self.table.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
|
||||||
|
create_action = QtWidgets.QAction("New dataset", self.table)
|
||||||
|
create_action.triggered.connect(self.create_clicked)
|
||||||
|
create_action.setShortcut("CTRL+N")
|
||||||
|
create_action.setShortcutContext(QtCore.Qt.WidgetShortcut)
|
||||||
|
self.table.addAction(create_action)
|
||||||
edit_action = QtWidgets.QAction("Edit dataset", self.table)
|
edit_action = QtWidgets.QAction("Edit dataset", self.table)
|
||||||
edit_action.triggered.connect(self.edit_clicked)
|
edit_action.triggered.connect(self.edit_clicked)
|
||||||
edit_action.setShortcut("RETURN")
|
edit_action.setShortcut("RETURN")
|
||||||
|
@ -146,6 +214,9 @@ class DatasetsDock(QtWidgets.QDockWidget):
|
||||||
self.table_model_filter.setSourceModel(self.table_model)
|
self.table_model_filter.setSourceModel(self.table_model)
|
||||||
self.table.setModel(self.table_model_filter)
|
self.table.setModel(self.table_model_filter)
|
||||||
|
|
||||||
|
def create_clicked(self):
|
||||||
|
Creator(self, self.dataset_ctl).open()
|
||||||
|
|
||||||
def edit_clicked(self):
|
def edit_clicked(self):
|
||||||
idx = self.table.selectedIndexes()
|
idx = self.table.selectedIndexes()
|
||||||
if idx:
|
if idx:
|
||||||
|
|
|
@ -191,10 +191,8 @@ device_db = {
|
||||||
"arguments": {
|
"arguments": {
|
||||||
"channel": 24,
|
"channel": 24,
|
||||||
"pgia_device": "spi_sampler0_pgia",
|
"pgia_device": "spi_sampler0_pgia",
|
||||||
"cpld0_device": "urukul0_cpld",
|
"cpld_devices": ["urukul0_cpld", "urukul1_cpld"],
|
||||||
"cpld1_device": "urukul1_cpld",
|
"dds_devices": ["urukul0_dds", "urukul1_dds"],
|
||||||
"dds0_device": "urukul0_dds",
|
|
||||||
"dds1_device": "urukul1_dds"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -1,56 +1,84 @@
|
||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "0.7.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "alloc_list"
|
name = "alloc_list"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bare-metal"
|
||||||
version = "1.0.3"
|
version = "0.2.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3"
|
||||||
|
dependencies = [
|
||||||
|
"rustc_version",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bit_field"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "board_artiq"
|
name = "board_artiq"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags",
|
||||||
"board_misoc 0.0.0",
|
"board_misoc",
|
||||||
"build_misoc 0.0.0",
|
"build_misoc",
|
||||||
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder",
|
||||||
"crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"crc",
|
||||||
"failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"failure",
|
||||||
"failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"failure_derive",
|
||||||
"io 0.0.0",
|
"io",
|
||||||
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log",
|
||||||
"proto_artiq 0.0.0",
|
"proto_artiq",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "board_misoc"
|
name = "board_misoc"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"build_misoc 0.0.0",
|
"build_misoc",
|
||||||
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder",
|
||||||
"cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cc",
|
||||||
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log",
|
||||||
"smoltcp 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"riscv",
|
||||||
|
"smoltcp",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bootloader"
|
name = "bootloader"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"board_misoc 0.0.0",
|
"board_misoc",
|
||||||
"build_misoc 0.0.0",
|
"build_misoc",
|
||||||
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder",
|
||||||
"crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"crc",
|
||||||
"smoltcp 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"riscv",
|
||||||
|
"smoltcp",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "build_const"
|
name = "build_const"
|
||||||
version = "0.2.1"
|
version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b4ae4235e6dac0694637c763029ecea1a2ec9e4e06ec2729bd21ba4d9c863eb7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "build_misoc"
|
name = "build_misoc"
|
||||||
|
@ -58,31 +86,48 @@ version = "0.0.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
version = "1.2.3"
|
version = "1.4.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.15"
|
version = "1.0.70"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "0.1.3"
|
version = "0.1.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "compiler_builtins"
|
||||||
|
version = "0.1.39"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3748f82c7d366a0b4950257d19db685d4958d2fa27c6d164a3f069fec42b748b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crc"
|
name = "crc"
|
||||||
version = "1.8.1"
|
version = "1.8.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"build_const",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cslice"
|
name = "cslice"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0f8cb7306107e4b10e64994de6d3274bd08996a7c1322a27b86482392f96be0a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dyld"
|
name = "dyld"
|
||||||
|
@ -92,202 +137,290 @@ version = "0.0.0"
|
||||||
name = "eh"
|
name = "eh"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"compiler_builtins",
|
||||||
|
"cslice",
|
||||||
|
"libc 0.1.0",
|
||||||
|
"unwind",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "failure"
|
name = "failure"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "934799b6c1de475a012a02dab0ace1ace43789ee4b99bcfbf1a2e3e8ced5de82"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "failure_derive"
|
name = "failure_derive"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c7cdda555bb90c9bb67a3b670a0f42de8e73f5981524123ad8578aafec8ddb8b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote",
|
||||||
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn",
|
||||||
"synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fringe"
|
name = "fringe"
|
||||||
version = "1.1.0"
|
version = "1.2.1"
|
||||||
source = "git+https://github.com/m-labs/libfringe?rev=b8a6d8f#b8a6d8f68df0edaa3d67d9f3b7b62af9d3bb64a5"
|
source = "git+https://git.m-labs.hk/M-Labs/libfringe.git?rev=3ecbe5#3ecbe53f7644b18ee46ebd5b2ca12c9cbceec43a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "io"
|
name = "io"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder",
|
||||||
"failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"failure",
|
||||||
"failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"failure_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ksupport"
|
name = "ksupport"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"board_artiq 0.0.0",
|
"board_artiq",
|
||||||
"board_misoc 0.0.0",
|
"board_misoc",
|
||||||
"build_misoc 0.0.0",
|
"build_misoc",
|
||||||
"cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cslice",
|
||||||
"dyld 0.0.0",
|
"dyld",
|
||||||
"eh 0.0.0",
|
"eh",
|
||||||
"io 0.0.0",
|
"io",
|
||||||
"proto_artiq 0.0.0",
|
"libc 0.1.0",
|
||||||
|
"proto_artiq",
|
||||||
|
"riscv",
|
||||||
|
"unwind",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "lazy_static"
|
||||||
version = "0.2.40"
|
version = "1.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.101"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.1"
|
version = "0.4.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cfg-if 1.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log_buffer"
|
name = "log_buffer"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f033173c9486b7fe97a79c895c0a3483ae395ab6744c985d10078950e2492419"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "logger_artiq"
|
name = "logger_artiq"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"board_misoc 0.0.0",
|
"board_misoc",
|
||||||
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log",
|
||||||
"log_buffer 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log_buffer",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "managed"
|
name = "managed"
|
||||||
version = "0.7.0"
|
version = "0.7.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c75de51135344a4f8ed3cfe2720dc27736f7711989703a0b43aadf3753c55577"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proto_artiq"
|
name = "proto_artiq"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder",
|
||||||
"cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cslice",
|
||||||
"dyld 0.0.0",
|
"dyld",
|
||||||
"failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"failure",
|
||||||
"failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"failure_derive",
|
||||||
"io 0.0.0",
|
"io",
|
||||||
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "0.3.15"
|
version = "0.3.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.5.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.6.25"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "riscv"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a2f0b705d428e9d0f78e2bb73093887ee58a83c9688de3faedbb4c0631c4618e"
|
||||||
|
dependencies = [
|
||||||
|
"bare-metal",
|
||||||
|
"bit_field",
|
||||||
|
"riscv-target",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "riscv-target"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "88aa938cda42a0cf62a20cfe8d139ff1af20c2e681212b5b34adb5a58333f222"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"regex",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "runtime"
|
name = "runtime"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"alloc_list 0.0.0",
|
"alloc_list",
|
||||||
"board_artiq 0.0.0",
|
"board_artiq",
|
||||||
"board_misoc 0.0.0",
|
"board_misoc",
|
||||||
"build_misoc 0.0.0",
|
"build_misoc",
|
||||||
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder",
|
||||||
"cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cslice",
|
||||||
"eh 0.0.0",
|
"eh",
|
||||||
"failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"failure",
|
||||||
"failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"failure_derive",
|
||||||
"fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=b8a6d8f)",
|
"fringe",
|
||||||
"io 0.0.0",
|
"io",
|
||||||
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log",
|
||||||
"logger_artiq 0.0.0",
|
"logger_artiq",
|
||||||
"managed 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"managed",
|
||||||
"proto_artiq 0.0.0",
|
"proto_artiq",
|
||||||
"smoltcp 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"riscv",
|
||||||
"unwind_backtrace 0.0.0",
|
"smoltcp",
|
||||||
|
"unwind_backtrace",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc_version"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||||
|
dependencies = [
|
||||||
|
"semver",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "satman"
|
name = "satman"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"board_artiq 0.0.0",
|
"board_artiq",
|
||||||
"board_misoc 0.0.0",
|
"board_misoc",
|
||||||
"build_misoc 0.0.0",
|
"build_misoc",
|
||||||
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log",
|
||||||
|
"riscv",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "semver"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||||
|
dependencies = [
|
||||||
|
"semver-parser",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "semver-parser"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smoltcp"
|
name = "smoltcp"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0fe46639fd2ec79eadf8fe719f237a7a0bd4dac5d957f1ca5bbdbc1c3c39e53a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags",
|
||||||
"byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder",
|
||||||
"managed 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"managed",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "0.11.11"
|
version = "0.11.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote",
|
||||||
"synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"synom",
|
||||||
"unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "synom"
|
name = "synom"
|
||||||
version = "0.11.3"
|
version = "0.11.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "synstructure"
|
name = "synstructure"
|
||||||
version = "0.6.1"
|
version = "0.6.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote",
|
||||||
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-xid"
|
name = "unicode-xid"
|
||||||
version = "0.0.4"
|
version = "0.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unwind"
|
||||||
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 0.1.10",
|
||||||
|
"libc 0.1.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unwind_backtrace"
|
name = "unwind_backtrace"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
dependencies = [
|
||||||
[metadata]
|
"libc 0.1.0",
|
||||||
"checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789"
|
"unwind",
|
||||||
"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39"
|
]
|
||||||
"checksum byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74c0b906e9446b0a2e4f760cdb3fa4b2c48cdc6db8766a845c54b6ff063fd2e9"
|
|
||||||
"checksum cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "0ebb87d1116151416c0cf66a0e3fb6430cccd120fd6300794b4dfaa050ac40ba"
|
|
||||||
"checksum cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "405216fd8fe65f718daa7102ea808a946b6ce40c742998fbfd3463645552de18"
|
|
||||||
"checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb"
|
|
||||||
"checksum cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0f8cb7306107e4b10e64994de6d3274bd08996a7c1322a27b86482392f96be0a"
|
|
||||||
"checksum failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "934799b6c1de475a012a02dab0ace1ace43789ee4b99bcfbf1a2e3e8ced5de82"
|
|
||||||
"checksum failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cdda555bb90c9bb67a3b670a0f42de8e73f5981524123ad8578aafec8ddb8b"
|
|
||||||
"checksum fringe 1.1.0 (git+https://github.com/m-labs/libfringe?rev=b8a6d8f)" = "<none>"
|
|
||||||
"checksum libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)" = "6fd41f331ac7c5b8ac259b8bf82c75c0fb2e469bbf37d2becbba9a6a2221965b"
|
|
||||||
"checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2"
|
|
||||||
"checksum log_buffer 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f033173c9486b7fe97a79c895c0a3483ae395ab6744c985d10078950e2492419"
|
|
||||||
"checksum managed 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba6713e624266d7600e9feae51b1926c6a6a6bebb18ec5a8e11a5f1d5661baba"
|
|
||||||
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
|
|
||||||
"checksum smoltcp 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0fe46639fd2ec79eadf8fe719f237a7a0bd4dac5d957f1ca5bbdbc1c3c39e53a"
|
|
||||||
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
|
|
||||||
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
|
|
||||||
"checksum synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd"
|
|
||||||
"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
|
|
||||||
|
|
|
@ -17,3 +17,4 @@ byteorder = { version = "1.0", default-features = false }
|
||||||
crc = { version = "1.7", default-features = false }
|
crc = { version = "1.7", default-features = false }
|
||||||
board_misoc = { path = "../libboard_misoc", features = ["uart_console", "smoltcp"] }
|
board_misoc = { path = "../libboard_misoc", features = ["uart_console", "smoltcp"] }
|
||||||
smoltcp = { version = "0.6.0", default-features = false, features = ["ethernet", "proto-ipv4", "proto-ipv6", "socket-tcp"] }
|
smoltcp = { version = "0.6.0", default-features = false, features = ["ethernet", "proto-ipv4", "proto-ipv6", "socket-tcp"] }
|
||||||
|
riscv = { version = "0.6.0", features = ["inline-asm"] }
|
||||||
|
|
|
@ -3,15 +3,19 @@ include $(MISOC_DIRECTORY)/software/common.mak
|
||||||
|
|
||||||
RUSTFLAGS += -Cpanic=abort
|
RUSTFLAGS += -Cpanic=abort
|
||||||
|
|
||||||
|
export XBUILD_SYSROOT_PATH=$(BUILDINC_DIRECTORY)/../sysroot
|
||||||
|
|
||||||
all:: bootloader.bin
|
all:: bootloader.bin
|
||||||
|
|
||||||
.PHONY: $(RUSTOUT)/libbootloader.a
|
.PHONY: $(RUSTOUT)/libbootloader.a
|
||||||
$(RUSTOUT)/libbootloader.a:
|
$(RUSTOUT)/libbootloader.a:
|
||||||
$(cargo) --manifest-path $(BOOTLOADER_DIRECTORY)/Cargo.toml
|
$(cargo) --target-dir ./cargo \
|
||||||
|
--manifest-path $(BOOTLOADER_DIRECTORY)/Cargo.toml \
|
||||||
|
--target $(BOOTLOADER_DIRECTORY)/../$(CARGO_TRIPLE).json
|
||||||
|
|
||||||
bootloader.elf: $(RUSTOUT)/libbootloader.a
|
bootloader.elf: $(RUSTOUT)/libbootloader.a
|
||||||
$(link) -T $(BOOTLOADER_DIRECTORY)/bootloader.ld
|
$(link) -T $(BOOTLOADER_DIRECTORY)/bootloader.ld
|
||||||
|
|
||||||
%.bin: %.elf
|
%.bin: %.elf
|
||||||
$(objcopy) -O binary
|
$(objcopy) -O binary
|
||||||
$(MSCIMG) $@
|
$(MSCIMG) $@ --little
|
||||||
|
|
|
@ -15,12 +15,10 @@ SECTIONS
|
||||||
*(.text .text.*)
|
*(.text .text.*)
|
||||||
} > rom
|
} > rom
|
||||||
|
|
||||||
/*
|
.eh_frame :
|
||||||
* The compiler_builtins crate includes some GOTPC relocations, which require a GOT symbol,
|
{
|
||||||
* but don't actually need a GOT. This really ought to be fixed on rustc level, but I'm afraid
|
*(.eh_frame.*)
|
||||||
* it will add further complications to our build system that aren't pulling their weight.
|
} > rom
|
||||||
*/
|
|
||||||
_GLOBAL_OFFSET_TABLE_ = .;
|
|
||||||
|
|
||||||
.rodata :
|
.rodata :
|
||||||
{
|
{
|
||||||
|
@ -29,25 +27,25 @@ SECTIONS
|
||||||
_end = .;
|
_end = .;
|
||||||
} > rom
|
} > rom
|
||||||
|
|
||||||
.crc ALIGN(4) :
|
.crc (NOLOAD) : ALIGN(4)
|
||||||
{
|
{
|
||||||
_crc = .;
|
_crc = .;
|
||||||
. += 4;
|
. += 4;
|
||||||
}
|
} > rom
|
||||||
|
|
||||||
.bss :
|
.bss (NOLOAD) :
|
||||||
{
|
{
|
||||||
_fbss = .;
|
_fbss = .;
|
||||||
*(.bss .bss.*)
|
*(.sbss .sbss.* .bss .bss.*);
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
_ebss = .;
|
_ebss = .;
|
||||||
} > sram
|
} > sram
|
||||||
|
|
||||||
.stack :
|
.stack (NOLOAD) : ALIGN(16)
|
||||||
{
|
{
|
||||||
/* Ensure we have a certain amount of space available for stack. */
|
/* Ensure we have a certain amount of space available for stack. */
|
||||||
/*. = ORIGIN(sram) + LENGTH(sram) - 0x1a00; */
|
/*. = ORIGIN(sram) + LENGTH(sram) - 0x1a00; */
|
||||||
. = ORIGIN(sram) + LENGTH(sram) - 4;
|
. = ORIGIN(sram) + LENGTH(sram) - 16;
|
||||||
_fstack = .;
|
_fstack = .;
|
||||||
} > sram
|
} > sram
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,23 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![feature(panic_implementation, panic_info_message)]
|
#![feature(panic_info_message)]
|
||||||
|
|
||||||
extern crate crc;
|
extern crate crc;
|
||||||
extern crate byteorder;
|
extern crate byteorder;
|
||||||
extern crate smoltcp;
|
extern crate smoltcp;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate board_misoc;
|
extern crate board_misoc;
|
||||||
|
extern crate riscv;
|
||||||
|
|
||||||
use core::{ptr, slice};
|
use core::{ptr, slice, convert::TryFrom};
|
||||||
use crc::crc32;
|
use crc::crc32;
|
||||||
use byteorder::{ByteOrder, BigEndian};
|
use byteorder::{ByteOrder, LittleEndian};
|
||||||
use board_misoc::{ident, cache, sdram, config, boot, mem as board_mem};
|
use board_misoc::{ident, cache, sdram, config, boot, mem as board_mem};
|
||||||
#[cfg(has_slave_fpga_cfg)]
|
#[cfg(has_slave_fpga_cfg)]
|
||||||
use board_misoc::slave_fpga;
|
use board_misoc::slave_fpga;
|
||||||
#[cfg(has_ethmac)]
|
#[cfg(has_ethmac)]
|
||||||
use board_misoc::{clock, ethmac, net_settings};
|
use board_misoc::{clock, ethmac, net_settings};
|
||||||
use board_misoc::uart_console::Console;
|
use board_misoc::uart_console::Console;
|
||||||
|
use riscv::register::{mcause, mepc, mtval};
|
||||||
|
|
||||||
fn check_integrity() -> bool {
|
fn check_integrity() -> bool {
|
||||||
extern {
|
extern {
|
||||||
|
@ -45,7 +47,7 @@ fn memory_test(total: &mut usize, wrong: &mut usize) -> bool {
|
||||||
MEMORY[$index:expr] = $data:expr
|
MEMORY[$index:expr] = $data:expr
|
||||||
}
|
}
|
||||||
) => ({
|
) => ({
|
||||||
$prepare;
|
$prepare
|
||||||
for $i in $range {
|
for $i in $range {
|
||||||
unsafe { ptr::write_volatile(MEMORY.offset($index as isize), $data) };
|
unsafe { ptr::write_volatile(MEMORY.offset($index as isize), $data) };
|
||||||
*total += 1;
|
*total += 1;
|
||||||
|
@ -54,7 +56,7 @@ fn memory_test(total: &mut usize, wrong: &mut usize) -> bool {
|
||||||
cache::flush_cpu_dcache();
|
cache::flush_cpu_dcache();
|
||||||
cache::flush_l2_cache();
|
cache::flush_l2_cache();
|
||||||
|
|
||||||
$prepare;
|
$prepare
|
||||||
for $i in $range {
|
for $i in $range {
|
||||||
if unsafe { ptr::read_volatile(MEMORY.offset($index as isize)) } != $data {
|
if unsafe { ptr::read_volatile(MEMORY.offset($index as isize)) } != $data {
|
||||||
*wrong += 1;
|
*wrong += 1;
|
||||||
|
@ -119,8 +121,8 @@ fn load_slave_fpga() {
|
||||||
const GATEWARE: *mut u8 = board_misoc::csr::CONFIG_SLAVE_FPGA_GATEWARE as *mut u8;
|
const GATEWARE: *mut u8 = board_misoc::csr::CONFIG_SLAVE_FPGA_GATEWARE as *mut u8;
|
||||||
|
|
||||||
let header = unsafe { slice::from_raw_parts(GATEWARE, 8) };
|
let header = unsafe { slice::from_raw_parts(GATEWARE, 8) };
|
||||||
let magic = BigEndian::read_u32(&header[0..]);
|
let magic = LittleEndian::read_u32(&header[0..]);
|
||||||
let length = BigEndian::read_u32(&header[4..]) as usize;
|
let length = LittleEndian::read_u32(&header[4..]) as usize;
|
||||||
println!(" magic: 0x{:08x}, length: 0x{:08x}", magic, length);
|
println!(" magic: 0x{:08x}, length: 0x{:08x}", magic, length);
|
||||||
if magic != 0x5352544d {
|
if magic != 0x5352544d {
|
||||||
println!(" ...Error: bad magic");
|
println!(" ...Error: bad magic");
|
||||||
|
@ -155,8 +157,8 @@ fn flash_boot() {
|
||||||
println!("Booting from flash...");
|
println!("Booting from flash...");
|
||||||
|
|
||||||
let header = unsafe { slice::from_raw_parts(FIRMWARE, 8) };
|
let header = unsafe { slice::from_raw_parts(FIRMWARE, 8) };
|
||||||
let length = BigEndian::read_u32(&header[0..]) as usize;
|
let length = LittleEndian::read_u32(&header[0..]) as usize;
|
||||||
let expected_crc = BigEndian::read_u32(&header[4..]);
|
let expected_crc = LittleEndian::read_u32(&header[4..]);
|
||||||
|
|
||||||
if length == 0 || length == 0xffffffff {
|
if length == 0 || length == 0xffffffff {
|
||||||
println!("No firmware present");
|
println!("No firmware present");
|
||||||
|
@ -517,8 +519,11 @@ pub extern fn main() -> i32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern fn exception(vect: u32, _regs: *const u32, pc: u32, ea: u32) {
|
pub extern fn exception(_regs: *const u32) {
|
||||||
panic!("exception {} at PC {:#08x}, EA {:#08x}", vect, pc, ea)
|
let pc = mepc::read();
|
||||||
|
let cause = mcause::read().cause();
|
||||||
|
let mtval = mtval::read();
|
||||||
|
panic!("{:?} at PC {:#08x}, trap value {:#08x}", cause, u32::try_from(pc).unwrap(), mtval);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -528,7 +533,7 @@ pub extern fn abort() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle] // https://github.com/rust-lang/rust/issues/{38281,51647}
|
#[no_mangle] // https://github.com/rust-lang/rust/issues/{38281,51647}
|
||||||
#[panic_implementation]
|
#[panic_handler]
|
||||||
pub fn panic_fmt(info: &core::panic::PanicInfo) -> ! {
|
pub fn panic_fmt(info: &core::panic::PanicInfo) -> ! {
|
||||||
#[cfg(has_error_led)]
|
#[cfg(has_error_led)]
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
"0ml6j4sxqrayqk25xkrikwg713mahfqa60nrx1jhrj8c2h3p07yk"
|
|
|
@ -20,3 +20,6 @@ dyld = { path = "../libdyld" }
|
||||||
board_misoc = { path = "../libboard_misoc" }
|
board_misoc = { path = "../libboard_misoc" }
|
||||||
board_artiq = { path = "../libboard_artiq" }
|
board_artiq = { path = "../libboard_artiq" }
|
||||||
proto_artiq = { path = "../libproto_artiq" }
|
proto_artiq = { path = "../libproto_artiq" }
|
||||||
|
riscv = { version = "0.6.0", features = ["inline-asm"] }
|
||||||
|
libc = { path = "../libc" }
|
||||||
|
unwind = { path = "../libunwind" }
|
||||||
|
|
|
@ -7,21 +7,26 @@ CFLAGS += \
|
||||||
-I$(MISOC_DIRECTORY)/software/include/dyld
|
-I$(MISOC_DIRECTORY)/software/include/dyld
|
||||||
|
|
||||||
LDFLAGS += --eh-frame-hdr \
|
LDFLAGS += --eh-frame-hdr \
|
||||||
|
--nmagic \
|
||||||
-L../libm \
|
-L../libm \
|
||||||
-L../libprintf \
|
-L../libprintf \
|
||||||
-L../libunwind
|
-L../libunwind
|
||||||
|
|
||||||
RUSTFLAGS += -Cpanic=unwind
|
RUSTFLAGS += -Cpanic=unwind
|
||||||
|
|
||||||
|
export XBUILD_SYSROOT_PATH=$(BUILDINC_DIRECTORY)/../sysroot
|
||||||
|
|
||||||
all:: ksupport.elf
|
all:: ksupport.elf
|
||||||
|
|
||||||
.PHONY: $(RUSTOUT)/libksupport.a
|
.PHONY: $(RUSTOUT)/libksupport.a
|
||||||
$(RUSTOUT)/libksupport.a:
|
$(RUSTOUT)/libksupport.a:
|
||||||
$(cargo) --manifest-path $(KSUPPORT_DIRECTORY)/Cargo.toml
|
$(cargo) --target-dir ./cargo \
|
||||||
|
--manifest-path $(KSUPPORT_DIRECTORY)/Cargo.toml \
|
||||||
|
--target $(KSUPPORT_DIRECTORY)/../$(CARGO_TRIPLE).json
|
||||||
|
|
||||||
ksupport.elf: $(RUSTOUT)/libksupport.a glue.o
|
ksupport.elf: $(RUSTOUT)/libksupport.a glue.o
|
||||||
$(link) -T $(KSUPPORT_DIRECTORY)/ksupport.ld \
|
$(link) -T $(KSUPPORT_DIRECTORY)/ksupport.ld \
|
||||||
-lunwind-elf -lprintf-float -lm
|
-lunwind-$(CPU)-elf -lprintf-float -lm
|
||||||
|
|
||||||
%.o: $(KSUPPORT_DIRECTORY)/%.c
|
%.o: $(KSUPPORT_DIRECTORY)/%.c
|
||||||
$(compile)
|
$(compile)
|
||||||
|
|
|
@ -131,9 +131,6 @@ static mut API: &'static [(&'static str, *const ())] = &[
|
||||||
api!(cache_get = ::cache_get),
|
api!(cache_get = ::cache_get),
|
||||||
api!(cache_put = ::cache_put),
|
api!(cache_put = ::cache_put),
|
||||||
|
|
||||||
api!(mfspr = ::board_misoc::spr::mfspr),
|
|
||||||
api!(mtspr = ::board_misoc::spr::mtspr),
|
|
||||||
|
|
||||||
/* direct syscalls */
|
/* direct syscalls */
|
||||||
api!(rtio_init = ::rtio::init),
|
api!(rtio_init = ::rtio::init),
|
||||||
api!(rtio_get_destination_status = ::rtio::get_destination_status),
|
api!(rtio_get_destination_status = ::rtio::get_destination_status),
|
||||||
|
|
|
@ -8,14 +8,14 @@
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
#![allow(private_no_mangle_fns, non_camel_case_types)]
|
#![allow(non_camel_case_types)]
|
||||||
|
|
||||||
use core::{ptr, mem};
|
use core::{ptr, mem};
|
||||||
use cslice::CSlice;
|
use cslice::CSlice;
|
||||||
use unwind as uw;
|
use unwind as uw;
|
||||||
use libc::{c_int, c_void};
|
use libc::{c_int, c_void};
|
||||||
|
|
||||||
use eh::dwarf::{self, EHAction};
|
use eh::dwarf::{self, EHAction, EHContext};
|
||||||
|
|
||||||
type _Unwind_Stop_Fn = extern "C" fn(version: c_int,
|
type _Unwind_Stop_Fn = extern "C" fn(version: c_int,
|
||||||
actions: uw::_Unwind_Action,
|
actions: uw::_Unwind_Action,
|
||||||
|
@ -58,8 +58,8 @@ struct ExceptionInfo {
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX
|
const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX
|
||||||
|
|
||||||
#[cfg(any(target_arch = "or1k"))]
|
#[cfg(any(target_arch = "riscv32"))]
|
||||||
const UNWIND_DATA_REG: (i32, i32) = (3, 4); // R3, R4
|
const UNWIND_DATA_REG: (i32, i32) = (10, 11); // X10, X11
|
||||||
|
|
||||||
#[export_name="__artiq_personality"]
|
#[export_name="__artiq_personality"]
|
||||||
pub extern fn personality(version: c_int,
|
pub extern fn personality(version: c_int,
|
||||||
|
@ -74,13 +74,25 @@ pub extern fn personality(version: c_int,
|
||||||
}
|
}
|
||||||
|
|
||||||
let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8;
|
let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8;
|
||||||
let ip = uw::_Unwind_GetIP(context) - 1;
|
let mut ip_before_instr: c_int = 0;
|
||||||
let func_start = uw::_Unwind_GetRegionStart(context);
|
let ip = uw::_Unwind_GetIPInfo(context, &mut ip_before_instr);
|
||||||
|
let eh_context = EHContext {
|
||||||
|
// The return address points 1 byte past the call instruction,
|
||||||
|
// which could be in the next IP range in LSDA range table.
|
||||||
|
ip: if ip_before_instr != 0 { ip } else { ip - 1 },
|
||||||
|
func_start: uw::_Unwind_GetRegionStart(context),
|
||||||
|
get_text_start: &|| uw::_Unwind_GetTextRelBase(context),
|
||||||
|
get_data_start: &|| uw::_Unwind_GetDataRelBase(context),
|
||||||
|
};
|
||||||
|
|
||||||
let exception_info = &mut *(uw_exception as *mut ExceptionInfo);
|
let exception_info = &mut *(uw_exception as *mut ExceptionInfo);
|
||||||
let exception = &exception_info.exception.unwrap();
|
let exception = &exception_info.exception.unwrap();
|
||||||
|
|
||||||
let eh_action = dwarf::find_eh_action(lsda, func_start, ip, exception.name);
|
let eh_action = match dwarf::find_eh_action(lsda, &eh_context) {
|
||||||
|
Ok(action) => action,
|
||||||
|
Err(_) => return uw::_URC_FATAL_PHASE1_ERROR,
|
||||||
|
};
|
||||||
|
|
||||||
if actions as u32 & uw::_UA_SEARCH_PHASE as u32 != 0 {
|
if actions as u32 & uw::_UA_SEARCH_PHASE as u32 != 0 {
|
||||||
match eh_action {
|
match eh_action {
|
||||||
EHAction::None |
|
EHAction::None |
|
||||||
|
|
|
@ -15,7 +15,7 @@ MEMORY {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Kernel stack is at the end of main RAM. */
|
/* Kernel stack is at the end of main RAM. */
|
||||||
_fstack = ORIGIN(main_ram) + LENGTH(main_ram) - 4;
|
_fstack = ORIGIN(main_ram) + LENGTH(main_ram) - 16;
|
||||||
|
|
||||||
/* Force ld to make the ELF header as loadable. */
|
/* Force ld to make the ELF header as loadable. */
|
||||||
PHDRS
|
PHDRS
|
||||||
|
@ -53,22 +53,22 @@ SECTIONS
|
||||||
.eh_frame :
|
.eh_frame :
|
||||||
{
|
{
|
||||||
KEEP(*(.eh_frame))
|
KEEP(*(.eh_frame))
|
||||||
} :text
|
} > ksupport :text
|
||||||
|
|
||||||
.eh_frame_hdr :
|
.eh_frame_hdr :
|
||||||
{
|
{
|
||||||
KEEP(*(.eh_frame_hdr))
|
KEEP(*(.eh_frame_hdr))
|
||||||
} :text :eh_frame
|
} > ksupport :text :eh_frame
|
||||||
|
|
||||||
.data :
|
.data :
|
||||||
{
|
{
|
||||||
*(.data .data.*)
|
*(.data .data.*)
|
||||||
}
|
}
|
||||||
|
|
||||||
.bss :
|
.bss (NOLOAD) : ALIGN(4)
|
||||||
{
|
{
|
||||||
_fbss = .;
|
_fbss = .;
|
||||||
*(.bss .bss.*)
|
*(.sbss .sbss.* .bss .bss.*);
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
_ebss = .;
|
_ebss = .;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#![feature(lang_items, asm, panic_unwind, libc, unwind_attributes,
|
#![feature(lang_items, llvm_asm, panic_unwind, libc, unwind_attributes,
|
||||||
panic_implementation, panic_info_message, nll)]
|
panic_info_message, nll)]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
@ -12,8 +12,9 @@ extern crate dyld;
|
||||||
extern crate board_misoc;
|
extern crate board_misoc;
|
||||||
extern crate board_artiq;
|
extern crate board_artiq;
|
||||||
extern crate proto_artiq;
|
extern crate proto_artiq;
|
||||||
|
extern crate riscv;
|
||||||
|
|
||||||
use core::{mem, ptr, slice, str};
|
use core::{mem, ptr, slice, str, convert::TryFrom};
|
||||||
use cslice::{CSlice, AsCSlice};
|
use cslice::{CSlice, AsCSlice};
|
||||||
use io::Cursor;
|
use io::Cursor;
|
||||||
use dyld::Library;
|
use dyld::Library;
|
||||||
|
@ -22,6 +23,7 @@ use proto_artiq::{kernel_proto, rpc_proto};
|
||||||
use kernel_proto::*;
|
use kernel_proto::*;
|
||||||
#[cfg(has_rtio_dma)]
|
#[cfg(has_rtio_dma)]
|
||||||
use board_misoc::csr;
|
use board_misoc::csr;
|
||||||
|
use riscv::register::{mcause, mepc, mtval};
|
||||||
|
|
||||||
fn send(request: &Message) {
|
fn send(request: &Message) {
|
||||||
unsafe { mailbox::send(request as *const _ as usize) }
|
unsafe { mailbox::send(request as *const _ as usize) }
|
||||||
|
@ -49,7 +51,7 @@ macro_rules! recv {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle] // https://github.com/rust-lang/rust/issues/{38281,51647}
|
#[no_mangle] // https://github.com/rust-lang/rust/issues/{38281,51647}
|
||||||
#[panic_implementation]
|
#[panic_handler]
|
||||||
pub fn panic_fmt(info: &core::panic::PanicInfo) -> ! {
|
pub fn panic_fmt(info: &core::panic::PanicInfo) -> ! {
|
||||||
if let Some(location) = info.location() {
|
if let Some(location) = info.location() {
|
||||||
send(&Log(format_args!("panic at {}:{}:{}",
|
send(&Log(format_args!("panic at {}:{}:{}",
|
||||||
|
@ -120,7 +122,7 @@ pub extern fn send_to_rtio_log(text: CSlice<u8>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unwind(aborts)]
|
#[unwind(aborts)]
|
||||||
extern fn rpc_send(service: u32, tag: CSlice<u8>, data: *const *const ()) {
|
extern fn rpc_send(service: u32, tag: &CSlice<u8>, data: *const *const ()) {
|
||||||
while !rpc_queue::empty() {}
|
while !rpc_queue::empty() {}
|
||||||
send(&RpcSend {
|
send(&RpcSend {
|
||||||
async: false,
|
async: false,
|
||||||
|
@ -131,7 +133,7 @@ extern fn rpc_send(service: u32, tag: CSlice<u8>, data: *const *const ()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unwind(aborts)]
|
#[unwind(aborts)]
|
||||||
extern fn rpc_send_async(service: u32, tag: CSlice<u8>, data: *const *const ()) {
|
extern fn rpc_send_async(service: u32, tag: &CSlice<u8>, data: *const *const ()) {
|
||||||
while rpc_queue::full() {}
|
while rpc_queue::full() {}
|
||||||
rpc_queue::enqueue(|mut slice| {
|
rpc_queue::enqueue(|mut slice| {
|
||||||
let length = {
|
let length = {
|
||||||
|
@ -201,15 +203,18 @@ fn terminate(exception: &eh_artiq::Exception, backtrace: &mut [usize]) -> ! {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unwind(aborts)]
|
#[unwind(aborts)]
|
||||||
extern fn cache_get(key: CSlice<u8>) -> CSlice<'static, i32> {
|
extern fn cache_get<'a>(ret: &'a mut CSlice<i32>, key: &CSlice<u8>) -> &'a CSlice<'a, i32> {
|
||||||
send(&CacheGetRequest {
|
send(&CacheGetRequest {
|
||||||
key: str::from_utf8(key.as_ref()).unwrap()
|
key: str::from_utf8(key.as_ref()).unwrap()
|
||||||
});
|
});
|
||||||
recv!(&CacheGetReply { value } => value.as_c_slice())
|
recv!(&CacheGetReply { value } => {
|
||||||
|
*ret = value.as_c_slice();
|
||||||
|
ret
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unwind(allowed)]
|
#[unwind(allowed)]
|
||||||
extern fn cache_put(key: CSlice<u8>, list: CSlice<i32>) {
|
extern fn cache_put(key: &CSlice<u8>, list: &CSlice<i32>) {
|
||||||
send(&CachePutRequest {
|
send(&CachePutRequest {
|
||||||
key: str::from_utf8(key.as_ref()).unwrap(),
|
key: str::from_utf8(key.as_ref()).unwrap(),
|
||||||
value: list.as_ref()
|
value: list.as_ref()
|
||||||
|
@ -243,7 +248,7 @@ fn dma_record_flush() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unwind(allowed)]
|
#[unwind(allowed)]
|
||||||
extern fn dma_record_start(name: CSlice<u8>) {
|
extern fn dma_record_start(name: &CSlice<u8>) {
|
||||||
let name = str::from_utf8(name.as_ref()).unwrap();
|
let name = str::from_utf8(name.as_ref()).unwrap();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -324,7 +329,7 @@ unsafe fn dma_record_output_prepare(timestamp: i64, target: i32,
|
||||||
#[unwind(aborts)]
|
#[unwind(aborts)]
|
||||||
extern fn dma_record_output(target: i32, word: i32) {
|
extern fn dma_record_output(target: i32, word: i32) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let timestamp = *(csr::rtio::NOW_HI_ADDR as *const i64);
|
let timestamp = ((csr::rtio::now_hi_read() as i64) << 32) | (csr::rtio::now_lo_read() as i64);
|
||||||
let data = dma_record_output_prepare(timestamp, target, 1);
|
let data = dma_record_output_prepare(timestamp, target, 1);
|
||||||
data.copy_from_slice(&[
|
data.copy_from_slice(&[
|
||||||
(word >> 0) as u8,
|
(word >> 0) as u8,
|
||||||
|
@ -340,7 +345,7 @@ extern fn dma_record_output_wide(target: i32, words: CSlice<i32>) {
|
||||||
assert!(words.len() <= 16); // enforce the hardware limit
|
assert!(words.len() <= 16); // enforce the hardware limit
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let timestamp = *(csr::rtio::NOW_HI_ADDR as *const i64);
|
let timestamp = ((csr::rtio::now_hi_read() as i64) << 32) | (csr::rtio::now_lo_read() as i64);
|
||||||
let mut data = dma_record_output_prepare(timestamp, target, words.len());
|
let mut data = dma_record_output_prepare(timestamp, target, words.len());
|
||||||
for word in words.as_ref().iter() {
|
for word in words.as_ref().iter() {
|
||||||
data[..4].copy_from_slice(&[
|
data[..4].copy_from_slice(&[
|
||||||
|
@ -355,7 +360,7 @@ extern fn dma_record_output_wide(target: i32, words: CSlice<i32>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unwind(aborts)]
|
#[unwind(aborts)]
|
||||||
extern fn dma_erase(name: CSlice<u8>) {
|
extern fn dma_erase(name: &CSlice<u8>) {
|
||||||
let name = str::from_utf8(name.as_ref()).unwrap();
|
let name = str::from_utf8(name.as_ref()).unwrap();
|
||||||
|
|
||||||
send(&DmaEraseRequest { name: name });
|
send(&DmaEraseRequest { name: name });
|
||||||
|
@ -368,7 +373,7 @@ struct DmaTrace {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unwind(allowed)]
|
#[unwind(allowed)]
|
||||||
extern fn dma_retrieve(name: CSlice<u8>) -> DmaTrace {
|
extern fn dma_retrieve(name: &CSlice<u8>) -> DmaTrace {
|
||||||
let name = str::from_utf8(name.as_ref()).unwrap();
|
let name = str::from_utf8(name.as_ref()).unwrap();
|
||||||
|
|
||||||
send(&DmaRetrieveRequest { name: name });
|
send(&DmaRetrieveRequest { name: name });
|
||||||
|
@ -454,7 +459,7 @@ unsafe fn attribute_writeback(typeinfo: *const ()) {
|
||||||
attributes = attributes.offset(1);
|
attributes = attributes.offset(1);
|
||||||
|
|
||||||
if (*attribute).tag.len() > 0 {
|
if (*attribute).tag.len() > 0 {
|
||||||
rpc_send_async(0, (*attribute).tag, [
|
rpc_send_async(0, &(*attribute).tag, [
|
||||||
&object as *const _ as *const (),
|
&object as *const _ as *const (),
|
||||||
&(*attribute).name as *const _ as *const (),
|
&(*attribute).name as *const _ as *const (),
|
||||||
(object as usize + (*attribute).offset) as *const ()
|
(object as usize + (*attribute).offset) as *const ()
|
||||||
|
@ -488,11 +493,16 @@ pub unsafe fn main() {
|
||||||
let _end = library.lookup(b"_end").unwrap();
|
let _end = library.lookup(b"_end").unwrap();
|
||||||
let __modinit__ = library.lookup(b"__modinit__").unwrap();
|
let __modinit__ = library.lookup(b"__modinit__").unwrap();
|
||||||
let typeinfo = library.lookup(b"typeinfo");
|
let typeinfo = library.lookup(b"typeinfo");
|
||||||
|
let _sstack_guard = library.lookup(b"_sstack_guard").unwrap();
|
||||||
|
|
||||||
LIBRARY = Some(library);
|
LIBRARY = Some(library);
|
||||||
|
|
||||||
ptr::write_bytes(__bss_start as *mut u8, 0, (_end - __bss_start) as usize);
|
ptr::write_bytes(__bss_start as *mut u8, 0, (_end - __bss_start) as usize);
|
||||||
|
|
||||||
|
board_misoc::pmp::init_stack_guard(_sstack_guard as usize);
|
||||||
|
board_misoc::cache::flush_cpu_dcache();
|
||||||
|
board_misoc::cache::flush_cpu_icache();
|
||||||
|
|
||||||
(mem::transmute::<u32, fn()>(__modinit__))();
|
(mem::transmute::<u32, fn()>(__modinit__))();
|
||||||
|
|
||||||
if let Some(typeinfo) = typeinfo {
|
if let Some(typeinfo) = typeinfo {
|
||||||
|
@ -519,8 +529,11 @@ pub unsafe fn main() {
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[unwind(allowed)]
|
#[unwind(allowed)]
|
||||||
pub extern fn exception(vect: u32, _regs: *const u32, pc: u32, ea: u32) {
|
pub extern fn exception(_regs: *const u32) {
|
||||||
panic!("exception {:?} at PC 0x{:x}, EA 0x{:x}", vect, pc, ea)
|
let pc = mepc::read();
|
||||||
|
let cause = mcause::read().cause();
|
||||||
|
let mtval = mtval::read();
|
||||||
|
panic!("{:?} at PC {:#08x}, trap value {:#08x}", cause, u32::try_from(pc).unwrap(), mtval);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
|
|
@ -23,6 +23,8 @@ mod imp {
|
||||||
pub const RTIO_I_STATUS_WAIT_STATUS: u8 = 4;
|
pub const RTIO_I_STATUS_WAIT_STATUS: u8 = 4;
|
||||||
pub const RTIO_I_STATUS_DESTINATION_UNREACHABLE: u8 = 8;
|
pub const RTIO_I_STATUS_DESTINATION_UNREACHABLE: u8 = 8;
|
||||||
|
|
||||||
|
const OFFSET_MULTIPLE: isize = (csr::CONFIG_DATA_WIDTH_BYTES / 4) as isize;
|
||||||
|
|
||||||
pub extern fn init() {
|
pub extern fn init() {
|
||||||
send(&RtioInitRequest);
|
send(&RtioInitRequest);
|
||||||
}
|
}
|
||||||
|
@ -47,19 +49,19 @@ mod imp {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn rtio_o_data_write(offset: usize, data: u32) {
|
pub unsafe fn rtio_o_data_write(offset: usize, data: u32) {
|
||||||
write_volatile(
|
write_volatile(
|
||||||
csr::rtio::O_DATA_ADDR.offset((csr::rtio::O_DATA_SIZE - 1 - offset) as isize),
|
csr::rtio::O_DATA_ADDR.offset(OFFSET_MULTIPLE*(csr::rtio::O_DATA_SIZE - 1 - offset) as isize),
|
||||||
data);
|
data);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub unsafe fn rtio_i_data_read(offset: usize) -> u32 {
|
pub unsafe fn rtio_i_data_read(offset: usize) -> u32 {
|
||||||
read_volatile(
|
read_volatile(
|
||||||
csr::rtio::I_DATA_ADDR.offset((csr::rtio::I_DATA_SIZE - 1 - offset) as isize))
|
csr::rtio::I_DATA_ADDR.offset(OFFSET_MULTIPLE*(csr::rtio::I_DATA_SIZE - 1 - offset) as isize))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
unsafe fn process_exceptional_status(channel: i32, status: u8) {
|
unsafe fn process_exceptional_status(channel: i32, status: u8) {
|
||||||
let timestamp = *(csr::rtio::NOW_HI_ADDR as *const i64);
|
let timestamp = ((csr::rtio::now_hi_read() as i64) << 32) | (csr::rtio::now_lo_read() as i64);
|
||||||
if status & RTIO_O_STATUS_WAIT != 0 {
|
if status & RTIO_O_STATUS_WAIT != 0 {
|
||||||
while csr::rtio::o_status_read() & RTIO_O_STATUS_WAIT != 0 {}
|
while csr::rtio::o_status_read() & RTIO_O_STATUS_WAIT != 0 {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,6 @@
|
||||||
use core::{ptr, mem, fmt};
|
use core::{ptr, mem, fmt};
|
||||||
use core::alloc::{GlobalAlloc, Layout};
|
use core::alloc::{GlobalAlloc, Layout};
|
||||||
|
|
||||||
// The minimum alignment guaranteed by the architecture.
|
|
||||||
const MIN_ALIGN: usize = 4;
|
|
||||||
|
|
||||||
const MAGIC_FREE: usize = 0xDEADDEAD;
|
const MAGIC_FREE: usize = 0xDEADDEAD;
|
||||||
const MAGIC_BUSY: usize = 0xFEEDFEED;
|
const MAGIC_BUSY: usize = 0xFEEDFEED;
|
||||||
|
|
||||||
|
@ -41,10 +38,6 @@ impl ListAlloc {
|
||||||
|
|
||||||
unsafe impl GlobalAlloc for ListAlloc {
|
unsafe impl GlobalAlloc for ListAlloc {
|
||||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||||
if layout.align() > MIN_ALIGN {
|
|
||||||
panic!("cannot allocate with alignment {}", layout.align())
|
|
||||||
}
|
|
||||||
|
|
||||||
let header_size = mem::size_of::<Header>();
|
let header_size = mem::size_of::<Header>();
|
||||||
let size;
|
let size;
|
||||||
if layout.size() % header_size != 0 {
|
if layout.size() % header_size != 0 {
|
||||||
|
@ -52,6 +45,7 @@ unsafe impl GlobalAlloc for ListAlloc {
|
||||||
} else {
|
} else {
|
||||||
size = layout.size()
|
size = layout.size()
|
||||||
}
|
}
|
||||||
|
let align = layout.align();
|
||||||
|
|
||||||
let mut curr = self.root;
|
let mut curr = self.root;
|
||||||
while !curr.is_null() {
|
while !curr.is_null() {
|
||||||
|
@ -67,21 +61,49 @@ unsafe impl GlobalAlloc for ListAlloc {
|
||||||
next = (*curr).next;
|
next = (*curr).next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*curr).size > size + header_size * 2 {
|
unsafe fn split(header: *mut Header, split_size: usize) {
|
||||||
// Split
|
let offset = mem::size_of::<Header>() + split_size;
|
||||||
let offset = header_size + size;
|
let next = (header as *mut u8).offset(offset as isize) as *mut Header;
|
||||||
let next = (curr as *mut u8).offset(offset as isize) as *mut Header;
|
|
||||||
(*next).magic = MAGIC_FREE;
|
(*next).magic = MAGIC_FREE;
|
||||||
(*next).size = (*curr).size - offset;
|
(*next).size = (*header).size - offset;
|
||||||
(*next).next = (*curr).next;
|
(*next).next = (*header).next;
|
||||||
(*curr).next = next;
|
(*header).next = next;
|
||||||
(*curr).size = size;
|
(*header).size = split_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case 1: Memory can be allocated straight from the current chunk
|
||||||
|
if (curr.offset(1) as usize) % align == 0 {
|
||||||
|
// Check available space
|
||||||
|
if (*curr).size > size + header_size * 2 {
|
||||||
|
split(curr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*curr).size >= size {
|
if (*curr).size >= size {
|
||||||
(*curr).magic = MAGIC_BUSY;
|
(*curr).magic = MAGIC_BUSY;
|
||||||
return curr.offset(1) as *mut u8
|
return curr.offset(1) as *mut u8
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case 2: Padding is needed to satisfy the alignment
|
||||||
|
else {
|
||||||
|
let alloc_addr = curr.offset(2) as usize;
|
||||||
|
let padding_size = align - (alloc_addr % align);
|
||||||
|
|
||||||
|
if (*curr).size >= size + padding_size + header_size {
|
||||||
|
// Create a padding region
|
||||||
|
split(curr, padding_size);
|
||||||
|
|
||||||
|
curr = (*curr).next;
|
||||||
|
|
||||||
|
// Check if a padding is needed at the rear
|
||||||
|
if (*curr).size > size + header_size * 2 {
|
||||||
|
split(curr, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
(*curr).magic = MAGIC_BUSY;
|
||||||
|
return curr.offset(1) as *mut u8
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
_ => panic!("heap corruption detected at {:p}", curr)
|
_ => panic!("heap corruption detected at {:p}", curr)
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,12 +137,11 @@ pub fn send(linkno: u8, packet: &Packet) -> Result<(), Error<!>> {
|
||||||
|
|
||||||
packet.write_to(&mut writer)?;
|
packet.write_to(&mut writer)?;
|
||||||
|
|
||||||
let padding = 4 - (writer.position() % 4);
|
// Pad till offset 4, insert checksum there
|
||||||
if padding != 4 {
|
let padding = (12 - (writer.position() % 8)) % 8;
|
||||||
for _ in 0..padding {
|
for _ in 0..padding {
|
||||||
writer.write_u8(0)?;
|
writer.write_u8(0)?;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let checksum = crc::crc32::checksum_ieee(&writer.get_ref()[0..writer.position()]);
|
let checksum = crc::crc32::checksum_ieee(&writer.get_ref()[0..writer.position()]);
|
||||||
writer.write_u32(checksum)?;
|
writer.write_u32(checksum)?;
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
#![feature(asm, lang_items, never_type)]
|
#![feature(lang_items, never_type)]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
extern crate failure;
|
extern crate failure;
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate failure_derive;
|
extern crate failure_derive;
|
||||||
#[macro_use]
|
|
||||||
extern crate bitflags;
|
|
||||||
extern crate byteorder;
|
extern crate byteorder;
|
||||||
extern crate crc;
|
extern crate crc;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
@ -15,8 +13,6 @@ extern crate io;
|
||||||
extern crate board_misoc;
|
extern crate board_misoc;
|
||||||
extern crate proto_artiq;
|
extern crate proto_artiq;
|
||||||
|
|
||||||
pub mod pcr;
|
|
||||||
|
|
||||||
pub mod spi;
|
pub mod spi;
|
||||||
|
|
||||||
#[cfg(has_kernel_cpu)]
|
#[cfg(has_kernel_cpu)]
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
use board_misoc::spr::*;
|
|
||||||
|
|
||||||
bitflags! {
|
|
||||||
pub struct Counters: u32 {
|
|
||||||
const LA = SPR_PCMR_LA;
|
|
||||||
const SA = SPR_PCMR_SA;
|
|
||||||
const IF = SPR_PCMR_IF;
|
|
||||||
const DCM = SPR_PCMR_DCM;
|
|
||||||
const ICM = SPR_PCMR_ICM;
|
|
||||||
const IFS = SPR_PCMR_IFS;
|
|
||||||
const LSUS = SPR_PCMR_LSUS;
|
|
||||||
const BS = SPR_PCMR_BS;
|
|
||||||
const DTLBM = SPR_PCMR_DTLBM;
|
|
||||||
const ITLBM = SPR_PCMR_ITLBM;
|
|
||||||
const DDS = SPR_PCMR_DDS;
|
|
||||||
|
|
||||||
const INSTRN = Self::IF.bits;
|
|
||||||
const MEMORY = Self::LA.bits | Self::SA.bits;
|
|
||||||
const STALL = Self::DCM.bits | Self::ICM.bits | Self::IFS.bits |
|
|
||||||
Self::LSUS.bits | Self::BS.bits | Self::DDS.bits ;
|
|
||||||
const MISS = Self::DTLBM.bits | Self::ITLBM.bits ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_valid(index: u32) -> bool {
|
|
||||||
index < 8 && unsafe { mfspr(SPR_PCMR0 + index) } & SPR_PCMR_CP != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn setup(index: u32, counters: Counters) {
|
|
||||||
debug_assert!(is_valid(index));
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
mtspr(SPR_PCMR0 + index, SPR_PCMR_CISM | SPR_PCMR_CIUM | counters.bits);
|
|
||||||
mtspr(SPR_PCCR0 + index, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn read(index: u32) -> u32 {
|
|
||||||
unsafe {
|
|
||||||
mfspr(SPR_PCCR0 + index)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +1,9 @@
|
||||||
use core::ptr::{read_volatile, write_volatile};
|
use core::ptr::{read_volatile, write_volatile};
|
||||||
use core::slice;
|
use core::slice;
|
||||||
use board_misoc::{mem, cache};
|
use board_misoc::{mem, cache, csr::CONFIG_DATA_WIDTH_BYTES};
|
||||||
|
|
||||||
const SEND_MAILBOX: *mut usize = (mem::MAILBOX_BASE + 4) as *mut usize;
|
const SEND_MAILBOX: *mut usize = (mem::MAILBOX_BASE + CONFIG_DATA_WIDTH_BYTES as usize) as *mut usize;
|
||||||
const RECV_MAILBOX: *mut usize = (mem::MAILBOX_BASE + 8) as *mut usize;
|
const RECV_MAILBOX: *mut usize = (mem::MAILBOX_BASE + (CONFIG_DATA_WIDTH_BYTES * 2) as usize) as *mut usize;
|
||||||
|
|
||||||
const QUEUE_BEGIN: usize = 0x44000000;
|
const QUEUE_BEGIN: usize = 0x44000000;
|
||||||
const QUEUE_END: usize = 0x44ffff80;
|
const QUEUE_END: usize = 0x44ffff80;
|
||||||
|
|
|
@ -16,6 +16,7 @@ build_misoc = { path = "../libbuild_misoc" }
|
||||||
byteorder = { version = "1.0", default-features = false }
|
byteorder = { version = "1.0", default-features = false }
|
||||||
log = { version = "0.4", default-features = false, optional = true }
|
log = { version = "0.4", default-features = false, optional = true }
|
||||||
smoltcp = { version = "0.6.0", default-features = false, optional = true }
|
smoltcp = { version = "0.6.0", default-features = false, optional = true }
|
||||||
|
riscv = { version = "0.6.0", features = ["inline-asm"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
uart_console = []
|
uart_console = []
|
||||||
|
|
|
@ -1,18 +1,16 @@
|
||||||
extern crate build_misoc;
|
extern crate build_misoc;
|
||||||
extern crate cc;
|
extern crate cc;
|
||||||
|
|
||||||
use std::env;
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
build_misoc::cfg();
|
build_misoc::cfg();
|
||||||
|
|
||||||
let triple = env::var("TARGET").unwrap();
|
let vectors_path = "riscv32/vectors.S";
|
||||||
let arch = triple.split("-").next().unwrap();
|
|
||||||
let vectors_path = Path::new(arch).join("vectors.S");
|
|
||||||
|
|
||||||
println!("cargo:rerun-if-changed={}", vectors_path.to_str().unwrap());
|
println!("cargo:rerun-if-changed={}", vectors_path);
|
||||||
cc::Build::new()
|
cc::Build::new()
|
||||||
.file(vectors_path)
|
.flag("--target=riscv32-unknown-elf")
|
||||||
|
.file(Path::new(vectors_path))
|
||||||
.compile("vectors");
|
.compile("vectors");
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,10 +77,10 @@ mod imp {
|
||||||
|
|
||||||
mod lock {
|
mod lock {
|
||||||
use core::slice;
|
use core::slice;
|
||||||
use core::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
|
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||||
use super::Error;
|
use super::Error;
|
||||||
|
|
||||||
static LOCKED: AtomicUsize = ATOMIC_USIZE_INIT;
|
static LOCKED: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
|
||||||
pub struct Lock;
|
pub struct Lock;
|
||||||
|
|
||||||
|
@ -216,7 +216,7 @@ mod imp {
|
||||||
let mut offset = 0;
|
let mut offset = 0;
|
||||||
let mut iter = Iter::new(old_data);
|
let mut iter = Iter::new(old_data);
|
||||||
'iter: while let Some(result) = iter.next() {
|
'iter: while let Some(result) = iter.next() {
|
||||||
let (key, mut value) = result?;
|
let (key, value) = result?;
|
||||||
if value.is_empty() {
|
if value.is_empty() {
|
||||||
// This is a removed entry, ignore it.
|
// This is a removed entry, ignore it.
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![feature(asm, try_from)]
|
#![feature(llvm_asm)]
|
||||||
|
|
||||||
extern crate byteorder;
|
extern crate byteorder;
|
||||||
#[cfg(feature = "log")]
|
#[cfg(feature = "log")]
|
||||||
|
@ -7,10 +7,13 @@ extern crate log;
|
||||||
#[cfg(feature = "smoltcp")]
|
#[cfg(feature = "smoltcp")]
|
||||||
extern crate smoltcp;
|
extern crate smoltcp;
|
||||||
|
|
||||||
#[cfg(target_arch = "or1k")]
|
#[cfg(target_arch = "riscv32")]
|
||||||
#[path = "or1k/mod.rs"]
|
#[path = "riscv32/mod.rs"]
|
||||||
mod arch;
|
mod arch;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "riscv32")]
|
||||||
|
extern crate riscv;
|
||||||
|
|
||||||
pub use arch::*;
|
pub use arch::*;
|
||||||
|
|
||||||
include!(concat!(env!("BUILDINC_DIRECTORY"), "/generated/mem.rs"));
|
include!(concat!(env!("BUILDINC_DIRECTORY"), "/generated/mem.rs"));
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
use super::{irq, cache};
|
|
||||||
|
|
||||||
pub unsafe fn reset() -> ! {
|
|
||||||
irq::set_ie(false);
|
|
||||||
asm!(r#"
|
|
||||||
l.j _reset_handler
|
|
||||||
l.nop
|
|
||||||
"# : : : : "volatile");
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe fn jump(addr: usize) -> ! {
|
|
||||||
irq::set_ie(false);
|
|
||||||
cache::flush_cpu_icache();
|
|
||||||
asm!(r#"
|
|
||||||
l.jr $0
|
|
||||||
l.nop
|
|
||||||
"# : : "r"(addr) : : "volatile");
|
|
||||||
loop {}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe fn hotswap(firmware: &[u8]) -> ! {
|
|
||||||
irq::set_ie(false);
|
|
||||||
asm!(r#"
|
|
||||||
# This loop overwrites itself, but it's structured in such a way
|
|
||||||
# that before that happens, it loads itself into I$$ fully.
|
|
||||||
l.movhi r4, hi(_reset_handler)
|
|
||||||
l.ori r4, r4, lo(_reset_handler)
|
|
||||||
l.or r7, r4, r0
|
|
||||||
0: l.sfnei r5, 0
|
|
||||||
l.bf 1f
|
|
||||||
l.nop
|
|
||||||
l.jr r7
|
|
||||||
l.nop
|
|
||||||
1: l.lwz r6, 0(r3)
|
|
||||||
l.sw 0(r4), r6
|
|
||||||
l.addi r3, r3, 4
|
|
||||||
l.addi r4, r4, 4
|
|
||||||
l.addi r5, r5, -4
|
|
||||||
l.bf 0b
|
|
||||||
l.nop
|
|
||||||
"#
|
|
||||||
:
|
|
||||||
: "{r3}"(firmware.as_ptr() as usize),
|
|
||||||
"{r5}"(firmware.len())
|
|
||||||
:
|
|
||||||
: "volatile");
|
|
||||||
loop {}
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
#[cfg(has_ddrphy)]
|
|
||||||
use core::ptr;
|
|
||||||
use super::spr::*;
|
|
||||||
#[cfg(has_ddrphy)]
|
|
||||||
use csr;
|
|
||||||
#[cfg(has_ddrphy)]
|
|
||||||
use mem;
|
|
||||||
|
|
||||||
pub fn flush_cpu_icache() {
|
|
||||||
unsafe {
|
|
||||||
let iccfgr = mfspr(SPR_ICCFGR);
|
|
||||||
let ways = 1 << (iccfgr & SPR_ICCFGR_NCW);
|
|
||||||
let set_size = 1 << ((iccfgr & SPR_ICCFGR_NCS) >> 3);
|
|
||||||
let block_size = if iccfgr & SPR_ICCFGR_CBS != 0 { 32 } else { 16 };
|
|
||||||
let size = set_size * ways * block_size;
|
|
||||||
|
|
||||||
let mut i = 0;
|
|
||||||
while i < size {
|
|
||||||
mtspr(SPR_ICBIR, i);
|
|
||||||
i += block_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn flush_cpu_dcache() {
|
|
||||||
unsafe {
|
|
||||||
let dccfgr = mfspr(SPR_DCCFGR);
|
|
||||||
let ways = 1 << (dccfgr & SPR_ICCFGR_NCW);
|
|
||||||
let set_size = 1 << ((dccfgr & SPR_DCCFGR_NCS) >> 3);
|
|
||||||
let block_size = if dccfgr & SPR_DCCFGR_CBS != 0 { 32 } else { 16 };
|
|
||||||
let size = set_size * ways * block_size;
|
|
||||||
|
|
||||||
let mut i = 0;
|
|
||||||
while i < size {
|
|
||||||
mtspr(SPR_DCBIR, i);
|
|
||||||
i += block_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(has_ddrphy)]
|
|
||||||
pub fn flush_l2_cache() {
|
|
||||||
unsafe {
|
|
||||||
for i in 0..2 * (csr::CONFIG_L2_SIZE as usize) / 4 {
|
|
||||||
let addr = mem::MAIN_RAM_BASE + i * 4;
|
|
||||||
ptr::read_volatile(addr as *const usize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,107 +0,0 @@
|
||||||
use core::{fmt, convert};
|
|
||||||
|
|
||||||
use super::spr::*;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
|
||||||
pub enum Exception {
|
|
||||||
Reset = 0x1,
|
|
||||||
BusError = 0x2,
|
|
||||||
DataPageFault = 0x3,
|
|
||||||
InsnPageFault = 0x4,
|
|
||||||
Tick = 0x5,
|
|
||||||
Alignment = 0x6,
|
|
||||||
IllegalInsn = 0x7,
|
|
||||||
Interrupt = 0x8,
|
|
||||||
DtlbMiss = 0x9,
|
|
||||||
ItlbMiss = 0xa,
|
|
||||||
Range = 0xb,
|
|
||||||
Syscall = 0xc,
|
|
||||||
FloatingPoint = 0xd,
|
|
||||||
Trap = 0xe,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Exception {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match *self {
|
|
||||||
Exception::Reset => write!(f, "reset"),
|
|
||||||
Exception::BusError => write!(f, "bus error"),
|
|
||||||
Exception::DataPageFault => write!(f, "data page fault"),
|
|
||||||
Exception::InsnPageFault => write!(f, "instruction page fault"),
|
|
||||||
Exception::Tick => write!(f, "tick"),
|
|
||||||
Exception::Alignment => write!(f, "alignment"),
|
|
||||||
Exception::IllegalInsn => write!(f, "illegal instruction"),
|
|
||||||
Exception::Interrupt => write!(f, "interrupt"),
|
|
||||||
Exception::DtlbMiss => write!(f, "D-TLB miss"),
|
|
||||||
Exception::ItlbMiss => write!(f, "I-TLB miss"),
|
|
||||||
Exception::Range => write!(f, "range"),
|
|
||||||
Exception::Syscall => write!(f, "system call"),
|
|
||||||
Exception::FloatingPoint => write!(f, "floating point"),
|
|
||||||
Exception::Trap => write!(f, "trap"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl convert::TryFrom<u32> for Exception {
|
|
||||||
type Error = ();
|
|
||||||
|
|
||||||
fn try_from(num: u32) -> Result<Self, Self::Error> {
|
|
||||||
match num {
|
|
||||||
0x1 => Ok(Exception::Reset),
|
|
||||||
0x2 => Ok(Exception::BusError),
|
|
||||||
0x3 => Ok(Exception::DataPageFault),
|
|
||||||
0x4 => Ok(Exception::InsnPageFault),
|
|
||||||
0x5 => Ok(Exception::Tick),
|
|
||||||
0x6 => Ok(Exception::Alignment),
|
|
||||||
0x7 => Ok(Exception::IllegalInsn),
|
|
||||||
0x8 => Ok(Exception::Interrupt),
|
|
||||||
0x9 => Ok(Exception::DtlbMiss),
|
|
||||||
0xa => Ok(Exception::ItlbMiss),
|
|
||||||
0xb => Ok(Exception::Range),
|
|
||||||
0xc => Ok(Exception::Syscall),
|
|
||||||
0xd => Ok(Exception::FloatingPoint),
|
|
||||||
0xe => Ok(Exception::Trap),
|
|
||||||
_ => Err(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn get_ie() -> bool {
|
|
||||||
unsafe { mfspr(SPR_SR) & SPR_SR_IEE != 0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn set_ie(ie: bool) {
|
|
||||||
if ie {
|
|
||||||
unsafe { mtspr(SPR_SR, mfspr(SPR_SR) | SPR_SR_IEE) }
|
|
||||||
} else {
|
|
||||||
unsafe { mtspr(SPR_SR, mfspr(SPR_SR) & !SPR_SR_IEE) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn get_mask() -> u32 {
|
|
||||||
unsafe { mfspr(SPR_PICMR) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn set_mask(mask: u32) {
|
|
||||||
unsafe { mtspr(SPR_PICMR, mask) }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn pending_mask() -> u32 {
|
|
||||||
unsafe { mfspr(SPR_PICSR) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn enable(irq: u32) {
|
|
||||||
set_mask(get_mask() | (1 << irq))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn disable(irq: u32) {
|
|
||||||
set_mask(get_mask() & !(1 << irq))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_pending(irq: u32) -> bool {
|
|
||||||
get_mask() & (1 << irq) != 0
|
|
||||||
}
|
|
|
@ -1,231 +0,0 @@
|
||||||
#[inline(always)]
|
|
||||||
pub unsafe fn mfspr(reg: u32) -> u32 {
|
|
||||||
let value: u32;
|
|
||||||
asm!("l.mfspr $0, $1, 0" : "=r"(value) : "r"(reg) : : "volatile");
|
|
||||||
value
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub unsafe fn mtspr(reg: u32, value: u32) {
|
|
||||||
asm!("l.mtspr $0, $1, 0" : : "r"(reg), "r"(value) : : "volatile")
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Definition of special-purpose registers (SPRs). */
|
|
||||||
|
|
||||||
pub const MAX_GRPS: u32 = 32;
|
|
||||||
pub const MAX_SPRS_PER_GRP_BITS: u32 = 11;
|
|
||||||
pub const MAX_SPRS_PER_GRP: u32 = 1 << MAX_SPRS_PER_GRP_BITS;
|
|
||||||
pub const MAX_SPRS: u32 = 0x10000;
|
|
||||||
|
|
||||||
/* Base addresses for the groups */
|
|
||||||
pub const SPRGROUP_SYS: u32 = 0 << MAX_SPRS_PER_GRP_BITS;
|
|
||||||
pub const SPRGROUP_DMMU: u32 = 1 << MAX_SPRS_PER_GRP_BITS;
|
|
||||||
pub const SPRGROUP_IMMU: u32 = 2 << MAX_SPRS_PER_GRP_BITS;
|
|
||||||
pub const SPRGROUP_DC: u32 = 3 << MAX_SPRS_PER_GRP_BITS;
|
|
||||||
pub const SPRGROUP_IC: u32 = 4 << MAX_SPRS_PER_GRP_BITS;
|
|
||||||
pub const SPRGROUP_MAC: u32 = 5 << MAX_SPRS_PER_GRP_BITS;
|
|
||||||
pub const SPRGROUP_D: u32 = 6 << MAX_SPRS_PER_GRP_BITS;
|
|
||||||
pub const SPRGROUP_PC: u32 = 7 << MAX_SPRS_PER_GRP_BITS;
|
|
||||||
pub const SPRGROUP_PM: u32 = 8 << MAX_SPRS_PER_GRP_BITS;
|
|
||||||
pub const SPRGROUP_PIC: u32 = 9 << MAX_SPRS_PER_GRP_BITS;
|
|
||||||
pub const SPRGROUP_TT: u32 = 10 << MAX_SPRS_PER_GRP_BITS;
|
|
||||||
pub const SPRGROUP_FP: u32 = 11 << MAX_SPRS_PER_GRP_BITS;
|
|
||||||
|
|
||||||
/* System control and status group */
|
|
||||||
pub const SPR_VR: u32 = SPRGROUP_SYS + 0;
|
|
||||||
pub const SPR_UPR: u32 = SPRGROUP_SYS + 1;
|
|
||||||
pub const SPR_CPUCFGR: u32 = SPRGROUP_SYS + 2;
|
|
||||||
pub const SPR_DMMUCFGR: u32 = SPRGROUP_SYS + 3;
|
|
||||||
pub const SPR_IMMUCFGR: u32 = SPRGROUP_SYS + 4;
|
|
||||||
pub const SPR_DCCFGR: u32 = SPRGROUP_SYS + 5;
|
|
||||||
pub const SPR_ICCFGR: u32 = SPRGROUP_SYS + 6;
|
|
||||||
pub const SPR_DCFGR: u32 = SPRGROUP_SYS + 7;
|
|
||||||
pub const SPR_PCCFGR: u32 = SPRGROUP_SYS + 8;
|
|
||||||
pub const SPR_VR2: u32 = SPRGROUP_SYS + 9;
|
|
||||||
pub const SPR_AVR: u32 = SPRGROUP_SYS + 10;
|
|
||||||
pub const SPR_EVBAR: u32 = SPRGROUP_SYS + 11;
|
|
||||||
pub const SPR_AECR: u32 = SPRGROUP_SYS + 12;
|
|
||||||
pub const SPR_AESR: u32 = SPRGROUP_SYS + 13;
|
|
||||||
pub const SPR_NPC: u32 = SPRGROUP_SYS + 16; /* CZ 21/06/01 */
|
|
||||||
pub const SPR_SR: u32 = SPRGROUP_SYS + 17; /* CZ 21/06/01 */
|
|
||||||
pub const SPR_PPC: u32 = SPRGROUP_SYS + 18; /* CZ 21/06/01 */
|
|
||||||
pub const SPR_FPCSR: u32 = SPRGROUP_SYS + 20; /* CZ 21/06/01 */
|
|
||||||
pub const SPR_ISR_BASE: u32 = SPRGROUP_SYS + 21;
|
|
||||||
pub const SPR_EPCR_BASE: u32 = SPRGROUP_SYS + 32; /* CZ 21/06/01 */
|
|
||||||
pub const SPR_EPCR_LAST: u32 = SPRGROUP_SYS + 47; /* CZ 21/06/01 */
|
|
||||||
pub const SPR_EEAR_BASE: u32 = SPRGROUP_SYS + 48;
|
|
||||||
pub const SPR_EEAR_LAST: u32 = SPRGROUP_SYS + 63;
|
|
||||||
pub const SPR_ESR_BASE: u32 = SPRGROUP_SYS + 64;
|
|
||||||
pub const SPR_ESR_LAST: u32 = SPRGROUP_SYS + 79;
|
|
||||||
pub const SPR_GPR_BASE: u32 = SPRGROUP_SYS + 1024;
|
|
||||||
|
|
||||||
/* Data MMU group */
|
|
||||||
pub const SPR_DMMUCR: u32 = SPRGROUP_DMMU + 0;
|
|
||||||
pub const SPR_DTLBEIR: u32 = SPRGROUP_DMMU + 2;
|
|
||||||
|
|
||||||
/* Instruction MMU group */
|
|
||||||
pub const SPR_IMMUCR: u32 = SPRGROUP_IMMU + 0;
|
|
||||||
pub const SPR_ITLBEIR: u32 = SPRGROUP_IMMU + 2;
|
|
||||||
|
|
||||||
/* Data cache group */
|
|
||||||
pub const SPR_DCCR: u32 = SPRGROUP_DC + 0;
|
|
||||||
pub const SPR_DCBPR: u32 = SPRGROUP_DC + 1;
|
|
||||||
pub const SPR_DCBFR: u32 = SPRGROUP_DC + 2;
|
|
||||||
pub const SPR_DCBIR: u32 = SPRGROUP_DC + 3;
|
|
||||||
pub const SPR_DCBWR: u32 = SPRGROUP_DC + 4;
|
|
||||||
pub const SPR_DCBLR: u32 = SPRGROUP_DC + 5;
|
|
||||||
|
|
||||||
/* Instruction cache group */
|
|
||||||
pub const SPR_ICCR: u32 = SPRGROUP_IC + 0;
|
|
||||||
pub const SPR_ICBPR: u32 = SPRGROUP_IC + 1;
|
|
||||||
pub const SPR_ICBIR: u32 = SPRGROUP_IC + 2;
|
|
||||||
pub const SPR_ICBLR: u32 = SPRGROUP_IC + 3;
|
|
||||||
|
|
||||||
// [snip]
|
|
||||||
|
|
||||||
/* Performance counters group */
|
|
||||||
pub const SPR_PCCR0: u32 = SPRGROUP_PC + 0;
|
|
||||||
pub const SPR_PCCR1: u32 = SPRGROUP_PC + 1;
|
|
||||||
pub const SPR_PCCR2: u32 = SPRGROUP_PC + 2;
|
|
||||||
pub const SPR_PCCR3: u32 = SPRGROUP_PC + 3;
|
|
||||||
pub const SPR_PCCR4: u32 = SPRGROUP_PC + 4;
|
|
||||||
pub const SPR_PCCR5: u32 = SPRGROUP_PC + 5;
|
|
||||||
pub const SPR_PCCR6: u32 = SPRGROUP_PC + 6;
|
|
||||||
pub const SPR_PCCR7: u32 = SPRGROUP_PC + 7;
|
|
||||||
pub const SPR_PCMR0: u32 = SPRGROUP_PC + 8;
|
|
||||||
pub const SPR_PCMR1: u32 = SPRGROUP_PC + 9;
|
|
||||||
pub const SPR_PCMR2: u32 = SPRGROUP_PC + 10;
|
|
||||||
pub const SPR_PCMR3: u32 = SPRGROUP_PC + 11;
|
|
||||||
pub const SPR_PCMR4: u32 = SPRGROUP_PC + 12;
|
|
||||||
pub const SPR_PCMR5: u32 = SPRGROUP_PC + 13;
|
|
||||||
pub const SPR_PCMR6: u32 = SPRGROUP_PC + 14;
|
|
||||||
pub const SPR_PCMR7: u32 = SPRGROUP_PC + 15;
|
|
||||||
|
|
||||||
/* PIC group */
|
|
||||||
pub const SPR_PICMR: u32 = SPRGROUP_PIC + 0;
|
|
||||||
pub const SPR_PICPR: u32 = SPRGROUP_PIC + 1;
|
|
||||||
pub const SPR_PICSR: u32 = SPRGROUP_PIC + 2;
|
|
||||||
|
|
||||||
// [snip]
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Bit definitions for the Supervision Register
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
pub const SPR_SR_SM: u32 = 0x00000001; /* Supervisor Mode */
|
|
||||||
pub const SPR_SR_TEE: u32 = 0x00000002; /* Tick timer Exception Enable */
|
|
||||||
pub const SPR_SR_IEE: u32 = 0x00000004; /* Interrupt Exception Enable */
|
|
||||||
pub const SPR_SR_DCE: u32 = 0x00000008; /* Data Cache Enable */
|
|
||||||
pub const SPR_SR_ICE: u32 = 0x00000010; /* Instruction Cache Enable */
|
|
||||||
pub const SPR_SR_DME: u32 = 0x00000020; /* Data MMU Enable */
|
|
||||||
pub const SPR_SR_IME: u32 = 0x00000040; /* Instruction MMU Enable */
|
|
||||||
pub const SPR_SR_LEE: u32 = 0x00000080; /* Little Endian Enable */
|
|
||||||
pub const SPR_SR_CE: u32 = 0x00000100; /* CID Enable */
|
|
||||||
pub const SPR_SR_F: u32 = 0x00000200; /* Condition Flag */
|
|
||||||
pub const SPR_SR_CY: u32 = 0x00000400; /* Carry flag */
|
|
||||||
pub const SPR_SR_OV: u32 = 0x00000800; /* Overflow flag */
|
|
||||||
pub const SPR_SR_OVE: u32 = 0x00001000; /* Overflow flag Exception */
|
|
||||||
pub const SPR_SR_DSX: u32 = 0x00002000; /* Delay Slot Exception */
|
|
||||||
pub const SPR_SR_EPH: u32 = 0x00004000; /* Exception Prefix High */
|
|
||||||
pub const SPR_SR_FO: u32 = 0x00008000; /* Fixed one */
|
|
||||||
pub const SPR_SR_SUMRA: u32 = 0x00010000; /* Supervisor SPR read access */
|
|
||||||
pub const SPR_SR_RES: u32 = 0x0ffe0000; /* Reserved */
|
|
||||||
pub const SPR_SR_CID: u32 = 0xf0000000; /* Context ID */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Bit definitions for Data Cache Control register
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
pub const SPR_DCCR_EW: u32 = 0x000000ff; /* Enable ways */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Bit definitions for Insn Cache Control register
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
pub const SPR_ICCR_EW: u32 = 0x000000ff; /* Enable ways */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Bit definitions for Data Cache Configuration Register
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
pub const SPR_DCCFGR_NCW: u32 = 0x00000007;
|
|
||||||
pub const SPR_DCCFGR_NCS: u32 = 0x00000078;
|
|
||||||
pub const SPR_DCCFGR_CBS: u32 = 0x00000080;
|
|
||||||
pub const SPR_DCCFGR_CWS: u32 = 0x00000100;
|
|
||||||
pub const SPR_DCCFGR_CCRI: u32 = 0x00000200;
|
|
||||||
pub const SPR_DCCFGR_CBIRI: u32 = 0x00000400;
|
|
||||||
pub const SPR_DCCFGR_CBPRI: u32 = 0x00000800;
|
|
||||||
pub const SPR_DCCFGR_CBLRI: u32 = 0x00001000;
|
|
||||||
pub const SPR_DCCFGR_CBFRI: u32 = 0x00002000;
|
|
||||||
pub const SPR_DCCFGR_CBWBRI: u32 = 0x00004000;
|
|
||||||
|
|
||||||
pub const SPR_DCCFGR_NCW_OFF: u32 = 0;
|
|
||||||
pub const SPR_DCCFGR_NCS_OFF: u32 = 3;
|
|
||||||
pub const SPR_DCCFGR_CBS_OFF: u32 = 7;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Bit definitions for Instruction Cache Configuration Register
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
pub const SPR_ICCFGR_NCW: u32 = 0x00000007;
|
|
||||||
pub const SPR_ICCFGR_NCS: u32 = 0x00000078;
|
|
||||||
pub const SPR_ICCFGR_CBS: u32 = 0x00000080;
|
|
||||||
pub const SPR_ICCFGR_CCRI: u32 = 0x00000200;
|
|
||||||
pub const SPR_ICCFGR_CBIRI: u32 = 0x00000400;
|
|
||||||
pub const SPR_ICCFGR_CBPRI: u32 = 0x00000800;
|
|
||||||
pub const SPR_ICCFGR_CBLRI: u32 = 0x00001000;
|
|
||||||
|
|
||||||
pub const SPR_ICCFGR_NCW_OFF: u32 = 0;
|
|
||||||
pub const SPR_ICCFGR_NCS_OFF: u32 = 3;
|
|
||||||
pub const SPR_ICCFGR_CBS_OFF: u32 = 7;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Bit definitions for Data MMU Configuration Register
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
pub const SPR_DMMUCFGR_NTW: u32 = 0x00000003;
|
|
||||||
pub const SPR_DMMUCFGR_NTS: u32 = 0x0000001C;
|
|
||||||
pub const SPR_DMMUCFGR_NAE: u32 = 0x000000E0;
|
|
||||||
pub const SPR_DMMUCFGR_CRI: u32 = 0x00000100;
|
|
||||||
pub const SPR_DMMUCFGR_PRI: u32 = 0x00000200;
|
|
||||||
pub const SPR_DMMUCFGR_TEIRI: u32 = 0x00000400;
|
|
||||||
pub const SPR_DMMUCFGR_HTR: u32 = 0x00000800;
|
|
||||||
|
|
||||||
pub const SPR_DMMUCFGR_NTW_OFF: u32 = 0;
|
|
||||||
pub const SPR_DMMUCFGR_NTS_OFF: u32 = 2;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Bit definitions for Instruction MMU Configuration Register
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
pub const SPR_IMMUCFGR_NTW: u32 = 0x00000003;
|
|
||||||
pub const SPR_IMMUCFGR_NTS: u32 = 0x0000001C;
|
|
||||||
pub const SPR_IMMUCFGR_NAE: u32 = 0x000000E0;
|
|
||||||
pub const SPR_IMMUCFGR_CRI: u32 = 0x00000100;
|
|
||||||
pub const SPR_IMMUCFGR_PRI: u32 = 0x00000200;
|
|
||||||
pub const SPR_IMMUCFGR_TEIRI: u32 = 0x00000400;
|
|
||||||
pub const SPR_IMMUCFGR_HTR: u32 = 0x00000800;
|
|
||||||
|
|
||||||
pub const SPR_IMMUCFGR_NTW_OFF: u32 = 0;
|
|
||||||
pub const SPR_IMMUCFGR_NTS_OFF: u32 = 2;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Bit definitions for Performance counters mode registers
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
pub const SPR_PCMR_CP: u32 = 0x00000001; /* Counter present */
|
|
||||||
pub const SPR_PCMR_UMRA: u32 = 0x00000002; /* User mode read access */
|
|
||||||
pub const SPR_PCMR_CISM: u32 = 0x00000004; /* Count in supervisor mode */
|
|
||||||
pub const SPR_PCMR_CIUM: u32 = 0x00000008; /* Count in user mode */
|
|
||||||
pub const SPR_PCMR_LA: u32 = 0x00000010; /* Load access event */
|
|
||||||
pub const SPR_PCMR_SA: u32 = 0x00000020; /* Store access event */
|
|
||||||
pub const SPR_PCMR_IF: u32 = 0x00000040; /* Instruction fetch event*/
|
|
||||||
pub const SPR_PCMR_DCM: u32 = 0x00000080; /* Data cache miss event */
|
|
||||||
pub const SPR_PCMR_ICM: u32 = 0x00000100; /* Insn cache miss event */
|
|
||||||
pub const SPR_PCMR_IFS: u32 = 0x00000200; /* Insn fetch stall event */
|
|
||||||
pub const SPR_PCMR_LSUS: u32 = 0x00000400; /* LSU stall event */
|
|
||||||
pub const SPR_PCMR_BS: u32 = 0x00000800; /* Branch stall event */
|
|
||||||
pub const SPR_PCMR_DTLBM: u32 = 0x00001000; /* DTLB miss event */
|
|
||||||
pub const SPR_PCMR_ITLBM: u32 = 0x00002000; /* ITLB miss event */
|
|
||||||
pub const SPR_PCMR_DDS: u32 = 0x00004000; /* Data dependency stall event */
|
|
||||||
pub const SPR_PCMR_WPE: u32 = 0x03ff8000; /* Watchpoint events */
|
|
|
@ -1,413 +0,0 @@
|
||||||
/*
|
|
||||||
* (C) Copyright 2012, Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU General Public License as
|
|
||||||
* published by the Free Software Foundation; either version 2 of
|
|
||||||
* the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
||||||
* MA 02111-1307 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <spr-defs.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* OR1K Architecture has a 128 byte "red zone" after the stack that can not be
|
|
||||||
* touched by exception handlers. GCC uses this red zone for locals and
|
|
||||||
* temps without needing to change the stack pointer.
|
|
||||||
*/
|
|
||||||
#define OR1K_RED_ZONE_SIZE 128
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We need 4 bytes (32 bits) * 32 registers space on the stack to save all the
|
|
||||||
* registers.
|
|
||||||
*/
|
|
||||||
#define EXCEPTION_STACK_SIZE ((4*32) + OR1K_RED_ZONE_SIZE)
|
|
||||||
|
|
||||||
#define HANDLE_EXCEPTION ; \
|
|
||||||
l.addi r1, r1, -EXCEPTION_STACK_SIZE ; \
|
|
||||||
l.sw 0x1c(r1), r9 ; \
|
|
||||||
l.jal _exception_handler ; \
|
|
||||||
l.nop ; \
|
|
||||||
l.lwz r9, 0x1c(r1) ; \
|
|
||||||
l.addi r1, r1, EXCEPTION_STACK_SIZE ; \
|
|
||||||
l.rfe ; \
|
|
||||||
l.nop
|
|
||||||
|
|
||||||
|
|
||||||
.section .vectors, "ax", @progbits
|
|
||||||
.global _reset_handler
|
|
||||||
_reset_handler:
|
|
||||||
l.movhi r0, 0
|
|
||||||
l.movhi r1, 0
|
|
||||||
l.movhi r2, 0
|
|
||||||
l.movhi r3, 0
|
|
||||||
l.movhi r4, 0
|
|
||||||
l.movhi r5, 0
|
|
||||||
l.movhi r6, 0
|
|
||||||
l.movhi r7, 0
|
|
||||||
l.movhi r8, 0
|
|
||||||
l.movhi r9, 0
|
|
||||||
l.movhi r10, 0
|
|
||||||
l.movhi r11, 0
|
|
||||||
l.movhi r12, 0
|
|
||||||
l.movhi r13, 0
|
|
||||||
l.movhi r14, 0
|
|
||||||
l.movhi r15, 0
|
|
||||||
l.movhi r16, 0
|
|
||||||
l.movhi r17, 0
|
|
||||||
l.movhi r18, 0
|
|
||||||
l.movhi r19, 0
|
|
||||||
l.movhi r20, 0
|
|
||||||
l.movhi r21, 0
|
|
||||||
l.movhi r22, 0
|
|
||||||
l.movhi r23, 0
|
|
||||||
l.movhi r24, 0
|
|
||||||
l.movhi r25, 0
|
|
||||||
l.movhi r26, 0
|
|
||||||
l.movhi r27, 0
|
|
||||||
l.movhi r28, 0
|
|
||||||
l.movhi r29, 0
|
|
||||||
l.movhi r30, 0
|
|
||||||
l.movhi r31, 0
|
|
||||||
|
|
||||||
l.ori r21, r0, SPR_SR_SM
|
|
||||||
l.mtspr r0, r21, SPR_SR
|
|
||||||
l.movhi r21, hi(_reset_handler)
|
|
||||||
l.ori r21, r21, lo(_reset_handler)
|
|
||||||
l.mtspr r0, r21, SPR_EVBAR
|
|
||||||
/* enable caches */
|
|
||||||
l.jal _cache_init
|
|
||||||
l.nop
|
|
||||||
l.j _crt0
|
|
||||||
l.nop
|
|
||||||
|
|
||||||
/* bus error */
|
|
||||||
.org 0x200
|
|
||||||
HANDLE_EXCEPTION
|
|
||||||
|
|
||||||
/* data page fault */
|
|
||||||
.org 0x300
|
|
||||||
HANDLE_EXCEPTION
|
|
||||||
|
|
||||||
/* instruction page fault */
|
|
||||||
.org 0x400
|
|
||||||
HANDLE_EXCEPTION
|
|
||||||
|
|
||||||
/* tick timer */
|
|
||||||
.org 0x500
|
|
||||||
HANDLE_EXCEPTION
|
|
||||||
|
|
||||||
/* alignment */
|
|
||||||
.org 0x600
|
|
||||||
HANDLE_EXCEPTION
|
|
||||||
|
|
||||||
/* illegal instruction */
|
|
||||||
.org 0x700
|
|
||||||
HANDLE_EXCEPTION
|
|
||||||
|
|
||||||
/* external interrupt */
|
|
||||||
.org 0x800
|
|
||||||
HANDLE_EXCEPTION
|
|
||||||
|
|
||||||
/* D-TLB miss */
|
|
||||||
.org 0x900
|
|
||||||
HANDLE_EXCEPTION
|
|
||||||
|
|
||||||
/* I-TLB miss */
|
|
||||||
.org 0xa00
|
|
||||||
HANDLE_EXCEPTION
|
|
||||||
|
|
||||||
/* range */
|
|
||||||
.org 0xb00
|
|
||||||
HANDLE_EXCEPTION
|
|
||||||
|
|
||||||
/* system call */
|
|
||||||
.org 0xc00
|
|
||||||
HANDLE_EXCEPTION
|
|
||||||
|
|
||||||
/* floating point */
|
|
||||||
.org 0xd00
|
|
||||||
HANDLE_EXCEPTION
|
|
||||||
|
|
||||||
/* trap */
|
|
||||||
.org 0xe00
|
|
||||||
HANDLE_EXCEPTION
|
|
||||||
|
|
||||||
/* reserved */
|
|
||||||
.org 0xf00
|
|
||||||
HANDLE_EXCEPTION
|
|
||||||
|
|
||||||
.org 0x1000
|
|
||||||
_crt0:
|
|
||||||
/* Setup stack and global pointer */
|
|
||||||
l.movhi r1, hi(_fstack)
|
|
||||||
l.ori r1, r1, lo(_fstack)
|
|
||||||
|
|
||||||
/* Clear BSS */
|
|
||||||
l.movhi r21, hi(_fbss)
|
|
||||||
l.ori r21, r21, lo(_fbss)
|
|
||||||
l.movhi r3, hi(_ebss)
|
|
||||||
l.ori r3, r3, lo(_ebss)
|
|
||||||
.clearBSS:
|
|
||||||
l.sfeq r21, r3
|
|
||||||
l.bf .callMain
|
|
||||||
l.nop
|
|
||||||
l.sw 0(r21), r0
|
|
||||||
l.addi r21, r21, 4
|
|
||||||
l.j .clearBSS
|
|
||||||
l.nop
|
|
||||||
|
|
||||||
.callMain:
|
|
||||||
l.j main
|
|
||||||
l.nop
|
|
||||||
|
|
||||||
_exception_handler:
|
|
||||||
.cfi_startproc
|
|
||||||
.cfi_return_column 32
|
|
||||||
.cfi_signal_frame
|
|
||||||
.cfi_def_cfa_offset EXCEPTION_STACK_SIZE
|
|
||||||
l.sw 0x00(r1), r2
|
|
||||||
.cfi_offset 2, 0x00-EXCEPTION_STACK_SIZE
|
|
||||||
l.sw 0x04(r1), r3
|
|
||||||
.cfi_offset 3, 0x04-EXCEPTION_STACK_SIZE
|
|
||||||
l.sw 0x08(r1), r4
|
|
||||||
.cfi_offset 4, 0x08-EXCEPTION_STACK_SIZE
|
|
||||||
l.sw 0x0c(r1), r5
|
|
||||||
.cfi_offset 5, 0x0c-EXCEPTION_STACK_SIZE
|
|
||||||
l.sw 0x10(r1), r6
|
|
||||||
.cfi_offset 6, 0x10-EXCEPTION_STACK_SIZE
|
|
||||||
l.sw 0x14(r1), r7
|
|
||||||
.cfi_offset 7, 0x14-EXCEPTION_STACK_SIZE
|
|
||||||
l.sw 0x18(r1), r8
|
|
||||||
.cfi_offset 8, 0x18-EXCEPTION_STACK_SIZE
|
|
||||||
/* r9 saved in HANDLE_EXCEPTION */
|
|
||||||
.cfi_offset 9, 0x1c-EXCEPTION_STACK_SIZE
|
|
||||||
l.sw 0x20(r1), r10
|
|
||||||
.cfi_offset 10, 0x20-EXCEPTION_STACK_SIZE
|
|
||||||
l.sw 0x24(r1), r11
|
|
||||||
.cfi_offset 11, 0x24-EXCEPTION_STACK_SIZE
|
|
||||||
l.sw 0x28(r1), r12
|
|
||||||
.cfi_offset 12, 0x28-EXCEPTION_STACK_SIZE
|
|
||||||
l.sw 0x2c(r1), r13
|
|
||||||
.cfi_offset 13, 0x2c-EXCEPTION_STACK_SIZE
|
|
||||||
l.sw 0x30(r1), r14
|
|
||||||
.cfi_offset 14, 0x30-EXCEPTION_STACK_SIZE
|
|
||||||
l.sw 0x34(r1), r15
|
|
||||||
.cfi_offset 15, 0x34-EXCEPTION_STACK_SIZE
|
|
||||||
l.sw 0x38(r1), r16
|
|
||||||
.cfi_offset 16, 0x38-EXCEPTION_STACK_SIZE
|
|
||||||
l.sw 0x3c(r1), r17
|
|
||||||
.cfi_offset 17, 0x3c-EXCEPTION_STACK_SIZE
|
|
||||||
l.sw 0x40(r1), r18
|
|
||||||
.cfi_offset 18, 0x40-EXCEPTION_STACK_SIZE
|
|
||||||
l.sw 0x44(r1), r19
|
|
||||||
.cfi_offset 19, 0x44-EXCEPTION_STACK_SIZE
|
|
||||||
l.sw 0x48(r1), r20
|
|
||||||
.cfi_offset 20, 0x48-EXCEPTION_STACK_SIZE
|
|
||||||
l.sw 0x4c(r1), r21
|
|
||||||
.cfi_offset 21, 0x4c-EXCEPTION_STACK_SIZE
|
|
||||||
l.sw 0x50(r1), r22
|
|
||||||
.cfi_offset 22, 0x50-EXCEPTION_STACK_SIZE
|
|
||||||
l.sw 0x54(r1), r23
|
|
||||||
.cfi_offset 23, 0x54-EXCEPTION_STACK_SIZE
|
|
||||||
l.sw 0x58(r1), r24
|
|
||||||
.cfi_offset 24, 0x58-EXCEPTION_STACK_SIZE
|
|
||||||
l.sw 0x5c(r1), r25
|
|
||||||
.cfi_offset 25, 0x5c-EXCEPTION_STACK_SIZE
|
|
||||||
l.sw 0x60(r1), r26
|
|
||||||
.cfi_offset 26, 0x60-EXCEPTION_STACK_SIZE
|
|
||||||
l.sw 0x64(r1), r27
|
|
||||||
.cfi_offset 27, 0x64-EXCEPTION_STACK_SIZE
|
|
||||||
l.sw 0x68(r1), r28
|
|
||||||
.cfi_offset 28, 0x68-EXCEPTION_STACK_SIZE
|
|
||||||
l.sw 0x6c(r1), r29
|
|
||||||
.cfi_offset 29, 0x6c-EXCEPTION_STACK_SIZE
|
|
||||||
l.sw 0x70(r1), r30
|
|
||||||
.cfi_offset 30, 0x70-EXCEPTION_STACK_SIZE
|
|
||||||
l.sw 0x74(r1), r31
|
|
||||||
.cfi_offset 31, 0x74-EXCEPTION_STACK_SIZE
|
|
||||||
|
|
||||||
/* Save return address */
|
|
||||||
l.or r14, r0, r9
|
|
||||||
/* Calculate exception vector from handler address */
|
|
||||||
l.andi r3, r9, 0xf00
|
|
||||||
l.srli r3, r3, 8
|
|
||||||
/* Pass saved register state */
|
|
||||||
l.or r4, r0, r1
|
|
||||||
/* Extract exception PC */
|
|
||||||
l.mfspr r5, r0, SPR_EPCR_BASE
|
|
||||||
/* Tell exception PC to the unwinder */
|
|
||||||
l.sw 0x78(r1), r5
|
|
||||||
.cfi_offset 32, 0x78-EXCEPTION_STACK_SIZE
|
|
||||||
/* Extract exception effective address */
|
|
||||||
l.mfspr r6, r0, SPR_EEAR_BASE
|
|
||||||
/* Extract exception SR */
|
|
||||||
l.mfspr r7, r0, SPR_ESR_BASE
|
|
||||||
/* Call exception handler with the link address as argument */
|
|
||||||
l.jal exception
|
|
||||||
l.nop
|
|
||||||
|
|
||||||
/* Load return address */
|
|
||||||
l.or r9, r0, r14
|
|
||||||
/* Restore state */
|
|
||||||
l.lwz r2, 0x00(r1)
|
|
||||||
l.lwz r3, 0x04(r1)
|
|
||||||
l.lwz r4, 0x08(r1)
|
|
||||||
l.lwz r5, 0x0c(r1)
|
|
||||||
l.lwz r6, 0x10(r1)
|
|
||||||
l.lwz r7, 0x14(r1)
|
|
||||||
l.lwz r8, 0x18(r1)
|
|
||||||
l.lwz r10, 0x20(r1)
|
|
||||||
l.lwz r11, 0x24(r1)
|
|
||||||
l.lwz r12, 0x28(r1)
|
|
||||||
l.lwz r13, 0x2c(r1)
|
|
||||||
l.lwz r14, 0x30(r1)
|
|
||||||
l.lwz r15, 0x34(r1)
|
|
||||||
l.lwz r16, 0x38(r1)
|
|
||||||
l.lwz r17, 0x3c(r1)
|
|
||||||
l.lwz r18, 0x40(r1)
|
|
||||||
l.lwz r19, 0x44(r1)
|
|
||||||
l.lwz r20, 0x48(r1)
|
|
||||||
l.lwz r21, 0x4c(r1)
|
|
||||||
l.lwz r22, 0x50(r1)
|
|
||||||
l.lwz r23, 0x54(r1)
|
|
||||||
l.lwz r24, 0x58(r1)
|
|
||||||
l.lwz r25, 0x5c(r1)
|
|
||||||
l.lwz r26, 0x60(r1)
|
|
||||||
l.lwz r27, 0x64(r1)
|
|
||||||
l.lwz r28, 0x68(r1)
|
|
||||||
l.lwz r29, 0x6c(r1)
|
|
||||||
l.lwz r30, 0x70(r1)
|
|
||||||
l.lwz r31, 0x74(r1)
|
|
||||||
l.jr r9
|
|
||||||
l.nop
|
|
||||||
.cfi_endproc
|
|
||||||
|
|
||||||
.global _cache_init
|
|
||||||
_cache_init:
|
|
||||||
/*
|
|
||||||
This function is to be used ONLY during reset, before main() is called.
|
|
||||||
TODO: Perhaps break into individual enable instruction/data cache
|
|
||||||
sections functions, and provide disable functions, also, all
|
|
||||||
callable from C
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Instruction cache enable */
|
|
||||||
/* Check if IC present and skip enabling otherwise */
|
|
||||||
#if 1
|
|
||||||
.L6:
|
|
||||||
l.mfspr r3,r0,SPR_UPR
|
|
||||||
l.andi r7,r3,SPR_UPR_ICP
|
|
||||||
l.sfeq r7,r0
|
|
||||||
l.bf .L8
|
|
||||||
l.nop
|
|
||||||
|
|
||||||
/* Disable IC */
|
|
||||||
l.mfspr r6,r0,SPR_SR
|
|
||||||
l.addi r5,r0,-1
|
|
||||||
l.xori r5,r5,SPR_SR_ICE
|
|
||||||
l.and r5,r6,r5
|
|
||||||
l.mtspr r0,r5,SPR_SR
|
|
||||||
|
|
||||||
/* Establish cache block size
|
|
||||||
If BS=0, 16;
|
|
||||||
If BS=1, 32;
|
|
||||||
r14 contain block size
|
|
||||||
*/
|
|
||||||
l.mfspr r3,r0,SPR_ICCFGR
|
|
||||||
l.andi r7,r3,SPR_ICCFGR_CBS
|
|
||||||
l.srli r8,r7,7
|
|
||||||
l.ori r4,r0,16
|
|
||||||
l.sll r14,r4,r8
|
|
||||||
|
|
||||||
/* Establish number of cache sets
|
|
||||||
r10 contains number of cache sets
|
|
||||||
r8 contains log(# of cache sets)
|
|
||||||
*/
|
|
||||||
l.andi r7,r3,SPR_ICCFGR_NCS
|
|
||||||
l.srli r8,r7,3
|
|
||||||
l.ori r4,r0,1
|
|
||||||
l.sll r10,r4,r8
|
|
||||||
|
|
||||||
/* Invalidate IC */
|
|
||||||
l.addi r6,r0,0
|
|
||||||
l.sll r5,r14,r8
|
|
||||||
|
|
||||||
.L7: l.mtspr r0,r6,SPR_ICBIR
|
|
||||||
l.sfne r6,r5
|
|
||||||
l.bf .L7
|
|
||||||
l.add r6,r6,r14
|
|
||||||
|
|
||||||
/* Enable IC */
|
|
||||||
l.mfspr r6,r0,SPR_SR
|
|
||||||
l.ori r6,r6,SPR_SR_ICE
|
|
||||||
l.mtspr r0,r6,SPR_SR
|
|
||||||
l.nop
|
|
||||||
l.nop
|
|
||||||
l.nop
|
|
||||||
l.nop
|
|
||||||
l.nop
|
|
||||||
l.nop
|
|
||||||
l.nop
|
|
||||||
l.nop
|
|
||||||
/* Data cache enable */
|
|
||||||
/* Check if DC present and skip enabling otherwise */
|
|
||||||
#endif
|
|
||||||
.L8:
|
|
||||||
#if 1
|
|
||||||
l.mfspr r3,r0,SPR_UPR
|
|
||||||
l.andi r7,r3,SPR_UPR_DCP
|
|
||||||
l.sfeq r7,r0
|
|
||||||
l.bf .L10
|
|
||||||
l.nop
|
|
||||||
/* Disable DC */
|
|
||||||
l.mfspr r6,r0,SPR_SR
|
|
||||||
l.addi r5,r0,-1
|
|
||||||
l.xori r5,r5,SPR_SR_DCE
|
|
||||||
l.and r5,r6,r5
|
|
||||||
l.mtspr r0,r5,SPR_SR
|
|
||||||
/* Establish cache block size
|
|
||||||
If BS=0, 16;
|
|
||||||
If BS=1, 32;
|
|
||||||
r14 contain block size
|
|
||||||
*/
|
|
||||||
l.mfspr r3,r0,SPR_DCCFGR
|
|
||||||
l.andi r7,r3,SPR_DCCFGR_CBS
|
|
||||||
l.srli r8,r7,7
|
|
||||||
l.ori r4,r0,16
|
|
||||||
l.sll r14,r4,r8
|
|
||||||
/* Establish number of cache sets
|
|
||||||
r10 contains number of cache sets
|
|
||||||
r8 contains log(# of cache sets)
|
|
||||||
*/
|
|
||||||
l.andi r7,r3,SPR_DCCFGR_NCS
|
|
||||||
l.srli r8,r7,3
|
|
||||||
l.ori r4,r0,1
|
|
||||||
l.sll r10,r4,r8
|
|
||||||
/* Invalidate DC */
|
|
||||||
l.addi r6,r0,0
|
|
||||||
l.sll r5,r14,r8
|
|
||||||
|
|
||||||
.L9:
|
|
||||||
l.mtspr r0,r6,SPR_DCBIR
|
|
||||||
l.sfne r6,r5
|
|
||||||
l.bf .L9
|
|
||||||
l.add r6,r6,r14
|
|
||||||
/* Enable DC */
|
|
||||||
l.mfspr r6,r0,SPR_SR
|
|
||||||
l.ori r6,r6,SPR_SR_DCE
|
|
||||||
l.mtspr r0,r6,SPR_SR
|
|
||||||
#endif
|
|
||||||
.L10:
|
|
||||||
/* Return */
|
|
||||||
l.jr r9
|
|
||||||
l.nop
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
use super::{cache, pmp};
|
||||||
|
use riscv::register::*;
|
||||||
|
|
||||||
|
pub unsafe fn reset() -> ! {
|
||||||
|
llvm_asm!(r#"
|
||||||
|
j _reset_handler
|
||||||
|
nop
|
||||||
|
"# : : : : "volatile");
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn jump(addr: usize) -> ! {
|
||||||
|
cache::flush_cpu_icache();
|
||||||
|
llvm_asm!(r#"
|
||||||
|
jalr x0, 0($0)
|
||||||
|
nop
|
||||||
|
"# : : "r"(addr) : : "volatile");
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn start_user(addr: usize) -> ! {
|
||||||
|
pmp::enable_user_memory();
|
||||||
|
mstatus::set_mpp(mstatus::MPP::User);
|
||||||
|
mepc::write(addr);
|
||||||
|
llvm_asm!(
|
||||||
|
"mret"
|
||||||
|
: : : : "volatile"
|
||||||
|
);
|
||||||
|
unreachable!()
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
#[cfg(has_ddrphy)]
|
||||||
|
use core::ptr;
|
||||||
|
#[cfg(has_ddrphy)]
|
||||||
|
use csr;
|
||||||
|
#[cfg(has_ddrphy)]
|
||||||
|
use mem;
|
||||||
|
|
||||||
|
pub fn flush_cpu_icache() {
|
||||||
|
unsafe {
|
||||||
|
llvm_asm!(r#"
|
||||||
|
fence.i
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
nop
|
||||||
|
"# : : : : "volatile");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn flush_cpu_dcache() {
|
||||||
|
unsafe {
|
||||||
|
llvm_asm!(".word(0x500F)" : : : : "volatile");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(has_ddrphy)]
|
||||||
|
pub fn flush_l2_cache() {
|
||||||
|
unsafe {
|
||||||
|
for i in 0..2 * (csr::CONFIG_L2_SIZE as usize) / 4 {
|
||||||
|
let addr = mem::MAIN_RAM_BASE + i * 4;
|
||||||
|
ptr::read_volatile(addr as *const usize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,3 @@
|
||||||
pub mod spr;
|
|
||||||
pub mod irq;
|
|
||||||
pub mod cache;
|
pub mod cache;
|
||||||
pub mod boot;
|
pub mod boot;
|
||||||
|
pub mod pmp;
|
|
@ -0,0 +1,55 @@
|
||||||
|
use riscv::register::{pmpaddr0, pmpaddr1, pmpaddr2, pmpaddr3, pmpcfg0};
|
||||||
|
|
||||||
|
static mut THREAD_DEPTH: u8 = 0;
|
||||||
|
|
||||||
|
const PMP_L : usize = 0b10000000;
|
||||||
|
const PMP_NAPOT: usize = 0b00011000;
|
||||||
|
const PMP_X : usize = 0b00000100;
|
||||||
|
const PMP_W : usize = 0b00000010;
|
||||||
|
const PMP_R : usize = 0b00000001;
|
||||||
|
const PMP_OFF : usize = 0b00000000;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn init_stack_guard(guard_base: usize) {
|
||||||
|
pmpaddr2::write((guard_base >> 2) | ((0x1000 - 1) >> 3));
|
||||||
|
pmpcfg0::write((PMP_L | PMP_NAPOT) << 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn enable_user_memory() {
|
||||||
|
pmpaddr3::write((0x80000000 - 1) >> 3);
|
||||||
|
pmpcfg0::write((PMP_L | PMP_NAPOT | PMP_X | PMP_W | PMP_R) << 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn push_pmp_region(addr: usize) {
|
||||||
|
let pmp_addr = (addr >> 2) | ((0x1000 - 1) >> 3);
|
||||||
|
match THREAD_DEPTH {
|
||||||
|
// Activate PMP0 when switching from main stack to thread
|
||||||
|
0 => {
|
||||||
|
pmpaddr0::write(pmp_addr);
|
||||||
|
pmpcfg0::write(PMP_NAPOT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Temporarily activate PMP1 when spawning a thread from a thread
|
||||||
|
// The thread should swap back to the main stack very soon after init
|
||||||
|
1 => {
|
||||||
|
pmpaddr1::write(pmp_addr);
|
||||||
|
pmpcfg0::write(PMP_NAPOT << 8 | PMP_NAPOT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Thread *running* another thread should not be possible
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
THREAD_DEPTH += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn pop_pmp_region() {
|
||||||
|
THREAD_DEPTH -= 1;
|
||||||
|
match THREAD_DEPTH {
|
||||||
|
0 => pmpcfg0::write(PMP_OFF),
|
||||||
|
1 => pmpcfg0::write(PMP_NAPOT),
|
||||||
|
_ => unreachable!()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,176 @@
|
||||||
|
# Adapted from riscv-rt project, with the following license:
|
||||||
|
#
|
||||||
|
# Copyright 2018 RISC-V team
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and/or distribute this software for any purpose
|
||||||
|
# with or without fee is hereby granted, provided that the above copyright notice and
|
||||||
|
# this permission notice appear in all copies.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||||
|
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
# FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
|
||||||
|
# OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
|
||||||
|
# OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||||
|
# ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
#if __riscv_xlen == 64
|
||||||
|
# define STORE sd
|
||||||
|
# define LOAD ld
|
||||||
|
# define LOG_REGBYTES 3
|
||||||
|
#else
|
||||||
|
# define STORE sw
|
||||||
|
# define LOAD lw
|
||||||
|
# define LOG_REGBYTES 2
|
||||||
|
#endif
|
||||||
|
#define REGBYTES (1 << LOG_REGBYTES)
|
||||||
|
|
||||||
|
/*
|
||||||
|
Entry point of all programs (_reset_handler).
|
||||||
|
|
||||||
|
It initializes DWARF call frame information, the stack pointer, the
|
||||||
|
frame pointer (needed for closures to work in start_rust) and the global
|
||||||
|
pointer. Then it calls _start_rust.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.section .vectors, "ax", @progbits
|
||||||
|
.global _reset_handler
|
||||||
|
|
||||||
|
_reset_handler:
|
||||||
|
/* Jump to the absolute address defined by the linker script. */
|
||||||
|
// for 32bit
|
||||||
|
.if __riscv_xlen == 32
|
||||||
|
lui ra, %hi(_abs_start)
|
||||||
|
jr %lo(_abs_start)(ra)
|
||||||
|
.endif
|
||||||
|
|
||||||
|
// for 64bit
|
||||||
|
.if __riscv_xlen == 64
|
||||||
|
.option push
|
||||||
|
.option norelax // to prevent an unsupported R_RISCV_ALIGN relocation from being generated
|
||||||
|
1:
|
||||||
|
auipc ra, %pcrel_hi(1f)
|
||||||
|
ld ra, %pcrel_lo(1b)(ra)
|
||||||
|
jr ra
|
||||||
|
.align 3
|
||||||
|
1:
|
||||||
|
.dword _abs_start
|
||||||
|
.option pop
|
||||||
|
.endif
|
||||||
|
|
||||||
|
_abs_start:
|
||||||
|
.cfi_startproc
|
||||||
|
.cfi_undefined ra
|
||||||
|
|
||||||
|
csrw mie, 0
|
||||||
|
csrw mip, 0
|
||||||
|
|
||||||
|
li x1, 0
|
||||||
|
li x2, 0
|
||||||
|
li x3, 0
|
||||||
|
li x4, 0
|
||||||
|
li x5, 0
|
||||||
|
li x6, 0
|
||||||
|
li x7, 0
|
||||||
|
li x8, 0
|
||||||
|
li x9, 0
|
||||||
|
li x10,0
|
||||||
|
li x11,0
|
||||||
|
li x12,0
|
||||||
|
li x13,0
|
||||||
|
li x14,0
|
||||||
|
li x15,0
|
||||||
|
li x16,0
|
||||||
|
li x17,0
|
||||||
|
li x18,0
|
||||||
|
li x19,0
|
||||||
|
li x20,0
|
||||||
|
li x21,0
|
||||||
|
li x22,0
|
||||||
|
li x23,0
|
||||||
|
li x24,0
|
||||||
|
li x25,0
|
||||||
|
li x26,0
|
||||||
|
li x27,0
|
||||||
|
li x28,0
|
||||||
|
li x29,0
|
||||||
|
li x30,0
|
||||||
|
li x31,0
|
||||||
|
|
||||||
|
// Check hart id
|
||||||
|
csrr a2, mhartid
|
||||||
|
|
||||||
|
// Allocate stacks
|
||||||
|
la sp, _fstack
|
||||||
|
|
||||||
|
// Set frame pointer
|
||||||
|
add s0, sp, zero
|
||||||
|
|
||||||
|
// Set trap vector
|
||||||
|
la t0, _start_trap
|
||||||
|
csrw mtvec, t0
|
||||||
|
|
||||||
|
// Zero initialize .bss
|
||||||
|
la t0, _fbss
|
||||||
|
la t1, _ebss
|
||||||
|
beq t0, t1, 2f
|
||||||
|
1: STORE zero, 0(t0)
|
||||||
|
addi t0, t0, REGBYTES
|
||||||
|
bne t0, t1, 1b
|
||||||
|
2:
|
||||||
|
// Enter main firmware
|
||||||
|
jal zero, main
|
||||||
|
|
||||||
|
.cfi_endproc
|
||||||
|
|
||||||
|
/*
|
||||||
|
Trap entry point (_start_trap)
|
||||||
|
|
||||||
|
Saves caller saved registers ra, t0..6, a0..7, calls exception,
|
||||||
|
restores caller saved registers and then returns.
|
||||||
|
*/
|
||||||
|
.global _start_trap
|
||||||
|
/* Make it .weak so PAC/HAL can provide their own if needed. */
|
||||||
|
.weak _start_trap
|
||||||
|
|
||||||
|
_start_trap:
|
||||||
|
addi sp, sp, -16*REGBYTES
|
||||||
|
|
||||||
|
STORE ra, 0*REGBYTES(sp)
|
||||||
|
STORE t0, 1*REGBYTES(sp)
|
||||||
|
STORE t1, 2*REGBYTES(sp)
|
||||||
|
STORE t2, 3*REGBYTES(sp)
|
||||||
|
STORE t3, 4*REGBYTES(sp)
|
||||||
|
STORE t4, 5*REGBYTES(sp)
|
||||||
|
STORE t5, 6*REGBYTES(sp)
|
||||||
|
STORE t6, 7*REGBYTES(sp)
|
||||||
|
STORE a0, 8*REGBYTES(sp)
|
||||||
|
STORE a1, 9*REGBYTES(sp)
|
||||||
|
STORE a2, 10*REGBYTES(sp)
|
||||||
|
STORE a3, 11*REGBYTES(sp)
|
||||||
|
STORE a4, 12*REGBYTES(sp)
|
||||||
|
STORE a5, 13*REGBYTES(sp)
|
||||||
|
STORE a6, 14*REGBYTES(sp)
|
||||||
|
STORE a7, 15*REGBYTES(sp)
|
||||||
|
|
||||||
|
add a0, sp, zero
|
||||||
|
jal ra, exception
|
||||||
|
|
||||||
|
LOAD ra, 0*REGBYTES(sp)
|
||||||
|
LOAD t0, 1*REGBYTES(sp)
|
||||||
|
LOAD t1, 2*REGBYTES(sp)
|
||||||
|
LOAD t2, 3*REGBYTES(sp)
|
||||||
|
LOAD t3, 4*REGBYTES(sp)
|
||||||
|
LOAD t4, 5*REGBYTES(sp)
|
||||||
|
LOAD t5, 6*REGBYTES(sp)
|
||||||
|
LOAD t6, 7*REGBYTES(sp)
|
||||||
|
LOAD a0, 8*REGBYTES(sp)
|
||||||
|
LOAD a1, 9*REGBYTES(sp)
|
||||||
|
LOAD a2, 10*REGBYTES(sp)
|
||||||
|
LOAD a3, 11*REGBYTES(sp)
|
||||||
|
LOAD a4, 12*REGBYTES(sp)
|
||||||
|
LOAD a5, 13*REGBYTES(sp)
|
||||||
|
LOAD a6, 14*REGBYTES(sp)
|
||||||
|
LOAD a7, 15*REGBYTES(sp)
|
||||||
|
|
||||||
|
addi sp, sp, 16*REGBYTES
|
||||||
|
mret
|
|
@ -2,6 +2,7 @@
|
||||||
mod ddr {
|
mod ddr {
|
||||||
use core::{ptr, fmt};
|
use core::{ptr, fmt};
|
||||||
use csr::{dfii, ddrphy};
|
use csr::{dfii, ddrphy};
|
||||||
|
use csr::CONFIG_DATA_WIDTH_BYTES;
|
||||||
use sdram_phy::{self, spin_cycles};
|
use sdram_phy::{self, spin_cycles};
|
||||||
use sdram_phy::{DFII_COMMAND_CS, DFII_COMMAND_WE, DFII_COMMAND_CAS, DFII_COMMAND_RAS,
|
use sdram_phy::{DFII_COMMAND_CS, DFII_COMMAND_WE, DFII_COMMAND_CAS, DFII_COMMAND_RAS,
|
||||||
DFII_COMMAND_WRDATA, DFII_COMMAND_RDDATA};
|
DFII_COMMAND_WRDATA, DFII_COMMAND_RDDATA};
|
||||||
|
@ -14,6 +15,8 @@ mod ddr {
|
||||||
|
|
||||||
const DQS_SIGNAL_COUNT: usize = DFII_PIX_DATA_SIZE / 2;
|
const DQS_SIGNAL_COUNT: usize = DFII_PIX_DATA_SIZE / 2;
|
||||||
|
|
||||||
|
const CSR_SEPARATION: isize = CONFIG_DATA_WIDTH_BYTES as isize / 4;
|
||||||
|
|
||||||
macro_rules! log {
|
macro_rules! log {
|
||||||
($logger:expr, $( $arg:expr ),+) => (
|
($logger:expr, $( $arg:expr ),+) => (
|
||||||
if let &mut Some(ref mut f) = $logger {
|
if let &mut Some(ref mut f) = $logger {
|
||||||
|
@ -31,7 +34,7 @@ mod ddr {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(ddrphy_wlevel)]
|
#[cfg(ddrphy_wlevel)]
|
||||||
unsafe fn write_level_scan(logger: &mut Option<&mut fmt::Write>) {
|
unsafe fn write_level_scan(logger: &mut Option<&mut dyn fmt::Write>) {
|
||||||
#[cfg(kusddrphy)]
|
#[cfg(kusddrphy)]
|
||||||
log!(logger, "DQS initial delay: {} taps\n", ddrphy::wdly_dqs_taps_read());
|
log!(logger, "DQS initial delay: {} taps\n", ddrphy::wdly_dqs_taps_read());
|
||||||
log!(logger, "Write leveling scan:\n");
|
log!(logger, "Write leveling scan:\n");
|
||||||
|
@ -46,7 +49,7 @@ mod ddr {
|
||||||
|
|
||||||
for n in 0..DQS_SIGNAL_COUNT {
|
for n in 0..DQS_SIGNAL_COUNT {
|
||||||
let dq_addr = dfii::PI0_RDDATA_ADDR
|
let dq_addr = dfii::PI0_RDDATA_ADDR
|
||||||
.offset((DQS_SIGNAL_COUNT - 1 - n) as isize);
|
.offset(CSR_SEPARATION * (DQS_SIGNAL_COUNT - 1 - n) as isize);
|
||||||
|
|
||||||
log!(logger, "Module {}:\n", DQS_SIGNAL_COUNT - 1 - n);
|
log!(logger, "Module {}:\n", DQS_SIGNAL_COUNT - 1 - n);
|
||||||
|
|
||||||
|
@ -82,7 +85,7 @@ mod ddr {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(ddrphy_wlevel)]
|
#[cfg(ddrphy_wlevel)]
|
||||||
unsafe fn write_level(logger: &mut Option<&mut fmt::Write>,
|
unsafe fn write_level(logger: &mut Option<&mut dyn fmt::Write>,
|
||||||
delay: &mut [u16; DQS_SIGNAL_COUNT],
|
delay: &mut [u16; DQS_SIGNAL_COUNT],
|
||||||
high_skew: &mut [bool; DQS_SIGNAL_COUNT]) -> bool {
|
high_skew: &mut [bool; DQS_SIGNAL_COUNT]) -> bool {
|
||||||
#[cfg(kusddrphy)]
|
#[cfg(kusddrphy)]
|
||||||
|
@ -100,7 +103,7 @@ mod ddr {
|
||||||
let mut failed = false;
|
let mut failed = false;
|
||||||
for n in 0..DQS_SIGNAL_COUNT {
|
for n in 0..DQS_SIGNAL_COUNT {
|
||||||
let dq_addr = dfii::PI0_RDDATA_ADDR
|
let dq_addr = dfii::PI0_RDDATA_ADDR
|
||||||
.offset((DQS_SIGNAL_COUNT - 1 - n) as isize);
|
.offset(CSR_SEPARATION * (DQS_SIGNAL_COUNT - 1 - n) as isize);
|
||||||
|
|
||||||
delay[n] = 0;
|
delay[n] = 0;
|
||||||
high_skew[n] = false;
|
high_skew[n] = false;
|
||||||
|
@ -172,7 +175,7 @@ mod ddr {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(ddrphy_wlevel)]
|
#[cfg(ddrphy_wlevel)]
|
||||||
unsafe fn read_bitslip(logger: &mut Option<&mut fmt::Write>,
|
unsafe fn read_bitslip(logger: &mut Option<&mut dyn fmt::Write>,
|
||||||
delay: &[u16; DQS_SIGNAL_COUNT],
|
delay: &[u16; DQS_SIGNAL_COUNT],
|
||||||
high_skew: &[bool; DQS_SIGNAL_COUNT]) {
|
high_skew: &[bool; DQS_SIGNAL_COUNT]) {
|
||||||
let threshold_opt = delay.iter().zip(high_skew.iter())
|
let threshold_opt = delay.iter().zip(high_skew.iter())
|
||||||
|
@ -203,7 +206,7 @@ mod ddr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn read_level_scan(logger: &mut Option<&mut fmt::Write>) {
|
unsafe fn read_level_scan(logger: &mut Option<&mut dyn fmt::Write>) {
|
||||||
log!(logger, "Read leveling scan:\n");
|
log!(logger, "Read leveling scan:\n");
|
||||||
|
|
||||||
// Generate pseudo-random sequence
|
// Generate pseudo-random sequence
|
||||||
|
@ -223,7 +226,7 @@ mod ddr {
|
||||||
// Write test pattern
|
// Write test pattern
|
||||||
for p in 0..DFII_NPHASES {
|
for p in 0..DFII_NPHASES {
|
||||||
for offset in 0..DFII_PIX_DATA_SIZE {
|
for offset in 0..DFII_PIX_DATA_SIZE {
|
||||||
let addr = DFII_PIX_WRDATA_ADDR[p].offset(offset as isize);
|
let addr = DFII_PIX_WRDATA_ADDR[p].offset(CSR_SEPARATION * offset as isize);
|
||||||
let data = prs[DFII_PIX_DATA_SIZE * p + offset];
|
let data = prs[DFII_PIX_DATA_SIZE * p + offset];
|
||||||
ptr::write_volatile(addr, data as u32);
|
ptr::write_volatile(addr, data as u32);
|
||||||
}
|
}
|
||||||
|
@ -258,7 +261,7 @@ mod ddr {
|
||||||
|
|
||||||
for p in 0..DFII_NPHASES {
|
for p in 0..DFII_NPHASES {
|
||||||
for &offset in [n, n + DQS_SIGNAL_COUNT].iter() {
|
for &offset in [n, n + DQS_SIGNAL_COUNT].iter() {
|
||||||
let addr = DFII_PIX_RDDATA_ADDR[p].offset(offset as isize);
|
let addr = DFII_PIX_RDDATA_ADDR[p].offset(CSR_SEPARATION * offset as isize);
|
||||||
let data = prs[DFII_PIX_DATA_SIZE * p + offset];
|
let data = prs[DFII_PIX_DATA_SIZE * p + offset];
|
||||||
if ptr::read_volatile(addr) as u8 != data {
|
if ptr::read_volatile(addr) as u8 != data {
|
||||||
working = false;
|
working = false;
|
||||||
|
@ -286,7 +289,7 @@ mod ddr {
|
||||||
spin_cycles(15);
|
spin_cycles(15);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn read_level(logger: &mut Option<&mut fmt::Write>) -> bool {
|
unsafe fn read_level(logger: &mut Option<&mut dyn fmt::Write>) -> bool {
|
||||||
log!(logger, "Read leveling: ");
|
log!(logger, "Read leveling: ");
|
||||||
|
|
||||||
// Generate pseudo-random sequence
|
// Generate pseudo-random sequence
|
||||||
|
@ -306,7 +309,7 @@ mod ddr {
|
||||||
// Write test pattern
|
// Write test pattern
|
||||||
for p in 0..DFII_NPHASES {
|
for p in 0..DFII_NPHASES {
|
||||||
for offset in 0..DFII_PIX_DATA_SIZE {
|
for offset in 0..DFII_PIX_DATA_SIZE {
|
||||||
let addr = DFII_PIX_WRDATA_ADDR[p].offset(offset as isize);
|
let addr = DFII_PIX_WRDATA_ADDR[p].offset(CSR_SEPARATION * offset as isize);
|
||||||
let data = prs[DFII_PIX_DATA_SIZE * p + offset];
|
let data = prs[DFII_PIX_DATA_SIZE * p + offset];
|
||||||
ptr::write_volatile(addr, data as u32);
|
ptr::write_volatile(addr, data as u32);
|
||||||
}
|
}
|
||||||
|
@ -349,7 +352,7 @@ mod ddr {
|
||||||
|
|
||||||
for p in 0..DFII_NPHASES {
|
for p in 0..DFII_NPHASES {
|
||||||
for &offset in [n, n + DQS_SIGNAL_COUNT].iter() {
|
for &offset in [n, n + DQS_SIGNAL_COUNT].iter() {
|
||||||
let addr = DFII_PIX_RDDATA_ADDR[p].offset(offset as isize);
|
let addr = DFII_PIX_RDDATA_ADDR[p].offset(CSR_SEPARATION * offset as isize);
|
||||||
let data = prs[DFII_PIX_DATA_SIZE * p + offset];
|
let data = prs[DFII_PIX_DATA_SIZE * p + offset];
|
||||||
if ptr::read_volatile(addr) as u8 != data {
|
if ptr::read_volatile(addr) as u8 != data {
|
||||||
valid = false;
|
valid = false;
|
||||||
|
@ -417,7 +420,7 @@ mod ddr {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn level(logger: &mut Option<&mut fmt::Write>) -> bool {
|
pub unsafe fn level(logger: &mut Option<&mut dyn fmt::Write>) -> bool {
|
||||||
#[cfg(ddrphy_wlevel)]
|
#[cfg(ddrphy_wlevel)]
|
||||||
{
|
{
|
||||||
let mut delay = [0; DQS_SIGNAL_COUNT];
|
let mut delay = [0; DQS_SIGNAL_COUNT];
|
||||||
|
@ -442,7 +445,7 @@ use core::fmt;
|
||||||
use csr;
|
use csr;
|
||||||
use sdram_phy;
|
use sdram_phy;
|
||||||
|
|
||||||
pub unsafe fn init(mut _logger: Option<&mut fmt::Write>) -> bool {
|
pub unsafe fn init(mut _logger: Option<&mut dyn fmt::Write>) -> bool {
|
||||||
sdram_phy::initialize();
|
sdram_phy::initialize();
|
||||||
|
|
||||||
#[cfg(has_ddrphy)]
|
#[cfg(has_ddrphy)]
|
||||||
|
|
|
@ -113,3 +113,9 @@ pub unsafe fn write(mut addr: usize, mut data: &[u8]) {
|
||||||
data = &data[size..];
|
data = &data[size..];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(soc_platform = "kasli", soc_platform = "metlino", soc_platform = "kc705"))]
|
||||||
|
pub unsafe fn reload () -> ! {
|
||||||
|
csr::icap::iprog_write(1);
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
[package]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["M-Labs"]
|
||||||
|
edition = "2018"
|
|
@ -0,0 +1,8 @@
|
||||||
|
// Helper crate for dealing with c ffi
|
||||||
|
#![allow(non_camel_case_types)]
|
||||||
|
#![no_std]
|
||||||
|
pub type c_char = i8;
|
||||||
|
pub type c_int = i32;
|
||||||
|
pub type size_t = usize;
|
||||||
|
pub type uintptr_t = usize;
|
||||||
|
pub type c_void = core::ffi::c_void;
|
|
@ -131,6 +131,7 @@ pub const EM_TILEPRO: u16 = 188;
|
||||||
pub const EM_MICROBLAZE: u16 = 189;
|
pub const EM_MICROBLAZE: u16 = 189;
|
||||||
pub const EM_TILEGX: u16 = 191;
|
pub const EM_TILEGX: u16 = 191;
|
||||||
pub const EM_NUM: u16 = 192;
|
pub const EM_NUM: u16 = 192;
|
||||||
|
pub const EM_RISCV: u16 = 243;
|
||||||
pub const EM_ALPHA: u16 = 36902;
|
pub const EM_ALPHA: u16 = 36902;
|
||||||
pub const EV_NONE: u8 = 0;
|
pub const EV_NONE: u8 = 0;
|
||||||
pub const EV_CURRENT: u8 = 1;
|
pub const EV_CURRENT: u8 = 1;
|
||||||
|
@ -2229,6 +2230,67 @@ pub const R_OR1K_TLS_TPOFF: u8 = 32;
|
||||||
pub const R_OR1K_TLS_DTPOFF: u8 = 33;
|
pub const R_OR1K_TLS_DTPOFF: u8 = 33;
|
||||||
pub const R_OR1K_TLS_DTPMOD: u8 = 34;
|
pub const R_OR1K_TLS_DTPMOD: u8 = 34;
|
||||||
pub const R_OR1K_NUM: u8 = 35;
|
pub const R_OR1K_NUM: u8 = 35;
|
||||||
|
pub const EF_RISCV_RVC: u32 = 1;
|
||||||
|
pub const EF_RISCV_FLOAT_ABI: u32 = 6;
|
||||||
|
pub const EF_RISCV_FLOAT_ABI_SOFT: u32 = 0;
|
||||||
|
pub const EF_RISCV_FLOAT_ABI_SINGLE: u32 = 2;
|
||||||
|
pub const EF_RISCV_FLOAT_ABI_DOUBLE: u32 = 4;
|
||||||
|
pub const EF_RISCV_FLOAT_ABI_QUAD: u32 = 6;
|
||||||
|
pub const R_RISCV_NONE: u8 = 0;
|
||||||
|
pub const R_RISCV_32: u8 = 1;
|
||||||
|
pub const R_RISCV_64: u8 = 2;
|
||||||
|
pub const R_RISCV_RELATIVE: u8 = 3;
|
||||||
|
pub const R_RISCV_COPY: u8 = 4;
|
||||||
|
pub const R_RISCV_JUMP_SLOT: u8 = 5;
|
||||||
|
pub const R_RISCV_TLS_DTPMOD32: u8 = 6;
|
||||||
|
pub const R_RISCV_TLS_DTPMOD64: u8 = 7;
|
||||||
|
pub const R_RISCV_TLS_DTPREL32: u8 = 8;
|
||||||
|
pub const R_RISCV_TLS_DTPREL64: u8 = 9;
|
||||||
|
pub const R_RISCV_TLS_TPREL32: u8 = 10;
|
||||||
|
pub const R_RISCV_TLS_TPREL64: u8 = 11;
|
||||||
|
pub const R_RISCV_BRANCH: u8 = 16;
|
||||||
|
pub const R_RISCV_JAL: u8 = 17;
|
||||||
|
pub const R_RISCV_CALL: u8 = 18;
|
||||||
|
pub const R_RISCV_CALL_PLT: u8 = 19;
|
||||||
|
pub const R_RISCV_GOT_HI20: u8 = 20;
|
||||||
|
pub const R_RISCV_TLS_GOT_HI20: u8 = 21;
|
||||||
|
pub const R_RISCV_TLS_GD_HI20: u8 = 22;
|
||||||
|
pub const R_RISCV_PCREL_HI20: u8 = 23;
|
||||||
|
pub const R_RISCV_PCREL_LO12_I: u8 = 24;
|
||||||
|
pub const R_RISCV_PCREL_LO12_S: u8 = 25;
|
||||||
|
pub const R_RISCV_HI20: u8 = 26;
|
||||||
|
pub const R_RISCV_LO12_I: u8 = 27;
|
||||||
|
pub const R_RISCV_LO12_S: u8 = 28;
|
||||||
|
pub const R_RISCV_TPREL_HI20: u8 = 29;
|
||||||
|
pub const R_RISCV_TPREL_LO12_I: u8 = 30;
|
||||||
|
pub const R_RISCV_TPREL_LO12_S: u8 = 31;
|
||||||
|
pub const R_RISCV_TPREL_ADD: u8 = 32;
|
||||||
|
pub const R_RISCV_ADD8: u8 = 33;
|
||||||
|
pub const R_RISCV_ADD16: u8 = 34;
|
||||||
|
pub const R_RISCV_ADD32: u8 = 35;
|
||||||
|
pub const R_RISCV_ADD64: u8 = 36;
|
||||||
|
pub const R_RISCV_SUB8: u8 = 37;
|
||||||
|
pub const R_RISCV_SUB16: u8 = 38;
|
||||||
|
pub const R_RISCV_SUB32: u8 = 39;
|
||||||
|
pub const R_RISCV_SUB64: u8 = 40;
|
||||||
|
pub const R_RISCV_GNU_VTINHERIT: u8 = 41;
|
||||||
|
pub const R_RISCV_GNU_VTENTRY: u8 = 42;
|
||||||
|
pub const R_RISCV_ALIGN: u8 = 43;
|
||||||
|
pub const R_RISCV_RVC_BRANCH: u8 = 44;
|
||||||
|
pub const R_RISCV_RVC_JUMP: u8 = 45;
|
||||||
|
pub const R_RISCV_RVC_LUI: u8 = 46;
|
||||||
|
pub const R_RISCV_GPREL_I: u8 = 47;
|
||||||
|
pub const R_RISCV_GPREL_S: u8 = 48;
|
||||||
|
pub const R_RISCV_TPREL_I: u8 = 49;
|
||||||
|
pub const R_RISCV_TPREL_S: u8 = 50;
|
||||||
|
pub const R_RISCV_RELAX: u8 = 51;
|
||||||
|
pub const R_RISCV_SUB6: u8 = 52;
|
||||||
|
pub const R_RISCV_SET6: u8 = 53;
|
||||||
|
pub const R_RISCV_SET8: u8 = 54;
|
||||||
|
pub const R_RISCV_SET16: u8 = 55;
|
||||||
|
pub const R_RISCV_SET32: u8 = 56;
|
||||||
|
pub const R_RISCV_32_PCREL: u8 = 57;
|
||||||
|
pub const R_RISCV_NUM: u8 = 58;
|
||||||
|
|
||||||
pub type Elf32_Half = u16;
|
pub type Elf32_Half = u16;
|
||||||
pub type Elf64_Half = u16;
|
pub type Elf64_Half = u16;
|
||||||
|
|
|
@ -75,6 +75,12 @@ impl<'a> fmt::Display for Error<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum Arch {
|
||||||
|
RiscV,
|
||||||
|
OpenRisc,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Library<'a> {
|
pub struct Library<'a> {
|
||||||
image_off: Elf32_Addr,
|
image_off: Elf32_Addr,
|
||||||
image_sz: usize,
|
image_sz: usize,
|
||||||
|
@ -134,7 +140,7 @@ impl<'a> Library<'a> {
|
||||||
pub unsafe fn rebind(&self, name: &[u8], addr: Elf32_Word) -> Result<(), Error<'a>> {
|
pub unsafe fn rebind(&self, name: &[u8], addr: Elf32_Word) -> Result<(), Error<'a>> {
|
||||||
for rela in self.pltrel.iter() {
|
for rela in self.pltrel.iter() {
|
||||||
match ELF32_R_TYPE(rela.r_info) {
|
match ELF32_R_TYPE(rela.r_info) {
|
||||||
R_OR1K_32 | R_OR1K_GLOB_DAT | R_OR1K_JMP_SLOT => {
|
R_RISCV_32 | R_RISCV_JUMP_SLOT => {
|
||||||
let sym = self.symtab.get(ELF32_R_SYM(rela.r_info) as usize)
|
let sym = self.symtab.get(ELF32_R_SYM(rela.r_info) as usize)
|
||||||
.ok_or("symbol out of bounds of symbol table")?;
|
.ok_or("symbol out of bounds of symbol table")?;
|
||||||
let sym_name = self.name_starting_at(sym.st_name as usize)?;
|
let sym_name = self.name_starting_at(sym.st_name as usize)?;
|
||||||
|
@ -151,7 +157,7 @@ impl<'a> Library<'a> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_rela(&self, rela: &Elf32_Rela, resolve: &Fn(&[u8]) -> Option<Elf32_Word>)
|
fn resolve_rela(&self, rela: &Elf32_Rela, resolve: &dyn Fn(&[u8]) -> Option<Elf32_Word>)
|
||||||
-> Result<(), Error<'a>> {
|
-> Result<(), Error<'a>> {
|
||||||
let sym;
|
let sym;
|
||||||
if ELF32_R_SYM(rela.r_info) == 0 {
|
if ELF32_R_SYM(rela.r_info) == 0 {
|
||||||
|
@ -163,13 +169,13 @@ impl<'a> Library<'a> {
|
||||||
|
|
||||||
let value;
|
let value;
|
||||||
match ELF32_R_TYPE(rela.r_info) {
|
match ELF32_R_TYPE(rela.r_info) {
|
||||||
R_OR1K_NONE =>
|
R_RISCV_NONE =>
|
||||||
return Ok(()),
|
return Ok(()),
|
||||||
|
|
||||||
R_OR1K_RELATIVE =>
|
R_RISCV_RELATIVE =>
|
||||||
value = self.image_off + rela.r_addend as Elf32_Word,
|
value = self.image_off + rela.r_addend as Elf32_Word,
|
||||||
|
|
||||||
R_OR1K_32 | R_OR1K_GLOB_DAT | R_OR1K_JMP_SLOT => {
|
R_RISCV_32 | R_RISCV_JUMP_SLOT => {
|
||||||
let sym = sym.ok_or("relocation requires an associated symbol")?;
|
let sym = sym.ok_or("relocation requires an associated symbol")?;
|
||||||
let sym_name = self.name_starting_at(sym.st_name as usize)?;
|
let sym_name = self.name_starting_at(sym.st_name as usize)?;
|
||||||
|
|
||||||
|
@ -195,7 +201,7 @@ impl<'a> Library<'a> {
|
||||||
self.update_rela(rela, value)
|
self.update_rela(rela, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load(data: &[u8], image: &'a mut [u8], resolve: &Fn(&[u8]) -> Option<Elf32_Word>)
|
pub fn load(data: &[u8], image: &'a mut [u8], resolve: &dyn Fn(&[u8]) -> Option<Elf32_Word>)
|
||||||
-> Result<Library<'a>, Error<'a>> {
|
-> Result<Library<'a>, Error<'a>> {
|
||||||
#![allow(unused_assignments)]
|
#![allow(unused_assignments)]
|
||||||
|
|
||||||
|
@ -204,16 +210,22 @@ impl<'a> Library<'a> {
|
||||||
|
|
||||||
const IDENT: [u8; EI_NIDENT] = [
|
const IDENT: [u8; EI_NIDENT] = [
|
||||||
ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3,
|
ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3,
|
||||||
ELFCLASS32, ELFDATA2MSB, EV_CURRENT, ELFOSABI_NONE,
|
ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE,
|
||||||
/* ABI version */ 0, /* padding */ 0, 0, 0, 0, 0, 0, 0
|
/* ABI version */ 0, /* padding */ 0, 0, 0, 0, 0, 0, 0
|
||||||
];
|
];
|
||||||
|
|
||||||
#[cfg(target_arch = "or1k")]
|
#[cfg(target_arch = "riscv32")]
|
||||||
const ARCH: u16 = EM_OPENRISC;
|
const ARCH: u16 = EM_RISCV;
|
||||||
#[cfg(not(target_arch = "or1k"))]
|
#[cfg(not(target_arch = "riscv32"))]
|
||||||
const ARCH: u16 = EM_NONE;
|
const ARCH: u16 = EM_NONE;
|
||||||
|
|
||||||
if ehdr.e_ident != IDENT || ehdr.e_type != ET_DYN || ehdr.e_machine != ARCH {
|
#[cfg(all(target_feature = "f", target_feature = "d"))]
|
||||||
|
const FLAGS: u32 = EF_RISCV_FLOAT_ABI_DOUBLE;
|
||||||
|
|
||||||
|
#[cfg(not(all(target_feature = "f", target_feature = "d")))]
|
||||||
|
const FLAGS: u32 = EF_RISCV_FLOAT_ABI_SOFT;
|
||||||
|
|
||||||
|
if ehdr.e_ident != IDENT || ehdr.e_type != ET_DYN || ehdr.e_machine != ARCH || ehdr.e_flags != FLAGS {
|
||||||
return Err("not a shared library for current architecture")?
|
return Err("not a shared library for current architecture")?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,3 +9,6 @@ path = "lib.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cslice = { version = "0.3" }
|
cslice = { version = "0.3" }
|
||||||
|
libc = { path = "../libc" }
|
||||||
|
unwind = { path = "../libunwind" }
|
||||||
|
compiler_builtins = "=0.1.39" # A dependency of alloc, libeh doesn't need it
|
||||||
|
|
|
@ -1,51 +1,71 @@
|
||||||
#![allow(non_upper_case_globals, dead_code)]
|
//! Parsing of GCC-style Language-Specific Data Area (LSDA)
|
||||||
|
//! For details see:
|
||||||
|
//! * <https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html>
|
||||||
|
//! * <https://itanium-cxx-abi.github.io/cxx-abi/exceptions.pdf>
|
||||||
|
//! * <https://www.airs.com/blog/archives/460>
|
||||||
|
//! * <https://www.airs.com/blog/archives/464>
|
||||||
|
//!
|
||||||
|
//! A reference implementation may be found in the GCC source tree
|
||||||
|
//! (`<root>/libgcc/unwind-c.c` as of this writing).
|
||||||
|
|
||||||
use core::{ptr, mem};
|
#![allow(non_upper_case_globals)]
|
||||||
use cslice::CSlice;
|
#![allow(unused)]
|
||||||
|
|
||||||
const DW_EH_PE_omit: u8 = 0xFF;
|
use core::mem;
|
||||||
const DW_EH_PE_absptr: u8 = 0x00;
|
|
||||||
|
|
||||||
const DW_EH_PE_uleb128: u8 = 0x01;
|
pub const DW_EH_PE_omit: u8 = 0xFF;
|
||||||
const DW_EH_PE_udata2: u8 = 0x02;
|
pub const DW_EH_PE_absptr: u8 = 0x00;
|
||||||
const DW_EH_PE_udata4: u8 = 0x03;
|
|
||||||
const DW_EH_PE_udata8: u8 = 0x04;
|
|
||||||
const DW_EH_PE_sleb128: u8 = 0x09;
|
|
||||||
const DW_EH_PE_sdata2: u8 = 0x0A;
|
|
||||||
const DW_EH_PE_sdata4: u8 = 0x0B;
|
|
||||||
const DW_EH_PE_sdata8: u8 = 0x0C;
|
|
||||||
|
|
||||||
const DW_EH_PE_pcrel: u8 = 0x10;
|
pub const DW_EH_PE_uleb128: u8 = 0x01;
|
||||||
const DW_EH_PE_textrel: u8 = 0x20;
|
pub const DW_EH_PE_udata2: u8 = 0x02;
|
||||||
const DW_EH_PE_datarel: u8 = 0x30;
|
pub const DW_EH_PE_udata4: u8 = 0x03;
|
||||||
const DW_EH_PE_funcrel: u8 = 0x40;
|
pub const DW_EH_PE_udata8: u8 = 0x04;
|
||||||
const DW_EH_PE_aligned: u8 = 0x50;
|
pub const DW_EH_PE_sleb128: u8 = 0x09;
|
||||||
|
pub const DW_EH_PE_sdata2: u8 = 0x0A;
|
||||||
|
pub const DW_EH_PE_sdata4: u8 = 0x0B;
|
||||||
|
pub const DW_EH_PE_sdata8: u8 = 0x0C;
|
||||||
|
|
||||||
const DW_EH_PE_indirect: u8 = 0x80;
|
pub const DW_EH_PE_pcrel: u8 = 0x10;
|
||||||
|
pub const DW_EH_PE_textrel: u8 = 0x20;
|
||||||
|
pub const DW_EH_PE_datarel: u8 = 0x30;
|
||||||
|
pub const DW_EH_PE_funcrel: u8 = 0x40;
|
||||||
|
pub const DW_EH_PE_aligned: u8 = 0x50;
|
||||||
|
|
||||||
#[derive(Clone)]
|
pub const DW_EH_PE_indirect: u8 = 0x80;
|
||||||
struct DwarfReader {
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct EHContext<'a> {
|
||||||
|
pub ip: usize, // Current instruction pointer
|
||||||
|
pub func_start: usize, // Address of the current function
|
||||||
|
pub get_text_start: &'a dyn Fn() -> usize, // Get address of the code section
|
||||||
|
pub get_data_start: &'a dyn Fn() -> usize, // Get address of the data section
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DwarfReader {
|
||||||
pub ptr: *const u8,
|
pub ptr: *const u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(C, packed)]
|
||||||
|
struct Unaligned<T>(T);
|
||||||
|
|
||||||
impl DwarfReader {
|
impl DwarfReader {
|
||||||
fn new(ptr: *const u8) -> DwarfReader {
|
pub fn new(ptr: *const u8) -> DwarfReader {
|
||||||
DwarfReader { ptr: ptr }
|
DwarfReader { ptr }
|
||||||
}
|
}
|
||||||
|
|
||||||
// DWARF streams are packed, so e.g. a u32 would not necessarily be aligned
|
// DWARF streams are packed, so e.g., a u32 would not necessarily be aligned
|
||||||
// on a 4-byte boundary. This may cause problems on platforms with strict
|
// on a 4-byte boundary. This may cause problems on platforms with strict
|
||||||
// alignment requirements. By wrapping data in a "packed" struct, we are
|
// alignment requirements. By wrapping data in a "packed" struct, we are
|
||||||
// telling the backend to generate "misalignment-safe" code.
|
// telling the backend to generate "misalignment-safe" code.
|
||||||
unsafe fn read<T: Copy>(&mut self) -> T {
|
pub unsafe fn read<T: Copy>(&mut self) -> T {
|
||||||
let result = ptr::read_unaligned(self.ptr as *const T);
|
let Unaligned(result) = *(self.ptr as *const Unaligned<T>);
|
||||||
self.ptr = self.ptr.offset(mem::size_of::<T>() as isize);
|
self.ptr = self.ptr.add(mem::size_of::<T>());
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
// ULEB128 and SLEB128 encodings are defined in Section 7.6 - "Variable
|
// ULEB128 and SLEB128 encodings are defined in Section 7.6 - "Variable
|
||||||
// Length Data".
|
// Length Data".
|
||||||
unsafe fn read_uleb128(&mut self) -> u64 {
|
pub unsafe fn read_uleb128(&mut self) -> u64 {
|
||||||
let mut shift: usize = 0;
|
let mut shift: usize = 0;
|
||||||
let mut result: u64 = 0;
|
let mut result: u64 = 0;
|
||||||
let mut byte: u8;
|
let mut byte: u8;
|
||||||
|
@ -60,8 +80,8 @@ impl DwarfReader {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn read_sleb128(&mut self) -> i64 {
|
pub unsafe fn read_sleb128(&mut self) -> i64 {
|
||||||
let mut shift: usize = 0;
|
let mut shift: u32 = 0;
|
||||||
let mut result: u64 = 0;
|
let mut result: u64 = 0;
|
||||||
let mut byte: u8;
|
let mut byte: u8;
|
||||||
loop {
|
loop {
|
||||||
|
@ -73,70 +93,61 @@ impl DwarfReader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// sign-extend
|
// sign-extend
|
||||||
if shift < 8 * mem::size_of::<u64>() && (byte & 0x40) != 0 {
|
if shift < u64::BITS && (byte & 0x40) != 0 {
|
||||||
result |= (!0 as u64) << shift;
|
result |= (!0 as u64) << shift;
|
||||||
}
|
}
|
||||||
result as i64
|
result as i64
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn read_encoded_pointer(&mut self, encoding: u8) -> usize {
|
|
||||||
fn round_up(unrounded: usize, align: usize) -> usize {
|
|
||||||
debug_assert!(align.is_power_of_two());
|
|
||||||
(unrounded + align - 1) & !(align - 1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_assert!(encoding != DW_EH_PE_omit);
|
unsafe fn read_encoded_pointer(
|
||||||
|
reader: &mut DwarfReader,
|
||||||
|
context: &EHContext<'_>,
|
||||||
|
encoding: u8,
|
||||||
|
) -> Result<usize, ()> {
|
||||||
|
if encoding == DW_EH_PE_omit {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
|
||||||
// DW_EH_PE_aligned implies it's an absolute pointer value
|
// DW_EH_PE_aligned implies it's an absolute pointer value
|
||||||
if encoding == DW_EH_PE_aligned {
|
if encoding == DW_EH_PE_aligned {
|
||||||
self.ptr = round_up(self.ptr as usize, mem::size_of::<usize>()) as *const u8;
|
reader.ptr = round_up(reader.ptr as usize, mem::size_of::<usize>())? as *const u8;
|
||||||
return self.read::<usize>()
|
return Ok(reader.read::<usize>());
|
||||||
}
|
}
|
||||||
|
|
||||||
let value_ptr = self.ptr;
|
|
||||||
let mut result = match encoding & 0x0F {
|
let mut result = match encoding & 0x0F {
|
||||||
DW_EH_PE_absptr => self.read::<usize>(),
|
DW_EH_PE_absptr => reader.read::<usize>(),
|
||||||
DW_EH_PE_uleb128 => self.read_uleb128() as usize,
|
DW_EH_PE_uleb128 => reader.read_uleb128() as usize,
|
||||||
DW_EH_PE_udata2 => self.read::<u16>() as usize,
|
DW_EH_PE_udata2 => reader.read::<u16>() as usize,
|
||||||
DW_EH_PE_udata4 => self.read::<u32>() as usize,
|
DW_EH_PE_udata4 => reader.read::<u32>() as usize,
|
||||||
DW_EH_PE_udata8 => self.read::<u64>() as usize,
|
DW_EH_PE_udata8 => reader.read::<u64>() as usize,
|
||||||
DW_EH_PE_sleb128 => self.read_sleb128() as usize,
|
DW_EH_PE_sleb128 => reader.read_sleb128() as usize,
|
||||||
DW_EH_PE_sdata2 => self.read::<i16>() as usize,
|
DW_EH_PE_sdata2 => reader.read::<i16>() as usize,
|
||||||
DW_EH_PE_sdata4 => self.read::<i32>() as usize,
|
DW_EH_PE_sdata4 => reader.read::<i32>() as usize,
|
||||||
DW_EH_PE_sdata8 => self.read::<i64>() as usize,
|
DW_EH_PE_sdata8 => reader.read::<i64>() as usize,
|
||||||
_ => panic!(),
|
_ => return Err(()),
|
||||||
};
|
};
|
||||||
|
|
||||||
result += match encoding & 0x70 {
|
result += match encoding & 0x70 {
|
||||||
DW_EH_PE_absptr => 0,
|
DW_EH_PE_absptr => 0,
|
||||||
// relative to address of the encoded value, despite the name
|
// relative to address of the encoded value, despite the name
|
||||||
DW_EH_PE_pcrel => value_ptr as usize,
|
DW_EH_PE_pcrel => reader.ptr as usize,
|
||||||
_ => panic!(),
|
DW_EH_PE_funcrel => {
|
||||||
|
if context.func_start == 0 {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
context.func_start
|
||||||
|
}
|
||||||
|
DW_EH_PE_textrel => (*context.get_text_start)(),
|
||||||
|
DW_EH_PE_datarel => (*context.get_data_start)(),
|
||||||
|
_ => return Err(()),
|
||||||
};
|
};
|
||||||
|
|
||||||
if encoding & DW_EH_PE_indirect != 0 {
|
if encoding & DW_EH_PE_indirect != 0 {
|
||||||
result = *(result as *const usize);
|
result = *(result as *const usize);
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
Ok(result)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn encoding_size(encoding: u8) -> usize {
|
|
||||||
if encoding == DW_EH_PE_omit {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
match encoding & 0x0F {
|
|
||||||
DW_EH_PE_absptr => mem::size_of::<usize>(),
|
|
||||||
DW_EH_PE_udata2 => 2,
|
|
||||||
DW_EH_PE_udata4 => 4,
|
|
||||||
DW_EH_PE_udata8 => 8,
|
|
||||||
DW_EH_PE_sdata2 => 2,
|
|
||||||
DW_EH_PE_sdata4 => 4,
|
|
||||||
DW_EH_PE_sdata8 => 8,
|
|
||||||
_ => panic!()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum EHAction {
|
pub enum EHAction {
|
||||||
|
@ -146,98 +157,94 @@ pub enum EHAction {
|
||||||
Terminate,
|
Terminate,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn find_eh_action(lsda: *const u8, func_start: usize, ip: usize,
|
pub const USING_SJLJ_EXCEPTIONS: bool = cfg!(all(target_os = "ios", target_arch = "arm"));
|
||||||
exn_name: CSlice<u8>) -> EHAction {
|
|
||||||
|
pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>) -> Result<EHAction, ()> {
|
||||||
if lsda.is_null() {
|
if lsda.is_null() {
|
||||||
return EHAction::None
|
return Ok(EHAction::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let func_start = context.func_start;
|
||||||
let mut reader = DwarfReader::new(lsda);
|
let mut reader = DwarfReader::new(lsda);
|
||||||
|
|
||||||
let start_encoding = reader.read::<u8>();
|
let start_encoding = reader.read::<u8>();
|
||||||
// base address for landing pad offsets
|
// base address for landing pad offsets
|
||||||
let lpad_base = if start_encoding != DW_EH_PE_omit {
|
let lpad_base = if start_encoding != DW_EH_PE_omit {
|
||||||
reader.read_encoded_pointer(start_encoding)
|
read_encoded_pointer(&mut reader, context, start_encoding)?
|
||||||
} else {
|
} else {
|
||||||
func_start
|
func_start
|
||||||
};
|
};
|
||||||
|
|
||||||
let ttype_encoding = reader.read::<u8>();
|
let ttype_encoding = reader.read::<u8>();
|
||||||
let ttype_encoding_size = encoding_size(ttype_encoding) as isize;
|
|
||||||
|
|
||||||
let class_info;
|
|
||||||
if ttype_encoding != DW_EH_PE_omit {
|
if ttype_encoding != DW_EH_PE_omit {
|
||||||
let class_info_offset = reader.read_uleb128();
|
// Rust doesn't analyze exception types, so we don't care about the type table
|
||||||
class_info = reader.ptr.offset(class_info_offset as isize);
|
reader.read_uleb128();
|
||||||
} else {
|
|
||||||
class_info = ptr::null();
|
|
||||||
}
|
}
|
||||||
assert!(!class_info.is_null());
|
|
||||||
|
|
||||||
let call_site_encoding = reader.read::<u8>();
|
let call_site_encoding = reader.read::<u8>();
|
||||||
let call_site_table_length = reader.read_uleb128();
|
let call_site_table_length = reader.read_uleb128();
|
||||||
let action_table = reader.ptr.offset(call_site_table_length as isize);
|
let action_table = reader.ptr.offset(call_site_table_length as isize);
|
||||||
|
let ip = context.ip;
|
||||||
|
|
||||||
|
if !USING_SJLJ_EXCEPTIONS {
|
||||||
while reader.ptr < action_table {
|
while reader.ptr < action_table {
|
||||||
let cs_start = reader.read_encoded_pointer(call_site_encoding);
|
let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding)?;
|
||||||
let cs_len = reader.read_encoded_pointer(call_site_encoding);
|
let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding)?;
|
||||||
let cs_lpad = reader.read_encoded_pointer(call_site_encoding);
|
let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding)?;
|
||||||
let cs_action = reader.read_uleb128();
|
let cs_action = reader.read_uleb128();
|
||||||
|
|
||||||
if ip < func_start + cs_start {
|
|
||||||
// Callsite table is sorted by cs_start, so if we've passed the ip, we
|
// Callsite table is sorted by cs_start, so if we've passed the ip, we
|
||||||
// may stop searching.
|
// may stop searching.
|
||||||
break
|
if ip < func_start + cs_start {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if ip > func_start + cs_start + cs_len {
|
if ip < func_start + cs_start + cs_len {
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if cs_lpad == 0 {
|
if cs_lpad == 0 {
|
||||||
return EHAction::None
|
return Ok(EHAction::None);
|
||||||
}
|
|
||||||
|
|
||||||
let lpad = lpad_base + cs_lpad;
|
|
||||||
if cs_action == 0 {
|
|
||||||
return EHAction::Cleanup(lpad)
|
|
||||||
}
|
|
||||||
|
|
||||||
let action_entry = action_table.offset((cs_action - 1) as isize);
|
|
||||||
let mut action_reader = DwarfReader::new(action_entry);
|
|
||||||
loop {
|
|
||||||
let type_info_offset = action_reader.read_sleb128() as isize;
|
|
||||||
let action_offset = action_reader.clone().read_sleb128() as isize;
|
|
||||||
assert!(type_info_offset >= 0);
|
|
||||||
|
|
||||||
if type_info_offset > 0 {
|
|
||||||
let type_info_ptr_ptr = class_info.offset(-type_info_offset * ttype_encoding_size);
|
|
||||||
let type_info_ptr = DwarfReader::new(type_info_ptr_ptr)
|
|
||||||
.read_encoded_pointer(ttype_encoding);
|
|
||||||
let type_info = *(type_info_ptr as *const CSlice<u8>);
|
|
||||||
|
|
||||||
if type_info.as_ref() == exn_name.as_ref() {
|
|
||||||
return EHAction::Catch(lpad)
|
|
||||||
}
|
|
||||||
|
|
||||||
if type_info.len() == 0 {
|
|
||||||
// This is a catch-all clause. We don't compare type_info_ptr with null here
|
|
||||||
// because, in PIC mode, the OR1K LLVM backend emits a literal zero
|
|
||||||
// encoded with DW_EH_PE_pcrel, which of course doesn't result in
|
|
||||||
// a proper null pointer.
|
|
||||||
return EHAction::Catch(lpad)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if action_offset == 0 {
|
|
||||||
break
|
|
||||||
} else {
|
} else {
|
||||||
action_reader.ptr = action_reader.ptr.offset(action_offset)
|
let lpad = lpad_base + cs_lpad;
|
||||||
|
return Ok(interpret_cs_action(cs_action, lpad));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Ip is not present in the table. This should not happen... but it does: issue #35011.
|
||||||
|
// So rather than returning EHAction::Terminate, we do this.
|
||||||
|
Ok(EHAction::None)
|
||||||
|
} else {
|
||||||
|
// SjLj version:
|
||||||
|
// The "IP" is an index into the call-site table, with two exceptions:
|
||||||
|
// -1 means 'no-action', and 0 means 'terminate'.
|
||||||
|
match ip as isize {
|
||||||
|
-1 => return Ok(EHAction::None),
|
||||||
|
0 => return Ok(EHAction::Terminate),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
let mut idx = ip;
|
||||||
|
loop {
|
||||||
|
let cs_lpad = reader.read_uleb128();
|
||||||
|
let cs_action = reader.read_uleb128();
|
||||||
|
idx -= 1;
|
||||||
|
if idx == 0 {
|
||||||
|
// Can never have null landing pad for sjlj -- that would have
|
||||||
|
// been indicated by a -1 call site index.
|
||||||
|
let lpad = (cs_lpad + 1) as usize;
|
||||||
|
return Ok(interpret_cs_action(cs_action, lpad));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return EHAction::None
|
fn interpret_cs_action(cs_action: u64, lpad: usize) -> EHAction {
|
||||||
|
if cs_action == 0 {
|
||||||
|
// If cs_action is 0 then this is a cleanup (Drop::drop). We run these
|
||||||
|
// for both Rust panics and foreign exceptions.
|
||||||
|
EHAction::Cleanup(lpad)
|
||||||
|
} else {
|
||||||
|
// Stop unwinding Rust panics at catch_unwind.
|
||||||
|
EHAction::Catch(lpad)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// the function has a personality but no landing pads; this is fine
|
#[inline]
|
||||||
EHAction::None
|
fn round_up(unrounded: usize, align: usize) -> Result<usize, ()> {
|
||||||
|
if align.is_power_of_two() { Ok((unrounded + align - 1) & !(align - 1)) } else { Err(()) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,13 +14,10 @@
|
||||||
//
|
//
|
||||||
// By design, this personality function is only ever called in the search phase, although
|
// By design, this personality function is only ever called in the search phase, although
|
||||||
// to keep things simple and close to upstream, it is not modified
|
// to keep things simple and close to upstream, it is not modified
|
||||||
#![allow(private_no_mangle_fns)]
|
|
||||||
|
|
||||||
use unwind as uw;
|
use unwind as uw;
|
||||||
use libc::{c_int, uintptr_t};
|
use libc::{c_int, uintptr_t};
|
||||||
use cslice::AsCSlice;
|
|
||||||
|
|
||||||
use dwarf::{self, EHAction};
|
use dwarf::{self, EHAction, EHContext};
|
||||||
|
|
||||||
// Register ids were lifted from LLVM's TargetLowering::getExceptionPointerRegister()
|
// Register ids were lifted from LLVM's TargetLowering::getExceptionPointerRegister()
|
||||||
// and TargetLowering::getExceptionSelectorRegister() for each architecture,
|
// and TargetLowering::getExceptionSelectorRegister() for each architecture,
|
||||||
|
@ -34,8 +31,8 @@ const UNWIND_DATA_REG: (i32, i32) = (0, 2); // EAX, EDX
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX
|
const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX
|
||||||
|
|
||||||
#[cfg(any(target_arch = "or1k"))]
|
#[cfg(any(target_arch = "riscv32"))]
|
||||||
const UNWIND_DATA_REG: (i32, i32) = (3, 4); // R3, R4
|
const UNWIND_DATA_REG: (i32, i32) = (10, 11); // X10, X11
|
||||||
|
|
||||||
// The following code is based on GCC's C and C++ personality routines. For reference, see:
|
// The following code is based on GCC's C and C++ personality routines. For reference, see:
|
||||||
// https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_personality.cc
|
// https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_personality.cc
|
||||||
|
@ -78,11 +75,17 @@ unsafe extern "C" fn rust_eh_personality(version: c_int,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn find_eh_action(context: *mut uw::_Unwind_Context)
|
unsafe fn find_eh_action(context: *mut uw::_Unwind_Context) -> Result<EHAction, ()> {
|
||||||
-> Result<EHAction, ()>
|
|
||||||
{
|
|
||||||
let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8;
|
let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8;
|
||||||
let func = uw::_Unwind_GetRegionStart(context);
|
let mut ip_before_instr: c_int = 0;
|
||||||
let ip = uw::_Unwind_GetIP(context);
|
let ip = uw::_Unwind_GetIPInfo(context, &mut ip_before_instr);
|
||||||
Ok(dwarf::find_eh_action(lsda, func, ip, [].as_c_slice()))
|
let eh_context = EHContext {
|
||||||
|
// The return address points 1 byte past the call instruction,
|
||||||
|
// which could be in the next IP range in LSDA range table.
|
||||||
|
ip: if ip_before_instr != 0 { ip } else { ip - 1 },
|
||||||
|
func_start: uw::_Unwind_GetRegionStart(context),
|
||||||
|
get_text_start: &|| uw::_Unwind_GetTextRelBase(context),
|
||||||
|
get_data_start: &|| uw::_Unwind_GetDataRelBase(context),
|
||||||
|
};
|
||||||
|
dwarf::find_eh_action(lsda, &eh_context)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#![feature(lang_items, panic_unwind, libc, unwind_attributes)]
|
#![feature(lang_items, panic_unwind, libc, unwind_attributes, int_bits_const)]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
extern crate cslice;
|
extern crate cslice;
|
||||||
|
|
|
@ -8,8 +8,8 @@ name = "io"
|
||||||
path = "lib.rs"
|
path = "lib.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
failure = { version = "0.1", default-features = false }
|
failure = { version = "=0.1.1", default-features = false }
|
||||||
failure_derive = { version = "0.1", default-features = false }
|
failure_derive = { version = "=0.1.1", default-features = false }
|
||||||
byteorder = { version = "1.0", default-features = false, optional = true }
|
byteorder = { version = "1.0", default-features = false, optional = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|
|
@ -69,7 +69,7 @@ impl<'a> Write for Cursor<&'a mut [u8]> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
impl Write for Cursor<::alloc::Vec<u8>> {
|
impl Write for Cursor<::alloc::vec::Vec<u8>> {
|
||||||
type WriteError = !;
|
type WriteError = !;
|
||||||
type FlushError = !;
|
type FlushError = !;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
#![cfg_attr(feature = "alloc", feature(alloc))]
|
|
||||||
|
|
||||||
extern crate failure;
|
extern crate failure;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
@ -131,7 +130,7 @@ impl<'a> Write for &'a mut [u8] {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
impl<'a> Write for alloc::Vec<u8> {
|
impl<'a> Write for alloc::vec::Vec<u8> {
|
||||||
type WriteError = !;
|
type WriteError = !;
|
||||||
type FlushError = !;
|
type FlushError = !;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
use {core::str::Utf8Error, alloc::String};
|
use {core::str::Utf8Error, alloc::string::String};
|
||||||
use byteorder::{ByteOrder, NetworkEndian};
|
use byteorder::{ByteOrder, NativeEndian};
|
||||||
|
|
||||||
use ::{Read, Write, Error as IoError};
|
use ::{Read, Write, Error as IoError};
|
||||||
|
|
||||||
|
@ -29,21 +29,21 @@ pub trait ProtoRead {
|
||||||
fn read_u16(&mut self) -> Result<u16, Self::ReadError> {
|
fn read_u16(&mut self) -> Result<u16, Self::ReadError> {
|
||||||
let mut bytes = [0; 2];
|
let mut bytes = [0; 2];
|
||||||
self.read_exact(&mut bytes)?;
|
self.read_exact(&mut bytes)?;
|
||||||
Ok(NetworkEndian::read_u16(&bytes))
|
Ok(NativeEndian::read_u16(&bytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn read_u32(&mut self) -> Result<u32, Self::ReadError> {
|
fn read_u32(&mut self) -> Result<u32, Self::ReadError> {
|
||||||
let mut bytes = [0; 4];
|
let mut bytes = [0; 4];
|
||||||
self.read_exact(&mut bytes)?;
|
self.read_exact(&mut bytes)?;
|
||||||
Ok(NetworkEndian::read_u32(&bytes))
|
Ok(NativeEndian::read_u32(&bytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn read_u64(&mut self) -> Result<u64, Self::ReadError> {
|
fn read_u64(&mut self) -> Result<u64, Self::ReadError> {
|
||||||
let mut bytes = [0; 8];
|
let mut bytes = [0; 8];
|
||||||
self.read_exact(&mut bytes)?;
|
self.read_exact(&mut bytes)?;
|
||||||
Ok(NetworkEndian::read_u64(&bytes))
|
Ok(NativeEndian::read_u64(&bytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -53,7 +53,7 @@ pub trait ProtoRead {
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn read_bytes(&mut self) -> Result<::alloc::Vec<u8>, Self::ReadError> {
|
fn read_bytes(&mut self) -> Result<::alloc::vec::Vec<u8>, Self::ReadError> {
|
||||||
let length = self.read_u32()?;
|
let length = self.read_u32()?;
|
||||||
let mut value = vec![0; length as usize];
|
let mut value = vec![0; length as usize];
|
||||||
self.read_exact(&mut value)?;
|
self.read_exact(&mut value)?;
|
||||||
|
@ -62,7 +62,7 @@ pub trait ProtoRead {
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn read_string(&mut self) -> Result<::alloc::String, ReadStringError<Self::ReadError>> {
|
fn read_string(&mut self) -> Result<::alloc::string::String, ReadStringError<Self::ReadError>> {
|
||||||
let bytes = self.read_bytes().map_err(ReadStringError::Other)?;
|
let bytes = self.read_bytes().map_err(ReadStringError::Other)?;
|
||||||
String::from_utf8(bytes).map_err(|err| ReadStringError::Utf8(err.utf8_error()))
|
String::from_utf8(bytes).map_err(|err| ReadStringError::Utf8(err.utf8_error()))
|
||||||
}
|
}
|
||||||
|
@ -88,42 +88,42 @@ pub trait ProtoWrite {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn write_u16(&mut self, value: u16) -> Result<(), Self::WriteError> {
|
fn write_u16(&mut self, value: u16) -> Result<(), Self::WriteError> {
|
||||||
let mut bytes = [0; 2];
|
let mut bytes = [0; 2];
|
||||||
NetworkEndian::write_u16(&mut bytes, value);
|
NativeEndian::write_u16(&mut bytes, value);
|
||||||
self.write_all(&bytes)
|
self.write_all(&bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn write_i16(&mut self, value: i16) -> Result<(), Self::WriteError> {
|
fn write_i16(&mut self, value: i16) -> Result<(), Self::WriteError> {
|
||||||
let mut bytes = [0; 2];
|
let mut bytes = [0; 2];
|
||||||
NetworkEndian::write_i16(&mut bytes, value);
|
NativeEndian::write_i16(&mut bytes, value);
|
||||||
self.write_all(&bytes)
|
self.write_all(&bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn write_u32(&mut self, value: u32) -> Result<(), Self::WriteError> {
|
fn write_u32(&mut self, value: u32) -> Result<(), Self::WriteError> {
|
||||||
let mut bytes = [0; 4];
|
let mut bytes = [0; 4];
|
||||||
NetworkEndian::write_u32(&mut bytes, value);
|
NativeEndian::write_u32(&mut bytes, value);
|
||||||
self.write_all(&bytes)
|
self.write_all(&bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn write_i32(&mut self, value: i32) -> Result<(), Self::WriteError> {
|
fn write_i32(&mut self, value: i32) -> Result<(), Self::WriteError> {
|
||||||
let mut bytes = [0; 4];
|
let mut bytes = [0; 4];
|
||||||
NetworkEndian::write_i32(&mut bytes, value);
|
NativeEndian::write_i32(&mut bytes, value);
|
||||||
self.write_all(&bytes)
|
self.write_all(&bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn write_u64(&mut self, value: u64) -> Result<(), Self::WriteError> {
|
fn write_u64(&mut self, value: u64) -> Result<(), Self::WriteError> {
|
||||||
let mut bytes = [0; 8];
|
let mut bytes = [0; 8];
|
||||||
NetworkEndian::write_u64(&mut bytes, value);
|
NativeEndian::write_u64(&mut bytes, value);
|
||||||
self.write_all(&bytes)
|
self.write_all(&bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn write_i64(&mut self, value: i64) -> Result<(), Self::WriteError> {
|
fn write_i64(&mut self, value: i64) -> Result<(), Self::WriteError> {
|
||||||
let mut bytes = [0; 8];
|
let mut bytes = [0; 8];
|
||||||
NetworkEndian::write_i64(&mut bytes, value);
|
NativeEndian::write_i64(&mut bytes, value);
|
||||||
self.write_all(&bytes)
|
self.write_all(&bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![cfg_attr(feature = "alloc", feature(alloc))]
|
|
||||||
|
|
||||||
extern crate failure;
|
extern crate failure;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use core::str::Utf8Error;
|
use core::str::Utf8Error;
|
||||||
use alloc::{Vec, String};
|
use alloc::{vec::Vec, string::String};
|
||||||
#[cfg(feature = "log")]
|
#[cfg(feature = "log")]
|
||||||
use log;
|
use log;
|
||||||
|
|
||||||
|
@ -63,15 +63,6 @@ pub enum Request {
|
||||||
ConfigRemove { key: String },
|
ConfigRemove { key: String },
|
||||||
ConfigErase,
|
ConfigErase,
|
||||||
|
|
||||||
StartProfiler {
|
|
||||||
interval_us: u32,
|
|
||||||
hits_size: u32,
|
|
||||||
edges_size: u32,
|
|
||||||
},
|
|
||||||
StopProfiler,
|
|
||||||
GetProfile,
|
|
||||||
|
|
||||||
Hotswap(Vec<u8>),
|
|
||||||
Reboot,
|
Reboot,
|
||||||
|
|
||||||
DebugAllocator,
|
DebugAllocator,
|
||||||
|
@ -86,8 +77,6 @@ pub enum Reply<'a> {
|
||||||
|
|
||||||
ConfigData(&'a [u8]),
|
ConfigData(&'a [u8]),
|
||||||
|
|
||||||
Profile,
|
|
||||||
|
|
||||||
RebootImminent,
|
RebootImminent,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,15 +119,6 @@ impl Request {
|
||||||
},
|
},
|
||||||
15 => Request::ConfigErase,
|
15 => Request::ConfigErase,
|
||||||
|
|
||||||
9 => Request::StartProfiler {
|
|
||||||
interval_us: reader.read_u32()?,
|
|
||||||
hits_size: reader.read_u32()?,
|
|
||||||
edges_size: reader.read_u32()?,
|
|
||||||
},
|
|
||||||
10 => Request::StopProfiler,
|
|
||||||
11 => Request::GetProfile,
|
|
||||||
|
|
||||||
4 => Request::Hotswap(reader.read_bytes()?),
|
|
||||||
5 => Request::Reboot,
|
5 => Request::Reboot,
|
||||||
|
|
||||||
8 => Request::DebugAllocator,
|
8 => Request::DebugAllocator,
|
||||||
|
@ -174,11 +154,6 @@ impl<'a> Reply<'a> {
|
||||||
writer.write_bytes(bytes)?;
|
writer.write_bytes(bytes)?;
|
||||||
},
|
},
|
||||||
|
|
||||||
Reply::Profile => {
|
|
||||||
writer.write_u8(5)?;
|
|
||||||
// profile data follows
|
|
||||||
}
|
|
||||||
|
|
||||||
Reply::RebootImminent => {
|
Reply::RebootImminent => {
|
||||||
writer.write_u8(3)?;
|
writer.write_u8(3)?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,31 @@
|
||||||
use core::str;
|
use core::str;
|
||||||
use core::slice;
|
use core::slice;
|
||||||
use cslice::{CSlice, CMutSlice};
|
use cslice::{CSlice, CMutSlice};
|
||||||
use byteorder::{NetworkEndian, ByteOrder};
|
use byteorder::{NativeEndian, ByteOrder};
|
||||||
use io::{ProtoRead, Read, Write, ProtoWrite, Error};
|
use io::{ProtoRead, Read, Write, ProtoWrite, Error};
|
||||||
use self::tag::{Tag, TagIterator, split_tag};
|
use self::tag::{Tag, TagIterator, split_tag};
|
||||||
|
|
||||||
|
unsafe fn align_ptr<T>(ptr: *const ()) -> *const T {
|
||||||
|
let alignment = core::mem::align_of::<T>() as isize;
|
||||||
|
let fix = (alignment - (ptr as isize) % alignment) % alignment;
|
||||||
|
((ptr as isize) + fix) as *const T
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn align_ptr_mut<T>(ptr: *mut ()) -> *mut T {
|
||||||
|
let alignment = core::mem::align_of::<T>() as isize;
|
||||||
|
let fix = (alignment - (ptr as isize) % alignment) % alignment;
|
||||||
|
((ptr as isize) + fix) as *mut T
|
||||||
|
}
|
||||||
|
|
||||||
unsafe fn recv_value<R, E>(reader: &mut R, tag: Tag, data: &mut *mut (),
|
unsafe fn recv_value<R, E>(reader: &mut R, tag: Tag, data: &mut *mut (),
|
||||||
alloc: &Fn(usize) -> Result<*mut (), E>)
|
alloc: &dyn Fn(usize) -> Result<*mut (), E>)
|
||||||
-> Result<(), E>
|
-> Result<(), E>
|
||||||
where R: Read + ?Sized,
|
where R: Read + ?Sized,
|
||||||
E: From<Error<R::ReadError>>
|
E: From<Error<R::ReadError>>
|
||||||
{
|
{
|
||||||
macro_rules! consume_value {
|
macro_rules! consume_value {
|
||||||
($ty:ty, |$ptr:ident| $map:expr) => ({
|
($ty:ty, |$ptr:ident| $map:expr) => ({
|
||||||
let $ptr = (*data) as *mut $ty;
|
let $ptr = align_ptr_mut::<$ty>(*data) as *mut $ty;
|
||||||
*data = $ptr.offset(1) as *mut ();
|
*data = $ptr.offset(1) as *mut ();
|
||||||
$map
|
$map
|
||||||
})
|
})
|
||||||
|
@ -51,7 +63,7 @@ unsafe fn recv_value<R, E>(reader: &mut R, tag: Tag, data: &mut *mut (),
|
||||||
}
|
}
|
||||||
Tag::List(it) => {
|
Tag::List(it) => {
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct List { elements: *mut (), length: u32 };
|
struct List { elements: *mut (), length: u32 }
|
||||||
consume_value!(List, |ptr| {
|
consume_value!(List, |ptr| {
|
||||||
(*ptr).length = reader.read_u32()?;
|
(*ptr).length = reader.read_u32()?;
|
||||||
let length = (*ptr).length as usize;
|
let length = (*ptr).length as usize;
|
||||||
|
@ -69,13 +81,13 @@ unsafe fn recv_value<R, E>(reader: &mut R, tag: Tag, data: &mut *mut (),
|
||||||
let dest = slice::from_raw_parts_mut(data as *mut u8, length * 4);
|
let dest = slice::from_raw_parts_mut(data as *mut u8, length * 4);
|
||||||
reader.read_exact(dest)?;
|
reader.read_exact(dest)?;
|
||||||
let dest = slice::from_raw_parts_mut(data as *mut i32, length);
|
let dest = slice::from_raw_parts_mut(data as *mut i32, length);
|
||||||
NetworkEndian::from_slice_i32(dest);
|
NativeEndian::from_slice_i32(dest);
|
||||||
},
|
},
|
||||||
Tag::Int64 | Tag::Float64 => {
|
Tag::Int64 | Tag::Float64 => {
|
||||||
let dest = slice::from_raw_parts_mut(data as *mut u8, length * 8);
|
let dest = slice::from_raw_parts_mut(data as *mut u8, length * 8);
|
||||||
reader.read_exact(dest)?;
|
reader.read_exact(dest)?;
|
||||||
let dest = slice::from_raw_parts_mut(data as *mut i64, length);
|
let dest = slice::from_raw_parts_mut(data as *mut i64, length);
|
||||||
NetworkEndian::from_slice_i64(dest);
|
NativeEndian::from_slice_i64(dest);
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
for _ in 0..length {
|
for _ in 0..length {
|
||||||
|
@ -109,13 +121,13 @@ unsafe fn recv_value<R, E>(reader: &mut R, tag: Tag, data: &mut *mut (),
|
||||||
let dest = slice::from_raw_parts_mut(data as *mut u8, length * 4);
|
let dest = slice::from_raw_parts_mut(data as *mut u8, length * 4);
|
||||||
reader.read_exact(dest)?;
|
reader.read_exact(dest)?;
|
||||||
let dest = slice::from_raw_parts_mut(data as *mut i32, length);
|
let dest = slice::from_raw_parts_mut(data as *mut i32, length);
|
||||||
NetworkEndian::from_slice_i32(dest);
|
NativeEndian::from_slice_i32(dest);
|
||||||
},
|
},
|
||||||
Tag::Int64 | Tag::Float64 => {
|
Tag::Int64 | Tag::Float64 => {
|
||||||
let dest = slice::from_raw_parts_mut(data as *mut u8, length * 8);
|
let dest = slice::from_raw_parts_mut(data as *mut u8, length * 8);
|
||||||
reader.read_exact(dest)?;
|
reader.read_exact(dest)?;
|
||||||
let dest = slice::from_raw_parts_mut(data as *mut i64, length);
|
let dest = slice::from_raw_parts_mut(data as *mut i64, length);
|
||||||
NetworkEndian::from_slice_i64(dest);
|
NativeEndian::from_slice_i64(dest);
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
for _ in 0..length {
|
for _ in 0..length {
|
||||||
|
@ -139,7 +151,7 @@ unsafe fn recv_value<R, E>(reader: &mut R, tag: Tag, data: &mut *mut (),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn recv_return<R, E>(reader: &mut R, tag_bytes: &[u8], data: *mut (),
|
pub fn recv_return<R, E>(reader: &mut R, tag_bytes: &[u8], data: *mut (),
|
||||||
alloc: &Fn(usize) -> Result<*mut (), E>)
|
alloc: &dyn Fn(usize) -> Result<*mut (), E>)
|
||||||
-> Result<(), E>
|
-> Result<(), E>
|
||||||
where R: Read + ?Sized,
|
where R: Read + ?Sized,
|
||||||
E: From<Error<R::ReadError>>
|
E: From<Error<R::ReadError>>
|
||||||
|
@ -161,7 +173,7 @@ unsafe fn send_value<W>(writer: &mut W, tag: Tag, data: &mut *const ())
|
||||||
{
|
{
|
||||||
macro_rules! consume_value {
|
macro_rules! consume_value {
|
||||||
($ty:ty, |$ptr:ident| $map:expr) => ({
|
($ty:ty, |$ptr:ident| $map:expr) => ({
|
||||||
let $ptr = (*data) as *const $ty;
|
let $ptr = align_ptr::<$ty>(*data);
|
||||||
*data = $ptr.offset(1) as *const ();
|
*data = $ptr.offset(1) as *const ();
|
||||||
$map
|
$map
|
||||||
})
|
})
|
||||||
|
@ -196,7 +208,7 @@ unsafe fn send_value<W>(writer: &mut W, tag: Tag, data: &mut *const ())
|
||||||
}
|
}
|
||||||
Tag::List(it) => {
|
Tag::List(it) => {
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct List { elements: *const (), length: u32 };
|
struct List { elements: *const (), length: u32 }
|
||||||
consume_value!(List, |ptr| {
|
consume_value!(List, |ptr| {
|
||||||
let length = (*ptr).length as usize;
|
let length = (*ptr).length as usize;
|
||||||
writer.write_u32((*ptr).length)?;
|
writer.write_u32((*ptr).length)?;
|
||||||
|
@ -204,8 +216,8 @@ unsafe fn send_value<W>(writer: &mut W, tag: Tag, data: &mut *const ())
|
||||||
let mut data = (*ptr).elements;
|
let mut data = (*ptr).elements;
|
||||||
writer.write_u8(tag.as_u8())?;
|
writer.write_u8(tag.as_u8())?;
|
||||||
match tag {
|
match tag {
|
||||||
// we cannot use NetworkEndian::from_slice_i32 as the data is not mutable,
|
// we cannot use NativeEndian::from_slice_i32 as the data is not mutable,
|
||||||
// and that is not needed as the data is already in network endian
|
// and that is not needed as the data is already in native endian
|
||||||
Tag::Bool => {
|
Tag::Bool => {
|
||||||
let slice = slice::from_raw_parts(data as *const u8, length);
|
let slice = slice::from_raw_parts(data as *const u8, length);
|
||||||
writer.write_all(slice)?;
|
writer.write_all(slice)?;
|
||||||
|
@ -243,8 +255,8 @@ unsafe fn send_value<W>(writer: &mut W, tag: Tag, data: &mut *const ())
|
||||||
let mut data = *buffer;
|
let mut data = *buffer;
|
||||||
writer.write_u8(elt_tag.as_u8())?;
|
writer.write_u8(elt_tag.as_u8())?;
|
||||||
match elt_tag {
|
match elt_tag {
|
||||||
// we cannot use NetworkEndian::from_slice_i32 as the data is not mutable,
|
// we cannot use NativeEndian::from_slice_i32 as the data is not mutable,
|
||||||
// and that is not needed as the data is already in network endian
|
// and that is not needed as the data is already in native endian
|
||||||
Tag::Bool => {
|
Tag::Bool => {
|
||||||
let slice = slice::from_raw_parts(data as *const u8, length);
|
let slice = slice::from_raw_parts(data as *const u8, length);
|
||||||
writer.write_all(slice)?;
|
writer.write_all(slice)?;
|
||||||
|
@ -275,7 +287,7 @@ unsafe fn send_value<W>(writer: &mut W, tag: Tag, data: &mut *const ())
|
||||||
}
|
}
|
||||||
Tag::Keyword(it) => {
|
Tag::Keyword(it) => {
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct Keyword<'a> { name: CSlice<'a, u8> };
|
struct Keyword<'a> { name: CSlice<'a, u8> }
|
||||||
consume_value!(Keyword, |ptr| {
|
consume_value!(Keyword, |ptr| {
|
||||||
writer.write_string(str::from_utf8((*ptr).name.as_ref()).unwrap())?;
|
writer.write_string(str::from_utf8((*ptr).name.as_ref()).unwrap())?;
|
||||||
let tag = it.clone().next().expect("truncated tag");
|
let tag = it.clone().next().expect("truncated tag");
|
||||||
|
@ -287,7 +299,7 @@ unsafe fn send_value<W>(writer: &mut W, tag: Tag, data: &mut *const ())
|
||||||
}
|
}
|
||||||
Tag::Object => {
|
Tag::Object => {
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct Object { id: u32 };
|
struct Object { id: u32 }
|
||||||
consume_value!(*const Object, |ptr|
|
consume_value!(*const Object, |ptr|
|
||||||
writer.write_u32((**ptr).id))
|
writer.write_u32((**ptr).id))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use core::str::Utf8Error;
|
use core::str::Utf8Error;
|
||||||
use alloc::{Vec, String};
|
use alloc::{vec::Vec, string::String};
|
||||||
|
|
||||||
use io::{Read, ProtoRead, Write, ProtoWrite, Error as IoError, ReadStringError};
|
use io::{Read, ProtoRead, Write, ProtoWrite, Error as IoError, ReadStringError};
|
||||||
|
|
||||||
|
@ -90,7 +90,9 @@ pub enum Reply<'a> {
|
||||||
LoadCompleted,
|
LoadCompleted,
|
||||||
LoadFailed(&'a str),
|
LoadFailed(&'a str),
|
||||||
|
|
||||||
KernelFinished,
|
KernelFinished {
|
||||||
|
async_errors: u8
|
||||||
|
},
|
||||||
KernelStartupFailed,
|
KernelStartupFailed,
|
||||||
KernelException {
|
KernelException {
|
||||||
name: &'a str,
|
name: &'a str,
|
||||||
|
@ -100,7 +102,8 @@ pub enum Reply<'a> {
|
||||||
line: u32,
|
line: u32,
|
||||||
column: u32,
|
column: u32,
|
||||||
function: &'a str,
|
function: &'a str,
|
||||||
backtrace: &'a [usize]
|
backtrace: &'a [usize],
|
||||||
|
async_errors: u8
|
||||||
},
|
},
|
||||||
|
|
||||||
RpcRequest { async: bool },
|
RpcRequest { async: bool },
|
||||||
|
@ -160,14 +163,16 @@ impl<'a> Reply<'a> {
|
||||||
writer.write_string(reason)?;
|
writer.write_string(reason)?;
|
||||||
},
|
},
|
||||||
|
|
||||||
Reply::KernelFinished => {
|
Reply::KernelFinished { async_errors } => {
|
||||||
writer.write_u8(7)?;
|
writer.write_u8(7)?;
|
||||||
|
writer.write_u8(async_errors)?;
|
||||||
},
|
},
|
||||||
Reply::KernelStartupFailed => {
|
Reply::KernelStartupFailed => {
|
||||||
writer.write_u8(8)?;
|
writer.write_u8(8)?;
|
||||||
},
|
},
|
||||||
Reply::KernelException {
|
Reply::KernelException {
|
||||||
name, message, param, file, line, column, function, backtrace
|
name, message, param, file, line, column, function, backtrace,
|
||||||
|
async_errors
|
||||||
} => {
|
} => {
|
||||||
writer.write_u8(9)?;
|
writer.write_u8(9)?;
|
||||||
writer.write_string(name)?;
|
writer.write_string(name)?;
|
||||||
|
@ -183,6 +188,7 @@ impl<'a> Reply<'a> {
|
||||||
for &addr in backtrace {
|
for &addr in backtrace {
|
||||||
writer.write_u32(addr as u32)?
|
writer.write_u32(addr as u32)?
|
||||||
}
|
}
|
||||||
|
writer.write_u8(async_errors)?;
|
||||||
},
|
},
|
||||||
|
|
||||||
Reply::RpcRequest { async } => {
|
Reply::RpcRequest { async } => {
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
[package]
|
||||||
|
authors = ["The Rust Project Developers"]
|
||||||
|
name = "unwind"
|
||||||
|
version = "0.0.0"
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
repository = "https://github.com/rust-lang/rust.git"
|
||||||
|
edition = "2018"
|
||||||
|
include = [
|
||||||
|
'/libunwind/*',
|
||||||
|
]
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
test = false
|
||||||
|
bench = false
|
||||||
|
doc = false
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
libc = { path = "../libc" }
|
||||||
|
cfg-if = "0.1.8"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
|
||||||
|
# Only applies for Linux and Fuchsia targets
|
||||||
|
# Static link to the in-tree build of llvm libunwind
|
||||||
|
llvm-libunwind = []
|
||||||
|
|
||||||
|
# Only applies for Linux and Fuchsia targets
|
||||||
|
# If crt-static is enabled, static link to `libunwind.a` provided by system
|
||||||
|
# If crt-static is disabled, dynamic link to `libunwind.so` provided by system
|
||||||
|
system-llvm-libunwind = []
|
|
@ -0,0 +1,11 @@
|
||||||
|
#![no_std]
|
||||||
|
#![unstable(feature = "panic_unwind", issue = "32837")]
|
||||||
|
#![feature(link_cfg)]
|
||||||
|
#![feature(nll)]
|
||||||
|
#![feature(staged_api)]
|
||||||
|
#![feature(unwind_attributes)]
|
||||||
|
#![feature(static_nobundle)]
|
||||||
|
#![cfg_attr(not(target_env = "msvc"), feature(libc))]
|
||||||
|
|
||||||
|
mod libunwind;
|
||||||
|
pub use libunwind::*;
|
|
@ -0,0 +1,282 @@
|
||||||
|
#![allow(nonstandard_style)]
|
||||||
|
|
||||||
|
use libc::{c_int, c_void, uintptr_t};
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
|
pub enum _Unwind_Reason_Code {
|
||||||
|
_URC_NO_REASON = 0,
|
||||||
|
_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
|
||||||
|
_URC_FATAL_PHASE2_ERROR = 2,
|
||||||
|
_URC_FATAL_PHASE1_ERROR = 3,
|
||||||
|
_URC_NORMAL_STOP = 4,
|
||||||
|
_URC_END_OF_STACK = 5,
|
||||||
|
_URC_HANDLER_FOUND = 6,
|
||||||
|
_URC_INSTALL_CONTEXT = 7,
|
||||||
|
_URC_CONTINUE_UNWIND = 8,
|
||||||
|
_URC_FAILURE = 9, // used only by ARM EHABI
|
||||||
|
}
|
||||||
|
pub use _Unwind_Reason_Code::*;
|
||||||
|
|
||||||
|
pub type _Unwind_Exception_Class = u64;
|
||||||
|
pub type _Unwind_Word = uintptr_t;
|
||||||
|
pub type _Unwind_Ptr = uintptr_t;
|
||||||
|
pub type _Unwind_Trace_Fn =
|
||||||
|
extern "C" fn(ctx: *mut _Unwind_Context, arg: *mut c_void) -> _Unwind_Reason_Code;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86")]
|
||||||
|
pub const unwinder_private_data_size: usize = 5;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
pub const unwinder_private_data_size: usize = 6;
|
||||||
|
|
||||||
|
#[cfg(all(target_arch = "arm", not(target_os = "ios")))]
|
||||||
|
pub const unwinder_private_data_size: usize = 20;
|
||||||
|
|
||||||
|
#[cfg(all(target_arch = "arm", target_os = "ios"))]
|
||||||
|
pub const unwinder_private_data_size: usize = 5;
|
||||||
|
|
||||||
|
#[cfg(all(target_arch = "aarch64", target_pointer_width = "64"))]
|
||||||
|
pub const unwinder_private_data_size: usize = 2;
|
||||||
|
|
||||||
|
#[cfg(all(target_arch = "aarch64", target_pointer_width = "32"))]
|
||||||
|
pub const unwinder_private_data_size: usize = 5;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "mips")]
|
||||||
|
pub const unwinder_private_data_size: usize = 2;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "mips64")]
|
||||||
|
pub const unwinder_private_data_size: usize = 2;
|
||||||
|
|
||||||
|
#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
|
||||||
|
pub const unwinder_private_data_size: usize = 2;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "s390x")]
|
||||||
|
pub const unwinder_private_data_size: usize = 2;
|
||||||
|
|
||||||
|
#[cfg(any(target_arch = "sparc", target_arch = "sparc64"))]
|
||||||
|
pub const unwinder_private_data_size: usize = 2;
|
||||||
|
|
||||||
|
#[cfg(any(target_arch = "riscv64", target_arch = "riscv32"))]
|
||||||
|
pub const unwinder_private_data_size: usize = 2;
|
||||||
|
|
||||||
|
#[cfg(target_os = "emscripten")]
|
||||||
|
pub const unwinder_private_data_size: usize = 20;
|
||||||
|
|
||||||
|
#[cfg(all(target_arch = "hexagon", target_os = "linux"))]
|
||||||
|
pub const unwinder_private_data_size: usize = 35;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct _Unwind_Exception {
|
||||||
|
pub exception_class: _Unwind_Exception_Class,
|
||||||
|
pub exception_cleanup: _Unwind_Exception_Cleanup_Fn,
|
||||||
|
pub private: [_Unwind_Word; unwinder_private_data_size],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum _Unwind_Context {}
|
||||||
|
|
||||||
|
pub type _Unwind_Exception_Cleanup_Fn =
|
||||||
|
extern "C" fn(unwind_code: _Unwind_Reason_Code, exception: *mut _Unwind_Exception);
|
||||||
|
#[cfg_attr(
|
||||||
|
all(feature = "llvm-libunwind", any(target_os = "fuchsia", target_os = "linux")),
|
||||||
|
link(name = "unwind", kind = "static")
|
||||||
|
)]
|
||||||
|
extern "C" {
|
||||||
|
#[unwind(allowed)]
|
||||||
|
pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !;
|
||||||
|
pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception);
|
||||||
|
pub fn _Unwind_GetLanguageSpecificData(ctx: *mut _Unwind_Context) -> *mut c_void;
|
||||||
|
pub fn _Unwind_GetRegionStart(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
|
||||||
|
pub fn _Unwind_GetTextRelBase(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
|
||||||
|
pub fn _Unwind_GetDataRelBase(ctx: *mut _Unwind_Context) -> _Unwind_Ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(any(target_os = "ios", target_os = "netbsd", not(target_arch = "arm")))] {
|
||||||
|
// Not ARM EHABI
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
|
pub enum _Unwind_Action {
|
||||||
|
_UA_SEARCH_PHASE = 1,
|
||||||
|
_UA_CLEANUP_PHASE = 2,
|
||||||
|
_UA_HANDLER_FRAME = 4,
|
||||||
|
_UA_FORCE_UNWIND = 8,
|
||||||
|
_UA_END_OF_STACK = 16,
|
||||||
|
}
|
||||||
|
pub use _Unwind_Action::*;
|
||||||
|
|
||||||
|
#[cfg_attr(all(feature = "llvm-libunwind",
|
||||||
|
any(target_os = "fuchsia", target_os = "linux")),
|
||||||
|
link(name = "unwind", kind = "static"))]
|
||||||
|
extern "C" {
|
||||||
|
pub fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word;
|
||||||
|
pub fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word);
|
||||||
|
pub fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> _Unwind_Word;
|
||||||
|
pub fn _Unwind_SetIP(ctx: *mut _Unwind_Context, value: _Unwind_Word);
|
||||||
|
pub fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context, ip_before_insn: *mut c_int)
|
||||||
|
-> _Unwind_Word;
|
||||||
|
pub fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// ARM EHABI
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
|
pub enum _Unwind_State {
|
||||||
|
_US_VIRTUAL_UNWIND_FRAME = 0,
|
||||||
|
_US_UNWIND_FRAME_STARTING = 1,
|
||||||
|
_US_UNWIND_FRAME_RESUME = 2,
|
||||||
|
_US_ACTION_MASK = 3,
|
||||||
|
_US_FORCE_UNWIND = 8,
|
||||||
|
_US_END_OF_STACK = 16,
|
||||||
|
}
|
||||||
|
pub use _Unwind_State::*;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
enum _Unwind_VRS_Result {
|
||||||
|
_UVRSR_OK = 0,
|
||||||
|
_UVRSR_NOT_IMPLEMENTED = 1,
|
||||||
|
_UVRSR_FAILED = 2,
|
||||||
|
}
|
||||||
|
#[repr(C)]
|
||||||
|
enum _Unwind_VRS_RegClass {
|
||||||
|
_UVRSC_CORE = 0,
|
||||||
|
_UVRSC_VFP = 1,
|
||||||
|
_UVRSC_FPA = 2,
|
||||||
|
_UVRSC_WMMXD = 3,
|
||||||
|
_UVRSC_WMMXC = 4,
|
||||||
|
}
|
||||||
|
use _Unwind_VRS_RegClass::*;
|
||||||
|
#[repr(C)]
|
||||||
|
enum _Unwind_VRS_DataRepresentation {
|
||||||
|
_UVRSD_UINT32 = 0,
|
||||||
|
_UVRSD_VFPX = 1,
|
||||||
|
_UVRSD_FPAX = 2,
|
||||||
|
_UVRSD_UINT64 = 3,
|
||||||
|
_UVRSD_FLOAT = 4,
|
||||||
|
_UVRSD_DOUBLE = 5,
|
||||||
|
}
|
||||||
|
use _Unwind_VRS_DataRepresentation::*;
|
||||||
|
|
||||||
|
pub const UNWIND_POINTER_REG: c_int = 12;
|
||||||
|
pub const UNWIND_SP_REG: c_int = 13;
|
||||||
|
pub const UNWIND_IP_REG: c_int = 15;
|
||||||
|
|
||||||
|
#[cfg_attr(all(feature = "llvm-libunwind",
|
||||||
|
any(target_os = "fuchsia", target_os = "linux")),
|
||||||
|
link(name = "unwind", kind = "static"))]
|
||||||
|
extern "C" {
|
||||||
|
fn _Unwind_VRS_Get(ctx: *mut _Unwind_Context,
|
||||||
|
regclass: _Unwind_VRS_RegClass,
|
||||||
|
regno: _Unwind_Word,
|
||||||
|
repr: _Unwind_VRS_DataRepresentation,
|
||||||
|
data: *mut c_void)
|
||||||
|
-> _Unwind_VRS_Result;
|
||||||
|
|
||||||
|
fn _Unwind_VRS_Set(ctx: *mut _Unwind_Context,
|
||||||
|
regclass: _Unwind_VRS_RegClass,
|
||||||
|
regno: _Unwind_Word,
|
||||||
|
repr: _Unwind_VRS_DataRepresentation,
|
||||||
|
data: *mut c_void)
|
||||||
|
-> _Unwind_VRS_Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// On Android or ARM/Linux, these are implemented as macros:
|
||||||
|
|
||||||
|
pub unsafe fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word {
|
||||||
|
let mut val: _Unwind_Word = 0;
|
||||||
|
_Unwind_VRS_Get(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32,
|
||||||
|
&mut val as *mut _ as *mut c_void);
|
||||||
|
val
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word) {
|
||||||
|
let mut value = value;
|
||||||
|
_Unwind_VRS_Set(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32,
|
||||||
|
&mut value as *mut _ as *mut c_void);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context)
|
||||||
|
-> _Unwind_Word {
|
||||||
|
let val = _Unwind_GetGR(ctx, UNWIND_IP_REG);
|
||||||
|
(val & !1) as _Unwind_Word
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn _Unwind_SetIP(ctx: *mut _Unwind_Context,
|
||||||
|
value: _Unwind_Word) {
|
||||||
|
// Propagate thumb bit to instruction pointer
|
||||||
|
let thumb_state = _Unwind_GetGR(ctx, UNWIND_IP_REG) & 1;
|
||||||
|
let value = value | thumb_state;
|
||||||
|
_Unwind_SetGR(ctx, UNWIND_IP_REG, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn _Unwind_GetIPInfo(ctx: *mut _Unwind_Context,
|
||||||
|
ip_before_insn: *mut c_int)
|
||||||
|
-> _Unwind_Word {
|
||||||
|
*ip_before_insn = 0;
|
||||||
|
_Unwind_GetIP(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function also doesn't exist on Android or ARM/Linux, so make it a no-op
|
||||||
|
pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut c_void) -> *mut c_void {
|
||||||
|
pc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // cfg_if!
|
||||||
|
|
||||||
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] {
|
||||||
|
// Not 32-bit iOS
|
||||||
|
#[cfg_attr(all(feature = "llvm-libunwind",
|
||||||
|
any(target_os = "fuchsia", target_os = "linux")),
|
||||||
|
link(name = "unwind", kind = "static"))]
|
||||||
|
extern "C" {
|
||||||
|
#[unwind(allowed)]
|
||||||
|
pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
|
||||||
|
pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
|
||||||
|
trace_argument: *mut c_void)
|
||||||
|
-> _Unwind_Reason_Code;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 32-bit iOS uses SjLj and does not provide _Unwind_Backtrace()
|
||||||
|
#[cfg_attr(all(feature = "llvm-libunwind",
|
||||||
|
any(target_os = "fuchsia", target_os = "linux")),
|
||||||
|
link(name = "unwind", kind = "static"))]
|
||||||
|
extern "C" {
|
||||||
|
#[unwind(allowed)]
|
||||||
|
pub fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn _Unwind_RaiseException(exc: *mut _Unwind_Exception) -> _Unwind_Reason_Code {
|
||||||
|
_Unwind_SjLj_RaiseException(exc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // cfg_if!
|
||||||
|
|
||||||
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(all(windows, target_arch = "x86_64", target_env = "gnu"))] {
|
||||||
|
// We declare these as opaque types. This is fine since you just need to
|
||||||
|
// pass them to _GCC_specific_handler and forget about them.
|
||||||
|
pub enum EXCEPTION_RECORD {}
|
||||||
|
pub type LPVOID = *mut c_void;
|
||||||
|
pub enum CONTEXT {}
|
||||||
|
pub enum DISPATCHER_CONTEXT {}
|
||||||
|
pub type EXCEPTION_DISPOSITION = c_int;
|
||||||
|
type PersonalityFn = unsafe extern "C" fn(version: c_int,
|
||||||
|
actions: _Unwind_Action,
|
||||||
|
exception_class: _Unwind_Exception_Class,
|
||||||
|
exception_object: *mut _Unwind_Exception,
|
||||||
|
context: *mut _Unwind_Context)
|
||||||
|
-> _Unwind_Reason_Code;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
pub fn _GCC_specific_handler(exceptionRecord: *mut EXCEPTION_RECORD,
|
||||||
|
establisherFrame: LPVOID,
|
||||||
|
contextRecord: *mut CONTEXT,
|
||||||
|
dispatcherContext: *mut DISPATCHER_CONTEXT,
|
||||||
|
personality: PersonalityFn)
|
||||||
|
-> EXCEPTION_DISPOSITION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // cfg_if!
|
|
@ -6,3 +6,7 @@ version = "0.0.0"
|
||||||
[lib]
|
[lib]
|
||||||
name = "unwind_backtrace"
|
name = "unwind_backtrace"
|
||||||
path = "lib.rs"
|
path = "lib.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
unwind = { path = "../libunwind" }
|
||||||
|
libc = { path = "../libc" }
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
{
|
||||||
|
"arch": "riscv32",
|
||||||
|
"code-model": "medium",
|
||||||
|
"cpu": "generic-rv32",
|
||||||
|
"crt-static-respected": true,
|
||||||
|
"data-layout": "e-m:e-p:32:32-i64:64-n32-S128",
|
||||||
|
"dynamic-linking": true,
|
||||||
|
"executables": true,
|
||||||
|
"features": "+m,+a,+f,+d",
|
||||||
|
"has-elf-tls": true,
|
||||||
|
"has-rpath": true,
|
||||||
|
"llvm-abiname": "ilp32d",
|
||||||
|
"llvm-target": "riscv32-unknown-linux",
|
||||||
|
"max-atomic-width": 32,
|
||||||
|
"position-independent-executables": true,
|
||||||
|
"pre-link-args": {
|
||||||
|
"gcc": [
|
||||||
|
"-Wl,--as-needed",
|
||||||
|
"-Wl,-z,noexecstack"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"relro-level": "full",
|
||||||
|
"target-family": "unix",
|
||||||
|
"target-pointer-width": "32",
|
||||||
|
"unsupported-abis": [
|
||||||
|
"cdecl",
|
||||||
|
"stdcall",
|
||||||
|
"fastcall",
|
||||||
|
"vectorcall",
|
||||||
|
"thiscall",
|
||||||
|
"aapcs",
|
||||||
|
"win64",
|
||||||
|
"sysv64",
|
||||||
|
"ptx-kernel",
|
||||||
|
"msp430-interrupt",
|
||||||
|
"x86-interrupt",
|
||||||
|
"amdgpu-kernel"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
{
|
||||||
|
"arch": "riscv32",
|
||||||
|
"cpu": "generic-rv32",
|
||||||
|
"data-layout": "e-m:e-p:32:32-i64:64-n32-S128",
|
||||||
|
"eh-frame-header": false,
|
||||||
|
"emit-debug-gdb-scripts": false,
|
||||||
|
"executables": true,
|
||||||
|
"features": "+m,+a,-c",
|
||||||
|
"is-builtin": false,
|
||||||
|
"linker": "rust-lld",
|
||||||
|
"linker-flavor": "ld.lld",
|
||||||
|
"llvm-target": "riscv32",
|
||||||
|
"max-atomic-width": 32,
|
||||||
|
"panic-strategy": "unwind",
|
||||||
|
"relocation-model": "static",
|
||||||
|
"target-pointer-width": "32",
|
||||||
|
"unsupported-abis": [
|
||||||
|
"cdecl",
|
||||||
|
"stdcall",
|
||||||
|
"fastcall",
|
||||||
|
"vectorcall",
|
||||||
|
"thiscall",
|
||||||
|
"aapcs",
|
||||||
|
"win64",
|
||||||
|
"sysv64",
|
||||||
|
"ptx-kernel",
|
||||||
|
"msp430-interrupt",
|
||||||
|
"x86-interrupt",
|
||||||
|
"amdgpu-kernel"
|
||||||
|
]
|
||||||
|
}
|
|
@ -18,7 +18,7 @@ failure_derive = { version = "0.1", default-features = false }
|
||||||
byteorder = { version = "1.0", default-features = false }
|
byteorder = { version = "1.0", default-features = false }
|
||||||
cslice = { version = "0.3" }
|
cslice = { version = "0.3" }
|
||||||
log = { version = "0.4", default-features = false }
|
log = { version = "0.4", default-features = false }
|
||||||
managed = { version = "= 0.7.0", default-features = false, features = ["alloc", "map"] }
|
managed = { version = "^0.7.1", default-features = false, features = ["alloc", "map"] }
|
||||||
eh = { path = "../libeh" }
|
eh = { path = "../libeh" }
|
||||||
unwind_backtrace = { path = "../libunwind_backtrace" }
|
unwind_backtrace = { path = "../libunwind_backtrace" }
|
||||||
io = { path = "../libio", features = ["byteorder"] }
|
io = { path = "../libio", features = ["byteorder"] }
|
||||||
|
@ -27,10 +27,11 @@ board_misoc = { path = "../libboard_misoc", features = ["uart_console", "smoltcp
|
||||||
logger_artiq = { path = "../liblogger_artiq" }
|
logger_artiq = { path = "../liblogger_artiq" }
|
||||||
board_artiq = { path = "../libboard_artiq" }
|
board_artiq = { path = "../libboard_artiq" }
|
||||||
proto_artiq = { path = "../libproto_artiq", features = ["log", "alloc"] }
|
proto_artiq = { path = "../libproto_artiq", features = ["log", "alloc"] }
|
||||||
smoltcp = { version = "0.6.0", default-features = false, features = ["rust-1_28", "alloc", "ethernet", "proto-ipv4", "proto-ipv6", "socket-tcp"] }
|
smoltcp = { version = "0.6.0", default-features = false, features = ["alloc", "ethernet", "proto-ipv4", "proto-ipv6", "socket-tcp"] }
|
||||||
|
riscv = { version = "0.6.0", features = ["inline-asm"] }
|
||||||
|
|
||||||
[dependencies.fringe]
|
[dependencies.fringe]
|
||||||
git = "https://github.com/m-labs/libfringe"
|
git = "https://git.m-labs.hk/M-Labs/libfringe.git"
|
||||||
rev = "b8a6d8f"
|
rev = "3ecbe5"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["alloc"]
|
features = ["alloc"]
|
||||||
|
|
|
@ -10,21 +10,25 @@ LDFLAGS += \
|
||||||
|
|
||||||
RUSTFLAGS += -Cpanic=unwind
|
RUSTFLAGS += -Cpanic=unwind
|
||||||
|
|
||||||
|
export XBUILD_SYSROOT_PATH=$(BUILDINC_DIRECTORY)/../sysroot
|
||||||
|
|
||||||
all:: runtime.bin runtime.fbi
|
all:: runtime.bin runtime.fbi
|
||||||
|
|
||||||
.PHONY: $(RUSTOUT)/libruntime.a
|
.PHONY: $(RUSTOUT)/libruntime.a
|
||||||
$(RUSTOUT)/libruntime.a:
|
$(RUSTOUT)/libruntime.a:
|
||||||
$(cargo) --manifest-path $(RUNTIME_DIRECTORY)/Cargo.toml
|
$(cargo) --target-dir ./cargo \
|
||||||
|
--manifest-path $(RUNTIME_DIRECTORY)/Cargo.toml \
|
||||||
|
--target $(RUNTIME_DIRECTORY)/../$(CARGO_TRIPLE).json
|
||||||
|
|
||||||
runtime.elf: $(RUSTOUT)/libruntime.a ksupport_data.o
|
runtime.elf: $(RUSTOUT)/libruntime.a ksupport_data.o
|
||||||
$(link) -T $(RUNTIME_DIRECTORY)/runtime.ld \
|
$(link) -T $(RUNTIME_DIRECTORY)/runtime.ld \
|
||||||
-lunwind-bare
|
-lunwind-bare -m elf32lriscv
|
||||||
|
|
||||||
ksupport_data.o: ../ksupport/ksupport.elf
|
ksupport_data.o: ../ksupport/ksupport.elf
|
||||||
$(LD) -r -b binary -o $@ $<
|
$(LD) -r -m elf32lriscv -b binary -o $@ $<
|
||||||
|
|
||||||
%.bin: %.elf
|
%.bin: %.elf
|
||||||
$(objcopy) -O binary
|
$(objcopy) -O binary
|
||||||
|
|
||||||
%.fbi: %.bin
|
%.fbi: %.bin
|
||||||
$(mscimg) -f
|
$(mscimg) -f --little
|
||||||
|
|
|
@ -51,7 +51,7 @@ fn worker(stream: &mut TcpStream) -> Result<(), IoError<SchedError>> {
|
||||||
};
|
};
|
||||||
debug!("{:?}", header);
|
debug!("{:?}", header);
|
||||||
|
|
||||||
stream.write_all("E".as_bytes())?;
|
stream.write_all("e".as_bytes())?;
|
||||||
header.write_to(stream)?;
|
header.write_to(stream)?;
|
||||||
if wraparound {
|
if wraparound {
|
||||||
stream.write_all(&data[pointer..])?;
|
stream.write_all(&data[pointer..])?;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use alloc::{Vec, String, BTreeMap};
|
use alloc::{vec::Vec, string::String, collections::btree_map::BTreeMap};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Entry {
|
struct Entry {
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
#![feature(lang_items, alloc, try_from, nonzero, asm,
|
#![feature(lang_items, panic_info_message)]
|
||||||
panic_implementation, panic_info_message,
|
|
||||||
const_slice_len)]
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
extern crate eh;
|
extern crate eh;
|
||||||
|
@ -25,12 +23,13 @@ extern crate board_misoc;
|
||||||
extern crate board_artiq;
|
extern crate board_artiq;
|
||||||
extern crate logger_artiq;
|
extern crate logger_artiq;
|
||||||
extern crate proto_artiq;
|
extern crate proto_artiq;
|
||||||
|
extern crate riscv;
|
||||||
|
|
||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
use core::convert::TryFrom;
|
use core::convert::TryFrom;
|
||||||
use smoltcp::wire::IpCidr;
|
use smoltcp::wire::IpCidr;
|
||||||
|
|
||||||
use board_misoc::{csr, irq, ident, clock, boot, config, net_settings};
|
use board_misoc::{csr, ident, clock, spiflash, config, net_settings, pmp, boot};
|
||||||
#[cfg(has_ethmac)]
|
#[cfg(has_ethmac)]
|
||||||
use board_misoc::ethmac;
|
use board_misoc::ethmac;
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
|
@ -41,6 +40,8 @@ use proto_artiq::{mgmt_proto, moninj_proto, rpc_proto, session_proto, kernel_pro
|
||||||
#[cfg(has_rtio_analyzer)]
|
#[cfg(has_rtio_analyzer)]
|
||||||
use proto_artiq::analyzer_proto;
|
use proto_artiq::analyzer_proto;
|
||||||
|
|
||||||
|
use riscv::register::{mcause, mepc, mtval};
|
||||||
|
|
||||||
mod rtio_clocking;
|
mod rtio_clocking;
|
||||||
mod rtio_mgt;
|
mod rtio_mgt;
|
||||||
|
|
||||||
|
@ -50,7 +51,6 @@ mod cache;
|
||||||
mod rtio_dma;
|
mod rtio_dma;
|
||||||
|
|
||||||
mod mgmt;
|
mod mgmt;
|
||||||
mod profiler;
|
|
||||||
mod kernel;
|
mod kernel;
|
||||||
mod kern_hwreq;
|
mod kern_hwreq;
|
||||||
mod session;
|
mod session;
|
||||||
|
@ -88,8 +88,6 @@ fn setup_log_levels() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn startup() {
|
fn startup() {
|
||||||
irq::set_mask(0);
|
|
||||||
irq::set_ie(true);
|
|
||||||
clock::init();
|
clock::init();
|
||||||
info!("ARTIQ runtime starting...");
|
info!("ARTIQ runtime starting...");
|
||||||
info!("software ident {}", csr::CONFIG_IDENTIFIER_STR);
|
info!("software ident {}", csr::CONFIG_IDENTIFIER_STR);
|
||||||
|
@ -145,7 +143,7 @@ fn startup() {
|
||||||
};
|
};
|
||||||
|
|
||||||
let neighbor_cache =
|
let neighbor_cache =
|
||||||
smoltcp::iface::NeighborCache::new(alloc::btree_map::BTreeMap::new());
|
smoltcp::iface::NeighborCache::new(alloc::collections::btree_map::BTreeMap::new());
|
||||||
let net_addresses = net_settings::get_adresses();
|
let net_addresses = net_settings::get_adresses();
|
||||||
info!("network addresses: {}", net_addresses);
|
info!("network addresses: {}", net_addresses);
|
||||||
let mut interface = match net_addresses.ipv6_addr {
|
let mut interface = match net_addresses.ipv6_addr {
|
||||||
|
@ -249,29 +247,64 @@ pub extern fn main() -> i32 {
|
||||||
extern {
|
extern {
|
||||||
static mut _fheap: u8;
|
static mut _fheap: u8;
|
||||||
static mut _eheap: u8;
|
static mut _eheap: u8;
|
||||||
|
static mut _sstack_guard: u8;
|
||||||
}
|
}
|
||||||
ALLOC.add_range(&mut _fheap, &mut _eheap);
|
ALLOC.add_range(&mut _fheap, &mut _eheap);
|
||||||
|
|
||||||
logger_artiq::BufferLogger::new(&mut LOG_BUFFER[..]).register(startup);
|
pmp::init_stack_guard(&_sstack_guard as *const u8 as usize);
|
||||||
|
|
||||||
|
logger_artiq::BufferLogger::new(&mut LOG_BUFFER[..]).register(||
|
||||||
|
boot::start_user(startup as usize)
|
||||||
|
);
|
||||||
|
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub extern fn exception(vect: u32, _regs: *const u32, pc: u32, ea: u32) {
|
#[repr(C)]
|
||||||
let vect = irq::Exception::try_from(vect).expect("unknown exception");
|
pub struct TrapFrame {
|
||||||
match vect {
|
pub ra: usize,
|
||||||
irq::Exception::Interrupt =>
|
pub t0: usize,
|
||||||
while irq::pending_mask() != 0 {
|
pub t1: usize,
|
||||||
match () {
|
pub t2: usize,
|
||||||
#[cfg(has_timer1)]
|
pub t3: usize,
|
||||||
() if irq::is_pending(csr::TIMER1_INTERRUPT) =>
|
pub t4: usize,
|
||||||
profiler::sample(pc as usize),
|
pub t5: usize,
|
||||||
_ => panic!("spurious irq {}", irq::pending_mask().trailing_zeros())
|
pub t6: usize,
|
||||||
|
pub a0: usize,
|
||||||
|
pub a1: usize,
|
||||||
|
pub a2: usize,
|
||||||
|
pub a3: usize,
|
||||||
|
pub a4: usize,
|
||||||
|
pub a5: usize,
|
||||||
|
pub a6: usize,
|
||||||
|
pub a7: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern fn exception(regs: *const TrapFrame) {
|
||||||
|
let pc = mepc::read();
|
||||||
|
let cause = mcause::read().cause();
|
||||||
|
match cause {
|
||||||
|
mcause::Trap::Interrupt(source) => {
|
||||||
|
info!("Called interrupt with {:?}", source);
|
||||||
},
|
},
|
||||||
_ => {
|
|
||||||
|
mcause::Trap::Exception(mcause::Exception::UserEnvCall) => {
|
||||||
|
unsafe {
|
||||||
|
if (*regs).a7 == 0 {
|
||||||
|
pmp::pop_pmp_region()
|
||||||
|
} else {
|
||||||
|
pmp::push_pmp_region((*regs).a7)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mepc::write(pc + 4);
|
||||||
|
},
|
||||||
|
|
||||||
|
mcause::Trap::Exception(e) => {
|
||||||
|
println!("Trap frame: {:x?}", unsafe { *regs });
|
||||||
|
|
||||||
fn hexdump(addr: u32) {
|
fn hexdump(addr: u32) {
|
||||||
let addr = (addr - addr % 4) as *const u32;
|
let addr = (addr - addr % 4) as *const u32;
|
||||||
let mut ptr = addr;
|
let mut ptr = addr;
|
||||||
|
@ -285,9 +318,9 @@ pub extern fn exception(vect: u32, _regs: *const u32, pc: u32, ea: u32) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hexdump(pc);
|
hexdump(u32::try_from(pc).unwrap());
|
||||||
hexdump(ea);
|
let mtval = mtval::read();
|
||||||
panic!("exception {:?} at PC 0x{:x}, EA 0x{:x}", vect, pc, ea)
|
panic!("exception {:?} at PC 0x{:x}, trap value 0x{:x}", e, u32::try_from(pc).unwrap(), mtval)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -305,10 +338,8 @@ pub fn oom(layout: core::alloc::Layout) -> ! {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle] // https://github.com/rust-lang/rust/issues/{38281,51647}
|
#[no_mangle] // https://github.com/rust-lang/rust/issues/{38281,51647}
|
||||||
#[panic_implementation]
|
#[panic_handler]
|
||||||
pub fn panic_impl(info: &core::panic::PanicInfo) -> ! {
|
pub fn panic_impl(info: &core::panic::PanicInfo) -> ! {
|
||||||
irq::set_ie(false);
|
|
||||||
|
|
||||||
#[cfg(has_error_led)]
|
#[cfg(has_error_led)]
|
||||||
unsafe {
|
unsafe {
|
||||||
csr::error_led::out_write(1);
|
csr::error_led::out_write(1);
|
||||||
|
@ -327,16 +358,17 @@ pub fn panic_impl(info: &core::panic::PanicInfo) -> ! {
|
||||||
|
|
||||||
println!("backtrace for software version {}:", csr::CONFIG_IDENTIFIER_STR);
|
println!("backtrace for software version {}:", csr::CONFIG_IDENTIFIER_STR);
|
||||||
let _ = unwind_backtrace::backtrace(|ip| {
|
let _ = unwind_backtrace::backtrace(|ip| {
|
||||||
// Backtrace gives us the return address, i.e. the address after the delay slot,
|
// Backtrace gives us the return address, i.e. the address after jal(r) insn,
|
||||||
// but we're interested in the call instruction.
|
// but we're interested in the call instruction.
|
||||||
println!("{:#08x}", ip - 2 * 4);
|
println!("{:#08x}", ip - 4);
|
||||||
});
|
});
|
||||||
|
|
||||||
if config::read_str("panic_reset", |r| r == Ok("1")) {
|
if config::read_str("panic_reset", |r| r == Ok("1")) &&
|
||||||
|
cfg!(any(soc_platform = "kasli", soc_platform = "metlino", soc_platform = "kc705")) {
|
||||||
println!("restarting...");
|
println!("restarting...");
|
||||||
unsafe {
|
unsafe {
|
||||||
kernel::stop();
|
kernel::stop();
|
||||||
boot::reset();
|
spiflash::reload();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
println!("halting.");
|
println!("halting.");
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue