Coredevice Input Validation (#1447)

* Input validation and masking of SI -> mu conversions (close #1446)

Signed-off-by: Marius Weber <marius.weber@physics.ox.ac.uk>

* Update RELEASE_NOTES

Signed-off-by: Marius Weber <marius.weber@physics.ox.ac.uk>

Co-authored-by: Robert Jördens <rj@quartiq.de>
This commit is contained in:
Marius Weber 2020-05-17 14:09:11 +01:00 committed by GitHub
parent b3b6cb8efe
commit 2538840756
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 35 additions and 21 deletions

View File

@ -11,6 +11,7 @@ Highlights:
* Performance improvements: * Performance improvements:
- #1432: SERDES TTL inputs can now detect edges on pulses that are shorter - #1432: SERDES TTL inputs can now detect edges on pulses that are shorter
than the RTIO period than the RTIO period
* Coredevice SI to mu conversions now always return valid codes, or raise a `ValueError`.
* Zotino now exposes `voltage_to_mu()` * Zotino now exposes `voltage_to_mu()`
Breaking changes: Breaking changes:

View File

@ -553,7 +553,7 @@ class AD9910:
@portable(flags={"fast-math"}) @portable(flags={"fast-math"})
def frequency_to_ftw(self, frequency): def frequency_to_ftw(self, frequency):
"""Return the frequency tuning word corresponding to the given """Return the 32-bit frequency tuning word corresponding to the given
frequency. frequency.
""" """
return int32(round(self.ftw_per_hz*frequency)) return int32(round(self.ftw_per_hz*frequency))
@ -567,9 +567,9 @@ class AD9910:
@portable(flags={"fast-math"}) @portable(flags={"fast-math"})
def turns_to_pow(self, turns): def turns_to_pow(self, turns):
"""Return the phase offset word corresponding to the given phase """Return the 16-bit phase offset word corresponding to the given phase
in turns.""" in turns."""
return int32(round(turns*0x10000)) return int32(round(turns*0x10000)) & 0xffff
@portable(flags={"fast-math"}) @portable(flags={"fast-math"})
def pow_to_turns(self, pow_): def pow_to_turns(self, pow_):
@ -579,9 +579,12 @@ class AD9910:
@portable(flags={"fast-math"}) @portable(flags={"fast-math"})
def amplitude_to_asf(self, amplitude): def amplitude_to_asf(self, amplitude):
"""Return amplitude scale factor corresponding to given fractional """Return 14-bit amplitude scale factor corresponding to given
amplitude.""" fractional amplitude."""
return int32(round(amplitude*0x3ffe)) code = int32(round(amplitude * 0x3ffe))
if code < 0 or code > (1 << 14) - 1:
raise ValueError("Invalid AD9910 fractional amplitude!")
return code
@portable(flags={"fast-math"}) @portable(flags={"fast-math"})
def asf_to_amplitude(self, asf): def asf_to_amplitude(self, asf):

View File

@ -157,10 +157,10 @@ class AD9912:
@portable(flags={"fast-math"}) @portable(flags={"fast-math"})
def frequency_to_ftw(self, frequency): def frequency_to_ftw(self, frequency):
"""Returns the frequency tuning word corresponding to the given """Returns the 48-bit frequency tuning word corresponding to the given
frequency. frequency.
""" """
return int64(round(self.ftw_per_hz*frequency)) return int64(round(self.ftw_per_hz*frequency)) & ((int64(1) << 48) - 1)
@portable(flags={"fast-math"}) @portable(flags={"fast-math"})
def ftw_to_frequency(self, ftw): def ftw_to_frequency(self, ftw):
@ -171,10 +171,10 @@ class AD9912:
@portable(flags={"fast-math"}) @portable(flags={"fast-math"})
def turns_to_pow(self, phase): def turns_to_pow(self, phase):
"""Returns the phase offset word corresponding to the given """Returns the 16-bit phase offset word corresponding to the given
phase. phase.
""" """
return int32(round((1 << 14)*phase)) return int32(round((1 << 14)*phase)) & 0xffff
@kernel @kernel
def set(self, frequency, phase=0.0): def set(self, frequency, phase=0.0):

View File

@ -236,10 +236,10 @@ class AD9914:
@portable(flags={"fast-math"}) @portable(flags={"fast-math"})
def frequency_to_ftw(self, frequency): def frequency_to_ftw(self, frequency):
"""Returns the frequency tuning word corresponding to the given """Returns the 32-bit frequency tuning word corresponding to the given
frequency. frequency.
""" """
return round(float(int64(2)**32*frequency/self.sysclk)) return int32(round(float(int64(2)**32*frequency/self.sysclk)))
@portable(flags={"fast-math"}) @portable(flags={"fast-math"})
def ftw_to_frequency(self, ftw): def ftw_to_frequency(self, ftw):
@ -250,9 +250,9 @@ class AD9914:
@portable(flags={"fast-math"}) @portable(flags={"fast-math"})
def turns_to_pow(self, turns): def turns_to_pow(self, turns):
"""Returns the phase offset word corresponding to the given phase """Returns the 16-bit phase offset word corresponding to the given
in turns.""" phase in turns."""
return round(float(turns*2**16)) return round(float(turns*2**16)) & 0xffff
@portable(flags={"fast-math"}) @portable(flags={"fast-math"})
def pow_to_turns(self, pow): def pow_to_turns(self, pow):
@ -262,8 +262,12 @@ class AD9914:
@portable(flags={"fast-math"}) @portable(flags={"fast-math"})
def amplitude_to_asf(self, amplitude): def amplitude_to_asf(self, amplitude):
"""Returns amplitude scale factor corresponding to given amplitude.""" """Returns 12-bit amplitude scale factor corresponding to given
return round(float(amplitude*0x0fff)) amplitude."""
code = round(float(amplitude * 0x0fff))
if code < 0 or code > 0xfff:
raise ValueError("Invalid AD9914 amplitude!")
return code
@portable(flags={"fast-math"}) @portable(flags={"fast-math"})
def asf_to_amplitude(self, asf): def asf_to_amplitude(self, asf):
@ -314,10 +318,11 @@ class AD9914:
@portable(flags={"fast-math"}) @portable(flags={"fast-math"})
def frequency_to_xftw(self, frequency): def frequency_to_xftw(self, frequency):
"""Returns the frequency tuning word corresponding to the given """Returns the 63-bit frequency tuning word corresponding to the given
frequency (extended resolution mode). frequency (extended resolution mode).
""" """
return int64(round(2.0*float(int64(2)**62)*frequency/self.sysclk)) return int64(round(2.0*float(int64(2)**62)*frequency/self.sysclk)) & (
(int64(1) << 63) - 1)
@portable(flags={"fast-math"}) @portable(flags={"fast-math"})
def xftw_to_frequency(self, xftw): def xftw_to_frequency(self, xftw):

View File

@ -558,5 +558,7 @@ class Channel:
:param y: IIR state in units of full scale :param y: IIR state in units of full scale
""" """
y_mu = int(round(y * Y_FULL_SCALE_MU)) y_mu = int(round(y * Y_FULL_SCALE_MU))
if y_mu < 0 or y_mu > (1 << 17) - 1:
raise ValueError("Invalid SUServo y-value!")
self.set_y_mu(profile, y_mu) self.set_y_mu(profile, y_mu)
return y_mu return y_mu

View File

@ -292,7 +292,7 @@ class CPLD:
:meth:`get_att_mu` to retrieve the hardware state set in previous experiments. :meth:`get_att_mu` to retrieve the hardware state set in previous experiments.
:param channel: Attenuator channel (0-3). :param channel: Attenuator channel (0-3).
:param att: Digital attenuation setting: :param att: 8-bit digital attenuation setting:
255 minimum attenuation, 0 maximum attenuation (31.5 dB) 255 minimum attenuation, 0 maximum attenuation (31.5 dB)
""" """
a = self.att_reg & ~(0xff << (channel * 8)) a = self.att_reg & ~(0xff << (channel * 8))
@ -325,7 +325,10 @@ class CPLD:
attenuation. Minimum attenuation is 0*dB, maximum attenuation is attenuation. Minimum attenuation is 0*dB, maximum attenuation is
31.5*dB. 31.5*dB.
""" """
self.set_att_mu(channel, 255 - int32(round(att*8))) code = 255 - int32(round(att*8))
if code < 0 or code > 255:
raise ValueError("Invalid urukul.CPLD attenuation!")
self.set_att_mu(channel, code)
@kernel @kernel
def get_att_mu(self): def get_att_mu(self):