How to create balanced logic (case) instead of priority (if .. else) for the following case?
I know I could get balanced logic when I change following priority logic
if(a == 2'b00) out = 1;
else if(a == 2'b01) out = 4'b0010;
else if(a == 2'b10) out = 4'b0100;
else if(a == 2'b11) out = 4'b1000;
To
case(a)
2'b00: out = 1;
2'b01: out = 2;
2'b10: out = 4;
2'b11: out = 8;
endcase
But how can I get balanced logic if the priority logic is this?
if(a) out = 1;
else if(b) out = 4'b0010;
else if(c) out = 4'b0100;
else if(d) out = 4'b1000;
How about:
case (1'b1)
a:out = 1;
b:out = 4'b0010;
c:out = 4'b0100;
d:out = 4'b1000;
endcase
See here for concerns about priority.
Related
I don't know what is wrong in my code. Refer to the /* status */ comment near the full and empty logic.
I have write pointer wrapping around catching up with read pointer, then wr_addr[3] == ~rd_addr[3] and wr_addr[2:0] == rd_addr[2:0], I have a full condition.
I have read pointer catching up with write pointer, then wr_addr[3:0] == rd_addr[3:0], I have empty.
Please check my code and give me some advice.
I also provide the code on edaplayground (for those of you who have an account there).
module fifo(input clk, rst,
input wr, rd,
input [3:0] din,
output logic [3:0] dout,
output fifo_full, fifo_empty
);
logic [3:0] w_ptr, r_ptr;
logic w_en, r_en;
status_pointer ptr(clk, rst, wr, rd, w_en, r_en, w_ptr, r_ptr, fifo_full, fifo_empty);
memory mem(clk, w_en, r_en, w_ptr, r_ptr, din, dout);
endmodule
module memory(input clk, we, oe,
input [3:0] w_ptr, r_ptr,
input [3:0] din,
output logic [3:0] dout
);
logic [3:0] mem [7:0];
always_ff #(posedge clk) begin
if(we & (~ oe)) begin
mem[w_ptr[2:0]] <= din;
end
else if((~ we) & oe) begin
dout <= mem[r_ptr[2:0]];
end
else if(we & oe) begin
mem[w_ptr[3:0]] <= din;
dout <= mem[r_ptr[2:0]];
end
end
endmodule
module status_pointer(input clk, rst,
input wr, rd,
output w_en, r_en,
output logic [3:0] w_ptr, r_ptr,
output logic fifo_full, fifo_empty
);
/* status */
always #(posedge clk) begin
if(rst) begin
fifo_full <= 0;
fifo_empty <= 0;
end
else begin
if(w_ptr[2:0] == r_ptr[2:0]) begin
if(w_ptr[3] == r_ptr[3])
fifo_empty <= 1;
else
fifo_full <= 1;
end
else begin
fifo_full <= fifo_full;
fifo_empty <= 0;
end
end
end
/* pointer */
assign w_en = (fifo_full == 0) & wr;
assign r_en = (fifo_empty == 0) & rd;
always_ff #(posedge clk, posedge rst) begin
if(rst) begin
w_ptr <= 4'b0;
r_ptr <= 4'b0;
end
else if(w_en & (!r_en)) begin
w_ptr <= w_ptr + 4'b001;
end
else if(r_en & (!w_en)) begin
r_ptr <= r_ptr + 4'b001;
end
else if(w_en & r_en) begin
w_ptr <= w_ptr + 4'b001;
r_ptr <= r_ptr + 4'b001;
end
else begin
w_ptr <= w_ptr;
r_ptr <= r_ptr;
end
end
endmodule
//// test bench ////
module tb_fifo();
logic clk, rst, wr, rd;
logic [3:0] din, dout;
logic fifo_full, fifo_empty;
logic [4:0] counter;
fifo dut_fifo(clk, rst, wr, rd, din, dout, fifo_full, fifo_empty);
always begin
clk = 1; #4;
clk = 0; #4;
end
initial begin
counter = 5'b00000;
rst = 0; #240; rst = 1;
end
always #(posedge clk) begin
if(~ rst) begin
counter <= counter + 5'b00001;
if(counter == 5'b00000) begin
wr = 1; rd = 0; din = counter[3:0];
end
else if(counter == 5'b00001) begin
wr = 1; rd = 1; din = counter[3:0];
end
else if(counter == 5'b00010) begin
wr = 0; rd = 1; din = counter[3:0];
end
else if(counter == 5'b00011) begin
wr = 1; rd = 1; din = counter[3:0];
end
else if(counter == 5'b00100) begin // [3]
wr = 1; rd = 0; din = counter[3:0];
end
else if(counter == 5'b00101) begin // [3]
wr = 1; rd = 0; din = counter[3:0];
end
else if(counter == 5'b00110) begin // [3]
wr = 1; rd = 1; din = counter[3:0];
end
else if(counter == 5'b00111) begin // [3]
wr = 1; rd = 1; din = counter[3:0];
end
else if(counter == 5'b01000) begin // [3]
wr = 1; rd = 1; din = counter[3:0];
end
else if(counter == 5'b01001) begin // [3]
wr = 0; rd = 1; din = counter[3:0];
end
else if(counter == 5'b01010) begin // [3]
wr = 0; rd = 1; din = counter[4:1];
end
else if(counter == 5'b01011) begin // [3]
wr = 1; rd = 1; din = counter[3:0];
end
else if(counter == 5'b01100) begin // [3]
wr = 1; rd = 1; din = counter[4:1];
end
else if(counter == 5'b01101) begin // [3]
wr = 0; rd = 1; din = counter[3:0];
end
else if(counter == 5'b01110) begin // [3]
wr = 0; rd = 1; din = counter[3:0];
end
else if(counter == 5'b01111) begin // [3]
wr = 1; rd = 0; din = counter[3:0];
end
else if(counter == 5'b11111) begin
$stop;
end
else begin
wr = 0; rd = 0;
end
end
else begin
counter <= 5'b00000;
wr = 0; rd = 0;
end
end
endmodule
There is a problem in your testbench. Your design expects an active-high reset. You need to drive rst high starting at time 0 to reset the design, then drop it low after a delay. Just invert how you drive rst. Change:
rst = 0; #240; rst = 1;
to:
rst = 1; #240; rst = 0;
How can I check for a parameter based value in an if statement?
I have a parametrized counter and I cannot find answers to how to check the max size i.e. e.g.
if(count_val == WIDTH'b1) count_pulse = 1'b1;
Any chance i could get some help :) ?
module counter #(
parameter WIDTH=3,
parameter DIR = 0
)(CLK, EN, RST, COUNT_VAL, COUNT_PULSE);
input CLK, EN, RST;
output [WIDTH:0] COUNT_VAL;
output COUNT_PULSE;
reg[WIDTH:0] count_val=0;
reg count_pulse;
always #(posedge CLK)
begin
if(RST == 1'b1) count_val <= 0;
else if(EN == 1'b1) begin
if(DIR == 1'b0) count_val <= count_val + 1;
else if(DIR == 1'b1) count_val <= count_val - 1;
if(count_val == WIDTH'b1) count_pulse = 1'b1;
else count_pulse = 1'b0;
end
end
assign COUNT_VAL = count_val;
endmodule
You can use a replication.
if(count_val == {WIDTH{1'b1}}) count_pulse = 1'b1;
or a shift
if(count_val == ((32'b1<<WIDTH)-1) count_pulse = 1'b1;
or in SystemVerilog, a bit fill
if(count_val == '1) count_pulse = 1'b1;
The syntax you have been trying to use WIDTH'b1 should be translated to 3'b1 which is 001. If this is the case, you do not really need the width specifier. The following will do:
if (counter_val == 1)
or to use precise widths:
if (counter_val == { {WIDTH-1{0}}, 1'b1} )
If you meant, 111, the see dave_59's answer.
I'm new to fpgas in general. I want to make counter that iterates each time SCK sees a rising edge. The issue i'm having with my code is that it seems to count twice. Two leds are lit each time there is a rising edge transition - as opposed to just one led. Any idea where this may be coming from?
module spi_slave(pcEn, LED, clk, SCK);
input clk, SCK;
output reg pcEn;
output reg [7:0] LED = 8'h00;
reg r1 = 0;
reg r2 = 0;
reg r3 = 0;
reg [3:0] cnt = 4'b0000;
always #(posedge clk)
begin
r1 <= SCK;
r2 <= r1;
pcEn <= r1 && !r3;
if (pcEn == 1) begin
cnt = cnt + 4'b0001;
if (cnt == 4'b0001) begin
LED[0] = 1'b1;
end
else if (cnt == 4'b0010) begin
LED[1] = 1'b1;
end
else if (cnt == 4'b0011) begin
LED[2] = 1'b1;
end
else if (cnt == 4'b0100) begin
LED[3] = 1'b1;
end
else if (cnt == 4'b0101) begin
LED[4] = 1'b1;
end
else if (cnt == 4'b0110) begin
LED[5] = 1'b1;
end
else if (cnt == 4'b0111) begin
LED[6] = 1'b1;
end
else if (cnt == 4'b1000) begin
LED[7] = 1'b1;
end
else
LED = 8'h00;
end
else
#100;
r3 <= r2;
end
endmodule
The counter is counting twice because you are comparing r1 & !r3.
r1->r2->r3 .it takes 2 clocks for r3 to be set after r1 equal 1. This implies that r1&!r3 condition will remain valid for 2 clocks. The pcEn will be generated for 2 clocks , Hence the counter will count twice.
r1 && !r2 or if you want a delay r2 && !r3 should work fine.
you should be able to see this behavior in a waveform to debug.Use $dumpvars; in your simulation to view the waveform.
Also there are couple of change to improve the code.
use of reset.
consistently use non-blocking assignment .
there is no need for #100 delay.
module spi_slave(pcEn, LED, clk, SCK,rst_n);
input clk, SCK,rst_n;
output reg pcEn;
output reg [7:0] LED ;
reg r1 ;
reg r2 ;
reg r3 ;
reg [3:0] cnt ;
always #(posedge clk or negedge rst_n)
begin
if ( rst_n == 0 )
begin
r1 <=0 ;
r2 <= 0 ;
r3 <= 0 ;
cnt <= 0 ;
LED <=0 ;
pcEn <=0 ;
end
else
begin
r1 <= SCK;
r2 <= r1;
r3 <= r2;
pcEn <= r2 && !r3;
if (pcEn == 1) begin
cnt <= cnt + 4'b0001;
if (cnt == 4'b0001) begin
LED[0] <= 1'b1;
end
else if (cnt == 4'b0010) begin
LED[1] <= 1'b1;
end
else if (cnt == 4'b0011) begin
LED[2] <= 1'b1;
end
else if (cnt == 4'b0100) begin
LED[3] <= 1'b1;
end
else if (cnt == 4'b0101) begin
LED[4] <= 1'b1;
end
else if (cnt == 4'b0110) begin
LED[5] <= 1'b1;
end
else if (cnt == 4'b0111) begin
LED[6] <= 1'b1;
end
else if (cnt == 4'b1000) begin
LED[7] <= 1'b1;
end
else
LED <= 8'h00;
end
end
end
endmodule
First of # delays are not synthesizable, they are delays for simulation only.
Generally is considered best practice to separate block and non-blocking logic into different always blocks. always #* for combinational (blocking assignments), and always #(posedge clk) for sequential (non-blocking assignments). FYI : Verilog supports case-statements which make coding value compare easier then nesting else-if.
I thing you may want to use r2 && !r3 instead of r1 && !r3 as Rahul also pointed out
always #* begin
if (pcEn == 1'b0) begin
next_cnt = cnt;
next_LED = LED;
else begin
next_cnt = cnt + 4'b0001;
next_LED = 8'h00; // Rest all to 0s
if(cnt >= 8'h8) next_cnt = 4'b0000; // optional : assuming you want to roll back before waiting another 8 SCK toggles
case(cnt)
4'b0000 : next_LED[0] = 1'b1;
4'b0001 : next_LED[1] = 1'b1;
// ...
4'b0111 : next_LED[7] = 1'b1;
endcase
end
end
always #(posedge clk) begin
r1 <= SCK;
r2 <= r1;
r3 <= r2;
pcEn <= r2 && !r3;
cnt <= next_cnt;
LED <= next_LED;
end
I'm trying to create an I2C protocol in verilog to read data from a sensor (TMP007)then show the data received using led but to no avail. I've been trying to put led (eg. LED_GREEN[2] =1;) in the state to test the flow of the state. Only the LED_GREEN1 and LED_GREEN[0] are lighten up. So I guess the problem does occur in STATE_WACK2. Anyone can help?
module tmpi2c(
input wire clk,
input wire reset,
inout reg i2c_sda,
output wire i2c_scl,
output reg [17:0] LED_RED, // LED Red[17:0]
output reg [7:0] LED_GREEN
);
// write to device address 0x40, 0x01h
localparam STATE_IDLE = 0;
localparam STATE_START = 1;
localparam STATE_ADDR = 2;
localparam STATE_RW = 3;
localparam STATE_WACK = 4;
localparam STATE_DATA = 5;
localparam STATE_WACK2 = 6;
localparam STATE_ADDR2 = 7;
localparam STATE_RW2 = 8;
localparam STATE_WACK3 = 9;
localparam STATE_READ = 10;
localparam STATE_WACK4 = 11;
localparam STATE_READ2 = 12;
localparam STATE_WACK5 = 13;
localparam STATE_STOP = 14;
localparam STATE_DISPLAY = 15;
reg enable; //(r=1, w=0)
reg clki2c = 0;
reg [9:0]counter = 0; // 10-bit counter size
reg [9:0] timer = 0;
reg [7:0] state;
reg [6:0] addr;
reg [7:0] data;
reg [7:0] count;
reg [15:0] value =0;
reg [4:0] ge,shi,bai;
reg i2c_scl_enable =0;
assign i2c_scl = (i2c_scl_enable == 0) ? 1 : ~clki2c;
reg i2c_sda_en;
wire i2c_sda_in = i2c_sda ;
// counter size calculation according to input and output frequencies
parameter sys_clk = 50000000; // 50 MHz system clock
//parameter clk_out = 400000; // 0.4 MHz clock output
parameter clk_out = 200000; // 0.2 MHz clock output
//parameter clk_out = 1; // 1Hz clock output
parameter max = sys_clk / (2*clk_out); // max-counter size
//clock divider from 50Mhz to 0.4Mhz
always#(posedge clk or posedge reset)
begin
if(reset) begin
counter <=0;
clki2c <= 0;
end
else begin
if (counter < max) begin
counter <= counter + 1'd1;
end
else begin
counter <= 0;
clki2c <= ~clki2c;
end
end
end
//end clock divider
always#(posedge clki2c) begin
if (!i2c_sda_en) begin i2c_sda = i2c_sda ;
end else begin
i2c_sda = 1'bz;
end
if (reset == 1)
begin
state <= 0;
//i2c_sda <= 1;
//i2c_scl <= 1;
i2c_sda_en <= 1;// i2c_sda ==z;
addr <= 7'h40;
count <= 8'd0;
data <= 8'h01;
LED_RED[17:0] = 0;
LED_GREEN[7:0] = 0;
end
else begin
case(state)
STATE_IDLE: begin //idle
state <= STATE_START;
end
STATE_START: begin //start
i2c_sda_en <= 0;
state <=STATE_ADDR;
count <= 6;
end
STATE_ADDR: begin //msb address bit
LED_GREEN[0] =1;
i2c_sda <= addr[count];
if (count ==0) state <= STATE_RW;
else count <= count -1;
end
STATE_RW: begin
i2c_sda <=0; //write here
state <=STATE_WACK;
end
STATE_WACK: begin
i2c_sda_en <= 1;
if(i2c_sda_in==1)
begin
state <= STATE_WACK;
end
else
begin
state <= STATE_DATA;
end
count <= 7 ;
i2c_sda_en <= 0;
end
STATE_DATA: begin
LED_GREEN[1] =1;
i2c_sda <= data[count];
if (count == 0) state <= STATE_WACK2;
else count <= count -1;
end
STATE_WACK2: begin
i2c_sda_en <= 1;
if(i2c_sda_in==1)
begin
state <= STATE_WACK2;
end
else
begin
state <= STATE_ADDR2;
//LED_GREEN[1] =1;
end
count <= 6;
i2c_sda_en <= 0;
end
STATE_ADDR2: begin
LED_GREEN[2] =1;
i2c_sda <= addr[count];
if (count ==0) state <= STATE_RW2;
else count <= count -1;
end
STATE_RW2: begin
i2c_sda <=1; //read here
state <=STATE_WACK3;
end
STATE_WACK3: begin
i2c_sda_en <= 1;
if(i2c_sda_in==1)
begin
state <= STATE_WACK2;
end
else
begin
state <= STATE_READ;
end
count <= 15;
//i2c_sda_en <= 0;
end
STATE_READ: begin
LED_GREEN[3] =1;
value[count] <= i2c_sda_in;
if (count == 8) state<= STATE_WACK4;
else count <= count -1;
end
STATE_WACK4: begin
i2c_sda_en <= 0;
i2c_sda <=1; //Master should leave SDA high to terminate a single-byte read operation.
state <= STATE_READ2;
count <= 7;
i2c_sda_en <= 1;
end
STATE_READ2: begin
LED_GREEN[4] =1;
value[count] <= i2c_sda_in;
if (count == 0) state<= STATE_WACK5;
else count <= count -1;
end
STATE_WACK5: begin
i2c_sda_en <= 0;
i2c_sda <=1; //Master should leave SDA high to terminate a two-byte read operation.
state <= STATE_STOP;
end
STATE_STOP: begin
//i2c_sda <=1;
state <= STATE_DISPLAY;
end
STATE_DISPLAY: begin
LED_RED[17] = value[15];
LED_RED[16] = value[14];
LED_RED[15] = value[13];
LED_RED[14] = value[12];
LED_RED[13] = value[11];
LED_RED[12] = value[10];
LED_RED[11] = value[9];
LED_RED[10] = value[8];
LED_RED[9] = value[7];
LED_RED[8] = value[6];
LED_RED[7] = value[5];
LED_RED[6] = value[4];
LED_RED[5] = value[3];
LED_RED[4] = value[2];
LED_RED[2] = value[0];
LED_RED[3] = value[1];
//display delay
if (timer < 100000) timer <= timer+1;
else timer <= 0;
state <= STATE_IDLE;
end
endcase
end
end
endmodule
Ok so I know my code works for a 3 number sequence but for with the finite state machine model I drew out this should be correct but it doesn't work for a 4 number sequence. It only detects the first 3. I need to detect with an overlap "0110" from the sequence 01100110110111. It should have 3 "0110" sequences and 2 overlapping but when I run my Verilog it detects 4 "0110" sequences which tells me it's only grabbing "011" Can someone look at my code and see what I'm doing wrong? I could simply add another state but I wouldn't think that's the correct way since I don't have another state in my diagram.
module moore_seq
(
input clock, reset, x,
output reg z
);
//assign binary encoded codes to the states A through D
parameter A = 2'b00,
B = 2'b01,
C = 2'b10,
D = 2'b11;
reg [1:0] current_state, next_state;
//Section 1: Next state generator (NSG)
always#(*)
begin
casex(current_state) //ignore unknown and Hi-Z inputs
A: if (x == 1)
next_state = A;
else
next_state = B;
B: if (x == 1)
next_state = C;
else
next_state = B;
C: if (x == 1)
next_state = D;
else
next_state = B;
D: if (x == 1)
next_state = A;
else
next_state = B;
endcase
end
//Section 2: Output Generator (OG)
always#(*)
begin
if(current_state == D)
z = 1;
else
z = 0;
end
//Section 3: The Flip Flops
always#(posedge clock, posedge reset)
begin
if(reset == 1)
current_state <= A;
else
current_state <= next_state;
end
endmodule
UPDATED:
parameter A = 3'b000,
B = 3'b001,
C = 3'b010,
D = 3'b011,
E = 3'b100;
reg [1:0] current_state, next_state;
//Section 1: Next state generator (NSG)
always#(*)
begin
casex(current_state) //ignore unknown and Hi-Z inputs
A: if (x == 1)
next_state = A;
else
next_state = B;
B: if (x == 1)
next_state = C;
else
next_state = B;
C: if (x == 1)
next_state = D;
else
next_state = B;
D: if (x == 1)
next_state = A;
else
next_state = E;
E: if (x == 1)
next_state = C;
else
next_state = B;
endcase
end
//Section 2: Output Generator (OG)
always#(*)
begin
if(current_state == E)
z = 1;
else
z = 0;
end
I suppose, four states is enough. Just change
//Section 2: Output Generator (OG)
always#(*)
begin
if(current_state == D)
to
//Section 2: Output Generator (OG)
always#(*)
begin
if(current_state == D && x == 0 )