udb 0.1.9 → 0.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (275) hide show
  1. checksums.yaml +4 -4
  2. data/.data/cfgs/example_rv64_with_overlay.yaml +5 -2
  3. data/.data/cfgs/mc100-32-full-example.yaml +1 -0
  4. data/.data/cfgs/profile/README.adoc +10 -0
  5. data/.data/cfgs/profile/RVA20S64.yaml +26 -6
  6. data/.data/cfgs/profile/RVA20U64.yaml +18 -4
  7. data/.data/cfgs/profile/RVA22S64.yaml +27 -7
  8. data/.data/cfgs/profile/RVA22U64.yaml +18 -4
  9. data/.data/cfgs/profile/RVA23S64.yaml +61 -7
  10. data/.data/cfgs/profile/RVA23U64.yaml +36 -4
  11. data/.data/cfgs/profile/RVB23S64.yaml +27 -7
  12. data/.data/cfgs/profile/RVB23U64.yaml +18 -4
  13. data/.data/cfgs/profile/RVI20U32.yaml +10 -4
  14. data/.data/cfgs/profile/RVI20U64.yaml +10 -4
  15. data/.data/cfgs/qc_iu.yaml +4 -1
  16. data/.data/cfgs/rv32-riscv-tests.yaml +2 -1
  17. data/.data/cfgs/rv32-vector.yaml +2 -1
  18. data/.data/cfgs/rv64-riscv-tests.yaml +2 -1
  19. data/.data/cfgs/rv64-vector.yaml +2 -1
  20. data/.data/spec/custom/isa/qc_iu/csr/Smrnmi/mnepc.yaml +17 -0
  21. data/.data/spec/custom/isa/qc_iu/csr/Xqccmi/qc.itba.yaml +45 -0
  22. data/.data/spec/custom/isa/qc_iu/csr/Xqccmi/qc.itdec.yaml +39 -0
  23. data/.data/spec/custom/isa/qc_iu/csr/jvt.yaml +11 -0
  24. data/.data/spec/custom/isa/qc_iu/csr/mepc.yaml +16 -0
  25. data/.data/spec/custom/isa/qc_iu/ext/Xqccmi.yaml +219 -0
  26. data/.data/spec/custom/isa/qc_iu/ext/Xqccmt.yaml +127 -0
  27. data/.data/spec/custom/isa/qc_iu/inst/Xqccmi/qc.cm.ilut.yaml +153 -0
  28. data/.data/spec/custom/isa/qc_iu/inst/Xqccmt/qc.cm.jalt.yaml +84 -0
  29. data/.data/spec/custom/isa/qc_iu/inst/Xqccmt/qc.cm.jt.yaml +60 -0
  30. data/.data/spec/custom/isa/qc_iu/isa/globals.isa +112 -0
  31. data/.data/spec/schemas/config_schema.json +219 -26
  32. data/.data/spec/schemas/csr_schema.json +0 -6
  33. data/.data/spec/schemas/ext_schema.json +80 -24
  34. data/.data/spec/schemas/inst_schema.json +0 -3
  35. data/.data/spec/schemas/profile_release_schema.json +1 -1
  36. data/.data/spec/schemas/profile_schema.json +0 -3
  37. data/.data/spec/schemas/register_file_schema.json +8 -3
  38. data/.data/spec/schemas/schema_defs.json +8 -27
  39. data/.data/spec/std/isa/csr/I/pmpcfg0.yaml +8 -8
  40. data/.data/spec/std/isa/csr/I/pmpcfg1.yaml +4 -4
  41. data/.data/spec/std/isa/csr/I/pmpcfg10.yaml +8 -8
  42. data/.data/spec/std/isa/csr/I/pmpcfg11.yaml +4 -4
  43. data/.data/spec/std/isa/csr/I/pmpcfg12.yaml +8 -8
  44. data/.data/spec/std/isa/csr/I/pmpcfg13.yaml +4 -4
  45. data/.data/spec/std/isa/csr/I/pmpcfg14.yaml +8 -8
  46. data/.data/spec/std/isa/csr/I/pmpcfg15.yaml +4 -4
  47. data/.data/spec/std/isa/csr/I/pmpcfg2.yaml +8 -8
  48. data/.data/spec/std/isa/csr/I/pmpcfg3.yaml +4 -4
  49. data/.data/spec/std/isa/csr/I/pmpcfg4.yaml +8 -8
  50. data/.data/spec/std/isa/csr/I/pmpcfg5.yaml +4 -4
  51. data/.data/spec/std/isa/csr/I/pmpcfg6.yaml +8 -8
  52. data/.data/spec/std/isa/csr/I/pmpcfg7.yaml +4 -4
  53. data/.data/spec/std/isa/csr/I/pmpcfg8.yaml +8 -8
  54. data/.data/spec/std/isa/csr/I/pmpcfg9.yaml +4 -4
  55. data/.data/spec/std/isa/csr/I/pmpcfgN.layout +1 -1
  56. data/.data/spec/std/isa/csr/Zicntr/mcountinhibit.layout +6 -2
  57. data/.data/spec/std/isa/csr/Zicntr/mcountinhibit.yaml +6 -2
  58. data/.data/spec/std/isa/csr/hstatus.yaml +16 -0
  59. data/.data/spec/std/isa/csr/mcycleh.yaml +1 -1
  60. data/.data/spec/std/isa/csr/misa.yaml +0 -12
  61. data/.data/spec/std/isa/csr/mstatus.yaml +38 -0
  62. data/.data/spec/std/isa/csr/mstatush.yaml +17 -15
  63. data/.data/spec/std/isa/csr/senvcfg.yaml +16 -0
  64. data/.data/spec/std/isa/csr/sstatus.yaml +12 -0
  65. data/.data/spec/std/isa/csr/vsstatus.yaml +24 -0
  66. data/.data/spec/std/isa/ext/A.yaml +5 -7
  67. data/.data/spec/std/isa/ext/S.yaml +12 -0
  68. data/.data/spec/std/isa/ext/Smpmpmt.yaml +52 -0
  69. data/.data/spec/std/isa/ext/Sv32.yaml +7 -19
  70. data/.data/spec/std/isa/ext/Sv39.yaml +7 -19
  71. data/.data/spec/std/isa/ext/Sv48.yaml +4 -20
  72. data/.data/spec/std/isa/ext/Sv57.yaml +4 -20
  73. data/.data/spec/std/isa/ext/Svukte.yaml +71 -0
  74. data/.data/spec/std/isa/ext/Zawrs.yaml +1 -1
  75. data/.data/spec/std/isa/ext/Zihpm.yaml +0 -12
  76. data/.data/spec/std/isa/inst/C/c.addi.yaml +1 -0
  77. data/.data/spec/std/isa/inst/C/c.addi16sp.yaml +1 -0
  78. data/.data/spec/std/isa/inst/C/c.addiw.yaml +1 -0
  79. data/.data/spec/std/isa/inst/C/c.andi.yaml +1 -0
  80. data/.data/spec/std/isa/inst/C/c.ldsp.yaml +1 -1
  81. data/.data/spec/std/isa/inst/C/c.li.yaml +1 -0
  82. data/.data/spec/std/isa/inst/C/c.lui.yaml +1 -0
  83. data/.data/spec/std/isa/inst/C/c.mv.yaml +1 -1
  84. data/.data/spec/std/isa/inst/C/c.sdsp.yaml +1 -1
  85. data/.data/spec/std/isa/inst/D/fsgnj.d.yaml +3 -0
  86. data/.data/spec/std/isa/inst/D/fsgnjn.d.yaml +3 -0
  87. data/.data/spec/std/isa/inst/D/fsgnjx.d.yaml +3 -0
  88. data/.data/spec/std/isa/inst/F/fadd.s.yaml +5 -5
  89. data/.data/spec/std/isa/inst/F/fclass.s.yaml +2 -2
  90. data/.data/spec/std/isa/inst/F/fcvt.l.s.yaml +1 -1
  91. data/.data/spec/std/isa/inst/F/fcvt.lu.s.yaml +1 -1
  92. data/.data/spec/std/isa/inst/F/fcvt.s.l.yaml +1 -1
  93. data/.data/spec/std/isa/inst/F/fcvt.s.lu.yaml +1 -1
  94. data/.data/spec/std/isa/inst/F/fcvt.s.w.yaml +1 -1
  95. data/.data/spec/std/isa/inst/F/fcvt.s.wu.yaml +1 -1
  96. data/.data/spec/std/isa/inst/F/fcvt.w.s.yaml +1 -1
  97. data/.data/spec/std/isa/inst/F/fcvt.wu.s.yaml +1 -1
  98. data/.data/spec/std/isa/inst/F/fdiv.s.yaml +1 -1
  99. data/.data/spec/std/isa/inst/F/feq.s.yaml +2 -2
  100. data/.data/spec/std/isa/inst/F/fle.s.yaml +2 -2
  101. data/.data/spec/std/isa/inst/F/fleq.s.yaml +2 -2
  102. data/.data/spec/std/isa/inst/F/flt.s.yaml +2 -2
  103. data/.data/spec/std/isa/inst/F/fltq.s.yaml +2 -2
  104. data/.data/spec/std/isa/inst/F/flw.yaml +2 -2
  105. data/.data/spec/std/isa/inst/F/fmadd.s.yaml +1 -1
  106. data/.data/spec/std/isa/inst/F/fmax.s.yaml +6 -6
  107. data/.data/spec/std/isa/inst/F/fmin.s.yaml +6 -6
  108. data/.data/spec/std/isa/inst/F/fmsub.s.yaml +1 -1
  109. data/.data/spec/std/isa/inst/F/fmul.s.yaml +1 -1
  110. data/.data/spec/std/isa/inst/F/fmv.w.x.yaml +2 -2
  111. data/.data/spec/std/isa/inst/F/fmv.x.w.yaml +1 -1
  112. data/.data/spec/std/isa/inst/F/fnmadd.s.yaml +2 -2
  113. data/.data/spec/std/isa/inst/F/fnmsub.s.yaml +1 -1
  114. data/.data/spec/std/isa/inst/F/fsgnj.s.yaml +4 -4
  115. data/.data/spec/std/isa/inst/F/fsgnjn.s.yaml +3 -3
  116. data/.data/spec/std/isa/inst/F/fsgnjx.s.yaml +4 -4
  117. data/.data/spec/std/isa/inst/F/fsqrt.s.yaml +1 -1
  118. data/.data/spec/std/isa/inst/F/fsub.s.yaml +1 -1
  119. data/.data/spec/std/isa/inst/F/fsw.yaml +1 -1
  120. data/.data/spec/std/isa/inst/I/addi.yaml +1 -1
  121. data/.data/spec/std/isa/inst/I/addiw.yaml +1 -1
  122. data/.data/spec/std/isa/inst/I/andi.yaml +1 -1
  123. data/.data/spec/std/isa/inst/I/beq.yaml +1 -1
  124. data/.data/spec/std/isa/inst/I/bge.yaml +4 -2
  125. data/.data/spec/std/isa/inst/I/bgeu.yaml +3 -0
  126. data/.data/spec/std/isa/inst/I/blt.yaml +4 -2
  127. data/.data/spec/std/isa/inst/I/bltu.yaml +3 -0
  128. data/.data/spec/std/isa/inst/I/bne.yaml +1 -1
  129. data/.data/spec/std/isa/inst/I/slt.yaml +2 -2
  130. data/.data/spec/std/isa/inst/I/sltiu.yaml +1 -1
  131. data/.data/spec/std/isa/inst/I/sltu.yaml +1 -1
  132. data/.data/spec/std/isa/inst/I/sub.yaml +1 -1
  133. data/.data/spec/std/isa/inst/I/subw.yaml +1 -1
  134. data/.data/spec/std/isa/inst/I/xori.yaml +1 -1
  135. data/.data/spec/std/isa/inst/M/mul.yaml +0 -19
  136. data/.data/spec/std/isa/inst/Q/fsgnj.q.yaml +1 -1
  137. data/.data/spec/std/isa/inst/S/sret.yaml +3 -1
  138. data/.data/spec/std/isa/inst/V/vadd.vv.yaml +1 -5
  139. data/.data/spec/std/isa/inst/V/vfsgnjn.vv.yaml +3 -0
  140. data/.data/spec/std/isa/inst/V/vfsgnjx.vv.yaml +3 -0
  141. data/.data/spec/std/isa/inst/V/vl1re8.v.yaml +3 -0
  142. data/.data/spec/std/isa/inst/V/vl2re8.v.yaml +3 -0
  143. data/.data/spec/std/isa/inst/V/vl4re8.v.yaml +3 -0
  144. data/.data/spec/std/isa/inst/V/vl8re8.v.yaml +3 -0
  145. data/.data/spec/std/isa/inst/V/vle8.v.yaml +3 -8
  146. data/.data/spec/std/isa/inst/V/vmand.mm.yaml +3 -0
  147. data/.data/spec/std/isa/inst/V/vmfle.vv.yaml +3 -0
  148. data/.data/spec/std/isa/inst/V/vmflt.vv.yaml +3 -0
  149. data/.data/spec/std/isa/inst/V/vmnand.mm.yaml +3 -0
  150. data/.data/spec/std/isa/inst/V/vmsgt.vi.yaml +3 -0
  151. data/.data/spec/std/isa/inst/V/vmsgtu.vi.yaml +3 -0
  152. data/.data/spec/std/isa/inst/V/vmsle.vi.yaml +3 -0
  153. data/.data/spec/std/isa/inst/V/vmsle.vv.yaml +3 -0
  154. data/.data/spec/std/isa/inst/V/vmsleu.vi.yaml +3 -0
  155. data/.data/spec/std/isa/inst/V/vmsleu.vv.yaml +3 -0
  156. data/.data/spec/std/isa/inst/V/vmslt.vv.yaml +3 -0
  157. data/.data/spec/std/isa/inst/V/vmsltu.vv.yaml +3 -0
  158. data/.data/spec/std/isa/inst/V/vmv.v.i.yaml +2 -13
  159. data/.data/spec/std/isa/inst/V/vmv.x.s.yaml +1 -1
  160. data/.data/spec/std/isa/inst/V/vmxnor.mm.yaml +3 -0
  161. data/.data/spec/std/isa/inst/V/vmxor.mm.yaml +3 -0
  162. data/.data/spec/std/isa/inst/V/vnsrl.wx.yaml +3 -0
  163. data/.data/spec/std/isa/inst/V/vrsub.vx.yaml +3 -0
  164. data/.data/spec/std/isa/inst/V/vse8.v.yaml +3 -4
  165. data/.data/spec/std/isa/inst/V/vwadd.vx.yaml +3 -0
  166. data/.data/spec/std/isa/inst/V/vwaddu.vx.yaml +3 -0
  167. data/.data/spec/std/isa/inst/V/vxor.vi.yaml +4 -0
  168. data/.data/spec/std/isa/inst/Zalasr/lSIZE.AQRL.layout +40 -5
  169. data/.data/spec/std/isa/inst/Zalasr/lb.aq.yaml +17 -1
  170. data/.data/spec/std/isa/inst/Zalasr/lb.aqrl.yaml +17 -1
  171. data/.data/spec/std/isa/inst/Zalasr/ld.aq.yaml +17 -1
  172. data/.data/spec/std/isa/inst/Zalasr/ld.aqrl.yaml +17 -1
  173. data/.data/spec/std/isa/inst/Zalasr/lh.aq.yaml +17 -1
  174. data/.data/spec/std/isa/inst/Zalasr/lh.aqrl.yaml +17 -1
  175. data/.data/spec/std/isa/inst/Zalasr/lw.aq.yaml +17 -1
  176. data/.data/spec/std/isa/inst/Zalasr/lw.aqrl.yaml +17 -1
  177. data/.data/spec/std/isa/inst/Zalasr/sSIZE.AQRL.layout +46 -5
  178. data/.data/spec/std/isa/inst/Zalasr/sb.aqrl.yaml +16 -1
  179. data/.data/spec/std/isa/inst/Zalasr/sb.rl.yaml +16 -1
  180. data/.data/spec/std/isa/inst/Zalasr/sd.aqrl.yaml +16 -1
  181. data/.data/spec/std/isa/inst/Zalasr/sd.rl.yaml +16 -1
  182. data/.data/spec/std/isa/inst/Zalasr/sh.aqrl.yaml +16 -1
  183. data/.data/spec/std/isa/inst/Zalasr/sh.rl.yaml +16 -1
  184. data/.data/spec/std/isa/inst/Zalasr/sw.aqrl.yaml +16 -1
  185. data/.data/spec/std/isa/inst/Zalasr/sw.rl.yaml +16 -1
  186. data/.data/spec/std/isa/inst/Zbkb/packw.yaml +1 -1
  187. data/.data/spec/std/isa/inst/Zcd/c.fld.yaml +1 -1
  188. data/.data/spec/std/isa/inst/Zcd/c.fldsp.yaml +1 -1
  189. data/.data/spec/std/isa/inst/Zcd/c.fsdsp.yaml +1 -1
  190. data/.data/spec/std/isa/inst/Zcf/c.flwsp.yaml +1 -1
  191. data/.data/spec/std/isa/inst/Zcf/c.fswsp.yaml +1 -1
  192. data/.data/spec/std/isa/inst/Zcmp/cm.pop.yaml +1 -1
  193. data/.data/spec/std/isa/inst/Zcmp/cm.popret.yaml +1 -1
  194. data/.data/spec/std/isa/inst/Zcmp/cm.popretz.yaml +1 -1
  195. data/.data/spec/std/isa/inst/Zcmp/cm.push.yaml +2 -3
  196. data/.data/spec/std/isa/inst/Zfa/fround.s.yaml +1 -1
  197. data/.data/spec/std/isa/inst/Zfh/fcvt.h.s.yaml +6 -6
  198. data/.data/spec/std/isa/inst/Zfh/fcvt.s.h.yaml +5 -5
  199. data/.data/spec/std/isa/inst/Zfh/flh.yaml +1 -1
  200. data/.data/spec/std/isa/inst/Zfh/fmv.h.x.yaml +1 -1
  201. data/.data/spec/std/isa/inst/Zfh/fmv.x.h.yaml +1 -1
  202. data/.data/spec/std/isa/inst/Zfh/fsh.yaml +1 -1
  203. data/.data/spec/std/isa/inst/Zicsr/csrrc.yaml +1 -1
  204. data/.data/spec/std/isa/inst/Zicsr/csrrci.yaml +1 -1
  205. data/.data/spec/std/isa/inst/Zicsr/csrrs.yaml +2 -2
  206. data/.data/spec/std/isa/inst/Zicsr/csrrsi.yaml +1 -1
  207. data/.data/spec/std/isa/inst/Zicsr/csrrw.yaml +1 -1
  208. data/.data/spec/std/isa/inst/Zicsr/csrrwi.yaml +1 -1
  209. data/.data/spec/std/isa/isa/builtin_functions.idl +17 -0
  210. data/.data/spec/std/isa/isa/fp.idl +1 -5
  211. data/.data/spec/std/isa/isa/globals.isa +45 -14
  212. data/.data/spec/std/isa/isa/vec.idl +1 -2
  213. data/.data/spec/std/isa/manual_version/isa/20240411/isa_20240411.yaml +5 -5
  214. data/.data/spec/std/isa/param/COUNTINHIBIT_EN.yaml +8 -2
  215. data/.data/spec/std/isa/param/JVT_BASE_MASK.yaml +1 -1
  216. data/.data/spec/std/isa/param/MCOUNTINHIBIT_IMPLEMENTED.yaml +25 -0
  217. data/.data/spec/std/isa/param/MTVEC_MODES.yaml +10 -3
  218. data/.data/spec/std/isa/param/VLEN.yaml +2 -0
  219. data/.data/spec/std/isa/profile/RVA20S64.yaml +11 -4
  220. data/.data/spec/std/isa/profile/RVA20U64.yaml +14 -5
  221. data/.data/spec/std/isa/profile/RVA22S64.yaml +14 -3
  222. data/.data/spec/std/isa/profile/RVA22U64.yaml +8 -1
  223. data/.data/spec/std/isa/profile/RVA23S64.yaml +13 -0
  224. data/.data/spec/std/isa/profile/RVA23U64.yaml +15 -1
  225. data/.data/spec/std/isa/profile/RVB23S64.yaml +15 -3
  226. data/.data/spec/std/isa/profile/RVB23U64.yaml +8 -1
  227. data/.data/spec/std/isa/profile/RVI20U32.yaml +8 -1
  228. data/.data/spec/std/isa/profile/RVI20U64.yaml +7 -0
  229. data/.data/spec/std/isa/register_file/F.yaml +3 -2
  230. data/.data/spec/std/isa/register_file/V.yaml +2 -2
  231. data/.data/spec/std/isa/register_file/X.yaml +2 -1
  232. data/lib/udb/architecture.rb +4 -25
  233. data/lib/udb/cfg_arch.rb +171 -59
  234. data/lib/udb/cli.rb +10 -1
  235. data/lib/udb/condition.rb +38 -37
  236. data/lib/udb/config.rb +72 -6
  237. data/lib/udb/logic.rb +29 -56
  238. data/lib/udb/obj/csr.rb +23 -5
  239. data/lib/udb/obj/csr_field.rb +36 -21
  240. data/lib/udb/obj/database_obj.rb +2 -5
  241. data/lib/udb/obj/extension.rb +0 -3
  242. data/lib/udb/obj/instruction.rb +1 -4
  243. data/lib/udb/obj/portfolio.rb +75 -20
  244. data/lib/udb/obj/profile.rb +0 -4
  245. data/lib/udb/obj/register_file.rb +63 -2
  246. data/lib/udb/portfolio_design.rb +3 -6
  247. data/lib/udb/resolver.rb +84 -23
  248. data/lib/udb/version.rb +1 -1
  249. data/lib/udb/version_spec.rb +8 -0
  250. data/lib/udb/z3.rb +23 -0
  251. data/lib/udb.rb +0 -3
  252. metadata +25 -37
  253. data/.data/cfgs/profile/RVA23M64.yaml +0 -159
  254. data/.data/cfgs/profile/RVB23M64.yaml +0 -149
  255. data/.data/spec/schemas/proc_cert_class_schema.json +0 -35
  256. data/.data/spec/schemas/proc_cert_model_schema.json +0 -336
  257. data/.data/spec/std/isa/proc_cert_class/AC.yaml +0 -13
  258. data/.data/spec/std/isa/proc_cert_class/MC.yaml +0 -13
  259. data/.data/spec/std/isa/proc_cert_class/RVI.yaml +0 -16
  260. data/.data/spec/std/isa/proc_cert_model/AC100.yaml +0 -72
  261. data/.data/spec/std/isa/proc_cert_model/AC200.yaml +0 -58
  262. data/.data/spec/std/isa/proc_cert_model/MC100-32.yaml +0 -155
  263. data/.data/spec/std/isa/proc_cert_model/MC100-64.yaml +0 -21
  264. data/.data/spec/std/isa/proc_cert_model/MC200-32.yaml +0 -60
  265. data/.data/spec/std/isa/proc_cert_model/MC200-64.yaml +0 -21
  266. data/.data/spec/std/isa/proc_cert_model/MC300-32.yaml +0 -40
  267. data/.data/spec/std/isa/proc_cert_model/MC300-64.yaml +0 -21
  268. data/.data/spec/std/isa/proc_cert_model/RVI20-32.yaml +0 -39
  269. data/.data/spec/std/isa/proc_cert_model/RVI20-64.yaml +0 -19
  270. data/.data/spec/std/isa/profile/RVA23M64.yaml +0 -24
  271. data/.data/spec/std/isa/profile/RVB23M64.yaml +0 -86
  272. data/lib/udb/cert_normative_rule.rb +0 -41
  273. data/lib/udb/obj/certifiable_obj.rb +0 -21
  274. data/lib/udb/obj/certificate.rb +0 -230
  275. data/lib/udb/proc_cert_design.rb +0 -77
data/lib/udb/cfg_arch.rb CHANGED
@@ -204,7 +204,19 @@ module Udb
204
204
  begin
205
205
  @symtab = create_symtab
206
206
 
207
- global_ast.add_global_symbols(@symtab)
207
+ # Guard against re-entrant solver calls from within add_global_symbols.
208
+ # Global initializers (e.g. FLEN) may call implemented?(), which triggers
209
+ # prohibited_ext?() and the Z3 solver chain. If those calls see @symtab is
210
+ # already set (partial), they'd use an incomplete symtab and fail.
211
+ # A depth counter (rather than a boolean) is used so that if this block
212
+ # ever nests (e.g. create_symtab is called recursively in the future),
213
+ # the inner ensure does not prematurely clear the guard for the outer block.
214
+ @constructing_symtab_depth = (@constructing_symtab_depth || 0) + 1
215
+ begin
216
+ global_ast.add_global_symbols(@symtab)
217
+ ensure
218
+ @constructing_symtab_depth -= 1
219
+ end
208
220
 
209
221
  @symtab.deep_freeze
210
222
  raise if @symtab.name.nil?
@@ -213,6 +225,11 @@ module Udb
213
225
  end
214
226
  end
215
227
 
228
+ # @return [Boolean] true while add_global_symbols is running inside symtab construction
229
+ # Used by implemented? callback to avoid triggering the Z3 solver on a partial symtab.
230
+ sig { returns(T::Boolean) }
231
+ def constructing_symtab? = (@constructing_symtab_depth || 0) > 0
232
+
216
233
  sig { returns(Idl::IsaAst) }
