1
0
mirror of https://github.com/aolofsson/oh.git synced 2025-01-17 20:02:53 +08:00
oh/elink/hdl/erx_protocol.v
Andreas Olofsson c0d8c967c4 Address remapping integration
Integrated remapping logic (compiles)
Starting debug tomorrow...
2015-04-24 17:39:05 -04:00

386 lines
12 KiB
Verilog

/*
########################################################################
EPIPHANY eLink RX Protocol block
########################################################################
This block takes the parallel output of the input deserializers, locates
valid frame transitions, and decodes the bytes into standard eMesh
protocol (104-bit transactions).
*/
module erx_protocol (/*AUTOARG*/
// Outputs
erx_access, erx_packet, erx_rr,
// Inputs
reset, rx_enable, rx_lclk_div4, rx_frame_par, rx_data_par
);
parameter AW = 32;
parameter DW = 32;
parameter PW = 104;
parameter ID = 0;
parameter [11:0] C_READ_TAG_ADDR = 12'h810;
// System reset input
input reset;
input rx_enable;//Enables receiver
// Parallel interface, 8 eLink bytes at a time
input rx_lclk_div4; // Parallel clock input from IO block
input [7:0] rx_frame_par;
input [63:0] rx_data_par;
// Output to MMU / filter
output erx_access;
output [PW-1:0] erx_packet;
output erx_rr; //needed for remapping logic
//######################
//# Identify FRAME edges
//######################
reg frame_prev;
reg [2:0] rxalign_in;
reg rxactive_in;
reg [63:0] rx_data_in;
reg [2:0] rxalign_0;
reg rxactive_0;
reg [3:0] ctrlmode_0;
reg [31:0] dstaddr_0;
reg [1:0] datamode_0;
reg write_0;
reg access_0;
reg [31:16] data_0;
reg stream_0;
reg [2:0] rxalign_1;
reg rxactive_1;
reg [3:0] ctrlmode_1;
reg [31:0] dstaddr_1;
reg [1:0] datamode_1;
reg write_1;
reg access_1;
reg [31:0] data_1;
reg [31:0] srcaddr_1;
reg stream_1;
reg [3:0] ctrlmode_reg;
reg [31:0] dstaddr_reg;
reg [1:0] datamode_reg;
reg write_reg;
reg access_reg;
reg [31:0] data_reg;
reg [31:0] srcaddr_reg;
reg stream_reg;
wire rx_enable_sync;
wire gated_access;
// Here we handle any alignment of the frame within an 8-cycle group,
// though in theory frames should only start on rising edges??
always @( posedge rx_lclk_div4 or posedge reset)
if(reset)
begin
rxalign_in <= 3'd0;
rxactive_in <= 1'b0;
end
else
begin
frame_prev <= rx_frame_par[0] ; // Capture last bit for next group
rx_data_in <= rx_data_par;
if( ~frame_prev & rx_frame_par[7] ) begin // All 8 bytes are a new frame
rxalign_in <= 3'd7;
rxactive_in <= 1'b1;
end else if( ~rx_frame_par[7] & rx_frame_par[6] ) begin
rxalign_in <= 3'd6;
rxactive_in <= 1'b1;
end else if( ~rx_frame_par[6] & rx_frame_par[5] ) begin
rxalign_in <= 3'd5;
rxactive_in <= 1'b1;
end else if( ~rx_frame_par[5] & rx_frame_par[4] ) begin
rxalign_in <= 3'd4;
rxactive_in <= 1'b1;
end else if( ~rx_frame_par[4] & rx_frame_par[3] ) begin
rxalign_in <= 3'd3;
rxactive_in <= 1'b1;
end else if( ~rx_frame_par[3] & rx_frame_par[2] ) begin
rxalign_in <= 3'd2;
rxactive_in <= 1'b1;
end else if( ~rx_frame_par[2] & rx_frame_par[1] ) begin
rxalign_in <= 3'd1;
rxactive_in <= 1'b1;
end else if( ~rx_frame_par[1] & rx_frame_par[0] ) begin
rxalign_in <= 3'd0;
rxactive_in <= 1'b1;
end else begin
rxactive_in <= 1'd0; // No edge
end
end // always @ ( posedge rx_lclk_div4 )
// 1st cycle
always @( posedge rx_lclk_div4 or posedge reset)
if(reset)
begin
rxactive_0 <= 1'b0;
rxalign_0 <= 1'b0;
stream_0 <= 1'b0;
access_0 <= 1'b0;
end
else
begin
rxactive_0 <= rxactive_in;
rxalign_0 <= rxalign_in;
stream_0 <= 1'b0;
case(rxalign_in[2:0])
3'd7:
begin
ctrlmode_0[3:0] <= rx_data_in[55:52];
dstaddr_0[31:0] <= rx_data_in[51:20];
datamode_0 <= rx_data_in[19:18];
write_0 <= rx_data_in[17];
access_0 <= rx_data_in[16];
data_0[31:16] <= rx_data_in[15:0];
stream_0 <= rx_frame_par[1] & (rxactive_in | stream_0);
end
3'd6:
begin
ctrlmode_0[3:0] <= rx_data_in[47:44];
dstaddr_0[31:0] <= rx_data_in[43:12];
datamode_0 <= rx_data_in[11:10];
write_0 <= rx_data_in[9];
access_0 <= rx_data_in[8];
data_0[31:24] <= rx_data_in[7:0];
stream_0 <= rx_frame_par[0] & (rxactive_in | stream_0);
end
3'd5:
begin
ctrlmode_0 <= rx_data_in[39:36];
dstaddr_0[31:0] <= rx_data_in[35:4];
datamode_0 <= rx_data_in[3:2];
write_0 <= rx_data_in[1];
access_0 <= rx_data_in[0];
end
3'd4:
begin
ctrlmode_0 <= rx_data_in[31:28];
dstaddr_0[31:4] <= rx_data_in[27:0];
end
3'd3:
begin
ctrlmode_0 <= rx_data_in[23:20];
dstaddr_0[31:12] <= rx_data_in[19:0];
end
3'd2:
begin
ctrlmode_0 <= rx_data_in[15:12];
dstaddr_0[31:20] <= rx_data_in[11:0];
end
3'd1:
begin
ctrlmode_0 <= rx_data_in[7:4];
dstaddr_0[31:28] <= rx_data_in[3:0];
end
default: ;
endcase // case (rxalign_in[2:0])
end // always @ ( posedge rx_lclk_div4 )
// 2nd cycle
always @( posedge rx_lclk_div4 or posedge reset)
if(reset)
begin
rxactive_1 <= 1'b0;
rxalign_1 <= 1'b0;
access_1 <= 1'b0;
end
else
begin
rxactive_1 <= rxactive_0;
rxalign_1 <= rxalign_0;
// default pass-throughs
ctrlmode_1 <= ctrlmode_0;
dstaddr_1 <= dstaddr_0;
datamode_1 <= datamode_0;
write_1 <= write_0;
access_1 <= access_0;
data_1[31:16] <= data_0[31:16];
stream_1 <= stream_0;
case(rxalign_0)
3'd7: begin
data_1[15:0] <= rx_data_in[63:48];
srcaddr_1 <= rx_data_in[47:16];
end
3'd6: begin
data_1[23:0] <= rx_data_in[63:40];
srcaddr_1 <= rx_data_in[39:8];
end
3'd5: begin
data_1 <= rx_data_in[63:32];
srcaddr_1 <= rx_data_in[31:0];
stream_1 <= rx_frame_par[7] & (rxactive_0 | stream_1);
end
3'd4: begin
dstaddr_1[3:0] <= rx_data_in[63:60];
datamode_1 <= rx_data_in[59:58];
write_1 <= rx_data_in[57];
access_1 <= rx_data_in[56];
data_1 <= rx_data_in[55:24];
srcaddr_1[31:8] <= rx_data_in[23:0];
stream_1 <= rx_frame_par[6] & (rxactive_0 | stream_1);
end
3'd3: begin
dstaddr_1[11:0] <= rx_data_in[63:52];
datamode_1 <= rx_data_in[51:50];
write_1 <= rx_data_in[49];
access_1 <= rx_data_in[48];
data_1 <= rx_data_in[47:16];
srcaddr_1[31:16] <= rx_data_in[15:0];
stream_1 <= rx_frame_par[5] & (rxactive_0 | stream_1);
end
3'd2: begin
dstaddr_1[19:0] <= rx_data_in[63:44];
datamode_1 <= rx_data_in[43:42];
write_1 <= rx_data_in[41];
access_1 <= rx_data_in[40];
data_1 <= rx_data_in[39:8];
srcaddr_1[31:24] <= rx_data_in[7:0];
stream_1 <= rx_frame_par[4] & (rxactive_0 | stream_1);
end
3'd1: begin
dstaddr_1[27:0] <= rx_data_in[63:36];
datamode_1 <= rx_data_in[35:34];
write_1 <= rx_data_in[33];
access_1 <= rx_data_in[32];
data_1 <= rx_data_in[31:0];
stream_1 <= rx_frame_par[3] & (rxactive_0 | stream_1);
end
3'd0: begin
ctrlmode_1 <= rx_data_in[63:60];
dstaddr_1[31:0] <= rx_data_in[59:28];
datamode_1 <= rx_data_in[27:26];
write_1 <= rx_data_in[25];
access_1 <= rx_data_in[24];
data_1[31:8] <= rx_data_in[23:0];
stream_1 <= rx_frame_par[2] & (rxactive_0 | stream_1);
end
endcase
end // always @ ( posedge rx_lclk_div4 )
// 3rd cycle
always @( posedge rx_lclk_div4 or posedge reset)
if (reset)
begin
access_reg <= 1'b0;
stream_reg <= 1'b0;
end
else
begin
// default pass-throughs
if(~stream_reg)
begin
ctrlmode_reg <= ctrlmode_1;
dstaddr_reg <= dstaddr_1;
datamode_reg <= datamode_1;
write_reg <= write_1;
access_reg <= access_1 & rxactive_1;
end
else
begin
dstaddr_reg <= dstaddr_reg + 32'h00000008;
end
data_reg <= data_1;
srcaddr_reg <= srcaddr_1;
stream_reg <= stream_1;
case( rxalign_1[2:0] )
// 7-5: Full packet is complete in 2nd cycle
3'd4:
srcaddr_reg[7:0] <= rx_data_in[63:56];
3'd3:
srcaddr_reg[15:0] <= rx_data_in[63:48];
3'd2:
srcaddr_reg[23:0] <= rx_data_in[63:40];
3'd1:
srcaddr_reg[31:0] <= rx_data_in[63:32];
3'd0:
begin
data_reg[7:0] <= rx_data_in[63:56];
srcaddr_reg[31:0] <= rx_data_in[55:24];
end
default:;//TODO: include error message
endcase // case ( rxalign_1 )
end // always @ ( posedge rx_lclk_div4 )
//Gating the rx with enable signal
synchronizer #(.DW(1)) sync (.out (rx_enable_sync),
.in (rx_enable),
.clk (rx_lclk_div4),
.reset (reset)
);
assign erx_access = access_reg & rx_enable_sync;
//Sending packet
emesh2packet e2p (
// Outputs
.packet_out (erx_packet[PW-1:0]),
// Inputs
.access_in (erx_access),
.write_in (write_reg),
.datamode_in (datamode_reg[1:0]),
.ctrlmode_in (ctrlmode_reg[3:0]),
.dstaddr_in (dstaddr_reg[AW-1:0]),
.data_in (data_reg[DW-1:0]),
.srcaddr_in (srcaddr_reg[AW-1:0])
);
assign erx_rr = erx_access &
write_reg &
(dstaddr_reg[31:20] == ID) &
(dstaddr_reg[19:16]==`EGROUP_READTAG)
;
endmodule // erx_protocol
// Local Variables:
// verilog-library-directories:("." "../../common/hdl")
// End:
/*
This file is part of the Parallella Project.
Copyright (C) 2014 Adapteva, Inc.
Contributed by Fred Huettig <fred@adapteva.com>
Contributed by Andreas Olofsson <andreas@adapteva.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program (see the file COPYING). If not, see
<http://www.gnu.org/licenses/>.
*/