Author Topic: FPGA VGA Controller for 8-bit computer  (Read 426376 times)

0 Members and 3 Guests are viewing this topic.

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 7747
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #2200 on: November 29, 2020, 11:39:36 pm »
So, regarding this project, I wonder: why not implementing a Softcore, say a RISC-V CPU, that does all the graphics stuff? This way, the Z80 would only need to move code and data into the GPU's ram (DMA is possible here), and the "graphic CPU" can be programmed in C more comfortably and more productively.
Will the softcore render 125 million new pixels a second (any line angle/shape) and only eat around 1k logic elements & 1k ram for software and hardware & registers and fifo, including the blitter function with rotation & up/down size/scale sampling & translucency features with adaption for different source bitplane depths to different destination bitplane depths with pixel overwrite/collision detection?

Because this is what we have now, including the addition of the ellipse.
 

Offline DiTBho

  • Super Contributor
  • ***
  • Posts: 3915
  • Country: gb
Re: FPGA VGA Controller for 8-bit computer
« Reply #2201 on: November 30, 2020, 09:40:59 am »
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Online Nominal Animal

  • Super Contributor
  • ***
  • Posts: 6265
  • Country: fi
    • My home page and email address
Re: FPGA VGA Controller for 8-bit computer
« Reply #2202 on: November 30, 2020, 10:45:52 am »
translucency
How does this work?
There are two mechanisms: copy with constant fractional opacity, blending the target and the copied together at target; and copying with an alpha channel (fourth component per pixel), which does the same except using the alpha channel opacity for each pixel.

The math is usually implemented by scaling (aligning to highest bit) each color component, then multiplying with the opacity for the new pixmap, 1-opacity for the target pixels, summing the two together, and using the most significant bits for the target.  Sometimes the pixmap pixel color values will have their components premultiplied with its opacity channel value ("pre-multiplied color components"), although that tends to affect the dynamic range and thus produce slightly worse visual results.

For example, to blend two 8-bit color components c0 and c1, opacity a being between 0 (keep c0) and 256 (use c1) you use
    c = ((256 - ac0 + a·c1) >> 8
This poses a slight issue when a is also only 8-bit. In that case, either the actual value a used is (a' + (a' >> 7)), or there is no true full transparency for one of the pixmaps (original or copied).

