How to phase clock in system-verilog? - system-verilog

In System-verilog one can initialize clock and make it tick by code below:
bit clk;
initial begin
clk <= 0;
end
always #CLOCK_SEMI_PERIOD begin
clk <= ~clk;
end
But what if I want to make clock ticking with some phase? For example we have two clock, with different semiperiod and I want first one to start ticking from zero, while second one ticking from $urandom_range(6)ns.
___ ___ ___ ___
clk1 ___| |___| |___| |___| |___
____ ____ ____
clk2 _____| |____| |____| |____
I can't just write something like:
module top(output bit clk1,clk2);
parameter CLOCK1_SEMI_PERIOD = 10;
parameter CLOCK2_SEMI_PERIOD = 13;
int phase;
initial begin
clk1 <= 0;
clk2 <= 0;
phase = $urandom_range(9);
end
always #(CLOCK1_SEMI_PERIOD) begin
clk1 <= ~clk1;
end
always #(CLOCK2_SEMI_PERIOD) begin
#phase;
clk2 <= ~clk2;
end
endmodule
because it will increase second clock period by phase ns.
Then how can I implement this kind of ticking?

Use an initial/forever loop
initial begin
clk1 <= 0;
clk2 <= 0;
phase = $urandom_range(9);
fork
forever #(CLOCK1_SEMI_PERIOD)
clk1 <= ~clk1;
#phase forever #(CLOCK2_SEMI_PERIOD)
clk2 <= ~clk2;
join
end

Assignment skew concept can also be applied for introducing the required phase,
module top(output bit clk1,clk2);
parameter CLOCK1_SEMI_PERIOD = 10;
parameter CLOCK2_SEMI_PERIOD = 13;
int phase;
reg temp_1_clk2;//Added
wire temp_2_clk2;//Added
initial begin
clk1 <= 0;
clk2 <= 0;
phase = $urandom_range(9);
temp_1_clk2 = 0;
end
always #(CLOCK1_SEMI_PERIOD) begin
clk1 <= ~clk1;
end
always #(CLOCK2_SEMI_PERIOD) begin
temp_1_clk2 <= ~ temp_1_clk2;
end
assign #(phase) temp_2_clk2 = temp_1_clk2;//Introduces the required phase
always #(temp_2_clk2) begin //Output the clock
clk2 = ~ temp_2_clk2;
end
endmodule
Also let me know if there is any complication with above code or if any optimisation could be done
Thank you !

Related

How to pass a reference array of variables to task?

I am trying to pass a reference array of variables. It works fine with a reference to variable, but not with an array of variables. The goal with the task is to be able to take an array of variables, and read them on every clock edge.
So this code does not work
module tb;
logic clock = 0;
logic a = 0;
logic b = 0;
task automatic read_vars(ref logic clock, input int clock_edges = 10,
const ref logic signal_array[]);
repeat (clock_edges) begin
#(posedge clock) $display("#TIME: %t Clock edge", $time);
for (int i = 0; i < signal_array.size(); i++) begin
$display("Variable %0d: %0b", i, signal_array[i]);
end
end
endtask
always begin
#1 clock = 1;
#1 clock = 0;
end
always begin
#3 b = 1;
#3 b = 0;
end
always begin
#7 a = 1;
#7 a = 0;
end
initial begin
fork
read_vars(.clock(clock), .signal_array({a, b}));
join_none
#1000;
$finish();
end
endmodule
I get the following error
read_vars(.clock(clock), .signal_array({a, b}));
|
xmvlog: *E,BADRFA (tb.sv,25|45): invalid ref argument usage because actual argument is not a variable. [SystemVerilog].
module worklib.tb:sv
But this code works.
module tb;
logic clock = 0;
logic a = 0;
logic b = 0;
task automatic read_vars(ref logic clock, ref logic a, ref logic b, input int clock_edges = 10);
repeat (clock_edges) begin
#(posedge clock) begin
$display("#TIME: %t Clock edge", $time);
$display("a = %b ", a);
$display("b = %b ", b);
end
end
endtask
always begin
#1 clock = 1;
#1 clock = 0;
end
always begin
#3 b = 1;
#3 b = 0;
end
always begin
#7 a = 1;
#7 a = 0;
end
initial begin
fork
read_vars(.clock(clock), .a(a), .b(b));
join_none
#1000;
$finish();
end
endmodule
What you are trying to do is impossible in verilog.
First of all, having a reference to an array will not help in solving the issue. Arrays contain values of something. So creation of an array with {a,b} will just copy values of the variables into the array and updating variables will not be reflected in any case.
What you are after is an array of references to variables, which is impossible in a verilog.
However, class variables are always reference. So, you can wrap your vars in a class in test bench. Here is a modified example of yours:
class V;
logic val;
endclass:V
module tb;
V a = new;
V b = new;
V arr[] = '{a, b};
logic clock = 0;
//logic a = 0;
//logic b = 0;
task automatic read_vars(ref logic clock, input int clock_edges = 10,
V signal_array[]);
repeat (clock_edges) begin
#(posedge clock) $display("#TIME: %t Clock edge", $time);
for (int i = 0; i < signal_array.size(); i++) begin
$display("Variable %0d: %0b", i, signal_array[i].val);
end
end
endtask
always begin
#1 clock = 1;
#1 clock = 0;
end
always begin
#3 b.val = 1;
#3 b.val = 0;
end
always begin
#7 a.val = 1;
#7 a.val = 0;
end
initial begin
fork
read_vars(.clock(clock), .signal_array(arr));
join_none
#1000;
$finish();
end
endmodule

Implementation of wait statement inside a fork join block

what modification is needed to display i value =5,2,7? I am not getting output. Any suggestion will be helpful.
module tb#(int T=8);
bit [8:0] abc;
initial
begin
for(int i=0; i<T; i++)
begin
fork
begin
wait(abc[i] == 1'b1);
$display(i,$time);
end
join_none
end
end
initial
begin
abc[5] = 1'b1;
#10 abc[2] = 1'b1;
abc[7] = 1'b1;
end
endmodule
https://www.edaplayground.com/x/JUZR
There is only one instance of the variable i and it's value is 8 by the point in time that the process begins. You need to declare a variable k that has a different value for each iteration of the loop.
module tb#(int T=8);
bit [8:0] abc;
initial
begin
for(int i=0; i<T; i++)
begin
automatic int k = i;
fork
begin
wait(abc[k] == 1'b1);
$display(i,k,,,$time);
end
join_none
end
end
initial
begin
abc[5] = 1'b1;
#10 abc[2] = 1'b1;
abc[7] = 1'b1;
end
endmodule
See https://verificationacademy.com/forums/systemverilog/fork-joinnone-inside-loop

How to change and manipulate clock in SystemVerilog

I'm trying to manipulate my clock by using my own clock divider module.
module clockDivider(input logic input0,
input logic input1,
input logic clock,
output logic y);
// 00 = stop, 01 = slow, 10 = medium, 11 = fast;
if( ~input1 & ~input0 ) /*stop clock*/ ;
else if( ~input1 & input0 ) /*slow*/ ;
else if( input1 & ~input0 ) /*medium*/ ;
else if( input1 & input0 ) /*fast*/ ;
endmodule
As you can see above, according to my inputs, I will manipulate my clock and then let the step motor which is located in our FPGA board. But I couldn't figure out how to do it.
And also is there any website other than doulos? I think it is not really clear and contains just a small amount of information about System Verilog.
Thanks
You can directly having a modulo N counter to divide frequency by N.
Suppose here is your all 3 types of clock.
00 - No Clock
01 - Clock/4
02 - Clock/2
03 - Clock
Here is the code for it. Please note that its a conceptual code and not verified.
module clockDivider(input logic input0,
input logic input1,
input logic clock,
input logic reset,
output logic y);
// 00 = stop, 01 = slow, 10 = medium, 11 = fast;
parameter mod = 2;
reg [mod-1:0] count, max;
assign y = ( ~input1 & ~input0 ) ? 1'b0 : count[mod-1]; /*stop clock*/
always # (posedge clock)
begin
if( ~input1 & input0 ) /*slow*/
max <= (1 << (mod-2)) - 1'b1;
else if( input1 & ~input0 ) /*medium*/
max <= (1 << (mod-1)) - 1'b1;
else if( input1 & input0 ) /*fast*/
max <= (1 << mod) - 1'b1;
end
always # (posedge clock, negedge reset)
begin
if (!reset)
count <= 0;
else if (count == max)
count <= 0;
else
count <= count + 1'b1;
end
endmodule
By slow, medium and fast, I am going to assume that the fastest you are expecting by this logic is the speed of clock itself i.e you are implementing a clock divider.
I have assumed the following:
slow = 0.25*clock
medium = 0.5*clock
fast = clock
module clockDivider(input logic reset,
input logic input0,
input logic input1,
input logic clock,
output logic y);
// 00 = stop, 01 = slow, 10 = medium, 11 = fast;
logic delayed_y;
logic delayed_delayed_y;
logic [1:0] counter;
always #(posedge clock) begin
if (reset) begin
counter <= 'h0;
end
else begin
counter <= counter+1'b1;
end
end
always #(posedge clock) begin
if (reset) begin
delayed_y <= 1'b0;
end
else begin
delayed_y <= counter[0];
end
end
always #(posedge clock) begin
if (reset) begin
delayed_delayed_y <= 1'b0;
end
else begin
delayed_delayed_y <= counter[1];
end
end
always #(*) begin
if (reset) begin
y = 1'b0;
end
else begin
/*stop clock*/
if( ~input1 & ~input0 ) begin
y = 1'b0;
end
/*slow*/
else if( ~input1 & input0 ) begin
y = delayed_delayed_y;
end
/* medium*/
else if( input1 & ~input0 ) begin
y = delayed_y;
end
/* fast */
else if( input1 & input0 ) begin
y = clock;
end
end
end
endmodule
You can find a working example here: https://www.edaplayground.com/x/5J75
Note: If you are looking to multiply the clock, you need to use the DCM on your target FPGA. There is another method as well with a 2-input XOR gate and a clock buffer but I would stick to the DCM.

2 Bit Counter using JK Flip Flop in Verilog

I'm writing verilog code of 2 Bit Counter using JK Flip Flop that counts 0-3 and back to 0. I'm using Xilinx EDA. However I'm keep getting one error and I don't know what it means? The line numbers doesn't show up here, but error is located at "always #(posedge clk)".
ERROR:HDLCompiler:1401 - "C:\Users\Eduardo\Documents\SFSU\Fall 2014\Engr 378\Lab 3\TwoBitCounter\twobitcounter.v" Line 30: Signal q in unit jkff is connected to following multiple drivers:
`timescale 1ns / 1ps
module twobitcounter( q_out, qbar_out, j,k, clk, reset);
input [1:0] j; input [1:0] k; input clk; input reset;
output [1:0] q_out;
output [1:0] qbar_out;
wire [1:0] q_out;
wire [1:0] qbar_out;
wire clk;
assign qbar_out[0] = ~q_out[0];
assign j[0] = 1;
assign k[0] = 1;
assign j[1] = q_out[0];
assign k[1] = q_out[0];
jkff M1(q_out[0], qbar_out[0], j[0], k[0], clk, reset);
jkff M2(q_out[1], qbar_out[1], j[1], k[1], qbar_out[0]);
endmodule
module jkff(output q_out, output qbar_out,
input j, input k, input clk, input reset);
reg q;
assign q_out = q;
assign qbar_out = ~q;
initial begin
q = 1'b0;
end
always #(posedge clk)
begin
case({j,k})
{1'b0, 1'b0}: begin
q = q;
end
{1'b0, 1'b1}: begin
q = 1'b0;
end
{1'b1, 1'b0}: begin
q = 1'b1;
end
{1'b1, 1'b1}: begin
q = ~q;
end
endcase
end
always #(posedge reset)
begin
q = 1'b0;
end
endmodule
The issue is q is being set in two always blocks, which is not allowed in synthesis. Merge the two always blocks. Also, q is a flop, so it should be assigned using non-blocking assignment (<=), not blocking assignment (=).
always #(posedge clk or posedge reset)
begin
if (reset == 1'b1) begin
q <= 1'b0;
end
else begin
case({j,k})
{1'b0, 1'b0}: begin
q <= q;
end
{1'b0, 1'b1}: begin
q <= 1'b0;
end
{1'b1, 1'b0}: begin
q <= 1'b1;
end
{1'b1, 1'b1}: begin
q <= ~q;
end
endcase
end
end
You should almost never use initial blocks in synthesizable code. Most FPGAs allow it for initialization. ASICs designs however do not support it. For both cases, if there is an asynchronous reset/set then it initial block shouldn't be used.
The error is telling you that you are assigning q in different blocks. This creates an error. You are assigning q in both your initial block and your always block.
You should never use initial blocks in synthesizable code.

DRDY signal in Verilog

in my recent CPLD design I implemented a frequency counter with an SPI slave interface. The SPI master MCU reads out the counter after it is signalled by a DRDY pin. My counter updates the DRDY signal by flipping it (DRDY <=~DRDY) but it requires both edges pin interrupt sensitivity at the MCU side. I'd like to implement it more universally, like the typical ADC chip data ready signal behaviour, which is: a rising edge, held for x clocks then a falling edge. I thought it should be easy however I stucked in conditional loops as a beginner in Verilog.
Here is my code so far:
module ec2(INP, RST, SR, DRDY, DRDY2, DRDY3);
input INP, RST, SR;
output reg DRDY2, DRDY3;//LEDs for verification/testing purposes
output reg DRDY;
reg [23:0] Q;
event data_ready;
always #(posedge INP or negedge RST)
begin
if(!RST)
begin
Q <= 24'd0;
end
else if( (Q == 24'd1000000 && SR) || (Q == 24'd500000 && !SR))
begin
Q <= 24'd0;
->data_ready;
DRDY2 <=~DRDY2;
end
else
begin
Q <= Q + 1;
end
end
always #(data_ready)
begin
DRDY=1'b1;
//wait for 10ms?
DRDY=1'b0;
DRDY3 = DRDY2;
end
endmodule
Events are not synthesizable, you should convert data_ready into a signal (reg). A second counter which triggers DRDY at data_ready assertion would do the trick:
always #(posedge INP or negedge RST)
begin
if (RST)
begin
DRDY <= 1'b0;
drdy_count <= 4'd0;
end
else
begin
if (~DRDY && data_ready)
begin
DRDY <= 1'b1;
drdy_count <= 4'd0;
end
else if (DRDY)
begin
drdy_count <= drdy_count + 1;
if (drdy_count == 15)
DRDY <= 1'b0;
end
end
end