/*****************************************************************************
 *
 * Copyright (c) 2018-19, Eduard Gerlits, Paula Herber, Josef Treus
 * Westfälische Wilhelms-Universität Münster, AG Embedded Systems 
 * All rights reserved.
 *
 * This file is part of SysCSec
 *
 * SysCSec 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.
 *
 * SysCSec 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 SysCSec.  If not, see <http://www.gnu.org/licenses/>.
 *
 *
 *  Please report any problems or bugs to: sysc.sec@uni-muenster.de
 *
 ****************************************************************************/


#include "IO.h"

void IOModule::exe(){
	p_data = 0;
	while(true){
		sc_uint<3> io_control = io_control_in->read();
		sc_biguint<160> data_in_val = data_in->read();
		sc_biguint<960> p_data_in_val = p_data_in->read();

		// select operation
		switch(io_control){
			case _IO_IDLE_:
			break;

			case _IO_SET_DATA_:
			io_status->write(_IO_PROCESSING_);
			set_data(p_data_in_val, p_data);
			io_status->write(_IO_FINISHED_);
			break;

			case _IO_GET_DATA_:
			io_status->write(_IO_PROCESSING_);
			get_data(p_data);
			io_status->write(_IO_FINISHED_);
			break;

			case _IO_PACK_DATA_:
			io_status->write(_IO_PROCESSING_);
			pack_data(data_in_val, p_data);
			io_status->write(_IO_FINISHED_);
			break;

			case _IO_UNPACK_DATA_:
			sc_biguint<160> data;
			io_status->write(_IO_PROCESSING_);
			unpack_data(data, p_data);
			io_status->write(_IO_FINISHED_);
			break;
		}
	}
}

/*
read 960 bit data packet
*/
void IOModule::set_data(sc_biguint<960> data, sc_biguint<960> &target){
	target = data;
	p_data_out->write(0);
	data_out->write(0);
}

/*
write 960 bit data packet and reset internal variable
*/
void IOModule::get_data(sc_biguint<960> &data){
	p_data_out->write(data);
	data_out->write(0);
	data=0;
}

/*
pack 160 bit data into a 960 bit data packet and shift by 160 bits to the left
*/
void IOModule::pack_data(sc_biguint<160> data, sc_biguint<960> &target){
	target <<= 160;
	target = target | data;
	p_data_out->write(0);
	data_out->write(0);
}

/*
unpack right most 160 bit data and shift by 160 bit to the right. write result to data
*/
void IOModule::unpack_data(sc_biguint<160> &data, sc_biguint<960> &source){
	data = source;
	source >>= 160;
	
	data_out->write(data);
	p_data_out->write(0);
}
