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

More file organization

Adding some more utility functions
This commit is contained in:
aolofsson 2014-11-06 12:19:39 -05:00
parent 60182e52e3
commit b151bc90e1
13 changed files with 2995 additions and 71 deletions

View File

@ -1,71 +0,0 @@
module axi_memif (/*AUTOARG*/
// Outputs
s_axi_awready, s_axi_wready, s_axi_bresp, s_axi_bvalid,
s_axi_arready, s_axi_rdata, s_axi_rresp, s_axi_rvalid, mi_addr,
mi_access, mi_write, mi_data_in,
// Inputs
s_axi_aclk, s_axi_aresetn, s_axi_awaddr, s_axi_awprot,
s_axi_awvalid, s_axi_wdata, s_axi_wstrb, s_axi_wvalid,
s_axi_bready, s_axi_araddr, s_axi_arprot, s_axi_arvalid,
s_axi_rready, mi_data_out
);
parameter AW = 32; //axi addr width
parameter DW = 32; //axi data width
parameter SW = DW/8;//==ADW/8
parameter MAW = 6; //memory address width
parameter MDW = 32; //memory data width
/*****************************/
/*AXI SLAVE INTERFACE */
/*****************************/
//Global signals
input s_axi_aclk; //clock source for axi slave interfaces
input s_axi_aresetn; //synchronous reset signal, active low
//Write address channel
input [AW-1:0] s_axi_awaddr; //write address
input [2:0] s_axi_awprot; //protection type
input s_axi_awvalid; //write address valid
output s_axi_awready; //write address ready
//Write data channel
input [DW-1:0] s_axi_wdata; //write data
input [SW-1:0] s_axi_wstrb; //write strobes
input s_axi_wvalid; //write valid
output s_axi_wready; //write channel ready
//Buffered write response channel
input s_axi_bready; //write ready
output [1:0] s_axi_bresp; //write response
output s_axi_bvalid; //write response valid
//Read address channel
input [AW-1:0] s_axi_araddr; //read address
input [2:0] s_axi_arprot; //protection type
input s_axi_arvalid; //read address valid
output s_axi_arready; //read address ready
//Read data channel
output [DW-1:0] s_axi_rdata; //read data
output [1:0] s_axi_rresp; //read response
output s_axi_rvalid; //read valid
input s_axi_rready; //read ready
/*****************************/
/*MEORY INTERFACE */
/*****************************/
output [MAW-1:0] mi_addr;
output mi_access;
output mi_write;
output [MDW-1:0] mi_data_in;
input [MDW-1:0] mi_data_out;
//Dummy interface, need to instantiate IP!!!
//this will lock up AXI bus
endmodule // axi_memif

49
common/hdl/mux2.v Normal file
View File

@ -0,0 +1,49 @@
/*
Copyright (C) 2013 Adapteva, Inc.
Contributed by Andreas Olofsson <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/>.
*/
module mux2(/*AUTOARG*/
// Outputs
out,
// Inputs
in0, in1, sel0, sel1
);
parameter DW=99;
//data inputs
input [DW-1:0] in0;
input [DW-1:0] in1;
//select inputs
input sel0;
input sel1;
output [DW-1:0] out;
assign out[DW-1:0] = ({(DW){sel0}} & in0[DW-1:0] |
{(DW){sel1}} & in1[DW-1:0]);
//making sure that selects are really one hot
always @*
if((sel0+sel1>1) && ($time>0))
$display("ERROR>>Arbitration failure in cell %m");
endmodule // mux2

51
common/hdl/mux3.v Normal file
View File

@ -0,0 +1,51 @@
/*
Copyright (C) 2013 Adapteva, Inc.
Contributed by Andreas Olofsson <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/>.
*/
module mux3(/*AUTOARG*/
// Outputs
out,
// Inputs
in0, in1, in2, sel0, sel1, sel2
);
parameter DW=99;
//data inputs
input [DW-1:0] in0;
input [DW-1:0] in1;
input [DW-1:0] in2;
//select inputs
input sel0;
input sel1;
input sel2;
output [DW-1:0] out;
assign out[DW-1:0] = ({(DW){sel0}} & in0[DW-1:0] |
{(DW){sel1}} & in1[DW-1:0] |
{(DW){sel2}} & in2[DW-1:0]);
// synthesis translate_off
always @*
if((sel0+sel1+sel2>1) && ($time>0))
$display("ERROR>>Arbitration failure in cell %m");
// synthesis translate_on
endmodule // mux3

View File

@ -0,0 +1,22 @@
/*
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/>.
*/
module axi_elink_master(/*AUTOARG*/);
endmodule // elink_axi_slave

View File

@ -0,0 +1,22 @@
/*
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/>.
*/
module axi_elink_slave(/*AUTOARG*/);
endmodule // elink_axi_slave

436
elink/hdl/esys_regs.v Normal file
View File

@ -0,0 +1,436 @@
`define REG_ESYSRESET 6'h00
`define REG_ESYSCFGTX 6'h01
`define REG_ESYSCFGRX 6'h02
`define REG_ESYSCFGCLK 6'h03
`define REG_ESYSCOREID 6'h04
`define REG_ESYSVERSION 6'h05
`define REG_ESYSDATAIN 6'h06
`define REG_ESYSDATAOUT 6'h07
`define REG_ESYSRXMON0 6'h08
`define REG_ESYSRXMON1 6'h09
`define REG_ESYSRXMON2 6'h0A
`define REG_ESYSTXMON0 6'h0B
`define REG_ESYSTXMON1 6'h0C
`define REG_ESYSTXMON2 6'h0D
`define REG_ESYSTXMO2 6'h0E
`define REG_ESYSIRQSRC 6'h0F
`define REG_ESYSIRQDATA 6'h10
`define EVERSION 32'h00000000
/*
Copyright (C) 2013 Adapteva, Inc.
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/>.
*/
/*
########################################################################
EPIPHANY CONFIGURATION REGISTER
########################################################################
-------------------------------------------------------------
ESYSRESET ***Elink reset***
[0] 0 - elink in reset
1 - elink NOT in reset
-------------------------------------------------------------
ESYSCFGTX ***Elink transmitter configuration***
[0] 0 - link TX disable
1 - link TX enable
[1] 0 - normal pass through transaction mode
1 - mmu mode
[3:2] 00 - normal mode
01 - gpio mode
10 - reserved
11 - reserved
[7:4] Transmit control mode for eMesh
[9:8] 00 - No division, full speed
01 - Divide by 2
10 - Reserved
11 - Reserved
-------------------------------------------------------------
ESYSCFGRX ***Elink receiver configuration***
[0] 0 - link RX disable
1 - link RX enable
[1] 0 - normal transaction mode
1 - mmu mode
[3:2] 00 - normal mode
01 - GPIO mode (drive rd wait pins from registers)
10 - loopback mode (loops TX-->RX)
11 - reserved
[4] 0 - set monitor to count traffic
1 - set monitor to count congestion
-------------------------------------------------------------
ESYSCFGCLK ***Epiphany clock frequency setting***
[3:0] Output divider
0000 - CLock turned off
0001 - CLKIN/64
0010 - CLKIN/32
0011 - CLKIN/16
0100 - CLKIN/8
0101 - CLKIN/4
0110 - CLKIN/2
0111 - CLKIN/1
1XXX - RESERVED
[7:4] PLL settings (TBD)
-------------------------------------------------------------
ESYSCOREID ***CORE ID***
[5:0] Column ID-->default at powerup/reset
[11:6] Row ID
-------------------------------------------------------------
ESYSVERSION ***Version number (read only)***
[7:0] Revision #, incremented in each change (match git?)
[15:8] Type (features included in FPGA load, same board)
[23:16] Board platform #
[31:24] Generation # (needed??)
-------------------------------------------------------------
ESYSDATAIN ***Data on elink input pins
[7:0] rx_data[7:0]
[8] tx_frame
[9] tx_wait_rd
[10] tx_wait_wr
-------------------------------------------------------------
ESYSDATAOUT ***Data on eLink output pins
[7:0] tx_data[7:0]
[8] tx_fram
[9] rx_wait_rd
[10] rx_wait_wr
-------------------------------------------------------------
ESYSRXMON0 ***Counts RX master write transactions***
-------------------------------------------------------------
ESYSRXMON1 ***Counts RX master read transactions***
-------------------------------------------------------------
ESYSRXMON2 ***Counts RX slave read response transactions***
-------------------------------------------------------------
ESYSTXMON0 ***Counts TX slave write transactions***
-------------------------------------------------------------
ESYSTXMON1 ***Counts TX slave read transactions***
-------------------------------------------------------------
ESYSTXMON2 ***Counts TX master read response transactions***
-------------------------------------------------------------
ESYSIRQSRC ***Current IRQ FIFO entry (12 bits)
Read of entry will increment FIFO read pointer
-------------------------------------------------------------
ESYSIRQDATA ***Data associated with current IRQ FIFO entry
32 bits (should be read before src)
-------------------------------------------------------------
########################################################################
*/
module esys_regs (/*AUTOARG*/
// Outputs
data_out, esys_tx_enable, esys_tx_mmu_mode, esys_tx_gpio_mode,
esys_tx_ctrl_mode, esys_tx_clkdiv, esys_rx_enable,
esys_rx_mmu_mode, esys_rx_gpio_mode, esys_rx_loopback_mode,
esys_cclk_div, esys_coreid, esys_dataout, esys_irqsrc_read,
// Inputs
param_coreid, clk, hw_reset, access, write, addr, data_in,
erx_irq_fifo_src, erx_irq_fifo_data, erx_rdfifo_access,
erx_rdfifo_wait, erx_wrfifo_access, erx_wrfifo_wait,
erx_wbfifo_access, erx_wbfifo_wait, etx_rdfifo_access,
etx_rdfifo_wait, etx_wrfifo_access, etx_wrfifo_wait,
etx_wbfifo_access, etx_wbfifo_wait
);
//Register file parameters
/*
#####################################################################
COMPILE TIME PARAMETERS
######################################################################
*/
parameter EMONW = 32; //elink monitor register width
parameter EMAW = 12; //mmu table address width
parameter EDW = 32; //Epiphany native data width
parameter EAW = 32; //Epiphany native address width
parameter EIDW = 12; //Elink ID (row,column coordinate)
parameter RFAW = 5; //Number of registers=2^RFAW
/*****************************/
/*STATIC CONFIG SIGNALS */
/*****************************/
input [EIDW-1:0] param_coreid;
/*****************************/
/*SIMPLE MEMORY INTERFACE */
/*****************************/
input clk;
input hw_reset;
input access;
input write;
input [RFAW-1:0] addr;
input [31:0] data_in;
output [31:0] data_out;
/*****************************/
/*ELINK DATAPATH INPUTS */
/*****************************/
input [11:0] erx_irq_fifo_src;
input [11:0] erx_irq_fifo_data;
input erx_rdfifo_access;
input erx_rdfifo_wait;
input erx_wrfifo_access;
input erx_wrfifo_wait;
input erx_wbfifo_access;
input erx_wbfifo_wait;
input etx_rdfifo_access;
input etx_rdfifo_wait;
input etx_wrfifo_access;
input etx_wrfifo_wait;
input etx_wbfifo_access;
input etx_wbfifo_wait;
/*****************************/
/*ESYS CONTROL OUTPUTS */
/*****************************/
//tx
output esys_tx_enable; //enable signal for TX
output esys_tx_mmu_mode; //enables MMU on transnmit path
output esys_tx_gpio_mode; //forces TX output pins to constants
output [3:0] esys_tx_ctrl_mode; //value for emesh ctrlmode tag
output [3:0] esys_tx_clkdiv; //transmit clock divider
//rx
output esys_rx_enable; //enable signal for rx
output esys_rx_mmu_mode; //enables MMU on rx path
output esys_rx_gpio_mode; //forces rx wait pins to constants
output esys_rx_loopback_mode; //loops back tx to rx receiver (after serdes)
//cclk
output [3:0] esys_cclk_div; //cclk divider setting
output [3:0] esys_cclk_pllcfg; //pll configuration
//coreid
output [11:0] esys_coreid; //core-id of fpga elink
//gpio
output [11:0] esys_dataout; //data for elink outputs {rd_wait,wr_wait,frame,data[7:0}
//irq
output esys_irqsrc_read; //increments the irq fifo pointer
/*------------------------BODY CODE---------------------------------------*/
//registers
reg [9:0] esys_cfgtx_reg;
reg [4:0] esys_cfgrx_reg;
reg [7:0] esys_cfgclk_reg;
reg [11:0] esys_coreid_reg;
wire [31:0] esys_version_reg; //fixed read only constant
reg esys_reset_reg;
reg [11:0] esys_datain_reg;
reg [11:0] esys_dataout_reg;
wire [11:0] esys_irqsrc_reg;
wire [31:0] esys_irqdata_reg;
reg [31:0] data_out;
//wires
wire esys_read;
wire esys_write;
wire esys_reset_match;
wire esys_cfgtx_match;
wire esys_cfgrx_match;
wire esys_cfgclk_match;
wire esys_coreid_match;
wire esys_version_match;
wire esys_datain_match;
wire esys_dataout_match;
wire esys_rxmon0_match;
wire esys_rxmon1_match;
wire esys_rxmon2_match;
wire esys_txmon0_match;
wire esys_txmon1_match;
wire esys_txmon2_match;
wire esys_irqsrc_match;
wire esys_irqdata_match;
wire esys_regmux;
wire [31:0] esys_reg_mux;
/*****************************/
/*ADDRESS DECODE LOGIC */
/*****************************/
//read/write decode
assign esys_write = access & write;
assign esys_read = access & ~write;
//address match signals
assign esys_reset_match = addr[RFAW-1:0]==`REG_ESYSRESET;
assign esys_cfgtx_match = addr[RFAW-1:0]==`REG_ESYSCFGTX;
assign esys_cfgrx_match = addr[RFAW-1:0]==`REG_ESYSCFGRX;
assign esys_cfgclk_match = addr[RFAW-1:0]==`REG_ESYSCFGCLK;
assign esys_coreid_match = addr[RFAW-1:0]==`REG_ESYSCOREID;
assign esys_version_match = addr[RFAW-1:0]==`REG_ESYSVERSION;
assign esys_datain_match = addr[RFAW-1:0]==`REG_ESYSDATAIN;
assign esys_dataout_match = addr[RFAW-1:0]==`REG_ESYSDATAOUT;
assign esys_rxmon0_match = addr[RFAW-1:0]==`REG_ESYSRXMON0;
assign esys_rxmon1_match = addr[RFAW-1:0]==`REG_ESYSRXMON1;
assign esys_rxmon2_match = addr[RFAW-1:0]==`REG_ESYSRXMON2;
assign esys_txmon0_match = addr[RFAW-1:0]==`REG_ESYSTXMON0;
assign esys_txmon1_match = addr[RFAW-1:0]==`REG_ESYSTXMON1;
assign esys_txmon2_match = addr[RFAW-1:0]==`REG_ESYSTXMON2;
assign esys_irqsrc_match = addr[RFAW-1:0]==`REG_ESYSIRQSRC;
assign esys_irqdata_match = addr[RFAW-1:0]==`REG_ESYSIRQDATA;
//Write enables
assign esys_reset_write = esys_reset_match & esys_write;
assign esys_cfgtx_write = esys_cfgtx_match & esys_write;
assign esys_cfgrx_write = esys_cfgrx_match & esys_write;
assign esys_cfgclk_write = esys_cfgclk_match & esys_write;
assign esys_coreid_write = esys_coreid_match & esys_write;
assign esys_version_write = esys_version_match & esys_write;
assign esys_datain_write = esys_datain_match & esys_write;
assign esys_dataout_write = esys_dataout_match & esys_write;
assign esys_rxmon0_write = esys_rxmon0_match & esys_write;
assign esys_rxmon1_write = esys_rxmon1_match & esys_write;
assign esys_rxmon2_write = esys_rxmon2_match & esys_write;
assign esys_txmon0_write = esys_rxmon0_match & esys_write;
assign esys_txmon1_write = esys_rxmon1_match & esys_write;
assign esys_txmon2_write = esys_rxmon2_match & esys_write;
assign esys_irqsrc_write = esys_irqsrc_match & esys_write;
assign esys_irqdata_write = esys_irqdata_match & esys_write;
//###########################
//# ESYSCFGTX
//###########################
always @ (posedge clk)
if(hw_reset)
esys_cfgtx_reg[9:0] <= 10'b0;
else if (esys_cfgtx_write)
esys_cfgtx_reg[9:0] <= data_in[9:0];
assign esys_tx_enable = esys_cfgtx_reg[0];
assign esys_tx_mmu_mode = esys_cfgtx_reg[1];
assign esys_tx_gpio_mode = esys_cfgtx_reg[3:2]==2'b01;
assign esys_tx_ctrl_mode[3:0] = esys_cfgtx_reg[7:4];
assign esys_tx_clkdiv[3:0] = esys_cfgtx_reg[11:8];
//###########################
//# ESYSCFGRX
//###########################
always @ (posedge clk)
if(hw_reset)
esys_cfgrx_reg[4:0] <= 5'b0;
else if (esys_cfgrx_write)
esys_cfgrx_reg[4:0] <= data_in[4:0];
assign esys_rx_enable = esys_cfgrx_reg[0];
assign esys_tx_mmu_mode = esys_cfgrx_reg[1];
assign esys_rx_gpio_mode = esys_cfgrx_reg[3:2]==2'b01;
assign esys_rx_loopback_mode = esys_cfgrx_reg[3:2]==2'b10;
assign esys_rx_monitor_mode = esys_cfgrx_reg[4];
//###########################
//# ESYSCFGCLK
//###########################
always @ (posedge clk)
if(hw_reset)
esys_cfgclk_reg[7:0] <= 8'b0;
else if (esys_cfgclk_write)
esys_cfgclk_reg[7:0] <= data_in[7:0];
assign esys_cclk_div[3:0] = esys_cfgclk_reg[3:0];
assign esys_cclk_pllcfg[3:0] = esys_cfgclk_reg[7:4];
//###########################
//# ESYSCOREID
//###########################
always @ (posedge clk)
if(hw_reset)
esys_coreid_reg[EIDW-1:0] <= param_coreid[EIDW-1:0];
else if (esys_coreid_write)
esys_coreid_reg[EIDW-1:0] <= data_in[EIDW-1:0];
assign esys_coreid[EIDW-1:0] = esys_coreid_reg[EIDW-1:0];
//###########################
//# ESYSVERSION
//###########################
assign esys_version_reg[31:0] = `EVERSION;
//###########################
//# ESYSDATAIN
//###########################
always @ (posedge clk)
if(hw_reset)
esys_datain_reg[11:0] <= 12'b0;
else if (esys_datain_write)
esys_datain_reg[11:0] <= data_in[11:0];
else
esys_datain_reg[11:0] <= data_in[11:0];
//###########################
//# ESYSDATAOUT
//###########################
always @ (posedge clk)
if(hw_reset)
esys_dataout_reg[11:0] <= 12'b0;
else if (esys_dataout_write)
esys_dataout_reg[11:0] <= data_in[11:0];
assign esys_dataout[11:0] = esys_dataout_reg[11:0];
//###########################
//# ESYSRXMON0
//###########################
`ifdef USE_ESYS_MONITORS
//create module
//instantiate monitors, similar to timers
//inputs
`endif
//###########################
//# ESYSIRQSRC
//###########################
assign esys_irqsrc_read = esys_irqsrc_match & access;
assign esys_irqsrc_reg[11:0] = erx_irq_fifo_src[11:0];
//###########################
//# ESYSIRQDATA
//###########################
assign esys_irqdata_reg[31:0] = erx_irq_fifo_data[31:0];
//###########################
//# ESYSRESET
//###########################
always @ (posedge clk)
if(hw_reset)
esys_reset_reg <= 1'b0;
else if (esys_reset_write)
esys_reset_reg <= data_in[0];
assign esys_reset = esys_reset_reg;
//###############################
//# DATA READBACK MUX
//###############################
assign esys_reg_mux[31:0] = ({(32){esys_cfgtx_match}} & {18'b0,esys_cfgtx_reg[11:0]}) |
({(32){esys_cfgrx_match}} & {18'b0,esys_cfgrx_reg[11:0]}) |
({(32){esys_cfgclk_match}} & {24'b0,esys_cfgclk_reg[7:0]}) |
({(32){esys_coreid_match}} & {18'b0,esys_coreid_reg[11:0]}) |
({(32){esys_irqsrc_match}} & {18'b0,esys_irqsrc_reg[11:0]}) |
({(32){esys_version_match}} & esys_version_reg[31:0]) |
({(32){esys_datain_match}} & esys_datain_reg[31:0]) |
({(32){esys_dataout_match}} & esys_dataout_reg[31:0]) |
({(32){esys_rxmon0_match}} & esys_rxmon0_reg[31:0]) |
({(32){esys_rxmon1_match}} & esys_rxmon1_reg[31:0]) |
({(32){esys_rxmon2_match}} & esys_rxmon2_reg[31:0]) |
({(32){esys_txmon0_match}} & esys_txmon0_reg[31:0]) |
({(32){esys_txmon1_match}} & esys_txmon1_reg[31:0]) |
({(32){esys_txmon2_match}} & esys_txmon2_reg[31:0]) |
({(32){esys_irqdata_match}} & esys_irqdata_reg[31:0]);
//Pipelineing readback
always @ (posedge clk)
if(access)
data_out[31:0] <= esys_reg_mux[31:0];
endmodule // para_config

View File

@ -0,0 +1,269 @@
/*
File: ewrapper_io_rx_slow.v
This file is part of the Parallella Project .
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/>.
*/
module ewrapper_io_rx_slow (/*AUTOARG*/
// Outputs
CLK_DIV_OUT, DATA_IN_TO_DEVICE,
// Inputs
CLK_IN_P, CLK_IN_N, CLK_RESET, IO_RESET, DATA_IN_FROM_PINS_P,
DATA_IN_FROM_PINS_N, BITSLIP
);
//###########
//# INPUTS
//###########
input CLK_IN_P; // Differential clock from IOB
input CLK_IN_N;
input CLK_RESET;
input IO_RESET;
input [8:0] DATA_IN_FROM_PINS_P;
input [8:0] DATA_IN_FROM_PINS_N;
input BITSLIP;
//#############
//# OUTPUTS
//#############
output CLK_DIV_OUT; // Slow clock output
output [71:0] DATA_IN_TO_DEVICE;
//############
//# REGS
//############
reg [3:0] clk_edge;
reg rx_pedge_first;
reg [8:0] clk_even_reg;
reg [8:0] clk_odd_reg;
reg [8:0] clk0_even;
reg [8:0] clk1_even;
reg [8:0] clk2_even;
reg [8:0] clk3_even;
reg [8:0] clk0_odd;
reg [8:0] clk1_odd;
reg [8:0] clk2_odd;
reg [8:0] clk3_odd;
reg [71:0] rx_out_sync_pos;
reg rx_outclock_del_45;
reg rx_outclock_del_135;
reg [71:0] rx_out;
//############
//# WIRES
//############
wire reset;
wire rx_outclock;
wire rxi_lclk;
wire [71:0] rx_out_int;
wire [8:0] rx_in_t;
wire [8:0] rx_in;
wire [8:0] clk_even;
wire [8:0] clk_odd;
wire [8:0] iddr_q1;
wire [8:0] iddr_q2;
// Inversions for E16/E64 migration
`ifdef TARGET_E16
assign rx_in = rx_in_t;
assign clk_even = iddr_q1;
assign clk_odd = iddr_q2;
`define CLKEDGE_DDR "SAME_EDGE_PIPELINED"
`elsif TARGET_E64
assign rx_in = ~rx_in_t;
assign clk_even = iddr_q2;
assign clk_odd = iddr_q1;
`define CLKEDGE_DDR "SAME_EDGE"
`endif
/*AUTOINPUT*/
/*AUTOWIRE*/
assign reset = IO_RESET;
assign DATA_IN_TO_DEVICE[71:0] = rx_out[71:0];
assign CLK_DIV_OUT = rx_outclock;
//################################
//# Input Buffers Instantiation
//################################
IBUFDS
#(.DIFF_TERM ("TRUE"), // Differential termination
.IOSTANDARD (`IOSTD_ELINK))
ibufds_inst[0:8]
(.I (DATA_IN_FROM_PINS_P),
.IB (DATA_IN_FROM_PINS_N),
.O (rx_in_t));
//#####################
//# Clock Buffers
//#####################
IBUFGDS
#(.DIFF_TERM ("TRUE"), // Differential termination
.IOSTANDARD (`IOSTD_ELINK))
ibufds_clk_inst
(.I (CLK_IN_P),
.IB (CLK_IN_N),
.O (rxi_lclk));
// BUFR generates the slow clock
BUFR
#(.SIM_DEVICE("7SERIES"),
.BUFR_DIVIDE("4"))
clkout_buf_inst
(.O (rx_outclock),
.CE(1'b1),
.CLR(CLK_RESET),
.I (rxi_lclk));
//#################################
//# De-serialization Cycle Counter
//#################################
always @ (posedge rxi_lclk) begin
if(rx_pedge_first)
clk_edge <= 4'b1000;
else
clk_edge <= {clk_edge[2:0], clk_edge[3]};
end
//################################################################
//# Posedge Detection of the Slow Clock in the Fast Clock Domain
//################################################################
always @ (negedge rxi_lclk) begin
rx_outclock_del_45 <= rx_outclock;
rx_outclock_del_135 <= rx_outclock_del_45;
rx_pedge_first <= ~rx_outclock_del_45 & ~rx_outclock_del_135;
end
//#############################
//# De-serialization Output
//#############################
// Synchronizing the clocks (fast to slow)
always @ (posedge rxi_lclk or posedge reset)
if(reset)
rx_out_sync_pos <= 72'd0;
else
rx_out_sync_pos <= rx_out_int;
always @ (posedge rx_outclock or posedge reset)
if(reset)
rx_out <= 72'd0;
else
rx_out <= rx_out_sync_pos;
//#############################
//# IDDR instantiation
//#############################
IDDR #(
.DDR_CLK_EDGE (`CLKEDGE_DDR),
.SRTYPE ("ASYNC"))
iddr_inst[0:8] (
.Q1 (iddr_q1),
.Q2 (iddr_q2),
.C (rxi_lclk),
.CE (1'b1),
.D (rx_in),
.R (1'b0),
.S (1'b0));
//#############################
//# De-serialization Registers
//#############################
always @ (posedge rxi_lclk or posedge reset) begin
if(reset) begin
clk_even_reg <= 9'd0;
clk_odd_reg <= 9'd0;
clk0_even <= 9'd0;
clk0_odd <= 9'd0;
clk1_even <= 9'd0;
clk1_odd <= 9'd0;
clk2_even <= 9'd0;
clk2_odd <= 9'd0;
clk3_even <= 9'd0;
clk3_odd <= 9'd0;
end else begin
clk_even_reg <= clk_even;
clk_odd_reg <= clk_odd;
if(clk_edge[0]) begin
clk0_even <= clk_even_reg;
clk0_odd <= clk_odd_reg;
end
if(clk_edge[1]) begin
clk1_even <= clk_even_reg;
clk1_odd <= clk_odd_reg;
end
if(clk_edge[2]) begin
clk2_even <= clk_even_reg;
clk2_odd <= clk_odd_reg;
end
if(clk_edge[3]) begin
clk3_even <= clk_even_reg;
clk3_odd <= clk_odd_reg;
end
end // else: !if(reset)
end // always @ (posedge rxi_lclk or posedge reset)
//#####################################
//# De-serialization Data Construction
//#####################################
assign rx_out_int[71:64]={clk0_even[8],clk0_odd[8],clk1_even[8],clk1_odd[8],
clk2_even[8],clk2_odd[8],clk3_even[8],clk3_odd[8]};
assign rx_out_int[63:56]={clk0_even[7],clk0_odd[7],clk1_even[7],clk1_odd[7],
clk2_even[7],clk2_odd[7],clk3_even[7],clk3_odd[7]};
assign rx_out_int[55:48]={clk0_even[6],clk0_odd[6],clk1_even[6],clk1_odd[6],
clk2_even[6],clk2_odd[6],clk3_even[6],clk3_odd[6]};
assign rx_out_int[47:40]={clk0_even[5],clk0_odd[5],clk1_even[5],clk1_odd[5],
clk2_even[5],clk2_odd[5],clk3_even[5],clk3_odd[5]};
assign rx_out_int[39:32]={clk0_even[4],clk0_odd[4],clk1_even[4],clk1_odd[4],
clk2_even[4],clk2_odd[4],clk3_even[4],clk3_odd[4]};
assign rx_out_int[31:24]={clk0_even[3],clk0_odd[3],clk1_even[3],clk1_odd[3],
clk2_even[3],clk2_odd[3],clk3_even[3],clk3_odd[3]};
assign rx_out_int[23:16]={clk0_even[2],clk0_odd[2],clk1_even[2],clk1_odd[2],
clk2_even[2],clk2_odd[2],clk3_even[2],clk3_odd[2]};
assign rx_out_int[15:8] ={clk0_even[1],clk0_odd[1],clk1_even[1],clk1_odd[1],
clk2_even[1],clk2_odd[1],clk3_even[1],clk3_odd[1]};
assign rx_out_int[7:0] ={clk0_even[0],clk0_odd[0],clk1_even[0],clk1_odd[0],
clk2_even[0],clk2_odd[0],clk3_even[0],clk3_odd[0]};
endmodule // dv_io_rx

View File

@ -0,0 +1,246 @@
/*
File: ewrapper_io_tx_slow.v
This file is part of the Parallella Project .
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/>.
*/
module ewrapper_io_tx_slow
(/*AUTOARG*/
// Outputs
DATA_OUT_TO_PINS_P, DATA_OUT_TO_PINS_N, LCLK_OUT_TO_PINS_P,
LCLK_OUT_TO_PINS_N,
// Inputs
CLK_IN, CLK_IN_90, CLK_DIV_IN, CLK_RESET, IO_RESET, elink_disable,
DATA_OUT_FROM_DEVICE
);
//###########
//# INPUTS
//###########
input CLK_IN; // Fast clock input from PLL/MMCM
input CLK_IN_90; // Fast clock input with 90deg phase shift
input CLK_DIV_IN; // Slow clock input from PLL/MMCM
input CLK_RESET;
input IO_RESET;
input elink_disable;
input [71:0] DATA_OUT_FROM_DEVICE;
//#############
//# OUTPUTS
//#############
output [8:0] DATA_OUT_TO_PINS_P;
output [8:0] DATA_OUT_TO_PINS_N;
output LCLK_OUT_TO_PINS_P;
output LCLK_OUT_TO_PINS_N;
//############
//# REGS
//############
reg [1:0] clk_cnt;
reg tx_coreclock_del_45;
reg tx_coreclock_del_135;
reg [8:0] clk_even_reg;
reg [8:0] clk_odd_reg;
reg [71:0] tx_in_sync;
reg tx_pedge_first;
reg [3:0] cycle_sel;
//############
//# WIRES
//############
wire txo_lclk;
wire txo_lclk90;
wire tx_coreclock;
wire reset;
wire [8:0] clk_even;
wire [8:0] clk0_even;
wire [8:0] clk1_even;
wire [8:0] clk2_even;
wire [8:0] clk3_even;
wire [8:0] clk_odd;
wire [8:0] clk0_odd;
wire [8:0] clk1_odd;
wire [8:0] clk2_odd;
wire [8:0] clk3_odd;
wire [71:0] tx_in;
wire [8:0] tx_out;
wire tx_lclk_out;
wire [8:0] DATA_OUT_TO_PINS_P;
wire [8:0] DATA_OUT_TO_PINS_N;
wire LCLK_OUT_TO_PINS_P;
wire LCLK_OUT_TO_PINS_N;
// Inversions for E16/E64 migration
`ifdef TARGET_E16
wire elink_invert = 1'b0;
`elsif TARGET_E64
wire elink_invert = 1'b1;
`endif
/*AUTOINPUT*/
/*AUTOWIRE*/
assign reset = IO_RESET;
assign tx_in[71:0] = DATA_OUT_FROM_DEVICE[71:0];
assign txo_lclk = CLK_IN;
assign txo_lclk90 = CLK_IN_90;
assign tx_coreclock = CLK_DIV_IN;
//#################################################
//# Synchronize incoming data to fast clock domain
//#################################################
always @ (posedge txo_lclk)
if(tx_pedge_first)
tx_in_sync <= elink_invert ? ~tx_in : tx_in;
//################################
//# Output Buffers Instantiation
//################################
OBUFTDS #(.IOSTANDARD (`IOSTD_ELINK))
obufds_inst [8:0]
(.O (DATA_OUT_TO_PINS_P),
.OB (DATA_OUT_TO_PINS_N),
.I (tx_out),
.T ({1'b0, {8{elink_disable}}})); // Frame is always enabled
OBUFDS #(.IOSTANDARD (`IOSTD_ELINK))
obufds_lclk_inst
(.O (LCLK_OUT_TO_PINS_P),
.OB (LCLK_OUT_TO_PINS_N),
.I (tx_lclk_out));
//#############################
//# ODDR instantiation
//#############################
ODDR #(
.DDR_CLK_EDGE ("SAME_EDGE"),
.INIT (1'b0),
.SRTYPE ("ASYNC"))
oddr_inst [8:0]
(
.Q (tx_out),
.C (txo_lclk),
.CE (1'b1),
.D1 (clk_even_reg),
.D2 (clk_odd_reg),
.R (reset),
.S (1'b0));
ODDR #(
.DDR_CLK_EDGE ("SAME_EDGE"),
.INIT (1'b0),
.SRTYPE ("ASYNC"))
oddr_lclk_inst
(
.Q (tx_lclk_out),
.C (txo_lclk90),
.CE (1'b1),
.D1 (~elink_invert & ~elink_disable),
.D2 (elink_invert & ~elink_disable),
.R (CLK_RESET),
.S (1'b0));
//########################
//# Data Serialization
//########################
always @ (posedge txo_lclk) begin
clk_even_reg[8:0] <= clk_even[8:0];
clk_odd_reg[8:0] <= clk_odd[8:0];
end
mux4 #(18) mux4
(// Outputs
.out ({clk_even[8:0],clk_odd[8:0]}),
// Inputs
.in0 ({clk0_even[8:0],clk0_odd[8:0]}),
.sel0 (cycle_sel[0]),
.in1 ({clk1_even[8:0],clk1_odd[8:0]}),
.sel1 (cycle_sel[1]),
.in2 ({clk2_even[8:0],clk2_odd[8:0]}),
.sel2 (cycle_sel[2]),
.in3 ({clk3_even[8:0],clk3_odd[8:0]}),
.sel3 (cycle_sel[3]));
//#################################
//# Serialization Cycle Counter
//#################################
always @ (posedge txo_lclk) begin
tx_pedge_first <= tx_coreclock_del_45 & tx_coreclock_del_135;
cycle_sel[0] <= tx_pedge_first;
cycle_sel[3:1] <= cycle_sel[2:0];
end
//################################################################
//# Posedge Detection of the Slow Clock in the Fast Clock Domain
//################################################################
always @ (negedge txo_lclk) begin
tx_coreclock_del_45 <= tx_coreclock;
tx_coreclock_del_135 <= tx_coreclock_del_45;
end
//##################################
//# Data Alignment Channel-to-Byte
//##################################
assign clk0_even[8:0] ={tx_in_sync[71],tx_in_sync[63],tx_in_sync[55],
tx_in_sync[47],tx_in_sync[39],tx_in_sync[31],
tx_in_sync[23],tx_in_sync[15],tx_in_sync[7]};
assign clk0_odd[8:0] ={tx_in_sync[70],tx_in_sync[62],tx_in_sync[54],
tx_in_sync[46],tx_in_sync[38],tx_in_sync[30],
tx_in_sync[22],tx_in_sync[14],tx_in_sync[6]};
assign clk1_even[8:0] ={tx_in_sync[69],tx_in_sync[61],tx_in_sync[53],
tx_in_sync[45],tx_in_sync[37],tx_in_sync[29],
tx_in_sync[21],tx_in_sync[13],tx_in_sync[5]};
assign clk1_odd[8:0] ={tx_in_sync[68],tx_in_sync[60],tx_in_sync[52],
tx_in_sync[44],tx_in_sync[36],tx_in_sync[28],
tx_in_sync[20],tx_in_sync[12],tx_in_sync[4]};
assign clk2_even[8:0] ={tx_in_sync[67],tx_in_sync[59],tx_in_sync[51],
tx_in_sync[43],tx_in_sync[35],tx_in_sync[27],
tx_in_sync[19],tx_in_sync[11],tx_in_sync[3]};
assign clk2_odd[8:0] ={tx_in_sync[66],tx_in_sync[58],tx_in_sync[50],
tx_in_sync[42],tx_in_sync[34],tx_in_sync[26],
tx_in_sync[18],tx_in_sync[10],tx_in_sync[2]};
assign clk3_even[8:0] ={tx_in_sync[65],tx_in_sync[57],tx_in_sync[49],
tx_in_sync[41],tx_in_sync[33],tx_in_sync[25],
tx_in_sync[17],tx_in_sync[9], tx_in_sync[1]};
assign clk3_odd[8:0] ={tx_in_sync[64],tx_in_sync[56],tx_in_sync[48],
tx_in_sync[40],tx_in_sync[32],tx_in_sync[24],
tx_in_sync[16],tx_in_sync[8], tx_in_sync[0]};
endmodule // ewrapper_io_tx_slow

View File

@ -0,0 +1,198 @@
/*
File: ewrapper_link_receiver.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/>.
*/
module ewrapper_link_receiver (/*AUTOARG*/
// Outputs
rxo_wr_wait, rxo_rd_wait, emesh_clk_inb, emesh_access_inb,
emesh_write_inb, emesh_datamode_inb, emesh_ctrlmode_inb,
emesh_dstaddr_inb, emesh_srcaddr_inb, emesh_data_inb,
// Inputs
reset, rxi_data, rxi_lclk, rxi_frame, emesh_wr_wait_outb,
emesh_rd_wait_outb
);
//#########
//# INPUTS
//#########
input reset; //reset input
//# From the lvds-serdes
input [63:0] rxi_data; //Eight Parallel Byte words
input rxi_lclk; //receive clock (synchronized to the data)
input [7:0] rxi_frame; //Parallel frame signals representing
// 4 transmission clock cycles
//# From the emesh interface
input emesh_wr_wait_outb;
input emesh_rd_wait_outb;
//##########
//# OUTPUTS
//##########
//# To the transmitter
output rxo_wr_wait; //wait indicator
output rxo_rd_wait; //wait indicator
//# To the emesh interface
output emesh_clk_inb;
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;
/*AUTOINPUT*/
/*AUTOWIRE*/
//#########
//# Wires
//#########
wire emesh_wr_access_inb;
wire emesh_wr_write_inb;
wire [1:0] emesh_wr_datamode_inb;
wire [3:0] emesh_wr_ctrlmode_inb;
wire [31:0] emesh_wr_dstaddr_inb;
wire [31:0] emesh_wr_srcaddr_inb;
wire [31:0] emesh_wr_data_inb;
wire emesh_rd_access_inb;
wire emesh_rd_write_inb;
wire [1:0] emesh_rd_datamode_inb;
wire [3:0] emesh_rd_ctrlmode_inb;
wire [31:0] emesh_rd_dstaddr_inb;
wire [31:0] emesh_rd_srcaddr_inb;
wire [31:0] emesh_rd_data_inb;
wire select_write_tran;
wire wr_wait;
wire rd_wait;
wire emesh_access_tmp;
//###############
//# Emesh clock
//###############
assign emesh_clk_inb = rxi_lclk;
//######################################
//# Write-Read Transactions Arbitration
//# Write has a higher priority ALWAYS
//######################################
assign select_write_tran = emesh_wr_access_inb & ~emesh_wr_wait_outb;
assign emesh_access_inb = emesh_access_tmp & ~emesh_wr_wait_outb;
assign wr_wait = emesh_wr_wait_outb;
assign rd_wait = emesh_rd_access_inb & select_write_tran |
(emesh_wr_wait_outb | emesh_rd_wait_outb);
assign emesh_srcaddr_inb[31:0] =
select_write_tran ? emesh_wr_srcaddr_inb[31:0] :
emesh_rd_srcaddr_inb[31:0];
assign emesh_dstaddr_inb[31:0] =
select_write_tran ? emesh_wr_dstaddr_inb[31:0] :
emesh_rd_dstaddr_inb[31:0];
assign emesh_datamode_inb[1:0] =
select_write_tran ? emesh_wr_datamode_inb[1:0] :
emesh_rd_datamode_inb[1:0];
assign emesh_ctrlmode_inb[3:0] =
select_write_tran ? emesh_wr_ctrlmode_inb[3:0] :
emesh_rd_ctrlmode_inb[3:0];
assign emesh_data_inb[31:0] = select_write_tran ? emesh_wr_data_inb[31:0] :
emesh_rd_data_inb[31:0];
assign emesh_access_tmp = select_write_tran ? emesh_wr_access_inb :
emesh_rd_access_inb;
assign emesh_write_inb = select_write_tran ? emesh_wr_write_inb :
emesh_rd_write_inb;
//############################################
//# Write Transactions Receiver Instantiation
//############################################
/*ewrapper_link_rxi AUTO_TEMPLATE(
.rxi_rd (1'b0),
.emesh_wait_outb (wr_wait),
.rxo_wait (rxo_wr_wait),
.emesh_\(.*\) (emesh_wr_\1[]),
);
*/
ewrapper_link_rxi wr_rxi(/*AUTOINST*/
// Outputs
.rxo_wait (rxo_wr_wait), // Templated
.emesh_access_inb (emesh_wr_access_inb), // Templated
.emesh_write_inb (emesh_wr_write_inb), // Templated
.emesh_datamode_inb (emesh_wr_datamode_inb[1:0]), // Templated
.emesh_ctrlmode_inb (emesh_wr_ctrlmode_inb[3:0]), // Templated
.emesh_dstaddr_inb (emesh_wr_dstaddr_inb[31:0]), // Templated
.emesh_srcaddr_inb (emesh_wr_srcaddr_inb[31:0]), // Templated
.emesh_data_inb (emesh_wr_data_inb[31:0]), // Templated
// Inputs
.reset (reset),
.rxi_data (rxi_data[63:0]),
.rxi_lclk (rxi_lclk),
.rxi_frame (rxi_frame[7:0]),
.emesh_wait_outb (wr_wait), // Templated
.rxi_rd (1'b0)); // Templated
//############################################
//# Read Transactions Receiver Instantiation
//############################################
/*ewrapper_link_rxi AUTO_TEMPLATE(
.rxi_rd (1'b1),
.emesh_wait_outb (rd_wait),
.rxo_wait (rxo_rd_wait),
.emesh_\(.*\) (emesh_rd_\1[]),
);
*/
ewrapper_link_rxi rd_rxi(/*AUTOINST*/
// Outputs
.rxo_wait (rxo_rd_wait), // Templated
.emesh_access_inb (emesh_rd_access_inb), // Templated
.emesh_write_inb (emesh_rd_write_inb), // Templated
.emesh_datamode_inb (emesh_rd_datamode_inb[1:0]), // Templated
.emesh_ctrlmode_inb (emesh_rd_ctrlmode_inb[3:0]), // Templated
.emesh_dstaddr_inb (emesh_rd_dstaddr_inb[31:0]), // Templated
.emesh_srcaddr_inb (emesh_rd_srcaddr_inb[31:0]), // Templated
.emesh_data_inb (emesh_rd_data_inb[31:0]), // Templated
// Inputs
.reset (reset),
.rxi_data (rxi_data[63:0]),
.rxi_lclk (rxi_lclk),
.rxi_frame (rxi_frame[7:0]),
.emesh_wait_outb (rd_wait), // Templated
.rxi_rd (1'b1)); // Templated
endmodule // ewrapper_link_receiver

View File

@ -0,0 +1,624 @@
/*
File: ewrapper_link_rxi.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/>.
*/
module ewrapper_link_rxi (/*AUTOARG*/
// Outputs
rxo_wait, emesh_access_inb, emesh_write_inb, emesh_datamode_inb,
emesh_ctrlmode_inb, emesh_dstaddr_inb, emesh_srcaddr_inb,
emesh_data_inb,
// Inputs
reset, rxi_data, rxi_lclk, rxi_frame, emesh_wait_outb, rxi_rd
);
//#########
//# INPUTS
//#########
input reset; //reset input
//# From the lvds-serdes
input [63:0] rxi_data; //Eight Parallel Byte words
input rxi_lclk; //receive clock (synchronized to the data)
input [7:0] rxi_frame; //Parallel frame signals representing
// 4 transmission clock cycles
//# From the emesh interface
input emesh_wait_outb;
//# constant control (distinguish read and write instances)
input rxi_rd; //this is read transactions instance
//##########
//# OUTPUTS
//##########
//# To the transmitter
output rxo_wait; //wait indicator
//# 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;
/*AUTOINPUT*/
/*AUTOWIRE*/
//#########
//# Regs
//#########
reg rxi_frame_last;
reg [7:0] rxi_data_last;
reg [3:0] frame_reg;
reg [3:0] frame_reg_del;
reg [7:0] first_byte0;
reg [3:0] first_ctrlmode;
reg [31:0] first_dstaddr;
reg [1:0] first_datamode;
reg first_write;
reg first_access;
reg [15:0] first_data;
reg [3:0] frame_redge_first_reg;
reg new_tran_reg;
reg [7:0] second_byte0;
reg [3:0] second_ctrlmode;
reg [31:0] second_dstaddr;
reg [1:0] second_datamode;
reg second_write;
reg second_access;
reg [31:0] second_data;
reg [31:0] second_srcaddr;
reg [3:0] frame_redge_first_reg1;
reg burst_byte6;
reg burst_byte0;
reg burst_byte2;
reg burst_byte4;
reg [63:0] data_long;
reg [63:0] data_long_reg;
reg [103:0] fifo_in;
reg fifo_wr;
reg [103:0] fifo_out_reg;
reg emesh_access_inb;
reg rxo_wait;
reg add_latency;
reg [31:0] ref_dstaddr;
//#########
//# Wires
//#########
wire rxi_frame_76;
wire rxi_frame_54;
wire rxi_frame_32;
wire rxi_frame_10;
wire rxi_add_latency;
wire rxi_frame_07;
wire rxi_frame_65;
wire rxi_frame_43;
wire rxi_frame_21;
wire rxi_remove_latency;
wire [7:0] rxi_frame_aligned;
wire [63:0] rxi_data_aligned;
wire [3:0] frame_redge_first_int;
wire [3:0] frame_redge_first;
wire [7:0] rxi_byte7;
wire [7:0] rxi_byte6;
wire [7:0] rxi_byte5;
wire [7:0] rxi_byte4;
wire [7:0] rxi_byte3;
wire [7:0] rxi_byte2;
wire [7:0] rxi_byte1;
wire [7:0] rxi_byte0;
wire [63:0] rxi_data_long;
wire [7:0] data_byte7;
wire [7:0] data_byte6;
wire [7:0] data_byte5;
wire [7:0] data_byte4;
wire [7:0] data_byte3;
wire [7:0] data_byte2;
wire [7:0] data_byte1;
wire [7:0] data_byte0;
wire [7:0] tran_byte0_int;
wire [3:0] tran_ctrlmode_int0;
wire [31:0] tran_dstaddr_int0;
wire [1:0] tran_datamode_int0;
wire tran_write_int0;
wire tran_access_int0;
wire new_tran;
wire [31:0] tran_dstaddr_int1;
wire [1:0] tran_datamode_int1;
wire tran_write_int1;
wire tran_access_int1;
wire [31:0] tran_data_int1;
wire [31:0] tran_srcaddr_int1;
wire [31:0] tran_srcaddr_int2;
wire burst_start_byte6;
wire burst_start_byte0;
wire burst_start_byte2;
wire burst_start_byte4;
wire burst_stop_byte6;
wire burst_stop_byte0;
wire burst_stop_byte2;
wire burst_stop_byte4;
wire [63:0] burst_data;
wire byte0_inc8;
wire [31:0] burst_dstaddr;
wire [3:0] tran_ctrlmode;
wire [31:0] tran_dstaddr;
wire [1:0] tran_datamode;
wire tran_write;
wire tran_access;
wire [31:0] tran_data;
wire [31:0] tran_srcaddr;
wire [103:0] assembled_tran;
wire tran_ready;
wire [107:0] fifo_out;
wire fifo_rd;
wire fifo_empty;
wire mine_tran;
wire frame_redge_first_or20_reg1;
//# "add/remove latency" detection
assign rxi_frame_76 = ~rxi_frame[7] & rxi_frame[6];
assign rxi_frame_54 = ~rxi_frame[5] & rxi_frame[4];
assign rxi_frame_32 = ~rxi_frame[3] & rxi_frame[2];
assign rxi_frame_10 = ~rxi_frame[1] & rxi_frame[0];
assign rxi_add_latency = rxi_frame_76 | rxi_frame_54 |
rxi_frame_32 | rxi_frame_10;
assign rxi_frame_07 = ~rxi_frame_last & rxi_frame[7];
assign rxi_frame_65 = ~rxi_frame[6] & rxi_frame[5];
assign rxi_frame_43 = ~rxi_frame[4] & rxi_frame[3];
assign rxi_frame_21 = ~rxi_frame[2] & rxi_frame[1];
assign rxi_remove_latency = rxi_frame_07 | rxi_frame_65 |
rxi_frame_43 | rxi_frame_21;
always @ (posedge rxi_lclk or posedge reset)
if(reset)
add_latency <= 1'b0;
else if(rxi_add_latency)
add_latency <= 1'b1;
else if(rxi_remove_latency)
add_latency <= 1'b0;
//# frame alignment
always @ (posedge rxi_lclk or posedge reset)
if(reset)
rxi_frame_last <= 1'b0;
else
rxi_frame_last <= rxi_frame[0];
assign rxi_frame_aligned[7:0] = (rxi_add_latency | add_latency) ?
{rxi_frame_last,rxi_frame[7:1]} : rxi_frame[7:0];
//# data alignment
//# we should interleave the received data:
assign rxi_byte0[7:0] ={rxi_data[63],rxi_data[55],rxi_data[47],rxi_data[39],
rxi_data[31],rxi_data[23],rxi_data[15],rxi_data[7]};
assign rxi_byte1[7:0] ={rxi_data[62],rxi_data[54],rxi_data[46],rxi_data[38],
rxi_data[30],rxi_data[22],rxi_data[14],rxi_data[6]};
assign rxi_byte2[7:0] ={rxi_data[61],rxi_data[53],rxi_data[45],rxi_data[37],
rxi_data[29],rxi_data[21],rxi_data[13],rxi_data[5]};
assign rxi_byte3[7:0] ={rxi_data[60],rxi_data[52],rxi_data[44],rxi_data[36],
rxi_data[28],rxi_data[20],rxi_data[12],rxi_data[4]};
assign rxi_byte4[7:0] ={rxi_data[59],rxi_data[51],rxi_data[43],rxi_data[35],
rxi_data[27],rxi_data[19],rxi_data[11],rxi_data[3]};
assign rxi_byte5[7:0] ={rxi_data[58],rxi_data[50],rxi_data[42],rxi_data[34],
rxi_data[26],rxi_data[18],rxi_data[10],rxi_data[2]};
assign rxi_byte6[7:0] ={rxi_data[57],rxi_data[49],rxi_data[41],rxi_data[33],
rxi_data[25],rxi_data[17],rxi_data[9], rxi_data[1]};
assign rxi_byte7[7:0] ={rxi_data[56],rxi_data[48],rxi_data[40],rxi_data[32],
rxi_data[24],rxi_data[16],rxi_data[8], rxi_data[0]};
assign rxi_data_long[63:0] = {rxi_byte0[7:0],rxi_byte1[7:0],
rxi_byte2[7:0],rxi_byte3[7:0],
rxi_byte4[7:0],rxi_byte5[7:0],
rxi_byte6[7:0],rxi_byte7[7:0]};
always @ (posedge rxi_lclk)
rxi_data_last[7:0] <= rxi_byte7[7:0];
assign rxi_data_aligned[63:0] = (rxi_add_latency | add_latency) ?
{rxi_data_last[7:0],rxi_data_long[63:8]} :
rxi_data_long[63:0];
//################################
//# Main "After Alignment" Logic
//################################
//# frame
always @ (posedge rxi_lclk or posedge reset)
if(reset)
begin
frame_reg[3:0] <= 4'b0000;
frame_reg_del[3:0] <= 4'b0000;
end
else
begin
frame_reg[3:0] <= {rxi_frame_aligned[7],rxi_frame_aligned[5],
rxi_frame_aligned[3],rxi_frame_aligned[1]};
frame_reg_del[3:0] <= frame_reg[3:0];
end
//# data
always @ (posedge rxi_lclk)
data_long[63:0] <= rxi_data_aligned[63:0];
assign data_byte7[7:0] = data_long[7:0];
assign data_byte6[7:0] = data_long[15:8];
assign data_byte5[7:0] = data_long[23:16];
assign data_byte4[7:0] = data_long[31:24];
assign data_byte3[7:0] = data_long[39:32];
assign data_byte2[7:0] = data_long[47:40];
assign data_byte1[7:0] = data_long[55:48];
assign data_byte0[7:0] = data_long[63:56];
//# frame rising edge detection
assign frame_redge_first_int[3] = frame_reg[3] & ~frame_reg_del[0];
assign frame_redge_first_int[2] = frame_reg[2] & ~frame_reg[3];
assign frame_redge_first_int[1] = frame_reg[1] & ~frame_reg[2];
assign frame_redge_first_int[0] = frame_reg[0] & ~frame_reg[1];
//# First Cycle of the Transaction
//# new transactions is detected when the type of transaction matches
//# type of the instance (read or write) during the rising edge of frame
assign mine_tran = ~(tran_byte0_int[7] ^ rxi_rd);
assign frame_redge_first[3:0] =frame_redge_first_int[3:0] & {(4){mine_tran}};
assign new_tran = |(frame_redge_first[3:0]);
assign tran_byte0_int[7:0] = frame_redge_first_int[3] ? data_byte0[7:0] :
frame_redge_first_int[2] ? data_byte2[7:0] :
frame_redge_first_int[1] ? data_byte4[7:0] :
data_byte6[7:0];
assign tran_ctrlmode_int0[3:0] = frame_redge_first[3] ? data_byte1[7:4] :
frame_redge_first[2] ? data_byte3[7:4] :
frame_redge_first[1] ? data_byte5[7:4] :
data_byte7[7:4];
assign tran_dstaddr_int0[31:28] = frame_redge_first[3] ? data_byte1[3:0] :
frame_redge_first[2] ? data_byte3[3:0] :
frame_redge_first[1] ? data_byte5[3:0] :
data_byte7[3:0];
assign tran_dstaddr_int0[27:20] = frame_redge_first[3] ? data_byte2[7:0] :
frame_redge_first[2] ? data_byte4[7:0] :
data_byte6[7:0];
assign tran_dstaddr_int0[19:12] = frame_redge_first[3] ? data_byte3[7:0] :
frame_redge_first[2] ? data_byte5[7:0] :
data_byte7[7:0];
assign tran_dstaddr_int0[11:4] = frame_redge_first[3] ? data_byte4[7:0] :
data_byte6[7:0];
assign tran_dstaddr_int0[3:0] = frame_redge_first[3] ? data_byte5[7:4] :
data_byte7[7:4];
assign tran_datamode_int0[1:0] = frame_redge_first[3] ? data_byte5[3:2] :
data_byte7[3:2];
assign tran_write_int0 = frame_redge_first[3] ? data_byte5[1] :
data_byte7[1];
assign tran_access_int0 = frame_redge_first[3] ? data_byte5[0] :
data_byte7[0];
always @ (posedge rxi_lclk)
if (new_tran)
begin
first_byte0[7:0] <= tran_byte0_int[7:0];
first_ctrlmode[3:0] <= tran_ctrlmode_int0[3:0];
first_dstaddr[31:0] <= tran_dstaddr_int0[31:0];
first_datamode[1:0] <= tran_datamode_int0[1:0];
first_write <= tran_write_int0;
first_access <= tran_access_int0;
first_data[15:0] <= {data_byte6[7:0],data_byte7[7:0]};
end
//# Second Cycle of the Transaction
always @ (posedge rxi_lclk or posedge reset)
if (reset)
begin
frame_redge_first_reg[3:0] <= 4'b0000;
new_tran_reg <= 1'b0;
end
else
begin
frame_redge_first_reg[3:0] <= frame_redge_first[3:0];
new_tran_reg <= new_tran;
end
assign tran_dstaddr_int1[31:28] = first_dstaddr[31:28];
assign tran_dstaddr_int1[27:12] =
frame_redge_first_reg[0] ? {data_byte0[7:0],data_byte1[7:0]} :
first_dstaddr[27:12];
assign tran_dstaddr_int1[11:4] = frame_redge_first_reg[1] ? data_byte0[7:0] :
frame_redge_first_reg[0] ? data_byte2[7:0] :
first_dstaddr[11:4];
assign tran_dstaddr_int1[3:0] = frame_redge_first_reg[1] ? data_byte1[7:4] :
frame_redge_first_reg[0] ? data_byte3[7:4] :
first_dstaddr[3:0];
assign tran_datamode_int1[1:0] = frame_redge_first_reg[1] ? data_byte1[3:2] :
frame_redge_first_reg[0] ? data_byte3[3:2] :
first_datamode[1:0];
assign tran_write_int1 = frame_redge_first_reg[1] ? data_byte1[1] :
frame_redge_first_reg[0] ? data_byte3[1] :
first_write;
assign tran_access_int1 = frame_redge_first_reg[1] ? data_byte1[0] :
frame_redge_first_reg[0] ? data_byte3[0] :
first_access;
assign tran_data_int1[31:24] = frame_redge_first_reg[2] ? data_byte0[7:0] :
frame_redge_first_reg[1] ? data_byte2[7:0] :
frame_redge_first_reg[0] ? data_byte4[7:0] :
first_data[15:8];
assign tran_data_int1[23:16] = frame_redge_first_reg[2] ? data_byte1[7:0] :
frame_redge_first_reg[1] ? data_byte3[7:0] :
frame_redge_first_reg[0] ? data_byte5[7:0] :
first_data[7:0];
assign tran_data_int1[15:8] = frame_redge_first_reg[3] ? data_byte0[7:0] :
frame_redge_first_reg[2] ? data_byte2[7:0] :
frame_redge_first_reg[1] ? data_byte4[7:0] :
data_byte6[7:0];
assign tran_data_int1[7:0] = frame_redge_first_reg[3] ? data_byte1[7:0] :
frame_redge_first_reg[2] ? data_byte3[7:0] :
frame_redge_first_reg[1] ? data_byte5[7:0] :
data_byte7[7:0];
assign tran_srcaddr_int1[31:24] = frame_redge_first_reg[3] ? data_byte2[7:0]:
frame_redge_first_reg[2] ? data_byte4[7:0]:
data_byte6[7:0];
assign tran_srcaddr_int1[23:16] = frame_redge_first_reg[3] ? data_byte3[7:0]:
frame_redge_first_reg[2] ? data_byte5[7:0]:
data_byte7[7:0];
assign tran_srcaddr_int1[15:8] = frame_redge_first_reg[3] ? data_byte4[7:0] :
data_byte6[7:0];
assign tran_srcaddr_int1[7:0] = frame_redge_first_reg[3] ? data_byte5[7:0] :
data_byte7[7:0];
always @ (posedge rxi_lclk)
if (new_tran_reg)
begin
second_byte0[7:0] <= first_byte0[7:0];
second_ctrlmode[3:0] <= first_ctrlmode[3:0];
second_dstaddr[31:0] <= tran_dstaddr_int1[31:0];
second_datamode[1:0] <= tran_datamode_int1[1:0];
second_write <= tran_write_int1;
second_access <= tran_access_int1;
second_data[31:0] <= tran_data_int1[31:0];
second_srcaddr[31:0] <= tran_srcaddr_int1[31:0];
end // if (new_tran_reg)
//# Third Cycle of the Transaction
always @ (posedge rxi_lclk or posedge reset)
if (reset)
frame_redge_first_reg1[3:0] <= 4'b0000;
else
frame_redge_first_reg1[3:0] <= frame_redge_first_reg[3:0];
assign tran_srcaddr_int2[31:16] =
frame_redge_first_reg1[0] ? {data_byte0[7:0],data_byte1[7:0]} :
second_srcaddr[31:16];
assign tran_srcaddr_int2[15:8] = frame_redge_first_reg1[1] ? data_byte0[7:0]:
frame_redge_first_reg1[0] ? data_byte2[7:0]:
second_srcaddr[15:8];
assign tran_srcaddr_int2[7:0] = frame_redge_first_reg1[1] ? data_byte1[7:0]:
frame_redge_first_reg1[0] ? data_byte3[7:0]:
second_srcaddr[7:0];
//############################################
//# Data Collection of the Burst Transactions
//############################################
assign burst_start_byte6 = frame_redge_first_reg[3] & frame_reg[0];
assign burst_start_byte0 = frame_redge_first_reg1[2] & frame_reg[3];
assign burst_start_byte2 = frame_redge_first_reg1[1] & frame_reg[2];
assign burst_start_byte4 = frame_redge_first_reg1[0] & frame_reg[1];
assign burst_stop_byte6 = ~frame_reg[0] & frame_reg_del[0];
assign burst_stop_byte0 = ~frame_reg[3] & frame_reg_del[3];
assign burst_stop_byte2 = ~frame_reg[2] & frame_reg_del[2];
assign burst_stop_byte4 = ~frame_reg[1] & frame_reg_del[1];
always @ (posedge rxi_lclk or posedge reset)
if (reset)
burst_byte6 <= 1'b0;
else if(burst_start_byte6)
burst_byte6 <= 1'b1;
else if(burst_stop_byte6)
burst_byte6 <= 1'b0;
always @ (posedge rxi_lclk or posedge reset)
if (reset)
burst_byte0 <= 1'b0;
else if(burst_start_byte0)
burst_byte0 <= 1'b1;
else if(burst_stop_byte0)
burst_byte0 <= 1'b0;
always @ (posedge rxi_lclk or posedge reset)
if (reset)
burst_byte2 <= 1'b0;
else if(burst_start_byte2)
burst_byte2 <= 1'b1;
else if(burst_stop_byte2)
burst_byte2 <= 1'b0;
always @ (posedge rxi_lclk or posedge reset)
if (reset)
burst_byte4 <= 1'b0;
else if(burst_start_byte4)
burst_byte4 <= 1'b1;
else if(burst_stop_byte4)
burst_byte4 <= 1'b0;
always @ (posedge rxi_lclk)
data_long_reg[63:0] <= data_long[63:0];
assign burst_data[63:0] =
burst_byte6 ? {data_long_reg[15:0],data_long[63:16]} :
burst_byte0 ? data_long_reg[63:0] :
burst_byte2 ? {data_long_reg[47:0],data_long[63:48]} :
{data_long_reg[31:0],data_long[63:32]};
//###############################################
//# Address Calculation of the Burst Transaction
//###############################################
always @ (posedge rxi_lclk)
if (tran_ready)
ref_dstaddr[31:0] <= tran_dstaddr[31:0];
assign byte0_inc8 = ~second_byte0[2];
assign burst_dstaddr[31:0] = ref_dstaddr[31:0] +
{{(28){1'b0}},byte0_inc8,3'b000};
//##########################################
//# Assembled Transaction to enter the FIFO
//##########################################
assign frame_redge_first_or20_reg1 = |(frame_redge_first_reg1[2:0]);
assign tran_ctrlmode[3:0] = frame_redge_first_reg[3] ? first_ctrlmode[3:0] :
second_ctrlmode[3:0];
assign tran_datamode[1:0] = frame_redge_first_reg[3] ? tran_datamode_int1[1:0]:
second_datamode[1:0];
assign tran_write = frame_redge_first_reg[3] ? tran_write_int1 :
second_write;
assign tran_access = frame_redge_first_reg[3] ? tran_access_int1 :
second_access;
assign tran_srcaddr[31:0] = frame_redge_first_reg[3] ? tran_srcaddr_int1[31:0]:
frame_redge_first_or20_reg1 ? tran_srcaddr_int2[31:0]:
burst_data[31:0];
assign tran_data[31:0] = frame_redge_first_reg[3] ? tran_data_int1[31:0]:
frame_redge_first_or20_reg1 ? second_data[31:0]:
burst_data[63:32];
assign tran_dstaddr[31:0] = frame_redge_first_reg[3] ? tran_dstaddr_int1[31:0]:
frame_redge_first_or20_reg1 ? second_dstaddr[31:0]:
burst_dstaddr[31:0];
assign assembled_tran[103:0] = {tran_srcaddr[31:0],
tran_data[31:0],
tran_dstaddr[31:0],
tran_ctrlmode[3:0],
tran_datamode[1:0],
tran_write,
tran_access};
assign tran_ready = frame_redge_first_reg[3] | frame_redge_first_or20_reg1 |
burst_byte6 | burst_byte0 | burst_byte2 | burst_byte4;
//# The transaction is latched before entering FIFO to prevent timing
//# issues
always @ (posedge rxi_lclk)
fifo_in[103:0] <= assembled_tran[103:0];
always @ (posedge rxi_lclk or posedge reset)
if (reset)
fifo_wr <= 1'b0;
else
fifo_wr <= tran_ready;
//# Wait logic
always @ (posedge rxi_lclk or posedge reset)
if (reset)
rxo_wait <= 1'b0;
else if (emesh_wait_outb)
rxo_wait <= 1'b1;
else if (fifo_empty)
rxo_wait <= 1'b0;
assign emesh_srcaddr_inb[31:0] = fifo_out_reg[103:72];
assign emesh_data_inb[31:0] = fifo_out_reg[71:40];
assign emesh_dstaddr_inb[31:0] = fifo_out_reg[39:8];
assign emesh_ctrlmode_inb[3:0] = fifo_out_reg[7:4];
assign emesh_datamode_inb[1:0] = fifo_out_reg[3:2];
assign emesh_write_inb = fifo_out_reg[1];
always @ (posedge rxi_lclk or posedge reset)
if (reset)
emesh_access_inb <= 1'b0;
else if (~emesh_wait_outb)
emesh_access_inb <= fifo_rd;
always @ (posedge rxi_lclk)
if (~emesh_wait_outb)
fifo_out_reg[103:0] <= fifo_out[103:0];
assign fifo_rd = ~(fifo_empty | emesh_wait_outb);
/*fifo AUTO_TEMPLATE(.rd_clk (rxi_lclk),
.wr_clk (rxi_lclk),
.wr_data (fifo_in[103:0]),
.rd_data (fifo_out[103:0]),
.rd_fifo_empty (fifo_empty),
.wr_fifo_full (),
.wr_write (fifo_wr),
.rd_read (fifo_rd),
);
*/
//# We have 32 entries of 104 bits each
fifo #(.DW(104), .AW(5)) fifo_rxi(/*AUTOINST*/
// Outputs
.rd_data (fifo_out[103:0]), // Templated
.rd_fifo_empty (fifo_empty), // Templated
.wr_fifo_full (), // Templated
// Inputs
.reset (reset),
.wr_clk (rxi_lclk), // Templated
.rd_clk (rxi_lclk), // Templated
.wr_write (fifo_wr), // Templated
.wr_data (fifo_in[103:0]), // Templated
.rd_read (fifo_rd)); // Templated
endmodule // ewrapper_link_rxi

View File

@ -0,0 +1,464 @@
/*
File: ewrapper_link_top.v
This file is part of the Parallella Project
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/>.
*/
module ewrapper_link_top (/*AUTOARG*/
// Outputs
emesh_clk_inb, 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,
emesh_rd_wait_inb, txo_data_p, txo_data_n, txo_frame_p,
txo_frame_n, txo_lclk_p, txo_lclk_n, rxo_wr_wait_p, rxo_wr_wait_n,
rxo_rd_wait_p, rxo_rd_wait_n, rxi_cclk_p, rxi_cclk_n,
// Inputs
reset, clkin_100, elink_disable, elink_cclk_enb, elink_clk_div,
emesh_access_outb, emesh_write_outb, emesh_datamode_outb,
emesh_ctrlmode_outb, emesh_dstaddr_outb, emesh_srcaddr_outb,
emesh_data_outb, emesh_wr_wait_outb, emesh_rd_wait_outb,
rxi_data_p, rxi_data_n, rxi_frame_p, rxi_frame_n, rxi_lclk_p,
rxi_lclk_n, txi_wr_wait_p, txi_wr_wait_n, txi_rd_wait_p,
txi_rd_wait_n, burst_en
);
//#############
//# INPUTS
//#############
input reset;
input clkin_100;
//# Controls
input elink_disable;
input elink_cclk_enb;
input [1:0] elink_clk_div;
//# 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_wr_wait_outb;
input emesh_rd_wait_outb;
//# From the chip (hsmc port)
input [7:0] rxi_data_p;
input [7:0] rxi_data_n;
input rxi_frame_p;
input rxi_frame_n;
input rxi_lclk_p;
input rxi_lclk_n;
input txi_wr_wait_p;
input txi_wr_wait_n;
input txi_rd_wait_p;
input txi_rd_wait_n;
input burst_en; // Burst enable control
//###################
//# OUTPUTS
//###################
//# To the emesh interface
output emesh_clk_inb;
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;
output emesh_rd_wait_inb;
//# To the chip (hsmc port)
output [7:0] txo_data_p;
output [7:0] txo_data_n;
output txo_frame_p;
output txo_frame_n;
output txo_lclk_p;
output txo_lclk_n;
output rxo_wr_wait_p;
output rxo_wr_wait_n;
output rxo_rd_wait_p;
output rxo_rd_wait_n;
output rxi_cclk_p;
output rxi_cclk_n;
/*AUTOINPUT*/
/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
wire [71:0] tx_in; // From ctrl_tx of ewrapper_link_transmitter.v
// End of automatics
//############
//# REGS
//############
//############
//# WIRES
//############
wire [63:0] rxi_data_paral;
wire [7:0] rxi_frame_paral;
wire [8:0] rx_in_p;
wire [8:0] rx_in_n;
wire [71:0] rx_out;
wire rx_outclock;
wire [8:0] tx_out_p;
wire [8:0] tx_out_n;
wire rxi_cclk;
wire clk_fast_deg0;
wire clk_slow_deg0;
wire clk_fast_deg90;
wire rxo_wr_wait;
wire rxo_rd_wait;
wire txi_wr_wait;
wire txi_rd_wait;
// Inversions for E16/E64 migration
`ifdef TARGET_E16
wire elink_invert = 1'b0;
`elsif TARGET_E64
wire elink_invert = 1'b1;
`endif
//#######################
//# LVDS RECEIVER
//#######################
assign rxi_data_paral[63:0] = rx_out[63:0];
assign rxi_frame_paral[7:0] = rx_out[71:64];
assign rx_in_p[8:0] = {rxi_frame_p,rxi_data_p[7:0]};
assign rx_in_n[8:0] = {rxi_frame_n,rxi_data_n[7:0]};
ewrapper_link_receiver ctrl_rx
(.rxi_data (rxi_data_paral[63:0]),
.rxi_frame (rxi_frame_paral[7:0]),
.rxi_lclk (rx_outclock),
/*AUTOINST*/
// Outputs
.rxo_wr_wait (rxo_wr_wait),
.rxo_rd_wait (rxo_rd_wait),
.emesh_clk_inb (emesh_clk_inb),
.emesh_access_inb (emesh_access_inb),
.emesh_write_inb (emesh_write_inb),
.emesh_datamode_inb (emesh_datamode_inb[1:0]),
.emesh_ctrlmode_inb (emesh_ctrlmode_inb[3:0]),
.emesh_dstaddr_inb (emesh_dstaddr_inb[31:0]),
.emesh_srcaddr_inb (emesh_srcaddr_inb[31:0]),
.emesh_data_inb (emesh_data_inb[31:0]),
// Inputs
.reset (reset),
.emesh_wr_wait_outb (emesh_wr_wait_outb),
.emesh_rd_wait_outb (emesh_rd_wait_outb));
ewrapper_io_rx_slow io_rx
(// Outputs
.CLK_DIV_OUT (rx_outclock),
.DATA_IN_TO_DEVICE (rx_out[71:0]),
// Inputs
.CLK_IN_P (rxi_lclk_p),
.CLK_IN_N (rxi_lclk_n),
.CLK_RESET (reset),
.IO_RESET (reset),
.DATA_IN_FROM_PINS_P(rx_in_p[8:0]),
.DATA_IN_FROM_PINS_N(rx_in_n[8:0]),
.BITSLIP (1'b0));
// xilinx ISERDESE2 ip instantiation
// !!! Make sure that the DIFF_TERM attribute of IBUFDS and IBUFGDS
// !!! is set to TRUE inside ewrapper_io_rx.v
//ewrapper_io_rx io_rx(// Inputs
// .CLK_IN_P (rxi_lclk_p),
// .CLK_IN_N (rxi_lclk_n),
// .DATA_IN_FROM_PINS_P (rx_in_p[8:0]),
// .DATA_IN_FROM_PINS_N (rx_in_n[8:0]),
// .BITSLIP (1'b0),
// .CLK_RESET (reset),
// .IO_RESET (reset),
// // Outputs
// .DATA_IN_TO_DEVICE (rx_out[71:0]),
// .CLK_DIV_OUT (rx_outclock));
//#######################
//# LVDS TRANSMITTER
//#######################
assign txo_frame_p = tx_out_p[8];
assign txo_frame_n = tx_out_n[8];
assign txo_data_p[7:0] = tx_out_p[7:0];
assign txo_data_n[7:0] = tx_out_n[7:0];
ewrapper_link_transmitter ctrl_tx
(.txo_lclk (clk_slow_deg0),
/*AUTOINST*/
// Outputs
.emesh_wr_wait_inb (emesh_wr_wait_inb),
.emesh_rd_wait_inb (emesh_rd_wait_inb),
.tx_in (tx_in[71:0]),
// Inputs
.reset (reset),
.emesh_clk_inb (emesh_clk_inb),
.emesh_access_outb (emesh_access_outb),
.emesh_write_outb (emesh_write_outb),
.emesh_datamode_outb (emesh_datamode_outb[1:0]),
.emesh_ctrlmode_outb (emesh_ctrlmode_outb[3:0]),
.emesh_dstaddr_outb (emesh_dstaddr_outb[31:0]),
.emesh_srcaddr_outb (emesh_srcaddr_outb[31:0]),
.emesh_data_outb (emesh_data_outb[31:0]),
.txi_wr_wait (txi_wr_wait),
.txi_rd_wait (txi_rd_wait),
.burst_en (burst_en));
// xilinx MMCME2_ADV ip instantiation
io_clock_gen_600mhz io_clock_gen(// Inputs
.CLK_IN1 (clkin_100),
.RESET (reset),
// Outputs
.CLK_OUT1 (rxi_cclk),
.CLK_OUT2 (clk_fast_deg0),
.CLK_OUT3 (clk_slow_deg0),
.CLK_OUT4 (clk_fast_deg90),
.LOCKED ());
ewrapper_io_tx_slow io_tx(// Outputs
.DATA_OUT_TO_PINS_P(tx_out_p[8:0]),
.DATA_OUT_TO_PINS_N(tx_out_n[8:0]),
.LCLK_OUT_TO_PINS_P(txo_lclk_p),
.LCLK_OUT_TO_PINS_N(txo_lclk_n),
// Inputs
.CLK_IN (clk_fast_deg0),
.CLK_IN_90 (clk_fast_deg90),
.CLK_DIV_IN (clk_slow_deg0),
.CLK_RESET (reset),
.IO_RESET (reset),
.elink_disable (elink_disable),
.DATA_OUT_FROM_DEVICE(tx_in[71:0]));
// xilinx ISERDESE2 ip instantiation
//
// ewrapper_io_tx io_tx(// Inputs
// .CLK_IN (clk_fast_deg0),
// .CLK_DIV_IN (clk_slow_deg0),
// .DATA_OUT_FROM_DEVICE (tx_in[71:0]),
// .CLK_RESET (reset),
// .IO_RESET (reset),
// // Outputs
// .DATA_OUT_TO_PINS_P (tx_out_p[8:0]),
// .DATA_OUT_TO_PINS_N (tx_out_n[8:0]));
// io_clock_fwd io_clock_fwd(// Inputs
// .CLK_IN (clk_fast_deg45),
// .CLK_DIV_IN (clk_slow_deg45),
// .DATA_OUT_FROM_DEVICE (8'b01010101),
// .CLK_RESET (reset),
// .IO_RESET (reset),
// // Outputs
// .DATA_OUT_TO_PINS_P (txo_lclk_p),
// .DATA_OUT_TO_PINS_N (txo_lclk_n));
`ifdef FEATURE_CCLK_DIV
// Create adjustable (but fast) CCLK
wire rxi_cclk_out;
reg [8:1] cclk_pattern;
reg [1:0] clk_div_sync;
reg enb_sync;
always @ (posedge clk_slow_deg0) begin
clk_div_sync <= elink_clk_div;
enb_sync <= elink_cclk_enb;
if(enb_sync)
case(clk_div_sync)
2'b00: cclk_pattern <= 8'b10101010; // Divide by 1
2'b01: cclk_pattern <= 8'b11001100; // Divide by 2
2'b10: cclk_pattern <= 8'b11110000; // Divide by 4
default: cclk_pattern <= {8{~cclk_pattern[1]}}; // /8
endcase
else
cclk_pattern <= 8'b00000000;
end // always @ (posedge clk_slow_deg0)
OSERDESE2
#(
.DATA_RATE_OQ("DDR"), // DDR, SDR
.DATA_RATE_TQ("SDR"), // DDR, BUF, SDR
.DATA_WIDTH(8), // Parallel data width (2-8,10,14)
.INIT_OQ(1'b0), // Initial value of OQ output (1'b0,1'b1)
.INIT_TQ(1'b0), // Initial value of TQ output (1'b0,1'b1)
.SERDES_MODE("MASTER"), // MASTER, SLAVE
.SRVAL_OQ(1'b0), // OQ output value when SR is used (1'b0,1'b1)
.SRVAL_TQ(1'b0), // TQ output value when SR is used (1'b0,1'b1)
.TBYTE_CTL("FALSE"), // Enable tristate byte operation (FALSE, TRUE)
.TBYTE_SRC("FALSE"), // Tristate byte source (FALSE, TRUE)
.TRISTATE_WIDTH(1) // 3-state converter width (1,4)
) OSERDESE2_inst
(
.OFB(), // 1-bit output: Feedback path for data
.OQ(rxi_cclk_out), // 1-bit output: Data path output
.SHIFTOUT1(), // SHIFTOUTn: 1-bit (each): Data output expansion
.SHIFTOUT2(),
.TBYTEOUT(), // 1-bit output: Byte group tristate
.TFB(), // 1-bit output: 3-state control
.TQ(), // 1-bit output: 3-state control
.CLK(rxi_cclk), // 1-bit input: High speed clock
.CLKDIV(clk_slow_deg0), // 1-bit input: Divided clock
.D1(cclk_pattern[1]), // D1 - D8: Parallel data inputs (1-bit each)
.D2(cclk_pattern[2]),
.D3(cclk_pattern[3]),
.D4(cclk_pattern[4]),
.D5(cclk_pattern[5]),
.D6(cclk_pattern[6]),
.D7(cclk_pattern[7]),
.D8(cclk_pattern[8]),
.OCE(1'b1), // 1-bit input: Output data clock enable
.RST(reset), // 1-bit input: Reset
.SHIFTIN1(1'b0), // SHIFTINn: Data input expansion (1-bit each)
.SHIFTIN2(1'b0),
.T1(1'b0), // T1 - T4: Parallel 3-state inputs
.T2(1'b0),
.T3(1'b0),
.T4(1'b0),
.TBYTEIN(1'b0), // 1-bit input: Byte group tristate
.TCE(1'b0) // 1-bit input: 3-state clock enable
);
`else // Non-dividable CCLK
reg enb_sync;
always @ (posedge clk_slow_deg0)
enb_sync <= elink_cclk_enb;
// The following does not result in timing failures,
// but doesn't seem glitch-safe
assign rxi_cclk_out = rxi_cclk & enb_sync;
`endif
// xilinx OBUFDS instantiation
//
OBUFDS
#(.IOSTANDARD (`IOSTD_ELINK))
obufds_cclk_inst
(.O (rxi_cclk_p),
.OB (rxi_cclk_n),
.I (rxi_cclk_out));
OBUFDS
#(.IOSTANDARD (`IOSTD_ELINK))
rxo_wr_wait_inst
(.O (rxo_wr_wait_p),
.OB (rxo_wr_wait_n),
.I (rxo_wr_wait ^ elink_invert));
OBUFDS
#(.IOSTANDARD (`IOSTD_ELINK))
rxo_rd_wait_inst
(.O (rxo_rd_wait_p),
.OB (rxo_rd_wait_n),
.I (rxo_rd_wait ^ elink_invert));
// xilinx IBUFDS instantiation
wire [1:0] txi_wr_wait_buf;
IBUFDS_DIFF_OUT
#(.DIFF_TERM ("TRUE"), // Differential termination
.IOSTANDARD (`IOSTD_ELINK))
txi_wr_wait_inst
(.I (txi_wr_wait_p),
.IB (txi_wr_wait_n),
.O (txi_wr_wait_buf[0]),
.OB (txi_wr_wait_buf[1]));
assign txi_wr_wait = elink_invert ? txi_wr_wait_buf[1] : txi_wr_wait_buf[0];
// IBUFDS #(.DIFF_TERM ("TRUE"), // Differential termination
// .IOSTANDARD (`IOSTD_ELINK)) txo_rd_wait_inst (.I (txo_rd_wait_p),
// .IB (txo_rd_wait_n),
// .O (txo_rd_wait));
//No need for differential buffer
assign txi_rd_wait = txi_rd_wait_p ^ elink_invert;
//#################################
//# Chip Scope Instantiation
//#################################
`ifdef kCHIPSCOPE_EWRAPPER
wire [7:0] cs_ila2_TRIG3;
wire [7:0] cs_ila3_TRIG3;
wire [35:0] CONTROL0;
wire [35:0] CONTROL1;
wire [35:0] CONTROL2;
wire [35:0] CONTROL3;
assign cs_ila2_TRIG3[7:0] = {emesh_wr_wait_inb,
emesh_rd_wait_inb,
emesh_ctrlmode_outb[1:0],
emesh_datamode_outb[1:0],
emesh_write_outb,
emesh_access_outb};
assign cs_ila3_TRIG3[7:0] = {emesh_wr_wait_outb,
emesh_rd_wait_outb,
emesh_ctrlmode_inb[1:0],
emesh_datamode_inb[1:0],
emesh_write_inb,
emesh_access_inb};
cs_ila0 cs_ila0(.TRIG0 (tx_in[71:0]),
.CONTROL (CONTROL0[35:0]),
.CLK (clk_slow_deg0));
cs_ila0 cs_ila1(.TRIG0 (rx_out[71:0]),
.CONTROL (CONTROL1[35:0]),
.CLK (emesh_clk_inb));
cs_ila1 cs_ila2(.TRIG0 (emesh_dstaddr_outb[31:0]),
.TRIG1 (emesh_data_outb[31:0]),
.TRIG2 (emesh_srcaddr_outb[31:0]),
.TRIG3 (cs_ila2_TRIG3[7:0]),
.CONTROL (CONTROL2[35:0]),
.CLK (emesh_clk_inb));
cs_ila1 cs_ila3(.TRIG0 (emesh_dstaddr_inb[31:0]),
.TRIG1 (emesh_data_inb[31:0]),
.TRIG2 (emesh_srcaddr_inb[31:0]),
.TRIG3 (cs_ila3_TRIG3[7:0]),
.CONTROL (CONTROL3[35:0]),
.CLK (emesh_clk_inb));
cs_icon cs_icon(.CONTROL0 (CONTROL0[35:0]),
.CONTROL1 (CONTROL1[35:0]),
.CONTROL2 (CONTROL2[35:0]),
.CONTROL3 (CONTROL3[35:0]));
`endif // kCHIPSCOPE_EWRAPPER
endmodule // ewrapper_link_top

View File

@ -0,0 +1,232 @@
/*
File: ewrapper_link_transmitter.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/>.
*/
module ewrapper_link_transmitter(/*AUTOARG*/
// Outputs
emesh_wr_wait_inb, emesh_rd_wait_inb, tx_in,
// Inputs
reset, txo_lclk, emesh_clk_inb, emesh_access_outb,
emesh_write_outb, emesh_datamode_outb, emesh_ctrlmode_outb,
emesh_dstaddr_outb, emesh_srcaddr_outb, emesh_data_outb,
txi_wr_wait, txi_rd_wait, burst_en
);
//#########
//# INPUTS
//#########
input reset; //reset input
input txo_lclk; //transmitter clock
input emesh_clk_inb; // clock of the incoming emesh transaction
//# From the Emesh
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;
//# From the receiver
input txi_wr_wait; //wait indicator
input txi_rd_wait; //wait indicator
input burst_en; // Burst enable control
//##########
//# OUTPUTS
//##########
//# To the Emesh
output emesh_wr_wait_inb;
output emesh_rd_wait_inb;
//# To the lvds-serdes
output [71:0] tx_in;
/*AUTOINPUT*/
/*AUTOWIRE*/
//#########
//# Regs
//#########
reg wrfifo_rd_en;
//#########
//# Wires
//#########
wire [1:0] txi_wait;
wire [1:0] txi_wait_sync;
wire txi_wr_wait_sync;
wire txi_rd_wait_sync;
wire [103:0] fifo_in;
wire [103:0] fifo_out;
wire [107:0] wrfifo_out;
wire [107:0] rdfifo_out;
wire wrfifo_wait;
wire rdfifo_wait;
wire wrfifo_rd_int;
wire rdfifo_rd_int;
wire wrfifo_rd;
wire rdfifo_rd;
wire wrfifo_wr;
wire rdfifo_wr;
wire rdfifo_empty;
wire wrfifo_empty;
wire txo_emesh_wait;
wire txo_emesh_access;
wire txo_emesh_write;
wire [1:0] txo_emesh_datamode;
wire [3:0] txo_emesh_ctrlmode;
wire [31:0] txo_emesh_dstaddr;
wire [31:0] txo_emesh_srcaddr;
wire [31:0] txo_emesh_data;
//############################
//# txo_wait synchronization
//############################
assign txi_wait[1:0] = {txi_rd_wait,txi_wr_wait};
assign txi_wr_wait_sync = txi_wait_sync[0];
assign txi_rd_wait_sync = txi_wait_sync[1];
synchronizer #(.DW(2)) synchronizer(.out (txi_wait_sync[1:0]),
.in (txi_wait[1:0]),
.clk (txo_lclk),
.reset (reset));
//#####################################
//# lvds_link_txo instantiation
//#####################################
ewrapper_link_txo txo(/*AUTOINST*/
// Outputs
.txo_emesh_wait (txo_emesh_wait),
.tx_in (tx_in[71:0]),
// Inputs
.reset (reset),
.txo_lclk (txo_lclk),
.txo_emesh_access (txo_emesh_access),
.txo_emesh_write (txo_emesh_write),
.txo_emesh_datamode (txo_emesh_datamode[1:0]),
.txo_emesh_ctrlmode (txo_emesh_ctrlmode[3:0]),
.txo_emesh_dstaddr (txo_emesh_dstaddr[31:0]),
.txo_emesh_srcaddr (txo_emesh_srcaddr[31:0]),
.txo_emesh_data (txo_emesh_data[31:0]),
.burst_en (burst_en));
//#####################################
//# synchronization FIFOs (read/write)
//#####################################
//# FIFO writes
assign wrfifo_wr = emesh_access_outb & emesh_write_outb & ~emesh_wr_wait_inb;
assign rdfifo_wr = emesh_access_outb &~emesh_write_outb & ~emesh_rd_wait_inb;
//# FIFO reads
assign wrfifo_rd_int = ~(wrfifo_empty | txi_wr_wait_sync | txo_emesh_wait);
assign rdfifo_rd_int = ~(rdfifo_empty | txi_rd_wait_sync | txo_emesh_wait);
//# arbitration
always @ (posedge txo_lclk or posedge reset)
if(reset)
wrfifo_rd_en <= 1'b0;
else
wrfifo_rd_en <= ~wrfifo_rd_en;
assign wrfifo_rd = wrfifo_rd_int & ( wrfifo_rd_en | ~rdfifo_rd_int);
assign rdfifo_rd = rdfifo_rd_int & (~wrfifo_rd_en | ~wrfifo_rd_int);
//# FIFO input
assign fifo_in[103:0] = {emesh_srcaddr_outb[31:0],
emesh_data_outb[31:0],
emesh_dstaddr_outb[31:0],
emesh_ctrlmode_outb[3:0],
emesh_datamode_outb[1:0],
emesh_write_outb,
emesh_access_outb};
//# FIFO output
assign fifo_out[103:0] = wrfifo_rd ? wrfifo_out[103:0] : rdfifo_out[103:0];
assign txo_emesh_access = wrfifo_rd | rdfifo_rd;
assign txo_emesh_write = fifo_out[1];
assign txo_emesh_datamode[1:0] = fifo_out[3:2];
assign txo_emesh_ctrlmode[3:0] = fifo_out[7:4];
assign txo_emesh_dstaddr[31:0] = fifo_out[39:8];
assign txo_emesh_data[31:0] = fifo_out[71:40];
assign txo_emesh_srcaddr[31:0] = fifo_out[103:72];
/*fifo AUTO_TEMPLATE(.rd_clk (txo_lclk),
.wr_clk (emesh_clk_inb),
.wr_data (fifo_in[103:0]),
.rd_data (wrfifo_out[103:0]),
.rd_fifo_empty (wrfifo_empty),
.wr_fifo_full (emesh_wr_wait_inb),
.wr_write (wrfifo_wr),
.rd_read (wrfifo_rd),
);
*/
//# We have 4 entries of 104 bits each
fifo #(.DW(104), .AW(2)) wrfifo_txo(/*AUTOINST*/
// Outputs
.rd_data (wrfifo_out[103:0]), // Templated
.rd_fifo_empty (wrfifo_empty), // Templated
.wr_fifo_full (emesh_wr_wait_inb), // Templated
// Inputs
.reset (reset),
.wr_clk (emesh_clk_inb), // Templated
.rd_clk (txo_lclk), // Templated
.wr_write (wrfifo_wr), // Templated
.wr_data (fifo_in[103:0]), // Templated
.rd_read (wrfifo_rd)); // Templated
/*fifo AUTO_TEMPLATE(.rd_clk (txo_lclk),
.wr_clk (emesh_clk_inb),
.wr_data (fifo_in[103:0]),
.rd_data (rdfifo_out[103:0]),
.rd_fifo_empty (rdfifo_empty),
.wr_fifo_full (emesh_rd_wait_inb),
.wr_write (rdfifo_wr),
.rd_read (rdfifo_rd),
);
*/
//# We have 4 entries of 104 bits each
fifo #(.DW(104), .AW(2)) rdfifo_txo(/*AUTOINST*/
// Outputs
.rd_data (rdfifo_out[103:0]), // Templated
.rd_fifo_empty (rdfifo_empty), // Templated
.wr_fifo_full (emesh_rd_wait_inb), // Templated
// Inputs
.reset (reset),
.wr_clk (emesh_clk_inb), // Templated
.rd_clk (txo_lclk), // Templated
.wr_write (rdfifo_wr), // Templated
.wr_data (fifo_in[103:0]), // Templated
.rd_read (rdfifo_rd)); // Templated
endmodule // ewrapper_link_transmitter

View File

@ -0,0 +1,382 @@
/*
File: ewrapper_link_txo.v
This file is part of the Parallella Project
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/>.
*/
module ewrapper_link_txo(/*AUTOARG*/
// Outputs
txo_emesh_wait, tx_in,
// Inputs
reset, txo_lclk, txo_emesh_access, txo_emesh_write,
txo_emesh_datamode, txo_emesh_ctrlmode, txo_emesh_dstaddr,
txo_emesh_srcaddr, txo_emesh_data, burst_en
);
//#########
//# INPUTS
//#########
input reset; //reset input
input txo_lclk; //transmitter clock
//# From the Emesh
input txo_emesh_access;
input txo_emesh_write;
input [1:0] txo_emesh_datamode;
input [3:0] txo_emesh_ctrlmode;
input [31:0] txo_emesh_dstaddr;
input [31:0] txo_emesh_srcaddr;
input [31:0] txo_emesh_data;
input burst_en; // Burst enable control
//##########
//# OUTPUTS
//##########
//# To the Emesh
output txo_emesh_wait;
//# To the lvds-serdes
// output [63:0] txo_data; //Eight Parallel Byte words
// output [7:0] txo_frame; //Parallel frame signals representing
// // 4 transmission clock cycles
output [71:0] tx_in;
/*AUTOINPUT*/
/*AUTOWIRE*/
//#########
//# Regs
//#########
reg shadow_access;
reg shadow_write;
reg [1:0] shadow_datamode;
reg [3:0] shadow_ctrlmode;
reg [31:0] shadow_dstaddr;
reg [31:0] shadow_srcaddr;
reg [31:0] shadow_data;
reg cycle1_access;
reg cycle1_write;
reg [1:0] cycle1_datamode;
reg [3:0] cycle1_ctrlmode;
reg [31:0] cycle1_dstaddr;
reg [31:0] cycle1_srcaddr;
reg [31:0] cycle1_data;
reg cycle2_access;
reg [31:0] cycle2_dstaddr;
reg [31:0] cycle2_srcaddr;
reg [31:0] cycle2_data;
reg cycle2_dbl;
reg [31:0] cycle2_dstaddr_inc8;
reg byte0_inc0;
reg txo_emesh_wait;
//reg [7:0] txo_frame;
//reg [63:0] txo_data;
reg [71:0] tx_in;
reg cycle1_frame_bit_del;
reg inc0_match_del;
//#########
//# Wires
//#########
wire emesh_access;
wire emesh_write;
wire [1:0] emesh_datamode;
wire [3:0] emesh_ctrlmode;
wire [31:0] emesh_dstaddr;
wire [31:0] emesh_srcaddr;
wire [31:0] emesh_data;
wire cycle1_dbl; // Cycle1 has a valid double write transaction
wire [31:0] cycle1_dstaddr_inc8;
wire inc8_match;
wire inc0_match;
wire burst_tran;
wire emesh_wait;
wire cycle1_frame_bit;
wire cycle2_frame_bit;
wire [7:0] cycle1_frame;
wire [7:0] cycle2_frame;
wire [7:0] txo_frame_int;
wire [7:0] tran_byte0;
wire [63:0] cycle1_data_long;
wire [63:0] cycle2_data_long;
wire [63:0] data_long;
wire [7:0] channel0;
wire [7:0] channel1;
wire [7:0] channel2;
wire [7:0] channel3;
wire [7:0] channel4;
wire [7:0] channel5;
wire [7:0] channel6;
wire [7:0] channel7;
// wire [8:0] channel0;
// wire [8:0] channel1;
// wire [8:0] channel2;
// wire [8:0] channel3;
// wire [8:0] channel4;
// wire [8:0] channel5;
// wire [8:0] channel6;
// wire [8:0] channel7;
// wire [63:0] txo_data_int;
wire [71:0] txo_data_int;
//##########################
//# Latch Emesh Transaction
//##########################
always @ (posedge txo_lclk or posedge reset)
if (reset)
shadow_access <= 1'b0;
else if(~txo_emesh_wait)
shadow_access <= txo_emesh_access;
always @ (posedge txo_lclk)
if (~txo_emesh_wait)
begin
shadow_write <= txo_emesh_write;
shadow_datamode[1:0] <= txo_emesh_datamode[1:0];
shadow_ctrlmode[3:0] <= txo_emesh_ctrlmode[3:0];
shadow_dstaddr[31:0] <= txo_emesh_dstaddr[31:0];
shadow_srcaddr[31:0] <= txo_emesh_srcaddr[31:0];
shadow_data[31:0] <= txo_emesh_data[31:0];
end
assign emesh_access = txo_emesh_wait ? shadow_access : txo_emesh_access;
assign emesh_write = txo_emesh_wait ? shadow_write : txo_emesh_write;
assign emesh_datamode[1:0] = txo_emesh_wait ? shadow_datamode[1:0] :
txo_emesh_datamode[1:0];
assign emesh_ctrlmode[3:0] = txo_emesh_wait ? shadow_ctrlmode[3:0] :
txo_emesh_ctrlmode[3:0];
assign emesh_dstaddr[31:0] = txo_emesh_wait ? shadow_dstaddr[31:0] :
txo_emesh_dstaddr[31:0];
assign emesh_srcaddr[31:0] = txo_emesh_wait ? shadow_srcaddr[31:0] :
txo_emesh_srcaddr[31:0];
assign emesh_data[31:0] = txo_emesh_wait ? shadow_data[31:0] :
txo_emesh_data[31:0];
//# Wait indication for emesh
assign emesh_wait = cycle1_access & cycle2_access & ~burst_tran;
always @ (posedge txo_lclk or posedge reset)
if (reset)
txo_emesh_wait <= 1'b0;
else
txo_emesh_wait <= emesh_wait;
//# First Cycle of the transaction to LVDS-SERDES
always @ (posedge txo_lclk or posedge reset)
if (reset)
cycle1_access <= 1'b0;
else if(~emesh_wait)
cycle1_access <= emesh_access;
always @ (posedge txo_lclk)
if (~emesh_wait)
begin
cycle1_write <= emesh_write;
cycle1_datamode[1:0] <= emesh_datamode[1:0];
cycle1_ctrlmode[3:0] <= emesh_ctrlmode[3:0];
cycle1_dstaddr[31:0] <= emesh_dstaddr[31:0];
cycle1_srcaddr[31:0] <= emesh_srcaddr[31:0];
cycle1_data[31:0] <= emesh_data[31:0];
end
//# Second Cycle of the transaction to LVDS-SERDES (never gets stalled)
always @ (posedge txo_lclk or posedge reset)
if (reset)
cycle2_access <= 1'b0;
else if(emesh_wait)
cycle2_access <= 1'b0;
else
cycle2_access <= cycle1_access;
always @ (posedge txo_lclk)
begin
cycle2_dstaddr[31:0] <= cycle1_dstaddr[31:0];
cycle2_srcaddr[31:0] <= cycle1_srcaddr[31:0];
cycle2_data[31:0] <= cycle1_data[31:0];
cycle2_dbl <= cycle1_dbl;
cycle2_dstaddr_inc8[31:0] <= cycle1_dstaddr_inc8[31:0];
end
always @ (posedge txo_lclk or posedge reset)
if(reset)
begin
cycle1_frame_bit_del <= 1'b0;
inc0_match_del <= 1'b0;
end
else
begin
cycle1_frame_bit_del <= cycle1_frame_bit;
inc0_match_del <= inc0_match;
end
//# keeping track of the address increment mode of burst transaction
always @ (posedge txo_lclk or posedge reset)
if(reset)
byte0_inc0 <= 1'b0;
else if(cycle1_frame_bit_del)
byte0_inc0 <= inc0_match_del;
//# transaction type + transaction address comparison
assign cycle1_dbl = cycle1_access & cycle1_write &
(&(cycle1_datamode[1:0])) & ~(|(cycle1_ctrlmode[3:0]));
assign cycle1_dstaddr_inc8[31:0] = cycle1_dstaddr[31:0] +
{{(28){1'b0}},4'b1000};
assign inc8_match = cycle1_dbl & cycle2_dbl &
(cycle1_dstaddr[31:0] == cycle2_dstaddr_inc8[31:0]);
assign inc0_match = cycle1_dbl & cycle2_dbl &
(cycle1_dstaddr[31:0] == cycle2_dstaddr[31:0]);
//# this is burst transaction
assign burst_tran = burst_en &
cycle1_dbl & cycle2_dbl &
((inc8_match & ~byte0_inc0) | // address match
(inc0_match & byte0_inc0));
assign tran_byte0[7:0] = {~cycle1_write,4'b0000,byte0_inc0,2'b00};
//###############################################
//# Actual Interface with LVDS-SERDES (easy :-) )
//###############################################
assign cycle1_frame_bit = cycle1_access & ~cycle2_access;
assign cycle2_frame_bit = cycle2_access;
assign cycle1_frame[7:0] = {2'b00,{(6){cycle1_frame_bit}}};
assign cycle2_frame[7:0] = {(8){cycle2_frame_bit}};
assign txo_frame_int[7:0] = cycle1_frame[7:0] | cycle2_frame[7:0];
assign cycle1_data_long[63:0] = {{(8){1'b0}},
{(8){1'b0}},
tran_byte0[7:0],
cycle1_ctrlmode[3:0],cycle1_dstaddr[31:28],
cycle1_dstaddr[27:20],
cycle1_dstaddr[19:12],
cycle1_dstaddr[11:4],
cycle1_dstaddr[3:0],cycle1_datamode[1:0],cycle1_write,cycle1_access};
assign cycle2_data_long[63:0] = {cycle2_data[31:0],cycle2_srcaddr[31:0]};
assign data_long[63:0] = cycle2_access ? cycle2_data_long[63:0] :
cycle1_data_long[63:0];
//# data per-channel arrangement
assign channel0[7:0] = {data_long[56],data_long[48],
data_long[40],data_long[32],
data_long[24],data_long[16],
data_long[8], data_long[0]
};
// assign channel0[8:0] = {txo_frame_int[0],data_long[7:0]};
assign channel1[7:0] = {data_long[57],data_long[49],
data_long[41],data_long[33],
data_long[25],data_long[17],
data_long[9], data_long[1]
};
// assign channel1[8:0] = {txo_frame_int[1],data_long[15:8]};
assign channel2[7:0] = {data_long[58],data_long[50],
data_long[42],data_long[34],
data_long[26],data_long[18],
data_long[10],data_long[2]
};
// assign channel2[8:0] = {txo_frame_int[2],data_long[23:16]};
assign channel3[7:0] = {data_long[59],data_long[51],
data_long[43],data_long[35],
data_long[27],data_long[19],
data_long[11],data_long[3]
};
// assign channel3[8:0] = {txo_frame_int[3],data_long[31:24]};
assign channel4[7:0] = {data_long[60],data_long[52],
data_long[44],data_long[36],
data_long[28],data_long[20],
data_long[12],data_long[4]
};
// assign channel4[8:0] = {txo_frame_int[4],data_long[39:32]};
assign channel5[7:0] = {data_long[61],data_long[53],
data_long[45],data_long[37],
data_long[29],data_long[21],
data_long[13],data_long[5]
};
// assign channel5[8:0] = {txo_frame_int[5],data_long[47:40]};
assign channel6[7:0] = {data_long[62],data_long[54],
data_long[46],data_long[38],
data_long[30],data_long[22],
data_long[14],data_long[6]
};
// assign channel6[8:0] = {txo_frame_int[6],data_long[55:48]};
assign channel7[7:0] = {data_long[63],data_long[55],
data_long[47],data_long[39],
data_long[31],data_long[23],
data_long[15],data_long[7]
};
// assign channel7[8:0] = {txo_frame_int[7],data_long[63:56]};
assign txo_data_int[71:0] =
{txo_frame_int[7:0],
channel7[7:0],channel6[7:0],channel5[7:0],channel4[7:0],
channel3[7:0],channel2[7:0],channel1[7:0],channel0[7:0]};
// assign txo_data_int[71:0] =
// {channel7[8:0],channel6[8:0],channel5[8:0],channel4[8:0],
// channel3[8:0],channel2[8:0],channel1[8:0],channel0[8:0]};
// always @ (posedge txo_lclk or posedge reset)
// if (reset)
// txo_frame[7:0] <= {(8){1'b0}};
// else
// txo_frame[7:0] <= txo_frame_int[7:0];
// always @ (posedge txo_lclk)
// txo_data[63:0] <= txo_data_int[63:0];
always @ (posedge txo_lclk or posedge reset)
if (reset)
tx_in[71:0] <= {(72){1'b0}};
else
tx_in[71:0] <= txo_data_int[71:0];
endmodule // ewrapper_link_txo