Skip to content

Check-in some changes to run the kernels correctly - #323

Open
Jackcuii wants to merge 41 commits into
masterfrom
kernel-submit
Open

Check-in some changes to run the kernels correctly#323
Jackcuii wants to merge 41 commits into
masterfrom
kernel-submit

Conversation

@Jackcuii

Copy link
Copy Markdown
Collaborator

No description provided.

Jackcuii and others added 30 commits March 29, 2026 09:05
- Add CgraRTL_relu4x4_test_from_yaml.py: ReLU kernel test on 4x4 Mesh CGRA
  using relu.yaml compiled kernel config (II=5, 32 iterations)
- Fix script_generator.py: swap STORE src_operands to match MemUnitRTL
  hardware expectation (in0=address, in1=data vs YAML order [data, addr])
…flag

Bug #1 - CrossbarRTL all-or-nothing: Stale prologued data blocked entire crossbar
- Mask recv_valid_vector, exclude prologued from send/recv_required_vector
- Gate changed: recv_valid_or_prologue_allowing_vector

Bug #2 - PhiRTL shared first flag: Multiple PHI_START on same tile failed
- Detect iteration wrap via ctrl_addr, clear s.first only at boundaries
- Added prev_ctrl_addr tracking

Tests: ReLU 379 cycles (pass), SpMV 759 cycles (pass)
@Jackcuii

Copy link
Copy Markdown
Collaborator Author

Superseded by focused PRs: #325 (YAML generator), #326 (basic vector/FIR kernels), #327 (SpMV), #328 (GEMM/GEMV), and #329 (convolution/SAD). Existing focused RTL fixes remain in #298, #303-#305, #307, and #309-#312. The replacement PRs exclude visualizer and trace_output artifacts.

@Jackcuii

Copy link
Copy Markdown
Collaborator Author

Added cleanup commit ce34b9b:

  • removed all visualizer/ files
  • removed all tracked trace_output/ files
  • removed validation artifacts not directly referenced by tracked test/test_from_yaml code
  • retained only script_generator.py and the eight newly added YAML files used by tracked tests

Python syntax checks pass. Pytest collection from the repository root is blocked by the project package layout (attempted relative import beyond top-level package), unrelated to the removed validation files.

# Conflicts:
#	fu/single/CompRTL.py
#	fu/single/test/CompRTL_test.py
@Jackcuii

Copy link
Copy Markdown
Collaborator Author

Detailed RTL-level change summary

This comment covers every *RTL.py file currently changed by this PR relative to the latest master. It describes both what changed and why the change is needed.

1. cgra/CgraRTL.py

What changed

  • line_trace() now obtains the optional structured trace logger through get_trace_logger().
  • When logging is enabled, the complete CGRA state is recorded once when line_trace() is invoked.
  • The existing human-readable line trace is unchanged.

Purpose

The structured log provides cycle-by-cycle machine-readable state for debugging long-running compiled kernels. It makes it possible to correlate tile/FU activity, control state, routing behavior, and memory activity without parsing the existing free-form line trace. The logger remains optional, so normal simulations do not need to enable it.

2. fu/single/GrantRTL.py

What changed

  • Replaced the single global already_grt_once bit with one bit per control-memory slot (ctrl_addr).
  • Added cur_already_grt_once to select the state associated with the currently executing control slot.
  • Added support for OPT_GRT_ONCE_CONST, which takes its value from the constant queue instead of a regular FU input.
  • Both OPT_GRT_ONCE and OPT_GRT_ONCE_CONST set the per-slot state only after a successful output valid/ready handshake.
  • Reset and clear now reset every slot independently.

Purpose

A tile can contain more than one GRANT_ONCE operation at different control addresses. A single shared bit caused the first operation to suppress all later operations on that tile. Per-slot state makes each scheduled operation independent. OPT_GRT_ONCE_CONST is needed for compiled kernels in which a loop-invariant or entry-block value is supplied by the constant queue and must receive a true predicate exactly once.

3. fu/single/MemUnitRTL.py

What changed

  • For OPT_STR, both the write-address valid signal and write-data valid signal are now gated by the predicates of the address and data inputs.
  • The existing valid/ready data-consumption behavior is otherwise unchanged.

Purpose

During pipeline drain cycles, a token may still have val=1 while carrying predicate=0. Previously, OPT_STR treated such a token as a real memory write and could overwrite a correct result with invalid drain data. Requiring both input predicates prevents side effects from predicated-off stores while still consuming the pipeline token normally.

4. fu/single/PhiRTL.py

What changed

  • Added handling for OPT_CONST inside the Phi FU.
  • The operation forwards the constant payload, combines the constant predicate with reached_vector_factor, and implements the normal constant/output valid-ready handshake.
  • The existing per-control-slot PHI first-execution state from master is retained.

Purpose

The compiled schedule can map a plain constant-producing operation onto a tile configuration that uses the Phi-capable FU. Supporting OPT_CONST here avoids rejecting or stalling that schedule and preserves normal predicate/vector-factor behavior.

5. fu/single/ShifterRTL.py

What changed

  • Added OPT_LLS_CONST for logical left shift by a constant amount.
  • The data operand comes from the selected FU input and the shift amount comes from the constant queue.
  • Output predicate, valid, and ready signals account for both operands and reached_vector_factor.

Purpose

Compiled address and index calculations frequently contain shifts by a compile-time constant. Supporting a constant shift avoids consuming a second routed FU input and allows the YAML generator to represent these operations directly.

6. mem/const/ConstQueueDynamicRTL.py

What changed

  • Added a consume_pending state bit.
  • A constant read handshake is remembered when send_const.rdy occurs before ctrl_proceed.
  • The pending consumption retires and advances the read cursor on the next ctrl_proceed pulse.
  • Reset/clear resets both the read cursor and pending state.

Purpose

The previous implementation advanced the queue only when send_const.rdy and ctrl_proceed were asserted in the same cycle. At iteration boundaries, another tile submodule can delay ctrl_proceed, causing an already-consumed constant to remain at the head of the queue. Remembering the pending consumption prevents constant-order corruption and repeated constants.

7. mem/ctrl/CtrlMemDynamicRTL.py

What changed

  • Added CMD_CONFIG_GEP_STRIDE to the set of controller commands forwarded to the tile element.
  • Added the same command to the set that is acknowledged/consumed from the controller packet queue.

Purpose

Two-dimensional GEP operations require runtime configuration of their stride. Without forwarding and consuming this command, the configuration packet can stall in control memory and the FU never receives the required stride value.

8. mem/register_cluster/RegisterClusterRTL.py

What changed

  • Relaxed recv_data_from_routing_crossbar[i].rdy so routing tokens can be consumed when:
    • the current operation is OPT_NAH,
    • the FU does not select this lane,
    • the register bank supplies the FU input for this lane, or
    • the FU output path is ready.
  • The previous, more conservative master condition is retained next to the implementation as a comment for comparison.
  • Most of the apparent full-file diff is line-ending normalization; the ready condition above is the functional change.

Purpose

Routing-crossbar tokens should not remain blocked merely because the FU is not consuming that lane. In compiled schedules this produced cycle gaps and could backpressure the routing network even when the token was irrelevant to the current FU operation. The relaxed condition drains unused routing tokens while preserving normal FU consumption when the lane is selected.

9. noc/CrossbarRTL.py

What changed

  • Prologued inputs are treated as satisfied for the all-input-valid gate, allowing non-prologued traffic to proceed.
  • A prologued output no longer requires downstream ready because no token should be sent on that output during the prologue.
  • Physical input data is masked from recv_valid_vector while the corresponding route is in its prologue period.
  • recv_required_vector excludes prologued routes and uses set-only/OR-style accumulation so multicast outputs sharing one input cannot overwrite one another's requirement.
  • send_required_vector excludes prologued outputs.
  • Output val and input dequeue logic use recv_valid_or_during_prologue_allowing_vector, while the required vectors ensure that prologued channels are neither sent nor consumed.

Purpose

The earlier crossbar could see stale physical data on a prologued route, attempt to send it, and then block the entire all-or-nothing multicast transaction when the destination was full. It could also let a bypassed/prologued route suppress unrelated valid traffic. These changes make prologue bypass explicit on both the input and output sides, prevent accidental consumption, preserve multicast requirements, and eliminate the observed SpMV deadlock.

10. tile/TileRTL.py

What changed

  • Added CMD_CONFIG_GEP_STRIDE to the controller commands routed from the tile's controller interface into CtrlMemDynamicRTL.
  • Removed two trailing spaces; those are formatting-only changes.

Purpose

This is the tile-level half of GEP stride delivery. TileRTL must accept and route the command before CtrlMemDynamicRTL can forward it to the element. Without this condition, the stride configuration would never enter the tile control path.

Note about CompRTL.py

CompRTL.py and CompRTL_test.py were previously modified by this branch, but they are no longer part of the current PR diff. After master merged its constant-comparison predicate semantics, the conflict was resolved by taking the master versions. Constant comparisons therefore follow master and require the data predicate, constant predicate, and reached_vector_factor.

@Jackcuii

Copy link
Copy Markdown
Collaborator Author

Update: The translation works well. The signal_a[signal_b] can be translated.
YoSys do report some comb loop warnings, but they seem not to be a new-introduced problem.

@Jackcuii

Copy link
Copy Markdown
Collaborator Author

Update: The reason of CI test fail is the invalid var that Verilog not support

@tancheng

Copy link
Copy Markdown
Owner

Update: The reason of CI test fail is the invalid var that Verilog not support

what is the invalid var you are referring to?

Comment thread cgra/test/CgraRTL_test.py

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The trace-related changes in this file can be reverted.

Comment thread cgra/CgraRTL.py

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the changes in this file can be reverted.

hmm, if you think this can help debugging, maybe we can also leave it there? as long as it can be conditionally invoked.

Comment thread lib/trace_logger.py

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can check this in if you want.

Comment thread mem/register_cluster/RegisterClusterRTL.py
Comment thread noc/CrossbarRTL.py
@tancheng

Copy link
Copy Markdown
Owner

Hi @Jackcuii, can you resolve the comments if you have bandwidth? I would like to merge some register bank related fixes after yours: #322

@Jackcuii

Copy link
Copy Markdown
Collaborator Author

Hi @Jackcuii, can you resolve the comments if you have bandwidth? I would like to merge some register bank related fixes after yours: #322

Hi Sir Tan, I was working on it~ However I caught a fever yesterday 🥵. Hopefully I will be better and back tomorrow.

@Jackcuii

Copy link
Copy Markdown
Collaborator Author

Update: The reason of CI test fail is the invalid var that Verilog not support

what is the invalid var you are referring to?

Oh sorry It is a typo, I mean char😂

@tancheng

Copy link
Copy Markdown
Owner

Hi @Jackcuii, can you resolve the comments if you have bandwidth? I would like to merge some register bank related fixes after yours: #322

Hi Sir Tan, I was working on it~ However I caught a fever yesterday 🥵. Hopefully I will be better and back tomorrow.

Ah, take care, get better soon!

Comment on lines +95 to +99
s.recv_data_from_routing_crossbar[i].rdy @= \
(s.inport_opt.operation == OPT_NAH) | \
(s.inport_opt.fu_in[i] == 0) | \
reg_towards_fu | \
s.send_data_to_fu[i].rdy

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yyan7223 does this make sense to you?

Comment thread noc/CrossbarRTL.py

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yyan7223 can you plz take a look at this change?

# lane, the register bank supplies the FU, or the FU is ready.
s.recv_data_from_routing_crossbar[i].rdy @= \
(s.inport_opt.operation == OPT_NAH) | \
(s.inport_opt.fu_in[i] == 0) | \

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you think we can remove this line? the "i" in fu_in[] is not the "i" for the routing_crossbar...

The 'fu_in[]` can shuffle the chosen inports.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or change it to sth like:

  bank_used_by_fu = (s.inport_opt.fu_in[0] == (i + 1))
  for slot in range(1, num_reg_banks):
    bank_used_by_fu = bank_used_by_fu | (s.inport_opt.fu_in[slot] == (i + 1))

  ...

  s.recv_data_from_routing_crossbar[i].rdy @= \
      (s.inport_opt.operation == OPT_NAH) | \
      ~bank_used_by_fu | \
      reg_towards_fu | \
      s.send_data_to_fu[i].rdy

though I feel it is over-complicated.

Comment thread noc/CrossbarRTL.py
s.send_rdy_vector @= 0
for i in range(num_outports):
# The `outport_towards_local_base_id` indicates the number of outports that go to other tiles.
# The `num_inports` indicates the number of outports that go to other tiles.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to change this comment of outport_towards_local_base_id -> num_inports, the original comment is correct.

Comment thread noc/CrossbarRTL.py
# The `num_inports` indicates the number of outports that go to other tiles.
# Specifically, if the compute already done, we shouldn't care the ones
# (i.e., i >= outport_towards_local_base_id) go to the FU's inports. In other words, we skip
# (i.e., i >= num_inports) go to the FU's inports. In other words, we skip

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

Comment thread noc/CrossbarRTL.py
# When prologue is active for this output's input, don't
# require the downstream channel to be ready -- we won't be
# sending any data through it during prologue anyway.
s.send_rdy_vector[i] @= s.send_data[i].rdy | \

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then can we change s.send_rdy_vector to s.send_rdy_or_during_prologue_vector?

Comment thread noc/CrossbarRTL.py
# trick the crossbar into attempting a send, and if the
# destination channel is full the all-or-nothing semantics
# cause a deadlock.
s.recv_valid_vector[i] @= s.recv_data_val[s.in_dir_local[i]] & \

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we then change this recv_valid_vector to recv_valid_excluding_prologue_vector

# lane, the register bank supplies the FU, or the FU is ready.
s.recv_data_from_routing_crossbar[i].rdy @= \
(s.inport_opt.operation == OPT_NAH) | \
(s.inport_opt.fu_in[i] == 0) | \

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or change it to sth like:

  bank_used_by_fu = (s.inport_opt.fu_in[0] == (i + 1))
  for slot in range(1, num_reg_banks):
    bank_used_by_fu = bank_used_by_fu | (s.inport_opt.fu_in[slot] == (i + 1))

  ...

  s.recv_data_from_routing_crossbar[i].rdy @= \
      (s.inport_opt.operation == OPT_NAH) | \
      ~bank_used_by_fu | \
      reg_towards_fu | \
      s.send_data_to_fu[i].rdy

though I feel it is over-complicated.

@tancheng

Copy link
Copy Markdown
Owner

Hi @Jackcuii, as long as you can resolve my comments, it should be okay to check in. Plz try to resolve them ASAP. Thanks!

@Jackcuii

Copy link
Copy Markdown
Collaborator Author

Hi @Jackcuii, as long as you can resolve my comments, it should be okay to check in. Plz try to resolve them ASAP. Thanks!

Okay~ I am checking in the logics the comments mentioned in the branch one by one to make sure all the yaml tests can still pass. It is somehow black-boxed😂

@tancheng

Copy link
Copy Markdown
Owner

Hi @Jackcuii, as long as you can resolve my comments, it should be okay to check in. Plz try to resolve them ASAP. Thanks!

Okay~ I am checking in the logics the comments mentioned in the branch one by one to make sure all the yaml tests can still pass. It is somehow black-boxed😂

I understand that. Can you then ask your agent to apply my suggestions to see whether it works?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants