?? agnus.v
字號(hào):
if(bplen && (verbeam[8:0]>={1'b0,vdiwstrt[15:8]}) && (verbeam[8:0]<{~vdiwstop[15],vdiwstop[15:8]})) bplenable=1; else bplenable=0; bpldma_engine bpd1( .clk(clk), .reset(reset), .enable(bplenable), .horbeam(horbeam), .dma(dma_bpl), .interlace(interlace), .regaddressin(regaddress), .regaddressout(regaddress_bpl), .datain(datain), .addressout(address_bpl) );//--------------------------------------------------------------------------------------//instantiate sprite dma enginesprdma_engine spr1( .clk(clk), .clk28m(clk28m), .reqdma(req_spr), .ackdma(ack_spr), .hpos(horbeam), .vpos(verbeam), .vbl(vbl), .vblend(vblend), .regaddressin(regaddress), .regaddressout(regaddress_spr), .datain(datain), .addressout(address_spr) );//--------------------------------------------------------------------------------------//instantiate coppercopper cp1( .clk(clk), .reset(reset), .reqdma(req_cop), .ackdma(ack_cop), .sof(sof), .eol(sol), .bbusy(bbusy), .vpos(verbeam[7:0]), .datain(datain), .regaddressin(regaddress), .regaddressout(regaddress_cop), .addressout(address_cop) );//--------------------------------------------------------------------------------------//instantiate blitterblitter bl1( .clk(clk), .reset(reset), .reqdma(req_blt), .ackdma(ack_blt), .bzero(bzero), .bbusy(bbusy), .bblck(bblck), .horbeam(horbeam[0]^horbeam[1]),//HACK, avoid dma contention a bit .wr(wr_blt), .datain(datain), .dataout(data_blt), .regaddressin(regaddress), .addressout(address_blt) );//generate blitter finished intterupt (int3)reg bbusyd;always @(posedge clk) bbusyd<=bbusy;assign int3=(~bbusy)&bbusyd;//--------------------------------------------------------------------------------------//instantiate beam countersbeamcounter bc1( .clk(clk), .reset(reset), .interlace(interlace), .ntsc(ntsc), .datain(datain), .dataout(data_bmc), .regaddressin(regaddress), .hpos(horbeam), .vpos(verbeam), ._hsync(_hsync), ._vsync(_vsync), .blank(blank), .vbl(vbl), .vblend(vblend), .eol(sol), .eof(sof));//horizontal strobe for Deniseassign strhor = horbeam==15 ? 1 : 0;//--------------------------------------------------------------------------------------endmodule//--------------------------------------------------------------------------------------//--------------------------------------------------------------------------------------//--------------------------------------------------------------------------------------//bit plane dma enginemodule bpldma_engine( input clk, //bus clock input reset, //reset input enable, //enable dma input input [8:0]horbeam, //horizontal beam counter output reg dma, //true if bitplane dma engine uses it's cycle output reg interlace, //interlace mode is selected through bplcon0 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 BPLPTBASE=9'h0e0; //bitplane pointers base addressparameter DDFSTRT=9'h092; parameter DDFSTOP=9'h094;parameter BPL1MOD=9'h108;parameter BPL2MOD=9'h10a;parameter BPLCON0=9'h100;parameter BPLCON1=9'h102; //JB: needed for better ddfstrt/ddfstop handling//local signalsreg [8:2]ddfstrt; //display data fetch start //JB: added bit #2reg [8:2]ddfstop; //display data fetch stop //JB: added bit #2reg [15:1]bpl1mod; //modulo for odd bitplanesreg [15:1]bpl2mod; //modulo for even bitplanesreg [15:12]bplcon0; //bitplane control (HIRES and BPU bits)reg [7:0]bplcon1; //JB:reg hires; //JB:reg shres; //JB:reg [20:1]newpt; //new pointer reg [20:16]bplpth[7:0]; //upper 5 bits bitplane pointersreg [15:1]bplptl[7:0]; //lower 16 bits bitplane pointersreg [2:0]plane; //plane pointer selectwire mod; //end of data fetch, add modulo //JB: changed reg to wire//--------------------------------------------------------------------------------------//register bank address multiplexerwire [2:0]select;assign select=(dma)?plane:regaddressin[4:2];//high word pointer register bank (implemented using distributed ram)wire [20:16]bplpth_in;assign bplpth_in=(dma)?newpt[20:16]:datain[4:0];always @(posedge clk) if(dma || ((regaddressin[8:5]==BPLPTBASE[8:5]) && !regaddressin[1]))//if bitplane dma cycle or bus write bplpth[select]<=bplpth_in;assign addressout[20:16]=bplpth[plane];//low word pointer register bank (implemented using distributed ram)wire [15:1]bplptl_in;assign bplptl_in=(dma)?newpt[15:1]:datain[15:1];always @(posedge clk) if(dma || ((regaddressin[8:5]==BPLPTBASE[8:5]) && regaddressin[1]))//if bitplane dma cycle or bus write bplptl[select]<=bplptl_in;assign addressout[15:1]=bplptl[plane];//--------------------------------------------------------------------------------------//write ddfstrt and ddfstop registersalways @(posedge clk) if(regaddressin[8:1]==DDFSTRT[8:1]) if (datain[7:1] < 7'b0001_100) ddfstrt[8:2] <= 7'b0001_100; else ddfstrt[8:2]<=datain[7:1]; //JB: added LSB always @(posedge clk) if(regaddressin[8:1]==DDFSTOP[8:1]) if (datain[7:1] > 7'b1101_100) ddfstop[8:2] <= 7'b1101_100; else ddfstop[8:2] <= datain[7:1]; //JB: added LSB//write modulo registersalways @(posedge clk) if(regaddressin[8:1]==BPL1MOD[8:1]) bpl1mod[15:1]<=datain[15:1];always @(posedge clk) if(regaddressin[8:1]==BPL2MOD[8:1]) bpl2mod[15:1]<=datain[15:1];//write parts of bplcon0 register that are relevant to bitplane dma + interlace and ersyalways @(posedge clk) if(reset) begin bplcon0[15:12]<=4'b0000; interlace<=0; hires <= 0; //JB: shres <= 0; //JB: end else if(regaddressin[8:1]==BPLCON0[8:1]) begin bplcon0[15:12]<=datain[15:12]; interlace<=datain[2]; hires <= datain[15]; //JB: shres <= datain[6]; //JB: end//JB: needed for better ddf handling//write part of bplcon1 registeralways @(posedge clk) if (regaddressin[8:1] == BPLCON1[8:1]) bplcon1[7:0] <= datain[7:0];//--------------------------------------------------------------------------------------// (JB) More on mystical magic investigation after some experiments with my real A4k:// H3/H2 bits in DDFSTRT and DDFSTOP registers are important in all resolutions.// LORES:// if H3 or H2 of DDFSTRT is set the display is delayed by one full dma fetch cycle (8 colour clocks [cck])// it means that the display stop position is also shifted by 16 lowres pixels eventhough DDFSTOP hasn't changed// if H3:H2 of DDFSTOP is greater than H3:H2 of DDFSTRT the display is stopped after an extra dma cycle// (extra 16 pixels fetched in lowres, 32 in hires and 64 in super hires)// if the DDFSTOP is close enough to the HTOTAL value in some cases the dma engine doesn't see a display stop// and total display corruption happens, i.e:// DDFSTOP=$D4 and DDFSTRT[3:2]=%01,// DDFSTOP=$D6 and (DDFSTRT[3:2]=%01 or DDFSTRT[3:2]=%10),// DDFSTOP>=$D8 and DDFSTRT[3:2]!=%00 // if DDFSTOP > $D8 and DDFSTRT[3:2]=%00 the display stops at $D8 (hardware stop)// in lores dma cycles always begin and end on 8 colour clock (cck) cycle boundary// HIRES:// dma cycles can start and stop on 4 cck boundary and always last 8 ccks// if H2 of DDFSTART is set the display starts on next 4 cck boundary// (the display is a multiple of 32 hires pixels)// SUPER HIRES:// dma cycles can start and stop on 2 cck boundary and always last 8 ccks// (the display is a multiple of 64 super hires pixels)// in all resolutions the dma engine fetch cycle lasts 8 colour clocks// it can start at a multiple of: 8 cck's in lowres, 4 cck's in hires and 2 cck's in super hires// hint: SHRES bit in BPLCON0 takes precedence over HIRES bit// all tests were performed with FMODE=0// more magic: ddfstrt is delayed by one fetch cycle only if ddfstrt[3:2]>bplcon1[3:2] (tested only under UAE)wire [8:2]ddf_start;reg [3:2]ddfstrt_latched;reg [3:2]ddf_start_latched;reg [3:2]bplcon1_latched;wire [8:2]ddf_stop;wire [8:2]ddf_stop_delay;reg ddf_enable;wire [8:2]ddf_mask;assign ddf_mask = shres ? 7'b000_0000 : hires ? 7'b000_0001 : 7'b000_0011;//this should be rewritten someday to use more efficient codeassign ddf_start = ddfstrt-7'd1-bplcon1[3:2] | ddf_mask;assign ddf_stop_delay = ddfstop[3:2] > ddfstrt_latched[3:2] ? 7'd4 : 7'd0;assign ddf_stop = ({ddfstop[8:4],ddfstrt_latched[3:2]}-7'd1-bplcon1_latched[3:2] | ddf_mask) + ddf_stop_delay; //display dma last cyclereg ddf_last_fetch;// changing ddfstrt register value when display has already started doesn't affect the stop condition// so we have to store the initial value of ddfstrt to determine stop condition (only two bits do matter)always @(posedge clk) if (reset) begin ddfstrt_latched <= 2'b00; ddf_start_latched <= 2'b00; bplcon1_latched <= 2'b00; end else if ({ddf_start,2'b11} == horbeam[8:0]) begin ddfstrt_latched[3:2] <= ddfstrt[3:2]; ddf_start_latched[3:2] <= ddf_start[3:2]; bplcon1_latched <= bplcon1[3:2]; endalways @(posedge clk) if (reset) ddf_last_fetch <= 0; else if ({ddf_stop,2'b11} == horbeam[8:0]) ddf_last_fetch <= ddf_enable; else if ({ddf_start_latched[3:2],2'b11} == horbeam[3:0]) ddf_last_fetch <= 0; always @(posedge clk) if (reset) ddf_enable <= 0; else if ({ddf_start,2'b11} == horbeam[8:0]) ddf_enable <= 1; else if (ddf_last_fetch && {ddf_start_latched[3:2],2'b11} == horbeam[3:0]) ddf_enable <= 0;assign mod = (ddf_last_fetch) & (hires ? horbeam[3]^ddfstrt_latched[3] : shres ? (&(horbeam[3:2]^ddfstrt_latched[3:2])): 1'b1);assign ddfenable = ddf_enable;always @(shres or hires or horbeam) if (shres) plane = {2'b00,~horbeam[1]}; else if (hires) plane = {1'b0,~horbeam[1],~horbeam[2]}; else plane = {~horbeam[1],~horbeam[2],~horbeam[3]};//generate dma signal//for a dma to happen plane must be less than BPU (bplcon0), dma must be enabled//(enable) and datafetch compares must be true (ddfenable)//because invalid slots are coded as plane=7, the compare with BPU is//automatically falsealways @(plane or bplcon0[14:12] or horbeam[0] or enable or ddfenable)begin if(ddfenable && enable && horbeam[0])//if dma enabled and within ddf limits and dma slot begin if(plane[2:0]<bplcon0[14:12])//if valid plane dma=1; else dma=0; end else dma=0;end//--------------------------------------------------------------------------------------//dma pointer arithmetic unitalways @(addressout or bpl1mod or bpl2mod or plane[0] or mod) if(mod) begin if(plane[0])//even plane modulo newpt[20:1]=addressout[20:1]+{bpl2mod[15],bpl2mod[15],bpl2mod[15],bpl2mod[15],bpl2mod[15],bpl2mod[15:1]}+1; else//odd plane modulo newpt[20:1]=addressout[20:1]+{bpl1mod[15],bpl1mod[15],bpl1mod[15],bpl1mod[15],bpl1mod[15],bpl1mod[15:1]}+1; end else newpt[20:1]=addressout[20:1]+1;//Denise bitplane shift registers address lookup tablealways @(plane)begin case(plane) 3'b000: regaddressout[8:1]=8'h88; 3'b001: regaddressout[8:1]=8'h89; 3'b010: regaddressout[8:1]=8'h8a; 3'b011: regaddressout[8:1]=8'h8b; 3'b100: regaddressout[8:1]=8'h8c; 3'b101: regaddressout[8:1]=8'h8d; default: regaddressout[8:1]=8'hff; endcaseend//--------------------------------------------------------------------------------------endmodule//--------------------------------------------------------------------------------------//--------------------------------------------------------------------------------------//--------------------------------------------------------------------------------------/*JB: some conclusions of sprite engine investigation, it seems to be as follows:- during vblank sprite dma is disabled by hardware, no automatic fetches occur but copper or cpucan write to any sprite register, and all SPRxPTR pointers should be refreshed- during the last line of vblank (PAL: $19, NTSC: $14) if sprite dma is enabledit fetches SPRxPOS/SPRxCTL registers according to current SPRxPTR pointers This is the only chance for DMA to fetch new values of SPRxPOS/SPRxCTL. If DMA isn't enabledduring this line new values won't be placed into SPRxPOS/SPRxCTL registers. Enabling DMA after this line can have two results depending on current value of SPRxPOS/SPRxCTL.- if VSTOP value is matched first with VERBEAM, data from memory is fetched and placed into SPRxPOS/SPRxCTL- or if VSTART value is matched with VERBEAM, data from memory is fetched and placed into SPRxDATA/SPRxDATB and the situation repeats with every new line until VSTOP condition is met.The VSTOP condition takes precedence. If you set VSTART to value lower or the same (remember that VSTOP takes precedence) as the current VERBEAMthis condition will never be met and sprite engine will wait till VSTOP matches VERBEAM. If it happens then itfetches another two words into SPRxPOS/SPRxCTL. And again if new VSTART is lower or the same as VERBEAMit will fetch another new SPRxPOS/SPRxCTL when VSTOP is met (or will wait till next vbl).
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -