Files
TSConf_MiST/rtl/video/video_ts_render.v

151 lines
4.3 KiB
Verilog

`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
);
// 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