URL
https://opencores.org/ocsvn/rtf_sprite_controller/rtf_sprite_controller/trunk
Subversion Repositories rtf_sprite_controller
Compare Revisions
- This comparison shows the changes necessary to convert path
/rtf_sprite_controller/trunk/rtl/verilog
- from Rev 5 to Rev 6
- ↔ Reverse comparison
Rev 5 → Rev 6
/rtfSpriteController2.v
1,6 → 1,6
// ============================================================================ |
// __ |
// \\__/ o\ (C) 2018 Robert Finch, Waterloo |
// \\__/ o\ (C) 2018-2019 Robert Finch, Waterloo |
// \ __ / All rights reserved. |
// \/_// robfinch<remove>@finitron.ca |
// || |
34,13 → 34,13
// A good value is just before the end of the scan, but that depends on |
// display resolution. |
`define SPR_WCA 12'd638 |
//`define SUPPORT_LOWRES 1'b1 |
|
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, |
dot_clk_i, hsync_i, vsync_i, zrgb_i, zrgb_o, test |
module rtfSpriteController2(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_spriteno_o, |
dot_clk_i, hsync_i, vsync_i, border_i, zrgb_i, zrgb_o, test |
); |
// Bus slave port |
input rst_i; |
input clk_i; |
input cs_i; |
input cyc_i; |
59,33 → 59,33
output [7:0] m_sel_o; |
output reg [`ABITS] m_adr_o; |
input [63:0] m_dat_i; |
output reg [4:0] m_spriteno_o; |
// Video port |
input dot_clk_i; |
input vsync_i; |
input hsync_i; |
input border_i; |
input [31:0] zrgb_i; |
output reg [31:0] zrgb_o; |
input test; |
|
parameter NSPR = 32; |
parameter IDLE = 3'd0; |
parameter DATA_FETCH = 3'd1; |
parameter MEM_ACCESS = 3'd2; |
parameter WAIT_NACK = 3'd3; |
parameter NEXT_SPRITE = 3'd4; |
parameter IDLE = 2'd0; |
parameter DATA_FETCH = 2'd1; |
parameter MEM_ACCESS = 2'd2; |
|
integer n; |
|
reg controller_enable; |
reg controller_enable = 1'b1; |
wire vclk; |
reg [2:0] state; |
reg [1:0] lowres; |
reg [1:0] state = IDLE; |
reg [1:0] lowres = 2'b00; |
wire [5:0] flashcnt; |
reg rst_collision; |
reg rst_collision = 1'b0; |
reg [31:0] collision, c_collision; |
reg [4:0] spriteno; |
reg [4:0] spriteno = 5'd0; |
reg sprite; |
reg [31:0] spriteEnable; |
reg [31:0] spriteEnable = 32'hFFFFFFFF; |
reg [31:0] spriteActive; |
reg [11:0] sprite_pv [0:31]; |
reg [11:0] sprite_ph [0:31]; |
103,19 → 103,27
reg [15:0] spriteWcnt [0:31]; |
reg [63:0] m_spriteBmp [0:31]; |
reg [63:0] spriteBmp [0:31]; |
reg [31:0] spriteLink1; |
reg [31:0] spriteLink1 = 32'h0; |
reg [7:0] spriteColorNdx [0:31]; |
|
initial begin |
for (n = 0; n < 256; n = n + 1) begin |
sprite_color[n] <= 38'h0000FF1F1F; |
sprite_color[n] <= {6'h00,8'h00,n[7:5],5'd0,n[4:3],6'd0,n[2:0],5'd0}; |
// 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 |
end |
for (n = 0; n < 32; n = n + 1) begin |
sprite_ph[n] <= 260 + n * 40; |
sprite_pv[n] <= 41 + n * 20; |
sprite_pz[n] <= 8'h00; |
spriteMcnt[n] <= 60 * 32; |
if (n < 16) begin |
sprite_ph[n] <= 400 + n * 32; |
sprite_pv[n] <= 100 + n * 8; |
end |
else begin |
sprite_ph[n] <= 400 + (n - 16) * 32; |
sprite_pv[n] <= 200 + n * 8; |
end |
sprite_pz[n] <= 8'h08; |
spriteMcnt[n] <= 80 * 32; |
spriteBmp[n] <= 64'hFFFFFFFFFFFFFFFF; |
spriteAddr[n] <= 32'h40000 + (n << 12); |
end |
end |
|
123,67 → 131,87
wire [11:0] hctr, vctr; |
reg [11:0] m_hctr, m_vctr; |
|
// Generate acknowledge signal |
wire cs = cs_i & cyc_i & stb_i; |
reg rdy1,rdy2,rdy3; |
always @(posedge clk_i) |
rdy1 <= cs; |
always @(posedge clk_i) |
rdy2 <= rdy1 & cs; |
always @(posedge clk_i) |
rdy3 <= rdy2 & cs; |
assign ack_o = (cs & we_i) ? 1'b1 : rdy3; |
reg cs; |
reg we; |
reg [7:0] sel; |
reg [11:0] adr; |
reg [63:0] dat; |
|
wire clk; |
`ifdef USE_CLOCK_GATE |
BUFH uclk (.I(clk_i), .O(clk)); |
`else |
wire clk = clk_i; |
`endif |
|
always @(posedge clk) |
cs <= cs_i & cyc_i & stb_i; |
always @(posedge clk) |
we <= we_i; |
always @(posedge clk) |
sel <= sel_i; |
always @(posedge clk) |
adr <= adr_i; |
always @(posedge clk) |
dat <= dat_i; |
|
ack_gen #( |
.READ_STAGES(4), |
.WRITE_STAGES(0), |
.REGISTER_OUTPUT(1) |
) uag1 |
( |
.clk_i(clk), |
.ce_i(1'b1), |
.i(cs), |
.we_i(cs & we), |
.o(ack_o) |
); |
|
(* ram_style="block" *) |
reg [63:0] shadow_ram [0:511]; |
reg [63:0] shadow_ramo; |
reg [8:0] sradr; |
always @(posedge clk_i) |
if (cs & we_i) begin |
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[2]) shadow_ram[adr_i[11:3]][23:16] <= dat_i; |
if (sel_i[3]) shadow_ram[adr_i[11:3]][31:24] <= dat_i; |
if (sel_i[4]) shadow_ram[adr_i[11:3]][39:32] <= dat_i; |
if (sel_i[5]) shadow_ram[adr_i[11:3]][47:40] <= dat_i; |
if (sel_i[6]) shadow_ram[adr_i[11:3]][55:48] <= dat_i; |
if (sel_i[7]) shadow_ram[adr_i[11:3]][63:56] <= dat_i; |
always @(posedge clk) |
if (cs & we) begin |
if (|sel[1:0]) shadow_ram[adr[11:3]][15: 0] <= dat[15: 0]; |
if (|sel[3:2]) shadow_ram[adr[11:3]][31:16] <= dat[31:16]; |
if (|sel[5:4]) shadow_ram[adr[11:3]][47:32] <= dat[47:32]; |
if (|sel[7:6]) shadow_ram[adr[11:3]][63:48] <= dat[63:48]; |
end |
always @(posedge clk_i) |
sradr <= adr_i[11:3]; |
always @(posedge clk_i) |
case(adr_i[11:3]) |
always @(posedge clk) |
sradr <= adr[11:3]; |
always @(posedge clk) |
shadow_ramo <= shadow_ram[sradr]; |
always @(posedge clk) |
case(adr[11:3]) |
9'b1010_0001_0: dat_o <= c_collision; |
default: dat_o <= shadow_ram[sradr]; |
default: dat_o <= shadow_ramo; |
endcase |
|
always @(posedge clk_i) |
if (rst_i) begin |
always @(posedge clk) |
begin |
rst_collision <= `FALSE; |
controller_enable <= `TRUE; |
spriteEnable <= 32'hFFFFFFFF; |
spriteLink1 <= 32'h0; |
end |
else begin |
rst_collision <= `FALSE; |
if (cs & we_i) begin |
casez(adr_i[11:3]) |
9'b0???_????_?: sprite_color[adr_i[10:3]] <= dat_i[37:0]; |
9'b100?_????_0: spriteAddr[adr_i[8:4]] <= dat_i[`ABITS]; |
if (cs & we) begin |
casez(adr[11:3]) |
9'b0???_????_?: sprite_color[adr[10:3]] <= dat[37:0]; |
9'b100?_????_0: spriteAddr[adr[8:4]] <= dat[`ABITS]; |
9'b100?_????_1: |
begin |
if (|sel_i[1:0]) sprite_ph[adr_i[8:4]] <= dat_i[11: 0]; |
if (|sel_i[3:2]) sprite_pv[adr_i[8:4]] <= dat_i[27:16]; |
if ( sel_i[ 4]) sprite_pz[adr_i[8:4]] <= dat_i[39:32]; |
if (|sel_i[7:6]) spriteMcnt[adr_i[8:4]] <= dat_i[63:48]; |
if (|sel[1:0]) sprite_ph[adr[8:4]] <= dat[11: 0]; |
if (|sel[3:2]) sprite_pv[adr[8:4]] <= dat[27:16]; |
if (|sel[5:4]) sprite_pz[adr[8:4]] <= dat[39:32]; |
if (|sel[7:6]) spriteMcnt[adr[8:4]] <= dat[63:48]; |
end |
9'b1010_0000_0: spriteEnable <= dat_i[31:0]; |
9'b1010_0000_1: spriteLink1 <= dat_i[31:0]; |
9'b1010_0000_0: spriteEnable <= dat[31:0]; |
9'b1010_0000_1: spriteLink1 <= dat[31:0]; |
9'b1010_0001_0: rst_collision <= `TRUE; |
9'b1010_0001_1: |
begin |
lowres <= dat_i[1:0]; |
controller_enable <= dat_i[8]; |
lowres <= dat[1:0]; |
controller_enable <= dat[8]; |
end |
default: ; |
endcase |
end |
end |
191,67 → 219,77
assign m_stb_o = m_cyc_o; |
assign m_sel_o = 8'hFF; |
|
wire clkm; |
`ifdef USE_CLOCK_GATE |
BUFHCE uclkm (.I(m_clk_i), .CE(controller_enable), .O(clkm)); |
`else |
wire clkm = m_clk_i; |
`endif |
|
// Register hctr to m_clk_i domain |
always @(posedge m_clk_i) |
always @(posedge clkm) |
m_hctr <= hctr; |
|
// State machine |
always @(posedge m_clk_i) |
if (rst_i) |
state <= IDLE; |
else begin |
case(state) |
IDLE: |
// dot_clk_i is likely faster than m_clk_i, so check for a trigger zone. |
if (m_hctr < 12'd10 && controller_enable) |
state <= DATA_FETCH; |
DATA_FETCH: |
if (spriteActive[spriteno]) |
always @(posedge clkm) |
case(state) |
IDLE: |
// dot_clk_i is likely faster than m_clk_i, so check for a trigger zone. |
if (m_hctr < 12'd10 && controller_enable) |
state <= DATA_FETCH; |
DATA_FETCH: |
if (spriteActive[spriteno]) begin |
if (~m_ack_i) |
state <= MEM_ACCESS; |
else |
state <= NEXT_SPRITE; |
MEM_ACCESS: |
if (m_ack_i) |
state <= WAIT_NACK; |
WAIT_NACK: |
if (~m_ack_i) |
state <= NEXT_SPRITE; |
NEXT_SPRITE: |
end |
else if (spriteno==5'd31) |
state <= IDLE; |
MEM_ACCESS: |
if (m_ack_i|test) begin |
if (spriteno==5'd31) |
state <= IDLE; |
else |
state <= DATA_FETCH; |
endcase |
end |
end |
default: state <= IDLE; |
endcase |
|
always @(posedge m_clk_i) |
if (rst_i) begin |
always @(posedge clkm) |
case(state) |
IDLE: |
m_cyc_o <= `LOW; |
DATA_FETCH: |
if (!m_ack_i && spriteActive[spriteno]) begin |
m_cyc_o <= ~test;//`HIGH; |
m_adr_o <= spriteWaddr[spriteno]; |
m_spriteno_o <= spriteno; |
end |
MEM_ACCESS: |
if (m_ack_i|test) begin |
m_cyc_o <= `LOW; |
m_spriteBmp[spriteno] <= m_dat_i; |
if (test) |
m_spriteBmp[spriteno] <= 64'h00005555AAAAFFFF; |
end |
default: ; |
endcase |
|
always @(posedge clkm) |
case(state) |
IDLE: |
spriteno <= 5'd0; |
end |
else begin |
case(state) |
IDLE: |
spriteno <= 5'd0; |
DATA_FETCH: |
if (spriteActive[spriteno]) begin |
m_cyc_o <= `HIGH; |
m_adr_o <= spriteWaddr[spriteno]; |
end |
MEM_ACCESS: |
if (m_ack_i) begin |
m_cyc_o <= `LOW; |
m_spriteBmp[spriteno] <= dat_i; |
if (test) |
m_spriteBmp[spriteno] <= 64'h00005555AAAAFFFF; |
end |
NEXT_SPRITE: |
DATA_FETCH: |
if (!spriteActive[spriteno]) |
spriteno <= spriteno + 5'd1; |
endcase |
end |
MEM_ACCESS: |
if (m_ack_i|test) |
spriteno <= spriteno + 5'd1; |
default: ; |
endcase |
|
|
// Register collision onto clk_i domain. |
always @(posedge clk_i) |
always @(posedge clk) |
c_collision <= collision; |
|
`ifdef USE_CLOCK_GATE |
268,9 → 306,9
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()); |
|
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()); |
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()); |
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()); |
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()); |
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()); |
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()); |
|
always @(posedge vclk) |
begin |
325,52 → 363,19
reg [31:0] spriteShift; |
always @(posedge vclk) |
for (n = 0; n < NSPR; n = n + 1) |
begin |
spriteShift[n] <= `FALSE; |
case(lowres) |
2'd0,2'd3: if (hctr >= sprite_ph[n]) spriteShift[n] <= `TRUE; |
2'd1: if (hctr[11:1] >= sprite_ph[n]) spriteShift[n] <= `TRUE; |
2'd2: if (hctr[11:2] >= sprite_ph[n]) spriteShift[n] <= `TRUE; |
endcase |
end |
spriteShift[n] <= ((hctr >> lowres) >= sprite_ph[n]); |
|
always @(posedge vclk) |
for (n = 0; n < NSPR; n = n + 1) |
spriteActive[n] = (spriteWcnt[n] <= spriteMcnt[n]) && spriteEnable[n]; |
spriteActive[n] <= (spriteWcnt[n] <= spriteMcnt[n]) && spriteEnable[n]; |
|
always @(posedge vclk) |
for (n = 0; n < NSPR; n = n + 1) |
begin |
case(lowres) |
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'd2: if ((vctr[11:2] == sprite_pv[n]) && (hctr == 12'h005)) spriteWcnt[n] <= 16'd0; |
endcase |
// The following assumes there are at least 640 clocks in a scan line. |
if (hctr==`SPR_WCA) // must be after image data fetch |
if (spriteActive[n]) |
case(lowres) |
2'd0,2'd3: 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; |
endcase |
end |
spriteWcnt[n] <= ((vctr >> lowres) - sprite_pv[n]) * 16'd32; |
|
always @(posedge vclk) |
for (n = 0; n < NSPR; n = n + 1) |
begin |
case(lowres) |
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'd2: if ((vctr[11:2] == sprite_pv[n]) && (hctr == 12'h005)) spriteWaddr[n] <= spriteAddr[n]; |
endcase |
if (hctr==`SPR_WCA) // must be after image data fetch |
case(lowres) |
2'd0,2'd3: spriteWaddr[n] <= spriteWaddr[n] + 32'd8; |
2'd1: if (vctr[0]) spriteWaddr[n] <= spriteWaddr[n] + 32'd8; |
2'd2: if (vctr[1:0]==2'b11) spriteWaddr[n] <= spriteWaddr[n] + 32'd8; |
endcase |
end |
spriteWaddr[n] <= spriteAddr[n] + spriteWcnt[n][15:2]; |
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - |
// clock edge #0 |
402,11 → 407,15
spriteBmp[n] <= m_spriteBmp[n]; |
for (n = 0; n < NSPR; n = n + 1) |
if (spriteShift[n]) |
`ifdef SUPPORT_LOWRES |
case(lowres) |
2'd0,2'd3: spriteBmp[n] <= {spriteBmp[n][61:0],2'h0}; |
2'd1: if (hctr[0]) spriteBmp[n] <= {spriteBmp[n][61:0],2'h0}; |
2'd2: if (&hctr[1:0]) spriteBmp[n] <= {spriteBmp[n][61:0],2'h0}; |
endcase |
`else |
spriteBmp[n] <= {spriteBmp[n][61:0],2'h0}; |
`endif |
end |
|
always @(posedge vclk) |
423,8 → 432,7
// 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. |
// Pipelining register |
reg blank1, blank2, blank3, blank4; |
reg border1, border2, border3, border4; |
reg border3, border4; |
reg any_sprite_on2, any_sprite_on3, any_sprite_on4; |
reg [31:0] zrgb_i3, zrgb_i4; |
reg [7:0] zb_i3, zb_i4; |
444,7 → 452,7
// Fetch sprite Z order |
|
always @(posedge vclk) |
sprite_on_d1 <= sprite_on; |
sprite_on_d1 <= sprite_on; |
|
always @(posedge vclk) |
begin |
472,10 → 480,6
always @(posedge vclk) |
any_sprite_on2 <= |sprite_on_d1; |
always @(posedge vclk) |
blank2 <= blank1; |
always @(posedge vclk) |
border2 <= border1; |
always @(posedge vclk) |
spriteColorOut2 <= sprite_color[spriteClrNdx]; |
always @(posedge vclk) |
sprite_z2 <= sprite_z1; |
501,10 → 505,8
always @(posedge vclk) |
zb_i3 <= zrgb_i[31:24]; |
always @(posedge vclk) |
blank3 <= blank2; |
border3 <= border_i; |
always @(posedge vclk) |
border3 <= border2; |
always @(posedge vclk) |
spriteColorOut3 <= spriteColorOut2; |
|
reg [23:0] flashOut; |
526,8 → 528,6
always @(posedge vclk) |
zb_i4 <= zb_i3; |
always @(posedge vclk) |
blank4 <= blank3; |
always @(posedge vclk) |
border4 <= border3; |
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - |
536,9 → 536,10
// final output registration |
|
always @(posedge dot_clk_i) |
case(any_sprite_on4 & controller_enable) |
1'b1: zrgb_o <= (zb_i4 < sprite_z4) ? zrgb_i4 : {sprite_z4,flashOut}; |
1'b0: zrgb_o <= zrgb_i4; |
casez({border4,any_sprite_on4 & controller_enable}) |
2'b01: zrgb_o <= (zb_i4 <= sprite_z4) ? zrgb_i4 : {sprite_z4,flashOut}; |
2'b00: zrgb_o <= zrgb_i4; |
2'b1?: zrgb_o <= zrgb_i4; |
endcase |
|
endmodule |