DRDY signal in Verilog - counter

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

Related

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 phase clock in 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 !

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.

"Illegal reference to net " error in systemverilog - trying to design simple arbitrer

Here is the code I have for simple arbitrer
module arbiter(clk,rst,req,grnt,req_val);
input clk;
input rst;
input [3:0] req;
input [3:0] req_val;
output [3:0] grnt;
int j;
int i;
parameter A = 2'd0;
parameter B = 2'd1;
parameter C = 2'd2;
parameter D = 2'd3;
logic [1:0] current_state;
logic [1:0] next_state;
always_comb
begin
case (current_state)
D:
begin
grnt = 4'b1000;
j = 0;
for (i = 0; i<4;i++) begin
if (req[(j+i) % 4 ] == 1)
break;
end
case (i)
0: next_state = A;
1: next_state = B;
2: next_state = C;
3: next_state = D;
endcase
end
A:
begin
j = 1;
grnt = 4'b001;
for (i = 0; i<4;i++) begin
if (req[(i+j) % 4] == 1)
break;
end
case (i)
0: next_state = A;
1: next_state = B;
2: next_state = C;
3: next_state = D;
endcase
end
B:
begin
j = 2;
grnt = 4'b0010;
for (i = 0; i<4;i++ ) begin
if (req[(i+j) % 4] == 1)
break;
end
case (i)
0: next_state = A;
1: next_state = B;
2: next_state = C;
3: next_state = D;
endcase
end
C:
begin
j = 3;
grnt = 4'b0100;
for (i = 0; i<4;i++ ) begin
if (req[(i+j)% 4] == 1)
break;
end
case (i)
0: next_state = A;
1: next_state = B;
2: next_state = C;
3: next_state = D;
endcase
end
endcase
end
endmodule
always_ff#(posedge clk)
begin
current_state <= next_state;
end
endmodule
and I get the following error:
arbitrer.sv(21): (vlog-2110) Illegal reference to net "grnt".
and
arbitrer.sv(87): near "always_ff": syntax error, unexpected always_ff, expecting class.
So whats wrong with grnt ? I cant assign directly to a module output ?
There are two problems with your code.
You have used endmodule statement twice in your code. Just comment out one at line number 86.
You haven't define a data type for grnt variable, so by default it's a wire and wire can't be used in always block, so declare it as a reg/logic.

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.