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

383 lines
12 KiB
Verilog

/*
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