//
// q_assm.V
//
// Quadlet Assembler: used to assemble the incoming data from PHY into quadlets
//The purpose of this module is to form quadlets i.e. 32 bits word from data that is
//provided by PHY according to the specified speed . Since all other modules can process
//quadlets, therefore the data which ic received from PHY in the form of 2,4, or 8 bits
//must be merged into a quadlet.
module Q_ASSM
( //Input
BCLK, //Clock from transaction layer
SCLK, //Clock from PHY (49.152 MHz)
D, //Data from PHY
reset_n, //reset signal to the LINK (active low)
pipe_en, //enable signal to quadlet assembler from PLI
quad_fill, //output signal to receiver for every quadlet
ctl, //control info from PHY
Q //Assembled Quadlet (32)
);
input pipe_en,reset_n;
wire pipe_en,reset_n;
input SCLK,BCLK;
wire SCLK,BCLK;
input [7:0] D;
wire [7:0] D;
input [1:0] ctl;
wire [1:0] ctl;
output quad_fill;
reg quad_fill;
output [31:0] Q;
reg [31:0] Q;
reg [1:0] Sel_400; //indicates the data reception progress for the speed of 400 Mb/sec
reg [2:0] Sel_200; //indicates the data reception progress for the speed of 200 Mb/sec
reg [3:0] Sel_100; //indicates the data reception progress for the speed of 100 Mb/sec
reg [31:0] Q_100, Q_200, Q_400; //To store assembled quadlet
reg count_allow;
reg [1:0] speedcode; //to store the speed code initially transferred from the PHY
reg En_100,En_200,En_400; //enable signals to the three sel counters used
always @(negedge SCLK or negedge reset_n)
begin
if(!reset_n)
speedcode <= 2'b11;
else if(pipe_en && speedcode == 2'b11) //pipe_en must be at logic 1 on positive edge
//of SCLK by PLI.With pipe_en D contains speed code.
speedcode <= D[1:0];
else if(!pipe_en)
speedcode <= 2'b11;
end
//to enable any of the sel counters
always @(speedcode)
begin
case(speedcode)
2'b00:
begin
En_100 <= 1;
En_200 <= 0;
En_400 <= 0;
end
2'b01:
begin
En_100 <= 0;
En_200 <= 1;
En_400 <= 0;
end
2'b10:
begin
En_100 <= 0;
En_200 <= 0;
En_400 <= 1;
end
2'b11:
begin
En_100 <= 0;
En_200 <= 0;
En_400 <= 0;
end
endcase
end
//Quadlet Assembling
always @(negedge SCLK or negedge reset_n)
begin
if(!reset_n)
begin
Q_100 = 32'h00000000;
Q_200 = 32'h00000000;
Q_400 = 32'h00000000;
end
else if(En_100 || ctl == 2'b01)
begin
Q_100 = Q_100 << 2;
Q_100[1:0] = D[1:0];
end
else if(En_200)
begin
Q_200 = Q_200 << 4;
Q_200[3:0] = D[3:0];
end
else if(En_400)
begin
Q_400 = Q_400 << 8;
Q_400[7:0] = D[7:0];
end
end
always @(negedge SCLK or negedge reset_n)
begin
if(!reset_n)
begin
Sel_100 <= 4'b1111;
Sel_200 <= 3'b111;
Sel_400 <= 2'b11;
count_allow <= 1'b0;
end
else if(En_100 || ctl == 2'b01) // ctl == status
begin
Sel_100 <= Sel_100 + 1'b1;
Sel_200 <= 3'b111;
Sel_400 <= 2'b11;
count_allow <= 1'b1;
end
else if(En_200)
begin
Sel_100 <= 4'b1111;
Sel_200 <= Sel_200 + 1'b1;
Sel_400 <= 2'b11;
count_allow <= 1'b1;
end
else if(En_400)
begin
Sel_100 <= 4'b1111;
Sel_200 <= 3'b111;
Sel_400 <= Sel_400 + 1'b1;
count_allow <= 1'b1;
end
else
begin
Sel_100 <= 4'b1111;
Sel_200 <= 3'b111;
Sel_400 <= 2'b11;
count_allow <= 1'b0;
end
end
always @(negedge BCLK or negedge reset_n)
begin
if(!reset_n)
quad_fill <= 1'b0;
else if( ((Sel_100 == 4'b1111 && En_100) || (Sel_200 == 3'b111 && En_200) || (Sel_400 == 2'b11 && En_400)) && count_allow && !quad_fill)
quad_fill <= 1'b1;
else if(Sel_100 == 3 && ctl == 2'b01) // ctl == status
quad_fill <= 1'b1;
else
quad_fill <= 1'b0;
end
always @(posedge quad_fill)
begin
if (En_100 || Sel_100 == 3) // to handle the status
Q <= Q_100;
else if(En_200)
Q <= Q_200;
else if(En_400)
Q <= Q_400;
else
Q <= 32'h00000000;
end
endmodule