|
|
nono 1.5.0
/* vi:set ts=4: */
/*
* nono
* Copyright (C) 2021 nono project
* Licensed under nono-license.txt
*/
#include "optestm88k_main.h"
#include <ieeefp.h>
#include <getopt.h>
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/siginfo.h>
// グローバルワーク (r2 でアセンブラに渡される)
// define の値を code.s と揃えること
int global_work[6];
// オーバーフロー例外なら 1、除算例外なら 2 をセットする。
// テスト前に 0 で初期化しておくこと。
#define exception_occurred (global_work[0])
// 例外を期待しないなら 0、期待するなら例外ごとのマスク値 (テスト側が書く)
#define exception_expected (global_work[1])
// 期待値と結果 (表示用)
#define expected_val (global_work[2])
#define expected_val2 (global_work[3])
#define actual_val (global_work[4])
#define actual_val2 (global_work[5])
static void
usage()
{
printf("usage: %s [<testname>]\n", getprogname());
exit(1);
}
static void
signal_handler(int signo, siginfo_t *si, void *ctx)
{
switch (si->si_signo) {
case SIGFPE:
if (si->si_code == FPE_INTOVF) {
exception_occurred = 0x0001;
return;
} else if (si->si_code == FPE_INTDIV) {
exception_occurred = 0x0002;
return;
}
printf("%s: signo=SIGFPE si_code=%x\n", __func__, si->si_code);
break;
case SIGILL:
if (si->si_code == ILL_ILLOPC) {
exception_occurred = 0x1000;
return;
}
printf("%s: signo=SIGILL si_code=%x\n", __func__, si->si_code);
break;
default:
printf("%s: signo=%d si_code=%x\n", __func__,
si->si_signo, si->si_code);
break;
}
// XXX
exception_occurred = -1;
}
int
main(int ac, char *av[])
{
char cause[128];
struct testentry *t;
func_t func;
const char *arg_name = "";
int c;
int i;
int j;
int num;
int res;
int failed;
int total_failed;
fp_rnd rnd_backup;
while ((c = getopt(ac, av, "")) != -1) {
switch (c) {
default:
usage();
break;
}
}
ac -= optind;
av += optind;
if (ac > 1) {
usage();
}
if (ac == 1) {
arg_name = av[0];
}
rnd_backup = fpgetround();
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_sigaction = signal_handler;
act.sa_flags = SA_SIGINFO;
sigaction(SIGFPE, &act, NULL);
sigaction(SIGILL, &act, NULL);
total_failed = 0;
for (i = j = 0; test_table[i].code != NULL; i++, j = 0) {
failed = 0;
t = &test_table[i];
if (strncasecmp(t->testname, arg_name, strlen(arg_name)) != 0) {
continue;
}
if (j == 0) {
// テスト数を数える
for (num = 0; t->testdata[num] != NULL; num++)
;
printf("%s (%d) ... ", t->testname, num);
fflush(stdout);
}
for (; j < num; j++) {
exception_occurred = 0;
res = (t->code)(global_work, t->testdata[j]);
// 失敗なら非 0 を返す
// bit3 は演算結果が期待と異なる
// それ以外のビットが立っていれば例外有無が期待と異なる
if (res != 0) {
cause[0] = '\0';
if ((res & 8)) {
#define SNPRINTF(s, fmt...) n += snprintf((s) + n, sizeof(s) - n, fmt)
int n = 0;
SNPRINTF(cause, "0x%08x", expected_val);
if (t->quad) {
SNPRINTF(cause, "'%08x", expected_val2);
}
SNPRINTF(cause, " expected but 0x%08x", actual_val);
if (t->quad) {
SNPRINTF(cause, "'%08x", actual_val2);
}
res &= ~8;
}
if (res != 0) {
if (cause[0]) {
strlcat(cause, ", ", sizeof(cause));
}
if (exception_expected) {
// 例外を期待したが、例外が起きなかった。
strlcat(cause, "exception not occurred", sizeof(cause));
} else {
// 例外が起きないことを期待したのに例外が起きた。
strlcat(cause, "exception occurred", sizeof(cause));
}
}
if (failed == 0) {
printf("\n");
}
printf("FAILED (%s) at test_%s_%d\n",
cause, t->testname, j);
failed++;
}
}
if (failed == 0) {
printf("ok\n");
}
total_failed += failed;
}
if (total_failed != 0) {
printf("%d failed!\n", total_failed);
}
fpsetround(rnd_backup);
return 0;
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.