gpcas_forwardcom 0.1.1

ForwardCom instruction set architecture (ISA) properties for use with the General Purpose Core Architecture Simulator (GPCAS).
Documentation
// Filename: execute.rs
// Author:	 Kai Rese
// Version:	 0.11
// Date:	 15-08-2022 (DD-MM-YYYY)
// Library:  gpcas_forwardcom
//
// Copyright (c) 2022 Kai Rese
// This program 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 of the
// License, or (at your option) any later version.
//
// This program 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 program. If not, see
// <https://www.gnu.org/licenses/>.

//! Executes instructions.

use crate::emulator::constants::operand_indices;
use crate::emulator::core::decode::OperandType;
use crate::emulator::instructions::VectorMode;
use crate::emulator::{EmulatorInstruction, ForwardComEmulator};

/// Executes the selected instruction.
///
/// The execution function of the instruction is called once for every element in the operands.
/// The `offset` is a byte offset to select each element.
#[inline]
pub fn execute(instruction: &mut EmulatorInstruction, emulator: &mut ForwardComEmulator) {
    let size = instruction.operand_type.log_size();
    log::trace!(
        "Operand size {}, element size {}",
        instruction.operand_size,
        1 << size
    );

    let call_count = match instruction.vector_mode {
        VectorMode::Element => instruction.operand_size >> size,
        VectorMode::Full => 1,
    };
    for i in 0..call_count {
        let offset = i << size;
        let mask = emulator
            .operands
            .get_offset_u8(operand_indices::MASK, offset);
        if (mask & 0x01) > 0 {
            (instruction.function)(emulator, instruction, offset);
            match instruction.operand_type {
                OperandType::I8 => {
                    log::trace!(
                        "Value after execution: {0} (hex {0:#X})",
                        emulator
                            .operands
                            .get_offset_u8(operand_indices::OUTPUT, offset)
                    );
                }
                OperandType::I16 => {
                    log::trace!(
                        "Value after execution: {0} (hex {0:#X})",
                        emulator
                            .operands
                            .get_offset_u16(operand_indices::OUTPUT, offset)
                    );
                }
                OperandType::I32 => {
                    log::trace!(
                        "Value after execution: {0} (hex {0:#X})",
                        emulator
                            .operands
                            .get_offset_u32(operand_indices::OUTPUT, offset)
                    );
                }
                OperandType::I64 => {
                    log::trace!(
                        "Value after execution: {0} (hex {0:#X})",
                        emulator
                            .operands
                            .get_offset_u64(operand_indices::OUTPUT, offset)
                    );
                }
                OperandType::I128 => {}
                OperandType::F16 => {
                    log::trace!(
                        "Value after execution: {0} (hex {0:#X})",
                        half::f16::from_bits(
                            emulator
                                .operands
                                .get_offset_u16(operand_indices::OUTPUT, offset)
                        )
                    );
                }
                OperandType::F32 => {
                    log::trace!(
                        "Value after execution: {0}",
                        emulator
                            .operands
                            .get_offset_f32(operand_indices::OUTPUT, offset)
                    );
                }
                OperandType::F64 => {
                    log::trace!(
                        "Value after execution: {0}",
                        emulator
                            .operands
                            .get_offset_f64(operand_indices::OUTPUT, offset)
                    );
                }
                OperandType::F128 => {}
            }
        } else {
            emulator.operands.copy(
                operand_indices::FALLBACK,
                operand_indices::OUTPUT,
                offset,
                offset,
                1 << size,
            );
        }
    }
    assert!(instruction.valid, "Committed an invalid instruction");
}