feat: add ps2 module to the prj

This commit is contained in:
maksyuki committed 2025-02-02 16:09:28 +08:00
1 parent 70826b98b9
commit cc6ea25eec
3 files changed
+421

No files matched your search

+168
View File
@@ -0,0 +1,168 @@
// Copyright (c) 2023-2024 Miao Yuchi <miaoyuchi@ict.ac.cn>
// common is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
// http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
`ifndef INC_EDGE_DET_SV
`define INC_EDGE_DET_SV
// need to use high freq clk to oversample the dat edge with sync
module edge_det #(
parameter STAGE = 2,
parameter DATA_WIDTH = 1
) (
input clk_i,
input rst_n_i,
input [DATA_WIDTH-1:0] dat_i,
output [DATA_WIDTH-1:0] dat_o,
output [DATA_WIDTH-1:0] re_o,
output [DATA_WIDTH-1:0] fe_o
);
wire [DATA_WIDTH-1:0] s_dat_d, s_dat_q;
assign dat_o = s_dat_q;
cdc_sync #(STAGE, DATA_WIDTH) u_cdc_sync (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (dat_i),
.dat_o (s_dat_d)
);
dffr #(DATA_WIDTH) u_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_dat_d),
.dat_o (s_dat_q)
);
assign re_o = (~s_dat_q) & s_dat_d;
assign fe_o = s_dat_q & (~s_dat_d);
endmodule
module edge_det_re #(
parameter STAGE = 2,
parameter DATA_WIDTH = 1
) (
input clk_i,
input rst_n_i,
input [DATA_WIDTH-1:0] dat_i,
output [DATA_WIDTH-1:0] re_o
);
wire [DATA_WIDTH-1:0] s_dat_d, s_dat_q;
cdc_sync #(STAGE, DATA_WIDTH) u_cdc_sync (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (dat_i),
.dat_o (s_dat_d)
);
dffr #(DATA_WIDTH) u_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_dat_d),
.dat_o (s_dat_q)
);
assign re_o = (~s_dat_q) & s_dat_d;
endmodule
module edge_det_sync #(
parameter DATA_WIDTH = 1
) (
input clk_i,
input rst_n_i,
input [DATA_WIDTH-1:0] dat_i,
output [DATA_WIDTH-1:0] re_o,
output [DATA_WIDTH-1:0] fe_o
);
wire [DATA_WIDTH-1:0] s_dat_d, s_dat_q;
assign s_dat_d = dat_i;
dffr #(DATA_WIDTH) u_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_dat_d),
.dat_o (s_dat_q)
);
assign re_o = (~s_dat_q) & s_dat_d;
assign fe_o = s_dat_q & (~s_dat_d);
endmodule
module edge_det_sync_re #(
parameter DATA_WIDTH = 1
) (
input clk_i,
input rst_n_i,
input [DATA_WIDTH-1:0] dat_i,
output [DATA_WIDTH-1:0] re_o
);
wire [DATA_WIDTH-1:0] s_dat_d, s_dat_q;
assign s_dat_d = dat_i;
dffr #(DATA_WIDTH) u_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_dat_d),
.dat_o (s_dat_q)
);
assign re_o = (~s_dat_q) & s_dat_d;
endmodule
module edge_det_fe #(
parameter STAGE = 2,
parameter DATA_WIDTH = 1
) (
input clk_i,
input rst_n_i,
input [DATA_WIDTH-1:0] dat_i,
output [DATA_WIDTH-1:0] fe_o
);
wire [DATA_WIDTH-1:0] s_dat_d, s_dat_q;
cdc_sync #(STAGE, DATA_WIDTH) u_cdc_sync (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (dat_i),
.dat_o (s_dat_d)
);
dffr #(DATA_WIDTH) u_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_dat_d),
.dat_o (s_dat_q)
);
assign fe_o = s_dat_q & (~s_dat_d);
endmodule
module edge_det_sync_fe #(
parameter DATA_WIDTH = 1
) (
input clk_i,
input rst_n_i,
input [DATA_WIDTH-1:0] dat_i,
output [DATA_WIDTH-1:0] fe_o
);
wire [DATA_WIDTH-1:0] s_dat_d, s_dat_q;
assign s_dat_d = dat_i;
dffr #(DATA_WIDTH) u_dffr (
.clk_i (clk_i),
.rst_n_i(rst_n_i),
.dat_i (s_dat_d),
.dat_o (s_dat_q)
);
assign fe_o = s_dat_q & (~s_dat_d);
endmodule
`endif
+211
View File
@@ -0,0 +1,211 @@
// Copyright (c) 2023-2024 Miao Yuchi <miaoyuchi@ict.ac.cn>
// ps2 is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
// http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
`ifndef INC_PS2_DEF_SV
`define INC_PS2_DEF_SV
/* register mapping
* PS2_CTRL:
* BITS: | 31:2 | 1 | 0 |
* FIELDS: | RES | EN | ITN |
* PERMS: | NONE | RW | RW |
* ---------------------------
* PS2_DATA:
* BITS: | 31:8 | 7:0 |
* FIELDS: | RES | DATA |
* PERMS: | NONE | RO |
* ---------------------------
* PS2_STAT:
* BITS: | 31:1 | 0 |
* FIELDS: | RES | ITF |
* PERMS: | NONE | RO |
* ---------------------------
*/
// verilog_format: off
`define PS2_CTRL 4'b0000 // BASEADDR + 0x00
`define PS2_DATA 4'b0001 // BASEADDR + 0x04
`define PS2_STAT 4'b0010 // BASEADDR + 0x08
`define PS2_CTRL_ADDR {26'b0, `PS2_CTRL, 2'b00}
`define PS2_DATA_ADDR {26'b0, `PS2_DATA, 2'b00}
`define PS2_STAT_ADDR {26'b0, `PS2_STAT, 2'b00}
`define PS2_CTRL_WIDTH 2
`define PS2_DATA_WIDTH 8
`define PS2_STAT_WIDTH 1
// verilog_format: on
`endif
// Copyright (c) 2023-2024 Miao Yuchi <miaoyuchi@ict.ac.cn>
// ps2 is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
// http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
// only support keyboard now
module apb4_ps2 (
input pclk,
input presetn,
input [31:0] paddr,
input [ 2:0] pprot,
input psel,
input penable,
input pwrite,
input [31:0] pwdata,
input [ 3:0] pstrb,
output pready,
output reg [31:0] prdata,
output pslverr,
input ps2_clk_i,
input ps2_dat_i,
output irq_o
);
wire [3:0] s_apb4_addr;
wire s_apb4_wr_hdshk, s_apb4_rd_hdshk;
wire [`PS2_CTRL_WIDTH-1:0] s_ps2_ctrl_d, s_ps2_ctrl_q;
wire s_ps2_ctrl_en;
reg [`PS2_STAT_WIDTH-1:0] s_ps2_stat_d;
wire [`PS2_STAT_WIDTH-1:0] s_ps2_stat_q;
wire s_ps2_stat_en;
reg [ 3:0] s_cnt_d;
wire [ 3:0] s_cnt_q;
reg [ 9:0] s_dat_d;
wire [ 9:0] s_dat_q;
wire s_fifo_empty;
reg s_fifo_push_valid;
wire [ 7:0] s_fifo_rd_dat;
wire s_bit_itn, s_bit_en, s_bit_itf, s_clk_fe, s_irq_trg;
assign s_apb4_addr = paddr[5:2];
assign s_apb4_wr_hdshk = psel && penable && pwrite;
assign s_apb4_rd_hdshk = psel && penable && (~pwrite);
assign pready = 1'b1;
assign pslverr = 1'b0;
assign s_bit_itn = s_ps2_ctrl_q[0];
assign s_bit_en = s_ps2_ctrl_q[1];
assign s_bit_itf = s_ps2_stat_q[0];
assign irq_o = s_bit_itf;
assign s_ps2_ctrl_en = s_apb4_wr_hdshk && s_apb4_addr == `PS2_CTRL;
assign s_ps2_ctrl_d = pwdata[`PS2_CTRL_WIDTH-1:0];
dffer #(`PS2_CTRL_WIDTH) u_ps2_ctrl_dffer (
pclk,
presetn,
s_ps2_ctrl_en,
s_ps2_ctrl_d,
s_ps2_ctrl_q
);
edge_det_fe #(2, 1) u_ps2_clk_edge_det_fe (
pclk,
presetn,
ps2_clk_i,
s_clk_fe
);
always @(*) begin
s_cnt_d = s_cnt_q;
if (s_clk_fe) begin
if (s_cnt_q == 4'd10) begin
s_cnt_d = 'h0;
end else begin
s_cnt_d = s_cnt_q + 1'b1;
end
end
end
dffer #(4) u_cnt_dffer (
pclk,
presetn,
s_clk_fe,
s_cnt_d,
s_cnt_q
);
always @(*) begin
s_dat_d = s_dat_q;
if (s_clk_fe) begin
if (s_cnt_q < 4'd10) begin
s_dat_d[s_cnt_q] = ps2_dat_i;
end
end
end
dffer #(10) u_dat_dffer (
pclk,
presetn,
s_clk_fe,
s_dat_d,
s_dat_q
);
always @(*) begin
s_fifo_push_valid = 1'b0;
if (s_bit_en && s_clk_fe) begin
if (s_cnt_q == 4'd10) begin
if (s_dat_q[0] == 1'b0 && ps2_dat_i && (^s_dat_q[9:1])) begin
s_fifo_push_valid = 1'b1;
end
end
end
end
fifo #(
.DATA_WIDTH (8),
.BUFFER_DEPTH(16)
) u_ps2_fifo (
.clk_i (pclk),
.rst_n_i(presetn),
.flush_i(1'b0),
.full_o (),
.empty_o(s_fifo_empty),
.cnt_o (),
.dat_i (s_dat_q[8:1]),
.push_i (s_fifo_push_valid),
.dat_o (s_fifo_rd_dat),
.pop_i (s_apb4_rd_hdshk && s_apb4_addr == `PS2_DATA)
);
assign s_irq_trg = ~s_fifo_empty;
assign s_ps2_stat_en = (s_bit_itf && s_apb4_rd_hdshk && s_apb4_addr == `PS2_STAT) || (~s_bit_itf && s_bit_en && s_bit_itn && s_irq_trg);
always @(*) begin
s_ps2_stat_d = s_ps2_stat_q;
if (s_bit_itf && s_apb4_rd_hdshk && s_apb4_addr == `PS2_STAT) begin
s_ps2_stat_d = 'h0;
end else if (~s_bit_itf && s_bit_en && s_bit_itn && s_irq_trg) begin
s_ps2_stat_d = 'h1;
end
end
dffer #(`PS2_STAT_WIDTH) u_ps2_stat_dffer (
pclk,
presetn,
s_ps2_stat_en,
s_ps2_stat_d,
s_ps2_stat_q
);
// verilog_format: off
always @(*) begin
prdata = 'h0;
if (s_apb4_rd_hdshk) begin
case (s_apb4_addr)
`PS2_CTRL: prdata[`PS2_CTRL_WIDTH-1:0] = s_ps2_ctrl_q;
`PS2_DATA: prdata[`PS2_DATA_WIDTH-1:0] = (s_fifo_empty || ~s_bit_en) ? 'h0 : s_fifo_rd_dat;
`PS2_STAT: prdata[`PS2_STAT_WIDTH-1:0] = s_ps2_stat_q;
default: prdata = 'h0;
endcase
end
end
// verilog_format: on
endmodule
+42
View File
@@ -0,0 +1,42 @@
// Copyright (c) 2023-2024 Miao Yuchi <miaoyuchi@ict.ac.cn>
// ps2 is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
// http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
module kdb_model (
output reg ps2_clk_o,
output reg ps2_dat_o
);
parameter [31:0] clk_period = 60;
initial begin
ps2_clk_o = 1'b1;
ps2_dat_o = 1'b1;
end
task send_code;
input [7:0] code;
integer i;
reg [10:0] send_buf;
begin
send_buf[0] = 1'b0; // start bit
send_buf[8:1] = code; // code
send_buf[9] = ~(^code); // odd parity bit
send_buf[10] = 1'b1; // stop bit
i = 0;
while (i < 11) begin
// set kbd_data
ps2_dat_o = send_buf[i];
#(clk_period / 2) ps2_clk_o = 1'b0;
#(clk_period / 2) ps2_clk_o = 1'b1;
i = i + 1;
end
ps2_clk_o = 1'b1;
ps2_dat_o = 1'b1;
end
endtask
endmodule