nn-usb-fpga/PS2_INTERFACE/logic/ps2_tx.v

166 lines
4.1 KiB
Verilog
Executable File

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 11:52:20 10/07/2010
// Design Name:
// Module Name: ps2_tx
// Project Name: keyboard
// Target Devices:
// Tool versions:
// Description: transmisor de teclado ps2
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module ps2_tx
(
input wire clk, reset,
input wire we_ps2,
input wire [7:0] din,
inout wire ps2_data, ps2_clk,
output reg tx_idle, tx_done
);
// symbolic state declaration
localparam [2:0]
idle = 3'b000,
rts = 3'b001,
start = 3'b010,
data = 3'b011,
stop = 3'b100;
// signal declaration
reg [2:0] state_reg, state_next;
reg [7:0] filter_reg;
wire [7:0] filter_next;
reg f_ps2c_reg;
wire f_ps2c_next;
reg [3:0] n_reg, n_next;
reg [8:0] b_reg, b_next;
reg [12:0] c_reg, c_next;
wire par, fall_edge;
reg ps2c_out, ps2d_out;
reg tri_c, tri_d;
//=================================================
// falling-edge generation for ps2_clk
//=================================================
always @(posedge clk, posedge reset)
if (reset)
begin
filter_reg <= 0;
f_ps2c_reg <= 0;
end
else
begin
filter_reg <= filter_next;
f_ps2c_reg <= f_ps2c_next;
end
assign filter_next = {ps2_clk, filter_reg[7:1]};
assign f_ps2c_next = (filter_reg==8'b11111111) ? 1'b1 :
(filter_reg==8'b00000000) ? 1'b0 :
f_ps2c_reg;
assign fall_edge = f_ps2c_reg & ~f_ps2c_next;
//=================================================
// FSM
//=================================================
// state & data registers
always @(posedge clk, posedge reset)
if (reset)
begin
state_reg <= idle;
c_reg <= 0;
n_reg <= 0;
b_reg <= 0;
end
else
begin
state_reg <= state_next;
c_reg <= c_next;
n_reg <= n_next;
b_reg <= b_next;
end
// odd parity bit
assign par = ~(^din);
// FSM next-state logic
always @*
begin
state_next = state_reg;
c_next = c_reg;
n_next = n_reg;
b_next = b_reg;
tx_done = 1'b0;
ps2c_out = 1'bz;
ps2d_out = 1'bz;
tri_c = 1'b0;
tri_d = 1'b0;
tx_idle = 1'b0;
case (state_reg)
idle:
begin
tx_idle = 1'b1;
if (we_ps2)
begin
b_next = {par, din};
c_next = 13'h1fff; // 2^13-1
state_next = rts;
end
end
rts: // request to send
begin
ps2c_out = 1'b0;
tri_c = 1'b1;
c_next = c_reg - 1;
if (c_reg==0)
state_next = start;
end
start: // assert start bit
begin
ps2d_out = 1'b0;
tri_d = 1'b1;
if (fall_edge)
begin
n_next = 4'h8;
state_next = data;
end
end
data: // 8 data + 1 parity
begin
ps2d_out = (b_reg[0])? 1'bz : 1'b0;
tri_d = 1'b1;
if (fall_edge)
begin
b_next = {1'b0, b_reg[8:1]};
if (n_reg == 0)
state_next = stop;
else
n_next = n_reg - 1;
end
end
stop: // assume floating high for ps2_data
if (fall_edge)
begin
state_next = idle;
tx_done = 1'b1;
end
endcase
end
// tri-state buffers
assign ps2_clk = (tri_c) ? ps2c_out : 1'bz;
assign ps2_data = (tri_d) ? ps2d_out : 1'bz;
endmodule