[reggen] Define classes to represent parameters in a block

This is supposed to represent the thing at obj['params_list']. The
Params class is essentially just a list of the parameters. These
parameters are now split into 3 classes, inheriting from BaseParam.

LocalParam and Parameter are for "normal" parameters and localparams.
RandParameter is used for random netlist constants.

This change has a small impact on topgen.py: the code that pulls
parameters up to the top-level actually gets a bit cleaner, but it now
needs to convert back to dict explicitly. That shuffling, in turn,
slightly changes the ordering of fields in (the checked-in)
top_earlgrey.gen.hjson.

Signed-off-by: Rupert Swarbrick <rswarbrick@lowrisc.org>
diff --git a/hw/top_earlgrey/data/top_earlgrey.sv.tpl b/hw/top_earlgrey/data/top_earlgrey.sv.tpl
index b507b29..de9342e 100644
--- a/hw/top_earlgrey/data/top_earlgrey.sv.tpl
+++ b/hw/top_earlgrey/data/top_earlgrey.sv.tpl
@@ -40,7 +40,7 @@
   % if not lib.is_inst(m):
 <% continue %>
   % endif
-  % for p_exp in filter(lambda p: p["expose"] == "true", m["param_list"]):
+  % for p_exp in filter(lambda p: p.get("expose") == "true", m["param_list"]):
   parameter ${p_exp["type"]} ${p_exp["name_top"]} = ${p_exp["default"]},
   % endfor
 % endfor
@@ -592,7 +592,7 @@
   % if m["param_list"]:
   ${m["type"]} #(
     % for i in m["param_list"]:
-    .${i["name"]}(${i["name_top" if i["expose"] == "true" or i["randtype"] != "none" else "default"]})${"," if not loop.last else ""}
+    .${i["name"]}(${i["name_top" if i.get("expose") == "true" or i.get("randtype", "none") != "none" else "default"]})${"," if not loop.last else ""}
     % endfor
   ) u_${m["name"]} (
   % else: