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

0 Members and 39 Guests are viewing this topic.

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #825 on: January 04, 2020, 02:17:32 pm »
Try changing these 3 lines:

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

This ignores the clocks and makes the FPGA look like static ram.

Everything is overwritten with $FF now.  Just updated with your latest post and re-compiling.  Will update with results of that code in a minute or three.
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8143
  • Country: ca
    • LinkedIn
Re: FPGA VGA Controller for 8-bit computer
« Reply #826 on: January 04, 2020, 02:19:42 pm »
Check my last msg.
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #827 on: January 04, 2020, 02:21:50 pm »
Ok, here is a new fix for the Z80 bridge:

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  = 0; // number of cycles to delay write for 245
parameter MEM_SIZE_BITS = 15; // number of cycles to delay write for 245

wire mem_window, Z80_mreq, Z80_write, Z80_read, Write_GPU_RAM;
wire Read_GPU_RAM_BEGIN, Read_GPU_RAM_END, mem_valid_range;
wire Z80_clk_pos,Z80_clk_neg,Z80_clk_trig;

reg Z80_clk_delay;
reg [9:0] Z80_write_sequencer;
//reg [18:0] rd_addr;

//assign mem_valid  = (rd_addr[15] == 1'b0); // HIGH if address is inside GPU RAM bounds (GPU RAM may not fill the 512KB host memory window, so this flag determines if the address is within GPU RAM bounds)

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 mem_window = (Z80_addr[21:19]            == MEMORY_RANGE); // Define an active memory range
assign Z80_mreq     = ~Z80_MREQn && Z80_M1n; // Define a bus memory access state
assign Z80_write = ~Z80_WRn; // Isolate a single write transaction
assign Z80_read     = ~Z80_RDn; // Isolate a single read transaction

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

assign mem_valid_range    = (gpu_addr <  2**MEM_SIZE_BITS); // Define GPU addressable memory space

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

always @ (posedge GPU_CLK) begin

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

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

if ( Z80_write_sequencer[DELAY_CYCLES] )  gpu_addr         <= Z80_addr[18:0];// latch address bus onto GPU address bus
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 ( Read_GPU_RAM_BEGIN ) begin

gpu_addr <= Z80_addr[18:0];// pass address to GPU RAM (cropped to 512KB range as that's all we're interested in)
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 && ~Write_GPU_RAM ) begin
Z80_245_oe <= 1'b1; // disable 245 output
Z80_rData_ena <= 1'b0; // re-set bidir pins to input
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


When not reading, it would always reset the 245 buffer even if a write was being performed.  I had to make a few changes...


Ookay... the writes seem to be working, I can see the correct settings for the text mode when the Microcom boots into the DMI, but everywhere else is $FF... which means the screen display is corrupted because ALL the unused HV triggers, HW_regs, MAGGIEs etc are filled with $FF values.
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #828 on: January 04, 2020, 02:25:50 pm »
... but with bit 7 set HIGH in OUTPUT[3] in the debugger, the mass of $FF's stops.  Output to the screen is corrupted, though - looks like some chars are being displayed twice.
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #829 on: January 04, 2020, 02:29:11 pm »
No, I take that back - bit 7 isn't making a difference.  Writes are corrupted, so sometimes enough get through to set up the display properly, but there is visible corruption in the on-screen text, other times the display setup is corrupted and all kinds of weirdness happen.
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8143
  • Country: ca
    • LinkedIn
Re: FPGA VGA Controller for 8-bit computer
« Reply #830 on: January 04, 2020, 02:30:53 pm »
Ok, I've made the reads and writes snap for 1 shot.

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  = 0; // number of cycles to delay write for 245
parameter MEM_SIZE_BITS = 15; // number of cycles to delay write for 245

wire mem_window, Z80_mreq, Z80_write, Z80_read, Write_GPU_RAM;
wire Read_GPU_RAM_BEGIN, Read_GPU_RAM_END, mem_valid_range;
wire Z80_clk_pos,Z80_clk_neg,Z80_clk_trig;

reg Z80_clk_delay, last_Z80_WR, last_Z80_RD;
reg [9:0] Z80_write_sequencer;



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 mem_window = (Z80_addr[21:19]            == MEMORY_RANGE); // Define an active memory range
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 && last_Z80_RD; // 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; // Define a GPU Write action - only write to address within GPU RAM bounds
assign Read_GPU_RAM_BEGIN =  mem_window && Z80_mreq && Z80_read;   // 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.

assign mem_valid_range    = (gpu_addr <  2**MEM_SIZE_BITS); // Define GPU addressable memory space

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

always @ (posedge GPU_CLK) begin

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

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

if ( Z80_write_sequencer[DELAY_CYCLES] )  gpu_addr         <= Z80_addr[18:0];// latch address bus onto GPU address bus
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_addr <= Z80_addr[18:0];// pass address to GPU RAM (cropped to 512KB range as that's all we're interested in)
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_245_oe <= 1'b1; // disable 245 output
Z80_rData_ena <= 1'b0; // re-set bidir pins to input
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
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8143
  • Country: ca
    • LinkedIn
Re: FPGA VGA Controller for 8-bit computer
« Reply #831 on: January 04, 2020, 02:36:08 pm »
Ok, I just patched the 'mem_valid_range' bug for the reads (fixes the reading of only 'FF'):

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  = 0; // number of cycles to delay write for 245
parameter MEM_SIZE_BITS = 15; // number of cycles to delay write for 245

wire mem_window, Z80_mreq, 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;
reg [9:0] Z80_write_sequencer;



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 mem_window = (Z80_addr[21:19]            == MEMORY_RANGE); // Define an active memory range
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 && last_Z80_RD; // 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; // Define a GPU Write action - only write to address within GPU RAM bounds
assign Read_GPU_RAM_BEGIN =  mem_window && Z80_mreq && Z80_read;   // 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_write_sequencer[9:0] <= { Z80_write_sequencer[8:0], Write_GPU_RAM };

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

if ( Z80_write_sequencer[DELAY_CYCLES] )  gpu_addr         <= Z80_addr[18:0];// latch address bus onto GPU address bus
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_addr     <= Z80_addr[18:0];// pass address to GPU RAM (cropped to 512KB range as that's all we're interested in)
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

mem_valid_range  <= (gpu_addr[18:0] <  2**MEM_SIZE_BITS); // Define GPU addressable memory space

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

if ( Read_GPU_RAM_END ) begin
Z80_245_oe <= 1'b1; // disable 245 output
Z80_rData_ena <= 1'b0; // re-set bidir pins to input
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 #832 on: January 04, 2020, 02:38:05 pm »
ONE thing that is consistent, though, is that the Microcom is reporting the correct amount of memory now - so the changes to the Z80_bridge to prevent reads/writes above the memory limit obviously works.  :-+

Ok, I've made the reads and writes snap for 1 shot.

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  = 0; // number of cycles to delay write for 245
parameter MEM_SIZE_BITS = 15; // number of cycles to delay write for 245

wire mem_window, Z80_mreq, Z80_write, Z80_read, Write_GPU_RAM;
wire Read_GPU_RAM_BEGIN, Read_GPU_RAM_END, mem_valid_range;
wire Z80_clk_pos,Z80_clk_neg,Z80_clk_trig;

reg Z80_clk_delay, last_Z80_WR, last_Z80_RD;
reg [9:0] Z80_write_sequencer;



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 mem_window = (Z80_addr[21:19]            == MEMORY_RANGE); // Define an active memory range
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 && last_Z80_RD; // 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; // Define a GPU Write action - only write to address within GPU RAM bounds
assign Read_GPU_RAM_BEGIN =  mem_window && Z80_mreq && Z80_read;   // 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.

assign mem_valid_range    = (gpu_addr <  2**MEM_SIZE_BITS); // Define GPU addressable memory space

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

always @ (posedge GPU_CLK) begin

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

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

if ( Z80_write_sequencer[DELAY_CYCLES] )  gpu_addr         <= Z80_addr[18:0];// latch address bus onto GPU address bus
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_addr <= Z80_addr[18:0];// pass address to GPU RAM (cropped to 512KB range as that's all we're interested in)
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_245_oe <= 1'b1; // disable 245 output
Z80_rData_ena <= 1'b0; // re-set bidir pins to input
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


Hmm... nope.  Reads/writes are all over the place - and the GPU seems to be driving the data pins at the wrong time as the Microcom is sometimes crashing as well.  I'm just compiling your latest post with the patched 'mem_valid_range'.
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #833 on: January 04, 2020, 02:42:55 pm »
Latest patch compiled and tested - writes to the GPU are corrupted; display setup is corrupted as a result and at one point I could see what I was typing into the Microcom via the console appearing on the screen, but the characters didn't match what I was typing.  Several resets later and during one reset, the Microcom crashed.
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8143
  • Country: ca
    • LinkedIn
Re: FPGA VGA Controller for 8-bit computer
« Reply #834 on: January 04, 2020, 02:54:34 pm »
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  = 0; // number of cycles to delay write for 245
parameter MEM_SIZE_BITS = 15; // number of cycles to delay write for 245

wire mem_window, Z80_mreq, 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;
reg [9:0] Z80_write_sequencer;



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 mem_window = (Z80_addr[21:19]            == MEMORY_RANGE); // Define an active memory range
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 && last_Z80_RD; // Isolate a single read transaction
assign Z80_readn     =  Z80_RDn; // Isolate a single read transaction

assign Write_GPU_RAM =  mem_window && Z80_mreq && Z80_write; // Define a GPU Write action - only write to address within GPU RAM bounds
assign Read_GPU_RAM_BEGIN =  mem_window && Z80_mreq && Z80_read;   // 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_write_sequencer[9:0] <= { Z80_write_sequencer[8:0], Write_GPU_RAM };

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

if ( Z80_write_sequencer[DELAY_CYCLES] )  gpu_addr         <= Z80_addr[18:0];// latch address bus onto GPU address bus
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 ( Read_GPU_RAM_BEGIN ) begin

gpu_addr     <= Z80_addr[18:0];// pass address to GPU RAM (cropped to 512KB range as that's all we're interested in)
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

mem_valid_range  <= (gpu_addr[18:0] <  2**MEM_SIZE_BITS); // Define GPU addressable memory space

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
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


I can only recommend changing those 4 address pins if this doesn't work.
Also, try doing some reads exclusively to see if they work with the correct data before doing any writing.
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8143
  • Country: ca
    • LinkedIn
Re: FPGA VGA Controller for 8-bit computer
« Reply #835 on: January 04, 2020, 03:03:02 pm »
Note that the writes outside the 32kb range are not protected.  Also, I might need to turn off the 245 at the end of a read....
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  = 0; // number of cycles to delay write for 245
parameter MEM_SIZE_BITS = 15; // number of cycles to delay write for 245

wire mem_window, Z80_mreq, 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;
reg [9:0] Z80_write_sequencer;



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 mem_window = (Z80_addr[21:19]            == MEMORY_RANGE); // Define an active memory range
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 && last_Z80_RD; // 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; // Define a GPU Write action - only write to address within GPU RAM bounds
assign Read_GPU_RAM_BEGIN =  mem_window && Z80_mreq && Z80_read;   // 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_write_sequencer[9:0] <= { Z80_write_sequencer[8:0], Write_GPU_RAM };

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

if ( Z80_write_sequencer[DELAY_CYCLES] )  gpu_addr         <= Z80_addr[18:0];// latch address bus onto GPU address bus
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       <= (gpu_addr[18:0] <  2**MEM_SIZE_BITS); // Define GPU addressable memory space  -  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 ( Read_GPU_RAM_BEGIN ) begin

gpu_addr     <= Z80_addr[18:0];// pass address to GPU RAM (cropped to 512KB range as that's all we're interested in)
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

mem_valid_range  <= (gpu_addr[18:0] <  2**MEM_SIZE_BITS); // Define GPU addressable memory space

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; // enable 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
« Last Edit: January 04, 2020, 03:08:20 pm by BrianHG »
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8143
  • Country: ca
    • LinkedIn
Re: FPGA VGA Controller for 8-bit computer
« Reply #836 on: January 04, 2020, 03:15:55 pm »
Which Z80 are you using?
EXACT part number! Manufacturer name as well.
The timing on the data sheet has some NEGATIVE setup times for the bus control signals on some models.
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #837 on: January 04, 2020, 03:22:42 pm »
Which Z80 are you using?
EXACT part number! Manufacturer name as well.
The timing on the data sheet has some NEGATIVE setup times for the bus control signals on some models.

Right.  So you may be on to something here.  I've been convinced I'm using an 8 MHz CPU, but it would appear not and this is quite embarrassing.  :-[  It's a Zilog Z80, Z84C0010PEG.  A 10 MHz model.

That could be the cause of the timing headaches right there. (It is DEFINITELY running at 8 MHz, however). :palm:
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #838 on: January 04, 2020, 03:27:51 pm »
CANCEL THAT.

It's a Zilog Z84C008PEG CPU.

Sorry for the confusion.  My main Microcom is wired up to the GPU and the CPU isn't the top card, so I couldn't get to it without taking the stack apart, so I referred to my second Microcom I've got sitting on a shelf - it would appear THAT one has a 10 MHz CPU in it.  I've just disassembled my main Microcom stack and checked out the CPU - it's definitely an 8 MHz Zilog part.

Raises an interesting point though - I got both the Z80's at the same time from the same supplier a few years ago...  :-//
« Last Edit: January 04, 2020, 03:30:42 pm by nockieboy »
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #839 on: January 04, 2020, 03:37:04 pm »
The project was working mostly at the start of the day - it only seemed to fall over when I tried to scroll the screen.  I might roll back to that state and try to sort out the pins that can't be assigned with fast regs, unless there's any changes you've made that definitely need to stay in?
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8143
  • Country: ca
    • LinkedIn
Re: FPGA VGA Controller for 8-bit computer
« Reply #840 on: January 04, 2020, 04:06:13 pm »
CANCEL THAT.

It's a Zilog Z84C008PEG CPU.

Sorry for the confusion.  My main Microcom is wired up to the GPU and the CPU isn't the top card, so I couldn't get to it without taking the stack apart, so I referred to my second Microcom I've got sitting on a shelf - it would appear THAT one has a 10 MHz CPU in it.  I've just disassembled my main Microcom stack and checked out the CPU - it's definitely an 8 MHz Zilog part.

Raises an interesting point though - I got both the Z80's at the same time from the same supplier a few years ago...  :-//
ok, blahhh, anyways, try this after a bunch of code changes for the 10&20mhz variants...:

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  = 0; // number of cycles to delay write for 245
parameter MEM_SIZE_BITS = 15; //
parameter MREQ_DLY_CLK  = 0; // number of cycles +1 to delay mreq trigger

wire Z80_mreq, Z80_mreq_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_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


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


I would still change those 4 pins if possible.  All addresses should be on a similar matching IO type.  Same for all data.

Do you have enough GND connections between the Z80 and GPU?
You might have massive ground bounce happening...
« Last Edit: January 04, 2020, 04:29:47 pm by BrianHG »
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8143
  • Country: ca
    • LinkedIn
Re: FPGA VGA Controller for 8-bit computer
« Reply #841 on: January 04, 2020, 04:28:57 pm »
Ok, go to this version:

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  = 0; // number of cycles to delay write for 245
parameter MEM_SIZE_BITS = 15; //
parameter MREQ_DLY_CLK  = 0; // 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
« Last Edit: January 04, 2020, 04:37:03 pm by BrianHG »
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #842 on: January 04, 2020, 04:36:37 pm »
I woul still change those 4 pins if possible.  All addresses should be on a similar matching IO type.  Same for all data.

It's top of my to-do list now.

Do you have enough GND connections between the Z80 and GPU?
You might have massive ground bounce happening...

Errrr... *goes away and looks up ground bounce*  Hmm... maybe not.  Just to explain the setup - I have the Microcom, I have a single breadboard with the level converters on it, then I have the FPGA dev board.

The Microcom's GND is connected to the breadboard via a single wire.  The breadboard GND is connected to the FPGA GND via a single wire.

I'm doubting that fulfils the 'enough GND connections between the Z80 and GPU question...  :o

Previous code changes doesn't help - mostly getting $FFs written to GPU RAM.  PEEK is returning garbage.  Seems to be just returning $1A.

Ok, go to this version:

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  = 0; // number of cycles to delay write for 245
parameter MEM_SIZE_BITS = 15; //
parameter MREQ_DLY_CLK  = 0; // 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 && last_Z80_RD; // 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


Compiling as we speak.
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8143
  • Country: ca
    • LinkedIn
Re: FPGA VGA Controller for 8-bit computer
« Reply #843 on: January 04, 2020, 04:38:07 pm »
I woul still change those 4 pins if possible.  All addresses should be on a similar matching IO type.  Same for all data.

It's top of my to-do list now.

Do you have enough GND connections between the Z80 and GPU?
You might have massive ground bounce happening...

Errrr... *goes away and looks up ground bounce*  Hmm... maybe not.  Just to explain the setup - I have the Microcom, I have a single breadboard with the level converters on it, then I have the FPGA dev board.

The Microcom's GND is connected to the breadboard via a single wire.  The breadboard GND is connected to the FPGA GND via a single wire.

I'm doubting that fulfils the 'enough GND connections between the Z80 and GPU question...  :o

Previous code changes doesn't help - mostly getting $FFs written to GPU RAM.  PEEK is returning garbage.  Seems to be just returning $1A.

Ok, go to this version:

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  = 0; // number of cycles to delay write for 245
parameter MEM_SIZE_BITS = 15; //
parameter MREQ_DLY_CLK  = 0; // 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 && last_Z80_RD; // 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


Compiling as we speak.

Error, fix this line #59:

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


1 GND wire, WTF??????
You should have 1 GND wire for every 2-4 signal wires.  Otherwise the GND is waving up and down, bouncing with it's lower impedance and inductance characteristics, messing up everything.

A proper high frequency design usually has 1-1.  Like your old IDE/floppy drive cables, 1 row side was almost all GND wires.
« Last Edit: January 04, 2020, 04:42:06 pm by BrianHG »
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8143
  • Country: ca
    • LinkedIn
Re: FPGA VGA Controller for 8-bit computer
« Reply #844 on: January 04, 2020, 04:44:03 pm »
I had better not been fiddling with all this just because you used 1 tiny thin ground wire which was competing against 35 CPU IO signals...

 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8143
  • Country: ca
    • LinkedIn
Re: FPGA VGA Controller for 8-bit computer
« Reply #845 on: January 04, 2020, 05:12:15 pm »
Also try these parameter settings:

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


Don't forget to update the symbol and edit the 2 values on the top hierarchy.
This slows down, adds a delay to the latching of the address and data during the read and write.
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #846 on: January 04, 2020, 06:19:45 pm »
1 GND wire, WTF??????
You should have 1 GND wire for every 2-4 signal wires.  Otherwise the GND is waving up and down, bouncing with it's lower impedance and inductance characteristics, messing up everything.

A proper high frequency design usually has 1-1.  Like your old IDE/floppy drive cables, 1 row side was almost all GND wires.

I had better not been fiddling with all this just because you used 1 tiny thin ground wire which was competing against 35 CPU IO signals...

Each IO group is grounded and is working at no more than 8 MHz, which is better than nothing I guess?  It was working fine(-ish) this morning and yesterday with only the one ground...  but that's not to say this test setup is anything near suitable - one reason I'm hoping to get a custom dev board created soon. :-[

Also try these parameter settings:

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

Don't forget to update the symbol and edit the 2 values on the top hierarchy.
This slows down, adds a delay to the latching of the address and data during the read and write.

Okay, that's a step forward - but it seems the data is still getting randomly corrupted.  It was able to display text on the screen this time and I could write some stuff there to test it.  It seems to be dropping characters and replacing them with null bytes ($00).

 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #847 on: January 04, 2020, 06:40:39 pm »
Reading seems to be quite accurate with individual PEEKs, but when I try to dump a page from the GPU, the system locks up.  Seems to lock up frequently trying to initialise the GPU as well.

For a sanity check, earlier I tested the project from this morning which I backed-up before we started making all these changes (at least I think I did before we made any sweeping changes).  It still works, but not very well - so I'm holding making any more changes until tomorrow when I can sort out exactly what's going wrong (it's going to be a bad connection on one of the buses) with a fresh head.   :palm:
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8143
  • Country: ca
    • LinkedIn
Re: FPGA VGA Controller for 8-bit computer
« Reply #848 on: January 05, 2020, 01:34:04 am »
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.

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.
« Last Edit: January 05, 2020, 08:11:33 am by BrianHG »
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 8143
  • Country: ca
    • LinkedIn
Re: FPGA VGA Controller for 8-bit computer
« Reply #849 on: January 05, 2020, 09:02:23 am »
Upload the latest copy of what you are compiling with...
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf