| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472 |
- `timescale 1ns/1ps
- `include "trace_build_id.vh"
- // -----------------------------------------------------------------------------
- // Single-CP2102 motor HIL + Trace top-level.
- //
- // One UART carries BOTH:
- // * control/HIL packets while the virtual motor is running
- // * Trace packets after the motor test finishes
- //
- // The PC program is the virtual motor and Trace receiver at the same time.
- // -----------------------------------------------------------------------------
- module top_ef2l45_motor_hil_trace #(
- parameter integer CLK_HZ = 25000000,
- parameter integer BAUD = 115200,
- parameter integer TRACE_DEPTH = 1024,
- parameter integer TRACE_ADDR_W = 10,
- parameter integer STEP_MS = 10,
- parameter integer FEEDBACK_TIMEOUT_CYCLES = 50000000,
- parameter integer LED_HOLD_CYCLES = 6250000
- )(
- input wire sys_clk,
- input wire reset_n,
- output wire uart_tx,
- input wire uart_rx,
- output wire led_heartbeat_n,
- output wire led_reset_n,
- output wire led_activity_n,
- output wire led_tx_n,
- output wire led_error_n
- );
- localparam [7:0] PKT_STATUS = 8'h81;
- localparam [7:0] PKT_TRACE = 8'h82;
- localparam [7:0] PKT_SUMMARY = 8'h83;
- localparam [7:0] PKT_MOTOR_CMD = 8'h90;
- localparam [15:0] STATUS_EVENT_ID = 16'hB17D;
- localparam [3:0] T_IDLE = 4'd0;
- localparam [3:0] T_SEND_STATUS = 4'd1;
- localparam [3:0] T_WAIT_STATUS = 4'd2;
- localparam [3:0] T_SEND_MOTOR = 4'd3;
- localparam [3:0] T_WAIT_MOTOR = 4'd4;
- localparam [3:0] T_WAIT_FB = 4'd5;
- localparam [3:0] T_APPLY_FB = 4'd6;
- localparam [3:0] T_CHECK = 4'd7;
- localparam [3:0] T_PREP = 4'd8;
- localparam [3:0] T_READ = 4'd9;
- localparam [3:0] T_SEND_TRACE = 4'd10;
- localparam [3:0] T_WAIT_TRACE = 4'd11;
- localparam [3:0] T_SEND_SUMMARY = 4'd12;
- localparam [3:0] T_WAIT_SUMMARY = 4'd13;
- wire rst_n;
- wire [7:0] rx_data;
- wire rx_valid;
- wire rx_framing_error;
- wire fb_packet_valid;
- wire [15:0] fb_packet_seq;
- wire [15:0] fb_packet_flags;
- wire [31:0] fb_packet_timestamp;
- wire [15:0] fb_packet_rpm;
- wire [15:0] fb_packet_current_ma;
- wire fb_crc_error;
- reg motor_start;
- reg motor_feedback_valid;
- reg [15:0] motor_feedback_rpm;
- reg [15:0] motor_feedback_current_ma;
- reg motor_feedback_fault;
- reg motor_feedback_encoder_ok;
- reg [15:0] motor_feedback_time_ms;
- wire motor_busy;
- wire motor_done;
- wire [6:0] motor_pwm;
- wire motor_enable;
- wire motor_direction;
- wire [15:0] motor_state_id;
- wire [7:0] motor_fault_code;
- wire motor_trace_valid;
- wire [15:0] motor_trace_id;
- wire [15:0] motor_trace_timestamp;
- wire [31:0] motor_trace_data;
- reg capture_reset;
- wire [15:0] captured_count;
- wire [31:0] drop_count;
- wire overflow;
- reg rd_en;
- reg [TRACE_ADDR_W-1:0] rd_addr;
- wire [63:0] rd_data;
- reg pkt_send;
- reg [7:0] pkt_type;
- reg [15:0] pkt_seq;
- reg [15:0] pkt_event_id;
- reg [31:0] pkt_timestamp;
- reg [31:0] pkt_data;
- wire pkt_busy;
- wire pkt_done;
- reg [3:0] top_state;
- reg [15:0] hil_seq;
- reg [31:0] sim_time_ms;
- reg [31:0] feedback_timeout_counter;
- reg [15:0] total_to_dump;
- reg [15:0] dump_index;
- reg [31:0] sim_time_latched;
- reg [31:0] drop_count_latched;
- reg hil_link_error;
- // Latch one validated feedback packet before applying it to the controller.
- reg [15:0] fb_seq_l;
- reg [15:0] fb_flags_l;
- reg [31:0] fb_time_l;
- reg [15:0] fb_rpm_l;
- reg [15:0] fb_current_l;
- reg [31:0] heartbeat_counter;
- reg heartbeat_phase;
- reg [31:0] activity_hold_counter;
- reg [31:0] tx_hold_counter;
- reg error_latched;
- wire start_cmd = rx_valid && (rx_data == 8'h53) && (top_state == T_IDLE); // 'S'
- wire ping_cmd = rx_valid && (rx_data == 8'h50) && (top_state == T_IDLE); // 'P'
- wire transaction_busy = (top_state != T_IDLE) &&
- (top_state != T_SEND_STATUS) &&
- (top_state != T_WAIT_STATUS);
- reset_sync u_reset_sync (
- .clk(sys_clk),
- .reset_n_ext(reset_n),
- .reset_n(rst_n)
- );
- uart_rx #(
- .CLK_HZ(CLK_HZ),
- .BAUD(BAUD)
- ) u_uart_rx (
- .clk(sys_clk),
- .reset_n(rst_n),
- .rx(uart_rx),
- .data(rx_data),
- .valid(rx_valid),
- .framing_error(rx_framing_error)
- );
- motor_feedback_rx u_feedback_rx (
- .clk(sys_clk),
- .reset_n(rst_n),
- .rx_data(rx_data),
- .rx_valid(rx_valid),
- .feedback_valid(fb_packet_valid),
- .feedback_seq(fb_packet_seq),
- .feedback_flags(fb_packet_flags),
- .feedback_timestamp(fb_packet_timestamp),
- .feedback_rpm(fb_packet_rpm),
- .feedback_current_ma(fb_packet_current_ma),
- .crc_error(fb_crc_error)
- );
- motor_controller_hil u_motor_controller (
- .clk(sys_clk),
- .reset_n(rst_n),
- .start(motor_start),
- .feedback_valid(motor_feedback_valid),
- .feedback_rpm(motor_feedback_rpm),
- .feedback_current_ma(motor_feedback_current_ma),
- .feedback_fault(motor_feedback_fault),
- .feedback_encoder_ok(motor_feedback_encoder_ok),
- .feedback_time_ms(motor_feedback_time_ms),
- .busy(motor_busy),
- .done(motor_done),
- .pwm_duty(motor_pwm),
- .motor_enable(motor_enable),
- .direction(motor_direction),
- .state_id(motor_state_id),
- .fault_code(motor_fault_code),
- .trace_valid(motor_trace_valid),
- .trace_id(motor_trace_id),
- .trace_timestamp(motor_trace_timestamp),
- .trace_data(motor_trace_data)
- );
- trace_capture_ram #(
- .TRACE_DEPTH(TRACE_DEPTH),
- .TRACE_ADDR_W(TRACE_ADDR_W)
- ) u_trace_ram (
- .clk(sys_clk),
- .reset_n(rst_n),
- .capture_reset(capture_reset),
- .trace_valid(motor_trace_valid && (top_state == T_APPLY_FB)),
- .trace_id(motor_trace_id),
- .trace_timestamp(motor_trace_timestamp),
- .trace_data(motor_trace_data),
- .captured_count(captured_count),
- .drop_count(drop_count),
- .overflow(overflow),
- .rd_en(rd_en),
- .rd_addr(rd_addr),
- .rd_data(rd_data)
- );
- trace_packet_tx #(
- .CLK_HZ(CLK_HZ),
- .BAUD(BAUD)
- ) u_packet_tx (
- .clk(sys_clk),
- .reset_n(rst_n),
- .send(pkt_send),
- .pkt_type(pkt_type),
- .seq(pkt_seq),
- .event_id(pkt_event_id),
- .timestamp(pkt_timestamp),
- .data(pkt_data),
- .uart_tx_o(uart_tx),
- .busy(pkt_busy),
- .done(pkt_done)
- );
- assign led_heartbeat_n = heartbeat_phase ? 1'b0 : 1'b1;
- assign led_reset_n = reset_n;
- assign led_activity_n = (activity_hold_counter != 0) ? 1'b0 : 1'b1;
- assign led_tx_n = (tx_hold_counter != 0) ? 1'b0 : 1'b1;
- assign led_error_n = error_latched ? 1'b0 : 1'b1;
- always @(posedge sys_clk or negedge rst_n) begin
- if (!rst_n) begin
- heartbeat_counter <= 32'd0;
- heartbeat_phase <= 1'b0;
- activity_hold_counter <= 32'd0;
- tx_hold_counter <= 32'd0;
- error_latched <= 1'b0;
- end else begin
- if (heartbeat_counter >= (CLK_HZ / 2) - 1) begin
- heartbeat_counter <= 32'd0;
- heartbeat_phase <= ~heartbeat_phase;
- end else begin
- heartbeat_counter <= heartbeat_counter + 1'b1;
- end
- if (start_cmd || transaction_busy)
- activity_hold_counter <= LED_HOLD_CYCLES;
- else if (activity_hold_counter != 0)
- activity_hold_counter <= activity_hold_counter - 1'b1;
- if (pkt_busy || pkt_send)
- tx_hold_counter <= LED_HOLD_CYCLES;
- else if (tx_hold_counter != 0)
- tx_hold_counter <= tx_hold_counter - 1'b1;
- if (start_cmd)
- error_latched <= 1'b0;
- if (rx_framing_error || fb_crc_error || overflow || hil_link_error || (motor_fault_code != 0))
- error_latched <= 1'b1;
- end
- end
- // Combinational control for one-cycle pulses and the shared packet transmitter.
- always @(*) begin
- motor_start = 1'b0;
- motor_feedback_valid = 1'b0;
- motor_feedback_rpm = fb_rpm_l;
- motor_feedback_current_ma = fb_current_l;
- motor_feedback_fault = fb_flags_l[0];
- motor_feedback_encoder_ok = fb_flags_l[1];
- motor_feedback_time_ms = fb_time_l[15:0];
- capture_reset = 1'b0;
- rd_en = 1'b0;
- rd_addr = dump_index[TRACE_ADDR_W-1:0];
- pkt_send = 1'b0;
- pkt_type = PKT_TRACE;
- pkt_seq = dump_index;
- pkt_event_id = rd_data[47:32];
- pkt_timestamp = {16'd0, rd_data[63:48]};
- pkt_data = rd_data[31:0];
- case (top_state)
- T_IDLE: begin
- if (start_cmd) begin
- capture_reset = 1'b1;
- motor_start = 1'b1;
- end
- end
- T_SEND_STATUS: begin
- pkt_type = PKT_STATUS;
- pkt_seq = 16'd0;
- pkt_event_id = STATUS_EVENT_ID;
- pkt_timestamp = 32'd0;
- pkt_data = `TRACE_BUILD_ID;
- if (!pkt_busy)
- pkt_send = 1'b1;
- end
- T_SEND_MOTOR: begin
- pkt_type = PKT_MOTOR_CMD;
- pkt_seq = hil_seq;
- pkt_event_id = motor_state_id;
- pkt_timestamp = sim_time_ms;
- pkt_data = {1'b0, motor_pwm, motor_enable, motor_direction, 22'd0};
- if (!pkt_busy)
- pkt_send = 1'b1;
- end
- T_APPLY_FB: begin
- motor_feedback_valid = 1'b1;
- end
- T_READ: begin
- rd_en = 1'b1;
- rd_addr = dump_index[TRACE_ADDR_W-1:0];
- end
- T_SEND_TRACE: begin
- if (!pkt_busy)
- pkt_send = 1'b1;
- end
- T_SEND_SUMMARY: begin
- pkt_type = PKT_SUMMARY;
- pkt_seq = total_to_dump;
- pkt_event_id = hil_link_error ? 16'hFFFE : 16'hFFFF;
- pkt_timestamp = sim_time_latched;
- pkt_data = drop_count_latched;
- if (!pkt_busy)
- pkt_send = 1'b1;
- end
- default: begin end
- endcase
- end
- always @(posedge sys_clk or negedge rst_n) begin
- if (!rst_n) begin
- top_state <= T_IDLE;
- hil_seq <= 16'd0;
- sim_time_ms <= 32'd0;
- feedback_timeout_counter <= 32'd0;
- total_to_dump <= 16'd0;
- dump_index <= 16'd0;
- sim_time_latched <= 32'd0;
- drop_count_latched <= 32'd0;
- hil_link_error <= 1'b0;
- fb_seq_l <= 16'd0;
- fb_flags_l <= 16'd0;
- fb_time_l <= 32'd0;
- fb_rpm_l <= 16'd0;
- fb_current_l <= 16'd0;
- end else begin
- case (top_state)
- T_IDLE: begin
- hil_seq <= 16'd0;
- sim_time_ms <= 32'd0;
- feedback_timeout_counter <= 32'd0;
- dump_index <= 16'd0;
- if (start_cmd) begin
- hil_link_error <= 1'b0;
- top_state <= T_SEND_MOTOR;
- end else if (ping_cmd) begin
- top_state <= T_SEND_STATUS;
- end
- end
- T_SEND_STATUS: begin
- if (!pkt_busy)
- top_state <= T_WAIT_STATUS;
- end
- T_WAIT_STATUS: begin
- if (pkt_done)
- top_state <= T_IDLE;
- end
- T_SEND_MOTOR: begin
- if (!pkt_busy)
- top_state <= T_WAIT_MOTOR;
- end
- T_WAIT_MOTOR: begin
- if (pkt_done) begin
- feedback_timeout_counter <= 32'd0;
- top_state <= T_WAIT_FB;
- end
- end
- T_WAIT_FB: begin
- if (fb_packet_valid) begin
- if (fb_packet_seq == hil_seq) begin
- fb_seq_l <= fb_packet_seq;
- fb_flags_l <= fb_packet_flags;
- fb_time_l <= fb_packet_timestamp;
- fb_rpm_l <= fb_packet_rpm;
- fb_current_l <= fb_packet_current_ma;
- top_state <= T_APPLY_FB;
- end else begin
- hil_link_error <= 1'b1;
- top_state <= T_PREP;
- end
- end else if (feedback_timeout_counter >= FEEDBACK_TIMEOUT_CYCLES - 1) begin
- hil_link_error <= 1'b1;
- top_state <= T_PREP;
- end else begin
- feedback_timeout_counter <= feedback_timeout_counter + 1'b1;
- end
- end
- T_APPLY_FB: begin
- top_state <= T_CHECK;
- end
- T_CHECK: begin
- hil_seq <= hil_seq + 1'b1;
- sim_time_ms <= sim_time_ms + STEP_MS;
- if (motor_done)
- top_state <= T_PREP;
- else
- top_state <= T_SEND_MOTOR;
- end
- T_PREP: begin
- total_to_dump <= captured_count;
- sim_time_latched <= sim_time_ms;
- drop_count_latched <= drop_count;
- dump_index <= 16'd0;
- if (captured_count == 0)
- top_state <= T_SEND_SUMMARY;
- else
- top_state <= T_READ;
- end
- T_READ: begin
- top_state <= T_SEND_TRACE;
- end
- T_SEND_TRACE: begin
- if (!pkt_busy)
- top_state <= T_WAIT_TRACE;
- end
- T_WAIT_TRACE: begin
- if (pkt_done) begin
- if ((dump_index + 1'b1) >= total_to_dump) begin
- top_state <= T_SEND_SUMMARY;
- end else begin
- dump_index <= dump_index + 1'b1;
- top_state <= T_READ;
- end
- end
- end
- T_SEND_SUMMARY: begin
- if (!pkt_busy)
- top_state <= T_WAIT_SUMMARY;
- end
- T_WAIT_SUMMARY: begin
- if (pkt_done)
- top_state <= T_IDLE;
- end
- default: top_state <= T_IDLE;
- endcase
- end
- end
- endmodule
|