#include <stdio.h>

const int SEGMENT_SHIFT = 12;  // number of bits to shift to get the segment
const long SEGMENT_MASK = 0x3 << SEGMENT_SHIFT;
const long OFFSET_MASK = 0xFFF;

unsigned long BASE[4];  // the base address for each segment
unsigned int BOUND[4];  // the upper bound for each segment
char GROWS_POSITIVE[4]; // 1: means ascending, 0: descending

unsigned long MAXIMUM_SEGMENT_SIZE = 4*1024;  // size of the virtual address segment

unsigned long AccessMemory( unsigned long physicalAddress ){
    unsigned long value = 0;
    // FUTURE: read from address physicalAddress and assign to value
    return value;
}

void translateAddress( unsigned long virtualAddress, unsigned long* physicalAddress ){
    unsigned int segment = 0;
    unsigned long offset = 0;
    unsigned long Register = 0;

    *physicalAddress = 0;

    // get top 2 bits of 14-bit virtual address
    segment = (virtualAddress & SEGMENT_MASK) >> SEGMENT_SHIFT;

    // now get offset
    offset = virtualAddress & OFFSET_MASK;

    if( offset >= BOUND[ segment ]){
        // RaiseException(PROTECTION_FAULT);
    } else {
        if( GROWS_POSITIVE[ segment ] == 0){
            offset = MAXIMUM_SEGMENT_SIZE - offset;
        }
        *physicalAddress = BASE[ segment ] + offset;
        Register = AccessMemory( *physicalAddress );
    }
    fprintf(stderr, "virtual address %p (segment: %d, offset: %p), physical address %p\n", (void*)virtualAddress, segment, (void*)offset, (void*)*physicalAddress);

}

int main(){
    fprintf(stderr, "SEGMENT_SHIFT: %d\n", SEGMENT_SHIFT);
    fprintf(stderr, "SEGMENT_MASK: %p\n\n", (void*)SEGMENT_MASK);

    BASE[ 0 ] = 32*1024;  BOUND[ 0 ] = BASE[0] + 2*1024;  GROWS_POSITIVE[ 0 ] = 1;
    BASE[ 1 ] = 34*1024;  BOUND[ 1 ] = BASE[1] + 2*1024;  GROWS_POSITIVE[ 1 ] = 1;
    BASE[ 3 ] = 28*1024;  BOUND[ 3 ] = BASE[3] + 2*1024;  GROWS_POSITIVE[ 3 ] = 0;


    unsigned long virtualAddresses[] = {200, 5000, 15000};
    unsigned long physAddr = 0;

    for( int i = 0; i < sizeof( virtualAddresses ) / sizeof( virtualAddresses[0] ); i++){
        translateAddress( virtualAddresses[ i ], &physAddr );
    }

    return 0;
}