CODE:
`timescale 1ns / 1ps
module ps2_interface(rst_n,clk50M,m1_ps2_clk,m1_ps2_data,m2_ps2_clk,m2_ps2_data,
ps2_tx_start,ps2_tx_data,ps2_rx_ready,ps2_rx_data,
ps2_busy,ps2_error);
input rst_n,clk50M;
input m1_ps2_clk,m1_ps2_data; //input of ps2_clk and ps2_data
output reg m2_ps2_clk,m2_ps2_data; //control the output of ps2_clk and ps2_data
input ps2_tx_start;
input[7:0] ps2_tx_data;
output reg ps2_rx_ready;
output[7:0] ps2_rx_data;
reg[7:0] ps2_rx_data;
output ps2_busy,ps2_error;
reg ps2_error;
//parameter define
parameter[3:0] DEBOUNCE_DELAY=4'hf; //delay for debouncing
parameter[3:0] TOTAL_BIT=4'd11; //total bits in a frame
//values are valid for a 50MHz clk,please adjust for other frequence if necessary
//20ns*5000=100us
parameter[15:0] DELAY_100US=16'd5000;
//20ns*1000=20us
parameter[15:0] DELAY_20US=16'd1000;
//delay 63clk
parameter[5:0] DELAY_63CLK=6'd63;
//state machine
parameter[4:0] idle=5'h0;
parameter[4:0] rx_clk_h=5'h1;
parameter[4:0] rx_falling_edge=5'h2; //ps2_clk falling edge
parameter[4:0] rx_clk_l=5'h3;
parameter[4:0] rx_error_parity=5'h4;
parameter[4:0] rx_ready=5'h5;
parameter[4:0] tx_force_clk_l=5'h6;
parameter[4:0] tx_bring_data_down=5'h7;
parameter[4:0] tx_release_clk=5'h8;
parameter[4:0] tx_first_wait_falling_edge=5'h9;
parameter[4:0] tx_falling_edge=5'ha;
parameter[4:0] tx_clk_l=5'hb;
parameter[4:0] tx_clk_h=5'hc;
parameter[4:0] tx_rising_edge_before_ack=5'hd;
parameter[4:0] tx_wait_ack=5'he;
parameter[4:0] tx_receive_ack=5'hf;
parameter[4:0] tx_error_no_ack=5'h10;
//intermediary signal, will be used in debouncing
reg[3:0] ps2_clk_cnt,ps2_data_cnt;
reg ps2_clk_inter,ps2_data_inter;
reg ps2_clk_syn,ps2_data_syn;
always@(negedge rst_n,posedge clk50M)
begin
if(!rst_n)
begin
ps2_clk_cnt<=4'h0;
ps2_clk_inter<=1'b0;
end
else
begin
if(ps2_clk_inter!=m1_ps2_clk)
begin
ps2_clk_cnt<=4'h0;
ps2_clk_inter<=m1_ps2_clk;
end
else
begin
if(ps2_clk_cnt==DEBOUNCE_DELAY)
begin
ps2_clk_syn<=ps2_clk_inter;
end
else
begin
ps2_clk_cnt<=ps2_clk_cnt+1'b1;
end
end
end
end
always@(negedge rst_n,posedge clk50M)
begin
if(!rst_n)
begin
ps2_data_cnt<=4'h0;
ps2_data_inter<=1'b0;
end
else
begin
if(ps2_data_inter!=m1_ps2_data)
begin
ps2_data_cnt<=4'h0;
ps2_data_inter<=m1_ps2_data;
end
else
begin
if(ps2_data_cnt==DEBOUNCE_DELAY)
begin
ps2_data_syn<=ps2_data_inter;
end
else
begin
ps2_data_cnt<=ps2_data_cnt+1'b1;
end
end
end
end
//state define
reg[4:0] cur_state,next_state;
//16 bits counter,used to wait 100us
reg[15:0] delay_100us_cnt;
//done signal for the counter
reg delay_100us_done;
wire delay_100us_enable;
assign delay_100us_enable=(next_state==tx_force_clk_l) ? 1'b1 : 1'b0;
always@(negedge rst_n,posedge clk50M)
begin
if(!rst_n)
begin
delay_100us_cnt<=16'h0;
delay_100us_done<=1'b0;
end
else
begin
if(delay_100us_enable==1'b1)
begin
if(delay_100us_cnt==DELAY_100US)
begin
delay_100us_cnt<=delay_100us_cnt;
delay_100us_done<=1'b1;
end
else
begin
delay_100us_cnt<=delay_100us_cnt+1'b1;
delay_100us_done<=1'b0;
end
end
else
begin
delay_100us_cnt<=16'h0;
delay_100us_done<=1'b0;
end
end
end
//16 bits counter,used to wait 20us
reg[15:0] delay_20us_cnt;
//done signal for the counter
reg delay_20us_done;
wire delay_20us_enable;
assign delay_20us_enable=(next_state==tx_bring_data_down) ? 1'b1 : 1'b0;
always@(negedge rst_n,posedge clk50M)
begin
if(!rst_n)
begin
delay_20us_cnt<=16'h0;
delay_20us_done<=1'b0;
end
else
begin
if(delay_20us_enable==1'b1)
begin
if(delay_20us_cnt==DELAY_20US)
begin
delay_20us_cnt<=delay_20us_cnt;
delay_20us_done<=1'b1;
end
else
begin
delay_20us_cnt<=delay_20us_cnt+1'b1;
delay_20us_done<=1'b0;
end
end
else
begin
delay_20us_cnt<=16'h0;
delay_20us_done<=1'b0;
end
end
end
//6 bits couner,useed to wait 63 clk periods
reg[5:0] delay_63clk_cnt;
//done signal for the counter
reg delay_63clk_done;
wire delay_63clk_enable;
assign delay_63clk_enable=(next_state==tx_first_wait_falling_edge) ? 1'b1 : 1'b0;
always@(negedge rst_n,posedge clk50M)
begin
if(!rst_n)
begin
delay_63clk_cnt<=6'h0;
delay_63clk_done<=1'b0;
end
else
begin
if(delay_63clk_enable==1'b1)
begin
if(delay_63clk_cnt==DELAY_63CLK)
begin
delay_63clk_cnt<=delay_63clk_cnt;
delay_63clk_done<=1'b1;
end
else
begin
delay_63clk_cnt<=delay_63clk_cnt+1'b1;
delay_63clk_done<=1'b0;
end
end
else
begin
delay_63clk_cnt<=6'h0;
delay_63clk_done<=1'b0;
end
end
end
//state transition,three paragraph
reg rst_bit_cnt;
reg[10:0] data_frame;
reg[3:0] bit_cnt; //how many bits have been received or transmitted
reg bit_parity; //parity bit
reg load_rx_data; //load data what have been received
reg load_tx_data; //if this signal is 1'b1,load data which will be transmitted
reg load_error_flag;
reg shift_rx_frame;
reg shift_tx_frame;
assign ps2_busy=(next_state==idle) ? 1'b0 : 1'b1;
always@(negedge rst_n,posedge clk50M)
begin
if(!rst_n)
begin
cur_state<=idle;
end
else
begin
cur_state<=next_state;
end
end
always@(cur_state,ps2_clk_syn,ps2_data_syn,bit_cnt,bit_parity,
delay_100us_done,delay_20us_done,delay_63clk_done,ps2_tx_start)
begin
rst_bit_cnt<=1'b0;
load_rx_data<=1'b0;
load_tx_data<=1'b0;
load_error_flag<=1'b0;
shift_rx_frame<=1'b0;
shift_tx_frame<=1'b0;
next_state<=idle;
case(cur_state)
idle:
begin
if(!ps2_clk_syn)
begin
shift_rx_frame<=1'b1;
next_state<=rx_falling_edge;
end
else if(ps2_tx_start==1'b1)
begin
next_state<=tx_force_clk_l;
load_tx_data<=1'b1;
end
else
begin
rst_bit_cnt<=1'b1;
next_state<=idle;
end
end
rx_clk_h:
begin
if(!ps2_clk_syn)
begin
shift_rx_frame<=1'b1;
next_state<=rx_falling_edge;
end
else
next_state<=rx_clk_h;
end
rx_falling_edge:
begin
next_state<=rx_clk_l;
end
rx_clk_l:
begin
if(bit_cnt==TOTAL_BIT)
begin
if(bit_parity)
begin
next_state<=rx_ready;
load_rx_data<=1'b1;
end
else
begin
load_error_flag<=1'b1;
next_state<=rx_error_parity;
end
end
else if(ps2_clk_syn)
begin
next_state<=rx_clk_h;
end
else
next_state<=rx_clk_l;
end
rx_ready:
begin
if((ps2_clk_syn==1'b1) && (ps2_data_syn==1'b1))
begin
rst_bit_cnt<=1'b1;
next_state<=idle;
end
else
begin
next_state<=rx_ready;
end
end
rx_error_parity:
begin
if((ps2_clk_syn==1'b1) && (ps2_data_syn==1'b1))
begin
rst_bit_cnt<=1'b1;
next_state<=idle;
end
else
begin
next_state<=rx_error_parity;
end
end
tx_force_clk_l:
begin
if(delay_100us_done==1'b1)
begin
next_state<=tx_bring_data_down;
end
else
begin
next_state<=tx_force_clk_l;
end
end
tx_bring_data_down:
begin
if(delay_20us_done==1'b1)
begin
next_state<=tx_release_clk;
end
else
begin
next_state<=tx_bring_data_down;
end
end
tx_release_clk:
begin
next_state<=tx_first_wait_falling_edge;
end
tx_first_wait_falling_edge:
begin
if(delay_63clk_done==1'b1)
begin
if(ps2_clk_syn==1'b0)
begin
shift_tx_frame<=1'b1;
next_state<=tx_falling_edge;
end
else
begin
next_state<=tx_first_wait_falling_edge;
end
end
else
begin
next_state<=tx_first_wait_falling_edge;
end
end
tx_falling_edge:
begin
next_state<=tx_clk_l;
end
tx_clk_l:
begin
if(bit_cnt==(TOTAL_BIT-1))
begin
next_state<=tx_rising_edge_before_ack;
end
else if(ps2_clk_syn==1'b1)
begin
next_state<=tx_clk_h;
end
else
begin
next_state<=tx_clk_l;
end
end
tx_clk_h:
begin
if(ps2_clk_syn==1'b0)
begin
shift_tx_frame<=1'b1;
next_state<=tx_falling_edge;
end
else
begin
next_state<=tx_clk_h;
end
end
tx_rising_edge_before_ack:
begin
if(ps2_clk_syn==1'b1)
begin
next_state<=tx_wait_ack;
end
else
begin
next_state<=tx_rising_edge_before_ack;
end
end
tx_wait_ack:
begin
if(ps2_clk_syn==1'b0)
begin
if(ps2_data_syn==1'b0)
begin
next_state<=tx_receive_ack;
end
else
begin
load_error_flag<=1'b1;
next_state<=tx_error_no_ack;
end
end
else
begin
next_state<=tx_wait_ack;
end
end
tx_receive_ack:
begin
if((ps2_clk_syn==1'b1) && (ps2_data_syn==1'b1))
begin
rst_bit_cnt<=1'b1;
next_state<=idle;
end
else
begin
next_state<=tx_receive_ack;
end
end
tx_error_no_ack:
begin
if((ps2_clk_syn==1'b1) && (ps2_data_syn==1'b1))
begin
rst_bit_cnt<=1'b1;
next_state<=idle;
end
else
begin
next_state<=tx_error_no_ack;
end
end
default:
begin
if((ps2_clk_syn==1'b1) && (ps2_data_syn==1'b1))
begin
rst_bit_cnt<=1'b1;
next_state<=idle;
end
else
begin
next_state<=next_state;
end
end
endcase
end
always@(negedge rst_n,posedge clk50M)
begin
if(!rst_n)
begin
m2_ps2_clk<=1'b1;
m2_ps2_data<=1'b1;
end
else
begin
case(next_state)
tx_force_clk_l:
begin
m2_ps2_clk<=1'b0;
m2_ps2_data<=1'b1;
end
tx_bring_data_down:
begin
m2_ps2_clk<=1'b0;
m2_ps2_data<=1'b0;
end
tx_release_clk:
begin
m2_ps2_clk<=1'b1;
m2_ps2_data<=1'b0;
end
tx_first_wait_falling_edge:
begin
m2_ps2_clk<=1'b1;
m2_ps2_data<=1'b0;
end
tx_falling_edge:
begin
m2_ps2_clk<=1'b1;
m2_ps2_data<=1'b1;
end
tx_clk_l:
begin
m2_ps2_clk<=1'b1;
m2_ps2_data<=data_frame[0];
end
tx_clk_h:
begin
m2_ps2_clk<=1'b1;
m2_ps2_data<=data_frame[0];
end
tx_rising_edge_before_ack:
begin
m2_ps2_clk<=1'b1;
m2_ps2_data<=data_frame[0];
end
default:
begin
m2_ps2_clk<=1'b1;
m2_ps2_data<=1'b1;
end
endcase
end
end
always@(negedge rst_n,posedge clk50M)
begin
if(!rst_n)
begin
bit_cnt<=4'h0;
data_frame<=11'h0;
bit_parity<=1'b0;
end
else
begin
if(rst_bit_cnt==1'b1)
begin
bit_cnt<=4'h0;
data_frame<=11'h0;
bit_parity<=1'b0;
end
if(shift_rx_frame==1'b1)
begin
data_frame<={ps2_data_syn,data_frame[10:1]};
bit_cnt<=bit_cnt+1'b1;
if(bit_cnt>4'd0 && bit_cnt<4'd10)
bit_parity<=bit_parity ^ ps2_data_syn;
end
if(load_tx_data==1'b1)
begin
data_frame[0]<=1'b0;
data_frame[8:1]<=ps2_tx_data;
data_frame[9]<=~^ps2_tx_data;
data_frame[10]<=1'b1;
end
if(shift_tx_frame==1'b1)
begin
data_frame[9:0]<=data_frame[10:1];
bit_cnt<=bit_cnt+1'b1;
end
end
end
always@(negedge rst_n,posedge clk50M)
begin
if(!rst_n)
begin
ps2_rx_data<=8'd0;
ps2_rx_ready<=1'b0;
end
else
begin
if(load_rx_data)
begin
ps2_rx_data<=data_frame[8:1];
ps2_rx_ready<=1'b1;
end
else
begin
ps2_rx_ready<=1'b0;
end
end
end
always@(negedge rst_n,posedge clk50M)
begin
if(!rst_n)
begin
ps2_error<=1'b0;
end
else
begin
if(load_error_flag==1'b1)
ps2_error<=1'b1;
else
ps2_error<=1'b0;
end
end
endmodule