From 4876225f60258a9bf467e606812c5763fec3739b Mon Sep 17 00:00:00 2001 From: liangkangnan Date: Wed, 23 Sep 2020 21:39:20 +0800 Subject: [PATCH] rtl: utils: add full handshake CDC source Signed-off-by: liangkangnan --- rtl/utils/full_handshake_rx.v | 128 +++++++++++++++++++++++++++++ rtl/utils/full_handshake_tx.v | 147 ++++++++++++++++++++++++++++++++++ sim/sim_default_nowave.bat | 2 +- sim/sim_new_nowave.bat | 2 +- 4 files changed, 277 insertions(+), 2 deletions(-) create mode 100644 rtl/utils/full_handshake_rx.v create mode 100644 rtl/utils/full_handshake_tx.v diff --git a/rtl/utils/full_handshake_rx.v b/rtl/utils/full_handshake_rx.v new file mode 100644 index 0000000..67f86ec --- /dev/null +++ b/rtl/utils/full_handshake_rx.v @@ -0,0 +1,128 @@ + /* + Copyright 2020 Blue Liang, liangkangnan@163.com + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +// 数据接收端模块 +// 跨时钟域传输,全(四次)握手协议 +// req = 1 +// ack_o = 1 +// req = 0 +// ack_o = 0 +module full_handshake_rx #( + parameter DW = 32)( // RX要接收数据的位宽 + + input wire clk, // RX端时钟信号 + input wire rst_n, // RX端复位信号 + + // from tx + input wire req_i, // TX端请求信号 + input wire[DW-1:0] req_data_i, // TX端输入数据 + + // to tx + output wire ack_o, // RX端应答TX端信号 + + // to rx + output wire[DW-1:0] recv_data_o,// RX端接收到的数据 + output wire recv_rdy_o // RX端是否接收到数据信号 + + ); + + localparam STATE_IDLE = 2'b01; + localparam STATE_DEASSERT = 2'b10; + + reg[1:0] state; + reg[1:0] state_next; + + always @ (posedge clk or negedge rst_n) begin + if (!rst_n) begin + state <= STATE_IDLE; + end else begin + state <= state_next; + end + end + + always @ (*) begin + case (state) + // 等待TX请求信号req=1 + STATE_IDLE: begin + if (req == 1'b1) begin + state_next = STATE_DEASSERT; + end else begin + state_next = STATE_IDLE; + end + end + // 等待req=0 + STATE_DEASSERT: begin + if (req) begin + state_next = STATE_DEASSERT; + end else begin + state_next = STATE_IDLE; + end + end + default: begin + state_next = STATE_IDLE; + end + endcase + end + + reg req_d; + reg req; + + // 将请求信号打两拍进行同步 + always @ (posedge clk or negedge rst_n) begin + if (!rst_n) begin + req_d <= 1'b0; + req <= 1'b0; + end else begin + req_d <= req_i; + req <= req_d; + end + end + + reg[DW-1:0] recv_data; + reg recv_rdy; + reg ack; + + always @ (posedge clk or negedge rst_n) begin + if (!rst_n) begin + ack <= 1'b0; + recv_rdy <= 1'b0; + recv_data <= {(DW){1'b0}}; + end else begin + case (state) + STATE_IDLE: begin + if (req == 1'b1) begin + ack <= 1'b1; + recv_rdy <= 1'b1; // 这个信号只会持续一个时钟 + recv_data <= req_data_i; // 这个信号只会持续一个时钟 + end + end + STATE_DEASSERT: begin + recv_rdy <= 1'b0; + recv_data <= {(DW){1'b0}}; + // req撤销后ack也撤销 + if (req == 1'b0) begin + ack <= 1'b0; + end + end + endcase + end + end + + assign ack_o = ack; + assign recv_rdy_o = recv_rdy; + assign recv_data_o = recv_data; + +endmodule diff --git a/rtl/utils/full_handshake_tx.v b/rtl/utils/full_handshake_tx.v new file mode 100644 index 0000000..b4a2c14 --- /dev/null +++ b/rtl/utils/full_handshake_tx.v @@ -0,0 +1,147 @@ + /* + Copyright 2020 Blue Liang, liangkangnan@163.com + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +// 数据发送端模块 +// 跨时钟域传输,全(四次)握手协议 +// req_o = 1 +// ack = 1 +// req_o = 0 +// ack = 0 +module full_handshake_tx #( + parameter DW = 32)( // TX要发送数据的位宽 + + input wire clk, // TX端时钟信号 + input wire rst_n, // TX端复位信号 + + // from rx + input wire ack_i, // RX端应答信号 + + // from tx + input wire req_i, // TX端请求信号,只需持续一个时钟 + input wire[DW-1:0] req_data_i, // TX端要发送的数据,只需持续一个时钟 + + // to tx + output wire idle_o, // TX端是否空闲信号,空闲才能发数据 + + // to rx + output wire req_o, // TX端请求信号 + output wire[DW-1:0] req_data_o // TX端要发送的数据 + + ); + + localparam STATE_IDLE = 3'b001; + localparam STATE_ASSERT = 3'b010; + localparam STATE_DEASSERT = 3'b100; + + reg[2:0] state; + reg[2:0] state_next; + + always @ (posedge clk or negedge rst_n) begin + if (!rst_n) begin + state <= STATE_IDLE; + end else begin + state <= state_next; + end + end + + always @ (*) begin + case (state) + STATE_IDLE: begin + if (req_i == 1'b1) begin + state_next = STATE_ASSERT; + end else begin + state_next = STATE_IDLE; + end + end + // 等待ack=1 + STATE_ASSERT: begin + if (!ack) begin + state_next = STATE_ASSERT; + end else begin + state_next = STATE_DEASSERT; + end + end + // 等待ack=0 + STATE_DEASSERT: begin + if (!ack) begin + state_next = STATE_IDLE; + end else begin + state_next = STATE_DEASSERT; + end + end + default: begin + state_next = STATE_IDLE; + end + endcase + end + + reg ack_d; + reg ack; + + // 将应答信号打两拍进行同步 + always @ (posedge clk or negedge rst_n) begin + if (!rst_n) begin + ack_d <= 1'b0; + ack <= 1'b0; + end else begin + ack_d <= ack_i; + ack <= ack_d; + end + end + + reg req; + reg[DW-1:0] req_data; + reg idle; + + always @ (posedge clk or negedge rst_n) begin + if (!rst_n) begin + idle <= 1'b1; + req <= 1'b0; + req_data <= {(DW){1'b0}}; + end else begin + case (state) + // 锁存TX请求数据,在收到ack之前一直保持有效 + STATE_IDLE: begin + if (req_i == 1'b1) begin + idle <= 1'b0; + req <= req_i; + req_data <= req_data_i; + end else begin + idle <= 1'b1; + req <= 1'b0; + end + end + // 收到RX的ack之后撤销TX请求 + STATE_ASSERT: begin + if (ack == 1'b1) begin + req <= 1'b0; + req_data <= {(DW){1'b0}}; + end + end + STATE_DEASSERT: begin + if (!ack) begin + idle <= 1'b1; + end + end + endcase + end + end + + assign idle_o = idle; + assign req_o = req; + assign req_data_o = req_data; + +endmodule diff --git a/sim/sim_default_nowave.bat b/sim/sim_default_nowave.bat index 78530f9..6407954 100644 --- a/sim/sim_default_nowave.bat +++ b/sim/sim_default_nowave.bat @@ -1,2 +1,2 @@ -iverilog -o out.vvp -I ..\rtl\core ..\tb\tinyriscv_soc_tb.v ..\rtl\core\defines.v ..\rtl\core\ex.v ..\rtl\core\id.v ..\rtl\core\tinyriscv.v ..\rtl\core\pc_reg.v ..\rtl\core\id_ex.v ..\rtl\core\ctrl.v ..\rtl\core\regs.v ..\rtl\perips\ram.v ..\rtl\perips\rom.v ..\rtl\perips\spi.v ..\rtl\core\if_id.v ..\rtl\core\div.v ..\rtl\core\rib.v ..\rtl\core\clint.v ..\rtl\core\csr_reg.v ..\rtl\debug\jtag_dm.v ..\rtl\debug\jtag_driver.v ..\rtl\debug\jtag_top.v ..\rtl\debug\uart_debug.v ..\rtl\perips\timer.v ..\rtl\perips\uart.v ..\rtl\perips\gpio.v ..\rtl\utils\gen_dff.v ..\rtl\utils\gen_buf.v ..\rtl\soc\tinyriscv_soc_top.v +iverilog -o out.vvp -I ..\rtl\core ..\tb\tinyriscv_soc_tb.v ..\rtl\core\defines.v ..\rtl\core\ex.v ..\rtl\core\id.v ..\rtl\core\tinyriscv.v ..\rtl\core\pc_reg.v ..\rtl\core\id_ex.v ..\rtl\core\ctrl.v ..\rtl\core\regs.v ..\rtl\perips\ram.v ..\rtl\perips\rom.v ..\rtl\perips\spi.v ..\rtl\core\if_id.v ..\rtl\core\div.v ..\rtl\core\rib.v ..\rtl\core\clint.v ..\rtl\core\csr_reg.v ..\rtl\debug\jtag_dm.v ..\rtl\debug\jtag_driver.v ..\rtl\debug\jtag_top.v ..\rtl\debug\uart_debug.v ..\rtl\perips\timer.v ..\rtl\perips\uart.v ..\rtl\perips\gpio.v ..\rtl\utils\gen_dff.v ..\rtl\utils\gen_buf.v ..\rtl\utils\full_handshake_rx.v ..\rtl\utils\full_handshake_tx.v ..\rtl\soc\tinyriscv_soc_top.v vvp out.vvp diff --git a/sim/sim_new_nowave.bat b/sim/sim_new_nowave.bat index 7b9cf2c..23c562b 100644 --- a/sim/sim_new_nowave.bat +++ b/sim/sim_new_nowave.bat @@ -1,3 +1,3 @@ ..\tools\BinToMem_CLI.exe %1 %2 -iverilog -o out.vvp -I ..\rtl\core ..\tb\tinyriscv_soc_tb.v ..\rtl\core\defines.v ..\rtl\core\ex.v ..\rtl\core\id.v ..\rtl\core\tinyriscv.v ..\rtl\core\pc_reg.v ..\rtl\core\id_ex.v ..\rtl\core\ctrl.v ..\rtl\core\regs.v ..\rtl\perips\ram.v ..\rtl\perips\rom.v ..\rtl\perips\spi.v ..\rtl\core\if_id.v ..\rtl\core\div.v ..\rtl\core\rib.v ..\rtl\core\clint.v ..\rtl\core\csr_reg.v ..\rtl\debug\jtag_dm.v ..\rtl\debug\jtag_driver.v ..\rtl\debug\jtag_top.v ..\rtl\debug\uart_debug.v ..\rtl\perips\timer.v ..\rtl\perips\uart.v ..\rtl\perips\gpio.v ..\rtl\utils\gen_dff.v ..\rtl\utils\gen_buf.v ..\rtl\soc\tinyriscv_soc_top.v +iverilog -o out.vvp -I ..\rtl\core ..\tb\tinyriscv_soc_tb.v ..\rtl\core\defines.v ..\rtl\core\ex.v ..\rtl\core\id.v ..\rtl\core\tinyriscv.v ..\rtl\core\pc_reg.v ..\rtl\core\id_ex.v ..\rtl\core\ctrl.v ..\rtl\core\regs.v ..\rtl\perips\ram.v ..\rtl\perips\rom.v ..\rtl\perips\spi.v ..\rtl\core\if_id.v ..\rtl\core\div.v ..\rtl\core\rib.v ..\rtl\core\clint.v ..\rtl\core\csr_reg.v ..\rtl\debug\jtag_dm.v ..\rtl\debug\jtag_driver.v ..\rtl\debug\jtag_top.v ..\rtl\debug\uart_debug.v ..\rtl\perips\timer.v ..\rtl\perips\uart.v ..\rtl\perips\gpio.v ..\rtl\utils\gen_dff.v ..\rtl\utils\gen_buf.v ..\rtl\utils\full_handshake_rx.v ..\rtl\utils\full_handshake_tx.v ..\rtl\soc\tinyriscv_soc_top.v vvp out.vvp