217
234
  def global_ast
218
235
  @global_ast ||=
@@ -277,7 +294,7 @@ module Udb
277
294
  reasons << "#{h.fetch("name")} is not a known extension"
278
295
  end
279
296
  if extensions.any? { |e| e.name == h.fetch("name") } && !T.must(extension(h.fetch("name"))).versions.any? { |v| v.version_spec == h.fetch("version") }
280
- reasons << "#{h.fetch("version")} is not a known extension"
297
+ reasons << "#{h.fetch("version")} is not a known version of extension #{h.fetch("name")}"
281
298
  end
282
299
  end
283
300
 
@@ -336,6 +353,8 @@ module Udb
336
353
  reasons += missing_params.map { |p| "Parameter is required but missing: '#{p.name}'" }
337
354
  end
338
355
 
356
+ validate_compatible(reasons)
357
+
339
358
  if reasons.empty?
340
359
  raise "bad validity check" unless to_condition.satisfiable?
341
360
  ValidationResult.new(valid: true, reasons:)
@@ -466,6 +485,8 @@ module Udb
466
485
  end
467
486
  end
468
487
 
488
+ validate_compatible(reasons)
489
+
469
490
  if reasons.empty?
470
491
  raise "Bad validation" unless to_condition.satisfiable?
471
492
  return ValidationResult.new(valid: true, reasons: [])
@@ -488,6 +509,11 @@ module Udb
488
509
  # we can know if it is implemented, but not if it's not implemented for a partially configured
489
510
  if ext?(ext_name)
490
511
  true
512
+ elsif constructing_symtab?
513
+ # During symtab construction (add_global_symbols), the Z3 solver is not
514
+ # available because the symtab is partial. Return nil (unknown) so that
515
+ # value_try falls back to storing the global with nil (no compile-time value).
516
+ nil
491
517
  elsif prohibited_ext?(ext_name)
492
518
  false
493
519
  else
@@ -504,6 +530,9 @@ module Udb
504
530
  # we can know if it is implemented, but not if it's not implemented for a partially configured
505
531
  if ext?(ext_name, [version])
506
532
  true
533
+ elsif constructing_symtab?
534
+ # Same guard as for implemented? above.
535
+ nil
507
536
  elsif prohibited_ext?(ext_name)
508
537
  false
509
538
  else
@@ -583,6 +612,33 @@ module Udb
583
612
  end
584
613
  pb.finish
585
614
 
615
+ # Build a bootstrap symtab and compute RF max widths before constructing the real
616
+ # symtab. The bootstrap needs add_global_symbols so that implemented?() is a known
617
+ # function (required for type_check to pass). Running it under @constructing_symtab=true
618
+ # ensures implemented?() returns nil → value_error during value evaluation, which
619
+ # causes TernaryOperatorExpressionAst#max_value to explore both branches.
620
+ bootstrap_st = Idl::SymbolTable.new(
621
+ mxlen:,
622
+ builtin_global_vars: final_param_vars,
623
+ builtin_enums: symtab_enums,
624
+ builtin_funcs: symtab_callbacks,
625
+ params: all_params,
626
+ name: "#{@name}/bootstrap",
627
+ register_files: []
628
+ )
629
+ rf_max_widths = begin
630
+ @constructing_symtab_depth = (@constructing_symtab_depth || 0) + 1
631
+ global_ast.add_global_symbols(bootstrap_st)
632
+ register_files.each_with_object({}) do |rf, h|
633
+ node = @idl_compiler.compile_expression(rf.register_length_expr, bootstrap_st, pass_error: true)
634
+ max = node.max_value(bootstrap_st)
635
+ raise "Cannot determine max width for register file '#{rf.name}'" if max == :unknown
636
+ h[rf.name] = Integer(max)
637
+ end
638
+ ensure
639
+ @constructing_symtab_depth -= 1
640
+ end
641
+
586
642
  Idl::SymbolTable.new(
587
643
  mxlen:,
588
644
  possible_xlens_cb: proc { possible_xlens },
@@ -591,7 +647,9 @@ module Udb
591
647
  builtin_enums: symtab_enums,
592
648
  name: @name,
593
649
  csrs:,
594
- params: all_params
650
+ params: all_params,
651
+ register_files: register_files,
652
+ register_file_max_widths: rf_max_widths
595
653
  )
596
654
  end
597
655
  private :create_symtab
@@ -665,6 +723,12 @@ module Udb
665
723
  # @param name [String] The $1 name
666
724
  # @return [$3] The $1
667
725
  # @return [nil] if there is no $1 named +name+
726
+ # Class-level cache of raw YAML file contents keyed by "#{resolved_spec_path}/#{obj_type_dir}".
727
+ # Maps each directory to an array of [content, original_path, realpath] triples so that a
728
+ # second ConfiguredArchitecture sharing the same spec path skips disk I/O and file locking.
729
+ # Benign race: two threads both missing the cache produce identical entries.
730
+ @@yaml_data_cache = Concurrent::Hash.new
731
+
668
732
  sig { params(fn_name: String, arch_dir: String, obj_class: T.class_of(TopLevelDatabaseObject)).void }
669
733
  def self.generate_obj_methods(fn_name, arch_dir, obj_class)
670
734
 
@@ -675,12 +739,25 @@ module Udb
675
739
 
676
740
  @objects[arch_dir] = Concurrent::Array.new
677
741
  @object_hashes[arch_dir] = Concurrent::Hash.new
678
- Dir.glob(@arch_dir / arch_dir / "**" / "*.yaml") do |obj_path|
679
- f = File.open(obj_path)
680
- f.flock(File::LOCK_EX)
681
- obj_yaml = YAML.load(f.read, filename: obj_path, permitted_classes: [Date])
682
- f.flock(File::LOCK_UN)
683
- @objects[arch_dir] << obj_class.new(obj_yaml, Pathname.new(obj_path).realpath, T.cast(self, ConfiguredArchitecture))
742
+
743
+ yaml_cache_key = "#{@arch_dir}/#{arch_dir}"
744
+ cached_files = @@yaml_data_cache[yaml_cache_key]
745
+ if cached_files.nil?
746
+ entries = []
747
+ Dir.glob(@arch_dir / arch_dir / "**" / "*.yaml") do |obj_path|
748
+ File.open(obj_path) do |f|
749
+ f.flock(File::LOCK_EX)
750
+ content = f.read
751
+ f.flock(File::LOCK_UN)
752
+ entries << [content, obj_path, Pathname.new(obj_path).realpath]
753
+ end
754
+ end
755
+ cached_files = @@yaml_data_cache[yaml_cache_key] = entries
756
+ end
757
+
758
+ cached_files.each do |content, obj_path, realpath|
759
+ obj_yaml = YAML.load(content, filename: obj_path, permitted_classes: [Date])
760
+ @objects[arch_dir] << obj_class.new(obj_yaml, realpath, T.cast(self, ConfiguredArchitecture))
684
761
  @object_hashes[arch_dir][@objects[arch_dir].last.name] = @objects[arch_dir].last
685
762
  end
686
763
  @objects[arch_dir]
@@ -714,43 +791,28 @@ module Udb
714
791
  # @param io where to write progress bars
715
792
  # @return [void]
716
793
  sig { params(show_progress: T::Boolean, io: IO).void }
717
- def type_check(show_progress: true, io: $stdout)
794
+ def type_check(show_progress: true, io: $stderr)
718
795
  io.puts "Type checking IDL code for #{@config.name}..." if show_progress
719
796
  insts = @config.unconfigured? ? instructions : possible_instructions(show_progress:)
720
797
  xlens = @config.unconfigured? ? [32, 64] : possible_xlens
721
798
 
722
799
  progressbar =
723
800
  if show_progress
724
- TTY::ProgressBar.new("type checking possible instructions [:bar] :current/:total", total: insts.size, output: $stdout)
801
+ TTY::ProgressBar.new("type checking possible instructions [:bar] :current/:total", total: insts.size, output: io)
725
802
  end
726
803
 
727
804
  insts.each do |inst|
728
805
  progressbar.advance if show_progress
729
806
  if @mxlen == 32
730
807
  if inst.rv32?
731
- op_ast = inst.operation_ast
732
- unless op_ast.nil?
733
- s = inst.fill_symtab(32, op_ast)
734
- op_ast.prune(s).type_check(s, strict: true)
735
- s.release
736
- end
808
+ inst.pruned_operation_ast(32)
737
809
  end
738
810
  else
739
811
  if inst.rv64?
740
- op_ast = inst.operation_ast
741
- unless op_ast.nil?
742
- s = inst.fill_symtab(64, op_ast)
743
- op_ast.prune(s).type_check(s, strict: true)
744
- s.release
745
- end
812
+ inst.pruned_operation_ast(64)
746
813
  end
747
814
  if xlens.include?(32) && inst.rv32?
748
- op_ast = inst.operation_ast
749
- unless op_ast.nil?
750
- s = inst.fill_symtab(32, op_ast)
751
- op_ast.prune(s).type_check(s, strict: true)
752
- s.release
753
- end
815
+ inst.pruned_operation_ast(32)
754
816
  end
755
817
  end
756
818
  end
@@ -758,7 +820,7 @@ module Udb
758
820
  csr_list = @config.unconfigured? ? csrs : possible_csrs
759
821
  progressbar =
760
822
  if show_progress
761
- TTY::ProgressBar.new("type checking CSRs [:bar]", total: csr_list.size, output: $stdout)
823
+ TTY::ProgressBar.new("type checking CSRs [:bar] :current/:total", total: csr_list.size, output: io)
762
824
  end
763
825
 
764
826
  csr_list.each do |csr|
@@ -769,53 +831,35 @@ module Udb
769
831
 
770
832
  if csr.has_custom_sw_read?
771
833
  if (xlens.include?(32) && csr_in_base32)
772
- s = csr.fill_symtab(nil, 32)
773
- csr.sw_read_ast(s).prune(s).type_check(s, strict: true)
774
- s.release
834
+ csr.type_checked_pruned_sw_read_ast(32)
775
835
  end
776
836
  if (xlens.include?(64) && csr_in_base64)
777
- s = csr.fill_symtab(nil, 64)
778
- csr.sw_read_ast(s).prune(s).type_check(s, strict: true)
779
- s.release
837
+ csr.type_checked_pruned_sw_read_ast(64)
780
838
  end
781
839
  end
782
840
  csr.possible_fields.each do |field|
783
- reset_ast = field.reset_value_ast
784
- unless reset_ast.nil?
841
+ if field.reset_value_ast
785
842
  if xlens.include?(32) && csr_in_base32 && field.defined_in_base32?
786
- s = field.fill_symtab_for_reset(nil)
787
- reset_ast.prune(s).type_check(s, strict: true)
788
- s.release
843
+ field.pruned_reset_value_ast
789
844
  end
790
845
  if xlens.include?(64) && csr_in_base64 && field.defined_in_base64?
791
- s = field.fill_symtab_for_reset(nil)
792
- reset_ast.prune(s).type_check(s, strict: true)
793
- s.release
846
+ field.pruned_reset_value_ast
794
847
  end
795
848
  end
796
849
  if field.has_custom_sw_write?
797
850
  if xlens.include?(32) && csr_in_base32 && field.defined_in_base32?
798
- s = field.fill_symtab_for_sw_write(32, nil)
799
- field.sw_write_ast(s).prune(s).type_check(s, strict: true)
800
- s.release
851
+ field.pruned_sw_write_ast(32)
801
852
  end
802
853
  if xlens.include?(64) && csr_in_base64 && field.defined_in_base64?
803
- s = field.fill_symtab_for_sw_write(64, nil)
804
- field.sw_write_ast(s).prune(s).type_check(s, strict: true)
805
- s.release
854
+ field.pruned_sw_write_ast(64)
806
855
  end
807
856
  end
808
- type_ast = field.type_ast
809
- unless type_ast.nil?
857
+ if field.type_ast
810
858
  if xlens.include?(32) && csr_in_base32 && field.defined_in_base32?
811
- s = field.fill_symtab_for_type(32, nil)
812
- type_ast.prune(s).type_check(s, strict: true)
813
- s.release
859
+ field.pruned_type_ast(32)
814
860
  end
815
861
  if xlens.include?(64) && csr_in_base64 && field.defined_in_base64?
816
- s = field.fill_symtab_for_type(64, nil)
817
- type_ast.prune(s).type_check(s, strict: true)
818
- s.release
862
+ field.pruned_type_ast(64)
819
863
  end
820
864
  end
821
865
  end
@@ -824,7 +868,7 @@ module Udb
824
868
  func_list = @config.unconfigured? ? functions : reachable_functions(show_progress:)
825
869
  progressbar =
826
870
  if show_progress
827
- TTY::ProgressBar.new("type checking functions [:bar]", total: func_list.size, output: $stdout)
871
+ TTY::ProgressBar.new("type checking functions [:bar] :current/:total", total: func_list.size, output: io)
828
872
  end
829
873
  func_list.each do |func|
830
874
  progressbar.advance if show_progress
@@ -1080,6 +1124,21 @@ module Udb
1080
1124
  end
1081
1125
  end
1082
1126
 
1127
+ # @return [Hash<String, Array<ExtensionVersion>>] possible_extension_versions grouped by name
1128
+ def possible_extension_versions_by_name
1129
+ @possible_extension_versions_by_name ||=
1130
+ possible_extension_versions.group_by(&:name)
1131
+ end
1132
+
1133
+ # Memoized Z3 satisfiability result for a ParameterTerm against this cfg_arch.
1134
+ # Keyed by ParameterTerm (uses hash/eql? based on yaml_no_reason), so identical
1135
+ # terms across different Condition objects share the same Z3 result.
1136
+ #
1137
+ # @return [Hash<ParameterTerm, SatisfiedResult>]
1138
+ def param_term_satisfied_memo
1139
+ @param_term_satisfied_memo ||= {}
1140
+ end
1141
+
1083
1142
  # @overload prohibited_ext?(ext)
1084
1143
  # Returns true if the ExtensionVersion +ext+ is prohibited
1085
1144
  # @param ext [ExtensionVersion] An extension version
@@ -1740,5 +1799,58 @@ module Udb
1740
1799
  end
1741
1800
  end
1742
1801
 
1802
+ sig { params(pointer: String).returns(ConfiguredArchitecture) }
1803
+ def resolve_compatible_pointer(pointer)
1804
+ @config.info.resolver.cfg_arch_for_pointer(
1805
+ pointer,
1806
+ relative_dir: Pathname.new(@config.info.path).dirname
1807
+ )
1808
+ end
1809
+ private :resolve_compatible_pointer
1810
+
1811
+ sig { params(other: ConfiguredArchitecture, reasons: T::Array[String], visited: T::Set[String]).void }
1812
+ def check_compatible_with(other, reasons, visited)
1813
+ return if visited.include?(other.name)
1814
+ visited.add(other.name)
1815
+
1816
+ combined = to_condition & other.to_condition
1817
+ unless combined.satisfiable_by_cfg_arch?(self)
1818
+ combined.to_logic_tree(expand: true).minimal_unsat_subsets.each do |min|
1819
+ reasons << "Config '#{name}' is not compatible with '#{other.name}': not satisfiable: #{min.to_s(format: LogicNode::LogicSymbolFormat::C)}"
1820
+ end
1821
+ end
1822
+
1823
+ # Resolve transitive pointers relative to `other`'s directory, not self's.
1824
+ Array(other.config.compatible).each do |pointer|
1825
+ begin
1826
+ trans = other.send(:resolve_compatible_pointer, pointer)
1827
+ check_compatible_with(trans, reasons, visited)
1828
+ rescue => e
1829
+ reasons << "Cannot resolve transitive compatible pointer '#{pointer}': #{e.message}"
1830
+ end
1831
+ end
1832
+ end
1833
+ private :check_compatible_with
1834
+
1835
+ sig { params(reasons: T::Array[String]).void }
1836
+ def validate_compatible(reasons)
1837
+ return if @config.compatible.nil?
1838
+
1839
+ # Use dup per top-level pointer so sibling pointers each get a fresh visited set —
1840
+ # each branch independently validates against any shared transitive targets. Cycle
1841
+ # detection within a single chain is still enforced because visited mutates in-place
1842
+ # during the recursive descent.
1843
+ visited = T.let(Set.new([name]), T::Set[String])
1844
+ Array(@config.compatible).each do |pointer|
1845
+ begin
1846
+ other = resolve_compatible_pointer(pointer)
1847
+ check_compatible_with(other, reasons, visited.dup)
1848
+ rescue => e
1849
+ reasons << "Cannot resolve compatible pointer '#{pointer}': #{e.message}"
1850
+ end
1851
+ end
1852
+ end
1853
+ private :validate_compatible
1854
+
1743
1855
  end
1744
1856
  end
data/lib/udb/cli.rb CHANGED
@@ -82,17 +82,21 @@ module Udb
82
82
  method_option :custom, type: :string, desc: "Path to custom specification directory, if needed", default: Udb.default_custom_isa_path.to_s
83
83
  method_option :config_dir, type: :string, desc: "Path to directory with config files", default: Udb.default_cfgs_path.to_s
84
84
  method_option :gen, type: :string, desc: "Path to folder used for generation", default: Udb.default_gen_path.to_s
85
+ method_option :strict_partial, type: :boolean, desc: "Whether or not to check if a partial config is fully specified -- that is, all requirements of a mandatory extension are also listed in mandatory extensions and/or parameters", default: false
85
86
  method_option :z3parallel, type: :boolean, desc: "Use parallel.enable for Z3", default: true
86
87
  def cfg(name_or_path)
87
88
  raise ArgumentError, "Spec directory does not exist: #{options[:std]}" unless File.directory?(options[:std])
88
89
 
89
90
  Udb.global_options.parallel_z3 = options[:z3parallel]
90
91
 
92
+
91
93
  cfg_file =
92
94
  if File.file?(name_or_path)
93
95
  Pathname.new(name_or_path)
94
96
  elsif File.file?("#{options[:config_dir]}/#{name_or_path}.yaml")
95
97
  Pathname.new("#{options[:config_dir]}/#{name_or_path}.yaml")
98
+ elsif File.file?("#{options[:config_dir]}/profile/#{name_or_path}.yaml")
99
+ Pathname.new("#{options[:config_dir]}/profile/#{name_or_path}.yaml")
96
100
  else
97
101
  raise ArgumentError, "Cannot find config: #{name_or_path}"
98
102
  end
@@ -108,7 +112,12 @@ module Udb
108
112
  say "Config is #{pastel.red.bold("invalid")}"
109
113
  exit 1
110
114
  end
111
- result = cfg_arch.valid?
115
+ result =
116
+ if options[:strict_partial]
117
+ cfg_arch.partial_config_strictly_specified?
118
+ else
119
+ cfg_arch.valid?
120
+ end
112
121
 
113
122
  if result.valid
114
123
  say "Config #{pastel.bold(cfg_arch.name)} is #{pastel.green.bold("valid")}"
data/lib/udb/condition.rb CHANGED
@@ -432,10 +432,6 @@ module Udb
432
432
  end
433
433
  end
434
434
 
435
- class MemoizedState < T::Struct
436
- prop :satisfied_by_cfg_arch, T::Hash[ConfiguredArchitecture, SatisfiedResult]
437
- end
438
-
439
435
  sig {
440
436
  params(
441
437
  yaml: T.any(T::Hash[String, T.untyped], T::Boolean),
@@ -450,7 +446,7 @@ module Udb
450
446
  @cfg_arch = cfg_arch
451
447
  @input_file = input_file
452
448
  @input_line = input_line
453
- @memo = MemoizedState.new(satisfied_by_cfg_arch: {})
449
+ @satisfied_by_cfg_arch_memo = T.let({}, T::Hash[ConfiguredArchitecture, SatisfiedResult])
454
450
  end
455
451
 
456
452
  sig { override.returns(T::Boolean) }
@@ -1103,7 +1099,7 @@ module Udb
1103
1099
 
1104
1100
  sig { override.params(cfg_arch: ConfiguredArchitecture).returns(SatisfiedResult) }
1105
1101
  def satisfied_by_cfg_arch?(cfg_arch)
1106
- @memo.satisfied_by_cfg_arch[cfg_arch] ||=
1102
+ @satisfied_by_cfg_arch_memo[cfg_arch] ||=
1107
1103
  if cfg_arch.fully_configured?
1108
1104
  implemented_ext_cb = make_cb_proc do |term|
1109
1105
  if term.is_a?(ExtensionTerm)
@@ -1115,18 +1111,7 @@ module Udb
1115
1111
  elsif term.is_a?(ParameterTerm)
1116
1112
  if cfg_arch.param_values.key?(term.name)
1117
1113
  result = term.eval(cfg_arch)
1118
- if result == SatisfiedResult::Maybe
1119
- # this might just mean we don't know the value.
1120
- # however, given the parameter schema and constraints, we could know that term is
1121
- # always false
1122
- if (Condition.new({ "param" => term.to_h }, cfg_arch) & cfg_arch.to_condition).unsatisfiable?
1123
- result = SatisfiedResult::No
1124
-
1125
- # or always true
1126
- elsif (-Condition.new({ "param" => term.to_h }, cfg_arch) & cfg_arch.to_condition).unsatisfiable?
1127
- result = SatisfiedResult::Yes
1128
- end
1129
- end
1114
+ result = resolve_param_term_from_maybe(term, cfg_arch) if result == SatisfiedResult::Maybe
1130
1115
  result
1131
1116
  else
1132
1117
  SatisfiedResult::No
@@ -1155,27 +1140,17 @@ module Udb
1155
1140
  elsif cfg_arch.partially_configured?
1156
1141
  cb = make_cb_proc do |term|
1157
1142
  if term.is_a?(ExtensionTerm)
1158
- if cfg_arch.mandatory_extension_reqs.any? { |cfg_ext_req| term.to_ext_req(cfg_arch).satisfied_by?(cfg_ext_req) }
1143
+ ext_req = term.to_ext_req(cfg_arch)
1144
+ if cfg_arch.mandatory_extension_reqs.any? { |cfg_ext_req| ext_req.satisfied_by?(cfg_ext_req) }
1159
1145
  SatisfiedResult::Yes
1160
- elsif cfg_arch.possible_extension_versions.any? { |cfg_ext_ver| term.to_ext_req(cfg_arch).satisfied_by?(cfg_ext_ver) }
1146
+ elsif (cfg_arch.possible_extension_versions_by_name[term.name] || []).any? { |cfg_ext_ver| ext_req.satisfied_by?(cfg_ext_ver) }
1161
1147
  SatisfiedResult::Maybe
1162
1148
  else
1163
1149
  SatisfiedResult::No
1164
1150
  end
1165
1151
  elsif term.is_a?(ParameterTerm)
1166
1152
  result = term.eval(cfg_arch)
1167
- if result == SatisfiedResult::Maybe
1168
- # this might just mean we don't know the value.
1169
- # however, given the parameter schema and constraints, we could know that term is
1170
- # always false
1171
- if (Condition.new({ "param" => term.to_h }, cfg_arch) & cfg_arch.to_condition).unsatisfiable?
1172
- result = SatisfiedResult::No
1173
-
1174
- # or always true
1175
- elsif (-Condition.new({ "param" => term.to_h }, cfg_arch) & cfg_arch.to_condition).unsatisfiable?
1176
- result = SatisfiedResult::Yes
1177
- end
1178
- end
1153
+ result = resolve_param_term_from_maybe(term, cfg_arch) if result == SatisfiedResult::Maybe
1179
1154
  result
1180
1155
  elsif term.is_a?(FreeTerm)
1181
1156
  raise "unreachable"
@@ -1232,7 +1207,8 @@ module Udb
1232
1207
  if node.type == LogicNodeType::Term
1233
1208
  term = node.children.fetch(0)
1234
1209
  if term.is_a?(ExtensionTerm)
1235
- if ext_reqs.any? { |ext_req| term.to_ext_req(@cfg_arch).satisfied_by?(ext_req) }
1210
+ term_ext_req = term.to_ext_req(@cfg_arch)
1211
+ if ext_reqs.any? { |ext_req| term_ext_req.satisfied_by?(ext_req) }
1236
1212
  next LogicNode::True
1237
1213
  end
1238
1214
  end
@@ -1277,9 +1253,10 @@ module Udb
1277
1253
  SatisfiedResult::Yes
1278
1254
  end
1279
1255
  elsif cfg_arch.partially_configured?
1280
- if cfg_arch.mandatory_extension_reqs.any? { |cfg_ext_req| term.to_ext_req(cfg_arch).satisfied_by?(cfg_ext_req) }
1256
+ ext_req = term.to_ext_req(cfg_arch)
1257
+ if cfg_arch.mandatory_extension_reqs.any? { |cfg_ext_req| ext_req.satisfied_by?(cfg_ext_req) }
1281
1258
  SatisfiedResult::Yes
1282
- elsif cfg_arch.possible_extension_versions.any? { |cfg_ext_ver| term.to_ext_req(cfg_arch).satisfied_by?(cfg_ext_ver) }
1259
+ elsif (cfg_arch.possible_extension_versions_by_name[term.name] || []).any? { |cfg_ext_ver| ext_req.satisfied_by?(cfg_ext_ver) }
1283
1260
  SatisfiedResult::Maybe
1284
1261
  else
1285
1262
  SatisfiedResult::No
@@ -1329,9 +1306,10 @@ module Udb
1329
1306
  SatisfiedResult::Yes
1330
1307
  end
1331
1308
  elsif cfg_arch.partially_configured?
1332
- if cfg_arch.mandatory_extension_reqs.any? { |cfg_ext_req| term.to_ext_req(cfg_arch).satisfied_by?(cfg_ext_req) }
1309
+ ext_req = term.to_ext_req(cfg_arch)
1310
+ if cfg_arch.mandatory_extension_reqs.any? { |cfg_ext_req| ext_req.satisfied_by?(cfg_ext_req) }
1333
1311
  SatisfiedResult::Yes
1334
- elsif cfg_arch.possible_extension_versions.any? { |cfg_ext_ver| term.to_ext_req(cfg_arch).satisfied_by?(cfg_ext_ver) }
1312
+ elsif (cfg_arch.possible_extension_versions_by_name[term.name] || []).any? { |cfg_ext_ver| ext_req.satisfied_by?(cfg_ext_ver) }
1335
1313
  SatisfiedResult::Maybe
1336
1314
  else
1337
1315
  SatisfiedResult::No
@@ -1645,6 +1623,27 @@ module Udb
1645
1623
  def -@
1646
1624
  Condition.not(self, @cfg_arch)
1647
1625
  end
1626
+
1627
+ private
1628
+
1629
+ # When term.eval returns Maybe, check whether the parameter schema and constraints
1630
+ # imply the term is always false or always true, and cache the result per (term, cfg_arch).
1631
+ sig { params(term: ParameterTerm, cfg_arch: ConfiguredArchitecture).returns(SatisfiedResult) }
1632
+ def resolve_param_term_from_maybe(term, cfg_arch)
1633
+ memo = cfg_arch.param_term_satisfied_memo
1634
+ unless memo.key?(term)
1635
+ param_cond = Condition.new({ "param" => term.to_h }, cfg_arch)
1636
+ memo[term] =
1637
+ if param_cond.unsatisfiable_by_cfg_arch?(cfg_arch)
1638
+ SatisfiedResult::No
1639
+ elsif (-param_cond).unsatisfiable_by_cfg_arch?(cfg_arch)
1640
+ SatisfiedResult::Yes
1641
+ else
1642
+ SatisfiedResult::Maybe
1643
+ end
1644
+ end
1645
+ memo[term]
1646
+ end
1648
1647
  end
1649
1648
 
1650
1649
  class LogicCondition < Condition
@@ -1654,6 +1653,7 @@ module Udb
1654
1653
  @logic_node = logic_node
1655
1654
  @cfg_arch = cfg_arch
1656
1655
  @yaml = logic_node.to_h
1656
+ @satisfied_by_cfg_arch_memo = T.let({}, T::Hash[ConfiguredArchitecture, SatisfiedResult])
1657
1657
  end
1658
1658
 
1659
1659
  sig { override.returns(T::Boolean) }
@@ -2040,6 +2040,7 @@ module Udb
2040
2040
  sig { params(xlen: Integer).void }
2041
2041
  def initialize(xlen)
2042
2042
  @xlen = xlen
2043
+ @satisfied_by_cfg_arch_memo = T.let({}, T::Hash[ConfiguredArchitecture, SatisfiedResult])
2043
2044
  end
2044
2045
 
2045
2046
  sig { override.returns(LogicNode) }