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
- from Rev 3 to Rev 4
- ↔ Reverse comparison
Rev 3 → Rev 4
/doc/rtfSpriteController2.docx
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
doc/rtfSpriteController2.docx
Property changes :
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: doc/rtfSpriteController2_WBC.docx
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: doc/rtfSpriteController2_WBC.docx
===================================================================
--- doc/rtfSpriteController2_WBC.docx (nonexistent)
+++ doc/rtfSpriteController2_WBC.docx (revision 4)
doc/rtfSpriteController2_WBC.docx
Property changes :
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: rtl/verilog/rtfSpriteController2.v
===================================================================
--- rtl/verilog/rtfSpriteController2.v (nonexistent)
+++ rtl/verilog/rtfSpriteController2.v (revision 4)
@@ -0,0 +1,550 @@
+// ============================================================================
+// __
+// \\__/ o\ (C) 2018 Robert Finch, Waterloo
+// \ __ / All rights reserved.
+// \/_// robfinch@finitron.ca
+// ||
+//
+// rtfSpriteController2.v
+//
+// This source file is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published
+// by the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This source file is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+// ============================================================================
+//
+`define TRUE 1'b1
+`define FALSE 1'b0
+`define HIGH 1'b1
+`define LOW 1'b0
+
+`define ABITS 31:0
+
+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
+);
+// Bus slave port
+input rst_i;
+input clk_i;
+input cs_i;
+input cyc_i;
+input stb_i;
+output ack_o;
+input we_i;
+input [7:0] sel_i;
+input [11:0] adr_i;
+input [63:0] dat_i;
+output reg [63:0] dat_o;
+// Bus master port
+input m_clk_i;
+output reg m_cyc_o;
+output m_stb_o;
+input m_ack_i;
+output [7:0] m_sel_o;
+output reg [`ABITS] m_adr_o;
+input [63:0] m_dat_i;
+// Video port
+input dot_clk_i;
+input vsync_i;
+input hsync_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;
+
+integer n;
+
+reg controller_enable;
+wire vclk;
+reg [2:0] state;
+reg [1:0] lowres;
+reg [3:0] flashcnt;
+reg rst_collision;
+reg [31:0] collision, c_collision;
+reg [4:0] spriteno;
+reg sprite;
+reg [31:0] spriteEnable;
+reg [31:0] spriteActive;
+reg [11:0] sprite_pv [0:31];
+reg [11:0] sprite_ph [0:31];
+reg [3:0] sprite_pz [0:31];
+reg [37:0] sprite_color [0:255];
+reg [31:0] sprite_on;
+reg [31:0] sprite_on_d1;
+reg [31:0] sprite_on_d2;
+reg [31:0] sprite_on_d3;
+reg [`ABITS] spriteAddr [0:31];
+reg [`ABITS] spriteWaddr [0:31];
+reg [15:0] spriteMcnt [0:31];
+reg [15:0] spriteWcnt [0:31];
+reg [63:0] m_spriteBmp [0:31];
+reg [63:0] spriteBmp [0:31];
+reg [15:0] spriteColor [0:31];
+reg [31:0] spriteLink1;
+reg [11:0] spriteColorNdx [0:31];
+
+initial begin
+ for (n = 0; n < 256; n = n + 1) begin
+ sprite_color[n][31:0] = $urandom;
+ sprite_color[n][37:32] = 6'd0;//$urandom & 6'd63;
+ end
+ for (n = 0; n < 32; n = n + 1) begin
+ sprite_ph[n] <= $urandom%800 + 260;
+ sprite_pv[n] <= $urandom%600 + 41;
+ sprite_pz[n] <= $urandom%256;
+ spriteMcnt[n] <= ($urandom%505 + 5) * 32;
+ end
+end
+
+wire pe_hsync, pe_vsync;
+reg [11:0] hctr, vctr, 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;
+
+(* ram_style="block" *)
+reg [63:0] shadow_ram [0:511];
+reg [10: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;
+ end
+always @(posedge clk_i)
+ sradr <= adr_i[11:3];
+always @(posedge clk_i)
+case(adr_i[11:3])
+9'b1010_0001_0: dat_o <= c_collision;
+default: dat_o <= shadow_ram[sradr];
+endcase
+
+always @(posedge clk_i)
+if (rst_i) begin
+ rst_collision <= `FALSE;
+ controller_enable <= `TRUE;
+ spriteEnable <= 32'hFFFFFFFF;
+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];
+ 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];
+ end
+ 9'b1010_0000_0: spriteEnable <= dat_i[31:0];
+ 9'b1010_0000_1: spriteLink1 <= dat_i[31:0];
+ 9'b1010_0001_0: rst_collision <= `TRUE;
+ 9'b1010_0001_1:
+ begin
+ lowres <= dat_i[1:0];
+ controller_enable <= dat_i[8];
+ end
+ endcase
+ end
+end
+
+assign m_stb_o = m_cyc_o;
+assign m_sel_o = 8'hFF;
+
+// Register hctr to m_clk_i domain
+always @(posedge m_clk_i)
+ 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])
+ 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:
+ if (spriteno==5'd31)
+ state <= IDLE;
+ else
+ state <= DATA_FETCH;
+ endcase
+end
+
+always @(posedge m_clk_i)
+if (rst_i) begin
+ m_cyc_o <= `LOW;
+ 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;
+ spriteBmp[spriteno] <= dat_i;
+ if (test)
+ spriteBmp[spriteno] <= 64'hFFFFFFFFFFFFFFFF;
+ end
+ NEXT_SPRITE:
+ spriteno <= spriteno + 5'd1;
+ endcase
+end
+
+// Register collision onto clk_i domain.
+always @(posedge clk_i)
+ c_collision <= collision;
+
+BUFHCE ucb1
+(
+ .I(dot_clk_i),
+ .CE(controller_enable),
+ .O(vclk)
+);
+
+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());
+
+always @(posedge vclk)
+if (rst_i)
+ hctr <= 12'd0;
+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)
+begin
+ if (rst_collision)
+ collision <= 32'd0;
+ else
+ case(sprite_on)
+ 32'b00000000000000000000000000000000,
+ 32'b00000000000000000000000000000001,
+ 32'b00000000000000000000000000000010,
+ 32'b00000000000000000000000000000100,
+ 32'b00000000000000000000000000001000,
+ 32'b00000000000000000000000000010000,
+ 32'b00000000000000000000000000100000,
+ 32'b00000000000000000000000001000000,
+ 32'b00000000000000000000000010000000,
+ 32'b00000000000000000000000100000000,
+ 32'b00000000000000000000001000000000,
+ 32'b00000000000000000000010000000000,
+ 32'b00000000000000000000100000000000,
+ 32'b00000000000000000001000000000000,
+ 32'b00000000000000000010000000000000,
+ 32'b00000000000000000100000000000000,
+ 32'b00000000000000001000000000000000,
+ 32'b00000000000000010000000000000000,
+ 32'b00000000000000100000000000000000,
+ 32'b00000000000001000000000000000000,
+ 32'b00000000000010000000000000000000,
+ 32'b00000000000100000000000000000000,
+ 32'b00000000001000000000000000000000,
+ 32'b00000000010000000000000000000000,
+ 32'b00000000100000000000000000000000,
+ 32'b00000001000000000000000000000000,
+ 32'b00000010000000000000000000000000,
+ 32'b00000100000000000000000000000000,
+ 32'b00001000000000000000000000000000,
+ 32'b00010000000000000000000000000000,
+ 32'b00100000000000000000000000000000,
+ 32'b01000000000000000000000000000000,
+ 32'b10000000000000000000000000000000: ;
+ default: collision <= collision | sprite_on;
+ endcase
+end
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - -
+// clock edge #-1
+// - - - - - - - - - - - - - - - - - - - - - - - - - -
+// Compute when to shift sprite bitmaps.
+// Set sprite active flag
+// Increment working count and address
+
+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
+
+always @(posedge vclk)
+for (n = 0; n < NSPR; n = n + 1)
+ 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==12'd638) // 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
+
+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==12'd638) // must be after image data fetch
+ case(lowres)
+ 2'd0,2'd3: spriteWaddr[n] <= spriteWaddr[n] + 32'd16;
+ 2'd1: if (vctr[0]) spriteWaddr[n] <= spriteWaddr[n] + 32'd16;
+ 2'd2: if (vctr[1:0]==2'b11) spriteWaddr[n] <= spriteWaddr[n] + 32'd16;
+ endcase
+ end
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - -
+// clock edge #0
+// - - - - - - - - - - - - - - - - - - - - - - - - - -
+// Get the sprite display status
+// Load the sprite bitmap from ram
+// Determine when sprite output should appear
+// Shift the sprite bitmap
+// Compute color indexes for all sprites
+
+always @(posedge vclk)
+begin
+ for (n = 0; n < NSPR; n = n + 1)
+ if (spriteActive[n] & spriteShift[n]) begin
+ sprite_on[n] <=
+ spriteLink1[n] ? |{spriteBmp[(n+1)&31][63:62],spriteBmp[n][63:62]} :
+ |spriteBmp[n][63:62];
+ end
+ else
+ sprite_on[n] <= 1'b0;
+end
+
+// Load / shift sprite bitmap
+// Register sprite data back to vclk domain
+always @(posedge vclk)
+begin
+ if (hctr==12'h5)
+ for (n = 0; n < NSPR; n = n + 1)
+ spriteBmp[n] <= m_spriteBmp[n];
+ for (n = 0; n < NSPR; n = n + 1)
+ if (spriteShift[n])
+ 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
+end
+
+always @(posedge vclk)
+for (n = 0; n < NSPR; n = n + 1)
+if (spriteLink1[n]) begin
+ spriteColorNdx[n] <= {n[3:0],spriteBmp[(n+1)&31][63:62],spriteBmp[n][63:62]};
+end
+else if (spriteLink1[(n-1)&31]) begin
+ spriteColorNdx[n] <= 8'h00; // transparent
+end
+else
+ spriteColorNdx[n] <= {n[4:0],spriteBmp[n][63:62]};
+
+// Compute index into sprite color palette
+// 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 twice they all share the same set of colors.
+// Pipelining register
+reg blank1, blank2, blank3, blank4;
+reg border1, border2, 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;
+reg [7:0] sprite_z1, sprite_z2, sprite_z3, sprite_z4;
+reg [7:0] sprite_pzx;
+// 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
+// saves having mulriple read ports on the color palette.
+reg [31:0] spriteColorOut2;
+reg [31:0] spriteColorOut3;
+reg [7:0] spriteClrNdx;
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - -
+// clock edge #1
+// - - - - - - - - - - - - - - - - - - - - - - - - - -
+// Mux color index
+// Fetch sprite Z order
+
+always @(posedge vclk)
+ sprite_on_d1 <= sprite_on;
+
+always @(posedge vclk)
+begin
+ spriteClrNdx <= 8'd0;
+ for (n = NSPR-1; n >= 0; n = n -1)
+ if (sprite_on[n])
+ spriteClrNdx <= spriteColorNdx[n];
+end
+
+always @(posedge vclk)
+begin
+ sprite_z1 <= 3'h7;
+ for (n = NSPR-1; n >= 0; n = n -1)
+ if (sprite_on[n])
+ sprite_z1 <= sprite_pz[n];
+end
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - -
+// clock edge #2
+// - - - - - - - - - - - - - - - - - - - - - - - - - -
+// Lookup color from palette
+
+always @(posedge vclk)
+ sprite_on_d2 <= sprite_on_d1;
+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;
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - -
+// clock edge #3
+// - - - - - - - - - - - - - - - - - - - - - - - - - -
+// Compute alpha blending
+
+wire [12: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 [12:0] alphaBlue = zrgb_i[7:0] * spriteColorOut2[31:24] + (spriteColorOut2[7:0] * (9'h100 - spriteColorOut2[31:24]));
+reg [23:0] alphaOut;
+
+always @(posedge vclk)
+ alphaOut <= {alphaRed[12:5],alphaGreen[12:5],alphaBlue[12:5]};
+always @(posedge vclk)
+ sprite_z3 <= sprite_z2;
+always @(posedge vclk)
+ any_sprite_on3 <= any_sprite_on2;
+always @(posedge vclk)
+ zrgb_i3 <= zrgb_i;
+always @(posedge vclk)
+ zb_i3 <= zrgb_i[31:24];
+always @(posedge vclk)
+ blank3 <= blank2;
+always @(posedge vclk)
+ border3 <= border2;
+always @(posedge vclk)
+ spriteColorOut3 <= spriteColorOut2;
+
+reg [23:0] flashOut;
+wire [23:0] reverseVideoOut = spriteColorOut2[37] ? alphaOut ^ 24'hFFFFFF : alphaOut;
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - -
+// clock edge #4
+// - - - - - - - - - - - - - - - - - - - - - - - - - -
+// Compute flash output
+
+always @(posedge vclk)
+ flashOut <= spriteColorOut3[36] ? (((flashcnt[5:2] & spriteColorOut3[35:32])!=4'b0000) ? reverseVideoOut : zrgb_i3) : reverseVideoOut;
+always @(posedge vclk)
+ zrgb_i4 <= zrgb_i3;
+always @(posedge vclk)
+ sprite_z4 <= sprite_z3;
+always @(posedge vclk)
+ any_sprite_on4 <= any_sprite_on3;
+always @(posedge vclk)
+ zb_i4 <= zb_i3;
+always @(posedge vclk)
+ blank4 <= blank3;
+always @(posedge vclk)
+ border4 <= border3;
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - -
+// clock edge #5
+// - - - - - - - - - - - - - - - - - - - - - - - - - -
+// final output registration
+
+always @(posedge dot_clk_i)
+ 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'b0: zrgb_o <= zrgb_i4;
+ endcase
+
+endmodule
+