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
This commit is contained in:
marcobaye 2013-06-26 23:01:00 +00:00
parent 6de19a5afe
commit 059238874d
27 changed files with 655 additions and 249 deletions

View File

@ -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

View File

@ -5,12 +5,17 @@ lib_cbm_basic10_a = 1
!source <cbm/basic7.a> ; 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}

View File

@ -4,4 +4,9 @@
lib_cbm_basic2_a = 1
!source <cbm/basic1.a> ; 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}

View File

@ -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 <cbm/basic2.a> ; 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}

View File

@ -4,19 +4,39 @@
lib_cbm_basic4_a = 1
!source <cbm/basic2.a> ; 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}

106
ACME_Lib/cbm/c64/float.a Normal file
View File

@ -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 <cbm/mflpt.a> ; 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()

79
ACME_Lib/cbm/mflpt.a Normal file
View File

@ -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)
}
}
}

View File

@ -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:
<cbm/basicWHATEVER.a> files now contain opcode_* constants in addition
to macros.
Added <cbm/mflpt.a>, 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 <cbm/c64/float.a>, containing definitions for using the BASIC
interpreter's float functions and constants.
----------------------------------------------------------------------
Section: New in release 0.94.4
----------------------------------------------------------------------

View File

@ -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

View File

@ -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. :)

View File

@ -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.

View File

@ -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:

View File

@ -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"

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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;

View File

@ -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),

View File

@ -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;

View File

@ -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);

View File

@ -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();

View File

@ -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:

View File

@ -11,6 +11,8 @@
#include <stdlib.h>
#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

View File

@ -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 {

View File

@ -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

View File

@ -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();
}

View File

@ -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