Skip to content
Snippets Groups Projects
Select Git revision
  • caddd55cfad87dd9c1edc44109c151ab07bc081d
  • master default
  • v1
3 results

cpu.c

Blame
  • cpu.c 24.80 KiB
    #include <stdlib.h>
    #include <assert.h>
    #include <string.h>
    
    /* DEBUG LIB */
    #include <stdio.h>
    
    #include "cpu.h"
    #include "debug.h"
    
    #define likely(x)       __builtin_expect((x),1)
    #define unlikely(x)     __builtin_expect((x),0)
    
    #define EIGHT_BIT true
    #define IMMEDIATE true
    
    #define SUBTRACTION true
    
    #define HIGH_BYTE true
    
    #define IS_HIGH(x) (x ## _type == REGISTER_HIGH)
    
    void *cpu_create(struct sig_host_bus *port_host);
    void  cpu_destroy(void *_cpu_state);
    
    static cpu_register cpu_modrm_eval_register(cpu_state *cpu_state, cpu_register reg, uint32_t **reg_addr, bool is_8bit);
    static bool         cpu_modrm_eval(cpu_state *cpu_state, modsib *mod, uint8_t byte, uint8_t is_8bit);
    
    static bool cpu_decode_RM(cpu_state *cpu_state, op_addr *addr, bool is_8bit);
    static void cpu_set_opaddr_regmem(cpu_state *cpu_state, uint8_t mode, uint32_t *addr, op_addr *op);
    
    static uint8_t  cpu_read_byte_from_reg(uint32_t *reg_addr, bool is_high);
    static uint32_t cpu_read_word_from_reg(uint32_t *reg_addr);
    static uint8_t  cpu_read_byte_from_mem(cpu_state *cpu_state, uint32_t mem_addr);
    static uint32_t cpu_read_word_from_mem(cpu_state *cpu_state, uint32_t mem_addr);
    
    static uint8_t  cpu_consume_byte_from_mem(cpu_state *cpu_state);
    static uint32_t cpu_consume_word_from_mem(cpu_state *cpu_state);
    
    static void cpu_write_byte_in_reg(uint32_t *reg_addr, uint8_t byte, bool is_high);
    static void cpu_write_word_in_reg(uint32_t *reg_addr, uint32_t word);
    static void cpu_write_byte_in_mem(cpu_state *cpu_state, uint8_t byte, uint32_t mem_addr);
    static void cpu_write_word_in_mem(cpu_state *cpu_state, uint32_t word, uint32_t mem_addr);
    
    static void cpu_stack_push_byte(cpu_state *cpu_state, uint8_t byte);
    static void cpu_stack_push_doubleword(cpu_state *cpu_state, uint32_t doubleword);
    static uint8_t cpu_stack_pop_byte(cpu_state *cpu_state);
    static uint32_t cpu_stack_pop_doubleword(cpu_state *cpu_state);
    
    static bool cpu_readb(void *_cpu_state, uint32_t addr, uint8_t *valp);
    static bool cpu_writeb(void *_cpu_state, uint32_t addr, uint8_t val);
    
    static void cpu_raise_flag(cpu_state *cpu_state, flag flag);
    static void cpu_clear_flag(cpu_state *cpu_state, flag flag);
    static void cpu_set_flag(cpu_state *cpu_state, flag flag, bool raised);
    
    static void cpu_set_carry_add(cpu_state *cpu_state, uint32_t first_summand, uint32_t result);
    static void cpu_set_carry_sub(cpu_state *cpu_state, uint32_t minuend, uint32_t subtrahend);
    
    static void cpu_set_overflow_add(cpu_state *cpu_state, uint32_t summand_fst, uint32_t summand_snd, uint32_t result, bool is_8bit);
    static void cpu_set_overflow_sub(cpu_state *cpu_state, uint32_t minuend, uint32_t subtrahend, uint32_t result, bool is_8bit);
    
    static void cpu_set_aux_flag_add(cpu_state *cpu_state, uint32_t op1, uint32_t op2, uint32_t result, bool is_8bit);
    static void cpu_set_aux_flag_sub(cpu_state *cpu_state, uint32_t minuend, uint32_t subtrahend, bool is_8bit);
    
    static void cpu_set_sign_flag(cpu_state *cpu_state, uint32_t result, bool is_8bit);
    static void cpu_set_zero_flag(cpu_state *cpu_state, uint32_t result);
    static void cpu_set_eflag_arith(cpu_state *cpu_state, uint32_t op1, uint32_t op2, uint32_t result, bool is_8bit, bool is_subtraction);
    static void cpu_set_eip(cpu_state *cpu_state, uint32_t new_addr);
    
    static bool cpu_get_carry_flag(cpu_state *cpu_state);
    static bool cpu_get_overflow_flag(cpu_state *cpu_state);
    static bool cpu_get_sign_flag(cpu_state *cpu_state);
    static bool cpu_get_zero_flag(cpu_state *cpu_state);
    
    /** @brief "constructor" of the cpu
     *
     *  @param port_host  the port the cpu is connected to
     */
    void *
    cpu_create(struct sig_host_bus *port_host) {
    	struct cpu_state *cpu_state;
    	static const struct sig_host_bus_funcs hf = {
    		.readb = cpu_readb,
    		.writeb = cpu_writeb
    	};
    
    	cpu_state = malloc(sizeof(struct cpu_state));
    	assert(cpu_state != NULL);
    
    	cpu_state->port_host = port_host;
    	/* Set base pointer to start address of ROM.
    	 * The address is hardcoded, like in real hardware.
    	 */
    	cpu_state->eip = 0xE000;
    	cpu_state->esp = 1024*32;
    
    	sig_host_bus_connect(port_host, cpu_state, &hf);
    	return cpu_state;
    }
    
    /** @brief Set instruction pointer
     *
     *  @param cpu_state is the cpu instance
     *  @param new_addr is the new memory address where the
     *                  next instruction will be loaded from
     */
    static void cpu_set_eip(cpu_state *cpu_state, uint32_t new_addr){
    	cpu_state->eip = new_addr;
    }
    
    /** @brief "destructor" of the cpu
     *
     *  @param _cpu_state  the cpu instance
     */
    void
    cpu_destroy(void *_cpu_state) {
    	free(_cpu_state);
    }
    
    
    /** @brief sets a given flag to high (1)
     *
     *  @param cpu_state the instance of the cpu
     *  @param flag      the flag to raise
     */
    static void cpu_raise_flag(cpu_state *cpu_state, flag flag){
    	cpu_state->eflags |= (1 << flag);
    }
    
    /** @brief sets a given flag to low (0)
     *
     *  @param cpu_state the instance of the cpu
     *  @param flag      the flag to clear
     */
    static void cpu_clear_flag(cpu_state *cpu_state, flag flag){
    	cpu_state->eflags &= ~(1 << flag);
    }
    
    /** @brief sets a given flag to a given value (high or low)
     *
     *  @param cpu_state the instance of the cpu
     *  @param flag      the flag to set
     *  @param raised    whether the flag should be high (true) or low (false)
     */
    static void cpu_set_flag(cpu_state *cpu_state, flag flag, bool raised){
    	cpu_state->eflags ^= (-raised ^ cpu_state->eflags) & (1 << flag);
    }
    
    /** @brief Set flags for addition or subtraction in eflag register
     *
     *  @param cpu_state is instance of the cpu
     *  @param op1 is the first operand of the arithmetic operation
     *  @param op2 is the second operand of the arithmetic operation
     *  @param result is the result of the arithmetic operation
     *  @param is_8bit indicates if 8bit modus is on or not
     *  @param is_subtraction indicates if a subtraction was performed
     */
    static void
    cpu_set_eflag_arith(cpu_state *cpu_state, uint32_t op1, uint32_t op2, uint32_t result, bool is_8bit, bool is_subtraction){
    	if(is_subtraction){
    		cpu_set_carry_sub(cpu_state, op1, op2);
    		cpu_set_overflow_sub(cpu_state, op1, op2, result, is_8bit);
    		cpu_set_aux_flag_sub(cpu_state, op1, op2, is_8bit);
    	} else {
    		cpu_set_carry_add(cpu_state, op1, result);
    		cpu_set_overflow_add(cpu_state, op1, op2, result, is_8bit);
    		cpu_set_aux_flag_add(cpu_state, op1, op2, result, is_8bit);
    	}
    	cpu_set_sign_flag(cpu_state, result, is_8bit);
    	cpu_set_zero_flag(cpu_state, result);
    }
    
    static void cpu_set_aux_flag_sub(cpu_state *cpu_state, uint32_t minuend, uint32_t subtrahend, bool is_8bit){
    	cpu_set_flag(cpu_state, AUX_CARRY_FLAG, ((minuend & 0x07) < (subtrahend & 0x07)));
    }
    
    static void cpu_set_aux_flag_add(cpu_state *cpu_state, uint32_t op1, uint32_t op2, uint32_t result, bool is_8bit){
    	if(is_8bit){
    		bool raised = ((op1 >> 3) & 0x01) ^ ((op2 >> 3) & 0x01) && !((result >> 3) & 0x01);
    		cpu_set_flag(cpu_state, AUX_CARRY_FLAG, raised);
    	} else {
    		bool raised = ((op1 >> 7) & 0x01) ^ ((op2 >> 7) & 0x01) && !((result >> 7) & 0x01);
    		cpu_set_flag(cpu_state, AUX_CARRY_FLAG, raised);
    	}
    	return;
    }
    
    /** @brief Set sign bit in EFLAG register
     *
     */
    static void cpu_set_sign_flag(cpu_state *cpu_state, uint32_t result, bool is_8bit){
    	if(is_8bit){
    		cpu_set_flag(cpu_state, SIGN_FLAG, (result & 0x80));
    	} else {
    		cpu_set_flag(cpu_state, SIGN_FLAG, (result & 0x80000000));
    	}
    	return;
    }
    
    /** @brief Set carry bit in eflag for addition
     *
     *  @param summand_fst the first operand of the additon
     *  @param result  result of addition
     */
    static void cpu_set_carry_add(cpu_state *cpu_state, uint32_t summand_fst, uint32_t result){
    	cpu_set_flag(cpu_state, CARRY_FLAG, (result < summand_fst));
    }
    
    /** @brief Set carry bit in eflag for subtraction
     *
     *  @param minuend the first operand of the subtraction
     *  @param subtrahend the second operand of the subtraction
     */
    static void cpu_set_carry_sub(cpu_state *cpu_state, uint32_t minuend, uint32_t subtrahend){
    	cpu_set_flag(cpu_state, CARRY_FLAG, (minuend < subtrahend));
    }
    
    /** @brief Set overflow bit in eflag for addition
     *
     *  @param summand_fst the first operand of the additon
     *  @param summand_snd the second operand of the additon
     *  @param result the result of the addtion
     *  @param is_8bit indicates 8bit operation. Whether sign bit
     *                 is at positon 7 or 31.
     */
    static void cpu_set_overflow_add(cpu_state *cpu_state, uint32_t summand_fst, uint32_t summand_snd, uint32_t result, bool is_8bit){
    	if(is_8bit){
    		bool raised = (!((summand_fst >> 7) ^ (summand_snd >> 7))) && ((summand_fst >> 7) ^ (result >> 7));
    		cpu_set_flag(cpu_state, OVERFLOW_FLAG, raised);
    	} else {
    		bool raised = (!((summand_fst >> 31) ^ (summand_snd >> 31))) && ((summand_fst >> 31) ^ (result >> 31));
    		cpu_set_flag(cpu_state, OVERFLOW_FLAG, raised);
    	}
    }
    
    /** @brief Set overflow bit in eflag for subtraction
     *
     *  @param minuend the first operand of the subtraction
     *  @param subtrahend the second operand of the subtraction
     *  @param result the result of the subtraction
     *  @param is_8bit indicates 8bit operation. Whether sign bit
     *                 is at positon 7 or 31.
     */
    static void cpu_set_overflow_sub(cpu_state *cpu_state, uint32_t minuend, uint32_t subtrahend, uint32_t result, bool is_8bit){
    	if(is_8bit){
    		bool raised = (((minuend >> 7) ^ (subtrahend >> 7)) && ((minuend >> 7) ^ (result >> 7)));
    		cpu_set_flag(cpu_state, OVERFLOW_FLAG, raised);
    	} else {
    		bool raised = (((minuend >> 31) ^ (subtrahend >> 31)) && ((minuend >> 31) ^ (result >> 31)));
    		cpu_set_flag(cpu_state, OVERFLOW_FLAG, raised);
    	}
    }
    
    /** @brief Set zero bit in eflag
     *
     *  @param cpu_state the cpu instance
     *  @param result the result of the operation
     */
    static void cpu_set_zero_flag(cpu_state *cpu_state, uint32_t result){
    	cpu_set_flag(cpu_state, ZERO_FLAG, result==0);
    }
    
    /** @brief Set parity bit in eflag depending on result
     *
     *  @param cpu_state the cpu instance
     *  @param result the result of the operation
     */
    static void cpu_set_parity_flag(cpu_state *cpu_state, uint32_t result){
    	//x86 only looks at the least significant bit
    	bool raised =   ((result & 0x01) != 0) ^ ((result & 0x10) != 0) ^
    					((result & 0x02) != 0) ^ ((result & 0x20) != 0) ^
    					((result & 0x04) != 0) ^ ((result & 0x40) != 0) ^
    					((result & 0x08) != 0) ^ ((result & 0x80) != 0);
    
    	cpu_set_flag(cpu_state, PARITY_FLAG, raised);
    }
    
    /** @brief returns sign flag in EFLAG register
     *
     *  @return true when sign flag is set
     *          false else
     */
    static bool cpu_get_sign_flag(cpu_state *cpu_state){
    	return cpu_state->eflags & (1 << SIGN_FLAG);
    }
    
    /** @brief returns zero flag in EFLAG register
     *
     *  @return true when zero flag is set
     *          false else
     */
    static bool cpu_get_zero_flag(cpu_state *cpu_state){
    	return cpu_state->eflags & (1 << ZERO_FLAG);
    }
    
    /** @brief returns overflow flag in EFLAG register
     *
     *  @return true when overflow flag is set
     *          false else
     */
    static bool cpu_get_overflow_flag(cpu_state *cpu_state){
    	return cpu_state->eflags & (1 << OVERFLOW_FLAG);
    }
    
    /** @brief returns carry flag in EFLAG register
     *
     *  @return true when carry flag is set
     *          false else
     */
    static bool cpu_get_carry_flag(cpu_state *cpu_state){
    	return cpu_state->eflags & (1 << CARRY_FLAG);
    }
    
    
    /** @brief Interpret the reg bits of the mod-reg-r/m byte
     *
     * @param cpu_state  CPU instance
     *
     * @param cpu_register  The register to address
     *
     * @param reg_addr  Pointer that holds the register
     *     address when register was valid
     *
     * @return The register which was read on success
     *         0xff in case of an error
     */
    static cpu_register
    cpu_modrm_eval_register(cpu_state *cpu_state, cpu_register reg, uint32_t **reg_addr, bool is_8bit) {
    	//unlikely: gcc macro specifying that the 'then' path is unlikely
    	if(unlikely(reg > EDI))
    		return 0xff;
    
    	if(!is_8bit){
    		*reg_addr = &(cpu_state->eax)+reg;
    		return reg;
    	}else{
    		if(reg > 0b011)
    			*reg_addr = &(cpu_state->eax)+reg-4;
    		else
    			*reg_addr = &(cpu_state->eax)+reg;
    		return reg+8;
    	}
    }
    
    /** @brief  Interpret the mod-reg-r/m byte
     * Bits 7..6  Scale or Addressing Mode
     * Bits 5..3  Register of first operand
     * Bits 2..0  Register of second operand
     *
     * @param cpu_state    CPU instance
     * @param mod      Pointer to structure where results will be saved in
    * @param byte     byte that will be analysed
     * @param is_8bit  Is it an 8 bit instruction
     *
     * @return         True on success.
     *                 False in case of a huge programming mistake.
     */
    static bool
    cpu_modrm_eval(cpu_state *cpu_state, modsib *mod, uint8_t byte, uint8_t is_8bit) {
    	uint32_t *mod_reg;
    	uint32_t *mod_rm;
    
    	mod->addr_or_scale_mode = (byte >> 6) & (0x7);
    
    	/* Decode register */
    	mod->mod_reg_name = cpu_modrm_eval_register(cpu_state, (byte >> 3) & (0x7), &mod_reg, is_8bit);
    	if( -1 == mod->mod_reg_name) {
    		return false;
    	}
    
    
    	if(mod->addr_or_scale_mode == REGISTER){
    		mod->mod_rm_name = cpu_modrm_eval_register(cpu_state, byte & 0x7, &mod_rm, is_8bit);
    	} else{
    		mod->mod_rm_name = cpu_modrm_eval_register(cpu_state, byte & 0x7, &mod_rm, !EIGHT_BIT);
    	}
    
    	/* Decode register/memory */
    	if( -1 == mod->mod_rm_name) {
    		return false;
    	}
    
    	mod->mod_reg = mod_reg;
    	mod->mod_rm = mod_rm;
    
    	return true;
    }
    
    /** @brief Read and interpret MOD_RM, SIB and DISPLACEMENT bytes
     * Furthermore compute the addresses of operand 1 and 2. Either
     * as pointer to a register or virtual address for the memory component
     *
     * @param cpu_state    CPU instance
     *
     * @param addr     Pointer to structure where virtual address
     *                 of memory or register addresses of the cpu
     *                 instance will be saved in.
     *
     * @param is_8bit  Is it an 8 bit instruction
     *
     * @return         True when everything works fine.
     *                 False when an error occured.
     */
    static bool
    cpu_decode_RM(cpu_state *cpu_state, op_addr *addr, bool is_8bit) {
    	uint8_t mod_rm = 0;
    
    	/* Eval MOD_RM Byte */
    	mod_rm = cpu_consume_byte_from_mem(cpu_state);
    	modsib s_modrm;
    	memset(&s_modrm, 0, sizeof(modsib));
    	// memset(addr, 0, sizeof(op_addr));
    
    	if(false == cpu_modrm_eval(cpu_state, &s_modrm, mod_rm, is_8bit)){
    		return false;
    	}
    
    	addr->reg_value = s_modrm.mod_reg_name & 0x07;
    
    	/*
    	 * set reg part, this is straightforward
    	 */
    	if(!is_8bit){//TODO: Alle is_8bit dinge auf unlikely stellen?
    		addr->reg_type = REGISTER_WORD;
    	}else{
    		if(s_modrm.mod_reg_name < AH){
    			addr->reg_type = REGISTER_LOW;
    		} else {
    			addr->reg_type = REGISTER_HIGH;
    		}
    	}
    	addr->reg = s_modrm.mod_reg;
    
    	/*
    	 * set regmem part, this the tricky part
    	 */
    	if(s_modrm.addr_or_scale_mode == REGISTER){
    		if(!is_8bit){
    			addr->reg_type = REGISTER_WORD;
    		}else{
    			if(s_modrm.mod_rm_name < AH){
    				addr->regmem_type = REGISTER_LOW;
    			} else {
    				addr->regmem_type = REGISTER_HIGH;
    			}
    		}
    
    		addr->regmem_reg = s_modrm.mod_rm;
    	}else{
    		addr->regmem_type = MEMORY;
    
    		if(s_modrm.mod_rm_name == ESP){
    			/* We have a SIB byte following */
    			uint32_t *base;
    			uint32_t *index;
    
    			uint8_t sib = 0;
    			uint8_t scale = 0;
    
    			/* Read next byte increment eip */
    			sib = cpu_consume_byte_from_mem(cpu_state);
    			modsib s_sib;
    			memset(&s_sib,0,sizeof(modsib));
    
    			if(false == cpu_modrm_eval(cpu_state, &s_sib, sib, is_8bit)){
    				return false;
    			}
    
    			scale = s_sib.addr_or_scale_mode;
    			scale = 1 << scale;
    			base = s_sib.mod_rm;
    			index = s_sib.mod_reg;
    
    			/* Compute base address for mod_rm */
    			uint32_t base_mod_rm;
    			if(s_sib.mod_reg_name == ESP) {
    				/* Index is not used */
    				base_mod_rm = *base;
    
    			} else if (s_sib.mod_rm_name == EBP){
    				/* Base is not used */
    				base_mod_rm= *index * scale;
    
    			} else {
    				base_mod_rm = *base + (*index * scale);
    			}
    			/* Remember: addressing mode is unequal to REGISTER! */
    			cpu_set_opaddr_regmem(cpu_state, s_modrm.addr_or_scale_mode, &base_mod_rm, addr);
    
    		} else if(s_modrm.mod_rm_name == EBP && s_modrm.addr_or_scale_mode == NO_DISPLACEMENT){
    			/* Special case: Reject mod_rm and read in a 32 Bit displacement instead. */
    			uint32_t base_0 = 0;
    			cpu_set_opaddr_regmem(cpu_state, DISPLACEMENT_32, &base_0, addr);
    		} else {
    			/* Compute address of mod_rm */
    			cpu_set_opaddr_regmem(cpu_state, s_modrm.addr_or_scale_mode, s_modrm.mod_rm, addr);
    		}
    	}
    	return true;
    }
    
    /** @brief          Compute address of operand 2 subjected to the addressing mode
     *
     * @param cpu_state CPU instance
     *
     * @param mode      Contains addressing mode
     *
     * @param base_addr Pointer that contains the base address. Usually
     *                  a pointer to CPU own register.
     *
     * @param op        Pointer to the op_addr to write to
     */
    static void
    cpu_set_opaddr_regmem(cpu_state *cpu_state, uint8_t mode, uint32_t *base_addr, op_addr *op) {
    	int8_t displ1;
    	int32_t displacement_complete;
    	switch(mode){
    		case NO_DISPLACEMENT:
    			/* Indirection with no displacement */
    			op->regmem_mem = *base_addr;
    			return;
    
    		case DISPLACEMENT_8:
    			/* Read one extra byte from bus */
    			displ1 = cpu_consume_byte_from_mem(cpu_state);
    			/* Indirection with 8 bit displacement */
    			op->regmem_mem = displ1 + (*base_addr);
    			return;
    
    		case DISPLACEMENT_32:
    			/* Indirection with 32 bit displacement */
    
    			/* Attention: Lowest byte will be read first */
    			displacement_complete = cpu_consume_word_from_mem(cpu_state);
    			op->regmem_mem = displacement_complete + (*base_addr);
    			return;
    		case REGISTER:
    			op->regmem_reg = base_addr;
    			return;
    	}
    	return;
    }
    
    /*
     *  Reading and peeking functions
     */
    /** @brief read a register and return the high or low byte
     *
     * @param reg_addr  the address of the register to read
     * @param is_high   whether to return the high byte
     *
     * @return the byte read
     */
    static uint8_t
    cpu_read_byte_from_reg(uint32_t *reg_addr, bool is_high) {
    	if(is_high) {
    		return (*reg_addr >> 8) & 0xff;
    	}
    
    	return *reg_addr & 0xff;
    }
    
    /** @brief read a register and return the word
     *
     * @param reg_addr  the address of the register to read
     *
     * @return the byte read
     */
    static uint32_t
    cpu_read_word_from_reg(uint32_t *reg_addr) {
    	return *reg_addr;
    }
    
    /** @brief read byte at the instruction pointer's address from memory and increment IP
     *
     * @param cpu_state CPU instance
     *
     * @return the byte read
     */
    static uint8_t
    cpu_consume_byte_from_mem(cpu_state *cpu_state) {
    	uint8_t next_byte = sig_host_bus_readb(cpu_state->port_host, (void *)cpu_state, cpu_state->eip);
    	cpu_state->eip = cpu_state->eip + 1;
    
    	return next_byte;
    }
    
    /** @brief read a word (4 byte) at the instruction pointer's address from memory
     *         and increment IP by 4
     *
     * @param cpu_state CPU instance
     *
     * @return the word read
     */
    static uint32_t
    cpu_consume_word_from_mem(cpu_state *cpu_state) {
    	uint8_t displ1, displ2, displ3, displ4;
    	uint32_t displacement_complete;
    
    	displ1 = cpu_consume_byte_from_mem(cpu_state);
    	displ2 = cpu_consume_byte_from_mem(cpu_state);
    	displ3 = cpu_consume_byte_from_mem(cpu_state);
    	displ4 = cpu_consume_byte_from_mem(cpu_state);
    
    	displacement_complete = displ1;
    	displacement_complete |= (displ2 << 8);
    	displacement_complete |= (displ3 << 16);
    	displacement_complete |= (displ4 << 24);
    
    	return displacement_complete;
    }
    
    /** @brief read byte at given address from memory. keeps IP untouched.
     *
     * @param cpu_state CPU instance
     * @param mem_addr  the address to read at
     *
     * @return the byte read
     */
    static uint8_t
    cpu_read_byte_from_mem(cpu_state *cpu_state, uint32_t mem_addr) {
    	return sig_host_bus_readb(cpu_state->port_host, cpu_state, mem_addr);
    }
    
    /** @brief read a word (4 byte) at given address from memory. keeps IP untouched.
     *
     * @param cpu_state CPU instance
     * @param mem_addr  the address to read at
     *
     * @return the word read
     */
    static uint32_t
    cpu_read_word_from_mem(cpu_state *cpu_state, uint32_t mem_addr) {
    
    	uint32_t data = 0;
    	uint8_t byte1, byte2, byte3, byte4;
    	byte1 = sig_host_bus_readb(cpu_state->port_host, cpu_state, mem_addr);
    	mem_addr++;
    
    	byte2 = sig_host_bus_readb(cpu_state->port_host, cpu_state, mem_addr);
    	mem_addr++;
    
    	byte3 = sig_host_bus_readb(cpu_state->port_host, cpu_state, mem_addr);
    	mem_addr++;
    
    	byte4 = sig_host_bus_readb(cpu_state->port_host, cpu_state, mem_addr);
    
    	data = byte1;
    	data |= (byte2 << 8);
    	data |= (byte3 << 16);
    	data |= (byte4 << 24);
    
    	return data;
    }
    
    
    /*
     *  Writing functions
     */
    
    /** @brief write a byte to a register's high or low byte
     *
     * @param reg_addr  the address of the register to read
     * @param byte      the byte to write
     * @param is_high   whether to write the high byte
     */
    static void
    cpu_write_byte_in_reg(uint32_t *reg_addr, uint8_t byte, bool is_high) {
    	if(!is_high) {
    		*reg_addr &= ~0xff;
    		*reg_addr |= byte;
    	} else {
    		*reg_addr &= ~0xff00;
    		*reg_addr |= (byte << 8);
    
    	}
    }
    
    /** @brief write a word (4 byte) to a register
     *
     * @param word      the word to write
     * @param reg_addr  the address of the register to read
     */
    static void
    cpu_write_word_in_reg(uint32_t *reg_addr, uint32_t word) {
    	*reg_addr = word;
    }
    
    /** @brief write a byte to the memory
     *
     * @param cpu_state  the cpu instance
     * @param byte       the byte to write
     * @param mem_addr   the address in the mem to write to
     */
    static void
    cpu_write_byte_in_mem(cpu_state *cpu_state, uint8_t byte, uint32_t mem_addr) {
    	sig_host_bus_writeb(cpu_state->port_host, cpu_state, mem_addr, byte);
    }
    
    /** @brief write a word (4 byte) to the memory
     *
     * @param cpu_state  the cpu instance
     * @param word       the word to write
     * @param mem_addr   the address in memory to write to
     */
    static void
    cpu_write_word_in_mem(cpu_state *cpu_state, uint32_t word, uint32_t mem_addr) {
    	uint8_t byte = word & 0xff;
    
    	sig_host_bus_writeb(cpu_state->port_host, cpu_state, mem_addr, byte);
    	byte = (word >> 8) & 0xff;
    	mem_addr++;
    
    	sig_host_bus_writeb(cpu_state->port_host, cpu_state, mem_addr, byte);
    	byte = (word >> 16) & 0xff;
    	mem_addr++;
    
    	sig_host_bus_writeb(cpu_state->port_host, cpu_state, mem_addr, byte);
    	byte = (word >> 24) & 0xff;
    	mem_addr++;
    
    	sig_host_bus_writeb(cpu_state->port_host, cpu_state, mem_addr, byte);
    }
    
    /** @brief Save byte on stack and decrements stack pointer afterwards
     *
     *  @param cpu_state is the cpu instance
     *  @param byte that get pushed on stack
     */
    static void cpu_stack_push_byte(cpu_state *cpu_state, uint8_t byte){
    	/* Decrement first to assert that esp points
    	 * on the last pushed byte
    	 */
    	cpu_state->esp--;
    	cpu_write_byte_in_mem(cpu_state, byte, cpu_state->esp);
    }
    
    /** @brief Save doubleword on stack and decrements stack pointer
     *         afterwards. The most significant byte
     *         get pushed first (on the higher address).
     *
     *  @param cpu_state is the cpu instance
     *  @param doubleword that get pushed on stack
     */
    static void cpu_stack_push_doubleword(cpu_state *cpu_state, uint32_t doubleword){
    	uint8_t byte = 0;
    	byte = (doubleword >> 24) & 0xff;
    	cpu_stack_push_byte(cpu_state, byte);
    
    	byte = (doubleword >> 16) & 0xff;
    	cpu_stack_push_byte(cpu_state, byte);
    
    	byte = (doubleword >> 8) & 0xff;
    	cpu_stack_push_byte(cpu_state, byte);
    
    	byte = doubleword & 0xff;
    	cpu_stack_push_byte(cpu_state, byte);
    }
    
    /** @brief Read byte from stack and increments stack pointer afterwards
     *
     *  @param cpu_state is the cpu instance
     *
     *  @return byte on stack
     */
    static uint8_t cpu_stack_pop_byte(cpu_state *cpu_state){
    	uint8_t byte = cpu_read_byte_from_mem(cpu_state, cpu_state->esp);
    	cpu_state->esp++;
    	return byte;
    }
    
    /** @brief Read doubleword from stack and increments stack pointer afterwards.
     *         Least significant byte is read first.
     *
     *  @param cpu_state is the cpu instance
     *
     *  @return doubleword on stack
     */
    static uint32_t cpu_stack_pop_doubleword(cpu_state *cpu_state){
    	uint32_t dw = 0;
    	uint8_t byte0, byte1, byte2, byte3;
    
    	byte0 = cpu_stack_pop_byte(cpu_state);
    	byte1 = cpu_stack_pop_byte(cpu_state);
    	byte2 = cpu_stack_pop_byte(cpu_state);
    	byte3 = cpu_stack_pop_byte(cpu_state);
    
    	dw  = byte0;
    	dw |= (byte1 << 8);
    	dw |= (byte2 << 16);
    	dw |= (byte3 << 24);
    
    	return dw;
    }
    
    bool
    cpu_step(void *_cpu_state) {
    	/* cast */
    	cpu_state *cpu_state = (struct cpu_state *) _cpu_state;
    
    	uint8_t op_code = 0;
    
    	/* read the first byte from instruction pointer and increment ip
    	 * afterards */
    	op_code = cpu_consume_byte_from_mem(cpu_state);
    
    	op_addr s_op;
    	memset(&s_op, 0, sizeof(op_addr));
    
    	#ifdef DEBUG_PRINT_INST_ADDR
    		#ifdef DEBUG_PRINT_INST
    			fprintf(stderr, "Instruction (%#08x): %#x   ", cpu_state->eip, op_code);
    		#else
    			fprintf(stderr, "Instruction (%#08x): %#x\n", cpu_state->eip, op_code);
    		#endif
    	#endif
    
    	switch(op_code) {
    		#include "instructionBlocks/cpu_addInst.c"
    
    		#include "instructionBlocks/cpu_compareInst.c"
    
    		#include "instructionBlocks/cpu_jumpInst.c"
    
    		#include "instructionBlocks/cpu_moveInst.c"
    
    		#include "instructionBlocks/cpu_specialInst.c"
    
    		#include "instructionBlocks/cpu_stackInst.c"
    
    		#include "instructionBlocks/cpu_xorInst.c"
    
    		#include "instructionBlocks/cpu_incInst.c"
    
    		#include "instructionBlocks/cpu_decInst.c"
    
    		#include "instructionBlocks/cpu_hltInst.c"
    
    
    		default:
    			fprintf(stderr, "Unknown op-code: 0x%02x\n", op_code);
    			break;
    	}
    	return false;
    }
    
    
    
    /** @brief nop - cpu does not support reading via bus
    */
    static bool
    cpu_readb(void *_cpu_state, uint32_t addr, uint8_t *valp) {
    	/* We dont read from CPU */
    
    	return false;
    }
    
    /** @brief nop - cpu does not support writing via bus
    */
    static bool
    cpu_writeb(void *_cpu_state, uint32_t addr, uint8_t val) {
    	/* We dont write into CPU */
    
    	return false;
    }
    /* vim: set tabstop=4 softtabstop=4 shiftwidth=4 noexpandtab : */