mirror of
https://github.com/aolofsson/oh.git
synced 2025-01-17 20:02:53 +08:00
eb3051ea93
(pre-debug)
504 lines
16 KiB
Verilog
504 lines
16 KiB
Verilog
module esaxi (/*autoarg*/
|
|
// Outputs
|
|
txwr_access, txwr_packet, txrd_access, txrd_packet, rxrr_wait,
|
|
s_axi_arready, s_axi_awready, s_axi_bid, s_axi_bresp, s_axi_bvalid,
|
|
s_axi_rid, s_axi_rdata, s_axi_rlast, s_axi_rresp, s_axi_rvalid,
|
|
s_axi_wready,
|
|
// Inputs
|
|
txwr_wait, txrd_wait, rxrr_access, rxrr_packet, s_axi_aclk,
|
|
s_axi_aresetn, s_axi_arid, s_axi_araddr, s_axi_arburst,
|
|
s_axi_arcache, s_axi_arlock, s_axi_arlen, s_axi_arprot,
|
|
s_axi_arqos, s_axi_arsize, s_axi_arvalid, s_axi_awid, s_axi_awaddr,
|
|
s_axi_awburst, s_axi_awcache, s_axi_awlock, s_axi_awlen,
|
|
s_axi_awprot, s_axi_awqos, s_axi_awsize, s_axi_awvalid,
|
|
s_axi_bready, s_axi_rready, s_axi_wid, s_axi_wdata, s_axi_wlast,
|
|
s_axi_wstrb, s_axi_wvalid
|
|
);
|
|
|
|
parameter [11:0] ID = 12'h810;
|
|
parameter IDW = 12;
|
|
parameter PW = 104;
|
|
parameter [15:0] RETURN_ADDR = {ID,4'hE};
|
|
parameter AW = 32;
|
|
parameter DW = 32;
|
|
|
|
/*****************************/
|
|
/*Write request for TX fifo */
|
|
/*****************************/
|
|
output txwr_access;
|
|
output [PW-1:0] txwr_packet;
|
|
input txwr_wait;
|
|
|
|
/*****************************/
|
|
/*Read request for TX fifo */
|
|
/*****************************/
|
|
output txrd_access;
|
|
output [PW-1:0] txrd_packet;
|
|
input txrd_wait;
|
|
|
|
/*****************************/
|
|
/*Read response from RX fifo */
|
|
/*****************************/
|
|
input rxrr_access;
|
|
input [PW-1:0] rxrr_packet;
|
|
output rxrr_wait;
|
|
|
|
/*****************************/
|
|
/*AXI slave interface */
|
|
/*****************************/
|
|
//Clock and reset
|
|
input s_axi_aclk;
|
|
input s_axi_aresetn;
|
|
|
|
//Read address channel
|
|
input [IDW-1:0] s_axi_arid; //write address ID
|
|
input [31:0] s_axi_araddr;
|
|
input [1:0] s_axi_arburst;
|
|
input [3:0] s_axi_arcache;
|
|
input [1:0] s_axi_arlock;
|
|
input [7:0] s_axi_arlen;
|
|
input [2:0] s_axi_arprot;
|
|
input [3:0] s_axi_arqos;
|
|
output s_axi_arready;
|
|
input [2:0] s_axi_arsize;
|
|
input s_axi_arvalid;
|
|
|
|
//Write address channel
|
|
input [IDW-1:0] s_axi_awid; //write address ID
|
|
input [31:0] s_axi_awaddr;
|
|
input [1:0] s_axi_awburst;
|
|
input [3:0] s_axi_awcache;
|
|
input [1:0] s_axi_awlock;
|
|
input [7:0] s_axi_awlen;
|
|
input [2:0] s_axi_awprot;
|
|
input [3:0] s_axi_awqos;
|
|
input [2:0] s_axi_awsize;
|
|
input s_axi_awvalid;
|
|
output s_axi_awready;
|
|
|
|
//Buffered write response channel
|
|
output [IDW-1:0] s_axi_bid; //write address ID
|
|
output [1:0] s_axi_bresp;
|
|
output s_axi_bvalid;
|
|
input s_axi_bready;
|
|
|
|
//Read channel
|
|
output [IDW-1:0] s_axi_rid; //write address ID
|
|
output [31:0] s_axi_rdata;
|
|
output s_axi_rlast;
|
|
output [1:0] s_axi_rresp;
|
|
output s_axi_rvalid;
|
|
input s_axi_rready;
|
|
|
|
//Write channel
|
|
input [IDW-1:0] s_axi_wid; //write address ID
|
|
input [31:0] s_axi_wdata;
|
|
input s_axi_wlast;
|
|
input [3:0] s_axi_wstrb;
|
|
input s_axi_wvalid;
|
|
output s_axi_wready;
|
|
|
|
//###################################################
|
|
//#WIRE/REG DECLARATIONS
|
|
//###################################################
|
|
|
|
reg s_axi_awready;
|
|
reg s_axi_wready;
|
|
reg s_axi_bvalid;
|
|
reg [1:0] s_axi_bresp;
|
|
reg s_axi_arready;
|
|
|
|
reg [31:0] axi_awaddr; // 32b for epiphany addr
|
|
reg [1:0] axi_awburst;
|
|
reg [2:0] axi_awsize;
|
|
|
|
reg [31:0] axi_araddr;
|
|
reg [7:0] axi_arlen;
|
|
reg [1:0] axi_arburst;
|
|
reg [2:0] axi_arsize;
|
|
|
|
reg [31:0] s_axi_rdata;
|
|
reg [1:0] s_axi_rresp;
|
|
reg s_axi_rlast;
|
|
reg s_axi_rvalid;
|
|
|
|
reg read_active;
|
|
reg [31:0] read_addr;
|
|
reg write_active;
|
|
reg b_wait; // waiting to issue write response (unlikely?)
|
|
|
|
reg txwr_access;
|
|
reg [1:0] txwr_datamode;
|
|
reg [31:0] txwr_dstaddr;
|
|
reg [31:0] txwr_data;
|
|
|
|
reg [31:0] txwr_data_reg;
|
|
reg [31:0] txwr_dstaddr_reg;
|
|
reg [1:0] txwr_datamode_reg;
|
|
|
|
reg txrd_access;
|
|
reg [1:0] txrd_datamode;
|
|
reg [31:0] txrd_dstaddr;
|
|
reg [31:0] txrd_srcaddr; //read reaspne address
|
|
|
|
reg pre_wr_en; // delay for data alignment
|
|
|
|
reg ractive_reg; // need leading edge of active for 1st req
|
|
reg rnext;
|
|
|
|
wire last_wr_beat;
|
|
wire last_rd_beat;
|
|
|
|
wire [31:0] rxrr_mux_data;
|
|
wire [DW-1:0] rxrr_data;
|
|
|
|
//###################################################
|
|
//#PACKET TO MESH
|
|
//###################################################
|
|
|
|
//TXWR
|
|
emesh2packet e2p_txwr (
|
|
// Outputs
|
|
.packet_out (txwr_packet[PW-1:0]),
|
|
// Inputs
|
|
.access_in (txwr_access),
|
|
.write_in (1'b1),
|
|
.datamode_in (txwr_datamode[1:0]),
|
|
.ctrlmode_in (4'b0),
|
|
.dstaddr_in (txwr_dstaddr[AW-1:0]),
|
|
.data_in (txwr_data[DW-1:0]),
|
|
.srcaddr_in (32'b0)//only 32b slave write supported
|
|
);
|
|
|
|
//TXRD
|
|
emesh2packet e2p_txrd (
|
|
// Outputs
|
|
.packet_out (txrd_packet[PW-1:0]),
|
|
// Inputs
|
|
.access_in (txrd_access),
|
|
.write_in (txrd_write),
|
|
.datamode_in (txrd_datamode[1:0]),
|
|
.ctrlmode_in (4'b0),
|
|
.dstaddr_in (txrd_dstaddr[AW-1:0]),
|
|
.data_in (32'b0),
|
|
.srcaddr_in (txrd_srcaddr[AW-1:0])
|
|
);
|
|
//RXRR
|
|
packet2emesh p2e_rxrr (
|
|
// Outputs
|
|
.access_out (),
|
|
.write_out (),
|
|
.datamode_out (),
|
|
.ctrlmode_out (),
|
|
.dstaddr_out (),
|
|
.data_out (rxrr_data[DW-1:0]),
|
|
.srcaddr_out (),
|
|
// Inputs
|
|
.packet_in (rxrr_packet[PW-1:0])
|
|
);
|
|
|
|
//###################################################
|
|
//#WRITE ADDRESS CHANNEL
|
|
//###################################################
|
|
|
|
assign last_wr_beat = s_axi_wready & s_axi_wvalid & s_axi_wlast;
|
|
|
|
// axi_awready is asserted when there is no write transfer in progress
|
|
|
|
always @(posedge s_axi_aclk )
|
|
begin
|
|
if(~s_axi_aresetn)
|
|
begin
|
|
s_axi_awready <= 1'b0;
|
|
write_active <= 1'b0;
|
|
end
|
|
else
|
|
begin
|
|
// we're always ready for an address cycle if we're not doing something else
|
|
// note: might make this faster by going ready on last beat instead of after,
|
|
// but if we want the very best each channel should be fifo'd.
|
|
if( ~s_axi_awready & ~write_active & ~b_wait )
|
|
s_axi_awready <= 1'b1;
|
|
else if( s_axi_awvalid )
|
|
s_axi_awready <= 1'b0;
|
|
|
|
// the write cycle is "active" as soon as we capture an address, it
|
|
// ends on the last beat.
|
|
if( s_axi_awready & s_axi_awvalid )
|
|
write_active <= 1'b1;
|
|
else if( last_wr_beat )
|
|
write_active <= 1'b0;
|
|
end // else: !if(~s_axi_aresetn)
|
|
end // always @ (posedge s_axi_aclk )
|
|
|
|
// capture address & other aw info, update address during cycle
|
|
always @( posedge s_axi_aclk )
|
|
if (~s_axi_aresetn)
|
|
begin
|
|
//s_axi_bid <= 'd0; // capture for write response
|
|
axi_awaddr[31:0] <= 32'd0;
|
|
axi_awsize[2:0] <= 3'd0;
|
|
axi_awburst[1:0] <= 2'd0;
|
|
end
|
|
else
|
|
begin
|
|
if( s_axi_awready & s_axi_awvalid )
|
|
begin
|
|
axi_awaddr[31:0] <= s_axi_awaddr[31:0];
|
|
axi_awsize <= s_axi_awsize; // 0=byte, 1=16b, 2=32b
|
|
axi_awburst <= s_axi_awburst; // type, 0=fixed, 1=incr, 2=wrap
|
|
end
|
|
else if( s_axi_wvalid & s_axi_wready )
|
|
if( axi_awburst == 2'b01 )
|
|
begin //incremental burst
|
|
// the write address for all the beats in the transaction are increments by the data width.
|
|
// note: this should be based on awsize instead to support narrow bursts, i think.
|
|
axi_awaddr[31:2] <= axi_awaddr[31:2] + 30'd1;
|
|
//awaddr alignedto data width
|
|
axi_awaddr[1:0] <= 2'b0;
|
|
end // both fixed & wrapping types are treated as fixed, no update.
|
|
end // else: !if(~s_axi_aresetn)
|
|
|
|
//###################################################
|
|
//#WRITE RESPONSE CHANNEL
|
|
//###################################################
|
|
always @ (posedge s_axi_aclk)
|
|
if(~s_axi_aresetn)
|
|
s_axi_wready <= 1'b0;
|
|
else
|
|
begin
|
|
if( last_wr_beat )
|
|
s_axi_wready <= 1'b0;
|
|
else if( write_active )
|
|
s_axi_wready <= ~txwr_wait;
|
|
end
|
|
|
|
always @( posedge s_axi_aclk )
|
|
if (~s_axi_aresetn)
|
|
begin
|
|
s_axi_bvalid <= 1'b0;
|
|
s_axi_bresp[1:0] <= 2'b0;
|
|
b_wait <= 1'b0;
|
|
end
|
|
else
|
|
begin
|
|
if( last_wr_beat )
|
|
begin
|
|
s_axi_bvalid <= 1'b1;
|
|
s_axi_bresp[1:0] <= 2'b0; // 'okay' response
|
|
b_wait <= ~s_axi_bready; // note: assumes bready will not drop without valid?
|
|
end
|
|
else if (s_axi_bready & s_axi_bvalid)
|
|
begin
|
|
s_axi_bvalid <= 1'b0;
|
|
b_wait <= 1'b0;
|
|
end
|
|
end // else: !if( s_axi_aresetn == 1'b0 )
|
|
|
|
//###################################################
|
|
//#READ REQUEST CHANNEL
|
|
//###################################################
|
|
|
|
assign last_rd_beat = s_axi_rvalid & s_axi_rlast & s_axi_rready;
|
|
|
|
always @( posedge s_axi_aclk )
|
|
if (~s_axi_aresetn)
|
|
begin
|
|
s_axi_arready <= 1'b0;
|
|
read_active <= 1'b0;
|
|
end
|
|
else
|
|
begin
|
|
//arready
|
|
if( ~s_axi_arready & ~read_active )
|
|
s_axi_arready <= 1'b1;
|
|
else if( s_axi_arvalid )
|
|
s_axi_arready <= 1'b0;
|
|
|
|
//read_active
|
|
if( s_axi_arready & s_axi_arvalid )
|
|
read_active <= 1'b1;
|
|
else if( last_rd_beat )
|
|
read_active <= 1'b0;
|
|
end // else: !if( s_axi_aresetn == 1'b0 )
|
|
|
|
//Read address channel state machine
|
|
always @( posedge s_axi_aclk )
|
|
if (~s_axi_aresetn)
|
|
begin
|
|
axi_araddr[31:0] <= 0;
|
|
axi_arlen <= 8'd0;
|
|
axi_arburst <= 2'd0;
|
|
axi_arsize[2:0] <= 3'b0;
|
|
s_axi_rlast <= 1'b0;
|
|
//s_axi_rid <= 'd0;
|
|
end
|
|
else
|
|
begin
|
|
if( s_axi_arready & s_axi_arvalid )
|
|
begin
|
|
axi_araddr[31:0] <= s_axi_araddr[31:0]; //NOTE: upper 2 bits get chopped by Zynq
|
|
axi_arlen <= s_axi_arlen;
|
|
axi_arburst <= s_axi_arburst;
|
|
axi_arsize <= s_axi_arsize;
|
|
s_axi_rlast <= ~(|s_axi_arlen);
|
|
//s_axi_rid <= s_axi_arid;
|
|
end
|
|
else if( s_axi_rvalid & s_axi_rready)
|
|
begin
|
|
axi_arlen <= axi_arlen - 1;
|
|
if(axi_arlen == 8'd1)
|
|
s_axi_rlast <= 1'b1;
|
|
if( s_axi_arburst == 2'b01)
|
|
begin //incremental burst
|
|
// the read address for all the beats in the transaction are increments by awsize
|
|
// note: this should be based on awsize instead to support narrow bursts, i think?
|
|
axi_araddr[31:2] <= axi_araddr[31:2] + 1;
|
|
//araddr aligned to 4 byte boundary
|
|
axi_araddr[1:0] <= 2'b0;
|
|
//for awsize = 4 bytes (010)
|
|
end
|
|
end // if ( s_axi_rvalid & s_axi_rready)
|
|
end // else: !if( s_axi_aresetn == 1'b0 )
|
|
|
|
|
|
//###################################################
|
|
//#WRITE REQUEST
|
|
//###################################################
|
|
assign txwr_write = 1'b1;
|
|
|
|
always @( posedge s_axi_aclk )
|
|
if (~s_axi_aresetn)
|
|
begin
|
|
txwr_data_reg[31:0] <= 32'd0;
|
|
txwr_dstaddr_reg[31:0] <= 32'd0;
|
|
txwr_datamode_reg[1:0] <= 2'd0;
|
|
txwr_access <= 1'b0;
|
|
pre_wr_en <= 1'b0;
|
|
end
|
|
else
|
|
begin
|
|
pre_wr_en <= s_axi_wready & s_axi_wvalid;
|
|
txwr_access <= pre_wr_en;
|
|
txwr_datamode_reg[1:0] <= axi_awsize[1:0];
|
|
txwr_dstaddr_reg[31:2] <= axi_awaddr[31:2]; //set lsbs of address based on write strobes
|
|
if(s_axi_wstrb[0] | (axi_awsize[1:0]==2'b10))
|
|
begin
|
|
txwr_data_reg[31:0] <= s_axi_wdata[31:0];
|
|
txwr_dstaddr_reg[1:0] <= 2'd0;
|
|
end
|
|
else if(s_axi_wstrb[1])
|
|
begin
|
|
txwr_data_reg[31:0] <= {8'd0, s_axi_wdata[31:8]};
|
|
txwr_dstaddr_reg[1:0] <= 2'd1;
|
|
end
|
|
else if(s_axi_wstrb[2])
|
|
begin
|
|
txwr_data_reg[31:0] <= {16'd0, s_axi_wdata[31:16]};
|
|
txwr_dstaddr_reg[1:0] <= 2'd2;
|
|
end
|
|
else
|
|
begin
|
|
txwr_data_reg[31:0] <= {24'd0, s_axi_wdata[31:24]};
|
|
txwr_dstaddr_reg[1:0] <= 2'd3;
|
|
end
|
|
end // else: !if(~s_axi_aresetn)
|
|
|
|
//Pipeline stage!
|
|
always @( posedge s_axi_aclk )
|
|
if (~s_axi_aresetn)
|
|
begin
|
|
txwr_data[31:0] <= 32'd0;
|
|
txwr_dstaddr[31:0] <= 32'd0;
|
|
txwr_datamode[1:0] <= 2'd0;
|
|
end
|
|
else
|
|
begin
|
|
txwr_data[31:0] <= txwr_data_reg[31:0];
|
|
txwr_dstaddr[31:0] <= txwr_dstaddr_reg[31:0];
|
|
txwr_datamode[1:0] <= txwr_datamode_reg[1:0];
|
|
end // else: !if(~s_axi_aresetn)
|
|
|
|
//###################################################
|
|
//#READ REQUEST (DATA CHANNEL)
|
|
//###################################################
|
|
// -- reads are performed by sending a read
|
|
// -- request out the tx port and waiting for
|
|
// -- data to come back through the rx read response port.
|
|
// --
|
|
// -- because elink reads are not generally
|
|
// -- returned in order, we will only allow
|
|
// -- one at a time.
|
|
|
|
assign txrd_write = 1'b0;
|
|
|
|
always @( posedge s_axi_aclk )
|
|
if (~s_axi_aresetn)
|
|
begin
|
|
txrd_access <= 1'b0;
|
|
txrd_datamode[1:0] <= 2'd0;
|
|
txrd_dstaddr[31:0] <= 32'd0;
|
|
txrd_srcaddr[31:0] <= 32'd0;
|
|
ractive_reg <= 1'b0;
|
|
rnext <= 1'b0;
|
|
end
|
|
else
|
|
begin
|
|
ractive_reg <= read_active;
|
|
rnext <= s_axi_rvalid & s_axi_rready & ~s_axi_rlast;
|
|
txrd_access <= ( ~ractive_reg & read_active ) | rnext;
|
|
txrd_datamode[1:0] <= axi_arsize[1:0];
|
|
txrd_dstaddr[31:0] <= axi_araddr[31:0];
|
|
txrd_srcaddr[31:0] <= {RETURN_ADDR, 16'd0};
|
|
//TODO: use arid+srcaddr for out of order ?
|
|
end
|
|
//###################################################
|
|
//#READ RESPONSE (DATA CHANNEL)
|
|
//###################################################
|
|
//Read response AXI state machine
|
|
//Only one outstanding read
|
|
|
|
assign rxrr_wait = 1'b0;
|
|
|
|
always @( posedge s_axi_aclk )
|
|
if (~s_axi_aresetn)
|
|
begin
|
|
s_axi_rvalid <= 1'b0;
|
|
s_axi_rdata[31:0] <= 32'd0;
|
|
s_axi_rresp <= 2'd0;
|
|
end
|
|
else
|
|
begin
|
|
if( rxrr_access )
|
|
begin
|
|
s_axi_rvalid <= 1'b1;
|
|
s_axi_rresp <= 2'd0;
|
|
case( axi_arsize[1:0] )
|
|
2'b00: s_axi_rdata[31:0] <= {4{rxrr_data[7:0]}}; //8-bit
|
|
2'b01: s_axi_rdata[31:0] <= {2{rxrr_data[15:0]}}; //16-bit
|
|
default: s_axi_rdata[31:0] <= rxrr_data[31:0]; //32-bit
|
|
endcase // case ( axi_arsize[1:0] )
|
|
end
|
|
else if( s_axi_rready )
|
|
s_axi_rvalid <= 1'b0;
|
|
end // else: !if( s_axi_aresetn == 1'b0 )
|
|
|
|
endmodule // esaxi
|
|
|
|
/*
|
|
Copyright (C) 2014 Adapteva, Inc.
|
|
|
|
Contributed by Andreas Olofsson <andreas@adapteva.com>
|
|
Contributed by Fred Huettig <fred@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/>.
|
|
*/
|