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

0 Members and 2 Guests are viewing this topic.

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #850 on: January 05, 2020, 12:15:28 pm »
Upload the latest copy of what you are compiling with...

Attached is latest copy of the project with all the changes made yesterday.
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #851 on: January 05, 2020, 12:25:35 pm »
Ok.  Without superimposed multichannel scope shots, I cant tell if all your addresses are properly being asserted at the same time or not.

If you have a logic analyzer, you will want one with a good 100MHz sampling rate on at least half the data and and the first addresses + buss control signals, including the 'WAIT' states which may be asserted by a third device on the bus.

My scope is next to useless for digital testing and my logic analyser isn't really up to that sort of work - it's just an 8-channel 25 MHz 'cheapy' off eBay.  It's served me just fine building the Microcom, but we're well out of '8 MHz-league', here.

I have a bit of time right now, so I'm going to try and sort the address bus and get those offending lanes moved to fast-input pins.

I made the current code sample the address at the fall of MREQn, after the fall of MREQ_DLY_CLK which run at 125MHz.

I downloaded the newer Zlog Z80 documents which have the 8/10/20 MHz variants included.  The bus transactions and timing is not as simple as that old dumb 4MHz data sheet.  The MREQn going up and down between bus cycles is not guaranteed, or, it can be such a small value in NS, that unless we make a true static interface, or a proper synchronous interface, things will go haywire.  Also, there are other cycles right after transactions, like refresh cycles, or program code fetch which may also hold or shrink the MREQn.

It's not that the interface needs to be any more complicated that it is, it that I cannot see what is going on remotely and 95% of the Z80 docs out there assume a cheap static type design.  And with you bread board wiring & choice of voltage level shifting, and choice of IOs, I'm not sure where the true problem is creeping in.

I know, it's a haystack and there's probably some fake needles in there to confuse things as well.  Is there a better way of doing the voltage level shifting then?  I'm always open to suggestions and guidance!
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7725
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #852 on: January 05, 2020, 12:48:46 pm »
Without seeing, I have nothing to go on.

Try changing these 2 values:
Also try these parameter settings:

parameter DELAY_CYCLES  = 0;      // number of cycles to delay write for 245
parameter MREQ_DLY_CLK  = 0;      // number of cycles +1 to delay mreq trigger

This should accelerate the response.  If it doesn't work, we can try full static approach.  However, this isn't too wise a strategy for future upgrade.


Also, you shouldn't use pins 88,89,90,91 for your addresses.  Please move them.
For these pins, you should only use them for Z80_CLK, only, or you may also tie MREQ, RD, WR to these pins as well.  They are dedicated inputs and their timing to logic cells slightly differs to the main IOs where the rest of the addresses are wired.

This is important especially if we want to clock off of the Z80_CLK input.

Also, in assignment settings, compiler settings, 'Advanced Settings (Fitter)...', please turn on :
Perform Register Retiming For Performance.

PLEASE SWAP THE INPUT PINS LIKE I SAID...

« Last Edit: January 05, 2020, 12:56:08 pm by BrianHG »
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7725
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #853 on: January 05, 2020, 01:06:49 pm »

I know, it's a haystack and there's probably some fake needles in there to confuse things as well.  Is there a better way of doing the voltage level shifting then?  I'm always open to suggestions and guidance!
Its more than just level shifting.  With a bread board and 1 GND wire to something like 35 signal wires, do you have proper signal termination?
What does your signal bounce look like?  The FPGA is still sensitive to signals in the 100MHz to 200MHz range even though the Z80 may only be sensitive to 20MHz.

When you build a PCB, will you be able to do proper resistor series and parallel termination on the right sides of the CMOS buffers?
Can you measure the signal bounce?

Without the above question being answered, you may want to use series resistor packs in dip or sip form so you may insert alternate values, or, you will have to design a quality layout PCB, with more than 1 GND wire going to the Z80...
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #854 on: January 05, 2020, 02:03:51 pm »
Without seeing, I have nothing to go on.

Try changing these 2 values:
Also try these parameter settings:

parameter DELAY_CYCLES  = 0;      // number of cycles to delay write for 245
parameter MREQ_DLY_CLK  = 0;      // number of cycles +1 to delay mreq trigger

Okay, that's done, but shouldn't there be some delay for the 245 to enable?

Also, you shouldn't use pins 88,89,90,91 for your addresses.  Please move them.
For these pins, you should only use them for Z80_CLK, only, or you may also tie MREQ, RD, WR to these pins as well.  They are dedicated inputs and their timing to logic cells slightly differs to the main IOs where the rest of the addresses are wired.

This is important especially if we want to clock off of the Z80_CLK input.

Okay, the offending address lanes have been moved to alternate input pins (84, 86, 105 & 106) - I've moved the Z80_CLK line to pin 90.

Also, in assignment settings, compiler settings, 'Advanced Settings (Fitter)...', please turn on :
Perform Register Retiming For Performance.

Done.  Am just testing the output now - seems with DELAY_CYCLES set to zero and MREQ_DLY_CLK set to zero, I'm unable to read or write to the GPU RAM, although the Microcom was stable.  Have just tried it with DELAY_CYCLES back to 2, that wasn't good - Microcom wouldn't boot into the DMI (where the GPU is set up) without locking up and the GPU RAM being corrupted.
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #855 on: January 05, 2020, 02:10:29 pm »
Its more than just level shifting.  With a bread board and 1 GND wire to something like 35 signal wires, do you have proper signal termination?
What does your signal bounce look like?  The FPGA is still sensitive to signals in the 100MHz to 200MHz range even though the Z80 may only be sensitive to 20MHz.

When you build a PCB, will you be able to do proper resistor series and parallel termination on the right sides of the CMOS buffers?
Can you measure the signal bounce?

Without the above question being answered, you may want to use series resistor packs in dip or sip form so you may insert alternate values, or, you will have to design a quality layout PCB, with more than 1 GND wire going to the Z80...

Aaaaaand it's at this point I realise I'm in waaaay over my head!   :o :o :o ???

How do you prototype circuits that run at silly speeds (100MHz+) if breadboard (clearly) isn't up to the task?
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7725
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #856 on: January 05, 2020, 02:14:19 pm »
Ok, this one is static read, one shot write:

Code: [Select]
module Z80_bridge (

// input
input wire reset, // GPU reset signal
input wire GPU_CLK, // GPU clock (125 MHz)
input wire Z80_CLK, // Microcom clock signal (8 MHz)
input wire Z80_M1n, // Z80 M1 - active LOW
input wire Z80_MREQn, // Z80 MREQ - active LOW
input wire Z80_WRn, // Z80 WR - active LOW
input wire Z80_RDn, // Z80 RD - active LOW
input wire [21:0] Z80_addr, // Microcom 22-bit address bus
input wire [7:0] Z80_wData, // Z80 DATA bus to pass incoming data to GPU RAM
input wire [7:0] gpu_rData,
input wire gpu_rd_rdy, // one-shot signal from mux that data is ready

// output
output reg Z80_245data_dir, // control level converter direction for data flow - HIGH = A -> B (toward FPGA)
output reg [7:0]  Z80_rData, // Z80 DATA bus to return data from GPU RAM to Z80
output reg Z80_rData_ena, // flag HIGH to write data back to Z80
output reg Z80_245_oe, // OE for 245 level translator *** ACTIVE LOW ***
output reg gpu_wr_ena, // flag HIGH for 1 clock when writing to GPU RAM
output reg gpu_rd_req, // flag HIGH for 1 clock when reading from GPU RAM
output reg [19:0] gpu_addr, // connect to Z80_addr in vid_osd_generator to address GPU RAM
output reg [7:0]  gpu_wdata, // 8-bit data bus to GPU RAM in vid_osd_generator

    input wire  sel_pclk,  // make HIGH to trigger the Z80 bus on the positive edge of Z80_CLK
    input wire  sel_nclk   // make LOW  to trigger the Z80 bus on the negative edge of Z80_CLK
);

// TODO:
//
// 1) Prevent reads to GPU RAM above top of GPU RAM
// 2) Respond with appropriate data to any requests from Microcom ROM identification routines
//

parameter MEMORY_RANGE  = 3'b010; // Z80_addr[21:19] == 3'b010 targets the 512KB 'window' at 0x100000-0x17FFFF (Socket 3 on the Microcom)
parameter DELAY_CYCLES  = 2; // number of cycles to delay write for 245
parameter MEM_SIZE_BITS = 15; //
parameter MREQ_DLY_CLK  = 2; // number of cycles +1 to delay mreq trigger

wire Z80_mreq, Z80_mreq_pulse, Z80_unmreq_pulse, Z80_write, Z80_read, Write_GPU_RAM;
wire Read_GPU_RAM_BEGIN, Read_GPU_RAM_END;
wire Z80_clk_pos,Z80_clk_neg,Z80_clk_trig;

reg Z80_clk_delay, last_Z80_WR, last_Z80_RD, mem_valid_range, MREQn_dly, MREQn_dly2, mem_window ;
reg [9:0] Z80_write_sequencer,Z80_mreq_dly;



assign Z80_clk_pos   = ~Z80_clk_delay &&  Z80_CLK;
assign Z80_clk_neg   =  Z80_clk_delay && ~Z80_CLK;
assign Z80_clk_trig  = (Z80_clk_pos && sel_pclk) || (Z80_clk_neg && ~sel_nclk);


assign Z80_mreq_pulse = ~Z80_mreq_dly[MREQ_DLY_CLK] && Z80_mreq_dly[MREQ_DLY_CLK+1];
assign Z80_unmreq_pulse = Z80_mreq_dly[MREQ_DLY_CLK] && ~Z80_mreq_dly[MREQ_DLY_CLK+1];
assign Z80_mreq     = ~Z80_mreq_dly[MREQ_DLY_CLK+1] && Z80_M1n; // Define a bus memory access state
assign Z80_write = ~Z80_WRn && last_Z80_WR; // Isolate a single write transaction
assign Z80_read     = ~Z80_RDn; // Isolate a single read transaction
assign Z80_readn     =  Z80_RDn && ~last_Z80_RD; // Isolate a single read transaction

assign Write_GPU_RAM =  mem_window && Z80_mreq && Z80_write && mem_valid_range; // Define a GPU Write action - only write to address within GPU RAM bounds
assign Read_GPU_RAM_BEGIN =  mem_window && Z80_mreq && Z80_read && mem_valid_range;   // Define the beginning of a Z80 read request of GPU Ram.
assign Read_GPU_RAM_END =  Z80_readn ;   // Define the ending of a Z80 read request of GPU Ram.

// **********************************************************************************************************

always @ (posedge GPU_CLK) begin

Z80_mreq_dly[9:0] <= { Z80_mreq_dly[8:0], Z80_MREQn };

//if (Z80_mreq_pulse) begin
gpu_addr         <=  Z80_addr[18:0];                         // latch address bus onto GPU address bus
mem_valid_range  <= (Z80_addr[18:0]  <  2**MEM_SIZE_BITS); // Define GPU addressable memory space
mem_window   <= (Z80_addr[21:19] == MEMORY_RANGE); // Define an active memory range
//end else if (Z80_unmreq_pulse) begin
// mem_valid_range  <= 1'b0; // Define GPU addressable memory space
// mem_window   <= 1'b0; // Define an active memory range
//end



Z80_write_sequencer[9:0] <= { Z80_write_sequencer[8:0], Write_GPU_RAM };

if ( Z80_write_sequencer[0] )                 Z80_245data_dir  <= 1'b1; // set 245 dir toward FPGA
if ( Z80_write_sequencer[0] )                 Z80_rData_ena    <= 1'b0; // set FPGA pins to input (should be by default)
if ( Z80_write_sequencer[0] )                 Z80_245_oe       <= 1'b0; // enable 245 output (WAS 1 - moved forward to step 0)

if ( Z80_write_sequencer[DELAY_CYCLES] )  gpu_wdata        <= Z80_wData; // latch data bus onto GPU data bus
if ( Z80_write_sequencer[DELAY_CYCLES] )  gpu_wr_ena       <= 1'b1; // turn on FPGA RAM we

if ( Z80_write_sequencer[DELAY_CYCLES + 2] )  gpu_wr_ena       <= 1'b0; // turn off FPGA RAM we (WAS STEP +2, now STEP +3 for additional WR)
if ( Z80_write_sequencer[DELAY_CYCLES + 2] )  Z80_245_oe <= 1'b1; // disable 245 output

if ( Read_GPU_RAM_BEGIN ) begin

gpu_rd_req <= 1'b1; // flag a read request to the mux which is one-shotted in the mux
Z80_245data_dir <= 1'b0; // set 245 direction (TO Z80)
Z80_245_oe <= 1'b0; // enable 245 output
Z80_rData_ena    <= 1'b1; // set bidir pins to output


end else begin
gpu_rd_req <= 1'b0; // end GPU read req after 1 pulse

//if ( Read_GPU_RAM_END ) begin
Z80_rData_ena <= 1'b0; // re-set bidir pins to input
   Z80_245_oe <= 1'b1; // disable 245 output
// end
end

if ( gpu_rd_rdy ) begin
if (mem_valid_range) Z80_rData[7:0] <= gpu_rData[7:0];// Latch the GPU RAM read into the output register for the Z80
else Z80_rData[7:0]  <= 8'b11111111; // return $FF if addressed byte is outside the GPU's upper RAM limit
end


last_Z80_WR <= Z80_WRn;
last_Z80_RD <= Z80_RDn;
Z80_clk_delay <= Z80_CLK; // find the rising clock edge

end

// **********************************************************************************************************

endmodule


Change the 2 delay parameters to 0, then try 1 and 2.  The parameters should only effect the writes.

Also, if your get timing violations, IE an FMAX too low, disable the 'register retiming' feature I told you to turn on earlier.
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7725
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #857 on: January 05, 2020, 02:20:17 pm »
Its more than just level shifting.  With a bread board and 1 GND wire to something like 35 signal wires, do you have proper signal termination?
What does your signal bounce look like?  The FPGA is still sensitive to signals in the 100MHz to 200MHz range even though the Z80 may only be sensitive to 20MHz.

When you build a PCB, will you be able to do proper resistor series and parallel termination on the right sides of the CMOS buffers?
Can you measure the signal bounce?

Without the above question being answered, you may want to use series resistor packs in dip or sip form so you may insert alternate values, or, you will have to design a quality layout PCB, with more than 1 GND wire going to the Z80...

Aaaaaand it's at this point I realise I'm in waaaay over my head!   :o :o :o ???

How do you prototype circuits that run at silly speeds (100MHz+) if breadboard (clearly) isn't up to the task?
Good thick grounding wiring.  Decoupling caps everywhere, and, wire-wrap or soldered prototype boards usually do the trick.
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7725
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #858 on: January 05, 2020, 02:28:01 pm »
Ooops, logic bomb on the 245 controls during write.  Here is the fix:

Code: [Select]
module Z80_bridge (

// input
input wire reset, // GPU reset signal
input wire GPU_CLK, // GPU clock (125 MHz)
input wire Z80_CLK, // Microcom clock signal (8 MHz)
input wire Z80_M1n, // Z80 M1 - active LOW
input wire Z80_MREQn, // Z80 MREQ - active LOW
input wire Z80_WRn, // Z80 WR - active LOW
input wire Z80_RDn, // Z80 RD - active LOW
input wire [21:0] Z80_addr, // Microcom 22-bit address bus
input wire [7:0] Z80_wData, // Z80 DATA bus to pass incoming data to GPU RAM
input wire [7:0] gpu_rData,
input wire gpu_rd_rdy, // one-shot signal from mux that data is ready

// output
output reg Z80_245data_dir, // control level converter direction for data flow - HIGH = A -> B (toward FPGA)
output reg [7:0]  Z80_rData, // Z80 DATA bus to return data from GPU RAM to Z80
output reg Z80_rData_ena, // flag HIGH to write data back to Z80
output reg Z80_245_oe, // OE for 245 level translator *** ACTIVE LOW ***
output reg gpu_wr_ena, // flag HIGH for 1 clock when writing to GPU RAM
output reg gpu_rd_req, // flag HIGH for 1 clock when reading from GPU RAM
output reg [19:0] gpu_addr, // connect to Z80_addr in vid_osd_generator to address GPU RAM
output reg [7:0]  gpu_wdata, // 8-bit data bus to GPU RAM in vid_osd_generator

    input wire  sel_pclk,  // make HIGH to trigger the Z80 bus on the positive edge of Z80_CLK
    input wire  sel_nclk   // make LOW  to trigger the Z80 bus on the negative edge of Z80_CLK
);

// TODO:
//
// 1) Prevent reads to GPU RAM above top of GPU RAM
// 2) Respond with appropriate data to any requests from Microcom ROM identification routines
//

parameter MEMORY_RANGE  = 3'b010; // Z80_addr[21:19] == 3'b010 targets the 512KB 'window' at 0x100000-0x17FFFF (Socket 3 on the Microcom)
parameter DELAY_CYCLES  = 2; // number of cycles to delay write for 245
parameter MEM_SIZE_BITS = 15; //
parameter MREQ_DLY_CLK  = 2; // number of cycles +1 to delay mreq trigger

wire Z80_mreq, Z80_mreq_pulse, Z80_unmreq_pulse, Z80_write, Z80_read, Write_GPU_RAM;
wire Read_GPU_RAM_BEGIN, Read_GPU_RAM_END;
wire Z80_clk_pos,Z80_clk_neg,Z80_clk_trig;

reg Z80_clk_delay, last_Z80_WR, last_Z80_RD, mem_valid_range, MREQn_dly, MREQn_dly2, mem_window ;
reg [9:0] Z80_write_sequencer,Z80_mreq_dly;



assign Z80_clk_pos   = ~Z80_clk_delay &&  Z80_CLK;
assign Z80_clk_neg   =  Z80_clk_delay && ~Z80_CLK;
assign Z80_clk_trig  = (Z80_clk_pos && sel_pclk) || (Z80_clk_neg && ~sel_nclk);


assign Z80_mreq_pulse = ~Z80_mreq_dly[MREQ_DLY_CLK] && Z80_mreq_dly[MREQ_DLY_CLK+1];
assign Z80_unmreq_pulse = Z80_mreq_dly[MREQ_DLY_CLK] && ~Z80_mreq_dly[MREQ_DLY_CLK+1];
assign Z80_mreq     = ~Z80_mreq_dly[MREQ_DLY_CLK+1] && Z80_M1n; // Define a bus memory access state
assign Z80_write = ~Z80_WRn && last_Z80_WR; // Isolate a single write transaction
assign Z80_read     = ~Z80_RDn; // Isolate a single read transaction
assign Z80_readn     =  Z80_RDn && ~last_Z80_RD; // Isolate a single read transaction

assign Write_GPU_RAM =  mem_window && Z80_mreq && Z80_write && mem_valid_range; // Define a GPU Write action - only write to address within GPU RAM bounds
assign Read_GPU_RAM_BEGIN =  mem_window && Z80_mreq && Z80_read && mem_valid_range;   // Define the beginning of a Z80 read request of GPU Ram.
assign Read_GPU_RAM_END =  Z80_readn ;   // Define the ending of a Z80 read request of GPU Ram.

// **********************************************************************************************************

always @ (posedge GPU_CLK) begin

Z80_mreq_dly[9:0] <= { Z80_mreq_dly[8:0], Z80_MREQn };

//if (Z80_mreq_pulse) begin
gpu_addr         <=  Z80_addr[18:0];                         // latch address bus onto GPU address bus
mem_valid_range  <= (Z80_addr[18:0]  <  2**MEM_SIZE_BITS); // Define GPU addressable memory space
mem_window   <= (Z80_addr[21:19] == MEMORY_RANGE); // Define an active memory range
//end else if (Z80_unmreq_pulse) begin
// mem_valid_range  <= 1'b0; // Define GPU addressable memory space
// mem_window   <= 1'b0; // Define an active memory range
//end



Z80_write_sequencer[9:0] <= { Z80_write_sequencer[8:0], Write_GPU_RAM };

if ( Z80_write_sequencer[0] )                 Z80_245data_dir  <= 1'b1; // set 245 dir toward FPGA
if ( Z80_write_sequencer[0] )                 Z80_rData_ena    <= 1'b0; // set FPGA pins to input (should be by default)
if ( Z80_write_sequencer[0] )                 Z80_245_oe       <= 1'b0; // enable 245 output (WAS 1 - moved forward to step 0)

if ( Z80_write_sequencer[DELAY_CYCLES] )  gpu_wdata        <= Z80_wData; // latch data bus onto GPU data bus
if ( Z80_write_sequencer[DELAY_CYCLES] )  gpu_wr_ena       <= 1'b1; // turn on FPGA RAM we

if ( Z80_write_sequencer[DELAY_CYCLES + 2] )  gpu_wr_ena       <= 1'b0; // turn off FPGA RAM we (WAS STEP +2, now STEP +3 for additional WR)
if ( Z80_write_sequencer[DELAY_CYCLES + 2] )  Z80_245_oe <= 1'b1; // disable 245 output

if ( Read_GPU_RAM_BEGIN && Z80_WRn ) begin

gpu_rd_req <= 1'b1; // flag a read request to the mux which is one-shotted in the mux
Z80_245data_dir <= 1'b0; // set 245 direction (TO Z80)
Z80_245_oe <= 1'b0; // enable 245 output
Z80_rData_ena    <= 1'b1; // set bidir pins to output


end else begin
gpu_rd_req <= 1'b0; // end GPU read req after 1 pulse

if ( Z80_WRn ) begin
Z80_rData_ena <= 1'b0; // re-set bidir pins to input
   Z80_245_oe <= 1'b1; // disable 245 output
end
end

if ( gpu_rd_rdy ) begin
if (mem_valid_range) Z80_rData[7:0] <= gpu_rData[7:0];// Latch the GPU RAM read into the output register for the Z80
else Z80_rData[7:0]  <= 8'b11111111; // return $FF if addressed byte is outside the GPU's upper RAM limit
end


last_Z80_WR <= Z80_WRn;
last_Z80_RD <= Z80_RDn;
Z80_clk_delay <= Z80_CLK; // find the rising clock edge

end

// **********************************************************************************************************

endmodule


Delay cycles needs to be at least 2.
« Last Edit: January 05, 2020, 02:30:09 pm by BrianHG »
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #859 on: January 05, 2020, 02:42:04 pm »
How do you prototype circuits that run at silly speeds (100MHz+) if breadboard (clearly) isn't up to the task?

Good thick grounding wiring.  Decoupling caps everywhere, and, wire-wrap or soldered prototype boards usually do the trick.

Everything has decoupling caps - all the chips on the breadboard are decoupled (I'm using SOIC->DIP converters with a 100nF cap on the mini-PCB).  There's two GND wires now (yay!) connecting the breadboard to both the FPGA and the Microcom.

Am just testing the delay settings now:

Both DLY valuse set to 0: Reading the GPU RAM caused a system crash.  Timing's definitely out on the 245, I presume.

Both DLY values set to 1: Writing any value to the GPU RAM writes $FF to that location.  Any read crashes the system.

Both DLY values set to 2: Writing any value to the GPU RAM writes $FF to that location.  Any read crashes the system.

EDIT: Just spotted your last post! Above results don't take that into account.
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7725
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #860 on: January 05, 2020, 02:50:34 pm »
Ooops, accidentally delaying the 'MREQ'.  Ok, this one should work and not crash the system.

Code: [Select]
module Z80_bridge (

// input
input wire reset, // GPU reset signal
input wire GPU_CLK, // GPU clock (125 MHz)
input wire Z80_CLK, // Microcom clock signal (8 MHz)
input wire Z80_M1n, // Z80 M1 - active LOW
input wire Z80_MREQn, // Z80 MREQ - active LOW
input wire Z80_WRn, // Z80 WR - active LOW
input wire Z80_RDn, // Z80 RD - active LOW
input wire [21:0] Z80_addr, // Microcom 22-bit address bus
input wire [7:0] Z80_wData, // Z80 DATA bus to pass incoming data to GPU RAM
input wire [7:0] gpu_rData,
input wire gpu_rd_rdy, // one-shot signal from mux that data is ready

// output
output reg Z80_245data_dir, // control level converter direction for data flow - HIGH = A -> B (toward FPGA)
output reg [7:0]  Z80_rData, // Z80 DATA bus to return data from GPU RAM to Z80
output reg Z80_rData_ena, // flag HIGH to write data back to Z80
output reg Z80_245_oe, // OE for 245 level translator *** ACTIVE LOW ***
output reg gpu_wr_ena, // flag HIGH for 1 clock when writing to GPU RAM
output reg gpu_rd_req, // flag HIGH for 1 clock when reading from GPU RAM
output reg [19:0] gpu_addr, // connect to Z80_addr in vid_osd_generator to address GPU RAM
output reg [7:0]  gpu_wdata, // 8-bit data bus to GPU RAM in vid_osd_generator

    input wire  sel_pclk,  // make HIGH to trigger the Z80 bus on the positive edge of Z80_CLK
    input wire  sel_nclk   // make LOW  to trigger the Z80 bus on the negative edge of Z80_CLK
);

// TODO:
//
// 1) Prevent reads to GPU RAM above top of GPU RAM
// 2) Respond with appropriate data to any requests from Microcom ROM identification routines
//

parameter MEMORY_RANGE  = 3'b010; // Z80_addr[21:19] == 3'b010 targets the 512KB 'window' at 0x100000-0x17FFFF (Socket 3 on the Microcom)
parameter DELAY_CYCLES  = 2; // number of cycles to delay write for 245
parameter MEM_SIZE_BITS = 15; //
parameter MREQ_DLY_CLK  = 2; // number of cycles +1 to delay mreq trigger

wire Z80_mreq, Z80_mreq_pulse, Z80_unmreq_pulse, Z80_write, Z80_read, Write_GPU_RAM;
wire Read_GPU_RAM_BEGIN, Read_GPU_RAM_END;
wire Z80_clk_pos,Z80_clk_neg,Z80_clk_trig;

reg Z80_clk_delay, last_Z80_WR, last_Z80_RD, mem_valid_range, MREQn_dly, MREQn_dly2, mem_window ;
reg [9:0] Z80_write_sequencer,Z80_mreq_dly;



assign Z80_clk_pos   = ~Z80_clk_delay &&  Z80_CLK;
assign Z80_clk_neg   =  Z80_clk_delay && ~Z80_CLK;
assign Z80_clk_trig  = (Z80_clk_pos && sel_pclk) || (Z80_clk_neg && ~sel_nclk);


assign Z80_mreq_pulse = ~Z80_mreq_dly[MREQ_DLY_CLK] && Z80_mreq_dly[MREQ_DLY_CLK+1];
assign Z80_unmreq_pulse = Z80_mreq_dly[MREQ_DLY_CLK] && ~Z80_mreq_dly[MREQ_DLY_CLK+1];
assign Z80_mreq     = ~Z80_MREQn && Z80_M1n; // Define a bus memory access state
assign Z80_write = ~Z80_WRn && last_Z80_WR; // Isolate a single write transaction
assign Z80_read     = ~Z80_RDn; // Isolate a single read transaction
assign Z80_readn     =  Z80_RDn && ~last_Z80_RD; // Isolate a single read transaction

assign Write_GPU_RAM =  mem_window && Z80_mreq && Z80_write && mem_valid_range; // Define a GPU Write action - only write to address within GPU RAM bounds
assign Read_GPU_RAM_BEGIN =  mem_window && Z80_mreq && Z80_read && mem_valid_range;   // Define the beginning of a Z80 read request of GPU Ram.
assign Read_GPU_RAM_END =  Z80_readn ;   // Define the ending of a Z80 read request of GPU Ram.

// **********************************************************************************************************

always @ (posedge GPU_CLK) begin

Z80_mreq_dly[9:0] <= { Z80_mreq_dly[8:0], Z80_MREQn };

//if (Z80_mreq_pulse) begin
gpu_addr         <=  Z80_addr[18:0];                         // latch address bus onto GPU address bus
mem_valid_range  <= (Z80_addr[18:0]  <  2**MEM_SIZE_BITS); // Define GPU addressable memory space
mem_window   <= (Z80_addr[21:19] == MEMORY_RANGE); // Define an active memory range
//end else if (Z80_unmreq_pulse) begin
// mem_valid_range  <= 1'b0; // Define GPU addressable memory space
// mem_window   <= 1'b0; // Define an active memory range
//end



Z80_write_sequencer[9:0] <= { Z80_write_sequencer[8:0], Write_GPU_RAM };

if ( Z80_write_sequencer[0] )                 Z80_245data_dir  <= 1'b1; // set 245 dir toward FPGA
if ( Z80_write_sequencer[0] )                 Z80_rData_ena    <= 1'b0; // set FPGA pins to input (should be by default)
if ( Z80_write_sequencer[0] )                 Z80_245_oe       <= 1'b0; // enable 245 output (WAS 1 - moved forward to step 0)

if ( Z80_write_sequencer[DELAY_CYCLES] )  gpu_wdata        <= Z80_wData; // latch data bus onto GPU data bus
if ( Z80_write_sequencer[DELAY_CYCLES] )  gpu_wr_ena       <= 1'b1; // turn on FPGA RAM we

if ( Z80_write_sequencer[DELAY_CYCLES + 2] )  gpu_wr_ena       <= 1'b0; // turn off FPGA RAM we (WAS STEP +2, now STEP +3 for additional WR)
if ( Z80_write_sequencer[DELAY_CYCLES + 2] )  Z80_245_oe <= 1'b1; // disable 245 output

if ( Read_GPU_RAM_BEGIN && Z80_WRn ) begin

gpu_rd_req <= 1'b1; // flag a read request to the mux which is one-shotted in the mux
Z80_245data_dir <= 1'b0; // set 245 direction (TO Z80)
Z80_245_oe <= 1'b0; // enable 245 output
Z80_rData_ena    <= 1'b1; // set bidir pins to output


end else begin
gpu_rd_req <= 1'b0; // end GPU read req after 1 pulse

if ( Z80_WRn ) begin
Z80_rData_ena <= 1'b0; // re-set bidir pins to input
   Z80_245_oe <= 1'b1; // disable 245 output
end
end

if ( gpu_rd_rdy ) begin
if (mem_valid_range) Z80_rData[7:0] <= gpu_rData[7:0];// Latch the GPU RAM read into the output register for the Z80
else Z80_rData[7:0]  <= 8'b11111111; // return $FF if addressed byte is outside the GPU's upper RAM limit
end


last_Z80_WR <= Z80_WRn;
last_Z80_RD <= Z80_RDn;
Z80_clk_delay <= Z80_CLK; // find the rising clock edge

end

// **********************************************************************************************************

endmodule
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #861 on: January 05, 2020, 03:13:05 pm »
Okay, with that latest update:

 DELAY_CYCLES  |   MREQ_DLY_CLK   |  RESULTS
-------------------+----------------------+----------------------------------------------------------------------
          2             |              2              | Unstable. Crash on read. Write only writes $FF to GPU RAM.
          2             |              1              | Unstable. Crash on read. Write only writes $FF to GPU RAM.
          2             |              0              | Unstable. Crash on read. Write only writes $FF to GPU RAM.

1) When I've tried writing, I've tried values $00, $55, $AA, $01 etc. to a variety of addresses across the entire first page of GPU RAM.

2) Unstable means it's taken a couple of resets to get the Microcom's Bootstrap to show on the console.  The Bootstrap does nothing to the GPU, other than a quick write/read loop through all the banks of memory to ascertain what's RAM and what's ROM.  It's most likely the read part of that routine that is causing the crash when it tries to write to, then read from the GPU memory.

3) All attempts to read data manually (via the PEEK command) have resulted in a crash.

Should I start increasing the DLY values?
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7725
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #862 on: January 05, 2020, 03:33:55 pm »
Seriously man, the read shouldn't be able to crash.  The read delay is being ignored.  It only delays the write capture of the Z80's data output.

Try this:
Code: [Select]
module Z80_bridge (

// input
input wire reset, // GPU reset signal
input wire GPU_CLK, // GPU clock (125 MHz)
input wire Z80_CLK, // Microcom clock signal (8 MHz)
input wire Z80_M1n, // Z80 M1 - active LOW
input wire Z80_MREQn, // Z80 MREQ - active LOW
input wire Z80_WRn, // Z80 WR - active LOW
input wire Z80_RDn, // Z80 RD - active LOW
input wire [21:0] Z80_addr, // Microcom 22-bit address bus
input wire [7:0] Z80_wData, // Z80 DATA bus to pass incoming data to GPU RAM
input wire [7:0] gpu_rData,
input wire gpu_rd_rdy, // one-shot signal from mux that data is ready

// output
output reg Z80_245data_dir, // control level converter direction for data flow - HIGH = A -> B (toward FPGA)
output reg [7:0]  Z80_rData, // Z80 DATA bus to return data from GPU RAM to Z80
output reg Z80_rData_ena, // flag HIGH to write data back to Z80
output reg Z80_245_oe, // OE for 245 level translator *** ACTIVE LOW ***
output reg gpu_wr_ena, // flag HIGH for 1 clock when writing to GPU RAM
output reg gpu_rd_req, // flag HIGH for 1 clock when reading from GPU RAM
output reg [19:0] gpu_addr, // connect to Z80_addr in vid_osd_generator to address GPU RAM
output reg [7:0]  gpu_wdata, // 8-bit data bus to GPU RAM in vid_osd_generator

    input wire  sel_pclk,  // make HIGH to trigger the Z80 bus on the positive edge of Z80_CLK
    input wire  sel_nclk   // make LOW  to trigger the Z80 bus on the negative edge of Z80_CLK
);

// TODO:
//
// 1) Prevent reads to GPU RAM above top of GPU RAM
// 2) Respond with appropriate data to any requests from Microcom ROM identification routines
//

parameter MEMORY_RANGE  = 3'b010; // Z80_addr[21:19] == 3'b010 targets the 512KB 'window' at 0x100000-0x17FFFF (Socket 3 on the Microcom)
parameter DELAY_CYCLES  = 2; // number of cycles to delay write for 245
parameter MEM_SIZE_BITS = 15; //
parameter MREQ_DLY_CLK  = 2; // number of cycles +1 to delay mreq trigger

wire Z80_mreq, Z80_mreq_pulse, Z80_unmreq_pulse, Z80_write, Z80_read, Write_GPU_RAM;
wire Read_GPU_RAM_BEGIN, Read_GPU_RAM_END;
wire Z80_clk_pos,Z80_clk_neg,Z80_clk_trig;

reg Z80_clk_delay, last_Z80_WR, last_Z80_RD, mem_valid_range, MREQn_dly, MREQn_dly2, mem_window ;
reg [9:0] Z80_write_sequencer,Z80_mreq_dly;

assign Z80_clk_pos   = ~Z80_clk_delay &&  Z80_CLK;
assign Z80_clk_neg   =  Z80_clk_delay && ~Z80_CLK;
assign Z80_clk_trig  = (Z80_clk_pos && sel_pclk) || (Z80_clk_neg && ~sel_nclk);


assign Z80_mreq     = ~Z80_MREQn && Z80_M1n; // Define a bus memory access state
assign Z80_write = ~Z80_WRn && last_Z80_WR; // Isolate a single write transaction
assign Z80_read     = ~Z80_RDn; // Isolate a single read transaction
assign Z80_readn     =  Z80_RDn && ~last_Z80_RD; // Isolate a single read transaction

assign Write_GPU_RAM =  mem_window && Z80_mreq && Z80_write && mem_valid_range; // Define a GPU Write action - only write to address within GPU RAM bounds
assign Read_GPU_RAM_BEGIN =  mem_window && Z80_mreq && Z80_read  && mem_valid_range;   // Define the beginning of a Z80 read request of GPU Ram.

// **********************************************************************************************************

always @ (posedge GPU_CLK) begin

Z80_mreq_dly[9:0] <= { Z80_mreq_dly[8:0], Z80_MREQn };

//if (Z80_mreq_pulse) begin
gpu_addr         <=  Z80_addr[18:0];                         // latch address bus onto GPU address bus
mem_valid_range  <= (Z80_addr[18:0]  <  2**MEM_SIZE_BITS); // Define GPU addressable memory space
mem_window   <= (Z80_addr[21:19] == MEMORY_RANGE); // Define an active memory range
//end else if (Z80_unmreq_pulse) begin
// mem_valid_range  <= 1'b0; // Define GPU addressable memory space
// mem_window   <= 1'b0; // Define an active memory range
//end



Z80_write_sequencer[9:0] <= { Z80_write_sequencer[8:0], Write_GPU_RAM };

if ( Z80_write_sequencer[0] )                 Z80_245data_dir  <= 1'b1; // set 245 dir toward FPGA
if ( Z80_write_sequencer[0] )                 Z80_rData_ena    <= 1'b0; // set FPGA pins to input (should be by default)
if ( Z80_write_sequencer[0] )                 Z80_245_oe       <= 1'b0; // enable 245 output (WAS 1 - moved forward to step 0)

if ( Z80_write_sequencer[DELAY_CYCLES] )  gpu_wdata        <= Z80_wData; // latch data bus onto GPU data bus
if ( Z80_write_sequencer[DELAY_CYCLES] )  gpu_wr_ena       <= 1'b1; // turn on FPGA RAM we

if ( Z80_write_sequencer[DELAY_CYCLES + 1] )  gpu_wr_ena       <= 1'b0; // turn off FPGA RAM we (WAS STEP +2, now STEP +3 for additional WR)

if ( Read_GPU_RAM_BEGIN ) begin

gpu_rd_req <= 1'b1; // flag a read request to the mux which is one-shotted in the mux
Z80_245data_dir <= 1'b0; // set 245 direction (TO Z80)
Z80_245_oe <= 1'b0; // enable 245 output
Z80_rData_ena    <= 1'b1; // set bidir pins to output


end else begin
gpu_rd_req <= 1'b0; // end GPU read req after 1 pulse
Z80_245data_dir   <= 1'b1; // set 245 dir toward FPGA
Z80_rData_ena <= 1'b0; // re-set bidir pins to input

if ( Z80_WRn ) begin
   //Z80_245_oe <= 1'b1; // disable 245 output
end
end

if ( gpu_rd_rdy ) begin
if (mem_valid_range) Z80_rData[7:0] <= gpu_rData[7:0];// Latch the GPU RAM read into the output register for the Z80
else Z80_rData[7:0]  <= 8'b11111111; // return $FF if addressed byte is outside the GPU's upper RAM limit
end


last_Z80_WR <= Z80_WRn;
last_Z80_RD <= Z80_RDn;
Z80_clk_delay <= Z80_CLK; // find the rising clock edge

end

// **********************************************************************************************************

endmodule


If this one still crashes on read, something went haywire with your wiring changes, or new IO pin assignments, or breadboard wiring contacts.

When single writing, make sure the written 'FF' appear in the correct address.  It would seem your are not outputting the 245 to the GPU FPGA.  This may mean controls to the 245, or it's VCC/GND isn't wired good.
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #863 on: January 05, 2020, 03:59:12 pm »
Seriously man, the read shouldn't be able to crash.  The read delay is being ignored.  It only delays the write capture of the Z80's data output.

Try this:
...

If this one still crashes on read, something went haywire with your wiring changes, or new IO pin assignments, or breadboard wiring contacts.

When single writing, make sure the written 'FF' appear in the correct address.  It would seem your are not outputting the 245 to the GPU FPGA.  This may mean controls to the 245, or it's VCC/GND isn't wired good.

I know, it's weird.  I've had this a lot during development, though, so I almost figure it's normal for electronics development.. I take it that it isn't.  ???  It's likely a loose connection somewhere, which frustrates me even more.

Well, that last update has certainly done something.

Writing to GPU RAM is now a little hit and miss - sometimes characters are dropped for null ($00) values, but infrequently.  I can almost get the DMI boot screen to display, but because of the write errors the Microcom isn't setting up the display properly.  If I load the default values using the RS232_debugger, I can see what I'm writing on the screen (but with the odd dropped character as mentioned previously).

Reading values appears to be solid - even if I 'dump' the entire first page of the GPU RAM to the console/screen, it's reading it accurately.

Here's the settings I'm using for this build:

DELAY_CYCLES  2
MREQ_DLY_CLK 0
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7725
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #864 on: January 05, 2020, 04:04:35 pm »
Increase the delay cycles to 4 or 6 or 8 or 10 or 12.
You may have to increase the delay register size and it's shift register values...

« Last Edit: January 05, 2020, 04:10:53 pm by BrianHG »
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #865 on: January 05, 2020, 04:16:19 pm »
Increase the delay cycles to 4 or 6 or 8 or 10 or 12.
You may have to increase the delay register size and it's shift register values...

Will do - not changing MREQ_DLY_CLK at all, right?
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7725
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #866 on: January 05, 2020, 04:17:53 pm »
Increase the delay cycles to 4 or 6 or 8 or 10 or 12.
You may have to increase the delay register size and it's shift register values...

Will do - not changing MREQ_DLY_CLK at all, right?
Its no longer being used...
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #867 on: January 05, 2020, 04:23:24 pm »
Will do - not changing MREQ_DLY_CLK at all, right?
Its no longer being used...

Aha, okay - removed it from the parameter block then.  Just tried with DELAY_CYCLES set to 4 - still dropping chars, but noticed that the screen actually shifted up a couple of lines when I got to the bottom, with minimal corruption, so it seems we're going in the right direction..  :-+
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7725
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #868 on: January 05, 2020, 04:31:46 pm »
Go to a delay of 8.
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7725
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #869 on: January 05, 2020, 05:15:02 pm »
This version is fully static, the delays are ignored...

Code: [Select]
module Z80_bridge (

// input
input wire reset, // GPU reset signal
input wire GPU_CLK, // GPU clock (125 MHz)
input wire Z80_CLK, // Microcom clock signal (8 MHz)
input wire Z80_M1n, // Z80 M1 - active LOW
input wire Z80_MREQn, // Z80 MREQ - active LOW
input wire Z80_WRn, // Z80 WR - active LOW
input wire Z80_RDn, // Z80 RD - active LOW
input wire [21:0] Z80_addr, // Microcom 22-bit address bus
input wire [7:0] Z80_wData, // Z80 DATA bus to pass incoming data to GPU RAM
input wire [7:0] gpu_rData,
input wire gpu_rd_rdy, // one-shot signal from mux that data is ready

// output
output reg Z80_245data_dir, // control level converter direction for data flow - HIGH = A -> B (toward FPGA)
output reg [7:0]  Z80_rData, // Z80 DATA bus to return data from GPU RAM to Z80
output reg Z80_rData_ena, // flag HIGH to write data back to Z80
output reg Z80_245_oe, // OE for 245 level translator *** ACTIVE LOW ***
output reg gpu_wr_ena, // flag HIGH for 1 clock when writing to GPU RAM
output reg gpu_rd_req, // flag HIGH for 1 clock when reading from GPU RAM
output reg [19:0] gpu_addr, // connect to Z80_addr in vid_osd_generator to address GPU RAM
output reg [7:0]  gpu_wdata, // 8-bit data bus to GPU RAM in vid_osd_generator

    input wire  sel_pclk,  // make HIGH to trigger the Z80 bus on the positive edge of Z80_CLK
    input wire  sel_nclk   // make LOW  to trigger the Z80 bus on the negative edge of Z80_CLK
);

// TODO:
//
// 1) Prevent reads to GPU RAM above top of GPU RAM
// 2) Respond with appropriate data to any requests from Microcom ROM identification routines
//

parameter MEMORY_RANGE  = 3'b010; // Z80_addr[21:19] == 3'b010 targets the 512KB 'window' at 0x100000-0x17FFFF (Socket 3 on the Microcom)
parameter DELAY_CYCLES  = 2; // number of cycles to delay write for 245
parameter MEM_SIZE_BITS = 15; //
parameter MREQ_DLY_CLK  = 2; // number of cycles +1 to delay mreq trigger

wire Z80_mreq, Z80_mreq_pulse, Z80_unmreq_pulse, Z80_write, Z80_read, Write_GPU_RAM;
wire Read_GPU_RAM_BEGIN, Read_GPU_RAM_END;
wire Z80_clk_pos,Z80_clk_neg,Z80_clk_trig;

reg Z80_clk_delay, last_Z80_WR, last_Z80_RD, mem_valid_range, MREQn_dly, MREQn_dly2, mem_window ;
reg [9:0] Z80_write_sequencer,Z80_mreq_dly;

assign Z80_clk_pos   = ~Z80_clk_delay &&  Z80_CLK;
assign Z80_clk_neg   =  Z80_clk_delay && ~Z80_CLK;
assign Z80_clk_trig  = (Z80_clk_pos && sel_pclk) || (Z80_clk_neg && ~sel_nclk);


assign Z80_mreq     = ~Z80_MREQn && Z80_M1n; // Define a bus memory access state
assign Z80_write = ~Z80_WRn ; // && last_Z80_WR; // Isolate a single write transaction

assign Z80_read     = ~Z80_RDn; // Isolate a single read transaction
assign Z80_readn     =  Z80_RDn && ~last_Z80_RD; // Isolate a single read transaction

assign Write_GPU_RAM =  mem_window && Z80_mreq && Z80_write && mem_valid_range; // Define a GPU Write action - only write to address within GPU RAM bounds
assign Read_GPU_RAM_BEGIN =  mem_window && Z80_mreq && Z80_read  && mem_valid_range;   // Define the beginning of a Z80 read request of GPU Ram.

// **********************************************************************************************************

always @ (posedge GPU_CLK) begin

Z80_mreq_dly[9:0] <= { Z80_mreq_dly[8:0], Z80_MREQn };

