| 1 |
4 |
robfinch |
// ============================================================================
|
| 2 |
|
|
// __
|
| 3 |
6 |
robfinch |
// \\__/ o\ (C) 2018-2019 Robert Finch, Waterloo
|
| 4 |
4 |
robfinch |
// \ __ / All rights reserved.
|
| 5 |
|
|
// \/_// robfinch<remove>@finitron.ca
|
| 6 |
|
|
// ||
|
| 7 |
|
|
//
|
| 8 |
|
|
// rtfSpriteController2.v
|
| 9 |
|
|
//
|
| 10 |
|
|
// This source file is free software: you can redistribute it and/or modify
|
| 11 |
|
|
// it under the terms of the GNU Lesser General Public License as published
|
| 12 |
|
|
// by the Free Software Foundation, either version 3 of the License, or
|
| 13 |
|
|
// (at your option) any later version.
|
| 14 |
|
|
//
|
| 15 |
|
|
// This source file is distributed in the hope that it will be useful,
|
| 16 |
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 17 |
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 18 |
|
|
// GNU General Public License for more details.
|
| 19 |
|
|
//
|
| 20 |
|
|
// You should have received a copy of the GNU General Public License
|
| 21 |
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 22 |
|
|
//
|
| 23 |
|
|
// ============================================================================
|
| 24 |
|
|
//
|
| 25 |
5 |
robfinch |
//`define USE_CLOCK_GATE 1'b1
|
| 26 |
|
|
|
| 27 |
4 |
robfinch |
`define TRUE 1'b1
|
| 28 |
|
|
`define FALSE 1'b0
|
| 29 |
|
|
`define HIGH 1'b1
|
| 30 |
|
|
`define LOW 1'b0
|
| 31 |
|
|
|
| 32 |
|
|
`define ABITS 31:0
|
| 33 |
5 |
robfinch |
// The cycle at which it's safe to update the working count and address.
|
| 34 |
|
|
// A good value is just before the end of the scan, but that depends on
|
| 35 |
|
|
// display resolution.
|
| 36 |
|
|
`define SPR_WCA 12'd638
|
| 37 |
6 |
robfinch |
//`define SUPPORT_LOWRES 1'b1
|
| 38 |
4 |
robfinch |
|
| 39 |
6 |
robfinch |
module rtfSpriteController2(clk_i, cs_i, cyc_i, stb_i, ack_o, we_i, sel_i, adr_i, dat_i, dat_o,
|
| 40 |
|
|
m_clk_i, m_cyc_o, m_stb_o, m_ack_i, m_sel_o, m_adr_o, m_dat_i, m_spriteno_o,
|
| 41 |
|
|
dot_clk_i, hsync_i, vsync_i, border_i, zrgb_i, zrgb_o, test
|
| 42 |
4 |
robfinch |
);
|
| 43 |
|
|
// Bus slave port
|
| 44 |
|
|
input clk_i;
|
| 45 |
|
|
input cs_i;
|
| 46 |
|
|
input cyc_i;
|
| 47 |
|
|
input stb_i;
|
| 48 |
|
|
output ack_o;
|
| 49 |
|
|
input we_i;
|
| 50 |
|
|
input [7:0] sel_i;
|
| 51 |
|
|
input [11:0] adr_i;
|
| 52 |
|
|
input [63:0] dat_i;
|
| 53 |
|
|
output reg [63:0] dat_o;
|
| 54 |
|
|
// Bus master port
|
| 55 |
|
|
input m_clk_i;
|
| 56 |
|
|
output reg m_cyc_o;
|
| 57 |
|
|
output m_stb_o;
|
| 58 |
|
|
input m_ack_i;
|
| 59 |
|
|
output [7:0] m_sel_o;
|
| 60 |
|
|
output reg [`ABITS] m_adr_o;
|
| 61 |
|
|
input [63:0] m_dat_i;
|
| 62 |
6 |
robfinch |
output reg [4:0] m_spriteno_o;
|
| 63 |
4 |
robfinch |
// Video port
|
| 64 |
|
|
input dot_clk_i;
|
| 65 |
|
|
input vsync_i;
|
| 66 |
|
|
input hsync_i;
|
| 67 |
6 |
robfinch |
input border_i;
|
| 68 |
4 |
robfinch |
input [31:0] zrgb_i;
|
| 69 |
|
|
output reg [31:0] zrgb_o;
|
| 70 |
|
|
input test;
|
| 71 |
|
|
|
| 72 |
|
|
parameter NSPR = 32;
|
| 73 |
6 |
robfinch |
parameter IDLE = 2'd0;
|
| 74 |
|
|
parameter DATA_FETCH = 2'd1;
|
| 75 |
|
|
parameter MEM_ACCESS = 2'd2;
|
| 76 |
4 |
robfinch |
|
| 77 |
|
|
integer n;
|
| 78 |
|
|
|
| 79 |
6 |
robfinch |
reg controller_enable = 1'b1;
|
| 80 |
4 |
robfinch |
wire vclk;
|
| 81 |
6 |
robfinch |
reg [1:0] state = IDLE;
|
| 82 |
|
|
reg [1:0] lowres = 2'b00;
|
| 83 |
5 |
robfinch |
wire [5:0] flashcnt;
|
| 84 |
6 |
robfinch |
reg rst_collision = 1'b0;
|
| 85 |
4 |
robfinch |
reg [31:0] collision, c_collision;
|
| 86 |
6 |
robfinch |
reg [4:0] spriteno = 5'd0;
|
| 87 |
4 |
robfinch |
reg sprite;
|
| 88 |
6 |
robfinch |
reg [31:0] spriteEnable = 32'hFFFFFFFF;
|
| 89 |
4 |
robfinch |
reg [31:0] spriteActive;
|
| 90 |
|
|
reg [11:0] sprite_pv [0:31];
|
| 91 |
|
|
reg [11:0] sprite_ph [0:31];
|
| 92 |
|
|
reg [3:0] sprite_pz [0:31];
|
| 93 |
5 |
robfinch |
(* ram_style="distributed" *)
|
| 94 |
4 |
robfinch |
reg [37:0] sprite_color [0:255];
|
| 95 |
|
|
reg [31:0] sprite_on;
|
| 96 |
|
|
reg [31:0] sprite_on_d1;
|
| 97 |
|
|
reg [31:0] sprite_on_d2;
|
| 98 |
|
|
reg [31:0] sprite_on_d3;
|
| 99 |
5 |
robfinch |
(* ram_style="distributed" *)
|
| 100 |
4 |
robfinch |
reg [`ABITS] spriteAddr [0:31];
|
| 101 |
|
|
reg [`ABITS] spriteWaddr [0:31];
|
| 102 |
|
|
reg [15:0] spriteMcnt [0:31];
|
| 103 |
|
|
reg [15:0] spriteWcnt [0:31];
|
| 104 |
|
|
reg [63:0] m_spriteBmp [0:31];
|
| 105 |
|
|
reg [63:0] spriteBmp [0:31];
|
| 106 |
6 |
robfinch |
reg [31:0] spriteLink1 = 32'h0;
|
| 107 |
5 |
robfinch |
reg [7:0] spriteColorNdx [0:31];
|
| 108 |
4 |
robfinch |
|
| 109 |
|
|
initial begin
|
| 110 |
|
|
for (n = 0; n < 256; n = n + 1) begin
|
| 111 |
6 |
robfinch |
sprite_color[n] <= {6'h00,8'h00,n[7:5],5'd0,n[4:3],6'd0,n[2:0],5'd0};
|
| 112 |
|
|
// sprite_color[n][31:0] <= {8'h00,n[7:5],5'd0,n[4:3],6'd0,n[2:0],5'd0}; // <- doesn't work
|
| 113 |
4 |
robfinch |
end
|
| 114 |
|
|
for (n = 0; n < 32; n = n + 1) begin
|
| 115 |
6 |
robfinch |
if (n < 16) begin
|
| 116 |
|
|
sprite_ph[n] <= 400 + n * 32;
|
| 117 |
|
|
sprite_pv[n] <= 100 + n * 8;
|
| 118 |
|
|
end
|
| 119 |
|
|
else begin
|
| 120 |
|
|
sprite_ph[n] <= 400 + (n - 16) * 32;
|
| 121 |
|
|
sprite_pv[n] <= 200 + n * 8;
|
| 122 |
|
|
end
|
| 123 |
|
|
sprite_pz[n] <= 8'h08;
|
| 124 |
|
|
spriteMcnt[n] <= 80 * 32;
|
| 125 |
5 |
robfinch |
spriteBmp[n] <= 64'hFFFFFFFFFFFFFFFF;
|
| 126 |
6 |
robfinch |
spriteAddr[n] <= 32'h40000 + (n << 12);
|
| 127 |
4 |
robfinch |
end
|
| 128 |
|
|
end
|
| 129 |
|
|
|
| 130 |
|
|
wire pe_hsync, pe_vsync;
|
| 131 |
5 |
robfinch |
wire [11:0] hctr, vctr;
|
| 132 |
|
|
reg [11:0] m_hctr, m_vctr;
|
| 133 |
4 |
robfinch |
|
| 134 |
6 |
robfinch |
reg cs;
|
| 135 |
|
|
reg we;
|
| 136 |
|
|
reg [7:0] sel;
|
| 137 |
|
|
reg [11:0] adr;
|
| 138 |
|
|
reg [63:0] dat;
|
| 139 |
4 |
robfinch |
|
| 140 |
6 |
robfinch |
wire clk;
|
| 141 |
|
|
`ifdef USE_CLOCK_GATE
|
| 142 |
|
|
BUFH uclk (.I(clk_i), .O(clk));
|
| 143 |
|
|
`else
|
| 144 |
|
|
wire clk = clk_i;
|
| 145 |
|
|
`endif
|
| 146 |
|
|
|
| 147 |
|
|
always @(posedge clk)
|
| 148 |
|
|
cs <= cs_i & cyc_i & stb_i;
|
| 149 |
|
|
always @(posedge clk)
|
| 150 |
|
|
we <= we_i;
|
| 151 |
|
|
always @(posedge clk)
|
| 152 |
|
|
sel <= sel_i;
|
| 153 |
|
|
always @(posedge clk)
|
| 154 |
|
|
adr <= adr_i;
|
| 155 |
|
|
always @(posedge clk)
|
| 156 |
|
|
dat <= dat_i;
|
| 157 |
|
|
|
| 158 |
|
|
ack_gen #(
|
| 159 |
|
|
.READ_STAGES(4),
|
| 160 |
|
|
.WRITE_STAGES(0),
|
| 161 |
|
|
.REGISTER_OUTPUT(1)
|
| 162 |
|
|
) uag1
|
| 163 |
|
|
(
|
| 164 |
|
|
.clk_i(clk),
|
| 165 |
|
|
.ce_i(1'b1),
|
| 166 |
|
|
.i(cs),
|
| 167 |
|
|
.we_i(cs & we),
|
| 168 |
|
|
.o(ack_o)
|
| 169 |
|
|
);
|
| 170 |
|
|
|
| 171 |
4 |
robfinch |
(* ram_style="block" *)
|
| 172 |
|
|
reg [63:0] shadow_ram [0:511];
|
| 173 |
6 |
robfinch |
reg [63:0] shadow_ramo;
|
| 174 |
5 |
robfinch |
reg [8:0] sradr;
|
| 175 |
6 |
robfinch |
always @(posedge clk)
|
| 176 |
|
|
if (cs & we) begin
|
| 177 |
|
|
if (|sel[1:0]) shadow_ram[adr[11:3]][15: 0] <= dat[15: 0];
|
| 178 |
|
|
if (|sel[3:2]) shadow_ram[adr[11:3]][31:16] <= dat[31:16];
|
| 179 |
|
|
if (|sel[5:4]) shadow_ram[adr[11:3]][47:32] <= dat[47:32];
|
| 180 |
|
|
if (|sel[7:6]) shadow_ram[adr[11:3]][63:48] <= dat[63:48];
|
| 181 |
4 |
robfinch |
end
|
| 182 |
6 |
robfinch |
always @(posedge clk)
|
| 183 |
|
|
sradr <= adr[11:3];
|
| 184 |
|
|
always @(posedge clk)
|
| 185 |
|
|
shadow_ramo <= shadow_ram[sradr];
|
| 186 |
|
|
always @(posedge clk)
|
| 187 |
|
|
case(adr[11:3])
|
| 188 |
4 |
robfinch |
9'b1010_0001_0: dat_o <= c_collision;
|
| 189 |
6 |
robfinch |
default: dat_o <= shadow_ramo;
|
| 190 |
4 |
robfinch |
endcase
|
| 191 |
|
|
|
| 192 |
6 |
robfinch |
always @(posedge clk)
|
| 193 |
|
|
begin
|
| 194 |
4 |
robfinch |
rst_collision <= `FALSE;
|
| 195 |
6 |
robfinch |
if (cs & we) begin
|
| 196 |
|
|
casez(adr[11:3])
|
| 197 |
|
|
9'b0???_????_?: sprite_color[adr[10:3]] <= dat[37:0];
|
| 198 |
|
|
9'b100?_????_0: spriteAddr[adr[8:4]] <= dat[`ABITS];
|
| 199 |
4 |
robfinch |
9'b100?_????_1:
|
| 200 |
|
|
begin
|
| 201 |
6 |
robfinch |
if (|sel[1:0]) sprite_ph[adr[8:4]] <= dat[11: 0];
|
| 202 |
|
|
if (|sel[3:2]) sprite_pv[adr[8:4]] <= dat[27:16];
|
| 203 |
|
|
if (|sel[5:4]) sprite_pz[adr[8:4]] <= dat[39:32];
|
| 204 |
|
|
if (|sel[7:6]) spriteMcnt[adr[8:4]] <= dat[63:48];
|
| 205 |
4 |
robfinch |
end
|
| 206 |
6 |
robfinch |
9'b1010_0000_0: spriteEnable <= dat[31:0];
|
| 207 |
|
|
9'b1010_0000_1: spriteLink1 <= dat[31:0];
|
| 208 |
4 |
robfinch |
9'b1010_0001_0: rst_collision <= `TRUE;
|
| 209 |
|
|
9'b1010_0001_1:
|
| 210 |
|
|
begin
|
| 211 |
6 |
robfinch |
lowres <= dat[1:0];
|
| 212 |
|
|
controller_enable <= dat[8];
|
| 213 |
4 |
robfinch |
end
|
| 214 |
6 |
robfinch |
default: ;
|
| 215 |
4 |
robfinch |
endcase
|
| 216 |
|
|
end
|
| 217 |
|
|
end
|
| 218 |
|
|
|
| 219 |
|
|
assign m_stb_o = m_cyc_o;
|
| 220 |
|
|
assign m_sel_o = 8'hFF;
|
| 221 |
|
|
|
| 222 |
6 |
robfinch |
wire clkm;
|
| 223 |
|
|
`ifdef USE_CLOCK_GATE
|
| 224 |
|
|
BUFHCE uclkm (.I(m_clk_i), .CE(controller_enable), .O(clkm));
|
| 225 |
|
|
`else
|
| 226 |
|
|
wire clkm = m_clk_i;
|
| 227 |
|
|
`endif
|
| 228 |
|
|
|
| 229 |
4 |
robfinch |
// Register hctr to m_clk_i domain
|
| 230 |
6 |
robfinch |
always @(posedge clkm)
|
| 231 |
4 |
robfinch |
m_hctr <= hctr;
|
| 232 |
|
|
|
| 233 |
|
|
// State machine
|
| 234 |
6 |
robfinch |
always @(posedge clkm)
|
| 235 |
|
|
case(state)
|
| 236 |
|
|
IDLE:
|
| 237 |
|
|
// dot_clk_i is likely faster than m_clk_i, so check for a trigger zone.
|
| 238 |
|
|
if (m_hctr < 12'd10 && controller_enable)
|
| 239 |
|
|
state <= DATA_FETCH;
|
| 240 |
|
|
DATA_FETCH:
|
| 241 |
|
|
if (spriteActive[spriteno]) begin
|
| 242 |
|
|
if (~m_ack_i)
|
| 243 |
4 |
robfinch |
state <= MEM_ACCESS;
|
| 244 |
6 |
robfinch |
end
|
| 245 |
|
|
else if (spriteno==5'd31)
|
| 246 |
|
|
state <= IDLE;
|
| 247 |
|
|
MEM_ACCESS:
|
| 248 |
|
|
if (m_ack_i|test) begin
|
| 249 |
4 |
robfinch |
if (spriteno==5'd31)
|
| 250 |
|
|
state <= IDLE;
|
| 251 |
|
|
else
|
| 252 |
|
|
state <= DATA_FETCH;
|
| 253 |
6 |
robfinch |
end
|
| 254 |
|
|
default: state <= IDLE;
|
| 255 |
|
|
endcase
|
| 256 |
4 |
robfinch |
|
| 257 |
6 |
robfinch |
always @(posedge clkm)
|
| 258 |
|
|
case(state)
|
| 259 |
|
|
IDLE:
|
| 260 |
4 |
robfinch |
m_cyc_o <= `LOW;
|
| 261 |
6 |
robfinch |
DATA_FETCH:
|
| 262 |
|
|
if (!m_ack_i && spriteActive[spriteno]) begin
|
| 263 |
|
|
m_cyc_o <= ~test;//`HIGH;
|
| 264 |
|
|
m_adr_o <= spriteWaddr[spriteno];
|
| 265 |
|
|
m_spriteno_o <= spriteno;
|
| 266 |
|
|
end
|
| 267 |
|
|
MEM_ACCESS:
|
| 268 |
|
|
if (m_ack_i|test) begin
|
| 269 |
|
|
m_cyc_o <= `LOW;
|
| 270 |
|
|
m_spriteBmp[spriteno] <= m_dat_i;
|
| 271 |
|
|
if (test)
|
| 272 |
|
|
m_spriteBmp[spriteno] <= 64'h00005555AAAAFFFF;
|
| 273 |
|
|
end
|
| 274 |
|
|
default: ;
|
| 275 |
|
|
endcase
|
| 276 |
|
|
|
| 277 |
|
|
always @(posedge clkm)
|
| 278 |
|
|
case(state)
|
| 279 |
|
|
IDLE:
|
| 280 |
4 |
robfinch |
spriteno <= 5'd0;
|
| 281 |
6 |
robfinch |
DATA_FETCH:
|
| 282 |
|
|
if (!spriteActive[spriteno])
|
| 283 |
4 |
robfinch |
spriteno <= spriteno + 5'd1;
|
| 284 |
6 |
robfinch |
MEM_ACCESS:
|
| 285 |
|
|
if (m_ack_i|test)
|
| 286 |
|
|
spriteno <= spriteno + 5'd1;
|
| 287 |
|
|
default: ;
|
| 288 |
|
|
endcase
|
| 289 |
4 |
robfinch |
|
| 290 |
6 |
robfinch |
|
| 291 |
4 |
robfinch |
// Register collision onto clk_i domain.
|
| 292 |
6 |
robfinch |
always @(posedge clk)
|
| 293 |
4 |
robfinch |
c_collision <= collision;
|
| 294 |
|
|
|
| 295 |
5 |
robfinch |
`ifdef USE_CLOCK_GATE
|
| 296 |
4 |
robfinch |
BUFHCE ucb1
|
| 297 |
|
|
(
|
| 298 |
|
|
.I(dot_clk_i),
|
| 299 |
|
|
.CE(controller_enable),
|
| 300 |
|
|
.O(vclk)
|
| 301 |
|
|
);
|
| 302 |
5 |
robfinch |
`else
|
| 303 |
|
|
assign vclk = dot_clk_i;
|
| 304 |
|
|
`endif
|
| 305 |
4 |
robfinch |
|
| 306 |
|
|
edge_det ued1 (.clk(vclk), .ce(1'b1), .i(hsync_i), .pe(pe_hsync), .ne(), .ee());
|
| 307 |
|
|
edge_det ued2 (.clk(vclk), .ce(1'b1), .i(vsync_i), .pe(pe_vsync), .ne(), .ee());
|
| 308 |
|
|
|
| 309 |
6 |
robfinch |
VT163 #(12) uhctr (.clk(vclk), .clr_n(1'b1), .ent(1'b1), .enp(1'b1), .ld_n(!pe_hsync), .d(12'd0), .q(hctr), .rco());
|
| 310 |
|
|
VT163 #(12) uvctr (.clk(vclk), .clr_n(1'b1), .ent(pe_hsync), .enp(1'b1), .ld_n(!pe_vsync), .d(12'd0), .q(vctr), .rco());
|
| 311 |
|
|
VT163 # (6) ufctr (.clk(vclk), .clr_n(1'b1), .ent(pe_vsync), .enp(1'b1), .ld_n(1'b1), .d( 6'd0), .q(flashcnt), .rco());
|
| 312 |
4 |
robfinch |
|
| 313 |
|
|
always @(posedge vclk)
|
| 314 |
|
|
begin
|
| 315 |
|
|
if (rst_collision)
|
| 316 |
|
|
collision <= 32'd0;
|
| 317 |
|
|
else
|
| 318 |
|
|
case(sprite_on)
|
| 319 |
|
|
32'b00000000000000000000000000000000,
|
| 320 |
|
|
32'b00000000000000000000000000000001,
|
| 321 |
|
|
32'b00000000000000000000000000000010,
|
| 322 |
|
|
32'b00000000000000000000000000000100,
|
| 323 |
|
|
32'b00000000000000000000000000001000,
|
| 324 |
|
|
32'b00000000000000000000000000010000,
|
| 325 |
|
|
32'b00000000000000000000000000100000,
|
| 326 |
|
|
32'b00000000000000000000000001000000,
|
| 327 |
|
|
32'b00000000000000000000000010000000,
|
| 328 |
|
|
32'b00000000000000000000000100000000,
|
| 329 |
|
|
32'b00000000000000000000001000000000,
|
| 330 |
|
|
32'b00000000000000000000010000000000,
|
| 331 |
|
|
32'b00000000000000000000100000000000,
|
| 332 |
|
|
32'b00000000000000000001000000000000,
|
| 333 |
|
|
32'b00000000000000000010000000000000,
|
| 334 |
|
|
32'b00000000000000000100000000000000,
|
| 335 |
|
|
32'b00000000000000001000000000000000,
|
| 336 |
|
|
32'b00000000000000010000000000000000,
|
| 337 |
|
|
32'b00000000000000100000000000000000,
|
| 338 |
|
|
32'b00000000000001000000000000000000,
|
| 339 |
|
|
32'b00000000000010000000000000000000,
|
| 340 |
|
|
32'b00000000000100000000000000000000,
|
| 341 |
|
|
32'b00000000001000000000000000000000,
|
| 342 |
|
|
32'b00000000010000000000000000000000,
|
| 343 |
|
|
32'b00000000100000000000000000000000,
|
| 344 |
|
|
32'b00000001000000000000000000000000,
|
| 345 |
|
|
32'b00000010000000000000000000000000,
|
| 346 |
|
|
32'b00000100000000000000000000000000,
|
| 347 |
|
|
32'b00001000000000000000000000000000,
|
| 348 |
|
|
32'b00010000000000000000000000000000,
|
| 349 |
|
|
32'b00100000000000000000000000000000,
|
| 350 |
|
|
32'b01000000000000000000000000000000,
|
| 351 |
|
|
32'b10000000000000000000000000000000: ;
|
| 352 |
|
|
default: collision <= collision | sprite_on;
|
| 353 |
|
|
endcase
|
| 354 |
|
|
end
|
| 355 |
|
|
|
| 356 |
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - -
|
| 357 |
|
|
// clock edge #-1
|
| 358 |
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - -
|
| 359 |
|
|
// Compute when to shift sprite bitmaps.
|
| 360 |
|
|
// Set sprite active flag
|
| 361 |
|
|
// Increment working count and address
|
| 362 |
|
|
|
| 363 |
|
|
reg [31:0] spriteShift;
|
| 364 |
|
|
always @(posedge vclk)
|
| 365 |
|
|
for (n = 0; n < NSPR; n = n + 1)
|
| 366 |
6 |
robfinch |
spriteShift[n] <= ((hctr >> lowres) >= sprite_ph[n]);
|
| 367 |
4 |
robfinch |
|
| 368 |
|
|
always @(posedge vclk)
|
| 369 |
|
|
for (n = 0; n < NSPR; n = n + 1)
|
| 370 |
6 |
robfinch |
spriteActive[n] <= (spriteWcnt[n] <= spriteMcnt[n]) && spriteEnable[n];
|
| 371 |
4 |
robfinch |
|
| 372 |
|
|
always @(posedge vclk)
|
| 373 |
|
|
for (n = 0; n < NSPR; n = n + 1)
|
| 374 |
6 |
robfinch |
spriteWcnt[n] <= ((vctr >> lowres) - sprite_pv[n]) * 16'd32;
|
| 375 |
4 |
robfinch |
|
| 376 |
|
|
always @(posedge vclk)
|
| 377 |
|
|
for (n = 0; n < NSPR; n = n + 1)
|
| 378 |
6 |
robfinch |
spriteWaddr[n] <= spriteAddr[n] + spriteWcnt[n][15:2];
|
| 379 |
4 |
robfinch |
|
| 380 |
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - -
|
| 381 |
|
|
// clock edge #0
|
| 382 |
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - -
|
| 383 |
|
|
// Get the sprite display status
|
| 384 |
|
|
// Load the sprite bitmap from ram
|
| 385 |
|
|
// Determine when sprite output should appear
|
| 386 |
|
|
// Shift the sprite bitmap
|
| 387 |
|
|
// Compute color indexes for all sprites
|
| 388 |
|
|
|
| 389 |
|
|
always @(posedge vclk)
|
| 390 |
|
|
begin
|
| 391 |
|
|
for (n = 0; n < NSPR; n = n + 1)
|
| 392 |
|
|
if (spriteActive[n] & spriteShift[n]) begin
|
| 393 |
|
|
sprite_on[n] <=
|
| 394 |
|
|
spriteLink1[n] ? |{spriteBmp[(n+1)&31][63:62],spriteBmp[n][63:62]} :
|
| 395 |
|
|
|spriteBmp[n][63:62];
|
| 396 |
|
|
end
|
| 397 |
|
|
else
|
| 398 |
|
|
sprite_on[n] <= 1'b0;
|
| 399 |
|
|
end
|
| 400 |
|
|
|
| 401 |
|
|
// Load / shift sprite bitmap
|
| 402 |
|
|
// Register sprite data back to vclk domain
|
| 403 |
|
|
always @(posedge vclk)
|
| 404 |
|
|
begin
|
| 405 |
|
|
if (hctr==12'h5)
|
| 406 |
|
|
for (n = 0; n < NSPR; n = n + 1)
|
| 407 |
|
|
spriteBmp[n] <= m_spriteBmp[n];
|
| 408 |
5 |
robfinch |
for (n = 0; n < NSPR; n = n + 1)
|
| 409 |
|
|
if (spriteShift[n])
|
| 410 |
6 |
robfinch |
`ifdef SUPPORT_LOWRES
|
| 411 |
5 |
robfinch |
case(lowres)
|
| 412 |
|
|
2'd0,2'd3: spriteBmp[n] <= {spriteBmp[n][61:0],2'h0};
|
| 413 |
|
|
2'd1: if (hctr[0]) spriteBmp[n] <= {spriteBmp[n][61:0],2'h0};
|
| 414 |
|
|
2'd2: if (&hctr[1:0]) spriteBmp[n] <= {spriteBmp[n][61:0],2'h0};
|
| 415 |
|
|
endcase
|
| 416 |
6 |
robfinch |
`else
|
| 417 |
|
|
spriteBmp[n] <= {spriteBmp[n][61:0],2'h0};
|
| 418 |
|
|
`endif
|
| 419 |
4 |
robfinch |
end
|
| 420 |
|
|
|
| 421 |
|
|
always @(posedge vclk)
|
| 422 |
|
|
for (n = 0; n < NSPR; n = n + 1)
|
| 423 |
5 |
robfinch |
if (spriteLink1[n])
|
| 424 |
4 |
robfinch |
spriteColorNdx[n] <= {n[3:0],spriteBmp[(n+1)&31][63:62],spriteBmp[n][63:62]};
|
| 425 |
5 |
robfinch |
else if (spriteLink1[(n-1)&31])
|
| 426 |
4 |
robfinch |
spriteColorNdx[n] <= 8'h00; // transparent
|
| 427 |
|
|
else
|
| 428 |
5 |
robfinch |
spriteColorNdx[n] <= {1'b0,n[4:0],spriteBmp[n][63:62]};
|
| 429 |
4 |
robfinch |
|
| 430 |
|
|
// Compute index into sprite color palette
|
| 431 |
|
|
// If none of the sprites are linked, each sprite has it's own set of colors.
|
| 432 |
|
|
// If the sprites are linked once the colors are available in groups.
|
| 433 |
|
|
// If the sprites are linked twice they all share the same set of colors.
|
| 434 |
|
|
// Pipelining register
|
| 435 |
6 |
robfinch |
reg border3, border4;
|
| 436 |
4 |
robfinch |
reg any_sprite_on2, any_sprite_on3, any_sprite_on4;
|
| 437 |
|
|
reg [31:0] zrgb_i3, zrgb_i4;
|
| 438 |
|
|
reg [7:0] zb_i3, zb_i4;
|
| 439 |
|
|
reg [7:0] sprite_z1, sprite_z2, sprite_z3, sprite_z4;
|
| 440 |
|
|
reg [7:0] sprite_pzx;
|
| 441 |
|
|
// The color index from each sprite can be mux'ed into a single value used to
|
| 442 |
|
|
// access the color palette because output color is a priority chain. This
|
| 443 |
|
|
// saves having mulriple read ports on the color palette.
|
| 444 |
5 |
robfinch |
reg [37:0] spriteColorOut2;
|
| 445 |
|
|
reg [37:0] spriteColorOut3;
|
| 446 |
4 |
robfinch |
reg [7:0] spriteClrNdx;
|
| 447 |
|
|
|
| 448 |
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - -
|
| 449 |
|
|
// clock edge #1
|
| 450 |
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - -
|
| 451 |
|
|
// Mux color index
|
| 452 |
|
|
// Fetch sprite Z order
|
| 453 |
|
|
|
| 454 |
|
|
always @(posedge vclk)
|
| 455 |
6 |
robfinch |
sprite_on_d1 <= sprite_on;
|
| 456 |
4 |
robfinch |
|
| 457 |
|
|
always @(posedge vclk)
|
| 458 |
|
|
begin
|
| 459 |
|
|
spriteClrNdx <= 8'd0;
|
| 460 |
|
|
for (n = NSPR-1; n >= 0; n = n -1)
|
| 461 |
|
|
if (sprite_on[n])
|
| 462 |
|
|
spriteClrNdx <= spriteColorNdx[n];
|
| 463 |
|
|
end
|
| 464 |
|
|
|
| 465 |
|
|
always @(posedge vclk)
|
| 466 |
|
|
begin
|
| 467 |
5 |
robfinch |
sprite_z1 <= 8'hff;
|
| 468 |
4 |
robfinch |
for (n = NSPR-1; n >= 0; n = n -1)
|
| 469 |
|
|
if (sprite_on[n])
|
| 470 |
|
|
sprite_z1 <= sprite_pz[n];
|
| 471 |
|
|
end
|
| 472 |
|
|
|
| 473 |
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - -
|
| 474 |
|
|
// clock edge #2
|
| 475 |
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - -
|
| 476 |
|
|
// Lookup color from palette
|
| 477 |
|
|
|
| 478 |
|
|
always @(posedge vclk)
|
| 479 |
|
|
sprite_on_d2 <= sprite_on_d1;
|
| 480 |
|
|
always @(posedge vclk)
|
| 481 |
|
|
any_sprite_on2 <= |sprite_on_d1;
|
| 482 |
|
|
always @(posedge vclk)
|
| 483 |
|
|
spriteColorOut2 <= sprite_color[spriteClrNdx];
|
| 484 |
|
|
always @(posedge vclk)
|
| 485 |
|
|
sprite_z2 <= sprite_z1;
|
| 486 |
|
|
|
| 487 |
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - -
|
| 488 |
|
|
// clock edge #3
|
| 489 |
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - -
|
| 490 |
|
|
// Compute alpha blending
|
| 491 |
|
|
|
| 492 |
5 |
robfinch |
wire [15:0] alphaRed = (zrgb_i[23:16] * spriteColorOut2[31:24]) + (spriteColorOut2[23:16] * (9'h100 - spriteColorOut2[31:24]));
|
| 493 |
|
|
wire [15:0] alphaGreen = (zrgb_i[15:8] * spriteColorOut2[31:24]) + (spriteColorOut2[15:8] * (9'h100 - spriteColorOut2[31:24]));
|
| 494 |
|
|
wire [15:0] alphaBlue = (zrgb_i[7:0] * spriteColorOut2[31:24]) + (spriteColorOut2[7:0] * (9'h100 - spriteColorOut2[31:24]));
|
| 495 |
4 |
robfinch |
reg [23:0] alphaOut;
|
| 496 |
|
|
|
| 497 |
|
|
always @(posedge vclk)
|
| 498 |
5 |
robfinch |
alphaOut <= {alphaRed[15:8],alphaGreen[15:8],alphaBlue[15:8]};
|
| 499 |
4 |
robfinch |
always @(posedge vclk)
|
| 500 |
|
|
sprite_z3 <= sprite_z2;
|
| 501 |
|
|
always @(posedge vclk)
|
| 502 |
|
|
any_sprite_on3 <= any_sprite_on2;
|
| 503 |
|
|
always @(posedge vclk)
|
| 504 |
|
|
zrgb_i3 <= zrgb_i;
|
| 505 |
|
|
always @(posedge vclk)
|
| 506 |
|
|
zb_i3 <= zrgb_i[31:24];
|
| 507 |
|
|
always @(posedge vclk)
|
| 508 |
6 |
robfinch |
border3 <= border_i;
|
| 509 |
4 |
robfinch |
always @(posedge vclk)
|
| 510 |
|
|
spriteColorOut3 <= spriteColorOut2;
|
| 511 |
|
|
|
| 512 |
|
|
reg [23:0] flashOut;
|
| 513 |
|
|
wire [23:0] reverseVideoOut = spriteColorOut2[37] ? alphaOut ^ 24'hFFFFFF : alphaOut;
|
| 514 |
|
|
|
| 515 |
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - -
|
| 516 |
|
|
// clock edge #4
|
| 517 |
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - -
|
| 518 |
|
|
// Compute flash output
|
| 519 |
|
|
|
| 520 |
|
|
always @(posedge vclk)
|
| 521 |
|
|
flashOut <= spriteColorOut3[36] ? (((flashcnt[5:2] & spriteColorOut3[35:32])!=4'b0000) ? reverseVideoOut : zrgb_i3) : reverseVideoOut;
|
| 522 |
|
|
always @(posedge vclk)
|
| 523 |
|
|
zrgb_i4 <= zrgb_i3;
|
| 524 |
|
|
always @(posedge vclk)
|
| 525 |
|
|
sprite_z4 <= sprite_z3;
|
| 526 |
|
|
always @(posedge vclk)
|
| 527 |
|
|
any_sprite_on4 <= any_sprite_on3;
|
| 528 |
|
|
always @(posedge vclk)
|
| 529 |
|
|
zb_i4 <= zb_i3;
|
| 530 |
|
|
always @(posedge vclk)
|
| 531 |
|
|
border4 <= border3;
|
| 532 |
|
|
|
| 533 |
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - -
|
| 534 |
|
|
// clock edge #5
|
| 535 |
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - -
|
| 536 |
|
|
// final output registration
|
| 537 |
|
|
|
| 538 |
|
|
always @(posedge dot_clk_i)
|
| 539 |
6 |
robfinch |
casez({border4,any_sprite_on4 & controller_enable})
|
| 540 |
|
|
2'b01: zrgb_o <= (zb_i4 <= sprite_z4) ? zrgb_i4 : {sprite_z4,flashOut};
|
| 541 |
|
|
2'b00: zrgb_o <= zrgb_i4;
|
| 542 |
|
|
2'b1?: zrgb_o <= zrgb_i4;
|
| 543 |
4 |
robfinch |
endcase
|
| 544 |
|
|
|
| 545 |
|
|
endmodule
|
| 546 |
|
|
|