7
mirror of https://github.com/parallella/parallella-hw.git synced 2024-11-24 11:35:00 +00:00
parallella-hw/archive/boards/gen1.1/fpga/hdl/axi_slave_rd.v
Andreas Olofsson 046706db8a Reorg
2016-02-03 00:43:14 -05:00

378 lines
12 KiB
Verilog

/*
File: axi_slave_rd.v
This file is part of the Parallella FPGA Reference Design.
Copyright (C) 2013 Adapteva, Inc.
Contributed by Roman Trogan <support@adapteva.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program (see the file COPYING). If not, see
<http://www.gnu.org/licenses/>.
*/
//# Limitations:
//# 1. Read burst cannot cross single core boundaries
module axi_slave_rd (/*AUTOARG*/
// Outputs
arready, rid, rdata, rresp, rlast, rvalid, emesh_access_inb,
emesh_write_inb, emesh_datamode_inb, emesh_ctrlmode_inb,
emesh_dstaddr_inb, emesh_srcaddr_inb, emesh_data_inb,
emesh_wr_wait_inb,
// Inputs
aclk, eclk, reset, arid, araddr, arlen, arsize, arburst, arlock,
arcache, arprot, arvalid, rready, emesh_access_outb,
emesh_write_outb, emesh_datamode_outb, emesh_ctrlmode_outb,
emesh_dstaddr_outb, emesh_srcaddr_outb, emesh_data_outb,
emesh_rd_wait_outb
);
parameter SIDW = 12; //ID Width
parameter SAW = 32; //Address Bus Width
parameter SDW = 32; //Data Bus Width
parameter ACH = SAW+SIDW+5; //Width of all used Read Address Signals
parameter DFW = 4; //Data channel Fifo address width
parameter DCH = SDW+SIDW+1; //Width of all used Read Data Signals
//#########
//# Inputs
//#########
// global signals
input aclk; // clock source of the axi bus
input eclk; // clock source of emesh interface
input reset; // reset
//########################
//# Read address channel
//########################
input [SIDW-1:0] arid; //read address ID
input [SAW-1:0] araddr; //read address
input [3:0] arlen; //burst lenght (the number of data transfers)
input [2:0] arsize; //burst size (the size of each transfer)
input [1:0] arburst; //burst type
input [1:0] arlock; //lock type (atomic characteristics)
input [3:0] arcache; //memory type
input [2:0] arprot; //protection type
input arvalid; //write address valid
//########################
//# Read data channel
//########################
input rready; //read ready
//##############################
//# From the emesh interface
//##############################
input emesh_access_outb;
input emesh_write_outb;
input [1:0] emesh_datamode_outb;
input [3:0] emesh_ctrlmode_outb;
input [31:0] emesh_dstaddr_outb;
input [31:0] emesh_srcaddr_outb;
input [31:0] emesh_data_outb;
input emesh_rd_wait_outb;
//##########
//# Outputs
//##########
//########################
//# Read address channel
//########################
output arready;//read address ready
//########################
//# Read data channel
//########################
output [SIDW-1:0] rid; //read ID tag (must match arid of the transaction)
output [SDW-1:0] rdata;//read data
output [1:0] rresp; //read response
output rlast; //read last, indicates the last transfer in burst
output rvalid;//read valid
//##############################
//# To the emesh interface
//##############################
output emesh_access_inb;
output emesh_write_inb;
output [1:0] emesh_datamode_inb;
output [3:0] emesh_ctrlmode_inb;
output [31:0] emesh_dstaddr_inb;
output [31:0] emesh_srcaddr_inb;
output [31:0] emesh_data_inb;
output emesh_wr_wait_inb;
/*AUTOINPUT*/
/*AUTOWIRE*/
//#########
//# Regs
//#########
reg [3:0] tran_len;
reg tran_go_reg;
reg [SIDW+5:0] tran_info_reg;
reg tran_last_reg;
reg [31:0] dstaddr_reg;
reg [31:0] data_reg;
reg emesh_wr_access_reg;
reg [31:0] realgn_byte;
reg dch_fifo_empty_reg;
reg [DCH-1:0] dch_fifo_reg;
//#########
//# Wires
//#########
wire arready;
wire tran_go;
wire tran_stall;
wire tran_last_int;
wire tran_last;//Indicates last data of burst (out of fifo_dch)
wire [SAW-1:0] tran_addr;
wire [1:0] tran_mode;
wire [SIDW-1:0] arid_ec;
wire [3:0] arlen_ec;
wire [3:0] arlen_new;
wire arlen_dec;
wire [3:0] arlen_upd;
wire rd_last;
wire [2:0] dalgn_ctrl;
wire byte_tran;
wire hword_tran;
wire word_tran;
wire [SIDW+5:0] tran_info;
wire emesh_wr_access;
wire dch_fifo_full;
wire [2:0] realgn_ctrl;
wire [31:0] realgn_hword;
wire byte_realgn;
wire hword_realgn;
wire word_realgn;
wire [31:0] data_realgn;
wire [SIDW-1:0] tran_id;
wire last_tran;
wire [DCH-1:0] dch_fifo_in;
wire dch_fifo_wr;
wire dch_fifo_rd;
wire dch_fifo_empty;
wire [DCH-1:0] dch_fifo_out;
wire rvalid_rready;
wire dch_advance;
wire new_burst;
//#######################################
//# Address channel synchronization FIFO
//#######################################
/*axi_slave_addrch AUTO_TEMPLATE(.aclk (aclk),
.addr (araddr[]),
.ach_fifo_empty (),
.a\(.*\) (ar\1[]),
.new_addr_sel (new_burst),
);
*/
axi_slave_addrch axi_slave_addrch(/*AUTOINST*/
// Outputs
.aready (arready), // Templated
.ach_fifo_empty (), // Templated
.tran_addr (tran_addr[SAW-1:0]),
.tran_mode (tran_mode[1:0]),
.dalgn_ctrl (dalgn_ctrl[2:0]),
.byte_tran (byte_tran),
.hword_tran (hword_tran),
.word_tran (word_tran),
.aid_ec (arid_ec[SIDW-1:0]), // Templated
.alen_ec (arlen_ec[3:0]), // Templated
.new_addr_sel (new_burst), // Templated
// Inputs
.aclk (aclk), // Templated
.eclk (eclk),
.reset (reset),
.avalid (arvalid), // Templated
.addr (araddr[SAW-1:0]), // Templated
.aid (arid[SIDW-1:0]), // Templated
.alen (arlen[3:0]), // Templated
.asize (arsize[2:0]), // Templated
.aburst (arburst[1:0]), // Templated
.tran_last (tran_last),
.tran_stall (tran_stall),
.tran_go (tran_go));
//########################
//# AXI-EMESH conversion
//########################
assign tran_go = |(arlen_new[3:0]);
assign tran_last_int = dch_fifo_wr & last_tran;
assign tran_last = tran_last_reg & ~tran_stall;
always @ (posedge eclk or posedge reset)
if(reset)
tran_last_reg <= 1'b0;
else if(tran_last_int | ~tran_stall)
tran_last_reg <= tran_last_int;
always @ (posedge eclk or posedge reset)
if(reset)
tran_len[3:0] <= 4'b0000;
else if(tran_go & ~tran_stall)
tran_len[3:0] <= arlen_new[3:0];
always @ (posedge eclk or posedge reset)
if(reset)
tran_go_reg <= 1'b0;
else if(~tran_stall)
tran_go_reg <= tran_go;
assign arlen_dec = |(tran_len[3:0]);
assign arlen_upd[3:0] = {(4){arlen_dec}} & (tran_len[3:0] - 4'b0001);
assign arlen_new[3:0] = new_burst ? arlen_ec[3:0] : arlen_upd[3:0];
assign rd_last = (tran_len[3:0] == 4'b0001);
assign tran_info[SIDW+5:0] = {arid_ec[SIDW-1:0],dalgn_ctrl[2:0],byte_tran,
hword_tran,word_tran};
always @ (posedge eclk)
if(tran_go & ~tran_stall)
tran_info_reg[SIDW+5:0] <= tran_info[SIDW+5:0];
//#############################
//# Emesh transaction creation
//#############################
assign emesh_dstaddr_inb[31:0] = tran_addr[SAW-1:0];
assign emesh_srcaddr_inb[31:0] = {`AXI_COORD,{(13-SIDW){1'b0}},
tran_info_reg[SIDW+5:0], rd_last};
assign emesh_data_inb[31:0] = 32'h00000000;
assign emesh_datamode_inb[1:0] = tran_mode[1:0];
assign emesh_ctrlmode_inb[3:0] = 4'b0000;
assign emesh_write_inb = 1'b0;
assign emesh_access_inb = tran_go_reg & ~tran_stall;
//#######################################
//# Data channel synchronization FIFO
//#######################################
assign emesh_wr_wait_inb = dch_fifo_full;
//# Incoming transaction should be sampled to prevent timing issues
assign emesh_wr_access = emesh_access_outb & emesh_write_outb &
~emesh_wr_wait_inb;
always @ (posedge eclk)
if (emesh_wr_access)
dstaddr_reg[31:0] <= emesh_dstaddr_outb[31:0];
always @ (posedge eclk)
if (emesh_wr_access)
data_reg[31:0] <= emesh_data_outb[31:0];
always @ (posedge eclk or posedge reset)
if(reset)
emesh_wr_access_reg <= 1'b0;
else if(~emesh_wr_wait_inb)
emesh_wr_access_reg <= emesh_wr_access;
//# RID
assign tran_id[SIDW-1:0] = dstaddr_reg[SIDW+6:7];
//# Data Re-alignment from the EMESH protocol
assign realgn_ctrl[2:0] = dstaddr_reg[6:4];
assign byte_realgn = dstaddr_reg[3];
assign hword_realgn = dstaddr_reg[2];
assign word_realgn = dstaddr_reg[1];
//# Last transfer
assign last_tran = dstaddr_reg[0];
always @ (realgn_ctrl[1:0] or data_reg[7:0])
begin
casez (realgn_ctrl[1:0])
2'b00 : realgn_byte[31:0] = {{(24){1'b0}},data_reg[7:0] };
2'b01 : realgn_byte[31:0] = {{(16){1'b0}},data_reg[7:0],{( 8){1'b0}}};
2'b10 : realgn_byte[31:0] = {{(8){1'b0}},data_reg[7:0],{(16){1'b0}}};
2'b11 : realgn_byte[31:0] = {data_reg[7:0],{(24){1'b0}}};
default: realgn_byte[31:0] = {{(24){1'b0}},data_reg[7:0]};
endcase // casez (realgn_ctrl[1:0])
end
assign realgn_hword[31:0] = realgn_ctrl[1] ? {data_reg[15:0],{(16){1'b0}}} :
{{(16){1'b0}},data_reg[15:0]};
assign data_realgn[31:0] = byte_realgn ? realgn_byte[31:0] :
hword_realgn ? realgn_hword[31:0]:
data_reg[31:0];
assign dch_fifo_in[DCH-1:0] = {data_realgn[31:0],tran_id[SIDW-1:0],last_tran};
assign dch_fifo_wr = emesh_wr_access_reg & ~dch_fifo_full;
assign dch_fifo_rd = ~dch_fifo_empty & (~rvalid | rvalid_rready);
assign dch_advance = rvalid_rready | ~rvalid;
/*fifo AUTO_TEMPLATE(.rd_clk (aclk),
.wr_clk (eclk),
.wr_data (dch_fifo_in[DCH-1:0]),
.rd_data (dch_fifo_out[DCH-1:0]),
.rd_fifo_empty (dch_fifo_empty),
.wr_fifo_full (dch_fifo_full),
.wr_write (dch_fifo_wr),
.rd_read (dch_fifo_rd),
);
*/
fifo #(.DW(DCH), .AW(DFW)) fifo_dch(/*AUTOINST*/
// Outputs
.rd_data (dch_fifo_out[DCH-1:0]), // Templated
.rd_fifo_empty (dch_fifo_empty), // Templated
.wr_fifo_full (dch_fifo_full), // Templated
// Inputs
.reset (reset),
.wr_clk (eclk), // Templated
.rd_clk (aclk), // Templated
.wr_write (dch_fifo_wr), // Templated
.wr_data (dch_fifo_in[DCH-1:0]), // Templated
.rd_read (dch_fifo_rd)); // Templated
//# The data is sampled after exiting FIFO to prevent timing issues
always @ (posedge aclk or posedge reset)
if(reset)
dch_fifo_empty_reg <= 1'b1;
else if(dch_advance)
dch_fifo_empty_reg <= dch_fifo_empty;
always @ (posedge aclk)
if (dch_advance)
dch_fifo_reg[DCH-1:0] <= dch_fifo_out[DCH-1:0];
assign rid[SIDW-1:0] = dch_fifo_reg[SIDW:1];
assign rresp[1:0] = 2'b00;
assign rvalid = ~dch_fifo_empty_reg;
assign rvalid_rready = rvalid & rready;
assign rdata[SDW-1:0] = dch_fifo_reg[DCH-1:SIDW+1];
assign rlast = dch_fifo_reg[0];
//# Transaction Stall
assign tran_stall = emesh_rd_wait_outb;
endmodule // axi_slave_rd