练习九-利用状态机实现比较复杂的接口设计

练习九-利用状态机实现比较复杂的接口设计

1,任务目的:

(1)学习运用状态机控制的逻辑开关,并设计出一个比较复杂的接口逻辑;

(2)在复杂设计中使用任务(task)结构,以提高程序的可读性;

(3)加深对可综合风格模块的认识。
下面例子是一个并行数据转换为串行位流的变换器,利用双向总线输出。该案例来自于EPROM读写器,电路工作的步骤是:
(1)把并行地址存入寄存器; (2)把并行数据存入寄存器; (3)连接串行单总线; (4)地址的串行输出; (5)数据的串行输出; (6)挂起串行单总线; (7)给信号源应答; (8)让信号源给出下一个操作对象; (9)结束写操作。

2,RTL代码

cpp 复制代码
`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2023/11/22 10:52:02
// Design Name: 
// Module Name: writing
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//

module writing(
rst_n, clk, address, data, sda, ack);

input			rst_n, clk;
input	[7:0]	data, address;

inout			sda;			// 	串行数据的输出或者输入接口
output			ack;			//	模块给出的应答信号
reg				link_write;		// link_write决定何时输出

reg		[3:0]	state;			//	主状态机的状态字
reg		[4:0]	sh8out_state;	// 从状态机的状态字
reg		[7:0]	sh8out_buf;		// 输入数据缓冲
reg				finish_F;		//	用以判断是否处理完一个操作对象
reg				ack;

parameter	idle 		= 0;
parameter	addr_write	= 1;
parameter	data_write	= 2;
parameter	stop_ack	= 3;

parameter	bit0		= 1;
parameter	bit1		= 2;
parameter	bit2		= 3;
parameter	bit3		= 4;
parameter	bit4		= 5;
parameter	bit5		= 6;
parameter	bit6		= 7;
parameter	bit7		= 8;

assign		sda = link_write ? sh8out_buf[7] : 1'bz;

always@(posedge clk)	begin
	if(!rst_n)	begin	// 复位
		link_write		<= 0;		// 挂起串行总线
		sh8out_state	<= idle;
		sh8out_buf		<= 0;
		state			<= idle;
		finish_F		<= 0;		// 结束标志清零
		ack				<= 0;
		end
		
	else	
		case(state)
			idle:	begin
				link_write		<= 0;	// 断开串行单总线
				sh8out_state	<= idle;
				sh8out_buf		<= address;	// 并行地址存入寄存器
				state			<= addr_write;	// 进入下一个状态
				finish_F		<= 0;				
				ack				<= 0;
				end
			
			addr_write:		// 地址的输入
				if(finish_F == 0)	
					shift8_out	;	// 地址的串行输出
					//	?	任务
				else	begin
				
					sh8out_state	<= idle;
					sh8out_buf		<= data;	// 并行数据存入寄存器
					state			<= data_write;
					finish_F		<= 0;
					
					end
			
			data_write:		// 数据的写入
				if(finish_F	== 0)
					shift8_out	;	//	数据的串行输出
					// 任务
				else	begin
					link_write	<= 0;
					
					state		<= stop_ack;
					finish_F	<= 0;
					ack			<= 1;	// 向信号源发出应答
					end
				
			stop_ack:	begin // 向信号源发出应答结果
				ack		<= 0;
				state	<= idle;
				end
		endcase
end

task	shift8_out;	// 地址和数据的串行输出
begin
  case(sh8out_state)
	idle:	begin
		link_write		<= 1;	// 连接串行单总线,立即输出地址或数据的最高位(MSB)
		sh8out_state	<= bit7;
		end
	bit7:	begin
		link_write		<= 1;	// 连接串行单总线
		sh8out_state	<= bit6;
		sh8out_buf		<= sh8out_buf << 1;	// 输出地址或数据的次高位(bit6)
		end
	bit6:	begin
		sh8out_state	<= bit5;
		sh8out_buf		<= sh8out_buf << 1;
		end
	bit5:	begin
		sh8out_state	<= bit4;
		sh8out_buf		<= sh8out_buf << 1;
		end
	bit4:	begin
		sh8out_state	<= bit3;
		sh8out_buf		<= sh8out_buf << 1;
		end
	bit3:	begin
		sh8out_state	<= bit2;
		sh8out_buf		<= sh8out_buf << 1;
		end
	bit2:	begin
		sh8out_state	<= bit1;
		sh8out_buf		<= sh8out_buf << 1;
		end
	bit1:	begin
		sh8out_state	<= bit0;
		sh8out_buf		<= sh8out_buf << 1;	// 输出地址或数据的最低位(LSB)
		end
	bit0:	begin
		link_write		<= 0;	// 挂起串行单总线
		finish_F		<= 1;	// 建立结束标志
		end
  endcase
end
endtask

endmodule

3,RTL原理框图

4,测试代码

cpp 复制代码
`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2023/11/22 10:53:46
// Design Name: 
// Module Name: writing_top
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//

// 测试代码
`define	clk_cycle	50
module	writing_top;
reg		rst_n,	clk;
reg		[7:0]	data, address;
wire	ack,	sda;

always #`clk_cycle	clk = ~clk;

initial	begin
	clk 	= 0;
	rst_n	= 1;
	data	= 0;
	address	= 0;
	#(2   * `clk_cycle)		rst_n = 0;
	#(2   * `clk_cycle)		rst_n = 1;
	#(100 * `clk_cycle)		$stop;
end

always@(posedge ack)	begin
	// 接收到应答信号后,给出下一个处理对象
	data 	= data + 1;
	address	= address + 1;
end

writing u_writing(
.rst_n			(rst_n		),
.clk			(clk		),
.data			(data		),
.address		(address	),
.ack			(ack		),
.sda			(sda		)
);

endmodule

5,波形输出



相关推荐
Terasic友晶科技14 小时前
答疑解惑|Agilex 3 FPGA QSPI时钟设置注意事项
fpga开发·de23-lite·terasic·qspi flash
国科安芯1 天前
卫星星务计算机数据管理中SEU容错机制的技术实现研究——以AS32S601存储器ECC架构为例
网络·单片机·算法·fpga开发·架构·云计算·risc-v
国科安芯1 天前
卫星电推进系统阀门驱动控制中的宽温域高可靠MCU应用研究——基于AS32S601电气特性与辐照试验数据的工程分析
单片机·嵌入式硬件·fpga开发·云计算·信息与通信·卫星·抗辐射芯片
郝旭帅电子设计团队2 天前
图像处理是什么
图像处理·fpga开发·郝旭帅电子设计团队·郝旭帅
ARM|X86+FPGA工业主板厂家2 天前
基于ARM+FPGA平台在精密测控领域的应用:8路同步IEPE振动采集系统
arm开发·fpga开发
weixin_452600692 天前
D2632大电流低差压可调线性稳压器介绍,D2632可替换MIC29302
fpga开发·机器人·无人机·电动工具·车载摄像头
ARM|X86+FPGA工业主板厂家2 天前
基于ARM+FPGA平台在精密测控领域的应用:ZYNQ千兆以太网高速数据记录仪
arm开发·fpga开发
cmc10282 天前
275.需要双边沿触发时,直接对时钟取反会不会出问题
fpga开发
ARM|X86+FPGA工业主板厂家2 天前
基于ARM+FPGA平台在精密测控领域的应用:ZYNQ FPGA图像预处理加速系统
arm开发·fpga开发
LCMICRO-133108477463 天前
国产长芯微LPS7118完全pin-pin替代ADP7118,是一款采用 CMOS 技术设计的低噪声、高 PSRR、快速瞬态响应、低压差线性稳压器
arm开发·单片机·嵌入式硬件·fpga开发·硬件工程·线性稳压器·adp7118