CPLD Breathing LED with flexible set points - verilog

This is my first post and my first attempt at using a PLD.
I have written some code to make a breathing LED with 7 set points. The code produces a pwm output according to the first set point. It then slowly increases/decreases the pwm towards the next set point (7 in total).
The code works but I think it can be done better as I need to put 16 instantiations of this into a Lattice 4256 CPLD (not possible with my code).
I am keen to learn how a professional Verilog programmer would tackle this.
Many thanks in advance for your support.
PWM Generation
module LED_breath (led, tmr_clk);
output reg led;
input tmr_clk;
reg [7:0] cnt;
reg [6:0] pwm_cnt;
reg [6:0] pwm_val;
reg [2:0] pat_cnt;
reg [9:0] delay_cnt;
reg [6:0] cur_pat;
reg [6:0] nxt_pat;
parameter pattern = {7'h00, 7'h00, 7'h00, 7'h00, 7'h00, 7'h00, 7'h00, 7'h00};
always #(posedge tmr_clk)
begin
pwm_cnt = cnt[7] ? ~cnt[6:0] : cnt[6:0]; //Generate triangle wave
if(pwm_cnt > pwm_val) //Generate pwm
led <= 1'b0;
if(pwm_cnt < pwm_val)
led <= 1'b1;
cnt = cnt + 1;
end
always #(posedge tmr_clk) //breathing pattern
begin
if(!delay_cnt) //Add delay
begin
cur_pat <= ((pattern >> (7*pat_cnt)) & 7'b1111111); //Find correct pattern No. from parameter list
if((pat_cnt+1) == 8) //Check for last pattern - overflow, set to 0
nxt_pat <= (pattern & 7'b1111111);
else
nxt_pat <= ((pattern >> (7*(pat_cnt+1))) & 7'b1111111);
if(pwm_val == nxt_pat) //If pwm is at max or min increment count to get next pattern
pat_cnt <= pat_cnt + 1;
if(cur_pat <= nxt_pat) //Current pattern < next pattern, count up
pwm_val <= pwm_val + 1;
if(cur_pat >= nxt_pat) //Current pattern < next pattern, count down
pwm_val <= pwm_val - 1;
end
delay_cnt <= delay_cnt + 1;
end
endmodule
module top (led_0, led_1, led_2, led_3);
output led_0;
output led_1;
output led_2;
output led_3;
defparam I1.TIMER_DIV = "128";
OSCTIMER I1 (.DYNOSCDIS(1'b0), .TIMERRES(1'b0), .OSCOUT(osc_clk), .TIMEROUT(tmr_clk));
LED_breath #(.pattern({7'h20, 7'h70, 7'h50, 7'h70, 7'h40, 7'h10, 7'h60, 7'h10})) led_A(
.led (led_0),
.tmr_clk (tmr_clk)
);
LED_breath #(.pattern({7'h70, 7'h10, 7'h30, 7'h20, 7'h60, 7'h40, 7'h70, 7'h10})) led_B(
.led (led_1),
.tmr_clk (tmr_clk)
);
LED_breath #(.pattern({7'h10, 7'h30, 7'h10, 7'h18, 7'h40, 7'h50, 7'h30, 7'h60})) led_C(
.led (led_2),
.tmr_clk (tmr_clk)
);
LED_breath #(.pattern({7'h50, 7'h70, 7'h40, 7'h50, 7'h40, 7'h70, 7'h60, 7'h70})) led_D(
.led (led_3),
.tmr_clk (tmr_clk)
);
endmodule

Can you explain a bit what you are trying to achieve in this always block ?
always #(posedge tmr_clk)
I think you're using a fixed frequency and changing duty cycle to get desired breathing effect.
1) Is my thinking correct ?
2) If yes, how do you decide when to change the pattern ?

Related

Verilog code that copies an input square wave signal to an output signal?

I was wondering if someone may be able to help me? I was not sure how to word the question, but I am basically trying to write a program that generates a square wave output signal from a square wave input signal, matching the duty cycle and frequency of the input signal. Basically, the output just copies the input. To summarize what I am saying graphically, here is a picture I made:
Link to diagram
It is not my final goal, but it would be enough to get me going. I am having a very hard time figuring out how to work with inputs. I have a signal generator making the input square wave signal, and am sending it into an input pin. I've tried calculating the duty cycle mathematically, and then just trying to assign the output to a reg that is set equal to the input on every rising edge of the clock signal but it didn't work.
Here's my code. It has extra functionality of generating a 1 Hz signal, but that is only from learning earlier how to create the pwm. You can ignore "pwm_reg" and the "pwm" output. The "pwm2" output is intended to copy "apwm" input:
`timescale 1ns / 1ps
module duty_cycle_gen(
input clk,
input rst_n,
input apwm,
output pwm,
output pwm2
);
// Input clock is 250MHz
localparam CLOCK_FREQUENCY = 250000000;
// Counter for toggling of clock
integer counter = 0;
reg pwm_reg = 0;
assign pwm = pwm_reg;
reg apwm_val;
always #(posedge clk) begin
if (!rst_n) begin
counter <= 8'h00;
pwm_reg <= 1'b0;
end
else begin
apwm_val <= apwm;
// If counter is zero, toggle pwm_reg
if (counter == 8'h00) begin
pwm_reg <= ~pwm_reg;
// Generate 1Hz Frequency
counter <= CLOCK_FREQUENCY/2 - 1;
end
// Else count down
else
counter <= counter - 1;
end
$display("counter : %d", counter);
end
assign pwm2 = apwm_val;
endmodule
Here is a simple example with a test bench. (I like to use a small delay when assigning, #1, to help capture causality for debugging purposes):
module example(
input wire clk,
input wire in,
output reg out);
always #(posedge clk)
begin
out <= #1 in;
end
endmodule // example
module example_test();
reg chip__clk;
reg chip__in;
wire chip__out;
reg [10:0] count;
example ex(
chip__clk,
chip__in,
chip__out);
initial
begin
$dumpvars();
count <= #1 0;
end
always #(count)
begin
count <= #1 (count + 1);
if (count == 1000)
begin
$display("RESULT=PASS:0 # done");
$finish_and_return(0);
end
if ((count == 60) & (chip__out != 1))
begin
$display("RESULT=FAIL:1 # chip.out not raised");
$finish_and_return(1);
end
if ((count == 30) & (chip__out != 0))
begin
$display("RESULT=FAIL:1 # chip.out not lowered");
$finish_and_return(1);
end
chip__in <= #1 count[5];
chip__clk <= #1 count[1];
end
endmodule // example_test
It works by treating the in signal as something that can can be thought of as constant over the timescale of the higher frequency clk.
If your in clock is an external signal which might be noisy, with the small latency delay, you can attempt to stabilize it by using a small fifo running with the high frequency clk:
module example(
input wire clk,
input wire in,
output reg out);
reg [1:0] buffer;
always #(posedge clk)
begin
out <= #1 buffer[1];
buffer[1] <= #1 buffer[0];
buffer[0] <= #1 in;
end
endmodule // example

Two ways to write pipeline in verilog, which one is better?

I learned two ways of writing pipeline(unblocking and blocking), I wonder which is better?
My personal opinion is that the second one is tedious and I don't understand why so many wire are needed.
Also, is there any standard style(template) of writing pipeline like FSM in verilog?
Thanks in advance.
module simplePipeline
#(
parameter WIDTH = 100
)
(
input clk,
input [WIDTH - 1 : 0] datain,
output [WIDTH - 1: 0] dataout
);
reg [WIDTH - 1 : 0] piprData1;
reg [WIDTH - 1 : 0] piprData2;
reg [WIDTH - 1 : 0] piprData3;
always #(posedge clk) begin
piprData1 <= datain;
end
always #(posedge clk) begin
piprData2 <= piprData1;
end
always #(posedge clk) begin
piprData3 <= piprData2;
end
assign dataout = piprData3;
endmodule
module blockingPipeline#2
(
parameter WIDTH = 100
)
(
input clk,
input rst,
input validIn,
input [WIDTH - 1 : 0] dataIn,
input outAllow,
output wire validOut,
output wire [WIDTH - 1 : 0] dataOut
);
reg pipe1Valid;
reg [WIDTH - 1 : 0] pipe1Data;
reg pipe2Valid;
reg [WIDTH - 1 : 0] pipe2Data;
reg pipe3Valid;
reg [WIDTH - 1 : 0] pipe3Data;
/*------------------------PIPE1 LOGIC------------------------*/
wire pipe1AllowIn;
wire pipe1ReadyGo;
wire pipe1ToPipe2Valid;
assign pipe1ReadyGo = 1'b1
assign pipe1AllowIn = ! pipe1Valid || pipe1ReadyGo && pipe2AllowIn;
assign pipe1ToPipe2Valid = pipe1Valid && pipe1ReadyGo
always #(posedge clk)begin
if( rst ) begin
pipe1Vali <= 1'b0;
end
else if(pipe1AllowIn)begin
pipe1Valid <= validIn;
end
ifvalidIn && pipe1AllowIn)begin
pipe1Data <= dataIn;
end
end
/*------------------------PIPE2 LOGIC------------------------*/
wire pipe2AllowIn;
wire pipe2ReadyGo;
wire pipe2ToPipe3Valid;
assign pipe2ReadyGo = 1'b1;
assign pipe2AllowIn = ! pipe2Valid || pipe2ReadyGo && pipe3AllowIn;
assign pipe2ToPipe3Valid = pipe2Valid && pipe3ReadyGo;
always #(posedge clk)begin
if( rst ) begin
pipe2Valid <= 1'b0;
end
else if(pipe2AllowIn)begin
pipe2Valid <= pipe1ToPipe2Valid;
end
if(pipe1ToPipe2Valid && pipe2AllowIn)begin
pipe2Data <= pipe1Data;
end
end
/*------------------------PIPE3 LOGIC------------------------*/
wire pipe3AllowIn;
wire pipe3ReadyGo;
assign pipe3ReadyGo = 1'b1;
assign pipe3AllowIn = ! pipe3Valid || pipe3ReadyGo && outAllow;
always #(posedge clk)begin
if( rst ) begin
pipe3Valid <= 1'b0;
end
else if(pipe3AllowIn)begin
pipe3Valid <= pipe2ToPipe3Valid;
end
if(pipe2ToPipe3Valid && pipe3AllowIn)begin
pipe3Data <= pipe2Data;
end
end
assign validOut = pipe3Valid && pipe3ReadyGo;
assign dataOut = pipe3Data;
endmodule
The problem with the first version is that there seems to be no clock gate at all. Unless your clock is well gated on a higher level or the pipeline is used every cycle you will waste a lot of power by (unnecessarily) toggling each stage of the pipeline every cycle.
As good practice, the second one seems "better" in the sense that when you design a hardware circuit part you might want offer great control possibilities. Generally speaking, since your code will be implemented in the silicon forever (or in your FPGA with painful reconfiguration) that would be a real problem to not have enough controls capacities, because you can't really add some afterward.
As an example you already mentioned in the comments that you'll have to stall the pipeline, so of course you need more wires to do it. You will also need to reset the pipeline sometimes, this is the purpose of the rst signal.
However, more signals means more silicon surface (or more FPGA resources using) which generally come with a greater price. One can argue that only one or two wires will not makes such great difference for a chip, which is true, but if you re-use your pipeline thousand times on the circuit it will be much more significant.
For me the first implementation can be relevant only with really strong optimization requirements at circuit level like for an ASIC, where you exactly know the overall wanted behavior.

Synthesizable Verilog modular shift register

I'm doing a LOTTT of pipelining with varying width signals and wanted a SYNTHESIZEABLE module wherein i could pass 2 parameters : 1) number of pipes (L) and 2) width of signal (W).
That way i just have to instantiate the module and pass 2 values which is so much simple and robust than typing loads and loads of signal propagation via dummy registers...prone to errors and et all.
I have HALF written the verilog code , kindly request you to correct me if i am wrong.
I AM FACING COMPILE ERROR ... SEE COMMENTS
*****************************************************************
PARTIAL VERILOG CODE FOR SERIAL IN SERIAL OUT SHIFT REGISTER WITH
1) Varying number of shifts / stages : L
2) Varying number of signal / register width : W
*****************************************************************
module SISO (clk, rst, Serial_in, Serial_out); // sIn -> [0|1|2|3|...|L-1] -> sOut
parameter L = 60; // Number of stages
parameter W = 60; // Width of Serial_in / Serial_out
input clk,rst;
input reg Serial_in;
output reg Serial_out;
// reg [L-1:0][W-1:0] R;
reg [L-1:0] R; // Declare a register which is L bit long
always #(posedge clk or posedge rst)
begin
if (rst) // Reset = active high
//**********************
begin
R[0] <= 'b0; // Exceptional case : feeding input to pipe
Serial_out <= 'b0; // Exceptional case : vomiting output from pipe
genvar j;
for(j = 1; j<= L; j=j+1) // Ensuring ALL registers are reset when rst = 1
begin : rst_regs // Block name = reset_the_registers
R[L] <= 'b0; // Verilog automatically assumes destination width # just using 'b0
end
end
else
//**********************
begin
generate
genvar i;
for(i = 1; i< L; i=i+1)
begin : declare_reg
R[0] <= Serial_in; // <---- COMPILE ERROR POINTED HERE
R[L] <= R[L-1];
Serial_out <= R[L-1];
end
endgenerate;
end
//**********************
endmodule
//**********************
Why so complicated? The following code would be much simpler and easier to understand:
module SISO #(
parameter L = 60, // Number of stages (1 = this is a simple FF)
parameter W = 60 // Width of Serial_in / Serial_out
) (
input clk, rst,
input [W-1:0] Serial_in,
output [W-1:0] Serial_out
);
reg [L*W-1:0] shreg;
always #(posedge clk) begin
if (rst)
shreg <= 0;
else
shreg <= {shreg, Serial_in};
end
assign Serial_out = shreg[L*W-1:(L-1)*W];
endmodule
However, looking at your code there are the following problems:
You declare Serial_in as input reg. This is not possible, an input cannot be a reg.
You are using generate..endgenerate within an always block. A generate block is a module item and cannot be used in an always block. Simply remove the generate and endgenerate statements and declare i as integer.
Obviously Serial_in and Serial_out must be declared as vectors of size [W-1:0].
You are using R as a memory. Declare it as such: reg [W-1:0] R [0:L-1].
You are not using i in you for loop. Obviously you meant to chain all the elements of R together, but you are just accessing the 0th, (L-1)th and Lth element. (Obviously the Lth element is nonexisting, this array would be going from 0 to L-1.
I'm now stopping writing this list because, I'm sorry, I think there really is not much to gain by improving the code you have posted..

Lattice iCE40-HX8K Board - UART

I have the following verilog code for my Lattice iCE40-HX8K Board:
uart.v:
module uart(input clk, output TXD);
reg [3:0] count;
reg [9:0] data;
reg z;
initial begin
data[9:0] = 10'b1000000000; // Startbit = 1, Stopbit = 0
z = 0;
end
always#(posedge clk)
begin
if(count == 1250) //9600x per Second (1250) = Baudrate
begin
count <= 0;
TXD = data[z];
z = z + 1;
if(z == 10)
begin
z = 0;
end
else
begin
end
end
else
begin
count <= count + 1;
end
end
endmodule
For receiving the UART-Data I use gtkterm under Ubuntu 14.04.
I have set the baudrate in gtkterm to 9600.
If I now program my FPGA with the code I receive once per programming a
hex "00" (irrespective of the 8 usage-bits).
Can anybody give me a hint what is wrong?
Thank you for your support.
There are at least two obvious problems with your design:
Your count is only 4 bits wide, thus it cannot count to 1250. It must be at least 11 bits wide to be able to count to 1250.
Also your z is only 1 bit wide, so it can only hold the values 0 and 1. It must be at least 4 bits wide to be able to count to 10.
You should also read up on blocking vs. non-blocking assignments. The way you use blocking assignments in sequential logic can lead to race conditions in the verilog simulation model.
You should always write testbenches for your HDL code and simulate it before trying to run it in hardware. A testbench for your design would be as easy as:
module uart_testbench;
reg clk = 1;
always #5 clk = ~clk;
uart uut (
.clk(clk)
);
initial begin
$dumpfile("uart.vcd");
$dumpvars(0, uut);
repeat (1000000) #(posedge clk);
$finish;
end
endmodule

My verilog VGA driver causes the screen to flicker (Basys2)

I'm trying to recreate Adventure(1979) in Verilog and so far I have character movement, collision and map generation done. It didn't flicker that much before I separated the maps into modules now it flickers constantly. When I was looking up this issue, I found out that the clock on the Basys2 board is pretty noisy and could be the culprit. However, putting the maps into modules shouldn't have made it worse unless I messed something up. Any idea what happened?
Here's my map generator:
module map_generator(clk_vga, reset, CurrentX, CurrentY, HBlank, VBlank, playerPosX, playerPosY, mapData
);
input clk_vga;
input reset;
input [9:0]CurrentX;
input [8:0]CurrentY;
input HBlank;
input VBlank;
input [9:0]playerPosX;
input [8:0]playerPosY;
output [7:0]mapData;
reg [7:0]mColor;
reg [5:0]currentMap = 0;
wire [7:0]startCastle;
StartCastle StartCastle(
.clk_vga(clk_vga),
.CurrentX(CurrentX),
.CurrentY(CurrentY),
.mapData(startCastle)
);
always #(posedge clk_vga) begin
if(reset)begin
currentMap <= 0;
end
end
always #(posedge clk_vga) begin
if(HBlank || VBlank) begin
mColor <= 0;
end
else begin
if(currentMap == 4'b0000) begin
mColor[7:0] <= startCastle[7:0];
end
//Add more maps later
end
end
assign mapData[7:0] = mColor[7:0];
endmodule
Here's the startCastle:
module StartCastle(clk_vga, CurrentX, CurrentY, active, mapData);
input clk_vga;
input [9:0]CurrentX;
input [8:0]CurrentY;
input active;
output [7:0]mapData;
reg [7:0]mColor;
always #(posedge clk_vga) begin
if(CurrentY < 40) begin
mColor[7:0] <= 8'b11100000;
end
else if(CurrentX < 40) begin
mColor[7:0] <= 8'b11100000;
end
else if(~(CurrentX < 600)) begin
mColor[7:0] <= 8'b11100000;
end
else if((~(CurrentY < 440) && (CurrentX < 260)) || (~(CurrentY < 440) && ~(CurrentX < 380))) begin
mColor[7:0] <= 8'b11100000;
end else
mColor[7:0] <= 8'b00011100;
end
assign mapData = mColor;
endmodule
Here's the VGA driver which is connected to my top module:
module vga_driver(clk_50MHz, vs_vga, hs_vga, RED, GREEN, BLUE, HBLANK, VBLANK, CURX, CURY, COLOR, CLK_DATA, RESET);
input clk_50MHz;
output vs_vga;
output hs_vga;
output [2:0] RED;
output [2:0] GREEN;
output [1:0] BLUE;
output HBLANK;
output VBLANK;
reg VS = 0;
reg HS = 0;
input RESET;
//current client data
input [7:0] COLOR;
output CLK_DATA;
output [9:0] CURX;
output [8:0] CURY;
//##### Module constants (http://tinyvga.com/vga-timing/640x480#60Hz)
parameter HDisplayArea = 640; // horizontal display area
parameter HLimit = 800; // maximum horizontal amount (limit)
parameter HFrontPorch = 16; // h. front porch
parameter HBackPorch = 48; // h. back porch
parameter HSyncWidth = 96; // h. pulse width
parameter VDisplayArea = 480; // vertical display area
parameter VLimit = 525; // maximum vertical amount (limit)
parameter VFrontPorch = 10; // v. front porch
parameter VBackPorch = 33; // v. back porch
parameter VSyncWidth = 2; // v. pulse width
//##### Local variables
wire clk_25MHz;
reg [9:0] CurHPos = 0; //maximum of HLimit (2^10 - 1 = 1023)
reg [9:0] CurVPos = 0; //maximum of VLimit
reg HBlank_reg, VBlank_reg, Blank = 0;
reg [9:0] CurrentX = 0; //maximum of HDisplayArea
reg [8:0] CurrentY = 0; //maximum of VDisplayArea (2^9 - 1 = 511)
//##### Submodule declaration
clock_divider clk_div(.clk_in(clk_50MHz), .clk_out(clk_25MHz));
//shifts the clock by half a period (negates it)
//see timing diagrams for a better understanding of the reason for this
clock_shift clk_shift(.clk_in(clk_25MHz), .clk_out(CLK_DATA));
//simulate the vertical and horizontal positions
always #(posedge clk_25MHz) begin
if(CurHPos < HLimit-1) begin
CurHPos <= CurHPos + 1;
end
else begin
CurHPos <= 0;
if(CurVPos < VLimit-1)
CurVPos <= CurVPos + 1;
else
CurVPos <= 0;
end
if(RESET) begin
CurHPos <= 0;
CurVPos <= 0;
end
end
//##### VGA Logic (http://tinyvga.com/vga-timing/640x480#60Hz)
//HSync logic
always #(posedge clk_25MHz)
if((CurHPos < HSyncWidth) && ~RESET)
HS <= 1;
else
HS <= 0;
//VSync logic
always #(posedge clk_25MHz)
if((CurVPos < VSyncWidth) && ~RESET)
VS <= 1;
else
VS <= 0;
//Horizontal logic
always #(posedge clk_25MHz)
if((CurHPos >= HSyncWidth + HFrontPorch) && (CurHPos < HSyncWidth + HFrontPorch + HDisplayArea) || RESET)
HBlank_reg <= 0;
else
HBlank_reg <= 1;
//Vertical logic
always #(posedge clk_25MHz)
if((CurVPos >= VSyncWidth + VFrontPorch) && (CurVPos < VSyncWidth + VFrontPorch + VDisplayArea) || RESET)
VBlank_reg <= 0;
else
VBlank_reg <= 1;
//Do not output any color information when we are in the vertical
//or horizontal blanking areas. Set a boolean to keep track of this.
always #(posedge clk_25MHz)
if((HBlank_reg || VBlank_reg) && ~RESET)
Blank <= 1;
else
Blank <= 0;
//Keep track of the current "real" X position. This is the actual current X
//pixel location abstracted away from all the timing details
always #(posedge clk_25MHz)
if(HBlank_reg && ~RESET)
CurrentX <= 0;
else
CurrentX <= CurHPos - HSyncWidth - HFrontPorch;
//Keep track of the current "real" Y position. This is the actual current Y
//pixel location abstracted away from all the timing details
always #(posedge clk_25MHz)
if(VBlank_reg && ~RESET)
CurrentY <= 0;
else
CurrentY <= CurVPos - VSyncWidth - VFrontPorch;
assign CURX = CurrentX;
assign CURY = CurrentY;
assign VBLANK = VBlank_reg;
assign HBLANK = HBlank_reg;
assign hs_vga = HS;
assign vs_vga = VS;
//Respects VGA Blanking areas
assign RED = (Blank) ? 3'b000 : COLOR[7:5];
assign GREEN = (Blank) ? 3'b000 : COLOR[4:2];
assign BLUE = (Blank) ? 2'b00 : COLOR[1:0];
endmodule
clk_div:
module clock_divider(clk_in, clk_out);
input clk_in;
output clk_out;
reg clk_out = 0;
always #(posedge clk_in)
clk_out <= ~clk_out;
endmodule
clk_shift:
module clock_shift(clk_in, clk_out);
input clk_in;
output clk_out;
assign clk_out = ~clk_in;
endmodule
I'm posting this as an answer because I cannot put a photo in a comment.
Is this what your design looks like?
My only guess ATM is that you might have misplaced some ports during instantiation of vga_driver and/or map_generator (if you used the old style instantiation). Nevertheless, I'm going to check VGA timmings, as I can see a strange vertical line at the left of the screen, as if the hblank interval was visible.
By the way: I've changed the way you generate the display. You use regs for HS, VS, etc, which get updated the next clock cycle. I treat display generation as a FSM, so outputs come from combinational blocks triggered by certain values (or range of values) from the counters. Besides, I start horizontal and vertical counters so position (0,0) measured in pixel coordinates in the screen actually maps to values (0,0) from horizontal and vertical counters, so no arithmetic needed.
This is my version of VGA display generation:
module videosyncs (
input wire clk,
input wire [2:0] rin,
input wire [2:0] gin,
input wire [1:0] bin,
output reg [2:0] rout,
output reg [2:0] gout,
output reg [1:0] bout,
output reg hs,
output reg vs,
output wire [10:0] hc,
output wire [10:0] vc
);
/* http://www.abramovbenjamin.net/calc.html */
// VGA 640x480#60Hz,25MHz
parameter htotal = 800;
parameter vtotal = 524;
parameter hactive = 640;
parameter vactive = 480;
parameter hfrontporch = 16;
parameter hsyncpulse = 96;
parameter vfrontporch = 11;
parameter vsyncpulse = 2;
parameter hsyncpolarity = 0;
parameter vsyncpolarity = 0;
reg [10:0] hcont = 0;
reg [10:0] vcont = 0;
reg active_area;
assign hc = hcont;
assign vc = vcont;
always #(posedge clk) begin
if (hcont == htotal-1) begin
hcont <= 0;
if (vcont == vtotal-1) begin
vcont <= 0;
end
else begin
vcont <= vcont + 1;
end
end
else begin
hcont <= hcont + 1;
end
end
always #* begin
if (hcont>=0 && hcont<hactive && vcont>=0 && vcont<vactive)
active_area = 1'b1;
else
active_area = 1'b0;
if (hcont>=(hactive+hfrontporch) && hcont<(hactive+hfrontporch+hsyncpulse))
hs = hsyncpolarity;
else
hs = ~hsyncpolarity;
if (vcont>=(vactive+vfrontporch) && vcont<(vactive+vfrontporch+vsyncpulse))
vs = vsyncpolarity;
else
vs = ~vsyncpolarity;
end
always #* begin
if (active_area) begin
gout = gin;
rout = rin;
bout = bin;
end
else begin
gout = 3'h00;
rout = 3'h00;
bout = 2'h00;
end
end
endmodule
Which is instantiated by your vga_driver module, which becomes nothing but a wrapper for this module:
module vga_driver (
input wire clk_25MHz,
output wire vs_vga,
output wire hs_vga,
output wire [2:0] RED,
output wire [2:0] GREEN,
output wire [1:0] BLUE,
output wire HBLANK,
output wire VBLANK,
output [9:0] CURX,
output [8:0] CURY,
input [7:0] COLOR,
input wire RESET
);
assign HBLANK = 0;
assign VBLANK = 0;
videosyncs syncgen (
.clk(clk_25MHz),
.rin(COLOR[7:5]),
.gin(COLOR[4:2]),
.bin(COLOR[1:0]),
.rout(RED),
.gout(GREEN),
.bout(BLUE),
.hs(hs_vga),
.vs(vs_vga),
.hc(CURX),
.vc(CURY)
);
endmodule
Note that in map_generator, the first if statement in this always block will never be true. We can forget about it, as the VGA display module will blank RGB outputs when needed.
always #(posedge clk_vga) begin
if(HBlank || VBlank) begin //
mColor <= 0; // Never reached
end //
else begin //
if(currentMap == 4'b0000) begin
mColor[7:0] <= startCastle[7:0];
end
//Add more maps later
end
end
Using the same approach, I've converted the map generator module to be a combinational module. For example, for map 0 (the castle -without the castle, I see-) it is like this:
module StartCastle(
input wire [9:0] CurrentX,
input wire [8:0] CurrentY,
output wire [7:0] mapData
);
reg [7:0] mColor;
assign mapData = mColor;
always #* begin
if(CurrentY < 40) begin
mColor[7:0] <= 8'b11100000;
end
else if(CurrentX < 40) begin
mColor[7:0] <= 8'b11100000;
end
else if(~(CurrentX < 600)) begin
mColor[7:0] <= 8'b11100000;
end
else if((~(CurrentY < 440) && (CurrentX < 260)) || (~(CurrentY < 440) && ~(CurrentX < 380))) begin
mColor[7:0] <= 8'b11100000;
end else
mColor[7:0] <= 8'b00011100;
end
endmodule
Just a FSM whose output is the colour that goes in a pixel. The input being the coordinates of the current pixel.
So when it is time to display map 0, map_generator simply switches to it based upon the current value of currentMap
module map_generator (
input wire clk,
input wire reset,
input wire [9:0]CurrentX,
input wire [8:0]CurrentY,
input wire HBlank,
input wire VBlank,
input wire [9:0]playerPosX,
input wire [8:0]playerPosY,
output wire [7:0]mapData
);
reg [7:0] mColor;
assign mapData = mColor;
reg [5:0]currentMap = 0;
wire [7:0] castle_map;
StartCastle StartCastle(
.CurrentX(CurrentX),
.CurrentY(CurrentY),
.mapData(castle_map)
);
always #(posedge clk) begin
if(reset) begin
currentMap <= 0;
end
end
always #* begin
if(currentMap == 6'b000000) begin
mColor = castle_map;
end
//Add more maps later
end
endmodule
This may look like a lot of comb logic is generated and so glitches may happen. It's actually very fast, no noticeable glitches on screen, and you can use the actual current x and y coordinates to choose what to display on screen. Thus, no need for an inverted clock. My final version of your design has only one 25MHz clock.
By the way, you want to keep device dependent constructions away from your design, placing things like clock generators in separate modules that will be connected to your design in the top module, which should be the only device dependent module.
So, I've written a device-agnostic adventure module, which will contain the entire game:
module adventure (
input clk_vga,
input reset,
output vs_vga,
output hs_vga,
output [2:0] RED,
output [2:0] GREEN,
output [1:0] BLUE
);
wire HBLANK, VBLANK;
wire [7:0] COLOR;
wire [9:0] CURX;
wire [8:0] CURY;
wire [9:0] playerPosX = 10'd320; // no actually used in the design yet
wire [8:0] playerPosY = 9'd240; // no actually used in the design yet
vga_driver the_screen (.clk_25MHz(clk_vga),
.vs_vga(vs_vga),
.hs_vga(hs_vga),
.RED(RED),
.GREEN(GREEN),
.BLUE(BLUE),
.HBLANK(HBLANK),
.VBLANK(VBLANK),
.CURX(CURX),
.CURY(CURY),
.COLOR(COLOR)
);
map_generator the_mapper (.clk(clk_vga),
.reset(reset),
.CurrentX(CURX),
.CurrentY(CURY),
.HBlank(HBLANK),
.VBlank(VBLANK),
.playerPosX(playerPosX),
.playerPosY(playerPosY),
.mapData(COLOR)
);
endmodule
This module is not complete: it lacks inputs from joystick or any other input device to update player current position. For now, player current position is fixed.
The top level design (TLD) is written exclusively for the FPGA trainer you have. It is here where you need to generate proper clocks using your device's available resources, such as the DCM in Spartan 3/3E devices.
module tld_basys(
input wire clk_50MHz,
input wire RESET,
output wire vs_vga,
output wire hs_vga,
output wire [2:0] RED,
output wire [2:0] GREEN,
output wire [1:0] BLUE
);
wire clk_25MHz;
dcm_clocks gen_vga_clock (
.CLKIN_IN(clk_50MHz),
.CLKDV_OUT(clk_25MHz)
);
adventure the_game (.clk_vga(clk_25MHz),
.reset(RESET),
.vs_vga(vs_vga),
.hs_vga(hs_vga),
.RED(RED),
.GREEN(GREEN),
.BLUE(BLUE)
);
endmodule
The DCM generated clocks goes in this module (generated by the Xilinx Core Generator)
module dcm_clocks (CLKIN_IN,
CLKDV_OUT
);
input CLKIN_IN;
output CLKDV_OUT;
wire CLKFB_IN;
wire CLKFX_BUF;
wire CLKDV_BUF;
wire CLKIN_IBUFG;
wire CLK0_BUF;
wire GND_BIT;
assign GND_BIT = 0;
BUFG CLKDV_BUFG_INST (.I(CLKDV_BUF),
.O(CLKDV_OUT));
IBUFG CLKIN_IBUFG_INST (.I(CLKIN_IN),
.O(CLKIN_IBUFG));
BUFG CLK0_BUFG_INST (.I(CLK0_BUF),
.O(CLKFB_IN));
DCM_SP #(.CLKDV_DIVIDE(2.0), .CLKIN_DIVIDE_BY_2("FALSE"),
.CLKIN_PERIOD(20.000), .CLKOUT_PHASE_SHIFT("NONE"),
.DESKEW_ADJUST("SYSTEM_SYNCHRONOUS"), .DFS_FREQUENCY_MODE("LOW"),
.DLL_FREQUENCY_MODE("LOW"), .DUTY_CYCLE_CORRECTION("TRUE"),
.FACTORY_JF(16'hC080), .PHASE_SHIFT(0), .STARTUP_WAIT("FALSE") )
DCM_SP_INST (.CLKFB(CLKFB_IN),
.CLKIN(CLKIN_IBUFG),
.DSSEN(GND_BIT),
.PSCLK(GND_BIT),
.PSEN(GND_BIT),
.PSINCDEC(GND_BIT),
.RST(GND_BIT),
.CLKDV(CLKDV_BUF),
.CLKFX(),
.CLKFX180(),
.CLK0(CLK0_BUF),
.CLK2X(),
.CLK2X180(),
.CLK90(),
.CLK180(),
.CLK270(),
.LOCKED(),
.PSDONE(),
.STATUS());
endmodule
Although it is safe (for Xilinx devices) to use a simple clock divider as you did. If you fear that the synthesizer won't treat your divided clock as an actual clock, add a BUFG primitive to route the output from the divider to a global buffer so it can be used as a clock with no problems (see the module above for an example on how to do this).
As a final note, you may want to add more independency from the final device, by using 24-bit colours for your graphics. At the TLD, you will use the actual number of bits per colour component you really have, but if you move from the Basys2 with 8-bit colour trainer board to the, say, Nexys4 board, with 12-bit colour, you will automatically enjoy a richer output display.
Now, it looks like this (no vertical bars at the left, and colours seem to be more vibrant)

Resources