| // | |
| // Switch between two clock sources testbench. | |
| // | |
| // | |
| // Design by G.J. van Loo, FenLogic Ltd, 15-January-2017. | |
| // | |
| // This program is free software. It comes without any guarantees or | |
| // warranty to the extent permitted by applicable law. Although the | |
| // author has attempted to find and correct any bugs in this free software | |
| // program, the author is not responsible for any damage or losses of any | |
| // kind caused by the use or misuse of the program. You can redistribute | |
| // the program and or modify it in any form without obligations, but the | |
| // author would appreciated if the credits stays in. | |
| // | |
| module clock_mux_test; | |
| // For specify to work CLK1PERIOD must be <= CLK2PERIOD !! | |
| localparam CLK1PERIOD = 8, | |
| CLK2PERIOD = 10; | |
| reg clk1; // Clock 1 | |
| reg clk2; // Clock 2 | |
| reg reset_n; // System reset | |
| reg sel_clk2; // Select clock2 when high | |
| wire clk1or2; // Selected clock | |
| integer l,r1,r2; | |
| initial | |
| begin | |
| sel_clk2 = 1'b0; | |
| reset_n = 1'b0; | |
| #50; | |
| reset_n = 1'b1; | |
| #250; | |
| sel_clk2 = 1'b1; | |
| #250; | |
| sel_clk2 = 1'b0; | |
| #1000; | |
| // Test reset release with sel2 high | |
| reset_n = 1'b0; | |
| #50; | |
| sel_clk2 = 1'b1; | |
| #50; | |
| reset_n = 1'b1; | |
| #250; | |
| // Test reset release and sel2 high at the same time | |
| reset_n = 1'b0; | |
| #50; | |
| sel_clk2 = 1'b1; | |
| reset_n = 1'b1; | |
| #250; | |
| #1000; | |
| // | |
| // Test clock not present | |
| // | |
| force clk2 = 1'b0; | |
| #250; | |
| // switch to not running clk2 | |
| sel_clk2 = 1'b1; | |
| #250; | |
| // switch back to clk1 | |
| sel_clk2 = 1'b0; | |
| #250; | |
| // switch to not running clk2 | |
| sel_clk2 = 1'b1; | |
| #250; | |
| // now clock2 comes on again | |
| // whilst it is selected | |
| release clk2; | |
| #250; | |
| // switch back to clk1 | |
| sel_clk2 = 1'b0; | |
| #250; | |
| // Switch often but never faster then 2xslowest input clock period | |
| for (l=0; l<10000; l=l+1) | |
| begin | |
| r1 = (($random>>3)&32'h1F)+2*CLK2PERIOD; | |
| r2 = (($random>>4)&32'h1F)+2*CLK2PERIOD; | |
| sel_clk2 = 1'b1; | |
| #r1; | |
| sel_clk2 = 1'b0; | |
| #r2; | |
| end | |
| #1000; | |
| // Really nasty and illegal clock switching. | |
| // Causes low period violations. | |
| // This gives more confidence that the testbench seems to work. | |
| $display("@%0t Illegal 'sel_clk2' pattern hereafter",$time); | |
| $display(" gives rise to low period violations."); | |
| $display(" Ignore all warnings from here."); | |
| for (l=0; l<500; l=l+1) | |
| begin | |
| r1 = ($random>>3)&32'h1F+CLK2PERIOD; | |
| r2 = ($random>>4)&32'h1F+CLK2PERIOD; | |
| sel_clk2 = 1'b1; | |
| #r1; | |
| sel_clk2 = 1'b0; | |
| #r2; | |
| end | |
| $stop; | |
| end | |
| initial | |
| begin | |
| clk1 = 1'b0; | |
| forever | |
| #(CLK1PERIOD/2) clk1 <= ~clk1; | |
| end | |
| initial | |
| begin | |
| clk2 = 1'b0; | |
| forever | |
| #(CLK2PERIOD/2) clk2 <= ~clk2; | |
| end | |
| clock_mux clock_mux0 | |
| ( | |
| .clk1 (clk1), // Clock 1 | |
| .clk2 (clk2), // Clock 2 | |
| .reset_n (reset_n), // System reset | |
| .sel_clk2(sel_clk2), // Select clock2 when high | |
| .clk1or2 (clk1or2) // Selected clock | |
| ); | |
| // Now check if time high or low is ever smaller than CLK1PERIOD/2 | |
| // (This is why CLK1PERIOD <= CLK2PERIOD) | |
| specify | |
| $width(posedge clk1or2, CLK1PERIOD/2); | |
| $width(negedge clk1or2, CLK1PERIOD/2); | |
| endspecify | |
| endmodule // clock_mux_test | |