Why output is in unknown state? - verilog

I want to make a serial comparator using a dff with async reset base on with continuous assignment. but output will come in unknown (x) state I don't know why. I checked every wire and assigned each of them an expression
dff code (verilog):
module comparator (input a, input b, input reset, input clk, output [1:0] o);
wire q0_p, q0_n, q1_p, q1_n, d0, d1;
wire s0, r0, w01, w02, s1, r1, w11, w12;
assign d0 = (q1_n & q0_p) | (q0_p & ~a & b) | (q1_n & ~a & b);
assign d1 = (q1_p & q0_n) | (q0_n & a & ~b) | (q1_p & a & ~b);
assign w01 = ~(w02 & s0);
assign s0 = ~(w01 & reset & clk);
assign r0 = ~(s0 & clk & w02);
assign w02 = ~(r0 & d0 & reset);
assign q0_p = ~(s0 & q0_n);
assign q0_n = ~(q0_p & r0 & reset);
assign w11 = ~(w12 & s1);
assign s1 = ~(w11 & reset & clk);
assign r1 = ~(s1 & clk & w12);
assign w12 = ~(r1 & d1 & reset);
assign q1_p = ~(s1 & q1_n);
assign q1_n = ~(q1_p & r1 & reset);
assign o[0] = q0_p;
assign o[1] = q1_p;
endmodule
testbench:
module test();
reg a, b, reset, clk = 0;
wire [1:0] o;
comparator cmp(a, b, reset, clk, o);
always #1 clk <= ~clk;
initial begin
$monitor("%b %b %b", a, b, o);
reset = 0;
reset = 1;
// a = 1110, b = 1011
#1 a = 1; b = 1;
#1 a = 1; b = 0;
#1 a = 1; b = 1;
#1 a = 0; b = 1;
$finish();
end
endmodule
output:
1 1 xx
1 0 xx
1 1 xx
0 1 xx

if 'D' is in 'x' state, as soon as you deassert reset, the outputs will become 'x' again. You need to set a known value to 'D' before deassert. Also, you need a delay between assert and deassert of reset.
For example,
initial begin
$monitor("%b %b %b", a, b, o);
reset = 0;
#1
a = 0; b = 0;
reset = 1;
...

As you can see, it is non-trivial to debug simulation problems when trying to model a logic circuit with feedback at the gate level. You get unknowns (x) because you do not correctly initialize all the signals which need to be initialized.
Your testbench does not really drive the reset signal to 0 because you immediately drive it to 1 (both happen at time 0). You should add a delay between the 2 values. However, that will still be insufficient to initialize all the signals.
The solution is to use the appropriate model for your logic: behavioral level. This is trivial in Verilog. The common way to model a dff with an asynchronous active-low reset is:
always #(posedge clk or negedge nreset) begin
if (!nreset) begin
q <= 1'b0;
end else begin
q <= d;
end
end
The beauty of digital design and Verilog is that you can abstract away all the unnecessary details. The code above eliminates all the issues with properly initializing all your signals.

Related

Verilog waveform of inputs is identical, however, output is different

I'm currently trying to implement an up/down counter in Verilog with dataflow modeling. While trying to add a limit to the counter (so that the counter will reset to the appropriate value when the limit is reached) I stumbled into an error. Even though the waveforms of clear_q, clear, and clear_s are the same, likewise the waveforms of preset_q, preset, and preset_s are the same, the behaviors of Q, R, and S are different, notably Q is different from R and S.
Picture of Waveforms
Of note, the rising edge of the three clear signals is not aligned with the falling edge of the clock, however, Q going from 0 to F is aligned with the rising edge of the three clear signals.
From the code, it is clear that the only difference between clear_q and clear_s, and preset_q and preset_s, is the simple inclusion of "& 1'b1". The only way that Q would go to F from 0 is if preset_q goes low and clear_q goes high momentarily, however from the waveform preset_q stays high.
The purpose of the "& 1'b1" is to temporarily simulate the equality checker commented out.
What exactly is wrong with the "& 1'b1" or is there another issue at hand?
limited_ud_counter.v
module limited_ud_counter(input clk, preset, clear, up, input[3:0] limit, output[3:0] Q);
//wire[3:0] n;
wire[3:0] Q, R, S;
wire e, preset_p, clear_p;
// assign n[0] = Q[0] ^ limit[0];
// assign n[1] = Q[1] ^ limit[1];
// assign n[2] = Q[2] ^ limit[2];
// assign n[3] = Q[3] ^ limit[3];
// assign e = !(n[0] | n[1] | n[2] | n[3]);
assign e = 0;
//(preset & clear & (!(e & up))) | (preset & !clear);
//(preset & clear & !(e & (!up))) | (clear & !preset);
assign preset_q = ((preset & clear) & 1'b1) | (preset & !clear);
assign clear_q = ((preset & clear) & 1'b1) | (clear & !preset);
assign preset_s = ((preset & clear)) | (preset & !clear);
assign clear_s = ((preset & clear)) | (clear & !preset);
//Q not showing expected behavior
up_down_counter udc0(clk, preset_q, clear_q, up, Q);
//R showing expected behavior
up_down_counter udc1(clk, preset, clear, up, R);
//S also showing expected behavior
up_down_counter udc2(clk, preset_s, clear_s, up, S);
endmodule;
up_down_counter.v
module up_down_counter(input clk, preset, clear, up, output[3:0] Q);
wire[2:0] jk_up, jk_down, jk;
wire[3:0] Q_bar;
assign jk_up[0] = Q[0] & up;
assign jk_down[0] = Q_bar[0] & (!up);
assign jk[0] = jk_up[0] | jk_down[0];
assign jk_up[1] = Q[1] & jk_up[0];
assign jk_down[1] = Q_bar[1] & jk_down[0];
assign jk[1] = jk_up[1] | jk_down[1];
assign jk_up[2] = Q[2] & jk_up[1];
assign jk_down[2] = Q_bar[2] & jk_down[1];
assign jk[2] = jk_up[2] | jk_down[2];
jkff jkff0(clk, 1'b1, 1'b1, preset, clear, Q[0], Q_bar[0]);
jkff jkff1(clk, jk[0], jk[0], preset, clear, Q[1], Q_bar[1]);
jkff jkff2(clk, jk[1], jk[1], preset, clear, Q[2], Q_bar[2]);
jkff jkff3(clk, jk[2], jk[2], preset, clear, Q[3], Q_bar[3]);
endmodule
jkff.v
module jkff(input clk, j, k, preset, clear, output q, q_bar);
wire j_p, k_p, q_m, q_bar_m;
assign j_p = !(j & q_bar & clk);
assign k_p = !(k & q & clk);
sr sr0(j_p, k_p, preset, clear, q_m, q_bar_m);
gated_sr gsr0(!clk, q_m, q_bar_m, preset, clear, q, q_bar);
endmodule;
sr.v
//set, reset, preset, clear are active low
module sr(input set, reset, preset, clear, output q, q_bar);
assign q = !(set & preset & q_bar);
assign q_bar = !(reset & clear & q);
endmodule
gated_sr.v
//enable, set, and reset are active high; preset and clear are active low
module gated_sr(input enable, set, reset, preset, clear, output q, q_bar);
wire set_p, reset_p;
assign set_p = !(set & enable);
assign reset_p = !(reset & enable);
sr sr0 (
.set (set_p),
.reset (reset_p),
.preset (preset),
.clear (clear),
.q (q),
.q_bar (q_bar)
);
endmodule
testbench code
`include "limited_ud_counter.v"
`include "../UpDownCounter/up_down_counter.v"
`include "../JKFF/jkff.v"
`include "../GatedSR/gated_sr.v"
`include "../SR/sr.v"
module limited_ud_counter_tb;
reg clk, preset, clear, up;
reg[3:0] limit;
wire[3:0] Q;
always begin
#5 clk = !clk;
end
initial begin
$dumpfile("limited_ud_counter_tb.vcd");
$dumpvars;
clk = 1'b0;
up = 1'b1;
preset = 1'b1;
clear = 1'b0;
limit = 4'b1100;
#12 clear = 1'b1;
#200 $finish;
end
limited_ud_counter ludc0(clk, preset, clear, up, limit, Q);
endmodule
This is using Icarus Verilog if that helps.
I've figured out the issue. What was happening was while the values of preset_q and clear_q were being computed, there was a moment where both preset_q and clear_q went low. Since these were fed into SR-latches, an error would occur.
All at the same time (t=12), preset_q and clear_q went like this:
preset_q = 1, clear_q = 0
preset_q = 0, clear_q = 0 <- this is the problem
preset_q = 1, clear_q = 1
Since these all happened at the same time, only the final values were visible on the waveform. To fix this, I chose to make both preset and clear signals go high if they were both low at the SR-latch level.

Verilog 4-bit comparator structural model

I would like to design a 4-bit comparator as a structural model using a 2-bit comparator.
As shown in the attached picture, after giving initial values ​​to each of Gt_I, Eq_I, and Lt_I, you need to design a 4-bit comparator as a structural model of a 2-bit comparator.
The code I've tried is a syntax error in assigning the initial values ​​of Gt_I, Eq_I, and Lt_I. I want to know a solution.
<2bit>
module Comparator_new(a, b, Gt_I, Eq_I, Lt_I, Gt_O, Eq_O, Lt_O);
input [1:0] a;
input [1:0] b;
input Gt_I, Eq_I, Lt_I;
output Gt_O, Eq_O, Lt_O;
assign Gt_O = ~(a[1] & ~b[1] | ~a[1] & b[1]) & a[0] & ~b[0] | a[1] & ~b[1];
assign Eq_O = ~(a[0] & ~b[0] | ~a[0] & b[0]) & ~(a[1] & ~b[1] | ~a[1] & b[1]);
assign Lt_O = ~(a[1] & ~b[1] | ~a[1] & b[1]) & ~a[0] & b[0] | ~a[1] & b[1];
endmodule
<4bit>
module Comparator_stru(a, b, Gt_I, Eq_I, Lt_I, Gt, Eq, Lt);
input [3:0] a;
input [3:0] b;
input Gt_I = 2'b00;
input Eq_I = 2'b01;
input Lt_I = 2'b00;
output Gt, Eq, Lt;
wire x, y, z;
Comparator_new c0(.a(a), .b(b), .Gt_I(Gt_I), .Eq_I(Eq_I), .Lt_I(Lt_I), .Gt_O(x), .Eq_O(y), .Lt_O(z));
Comparator_new c1(.a(a), .b(b), .Gt_I(x), .Eq_I(y), .Lt_I(z), .Gt_O(Gt), .Eq_O(Eq), .Lt_O(Lt));
assign Gt_O = ~(a[3] & ~b[3] | ~a[3] & b[3]) & a[2] & ~b[2] | a[3] & ~b[3];
assign Eq_O = ~(a[2] & ~b[2] | ~a[2] & b[2]) & ~(a[3] & ~b[3] | ~a[3] & b[3]);
assign Lt_O = ~(a[3] & ~b[3] | ~a[3] & b[3]) & ~a[2] & b[2] | ~a[3] & b[3];
endmodule
`timescale 1ns/10ps
module tb_Comparator_stru;
reg a, b;
wire Gt, Eq, Lt;
Comparator_stru tb(.a(a), .b(b), .Gt(Gt), .Eq(Eq), .Lt(Lt));
initial
begin
$dumpfile("test_Comparator_stru_out.vcd");
$dumpvars(-1, tb);
$monitor("%b", Gt);
$monitor("%b", Eq);
$monitor("%b", Lt);
end
initial
begin
a = 2'b00; b = 2'b00;
#50 a = 2'b01; b = 2'b00;
#50 a = 2'b01; b = 2'b01;
#50 a = 2'b01; b = 2'b10;
#50 a = 2'b10; b = 2'b10;
#50 a = 2'b11; b = 2'b10;
#50 a = 2'b11; b = 2'b11;
#50;
end
endmodule
Gt_I, Eq_I, and Lt_I are input ports of module Comparator_stru. They are driven by, and receive values from their drivers.
In your case, if you want to assign initial values to them, you need to use initial block, and do it in the testbench.
<4bit>
module Comparator_stru(a, b, Gt_I, Eq_I, Lt_I, Gt, Eq, Lt);
input [3:0] a;
input [3:0] b;
input Gt_I; // = 2'b00;
input Eq_I; // = 2'b01;
input Lt_I; // = 2'b00;
testbench
Comparator_stru tb(.a(a), .b(b), .Gt_I(Gt_I), .Eq_I(Eq_I), .Lt_I(Lt_I), .Gt(Gt), .Eq(Eq), .Lt(Lt));
initial begin
Gt_I = 1'b0;
Eq_I = 1'b1;
Lt_I = 1'b0;
end
module Comparator_stru() will have assign variables as Gt, Lt, Eq instead of Gt_O, Lt_O, Eq_O as this module is not having Gt_O, Lt_O, Eq_O as outputs.

Verilog Constructing synchronous 4-bit counter using negative edged JK Flip Flop testbench problem

I am constructing a 4-bit mod 12 counter
(0->1->2->...->11->0) in Verilog.
However when I try to simulate this code with testbench in Vivado FPGA,
it doesn't seems to operate correctly. Output of the counter module always shows 0.
I tried to modify testbench codes in several ways but nothing has been changed.
Actually I constructed 2 more counter(3-6-9 counter, 2-digit decade counter),
all counters are not simulated as I expected.
module counter3
`timescale 1ns / 1ps
module counter_3(input RESET_N, input CK, output[3:0] COUNT, output[3:0] COMP);
wire J3, K3, J2, K2, J1, K1, J0, K0;
assign J3 = COUNT[2] & COUNT[1] & COUNT[0];
assign K3 = COUNT[1] & COUNT[0];
assign J2 = COMP[3] & COUNT[1] & COUNT[0];
assign K2 = COUNT[1] & COMP[0];
assign J1 = COUNT[0];
assign K1 = COUNT[0];
assign J0 = 1;
assign K0 = 1;
edgeTriggeredJKFF jk1(.RESET_N(RESET_N), .J(J3), .K(K3), .CK(CK), .Q(COUNT[3]), .Q_(COMP[3]));
edgeTriggeredJKFF jk2(.RESET_N(RESET_N), .J(J2), .K(K2), .CK(CK), .Q(COUNT[2]), .Q_(COMP[2]));
edgeTriggeredJKFF jk3(.RESET_N(RESET_N), .J(J1), .K(K1), .CK(CK), .Q(COUNT[1]), .Q_(COMP[1]));
edgeTriggeredJKFF jk4(.RESET_N(RESET_N), .J(J0), .K(K0), .CK(CK), .Q(COUNT[0]), .Q_(COMP[0]));
endmodule
module edgeTriggeredJKFF
`timescale 1ns / 1ps
module edgeTriggeredJKFF(input RESET_N, input J, input K, input CK, output reg Q, output reg Q_);
initial begin
Q = 0;
Q_ = ~Q;
end
always #(negedge CK) begin
Q = RESET_N & (J&~Q | ~K&Q);
Q_ = ~RESET_N | ~Q;
end
endmodule
Testbench Code
`timescale 1ns / 1ps
module test_tb();
reg counter3_RESET_N;
wire [3:0] counter3_CNT;
reg CK;
integer i;
counter_3 c3 (.RESET_N(counter3_RESET_N), .CK(counter3_ck), .COUNT(counter3_CNT));
always #3 CK = ~CK;
initial begin
Passed = 0;
Failed = 0;
CK <= 0;
counter_3_test;
end
task counter_3_test;
begin
CK <= 0;
counter3_RESET_N <= 1;
#60 counter3_RESET_N <= 0;
#6 counter3_RESET_N <= 1;
#48;
end
endtask
endmodule
You forgot to pass your clock down to the DUT. Instead of CK you passed counter3_ck which has not even been declared. I suggest that you the ``default_nettype none directive to catch those bugs.
On the side note, you misuse blocking and non-blocking assignments. There should be none in the intial block of your test bench and you should have used them in the flop of your jk module. Q_ will not work correclty and will be late one cycle in this case. It should be combinational:
always #(negedge CK)
Q <= RESET_N & (J&~Q | ~K&Q);
always #*
Q_ = ~RESET_N | ~Q;
And you should always consider any initial block as a part of the testbench. So is your initial block in the jk module.

Using created ALU to make a bigger one

I have a 8-bit ALU unit in verilog that can do addition, invert, etc. This single unit is tested and performs correctly. When I combine 4 of these to make a bigger ALU every output is correct except when I choose the addition operation it comes out as
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx01010101, basically the first alu does the work right then the output from the second is xxxxxxxx as is the third and fourth. This is really frustrating!!
the 8 bit module( it would be nice to point if this model is behavioral or structural model i go for the former!)
module alu_8bit(
output reg [7:0] out,
output reg cout,g,e,
input [7:0] A,B,
input cin,
input [2:0] S
);
//used functions
parameter BUF_A = 3'b000;
parameter NOT_A = 3'b001;
parameter ADD = 3'b010;
parameter OR = 3'b011;
parameter AND = 3'b100;
parameter NOT_B = 3'b101;
parameter BUF_B = 3'b110;
parameter LOW = 3'b111;
always #(A or B or S) begin
//Comparator
g = A>B;
e = A==B;
//Other selective functions
case(S)
BUF_A: out = A;
NOT_A: out = ~A;
ADD: {cout,out} = A+B+cin;
OR: out = A | B;
AND: out = A & B;
NOT_B: out = ~B;
BUF_B: out = B;
LOW: out = {8{1'b0}};
endcase
end
endmodule
Here is the code of the bigger one:
module alu_32bit(
output [31:0] out,
output cout,g,e,
input [31:0] A,B,
input cin,
input [2:0] S
);
wire e1,e2,e3,e4;
wire g1,g2,g3,g4;
alu_8bit ALU1(out[7:0],cin2,g1,e1,A[7:0],B[7:0],cin,S);
alu_8bit ALU2(out[15:8],cin3,g2,e2,A[15:8],B[15:8],cin2,S);
alu_8bit ALU3(out[23:16],cin4,g3,e3,A[23:16],B[23:16],cin3,S);
alu_8bit ALU4(out[31:24],cout,g4,e4,A[31:24],B[31:24],cin4,S);
assign g = g4 | (e4 & g3) |(e4 & e3 & g2) | (e4& e3 & e2 & g1);
assign e = e4 & e3 & e2 & e1;
endmodule
Can any one give some help?! if you need more info just tell me.
Edited:
Waveform pic clearly input comes in correct but output not
The dataflow diagram shows that ALU1 output is just fine
Your sensitivity list for the main part of the ALU doesn't include cin.

Seven Segment Multiplexing on Basys2

this is my first post so I hope I'm doing this correctly. I'm trying to output a "4 3 2 1" on a four digit seven segment display on a BASYS2 board. I have checked to make sure that 0 enables the signal and that I have the ports mapped correctly. I believe the error is within my multiplexing logic since I am only able to display a single digit. I'm new to Verilog (am used to C) and would appreciate any suggestions. Thanks
`timescale 1ns / 1ps
module main (clock, AN0, AN1, AN2, AN3, CA, CB, CC, CD, CE, CF, CG, CDP);
//USED FOR SEVEN SEG
input clock;
output AN0, AN1, AN2, AN3, CA, CB, CC, CD, CE, CF, CG, CDP;
reg [7:0] cathodedata; //cathode data
reg [3:0] anodedata; //anode data
reg [2:0] digit = 1;
reg [6:0] data;
reg setdp;
reg [19:0] counter = 0;
assign CA = cathodedata [7];
assign CB = cathodedata [6];
assign CC = cathodedata [5];
assign CD = cathodedata [4];
assign CE = cathodedata [3];
assign CF = cathodedata [2];
assign CG = cathodedata [1];
assign CDP = cathodedata [0];
assign AN3 = anodedata [3];
assign AN2 = anodedata [2];
assign AN1 = anodedata [1];
assign AN0 = anodedata [0];
//USED FOR SEVEN SEG
//Multiplexing
//Board Clock: 50MHz
//p = t*f
//t = 16ms
//p = 16ms * 50*10^6 = 800,000 cycles
//200,000 cycles for each digit
//Refreshed every 16ms (~60Hz)
always#(negedge clock)
begin
if (digit == 1)
begin
if (counter == 200_000)
begin
digit = 2;
end
else
begin
counter = counter + 1;
data = 4;
end
end
else if (digit == 2)
begin
if (counter == 400_000)
begin
digit = 3;
end
else
begin
counter = counter + 1;
data = 3;
end
end
else if (digit == 3)
begin
if (counter == 600_000)
begin
digit = 4;
end
else
begin
counter = counter + 1;
data = 2;
end
end
else if (digit == 4)
begin
if (counter == 800_000)
begin
digit = 1;
counter = 0;
end
else
begin
counter = counter + 1;
data = 1;
end
end
end
always # (*)
begin
case (data)
6'd0: cathodedata = 8'b00000011; //0
6'd1: cathodedata = 8'b10011111; //1
6'd2: cathodedata = 8'b00100101; //2
6'd3: cathodedata = 8'b00001101; //3
6'd4: cathodedata = 8'b10011001; //4
6'd5: cathodedata = 8'b01001001; //5
6'd6: cathodedata = 8'b01000001; //6
6'd7: cathodedata = 8'b00011111; //7
6'd8: cathodedata = 8'b00000001; //8
6'd9: cathodedata = 8'b00001001; //9
6'd10: cathodedata = 8'b00010001; //A
6'd11: cathodedata = 8'b11000001; //B
6'd12: cathodedata = 8'b01100011; //C
6'd13: cathodedata = 8'b10000101; //D
6'd14: cathodedata = 8'b00100001; //E
6'd15: cathodedata = 8'b01110001; //F
default: cathodedata = 8'b11111111; //default all off
endcase
if (setdp == 1) //decimal point
cathodedata = cathodedata & 8'hFE;
case(digit)
0: anodedata = 4'b1111; //all OFF
4: anodedata = 4'b1110; //AN0
3: anodedata = 4'b1101; //AN1
2: anodedata = 4'b1011; //AN2
1: anodedata = 4'b0111; //AN3
default:
anodedata = 4'b1111; //all OFF
endcase
end
endmodule
Here's a modified version of one of my pet projects. It should do exactly as you wanted: display 4 3 2 1 on the 4dig7seg display. I tested it on an Amani GTX CPLD, and it should transfer cleanly to your board.
I like separating projects into separate modules to keep organized. The top level module takes the on board clock as an input and outputs 14 signals to a four-digit-seven-segment serial display. Make sure the pins are correctly assigned.
module SevenSeg(clk, odig, onum, col, ap);
input clk; // 50 MHz oscillator
output [3:0] odig; // selected digit output
output [7:0] onum; // selected display output
output col = 1; // turns the colon off
output ap = 1; // turns the apostrophe off
wire clock; // divided oscillator to slow the display output
parameter a = 8'b11111110; // low means on, high means off
parameter b = 8'b11111101; // these are just parameters
parameter c = 8'b11111011; // defining each of the
parameter d = 8'b11110111; // seven segments
parameter e = 8'b11101111; // making life easier
parameter f = 8'b11011111;
parameter g = 8'b10111111;
parameter dp = 8'b01111111;
parameter off = 8'b11111111;
parameter one = b & c; // parameters for outputs
parameter two = a & b & d & e & g;
parameter three = a & b & c & d & g;
parameter four = b & c & f & g;
wire [7:0] port1 = one; // This is set up so these can change dynamically...
wire [7:0] port2 = two; // ... if so desired.
wire [7:0] port3 = three;
wire [7:0] port4 = four;
slowclk m1(clk, clock); // divides clk by 500, for 50 MHz in, 100 kHz out
digitize m2(clock, port1, port2, port3, port4, odig, onum); // rotates the digit outputs
endmodule
Next I have a simple clock divider. The case count = 500 can be modified to divide your clock to whatever frequency you like. The output should look fine in the range of about 120 Hz to about 2 MHz.
module slowclk(clk, clock);
input clk;
output reg clock;
integer count;
always #(posedge clk)
case(count)
500: begin clock <= clock + 1; count <= 0; end // Change 500 to any divisor you like
default: count <= count + 1;
endcase
endmodule
Then we have to rotate the digits. Note if you change the anodes and cathodes at the "same" time, there will be a small leakage current into the neighboring segments causing a "ghost" effect.
module digitize(clock, num1, num2, num3, num4, odig, onum);
input wire clock;
input [7:0] num1; // rightmost digit
input [7:0] num2;
input [7:0] num3;
input [7:0] num4; // leftmost digit
output reg [3:0] odig;
output reg [7:0] onum;
parameter [7:0] off = 8'b11111111;
reg [3:0] dstate;
always #(posedge clock)
case(dstate)
0:begin odig <= 4'b0001; dstate <= 1; end
1:begin onum <= num1; dstate <= 2; end
2:begin onum <= off; dstate <= 3; end // off states prevent 'ghosting'
3:begin odig <= 4'b0010; dstate <= 4; end // when changing output digit
4:begin onum <= num2; dstate <= 5; end
5:begin onum <= off; dstate <= 6; end
6:begin odig <= 4'b0100; dstate <= 7; end
7:begin onum <= num3; dstate <= 8; end
8:begin onum <= off; dstate <= 9; end
9:begin odig <= 4'b1000; dstate <= 10; end
10:begin onum <= num4; dstate <= 11; end
11:begin onum <= off; dstate <= 0; end
default: dstate <= 0;
endcase
endmodule
I too am using a basys2 and looking for a 7-seg driver. Nathan G's code did not work for me (using system verilog perhaps?), but I found this article: http://simplefpga.blogspot.co.uk/2012/12/scrolling-or-moving-text-using-7.html?showComment=1362783256904#c5783969326158067433 and I cannibalized it to my own ends.The modified code is below. It should take (although I haven't checked the decoding fully yet) four hex values and display them on the 7-seg. In my example my board now says 'FAAF' (because getting this working was faf)
ucf file taken from digilent site:
# Pin assignment for DispCtl
# Connected to Basys2 onBoard 7seg display
NET "seg<0>" LOC = "L14"; # Bank = 1, Signal name = CA
NET "seg<1>" LOC = "H12"; # Bank = 1, Signal name = CB
NET "seg<2>" LOC = "N14"; # Bank = 1, Signal name = CC
NET "seg<3>" LOC = "N11"; # Bank = 2, Signal name = CD
NET "seg<4>" LOC = "P12"; # Bank = 2, Signal name = CE
NET "seg<5>" LOC = "L13"; # Bank = 1, Signal name = CF
NET "seg<6>" LOC = "M12"; # Bank = 1, Signal name = CG
NET "dp" LOC = "N13"; # Bank = 1, Signal name = DP
NET "an<3>" LOC = "K14"; # Bank = 1, Signal name = AN3
NET "an<2>" LOC = "M13"; # Bank = 1, Signal name = AN2
NET "an<1>" LOC = "J12"; # Bank = 1, Signal name = AN1
NET "an<0>" LOC = "F12"; # Bank = 1, Signal name = AN0
Top level module has this:
module top_level(
//clock input
input CLK,
output [7:0] seg,
output dp,
output [3:0] an
);
scrolling_name scrolling_name(
.clock(CLK),
.reset(RESET),
.a(seg[0]),
.b(seg[1]),
.c(seg[2]),
.d(seg[3]),
.e(seg[4]),
.f(seg[5]),
.g(seg[6]),
.dp(dp),
.an(an),
//.XPosition(XPosition),
//.YPosition(YPosition)
.XPosition(8'hFA),
.YPosition(8'hAF)
);
endmodule
and the file I took from the guy in the link and have edited is:
`timescale 1ns / 1ps
module scrolling_name(
input clock,
input reset,
output a,
output b,
output c,
output d,
output e,
output f,
output g,
output dp,
output [3:0] an,
input [7:0] XPosition,
input [7:0] YPosition
);
reg [28:0] ticker; //to hold a count of 50M
wire click;
reg [3:0] fourth, third, second, first; // registers to hold the LED values
always # (posedge clock or posedge reset) //always block for the ticker
begin
if(reset)
ticker <= 0;
else if(ticker == 50000000) //reset after 1 second
ticker <= 0;
else
ticker <= ticker + 1;
end
reg [3:0] clickcount; //register to hold the count upto 9. That is why a 4 bit register is used. 3 bit would not have been enough.
assign click = ((ticker == 50000000)?1'b1:1'b0); //click every second
always # (posedge click or posedge reset)
begin
if(reset)
clickcount <= 0;
else if(clickcount == 8)
clickcount <= 0;
else
clickcount <= clickcount + 1;
end
always#(posedge clock)
begin
fourth = XPosition[7:4];
third = XPosition[3:0];
second = YPosition[7:4];
first = YPosition[3:0];
end
//see my other post on explanation of LED multiplexing.
localparam N = 18;
reg [N-1:0]count;
always # (posedge clock or posedge reset)
begin
if (reset)
count <= 0;
else
count <= count + 1;
end
reg [6:0]sseg;
reg [3:0]an_temp;
always # (*)
begin
case(count[N-1:N-2])
2'b00 :
begin
sseg = first;
an_temp = 4'b1110;
end
2'b01:
begin
sseg = second;
an_temp = 4'b1101;
end
2'b10:
begin
sseg = third;
an_temp = 4'b1011;
end
2'b11:
begin
sseg = fourth;
an_temp = 4'b0111;
end
endcase
end
assign an = an_temp;
reg [6:0] sseg_temp;
always # (*)
begin
case(sseg)
0 : sseg_temp = 7'b1000000; //to display 0
1 : sseg_temp = 7'b1001111; //to display 1
2 : sseg_temp = 7'b0100100; //to display 2
3 : sseg_temp = 7'b0110000; //to display 3
4 : sseg_temp = 7'b0011001; //to display 4
5 : sseg_temp = 7'b0010010; //to display 5
6 : sseg_temp = 7'b0000011; //to display 6
7 : sseg_temp = 7'b1111000; //to display 7
8 : sseg_temp = 7'b0000000; //to display 8
9 : sseg_temp = 7'b0011000; //to display 9
10 : sseg_temp = 7'b0001000; //to display A
11 : sseg_temp = 7'b0000011; //to display B
12 : sseg_temp = 7'b1000110; //to display C
13 : sseg_temp = 7'b0100001; //to display D
14 : sseg_temp = 7'b0000110; //to display E
15 : sseg_temp = 7'b0001110; //to display F
default : sseg_temp = 7'b1111111; //blank
endcase
end
assign {g, f, e, d, c, b, a} = sseg_temp;
assign dp = 1'b1;
endmodule
Please excuse the horrible formatting/indenting - there is a combination of his, mine, and adding four spaces to get stack overflow to recognize it as code. I don't have time to make things pretty unfortunately. I can bundle all this together and put it on dropbox if you would like.
Nathan
Towards the end you have :
always #(*) begin
...
if (setdp == 1) //decimal point
cathodedata = cathodedata & 8'hFE;
always #* implies a combinatorial block, that is no flip-flop to break up loops etc. Your simulator may not have caught this but I would expect it to have real problems in synthesis.
Basically you have cathodedata driving itself.
I would replace this with something like:
always #(*) begin
...
if (setdp == 1) //decimal point
cathodedata_mask = cathodedata & 8'hFE;
else
cathodedata_mask = cathodedata;

Resources