Z80_bridge now good .
This isn't where your error is. This is the way the PS2 VHDL is written and that its working at 50MHz, not 125MHz.
Your lines:Code: [Select]if (PS2_RDY) begin // valid data on PS2_DAT
PS2_CHAR <= PS2_DAT; // Latch the character into Ps2_char register
end
Is where the problem lies.
try this instead:Code: [Select]reg [7:0] PS2_RDY_r;
.......
PS2_RDY_r[7:0] <= {PS2_RDY_r[7:1],PS2_RDY};
if (PS2_RDY_r[7:0] == 8'b00001111 ) begin // valid data on PS2_DAT
PS2_CHAR <= PS2_DAT; // Latch the character into Ps2_char register
end
PS2_RDY_r[7:0] <= {PS2_RDY_r[6:0],PS2_RDY};
This means that the PS2_RDY needs to come in for 4 clocks low, then 4 clocks high in a row for the PS2_CHAR to latch the data on that 1 single clock shot, however, this will not solve reading the keyboard port & hitting a key simultaneously.
To fix that problem, you need to:Code: [Select]if ( z80_read_port_1s && Z80_addr_r[7:0]==IO_DATA[7:0] ) begin // Z80 is reading PS/2 port
Z80_rData <= PS2_CHAR;
if (PS2_RDY_r[7:0] != 8'b00001111 ) PS2_CHAR <= 8'b0;
end
That if will prevent the clearing of the PS2_CHAR if a new key is pressed at the same time you are reading the current character.
try this instead:Code: [Select]reg [7:0] PS2_RDY_r;
.......
PS2_RDY_r[7:0] <= {PS2_RDY_r[7:1],PS2_RDY};
if (PS2_RDY_r[7:0] == 8'b00001111 ) begin // valid data on PS2_DAT
PS2_CHAR <= PS2_DAT; // Latch the character into Ps2_char register
end
Yeah, that's the thing.
Oh, shouldn't that be:Code: [Select]PS2_RDY_r[7:0] <= {PS2_RDY_r[6:0],PS2_RDY};
What you will need to eventually do is make an 8 byte port where if you have multiple keys pressed, each byte will retain one of the 8 keys while they are still pressed. As they keys are released the keyboard HDL will clear the correct one of the 8 bytes to 0. The read port will not clear each key's set byte, but HDL will react to you releasing each key on the keyboard by clearing to 0 of the correct one of the 8 bytes.
Your Z80 can scan the 8 bytes and decide what to do, like key repeats, or in game mode, have raw access to those 8 bytes for game controls.
If you want the Z80 to clear any one of the 8 keyboard bytes, you would just write to that port byte.
Or, just 'F' it and do it in software. Use the current setup and use the bit 8 in the character to send to the Z80 normal key bottom 7 bit code plus the same code again with bit 8 signifying that the key was released.
This way it is backwards compatible with what you have now as long as you ignore any incoming characters with a value above 127.
Other than other functions I don't know you want to add, just adding read and write ports should now be easy peasy. This includes adding the GPU 'ID' onto the Z80 data lines if the address is within a specific range.
if ( z80_read_memory_1s && mem_in_range ) begin // pass read request to GPU ram
gpu_addr <= Z80_addr_r[19:0];
gpu_rd_req <= 1'b1; // Flag HIGH for 1 clock when reading from GPU RAM
end else begin
gpu_rd_req <= 1'b0; // Flag HIGH for 1 clock when reading from GPU RAM
end
if ( ~Z80_RDn_r ) begin // this section sets the output enable and sends the correct data back to the Z80
//if (z80_read_opcode) // unused
if (z80_read_memory && mem_in_range && gpu_rd_rdy ) begin // if a valid read memory range and the GPU returns a gpu_rd_rdy, send out data
Z80_rData <= gpu_rData ;
Z80_245data_dir <= data_out;
Z80_rData_ena <= 1'b1 ;
Z80_245_oe <= 1'b0 ;
end else if (z80_read_memory && <RD ADDR above MEM_SIZE_BYTES but below MEMORY_RANGE> && gpu_rd_rdy) begin
<return 0xFF if below BANK_ID address> or <return BANK_ID byte if in BANK_ID range>
end
wire mem_in_bank;
assign mem_in_bank = (Z80_addr_r[21:19]==MEMORY_RANGE[2:0]) ; // Define the memory access window
wire mem_in_range;
assign mem_in_range = (Z80_addr_r[18:0] < MEM_SIZE_BYTES[19:0]) ; // The size of GPU ram + GPU palette ram
if ( z80_read_memory_1s && mem_in_bank ) begin // pass read request to GPU ram
gpu_addr <= Z80_addr_r[19:0];
gpu_rd_req <= 1'b1; // Flag HIGH for 1 clock when reading from GPU RAM
end else begin
gpu_rd_req <= 1'b0; // Flag HIGH for 1 clock when reading from GPU RAM
end
if ( ~Z80_RDn_r ) begin // this section sets the output enable sends the correct data back to the Z80
//if (z80_read_opcode) // unused
if (z80_read_memory && mem_in_bank && gpu_rd_rdy ) begin // if a valid read memory range and the GUP returns a gpu_rd_rdy, send out data
if (mem_in_range) Z80_rData <= gpu_rData ;
else Z80_rData <= BANK_ID[Z80_addr_r[3:0]];
Z80_245data_dir <= data_out;
Z80_rData_ena <= 1'b1 ;
Z80_245_oe <= 1'b0 ;
end
if ( z80_write_memory_1s && mem_in_bank && mem_in_range ) begin // pass write request to GPU ram
if ( z80_read_memory_1s && mem_in_bank && mem_in_range ) begin // pass read request to GPU ram
gpu_addr <= Z80_addr_r[19:0];
gpu_rd_req <= 1'b1; // Flag HIGH for 1 clock when reading from GPU RAM
end else begin
gpu_rd_req <= 1'b0; // Flag HIGH for 1 clock when reading from GPU RAM
end
if (z80_read_memory && mem_in_bank && ~mem_in_range ) begin // memory read outside memory range, but inside the bank. Return BANK_ID
Z80_rData <= BANK_ID[Z80_addr_r[3:0]];
Z80_245data_dir <= data_out;
Z80_rData_ena <= 1'b1 ;
Z80_245_oe <= 1'b0 ;
end
if (z80_read_memory && mem_in_bank && mem_in_range && gpu_rd_rdy ) begin // if a valid read memory range and the GUP returns a gpu_rd_rdy, send out data
Z80_rData <= gpu_rData ;
Z80_245data_dir <= data_out;
Z80_rData_ena <= 1'b1 ;
Z80_245_oe <= 1'b0 ;
end
You should begin on making the single line engine into a channel 4-line engine. Then you will make the drawn triangle filled triangle commands.
Try making all the line's registers [3:0] / 4 slot arrays.
This also means when running a line, you draw a single pixel of a single line, 1 at a time, or select a few in sequence.
Also think of the sub-routine steps to run and stop each line or part of a line.
Please test the attached updated 'FIFO_3word_0_latency.sv'. If it works, please update all your project folders with the new version.
Wanted to ask a question re: BGA soldering to anyone reading this, really. Bearing in mind I'm looking to fabricate a PCB for the EP4CE22F17 (256-fBGA with 1mm pitch), is it necessary to have a pre-heater or some form of board heater to use in addition with the hot air gun to solder the BGA effectively? I don't have an expensive hot air gun - it's a pretty cheap one to be honest, but has served me well so far soldering the EQFP-144 packages.
Is pre-heating (is that the right term?) necessary? Could I just get away with hot-air soldering the BGA onto the PCB in a skillet over the cooker, if necessary?
Have you tried to figure out how to draw a filled triangle, why it needs 3 running lines.
Try to make a working one in the FreeBasic geo.bas and show it to me.
When I said 3 lines for triangle, a hint would be that 1 line is always re-drawing with a new start and stop coordinates every time it finishes.
Now, what are the other 2 line drawing engines doing?
Can this still work for fill 4 coordinate geometric shapes as well?
When I said 3 lines for triangle, a hint would be that 1 line is always re-drawing with a new start and stop coordinates every time it finishes.
So one line draws the perimeter of the triangle? It would draw a line from x0,y0 to x1,y1, then from x1,y1 to x2,y2, then from x2,y2 to x0,y0?Now, what are the other 2 line drawing engines doing?
Supervising the work of the first one?
Erm... a random guess would be filling the shape - one engine to each half (top/bottom) of the shape??Can this still work for fill 4 coordinate geometric shapes as well?
I suppose so. A 4-coordinate geometric shape is just a compound shape made of two triangles.
None of the suggested methods for filling a triangle sounds like the way I would do it, which is this:
Let A, B, C be the vertices in order from top to bottom. Initialise two line generators, L1 from A to B and L2 from A to C. Step them both together vertically and fill horizontal rows between L1 and L2 at each step. When L1 reaches B, reset it to go from B to C and continue.
This method only requires two line generators, and has the advantage that it writes consecutive pixels horizontally, which could be important if your graphics memory benefits from burst accesses. It also doesn't rely on adjacent non-axis-aligned lines fitting together perfectly without leaving gaps.
Polygons with more than three vertices can be handled by dividing them into triangles. This is probably best done in software rather than trying to make the hardware do it.