From 059238874def6bc1010abecb0ccd8ccf177a6df0 Mon Sep 17 00:00:00 2001 From: marcobaye Date: Wed, 26 Jun 2013 23:01:00 +0000 Subject: [PATCH] Release 0.94.5: Fixed bugs in wrap-around branches and left-shifting floats. Several changes in library. git-svn-id: https://svn.code.sf.net/p/acme-crossass/code-0/trunk@15 4df02467-bbd4-4a76-a152-e7ce94205b78 --- ACME_Lib/cbm/basic1.a | 232 ++++++++++++++++++++++++++------------- ACME_Lib/cbm/basic10.a | 17 ++- ACME_Lib/cbm/basic2.a | 7 +- ACME_Lib/cbm/basic3.5.a | 160 ++++++++++++++++++--------- ACME_Lib/cbm/basic4.a | 50 ++++++--- ACME_Lib/cbm/c64/float.a | 106 ++++++++++++++++++ ACME_Lib/cbm/mflpt.a | 79 +++++++++++++ docs/Changes.txt | 22 ++++ docs/Errors.txt | 22 ++-- docs/Example.txt | 1 - docs/Floats.txt | 37 ++++--- docs/Help.txt | 19 ++-- docs/QuickRef.txt | 2 +- docs/Source.txt | 2 +- examples/macedit.a | 6 +- src/acme.c | 6 +- src/alu.c | 9 +- src/basics.c | 2 + src/cpu.c | 12 +- src/cpu.h | 2 +- src/flow.c | 26 ++--- src/global.c | 6 +- src/global.h | 2 + src/input.c | 4 +- src/macro.c | 12 +- src/mnemo.c | 58 ++++++---- src/output.c | 3 +- 27 files changed, 655 insertions(+), 249 deletions(-) create mode 100644 ACME_Lib/cbm/c64/float.a create mode 100644 ACME_Lib/cbm/mflpt.a diff --git a/ACME_Lib/cbm/basic1.a b/ACME_Lib/cbm/basic1.a index 4ff997b..6c8b98a 100644 --- a/ACME_Lib/cbm/basic1.a +++ b/ACME_Lib/cbm/basic1.a @@ -3,86 +3,166 @@ !ifdef lib_cbm_basic1_a !eof lib_cbm_basic1_a = 1 +; token values +token_END = $80 +token_FOR = $81 +token_NEXT = $82 +token_DATA = $83 +token_INPUT_ = $84 ; INPUT# +token_INPUT = $85 +token_DIM = $86 +token_READ = $87 +token_LET = $88 +token_GOTO = $89 +token_RUN = $8a +token_IF = $8b +token_RESTORE = $8c +token_GOSUB = $8d +token_RETURN = $8e +token_REM = $8f +token_STOP = $90 +token_ON = $91 +token_WAIT = $92 +token_LOAD = $93 +token_SAVE = $94 +token_VERIFY = $95 +token_DEF = $96 +token_POKE = $97 +token_PRINT_ = $98 ; PRINT# +token_PRINT = $99 +token_CONT = $9a +token_LIST = $9b +token_CLR = $9c +token_CMD = $9d +token_SYS = $9e +token_OPEN = $9f +token_CLOSE = $a0 +token_GET = $a1 +token_NEW = $a2 +token_TAB = $a3 ; the token already includes '(' +token_TO = $a4 +token_FN = $a5 +token_SPC = $a6 ; the token already includes '(' +token_THEN = $a7 +token_NOT = $a8 +token_STEP = $a9 +token_ADD = $aa ; '+' +token_SUBTRACT = $ab ; '-' +token_MULTIPLY = $ac ; '*' +token_DIVIDE = $ad ; '/' +token_POWEROF = $ae ; '^' +token_AND = $af +token_OR = $b0 +token_GREATER = $b1 ; '>' +token_EQUAL = $b2 ; '=' +token_LESS = $b3 ; '<' +token_SGN = $b4 +token_INT = $b5 +token_ABS = $b6 +token_USR = $b7 +token_FRE = $b8 +token_POS = $b9 +token_SQR = $ba +token_RND = $bb +token_LOG = $bc +token_EXP = $bd +token_COS = $be +token_SIN = $bf +token_TAN = $c0 +token_ATN = $c1 +token_PEEK = $c2 +token_LEN = $c3 +token_STR_ = $c4 ; STR$ +token_VAL = $c5 +token_ASC = $c6 +token_CHR_ = $c7 ; CHR$ +token_LEFT_ = $c8 ; LEFT$ +token_RIGHT_ = $c9 ; RIGHT$ +token_MID_ = $ca ; MID$ + +token_PI = $ff ; greek letter pi + + ; Macros for inserting BASIC commands. Note that "#" and "$" characters in ; BASIC keywords have been converted to "_" in the macro names. ; *All* function macros already include the '(' character. -!macro b_END {!by $80} -!macro b_FOR {!by $81} -!macro b_NEXT {!by $82} -!macro b_DATA {!by $83} -!macro b_INPUT_ {!by $84} ; INPUT# -!macro b_INPUT {!by $85} -!macro b_DIM {!by $86} -!macro b_READ {!by $87} -!macro b_LET {!by $88} -!macro b_GOTO {!by $89} -!macro b_RUN {!by $8a} -!macro b_IF {!by $8b} -!macro b_RESTORE {!by $8c} -!macro b_GOSUB {!by $8d} -!macro b_RETURN {!by $8e} -!macro b_REM {!by $8f} -!macro b_STOP {!by $90} -!macro b_ON {!by $91} -!macro b_WAIT {!by $92} -!macro b_LOAD {!by $93} -!macro b_SAVE {!by $94} -!macro b_VERIFY {!by $95} +!macro b_END {!by token_END} +!macro b_FOR {!by token_FOR} +!macro b_NEXT {!by token_NEXT} +!macro b_DATA {!by token_DATA} +!macro b_INPUT_ {!by token_INPUT_} ; INPUT# +!macro b_INPUT {!by token_INPUT} +!macro b_DIM {!by token_DIM} +!macro b_READ {!by token_READ} +!macro b_LET {!by token_LET} +!macro b_GOTO {!by token_GOTO} +!macro b_RUN {!by token_RUN} +!macro b_IF {!by token_IF} +!macro b_RESTORE {!by token_RESTORE} +!macro b_GOSUB {!by token_GOSUB} +!macro b_RETURN {!by token_RETURN} +!macro b_REM {!by token_REM} +!macro b_STOP {!by token_STOP} +!macro b_ON {!by token_ON} +!macro b_WAIT {!by token_WAIT} +!macro b_LOAD {!by token_LOAD} +!macro b_SAVE {!by token_SAVE} +!macro b_VERIFY {!by token_VERIFY} ; As "DEF" cannot be used without "FN", here is a macro called "b_DEFFN" ; instead of one called "b_DEF": -!macro b_DEFFN {!by $96, $a5} -!macro b_POKE {!by $97} -!macro b_PRINT_ {!by $98} ; PRINT# -!macro b_PRINT {!by $99} -!macro b_CONT {!by $9a} -!macro b_LIST {!by $9b} -!macro b_CLR {!by $9c} -!macro b_CMD {!by $9d} -!macro b_SYS {!by $9e} -!macro b_OPEN {!by $9f} -!macro b_CLOSE {!by $a0} -!macro b_GET {!by $a1} -!macro b_NEW {!by $a2} -!macro b_TAB {!by $a3} ; the token already includes '(' -!macro b_TO {!by $a4} -!macro b_FN {!by $a5} -!macro b_SPC {!by $a6} ; the token already includes '(' -!macro b_THEN {!by $a7} -!macro b_NOT {!by $a8} -!macro b_STEP {!by $a9} -!macro b_ADD {!by $aa} ; '+' -!macro b_SUBTRACT {!by $ab} ; '-' -!macro b_MULTIPLY {!by $ac} ; '*' -!macro b_DIVIDE {!by $ad} ; '/' -!macro b_POWEROF {!by $ae} ; '^' -!macro b_AND {!by $af} -!macro b_OR {!by $b0} -!macro b_GREATER {!by $b1} ; '>' -!macro b_EQUAL {!by $b2} ; '=' -!macro b_LESS {!by $b3} ; '<' -!macro b_SGN {!by $b4:!pet '('} -!macro b_INT {!by $b5:!pet '('} -!macro b_ABS {!by $b6:!pet '('} -!macro b_USR {!by $b7:!pet '('} -!macro b_FRE {!by $b8:!pet '('} -!macro b_POS {!by $b9:!pet '('} -!macro b_SQR {!by $ba:!pet '('} -!macro b_RND {!by $bb:!pet '('} -!macro b_LOG {!by $bc:!pet '('} -!macro b_EXP {!by $bd:!pet '('} -!macro b_COS {!by $be:!pet '('} -!macro b_SIN {!by $bf:!pet '('} -!macro b_TAN {!by $c0:!pet '('} -!macro b_ATN {!by $c1:!pet '('} -!macro b_PEEK {!by $c2:!pet '('} -!macro b_LEN {!by $c3:!pet '('} -!macro b_STR_ {!by $c4:!pet '('} ; STR$( -!macro b_VAL {!by $c5:!pet '('} -!macro b_ASC {!by $c6:!pet '('} -!macro b_CHR_ {!by $c7:!pet '('} ; CHR$( -!macro b_LEFT_ {!by $c8:!pet '('} ; LEFT$( -!macro b_RIGHT_ {!by $c9:!pet '('} ; RIGHT$( -!macro b_MID_ {!by $ca:!pet '('} ; MID$( +!macro b_DEFFN {!by token_DEF, token_FN} ; DEFFN +!macro b_POKE {!by token_POKE} +!macro b_PRINT_ {!by token_PRINT_} ; PRINT# +!macro b_PRINT {!by token_PRINT} +!macro b_CONT {!by token_CONT} +!macro b_LIST {!by token_LIST} +!macro b_CLR {!by token_CLR} +!macro b_CMD {!by token_CMD} +!macro b_SYS {!by token_SYS} +!macro b_OPEN {!by token_OPEN} +!macro b_CLOSE {!by token_CLOSE} +!macro b_GET {!by token_GET} +!macro b_NEW {!by token_NEW} +!macro b_TAB {!by token_TAB} ; TAB( the token already includes '(' +!macro b_TO {!by token_TO} +!macro b_FN {!by token_FN} +!macro b_SPC {!by token_SPC} ; SPC( the token already includes '(' +!macro b_THEN {!by token_THEN} +!macro b_NOT {!by token_NOT} +!macro b_STEP {!by token_STEP} +!macro b_ADD {!by token_ADD} ; + +!macro b_SUBTRACT {!by token_SUBTRACT} ; - +!macro b_MULTIPLY {!by token_MULTIPLY} ; * +!macro b_DIVIDE {!by token_DIVIDE} ; / +!macro b_POWEROF {!by token_POWEROF} ; ^ +!macro b_AND {!by token_AND} +!macro b_OR {!by token_OR} +!macro b_GREATER {!by token_GREATER} ; > +!macro b_EQUAL {!by token_EQUAL} ; = +!macro b_LESS {!by token_LESS} ; < +!macro b_SGN {!by token_SGN, $28} ; SGN( +!macro b_INT {!by token_INT, $28} ; INT( +!macro b_ABS {!by token_ABS, $28} ; ABS( +!macro b_USR {!by token_USR, $28} ; USR( +!macro b_FRE {!by token_FRE, $28} ; FRE( +!macro b_POS {!by token_POS, $28} ; POS( +!macro b_SQR {!by token_SQR, $28} ; SQR( +!macro b_RND {!by token_RND, $28} ; RND( +!macro b_LOG {!by token_LOG, $28} ; LOG( +!macro b_EXP {!by token_EXP, $28} ; EXP( +!macro b_COS {!by token_COS, $28} ; COS( +!macro b_SIN {!by token_SIN, $28} ; SIN( +!macro b_TAN {!by token_TAN, $28} ; TAN( +!macro b_ATN {!by token_ATN, $28} ; ATN( +!macro b_PEEK {!by token_PEEK, $28} ; PEEK( +!macro b_LEN {!by token_LEN, $28} ; LEN( +!macro b_STR_ {!by token_STR_, $28} ; STR$( +!macro b_VAL {!by token_VAL, $28} ; VAL( +!macro b_ASC {!by token_ASC, $28} ; ASC( +!macro b_CHR_ {!by token_CHR_, $28} ; CHR$( +!macro b_LEFT_ {!by token_LEFT_, $28} ; LEFT$( +!macro b_RIGHT_ {!by token_RIGHT_, $28} ; RIGHT$( +!macro b_MID_ {!by token_MID_, $28} ; MID$( -!macro b_PI {!by $ff} +!macro b_PI {!by token_PI} ; greek letter pi diff --git a/ACME_Lib/cbm/basic10.a b/ACME_Lib/cbm/basic10.a index c72b536..b12286c 100644 --- a/ACME_Lib/cbm/basic10.a +++ b/ACME_Lib/cbm/basic10.a @@ -5,12 +5,17 @@ lib_cbm_basic10_a = 1 !source ; from 0x80 to 0xff, 0xce 0x02 to 0xce 0x0a, 0xfe 0x02 to 0xfe 0x26 -; GSHAPE/SSHAPE/DRAW have new names: -!macro b_PASTE {!by $e3} -!macro b_CUT {!by $e4} -!macro b_LINE {!by $e5} -; DIRECTORY has a new name: -!macro b_DIR {!by $ee} +; token values +token_PASTE = $e3 ; was called GSHAPE in basic v7 +token_CUT = $e4 ; was called SSHAPE in basic v7 +token_LINE = $e5 ; was called DRAW in basic v7 +token_DIR = $ee ; was called DIRECTORY in basic v7 + +; Macros for inserting BASIC commands +!macro b_PASTE {!by token_PASTE} ; aka GSHAPE +!macro b_CUT {!by token_CUT} ; aka SSHAPE +!macro b_LINE {!by token_LINE} ; aka DRAW +!macro b_DIR {!by token_DIR} ; aka DIRECTORY ; STASH/FETCH/SWAP are all decoded to DMA: !macro b_DMA {!by $fe, $1f} diff --git a/ACME_Lib/cbm/basic2.a b/ACME_Lib/cbm/basic2.a index 5ce7894..41a441e 100644 --- a/ACME_Lib/cbm/basic2.a +++ b/ACME_Lib/cbm/basic2.a @@ -4,4 +4,9 @@ lib_cbm_basic2_a = 1 !source ; from 0x80 to 0xca -!macro b_GO {!by $cb} + +; token values +token_GO = $cb + +; Macros for inserting BASIC commands +!macro b_GO {!by token_GO} diff --git a/ACME_Lib/cbm/basic3.5.a b/ACME_Lib/cbm/basic3.5.a index 79cad60..f37d49d 100644 --- a/ACME_Lib/cbm/basic3.5.a +++ b/ACME_Lib/cbm/basic3.5.a @@ -3,72 +3,124 @@ !ifdef lib_cbm_basic3_5_a !eof lib_cbm_basic3_5_a = 1 -; Macros for inserting BASIC commands. Note that "#" and "$" characters in -; BASIC keywords have been converted to "_" in the macro names. -; *All* function macros already include the '(' character. - !source ; from 0x80 to $cb -!macro b_RGR {!by $cc:!pet '('} -!macro b_RCLR {!by $cd:!pet '('} + +; token values +token_RGR = $cc +token_RCLR = $cd ; if this file gets included via "cbm/basic7.a" or "cbm/basic10.a", do not define RLUM ; (because v7 and higher use $ce as prefix byte for additional functions): !ifndef lib_cbm_basic7_a { !ifndef lib_cbm_basic10_a { - !macro b_RLUM {!by $ce:!pet '('} + token_RLUM = $ce } } -!macro b_JOY {!by $cf:!pet '('} -!macro b_RDOT {!by $d0:!pet '('} -!macro b_DEC {!by $d1:!pet '('} -!macro b_HEX_ {!by $d2:!pet '('} ; HEX$( -!macro b_ERR_ {!by $d3:!pet '('} ; ERR$( -!macro b_INSTR {!by $d4:!pet '('} -!macro b_ELSE {!by $d5} -!macro b_RESUME {!by $d6} -!macro b_TRAP {!by $d7} -!macro b_TRON {!by $d8} -!macro b_TROFF {!by $d9} -!macro b_SOUND {!by $da} -!macro b_VOL {!by $db} -!macro b_AUTO {!by $dc} -!macro b_PUDEF {!by $dd} -!macro b_GRAPHIC {!by $de} -!macro b_PAINT {!by $df} -!macro b_CHAR {!by $e0} -!macro b_BOX {!by $e1} -!macro b_CIRCLE {!by $e2} +token_JOY = $cf +token_RDOT = $d0 +token_DEC = $d1 +token_HEX_ = $d2 ; HEX$ +token_ERR_ = $d3 ; ERR$ +token_INSTR = $d4 +token_ELSE = $d5 +token_RESUME = $d6 +token_TRAP = $d7 +token_TRON = $d8 +token_TROFF = $d9 +token_SOUND = $da +token_VOL = $db +token_AUTO = $dc +token_PUDEF = $dd +token_GRAPHIC = $de +token_PAINT = $df +token_CHAR = $e0 +token_BOX = $e1 +token_CIRCLE = $e2 ; if this file gets included via "cbm/basic10.a", do not define GSHAPE/SSHAPE/DRAW ; (because in v10, they are called PASTE/CUT/LINE): !ifndef lib_cbm_basic10_a { - !macro b_GSHAPE {!by $e3} - !macro b_SSHAPE {!by $e4} - !macro b_DRAW {!by $e5} + token_GSHAPE = $e3 + token_SSHAPE = $e4 + token_DRAW = $e5 } -!macro b_LOCATE {!by $e6} -!macro b_COLOR {!by $e7} -!macro b_SCNCLR {!by $e8} -!macro b_SCALE {!by $e9} -!macro b_HELP {!by $ea} -!macro b_DO {!by $eb} -!macro b_LOOP {!by $ec} -!macro b_EXIT {!by $ed} +token_LOCATE = $e6 +token_COLOR = $e7 +token_SCNCLR = $e8 +token_SCALE = $e9 +token_HELP = $ea +token_DO = $eb +token_LOOP = $ec +token_EXIT = $ed ; if this file gets included via "cbm/basic10.a", do not define DIRECTORY ; (because in v10, it is called DIR): !ifndef lib_cbm_basic10_a { - !macro b_DIRECTORY {!by $ee} + token_DIRECTORY = $ee } -!macro b_DSAVE {!by $ef} -!macro b_DLOAD {!by $f0} -!macro b_HEADER {!by $f1} -!macro b_SCRATCH {!by $f2} -!macro b_COLLECT {!by $f3} -!macro b_COPY {!by $f4} -!macro b_RENAME {!by $f5} -!macro b_BACKUP {!by $f6} -!macro b_DELETE {!by $f7} -!macro b_RENUMBER {!by $f8} -!macro b_KEY {!by $f9} -!macro b_MONITOR {!by $fa} -!macro b_USING {!by $fb} -!macro b_UNTIL {!by $fc} -!macro b_WHILE {!by $fd} +token_DSAVE = $ef +token_DLOAD = $f0 +token_HEADER = $f1 +token_SCRATCH = $f2 +token_COLLECT = $f3 +token_COPY = $f4 +token_RENAME = $f5 +token_BACKUP = $f6 +token_DELETE = $f7 +token_RENUMBER = $f8 +token_KEY = $f9 +token_MONITOR = $fa +token_USING = $fb +token_UNTIL = $fc +token_WHILE = $fd + +; Macros for inserting BASIC commands. Note that "#" and "$" characters in +; BASIC keywords have been converted to "_" in the macro names. +; *All* function macros already include the '(' character. +!macro b_RGR {!by token_RGR, $28} ; RGR( +!macro b_RCLR {!by token_RCLR, $28} ; RCLR( +!macro b_RLUM {!by token_RLUM, $28} ; RLUM( +!macro b_JOY {!by token_JOY, $28} ; JOY( +!macro b_RDOT {!by token_RDOT, $28} ; RDOT( +!macro b_DEC {!by token_DEC, $28} ; DEC( +!macro b_HEX_ {!by token_HEX_, $28} ; HEX$( +!macro b_ERR_ {!by token_ERR_, $28} ; ERR$( +!macro b_INSTR {!by token_INSTR, $28} ; INSTR( +!macro b_ELSE {!by token_ELSE} +!macro b_RESUME {!by token_RESUME} +!macro b_TRAP {!by token_TRAP} +!macro b_TRON {!by token_TRON} +!macro b_TROFF {!by token_TROFF} +!macro b_SOUND {!by token_SOUND} +!macro b_VOL {!by token_VOL} +!macro b_AUTO {!by token_AUTO} +!macro b_PUDEF {!by token_PUDEF} +!macro b_GRAPHIC {!by token_GRAPHIC} +!macro b_PAINT {!by token_PAINT} +!macro b_CHAR {!by token_CHAR} +!macro b_BOX {!by token_BOX} +!macro b_CIRCLE {!by token_CIRCLE} +!macro b_GSHAPE {!by token_GSHAPE} +!macro b_SSHAPE {!by token_SSHAPE} +!macro b_DRAW {!by token_DRAW} +!macro b_LOCATE {!by token_LOCATE} +!macro b_COLOR {!by token_COLOR} +!macro b_SCNCLR {!by token_SCNCLR} +!macro b_SCALE {!by token_SCALE} +!macro b_HELP {!by token_HELP} +!macro b_DO {!by token_DO} +!macro b_LOOP {!by token_LOOP} +!macro b_EXIT {!by token_EXIT} +!macro b_DIRECTORY {!by token_DIRECTORY} +!macro b_DSAVE {!by token_DSAVE} +!macro b_DLOAD {!by token_DLOAD} +!macro b_HEADER {!by token_HEADER} +!macro b_SCRATCH {!by token_SCRATCH} +!macro b_COLLECT {!by token_COLLECT} +!macro b_COPY {!by token_COPY} +!macro b_RENAME {!by token_RENAME} +!macro b_BACKUP {!by token_BACKUP} +!macro b_DELETE {!by token_DELETE} +!macro b_RENUMBER {!by token_RENUMBER} +!macro b_KEY {!by token_KEY} +!macro b_MONITOR {!by token_MONITOR} +!macro b_USING {!by token_USING} +!macro b_UNTIL {!by token_UNTIL} +!macro b_WHILE {!by token_WHILE} diff --git a/ACME_Lib/cbm/basic4.a b/ACME_Lib/cbm/basic4.a index 6c7f04e..00a86b5 100644 --- a/ACME_Lib/cbm/basic4.a +++ b/ACME_Lib/cbm/basic4.a @@ -4,19 +4,39 @@ lib_cbm_basic4_a = 1 !source ; from 0x80 to $cb + ; CAUTION - these tokens are different to the ones in BASIC 3.5, BASIC 7 and BASIC 10! -!macro b_CONCAT {!by $cc} -!macro b_DOPEN {!by $cd} -!macro b_DCLOSE {!by $ce} -!macro b_RECORD {!by $cf} -!macro b_HEADER {!by $d0} -!macro b_COLLECT {!by $d1} -!macro b_BACKUP {!by $d2} -!macro b_COPY {!by $d3} -!macro b_APPEND {!by $d4} -!macro b_DSAVE {!by $d5} -!macro b_DLOAD {!by $d6} -!macro b_CATALOG {!by $d7} -!macro b_RENAME {!by $d8} -!macro b_SCRATCH {!by $d9} -!macro b_DIRECTORY {!by $da} + +; token values +token_CONCAT = $cc +token_DOPEN = $cd +token_DCLOSE = $ce +token_RECORD = $cf +token_HEADER = $d0 +token_COLLECT = $d1 +token_BACKUP = $d2 +token_COPY = $d3 +token_APPEND = $d4 +token_DSAVE = $d5 +token_DLOAD = $d6 +token_CATALOG = $d7 +token_RENAME = $d8 +token_SCRATCH = $d9 +token_DIRECTORY = $da + +; Macros for inserting BASIC commands: +!macro b_CONCAT {!by token_CONCAT} +!macro b_DOPEN {!by token_DOPEN} +!macro b_DCLOSE {!by token_DCLOSE} +!macro b_RECORD {!by token_RECORD} +!macro b_HEADER {!by token_HEADER} +!macro b_COLLECT {!by token_COLLECT} +!macro b_BACKUP {!by token_BACKUP} +!macro b_COPY {!by token_COPY} +!macro b_APPEND {!by token_APPEND} +!macro b_DSAVE {!by token_DSAVE} +!macro b_DLOAD {!by token_DLOAD} +!macro b_CATALOG {!by token_CATALOG} +!macro b_RENAME {!by token_RENAME} +!macro b_SCRATCH {!by token_SCRATCH} +!macro b_DIRECTORY {!by token_DIRECTORY} diff --git a/ACME_Lib/cbm/c64/float.a b/ACME_Lib/cbm/c64/float.a new file mode 100644 index 0000000..59977fa --- /dev/null +++ b/ACME_Lib/cbm/c64/float.a @@ -0,0 +1,106 @@ +;ACME 0.94.4 + +!ifdef lib_cbm_c64_float_a !eof +lib_cbm_c64_float_a = 1 + +; Here are some definitions to help you call the floating-point functions of the +; C64's BASIC ROM. They work using two structures in zero page, called fac1 and +; fac2 (floating-point accumulator 1 and 2, located at $61 and $69). + +!source ; include macro to store floats in MFLPT format + +; convenience macros: + +; some float functions need a memory address in A (low) and Y (high) +!macro movAY .adr { + lda #<.adr + ldy #>.adr +} +; ...or in X (low) and Y (high) +!macro movXY .adr { + ldx #<.adr + ldy #>.adr +} +; other float functions expect or output a value in Y (low) and A (high) +!macro movYA .val { + ldy #<.val + lda #>.val +} +!macro ldYA .adr { + ldy .adr + lda .adr + 1 +} +!macro stYA .adr { + sty .adr + sta .adr + 1 +} +; ...or in X (low) and A (high) +!macro ldXA .adr { + ldx .adr + lda .adr + 1 +} + +; constants in five-byte "mflpt" format +mflpt_pi = $aea8 ; 3.1415926... +mflpt_minus32768 = $b1a5 ; -32768 +mflpt_1 = $b9bc ; 1 +mflpt_half_sqr2 = $b9d6 ; SQR(2) / 2 +mflpt_sqr2 = $b9db ; SQR(2) +mflpt_minus_point5 = $b9e0 ; -.5 +mflpt_log_2 = $b9e5 ; LOG(2) +mflpt_10 = $baf9 ; 10 +mflpt_99999999 = $bdb3 ; 99 999 999 +mflpt_999999999 = $bdb8 ; 999 999 999 +mflpt_1000000000 = $bdbd ; 1 000 000 000 +mflpt_point5 = $bf11 ; .5, also known as 1 / 2 +mflpt_log_2_reciprocal = $bfbf ; 1 / LOG(2) +mflpt_half_pi = $e2e0 ; PI / 2 +mflpt_double_pi = $e2e5 ; 2 * PI (also see $e309) +mflpt_point25 = $e2ea ; .25, also known as 1 / 4 +mflpt_2_pi = $e309 ; 2 * PI (also see $e2e5) + +; functions - a few points to note: +; fac1/2 might get clobbered even if not mentioned in the function's name, +; because stuff like fac1_times_memYYAA will load the value from memory +; into fac2 first. +; for subtraction and division, the left operand is in fac2, the right operand in fac1. +fac1_print = $aabc ; print string representation of contents of fac1 +fac1_to_signedYA = $b1aa ; might throw ILLEGAL QUANTITY +fac1_to_signed16 = $b1bf ; might throw ILLEGAL QUANTITY +fac1_read_signedYA = $b391 ; convert 16 bit signed int to float +fac1_read_unsignedY = $b3a2 ; convert 8 bit unsigned int to float +fac1_read_string = $b7b5 ; $22/23 must point to string, A must be string length +fac1_to_unsignedYA = $b7f7 ; might throw ILLEGAL QUANTITY (result is also in $14/15) +fac1_add_point5 = $b849 ; for rounding, call this before fac1_int +fac1_memAY_minus_fac1 = $b850 +fac1_fac2_minus_fac1 = $b853 +fac1_add_memAY = $b867 +fac1_add_fac2 = $b86a +fac1_log = $b9ea ; LOG() +fac1_times_memAY = $ba28 +fac2_read_memAY = $ba8c ; load value from memory into fac2 +fac1_times_10 = $bae2 +fac1_divide_by_10 = $bafe +fac1_divide_memAY_by_fac1 = $bb0f +fac1_read_memAY = $bba2 ; load value from memory into fac1 +fac1_to_memXY = $bbd4 ; store fac1 to memory +fac1_read_fac2 = $bbfc ; copy fac2 to fac1 +fac2_read_fac1 = $bc0c ; copy fac1 to fac2 +fac1_sign_to_A = $bc2b ; $ff, $0, $1 for negative, zero, positive +fac1_sgn = $bc39 ; SGN() +fac1_abs = $bc58 ; ABS() +fac1_compare_to_memAY = $bc5b +fac1_to_signed32 = $bc9b +fac1_int = $bccc ; INT() +fac1_print_unsignedXA = $bdcd +fac1_to_string = $bddd ; string is stored at $0100 (address returned in YYAA) +fac1_sqr = $bf71 ; SQR() +fac1_fac2_to_the_power_of_memAY = $bf78 +fac1_negate = $bfb4 +fac1_exp = $bfed ; EXP() +; end of basic rom jumps to start of kernel rom! +fac1_rnd = $e097 ; RND() +fac1_cos = $e264 ; COS() +fac1_sin = $e26b ; SIN() +fac1_tan = $e2b4 ; TAN() +fac1_atn = $e30e ; ATN() diff --git a/ACME_Lib/cbm/mflpt.a b/ACME_Lib/cbm/mflpt.a new file mode 100644 index 0000000..f9f9685 --- /dev/null +++ b/ACME_Lib/cbm/mflpt.a @@ -0,0 +1,79 @@ +;ACME 0.94.5 + +!ifdef lib_cbm_mflpt_a !eof +lib_cbm_mflpt_a = 1 + +; here's a macro for writing floating point numbers in the "mflpt" format used by BASIC. +; "mflpt" stands for "memory floating point", where the sign bit is packed into the mantissa. + +; to use it, write: +; +mflpt 3.1415926 ; each use will take up five bytes of memory + + +; now for the technical stuff (stop reading right now if you value your sanity) + +; five-byte layout in memory: +; eeeeeeee smmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm ; eight bits exponent, 32 bits mantissa with sign bit overlay + +; exponent byte: +; exponent has a bias of 128 (128 means the decimal point is right before the mantissa's leading zero) +; if exponent is zero, number value is considered to be zero, regardless of mantissa +; exponents 1..128 are for values < 1 +; exponents 129..255 are for values >= 1 + +; mantissa: +; mantissa is stored big-endian(!) +; the mantissa's mandatory leading '1' is replaced by the sign bit + +; so logically, this is equivalent to: +; + .1mmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm * 2^(eeeeeeee - 128) if sign bit is 0 +; - .1mmmmmmm mmmmmmmm mmmmmmmm mmmmmmmm * 2^(eeeeeeee - 128) if sign bit is 1 + + + +; this is ugly, but it gets the job done +; (if it's stupid, but it works, then it's not stupid) +!macro mflpt .value { + !set .float = float(.value) ; make sure to do passes until value is defined + !ifndef .float { + !by $ff, $ff, $ff, $ff, $ff ; place holder + } else { + ; value is defined, so split up into sign and non-negative value + !if .float < 0 { + !set .sign = $80 + !set .float = -.float + } else { + !set .sign = $00 + } + !if .float = 0 { + !by 0, 0, 0, 0, 0 ; zero is represented as all bits zero + } else { + ; split up into exponent and mantissa + !set .exponent = 128 + 32 ; 128 is cbm's bias, 32 is this algo's bias + ; if mantissa is too large, shift right and adjust exponent + !do while .float >= (2.0 ^ 32.0) { + !set .float = .float >> 1 + !set .exponent = .exponent + 1 + } + ; if mantissa is too small, shift left and adjust exponent + !do while .float < (2.0 ^ 31.0) { + !set .float = .float << 1 + !set .exponent = .exponent - 1 + } + !if .exponent < 1 { + !warn "MFLPT underflow, using zero instead" + !set .float = 0 + !set .exponent = 0 + !set .sign = 0 + } + !if .exponent > 255 { + !error "MFLPT overflow" + } + !by .exponent + !by (127 & int(.float >> 24)) | .sign + !by 255 & int(.float >> 16) + !by 255 & int(.float >> 8) + !by 255 & int(.float) + } + } +} diff --git a/docs/Changes.txt b/docs/Changes.txt index 036200a..ea00393 100644 --- a/docs/Changes.txt +++ b/docs/Changes.txt @@ -12,6 +12,28 @@ platform used. There should be another help file in this archive outlining the platform specific changes. +---------------------------------------------------------------------- +Section: New in release 0.94.5 +---------------------------------------------------------------------- + +Fixed bug: wrap-around branches (from $ff80+ to zp and back) were + reported as errors. Thanks to Bitbreaker for reporting this. +Fixed bug: left-shifting float values went wrong for large shifts. +New error message: "Target not in bank (0xTARGET)" for branches. +Fixed example program to get it to assemble with current library. +Streamlined "Floats.txt" docs. + +Changes in library files: + files now contain opcode_* constants in addition + to macros. +Added , containing a macro to store a float value in the + five-byte format used by CBM basic (and while writing that macro, + found the left-shift-float bug mentioned above, so the macro needs + this fixed version to work). +Added , containing definitions for using the BASIC + interpreter's float functions and constants. + + ---------------------------------------------------------------------- Section: New in release 0.94.4 ---------------------------------------------------------------------- diff --git a/docs/Errors.txt b/docs/Errors.txt index 8ae1aea..31f6172 100644 --- a/docs/Errors.txt +++ b/docs/Errors.txt @@ -47,8 +47,9 @@ Assembling buggy JMP($xxff) instruction The original 6502 processor has a bug: When executing an indirect JMP instruction where the low byte of the argument equals $ff, it fetches the high byte of the jump target address not from memory - location ARGUMENT+1, but from ARGUMENT-255. Therefore ACME issues - this warning if you are about to generate such an instruction. + location ARGUMENT + 1, but from ARGUMENT - 255. Therefore ACME + issues this warning if you are about to generate such an + instruction. Note that this warning is only given for CPU types 6502 and 6510, because 65c02 and 65816 have been fixed in this respect. @@ -157,8 +158,8 @@ Division by zero. Guess what - you attempted to divide by zero. Exponent is negative. - Using negative exponents would only give sensible results when - using floating point maths. + Using negative exponents only give sensible results when using + floating point maths. File name quotes not found ("" or <>). File names have to be given in quotes. Either "" quoting for files @@ -227,11 +228,16 @@ Source file contains illegal character. Syntax error. Guess what - there's a syntax error. +Target not in bank (0xTARGET). + You tried to branch to an address not in the 0x0000..0xffff range. + Relative addressing (branch commands or PER) cannot leave the + current code bank of 64 KiB. + Target out of range (N; M too far). - A relative addressing (branch commands or PER) only has a limited - range. You exceeded it. N is the attempted offset, M is the difference - to the limit - so if you succeed in optimizing M bytes away, the code - would assemble. + Branch commands use relative addressing, which only has a limited + range. You exceeded it. N is the attempted offset, M is the + difference to the limit - so if you succeed in optimizing M bytes + away, the code would assemble. There's more than one character. You used a text string in an arithmetic expression, but the string diff --git a/docs/Example.txt b/docs/Example.txt index 58c5a28..5d09d16 100644 --- a/docs/Example.txt +++ b/docs/Example.txt @@ -28,4 +28,3 @@ Just in case you wonder: "macedit" is an unusably bad text editor for the C128. The source code is not meant to be a good example of ACME's capabilities. Please *don't* look at it. :) - diff --git a/docs/Floats.txt b/docs/Floats.txt index 6b8350a..99782a3 100644 --- a/docs/Floats.txt +++ b/docs/Floats.txt @@ -1,13 +1,16 @@ -Hi! -This is a preliminary release of ACME. I added basic support for -floating point maths. Consider this a special version for beta -testers. Known bugs: Segment counting may be screwed up at the moment. -New: -The maths parser knows about floating point maths, so you can finally -build sin/cos tables directly in ACME. But the expression parser still -uses integer calculations per default. Here are the rules: + ACME + + ...the ACME Crossassembler for Multiple Environments + + --- floating-point support --- + + +In release 0.92, ACME gained some experimental support for floating- +point maths, so you can finally build sin/cos tables directly in ACME. +But the expression parser still uses integer calculations per default. +Here are the rules: a) if a maths operation is useless when done with integers, it is done with floats and returns a float. Applies to sin(), cos(), tan(), @@ -28,7 +31,12 @@ To force a numerical value to be flagged as being a float, just add a decimal point and a zero. If a decimal value ends with a dot character, ACME switches to using the C type "double" and keeps reading digits. The value is then flagged internally as being float. - +CAUTION: Float usage is only activated when a decimal point has been +found, so don't expect "100000000000000000000" to work. +"100000000000000000000.0" won't work either, because when the decimal +point gets parsed, the integer value will have overflown already. As +there is no support yet for the "e" format (1e20 for 1*10^20) either, +the only way to enter this value is by writing "1.0 * 10.0 ^ 20.0". Examples: @@ -46,14 +54,11 @@ You can use the new float() and int() functions to ensure the type of maths: !byte a / b * c ; depends on a/b/c's internal flags - !byte float(a)/b*c ; calculation is done in FP - !byte int(a)/int(b)*int(c); calculation is done in integer + !byte float(a) / b * c ; calculation is done as float + !byte int(a) / int(b) * int(c) ; calculation is done as int As you will have guessed, the trigonometric functions assume radians for measuring angles (90 degrees equals PI/2). -Have a look at the example source code, it builds some sin/cos tables. - -Have fun, and let me know what you think, - -Marco Baye +Have a look at the example source code "trigono.a", it builds some +sin/cos tables. diff --git a/docs/Help.txt b/docs/Help.txt index e7eec6a..3d2865f 100644 --- a/docs/Help.txt +++ b/docs/Help.txt @@ -4,11 +4,11 @@ ...the ACME Crossassembler for Multiple Environments - Release 0.91 + Release 0.94.5 - free software - - (C) 1998-2006 Marco Baye + (C) 1998-2013 Marco Baye ---------------------------------------------------------------------- @@ -54,16 +54,17 @@ The files in the docs directory and what they contain: 65816.txt Stuff specific to the 65816 processor AddrModes.txt How to choose non-standard addressing modes AllPOs.txt Lists ACME's pseudo opcodes. Use as a reference. - Changes.txt The change log. + Changes.txt The change log COPYING Version 2 of the GNU General Public License Errors.txt Lists ACME's error messages and what they mean. Example.txt Information on how to assemble the example sources. + Floats.txt About the support for floating-point values Help.txt ...is this text. - Illegals.txt Support for undocumented opcodes. - Lib.txt Information about the library. - QuickRef.txt All the basic stuff about ACME. - Source.txt How to compile ACME. - Upgrade.txt Incompatibilities to earlier versions. + Illegals.txt Support for undocumented opcodes + Lib.txt Information about the library + QuickRef.txt All the basic stuff about ACME + Source.txt How to compile ACME + Upgrade.txt Incompatibilities to earlier versions IMPORTANT: If you upgrade from ACME 0.05 or earlier, don't forget to read the file "Upgrade.txt" - release 0.07 and all later ones are @@ -170,7 +171,7 @@ Section: Contacting the author ---------------------------------------------------------------------- The newest version of ACME can be found at the ACME homepage: -http://home.pages.de/~mac_bacon/smorbrod/acme/ +http://sourceforge.net/p/acme-crossass/ If you want to report a bug or make a suggestion, then simply send me an email: diff --git a/docs/QuickRef.txt b/docs/QuickRef.txt index e30e9d0..e7e5d7e 100644 --- a/docs/QuickRef.txt +++ b/docs/QuickRef.txt @@ -246,7 +246,7 @@ Section: The maths parser ---------------------------------------------------------------------- ACME has a relatively powerful maths parser. This parser is used -whenever ACME expects to read an integer value. Supported operations +whenever ACME expects to read a numerical value. Supported operations include addition, subtraction, multiplication, divisions, comparisons, shifts, negation, boolean operations and some assembler-specific stuff like extracting the "low byte", the "high byte" or the "bank byte" diff --git a/docs/Source.txt b/docs/Source.txt index d248999..d2df6e5 100644 --- a/docs/Source.txt +++ b/docs/Source.txt @@ -12,7 +12,7 @@ General Public License. Therefore, the sources must be made publicly accessible. If this archive does not contain the source file tree, you can download it from the ACME web page at -http://home.pages.de/~mac_bacon/smorbrod/acme/ +http://sourceforge.net/p/acme-crossass/ To build ACME, you need a recent C compiler and a "make" utility. On most systems, typing "make" should suffice to build the binary. See diff --git a/examples/macedit.a b/examples/macedit.a index b72fa16..8a67016 100644 --- a/examples/macedit.a +++ b/examples/macedit.a @@ -9,8 +9,8 @@ *= $1300 !ct pet !source <6502/std.a> - !ifndef Lib_6502_std_a { - !serious "To assemble this program, you need to install the ACME library." + !ifndef lib_6502_std_a { + !serious "To assemble this program, you need to install the current ACME library." } !source "me/macros.a" !source "me/const.a" @@ -74,3 +74,5 @@ Spätere Änderungen am Source: Now throws serious error if the library file could not be loaded. 7 Apr 2013: Converted to UTF-8 +27 Jun 2013: + Adjusted to change in library. diff --git a/src/acme.c b/src/acme.c index 799a6a2..400a12a 100644 --- a/src/acme.c +++ b/src/acme.c @@ -15,10 +15,10 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -#define RELEASE "0.94.4" // update before release (FIXME) +#define RELEASE "0.94.5" // update before release (FIXME) #define CODENAME "Zarquon" // update before release -#define CHANGE_DATE "9 Oct" // update before release -#define CHANGE_YEAR "2012" // update before release +#define CHANGE_DATE "27 Jun" // update before release +#define CHANGE_YEAR "2013" // update before release //#define HOME_PAGE "http://home.pages.de/~mac_bacon/smorbrod/acme/" // FIXME #define HOME_PAGE "http://sourceforge.net/p/acme-crossass/" // FIXME diff --git a/src/alu.c b/src/alu.c index 187275a..7f50866 100644 --- a/src/alu.c +++ b/src/alu.c @@ -625,6 +625,7 @@ static void expect_operand_or_monadic_operator(void) // Now GotByte = char after closing quote goto now_expect_dyadic; +// FIXME - find a way to tell decimal point and LOCAL_PREFIX apart! case '.': // Local label or fractional part of float value GetByte(); // start after '.' // check for fractional part of float value @@ -995,7 +996,7 @@ static void try_to_reduce_stacks(int *open_parentheses) // monadic operators case OPHANDLE_NOT: - // different operations for fp and int + // fp becomes int if (RIGHT_FLAGS & MVALUE_IS_FP) right_fp_to_int(); RIGHT_INTVAL = ~(RIGHT_INTVAL); @@ -1141,7 +1142,7 @@ static void try_to_reduce_stacks(int *open_parentheses) if (RIGHT_FLAGS & MVALUE_IS_FP) right_fp_to_int(); if (LEFT_FLAGS & MVALUE_IS_FP) - LEFT_FPVAL *= (1 << RIGHT_INTVAL); + LEFT_FPVAL *= pow(2.0, RIGHT_INTVAL); else LEFT_INTVAL <<= RIGHT_INTVAL; goto handle_flags_and_dec_stacks; @@ -1156,6 +1157,7 @@ static void try_to_reduce_stacks(int *open_parentheses) goto handle_flags_and_dec_stacks; case OPHANDLE_LSR: + // fp become int if ((RIGHT_FLAGS | LEFT_FLAGS) & MVALUE_IS_FP) both_ensure_int(TRUE); LEFT_INTVAL = ((uintval_t) LEFT_INTVAL) >> RIGHT_INTVAL; @@ -1216,6 +1218,7 @@ static void try_to_reduce_stacks(int *open_parentheses) goto handle_flags_and_dec_stacks; case OPHANDLE_AND: + // fp become int if ((RIGHT_FLAGS | LEFT_FLAGS) & MVALUE_IS_FP) both_ensure_int(TRUE); LEFT_INTVAL &= RIGHT_INTVAL; @@ -1225,12 +1228,14 @@ static void try_to_reduce_stacks(int *open_parentheses) Throw_first_pass_warning("\"EOR\" is deprecated; use \"XOR\" instead."); /*FALLTHROUGH*/ case OPHANDLE_XOR: + // fp become int if ((RIGHT_FLAGS | LEFT_FLAGS) & MVALUE_IS_FP) both_ensure_int(TRUE); LEFT_INTVAL ^= RIGHT_INTVAL; goto handle_flags_and_dec_stacks; case OPHANDLE_OR: + // fp become int if ((RIGHT_FLAGS | LEFT_FLAGS) & MVALUE_IS_FP) both_ensure_int(TRUE); LEFT_INTVAL |= RIGHT_INTVAL; diff --git a/src/basics.c b/src/basics.c index 7862a94..176fce3 100644 --- a/src/basics.c +++ b/src/basics.c @@ -189,6 +189,7 @@ static enum eos_t throw_string(const char prefix[], void (*fn)(const char *)) //// +//static enum eos_t PO_debug(void) //static enum eos_t PO_info(void) //static enum eos_t PO_print(void) //{ @@ -233,6 +234,7 @@ static struct node_t pseudo_opcodes[] = { PREDEFNODE("binary", PO_binary), PREDEFNODE("fi", PO_fill), PREDEFNODE("fill", PO_fill), +// PREDEFNODE("debug", PO_debug), // PREDEFNODE("info", PO_info), // PREDEFNODE("print", PO_print), PREDEFNODE("warn", PO_warn), diff --git a/src/cpu.c b/src/cpu.c index 83ec5a9..341a38d 100644 --- a/src/cpu.c +++ b/src/cpu.c @@ -66,8 +66,8 @@ static struct cpu_t CPU_65816 = { struct cpu_t *CPU_now; // struct of current CPU type (default 6502) struct result_int_t CPU_pc; // (pseudo) program counter at start of statement int CPU_2add; // increase PC by this after statement -static intval_t current_offset; // PseudoPC - MemIndex -static int uses_pseudo_pc; // offset assembly active? +static intval_t current_offset; // PseudoPC - MemIndex (FIXME - why is this needed?) +static int uses_pseudo_pc; // offset assembly active? FIXME - what is this for? // predefined stuff static struct node_t *CPU_tree = NULL; // tree to hold CPU types static struct node_t CPUs[] = { @@ -144,16 +144,17 @@ static const char Warning_old_offset_assembly[] = // start offset assembly static enum eos_t PO_pseudopc(void) { +// future algo: remember outer memaddress and outer pseudopc int outer_state = uses_pseudo_pc; intval_t new_pc, outer_offset = current_offset; int outer_flags = CPU_pc.flags; // set new - new_pc = ALU_defined_int(); + new_pc = ALU_defined_int(); // FIXME - allow for undefined pseudopc! current_offset = (current_offset + new_pc - CPU_pc.intval) & 0xffff; CPU_pc.intval = new_pc; - CPU_pc.flags |= MVALUE_DEFINED; + CPU_pc.flags |= MVALUE_DEFINED; // FIXME - remove! uses_pseudo_pc = TRUE; // if there's a block, parse that and then restore old value! if (Parse_optional_block()) { @@ -162,6 +163,7 @@ static enum eos_t PO_pseudopc(void) CPU_pc.flags = outer_flags; CPU_pc.intval = (outer_offset + CPU_pc.intval - current_offset) & 0xffff; current_offset = outer_offset; +// future algo: new outer pseudopc = (old outer pseudopc + (current memaddress - outer memaddress)) & 0xffff } else { Throw_first_pass_warning(Warning_old_offset_assembly); } @@ -181,7 +183,7 @@ static enum eos_t PO_realpc(void) } -// return whether offset assembly is active +// return whether offset assembly is active (FIXME - remove this function) int CPU_uses_pseudo_pc(void) { return uses_pseudo_pc; diff --git a/src/cpu.h b/src/cpu.h index 9440188..052c4fa 100644 --- a/src/cpu.h +++ b/src/cpu.h @@ -36,7 +36,7 @@ extern void CPUtype_init(void); extern void CPU_init(void); // set default values for pass extern void CPU_passinit(struct cpu_t *cpu_type); -// set program counter to defined value +// set program counter to defined value (FIXME - allow undefined!) extern void CPU_set_pc(intval_t new_pc); // try to find CPU type held in DynaBuf. Returns whether succeeded. extern int CPU_find_cpu_struct(struct cpu_t **target); diff --git a/src/flow.c b/src/flow.c index d154281..b84a203 100644 --- a/src/flow.c +++ b/src/flow.c @@ -25,13 +25,10 @@ // type definitions -enum cond_key_t { - ID_UNTIL, // Handles to store instead of - ID_WHILE, // the UNTIL and WHILE keywords -}; + struct loop_condition { - enum cond_key_t type; // either ID_UNTIL or ID_WHILE int line; // original line number + int invert; // actually bool (0 for WHILE, 1 for UNTIL) char *body; // pointer to actual expression }; @@ -41,8 +38,8 @@ struct loop_condition { // predefined stuff static struct node_t *condkey_tree = NULL; // tree to hold UNTIL and WHILE static struct node_t condkeys[] = { - PREDEFNODE("until", ID_UNTIL), - PREDEFLAST("while", ID_WHILE), + PREDEFNODE("until", TRUE), // UNTIL inverts the condition + PREDEFLAST("while", FALSE), // WHILE does not change the condition // ^^^^ this marks the last element }; @@ -62,7 +59,7 @@ static void parse_ram_block(int line_number, char *body) // try to read a condition into DynaBuf and store copy pointer in -// given loopcond_t structure. +// given loop_condition structure. // if no condition given, NULL is written to structure. // call with GotByte = first interesting character static void store_condition(struct loop_condition *condition, char terminator) @@ -74,6 +71,7 @@ static void store_condition(struct loop_condition *condition, char terminator) // Check for empty condition if (GotByte == terminator) { // Write NULL condition, then return + condition->invert = FALSE; condition->body = NULL; return; } @@ -83,10 +81,11 @@ static void store_condition(struct loop_condition *condition, char terminator) // Search for new tree item if (!Tree_easy_scan(condkey_tree, &node_body, GlobalDynaBuf)) { Throw_error(exception_syntax); + condition->invert = FALSE; condition->body = NULL; return; } - condition->type = (enum cond_key_t) node_body; + condition->invert = (int) node_body; // Write given condition into buffer SKIPSPACE(); DYNABUF_CLEAR(GlobalDynaBuf); @@ -104,7 +103,7 @@ static int check_condition(struct loop_condition *condition) // First, check whether there actually *is* a condition if (condition->body == NULL) - return 1; // non-existant conditions are always true + return TRUE; // non-existing conditions are always true // set up input for expression evaluation Input_now->line_number = condition->line; @@ -113,7 +112,7 @@ static int check_condition(struct loop_condition *condition) expression = ALU_defined_int(); if (GotByte) Throw_serious_error(exception_syntax); - return (condition->type == ID_UNTIL) ? !expression : !!expression; + return condition->invert ? !expression : !!expression; } @@ -128,9 +127,10 @@ static enum eos_t PO_do(void) // Now GotByte = illegal char int go_on, loop_start; // line number of loop pseudo opcode // Init - condition2.type = ID_UNTIL; - condition2.body = NULL; + condition1.invert = FALSE; condition1.body = NULL; + condition2.invert = FALSE; + condition2.body = NULL; // Read head condition to buffer SKIPSPACE(); diff --git a/src/global.c b/src/global.c index 0884f4e..837fcfc 100644 --- a/src/global.c +++ b/src/global.c @@ -275,19 +275,19 @@ void Parse_until_eob_or_eof(void) break; case '+': GetByte(); - if ((GotByte == '.') + if ((GotByte == LOCAL_PREFIX) || (BYTEFLAGS(GotByte) & CONTS_KEYWORD)) Macro_parse_call(); else parse_forward_anon_def(&statement_flags); break; - case '!': + case PSEUDO_OPCODE_PREFIX: parse_pseudo_opcode(); break; case '*': parse_pc_def(); break; - case '.': + case LOCAL_PREFIX: parse_local_label_def(&statement_flags); break; default: diff --git a/src/global.h b/src/global.h index c4affe8..5c59680 100644 --- a/src/global.h +++ b/src/global.h @@ -11,6 +11,8 @@ #include #include "config.h" +#define PSEUDO_OPCODE_PREFIX '!' // FIXME - this is not yet used consistently! +#define LOCAL_PREFIX '.' // FIXME - this is not yet used consistently! // Constants diff --git a/src/input.c b/src/input.c index 635a63d..fd5423b 100644 --- a/src/input.c +++ b/src/input.c @@ -378,14 +378,14 @@ int Input_append_keyword_to_global_dynabuf(void) return length; } -// Check whether GotByte is a dot. +// Check whether GotByte is LOCAL_PREFIX (default '.'). // If not, store global zone value. // If yes, store current zone value and read next byte. // Then jump to Input_read_keyword(), which returns length of keyword. int Input_read_zone_and_keyword(zone_t *zone) { SKIPSPACE(); - if (GotByte == '.') { + if (GotByte == LOCAL_PREFIX) { GetByte(); *zone = Section_now->zone; } else { diff --git a/src/macro.c b/src/macro.c index 8c2f040..3a1edf8 100644 --- a/src/macro.c +++ b/src/macro.c @@ -78,7 +78,7 @@ void Macro_init(void) // Read macro zone and title. Title is read to GlobalDynaBuf and then copied // over to internal_name DynaBuf, where ARG_SEPARATOR is added. // In user_macro_name DynaBuf, the original name is reconstructed (even with -// '.' prefix) so a copy can be linked to the resulting macro struct. +// LOCAL_PREFIX) so a copy can be linked to the resulting macro struct. static zone_t get_zone_and_title(void) { zone_t macro_zone; @@ -89,7 +89,7 @@ static zone_t get_zone_and_title(void) DYNABUF_CLEAR(user_macro_name); DYNABUF_CLEAR(internal_name); if (macro_zone != ZONE_GLOBAL) - DynaBuf_append(user_macro_name, '.'); + DynaBuf_append(user_macro_name, LOCAL_PREFIX); DynaBuf_add_string(user_macro_name, GLOBALDYNABUF_CURRENT); DynaBuf_add_string(internal_name, GLOBALDYNABUF_CURRENT); DynaBuf_append(user_macro_name, '\0'); @@ -168,7 +168,7 @@ void Macro_parse_definition(void) // Now GotByte = illegal char after "!macro" // now GotByte = first non-space after title DYNABUF_CLEAR(GlobalDynaBuf); // prepare to hold formal parameters // GlobalDynaBuf = "" (will hold formal parameter list) - // user_macro_name = ['.'] MacroTitle NUL + // user_macro_name = [LOCAL_PREFIX] MacroTitle NUL // internal_name = MacroTitle ARG_SEPARATOR (grows to signature) // Accept n>=0 comma-separated formal parameters before CHAR_SOB ('{'). // Valid argument formats are: @@ -187,9 +187,9 @@ void Macro_parse_definition(void) // Now GotByte = illegal char after "!macro" DynaBuf_append(GlobalDynaBuf, REFERENCE_CHAR); GetByte(); } - // handle prefix for local labels ('.') - if (GotByte == '.') { - DynaBuf_append(GlobalDynaBuf, '.'); + // handle prefix for local labels (LOCAL_PREFIX, normally '.') + if (GotByte == LOCAL_PREFIX) { + DynaBuf_append(GlobalDynaBuf, LOCAL_PREFIX); GetByte(); } // handle label name diff --git a/src/mnemo.c b/src/mnemo.c index c7212dd..b10fd65 100644 --- a/src/mnemo.c +++ b/src/mnemo.c @@ -571,53 +571,65 @@ static void group_only_implied_addressing(int opcode) Input_ensure_EOS(); } -// helper function to output "Target out of range" message -static void too_far(intval_t actual, intval_t minimum, intval_t maximum) +// helper function to output "Target not in bank" message +static void not_in_bank(intval_t target) { char buffer[60]; // 640K should be enough for anybody - sprintf(buffer, "Target out of range (%ld; %ld too far).", actual, actual < minimum ? minimum - actual : actual - maximum); + sprintf(buffer, "Target not in bank (0x%lx).", target); Throw_error(buffer); } // Mnemonics using only 8bit relative addressing (short branch instructions). static void group_only_relative8_addressing(int opcode) { - struct result_int_t result; + struct result_int_t target; + intval_t offset = 0; // dummy value, to not throw more errors than necessary - ALU_int_result(&result); - if (result.flags & MVALUE_DEFINED) { - result.intval -= (CPU_pc.intval + 2); - if ((result.intval < -128) || (result.intval > 127)) - too_far(result.intval, -128, 127); + ALU_int_result(&target); + if (CPU_pc.flags & target.flags & MVALUE_DEFINED) { + if ((target.intval | 0xffff) != 0xffff) { + not_in_bank(target.intval); + } else { + offset = (target.intval - (CPU_pc.intval + 2)) & 0xffff; // clip to 16 bit offset + // fix sign + if (offset & 0x8000) + offset -= 0x10000; + // range check + if ((offset < -128) || (offset > 127)) { + char buffer[60]; // 640K should be enough for anybody + + sprintf(buffer, "Target out of range (%ld; %ld too far).", offset, offset < -128 ? -128 - offset : offset - 127); + Throw_error(buffer); + } + } } Output_byte(opcode); // this fn has its own range check (see above). // No reason to irritate the user with another error message, // so use Output_byte() instead of Output_8b() - //Output_8b(result.value); - Output_byte(result.intval); + //Output_8b(offset); + Output_byte(offset); Input_ensure_EOS(); } // Mnemonics using only 16bit relative addressing (BRL and PER). static void group_only_relative16_addressing(int opcode) { - struct result_int_t result; + struct result_int_t target; + intval_t offset = 0; // dummy value, to not throw more errors than necessary - ALU_int_result(&result); - if (result.flags & MVALUE_DEFINED) { - result.intval -= (CPU_pc.intval + 3); - if ((result.intval < -32768) || (result.intval > 32767)) - too_far(result.intval, -32768, 32767); + ALU_int_result(&target); + if (CPU_pc.flags & target.flags & MVALUE_DEFINED) { + if ((target.intval | 0xffff) != 0xffff) { + not_in_bank(target.intval); + } else { + offset = (target.intval - (CPU_pc.intval + 3)) & 0xffff; + // no further checks necessary, 16-bit branches can access whole bank + } } Output_byte(opcode); - // this fn has its own range check (see above). - // No reason to irritate the user with another error message, - // so use Output_byte() instead of Output_16b() - //Output_16b(result.value); - Output_byte(result.intval); - Output_byte(result.intval >> 8); + Output_16b(offset); Input_ensure_EOS(); } diff --git a/src/output.c b/src/output.c index b0d5464..8850e7c 100644 --- a/src/output.c +++ b/src/output.c @@ -486,7 +486,7 @@ void Output_passinit(signed long start_addr) segment_start = 0; } // other stuff - segment_max = OUTBUFFERSIZE-1; + segment_max = OUTBUFFERSIZE - 1; segment_flags = 0; } @@ -513,6 +513,7 @@ void Output_start_segment(void) new_flags |= (int) node_body; } +// to allow for undefined pseudopc, this must be changed to use memaddress instead! if (CPU_pc.flags & MVALUE_DEFINED) { // it's a redefinition. Check some things: // check whether new low