Exemplo n.º 1
0
uint8_t execute_interpreter_cycle(cpu_registers* registers, bool nmi_flag) {
    static bool previous_nmi_flag = false;
    uint8_t cpu_cycles_executed = 0;
    uint8_t extra_cycles= 0;

    if(DMA_is_executing()) cpu_cycles_executed = execute_DMA();
    else {
        uint8_t opcode = fetch_opcode(registers);
        increment_PC(registers);

        if(nmi_flag && !previous_nmi_flag) cpu_cycles_executed = execute_NMI(registers);
        else {
            #ifdef DEBUG
                print_debug_info(registers, opcode);
            #endif
            extra_cycles = execute_instruction(registers, opcode);
            cpu_cycles_executed = instruction_cycle_length[opcode] + extra_cycles;
            // Do not increment PC if we jump because it will skip the first instruction at least
            if(!is_JSR_or_JMP(opcode) && !is_RTI(opcode)) increment_PC_instruction_length(registers, opcode);
        }
    }

    previous_nmi_flag = nmi_flag;
    odd_cpu_cycle = cpu_cycles_executed & 0x1;

    return cpu_cycles_executed;
}
//Executes all commmands stored in 'command_arr'.
void execute_set_of_instructions(COMMAND* commands_arr, int* registers_arr, byte* mem, int* current_time, CONFIG* config, L1_CACHE* L1_cache, L2_CACHE* L2_cache ){
	int instruction_counter = 1;
	int pc = 0;
	unsigned tag_L1;
	unsigned index_L1;
	unsigned offset_L1;
	unsigned tag_L2;
	unsigned index_L2;
	unsigned offset_L2;
	int way;
	int mem_to_L2_end_time_last_trans;
	
	while (strcmp(commands_arr[pc].cmd_type, "H") != 0){
		parse_address(&offset_L1, &index_L1, &tag_L1, commands_arr[pc].inst_address, config->l1_block_size, config->l1_cache_size);
		parse_address(&offset_L2, &index_L2, &tag_L2, commands_arr[pc].inst_address, config->l2_block_size, config->l2_cache_size);
		
		if (!is_in_L1(index_L1, tag_L1,offset_L1,L1_cache, current_time, config)){
			if (is_in_L2(index_L2, tag_L2,offset_L2,L2_cache,current_time,config)){
				L2_to_L1_trans(L1_cache, offset_L1,index_L1,tag_L1,L2_cache,offset_L2,index_L2,tag_L2,*current_time,config,way,true);
			}else{
				MEM_to_L2_trans(mem, L2_cache, offset_L2, index_L2, tag_L2,*current_time,config,NULL,way,true);
				way = !L2_cache->block_arr[index_L2].LRU;
				mem_to_L2_end_time_last_trans = L2_cache->block_arr[index_L2].block_trans_end_time[way];
				L2_to_L1_trans(L1_cache, offset_L1,index_L1,tag_L1,L2_cache,offset_L2,index_L2,tag_L2,mem_to_L2_end_time_last_trans,config,way,true);
			}
		}

		execute_instruction(commands_arr[pc], commands_arr, registers_arr, mem, &pc);
		instruction_counter++;
	}

}
void execute(Processor *processor,int prompt,int print) {
    Instruction instruction;
    
    /* fetch an instruction */
    instruction.bits = load(memory,processor->PC,LENGTH_WORD);
    
    /* interactive-mode prompt */
    if(prompt) {
        if(prompt==1) {
            printf("simulator paused,enter to continue...");
            while(getchar()!='\n');
        }
        printf("%08x: ",processor->PC);
        decode_instruction(instruction);
    }
    
    execute_instruction(instruction,processor,memory);
    
    // enforce $0 being hard-wired to 0
    processor->R[0] = 0;
    
    // print trace
    if(print) {
        int i,j;
        for(i=0;i<8;i++) {
            for(j=0;j<4;j++) {
                printf("r%2d=%08x ",i*4+j,processor->R[i*4+j]);
            }
            puts("");
        }
    }
}
Exemplo n.º 4
0
/* Simulate the code and output results to standard out */
void simulate(Instruction* code)
{
    Change* list_of_effects = NULL; 
    Change* last_effect = NULL;
    Change* new_effects;
    int instruction_count = 0;
    int operation_count = 0;
    int vect_operation_count = 0; /* Number of operations that can be vectorized. Uli  04/13/2011 */
    int cycle_count = 0;

    while(code)
    {
	if (!((memory_stall(code,list_of_effects) && stall_on_memory) ||
	      (register_stall(code,list_of_effects) && stall_on_registers) ||
	      (branch_stall(list_of_effects) && stall_on_branches)))
	{
	    if (!check_machine_constraints(code))
	    {
		fprintf(stderr,"Error: Machine constraints violated.\n");
		exit(1);
	    }
		
	    new_effects = execute_instruction(code,&operation_count,&vect_operation_count);
	    instruction_count++;

	    if (!list_of_effects)
	    {
		list_of_effects = new_effects;
		last_effect = new_effects;
	    }
	    else
		last_effect->next = new_effects;

	    /* Move last effect to end */
	    if (last_effect)
		while(last_effect->next)
		    last_effect = last_effect->next;

	    /* Go to next instruction */
	    code = code->next;
	}
	
	list_of_effects = execute_changes(list_of_effects,&last_effect,&code);
	cycle_count++;

    }

    while(list_of_effects)
    {
	list_of_effects = execute_changes(list_of_effects,&last_effect,&code);
	cycle_count++;
    }

    fprintf(stdout,"Executed %d instructions and %d operations in %d cycles.\n",
	    instruction_count,operation_count,cycle_count);
    fprintf(stdout,"Executed %d vectorizable operations (%d percent of overall executed operations).\n",
	    vect_operation_count, (int) floor(((double) vect_operation_count / (double) operation_count) * 100));

}
Exemplo n.º 5
0
void process_instruction(){
  // update stage
  write_back();
  if( if_register.stall == 0 ) {
    instruction_fetch();
  } else {
    if_register.stall += -1;
  }
  instruction_decode();
  execute_instruction();
  memory_access();
  btb_move_right();
  int index =  (CURRENT_STATE.PC - MEM_TEXT_START - 4)/4 ;
//  printf(" index %d, NUM_INST %d \n",index,NUM_INST);
  if( index == NUM_INST ) {
    CURRENT_STATE.PC += -4;
//    printf("Run bit unset pc: %x\n",CURRENT_STATE.PC);
  }
}
Exemplo n.º 6
0
/*
 * Creates memeory for the program to run and gets the instruction code along
 * with the registers.
 */
void build_and_execute_um(FILE* program){
    memorySegments = newMem();
    instantiateMem(memorySegments, INITIAL_SET_SIZE);
    initializeRegisters(registers, numRegisters);

    mapProgram(program);
    programCounter = 0;
    numInstructions = instructionLength(); 
    //programPointer = getInstructions(memorySegments);

    while(programCounter < numInstructions){
        UM_Word instruction = getInstruction(programCounter);
        Instruction instr = parseInstruction(instruction);
        execute_instruction(instr);
        if(instr.op == HALT) break;
    }

    freeMem(memorySegments);
}
Exemplo n.º 7
0
inline void cosmac_device::run()
{
	output_state_code();

	switch (m_state)
	{
	case COSMAC_STATE_0_FETCH:
		fetch_instruction();
		break;

	case COSMAC_STATE_1_RESET:
		reset();
		debug();
		break;

	case COSMAC_STATE_1_INIT:
		initialize();
		debug();
		break;

	case COSMAC_STATE_1_EXECUTE:
		sample_ef_lines();
		execute_instruction();
		debug();
		break;

	case COSMAC_STATE_2_DMA_IN:
		dma_input();
		break;

	case COSMAC_STATE_2_DMA_OUT:
		dma_output();
		break;

	case COSMAC_STATE_3_INT:
		interrupt();
		debug();
		break;
	}
}
Exemplo n.º 8
0
void ick_iffi_interpreter_one_iteration(void)
{
	funge_cell opcode;
	opcode = fungespace_get(&iffiIP->position);

	if (setting_trace_level > 8) {
		fprintf(stderr, "x=%" FUNGECELLPRI " y=%" FUNGECELLPRI
				": %c (%" FUNGECELLPRI ")\n",
				iffiIP->position.x, iffiIP->position.y, (char)opcode, opcode);
		stack_print_top(iffiIP->stack);
	} else if (setting_trace_level > 3) {
		fprintf(stderr, "x=%" FUNGECELLPRI " y=%" FUNGECELLPRI
				": %c (%" FUNGECELLPRI ")\n",
				iffiIP->position.x, iffiIP->position.y, (char)opcode, opcode);
	} else if (setting_trace_level > 2)
		fprintf(stderr, "%c", (char)opcode);

	execute_instruction(opcode, iffiIP);
	if (iffiIP->needMove)
		ip_forward(iffiIP);
	else
		iffiIP->needMove = true;
}
Exemplo n.º 9
0
int process_block(struct self_s *self, struct process_state_s *process_state, uint64_t inst_log_prev, uint64_t eip_offset_limit) {
	uint64_t offset = 0;
	int result;
	int n, m, l;
	int err;
	int found;
	struct inst_log_entry_s *inst_exe_prev;
	struct inst_log_entry_s *inst_exe;
	struct inst_log_entry_s *inst_log_entry = self->inst_log_entry;
	struct instruction_s *instruction = NULL;
	int instruction_offset = 0;
	int octets = 0;
	//struct memory_s *memory_text;
	//struct memory_s *memory_stack;
	struct memory_s *memory_reg;
	//struct memory_s *memory_data;
	struct dis_instructions_s dis_instructions;
	int *memory_used;
	struct entry_point_s *entry = self->entry_point;
	uint64_t list_length = self->entry_point_list_length;
	void *handle_void = self->handle_void;

	//memory_text = process_state->memory_text;
	//memory_stack = process_state->memory_stack;
	memory_reg = process_state->memory_reg;
	//memory_data = process_state->memory_data;
	memory_used = process_state->memory_used;

	debug_print(DEBUG_EXE, 1, "process_block entry\n");
	debug_print(DEBUG_EXE, 1, "inst_log=%"PRId64"\n", inst_log);
	debug_print(DEBUG_EXE, 1, "dis:Data at %p, size=0x%"PRIx64"\n", inst, inst_size);
	for (offset = 0; ;) {
	//for (offset = 0; offset < inst_size;
			//offset += dis_instructions.bytes_used) {
		/* Update EIP */
		offset = memory_reg[2].offset_value;
		if (offset >= eip_offset_limit) {
			debug_print(DEBUG_EXE, 1, "Over ran offset=0x%"PRIx64" >= eip_offset_limit=0x%"PRIx64" \n",
				offset, eip_offset_limit);
			return 1;
		}
		dis_instructions.instruction_number = 0;
		dis_instructions.bytes_used = 0;
		debug_print(DEBUG_EXE, 1, "eip=0x%"PRIx64", offset=0x%"PRIx64"\n",
			memory_reg[2].offset_value, offset);
		/* the calling program must define this function. This is a callback. */
		result = disassemble(self, &dis_instructions, inst, inst_size, offset);
		debug_print(DEBUG_EXE, 1, "bytes used = %d\n", dis_instructions.bytes_used);
		debug_print(DEBUG_EXE, 1, "eip=0x%"PRIx64", offset=0x%"PRIx64"\n",
			memory_reg[2].offset_value, offset);
		/* Memory not used yet */
		if (0 == memory_used[offset]) {
			debug_print(DEBUG_EXE, 1, "Memory not used yet\n");
			for (n = 0; n < dis_instructions.bytes_used; n++) {
				memory_used[offset + n] = -n;
				debug_print(DEBUG_EXE, 1, " 0x%02x\n", inst[offset + n]);
			}
			debug_print(DEBUG_EXE, 1, "\n");
			memory_used[offset] = inst_log;
		} else {
			int inst_this = memory_used[offset];
			if (inst_this < 0) {
				/* FIXME: What to do in this case? */
				/* problem caused by rep movs instruction */
				debug_print(DEBUG_EXE, 1, "process_block:line110:FIXME:Not a valid instuction %d at eip offset 0x%"PRIx64"\n", inst_this, offset);
			}
			/* If value == maxint, then it is the destination of a jump */
			/* But I need to separate the instruction flows */
			/* A jump/branch inst should create a new instruction tree */
			debug_print(DEBUG_EXE, 1, "Memory already used\n");
			inst_exe_prev = &inst_log_entry[inst_log_prev];
			inst_exe = &inst_log_entry[inst_this];
			debug_print(DEBUG_EXE, 1, "inst_exe_prev=%p, inst_exe=%p\n",
				inst_exe_prev, inst_exe);
			inst_exe->prev_size++;
			if (inst_exe->prev_size == 1) {
				inst_exe->prev = malloc(sizeof(inst_exe->prev));
			} else {
				inst_exe->prev = realloc(inst_exe->prev, sizeof(inst_exe->prev) * inst_exe->prev_size);
			}
			inst_exe->prev[inst_exe->prev_size - 1] = inst_log_prev;
			if (inst_exe_prev->next_size > 0) {
				debug_print(DEBUG_EXE, 1, "JCD8a: next_size = 0x%x\n", inst_exe_prev->next_size);
			}
			if (inst_exe_prev->next_size == 0) {
				inst_exe_prev->next_size++;
				inst_exe_prev->next = malloc(sizeof(inst_exe_prev->next));
				inst_exe_prev->next[inst_exe_prev->next_size - 1] = inst_this;
			} else {
				found = 0;
				for (l = 0; l < inst_exe_prev->next_size; l++) {
					if (inst_exe_prev->next[inst_exe_prev->next_size - 1] == inst_this) {
						found = 1;
						break;
					}
				}
				if (!found) {
					inst_exe_prev->next_size++;
					if (inst_exe_prev->next_size > 2) {
						debug_print(DEBUG_EXE, 1, "process_block: next_size = %d, inst = 0x%x\n", inst_exe_prev->next_size, inst_this);
					}
					inst_exe_prev->next = realloc(inst_exe_prev->next, sizeof(inst_exe_prev->next) * inst_exe_prev->next_size);
					inst_exe_prev->next[inst_exe_prev->next_size - 1] = inst_this;
				}
			}
			break;
		}	
		//debug_print(DEBUG_EXE, 1, "disassemble_fn\n");
		//disassemble_fn = disassembler (handle->bfd);
		//debug_print(DEBUG_EXE, 1, "disassemble_fn done\n");
		debug_print(DEBUG_EXE, 1, "disassemble att  : ");
		bf_disassemble_set_options(handle_void, "att");
		bf_disassemble_callback_start(handle_void);
		octets = bf_disassemble(handle_void, offset);
		bf_disassemble_callback_end(handle_void);
		debug_print(DEBUG_EXE, 1, "  octets=%d\n", octets);
		debug_print(DEBUG_EXE, 1, "disassemble intel: ");
		bf_disassemble_set_options(handle_void, "intel");
		bf_disassemble_callback_start(handle_void);
		octets = bf_disassemble(handle_void, offset);
		bf_disassemble_callback_end(handle_void);
		debug_print(DEBUG_EXE, 1, "  octets=%d\n", octets);
		if (dis_instructions.bytes_used != octets) {
			debug_print(DEBUG_EXE, 1, "Unhandled instruction. Length mismatch. Got %d, expected %d, Exiting\n", dis_instructions.bytes_used, octets);
			return 1;
		}
		/* Update EIP */
		memory_reg[2].offset_value += octets;

		debug_print(DEBUG_EXE, 1, "Number of RTL dis_instructions=%d\n",
			dis_instructions.instruction_number);
		if (result != 0) {
			debug_print(DEBUG_EXE, 1, "Unhandled instruction. Exiting\n");
			return 1;
		}
		if (dis_instructions.instruction_number == 0) {
			debug_print(DEBUG_EXE, 1, "NOP instruction. Get next inst\n");
			continue;
		}
		for (n = 0; n < dis_instructions.instruction_number; n++) {
			instruction = &dis_instructions.instruction[n];
			debug_print(DEBUG_EXE, 1,  "Printing inst1111:0x%x, 0x%x, 0x%"PRIx64"\n",instruction_offset, n, inst_log);
			err = print_inst(self, instruction, instruction_offset + n + 1, NULL);
			if (err) {
				debug_print(DEBUG_EXE, 1, "print_inst failed\n");
				return err;
			}
			inst_exe_prev = &inst_log_entry[inst_log_prev];
			inst_exe = &inst_log_entry[inst_log];
			memcpy(&(inst_exe->instruction), instruction, sizeof(struct instruction_s));
			err = execute_instruction(self, process_state, inst_exe);
			if (err) {
				debug_print(DEBUG_EXE, 1, "execute_intruction failed err=%d\n", err);
				return err;
			}
			inst_exe->prev_size++;
			if (inst_exe->prev_size == 1) {
				inst_exe->prev = malloc(sizeof(inst_exe->prev));
			} else {
				inst_exe->prev = realloc(inst_exe->prev, sizeof(inst_exe->prev) * inst_exe->prev_size);
			}
			inst_exe->prev[inst_exe->prev_size - 1] = inst_log_prev;
			inst_exe_prev->next_size++;
			if (inst_exe_prev->next_size > 2) {
				debug_print(DEBUG_EXE, 1, "process_block:line203: next_size = %d, inst = 0x%"PRIx64"\n", inst_exe_prev->next_size, inst_log);
			}
			if (inst_exe_prev->next_size > 1) {
				debug_print(DEBUG_EXE, 1, "JCD8b: next_size = 0x%x\n", inst_exe_prev->next_size);
			}
			if (inst_exe_prev->next_size == 1) {
				inst_exe_prev->next = malloc(sizeof(inst_exe_prev->next));
				inst_exe_prev->next[inst_exe_prev->next_size - 1] = inst_log;
			} else {
				inst_exe_prev->next = realloc(inst_exe_prev->next, sizeof(inst_exe_prev->next) * inst_exe_prev->next_size);
				inst_exe_prev->next[inst_exe_prev->next_size - 1] = inst_log;
			}
			inst_exe_prev->next[inst_exe_prev->next_size - 1] = inst_log;

			if (IF == instruction->opcode) {
				debug_print(DEBUG_EXE, 1, "IF FOUND\n");
				//debug_print(DEBUG_EXE, 1, "Breaking at IF\n");
				debug_print(DEBUG_EXE, 1, "IF: this EIP = 0x%"PRIx64"\n",
					memory_reg[2].offset_value);
				debug_print(DEBUG_EXE, 1, "IF: jump dst abs EIP = 0x%"PRIx64"\n",
					inst_exe->value3.offset_value);
				debug_print(DEBUG_EXE, 1, "IF: inst_log = %"PRId64"\n",
					inst_log);
				for (m = 0; m < list_length; m++ ) {
					if (0 == entry[m].used) {
						entry[m].esp_init_value = memory_reg[0].init_value;
						entry[m].esp_offset_value = memory_reg[0].offset_value;
						entry[m].ebp_init_value = memory_reg[1].init_value;
						entry[m].ebp_offset_value = memory_reg[1].offset_value;
						entry[m].eip_init_value = memory_reg[2].init_value;
						entry[m].eip_offset_value = memory_reg[2].offset_value;
						entry[m].previous_instuction = inst_log;
						entry[m].used = 1;
						debug_print(DEBUG_EXE, 1, "JCD:8 used 1\n");
						
						break;
					}
				}
				/* FIXME: Would starting a "m" be better here? */
				for (m = 0; m < list_length; m++ ) {
					if (0 == entry[m].used) {
						entry[m].esp_init_value = memory_reg[0].init_value;
						entry[m].esp_offset_value = memory_reg[0].offset_value;
						entry[m].ebp_init_value = memory_reg[1].init_value;
						entry[m].ebp_offset_value = memory_reg[1].offset_value;
						entry[m].eip_init_value = inst_exe->value3.init_value;
						entry[m].eip_offset_value = inst_exe->value3.offset_value;
						entry[m].previous_instuction = inst_log;
						entry[m].used = 1;
						debug_print(DEBUG_EXE, 1, "JCD:8 used 2\n");
						break;
					}
				}
			}
			if (JMPT == instruction->opcode) {
				/* FIXME: add the jump table detection here */
				uint64_t inst_base;
				int tmp;
				struct inst_log_entry_s *inst_exe_base;
				struct instruction_s *instruction = NULL;
				int relocation_area;
				uint64_t relocation_index;
				tmp = search_for_jump_table_base(self, inst_log, &inst_base);
				if (tmp) {
					debug_print(DEBUG_EXE, 1, "FIXME: JMPT reached..exiting %d 0x%"PRIx64"\n", tmp, inst_base);
					exit(1);
				}
				inst_exe_base = &inst_log_entry[inst_base];
				instruction = &(inst_exe_base->instruction);
				debug_print(DEBUG_EXE, 1, "Relocated = 0x%x\n", instruction->srcB.relocated);
				debug_print(DEBUG_EXE, 1, "Relocated_area = 0x%x\n", instruction->srcB.relocated_area);
				debug_print(DEBUG_EXE, 1, "Relocated_index = 0x%x\n", instruction->srcB.relocated_index);
				if (2 == instruction->srcB.relocated_area) {
					uint64_t index = instruction->srcB.relocated_index;
					tmp = 0;
					
					do {
						tmp = bf_find_relocation_rodata(handle_void, index, &relocation_area, &relocation_index);
						if (!tmp) {
							if (1 != relocation_area) {
								debug_print(DEBUG_EXE, 1, "JMPT Relocation area not to code\n");
								exit(1);
							}
							for (m = 0; m < list_length; m++ ) {
								if (0 == entry[m].used) {
									entry[m].esp_init_value = memory_reg[0].init_value;
									entry[m].esp_offset_value = memory_reg[0].offset_value;
									entry[m].ebp_init_value = memory_reg[1].init_value;
									entry[m].ebp_offset_value = memory_reg[1].offset_value;
									entry[m].eip_init_value = 0;
									entry[m].eip_offset_value = relocation_index;
									entry[m].previous_instuction = inst_log;
									entry[m].used = 1;
									debug_print(DEBUG_EXE, 1, "JMPT new entry \n");
									break;
								}
							}
						} else {
							debug_print(DEBUG_EXE, 1, "JMPT index, 0x%"PRIx64", not found in rodata relocation table\n", index);
						}
						index += 8;
					} while (!tmp);
				}
			}
			inst_log_prev = inst_log;
			inst_log++;
			if (0 == memory_reg[2].offset_value) {
				debug_print(DEBUG_EXE, 1, "Function exited\n");
				if (inst_exe_prev->instruction.opcode == NOP) {
					inst_exe_prev->instruction.opcode = RET;
				}
				break;
			}
			if (JMPT == instruction->opcode) {
				debug_print(DEBUG_EXE, 1, "Function exited. Temporary action for JMPT\n");
				break;
			}
		}
		instruction_offset += dis_instructions.instruction_number;
		if (0 == memory_reg[2].offset_value) {
			debug_print(DEBUG_EXE, 1, "Breaking\n");
			break;
		}
		if (instruction && (JMPT == instruction->opcode)) {
			debug_print(DEBUG_EXE, 1, "Function exited. Temporary action for JMPT\n");
			break;
		}
#if 0
		if (IF == instruction->opcode) {
			debug_print(DEBUG_EXE, 1, "Breaking at IF\n");
			debug_print(DEBUG_EXE, 1, "IF: this EIP = 0x%"PRIx64"\n",
				memory_reg[2].offset_value);
			debug_print(DEBUG_EXE, 1, "IF: jump dst abs EIP = 0x%"PRIx64"\n",
				inst_exe->value3.offset_value);
			debug_print(DEBUG_EXE, 1, "IF: inst_log = %"PRId64"\n",
				inst_log);
			for (n = 0; n < list_length; n++ ) {
				if (0 == entry[n].used) {
					entry[n].esp_init_value = memory_reg[0].init_value;
					entry[n].esp_offset_value = memory_reg[0].offset_value;
					entry[n].ebp_init_value = memory_reg[1].init_value;
					entry[n].ebp_offset_value = memory_reg[1].offset_value;
					entry[n].eip_init_value = memory_reg[2].init_value;
					entry[n].eip_offset_value = memory_reg[2].offset_value;
					entry[n].previous_instuction = inst_log - 1;
					entry[n].used = 1;
					break;
				}
			}
			/* FIXME: Would starting a "n" be better here? */
			for (n = 0; n < list_length; n++ ) {
				if (0 == entry[n].used) {
					entry[n].esp_init_value = memory_reg[0].init_value;
					entry[n].esp_offset_value = memory_reg[0].offset_value;
					entry[n].ebp_init_value = memory_reg[1].init_value;
					entry[n].ebp_offset_value = memory_reg[1].offset_value;
					entry[n].eip_init_value = inst_exe->value3.init_value;
					entry[n].eip_offset_value = inst_exe->value3.offset_value;
					entry[n].previous_instuction = inst_log - 1;
					entry[n].used = 1;
					break;
				}
			}
			break;
		}
#endif
	}
	return 0;
}