⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 copper.v

📁 Verilog, c and asm source codes of the Minimig system, a fpga implementation of the Amiga computer.
💻 V
字号:
// 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 <http://www.gnu.org/licenses/>.//////// This is the Copper (part of the Agnus chip)//// 24-05-2005	-started coding (created all user accessible registers)// 25-05-2005	-added beam counter compare logic// 29-05-2005	-added blitter finished disable logic//				-added copper danger/address range check logic//				-added controlling state machine//				-adapted to use reqdma/ackdma model//				-first finished version// 11-09-2005	-added proper reset for copper location registers// 24-09-2005	-fixed bug, when an illegal register is loaded by MOVE,//				 the copper must halt until the next strobe or vertical blank.//				 the copper now does this properly// 02-10-2005	-modified skip instruction to only skip MOVE instructions.// 19-10-2005	-replaced vertb (vertical blank) signal by sof (start of frame)// 07-12-2005	-added dummy cycle after copper wakeup, this is needed for copperlists//				 that wait for vertical beamcounter rollover ($FFDF,FFFE)//				 The dummy cycle is indicated by making both selins and selreg high.// 26-12-2005	-added exception for last cycle of horizontal line, this cycle is not used by copper//
// JB:// 2008-03-03	- ECS copper danger behaviour// 2008-07-08	- cleanup
// 2008-07-17	- real Amiga copper timing (thanks to Toni Wilen for help)//
// Although I have spent a lot of time trying to figure out the real behaviour of Amiga hardware this solution is far from complete.
module copper(	input 	clk,	 					//bus clock	input 	reset,	 					//reset	output	reg reqdma,				//copper requests dma cycle	input	ackdma,						//agnus dma priority logic grants dma cycle	input	sof,						//start of frame input	input	eol,						//start of line input	input	bbusy,						//blitter busy flag input	input	[7:0]vpos,				//vertical beam counter	input 	[15:0]datain,	    		//bus data in	input 	[8:1]regaddressin,		//register address inputs	output 	reg [8:1]regaddressout, 	//register address outputs	output 	reg [20:1]addressout 		//chip address outputs);//register names and adresses		parameter COP1LCH=9'h080;parameter COP1LCL=9'h082;parameter COP2LCH=9'h084;parameter COP2LCL=9'h086;parameter COPCON=9'h02e;parameter COPINS=9'h08c;parameter COPJMP1=9'h088;parameter COPJMP2=9'h08a;//local signalsreg		[8:0]hpos;		//horizontal beam counterreg		[20:16]cop1lch;	//copper location register 1reg		[15:1]cop1lcl;	//copper location register 1reg		[20:16]cop2lch;	//copper location register 2reg		[15:1]cop2lcl;	//copper location register 2reg		cdang;				//copper danger bitreg		[15:1]ir1;		//instruction register 1reg		[15:0]ir2;		//instruction register 2reg		[2:0]copperstate;	//current state of copper state machinereg		[2:0]coppernext;	//next state of copper state machinereg		strobe1;			//strobe 1 reg		strobe2;			//strobe 2 reg		beammatch;			//true if beamcounters >= value in instruction registerreg		illegalreg;			//illegal register (MOVE instruction)reg		skipmove;			//skip move instruction latchreg		selins;				//load instruction register (register address out = COPINS)reg		selreg;				//load chip register address, when both selins and selreg are active							//a dummy cycle is executedreg		skip;				//skip next move instruction (input to skipmove register)//--------------------------------------------------------------------------------------//local horizontal counter - to compensate for WAIT instruction delay it is advanced 4 lores pixels
//the last cycle in line is not usable by copper so the max hpos visible to copper is $E2always @(posedge clk)	if (eol)		hpos = 4;	else		hpos = hpos + 1;//write copper location register 1 high and low wordalways @(posedge clk)	if(reset)		cop1lch[20:16]<=0;	else if(regaddressin[8:1]==COP1LCH[8:1])		cop1lch[20:16]<=datain[4:0];
		always @(posedge clk)	if(reset)		cop1lcl[15:1]<=0;	else if(regaddressin[8:1]==COP1LCL[8:1])		cop1lcl[15:1]<=datain[15:1];//write copper location register 2 high and low wordalways @(posedge clk)	if(reset)		cop2lch[20:16]<=0;	else if(regaddressin[8:1]==COP2LCH[8:1])		cop2lch[20:16]<=datain[4:0];
always @(posedge clk)	if(reset)		cop2lcl[15:1]<=0;	else if(regaddressin[8:1]==COP2LCL[8:1])		cop2lcl[15:1]<=datain[15:1];//write copcon register (copper danger bit)always @(posedge clk)	if(reset)		cdang<=0;	else if(regaddressin[8:1]==COPCON[8:1])		cdang<=datain[1];//copper instruction registers ir1 and ir2always @(posedge clk)	if(regaddressin[8:1]==COPINS[8:1])	begin		ir1[15:1]<=ir2[15:1];		ir2[15:0]<=datain[15:0];	end//--------------------------------------------------------------------------------------//chip address pointer (or copper program counter) controlleralways @(posedge clk)	if (strobe1)//load pointer with location register 1		addressout[20:1] <= {cop1lch[20:16],cop1lcl[15:1]};	else if (strobe2)//load pointer with location register 2		addressout[20:1] <= {cop2lch[20:16],cop2lcl[15:1]};	else if (ackdma && !(selins && selreg))//increment address pointer (when not dummy cycle) 		addressout[20:1] <= addressout[20:1] + 1;//--------------------------------------------------------------------------------------//regaddress output select//if selins=1 the address of the copper instruction register//is sent out (not strictly necessary as we can load copins directly. However, this is //more according to what happens in a real amiga... I think), else the contents of//ir2[8:1] is selected //(if you ask yourself: IR2? is this a bug? then check how ir1/ir2 are loaded in this design)always @(selins or selreg or ir2)	if (selins && !selreg) //load our instruction register		regaddressout[8:1] = COPINS[8:1];	else if (selreg && !selins)//load register in move instruction		regaddressout[8:1] = ir2[8:1];	else		regaddressout[8:1] = 8'hFF;//during dummy cycle null register address is present//detect illegal register accessalways @(ir2 or cdang)	if((ir2[8:7] == 2'b00) && (cdang==0))//$000 -> $07E illegal if cdang=0		illegalreg = 1;	else//$080 -> $1FE always allowed		illegalreg = 0;//--------------------------------------------------------------------------------------//strobe1 (also triggered by sof, start of frame)always @(regaddressin or sof)	if( (regaddressin[8:1]==COPJMP1[8:1]) || sof )		strobe1=1;	else		strobe1=0;//strobe2always @(regaddressin)	if(regaddressin[8:1]==COPJMP2[8:1])		strobe2=1;	else		strobe2=0;//--------------------------------------------------------------------------------------//beam compare circuitry//when the mask for a compare bit is 1, the beamcounter is compared with that bit,//when the mask is 0, the compare bit is replaced with the corresponding beamcounter bit//itself, thus the compare is always true.//the blitter busy flag is also checked if blitter finished disable is falsewire [8:2]horcmp;wire [7:0]vercmp;//construct compare value for horizontal beam counter (4 lores pixels resolution)assign horcmp[2]=(ir2[1])?ir1[1]:hpos[2];assign horcmp[3]=(ir2[2])?ir1[2]:hpos[3];assign horcmp[4]=(ir2[3])?ir1[3]:hpos[4];assign horcmp[5]=(ir2[4])?ir1[4]:hpos[5];assign horcmp[6]=(ir2[5])?ir1[5]:hpos[6];assign horcmp[7]=(ir2[6])?ir1[6]:hpos[7];assign horcmp[8]=(ir2[7])?ir1[7]:hpos[8];//construct compare value for vertical beam counter (1 line resolution)assign vercmp[0]=(ir2[8])?ir1[8]:vpos[0];assign vercmp[1]=(ir2[9])?ir1[9]:vpos[1];assign vercmp[2]=(ir2[10])?ir1[10]:vpos[2];assign vercmp[3]=(ir2[11])?ir1[11]:vpos[3];assign vercmp[4]=(ir2[12])?ir1[12]:vpos[4];assign vercmp[5]=(ir2[13])?ir1[13]:vpos[5];assign vercmp[6]=(ir2[14])?ir1[14]:vpos[6];assign vercmp[7]=ir1[15]; //final beamcounter compare logic //(also takes bbusy/blitter finished disable into account)always @(hpos or vpos or vercmp or horcmp or ir2[15] or bbusy)	if({vpos[7:0],hpos[8:2]}>={vercmp[7:0],horcmp[8:2]})	begin		if(ir2[15])//blitter finished disabled			beammatch=1;		else if(!bbusy)//blitter is finished			beammatch=1;		else//blitter not finished yet			beammatch=0;	end	else		beammatch=0;//--------------------------------------------------------------------------------------    //copper statesparameter RESET1   = 3'b000;parameter RESET2   = 3'b001;parameter FETCH1   = 3'b101;parameter FETCH2   = 3'b111;parameter DUMMY    = 3'b110;parameter WAITSKIP = 3'b100;//copper state machine and skipmove latchalways @(posedge clk)	if (reset || strobe1 || strobe2)//on strobe or reset fetch first instruction word		copperstate <= RESET1;	else if (ackdma || (copperstate==RESET1 && hpos[1:0]==2'b01))//if granted dma cycle go to next state		copperstate <= coppernext;always @(posedge clk)	if (ackdma)//if granted dma cycle go to next state		skipmove <= skip;always @(copperstate or ir2 or beammatch or illegalreg or skipmove)begin	case(copperstate)	
		//when COPJMPx is written there is 2 cycle delay before data from new location is read to COPINS
		//usually first cycle is a read of the next instruction to COPINS or bitplane DMA,
		//the second is dma free cycle (it's a dummy cycle requested by copper but not used to transfer data)
		
		//even cycle without dma slot		RESET1:		begin			skip = 0;			selins = 0;			selreg = 0;			coppernext = RESET2;		end		
		//dummy cycle with dma slot allocation		RESET2:		begin			skip = 0;			selins = 1;	//dummy cycle (setting both selins and selreg prevents location pointer from incrementation)			selreg = 1;			coppernext = FETCH1;		end				//fetch first instruction word		FETCH1:		begin			skip = skipmove;			selins = 1;			selreg = 0;			coppernext = FETCH2;		end		//fetch second instruction word, skip or do MOVE instruction or halt copper		FETCH2:					begin			if (!ir2[0] && illegalreg)//illegal MOVE instruction, halt copper			begin				skip = 0;				selins = 0;				selreg = 0;				coppernext = FETCH2;			end			else if (!ir2[0] && skipmove)//skip this MOVE instruction			begin				skip = 0;				selins = 1;				selreg = 0;				coppernext = FETCH1;			end			else if(!ir2[0])//MOVE instruction			begin				skip = 0;				selins = 0;				selreg = 1;				coppernext = FETCH1;			end			else//fetch second instruction word of WAIT or SKIP instruction			begin				skip = 0;				selins = 1;				selreg = 0;				coppernext = DUMMY;			end		end				//both SKIP and WAIT have the same timing when WAIT is immediatelly complete
		//both this instructions complete in 4 cycles and these cycles must be allocated dma cycles
		//first cycle seems to be dummy		DUMMY:		begin			skip = 0;			selins = 1;//both selins and selreg high --> this is a dummy cycle			selreg = 1;//both selins and selreg high --> this is a dummy cycle			coppernext = WAITSKIP;		end		
		//second cycle of WAIT or SKIP (allocated dma)		//WAIT or SKIP instruction		WAITSKIP:		begin			if (!ir2[0])//WAIT instruction			begin				if (beammatch)//wait is over, fetch next instruction				begin					skip = 0;					selins = 1;//both selins and selreg high --> this is a dummy cycle					selreg = 1;//both selins and selreg high --> this is a dummy cycle					coppernext = FETCH1;				end				else//still waiting				begin					skip = 0;					selins = 0;					selreg = 0;					coppernext = WAITSKIP;				end			end			else//SKIP instruction			begin				if (beammatch)//compare is true, fetch next instruction and skip it if it's MOVE				begin					skip = 1;					selins = 1;					selreg = 1;					coppernext = FETCH1;				end				else//do not skip, fetch next instruction				begin					skip = 0;					selins = 1;					selreg = 1;					coppernext = FETCH1;				end			end		end				//default, go back to reset state		default:		begin			skip = 1'b0;			selins = 1'b0;			selreg = 1'b0;			coppernext = FETCH1;		end			endcaseend	//--------------------------------------------------------------------------------------//generate request dma (reqdma) signal			 //for a dma to be requested first of all the cycle must be right (hpos[1:0])
//(copper only uses even cycles: hpos[1:0]==2'b01)//second, selins or selreg must be true (state machine request bus operation)//the last cycle in a line is not usable by the copper (see AHRM)always @(selins or selreg or hpos[1:0])	if( (hpos[8:2]!=7'b1110001) && (hpos[1:0]==2'b01) && (selins || selreg) )//request dma cycle		reqdma=1;			else		reqdma=0;//--------------------------------------------------------------------------------------endmodule

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -