Page 30 of 41
Re: Concept & Design of 3.3V Parallel 16-bit VGA Boards
Posted: Sat Apr 13, 2013 9:38 pm
by ElEctric_EyE
Very cool. I read in the WIKI that flipping the x & y coordinated before input then flipping them back on output is used in hardware frequently. That would essential flip DX and DY...
I have code for the 1st quadrant... I tried to throw in some comments. When DX >= DY, use the formula on the wiki. When DY>DX, swapping DX and DY for all the calculations works. This code was abit more challenging and there's probably a more efficient way to do it. I'm posting my code in case something happens to my computer. BTW it will plot vertical and horizontal lines without extra checking.
Code: Select all
module LineGen ( input clk,
output reg [9:0] X = 0, //LSB of RAM address
output reg [8:0] Y = 0 //MSB of RAM address
);
reg [9:0] x0, x1, dx; //internal module registers
reg [8:0] y0, y1, dy;
reg [16:0] D; //error accumulator + carry bit. if D[16] = 1, it is negative
reg steep; //this will be a '1' when dy>dx
reg [3:0] state;
parameter LOAD = 0, DXDY = 1, CALC1 = 2, CALC2 = 3, PLOT = 4;
always @(posedge clk) begin
state <= LOAD;
case (state)
LOAD: //load register values
state <= DXDY; //go on to the next state
DXDY: //calculate dx & dy and plot initial (x0,y0) coordinates
state <= CALC1; //go on to the next state
CALC1: //calculate 'D' for dy>dx and dx>=dy
state <= CALC2; //go on to next state
CALC2: //use 'steep' to determine if dx/dy swapping is necessary
state <= PLOT; //go on to next state
PLOT:
if (steep) begin
if (y0 + 1 <= y1)
state <= CALC2;
else state <= LOAD;
end
else begin
if (x0 + 1 <= x1)
state <= CALC2;
else state <= LOAD;
end
endcase
end
always @(posedge clk) begin
case (state)
LOAD: //1st clk: load values into (x0,y0) & (x1,y1)
begin
x0 <= 0;
y0 <= 0;
x1 <= 10;
y1 <= 0;
end
DXDY: //2nd clk: figure dx & dy, output initial coordinates: (x0,y0)
begin
dx <= x1 - x0;
dy <= y1 - y0;
X <= x0;
Y <= y0; //plot first coordinate before changing x0 & y0.
end
CALC1: //3rd clk: based on dx and dy, start swapping dx and dy within the error accumulator
if (dx >= dy) begin //if dy>dx, swap dx and dy
steep <= 0;
D <= (dy*2 - dx); //calculate the initial error value when x is the greater axis
end
else begin
steep <= 1;
D <= (dx*2 - dy); //calculate the initial error value when y is the greater axis
end
CALC2: //4th clk: after error is calculated, perform the x,y advance based on the error accumulator
if (steep) begin //if dy>dx, swap dx and dy
if ( D[16] == 0 ) begin //test for when error accumulator is negative value
x0 <= x0 + 1; //then
y0 <= y0 + 1; //go diagonal
D <= D + (dx*2 - dy*2); //accumulate the error
end
else begin
y0 <= y0 + 1; //increment on the greater axis
D <= D + dx*2;
end
end
else if ( D[16] == 0 ) begin //dx>dy here: test for when error accumulator is negative value
x0 <= x0 + 1; //then
y0 <= y0 + 1; //go diagonal
D <= D + (dy*2 - dx*2); //accumulate the error
end
else begin
x0 <= x0 + 1; //increment on the greater axis
D <= D + dy*2;
end
PLOT: //5th clk: output values
begin
X <= x0;
Y <= y0;
end
endcase
end
endmodule
Re: Concept & Design of 3.3V Parallel 16-bit VGA Boards
Posted: Sun Apr 14, 2013 10:00 pm
by ElEctric_EyE
There is one thing left I'm in the process of completing and that is the case of an opposite slope, e.g. (0,10) to (10,0) where the dy is negative since the plotting is being done left to right in all instances. Once this is done, all other possible combinations will just require a swapping of start/endpoints. Although I have already tried 2x and gave up. I will re-study what I've done successfully up to this point, make some notes and then maybe start from scratch, althought I have 1 more idea to try tonight involving the current code.
Re: Concept & Design of 3.3V Parallel 16-bit VGA Boards
Posted: Mon Apr 15, 2013 12:57 am
by ElEctric_EyE
Success! 1 case left to consider: -dy, steep. -dy, !steep works.:
Code: Select all
module LineGen ( input clk,
output reg [9:0] X = 0, //LSB of RAM address
output reg [8:0] Y = 0 //MSB of RAM address
);
reg [9:0] x0, x1, dx; //internal module registers
reg [8:0] y0, y1, dy;
reg [16:0] D; //error accumulator + carry bit. if D[16] = 1, it is negative
reg steep; //1 when dy>dx
reg dyneg; //1 when dy is negative
reg [2:0] state;
parameter LOAD = 0, DXDY = 1, CALC1 = 2, CALC2 = 3, PLOT = 4;
always @(posedge clk) begin
state <= LOAD;
case (state)
LOAD:
state <= DXDY;
DXDY:
state <= CALC1;
CALC1:
state <= CALC2;
CALC2:
state <= PLOT;
PLOT:
begin
if (!dyneg && steep) begin //e.g. (0,0) to (2,10)
if (y0 + 1 <= y1)
state <= CALC2;
else state <= LOAD;
end
if (!dyneg && !steep) begin //e.g. (0,0) to (10,10)
if (x0 + 1 <= x1)
state <= CALC2;
else state <= LOAD;
end
if (dyneg && !steep) begin //e.g. (0,10) to (10,0)
if (y1 != y0)
state <= CALC2;
else state <= LOAD;
end
end
endcase
end
always @(posedge clk) begin
case (state)
LOAD:
begin
x0 <= 0;
y0 <= 0;
x1 <= 20;
y1 <= 20;
if (y0 >= y1)
dyneg <= 1;
else dyneg <= 0;
end
DXDY:
begin
dx <= x1 - x0;
X <= x0;
Y <= y0;
if (dyneg)
dy <= y0 - y1;
else dy <= y1 - y0;
end
CALC1:
if (dx >= dy) begin
steep <= 0;
D <= (dy*2 - dx);
end
else begin
steep <= 1;
D <= (dx*2 - dy);
end
CALC2:
if (steep) begin
if ( D[16] == 0 ) begin
x0 <= x0 + 1;
y0 <= y0 + 1;
D <= D + (dx*2 - dy*2);
end
else begin
y0 <= y0 + 1;
D <= D + dx*2;
end
end
else if ( D[16] == 0 ) begin
x0 <= x0 + 1;
y0 <= dyneg ? y0 - 1:
y0 + 1;
D <= D + (dy*2 - dx*2);
end
else begin
x0 <= x0 + 1;
D <= D + dy*2;
end
PLOT:
begin
X <= x0;
Y <= y0;
end
endcase
end
endmodule
Re: Concept & Design of 3.3V Parallel 16-bit VGA Boards
Posted: Mon Apr 15, 2013 11:37 am
by ElEctric_EyE
I couldn't reliably test for dyneg in the LOAD state, so I had to add 1 more state, which doesn't really slow things down any as the main loop is still CALC2 --> PLOT --> CALC2... Plus a minor correction or two. Hopefully I can get this finished today so I can start working on melding it to the project. I'm optimistic this LineGen module coding is tight because top speed of the module itself has not changed since the beginning stage, @180MHz... So far these coordinates work in ISim:
Code: Select all
(0,0) to (20,20)
(0,20) to (20,0)
(0,0) to (20,2)
(0,0) to (2,20)
Code: Select all
module LineGen ( input clk,
output reg [9:0] X = 0, //LSB of RAM address
output reg [8:0] Y = 0 //MSB of RAM address
);
reg [9:0] x0, x1, dx; //internal module registers
reg [8:0] y0, y1, dy;
reg [16:0] D; //error accumulator + carry bit. if D[16] = 1, it is negative
reg steep; //1 when dy>dx
reg dyneg; //1 when dy is negative
reg [2:0] state;
parameter LOAD = 0, SLOPE = 1, DXDY = 2, CALC1 = 3, CALC2 = 4, PLOT = 5;
always @(posedge clk) begin
state <= LOAD;
case (state)
LOAD:
state <= SLOPE;
SLOPE:
state <= DXDY;
DXDY:
state <= CALC1;
CALC1:
state <= CALC2;
CALC2:
state <= PLOT;
PLOT:
begin
if (!dyneg && steep) begin //e.g. (0,0) to (2,10)
if (y0 != y1)
state <= CALC2;
else state <= LOAD;
end
if (!dyneg && !steep) begin //e.g. (0,0) to (10,10)
if (x0 != x1)
state <= CALC2;
else state <= LOAD;
end
if (dyneg) begin //e.g. (0,10) to (10,0)
if (y1 != y0)
state <= CALC2;
else state <= LOAD;
end
end
endcase
end
always @(posedge clk) begin
case (state)
LOAD:
begin
x0 <= 0;
y0 <= 0;
x1 <= 2;
y1 <= 20;
end
SLOPE:
if (y0 > y1)
dyneg <= 1;
else dyneg <= 0;
DXDY:
begin
dx <= x1 - x0;
X <= x0;
Y <= y0;
if (dyneg)
dy <= y0 - y1;
else dy <= y1 - y0;
end
CALC1:
if (dx >= dy) begin
steep <= 0;
D <= (dy*2 - dx);
end
else begin
steep <= 1;
D <= (dx*2 - dy);
end
CALC2:
if (steep) begin
if ( D[16] == 0 ) begin
x0 <= x0 + 1;
y0 <= dyneg ? y0 - 1:
y0 + 1;
D <= D + (dx*2 - dy*2);
end
else begin
y0 <= dyneg ? y0 - 1:
y0 + 1;
D <= D + dx*2;
end
end
else if ( D[16] == 0 ) begin
x0 <= x0 + 1;
y0 <= dyneg ? y0 - 1:
y0 + 1;
D <= D + (dy*2 - dx*2);
end
else begin
x0 <= x0 + 1;
D <= D + dy*2;
end
PLOT:
begin
X <= x0;
Y <= y0;
end
endcase
end
endmodule
Re: Concept & Design of 3.3V Parallel 16-bit VGA Boards
Posted: Mon Apr 15, 2013 12:05 pm
by BitWise
Are you drawing the last pixel in the lines you are generating?
Its quite common not to plot the last pixel so that vertices are not double drawn when ploting a succession of lines around a polygon, especially if the pixel values are being XOR'd into display memory.
Re: Concept & Design of 3.3V Parallel 16-bit VGA Boards
Posted: Tue Apr 16, 2013 1:05 am
by ElEctric_EyE
Are you drawing the last pixel in the lines you are generating?
Its quite common not to plot the last pixel so that vertices are not double drawn when ploting a succession of lines around a polygon, especially if the pixel values are being XOR'd into display memory.
Hi Bitwise! No to your first question... And, I'll remember that pointer about the vertices because I believe the code is complete and real world testing is about to start.
Sorry about the lack of comments, but reading over my last post of the code with comments just seemed pretentious, also it was confusing me because the code was still changing. I guess comments should be saved for last!
My code seems to work for any numbers I throw at it, for the Start/End coordinates. Please let me know if anyone sees a problem.
Code: Select all
module LineGen ( input clk,
output reg [9:0] X = 0, //LSB of RAM address
output reg [8:0] Y = 0 //MSB of RAM address
);
reg [9:0] x0, x1, dx; //internal module registers
reg [8:0] y0, y1, dy;
reg [16:0] D; //error accumulator + carry bit. if D[16] = 1, it is negative
reg steep; //1 when dy>dx
reg dyneg; //1 when dy is negative
reg [2:0] state;
parameter LOAD = 0, SLOPE = 1, DXDY = 2, CALC1 = 3, CALC2 = 4, PLOT = 5;
always @(posedge clk) begin
state <= LOAD;
case (state)
LOAD:
state <= SLOPE;
SLOPE:
state <= DXDY;
DXDY:
state <= CALC1;
CALC1:
state <= CALC2;
CALC2:
state <= PLOT;
PLOT:
begin
if (!dyneg && steep) //e.g. (0,0) to (2,10)
if (y0 != y1)
state <= CALC2;
else state <= LOAD;
if (!dyneg && !steep) //e.g. (0,0) to (10,10)
if (x0 != x1)
state <= CALC2;
else state <= LOAD;
if (dyneg && !steep) //e.g. (0,10) to (10,0)
if (x0 != x1)
state <= CALC2;
else state <= LOAD;
if (dyneg && steep) //e.g. (0,20) to (2,0)
if (y0 != y1)
state <= CALC2;
else state <= LOAD;
end
endcase
end
always @(posedge clk) begin
case (state)
LOAD:
begin
x0 <= 0;
y0 <= 20;
x1 <= 2;
y1 <= 0;
end
SLOPE:
if (y0 > y1)
dyneg <= 1;
else dyneg <= 0;
DXDY:
begin
dx <= x1 - x0;
X <= x0;
Y <= y0;
if (dyneg)
dy <= y0 - y1;
else dy <= y1 - y0;
end
CALC1:
if (dx >= dy) begin
steep <= 0;
D <= (dy*2 - dx);
end
else begin
steep <= 1;
D <= (dx*2 - dy);
end
CALC2:
if (steep) begin
if ( D[16] == 0 ) begin
x0 <= x0 + 1;
y0 <= dyneg ? y0 - 1:
y0 + 1;
D <= D + (dx*2 - dy*2);
end
else begin
y0 <= dyneg ? y0 - 1:
y0 + 1;
D <= D + dx*2;
end
end
else if ( D[16] == 0 ) begin
x0 <= x0 + 1;
y0 <= dyneg ? y0 - 1:
y0 + 1;
D <= D + (dy*2 - dx*2);
end
else begin
x0 <= x0 + 1;
D <= D + dy*2;
end
PLOT:
begin
X <= x0;
Y <= y0;
end
endcase
end
endmodule
Re: Concept & Design of 3.3V Parallel 16-bit VGA Boards
Posted: Tue Apr 16, 2013 1:19 am
by ElEctric_EyE
Some info from the console:
Code: Select all
NFO:Xst:1767 - HDL ADVISOR - Resource sharing has identified that some arithmetic operations in this design can share the same physical resources for reduced device utilization. For improved clock frequency you may try to disable resource sharing.
Code: Select all
=========================================================================
Advanced HDL Synthesis Report
Macro Statistics
# Adders/Subtractors : 11
10-bit adder : 1
10-bit subtractor : 2
11-bit subtractor : 1
12-bit subtractor : 3
17-bit adder : 3
9-bit subtractor : 1
# Counters : 1
10-bit up counter : 1
# Registers : 80
Flip-Flops : 80
# Comparators : 4
10-bit comparator greater : 1
10-bit comparator not equal : 1
9-bit comparator greater : 1
9-bit comparator not equal : 1
# Multiplexers : 16
17-bit 2-to-1 multiplexer : 8
3-bit 2-to-1 multiplexer : 4
32-bit 2-to-1 multiplexer : 1
9-bit 2-to-1 multiplexer : 3
=========================================================================
Code: Select all
Asynchronous Control Signals Information:
----------------------------------------
No asynchronous control signals found in this design
Timing Summary:
---------------
Speed Grade: -3
Minimum period: 5.535ns (Maximum Frequency: 180.665MHz)
Minimum input arrival time before clock: No path found
Maximum output required time after clock: 3.597ns
Maximum combinational path delay: No path found
=========================================================================
Process "Synthesize - XST" completed successfully
Re: Concept & Design of 3.3V Parallel 16-bit VGA Boards
Posted: Tue Apr 16, 2013 9:58 pm
by ElEctric_EyE
Code: Select all
NFO:Xst:1767 - HDL ADVISOR - Resource sharing has identified that some arithmetic operations in this design can share the same physical resources for reduced device utilization. For improved clock frequency you may try to disable resource sharing.
Yesterday I tried disabling the 'resource sharing' as was suggested by the programmer(s) of ISE and max speed shot up to 220+MHz just for the module...
So, with confidence I could maintain 100MHz cpu speed, I applied this setting to my current project in the midst of adding in the LineGen module and was able to keep the cpu and all the other modules 4x speed above the 640x480 25MHz video generator module!
I have successfully drawn 4 lines using my LineGen state machine running @100MHz alongside the .b core. I have it set up so that it immediately starts plotting each time after the cpu has sent the last coordinate, i.e. 'y1'. The software sends x0, y0, x1, finally y1. I put a software delay in after sending the final y1 coordinate as I have not yet added in a DONE state to LineGen and it takes 2 cycles for each pixel to be plotted + another 4 cycles for each line total.
Just as I have tried to route the stack page and zero page pointers off cpu, I tried to do the same with the B accumulator, which I want dedicated to the pixel color. This part is not yet correct as the FPGA is writing '0's to the external SyncRAM instead of the B accumulator value that I can see in ISim correctly as a yellow value 'FFE4' (although it looks blue in the pic). More work is needed, but I am very pleased with the progress, and the Spartan6 product.
The 4 line coordinates are (swapping is still needed as not all coordinates functioned correctly):
Code: Select all
(0,0) to (320,240)
(320,240) to (639,0)
(320,240) to (639,479)
(0,479) to (320,240)
So in the name of the projects' progress I think I should post the LineGen, especially since it will be the last post on this page:
Code: Select all
`timescale 1ns / 1ps
module LineGen ( input clk,
input lineCS,
input [15:0] cpuDO,
input [1:0] cpuAB,
output reg RAMWE,
output reg [9:0] X,
output reg [8:0] Y
);
reg [9:0] x0, x1, dx, x0t, x1t; //internal module registers
reg [8:0] y0, y1, dy, y0t, y1t;
reg [16:0] D; //error accumulator + carry bit. if D[16] = 1, it is negative
reg steep; //1 when dy>dx
reg dyneg; //1 when dy is negative
reg [2:0] state;
parameter WAIT = 0, LOAD = 1, SLOPE = 2, DXDY = 3, CALC1 = 4, CALC2 = 5, PLOT = 6;
always @(posedge clk) begin
if (lineCS && cpuAB == 2'b00)
x0t <= cpuDO;
if (lineCS && cpuAB == 2'b01)
y0t <= cpuDO;
if (lineCS && cpuAB == 2'b10)
x1t <= cpuDO;
if (lineCS && cpuAB == 2'b11)
y1t <= cpuDO;
end
always @(posedge clk) begin
state <= WAIT;
case (state)
WAIT:
if (lineCS && cpuAB == 2'b11)
state <= LOAD;
else state <= WAIT;
LOAD:
state <= SLOPE;
SLOPE:
state <= DXDY;
DXDY:
state <= CALC1;
CALC1:
state <= CALC2;
CALC2:
state <= PLOT;
PLOT:
begin
if (!dyneg && steep) //e.g. (0,0) to (2,10)
if (y0 != y1)
state <= CALC2;
else state <= WAIT;
if (!dyneg && !steep) //e.g. (0,0) to (10,10)
if (x0 != x1)
state <= CALC2;
else state <= WAIT;
if (dyneg && !steep) //e.g. (0,10) to (10,0)
if (x0 != x1)
state <= CALC2;
else state <= WAIT;
if (dyneg && steep) //e.g. (0,20) to (2,0)
if (y0 != y1)
state <= CALC2;
else state <= WAIT;
end
endcase
end
always @(posedge clk) begin
case (state)
WAIT:
RAMWE <= 0;
LOAD:
begin
x0 <= x0t;
y0 <= y0t;
x1 <= x1t;
y1 <= y1t;
end
SLOPE:
if (y0 > y1)
dyneg <= 1;
else dyneg <= 0;
DXDY:
begin
dx <= x1 - x0;
RAMWE <= 1;
X <= x0;
Y <= y0;
if (dyneg)
dy <= y0 - y1;
else dy <= y1 - y0;
end
CALC1:
if (dx >= dy) begin
steep <= 0;
D <= (dy*2 - dx);
end
else begin
steep <= 1;
D <= (dx*2 - dy);
end
CALC2:
begin
RAMWE <= 0;
if (steep) begin
if ( D[16] == 0 ) begin
x0 <= x0 + 1;
y0 <= dyneg ? y0 - 1:
y0 + 1;
D <= D + (dx*2 - dy*2);
end
else begin
y0 <= dyneg ? y0 - 1:
y0 + 1;
D <= D + dx*2;
end
end
else if ( D[16] == 0 ) begin
x0 <= x0 + 1;
y0 <= dyneg ? y0 - 1:
y0 + 1;
D <= D + (dy*2 - dx*2);
end
else begin
x0 <= x0 + 1;
D <= D + dy*2;
end
end
PLOT:
begin
RAMWE <= 1;
X <= x0;
Y <= y0;
end
endcase
end
endmodule
Re: Concept & Design of 3.3V Parallel 16-bit VGA Boards
Posted: Wed Apr 17, 2013 1:01 pm
by ElEctric_EyE
I added in the check for when x0>x1, so now it'll plot any coordinate except when x0=x1=y0=y1. That's untested. I made a video of a test I did similar to the last video, except this one I had to slow down with a large delay between each line. You get to see my dog too, lol. You can tell it doesn't like being filmed. The delay is a 16x countdown from 65535 to 0, so over 1 million cycles. I still have to figure out why the RAM is getting zero's for the pixel value.
VIDEO
Re: Concept & Design of 3.3V Parallel 16-bit VGA Boards
Posted: Wed Apr 17, 2013 8:59 pm
by ElEctric_EyE
I figured it out, but the fix took just awhile longer. After I found the problem in the SRAM interface module, I had to figure out bus contention between when the cpu was sending data to RAM and the LineGen module was sending addresses with the intended data also coming from the cpu. In the end, it was easiest to make it so all pixel data comes from the B accumulator. I had to rewrite to clearscreen routine which was using the C accumulator for the background. Now it is working
apparently flawlessly. At one point I was stretching the RAMWE signal from the LineGen module with another case statement after the PLOT. I now see the value in CASE vs' IF statements. Using CASE one can control what happens in each and every cycle. Luckily the project still running at 100MHz, also without stretching the RAMWE signal. Whew!
Now I intend to do the line test by modifying it to clear the last line drawn. I would expect flickering, so then I am going to experiment with page flipping the videoRAM.
EDIT: There I go again making bold and grandiose statements.

I still have much to learn.
Re: Concept & Design of 3.3V Parallel 16-bit VGA Boards
Posted: Fri Apr 19, 2013 1:49 am
by ElEctric_EyE
So I have this code:
Code: Select all
always @(posedge clk) begin
if (lineCS && cpuAB == 2'b00)
x0t <= cpuDO;
if (lineCS && cpuAB == 2'b01)
y0t <= cpuDO;
if (lineCS && cpuAB == 2'b10)
x1t <= cpuDO;
if (lineCS && cpuAB == 2'b11)
y1t <= cpuDO;
end
that I would like to make into a parallel case statement. In a regular case statement each case is tested on the consecutive clocks. A parallel case considers each case at the same time which I need here. I've read all that is needed is a comment that is directed to the synthesizer. Is this true?
I'm trying to convert to case in order to compare resources used and also see the differences in what the console outputs.
Re: Concept & Design of 3.3V Parallel 16-bit VGA Boards
Posted: Fri Apr 19, 2013 5:31 am
by Arlet
You don't have to worry about the case statement. Every case is always tested on every clock. The difference between a "parallel" case, and a regular one, is that the parallel case does not have overlapping case expressions. Overlapping case expressions can lead to priority encoding, which can require more logic to implement. Note that you can only have overlapping case expressions if you use casez/casex.
Re: Concept & Design of 3.3V Parallel 16-bit VGA Boards
Posted: Fri Apr 19, 2013 6:51 pm
by ElEctric_EyE
Thanks!
Shouldn't I be able to do a load and a compare on the same cycle? or do you have any suggestions for improvement?
Re: Concept & Design of 3.3V Parallel 16-bit VGA Boards
Posted: Fri Apr 19, 2013 6:56 pm
by Arlet
I'm not sure what load and compare you are talking about...
Re: Concept & Design of 3.3V Parallel 16-bit VGA Boards
Posted: Fri Apr 19, 2013 7:24 pm
by ElEctric_EyE
I don't have the newest code posted yet, but for instance shouldn't I be able to do a LOAD and SLOPE from that last version I posted? If I wasn't doing a synchronous always block(always @(posedge clk) and was using a combinatorial always block(always @*), I'm sure it could be done simultaneous.