dsi-shield/hdl/rtl/dsi_core/dsi_packer.v

239 lines
5.8 KiB
Verilog

/*
* DSI Core
* Copyright (C) 2013 twl <twlostow@printf.cc>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
*/
`timescale 1ns/1ps
/*
* dsi_packer.v
*
* A module that tightly packs bytes or byte sequences in to an output word of certain
* size.
*/
module dsi_byte_reverse
(
d_i,
q_o);
parameter g_num_bytes = 4;
input [g_num_bytes * 8 - 1 : 0] d_i;
output [g_num_bytes * 8 - 1 : 0] q_o;
generate
genvar i, j;
for(i=0;i<8;i=i+1)
for(j=0;j<g_num_bytes;j=j+1)
assign q_o[8 * (g_num_bytes-1-j) + i] = d_i[8 * j + i];
endgenerate
endmodule
module dsi_byte_swapper
(
d_i,
size_i,
q_o);
parameter g_num_bytes = 4;
input [g_num_bytes * 8 - 1 : 0] d_i;
output [g_num_bytes * 8 - 1 : 0] q_o;
input [2:0] size_i;
wire [g_num_bytes * 8 - 1 : 0] swapped[1:g_num_bytes];
generate
genvar i, j, nbytes;
for(nbytes = 1; nbytes <= g_num_bytes; nbytes = nbytes + 1)
for(i=0;i<8;i=i+1)
begin
for(j=0;j<nbytes;j=j+1)
assign swapped[nbytes] [8 * (nbytes-1-j) + i] = d_i[8 * j + i];
for(j=nbytes;j<g_num_bytes;j=j+1)
assign swapped[nbytes] [j * 8 + i ] = 1'b0;
end
endgenerate
assign q_o = (size_i) <= g_num_bytes ? swapped[size_i] : 'hx;
endmodule
module dsi_byte_shifter
(
d_i,
shifted_o,
shift_i
);
parameter g_data_bytes = 3;
parameter g_max_shift = 3;
localparam c_output_width = 8 * (g_data_bytes + g_max_shift);
input [3:0] shift_i;
input [g_data_bytes * 8 - 1: 0] d_i;
output [c_output_width - 1: 0] shifted_o;
wire [c_output_width - 1 : 0] gen_array[0:g_max_shift];
genvar i;
generate
for (i=0;i<g_max_shift;i=i+1)
assign gen_array[i] = d_i << (i * 8);
endgenerate
assign shifted_o = gen_array[shift_i];
endmodule // dsi_byte_shifter
module dsi_packer
(
clk_i,
rst_n_i,
d_i,
d_size_i,
d_req_o,
d_valid_i,
d_empty_o,
q_o,
q_req_i,
q_flush_i,
q_valid_o
);
parameter g_input_bytes = 3;
parameter g_output_bytes = 3;
localparam c_shiftreg_bytes = 2 * (g_input_bytes > g_output_bytes ? g_input_bytes : g_output_bytes) + 2;
input clk_i, rst_n_i;
input [g_input_bytes * 8 - 1 : 0] d_i;
input [3 : 0] d_size_i;
output d_req_o;
input d_valid_i, q_flush_i;
output [g_output_bytes * 8 -1 :0] q_o;
output reg [g_output_bytes-1:0] q_valid_o;
output d_empty_o;
input q_req_i;
wire [g_input_bytes * 8 - 1 : 0] d_in;
reg [g_output_bytes * 8 - 1 : 0] q_out;
reg [4:0] count, avail, avail_next;
reg [c_shiftreg_bytes * 8 -1 :0] shreg;
wire [c_shiftreg_bytes * 8 -1 :0] in_shifted;
wire shift_out;
wire [4:0] in_shift;
wire d_req_int;
assign shift_out = (count >= g_output_bytes && q_req_i);
assign in_shift = (shift_out ? count - g_output_bytes : count);
dsi_byte_swapper #(g_input_bytes) U_RevIn ( d_i, d_size_i, d_in );
dsi_byte_reverse #(g_output_bytes) U_RevOut ( q_out, q_o );
dsi_byte_shifter
#(
.g_data_bytes(g_input_bytes),
.g_max_shift(c_shiftreg_bytes - 1)
)
U_Shifter
(
.d_i(d_in),
.shift_i(in_shift),
.shifted_o(in_shifted)
);
always@(posedge clk_i)
if(!rst_n_i) begin
q_valid_o <= 0;
q_out <= 0;
end else if(shift_out || q_flush_i)
begin : drive_output
integer i;
q_out <= shreg[g_output_bytes * 8 - 1 : 0];
for(i=0;i<g_output_bytes;i=i+1)
q_valid_o[i] <= count > i;
end else
q_valid_o <= 0;
always@(posedge clk_i)
if (!rst_n_i)
begin
count <= 0;
avail <= c_shiftreg_bytes;
shreg <= 0;
end else begin
if(d_valid_i && shift_out) begin
shreg <= (shreg >> ( 8 * g_output_bytes )) | in_shifted;
count <= count - g_output_bytes + d_size_i;
end else if(d_valid_i) begin
shreg <= shreg | in_shifted;
count <= count + d_size_i;
end else if(shift_out) begin
shreg <= (shreg >> ( 8 * g_output_bytes ));
count <= count - g_output_bytes;
end else if (q_flush_i) begin
count <= 0;
shreg <= 0;
end
avail <= avail_next;
end // else: !if(!rst_n_i)
always@*
if(d_valid_i && shift_out)
avail_next <= avail + g_output_bytes - d_size_i;
else if(d_valid_i)
avail_next <= avail - d_size_i;
else if(shift_out)
avail_next <= avail + g_output_bytes;
else if(q_flush_i)
avail_next <= c_shiftreg_bytes;
else
avail_next <= avail;
assign d_req_int = (avail_next >= g_input_bytes) || (shift_out && avail_next >= (g_input_bytes - g_output_bytes));
assign d_req_o = d_req_int;
assign d_empty_o = !count;
endmodule // dsi_packer