//if (Z80_mreq_pulse) begin
gpu_addr         <=  Z80_addr[18:0];                         // latch address bus onto GPU address bus
mem_valid_range  <= (Z80_addr[18:0]  <  2**MEM_SIZE_BITS); // Define GPU addressable memory space
mem_window   <= (Z80_addr[21:19] == MEMORY_RANGE); // Define an active memory range
//end else if (Z80_unmreq_pulse) begin
// mem_valid_range  <= 1'b0; // Define GPU addressable memory space
// mem_window   <= 1'b0; // Define an active memory range
//end



// Z80_write_sequencer[9:0] <= { Z80_write_sequencer[8:0], Write_GPU_RAM };

// if ( Z80_write_sequencer[0] )                 Z80_245data_dir  <= 1'b1; // set 245 dir toward FPGA
// if ( Z80_write_sequencer[0] )                 Z80_rData_ena    <= 1'b0; // set FPGA pins to input (should be by default)
// if ( Z80_write_sequencer[0] )                 Z80_245_oe       <= 1'b0; // enable 245 output (WAS 1 - moved forward to step 0)

// if ( Z80_write_sequencer[DELAY_CYCLES] )  gpu_wdata        <= Z80_wData; // latch data bus onto GPU data bus
// if ( Z80_write_sequencer[DELAY_CYCLES] )  gpu_wr_ena       <= 1'b1; // turn on FPGA RAM we

// if ( Z80_write_sequencer[DELAY_CYCLES + 1] )  gpu_wr_ena       <= 1'b0; // turn off FPGA RAM we (WAS STEP +2, now STEP +3 for additional WR)


if ( Write_GPU_RAM ) begin
Z80_245data_dir  <= 1'b1; // set 245 dir toward FPGA
Z80_rData_ena    <= 1'b0; // set FPGA pins to input (should be by default)
Z80_245_oe       <= 1'b0; // enable 245 output (WAS 1 - moved forward to step 0)
 
gpu_wdata        <= Z80_wData; // latch data bus onto GPU data bus
gpu_wr_ena       <= 1'b1; // turn on FPGA RAM we
end else begin
gpu_wr_ena       <= 1'b0; // turn off FPGA RAM we
end


if ( Read_GPU_RAM_BEGIN ) begin

gpu_rd_req <= 1'b1; // flag a read request to the mux which is one-shotted in the mux
Z80_245data_dir <= 1'b0; // set 245 direction (TO Z80)
Z80_245_oe <= 1'b0; // enable 245 output
Z80_rData_ena    <= 1'b1; // set bidir pins to output


end else begin
gpu_rd_req <= 1'b0; // end GPU read req after 1 pulse
Z80_245data_dir   <= 1'b1; // set 245 dir toward FPGA
Z80_rData_ena <= 1'b0; // re-set bidir pins to input

if ( Z80_WRn ) begin
   //Z80_245_oe <= 1'b1; // disable 245 output
end
end

if ( gpu_rd_rdy ) begin
if (mem_valid_range) Z80_rData[7:0] <= gpu_rData[7:0];// Latch the GPU RAM read into the output register for the Z80
else Z80_rData[7:0]  <= 8'b11111111; // return $FF if addressed byte is outside the GPU's upper RAM limit
end


last_Z80_WR <= Z80_WRn;
last_Z80_RD <= Z80_RDn;
Z80_clk_delay <= Z80_CLK; // find the rising clock edge

end

// **********************************************************************************************************

endmodule


If this works, first I'll need to do a cleanup, then we'll decide what to do next...
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #870 on: January 05, 2020, 06:37:06 pm »
If this works, first I'll need to do a cleanup, then we'll decide what to do next...

Oh boy does it work... CLS is clearing the screen nicely now and screen scrolling is working great with no artefacts at all...   ;D

« Last Edit: January 05, 2020, 06:38:52 pm by nockieboy »
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7725
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #871 on: January 06, 2020, 12:01:50 am »
I need a copy of your current project.
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #872 on: January 06, 2020, 08:19:57 am »
I need a copy of your current project.

Oops...  ::)  Here it is.
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7725
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #873 on: January 06, 2020, 11:29:10 am »
Ok, here you go.

I cleaned up the project.  I had to also patch the MUX algorithm.

First, try the complete cleaned project 'GPU_Z80_bridge_staticIO.zip'.

If everything is ok, then switch the Z80_Bridge.v to the attached 'Z80_bridge_1-write.v'.  This version only does 1 single write to the GPU ram once at the end of every write cycle instead of 62.5 million writes / second during the entire time the Z80_WRn signal is low with a valid address.

Only if the 1-write version works, next switch to the 'Z80_bridge_1-read.v', 1 read / cycle version.  This version will send out a single read_req to the GPU ram at the beginning of the read cycle, latch the result and hold it on the output while the Z80_RDn is low instead of the static version which does a continuous 62.5 million reads / second during the entire time the Z80_RDn is low.

If the 1 read version works, then you have a good Z80 bridge interface which will eat practically no clock cycles from the GPU ram as a read and write to and from GPU ram will only come around once every 6 or more 8 MHz clock cycles.

In the future, it may be possible to enhance the MUX.v to better select the source A/B - READ/WRITE ports based on priority, but for now, it basically does a dumb 1 clk A, 1 clk B cycle.
 
The following users thanked this post: nockieboy

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #874 on: January 06, 2020, 12:55:38 pm »
Ok, here you go.

I cleaned up the project.  I had to also patch the MUX algorithm.

First, try the complete cleaned project 'GPU_Z80_bridge_staticIO.zip'.

If everything is ok, then switch the Z80_Bridge.v to the attached 'Z80_bridge_1-write.v'.  This version only does 1 single write to the GPU ram once at the end of every write cycle instead of 62.5 million writes / second during the entire time the Z80_WRn signal is low with a valid address.

Only if the 1-write version works, next switch to the 'Z80_bridge_1-read.v', 1 read / cycle version.  This version will send out a single read_req to the GPU ram at the beginning of the read cycle, latch the result and hold it on the output while the Z80_RDn is low instead of the static version which does a continuous 62.5 million reads / second during the entire time the Z80_RDn is low.

If the 1 read version works, then you have a good Z80 bridge interface which will eat practically no clock cycles from the GPU ram as a read and write to and from GPU ram will only come around once every 6 or more 8 MHz clock cycles.

In the future, it may be possible to enhance the MUX.v to better select the source A/B - READ/WRITE ports based on priority, but for now, it basically does a dumb 1 clk A, 1 clk B cycle.

I seem to be fighting with a little instability today with one (or several) of the connections (which I've confirmed with the previous stable version of the project, it's not specific to the new project and Z80_bridge versions), but that aside, the new updates seems to be working very nicely.

EDIT: No - hang on..  more testing required.
« Last Edit: January 06, 2020, 01:15:33 pm by nockieboy »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf