Line 20... |
Line 20... |
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
//
|
//
|
// ============================================================================
|
// ============================================================================
|
//
|
//
|
|
//`define USE_CLOCK_GATE 1'b1
|
|
|
`define TRUE 1'b1
|
`define TRUE 1'b1
|
`define FALSE 1'b0
|
`define FALSE 1'b0
|
`define HIGH 1'b1
|
`define HIGH 1'b1
|
`define LOW 1'b0
|
`define LOW 1'b0
|
|
|
`define ABITS 31:0
|
`define ABITS 31:0
|
|
// The cycle at which it's safe to update the working count and address.
|
|
// A good value is just before the end of the scan, but that depends on
|
|
// display resolution.
|
|
`define SPR_WCA 12'd638
|
|
|
module rtfSpriteController2(rst_i, clk_i, cs_i, cyc_i, stb_i, ack_o, we_i, sel_i, adr_i, dat_i, dat_o,
|
module rtfSpriteController2(rst_i, clk_i, cs_i, cyc_i, stb_i, ack_o, we_i, sel_i, adr_i, dat_i, dat_o,
|
m_clk_i, m_cyc_o, m_stb_o, m_ack_i, m_sel_o, m_adr_o, m_dat_i,
|
m_clk_i, m_cyc_o, m_stb_o, m_ack_i, m_sel_o, m_adr_o, m_dat_i,
|
dot_clk_i, hsync_i, vsync_i, zrgb_i, zrgb_o, test
|
dot_clk_i, hsync_i, vsync_i, zrgb_i, zrgb_o, test
|
);
|
);
|
Line 72... |
Line 78... |
|
|
reg controller_enable;
|
reg controller_enable;
|
wire vclk;
|
wire vclk;
|
reg [2:0] state;
|
reg [2:0] state;
|
reg [1:0] lowres;
|
reg [1:0] lowres;
|
reg [3:0] flashcnt;
|
wire [5:0] flashcnt;
|
reg rst_collision;
|
reg rst_collision;
|
reg [31:0] collision, c_collision;
|
reg [31:0] collision, c_collision;
|
reg [4:0] spriteno;
|
reg [4:0] spriteno;
|
reg sprite;
|
reg sprite;
|
reg [31:0] spriteEnable;
|
reg [31:0] spriteEnable;
|
reg [31:0] spriteActive;
|
reg [31:0] spriteActive;
|
reg [11:0] sprite_pv [0:31];
|
reg [11:0] sprite_pv [0:31];
|
reg [11:0] sprite_ph [0:31];
|
reg [11:0] sprite_ph [0:31];
|
reg [3:0] sprite_pz [0:31];
|
reg [3:0] sprite_pz [0:31];
|
|
(* ram_style="distributed" *)
|
reg [37:0] sprite_color [0:255];
|
reg [37:0] sprite_color [0:255];
|
reg [31:0] sprite_on;
|
reg [31:0] sprite_on;
|
reg [31:0] sprite_on_d1;
|
reg [31:0] sprite_on_d1;
|
reg [31:0] sprite_on_d2;
|
reg [31:0] sprite_on_d2;
|
reg [31:0] sprite_on_d3;
|
reg [31:0] sprite_on_d3;
|
|
(* ram_style="distributed" *)
|
reg [`ABITS] spriteAddr [0:31];
|
reg [`ABITS] spriteAddr [0:31];
|
reg [`ABITS] spriteWaddr [0:31];
|
reg [`ABITS] spriteWaddr [0:31];
|
reg [15:0] spriteMcnt [0:31];
|
reg [15:0] spriteMcnt [0:31];
|
reg [15:0] spriteWcnt [0:31];
|
reg [15:0] spriteWcnt [0:31];
|
reg [63:0] m_spriteBmp [0:31];
|
reg [63:0] m_spriteBmp [0:31];
|
reg [63:0] spriteBmp [0:31];
|
reg [63:0] spriteBmp [0:31];
|
reg [15:0] spriteColor [0:31];
|
|
reg [31:0] spriteLink1;
|
reg [31:0] spriteLink1;
|
reg [11:0] spriteColorNdx [0:31];
|
reg [7:0] spriteColorNdx [0:31];
|
|
|
initial begin
|
initial begin
|
for (n = 0; n < 256; n = n + 1) begin
|
for (n = 0; n < 256; n = n + 1) begin
|
sprite_color[n][31:0] = $urandom;
|
sprite_color[n] <= 38'h0000FF1F1F;
|
sprite_color[n][37:32] = 6'd0;//$urandom & 6'd63;
|
|
end
|
end
|
for (n = 0; n < 32; n = n + 1) begin
|
for (n = 0; n < 32; n = n + 1) begin
|
sprite_ph[n] <= $urandom%800 + 260;
|
sprite_ph[n] <= 260 + n * 40;
|
sprite_pv[n] <= $urandom%600 + 41;
|
sprite_pv[n] <= 41 + n * 20;
|
sprite_pz[n] <= $urandom%256;
|
sprite_pz[n] <= 8'h00;
|
spriteMcnt[n] <= ($urandom%505 + 5) * 32;
|
spriteMcnt[n] <= 60 * 32;
|
|
spriteBmp[n] <= 64'hFFFFFFFFFFFFFFFF;
|
end
|
end
|
end
|
end
|
|
|
wire pe_hsync, pe_vsync;
|
wire pe_hsync, pe_vsync;
|
reg [11:0] hctr, vctr, m_hctr, m_vctr;
|
wire [11:0] hctr, vctr;
|
|
reg [11:0] m_hctr, m_vctr;
|
|
|
// Generate acknowledge signal
|
// Generate acknowledge signal
|
wire cs = cs_i & cyc_i & stb_i;
|
wire cs = cs_i & cyc_i & stb_i;
|
reg rdy1,rdy2,rdy3;
|
reg rdy1,rdy2,rdy3;
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
rdy1 <= cs;
|
rdy1 <= cs;
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
rdy2 <= rdy1 & cs;
|
rdy2 <= rdy1 & cs;
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
rdy3 <= rdy2 & cs;
|
rdy3 <= rdy2 & cs;
|
assign ack_o = cs & we_i ? 1'b1 : rdy3;
|
assign ack_o = (cs & we_i) ? 1'b1 : rdy3;
|
|
|
(* ram_style="block" *)
|
(* ram_style="block" *)
|
reg [63:0] shadow_ram [0:511];
|
reg [63:0] shadow_ram [0:511];
|
reg [10:0] sradr;
|
reg [8:0] sradr;
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
if (cs & we_i) begin
|
if (cs & we_i) begin
|
if (sel_i[0]) shadow_ram[adr_i[11:3]][ 7: 0] <= dat_i;
|
if (sel_i[0]) shadow_ram[adr_i[11:3]][ 7: 0] <= dat_i;
|
if (sel_i[1]) shadow_ram[adr_i[11:3]][15: 8] <= dat_i;
|
if (sel_i[1]) shadow_ram[adr_i[11:3]][15: 8] <= dat_i;
|
if (sel_i[2]) shadow_ram[adr_i[11:3]][23:16] <= dat_i;
|
if (sel_i[2]) shadow_ram[adr_i[11:3]][23:16] <= dat_i;
|
Line 151... |
Line 159... |
always @(posedge clk_i)
|
always @(posedge clk_i)
|
if (rst_i) begin
|
if (rst_i) begin
|
rst_collision <= `FALSE;
|
rst_collision <= `FALSE;
|
controller_enable <= `TRUE;
|
controller_enable <= `TRUE;
|
spriteEnable <= 32'hFFFFFFFF;
|
spriteEnable <= 32'hFFFFFFFF;
|
|
spriteLink1 <= 32'h0;
|
end
|
end
|
else begin
|
else begin
|
rst_collision <= `FALSE;
|
rst_collision <= `FALSE;
|
if (cs & we_i) begin
|
if (cs & we_i) begin
|
casez(adr_i[11:3])
|
casez(adr_i[11:3])
|
Line 230... |
Line 239... |
m_adr_o <= spriteWaddr[spriteno];
|
m_adr_o <= spriteWaddr[spriteno];
|
end
|
end
|
MEM_ACCESS:
|
MEM_ACCESS:
|
if (m_ack_i) begin
|
if (m_ack_i) begin
|
m_cyc_o <= `LOW;
|
m_cyc_o <= `LOW;
|
spriteBmp[spriteno] <= dat_i;
|
m_spriteBmp[spriteno] <= dat_i;
|
if (test)
|
if (test)
|
spriteBmp[spriteno] <= 64'hFFFFFFFFFFFFFFFF;
|
m_spriteBmp[spriteno] <= 64'h00005555AAAAFFFF;
|
end
|
end
|
NEXT_SPRITE:
|
NEXT_SPRITE:
|
spriteno <= spriteno + 5'd1;
|
spriteno <= spriteno + 5'd1;
|
endcase
|
endcase
|
end
|
end
|
|
|
// Register collision onto clk_i domain.
|
// Register collision onto clk_i domain.
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
c_collision <= collision;
|
c_collision <= collision;
|
|
|
|
`ifdef USE_CLOCK_GATE
|
BUFHCE ucb1
|
BUFHCE ucb1
|
(
|
(
|
.I(dot_clk_i),
|
.I(dot_clk_i),
|
.CE(controller_enable),
|
.CE(controller_enable),
|
.O(vclk)
|
.O(vclk)
|
);
|
);
|
|
`else
|
|
assign vclk = dot_clk_i;
|
|
`endif
|
|
|
edge_det ued1 (.clk(vclk), .ce(1'b1), .i(hsync_i), .pe(pe_hsync), .ne(), .ee());
|
edge_det ued1 (.clk(vclk), .ce(1'b1), .i(hsync_i), .pe(pe_hsync), .ne(), .ee());
|
edge_det ued2 (.clk(vclk), .ce(1'b1), .i(vsync_i), .pe(pe_vsync), .ne(), .ee());
|
edge_det ued2 (.clk(vclk), .ce(1'b1), .i(vsync_i), .pe(pe_vsync), .ne(), .ee());
|
|
|
always @(posedge vclk)
|
VT163 #(12) uhctr (.clk(vclk), .clr_n(!rst_i), .ent(1'b1), .enp(1'b1), .ld_n(!pe_hsync), .d(12'd0), .q(hctr), .rco());
|
if (rst_i)
|
VT163 #(12) uvctr (.clk(vclk), .clr_n(!rst_i), .ent(pe_hsync), .enp(1'b1), .ld_n(!pe_vsync), .d(12'd0), .q(vctr), .rco());
|
hctr <= 12'd0;
|
VT163 # (6) ufctr (.clk(vclk), .clr_n(!rst_i), .ent(pe_vsync), .enp(1'b1), .ld_n(1'b1), .d( 6'd0), .q(flashcnt), .rco());
|
else begin
|
|
if (pe_hsync)
|
|
hctr <= 12'd0;
|
|
else
|
|
hctr <= hctr + 12'd1;
|
|
end
|
|
|
|
always @(posedge vclk)
|
|
if (rst_i)
|
|
vctr <= 12'd0;
|
|
else begin
|
|
if (pe_vsync)
|
|
vctr <= 12'd0;
|
|
else if (pe_hsync)
|
|
vctr <= vctr + 12'd1;
|
|
end
|
|
|
|
always @(posedge vclk)
|
always @(posedge vclk)
|
begin
|
begin
|
if (rst_collision)
|
if (rst_collision)
|
collision <= 32'd0;
|
collision <= 32'd0;
|
Line 348... |
Line 345... |
2'd0,2'd3: if ((vctr == sprite_pv[n]) && (hctr == 12'h005)) spriteWcnt[n] <= 16'd0;
|
2'd0,2'd3: if ((vctr == sprite_pv[n]) && (hctr == 12'h005)) spriteWcnt[n] <= 16'd0;
|
2'd1: if ((vctr[11:1] == sprite_pv[n]) && (hctr == 12'h005)) spriteWcnt[n] <= 16'd0;
|
2'd1: if ((vctr[11:1] == sprite_pv[n]) && (hctr == 12'h005)) spriteWcnt[n] <= 16'd0;
|
2'd2: if ((vctr[11:2] == sprite_pv[n]) && (hctr == 12'h005)) spriteWcnt[n] <= 16'd0;
|
2'd2: if ((vctr[11:2] == sprite_pv[n]) && (hctr == 12'h005)) spriteWcnt[n] <= 16'd0;
|
endcase
|
endcase
|
// The following assumes there are at least 640 clocks in a scan line.
|
// The following assumes there are at least 640 clocks in a scan line.
|
if (hctr==12'd638) // must be after image data fetch
|
if (hctr==`SPR_WCA) // must be after image data fetch
|
if (spriteActive[n])
|
if (spriteActive[n])
|
case(lowres)
|
case(lowres)
|
2'd0,2'd3: spriteWcnt[n] <= spriteWcnt[n] + 16'd32;
|
2'd0,2'd3: spriteWcnt[n] <= spriteWcnt[n] + 16'd32;
|
2'd1: if (vctr[0]) spriteWcnt[n] <= spriteWcnt[n] + 16'd32;
|
2'd1: if (vctr[0]) spriteWcnt[n] <= spriteWcnt[n] + 16'd32;
|
2'd2: if (vctr[1:0]==2'b11) spriteWcnt[n] <= spriteWcnt[n] + 16'd32;
|
2'd2: if (vctr[1:0]==2'b11) spriteWcnt[n] <= spriteWcnt[n] + 16'd32;
|
Line 365... |
Line 362... |
case(lowres)
|
case(lowres)
|
2'd0,2'd3: if ((vctr == sprite_pv[n]) && (hctr == 12'h005)) spriteWaddr[n] <= spriteAddr[n];
|
2'd0,2'd3: if ((vctr == sprite_pv[n]) && (hctr == 12'h005)) spriteWaddr[n] <= spriteAddr[n];
|
2'd1: if ((vctr[11:1] == sprite_pv[n]) && (hctr == 12'h005)) spriteWaddr[n] <= spriteAddr[n];
|
2'd1: if ((vctr[11:1] == sprite_pv[n]) && (hctr == 12'h005)) spriteWaddr[n] <= spriteAddr[n];
|
2'd2: if ((vctr[11:2] == sprite_pv[n]) && (hctr == 12'h005)) spriteWaddr[n] <= spriteAddr[n];
|
2'd2: if ((vctr[11:2] == sprite_pv[n]) && (hctr == 12'h005)) spriteWaddr[n] <= spriteAddr[n];
|
endcase
|
endcase
|
if (hctr==12'd638) // must be after image data fetch
|
if (hctr==`SPR_WCA) // must be after image data fetch
|
case(lowres)
|
case(lowres)
|
2'd0,2'd3: spriteWaddr[n] <= spriteWaddr[n] + 32'd16;
|
2'd0,2'd3: spriteWaddr[n] <= spriteWaddr[n] + 32'd8;
|
2'd1: if (vctr[0]) spriteWaddr[n] <= spriteWaddr[n] + 32'd16;
|
2'd1: if (vctr[0]) spriteWaddr[n] <= spriteWaddr[n] + 32'd8;
|
2'd2: if (vctr[1:0]==2'b11) spriteWaddr[n] <= spriteWaddr[n] + 32'd16;
|
2'd2: if (vctr[1:0]==2'b11) spriteWaddr[n] <= spriteWaddr[n] + 32'd8;
|
endcase
|
endcase
|
end
|
end
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// clock edge #0
|
// clock edge #0
|
Line 412... |
Line 409... |
endcase
|
endcase
|
end
|
end
|
|
|
always @(posedge vclk)
|
always @(posedge vclk)
|
for (n = 0; n < NSPR; n = n + 1)
|
for (n = 0; n < NSPR; n = n + 1)
|
if (spriteLink1[n]) begin
|
if (spriteLink1[n])
|
spriteColorNdx[n] <= {n[3:0],spriteBmp[(n+1)&31][63:62],spriteBmp[n][63:62]};
|
spriteColorNdx[n] <= {n[3:0],spriteBmp[(n+1)&31][63:62],spriteBmp[n][63:62]};
|
end
|
else if (spriteLink1[(n-1)&31])
|
else if (spriteLink1[(n-1)&31]) begin
|
|
spriteColorNdx[n] <= 8'h00; // transparent
|
spriteColorNdx[n] <= 8'h00; // transparent
|
end
|
|
else
|
else
|
spriteColorNdx[n] <= {n[4:0],spriteBmp[n][63:62]};
|
spriteColorNdx[n] <= {1'b0,n[4:0],spriteBmp[n][63:62]};
|
|
|
// Compute index into sprite color palette
|
// Compute index into sprite color palette
|
// If none of the sprites are linked, each sprite has it's own set of colors.
|
// If none of the sprites are linked, each sprite has it's own set of colors.
|
// If the sprites are linked once the colors are available in groups.
|
// If the sprites are linked once the colors are available in groups.
|
// If the sprites are linked twice they all share the same set of colors.
|
// If the sprites are linked twice they all share the same set of colors.
|
Line 436... |
Line 431... |
reg [7:0] sprite_z1, sprite_z2, sprite_z3, sprite_z4;
|
reg [7:0] sprite_z1, sprite_z2, sprite_z3, sprite_z4;
|
reg [7:0] sprite_pzx;
|
reg [7:0] sprite_pzx;
|
// The color index from each sprite can be mux'ed into a single value used to
|
// The color index from each sprite can be mux'ed into a single value used to
|
// access the color palette because output color is a priority chain. This
|
// access the color palette because output color is a priority chain. This
|
// saves having mulriple read ports on the color palette.
|
// saves having mulriple read ports on the color palette.
|
reg [31:0] spriteColorOut2;
|
reg [37:0] spriteColorOut2;
|
reg [31:0] spriteColorOut3;
|
reg [37:0] spriteColorOut3;
|
reg [7:0] spriteClrNdx;
|
reg [7:0] spriteClrNdx;
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// clock edge #1
|
// clock edge #1
|
// - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - -
|
Line 459... |
Line 454... |
spriteClrNdx <= spriteColorNdx[n];
|
spriteClrNdx <= spriteColorNdx[n];
|
end
|
end
|
|
|
always @(posedge vclk)
|
always @(posedge vclk)
|
begin
|
begin
|
sprite_z1 <= 3'h7;
|
sprite_z1 <= 8'hff;
|
for (n = NSPR-1; n >= 0; n = n -1)
|
for (n = NSPR-1; n >= 0; n = n -1)
|
if (sprite_on[n])
|
if (sprite_on[n])
|
sprite_z1 <= sprite_pz[n];
|
sprite_z1 <= sprite_pz[n];
|
end
|
end
|
|
|
Line 488... |
Line 483... |
// - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// clock edge #3
|
// clock edge #3
|
// - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// Compute alpha blending
|
// Compute alpha blending
|
|
|
wire [12:0] alphaRed = zrgb_i[23:16] * spriteColorOut2[31:24] + (spriteColorOut2[23:16] * (9'h100 - spriteColorOut2[31:24]));
|
wire [15:0] alphaRed = (zrgb_i[23:16] * spriteColorOut2[31:24]) + (spriteColorOut2[23:16] * (9'h100 - spriteColorOut2[31:24]));
|
wire [12:0] alphaGreen = zrgb_i[15:8] * spriteColorOut2[31:24] + (spriteColorOut2[15:8] * (9'h100 - spriteColorOut2[31:24]));
|
wire [15:0] alphaGreen = (zrgb_i[15:8] * spriteColorOut2[31:24]) + (spriteColorOut2[15:8] * (9'h100 - spriteColorOut2[31:24]));
|
wire [12:0] alphaBlue = zrgb_i[7:0] * spriteColorOut2[31:24] + (spriteColorOut2[7:0] * (9'h100 - spriteColorOut2[31:24]));
|
wire [15:0] alphaBlue = (zrgb_i[7:0] * spriteColorOut2[31:24]) + (spriteColorOut2[7:0] * (9'h100 - spriteColorOut2[31:24]));
|
reg [23:0] alphaOut;
|
reg [23:0] alphaOut;
|
|
|
always @(posedge vclk)
|
always @(posedge vclk)
|
alphaOut <= {alphaRed[12:5],alphaGreen[12:5],alphaBlue[12:5]};
|
alphaOut <= {alphaRed[15:8],alphaGreen[15:8],alphaBlue[15:8]};
|
always @(posedge vclk)
|
always @(posedge vclk)
|
sprite_z3 <= sprite_z2;
|
sprite_z3 <= sprite_z2;
|
always @(posedge vclk)
|
always @(posedge vclk)
|
any_sprite_on3 <= any_sprite_on2;
|
any_sprite_on3 <= any_sprite_on2;
|
always @(posedge vclk)
|
always @(posedge vclk)
|
Line 540... |
Line 535... |
// - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// final output registration
|
// final output registration
|
|
|
always @(posedge dot_clk_i)
|
always @(posedge dot_clk_i)
|
case(any_sprite_on4 & controller_enable)
|
case(any_sprite_on4 & controller_enable)
|
1'b1: zrgb_o <= {zrgb_i4[31:24],((zb_i4 < sprite_z4) ? zrgb_i4[23:0] : flashOut[23:0])};
|
1'b1: zrgb_o <= (zb_i4 < sprite_z4) ? zrgb_i4 : {sprite_z4,flashOut};
|
1'b0: zrgb_o <= zrgb_i4;
|
1'b0: zrgb_o <= zrgb_i4;
|
endcase
|
endcase
|
|
|
endmodule
|
endmodule
|
|
|