Files
kernels/hw/rtl/libs/VX_scope_tap.sv
Blaise Tine c1e168fdbe Vortex 2.0 changes:
+ Microarchitecture optimizations
+ 64-bit support
+ Xilinx FPGA support
+ LLVM-16 support
+ Refactoring and quality control fixes

minor update

minor update

minor update

minor update

minor update

minor update

cleanup

cleanup

cache bindings and memory perf refactory

minor update

minor update

hw unit tests fixes

minor update

minor update

minor update

minor update

minor update

minor udpate

minor update

minor update

minor update

minor update

minor update

minor update

minor update

minor updates

minor updates

minor update

minor update

minor update

minor update

minor update

minor update

minor updates

minor updates

minor updates

minor updates

minor update

minor update
2023-11-10 02:47:05 -08:00

314 lines
12 KiB
Systemverilog

// Copyright © 2019-2023
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
`include "VX_platform.vh"
`TRACING_OFF
module VX_scope_tap #(
parameter SCOPE_ID = 0, // scope identifier
parameter SCOPE_IDW = 8, // scope identifier width
parameter TRIGGERW = 0, // trigger signals width
parameter PROBEW = 0, // probe signal width
parameter SIZE = 256, // trace buffer size
parameter IDLE_CTRW = 16 // idle time between triggers counter width
) (
input wire clk,
input wire reset,
input wire start,
input wire stop,
input wire [TRIGGERW-1:0] triggers,
input wire [PROBEW-1:0] probes,
input wire bus_in,
output wire bus_out
);
localparam TX_DATAW = 64;
localparam TX_DATA_BITS = `LOG2UP(TX_DATAW);
localparam DATAW = PROBEW + TRIGGERW;
localparam DATA_BITS = `LOG2UP(DATAW);
localparam ADDRW = `CLOG2(SIZE);
localparam TRIGGER_ENABLE = (TRIGGERW != 0);
localparam MAX_IDLE_CTR = (2 ** IDLE_CTRW) - 1;
localparam CTRL_STATE_IDLE = 2'd0;
localparam CTRL_STATE_RECV = 2'd1;
localparam CTRL_STATE_CMD = 2'd2;
localparam CTRL_STATE_SEND = 2'd3;
localparam CTRL_STATE_BITS = 2;
localparam TAP_STATE_IDLE = 2'd0;
localparam TAP_STATE_WAIT = 2'd1;
localparam TAP_STATE_RUN = 2'd2;
localparam TAP_STATE_BITS = 2;
localparam CMD_GET_WIDTH = 3'd0;
localparam CMD_GET_COUNT = 3'd1;
localparam CMD_GET_START = 3'd2;
localparam CMD_GET_DATA = 3'd3;
localparam CMD_SET_START = 3'd4;
localparam CMD_SET_STOP = 3'd5;
localparam CMD_TYPE_BITS = 3;
localparam GET_TYPE_WIDTH = 2'd0;
localparam GET_TYPE_COUNT = 2'd1;
localparam GET_TYPE_START = 2'd2;
localparam GET_TYPE_DATA = 2'd3;
localparam GET_TYPE_BITS = 2;
`NO_RW_RAM_CHECK reg [DATAW-1:0] data_store [SIZE-1:0];
`NO_RW_RAM_CHECK reg [IDLE_CTRW-1:0] delta_store [SIZE-1:0];
reg [TRIGGERW-1:0] prev_triggers;
reg [IDLE_CTRW-1:0] delta;
reg [63:0] timestamp, start_time;
reg [ADDRW-1:0] waddr, waddr_end;
reg cmd_start, delta_flush;
reg [63:0] start_delay, delay_cntr;
reg [TAP_STATE_BITS-1:0] tap_state;
reg [CTRL_STATE_BITS-1:0] ctrl_state;
reg [GET_TYPE_BITS-1:0] get_type;
reg [TX_DATA_BITS-1:0] ser_tx_ctr;
reg [DATA_BITS-1:0] read_offset;
reg [ADDRW-1:0] raddr;
reg read_data;
//
// trace capture
//
wire [ADDRW-1:0] raddr_n = raddr + 1;
wire [ADDRW:0] count = (ADDRW+1)'(waddr) + 1;
always @(posedge clk) begin
if (reset) begin
tap_state <= TAP_STATE_IDLE;
raddr <= '0;
waddr <= '0;
delta <= '0;
prev_triggers <= '0;
read_offset <= '0;
read_data <= 0;
timestamp <= '0;
end else begin
timestamp <= timestamp + 1;
case (tap_state)
TAP_STATE_IDLE: begin
if (start || cmd_start) begin
delta <= '0;
delta_flush <= 1;
if (0 == start_delay) begin
tap_state <= TAP_STATE_RUN;
start_time <= timestamp;
`ifdef DBG_TRACE_SCOPE
`TRACE(2, ("%d: *** scope #%0d: recording start - time=%0d\n", $time, SCOPE_ID, timestamp));
`endif
end else begin
tap_state <= TAP_STATE_WAIT;
delay_cntr <= start_delay;
`ifdef DBG_TRACE_SCOPE
`TRACE(2, ("%d: *** scope #%0d: delayed start - time=%0d\n", $time, SCOPE_ID, start_delay));
`endif
end
end
end
TAP_STATE_WAIT: begin
delay_cntr <= delay_cntr - 1;
if (1 == delay_cntr) begin
tap_state <= TAP_STATE_RUN;
start_time <= timestamp;
`ifdef DBG_TRACE_SCOPE
`TRACE(2, ("%d: *** scope #%0d: recording start - time=%0d\n", $time, SCOPE_ID, timestamp));
`endif
end
end
TAP_STATE_RUN: begin
if (TRIGGER_ENABLE != 0) begin
if (delta_flush || (triggers != prev_triggers)) begin
data_store[waddr] <= {probes, triggers};
delta_store[waddr] <= delta;
waddr <= waddr + 1;
delta <= '0;
delta_flush <= 0;
end else begin
delta <= delta + 1;
delta_flush <= (delta == (MAX_IDLE_CTR-1));
end
prev_triggers <= triggers;
end else begin
data_store[waddr] <= {probes, triggers};
delta_store[waddr] <= '0;
waddr <= waddr + 1;
end
if (stop || (waddr >= waddr_end)) begin
waddr <= waddr;
`ifdef DBG_TRACE_SCOPE
`TRACE(2, ("%d: *** scope #%0d: recording stop - waddr=(%0d, %0d)\n", $time, SCOPE_ID, waddr, waddr_end));
`endif
tap_state <= TAP_STATE_IDLE;
end
end
default:;
endcase
if (ctrl_state == CTRL_STATE_SEND
&& get_type == GET_TYPE_DATA
&& ser_tx_ctr == 0) begin
if (~read_data) begin
read_data <= 1;
end else begin
if (DATAW > TX_DATAW) begin
`IGNORE_WARNINGS_BEGIN
if (read_offset < DATA_BITS'(DATAW-TX_DATAW)) begin
read_offset <= read_offset + DATA_BITS'(TX_DATAW);
end else begin
raddr <= raddr_n;
read_data <= 0;
read_offset <= '0;
end
`IGNORE_WARNINGS_END
end else begin
raddr <= raddr_n;
read_data <= 0;
end
if (raddr_n == waddr) begin
raddr <= 0;
end
end
end
end
end
//
// command controller
//
reg bus_out_r;
reg [TX_DATAW-1:0] ser_buf_in;
wire [TX_DATAW-1:0] ser_buf_in_n = {ser_buf_in[TX_DATAW-2:0], bus_in};
`UNUSED_VAR (ser_buf_in)
wire [CMD_TYPE_BITS-1:0] cmd_type = ser_buf_in[CMD_TYPE_BITS-1:0];
wire [SCOPE_IDW-1:0] cmd_scope_id = ser_buf_in_n[CMD_TYPE_BITS +: SCOPE_IDW];
wire [TX_DATAW-CMD_TYPE_BITS-SCOPE_IDW-1:0] cmd_data = ser_buf_in[TX_DATAW-1:CMD_TYPE_BITS+SCOPE_IDW];
wire [TX_DATAW-1:0] data_chunk = TX_DATAW'(DATAW'(data_store[raddr] >> read_offset));
wire [TX_DATAW-1:0] get_data = read_data ? data_chunk : TX_DATAW'(delta_store[raddr]);
always @(posedge clk) begin
if (reset) begin
ctrl_state <= CTRL_STATE_IDLE;
cmd_start <= 0;
start_delay <= '0;
waddr_end <= ADDRW'(SIZE-1);
bus_out_r <= 0;
end else begin
bus_out_r <= 0;
cmd_start <= 0;
case (ctrl_state)
CTRL_STATE_IDLE: begin
if (bus_in) begin
ctrl_state <= CTRL_STATE_RECV;
end
ser_tx_ctr <= TX_DATA_BITS'(TX_DATAW-1);
end
CTRL_STATE_RECV: begin
ser_tx_ctr <= ser_tx_ctr - 1;
ser_buf_in <= ser_buf_in_n;
if (ser_tx_ctr == 0) begin
ctrl_state <= (cmd_scope_id == SCOPE_ID) ? CTRL_STATE_CMD : CTRL_STATE_IDLE;
end
end
CTRL_STATE_CMD: begin
ctrl_state <= CTRL_STATE_IDLE;
case (cmd_type)
CMD_SET_START: begin
start_delay <= 64'(cmd_data);
cmd_start <= 1;
end
CMD_SET_STOP: begin
waddr_end <= ADDRW'(cmd_data);
end
CMD_GET_WIDTH,
CMD_GET_START,
CMD_GET_COUNT,
CMD_GET_DATA: begin
ctrl_state <= CTRL_STATE_SEND;
get_type <= GET_TYPE_BITS'(cmd_type);
ser_tx_ctr <= TX_DATA_BITS'(TX_DATAW-1);
bus_out_r <= 1;
end
default:;
endcase
`ifdef DBG_TRACE_SCOPE
`TRACE(2, ("%d: *** scope #%0d: CMD: type=%0d\n", $time, SCOPE_ID, cmd_type));
`endif
end
CTRL_STATE_SEND: begin
ser_tx_ctr <= ser_tx_ctr - 1;
case (get_type)
GET_TYPE_WIDTH: begin
bus_out_r <= 1'(DATAW >> ser_tx_ctr);
`ifdef DBG_TRACE_SCOPE
if (ser_tx_ctr == 0) begin
`TRACE(2, ("%d: *** scope #%0d: SEND width=%0d\n", $time, SCOPE_ID, DATAW));
end
`endif
end
GET_TYPE_COUNT: begin
bus_out_r <= 1'(count >> ser_tx_ctr);
`ifdef DBG_TRACE_SCOPE
if (ser_tx_ctr == 0) begin
`TRACE(2, ("%d: *** scope #%0d: SEND count=%0d\n", $time, SCOPE_ID, count));
end
`endif
end
GET_TYPE_START: begin
bus_out_r <= 1'(start_time >> ser_tx_ctr);
`ifdef DBG_TRACE_SCOPE
if (ser_tx_ctr == 0) begin
`TRACE(2, ("%d: *** scope #%0d: SEND start=%0d\n", $time, SCOPE_ID, start_time));
end
`endif
end
GET_TYPE_DATA: begin
bus_out_r <= 1'(get_data >> ser_tx_ctr);
`ifdef DBG_TRACE_SCOPE
if (ser_tx_ctr == 0) begin
`TRACE(2, ("%d: *** scope #%0d: SEND data=%0d\n", $time, SCOPE_ID, get_data));
end
`endif
end
default:;
endcase
if (ser_tx_ctr == 0) begin
ctrl_state <= CTRL_STATE_IDLE;
end
end
default:;
endcase
end
end
assign bus_out = bus_out_r;
endmodule
`TRACING_ON