1
0
mirror of https://github.com/hsoft/collapseos.git synced 2024-11-02 18:10:55 +11:00

Compare commits

..

No commits in common. "1b8b113536b560039ac02f224ce02315d9fb0fe5" and "5d33d165a2854f579140404c36ca5c0da21efe08" have entirely different histories.

41 changed files with 165 additions and 346 deletions

View File

@ -88,22 +88,13 @@ etc.) always to so in variable `A`.
Another is that whenever a number is expected, expressions, including the ones
with variables in it, work fine.
### One-liners
The `:` character, when not inside a `""` literal, allows you to cram more than
one instruction on the same line.
Things are special with `if`. All commands following a `if` are bound to that
`if`'s condition. `if 0 foo:bar` doesn't execute `bar`.
Another special thing is `goto`. A `goto` followed by `:` will have the commands
following the `:` before the goto occurs.
### Commands
There are two types of commands: normal and direct-only. The latter can only
be invoked in direct mode, not through a code listing.
`bye`: Direct-only. Quits BASIC
`list`: Direct-only. Prints all lines in the code listing, prefixing them
with their associated line number.
@ -126,14 +117,11 @@ specified as an argument. Errors out if line doesn't exist. Argument can be
an expression. If invoked in direct mode, `run` must be called to actually
run the line (followed by the next, and so on).
`if <cond> <cmds>`: If specified condition is true, execute the rest of the
`if <cond> <cmd>`: If specified condition is true, execute the rest of the
line. Otherwise, do nothing. For example, `if 2>1 print 12` prints `12` and `if
2<1 print 12` does nothing. The argument for this command is a "thruth
expression".
`while <cond> <cmds>`: As long as specified condition is true, execute specified
commands repeatedly.
`input [<prompt>]`: Prompts the user for a numerical value and puts that
value in `A`. The prompted value is evaluated as an expression and then stored.
The command takes an optional string literal parameter. If present, that string

View File

@ -46,7 +46,7 @@ basLDBAS:
call parseDecimal
jr nz, .notANumber
push ix \ pop de
call toSepOrEnd
call toSep
call rdSep
call bufAdd
pop hl ; <-- lvl 1

View File

@ -41,14 +41,14 @@ basLoop:
call parseDecimal
jr z, .number
ld de, basCmds1
call basCallCmds
call basCallCmd
jr z, basLoop
; Error
call basERR
jr basLoop
.number:
push ix \ pop de
call toSepOrEnd
call toSep
call rdSep
call bufAdd
jp nz, basERR
@ -110,27 +110,6 @@ basCallCmd:
call rdSep
jp (ix)
; Call a series of ':'-separated commands in (HL) using cmd table in (DE).
; Stop processing as soon as one command unsets Z.
basCallCmds:
; Commands are not guaranteed at all to preserve HL and DE, so we
; preserve them ourselves here.
push hl ; --> lvl 1
push de ; --> lvl 2
call basCallCmd
pop de ; <-- lvl 2
pop hl ; <-- lvl 1
ret nz
call toEnd
ret z ; no more cmds
; we met a ':', we have more cmds
inc hl
call basCallCmds
; move the the end of the string so that we don't run cmds following a
; ':' twice.
call strskip
ret
basERR:
ld hl, .sErr
call printstr
@ -175,7 +154,7 @@ basRUN:
call bufStr
ld de, basCmds2
push ix ; --> lvl 1
call basCallCmds
call basCallCmd
pop ix ; <-- lvl 1
jp nz, .err
call .maybeGOTO
@ -267,49 +246,22 @@ basGOTO:
ld (BAS_PNEXTLN), de
ret
; evaluate truth condition at (HL) and set A to its value
; Z for success (but not truth!)
_basEvalCond:
basIF:
push hl ; --> lvl 1. original arg
ld de, SCRATCHPAD
call rdWord
ex de, hl
call parseTruth
pop hl ; <-- lvl 1. restore
ret
basIF:
call _basEvalCond
ret nz ; error
ret nz
or a
ret z
; expr is true, execute next
; (HL) back to beginning of args, skip to next arg
call toSepOrEnd
call toSep
call rdSep
ret nz
ld de, basCmds2
jp basCallCmds
basWHILE:
push hl ; --> lvl 1
call _basEvalCond
jr nz, .stop ; error
or a
jr z, .stop
ret z
; expr is true, execute next
; (HL) back to beginning of args, skip to next arg
call toSepOrEnd
call rdSep
ret nz
ld de, basCmds2
call basCallCmds
pop hl ; <-- lvl 1
jr basWHILE
.stop:
pop hl ; <-- lvl 1
ret
jp basCallCmd
basINPUT:
; If our first arg is a string literal, spit it
@ -504,8 +456,6 @@ basCmds2:
.dw basGOTO
.db "if", 0
.dw basIF
.db "while", 0
.dw basWHILE
.db "input", 0
.dw basINPUT
.db "peek", 0

View File

@ -1,16 +1,10 @@
; Whether A is a separator or end-of-string (null or ':')
isSepOrEnd:
or a
ret z
cp ':'
ret z
; continue to isSep
; Sets Z is A is ' ' or '\t' (whitespace)
; Sets Z is A is ' ' or '\t' (whitespace), or ',' (arg sep)
isSep:
cp ' '
ret z
cp 0x09
ret z
cp ','
ret
; Expect at least one whitespace (0x20, 0x09) at (HL), and then advance HL
@ -29,8 +23,8 @@ rdSep:
ld a, (hl)
call isSep
jr z, .loop
call isSepOrEnd
jp z, .fail ; unexpected EOL. fail
or a ; cp 0
jp z, .fail
cp a ; ensure Z
ret
.fail:
@ -39,28 +33,12 @@ rdSep:
ret
; Advance HL to the next separator or to the end of string.
toSepOrEnd:
toSep:
ld a, (hl)
call isSepOrEnd
call isSep
ret z
inc hl
jr toSepOrEnd
; Advance HL to the end of the line, that is, either a null terminating char
; or the ':'.
; Sets Z if we met a null char, unset if we met a ':'
toEnd:
ld a, (hl)
or a
ret z
cp ':'
jr z, .havesep
inc hl
call skipQuoted
jr toEnd
.havesep:
inc a ; unset Z
ret
jr toSep
; Read (HL) until the next separator and copy it in (DE)
; DE is preserved, but HL is advanced to the end of the read word.
@ -69,7 +47,9 @@ rdWord:
push de
.loop:
ld a, (hl)
call isSepOrEnd
call isSep
jr z, .stop
or a
jr z, .stop
ld (de), a
inc hl

View File

@ -11,22 +11,5 @@ spitQuoted:
inc hl
cp '"'
ret z
or a
ret z
call stdioPutC
jr .loop
; Same as spitQuoted, but without the spitting
skipQuoted:
ld a, (hl)
cp '"'
ret nz
inc hl
.loop:
ld a, (hl)
inc hl
cp '"'
ret z
or a
ret z
jr .loop

View File

@ -33,7 +33,6 @@
.inc "core.asm"
.inc "lib/util.asm"
.inc "lib/parse.asm"
.inc "ed/util.asm"
.equ IO_RAMSTART USER_RAMSTART
.inc "ed/io.asm"
.equ BUF_RAMSTART IO_RAMEND

View File

@ -1,8 +0,0 @@
; Compare HL with DE and sets Z and C in the same way as a regular cp X where
; HL is A and DE is X.
cpHLDE:
push hl
or a ;reset carry flag
sbc hl, de ;There is no 'sub hl, de', so we must use sbc
pop hl
ret

View File

@ -52,12 +52,21 @@ Let's try an example: You glue yourself a Collapse OS with a mmap starting at
could do to copy memory around:
> m=0xe000
> while m<0xe004 getc:poke m a:m=m+1
> 10 getc
> 20 poke m a
> 30 m=m+1
> 40 if m<0xe004 goto 10
> run
[enter "abcd"]
> bsel 3
> i=0
> while i<4 getb:puth a:i=i+1
61626364> bseek 2
> getb:puth a
63> getb:puth a
> clear
> 10 getb
> 20 puth a
> run
61> run
62> run
63> run
64> bseek 2
> run
63> run
64>

View File

@ -21,7 +21,9 @@ increase a number at memory address `0xa100`. First, compile it:
Now, we'll send that code to address `0xa000`:
> m=0xa000
> while m<0xa008 getc:poke m a:m=m+1
> 10 getc
> 20 poke m a
> 30 if m<0xa008 goto 10
(resulting binary is 8 bytes long)
Now, at this point, it's a bit delicate. To pipe your binary to your serial

View File

@ -57,6 +57,15 @@ intoIX:
pop ix
ret
; Compare HL with DE and sets Z and C in the same way as a regular cp X where
; HL is A and DE is X.
cpHLDE:
push hl
or a ;reset carry flag
sbc hl, de ;There is no 'sub hl, de', so we must use sbc
pop hl
ret
; Write the contents of HL in (DE)
; de and hl are preserved, so no pushing/popping necessary
writeHLinDE:

View File

@ -413,17 +413,17 @@ fsPlaceH:
; Sets Z according to whether HL is within bounds for file handle at (IX), that
; is, if it is smaller than file size.
fsWithinBounds:
ld a, h
cp (ix+5)
jr c, .within ; H < (IX+5)
jp nz, unsetZ ; H > (IX+5)
; H == (IX+5)
ld a, l
cp (ix+4)
jp nc, unsetZ ; L >= (IX+4)
.within:
push de
; file size
ld e, (ix+4)
ld d, (ix+5)
call cpHLDE
pop de
jr nc, .outOfBounds ; HL >= DE
cp a ; ensure Z
ret
.outOfBounds:
jp unsetZ ; returns
; Set size of file handle (IX) to value in HL.
; This writes directly in handle's metadata.

View File

@ -13,10 +13,8 @@
_mmapAddr:
push de
ld de, MMAP_LEN
or a ; reset carry flag
sbc hl, de
call cpHLDE
jr nc, .outOfBounds ; HL >= DE
add hl, de ; old HL value
ld de, MMAP_START
add hl, de
cp a ; ensure Z

View File

@ -27,7 +27,7 @@
; *** Consts ***
; Size of the readline buffer. If a typed line reaches this size, the line is
; flushed immediately (same as pressing return).
.equ STDIO_BUFSIZE 0x40
.equ STDIO_BUFSIZE 0x20
; *** Variables ***
; Line buffer. We read types chars into this buffer until return is pressed

View File

@ -40,7 +40,7 @@ jp aciaInt
; *** BASIC ***
; RAM space used in different routines for short term processing.
.equ SCRATCHPAD_SIZE STDIO_BUFSIZE
.equ SCRATCHPAD_SIZE 0x20
.equ SCRATCHPAD AT28W_RAMEND
.inc "lib/util.asm"
.inc "lib/ari.asm"

View File

@ -25,7 +25,7 @@ jp aciaInt
; *** BASIC ***
; RAM space used in different routines for short term processing.
.equ SCRATCHPAD_SIZE STDIO_BUFSIZE
.equ SCRATCHPAD_SIZE 0x20
.equ SCRATCHPAD STDIO_RAMEND
.inc "lib/util.asm"
.inc "lib/ari.asm"

View File

@ -24,7 +24,7 @@ jp init
; *** BASIC ***
; RAM space used in different routines for short term processing.
.equ SCRATCHPAD_SIZE STDIO_BUFSIZE
.equ SCRATCHPAD_SIZE 0x20
.equ SCRATCHPAD STDIO_RAMEND
.inc "lib/util.asm"
.inc "lib/ari.asm"

View File

@ -48,7 +48,7 @@ jp aciaInt
; *** BASIC ***
; RAM space used in different routines for short term processing.
.equ SCRATCHPAD_SIZE STDIO_BUFSIZE
.equ SCRATCHPAD_SIZE 0x20
.equ SCRATCHPAD FS_RAMEND
.inc "lib/util.asm"
.inc "lib/ari.asm"

View File

@ -1,10 +1,10 @@
; classic RC2014 setup (8K ROM + 32K RAM) and a stock Serial I/O module
; The RAM module is selected on A15, so it has the range 0x8000-0xffff
.equ RAMSTART 0x8000
; Kernel RAMEND last check: 0x9933
; Kernel RAMEND last check: 0x98f3
; We allocate at least 0x100 bytes for the stack, which is why we have this
; threshold.
.equ RAMEND 0x9b00
.equ RAMEND 0x9a00
.equ USER_CODE RAMEND ; in sync with user.h
.equ ACIA_CTL 0x80 ; Control and status. RS off.
.equ ACIA_IO 0x81 ; Transmit. RS on.
@ -67,7 +67,7 @@ jp aciaInt
; *** BASIC ***
; RAM space used in different routines for short term processing.
.equ SCRATCHPAD_SIZE STDIO_BUFSIZE
.equ SCRATCHPAD_SIZE 0x20
.equ SCRATCHPAD FS_RAMEND
.inc "lib/util.asm"
.inc "lib/ari.asm"

View File

@ -1,4 +1,4 @@
.org 0x9b00
.org 0x9a00
; *** JUMP TABLE ***
.equ strncmp 0x03

View File

@ -27,7 +27,7 @@
; *** BASIC ***
; RAM space used in different routines for short term processing.
.equ SCRATCHPAD_SIZE STDIO_BUFSIZE
.equ SCRATCHPAD_SIZE 0x20
.equ SCRATCHPAD STDIO_RAMEND
.inc "lib/util.asm"
.inc "lib/ari.asm"

View File

@ -29,7 +29,7 @@
; *** BASIC ***
; RAM space used in different routines for short term processing.
.equ SCRATCHPAD_SIZE STDIO_BUFSIZE
.equ SCRATCHPAD_SIZE 0x20
.equ SCRATCHPAD STDIO_RAMEND
.inc "lib/util.asm"
.inc "lib/ari.asm"

View File

@ -77,7 +77,7 @@
; *** BASIC ***
; RAM space used in different routines for short term processing.
.equ SCRATCHPAD_SIZE STDIO_BUFSIZE
.equ SCRATCHPAD_SIZE 0x20
.equ SCRATCHPAD FS_RAMEND
.inc "lib/util.asm"
.inc "lib/ari.asm"

View File

@ -40,7 +40,7 @@
; *** BASIC ***
; RAM space used in different routines for short term processing.
.equ SCRATCHPAD_SIZE STDIO_BUFSIZE
.equ SCRATCHPAD_SIZE 0x20
.equ SCRATCHPAD STDIO_RAMEND
.inc "lib/util.asm"
.inc "lib/ari.asm"

View File

@ -21,18 +21,17 @@ int main(int argc, char **argv)
}
int fd = open(argv[1], O_RDWR|O_NOCTTY);
char s[0x30];
sendcmdp(fd, "i=0");
sprintf(s, "while i<0x%04x getb:puth a:i=i+1", bytecount);
sendcmd(fd, s);
char s[3];
for (int i=0; i<bytecount; i++) {
sendcmd(fd, "getb");
read(fd, s, 2); // read prompt
sendcmd(fd, "puth a");
read(fd, s, 2); // read hex pair
s[2] = 0; // null terminate
unsigned char c = strtol(s, NULL, 16);
putchar(c);
read(fd, s, 2); // read prompt
}
read(fd, s, 2); // read prompt
return 0;
}

View File

@ -25,16 +25,6 @@ We don't try to emulate real hardware to ease the development of device drivers
because so far, I don't see the advantage of emulation versus running code on
the real thing.
By default, the shell initialized itself with a CFS device containing the
contents of `cfsin/` at launch (it's packed on the fly). You can specify an
alternate CFS device file (it has to be packaed already) through the `-f` flag.
By default, the shell runs interactively, but you can also pipe contents through
stdin instead. The contents will be interpreted exactly as if you had typed it
yourself and the result will be spit in stdout (it includes your typed in
contents because the Collapse OS console echoes back every character that is
sent to it.). This feature is useful for automated tests in `tools/tests/shell`.
## zasm
`zasm/zasm` is `apps/zasm` wrapped in an emulator. It is quite central to the

View File

@ -70,7 +70,7 @@
; *** BASIC ***
; RAM space used in different routines for short term processing.
.equ SCRATCHPAD_SIZE STDIO_BUFSIZE
.equ SCRATCHPAD_SIZE 0x20
.equ SCRATCHPAD FS_RAMEND
.inc "lib/util.asm"
.inc "lib/ari.asm"

View File

@ -1,6 +1,5 @@
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include "../emul.h"
#include "shell-bin.h"
@ -41,6 +40,7 @@
#define FS_ADDR_PORT 0x02
static uint8_t fsdev[MAX_FSDEV_SIZE] = {0};
static uint32_t fsdev_size = 0;
static uint32_t fsdev_ptr = 0;
// 0 = idle, 1 = received MSB (of 24bit addr), 2 = received middle addr
static int fsdev_addr_lvl = 0;
@ -61,13 +61,16 @@ static uint8_t iord_fsdata()
fprintf(stderr, "Reading FSDEV in the middle of an addr op (%d)\n", fsdev_ptr);
return 0;
}
if (fsdev_ptr < MAX_FSDEV_SIZE) {
if (fsdev_ptr < fsdev_size) {
#ifdef DEBUG
fprintf(stderr, "Reading FSDEV at offset %d\n", fsdev_ptr);
#endif
return fsdev[fsdev_ptr];
} else {
fprintf(stderr, "Out of bounds FSDEV read at %d\n", fsdev_ptr);
// don't warn when ==, we're not out of bounds, just at the edge.
if (fsdev_ptr > fsdev_size) {
fprintf(stderr, "Out of bounds FSDEV read at %d\n", fsdev_ptr);
}
return 0;
}
}
@ -76,9 +79,11 @@ static uint8_t iord_fsaddr()
{
if (fsdev_addr_lvl != 0) {
return 3;
} else if (fsdev_ptr >= MAX_FSDEV_SIZE) {
fprintf(stderr, "Out of bounds FSDEV addr request at %d / %d\n", fsdev_ptr, MAX_FSDEV_SIZE);
} else if (fsdev_ptr > fsdev_size) {
fprintf(stderr, "Out of bounds FSDEV addr request at %d / %d\n", fsdev_ptr, fsdev_size);
return 2;
} else if (fsdev_ptr == fsdev_size) {
return 1;
} else {
return 0;
}
@ -99,11 +104,18 @@ static void iowr_fsdata(uint8_t val)
fprintf(stderr, "Writing to FSDEV in the middle of an addr op (%d)\n", fsdev_ptr);
return;
}
if (fsdev_ptr < MAX_FSDEV_SIZE) {
if (fsdev_ptr < fsdev_size) {
#ifdef DEBUG
fprintf(stderr, "Writing to FSDEV (%d)\n", fsdev_ptr);
#endif
fsdev[fsdev_ptr] = val;
} else if ((fsdev_ptr == fsdev_size) && (fsdev_ptr < MAX_FSDEV_SIZE)) {
// We're at the end of fsdev, grow it
fsdev[fsdev_ptr] = val;
fsdev_size++;
#ifdef DEBUG
fprintf(stderr, "Growing FSDEV (%d)\n", fsdev_ptr);
#endif
} else {
fprintf(stderr, "Out of bounds FSDEV write at %d\n", fsdev_ptr);
}
@ -123,60 +135,34 @@ static void iowr_fsaddr(uint8_t val)
}
}
int main(int argc, char *argv[])
int main()
{
FILE *fp = NULL;
while (1) {
int c = getopt(argc, argv, "f:");
if (c < 0) {
break;
}
switch (c) {
case 'f':
fp = fopen(optarg, "r");
if (fp == NULL) {
fprintf(stderr, "Can't open %s\n", optarg);
return 1;
}
break;
default:
fprintf(stderr, "Usage: shell [-f fsdev]\n");
return 1;
}
}
// Setup fs blockdev
if (fp == NULL) {
fp = popen("../cfspack/cfspack cfsin", "r");
if (fp == NULL) {
fprintf(stderr, "Can't initialize filesystem. Leaving blank.\n");
}
}
FILE *fp = popen("../cfspack/cfspack cfsin", "r");
if (fp != NULL) {
fprintf(stderr, "Initializing filesystem\n");
printf("Initializing filesystem\n");
int i = 0;
int c;
while ((c = fgetc(fp)) != EOF && i < MAX_FSDEV_SIZE) {
fsdev[i++] = c & 0xff;
}
if (i == MAX_FSDEV_SIZE) {
fprintf(stderr, "Filesytem image too large.\n");
return 1;
int c = fgetc(fp);
while (c != EOF) {
fsdev[i] = c & 0xff;
i++;
c = fgetc(fp);
}
fsdev_size = i;
pclose(fp);
} else {
printf("Can't initialize filesystem. Leaving blank.\n");
}
bool tty = isatty(fileno(stdin));
// Turn echo off: the shell takes care of its own echoing.
struct termios termInfo;
if (tty) {
// Turn echo off: the shell takes care of its own echoing.
if (tcgetattr(0, &termInfo) == -1) {
printf("Can't setup terminal.\n");
return 1;
}
termInfo.c_lflag &= ~ECHO;
termInfo.c_lflag &= ~ICANON;
tcsetattr(0, TCSAFLUSH, &termInfo);
if (tcgetattr(0, &termInfo) == -1) {
printf("Can't setup terminal.\n");
return 1;
}
termInfo.c_lflag &= ~ECHO;
termInfo.c_lflag &= ~ICANON;
tcsetattr(0, TCSAFLUSH, &termInfo);
Machine *m = emul_init();
@ -196,12 +182,10 @@ int main(int argc, char *argv[])
while (running && emul_step());
if (tty) {
printf("Done!\n");
termInfo.c_lflag |= ECHO;
termInfo.c_lflag |= ICANON;
tcsetattr(0, TCSAFLUSH, &termInfo);
emul_printdebug();
}
printf("Done!\n");
termInfo.c_lflag |= ECHO;
termInfo.c_lflag |= ICANON;
tcsetattr(0, TCSAFLUSH, &termInfo);
emul_printdebug();
return 0;
}

View File

@ -28,18 +28,22 @@ int main(int argc, char **argv)
}
int fd = open(argv[1], O_RDWR|O_NOCTTY);
char s[0x30];
char s[0x20];
sprintf(s, "m=0x%04x", memptr);
sendcmdp(fd, s);
sprintf(s, "while m<0x%04x peek m:puth a:m=m+1", memptr+bytecount);
sendcmd(fd, s);
read(fd, s, 2); // read prompt
for (int i=0; i<bytecount; i++) {
sendcmd(fd, "peek m");
read(fd, s, 2); // read prompt
sendcmd(fd, "puth a");
read(fd, s, 2); // read hex pair
s[2] = 0; // null terminate
unsigned char c = strtol(s, NULL, 16);
putchar(c);
read(fd, s, 2); // read prompt
sendcmd(fd, "m=m+1");
read(fd, s, 2); // read prompt
}
read(fd, s, 2); // read prompt
return 0;
}

View File

@ -1,16 +1,7 @@
EMULDIR = ../emul
CFSPACK = ../cfspack/cfspack
.PHONY: run
run:
$(MAKE) -C $(EMULDIR) zasm/zasm runbin/runbin shell/shell
$(MAKE) -C $(EMULDIR) zasm/zasm runbin/runbin
cd unit && ./runtests.sh
cd zasm && ./runtests.sh
cd shell && ./runtests.sh
$(CFSPACK):
$(MAKE) -C ../cfspack
.PHONY: cfs
cfs: $(CFSPACK)
$(CFSPACK) shell/cfsin > shell/test.cfs

View File

@ -40,10 +40,3 @@ However, there are tricks.
1. Run `unit/runtests.sh <name of file to test>` to target a specific test unit.
2. Insert a `halt` to see the value of `A` at any given moment: it will be your
reported error code (if 0, runbin will report a success).
## shell
Those tests are in the form of shell "replay" files. Every ".replay" file in
this folder contains the contents to type in the shell. That contents is piped
through the shell and the output is then compared with the corresponding
".expected" file. If they match exactly, the test passes.

View File

@ -1 +0,0 @@
Hello Bar!

View File

@ -1 +0,0 @@
Hello Foo!

View File

@ -1,5 +0,0 @@
Collapse OS
> fls
bar
foo
>

