// Copyright 2006, 2007 Dennis van Weeren // // This file is part of Minimig // // Minimig is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or // (at your option) any later version. // // Minimig is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // // // // This is the Blitter (part of the Agnus chip) // // 14-08-2005 -started coding // 16-08-2005 -done more coding // 19-08-2005 -added C source channel // -added minterm function generator // 21-08-2005 -added proper masking for A channel // -added fill logic and D destination channel // -added normal/line mode control logic // -added address generator but it needs more work to reduce slices // 23-08-2005 -done more work // -added blitsize counter // 24-08-2005 -done some cleanup // 28-08-2005 -redesigned address generator module // -started coding of main state machine // 29-08-2005 -added blitter zero detect // -added logic for special line mode to channel D // 31-08-2005 -blitsize is now decremented automatically during channel D cycle // -added delayed version for lwt called lwtd (needed for pipelining) // 04-09-2005 -added state machine for normal blitter mode // -added data output gate in channel D (needed for integration into Agnus) // 05-09-2005 -fixed bug in bltaddress module // -modified state machine start of blit handling // 06-09-2005 -restored state machine, we should now have a working blitter (normal mode) // -fixed bug, channel B preload didn't work // 14-09-2005 -fixed bug in channel A masking logic when doing 1 word wide blits // (and subsequently found another error in the Hardware Reference Manual) // 18-09-2005 -added sign bit handling for line mode // -redesigned address pointer ALU // -adapted state machine to use new style ALU codes // -added experimental line mode for octant 0,3,4,7 // 19-09-2005 -fixed bugs in line mode state machine and it begins to start working.. // 20-09-2005 -testing // 25-09-2005 -complete redesign of controller logic // -added new linemode logic for all octants // 27-09-2005 -fixed problem in linemode with dma/channel D modulo: it seems like the real blitter // uses only C modulo for channel C and D during linemode, same for USEC/USED // -sign is taken from bit 15 of pointer A, NOT bit 20! -->fixed // -line drawing in octant 0,3,4,7 now works! // 28-09-2005 -line drawing in octant 1,2,5,6 now works too! // 02-10-2005 -special line draw mode added (single bit per horizontal line) // this completes the blitter (but some bugs may still remain...) // 17-10-2005 -fixed typo in sensitivity list of always block // 22-01-2006 -fixed bug in special line draw mode // 25-01-2006 -added bblck signal // 14-02-2006 -improved bblck table // 07-07-2006 -added some comments // 25-12-07 Redskulldc : Start adding ECS components module blitter(clk,reset,reqdma,ackdma,bzero,bbusy,bblck,horbeam,wr,datain,dataout,regaddressin,addressout); input clk; //bus clock input reset; //reset output reqdma; //blitter requests dma cycle input ackdma; //agnus dma priority logic grants dma cycle output bzero; //blitter zero status output bbusy; //blitter busy status output bblck; //blitter is blocking cpu, cpu may not access chip bus input horbeam; //least significant bit of horbeam[] output wr; //write (blitter writes to memory) input [15:0] datain; //bus data in output [15:0] dataout; //bus data out input [8:1] regaddressin; //register address inputs output [20:1] addressout; //chip address outputs //register names and adresses parameter BLTCON0=9'h040; parameter BLTCON1=9'h042; parameter BLTAFWM=9'h044; parameter BLTALWM=9'h046; parameter BLTADAT=9'h074; parameter BLTBDAT=9'h072; parameter BLTCDAT=9'h070; parameter BLTSIZE=9'h058; parameter BLTSIZV=9'h05C; //ECS new Blitter V size (for 15 bit vertical start) parameter BLTSIZH=9'h05E; //ECS new Blitter H size and start (for 11 bit H size) //channel select codes parameter CHA=2'b00; //channel A parameter CHB=2'b01; //channel B parameter CHC=2'b10; //channel C parameter CHD=2'b11; //channel D //local signals reg bzero; //see above reg bblck; //see above reg [15:0]bltcon0; //blitter control register 0 reg [15:0]bltcon1; //blitter control register 1 reg [15:0]bltafwm; //blitter first word mask for source A reg [15:0]bltalwm; //blitter last word mask for source A reg [15:0]bltadat; //blitter source A preload data register reg [15:0]bltbdat; //blitter source B preload data register reg [15:0]bltaold; //blitter source A 'old' data reg [15:0]bltbold; //blitter source B 'old' data reg [15:0]ahold; //A holding register reg [15:0]bhold; //B holding register reg [15:0]chold; //C holding register reg [15:0]dhold; //D holding register //reg [5:0]bltwidth; //blitsize number of words (width) --OCS //reg [9:0]bltheight; //blitsize number of lines (height) --OCS reg [10:0]bltwidth; //blitsize number of words (width = 11) reg [14:0]bltheight; //blitsize number of lines (height = 15) reg [4:0]bltstate; //blitter state reg [4:0]bltnext; //blitter next state reg ife; //enable inclusive fill mode reg efe; //enable exclusive fill mode reg desc; //descending mode reg bpa; //bypass preload register for channel A reg bpb; //bypass preload register for channel B reg tmb; //channel B is in texturing mode reg sing; //single bit per horizontal line (special line mode) reg enable; //blit cycle enable signal reg [1:0]chs; //channel select(A,B,C,D) wire ame; //instruct address generator to add or subtract modulo (enable) reg ams; //instruct address generator to subtract modulo wire ape; //instruct address generator increment or decrement pointer (enable) reg apd; //instruct address generator to decrement pointer wire amb; //instruct address generator to only use modulo B and C wire sbz; //set blitter zero bit wire incash; //increment ASH (line mode) wire decash; //decrement ASH (line mode) wire rlb; //rotate B holding register to the left (line mode) reg fpl; //first pixel on horizontal line signal used for special line draw mode (SING) reg start; //blitter is started by write to BLTSIZE or BLTSIZH (ECS) wire fwt; //first word time wire lwt; //last word time reg bbusyd; //bbusy delayed for channel D modulo handling reg lwtd; //last word time delayed for channel D modulo handling wire nml; //no more lines to blit (blit is done), only valid during first word time wire signout; //new accumulator sign calculated by address generator (line mode) reg sign; //current sign of accumulator (line mode) reg plr; //move pointer left or right due to shifter roll over (line mode) //-------------------------------------------------------------------------------------- //bltcon0 ASH part //In order to move the $8000 value in BLTADAT around during line mode //the value of ASH can be changed by the main controlling state machine always @(posedge clk) if(reset) bltcon0[15:12]<=0; else if(enable && incash)//increment (used in line mode) bltcon0[15:12]<=bltcon0[15:12]+{decash,decash,decash,1'b1}; else if(enable && decash)//decrement (used in line mode) bltcon0[15:12]<=bltcon0[15:12]+{decash,decash,decash,1'b1}; else if (regaddressin[8:1]==BLTCON0[8:1])//written from bus (68000 or copper) bltcon0[15:12]<=datain[15:12]; //generate plr signal, this is used to detect if we have to increment/decrement channel C/D pointers //during line mode (sort of shifter carry out/roll over out) always @(bltcon0 or bltcon1) if(bltcon1[4])//octant 0,3,4,7 plr=(bltcon0[15]&bltcon0[14]&bltcon0[13]&bltcon0[12]&!bltcon1[2]) | (!bltcon0[15]&!bltcon0[14]&!bltcon0[13]&!bltcon0[12]&bltcon1[2]); else//octant 1,2,5,6 plr=(bltcon0[15]&bltcon0[14]&bltcon0[13]&bltcon0[12]&!bltcon1[3]) | (!bltcon0[15]&!bltcon0[14]&!bltcon0[13]&!bltcon0[12]&bltcon1[3]); //bltcon0 USE and LF part always @(posedge clk) if(reset) bltcon0[11:0]<=0; else if (regaddressin[8:1]==BLTCON0[8:1]) bltcon0[11:0]<=datain[11:0]; //writing of bltcon1 from bus always @(posedge clk) if(reset) bltcon1[15:0]<=0; else if (regaddressin[8:1]==BLTCON1[8:1]) bltcon1[15:0]<=datain[15:0]; //-------------------------------------------------------------------------------------- //writing of bltafwm from bus always @(posedge clk) if(reset) bltafwm[15:0]<=0; else if (regaddressin[8:1]==BLTAFWM[8:1]) bltafwm[15:0]<=datain[15:0]; //writing of bltalwm from bus always @(posedge clk) if(reset) bltalwm[15:0]<=0; else if (regaddressin[8:1]==BLTALWM[8:1]) bltalwm[15:0]<=datain[15:0]; //writing of bltadat from bus (preload) always @(posedge clk) if(reset) bltadat[15:0]<=0; else if(regaddressin[8:1]==BLTADAT[8:1]) bltadat[15:0]<=datain[15:0]; //writing of bltbdat from bus (preload) always @(posedge clk) if(reset) bltbdat[15:0]<=0; else if(regaddressin[8:1]==BLTBDAT[8:1]) bltbdat[15:0]<=datain[15:0]; //-------------------------------------------------------------------------------------- //A and B channel processing chain //these channels share a single barrel shifter to save slices //The channel B holding register can be directly loaded by writing from the bus //to BLTBDAT. //local signals reg [15:0]amux; reg [15:0]amask; reg [15:0]bmux; wire [15:0]newmux; wire [15:0]oldmux; wire [3:0]shmux; wire [15:0]shiftout; //channel A mask select always @(bltafwm or bltalwm or fwt or lwt) if(fwt && lwt) amask[15:0]=bltafwm[15:0]&bltalwm[15:0]; else if(fwt) amask[15:0]=bltafwm[15:0]; else if(lwt) amask[15:0]=bltalwm[15:0]; else amask[15:0]=16'b1111111111111111; //channel A source select mux always @(bltadat or datain or amask or bpa) if(bpa) amux[15:0]=datain[15:0]&amask[15:0]; else amux[15:0]=bltadat[15:0]&amask[15:0]; //channel A 'old' register always @(posedge clk) if(!bbusy) bltaold[15:0]<=0; else if(enable && (chs[1:0]==CHA[1:0])) bltaold[15:0]<=amux[15:0]; //channel A holding register always @(posedge clk) if(enable && (chs[1:0]==CHA[1:0])) ahold[15:0]<=shiftout[15:0]; //channel B source select mux always @(bltbdat or datain or bpb or regaddressin) if(bpb || (regaddressin[8:1]==BLTBDAT[8:1])) bmux[15:0]=datain[15:0]; else bmux[15:0]=bltbdat[15:0]; //channel B 'old' register always @(posedge clk) if(!bbusy) bltbold[15:0]<=0; else if(enable && (chs[1:0]==CHB[1:0])) bltbold[15:0]<=bmux[15:0]; //channel B holding register always @(posedge clk) if(enable && rlb)//rotate register to the left (line mode) bhold[15:0]<={bhold[14:0],bhold[15]}; else if((enable && (chs[1:0]==CHB[1:0])) || (regaddressin[8:1]==BLTBDAT[8:1])) bhold[15:0]<=shiftout[15:0]; //multiplexed barrel shifter for channel A and channel B //the multiplexer is controlled by lhs (holding register select) assign newmux[15:0]=(chs[1:0]==CHA[1:0])?amux[15:0]:bmux[15:0]; assign oldmux[15:0]=(chs[1:0]==CHA[1:0])?bltaold[15:0]:bltbold[15:0]; assign shmux[3:0]=(chs[1:0]==CHA[1:0])?bltcon0[15:12]:bltcon1[15:12]; bltshift blts1 ( .desc(desc), .sh(shmux), .newm(newmux), .old(oldmux), .out(shiftout) ); //-------------------------------------------------------------------------------------- //C channel processing chain //This channel is very simple as it has only a holding register //the holding register can be preloaded from the bus or loaded by dma //channel C holding register always @(posedge clk) if((enable && (chs[1:0]==CHC[1:0])) || (regaddressin[8:1]==BLTCDAT[8:1])) chold[15:0]<=datain[15:0]; //-------------------------------------------------------------------------------------- //D channel processing chain //The D channel is the output channel. The data from sources A,B and C are //combined here by the minterm generator. Then the data is fed through the //fill logic and loaded into the channel D holding register. //local signals reg [15:0]ain; //A channel input for minterm generator reg [15:0]bin; //B channel input for minterm generator wire [15:0]mintermout; //minterm generator output wire [15:0]fillout; //fill logic output wire fci; //fill carry in wire fco; //fill carry out to next word reg fcy; //fill carry latch //minterm A channel input select: special line draw mode or normal blit mode always @(sing or fpl or ahold) if(sing && !fpl) ain[15:0]=16'h0000; else ain[15:0]=ahold[15:0]; //minterm A channel input select: line texturing mode or normal blit mode always @(tmb or bhold) if(tmb)//nomal line draw mode (apply texture) bin[15:0]={bhold[0],bhold[0],bhold[0],bhold[0],bhold[0],bhold[0],bhold[0],bhold[0],bhold[0],bhold[0],bhold[0],bhold[0],bhold[0],bhold[0],bhold[0],bhold[0]}; else//normal blit mode bin[15:0]=bhold[15:0]; //minterm generator instantation bltminterm bltmt1 ( .lf(bltcon0[7:0]), .ain(ain[15:0]), .bin(bin[15:0]), .cin(chold[15:0]), .out(mintermout[15:0]) ); //fill logic instantiation bltfill bltfl1 ( .ife(ife), .efe(efe), .fci(fci), .fco(fco), .in(mintermout[15:0]), .out(fillout[15:0]) ); //fill carry control assign fci=(fwt)?bltcon1[2]:fcy; always @(posedge clk) if(enable && (chs[1:0]==CHD[1:0])) fcy<=fco; //channel D holding register always @(posedge clk) if(enable && (chs[1:0]==CHD[1:0])) dhold[15:0]<=fillout[15:0]; //channel D data output gate assign 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 detect always @(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 (first word time), // (last word time) and (no more lines to blit) //Note that is only valid when is true. This is to allow //heights of 1024 lines, which are written as 10'b0000000000 //by the software. (see amiga hardware reference manual) // is also controlled here (used to start the blitter state machine) // and are delayed version for channel D (pipeline delay) //reg [5:0]bltwcount; //--OCS reg [10:0]bltwcount; //start control always @(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/BLTSIZH 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) //Pad to 11bits for ECS //or bltwidth register (lower 11 bits of BLTSIZH) --ECS new always @(posedge clk) if(regaddressin[8:1]==BLTSIZE[8:1]) bltwidth[10:0]<= {5'b00000,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 or blitsizh written, go to first word time bltwcount[10:0]<= 11'b00000000001; 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'b00000000001; else//else go to next word bltwcount[10:0]<=bltwcount[10:0]+1'b1; end //bltheight register (upper 10 bits of BLTSIZE, or first 15bits of BLTSIZV) and counter always @(posedge clk) if(regaddressin[8:1]==BLTSIZE[8:1])//blitheight loaded by write to bltsize bltheight[14:0]<= {5'b00000,datain[15:6]}; //pad for ECS else if(regaddressin[8:1]==BLTSIZV[8:1])//blitheight loaded by write to bltsizh bltheight[14:0]<=datain[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; //generate fwt (first word time) signal assign fwt=(bltwcount[10:0]==11'b00000000001)?1:0; //generate lwt (last word time) signal assign lwt=(bltwcount[10:0]==bltwidth[10:0])?1:0; //generate lwtd (delayed last word time) signal //and bbusyd1 (delayed bbusy1) signal always @(posedge clk) if((regaddressin[8:1]==BLTSIZE[8:1])||(regaddressin[8:1]==BLTSIZH[8:1]))//reset signals upon BLTSIZE or BLTSIZH 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'b000000000000000) && fwt)?1:0; //-------------------------------------------------------------------------------------- //instantiate address generator bltaddress 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 channel reg [4:0]scn; //various signals vector used by main state machine reg [3:0]acn; //address/alu control vector used by main state machine //main states parameter 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 settings always @(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 end end //sign bit handling and fpl bit handling always @(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 signal always @(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 signal always @(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 control assign incash=scn[4]; assign decash=scn[3]; assign rlb=scn[2]; assign sbz=scn[1]; assign bbusy=scn[0]; //address contol assign reqdma=acn[3]&horbeam;//only request DMA during odd slots assign amb=acn[2]; assign ame=acn[1]; assign ape=acn[0]; //main state machine always @(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; chs=CHB; if(bltcon0[9]) bltnext=BLT_NB_3; else bltnext=BLT_NB_4; end BLT_NB_3://normal blitter operation cycle 3 (always dma, skipped otherwise) begin acn={2'b10,lwt,1'b1}; scn=5'b00001; chs=CHC; bltnext=BLT_NB_4; end BLT_NB_4://normal blitter operation cycle 4 begin if(bltcon0[8] && bbusyd)//DMA (only if not first cycle) acn={2'b10,lwtd,1'b1}; else//internal acn=4'b0x00; scn={3'b000,~bbusyd,1'b1};//if first (dummy) cycle, set blitter zero flag chs=CHD; bltnext=BLT_NB_1; end default://unknown state, go back to reset state begin //-----IDRZB scn=5'bxxxx1; //-----RBMA acn=4'b0xxx; chs=2'bxx; bltnext=BLT_DONE; end endcase end //-------------------------------------------------------------------------------------- endmodule //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- //Blitter barrel shifter //This module can shift 0-15 positions/bits to the right (normal mode) or to the left //(descending mode). Inputs are two words, and . //For example, when shifting to the right, //the bits to the left are filled with . The bits of that //are shifted out are discarded. module bltshift(desc,sh,newm,old,out); input desc; //select descending mode (shift to the left) input [3:0]sh; //shift value (0 to 15) input [15:0] newm; //barrel shifter data in input [15:0] old; //barrel shifter data in output [15:0] out; //barrel shifter data out //local signals reg [15:0]out; //see above wire [30:0]bshiftin; //barrel shifter input wire [3:0]bsh; //barrel shift value //cross multiplexer feeding barrelshifter assign bshiftin[30:0]=(desc)?{newm[15:0],old[15:1]}:{old[14:0],newm[15:0]}; //shift value generator for barrel shifter assign bsh[3:0]=(desc)?(~sh[3:0]):sh[3:0]; //actual barrel shifter always @(bsh or bshiftin) case(bsh[3:0]) 0: out[15:0]=bshiftin[15:0]; 1: out[15:0]=bshiftin[16:1]; 2: out[15:0]=bshiftin[17:2]; 3: out[15:0]=bshiftin[18:3]; 4: out[15:0]=bshiftin[19:4]; 5: out[15:0]=bshiftin[20:5]; 6: out[15:0]=bshiftin[21:6]; 7: out[15:0]=bshiftin[22:7]; 8: out[15:0]=bshiftin[23:8]; 9: out[15:0]=bshiftin[24:9]; 10: out[15:0]=bshiftin[25:10]; 11: out[15:0]=bshiftin[26:11]; 12: out[15:0]=bshiftin[27:12]; 13: out[15:0]=bshiftin[28:13]; 14: out[15:0]=bshiftin[29:14]; 15: out[15:0]=bshiftin[30:15]; endcase endmodule //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- //Blitter minterm function generator //The minterm function generator takes , and //and checks every logic combination against the LF control byte. //If a combination is marked as 1 in the LF byte, the ouput will //also be 1, else the output is 0. module bltminterm(lf,ain,bin,cin,out); input [7:0]lf; //LF control byte input [15:0]ain; //A channel in input [15:0]bin; //B channel in input [15:0]cin; //C channel in output [15:0]out; //function generator output reg [15:0]mt0; //minterm 0 reg [15:0]mt1; //minterm 1 reg [15:0]mt2; //minterm 2 reg [15:0]mt3; //minterm 3 reg [15:0]mt4; //minterm 4 reg [15:0]mt5; //minterm 5 reg [15:0]mt6; //minterm 6 reg [15:0]mt7; //minterm 7 //Minterm generator for each bit. The code inside the loop //describes one bit. The loop is 'unrolled' by the //synthesizer to cover all 16 bits in the word. integer j; always @(ain or bin or cin or lf) for(j=15;j>=0;j=j-1) begin mt0[j]=(~ain[j])&(~bin[j])&(~cin[j])&lf[0]; mt1[j]=(~ain[j])&(~bin[j])&( cin[j])&lf[1]; mt2[j]=(~ain[j])&( bin[j])&(~cin[j])&lf[2]; mt3[j]=(~ain[j])&( bin[j])&( cin[j])&lf[3]; mt4[j]=( ain[j])&(~bin[j])&(~cin[j])&lf[4]; mt5[j]=( ain[j])&(~bin[j])&( cin[j])&lf[5]; mt6[j]=( ain[j])&( bin[j])&(~cin[j])&lf[6]; mt7[j]=( ain[j])&( bin[j])&( cin[j])&lf[7]; end //Generate function generator output by or-ing all //minterms together. assign out=mt0|mt1|mt2|mt3|mt4|mt5|mt6|mt7; endmodule //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- //Blitter fill logic //The fill logic module has 2 modes, inclusive fill and exclusive fill. //Both share the same xor operation but in inclusive fill mode, //the output of the xor-filler is or-ed with the input data. module bltfill(ife,efe,fci,fco,in,out); input ife; //inclusive fill enable input efe; //exclusive fill enable input fci; //fill carry input output fco; //fill carry output input [15:0]in; //data in output [15:0]out; //data out //local signals reg [15:0]out; reg [15:0]carry; //generate all fill carry's integer j; always @(fci or in[0])//least significant bit carry[0]=fci^in[0]; always @(in or carry)//rest of bits for(j=1;j<=15;j=j+1) carry[j]=carry[j-1]^in[j]; //fill carry output assign fco=carry[15]; //fill data output always @(ife or efe or carry or in) if(efe)//exclusive fill out[15:0]=carry[15:0]; else if(ife)//inclusive fill out[15:0]=carry[15:0]|in[15:0]; else//bypass, no filling out[15:0]=in[15:0]; endmodule //-------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------- //Blitter address generator //This module generates the addresses for blitter DMA //It has 4 21bit pointer registers, 4 16bit modulo //registers and an ALU that can add and subtract //alu function codes bits [3:2]: //00 = bypass (no operation) //01 = bypass (no operation) //10 = add modulo //11 = subtract modulo //alu function codes bits [1:0]: //00 = bypass (no operation) //01 = bypass (no operation) //10 = add 2 (next word) //11 = subtract 2 (previous word) // //when modb=1, address pointer selection remains unchanged but modulo selection is as follows: //chs[1:0] modb=0 modb=1 //2'b00 A B //2'b01 B B //2'b10 C C //2'b11 D C module bltaddress(clk,reset,enable,modb,chs,alu,signout,datain,regaddressin,addressout); input clk; //bus clock input reset; //reset input enable; //cycle enable input input modb; //always select modulo B or C (dependening of chs[1]) input [1:0]chs; //channel select input [3:0]alu; //ALU function select output signout; //sign output (used for line mode) input [15:0]datain; //bus data in input [8:1]regaddressin; //register address input output [20:1]addressout; //generated address out //register names and addresses parameter BLTAMOD=9'h064; parameter BLTBMOD=9'h062; parameter BLTCMOD=9'h060; parameter BLTDMOD=9'h066; parameter BLTAPTH=9'h050; parameter BLTAPTL=9'h052; parameter BLTBPTH=9'h04c; parameter BLTBPTL=9'h04e; parameter BLTCPTH=9'h048; parameter BLTCPTL=9'h04a; parameter BLTDPTH=9'h054; parameter BLTDPTL=9'h056; //local signals reg [20:1]addressout; //see above reg [15:1]bltamod; //blitter modulo for source A reg [15:1]bltbmod; //blitter modulo for source B reg [15:1]bltcmod; //blitter modulo for source C reg [15:1]bltdmod; //blitter modulo for destination D reg [20:1]bltapt; //blitter pointer A reg [20:1]bltbpt; //blitter pointer B reg [20:1]bltcpt; //blitter pointer C reg [20:1]bltdpt; //blitter pointer D reg [20:1]newpt; //new pointer reg [15:1]modulo; //modulo //-------------------------------------------------------------------------------------- //writing of bltamod from bus always @(posedge clk) if(reset) bltamod[15:1]<=0; else if (regaddressin[8:1]==BLTAMOD[8:1]) bltamod[15:1]<=datain[15:1]; //writing of bltbmod from bus always @(posedge clk) if(reset) bltbmod[15:1]<=0; else if (regaddressin[8:1]==BLTBMOD[8:1]) bltbmod[15:1]<=datain[15:1]; //writing of bltcmod from bus always @(posedge clk) if(reset) bltcmod[15:1]<=0; else if (regaddressin[8:1]==BLTCMOD[8:1]) bltcmod[15:1]<=datain[15:1]; //writing of bltdmod from bus always @(posedge clk) if(reset) bltdmod[15:1]<=0; else if (regaddressin[8:1]==BLTDMOD[8:1]) bltdmod[15:1]<=datain[15:1]; //-------------------------------------------------------------------------------------- //pointer bank input multiplexer wire [20:1]ptin; assign ptin[20:1]=(enable)?newpt[20:1]:{datain[4:0],datain[15:1]}; //writing of blitter pointer A always @(posedge clk) if((enable && (chs[1:0]==2'b00)) || (regaddressin[8:1]==BLTAPTH[8:1])) bltapt[20:16]<=ptin[20:16]; always @(posedge clk) if((enable && (chs[1:0]==2'b00)) || (regaddressin[8:1]==BLTAPTL[8:1])) bltapt[15:1]<=ptin[15:1]; //writing of blitter pointer B always @(posedge clk) if((enable && (chs[1:0]==2'b01)) || (regaddressin[8:1]==BLTBPTH[8:1])) bltbpt[20:16]<=ptin[20:16]; always @(posedge clk) if((enable && (chs[1:0]==2'b01)) || (regaddressin[8:1]==BLTBPTL[8:1])) bltbpt[15:1]<=ptin[15:1]; //writing of blitter pointer C always @(posedge clk) if((enable && (chs[1:0]==2'b10)) || (regaddressin[8:1]==BLTCPTH[8:1])) bltcpt[20:16]<=ptin[20:16]; always @(posedge clk) if((enable && (chs[1:0]==2'b10)) || (regaddressin[8:1]==BLTCPTL[8:1])) bltcpt[15:1]<=ptin[15:1]; //writing of blitter pointer D always @(posedge clk) if((enable && (chs[1:0]==2'b11)) || (regaddressin[8:1]==BLTDPTH[8:1])) bltdpt[20:16]<=ptin[20:16]; always @(posedge clk) if((enable && (chs[1:0]==2'b11)) || (regaddressin[8:1]==BLTDPTL[8:1])) bltdpt[15:1]<=ptin[15:1]; //-------------------------------------------------------------------------------------- //address output multiplexer always @(chs or bltapt or bltbpt or bltcpt or bltdpt) case(chs[1:0]) 2'b00://channel A addressout[20:1]=bltapt; 2'b01://channel B addressout[20:1]=bltbpt; 2'b10://channel C addressout[20:1]=bltcpt; 2'b11://channel D addressout[20:1]=bltdpt; endcase //-------------------------------------------------------------------------------------- //modulo multiplexer wire [1:0]msel; assign msel[1:0]=(modb)?{chs[1],~chs[1]}:chs[1:0]; always @(msel or bltamod or bltbmod or bltcmod or bltdmod) case(msel[1:0]) 2'b00://channel A modulo[15:1]=bltamod[15:1]; 2'b01://channel B modulo[15:1]=bltbmod[15:1]; 2'b10://channel C modulo[15:1]=bltcmod[15:1]; 2'b11://channel D modulo[15:1]=bltdmod[15:1]; endcase //-------------------------------------------------------------------------------------- //ALU //The ALU calculates a new address pointer based on the value of modulo //and the selected ALU operation reg [20:1]npt; //first adder/subtracter always @(alu or addressout) case(alu[1:0]) 2'b10: npt[20:1]=addressout[20:1]+20'h1; // + 1 2'b11: npt[20:1]=addressout[20:1]-20'h1; // - 1 default: npt[20:1]=addressout[20:1]; // bypass endcase //second adder/subtracter always @(alu or npt or modulo) case(alu[3:2]) 2'b10: newpt[20:1]=npt[20:1]+{modulo[15],modulo[15],modulo[15],modulo[15],modulo[15],modulo[15:1]}; // + modulo 2'b11: newpt[20:1]=npt[20:1]-{modulo[15],modulo[15],modulo[15],modulo[15],modulo[15],modulo[15:1]}; // - modulo default: newpt[20:1]=npt[20:1]; // bypass endcase //sign output assign signout=newpt[15]; endmodule