|
| 1 | +/******************************************************************************* |
| 2 | + * Copyright 2026 Zero ASIC Corporation |
| 3 | + * |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | + * you may not use this file except in compliance with the License. |
| 6 | + * You may obtain a copy of the License at |
| 7 | + * |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | + * |
| 10 | + * Unless required by applicable law or agreed to in writing, software |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | + * See the License for the specific language governing permissions and |
| 14 | + * limitations under the License. |
| 15 | + * |
| 16 | + * ---- |
| 17 | + * |
| 18 | + * Documentation: |
| 19 | + * |
| 20 | + * Passive UMI bus monitor. Taps a UMI bus without driving any signals. |
| 21 | + * |
| 22 | + * Synthesis: produces a 1-cycle 'beat' pulse on every valid+ready |
| 23 | + * handshake. Can be used for transaction counters, performance |
| 24 | + * monitors, or activity indicators. |
| 25 | + * |
| 26 | + * Simulation: on negedge clock, displays the full transaction |
| 27 | + * (opcode name, addresses, data) whenever a handshake occurs. |
| 28 | + * Acts as a built-in protocol analyzer for debug. |
| 29 | + * |
| 30 | + ******************************************************************************/ |
| 31 | + |
| 32 | +module umi_monitor |
| 33 | + #(parameter CW = 32, |
| 34 | + parameter AW = 64, |
| 35 | + parameter DW = 128, |
| 36 | + parameter TIMEOUT = 100, // simulation only |
| 37 | + parameter VERBOSE = 0, // set to 1 always enable tracing |
| 38 | + parameter [12*8-1:0] NAME = "umi") // short label for display (12 chars) |
| 39 | + (// UMI bus tap |
| 40 | + input valid, |
| 41 | + input ready, |
| 42 | + input [CW-1:0] cmd, |
| 43 | + input [AW-1:0] dstaddr, |
| 44 | + input [AW-1:0] srcaddr, |
| 45 | + input [DW-1:0] data, |
| 46 | + // clk, reset only used for simulation display |
| 47 | + input clk, |
| 48 | + input nreset, |
| 49 | + // beat output |
| 50 | + output beat |
| 51 | + ); |
| 52 | + |
| 53 | + //########################################## |
| 54 | + // A transaction has happened |
| 55 | + //########################################## |
| 56 | + |
| 57 | +`include "umi_messages.vh" |
| 58 | + |
| 59 | + assign beat = valid & ready; |
| 60 | + |
| 61 | + //########################################## |
| 62 | + // Simulation only monitoring |
| 63 | + //########################################## |
| 64 | + |
| 65 | +`ifdef SIMULATION |
| 66 | + |
| 67 | + // compile time enable of verbose tracing |
| 68 | + `ifdef VERBOSE |
| 69 | + localparam VERBOSE_SWITCH = 1; |
| 70 | + `else |
| 71 | + localparam VERBOSE_SWITCH = 0; |
| 72 | + `endif |
| 73 | + |
| 74 | + // sane printing |
| 75 | + initial $timeformat(-9, 2, "ns", 0); |
| 76 | + |
| 77 | + // Pad NAME with leading spaces for aligned display |
| 78 | + reg [12*8-1:0] name_padded; |
| 79 | + integer ni; |
| 80 | + initial begin |
| 81 | + name_padded = " "; // 12 spaces |
| 82 | + for (ni = 0; ni < 12; ni = ni + 1) |
| 83 | + if (NAME[ni*8+:8] != 0) |
| 84 | + name_padded[ni*8+:8] = NAME[ni*8+:8]; |
| 85 | + end |
| 86 | + |
| 87 | + wire [4:0] opcode; |
| 88 | + |
| 89 | + assign opcode = cmd[4:0]; |
| 90 | + |
| 91 | + // Stall timeout: valid high but ready low for TIMEOUT cycles |
| 92 | + integer stall_count; |
| 93 | + always @(posedge clk or negedge nreset) |
| 94 | + if (!nreset) |
| 95 | + stall_count <= 0; |
| 96 | + else if (valid & ~ready) |
| 97 | + stall_count <= stall_count + 1; |
| 98 | + else |
| 99 | + stall_count <= 0; |
| 100 | + |
| 101 | + always @(posedge clk) begin |
| 102 | + if (nreset & (stall_count == TIMEOUT)) begin |
| 103 | + $display("%10t %s WARNING: UMI_TIMEOUT: valid=%b ready=%b dst=0x%h src=0x%h cmd=0x%h (%0d cycles) (%m)", |
| 104 | + $realtime, name_padded, valid, ready, dstaddr, srcaddr, cmd, stall_count); |
| 105 | + end |
| 106 | + end |
| 107 | + |
| 108 | + if (VERBOSE | VERBOSE_SWITCH) begin |
| 109 | + // Transaction display on handshake |
| 110 | + always @(negedge clk) begin |
| 111 | + if (nreset & beat) begin |
| 112 | + case (opcode) |
| 113 | + UMI_REQ_READ: $display("%10t %s UMI_REQ_READ: dst=0x%h src=0x%h data=0x%h (%m)", $realtime, name_padded, dstaddr, srcaddr, data); |
| 114 | + UMI_REQ_WRITE: $display("%10t %s UMI_REQ_WRITE: dst=0x%h src=0x%h data=0x%h (%m)", $realtime, name_padded, dstaddr, srcaddr, data); |
| 115 | + UMI_REQ_POSTED: $display("%10t %s UMI_REQ_POSTED: dst=0x%h src=0x%h data=0x%h (%m)", $realtime, name_padded, dstaddr, srcaddr, data); |
| 116 | + UMI_RESP_READ: $display("%10t %s UMI_RESP_READ: dst=0x%h src=0x%h data=0x%h (%m)", $realtime, name_padded, dstaddr, srcaddr, data); |
| 117 | + UMI_RESP_WRITE: $display("%10t %s UMI_RESP_WRITE: dst=0x%h src=0x%h data=0x%h (%m)", $realtime, name_padded, dstaddr, srcaddr, data); |
| 118 | + UMI_REQ_ATOMIC: $display("%10t %s UMI_REQ_ATOMIC: dst=0x%h src=0x%h data=0x%h (%m)", $realtime, name_padded, dstaddr, srcaddr, data); |
| 119 | + UMI_REQ_RDMA: $display("%10t %s UMI_REQ_RDMA: dst=0x%h src=0x%h data=0x%h (%m)", $realtime, name_padded, dstaddr, srcaddr, data); |
| 120 | + UMI_REQ_USER0: $display("%10t %s UMI_REQ_USER0: dst=0x%h src=0x%h data=0x%h (%m)", $realtime, name_padded, dstaddr, srcaddr, data); |
| 121 | + UMI_REQ_ERROR: $display("%10t %s UMI_REQ_ERROR: dst=0x%h src=0x%h data=0x%h (%m)", $realtime, name_padded, dstaddr, srcaddr, data); |
| 122 | + UMI_REQ_LINK: $display("%10t %s UMI_REQ_LINK: dst=0x%h src=0x%h data=0x%h (%m)", $realtime, name_padded, dstaddr, srcaddr, data); |
| 123 | + default: $display("%10t %s UMI_OPCODE=0x%h: dst=0x%h src=0x%h data=0x%h (%m)", $realtime, name_padded, opcode, dstaddr, srcaddr, data); |
| 124 | + endcase |
| 125 | + end |
| 126 | + end |
| 127 | + end |
| 128 | +`endif |
| 129 | + |
| 130 | +endmodule |
0 commit comments