1698|1

3186

帖子

0

TA的资源

纯净的硅(高级)

楼主
 

夏宇闻老师书第16章例子仿真的问题 [复制链接]

程序实现一个EEPROM(AT24C02/4/8/16)

代码如下:

`timescale 1ns/1ps

module EEPROM_WR(sda,scl,ACK,RESET,CLK,WR,RD,ADDR,DATA);
output scl;
output ACK;
input RESET;
input CLK;
input WR,RD;
input [10:0] ADDR;
inout sda;
inout [7:0] DATA;

reg ACK;
reg scl;
reg WF,RF;
reg FF;
reg [1:0] head_buf;
reg [1:0] stop_buf;
reg [7:0] sh8out_buf;
reg [8:0] sh8out_state;
reg [9:0] sh8in_state;
reg [2:0] head_state;
reg [2:0] stop_state;
reg [10:0] main_state;
reg [7:0] data_from_rm;
reg link_sda;
reg link_read;
reg link_head;
reg link_write;
reg link_stop;
wire sda1,sda2,sda3,sda4;

//串行数据在开关控制下有秩序的输出或输入
assign sda1=(link_head) ? head_buf[1] :1'b0;
assign sda2=(link_write) ? sh8out_buf[7] : 1'b0;
assign sda3=(link_stop) ?stop_buf[1] :1'b0;
assign sda4=(sda1|sda2|sda3);
assign sda=(link_sda)? sda4:1'bz;
assign DATA=(link_read)?data_from_rm:8'hzz;

//主状态机状态定义

parameter 
	Idle				=11'b00000000001,
	Ready				=11'b00000000010,
	Write_start		=11'b00000000100,
	Ctrl_write		=11'b00000001000,
	Addr_write		=11'b00000010000,
	Data_write		=11'b00000100000,
	Read_start		=11'b00001000000,
	Ctrl_read		=11'b00010000000,
	Data_read		=11'b00100000000,
	Stop   			=11'b01000000000,
	Ackn				=11'b10000000000,
	
//并行数据串行输出状态
	sh8out_bit7=9'b000000001,
	sh8out_bit6=9'b000000010,
	sh8out_bit5=9'b000000100,
	sh8out_bit4=9'b000001000,
	sh8out_bit3=9'b000010000,
	sh8out_bit2=9'b000100000,
	sh8out_bit1=9'b001000000,
	sh8out_bit0=9'b010000000,
	sh8out_end =9'b100000000;
	
//串行数据并行输出状态
parameter sh8in_begin			=10'b0000000001,
			 sh8in_bit7				=10'b0000000010,
			 sh8in_bit6				=10'b0000000100,
			 sh8in_bit5				=10'b0000001000,
			 sh8in_bit4				=10'b0000010000,
			 sh8in_bit3				=10'b0000100000,
			 sh8in_bit2				=10'b0001000000,
			 sh8in_bit1				=10'b0010000000,
			 sh8in_bit0				=10'b0100000000,
			 sh8in_end				=10'b1000000000,
			 
//启动状态
			head_begin=3'b001,
			head_bit	 =3'b010,
			head_end	 =3'b100,
//停止状态
			stop_begin	=3'b001,
			stop_bit		=3'b010,
			stop_end		=3'b100;

parameter	YES	=1,
				NO		=0;
//产生串行时钟SCL,为输入时钟的2分频
always @(negedge CLK)
	if(RESET)
		scl<=0;
	else	
		scl<=~scl;
		
//主状态机程序
always @(posedge CLK)
	if(RESET)
		begin
			link_read<=NO;
			link_write<=NO;
			link_head<=NO;
			link_stop<=NO;
			link_sda<=NO;
			ACK<=0;
			RF<=0;
			WF<=0;
			FF<=0;
			main_state<=Idle;
		end
	else	
		begin
			casex(main_state)
				Idle:
					begin	
						link_read<=NO;
						link_write<=NO;
						link_head<=NO;
						link_stop<=NO;
						link_sda<=NO;
						if(WR)
							begin
								WF<=1;
								main_state<=Ready;
							end
						else if(RD)
							begin
								RF<=1;
								main_state<=Ready;
							end
						else
							begin
								WF<=0;
								RF<=0;
								main_state<=Idle;
							end
						end
				Ready:
					begin	
						link_read<=NO;
						link_write<=NO;
						link_stop<=NO;
						link_head<=YES;
						link_sda<=YES;
						head_buf[1:0]<=2'b10;
						stop_buf[1:0]<=2'b01;
						head_state<=head_begin;
						FF<=0;
						ACK<=0;
						main_state<=Write_start;
					end
		Write_start:
					if(FF==0)
						shift_head;
					else
						begin
							sh8out_buf[7:0]<={1'b1,1'b0,1'b1,1'b0,ADDR[10:8],1'b0};
							link_head<=NO;
							link_write<=YES;
							FF<=0;
							sh8out_state<=sh8out_bit6;
							main_state<=Ctrl_write;
						end
	Ctrl_write:
					if(FF==0)
						shift8_out;
					else
						begin
							sh8out_state<=sh8out_bit7;
							sh8out_buf[7:0] <= ADDR[7:0];
							FF<=0;
							main_state<=Addr_write;
						end
	Addr_write:
					if(FF==0)
						shift8_out;
					else
						begin
							FF<=0;
							if(WF)
								begin
									sh8out_state  <=   sh8out_bit7;
									sh8out_buf[7:0] <=DATA;
									main_state	<=Data_write;
							  end
							if(RF)
								begin
									head_buf  <= 2'b10;
									head_state<=head_begin;
									main_state<=Read_start;
								end
					 end
	Data_write:
			if(FF==0)
				shift8_out;
			else
				begin	
					stop_state<=stop_begin;
					main_state<=Stop;
					link_write<=NO;
					FF<=0;
				end
	Read_start:
			if(FF==0)
				shift_head;
			else	
				begin
					sh8out_buf<={1'b1,1'b0,1'b1,1'b0,ADDR[10:8],1'b1};
					link_head<=NO;
					link_sda<=YES;
					link_write<=YES;
					FF<=0;
					sh8out_state<=sh8out_bit6;
					main_state<=Ctrl_read;
				end
	Ctrl_read:
			if(FF==0)
				shift8_out;
			else
				begin
					
					link_sda<=NO;
					link_write<=NO;
					FF<=0;
					sh8in_state<=sh8in_begin;
					main_state<=Data_read;
				end
				
	Data_read:
			if(FF==0)
				shift8in;
			else	
				begin
					link_stop<=YES;
					link_sda<=YES;
					stop_state<=stop_bit;
					FF<=0;
					main_state<=Stop;
				end
	Stop:
			if(FF==0)
				shift_stop;
			else
				begin
					ACK<=1;
					FF<=0;
					main_state<=Ackn;
				end
				
	Ackn:
			begin	
				ACK<=0;
				WF<=0;
				RF<=0;
				main_state<=Idle;
			end
	default:
			main_state<=Idle;
	endcase
end
//串行数据转换为并行数据任务
task shift8in;
		begin
			casex(sh8in_state)
				sh8in_begin:
					sh8in_state<=sh8in_bit7;
				sh8in_bit7:
					if(scl)
						begin
							data_from_rm[7] <=sda;
							sh8in_state<=sh8in_bit6;
						end
					else
						sh8in_state<=sh8in_bit7;
			   sh8in_bit6:
					if(scl)
						begin
							data_from_rm[6] <=sda;
							sh8in_state<=sh8in_bit5;
						end
					else
						sh8in_state<=sh8in_bit6;
				sh8in_bit5:
					if(scl)
						begin
							data_from_rm[5] <=sda;
							sh8in_state<=sh8in_bit4;
						end
					else
						sh8in_state<=sh8in_bit5;
				sh8in_bit4:
					if(scl)
						begin
							data_from_rm[4] <=sda;
							sh8in_state<=sh8in_bit3;
						end
					else
						sh8in_state<=sh8in_bit4;
				sh8in_bit3:
					if(scl)
						begin
							data_from_rm[3] <=sda;
							sh8in_state<=sh8in_bit2;
						end
					else
						sh8in_state<=sh8in_bit3;
				sh8in_bit2:
					if(scl)
						begin
							data_from_rm[2] <=sda;
							sh8in_state<=sh8in_bit1;
						end
					else
						sh8in_state<=sh8in_bit2;
				sh8in_bit1:
					if(scl)
						begin
							data_from_rm[1] <=sda;
							sh8in_state<=sh8in_bit0;
						end
					else
						sh8in_state<=sh8in_bit1;
				sh8in_bit0:
					if(scl)
						begin
							data_from_rm[0] <=sda;
							sh8in_state<=sh8in_end;
						end
					else
						sh8in_state<=sh8in_bit0;
				sh8in_end:
					if(scl)
						begin
							link_read<=YES;
							FF<=1;
							sh8in_state<=sh8in_bit7;
						end
					else
						sh8in_state<=sh8in_end;
				default:
					begin
						link_read<=NO;
						sh8in_state<=sh8in_bit7;
					end
			endcase
		end
	endtask
	
//并行数据转换为串行数据任务
task shift8_out;
	begin
		casex(sh8out_state)
			sh8out_bit7:
				if(!scl)
					begin
						link_sda<=YES;
						link_write<=YES;
						sh8out_state<=sh8out_bit6;
					end
				else
					sh8out_state<=sh8out_bit7;
			sh8out_bit6:
				if(!scl)
					begin
						link_sda<=YES;
						link_write<=YES;
						sh8out_state<=sh8out_bit5;
						sh8out_buf<=sh8out_buf<<1;
					end
				else
					sh8out_state<=sh8out_bit6;
			sh8out_bit5:
				if(!scl)
					begin
						
						sh8out_state<=sh8out_bit4;
						sh8out_buf<=sh8out_buf<<1;
					end
				else
					sh8out_state<=sh8out_bit5;
			sh8out_bit4:
				if(!scl)
					begin
						
						sh8out_state<=sh8out_bit3;
						sh8out_buf<=sh8out_buf<<1;
					end
				else
					sh8out_state<=sh8out_bit4;	
			sh8out_bit3:
				if(!scl)
					begin
						
						sh8out_state<=sh8out_bit2;
						sh8out_buf<=sh8out_buf<<1;
					end
				else
					sh8out_state<=sh8out_bit3;	
			sh8out_bit2:
				if(!scl)
					begin
						
						sh8out_state<=sh8out_bit1;
						sh8out_buf<=sh8out_buf<<1;
					end
				else
					sh8out_state<=sh8out_bit2;
			sh8out_bit1:
				if(!scl)
					begin
						
						sh8out_state<=sh8out_bit0;
						sh8out_buf<=sh8out_buf<<1;
					end
				else
					sh8out_state<=sh8out_bit1;	
			sh8out_bit0:
				if(!scl)
					begin
						
						sh8out_state<=sh8out_end;
						sh8out_buf<=sh8out_buf<<1;
					end
				else
					sh8out_state<=sh8out_bit0;		
		 sh8out_end:
				if(!scl)
					begin
						
						link_sda<=NO;
						link_write<=NO;
						FF<=1;
						
					end
				else
					sh8out_state<=sh8out_end;	
			endcase
		end
	endtask
	
//输出启动信号任务
task shift_head;
	begin
		casex(head_state)
			head_begin:
				if(!scl)
					begin
						link_write<=NO;
						link_sda<=YES;
						link_head<=YES;
						head_state<=head_bit;
					end
				else
					head_state<=head_begin;
			head_bit:
				if(scl)
					begin	
						FF<=1;
						head_buf<=head_buf<<1;
						head_state<=head_end;
					end
				else
					head_state<=head_bit;
			head_end:
				if(!scl)
					begin
						link_head<=NO;
						link_write<=YES;
					end
				else
					head_state<=head_end;
			endcase
		end
	endtask
	
//输出停止信号任务
task shift_stop;
	begin	
	
		casex(stop_state)
			stop_begin:
				if(!scl)
					begin		
						link_sda<=YES;
						link_write<=NO;
						link_stop<=YES;
						stop_state<=stop_bit;
					end
				else
					stop_state<=stop_begin;
			stop_bit:
				if(scl)
					begin	
						stop_buf<=stop_buf<<1;
						stop_state<=stop_end;
					end
				else
					stop_state<=stop_bit;
			stop_end:
				if(!scl)
					begin
						link_head<=NO;
						link_stop<=NO;
						link_sda<=NO;
						FF<=1;
					end
				else
					stop_state<=stop_end;
					
			endcase
		end
	endtask
endmodule

				
	
				
				
				

仿真文件如下:

`timescale 1ns/1ps
`define timeslice 200

module signal(RESET,CLK,RD,WR,ADDR,ACK,DATA);
output RESET;
output CLK;
output RD,WR;
output [10:0] ADDR;
input ACK;
inout [7:0] DATA;

reg RESET;
reg CLK;
reg RD,WR;
reg W_R;
reg [10:0] ADDR;
reg [7:0] data_to_eeprom;
reg [10:0] addr_mem[0:255];
reg [7:0] data_mem[0:255];
reg [7:0] ROM[1:2047];
integer i,j;
integer OUTFILE;

parameter test_number=5;
assign DATA=(W_R)? 8'bz:data_to_eeprom;

always #(`timeslice/2)
	CLK=~CLK;

//读写信号输入
initial
	begin
		i=0;j=0;
		W_R=0;
		CLK=0;
		RD=0;
		WR=0;
		#1000;
		RESET=0;
		repeat(test_number)
		begin
			#(5*`timeslice);
			WR=1;
			#(`timeslice);
			WR=0;
			@(posedge ACK);
		end
		#(10* `timeslice);
		W_R=1;
		repeat(test_number)
			begin
				#(5*`timeslice);
				RD=1;
				#(`timeslice);
				RD=0;
				@(posedge ACK);
			end
		end
//写操作
initial
	begin
		$display("writing-----writing-----writing-----writing");
		#(2*`timeslice);
		for(i=0;i<test_number;i=i+1)
			begin	
				ADDR=addr_mem[i];
				data_to_eeprom=data_mem[i];
				$fdisplay(OUTFILE,"@%0h   %0h",ADDR,data_to_eeprom);
				@(posedge ACK);
			end
		end
		
//读操作
initial	
	@(posedge W_R)
		begin
			ADDR=addr_mem[0];
			$fclose(OUTFILE);
			$readmemh("eeprom.dat",ROM);
			$display("Begin READING-----READING-----READING-----READING");
			for(j=0;j<=test_number;j=j+1)
				begin
					ADDR=addr_mem[j];
					@(posedge ACK);
					if(DATA==ROM[ADDR])
						$display("DATA %0h ==ROM[%0h]----READ RIGHT",DATA,ADDR);
					else
						$display("DATA %0h != ROM[%0h]-----READ WRONG",DATA,ADDR);
				end
			end
		initial
			begin
				OUTFILE=$fopen("eeprom.dat");
				$readmemh("addr.dat",addr_mem);
				$readmemh("data.dat",data_mem);
			end
		endmodule
		
		
		

仿真出不来波形:

请问高手,哪里有问题?谢谢!

点赞 关注
个人签名为江山踏坏了乌骓马,为社稷拉断了宝雕弓。
 

回复
举报

3186

帖子

0

TA的资源

纯净的硅(高级)

沙发
 

仿真代码我改了一下:

`timescale 1ns/1ps
`define timeslice 200

module signal(RESET,CLK,RD,WR,ADDR,ACK,DATA);
output RESET;
output CLK;
output RD,WR;
output [10:0] ADDR;
input ACK;
inout [7:0] DATA;

reg RESET;
reg CLK;
reg RD,WR;
reg W_R;
reg [10:0] ADDR;
reg [7:0] data_to_eeprom;
reg [10:0] addr_mem[0:255];
reg [7:0] data_mem[0:255];
reg [7:0] ROM[1:2047];
reg [11:0]  Cnt;
integer i,j;
integer OUTFILE;

parameter test_number=5;
assign DATA=(W_R)? 8'bz:data_to_eeprom;
assign ACK=Cnt[11];

always #(`timeslice/2)
	CLK=~CLK;

always @(posedge CLK)
		Cnt<=Cnt+1;
//读写信号输入
initial
	begin
		RESET=1;
		i=0;j=0;
		W_R=0;
		CLK=0;
		Cnt=0;
		RD=0;
		WR=0;
		#1000;
		RESET=0;
		repeat(test_number)
		begin
			#(5*`timeslice);
			WR=1;
			#(`timeslice);
			WR=0;
			@(posedge ACK);
		end
		#(10* `timeslice);
		W_R=1;
		repeat(test_number)
			begin
				#(5*`timeslice);
				RD=1;
				#(`timeslice);
				RD=0;
				@(posedge ACK);
			end
		end
//写操作
initial
	begin
		$display("writing-----writing-----writing-----writing");
		#(2*`timeslice);
		
		for(i=0;i<=test_number;i=i+1)
			begin	
				ADDR=addr_mem[i];
				data_to_eeprom=data_mem[i];
				//$fdisplay(OUTFILE,"%0h     %0h",ADDR,data_to_eeprom);
				$fdisplay(OUTFILE,"%h",data_to_eeprom);
				@(posedge ACK);
				
			end
		end
		
//读操作
initial	
	@(posedge W_R)
		begin
			ADDR=addr_mem[0];
			$fclose(OUTFILE);
			
			$readmemh("./eeprom.dat",ROM);
			$display("Begin READING-----READING-----READING-----READING");
			for(j=0;j<=test_number;j=j+1)
				begin
					ADDR=addr_mem[j];
					
					
					@(posedge ACK);
					$display("ROM[ADDR]=%0h",ROM[ADDR]);
					if(data_mem[ADDR]==ROM[ADDR+1])
						$display("DATA %0h ==ROM[%0h]----READ RIGHT",data_mem[ADDR],ADDR);
					else
						$display("DATA %0h != ROM[%0h]-----READ WRONG",data_mem[ADDR],ADDR);
				end
			end
		initial
			begin
				OUTFILE=$fopen("./eeprom.dat");
				
				$readmemh("./addr.dat",addr_mem);
				
				$readmemh("./data.dat",data_mem);
				
			end
		endmodule
		
		
		

这样仿真结果就是对的

可是有个问题,代码里面是ROM[ADDR+1],按说不应该加1的。

可是不加1,

if(data_mem[ADDR]==ROM[ADDR])
						$display("DATA %0h ==ROM[%0h]----READ RIGHT",data_mem[ADDR],ADDR);
					else
						$display("DATA %0h != ROM[%0h]-----READ WRONG",data_mem[ADDR],ADDR);

仿真结果就不对:

请问高手,这是怎么回事呢?谢谢!

个人签名为江山踏坏了乌骓马,为社稷拉断了宝雕弓。
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表