📄 blitter.v
字号:
always @(posedge clk) if(enable && (chs[1:0]==CHD[1:0])) fcy<=fco;//channel D holding registeralways @(posedge clk) if(enable && (chs[1:0]==CHD[1:0])) dhold[15:0]<=fillout[15:0]; //channel D data output gateassign dataout[15:0]=(ackdma && (chs[1:0]==CHD))?dhold[15:0]:16'h0000;assign wr=(chs[1:0]==CHD)?1:0;//channel D blitter zero detectalways @(posedge clk) if(reset || sbz) bzero<=1;//reset blitter zero detector else if(enable && (chs[1:0]==CHD[1:0]) && (dhold[15:0]!=16'h0000)) bzero<=0;//non-zero output of channel D detected//--------------------------------------------------------------------------------------//Blitsize counter and control//This module keeps track of how many lines and words//we have to blit.//The main register bltsize is loaded from the bus and //then decremented during a channel D cycle (chs==CHD)//In line mode, channel D cycle happens twice for every pixel,//hence bltwidth is always 2 in line mode.//This module also generates <fwt> (first word time),//<lwt> (last word time) and <nml> (no more lines to blit)//Note that <nml> is only valid when <fwt> is true. This is to allow//heights of 1024 lines, which are written as 10'b0000000000//by the software. (see amiga hardware reference manual)//<start> is also controlled here (used to start the blitter state machine)//<bbusy1d> and <lwtd> are delayed version for channel D (pipeline delay)reg [10:0]bltwcount;//start controlalways @(posedge clk) if(reset) start <= 0; else if ( regaddressin[8:1] == BLTSIZE[8:1] || regaddressin[8:1] == BLTSIZH[8:1])//blitter is started by write to BLTSIZE start <= 1; else if (bbusy)//state machine has got the message, we can clear start now start <= 0;//bltwidth register (lower 6 bits of BLTSIZE)always @(posedge clk) if ( regaddressin[8:1] == BLTSIZE[8:1] ) bltwidth[10:0] <= { 4'b0000, (datain[5:0]==6'b00_0000)?1'b1:1'b0, datain[5:0] }; else if ( regaddressin[8:1] == BLTSIZH[8:1] ) bltwidth[10:0] <= datain[10:0];//bltwidth counter always @(posedge clk) if (regaddressin[8:1] == BLTSIZE[8:1] || regaddressin[8:1] == BLTSIZH[8:1])//blitsize written, go to first word time bltwcount[10:0] <= 11'b000_0000_0001; else if(enable && (chs[1:0]==CHD[1:0]))//decrement blitsize counter begin if (lwt) //if last word time, go to first word time bltwcount[10:0] <= 11'b000_0000_0001; else //else go to next word bltwcount[10:0] <= bltwcount[10:0] + 1'b1; end//bltheight register (upper 10 bits of BLTSIZE) and counter always @(posedge clk) if (regaddressin[8:1] == BLTSIZE[8:1]) //blitheight loaded by write to bltsize bltheight[14:0] <= { 4'b0000, (datain[15:6]==10'b00_0000_0000)?1'b1:1'b0, datain[15:6] }; else if (regaddressin[8:1] == BLTSIZH[8:1]) //blitheight loaded by write to bltsizh bltheight[14:0]<= bltsizv[14:0]; else if(enable && lwt && (chs[1:0]==CHD[1:0]))//if last word in this line decrement height counter bltheight[14:0] <= bltheight[14:0] - 1'b1;always @(posedge clk) if (regaddressin[8:1] == BLTSIZV[8:1]) //blitheight loaded by write to bltsizv bltsizv[14:0]<= datain[14:0];//generate fwt (first word time) signalassign fwt = (bltwcount[10:0] == 11'b000_0000_0001) ? 1 : 0;//generate lwt (last word time) signalassign lwt = (bltwcount[10:0] == bltwidth[10:0]) ? 1 : 0;//generate lwtd (delayed last word time) signal //and bbusyd1 (delayed bbusy1) signalalways @(posedge clk) if (regaddressin[8:1]==BLTSIZE[8:1] || regaddressin[8:1]==BLTSIZH[8:1])//reset signals upon BLTSIZE write, just to be sure begin lwtd<=1'b0; bbusyd<=1'b0; end else if(enable && (chs[1:0]==CHD[1:0])) begin lwtd<=lwt; bbusyd<=bbusy; end//generate nml (no more lines) signal (only valid during first word time)assign nml = ((bltheight[14:0] == 15'b000_0000_0000_0000) && fwt) ? 1 : 0;//--------------------------------------------------------------------------------------//instantiate address generatorbltaddress bltad1( .clk(clk), .reset(reset), .enable(enable), .modb(amb), .chs(chs), .alu({ame,ams,ape,apd}), .signout(signout), .datain(datain), .regaddressin(regaddressin), .addressout(addressout));//--------------------------------------------------------------------------------------//Blitter main controller logic//This code controls the blitter A, B, C and D channelreg [4:0]scn; //various signals vector used by main state machinereg [3:0]acn; //address/alu control vector used by main state machine//main statesparameter BLT_DONE=0;parameter BLT_NB_1=1;parameter BLT_NB_2=2;parameter BLT_NB_3=3;parameter BLT_NB_4=4;parameter BLT_LP_1=5;parameter BLT_LP_2=6;parameter BLT_LB_1=7;parameter BLT_LB_2=8;parameter BLT_LB_3=9;parameter BLT_LB_4=10; //Normal/line mode settingsalways @(bltcon1[0] or bltcon0[11:10] or chs)begin if(bltcon1[0])//line mode begin bpa=0;//channel A uses preload bpb=0;//channel B uses preload tmb=1;//channel B is in texturing mode efe=0;//fill mode disabled ife=0;//fill mode disabled desc=0;//ascending mode selected sing=bltcon1[1]&bltcon1[4];//special line mode according to bltcon if(chs[1:0]==CHA[1:0])//in line mode, channel A is accumulator and modulo's are always added begin ams=0; apd=0; end else//for all other channels (C and D) it depends on the octant begin if(bltcon1[4])//octant 0,3,4,7 begin ams=bltcon1[3];//up or down ? apd=bltcon1[2];//left or right ? end else//octant 1,2,5,6 begin ams=bltcon1[2];//up or down ? apd=bltcon1[3];//left or right ? end end end else//normal mode begin bpa=bltcon0[11];//if USEA, do not use channel A preload bpb=bltcon0[10];//if USEB, do not use channel B preload tmb=0;//channel B is in normal mode efe=bltcon1[4];//fill mode according to bltcon ife=bltcon1[3];//fill mode according to bltcon desc=bltcon1[1];//descending mode according to bltcon sing=0;//no special line mode ams=bltcon1[1];//modulo's are subtracted if descending mode apd=bltcon1[1];//pointers are decremented if descending mode endend//sign bit handling and fpl bit handlingalways @(posedge clk) if(!bbusyd)//if blitter not busy, copy sign from bltcon and preset fpl begin sign<=bltcon1[6]; fpl<=1; end //update sign flag and fpl bit (if first D cycle has happened and channel A cycle + dma enabled and line mode) else if(enable && bbusyd && bltcon0[11] && bltcon1[0] && (chs[1:0]==CHA[1:0])) begin sign<=signout; fpl<=~sign; end//enable signal control //enable controls most of the latches in the blitter//this is a very important signalalways @(horbeam or bbusy or reqdma or ackdma) if(reqdma && ackdma)//dma requested and granted, do external (dma) cycle enable=1; else if(!reqdma && bbusy && horbeam)//do internal cycle enable=1; else//do nothing (blitter not busy) enable=0; //bblck control//In order to let this blitter run at the same speed as in a real Amiga, it must block the cpu//in some cases. Apparently (according to winuae sources), cycles that are normally internal//(channel A/D when USEA/USED=0), DO allocate a bus slot when channel A is enabled in blitter nasty mode.//This effectively blocks the cpu from the chip bus. Also, when fill mode is enabled but channel C is not (USEC=0)//we also get some extra idle cycles (cpu is not blocked).//In line mode, blitter never blocks the cpu.//the following logic handles the bblck signalalways @(bltcon0 or bltcon1 or bbusy or bbusyd)begin if(bbusy&bbusyd)//blitter busy and not first cycle? //{FILL,LINE,USEA,USEC} case({bltcon1[3]|bltcon1[4],bltcon1[0],bltcon0[11],bltcon0[9]}) 4'b0000: bblck=0; 4'b0001: bblck=0; 4'b0010: bblck=1; 4'b0011: bblck=1; 4'b0100: bblck=0;//LINE MODE 4'b0101: bblck=0;//LINE MODE 4'b0110: bblck=0;//LINE MODE 4'b0111: bblck=0;//LINE MODE 4'b1000: bblck=0; 4'b1001: bblck=0; 4'b1010: bblck=0; 4'b1011: bblck=1; 4'b1100: bblck=0;//LINE MODE 4'b1101: bblck=0;//LINE MODE 4'b1110: bblck=0;//LINE MODE 4'b1111: bblck=0;//LINE MODE endcase else//blitter not busy bblck=0;end//state machine outputs//we use a couple of vectors here to keep the statemachine readable//various signals controlassign incash=scn[4];assign decash=scn[3];assign rlb=scn[2];assign sbz=scn[1];assign bbusy=scn[0];//address contolassign reqdma=acn[3]&horbeam;//only request DMA during odd slotsassign amb=acn[2];assign ame=acn[1];assign ape=acn[0];//main state machinealways @(posedge clk) if(reset)//master reset bltstate<=BLT_DONE; else if(enable || (start && !bbusy))//blitter next cycle if (enable) or (start pulse while not yet busy) bltstate<=bltnext;always @(bltstate or bltcon0 or lwt or lwtd or bbusyd or bltcon1 or sign or nml or plr)begin case(bltstate) BLT_DONE://blitter is done begin //-----IDRZB scn=5'b00000; //-----RBMA acn=4'b0x00; chs=CHB; if(!bltcon1[0])//start normal blit bltnext=BLT_NB_1; else//start line blit bltnext=BLT_LP_1; end BLT_LP_1://line blit preparation cycle 1 (load channel B 'old' register with texture) begin acn=4'b0x00; scn=5'b00001; chs=CHB; bltnext=BLT_LP_2; end BLT_LP_2://line blit preparation cycle 2 (load channel B holding register with texture) begin acn=4'b0x00; scn=5'b00001; chs=CHB; bltnext=BLT_LB_1; end BLT_LB_1://line blit cycle 1 (check accumulator, load channel A and update sign) begin acn={1'b0,sign,bbusyd,1'b0};//only update accumulator if not first cycle, sign selects modulo A/B scn=5'b00001; chs=CHA; if(nml && bbusyd)//check if blit is done bltnext=BLT_DONE; else bltnext=BLT_LB_2; end BLT_LB_2://line blit cycle 2 (load channel C) begin if(bltcon1[4]) acn={bltcon0[9],1'b0,~sign,plr}; else acn={bltcon0[9],2'b01,~sign&plr}; scn=5'b00001; chs=CHC; bltnext=BLT_LB_3; end BLT_LB_3://line blit cycle 3 (load channel D and point to next texture bit) begin acn=4'b0x00; scn=5'b00101; chs=CHD; bltnext=BLT_LB_4; end BLT_LB_4://line blit cycle 4 (write channel D and update shifter channel A) begin if(bltcon1[4]) begin acn={bltcon0[9],1'b1,~sign,plr};//modulo C is used for channel D also in line mode scn={~bltcon1[2],bltcon1[2],3'b001}; end else begin acn={bltcon0[9],2'b11,~sign&plr}; scn={~bltcon1[3]&~sign,bltcon1[3]&~sign,3'b001}; end chs=CHD; if(nml)//PANIC! this shouldn't happen but just in case... bltnext=BLT_DONE; else bltnext=BLT_LB_1; end BLT_NB_1://normal blit cycle 1 begin if(nml && bbusyd)//blit is done, handle data still in pipeline begin if(bltcon0[8])//DMA acn={2'b10,lwtd,1'b1}; else//internal acn=4'b0x00; //-----IDRZB scn=5'b00001; chs=CHD; bltnext=BLT_DONE; end else//else handle channel A begin if(bltcon0[11])//DMA acn={2'b10,lwt,1'b1}; else//internal acn=4'b0x00; //-----IDRZB scn=5'b00001; chs=CHA; if(bltcon0[10]) bltnext=BLT_NB_2; else if(bltcon0[9]) bltnext=BLT_NB_3; else bltnext=BLT_NB_4; end end BLT_NB_2://normal blitter operation cycle 2 (always dma, skipped otherwise) begin acn={2'b10,lwt,1'b1}; scn=5'b00001;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -