kasli_generic: validate description against schema, use defaults from schema

This commit is contained in:
Astro 2020-12-29 19:18:12 +01:00 committed by Sébastien Bourdeauducq
parent 45b5cfce05
commit c6807f4594
5 changed files with 66 additions and 33 deletions

View File

@ -3,3 +3,4 @@ graft artiq/examples
include artiq/gui/logo*.svg include artiq/gui/logo*.svg
include versioneer.py include versioneer.py
include artiq/_version.py include artiq/_version.py
include artiq/gateware/targets/kasli_generic.schema.json

View File

@ -2,12 +2,12 @@
import argparse import argparse
import sys import sys
import json
import textwrap import textwrap
from collections import defaultdict from collections import defaultdict
from itertools import count from itertools import count
from artiq import __version__ as artiq_version from artiq import __version__ as artiq_version
from artiq.gateware import jsondesc
def process_header(output, description): def process_header(output, description):
@ -57,8 +57,8 @@ def process_header(output, description):
}} }}
""").format( """).format(
variant=description["variant"], variant=description["variant"],
core_addr=description.get("core_addr", "192.168.1.70"), core_addr=description["core_addr"],
ref_period=1/(8*description.get("rtio_frequency", 125e6))), ref_period=1/(8*description["rtio_frequency"])),
file=output) file=output)
@ -116,7 +116,7 @@ class PeripheralManager:
def process_urukul(self, rtio_offset, peripheral): def process_urukul(self, rtio_offset, peripheral):
urukul_name = self.get_name("urukul") urukul_name = self.get_name("urukul")
synchronization = peripheral.get("synchronization", False) synchronization = peripheral["synchronization"]
channel = count(0) channel = count(0)
self.gen(""" self.gen("""
device_db["eeprom_{name}"]={{ device_db["eeprom_{name}"]={{
@ -181,10 +181,10 @@ class PeripheralManager:
}}""", }}""",
name=urukul_name, name=urukul_name,
sync_device="\"ttl_{name}_sync\"".format(name=urukul_name) if synchronization else "None", sync_device="\"ttl_{name}_sync\"".format(name=urukul_name) if synchronization else "None",
refclk=peripheral.get("refclk", self.master_description.get("rtio_frequency", 125e6)), refclk=peripheral.get("refclk", self.master_description["rtio_frequency"]),
clk_sel=peripheral["clk_sel"]) clk_sel=peripheral["clk_sel"])
dds = peripheral.get("dds", "ad9910") dds = peripheral["dds"]
pll_vco = peripheral.get("pll_vco", None) pll_vco = peripheral.get("pll_vco")
for i in range(4): for i in range(4):
if dds == "ad9910": if dds == "ad9910":
self.gen(""" self.gen("""
@ -280,8 +280,8 @@ class PeripheralManager:
}}, }},
}}""", }}""",
name=mirny_name, name=mirny_name,
refclk=peripheral.get("refclk", 100e6), refclk=peripheral["refclk"],
clk_sel=peripheral.get("clk_sel", 0)) clk_sel=peripheral["clk_sel"])
return next(channel) return next(channel)
@ -394,7 +394,7 @@ class PeripheralManager:
}}""", }}""",
sampler_name=sampler_name, sampler_name=sampler_name,
sampler_channel=rtio_offset+next(channel)) sampler_channel=rtio_offset+next(channel))
pll_vco = peripheral.get("pll_vco", None) pll_vco = peripheral.get("pll_vco")
for urukul_name in (urukul0_name, urukul1_name): for urukul_name in (urukul0_name, urukul1_name):
self.gen(""" self.gen("""
device_db["spi_{urukul_name}"] = {{ device_db["spi_{urukul_name}"] = {{
@ -425,10 +425,10 @@ class PeripheralManager:
}}""", }}""",
urukul_name=urukul_name, urukul_name=urukul_name,
urukul_channel=rtio_offset+next(channel), urukul_channel=rtio_offset+next(channel),
refclk=peripheral.get("refclk", self.master_description.get("rtio_frequency", 125e6)), refclk=peripheral.get("refclk", self.master_description["rtio_frequency"]),
clk_sel=peripheral["clk_sel"], clk_sel=peripheral["clk_sel"],
pll_vco=",\n \"pll_vco\": {}".format(pll_vco) if pll_vco is not None else "", pll_vco=",\n \"pll_vco\": {}".format(pll_vco) if pll_vco is not None else "",
pll_n=peripheral.get("pll_n", 32)) pll_n=peripheral["pll_n"])
return next(channel) return next(channel)
def process_zotino(self, rtio_offset, peripheral): def process_zotino(self, rtio_offset, peripheral):
@ -573,13 +573,12 @@ def main():
args = parser.parse_args() args = parser.parse_args()
with open(args.master_description, "r") as f: master_description = jsondesc.load(args.master_description)
master_description = json.load(f)
satellites = [] satellites = []
for destination, description in args.satellite: for destination, description_path in args.satellite:
with open(description, "r") as f: satellite_description = jsondesc.load(description_path)
satellites.append((int(destination, 0), json.load(f))) satellites.append((int(destination, 0), satellite_description))
if args.output is not None: if args.output is not None:
with open(args.output, "w") as f: with open(args.output, "w") as f:

View File

@ -0,0 +1,35 @@
from os import path
import json
from jsonschema import Draft7Validator, validators
def extend_with_default(validator_class):
validate_properties = validator_class.VALIDATORS["properties"]
def set_defaults(validator, properties, instance, schema):
for property, subschema in properties.items():
if "default" in subschema:
instance.setdefault(property, subschema["default"])
for error in validate_properties(
validator, properties, instance, schema,
):
yield error
return validators.extend(
validator_class, {"properties" : set_defaults},
)
schema_path = path.join(path.dirname(__file__), "targets/kasli_generic.schema.json")
with open(schema_path, "r") as f:
schema = json.load(f)
validator = extend_with_default(Draft7Validator)(schema)
def load(description_path):
with open(description_path, "r") as f:
result = json.load(f)
global validator
validator.validate(result)
return result

View File

@ -1,14 +1,12 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import argparse import argparse
import json
from misoc.integration.builder import builder_args, builder_argdict from misoc.integration.builder import builder_args, builder_argdict
from misoc.targets.kasli import soc_kasli_args, soc_kasli_argdict from misoc.targets.kasli import soc_kasli_args, soc_kasli_argdict
from artiq.gateware import rtio from artiq.gateware import rtio, eem, jsondesc
from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, edge_counter from artiq.gateware.rtio.phy import ttl_simple, ttl_serdes_7series, edge_counter
from artiq.gateware import eem
from artiq.gateware.targets.kasli import StandaloneBase, MasterBase, SatelliteBase from artiq.gateware.targets.kasli import StandaloneBase, MasterBase, SatelliteBase
from artiq.build_soc import * from artiq.build_soc import *
@ -20,7 +18,7 @@ def peripheral_dio(module, peripheral):
} }
if len(peripheral["ports"]) != 1: if len(peripheral["ports"]) != 1:
raise ValueError("wrong number of ports") raise ValueError("wrong number of ports")
if peripheral.get("edge_counter", False): if peripheral["edge_counter"]:
edge_counter_cls = edge_counter.SimpleEdgeCounter edge_counter_cls = edge_counter.SimpleEdgeCounter
else: else:
edge_counter_cls = None edge_counter_cls = None
@ -37,7 +35,7 @@ def peripheral_urukul(module, peripheral):
port, port_aux = peripheral["ports"] port, port_aux = peripheral["ports"]
else: else:
raise ValueError("wrong number of ports") raise ValueError("wrong number of ports")
if peripheral.get("synchronization", False): if peripheral["synchronization"]:
sync_gen_cls = ttl_simple.ClockGen sync_gen_cls = ttl_simple.ClockGen
else: else:
sync_gen_cls = None sync_gen_cls = None
@ -110,7 +108,7 @@ def peripheral_fastino(module, peripheral):
if len(peripheral["ports"]) != 1: if len(peripheral["ports"]) != 1:
raise ValueError("wrong number of ports") raise ValueError("wrong number of ports")
eem.Fastino.add_std(module, peripheral["ports"][0], eem.Fastino.add_std(module, peripheral["ports"][0],
peripheral.get("log2_width", 0)) peripheral["log2_width"])
def peripheral_phaser(module, peripheral): def peripheral_phaser(module, peripheral):
@ -146,7 +144,7 @@ class GenericStandalone(StandaloneBase):
StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs) StandaloneBase.__init__(self, hw_rev=hw_rev, **kwargs)
self.config["SI5324_AS_SYNTHESIZER"] = None self.config["SI5324_AS_SYNTHESIZER"] = None
self.config["RTIO_FREQUENCY"] = "{:.1f}".format(description.get("rtio_frequency", 125e6)/1e6) self.config["RTIO_FREQUENCY"] = "{:.1f}".format(description["rtio_frequency"]/1e6)
if "ext_ref_frequency" in description: if "ext_ref_frequency" in description:
self.config["SI5324_EXT_REF"] = None self.config["SI5324_EXT_REF"] = None
self.config["EXT_REF_FREQUENCY"] = "{:.1f}".format( self.config["EXT_REF_FREQUENCY"] = "{:.1f}".format(
@ -189,8 +187,8 @@ class GenericMaster(MasterBase):
self.class_name_override = description["variant"] self.class_name_override = description["variant"]
MasterBase.__init__(self, MasterBase.__init__(self,
hw_rev=hw_rev, hw_rev=hw_rev,
rtio_clk_freq=description.get("rtio_frequency", 125e6), rtio_clk_freq=description["rtio_frequency"],
enable_sata=description.get("enable_sata_drtio", False), enable_sata=description["enable_sata_drtio"],
**kwargs) **kwargs)
if "ext_ref_frequency" in description: if "ext_ref_frequency" in description:
self.config["SI5324_EXT_REF"] = None self.config["SI5324_EXT_REF"] = None
@ -226,8 +224,8 @@ class GenericSatellite(SatelliteBase):
self.class_name_override = description["variant"] self.class_name_override = description["variant"]
SatelliteBase.__init__(self, SatelliteBase.__init__(self,
hw_rev=hw_rev, hw_rev=hw_rev,
rtio_clk_freq=description.get("rtio_frequency", 125e6), rtio_clk_freq=description["rtio_frequency"],
enable_sata=description.get("enable_sata_drtio", False), enable_sata=description["enable_sata_drtio"],
**kwargs) **kwargs)
if hw_rev == "v1.0": if hw_rev == "v1.0":
# EEM clock fan-out from Si5324, not MMCX # EEM clock fan-out from Si5324, not MMCX
@ -263,9 +261,7 @@ def main():
parser.add_argument("--gateware-identifier-str", default=None, parser.add_argument("--gateware-identifier-str", default=None,
help="Override ROM identifier") help="Override ROM identifier")
args = parser.parse_args() args = parser.parse_args()
description = jsondesc.load(args.description)
with open(args.description, "r") as f:
description = json.load(f)
if description["target"] != "kasli": if description["target"] != "kasli":
raise ValueError("Description is for a different target") raise ValueError("Description is for a different target")

View File

@ -42,7 +42,8 @@
"core_addr": { "core_addr": {
"type": "string", "type": "string",
"format": "ipv4", "format": "ipv4",
"description": "IPv4 address" "description": "IPv4 address",
"default": "192.168.1.70"
}, },
"vendor": { "vendor": {
"type": "string", "type": "string",
@ -262,7 +263,8 @@
"maximum": 3 "maximum": 3
}, },
"pll_n": { "pll_n": {
"type": "integer" "type": "integer",
"default": 32
}, },
"pll_vco": { "pll_vco": {
"type": "integer" "type": "integer"