Repository navigation
asap7/coralnpu: register file generated, the snapshot unchanged #4653
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
3710a69
asap7/coralnpu: a synthesis build of the snapshot
oharboe cedef1e
asap7/coralnpu-regfile: coralnpu's integer register file, generated
oharboe c0cc172
asap7/coralnpu: surgery.py reads and writes UTF-8
oharboe ec346c1
asap7/coralnpu-exmem: an EX/MEM register in front of the load/store unit
oharboe 17ade36
asap7/coralnpu: a README, with the surgery an exercise left to the re…
oharboe File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| export DESIGN_NICKNAME = coralnpu-exmem | ||
|
|
||
| include designs/asap7/coralnpu/config.mk | ||
|
|
||
| # LsuV1's inputs registered by surgery.py --address-register: the | ||
| # EX/MEM register between dispatch and the load/store unit. | ||
| export SYNTH_VERILOG_SURGERY_ARGS = --address-register | ||
|
|
||
| # The clock, just under what the EX/MEM register lets the design reach. | ||
| export SDC_FILE = $(DESIGN_HOME)/$(PLATFORM)/coralnpu-exmem/constraint.sdc |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| current_design CoreMiniAxi | ||
|
|
||
| set clk_name io_aclk | ||
| set clk_port_name io_aclk | ||
| # coralnpu's constraints with this design's clock: just under the | ||
| # 1,701 ps it reaches at global route against a 1,700 ps target, so | ||
| # repair has a real target. | ||
| set clk_period 1700 | ||
|
|
||
| # IO budgets as optimization targets, the platform's set_max_delay | ||
| # model: 0.8 of the period for a path with a register at one end, 0.6 | ||
| # for a combinational path straight through. | ||
| set in2reg_max [expr { $clk_period * 0.8 }] | ||
| set reg2out_max [expr { $clk_period * 0.8 }] | ||
| set in2out_max [expr { $clk_period * 0.6 }] | ||
|
|
||
| # Functional mode: io_te, the test enable, selects the reset bypass and | ||
| # opens every clock gate in test. | ||
| set_case_analysis 0 [get_ports io_te] | ||
|
|
||
| # io_aresetn is asynchronous and reaches the core through RstSync's | ||
| # synchroniser; its recovery and removal are not what sets the core's | ||
| # frequency. | ||
| set_false_path -from [get_ports io_aresetn] | ||
|
|
||
| source $::env(PLATFORM_DIR)/constraints.sdc |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| export DESIGN_NICKNAME = coralnpu-regfile-exmem | ||
|
|
||
| include designs/asap7/coralnpu/config.mk | ||
|
|
||
| # coralnpu-regfile's generated register file and coralnpu-exmem's | ||
| # EX/MEM register together. | ||
| export SYNTH_VERILOG_SURGERY_ARGS = --regfile --address-register | ||
| export AUTO_MEMORIES_REGFILES = $(DESIGN_HOME)/$(PLATFORM)/coralnpu-regfile/Regfile_rf.regfile | ||
|
|
||
| # The clock, just under what the EX/MEM register lets the design reach. | ||
| export SDC_FILE = $(DESIGN_HOME)/$(PLATFORM)/coralnpu-regfile-exmem/constraint.sdc |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| current_design CoreMiniAxi | ||
|
|
||
| set clk_name io_aclk | ||
| set clk_port_name io_aclk | ||
| # coralnpu's constraints with this design's clock: a guess just under | ||
| # the 1,700 ps it meets at global route, so repair has a real target. | ||
| set clk_period 1650 | ||
|
|
||
| # IO budgets as optimization targets, the platform's set_max_delay | ||
| # model: 0.8 of the period for a path with a register at one end, 0.6 | ||
| # for a combinational path straight through. | ||
| set in2reg_max [expr { $clk_period * 0.8 }] | ||
| set reg2out_max [expr { $clk_period * 0.8 }] | ||
| set in2out_max [expr { $clk_period * 0.6 }] | ||
|
|
||
| # Functional mode: io_te, the test enable, selects the reset bypass and | ||
| # opens every clock gate in test. | ||
| set_case_analysis 0 [get_ports io_te] | ||
|
|
||
| # io_aresetn is asynchronous and reaches the core through RstSync's | ||
| # synchroniser; its recovery and removal are not what sets the core's | ||
| # frequency. | ||
| set_false_path -from [get_ports io_aresetn] | ||
|
|
||
| source $::env(PLATFORM_DIR)/constraints.sdc |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| # coralnpu's integer register file as standard cells, inlined in its | ||
| # place: Regfile_rf, the module surgery.py --regfile moves Regfile's | ||
| # storage into. 32 x 32 with x0 reading zero, eight combinational reads, | ||
| # six writes ORed when two write one word (Regfile's own data_N), a | ||
| # clock gate per word, every word reset to zero while reset is high. | ||
| module Regfile_rf | ||
| words 32 | ||
| bits 32 | ||
| clock clock | ||
| async_reset reset high | ||
| read raddr0 rdata0 | ||
| read raddr1 rdata1 | ||
| read raddr2 rdata2 | ||
| read raddr3 rdata3 | ||
| read raddr4 rdata4 | ||
| read raddr5 rdata5 | ||
| read raddr6 rdata6 | ||
| read raddr7 rdata7 | ||
| write waddr0 wdata0 we0 | ||
| write waddr1 wdata1 we1 | ||
| write waddr2 wdata2 we2 | ||
| write waddr3 wdata3 we3 | ||
| write waddr4 wdata4 we4 | ||
| write waddr5 wdata5 we5 | ||
| zero_word 0 | ||
| write_style clock_gate | ||
| cell icg ICGx1_ASAP7_75t_R | ||
| cell flop DFFHQNx1_ASAP7_75t_R | ||
| cell flop_r DFFASRHQNx1_ASAP7_75t_R | ||
| cell tie_hi TIEHIx1_ASAP7_75t_R | ||
| cell and2 AND2x2_ASAP7_75t_R | ||
| cell or2 OR2x2_ASAP7_75t_R | ||
| cell ao22 AO22x2_ASAP7_75t_R | ||
| cell inv INVx1_ASAP7_75t_R |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| export DESIGN_NICKNAME = coralnpu-regfile | ||
|
|
||
| include designs/asap7/coralnpu/config.mk | ||
|
|
||
| # Regfile's 31 words, moved by surgery.py --regfile into Regfile_rf, as | ||
| # a generated register file of standard cells inlined in their place. | ||
| export SYNTH_VERILOG_SURGERY_ARGS = --regfile | ||
| export AUTO_MEMORIES_REGFILES = $(DESIGN_HOME)/$(PLATFORM)/$(DESIGN_NICKNAME)/Regfile_rf.regfile |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
| # coralnpu on asap7 | ||
|
|
||
| [CoralNPU](https://github.com/google-coral/coralnpu) is Google's open | ||
| RISC-V core for edge machine learning: an in-order scalar core that | ||
| dispatches up to four instructions a cycle, with a float unit, two TCM | ||
| SRAMs and AXI ports. `../../src/coralnpu/CoreMiniAxi.sv` is firtool's | ||
| output for `CoreMiniAxi`, every file of the build concatenated. | ||
|
|
||
| | design | what it builds | | ||
| |---|---| | ||
| | `coralnpu` | the snapshot as a synthesis build | | ||
| | `coralnpu-regfile` | the integer register file generated as an array | | ||
| | `coralnpu-exmem` | an EX/MEM register in front of the load/store unit | | ||
| | `coralnpu-regfile-exmem` | both | | ||
|
|
||
| ## Results at global route | ||
|
|
||
| OpenROAD's global route with timing repair, built with bazel-orfs. | ||
| Each design's clock sits just under what it reaches, so repair has a | ||
| target and the WNS is slightly negative. | ||
|
|
||
| | design | clock | period at global route | std-cell area | CTS + global route | | ||
| |---|---|---|---|---| | ||
| | `coralnpu` | 1,900 ps | 2,031 ps | 16,757 µm² | about 8,700 s | | ||
| | `coralnpu-regfile` | 1,900 ps | 1,902 ps | 15,628 µm² | 836 s | | ||
| | `coralnpu-exmem` | 1,700 ps | 1,701 ps | 16,041 µm² | 1,172 s | | ||
| | `coralnpu-regfile-exmem` | 1,650 ps | not yet measured; meets 1,700 ps | 15,565 µm² at 1,700 ps | 642 s at 1,700 ps | | ||
|
|
||
| In `coralnpu`, nearly all of the CTS and global route time is | ||
| `repair_timing` chasing the one family of paths described below. | ||
| With the EX/MEM register, the worst path is the register file into the | ||
| CSR's `minstret` counter, a path upstream has also worked on | ||
| ([8baac41](https://github.com/google-coral/coralnpu/commit/8baac41897c40c6eafdbaabe491117dc60c6175e), | ||
| "Fix critical path in CSR minstret register"); the snapshot does not | ||
| record whether it predates that change. | ||
|
|
||
| ## Where the RTL comes from, and what is missing | ||
|
|
||
| The snapshot records neither the coralnpu commit it was generated from | ||
| nor how. It should: a `MODULE.bazel` here that builds the Verilog from a | ||
| pinned coralnpu commit, with the output checked in, so that testing | ||
| coralnpu for ORFS and OpenROAD needs neither Bazel nor Chisel, and a | ||
| fresh copy is one command. Until then the snapshot stands, and upstream | ||
| has moved on from it (below). | ||
|
|
||
| `surgery.py` (`SYNTH_VERILOG_SURGERY`) edits the snapshot before | ||
| synthesis. Some of it is the gap between what upstream ships and what an | ||
| idiomatic ORFS build needs, which upstream is not expected to close: | ||
|
|
||
| - firtool's verification layers removed, as a build without layers | ||
| enabled would leave them; | ||
| - the two TCM SRAMs moved into memory modules that `AUTO_MEMORIES` | ||
| generates, write masks and all; | ||
| - `--regfile`: the integer register file's 31 words moved into a module | ||
| that `AUTO_MEMORIES_REGFILES` generates. | ||
|
|
||
| `--address-register` is not that. It is a placeholder for a fresh | ||
| snapshot from upstream. | ||
|
|
||
| ## Surgery: an exercise left to the reader, solved | ||
|
|
||
| In the snapshot, one execute cycle reads the register file, forwards an | ||
| ALU result through it, lets dispatch decide which lanes issue, and has | ||
| the load/store unit build its micro-ops and enqueue them in its input | ||
| queue (`FifoX`, eight slots filled in one cycle). On asap7 this one | ||
| family of paths sets the period, 2,031 ps at global route. | ||
|
|
||
| The classic pipeline puts a register here: the EX/MEM latch of Hennessy | ||
| and Patterson's five-stage pipeline, which holds the effective address, | ||
| the store data and the request between execute and the memory side | ||
| (Rocket and CV32E40P do the same). `surgery.py --address-register` adds | ||
| it on `LsuV1`'s inputs: | ||
|
|
||
| ```mermaid | ||
| flowchart LR | ||
| subgraph snapshot["snapshot: one cycle"] | ||
| direction LR | ||
| RF1["register file<br/>read + forward"] --> D1["dispatch<br/>lane issue"] --> L1["LSU: micro-ops"] --> Q1["FifoX<br/>enqueue"] | ||
| end | ||
| subgraph surgered["coralnpu-exmem: two cycles"] | ||
| direction LR | ||
| RF2["register file<br/>read + forward"] --> D2["dispatch<br/>lane issue"] --> R[["EX/MEM register<br/>request, address, data"]] --> L2["LSU: micro-ops"] --> Q2["FifoX<br/>enqueue"] | ||
| Q2 -. "count + in flight" .-> RDY["io_req_N_ready"] | ||
| R -. "in flight" .-> RDY | ||
| R -. "busy" .-> ACT["io_active"] | ||
| end | ||
| ``` | ||
|
|
||
| - `io_req_N_ready` keeps the snapshot's thresholds, applied to the | ||
| queue's count plus the entries the register will enqueue, so a request | ||
| accepted now has its room a cycle later. | ||
| - `io_active` includes the register, so a fence waits for it. | ||
| - Loads and stores take one cycle longer. Nothing else changes. | ||
|
|
||
| bazel-orfs's `test/coralnpu_exmem` simulates both load/store units | ||
| under the same random requests, up to four lanes a cycle with the buses | ||
| stalling at random, and compares every bus transaction, writeback, | ||
| flush and fault in order; a negative control without the ready | ||
| adjustment must differ, and does. It also checks that the surgery | ||
| changes `LsuV1` and no other module. | ||
|
|
||
| ### What the silicon did | ||
|
|
||
| CoralNPU is in silicon: Synaptics' Astra SL2610 is its first production | ||
| implementation, and VeriSilicon, Google's commercial partner for the | ||
| IP, has built test silicon. Whoever implemented it met this cycle, in | ||
| one of three ways: a register as above, less work per cycle (fewer | ||
| lanes, a smaller configuration), or a slower clock. We probably cannot | ||
| know which. What is public: | ||
|
|
||
| - the SL2610 datasheet rates the NPU at "up to 1 TOPS" and gives no | ||
| clock for the CoralNPU core; | ||
| - Google states targets of 1 GHz (22 nm) and VeriSilicon 800 MHz | ||
| (22 nm), not measured silicon; | ||
| - upstream coralnpu has reworked this cycle in Chisel since the | ||
| snapshot was taken: | ||
| [43d2030](https://github.com/google-coral/coralnpu/commit/43d20300e9968a444eec4756f42135226e4fbc59) | ||
| "Drive Regfile busPort.data from unforwarded rdata" takes the | ||
| ALU-to-register-file forwarding out of the load/store unit's enqueue | ||
| timing, and a series of LSU timing changes follows, against a stated | ||
| target of 800 MHz in 12 nm | ||
| ([03fa31a](https://github.com/google-coral/coralnpu/commit/03fa31aa589fa4bf8616ffcae54b41d301b57e73)). | ||
|
|
||
| ### What is not solved here | ||
|
|
||
| The proper fix is in the source: a patch to coralnpu's Chisel, | ||
| Verilog regenerated from it, and coralnpu's own tests run on the | ||
| result, or simply a fresh snapshot of an upstream that has done the | ||
| work. That is out of scope for this design. The surgery is an | ||
| implementation step on a snapshot, verified by the simulation above | ||
| and not by coralnpu's own test suite. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,28 +1,37 @@ | ||
| export PLATFORM = asap7 | ||
|
|
||
| export DESIGN_NICKNAME = coralnpu | ||
| export DESIGN_NICKNAME ?= coralnpu | ||
| export DESIGN_NAME = CoreMiniAxi | ||
|
|
||
| export VERILOG_FILES = $(DESIGN_HOME)/src/$(DESIGN_NICKNAME)/$(DESIGN_NAME).sv \ | ||
| $(PLATFORM_DIR)/verilog/fakeram_512x128.sv \ | ||
| $(PLATFORM_DIR)/verilog/fakeram_2048x128.sv | ||
| export VERILOG_FILES = $(DESIGN_HOME)/src/coralnpu/$(DESIGN_NAME).sv | ||
|
|
||
| export VERILOG_DEFINES += -D USE_ASAP7 | ||
| # The snapshot is firtool's output with its verification layers | ||
| # concatenated in: 61 binds of *_Verification_Assert into the core. A | ||
| # layer is opt-in, so a synthesis build leaves them out; surgery.py | ||
| # removes them, as firtool's output without layers enabled would be. | ||
| export SYNTH_VERILOG_SURGERY = $(DESIGN_HOME)/$(PLATFORM)/coralnpu/surgery.py | ||
|
|
||
| export ADDITIONAL_LEFS = $(PLATFORM_DIR)/lef/fakeram_512x128.lef \ | ||
| $(PLATFORM_DIR)/lef/fakeram_2048x128.lef | ||
| # The two TCM SRAMs, Sram_512x128 and Sram_2048x128, keep their arrays | ||
| # inside wrappers; surgery.py moves each into a memory module of | ||
| # firtool's convention (one read port, one write port with a 16-lane | ||
| # byte mask), and AUTO_MEMORIES gives each a generated macro, mask and | ||
| # all. The USE_ASAP7 fakerams have no write mask. | ||
| export AUTO_MEMORIES = 1 | ||
|
|
||
| export ADDITIONAL_LIBS += $(PLATFORM_DIR)/lib/NLDM/fakeram_512x128.lib \ | ||
| $(PLATFORM_DIR)/lib/NLDM/fakeram_2048x128.lib | ||
|
|
||
| export SDC_FILE = $(DESIGN_HOME)/$(PLATFORM)/$(DESIGN_NICKNAME)/constraint.sdc | ||
| export SDC_FILE = $(DESIGN_HOME)/$(PLATFORM)/coralnpu/constraint.sdc | ||
|
|
||
| export SYNTH_HDL_FRONTEND ?= slang | ||
|
|
||
| export CORE_UTILIZATION = 65 | ||
|
|
||
| # coralnpu's units, kept by name: the core, its fetch, dispatch, | ||
| # register files, load/store unit, CSRs and FPU, and the two AXI | ||
| # bridges. The ALUs, branch units, multiplier and divider are small and | ||
| # belong with the dispatch and writeback around them. The size | ||
| # threshold is out of reach so that the list alone decides. | ||
| export SYNTH_HIERARCHICAL = 1 | ||
| export SYNTH_MINIMUM_KEEP_SIZE = 40000 | ||
| export SYNTH_KEEP_MODULES = SCore UncachedFetch DispatchV1 Regfile FRegfile LsuV1 Csr FloatCore AxiSlave DBus2AxiV1 | ||
| export SYNTH_MINIMUM_KEEP_SIZE = 1000000000 | ||
| export OPENROAD_HIERARCHICAL = 1 | ||
|
|
||
| export RTLMP_MIN_CHANNEL_SIZE = 4 4 | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where is this file? I don't see it in the PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a draft where I keep notes, the file is still in a patch in bazel-orfs for now.
Once all fhe auto memories land in ORFS, I will clean this up if you want it, otherwise it has been useful for my testing when working on auto memories.