mirror of
https://github.com/UzixLS/TSConf_MiST.git
synced 2025-07-18 23:01:37 +03:00
update tsconf to commit 83afbba6f5d366f96297028aa3d64512fa254a51
This commit is contained in:
@ -1,33 +1,35 @@
|
||||
// This module fetches video data from DRAM
|
||||
|
||||
// This module fetches video data from DRAM
|
||||
|
||||
`include "tune.v"
|
||||
|
||||
module video_fetch
|
||||
(
|
||||
// clocks
|
||||
input wire clk,
|
||||
|
||||
// control
|
||||
input wire [3:0] f_sel,
|
||||
input wire [1:0] b_sel,
|
||||
input wire fetch_stb,
|
||||
|
||||
// video data
|
||||
output reg [31:0] fetch_data,
|
||||
output reg [31:0] fetch_temp,
|
||||
|
||||
// DRAM interface
|
||||
input wire video_strobe,
|
||||
input wire [15:0] video_data
|
||||
);
|
||||
|
||||
// fetching data
|
||||
always @(posedge clk) if (video_strobe)
|
||||
begin
|
||||
if (f_sel[0]) fetch_temp[ 7: 0] <= b_sel[0] ? video_data[15:8] : video_data[ 7:0];
|
||||
if (f_sel[1]) fetch_temp[15: 8] <= b_sel[1] ? video_data[15:8] : video_data[ 7:0];
|
||||
if (f_sel[2]) fetch_temp[23:16] <= video_data[ 7:0];
|
||||
if (f_sel[3]) fetch_temp[31:24] <= video_data[15:8];
|
||||
end
|
||||
|
||||
always @(posedge clk) if (fetch_stb) fetch_data <= fetch_temp;
|
||||
|
||||
(
|
||||
// clocks
|
||||
input wire clk,
|
||||
|
||||
// control
|
||||
input wire [3:0] f_sel,
|
||||
input wire [1:0] b_sel,
|
||||
input wire fetch_stb,
|
||||
|
||||
// video data
|
||||
output reg [31:0] fetch_data,
|
||||
output reg [31:0] fetch_temp,
|
||||
|
||||
// DRAM interface
|
||||
input wire video_strobe,
|
||||
input wire [15:0] video_data
|
||||
);
|
||||
|
||||
always @(posedge clk) if (video_strobe)
|
||||
begin
|
||||
if (f_sel[0]) fetch_temp[ 7: 0] <= b_sel[0] ? video_data[15:8] : video_data[ 7:0];
|
||||
if (f_sel[1]) fetch_temp[15: 8] <= b_sel[1] ? video_data[15:8] : video_data[ 7:0];
|
||||
if (f_sel[2]) fetch_temp[23:16] <= video_data[ 7:0];
|
||||
if (f_sel[3]) fetch_temp[31:24] <= video_data[15:8];
|
||||
end
|
||||
|
||||
always @(posedge clk) if (fetch_stb)
|
||||
fetch_data <= fetch_temp;
|
||||
|
||||
endmodule
|
||||
|
@ -1,235 +1,230 @@
|
||||
|
||||
// This module decodes video modes
|
||||
|
||||
// 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,
|
||||
|
||||
// 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 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;
|
||||
|
||||
// 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];
|
||||
// these values are from a thin air!!! recheck them occasionally!
|
||||
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 m_c = (vmod == M_HC) | (vmod == M_XC);
|
||||
// assign fetch_sel = vmod == M_TX ? f_txt_sel[cnt_col[1:0]] : {~cptr, ~cptr, cptr | m_c, cptr | m_c};
|
||||
|
||||
// wire [3:0] f_sel[0:7];
|
||||
wire [3:0] f_sel[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;
|
||||
|
||||
// wire [1:0] f_bsl[0:7];
|
||||
// assign f_bsl[M_ZX] = 2'b10;
|
||||
// assign f_bsl[M_HC] = 2'b10;
|
||||
// assign f_bsl[M_XC] = 2'b10;
|
||||
// assign f_bsl[M_TX] = f_txt_bsl[cnt_col[1:0]];
|
||||
// assign fetch_bsl = f_bsl[vmod];
|
||||
|
||||
wire [3:0] f_txt_sel[0:3];
|
||||
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
|
||||
|
||||
wire [1:0] f_txt_bsl[0:3];
|
||||
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:7];
|
||||
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'd136; // 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'd392; // 256
|
||||
assign hp_end[1] = 9'd428; // 320
|
||||
assign hp_end[2] = 9'd428; // 320
|
||||
assign hp_end[3] = 9'd448; // 360
|
||||
|
||||
assign vp_beg[0] = 9'd080; // 192 (22-24-192-24)/(32-48-192-48) (blank-border-pixels-border)
|
||||
assign vp_beg[1] = 9'd076; // 200 (22-20-200-20)/(32-44-200-44)
|
||||
assign vp_beg[2] = 9'd056; // 240 (22-0-240-0)/(32-24-240-24)
|
||||
assign vp_beg[3] = 9'd032; // 288 (22-0-240-0)/(32-0-288-0)
|
||||
|
||||
assign vp_end[0] = 9'd272; // 192
|
||||
assign vp_end[1] = 9'd276; // 200
|
||||
assign vp_end[2] = 9'd296; // 240
|
||||
assign vp_end[3] = 9'd320; // 240/288
|
||||
|
||||
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];
|
||||
(
|
||||
// clocks
|
||||
input wire clk, f1, c3,
|
||||
|
||||
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];
|
||||
// video config
|
||||
input wire [7:0] vpage,
|
||||
input wire [7:0] vconf,
|
||||
input wire ts_rres_ext,
|
||||
input wire v60hz,
|
||||
|
||||
assign x_tiles = ts_rres_ext ? x_tile[3] : x_tile[rres];
|
||||
|
||||
// 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];
|
||||
|
||||
// ZX
|
||||
wire [20:0] addr_zx = {vpage, 1'b0, ~cnt_col[0] ? addr_zx_gfx : addr_zx_atr};
|
||||
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]};
|
||||
|
||||
// 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 [20:0] addr_text = {vpage[7:1], addr_tx[cnt_col[1:0]]};
|
||||
wire [13:0] addr_tx[0:3];
|
||||
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]
|
||||
|
||||
|
||||
endmodule
|
||||
// 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
|
||||
|
@ -2,59 +2,181 @@
|
||||
// This module generates video for DAC
|
||||
// (c)2015 TSL
|
||||
|
||||
`include "tune.v"
|
||||
|
||||
module video_out
|
||||
(
|
||||
// clocks
|
||||
input wire clk, c3,
|
||||
// clocks
|
||||
input wire clk, c3,
|
||||
|
||||
// video controls
|
||||
input wire tv_blank,
|
||||
input wire [1:0] plex_sel_in,
|
||||
// video controls
|
||||
input wire vga_on,
|
||||
input wire tv_blank,
|
||||
input wire vga_blank,
|
||||
input wire vga_line,
|
||||
input wire [1:0] plex_sel_in,
|
||||
|
||||
// mode controls
|
||||
input wire tv_hires,
|
||||
input wire [3:0] palsel,
|
||||
// mode controls
|
||||
input wire tv_hires,
|
||||
input wire vga_hires,
|
||||
input wire [3:0] palsel,
|
||||
|
||||
// Z80 pins
|
||||
input wire [15:0] cram_data_in,
|
||||
input wire [7:0] cram_addr_in,
|
||||
input wire cram_we,
|
||||
// Z80 pins
|
||||
input wire [15:0] cram_data_in,
|
||||
input wire [7:0] cram_addr_in,
|
||||
input wire cram_we,
|
||||
|
||||
// video data
|
||||
input wire [7:0] vplex_in,
|
||||
output wire [7:0] vred,
|
||||
output wire [7:0] vgrn,
|
||||
output wire [7:0] vblu,
|
||||
output wire vdac_mode
|
||||
// video data
|
||||
input wire [7:0] vplex_in,
|
||||
input wire [7:0] vgaplex,
|
||||
output wire [1:0] vred,
|
||||
output wire [1:0] vgrn,
|
||||
output wire [1:0] vblu,
|
||||
output wire [4:0] vred_raw,
|
||||
output wire [4:0] vgrn_raw,
|
||||
output wire [4:0] vblu_raw,
|
||||
output wire vdac_mode
|
||||
);
|
||||
|
||||
wire [14:0] vpix;
|
||||
wire [15:0] vpixel;
|
||||
wire [1:0] phase;
|
||||
wire [7:0] pwm[0:7];
|
||||
|
||||
reg [7:0] vplex;
|
||||
always @(posedge clk) if (c3) vplex <= vplex_in;
|
||||
reg blank1; // GOVNOKOD!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
wire [7:0] vdata = tv_hires ? {palsel, plex_sel_in[1] ? vplex[3:0] : vplex[7:4]} : vplex;
|
||||
assign vred_raw = vpix[14:10];
|
||||
assign vgrn_raw = vpix[9:5];
|
||||
assign vblu_raw = vpix[4:0];
|
||||
assign vdac_mode = vpixel[15];
|
||||
|
||||
// TV/VGA mux
|
||||
reg [7:0] vplex;
|
||||
always @(posedge clk) if (c3)
|
||||
vplex <= vplex_in;
|
||||
|
||||
wire [7:0] plex = vga_on ? vgaplex : vplex;
|
||||
wire hires = vga_on ? vga_hires : tv_hires;
|
||||
wire plex_sel = vga_on ? plex_sel_in[0] : plex_sel_in[1];
|
||||
wire [7:0] vdata = hires ? {palsel, plex_sel ? plex[3:0] : plex[7:4]} : plex;
|
||||
wire blank = vga_on ? vga_blank : tv_blank;
|
||||
|
||||
assign vpix = blank1 ? 15'b0 : vpixel[14:0];
|
||||
// assign vpix = blank1 ? 15'b0 : (vpixel[14:0] & 15'b111001110011100); // test for 373 colors
|
||||
// assign vpix = blank1 ? 15'b0 : (vpixel[14:0] & 15'b110001100011000); // test for 64 colors
|
||||
|
||||
// GOVNOKOD!!!!!!!!!!!!!!!!!!!!!
|
||||
always @(posedge clk)
|
||||
begin
|
||||
blank1 <= blank;
|
||||
end
|
||||
|
||||
// color components extraction
|
||||
wire [1:0] cred = vpix[14:13];
|
||||
wire [2:0] ired = vpix[12:10];
|
||||
wire [1:0] cgrn = vpix[ 9: 8];
|
||||
wire [2:0] igrn = vpix[ 7: 5];
|
||||
wire [1:0] cblu = vpix[ 4: 3];
|
||||
wire [2:0] iblu = vpix[ 2: 0];
|
||||
|
||||
// prepare and clocking two phases of output
|
||||
reg [1:0] red0;
|
||||
reg [1:0] grn0;
|
||||
reg [1:0] blu0;
|
||||
reg [1:0] red1;
|
||||
reg [1:0] grn1;
|
||||
reg [1:0] blu1;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
red0 <= (!pwm[ired][{phase, 1'b0}] | &cred) ? cred : (cred + 2'b1);
|
||||
grn0 <= (!pwm[igrn][{phase, 1'b0}] | &cgrn) ? cgrn : (cgrn + 2'b1);
|
||||
blu0 <= (!pwm[iblu][{phase, 1'b0}] | &cblu) ? cblu : (cblu + 2'b1);
|
||||
red1 <= (!pwm[ired][{phase, 1'b1}] | &cred) ? cred : (cred + 2'b1);
|
||||
grn1 <= (!pwm[igrn][{phase, 1'b1}] | &cgrn) ? cgrn : (cgrn + 2'b1);
|
||||
blu1 <= (!pwm[iblu][{phase, 1'b1}] | &cblu) ? cblu : (cblu + 2'b1);
|
||||
end
|
||||
|
||||
`ifdef IDE_VDAC
|
||||
// no PWM
|
||||
assign vred = cred;
|
||||
assign vgrn = cgrn;
|
||||
assign vblu = cblu;
|
||||
`elsif IDE_VDAC2
|
||||
// no PWM
|
||||
assign vred = cred;
|
||||
assign vgrn = cgrn;
|
||||
assign vblu = cblu;
|
||||
`else
|
||||
// output muxing for 56MHz PWM resolution
|
||||
assign vred = clk ? red1 : red0;
|
||||
assign vgrn = clk ? grn1 : grn0;
|
||||
assign vblu = clk ? blu1 : blu0;
|
||||
`endif
|
||||
|
||||
// PWM phase
|
||||
reg [1:0] ph;
|
||||
always @(posedge clk)
|
||||
ph <= ph + 2'b1;
|
||||
|
||||
assign phase = {vga_on ? vga_line : ph[1], ph[0]};
|
||||
|
||||
// PWM
|
||||
assign pwm[0] = 8'b00000000;
|
||||
assign pwm[1] = 8'b00000001;
|
||||
assign pwm[2] = 8'b01000001;
|
||||
assign pwm[3] = 8'b01000101;
|
||||
assign pwm[4] = 8'b10100101;
|
||||
assign pwm[5] = 8'b10100111;
|
||||
assign pwm[6] = 8'b11010111;
|
||||
assign pwm[7] = 8'b11011111;
|
||||
|
||||
// CRAM
|
||||
wire [15:0] vpixel;
|
||||
dpram #(.DATAWIDTH(16), .ADDRWIDTH(8), .MEM_INIT_FILE("rtl/video/video_cram.mif")) video_cram
|
||||
(
|
||||
.clock (clk),
|
||||
.address_a(cram_addr_in),
|
||||
.data_a (cram_data_in),
|
||||
.wren_a (cram_we),
|
||||
.address_b(vdata),
|
||||
.q_b (vpixel)
|
||||
);
|
||||
|
||||
reg blank;
|
||||
always @(posedge clk) blank <= tv_blank;
|
||||
|
||||
wire [14:0] vpix = blank ? 15'b0 : vpixel[14:0];
|
||||
|
||||
assign vred = {vpix[14:10], vpix[14:12]};
|
||||
assign vgrn = {vpix[ 9: 5], vpix[ 9: 7]};
|
||||
assign vblu = {vpix[ 4: 0], vpix[ 4: 2]};
|
||||
assign vdac_mode = vpixel[15];
|
||||
dpram #(.DATAWIDTH(16), .ADDRWIDTH(8), .MEM_INIT_FILE("rtl/video/video_cram.mif")) video_cram
|
||||
(
|
||||
.clock (clk),
|
||||
.address_a(cram_addr_in),
|
||||
.data_a (cram_data_in),
|
||||
.wren_a (cram_we),
|
||||
.address_b(vdata),
|
||||
.q_b (vpixel)
|
||||
);
|
||||
/*
|
||||
altdpram video_cram
|
||||
(
|
||||
.inclock (clk),
|
||||
.data (cram_data_in),
|
||||
.rdaddress (vdata),
|
||||
.wraddress (cram_addr_in),
|
||||
.wren (cram_we),
|
||||
.q (vpixel),
|
||||
.aclr (1'b0),
|
||||
.byteena (1'b1),
|
||||
.inclocken (1'b1),
|
||||
.outclock (1'b1),
|
||||
.outclocken (1'b1),
|
||||
.rdaddressstall (1'b0),
|
||||
.rden (1'b1),
|
||||
.wraddressstall (1'b0)
|
||||
);
|
||||
|
||||
defparam
|
||||
video_cram.indata_aclr = "OFF",
|
||||
video_cram.indata_reg = "INCLOCK",
|
||||
video_cram.intended_device_family = "ACEX1K",
|
||||
video_cram.lpm_file = "../video/mem/video_cram.mif",
|
||||
video_cram.lpm_type = "altdpram",
|
||||
video_cram.outdata_aclr = "OFF",
|
||||
video_cram.outdata_reg = "UNREGISTERED",
|
||||
video_cram.rdaddress_aclr = "OFF",
|
||||
video_cram.rdaddress_reg = "INCLOCK",
|
||||
video_cram.rdcontrol_aclr = "OFF",
|
||||
video_cram.rdcontrol_reg = "UNREGISTERED",
|
||||
video_cram.width = 16,
|
||||
video_cram.widthad = 8,
|
||||
video_cram.wraddress_aclr = "OFF",
|
||||
video_cram.wraddress_reg = "INCLOCK",
|
||||
video_cram.wrcontrol_aclr = "OFF",
|
||||
video_cram.wrcontrol_reg = "INCLOCK";
|
||||
*/
|
||||
endmodule
|
||||
|
@ -1,149 +1,166 @@
|
||||
// This module latches all port parameters for video from Z80
|
||||
|
||||
|
||||
module video_ports
|
||||
(
|
||||
// clocks
|
||||
input wire clk,
|
||||
|
||||
input wire [ 7:0] d,
|
||||
input wire res,
|
||||
input wire int_start,
|
||||
input wire line_start_s,
|
||||
|
||||
// port write strobes
|
||||
input wire zborder_wr,
|
||||
input wire border_wr,
|
||||
input wire zvpage_wr,
|
||||
input wire vpage_wr,
|
||||
input wire vconf_wr,
|
||||
input wire gx_offsl_wr,
|
||||
input wire gx_offsh_wr,
|
||||
input wire gy_offsl_wr,
|
||||
input wire gy_offsh_wr,
|
||||
input wire t0x_offsl_wr,
|
||||
input wire t0x_offsh_wr,
|
||||
input wire t0y_offsl_wr,
|
||||
input wire t0y_offsh_wr,
|
||||
input wire t1x_offsl_wr,
|
||||
input wire t1x_offsh_wr,
|
||||
input wire t1y_offsl_wr,
|
||||
input wire t1y_offsh_wr,
|
||||
input wire tsconf_wr,
|
||||
input wire palsel_wr,
|
||||
input wire tmpage_wr,
|
||||
input wire t0gpage_wr,
|
||||
input wire t1gpage_wr,
|
||||
input wire sgpage_wr,
|
||||
input wire hint_beg_wr ,
|
||||
input wire vint_begl_wr,
|
||||
input wire vint_begh_wr,
|
||||
|
||||
// video parameters
|
||||
output reg [7:0] border,
|
||||
output reg [7:0] vpage,
|
||||
output reg [7:0] vconf,
|
||||
output reg [8:0] gx_offs,
|
||||
output reg [8:0] gy_offs,
|
||||
output reg [8:0] t0x_offs,
|
||||
output reg [8:0] t0y_offs,
|
||||
output reg [8:0] t1x_offs,
|
||||
output reg [8:0] t1y_offs,
|
||||
output reg [7:0] palsel,
|
||||
output reg [7:0] hint_beg,
|
||||
output reg [8:0] vint_beg,
|
||||
output reg [7:0] tsconf,
|
||||
output reg [7:0] tmpage,
|
||||
output reg [7:0] t0gpage,
|
||||
output reg [7:0] t1gpage,
|
||||
output reg [7:0] sgpage
|
||||
);
|
||||
|
||||
reg [7:0] vpage_r;
|
||||
reg [7:0] vconf_r;
|
||||
reg [7:0] t0gpage_r;
|
||||
reg [7:0] t1gpage_r;
|
||||
reg [8:0] gx_offs_r;
|
||||
reg [8:0] t0x_offs_r;
|
||||
reg [8:0] t1x_offs_r;
|
||||
reg [7:0] palsel_r;
|
||||
|
||||
wire [8:0] vint_beg_inc = vint_beg + vint_inc;
|
||||
wire [8:0] vint_beg_next = {(vint_beg_inc[8:6] == 3'b101) ? 3'b0 : vint_beg_inc[8:6], vint_beg_inc[5:0]}; // if over 319 lines, decrement 320
|
||||
// This module latches all port parameters for video from Z80
|
||||
|
||||
reg [3:0] vint_inc;
|
||||
always @(posedge clk) begin
|
||||
if (res) begin
|
||||
vint_beg <= 9'd0;
|
||||
vint_inc <= 4'b0;
|
||||
end
|
||||
else if (vint_begl_wr) vint_beg[7:0] <= d;
|
||||
else if (vint_begh_wr) begin
|
||||
vint_beg[8] <= d[0];
|
||||
vint_inc <= d[7:4];
|
||||
end
|
||||
else if (int_start) vint_beg <= vint_beg_next;
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (res) begin
|
||||
vpage_r <= 8'h05;
|
||||
vconf_r <= 8'h00;
|
||||
gx_offs_r <= 9'b0;
|
||||
palsel_r <= 8'h0F;
|
||||
gy_offs <= 9'b0;
|
||||
tsconf <= 8'b0;
|
||||
hint_beg <= 8'd1;
|
||||
end
|
||||
else begin
|
||||
if (zborder_wr ) border <= {palsel[3:0], 1'b0, d[2:0]};
|
||||
if (border_wr ) border <= d;
|
||||
if (gy_offsl_wr ) gy_offs[7:0] <= d;
|
||||
if (gy_offsh_wr ) gy_offs[8] <= d[0];
|
||||
if (t0y_offsl_wr) t0y_offs[7:0] <= d;
|
||||
if (t0y_offsh_wr) t0y_offs[8] <= d[0];
|
||||
if (t1y_offsl_wr) t1y_offs[7:0] <= d;
|
||||
if (t1y_offsh_wr) t1y_offs[8] <= d[0];
|
||||
if (tsconf_wr ) tsconf <= d;
|
||||
if (tmpage_wr ) tmpage <= d;
|
||||
if (sgpage_wr ) sgpage <= d;
|
||||
if (hint_beg_wr ) hint_beg <= d;
|
||||
|
||||
if (zvpage_wr ) vpage_r <= {6'b000001, d[3], 1'b1};
|
||||
if (vpage_wr ) vpage_r <= d;
|
||||
if (vconf_wr ) vconf_r <= d;
|
||||
if (gx_offsl_wr ) gx_offs_r[7:0] <= d;
|
||||
if (gx_offsh_wr ) gx_offs_r[8] <= d[0];
|
||||
if (palsel_wr ) palsel_r <= d;
|
||||
if (t0x_offsl_wr) t0x_offs_r[7:0] <= d;
|
||||
if (t0x_offsh_wr) t0x_offs_r[8] <= d[0];
|
||||
if (t1x_offsl_wr) t1x_offs_r[7:0] <= d;
|
||||
if (t1x_offsh_wr) t1x_offs_r[8] <= d[0];
|
||||
if (t0gpage_wr ) t0gpage_r <= d;
|
||||
if (t1gpage_wr ) t1gpage_r <= d;
|
||||
end
|
||||
end
|
||||
|
||||
// latching regs at line start, delaying hires for 1 line
|
||||
always @(posedge clk) begin
|
||||
if (res)
|
||||
begin
|
||||
vpage <= 8'h05;
|
||||
vconf <= 8'h00;
|
||||
gx_offs <= 9'b0;
|
||||
palsel <= 8'h0F;
|
||||
end
|
||||
else if (zvpage_wr) vpage <= {6'b000001, d[3], 1'b1};
|
||||
else if (line_start_s) begin
|
||||
vpage <= vpage_r;
|
||||
vconf <= vconf_r;
|
||||
gx_offs <= gx_offs_r;
|
||||
palsel <= palsel_r;
|
||||
t0x_offs <= t0x_offs_r;
|
||||
t1x_offs <= t1x_offs_r;
|
||||
t0gpage <= t0gpage_r;
|
||||
t1gpage <= t1gpage_r;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
`include "tune.v"
|
||||
|
||||
module video_ports
|
||||
(
|
||||
// clocks
|
||||
input wire clk,
|
||||
|
||||
input wire [ 7:0] d,
|
||||
input wire res,
|
||||
input wire int_start,
|
||||
input wire line_start_s,
|
||||
|
||||
// port write strobes
|
||||
input wire zborder_wr,
|
||||
input wire border_wr,
|
||||
input wire zvpage_wr,
|
||||
input wire vpage_wr,
|
||||
input wire vconf_wr,
|
||||
input wire gx_offsl_wr,
|
||||
input wire gx_offsh_wr,
|
||||
input wire gy_offsl_wr,
|
||||
input wire gy_offsh_wr,
|
||||
input wire t0x_offsl_wr,
|
||||
input wire t0x_offsh_wr,
|
||||
input wire t0y_offsl_wr,
|
||||
input wire t0y_offsh_wr,
|
||||
input wire t1x_offsl_wr,
|
||||
input wire t1x_offsh_wr,
|
||||
input wire t1y_offsl_wr,
|
||||
input wire t1y_offsh_wr,
|
||||
input wire tsconf_wr,
|
||||
input wire palsel_wr,
|
||||
input wire tmpage_wr,
|
||||
input wire t0gpage_wr,
|
||||
input wire t1gpage_wr,
|
||||
input wire sgpage_wr,
|
||||
input wire hint_beg_wr ,
|
||||
input wire vint_begl_wr,
|
||||
input wire vint_begh_wr,
|
||||
|
||||
// video parameters
|
||||
output reg [7:0] border = 0,
|
||||
output reg [7:0] vpage = 0,
|
||||
output reg [7:0] vconf = 0,
|
||||
output reg [8:0] gx_offs = 0,
|
||||
output reg [8:0] gy_offs = 0,
|
||||
output reg [8:0] t0x_offs = 0,
|
||||
output reg [8:0] t0y_offs = 0,
|
||||
output reg [8:0] t1x_offs = 0,
|
||||
output reg [8:0] t1y_offs = 0,
|
||||
output reg [7:0] palsel = 0,
|
||||
output reg [7:0] hint_beg = 0,
|
||||
output reg [8:0] vint_beg = 0,
|
||||
output reg [7:0] tsconf = 0,
|
||||
output reg [7:0] tmpage = 0,
|
||||
output reg [7:0] t0gpage = 0,
|
||||
output reg [7:0] t1gpage = 0,
|
||||
output reg [7:0] sgpage = 0
|
||||
);
|
||||
|
||||
reg [7:0] vpage_r = 0;
|
||||
reg [7:0] vconf_r = 0;
|
||||
reg [7:0] t0gpage_r = 0;
|
||||
reg [7:0] t1gpage_r = 0;
|
||||
reg [8:0] gx_offs_r = 0;
|
||||
reg [8:0] t0x_offs_r = 0;
|
||||
reg [8:0] t1x_offs_r = 0;
|
||||
reg [7:0] palsel_r = 0;
|
||||
reg [3:0] vint_inc = 0;
|
||||
|
||||
wire [8:0] vint_beg_inc = vint_beg + vint_inc;
|
||||
wire [8:0] vint_beg_next = {(vint_beg_inc[8:6] == 3'b101) ? 3'b0 : vint_beg_inc[8:6], vint_beg_inc[5:0]}; // if over 319 lines, decrement 320
|
||||
|
||||
always @(posedge clk or posedge res)
|
||||
if (res)
|
||||
begin
|
||||
vint_beg <= 9'd0;
|
||||
vint_inc <= 4'b0;
|
||||
end
|
||||
else if (vint_begl_wr)
|
||||
vint_beg[7:0] <= d;
|
||||
|
||||
else if (vint_begh_wr)
|
||||
begin
|
||||
vint_beg[8] <= d[0];
|
||||
vint_inc <= d[7:4];
|
||||
end
|
||||
|
||||
else if (int_start)
|
||||
vint_beg <= vint_beg_next;
|
||||
|
||||
always @(posedge clk or posedge res)
|
||||
if (res)
|
||||
begin
|
||||
vpage_r <= 8'h05;
|
||||
vconf_r <= 8'h00;
|
||||
gx_offs_r <= 9'b0;
|
||||
palsel_r <= 8'h0F;
|
||||
gy_offs <= 9'b0;
|
||||
tsconf <= 8'b0;
|
||||
hint_beg <= 8'd1;
|
||||
end
|
||||
|
||||
else
|
||||
begin
|
||||
if (zborder_wr ) border <= {palsel[3:0], 1'b0, d[2:0]};
|
||||
if (border_wr ) border <= d;
|
||||
if (gy_offsl_wr ) gy_offs[7:0] <= d;
|
||||
if (gy_offsh_wr ) gy_offs[8] <= d[0];
|
||||
if (t0y_offsl_wr) t0y_offs[7:0] <= d;
|
||||
if (t0y_offsh_wr) t0y_offs[8] <= d[0];
|
||||
if (t1y_offsl_wr) t1y_offs[7:0] <= d;
|
||||
if (t1y_offsh_wr) t1y_offs[8] <= d[0];
|
||||
if (tsconf_wr ) tsconf <= d;
|
||||
if (tmpage_wr ) tmpage <= d;
|
||||
if (sgpage_wr ) sgpage <= d;
|
||||
if (hint_beg_wr ) hint_beg <= d;
|
||||
|
||||
if (zvpage_wr ) vpage_r <= {6'b000001, d[3], 1'b1};
|
||||
if (vpage_wr ) vpage_r <= d;
|
||||
if (vconf_wr ) vconf_r <= d;
|
||||
if (gx_offsl_wr ) gx_offs_r[7:0] <= d;
|
||||
if (gx_offsh_wr ) gx_offs_r[8] <= d[0];
|
||||
if (palsel_wr ) palsel_r <= d;
|
||||
if (t0x_offsl_wr) t0x_offs_r[7:0] <= d;
|
||||
if (t0x_offsh_wr) t0x_offs_r[8] <= d[0];
|
||||
if (t1x_offsl_wr) t1x_offs_r[7:0] <= d;
|
||||
if (t1x_offsh_wr) t1x_offs_r[8] <= d[0];
|
||||
if (t0gpage_wr ) t0gpage_r <= d;
|
||||
if (t1gpage_wr ) t1gpage_r <= d;
|
||||
end
|
||||
|
||||
// latching regs at line start, delaying hires for 1 line
|
||||
always @(posedge clk or posedge res)
|
||||
if (res)
|
||||
begin
|
||||
vpage <= 8'h05;
|
||||
`ifdef FORCE_TEXT_MODE
|
||||
vconf <= 8'h83;
|
||||
`else
|
||||
vconf <= 8'h00;
|
||||
`endif
|
||||
gx_offs <= 9'b0;
|
||||
palsel <= 8'h0F;
|
||||
end
|
||||
|
||||
else if (zvpage_wr)
|
||||
vpage <= {6'b000001, d[3], 1'b1};
|
||||
|
||||
else if (line_start_s)
|
||||
begin
|
||||
vpage <= vpage_r;
|
||||
`ifndef FORCE_TEXT_MODE
|
||||
vconf <= vconf_r;
|
||||
`endif
|
||||
gx_offs <= gx_offs_r;
|
||||
palsel <= palsel_r;
|
||||
t0x_offs <= t0x_offs_r;
|
||||
t1x_offs <= t1x_offs_r;
|
||||
t0gpage <= t0gpage_r;
|
||||
t1gpage <= t1gpage_r;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
@ -1,84 +1,87 @@
|
||||
// This module renders video data for output
|
||||
|
||||
// This module renders video data for output
|
||||
|
||||
`include "tune.v"
|
||||
|
||||
module video_render
|
||||
(
|
||||
// clocks
|
||||
input wire clk, c1,
|
||||
|
||||
// video controls
|
||||
input wire hvpix,
|
||||
input wire hvtspix,
|
||||
input wire nogfx,
|
||||
input wire notsu,
|
||||
input wire gfxovr,
|
||||
input wire flash,
|
||||
input wire hires,
|
||||
input wire [3:0] psel,
|
||||
input wire [3:0] palsel,
|
||||
|
||||
// mode controls
|
||||
input wire [1:0] render_mode,
|
||||
|
||||
// video data
|
||||
input wire [31:0] data,
|
||||
input wire [ 7:0] border_in,
|
||||
input wire [ 7:0] tsdata_in,
|
||||
output wire [ 7:0] vplex_out
|
||||
);
|
||||
|
||||
localparam R_ZX = 2'h0;
|
||||
localparam R_HC = 2'h1;
|
||||
localparam R_XC = 2'h2;
|
||||
localparam R_TX = 2'h3;
|
||||
|
||||
// ZX graphics
|
||||
wire [15:0] zx_gfx = data[15: 0];
|
||||
wire [15:0] zx_atr = data[31:16];
|
||||
wire zx_dot = zx_gfx[{psel[3], ~psel[2:0]}];
|
||||
wire [7:0] zx_attr = ~psel[3] ? zx_atr[7:0] : zx_atr[15:8];
|
||||
wire [7:0] zx_pix = {palsel, zx_attr[6], zx_dot ^ (flash & zx_attr[7]) ? zx_attr[2:0] : zx_attr[5:3]};
|
||||
|
||||
// text graphics
|
||||
// (it uses common renderer with ZX, but different attributes)
|
||||
wire [7:0] tx_pix = {palsel, zx_dot ? zx_attr[3:0] : zx_attr[7:4]};
|
||||
|
||||
// 16c graphics
|
||||
wire [3:0] hc_dot[0:3];
|
||||
assign hc_dot[0] = data[ 7: 4];
|
||||
assign hc_dot[1] = data[ 3: 0];
|
||||
assign hc_dot[2] = data[15:12];
|
||||
assign hc_dot[3] = data[11: 8];
|
||||
wire [7:0] hc_pix = {palsel, hc_dot[psel[1:0]]};
|
||||
|
||||
// 256c graphics
|
||||
wire [7:0] xc_dot[0:1];
|
||||
assign xc_dot[0] = data[ 7: 0];
|
||||
assign xc_dot[1] = data[15: 8];
|
||||
wire [7:0] xc_pix = xc_dot[psel[0]];
|
||||
|
||||
// mode selects
|
||||
wire [7:0] pix[0:3];
|
||||
assign pix[R_ZX] = zx_pix; // ZX
|
||||
assign pix[R_HC] = hc_pix; // 16c
|
||||
assign pix[R_XC] = xc_pix; // 256c
|
||||
assign pix[R_TX] = tx_pix; // text
|
||||
|
||||
wire pixv[0:3];
|
||||
assign pixv[R_ZX] = zx_dot ^ (flash & zx_attr[7]);
|
||||
assign pixv[R_HC] = |hc_dot[psel[1:0]];
|
||||
assign pixv[R_XC] = |xc_dot[psel[0]];
|
||||
assign pixv[R_TX] = zx_dot;
|
||||
|
||||
// video plex muxer
|
||||
wire tsu_visible = (|tsdata_in[3:0] && !notsu);
|
||||
wire gfx_visible = (pixv[render_mode] && !nogfx);
|
||||
wire [7:0] video1 = tsu_visible ? tsdata_in : (nogfx ? border_in : pix[render_mode]);
|
||||
wire [7:0] video2 = gfx_visible ? pix[render_mode] : (tsu_visible ? tsdata_in : border_in);
|
||||
wire [7:0] video = hvpix ? (gfxovr ? video2 : video1) : ((hvtspix && tsu_visible) ? tsdata_in : border_in);
|
||||
assign vplex_out = hires ? {temp, video[3:0]} : video; // in hi-res plex contains two pixels 4 bits each
|
||||
|
||||
reg [3:0] temp;
|
||||
always @(posedge clk) if (c1) temp <= video[3:0];
|
||||
|
||||
endmodule
|
||||
|
||||
(
|
||||
// clocks
|
||||
input wire clk, c1,
|
||||
|
||||
// video controls
|
||||
input wire hvpix,
|
||||
input wire hvtspix,
|
||||
input wire nogfx,
|
||||
input wire notsu,
|
||||
input wire gfxovr,
|
||||
input wire flash,
|
||||
input wire hires,
|
||||
input wire [3:0] psel,
|
||||
input wire [3:0] palsel,
|
||||
|
||||
// mode controls
|
||||
input wire [1:0] render_mode,
|
||||
|
||||
// video data
|
||||
input wire [31:0] data,
|
||||
input wire [ 7:0] border_in,
|
||||
input wire [ 7:0] tsdata_in,
|
||||
output wire [ 7:0] vplex_out
|
||||
);
|
||||
|
||||
localparam R_ZX = 2'h0;
|
||||
localparam R_HC = 2'h1;
|
||||
localparam R_XC = 2'h2;
|
||||
localparam R_TX = 2'h3;
|
||||
|
||||
reg [3:0] temp;
|
||||
|
||||
// ZX graphics
|
||||
wire [15:0] zx_gfx = data[15: 0];
|
||||
wire [15:0] zx_atr = data[31:16];
|
||||
wire zx_dot = zx_gfx[{psel[3], ~psel[2:0]}];
|
||||
wire [7:0] zx_attr = ~psel[3] ? zx_atr[7:0] : zx_atr[15:8];
|
||||
wire [7:0] zx_pix = {palsel, zx_attr[6], zx_dot ^ (flash & zx_attr[7]) ? zx_attr[2:0] : zx_attr[5:3]};
|
||||
|
||||
// text graphics
|
||||
// (uses common renderer with ZX, but different attributes)
|
||||
wire [7:0] tx_pix = {palsel, zx_dot ? zx_attr[3:0] : zx_attr[7:4]};
|
||||
|
||||
// 16c graphics
|
||||
wire [3:0] hc_dot[0:3];
|
||||
assign hc_dot[0] = data[ 7: 4];
|
||||
assign hc_dot[1] = data[ 3: 0];
|
||||
assign hc_dot[2] = data[15:12];
|
||||
assign hc_dot[3] = data[11: 8];
|
||||
wire [7:0] hc_pix = {palsel, hc_dot[psel[1:0]]};
|
||||
|
||||
// 256c graphics
|
||||
wire [7:0] xc_dot[0:1];
|
||||
assign xc_dot[0] = data[ 7: 0];
|
||||
assign xc_dot[1] = data[15: 8];
|
||||
wire [7:0] xc_pix = xc_dot[psel[0]];
|
||||
|
||||
// mode selects
|
||||
wire [7:0] pix[0:3];
|
||||
assign pix[R_ZX] = zx_pix; // ZX
|
||||
assign pix[R_HC] = hc_pix; // 16c
|
||||
assign pix[R_XC] = xc_pix; // 256c
|
||||
assign pix[R_TX] = tx_pix; // text
|
||||
|
||||
wire pixv[0:3];
|
||||
assign pixv[R_ZX] = zx_dot ^ (flash & zx_attr[7]);
|
||||
assign pixv[R_HC] = |hc_dot[psel[1:0]];
|
||||
assign pixv[R_XC] = |xc_dot[psel[0]];
|
||||
assign pixv[R_TX] = zx_dot;
|
||||
|
||||
// video plex muxer
|
||||
wire tsu_visible = (|tsdata_in[3:0] && !notsu);
|
||||
wire gfx_visible = (pixv[render_mode] && !nogfx);
|
||||
wire [7:0] video1 = tsu_visible ? tsdata_in : (nogfx ? border_in : pix[render_mode]);
|
||||
wire [7:0] video2 = gfx_visible ? pix[render_mode] : (tsu_visible ? tsdata_in : border_in);
|
||||
wire [7:0] video = hvpix ? (gfxovr ? video2 : video1) : ((hvtspix && tsu_visible) ? tsdata_in : border_in);
|
||||
assign vplex_out = hires ? {temp, video[3:0]} : video; // in hi-res plex contains two pixels 4 bits each
|
||||
|
||||
always @(posedge clk) if (c1)
|
||||
temp <= video[3:0];
|
||||
|
||||
endmodule
|
||||
|
@ -1,169 +1,243 @@
|
||||
|
||||
// This module generates all video raster signals
|
||||
|
||||
|
||||
`include "tune.v"
|
||||
|
||||
// This module generates video raster signals
|
||||
|
||||
module video_sync
|
||||
(
|
||||
// clocks
|
||||
input wire clk, f1, c0, c1, c3, pix_stb,
|
||||
|
||||
// video parameters
|
||||
input wire [8:0] hpix_beg,
|
||||
input wire [8:0] hpix_end,
|
||||
input wire [8:0] vpix_beg,
|
||||
input wire [8:0] vpix_end,
|
||||
input wire [8:0] hpix_beg_ts,
|
||||
input wire [8:0] hpix_end_ts,
|
||||
input wire [8:0] vpix_beg_ts,
|
||||
input wire [8:0] vpix_end_ts,
|
||||
input wire [4:0] go_offs,
|
||||
input wire [1:0] x_offs,
|
||||
input wire [7:0] hint_beg,
|
||||
input wire [8:0] vint_beg,
|
||||
input wire [7:0] cstart,
|
||||
input wire [8:0] rstart,
|
||||
|
||||
// video syncs
|
||||
output reg hsync,
|
||||
output reg vsync,
|
||||
|
||||
// video controls
|
||||
input wire nogfx,
|
||||
output wire v_pf,
|
||||
output wire hpix,
|
||||
output wire vpix,
|
||||
output wire v_ts,
|
||||
output wire hvpix,
|
||||
output wire hvtspix,
|
||||
output wire tv_hblank,
|
||||
output wire tv_vblank,
|
||||
output wire frame_start,
|
||||
output wire line_start_s,
|
||||
output wire pix_start,
|
||||
output wire ts_start,
|
||||
output wire frame,
|
||||
output wire flash,
|
||||
|
||||
// video counters
|
||||
output wire [8:0] ts_raddr,
|
||||
output reg [8:0] lcount,
|
||||
output reg [7:0] cnt_col,
|
||||
output reg [8:0] cnt_row,
|
||||
output reg cptr,
|
||||
output reg [3:0] scnt,
|
||||
|
||||
// DRAM
|
||||
input wire video_pre_next,
|
||||
output reg video_go,
|
||||
|
||||
// ZX controls
|
||||
input wire y_offs_wr,
|
||||
output wire int_start
|
||||
);
|
||||
|
||||
localparam HSYNC_BEG = 9'd11;
|
||||
localparam HSYNC_END = 9'd43;
|
||||
localparam HBLNK_BEG = 9'd00;
|
||||
localparam HBLNK_END = 9'd88;
|
||||
localparam HSYNCV_BEG = 9'd5;
|
||||
localparam HSYNCV_END = 9'd31;
|
||||
localparam HBLNKV_END = 9'd42;
|
||||
localparam HPERIOD = 9'd448;
|
||||
|
||||
localparam VSYNC_BEG = 9'd08;
|
||||
localparam VSYNC_END = 9'd11;
|
||||
localparam VBLNK_BEG = 9'd00;
|
||||
localparam VBLNK_END = 9'd32;
|
||||
localparam VPERIOD = 9'd320;
|
||||
|
||||
// counters
|
||||
reg [8:0] hcount = 0;
|
||||
reg [8:0] vcount = 0;
|
||||
|
||||
// horizontal TV (7 MHz)
|
||||
always @(posedge clk) if (c3) hcount <= line_start ? 9'b0 : hcount + 9'b1;
|
||||
|
||||
// vertical TV (15.625 kHz)
|
||||
always @(posedge clk) if (line_start_s) vcount <= (vcount == (VPERIOD - 1)) ? 9'b0 : vcount + 9'b1;
|
||||
|
||||
// column address for DRAM
|
||||
always @(posedge clk) begin
|
||||
if (line_start2) begin
|
||||
cnt_col <= cstart;
|
||||
cptr <= 1'b0;
|
||||
end
|
||||
else if (video_pre_next) begin
|
||||
cnt_col <= cnt_col + 8'b1;
|
||||
cptr <= ~cptr;
|
||||
end
|
||||
end
|
||||
|
||||
// row address for DRAM
|
||||
always @(posedge clk) begin if (c3)
|
||||
if (vis_start || (line_start && y_offs_wr_r)) cnt_row <= rstart;
|
||||
else if (line_start && vpix) cnt_row <= cnt_row + 9'b1;
|
||||
end
|
||||
|
||||
// pixel counter
|
||||
always @(posedge clk) if (pix_stb) scnt <= pix_start ? 4'b0 : scnt + 4'b1; // f1 or c3
|
||||
|
||||
// TS-line counter
|
||||
assign ts_raddr = hcount - hpix_beg_ts;
|
||||
|
||||
always @(posedge clk) if (ts_start_coarse) lcount <= vcount - vpix_beg_ts + 9'b1;
|
||||
|
||||
// Y offset re-latch trigger
|
||||
reg y_offs_wr_r;
|
||||
always @(posedge clk) begin
|
||||
if (y_offs_wr) y_offs_wr_r <= 1'b1;
|
||||
else if (line_start_s) y_offs_wr_r <= 1'b0;
|
||||
end
|
||||
|
||||
// FLASH generator
|
||||
reg [4:0] flash_ctr;
|
||||
assign frame = flash_ctr[0];
|
||||
assign flash = flash_ctr[4];
|
||||
always @(posedge clk) begin
|
||||
if (frame_start && c3) begin
|
||||
flash_ctr <= flash_ctr + 5'b1;
|
||||
end
|
||||
end
|
||||
|
||||
// sync strobes
|
||||
wire hs = (hcount >= HSYNC_BEG) && (hcount < HSYNC_END);
|
||||
wire vs = (vcount >= VSYNC_BEG) && (vcount < VSYNC_END);
|
||||
|
||||
assign tv_hblank = (hcount > HBLNK_BEG) && (hcount <= HBLNK_END);
|
||||
assign tv_vblank = (vcount >= VBLNK_BEG) && (vcount < VBLNK_END);
|
||||
|
||||
assign hvpix = hpix && vpix;
|
||||
|
||||
assign hpix = (hcount >= hpix_beg) && (hcount < hpix_end);
|
||||
|
||||
assign vpix = (vcount >= vpix_beg) && (vcount < vpix_end);
|
||||
(
|
||||
// clocks
|
||||
input wire clk, f1, c0, c3, pix_stb,
|
||||
|
||||
assign hvtspix = htspix && vtspix;
|
||||
wire htspix = (hcount >= hpix_beg_ts) && (hcount < hpix_end_ts);
|
||||
wire vtspix = (vcount >= vpix_beg_ts) && (vcount < vpix_end_ts);
|
||||
// video parameters
|
||||
input wire [8:0] hpix_beg,
|
||||
input wire [8:0] hpix_end,
|
||||
input wire [8:0] vpix_beg,
|
||||
input wire [8:0] vpix_end,
|
||||
input wire [8:0] hpix_beg_ts,
|
||||
input wire [8:0] hpix_end_ts,
|
||||
input wire [8:0] vpix_beg_ts,
|
||||
input wire [8:0] vpix_end_ts,
|
||||
input wire [4:0] go_offs,
|
||||
input wire [1:0] x_offs,
|
||||
input wire [7:0] hint_beg,
|
||||
input wire [8:0] vint_beg,
|
||||
input wire [7:0] cstart,
|
||||
input wire [8:0] rstart,
|
||||
|
||||
assign v_ts = (vcount >= (vpix_beg_ts - 1)) && (vcount < (vpix_end_ts - 1)); // vertical TS window
|
||||
assign v_pf = (vcount >= (vpix_beg_ts - 17)) && (vcount < (vpix_end_ts - 9)); // vertical tilemap prefetch window
|
||||
|
||||
always @(posedge clk) video_go <= (hcount >= (hpix_beg - go_offs - x_offs)) && (hcount < (hpix_end - go_offs - x_offs + 4)) && vpix && !nogfx;
|
||||
|
||||
wire line_start = hcount == (HPERIOD - 1);
|
||||
assign line_start_s = line_start && c3;
|
||||
wire line_start2 = hcount == (HSYNC_END - 1);
|
||||
assign frame_start = line_start && (vcount == (VPERIOD - 1));
|
||||
wire vis_start = line_start && (vcount == (VBLNK_END - 1));
|
||||
assign pix_start = hcount == (hpix_beg - x_offs - 1);
|
||||
wire ts_start_coarse = hcount == (hpix_beg_ts - 1);
|
||||
assign ts_start = c3 && ts_start_coarse;
|
||||
assign int_start = (hcount == {hint_beg, 1'b0}) && (vcount == vint_beg) && c0;
|
||||
|
||||
always @(posedge clk) begin
|
||||
hsync <= hs;
|
||||
vsync <= vs;
|
||||
end
|
||||
|
||||
endmodule
|
||||
// video syncs
|
||||
output reg hsync,
|
||||
output reg vsync,
|
||||
output reg csync,
|
||||
|
||||
// video controls
|
||||
input wire cfg_60hz,
|
||||
input wire vga_on,
|
||||
output reg v60hz = 0,
|
||||
input wire nogfx,
|
||||
output wire v_pf,
|
||||
output wire hpix,
|
||||
output wire vpix,
|
||||
output wire v_ts,
|
||||
output wire hvpix,
|
||||
output wire hvtspix,
|
||||
output wire tv_blank,
|
||||
output wire vga_blank,
|
||||
output wire vga_line,
|
||||
output wire frame_start,
|
||||
output wire line_start_s,
|
||||
output wire pix_start,
|
||||
output wire ts_start,
|
||||
output wire frame,
|
||||
output wire flash,
|
||||
|
||||
// video counters
|
||||
output wire [9:0] vga_cnt_in,
|
||||
output wire [9:0] vga_cnt_out,
|
||||
output wire [8:0] ts_raddr,
|
||||
output reg [8:0] lcount = 0,
|
||||
output reg [7:0] cnt_col = 0,
|
||||
output reg [8:0] cnt_row = 0,
|
||||
output reg cptr = 0,
|
||||
output reg [3:0] scnt = 0,
|
||||
`ifdef PENT_312
|
||||
output wire [4:0] hcnt,
|
||||
output wire upper8,
|
||||
`endif
|
||||
|
||||
// DRAM
|
||||
input wire video_pre_next,
|
||||
output reg video_go = 0,
|
||||
|
||||
// ZX controls
|
||||
input wire y_offs_wr,
|
||||
output wire int_start
|
||||
);
|
||||
|
||||
localparam HSYNC_BEG = 9'd11;
|
||||
localparam HSYNC_END = 9'd43;
|
||||
localparam HBLNK_BEG = 9'd00;
|
||||
localparam HBLNK_END = 9'd88;
|
||||
localparam HSYNCV_BEG = 9'd5;
|
||||
localparam HSYNCV_END = 9'd31;
|
||||
localparam HBLNKV_END = 9'd42;
|
||||
localparam HPERIOD = 9'd448;
|
||||
|
||||
localparam VSYNC_BEG_50 = 9'd08;
|
||||
localparam VSYNC_END_50 = 9'd11;
|
||||
localparam VBLNK_BEG_50 = 9'd00;
|
||||
`ifdef PENT_312
|
||||
localparam VBLNK_END_50 = 9'd24;
|
||||
localparam VPERIOD_50 = 9'd312;
|
||||
`else
|
||||
localparam VBLNK_END_50 = 9'd32;
|
||||
localparam VPERIOD_50 = 9'd320;
|
||||
`endif
|
||||
|
||||
localparam VSYNC_BEG_60 = 9'd04;
|
||||
localparam VSYNC_END_60 = 9'd07;
|
||||
localparam VBLNK_BEG_60 = 9'd00;
|
||||
localparam VBLNK_END_60 = 9'd22;
|
||||
localparam VPERIOD_60 = 9'd262;
|
||||
|
||||
wire [8:0] vsync_beg = v60hz ? VSYNC_BEG_60 : VSYNC_BEG_50;
|
||||
wire [8:0] vsync_end = v60hz ? VSYNC_END_60 : VSYNC_END_50;
|
||||
wire [8:0] vblnk_beg = v60hz ? VBLNK_BEG_60 : VBLNK_BEG_50;
|
||||
wire [8:0] vblnk_end = v60hz ? VBLNK_END_60 : VBLNK_END_50;
|
||||
wire [8:0] vperiod = v60hz ? VPERIOD_60 : VPERIOD_50;
|
||||
|
||||
`ifdef PENT_312
|
||||
assign hcnt = hcount[4:0];
|
||||
assign upper8 = vcount < 8;
|
||||
`endif
|
||||
|
||||
reg [8:0] hcount = 0;
|
||||
reg [8:0] vcount = 0;
|
||||
reg [8:0] cnt_out = 0;
|
||||
reg vga_hblank = 0;
|
||||
reg vga_vblank = 0;
|
||||
|
||||
wire line_start = hcount == (HPERIOD - 1);
|
||||
wire line_start2 = hcount == (HSYNC_END - 1);
|
||||
assign line_start_s = line_start && c3;
|
||||
assign frame_start = line_start && (vcount == (vperiod - 1));
|
||||
wire vis_start = line_start && (vcount == (vblnk_end - 1));
|
||||
assign pix_start = hcount == (hpix_beg - x_offs - 1);
|
||||
wire ts_start_coarse = hcount == (hpix_beg_ts - 1);
|
||||
assign ts_start = c3 && ts_start_coarse;
|
||||
assign int_start = (hcount == {hint_beg, 1'b0}) && (vcount == vint_beg) && c0;
|
||||
wire vga_pix_start = ((hcount == (HBLNKV_END)) || (hcount == (HBLNKV_END + HPERIOD/2)));
|
||||
wire hs_vga = ((hcount >= HSYNCV_BEG) && (hcount < HSYNCV_END)) || ((hcount >= (HSYNCV_BEG + HPERIOD/2)) && (hcount < (HSYNCV_END + HPERIOD/2)));
|
||||
assign vga_line = (hcount >= HPERIOD/2);
|
||||
wire hs = (hcount >= HSYNC_BEG) && (hcount < HSYNC_END);
|
||||
wire vs = (vcount >= vsync_beg) && (vcount < vsync_end);
|
||||
assign vga_cnt_in = {vcount[0], hcount - HBLNK_END};
|
||||
assign vga_cnt_out = {~vcount[0], cnt_out};
|
||||
wire tv_hblank = (hcount > HBLNK_BEG) && (hcount <= HBLNK_END);
|
||||
wire tv_vblank = (vcount >= vblnk_beg) && (vcount < vblnk_end);
|
||||
assign vga_blank = vga_hblank || vga_vblank;
|
||||
assign tv_blank = tv_hblank || tv_vblank;
|
||||
|
||||
// horizontal TV (7 MHz)
|
||||
always @(posedge clk) if (c3)
|
||||
hcount <= line_start ? 9'b0 : hcount + 9'b1;
|
||||
|
||||
// vertical TV (15.625 kHz)
|
||||
always @(posedge clk) if (line_start_s)
|
||||
vcount <= (vcount == (vperiod - 1)) ? 9'b0 : vcount + 9'b1;
|
||||
|
||||
// horizontal VGA (14MHz)
|
||||
always @(posedge clk) if (f1)
|
||||
cnt_out <= vga_pix_start && c3 ? 9'b0 : cnt_out + 9'b1;
|
||||
|
||||
// column address for DRAM
|
||||
always @(posedge clk)
|
||||
begin
|
||||
if (line_start2)
|
||||
begin
|
||||
cnt_col <= cstart;
|
||||
cptr <= 1'b0;
|
||||
end
|
||||
|
||||
else if (video_pre_next)
|
||||
begin
|
||||
cnt_col <= cnt_col + 8'b1;
|
||||
cptr <= ~cptr;
|
||||
end
|
||||
end
|
||||
|
||||
// row address for DRAM
|
||||
reg y_offs_wr_r;
|
||||
|
||||
always @(posedge clk) if (c3)
|
||||
if (vis_start || (line_start && y_offs_wr_r))
|
||||
cnt_row <= rstart;
|
||||
else
|
||||
if (line_start && vpix)
|
||||
cnt_row <= cnt_row + 9'b1;
|
||||
|
||||
// pixel counter
|
||||
always @(posedge clk) if (pix_stb) // f1 or c3
|
||||
scnt <= pix_start ? 4'b0 : scnt + 4'b1;
|
||||
|
||||
// TS-line counter
|
||||
assign ts_raddr = hcount - hpix_beg_ts;
|
||||
|
||||
always @(posedge clk)
|
||||
if (ts_start_coarse)
|
||||
lcount <= vcount - vpix_beg_ts + 9'b1;
|
||||
|
||||
// Y offset re-latch trigger
|
||||
always @(posedge clk)
|
||||
if (y_offs_wr)
|
||||
y_offs_wr_r <= 1'b1;
|
||||
else if (line_start_s)
|
||||
y_offs_wr_r <= 1'b0;
|
||||
|
||||
// FLASH generator
|
||||
reg [4:0] flash_ctr;
|
||||
assign frame = flash_ctr[0];
|
||||
assign flash = flash_ctr[4];
|
||||
|
||||
always @(posedge clk)
|
||||
if (frame_start && c3)
|
||||
begin
|
||||
flash_ctr <= flash_ctr + 5'b1;
|
||||
// re-sync 60Hz mode selector
|
||||
`ifdef FORCE_60HZ
|
||||
v60hz <= 1'b1;
|
||||
`elsif ENABLE_60HZ
|
||||
v60hz <= !cfg_60hz;
|
||||
`else
|
||||
v60hz <= 1'b0;
|
||||
`endif
|
||||
end
|
||||
|
||||
// sync strobes
|
||||
wire vga_hblank1 = (cnt_out > 9'd359);
|
||||
always @(posedge clk) if (f1) // fix me - bydlocode !!!
|
||||
vga_hblank <= vga_hblank1;
|
||||
|
||||
assign hvpix = hpix && vpix;
|
||||
assign hpix = (hcount >= hpix_beg) && (hcount < hpix_end);
|
||||
assign vpix = (vcount >= vpix_beg) && (vcount < vpix_end);
|
||||
|
||||
wire htspix = (hcount >= hpix_beg_ts) && (hcount < hpix_end_ts);
|
||||
wire vtspix = (vcount >= vpix_beg_ts) && (vcount < vpix_end_ts);
|
||||
assign hvtspix = htspix && vtspix;
|
||||
|
||||
assign v_ts = (vcount >= (vpix_beg_ts - 1)) && (vcount < (vpix_end_ts - 1)); // vertical TS window
|
||||
assign v_pf = (vcount >= (vpix_beg_ts - 17)) && (vcount < (vpix_end_ts - 9)); // vertical tilemap prefetch window
|
||||
|
||||
always @(posedge clk)
|
||||
video_go <= (hcount >= (hpix_beg - go_offs - x_offs)) && (hcount < (hpix_end - go_offs - x_offs + 4)) && vpix && !nogfx;
|
||||
|
||||
always @(posedge clk) if (line_start_s) // fix me - bydlocode !!!
|
||||
vga_vblank <= tv_vblank;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
hsync <= vga_on ? hs_vga : hs;
|
||||
vsync <= vs;
|
||||
csync <= ~(vs ^ hs);
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,383 +1,459 @@
|
||||
|
||||
// This is the Tile Sprite Processing Unit
|
||||
|
||||
// Tiles map address:
|
||||
// bits desc
|
||||
// 20:13 tmpage
|
||||
// 12:
|
||||
|
||||
// Graphics address:
|
||||
// bits desc
|
||||
// 20:13 Xgpage
|
||||
// 15:7 line (bits 15:13 are added) - 512 lines
|
||||
// 6:0 word within line - 128 words = 512 pixels
|
||||
|
||||
|
||||
module video_ts
|
||||
(
|
||||
|
||||
// clocks
|
||||
input wire clk,
|
||||
|
||||
// video controls
|
||||
input wire start,
|
||||
input wire [8:0] line, // = vcount - vpix_beg + 9'b1;
|
||||
input wire v_ts,
|
||||
input wire v_pf, // vertical tilemap prefetch window
|
||||
|
||||
// video config
|
||||
input wire [7:0] tsconf,
|
||||
input wire [7:0] t0gpage,
|
||||
input wire [7:0] t1gpage,
|
||||
input wire [7:0] sgpage,
|
||||
input wire [7:0] tmpage,
|
||||
input wire [5:0] num_tiles,
|
||||
input wire [8:0] t0x_offs,
|
||||
input wire [8:0] t1x_offs,
|
||||
input wire [8:0] t0y_offs,
|
||||
input wire [8:0] t1y_offs,
|
||||
input wire [1:0] t0_palsel,
|
||||
input wire [1:0] t1_palsel,
|
||||
|
||||
// SFYS interface
|
||||
input wire [7:0] sfile_addr_in,
|
||||
input wire [15:0] sfile_data_in,
|
||||
input wire sfile_we,
|
||||
|
||||
// renderer interface
|
||||
output wire tsr_go,
|
||||
output wire [5:0] tsr_addr, // graphics address within the line
|
||||
output wire [8:0] tsr_line, // bitmap line
|
||||
output wire [7:0] tsr_page, // bitmap 1st page
|
||||
output wire [8:0] tsr_x, // addr in buffer (0-359 visibles)
|
||||
output wire [2:0] tsr_xs, // size (8-64 pix)
|
||||
output wire tsr_xf, // X flip
|
||||
output wire [3:0] tsr_pal, // palette
|
||||
input wire tsr_rdy, // renderer is done and ready to receive a new task
|
||||
|
||||
// DRAM interface
|
||||
output wire [20:0] dram_addr,
|
||||
output wire dram_req,
|
||||
input wire dram_next,
|
||||
input wire [15:0] dram_rdata
|
||||
);
|
||||
|
||||
|
||||
// config
|
||||
wire s_en = tsconf[7];
|
||||
wire t1_en = tsconf[6];
|
||||
wire t0_en = tsconf[5];
|
||||
wire t1z_en = tsconf[3];
|
||||
wire t0z_en = tsconf[2];
|
||||
|
||||
|
||||
// TS renderer interface
|
||||
assign tsr_go = sprite_go || tile_go;
|
||||
assign tsr_x = sprites ? sprites_x : tile_x;
|
||||
assign tsr_xs = sprites ? sprites_xs : 3'd0;
|
||||
assign tsr_xf = sprites ? sprites_xf : t_xflp;
|
||||
assign tsr_page = sprites ? sgpage : tile_page;
|
||||
assign tsr_line = sprites ? sprites_line : tile_line;
|
||||
assign tsr_addr = sprites ? sprites_addr : tile_addr;
|
||||
assign tsr_pal = sprites ? s_pal : tile_pal;
|
||||
|
||||
|
||||
// Layer selectors control
|
||||
|
||||
localparam LAYERS = 6; // Total number of layers to process
|
||||
localparam TM = 0; // Individual layers
|
||||
localparam S0 = 1;
|
||||
localparam T0 = 2;
|
||||
localparam S1 = 3;
|
||||
localparam T1 = 4;
|
||||
localparam S2 = 5;
|
||||
|
||||
wire tmap = layer_active[TM];
|
||||
wire sprites = layer_active[S0] || layer_active[S1] || layer_active[S2];
|
||||
wire tiles = layer_active[T0] || layer_active[T1];
|
||||
|
||||
reg [LAYERS-1:0] layer;
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
layer <= 1;
|
||||
else if (|(layer & layer_skip))
|
||||
layer <= {layer[LAYERS-2:0], 1'b0};
|
||||
|
||||
reg [LAYERS-1:0] layer_active;
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
layer_active <= 0;
|
||||
else
|
||||
layer_active <= layer & ~layer_skip;
|
||||
|
||||
wire [LAYERS-1:0] layer_enabled = {s_en, t1_en, s_en, t0_en, s_en, t1_en || t0_en};
|
||||
wire [LAYERS-1:0] layer_allowed = {{5{v_ts}}, v_pf};
|
||||
wire [LAYERS-1:0] layer_end = {spr_end[2], tile_end[1], spr_end[1], tile_end[0], spr_end[0], tm_end};
|
||||
|
||||
reg [LAYERS-1:0] layer_skip;
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
layer_skip <= ~(layer_enabled & layer_allowed);
|
||||
else
|
||||
layer_skip <= layer_skip | layer_end;
|
||||
|
||||
|
||||
// --- Tile map prefetch ---
|
||||
|
||||
// DRAM controls
|
||||
assign dram_addr = {tmpage, tm_b_row, tm_layer, tm_b_line, tm_num}; // 20:13 - page, 12:7 - row, 6 - layer, 5:0 - column (burst number : number in burst)
|
||||
assign dram_req = tmap;
|
||||
|
||||
// TMB control
|
||||
wire [8:0] tmb_waddr = {tm_line[4:3], tm_b_line, tm_num, tm_layer}; // 8:7 - buffer #, 6:4 - burst number (of 8 bursts), 3:1 - number in burst (8 tiles per burst), 0 - layer
|
||||
wire [8:0] tm_line = line + 9'd16;
|
||||
wire [2:0] tm_b_line = tm_line[2:0];
|
||||
wire [5:0] tm_b_row = tm_line[8:3] + (tm_layer ? t1y_offs[8:3] : t0y_offs[8:3]);
|
||||
wire [2:0] tm_num = tm_x[2:0];
|
||||
wire tm_layer = tm_x[3];
|
||||
|
||||
// internal layers control
|
||||
wire tm_end = tm_x == (t1_en ? 5'd16 : 5'd8);
|
||||
wire tm_next = dram_next && tmap;
|
||||
|
||||
reg [1:0] m_layer;
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
m_layer <= 2'b1;
|
||||
else if (tm_end)
|
||||
m_layer <= {m_layer[0], 1'b0};
|
||||
|
||||
// tilemap X coordinate
|
||||
reg [4:0] tm_x;
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
tm_x <= t0_en ? 5'd0 : 5'd8;
|
||||
else if (tm_next)
|
||||
tm_x <= tm_x + 5'd1;
|
||||
|
||||
|
||||
// --- Tiles ---
|
||||
|
||||
// tile descriptor fields
|
||||
wire [11:0] t_tnum = tmb_rdata[11:0];
|
||||
wire [1:0] t_pal = tmb_rdata[13:12];
|
||||
wire t_xflp = tmb_rdata[14];
|
||||
wire t_yflp = tmb_rdata[15];
|
||||
|
||||
// TSR control
|
||||
wire [7:0] tile_page = t_sel ? t0gpage : t1gpage;
|
||||
wire [8:0] tile_line = {t_tnum[11:6], (t_line[2:0] ^ {3{t_yflp}})};
|
||||
wire [5:0] tile_addr = t_tnum[5:0];
|
||||
wire [8:0] tile_x = {(tx - 6'd1), 3'd0} - tx_offs[2:0];
|
||||
wire [3:0] tile_pal = {t_sel ? t0_palsel : t1_palsel, t_pal};
|
||||
|
||||
// TMB control
|
||||
wire [8:0] tmb_raddr = {t_line[4:3], tx + tx_offs[8:3], ~t_sel};
|
||||
|
||||
// layer parameter selectors
|
||||
wire [8:0] tx_offs = t_sel ? t0x_offs : t1x_offs;
|
||||
wire [3:0] ty_offs = t_sel ? t0y_offs[2:0] : t1y_offs[2:0];
|
||||
wire t_sel = t_layer[0];
|
||||
|
||||
// internal layers control
|
||||
wire [1:0] tile_end = {2{t_layer_end}} & t_layer[1:0];
|
||||
wire t_layer_end = tx == num_tiles;
|
||||
wire t_layer_start = start || t_layer_end;
|
||||
|
||||
reg [1:0] t_layer;
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
t_layer <= t0_en ? 2'b01 : 2'b10;
|
||||
else if (t_layer_end)
|
||||
t_layer <= {t_layer[0], 1'b0};
|
||||
|
||||
// TMBUF control
|
||||
// condition write to tx write to tm_valid
|
||||
// t_layer_start 0 TM_PRE_VALID
|
||||
// tm_pre_valid tx+1 TM_VALID
|
||||
// tile_skip tx+1 -
|
||||
// tile_go tx+1 TM_VALID
|
||||
// tile_wait tx-1 TM_PRE_VALID
|
||||
|
||||
localparam TM_PRE_VALID = 2'b01;
|
||||
localparam TM_VALID = 2'b10;
|
||||
|
||||
wire tile_go = tile_good && tsr_allowed;
|
||||
wire tile_wait = tile_good && !tsr_allowed;
|
||||
wire tile_good = tm_valid && tile_valid;
|
||||
wire tile_skip = tm_valid && !tile_valid;
|
||||
wire tsr_allowed = tiles && tsr_rdy;
|
||||
wire tile_valid = |t_tnum || (t_sel ? t0z_en : t1z_en);
|
||||
|
||||
wire tm_pre_valid = tm_valid_r[0];
|
||||
wire tm_valid = tm_valid_r[1];
|
||||
|
||||
reg [1:0] tm_valid_r;
|
||||
always @(posedge clk)
|
||||
if (t_layer_start || tile_wait)
|
||||
tm_valid_r <= TM_PRE_VALID;
|
||||
else if (tm_pre_valid || tile_go)
|
||||
tm_valid_r <= TM_VALID;
|
||||
|
||||
reg [5:0] tx;
|
||||
always @(posedge clk)
|
||||
if (t_layer_start)
|
||||
tx <= 6'd0;
|
||||
else if (tm_pre_valid || tile_skip || tile_go)
|
||||
tx <= tx + 6'd1;
|
||||
else if (tile_wait)
|
||||
tx <= tx - 6'd1;
|
||||
|
||||
// tile Y geometry
|
||||
wire [4:0] t_line = line[4:0] + ty_offs;
|
||||
|
||||
|
||||
// --- Sprites ---
|
||||
|
||||
// sprite descriptor fields
|
||||
// R0
|
||||
wire [8:0] s_ycrd = sfile_rdata[8:0];
|
||||
wire [2:0] s_ysz = sfile_rdata[11:9];
|
||||
wire s_act = sfile_rdata[13];
|
||||
wire s_leap = sfile_rdata[14];
|
||||
wire s_yflp = sfile_rdata[15];
|
||||
// R1
|
||||
wire [8:0] s_xcrd = sfile_rdata[8:0];
|
||||
wire [2:0] s_xsz = sfile_rdata[11:9];
|
||||
wire s_xflp = sfile_rdata[15];
|
||||
// R2
|
||||
wire [11:0] s_tnum = sfile_rdata[11:0];
|
||||
wire [3:0] s_pal = sfile_rdata[15:12];
|
||||
|
||||
// TSR control
|
||||
reg [8:0] sprites_x;
|
||||
reg [2:0] sprites_xs;
|
||||
reg sprites_xf;
|
||||
wire [5:0] sprites_addr = s_tnum[5:0];
|
||||
|
||||
// internal layers control
|
||||
wire [2:0] spr_end = ({3{s_layer_end}} & s_layer[2:0]) | {3{sprites_last}};
|
||||
wire s_layer_end = (sr0_valid && !spr_valid && s_leap) || (sprite_go && s_leap_r);
|
||||
wire sprites_last = sr0_valid && sprites_last_r;
|
||||
|
||||
reg sprites_last_r;
|
||||
always @(posedge clk) sprites_last_r <= sreg == 8'd255;
|
||||
|
||||
|
||||
reg [2:0] s_layer;
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
s_layer <= 3'b1;
|
||||
else if (s_layer_end)
|
||||
s_layer <= {s_layer[1:0], 1'b0};
|
||||
|
||||
// SFile registers control
|
||||
// condition write to sreg write to sr_valid action
|
||||
// start 0 SR0_PRE_VALID Start
|
||||
// sr0_pre_valid sreg+3 SR0_VALID SR0 pre-read
|
||||
// sr0_valid && !spr_valid sreg+3 - Skip sprite
|
||||
// sr0_valid && spr_valid sreg-2 SR1_PRE_VALID SR1 pre-read
|
||||
// sr1_pre_valid sreg+1 SR1_VALID SR1 read
|
||||
// sr1_valid sreg+1 SR2_VALID SR2 pre-read
|
||||
// sr2_valid && !tsr_rdy - - Wait for TSR ready
|
||||
// sr2_valid && tsr_rdy sreg+1 SR0_PRE_VALID Next sprite
|
||||
// sprites_last - NONE_VALID End
|
||||
|
||||
localparam NONE_VALID = 5'b00000;
|
||||
localparam SR0_PRE_VALID = 5'b00001;
|
||||
localparam SR0_VALID = 5'b00010;
|
||||
localparam SR1_PRE_VALID = 5'b00100;
|
||||
localparam SR1_VALID = 5'b01000;
|
||||
localparam SR2_VALID = 5'b10000;
|
||||
|
||||
wire sprite_go = sr2_valid && sprites && tsr_rdy; // kick to renderer
|
||||
wire spr_valid = s_visible && s_act;
|
||||
|
||||
wire sr0_pre_valid = sr_valid[0];
|
||||
wire sr0_valid = sr_valid[1];
|
||||
wire sr1_pre_valid = sr_valid[2];
|
||||
wire sr1_valid = sr_valid[3];
|
||||
wire sr2_valid = sr_valid[4];
|
||||
|
||||
reg [4:0] sr_valid;
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
sr_valid <= SR0_PRE_VALID;
|
||||
else if (sprites_last)
|
||||
sr_valid <= NONE_VALID;
|
||||
else if (sr0_pre_valid)
|
||||
sr_valid <= SR0_VALID;
|
||||
else if (sr0_valid && spr_valid)
|
||||
sr_valid <= SR1_PRE_VALID;
|
||||
else if (sr1_pre_valid)
|
||||
sr_valid <= SR1_VALID;
|
||||
else if (sr1_valid)
|
||||
sr_valid <= SR2_VALID;
|
||||
else if (sprite_go)
|
||||
sr_valid <= SR0_PRE_VALID;
|
||||
|
||||
reg [7:0] sreg;
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
sreg <= 8'd0;
|
||||
else if (sr0_pre_valid)
|
||||
sreg <= sreg + 8'd3;
|
||||
else if (sr0_valid)
|
||||
sreg <= spr_valid ? (sreg - 8'd2) : (sreg + 8'd3);
|
||||
else if (sr1_pre_valid || sprite_go)
|
||||
sreg <= sreg + 8'd1;
|
||||
|
||||
// SFile control
|
||||
reg [5:0] s_bmline_offset_r;
|
||||
reg s_leap_r;
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (sr0_valid)
|
||||
begin
|
||||
s_leap_r <= s_leap;
|
||||
s_bmline_offset_r <= s_bmline_offset;
|
||||
end
|
||||
|
||||
if (sr1_valid)
|
||||
begin
|
||||
sprites_x <= s_xcrd;
|
||||
sprites_xs <= s_xsz;
|
||||
sprites_xf <= s_xflp;
|
||||
end
|
||||
end
|
||||
|
||||
// sprite Y geometry
|
||||
wire [8:0] s_line = line - s_ycrd; // visible line of sprite in current video line
|
||||
wire s_visible = (s_line <= s_ymax); // check if sprite line is within Y size
|
||||
wire [5:0] s_ymax = {s_ysz, 3'b111};
|
||||
|
||||
wire [8:0] sprites_line = {s_tnum[11:6], 3'b0} + s_bmline_offset_r;
|
||||
wire [5:0] s_bmline_offset = s_yflp ? (s_ymax - s_line[5:0]) : s_line[5:0];
|
||||
|
||||
|
||||
// SFile
|
||||
wire [15:0] sfile_rdata;
|
||||
dpram #(.DATAWIDTH(16), .ADDRWIDTH(8)) video_sfile
|
||||
`include "tune.v"
|
||||
|
||||
// This is the Tile Sprite Processing Unit
|
||||
|
||||
// Tiles map address:
|
||||
// bits desc
|
||||
// 20:13 tmpage
|
||||
// 12:
|
||||
|
||||
// Graphics address:
|
||||
// bits desc
|
||||
// 20:13 Xgpage
|
||||
// 15:7 line (bits 15:13 are added) - 512 lines
|
||||
// 6:0 word within line - 128 words = 512 pixels
|
||||
|
||||
|
||||
module video_ts
|
||||
(
|
||||
.clock (clk),
|
||||
.address_a (sfile_addr_in),
|
||||
.data_a (sfile_data_in),
|
||||
.wren_a (sfile_we),
|
||||
.address_b (sreg),
|
||||
.q_b (sfile_rdata)
|
||||
);
|
||||
|
||||
// 4 buffers * 2 tile-planes * 64 tiles * 16 bits (9x16) - used to prefetch tiles
|
||||
// (2 altdprams)
|
||||
wire [15:0] tmb_rdata;
|
||||
dpram #(.DATAWIDTH(16), .ADDRWIDTH(9)) video_tmbuf
|
||||
(
|
||||
.clock (clk),
|
||||
.address_a (tmb_waddr),
|
||||
.data_a (dram_rdata),
|
||||
.wren_a (tm_next),
|
||||
.address_b (tmb_raddr),
|
||||
.q_b (tmb_rdata)
|
||||
// clocks
|
||||
input wire clk,
|
||||
|
||||
// video controls
|
||||
input wire start,
|
||||
input wire [8:0] line, // = vcount - vpix_beg + 9'b1;
|
||||
input wire v_ts,
|
||||
input wire v_pf, // vertical tilemap prefetch window
|
||||
|
||||
// video config
|
||||
input wire [7:0] tsconf,
|
||||
input wire [7:0] t0gpage,
|
||||
input wire [7:0] t1gpage,
|
||||
input wire [7:0] sgpage,
|
||||
input wire [7:0] tmpage,
|
||||
input wire [5:0] num_tiles,
|
||||
input wire [8:0] t0x_offs,
|
||||
input wire [8:0] t1x_offs,
|
||||
input wire [8:0] t0y_offs,
|
||||
input wire [8:0] t1y_offs,
|
||||
input wire [1:0] t0_palsel,
|
||||
input wire [1:0] t1_palsel,
|
||||
|
||||
// SFYS interface
|
||||
input wire [7:0] sfile_addr_in,
|
||||
input wire [15:0] sfile_data_in,
|
||||
input wire sfile_we,
|
||||
|
||||
// renderer interface
|
||||
output wire tsr_go,
|
||||
output wire [5:0] tsr_addr, // graphics address within the line
|
||||
output wire [8:0] tsr_line, // bitmap line
|
||||
output wire [7:0] tsr_page, // bitmap 1st page
|
||||
output wire [8:0] tsr_x, // addr in buffer (0-359 visibles)
|
||||
output wire [2:0] tsr_xs, // size (8-64 pix)
|
||||
output wire tsr_xf, // X flip
|
||||
output wire [3:0] tsr_pal, // palette
|
||||
input wire tsr_rdy, // renderer is done and ready to receive a new task
|
||||
|
||||
// DRAM interface
|
||||
output wire [20:0] dram_addr,
|
||||
output wire dram_req,
|
||||
input wire dram_next,
|
||||
input wire [15:0] dram_rdata
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
// config
|
||||
wire s_en = tsconf[7];
|
||||
wire t1_en = tsconf[6];
|
||||
wire t0_en = tsconf[5];
|
||||
wire t1z_en = tsconf[3];
|
||||
wire t0z_en = tsconf[2];
|
||||
|
||||
// tile descriptor fields
|
||||
wire [15:0] tmb_rdata;
|
||||
|
||||
wire [11:0] t_tnum = tmb_rdata[11:0];
|
||||
wire [1:0] t_pal = tmb_rdata[13:12];
|
||||
wire t_xflp = tmb_rdata[14];
|
||||
wire t_yflp = tmb_rdata[15];
|
||||
|
||||
// Layer selectors control
|
||||
localparam LAYERS = 6; // total number of layers to process
|
||||
|
||||
localparam TM = 0; // Individual layers
|
||||
localparam S0 = 1;
|
||||
localparam T0 = 2;
|
||||
localparam S1 = 3;
|
||||
localparam T1 = 4;
|
||||
localparam S2 = 5;
|
||||
|
||||
reg [LAYERS-1:0] layer_active;
|
||||
reg [LAYERS-1:0] layer_skip;
|
||||
|
||||
wire tmap = layer_active[TM];
|
||||
wire sprites = layer_active[S0] || layer_active[S1] || layer_active[S2];
|
||||
wire tiles = layer_active[T0] || layer_active[T1];
|
||||
|
||||
reg [LAYERS-1:0] layer;
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
layer <= 1;
|
||||
else if (|(layer & layer_skip))
|
||||
layer <= {layer[LAYERS-2:0], 1'b0};
|
||||
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
layer_active <= 0;
|
||||
else
|
||||
layer_active <= layer & ~layer_skip;
|
||||
|
||||
wire [2:0] spr_end;
|
||||
wire [1:0] tile_end;
|
||||
wire tm_end;
|
||||
wire [LAYERS-1:0] layer_enabled = {s_en, t1_en, s_en, t0_en, s_en, t1_en || t0_en};
|
||||
wire [LAYERS-1:0] layer_allowed = {{5{v_ts}}, v_pf};
|
||||
wire [LAYERS-1:0] layer_end = {spr_end[2], tile_end[1], spr_end[1], tile_end[0], spr_end[0], tm_end};
|
||||
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
layer_skip <= ~(layer_enabled & layer_allowed);
|
||||
else
|
||||
layer_skip <= layer_skip | layer_end;
|
||||
|
||||
// --- Tile map prefetch ---
|
||||
// TMB control
|
||||
reg [4:0] tm_x;
|
||||
|
||||
wire [8:0] tm_line = line + 9'd16;
|
||||
wire [2:0] tm_b_line = tm_line[2:0];
|
||||
wire [2:0] tm_num = tm_x[2:0];
|
||||
wire tm_layer = tm_x[3];
|
||||
wire [8:0] tmb_waddr = {tm_line[4:3], tm_b_line, tm_num, tm_layer}; // 8:7 - buffer #, 6:4 - burst number (of 8 bursts), 3:1 - number in burst (8 tiles per burst), 0 - layer
|
||||
wire [5:0] tm_b_row = tm_line[8:3] + (tm_layer ? t1y_offs[8:3] : t0y_offs[8:3]);
|
||||
|
||||
// DRAM controls
|
||||
assign dram_addr = {tmpage, tm_b_row, tm_layer, tm_b_line, tm_num}; // 20:13 - page, 12:7 - row, 6 - layer, 5:0 - column (burst number : number in burst)
|
||||
assign dram_req = tmap;
|
||||
|
||||
// internal layers control
|
||||
assign tm_end = tm_x == (t1_en ? 5'd16 : 5'd8);
|
||||
wire tm_next = dram_next && tmap;
|
||||
|
||||
reg [1:0] m_layer;
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
m_layer <= 2'b1;
|
||||
else if (tm_end)
|
||||
m_layer <= {m_layer[0], 1'b0};
|
||||
|
||||
// tilemap X coordinate
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
tm_x <= t0_en ? 5'd0 : 5'd8;
|
||||
else if (tm_next)
|
||||
tm_x <= tm_x + 5'd1;
|
||||
|
||||
// --- Tiles ---
|
||||
// layer parameter selectors
|
||||
reg [1:0] t_layer;
|
||||
reg [5:0] tx;
|
||||
|
||||
wire t_sel = t_layer[0];
|
||||
wire [8:0] tx_offs = t_sel ? t0x_offs : t1x_offs;
|
||||
wire [3:0] ty_offs = t_sel ? t0y_offs[2:0] : t1y_offs[2:0];
|
||||
|
||||
// TSR control
|
||||
wire [4:0] t_line;
|
||||
wire [7:0] tile_page = t_sel ? t0gpage : t1gpage;
|
||||
wire [8:0] tile_line = {t_tnum[11:6], (t_line[2:0] ^ {3{t_yflp}})};
|
||||
wire [5:0] tile_addr = t_tnum[5:0];
|
||||
wire [8:0] tile_x = {(tx - 6'd1), 3'd0} - tx_offs[2:0];
|
||||
wire [3:0] tile_pal = {t_sel ? t0_palsel : t1_palsel, t_pal};
|
||||
|
||||
// TMB control
|
||||
wire [8:0] tmb_raddr = {t_line[4:3], tx + tx_offs[8:3], ~t_sel};
|
||||
|
||||
// internal layers control
|
||||
wire t_layer_end = tx == num_tiles;
|
||||
wire t_layer_start = start || t_layer_end;
|
||||
assign tile_end = {2{t_layer_end}} & t_layer[1:0];
|
||||
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
t_layer <= t0_en ? 2'b01 : 2'b10;
|
||||
else if (t_layer_end)
|
||||
t_layer <= {t_layer[0], 1'b0};
|
||||
|
||||
// TMBUF control
|
||||
// condition write to tx write to tm_valid
|
||||
// t_layer_start 0 TM_PRE_VALID
|
||||
// tm_pre_valid tx+1 TM_VALID
|
||||
// tile_skip tx+1 -
|
||||
// tile_go tx+1 TM_VALID
|
||||
// tile_wait tx-1 TM_PRE_VALID
|
||||
|
||||
localparam TM_PRE_VALID = 2'b01;
|
||||
localparam TM_VALID = 2'b10;
|
||||
|
||||
reg [1:0] tm_valid_r;
|
||||
wire tm_valid = tm_valid_r[1];
|
||||
wire tm_pre_valid = tm_valid_r[0];
|
||||
|
||||
wire tile_valid = |t_tnum || (t_sel ? t0z_en : t1z_en);
|
||||
wire tsr_allowed = tiles && tsr_rdy;
|
||||
wire tile_good = tm_valid && tile_valid;
|
||||
wire tile_wait = tile_good && !tsr_allowed;
|
||||
wire tile_skip = tm_valid && !tile_valid;
|
||||
wire tile_go = tile_good && tsr_allowed;
|
||||
|
||||
always @(posedge clk)
|
||||
if (t_layer_start || tile_wait)
|
||||
tm_valid_r <= TM_PRE_VALID;
|
||||
else if (tm_pre_valid || tile_go)
|
||||
tm_valid_r <= TM_VALID;
|
||||
|
||||
always @(posedge clk)
|
||||
if (t_layer_start)
|
||||
tx <= 6'd0;
|
||||
else if (tm_pre_valid || tile_skip || tile_go)
|
||||
tx <= tx + 6'd1;
|
||||
else if (tile_wait)
|
||||
tx <= tx - 6'd1;
|
||||
|
||||
// tile Y geometry
|
||||
assign t_line = line[4:0] + ty_offs;
|
||||
|
||||
// --- Sprites ---
|
||||
// sprite descriptor fields
|
||||
// R0
|
||||
wire [15:0] sfile_rdata;
|
||||
|
||||
wire [8:0] s_ycrd = sfile_rdata[8:0];
|
||||
wire [2:0] s_ysz = sfile_rdata[11:9];
|
||||
wire s_act = sfile_rdata[13];
|
||||
wire s_leap = sfile_rdata[14];
|
||||
wire s_yflp = sfile_rdata[15];
|
||||
// R1
|
||||
wire [8:0] s_xcrd = sfile_rdata[8:0];
|
||||
wire [2:0] s_xsz = sfile_rdata[11:9];
|
||||
wire s_xflp = sfile_rdata[15];
|
||||
// R2
|
||||
wire [11:0] s_tnum = sfile_rdata[11:0];
|
||||
wire [3:0] s_pal = sfile_rdata[15:12];
|
||||
|
||||
// TSR control
|
||||
wire [5:0] sprites_addr = s_tnum[5:0];
|
||||
|
||||
// internal layers control
|
||||
reg sprites_last_r;
|
||||
reg [2:0] s_layer;
|
||||
reg [7:0] sreg;
|
||||
reg [4:0] sr_valid;
|
||||
reg s_leap_r;
|
||||
|
||||
wire sr0_pre_valid = sr_valid[0];
|
||||
wire sr0_valid = sr_valid[1];
|
||||
wire sr1_pre_valid = sr_valid[2];
|
||||
wire sr1_valid = sr_valid[3];
|
||||
wire sr2_valid = sr_valid[4];
|
||||
|
||||
wire sprite_go;
|
||||
wire s_visible;
|
||||
wire spr_valid = s_visible && s_act;
|
||||
wire s_layer_end = (sr0_valid && !spr_valid && s_leap) || (sprite_go && s_leap_r);
|
||||
wire sprites_last = sr0_valid && sprites_last_r;
|
||||
assign spr_end = ({3{s_layer_end}} & s_layer[2:0]) | {3{sprites_last}};
|
||||
|
||||
always @(posedge clk)
|
||||
sprites_last_r <= sreg == 8'd255;
|
||||
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
s_layer <= 3'b1;
|
||||
else if (s_layer_end)
|
||||
s_layer <= {s_layer[1:0], 1'b0};
|
||||
|
||||
// SFile registers control
|
||||
// condition write to sreg write to sr_valid action
|
||||
// start 0 SR0_PRE_VALID Start
|
||||
// sr0_pre_valid sreg+3 SR0_VALID SR0 pre-read
|
||||
// sr0_valid && !spr_valid sreg+3 - Skip sprite
|
||||
// sr0_valid && spr_valid sreg-2 SR1_PRE_VALID SR1 pre-read
|
||||
// sr1_pre_valid sreg+1 SR1_VALID SR1 read
|
||||
// sr1_valid sreg+1 SR2_VALID SR2 pre-read
|
||||
// sr2_valid && !tsr_rdy - - Wait for TSR ready
|
||||
// sr2_valid && tsr_rdy sreg+1 SR0_PRE_VALID Next sprite
|
||||
// sprites_last - NONE_VALID End
|
||||
|
||||
localparam NONE_VALID = 5'b00000;
|
||||
localparam SR0_PRE_VALID = 5'b00001;
|
||||
localparam SR0_VALID = 5'b00010;
|
||||
localparam SR1_PRE_VALID = 5'b00100;
|
||||
localparam SR1_VALID = 5'b01000;
|
||||
localparam SR2_VALID = 5'b10000;
|
||||
|
||||
assign sprite_go = sr2_valid && sprites && tsr_rdy; // a kick to renderer
|
||||
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
sr_valid <= SR0_PRE_VALID;
|
||||
else if (sprites_last)
|
||||
sr_valid <= NONE_VALID;
|
||||
else if (sr0_pre_valid)
|
||||
sr_valid <= SR0_VALID;
|
||||
else if (sr0_valid && spr_valid)
|
||||
sr_valid <= SR1_PRE_VALID;
|
||||
else if (sr1_pre_valid)
|
||||
sr_valid <= SR1_VALID;
|
||||
else if (sr1_valid)
|
||||
sr_valid <= SR2_VALID;
|
||||
else if (sprite_go)
|
||||
sr_valid <= SR0_PRE_VALID;
|
||||
|
||||
always @(posedge clk)
|
||||
if (start)
|
||||
sreg <= 8'd0;
|
||||
else if (sr0_pre_valid)
|
||||
sreg <= sreg + 8'd3;
|
||||
else if (sr0_valid)
|
||||
sreg <= spr_valid ? (sreg - 8'd2) : (sreg + 8'd3);
|
||||
else if (sr1_pre_valid || sprite_go)
|
||||
sreg <= sreg + 8'd1;
|
||||
|
||||
// sprite Y geometry
|
||||
reg [5:0] s_bmline_offset_r;
|
||||
|
||||
wire [8:0] s_line = line - s_ycrd; // visible line of sprite in current video line
|
||||
wire [5:0] s_ymax = {s_ysz, 3'b111};
|
||||
assign s_visible = (s_line <= s_ymax); // check if sprite line is within Y size
|
||||
|
||||
wire [8:0] sprites_line = {s_tnum[11:6], 3'b0} + s_bmline_offset_r;
|
||||
wire [5:0] s_bmline_offset = s_yflp ? (s_ymax - s_line[5:0]) : s_line[5:0];
|
||||
|
||||
// SFile control
|
||||
reg [8:0] sprites_x;
|
||||
reg [2:0] sprites_xs;
|
||||
reg sprites_xf;
|
||||
|
||||
always @(posedge clk)
|
||||
begin
|
||||
if (sr0_valid)
|
||||
begin
|
||||
s_leap_r <= s_leap;
|
||||
s_bmline_offset_r <= s_bmline_offset;
|
||||
end
|
||||
|
||||
if (sr1_valid)
|
||||
begin
|
||||
sprites_x <= s_xcrd;
|
||||
sprites_xs <= s_xsz;
|
||||
sprites_xf <= s_xflp;
|
||||
end
|
||||
end
|
||||
|
||||
// SFile
|
||||
dpram #(.DATAWIDTH(16), .ADDRWIDTH(8)) video_sfile
|
||||
(
|
||||
.clock (clk),
|
||||
.address_a (sfile_addr_in),
|
||||
.data_a (sfile_data_in),
|
||||
.wren_a (sfile_we),
|
||||
.address_b (sreg),
|
||||
.q_b (sfile_rdata)
|
||||
);
|
||||
/*
|
||||
altdpram video_sfile
|
||||
(
|
||||
.outclock (clk),
|
||||
.wren (sfile_we),
|
||||
.inclock (clk),
|
||||
.data (sfile_data_in),
|
||||
.rdaddress (sreg),
|
||||
.wraddress (sfile_addr_in),
|
||||
.q (sfile_rdata),
|
||||
.aclr (1'b0),
|
||||
.byteena (1'b1),
|
||||
.inclocken (1'b1),
|
||||
.outclocken (1'b1),
|
||||
.rdaddressstall (1'b0),
|
||||
.rden (1'b1),
|
||||
.wraddressstall (1'b0)
|
||||
);
|
||||
|
||||
defparam
|
||||
video_sfile.indata_aclr = "OFF",
|
||||
video_sfile.indata_reg = "INCLOCK",
|
||||
video_sfile.intended_device_family = "ACEX1K",
|
||||
video_sfile.lpm_type = "altdpram",
|
||||
video_sfile.outdata_aclr = "OFF",
|
||||
video_sfile.outdata_reg = "OUTCLOCK",
|
||||
video_sfile.rdaddress_aclr = "OFF",
|
||||
video_sfile.rdaddress_reg = "UNREGISTERED",
|
||||
video_sfile.rdcontrol_aclr = "OFF",
|
||||
video_sfile.rdcontrol_reg = "UNREGISTERED",
|
||||
video_sfile.width = 16,
|
||||
video_sfile.widthad = 8,
|
||||
video_sfile.wraddress_aclr = "OFF",
|
||||
video_sfile.wraddress_reg = "INCLOCK",
|
||||
video_sfile.wrcontrol_aclr = "OFF",
|
||||
video_sfile.wrcontrol_reg = "INCLOCK";
|
||||
*/
|
||||
// 4 buffers * 2 tile-planes * 64 tiles * 16 bits (9x16) - used to prefetch tiles
|
||||
// (2 altdprams)
|
||||
dpram #(.DATAWIDTH(16), .ADDRWIDTH(9)) video_tmbuf
|
||||
(
|
||||
.clock (clk),
|
||||
.address_a (tmb_waddr),
|
||||
.data_a (dram_rdata),
|
||||
.wren_a (tm_next),
|
||||
.address_b (tmb_raddr),
|
||||
.q_b (tmb_rdata)
|
||||
);
|
||||
/*
|
||||
altdpram video_tmbuf
|
||||
(
|
||||
.outclock (clk),
|
||||
.wren (tm_next),
|
||||
.inclock (clk),
|
||||
.data (dram_rdata),
|
||||
.rdaddress (tmb_raddr),
|
||||
.wraddress (tmb_waddr),
|
||||
.q (tmb_rdata),
|
||||
.aclr (1'b0),
|
||||
.byteena (1'b1),
|
||||
.inclocken (1'b1),
|
||||
.outclocken (1'b1),
|
||||
.rdaddressstall (1'b0),
|
||||
.rden (1'b1),
|
||||
.wraddressstall (1'b0)
|
||||
);
|
||||
|
||||
defparam
|
||||
video_tmbuf.indata_aclr = "OFF",
|
||||
video_tmbuf.indata_reg = "INCLOCK",
|
||||
video_tmbuf.intended_device_family = "ACEX1K",
|
||||
video_tmbuf.lpm_type = "altdpram",
|
||||
video_tmbuf.outdata_aclr = "OFF",
|
||||
video_tmbuf.outdata_reg = "OUTCLOCK",
|
||||
video_tmbuf.rdaddress_aclr = "OFF",
|
||||
video_tmbuf.rdaddress_reg = "UNREGISTERED",
|
||||
video_tmbuf.rdcontrol_aclr = "OFF",
|
||||
video_tmbuf.rdcontrol_reg = "UNREGISTERED",
|
||||
video_tmbuf.width = 16,
|
||||
video_tmbuf.widthad = 9,
|
||||
video_tmbuf.wraddress_aclr = "OFF",
|
||||
video_tmbuf.wraddress_reg = "INCLOCK",
|
||||
video_tmbuf.wrcontrol_aclr = "OFF",
|
||||
video_tmbuf.wrcontrol_reg = "INCLOCK";
|
||||
*/
|
||||
// TS renderer interface
|
||||
assign tsr_go = sprite_go || tile_go;
|
||||
assign tsr_x = sprites ? sprites_x : tile_x;
|
||||
assign tsr_xs = sprites ? sprites_xs : 3'd0;
|
||||
assign tsr_xf = sprites ? sprites_xf : t_xflp;
|
||||
assign tsr_page = sprites ? sgpage : tile_page;
|
||||
assign tsr_line = sprites ? sprites_line : tile_line;
|
||||
assign tsr_addr = sprites ? sprites_addr : tile_addr;
|
||||
assign tsr_pal = sprites ? s_pal : tile_pal;
|
||||
|
||||
endmodule
|
||||
|
@ -1,150 +1,150 @@
|
||||
|
||||
// This module renders pixels into TS-line for tiles/sprites
|
||||
// Task execution is initiated by 'tsr_go' (one 'clk' period strobe).
|
||||
// Inputs (only valid by 'tsr_go'):
|
||||
// - DRAM address of graphics data (including page, line, word)
|
||||
// - number of cycles to render (one cycle is 2 words = 8 pixels; 8 cycles = 64 pixels max)
|
||||
// - X coordinate
|
||||
// - X flip bit
|
||||
// - palette selector
|
||||
// Address in TS-line is calculated from X coordinate respecting the X flip.
|
||||
// Inc/dec direction is set automatically.
|
||||
// At the 'c2' of last DRAM cycle 'mem_rdy' is asserted.
|
||||
// It should be used in comb to generate next cycle 'tsr_go' strobe for continuous renderer operation.
|
||||
// First 'tsr_go' may be issued at any DRAM cycle, but the operation starts only
|
||||
// after TS request recognized and processed by DRAM controller.
|
||||
// It is recommended to assert 'tsr_go' at 'c2'.
|
||||
|
||||
`include "tune.v"
|
||||
|
||||
// This module renders pixels into TS-line for tiles/sprites
|
||||
// Task execution is initiated by 'tsr_go' (one 'clk' period strobe).
|
||||
// Inputs (only valid by 'tsr_go'):
|
||||
// - DRAM address of graphics data (including page, line, word)
|
||||
// - number of cycles to render (one cycle is 2 words = 8 pixels; 8 cycles = 64 pixels max)
|
||||
// - X coordinate
|
||||
// - X flip bit
|
||||
// - palette selector
|
||||
// Address in TS-line is calculated from X coordinate respecting the X flip.
|
||||
// Inc/dec direction is set automatically.
|
||||
// At the 'c2' of last DRAM cycle 'mem_rdy' is asserted.
|
||||
// It should be used in comb to generate next cycle 'tsr_go' strobe for continuous renderer operation.
|
||||
// First 'tsr_go' may be issued at any DRAM cycle, but the operation starts only
|
||||
// after TS request recognized and processed by DRAM controller.
|
||||
// It is recommended to assert 'tsr_go' at 'c2'.
|
||||
|
||||
module video_ts_render
|
||||
(
|
||||
// clocks
|
||||
input wire clk,
|
||||
|
||||
// controls
|
||||
input wire reset, // line start strobe, inits the machine
|
||||
|
||||
input wire [ 8:0] x_coord, // address in TS-line where render to, auto-flipped to match 'flip' times 'x_size'
|
||||
input wire [ 2:0] x_size, // number of rendering cycles (each cycle is 8 pixels, 0 = 1 cycle)
|
||||
input wire flip, // indicates that sprite is X-flipped
|
||||
|
||||
input wire tsr_go, // 1 clk 28MHz strobe for render start. Should be issued along with 'mem_rdy' for continuous process
|
||||
input wire [ 5:0] addr, // address of dword within the line (dword = 8 pix)
|
||||
input wire [ 8:0] line, // line of bitmap
|
||||
input wire [ 7:0] page, // 1st page of bitmap (TxGpage or SGpage)
|
||||
input wire [ 3:0] pal, // palette selector, bits[7:4] of CRAM address
|
||||
output wire mem_rdy, // ready to receive new task
|
||||
|
||||
// TS-Line interface
|
||||
output reg [ 8:0] ts_waddr,
|
||||
output wire [ 7:0] ts_wdata,
|
||||
output wire ts_we,
|
||||
|
||||
// DRAM interface
|
||||
output wire [20:0] dram_addr,
|
||||
output wire dram_req,
|
||||
input wire [15:0] dram_rdata,
|
||||
input wire dram_pre_next,
|
||||
input wire dram_next
|
||||
);
|
||||
|
||||
|
||||
// DRAM request
|
||||
assign dram_req = tsr_go || !mem_rdy;
|
||||
|
||||
|
||||
// DRAM addressing
|
||||
assign dram_addr = tsr_go ? addr_in : addr_next;
|
||||
wire [20:0] addr_in = {addr_offset, addr, 1'b0};
|
||||
wire [13:0] addr_offset = {page[7:3], line};
|
||||
wire [20:0] addr_next = {addr_reg[20:7], addr_reg[6:0] + dram_next};
|
||||
// as renderer can't move outside the single bitmap line, only 7 bits are processed
|
||||
|
||||
reg [20:0] addr_reg;
|
||||
always @(posedge clk) addr_reg <= dram_addr;
|
||||
|
||||
|
||||
// DRAM cycles counter
|
||||
assign mem_rdy = cyc[4];
|
||||
|
||||
reg [4:0] cyc;
|
||||
always @(posedge clk)
|
||||
if (reset)
|
||||
cyc <= 5'b10000;
|
||||
else if (tsr_go)
|
||||
cyc <= {1'b0, x_size, 1'b1};
|
||||
else if (dram_pre_next)
|
||||
cyc <= cyc - 5'd1;
|
||||
|
||||
|
||||
// DRAM data fetching
|
||||
reg [15:0] data;
|
||||
always @(posedge clk) if (dram_next) data <= dram_rdata;
|
||||
|
||||
|
||||
// pixel render counter
|
||||
assign ts_we = render_on && |pix; // write signal for TS-line
|
||||
wire render_on = !cnt[2];
|
||||
|
||||
reg [2:0] cnt;
|
||||
always @(posedge clk)
|
||||
if (reset)
|
||||
cnt <= 3'b100;
|
||||
else if (dram_next)
|
||||
cnt <= 3'b000;
|
||||
else if (render_on)
|
||||
cnt <= cnt + 3'd1;
|
||||
|
||||
|
||||
// renderer reload
|
||||
reg tsr_rld;
|
||||
always @(posedge clk)
|
||||
if (reset)
|
||||
tsr_rld <= 1'b0;
|
||||
else if (tsr_go)
|
||||
tsr_rld <= 1'b1;
|
||||
else if (dram_next)
|
||||
tsr_rld <= 1'b0;
|
||||
|
||||
|
||||
// delayed values
|
||||
reg [8:0] x_coord_d;
|
||||
reg [3:0] pal_d;
|
||||
reg flip_d;
|
||||
always @(posedge clk)
|
||||
if (tsr_go)
|
||||
begin
|
||||
x_coord_d <= x_coord + (flip ? {x_size, 3'b111} : 6'd0);
|
||||
pal_d <= pal;
|
||||
flip_d <= flip;
|
||||
end
|
||||
|
||||
|
||||
// TS-line address
|
||||
wire [8:0] ts_waddr_mx = tsr_rld_stb ? x_coord_d : (render_on ? x_next : ts_waddr);
|
||||
wire [8:0] x_next = ts_waddr + {{8{flip_r}}, 1'b1};
|
||||
wire tsr_rld_stb = tsr_rld && dram_next;
|
||||
|
||||
always @(posedge clk) ts_waddr <= ts_waddr_mx;
|
||||
|
||||
reg [3:0] pal_r;
|
||||
reg flip_r;
|
||||
always @(posedge clk)
|
||||
if (tsr_rld_stb)
|
||||
begin
|
||||
pal_r <= pal_d;
|
||||
flip_r <= flip_d;
|
||||
end
|
||||
|
||||
|
||||
// renderer mux
|
||||
assign ts_wdata = {pal_r, pix};
|
||||
wire [3:0] pix = pix_m[cnt[1:0]];
|
||||
|
||||
wire [3:0] pix_m[0:3];
|
||||
assign pix_m[0] = data[7:4];
|
||||
assign pix_m[1] = data[3:0];
|
||||
assign pix_m[2] = data[15:12];
|
||||
assign pix_m[3] = data[11:8];
|
||||
|
||||
|
||||
endmodule
|
||||
(
|
||||
// clocks
|
||||
input wire clk,
|
||||
|
||||
// controls
|
||||
input wire reset, // line start strobe, inits the machine
|
||||
|
||||
input wire [ 8:0] x_coord, // address in TS-line where render to, auto-flipped to match 'flip' times 'x_size'
|
||||
input wire [ 2:0] x_size, // number of rendering cycles (each cycle is 8 pixels, 0 = 1 cycle)
|
||||
input wire flip, // indicates that sprite is X-flipped
|
||||
|
||||
input wire tsr_go, // 1 clk 28MHz strobe for render start. Should be issued along with 'mem_rdy' for continuous process
|
||||
input wire [ 5:0] addr, // address of dword within the line (dword = 8 pix)
|
||||
input wire [ 8:0] line, // line of bitmap
|
||||
input wire [ 7:0] page, // 1st page of bitmap (TxGpage or SGpage)
|
||||
input wire [ 3:0] pal, // palette selector, bits[7:4] of CRAM address
|
||||
output wire mem_rdy, // ready to receive new task
|
||||
|
||||
// TS-Line interface
|
||||
output reg [ 8:0] ts_waddr,
|
||||
output wire [ 7:0] ts_wdata,
|
||||
output wire ts_we,
|
||||
|
||||
// DRAM interface
|
||||
output wire [20:0] dram_addr,
|
||||
output wire dram_req,
|
||||
input wire [15:0] dram_rdata,
|
||||
input wire dram_pre_next,
|
||||
input wire dram_next
|
||||
);
|
||||
|
||||
// renderer mux
|
||||
reg [15:0] data;
|
||||
reg [3:0] pal_r;
|
||||
reg [2:0] pix_cnt;
|
||||
|
||||
wire [3:0] pix_m[0:3];
|
||||
wire [3:0] pix = pix_m[pix_cnt[1:0]];
|
||||
assign ts_wdata = {pal_r, pix};
|
||||
|
||||
assign pix_m[0] = data[7:4];
|
||||
assign pix_m[1] = data[3:0];
|
||||
assign pix_m[2] = data[15:12];
|
||||
assign pix_m[3] = data[11:8];
|
||||
|
||||
// DRAM request
|
||||
assign dram_req = tsr_go || !mem_rdy;
|
||||
|
||||
// DRAM addressing
|
||||
reg [20:0] addr_reg;
|
||||
|
||||
wire [13:0] addr_offset = {page[7:3], line};
|
||||
wire [20:0] addr_in = {addr_offset, addr, 1'b0};
|
||||
wire [20:0] addr_next = {addr_reg[20:7], addr_reg[6:0] + dram_next};
|
||||
assign dram_addr = tsr_go ? addr_in : addr_next;
|
||||
|
||||
always @(posedge clk)
|
||||
addr_reg <= dram_addr;
|
||||
|
||||
// DRAM cycles counter
|
||||
reg [4:0] cyc;
|
||||
|
||||
assign mem_rdy = cyc[4];
|
||||
|
||||
always @(posedge clk or posedge reset)
|
||||
if (reset)
|
||||
cyc <= 5'b10000;
|
||||
else if (tsr_go)
|
||||
cyc <= {1'b0, x_size, 1'b1};
|
||||
else if (dram_pre_next)
|
||||
cyc <= cyc - 5'd1;
|
||||
|
||||
// DRAM data fetching
|
||||
always @(posedge clk)
|
||||
if (dram_next)
|
||||
data <= dram_rdata;
|
||||
|
||||
// pixel render counter
|
||||
wire render_on = !pix_cnt[2];
|
||||
assign ts_we = render_on && |pix; // write signal for TS-line
|
||||
|
||||
always @(posedge clk or posedge reset)
|
||||
if (reset)
|
||||
pix_cnt <= 3'b100;
|
||||
else if (dram_next)
|
||||
pix_cnt <= 3'b000;
|
||||
else if (render_on)
|
||||
pix_cnt <= pix_cnt + 3'd1;
|
||||
|
||||
// renderer reload
|
||||
reg tsr_rld;
|
||||
always @(posedge clk or posedge reset)
|
||||
if (reset)
|
||||
tsr_rld <= 1'b0;
|
||||
else if (tsr_go)
|
||||
tsr_rld <= 1'b1;
|
||||
else if (dram_next)
|
||||
tsr_rld <= 1'b0;
|
||||
|
||||
// delayed values
|
||||
reg [8:0] x_coord_d;
|
||||
reg [3:0] pal_d;
|
||||
reg flip_d;
|
||||
|
||||
always @(posedge clk)
|
||||
if (tsr_go)
|
||||
begin
|
||||
x_coord_d <= x_coord + (flip ? {x_size, 3'b111} : 6'd0);
|
||||
pal_d <= pal;
|
||||
flip_d <= flip;
|
||||
end
|
||||
|
||||
|
||||
// TS-line address
|
||||
reg flip_r;
|
||||
|
||||
wire [8:0] x_next = ts_waddr + {{8{flip_r}}, 1'b1};
|
||||
wire tsr_rld_stb = tsr_rld && dram_next;
|
||||
wire [8:0] ts_waddr_mx = tsr_rld_stb ? x_coord_d : (render_on ? x_next : ts_waddr);
|
||||
|
||||
always @(posedge clk)
|
||||
ts_waddr <= ts_waddr_mx;
|
||||
|
||||
always @(posedge clk)
|
||||
if (tsr_rld_stb)
|
||||
begin
|
||||
pal_r <= pal_d;
|
||||
flip_r <= flip_d;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
Reference in New Issue
Block a user