blob: 009719262ec1542910f75ad920b827a25a5e7fc4 [file] [log] [blame]
/******************************************************************************
* (C) Copyright 2014 AMIQ Consulting
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* NAME: amiq_eth_packer.cpp
* PROJECT: amiq_eth
* Description: This file declares the packer used in packing/unpacking of the
* Ethernet packets
*******************************************************************************/
//the block size - used in avoiding memory re-allocations at every pack action
#define AMIQ_ETH_PACKING_BLOCK_SIZE 4096
//class for packing and unpacking the Ethernet packets
class amiq_eth_packer {
private:
//pack index
unsigned int pack_index;
//unpack index
unsigned int unpack_index;
//information bits
sc_bv_base* information_bits;
//the current size (in memory blocks)
int size;
//the maximum size (in memory blocks)
int max_size;
protected:
//method for allocating required memory
//@param - number_of_bits - number of bits requested to be packed
void allocate(int number_of_bits) {
//number of bits which will be packed
int total_bits = pack_index + number_of_bits;
//the new size (in memory blocks) required to hold the entire information
size = ((total_bits - 1) / AMIQ_ETH_PACKING_BLOCK_SIZE + 1) * AMIQ_ETH_PACKING_BLOCK_SIZE;
if (size > max_size) {
//the new size exceeds the current allocated memory space so new allocation must be done
//allocate a new memory region of required size
sc_bv_base* new_bv = new sc_bv_base(size);
if (information_bits) {
//save the current information
*new_bv = *information_bits;
//delete the old memory location of the information bits
delete information_bits;
}
information_bits = new_bv;
//save the current allocated size
max_size = size;
}
}
//method for checking the number of bits requested to be packed
//@param - number_of_bits - number of bits requested to be packed
void check_size(int number_of_bits) {
//determine the current free space
int free_space = size - pack_index;
if (number_of_bits >= free_space) {
//the number of bits requested to be packed is bigger then the available free space
//so new memory allocation is required
allocate(number_of_bits);
}
}
//method for incrementing the unpacking index
//@param - number_of_bits - number of bits to be unpacked
void inc_unpack_index(int number_of_bits) {
unpack_index += number_of_bits;
if (unpack_index > pack_index) {
char msg[1024];
sprintf(msg, "Trying to unpack more information then it was packed so far - unpack_index=%d, pack_index=%d", unpack_index, pack_index);
SC_REPORT_ERROR("AMIQ_ETH", msg);
}
}
//method for packing an integer
//@param data - data to be packed
//@param - number_of_bits - number of bits used to pack "data"
void pack_int_n(unsigned long long data, unsigned number_of_bits) {
check_size(number_of_bits);
(*information_bits)(pack_index + number_of_bits - 1, pack_index) = data;
pack_index += number_of_bits;
}
//method for unpacking an integer
//@param - number_of_bits - number of bits to be unpacked
//@return - the unpacked integer
uint64 unpack_int_n(unsigned number_of_bits) {
uint64 data;
data = (*information_bits)(unpack_index + number_of_bits - 1, unpack_index).to_uint64();
inc_unpack_index(number_of_bits);
return data;
}
public:
//constructor
amiq_eth_packer() {
pack_index = 0;
unpack_index = 0;
size = 0;
max_size = 0;
information_bits = 0;
}
//destructor
virtual ~amiq_eth_packer() {
if (information_bits) {
delete information_bits;
}
}
//packing operator
virtual amiq_eth_packer& operator <<(bool a) {
int bit_value = a ? 1 : 0;
pack_int_n(bit_value, 1);
return *this;
}
//unpacking operator
virtual amiq_eth_packer& operator >>(bool& a) {
a = (bool) (unpack_int_n(1));
return *this;
}
//reset the packer
virtual void reset() {
pack_index = 0;
unpack_index = 0;
size = 0;
}
//method for returning the number of remaining unpacked bits
//@return number of unpacked bits
virtual int get_remaining_unpacked_bits() {
return pack_index - unpack_index;
}
//method for getting a vector of bytes
//@param data - vector of bytes
void get_bytes(std::vector<char>& data) {
unsigned n = get_remaining_unpacked_bits();
unsigned nbytes = 1 + (n - 1) / 8;
for (unsigned i = 0; i < nbytes; i++) {
char b = (*information_bits).range(8 * i + 7, 8 * i).to_int();
data.push_back(b);
}
}
};