Skip to content
Snippets Groups Projects
Commit b80ec766 authored by iftach's avatar iftach
Browse files

added data processing instruction

parent 7ff087a5
No related branches found
No related tags found
No related merge requests found
......@@ -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();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment