diff --git a/backends/jny/jny.cc b/backends/jny/jny.cc index d801b144c..2b8d51b76 100644 --- a/backends/jny/jny.cc +++ b/backends/jny/jny.cc @@ -27,6 +27,8 @@ #include #include #include +#include +#include USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -116,17 +118,17 @@ struct JnyWriter _include_connections(connections), _include_attributes(attributes), _include_properties(properties) { } - void write_metadata(Design *design, uint16_t indent_level = 0) + void write_metadata(Design *design, uint16_t indent_level = 0, std::string invk = "") { log_assert(design != nullptr); design->sort(); f << "{\n"; + f << " \"$schema\": \"https://raw.githubusercontent.com/YosysHQ/yosys/master/misc/jny.schema.json\",\n"; f << stringf(" \"generator\": \"%s\",\n", escape_string(yosys_version_str).c_str()); - // XXX(aki): Replace this with a proper version info eventually:tm: - f << " \"version\": \"0.0.0\",\n"; - + f << " \"version\": \"0.0.1\",\n"; + f << " \"invocation\": \"" << escape_string(invk) << "\",\n"; f << " \"features\": ["; size_t fnum{0}; @@ -409,11 +411,12 @@ struct JnyWriter struct JnyBackend : public Backend { JnyBackend() : Backend("jny", "generate design metadata") { } void help() override { - // XXX(aki): TODO: explicitly document the JSON schema // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); log(" jny [options] [selection]\n"); log("\n"); + log("Write JSON netlist metadata for the current design\n"); + log("\n"); log(" -no-connections\n"); log(" Don't include connection information in the netlist output.\n"); log("\n"); @@ -423,8 +426,8 @@ struct JnyBackend : public Backend { log(" -no-properties\n"); log(" Don't include property information in the netlist output.\n"); log("\n"); - log("Write a JSON metadata for the current design\n"); - log("\n"); + log("The JSON schema for JNY output files is located in the \"jny.schema.json\" file\n"); + log("which is located at \"https://raw.githubusercontent.com/YosysHQ/yosys/master/misc/jny.schema.json\"\n"); log("\n"); } @@ -453,12 +456,22 @@ struct JnyBackend : public Backend { break; } + + // Compose invocation line + std::ostringstream invk; + if (!args.empty()) { + std::copy(args.begin(), args.end(), + std::ostream_iterator(invk, " ") + ); + } + invk << filename; + extra_args(f, filename, args, argidx); log_header(design, "Executing jny backend.\n"); JnyWriter jny_writer(*f, false, connections, attributes, properties); - jny_writer.write_metadata(design); + jny_writer.write_metadata(design, 0, invk.str()); } } JnyBackend; @@ -472,7 +485,7 @@ struct JnyPass : public Pass { log("\n"); log(" jny [options] [selection]\n"); log("\n"); - log("Write a JSON netlist metadata for the current design\n"); + log("Write JSON netlist metadata for the current design\n"); log("\n"); log(" -o \n"); log(" write to the specified file.\n"); @@ -520,6 +533,15 @@ struct JnyPass : public Pass { break; } + + // Compose invocation line + std::ostringstream invk; + if (!args.empty()) { + std::copy(args.begin(), args.end(), + std::ostream_iterator(invk, " ") + ); + } + extra_args(args, argidx, design); std::ostream *f; @@ -534,13 +556,14 @@ struct JnyPass : public Pass { log_error("Can't open file `%s' for writing: %s\n", filename.c_str(), strerror(errno)); } f = ff; + invk << filename; } else { f = &buf; } JnyWriter jny_writer(*f, false, connections, attributes, properties); - jny_writer.write_metadata(design); + jny_writer.write_metadata(design, 0, invk.str()); if (!filename.empty()) { delete f; diff --git a/misc/jny.schema.json b/misc/jny.schema.json new file mode 100644 index 000000000..0fff8ee57 --- /dev/null +++ b/misc/jny.schema.json @@ -0,0 +1,193 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://raw.githubusercontent.com/YosysHQ/yosys/master/misc/jny.schema.json", + "title": "Yosys JSON Netlist metadata", + "description": "Yosys JSON Netlist", + "type": "object", + "properties": { + "generator": { + "type": "string", + "description": "JNY File Generator" + }, + "version": { + "type": "string", + "description": "JNY Version" + }, + "invocation": { + "type": "string", + "description": "Invocation line that generated the JNY metadata" + }, + "features": { + "type": "array", + "description": "What information is contained in the JNY file", + "items": { + "type": "string" + } + }, + "modules": { + "type": "array", + "items": { "$ref": "#/$defs/module" } + } + }, + "required": [ + "generator", + "version", + "invocation", + "features" + ], + "$defs": { + "module": { + "type": "object", + "description": "Module definition", + "properties": { + "name": { + "type": "string", + "description": "Module Name" + }, + "cell_sorts": { + "type": "array", + "description": "", + "items": { "$ref": "#/$defs/cell_sort" } + }, + "connections": { + "type": "array", + "description": "Cell connections", + "items": { "$ref": "#/$defs/connection" } + }, + "attributes": { + "type": "object", + "description": "Attributes attached to the module" + }, + "parameters": { + "type": "object", + "description": "Parameters attached to the module" + } + }, + "required": [ + "name", + "cell_sorts" + ] + }, + "cell_sort": { + "type": "object", + "description": "Describes a type of cell", + "properties": { + "type": { + "type": "string", + "description": "Type of cell" + }, + "ports": { + "type": "array", + "description": "Cell ports", + "items": { "$ref": "#/$defs/port" } + } + , + "cells": { + "type": "array", + "description": "Cells of cell_sort", + "items": { "$ref": "#/$defs/cell" } + } + }, + "required": [ + "type", + "ports", + "cells" + ] + }, + "connection": { + "type": "object", + "description": "A connection within a module or cell", + "properties": { + "name": { + "type": "string", + "description": "Connection name" + }, + "signals": { + "type": "array", + "description": "Signals that compose the connection", + "items": { "$ref": "#/$defs/signal" } + } + }, + "required": [ + "name", + "signals" + ] + }, + "port": { + "type": "object", + "description": "Cell port description", + "properties": { + "name": { + "type": "string", + "description": "Port name" + }, + "direction": { + "type": "string", + "description": "Port direction", + "enum": ["i", "o", "io", ""] + }, + "range": { + "type": "array", + "description": "Port width [MSB, LSB]", + "items": { + "type": "number" + }, + "minContains": 1, + "maxContains": 2 + } + }, + "required": [ + "name", + "direction", + "range" + ] + }, + "cell": { + "type": "object", + "description": "Module cell definition", + "properties": { + "name": { + "type": "string", + "description": "Cell name" + }, + "connections": { + "type": "array", + "description": "Cell connections", + "items": { "$ref": "#/$defs/connection" } + }, + "attributes": { + "type": "object", + "description": "Attributes attached to the cell" + }, + "parameters": { + "type": "object", + "description": "Parameters attached to the cell" + } + }, + "required": [ + "name" + ] + }, + "signal": { + "type": "object", + "description": "A signal definition", + "parameters": { + "width": { + "type": "string" + }, + "type": { + "type": "string", + "enum": ["wire", "chunk"] + }, + "const": { + "type": "boolean" + } + }, + "required": [ + "width", + "type", + "const" + ] + } + } +}