?? agnus.v
字號:
To disable further sprite list processing it's enough to set VSTART and VSTOP to values which are outsideof the screen or has been already achieved. When waiting for VSTART condition any write to SPRxDATA (write to SPRxDATB takes no effect) makes the written valuevisible on the screen but it doesn't start DMA although it's enabled. The same value is displayed in every subsequent line until DMA starts and delivers new data to SPRxDAT or SPRxCTL is written (by DMA, copper or cpu).It seems like only VSTART condition starts DMA transfer. Any write to SPRxCTL while DMA is active doesn't stop display but new value of VSTOP takes effect. Actually display is reenabled by DMA write to SPRxDATA in next line. The same applies to SPRxPOS writes when sprite is beeing displayed - only HSTART position changes (if new VSTARTis specified to be met before VSTOP nothing interesting happens). The DMA engine sees VSTART condition as true even if DMA is dissabled. Enabling DMA after VSTART and before VSTOPstarts sprite display in enabled line (if it's enabled early enough). Dissabling DMA in the line when new SPRxPOS/SPRxCTL is fetched and enabling it in the next one results in stoppedDMA transfer but the last line of sprite is displayed till the end of the screen.VSTART and VSTOP specified within vbl are not met.vbl stops dma transfer.The first possible line to display a sprite is line $1A (PAL).During vbl SPRxPOS/SPRxCTL are not automatically modified, values written before vbl are still present when vbl ends.algo: if vbl or VSTOP : disable data dma else if VSTART: start data dma if vblend or (VSTOP and not vbl): dma transfer to sprxpos/sprxctl else if data dma active: transfer to sprxdata/sprcdatbIt doesn't seem to be complicated :)Sprite which has been triggered by write to SPRxDATA is not disabled by vbl.It seems that vstop and vstart conditions are checked every cycle. Dma doesn't fetch new pos/ctl if vstop is not equal to the current line number.Feature:If new vstart is specified to be the same as the line during which it's fetched, display starts in the next linebut is one line shorter.*///sprite dma enginemodule sprdma_engine( input clk, //bus clock input clk28m, output reg reqdma, //sprite dma engine requests dma cycle input ackdma, //agnus dma priority logic grants dma cycle input [8:0]hpos, //horizontal beam counter input [10:0]vpos, //vertical beam counter input vbl, //JB: vertical blanking input vblend, //JB: last line of vertical blanking input [8:1]regaddressin, //register address inputs output reg [8:1]regaddressout, //register address outputs input [15:0]datain, //bus data in output [20:1]addressout //chip address out);//register names and adresses parameter SPRPTBASE=9'h120; //sprite pointers base addressparameter SPRPOSCTLBASE=9'h140; //sprite data, position and control register base address//local signalsreg [20:16]sprpth[7:0]; //upper 5 bits sprite pointers register bankreg [15:1]sprptl[7:0]; //lower 16 bits sprite pointers register bankreg [15:8]sprpos[7:0]; //sprite vertical start position register bank//JB: implementing ECS extended vertical sprite positionreg [15:4]sprctl[7:0]; //sprite vertical stop position register bankwire [9:0]vstart; //vertical start of selected spritewire [9:0]vstop; //vertical stop of selected spritewire [2:0]sprite; //sprite select signalwire [20:1]newptr; //new sprite pointer valuewire enable; //hpos in sprite region//the following signals change their value during cycle 0 of 4-cycle dma sprite windowreg sprvstop; //current line is sprite's vstopreg sprdmastate; //sprite dma state (sprite image data cycles)reg dmastate_mem[7:0]; //dma state for every spritewire dmastate; //output from memoryreg dmastate_in; //input to memoryreg [2:0]sprsel; //memory selection//sprite selection signal (in real amiga sprites are evaluated concurently,//in our solution to save resources they are evaluated sequencially but 8 times faster (28MHz clock)always @(posedge clk28m) if (sprsel[2]==hpos[0]) //sprsel[2] is synced with hpos[0] sprsel <= sprsel + 1;//--------------------------------------------------------------------------------------//register bank address multiplexerwire [2:0]ptsel; //sprite pointer and state registers selectwire [2:0]pcsel; //sprite position and control registers selectassign ptsel = (ackdma) ? sprite : regaddressin[4:2];assign pcsel = (ackdma) ? sprite : regaddressin[5:3];//sprite pointer arithmetic unitassign newptr = addressout[20:1] + 1;//sprite pointer high word register bank (implemented using distributed ram)wire [20:16]sprpth_in;assign sprpth_in = ackdma ? newptr[20:16] : datain[4:0];always @(posedge clk) if(ackdma || ((regaddressin[8:5]==SPRPTBASE[8:5]) && !regaddressin[1]))//if dma cycle or bus write sprpth[ptsel] <= sprpth_in;assign addressout[20:16] = sprpth[sprite];//sprite pointer low word register bank (implemented using distributed ram)wire [15:1]sprptl_in;assign sprptl_in = ackdma ? newptr[15:1] : datain[15:1];always @(posedge clk) if(ackdma || ((regaddressin[8:5]==SPRPTBASE[8:5]) && regaddressin[1]))//if dma cycle or bus write sprptl[ptsel] <= sprptl_in;assign addressout[15:1] = sprptl[sprite];//sprite vertical start position register bank (implemented using distributed ram)always @(posedge clk) if((regaddressin[8:6]==SPRPOSCTLBASE[8:6]) && (regaddressin[2:1]==2'b00))//if bus write sprpos[pcsel] <= datain[15:8];assign vstart[7:0] = sprpos[sprsel];//sprite vertical stop position register bank (implemented using distributed ram)always @(posedge clk) if((regaddressin[8:6]==SPRPOSCTLBASE[8:6]) && (regaddressin[2:1]==2'b01))//if bus write sprctl[pcsel] <= {datain[15:8],datain[6],datain[5],datain[2],datain[1]}; assign {vstop[7:0],vstart[9],vstop[9],vstart[8],vstop[8]} = sprctl[sprsel];//sprite dma channel state register bank//update dmastate when hpos is in sprite fetch region//every sprite has allocated 8 system clock cycles with two active dma slots://the first during cycle #3 and the second during cycle #7//first slot transfers data to sprxpos register during vstop or vblend or to sprxdata when dma is active//second slot transfers data to sprxctl register during vstop or vblend or to sprxdatb when dma is active//current dmastate is valid after cycle #1 for given sprite and it's needed during cycle #3 and #7always @(posedge clk28m) dmastate_mem[sprsel] <= dmastate_in;assign dmastate = dmastate_mem[sprsel];//evaluating sprite image dma data statealways @(vbl or vpos or vstop or vstart or dmastate) if (vbl || (vstop[9:0]==vpos[9:0])) dmastate_in = 0; else if (vstart[9:0]==vpos[9:0]) dmastate_in = 1; else dmastate_in = dmastate;always @(posedge clk28m) if (sprite==sprsel && hpos[2:1]==2'b00) sprdmastate <= dmastate;always @(posedge clk28m) if (sprite==sprsel && hpos[2:1]==2'b00) sprvstop <= vstop[9:0]==vpos[9:0] ? 1 : 0;//--------------------------------------------------------------------------------------//--------------------------------------------------------------------------------------//check if we are allowed to allocate dma slots for sprites//dma slots for sprites from cycle 20 till 51assign enable = hpos[8:1]>=8'b0001_0100 && hpos[8:1]<8'b0011_0100 ? 1: 0; //get sprite number for which we are going to do dmaassign sprite = hpos[5:3] - 3'b101;//generate regdma signalalways @(vpos or vbl or vblend or hpos or enable or sprite or sprvstop or sprdmastate) if (enable && hpos[1:0]==2'b11) begin if (vblend || (sprvstop && ~vbl)) begin reqdma = 1; if (~hpos[2]) regaddressout[8:1] = {SPRPOSCTLBASE[8:6],sprite,2'b00}; //SPRxPOS else regaddressout[8:1] = {SPRPOSCTLBASE[8:6],sprite,2'b01}; //SPRxCTL end else if (sprdmastate) begin reqdma = 1; if (~hpos[2]) regaddressout[8:1] = {SPRPOSCTLBASE[8:6],sprite,2'b10}; //SPRxDATA else regaddressout[8:1] = {SPRPOSCTLBASE[8:6],sprite,2'b11}; //SPRxDATB end
else begin reqdma = 0; regaddressout[8:1] = 8'hFF; end end else begin reqdma = 0; regaddressout[8:1] = 8'hFF; end//--------------------------------------------------------------------------------------//--------------------------------------------------------------------------------------endmodule//--------------------------------------------------------------------------------------//--------------------------------------------------------------------------------------//--------------------------------------------------------------------------------------//disk dma engine//the DMA cycle allocation is not completely according to the HRM,//there are 4 slots allocated for disk dma instead of 3////slots are: (horbeam[8:0] counts) //slot 0x000000011 //slot 0x000000111 //slot 0x000001011 //slot 0x000001111 module dskdma_engine( input clk, //bus clock output dma, //true if disk dma engine uses it's cycle input dmal, //Paula requests dma input dmas, //Paula special dma input [8:0]horbeam, //horizontal beam counter output wr, //write (disk dma writes to memory) input [8:1]regaddressin, //register address inputs output [8:1]regaddressout, //register address outputs input [15:0]datain, //bus data in output reg [20:1]addressout //chip address out current disk dma pointer);//register names and adresses parameter DSKPTH=9'h020; parameter DSKPTL=9'h022; parameter DSKDAT=9'h026; parameter DSKDATR=9'h008; //local signalswire [20:1]addressoutnew; //new disk dma pointer//--------------------------------------------------------------------------------------//dma cycle allocationassign dma=(dmal && (horbeam[8:4]==5'b00000) && (horbeam[1:0]==2'b11))?1:0;//write signalassign wr=~dmas;//--------------------------------------------------------------------------------------//addressout input multiplexer and ALUassign addressoutnew[20:1] = dma ? addressout[20:1]+1 : {datain[4:0],datain[15:1]}; //disk pointer controlalways @(posedge clk) if(dma || (regaddressin[8:1]==DSKPTH[8:1])) addressout[20:16]<=addressoutnew[20:16];//high 5 bitsalways @(posedge clk) if(dma || (regaddressin[8:1]==DSKPTL[8:1])) addressout[15:1]<=addressoutnew[15:1];//low 15 bits//--------------------------------------------------------------------------------------//register address outputassign regaddressout[8:1] = wr ? DSKDATR[8:1] : DSKDAT[8:1];//--------------------------------------------------------------------------------------endmodule//--------------------------------------------------------------------------------------//--------------------------------------------------------------------------------------//--------------------------------------------------------------------------------------//Audio dma engine//2 cycle types are defined, restart pointer, (go back to beginning of sample) and next pointer//(get next word of sample, dmas indicates restart pointer cycle//////slots are: (horbeam[8:0] counts) //slot 0x000010011 (channel #0)//slot 0x000010111 (channel #1)//slot 0x000011011 (channel #2)//slot 0x000011111 (channel #3)module auddma_engine(clk,dma,dmal,dmas,horbeam,regaddressin,regaddressout,datain,addressout);input clk; //bus clockoutput dma; //true if audio dma engine uses it's cycleinput dmal; //Paula requests dmainput dmas; //Paula special dmainput [8:0]horbeam; //horizontal beam counterinput [8:1]regaddressin; //register address inputsoutput [8:1]regaddressout; //register address outputsinput [15:0]datain; //bus data inoutput [20:1]addressout; //chip address out//register names and adresses parameter AUD0DAT=9'h0aa; parameter AUD1DAT=9'h0ba; parameter AUD2DAT=9'h0ca; parameter AUD3DAT=9'h0da; parameter AUD0LCH=9'h0a0; parameter AUD1LCH=9'h0b0; parameter AUD2LCH=9'h0c0; parameter AUD3LCH=9'h0d0; //local signalsreg [8:1]regaddressout; //see abovereg [20:1]aud0lc; //audio location register channel 0reg [20:1]aud1lc; //audio location register channel 1reg [20:1]aud2lc; //audio location register channel 2reg [20:1]aud3lc; //audio location register channel 3reg [20:1]audlcout; //audio location outputreg [20:1]audpt[3:0]; //audio pointer bankwire [20:1]audptout; //audio pointer bank output//--------------------------------------------------------------------------------------//audio location register channel 0always @(posedge clk) if((regaddressin[8:2]==AUD0LCH[8:2]) && !regaddressin[1]) aud0lc[20:16]<=datain[4:0]; else if((regaddressin[8:2]==AUD0LCH[8:2]) && regaddressin[1]) aud0lc[15:1]<=datain[15:1];//audio location register channel 1always @(posedge clk) if((regaddressin[8:2]==AUD1LCH[8:2]) && !regaddressin[1]) aud1lc[20:16]<=datain[4:0]; else if((regaddressin[8:2]==AUD1LCH[8:2]) && regaddressin[1]) aud1lc[15:1]<=datain[15:1];//audio location register channel 2always @(posedge clk) if((regaddressin[8:2]==AUD2LCH[8:2]) && !regaddressin[1]) aud2lc[20:16]<=datain[4:0]; else if((regaddressin[8:2]==AUD2LCH[8:2]) && regaddressin[1]) aud2lc[15:1]<=datain[15:1];//audio location register channel 3always @(posedge clk) if((regaddressin[8:2]==AUD3LCH[8:2]) && !regaddressin[1]) aud3lc[20:16]<=datain[4:0]; else if((regaddressin[8:2]==AUD3LCH[8:2]) && regaddressin[1]) aud3lc[15:1]<=datain[15:1];//--------------------------------------------------------------------------------------//get audio location pointeralways @(horbeam or aud0lc or aud1lc or aud2lc or aud3lc) case(horbeam[3:2]) 2'b00: audlcout[20:1]=aud0lc[20:1]; 2'b01: audlcout[20:1]=aud1lc[20:1]; 2'b10: audlcout[20:1]=aud2lc[20:1]; 2'b11: audlcout[20:1]=aud3lc[20:1]; endcase//dma cycle allocationassign dma=(dmal && (horbeam[8:4]==5'b00001) && (horbeam[1:0]==2'b11))?1:0;//addressout output multiplexerassign addressout[20:1]=(dmas)?audlcout[20:1]:audptout[20:1]; //audio location register bank (implemented using distributed ram)//and ALUalways @(posedge clk) if(dma)//dma cycle audpt[horbeam[3:2]]<=(addressout[20:1]+1);assign audptout[20:1]=audpt[horbeam[3:2]];//register address output multiplexeralways @(horbeam) case(horbeam[3:2]) 2'b00: regaddressout[8:1]=AUD0DAT[8:1]; 2'b01: regaddressout[8:1]=AUD1DAT[8:1]; 2'b10: regaddressout[8:1]=AUD2DAT[8:1]; 2'b11: regaddressout[8:1]=AUD3DAT[8:1]; endcase//--------------------------------------------------------------------------------------endmodule
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -