|
@@ -0,0 +1,940 @@
|
|
|
|
|
+`timescale 1ns/1ps
|
|
|
|
|
+
|
|
|
|
|
+module axis_travel_monitor_tb;
|
|
|
|
|
+
|
|
|
|
|
+ reg clk;
|
|
|
|
|
+ reg reset_n;
|
|
|
|
|
+ reg start;
|
|
|
|
|
+
|
|
|
|
|
+ reg signed [31:0] current_position;
|
|
|
|
|
+ reg signed [31:0] target_travel;
|
|
|
|
|
+
|
|
|
|
|
+ reg [31:0] tolerance;
|
|
|
|
|
+
|
|
|
|
|
+ reg limit_pos;
|
|
|
|
|
+ reg limit_neg;
|
|
|
|
|
+
|
|
|
|
|
+ wire signed [31:0] start_position;
|
|
|
|
|
+ wire signed [31:0] target_position;
|
|
|
|
|
+ wire signed [31:0] travel;
|
|
|
|
|
+
|
|
|
|
|
+ wire busy;
|
|
|
|
|
+ wire in_position;
|
|
|
|
|
+ wire done;
|
|
|
|
|
+
|
|
|
|
|
+ wire limit_hit;
|
|
|
|
|
+ wire limit_pos_hit;
|
|
|
|
|
+ wire limit_neg_hit;
|
|
|
|
|
+
|
|
|
|
|
+ integer errors;
|
|
|
|
|
+ integer checks;
|
|
|
|
|
+
|
|
|
|
|
+ integer i;
|
|
|
|
|
+
|
|
|
|
|
+ integer random_start;
|
|
|
|
|
+ integer random_distance;
|
|
|
|
|
+ integer random_tolerance;
|
|
|
|
|
+ integer random_target;
|
|
|
|
|
+ integer random_middle;
|
|
|
|
|
+
|
|
|
|
|
+ reg [31:0] lfsr;
|
|
|
|
|
+
|
|
|
|
|
+ axis_travel_monitor dut (
|
|
|
|
|
+ .clk(clk),
|
|
|
|
|
+ .reset_n(reset_n),
|
|
|
|
|
+
|
|
|
|
|
+ .start(start),
|
|
|
|
|
+
|
|
|
|
|
+ .current_position(current_position),
|
|
|
|
|
+ .target_travel(target_travel),
|
|
|
|
|
+
|
|
|
|
|
+ .tolerance(tolerance),
|
|
|
|
|
+
|
|
|
|
|
+ .limit_pos(limit_pos),
|
|
|
|
|
+ .limit_neg(limit_neg),
|
|
|
|
|
+
|
|
|
|
|
+ .start_position(start_position),
|
|
|
|
|
+ .target_position(target_position),
|
|
|
|
|
+ .travel(travel),
|
|
|
|
|
+
|
|
|
|
|
+ .busy(busy),
|
|
|
|
|
+ .in_position(in_position),
|
|
|
|
|
+ .done(done),
|
|
|
|
|
+
|
|
|
|
|
+ .limit_hit(limit_hit),
|
|
|
|
|
+ .limit_pos_hit(limit_pos_hit),
|
|
|
|
|
+ .limit_neg_hit(limit_neg_hit)
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ // ------------------------------------------------------------
|
|
|
|
|
+ // Clock
|
|
|
|
|
+ // ------------------------------------------------------------
|
|
|
|
|
+
|
|
|
|
|
+ initial clk = 0;
|
|
|
|
|
+ always #5 clk = ~clk;
|
|
|
|
|
+
|
|
|
|
|
+ // ------------------------------------------------------------
|
|
|
|
|
+ // Reset
|
|
|
|
|
+ // ------------------------------------------------------------
|
|
|
|
|
+
|
|
|
|
|
+ task reset_dut;
|
|
|
|
|
+ begin
|
|
|
|
|
+
|
|
|
|
|
+ reset_n = 0;
|
|
|
|
|
+ start = 0;
|
|
|
|
|
+
|
|
|
|
|
+ current_position = 0;
|
|
|
|
|
+ target_travel = 0;
|
|
|
|
|
+ tolerance = 0;
|
|
|
|
|
+
|
|
|
|
|
+ limit_pos = 0;
|
|
|
|
|
+ limit_neg = 0;
|
|
|
|
|
+
|
|
|
|
|
+ repeat (3)
|
|
|
|
|
+ @(posedge clk);
|
|
|
|
|
+
|
|
|
|
|
+ #1;
|
|
|
|
|
+
|
|
|
|
|
+ reset_n = 1;
|
|
|
|
|
+
|
|
|
|
|
+ @(posedge clk);
|
|
|
|
|
+ #1;
|
|
|
|
|
+
|
|
|
|
|
+ end
|
|
|
|
|
+ endtask
|
|
|
|
|
+
|
|
|
|
|
+ // ------------------------------------------------------------
|
|
|
|
|
+ // Generate one-cycle START pulse
|
|
|
|
|
+ // ------------------------------------------------------------
|
|
|
|
|
+
|
|
|
|
|
+ task start_move;
|
|
|
|
|
+
|
|
|
|
|
+ input integer position;
|
|
|
|
|
+ input integer distance;
|
|
|
|
|
+ input integer tolerance_value;
|
|
|
|
|
+
|
|
|
|
|
+ begin
|
|
|
|
|
+
|
|
|
|
|
+ current_position = position;
|
|
|
|
|
+ target_travel = distance;
|
|
|
|
|
+ tolerance = tolerance_value;
|
|
|
|
|
+
|
|
|
|
|
+ limit_pos = 0;
|
|
|
|
|
+ limit_neg = 0;
|
|
|
|
|
+
|
|
|
|
|
+ @(negedge clk);
|
|
|
|
|
+
|
|
|
|
|
+ start = 1;
|
|
|
|
|
+
|
|
|
|
|
+ @(posedge clk);
|
|
|
|
|
+ #1;
|
|
|
|
|
+
|
|
|
|
|
+ start = 0;
|
|
|
|
|
+
|
|
|
|
|
+ end
|
|
|
|
|
+ endtask
|
|
|
|
|
+
|
|
|
|
|
+ // ------------------------------------------------------------
|
|
|
|
|
+ // Check helper
|
|
|
|
|
+ // ------------------------------------------------------------
|
|
|
|
|
+
|
|
|
|
|
+ task expect_value;
|
|
|
|
|
+
|
|
|
|
|
+ input integer condition;
|
|
|
|
|
+ input [8*80-1:0] message;
|
|
|
|
|
+
|
|
|
|
|
+ begin
|
|
|
|
|
+
|
|
|
|
|
+ checks = checks + 1;
|
|
|
|
|
+
|
|
|
|
|
+ if (!condition) begin
|
|
|
|
|
+
|
|
|
|
|
+ $display(
|
|
|
|
|
+ "FAIL: %0s",
|
|
|
|
|
+ message
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ errors = errors + 1;
|
|
|
|
|
+
|
|
|
|
|
+ end
|
|
|
|
|
+
|
|
|
|
|
+ end
|
|
|
|
|
+ endtask
|
|
|
|
|
+
|
|
|
|
|
+ // ------------------------------------------------------------
|
|
|
|
|
+ // MAIN
|
|
|
|
|
+ // ------------------------------------------------------------
|
|
|
|
|
+
|
|
|
|
|
+ initial begin
|
|
|
|
|
+
|
|
|
|
|
+ errors = 0;
|
|
|
|
|
+ checks = 0;
|
|
|
|
|
+
|
|
|
|
|
+ lfsr = 32'h1ACE_B00C;
|
|
|
|
|
+
|
|
|
|
|
+ reset_dut();
|
|
|
|
|
+
|
|
|
|
|
+ $display("");
|
|
|
|
|
+ $display("============================================================");
|
|
|
|
|
+ $display(" AXIS TRAVEL MONITOR AUTOMATED VERIFICATION");
|
|
|
|
|
+ $display("============================================================");
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ // ========================================================
|
|
|
|
|
+ // TEST A
|
|
|
|
|
+ // Positive travel
|
|
|
|
|
+ // ========================================================
|
|
|
|
|
+
|
|
|
|
|
+ $display("");
|
|
|
|
|
+ $display("[A] Positive travel");
|
|
|
|
|
+
|
|
|
|
|
+ start_move(
|
|
|
|
|
+ 1000,
|
|
|
|
|
+ 500,
|
|
|
|
|
+ 5
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ start_position == 1000,
|
|
|
|
|
+ "start_position should be 1000"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ target_position == 1500,
|
|
|
|
|
+ "target_position should be 1500"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ busy == 1,
|
|
|
|
|
+ "positive move should be busy"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ current_position = 1200;
|
|
|
|
|
+ #1;
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ travel == 200,
|
|
|
|
|
+ "travel should be 200"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ in_position == 0,
|
|
|
|
|
+ "1200 must not be in target window"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ current_position = 1494;
|
|
|
|
|
+ #1;
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ in_position == 0,
|
|
|
|
|
+ "1494 must be outside tolerance"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ current_position = 1495;
|
|
|
|
|
+ #1;
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ in_position == 1,
|
|
|
|
|
+ "1495 must be inside tolerance"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ @(posedge clk);
|
|
|
|
|
+ #1;
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ done == 1,
|
|
|
|
|
+ "positive travel should complete"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ busy == 0,
|
|
|
|
|
+ "busy should clear after completion"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ $display("PASS [A] Positive travel");
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ // ========================================================
|
|
|
|
|
+ // TEST B
|
|
|
|
|
+ // Negative travel
|
|
|
|
|
+ // ========================================================
|
|
|
|
|
+
|
|
|
|
|
+ $display("");
|
|
|
|
|
+ $display("[B] Negative travel");
|
|
|
|
|
+
|
|
|
|
|
+ start_move(
|
|
|
|
|
+ 3000,
|
|
|
|
|
+ -500,
|
|
|
|
|
+ 5
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ start_position == 3000,
|
|
|
|
|
+ "negative start_position"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ target_position == 2500,
|
|
|
|
|
+ "negative target_position"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ current_position = 2506;
|
|
|
|
|
+ #1;
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ in_position == 0,
|
|
|
|
|
+ "2506 must be outside tolerance"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ current_position = 2505;
|
|
|
|
|
+ #1;
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ in_position == 1,
|
|
|
|
|
+ "2505 must be inside tolerance"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ @(posedge clk);
|
|
|
|
|
+ #1;
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ done == 1,
|
|
|
|
|
+ "negative travel should complete"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ travel == -495,
|
|
|
|
|
+ "negative travel calculation"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ $display("PASS [B] Negative travel");
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ // ========================================================
|
|
|
|
|
+ // TEST C
|
|
|
|
|
+ // Exact tolerance boundaries
|
|
|
|
|
+ // ========================================================
|
|
|
|
|
+
|
|
|
|
|
+ $display("");
|
|
|
|
|
+ $display("[C] Position tolerance window");
|
|
|
|
|
+
|
|
|
|
|
+ start_move(
|
|
|
|
|
+ 1000,
|
|
|
|
|
+ 500,
|
|
|
|
|
+ 5
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ current_position = 1494;
|
|
|
|
|
+ #1;
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ in_position == 0,
|
|
|
|
|
+ "target-6 must fail"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ current_position = 1495;
|
|
|
|
|
+ #1;
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ in_position == 1,
|
|
|
|
|
+ "target-5 must pass"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ current_position = 1505;
|
|
|
|
|
+ #1;
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ in_position == 1,
|
|
|
|
|
+ "target+5 must pass"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ current_position = 1506;
|
|
|
|
|
+ #1;
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ in_position == 0,
|
|
|
|
|
+ "target+6 must fail"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ $display("PASS [C] Tolerance window");
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ // ========================================================
|
|
|
|
|
+ // TEST D
|
|
|
|
|
+ // Positive limit during positive travel
|
|
|
|
|
+ // ========================================================
|
|
|
|
|
+
|
|
|
|
|
+ $display("");
|
|
|
|
|
+ $display("[D] Positive limit");
|
|
|
|
|
+
|
|
|
|
|
+ start_move(
|
|
|
|
|
+ 1000,
|
|
|
|
|
+ 2000,
|
|
|
|
|
+ 5
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ current_position = 1300;
|
|
|
|
|
+
|
|
|
|
|
+ limit_pos = 1;
|
|
|
|
|
+
|
|
|
|
|
+ @(posedge clk);
|
|
|
|
|
+ #1;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ busy == 0,
|
|
|
|
|
+ "positive limit must terminate travel"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ done == 0,
|
|
|
|
|
+ "limit termination must not be normal DONE"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ limit_hit == 1,
|
|
|
|
|
+ "limit_hit must latch"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ limit_pos_hit == 1,
|
|
|
|
|
+ "positive limit flag must latch"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ limit_neg_hit == 0,
|
|
|
|
|
+ "negative limit flag must remain clear"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ limit_pos = 0;
|
|
|
|
|
+
|
|
|
|
|
+ $display("PASS [D] Positive limit");
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ // ========================================================
|
|
|
|
|
+ // TEST E
|
|
|
|
|
+ // Negative limit during negative travel
|
|
|
|
|
+ // ========================================================
|
|
|
|
|
+
|
|
|
|
|
+ $display("");
|
|
|
|
|
+ $display("[E] Negative limit");
|
|
|
|
|
+
|
|
|
|
|
+ start_move(
|
|
|
|
|
+ 3000,
|
|
|
|
|
+ -2000,
|
|
|
|
|
+ 5
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ current_position = 2700;
|
|
|
|
|
+
|
|
|
|
|
+ limit_neg = 1;
|
|
|
|
|
+
|
|
|
|
|
+ @(posedge clk);
|
|
|
|
|
+ #1;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ busy == 0,
|
|
|
|
|
+ "negative limit must terminate travel"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ done == 0,
|
|
|
|
|
+ "negative limit must not generate DONE"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ limit_hit == 1,
|
|
|
|
|
+ "limit_hit must latch on negative limit"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ limit_neg_hit == 1,
|
|
|
|
|
+ "negative limit flag must latch"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ limit_neg = 0;
|
|
|
|
|
+
|
|
|
|
|
+ $display("PASS [E] Negative limit");
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ // ========================================================
|
|
|
|
|
+ // TEST F
|
|
|
|
|
+ // Wrong-direction limit must not terminate movement
|
|
|
|
|
+ // ========================================================
|
|
|
|
|
+
|
|
|
|
|
+ $display("");
|
|
|
|
|
+ $display("[F] Opposite limit immunity");
|
|
|
|
|
+
|
|
|
|
|
+ start_move(
|
|
|
|
|
+ 1000,
|
|
|
|
|
+ 1000,
|
|
|
|
|
+ 5
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ limit_neg = 1;
|
|
|
|
|
+
|
|
|
|
|
+ @(posedge clk);
|
|
|
|
|
+ #1;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ busy == 1,
|
|
|
|
|
+ "negative limit should not stop positive travel"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ limit_hit == 0,
|
|
|
|
|
+ "wrong-direction limit must not latch"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ limit_neg = 0;
|
|
|
|
|
+
|
|
|
|
|
+ $display("PASS [F] Opposite limit immunity");
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ // ========================================================
|
|
|
|
|
+ // TEST G
|
|
|
|
|
+ // Reset during travel
|
|
|
|
|
+ // ========================================================
|
|
|
|
|
+
|
|
|
|
|
+ $display("");
|
|
|
|
|
+ $display("[G] Reset during active travel");
|
|
|
|
|
+
|
|
|
|
|
+ start_move(
|
|
|
|
|
+ 5000,
|
|
|
|
|
+ 1000,
|
|
|
|
|
+ 5
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ current_position = 5300;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ reset_n = 0;
|
|
|
|
|
+
|
|
|
|
|
+ #1;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ busy == 0,
|
|
|
|
|
+ "reset must clear busy"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ done == 0,
|
|
|
|
|
+ "reset must clear done"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ limit_hit == 0,
|
|
|
|
|
+ "reset must clear limit_hit"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ reset_n = 1;
|
|
|
|
|
+
|
|
|
|
|
+ @(posedge clk);
|
|
|
|
|
+ #1;
|
|
|
|
|
+
|
|
|
|
|
+ $display("PASS [G] Reset");
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ // ========================================================
|
|
|
|
|
+ // TEST H
|
|
|
|
|
+ // New start while previous travel is still active
|
|
|
|
|
+ // ========================================================
|
|
|
|
|
+
|
|
|
|
|
+ $display("");
|
|
|
|
|
+ $display("[H] Restart / new segment");
|
|
|
|
|
+
|
|
|
|
|
+ start_move(
|
|
|
|
|
+ 1000,
|
|
|
|
|
+ 1000,
|
|
|
|
|
+ 5
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ current_position = 1300;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ // New travel begins from 1300.
|
|
|
|
|
+ start_move(
|
|
|
|
|
+ 1300,
|
|
|
|
|
+ 200,
|
|
|
|
|
+ 2
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ start_position == 1300,
|
|
|
|
|
+ "restart must capture new start position"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ target_position == 1500,
|
|
|
|
|
+ "restart target should be 1500"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ travel == 0,
|
|
|
|
|
+ "new segment travel must restart from zero"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ busy == 1,
|
|
|
|
|
+ "new segment should be busy"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ current_position = 1500;
|
|
|
|
|
+
|
|
|
|
|
+ @(posedge clk);
|
|
|
|
|
+ #1;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ done == 1,
|
|
|
|
|
+ "restarted travel should complete"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ $display("PASS [H] Restart");
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ // ========================================================
|
|
|
|
|
+ // TEST I
|
|
|
|
|
+ // Zero travel
|
|
|
|
|
+ // ========================================================
|
|
|
|
|
+
|
|
|
|
|
+ $display("");
|
|
|
|
|
+ $display("[I] Zero-distance travel");
|
|
|
|
|
+
|
|
|
|
|
+ start_move(
|
|
|
|
|
+ 12345,
|
|
|
|
|
+ 0,
|
|
|
|
|
+ 0
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ start_position == 12345,
|
|
|
|
|
+ "zero travel start position"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ target_position == 12345,
|
|
|
|
|
+ "zero travel target position"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ busy == 0,
|
|
|
|
|
+ "zero travel must not remain busy"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ done == 1,
|
|
|
|
|
+ "zero travel should complete immediately"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ in_position == 1,
|
|
|
|
|
+ "zero travel should be in position"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ $display("PASS [I] Zero-distance travel");
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ // ========================================================
|
|
|
|
|
+ // TEST J
|
|
|
|
|
+ // Negative absolute positions
|
|
|
|
|
+ // ========================================================
|
|
|
|
|
+
|
|
|
|
|
+ $display("");
|
|
|
|
|
+ $display("[J] Negative absolute positions");
|
|
|
|
|
+
|
|
|
|
|
+ start_move(
|
|
|
|
|
+ -5000,
|
|
|
|
|
+ 750,
|
|
|
|
|
+ 3
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ target_position == -4250,
|
|
|
|
|
+ "negative-coordinate target"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ current_position = -4250;
|
|
|
|
|
+
|
|
|
|
|
+ @(posedge clk);
|
|
|
|
|
+ #1;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ done == 1,
|
|
|
|
|
+ "negative-coordinate move should complete"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ expect_value(
|
|
|
|
|
+ travel == 750,
|
|
|
|
|
+ "travel across negative coordinates"
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ $display("PASS [J] Negative absolute positions");
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ // ========================================================
|
|
|
|
|
+ // TEST K
|
|
|
|
|
+ // 500 deterministic pseudo-random travel segments
|
|
|
|
|
+ // ========================================================
|
|
|
|
|
+
|
|
|
|
|
+ $display("");
|
|
|
|
|
+ $display("[K] 500 randomized travel segments");
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ for (i = 0; i < 500; i = i + 1) begin
|
|
|
|
|
+
|
|
|
|
|
+ // LFSR
|
|
|
|
|
+ lfsr = {
|
|
|
|
|
+ lfsr[30:0],
|
|
|
|
|
+ lfsr[31] ^
|
|
|
|
|
+ lfsr[21] ^
|
|
|
|
|
+ lfsr[1] ^
|
|
|
|
|
+ lfsr[0]
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ random_start =
|
|
|
|
|
+ $signed(lfsr[15:0]);
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ // Make distance between 50 and 1049.
|
|
|
|
|
+ random_distance =
|
|
|
|
|
+ 50 + (lfsr[25:16] % 1000);
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ // Random direction.
|
|
|
|
|
+ if (lfsr[26])
|
|
|
|
|
+ random_distance = -random_distance;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ random_tolerance =
|
|
|
|
|
+ lfsr[30:27] % 6;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ random_target =
|
|
|
|
|
+ random_start +
|
|
|
|
|
+ random_distance;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ random_middle =
|
|
|
|
|
+ random_start +
|
|
|
|
|
+ random_distance / 2;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ start_move(
|
|
|
|
|
+ random_start,
|
|
|
|
|
+ random_distance,
|
|
|
|
|
+ random_tolerance
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ checks = checks + 3;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ if (start_position != random_start) begin
|
|
|
|
|
+
|
|
|
|
|
+ $display(
|
|
|
|
|
+ "FAIL RANDOM START: case=%0d expected=%0d actual=%0d",
|
|
|
|
|
+ i,
|
|
|
|
|
+ random_start,
|
|
|
|
|
+ start_position
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ errors = errors + 1;
|
|
|
|
|
+
|
|
|
|
|
+ end
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ if (target_position != random_target) begin
|
|
|
|
|
+
|
|
|
|
|
+ $display(
|
|
|
|
|
+ "FAIL RANDOM TARGET: case=%0d expected=%0d actual=%0d",
|
|
|
|
|
+ i,
|
|
|
|
|
+ random_target,
|
|
|
|
|
+ target_position
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ errors = errors + 1;
|
|
|
|
|
+
|
|
|
|
|
+ end
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ if (!busy) begin
|
|
|
|
|
+
|
|
|
|
|
+ $display(
|
|
|
|
|
+ "FAIL RANDOM BUSY: case=%0d",
|
|
|
|
|
+ i
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ errors = errors + 1;
|
|
|
|
|
+
|
|
|
|
|
+ end
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ // Halfway should still be active.
|
|
|
|
|
+ current_position = random_middle;
|
|
|
|
|
+
|
|
|
|
|
+ @(posedge clk);
|
|
|
|
|
+ #1;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ checks = checks + 1;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ if (!busy) begin
|
|
|
|
|
+
|
|
|
|
|
+ $display(
|
|
|
|
|
+ "FAIL RANDOM EARLY DONE: case=%0d",
|
|
|
|
|
+ i
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ errors = errors + 1;
|
|
|
|
|
+
|
|
|
|
|
+ end
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ // Move exactly to target.
|
|
|
|
|
+ current_position = random_target;
|
|
|
|
|
+
|
|
|
|
|
+ @(posedge clk);
|
|
|
|
|
+ #1;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ checks = checks + 3;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ if (!done) begin
|
|
|
|
|
+
|
|
|
|
|
+ $display(
|
|
|
|
|
+ "FAIL RANDOM DONE: case=%0d start=%0d distance=%0d target=%0d current=%0d",
|
|
|
|
|
+ i,
|
|
|
|
|
+ random_start,
|
|
|
|
|
+ random_distance,
|
|
|
|
|
+ random_target,
|
|
|
|
|
+ current_position
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ errors = errors + 1;
|
|
|
|
|
+
|
|
|
|
|
+ end
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ if (busy) begin
|
|
|
|
|
+
|
|
|
|
|
+ $display(
|
|
|
|
|
+ "FAIL RANDOM BUSY CLEAR: case=%0d",
|
|
|
|
|
+ i
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ errors = errors + 1;
|
|
|
|
|
+
|
|
|
|
|
+ end
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ if (!in_position) begin
|
|
|
|
|
+
|
|
|
|
|
+ $display(
|
|
|
|
|
+ "FAIL RANDOM IN_POSITION: case=%0d",
|
|
|
|
|
+ i
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ errors = errors + 1;
|
|
|
|
|
+
|
|
|
|
|
+ end
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ if ((i % 100) == 0) begin
|
|
|
|
|
+
|
|
|
|
|
+ $display(
|
|
|
|
|
+ "Random progress: %0d / 500",
|
|
|
|
|
+ i
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ end
|
|
|
|
|
+
|
|
|
|
|
+ end
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ $display("PASS [K] 500 randomized travel segments");
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ // ========================================================
|
|
|
|
|
+ // FINAL RESULT
|
|
|
|
|
+ // ========================================================
|
|
|
|
|
+
|
|
|
|
|
+ $display("");
|
|
|
|
|
+ $display("============================================================");
|
|
|
|
|
+ $display("TOTAL CHECKS : %0d", checks);
|
|
|
|
|
+ $display("TOTAL ERRORS : %0d", errors);
|
|
|
|
|
+ $display("============================================================");
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ if (errors == 0) begin
|
|
|
|
|
+
|
|
|
|
|
+ $display("");
|
|
|
|
|
+ $display("ALL AXIS TRAVEL TESTS PASSED");
|
|
|
|
|
+
|
|
|
|
|
+ $display("");
|
|
|
|
|
+ $display("Verified:");
|
|
|
|
|
+ $display(" - positive travel");
|
|
|
|
|
+ $display(" - negative travel");
|
|
|
|
|
+ $display(" - start-position capture");
|
|
|
|
|
+ $display(" - relative travel calculation");
|
|
|
|
|
+ $display(" - target-position calculation");
|
|
|
|
|
+ $display(" - tolerance / in-position window");
|
|
|
|
|
+ $display(" - positive limit");
|
|
|
|
|
+ $display(" - negative limit");
|
|
|
|
|
+ $display(" - opposite-limit handling");
|
|
|
|
|
+ $display(" - reset");
|
|
|
|
|
+ $display(" - restart during travel");
|
|
|
|
|
+ $display(" - zero-distance travel");
|
|
|
|
|
+ $display(" - negative coordinates");
|
|
|
|
|
+ $display(" - 500 randomized travel segments");
|
|
|
|
|
+
|
|
|
|
|
+ $display("");
|
|
|
|
|
+ $display("============================================================");
|
|
|
|
|
+
|
|
|
|
|
+ $finish;
|
|
|
|
|
+
|
|
|
|
|
+ end else begin
|
|
|
|
|
+
|
|
|
|
|
+ $display("");
|
|
|
|
|
+ $display(
|
|
|
|
|
+ "AXIS TRAVEL TEST FAILED: %0d error(s)",
|
|
|
|
|
+ errors
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ $display("============================================================");
|
|
|
|
|
+
|
|
|
|
|
+ $fatal(1);
|
|
|
|
|
+
|
|
|
|
|
+ end
|
|
|
|
|
+
|
|
|
|
|
+ end
|
|
|
|
|
+
|
|
|
|
|
+endmodule
|