1
0
mirror of https://github.com/aolofsson/oh.git synced 2025-01-17 20:02:53 +08:00
oh/elink/hdl/emaxi.v

431 lines
15 KiB
Coq
Raw Normal View History

/*
########################################################################
Epiphany eLink AXI Master Module
########################################################################
*/
module emaxi(/*autoarg*/
// Outputs
emwr_rd_en, emrq_rd_en, emrr_access, emrr_write, emrr_datamode,
emrr_ctrlmode, emrr_dstaddr, emrr_data, emrr_srcaddr, 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
emwr_access, emwr_write, emwr_datamode, emwr_ctrlmode,
emwr_dstaddr, emwr_data, emwr_srcaddr, emrq_access, emrq_write,
emrq_datamode, emrq_ctrlmode, emrq_dstaddr, emrq_data,
emrq_srcaddr, emrr_progfull, 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 IDW = 12;
// fifo read-master port, writes from rx
input emwr_access;
input emwr_write;
input [1:0] emwr_datamode;
input [3:0] emwr_ctrlmode;
input [31:0] emwr_dstaddr;
input [31:0] emwr_data;
input [31:0] emwr_srcaddr;
output emwr_rd_en; //read ptr update for fifo
// fifo read-master port; read requests from rx
input emrq_access;
input emrq_write;
input [1:0] emrq_datamode;
input [3:0] emrq_ctrlmode;
input [31:0] emrq_dstaddr;
input [31:0] emrq_data;
input [31:0] emrq_srcaddr;
output emrq_rd_en; //read ptr update for fifo
// fifo write-master port; read responses for etx
output emrr_access;
output emrr_write;
output [1:0] emrr_datamode;
output [3:0] emrr_ctrlmode;
output [31:0] emrr_dstaddr;
output [31:0] emrr_data;
output [31:0] emrr_srcaddr;
input emrr_progfull;
/*****************************/
/*axi */
/*****************************/
input m_axi_aclk; // global clock signal.
input m_axi_aresetn; // global reset singal.
//Write address channel
output [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 [1 : 0] 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 [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 [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 [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 [1 : 0] 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 [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
2015-03-24 15:12:53 -04:00
//registers
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 [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 emrr_access;
reg emrr_access_reg;
reg [31:0] emrr_data;
reg [31:0] emrr_srcaddr;
//wires
wire aw_go;
wire w_go;
wire readinfo_wren;
wire readinfo_rden;
wire readinfo_full;
wire [47:0] readinfo_out;
wire [47:0] readinfo_in;
//i/o connections. write address (aw)
assign m_axi_awburst[1:0] = 2'b01;
assign m_axi_awcache[3:0] = 4'b0010;//TODO??update value to 4'b0011 if coherent accesses to be used via the zynq acp port
assign m_axi_awprot[2:0] = 3'h0;
assign m_axi_awqos[3:0] = 4'h0;
assign m_axi_bready = 1'b1; //TODO? axi_bready, why constant
assign m_axi_arburst[1:0] = 2'b01;
assign m_axi_arcache[3:0] = 4'b0010;
assign m_axi_arprot[2:0] = 3'h0;
assign m_axi_arqos[3:0] = 4'h0;
//--------------------
//write address channel
//--------------------
assign aw_go = m_axi_awvalid & m_axi_awready;
assign w_go = m_axi_wvalid & m_axi_wready;
assign emwr_rd_en = ( emwr_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[31:0] <= 32'd0;
awlen_b[7:0] <= 8'd0;
awsize_b[2:0] <= 3'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 <= emwr_rd_en;
m_axi_awaddr[31:0] <= emwr_dstaddr[31:0];
m_axi_awlen[7:0] <= 8'b0;
m_axi_awsize[2:0] <= { 1'b0, emwr_datamode[1:0]};
end
end
if( emwr_rd_en & m_axi_awvalid & ~aw_go )
awvalid_b <= 1'b1;
else if( aw_go )
awvalid_b <= 1'b0;
//Pipeline stage
if( emwr_rd_en )
begin
awaddr_b[31:0] <= emwr_dstaddr[31:0];
awlen_b[7:0] <= 8'b0;
awsize_b[2:0] <= { 1'b0, emwr_datamode[1:0] };
end
end // else: !if(~m_axi_aresetn)
2015-03-24 15:12:53 -04:00
//--------------------
//write alignment circuit
//--------------------
always @*
case( emwr_datamode[1:0] )
2'd0: wdata_aligned[63:0] = { 8{emwr_data[7:0]}};
2'd1: wdata_aligned[63:0] = { 4{emwr_data[15:0]}};
2'd2: wdata_aligned[63:0] = { 2{emwr_data[31:0]}};
default: wdata_aligned[63:0] = { emwr_srcaddr[31:0], emwr_data[31:0]};
endcase
//TODO: Simplify logic below!!!!!
//Should include separate fields for address/data/datamode!!!!
always @*
begin
case(emwr_datamode[1:0])
2'd0: // byte
case(emwr_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(emwr_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(emwr_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 @ *
// generate the write-data signals
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: no bursts for now?
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 <= emwr_rd_en;//todo
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( emwr_rd_en & m_axi_wvalid & ~w_go )
wvalid_b <= 1'b1;
else if( w_go )
wvalid_b <= 1'b0;
if( emwr_rd_en )
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 handler
// elink read requests generate a transaction on the ar channel,
// buffer the src info to generate an elink write when the
// read data comes back.
//----------------------------
//TODO: Can we improve this??
assign readinfo_in[47:0] =
{
7'b0,
emrq_srcaddr[31:0],//40:9
emrq_dstaddr[2:0], //8:6
2015-04-14 11:44:31 -04:00
emrq_ctrlmode[3:0], //5:2
emrq_datamode[1:0]
};
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 (~m_axi_aresetn),
.wr_data (readinfo_in[47:0]),
.wr_en (emrq_rd_en),
.rd_en (readinfo_rden));
assign emrr_datamode[1:0] = readinfo_out[1:0];
assign emrr_ctrlmode[3:0] = readinfo_out[5:2];
assign emrr_dstaddr[31:0] = readinfo_out[40:9];
//----------------------------
// read address channel
//----------------------------
assign m_axi_araddr[31:0] = emrq_dstaddr[31:0];
assign m_axi_arsize[2:0] = {1'b0, emrq_datamode[1:0]};
assign m_axi_arlen[7:0] = 8'd0;
assign m_axi_arvalid = emrq_access & ~readinfo_full;
assign emrq_rd_en = m_axi_arvalid & m_axi_arready;
//--------------------------------
// read data (and response) channel
//--------------------------------
assign m_axi_rready = ~emrr_progfull;
assign readinfo_rden = ~emrr_progfull & m_axi_rvalid;
2015-04-14 11:44:31 -04:00
assign emrr_write = 1'b1;
always @( posedge m_axi_aclk )
if( ~m_axi_aresetn )
begin
emrr_data[31:0] <= 32'b0;
emrr_srcaddr[31:0] <= 32'b0;
emrr_access_reg <= 1'b0;
emrr_access <= 1'b0;
end
else
begin
emrr_access_reg <= m_axi_rready & m_axi_rvalid;
emrr_access <= emrr_access_reg;//added pipeline stage for data
emrr_srcaddr[31:0] <= m_axi_rdata[63:32];
// 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: emrr_data[7:0] <= m_axi_rdata[7:0];
3'd1: emrr_data[7:0] <= m_axi_rdata[15:8];
3'd2: emrr_data[7:0] <= m_axi_rdata[23:16];
3'd3: emrr_data[7:0] <= m_axi_rdata[31:24];
3'd4: emrr_data[7:0] <= m_axi_rdata[39:32];
3'd5: emrr_data[7:0] <= m_axi_rdata[47:40];
3'd6: emrr_data[7:0] <= m_axi_rdata[55:48];
default: emrr_data[7:0] <= m_axi_rdata[63:56];
endcase
2'd1: // 16b hword
case( readinfo_out[8:7] )
2'd0: emrr_data[15:0] <= m_axi_rdata[15:0];
2'd1: emrr_data[15:0] <= m_axi_rdata[31:16];
2'd2: emrr_data[15:0] <= m_axi_rdata[47:32];
default: emrr_data[15:0] <= m_axi_rdata[63:48];
endcase
2'd2: // 32b word
if( readinfo_out[8] )
emrr_data[31:0] <= m_axi_rdata[63:32];
else
emrr_data[31:0] <= m_axi_rdata[31:0];
// 64b word already defined by defaults above
2'd3: begin // 64b dword
emrr_data[31:0] <= m_axi_rdata[31:0];
end
endcase
end // else: !if( ~m_axi_aresetn )
endmodule
/*
copyright (c) 2014 adapteva, inc.
contributed by fred huettig <fred@adapteva.com>
contributed by andreas olofsson <andreas@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/>.
*/