简单卷积器的设计docx.docx
《简单卷积器的设计docx.docx》由会员分享,可在线阅读,更多相关《简单卷积器的设计docx.docx(25页珍藏版)》请在冰豆网上搜索。
![简单卷积器的设计docx.docx](https://file1.bdocx.com/fileroot1/2022-12/15/ce36a416-b3eb-4495-88cb-aa285bc772cc/ce36a416-b3eb-4495-88cb-aa285bc772cc1.gif)
简单卷积器的设计docx
练习十
简单卷积器的设计
//'timescale100ps/100ps
modulecon1(address,indata,outdata,wr,neonvst,nbusy,
enout1,enout2,CLK,reset,start);
inputCLK,//采用10MHZ的时钟
reset,//复位信号
start,〃因为RAM的空间是有限的,当RAM存满后采样和卷积都会停止。
〃此时给一个start的高电平脉冲将会开始下一次的卷积。
nbusy;〃从A/D转换器来的信号表示转换器的忙或闲
outputwr,//RAM写控制信号
enout1,enout2,〃enout1是存储卷积低字节结果RAM的片选信号
//enout2是存储卷积高字节结果RAM的片选信号
nconvst,//给A/D转换器的控制信号,命令转换器开始工作,低电平有效address;//地址输出
input[7:
0]indata;//从A/D转换器来的数据总线
output[7:
0]outdata;//写到RAM去的数据总线
wirenbusy;
regwr;
regneonvst,
enoutl,enout2;
reg[7:
0]outdata;
reg[10:
0]address;reg[8:
0]state;reg[15:
0]result;
reg[23:
0]line;reg[11:
0]counter;reghigh;
reg[4:
0]j;regEOC;
parameterh1=1,h2=2,h3=3;〃假设的系统系数
parameterIDLE=9'b000000001,START=9'b000000010,NCONVST=9'b000000100,
READ=9'b000001000,CALCU=9'b000010000,WRREADY=9'b000100000,
WR=9'b001000000,WREND=9'b010000000,WAITFOR=9'b100000000;
parameterFMAX=20;〃因为A/D转换的时间是随机的,为保证按一定的频率采样,A/D
//转换控制信号应以一定频率给出。
这里采样频率通过FMAX控制
//为500KHZ。
always@(posedgeCLK)
if(!
reset)
begin
state<=IDLE;
neonvst<=1'b1;
enout1<=1;
enout2<=1;
eounter<=12'b0;
high<=0;
wr<=1;
line<=24'b0;
address<=11'b0;
end
else
ease(state)
IDLE:
if(start==1)
begin
eounter<=0;//eounter是一个计数器,记录已
〃用的RAM空间
line<=24'b0;
state<=START;
end
else
state<=IDLE;
//START状态控制A/D开始转换
START:
if(EOC)
begin
neonvst<=0;
high<=0;
state<=NCONVST;
end
else
state<=START;
//NCONVST状态是A/D转换保持阶段
NCONVST:
begin
neonvst<=1;
state<=READ;
end
//READ状态读取A/D转换结果,计算卷积结果
READ:
begin
if(EOC)
begin
line<={line[15:
0],indata};
state<=CALCU;
end
else
state<=READ;
end
CALCU:
begin
result<=line[7:
0]*h1+line[15:
8]*h2+line[23:
16]*h3;state<=WRREADY;
end
〃将卷积结果写入RAM时,先写入低字节,再写入高字节//WRREADY状态是写RAM准备状态,建立地址和数据信
WRREADY:
begin
address<=counter;
if(!
high)outdata<=result[7:
0];elseoutdata<=result[15:
8];
state<=WR;
end
//WR状态产生片选和写脉冲
WR:
begin
if(!
high)enout1<=0;
elseenout2<=0;
wr<=0;state<=WREND;
end
WRREADY
//WREND状态结束一次写操作,若还未写入高字节则转到
//态开始高字节写入
WREND:
begin
wr<=1;
enout1<=1;
enout2<=1;
if(!
high)
begin
high<=1;
state<=WRREADY;
end
elsestate<=WAITFOR;
end
//WAITFOR状态控制采样频率并判断RAM是否已被写满
WAITFOR:
begin
if(j==FMAX-1)
begin
counter<=counter+1;
if(!
counter[11])state<=START;
else
begin
state<=IDLE;
$display($time,"Theramisused
up.");
$stop;
end
end
elsestate<=WAITFOR;
end
default:
state<=IDLE;
endcase
//assignrd=1;//RAM的读信号始终保持为高
//j记录时钟,与FMAX共同控制采样频率
//由于直接用CLK的上升沿对nbusy判断以
//决定某些操作是否运行时,会因为两个信号
//的跳变沿相隔太近而令状态机不能正常工作。
因此
//利用CLK的下降沿建立EOC信号与nbusy同步,相位〃相差180度,然后用CLK的上升沿判断操作是否进行。
always@(negedgeCLK)
begin
EOC<=nbusy;
if(!
reset||state==START)
j<=1;
else
j<=j+1;
end
endmodule
//testconl.v
'timescale100ps/100psmoduletestconl;
wirewr,
enin,
enoutl,
enout2;
wire[10:
0]address;
regrd,
CLK,
reset,start;
wirenbusy;
wireneonvst;
wire[7:
0]indata;
wire[7:
0]outdata;
integeri;
parameterHALF_PERIOD=1000;
//产生10KHZ的时钟
initial
begin
rd=1;
i=0;
CLK=1;forever#HALF_PERIODCLK=~CLK;
end
//产生置位信号
initial
begin
reset=1;
#(HALF_PERIOD*2+50)reset=0;#(HALF_PERIOD*3)reset=1;
end
//产生开始卷积控制信号
initial
begin
start=0;
#(HALF_PERIOD*7+20)start=1;#(HALF_PERIOD*2)start=0;
#(HALF_PERIOD*1OOO)start=1;#(HALF_PERIOD*2)start=0;end
assignenin=1;
conicon(.address(address),.indata(indata),.outdata(outdata),.wr(wr),.nconvst(nconvst),.nbusy(nbusy),.enout1(enoutl),
.enout2(enout2),.CLK(CLK),.reset(reset),.start(start));
sramramlow(.Address(address),.Data(outdata),.SRW(wr),.SRG(rd),.SRE(enout1));adcadc(.nconvst(nconvst),.nbusy(nbusy),.data(indata));
endmodule
//卷积器的改进
//con3ad.v
'timescaleins/100ps
modulecon3ad(indata,outdata,address,CLK,reset,start,nconvsti,neonvst2,neonvst3,nbusyl,nbusy2,nbusy3,wr,enout1,enout2);
inputindata,
CLK,
reset,
start,
nbusyl,
nbusy2,
nbusy3;
outputoutdata,
address,
nconvsti,//采用三根控制线控制三片A/D转换器
neonvst2,
neonvst3,
wr,
enoutl,
enout2;
wire[7:
0]indata;
wireCLK,
reset,
start,
nbusyl,
nbusy2,
nbusy3;
reg[7:
0]outdata;
reg[10:
0]address;
regneonvsti,
neonvst2,
neonvst3,
wr,
enoutl,
enout2;
reg[6:
0]state;
reg[5:
0]i;
reg[1:
0]j;
reg[11:
0]counter;
reg[23:
0]line;
reg[15:
0]result;
reghigh;
regk;
regEOC1,EOC2,EOC3;
parameterh1=1,h2=2,h3=3;
parameterIDLE=7'b0000001,READ_PRE=7'b0000010,
READ=7'b0000100,CALCU=7'b0001000,
WR=7'b0100000,
WRREADY=7'b0010000,
WREND=7'b1000000;
always@(posedgeCLK)
begin
if(!
reset)
beginstate<=IDLE;
counter<=12'b0;
wr<=1;
enout1<=1;
enout2<=1;
outdata<=8'bz;
address<=11'bz;
line<=24'b0;
result<=16'b0;
high<=0;
end//endof"if"
else
begincase(state)
IDLE:
if(start)
begin
counter<=0;state<=READ_PRE;end
elsestate<=IDLE;
READ_PRE:
if(EOC1||EOC2||EOC3)//由于频率相对改进前的卷积//器大大提高,所以加入〃READ_PRE状态对取数操作〃予以缓冲。
state<=READ;
else
state<=READ_PRE;
READ:
begin
high<=0;
enout2<=1;
wr<=1;
if(j==1)
begin
if(EOC1)
begin
line<={line[15:
0],indata};state<=CALCU;endelsestate<=READ_PRE;
end
elseif(j==2&&counter!
=0)
beginif(EOC2)beginline<={line[15:
0],indata};state<=CALCU;
end
elsestate<=READ_PRE;
end
elseif(j==3&&counter!
=0)
begin
if(EOC3)
begin
line<={line[15:
0],indata};
state<=CALCU;
end
elsestate<=READ_PRE;
end
elsestate<=READ;
end
CALCU:
beginresult<=line[7:
0]*h1+line[15:
8]*h2+line[23:
16]*h;state<=WRREADY;
end
WRREADY:
begin
wr<=1;
address<=counter;
if(k==1)state<=WR;
elsestate<=WRREADY;
end
WR:
begin
if(!
high)
enout1<=0;
else
enout2<=0;
wr<=0;
if(!
high)
outdata<=result[7:
0];
else
outdata<=result[15:
8];
if(k==1)
state<=WREND;
else
state<=WR;
end
WREND:
begin
wr<=1;
enout1<=1;
enout2<=1;
if(k==1)
if(!
high)
begin
high<=1;state<=WRREADY;end
else
begin
counter<=counter+1;
if(counter[11]&&counter[0])state<=IDLE;
elsestate<=READ_PRE;end
elsestate<=WREND;
end
default:
state<=IDLE;
endcase//endofthecase
end//endof"else"
end//endof"always"
//计数器i用来记录时间
always@(posedgeCLK)
begin
if(!
reset)i<=0;
else
begin
if(i==44)i<=0;
elsei<=i+1;
end
end
//j是控制信号,协调卷积器轮流从三片A/D上读取数据。
always@(posedgeCLK)
begin
if(i==4)j<=2;
elseif(i==10)j<=0;
elseif(i==19)j<=3;
elseif(i==25)j<=0;
elseif(i==34)j<=1;
elseif(i==40)j<=0;
end
//k是计数器,用以控制写操作信号
always@(posedgeCLK)
begin
if(state==WRREADY||state==WR||state==WREND)
if(k==1)k<=0;
elsek<=1;
elsek<=0;
NCONVST3
end
//根据计数器i控制三片A/D转换信号NC0NVST1,NCONVST2,always@(posedgeCLK)
begin
if(!
reset)neonvst1<=1;
elseif(i==0)neonvst1<=0;
elseif(i==3)neonvst1<=1;
end
always@(posedgeCLK)
begin
if(!
reset)neonvst2<=1;
elseif(i==15)neonvst2<=0;
elseif(i==18)neonvst2<=1;
endalways@(posedgeCLK)
begin
if(!
reset)neonvst3<=1;
elseif(i==30)neonvst3<=0;
elseif(i==33)neonvst3<=1;
end
always@(negedgeCLK)
begin
EOC1<=nbusyl;
EOC2<=nbusy2;
EOC3<=nbusy3;
end
endmodule
〃测试程序如下:
'timescale1ns/100ps
moduletesteon3ad;
wirewr,
enin,
enoutl,
enout2;
wire[10:
0]address;
regelk,
reset,
start;
rd;
wirenbusyl,
nbusy2,
nbusy3;
wireneonvstl,
neonvst2,
neonvst3;
wire[7:
0]indata;
wire[7:
0]outdata;
parameterHALF_PERIOD=15;〃时钟周期为30nsinitialbegin
clk=1;
forever#HALF_PERIODclk=~clk;
end
initial
begin
reset=1;
#110reset=0;
#140reset=1;
end
initial
begin
start=0;
rd=1;
#420start=1;
#120start=0;
#107600start=1;
#150start=0;
end
assignenin=1;
con3adcon3ad(.indata(indata),.outdata(outdata),.address(address),
.CLK(clk),.reset(reset),.start(start),
.neonvst1(neonvst1),.neonvst2(neonvst2),.neonvst3(neonvst3),
.nbusy1(nbusy1),.nbusy2(nbusy2),.nbusy3(nbusy3),
.wr(wr),.enout1(enout1),.enout2(enout2));
sramramlow(.Address(address),.Data(outdata),.SRW(wr),.SRG(rd),.SRE(enout1));
adcad_1(.nconvst(nconvst1),.nbusy(nbusy1),.data(indata));
adcad_2(.nconvst(nconvst2),.nbusy(nbusy2),.data(indata));
adcad_3(.nconvst(nconvst3),.nbusy(nbusy3),.data(indata));
endmodule
//A/D转换器的VerilogHDL行为模型如下:
//adc.v
'timescale100ps/100ps
moduleadc(neonvst,nbusy,data);
inputneonvst;//A/D启动脉冲ST,即上图中
outputnbusy;//A/D工作标志,即上图中
outputdata;//数据总线,从AD.DATA文件中读取数据后经端口输出
reg[7:
0]databuf,i;//内部寄存器
regnbusy;
wire[7:
0]data;
reg[7:
0]data_mem[0:
255];
reglink_bus;
integertconv,
t5,
t8,
t9,
t12;
integerwideth1,
wideth2,
wideth;
//时间参数定义(依据AD7886手册):
always@(negedgeneonvst)
begin
tconv=9500+{$random}%500;//(type950ns,max1000ns)ConversionTimet5={$random}%1000;//(max100ns)CONVSTtoBUSYPropagationDlay//CL=10pf
t8=200;//(min20ns)CL=20pfDataSetupTimePriortoBUSY
//(min10ns)CL=100pf
t9=100+{$random}%900;
//(min10ns,max100ns)BusRelinquishTimeAfterCONVST
t12=2500;//(type)BUSYHightoCONVSTLow,SHAAcquisitionTime
endinitial
begin
$readmemh("adc.data",data_mem);〃从数据文件adc.data中读取数据
i=0;
nbusy=1;
link_bus=0;
end
assigndata=link_bus?
databuf:
8'bzz;//三态总线
/*
在信号nconvst的负跳降沿到来后,隔t5秒nbusy信号置为低,tconv是AD将模拟信号转
换为数字信号的时间,在信号nconvst的正跳降沿到来后经过tconv时间后,输出nbusy信
号变为高。
*/
always@(negedgeneonvst)
fork
#t5nbusy=0;
@(posedgeneonvst)begin
#teonvnbusy=1;
end
join
/*
neonvst信号的下降沿触发,经过t9延时后,把数据总线输出关闭置为高阻态,如图示。
nconvst信号的上升沿到来后,经过(tconv-⑹时间,输出一个字节(8位数据)到databuf,该数据来自于data_mem。
而data_mem中的数据是初始化时从数据文件AD.DATA中读取的。
此时应启动总线的三态输出。
*/always@(negedgeneonvst)
begin
@(posedgeneonvst)
begin
#(teonv-t8)databuf=data_mem[i];
end
if(wideth<10000&&wideth>500)
begin
if(i==255)i=0;
elsei=i+1;
end
elsei=i;
end
〃在模数转换期间关闭三态输出,转换结束时启动三态输出
always@(negedgeneonvst)
fork
#t9link_bus=1'b0;//关闭三态输出,不允许总线输出
@(posedgeneonv