Newer
Older
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#define MEMORY_SIZE 65536
// Helpful stuff (things that will probably be used to implement more than one instruction type)
// struct representing a processor:
struct ProcessorState
{
int32_t registers[17];
int32_t memory[MEMORY_SIZE];
};
// Reads bits from source in the range [start, end] (inclusive). Returns an int32_t with the result as its least significant bits.
// (e.g. getBits(8, 2, 3) == 2)
int32_t getBits(int source, int start, int end)
{
return (source & ((2 << end) - (1 << start))) >> start;
}
// Shorthand for getBits(source, index, index)
int isSet(int source, int index)
{
return (source & (1 << index));
}
// 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.
int validCond(int32_t cond, struct ProcessorState *processor)
{
int32_t cprs = (*processor).registers[16];
int n = isSet(cprs, 31);
int z = isSet(cprs, 30);
int c = isSet(cprs, 29);
int v = isSet(cprs, 28);
switch (cond)
{
case 0:
case 10:
return n == z;
case 11:
return n != z;
case 12:
return !z && (n == v);
case 13:
return z || (n != v);
case 14:
return 1;
default:
return 0;
}
}
/*
Implements the barrel shifter.
immediate: the I bit from the spec. Determines whether to shift by immediate value. Boolean type.
operand: the entire shift instruction (12 bits long). Operand2 on the spec.
carry: the carry-out bit (in case flags need to be updated).
processor: the processor (needed for reading from the registers).
this is completely untested and probably buggy, for all I know this becomes self-aware at runtime so don't trust anything it tells you
also, this doesn't cast return types; i don't think it's a problem but this is C so who knows what it's thinking
*/
int32_t barrelShift(int immediate, int32_t operand, int *carry, struct ProcessorState *processor)
{
if (immediate)
{
//*** shift using immediate value ***//
unsigned int shiftCount = (unsigned int)getBits(operand, 8, 11);
uint32_t operandVal = (uint32_t)getBits(operand, 0, 7);
// shifting an int32_t by 32 bits is undefined behaviour in C, and this if statement prevents it.
if(shiftCount == 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;
uint32_t operandVal = (uint32_t)(*processor).registers[getBits(operand, 0, 3)];
unsigned int shiftType = getBits(operand, 5, 6);
unsigned int shiftCount;
if (isSet(operand, 4))
{
//*** shift using shift count stored in a register ***//
uint32_t shiftReg = getBits(operand, 8, 11);
// register should not be the PC
assert((shiftReg != 15));
// the spec says that the bottom byte of the register defines the shift amount... but this allows values much bigger than 31 (which is the max shift of all the other shift operation types)
// I'm not sure if it's a mistake or intentional - for now I'm just loading the bottom 5 bytes (2^5 = 32), since shifting an int32_t by more than 32 is undefined for C's bitwise operators.
shiftCount = getBits((*processor).registers[shiftReg], 0, 4);
}
else
{
//*** shift using immediate shift count ***//
shiftCount = getbits(operand, 7, 11);
}
// Exit early if not shifting. This makes some of the upcoming logic simpler.
if (shiftCount == 0)
{
return operandVal;
}
//*** perform the shift ***//
switch (shiftType)
{
case 0:
// logical left shift
(*carry) = isSet(operandVal, 32 - shiftCount);
return operandVal << shiftCount;
case 1:
// logical right shift
// operandVal is a uint32_t, so C shouldn't sign-extend it
(*carry) = isSet(operandVal, shiftCount - 1);
return operandVal >> shiftCount;
case 2:
// arithmetic right shift
(*carry) = isSet(operandVal, shiftCount - 1);
// convert operandVal to a signed type, then shift it
return (int32_t)operandVal >> shiftCount;
case 3:
// rotate right
(*carry) = isSet(operand, shiftCount - 1);
return (operandVal >> shiftCount) | (operandVal << (32 - shiftCount));
}
// TODO: applyOperation(int opcode, int32_t operator1, int32_t operator2, int *carry)