Concept & Design of 3.3V Parallel 16-bit VGA Boards
Re: Concept & Design of 3.3V Parallel 16-bit VGA Boards
If you don't count the code for the straight line segments, and the sine tables, the polygon method takes less code. And like I said, it works well for partial circles. The Bresenham circle algorithm is probably the fastest, if implemented well.
-
ElEctric_EyE
- Posts: 3260
- Joined: 02 Mar 2009
- Location: OH, USA
Re: Concept & Design of 3.3V Parallel 16-bit VGA Boards
I'm going to bring back the hardware Random Number Generator for some speed tests with randomly placed origins, colors, radii, etc.
Also I would like to try filled circles, which would be done by decreasing the max radius by one until zero and plotting the circles around each origin. Also, if there's 8 quadrants I can envision some kind of math affecting the color to simulate a kind of light source to make a 3d effect. Just thinking as for an experiment. I'm not hell bent on it.
Also, I want to do a spiral where the radius decreased by some amount before the circumference is complete.
I would like to do all this without the use if lookup tables, load down the system then do a comparison with the LUT's. I have plenty of blockRAM left.
Also I would like to try filled circles, which would be done by decreasing the max radius by one until zero and plotting the circles around each origin. Also, if there's 8 quadrants I can envision some kind of math affecting the color to simulate a kind of light source to make a 3d effect. Just thinking as for an experiment. I'm not hell bent on it.
Also, I want to do a spiral where the radius decreased by some amount before the circumference is complete.
I would like to do all this without the use if lookup tables, load down the system then do a comparison with the LUT's. I have plenty of blockRAM left.
Re: Concept & Design of 3.3V Parallel 16-bit VGA Boards
I tried the fill circle by reducing the radius but it leaves holes scattered. My 320x240 display modified the circle routine to draw horizontal lines from top to bottom, using the endpoints calculated by the original circle routine. It runs fast and leaves no holes. I do not have 65c02 code for it but its not hard to figure out.
Daryl
Daryl
Please visit my website -> https://sbc.rictor.org/
-
ElEctric_EyE
- Posts: 3260
- Joined: 02 Mar 2009
- Location: OH, USA
Re: Concept & Design of 3.3V Parallel 16-bit VGA Boards
8BIT wrote:
I tried the fill circle by reducing the radius but it leaves holes scattered...Daryl
Just in case I made an error in the code, I post it... Been a long day at work, but this is some good motivating stuff!
Code: Select all
START: LDA #$0000
TAZP ;SET ZEROPAGE @$0000_0000
LDA #$0001
TASP ;SET STACKPAGE @$0001_0000
LDWi $0000 ; LDW #$0000 - SET BLACK SCREEN ACCORDING TO COLOR LUT
LDBaw COLTABLE ; LDB COLTABLE,w
STBzp SCRCOL ; STB SCRCOL
JSR CLRSCR
LDWi $0005 ; LDW #$0005 - SET PIXEL COLOR GREEN ACCORDING TO COLOR LUT
LDBaw COLTABLE ; LDB COLTABLE,w
STBzp PXLCOL ; B ACCUMULATOR, PIXELCOLOR
LDA #$0000
STA Numberh
LDFi $00F0 ;F ACCUMULATOR, RADIUS
AD STFzp Number ;RADIUS
JSR Square
LDA Sqr
STA RSQR ;RSQR= R^2
CLC
LDWi $0000 ; LDW #$0000
AC LDA #$0140 ; X CENTER OF 640x480 SCREEN
STA SCRLO
LDA #$80F0 ; Y CENTER OF 640x480 SCREEN
STA SCRHI ; START @ORIGIN
STWzp Number ; This 'Number' is actually X
JSR Square ; Now square it!
LDA RSQR ; Radius SQUARED
SBC Sqr ; Sqr=Number^2
STA Numberl ; This Numberl IS (R^2-X^2)
JSR SqRoot ; THIS ROUTINE WILL RETURN Root=SQRT(Numberl)
TWY
LDA SCRHI ;A ACCUMULATOR, Y COORDINATE
SBCAopCzp Root ;C ACCUMULATOR, Y MATH
STCzp SCRHI
STBiy SCRLO ;PLOT 1st Quadrant
ADCAopCzp Root
STCzp SCRHI
STBiy SCRLO ;PLOT 2nd Quadrant
INW
CPWi $00EF ; CPW #$00EF
BNE AC
DECF
CMPFi $0000
BNE AD
END JMP END-
ElEctric_EyE
- Posts: 3260
- Joined: 02 Mar 2009
- Location: OH, USA
Re: Concept & Design of 3.3V Parallel 16-bit VGA Boards
Maybe a better way would be to draw lines from the center to the circumference.
Daryl you wouldn't happen to have Bresenham line algorithm would you?
EDIT: Sorry, I missed this part of your post originally:
Daryl you wouldn't happen to have Bresenham line algorithm would you?
EDIT: Sorry, I missed this part of your post originally:
8BIT wrote:
...using the endpoints calculated by the original circle routine...
Daryl
Daryl
Re: Concept & Design of 3.3V Parallel 16-bit VGA Boards
If I understand you correctly, drawing something like a radar sweep? I have line drawing routines that work relatively well, but I think you will still end up with holes.
If you look closely at my circle routine, you see that it only calculates points over a 45 degree arc. It then just uses the mirror image to calculate the other 7 arcs that complete the circle.
x = 0-45 - calculated
x1 = 90 - x
x2 = 90 + x
x3 = 180 - x
x4 = 180 + x
x5 = 270 - x
x6 = 270 + x
x7 = 360 - x
By choosing two of the end points in pairs, you just draw a horizontal line which is much faster than a sloped line.
x1 to x2
x to x3
x4 to x7
x5 to x6
This can also be done with vertical lines equally fast.
Hope this helps.
BTW, here is the line code (unedited from cc65 this time... you will need to edit it some and convert the local lables to globals)
All variables are in ZP. Some are two byte, others are one byte.
Daryl
If you look closely at my circle routine, you see that it only calculates points over a 45 degree arc. It then just uses the mirror image to calculate the other 7 arcs that complete the circle.
x = 0-45 - calculated
x1 = 90 - x
x2 = 90 + x
x3 = 180 - x
x4 = 180 + x
x5 = 270 - x
x6 = 270 + x
x7 = 360 - x
By choosing two of the end points in pairs, you just draw a horizontal line which is much faster than a sloped line.
x1 to x2
x to x3
x4 to x7
x5 to x6
This can also be done with vertical lines equally fast.
Hope this helps.
BTW, here is the line code (unedited from cc65 this time... you will need to edit it some and convert the local lables to globals)
All variables are in ZP. Some are two byte, others are one byte.
Code: Select all
; ------------------------------------------------------------------------
; LINE: Draw a line from X1/Y1 to X2/Y2, where X1/Y1 = ptr1/ptr2 and
; X2/Y2 = ptr3/ptr4 using the current drawing color.
;
; Must set an error code: NO
;
LINE:
@CHECK: lda X2 ;Make sure x1<x2
sec
sbc X1
tax
lda X2+1
sbc X1+1
bpl @CONT
lda Y2 ;If not, swap P1 and P2
ldy Y1
sta Y1
sty Y2
lda Y2+1
ldy Y1+1
sta Y1+1
sty Y2+1
lda X1
ldy X2
sty X1
sta X2
lda X2+1
ldy X1+1
sta X1+1
sty X2+1
bcc @CHECK
@CONT: lsr
sta DX+1
txa
ror
sta DX
bne @NVT
jmp @VERT
@NVT: stz IX
stz IY
sec
lda Y2 ;Calculate dy
sbc Y1
bne @NHZ
jmp @HORZ
@NHZ: bcc @YNEG
@YPOS: lsr
sta DY
jsr SETPIXELCLIP ;plot first point
@LOOP0: ldx #$00
@LOOP: clc
lda IX
adc DX
sta IX
bcc @LOOP1
inx
inc X1
bne @LOOP1
inc X1+1
@LOOP1: clc
lda IY
adc DY
sta IY
bcc @LOOP2
inx
INC Y1
@LOOP2: txa
beq @LOOP ; no adjustment yet
jsr SETPIXELCLIP
lda DX
beq @END0 ; if DX=0, skip x end test
lda X1
cmp X2
bne @END0
lda X1+1
cmp X2+1
beq @END
@END0: lda DY
beq @LOOP0 ; if dy=0, skip y end test
lda Y1
cmp Y2
bne @LOOP0 ; reset x=0
@END: lda X2
sta X1
lda X2+1
sta X1+1
lda Y2
sta Y1
jsr SETPIXELCLIP
rts
@YNEG: jsr SETPIXELCLIP ;plot first point
lda Y1
sec
sbc Y2
lsr
sta DY
@LOOPX: ldx #$00
@LOOP3: clc
lda IX
adc DX
sta IX
bcc @LOOP4
inx
inc X1
bne @LOOP4
inc X1+1
@LOOP4: clc
lda IY
adc DY
sta IY
bcc @LOOP5
inx
DEC Y1
@LOOP5: txa
beq @LOOP3 ; no adjustment yet
jsr SETPIXELCLIP
lda DX
beq @LOOP6 ; if DX=0, skip x end test
lda X1
cmp X2
bne @LOOP6
lda X1+1
cmp X2+1
beq @END
@LOOP6: lda DY
beq @LOOPX ; reset x
lda Y1
cmp Y2
beq @END
bra @LOOPX
@VERT: sec
lda Y2 ;Calculate dy
sbc Y1
bcc @VNEG
bra @VP2
@VP1: inc Y1
@VP2: jsr SETPIXELCLIP
sec
lda Y2
sbc Y1
bne @VP1
rts
@VN1: dec Y1
@VNEG: jsr SETPIXELCLIP
sec
lda Y2
sbc Y1
bne @VN1
rts
@HRZ: inc X1
bne @HORZ
inc X1+1
@HORZ: jsr SETPIXELCLIP
sec
lda X2
sbc X1
bne @HRZ
lda X2+1
sbc X1+1
bne @HRZ
rtsPlease visit my website -> https://sbc.rictor.org/
Re: Concept & Design of 3.3V Parallel 16-bit VGA Boards
Guess I should explain the method for the line drawing routine. I thought this up myself about 30 years ago but doubt that it's an original idea.
First set it up so you increment from x1 to x2, swapping the two points if needed.
You calculate the difference between x1 and x2, store it in dx. Do the same for y1 and y2 stored in dy.
Test for vertical or horizontal lines, and move to optimized code for either.
Now test to see if you will increment or decrement y and point to the proper code section.
Create new variables ix and iy and set to zero. Now, simply add dx to ix and if it carries, inc x1. Then add dy to iy and if it carries, increment y1 (or decrement based in the test above). Plot the new x1,y1 point only when x1 or y1 change.
Keep adding dx to ix and dy to iy until x1 reaches x2.
The loop cycles more times but since there is no multiplication or division, it runs quite fast.
Daryl
First set it up so you increment from x1 to x2, swapping the two points if needed.
You calculate the difference between x1 and x2, store it in dx. Do the same for y1 and y2 stored in dy.
Test for vertical or horizontal lines, and move to optimized code for either.
Now test to see if you will increment or decrement y and point to the proper code section.
Create new variables ix and iy and set to zero. Now, simply add dx to ix and if it carries, inc x1. Then add dy to iy and if it carries, increment y1 (or decrement based in the test above). Plot the new x1,y1 point only when x1 or y1 change.
Keep adding dx to ix and dy to iy until x1 reaches x2.
The loop cycles more times but since there is no multiplication or division, it runs quite fast.
Daryl
Please visit my website -> https://sbc.rictor.org/
-
ElEctric_EyE
- Posts: 3260
- Joined: 02 Mar 2009
- Location: OH, USA
Re: Concept & Design of 3.3V Parallel 16-bit VGA Boards
Awesome. That's all I need is the code. I can work with that and adapt it. Again, thanks a million!
-
ElEctric_EyE
- Posts: 3260
- Joined: 02 Mar 2009
- Location: OH, USA
Re: Concept & Design of 3.3V Parallel 16-bit VGA Boards
Added a random number generator. So far it's only being used for the color look up table for plotting pixels. So the pic above is now made of randomized pixels. Also, in a separate experiment, I made it so each concentric circle had its own color as I was originally trying to perform a filled-in circle.
The idea now is to use the RNG to plot many circles, each with a random radius, position and color as fast as 65Org16 machinely possible.
Also, I've been working on a simple start/stop counter based on the 100MHz clock to quantify testing. I already think I know which one will be the highest speed, so I will concentrate first on the accuracy of the timer, then on that conversion to 65Org16 on my next 2 days off.
I have my timer circuit almost done in Verilog. 2 things left for the timer, then to plot characters utilizing the new plotting setup using indirect indexed. This way I'll be able to plot the timing results, I will need text!
I decided to post the code now, even though the reset bit isn't working on the counter yet...just in case anyone sees a better way of an overall Timer construction! I'm thinking this Timer is using too many resources.
I use extremely loose address decoding in order to save FPGA resources.
The idea now is to use the RNG to plot many circles, each with a random radius, position and color as fast as 65Org16 machinely possible.
Also, I've been working on a simple start/stop counter based on the 100MHz clock to quantify testing. I already think I know which one will be the highest speed, so I will concentrate first on the accuracy of the timer, then on that conversion to 65Org16 on my next 2 days off.
I have my timer circuit almost done in Verilog. 2 things left for the timer, then to plot characters utilizing the new plotting setup using indirect indexed. This way I'll be able to plot the timing results, I will need text!
I decided to post the code now, even though the reset bit isn't working on the counter yet...just in case anyone sees a better way of an overall Timer construction! I'm thinking this Timer is using too many resources.
I use extremely loose address decoding in order to save FPGA resources.
Code: Select all
`timescale 1ns / 1ps
module Timer(input clk,
input [15:0] cpuDO, //cpu databus out
input cpuWE, //cpu write, active high
input cntrCS, //active high from $c000_0000-$cfff_ffff
output reg [15:0] countDO //from count [15:0] to cpuDataIn
);
reg [19:0] counter = 0; //main .01sec counter from 100MHz clock
reg [4:0] seconds = 0; //up to 32 seconds
reg [3:0] tens = 0; //10 tenths
reg [6:0] hundreds = 0; //100 hundredths
wire [15:0] count;
reg stp = 0; //control bit for stop
reg res = 0; //control bit for reset main .01sec counter
assign count [15:0] = {seconds,tens,hundreds}; //assign the bit values when reading the counter
always @(posedge clk)
if(cntrCS) begin
if(cpuWE) begin
res <= cpuDO [15]; //write to $c000_0000, bit 15 = reset
stp <= cpuDO [14]; //write to $c000_0000, bit 14 = stop
end
else
countDO <= count; //read from $c000_0000 16-bit count {sec,tens,hundreds} = xxxxx_xxxx_xxxxxxx
end
else countDO <= 16'h0000;
always @(posedge clk) begin
if (res)
counter <= 20'b0000_0000_0000_0000_0000;
if (tens == 4'b1001) begin
tens <= 4'b0000;
seconds <= seconds + 1;
end
else if (hundreds == 7'b110_0011) begin
hundreds <= 7'b0000000;
tens <= tens + 1;
end
if (stp)
counter <= counter;
else if (counter >= 20'b1111_0100_0010_0011_1111) begin //0 to 999,999 for .01sec counter
counter <= 20'b0000_0000_0000_0000_0000;
hundreds <= hundreds + 1;
end
else
counter <= counter + 1;
end
endmodule-
ElEctric_EyE
- Posts: 3260
- Joined: 02 Mar 2009
- Location: OH, USA
Re: Concept & Design of 3.3V Parallel 16-bit VGA Boards
This works, now onto converting Daryl's Bresenham...
Added toggle to reset:
EDIT: Sorry, reposted code several times. This one is final.
Added toggle to reset:
Code: Select all
module Timer(input clk,
input [15:0] cpuDO, //cpu databus out
input cpuWE, //cpu write, active high
input cntrCS, //active high from $c000_0000-$cfff_ffff
output reg [15:0] countDO //from cpuDataOut
);
reg [19:0] counter = 0; //main .01sec counter from 100MHz clock
reg [4:0] seconds = 0; //up to 31.99 seconds
reg [3:0] tens = 0; //10 tenths (0..9)
reg [6:0] hundreds = 0; //100 hundredths 0..99)
wire [15:0] count;
reg stp = 0; //control bit for stop(hold)
reg res = 0; //control bit to reset main .01sec counter
assign count [15:0] = {seconds,tens,hundreds}; //assign the bit values ($xxxxx_xxxx_xxxxxxx) when reading the counter
always @(posedge clk) begin
if(cntrCS & cpuWE) begin
res <= cpuDO [15]; //a write to $c000_0000, bit 15 = reset
stp <= cpuDO [14]; //a write to $c000_0000, bit 14 = stop
end
if(cntrCS & !cpuWE)
countDO [15:0] <= count [15:0]; //read from $c000_0000 16-bit count {sec,tens,hundreds} = xxxxx_xxxx_xxxxxxx
else
countDO [15:0] <= 16'h0000;
if (res)
res <= ~res; //auto toggle back to count
end
always @(posedge clk) begin
if (res)
counter <= 20'b0000_0000_0000_0000_0000;
else if (stp)
counter <= counter;
else begin
if (tens == 4'b1001) begin
tens <= 4'b0000;
seconds <= seconds + 5'b0_0001;
end
else if (hundreds == 7'b110_0011) begin
hundreds <= 7'b000_0000;
tens <= tens + 4'b0001;
end
else begin
if (counter >= 20'b1111_0100_0010_0011_1111) begin //0 to 999,999 for .01sec counter
counter <= 20'b0000_0000_0000_0000_0000;
hundreds <= hundreds + 7'b000_0001;
end
else
counter <= counter + 20'b0000_0000_0000_0000_0001;
end
end
end
endmodule-
ElEctric_EyE
- Posts: 3260
- Joined: 02 Mar 2009
- Location: OH, USA
Re: Concept & Design of 3.3V Parallel 16-bit VGA Boards
Hmmm, I thought I would do a character plot routine in order to plot the result of the Timer before doing the circle routine. So I finished already and came to the realization that video memory would be best placed at the very bottom $0000_0000-$0fff_ffff. Then the 64K zero-page and 64K stack sit above this. All is working. Now I must do a 'plot number' routine and adapt it to the output of the Timer module.
-
ElEctric_EyE
- Posts: 3260
- Joined: 02 Mar 2009
- Location: OH, USA
Re: Concept & Design of 3.3V Parallel 16-bit VGA Boards
woops, I realized I don't need a tenths counter. Just 2 8 bit counters that max at 99, 1 for seconds and 1 for 10ths and 100ths
I'll try to adapt a bit of Verilog code I have in a book that converts 8-bit binary to BCD.
I'll try to adapt a bit of Verilog code I have in a book that converts 8-bit binary to BCD.
Re: Concept & Design of 3.3V Parallel 16-bit VGA Boards
Instead of 7'b110_0011 I would prefer to write 7'd99.
And if you want BCD, it's easier to make a BCD counter than it is to make a binary counter + binary to BCD converter.
And if you want BCD, it's easier to make a BCD counter than it is to make a binary counter + binary to BCD converter.
-
ElEctric_EyE
- Posts: 3260
- Joined: 02 Mar 2009
- Location: OH, USA
Re: Concept & Design of 3.3V Parallel 16-bit VGA Boards
Of course! Thank you!
I need to refresh my memory with some old school TTL datasheets. Vague memories are there with a great many cobwebs from when I first experimented with counters and 7-segment displays on a breadboard.
EDIT: I was on the right track, just trying to be to fancy for my own good. Hopefully I can get this timer section (Verilog & software) done today.
I need to refresh my memory with some old school TTL datasheets. Vague memories are there with a great many cobwebs from when I first experimented with counters and 7-segment displays on a breadboard.
EDIT: I was on the right track, just trying to be to fancy for my own good. Hopefully I can get this timer section (Verilog & software) done today.
-
ElEctric_EyE
- Posts: 3260
- Joined: 02 Mar 2009
- Location: OH, USA
Re: Concept & Design of 3.3V Parallel 16-bit VGA Boards
ARG, I HATE GHOSTS IN THE MACHINE!
I would've been done 5 min's after the last post if it wasn't for the ghost. Old variables (with same names) in ISim were not changing, and I was chasing my tail. Now I'm going on to write this easy HEX plotting software!
Looks like I'm seeming to favor the 'IF's.
@ Arlet, thanks for the tip of decimal. I think I've learned the bit value is absolute key for proper bit placement. I didn't realize this before, hence my avoiding it and using strictly binary.
@anyone. What's the alternative to all the 'IF's?
I would've been done 5 min's after the last post if it wasn't for the ghost. Old variables (with same names) in ISim were not changing, and I was chasing my tail. Now I'm going on to write this easy HEX plotting software!
Code: Select all
module Timer(input clk,
input [15:0] cpuDO, //cpu databus out
input cpuWE, //cpu write, active high
input cntrCS, //active high from $c000_0000-$cfff_ffff
output reg [15:0] countDO //from cpuDataOut
);
reg [16:0] counter = 0; //main .001sec counter from 100MHz clock
reg [3:0] seconds = 0;
reg [3:0] tenths = 0;
reg [3:0] hundredths = 0;
reg [3:0] thousandths = 0;
wire [15:0] count;
reg stp = 0; //control bit for stop(hold)
reg res = 0; //control bit to reset main .001sec counter
assign count [15:0] = {seconds, tenths, hundredths, thousandths}; //assign the bit values when reading the counter
always @(posedge clk) begin
if(cntrCS & cpuWE) begin
res <= cpuDO [15]; //a write to $c000_0000, bit 15 = reset
stp <= cpuDO [14]; //a write to $c000_0000, bit 14 = stop
end
if(cntrCS & !cpuWE)
countDO [15:0] <= count [15:0]; //read from $c000_0000 16-bit BCD count
else
countDO [15:0] <= 16'h0000;
if (res)
res <= ~res; //auto toggle back to count
end
always @(posedge clk) begin
if (res)
counter <= 17'd0;
else if
(stp) counter <= counter;
else begin
if (tenths == 4'd9) begin
tenths <= 4'd0;
seconds <= seconds + 4'd1;
end
else if (hundredths == 4'd9) begin
hundredths <= 4'd0;
tenths <= tenths + 4'd1;
end
else if (thousandths == 4'd9) begin
thousandths <= 4'd0;
hundredths <= hundredths + 4'd1;
end
else begin
if (counter == 17'd99999) begin //0 to 99,999 for .001sec counter
counter <= 17'd0;
thousandths <= thousandths + 4'd1;
end
else
counter <= counter + 17'd1;
end
end
end
endmodule@ Arlet, thanks for the tip of decimal. I think I've learned the bit value is absolute key for proper bit placement. I didn't realize this before, hence my avoiding it and using strictly binary.
@anyone. What's the alternative to all the 'IF's?