diff --git a/ActionBurst.v b/ActionBurst.v deleted file mode 100644 index 0980d7c..0000000 --- a/ActionBurst.v +++ /dev/null @@ -1,84 +0,0 @@ -//-------------------------------------------------------------------------------- -// ActionBurst.v -// Konstantin Pavlov, pavlovconst@gmail.com -//-------------------------------------------------------------------------------- - -// INFO -------------------------------------------------------------------------------- -// Module is designed to generate one-shot trigger pulses on multiple channels (default is 8) -// Every output channel is triggered only once -// Channels get triggered in sequense from out[0] to out[8] -// That is useful when you need to start some tasks in exact order, but there are no convinient signals to line them up. -// Instance of ActionBurst() is started by high level on start input and the only way to stop generation before all channels get triggered is to reset the instance - - -/* --- INSTANTIATION TEMPLATE BEGIN --- - -ActionBurst AB1 ( - .clk( ), - .nrst( 1'b1 ), - .step_wdth( ), - .start( ), - .busy( ), - .out( ) - ); -defparam AB1.WIDTH = 8; - ---- INSTANTIATION TEMPLATE END ---*/ - - -module ActionBurst(clk,nrst,step_wdth,start,busy,out); - -parameter WIDTH = 8; - -input wire clk; -input wire nrst; -input wire [31:0] step_wdth; // Module buffers step_wdth in PG instance on the SECOND cycle ater start applyed! -input wire start; -output reg busy = 0; -output wire [(WIDTH-1):0] out; - -wire PgOut; -reg [31:0] state = 0; -//reg [31:0] step_wdth_buf = 0; // buffering is done in PG - -PulseGen PG( - .clk( clk ), - .nrst( start || busy ), - .low_wdth( step_wdth[31:0] ), - .high_wdth( 32'b1 ), - .rpt( 1'b1 ), - .start( busy ), - .busy( ), - .out( PgOut ) - ); - -always @ (posedge clk) begin - if (~nrst) begin - state[31:0] <= 0; - end else begin - if (~busy) begin - if (start) begin // buffering input values - state[31:0] <= 0; - //step_wdth_buf[31:0] <= step_wdth[31:0]; // buffering is done in PG - busy <= 1; - end // start - end else begin - if (PgOut) begin - if (state != (WIDTH-1)) begin - state[31:0] <= state[31:0] + 1'b1; - end else begin - busy <= 0; - end // state - end // PgOut - end // busy - end // nrst -end - -genvar i; -generate - for (i=0; i>1); -end + always_comb begin + gray_out[WIDTH-1:0] = bin_in[WIDTH-1:0] ^ ( bin_in[WIDTH-1:0] >> 1 ); + end endmodule diff --git a/gray2bin.sv b/gray2bin.sv index 6c3fe4a..c0f4871 100644 --- a/gray2bin.sv +++ b/gray2bin.sv @@ -1,5 +1,6 @@ //------------------------------------------------------------------------------ // gray2bin.sv +// published as part of https://github.com/pConst/basic_verilog // Konstantin Pavlov, pavlovconst@gmail.com //------------------------------------------------------------------------------ @@ -23,15 +24,16 @@ module gray2bin #( parameter WIDTH = 32 )( input [WIDTH-1:0] gray_in, - output [WIDTH-1:0] bin_out + output logic [WIDTH-1:0] bin_out ); -genvar i; -generate - for( i=0; i> i; + end + endfunction + +endclass + diff --git a/gray_functions_tb.sv b/gray_functions_tb.sv new file mode 100644 index 0000000..246530c --- /dev/null +++ b/gray_functions_tb.sv @@ -0,0 +1,175 @@ +//------------------------------------------------------------------------------ +// gray_functions_tb.sv +// published as part of https://github.com/pConst/basic_verilog +// Konstantin Pavlov, pavlovconst@gmail.com +//------------------------------------------------------------------------------ + +// INFO ------------------------------------------------------------------------ +// Testbench for gray_functions class + +// use this define to make some things differently in simulation +`define SIMULATION yes + +`timescale 1ns / 1ps + +module gray_functions_tb(); + +initial begin + // Print out time markers in nanoseconds + // Example: $display("[T=%0t] start=%d", $realtime, start); + $timeformat(-9, 3, " ns"); + + // seed value setting is intentionally manual to achieve repeatability between sim runs + $urandom( 1 ); // SEED value +end + +logic clk200; +sim_clk_gen #( + .FREQ( 200_000_000 ), // in Hz + .PHASE( 0 ), // in degrees + .DUTY( 50 ), // in percentage + .DISTORT( 10 ) // in picoseconds +) clk200_gen ( + .ena( 1'b1 ), + .clk( clk200 ), + .clkd( ) +); + +logic nrst_once; + +logic [31:0] clk200_div; +clk_divider #( + .WIDTH( 32 ) +) cd1 ( + .clk( clk200 ), + .nrst( nrst_once ), + .ena( 1'b1 ), + .out( clk200_div[31:0] ) +); + +logic [31:0] clk200_div_rise; +edge_detect ed1[31:0] ( + .clk( {32{clk200}} ), + .anrst( {32{nrst_once}} ), + .in( clk200_div[31:0] ), + .rising( clk200_div_rise[31:0] ), + .falling( ), + .both( ) +); + +// external device "asynchronous" clock +logic clk33; +logic clk33d; +sim_clk_gen #( + .FREQ( 200_000_000 ), // in Hz + .PHASE( 0 ), // in degrees + .DUTY( 50 ), // in percentage + .DISTORT( 1000 ) // in picoseconds +) clk33_gen ( + .ena( 1'b1 ), + .clk( clk33 ), + .clkd( clk33d ) +); + + +logic rst; +initial begin + rst = 1'b0; // initialization + repeat( 1 ) @(posedge clk200); + + forever begin + repeat( 1 ) @(posedge clk200); // synchronous rise + rst = 1'b1; + //$urandom( 1 ); // uncomment to get the same random pattern EVERY nrst + + repeat( 2 ) @(posedge clk200); // synchronous fall, controls rst pulse width + rst = 1'b0; + + repeat( 100 ) @(posedge clk200); // controls test body width + end +end +logic nrst; +assign nrst = ~rst; + + +logic rst_once; +initial begin + rst_once = 1'b0; // initialization + repeat( 1 ) @(posedge clk200); + + repeat( 1 ) @(posedge clk200); // synchronous rise + rst_once = 1'b1; + + repeat( 2 ) @(posedge clk200); // synchronous fall, controls rst_once pulse width + rst_once = 1'b0; +end +//logic nrst_once; // declared before +assign nrst_once = ~rst_once; + + +// random pattern generation +logic [31:0] rnd_data; +always_ff @(posedge clk200) begin + rnd_data[31:0] <= $urandom; + end + +initial forever begin + @(posedge nrst); + $display("[T=%0t] rnd_data[]=%h", $realtime, rnd_data[31:0]); +end + + +// helper start strobe appears unpredictable up to 20 clocks after nrst +logic start; +initial forever begin + start = 1'b0; // initialization + + @(posedge nrst); // synchronous rise after EVERY nrst + repeat( $urandom_range(0, 20) ) @(posedge clk200); + start = 1'b1; + + @(posedge clk200); // synchronous fall exactly 1 clock after rise + start = 1'b0; +end + + +initial begin +// #10000 $stop; +// #10000 $finish; +end + +// Module under test =========================================================== + +logic [15:0] seq_cntr = '0; + +logic [31:0] id = '0; +always_ff @(posedge clk200) begin + if( ~nrst_once ) begin + seq_cntr[15:0] <= '0; + id[31:0] <= '0; + end else begin + // incrementing sequence counter + if( seq_cntr[15:0]!= '1 ) begin + seq_cntr[15:0] <= seq_cntr[15:0] + 1'b1; + end + + if( seq_cntr[15:0]<300 ) begin + id[31:0] <= '1; + //id[31:0] <= {4{rnd_data[15:0]}}; + end else begin + id[31:0] <= '0; + end + end +end + +`include "gray_functions.vh" + +logic [15:0] gray; +logic [15:0] bin; +always_comb begin + gray[15:0] = gray_functions#(16)::bin2gray( seq_cntr[15:0] ); + bin[15:0] = gray_functions#(16)::gray2bin( gray[15:0] ); +end + +endmodule +