Is the sc_FIFO up to the task then? Would using your zero-latency FIFO be overkill?
Now, with the next 3 weeks, do you think you can squeeze in past the triangle fill to ellipse fill and do a copy & paste function to finish this geometry unit V1.0 meaning you may even be able to paint (blit) software fonts on a normal graphics screen and even draw/copy/render multiple sprites all over the screen being able to replicate car racing games like 'Out Run' at full arcade speed and quality?
Ok, you'll need either the Lattice FPGA with a little trickery to retain the full 320x240 res, and/or add the 512k ram chip to get every single asset for this one running on a 256 color full arcade quality 320x240 screen.
I hope you have a good BGA Cyclone choice + add at least 1 or 2 of those ZBT rams chips for 1mb. You will be able to do full audio as well.
Note that the sampling audio system will eat up the RS232 debugger port to the GPU ram controller.
Yes, if you want DDR ram with full efficient access, especially for the geometry unit, there will be a ton leg work to do on your own. The ZBT ram would be a drop-in addition which still requires a little steering logic inside the 'vid_osd_generator.sv' to give access to it's own 1 or 2 MAGGIE layers as it is will be 2x slower at 125MHz, or if you are lucky you can run it at 250MHz, but it can still get the read data back in 3 clocks instead of 2.
Also remember, Maggie currently can only address 1 megabyte as much of the rest of your design also has only 20 bit addressing.
I also want to see a 16 bit output port added to the Z80 but. Basically 2 adjacent 8 bit ports, with a write strobe output for each. (This is so you can select loading data into the geo-unit after the low byte is sent, or, after the high byte is sent since the geo unit needs to take in 16bit at a time) If you do not want to 2 ports to write to the geometry_xy_plotter, but a memory address bytes instead, you will need to do this on your own later. This 16 bit port will feed a 512x16 word ALT_FIFO megafunction into the geometry_xy_plotter module.
I've added an input to the pixel_address_generator called fifo_full which connects to the output of the same name (presumably) on the zero-latency fifo.
In the comb section of the pixel_address_generator, pixel_cmd_rdy is now the ANDed product of (what was called) pixel_cmd_rdy && !fifo_full, so pixel_cmd_rdy only goes high now when cmd_rdy is HIGH AND fifo_full is LOW.Shouldn't draw_busy also be ANDed with !fifo_full, so the pixel_address_generator(I'm calling it PAGET from now on)stops working whilst the pixel_writer's input fifo is full?
Just read in your previous post(s) that it should do.
Z80_bridge_v2 attached, with inputs and outputs added as described.I also want to see a 16 bit output port added to the Z80 but. Basically 2 adjacent 8 bit ports, with a write strobe output for each. (This is so you can select loading data into the geo-unit after the low byte is sent, or, after the high byte is sent since the geo unit needs to take in 16bit at a time) If you do not want to 2 ports to write to the geometry_xy_plotter, but a memory address bytes instead, you will need to do this on your own later. This 16 bit port will feed a 512x16 word ALT_FIFO megafunction into the geometry_xy_plotter module.
Won't I need a third IO port to tell the Z80_bridge to send the data to the geo-unit?
input logic WR_PX_CTR_STROBE, // HIGH to clear the WRITE PIXEL collision counter
input logic [7:0] WR_PX_CTR, // WRITE PIXEL collision counter from pixel_writer
input logic WFR_PX_CTR_STROBE,// HIGH to clear the WRITE FROM READ PIXEL collision counter
input logic [7:0] WFR_PX_CTR, // WRITE FROM READ PIXEL collision counter from pixel_writer
input logic PAGET_FIFO_STROBE,// HIGH for valid data on PAGET_FIFO bus
input logic [7:0] PAGET_FIFO, // pixel_address_generator FIFO flags
input logic GEOFF_FIFO_STROBE,// HIGH for valid data on GEOFF_FIFO bus
input logic [7:0] GEOFF_FIFO, // geometry_xy_plotter FIFO flags
I wouldn't have a clue how to connect up DDR ram. I mean, the actual physical connection should be easy enough (with a little learning about matching trace lengths and some other oddities of PCB design), but actually integrating it into the GPU HDL would be the big issue for me. Having access to megabytes of RAM would be massively advantageous, though. Not just for the GPU, but for any application I'd decide to put the FPGA to. I could get rid of all the 'old' hardware (memory, CF card, CPU) and have it all on the one PCB, for example.
Also remember, Maggie currently can only address 1 megabyte as much of the rest of your design also has only 20 bit addressing.
That'd be easy enough to improve, though - at least in theory.
The '_STROBE' are outputs, not inputs. This is how we are able to tell if the Z80 read each one of those ports so we may auto clear and update their values.
'WRITE FROM READ PIXEL collision counter' Should just be a COPY READ PIXEL collision counter. The 'WRITE PIXEL' collision counter is already doing what you describe.
'GEOFF_FIFO_STROBE' & 'PAGET_FIFO_STROBE', these are outside of your control. you do not have Z80 access to these.
What you want is:
GEO_STATUS_STROBE output and
GEO_STATUS_DATA_READ_IN 8 bit input read port where we may tie the 510 word scfifo's almost full flag to bit 0, and maybe some other status information to to any other of the 7 bits, like a 1 bit VS frame counter or spare programmable H/V strobe output on bit 1 so you may sync animation to a new frame or chosen line of video.
GEO_STATUS_DATA_WRITE_OUT this output on the same port is optional as you may use a selected bit, say bit 7 to feed all the reset lines for the entire geometry section so it may be kept in sleep until you release the reset. Or, if the geometry unit crashes, IE 510 word scfifo's almost full flag stays full for a consecutive 65535 reads, you may assume a geo crash and reset the entire section and send a fault error to your OS graphics driver.
The '_STROBE' are outputs, not inputs. This is how we are able to tell if the Z80 read each one of those ports so we may auto clear and update their values.
'WRITE FROM READ PIXEL collision counter' Should just be a COPY READ PIXEL collision counter. The 'WRITE PIXEL' collision counter is already doing what you describe.
'GEOFF_FIFO_STROBE' & 'PAGET_FIFO_STROBE', these are outside of your control. you do not have Z80 access to these.
Ah okay, I've updated the Z80_bridge code accordingly. I've called the 'COPY READ PIXEL' counter port simply 'RD_PX_CTR_STROBE'.What you want is:
GEO_STATUS_STROBE output and
GEO_STATUS_DATA_READ_IN 8 bit input read port where we may tie the 510 word scfifo's almost full flag to bit 0, and maybe some other status information to to any other of the 7 bits, like a 1 bit VS frame counter or spare programmable H/V strobe output on bit 1 so you may sync animation to a new frame or chosen line of video.
GEO_STATUS_DATA_WRITE_OUT this output on the same port is optional as you may use a selected bit, say bit 7 to feed all the reset lines for the entire geometry section so it may be kept in sleep until you release the reset. Or, if the geometry unit crashes, IE 510 word scfifo's almost full flag stays full for a consecutive 65535 reads, you may assume a geo crash and reset the entire section and send a fault error to your OS graphics driver.
Okay, I think I've got the IO as you want it now. Z80_bridge attached. Obviously there's nothing driving or reading these new ports yet.
Where are the:
output logic GEO_WR_LO_STROBE,// HIGH to write low byte to geo unit
output logic GEO_WR_HI_STROBE,// HIGH to write high byte to geo unit
outputs?
They seem dead when you write GEO_LO_BYTE and write GEO_HI_BYTE....
Why are they pulsing when you send something to port 248?
You have 2 strobes to just get used to the fact that each IO port should have it's associated strobe.
Separate ones for each read and separate ones for each write.
For the geo write data, you will only be using one of them, the one associated with the second half of the 16bit word you will be sending.
I'm looking at setting up the Z80_bridge code to send data to the FIFO currently, and can't see a way to do it without adding a third IO port to trigger the send. Is that right?
Also, is there any reason I can't just merge GEO_WR_LO and GEO_WR_HI into one 16-bit bus with one strobe? I can't see the advantage of being able to send one byte instead of one word, so I've probably missed something important. (i.e. the Z80 could load the 16-bit register via two IO writes for the low and high byte, then write to the third port to send the 16-bit word to the geo_unit?)
You just need to decide when copying memory from somewhere else in your Z80 ram, which direction the results are written into the LO and HI port and select which one of those strobes signify that the full 16bit value has been transmitted to both.
It might even be faster to change the ports to 2 bytes of memory access. I'll leave the lessons learned here and you may choose to swap to a memory ram address in place of reading and writing to ports to drive the GPU.
Here's the latest simulation with the third IO removed. Will the strobes be okay or are they a little early for the GEO_WR_HI and _LO lines to stabilise?
// **** Manage IO interface to GEOFF ****
if ( z80_write_port_1s && Z80_addr_r[7:0]==GEO_LO ) begin // Write to GEOFF low-byte register
GEO_WR_LO <= Z80_wData_r[7:0] ;
GEO_WR_LO_STROBE <= 1'b1 ; // Pulse both strobes HIGH to signal to FIFO new data on the bus
end
if ( z80_write_port_1s && Z80_addr_r[7:0]==GEO_HI ) begin // Write to GEOFF high-byte register
GEO_WR_HI <= Z80_wData_r[7:0] ;
GEO_WR_HI_STROBE <= 1'b1 ;
end
// ***** End of GEOFFs IO interface *****
// **** ONE-SHOTS ****
if ( GEO_WR_HI_STROBE ) GEO_WR_HI_STROBE <= 1'b0 ; //
if ( GEO_WR_LO_STROBE ) GEO_WR_LO_STROBE <= 1'b0 ; //
// *******************
// **** Manage IO interface to GEOFF ****
if ( z80_write_port_1s && Z80_addr_r[7:0]==GEO_LO ) begin // Write to GEOFF low-byte register
GEO_WR_LO <= Z80_wData_r[7:0] ;
GEO_WR_LO_STROBE <= 1'b1 ; // Pulse both strobes HIGH to signal to FIFO new data on the bus
end else GEO_WR_LO_STROBE <= 1'b0 ;
if ( z80_write_port_1s && Z80_addr_r[7:0]==GEO_HI ) begin // Write to GEOFF high-byte register
GEO_WR_HI <= Z80_wData_r[7:0] ;
GEO_WR_HI_STROBE <= 1'b1 ;
end else GEO_WR_HI_STROBE <= 1'b0 ;
// ***** End of GEOFFs IO interface *****
What's going on here is that if somehow, (I don't know how), but imagine somehow, if the xxx_STROBE = 1 and a write port to that same strobe comes in at the same time, you would simultaneously be setting the xxx_STROBE to a 1 and the 'one shots' below will be trying to set that xxx_STROBE to 0 at the same time.Using the 'else' means the xxx_STROBE will be continuously cleared to 0 unless that port write happens where it would be set to a '1' for that port write cycle, then back to clearing the strobe under any other circumstance.
However, as you can see, your simulation still worked anyways. You decide how you want to keep your code.
Step #3, copy pixel function. Since this is a read pixel ram only function, lets begin here as the pixel writer begins with the same logic with added functions.
a) Check if our copy pixel read cache has already read the same address and the read cache valid flag is set, if so, store the new read bits per pixel setting & latch the sub pixel bit position & color data. Do nothing else.
b) If not, stop the fifo read command (shift_out) and send a 'rd_req_a' pulse and clear the read cache valid flag to 0.
c) once the 'rd_data_rdy_a' pulse comes in, latch the read data & latch the read address & latch the read bits per pixel setting & latch the sub pixel bit position & color data and set the read cache valid flag to 1.
cache_address <= 20'b0 ;
cache_colour <= 8'b0 ;
cache_bpp <= 4'b0 ;
cache_target <= 4'b0 ;