mirror of
https://github.com/UzixLS/TSConf_MiST.git
synced 2025-07-18 23:01:37 +03:00
Update sys. Re-organize the sources.
This commit is contained in:
280
rtl/video/video_cram.mif
Normal file
280
rtl/video/video_cram.mif
Normal file
@ -0,0 +1,280 @@
|
||||
-- Copyright (C) 1991-2007 Altera Corporation
|
||||
-- Your use of Altera Corporation's design tools, logic functions
|
||||
-- and other software and tools, and its AMPP partner logic
|
||||
-- functions, and any output files from any of the foregoing
|
||||
-- (including device programming or simulation files), and any
|
||||
-- associated documentation or information are expressly subject
|
||||
-- to the terms and conditions of the Altera Program License
|
||||
-- Subscription Agreement, Altera MegaCore Function License
|
||||
-- Agreement, or other applicable license agreement, including,
|
||||
-- without limitation, that your use is for the sole purpose of
|
||||
-- programming logic devices manufactured by Altera and sold by
|
||||
-- Altera or its authorized distributors. Please refer to the
|
||||
-- applicable agreement for further details.
|
||||
|
||||
-- Quartus II generated Memory Initialization File (.mif)
|
||||
|
||||
WIDTH=16;
|
||||
DEPTH=256;
|
||||
|
||||
ADDRESS_RADIX=HEX;
|
||||
DATA_RADIX=HEX;
|
||||
|
||||
CONTENT BEGIN
|
||||
000 : 0000;
|
||||
001 : 0008;
|
||||
002 : 0010;
|
||||
003 : 0018;
|
||||
004 : 2000;
|
||||
005 : 2008;
|
||||
006 : 2010;
|
||||
007 : 2018;
|
||||
008 : 4000;
|
||||
009 : 4008;
|
||||
00A : 4010;
|
||||
00B : 4018;
|
||||
00C : 6000;
|
||||
00D : 6008;
|
||||
00E : 6010;
|
||||
00F : 6018;
|
||||
010 : 0100;
|
||||
011 : 0108;
|
||||
012 : 0110;
|
||||
013 : 0118;
|
||||
014 : 2100;
|
||||
015 : 2108;
|
||||
016 : 2110;
|
||||
017 : 2118;
|
||||
018 : 4100;
|
||||
019 : 4108;
|
||||
01A : 4110;
|
||||
01B : 4118;
|
||||
01C : 6100;
|
||||
01D : 6108;
|
||||
01E : 6110;
|
||||
01F : 6118;
|
||||
020 : 0200;
|
||||
021 : 0208;
|
||||
022 : 0210;
|
||||
023 : 0218;
|
||||
024 : 2200;
|
||||
025 : 2208;
|
||||
026 : 2210;
|
||||
027 : 2218;
|
||||
028 : 4200;
|
||||
029 : 4208;
|
||||
02A : 4210;
|
||||
02B : 4218;
|
||||
02C : 6200;
|
||||
02D : 6208;
|
||||
02E : 6210;
|
||||
02F : 6218;
|
||||
030 : 0300;
|
||||
031 : 0308;
|
||||
032 : 0310;
|
||||
033 : 0318;
|
||||
034 : 2300;
|
||||
035 : 2308;
|
||||
036 : 2310;
|
||||
037 : 2318;
|
||||
038 : 4300;
|
||||
039 : 4308;
|
||||
03A : 4310;
|
||||
03B : 4318;
|
||||
03C : 6300;
|
||||
03D : 6308;
|
||||
03E : 6310;
|
||||
03F : 6318;
|
||||
040 : 0000;
|
||||
041 : 0010;
|
||||
042 : 4000;
|
||||
043 : 4010;
|
||||
044 : 0200;
|
||||
045 : 0210;
|
||||
046 : 4200;
|
||||
047 : 4210;
|
||||
048 : 2108;
|
||||
049 : 0018;
|
||||
04A : 6000;
|
||||
04B : 6018;
|
||||
04C : 0300;
|
||||
04D : 0318;
|
||||
04E : 6300;
|
||||
04F : 6318;
|
||||
050 : 0000;
|
||||
051 : 0010;
|
||||
052 : 4000;
|
||||
053 : 4010;
|
||||
054 : 0200;
|
||||
055 : 0210;
|
||||
056 : 4200;
|
||||
057 : 4210;
|
||||
058 : 0000;
|
||||
059 : 0018;
|
||||
05A : 6000;
|
||||
05B : 6018;
|
||||
05C : 0300;
|
||||
05D : 0318;
|
||||
05E : 6300;
|
||||
05F : 6318;
|
||||
060 : 0000;
|
||||
061 : 0010;
|
||||
062 : 4000;
|
||||
063 : 4010;
|
||||
064 : 0200;
|
||||
065 : 0210;
|
||||
066 : 4200;
|
||||
067 : 4210;
|
||||
068 : 2108;
|
||||
069 : 0018;
|
||||
06A : 6000;
|
||||
06B : 6018;
|
||||
06C : 0300;
|
||||
06D : 0318;
|
||||
06E : 6300;
|
||||
06F : 6318;
|
||||
070 : 0000;
|
||||
071 : 0010;
|
||||
072 : 4000;
|
||||
073 : 4010;
|
||||
074 : 0200;
|
||||
075 : 0210;
|
||||
076 : 4200;
|
||||
077 : 4210;
|
||||
078 : 0000;
|
||||
079 : 0018;
|
||||
07A : 6000;
|
||||
07B : 6018;
|
||||
07C : 0300;
|
||||
07D : 0318;
|
||||
07E : 6300;
|
||||
07F : 6318;
|
||||
080 : 0000;
|
||||
081 : 0010;
|
||||
082 : 4000;
|
||||
083 : 4010;
|
||||
084 : 0200;
|
||||
085 : 0210;
|
||||
086 : 4200;
|
||||
087 : 4210;
|
||||
088 : 2108;
|
||||
089 : 0018;
|
||||
08A : 6000;
|
||||
08B : 6018;
|
||||
08C : 0300;
|
||||
08D : 0318;
|
||||
08E : 6300;
|
||||
08F : 6318;
|
||||
090 : 0000;
|
||||
091 : 0010;
|
||||
092 : 4000;
|
||||
093 : 4010;
|
||||
094 : 0200;
|
||||
095 : 0210;
|
||||
096 : 4200;
|
||||
097 : 4210;
|
||||
098 : 0000;
|
||||
099 : 0018;
|
||||
09A : 6000;
|
||||
09B : 6018;
|
||||
09C : 0300;
|
||||
09D : 0318;
|
||||
09E : 6300;
|
||||
09F : 6318;
|
||||
0A0 : 0000;
|
||||
0A1 : 0010;
|
||||
0A2 : 4000;
|
||||
0A3 : 4010;
|
||||
0A4 : 0200;
|
||||
0A5 : 0210;
|
||||
0A6 : 4200;
|
||||
0A7 : 4210;
|
||||
0A8 : 2108;
|
||||
0A9 : 0018;
|
||||
0AA : 6000;
|
||||
0AB : 6018;
|
||||
0AC : 0300;
|
||||
0AD : 0318;
|
||||
0AE : 6300;
|
||||
0AF : 6318;
|
||||
0B0 : 0000;
|
||||
0B1 : 0010;
|
||||
0B2 : 4000;
|
||||
0B3 : 4010;
|
||||
0B4 : 0200;
|
||||
0B5 : 0210;
|
||||
0B6 : 4200;
|
||||
0B7 : 4210;
|
||||
0B8 : 0000;
|
||||
0B9 : 0018;
|
||||
0BA : 6000;
|
||||
0BB : 6018;
|
||||
0BC : 0300;
|
||||
0BD : 0318;
|
||||
0BE : 6300;
|
||||
0BF : 6318;
|
||||
0C0 : 0000;
|
||||
0C1 : 0010;
|
||||
0C2 : 4000;
|
||||
0C3 : 4010;
|
||||
0C4 : 0200;
|
||||
0C5 : 0210;
|
||||
0C6 : 4200;
|
||||
0C7 : 4210;
|
||||
0C8 : 2108;
|
||||
0C9 : 0018;
|
||||
0CA : 6000;
|
||||
0CB : 6018;
|
||||
0CC : 0300;
|
||||
0CD : 0318;
|
||||
0CE : 6300;
|
||||
0CF : 6318;
|
||||
0D0 : 0000;
|
||||
0D1 : 0010;
|
||||
0D2 : 4000;
|
||||
0D3 : 4010;
|
||||
0D4 : 0200;
|
||||
0D5 : 0210;
|
||||
0D6 : 4200;
|
||||
0D7 : 4210;
|
||||
0D8 : 0000;
|
||||
0D9 : 0018;
|
||||
0DA : 6000;
|
||||
0DB : 6018;
|
||||
0DC : 0300;
|
||||
0DD : 0318;
|
||||
0DE : 6300;
|
||||
0DF : 6318;
|
||||
0E0 : 0000;
|
||||
0E1 : 0010;
|
||||
0E2 : 4000;
|
||||
0E3 : 4010;
|
||||
0E4 : 0200;
|
||||
0E5 : 0210;
|
||||
0E6 : 4200;
|
||||
0E7 : 4210;
|
||||
0E8 : 2108;
|
||||
0E9 : 0018;
|
||||
0EA : 6000;
|
||||
0EB : 6018;
|
||||
0EC : 0300;
|
||||
0ED : 0318;
|
||||
0EE : 6300;
|
||||
0EF : 6318;
|
||||
0F0 : 0000;
|
||||
0F1 : 0010;
|
||||
0F2 : 4000;
|
||||
0F3 : 4010;
|
||||
0F4 : 0200;
|
||||
0F5 : 0210;
|
||||
0F6 : 4200;
|
||||
0F7 : 4210;
|
||||
0F8 : 0000;
|
||||
0F9 : 0018;
|
||||
0FA : 6000;
|
||||
0FB : 6018;
|
||||
0FC : 0300;
|
||||
0FD : 0318;
|
||||
0FE : 6300;
|
||||
0FF : 6318;
|
||||
END;
|
33
rtl/video/video_fetch.v
Normal file
33
rtl/video/video_fetch.v
Normal file
@ -0,0 +1,33 @@
|
||||
// This module fetches video data from DRAM
|
||||
|
||||
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;
|
||||
|
||||
endmodule
|
235
rtl/video/video_mode.v
Normal file
235
rtl/video/video_mode.v
Normal file
@ -0,0 +1,235 @@
|
||||
|
||||
// This module decodes video modes
|
||||
|
||||
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];
|
||||
|
||||
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];
|
||||
|
||||
// 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
|
60
rtl/video/video_out.v
Normal file
60
rtl/video/video_out.v
Normal file
@ -0,0 +1,60 @@
|
||||
|
||||
// This module generates video for DAC
|
||||
// (c)2015 TSL
|
||||
|
||||
module video_out
|
||||
(
|
||||
// clocks
|
||||
input wire clk, c3,
|
||||
|
||||
// video controls
|
||||
input wire tv_blank,
|
||||
input wire [1:0] plex_sel_in,
|
||||
|
||||
// mode controls
|
||||
input wire tv_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,
|
||||
|
||||
// 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
|
||||
);
|
||||
|
||||
|
||||
reg [7:0] vplex;
|
||||
always @(posedge clk) if (c3) vplex <= vplex_in;
|
||||
|
||||
wire [7:0] vdata = tv_hires ? {palsel, plex_sel_in[1] ? vplex[3:0] : vplex[7:4]} : vplex;
|
||||
|
||||
|
||||
// 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];
|
||||
|
||||
endmodule
|
149
rtl/video/video_ports.v
Normal file
149
rtl/video/video_ports.v
Normal file
@ -0,0 +1,149 @@
|
||||
// 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
|
||||
|
||||
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
|
84
rtl/video/video_render.v
Normal file
84
rtl/video/video_render.v
Normal file
@ -0,0 +1,84 @@
|
||||
// This module renders video data for output
|
||||
|
||||
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
|
||||
|
169
rtl/video/video_sync.v
Normal file
169
rtl/video/video_sync.v
Normal file
@ -0,0 +1,169 @@
|
||||
|
||||
// This module generates all 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);
|
||||
|
||||
assign hvtspix = htspix && vtspix;
|
||||
wire htspix = (hcount >= hpix_beg_ts) && (hcount < hpix_end_ts);
|
||||
wire vtspix = (vcount >= vpix_beg_ts) && (vcount < vpix_end_ts);
|
||||
|
||||
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
|
467
rtl/video/video_top.v
Normal file
467
rtl/video/video_top.v
Normal file
@ -0,0 +1,467 @@
|
||||
|
||||
// This module is a video top-level
|
||||
|
||||
|
||||
module video_top
|
||||
(
|
||||
// clocks
|
||||
input wire clk,
|
||||
input wire f0, f1,
|
||||
input wire h0, h1,
|
||||
input wire c0, c1, c2, c3,
|
||||
// input wire t0, // debug!!!
|
||||
|
||||
// video DAC
|
||||
output wire [7:0] vred,
|
||||
output wire [7:0] vgrn,
|
||||
output wire [7:0] vblu,
|
||||
output wire vdac_mode,
|
||||
|
||||
// video syncs
|
||||
output wire hsync,
|
||||
output wire vsync,
|
||||
output wire hblank,
|
||||
output wire vblank,
|
||||
output wire pix_stb,
|
||||
|
||||
// Z80 controls
|
||||
input wire [ 7:0] d,
|
||||
input wire [15:0] zmd,
|
||||
input wire [ 7:0] zma,
|
||||
input wire cram_we,
|
||||
input wire sfile_we,
|
||||
|
||||
// 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,
|
||||
|
||||
// ZX controls
|
||||
input wire res,
|
||||
output wire int_start,
|
||||
output wire line_start_s,
|
||||
|
||||
// DRAM interface
|
||||
output wire [20:0] video_addr,
|
||||
output wire [ 4:0] video_bw,
|
||||
output wire video_go,
|
||||
input wire [15:0] dram_rdata, // raw, should be latched by c2 (video_next)
|
||||
input wire video_next,
|
||||
input wire video_pre_next,
|
||||
input wire next_video,
|
||||
input wire video_strobe,
|
||||
output wire [20:0] ts_addr,
|
||||
output wire ts_req,
|
||||
input wire ts_pre_next,
|
||||
input wire ts_next,
|
||||
output wire [20:0] tm_addr,
|
||||
output wire tm_req,
|
||||
input wire tm_next
|
||||
);
|
||||
|
||||
|
||||
// video config
|
||||
wire [7:0] vpage; // re-latched at line_start
|
||||
wire [7:0] vconf; //
|
||||
wire [8:0] gx_offs; //
|
||||
wire [8:0] gy_offs; //
|
||||
wire [7:0] palsel; //
|
||||
wire [8:0] t0x_offs; //
|
||||
wire [8:0] t1x_offs; //
|
||||
wire [7:0] t0gpage; //
|
||||
wire [7:0] t1gpage; //
|
||||
wire [7:0] sgpage; // * not yet !!!
|
||||
wire [8:0] t0y_offs;
|
||||
wire [8:0] t1y_offs;
|
||||
wire [7:0] tsconf;
|
||||
wire [7:0] tmpage;
|
||||
wire [7:0] hint_beg;
|
||||
wire [8:0] vint_beg;
|
||||
wire [8:0] hpix_beg;
|
||||
wire [8:0] hpix_end;
|
||||
wire [8:0] vpix_beg;
|
||||
wire [8:0] vpix_end;
|
||||
wire [8:0] hpix_beg_ts;
|
||||
wire [8:0] hpix_end_ts;
|
||||
wire [8:0] vpix_beg_ts;
|
||||
wire [8:0] vpix_end_ts;
|
||||
wire [5:0] x_tiles;
|
||||
wire [9:0] x_offs_mode;
|
||||
wire [4:0] go_offs;
|
||||
wire [1:0] render_mode;
|
||||
wire tv_hires;
|
||||
wire nogfx = vconf[5];
|
||||
wire notsu = vconf[4];
|
||||
wire gfxovr = vconf[3];
|
||||
wire tv_hblank;
|
||||
wire tv_vblank;
|
||||
|
||||
// counters
|
||||
wire [7:0] cnt_col;
|
||||
wire [8:0] cnt_row;
|
||||
wire cptr;
|
||||
wire [3:0] scnt;
|
||||
wire [8:0] lcount;
|
||||
|
||||
// synchro
|
||||
wire frame_start;
|
||||
wire pix_start;
|
||||
wire tv_pix_start;
|
||||
wire ts_start;
|
||||
wire v_ts;
|
||||
wire v_pf;
|
||||
wire hpix;
|
||||
wire vpix;
|
||||
wire hvpix;
|
||||
wire hvtspix;
|
||||
wire flash;
|
||||
|
||||
// fetcher
|
||||
wire [31:0] fetch_data;
|
||||
wire [31:0] fetch_temp;
|
||||
wire [3:0] fetch_sel;
|
||||
wire [1:0] fetch_bsl;
|
||||
wire fetch_stb;
|
||||
|
||||
// video data
|
||||
wire [7:0] border;
|
||||
wire [7:0] vplex;
|
||||
|
||||
// TS
|
||||
wire tsr_go;
|
||||
wire [5:0] tsr_addr;
|
||||
wire [8:0] tsr_line;
|
||||
wire [7:0] tsr_page;
|
||||
wire [8:0] tsr_x;
|
||||
wire [2:0] tsr_xs;
|
||||
wire tsr_xf;
|
||||
wire [3:0] tsr_pal;
|
||||
wire tsr_rdy;
|
||||
|
||||
// TS-line
|
||||
wire [8:0] ts_waddr;
|
||||
wire [7:0] ts_wdata;
|
||||
wire ts_we;
|
||||
wire [8:0] ts_raddr;
|
||||
|
||||
video_ports video_ports
|
||||
(
|
||||
.clk (clk),
|
||||
.d (d),
|
||||
.res (res),
|
||||
.line_start_s (line_start_s),
|
||||
.border_wr (border_wr),
|
||||
.zborder_wr (zborder_wr),
|
||||
.zvpage_wr (zvpage_wr),
|
||||
.vpage_wr (vpage_wr),
|
||||
.vconf_wr (vconf_wr),
|
||||
.gx_offsl_wr (gx_offsl_wr),
|
||||
.gx_offsh_wr (gx_offsh_wr),
|
||||
.gy_offsl_wr (gy_offsl_wr),
|
||||
.gy_offsh_wr (gy_offsh_wr),
|
||||
.t0x_offsl_wr (t0x_offsl_wr),
|
||||
.t0x_offsh_wr (t0x_offsh_wr),
|
||||
.t0y_offsl_wr (t0y_offsl_wr),
|
||||
.t0y_offsh_wr (t0y_offsh_wr),
|
||||
.t1x_offsl_wr (t1x_offsl_wr),
|
||||
.t1x_offsh_wr (t1x_offsh_wr),
|
||||
.t1y_offsl_wr (t1y_offsl_wr),
|
||||
.t1y_offsh_wr (t1y_offsh_wr),
|
||||
.palsel_wr (palsel_wr),
|
||||
.hint_beg_wr (hint_beg_wr),
|
||||
.vint_begl_wr (vint_begl_wr),
|
||||
.vint_begh_wr (vint_begh_wr),
|
||||
.tsconf_wr (tsconf_wr),
|
||||
.tmpage_wr (tmpage_wr),
|
||||
.t0gpage_wr (t0gpage_wr),
|
||||
.t1gpage_wr (t1gpage_wr),
|
||||
.sgpage_wr (sgpage_wr),
|
||||
.border (border),
|
||||
.vpage (vpage),
|
||||
.vconf (vconf),
|
||||
.gx_offs (gx_offs),
|
||||
.gy_offs (gy_offs),
|
||||
.t0x_offs (t0x_offs),
|
||||
.t1x_offs (t1x_offs),
|
||||
.t0y_offs (t0y_offs),
|
||||
.t1y_offs (t1y_offs),
|
||||
.palsel (palsel),
|
||||
.hint_beg (hint_beg),
|
||||
.vint_beg (vint_beg),
|
||||
.int_start (0),
|
||||
.tsconf (tsconf),
|
||||
.tmpage (tmpage),
|
||||
.t0gpage (t0gpage),
|
||||
.t1gpage (t1gpage),
|
||||
.sgpage (sgpage)
|
||||
);
|
||||
|
||||
|
||||
video_mode video_mode
|
||||
(
|
||||
.clk (clk),
|
||||
.f1 (f1),
|
||||
.c3 (c3),
|
||||
.vpage (vpage),
|
||||
.vconf (vconf),
|
||||
.fetch_sel (fetch_sel),
|
||||
.fetch_bsl (fetch_bsl),
|
||||
.fetch_cnt (scnt),
|
||||
.fetch_stb (fetch_stb),
|
||||
.txt_char (fetch_temp[15:0]),
|
||||
.gx_offs (gx_offs),
|
||||
.x_offs_mode (x_offs_mode),
|
||||
.ts_rres_ext (tsconf[0]),
|
||||
.hpix_beg (hpix_beg),
|
||||
.hpix_end (hpix_end),
|
||||
.vpix_beg (vpix_beg),
|
||||
.vpix_end (vpix_end),
|
||||
.hpix_beg_ts (hpix_beg_ts),
|
||||
.hpix_end_ts (hpix_end_ts),
|
||||
.vpix_beg_ts (vpix_beg_ts),
|
||||
.vpix_end_ts (vpix_end_ts),
|
||||
.x_tiles (x_tiles),
|
||||
.go_offs (go_offs),
|
||||
.cnt_col (cnt_col),
|
||||
.cnt_row (cnt_row),
|
||||
.cptr (cptr),
|
||||
.line_start_s (line_start_s),
|
||||
.pix_start (pix_start),
|
||||
.tv_hires (tv_hires),
|
||||
.pix_stb (pix_stb),
|
||||
.render_mode (render_mode),
|
||||
.video_addr (video_addr),
|
||||
.video_bw (video_bw)
|
||||
);
|
||||
|
||||
|
||||
video_sync video_sync
|
||||
(
|
||||
.clk (clk),
|
||||
.f1 (f1),
|
||||
.c0 (c0),
|
||||
.c1 (c1),
|
||||
.c3 (c3),
|
||||
.hpix_beg (hpix_beg),
|
||||
.hpix_end (hpix_end),
|
||||
.vpix_beg (vpix_beg),
|
||||
.vpix_end (vpix_end),
|
||||
.hpix_beg_ts (hpix_beg_ts),
|
||||
.hpix_end_ts (hpix_end_ts),
|
||||
.vpix_beg_ts (vpix_beg_ts),
|
||||
.vpix_end_ts (vpix_end_ts),
|
||||
.go_offs (go_offs),
|
||||
.x_offs (x_offs_mode[1:0]),
|
||||
.y_offs_wr (gy_offsl_wr || gy_offsh_wr),
|
||||
.line_start_s (line_start_s),
|
||||
.hint_beg (hint_beg),
|
||||
.vint_beg (vint_beg),
|
||||
.hsync (hsync),
|
||||
.vsync (vsync),
|
||||
.tv_hblank (tv_hblank),
|
||||
.tv_vblank (tv_vblank),
|
||||
.ts_raddr (ts_raddr),
|
||||
.lcount (lcount),
|
||||
.cnt_col (cnt_col),
|
||||
.cnt_row (cnt_row),
|
||||
.cptr (cptr),
|
||||
.scnt (scnt),
|
||||
.flash (flash),
|
||||
.pix_stb (pix_stb),
|
||||
.pix_start (pix_start),
|
||||
.ts_start (ts_start),
|
||||
.cstart (x_offs_mode[9:2]),
|
||||
.rstart (gy_offs),
|
||||
.frame_start (frame_start),
|
||||
.int_start (int_start),
|
||||
.v_pf (v_pf),
|
||||
.hpix (hpix),
|
||||
.v_ts (v_ts),
|
||||
.vpix (vpix),
|
||||
.hvpix (hvpix),
|
||||
.hvtspix (hvtspix),
|
||||
.nogfx (nogfx),
|
||||
.video_go (video_go),
|
||||
.video_pre_next(video_pre_next)
|
||||
);
|
||||
|
||||
|
||||
video_fetch video_fetch
|
||||
(
|
||||
.clk (clk),
|
||||
.f_sel (fetch_sel),
|
||||
.b_sel (fetch_bsl),
|
||||
.fetch_stb (fetch_stb),
|
||||
.fetch_data (fetch_data),
|
||||
.fetch_temp (fetch_temp),
|
||||
.video_strobe (video_strobe),
|
||||
.video_data (dram_rdata)
|
||||
);
|
||||
|
||||
video_ts video_ts
|
||||
(
|
||||
.clk (clk),
|
||||
.start (ts_start),
|
||||
.line (lcount),
|
||||
.v_ts (v_ts),
|
||||
|
||||
.tsconf (tsconf),
|
||||
.t0gpage (t0gpage),
|
||||
.t1gpage (t1gpage),
|
||||
.sgpage (sgpage),
|
||||
.tmpage (tmpage),
|
||||
.num_tiles (x_tiles),
|
||||
.v_pf (v_pf),
|
||||
.t0x_offs (t0x_offs),
|
||||
.t1x_offs (t1x_offs),
|
||||
.t0y_offs (t0y_offs),
|
||||
.t1y_offs (t1y_offs),
|
||||
.t0_palsel (palsel[5:4]),
|
||||
.t1_palsel (palsel[7:6]),
|
||||
|
||||
.dram_addr (tm_addr),
|
||||
.dram_req (tm_req),
|
||||
.dram_next (tm_next),
|
||||
.dram_rdata (dram_rdata),
|
||||
|
||||
.tsr_go (tsr_go),
|
||||
.tsr_addr (tsr_addr),
|
||||
.tsr_line (tsr_line),
|
||||
.tsr_page (tsr_page),
|
||||
.tsr_pal (tsr_pal),
|
||||
.tsr_x (tsr_x),
|
||||
.tsr_xs (tsr_xs),
|
||||
.tsr_xf (tsr_xf),
|
||||
.tsr_rdy (tsr_rdy),
|
||||
|
||||
.sfile_addr_in (zma),
|
||||
.sfile_data_in (zmd),
|
||||
.sfile_we (sfile_we)
|
||||
);
|
||||
|
||||
video_ts_render video_ts_render
|
||||
(
|
||||
.clk (clk),
|
||||
|
||||
.reset (ts_start),
|
||||
|
||||
.tsr_go (tsr_go),
|
||||
.addr (tsr_addr),
|
||||
.line (tsr_line),
|
||||
.page (tsr_page),
|
||||
.pal (tsr_pal),
|
||||
.x_coord (tsr_x),
|
||||
.x_size (tsr_xs),
|
||||
.flip (tsr_xf),
|
||||
.mem_rdy (tsr_rdy),
|
||||
|
||||
.ts_waddr (ts_waddr),
|
||||
.ts_wdata (ts_wdata),
|
||||
.ts_we (ts_we),
|
||||
|
||||
.dram_addr (ts_addr),
|
||||
.dram_req (ts_req),
|
||||
.dram_pre_next (ts_pre_next),
|
||||
.dram_next (ts_next),
|
||||
.dram_rdata (dram_rdata)
|
||||
);
|
||||
|
||||
|
||||
video_render video_render
|
||||
(
|
||||
.clk (clk),
|
||||
.c1 (c1),
|
||||
.hvpix (hvpix),
|
||||
.hvtspix (hvtspix),
|
||||
.nogfx (nogfx),
|
||||
.notsu (notsu),
|
||||
.gfxovr (gfxovr),
|
||||
.flash (flash),
|
||||
.hires (tv_hires),
|
||||
.psel (scnt),
|
||||
.palsel (palsel[3:0]),
|
||||
.render_mode (render_mode),
|
||||
.data (fetch_data),
|
||||
.border_in (border),
|
||||
.tsdata_in (ts_rdata),
|
||||
.vplex_out (vplex)
|
||||
);
|
||||
|
||||
video_out video_out
|
||||
(
|
||||
.clk (clk),
|
||||
.c3 (c3),
|
||||
.tv_blank (tv_hblank|tv_vblank),
|
||||
.palsel (palsel[3:0]),
|
||||
.plex_sel_in ({h1, f1}),
|
||||
.tv_hires (tv_hires),
|
||||
.cram_addr_in (zma),
|
||||
.cram_data_in (zmd[15:0]),
|
||||
.cram_we (cram_we),
|
||||
.vplex_in (vplex),
|
||||
.vred (vred),
|
||||
.vgrn (vgrn),
|
||||
.vblu (vblu),
|
||||
.vdac_mode (vdac_mode)
|
||||
);
|
||||
|
||||
assign hblank = tv_hblank;
|
||||
assign vblank = tv_vblank;
|
||||
|
||||
// 2 buffers: 512 pixels * 8 bits (9x8) - used as bitmap buffer for TS overlay over graphics
|
||||
// (2 altdprams)
|
||||
wire tl_act0 = lcount[0];
|
||||
wire tl_act1 = ~lcount[0];
|
||||
wire [8:0] ts_waddr0 = tl_act0 ? ts_raddr : ts_waddr;
|
||||
wire [7:0] ts_wdata0 = tl_act0 ? 8'd0 : ts_wdata;
|
||||
wire ts_we0 = tl_act0 ? c3 : ts_we;
|
||||
wire [8:0] ts_waddr1 = tl_act1 ? ts_raddr : ts_waddr;
|
||||
wire [7:0] ts_wdata1 = tl_act1 ? 8'd0 : ts_wdata;
|
||||
wire ts_we1 = tl_act1 ? c3 : ts_we;
|
||||
wire [7:0] ts_rdata = tl_act0 ? ts_rdata0 : ts_rdata1;
|
||||
wire [7:0] ts_rdata0, ts_rdata1;
|
||||
|
||||
dpram #(.ADDRWIDTH(9)) video_tsline0
|
||||
(
|
||||
.clock (clk),
|
||||
.address_a (ts_waddr0),
|
||||
.data_a (ts_wdata0),
|
||||
.wren_a (ts_we0),
|
||||
.address_b (ts_raddr),
|
||||
.q_b (ts_rdata0)
|
||||
);
|
||||
|
||||
dpram #(.ADDRWIDTH(9)) video_tsline1
|
||||
(
|
||||
.clock (clk),
|
||||
.address_a (ts_waddr1),
|
||||
.data_a (ts_wdata1),
|
||||
.wren_a (ts_we1),
|
||||
.address_b (ts_raddr),
|
||||
.q_b (ts_rdata1)
|
||||
);
|
||||
|
||||
endmodule
|
379
rtl/video/video_ts.v
Normal file
379
rtl/video/video_ts.v
Normal file
@ -0,0 +1,379 @@
|
||||
|
||||
// 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 = 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
|
||||
(
|
||||
.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)
|
||||
);
|
||||
|
||||
endmodule
|
150
rtl/video/video_ts_render.v
Normal file
150
rtl/video/video_ts_render.v
Normal file
@ -0,0 +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'.
|
||||
|
||||
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
|
Reference in New Issue
Block a user