As you can see, there are six multiplications and six additions that can be done in parallel, and makes up most of the computation involved.  (There is some bit shifting depending on the bit depths involved, too, but that's minor.)  It is perfect for an FPGA or dedicated logic.
« Last Edit: November 30, 2020, 10:48:54 am by Nominal Animal »
 
The following users thanked this post: DiTBho

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #2203 on: November 30, 2020, 12:17:16 pm »
Yes.  What you have is a modified linegen which makes 2 arcs generating the variables X&Y.  And if we look at the two 45 degree segments/halves, with a little effort, we will make that two loop code into a single loop code, called twice with a selection switch to draw each 45 degree half.  Then, for the output, we will make the 4x 'drawpixels' into 1 'drawpixel' and call the routine 4 times, each time with a switch selecting to output 1 of those 4 quadrants.

For the fill flag, we already have that programmed programmed into our verilog code where we currently fill the triangles and boxes.  All we need the ellipse to do is generate the outer edge of the arc line by line, or in a manner where we can see the y coordinate has moved.  Again, already coded as you know.

Okay, I have the full ellipse function working now.  It takes X,Y coordinates for the centre of the ellipse and a & b values for X- and Y-axis dimensions, as well as the usual colour and filled attributes.

Am I needing to optimise this code before translation to HDL, or are your comments about reducing to one loop part of the Verilogification process?  ???
 

Offline asmi

  • Super Contributor
  • ***
  • Posts: 2733
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #2204 on: November 30, 2020, 02:58:38 pm »
So, regarding this project, I wonder: why not implementing a Softcore, say a RISC-V CPU, that does all the graphics stuff? This way, the Z80 would only need to move code and data into the GPU's ram (DMA is possible here), and the "graphic CPU" can be programmed in C more comfortably and more productively.
Video card is a parallel system, while CPU is serial one. You can't replace one with another without losing a lot of performance.
 
The following users thanked this post: DiTBho

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 7747
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #2205 on: November 30, 2020, 06:01:20 pm »
translucency

How does this work?
Sorry, little correction.  In the geometry unit, we only have transparency.
To render each pixel, the geometry unit's pixel writer does a 'read-modify-write' of each written pixel.  This is how it can determine pixel collisions, decide whether 1 pixel or the other should be written on top and convert between different bitplane formats, all handled by the 'pixel-writer' module.

In the current 'MAGGIE' layers system, we currently have translucency between layers since we use a 16 bit ARGB color system, 4 bit alpha translucency + 12 bit RGB.  The resulting function for each pixel is the exact formula as 'Nominal Animal' described.  When adding the DDR ram with the larger new CycloneV FPGA, we will have the option to introduce the 'Alpha blend' in our 'pixel-writer' module when in true-color mode as with <16 bit color screens, there is no way to calculate or pre-determin the output color palette to be chosen.

The MAGGIE system allows this since it's output overlay is calculated after going through the palette where the decoded color output of each layer is always 16/32bits & we are able to mix the resulting colors providing a true-color output.

« Last Edit: November 30, 2020, 06:12:22 pm by BrianHG »
 
The following users thanked this post: DiTBho

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #2206 on: December 01, 2020, 10:10:25 am »
Yes.  What you have is a modified linegen which makes 2 arcs generating the variables X&Y.  And if we look at the two 45 degree segments/halves, with a little effort, we will make that two loop code into a single loop code, called twice with a selection switch to draw each 45 degree half.  Then, for the output, we will make the 4x 'drawpixels' into 1 'drawpixel' and call the routine 4 times, each time with a switch selecting to output 1 of those 4 quadrants.

For the fill flag, we already have that programmed programmed into our verilog code where we currently fill the triangles and boxes.  All we need the ellipse to do is generate the outer edge of the arc line by line, or in a manner where we can see the y coordinate has moved.  Again, already coded as you know.

Okay, I have the full ellipse function working now.  It takes X,Y coordinates for the centre of the ellipse and a & b values for X- and Y-axis dimensions, as well as the usual colour and filled attributes.

Am I needing to optimise this code before translation to HDL, or are your comments about reducing to one loop part of the Verilogification process?  ???

So, optimisation of existing code or crack on with Verilogification?

Code: [Select]
Sub drawCircle(ByVal xc As integer, ByVal yc As Integer, ByVal a As integer, ByVal b As Integer, ByVal colour as Integer, ByVal filled As Boolean = FALSE)

Dim As Integer x, y, sigma, xd
Dim As Integer a2 = a*a, b2 = b*b, fa2 = 4*a2, fb2 = 4*b2

x=0
y=b
sigma = 2*b2+a2*(1-2*b)
   While (b2*x <= a2*y)
      draw_pixel(xc+x, yc+y, colour) : Rem   I. Quadrant
      draw_pixel(xc-x, yc+y, colour) : Rem   II. Quadrant
      draw_pixel(xc+x, yc-y, colour) : Rem   III. Quadrant
      draw_pixel(xc-x, yc-y, colour) : Rem   IV. Quadrant
     
If (filled) Then
      For xd=xc-x to xc+x
draw_pixel (xd, yc+y, colour)
draw_pixel (xd, yc-y, colour)
      Next xd
EndIf

If (sigma>= 0) Then
sigma += fa2*(1-y)
y=y-1
EndIf
sigma = sigma + b2*(4*x+6)
x=x+1
   Wend
   
   x=a
   y=0
   sigma = 2*a2+b2*(1-2*a)
   While (a2*y <= b2*x)
      draw_pixel(xc+x, yc+y, colour) : Rem   I. Quadrant
      draw_pixel(xc-x, yc+y, colour) : Rem   II. Quadrant
      draw_pixel(xc+x, yc-y, colour) : Rem   III. Quadrant
      draw_pixel(xc-x, yc-y, colour) : Rem   IV. Quadrant

If (filled) Then
      For xd=xc-x to xc+x
draw_pixel (xd, yc+y, colour)
draw_pixel (xd, yc-y, colour)
      Next xd
EndIf

If (sigma>= 0) Then
sigma += fb2*(1-x)
x=x-1
EndIf
sigma = sigma + a2*(4*y+6)
y=y+1
   Wend
 
End Sub
 

Offline asmi

  • Super Contributor
  • ***
  • Posts: 2733
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #2207 on: December 01, 2020, 04:18:22 pm »
That company was founded in 1993, and their V1000 is based on a single Mips-like CPU, accessing all the video memory. The v1000 is a RISC CPU @ 25 MHz having a one-cycle multiplication of 32 * 32 occupying a solid part of the chip! All operations were performed in 32-bit integers with a fixed comma, and there was also a one-cycle instruction for calculating the approximate inverse value, that is, a two-stroke approximated integer division, and the usual set of RISC instructions.
Modern GPUs are massive SIMD machines, which means a single sequence of instructions is scheduled into 1000's of identical cores, which are fed by (and feed into) very high-latency, but massive bandwidth GDDR6/6X memory. This is what allows them to output 8.3 million of pixels of 4K many times per second, and process 100's of millions of triangles while rendering each frame.
There is no realistic way to replicate that inside FPGA, unless you use a really big and fast one (==super expensive and very power-hungry) with HBM2 DRAM, or you can settle for way less impressive results. Like maybe 1M triangles and 1080p resolution are possible if you use 64bit DDR3 memory bus running at 933 MHz and a something like 160T Kintex-7 device, as you will be lucky to fit 100 cores into it.
 
The following users thanked this post: DiTBho

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 7747
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #2208 on: December 03, 2020, 09:25:19 pm »
So, optimisation of existing code or crack on with Verilogification?

Code: [Select]
Sub drawCircle(ByVal xc As integer, ByVal yc As Integer, ByVal a As integer, ByVal b As Integer, ByVal colour as Integer, ByVal filled As Boolean = FALSE)

Dim As Integer x, y, sigma, xd
Dim As Integer a2 = a*a, b2 = b*b, fa2 = 4*a2, fb2 = 4*b2

x=0
y=b
sigma = 2*b2+a2*(1-2*b)
   While (b2*x <= a2*y)
      draw_pixel(xc+x, yc+y, colour) : Rem   I. Quadrant
      draw_pixel(xc-x, yc+y, colour) : Rem   II. Quadrant
      draw_pixel(xc+x, yc-y, colour) : Rem   III. Quadrant
      draw_pixel(xc-x, yc-y, colour) : Rem   IV. Quadrant
     
If (filled) Then
      For xd=xc-x to xc+x
draw_pixel (xd, yc+y, colour)
draw_pixel (xd, yc-y, colour)
      Next xd
EndIf

If (sigma>= 0) Then
sigma += fa2*(1-y)
y=y-1
EndIf
sigma = sigma + b2*(4*x+6)
x=x+1
   Wend
   
   x=a
   y=0
   sigma = 2*a2+b2*(1-2*a)
   While (a2*y <= b2*x)
      draw_pixel(xc+x, yc+y, colour) : Rem   I. Quadrant
      draw_pixel(xc-x, yc+y, colour) : Rem   II. Quadrant
      draw_pixel(xc+x, yc-y, colour) : Rem   III. Quadrant
      draw_pixel(xc-x, yc-y, colour) : Rem   IV. Quadrant

If (filled) Then
      For xd=xc-x to xc+x
draw_pixel (xd, yc+y, colour)
draw_pixel (xd, yc-y, colour)
      Next xd
EndIf

If (sigma>= 0) Then
sigma += fb2*(1-x)
x=x-1
EndIf
sigma = sigma + a2*(4*y+6)
y=y+1
   Wend
 
End Sub

Ok, to begin with, get rid of the fill nonsense for now and remembering that we will only be outputting a single quadrant at a time, step 1 is to test the code...

Code: [Select]
Sub draw_ellipse (ByVal xc As integer, ByVal yc As Integer, ByVal a As integer, ByVal b As Integer)

Dim As Integer x, y, sigma, xd
Dim As Integer a2 = a*a, b2 = b*b, fa2 = 4*a2, fb2 = 4*b2
        Dim As Integer cr,cg,cb


cr=255:cg=0:cb=0

x=0
y=b
sigma = 2*b2+a2*(1-2*b)
   While (b2*x <= a2*y)
      draw_pixel(xc+x, yc+y, cr, cg, cb) : Rem   I. Quadrant
      draw_pixel(xc-x, yc+y, cr, cg, cb) : Rem   II. Quadrant
      draw_pixel(xc+x, yc-y, cr, cg, cb) : Rem   III. Quadrant
      draw_pixel(xc-x, yc-y, cr, cg, cb) : Rem   IV. Quadrant
     

If (sigma>= 0) Then
sigma += fa2*(1-y)
y=y-1
EndIf
sigma = sigma + b2*(4*x+6)
x=x+1
   Wend




cr=0:cg=255:cb=0
   
   x=a
   y=0
   sigma = 2*a2+b2*(1-2*a)
   While (a2*y <= b2*x)
      draw_pixel(xc+x, yc+y, cr, cg, cb) : Rem   I. Quadrant
      draw_pixel(xc-x, yc+y, cr, cg, cb) : Rem   II. Quadrant
      draw_pixel(xc+x, yc-y, cr, cg, cb) : Rem   III. Quadrant
      draw_pixel(xc-x, yc-y, cr, cg, cb) : Rem   IV. Quadrant


If (sigma>= 0) Then
sigma += fb2*(1-x)
x=x-1
EndIf
sigma = sigma + a2*(4*y+6)
y=y+1
   Wend

End Sub

I've attached the basic code and .exe in the .zip.
Just move the mouse to manipulate the ellipse.
I used 2 colors, red when drawing the first 45 degrees, green when drawing the second.
  (Press ESC key to quit...)
  (Sorry, the code craps out if the X&Y radius are both 0)

Take a look at what happens when the ellipse is very narrow.
Yes, the code needs 1 more thing before we begin to HDL it.
« Last Edit: December 03, 2020, 09:38:03 pm by BrianHG »
 
The following users thanked this post: nockieboy

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 7747
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #2209 on: December 04, 2020, 12:05:08 am »
Ok, here are the fixes.
What was needed was 2 things.
1.  If the radius of the ellipse on the current 45 degree plane is 0, just render a straight line.
2.  If after rendering the curve of the ellipse on the current 45 degree plane still has a remainder, IE it hasn't reached the '0' axis, finish rendering a line.

See code and attached examples:
Code: [Select]
Sub draw_ellipse (ByVal xc As integer, ByVal yc As Integer, ByVal a As integer, ByVal b As Integer)

Dim As Integer x, y, sigma, xd
Dim As Integer a2 = a*a, b2 = b*b, fa2 = 4*a2, fb2 = 4*b2
        Dim As Integer cr,cg,cb


cr=255:cg=0:cb=0

x=0
y=b
sigma = 2*b2+a2*(1-2*b)
   While ((b2*x <= a2*y) and b>0)
      draw_pixel(xc+x, yc+y, cr, cg, cb) : Rem   I. Quadrant
      draw_pixel(xc-x, yc+y, cr, cg, cb) : Rem   II. Quadrant
      draw_pixel(xc+x, yc-y, cr, cg, cb) : Rem   III. Quadrant
      draw_pixel(xc-x, yc-y, cr, cg, cb) : Rem   IV. Quadrant
     

If (sigma>= 0) Then
sigma += fa2*(1-y)
y=y-1
EndIf
sigma = sigma + b2*(4*x+6)
x=x+1
   Wend

REM Finish line if Y hasn't landed on 0
if y<=1 then
  y=0
    for x=x to a
      draw_pixel(xc+x, yc+y, cr, cg, cb) : Rem   I. Quadrant
      draw_pixel(xc-x, yc+y, cr, cg, cb) : Rem   II. Quadrant
      draw_pixel(xc+x, yc-y, cr, cg, cb) : Rem   III. Quadrant
      draw_pixel(xc-x, yc-y, cr, cg, cb) : Rem   IV. Quadrant
    next x
endif


cr=0:cg=255:cb=0
   
   x=a
   y=0
   sigma = 2*a2+b2*(1-2*a)
   While ((a2*y <= b2*x) and a>0)
      draw_pixel(xc+x, yc+y, cr, cg, cb) : Rem   I. Quadrant
      draw_pixel(xc-x, yc+y, cr, cg, cb) : Rem   II. Quadrant
      draw_pixel(xc+x, yc-y, cr, cg, cb) : Rem   III. Quadrant
      draw_pixel(xc-x, yc-y, cr, cg, cb) : Rem   IV. Quadrant


If (sigma>= 0) Then
sigma += fb2*(1-x)
x=x-1
EndIf
sigma = sigma + a2*(4*y+6)
y=y+1
   Wend

REM Finish line if X hasn't landed on 0
if x<=1 then
  x=0
    for y=y to b
      draw_pixel(xc+x, yc+y, cr, cg, cb) : Rem   I. Quadrant
      draw_pixel(xc-x, yc+y, cr, cg, cb) : Rem   II. Quadrant
      draw_pixel(xc+x, yc-y, cr, cg, cb) : Rem   III. Quadrant
      draw_pixel(xc-x, yc-y, cr, cg, cb) : Rem   IV. Quadrant
    next y
endif

End Sub

Next step; if you look at the above code, it is doing the same thing twice, except that X&Y, A&B are swapped.
Basically, before we make the HDL, we want to make that '45 degree' arc as an internal function once, (since we are hard-coding the logic gates, only code the math once) while feeding that function the 2 different startup conditions and swapping the result.
« Last Edit: December 04, 2020, 12:30:52 am by BrianHG »
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #2210 on: December 04, 2020, 10:27:34 am »
Hmm... I can't figure out the best way to cater for the second run-through of the arc-drawing function.  I need to swap x and y for the arc calculations, but I need to keep them the same for the draw_pixel calls.  I can't figure out a simple way to do this without ugly hacks. Code below uses drawArc to draw the first arc, but the second is still drawn the old way.  Is there a better way to make drawArc work for both arcs than adding a boolean parameter to the function and having two sets of draw_pixel calls, one with x and y swapped?

Code: [Select]
Sub draw_ellipse (ByVal xc As integer, ByVal yc As Integer, ByVal a As integer, ByVal b As Integer)

   Dim As Integer x, y, sigma, xd
   Dim As Integer a2 = a*a, b2 = b*b, fa2 = 4*a2, fb2 = 4*b2
   Dim As Integer cr,cg,cb

   cr=255:cg=0:cb=0
   x=0
   y=b
   drawArc (x, y, a, b, xc, yc, cr, cg, cb) *****  First call to drawArc, second call needs to be 'drawArc (y, x, b, a, xc, yc, cr, cg, cb)
                                            *****  but part of drawArc needs x & y not to be flipped (draw_pixel calls)
   cr=0:cg=255:cb=0   
   x=a
   y=0
   sigma = 2*a2+b2*(1-2*a)
   While ((a2*y <= b2*x) and a>0)
      draw_pixel(xc+x, yc+y, cr, cg, cb) : Rem   I. Quadrant
      draw_pixel(xc-x, yc+y, cr, cg, cb) : Rem   II. Quadrant
      draw_pixel(xc+x, yc-y, cr, cg, cb) : Rem   III. Quadrant
      draw_pixel(xc-x, yc-y, cr, cg, cb) : Rem   IV. Quadrant

      If (sigma>= 0) Then
         sigma += fb2*(1-x)
         x=x-1
      EndIf
      sigma = sigma + a2*(4*y+6)
      y=y+1
   Wend

   Rem Finish line if X hasn't landed on 0
   If x<=1 Then
      x=0
      For y=y to b
         draw_pixel(xc+x, yc+y, cr, cg, cb) : Rem   I. Quadrant
         draw_pixel(xc-x, yc+y, cr, cg, cb) : Rem   II. Quadrant
         draw_pixel(xc+x, yc-y, cr, cg, cb) : Rem   III. Quadrant
         draw_pixel(xc-x, yc-y, cr, cg, cb) : Rem   IV. Quadrant
      Next y
   EndIf

End Sub

Sub drawArc (ByVal x As Integer, ByVal y As Integer, ByVal a As Integer, ByVal b As Integer, ByVal xc As Integer, ByVal yc As Integer, ByVal cr As Integer, ByVal cg As Integer, ByVal cb As Integer)

   Dim As Integer sigma
   Dim As Integer a2 = a*a, b2 = b*b, fa2 = 4*a2, fb2 = 4*b2

   sigma = 2*b2+a2*(1-2*b)
   While ((b2*x <= a2*y) and b>0)
      draw_pixel(xc+x, yc+y, cr, cg, cb) : Rem   I. Quadrant
      draw_pixel(xc-x, yc+y, cr, cg, cb) : Rem   II. Quadrant
      draw_pixel(xc+x, yc-y, cr, cg, cb) : Rem   III. Quadrant
      draw_pixel(xc-x, yc-y, cr, cg, cb) : Rem   IV. Quadrant

      If (sigma>= 0) Then
         sigma += fa2*(1-y)
         y=y-1
      EndIf
      sigma = sigma + b2*(4*x+6)
      x=x+1
   Wend

   REM Finish line if y hasn't landed on 0
   If y<=1 Then
      y=0
      For x=x to a
         draw_pixel(xc+x, yc+y, cr, cg, cb) : Rem   I. Quadrant
         draw_pixel(xc-x, yc+y, cr, cg, cb) : Rem   II. Quadrant
         draw_pixel(xc+x, yc-y, cr, cg, cb) : Rem   III. Quadrant
         draw_pixel(xc-x, yc-y, cr, cg, cb) : Rem   IV. Quadrant
      Next x
   EndIf

End Sub
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #2211 on: December 04, 2020, 04:11:34 pm »
Just for completeness, here's my hacky (but working) ellipse function:

Code: [Select]
Sub draw_ellipse (ByVal xc As integer, ByVal yc As Integer, ByVal a As integer, ByVal b As Integer)

Dim As Integer x, y, sigma, xd
Dim As Integer a2 = a*a, b2 = b*b, fa2 = 4*a2, fb2 = 4*b2
   Dim As Integer cr,cg,cb

cr=255:cg=0:cb=0
x=0
y=b
drawArc (FALSE, x, y, a, b, xc, yc, cr, cg, cb)

cr=0:cg=255:cb=0   
   x=a
   y=0
   drawArc (TRUE, y, x, b, a, xc, yc, cr, cg, cb)


End Sub

Sub drawArc (ByVal inv As Boolean, ByVal x As Integer, ByVal y As Integer, ByVal a As Integer, ByVal b As Integer, ByVal xc As Integer, ByVal yc As Integer, ByVal cr As Integer, ByVal cg As Integer, ByVal cb As Integer)

Dim As Integer sigma
Dim As Integer a2 = a*a, b2 = b*b, fa2 = 4*a2, fb2 = 4*b2

sigma = 2*b2+a2*(1-2*b)
   While ((b2*x <= a2*y) and b>0)
   
    If (inv) Then
      draw_pixel(xc+y, yc+x, cr, cg, cb) : Rem   I. Quadrant
      draw_pixel(xc-y, yc+x, cr, cg, cb) : Rem   II. Quadrant
      draw_pixel(xc+y, yc-x, cr, cg, cb) : Rem   III. Quadrant
      draw_pixel(xc-y, yc-x, cr, cg, cb) : Rem   IV. Quadrant
    Else
      draw_pixel(xc+x, yc+y, cr, cg, cb) : Rem   I. Quadrant
      draw_pixel(xc-x, yc+y, cr, cg, cb) : Rem   II. Quadrant
      draw_pixel(xc+x, yc-y, cr, cg, cb) : Rem   III. Quadrant
      draw_pixel(xc-x, yc-y, cr, cg, cb) : Rem   IV. Quadrant
    EndIf

If (sigma>= 0) Then
sigma += fa2*(1-y)
y=y-1
EndIf
sigma = sigma + b2*(4*x+6)
x=x+1
   Wend

REM Finish Line if y hasn't landed on 0
If y<=1 Then
  y=0
    For x=x to a
      If (inv) Then
      draw_pixel(xc+y, yc+x, cr, cg, cb) : Rem   I. Quadrant
      draw_pixel(xc-y, yc+x, cr, cg, cb) : Rem   II. Quadrant
      draw_pixel(xc+y, yc-x, cr, cg, cb) : Rem   III. Quadrant
      draw_pixel(xc-y, yc-x, cr, cg, cb) : Rem   IV. Quadrant
      Else
      draw_pixel(xc+x, yc+y, cr, cg, cb) : Rem   I. Quadrant
      draw_pixel(xc-x, yc+y, cr, cg, cb) : Rem   II. Quadrant
      draw_pixel(xc+x, yc-y, cr, cg, cb) : Rem   III. Quadrant
      draw_pixel(xc-x, yc-y, cr, cg, cb) : Rem   IV. Quadrant
      EndIf
    Next x
EndIf

End Sub
« Last Edit: December 04, 2020, 04:13:51 pm by nockieboy »
 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 7747
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #2212 on: December 08, 2020, 01:15:30 am »
Just for completeness, here's my hacky (but working) ellipse function:

Code: [Select]
Sub draw_ellipse (ByVal xc As integer, ByVal yc As Integer, ByVal a As integer, ByVal b As Integer)

Dim As Integer x, y, sigma, xd
Dim As Integer a2 = a*a, b2 = b*b, fa2 = 4*a2, fb2 = 4*b2
   Dim As Integer cr,cg,cb

cr=255:cg=0:cb=0
x=0
y=b
drawArc (FALSE, x, y, a, b, xc, yc, cr, cg, cb)

cr=0:cg=255:cb=0   
   x=a
   y=0
   drawArc (TRUE, y, x, b, a, xc, yc, cr, cg, cb)


End Sub

Sub drawArc (ByVal inv As Boolean, ByVal x As Integer, ByVal y As Integer, ByVal a As Integer, ByVal b As Integer, ByVal xc As Integer, ByVal yc As Integer, ByVal cr As Integer, ByVal cg As Integer, ByVal cb As Integer)

Dim As Integer sigma
Dim As Integer a2 = a*a, b2 = b*b, fa2 = 4*a2, fb2 = 4*b2

sigma = 2*b2+a2*(1-2*b)
   While ((b2*x <= a2*y) and b>0)
   
    If (inv) Then
      draw_pixel(xc+y, yc+x, cr, cg, cb) : Rem   I. Quadrant
      draw_pixel(xc-y, yc+x, cr, cg, cb) : Rem   II. Quadrant
      draw_pixel(xc+y, yc-x, cr, cg, cb) : Rem   III. Quadrant
      draw_pixel(xc-y, yc-x, cr, cg, cb) : Rem   IV. Quadrant
    Else
      draw_pixel(xc+x, yc+y, cr, cg, cb) : Rem   I. Quadrant
      draw_pixel(xc-x, yc+y, cr, cg, cb) : Rem   II. Quadrant
      draw_pixel(xc+x, yc-y, cr, cg, cb) : Rem   III. Quadrant
      draw_pixel(xc-x, yc-y, cr, cg, cb) : Rem   IV. Quadrant
    EndIf

If (sigma>= 0) Then
sigma += fa2*(1-y)
y=y-1
EndIf
sigma = sigma + b2*(4*x+6)
x=x+1
   Wend

REM Finish Line if y hasn't landed on 0
If y<=1 Then
  y=0
    For x=x to a
      If (inv) Then
      draw_pixel(xc+y, yc+x, cr, cg, cb) : Rem   I. Quadrant
      draw_pixel(xc-y, yc+x, cr, cg, cb) : Rem   II. Quadrant
      draw_pixel(xc+y, yc-x, cr, cg, cb) : Rem   III. Quadrant
      draw_pixel(xc-y, yc-x, cr, cg, cb) : Rem   IV. Quadrant
      Else
      draw_pixel(xc+x, yc+y, cr, cg, cb) : Rem   I. Quadrant
      draw_pixel(xc-x, yc+y, cr, cg, cb) : Rem   II. Quadrant
      draw_pixel(xc+x, yc-y, cr, cg, cb) : Rem   III. Quadrant
      draw_pixel(xc-x, yc-y, cr, cg, cb) : Rem   IV. Quadrant
      EndIf
    Next x
EndIf

End Sub
Ok, study your correct 'flip' and move the (red parts):

   x=0
   y=b
   drawArc (FALSE, x, y, a, b, xc, yc, cr, cg, cb)

and

   x=a
   y=0
   drawArc (TRUE, y, x, b, a, xc, yc, cr, cg, cb)

inside the draw arc.

This should eliminate the (stuff in red):
   Dim As Integer x, y, sigma, xd
   Dim As Integer a2 = a*a, b2 = b*b, fa2 = 4*a2, fb2 = 4*b2
   Dim As Integer cr,cg,cb

Right at the top of your code.
Next, make 1 output at a time and add to the 'Sub drawArc (ByVal inv As Boolean,...' another flag called 'Quadrant' which goes from 0 to 3.  Then call the 'drawArc (FALSE, [quadrant] ' and 'drawArc (TRUE, [quadrant]' 4 times to generate the ellipse.

In Verilog, the module will only output 1 quadrant/set of coordinates at a time.  When calling the ellipse from the Z80, you will call the Draw-Ellipse 4 times to draw the 4 corners.  This will allow you to either render ellipses when calling the 4 with the same center coordinates, or move the XY center coordinates to make rectangle boxes with rounded corners.

Do not worry about the fill, the line filler runs outside the draw-ellipse generator.
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #2213 on: December 08, 2020, 10:32:44 am »
In Verilog, the module will only output 1 quadrant/set of coordinates at a time.  When calling the ellipse from the Z80, you will call the Draw-Ellipse 4 times to draw the 4 corners.  This will allow you to either render ellipses when calling the 4 with the same center coordinates, or move the XY center coordinates to make rectangle boxes with rounded corners.

To have rounded edges on a rectangle, I'm going to need to rotate the ellipse or arc by 45 degrees, though?

Here's what I've done - all working fine:

Code: [Select]
Sub draw_ellipse (ByVal xc As integer, ByVal yc As Integer, ByVal a As integer, ByVal b As Integer)
   
   Dim As Integer cr, cg, cb=0, quad
   
    For quad=0 To 3
        cr=0:cg=255
        drawArc (TRUE, quad, a, b, xc, yc, cr, cg, cb)
        cr=255:cg=0
        drawArc (FALSE, quad, a, b, xc, yc, cr, cg, cb)
    Next quad
   
End Sub

Sub drawArc (ByVal inv As Boolean, ByVal quadrant As Integer, ByVal af As Integer, ByVal bf As Integer, ByVal xc As Integer, ByVal yc As Integer, ByVal cr As Integer, ByVal cg As Integer, ByVal cb As Integer)
   
    Dim As Integer sigma, x=0, y, a, b, a2, b2, fa2, fb2
   
    If (inv) Then
        a=bf
        b=af
    Else
        a=af
        b=bf
    EndIf
   
    a2 = a*a
    b2 = b*b
    fa2 = 4*a2
    fb2 = 4*b2
    y=b
   
    sigma = 2*b2+a2*(1-2*b)
    While ((b2*x <= a2*y) and b>0)
   
        Select Case quadrant
            Case 0
                If (inv) Then
                    draw_pixel(xc+y, yc+x, cr, cg, cb) : Rem   I. Quadrant
                Else
                    draw_pixel(xc+x, yc+y, cr, cg, cb) : Rem   I. Quadrant
                EndIf
            Case 1
                If (inv) Then
                    draw_pixel(xc-y, yc+x, cr, cg, cb) : Rem  II. Quadrant
                Else
                    draw_pixel(xc-x, yc+y, cr, cg, cb) : Rem  II. Quadrant
                EndIf
            Case 2
                If (inv) Then
                    draw_pixel(xc+y, yc-x, cr, cg, cb) : Rem III. Quadrant
                Else
                    draw_pixel(xc+x, yc-y, cr, cg, cb) : Rem III. Quadrant
                EndIf
            Case 3
                If (inv) Then
                    draw_pixel(xc-y, yc-x, cr, cg, cb) : Rem  IV. Quadrant
                Else
                    draw_pixel(xc-x, yc-y, cr, cg, cb) : Rem  IV. Quadrant
                EndIf
            Case Else
                Return
        End Select
   
        If (sigma>= 0) Then
            sigma += fa2*(1-y)
            y=y-1
        EndIf
        sigma = sigma + b2*(4*x+6)
        x=x+1
       
    Wend

    REM Finish Line if y hasn't landed on 0
    If y<=1 Then
        y=0
        For x=x to a
        If (inv) Then
              draw_pixel(xc+y, yc+x, cr, cg, cb) : Rem   I. Quadrant
              draw_pixel(xc-y, yc+x, cr, cg, cb) : Rem   II. Quadrant
              draw_pixel(xc+y, yc-x, cr, cg, cb) : Rem   III. Quadrant
              draw_pixel(xc-y, yc-x, cr, cg, cb) : Rem   IV. Quadrant
        Else
              draw_pixel(xc+x, yc+y, cr, cg, cb) : Rem   I. Quadrant
              draw_pixel(xc-x, yc+y, cr, cg, cb) : Rem   II. Quadrant
              draw_pixel(xc+x, yc-y, cr, cg, cb) : Rem   III. Quadrant
              draw_pixel(xc-x, yc-y, cr, cg, cb) : Rem   IV. Quadrant
        EndIf
        Next x
    EndIf
   
End Sub

Have attached geoarc.bas and the compiled .exe in the zip below.  There was a little head-scratching caused by trying to remove x and y from the function parameters and normalising the inputs to the drawArc function, but I worked it out in the end. ::)
« Last Edit: December 08, 2020, 11:10:11 am by nockieboy »
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #2214 on: December 08, 2020, 11:03:29 am »
So this arrived the other day - unwrapped today to take a look.  Those 0403s around the QFN don't look as bad as I thought they'd be.  Guess I'll just lightly tin one set of pads, fix the resistors/caps to those pads and then solder the other sides to their pads, same way as I do all the others, just with a little more care.

Have looked up a couple of videos on YouTube to see how best to solder the QFN.  That's going to be a first for me, but I've got 10 QFNs and 10 boards, so I'm hoping I'll get the hang of it before the 10th one.  :o  In fairness, doesn't look too hard - flux, lightly tin the pads, clean and flux, pop the QFN down and attempt to follow some sort of soldering profile as best I can with my heatgun.  I guess the thinner PCB will warm up more quickly, but I'll need to be careful not to overheat it.

For anyone following along to get a sense of scale, C11 and R18 are 0805 components, the network of resistors and capacitors near the thru-holes at the top of the card are 0603, and the components around the QFN footprint are 0402s.  The cutting mat underneath has 1cm boxes.
 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 7747
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #2215 on: December 08, 2020, 07:52:04 pm »
Nice PCB.  Only place the 100ohm parallel terminators and 0.1uf caps.  Do not place the double 50ohm terminators.
 
The following users thanked this post: nockieboy

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 7747
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #2216 on: December 08, 2020, 07:55:12 pm »
In Verilog, the module will only output 1 quadrant/set of coordinates at a time.  When calling the ellipse from the Z80, you will call the Draw-Ellipse 4 times to draw the 4 corners.  This will allow you to either render ellipses when calling the 4 with the same center coordinates, or move the XY center coordinates to make rectangle boxes with rounded corners.

To have rounded edges on a rectangle, I'm going to need to rotate the ellipse or arc by 45 degrees, though?

Here's what I've done - all working fine:

Think for a second.   There are 4 quadrants being plotted.  Hence 4 sides of the ellipse.
Q1: What happens (IE what it the resulting shape) if you call only 1 of the 4?
Q2: What happens if you change the Xc/Yc and call a single different 1 of 4 each time?

I'll ignore the ' REM Finish Line if y hasn't landed on 0' having drawn 4 quadrants.  We will fix this in verilog...

Ok, now, to convert the function into verilog.  We will make the function look/have the same IOs and controls as the current 'line_generator.sv'.  Except, we will add a 2 bit input called 'Quadrant' which latches which quadrant to output/render when the 'RUN' is asserted.

Basically copy & rename the 'line_generator.sv' into a 'ellipse_generator.sv' and add a new 2 bit input called 'Quadrant'.

As for the 'geometry_xy_plotter.sv', we will generate a 'line_select_mux' module which will address the  'line_generator.sv' or 'ellipse_generator.sv' into the place of the first current 'line_generator.sv' which will select between the 2 depending of the called graphics op-code.

« Last Edit: December 08, 2020, 09:32:46 pm by BrianHG »
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #2217 on: December 09, 2020, 03:27:56 pm »
Think for a second.   There are 4 quadrants being plotted.  Hence 4 sides of the ellipse.
Q1: What happens (IE what it the resulting shape) if you call only 1 of the 4?
Q2: What happens if you change the Xc/Yc and call a single different 1 of 4 each time?

Ah, wasn't thinking straight when I asked that question.  ;)

Ok, now, to convert the function into verilog.  We will make the function look/have the same IOs and controls as the current 'line_generator.sv'.  Except, we will add a 2 bit input called 'Quadrant' which latches which quadrant to output/render when the 'RUN' is asserted.

Basically copy & rename the 'line_generator.sv' into a 'ellipse_generator.sv' and add a new 2 bit input called 'Quadrant'.

All done - see attached.  I was going to push on and attempt to convert the FreeBasic into HDL, but don't we need an input for 'invert' as well?

We're going to be doing multiplication.  Can't recall without looking (and can't at the moment) if we've done that before - that'll infer some extra logic I'm guessing, so I didn't want to rush ahead and get it all wrong without waiting to see what you've got in mind next. :)

As for the 'geometry_xy_plotter.sv', we will generate a 'line_select_mux' module which will address the  'line_generator.sv' or 'ellipse_generator.sv' into the place of the first current 'line_generator.sv' which will select between the 2 depending of the called graphics op-code.

Does it need to be a separate module?  Would have thought that would be a convenient thing just to drop into geometry_xy_plotter.sv, unless you've got plans to re-use it elsewhere?
« Last Edit: December 09, 2020, 04:41:19 pm by nockieboy »
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #2218 on: December 10, 2020, 05:47:06 pm »
Had a go at building the DVI tester today.  Took me three attempts to get the QFN to solder to the PCB in a way that I'm vaguely happy with - it probably still isn't soldered properly, but looks good on all contacts as best I can tell, so I've assembled the rest of the board.  That's when I found that 0402s aren't that bad, just damn fiddly and it's really hard trying not to deposit too much solder when attaching them, even though I'm using 0.5mm solder.

Have had to stop, though, as I've realised I've made a mistake - I didn't order any 0402 12.4K resistors. |O  This means I've got no R3 and I guess the board won't work.  That's going to be a delay to get those resistors, guess I'll just have to bite the bullet and do another big order with Mouser to negate their P&P charges, otherwise it'll cost me about $20 for 100 of those resistors...  :-\
 

Offline asmi

  • Super Contributor
  • ***
  • Posts: 2733
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #2219 on: December 10, 2020, 08:52:58 pm »
Have had to stop, though, as I've realised I've made a mistake - I didn't order any 0402 12.4K resistors. |O  This means I've got no R3 and I guess the board won't work.  That's going to be a delay to get those resistors, guess I'll just have to bite the bullet and do another big order with Mouser to negate their P&P charges, otherwise it'll cost me about $20 for 100 of those resistors...  :-\
Don't worry - that happens to all of us every once in a while :-[ Especially for REV 1 of a project.
Don't you have any local online retailers which don't charge ridiculous fees for shipping small orders? There is no rush for these parts to arrive, as you still have no code for it, and just plugging it in won't do anything (well, aside from ensuring it won't let the magic smoke out when you connect it and power up for the first time :D ). I would just go onto LCSC and order reels of all passive parts (most of them are super cheap there, even those from name-brands), and let them slowboat via e-packet or something like that, while you work on HDL code to get this stuff up and running. You will find a use for these parts in your later projects.
In the mean time I suggest you to download HDMI spec - version 1.3a can be downloaded for free after filling out a short form here: https://www.hdmi.org/requestform/clickrequestasync?docId=16 This version will be more than enough for your needs, so skim through it to get familiar with how things work at the high level. Don't get bogged down in details for now, just basic familiarization will be enough. You will see a lot of similarities with VGA, the differences will be mostly in what happens during blanking intervals - that's when all auxiliary information like stream info packets, audio, and/or other things, are transmitted (in case of VGA or DVI it's just a whole bunch of nothingness).
« Last Edit: December 10, 2020, 10:11:32 pm by asmi »
 
The following users thanked this post: nockieboy

Offline mariush

  • Super Contributor
  • ***
  • Posts: 5030
  • Country: ro
  • .
Re: FPGA VGA Controller for 8-bit computer
« Reply #2220 on: December 10, 2020, 09:07:01 pm »

Have had to stop, though, as I've realised I've made a mistake - I didn't order any 0402 12.4K resistors. |

You could just stack 2-3 resistors ... parallel resistors ... ex 68k + 15k gives you 12.3k  , 39+39+33 gives you 12.26 etc , 47+47+27 = 12.56 ....
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #2221 on: December 10, 2020, 10:11:54 pm »

Have had to stop, though, as I've realised I've made a mistake - I didn't order any 0402 12.4K resistors. |

You could just stack 2-3 resistors ... parallel resistors ... ex 68k + 15k gives you 12.3k  , 39+39+33 gives you 12.26 etc , 47+47+27 = 12.56 ....

I just don't have the selection of resistors in any size (except maybe through-hole) to make up that value, let alone 0402 which I've just started using.

Don't you have any local online retailers which don't charge ridiculous fees for shipping small orders? There is no rush for these parts to arrive, as you still have a code for it, and just plugging it in won't do anything (well, aside from ensuring it won't let the magic smoke out when you connect it and power up for the first time :D ). I would just go onto LCSC and order reels of all passive parts (most of them are super cheap there, even those from name-brands), and let them slowboat via e-packet or something like that, while you work on HDL code to get this stuff up and running. You will find a use for these parts in your later projects.

Not really, no.  They all seem to price their shipping and 'free' thresholds to dissuade people from making small orders.  The only real supplier/s of cheap and small-quantity parts are the Chinese distributors, and I was trying to ween myself off them. Might have to make an exception, especially as time isn't an issue as you rightly point out.  ;)
 

Offline asmi

  • Super Contributor
  • ***
  • Posts: 2733
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #2222 on: December 10, 2020, 10:41:06 pm »
Not really, no.  They all seem to price their shipping and 'free' thresholds to dissuade people from making small orders.  The only real supplier/s of cheap and small-quantity parts are the Chinese distributors, and I was trying to ween myself off them. Might have to make an exception, especially as time isn't an issue as you rightly point out.  ;)
Looked at the Farnell: https://uk.farnell.com/help-delivery-information They show free shipping for 40+ quid, which sounds great. Over here we have 100$ free shipping threshold at both Digikey and Mouser.

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #2223 on: December 11, 2020, 11:50:48 am »
Not really, no.  They all seem to price their shipping and 'free' thresholds to dissuade people from making small orders.  The only real supplier/s of cheap and small-quantity parts are the Chinese distributors, and I was trying to ween myself off them. Might have to make an exception, especially as time isn't an issue as you rightly point out.  ;)
Looked at the Farnell: https://uk.farnell.com/help-delivery-information They show free shipping for 40+ quid, which sounds great. Over here we have 100$ free shipping threshold at both Digikey and Mouser.

Yeah, Mouser do the same - the £40 threshold for free shipping is the same.  Just annoying that I have to make up a £40+ order for what is effectively 0.011p worth of resistor that I need. ;)

Having read the datasheet, it appears I might not need it anyway - the following is lifted straight from the datasheet:

7.2 Analog current reference
The REXT pin (pin 6) is an analog current sense port used to provide an accurate current reference for the differential outputs OUT_Dx. For best output voltage swing accuracy, use of a 12.4 kohm resistor (1% tolerance) connected between this terminal and GND is recommended.

If an external 12.4 kohm 1% resistor is not used, this pin can be connected to GND or VDD directly (0 ohm). In any of these cases, the output functions normally but at reduced accuracy over voltage and temperature of the following parameters: output levels (VOL), differential output voltage swing, and rise and fall time accuracy.


It doesn't specify just how much the accuracy is reduced, but it should function well enough for me to work out if the board and HDL are working as expected, whilst I wait for the 12.4K resistors from wherever I end up ordering them from.
 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 7747
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #2224 on: December 11, 2020, 11:54:48 pm »
Not really, no.  They all seem to price their shipping and 'free' thresholds to dissuade people from making small orders.  The only real supplier/s of cheap and small-quantity parts are the Chinese distributors, and I was trying to ween myself off them. Might have to make an exception, especially as time isn't an issue as you rightly point out.  ;)
Looked at the Farnell: https://uk.farnell.com/help-delivery-information They show free shipping for 40+ quid, which sounds great. Over here we have 100$ free shipping threshold at both Digikey and Mouser.

Yeah, Mouser do the same - the £40 threshold for free shipping is the same.  Just annoying that I have to make up a £40+ order for what is effectively 0.011p worth of resistor that I need. ;)

Having read the datasheet, it appears I might not need it anyway - the following is lifted straight from the datasheet:

7.2 Analog current reference
The REXT pin (pin 6) is an analog current sense port used to provide an accurate current reference for the differential outputs OUT_Dx. For best output voltage swing accuracy, use of a 12.4 kohm resistor (1% tolerance) connected between this terminal and GND is recommended.

If an external 12.4 kohm 1% resistor is not used, this pin can be connected to GND or VDD directly (0 ohm). In any of these cases, the output functions normally but at reduced accuracy over voltage and temperature of the following parameters: output levels (VOL), differential output voltage swing, and rise and fall time accuracy.


It doesn't specify just how much the accuracy is reduced, but it should function well enough for me to work out if the board and HDL are working as expected, whilst I wait for the 12.4K resistors from wherever I end up ordering them from.
I would say, don't bother ordering the 12.4k for now.  Just insert a 10k resistor.  Let's see what happens.  Save the 12.4k for when you need to make another larger order.

I will have time this weekend to help you with the Ellipse.  It shouldn't be too hard as we have done this type of coding before everywhere else.  And, multiply in verilog is just a ' * '.  I will go more into the coding tomorrow.
 
The following users thanked this post: nockieboy


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf