| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299 |
- `timescale 1ns/1ps
- module pwm_trace_uart_tb;
- localparam integer CLOCK_HZ = 25_000_000;
- localparam integer TEST_BAUD = 1_000_000;
- localparam integer BIT_NS = 1000;
- reg sys_clk = 1'b0;
- reg reset_n = 1'b0;
- reg trace_heater = 1'b0;
- reg trace_fan = 1'b0;
- reg trace_motor1 = 1'b0;
- reg trace_motor2 = 1'b0;
- reg trace_motor3 = 1'b0;
- reg trace_limit1 = 1'b0;
- reg trace_limit2 = 1'b0;
- reg trace_limit3 = 1'b0;
- wire uart_tx;
- wire led_activity_n;
- integer errors = 0;
- integer i;
- reg [7:0] packet [0:15];
- reg [15:0] event_id;
- reg [31:0] data_value;
- reg [31:0] packet_time;
- reg [31:0] first_timestamp;
- reg [31:0] heater_count, heater_period, heater_high;
- reg [31:0] fan_count, fan_period, fan_high;
- reg [31:0] motor1_count, motor1_period, motor1_high;
- reg [31:0] motor2_count, motor2_period, motor2_high;
- reg [31:0] motor3_count, motor3_period, motor3_high;
- reg [31:0] status_data;
- always #20 sys_clk = ~sys_clk;
- pwm_trace_top #(
- .CLOCK_HZ(CLOCK_HZ),
- .BAUD(TEST_BAUD),
- .REPORT_MS(20)
- ) dut (
- .sys_clk(sys_clk),
- .reset_n(reset_n),
- .trace_heater(trace_heater),
- .trace_fan(trace_fan),
- .trace_motor1(trace_motor1),
- .trace_motor2(trace_motor2),
- .trace_motor3(trace_motor3),
- .trace_limit1(trace_limit1),
- .trace_limit2(trace_limit2),
- .trace_limit3(trace_limit3),
- .uart_tx(uart_tx),
- .led_activity_n(led_activity_n)
- );
- // Distinct waveforms verify that each event ID is tied to the intended
- // channel rather than accidentally reusing another channel's measurement.
- initial forever begin
- @(negedge sys_clk); trace_heater = 1'b1;
- repeat (250) @(negedge sys_clk); trace_heater = 1'b0;
- repeat (749) @(negedge sys_clk);
- end
- initial forever begin
- @(negedge sys_clk); trace_fan = 1'b1;
- repeat (500) @(negedge sys_clk); trace_fan = 1'b0;
- repeat (749) @(negedge sys_clk);
- end
- initial forever begin
- @(negedge sys_clk); trace_motor1 = 1'b1;
- repeat (1250) @(negedge sys_clk); trace_motor1 = 1'b0;
- repeat (1249) @(negedge sys_clk);
- end
- initial forever begin
- @(negedge sys_clk); trace_motor2 = 1'b1;
- repeat (1000) @(negedge sys_clk); trace_motor2 = 1'b0;
- repeat (3999) @(negedge sys_clk);
- end
- initial forever begin
- @(negedge sys_clk); trace_motor3 = 1'b1;
- repeat (7500) @(negedge sys_clk); trace_motor3 = 1'b0;
- repeat (2499) @(negedge sys_clk);
- end
- // Limit transitions before the first 20 ms report:
- // current raw state at snapshot: L3=1, L2=1, L1=0 -> 3'b110
- // rising seen: all three; falling seen: L1 only.
- initial begin
- wait(reset_n == 1'b1);
- #2000000; trace_limit1 = 1'b1;
- #2000000; trace_limit2 = 1'b1;
- #2000000; trace_limit1 = 1'b0;
- #2000000; trace_limit3 = 1'b1;
- end
- function [7:0] crc8_next;
- input [7:0] crc_in;
- input [7:0] data_in;
- integer k;
- reg [7:0] c;
- begin
- c = crc_in ^ data_in;
- for (k = 0; k < 8; k = k + 1) begin
- if (c[7])
- c = (c << 1) ^ 8'h07;
- else
- c = (c << 1);
- end
- crc8_next = c;
- end
- endfunction
- task uart_recv_byte;
- output [7:0] value;
- integer b;
- begin
- @(negedge uart_tx);
- #(BIT_NS + BIT_NS/2);
- for (b = 0; b < 8; b = b + 1) begin
- value[b] = uart_tx;
- #BIT_NS;
- end
- if (uart_tx !== 1'b1) begin
- $display("FAIL UART stop bit");
- errors = errors + 1;
- end
- #(BIT_NS/2);
- end
- endtask
- task recv_packet;
- integer n;
- reg [7:0] crc;
- begin
- packet[0] = 8'h00;
- packet[1] = 8'h00;
- while (!((packet[0] == 8'hA5) && (packet[1] == 8'h5A))) begin
- packet[0] = packet[1];
- uart_recv_byte(packet[1]);
- end
- for (n = 2; n < 16; n = n + 1)
- uart_recv_byte(packet[n]);
- crc = 8'h00;
- for (n = 2; n <= 14; n = n + 1)
- crc = crc8_next(crc, packet[n]);
- if (crc !== packet[15]) begin
- $display("FAIL CRC expected=%02x actual=%02x", crc, packet[15]);
- errors = errors + 1;
- end
- if (packet[2] !== 8'h82) begin
- $display("FAIL packet type expected=82 actual=%02x", packet[2]);
- errors = errors + 1;
- end
- event_id = {packet[5], packet[6]};
- packet_time = {packet[7], packet[8], packet[9], packet[10]};
- data_value = {packet[11], packet[12], packet[13], packet[14]};
- end
- endtask
- task check_u32;
- input [8*24-1:0] label_text;
- input [31:0] actual;
- input [31:0] expected;
- begin
- if (actual !== expected) begin
- $display("FAIL %0s expected=%0d actual=%0d", label_text, expected, actual);
- errors = errors + 1;
- end else begin
- $display("PASS %0s = %0d", label_text, actual);
- end
- end
- endtask
- initial begin
- $display("");
- $display("==============================================");
- $display(" 8-CHANNEL TRACE UART INTEGRATION TEST");
- $display("==============================================");
- repeat (10) @(posedge sys_clk);
- reset_n = 1'b1;
- heater_count = 0; heater_period = 0; heater_high = 0;
- fan_count = 0; fan_period = 0; fan_high = 0;
- motor1_count = 0; motor1_period = 0; motor1_high = 0;
- motor2_count = 0; motor2_period = 0; motor2_high = 0;
- motor3_count = 0; motor3_period = 0; motor3_high = 0;
- status_data = 0;
- first_timestamp = 32'hFFFF_FFFF;
- for (i = 0; i < 16; i = i + 1) begin
- recv_packet();
- $display("TRACE event=0x%04x timestamp=%0d data=%0d", event_id, packet_time, data_value);
- if (i == 0)
- first_timestamp = packet_time;
- else if (packet_time !== first_timestamp) begin
- $display("FAIL snapshot timestamps differ");
- errors = errors + 1;
- end
- case (event_id)
- 16'h5101: heater_count = data_value;
- 16'h5102: heater_period = data_value;
- 16'h5103: heater_high = data_value;
- 16'h5111: fan_count = data_value;
- 16'h5112: fan_period = data_value;
- 16'h5113: fan_high = data_value;
- 16'h5121: motor1_count = data_value;
- 16'h5122: motor1_period = data_value;
- 16'h5123: motor1_high = data_value;
- 16'h5131: motor2_count = data_value;
- 16'h5132: motor2_period = data_value;
- 16'h5133: motor2_high = data_value;
- 16'h5141: motor3_count = data_value;
- 16'h5142: motor3_period = data_value;
- 16'h5143: motor3_high = data_value;
- 16'h5200: status_data = data_value;
- default: begin
- $display("FAIL unexpected event ID 0x%04x", event_id);
- errors = errors + 1;
- end
- endcase
- end
- if (heater_count == 0 || fan_count == 0 || motor1_count == 0 || motor2_count == 0 || motor3_count == 0) begin
- $display("FAIL one or more pulse counts are zero");
- errors = errors + 1;
- end else begin
- $display("PASS all five pulse counts > 0");
- end
- check_u32("heater_period", heater_period, 32'd1000);
- check_u32("heater_high", heater_high, 32'd250);
- check_u32("fan_period", fan_period, 32'd1250);
- check_u32("fan_high", fan_high, 32'd500);
- check_u32("motor1_period", motor1_period, 32'd2500);
- check_u32("motor1_high", motor1_high, 32'd1250);
- check_u32("motor2_period", motor2_period, 32'd5000);
- check_u32("motor2_high", motor2_high, 32'd1000);
- check_u32("motor3_period", motor3_period, 32'd10000);
- check_u32("motor3_high", motor3_high, 32'd7500);
- // Status bit layout check. PWM instantaneous level bits [4:0] are not
- // checked because the report can occur at any phase of each waveform.
- if (status_data[7:5] !== 3'b110) begin
- $display("FAIL limit levels expected=110 actual=%b", status_data[7:5]);
- errors = errors + 1;
- end else begin
- $display("PASS limit raw levels = 110");
- end
- if (status_data[12:8] !== 5'b11111) begin
- $display("FAIL valid flags expected=11111 actual=%b", status_data[12:8]);
- errors = errors + 1;
- end
- if (status_data[17:13] !== 5'b11111) begin
- $display("FAIL present flags expected=11111 actual=%b", status_data[17:13]);
- errors = errors + 1;
- end
- if (status_data[20:18] !== 3'b111) begin
- $display("FAIL limit rise-seen expected=111 actual=%b", status_data[20:18]);
- errors = errors + 1;
- end
- if (status_data[23:21] !== 3'b001) begin
- $display("FAIL limit fall-seen expected=001 actual=%b", status_data[23:21]);
- errors = errors + 1;
- end
- $display("");
- $display("==============================================");
- if (errors == 0) begin
- $display("ALL 8-CHANNEL TRACE UART TESTS PASSED");
- $display("==============================================");
- $finish;
- end else begin
- $display("8-CHANNEL TRACE UART TEST FAILED: %0d error(s)", errors);
- $display("==============================================");
- $fatal(1);
- end
- end
- endmodule
|