Author Topic: FPGA VGA Controller for 8-bit computer  (Read 426359 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 #475 on: November 26, 2019, 10:02:17 am »
Ok, @nockieboy, now that I know you can simulate code in Quartus, let's take a look at point #3 here:
https://www.eevblog.com/forum/fpga/fpga-vga-controller-for-8-bit-computer/msg2788698/#msg2788698
...
Now, you will need to re-work it to the specs and controls I laid out for your GPU....

Okay, have done that (thanks for the example - makes my life much easier and assists my understanding no end!) - code below:

Code: [Select]
module GPU_HW_Control_Regs (

input reg rst,
input reg clk,
input reg we,
input reg [19:0] addr_in,
input reg [7:0] data_in,

output reg  [7:0] GPU_HW_Control_regs[HW_REGS_SIZE]

);
 
parameter HW_REGS_SIZE = HW_REGS;

parameter [7:0] RST_VALUES [32] = {
8'h01,
8'h02,
8'h03,
8'h04,
8'h05,
8'h06,
8'h07,
8'h08,
8'h09,
8'h0A,
8'h0B,
8'h0C,
8'h0D,
8'h0E,
8'h0F,
8'h10,
8'h11,
8'h12,
8'h13,
8'h14,
8'h15,
8'h16,
8'h17,
8'h18,
8'h19,
8'h1A,
8'h1B,
8'h1C,
8'h1D,
8'h1E,
8'h1F,
8'h20
};

wire valid_wr;

assign valid_wr = we && ( addr_in[19:8] == data_in ); // upper 8-bits of addr_in should equal data_in for a successful write

integer i;
 
always @ (posedge clk) begin

if (rst) begin

// reset key registers to initial values
for (i = 0; i < 32; i = i + 1) begin
GPU_HW_Control_regs[i] <= RST_VALUES[i];
end

// reset remaining registers to zero
for (i = 33; i < HW_REGS_SIZE; i = i + 1) begin
GPU_HW_Control_regs[i] <= 8'h0;
end

end
else
begin

if (valid_wr) begin

// apply written value to addressed register
GPU_HW_Control_regs[addr_in[7:0]] <= data_in;

end

end
end

endmodule

So I've been wading through the specifications you provided in the earlier post for the GPU_HW_Control_Regs, but I'm struggling with this bit:

Quote
c)  Base write address for the write input.  The module will always take in all 20 address bits, but when writing data to the 8 bit data input port, the upper address wires [19:8] should equal this number for the write to be successful.  If parameter (b) is >256, then the bottom of the upper base write address [8] will be ignored as you will be opening a 512 byte window, and so on.  (Set this default to the base of the last 256 bytes in your system memory.  Yes, it will occupy the same last 256 bytes as your system GPU ram.)

I've got the check to make sure the data value is the same as the upper 8-bits of the address value, but the bit in bold is making my brain ache.  Can you rephrase those three sentences, or reduce them to single-syllable words with crayon sketches?  :o

You can see how Altera/Intel labels the ' register memory bank ' differently outside the Verilog module where I fed some of the individual register bytes to a few output pins.
This bank of registers is what will hold and feed all you graphics control settings.  As you can see, you write to them just like ram, but, you have individual access to all their contents at all times.

So I'll need 32 output pins - one for each of the 'main' registers?
« Last Edit: November 26, 2019, 11:03:39 am by nockieboy »
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7747
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #476 on: November 26, 2019, 11:18:01 am »
Ok, @nockieboy, now that I know you can simulate code in Quartus, let's take a look at point #3 here:
https://www.eevblog.com/forum/fpga/fpga-vga-controller-for-8-bit-computer/msg2788698/#msg2788698
...
Now, you will need to re-work it to the specs and controls I laid out for your GPU....

Okay, have done that (thanks for the example - makes my life much easier and assists my understanding no end!) - code below:

Code: [Select]
module GPU_HW_Control_Regs (

input reg rst,
input reg clk,
input reg we,
input reg [19:0] addr_in,
input reg [7:0] data_in,

output reg  [7:0] GPU_HW_Control_regs[HW_REGS_SIZE]

);
 
parameter HW_REGS_SIZE = HW_REGS;

parameter [7:0] RST_VALUES [32] = {
8'h01,
8'h02,
8'h03,
8'h04,
8'h05,
8'h06,
8'h07,
8'h08,
8'h09,
8'h0A,
8'h0B,
8'h0C,
8'h0D,
8'h0E,
8'h0F,
8'h10,
8'h11,
8'h12,
8'h13,
8'h14,
8'h15,
8'h16,
8'h17,
8'h18,
8'h19,
8'h1A,
8'h1B,
8'h1C,
8'h1D,
8'h1E,
8'h1F,
8'h20
};

wire valid_wr;

assign valid_wr = we && ( addr_in[19:8] == data_in ); // upper 8-bits of addr_in should equal data_in for a successful write

integer i;
 
always @ (posedge clk) begin

if (rst) begin

// reset key registers to initial values
for (i = 0; i < 32; i = i + 1) begin
GPU_HW_Control_regs[ i ] <= RST_VALUES[ i ];
end

// reset remaining registers to zero
for (i = 4; i < HW_REGS_SIZE; i = i + 1) begin
GPU_HW_Control_regs[ i ] <= 8'h0;
end

end
else
begin

if (valid_wr) begin

// apply written value to addressed register
GPU_HW_Control_regs[addr_in[7:0]] <= data_in;

end

end
end

endmodule

So I've been wading through the specifications you provided in the earlier post for the GPU_HW_Control_Regs, but I'm struggling with this bit:

Quote
c)  Base write address for the write input.  The module will always take in all 20 address bits, but when writing data to the 8 bit data input port, the upper address wires [19:8] should equal this number for the write to be successful.  If parameter (b) is >256, then the bottom of the upper base write address [8] will be ignored as you will be opening a 512 byte window, and so on.  (Set this default to the base of the last 256 bytes in your system memory.  Yes, it will occupy the same last 256 bytes as your system GPU ram.)

I've got the check to make sure the data value is the same as the upper 8-bits of the address value, but the bit in bold is making my brain ache.  Can you rephrase those three sentences, or reduce them to single-syllable words with crayon sketches?  :o

You can see how Altera/Intel labels the ' register memory bank ' differently outside the Verilog module where I fed some of the individual register bytes to a few output pins.
This bank of registers is what will hold and feed all you graphics control settings.  As you can see, you write to them just like ram, but, you have individual access to all their contents at all times.

So I'll need 32 output pins - one for each of the 'main' registers?
You just about got it... #1, see error in 'RED'
         // reset key registers to initial values      
         for (i = 0; i < 32; i = i + 1) begin
            GPU_HW_Control_regs[ i ] <= RST_VALUES[ i ];
         end
         
         // reset remaining registers to zero
         for (i = 4; i < HW_REGS_SIZE; i = i + 1) begin
            GPU_HW_Control_regs[ i ] <= 8'h0;
         end

A simulation which had a reset somewhere and at least 8 output regs on display and some random parameters would have shown you this bug.

Quote
I've got the check to make sure the data value is the same as the upper 8-bits of the address value, but the bit in bold is making my brain ache.  Can you rephrase those three sentences, or reduce them to single-syllable words with crayon sketches?  :o

Ok, you need another Parameter.  Call it 'BASE_WRITE_ADDRESS'.  Now, change to your current valid write enable condition:


   assign valid_wr = we && ( addr_in[19:HW_REGS_SIZE] == BASE_WRITE_ADDRESS[19:HW_REGS_SIZE] );      // upper addr_in should equal to the same specified upper base address.  This will allow us to map the register bank anywhere inside the 20bit address range.

 
So, if we have a HW_REG_SIZE of 8, space for 256 registers, only addr_in address wires [19:8] need to be equal with the value in 'BASE_WRITE_ADDRESS[19:8]' and 'we' needs to be high to engage the write enable.  Remember, even though you may think of parameters as numbers, to a Verilog compiler, it is nothing more than a bundle of single wires with set specific high and low values.  So writing my above line make all too much easy sense.  (HINT: In specifying a Z80 window address location..... not in binary or 3 arbitrary bit located who knows where.... Give it a legitimate understandable figure which matches what you code in the Z80 + what you see when you enter an address in your simulator setup.)


And, don't forget this:

      if (valid_wr) begin
            
            // apply written value to addressed register
            GPU_HW_Control_regs[addr_in[HW_REG_SIZE-1:0]] <= data_in;
            
         end

Let's see a test bench of this for setting a few regs, then doing a reset showing all the defaults set in 1 shot.

Quote
So I'll need 32 output pins - one for each of the 'main' registers?
Only if you want to send 32 registers to 32x8bit output pins.  All I'm saying is that when Quartus wires a addressable register ram on it's block diagrams, it calls them "mem[0..255][7..0]" instead of Veriog's  ' reg [7:0] mem [256]; '.  Quartus does this to allow you to take sub-groups of 'mem', like [15..20] and sen those to 1 module while wiring [200..210] to another in the block diagram.  Don't worry, we will be piping all 256, [0..255] into each verilog module and a parameter there will select which memory contents in that bundle will control it's features.  My example screenshot shows you how to select and wire a bundle of the mem register bank in the block diagram editor to anywhere you like.
« Last Edit: November 26, 2019, 11:43:36 am by BrianHG »
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #477 on: November 26, 2019, 12:18:36 pm »
You just about got it... #1, see error in 'RED'
         // reset key registers to initial values      
         for (i = 0; i < 32; i = i + 1) begin
            GPU_HW_Control_regs[ i ] <= RST_VALUES[ i ];
         end
         
         // reset remaining registers to zero
         for (i = 4; i < HW_REGS_SIZE; i = i + 1) begin
            GPU_HW_Control_regs[ i ] <= 8'h0;
         end

Yeah, I spotted and corrected that bug in my post above, but not in time before you read it.  :)

Ok, you need another Parameter.  Call it 'BASE_WRITE_ADDRESS'.  Now, change to your current valid write enable condition:


   assign valid_wr = we && ( addr_in[19:HW_REGS_SIZE] == BASE_WRITE_ADDRESS[19:HW_REGS_SIZE] );      // upper addr_in should equal to the same specified upper base address.  This will allow us to map the register bank anywhere inside the 20bit address range.

Couple of issues here - HW_REGS_SIZE originally was intended to be a literal number of registers... i.e. 32 for 32 registers.  So I've had to make some changes to the code to treat HW_REGS_SIZE as the square root of the desired number of registers, so it can be dropped into address ranges directly as the number of address lines needed to make the required number of regs.  So now it would have a value of 5 for 32 registers, instead of 32 before.

The other thing is this:

Quote
assign valid_wr = we && ( addr_in[19:HW_REGS_SIZE] == BASE_WRITE_ADDRESS[19:HW_REGS_SIZE] );

BASE_WRITE_ADDRESS:  Can I just declare it as a hex or binary value?

Code: [Select]
BASE_ADDRESS = 19'b0000011111100000000;
That should be the address of the top 256 bytes of the GPU's 16K RAM?

Code: [Select]
module GPU_HW_Control_Regs (

input reg rst,
input reg clk,
input reg we,
input reg [19:0] addr_in,
input reg [7:0] data_in,

output reg  [7:0] GPU_HW_Control_regs[2**HW_REGS_SIZE]

);
 
parameter HW_REGS_SIZE = HW_REGS;
parameter BASE_WRITE_ADDRESS = 0;

parameter [7:0] RST_VALUES [32] = {
8'h01,
8'h02,
8'h03,
8'h04,
8'h05,
8'h06,
8'h07,
8'h08,
8'h09,
8'h0A,
8'h0B,
8'h0C,
8'h0D,
8'h0E,
8'h0F,
8'h10,
8'h11,
8'h12,
8'h13,
8'h14,
8'h15,
8'h16,
8'h17,
8'h18,
8'h19,
8'h1A,
8'h1B,
8'h1C,
8'h1D,
8'h1E,
8'h1F,
8'h20
};

wire valid_wr;

assign valid_wr = we && ( addr_in[19:HW_REGS_SIZE] == BASE_WRITE_ADDRESS[19:HW_REGS_SIZE] ); // upper 8-bits of addr_in should equal data_in for a successful write

integer i;
 
always @ (posedge clk) begin

if (rst) begin

// reset key registers to initial values
for (i = 0; i < 32; i = i + 1) begin
GPU_HW_Control_regs[i] <= RST_VALUES[i];
end

// reset remaining registers to zero
for (i = 4; i < 2**HW_REGS_SIZE; i = i + 1) begin
GPU_HW_Control_regs[i] <= 8'h0;
end

end
else
begin

if (valid_wr) begin

// apply written value to addressed register
GPU_HW_Control_regs[addr_in[HW_REG_SIZE-1:0]] <= data_in;

end

end
end

endmodule
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #478 on: November 26, 2019, 12:35:13 pm »
 :palm:

Now I'm hitting error after error trying to create symbol files for GPU_HW_Control_Regs.  I've saved it as a .sv file to try to enforce the System Verilog language, but it's really not happy with the RST_VALUES parameter array.

This is where I am currently - this error message:


Error (10016): Can't create symbol/include/instantiation/component file for module "GPU_HW_Control_Regs" because port "GPU_HW_Control_regs" has an unsupported type


Code: [Select]
module GPU_HW_Control_Regs (

input rst,
input clk,
input we,
input [19:0] addr_in,
input [7:0] data_in,

output reg  [7:0] GPU_HW_Control_regs[2**HW_REGS_SIZE]

);
 
parameter HW_REGS_SIZE = 5;
parameter BASE_WRITE_ADDRESS = 0;

parameter bit [7:0] RST_VALUES [32] = '{
8'h01,
8'h02,
8'h03,
8'h04,
8'h05,
8'h06,
8'h07,
8'h08,
8'h09,
8'h0A,
8'h0B,
8'h0C,
8'h0D,
8'h0E,
8'h0F,
8'h10,
8'h11,
8'h12,
8'h13,
8'h14,
8'h15,
8'h16,
8'h17,
8'h18,
8'h19,
8'h1A,
8'h1B,
8'h1C,
8'h1D,
8'h1E,
8'h1F,
8'h20
};

wire valid_wr;

assign valid_wr = we && ( addr_in[19:HW_REGS_SIZE] == BASE_WRITE_ADDRESS[19:HW_REGS_SIZE] ); // upper 8-bits of addr_in should equal data_in for a successful write

integer i;
 
always @ (posedge clk) begin

if (rst) begin

// reset key registers to initial values
for (i = 0; i < 32; i = i + 1) begin
GPU_HW_Control_regs[i] <= RST_VALUES[i];
end

// reset remaining registers to zero
for (i = 4; i < 2**HW_REGS_SIZE; i = i + 1) begin
GPU_HW_Control_regs[i] <= 8'h0;
end

end
else
begin

if (valid_wr) begin

// apply written value to addressed register
GPU_HW_Control_regs[addr_in[HW_REGS_SIZE-1:0]] <= data_in;

end

end
end

endmodule

I've made changes to how RST_VALUES is declared, including specifying a type which I think is causing this error, but I get other errors if I don't specify a type.
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7747
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #479 on: November 26, 2019, 12:37:12 pm »

BASE_WRITE_ADDRESS:  Can I just declare it as a hex or binary value?

Code: [Select]
BASE_ADDRESS = 19'b0000011111100000000;
That should be the address of the top 256 bytes of the GPU's 16K RAM?

Yup, that's fine, just note that [19:0] is 20'bxxxx not 19'bxxxx.  0 in 19:0 counts as a bit as well.

As for hardware regs, just fix up the parameter nae to what you like.  A parameter of HW_REG_ADDR_SIZE would be fine and using the 2**HW_REG_ADDR_SIZE would do it for you  [7:0]reg[xxxxx], and don't forget your reset loop...
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7747
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #480 on: November 26, 2019, 12:42:04 pm »
:palm:

Now I'm hitting error after error trying to create symbol files for GPU_HW_Control_Regs.  I've saved it as a .sv file to try to enforce the System Verilog language, but it's really not happy with the RST_VALUES parameter array.

This is where I am currently - this error message:


Error (10016): Can't create symbol/include/instantiation/component file for module "GPU_HW_Control_Regs" because port "GPU_HW_Control_regs" has an unsupported type


Code: [Select]
module GPU_HW_Control_Regs (

input rst,
input clk,
input we,
input [19:0] addr_in,
input [7:0] data_in,

output reg  [7:0] GPU_HW_Control_regs[2**HW_REGS_SIZE]

);
 
parameter HW_REGS_SIZE = 5;
parameter BASE_WRITE_ADDRESS = 0;

parameter bit [7:0] RST_VALUES [32] = '{
8'h01,
8'h02,
8'h03,
8'h04,
8'h05,
8'h06,
8'h07,
8'h08,
8'h09,
8'h0A,
8'h0B,
8'h0C,
8'h0D,
8'h0E,
8'h0F,
8'h10,
8'h11,
8'h12,
8'h13,
8'h14,
8'h15,
8'h16,
8'h17,
8'h18,
8'h19,
8'h1A,
8'h1B,
8'h1C,
8'h1D,
8'h1E,
8'h1F,
8'h20
};

wire valid_wr;

assign valid_wr = we && ( addr_in[19:HW_REGS_SIZE] == BASE_WRITE_ADDRESS[19:HW_REGS_SIZE] ); // upper 8-bits of addr_in should equal data_in for a successful write

integer i;
 
always @ (posedge clk) begin

if (rst) begin

// reset key registers to initial values
for (i = 0; i < 32; i = i + 1) begin
GPU_HW_Control_regs[i] <= RST_VALUES[i];
end

// reset remaining registers to zero
for (i = 4; i < 2**HW_REGS_SIZE; i = i + 1) begin
GPU_HW_Control_regs[i] <= 8'h0;
end

end
else
begin

if (valid_wr) begin

// apply written value to addressed register
GPU_HW_Control_regs[addr_in[HW_REGS_SIZE-1:0]] <= data_in;

end

end
end

endmodule

I've made changes to how RST_VALUES is declared, including specifying a type which I think is causing this error, but I get other errors if I don't specify a type.

It's in part a limitation of QuartusIIv9's 'generate sheet symbol' function, you just need to generate the sheet symbol in Quartus Prime, then it will still load in QuartusIIv9 once generated.  Once you have the symbol, everything else is still functional in both versions of Quartus.
« Last Edit: November 26, 2019, 12:43:43 pm by BrianHG »
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7747
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #481 on: November 26, 2019, 12:59:20 pm »
If you cant solve the reset parameter array, just make 8 16 bit parameter inputs and assign the 8 to the first 16 regs.  We will most likely only use 4 of these, filled with 16 or even 24 bit quantities as they will point to the power up display address pointer settings to generate a valid picture.
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #482 on: November 26, 2019, 01:36:38 pm »
It's in part a limitation of QuartusIIv9's 'generate sheet symbol' function, you just need to generate the sheet symbol in Quartus Prime, then it will still load in QuartusIIv9 once generated.  Once you have the symbol, everything else is still functional in both versions of Quartus.

It's Quartus Prime I'm getting the errors in.  :-\

If you cant solve the reset parameter array, just make 8 16 bit parameter inputs and assign the 8 to the first 16 regs.  We will most likely only use 4 of these, filled with 16 or even 24 bit quantities as they will point to the power up display address pointer settings to generate a valid picture.

I'll go for this solution, I think. Here's the updated code:

Code: [Select]
module GPU_HW_Control_Regs (

input rst,
input clk,
input we,
input [19:0] addr_in,
input [7:0] data_in,

output reg  [7:0] GPU_HW_Control_regs[2**HW_REGS_SIZE]

);
 
parameter HW_REGS_SIZE = 5;
parameter BASE_WRITE_ADDRESS = 0;
parameter RST_VALUE_0 = 16'b0000000000000000;
parameter RST_VALUE_1 = 16'b0000000000000001;
parameter RST_VALUE_2 = 16'b0000000000000010;
parameter RST_VALUE_3 = 16'b0000000000000011;
parameter RST_VALUE_4 = 16'b0000000000000100;
parameter RST_VALUE_5 = 16'b0000000000000101;
parameter RST_VALUE_6 = 16'b0000000000000110;
parameter RST_VALUE_7 = 16'b0000000000000111;

wire valid_wr;

assign valid_wr = we && ( addr_in[19:HW_REGS_SIZE] == BASE_WRITE_ADDRESS[19:HW_REGS_SIZE] ); // upper 8-bits of addr_in should equal data_in for a successful write

integer i;
 
always @ (posedge clk) begin

if (rst) begin

// reset key registers to initial values
GPU_HW_Control_regs[0] <= RST_VALUE_0[7:0];
GPU_HW_Control_regs[1] <= RST_VALUE_0[15:8];
GPU_HW_Control_regs[2] <= RST_VALUE_1[7:0];
GPU_HW_Control_regs[3] <= RST_VALUE_1[15:8];
GPU_HW_Control_regs[4] <= RST_VALUE_2[7:0];
GPU_HW_Control_regs[5] <= RST_VALUE_2[15:8];
GPU_HW_Control_regs[6] <= RST_VALUE_3[7:0];
GPU_HW_Control_regs[7] <= RST_VALUE_3[15:8];
GPU_HW_Control_regs[8] <= RST_VALUE_4[7:0];
GPU_HW_Control_regs[9] <= RST_VALUE_4[15:8];
GPU_HW_Control_regs[10] <= RST_VALUE_5[7:0];
GPU_HW_Control_regs[11] <= RST_VALUE_5[15:8];
GPU_HW_Control_regs[12] <= RST_VALUE_6[7:0];
GPU_HW_Control_regs[13] <= RST_VALUE_6[15:8];
GPU_HW_Control_regs[14] <= RST_VALUE_7[7:0];
GPU_HW_Control_regs[15] <= RST_VALUE_7[15:8];

// reset remaining registers to zero
for (i = 16; i < 2**HW_REGS_SIZE; i = i + 1) begin
GPU_HW_Control_regs[i] <= 8'h0;
end

end
else
begin

if (valid_wr) begin

// apply written value to addressed register
GPU_HW_Control_regs[addr_in[HW_REGS_SIZE-1:0]] <= data_in;

end

end
end

endmodule
« Last Edit: November 26, 2019, 01:42:24 pm by nockieboy »
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7747
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #483 on: November 26, 2019, 05:07:25 pm »
It's in part a limitation of QuartusIIv9's 'generate sheet symbol' function, you just need to generate the sheet symbol in Quartus Prime, then it will still load in QuartusIIv9 once generated.  Once you have the symbol, everything else is still functional in both versions of Quartus.

It's Quartus Prime I'm getting the errors in.  :-\

If you cant solve the reset parameter array, just make 8 16 bit parameter inputs and assign the 8 to the first 16 regs.  We will most likely only use 4 of these, filled with 16 or even 24 bit quantities as they will point to the power up display address pointer settings to generate a valid picture.

I'll go for this solution, I think. Here's the updated code:

Code: [Select]
module GPU_HW_Control_Regs (

input rst,
input clk,
input we,
input [19:0] addr_in,
input [7:0] data_in,

output reg  [7:0] GPU_HW_Control_regs[2**HW_REGS_SIZE]

);
 
parameter HW_REGS_SIZE = 8;
parameter BASE_WRITE_ADDRESS = 20'h003F00;
parameter RST_VALUE_0 = 16'h0000;
parameter RST_VALUE_1 = 16'h0011;
parameter RST_VALUE_2 = 16'h0022;
parameter RST_VALUE_3 = 16'h0033;
parameter RST_VALUE_4 = 16'h0044;
parameter RST_VALUE_5 = 16'h0055;
parameter RST_VALUE_6 = 16'h0066;
parameter RST_VALUE_7 = 16'h0077;

This should be more functional, closer to my spec, and easier to see on the simulation.
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #484 on: November 26, 2019, 06:19:35 pm »
This should be more functional, closer to my spec, and easier to see on the simulation.

Okay, I've updated the code with those changes - still can't compile it in Quartus Prime.  :-\  Getting this error still:

Error (10016): Can't create symbol/include/instantiation/component file for module "GPU_HW_Control_Regs" because port "GPU_HW_Control_regs" has an unsupported type


This is where the problem is:

Code: [Select]
output reg  [7:0] GPU_HW_Control_regs[2**HW_REGS_SIZE]

If I remove [2**HW_REGS_SIZE] it compiles.  Is it not happy with the parameter size or the maths going on there? Or both?
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7747
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #485 on: November 26, 2019, 06:29:28 pm »
Arrrrrrrgggg  :rant: Damn Quartus prime and QuartusIIv9.1 with their 'SPECIFIC' syntax which must be met just for the block diagram entry.  This version works, generates the block diagram, compiles without warnings, still System Verilog compliant, and simulates properly too:

Do not loose this example.  It works, and is totally parameter configurable, including the 'Arrayed' parameter feature.

Not only that, but, the 'Generate Sheet Symbol' function now also works in Quartus II v9.1!!!
(Not to mention compiling and simulating in 2 seconds instead of 50 seconds!)


Code: [Select]
module GPU_HW_Control_Regs (

input rst,
input clk,
input we,
input [19:0] addr_in,
input [7:0] data_in,

output reg  [7:0] GPU_HW_Control_regs[0:(2**HW_REGS_SIZE-1)]

);
 
parameter HW_REGS_SIZE = 8;
parameter int BASE_WRITE_ADDRESS = 20'h0;

parameter int RST_VALUES [32] = '{
8'h01, 8'h02, 8'h03, 8'h04, 8'h05, 8'h06, 8'h07, 8'h08,
8'h09, 8'h0A, 8'h0B, 8'h0C, 8'h0D, 8'h0E, 8'h0F, 8'h10,
8'h11, 8'h12, 8'h13, 8'h14, 8'h15, 8'h16, 8'h17, 8'h18,
8'h19, 8'h1A, 8'h1B, 8'h1C, 8'h1D, 8'h1E, 8'h1F, 8'h20 };

wire valid_wr;

assign valid_wr = we && ( addr_in[19:HW_REGS_SIZE] == BASE_WRITE_ADDRESS[19:HW_REGS_SIZE] ); // upper 8-bits of addr_in should equal data_in for a successful write

integer i;
 
always @ (posedge clk) begin

if (rst) begin

// reset key registers to initial values
for (i = 0; i < 32; i = i + 1) begin
GPU_HW_Control_regs[i] <= RST_VALUES[i][7:0];
end

// reset remaining registers to zero
for (i = 32; i < 2**HW_REGS_SIZE; i = i + 1) begin
GPU_HW_Control_regs[i] <= 8'h0;
end

end
else
begin

if (valid_wr) begin

// apply written value to addressed register
GPU_HW_Control_regs[addr_in[HW_REGS_SIZE-1:0]] <= data_in;

end

end
end

endmodule

« Last Edit: November 26, 2019, 09:41:59 pm by BrianHG »
 
The following users thanked this post: nockieboy

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7747
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #486 on: November 26, 2019, 06:33:52 pm »
I've attached a simulation test bench Quartus project of the above code testing a few writes, then a sudden reset.  As you can see, the simulation proves the module is doing exactly what we want it to do...
« Last Edit: November 26, 2019, 06:36:35 pm by BrianHG »
 
The following users thanked this post: nockieboy

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7747
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #487 on: November 26, 2019, 06:43:44 pm »
Ok, it's time to get onto points #4 and #5 here: https://www.eevblog.com/forum/fpga/fpga-vga-controller-for-8-bit-computer/msg2788698/#msg2788698

Note: place the register bank in the last 256 bytes of the 16kb addressable memory and tie it's data/address/we inputs to the RS232 debugger outputs in parallel with system 'host_' memory.

I'm assuming you will be updating points #2.  And, we will wait on point #1 so you will see what happens and why point #1 needs to be taken care of after you finish point #5.

using the 'for' loop trick, point #5 is easily doable for all those cursors.  Mix the outputs in the new temporary 'color_sel' color mixing block.  Mix the lines with simple 'OR' gates right at the 'out[11:0]', prior to the modules output pins.  Show us your results...

« Last Edit: November 26, 2019, 06:45:41 pm by BrianHG »
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7747
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #488 on: November 26, 2019, 07:55:08 pm »
Damn, we would be nowhere if I didn't re-install Quartus myself...
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #489 on: November 26, 2019, 07:59:11 pm »
I've attached a simulation test bench Quartus project of the above code testing a few writes, then a sudden reset.  As you can see, the simulation proves the module is doing exactly what we want it to do...

Works just fine in 9.1.  :-+

Ok, it's time to get onto points #4 and #5 here: https://www.eevblog.com/forum/fpga/fpga-vga-controller-for-8-bit-computer/msg2788698/#msg2788698

Note: place the register bank in the last 256 bytes of the 16kb addressable memory and tie it's data/address/we inputs to the RS232 debugger outputs in parallel with system 'host_' memory.

I'm assuming you will be updating points #2.  And, we will wait on point #1 so you will see what happens and why point #1 needs to be taken care of after you finish point #5.

using the 'for' loop trick, point #5 is easily doable for all those cursors.  Mix the outputs in the new temporary 'color_sel' color mixing block.  Mix the lines with simple 'OR' gates right at the 'out[11:0]', prior to the modules output pins.  Show us your results...

Okay, will have a go at this tomorrow now as I doubt I'll have any time tonight the way things are going.   ::)

Damn, we would be nowhere if I didn't re-install Quartus myself...

Some things are just too complicated to give direction by proxy, I guess.  Quartus is certainly one of those things.  :-\
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #490 on: November 27, 2019, 10:56:23 am »
Ok, it's time to get onto points #4 and #5 here: https://www.eevblog.com/forum/fpga/fpga-vga-controller-for-8-bit-computer/msg2788698/#msg2788698

Note: place the register bank in the last 256 bytes of the 16kb addressable memory and tie it's data/address/we inputs to the RS232 debugger outputs in parallel with system 'host_' memory.

Okay, point #4 is nearly done.  I've attached the project below - that's the LATEST version, with all the changes so far including point #4 changes and some tweaks I made to the format of the vid_osd_generator code at the very start to make the I/O declarations easier to read.  I've also made the connections on the design sheet to the outputs of the RS232 module, so should all be present and correct.

Here's a screenshot of the design sheet now - it's getting hard to fit into one screen:

879708-0

(I'm aware I've set a hex value when it should be INT for the BASE_WRITE_ADDRESS in the design sheet - that's corrected).  However, it won't compile due to bus width errors - it seems Quartus isn't happy with me connecting a 14-lane bus from host_addr in the RS232 debugger module to a 20-lane input bus for addr_in in the GPU_HW_Control_Regs module.  It's also complaining about bus width errors elsewhere where the GPU_HW_REGS_BUS connects to other modules.

Is there an easy way to interface buses of different sizes without changing parameters in the modules themselves?
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #491 on: November 27, 2019, 12:45:53 pm »
In danger of diluting the focus of our current efforts (#4 & #5 in the current task list), here's my latest on #1.  I've updated the sync_generator to include the 16 pixel X and Y offset.  Not 100% convinced you'll be happy with how I've done it, but it seems to work according to how I'm interpreting the simulation results (below).

879750-0

It's not visible in the screenshot above, but hde doesn't go high until the h_count = 16, and vde doesn't go high until v_count = 16.  Here's some close-ups:

879754-1

Above shows hde going high after 16 pixels.

879758-2

Above shows vde going high on the 16th line.

 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7747
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #492 on: November 27, 2019, 01:12:33 pm »
Ok, it's time to get onto points #4 and #5 here: https://www.eevblog.com/forum/fpga/fpga-vga-controller-for-8-bit-computer/msg2788698/#msg2788698

Note: place the register bank in the last 256 bytes of the 16kb addressable memory and tie it's data/address/we inputs to the RS232 debugger outputs in parallel with system 'host_' memory.

Okay, point #4 is nearly done.  I've attached the project below - that's the LATEST version, with all the changes so far including point #4 changes and some tweaks I made to the format of the vid_osd_generator code at the very start to make the I/O declarations easier to read.  I've also made the connections on the design sheet to the outputs of the RS232 module, so should all be present and correct.

Here's a screenshot of the design sheet now - it's getting hard to fit into one screen:

(Attachment Link)

(I'm aware I've set a hex value when it should be INT for the BASE_WRITE_ADDRESS in the design sheet - that's corrected).  However, it won't compile due to bus width errors - it seems Quartus isn't happy with me connecting a 14-lane bus from host_addr in the RS232 debugger module to a 20-lane input bus for addr_in in the GPU_HW_Control_Regs module.  It's also complaining about bus width errors elsewhere where the GPU_HW_REGS_BUS connects to other modules.

I just clicked on 1 error at a time and fixed them.  It compiled fine... See here...
Though, you will eventually need to up, or decide what to do with the RS232_Debugger's 14 bit address.
The desktop param does feed everything else properly.  (Warning, I changer the extension of the GPU_HW_Control_Regs.sv to GPU_HW_Control_Regs.v)
(Attachment Link)

Is there an easy way to interface buses of different sizes without changing parameters in the modules themselves?
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7747
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #493 on: November 27, 2019, 01:39:35 pm »
In danger of diluting the focus of our current efforts (#4 & #5 in the current task list), here's my latest on #1.  I've updated the sync_generator to include the 16 pixel X and Y offset.  Not 100% convinced you'll be happy with how I've done it, but it seems to work according to how I'm interpreting the simulation results (below).

(Attachment Link)

It's not visible in the screenshot above, but hde doesn't go high until the h_count = 16, and vde doesn't go high until v_count = 16.  Here's some close-ups:

(Attachment Link)

Above shows hde going high after 16 pixels.

(Attachment Link)

Above shows vde going high on the 16th line.

Your going to have to get rid of the '-1' and accept that the outputs are delayed by 1-Hcount and 1-Vcount.  Unfortunately, with the way it is setup, if you choose an offset of 0x0, the beginning positions would never happen.
The true method of getting a proper H&V count would be to make 2 new output regs, Hcount_out and Vcount_out which latch their values from the source H&V internal counters.
Having the 'Adjusting' -1 for the counter raster limits and for the syncs are fine, bur, you now need to verify that the HH&V syncs begin and stop 16 H&V positions later compared to their original locations so that the output image is still relatively centered.  This one is easy as you will just add the H&V offset to the H&V start and stop of your current formula knowing having a '0' for an offset would move nothing as it should.  Bit, wait a minute, you HDE and VDE are now 1 pixel/line later with the new setup having '0's as an offset.  It looks like your sync offsets were OFF by 1 pixel and line all along.... Who knew?  Wait, everything needs to be re-checked.  Your going to need to verify that you actually have 640 'ON' pixels, not 641... Same with lines.  Also, when does the sync begin and end.  (Remember I said there would be a pitfall...) 

Ok, to clear things up, there is a 1 count delay from the counter when you say you want the start/begin to ==.  This is fine understanding that that 1 delay is everywhere else since you H&V internal counters are preparing their value 1 clock in advance, and the 'IF(a==b) DE=<=1' result 'DE<=#' are set on the next clock.  This is fine for 2 reasons, we do not use these Hcount & Vcount anywhere else, they are just internal for the sync generator & any special trigger controls we may be adding now will also be stuck on that 1 pixel/line clock delay.



 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #494 on: November 27, 2019, 01:48:25 pm »

Thanks - so it was just the naming of the bus(es) that was the issue.  |O  I just modified the design on my current project instead of using the one you uploaded above as I have modifications to sync_generator (made a start on #5) and image offset addition.  :-+
« Last Edit: November 27, 2019, 01:53:16 pm by nockieboy »
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #495 on: November 27, 2019, 02:27:13 pm »
Your going to have to get rid of the '-1' and accept that the outputs are delayed by 1-Hcount and 1-Vcount.  Unfortunately, with the way it is setup, if you choose an offset of 0x0, the beginning positions would never happen.

:o  Yeah, you're right. Okay, removed the -1's.

Your going to need to verify that you actually have 640 'ON' pixels, not 641... Same with lines.  Also, when does the sync begin and end.  (Remember I said there would be a pitfall...)

Okay, so vde goes on on line 17 and is going off on line 496, so that seems like 480 + Y_OFFSET is working okay:

879820-0

hde is going off on pixel 656, which is 640 + X_OFFSET:

879824-1

Both come on at the right time (unless I'm misunderstanding the whole 1 pixel offset thing).

Latest zipped project file attached.
« Last Edit: November 27, 2019, 04:11:44 pm by nockieboy »
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #496 on: November 27, 2019, 04:32:30 pm »
5.  Add a new 48 register output to the 'sync_gen.v' called 'raster_HV_trigger[47:0]'.

Okay, that was easy enough - that's already in the project files I attached in my last post.  I may need some clarification of the next bits, though...  ???

Make the even 'raster_HV_trigger[47:0]' wires pulse at a horizontal pixel position and the odd wires pulse on a vertical line according to the new 'GPU_HW_Control_regs[HW_REGS_SIZE*8-1:0]' onput wire, organized as 16 bit words, using the first 10 of 16 bits of each 2x2 bytes coming from the new input "GPU_HW_Control_regs[HW_REGS_SIZE*8-1:0]".

So the even wires [0..46] need to have a positive (one-clock?) pulse when h_count matches a value that matches the 10 bits of each 2-byte pair in GPU_HW_Control_regs?

The odd wires [1..47] will be the same, but trigger when v_count matches a value in the hardware regs?

So only the wire corresponding to the appropriate byte-pair in the hardware registers will pulse?  :-//

You should add a new parameter input to the sync_gen.v which will allow you to shift the beginning byte base (beginning) address of GPU_HW_Controls where the 'raster_HV_trigger' get their 48 settings from.  IE 48x2 bytes = 96 bytes total.

Right, that makes sense.  So we're looking to use 96 bytes from the 256 available hardware registers for these raster triggers?  And this parameter will set the base where the first of 96 bytes will be read from in the hardware registers and have a value between 0 and 160 (or 2**HW_REGS - 96)?

Once done, out on your top block diagram, 'or' these 48 HV triggers outputs together and 'or' tie them to to the upper ro[],go[],bo[] bits of the OSD_img output.  Test with the GPUtalk app.  You should be able to move 24 vertical lines and 24 horizontal lines around the screen, with the first 0-15 coordinates being non-visible as those coordinates are too far to the left and above the top of the picture since we moved the picture window by 16 pixels to the right and down in step (1).  (Once working, mix and combine / change around the 'or' driven ro[]&go[]&bo[] colors VS raster_HV_trigger[47:0] even and odd pairs so each set of coordinate generated lines may generate a different color on the display.)

I was with you all the way to 'once done'...  :-DD :-//
« Last Edit: November 27, 2019, 04:38:18 pm by nockieboy »
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7747
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #497 on: November 27, 2019, 05:04:18 pm »
Think this one through....

example:

Code: [Select]
for (..i..) begin
     if  ( h_count[9:8] == HW_REGS[i*4+base_offset+0][1:0] && h_count[7:0] == HW_REGS[i*4+base_offset+1][7:0] ) raster_HV_triggers[i*2+0] <= 1;
     else raster_HV_triggers[i*2+0] <= 0;
end
then inside the 'v_count increment 'IF()begin'  Place the vertical version.

Your Syncgen should have a new output register wire called 'raster_HV_triggers[47:0]' each even one should pulse on and off for a pixel.  Make sure the odd wires in there pulse on, then off for an entire line.

Take that bundle and tie it into the current 'color_sel' module.  Make a bunch of the 'raster_HV_triggers[47:0]' force on your choice of color for each wire, over the text box and static noise, or, whatever may be feeding the color_sel modules output so you may see if what you made works...

Now, you better figure out what the 'base_offset' is, otherwise I'll go nuts.
« Last Edit: November 27, 2019, 06:30:39 pm by BrianHG »
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7747
  • Country: ca
Re: FPGA VGA Controller for 8-bit computer
« Reply #498 on: November 27, 2019, 05:29:14 pm »
Your going to miss the vcount position '==0' if you keep your 'VDE' in it's current location.  Move it outside the vcounter increment but leave it inside when the vcoun increment happens...


This is what you have now, it needs correcting...
Code: [Select]
// reset h_count & increment v_count at end of scanline
if (h_count == LINE - 1) // end of line
begin
h_count <= 9'b0; // reset h_count

// Now h_count has been zeroed, check if the V-count should be cleared at end of SCANLINES
if (v_count == SCANLINES - 1)
begin
v_count <= 9'b0;
frame_ctr <= frame_ctr + 1'b1; // Increment the frame counter
end
else
begin // If v_count isn't being cleared, increment v_count
v_count <= v_count + 1'b1; // increment v_count to next scanline

if (v_count == IMAGE_OFFSET_Y)
vde <= 1'b1; // Turn on vertical video data enable - start of display area
else if (v_count == IMAGE_OFFSET_Y + V_RES - 1)
vde <= 1'b0 ; // Turn off vertical video data enable - reached bottom of display area
end
end

Actually, this would still work unless you vde is set to SCANLINES - 1....
« Last Edit: November 27, 2019, 05:35:57 pm by BrianHG »
 

Offline nockieboyTopic starter

  • Super Contributor
  • ***
  • Posts: 1812
  • Country: england
Re: FPGA VGA Controller for 8-bit computer
« Reply #499 on: November 27, 2019, 08:47:02 pm »
Your going to miss the vcount position '==0' if you keep your 'VDE' in it's current location.  Move it outside the vcounter increment but leave it inside when the vcoun increment happens...


This is what you have now, it needs correcting...
Code: [Select]
// reset h_count & increment v_count at end of scanline
if (h_count == LINE - 1) // end of line
begin
h_count <= 9'b0; // reset h_count

// Now h_count has been zeroed, check if the V-count should be cleared at end of SCANLINES
if (v_count == SCANLINES - 1)
begin
v_count <= 9'b0;
frame_ctr <= frame_ctr + 1'b1; // Increment the frame counter
end
else
begin // If v_count isn't being cleared, increment v_count
v_count <= v_count + 1'b1; // increment v_count to next scanline

if (v_count == IMAGE_OFFSET_Y)
vde <= 1'b1; // Turn on vertical video data enable - start of display area
else if (v_count == IMAGE_OFFSET_Y + V_RES - 1)
vde <= 1'b0 ; // Turn off vertical video data enable - reached bottom of display area
end
end


Actually, this would still work unless you vde is set to SCANLINES - 1....

Soooo... How about I just move the VDE assignment out of the if (v_count == SCANLINES - 1) conditional entirely?  It'll be assigned no matter what the outcome of the if-conditional then.

Code: [Select]
if (v_count == IMAGE_OFFSET_Y)
vde <= 1'b1; // Turn on vertical video data enable - start of display area
else if (v_count == IMAGE_OFFSET_Y + V_RES - 1)
vde <= 1'b0 ; // Turn off vertical video data enable - reached bottom of display area

// Now h_count has been zeroed, check if the V-count should be cleared at end of SCANLINES
if (v_count == SCANLINES - 1)
begin

v_count <= 9'b0;
frame_ctr <= frame_ctr + 1'b1; // Increment the frame counter

end
else
begin // If v_count isn't being cleared, increment v_count

v_count <= v_count + 1'b1; // increment v_count to next scanline

end


Owzat?

example:

Code: [Select]
for (..i..) begin
     if  ( h_count[9:8] == HW_REGS[i*4+base_offset+0][1:0] && h_count[7:0] == HW_REGS[i*4+base_offset+1][7:0] ) raster_HV_triggers[i*2+0] <= 1;
     else raster_HV_triggers[i*2+0] <= 0;
end

then inside the 'v_count increment 'IF()begin'  Place the vertical version.

Your Syncgen should have a new output register wire called 'raster_HV_triggers[47:0]' each even one should pulse on and off for a pixel.  Make sure the odd wires in there pulse on, then off for an entire line.

Take that bundle and tie it into the current 'color_sel' module.  Make a bunch of the 'raster_HV_triggers[47:0]' force on your choice of color for each wire, over the text box and static noise, or, whatever may be feeding the color_sel modules output so you may see if what you made works...

Hmm.. well nothing blows up, so that's good I guess? ???  I'm going to have to remind myself how the values in raster_HV_triggers work.  I'd be lying if I said:

Code: [Select]
h_count[9:8] == GPU_HW_Control_regs[i*4+BASE_OFFSET][1:0] && h_count[7:0] == GPU_HW_Control_regs[i*4+BASE_OFFSET+1][7:0]

...didn't confuse the hell out of me.  :o  Doesn't help that concentration is difficult when I've got a daughter singing the theme tune to Frozen 2 in my ear...  :blah:

Now, you better figure out what the 'base_offset' is, otherwise I'll go nuts.

Oh ye of little faith..  ^-^  (Hoping against all hope that I actually did get it right!)

Code: [Select]
// VGA Sync Generator
//
// Default: 640x480x60
//
// Can take parameters when initialised
// to output sync signals for any screen
// resolution

module sync_generator(

// inputs
input wire pclk, // base pixel clock (125 MHz)
input wire reset, // reset: restarts frame
input wire [7:0] GPU_HW_Control_regs[0:(2**HW_REGS_SIZE-1)],

// outputs
output reg [3:0] pc_ena,  // Pixel clock enable (4-bit to allow clock division in video sub-modules)
output reg hde, // Horizontal Display Enable - high when in display area (valid drawing area)
output reg vde, // Vertical Display Enable - high when in display area (valid drawing area)
output reg hsync, // horizontal sync
output reg vsync, // vertical sync

output reg [15:0] frame_ctr,
output reg [47:0] raster_HV_triggers

);

// default resolution if no parameters are passed
parameter H_RES = 640; // horizontal display resolution
parameter V_RES = 480; // vertical display resolution

// image offset parameters
parameter IMAGE_OFFSET_X = 16; // offset the display to allow room at the start
parameter IMAGE_OFFSET_Y = 16; // for things to go off edge of screen

// no-draw area definitions
// defined as parameters so you can edit these on Quartus' block diagram editor
parameter H_FRONT_PORCH = 16;
parameter HSYNC_WIDTH = 96;
parameter H_BACK_PORCH = 48;
parameter V_FRONT_PORCH = 10;
parameter VSYNC_HEIGHT = 2;
parameter V_BACK_PORCH = 33;
parameter PIX_CLK_DIVIDER = 4;

parameter HW_REGS_SIZE = 8; // hardware register size set by HW_REGS parameter in design sheet
parameter BASE_OFFSET = 32; // hardware register base offset for raster triggers

// total screen resolution
localparam LINE = H_RES + H_FRONT_PORCH + HSYNC_WIDTH + H_BACK_PORCH; // complete line (inc. horizontal blanking area)
localparam SCANLINES = V_RES + V_FRONT_PORCH + VSYNC_HEIGHT + V_BACK_PORCH; // total scan lines (inc. vertical blanking area)

// useful trigger points
localparam HS_STA = IMAGE_OFFSET_X + H_RES + H_FRONT_PORCH - 1; // horizontal sync ON (the minus 1 is because hsync is a REG, and thus one clock behind)
localparam HS_END = IMAGE_OFFSET_X + H_RES + H_FRONT_PORCH + HSYNC_WIDTH - 1; // horizontal sync OFF (the minus 1 is because hsync is a REG, and thus one clock behind)
localparam VS_STA = IMAGE_OFFSET_Y + V_RES + V_FRONT_PORCH; // vertical sync ON
localparam VS_END = IMAGE_OFFSET_Y + V_RES + V_FRONT_PORCH + VSYNC_HEIGHT; // vertical sync OFF

reg [9:0] h_count; // current pixel x position
reg [9:0] v_count; // current line y position

   always @(posedge pclk)
if (pc_ena == PIX_CLK_DIVIDER) pc_ena <= 0;
else pc_ena <= pc_ena +1;

integer i;

// handle signal generation
always @(posedge pclk)
begin

if (reset) // reset to start of frame
begin
h_count <= (IMAGE_OFFSET_X + H_RES - 2);
v_count <= (SCANLINES - 2);
//z_count <= 1'b0;
hsync   <= 1'b0;
vsync   <= 1'b0;
vde     <= 1'b0;
hde     <= 1'b0;
frame_ctr <= 16'h0000;
end
else
begin
if (pc_ena[3:0] == 0) // once per pixel
begin

// horizontal raster trigger generation
for (i = 0; i < 24; i = i + 2) begin

if ( h_count[9:8] == GPU_HW_Control_regs[i*4+BASE_OFFSET][1:0] && h_count[7:0] == GPU_HW_Control_regs[i*4+BASE_OFFSET+1][7:0] )
raster_HV_triggers[i*2+0] <= 1'b1;
else
raster_HV_triggers[i*2+0] <= 1'b0;

end

// horizontal blanking area - set HDE LOW
if (h_count == IMAGE_OFFSET_X + H_RES - 1)
hde <= 1'b0; // Turn off horizontal video data enable
else if (h_count == IMAGE_OFFSET_X)
hde <= 1'b1;  // Turn on horizontal video data enable

// check for generation of HSYNC pulse
if (h_count == HS_STA)
hsync <= 1'b1; // turn on HSYNC pulse
else if (h_count == HS_END)
hsync <= 1'b0; // turn off HSYNC pulse

// check for generation of VSYNC pulse
if (v_count == VS_STA)
vsync <= 1'b1; // turn on VSYNC pulse
else if (v_count == VS_END)
vsync <= 1'b0; // turn off VSYNC pulse

// reset h_count & increment v_count at end of scanline
if (h_count == LINE - 1) // end of line
begin

h_count <= 9'b0; // reset h_count

// vertical raster trigger generation
for (i = 1; i < 24; i = i + 2) begin

if ( v_count[9:8] == GPU_HW_Control_regs[i*4+BASE_OFFSET][1:0] && v_count[7:0] == GPU_HW_Control_regs[i*4+BASE_OFFSET+1][7:0] )
raster_HV_triggers[i*2+0] <= 1'b1;
else
raster_HV_triggers[i*2+0] <= 1'b0;

end

if (v_count == IMAGE_OFFSET_Y)
vde <= 1'b1; // Turn on vertical video data enable - start of display area
else if (v_count == IMAGE_OFFSET_Y + V_RES - 1)
vde <= 1'b0 ; // Turn off vertical video data enable - reached bottom of display area

// Now h_count has been zeroed, check if the V-count should be cleared at end of SCANLINES
if (v_count == SCANLINES - 1)
begin

v_count <= 9'b0;
frame_ctr <= frame_ctr + 1'b1; // Increment the frame counter

end
else
begin // If v_count isn't being cleared, increment v_count

v_count <= v_count + 1'b1; // increment v_count to next scanline

end
end
else // not at end of scanline, so just increment horizontal counter
begin

h_count <= h_count + 1'b1;
if (h_count == IMAGE_OFFSET_X + H_RES - 1)
hde <= 1'b0 ;  // Turn off horizontal video data enable

end // if (h_count == LINE - 1)

end // if (pc_ena)

end // else !reset

end // always @clk

endmodule
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf