diff --git a/tools/tests/README.md b/tools/tests/README.md index 618aab15..b052392c 100644 --- a/tools/tests/README.md +++ b/tools/tests/README.md @@ -3,3 +3,4 @@ This directory tree contains **test programs** and is organized in | Directory | Content | | --------- | ------- | | [divtst](divtst) | `divtst` program: test DIV instruction response | +| [stktst](stktst) | `stktst` program: test 2.11BSD stack extension | diff --git a/tools/tests/stktst/Makefile b/tools/tests/stktst/Makefile new file mode 100644 index 00000000..8d7bd6f0 --- /dev/null +++ b/tools/tests/stktst/Makefile @@ -0,0 +1,12 @@ +# $Id: $ +# SPDX-License-Identifier: GPL-3.0-or-later +# Copyright 2022- by Walter F.J. Mueller +# +stktst : stktst.o dotst.o + cc -o stktst stktst.o dotst.o + +stktst.o : stktst.c + cc -O -c stktst.c + +clean : + rm -f *.o stktst diff --git a/tools/tests/stktst/dotst.s b/tools/tests/stktst/dotst.s new file mode 100644 index 00000000..2034d83a --- /dev/null +++ b/tools/tests/stktst/dotst.s @@ -0,0 +1,165 @@ +/ $Id: $ +/ SPDX-License-Identifier: GPL-3.0-or-later +/ Copyright 2022- by Walter F.J. Mueller +/ +/ called from C as +/ irc = dotst(idat, odat) +/ with +/ idat[0] command ('I','i','l','f','d','r','w', or 'h') +/ idat[1] command repeat count +/ idat[2] -c repeat count +/ idat[3] -s repeat count +/ idat[4] -o byte offset +/ and returns in odat +/ odat[0] sp before align and offset +/ odat[1] sp after align and offset +/ odat[2] sp final +/ +/ Revision History: +/ Date Rev Version Comment +/ 2022-08-01 1267 1.0 Initial version +/ + +.globl _dotst +.text + +_dotst: mov r2,-(sp) / save r2 (r0,r1 are volatile) + mov r3,-(sp) / save r3 + mov r4,-(sp) / save r4 + mov r5,-(sp) / save r5 + / now (sp) -> saved r5 + / 2(sp) -> saved r4 + / 4(sp) -> saved r3 + / 6(sp) -> saved r2 + / 10(sp) -> return address + / 12(sp) -> 1st arg: idat + / 14(sp) -> 2nd arg: odat + + mov 12(sp), r2 / r2 = idat + mov 14(sp), r3 / r3 = odat + + mov sp,r5 / save sp + mov sp,(r3) / store original sp in odat[0] + mov sp,2(r3) / store original sp in odat[1] + mov sp,4(r3) / store original sp in odat[2] + +/ handle r,w,h commands first + clr r0 / set exit code + movb (r2),r1 / command code + mov 2(r2),r4 / repeat count used as address + +/ handle 'r': probe read + cmpb $'r,r1 + bne testw + mov (r4),r1 / probe read + br done + +/ handle 'w': probe read/write +testw: cmpb $'w,r1 + bne testh + mov (r4),r1 / probe read + mov r1,(r4) / probe re-write + br done + +/ handle 'h': probe halt +testh: cmpb $'h,r1 + bne testx + halt / success is crash here :) +testx: + +/ apply sp aligns and offset. In python pseudo code do +/ # segmemt align +/ if idat[3] > 0: +/ sp &= 017777 +/ sp -= 8192 * (idat[3]-1) +/ # click align +/ if idat[2] > 0: +/ sp &= 077 +/ sp -= 64 * (idat[2]-1) +/ # byte offset +/ sp += idat[4] +/ + mov sp,r4 +/ handle -s + tst 6(r2) / idat[3] -s count > 0 ? + beq optc + bic $017777,r4 / sp &= 017777 + mov 6(r2),r1 + dec r1 / idat[3]-1 + mul $020000,r1 + sub r1,r4 / sp -= 8192 * (idat[3]-1) +/ handle -c +optc: tst 4(r2) / idat[2] -c count > 0 ? + beq opto + bic $000077,r4 / sp &= 077 + mov 4(r2),r1 + dec r1 / idat[2]-1 + mul $000100,r1 + sub r1,r4 / sp -= 64 * (idat[2]-1) +/ handle -o +opto: add 10(r2),r4 + mov r4,sp + mov sp,2(r3) / store aligned+offset sp in odat[1] + +/ prepare command handling + clr r0 / set exit code + mov (r2),r1 / command code + mov 2(r2),r4 / command repeat count + beq done / if zero quit + +/ handle 'I': clr -(sp) + cmpb $'I,r1 + bne testi +1: clr -(sp) + sob r4,1b + br done + +/ handle 'i': stcfi f0,-(sp); movfi fr0,-(sp) in BSD +testi: cmpb $'i,r1 + bne testl + seti + setf + clrf fr0 +1: movfi fr0,-(sp) + sob r4,1b + br done + +/ handle 'l': stcfl f0,-(sp); movfi fr0,-(sp) in BSD +testl: cmpb $'l,r1 + bne testf + setl + setf + clrf fr0 +1: movfi fr0,-(sp) + sob r4,1b + br done + +/ handle 'f': stf f0,-(sp); movf fr0,-(sp) in BSD +testf: cmpb $'f,r1 + bne testd + setf + clrf fr0 +1: movf fr0,-(sp) + sob r4,1b + br done + +/ handle 'd': std f0,-(sp); movf fr0,-(sp) in BSD +testd: cmpb $'d,r1 + bne quit + setd + clrf fr0 +1: movf fr0,-(sp) + sob r4,1b + br done + +/ quit with bad command +quit: inc r0 + +/ final cleanup +done: mov sp,4(r3) / sp after tests + mov r5,sp / restore sp + mov (sp)+,r5 / restore r5 + mov (sp)+,r4 / restore r4 + mov (sp)+,r3 / restore r3 + mov (sp)+,r2 / restore r2 + rts pc diff --git a/tools/tests/stktst/stktst.c b/tools/tests/stktst/stktst.c new file mode 100644 index 00000000..775d1e45 --- /dev/null +++ b/tools/tests/stktst/stktst.c @@ -0,0 +1,116 @@ +/* $Id: $ */ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* Copyright 2022- by Walter F.J. Mueller */ + +/* Revision History: */ +/* Date Rev Version Comment */ +/* 2022-08-01 1267 1.0 Initial version */ + +#include +#include +#include +#include +#include + +int doconv(arg) + char *arg; +{ + char *eptr = NULL; + long res = 0; + int ires = 0; + if (arg[0] == 0) { + fprintf(stderr, "stktst-E: empty string instead of a number\n"); + exit(1); + } + res = strtol(arg, &eptr, 0); + if (eptr[0] != 0) { + fprintf(stderr, "stktst-E: number '%s' invalid after '%s' \n", arg, eptr); + exit(1); + } + + if (errno == ERANGE || res > 0xFFFFL || res < -0x8000L) { + fprintf(stderr, "stktst-E: number '%s' out of range\n", arg); + exit(1); + } + + ires = res; + return ires; +} + + +int main(argc, argv) + int argc; + char *argv[]; +{ + int argi = 0; + char cmd = 0; + int rcnt = 0; + int cnt = 0; + int idat[5]; + int odat[3]; + int optrwh = 0; + int dotst(); + + if (argc < 3) { + fprintf(stderr, "stktst-E: at least two arguments required\n"); + exit(1); + } + + cmd = argv[1][0]; /* get command */ + rcnt = doconv(argv[2]); + idat[0] = cmd; /* command code */ + idat[1] = 0; /* command repeat */ + idat[2] = 0; /* -c repeat */ + idat[3] = 0; /* -s repeat */ + idat[4] = 0; /* -o offset */ + + /* check that command is valid */ + switch (cmd) { + case 'r': + case 'w': + case 'h': + optrwh = 1; + break; + case 'I': + case 'i': + case 'l': + case 'f': + case 'd': + break; + default: + fprintf(stderr, "stktst-E: invalid command %c\n", cmd); + exit(1); + } + + /* process options */ + for (argi=3; argi= argc) { + fprintf(stderr, "stktst-E: no value after %s \n", argv[argi]); + exit(1); + } + cnt = doconv(argv[argi+1]); + if (strcmp(argv[argi], "-c") == 0) { + idat[2] = cnt; + } else if (strcmp(argv[argi], "-s") == 0) { + idat[3] = cnt; + } else if (strcmp(argv[argi], "-o") == 0) { + idat[4] = cnt; + } else { + fprintf(stderr, "stktst-E: bad option %s \n", argv[argi]); + exit(1); + } + } + + if (optrwh) idat[1] = rcnt; + /* call test: 1st round */ + dotst(idat, odat); + if (optrwh) exit(0); + fprintf(stdout, "stktst-I: before sp %06o %06o\n", odat[0], odat[1]); + + /* call test: 2nd round */ + idat[1] = rcnt; + dotst(idat, odat); + fprintf(stdout, "stktst-I: after sp %06o %06o %6o\n", + odat[0], odat[1], odat[2]); + exit(0); +}