json: remove the 32-bit parameter special case
authorMarcin Kościelnicki <mwk@0x04.net>
Sat, 1 Feb 2020 09:21:19 +0000 (10:21 +0100)
committerMarcelina Kościelnicka <mwk@0x04.net>
Sat, 1 Feb 2020 15:16:26 +0000 (16:16 +0100)
Before, the rules for encoding parameters in JSON were as follows:

- if the parameter is not a string:

  - if it is exactly 32 bits long and there are no z or x bits, emit it
    as an int
  - otherwise, emit it as a string made of 0/1/x/z characters

- if the parameter is a string:

  - if it contains only 0/1/x/z characters, append a space at the end
    to distinguish it from a non-string
  - otherwise, emit it directly

However, this caused a problem in the json11 parser used in nextpnr:
yosys emits unsigned ints, and nextpnr parses them as signed, using
the value of INT_MIN for values that overflow the signed int range.
This caused destruction of LUT5 initialization values.  Since both
nextpnr and yosys parser can also accept 32-bit parameters in the
same encoding as other widths, let's just remove that special case.
The old behavior is still left behind a `-compat-int` flag, in case
someone relies on it.

backends/json/json.cc

index 107009ee4e80bc9d904cf75ade9f22776741fee9..5c67cb857e34aae90a49222398a3f345df459d84 100644 (file)
@@ -33,6 +33,7 @@ struct JsonWriter
        std::ostream &f;
        bool use_selection;
        bool aig_mode;
+       bool compat_int_mode;
 
        Design *design;
        Module *module;
@@ -42,8 +43,9 @@ struct JsonWriter
        dict<SigBit, string> sigids;
        pool<Aig> aig_models;
 
-       JsonWriter(std::ostream &f, bool use_selection, bool aig_mode) :
-                       f(f), use_selection(use_selection), aig_mode(aig_mode) { }
+       JsonWriter(std::ostream &f, bool use_selection, bool aig_mode, bool compat_int_mode) :
+                       f(f), use_selection(use_selection), aig_mode(aig_mode),
+                       compat_int_mode(compat_int_mode) { }
 
        string get_string(string str)
        {
@@ -102,8 +104,7 @@ struct JsonWriter
                        if (state < 2)
                                str += " ";
                        f << get_string(str);
-               } else
-               if (GetSize(value) == 32 && value.is_fully_def()) {
+               } else if (compat_int_mode && GetSize(value) == 32 && value.is_fully_def()) {
                        if ((value.flags & RTLIL::ConstFlags::CONST_FLAG_SIGNED) != 0)
                                f << stringf("%d", value.as_int());
                        else
@@ -294,6 +295,10 @@ struct JsonBackend : public Backend {
                log("    -aig\n");
                log("        include AIG models for the different gate types\n");
                log("\n");
+               log("    -compat-int\n");
+               log("        emit 32-bit fully-defined parameter values directly\n");
+               log("        as JSON numbers (for compatibility with old parsers)\n");
+               log("\n");
                log("\n");
                log("The general syntax of the JSON output created by this command is as follows:\n");
                log("\n");
@@ -368,10 +373,9 @@ struct JsonBackend : public Backend {
                log("connected to a constant driver are denoted as string \"0\", \"1\", \"x\", or\n");
                log("\"z\" instead of a number.\n");
                log("\n");
-               log("Numeric 32-bit parameter and attribute values are written as decimal values.\n");
-               log("Bit verctors of different sizes, or ones containing 'x' or 'z' bits, are written\n");
-               log("as string holding the binary representation of the value. Strings are written\n");
-               log("as strings, with an appended blank in cases of strings of the form /[01xz]* */.\n");
+               log("Bit vectors (including integers) are written as string holding the binary");
+               log("representation of the value. Strings are written as strings, with an appended");
+               log("blank in cases of strings of the form /[01xz]* */.\n");
                log("\n");
                log("For example the following Verilog code:\n");
                log("\n");
@@ -495,6 +499,7 @@ struct JsonBackend : public Backend {
        void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
        {
                bool aig_mode = false;
+               bool compat_int_mode = false;
 
                size_t argidx;
                for (argidx = 1; argidx < args.size(); argidx++)
@@ -503,13 +508,17 @@ struct JsonBackend : public Backend {
                                aig_mode = true;
                                continue;
                        }
+                       if (args[argidx] == "-compat-int") {
+                               compat_int_mode = true;
+                               continue;
+                       }
                        break;
                }
                extra_args(f, filename, args, argidx);
 
                log_header(design, "Executing JSON backend.\n");
 
-               JsonWriter json_writer(*f, false, aig_mode);
+               JsonWriter json_writer(*f, false, aig_mode, compat_int_mode);
                json_writer.write_design(design);
        }
 } JsonBackend;
@@ -530,6 +539,10 @@ struct JsonPass : public Pass {
                log("    -aig\n");
                log("        also include AIG models for the different gate types\n");
                log("\n");
+               log("    -compat-int\n");
+               log("        emit 32-bit fully-defined parameter values directly\n");
+               log("        as JSON numbers (for compatibility with old parsers)\n");
+               log("\n");
                log("See 'help write_json' for a description of the JSON format used.\n");
                log("\n");
        }
@@ -537,6 +550,7 @@ struct JsonPass : public Pass {
        {
                std::string filename;
                bool aig_mode = false;
+               bool compat_int_mode = false;
 
                size_t argidx;
                for (argidx = 1; argidx < args.size(); argidx++)
@@ -549,6 +563,10 @@ struct JsonPass : public Pass {
                                aig_mode = true;
                                continue;
                        }
+                       if (args[argidx] == "-compat-int") {
+                               compat_int_mode = true;
+                               continue;
+                       }
                        break;
                }
                extra_args(args, argidx, design);
@@ -569,7 +587,7 @@ struct JsonPass : public Pass {
                        f = &buf;
                }
 
-               JsonWriter json_writer(*f, true, aig_mode);
+               JsonWriter json_writer(*f, true, aig_mode, compat_int_mode);
                json_writer.write_design(design);
 
                if (!filename.empty()) {