1
0
mirror of https://github.com/aolofsson/oh.git synced 2025-01-17 20:02:53 +08:00
oh/elink/hdl/emaxi.v
Andreas Olofsson c885745f6c Fixing half/byte zero-out bug
- Interrupted mid coding apparently..
- Upper bits need to be zeroed out for 8/16 bit read responses
2015-11-11 14:00:13 -05:00

520 lines
18 KiB
Verilog

/*
########################################################################
Epiphany eLink AXI Master Module
########################################################################
NOTES:
--write channels: write address, write data, write response
--read channels: read address, read data channel
--'valid' source signal used to show valid address,data,control is available
--'ready' destination ready signal indicates readyness to accept information
--'last' signal indicates the transfer of final data item
--read and write have separate address channels
--read data channel carries read data from slave to master
--write channel includes a byte lane strobe signal for every eight data bits
--there is no acknowledge on write, treated as buffered
--channels are unidirectional
--valid is asserted uncondotionally
--ready occurs cycle after valid
--there can be no combinatorial path between input and output of interface
--destination is permitted to wait for valud before asserting READY
--source is not allowed to wait for READY to assert VALID
--AWVALID must remain asserted until the rising clock edge after slave asserts AWREADY??
--The default state of AWREADY can be either HIGH or LOW. This specification recommends a default state of HIGH.
--During a write burst, the master can assert the WVALID signal only when it drives valid write data.
--The default state of WREADY can be HIGH, but only if the slave can always accept write data in a single cycle.
--The master must assert the WLAST signal while it is driving the final write transfer in the burst.
--_aw=write address channel
--_ar=read address channel
--_r=read data channel
--_w=write data channel
--_b=write response channel
*/
module emaxi(/*autoarg*/
// Outputs
rxwr_wait, rxrd_wait, txrr_access, txrr_packet, m_axi_awid,
m_axi_awaddr, m_axi_awlen, m_axi_awsize, m_axi_awburst,
m_axi_awlock, m_axi_awcache, m_axi_awprot, m_axi_awqos,
m_axi_awvalid, m_axi_wid, m_axi_wdata, m_axi_wstrb, m_axi_wlast,
m_axi_wvalid, m_axi_bready, m_axi_arid, m_axi_araddr, m_axi_arlen,
m_axi_arsize, m_axi_arburst, m_axi_arlock, m_axi_arcache,
m_axi_arprot, m_axi_arqos, m_axi_arvalid, m_axi_rready,
// Inputs
rxwr_access, rxwr_packet, rxrd_access, rxrd_packet, txrr_wait,
m_axi_aclk, m_axi_aresetn, m_axi_awready, m_axi_wready, m_axi_bid,
m_axi_bresp, m_axi_bvalid, m_axi_arready, m_axi_rid, m_axi_rdata,
m_axi_rresp, m_axi_rlast, m_axi_rvalid
);
parameter M_IDW = 12;
parameter PW = 104;
parameter AW = 32;
parameter DW = 32;
//########################
//ELINK INTERFACE
//########################
//Write request from erx
input rxwr_access;
input [PW-1:0] rxwr_packet;
output rxwr_wait;
//Read request from erx
input rxrd_access;
input [PW-1:0] rxrd_packet;
output rxrd_wait;
//Read respoonse for etx
output txrr_access;
output [PW-1:0] txrr_packet;
input txrr_wait;
//########################
//AXI MASTER INTERFACE
//########################
input m_axi_aclk; // global clock signal.
input m_axi_aresetn; // global reset singal.
//Write address channel
output [M_IDW-1:0] m_axi_awid; // write address ID
output [31 : 0] m_axi_awaddr; // master interface write address
output [7 : 0] m_axi_awlen; // burst length.
output [2 : 0] m_axi_awsize; // burst size.
output [1 : 0] m_axi_awburst; // burst type.
output m_axi_awlock; // lock type
output [3 : 0] m_axi_awcache; // memory type.
output [2 : 0] m_axi_awprot; // protection type.
output [3 : 0] m_axi_awqos; // quality of service
output m_axi_awvalid; // write address valid
input m_axi_awready; // write address ready
//Write data channel
output [M_IDW-1:0] m_axi_wid;
output [63 : 0] m_axi_wdata; // master interface write data.
output [7 : 0] m_axi_wstrb; // byte write strobes
output m_axi_wlast; // indicates last transfer in a write burst.
output m_axi_wvalid; // indicates data is ready to go
input m_axi_wready; // indicates that the slave is ready for data
//Write response channel
input [M_IDW-1:0] m_axi_bid;
input [1 : 0] m_axi_bresp; // status of the write transaction.
input m_axi_bvalid; // channel is signaling a valid write response
output m_axi_bready; // master can accept write response.
//Read address channel
output [M_IDW-1:0] m_axi_arid; // read address ID
output [31 : 0] m_axi_araddr; // initial address of a read burst
output [7 : 0] m_axi_arlen; // burst length
output [2 : 0] m_axi_arsize; // burst size
output [1 : 0] m_axi_arburst; // burst type
output m_axi_arlock; //lock type
output [3 : 0] m_axi_arcache; // memory type
output [2 : 0] m_axi_arprot; // protection type
output [3 : 0] m_axi_arqos; //
output m_axi_arvalid; // valid read address and control information
input m_axi_arready; // slave is ready to accept an address
//Read data channel
input [M_IDW-1:0] m_axi_rid;
input [63 : 0] m_axi_rdata; // master read data
input [1 : 0] m_axi_rresp; // status of the read transfer
input m_axi_rlast; // signals last transfer in a read burst
input m_axi_rvalid; // signaling the required read data
output m_axi_rready; // master can accept the readback data
//#########################################################################
//REGISTER/WIRE DECLARATIONS
//#########################################################################
reg [31 : 0] m_axi_awaddr;
reg [7:0] m_axi_awlen;
reg [2:0] m_axi_awsize;
reg m_axi_awvalid;
reg [63 : 0] m_axi_wdata;
reg [63 : 0] m_axi_rdata_reg;
reg [7 : 0] m_axi_wstrb;
reg m_axi_wlast;
reg m_axi_wvalid;
reg awvalid_b;
reg [31:0] awaddr_b;
reg [2:0] awsize_b;
reg [7:0] awlen_b;
reg wvalid_b;
reg [63:0] wdata_b;
reg [7:0] wstrb_b;
reg [63 : 0] wdata_aligned;
reg [7 : 0] wstrb_aligned;
reg txrr_access;
reg txrr_access_reg;
reg [31:0] txrr_data;
reg [31:0] txrr_srcaddr;
//wires
wire aw_go;
wire w_go;
wire readinfo_wren;
wire readinfo_full;
wire [47:0] readinfo_out;
wire [47:0] readinfo_in;
wire awvalid_in;
wire [1:0] rxwr_datamode;
wire [AW-1:0] rxwr_dstaddr;
wire [DW-1:0] rxwr_data;
wire [AW-1:0] rxwr_srcaddr;
wire [1:0] rxrd_datamode;
wire [3:0] rxrd_ctrlmode;
wire [AW-1:0] rxrd_dstaddr;
wire [AW-1:0] rxrd_srcaddr;
wire [1:0] txrr_datamode;
wire [3:0] txrr_ctrlmode;
wire [31:0] txrr_dstaddr;
//#########################################################################
//EMESH 2 PACKET CONVERSION
//#########################################################################
//RXWR
packet2emesh p2e_rxwr (
// Outputs
.write_out (),
.datamode_out (rxwr_datamode[1:0]),
.ctrlmode_out (),
.dstaddr_out (rxwr_dstaddr[AW-1:0]),
.data_out (rxwr_data[DW-1:0]),
.srcaddr_out (rxwr_srcaddr[AW-1:0]),
// Inputs
.packet_in (rxwr_packet[PW-1:0])
);
//RXRD
packet2emesh p2e_rxrd (
// Outputs
.write_out (),
.datamode_out (rxrd_datamode[1:0]),
.ctrlmode_out (rxrd_ctrlmode[3:0]),
.dstaddr_out (rxrd_dstaddr[AW-1:0]),
.data_out (),
.srcaddr_out (rxrd_srcaddr[AW-1:0]),
// Inputs
.packet_in (rxrd_packet[PW-1:0])
);
//TXRR
emesh2packet e2p (
// Outputs
.packet_out (txrr_packet[PW-1:0]),
// Inputs
.write_in (1'b1),
.datamode_in (txrr_datamode[1:0]),
.ctrlmode_in (txrr_ctrlmode[3:0]),
.dstaddr_in (txrr_dstaddr[AW-1:0]),
.data_in (txrr_data[DW-1:0]),
.srcaddr_in (txrr_srcaddr[AW-1:0])
);
//#########################################################################
//AXI unimplemented constants
//#########################################################################
//AW
assign m_axi_awid[M_IDW-1:0] = {(M_IDW){1'b0}};
assign m_axi_awburst[1:0] = 2'b01; //only increment burst supported
assign m_axi_awcache[3:0] = 4'b0000;//TODO: correct value??
assign m_axi_awprot[2:0] = 3'b000;
assign m_axi_awqos[3:0] = 4'b0000;
assign m_axi_awlock = 1'b0;
//AR
assign m_axi_arid[M_IDW-1:0] = {(M_IDW){1'b0}};
assign m_axi_arburst[1:0] = 2'b01; //only increment burst supported
assign m_axi_arcache[3:0] = 4'b0000;
assign m_axi_arprot[2:0] = 3'h0;
assign m_axi_arqos[3:0] = 4'h0;
assign m_axi_arlock = 1'b0;
//B
assign m_axi_bready = 1'b1;//TODO: tie to wait signal????
//W
assign m_axi_wid[M_IDW-1:0] = {(M_IDW){1'b0}};
//#########################################################################
//Write address channel
//#########################################################################
assign aw_go = m_axi_awvalid & m_axi_awready;
assign w_go = m_axi_wvalid & m_axi_wready;
assign rxwr_wait = awvalid_b | wvalid_b;
assign awvalid_in = rxwr_access & ~awvalid_b & ~wvalid_b;
// generate write-address signals
always @( posedge m_axi_aclk )
if(!m_axi_aresetn)
begin
m_axi_awvalid <= 1'b0;
m_axi_awaddr[31:0] <= 32'd0;
m_axi_awlen[7:0] <= 8'd0;
m_axi_awsize[2:0] <= 3'd0;
awvalid_b <= 1'b0;
awaddr_b <= 'd0;
awlen_b[7:0] <= 'd0;
awsize_b[2:0] <= 'd0;
end
else
begin
if( ~m_axi_awvalid | aw_go )
begin
if( awvalid_b )
begin
m_axi_awvalid <= 1'b1;
m_axi_awaddr[31:0] <= awaddr_b[31:0];
m_axi_awlen[7:0] <= awlen_b[7:0];
m_axi_awsize[2:0] <= awsize_b[2:0];
end
else
begin
m_axi_awvalid <= awvalid_in;
m_axi_awaddr[31:0] <= rxwr_dstaddr[31:0];
m_axi_awlen[7:0] <= 8'b0;
m_axi_awsize[2:0] <= { 1'b0, rxwr_datamode[1:0]};
end
end
if( awvalid_in & m_axi_awvalid & ~aw_go )
awvalid_b <= 1'b1;
else if( aw_go )
awvalid_b <= 1'b0;
//Pipeline stage
if( awvalid_in )
begin
awaddr_b[31:0] <= rxwr_dstaddr[31:0];
awlen_b[7:0] <= 8'b0;
awsize_b[2:0] <= { 1'b0, rxwr_datamode[1:0] };
end
end // else: !if(~m_axi_aresetn)
//#########################################################################
//Write data alignment circuit
//#########################################################################
always @*
case( rxwr_datamode[1:0] )
2'b00: wdata_aligned[63:0] = { 8{rxwr_data[7:0]}};
2'b01: wdata_aligned[63:0] = { 4{rxwr_data[15:0]}};
2'b10: wdata_aligned[63:0] = { 2{rxwr_data[31:0]}};
default: wdata_aligned[63:0] = { rxwr_srcaddr[31:0], rxwr_data[31:0]};
endcase
always @*
begin
case(rxwr_datamode[1:0])
2'd0: // byte
case(rxwr_dstaddr[2:0])
3'd0: wstrb_aligned[7:0] = 8'h01;
3'd1: wstrb_aligned[7:0] = 8'h02;
3'd2: wstrb_aligned[7:0] = 8'h04;
3'd3: wstrb_aligned[7:0] = 8'h08;
3'd4: wstrb_aligned[7:0] = 8'h10;
3'd5: wstrb_aligned[7:0] = 8'h20;
3'd6: wstrb_aligned[7:0] = 8'h40;
default: wstrb_aligned[7:0] = 8'h80;
endcase
2'd1: // 16b hword
case(rxwr_dstaddr[2:1])
2'd0: wstrb_aligned[7:0] = 8'h03;
2'd1: wstrb_aligned[7:0] = 8'h0c;
2'd2: wstrb_aligned[7:0] = 8'h30;
default: wstrb_aligned[7:0] = 8'hc0;
endcase
2'd2: // 32b word
if(rxwr_dstaddr[2])
wstrb_aligned[7:0] = 8'hf0;
else
wstrb_aligned[7:0] = 8'h0f;
2'd3:
wstrb_aligned[7:0] = 8'hff;
endcase // case (emwr_datamode[1:0])
end // always @ *
//#########################################################################
//Write data channel
//#########################################################################
always @ (posedge m_axi_aclk )
if(~m_axi_aresetn)
begin
m_axi_wvalid <= 1'b0;
m_axi_wdata[63:0] <= 64'b0;
m_axi_wstrb[7:0] <= 8'b0;
m_axi_wlast <= 1'b1; // TODO:bursts!!
wvalid_b <= 1'b0;
wdata_b[63:0] <= 64'b0;
wstrb_b[7:0] <= 8'b0;
end
else
begin
if( ~m_axi_wvalid | w_go )
begin
if( wvalid_b )
begin
m_axi_wvalid <= 1'b1;
m_axi_wdata[63:0] <= wdata_b[63:0];
m_axi_wstrb[7:0] <= wstrb_b[7:0];
end
else
begin
m_axi_wvalid <= awvalid_in;
m_axi_wdata[63:0] <= wdata_aligned[63:0];
m_axi_wstrb[7:0] <= wstrb_aligned[7:0];
end
end // if ( ~axi_wvalid | w_go )
if( rxwr_access & m_axi_wvalid & ~w_go )
wvalid_b <= 1'b1;
else if( w_go )
wvalid_b <= 1'b0;
if( awvalid_in )
begin
wdata_b[63:0] <= wdata_aligned[63:0];
wstrb_b[7:0] <= wstrb_aligned[7:0];
end
end // else: !if(~m_axi_aresetn)
//#########################################################################
//Read request channel
//#########################################################################
//1. read request comes in on ar channel
//2. use src address to match with writes coming back
//3. Assumes in order returns
assign readinfo_in[47:0] =
{
7'b0,
rxrd_srcaddr[31:0],//40:9
rxrd_dstaddr[2:0], //8:6
rxrd_ctrlmode[3:0],//5:2
rxrd_datamode[1:0]
};
//Rest synchronization
wire sync_nreset;
dsync dsync(.dout (sync_nreset),
.clk (m_axi_aclk),
.din (m_axi_aresetn)
);
//Synchronous FIFO for read transactions
fifo_sync
#(
// parameters
.AW (5),
.DW (48))
fifo_readinfo_i
(
// outputs
.rd_data (readinfo_out[47:0]),
.rd_empty (),
.wr_full (readinfo_full),
// inputs
.clk (m_axi_aclk),
.reset (~sync_nreset),
.wr_data (readinfo_in[47:0]),
.wr_en (m_axi_arvalid & m_axi_arready),
.rd_en (m_axi_rready & m_axi_rvalid)
);
assign txrr_datamode[1:0] = readinfo_out[1:0];
assign txrr_ctrlmode[3:0] = readinfo_out[5:2];
assign txrr_dstaddr[31:0] = readinfo_out[40:9];
//#########################################################################
//Read address channel
//#########################################################################
assign m_axi_araddr[31:0] = rxrd_dstaddr[31:0];
assign m_axi_arsize[2:0] = {1'b0, rxrd_datamode[1:0]};
assign m_axi_arlen[7:0] = 8'd0;
assign m_axi_arvalid = rxrd_access & ~readinfo_full;
assign rxrd_wait = readinfo_full | ~m_axi_arready;
//#########################################################################
//Read response channel
//#########################################################################
assign m_axi_rready = ~txrr_wait; //pass through
always @( posedge m_axi_aclk )
if ( ~m_axi_aresetn )
m_axi_rdata_reg <= 'b0;
else
m_axi_rdata_reg <= m_axi_rdata;
always @( posedge m_axi_aclk )
if( ~m_axi_aresetn )
begin
txrr_data[31:0] <= 32'b0;
txrr_srcaddr[31:0] <= 32'b0;
txrr_access_reg <= 1'b0;
txrr_access <= 1'b0;
end
else
begin
txrr_access_reg <= m_axi_rready & m_axi_rvalid;
txrr_access <= txrr_access_reg;//added pipeline stage for data
// steer read data according to size & host address lsbs
//all data needs to be right aligned
//(this is due to the Epiphany right aligning all words)
case(readinfo_out[1:0])//datamode
2'd0: // byte read
case(readinfo_out[8:6])
3'd0: txrr_data[31:0] <= {24'b0,m_axi_rdata_reg[7:0]};
3'd1: txrr_data[31:0] <= {24'b0,m_axi_rdata_reg[15:8]};
3'd2: txrr_data[31:0] <= {24'b0,m_axi_rdata_reg[23:16]};
3'd3: txrr_data[31:0] <= {24'b0,m_axi_rdata_reg[31:24]};
3'd4: txrr_data[31:0] <= {24'b0,m_axi_rdata_reg[39:32]};
3'd5: txrr_data[31:0] <= {24'b0,m_axi_rdata_reg[47:40]};
3'd6: txrr_data[31:0] <= {24'b0,m_axi_rdata_reg[55:48]};
default: txrr_data[31:0] <= {24'b0,m_axi_rdata_reg[63:56]};
endcase
2'd1: // 16b hword
case( readinfo_out[8:7] )
2'd0: txrr_data[31:0] <= {16'b0,m_axi_rdata_reg[15:0]};
2'd1: txrr_data[31:0] <= {16'b0,m_axi_rdata_reg[31:16]};
2'd2: txrr_data[31:0] <= {16'b0,m_axi_rdata_reg[47:32]};
default: txrr_data[31:0] <= {16'b0,m_axi_rdata_reg[63:48]};
endcase
2'd2: // 32b word
if( readinfo_out[8] )
txrr_data[31:0] <= m_axi_rdata_reg[63:32];
else
txrr_data[31:0] <= m_axi_rdata_reg[31:0];
// 64b word already defined by defaults above
2'd3:
begin // 64b dword
txrr_data[31:0] <= m_axi_rdata_reg[31:0];
txrr_srcaddr[31:0] <= m_axi_rdata_reg[63:32];
end
endcase
end // else: !if( ~m_axi_aresetn )
endmodule // emaxi
// Local Variables:
// verilog-library-directories:("." "../../emesh/hdl" "../../memory/hdl" "../../common/hdl" )
// End: