Forum Discussion
Altera_Forum
Honored Contributor
8 years agoFPGA Development Board - strange shift operation behavior
My development board based on:
Cyclone IV EP4CE10E22C8N Quartus: 17.0.0 Lite Edition top-level entity code:
module led4_reg(clk, led);
parameter BASE_LED_SEQUENCE = 12'b000011101101;
input clk;
output led;
reg led;
reg circle_count;
initial begin
led = 0;
count = 0;
circle_count = 0;
led <= ~led;
$monitor($time, " led = %b count = %d", led, circle_count);
end
reg count;
always @(posedge clk)
begin
count <= count + 1;
if (count == 1) begin
count <= 0;
circle_count <= circle_count + 1;
end
if (circle_count == 12)
circle_count <= 0;
end
always @(circle_count)
begin
case (circle_count)
0: led <= BASE_LED_SEQUENCE;
1,2,3,4: led <= (led << 1);
// 1: led <= 12'b000111011010;
// 2: led <= 12'b001110110100;
// 3: led <= 12'b011101101000;
// 4: led <= 12'b111011010000;
5: led <= 12'b110110100001;
6: led <= 12'b101101000011;
7: led <= 12'b011010000111;
8: led <= 12'b110100001110;
9: led <= 12'b101000011101;
10: led <= 12'b010000111011;
11: led <= 12'b100001110110;
default: led <= 12'b000_111_111_111;
endcase
end
endmodule
My test file:
`include "led4_reg.v"
module main();
reg clk;
wire leds;
led4_reg reglight(clk, leds);
initial begin
clk = 0;
forever# 1 clk = ~clk;
end
initial# 160_000_000 $finish;
endmodule
And test results:
0 led = 000011101101 count = 0
16777217 led = 000111011010 count = 1
33554435 led = 001110110100 count = 2
50331653 led = 011101101000 count = 3
67108871 led = 111011010000 count = 4
83886089 led = 110110100001 count = 5
100663307 led = 101101000011 count = 6
117440525 led = 011010000111 count = 7
134217743 led = 110100001110 count = 8
150994961 led = 101000011101 count = 9
But on the Dev Board LED for count item 1,2,3,4 always: 12'b000_000_000_000; I don't understand why. Additionally for some reason '0' - turn on light for LED. '1' - turn off for LED. Is it normal? Any idea? )) Thanks!15 Replies
- Altera_Forum
Honored Contributor
Hi,
Is your board an Altera/terasic dev board or a custom one based on Cyclone IV ? If its the Altera/terasic one, then most likely the LEDs are all active low , meaning, a writing a '0' will turn ON the LED and '1' will turn OFF the LED. - Altera_Forum
Honored Contributor
--- Quote Start --- Hi, Is your board an Altera/terasic dev board or a custom one based on Cyclone IV ? If its the Altera/terasic one, then most likely the LEDs are all active low , meaning, a writing a '0' will turn ON the LED and '1' will turn OFF the LED. --- Quote End --- Looks like custome Dev Board ZEOWAA A-C4E6E10. Main problem in the part:
if I use explicit form like:led <= (led << 1);
it work pretty well on Dev Board.led <= (12'b000111011010 << 1); - Altera_Forum
Honored Contributor
Hi,
There are a few issues in the code. 1. You cannot use initial blocks and $display tasks in RTL code for synthesis as these constructs are non-synthesizable . These are used only for simulation 2. The code does not have a reset value or initial value. Use an asynchronous reset input and in the always block check for its negedge. When reset is asserted, initialize the count and output to '0'. 3. The reason why led is always 0, is due to the fact that for the first case item (case 0) it will get the value from the parameter. For the next case items (case 1,2,3,4).. You are left shifting the value in the register which is always at 0. This is due to the fact that, after the case is hit, its value will get updated outside the always block. So the next time the code comes back to the case and hits the next one, the value of the led variable is 0. The previous value of led variable is not stored. You can accomplish this by modifying the default condition..
Although this will infer a latch that will store the last value of the register led.default : led <= led; - Altera_Forum
Honored Contributor
--- Quote Start --- Hi, There are a few issues in the code. --- Quote End --- Thank you for the response! Point 1,2 - thank you very much for remarks! 3. I really can't understand why:
but1: led <= led; // will get previous value
Additionally, the default block never invoked. Am I understand correctly that I should implement simple latch for storing previous value?1: led <= (led << 1); // can't get previous value - Altera_Forum
Honored Contributor
You should ideally, store the previous value or initial value of the led in a register/flop. Then have it shifted out in the case. The default case may not work, but worth a try. You will understand what I mentioned if you look at how an always block will be executed.
What you need to do is to latch in or register in the default value of the led (parameter) then use this value to shift left and get your corresponding outputs. For this to happen, the value of led register should be latched or stored, then used again in the case to update for the next case item. - Altera_Forum
Honored Contributor
Try this code out. I just modified it to add the reset and logic to store initial value.
module LED4(clk, reset, led); parameter BASE_LED_SEQUENCE = 12'b000011101101; input clk; input reset; output led; reg led; reg circle_count; //initial begin // led = 0; // count = 0; // circle_count = 0; // led <= ~led; // $monitor($time, " led = %b count = %d", led, circle_count); //end reg count; always @(posedge clk or negedge reset) begin if (!reset) begin count <= 28'd0; circle_count <= 4'd0; end else begin count <= count + 1; count <= 0; circle_count <= circle_count + 1; if (circle_count == 12) circle_count <= 0; end end always @(circle_count) begin led <= BASE_LED_SEQUENCE; case (circle_count) 0: led <= BASE_LED_SEQUENCE; 1,2,3,4: led <= (led << 1); // 1: led <= 12'b000111011010; // 2: led <= 12'b001110110100; // 3: led <= 12'b011101101000; // 4: led <= 12'b111011010000; 5: led <= 12'b110110100001; 6: led <= 12'b101101000011; 7: led <= 12'b011010000111; 8: led <= 12'b110100001110; 9: led <= 12'b101000011101; 10: led <= 12'b010000111011; 11: led <= 12'b100001110110; default: led <= 12'b000_111_111_111; endcase end endmodule - Altera_Forum
Honored Contributor
--- Quote Start --- Try this code out. I just modified it to add the reset and logic to store initial value.
--- Quote End --- Same result: 1,2,3,4 = 0; With D-latch same result:1,2,3,4: led <= (led << 1);
if I use:module led4_reg( input clk, input rst, output reg led ); parameter BASE_LED_SEQUENCE = 12'b000011101101; reg led_value; reg circle_count; reg count; always @(posedge clk or negedge rst) begin if (!rst) begin count <= 0; circle_count <= 0; end else begin count <= count + 1'b1; if (count == 1) begin count <= 1'b0; circle_count <= circle_count + 1'b1; end if (circle_count == 12) circle_count <= 0; end end always @(led) begin led_value <= led; end always @(circle_count or led_value) begin case (circle_count) 0: led <= BASE_LED_SEQUENCE; 1,2,3,4: led <= (led_value << 1); 5: led <= 12'b110110100001; 6: led <= 12'b101101000011; 7: led <= 12'b011010000111; 8: led <= 12'b110100001110; 9: led <= 12'b101000011101; 10: led <= 12'b010000111011; 11: led <= 12'b100001110110; default: led <= 12'b000_000_000_000; endcase end endmodule
it will get previous data.1,2,3,4: led <= led_value; - Altera_Forum
Honored Contributor
--- Quote Start --- Try this code out. I just modified it to add the reset and logic to store initial value. --- Quote End --- Same result. - Altera_Forum
Honored Contributor
Try this one and check, it runs in my simulations..
module led4_reg(clk, reset, led); parameter BASE_LED_SEQUENCE = 12'b000011101101; input clk; input reset; output led; reg led; reg circle_count; //wire led_tmp; //initial begin // led = 0; // count = 0; // circle_count = 0; // led <= ~led; // $monitor($time, " led = %b count = %d", led, circle_count); //end reg count; always @(posedge clk or negedge reset) begin if (!reset) begin count <= 28'd0; circle_count <= 4'd0; end else begin count <= count + 28'd1; circle_count <= circle_count + 4'd1; if (circle_count == 4'd12) circle_count <= 4'd0; end end always@(circle_count or led) begin if (circle_count == 4'd0) begin led = BASE_LED_SEQUENCE; end else begin led = led << 1; end end endmodule - Altera_Forum
Honored Contributor
This is very inefficient logic for variables defined as registers. You have built a change detector on circle_count[3:0] that will trigger an asynchronous clocking of the led[11:0] registers when it triggers. Why not just add the statement:reg led; reg circle_count; ... always@(circle_count or led) begin if (circle_count == 4'd0) begin led = BASE_LED_SEQUENCE; end else begin led = led << 1; end end
into the main loop, so it looks like this:led <= circle_count == 4'd0 ? BASE_LED_SEQUENCE : led << 1;
which I think is a lot easier to follow.always @(posedge clk or negedge reset) begin if (!reset) begin count <= 28'd0; circle_count <= 4'd0; led <= 12'b0; end else begin if (count == 1'b1) begin count <= 28'd0; circle_count <= circle_count == 4'd12 ? 4'd0 : circle_count + 4'd1; led <= circle_count == 4'd0 ? BASE_LED_SEQUENCE : led << 1; end else count <= count + 28'd1; end end