/*
|
/*
|
* main.c -- the main program
|
* main.c -- the main program
|
*/
|
*/
|
|
|
|
|
#include "common.h"
|
#include "common.h"
|
#include "lib.h"
|
#include "lib.h"
|
#include "start.h"
|
#include "start.h"
|
|
|
|
|
Word userMissTaken;
|
Word userMissTaken;
|
|
|
|
|
static InterruptContext initial = {
|
static InterruptContext initial = {
|
/* regs */
|
/* regs */
|
0x00000011, 0x11111112, 0x22222213, 0x33333314,
|
0x00000011, 0x11111112, 0x22222213, 0x33333314,
|
0x44444415, 0x55555516, 0x66666617, 0x77777718,
|
0x44444415, 0x55555516, 0x66666617, 0x77777718,
|
0x88888819, 0x9999991A, 0xAAAAAA1B, 0xBBBBBB1C,
|
0x88888819, 0x9999991A, 0xAAAAAA1B, 0xBBBBBB1C,
|
0xCCCCCC1D, 0xDDDDDD1E, 0xEEEEEE1F, 0xFFFFFF10,
|
0xCCCCCC1D, 0xDDDDDD1E, 0xEEEEEE1F, 0xFFFFFF10,
|
0x00000021, 0x11111122, 0x22222223, 0x33333324,
|
0x00000021, 0x11111122, 0x22222223, 0x33333324,
|
0x44444425, 0x55555526, 0x66666627, 0x77777728,
|
0x44444425, 0x55555526, 0x66666627, 0x77777728,
|
0x88888829, 0x9999992A, 0xAAAAAA2B, 0xBBBBBB2C,
|
0x88888829, 0x9999992A, 0xAAAAAA2B, 0xBBBBBB2C,
|
0xCCCCCC2D, 0xDDDDDD2E, 0xEEEEEE2F, 0xFFFFFF20,
|
0xCCCCCC2D, 0xDDDDDD2E, 0xEEEEEE2F, 0xFFFFFF20,
|
/* PSW */
|
/* PSW */
|
0x03FF5678,
|
0x03FF5678,
|
/* TLB index */
|
/* TLB index */
|
0x87654321,
|
0x87654321,
|
/* TLB EntryHi */
|
/* TLB EntryHi */
|
0x9ABCDEF0,
|
0x9ABCDEF0,
|
/* TLB EntryLo */
|
/* TLB EntryLo */
|
0x0FEDCBA9
|
0x0FEDCBA9,
|
|
/* bad address */
|
|
0xDEADBEEF,
|
};
|
};
|
|
|
static InterruptContext ic;
|
static InterruptContext ic;
|
|
|
|
|
static char *errorMessage[] = {
|
static char *errorMessage[] = {
|
/* 0 */ "no error",
|
/* 0 */ "no error",
|
/* 1 */ "general register clobbered",
|
/* 1 */ "general register clobbered",
|
/* 2 */ "write to register 0 succeeded",
|
/* 2 */ "write to register 0 succeeded",
|
/* 3 */ "locus of exception incorrect",
|
/* 3 */ "locus of exception incorrect",
|
/* 4 */ "TLB register clobbered",
|
/* 4 */ "TLB register clobbered",
|
/* 5 */ "vector bit incorrect",
|
/* 5 */ "vector bit incorrect",
|
/* 6 */ "user mode bits incorrect",
|
/* 6 */ "user mode bits incorrect",
|
/* 7 */ "interrupt enable bits incorrect",
|
/* 7 */ "interrupt enable bits incorrect",
|
/* 8 */ "wrong exception number",
|
/* 8 */ "wrong exception number",
|
/* 9 */ "interrupt mask bits clobbered",
|
/* 9 */ "interrupt mask bits clobbered",
|
/* 10 */ "ISR entry was 'user miss'",
|
/* 10 */ "ISR entry was 'user miss'",
|
/* 11 */ "ISR entry was not 'user miss'",
|
/* 11 */ "ISR entry was not 'user miss'",
|
|
/* 12 */ "bad address register clobbered",
|
|
/* 13 */ "bad address register incorrect",
|
};
|
};
|
|
|
|
|
static void flushTLB(void) {
|
static void flushTLB(void) {
|
Word invalPage;
|
Word invalPage;
|
int i;
|
int i;
|
|
|
invalPage = 0xC0000000;
|
invalPage = 0xC0000000;
|
for (i = 0; i < 32; i++) {
|
for (i = 0; i < 32; i++) {
|
setTLB(i, invalPage, 0);
|
setTLB(i, invalPage, 0);
|
invalPage += (1 << 12);
|
invalPage += (1 << 12);
|
}
|
}
|
}
|
}
|
|
|
|
|
static void check(unsigned int *res1, unsigned int *res2,
|
static void check(unsigned int *res1, unsigned int *res2,
|
Word expectedEntryHi) {
|
Word expectedEntryHi) {
|
int i;
|
int i;
|
|
|
*res1 = 0;
|
*res1 = 0;
|
*res2 = 0;
|
*res2 = 0;
|
for (i = 0; i < 32; i++) {
|
for (i = 0; i < 32; i++) {
|
if (ic.reg[i] != initial.reg[i]) {
|
if (ic.reg[i] != initial.reg[i]) {
|
*res1 |= (1 << i);
|
*res1 |= (1 << i);
|
}
|
}
|
}
|
}
|
if ((ic.psw & 0x0FFFFFFF) != (initial.psw & 0x0FFFFFFF)) {
|
if ((ic.psw & 0x0FFFFFFF) != (initial.psw & 0x0FFFFFFF)) {
|
*res2 |= (1 << 0);
|
*res2 |= (1 << 0);
|
}
|
}
|
if ((ic.tlbIndex & 0x0000001F) != (initial.tlbIndex & 0x0000001F)) {
|
if ((ic.tlbIndex & 0x0000001F) != (initial.tlbIndex & 0x0000001F)) {
|
*res2 |= (1 << 1);
|
*res2 |= (1 << 1);
|
}
|
}
|
if ((ic.tlbHi & 0xFFFFF000) != (expectedEntryHi & 0xFFFFF000)) {
|
if ((ic.tlbHi & 0xFFFFF000) != (expectedEntryHi & 0xFFFFF000)) {
|
*res2 |= (1 << 2);
|
*res2 |= (1 << 2);
|
}
|
}
|
if ((ic.tlbLo & 0x3FFFF003) != (initial.tlbLo & 0x3FFFF003)) {
|
if ((ic.tlbLo & 0x3FFFF003) != (initial.tlbLo & 0x3FFFF003)) {
|
*res2 |= (1 << 3);
|
*res2 |= (1 << 3);
|
}
|
}
|
}
|
}
|
|
|
|
|
static int execTest(void (*run)(InterruptContext *icp),
|
static int execTest(void (*run)(InterruptContext *icp),
|
Word *expectedLocus,
|
Word *expectedLocus,
|
int expectedException,
|
int expectedException,
|
Bool execInUserMode,
|
Bool execInUserMode,
|
Bool clobberEntryHi,
|
Bool clobberEntryHi,
|
Bool shouldTakeUserMiss) {
|
Bool shouldTakeUserMiss,
|
|
Bool shouldSetBadAddr,
|
|
Word expectedBadAddr) {
|
unsigned int res1, res2;
|
unsigned int res1, res2;
|
int result;
|
int result;
|
Word *locus;
|
Word *locus;
|
|
Word badAddr;
|
|
|
if (execInUserMode) {
|
if (execInUserMode) {
|
initial.psw |= 1 << 26;
|
initial.psw |= 1 << 26;
|
}
|
}
|
ic = initial;
|
ic = initial;
|
flushTLB();
|
flushTLB();
|
userMissTaken = 0xFFFFFFFF;
|
userMissTaken = 0xFFFFFFFF;
|
(*run)(&ic);
|
(*run)(&ic);
|
if (execInUserMode) {
|
if (execInUserMode) {
|
locus = (Word *) (0xC0000000 | ic.reg[30]);
|
locus = (Word *) (0xC0000000 | ic.reg[30]);
|
} else {
|
} else {
|
locus = (Word *) ic.reg[30];
|
locus = (Word *) ic.reg[30];
|
}
|
}
|
|
badAddr = ic.badAddr;
|
if (!clobberEntryHi) {
|
if (!clobberEntryHi) {
|
check(&res1, &res2, initial.tlbHi);
|
check(&res1, &res2, initial.tlbHi);
|
} else {
|
} else {
|
if (shouldTakeUserMiss) {
|
if (shouldTakeUserMiss) {
|
check(&res1, &res2, initial.reg[3]);
|
check(&res1, &res2, initial.reg[3]);
|
} else {
|
} else {
|
check(&res1, &res2, initial.reg[11]);
|
check(&res1, &res2, initial.reg[11]);
|
}
|
}
|
}
|
}
|
result = 0;
|
result = 0;
|
if (((ic.psw >> 16) & 0x1F) != expectedException) {
|
if (((ic.psw >> 16) & 0x1F) != expectedException) {
|
result = 8;
|
result = 8;
|
} else
|
} else
|
if (!shouldTakeUserMiss && userMissTaken != 0) {
|
if (!shouldTakeUserMiss && userMissTaken != 0) {
|
result = 10;
|
result = 10;
|
} else
|
} else
|
if (shouldTakeUserMiss && userMissTaken != (Word) &userMissTaken) {
|
if (shouldTakeUserMiss && userMissTaken != (Word) &userMissTaken) {
|
result = 11;
|
result = 11;
|
} else
|
} else
|
if (res1 != 0x50000001) {
|
if (res1 != 0x50000001) {
|
result = 1;
|
result = 1;
|
} else
|
} else
|
if (ic.reg[0] != 0x00000000) {
|
if (ic.reg[0] != 0x00000000) {
|
result = 2;
|
result = 2;
|
} else
|
} else
|
if (locus != expectedLocus) {
|
if (locus != expectedLocus) {
|
result = 3;
|
result = 3;
|
} else
|
} else
|
|
if (!shouldSetBadAddr && badAddr != initial.badAddr) {
|
|
result = 12;
|
|
} else
|
|
if (shouldSetBadAddr && badAddr != expectedBadAddr) {
|
|
result = 13;
|
|
} else
|
if (res2 != 0x00000001) {
|
if (res2 != 0x00000001) {
|
result = 4;
|
result = 4;
|
} else
|
} else
|
if (((ic.psw >> 27) & 0x01) != ((initial.psw >> 27) & 0x01)) {
|
if (((ic.psw >> 27) & 0x01) != ((initial.psw >> 27) & 0x01)) {
|
result = 5;
|
result = 5;
|
} else
|
} else
|
if (((ic.psw >> 24) & 0x07) != ((initial.psw >> 25) & 0x03)) {
|
if (((ic.psw >> 24) & 0x07) != ((initial.psw >> 25) & 0x03)) {
|
result = 6;
|
result = 6;
|
} else
|
} else
|
if (((ic.psw >> 21) & 0x07) != ((initial.psw >> 22) & 0x03)) {
|
if (((ic.psw >> 21) & 0x07) != ((initial.psw >> 22) & 0x03)) {
|
result = 7;
|
result = 7;
|
} else
|
} else
|
if (((ic.psw >> 0) & 0xFF) != ((initial.psw >> 0) & 0xFF)) {
|
if (((ic.psw >> 0) & 0xFF) != ((initial.psw >> 0) & 0xFF)) {
|
result = 9;
|
result = 9;
|
}
|
}
|
if (execInUserMode) {
|
if (execInUserMode) {
|
initial.psw &= ~(1 << 26);
|
initial.psw &= ~(1 << 26);
|
}
|
}
|
return result;
|
return result;
|
}
|
}
|
|
|
|
|
static struct {
|
static struct {
|
char *name;
|
char *name;
|
void (*run)(InterruptContext *icp);
|
void (*run)(InterruptContext *icp);
|
Word *locus;
|
Word *locus;
|
int exception;
|
int exception;
|
Bool execInUserMode;
|
Bool execInUserMode;
|
Bool clobberEntryHi;
|
Bool clobberEntryHi;
|
Bool shouldTakeUserMiss;
|
Bool shouldTakeUserMiss;
|
|
Bool shouldSetBadAddr;
|
|
Word expectedBadAddr;
|
} tests[] = {
|
} tests[] = {
|
{ "Trap instr test:\t\t\t",
|
{ "Trap instr test:\t\t\t",
|
xtest1, &xtest1x, 20, false, false, false },
|
xtest1, &xtest1x, 20, false, false, false, false, 0 },
|
{ "Illegal instr test:\t\t\t",
|
{ "Illegal instr test:\t\t\t",
|
xtest2, &xtest2x, 17, false, false, false },
|
xtest2, &xtest2x, 17, false, false, false, false, 0 },
|
{ "Divide instr test 1 (div):\t\t",
|
{ "Divide instr test 1 (div):\t\t",
|
xtest3, &xtest3x, 19, false, false, false },
|
xtest3, &xtest3x, 19, false, false, false, false, 0 },
|
{ "Divide instr test 2 (divi):\t\t",
|
{ "Divide instr test 2 (divi):\t\t",
|
xtest4, &xtest4x, 19, false, false, false },
|
xtest4, &xtest4x, 19, false, false, false, false, 0 },
|
{ "Divide instr test 3 (divu):\t\t",
|
{ "Divide instr test 3 (divu):\t\t",
|
xtest5, &xtest5x, 19, false, false, false },
|
xtest5, &xtest5x, 19, false, false, false, false, 0 },
|
{ "Divide instr test 4 (divui):\t\t",
|
{ "Divide instr test 4 (divui):\t\t",
|
xtest6, &xtest6x, 19, false, false, false },
|
xtest6, &xtest6x, 19, false, false, false, false, 0 },
|
{ "Divide instr test 5 (rem):\t\t",
|
{ "Divide instr test 5 (rem):\t\t",
|
xtest7, &xtest7x, 19, false, false, false },
|
xtest7, &xtest7x, 19, false, false, false, false, 0 },
|
{ "Divide instr test 6 (remi):\t\t",
|
{ "Divide instr test 6 (remi):\t\t",
|
xtest8, &xtest8x, 19, false, false, false },
|
xtest8, &xtest8x, 19, false, false, false, false, 0 },
|
{ "Divide instr test 7 (remu):\t\t",
|
{ "Divide instr test 7 (remu):\t\t",
|
xtest9, &xtest9x, 19, false, false, false },
|
xtest9, &xtest9x, 19, false, false, false, false, 0 },
|
{ "Divide instr test 8 (remui):\t\t",
|
{ "Divide instr test 8 (remui):\t\t",
|
xtest10, &xtest10x, 19, false, false, false },
|
xtest10, &xtest10x, 19, false, false, false, false, 0 },
|
{ "Bus timeout test 1 (fetch):\t\t",
|
{ "Bus timeout test 1 (fetch):\t\t",
|
xtest11, &xtest11x, 16, false, false, false },
|
xtest11, &xtest11x, 16, false, false, false, false, 0 },
|
{ "Bus timeout test 2 (load):\t\t",
|
{ "Bus timeout test 2 (load):\t\t",
|
xtest12, &xtest12x, 16, false, false, false },
|
xtest12, &xtest12x, 16, false, false, false, false, 0 },
|
{ "Bus timeout test 3 (store):\t\t",
|
{ "Bus timeout test 3 (store):\t\t",
|
xtest13, &xtest13x, 16, false, false, false },
|
xtest13, &xtest13x, 16, false, false, false, false, 0 },
|
{ "Privileged instr test 1 (rfx):\t\t",
|
{ "Privileged instr test 1 (rfx):\t\t",
|
xtest14, &xtest14x, 18, true, false, false },
|
xtest14, &xtest14x, 18, true, false, false, false, 0 },
|
{ "Privileged instr test 2 (mvts):\t\t",
|
{ "Privileged instr test 2 (mvts):\t\t",
|
xtest15, &xtest15x, 18, true, false, false },
|
xtest15, &xtest15x, 18, true, false, false, false, 0 },
|
{ "Privileged instr test 3 (tb..):\t\t",
|
{ "Privileged instr test 3 (tb..):\t\t",
|
xtest16, &xtest16x, 18, true, false, false },
|
xtest16, &xtest16x, 18, true, false, false, false, 0 },
|
{ "Privileged address test 1 (fetch):\t",
|
{ "Privileged address test 1 (fetch):\t",
|
xtest17, &xtest17x, 25, true, false, false },
|
xtest17, &xtest17x, 25, true, false, false, true, 0xffffff10 },
|
{ "Privileged address test 2 (load):\t",
|
{ "Privileged address test 2 (load):\t",
|
xtest18, &xtest18x, 25, true, false, false },
|
xtest18, &xtest18x, 25, true, false, false, true, 0xffffff10 },
|
{ "Privileged address test 3 (store):\t",
|
{ "Privileged address test 3 (store):\t",
|
xtest19, &xtest19x, 25, true, false, false },
|
xtest19, &xtest19x, 25, true, false, false, true, 0xffffff10 },
|
{ "Illegal address test 1 (fetch):\t\t",
|
{ "Illegal address test 1 (fetch):\t\t",
|
xtest20, &xtest20x, 24, false, false, false },
|
xtest20, &xtest20x, 24, false, false, false, true, 0x11111122 },
|
{ "Illegal address test 2 (fetch):\t\t",
|
{ "Illegal address test 2 (fetch):\t\t",
|
xtest21, &xtest21x, 24, false, false, false },
|
xtest21, &xtest21x, 24, false, false, false, true, 0x00000021 },
|
{ "Illegal address test 3 (ldw):\t\t",
|
{ "Illegal address test 3 (ldw):\t\t",
|
xtest22, &xtest22x, 24, false, false, false },
|
xtest22, &xtest22x, 24, false, false, false, true, 0xffffff12 },
|
{ "Illegal address test 4 (ldw):\t\t",
|
{ "Illegal address test 4 (ldw):\t\t",
|
xtest23, &xtest23x, 24, false, false, false },
|
xtest23, &xtest23x, 24, false, false, false, true, 0xffffff11 },
|
{ "Illegal address test 5 (ldh):\t\t",
|
{ "Illegal address test 5 (ldh):\t\t",
|
xtest24, &xtest24x, 24, false, false, false },
|
xtest24, &xtest24x, 24, false, false, false, true, 0xffffff11 },
|
{ "Illegal address test 6 (stw):\t\t",
|
{ "Illegal address test 6 (stw):\t\t",
|
xtest25, &xtest25x, 24, false, false, false },
|
xtest25, &xtest25x, 24, false, false, false, true, 0xffffff12 },
|
{ "Illegal address test 7 (stw):\t\t",
|
{ "Illegal address test 7 (stw):\t\t",
|
xtest26, &xtest26x, 24, false, false, false },
|
xtest26, &xtest26x, 24, false, false, false, true, 0xffffff11 },
|
{ "Illegal address test 8 (sth):\t\t",
|
{ "Illegal address test 8 (sth):\t\t",
|
xtest27, &xtest27x, 24, false, false, false },
|
xtest27, &xtest27x, 24, false, false, false, true, 0xffffff11 },
|
{ "TLB user miss test 1 (fetch):\t\t",
|
{ "TLB user miss test 1 (fetch):\t\t",
|
xtest28, &xtest28x, 21, false, true, true },
|
xtest28, &xtest28x, 21, false, true, true, true, 0x33333314 },
|
{ "TLB user miss test 2 (load):\t\t",
|
{ "TLB user miss test 2 (load):\t\t",
|
xtest29, &xtest29x, 21, false, true, true },
|
xtest29, &xtest29x, 21, false, true, true, true, 0x33333314 },
|
{ "TLB user miss test 3 (store):\t\t",
|
{ "TLB user miss test 3 (store):\t\t",
|
xtest30, &xtest30x, 21, false, true, true },
|
xtest30, &xtest30x, 21, false, true, true, true, 0x33333314 },
|
{ "TLB kernel miss test 1 (fetch):\t\t",
|
{ "TLB kernel miss test 1 (fetch):\t\t",
|
xtest31, &xtest31x, 21, false, true, false },
|
xtest31, &xtest31x, 21, false, true, false, true, 0xbbbbbb1c },
|
{ "TLB kernel miss test 2 (load):\t\t",
|
{ "TLB kernel miss test 2 (load):\t\t",
|
xtest32, &xtest32x, 21, false, true, false },
|
xtest32, &xtest32x, 21, false, true, false, true, 0xbbbbbb1c },
|
{ "TLB kernel miss test 3 (store):\t\t",
|
{ "TLB kernel miss test 3 (store):\t\t",
|
xtest33, &xtest33x, 21, false, true, false },
|
xtest33, &xtest33x, 21, false, true, false, true, 0xbbbbbb1c },
|
{ "TLB invalid test 1 (fetch):\t\t",
|
{ "TLB invalid test 1 (fetch):\t\t",
|
xtest34, &xtest34x, 23, false, true, false },
|
xtest34, &xtest34x, 23, false, true, false, true, 0xbbbbbb1c },
|
{ "TLB invalid test 2 (load):\t\t",
|
{ "TLB invalid test 2 (load):\t\t",
|
xtest35, &xtest35x, 23, false, true, false },
|
xtest35, &xtest35x, 23, false, true, false, true, 0xbbbbbb1c },
|
{ "TLB invalid test 3 (store):\t\t",
|
{ "TLB invalid test 3 (store):\t\t",
|
xtest36, &xtest36x, 23, false, true, false },
|
xtest36, &xtest36x, 23, false, true, false, true, 0xbbbbbb1c },
|
{ "TLB wrtprot test (store):\t\t",
|
{ "TLB wrtprot test (store):\t\t",
|
xtest37, &xtest37x, 22, false, true, false },
|
xtest37, &xtest37x, 22, false, true, false, true, 0xbbbbbb1c },
|
};
|
};
|
|
|
|
|
int main(void) {
|
int main(void) {
|
int i;
|
int i;
|
int result;
|
int result;
|
|
|
printf("\nStart of exception tests.\n\n");
|
printf("\nStart of exception tests.\n\n");
|
for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) {
|
for (i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) {
|
printf("%s", tests[i].name);
|
printf("%s", tests[i].name);
|
result = execTest(tests[i].run,
|
result = execTest(tests[i].run,
|
tests[i].locus,
|
tests[i].locus,
|
tests[i].exception,
|
tests[i].exception,
|
tests[i].execInUserMode,
|
tests[i].execInUserMode,
|
tests[i].clobberEntryHi,
|
tests[i].clobberEntryHi,
|
tests[i].shouldTakeUserMiss);
|
tests[i].shouldTakeUserMiss,
|
|
tests[i].shouldSetBadAddr,
|
|
tests[i].expectedBadAddr);
|
if (result == 0) {
|
if (result == 0) {
|
printf("ok");
|
printf("ok");
|
} else {
|
} else {
|
printf("failed (%s)", errorMessage[result]);
|
printf("failed (%s)", errorMessage[result]);
|
}
|
}
|
printf("\n");
|
printf("\n");
|
}
|
}
|
printf("\nEnd of exception tests.\n");
|
printf("\nEnd of exception tests.\n");
|
while (1) ;
|
while (1) ;
|
return 0;
|
return 0;
|
}
|
}
|
|
|