blob: 5d313865c9300958530cc2af0a8e1f977153f46a [file] [log] [blame]
// SPDX-FileCopyrightText:
// 2021 Andrew Attwood
//
// 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.
//
// SPDX-License-Identifier: Apache-2.0
module uart_to_mem (
clk_i,
rst_i,
rx_i,
tx_o,
data_req_o,
data_addr_o,
data_we_o,
data_be_o,
data_wdata_o,
data_rdata_i,
data_rvalid_i,
data_gnt_i,
uart_error
);
parameter ADDR_WIDTH = 12;
input clk_i;
input rst_i;
input rx_i;
output tx_o;
output reg data_req_o;
output [ADDR_WIDTH - 1:0] data_addr_o;
output reg data_we_o;
output [3:0] data_be_o;
output [31:0] data_wdata_o;
input reg [31:0] data_rdata_i;
input data_rvalid_i;
input data_gnt_i;
output uart_error;
assign data_be_o = 4'b1111;
wire transmit_i;
reg [7:0] tx_byte_i;
wire received_o;
wire [7:0] rx_byte_o;
wire is_receiving_o;
wire is_transmitting_o;
wire recv_error_o;
assign uart_error = recv_error_o;
parameter IDLE = 0;
parameter WAIT_ADDR_HEAD = 1;
parameter WAIT_ADDR_TAIL = 2;
parameter RECEIVE_WRITE_DATA = 3;
parameter SEND_READ_DATA = 4;
parameter PKT_ALIVE = 8'b00100000;
parameter PKT_WRITE_CMD = 8'b01000001;
parameter PKT_ADR = 8'b01100000;
parameter PKT_READ_CMD = 8'b01000010;
reg [2:0] UART_STATE;
reg [31:0] DATA;
reg [31:0] DATA_READ;
reg [ADDR_WIDTH - 1:0] MEMORY_ADDRESS;
assign data_wdata_o = DATA[31:0];
assign data_addr_o[ADDR_WIDTH - 1:0] = {MEMORY_ADDRESS[ADDR_WIDTH - 1:0]};
reg transmit;
reg trans_txn_ff2;
reg trans_txn_ff;
assign transmit_i = !trans_txn_ff2 & trans_txn_ff;
always @(posedge clk_i)
if (rst_i) begin
trans_txn_ff <= 1'b0;
trans_txn_ff2 <= 1'b0;
end
else begin
trans_txn_ff <= transmit;
trans_txn_ff2 <= trans_txn_ff;
end
reg [2:0] data_count;
reg we;
reg start_read;
reg read_issued;
reg read_registered;
reg read_complete;
reg write_issued;
reg pending_res;
always @(posedge clk_i or posedge rst_i)
if (rst_i) begin
pending_res <= 0;
UART_STATE <= IDLE;
MEMORY_ADDRESS <= 0;
transmit <= 0;
data_count <= 4;
we <= 0;
start_read <= 0;
DATA <= 0;
tx_byte_i <= 0;
end
else
case (UART_STATE)
IDLE: begin
data_count <= 4;
start_read <= 0;
if ((!is_transmitting_o & !received_o) & !is_receiving_o) begin
tx_byte_i <= PKT_ALIVE;
transmit <= 1;
end
else if (received_o || (pending_res == 1'b1)) begin
if (recv_error_o == 1'b0)
if (is_transmitting_o)
pending_res <= 1'b1;
else if (rx_byte_o[7:0] == PKT_WRITE_CMD[7:0]) begin
tx_byte_i <= PKT_WRITE_CMD;
we <= 1;
transmit <= 1;
pending_res <= 1'b0;
UART_STATE <= WAIT_ADDR_HEAD;
end
else if (rx_byte_o[7:0] == PKT_READ_CMD[7:0]) begin
tx_byte_i <= PKT_READ_CMD;
$display("IDLE to WAIT_ADDR_HEAD \n");
we <= 0;
transmit <= 1;
pending_res <= 1'b0;
UART_STATE <= WAIT_ADDR_HEAD;
end
end
else
transmit <= 0;
end
WAIT_ADDR_HEAD:
if (received_o) begin
if (recv_error_o == 1'b1)
UART_STATE <= IDLE;
else if (rx_byte_o[7:5] == PKT_ADR[7:5]) begin
tx_byte_i <= rx_byte_o;
MEMORY_ADDRESS[11:8] <= rx_byte_o[3:0];
transmit <= 1;
UART_STATE <= WAIT_ADDR_TAIL;
$display("WAIT_ADDR_HEAD to WAIT_ADDR_TAIL\n");
end
end
else
transmit <= 0;
WAIT_ADDR_TAIL:
if (received_o) begin
MEMORY_ADDRESS[7:0] <= rx_byte_o[7:0];
data_count <= 4;
if (recv_error_o == 1'b1)
UART_STATE <= IDLE;
else if (we == 1) begin
tx_byte_i <= rx_byte_o;
transmit <= 1;
UART_STATE <= RECEIVE_WRITE_DATA;
end
else begin
start_read <= 1;
$display("WAIT_ADDR_TAIL received_o\n");
end
end
else if (read_issued) begin
$display("WAIT_ADDR_TAIL READ ISSUED\n");
start_read <= 0;
end
else if (read_complete) begin
$display("WAIT_ADDR_TAIL to SEND_READ_DATA\n");
UART_STATE <= SEND_READ_DATA;
end
else
transmit <= 0;
RECEIVE_WRITE_DATA:
if (received_o) begin
$display("packet recieved uart 2 mem");
tx_byte_i <= rx_byte_o;
if (data_count == 4) begin
DATA[31:24] <= rx_byte_o;
data_count <= 3;
end
else if (data_count == 3) begin
DATA[23:16] <= rx_byte_o;
data_count <= 2;
end
else if (data_count == 2) begin
DATA[15:8] <= rx_byte_o;
data_count <= 1;
end
else if (data_count == 1) begin
DATA[7:0] <= rx_byte_o;
data_count <= 0;
UART_STATE <= IDLE;
end
transmit <= 1;
end
else
transmit <= 0;
SEND_READ_DATA:
if (data_count == 4) begin
tx_byte_i <= DATA_READ[31:24];
transmit <= 1;
data_count <= 3;
$display("U2M - Sending B1 -", DATA_READ[31:24]);
end
else if (received_o) begin
if (data_count == 3) begin
tx_byte_i <= DATA_READ[23:16];
data_count <= 2;
$display("U2M - Sending B2 -", DATA_READ[23:16]);
end
else if (data_count == 2) begin
tx_byte_i <= DATA_READ[15:8];
data_count <= 1;
$display("U2M - Sending B3 -", DATA_READ[15:8]);
end
else if (data_count == 1) begin
tx_byte_i <= DATA_READ[7:0];
data_count <= 0;
$display("U2M - Sending B4 -", DATA_READ[7:0]);
end
else if (data_count == 0)
UART_STATE <= IDLE;
transmit <= 1;
end
else
transmit <= 0;
endcase
always @(posedge clk_i)
if (rst_i) begin
write_issued <= 0;
read_issued <= 0;
read_registered <= 0;
DATA_READ <= 0;
data_we_o <= 0;
data_req_o <= 0;
read_complete <= 0;
end
else if (((data_count == 0) | (write_issued == 1)) & (we == 1)) begin
if (write_issued == 0) begin
data_we_o <= 1;
data_req_o <= 1;
write_issued <= 1;
end
else if (write_issued == 1)
if (data_gnt_i == 1) begin
data_req_o <= 0;
write_issued <= 0;
end
end
else if (~read_issued & (start_read == 1)) begin
read_complete <= 0;
data_we_o <= 0;
data_req_o <= 1;
read_issued <= 1;
end
else if ((read_issued == 1) & (data_gnt_i == 1)) begin
data_req_o <= 0;
read_issued <= 0;
read_registered <= 1;
end
else if (read_registered == 1) begin
if (data_rvalid_i) begin
read_registered <= 0;
DATA_READ <= data_rdata_i;
read_complete <= 1;
end
end
else if (read_complete == 1)
read_complete <= 0;
uart uart_i(
clk_i,
rst_i,
rx_i,
tx_o,
transmit_i,
tx_byte_i,
received_o,
rx_byte_o,
is_receiving_o,
is_transmitting_o,
recv_error_o
);
endmodule