tinyriscv/rtl/utils/full_handshake_tx.v

148 lines
4.5 KiB
Verilog
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
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