`
timerri
  • 浏览: 47224 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

抄来的ps2 verilog

    博客分类:
  • c
F# 
阅读更多
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//公司:
//工程师: Lawson
//
//创建日期: 2004年10月10日
//设计名字:
//模块名字: PS2驱动器 Driver
//目标装置:
//工具版本: Xilinx ISE 6.3.02i
//描述:
//    按照PS2协议,驱动PS2设备并给出错误信号
//属性:
//
//修改:
//
//附加说明:
//
//
// 读时序状态图:
//
//	CLK:  
//______| ̄ ̄ ̄ ̄ ̄ ̄|____________________| ̄ ̄ ̄ ̄ ̄ ̄|____________________| ̄ ̄ ̄ ̄ ̄ ̄|_____…………………………______| ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
//
//	延时时钟信号
//	key_clk: 
//_______| ̄ ̄ ̄ ̄ ̄ ̄|____________________| ̄ ̄ ̄ ̄ ̄ ̄|____________________| ̄ ̄ ̄ ̄ ̄ ̄|_____…………………………______| ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
//	状态:	   Idle | Read_start | Read_start_complete|  Read_data | 
Read_data_complete |     Read_data  ←→  Read_data_complete    | 
Read_finish | Idle
//
//									   bit_0			bit_1 - bit_7,P_bit,stop_bit
//	DATA: 
// ̄ ̄ ̄ ̄ ̄ ̄ ̄|________________________________|〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓|〓〓〓〓………………………… ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
// 								       ↑		    ↑		 ↑
//	操作:							     数据读入	      counter_reg加一 数据读入
//
//
// 写时序状态图:
//		       延时100uS
//	CLK:  
//_____________________| ̄ ̄ ̄ ̄ ̄ ̄ ̄|___________________| ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄|______………………………………… ̄ ̄ ̄|_______________| ̄ ̄ ̄ ̄ ̄ ̄ ̄|_______________| ̄ ̄ ̄ ̄ ̄
//
//	状态: Idle | Inhibit_com ||  Write_start |     Write_data    |  
//Write_data_complete |  Write_data ←→ Write_data_complete | 	Write_stop  |  
//  Read_ACK   |    Write_finish   | Idle
//				  ↑
//         		  Inhibit_com_complete
//							   bit_0					bit_1 - bit_7,P_bit              stop_bit
//	DATA: 
// ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄|________________|〓〓〓〓〓〓〓〓〓〓|〓〓〓〓〓〓〓〓〓〓〓〓〓…………………………………〓〓〓〓| ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄|______________________| ̄ ̄ ̄
// 				 ↑		  ↑		       ↑		    					    ↑				   ↑
//	操作:		     释放时钟线		写数据		     写数据							释放数据线		         
//读ACK
//			     下拉数据线				 counter_reg加一
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

`timescale 1 ns / 1 ns

module  PS2_Driver (
		//bidirectional
		ps2_data,					//ps2设备数据端
		ps2_clk,					//ps2设备时钟端
		//input
		w_data,						//驱动器数据输入端
		ena,						//驱动器使能端
		rw,						//驱动器读写控制端(1:读,0:写)
		drv_clk,					//驱动器时钟端
		clr_n,						//驱动器复位端
		//output
		r_data,						//驱动器数据输出端
		ready,						//驱动器完成信号
		error						//驱动器错误代码输出端
		);

//+--------------------------- 参数设置-----------------------------------+

   parameter DATA_WIDTH = 8;					//输入/输出数据宽度
   parameter COUNT	= 4;					//状态码宽度
   parameter TIME 	= 8'd100;				//抑制通信时间

//+-----------------------------------------------------------------------+

	inout ps2_data /* synthesis xc_padtype = "IOBUF_LVTTL_F_24" */;
	inout ps2_clk  /* synthesis xc_padtype = "IOBUF_LVTTL_F_24" */;

	input [DATA_WIDTH-1:0] w_data;
	input rw;
	input ena;
	input clr_n;
	input drv_clk;

	output [DATA_WIDTH-1:0] r_data;
	output ready;
	output [1:0] error;

//+-------------------------------PS2状态代码------------------------------+

	parameter Idle			= 4'h0;			//初始化

	parameter Read_start 		= 4'h1;			//读开始位
	parameter Read_start_complete 	= 4'h2;			//完成读开始位
	parameter Read_data 		= 4'h3;			//读数据
	parameter Read_data_complete 	= 4'h4;			//完成读数据
	parameter Read_finish 		= 4'h5;			//完成读操作

	parameter Inhibit_com 		= 4'h6;			//抑制通讯
	parameter Inhibit_com_complete	= 4'h7;			//完成抑制通讯
	parameter Write_start 		= 4'h8;			//写开始位
	parameter Write_data 		= 4'h9;			//写数据
	parameter Write_data_complete 	= 4'hA;			//完成写数据
	parameter Write_stop 		= 4'hB;			//写停止位
	parameter Read_ACK 		= 4'hC;			//读应答位
	parameter Write_finish 		= 4'hD;			//完成写操作

//+-----------------------------KeyBoard 错误代码--------------------------+

	parameter PARITY_ERROR 		= 2'h1;			//效验错误
	parameter NO_ACK 		= 2'h2;			//无应答错误

//+------------------------------------------------------------------------+

	reg [COUNT-1:0] current_state;
	reg [COUNT-1:0] next_state;

	reg [DATA_WIDTH:0] r_data_reg;				// |  8  |  7-0  |
								//  效验位 数据位
								// |  P  |  DATA |

	reg [DATA_WIDTH:0] w_data_reg;				// |  8  |  7-0  |
								//  效验位 数据位
								// |  P  |  DATA |
	reg clk_w;
	reg data_w;
	reg key_reg;
	reg ready;
	reg [9:0] clk_sampling_reg;
	reg [2:0] data_sampling_reg;
	reg [1:0] error;
	reg [DATA_WIDTH-1:0] counter_reg;

	wire key_data;
	wire k_data;
	wire key_clk;
	wire k_clk;
	wire clr_n;
	wire write_parity;
	wire read_parity;

//------------------------------------------------------------------------------//
//										//
//				接口逻辑函数					//
//										//
//------------------------------------------------------------------------------//

	assign r_data = r_data_reg [7:0];

	assign write_parity = ^~w_data;
	assign read_parity = ^~r_data_reg [7:0];

	//对延时4个时钟,延时7个时钟,延时10个时钟后的ps2_clk信号进行取样
	assign key_clk = (clk_sampling_reg[3]&clk_sampling_reg[6])|
	(clk_sampling_reg[6]&clk_sampling_reg[9])|(clk_sampling_reg[3]&clk_sampling_reg[9]);

	assign key_data = (data_sampling_reg[0]&data_sampling_reg[1])|
	(data_sampling_reg[1]&data_sampling_reg[2])|(data_sampling_reg[2]&data_sampling_reg[0]);

	//ps2_data双向IO口
	assign ps2_data = data_w ? 1'bz : key_reg;		// 1:输入 0:输出
	assign k_data = ps2_data;

	//ps2_data双向IO口
	assign ps2_clk = clk_w ? 1'bz : 1'b0;
	assign k_clk = ps2_clk;

//------------------------------------------------------------------------------//
//										//
//				     采样输入					//
//										//
//------------------------------------------------------------------------------//

	always @ (posedge drv_clk or negedge clr_n)
		if (!clr_n) clk_sampling_reg <= 0;
		else clk_sampling_reg <= {clk_sampling_reg[8:0],k_clk};

	always @ (posedge drv_clk or negedge clr_n)
		if (!clr_n) data_sampling_reg <= 0;
		else data_sampling_reg <= {data_sampling_reg[1:0],k_data};

//------------------------------------------------------------------------------//
//										//
//				PS2驱动器状态机					//
//										//
//------------------------------------------------------------------------------//

	always @(posedge drv_clk or negedge clr_n)
		if (!clr_n) begin
		  current_state <= Idle;
      		end
      		else begin
      		  current_state <= next_state;
		end

	always @(current_state or ena or rw or k_clk or k_data or key_clk or 
key_data or counter_reg)
		case(current_state)
		  Idle: begin
			if(ena) begin
			  if(rw) begin
			    next_state = Read_start;
			  end
			  else next_state = Inhibit_com;
			end
			else begin
			  next_state = Idle;
			end
		  end

//---------------------------------PS2驱动器读状态-------------------------------//

      		  Read_start: begin
                  	if( key_clk == 0 && key_data == 0) begin
			  next_state = Read_start_complete;
			end
			else next_state = Read_start;
               	  end

      		  Read_start_complete: begin
                  	if( key_clk == 1) begin
			  next_state = Read_data;
			end
			else next_state = Read_start_complete;
               	  end

      		  Read_data: begin														//读数据和效验位
                  	if( key_clk == 0 ) begin
			  next_state = Read_data_complete;
			end
			else next_state = Read_data;
               	  end

      		  Read_data_complete: begin
                  	if( key_clk == 1 ) begin
			  if( counter_reg == 8'd9) begin
			    next_state = Read_finish;
			  end
			  else begin
			    next_state = Read_data;
			  end
			end
			else next_state = Read_data_complete;
               	  end

		  Read_finish: begin
                  	if( key_clk == 1 && key_data == 1) begin
			  next_state = Idle;
			end
			else next_state = Read_finish;
               	  end

//---------------------------------PS2驱动器写状态-------------------------------//

      		  Inhibit_com: begin
                  	if(counter_reg == TIME) begin			//抑制通讯约100μS
			  next_state = Inhibit_com_complete;
			end
			else next_state = Inhibit_com;
               	  end

		  Inhibit_com_complete: begin
			if( k_clk == 1 ) begin
			  next_state = Write_start;
			end
			else next_state = Inhibit_com_complete;
		  end

		  Write_start: begin
			if( k_clk == 0 ) begin
			  next_state = Write_data;
			end
			  else next_state = Write_start;
               	  end

      		  Write_data: begin
                  	if( k_clk == 1 ) begin
			  next_state = Write_data_complete;
			end
			else next_state = Write_data;
               	  end

      		  Write_data_complete: begin
                  	if( k_clk == 0 ) begin
			  if( counter_reg == 8'd9) begin
			    next_state = Write_stop;
			  end
			  else begin
			   next_state = Write_data;
			  end
			end
			else next_state = Write_data_complete;
               	  end

		  Write_stop: begin
                  	if( k_clk == 1 ) begin
			  next_state = Read_ACK;
			end
			else next_state = Write_stop;
               	  end

		  Read_ACK: begin														//应答检测
                  	if( k_clk == 0) begin
			  next_state = Write_finish;
			end
			  else next_state = Read_ACK;
               	  end

		  Write_finish: begin
                  	if( k_data == 1 && k_clk == 1 ) begin
			  next_state = Idle;
			end
			else begin
			  next_state = Write_finish;
			end
               	  end

      		  default: begin
                  	next_state = 'bx;
               	  end
		endcase

//------------------------------------------------------------------------------//
//										//
//				PS2驱动器控制输出				//
//										//
//------------------------------------------------------------------------------//

   	always @( posedge drv_clk or negedge clr_n)
	  	if (!clr_n) begin
	  	  r_data_reg <= 0;
	  	  w_data_reg <= 0;
	  	  clk_w <= 0;
	  	  data_w <= 1;
	  	  key_reg <= 0;
	  	  ready <= 0;
	  	  error <= 0;
	  	  counter_reg <= 0;
      		end
      		else begin
	  	  case (current_state)

	  	  Idle: begin
			$display("Idle start");
			ready <= 0;
			clk_w <= 0;														//抑制通讯
		  end

//------------------------------------------------------------------------------//
//										//
//				PS2驱动器读操作					//
//										//
//------------------------------------------------------------------------------//

      		  Read_start: begin
		    clk_w <= 1;
		    $display("Read start");
               	  end

      		  Read_start_complete: begin
		    $display("Complete read start");
               	  end

      		  Read_data: begin
		    if( key_clk == 0 ) begin
		      r_data_reg [counter_reg] <= key_data;	//读数据、效验位和结束位
		      $display("read r_data[%d] BIT is %b",counter_reg,ps2_data);
		    end
		    else $display("Wait negative edge");
               	  end

      		  Read_data_complete: begin
		    if( key_clk == 1 ) begin
		      counter_reg <= counter_reg + 1;
		    end
		    else $display("Wait advancing edge");
               	  end

		  Read_finish: begin
		    ready <= 1;
		    counter_reg <= 0;
		    $display("PS2K parity bit is %b",r_data_reg [8]);
		    if( read_parity == r_data_reg [8] ) 
begin		//数据效验位和接收效验位比较
			$display("PS2K parity bit is right");
			$display("Complete read r_data is %b",r_data);
		    end
		    else begin
			$display("PS2K parity bit is error");
			error <= PARITY_ERROR;
		    end
               	  end

//------------------------------------------------------------------------------//
//										//
//				  PS2驱动器写操作				//
//										//
//------------------------------------------------------------------------------//

      		  Inhibit_com: begin
		    counter_reg <= counter_reg + 1;			//延时计数
		    $display("Inhibit communication");
		  end

		  Inhibit_com_complete: begin
		    if( k_clk == 1 ) begin
			w_data_reg <= {write_parity,w_data};		//写数据寄存器
			counter_reg <= 0;
		    end
		    else begin
			$display("Complete Inhibit communication");
			data_w <= 0;												//设数据线为输出
			key_reg <= 0;												//置数据线为"0"
			clk_w <= 1;													//释放时钟线
		    end
		  end

		  Write_start: begin
			if( k_clk == 0 ) begin
			  $display("write w_data_reg[%d] BIT is 
%b",counter_reg,w_data_reg[counter_reg]);
			  key_reg <= w_data_reg [counter_reg];		//写0位数据
			end
			else begin
			  $display("Write start");
			end
               	  end

      		  Write_data: begin
			if( k_clk == 1 ) begin
			  counter_reg <= counter_reg + 1;		//加位数计数器
			  key_reg <= w_data_reg [counter_reg];		//写1-7位,校验位数据
			  $display("write w_data_reg[%d] BIT is 
%b",counter_reg,w_data_reg[counter_reg]);
			end
			else begin
			  $display("Write data");
			  $display("Wait advancing edge");
			end
		  end

      		  Write_data_complete: begin
			$display("Wait negative edge");
               	  end

		  Write_stop: begin
			data_w <= 1;													//释放数据线
			counter_reg <= 0;
                  	$display("Write stop");
		  end

		  Read_ACK: begin															//应答检测
			if( k_clk == 0 ) begin
			  if( k_data == 0) begin
			    $display("PS2K_DATA ACK ");
			  end
			  else begin
			   $display("PS2K_DATA NO ACK ");
			   error <= NO_ACK;
			  end
			end
			else begin
                  	  $display("Read ACK");
			end
		  end

		  Write_finish: begin
                  	$display("Complete write data");
			ready <= 1;
		  end
   		endcase
      	end
endmodule

//1、命名规则很统一,但是不太符合惯例,惯例也就是没有人说必须,但是大家都这样做^_^,
//   一般parameter/define等用大写,其他都是小写。182-202中always @ 格式不统一。
//2、不要使用tab键或者将tab键自动转换为空格,因为不同的编辑器可能会看到不同结果,
//   就像你现在肯定不能想象我这边看到的代码是什么样子,如果使用空格就没有这个问题。
//说明一点,虽然一般代码文字编写规范不是很重要,但是好的规范会给人professional的感觉,所以还是很重要的^_^
//

 

分享到:
评论

相关推荐

    ps2的verilog程序

    这样的资源对于学习Verilog和数字逻辑设计,特别是PS2接口实现的人来说非常宝贵。通常,这样的程序会包含详细的注释来解释代码的工作原理,帮助初学者理解并应用到实际设计中。 在标签“ps2程序”中,我们可以推断...

    Verilog模拟PS2协议

    在本文中,我们将深入探讨如何使用Verilog语言来模拟PS2协议,特别是在FPGA(Field-Programmable Gate Array)平台上实现。PS2协议相对简单,只需要四条线连接,其中VCC为+5V电源,时钟和数据线是双向的bidir接口,...

    PS2键盘控制verilog程序

    3. **状态机设计**:PS2键盘控制器通常需要一个状态机来管理与键盘交互的不同阶段,如等待数据、读取数据、解析数据等。状态机可以用case语句实现,每个状态对应一种操作。 4. **同步电路**:由于Verilog设计的硬件...

    ps2verilog.rar_FPGA PS2_ps2 verilog_ps2时序_verilog hdl ps2_verilo

    verilog hdl FPGA PS2时序控制接口源代码 很经典 很实用

    基于verilog的PS2键盘设计进阶

    本篇文章将深入探讨如何利用Verilog进行PS2(Personal System/2)键盘的设计,这是一种常见于早期个人电脑的接口技术,尽管现在已经被USB取代,但在FPGA(Field-Programmable Gate Array)学习和应用中,PS2键盘仍然...

    PS2协议的verilog实现

    1. **时钟和复用器**:由于PS2协议的数据和时钟线是分离的,我们需要在Verilog中创建两个独立的输入端口来处理这两个信号。时钟信号通常比数据传输速率快,所以需要用到边沿触发的D触发器来捕获数据。复用器用于在...

    1_070116141639.rar_ps2_ps2 verilog_verilog ps2

    verilog编程ps2接口设计,基于fpga的设计

    ps2 verilog代码

    **PS2键盘接口Verilog实现详解** 在数字电路设计领域,Verilog是一种广泛使用的硬件描述语言,用于描述和实现各种数字逻辑系统。本篇将详细探讨如何使用Verilog实现PS/2(Personal System/2)键盘接口。PS/2键盘...

    基于verilog下的ps2程序

    本项目关注的是在Verilog环境下实现PS2(Personal System/2)键盘接口的程序。PS2键盘是早期个人计算机上常见的接口,尽管现在已被USB接口取代,但在学习嵌入式系统和硬件设计时,理解PS2接口仍然是很有价值的。 ...

    SourceFile.rar_mouse verilog_ps2_ps2 mouse verilog_ps2 mouse wit

    在实际的设计过程中,开发者首先需要了解PS2接口规范,然后用Verilog HDL编写代码,最后通过仿真验证和FPGA硬件实现来测试设计是否符合预期。这个实验不仅帮助学生掌握Verilog编程,还能加深对数字系统设计和接口...

    verilog PS2 源程序

    在这个特定的“verilog PS2 源程序”项目中,开发者使用Verilog编写了代码,以便在DE2开发板上实现与PS/2(Personal System/2)键盘的接口。 PS/2键盘接口是IBM个人电脑上的一种标准接口,用于连接键盘和鼠标。它...

    verilog PS2键盘解码程序

    从提供的部分代码来看,有两个主要的Verilog模块:`ps2_key`作为顶层模块,负责协调整个系统的运作;`ps2scan`是底层模块之一,专门处理PS/2键盘的扫描和解码。`ps2_key`模块接收到50MHz的时钟信号(`clk`),复位...

    PS2键盘Verilog源代码

    这个Verilog代码将帮助你理解如何用硬件描述语言来处理PS/2协议,包括时序控制、数据解析和错误检测。 PS/2键盘协议基于异步串行通信,通常使用4线连接,其中两根线用于数据传输(数据线),两根线用于时钟信号...

    ps2键盘的verilog源码

    总的来说,通过这个Verilog实现的PS/2键盘控制器,我们可以学习到串行通信协议的实现,状态机设计,错误检测,以及FPGA设计的基本原则,这些都是数字逻辑设计的基础知识,对于电子工程师来说是非常有价值的。

    ps2键盘驱动 fpga

    在这个项目中,我们关注的是如何使用FPGA来实现PS2(Personal System/2)键盘的驱动。PS2键盘是早期个人电脑上常见的输入设备接口,尽管现在已被USB接口取代,但在学习和实验环境中仍然有其价值。 首先,我们需要...

    ps2键盘verilog代码

    ps2键盘verilog代码 可以使用已经测试过 比较完善的一个代码

    FPGA控制PS2键盘verilog设计Quartus9.1工程源码+设计说明文件.zip

    FPGA控制PS2键盘verilog设计Quartus9.1工程源码+设计说明文件,可以做为你的学习设计参考。 1. 这个实例通过开发板上面的PS/2接口接收键盘输入的数据,在LCD上面显示出来; 2. 工程在project文件夹里面,打开工程; 3...

    PS2_DEMO.rar_DEMO_FPGA PS2 键盘_Verilog ps2键盘

    在这个场景下,开发人员使用Verilog来设计一个模块,该模块能够接收并处理来自PS/2键盘的输入信号,然后可能将这些信号转换为可读的数据格式供其他系统使用。 标签“demo fpga__ps2__键盘 verilog_ps2键盘”是对...

    S9_PS2_LCD.rar_12864_12864 verilog_ps2_ps2_lcd_12864_verilog 128

    标题中的"S9_PS2_LCD.rar_12864_12864 verilog_ps2_ps2_lcd_12864_verilog 128"提到了几个关键概念,包括“S9_PS2_LCD”、“12864”、“verilog”、“ps2”和“ps2_lcd_12864”。这些关键词暗示了这是一个关于使用...

Global site tag (gtag.js) - Google Analytics