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

0 Members and 3 Guests are viewing this topic.

Offline asmi

  • Super Contributor
  • ***
  • Posts: 1135
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #1150 on: June 30, 2020, 07:59:47 pm »
You won't have enough time to refresh everything at that speed.
DLL disabled mode is not designed for operational use and none of characteristics are guaranteed. Quote from Micron's datasheet:
Quote
The DRAM is not tested to check—nor does Micron warrant compliance with—normal mode timings or functionality when the DLL is disabled. An attempt has been made to have the DRAM operate in the normal mode where reasonably possible when the DLL has been disabled; however, by industry standard, a few known exceptions are defined:
• ODT is not allowed to be used.
• The output data is no longer edge-aligned to the clock.
• CL and CWL can only be six clocks.
When the DLL is disabled, timing and functionality can vary from the normal operation specifications when the DLL is enabled (see DLL Disable Mode in Commands section of the data sheet for more information). Disabling the DLL also implies the need to change the clock frequency (see Input Clock Frequency Change section of the data sheet for details).

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 4000
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #1151 on: June 30, 2020, 09:18:56 pm »
EDIT: Just a thought, but what about a general FILL function?  Specify a point coordinate and a colour and off it goes, filling in all pixels of the colour at the point coordinate with the new colour, until bounded by other colours?  Or would that be too far?
You only call the function twice in a row...
EG,


Code: [Select]
; *************************************************************************************
; ** Draw a filled ellipse (250,250)-(300,350) with palette color 9
; *************************************************************************************
set_x 0,d'175' ; set x0 register to 250 - The ellipse's top-left X position
set_y 0,d'175' ; set y0 register to 250 - The ellipse's top-left Y position
set_x 1,d'300' ; set x1 register to 300 - The ellipse's bottom-right X position
set_y 1,d'350' ; set y1 register to 350 - The ellipse's bottom-right Y position
plot_circle_fill d'9' ; plot a filled ellipse with palette color 9
        plot_circle d'15'         ; plot the outline of the same ellipse with palette color 15

Remember, my commands holding their screen coordinates were optimized to do this sort of thing.
You may make such a command in your Z80 graphics driver, but, it would just execute the above code.
The Geometry unit will draw between 25 million all the way up to 125 million pixels a second.  It wont break a sweat drawing the extra few pixels surrounding the edge of an ellipse, or rectangle a second time.

Give it a test in geo.bas.
Now, truly begin the 'geometry_xy_plotter.sv'.  Start with being able to load it's internal storage registers with the command input port.

 :palm: Sorry, my bad.  You meant a general 'Flood Fill', right?

     Ok, that would take a little feedback cooperation between the 'geometry_xy_plotter.sv' and 'pixel_writer', but I'm wondering how I could generate a cheap method where it can properly seek and fill around the corner of an onscreen object.

     A radiant style fill would be easy, but, on screen objects would be able to cast shadows which means it wouldn't be a true 'Flood Fill'.  If a shadow is cast, you would need to manually start an additional 'Flood Fill' in the void to complete the fill which may once again still contain additional voids.  If I can figure out an easy way to automatically drive the filling of the voids, you would have a really fast 'Flood Fill'.  Otherwise, the fill will need to be done in a much slower maze-seek algorithm.  (Much slower means filling something like 5 million pixels a second instead of 125 million a second.)
« Last Edit: June 30, 2020, 09:21:01 pm by BrianHG »
__________
BrianHG.
 
The following users thanked this post: nockieboy

Offline nockieboy

  • Frequent Contributor
  • **
  • Posts: 876
  • Country: gb
Re: FPGA VGA Controller for 8-bit computer
« Reply #1152 on: June 30, 2020, 09:31:24 pm »
:palm: Sorry, my bad.  You meant a general 'Flood Fill', right?

Yes, that's the one.  Sorry, my terminology isn't necessarily up to the task - this is all new ground for me.

     Ok, that would take a little feedback cooperation between the 'geometry_xy_plotter.sv' and 'pixel_writer', but I'm wondering how I could generate a cheap method where it can properly seek and fill around the corner of an onscreen object.

     A radiant style fill would be easy, but, on screen objects would be able to cast shadows which means it wouldn't be a true 'Flood Fill'.  If a shadow is cast, you would need to manually start an additional 'Flood Fill' in the void to complete the fill which may once again still contain additional voids.  If I can figure out an easy way to automatically drive the filling of the voids, you would have a really fast 'Flood Fill'.  Otherwise, the fill will need to be done in a much slower maze-seek algorithm.  (Much slower means filling something like 5 million pixels a second instead of 125 million a second.)

Okay, well I kind of broke it into two separate things.  One was the original idea - the flood fill.  I have memories of doing these on my old Amstrad in whatever graphics programme I used to have and it would literally take tens of seconds, if not more for more complex shapes, to fill with a colour.  Having a hardware version of that would be useful - although perhaps with limited use-cases (the aforementioned graphics programme being the most obvious) - or old 'graphical adventures', where the picture for a key location would be built up in front of you as you read the descriptive text - again with some painfully slow flood fills.

The other idea that came out of it was polygons.  I think you mentioned being able to draw triangles or polygons with the ellipse function?  Being able to draw bespoke shapes with three, four or potentially more, vertices either as wireframe or filled would be VERY useful.  I know the line function can do the same thing with some additional work from the Z80, but being able to fill those shapes would be nice.
 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 4000
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #1153 on: June 30, 2020, 09:42:01 pm »
Also I wonder if your existing core would be much simpler had it worked with full color objects and surfaces as opposed to packed-color ones, as I assume you will need additional HW to pack and unpack pixel information from data bytes stored in memory. While in case of full color this will be a trivial memory address calculation without any need to somehow transform data you get from memory.
Yes, currently we have multiple different packed color modes and the pixel writer after the geometry unit has code to deal with it.  Yes, 32 bit only removes a lot of glut, but, remember DDR3 smallest burst has 8 words @ 32 bit for the optimum.  To make efficient use of the dram when reading and writing pixels, internally we would have a 8x32 = 256 bit bus which would look equivilant to a 1 bitplane image with an 8 bit memory bus.  Yes, it would be written out a little different, but it boils down to the same idea.  When reading or writing adjacent pixels, you do not want to sacrifice that minimum 4 cycle burst of the same DRAM memory address 8 times in a row with the write mask set for 1 individual byte every time.  Now you may have a DDR3 ram controller with a smart cache to manage this, but to properly weave your pixel plotting commands with reads for the screen refresh, you should organize your memory requests on the page burst boundary with the bottom CAS A0,A1,A2 all = 0.  Otherwise, there will end up having a few access penalties when as you cross a row address if the word alignment isn't on centered on the 8 byte burst.  In fact, once you have done this, everything, like geometry command arrays should all be padded and sit on an 8 word boundary.

The big difference is that we wouldn't have to worry about any other pixel formats.  And in the case of a 256 color paletted bitmap, there would be 1 function in the pixel writer to convert that bitmap to 32 bit in real time.
« Last Edit: June 30, 2020, 09:55:39 pm by BrianHG »
__________
BrianHG.
 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 4000
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #1154 on: June 30, 2020, 09:53:13 pm »
The other idea that came out of it was polygons.  I think you mentioned being able to draw triangles or polygons with the ellipse function?  Being able to draw bespoke shapes with three, four or potentially more, vertices either as wireframe or filled would be VERY useful.  I know the line function can do the same thing with some additional work from the Z80, but being able to fill those shapes would be nice.

Triangle and filled triangle, 4 sided polygon and filled 4 sided polygon will be added as they are basic functions for a 2D accelerator.  They are basically just 2 line functions running at once and tied together.  This is why I made the source X&Y coordinates have 4 points for up to 4 vertices.

Using the 'Line' function, with multiple coordinates to construct a closed shape, then flood fill that shape is easy.  Once the shape is completed, you would once again go back through all the 'points' in the object and do a radiant style fill 1 pixel toward the inside of the object.  Otherwise, you would just generate your object using multiple filled triangles just like any other 3D geometric generated image, or filled 4 sided polygons which are actually only 2 triangles with 1 matching face.
« Last Edit: June 30, 2020, 10:19:15 pm by BrianHG »
__________
BrianHG.
 

Offline asmi

  • Super Contributor
  • ***
  • Posts: 1135
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #1155 on: July 01, 2020, 01:08:17 am »
Yes, currently we have multiple different packed color modes and the pixel writer after the geometry unit has code to deal with it.  Yes, 32 bit only removes a lot of glut, but, remember DDR3 smallest burst has 8 words @ 32 bit for the optimum.  To make efficient use of the dram when reading and writing pixels, internally we would have a 8x32 = 256 bit bus which would look equivilant to a 1 bitplane image with an 8 bit memory bus.  Yes, it would be written out a little different, but it boils down to the same idea.  When reading or writing adjacent pixels, you do not want to sacrifice that minimum 4 cycle burst of the same DRAM memory address 8 times in a row with the write mask set for 1 individual byte every time.  Now you may have a DDR3 ram controller with a smart cache to manage this, but to properly weave your pixel plotting commands with reads for the screen refresh, you should organize your memory requests on the page burst boundary with the bottom CAS A0,A1,A2 all = 0.  Otherwise, there will end up having a few access penalties when as you cross a row address if the word alignment isn't on centered on the 8 byte burst.  In fact, once you have done this, everything, like geometry command arrays should all be padded and sit on an 8 word boundary.
Well - there is quite a bit you can do. For example, you can have a FIFO with 32 bit write port and whatever your memory interface width for a read port. Or you can split single x32 interface in two x16 ones, or four x8 (though that can get a bit wasteful in terms of pins needed for ADDR/CTRL lines). Or just duplicate your processing cores and process several pixels in parallel, so that you can write them all at the same time. Or some combination of above :)

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 2086
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #1156 on: July 01, 2020, 01:47:51 am »
Otherwise, there will end up having a few access penalties when as you cross a row address

If your addressing scheme is such that the adjacent rows are in different banks, then crossing row boundaries will not pose any additional penalties.
 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 4000
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #1157 on: July 01, 2020, 02:39:40 am »
Otherwise, there will end up having a few access penalties when as you cross a row address

If your addressing scheme is such that the adjacent rows are in different banks, then crossing row boundaries will not pose any additional penalties.
You still cannot terminate mid burst without penalty.  With so much ram, word aligning all you data structures to sit evenly on a 8 word x whatever width bits boundary in the memory just shrinks down that problem.  For example, if you need to begin to read right at the end of the row, all addresses '1's, even though the ram will do it, the 8 word burst will just wrap around for the remaining 7 cycles after you get that first word you want, and the remainder of that burst will be wasted when what you want right after that initial last word is the next row right after.  Such word, and even double word alignment for data and code to even accelerate CPU copies began way, way, way back with 68020 and up.
« Last Edit: July 01, 2020, 02:44:23 am by BrianHG »
__________
BrianHG.
 

Offline nockieboy

  • Frequent Contributor
  • **
  • Posts: 876
  • Country: gb
Re: FPGA VGA Controller for 8-bit computer
« Reply #1158 on: July 01, 2020, 02:32:42 pm »
Now, truly begin the 'geometry_xy_plotter.sv'.  Start with being able to load it's internal storage registers with the command input port.

Use the maggie.sv and rs232_DEBUGGER.v to get an idea of how to associate/assign labels from the source command & how to store those labels into the memory registers.  The labels and registers should be almost identical to the geo.bas labels.  Except for the x# & y#, make them 2 dimensional 12 bit registers for ease of design.  (I should have done that anyways within geo.bas.  Sorry, my bad.

I'd be lying if I said I knew what I was doing, so I've thrown some code at the Quartus project and I'm hoping what stuck is vaguely going in the right direction..  ???

Have got as far as the functions (I think) - not sure how to progress.  Anyway, take a look at the attached and let me know where I've gone wrong so far.  ::)

EDIT:
Updated code as I hadn't created registers for max_x, max_y or the two collision counters.  :palm:
« Last Edit: July 01, 2020, 02:40:13 pm by nockieboy »
 

Offline NorthGuy

  • Super Contributor
  • ***
  • Posts: 2086
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #1159 on: July 01, 2020, 02:43:53 pm »
For example, if you need to begin to read right at the end of the row, all addresses '1's, even though the ram will do it, the 8 word burst will just wrap around for the remaining 7 cycles after you get that first word you want, and the remainder of that burst will be wasted when what you want right after that initial last word is the next row right after.

You just read in whole bursts. If the start address is all ones, you don't align it so that it is the first bit in the burst. You align the bursts always the same. The content corresponding to the odd address with all '1' will be the last bit in the burst. Then you can cross row borders without problems. You can read something which spans several rows non-stop.
 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 4000
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #1160 on: July 01, 2020, 04:01:52 pm »
Now, truly begin the 'geometry_xy_plotter.sv'.  Start with being able to load it's internal storage registers with the command input port.

Use the maggie.sv and rs232_DEBUGGER.v to get an idea of how to associate/assign labels from the source command & how to store those labels into the memory registers.  The labels and registers should be almost identical to the geo.bas labels.  Except for the x# & y#, make them 2 dimensional 12 bit registers for ease of design.  (I should have done that anyways within geo.bas.  Sorry, my bad.

I'd be lying if I said I knew what I was doing, so I've thrown some code at the Quartus project and I'm hoping what stuck is vaguely going in the right direction..  ???

Have got as far as the functions (I think) - not sure how to progress.  Anyway, take a look at the attached and let me know where I've gone wrong so far.  ::)

EDIT:
Updated code as I hadn't created registers for max_x, max_y or the two collision counters.  :palm:

Ok, a little mistake on my part, these guys will be in the inside the memory pixel writer...  So they have to be removed.
Code: [Select]
    output Write_col[7:0],  // An 8 bit saturation counter which counts the number of pixel write collisions
    output Copy_col[7:0],   // An 8 bit saturation counter which counts the number of blit write from read pixel write collisions
    output idle             // An output which goes high when the geometry plotter is finished and is doing nothing

Next, your first 4 assigns need the destinations to have wires declared.

Next, this module's outputs are also wires (as well as the inputs).  (See maggie.sv for example.)

To begin with, make all your inputs and outputs on the ports 'wire'.  Look at maggie.sv to see how this is done.  You have the [x:y] on the wrong side of the names.

next make these 5 regs:
Code: [Select]
draw_cmd_func[3:0]
draw_cmd_data_color[7:0]
draw_cmd_data_word_Y[11:0]
draw_cmd_data_word_X[11:0]
draw_cmd_tx
Then I would assign the output port wire to them:
Code: [Select]
draw_cmd[35:32] = draw_cmd_func[3:0]
draw_cmd[31:24] = draw_cmd_data_color[7:0]
draw_cmd[23:12] = draw_cmd_data_word_Y[11:0]
draw_cmd[11:0]  = draw_cmd_data_word_X[11:0]
draw_cmd_rdy    = draw_cmd_tx

Make 16 localparams CMD_OUT_#choose a function name#  and make each = to the AUX# in my comments.

Then when sending a command, all you need to do is:
Code: [Select]
begin
 draw_cmd_func         <= CMD_OUT_#choose a function name#[3:0];
 draw_cmd_data_color   <= 'usually the draw color'
 draw_cmd_data_word_Y  <= 'usually Y coordinate'
 draw_cmd_data_word_X  <= 'usually  X coordinate'
 draw_cmd_tx           <= 1;
end ...
 else if no other new commands running draw_cmd_tx  <=0 ;

Basically, when sending a command, the 'draw_cmd' should have the right data and the 'draw_cmd_rdy' should go high same time.  The 'draw_cmd_rdy' may only be high for additional clocks if the next command going out is ready to go.
Basically when sending a command, make the draw_cmd_rdy =1, when doing nothing, or default state, make it =0.

I left out the things you should be able to work out on your own...

After this, compile in Quartus 9.1 on a schematic with inputs and outputs & try sending a few of the current completed commands and see if the output simulate right.

See attached 'geometry_xy_plotter.sv' where I tell you where and when you send out a command...
« Last Edit: July 01, 2020, 04:35:41 pm by BrianHG »
__________
BrianHG.
 

Offline nockieboy

  • Frequent Contributor
  • **
  • Posts: 876
  • Country: gb
Re: FPGA VGA Controller for 8-bit computer
« Reply #1161 on: July 01, 2020, 04:48:03 pm »
Sorry, bit confused - how does draw_cmd[35:0] get populated with data?  draw_cmd_func, draw_cmd_data_color, draw_cmd_data_word_Y and draw_cmd_data_word_X don't get set anywhere?  I've obviously missed something...  ???

EDIT: Yes - I missed the last code paragraph in your reply.  Still not sure which X/Y coordinate gets set though?
 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 4000
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #1162 on: July 01, 2020, 05:17:28 pm »
Sorry, bit confused - how does draw_cmd[35:0] get populated with data?  draw_cmd_func, draw_cmd_data_color, draw_cmd_data_word_Y and draw_cmd_data_word_X don't get set anywhere?  I've obviously missed something...  ???

EDIT: Yes - I missed the last code paragraph in your reply.  Still not sure which X/Y coordinate gets set though?
Take a look at the assigns I added:
Code: [Select]
//************************************************
// Assign output port wires to internal registers
//************************************************
assign draw_cmd[35:32] = draw_cmd_func[3:0];
assign draw_cmd[31:24] = draw_cmd_data_color[7:0];
assign draw_cmd[23:12] = draw_cmd_data_word_Y[11:0];
assign draw_cmd[11:0]  = draw_cmd_data_word_X[11:0];
assign draw_cmd_rdy    = draw_cmd_tx;

Also, I changed your first 4 command names so they make modern sense.
I also added parameters to the reset collision counters so you may also set 1 to 4 transparent colors when counting collisions, and for when you write/paste a pixel with the mask function.

(See next post)
(back in 1.5hours)
« Last Edit: July 01, 2020, 05:59:33 pm by BrianHG »
__________
BrianHG.
 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 4000
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #1163 on: July 01, 2020, 05:55:58 pm »
Ok, I simplified the layout and and broke everything down to 2 case statements.  See attached code.

It would be nice to replace all the 8'd### with FUNC_IN_'name of function' and at the beginning of the code, make localparams for all the FUNC_IN_'name of function'.

You will need to change the geo.bas to reflect the new FUNC_IN_xxxx #s, and modify the 'instr.txt' file for the fwasm.exe compiler so it's commands reflect the new FUNC_IN_xxxx #s.

I'll be back in 1.5 hours...
« Last Edit: July 01, 2020, 05:59:03 pm by BrianHG »
__________
BrianHG.
 

Offline nockieboy

  • Frequent Contributor
  • **
  • Posts: 876
  • Country: gb
Re: FPGA VGA Controller for 8-bit computer
« Reply #1164 on: July 01, 2020, 06:25:22 pm »
So I'm removing the func3 checks from Geo.bas entirely and instead checking func2 values, which need to match those in the Verilog file, right?

Did you include the code for 8'd127 in the extend_cmd case statement as an example of how the rest should go, or....?  Bit confused as Geo.bas uses x0 * 4096 + y0, but in the Verilog you've just assigned x[0] and y[0] directly to draw_cmd_data_word_X/Y.  Is that right?
 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 4000
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #1165 on: July 01, 2020, 07:20:54 pm »
So I'm removing the func3 checks from Geo.bas entirely and instead checking func2 values, which need to match those in the Verilog file, right?

Did you include the code for 8'd127 in the extend_cmd case statement as an example of how the rest should go, or....?  Bit confused as Geo.bas uses x0 * 4096 + y0, but in the Verilog you've just assigned x[0] and y[0] directly to draw_cmd_data_word_X/Y.  Is that right?
Yes.  Its just that in the geo.bas, x&y should be swapped as Y holds the MSBs and X the LSBs.  I already got the right order in the .sv file for you.

Just look at the width of the assigned bits and where they end up.
I know in basic, I did it the *4096 for the MSBs and +(add) the LSBs.

Since the command input into this module is 16 bits wide, we need a method send a 24 bit address to the pixel writer.  The only way to do so is load 2 12 bit addresses into one of our temporary X&Y registers, then send those to the pixel writer.  Remember, the pixel writer has a 36bit command port, not 16 bit.

I allowed 12 bits to sent in 1 command by reserving commands 128 through 255, and using the lower 12 bits of the command to set the 8 available 12bit work registers.  Commands 0 through 127, IE command bit [7] being low, all perform 1 alternate function with the allowance for 1 additional byte stored in the first 8 bits of the command.


This means for the Z80 to send a command, it would need to send 2 adjacent bytes every time.
The 'geometry_xy_plotter.sv' takes in those 16 bit commands and will occasionally spit out 36bit commands to the next module containing the address generator which translates the mem address and x&y coordinates into a new mem address with the right offset pointing to the pixel, that unit will feed the memory writer which does a read/modify/write at the specified address, counting if there is a pixel collision.

After you complete this part and simulation of the geometry engine, we will add the first geometric shape, a box and a box fill.  When simulating that one, after issuing the command, the geo engine should spit a stream of CMD_OUT_PXWRI commands with x&y coordinates.
« Last Edit: July 01, 2020, 07:40:54 pm by BrianHG »
__________
BrianHG.
 

Offline nockieboy

  • Frequent Contributor
  • **
  • Posts: 876
  • Country: gb
Re: FPGA VGA Controller for 8-bit computer
« Reply #1166 on: July 01, 2020, 08:08:50 pm »
Okaaay.. I think the code is up to date with what you've specified.  Have attached both the Verilog and Free Basic source below.
 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 4000
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #1167 on: July 01, 2020, 09:02:18 pm »
Ok, I touched up the geometry_xy_plotter.sv.
Read it carefully and make it work and simulate in Quartus.

Also, add an IF(reset) ... else ... right at the top to default all the registers.

I also added the geo_shape, geo_run, geo_mask, geo_fill registers, tied them into the case statement and made a separate section after the loading of a command, the area where we place the running geo units.  I also assigned the load_cmd output and commented on each reg's purpose.


« Last Edit: July 01, 2020, 09:43:08 pm by BrianHG »
__________
BrianHG.
 

Offline nockieboy

  • Frequent Contributor
  • **
  • Posts: 876
  • Country: gb
Re: FPGA VGA Controller for 8-bit computer
« Reply #1168 on: July 01, 2020, 09:33:07 pm »
Ok, I touched up the geometry_xy_plotter.sv.
Read it carefully and make it work and simulate in Quartus.

Also, add an IF(reset) ... else ... right at the top to default all the registers.

I also added the geo_shape, geo_run, geo_mask, geo_fill registers, tied them into the case statement and made a separate section after the loading of a command, the area where we place the running geo units.  I also assigned the load_cmd output and commented on each reg's purpose.

You just need to attach the file.  ;)  Will take a look tomorrow.  :-+
 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 4000
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #1169 on: July 01, 2020, 11:06:43 pm »
Ok, I've done the heavy lifting...

Here is the Quartus9.1 Simulation test bench:
[attachimg=1]

Here is a test simulation:
[attach=2]

And, I've attached the Quartus project.
Read the 'geometry_xy_plotter.sv' inside and see how I vastly simplified the case setup using the 'casez' command and using '?' for don't care bits on the commands.

Make sure you understand everything before continuing.  Next, you still need to add the 'reset' and test out a few of the current functioning commands in the simulation.

Ask questions!
Change my stimulus simulation inputs so that you at least fill an x&y coordinates in x0/y0, x1/y1.

Don't assume anything cause next, we will put in the 'draw_box' algorithm and watch it spit out a bunch of coordinates to plot.
__________
BrianHG.
 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 4000
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #1170 on: July 02, 2020, 03:40:15 am »
Ok, so I had time and got bored....  I figured coding would be better the snacking on junk food...

I've added the box & box_filled command, however, I deliberately did not make any comments on the function.
It will be your job to fill in the comments for each line & post them here so I can make sure you understand what's going on.

The code appears to simulate fine, with coordinates in all 4 directions.

You will also be responsible for testing the code in the simulator by manipulating the commands going into the geometry unit and deciphering the results.

Full Quartus project attached below.
(It so far compiles with an FMAX above your core 125MHz clock, though, we can run the geometry unit at 75MHz if ever needed.  It's only the memory pixel writer which we want running at 125MHz.)
__________
BrianHG.
 

Offline nockieboy

  • Frequent Contributor
  • **
  • Posts: 876
  • Country: gb
Re: FPGA VGA Controller for 8-bit computer
« Reply #1171 on: July 02, 2020, 10:15:54 am »
I've added the box & box_filled command, however, I deliberately did not make any comments on the function.
It will be your job to fill in the comments for each line & post them here so I can make sure you understand what's going on.

Here you go:

Code: [Select]
case (geo_shape)    // run a selected geometric drawing engine

4'd1 : begin    // draw a filled rectangle

if ( geo_y != (y[1] + geo_ydir) ) begin             // Check for bottom (or top, depending on sign of geo_ydir) of rectangle reached
if ( geo_x != (x[1] + geo_xdir) ) begin         // Check for right (or left, depending on sign of geo_xdir) of rectangle reached
draw_cmd_func        <= CMD_OUT_PXWRI[3:0]; // Set up command to pixel plotter to write a pixel,
draw_cmd_data_color  <= geo_color;          // ... in geo_colour,
draw_cmd_data_word_Y <= geo_y ;             // ... at Y-coordinate,
draw_cmd_data_word_X <= geo_x ;             // ... and X-coordinate.
draw_cmd_tx          <= 1'b1;               // send command (have moved this after the X, Y setting for easy reading)

// Now increment (or decrement according to geo_xdir) geo_x to the next pixel.
// If geo_fill is HIGH, step to next X-position to fill the rectangle.
// If geo_x is at the end edge, step past it.
// If geo_y is at start or end (top or bottom edge), step to next X-position to draw the horizontal line.
if (geo_fill || geo_x == x[1] || geo_y == y[0] || geo_y == y[1] )   geo_x <= geo_x + geo_xdir;
// Otherwise, jump to end X-position to draw other edge for non-filled rectangle.
else                                                                geo_x <= x[1];

end else begin  // geo_x has passed vertical edge
draw_cmd_tx         <= 1'b0;                // do not send a draw cmd this cycle
geo_x               <= x[0];                // reset X to start X-position
geo_y               <= geo_y + geo_ydir;    // increment (or decrement) Y-position for next line
end
end else begin      // geo_y has passed horizontal edge
geo_run             <= 1'b0;                // stop geometry engine - shape completed
draw_cmd_tx         <= 1'b0;                // do not send a draw cmd this cycle
end

end // draw a filled rectangle

The code appears to simulate fine, with coordinates in all 4 directions.

You will also be responsible for testing the code in the simulator by manipulating the commands going into the geometry unit and deciphering the results.

I'm confused about how cmd_h (with a value of 12) creates a filled rectangle (or a value of 8 creates a non-filled rectangle) - or how any value is interpreted from cmd_h and cmd_l.  There's a few bit operations and splitting of the cmd bus going on that I'm having difficulty following.   :o
 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 4000
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #1172 on: July 02, 2020, 11:08:34 am »
I'm confused about how cmd_h (with a value of 12) creates a filled rectangle (or a value of 8 creates a non-filled rectangle) - or how any value is interpreted from cmd_h and cmd_l.  There's a few bit operations and splitting of the cmd bus going on that I'm having difficulty following.   :o
I separated the command into _h and _l for legibility.  Take a look at lines 207 through 231 (in particular line 214 where I transpose the draw command number) this is where I setup all the controls for the geometry engine:
Code: [Select]
            8'b000????? : begin // this range of commands all begin drawing a shape.
                                // drawing commands begin here.  Keep the convention that:
                                // extend_cmd[0] = mask enable
                                // extend_cmd[1] = use the color in the copy/paste buffer.  This one is for drawing in true color mode.
                                // extend_cmd[2] = fill enable

                geo_shape[3]         <= 1'b0;           // geo shapes 0 through 7, geo shapes 8 through 15 are for copy & paste.
/*LINE 214*/      geo_shape[2:0]       <= command_in[5:3];// Set which one of shapes 0 through 7 should be drawn.  Shape 0 turns means nothing is being drawn
                geo_fill             <= command_in[2];
                geo_paste            <= command_in[1];  // used for drawing in true color 16 bit mode
                geo_mask             <= command_in[0];
                geo_run              <= 1'b1;           // a flag which signifies that a geometric shap drawing engine will begin drawing
                geo_color            <= command_data8;  // set the 8bit pen color.
               
                geo_sub_func1        <= 4'b0;           // for geometric engines which have multiple phases, reset the phase counter
                geo_sub_func2        <= 4'b0;           // for geometric engines which have 2 dimensional multiple phases, reset the phase counter
               
                // Initialize the geometry unit starting coordinates and direction so it can begin plotting immediately
                geo_x                <= x[0];           // initialize the beginning pixel location
                geo_y                <= y[0];           // initialize the beginning pixel location
                if ( x[1] < x[0] ) geo_xdir <= 12'd0-12'd1; // set the direction of the counter (negative x in this case)
                else               geo_xdir <= 12'd1;       // positive x direction
                if ( y[1] < y[0] ) geo_ydir <= 12'd0-12'd1; // negative y direction
                else               geo_ydir <= 12'd1;       // positive y direction
            end

Now, let's make a change (Read all the ***):
Code: [Select]
            8'b000????? : begin // this range of commands all begin drawing a shape.
                                // drawing commands begin here.  Keep the convention that:
                                // ***extend_cmd[3] = fill enable
                                // ***extend_cmd[4] = use the color in the copy/paste buffer.  This one is for drawing in true color mode.
                                // ***extend_cmd[5] = mask enable - when drawing, the mask colors will not be plotted as they are transparent
 
                geo_shape[3]         <= 1'b0;           // geo shapes 0 through 7, geo shapes 8 through 15 are for copy & paste.
/*LINE214*/     geo_shape[2:0]       <= command_in[2:0];// *** Set which one of shapes 0 through 7 should be drawn.  Shape 0 turns means nothing is being drawn
                geo_fill             <= command_in[3];  // *** Fill enable bit.
                geo_paste            <= command_in[4];  // *** used for drawing in true color 16 bit mode
                geo_mask             <= 1'b0;           // *** Mask disables when drawing raw geometry shapes
                geo_run              <= 1'b1;           // a flag which signifies that a geometric shap drawing engine will begin drawing
                geo_color            <= command_data8;  // set the 8bit pen color.
               
                geo_sub_func1        <= 4'b0;           // for geometric engines which have multiple phases, reset the phase counter
                geo_sub_func2        <= 4'b0;           // for geometric engines which have 2 dimensional multiple phases, reset the phase counter
               
                // Initialize the geometry unit starting coordinates and direction so it can begin plotting immediately
                geo_x                <= x[0];           // initialize the beginning pixel location
                geo_y                <= y[0];           // initialize the beginning pixel location
                if ( x[1] < x[0] ) geo_xdir <= 12'd0-12'd1; // set the direction of the counter (negative x in this case)
                else               geo_xdir <= 12'd1;       // positive x direction
                if ( y[1] < y[0] ) geo_ydir <= 12'd0-12'd1; // negative y direction
                else               geo_ydir <= 12'd1;       // positive y direction
            end

Change the .sv and simulate.  Tell me now what are the new 2 commands for drawing a box outline and filled box.  Simulate to make sure you got the figures correct.

This setup should make more sense...

Also make sure you verify that you understand how lines 101 & 102 work.  Why those 2 allow you to set all the x#&y# with 12 bit numbers, and why lines 107-108 & 115-116 send out all 4 of each as destination or source memory addresses.
« Last Edit: July 02, 2020, 11:28:44 am by BrianHG »
__________
BrianHG.
 

Offline nockieboy

  • Frequent Contributor
  • **
  • Posts: 876
  • Country: gb
Re: FPGA VGA Controller for 8-bit computer
« Reply #1173 on: July 02, 2020, 11:44:46 am »
Change the .sv and simulate.  Tell me now what are the new 2 commands for drawing a box outline and filled box.  Simulate to make sure you got the figures correct.

Box outline = 0x01
Box filled    = 0x09

[attachimg=1]

This setup should make more sense...

Also make sure you verify that you understand how lines 101 & 102 work.  Why those 2 allow you to set all the x#&y# with 12 bit numbers, and why lines 107-108 & 115-116 send out all 4 of each as destination or source memory addresses.

 :-+ Sure does.

As for lines 101/102 - yes, happy with how they work.  Haven't encountered casez before, but certainly looks like a powerful and useful statement.  Clever coding as well, reducing all those previous case statements down to two lines to assign the 12-bit number to the appropriate x# and y#.  :clap:

 

Offline BrianHG

  • Super Contributor
  • ***
  • Posts: 4000
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #1174 on: July 02, 2020, 12:10:08 pm »
Ok, change line 244 to:

Code: [Select]
4'd2 : begin    // draw a filled rectangle
This will make the rectangle shape #2 and filled rectangle shape #10.

Now, add in the plotting section:
Code: [Select]
4'd1 : begin    // draw line from (x[0],y[0]) to (x[1],y[1])
.......
end //  draw line from x[0],y[0] to x[1],y[1]

Remember my trick when I construct the rectangle that the first point in the line has already been set by the time this algorithm has been called.  When turning on the CMD_OUT_PXWRI, that coordinate will be sent.  When incrementing the line location, that inc comes out on the next clock cycle which is why I increase the destination by 1 when testing to see if we reached the final pixel in the IF().

Note: The filled flag is ignored for a single line.
__________
BrianHG.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf