F
Frank Buss
Guest
I'm learning Verilog and have some questions, because I have no
experience with HDL and not much with hardware design. Below is my
first Verilog program, which works with the nice Spartan3 starter
kit from Xilinx. Perhaps you can take a look at it and give me some
hints how I can improve it and where are possible bugs.
Some specific questions:
- how can I latch the vga output signals on falling clock edge without
another reg-set? I assume somthing with "wire", but I don't know
- the state machine for the VGA signal generation looks like it can be
simplified
- how can I do "meta"-programming? For example the handling for
led0Power to led7Power is all the same, so I need something like a loop,
but how do I declare the variables as arrays and access them?
module test(
clk, led, segment, digit,
VGA_Red, VGA_Green, VGA_Blue, VGA_HSYNCH_N, VGA_VSYNCH_N);
input clk;
output [7:0] led;
output [7:0] segment;
output [3:0] digit;
assign segment[0] = 0;
assign segment[1] = 0;
assign segment[2] = 0;
assign segment[3] = 0;
assign segment[4] = 0;
assign segment[5] = 0;
assign segment[6] = 0;
assign segment[7] = 0;
assign digit[0] = 1;
assign digit[1] = 1;
assign digit[2] = 1;
assign digit[3] = 1;
//
// VGA video pattern generator
//
/* VGA timings:
clocks per line:
1. HSync low pulse for 96 clocks
2. back porch for 48 clocks
3. data for 640 clocks
4. front porch for 16 clocks
VSync timing per picture (800 clocks = 1 line):
1. VSync low pulse for 2 lines
2. back porch for 29 lines
3. data for 480 lines
4. front porch for 10 lines
*/
`define LINE_HSYNC_LOW 0
`define LINE_BACK_PORCH 1
`define LINE_DATA 2
`define LINE_FRONT_PORCH 3
`define IMAGE_VSYNC_LOW 0
`define IMAGE_BACK_PORCH 1
`define IMAGE_DATA 2
`define IMAGE_FRONT_PORCH 3
output VGA_Red;
output VGA_Green;
output VGA_Blue;
output VGA_HSYNCH_N;
output VGA_VSYNCH_N;
reg rVGA_Red = 0;
reg rVGA_Green = 0;
reg rVGA_Blue = 0;
reg rVGA_HSYNCH_N = 0;
reg rVGA_VSYNCH_N = 0;
reg latchVGA_Red = 0;
reg latchVGA_Green = 0;
reg latchVGA_Blue = 0;
reg latchVGA_HSYNCH_N = 0;
reg latchVGA_VSYNCH_N = 0;
assign VGA_Red = latchVGA_Red;
assign VGA_Green = latchVGA_Green;
assign VGA_Blue = latchVGA_Blue;
assign VGA_HSYNCH_N = latchVGA_HSYNCH_N;
assign VGA_VSYNCH_N = latchVGA_VSYNCH_N;
reg [2:0] lineState = 0;
reg [2:0] imageState = 0;
reg [10:0] pixelCounter = 0;
reg [10:0] lineCounter = 0;
reg devide2 = 0;
always @(posedge clk) begin
devide2 <= ~devide2;
if (devide2) begin
// check line
case (lineState)
`LINE_HSYNC_LOW: begin
if (pixelCounter == 96) begin
pixelCounter <= 0;
lineState = `LINE_BACK_PORCH;
rVGA_HSYNCH_N <= 1;
end else pixelCounter <= pixelCounter + 1;
end
`LINE_BACK_PORCH: begin
if (pixelCounter == 48) begin
pixelCounter <= 0;
lineState = `LINE_DATA;
end else pixelCounter <= pixelCounter + 1;
end
`LINE_DATA: begin
if (lineCounter < 480 && imageState == `IMAGE_DATA) begin
rVGA_Red <= pixelCounter[4];
rVGA_Green <= pixelCounter[5];
rVGA_Blue <= pixelCounter[6];
end else begin
rVGA_Red <= 0;
rVGA_Green <= 0;
rVGA_Blue <= 0;
end
if (pixelCounter == 640) begin
pixelCounter <= 0;
lineState = `LINE_FRONT_PORCH;
end else pixelCounter <= pixelCounter + 1;
end
`LINE_FRONT_PORCH: begin
if (pixelCounter == 16) begin
pixelCounter <= 0;
lineState = `LINE_HSYNC_LOW;
rVGA_HSYNCH_N <= 0;
// check image
case (imageState)
`IMAGE_VSYNC_LOW: begin
if (lineCounter == 2) begin
lineCounter <= 0;
imageState = `IMAGE_BACK_PORCH;
rVGA_VSYNCH_N <= 1;
end else lineCounter <= lineCounter + 1;
end
`IMAGE_BACK_PORCH: begin
if (lineCounter == 29) begin
lineCounter <= 0;
imageState = `IMAGE_DATA;
end else lineCounter <= lineCounter + 1;
end
`IMAGE_DATA: begin
if (lineCounter == 480) begin
lineCounter <= 0;
imageState = `IMAGE_FRONT_PORCH;
end else lineCounter <= lineCounter + 1;
end
`IMAGE_FRONT_PORCH: begin
if (lineCounter == 16) begin
lineCounter <= 0;
imageState = `IMAGE_VSYNC_LOW;
rVGA_VSYNCH_N <= 0;
end else lineCounter <= lineCounter + 1;
end
default:
imageState = `IMAGE_VSYNC_LOW;
endcase
end else pixelCounter <= pixelCounter + 1;
end
default:
lineState = `LINE_HSYNC_LOW;
endcase
end
end
always @(negedge clk) begin
latchVGA_Red <= rVGA_Red;
latchVGA_Green <= rVGA_Green;
latchVGA_Blue <= rVGA_Blue;
latchVGA_HSYNCH_N <= rVGA_HSYNCH_N;
latchVGA_VSYNCH_N <= rVGA_VSYNCH_N;
end
//
// knight rider like LED scroll
//
reg [16:0] devide2500 = 0; // 50 MHz / 1000 = 50 kHz
reg [16:0] devideLed = 0;
reg [16:0] scrollLedCounter = 0;
reg [4:0] scrollLed = 0;
reg led0 = 0;
assign led[0] = led0;
reg [7:0] led0Power = 0;
reg [7:0] led0Counter = 0;
reg led1 = 0;
assign led[1] = led1;
reg [7:0] led1Power = 0;
reg [7:0] led1Counter = 0;
reg led2 = 0;
assign led[2] = led2;
reg [7:0] led2Power = 0;
reg [7:0] led2Counter = 0;
reg led3 = 0;
assign led[3] = led3;
reg [7:0] led3Power = 0;
reg [7:0] led3Counter = 0;
reg led4 = 0;
assign led[4] = led4;
reg [7:0] led4Power = 0;
reg [7:0] led4Counter = 0;
reg led5 = 0;
assign led[5] = led5;
reg [7:0] led5Power = 0;
reg [7:0] led5Counter = 0;
reg led6 = 0;
assign led[6] = led6;
reg [7:0] led6Power = 0;
reg [7:0] led6Counter = 0;
reg led7 = 0;
assign led[7] = led7;
reg [7:0] led7Power = 0;
reg [7:0] led7Counter = 0;
always @(posedge clk) begin
if (devide2500 == 2500) begin
devide2500 = 0;
if (led0Power > led0Counter) led0 <= 1; else led0 <= 0;
if (led0Counter == 255) led0Counter <= 0; else led0Counter <= led0Counter + 1;
if (led1Power > led1Counter) led1 <= 1; else led1 <= 0;
if (led1Counter == 255) led1Counter <= 0; else led1Counter <= led1Counter + 1;
if (led2Power > led2Counter) led2 <= 1; else led2 <= 0;
if (led2Counter == 255) led2Counter <= 0; else led2Counter <= led2Counter + 1;
if (led3Power > led3Counter) led3 <= 1; else led3 <= 0;
if (led3Counter == 255) led3Counter <= 0; else led3Counter <= led3Counter + 1;
if (led4Power > led4Counter) led4 <= 1; else led4 <= 0;
if (led4Counter == 255) led4Counter <= 0; else led4Counter <= led4Counter + 1;
if (led5Power > led5Counter) led5 <= 1; else led5 <= 0;
if (led5Counter == 255) led5Counter <= 0; else led5Counter <= led5Counter + 1;
if (led6Power > led6Counter) led6 <= 1; else led6 <= 0;
if (led6Counter == 255) led6Counter <= 0; else led6Counter <= led6Counter + 1;
if (led7Power > led7Counter) led7 <= 1; else led7 <= 0;
if (led7Counter == 255) led7Counter <= 0; else led7Counter <= led7Counter + 1;
if (devideLed == 60) begin
devideLed <= 0;
if (led0Power > 0) led0Power <= led0Power * 255 / 256;
if (led1Power > 0) led1Power <= led1Power * 255 / 256;
if (led2Power > 0) led2Power <= led2Power * 255 / 256;
if (led3Power > 0) led3Power <= led3Power * 255 / 256;
if (led4Power > 0) led4Power <= led4Power * 255 / 256;
if (led5Power > 0) led5Power <= led5Power * 255 / 256;
if (led6Power > 0) led6Power <= led6Power * 255 / 256;
if (led7Power > 0) led7Power <= led7Power * 255 / 256;
if (scrollLedCounter == 60) begin
scrollLedCounter <= 0;
scrollLed <= scrollLed + 1;
case (scrollLed)
0: led0Power <= 255;
1: led1Power <= 255;
2: led2Power <= 255;
3: led3Power <= 255;
4: led4Power <= 255;
5: led5Power <= 255;
6: led6Power <= 255;
7: led7Power <= 255;
8: led7Power <= 255;
9: led6Power <= 255;
10: led5Power <= 255;
11: led4Power <= 255;
12: led3Power <= 255;
13: led2Power <= 255;
14: led1Power <= 255;
15: begin led0Power <= 255; scrollLed <= 0; end
endcase
end else begin
scrollLedCounter <= scrollLedCounter + 1;
end
end else begin
devideLed <= devideLed + 1;
end
end else devide2500 = devide2500 + 1;
end
endmodule
--
Frank Buß, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
experience with HDL and not much with hardware design. Below is my
first Verilog program, which works with the nice Spartan3 starter
kit from Xilinx. Perhaps you can take a look at it and give me some
hints how I can improve it and where are possible bugs.
Some specific questions:
- how can I latch the vga output signals on falling clock edge without
another reg-set? I assume somthing with "wire", but I don't know
- the state machine for the VGA signal generation looks like it can be
simplified
- how can I do "meta"-programming? For example the handling for
led0Power to led7Power is all the same, so I need something like a loop,
but how do I declare the variables as arrays and access them?
module test(
clk, led, segment, digit,
VGA_Red, VGA_Green, VGA_Blue, VGA_HSYNCH_N, VGA_VSYNCH_N);
input clk;
output [7:0] led;
output [7:0] segment;
output [3:0] digit;
assign segment[0] = 0;
assign segment[1] = 0;
assign segment[2] = 0;
assign segment[3] = 0;
assign segment[4] = 0;
assign segment[5] = 0;
assign segment[6] = 0;
assign segment[7] = 0;
assign digit[0] = 1;
assign digit[1] = 1;
assign digit[2] = 1;
assign digit[3] = 1;
//
// VGA video pattern generator
//
/* VGA timings:
clocks per line:
1. HSync low pulse for 96 clocks
2. back porch for 48 clocks
3. data for 640 clocks
4. front porch for 16 clocks
VSync timing per picture (800 clocks = 1 line):
1. VSync low pulse for 2 lines
2. back porch for 29 lines
3. data for 480 lines
4. front porch for 10 lines
*/
`define LINE_HSYNC_LOW 0
`define LINE_BACK_PORCH 1
`define LINE_DATA 2
`define LINE_FRONT_PORCH 3
`define IMAGE_VSYNC_LOW 0
`define IMAGE_BACK_PORCH 1
`define IMAGE_DATA 2
`define IMAGE_FRONT_PORCH 3
output VGA_Red;
output VGA_Green;
output VGA_Blue;
output VGA_HSYNCH_N;
output VGA_VSYNCH_N;
reg rVGA_Red = 0;
reg rVGA_Green = 0;
reg rVGA_Blue = 0;
reg rVGA_HSYNCH_N = 0;
reg rVGA_VSYNCH_N = 0;
reg latchVGA_Red = 0;
reg latchVGA_Green = 0;
reg latchVGA_Blue = 0;
reg latchVGA_HSYNCH_N = 0;
reg latchVGA_VSYNCH_N = 0;
assign VGA_Red = latchVGA_Red;
assign VGA_Green = latchVGA_Green;
assign VGA_Blue = latchVGA_Blue;
assign VGA_HSYNCH_N = latchVGA_HSYNCH_N;
assign VGA_VSYNCH_N = latchVGA_VSYNCH_N;
reg [2:0] lineState = 0;
reg [2:0] imageState = 0;
reg [10:0] pixelCounter = 0;
reg [10:0] lineCounter = 0;
reg devide2 = 0;
always @(posedge clk) begin
devide2 <= ~devide2;
if (devide2) begin
// check line
case (lineState)
`LINE_HSYNC_LOW: begin
if (pixelCounter == 96) begin
pixelCounter <= 0;
lineState = `LINE_BACK_PORCH;
rVGA_HSYNCH_N <= 1;
end else pixelCounter <= pixelCounter + 1;
end
`LINE_BACK_PORCH: begin
if (pixelCounter == 48) begin
pixelCounter <= 0;
lineState = `LINE_DATA;
end else pixelCounter <= pixelCounter + 1;
end
`LINE_DATA: begin
if (lineCounter < 480 && imageState == `IMAGE_DATA) begin
rVGA_Red <= pixelCounter[4];
rVGA_Green <= pixelCounter[5];
rVGA_Blue <= pixelCounter[6];
end else begin
rVGA_Red <= 0;
rVGA_Green <= 0;
rVGA_Blue <= 0;
end
if (pixelCounter == 640) begin
pixelCounter <= 0;
lineState = `LINE_FRONT_PORCH;
end else pixelCounter <= pixelCounter + 1;
end
`LINE_FRONT_PORCH: begin
if (pixelCounter == 16) begin
pixelCounter <= 0;
lineState = `LINE_HSYNC_LOW;
rVGA_HSYNCH_N <= 0;
// check image
case (imageState)
`IMAGE_VSYNC_LOW: begin
if (lineCounter == 2) begin
lineCounter <= 0;
imageState = `IMAGE_BACK_PORCH;
rVGA_VSYNCH_N <= 1;
end else lineCounter <= lineCounter + 1;
end
`IMAGE_BACK_PORCH: begin
if (lineCounter == 29) begin
lineCounter <= 0;
imageState = `IMAGE_DATA;
end else lineCounter <= lineCounter + 1;
end
`IMAGE_DATA: begin
if (lineCounter == 480) begin
lineCounter <= 0;
imageState = `IMAGE_FRONT_PORCH;
end else lineCounter <= lineCounter + 1;
end
`IMAGE_FRONT_PORCH: begin
if (lineCounter == 16) begin
lineCounter <= 0;
imageState = `IMAGE_VSYNC_LOW;
rVGA_VSYNCH_N <= 0;
end else lineCounter <= lineCounter + 1;
end
default:
imageState = `IMAGE_VSYNC_LOW;
endcase
end else pixelCounter <= pixelCounter + 1;
end
default:
lineState = `LINE_HSYNC_LOW;
endcase
end
end
always @(negedge clk) begin
latchVGA_Red <= rVGA_Red;
latchVGA_Green <= rVGA_Green;
latchVGA_Blue <= rVGA_Blue;
latchVGA_HSYNCH_N <= rVGA_HSYNCH_N;
latchVGA_VSYNCH_N <= rVGA_VSYNCH_N;
end
//
// knight rider like LED scroll
//
reg [16:0] devide2500 = 0; // 50 MHz / 1000 = 50 kHz
reg [16:0] devideLed = 0;
reg [16:0] scrollLedCounter = 0;
reg [4:0] scrollLed = 0;
reg led0 = 0;
assign led[0] = led0;
reg [7:0] led0Power = 0;
reg [7:0] led0Counter = 0;
reg led1 = 0;
assign led[1] = led1;
reg [7:0] led1Power = 0;
reg [7:0] led1Counter = 0;
reg led2 = 0;
assign led[2] = led2;
reg [7:0] led2Power = 0;
reg [7:0] led2Counter = 0;
reg led3 = 0;
assign led[3] = led3;
reg [7:0] led3Power = 0;
reg [7:0] led3Counter = 0;
reg led4 = 0;
assign led[4] = led4;
reg [7:0] led4Power = 0;
reg [7:0] led4Counter = 0;
reg led5 = 0;
assign led[5] = led5;
reg [7:0] led5Power = 0;
reg [7:0] led5Counter = 0;
reg led6 = 0;
assign led[6] = led6;
reg [7:0] led6Power = 0;
reg [7:0] led6Counter = 0;
reg led7 = 0;
assign led[7] = led7;
reg [7:0] led7Power = 0;
reg [7:0] led7Counter = 0;
always @(posedge clk) begin
if (devide2500 == 2500) begin
devide2500 = 0;
if (led0Power > led0Counter) led0 <= 1; else led0 <= 0;
if (led0Counter == 255) led0Counter <= 0; else led0Counter <= led0Counter + 1;
if (led1Power > led1Counter) led1 <= 1; else led1 <= 0;
if (led1Counter == 255) led1Counter <= 0; else led1Counter <= led1Counter + 1;
if (led2Power > led2Counter) led2 <= 1; else led2 <= 0;
if (led2Counter == 255) led2Counter <= 0; else led2Counter <= led2Counter + 1;
if (led3Power > led3Counter) led3 <= 1; else led3 <= 0;
if (led3Counter == 255) led3Counter <= 0; else led3Counter <= led3Counter + 1;
if (led4Power > led4Counter) led4 <= 1; else led4 <= 0;
if (led4Counter == 255) led4Counter <= 0; else led4Counter <= led4Counter + 1;
if (led5Power > led5Counter) led5 <= 1; else led5 <= 0;
if (led5Counter == 255) led5Counter <= 0; else led5Counter <= led5Counter + 1;
if (led6Power > led6Counter) led6 <= 1; else led6 <= 0;
if (led6Counter == 255) led6Counter <= 0; else led6Counter <= led6Counter + 1;
if (led7Power > led7Counter) led7 <= 1; else led7 <= 0;
if (led7Counter == 255) led7Counter <= 0; else led7Counter <= led7Counter + 1;
if (devideLed == 60) begin
devideLed <= 0;
if (led0Power > 0) led0Power <= led0Power * 255 / 256;
if (led1Power > 0) led1Power <= led1Power * 255 / 256;
if (led2Power > 0) led2Power <= led2Power * 255 / 256;
if (led3Power > 0) led3Power <= led3Power * 255 / 256;
if (led4Power > 0) led4Power <= led4Power * 255 / 256;
if (led5Power > 0) led5Power <= led5Power * 255 / 256;
if (led6Power > 0) led6Power <= led6Power * 255 / 256;
if (led7Power > 0) led7Power <= led7Power * 255 / 256;
if (scrollLedCounter == 60) begin
scrollLedCounter <= 0;
scrollLed <= scrollLed + 1;
case (scrollLed)
0: led0Power <= 255;
1: led1Power <= 255;
2: led2Power <= 255;
3: led3Power <= 255;
4: led4Power <= 255;
5: led5Power <= 255;
6: led6Power <= 255;
7: led7Power <= 255;
8: led7Power <= 255;
9: led6Power <= 255;
10: led5Power <= 255;
11: led4Power <= 255;
12: led3Power <= 255;
13: led2Power <= 255;
14: led1Power <= 255;
15: begin led0Power <= 255; scrollLed <= 0; end
endcase
end else begin
scrollLedCounter <= scrollLedCounter + 1;
end
end else begin
devideLed <= devideLed + 1;
end
end else devide2500 = devide2500 + 1;
end
endmodule
--
Frank Buß, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de