diff --git a/cores/mist/data_io.v b/cores/mist/data_io.v index 6ff5e72..5b5ecb9 100644 --- a/cores/mist/data_io.v +++ b/cores/mist/data_io.v @@ -1,4 +1,5 @@ // SPI data client (rom, floppy, harddisk io) + module data_io ( // clocks input clk_8, @@ -16,8 +17,10 @@ module data_io ( output [4:0] dma_idx, input [7:0] dma_data, output reg dma_ack, - output reg br, + + // horizontal and vertical screen adjustments + output reg [15:0] video_adj, // ram interface output reg [2:0] state, // state bits required to drive the sdram host @@ -160,11 +163,15 @@ always@(posedge sck, posedge ss) begin // set control register (32 bits written in 2 * 16 bits) if((cmd == 4) && (cnt == 5'd23)) begin - if(bcnt < 2) - ctrl_out[31:16] <= { sbuf, sdi }; - else - ctrl_out[15:0] <= { sbuf, sdi }; + if(bcnt < 2) + ctrl_out[31:16] <= { sbuf, sdi }; + else + ctrl_out[15:0] <= { sbuf, sdi }; end + + // set video offsets + if((cmd == 9) && (cnt == 5'd23)) + video_adj <= { sbuf, sdi }; end end end diff --git a/cores/mist/mist_top.v b/cores/mist/mist_top.v index 0e03b07..3faf31e 100644 --- a/cores/mist/mist_top.v +++ b/cores/mist/mist_top.v @@ -45,7 +45,8 @@ module mist_top ( wire [15:0] video_data; wire video_read; wire [22:0] video_address; -wire video_de, video_hs; +wire st_de, st_hs, st_vs; +wire [15:0] video_adj; // on-board io wire [1:0] buttons; @@ -180,7 +181,6 @@ wire [15:0] io_data_out = vreg_data_out | dma_data_out | blitter_data_out | wire init = ~pll_locked; video video ( - .reset (init ), // reset input .clk (clk_32 ), .clk27 (CLOCK_27[0]), .bus_cycle (bus_cycle ), @@ -207,15 +207,19 @@ video video ( .hs (VGA_HS ), .vs (VGA_VS ), - .video_r (VGA_R ), - .video_g (VGA_G ), - .video_b (VGA_B ), + .video_r (VGA_R ), + .video_g (VGA_G ), + .video_b (VGA_B ), + .adjust (video_adj ), .pal56 (~system_ctrl[9]), .scanlines (system_ctrl[21:20]), - .hsO (video_hs ), - .deO (video_de ) + // signals not affected by scan doubler required for + // irq generation + .st_hs (st_hs ), + .st_vs (st_vs ), + .st_de (st_de ) ); mmu mmu ( @@ -251,7 +255,7 @@ mfp mfp ( // input signals .clk_ext (clk_mfp ), - .de (video_de ), + .de (st_de ), .dma_irq (dma_irq ), .acia_irq (acia_irq ), .blitter_irq (blitter_irq ), @@ -354,10 +358,11 @@ YM2149 ym2149 ( .I_BC1 ( psg_sel && !tg68_adr[1]), .I_SEL_L ( 1'b1 ), - .O_AUDIO_L (audio_out_l), - .O_AUDIO_R (audio_out_r), + .O_AUDIO_L (audio_out_l ), + .O_AUDIO_R (audio_out_r ), - .stereo (system_ctrl[29]), + .stereo (system_ctrl[22] ), + // port a .I_IOA ( 8'd0 ), .O_IOA ( port_a_out ), @@ -506,7 +511,7 @@ assign vbi_ack = cpu2iack && address_strobe && (tg68_adr[3:1] == 3'b100); reg vsD, vsD2, vsI, vbi; always @(negedge clk_8) - vsD <= VGA_VS; + vsD <= st_vs; always @(posedge clk_8) begin vsD2 <= vsD; // delay by one @@ -524,7 +529,7 @@ assign hbi_ack = cpu2iack && address_strobe && (tg68_adr[3:1] == 3'b010); reg hsD, hsD2, hsI, hbi; always @(negedge clk_8) - hsD <= video_hs; + hsD <= st_hs; always @(posedge clk_8) begin hsD2 <= hsD; // delay by one @@ -771,12 +776,13 @@ data_io data_io ( .ss (SPI_SS2 ), .sdo (data_io_sdo ), - .br (data_io_br ), + .video_adj (video_adj ), // dma status interface .dma_idx (dma_dio_idx ), .dma_data (dma_dio_data ), .dma_ack (dma_dio_ack ), + .br (data_io_br ), // ram interface .state (host_state ), diff --git a/cores/mist/video.v b/cores/mist/video.v index af4cd70..9ede212 100644 --- a/cores/mist/video.v +++ b/cores/mist/video.v @@ -1,5 +1,5 @@ // -// video.v - new version +// video.v // // Atari ST shifter implementation for the MiST board // http://code.google.com/p/mist-board/ @@ -20,33 +20,19 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// original atari video timing -// mono color -// pclk 32MHz 16/8MHz -// hfreq 35.7kHz 15.75kHz -// vfreq 71.2Hz 50/60Hz -// -// avg. values derived from frequencies: -// hdisp 640 640/320 -// htot 896 1015/507 -// vdisp 400 200 -// vtot 501 315/262 - // TODO: // - async timing - // Overscan: // http://codercorner.com/fullscrn.txt -// Examples: automation 000 + 001: bottom border -// automation 097: top+ bottom border +// Examples: automation 000 + 001 + 097: bottom border +// automation 196: top + bottom border module video ( // system interface input clk, // 31.875 MHz input clk27, // 27.000 Mhz - input reset, // reset input [3:0] bus_cycle, // bus-cycle for sync // SPI interface for OSD @@ -78,25 +64,34 @@ module video ( output reg [5:0] video_b, // Blue[5:0] // system config - input pal56, // use VGA compatible 56hz for PAL - input [1:0] scanlines, // scanlines (00-none 01-25% 10-50% 11-100%) + input pal56, // use VGA compatible 56hz for PAL + input [1:0] scanlines, // scanlines (00-none 01-25% 10-50% 11-100%) + input [15:0] adjust, // hor/ver video adjust - // for internal use - output deO, - output hsO + // signals not affected by scan doubler for internal use like irqs + output st_de, + output st_vs, + output st_hs ); +localparam LINE_WIDTH = 10'd640; +localparam LINE_BORDER = 10'd80; // width of left and right screen border + // --------------------------------------------------------------------------- // ------------------------------ internal signals --------------------------- // --------------------------------------------------------------------------- -// deO is the internal display enable signal as used by the mfp. This is used +// st_de is the internal display enable signal as used by the mfp. This is used // by software to generate a line interrupt and to e.g. do 512 color effects. -// deO is active low -assign deO = ~me; // ~(scan_doubler_enable?sd_de:de); +// st_de is active low. Using memory enable (me) for this makes sure the cpu has +// plenty of time before data for the next line is starting to be fetched +assign st_de = ~me; -// similar for hsync -assign hsO = (st_h_state == 2'd0); +// hsync irq is generated at the rising edge of st_hs +assign st_hs = (st_h_state == 2'd0); + +// vsync irq is generated at the rising edge of st_vs +assign st_vs = (v_state == 2'd0); // --------------------------------------------------------------------------- // -------------------------------- video mode ------------------------------- @@ -154,11 +149,6 @@ wire low = (shmode == 2'd0); // derive number of planes from shiftmode wire [2:0] planes = mono?3'd1:(mid?3'd2:3'd4); -// scandoubler is used for the mid and low rez mode -wire scan_doubler_enable = mid || low; - -// line buffer for two lines of 640 pixels rgb data -reg [8:0] sd_buffer [1279:0]; reg [1:0] syncmode; reg [1:0] syncmode_latch; @@ -302,10 +292,10 @@ wire [2:0] mono_rgb = de?{mono_bit, mono_bit, mono_bit}:3'b100; // ------------------------- colour video signal ----------------------------- -reg [8:0] color, border_color; -wire [2:0] color_r = de?color[8:6]:border_color[8:6]; -wire [2:0] color_g = de?color[5:3]:border_color[5:3]; -wire [2:0] color_b = de?color[2:0]:border_color[2:0]; +reg [8:0] color; +wire [2:0] color_r = color[8:6]; +wire [2:0] color_g = color[5:3]; +wire [2:0] color_b = color[2:0]; // --------------- de-multiplex color and mono into one vga signal ----------- wire [2:0] stvid_r = mono?mono_rgb:color_r; @@ -316,19 +306,21 @@ wire [2:0] stvid_b = mono?mono_rgb:color_b; reg [15:0] shift_0, shift_1, shift_2, shift_3; // this line is to be displayed darker in scanline mode -wire scanline = scan_doubler_enable && vcnt[0]; +wire scanline = scan_doubler_enable && sd_vcnt[0]; // reading the scan doubler ram results in one extra delay and thus // reading it has to look one vga_hcnt cycle into the future -wire [9:0] vga_hcnt_next = (vga_hcnt == t5_h_end)?10'd0:(vga_hcnt+10'd1); +wire [9:0] border_width = t5_h_end - t4_h_border_left; +wire [9:0] vga_hcnt_next = + (vga_hcnt == t5_h_end)?(t5_h_end - t4_h_border_left): + ((vga_hcnt >= t4_h_border_left)?(vga_hcnt-t4_h_border_left):(vga_hcnt+LINE_BORDER+10'd1)); always @(posedge clk) begin - hs <= h_sync_pol ^ ((vga_h_state == 2'd0)?1'b0:1'b1); - vs <= v_sync_pol ^ ((v_state == 2'd0)?1'b0:1'b1); + hs <= h_sync_pol ^ ~vga_h_sync; + vs <= v_sync_pol ^ ~vga_v_sync; // color data is permanently read from the scan doubler buffers color <= sd_buffer[{vga_hcnt_next, !sd_toggle}]; - border_color <= sd_border_color[!sd_toggle]; // drive video output and apply scanline effect if enabled if(!scanline || scanlines == 2'b00) begin //if no scanlines or not a scanline @@ -402,26 +394,41 @@ end // ------------------------------- scan doubler ------------------------------ // --------------------------------------------------------------------------- +// scandoubler is used for the mid and low rez mode +wire scan_doubler_enable = mid || low; + // scan doubler signale indicating first or second buffer used -wire sd_toggle = vcnt[1]; +wire sd_toggle = sd_vcnt[1]; // four scan doubler shift registers for up to 4 planes reg [15:0] sd_shift_0, sd_shift_1, sd_shift_2, sd_shift_3; -// register to save the border color for delayed output through scan doubler -reg [8:0] sd_border_color[2]; +// msb of the shift registers is the index used to access the palette registers. +// Return border color index (0) if outside display area +wire [3:0] sd_index = (!me_v)?4'd0: + { sd_shift_3[15], sd_shift_2[15], sd_shift_1[15], sd_shift_0[15]}; -// msb of the shift registers is the index used to access the palette registers -wire [3:0] sd_index = { sd_shift_3[15], sd_shift_2[15], - sd_shift_1[15], sd_shift_0[15]}; + +// line buffer for two lines of 720 pixels (640 + 2 * 40 border) 3 * 3 bit rgb data +reg [8:0] sd_buffer [(2*(LINE_WIDTH+2*LINE_BORDER))-1:0]; + +// the scan doubler needs to know which border (left or right) is currently being displayed +reg sd_border_side; + +// line counter used to create scan doubler states +reg [1:0] sd_vcnt; always @(posedge clk) begin - - // save border color to cope with only line delay imposed by scan doubler - if(st_hcnt == t4_h_border_left) - sd_border_color[sd_toggle] <= {palette_r[0], palette_g[0], palette_b[0]}; - // permanently move data from data_latch into scan doublers shift registers + // vertical state changes at end of hsync (begin of left blank) + if(vga_hcnt == v_event) begin + // reset state counter two vga lines before screen start since scan doubler + // starts prefetching data two vga lines before + if(vcnt == (t11_v_end-10'd2)) sd_vcnt <= 2'd0; + else sd_vcnt <= sd_vcnt + 2'd1; + end + + // permanently move data from data_latch into scan doublers shift registers if((bus_cycle == 4'd15) && (plane == 2'd0)) begin // clear shift registers since some of them may be unused and need to forced to 0 sd_shift_1 <= 16'h0000; @@ -447,10 +454,31 @@ always @(posedge clk) begin end end - // move data from input buffer into line buffer - if((st_h_state == 2'd3) && (vga_hcnt[0] == 1'b0)) begin - sd_buffer[{st_hcnt[9:0], sd_toggle}] <= - {palette_r[sd_index], palette_g[sd_index], palette_b[sd_index]}; + // to store border colors we need to know which border we currently draw + if(st_hcnt == t4_h_border_left) sd_border_side <= 1'b0; + if(st_hcnt == t0_h_border_right) sd_border_side <= 1'b1; + + // scan doubler makes the st side operate at half the vga pixel clock + if(vga_hcnt[0] == 1'b0) begin + + // move data from shift register into line buffer. capture border colors as + // well to have the scan doubler delay in the border colors as well just in + // case a program changes border colors dynamically (e.g. different colors + // for left and right or top and bottom borders) + if(st_h_state == 2'd3) begin + sd_buffer[{LINE_BORDER + st_hcnt[9:0], sd_toggle}] <= + {palette_r[sd_index], palette_g[sd_index], palette_b[sd_index]}; + end else if(st_h_state == 2'd2) begin + // move bites from left/right border into appropriate places in the line buffer + if(!sd_border_side) + // left border + sd_buffer[{st_hcnt[9:0] - t4_h_border_left-10'd1, sd_toggle}] <= + {palette_r[0], palette_g[0], palette_b[0]}; + else + // right border + sd_buffer[{st_hcnt[9:0] + LINE_BORDER, sd_toggle}] <= + {palette_r[0], palette_g[0], palette_b[0]}; + end end end @@ -488,7 +516,8 @@ always @(posedge clk) begin end // memory enable signal 16/32/64 bits (16*planes) ahead of display enable (de) - if(me_v) begin + // include bus cycle to stay in sync in scna doubler mode + if(me_v && bus_cycle[0]) begin if(st_hcnt == me_h_start) me <= 1'b1; if(st_hcnt == me_h_end) me <= 1'b0; end @@ -497,10 +526,8 @@ always @(posedge clk) begin if(st_hcnt == me_h_start) plane <= 2'd0; - // starting new image at left/top start of (vga) border, this doesn't matter - // and is easier than coping with the differnt resultions of the st video - // modes - if((vga_hcnt == t4_h_border_left) && (vcnt == t10_v_border_top)) begin + // The video address counter is reloaded slightly before vsync + if((vga_hcnt == t4_h_border_left) && (vcnt == t8_v_sync - 10'd3)) begin vaddr <= _v_bas_ad; // copy syncmode @@ -549,64 +576,72 @@ reg [1:0] v_state; // 0=sync, 1=blank, 2=border, 3=display wire blank = (v_state == 2'd1) || (vga_h_state == 2'd1) || (v_state == 2'd0) || (vga_h_state == 2'd0); wire de = (v_state == 2'd3) && (vga_h_state == 2'd3); -wire border = - ((v_state == 2'd2) && ((vga_h_state == 2'd3) || (vga_h_state == 2'd2)) || // top/bottom border - (vga_h_state == 2'd2) && ((v_state == 2'd3) || (v_state == 2'd2))); // left/right border +// time in horizontal timing where vertical states change (at the begin of the sync phase) +wire [9:0] v_event = t2_h_sync; -// time in horizontal timing where vertical states change (at the begin of the left blank phase) -wire [9:0] v_event = t3_h_blank_left; +// extend adjust values to 10 bits +wire [9:0] adjust_v = { adjust[7], adjust[7], adjust[7:0] }; +wire [9:0] adjust_h = { adjust[15], adjust[15], adjust[15:8] }; +reg vga_v_sync, vga_h_sync; always @(posedge clk) begin - if(reset) begin - // It is important to reset the vga_hcnt counter here and this way (using reset which is the - // plls init signal). This is necessary to keep the video states in sync with the cpus memory - // timing. - vga_hcnt <= 10'd0; - vcnt <= 10'd0; - end else begin - // ------------- horizontal VGA timing generation ------------- - if(vga_hcnt == t5_h_end) vga_hcnt <= 10'd0; - else vga_hcnt <= vga_hcnt + 10'd1; + // ------------- horizontal VGA timing generation ------------- + + // sync horizontal counter with bus cycle counter so cpu and video stay synchronous + // even if horizotal counter is affected by resolution changes + // the scan doubler is a special case as the atari line timing then expands over two vga + // lines and may/must be asynchronous to the vga timing at the end of the first line + if(vga_hcnt == t5_h_end) begin + if((bus_cycle == 4'd15) || (scan_doubler_enable && sd_vcnt[0])) + vga_hcnt <= 10'd0; + end else + vga_hcnt <= vga_hcnt + 10'd1; + + // generate user adjustable vga sync signal + if( vga_hcnt == t2_h_sync - adjust_h ) vga_h_sync <= 1'b1; + if( vga_hcnt == t3_h_blank_left - adjust_h ) vga_h_sync <= 1'b0; + + // generate horizontal video signal states + if( vga_hcnt == t2_h_sync ) vga_h_state <= 2'd0; + if((vga_hcnt == t0_h_border_right) || (vga_hcnt == t4_h_border_left)) vga_h_state <= 2'd2; + if((vga_hcnt == t1_h_blank_right) || (vga_hcnt == t3_h_blank_left)) vga_h_state <= 2'd1; + if( vga_hcnt == t5_h_end) vga_h_state <= 2'd3; + + // ------------- horizontal ST timing generation ------------- + // Run st timing at full speed if no scan doubler is being used. Otherwise run + // it at half speed + if((!scan_doubler_enable) || vga_hcnt[0]) begin + if(st_hcnt == t5_h_end) begin + // changing video modes toggles scan_doubler_enable and will bring + // the two hcnt counters out of sync. So we'll resync st_hcnt with vgs_hcnt here + if((vga_hcnt == t5_h_end) && (!scan_doubler_enable || !sd_vcnt[0])) + st_hcnt <= 10'd0; + end else + st_hcnt <= st_hcnt + 10'd1; // generate horizontal video signal states - if( vga_hcnt == t2_h_sync ) vga_h_state <= 2'd0; - if((vga_hcnt == t0_h_border_right) || (vga_hcnt == t4_h_border_left)) vga_h_state <= 2'd2; - if((vga_hcnt == t1_h_blank_right) || (vga_hcnt == t3_h_blank_left)) vga_h_state <= 2'd1; - if( vga_hcnt == t5_h_end) vga_h_state <= 2'd3; - - // ------------- horizontal ST timing generation ------------- - // Run st timing at full speed if no scan doubler is being used. Otherwise run - // it at half speed - if((!scan_doubler_enable) || vga_hcnt[0]) begin - if(st_hcnt == t5_h_end) begin - // changing video modes toggles scan_doubler_enable and will bring - // the two hcnt counters out of sync. So we'll resync st_hcnt with vgs_hcnt here - if((vga_hcnt == t5_h_end) && (!scan_doubler_enable || !vcnt[0])) - st_hcnt <= 10'd0; - end else - st_hcnt <= st_hcnt + 10'd1; + if( st_hcnt == t2_h_sync ) st_h_state <= 2'd0; + if((st_hcnt == t0_h_border_right) || (st_hcnt == t4_h_border_left)) st_h_state <= 2'd2; + if((st_hcnt == t1_h_blank_right) || (st_hcnt == t3_h_blank_left)) st_h_state <= 2'd1; + if( st_hcnt == t5_h_end) st_h_state <= 2'd3; + end - // generate horizontal video signal states - if( st_hcnt == t2_h_sync ) st_h_state <= 2'd0; - if((st_hcnt == t0_h_border_right) || (st_hcnt == t4_h_border_left)) st_h_state <= 2'd2; - if((st_hcnt == t1_h_blank_right) || (st_hcnt == t3_h_blank_left)) st_h_state <= 2'd1; - if( st_hcnt == t5_h_end) st_h_state <= 2'd3; - end + // vertical state changes at end of hsync (begin of left blank) + if(vga_hcnt == v_event) begin - // vertical state changes at end of hsync (begin of left blank) - if(vga_hcnt == v_event) begin + // ------------- vertical timing generation ------------- + // increase vcnt + if(vcnt == t11_v_end) vcnt <= 10'd0; + else vcnt <= vcnt + 10'd1; - // ------------- vertical timing generation ------------- - // increase vcnt - if(vcnt == t11_v_end) vcnt <= 10'd0; - else vcnt <= vcnt + 10'd1; + if( vcnt == t8_v_sync - adjust_v ) vga_v_sync <= 1'b1; + if( vcnt == t9_v_blank_top - adjust_v ) vga_v_sync <= 1'b0; - // generate vertical video signal states - if( vcnt == t8_v_sync ) v_state <= 2'd0; - if((vcnt == t6_v_border_bot) || (vcnt == t10_v_border_top)) v_state <= 2'd2; - if((vcnt == t7_v_blank_bot) || (vcnt == t9_v_blank_top)) v_state <= 2'd1; - if( vcnt == t11_v_end) v_state <= 2'd3; - end + // generate vertical video signal states + if( vcnt == t8_v_sync ) v_state <= 2'd0; + if((vcnt == t6_v_border_bot) || (vcnt == t10_v_border_top)) v_state <= 2'd2; + if((vcnt == t7_v_blank_bot) || (vcnt == t9_v_blank_top)) v_state <= 2'd1; + if( vcnt == t11_v_end) v_state <= 2'd3; end end diff --git a/cores/mist/video_modes.v b/cores/mist/video_modes.v index f51dabd..f2b04b6 100644 --- a/cores/mist/video_modes.v +++ b/cores/mist/video_modes.v @@ -23,17 +23,10 @@ // http://martin.hinner.info/vga/timing.html // http://www.epanorama.net/faq/vga2rgb/calc.html -// original atari video timing -// mono color -// pclk 32MHz 16/8MHz -// hfreq 35.7kHz 15.75kHz -// vfreq 71.2Hz 50/60Hz -// -// avg. values derived from frequencies: -// hdisp 640 640/320 -// htot 896 1015/507 -// vdisp 400 200 -// vtot 501 315/262 +// clocks on real sts: +// PAL 32084988 Hz +// NTSC 32042400 Hz +// MIST 31875000 Hz module video_modes ( inout mono, // select monochrome mode (and not color) @@ -52,16 +45,16 @@ localparam V_ACT = 10'd400; // TIMING CONSTRAINTS: // The total width (act+both blank+2*border+sync) must be a multiple of 16, for -// low rez a multiple of 32 -// For modes to be used with the scan doubler the total heigth (act+both blank+ -// 2*border+sync) must be a multiple of 4 +// scan doubled modes a multiple of 8 // --------------------------------------------------------------------------- // ----------------------------- pal56 timing ------------------------------- // --------------------------------------------------------------------------- -// PAL modes need ~80 pixels vertical border for border removal -// 34.21 kHz / 55.9 Hz +// 56Hz replacement for Atari 50Hz low and medium resolution video mode scan doubled: +// total: 1024x626, active incl border: 800x560, displayed: 640x400 +// horizontal scan rate: 17.27 kHz, vertical scan rate: 56.34 hz + wire [121:0] pal56_config_str; @@ -76,12 +69,15 @@ conf pal56_conf( // ----------------------------- pal50 timing ------------------------------- // --------------------------------------------------------------------------- -wire [121:0] pal50_config_str; +// Atari 50Hz low and medium resolution video mode scan doubled: +// total: 1024x626, active incl border: 800x560, displayed: 640x400 +// horizontal scan rate: 15.625 kHz, vertical scan rate: 49.92 hz +wire [121:0] pal50_config_str; conf pal50_conf( // front porch sync width back porch border width sync polarity - .h_fp ( 10'd80), .h_s ( 10'd40), .h_bp (10'd152), .h_bd (10'd40), .h_sp (1'b1), - .v_fp ( 10'd37), .v_s ( 10'd3), .v_bp ( 10'd36), .v_bd (10'd80), .v_sp (1'b1), + .h_fp ( 10'd80), .h_s ( 10'd64), .h_bp ( 10'd80), .h_bd (10'd80), .h_sp (1'b1), + .v_fp ( 10'd30), .v_s ( 10'd6), .v_bp ( 10'd30), .v_bd (10'd80), .v_sp (1'b1), .str (pal50_config_str) ); @@ -89,14 +85,15 @@ conf pal50_conf( // ------------------------------ ntsc timing ------------------------------- // --------------------------------------------------------------------------- -// 31.01 kHz / 59.63 Hz +// Atari 60Hz low and medium resolution video mode scan doubled: +// total: 1016x526, active incl border: 800x480, displayed: 640x400 +// horizontal scan rate: 15.748 kHz, vertical scan rate: 59.88 hz wire [121:0] ntsc_config_str; - conf ntsc_conf( // front porch sync width back porch border width sync polarity - .h_fp ( 10'd88), .h_s (10'd120), .h_bp ( 10'd96), .h_bd (10'd40), .h_sp (1'b0), - .v_fp ( 10'd18), .v_s ( 10'd3), .v_bp ( 10'd19), .v_bd (10'd40), .v_sp (1'b0), + .h_fp ( 10'd76), .h_s ( 10'd64), .h_bp ( 10'd76), .h_bd (10'd80), .h_sp (1'b1), + .v_fp ( 10'd20), .v_s ( 10'd6), .v_bp ( 10'd20), .v_bd (10'd40), .v_sp (1'b0), .str (ntsc_config_str) ); @@ -104,19 +101,22 @@ conf ntsc_conf( // ------------------------------ mono timing ------------------------------- // --------------------------------------------------------------------------- +// Atari 71Hz high resolution video mode: +// total: 896x501, displayed: 640x400 +// horizontal scan rate: 35.714 kHz, vertical scan rate: 71.286 hz + wire [121:0] mono_config_str; conf mono_conf( // front porch sync width back porch border width sync polarity - .h_fp ( 10'd24), .h_s ( 10'd40), .h_bp (10'd128), .h_bd ( 10'd0), .h_sp (1'b0), - .v_fp ( 10'd55), .v_s ( 10'd3), .v_bp ( 10'd74), .v_bd ( 10'd0), .v_sp (1'b0), + .h_fp (10'd108), .h_s ( 10'd40), .h_bp (10'd108), .h_bd ( 10'd0), .h_sp (1'b0), + .v_fp ( 10'd48), .v_s ( 10'd5), .v_bp ( 10'd48), .v_bd ( 10'd0), .v_sp (1'b0), .str (mono_config_str) ); // this is the video mode multiplexer ... -assign mode_str = - mono?mono_config_str:(pal?(pal56?pal56_config_str:pal50_config_str):ntsc_config_str); +assign mode_str = mono?mono_config_str:(pal?(pal56?pal56_config_str:pal50_config_str):ntsc_config_str); endmodule