In verilog I have an array of binary values. How do I take the absolute value of the subtracted values ?
Verilog code:
module aaa(clk);
input clk;
reg [7:0] a [1:9];
reg [7:0] s [1:9];
always#(posedge clk)
begin
s[1] = a[1] - a[2];
s[2] = a[2] - a[3];
s[3] = a[1] + a[3];
end
endmodule
I want my s[1] and s[2] values to be always positive. How can I do it in synthesisable verilog?
I have tried using signed reg, but it shows an error.
Regardless of whether the number is signed or not twos complement is still used which correctly performs addition and subtraction at the bit level.
If a number is to be interpreted as signed the MSB can be used to tell if it is positive (0) or negative (1)
To absolute the number just invert based on the MSB:
reg [31:0] ans ; // Something else drives this value
reg [31:0] abs_ans; // Absolute version of ans
// invert (absolute value)
always #* begin
if (ans[31] == 1'b1) begin
abs_ans = -ans;
end
else begin
abs_ans = ans;
end
end
NB: using = because it is a combinatorial block, if using a flip-flop (edge trigger) use <= as #TzachiNoy has mentioned.
This should do the work:
s[1] <= (a[1]>a[2])?(a[1]-a[2]):(a[2]-a[1]);
Note: you should always use '<=' in clocked always blocks.
Just following the answer from #Morgan, and because I already had a module in my system that performed this operation, here is my contribution:
module Mod(
input signed [11:0] i,
output signed [11:0] o
);
assign o = i[11] ? -i : i; // This does all the magic
endmodule
And here is a testbench:
module tb;
reg signed [11:0] i;
wire signed [11:0] o;
Mod M(i,o);
integer t;
initial begin
for (t = -10; t < 10; t = t + 1) begin
#1
i <= t;
$display("i = %d, o = %d", i, o);
end
end
endmodule
The output is:
i = x, o = x
i = -10, o = 10
i = -9, o = 9
i = -8, o = 8
i = -7, o = 7
i = -6, o = 6
i = -5, o = 5
i = -4, o = 4
i = -3, o = 3
i = -2, o = 2
i = -1, o = 1
i = 0, o = 0
i = 1, o = 1
i = 2, o = 2
i = 3, o = 3
i = 4, o = 4
i = 5, o = 5
i = 6, o = 6
i = 7, o = 7
i = 8, o = 8
Related
I have a big issue with an 8-bit ALU. To begin with, the code won't stop running. Second, a chart of specifications was given, and I believe I'm missing some of them
Here are the specifications:
Specification
Data Inputs: A (8-bit), B (8-bit)
Control Inputs: S (1-bit), E (1-bit)
Output: W (8-bit)
The output W should be 0 if E = 0. If E = 1, then W = A + B for S = 0, and W = A - B for S = 1.
Here is the code:
`timescale 1ns / 1ps
module ALU8bit( Opcode,
Operand1,
Operand2,
Result,
flagC,
flagZ
);
input [2:0] Opcode;
input [7:0] Operand1,
Operand2;
output reg [15:0] Result = 16'b0;
output reg flagC = 1'b0,
flagZ = 1'b0;
parameter [2:0] ADD = 3'b000,
SUB = 3'b001,
MUL = 3'b010,
AND = 3'b011,
OR = 3'b100,
NAND = 3'b101,
NOR = 3'b110,
XOR = 3'b111;
always # (Opcode or Operand1 or Operand2)
begin
case (Opcode)
ADD: begin
Result = Operand1 + Operand2;
flagC = Result[8];
flagZ = (Result == 16'b0);
end
SUB: begin
Result = Operand1 - Operand2;
flagC = Result[8];
flagZ = (Result == 16'b0);
end
MUL: begin
Result = Operand1 * Operand2;
flagZ = (Result == 16'b0);
end
AND: begin
Result = Operand1 & Operand2;
flagZ = (Result == 16'b0);
end
OR: begin
Result = Operand1 | Operand2;
flagZ = (Result == 16'b0);
end
NAND: begin
Result = ~(Operand1 & Operand2);
flagZ = (Result == 16'b0);
end
NOR: begin
Result = ~(Operand1 | Operand2);
flagZ = (Result == 16'b0);
end
XOR: begin
Result = Operand1 ^ Operand2;
flagZ = (Result == 16'b0);
end
default: begin
Result = 16'b0;
flagC = 1'b0;
flagZ = 1'b0;
end
endcase
end
endmodule
and here is the testbench:
`timescale 1ns / 1ps
`include "alu_8bit.v"
module alu_8bit_test;
// Inputs
reg [2:0] Opcode;
reg [7:0] Operand1;
reg [7:0] Operand2;
// Outputs
wire [15:0] Result;
wire flagC;
wire flagZ;
//Temporary variable
reg [2:0] count = 3'd0;
// Instantiate the Unit Under Test (UUT)
ALU8bit uut (
.Opcode(Opcode),
.Operand1(Operand1),
.Operand2(Operand2),
.Result(Result),
.flagC(flagC),
.flagZ(flagZ)
);
initial begin
$display("Start of Test.");
$dumpfile("alu_8bit.vcd");
$dumpvars(0, alu_8bit_test);
// Initialize Inputs
Opcode = 3'b0;
Operand1 = 8'd0;
Operand2 = 8'd0;
// Wait 100 ns for global reset to finish
#100;
$display("End of Test.");
// Add stimulus here
Operand1 = 8'hAA;
Operand2 = 8'h55;
for (count = 0; count < 8; count = count + 1'b1)
begin
Opcode = count;
#20;
end
end
endmodule
I really appreciate any help you guys can provide me with.
The range of your count variable is 0 to 7. This means count will always be less than 8, and your count < 8 expression will always be true. This causes the for loop to be an infinite loop, which is why the simulation never stops.
Change:
reg [2:0] count = 3'd0;
to:
integer count = 0;
This program needs to be able to output a sinewave to the testbench, where the frequency of the output signal should be specified by an eight bit
input. My understnading is that I need to change the clock period which will alter the frequency of the waveform accordingly.The code is provided below:
module functionGenerator(Clk,data_out, freq);
//declare input and output
input [7:0] freq;
input Clk;
output [9:0] data_out;
//declare the sine ROM - 30 registers each 8 bit wide.
reg [9:0] sine [0:99];
//Internal signals
integer i;
reg [9:0] data_out;
//Initialize the sine rom with samples.
initial begin
i = 0;
sine[0] = 0; sine[1] = 10; sine[2] = 20; sine[3] = 29; sine[4] = 39;
sine[5] = 48; sine[6] = 58; sine[7] = 67; sine[8] = 75; sine[9] = 84;
sine[10] = 92; sine[11] = 100; sine[12] = 107; sine[13] = 114; sine[14] = 120;
sine[15] = 126; sine[16] = 132; sine[17] = 137; sine[18] = 141; sine[19] = 145;
sine[20] = 149; sine[21] = 151; sine[22] = 153; sine[23] = 155; sine[24] = 156;
sine[25] = 156; sine[26] = 156; sine[27] = 155; sine[28] = 153; sine[29] = 151;
sine[30] = 149; sine[31] = 145; sine[32] = 141; sine[33] = 137; sine[34] = 132;
sine[35] = 126; sine[36] = 120; sine[37] = 114; sine[38] = 107; sine[39] = 100;
sine[40] = 92; sine[41] = 84; sine[42] = 75; sine[43] = 67; sine[44] = 58;
sine[45] = 48; sine[46] = 39; sine[47] = 29; sine[48] = 20; sine[49] = 10;
sine[50] = 0; sine[51] = -10; sine[52] = -20; sine[53] = -29; sine[54] = -39;
sine[55] = -48; sine[56] = -58; sine[57] = -67; sine[58] = -75; sine[59] = -84;
sine[60] = -92; sine[61] = -100; sine[62] = -107; sine[63] = -114; sine[64] = -120;
sine[65] = -126; sine[66] = -132; sine[67] = -137; sine[68] = -141; sine[69] = -145;
sine[70] = -149; sine[71] = -151; sine[72] = -153; sine[73] = -155; sine[74] = -156;
sine[75] = -156; sine[76] = -156; sine[77] = -155; sine[78] = -153; sine[79] = -151;
sine[80] = -149; sine[81] = -145; sine[82] = -141; sine[83] = -137; sine[84] = -132;
sine[85] = -126; sine[86] = -120; sine[87] = -114; sine[88] = -107; sine[89] = -100;
sine[90] = -92; sine[91] = -84; sine[92] = -75; sine[93] = -67; sine[94] = -58;
sine[95] = -48; sine[96] = -39; sine[97] = -29; sine[98] = -20; sine[99] = -10;
end
//At every positive edge of the clock, output a sine wave sample.
always# (posedge(Clk))
begin
data_out = sine[i];
i = i+ 1;
if(i == 99)
i = 0;
end
endmodule
Testbench
module functionGeneratror_tb();
// Inputs
reg Clk;
reg freq;
// Outputs
wire [9:0] data_out;
// Instantiate the Unit Under Test (UUT)
functionGenerator uut (
.Clk(Clk),
.data_out(data_out),
.freq(freq)
);
//Generate a clock with 10 ns clock period.
initial Clk = 0;
always #5 Clk = ~Clk; // CAN I PASS IN AN INPUT HERE INSTEAD OF 5?
initial
#10000 $finish;
endmodule
always #5 Clk = ~Clk;
This statement is part of your testbench, not part of the UUT. You aren't supposed to change it; the expectation is that the clock frequency remains constant.
Your functionGenerator module currently doesn't make any use of the freq input. You will need to come up with some way to control how quickly the synthesizer steps through the sine array based on the value of freq. This may involve either making less than one step per clk period, or making multiple steps per period, depending on your requirements.
This is a typical case in which a phase-acummulator oscillator is used to generate the ROM address for the new sample to output.
Something like this: the phase accumulator here is 14 bits wide, and we are using the 6 most significant bits to have a sine wave of 64 samples. The output frequency of such sine wave is CLK * freq / 16384
Actually, the ROM has only 16 cells, as it needs only to store one quarter of a sine wave. Bits 3 to 0 from the calculated address from the phase accumulator are used to address the ROM, and bits 5 to 4 are used to find out which quadrant we are in, so the actual address may need to be inverted and/or the actual output may need to be negated.
module FunctionGenerator (
input wire clk,
input wire [7:0] freq, // frequency of output signal is: clk * freq / 16384
output reg signed [9:0] out
);
reg signed [9:0] quartersin[0:15];
// Generate initial values with this little C program:
// #include <stdio.h>
// #include <math.h>
//
// #define PI 3.141592654
//
// int main()
// {
// int i;
//
// for (i=0;i<16;i++)
// {
// printf (" quartersin[%2d] = %d;\n", i, (int)(511*sin(i*2*PI/64.0)));
// }
//
// return 0;
// }
initial begin
quartersin[ 0] = 0;
quartersin[ 1] = 50;
quartersin[ 2] = 99;
quartersin[ 3] = 148;
quartersin[ 4] = 195;
quartersin[ 5] = 240;
quartersin[ 6] = 283;
quartersin[ 7] = 324;
quartersin[ 8] = 361;
quartersin[ 9] = 395;
quartersin[10] = 424;
quartersin[11] = 450;
quartersin[12] = 472;
quartersin[13] = 488;
quartersin[14] = 501;
quartersin[15] = 508;
end
reg [13:0] phaseacum = 14'h0000;
reg [3:0] indx;
always #(posedge clk) begin
phaseacum <= phaseacum + {6'b000000, freq};
if (phaseacum[13] == 1'b0) // if in quadrants 0 or 1, out as is
out <= quartersin[indx];
else
out <= -quartersin[indx]; // if in quadrants 2 or 3, negate out
end
always #* begin
if (phaseacum[12] == 1'b0) // which quadrant am I ?
indx = phaseacum[11:8]; // if in quadrant 0 or 2
else
indx = ~phaseacum[11:8]; // else, in quadrant 1 or 3
endcase
end
endmodule
A minimal testbench can be used to let this function generator to run for a thousand or so clock cycles, and then take the output to GTKWave and display it as an analog output:
`timescale 1ns / 1ns
module tb;
reg clk;
reg [7:0] freq;
wire [9:0] out;
FunctionGenerator uut (
.clk(clk),
.freq(freq),
.out(out)
);
initial begin
$dumpfile("dump.vcd");
$dumpvars(1,uut);
clk = 1'b0;
freq = 8'd16; // aprox. 1 kHz sine wave for a 1 MHz clk
repeat (2000) begin
#(posedge clk);
end
$finish;
end
always begin
clk = #500 ~clk; // a 1 MHz clock
end
endmodule
This is the result, simulated with iverilog / GTKWave:
I am working on a Verilog fixed point adder, using which I will also do the subtraction. When I do the subtraction not always I get the correct result.
For example, 1-1=0, but I get -0.
Kindly have a look on the below mentioned code:
`timescale 1ns/1ps
module adder #(
//Parameterized values
parameter Q = 27,
parameter N = 32
)
(
input [N-1:0] a,
input [N-1:0] b,
output [N-1:0] c
);
reg [N-1:0] res;
assign c = res;
always #(a,b) begin
// both negative or both positive
if(a[N-1] == b[N-1]) begin //Since they have the same sign, absolute magnitude increases
res[N-2:0] = a[N-2:0] + b[N-2:0]; //So just the two numbers are added
res[N-1] = a[N-1]; //and the sign is set appropriately...
end
// one of them is negative...
else if(a[N-1] == 0 && b[N-1] == 1) begin // subtracts a-b
if( a[N-2:0] > b[N-2:0] ) begin // if a is greater than b,
res[N-2:0] = a[N-2:0] - b[N-2:0];
res[N-1] = 0; // manually the sign is set to positive
end
else begin // if a is less than b,
res[N-2:0] = b[N-2:0] - a[N-2:0]; // subtracting a from b to avoid a 2's complement answer
if (res[N-2:0] == 0)
res[N-1] = 0; // To remove negative zero....
else
res[N-1] = 1; // and manually the sign is set to negative
end
end
else begin // subtract b-a (a negative, b positive)
if( a[N-2:0] > b[N-2:0] ) begin // if a is greater than b,
res[N-2:0] = a[N-2:0] - b[N-2:0]; // subtracting b from a to avoid a 2's complement answer
if (res[N-2:0] == 0)
res[N-1] = 0;
else
res[N-1] = 1; // and manually the sign is set to negative
end
else begin // if a is less than b,
res[N-2:0] = b[N-2:0] - a[N-2:0];
res[N-1] = 0;
end
end
end
endmodule
Testbench for the adder is below:
`timescale 1ns/1ps
module tb_adder (
);
reg clk;
reg [ 31 : 0 ] a;
reg [ 31 : 0 ] b;
wire [ 31: 0 ] c;
adder adder_i (
.a(a),
.b(b),
.c(c)
);
parameter CLKPERIODE = 100;
initial clk = 1'b1;
always #(CLKPERIODE/2) clk = !clk;
initial begin
$monitor ("adder=%h", c);
#1
a = 32'h08000000;
b = 32'hF8000000;
#(CLKPERIODE)
$finish();
end
endmodule
I am having a hard time to find where did I go wrong as I am a newbie in Verilog. I am using this module to calculate Taylor Series in Fixed Point arithmetic. Any suggestions?
The only case I could find where your code produces the dirty zero is when both inputs are the dirty zero themselves. i.e.
a = b = 32'h80000000 = "-0"
It looks like this happens because in this case your code takes the branch at
if(a[N-1] == b[N-1]) begin //Since they have the same sign, absolute magnitude increases
and this branch doesn't have the same check as the others that specifically avoids it. You could fix this by moving that code to the end of the always block so it runs no matter what branch is taken earlier.
I know how to design a 4x4 array multiplier , but if I follow the same logic , the coding becomes tedious.
4 x 4 - 16 partial products
64 x 64 - 4096 partial products.
Along with 8 full adders and 4 half adders, How many full adders and half adders do I need for 64 x 64 bit. How do I reduce the number of Partial products? Is there any simple way to solve this ?
Whenever tediously coding a repetitive pattern you should use a generate statement instead:
module array_multiplier(a, b, y);
parameter width = 8;
input [width-1:0] a, b;
output [width-1:0] y;
wire [width*width-1:0] partials;
genvar i;
assign partials[width-1 : 0] = a[0] ? b : 0;
generate for (i = 1; i < width; i = i+1) begin:gen
assign partials[width*(i+1)-1 : width*i] = (a[i] ? b << i : 0) +
partials[width*i-1 : width*(i-1)];
end endgenerate
assign y = partials[width*width-1 : width*(width-1)];
endmodule
I've verified this module using the following test-bench:
http://svn.clifford.at/handicraft/2013/array_multiplier/array_multiplier_tb.v
EDIT:
As #Debian has asked for a pipelined version - here it is. This time using a for loop in an always-region for the array part.
module array_multiplier_pipeline(clk, a, b, y);
parameter width = 8;
input clk;
input [width-1:0] a, b;
output [width-1:0] y;
reg [width-1:0] a_pipeline [0:width-2];
reg [width-1:0] b_pipeline [0:width-2];
reg [width-1:0] partials [0:width-1];
integer i;
always #(posedge clk) begin
a_pipeline[0] <= a;
b_pipeline[0] <= b;
for (i = 1; i < width-1; i = i+1) begin
a_pipeline[i] <= a_pipeline[i-1];
b_pipeline[i] <= b_pipeline[i-1];
end
partials[0] <= a[0] ? b : 0;
for (i = 1; i < width; i = i+1)
partials[i] <= (a_pipeline[i-1][i] ? b_pipeline[i-1] << i : 0) +
partials[i-1];
end
assign y = partials[width-1];
endmodule
Note that with many synthesis tools it's also possible to just add (width) register stages after the non-pipelined adder and let the tools register balancing pass do the pipelining.
[how to] reduce the number of partial products?
A method somewhat common used to be modified Booth encoding:
At the cost of more complicated addend selection, it at least almost halves their number.
In its simplest form, considering groups of three adjacent bits (overlapping by one) from one of the operands, say, b, and selecting 0, a, 2a, -2a or -a as an addend.
The code below generates only half of expected the output.
module arr_multi(a, b, y);
parameter w = 8;
input [w-1:0] a, b; // w-width
output [(2*w)-1:0] y; // p-partials
wire [(2*w*w)-1:0] p; //assign width as input bits multiplied by
output bits
genvar i;
assign p[(2*w)-1 : 0] = a[0] ? b : 0; //first output size bits
generate
for (i = 1; i < w; i = i+1)
begin
assign p[(w*(4+(2*(i-1))))-1 : (w*2)*i] = (a[i]?b<<i :0) + p[(w*(4+(2*
(i-2))))-1 :(w*2)*(i-1)];
end
endgenerate
assign y=p[(2*w*w)-1:(2*w)*(w-1)]; //taking last output size bits
endmodule
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;