/** * A utility function to avoid duplication when testing pop() implementations. * * @param push_value TODO * @param pop_mode TODO * @param storage_location TODO * @param source_location TODO */ void pop_test_util(uint32_t push_value, uint8_t pop_mode, uint32_t storage_location, int source_location) { allocate(); push(push_value); if (source_location == SOURCE_IMMEDIATE) { store_dword(ram, NEXT_INSTR, NEXT2_INSTR); if (storage_location == NEXT3_INSTR) store_dword(ram, NEXT2_INSTR, NEXT3_INSTR); exec(create_instruction(INSTR_POP, pop_mode, EMPTY_BYTE, EMPTY_BYTE)); } else { // We can point the register to next instruction by default r[TEST_REGISTER] = NEXT_INSTR; if (storage_location == NEXT2_INSTR) store_dword(ram, NEXT_INSTR, NEXT2_INSTR); exec(create_instruction(INSTR_POP, pop_mode, EMPTY_BYTE, TEST_REGISTER)); } if (storage_location == REGISTER_LOCATION) { CU_ASSERT(push_value == r[TEST_REGISTER]); } else { switch (push_value) { case DUMMY_VALUE_32: CU_ASSERT(push_value == get_dword(ram, storage_location)); break; case DUMMY_VALUE_16: CU_ASSERT(push_value == get_word(ram, storage_location)); break; case DUMMY_VALUE_8: CU_ASSERT(push_value == get_byte(ram, storage_location)); break; default: CU_FAIL("Invalid push_value"); } } deallocate(); }
/** * Tests 'isntr_exit()'. */ void test_instr_exit() { allocate(); CU_ASSERT(1 == exec(create_instruction(INSTR_EXIT, EMPTY_BYTE, EMPTY_BYTE, EMPTY_BYTE))); deallocate(); }
static token_list * zero_reg_op( token_list *t, int op ) { RW_Robo_Op new_op; /* Create instruction */ encode_op_regs(new_op, op_zero_reg, 0, 0, op); create_instruction(new_op); return t->next; }
static token_list * push_op( token_list *t ) { token_list *tok = t; int dest, reg; RW_Robo_Op new_op; /* Push can take a register, immediate, or label. This makes things a bit hairy, as we don't have an instruction for both immediates and registers. Therefor, we have two different instructions, and pick which one depending on what we got. */ tok = t->next; if( !tok ) { error = err_unexpected_eof; return NULL; } else if( tok->t == token_reg ) { reg = tok->value; encode_op_regs(new_op, op_one_reg, reg, 0, op_pushr); } else if( tok->t == token_num ) { dest = tok->value; encode_op_imme(new_op, op_push, dest); } else if( tok->t == token_label ) { dest = check_label(tok); encode_op_imme(new_op, op_push, dest); } else { error_line = tok->line_number; error = err_labelnumreg_expected; return NULL; } create_instruction(new_op); return tok->next; }
instruction* decode_mnemonic_instruction(char** tokens) { instruction* inst; inst = create_instruction(); char** tokens_tmp; int count = 0; tokens_tmp = tokens; inst->mnemonico = (char*)malloc(sizeof(strlen(*tokens_tmp)*sizeof(char))); strcpy(inst->mnemonico,*tokens_tmp); prepair_instruct_by_minemonic(&inst); int i; for (i = 1; i <= inst->qtd_op; i++) { if (i == 1) { inst->op1 = (char*)malloc(sizeof(strlen(*(tokens_tmp + i))*sizeof(char))); strcpy(inst->op1,*(tokens_tmp + i)); } else if (i == 2) { inst->op2 = (char*)malloc(sizeof(strlen(*(tokens_tmp + i))*sizeof(char))); strcpy(inst->op2,*(tokens_tmp + i)); } else if (i == 3) { inst->op3 = (char*)malloc(sizeof(strlen(*(tokens_tmp + i))*sizeof(char))); strcpy(inst->op2,*(tokens_tmp + i)); } } inst->type = 1; return inst; }
/** * Tests 'exec_program()'. */ void test_exec_program() { allocate(); uint32_t test_instructions[2] = { create_instruction(INSTR_NOOP, EMPTY_BYTE, EMPTY_BYTE, EMPTY_BYTE), create_instruction(INSTR_EXIT, EMPTY_BYTE, EMPTY_BYTE, EMPTY_BYTE)}; load_program(test_instructions, sizeof(test_instructions) / sizeof(test_instructions[0]), flash); exec_program(); // TODO: Maybe there is a better way to test this // This is a very trivial test just to check that the pc was incremented // after executing a no op CU_ASSERT(0 != pc); deallocate(); }
/** * Tests 'instr_noop' */ void test_instr_noop() { allocate(); exec(create_instruction(INSTR_NOOP, EMPTY_BYTE, EMPTY_BYTE, EMPTY_BYTE)); // TODO: Not sure what to test here, just checking that the PC // was incremented for now CU_ASSERT(INSTRUCTION_SIZE == pc); deallocate(); }
static void __init create_trampoline(unsigned long addr) { /* The maximum range of a single instruction branch, is the current * instruction's address + (32 MB - 4) bytes. For the trampoline we * need to branch to current address + 32 MB. So we insert a nop at * the trampoline address, then the next instruction (+ 4 bytes) * does a branch to (32 MB - 4). The net effect is that when we * branch to "addr" we jump to ("addr" + 32 MB). Although it requires * two instructions it doesn't require any registers. */ create_instruction(addr, 0x60000000); /* nop */ create_branch(addr + 4, addr + PHYSICAL_START, 0); }
static token_list * two_reg_op( token_list *t, int op ) { int reg1, reg2; RW_Robo_Op new_op; token_list *tok = t; /* Get reg1 */ tok = tok->next; if( !tok ) { error = err_unexpected_eof; return NULL; } else if( tok->t != token_reg ) { /* Syntax error */ error_line = tok->line_number; error = err_reg1_expected; return NULL; } reg1 = tok->value; /* Eat a comma, get reg2 or first immediate */ tok = tok->next; if( !tok ) { error = err_unexpected_eof; return NULL; } else if( tok->t != token_comma ) { /* Syntax error */ error_line = tok->line_number; error = err_comma_expected; return NULL; } tok = tok->next; if( !tok ) { error = err_unexpected_eof; return NULL; } else if( tok->t == token_reg ) { reg2 = tok->value; } else if( tok->t == token_num ) { reg2 = reg_a; create_mova(tok->value); } else { error_line = tok->line_number; error = err_regnum2_expected; return NULL; } /* Create instruction */ encode_op_regs(new_op, op_two_reg, reg1, reg2, op); create_instruction(new_op); return tok->next; }
/** * Tests 'copy_memory()'. */ void test_copy_memory() { allocate(); // We don't need to test a TON of ram... int num_instructions = (configured_ram_size / 2 > 1000) ? 1000 : configured_ram_size / 2; uint32_t instruction_array[num_instructions]; for (int i = 0; i < num_instructions; i++) { uint8_t *p_ram = ram + (i * INSTRUCTION_SIZE); instruction_array[i] = create_instruction(i, i, i, i); *((uint32_t *) p_ram) = instruction_array[i]; } // Find the next available ram int used_ram = INSTRUCTION_SIZE * num_instructions; uint8_t *p_dest = ram + used_ram; CU_ASSERT(0 == copy_memory(ram, p_dest, num_instructions)); int failed_match = 0; // Check the memory where we copied to and verify it is the same as the // source data for (int i = 0; i < num_instructions; i++) { if ((((uint32_t *) p_dest)[i] != instruction_array[i])) { failed_match = 1; break; } } CU_ASSERT(0 == failed_match); // Check that we can't write past our allocated RAM CU_ASSERT(1 == copy_memory(ram, p_dest + configured_ram_size, num_instructions)); deallocate(); }
static token_list * one_reg_op( token_list *t, int op ) { int reg1; RW_Robo_Op new_op; token_list *tok = t; /* Get reg1 */ tok = tok->next; if( !tok ) { error = err_unexpected_eof; return NULL; } else if( tok->t != token_reg ) { /* Syntax error */ error_line = tok->line_number; error = err_reg1_expected; return NULL; } reg1 = tok->value; /* Create instruction */ encode_op_regs(new_op, op_one_reg, reg1, 0, op); create_instruction(new_op); return tok->next; }
t_list *my_append_instruction(t_list *begin, char *str, int *label_nbr, int line_nbr) { t_list *new_element; t_list *tmp; char **args; if ((new_element = malloc(sizeof(t_list))) == NULL) exit(0); args = create_instruction(str, label_nbr, line_nbr, -1); new_element->args = args; new_element->argnbr = (args == NULL) ? 0 : my_getnbr(args[1]); new_element->line = line_nbr; new_element->octet = 0; new_element->next = NULL; if (begin == NULL) return (new_element); tmp = begin; while (tmp->next != NULL) tmp = tmp->next; tmp->next = new_element; return (begin); }
/** * A utility function to avoid duplication when testing push() implementations. * * @param pop_value TODO * @param push_mode TODO * @param storage_location TODO * @param source_location TODO */ void push_test_util(uint32_t pop_value, uint8_t push_mode, uint32_t storage_location, int source_location) { allocate(); if (storage_location != IMMEDIATE) { if (storage_location == NEXT2_INSTR) store_dword(ram, NEXT_INSTR, NEXT2_INSTR); if (source_location == SOURCE_IMMEDIATE && storage_location == NEXT3_INSTR) { store_dword(ram, NEXT_INSTR, NEXT2_INSTR); store_dword(ram, NEXT2_INSTR, NEXT3_INSTR); } else if (source_location == SOURCE_REGISTER) r[TEST_REGISTER] = NEXT_INSTR; } switch (pop_value) { case DUMMY_VALUE_8: if (source_location == SOURCE_IMMEDIATE) { store_byte(ram, storage_location, DUMMY_VALUE_8); exec(create_instruction(INSTR_PUSH, push_mode, EMPTY_BYTE, DUMMY_VALUE_8)); } else if (source_location == SOURCE_REGISTER) { if (storage_location == IMMEDIATE) r[TEST_REGISTER] = DUMMY_VALUE_8; else store_byte(ram, storage_location, DUMMY_VALUE_8); } break; case DUMMY_VALUE_16: if (source_location == SOURCE_IMMEDIATE) { store_word(ram, storage_location, DUMMY_VALUE_16); exec(create_instruction(INSTR_PUSH, push_mode, DUMMY_VALUE_8, DUMMY_VALUE_8)); } else if (source_location == SOURCE_REGISTER) { if (storage_location == IMMEDIATE) r[TEST_REGISTER] = DUMMY_VALUE_16; else store_word(ram, storage_location, DUMMY_VALUE_16); } break; case DUMMY_VALUE_32: if (source_location == SOURCE_IMMEDIATE) { store_dword(ram, storage_location, DUMMY_VALUE_32); exec(create_instruction(INSTR_PUSH, push_mode, EMPTY_BYTE, EMPTY_BYTE)); } else if (source_location == SOURCE_REGISTER) { if (storage_location == IMMEDIATE) r[TEST_REGISTER] = DUMMY_VALUE_32; else store_dword(ram, storage_location, DUMMY_VALUE_32); } break; default: CU_FAIL("Invalid pop_value"); } if (source_location == SOURCE_REGISTER) exec(create_instruction(INSTR_PUSH, push_mode, EMPTY_BYTE, TEST_REGISTER)); CU_ASSERT(pop_value == pop()); deallocate(); }
static token_list * branch_op( token_list *t ) { int reg, dest; RW_Robo_Op new_op; token_list *tok = t; int type = tok->t; /* Check if we need a test instruction */ if( tok->t != token_call && tok->t != token_jump ) { /* Get reg1 */ tok = tok->next; if( !tok ) { error = err_unexpected_eof; return NULL; } else if( tok->t != token_reg ) { /* Syntax error */ error_line = tok->line_number; error = err_reg1_expected; return NULL; } reg = tok->value; /* Create test instruction */ encode_op_regs(new_op, op_one_reg, reg, 0, op_test); create_instruction(new_op); /* Eat comma */ tok = tok->next; if( !tok ) { error = err_unexpected_eof; return NULL; } else if( tok->t != token_comma ) { /* Syntax error */ error_line = tok->line_number; error = err_comma_expected; return NULL; } } /* Every branch instruction has at least 1 dest */ tok = tok->next; if( !tok ) { error = err_unexpected_eof; return NULL; } else if( tok->t != token_label && tok->t != token_num ) { /* Syntax error */ error_line = tok->line_number; error = err_labelnum_expected; return NULL; } if( tok->t == token_label ) { dest = check_label(tok); } else { /* tok->t == token_num */ dest = tok->value; } /* Create first (and possibly last) branch instruction */ if( type == token_jump || type == token_ifg || type == token_ifeg ) { encode_op_imme(new_op, op_jump, dest); create_instruction(new_op); } else { encode_op_imme(new_op, op_call, dest); create_instruction(new_op); } /* Do we have a second branch instruction we need to make? */ if( type == token_ife || type == token_ifeg ) { /* Eat comma */ tok = tok->next; if( !tok ) { error = err_unexpected_eof; return NULL; } else if( tok->t != token_comma ) { /* Syntax error */ error_line = tok->line_number; error = err_comma_expected; return NULL; } tok = tok->next; if( !tok ) { error = err_unexpected_eof; return NULL; } else if( tok->t != token_label && tok->t != token_num ) { /* Syntax error */ error_line = tok->line_number; error = err_labelnum_expected; return NULL; } if( tok->t == token_label ) { dest = check_label(tok); } else { /* tok->t == token_num */ dest = tok->value; } /* Create second branch instruction */ if( type == token_ifeg ) { encode_op_imme(new_op, op_jump, dest); create_instruction(new_op); } else { encode_op_imme(new_op, op_call, dest); create_instruction(new_op); } } return tok->next; }
static void create_movb( int value ) { RW_Robo_Op new_op; encode_op_imme(new_op, op_movb, value); create_instruction(new_op); }