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:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user