Code: [Select]// horizontal raster trigger generation
for (i = 0; i < 24; i = i + 1) begin
if ( h_count[9:8] == GPU_HW_Control_regs[i*4+BASE_OFFSET+0][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
------------------------------------------------------------------------------------------------------------------
// vertical raster trigger generation
for (i = 1; i < 24; i = i + 1) begin
if ( v_count[9:8] == GPU_HW_Control_regs[i*4+BASE_OFFSET+2][1:0] && v_count[7:0] == GPU_HW_Control_regs[i*4+BASE_OFFSET+3][7:0] )
raster_HV_triggers[i*2+1] <= 1'b1;
else
raster_HV_triggers[i*2+1] <= 1'b0;
end
Hints, what's i*2+1 = when 'i' is 23?
What's the top 'raster_HV_triggers' wire position.
Read all the other changes...
I'm expecting to see some screenshots with cursor lines which your positioned & moved around with the RS232_Debugger... Maybe video of them animated using the RS232_Debugger's mouse wheel, or +/- keys which actually edit a full 16bit word...
I also expect you to discover 1 problem with the vertical lines...
I also expect you to discover 1 problem with the vertical lines...
I also expect you to discover 1 problem with the vertical lines...
Still looking for this one. The vertical line on the left appears at 16, which seems okay. The vertical line on the right edge of the screen, however, is at 661, which seems odd...
EDIT: Latest project files attached.
Step #1 test if all ' raster_HV_triggers[47..0] ' do something....
Problem #1. raster_HV_triggers[1], the first horizontal line after the first vertical line seems to be dead!!!
These are the coordinates I set in the first 4 functional cursors:
raster_HV_triggers[0] = $0017 = 23 decimal. First vertical line at left most of screen. (Bad)
raster_HV_triggers[1] = DEAD [FIXED]
raster_HV_triggers[2] = $0295 = 661 decimal. Right most pixel on screen. (Bad)
raster_HV_triggers[3] = $0010 = 16 decimal. Top most line on screen. (The 1 good thing...)
#4 skipped as it is vertical...
raster_HV_triggers[5] = $01EE = 494 decimal. Bottom most visible line. (Bad, Error, see if you can figure out why...)
Now, don't threat, I've done this stuff for years and know where your problems are, however, enough development and tools have been doe that you should be able to figure out the solutions.
Think through the IF's. What mutes the video on the screen, or allows it through.
Also think about pixel coordinates and their numbers.
Try setting the X&Y offset parameters down to 0, play with the H&V numbers to give you a hand and really think through what happens when in the 'IF (a==b) statements. What the numbers are at each clock and what happens to the results and 'WHEN'...
As for the vertical lines, obviously think about when they come out and if I said that the OSD was dead perfect since I simulated the whole thing even before I 'threw' your GPU into one of my scalers, why is the text ok and why is the vertical lines miss located?
Horizontal raster triggers:
The first vertical line should appear at 16, but appears at 23 (out by +7).
The last vertical line should appear at 656 (640+16 X_offset) but appears at 661 (out by +5).
Vertical raster triggers:
The first horizontal appears at 16 decimal, so that's okay.
The last appears at 494 decimal, when it should be 496 (480+16 Y_offset) (out by 2).
Lets start with the Horizontal line only. You say 0 starts at 0. Fine. Now, at 640x480, starting coordinate Y 0, where does Y actually end?
Lets start with the Horizontal line only. You say 0 starts at 0. Fine. Now, at 640x480, starting coordinate Y 0, where does Y actually end?
With no offset, the display area ends at 479 and the last line is 524. So could it just be a -1 error as it appears at 478?
if (v_count == IMAGE_OFFSET_Y)
vde <= 1'b1; // Turn on vertical video data enable - start of display area
When does it do it? else if (v_count == IMAGE_OFFSET_Y + V_RES - 1)
vde <= 1'b0 ; // Turn off vertical video data enable - reached bottom of display area
When does it do it?If IMAGE_OFFSET_Y is 0, what does this line of code do?Code: [Select]if (v_count == IMAGE_OFFSET_Y)
When does it do it?
vde <= 1'b1; // Turn on vertical video data enable - start of display area
Next, assuming IMAGE_OFFSET_Y is till 0, and V_RES is 480: What does this line do?Code: [Select]else if (v_count == IMAGE_OFFSET_Y + V_RES - 1)
When does it do it?
vde <= 1'b0 ; // Turn off vertical video data enable - reached bottom of display area
If IMAGE_OFFSET_Y is 0, what does this line of code do?Code: [Select]if (v_count == IMAGE_OFFSET_Y)
When does it do it?
vde <= 1'b1; // Turn on vertical video data enable - start of display area
It turns vde on when v_count is 0. As for when it does it - I guess on the rising edge of the next CLK?Next, assuming IMAGE_OFFSET_Y is till 0, and V_RES is 480: What does this line do?Code: [Select]else if (v_count == IMAGE_OFFSET_Y + V_RES - 1)
When does it do it?
vde <= 1'b0 ; // Turn off vertical video data enable - reached bottom of display area
It turns vde off when v_count is 479 - again, on the rising edge of the next CLK pulse?
Ok, now here is the important bit....
Ignoring the clk for a second, if you have the video enable turning ON on line 0, and your starting coordinate Y is 0 and this is correct on the screen, do you not think turning OFF the visible line at line 479 is a bad idea if you want to visibly see line 479?
Regardless if the counter is behind by 1 CLK, meaning this hidden internal counter is already +1, meaning whend you turn on at line 0, the counter may be at line 1, and the same for at the end since the switch on and off both have the same delay....
if (v_count == IMAGE_OFFSET_Y) <---- REMOVED -1
vde <= 1'b1; // Turn on vertical video data enable - start of display area
else if (v_count == IMAGE_OFFSET_Y + V_RES)
vde <= 1'b0 ; // Turn off vertical video data enable - reached bottom of display area
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)
--------------------------------------------------------------------------------------------
if (h_count == IMAGE_OFFSET_X + H_RES - 1)
--------------------------------------------------------------------------------------------
if (h_count == IMAGE_OFFSET_X + H_RES - 1)
--------------------------------------------------------------------------------------------
Do a simulation and show me the key horizontal numerical points. Make sure everything is going off and of with the right amount of pixels, regardless that they will all be shifted to the right by 1 pixel.Do a simulation and show me the key horizontal numerical points. Make sure everything is going off and of with the right amount of pixels, regardless that they will all be shifted to the right by 1 pixel.
@nockieboy I realize the holidays coming up with family obligations must be adding a toll on your available time to concentrate here.
You have 1 thing left to verify about the sync generator, then, you will be gutting the osd_generator and wiring in 2 or 3 address generators in place of my limited 64x32 column current one.
We'll skip sprites and just do the final 2 palette memories and overlay. You already have what might already be functional Z80 interface, but you may want to multiplex that GPU memory interface side with a separate module so you may have additional access within the GPU project.
If there is time later, we'll look at piggy-backing on some sprites and other more advanced features.
// 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 + 1) begin
if ( h_count[9:8] == GPU_HW_Control_regs[i*4+BASE_OFFSET+0][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
// start of visible display area - set HDE HIGH
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 = 0; i < 24; i = i + 1) begin
if ( v_count[9:8] == GPU_HW_Control_regs[i*4+BASE_OFFSET+2][1:0] && v_count[7:0] == GPU_HW_Control_regs[i*4+BASE_OFFSET+3][7:0] )
raster_HV_triggers[i*2+1] <= 1'b1;
else
raster_HV_triggers[i*2+1] <= 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)
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)
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
Do a simulation and show me the key horizontal numerical points. Make sure everything is going off and of with the right amount of pixels, regardless that they will all be shifted to the right by 1 pixel.
Okay, I'm hoping this is what you're asking for... I've got the start of the visible display (top left of screen) and end of the visible display (bottom right of screen):
Start:
(Attachment Link)
End:
(Attachment Link)@nockieboy I realize the holidays coming up with family obligations must be adding a toll on your available time to concentrate here.
Yes, work had cranked up the last week as well, so I've been finding it very hard to find time to work on the project.You have 1 thing left to verify about the sync generator, then, you will be gutting the osd_generator and wiring in 2 or 3 address generators in place of my limited 64x32 column current one.
We'll skip sprites and just do the final 2 palette memories and overlay. You already have what might already be functional Z80 interface, but you may want to multiplex that GPU memory interface side with a separate module so you may have additional access within the GPU project.
If there is time later, we'll look at piggy-backing on some sprites and other more advanced features.
I would really appreciate being able to get some form of sprite support implemented, but I understand that your time is limited. I may have some time this week so I'll try to catch up as best I can.
I have the hardware for the Z80 interface sorted (well, it's just a breadboard with 4 buffers on it to convert from 5V down to 3.3V and a bi-directional buffer for the data bus), I think it's just the mux to allow the RS232 and the Z80_bridge modules to work alongside each other. I haven't given that any thought past your previous comments on it yet.
EDIT:
Added end of line as well:
[ Attachment Invalid Or Does Not Exist ]
So, I've removed a couple of the -1's from the checks for the hde assignment - I've also removed an unnecessary check to turn off hde when leaving the visible area as it's already done further down in the code. Updated sync_generator code is below, but I've also attached the current project so we're on the same page.
This change means that the bottom horizontal bar is at decimal 495, and the far right vertical is now on decimal 662 (with X_OFFSET and Y_OFFSET set to 16).
Though I'm still going round in circles with this - I'm going to need you to tell me what the issue is, I think, as I'll never find it before Christmas on my own.
(Okay, can't leave the code for sync_generator in this post as there's a bug in the forum software that doesn't allow me to post code blocks in the same forum post as attachments for some reason.)
if (h_count == IMAGE_OFFSET_X + H_RES)
hde <= 1'b0 ; // Turn off horizontal video data enable
if (h_count == IMAGE_OFFSET_X)
hde <= 1'b1; // Turn on horizontal video data enable
adding the word 'ELSE' in front of the 'Turn Off' if().If your arbiter only samples the request signals when there is no request in progress, there won't be any conflicts.
Ok, VDE beginning 1 pixel to the left is OK as it will not affect anything anywhere else.
There is 1 minor change I want you to make, though it wont alter anything, in reading the code, in the future, it will make things easier:
Move this line:Code: [Select]if (h_count == IMAGE_OFFSET_X + H_RES)
hde <= 1'b0 ; // Turn off horizontal video data enable
To right after this line:Code: [Select]if (h_count == IMAGE_OFFSET_X)
adding the word 'ELSE' in front of the 'Turn Off' if().
hde <= 1'b1; // Turn on horizontal video data enable
Ok, now, for that pesky vertical margin bars being off the the right by 6 pixels. Tell me:
Why do you think we pass the 'hde, vde, vs, hs' coming out of the sync generator, going into the 'vid_ods_generator', then out of the 'vid_osd_generator' into the 'vid_out_stencil' then out of there into the video output pins? Why didn't we just tie those signals straight from the sync generator to all those adjacent modules and the output pins in parallel?
Where is the test picture coming out of?
Where are the HV triggers currently coming out of?
Ok, VDE beginning 1 pixel to the left is OK as it will not affect anything anywhere else.
There is 1 minor change I want you to make, though it wont alter anything, in reading the code, in the future, it will make things easier:
Move this line:Code: [Select]if (h_count == IMAGE_OFFSET_X + H_RES)
hde <= 1'b0 ; // Turn off horizontal video data enable
To right after this line:Code: [Select]if (h_count == IMAGE_OFFSET_X)
adding the word 'ELSE' in front of the 'Turn Off' if().
hde <= 1'b1; // Turn on horizontal video data enable
All done.Ok, now, for that pesky vertical margin bars being off the the right by 6 pixels. Tell me:
Why do you think we pass the 'hde, vde, vs, hs' coming out of the sync generator, going into the 'vid_ods_generator', then out of the 'vid_osd_generator' into the 'vid_out_stencil' then out of there into the video output pins? Why didn't we just tie those signals straight from the sync generator to all those adjacent modules and the output pins in parallel?
Where is the test picture coming out of?
Where are the HV triggers currently coming out of?
Ahhh... of course! There's a 6-pixel delay on hde, vde, vs and hs. How did I not see that?!
So the question now is: what's the best way to delay the 48 triggers by PIPE_DELAY? I could create a 48-wide delay pipe, but to my inexperienced mind that seems very wasteful...