View File

@ -1 +0,0 @@
fls

View File

@ -1,4 +0,0 @@
Collapse OS
> print 42
42
>

View File

@ -1 +0,0 @@
print 42

View File

@ -1,28 +0,0 @@
#!/bin/sh -e
EMULDIR=../../emul
SHELL=../../emul/shell/shell
replay() {
fn=$1
replayfn=${fn%.*}.expected
ACTUAL=$("${SHELL}" -f test.cfs < "${fn}" 2> /dev/null)
EXPECTED=$(cat ${replayfn})
if [ "$ACTUAL" = "$EXPECTED" ]; then
echo ok
else
echo different. Whole output:
echo "${ACTUAL}"
exit 1
fi
}
if [ ! -z $1 ]; then
replay $1
exit 0
fi
for fn in *.replay; do
echo "Replaying ${fn}"
replay "${fn}"
done

Binary file not shown.

View File

@ -5,6 +5,8 @@
jp test
.inc "core.asm"
dummyLabel:
testNum: .db 1
@ -46,11 +48,30 @@ test:
; test that "@" is updated by a .org directive
ld hl, AFTER_ORG
ld de, 0x1234
or a ; clear carry
sbc hl, de
call cpHLDE
jp nz, fail
call nexttest
; *** cpHLDE ***
ld hl, 0x42
ld de, 0x42
call cpHLDE
jp nz, fail
jp c, fail
call nexttest
ld de, 0x4242
call cpHLDE
jp z, fail
jp nc, fail
call nexttest
ld hl, 0x4243
call cpHLDE
jp z, fail
jp c, fail
call nexttest
; success
xor a
halt

View File

@ -1,42 +0,0 @@
jp test
.inc "ed/util.asm"
test:
ld sp, 0xffff
; *** cpHLDE ***
ld hl, 0x42
ld de, 0x42
call cpHLDE
jp nz, fail
jp c, fail
call nexttest
ld de, 0x4242
call cpHLDE
jp z, fail
jp nc, fail
call nexttest
ld hl, 0x4243
call cpHLDE
jp z, fail
jp c, fail
call nexttest
; success
xor a
halt
testNum: .db 1
nexttest:
ld a, (testNum)
inc a
ld (testNum), a
ret
fail:
ld a, (testNum)
halt

View File

@ -5,8 +5,10 @@
#include "common.h"
/* Push specified file to specified device running the BASIC shell and verify
/* Push specified file to specified device **running the BASIC shell** and verify
* that the sent contents is correct.
*
* Note: running this will clear the current BASIC listing on the other side.
*/
int main(int argc, char **argv)
@ -36,12 +38,20 @@ int main(int argc, char **argv)
}
rewind(fp);
int fd = open(argv[1], O_RDWR|O_NOCTTY);
char s[0x40];
char s[0x20];
sprintf(s, "m=0x%04x", memptr);
sendcmdp(fd, s);
sprintf(s, "while m<0x%04x getc:puth a:poke m a:m=m+1", memptr+bytecount);
sendcmd(fd, s);
// Send program
sendcmdp(fd, "clear");
sendcmdp(fd, "1 getc");
sendcmdp(fd, "2 puth a");
sendcmdp(fd, "3 poke m a");
sendcmdp(fd, "4 m=m+1");
sprintf(s, "5 if m<0x%04x goto 1", memptr+bytecount);
sendcmdp(fd, s);
sendcmd(fd, "run");
int returncode = 0;
while (fread(s, 1, 1, fp)) {
putchar('.');