OpenCores
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
    from Rev 6 to Rev 7
    Reverse comparison

Rev 6 → Rev 7

/verilog/rfSpriteController.sv
0,0 → 1,1305
`timescale 1ns / 1ps
// ============================================================================
// __
// \\__/ o\ (C) 2005-2022 Robert Finch, Waterloo
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
// rfSpriteController.sv
// sprite / hardware cursor controller
//
// BSD 3-Clause License
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//
// Sprite Controller
//
// FEATURES
// - parameterized number of sprites 1,2,4,6,8,14,16 or 32
// - sprite image cache buffers
// - each image cache is capable of holding multiple
// sprite images
// - an embedded DMA controller is used for sprite reload
// - programmable image offset within cache
// - programmable sprite width,height, and pixel size
// - sprite width and height may vary from 1 to 256 as long
// as the product doesn't exceed 4096.
// - pixels may be programmed to be 1,2,3 or 4 video clocks
// both height and width are programmable
// - programmable sprite position
// - programmable 8, 16 or 32 bits for color
// eg 32k color + 1 bit alpha blending indicator (1,5,5,5)
// - fixed display and DMA priority
// sprite 0 highest, sprite 31 lowest
// - graphics plane control
//
// This core requires an external timing generator to
// provide horizontal and vertical sync signals, but
// otherwise can be used as a display controller on it's
// own. However, normally this core would be embedded
// within another core such as a VGA controller. Sprite
// positions are referenced to the rising edge of the
// vertical and horizontal sync pulses.
// The core includes an embedded dual port RAM to hold the
// sprite images. The image RAM is updated using a built in DMA
// controller. The DMA controller uses 32 bit accesses to fill
// the sprite buffers. The circuit features an automatic bus
// transaction timeout; if the system bus hasn't responded
// within 20 clock cycles, the DMA controller moves onto the
// next address.
// The controller uses a ram underlay to cache the values
// of the registers. This is a lot cheaper resource wise than
// using a 32 to 1 multiplexor (well at least for an FPGA).
//
// All registers are 32 bits wide
//
// These registers repeat in incrementing block of four registers
// and pertain to each sprite
// 00: - position register
// HPOS [11: 0] horizontal position (hctr value)
// VPOS [27:16] vertical position (vctr value)
//
// 04: SZ - size register
// bits
// [ 7: 0] width of sprite in pixels - 1
// [15: 8] height of sprite in pixels -1
// [19:16] size of horizontal pixels - 1 in clock cycles
// [23:20] size of vertical pixels in scan-lines - 1
// * the product of width * height cannot exceed 2048 !
// if it does, the display will begin repeating
// [27:24] output plane
// [31:30] color depth 01=RGB332,10=RGB555+A,11=RGB888+A
//
// 08: ADR [31:12] 20 bits sprite image address bits
// This registers contain the high order address bits of the
// location of the sprite image in system memory.
// The DMA controller will assign the low order 12 bits
// during DMA.
// [11:0] image offset bits [11:0]
// offset of the sprite image within the sprite image cache
// typically zero
//
// 0C: TC [23:0] transparent color
// This register identifies which color of the sprite
// is transparent
//
//
//
// 0C-1FC: registers reserved for up to thirty-one other sprites
//
// 200: DMA burst reg sprite 0
// [8:0] burst start
// [24:16] burst end
// ...
// 27C: DMA burst reg sprite 31
//
// 280: [ 7: 0] Frame size, multiples of 16 pixels
// [15: 8] Number of frames of animation
// [25:16] Animation Rate
// [29:26] Frame size, LSBs 0 to 3
// [30] Auto repeat
// [31] Enable animation
// ...
// 2FC: Animation register sprite #31
//
// Global status and control
// 3C0: EN [31:0] sprite enable register
// 3C4: IE [31:0] sprite interrupt enable / status
// 3C8: SCOL [31:0] sprite-sprite collision register
// 3CC: BCOL [31:0] sprite-background collision register
// 3D0: DT [31:0] sprite DMA trigger on
// 3D4: DT [31:0] sprite DMA trigger off
// 3D8: VDT [31:0] sprite vertical sync DMA trigger
// 3EC: BC [29:0] background color
// 3FC: ADDR [31:0] sprite DMA address bits [63:32]
//
//=============================================================================
 
import wishbone_pkg::*;
 
module rfSpriteController(
// Bus Slave interface
//------------------------------
// Slave signals
input rst_i, // reset
input s_clk_i, // clock
input s_cs_i,
input wb_write_request32_t wbs_req,
output wb_read_response32_t wbs_resp,
//------------------------------
// Bus Master Signals
input m_clk_i, // clock
output wb_write_request128_t wbm_req,
input wb_read_response128_t wbm_resp,
output [4:0] m_spriteno_o,
//--------------------------
input dot_clk_i, // video dot clock
input hsync_i, // horizontal sync pulse
input vsync_i, // vertical sync pulse
input blank_i, // blanking signal
input [39:0] zrgb_i, // input pixel stream
output [39:0] zrgb_o, // output pixel stream 12-12-12-4
output irq, // interrupt request
input test,
input xonoff_i
);
 
reg m_soc_o;
wire vclk = dot_clk_i;
wire hSync = hsync_i;
wire vSync = vsync_i;
reg [39:0] zrgb_o;
 
//--------------------------------------------------------------------
// Core Parameters
//--------------------------------------------------------------------
parameter pnSpr = 32; // number of sprites
parameter phBits = 12; // number of bits in horizontal timing counter
parameter pvBits = 12; // number of bits in vertical timing counter
localparam pnSprm = pnSpr-1;
 
 
//--------------------------------------------------------------------
// Variable Declarations
//--------------------------------------------------------------------
 
reg ce; // controller enable
wb_write_request32_t wb_reqs; // synchronized request
 
wire [4:0] sprN = wb_reqs.adr[8:4];
 
reg [phBits-1:0] hctr; // horizontal reference counter (counts dots since hSync)
reg [pvBits-1:0] vctr; // vertical reference counter (counts scanlines since vSync)
reg sprSprIRQ;
reg sprBkIRQ;
 
reg [31:0] out; // sprite output
reg outact; // sprite output is active
reg [3:0] outplane;
reg [pnSprm:0] bkCollision; // sprite-background collision
reg [29:0] bgTc; // background transparent color
reg [29:0] bkColor; // background color
 
 
reg [pnSprm:0] sprWe; // block ram write enable for image cache update
reg [pnSprm:0] sprRe; // block ram read enable for image cache update
 
// Global control registers
reg [31:0] sprEn; // enable sprite
reg [pnSprm:0] sprCollision; // sprite-sprite collision
reg sprSprIe; // sprite-sprite interrupt enable
reg sprBkIe; // sprite-background interrupt enable
reg sprSprIRQPending; // sprite-sprite collision interrupt pending
reg sprBkIRQPending; // sprite-background collision interrupt pending
reg sprSprIRQPending1; // sprite-sprite collision interrupt pending
reg sprBkIRQPending1; // sprite-background collision interrupt pending
reg sprSprIRQ1; // vclk domain regs
reg sprBkIRQ1;
 
// Sprite control registers
reg [31:0] sprSprCollision;
reg [pnSprm:0] sprSprCollision1;
reg [31:0] sprBkCollision;
reg [pnSprm:0] sprBkCollision1;
reg [23:0] sprTc [pnSprm:0]; // sprite transparent color code
// How big the pixels are:
// 1 to 16 video clocks
reg [3:0] hSprRes [pnSprm:0]; // sprite horizontal resolution
reg [3:0] vSprRes [pnSprm:0]; // sprite vertical resolution
reg [7:0] sprWidth [pnSprm:0]; // number of pixels in X direction
reg [7:0] sprHeight [pnSprm:0]; // number of vertical pixels
reg [3:0] sprPlane [pnSprm:0]; // output plane sprite is in
reg [1:0] sprColorDepth [pnSprm:0];
reg [1:0] colorBits;
// Sprite DMA control
reg [8:0] sprBurstStart [pnSprm:0];
reg [8:0] sprBurstEnd [pnSprm:0];
reg [31:0] vSyncT; // DMA on vSync
 
// display and timing signals
reg [31:0] hSprReset; // horizontal reset
reg [31:0] vSprReset; // vertical reset
reg [31:0] hSprDe; // sprite horizontal display enable
reg [31:0] vSprDe; // sprite vertical display enable
reg [31:0] sprDe; // display enable
reg [phBits-1:0] hSprPos [pnSprm:0]; // sprite horizontal position
reg [pvBits-1:0] vSprPos [pnSprm:0]; // sprite vertical position
reg [7:0] hSprCnt [pnSprm:0]; // sprite horizontal display counter
reg [7:0] vSprCnt [pnSprm:0]; // vertical display counter
reg [11:0] sprImageOffs [pnSprm:0]; // offset within sprite memory
reg [12:0] sprAddr [pnSprm:0]; // index into sprite memory (pixel number)
reg [9:0] sprAddr1 [pnSprm:0]; // index into sprite memory
reg [2:0] sprAddr2 [pnSprm:0]; // index into sprite memory
reg [2:0] sprAddr3 [pnSprm:0]; // index into sprite memory
reg [2:0] sprAddr4 [pnSprm:0]; // index into sprite memory
reg [2:0] sprAddr5 [pnSprm:0]; // index into sprite memory
reg [11:0] sprAddrB [pnSprm:0]; // backup address cache for rescan
wire [31:0] sprOut4 [pnSprm:0]; // sprite image data output
reg [31:0] sprOut [pnSprm:0]; // sprite image data output
reg [31:0] sprOut5 [pnSprm:0]; // sprite image data output
 
// Animation
reg [11:0] sprFrameSize [pnSprm:0];
reg [7:0] sprFrames [pnSprm:0];
reg [7:0] sprCurFrame [pnSprm:0];
reg [9:0] sprRate [pnSprm:0];
reg [9:0] sprCurRateCount [pnSprm:0];
reg [pnSprm:0] sprEnableAnimation;
reg [pnSprm:0] sprAutoRepeat;
 
// DMA access
reg [31:12] sprSysAddr [pnSprm:0]; // system memory address of sprite image (low bits)
reg [4:0] dmaOwner; // which sprite has the DMA channel
reg [31:0] sprDt; // DMA trigger register
reg dmaActive; // this flag indicates that a block DMA transfer is active
 
genvar g;
 
//--------------------------------------------------------------------
// DMA control / bus interfacing
//--------------------------------------------------------------------
reg cs_regs;
always_ff @(posedge s_clk_i)
cs_regs <= wbs_req.cyc & wbs_req.stb & s_cs_i;
always_ff @(posedge s_clk_i)
wb_reqs <= wbs_req;
 
wire s_ack_o;
ack_gen #(
.READ_STAGES(3),
.WRITE_STAGES(1),
.REGISTER_OUTPUT(1)
)
uag1 (
.clk_i(s_clk_i),
.ce_i(1'b1),
.i(cs_regs),
.we_i(cs_regs & wb_reqs.we),
.o(s_ack_o),
.rid_i(0),
.wid_i(0),
.rid_o(),
.wid_o()
);
always_comb
begin
wbs_resp.ack = s_ack_o & wbs_req.cyc & wbs_req.stb;
wbs_resp.next = s_ack_o & wbs_req.cyc & wbs_req.stb;
end
 
assign irq = sprSprIRQ|sprBkIRQ;
 
//--------------------------------------------------------------------
// DMA control / bus interfacing
//--------------------------------------------------------------------
 
reg [5:0] dmaStart;
reg [8:0] cob; // count of burst cycles
 
assign wbm_req.bte = LINEAR;
assign wbm_req.cti = CLASSIC;
assign wbm_req.stb = wbm_req.cyc;
assign wbm_req.sel = 16'hFFFF;
assign wbm_req.cid = 4'd5;
assign m_spriteno_o = dmaOwner;
 
reg [2:0] mstate;
parameter IDLE = 3'd0;
parameter ACTIVE = 3'd1;
parameter ACK = 3'd2;
parameter NACK = 3'd3;
 
wire pe_m_ack_i;
edge_det ued2 (.rst(rst_i), .clk(m_clk_i), .ce(1'b1), .i(wbm_resp.ack), .pe(pe_m_ack_i), .ne(), .ee());
 
always_ff @(posedge m_clk_i)
if (rst_i)
mstate <= IDLE;
else begin
case(mstate)
IDLE:
if (|sprDt & ce)
mstate <= ACTIVE;
ACTIVE:
mstate <= ACK;
ACK:
if (wbm_resp.ack | wbm_resp.err)
mstate <= NACK;
NACK:
if (~(wbm_resp.ack|wbm_resp.err))
mstate <= cob==sprBurstEnd[dmaOwner] ? IDLE : ACTIVE;
default:
mstate <= IDLE;
endcase
end
 
integer n30;
always_ff @(posedge m_clk_i)
begin
case(mstate)
IDLE:
begin
dmaOwner <= 5'd0;
for (n30 = pnSprm; n30 >= 0; n30 = n30 - 1)
if (sprDt[n30])
dmaOwner <= n30;
end
default: ;
endcase
end
 
always_ff @(posedge m_clk_i)
if (rst_i)
dmaStart <= 6'b0;
else begin
dmaStart <= {dmaStart[4:0],1'b0};
case(mstate)
IDLE:
if (|sprDt & ce)
dmaStart <= 6'h3F;
default: ;
endcase
end
 
integer n32;
always_ff @(posedge m_clk_i)
begin
case(mstate)
IDLE:
for (n32 = pnSprm; n32 >= 0; n32 = n32 - 1)
if (sprDt[n32])
cob <= sprBurstStart[n32];
ACTIVE:
cob <= cob + 2'd2;
default: ;
endcase
end
 
always_ff @(posedge m_clk_i)
if (rst_i)
wb_m_nack();
else begin
case(mstate)
IDLE:
wb_m_nack();
ACTIVE:
begin
wbm_req.cyc <= 1'b1;
wbm_req.adr <= {sprSysAddr[dmaOwner],cob[8:1],4'h0};
end
ACK:
if (wbm_resp.ack|wbm_resp.err)
wb_m_nack();
endcase
end
 
task wb_m_nack;
begin
wbm_req.cyc <= 1'b0;
end
endtask
 
 
// generate a write enable strobe for the sprite image memory
integer n1;
reg [8:0] m_adr_or;
reg [127:0] m_dat_ir;
reg ack1;
 
always_ff @(posedge m_clk_i)
for (n1 = 0; n1 < pnSpr; n1 = n1 + 1)
sprWe[n1] <= (dmaOwner==n1 && (pe_m_ack_i||ack1));
 
always_ff @(posedge m_clk_i)
ack1 <= pe_m_ack_i;
always_ff @(posedge m_clk_i)
if (pe_m_ack_i|ack1)
m_adr_or <= {wbm_req.adr[11:4],ack1};
always_ff @(posedge m_clk_i)
if (pe_m_ack_i) begin
if (test)
m_dat_ir <= {8{1'b0,dmaOwner,10'b0}};
else
m_dat_ir <= {wbm_resp.dat[63:0],wbm_resp.dat[127:64]};
end
else if (ack1)
m_dat_ir <= {64'd0,m_dat_ir[127:64]};
 
 
//--------------------------------------------------------------------
//--------------------------------------------------------------------
 
reg [31:0] reg_shadow [0:255];
reg [7:0] radr;
always_ff @(posedge s_clk_i)
begin
if (cs_regs & wb_reqs.we & wb_reqs.sel[0]) reg_shadow[wb_reqs.adr[9:2]][7:0] <= wb_reqs.dat[7:0];
if (cs_regs & wb_reqs.we & wb_reqs.sel[1]) reg_shadow[wb_reqs.adr[9:2]][15:8] <= wb_reqs.dat[15:8];
if (cs_regs & wb_reqs.we & wb_reqs.sel[2]) reg_shadow[wb_reqs.adr[9:2]][23:16] <= wb_reqs.dat[23:16];
if (cs_regs & wb_reqs.we & wb_reqs.sel[3]) reg_shadow[wb_reqs.adr[9:2]][31:24] <= wb_reqs.dat[31:24];
end
always @(posedge s_clk_i)
radr <= wb_reqs.adr[9:2];
wire [31:0] reg_shadow_o = reg_shadow[radr];
 
// register/sprite memory output mux
always_ff @(posedge s_clk_i)
if (cs_regs)
case (wb_reqs.adr[9:2]) // synopsys full_case parallel_case
8'b11110000: wbs_resp.dat <= sprEn;
8'b11110001: wbs_resp.dat <= {sprBkIRQPending|sprSprIRQPending,5'b0,sprBkIRQPending,sprSprIRQPending,6'b0,sprBkIe,sprSprIe};
8'b11110010: wbs_resp.dat <= sprSprCollision;
8'b11110011: wbs_resp.dat <= sprBkCollision;
8'b11110100: wbs_resp.dat <= sprDt;
default: wbs_resp.dat <= reg_shadow_o;
endcase
else
wbs_resp.dat <= 32'h0;
 
 
// vclk -> clk_i
always @(posedge s_clk_i)
begin
sprSprIRQ <= sprSprIRQ1;
sprBkIRQ <= sprBkIRQ1;
sprSprIRQPending <= sprSprIRQPending1;
sprBkIRQPending <= sprBkIRQPending1;
sprSprCollision <= sprSprCollision1;
sprBkCollision <= sprBkCollision1;
end
 
 
// register updates
// on the clk_i domain
reg vSync1;
integer n33;
always_ff @(posedge s_clk_i)
if (rst_i) begin
vSyncT <= 32'hFFFF0000;//FFFFFFFF;
sprEn <= 32'hFFFFFFFF;
sprDt <= 0;
for (n33 = 0; n33 < pnSpr; n33 = n33 + 1) begin
sprSysAddr[n33] <= 20'b0000_0000_0011_0000_0000 + n33; //0030_0000
end
sprSprIe <= 0;
sprBkIe <= 0;
 
// Set reasonable starting positions on the screen
// so that the sprites might be visible for testing
for (n33 = 0; n33 < pnSpr; n33 = n33 + 1) begin
hSprPos[n33] <= 200 + (n33 & 7) * 70;
vSprPos[n33] <= 100 + (n33 >> 3) * 100;
sprTc[n33] <= 24'h7FFF; // White 16 bpp
sprWidth[n33] <= 8'd16; // 16x16 sprites
sprHeight[n33] <= 8'd16;
hSprRes[n33] <= 2; // our standard display
vSprRes[n33] <= 2;
sprImageOffs[n33] <= 0;
sprPlane[n33] <= 4'hF;//n[3:0];
sprBurstStart[n33] <= 9'h000;
sprBurstEnd[n33] <= 9'h1FE;
sprColorDepth[n33] <= 2'b10;
sprFrameSize[n33] <= 12'd256;
sprFrames[n33] <= 8'd5;
sprRate[n33] <= 12'd10;
sprEnableAnimation[n33] <= 1'b1;
sprAutoRepeat[n33] <= 1'b1;
end
hSprPos[0] <= 210;
vSprPos[0] <= 72;
 
bgTc <= 24'h08_08_08;
bkColor <= 24'hFF_FF_60;
end
else begin
ce <= xonoff_i;
vSync1 <= vSync;
if (vSync & ~vSync1)
sprDt <= sprDt | vSyncT;
 
// clear DMA trigger bit once DMA is recognized
if (dmaStart[5])
sprDt[dmaOwner] <= 1'b0;
 
// Disable animation after frame count expired, if not auto-repeat.
for (n33 = 0; n33 < pnSpr; n33 = n33 + 1)
if (sprCurFrame[n33] >= sprFrames[n33] && !sprAutoRepeat[n33])
sprEnableAnimation[n33] <= 1'b0;
 
if (cs_regs & wb_reqs.we) begin
 
casez (wb_reqs.adr[9:2])
8'b100?????:
begin
if (&wb_reqs.sel[1:0]) sprBurstStart[wb_reqs.adr[6:2]] <= {wb_reqs.dat[8:1],1'b0};
if (&wb_reqs.sel[3:2]) sprBurstEnd[wb_reqs.adr[6:2]] <= {wb_reqs.dat[24:17],1'b0};
end
8'b101?????:
begin
if (wb_reqs.sel[0]) sprFrameSize[wb_reqs.adr[6:2]][11:4] <= wb_reqs.dat[7:0];
if (wb_reqs.sel[1]) sprFrames[wb_reqs.adr[6:2]] <= wb_reqs.dat[15:8];
if (wb_reqs.sel[2]) sprRate[wb_reqs.adr[6:2]][7:0] <= wb_reqs.dat[23:16];
if (wb_reqs.sel[3])
begin
sprRate[wb_reqs.adr[6:2]][9:8] <= wb_reqs.dat[25:24];
sprFrameSize[wb_reqs.adr[6:2]][3:0] <= wb_reqs.dat[29:26];
sprAutoRepeat[wb_reqs.adr[6:2]] <= wb_reqs.dat[30];
sprEnableAnimation[wb_reqs.adr[6:2]] <= wb_reqs.dat[31];
end
end
8'b11110000: // 3C0
begin
if (wb_reqs.sel[0]) sprEn[7:0] <= wb_reqs.dat[7:0];
if (wb_reqs.sel[1]) sprEn[15:8] <= wb_reqs.dat[15:8];
if (wb_reqs.sel[2]) sprEn[23:16] <= wb_reqs.dat[23:16];
if (wb_reqs.sel[3]) sprEn[31:24] <= wb_reqs.dat[31:24];
end
8'b11110001: // 3C4
if (wb_reqs.sel[0]) begin
sprSprIe <= wb_reqs.dat[0];
sprBkIe <= wb_reqs.dat[1];
end
// update DMA trigger
// s_wb_reqs.dat[7:0] indicates which triggers to set (1=set,0=ignore)
// s_wb_reqs.dat[7:0] indicates which triggers to clear (1=clear,0=ignore)
8'b11110100: // 3D0
begin
if (wb_reqs.sel[0]) sprDt[7:0] <= sprDt[7:0] | wb_reqs.dat[7:0];
if (wb_reqs.sel[1]) sprDt[15:8] <= sprDt[15:8] | wb_reqs.dat[15:8];
if (wb_reqs.sel[2]) sprDt[23:16] <= sprDt[23:16] | wb_reqs.dat[23:16];
if (wb_reqs.sel[3]) sprDt[31:24] <= sprDt[31:24] | wb_reqs.dat[31:24];
end
8'b11110101: // 3D4
begin
if (wb_reqs.sel[0]) sprDt[7:0] <= sprDt[7:0] & ~wb_reqs.dat[7:0];
if (wb_reqs.sel[1]) sprDt[15:8] <= sprDt[15:8] & ~wb_reqs.dat[15:8];
if (wb_reqs.sel[2]) sprDt[23:16] <= sprDt[23:16] & ~wb_reqs.dat[23:16];
if (wb_reqs.sel[3]) sprDt[31:24] <= sprDt[31:24] & ~wb_reqs.dat[31:24];
end
8'b11110110: // 3D8
begin
if (wb_reqs.sel[0]) vSyncT[7:0] <= wb_reqs.dat[7:0];
if (wb_reqs.sel[1]) vSyncT[15:8] <= wb_reqs.dat[15:8];
if (wb_reqs.sel[2]) vSyncT[23:16] <= wb_reqs.dat[23:16];
if (wb_reqs.sel[3]) vSyncT[31:24] <= wb_reqs.dat[31:24];
end
8'b11111010: // 3E8
begin
if (wb_reqs.sel[0]) bgTc[7:0] <= wb_reqs.dat[7:0];
if (wb_reqs.sel[1]) bgTc[15:8] <= wb_reqs.dat[15:8];
if (wb_reqs.sel[2]) bgTc[23:16] <= wb_reqs.dat[23:16];
if (wb_reqs.sel[3]) bgTc[29:24] <= wb_reqs.dat[29:24];
end
8'b11111011: // 3EC
begin
if (wb_reqs.sel[0]) bkColor[7:0] <= wb_reqs.dat[7:0];
if (wb_reqs.sel[1]) bkColor[15:8] <= wb_reqs.dat[15:8];
if (wb_reqs.sel[2]) bkColor[23:16] <= wb_reqs.dat[23:16];
if (wb_reqs.sel[3]) bkColor[29:24] <= wb_reqs.dat[29:24];
end
// 8'b11111100: // 3F0
// if (wb_reqs.sel[0]) ce <= wb_reqs[0];
8'b0?????00:
begin
if (wb_reqs.sel[0]) hSprPos[sprN][ 7:0] <= wb_reqs.dat[ 7: 0];
if (wb_reqs.sel[1]) hSprPos[sprN][11:8] <= wb_reqs.dat[11: 8];
if (wb_reqs.sel[2]) vSprPos[sprN][ 7:0] <= wb_reqs.dat[23:16];
if (wb_reqs.sel[3]) vSprPos[sprN][11:8] <= wb_reqs.dat[27:24];
end
8'b0?????01:
begin
if (wb_reqs.sel[0]) begin
sprWidth[sprN] <= wb_reqs.dat[7:0];
end
if (wb_reqs.sel[1]) begin
sprHeight[sprN] <= wb_reqs.dat[15:8];
end
if (wb_reqs.sel[2]) begin
hSprRes[sprN] <= wb_reqs.dat[19:16];
vSprRes[sprN] <= wb_reqs.dat[23:20];
end
if (wb_reqs.sel[3]) begin
sprPlane[sprN] <= wb_reqs.dat[27:24];
sprColorDepth[sprN] <= wb_reqs.dat[31:30];
end
end
8'b0?????10:
begin // DMA address set on clk_i domain
if (wb_reqs.sel[0]) sprImageOffs[sprN][ 7:0] <= wb_reqs.dat[7:0];
if (wb_reqs.sel[1]) sprImageOffs[sprN][11:8] <= wb_reqs.dat[11:8];
if (wb_reqs.sel[1]) sprSysAddr[sprN][15:12] <= wb_reqs.dat[15:12];
if (wb_reqs.sel[2]) sprSysAddr[sprN][23:16] <= wb_reqs.dat[23:16];
if (wb_reqs.sel[3]) sprSysAddr[sprN][31:24] <= wb_reqs.dat[31:24];
end
8'b0?????11:
begin
if (wb_reqs.sel[0]) sprTc[sprN][ 7:0] <= wb_reqs.dat[ 7:0];
if (wb_reqs.sel[1]) sprTc[sprN][15:8] <= wb_reqs.dat[15:8];
if (wb_reqs.sel[2]) sprTc[sprN][23:16] <= wb_reqs.dat[23:16];
end
 
default: ;
endcase
end
end
 
//-------------------------------------------------------------
// Sprite Image Cache RAM
// This RAM is dual ported with an SoC side and a display
// controller side.
//-------------------------------------------------------------
 
integer n2;
always_ff @(posedge vclk)
for (n2 = 0; n2 < pnSpr; n2 = n2 + 1)
case(sprColorDepth[n2])
2'd1: sprAddr1[n2] <= {sprAddr[n2][11:3],~sprAddr[n2][2]};
2'd2: sprAddr1[n2] <= {sprAddr[n2][10:2],~sprAddr[n2][1]};
2'd3: sprAddr1[n2] <= {sprAddr[n2][ 9:1],~sprAddr[n2][0]};
default: ;
endcase
 
// The three LSBs of the image index need to be pipelined so they may be used
// to select the pixel. Output from the SRAM is always 32-bits wide so an
// additional mux is needed.
integer n4, n5, n27, n29;
always_ff @(posedge vclk)
for (n4 = 0; n4 < pnSpr; n4 = n4 + 1)
sprAddr2[n4] <= ~sprAddr[n4][2:0];
always_ff @(posedge vclk)
for (n5 = 0; n5 < pnSpr; n5 = n5 + 1)
sprAddr3[n5] <= sprAddr2[n5];
always_ff @(posedge vclk)
for (n27 = 0; n27 < pnSpr; n27 = n27 + 1)
sprAddr4[n27] <= sprAddr3[n27];
always_ff @(posedge vclk)
for (n29 = 0; n29 < pnSpr; n29 = n29 + 1)
sprAddr5[n29] <= sprAddr4[n29];
 
// The pixels are displayed from most signicant to least signicant bits of the
// word. Display order is opposite to memory storage. So, the least significant
// address bits are flipped to get the correct display.
integer n3;
always_ff @(posedge vclk)
for (n3 = 0; n3 < pnSpr; n3 = n3 + 1)
case(sprColorDepth[n3])
2'd1:
case(sprAddr5[n3][1:0])
2'd3: sprOut5[n3] <= sprOut4[n3][31:24];
2'd2: sprOut5[n3] <= sprOut4[n3][23:16];
2'd1: sprOut5[n3] <= sprOut4[n3][15:8];
2'd0: sprOut5[n3] <= sprOut4[n3][7:0];
endcase
2'd2:
case(sprAddr5[n3][0])
1'd0: sprOut5[n3] <= {sprOut4[n3][15],16'h0000,sprOut4[n3][14:0]};
1'd1: sprOut5[n3] <= {sprOut4[n3][31],16'h0000,sprOut4[n3][30:16]};
endcase
2'd3:
sprOut5[n3] <= sprOut4[n3];
default: ;
endcase
 
generate
for (g = 0; g < pnSpr; g = g + 1) begin : sprRam
SpriteRam sprRam0
(
.clka(m_clk_i),
.addra(m_adr_or),
.dina(m_dat_ir[63:0]),
.ena(sprWe[g]),
.wea(sprWe[g]),
// Core reg and output reg 3 clocks from read address
.clkb(vclk),
.addrb(sprAddr1[g]),
.doutb(sprOut4[g]),
.enb(1'b1)
);
end
endgenerate
 
//-------------------------------------------------------------
// Timing counters and addressing
// Sprites are like miniature bitmapped displays, they need
// all the same timing controls.
//-------------------------------------------------------------
 
// Create a timing reference using horizontal and vertical
// sync
wire hSyncEdge, vSyncEdge;
edge_det ed0(.rst(rst_i), .clk(vclk), .ce(1'b1), .i(hSync), .pe(hSyncEdge), .ne(), .ee() );
edge_det ed1(.rst(rst_i), .clk(vclk), .ce(1'b1), .i(vSync), .pe(vSyncEdge), .ne(), .ee() );
 
always_ff @(posedge vclk)
if (hSyncEdge) hctr <= {phBits{1'b0}};
else hctr <= hctr + 2'd1;
 
always_ff @(posedge vclk)
if (vSyncEdge) vctr <= {pvBits{1'b0}};
else if (hSyncEdge) vctr <= vctr + 2'd1;
 
// track sprite horizontal reset
integer n19;
always_ff @(posedge vclk)
for (n19 = 0; n19 < pnSpr; n19 = n19 + 1)
hSprReset[n19] <= hctr==hSprPos[n19];
 
// track sprite vertical reset
integer n20;
always_ff @(posedge vclk)
for (n20 = 0; n20 < pnSpr; n20 = n20 + 1)
vSprReset[n20] <= vctr==vSprPos[n20];
 
integer n21;
always_comb
for (n21 = 0; n21 < pnSpr; n21 = n21 + 1)
sprDe[n21] <= hSprDe[n21] & vSprDe[n21];
 
 
// take care of sprite size scaling
// video clock division
reg [31:0] hSprNextPixel;
reg [31:0] vSprNextPixel;
reg [3:0] hSprPt [31:0]; // horizontal pixel toggle
reg [3:0] vSprPt [31:0]; // vertical pixel toggle
integer n17;
always_comb
for (n17 = 0; n17 < pnSpr; n17 = n17 + 1)
hSprNextPixel[n17] = hSprPt[n17]==hSprRes[n17];
integer n18;
always_comb
for (n18 = 0; n18 < pnSpr; n18 = n18 + 1)
vSprNextPixel[n18] = vSprPt[n18]==vSprRes[n18];
 
// horizontal pixel toggle counter
integer n6;
always_ff @(posedge vclk)
for (n6 = 0; n6 < pnSpr; n6 = n6 + 1)
if (hSprReset[n6])
hSprPt[n6] <= 4'd0;
else if (hSprNextPixel[n6])
hSprPt[n6] <= 4'd0;
else
hSprPt[n6] <= hSprPt[n6] + 2'd1;
 
// vertical pixel toggle counter
integer n7;
always_ff @(posedge vclk)
for (n7 = 0; n7 < pnSpr; n7 = n7 + 1)
if (hSprReset[n7]) begin
if (vSprReset[n7])
vSprPt[n7] <= 4'd0;
else if (vSprNextPixel[n7])
vSprPt[n7] <= 4'd0;
else
vSprPt[n7] <= vSprPt[n7] + 2'd1;
end
 
// Animation rate count and frame increment.
integer n28;
always_ff @(posedge vclk)
if (vSyncEdge) begin
for (n28 = 0; n28 < pnSpr; n28 = n28 + 1) begin
if (sprEnableAnimation[n28]) begin
sprCurRateCount[n28] <= sprCurRateCount[n28] + 2'd1;
if (sprCurRateCount[n28] >= sprRate[n28]) begin
sprCurRateCount[n28] <= 'd0;
sprCurFrame[n28] <= sprCurFrame[n28] + 2'd1;
if (sprCurFrame[n28] >= sprFrames[n28])
sprCurFrame[n28] <= 'd0;
end
end
else
sprCurFrame[n28] <= 'd0;
end
end
// clock sprite image address counters
integer n8;
always_ff @(posedge vclk)
for (n8 = 0; n8 < pnSpr; n8 = n8 + 1) begin
// hReset and vReset - top left of sprite,
// reset address to image offset
if (hSprReset[n8] & vSprReset[n8]) begin
sprAddr[n8] <= sprImageOffs[n8] + sprCurFrame[n8] * sprFrameSize[n8];
sprAddrB[n8] <= sprImageOffs[n8] + sprCurFrame[n8] * sprFrameSize[n8];
end
// hReset:
// If the next vertical pixel
// set backup address to current address
// else
// set current address to backup address
// in order to rescan the line
else if (hSprReset[n8]) begin
if (vSprNextPixel[n8])
sprAddrB[n8] <= sprAddr[n8];
else
sprAddr[n8] <= sprAddrB[n8];
end
// Not hReset or vReset - somewhere on the sprite scan line
// just advance the address when the next pixel should be
// fetched
else if (hSprDe[n8] & hSprNextPixel[n8])
sprAddr[n8] <= sprAddr[n8] + 2'd1;
end
 
 
// clock sprite column (X) counter
integer n9;
always_ff @(posedge vclk)
for (n9 = 0; n9 < pnSpr; n9 = n9 + 1)
if (hSprReset[n9])
hSprCnt[n9] <= 8'd1;
else if (hSprNextPixel[n9])
hSprCnt[n9] <= hSprCnt[n9] + 2'd1;
 
 
// clock sprite horizontal display enable
integer n10;
always_ff @(posedge vclk)
for (n10 = 0; n10 < pnSpr; n10 = n10 + 1) begin
if (hSprReset[n10])
hSprDe[n10] <= 1'b1;
else if (hSprNextPixel[n10]) begin
if (hSprCnt[n10] == sprWidth[n10])
hSprDe[n10] <= 1'b0;
end
end
 
 
// clock the sprite row (Y) counter
integer n11;
always_ff @(posedge vclk)
for (n11 = 0; n11 < pnSpr; n11 = n11 + 1)
if (hSprReset[n11]) begin
if (vSprReset[n11])
vSprCnt[n11] <= 8'd1;
else if (vSprNextPixel[n11])
vSprCnt[n11] <= vSprCnt[n11] + 2'd1;
end
 
 
// clock sprite vertical display enable
integer n12;
always_ff @(posedge vclk)
for (n12 = 0; n12 < pnSpr; n12 = n12 + 1) begin
if (hSprReset[n12]) begin
if (vSprReset[n12])
vSprDe[n12] <= 1'b1;
else if (vSprNextPixel[n12]) begin
if (vSprCnt[n12] == sprHeight[n12])
vSprDe[n12] <= 1'b0;
end
end
end
 
 
//-------------------------------------------------------------
// Output stage
//-------------------------------------------------------------
 
// function used for color blending
// given an alpha and a color component, determine the resulting color
// this blends towards black or white
// alpha is eight bits ranging between 0 and 1.999...
// 1 bit whole, 7 bits fraction
function [11:0] fnBlend;
input [7:0] alpha;
input [11:0] color1bits;
input [11:0] color2bits;
 
begin
fnBlend = (({8'b0,color1bits} * alpha) >> 7) + (({8'h00,color2bits} * (9'h100 - alpha)) >> 7);
end
endfunction
 
 
// pipeline delays for display enable
reg [31:0] sprDe1, sprDe2, sprDe3, sprDe4, sprDe5, sprDe6;
reg [31:0] sproact;
integer n13;
always_ff @(posedge vclk)
for (n13 = 0; n13 < pnSpr; n13 = n13 + 1)
sprDe1[n13] <= sprDe[n13];
integer n22;
always_ff @(posedge vclk)
for (n22 = 0; n22 < pnSpr; n22 = n22 + 1)
sprDe2[n22] <= sprDe1[n22];
integer n23;
always_ff @(posedge vclk)
for (n23 = 0; n23 < pnSpr; n23 = n23 + 1)
sprDe3[n23] <= sprDe2[n23];
integer n24;
always_ff @(posedge vclk)
for (n24 = 0; n24 < pnSpr; n24 = n24 + 1)
sprDe4[n24] <= sprDe3[n24];
integer n25;
always_ff @(posedge vclk)
for (n25 = 0; n25 < pnSpr; n25 = n25 + 1)
sprDe5[n25] <= sprDe4[n25];
integer n26;
always_ff @(posedge vclk)
for (n26 = 0; n26 < pnSpr; n26 = n26 + 1)
sprDe6[n26] <= sprDe5[n26];
 
 
// Detect which sprite outputs are active
// The sprite output is active if the current display pixel
// address is within the sprite's area, the sprite is enabled,
// and it's not a transparent pixel that's being displayed.
integer n14;
always_ff @(posedge vclk)
for (n14 = 0; n14 < pnSpr; n14 = n14 + 1)
sproact[n14] <= sprEn[n14] && sprDe5[n14] && sprTc[n14]!=sprOut5[n14];
integer n15;
always_ff @(posedge vclk)
for (n15 = 0; n15 < pnSpr; n15 = n15 + 1)
sprOut[n15] <= sprOut5[n15];
 
// register sprite activity flag
// The image combiner uses this flag to know what to do with
// the sprite output.
always_ff @(posedge vclk)
outact <= |sproact & ce;
 
// Display data comes from the active sprite with the
// highest display priority.
// Make sure that alpha blending is turned off when
// no sprite is active.
integer n16;
always_ff @(posedge vclk)
begin
out <= 32'h0080; // alpha blend max (and off)
outplane <= 4'h0;
colorBits <= 2'b00;
for (n16 = pnSprm; n16 >= 0; n16 = n16 - 1)
if (sproact[n16]) begin
out <= sprOut[n16];
outplane <= sprPlane[n16];
colorBits <= sprColorDepth[n16];
end
end
 
 
// combine the text / graphics color output with sprite color output
// blend color output
wire [35:0] blendedColor32 = {
fnBlend(out[31:24],{out[23:16],4'h0},zrgb_i[35:24]),
fnBlend(out[31:24],{out[15:8],4'h0},zrgb_i[23:12]),
fnBlend(out[31:24],{out[7:0],4'h0},zrgb_i[11: 0])}
;
 
wire [35:0] blendedColor16 = {
fnBlend(out[7:0],zrgb_i[35:24],12'h0),
fnBlend(out[7:0],zrgb_i[23:12],12'h0),
fnBlend(out[7:0],zrgb_i[11: 0],12'h0)}
;
 
always_ff @(posedge vclk)
if (blank_i)
zrgb_o <= 0;
else begin
if (outact) begin
if (zrgb_i[39:36] > outplane) begin // rgb input is in front of sprite
zrgb_o <= zrgb_i;
end
else
if (!out[31]) begin // a sprite is displayed without alpha blending
case(colorBits)
2'd0: zrgb_o <= {outplane,out[7:5],9'b0,out[4:2],9'b0,out[1:0],10'b0};
2'd1: zrgb_o <= {outplane,out[7:5],9'b0,out[4:2],9'b0,out[1:0],10'b0};
2'd2: zrgb_o <= {outplane,out[14:10],7'b0,out[9:5],7'b0,out[4:0],7'b0};
2'd3: zrgb_o <= zrgb_o <= {outplane,blendedColor32}; // combine colors {outplane,out[23:16],4'h0,out[15:8],4'h0,out[7:0],4'h0};
endcase
end
else
case(colorBits)
2'd2: zrgb_o <= {outplane,blendedColor16}; // towards black/white
2'd3: zrgb_o <= {outplane,blendedColor32}; // combine colors
default: zrgb_o <= {outplane,out[7:5],9'b0,out[4:2],9'b0,out[1:0],10'b0}; // no blending
endcase
end
else
zrgb_o <= zrgb_i;
end
 
 
//--------------------------------------------------------------------
// Collision logic
//--------------------------------------------------------------------
 
// Detect when a sprite-sprite collision has occurred. The criteria
// for this is that a pixel from the sprite is being displayed, while
// there is a pixel from another sprite that could be displayed at the
// same time.
 
//--------------------------------------------------------------------
// Note this case has to be modified for the number of sprites
// ToDo: make collision also depend on plane
//--------------------------------------------------------------------
generate
begin : gSprsColliding
always @(pnSpr or sproact)
if (pnSpr==1)
sprCollision = 0;
else if (pnSpr==2)
case (sproact)
2'b00,
2'b01,
2'b10: sprCollision = 0;
2'b11: sprCollision = 1;
endcase
else if (pnSpr==4)
case (sproact)
4'b0000,
4'b0001,
4'b0010,
4'b0100,
4'b1000: sprCollision = 0;
default: sprCollision = 1;
endcase
else if (pnSpr==6)
case (sproact)
6'b000000,
6'b000001,
6'b000010,
6'b000100,
6'b001000,
6'b010000,
8'b100000: sprCollision = 0;
default: sprCollision = 1;
endcase
else if (pnSpr==8)
case (sproact)
8'b00000000,
8'b00000001,
8'b00000010,
8'b00000100,
8'b00001000,
8'b00010000,
8'b00100000,
8'b01000000,
8'b10000000: sprCollision = 0;
default: sprCollision = 1;
endcase
else if (pnSpr==10)
case (sproact)
10'b0000000000,
10'b0000000001,
10'b0000000010,
10'b0000000100,
10'b0000001000,
10'b0000010000,
10'b0000100000,
10'b0001000000,
10'b0010000000,
10'b0100000000,
10'b1000000000: sprCollision = 0;
default: sprCollision = 1;
endcase
else if (pnSpr==14)
case (sproact)
14'b00000000000000,
14'b00000000000001,
14'b00000000000010,
14'b00000000000100,
14'b00000000001000,
14'b00000000010000,
14'b00000000100000,
14'b00000001000000,
14'b00000010000000,
14'b00000100000000,
14'b00001000000000,
14'b00010000000000,
14'b00100000000000,
14'b01000000000000,
14'b10000000000000: sprCollision = 0;
default: sprCollision = 1;
endcase
else if (pnSpr==16)
case (sproact)
16'h0000,
16'h0001,
16'h0002,
16'h0004,
16'h0008,
16'h0010,
16'h0020,
16'h0040,
16'h0080,
16'h0100,
16'h0200,
16'h0400,
16'h0800,
16'h1000,
16'h2000,
16'h4000,
16'h8000: sprCollision = 0;
default: sprCollision = 1;
endcase
else if (pnSpr==32)
case (sproact)
32'h00000000,
32'h00000001,
32'h00000002,
32'h00000004,
32'h00000008,
32'h00000010,
32'h00000020,
32'h00000040,
32'h00000080,
32'h00000100,
32'h00000200,
32'h00000400,
32'h00000800,
32'h00001000,
32'h00002000,
32'h00004000,
32'h00008000,
32'h00010000,
32'h00020000,
32'h00040000,
32'h00080000,
32'h00100000,
32'h00200000,
32'h00400000,
32'h00800000,
32'h01000000,
32'h02000000,
32'h04000000,
32'h08000000,
32'h10000000,
32'h20000000,
32'h40000000,
32'h80000000: sprCollision = 0;
default: sprCollision = 1;
endcase
end
endgenerate
 
// Detect when a sprite-background collision has occurred
integer n31;
always_comb
for (n31 = 0; n31 < pnSpr; n31 = n31 + 1)
bkCollision[n31] <=
sproact[n31] && zrgb_i[39:36]==sprPlane[n31];
 
// Load the sprite collision register. This register continually
// accumulates collision bits until reset by reading the register.
// Set the collision IRQ on the first collision and don't set it
// again until after the collision register has been read.
always @(posedge vclk)
if (rst_i) begin
sprSprIRQPending1 <= 0;
sprSprCollision1 <= 0;
sprSprIRQ1 <= 0;
end
else if (sprCollision) begin
// isFirstCollision
if ((sprSprCollision1==0)||(cs_regs && wb_reqs.sel[0] && wb_reqs.adr[9:2]==8'b11110010)) begin
sprSprIRQPending1 <= 1;
sprSprIRQ1 <= sprSprIe;
sprSprCollision1 <= sproact;
end
else
sprSprCollision1 <= sprSprCollision1|sproact;
end
else if (cs_regs && wb_reqs.sel[0] && wb_reqs.adr[9:2]==8'b11110010) begin
sprSprCollision1 <= 0;
sprSprIRQPending1 <= 0;
sprSprIRQ1 <= 0;
end
 
 
// Load the sprite background collision register. This register
// continually accumulates collision bits until reset by reading
// the register.
// Set the collision IRQ on the first collision and don't set it
// again until after the collision register has been read.
// Note the background collision indicator is externally supplied,
// it will come from the color processing logic.
always @(posedge vclk)
if (rst_i) begin
sprBkIRQPending1 <= 0;
sprBkCollision1 <= 0;
sprBkIRQ1 <= 0;
end
else if (|bkCollision) begin
// Is the register being cleared at the same time
// a collision occurss ?
// isFirstCollision
if ((sprBkCollision1==0) || (cs_regs && wb_reqs.sel[0] && wb_reqs.adr[9:2]==8'b11110011)) begin
sprBkIRQ1 <= sprBkIe;
sprBkCollision1 <= bkCollision;
sprBkIRQPending1 <= 1;
end
else
sprBkCollision1 <= sprBkCollision1|bkCollision;
end
else if (cs_regs && wb_reqs.sel[0] && wb_reqs.adr[9:2]==8'b11110011) begin
sprBkCollision1 <= 0;
sprBkIRQPending1 <= 0;
sprBkIRQ1 <= 0;
end
 
endmodule
 
/*
module SpriteRam32 (
clka, adra, dia, doa, cea, wea,
clkb, adrb, dib, dob, ceb, web
);
input clka;
input [9:0] adra;
input [31:0] dia;
output [31:0] doa;
input cea;
input wea;
input clkb;
input [9:0] adrb;
input [31:0] dib;
output [31:0] dob;
input ceb;
input web;
 
reg [31:0] mem [0:1023];
reg [9:0] radra;
reg [9:0] radrb;
 
always @(posedge clka) if (cea) radra <= adra;
always @(posedge clkb) if (ceb) radrb <= adrb;
assign doa = mem [radra];
assign dob = mem [radrb];
always @(posedge clka)
if (cea & wea) mem[adra] <= dia;
always @(posedge clkb)
if (ceb & web) mem[adrb] <= dib;
 
endmodule
 
*/
/verilog/wishbone_pkg.sv
0,0 → 1,612
// ============================================================================
// __
// \\__/ o\ (C) 2015-2022 Robert Finch, Waterloo
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
// BSD 3-Clause License
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ============================================================================
//
package wishbone_pkg;
 
typedef logic [31:0] wb_address_t;
typedef logic [2:0] wb_burst_len_t; // number of beats in a burst -1
typedef logic [3:0] wb_channel_t; // channel for devices like system cache
typedef logic [7:0] wb_tranid_t; // transaction id
typedef logic [7:0] wb_priv_level_t; // 0=all access,
typedef logic [3:0] wb_priority_t; // network transaction priority, higher is better
 
typedef enum logic [2:0] {
CLASSIC = 3'b000,
FIXED = 3'b001, // constant data address
INCR = 3'b010, // incrementing data address
EOB = 3'b111 // end of data burst
} wb_cycle_type_t;
 
typedef enum logic [2:0] {
DATA = 3'b000,
STACK = 3'b110,
CODE = 3'b111
} wb_segment_t;
 
typedef enum logic [2:0] {
LINEAR = 3'b000,
WRAP4 = 3'b001,
WRAP8 = 3'b010,
WRAP16 = 3'b011,
WRAP32 = 3'b100,
WRAP64 = 3'b101,
WRAP128 = 3'b110
} wb_burst_type_t;
 
// number of byte transferred in a beat
typedef enum logic [2:0] {
B8 = 3'd0,
B16 = 3'd1,
B32 = 3'd2,
B64 = 3'd3,
B128 = 3'd4
} wb_size_t;
 
typedef enum logic [1:0] {
OKAY = 2'b00, // no error
DECERR = 2'd01, // decode error
PROTERR = 2'b10, // security violation
ERR = 2'b11 // general error
} wb_error_t;
 
typedef enum logic [3:0] {
NC_NB = 4'd0, // Non-cacheable, non-bufferable
NON_CACHEABLE = 4'd1,
CACHEABLE_NB = 4'd2, // Cacheable, non-bufferable
CACHEABLE = 4'd3, // Cacheable, bufferable
WT_NO_ALLOCATE = 4'd8, // Write Through
WT_READ_ALLOCATE = 4'd9,
WT_WRITE_ALLOCATE = 4'd10,
WT_READWRITE_ALLOCATE = 4'd11,
WB_NO_ALLOCATE = 4'd12, // Write Back
WB_READ_ALLOCATE = 4'd13,
WB_WRITE_ALLOCATE = 4'd14,
WB_READWRITE_ALLOCATE = 4'd15
} wb_cache_t;
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Read requests
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
typedef struct packed {
wb_burst_type_t bte; // burst type extension
wb_cycle_type_t cti; // cycle type indicator
wb_burst_len_t blen; // length of burst-1
wb_segment_t seg; // segment
logic cyc; // valid cycle
logic stb; // data strobe
wb_address_t adr; // address
wb_channel_t cid; // channel id
wb_tranid_t tid; // transaction id
logic sr; // set reservation
wb_priv_level_t pl; // privilege level
wb_priority_t pri; // transaction priority
wb_cache_t cache; // cache and buffer properties
} wb_read_request8_t;
 
typedef struct packed {
wb_burst_type_t bte; // burst type extension
wb_cycle_type_t cti; // cycle type indicator
wb_burst_len_t blen; // length of burst-1
wb_segment_t seg; // segment
logic cyc; // valid cycle
logic stb; // data strobe
wb_address_t adr; // address
logic [1:0] sel; // byte lane select
wb_channel_t cid; // channel id
wb_tranid_t tid; // transaction id
logic sr; // set reservation
wb_priv_level_t pl; // privilege level
wb_priority_t pri; // transaction priority
wb_cache_t cache; // cache and buffer properties
} wb_read_request16_t;
 
typedef struct packed {
wb_burst_type_t bte; // burst type extension
wb_cycle_type_t cti; // cycle type indicator
wb_burst_len_t blen; // length of burst-1
wb_segment_t seg; // segment
logic cyc; // valid cycle
logic stb; // data strobe
wb_address_t adr; // address
logic [3:0] sel; // byte lane select
wb_channel_t cid; // channel id
wb_tranid_t tid; // transaction id
logic sr; // set reservation
wb_priv_level_t pl; // privilege level
wb_priority_t pri; // transaction priority
wb_cache_t cache; // cache and buffer properties
} wb_read_request32_t;
 
typedef struct packed {
wb_burst_type_t bte; // burst type extension
wb_cycle_type_t cti; // cycle type indicator
wb_burst_len_t blen; // length of burst-1
wb_segment_t seg; // segment
logic cyc; // valid cycle
logic stb; // data strobe
wb_address_t adr; // address
logic [7:0] sel; // byte lane select
wb_channel_t cid; // channel id
wb_tranid_t tid; // transaction id
logic sr; // set reservation
wb_priv_level_t pl; // privilege level
wb_priority_t pri; // transaction priority
wb_cache_t cache; // cache and buffer properties
} wb_read_request64_t;
 
typedef struct packed {
wb_burst_type_t bte; // burst type extension
wb_cycle_type_t cti; // cycle type indicator
wb_burst_len_t blen; // length of burst-1
wb_segment_t seg; // segment
logic cyc; // valid cycle
logic stb; // data strobe
wb_address_t adr; // address
logic [15:0] sel; // byte lane select
wb_channel_t cid; // channel id
wb_tranid_t tid; // transaction id
logic sr; // set reservation
wb_priv_level_t pl; // privilege level
wb_priority_t pri; // transaction priority
wb_cache_t cache; // cache and buffer properties
} wb_read_request128_t;
 
typedef struct packed {
wb_burst_type_t bte; // burst type extension
wb_cycle_type_t cti; // cycle type indicator
wb_burst_len_t blen; // length of burst-1
wb_segment_t seg; // segment
logic cyc; // valid cycle
logic stb; // data strobe
wb_address_t adr; // address
logic [31:0] sel; // byte lane select
wb_channel_t cid; // channel id
wb_tranid_t tid; // transaction id
logic sr; // set reservation
wb_priv_level_t pl; // privilege level
wb_priority_t pri; // transaction priority
wb_cache_t cache; // cache and buffer properties
} wb_read_request256_t;
 
typedef struct packed {
wb_burst_type_t bte; // burst type extension
wb_cycle_type_t cti; // cycle type indicator
wb_burst_len_t blen; // length of burst-1
wb_segment_t seg; // segment
logic cyc; // valid cycle
logic stb; // data strobe
wb_address_t adr; // address
logic [63:0] sel; // byte lane select
wb_channel_t cid; // channel id
wb_tranid_t tid; // transaction id
logic sr; // set reservation
wb_priv_level_t pl; // privilege level
wb_priority_t pri; // transaction priority
wb_cache_t cache; // cache and buffer properties
} wb_read_request512_t;
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Write requests
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
typedef struct packed {
wb_burst_type_t bte; // burst type extension
wb_cycle_type_t cti; // cycle type indicator
wb_burst_len_t blen; // length of burst-1
wb_segment_t seg; // segment
logic cyc; // valid cycle
logic stb; // data strobe
logic we; // write enable
wb_address_t adr; // address
logic [7:0] dat; // data
wb_channel_t cid; // channel id
wb_tranid_t tid; // transaction id
logic csr; // set or clear reservation we:1=clear 0=set
wb_priv_level_t pl; // privilege level
wb_priority_t pri; // transaction priority
wb_cache_t cache; // cache and buffer properties
} wb_write_request8_t;
 
typedef struct packed {
wb_burst_type_t bte; // burst type extension
wb_cycle_type_t cti; // cycle type indicator
wb_burst_len_t blen; // length of burst-1
wb_segment_t seg; // segment
logic cyc; // valid cycle
logic stb; // data strobe
logic we; // write enable
wb_address_t adr; // address
logic [1:0] sel; // byte lane selects
logic [15:0] dat; // data
wb_channel_t cid; // channel id
wb_tranid_t tid; // transaction id
logic csr; // set or clear reservation we:1=clear 0=set
wb_priv_level_t pl; // privilege level
wb_priority_t pri; // transaction priority
wb_cache_t cache; // cache and buffer properties
} wb_write_request16_t;
 
typedef struct packed {
wb_burst_type_t bte; // burst type extension
wb_cycle_type_t cti; // cycle type indicator
wb_burst_len_t blen; // length of burst-1
wb_segment_t seg; // segment
logic cyc; // valid cycle
logic stb; // data strobe
logic we; // write enable
wb_address_t adr; // address
logic [3:0] sel; // byte lane selects
logic [31:0] dat; // data
wb_channel_t cid; // channel id
wb_tranid_t tid; // transaction id
logic csr; // set or clear reservation we:1=clear 0=set
wb_priv_level_t pl; // privilege level
wb_priority_t pri; // transaction priority
wb_cache_t cache; // cache and buffer properties
} wb_write_request32_t;
 
typedef struct packed {
wb_burst_type_t bte; // burst type extension
wb_cycle_type_t cti; // cycle type indicator
wb_burst_len_t blen; // length of burst-1
wb_segment_t seg; // segment
logic cyc; // valid cycle
logic stb; // data strobe
logic we; // write enable
wb_address_t adr; // address
logic [7:0] sel; // byte lane selects
logic [63:0] dat; // data
wb_channel_t cid; // channel id
wb_tranid_t tid; // transaction id
logic csr; // set or clear reservation we:1=clear 0=set
wb_priv_level_t pl; // privilege level
wb_priority_t pri; // transaction priority
wb_cache_t cache; // cache and buffer properties
} wb_write_request64_t;
 
typedef struct packed {
wb_burst_type_t bte; // burst type extension
wb_cycle_type_t cti; // cycle type indicator
wb_burst_len_t blen; // length of burst-1
wb_segment_t seg; // segment
logic cyc; // valid cycle
logic stb; // data strobe
logic we; // write enable
wb_address_t adr; // address
logic [15:0] sel; // byte lane selects
logic [127:0] dat; // data
wb_channel_t cid; // channel id
wb_tranid_t tid; // transaction id
logic csr; // set or clear reservation we:1=clear 0=set
wb_priv_level_t pl; // privilege level
wb_priority_t pri; // transaction priority
wb_cache_t cache; // cache and buffer properties
} wb_write_request128_t;
 
typedef struct packed {
wb_burst_type_t bte; // burst type extension
wb_cycle_type_t cti; // cycle type indicator
wb_burst_len_t blen; // length of burst-1
wb_segment_t seg; // segment
logic cyc; // valid cycle
logic stb; // data strobe
logic we; // write enable
wb_address_t adr; // address
logic [31:0] sel; // byte lane selects
logic [255:0] dat; // data
wb_channel_t cid; // channel id
wb_tranid_t tid; // transaction id
logic csr; // set or clear reservation we:1=clear 0=set
wb_priv_level_t pl; // privilege level
wb_priority_t pri; // transaction priority
wb_cache_t cache; // cache and buffer properties
} wb_write_request256_t;
 
typedef struct packed {
wb_burst_type_t bte; // burst type extension
wb_cycle_type_t cti; // cycle type indicator
wb_burst_len_t blen; // length of burst-1
wb_segment_t seg; // segment
logic cyc; // valid cycle
logic stb; // data strobe
logic we; // write enable
wb_address_t adr; // address
logic [63:0] sel; // byte lane selects
logic [511:0] dat; // data
wb_channel_t cid; // channel id
wb_tranid_t tid; // transaction id
logic csr; // set or clear reservation we:1=clear 0=set
wb_priv_level_t pl; // privilege level
wb_priority_t pri; // transaction priority
wb_cache_t cache; // cache and buffer properties
} wb_write_request512_t;
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Read responses
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
typedef struct packed {
wb_channel_t cid; // channel id
wb_tranid_t tid; // transaction id
logic stall; // stall pipeline
logic next; // advance to next transaction
logic ack; // response acknowledge
logic rty; // retry
logic err; // error
wb_priority_t pri; // response priority
logic [7:0] dat; // data
} wb_read_response8_t;
 
typedef struct packed {
wb_channel_t cid; // channel id
wb_tranid_t tid; // transaction id
logic stall; // stall pipeline
logic next; // advance to next transaction
logic ack; // response acknowledge
logic rty; // retry
logic err; // error
wb_priority_t pri; // response priority
logic [15:0] dat; // data
} wb_read_response16_t;
 
typedef struct packed {
wb_channel_t cid; // channel id
wb_tranid_t tid; // transaction id
logic stall; // stall pipeline
logic next; // advance to next transaction
logic ack; // response acknowledge
logic rty; // retry
logic err; // error
wb_priority_t pri; // response priority
logic [31:0] dat; // data
} wb_read_response32_t;
 
typedef struct packed {
wb_channel_t cid; // channel id
wb_tranid_t tid; // transaction id
logic stall; // stall pipeline
logic next; // advance to next transaction
logic ack; // response acknowledge
logic rty; // retry
logic err; // error
wb_priority_t pri; // response priority
logic [31:0] dat; // data
} wb_response32_t;
 
typedef struct packed {
wb_channel_t cid; // channel id
wb_tranid_t tid; // transaction id
logic stall; // stall pipeline
logic next; // advance to next transaction
logic ack; // response acknowledge
logic rty; // retry
logic err; // error
wb_priority_t pri; // response priority
logic [63:0] dat; // data
} wb_read_response64_t;
 
typedef struct packed {
wb_channel_t cid; // channel id
wb_tranid_t tid; // transaction id
logic stall; // stall pipeline
logic next; // advance to next transaction
logic ack; // response acknowledge
logic rty; // retry
logic err; // error
wb_priority_t pri; // response priority
logic [127:0] dat; // data
} wb_read_response128_t;
 
typedef struct packed {
wb_channel_t cid; // channel id
wb_tranid_t tid; // transaction id
logic stall; // stall pipeline
logic next; // advance to next transaction
logic ack; // response acknowledge
logic rty; // retry
logic err; // error
wb_priority_t pri; // response priority
logic [127:0] dat; // data
} wb_response128_t;
 
typedef struct packed {
wb_channel_t cid; // channel id
wb_tranid_t tid; // transaction id
logic stall; // stall pipeline
logic next; // advance to next transaction
logic ack; // response acknowledge
logic rty; // retry
logic err; // error
wb_priority_t pri; // response priority
logic [255:0] dat; // data
} wb_read_response256_t;
 
typedef struct packed {
wb_channel_t cid; // channel id
wb_tranid_t tid; // transaction id
logic stall; // stall pipeline
logic next; // advance to next transaction
logic ack; // response acknowledge
logic rty; // retry
logic err; // error
wb_priority_t pri; // response priority
logic [511:0] dat; // data
} wb_read_response512_t;
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Write responses
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
// Sometimes write cycles can expect data responses back too. This is typically
// just a single bit. For instance, the reservation status. Write responses all
// have a common structure.
 
typedef struct packed {
wb_channel_t cid; // channel id
wb_tranid_t tid; // transaction id
logic stall; // stall pipeline
logic next; // advance to next transaction
logic ack; // response acknowledge
logic rty; // retry
logic err; // error
wb_priority_t pri; // response priority
logic [7:0] dat; // data
} wb_write_response_t;
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// read/write requests
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
typedef struct packed
{
wb_read_request8_t read;
wb_write_request8_t write;
} wb_readwrite_request8_t;
 
typedef struct packed
{
wb_read_request16_t read;
wb_write_request16_t write;
} wb_readwrite_request16_t;
 
typedef struct packed
{
wb_read_request32_t read;
wb_write_request32_t write;
} wb_readwrite_request32_t;
 
typedef struct packed
{
wb_read_request64_t read;
wb_write_request64_t write;
} wb_readwrite_request64_t;
 
typedef struct packed
{
wb_read_request128_t read;
wb_write_request128_t write;
} wb_readwrite_request128_t;
 
typedef struct packed
{
wb_read_request256_t read;
wb_write_request256_t write;
} wb_readwrite_request256_t;
 
typedef struct packed
{
wb_read_request512_t read;
wb_write_request512_t write;
} wb_readwrite_request512_t;
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// read / write responses
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
typedef struct packed
{
wb_read_response8_t read;
wb_write_response_t write;
} wb_readwrite_response8_t;
 
typedef struct packed
{
wb_read_response16_t read;
wb_write_response_t write;
} wb_readwrite_response16_t;
 
typedef struct packed
{
wb_read_response32_t read;
wb_write_response_t write;
} wb_readwrite_response32_t;
 
typedef struct packed
{
wb_read_response64_t read;
wb_write_response_t write;
} wb_readwrite_response64_t;
 
typedef struct packed
{
wb_read_response128_t read;
wb_write_response_t write;
} wb_readwrite_response128_t;
 
typedef struct packed
{
wb_read_response256_t read;
wb_write_response_t write;
} wb_readwrite_response256_t;
 
typedef struct packed
{
wb_read_response512_t read;
wb_write_response_t write;
} wb_readwrite_response512_t;
 
endpackage
 
interface wb_request_i #(int WID);
wb_burst_type_t bte; // burst type extension
wb_cycle_type_t cti; // cycle type indicator
wb_burst_len_t blen; // length of burst-1
wb_segment_t seg; // segment
logic cyc; // valid cycle
logic stb; // data strobe
logic we; // write enable
wb_address_t adr; // address
logic [WID/8-1:0] sel; // byte lane selects
logic [WID-1:0] dat; // data
wb_channel_t cid; // channel id
wb_tranid_t tid; // transaction id
logic csr; // set or clear reservation we:1=clear 0=set
wb_priv_level_t pl; // privilege level
wb_priority_t pri; // transaction priority
wb_cache_t cache; // cache and buffer properties
endinterface
 
interface wb_response_i #(int WID);
wb_channel_t cid; // channel id
wb_tranid_t tid; // transaction id
logic stall; // stall pipeline
logic next; // advance to next transaction
logic ack; // response acknowledge
logic rty; // retry
logic err; // error
wb_priority_t pri; // response priority
logic [WID-1:0] dat; // data
endinterface

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.