`timescale 1ns/1ps // 16-byte binary frame over UART. // Byte 0 : 0xA5 // Byte 1 : 0x5A // Byte 2 : type (0x81 STATUS/PONG, 0x82 TRACE, 0x83 SUMMARY) // Byte 3..4 : sequence/count, big-endian // Byte 5..6 : event_id, big-endian // Byte 7..10 : timestamp/run_cycles, big-endian // Byte 11..14 : data/drop_count, big-endian // Byte 15 : CRC-8, polynomial 0x07, init 0x00, over bytes 2..14 module trace_packet_tx #( parameter integer CLK_HZ = 25000000, parameter integer BAUD = 115200 )( input wire clk, input wire reset_n, input wire send, input wire [7:0] pkt_type, input wire [15:0] seq, input wire [15:0] event_id, input wire [31:0] timestamp, input wire [31:0] data, output wire uart_tx_o, output reg busy, output reg done ); reg [7:0] type_l; reg [15:0] seq_l; reg [15:0] event_l; reg [31:0] time_l; reg [31:0] data_l; reg [4:0] byte_index; reg [7:0] crc; reg uart_start; reg [7:0] uart_data; reg waiting_uart; wire uart_busy; wire uart_done; function [7:0] crc8_update; input [7:0] crc_in; input [7:0] data_in; integer i; reg [7:0] c; begin c = crc_in ^ data_in; for (i = 0; i < 8; i = i + 1) begin if (c[7]) c = (c << 1) ^ 8'h07; else c = (c << 1); end crc8_update = c; end endfunction function [7:0] frame_byte; input [4:0] idx; begin case (idx) 5'd0: frame_byte = 8'hA5; 5'd1: frame_byte = 8'h5A; 5'd2: frame_byte = type_l; 5'd3: frame_byte = seq_l[15:8]; 5'd4: frame_byte = seq_l[7:0]; 5'd5: frame_byte = event_l[15:8]; 5'd6: frame_byte = event_l[7:0]; 5'd7: frame_byte = time_l[31:24]; 5'd8: frame_byte = time_l[23:16]; 5'd9: frame_byte = time_l[15:8]; 5'd10: frame_byte = time_l[7:0]; 5'd11: frame_byte = data_l[31:24]; 5'd12: frame_byte = data_l[23:16]; 5'd13: frame_byte = data_l[15:8]; 5'd14: frame_byte = data_l[7:0]; 5'd15: frame_byte = crc; default: frame_byte = 8'h00; endcase end endfunction uart_tx #( .CLK_HZ(CLK_HZ), .BAUD(BAUD) ) u_uart_tx ( .clk(clk), .reset_n(reset_n), .start(uart_start), .data(uart_data), .tx(uart_tx_o), .busy(uart_busy), .done(uart_done) ); always @(posedge clk or negedge reset_n) begin if (!reset_n) begin type_l <= 8'd0; seq_l <= 16'd0; event_l <= 16'd0; time_l <= 32'd0; data_l <= 32'd0; byte_index <= 5'd0; crc <= 8'd0; uart_start <= 1'b0; uart_data <= 8'd0; waiting_uart <= 1'b0; busy <= 1'b0; done <= 1'b0; end else begin uart_start <= 1'b0; done <= 1'b0; if (!busy) begin waiting_uart <= 1'b0; if (send) begin type_l <= pkt_type; seq_l <= seq; event_l <= event_id; time_l <= timestamp; data_l <= data; byte_index <= 5'd0; crc <= 8'h00; busy <= 1'b1; end end else begin if (!waiting_uart && !uart_busy) begin uart_data <= frame_byte(byte_index); uart_start <= 1'b1; waiting_uart <= 1'b1; end if (waiting_uart && uart_done) begin if ((byte_index >= 5'd2) && (byte_index <= 5'd14)) crc <= crc8_update(crc, frame_byte(byte_index)); waiting_uart <= 1'b0; if (byte_index == 5'd15) begin busy <= 1'b0; done <= 1'b1; end else begin byte_index <= byte_index + 1'b1; end end end end end endmodule