Reputation: 55
I am new in Verilog and I still have some problems with basics. The following code is one of the modules and works the way I want, but I wonder if it can be written more efficient and shorter and how could it be done. Thank you for your help!
`timescale 1ns / 1ps
module COUNTER
(
input A_i,
input B_i,
input ENABLE_i,
input CLK,
input RESET,
input R_i,
input UP_DOWN_i, // za realno stanje se UP_DOWN_o prepisuje v UP_DOWN_i
output reg signed [7:0] VALUE_o,
output reg UP_DOWN_o
);
reg A;
reg B;
reg signed [7:0] VALUE_cmp;
wire [1:0] A_B={A,B};
initial VALUE_o = 8'b00000000;
initial VALUE_cmp = 8'b00000000;
initial A = 1'b0;
initial B = 1'b0;
initial UP_DOWN_o = 1'b1;
always@ (posedge CLK or posedge RESET)
begin
A <= A_i;
B <= B_i;
VALUE_cmp <= VALUE_o;
if (RESET || R_i)
begin
VALUE_o<= 8'b0;
VALUE_cmp <=8'b0;
end
else if (ENABLE_i)
begin
//up or down
if (UP_DOWN_i)
begin
//up
if ((A == 1'b0) && (A_i == 1'b0) && (B == 1'b0) && (B_i == 1'b1))
VALUE_o <= VALUE_o+1;
else if ((A == 1'b0) && (A_i == 1'b1) && (B == 1'b1) && (B_i == 1'b1))
VALUE_o <= VALUE_o+1;
else if ((A == 1'b1) && (A_i == 1'b1) && (B == 1'b1) && (B_i == 1'b0))
VALUE_o <= VALUE_o+1;
else if ((A == 1'b1) && (A_i == 1'b0) && (B == 1'b0) && (B_i == 1'b0))
VALUE_o <= VALUE_o+1;
// change
if ((A == 1'b0) && (A_i == 1'b1) && (B == 1'b0) && (B_i == 1'b0))
VALUE_o <= VALUE_o+1;
else if ((A == 1'b1) && (A_i == 1'b1) && (B == 1'b0) && (B_i == 1'b1))
VALUE_o <= VALUE_o+1;
else if ((A == 1'b1) && (A_i == 1'b0) && (B == 1'b1) && (B_i == 1'b1))
VALUE_o <= VALUE_o+1;
else if ((A == 1'b0) && (A_i == 1'b0) && (B == 1'b1) && (B_i == 1'b0))
VALUE_o <= VALUE_o+1;
// after
else if (A == A_i ==B == B_i )
VALUE_o <= VALUE_o+1;
end
else
begin
//down
if ((A == 1'b0) && (A_i == 1'b1) && (B == 1'b0) && (B_i == 1'b0))
VALUE_o <= VALUE_o-1;
else if ((A == 1'b1) && (A_i == 1'b1) && (B == 1'b0) && (B_i == 1'b1))
VALUE_o <= VALUE_o-1;
else if ((A == 1'b1) && (A_i == 1'b0) && (B == 1'b1) && (B_i == 1'b1))
VALUE_o <= VALUE_o-1;
else if ((A == 1'b0) && (A_i == 1'b0) && (B == 1'b1) && (B_i == 1'b0))
VALUE_o <= VALUE_o-1;
//change
else if ((A == 1'b1) && (A_i == 1'b1) && (B == 1'b1) && (B_i == 1'b0))
VALUE_o <= VALUE_o-1;
else if ((A == 1'b0) && (A_i == 1'b1) && (B == 1'b1) && (B_i == 1'b1))
VALUE_o <= VALUE_o-1;
else if ((A == 1'b0) && (A_i == 1'b0) && (B == 1'b0) && (B_i == 1'b1))
VALUE_o <= VALUE_o-1;
else if ((A == 1'b1) && (A_i == 1'b0) && (B == 1'b0) && (B_i == 1'b0))
VALUE_o <= VALUE_o-1;
// after
else if (A == A_i ==B == B_i )
VALUE_o <= VALUE_o-1;
end
end
end
always@ (posedge CLK) // kasneje potrebo vezat za UP_DOWN_o
begin
//steje dol
if (VALUE_cmp > VALUE_o)
UP_DOWN_o <= 0;
//steje gor
else if (VALUE_cmp < VALUE_o)
UP_DOWN_o <= 1;
end
endmodule
Upvotes: 1
Views: 397
Reputation: 334
It can be shortened by replacing the if-else
chains with the a case
as you suggest. Here is the dense implementation. Also in this kind of problems you can use Look up tables (LUT).
always@ (posedge CLK or posedge RESET)
begin
A <= A_i;
B <= B_i;
VALUE_cmp <= VALUE_o;
if (RESET || R_i)
begin
VALUE_o<= 8'b0;
VALUE_cmp <=8'b0;
end
else if (ENABLE_i)
begin
//up or down
if (UP_DOWN_i)
begin
case({A,A_i,B,B_i})
//up
4'b0001, 4'b0111,
4'b1110, 4'b1000,
// change
4'b0100, 4'b1101,
4'b1011, 4'b0010:
VALUE_o <= VALUE_o+1;
endcase
if (A == A_i ==B == B_i )
VALUE_o <= VALUE_o+1;
end
else
begin
case({A,A_i,B,B_i})
//down
4'b0100, 4'b1101,
4'b1011, 4'b0010,
//change
4'b1110, 4'b0111,
4'b0001, 4'b1000:
VALUE_o <= VALUE_o-1;
endcase
// after
else if (A == A_i ==B == B_i )
VALUE_o <= VALUE_o-1;
end
end
end
Here is a reference for LUT implementations: https://www.csee.umbc.edu/~tinoosh/cmpe415/slides/Rom-LUT-verilog.pdf
Upvotes: 1