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