| /****************************************************************************** | |
| * (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); | |
| } | |
| } | |
| }; |