diff --git a/emulate.c b/emulate.c index e816b4bfb2d4cac9c1160ab31ac00513299919dd..565c9295ab9019f6928a4f9b737c1d250cc91a39 100644 --- a/emulate.c +++ b/emulate.c @@ -17,7 +17,7 @@ struct ProcessorState { uint32_t registers[17]; // each uint32_t is 4 bytes large: - uint32_t memory[MEMORY_SIZE/4]; + uint32_t memory[MEMORY_SIZE / 4]; }; // Reads bits from source in the range [start, end] (inclusive). Returns an int32_t with the result as its least significant bits. @@ -27,12 +27,25 @@ uint32_t getBits(uint32_t source, int start, int end) return (source & ((2 << end) - (1 << start))) >> start; } +void setBit(uint32_t *source, int index, bool result){ + (*source) |= (1 << index); +} + // Shorthand for getBits(source, index, index) bool isSet(uint32_t source, int index) { return (source & (1 << index)); } +void verifyAddress(unsigned int address) +{ + if (address > MEMORY_SIZE / 8 || address % 4 != 0) + { + printf("Invalid address! Exiting..."); + exit(-1); + } +} + // Returns 1 if the condition code 'cond' is satisfied by the processor's current state, and 0 otherwise. // Any condition code not listed in the spec will cause this to return 0. bool validCond(uint32_t cond, struct ProcessorState *processor) @@ -88,12 +101,13 @@ uint32_t barrelShift(bool immediate, uint32_t operand, bool *carry, struct Proce // shifting an int32_t by 32 bits is undefined behaviour in C, and this if statement prevents it from happening later. if (shiftCount == 0) { + (*carry) = 0; return operandVal; } // set operandVal to the result after rotation operandVal = (operandVal >> (2 * shiftCount)) | (operandVal << (32 - 2 * shiftCount)); - + // set c to the last bit of operandVal (the last bit to be rotated) (*carry) = isSet(operandVal, 31); return operandVal; @@ -108,7 +122,8 @@ uint32_t barrelShift(bool immediate, uint32_t operand, bool *carry, struct Proce //*** shift using shift count stored in a register ***// uint32_t shiftReg = getBits(operand, 8, 11); // register should not be the PC - if(shiftReg == 15){ + if (shiftReg == 15) + { printf("Invalid instruction: shift count cannot be stored in PC"); exit(-1); } @@ -186,8 +201,9 @@ uint32_t barrelShift(bool immediate, uint32_t operand, bool *carry, struct Proce return (operandVal >> shiftCount) | (operandVal << (32 - shiftCount)); default: - // this should never happen (but gcc wants it) - return 0; + // this should never happen (but gcc wants it) + printf("Somehow, a 2-bit value has been interpreted as more than 3. Exiting..."); + exit(-1); }; } @@ -229,9 +245,9 @@ int32_t applyOperation(int opcode, int32_t operand1, int32_t operand2, bool *car case 3: // rsb { - int32_t swap = operand1; - operand1 = operand2; - operand2 = swap; + int32_t swap = operand1; + operand1 = operand2; + operand2 = swap; } case 2: // sub @@ -239,10 +255,10 @@ int32_t applyOperation(int opcode, int32_t operand1, int32_t operand2, bool *car case 4: // add { - uint32_t result = operand1 + operand2; - // check for overflow (this should work in all cases): - (*carry) = (result < operand1); - return result; + uint32_t result = operand1 + operand2; + // check for overflow (this should work in all cases): + (*carry) = (result < operand1); + return result; } case 13: @@ -254,6 +270,45 @@ int32_t applyOperation(int opcode, int32_t operand1, int32_t operand2, bool *car }; } +//*** INSTRUCTIONS ***/// + +void dataProcessingInstr(struct ProcessorState *processor, int address) +{ + // Check if address is valid + verifyAddress(address); + uint32_t instr = processor->memory[address]; + + // Check if the instruction should be executed according to its condition codes + if(!validCond(getBits(instr, 28, 31), processor)){ + return; + } + + // Get the shifted second operand + bool carry; + uint32_t operand2 = barrelShift(isSet(instr, 25), getBits(instr, 0, 11), &carry, processor); + + // Execute the instruction + bool store; + uint32_t result = applyOperation(getBits(instr, 21, 24), processor->registers[getBits(instr, 16, 19)], operand2, &carry, &store); + + // Store the result + if(store){ + processor->registers[getBits(instr, 12, 15)] = result; + } + + // Set the CPSR flags + if(isSet(instr, 20)){ + uint32_t *cprs = processor->registers[16]; + // C + setBit(cprs, 29, carry); + // Z (I think this should be set to 0 if the result isn't all zeros, but the spec is a little unclear) + setBit(cprs, 30, result == 0); + // N + setBit(cprs, 31, isSet(result, 31)); + } +} + + //*** TESTING FUNCTIONS ***// /* testing helper function (similar to the one in the slides) */ @@ -264,12 +319,15 @@ void test(bool pass, char *testname) /* converts string representing a binary number to a number. for testing - doesn't check validity. ignores leading zeros and any spaces*/ -uint32_t bin(char* number){ +uint32_t bin(char *number) +{ uint32_t result = 0; int end = strlen(number) - 1; int spaceCount = 0; - for(int i = end; i >= 0; i--){ - if(number[i] == ' '){ + for (int i = end; i >= 0; i--) + { + if (number[i] == ' ') + { spaceCount++; continue; } @@ -278,7 +336,8 @@ uint32_t bin(char* number){ return result; } -void testBitGetters(void){ +void testBitGetters(void) +{ printf("*** getBits() tests ***\n"); test(getBits(bin("11000000000000000000000101101110"), 28, 31) == 12, "leftmost bits"); test(getBits(bin("11000000000000000000000101101110"), 8, 20) == 1, "middle bits"); @@ -290,19 +349,10 @@ void testBitGetters(void){ test(isSet(bin("11000000000000000000000101101110"), 8), "middle bit"); test(!isSet(bin("11000000000000000000000101101110"), 0), "rightmost bit"); printf("\n"); - -} - -/* creates a new processor, setting all registers to 0. Dynamically allocated - call free()! */ -struct ProcessorState *makeProcessor(void){ - struct ProcessorState* processor = (struct ProcessorState*)malloc(sizeof(struct ProcessorState)); - for(int i = 0; i < 17; i++){ - processor->registers[i] = 0; - } - return processor; } -void testBarrelShifter(void){ +void testBarrelShifter(void) +{ printf("*** barrelShifter() tests ***\n"); struct ProcessorState *processor = makeProcessor(); processor->registers[0] = bin("10110100000000000000000000000000"); @@ -328,7 +378,19 @@ void testBarrelShifter(void){ free(processor); } -int main(void){ +/* creates a new processor, setting all registers to 0. Dynamically allocated - call free()! */ +struct ProcessorState *makeProcessor(void) +{ + struct ProcessorState *processor = (struct ProcessorState *)malloc(sizeof(struct ProcessorState)); + for (int i = 0; i < 17; i++) + { + processor->registers[i] = 0; + } + return processor; +} + +int main(void) +{ testBitGetters(); printf("\n"); testBarrelShifter();