// This module decodes video modes `include "tune.v" module video_mode ( // clocks input wire clk, f1, c3, // video config input wire [7:0] vpage, input wire [7:0] vconf, input wire ts_rres_ext, input wire v60hz, // video parameters & mode controls input wire [8:0] gx_offs, output wire [9:0] x_offs_mode, output wire [8:0] hpix_beg, output wire [8:0] hpix_end, output wire [8:0] vpix_beg, output wire [8:0] vpix_end, output wire [8:0] hpix_beg_ts, output wire [8:0] hpix_end_ts, output wire [8:0] vpix_beg_ts, output wire [8:0] vpix_end_ts, output wire [5:0] x_tiles, output wire [4:0] go_offs, output wire [3:0] fetch_sel, output wire [1:0] fetch_bsl, input wire [3:0] fetch_cnt, input wire pix_start, input wire line_start_s, output wire tv_hires, output reg vga_hires = 0, output wire [1:0] render_mode, output wire pix_stb, output wire fetch_stb, // video data input wire [15:0] txt_char, // video counters input wire [7:0] cnt_col, input wire [8:0] cnt_row, input wire cptr, // DRAM interface output wire [20:0] video_addr, output wire [ 4:0] video_bw ); wire [1:0] vmod = vconf[1:0]; wire [1:0] rres = vconf[7:6]; // clocking strobe for pixels (TV) assign pix_stb = tv_hires ? f1 : c3; always @(posedge clk) if (line_start_s) vga_hires <= tv_hires; // Modes localparam M_ZX = 2'h0; // ZX localparam M_HC = 2'h1; // 16c localparam M_XC = 2'h2; // 256c localparam M_TX = 2'h3; // Text // Render modes (affects 'video_render.v') localparam R_ZX = 2'h0; localparam R_HC = 2'h1; localparam R_XC = 2'h2; localparam R_TX = 2'h3; // fetch strobes wire ftch[0:3]; assign fetch_stb = (pix_start | ftch[render_mode]) && c3; assign ftch[R_ZX] = &fetch_cnt[3:0]; assign ftch[R_HC] = &fetch_cnt[1:0]; assign ftch[R_XC] = fetch_cnt[0]; assign ftch[R_TX] = &fetch_cnt[3:0]; // fetch window wire [4:0] g_offs[0:3]; assign g_offs[M_ZX] = 5'd18; assign g_offs[M_HC] = 5'd6; assign g_offs[M_XC] = 5'd4; assign g_offs[M_TX] = 5'd10; assign go_offs = g_offs[vmod]; // fetch selectors // Attention: counter is already incremented at the time of video data fetching! wire [3:0] f_sel[0:3]; wire [3:0] f_txt_sel[0:3]; wire [1:0] f_txt_bsl[0:3]; assign f_sel[M_ZX] = {~cptr, ~cptr, cptr, cptr}; assign f_sel[M_HC] = {~cptr, ~cptr, 2'b11}; assign f_sel[M_XC] = {~cptr, ~cptr, 2'b11}; assign f_sel[M_TX] = f_txt_sel[cnt_col[1:0]]; assign fetch_sel = f_sel[vmod]; assign fetch_bsl = (vmod == M_TX) ? f_txt_bsl[cnt_col[1:0]] : 2'b10; assign f_txt_sel[1] = 4'b0011; // char assign f_txt_sel[2] = 4'b1100; // attr assign f_txt_sel[3] = 4'b0001; // gfx0 assign f_txt_sel[0] = 4'b0010; // gfx1 assign f_txt_bsl[1] = 2'b10; // char assign f_txt_bsl[2] = 2'b10; // attr assign f_txt_bsl[3] = {2{cnt_row[0]}}; // gfx0 assign f_txt_bsl[0] = {2{cnt_row[0]}}; // gfx1 // X offset assign x_offs_mode = {vmod == M_XC ? {gx_offs[8:1], 1'b0} : {1'b0, gx_offs[8:1]}, gx_offs[0]}; // DRAM bandwidth usage localparam BW2 = 2'b00; localparam BW4 = 2'b01; localparam BW8 = 2'b11; localparam BU1 = 3'b001; localparam BU2 = 3'b010; localparam BU4 = 3'b100; // [4:3] - total cycles: 11 = 8 / 01 = 4 / 00 = 2 // [2:0] - need cycles wire [4:0] bw[0:3]; assign bw[M_ZX] = {BW8, BU1}; // '1 of 8' (ZX) assign bw[M_HC] = {BW4, BU1}; // '1 of 4' (16c) assign bw[M_XC] = {BW2, BU1}; // '1 of 2' (256c) assign bw[M_TX] = {BW8, BU4}; // '4 of 8' (text) assign video_bw = bw[vmod]; // pixelrate wire [3:0] pixrate = 4'b1000; // change these if you change the modes indexes! assign tv_hires = pixrate[vmod]; // render mode wire [1:0] r_mode[0:3]; assign r_mode[M_ZX] = R_ZX; assign r_mode[M_HC] = R_HC; assign r_mode[M_XC] = R_XC; assign r_mode[M_TX] = R_TX; assign render_mode = r_mode[vmod]; // raster resolution wire [8:0] hp_beg[0:3]; wire [8:0] hp_end[0:3]; wire [8:0] vp_beg[0:3]; wire [8:0] vp_end[0:3]; wire [5:0] x_tile[0:3]; assign hp_beg[0] = 9'd140; // 256 (88-52-256-52) assign hp_beg[1] = 9'd108; // 320 (88-20-320-20) assign hp_beg[2] = 9'd108; // 320 (88-20-320-20) assign hp_beg[3] = 9'd88; // 360 (88-0-360-0) assign hp_end[0] = 9'd396; // 256 assign hp_end[1] = 9'd428; // 320 assign hp_end[2] = 9'd428; // 320 assign hp_end[3] = 9'd448; // 360 `ifdef PENT_312 assign vp_beg[0] = v60hz ? 9'd046 : 9'd072; // 192 (22-24-192-24)/(24-48-192-48) (blank-border-pixels-border) assign vp_beg[1] = v60hz ? 9'd042 : 9'd068; // 200 (22-20-200-20)/(24-44-200-44) assign vp_beg[2] = v60hz ? 9'd022 : 9'd048; // 240 (22-0-240-0)/(24-24-240-24) assign vp_beg[3] = v60hz ? 9'd022 : 9'd024; // 240/288 (22-0-240-0)/(24-0-288-0) assign vp_end[0] = v60hz ? 9'd238 : 9'd264; // 192 assign vp_end[1] = v60hz ? 9'd242 : 9'd268; // 200 assign vp_end[2] = v60hz ? 9'd262 : 9'd288; // 240 assign vp_end[3] = v60hz ? 9'd262 : 9'd312; // 240/288 `else assign vp_beg[0] = v60hz ? 9'd046 : 9'd080; // 192 (22-24-192-24)/(32-48-192-48) (blank-border-pixels-border) assign vp_beg[1] = v60hz ? 9'd042 : 9'd076; // 200 (22-20-200-20)/(32-44-200-44) assign vp_beg[2] = v60hz ? 9'd022 : 9'd056; // 240 (22-0-240-0)/(32-24-240-24) assign vp_beg[3] = v60hz ? 9'd022 : 9'd032; // 240/288 (22-0-240-0)/(32-0-288-0) assign vp_end[0] = v60hz ? 9'd238 : 9'd272; // 192 assign vp_end[1] = v60hz ? 9'd242 : 9'd276; // 200 assign vp_end[2] = v60hz ? 9'd262 : 9'd296; // 240 assign vp_end[3] = v60hz ? 9'd262 : 9'd320; // 240/288 `endif assign x_tile[0] = 6'd34; // 256 assign x_tile[1] = 6'd42; // 320 assign x_tile[2] = 6'd42; // 320 assign x_tile[3] = 6'd47; // 360 assign hpix_beg = hp_beg[rres]; assign hpix_end = hp_end[rres]; assign vpix_beg = vp_beg[rres]; assign vpix_end = vp_end[rres]; assign hpix_beg_ts = ts_rres_ext ? hp_beg[3] : hp_beg[rres]; assign hpix_end_ts = ts_rres_ext ? hp_end[3] : hp_end[rres]; assign vpix_beg_ts = ts_rres_ext ? vp_beg[3] : vp_beg[rres]; assign vpix_end_ts = ts_rres_ext ? vp_end[3] : vp_end[rres]; assign x_tiles = ts_rres_ext ? x_tile[3] : x_tile[rres]; // ZX wire [11:0] addr_zx_gfx = {cnt_row[7:6], cnt_row[2:0], cnt_row[5:3], cnt_col[4:1]}; wire [11:0] addr_zx_atr = {3'b110, cnt_row[7:3], cnt_col[4:1]}; wire [20:0] addr_zx = {vpage, 1'b0, ~cnt_col[0] ? addr_zx_gfx : addr_zx_atr}; // 16c wire [20:0] addr_16c = {vpage[7:3], cnt_row, cnt_col[6:0]}; // 256c wire [20:0] addr_256c = {vpage[7:4], cnt_row, cnt_col[7:0]}; // Textmode wire [13:0] addr_tx[0:3]; wire [20:0] addr_text = {vpage[7:1], addr_tx[cnt_col[1:0]]}; assign addr_tx[0] = {vpage[0], cnt_row[8:3], 1'b0, cnt_col[7:2]}; // char codes, data[15:0] assign addr_tx[1] = {vpage[0], cnt_row[8:3], 1'b1, cnt_col[7:2]}; // char attributes, data[31:16] assign addr_tx[2] = {~vpage[0], 3'b000, (txt_char[7:0]), cnt_row[2:1]}; // char0 graphics, data[7:0] assign addr_tx[3] = {~vpage[0], 3'b000, (txt_char[15:8]), cnt_row[2:1]}; // char1 graphics, data[15:8] // videomode addresses wire [20:0] v_addr[0:3]; assign v_addr[M_ZX] = addr_zx; assign v_addr[M_HC] = addr_16c; assign v_addr[M_XC] = addr_256c; assign v_addr[M_TX] = addr_text; assign video_addr = v_addr[vmod]; endmodule