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:
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:
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?
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.
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?
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.
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.