{"id":153,"date":"2026-08-12T00:59:28","date_gmt":"2026-08-11T19:29:28","guid":{"rendered":"https:\/\/www.sushantmondal.com\/blog\/?p=153"},"modified":"2026-08-18T08:22:29","modified_gmt":"2026-08-18T02:52:29","slug":"renvatek-quartz-1-passes-all-39-risc-v-act4-architectural-compliance-tests","status":"publish","type":"post","link":"https:\/\/www.sushantmondal.com\/blog\/2026\/08\/12\/renvatek-quartz-1-passes-all-39-risc-v-act4-architectural-compliance-tests\/","title":{"rendered":"Renvatek Quartz-1 passes all 39 RISC-V ACT4 architectural compliance tests"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">What&#8217;s Renvatek and this core about?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">On this month&#8217;s very first day, I bought two .com domains: <a href=\"https:\/\/www.renvatek.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">renvatek.com<\/a> (canonical) and <a href=\"https:\/\/www.renvatech.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">renvatech.com<\/a> (redirect). Pretty sure the name &#8220;Renvatek&#8221; is pronounceable by almost everyone (hopefully). From now on, the entity &#8220;Renvatek&#8221; will serve as my in-house computational-cores designing powerhouse!<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">And the good news is that I have completed the RTL development and the verification for its very first core, the Renvatek Quartz-1! Heads up, this post is going to be about verification and compliance details of this core entirely.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Renvatek Quartz-1 (QE001001RV32IN0), my single-cycle RV32I core, just passed all 39 RISC-V ACT4 architectural compliance tests. <strong>100% pass rate on the very first shot.<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Here&#8217;s what that took, and what actually went wrong along the way.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What ACT4 tests<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">ACT4 is the official RISC-V Architectural Certification Test framework, maintained by the RISC-V Foundation at <a href=\"https:\/\/github.com\/riscv\/riscv-arch-test\/tree\/act4\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">riscv\/riscv-arch-test<\/a>. For the RV32I base ISA, there are 39 self-checking test programs, one per instruction or instruction group, covering the entire base instruction set: arithmetic, branches, jumps, loads, stores, shifts, and comparisons.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Each test&#8217;s expected result is pre-computed by <a href=\"https:\/\/github.com\/riscv\/sail-riscv\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">Sail<\/a>, the Foundation&#8217;s reference model, and baked into the ELF at build time. So no live reference model is running alongside my CPU during simulation. My hardware computes a result, checks it against what Sail already decided the answer should be, and either matches or fails right there.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I ran this against <a href=\"https:\/\/github.com\/riscv\/riscv-arch-test\/tree\/5590e5c64a2ae83a0e4e29a20c3043676c02668f\" target=\"_blank\" rel=\"noreferrer noopener nofollow\"><code class=\"\" data-line=\"\">riscv-arch-test<\/code> commit <code class=\"\" data-line=\"\">5590e5c64a2ae83a0e4e29a20c3043676c02668f<\/code><\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Why this matters<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Architectural compliance means Quartz-1 implements RV32I as the spec says it should, instruction by instruction, and is checked against the same reference model the RISC-V Foundation uses. That&#8217;s the baseline any RISC-V core needs before anyone should trust it with real work, and it matters even more for something aimed at defense-grade, radiation-tolerant silicon (future to-do).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The messy part<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Getting the core to run was one thing. Getting an actual verification flow around it was a different problem.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I started by wiring the core into Verilator and Cocotb. The first test was deliberately simple: <code class=\"\" data-line=\"\">echo_ascii_chars<\/code> (harnessing the virtual printer @ a print port register (IO): <a href=\"https:\/\/github.com\/riscv\/riscv-arch-test\/blob\/5590e5c64a2ae83a0e4e29a20c3043676c02668f\/config\/cores\/cve2\/cv32e20\/rvmodel_macros.h#L55-L76\" target=\"_blank\" rel=\"noreferrer noopener nofollow\"><code class=\"\" data-line=\"\">RVMODEL_IO_WRITE_STR<\/code> macro @ <code class=\"\" data-line=\"\">rvmodel_macros.h<\/code><\/a>). Verilator was able to build the whole <code class=\"\" data-line=\"\">rv32i_sc<\/code> design and cocotb started correctly. The test itself passed, but there was already a warning sitting in the output:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">%Warning: imem_program.bin:0: $readmem file not found<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The test still reported <code class=\"\" data-line=\"\">PASS<\/code>, which made the result a little misleading. At that point I was not yet running an architecture test through the instruction memory. I had a simulator that worked, but I did not yet have a useful compliance flow.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The next problem was getting the RISC-V Architecture Tests framework running. I ended up dealing with the framework&#8217;s Python environment, <code class=\"\" data-line=\"\">uv<\/code>, the generated test infrastructure, the <a href=\"https:\/\/github.com\/riscv\/riscv-unified-db\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">Unified Database<\/a> tooling (<code class=\"\" data-line=\"\">udb<\/code>), and the different branches of <code class=\"\" data-line=\"\">riscv-arch-test<\/code>. There were several attempts at this. At one point I had switched between <code class=\"\" data-line=\"\">main<\/code>, <code class=\"\" data-line=\"\">act4<\/code> and <a href=\"https:\/\/github.com\/jordancarlin\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">Jordan Carlin<\/a>&#8216;s <code class=\"\" data-line=\"\">import_module_refactor<\/code> branch while trying to get the new test-generation code working. The <code class=\"\" data-line=\"\">testgen<\/code> package itself was failing during module discovery because of a circular import involving <code class=\"\" data-line=\"\">vector_helpers.py<\/code> and <code class=\"\" data-line=\"\">vv_type.py<\/code>. I flagged this issue @ <a href=\"https:\/\/github.com\/riscv\/riscv-arch-test\/issues\/2061\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">#2061<\/a>, which was fixed by Carlin (PR <a href=\"https:\/\/github.com\/riscv\/riscv-arch-test\/pull\/2065\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">#2065<\/a>) and merged to upstream.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Eventually the framework got far enough to generate the test infrastructure. The output showed 177 test suites being generated, one DUT configuration being prepared, and 195 build targets already up to date. That was the first point where the compliance framework was actually doing something substantial with my core instead of just compiling the simulator.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Then I had to figure out how to get the generated ELF files into my very specific memory model. The architecture tests produce ELF binaries, while my core expects its instruction memory in a binary format that can be consumed by <code class=\"\" data-line=\"\">$readmem<\/code>. I wrote a runner that finds every generated ELF, extracts the relevant <code class=\"\" data-line=\"\">.text<\/code> sections with <code class=\"\" data-line=\"\">riscv32-unknown-elf-objcopy<\/code>, converts the resulting bytes into the bit ordering expected by my instruction memory, and writes them to <code class=\"\" data-line=\"\">imem_program.bin<\/code>. I also extract <code class=\"\" data-line=\"\">.rodata<\/code>, <code class=\"\" data-line=\"\">.data<\/code> and <code class=\"\" data-line=\"\">.bss<\/code> into a Verilog-format data-memory initialization file. Each test gets its own temporary directory so that the generated memory files do not collide with one another. Refs: <a href=\"https:\/\/github.com\/riscv\/riscv-arch-test\/blob\/5590e5c64a2ae83a0e4e29a20c3043676c02668f\/config\/cores\/cve2\/cv32e20\/link.ld\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">link.ld<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That runner had its own problems.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Because the scripts use <code class=\"\" data-line=\"\">set -euo pipefail<\/code>, an unset <code class=\"\" data-line=\"\">PYTHONPATH<\/code> immediately killed the run with:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">PYTHONPATH: unbound variable<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">After fixing that, the simulator started launching, but cocotb could not load <code class=\"\" data-line=\"\">libpython3.13.so<\/code>. The simulator would start, print the cocotb\/VPI messages, and then finish, but the actual Python test environment could not be loaded.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">There were also smaller environment problems along the way. Running the compliance script before activating the correct environment produced <code class=\"\" data-line=\"\">cocotb-config: No such file or directory<\/code>. The Python environment being used by the shell and the <code class=\"\" data-line=\"\">.venv<\/code> expected by <code class=\"\" data-line=\"\">riscv-arch-test<\/code> also kept disagreeing, which showed up repeatedly as <code class=\"\" data-line=\"\">VIRTUAL_ENV<\/code> warnings. I had to keep untangling whether a failure was coming from my RTL, cocotb, Verilator, the architecture-test framework, Python, or simply the shell environment.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That is probably the least glamorous part of building a CPU. At this stage, very little of the debugging was actually about the datapath. I was debugging the machinery around the datapath so that I could eventually trust the tests being run against it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The useful part is that the pieces are now separated. The architecture-test framework generates the tests, the ELF files are converted into the memory format my core expects, the runner launches the compiled Verilator model, and cocotb provides the interface between the test environment and the RTL. That gives me a path from an architectural test case all the way down to instructions actually being executed by my core.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">A personal note<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">It&#8217;s been almost six months of RTL work (started late February this year), and this is the first result that felt real. Not &#8220;it compiled.&#8221; Not &#8220;it ran once and looked okay.&#8221; A test suite I didn&#8217;t write, checked against a reference model I don&#8217;t control, and every single case passed. The confusion at the start wasn&#8217;t wasted time. Having to trace the framework by hand is exactly what made the pass mean something.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Next up are the pipelined variants, and eventually taking this from architectural correctness to radiation-hardened silicon. For today, though, I&#8217;m just sitting with this one :-).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Video proof<\/h2>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"Renvatek Quartz-1 passes all 39 RISC-V ACT4 architectural compliance tests\" width=\"500\" height=\"281\" src=\"https:\/\/www.youtube.com\/embed\/OP7DoQ6LS8w?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Do you also want to test this core by yourself?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Third-party verification is the best thing I could ask for. For this, you have to clone <a href=\"https:\/\/github.com\/renvatek\/verify-core-quartz-1\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">the verification repository<\/a> first.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Then execute the following commands to verify this core using its simulated binary version:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\" data-line=\"\">cd compliance\nchmod +x main.sh\n.\/main.sh<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">End note<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Quartz-1 is my first CPU core, and getting it from RTL to a point where someone else can actually run the verification suite was a big part of the process. There were plenty of rough edges along the way, especially around the verification setup, but getting the ACT4 tests passing and packaging the verification environment into something reproducible was a good milestone.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This is only the beginning for Renvatek and for the cores that come after Quartz-1.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Thanks for taking the time to read through the process.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>What&#8217;s Renvatek and this core about? On this month&#8217;s very first day, I bought two .com domains: renvatek.com (canonical) and renvatech.com (redirect). Pretty sure the name &#8220;Renvatek&#8221; is pronounceable by almost everyone (hopefully). From now on, the entity &#8220;Renvatek&#8221; will serve as my in-house computational-cores designing powerhouse! And the good news is that I have [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":154,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"pagelayer_contact_templates":[],"_pagelayer_content":"","inline_featured_image":false,"_jetpack_newsletter_access":"everybody","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[9],"tags":[27,32,31,34,29,33,30,13,28,10,11],"class_list":["post-153","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-hardware","tag-act4","tag-compliance","tag-core","tag-hdl","tag-renvatek","tag-renvatek-qe111rv32i1","tag-renvatek-quartz-1","tag-risc-v","tag-riscv-arch-test","tag-rtl","tag-systemverilog"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"https:\/\/www.sushantmondal.com\/blog\/wp-content\/uploads\/2026\/08\/renvatek-quartz-1-act4-100-percent-compliance.png","_links":{"self":[{"href":"https:\/\/www.sushantmondal.com\/blog\/wp-json\/wp\/v2\/posts\/153","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.sushantmondal.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sushantmondal.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sushantmondal.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sushantmondal.com\/blog\/wp-json\/wp\/v2\/comments?post=153"}],"version-history":[{"count":22,"href":"https:\/\/www.sushantmondal.com\/blog\/wp-json\/wp\/v2\/posts\/153\/revisions"}],"predecessor-version":[{"id":182,"href":"https:\/\/www.sushantmondal.com\/blog\/wp-json\/wp\/v2\/posts\/153\/revisions\/182"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.sushantmondal.com\/blog\/wp-json\/wp\/v2\/media\/154"}],"wp:attachment":[{"href":"https:\/\/www.sushantmondal.com\/blog\/wp-json\/wp\/v2\/media?parent=153"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sushantmondal.com\/blog\/wp-json\/wp\/v2\/categories?post=153"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sushantmondal.com\/blog\/wp-json\/wp\/v2\/tags?post=153"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}