📄 audio.v
字号:
endmodule//--------------------------------------------------------------------------------------//--------------------------------------------------------------------------------------//--------------------------------------------------------------------------------------//This module handles a single amiga audio channel. attached modes are not supportedmodule audiochannel(clk,reset,tick,aen,den,regaddress,data,volume,sample,intreq,intpen,dmareq,dmas);input clk; //bus clock input reset; //resetinput tick; //audio clock enableinput aen; //address enableinput den; //dma enableinput [3:1]regaddress; //register address inputinput [15:0]data; //bus data inputoutput [6:0]volume; //channel volume outputoutput [7:0]sample; //channel sample outputoutput intreq; //interrupt requestinput intpen; //interrupt pending inputoutput dmareq; //dma requestoutput dmas; //dma special (restart)//register names and addressesparameter AUDLEN=4'h4;parameter AUDPER=4'h6;parameter AUDVOL=4'h8;parameter AUDDAT=4'ha;//local signalsreg dmareq; //see abovereg dmas; //see abovereg intreq; //see abovereg [15:0]audlen; //audio length registerreg [15:0]audper; //audio period registerreg [6:0]audvol; //audio volume registerreg [15:0]auddat; //audio data registerreg [15:0]percount; //audio period counterreg [15:0]lencount; //audio length counterreg [15:0]datbuf; //audio data bufferreg [2:0]audiostate; //audio current statereg [2:0]audionext; //audio next statereg intreq2; //used to time interruptsreg datld; //load audio buffer from auddatreg datsh; //shift datbuf 8 bits to the left, shift in zero'sreg lendec; //decrement length counterreg lenload; //load length counterreg perload; //load period counterreg intrst; //intreq2 latch resetreg dma; //request dmawire lenfin; //length counter is 1wire perzero; //period counter is zerowire datwrite; //data register is written//-------------------------------------------------------------------------------------- //length register bus writealways @(posedge clk) if(reset) audlen[15:0]<=0; else if(aen && (regaddress[3:1]==AUDLEN[3:1])) audlen[15:0]<=data[15:0];//period register bus writealways @(posedge clk) if(reset) audper[15:0]<=0; else if(aen && (regaddress[3:1]==AUDPER[3:1])) audper[15:0]<=data[15:0];//volume register bus writealways @(posedge clk) if(reset) audvol[6:0]<=0; else if(aen && (regaddress[3:1]==AUDVOL[3:1])) audvol[6:0]<=data[6:0];//data register strobeassign datwrite=(aen && (regaddress[3:1]==AUDDAT[3:1]))?1:0;//data register bus writealways @(posedge clk) if(reset) auddat[15:0]<=0; else if(datwrite) auddat[15:0]<=data[15:0]; //--------------------------------------------------------------------------------------//period counter always @(posedge clk) if(perload || perzero)//load period counter from audio period register percount[15:0]<=audper[15:0]; else if(tick)//period counter count down percount[15:0]<=percount[15:0]-1;assign perzero=(percount[15:0]==0)?1:0;//length counter always @(posedge clk) if(lenload)//load length counter from audio length register lencount[15:0]<=audlen[15:0]; else if(lendec)//length counter count down lencount[15:0]<=lencount[15:0]-1;assign lenfin=(lencount[15:0]==1)?1:0;//--------------------------------------------------------------------------------------//audio bufferalways @(posedge clk) if(reset) datbuf[15:0]<=0; else if(datld) datbuf[15:0]<=auddat[15:0]; else if(datsh) datbuf[15:0]<={datbuf[7:0],8'h00}; //sample outputassign sample[7:0]=datbuf[15:8];//volume outputassign volume[6:0]=audvol[6:0];//--------------------------------------------------------------------------------------//dma request logic//dma is requested by main state machine//dma is cleared when auddat is written//if length counter is being reloaded, dma restart is requestedalways @(posedge clk)begin if(reset || datwrite) begin dmareq<=0; dmas<=0; end else if(dma) begin dmareq<=1; dmas<=lenload; endend//intreq2 latch//this signal is used to properly request interrupts in dma mode//if data from dma restart request has come in --> intreq2 is truealways @(posedge clk) if(reset||intrst) intreq2<=0; else if(dmas && den && datwrite)//(dmas=1 if restart request is pending) intreq2<=1;//audio statesparameter AUDIDLE=0;parameter AUDGET=1;parameter AUDSTATE1=2;parameter AUDSTATE2=3;parameter AUDSTATE3=4;//audio channel state machinealways @(posedge clk)begin if(reset) audiostate<=AUDIDLE; else audiostate<=audionext;endalways @(audiostate or den or datwrite or lenfin or intreq2 or perzero or intpen)begin case(audiostate) //audio state machine idle state (state 000) //mute output //reload period counter //start dma driven audio immediately if dma enabled //start interrupt driven audio immediately when auddat is written AUDIDLE: begin datld=0; datsh=1;//this mutes sample output after max 2 clocks intrst=0; lendec=0; lenload=1;//**dma restart enable** perload=0; intreq=0; dma=den; if(datwrite)//start interrupt driven audio audionext=AUDSTATE1; else if(den)//start dma driven audio audionext=AUDGET; else audionext=AUDIDLE; end //wait for first word of dma driven audio to arrive (state 101) //reset intreq2 latch //when it arrives, reload period counter, request interrupt and go to next state //if dma is disabled, return to idle state AUDGET: begin datld=0; datsh=0; intrst=1; lendec=0; lenload=0; perload=1; intreq=datwrite; dma=0; if(!den) audionext=AUDIDLE; else if(datwrite) audionext=AUDSTATE1; else audionext=AUDGET; end //state transition handling (transition 101->010 and 011->010) //load data from auddat to sample buffer //reset intreq2 latch //decrement length counter if len>1 //reload length counter if len=1 //request interrupt if dma disabled (interrupt driven mode) //request interrupt if intreq2 occurred(dma driven mode) //request new data by dma if dma enabled AUDSTATE1: begin datld=1; datsh=0; intrst=1; lendec=~lenfin; lenload=lenfin;//**dma restart enable** perload=0; intreq=~den|intreq2; dma=den; audionext=AUDSTATE2; end //first sample of word state (state 010) //load second sample when period counter expires //go to next state when period counter expires AUDSTATE2: begin datld=0; datsh=perzero; intrst=0; lendec=0; lenload=0; perload=0; intreq=0; dma=0; if(perzero)//next state audionext=AUDSTATE3; else//stay here audionext=AUDSTATE2; end //second sample of word state (state 011) //go to idle state when period counter expires and not (enabled or intterupt not pending) //else go to next state if period counter expires AUDSTATE3: begin datld=0; datsh=0; intrst=0; lendec=0; lenload=0; perload=0; intreq=0; dma=0; if(perzero && !(den || !intpen))//see HRM state diagram audionext=AUDIDLE; else if(perzero) audionext=AUDSTATE1; else audionext=AUDSTATE3; end //we should never come here (state 100,110,111) default: begin datld=1'bx; datsh=1'bx; intrst=1'bx; lendec=1'bx; lenload=1'bx; perload=1'bx; intreq=1'bx; dma=1'bx; audionext=AUDIDLE; end endcaseend//--------------------------------------------------------------------------------------endmodule
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -