1
0
mirror of https://github.com/mist-devel/mist-board.git synced 2026-01-26 11:51:45 +00:00

Bottom border overscan

This commit is contained in:
harbaum
2013-07-30 15:47:53 +00:00
parent 26b38ce8a6
commit a6f6474ff1
5 changed files with 92 additions and 21 deletions

View File

@@ -322,6 +322,7 @@ PROCESS (clk, reset, state, as_s, as_e, rw_s, rw_e, uds_s, uds_e, lds_s, lds_e)
data_akt_s <= '0';
CASE S_state IS
WHEN "00" => IF state/="01" AND sel_fast='0' THEN
as_s <= '0';
rw_s <= wr;
uds_s <= uds_in;
lds_s <= lds_in;

View File

@@ -1,5 +1,8 @@
//
// define this for cubase acia irq hack
// `define CUBHACK
module mfp (
// cpu register interface
input clk,
@@ -235,12 +238,28 @@ always @(iack, sel, ds, rw, addr, gpip_cpu_out, aer, ddr, ier, ipr, isr, imr,
end
end
`ifndef CUBHACK
// delay de and timer to detect changes
reg acia_irqD, acia_irqD2, dma_irqD, dma_irqD2;
`endif
reg [7:0] irq_vec;
always @(posedge clk) begin
iackD <= iack;
`ifndef CUBHACK
dma_irqD <= dma_irq;
acia_irqD <= acia_irq;
`endif
iackD <= iack;
// the polarity of the irq is negated over a real st.
// if(aer[7]) dma_irqD <= dma_irq;
// else dma_irqD <= !dma_irq;
// if(aer[6]) acia_irqD <= acia_irq;
// else acia_irqD <= !acia_irq;
// the pending irq changes in the middle of an iack
// phase, so we latch the current vector to keep is stable
// during the entire cpu read
@@ -249,6 +268,9 @@ end
reg iackD;
always @(negedge clk) begin
dma_irqD2 <= dma_irqD;
acia_irqD2 <= acia_irqD;
if(reset) begin
ipr <= 16'h0000; ier <= 16'h0000;
imr <= 16'h0000; isr <= 16'h0000;
@@ -271,13 +293,29 @@ always @(negedge clk) begin
if(timerc_done && ier[ 5]) ipr[ 5] <= 1'b1; // timer_c
if(timerd_done && ier[ 4]) ipr[ 4] <= 1'b1; // timer_d
// irq by acia ...
if(acia_irq && ier[6])
ipr[6] <= 1'b1;
`ifndef CUBHACK
// in the real atari st the irqs are edge sensitive. however, this makes problems
// with the acias in cubase as a work around ...
if(acia_irqD && !acia_irqD2) begin
if(ier[6]) ipr[6] <= 1'b1;
end
// ... and dma
if(dma_irqD && !dma_irqD2) begin
if(ier[7]) ipr[7] <= 1'b1;
end
`else
// ... they can be implemented level sensitive. However, this breaks some games
// like eg. "no second place" and even the rainbow logo in the tos 1.04 desktop
// irq by acia ...
if(acia_irq && ier[6])
ipr[6] <= 1'b1;
// ... and dma
if(dma_irq && ier[7])
ipr[7] <= 1'b1;
ipr[7] <= 1'b1;
`endif
if(sel && ~ds && ~rw) begin
if(addr == 5'h00) gpip <= din;

View File

@@ -111,7 +111,7 @@ always @(negedge CLK) begin
down_counter <= data;
T_O_PULSE <= 1'b1;
end else begin
end else begin
down_counter <= down_counter - 8'd1;
end

View File

@@ -100,7 +100,7 @@ always @(posedge clk_8) begin
// timeout only when cpu owns the bus and when
// neither dtack nor fast ram are active
if(dtack_timeout != 3'd7) begin
if(!tg68_dtack || br || tg68_cpuena || tg68_as)
if(!tg68_dtack || br || tg68_cpuena || tg68_lds || tg68_uds)
dtack_timeout <= 3'd0;
else
dtack_timeout <= dtack_timeout + 3'd1;
@@ -540,7 +540,7 @@ wire [22:0] ram_address;
wire [15:0] ram_data;
wire video_cycle = (bus_cycle[3:2] == 0);
wire cpu_cycle = (bus_cycle[3:2] == 1);
wire cpu_cycle = (bus_cycle[3:2] == 1); // || (bus_cycle[3:2] == 3);
wire io_cycle = (bus_cycle[3:2] == 2);
assign ram_address = video_cycle?video_address:tg68_adr[23:1];
@@ -555,9 +555,9 @@ wire MEM8M = (system_ctrl[3:1] == 3'd4);
wire MEM14M = (system_ctrl[3:1] == 3'd5);
// ram from 0x000000 to 0x400000
wire cpu2ram = (tg68_adr[23:22] == 2'b00) || // ordinary 4MB
wire cpu2ram = (tg68_adr[23:22] == 2'b00) || // ordinary 4MB
((MEM14M || MEM8M) && (tg68_adr[23:22] == 2'b01)) || // 8MB
(MEM14M && ((tg68_adr[23:22] == 2'b10) | // 12MB
(MEM14M && ((tg68_adr[23:22] == 2'b10) || // 12MB
(tg68_adr[23:21] == 3'b110))); // 14MB
wire cpu2ram14 = (tg68_adr[23:22] == 2'b00) || // ordinary 4MB
@@ -588,7 +588,8 @@ wire cpu2iack = (tg68_adr[23:4] == 20'hfffff);
// wire address_strobe = ~tg68_uds || ~tg68_lds;
reg address_strobe;
always @(posedge clk_8)
address_strobe <= (video_cycle) && ~tg68_as;
// address_strobe <= (video_cycle) && (~tg68_lds || ~tg68_uds);
address_strobe <= video_cycle && ~tg68_as;
// generate dtack (for st ram only and rom), TODO: no dtack for rom write
// assign tg68_dtack = ~(((cpu2mem && address_strobe && cpu_cycle) || io_dtack ) && !br);

View File

@@ -13,6 +13,11 @@
// vdisp 400 200
// vtot 501 315/262
// Overscan:
// http://codercorner.com/fullscrn.txt
// Examples: automation 000 + 001: bottom border
// automation 097: top+ bottom border
module video (
// system interface
@@ -181,8 +186,13 @@ reg [1:0] shmode;
wire mono = (shmode == 2'd2);
wire low = (shmode == 2'd0);
// syncmode is delayed until next vsync to cope with "bottom border overscan"
reg [1:0] syncmode;
wire pal = (syncmode[1] == 1'b1);
reg [1:0] syncmode_latch;
wire pal = (syncmode_latch[1] == 1'b1);
reg overscan; // overscan detected in current frame
reg overscan_latched;
// 16 colors with 3*3 bits each
reg [2:0] palette_r[15:0];
@@ -257,7 +267,11 @@ always @(negedge reg_clk) begin
if(reg_sel && ~reg_rw) begin
if(reg_addr == 6'h00 && ~reg_lds) _v_bas_ad[22:15] <= reg_din[7:0];
if(reg_addr == 6'h01 && ~reg_lds) _v_bas_ad[14:7] <= reg_din[7:0];
if(reg_addr == 6'h05 && ~reg_uds) syncmode <= reg_din[9:8];
if(reg_addr == 6'h05 && ~reg_uds) begin
// writing to sync mode toggles between 50 and 60 hz modes
syncmode <= reg_din[9:8];
end
// the color palette registers
if(reg_addr >= 6'h20 && reg_addr < 6'h30 ) begin
@@ -295,37 +309,37 @@ wire [2:0] stvid_g = mono?mono_rgb:color_g;
wire [2:0] stvid_b = mono?mono_rgb:color_b;
// ... add OSD overlay and feed into VGA outputs
//assign video_r = !osd_oe?{stvid_r,stvid_r}:{osd_pixel, osd_pixel, osd_pixel, stvid_r};
//assign video_g = !osd_oe?{stvid_g,stvid_g}:{osd_pixel, osd_pixel, 1'b1, stvid_g};
//assign video_b = !osd_oe?{stvid_b,stvid_b}:{osd_pixel, osd_pixel, osd_pixel, stvid_b};
always @(posedge clk) begin
video_r <= !osd_oe?{stvid_r,stvid_r}:{osd_pixel, osd_pixel, osd_pixel, stvid_r};
video_g <= !osd_oe?{stvid_g,stvid_g}:{osd_pixel, osd_pixel, 1'b1, stvid_g};
video_b <= !osd_oe?{stvid_b,stvid_b}:{osd_pixel, osd_pixel, osd_pixel, stvid_b};
end
wire [9:0] overscan_bottom = overscan_latched?10'd60:10'd0;
// display enable signal
// the color modes use a scan doubler and output the data with 2 lines delay
wire [9:0] v_offset = mono?10'd0:10'd2;
wire de = (hcnt >= H_PRE) && (hcnt < H_ACT+H_PRE) && (vcnt >= v_offset && vcnt < V_ACT+v_offset);
wire de = (hcnt >= H_PRE) && (hcnt < H_ACT+H_PRE) && (vcnt >= v_offset && vcnt < V_ACT+v_offset+overscan_bottom);
// a fake de signal for timer a for color modes with half the hsync frequency
wire deC = (((hcnt >= H_PRE) && !vcnt[0]) || ((hcnt < H_ACT+H_PRE-10'd160) && vcnt[0])) &&
(vcnt >= (v_offset-10'd0) && vcnt < (V_ACT+v_offset-10'd0));
(vcnt >= (v_offset-10'd0) && vcnt < (V_ACT+v_offset+overscan_bottom-10'd0));
// a fake hsync pulse for the scan doubled color modes
wire hsC = vcnt[0] && hs;
// create a read signal that's 16 clocks ahead of oe
assign read = (bus_cycle[3:2] == 0) && (hcnt < H_ACT) && (vcnt < V_ACT);
assign read = (bus_cycle[3:2] == 0) && (hcnt < H_ACT) && (vcnt < V_ACT + overscan_bottom);
reg line;
reg last_syncmode;
always @(posedge clk) begin
if(reset) begin
vaddr <= _v_bas_ad;
end else begin
last_syncmode <= syncmode[1]; // delay syncmode to detect changes
line <= vcnt[1];
// ---- scan doubler pointer handling -----
@@ -358,10 +372,27 @@ always @(posedge clk) begin
vaddr <= vaddr + 23'd1;
end
end else begin
// this is also the magic used to do "overscan".
// the magic actually involves more than writing zero (60hz)
// within line 200. But htis is sufficient for our detection
if(vcnt[9:1] == 8'd200) begin
// syncmode has changed from 1 to 0 (50 to 60 hz)
if((syncmode[1] == 1'b0) && (last_syncmode == 1'b1))
overscan <= 1'b1;
end
// reached last possible pixel pos
if(hmax && vmax) begin
// reset video address counter
vaddr <= _v_bas_ad;
// copy syncmode
syncmode_latch <= syncmode;
// save and reset overscan
overscan_latched <= overscan;
overscan <= 1'b0;
end
end