diff options
author | B. Watson <urchlay@slackware.uk> | 2025-03-26 03:00:48 -0400 |
---|---|---|
committer | B. Watson <urchlay@slackware.uk> | 2025-03-26 03:00:48 -0400 |
commit | 67b67eebb77512ffac50e8650cfc9f30913869fd (patch) | |
tree | 3c8093d75b45fdcdb734d59042e82014c1a7a2e5 | |
parent | e45e1eefc9d7abc526d28710e6a0298c525c80fb (diff) | |
download | bw-atari8-tools-67b67eebb77512ffac50e8650cfc9f30913869fd.tar.gz |
whichbas and listbas: distinguish between Integer BASIC disk and cart versions.
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | bas.c | 5 | ||||
-rw-r--r-- | bas.h | 2 | ||||
-rw-r--r-- | int_disk_tokens.c | 94 | ||||
-rw-r--r-- | int_disk_tokens.h | 5 | ||||
-rw-r--r-- | listbas.c | 47 | ||||
-rw-r--r-- | ossintbas.7 | 218 | ||||
-rw-r--r-- | ossintbas_content.rst | 80 | ||||
-rw-r--r-- | whichbas.c | 19 | ||||
-rw-r--r-- | whichbas.h | 3 |
10 files changed, 446 insertions, 31 deletions
@@ -74,8 +74,8 @@ cxrefbas: bas.o bcdfp.o linetab.o bas2aplus: bas.o -listbas: listbas.c bas.o bcdfp.o tokens.o atables.o turbo_tokens.o aplus_tokens.o bxl_tokens.o bxe_tokens.o int_tokens.o - $(CC) $(CFLAGS) -o listbas listbas.c bas.o bcdfp.o tokens.o atables.o turbo_tokens.o aplus_tokens.o bxl_tokens.o bxe_tokens.o int_tokens.o -lm +listbas: listbas.c bas.o bcdfp.o tokens.o atables.o turbo_tokens.o aplus_tokens.o bxl_tokens.o bxe_tokens.o int_disk_tokens.o int_tokens.o + $(CC) $(CFLAGS) -o listbas listbas.c bas.o bcdfp.o tokens.o atables.o turbo_tokens.o aplus_tokens.o bxl_tokens.o bxe_tokens.o int_disk_tokens.o int_tokens.o -lm bas.o: bas.c bas.h @@ -42,6 +42,8 @@ unsigned short stmcur; unsigned short starp; unsigned short codestart; unsigned short code_end; +unsigned short save_command_pos; +unsigned short save_command_tok; unsigned short vnstart; unsigned short vvstart; int filelen; @@ -111,6 +113,7 @@ void dump_header_vars(void) { fprintf(stderr, "LOMEM $%04x VNTP $%04x VNTD $%04x VVTP $%04x\n", lomem, vntp, vntd, vvtp); fprintf(stderr, "STMTAB $%04x STMCUR $%04x STARP $%04x\n", stmtab, stmcur, starp); fprintf(stderr, "vnstart $%04x, vvstart $%04x, codestart $%04x, code_end $%04x\n", vnstart, vvstart, codestart, code_end); + fprintf(stderr, "save_command_pos $%04x (tok $%02x)\n", save_command_pos, save_command_tok); } void parse_header(void) { @@ -127,6 +130,8 @@ void parse_header(void) { codestart = stmtab - TBL_OFFSET - (vntp - 256); vnstart = vntp - TBL_OFFSET; vvstart = vvtp - TBL_OFFSET; + save_command_pos = stmcur - TBL_OFFSET; + save_command_tok = program[save_command_pos + 4]; code_end = starp - TBL_OFFSET; if(vnstart > 0x0e) { @@ -184,6 +184,8 @@ extern unsigned short starp; /* positions where various parts of the file start, derived from the header vars above. */ extern unsigned short codestart; +extern unsigned short save_command_pos; +extern unsigned short save_command_tok; extern unsigned short code_end; extern unsigned short vnstart; extern unsigned short vvstart; diff --git a/int_disk_tokens.c b/int_disk_tokens.c new file mode 100644 index 0000000..9e15534 --- /dev/null +++ b/int_disk_tokens.c @@ -0,0 +1,94 @@ +const char *int_disk_cmds[] = { + "REM", /* $00 */ + "DATA", /* $01 */ + "INPUT", /* $02 */ + "COLOR", /* $03 */ + "LIST", /* $04 */ + "ENTER", /* $05 */ + "LET", /* $06 */ + "IF", /* $07 */ + "FOR", /* $08 */ + "NEXT", /* $09 */ + "GOTO", /* $0A */ + "GO TO", /* $0B */ + "GOSUB", /* $0C */ + "TRAP", /* $0D */ + "BYE", /* $0E */ + "CONT", /* $0F */ + "COM", /* $10 */ + "CLOSE", /* $11 */ + "CLR", /* $12 */ + "VBLANKWAIT", /* $13 */ + "DIM", /* $14 */ + "", /* $15 */ + "NEW", /* $16 */ + "OPEN", /* $17 */ + "LOAD", /* $18 */ + "SAVE", /* $19 */ + "STATUS", /* $1A */ + "NOTE", /* $1B */ + "POINT", /* $1C */ + "XIO", /* $1D */ + "ON", /* $1E */ + "POKE", /* $1F */ + "PRINT", /* $20 */ + "READ", /* $21 */ + "RESTORE", /* $22 */ + "RETURN", /* $23 */ + "RUN", /* $24 */ + "STOP", /* $25 */ + "POP", /* $26 */ + "?", /* $27 */ + "GET", /* $28 */ + "PUT", /* $29 */ + "GRAPHICS", /* $2A */ + "PLOT", /* $2B */ + "POSITION", /* $2C */ + "DOS", /* $2D */ + "DRAWTO", /* $2E */ + "SETCOLOR", /* $2F */ + "LOCATE", /* $30 */ + "SOUND", /* $31 */ + "LPRINT", /* $32 */ + "CSAVE", /* $33 */ + "CLOAD", /* $34 */ + "", /* $35 */ + "ERROR- ", /* $36 */ + "WHILE", /* $37 */ + "ENDWHILE", /* $38 */ + "TRACEOFF", /* $39 */ + "TRACE", /* $3A */ + "ELSE", /* $3B */ + "ENDIF", /* $3C */ + "DPOKE", /* $3D */ + "LOMEM", /* $3E */ + "DEL", /* $3F */ + "VINC", /* $40 */ + "VDEC", /* $41 */ + "VCONST", /* $42 */ + "BPUT", /* $43 */ + "BGET", /* $44 */ + "TAB", /* $45 */ + "CP", /* $46 */ + "ERASE", /* $47 */ + "PROTECT", /* $48 */ + "UNPROTECT", /* $49 */ + "DIR", /* $4A */ + "RENAME", /* $4B */ + "MOVE", /* $4C */ + "MISSILE", /* $4D */ + "PMCLR", /* $4E */ + "PMCOLOR", /* $4F */ + "PMGRAPHICS", /* $50 */ + "PMMOVE", /* $51 */ + "PMWIDTH", /* $52 */ + "SET", /* $53 */ + "LVAR", /* $54 */ + "RENUM", /* $55 */ + "FAST", /* $56 */ + "NUM", /* $57 */ + "END", /* $58 */ +}; + +const int int_disk_cmd_size = sizeof(int_disk_cmds); + diff --git a/int_disk_tokens.h b/int_disk_tokens.h new file mode 100644 index 0000000..f5059d9 --- /dev/null +++ b/int_disk_tokens.h @@ -0,0 +1,5 @@ +extern const char *int_disk_cmds[]; +#define int_disk_ops int_ops + +extern const int int_disk_cmd_size; +#define int_disk_ops_size int_ops_size @@ -18,6 +18,7 @@ #include "bxl_tokens.h" #include "bxe_tokens.h" #include "int_tokens.h" +#include "int_disk_tokens.h" #include "atables.h" #include "whichbas.h" @@ -26,7 +27,8 @@ #define B_APLUS SRET_APLUS #define B_BXL SRET_BXL #define B_BXE SRET_BXE -#define B_INT SRET_OSSINT +#define B_INT_C SRET_OSSINT_CART +#define B_INT_D SRET_OSSINT_DISK #define COLOR_FMT "\x1b[%d;3%dm" /* 1st %d is 1 for bold, 2nd is color */ @@ -137,8 +139,12 @@ int get_bas_type(char *arg) { if(arg[0] == 't') return B_TURBO; - if(arg[0] == 'i') - return B_INT; + if(arg[0] == 'i') { + if(arg[1] == 'd') + return B_INT_D; + else if(arg[1] == 'c') + return B_INT_C; + } if(arg[0] == 'a') { if(arg[1] == '+') @@ -377,7 +383,7 @@ void print_bcd_number(unsigned int pos, int hex) { } void print_number(unsigned int pos, int hex) { - if(bas_type == B_INT) + if(bas_type == B_INT_C || bas_type == B_INT_D) print_int_number(pos, hex); else print_bcd_number(pos, hex); @@ -756,7 +762,7 @@ void indent_line(const unsigned char tok) { case B_TURBO: turbo_indent_line(tok); return; case B_BXL: bxl_indent_line(tok); return; case B_BXE: bxe_indent_line(tok); return; - /* TODO: case B_INT: int_indent_line(tok); return; */ + /* TODO: case B_INT_C: int_indent_line(tok); return; */ case B_ATARI: default: return; @@ -772,8 +778,10 @@ CALLBACK(print_cmd) { if(bas_type == B_APLUS) { if(tok == 0x52) return; - } else if(bas_type == B_INT) { + } else if(bas_type == B_INT_C) { if(tok == 0x37) return; + } else if(bas_type == B_INT_D) { + if(tok == 0x35) return; } else { if(tok == CMD_ILET) return; } @@ -942,11 +950,11 @@ CALLBACK(print_op) { return; case OP_EOL: /* in Integer BASIC, this token is TO */ - if(bas_type != B_INT) return; + if((bas_type != B_INT_D) && (bas_type != B_INT_D)) return; break; case 0x13: /* in Integer BASIC, this is the real end-of-line token */ - if(bas_type == B_INT) return; + if(bas_type == B_INT_D || bas_type == B_INT_C) return; default: break; } @@ -956,7 +964,7 @@ CALLBACK(print_op) { fprintf(outfh, "(bad op token $%02x)", tok); badtok = 1; } else { - if(bas_type == B_BXL || bas_type == B_BXE || bas_type == B_INT) + if(bas_type == B_BXL || bas_type == B_BXE || bas_type == B_INT_C || bas_type == B_INT_D) print_mixed_case(name); else fprintf(outfh, "%s", name); @@ -1040,11 +1048,17 @@ void init_aplus_tables() { memmove(op_tokens, aplus_ops, aplus_ops_size); } +/* cartridge version */ void init_int_tables() { memmove(cmd_tokens, int_cmds, int_cmd_size); memmove(op_tokens, int_ops, int_ops_size); } +void init_int_disk_tables() { + memmove(cmd_tokens, int_disk_cmds, int_disk_cmd_size); + memmove(op_tokens, int_disk_ops, int_disk_ops_size); +} + void init_turbo_tables() { memmove(cmd_tokens + last_command + 1, turbo_cmds, turbo_cmd_size); memmove(op_tokens + last_operator + 1, turbo_ops, turbo_ops_size); @@ -1066,9 +1080,12 @@ void init_token_tables() { if(bas_type == B_APLUS) { init_aplus_tables(); return; - } else if(bas_type == B_INT) { + } else if(bas_type == B_INT_C) { init_int_tables(); return; + } else if(bas_type == B_INT_D) { + init_int_disk_tables(); + return; } init_bas_tables(); @@ -1106,7 +1123,8 @@ void set_bas_dialect(int d) { case SRET_TURBO: case SRET_BXL: case SRET_BXE: - case SRET_OSSINT: + case SRET_OSSINT_CART: + case SRET_OSSINT_DISK: bas_type = d; break; case SRET_AMSB: @@ -1161,9 +1179,12 @@ void init_bas_dialect() { if(autodetect) detect_bas_dialect(); - if(bas_type == B_INT) { + if(bas_type == B_INT_C || bas_type == B_INT_D) { numconst_size = 2; - error_token = 0x38; + if(bas_type == B_INT_C) + error_token = 0x38; + else + error_token = 0x36; allow_hex_const = 1; mixed_case = 1; } diff --git a/ossintbas.7 b/ossintbas.7 index 19cbc3a..dda00d3 100644 --- a/ossintbas.7 +++ b/ossintbas.7 @@ -43,12 +43,7 @@ BASIC XL/XE here, as I discover them. For more info on the release: .INDENT 0.0 .INDENT 3.5 -.sp -.nf -.ft C -https://forums.atariage.com/topic/257029\-oss\-d\-day\-part\-3\-integer\-basic\-source\-code\-now\-in\-pd/ -.ft P -.fi +\fI\%https://forums.atariage.com/topic/257029\-oss\-d\-day\-part\-3\-integer\-basic\-source\-code\-now\-in\-pd/\fP .UNINDENT .UNINDENT .SH NUMERICS @@ -91,7 +86,7 @@ Abbreviation: \fBV.\fP .INDENT 0.0 .INDENT 3.5 Increment (add 1 to) a variable. This is about 30% faster than -\fBA=A+1\fP\&. Abbreviate as \fBVD.\fP\&. +\fBA=A+1\fP\&. .sp Abbreviation: \fBVI.\fP .UNINDENT @@ -100,7 +95,7 @@ Abbreviation: \fBVI.\fP \fBVDEC\fP \fI<var>\fP .INDENT 0.0 .INDENT 3.5 -Decrement (subtract 1 from) a variable. Abbreviate as \fBVD.\fP\&. +Decrement (subtract 1 from) a variable. Faster than \fBA=A\-1\fP\&. .sp Abbreviation: \fBVD.\fP .UNINDENT @@ -264,6 +259,213 @@ be used as array variable names, if you wish. .B \fBUSING\fP BASIC XL and XE\(aqs "PRINT USING" doesn\(aqt exist in Integer BASIC. .UNINDENT +.SH PERFORMANCE +.sp +OSS Integer BASIC is \fIfast\fP, compared to other interpreted BASICs on +the Atari. It even outperforms Turbo BASIC XL (though, not \fIcompiled\fP +Turbo). +.sp +For testing, I used a modified version of the Sieve of Eratosthenes +program, found in the source for \fBbas55\fP\&. The program finds and +prints all the prime numbers between 2 and 1000. The code: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +10 POKE 18,0:POKE 19,0:POKE 20,0 +20 DIM A(1000) +30 N=1000 +100 S=SQR(N) +110 FOR I=2 TO S +120 IF A(I)=1 THEN 170 +130 D=N/I +140 FOR J=I TO D +150 A(I*J)=1 +160 NEXT J +170 NEXT I +180 FOR I=2 TO N +190 IF A(I)=1 THEN 210 +200 PRINT I +210 NEXT I +1000 PRINT PEEK(18)*256*256+PEEK(19)*256+PEEK(20) +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Line 1000 prints how many jiffies the program took to run. I used +Atari800 5.2.0 emulating an NTSC Atari 800XL, so one jiffy is 1/60 of +a second. The "Fastchip" results use Charles Marslet\(aqs OS floating +point replacement ROM. For Integer BASIC, BASIC XL and BASIC XE, +separate runs were done with the line \fB5 FAST\fP at the start of the +program. Results: +.TS +center; +|l|l|l|. +_ +T{ +BASIC +T} T{ +Jiffies +T} T{ +Speedup +T} +_ +T{ +Atari 8K +T} T{ +1867 +T} T{ +\-\- +T} +_ +T{ +A+ +T} T{ +1671 +T} T{ +1.12 +T} +_ +T{ +Atari 8K (Fastchip) +T} T{ +1587 +T} T{ +1.18 +T} +_ +T{ +A+ (Fastchip) +T} T{ +1569 +T} T{ +1.19 +T} +_ +T{ +XE +T} T{ +1440 +T} T{ +1.3 +T} +_ +T{ +AMSB2 +T} T{ +1518 +T} T{ +1.23 +T} +_ +T{ +XL +T} T{ +1270 +T} T{ +1.47 +T} +_ +T{ +Altirra +T} T{ +1166 +T} T{ +1.67 +T} +_ +T{ +XL (FAST) +T} T{ +1110 +T} T{ +1.68 +T} +_ +T{ +XL (Fastchip) +T} T{ +1049 +T} T{ +1.78 +T} +_ +T{ +XL (Fastchip, FAST) +T} T{ +887 +T} T{ +2.1 +T} +_ +T{ +Turbo +T} T{ +825 +T} T{ +2.3 +T} +_ +T{ +XE (FAST) +T} T{ +777 +T} T{ +2.4 +T} +_ +T{ +XE (Fastchip, FAST) +T} T{ +777 +T} T{ +2.4 +T} +_ +T{ +Altirra (Fastchip) +T} T{ +769 +T} T{ +2.43 +T} +_ +T{ +Integer +T} T{ +719 +T} T{ +2.6 +T} +_ +T{ +Integer (FAST) +T} T{ +575 +T} T{ +3.25 +T} +_ +.TE +.sp +Turbo BASIC XL, Atari Microsoft BASIC, and OSS Integer BASIC run at +the same speed with or without the Fastchip ROM, since they don\(aqt use +the OS floating point routines. +.sp +For reference, I rewrote the program in C and compiled it with +cc65. It runs in 349 jiffies, 5.35x as fast as BASIC, with or without +the Fastchip ROM. Since cc65 only supports integer arithmetic, this +probably represents the theoretical maximum speed the algorithm could +run in on the Atari, without rewriting it in assembly. By comparison, +Integer BASIC looks pretty good. +.sp +If you get rid of lines 180 to 210 (don\(aqt print the results), Integer +BASIC with FAST runs it in 245 jiffies, and the equivalent C program +runs in 61 jiffies. This shows that CIO and the E: device are the +"bottleneck" for this program (and that compiled C is still faster +than anything interpreted). .SH BUGS .SS Modulo Arithmetic .sp diff --git a/ossintbas_content.rst b/ossintbas_content.rst index acdd9b0..2289a84 100644 --- a/ossintbas_content.rst +++ b/ossintbas_content.rst @@ -9,7 +9,7 @@ It appears to be complete and free of major bugs. There is no manual for it, so I'm documenting the differences between Integer BASIC and BASIC XL/XE here, as I discover them. -For more info on the release:: +For more info on the release: https://forums.atariage.com/topic/257029-oss-d-day-part-3-integer-basic-source-code-now-in-pd/ @@ -52,13 +52,13 @@ COMMANDS **VINC** *<var>* Increment (add 1 to) a variable. This is about 30% faster than - **A=A+1**. Abbreviate as **VD.**. + **A=A+1**. Abbreviation: **VI.** **VDEC** *<var>* - Decrement (subtract 1 from) a variable. Abbreviate as **VD.**. + Decrement (subtract 1 from) a variable. Faster than **A=A-1**. Abbreviation: **VD.** @@ -198,6 +198,80 @@ Missing Operators/Functions **USING** BASIC XL and XE's "PRINT USING" doesn't exist in Integer BASIC. +PERFORMANCE +=========== + +OSS Integer BASIC is *fast*, compared to other interpreted BASICs on +the Atari. It even outperforms Turbo BASIC XL (though, not *compiled* +Turbo). + +For testing, I used a modified version of the Sieve of Eratosthenes +program, found in the source for **bas55**. The program finds and +prints all the prime numbers between 2 and 1000. The code:: + + 10 POKE 18,0:POKE 19,0:POKE 20,0 + 20 DIM A(1000) + 30 N=1000 + 100 S=SQR(N) + 110 FOR I=2 TO S + 120 IF A(I)=1 THEN 170 + 130 D=N/I + 140 FOR J=I TO D + 150 A(I*J)=1 + 160 NEXT J + 170 NEXT I + 180 FOR I=2 TO N + 190 IF A(I)=1 THEN 210 + 200 PRINT I + 210 NEXT I + 1000 PRINT PEEK(18)*256*256+PEEK(19)*256+PEEK(20) + +Line 1000 prints how many jiffies the program took to run. I used +Atari800 5.2.0 emulating an NTSC Atari 800XL, so one jiffy is 1/60 of +a second. The "Fastchip" results use Charles Marslet's OS floating +point replacement ROM. For Integer BASIC, BASIC XL and BASIC XE, +separate runs were done with the line **5 FAST** at the start of the +program. Results: + +.. csv-table:: + + "BASIC", "Jiffies", "Speedup" + "Atari 8K", "1867", "--" + "A+", "1671", "1.12" + "Atari 8K (Fastchip)", "1587", "1.18" + "A+ (Fastchip)", "1569", "1.19" + "XE", "1440", "1.3" + "AMSB2", "1518", "1.23" + "XL", "1270", "1.47" + "Altirra", "1166", "1.67" + "XL (FAST)", "1110", "1.68" + "XL (Fastchip)", "1049", "1.78" + "XL (Fastchip, FAST)", "887", "2.1" + "Turbo", "825", "2.3" + "XE (FAST)", "777", "2.4" + "XE (Fastchip, FAST)", "777", "2.4" + "Altirra (Fastchip)", "769", "2.43" + "Integer", "719", "2.6" + "Integer (FAST)", "575", "3.25" + +Turbo BASIC XL, Atari Microsoft BASIC, and OSS Integer BASIC run at +the same speed with or without the Fastchip ROM, since they don't use +the OS floating point routines. + +For reference, I rewrote the program in C and compiled it with +cc65. It runs in 349 jiffies, 5.35x as fast as BASIC, with or without +the Fastchip ROM. Since cc65 only supports integer arithmetic, this +probably represents the theoretical maximum speed the algorithm could +run in on the Atari, without rewriting it in assembly. By comparison, +Integer BASIC looks pretty good. + +If you get rid of lines 180 to 210 (don't print the results), Integer +BASIC with FAST runs it in 245 jiffies, and the equivalent C program +runs in 61 jiffies. This shows that CIO and the E: device are the +"bottleneck" for this program (and that compiled C is still faster +than anything interpreted). + + BUGS ==== @@ -1030,15 +1030,12 @@ void detect_foreign(void) { if(c == EOF || d == EOF) die("File is too short to be a BASIC program of any kind."); - if(c == 0 && d == 0) { + if((c == 0 || c == 0x77) && d == 0) { /* This is why we can't read from stdin. */ rewind(input_file); return; } - if(c == 0x77 && d == 0x00) - foreign("OSS Integer BASIC", SRET_OSSINT); - if(c == 0xfb && d == 0xc2) foreign("Compiled Turbo BASIC XL", SRET_COMPILED_TURBO); @@ -1224,6 +1221,19 @@ CALLBACK(check_aplus_cmd) { last_cmd = tok; } +void check_oss_int(void) { + if(lomem != 0x77) return; + switch(save_command_tok) { + case 0x19: /* SAVE */ + case 0x33: /* CSAVE */ + foreign("OSS Integer BASIC (disk)", SRET_OSSINT_DISK); + break; + default: + foreign("OSS Integer BASIC (cartridge)", SRET_OSSINT_DISK); + break; + } +} + void check_aplus(void) { allow_hex_const = 1; @@ -1250,6 +1260,7 @@ int main(int argc, char **argv) { readfile(); parse_header(); + check_oss_int(); check_variables(); check_aplus(); @@ -14,5 +14,6 @@ #define SRET_EXTENDED_BXE 12 #define SRET_COMPILED_TURBO 13 #define SRET_APLUS 14 -#define SRET_OSSINT 15 +#define SRET_OSSINT_CART 15 +#define SRET_OSSINT_DISK 16 #define SRET_NOT_BASIC 64 |