Advertisement
Guest User

ca 65 hl

a guest
Oct 23rd, 2012
395
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 40.31 KB | None | 0 0
  1. ; CA65 HLA macro pack v5
  2.  
  3. ; Copyright Movax big.jay.tee@gmail.com
  4. ; You are free: to Share — to copy, distribute and transmit the work
  5. ; to Remix — to adapt the work
  6. ; to make commercial use of the work
  7. ; Under the following conditions:
  8.  
  9. ; Attribution — You must attribute the work to big.jay.tee@gmail.com in documentation or with any other credits.
  10. ;
  11. ; And you must read and be aware of the implications here: http://creativecommons.org/licenses/by/3.0/us/
  12. ;
  13. ;
  14. ;---------------------------------------------------------------------------------------------------------------------------------------------------
  15. ;
  16. ; Adds IF-ELSE-ENDIF, DO-WHILE, WHILE-DO-ENDWHILE,REPEAT-UNTIL
  17. ; As well as the ability to use a 'function' macro to call other code in a way compatible with the above
  18. ; Included is an expression evaluation for unsigned (comp) and signed (scomp) comparisons. Note that any comparison using greater (>) or less (<) cannot also include a
  19. ; low or high byte operator (< or > ) unless it is enclosed in brackets.
  20. ;
  21. ; Please send any bugs to the above email or message Movax12 at forums.nesdev.com
  22. ; As well there are two macros named mb, mw for (m)ove (b)yte (m)ove (w)ord that use an := assingment operator
  23. ;
  24. ; Expression to test represents the flags of the 6502
  25. ; All expressions evaluate into a singe branch instruction with the exception of 'greater' and 'not greater'/'lessORequal'
  26. ; which is handled with two small macros
  27. ;
  28. ; Only simple flag name is evaluated (ie C,Z,N,V) along with no/not before and set/clear after
  29. ; a second 'clear' will negate the flag check, a not will negate the entire expression and is applied last
  30. ;
  31. ; FORMAT
  32. ; In order: Optional: 'no' OR 'not'', Required: <flag alias> or <flag set/clear>, Optional: 'clear' or 'set'
  33.  
  34. ; Some strict sytax and error checking.
  35. ;
  36. ;
  37. ; More documentation http://mynesdev.blogspot.ca/
  38.  
  39.  
  40. ; BELOW: .defines for recognized flag tests. Format: Flag to test for and default setting. Add or remove from this block at will
  41.  
  42. .define less C clear
  43. .define greaterORequal C set
  44. .define carry C set
  45. .define zero Z set
  46. .define equal Z set
  47. .define plus N clear
  48. .define positive N clear
  49. .define minus N set
  50. .define negative N set
  51. .define bit7 N set
  52. .define overflow V set
  53. .define bit6 V set
  54. .define true Z clear ; NON-ZERO is TRUE - Use after AND instruction (any bits set = true)
  55. .define false Z set ; ZERO is false
  56.  
  57. .define greater G set ; Use greater and less/equal macros to simulate
  58. .define lessORequal G clear
  59.  
  60. ; define symbols for AND, OR, NOT
  61.  
  62. .define _USER_AND_DEFINITION_ && ; '&&' will match '.and'
  63. .define _USER_OR_DEFINITION_ || ; '||' will match '.or'
  64. .define _USER_NOT_DEFINITION1 not
  65. .define _USER_NOT_DEFINITION2 !
  66. .define _USER_GOTO_DEFINITION goto ; if condition goto label
  67.  
  68. ; No changes past this line ..etc.. unless you know what you are doing
  69.  
  70. ; BELOW HERE IS HIGH LEVEL LANGUAGE FUNCTIONS
  71.  
  72. ; branch array
  73. ; instruction 0 means flag clear, 1 means set
  74.  
  75. .define FLAG_1_1 bcs
  76. .define FLAG_1_2 beq
  77. .define FLAG_1_3 bmi
  78. .define FLAG_1_4 bvs
  79. .define FLAG_0_1 bcc
  80. .define FLAG_0_2 bne
  81. .define FLAG_0_3 bpl
  82. .define FLAG_0_4 bvc
  83.  
  84. .define FLAG_1_5 branch_if_greater
  85. .define FLAG_0_5 branch_if_less_or_equal
  86.  
  87. _EXP_ERROR .set 0
  88.  
  89. _IF_ENDIF__IF_label .set 0 ; total number of IFs used
  90. _IF_ENDIF__SP .set 0 ; Stack Pointer
  91. _IF_ENDIF__END_label .set 0
  92. _IF_ENDIF__flagnum .set 0
  93. _IF_ENDIF__flagset .set 0
  94.  
  95.  
  96. _DO_WHILE__DO_label .set 0
  97. _DO_WHILE__SP .set 0 ; Stack Pointer
  98. _DO_WHILE__WHILE_label .set 0
  99. _DO_WHILE__flagnum .set 0
  100. _DO_WHILE__flagset .set 0
  101.  
  102.  
  103. _WHILE_ENDWHILE__WHILE_label .set 0
  104. _WHILE_ENDWHILE__SP .set 0 ; Stack Pointer
  105. _WHILE_ENDWHILE__END_label .set 0
  106. _WHILE_ENDWHILE__flagnum .set 0
  107. _WHILE_ENDWHILE__flagset .set 0
  108.  
  109. __MACRO_FUNCTION_COMPLETE_ .set 0 ; signal back to the "process_expression_FLAGS" that function is done sucessfully
  110.  
  111. ; temp variables for parsing strings / tokens
  112. _AND_POS_ .set 0
  113. _OR_POS_ .set 0
  114. _AND_POS_copy .set 0
  115. _OR_POS_copy .set 0
  116.  
  117. _LONG_JUMP_ .set 0 ; options for generating long jumps
  118. _BRANCH_LENGTH_CHECKING_ .set 1
  119.  
  120. ;----------------------------------------------------------------------------
  121.  
  122. .macro branch_if_greater label
  123. .local over
  124. beq over
  125. bcs label
  126. over:
  127. .endmacro
  128.  
  129. .macro branch_if_less_or_equal label
  130. beq label
  131. bcc label
  132. .endmacro
  133.  
  134. ; Set options
  135. .macro set_long_branch option, messages
  136. .if .xmatch(option, +)
  137. ::_LONG_JUMP_ .set 1
  138. .elseif .xmatch(option,-)
  139. ::_LONG_JUMP_ .set 0
  140. .else
  141. .out "Unknown branch setting, branches are set to LONG."
  142. ::_LONG_JUMP_ .set 1
  143. .endif
  144.  
  145. .if .xmatch(messages, +)
  146. ::_BRANCH_LENGTH_CHECKING_ .set 1
  147. .elseif .xmatch(messages,-) .or .xmatch(option,-)
  148. ::_BRANCH_LENGTH_CHECKING_.set 0
  149. .else
  150. .out "Unknown branch message setting, set to ON"
  151. ::_BRANCH_LENGTH_CHECKING_.set 1
  152. .endif
  153. .endmacro
  154.  
  155. ; Common macro 'sub' routines
  156.  
  157. .macro checkbrackets flagtest ; this can't error check too many closing brackets, it will match first properly closed bracket that matches the starting bracket
  158.  
  159. ::_OR_POS_ .set 0 ; use as temp
  160. ::_AND_POS_ .set 0
  161. findposition {flagtest}, (, ::_OR_POS_
  162.  
  163. .if ::_OR_POS_ = -1 ; if bracket is on very left side, look for matching close, otherwise ignore
  164. ::_OR_POS_ .set 0
  165. matchbrackets {flagtest}, ::_OR_POS_, (,)
  166. .if ::_OR_POS_ = .tcount({flagtest}) - 1 ; if bracket is on the very outside:
  167. ::_AND_POS_ .set -1
  168. .exitmacro
  169. .else
  170. .if ::_OR_POS_ = 0 ; not found
  171. .error " Brackets do not match."
  172. ::_EXP_ERROR .set 1
  173. .endif
  174. .endif
  175.  
  176. .endif
  177.  
  178. .endmacro
  179.  
  180. ; Find the position and exact value of a token 'tok' in 'exp' and change the value of 'position' whilst skipping any tokens
  181. ; inside matching openskip and closeskip - nested
  182. ; Does not match very 1st character at pos 0, beacuse 0 means not found
  183. ; will return -1 if character found at pos 0 (this is better generally for using wih .mid() )
  184.  
  185. .macro findposition exp, tok, position, openskip, closeskip
  186.  
  187. .if .xmatch({.mid(position,1,{exp})},{tok})
  188.  
  189. .if position = 0
  190. position .set -1
  191. .endif
  192. .exitmacro
  193. .else
  194.  
  195. ; no match yet:
  196. .ifnblank {openskip} ; if open bracket then expand a new macro to find close bracket honoring other brackets
  197. .if .xmatch({.mid(position,1,{exp})},{openskip})
  198. position .set position + 1
  199. findposition {exp}, {closeskip}, position , openskip, closeskip
  200. .endif
  201. .endif
  202.  
  203. .if (position >= .tcount({exp}))
  204. ; no more tokens, not found, set pos to 0
  205. position .set 0
  206. .exitmacro
  207. .endif
  208. position .set position + 1
  209. findposition {exp}, {tok}, position, openskip, closeskip
  210. .endif
  211. .endmacro
  212.  
  213.  
  214. ; given position of left bracket, matches right bracket, skipping other bracket pairs of the same kind
  215.  
  216. .macro matchbrackets exp, position, openbracket, closebracket, openskip, closeskip
  217.  
  218. ; assume position is at left bracket first time:
  219. position .set position + 1
  220.  
  221. .if .xmatch({.mid(position,1,{exp})},{closebracket})
  222. .exitmacro
  223. .else
  224. ; no match yet:
  225. .ifnblank {openskip} ; if open bracket then expand a new macro to find close bracket honoring other open/closeskip
  226. .if .xmatch({.mid(position,1,{exp})},{openskip})
  227. matchbrackets {exp}, position, openskip, closeskip
  228. .endif
  229. .endif
  230.  
  231. .if .xmatch({.mid(position,1,{exp})},{openbracket})
  232. matchbrackets {exp}, position, openbracket, closebracket, openskip, closeskip
  233. .endif
  234.  
  235. .if (position >= .tcount({exp}))
  236. ; no more tokens, not found, set pos to 0
  237. position .set 0 ; no matching closing bracket - not there or mismatched
  238. .exitmacro
  239. .endif
  240.  
  241. matchbrackets {exp}, position, openbracket, closebracket, openskip, closeskip
  242. .endif
  243. .endmacro
  244.  
  245. ; stack macros:
  246.  
  247. .macro push stackname, value, sp ; stackname, valuetoassign, stackpointer
  248.  
  249. .ident( .sprintf("%s_%04X_",stackname,sp)) .set value
  250. sp .set sp + 1
  251.  
  252. .endmacro
  253.  
  254. .macro pop stackname, var, sp
  255.  
  256. sp .set sp - 1
  257. var .set .ident( .sprintf("%s_%04X_",stackname,sp))
  258.  
  259. .endmacro
  260.  
  261. .macro codeout I,O ; wrap an ident into an instruction
  262. .ifnblank O
  263. I O
  264. .else
  265. I
  266. .endif
  267. .endmacro
  268.  
  269. .macro codeout_recursive I
  270.  
  271. ; I can contain a macro + options or any number of instructions seperated by +
  272. ; it must end with a macro that sets the flags via set_flag_test or set the flags with ==
  273.  
  274. .local pos, flag, plus_pos, equal_pos
  275.  
  276. plus_pos .set 0
  277. equal_pos .set 0
  278. findposition {I}, +,plus_pos , (,)
  279. findposition {I},=,equal_pos , (,)
  280. ; only match double equal:
  281.  
  282. .if .not .xmatch( {.mid(equal_pos+ (equal_pos = - 1) +1,1,{I})},=) ; If second equal doesn't exsit
  283. equal_pos .set 0
  284. .endif
  285.  
  286. .if plus_pos
  287. codeout {.mid(0, plus_pos, {I}) }
  288. codeout_recursive {.mid(plus_pos+1, .tcount({I}) - plus_pos - 1,{I})}
  289. .elseif equal_pos ; no more plus
  290. codeout {.mid(0, equal_pos, {I}) }
  291. .define _CPU_FLAGS_ .mid(equal_pos + 2 ,.tcount({I}) - equal_pos -2,{I})
  292. ::__MACRO_FUNCTION_COMPLETE_ .set 1
  293. .else ; no plus, no equal, should be a macro:
  294. I
  295. .endif
  296.  
  297. .endmacro
  298.  
  299.  
  300. .macro process_expression_FLAGS flagtest, flag, flagisset, negatefunction
  301.  
  302. ; Find a value for which flag we are checking and return:
  303. ; format of flagtest = [no OR not] flag 'set' OR 'clear' ['set' OR 'clear' ]
  304. ; If flag is not recognized, attempt to expand the macro and test if it completed
  305. ; if so, test the flag it set
  306.  
  307. ::_EXP_ERROR .set 0
  308. _n_ .set ( (.xmatch(.left(1, {flagtest}) , _USER_NOT_DEFINITION1)) .or (.xmatch(.left(1, {flagtest}) , _USER_NOT_DEFINITION2)) ) ; not or no prefix
  309.  
  310. ; Which flag are we testing? HAS to be a real flag, with the exception of G = greater
  311.  
  312. flag .set (.xmatch(.mid(_n_,1, {flagtest}) , C)) * 1 + (.xmatch(.mid(_n_,1, {flagtest}) , Z)) * 2 + (.xmatch(.mid(_n_,1,{flagtest}) , N)) * 3 + (.xmatch(.mid(_n_,1,{flagtest}) , V)) * 4 + (.xmatch(.mid(_n_,1,{flagtest}) , G)) * 5
  313.  
  314. .if (flag = 0) ; No flag found, Assume we should be calling a macro, or executing code .. ca65 needs a try command
  315.  
  316. ::__MACRO_FUNCTION_COMPLETE_ .set 0
  317.  
  318. codeout_recursive {.mid(_n_,.tcount({flagtest}) - _n_ , {flagtest})}
  319.  
  320. .if .not ::__MACRO_FUNCTION_COMPLETE_
  321. .error .sprintf("%s","Error in or unrecognized conditional function or instruction.")
  322. ::_EXP_ERROR .set 1
  323. .else
  324. _negate_next_ .set _n_ ; pass not to the recursion
  325. process_expression_FLAGS {_CPU_FLAGS_}, flag, flagisset, _negate_next_
  326. .undefine _CPU_FLAGS_
  327. .endif
  328. .exitmacro
  329.  
  330. .endif
  331.  
  332. __flag_set_default .set (.xmatch(.mid(_n_+1,1, {flagtest}), set)) * 1 + (.xmatch(.mid(_n_+1,1, {flagtest}), clear)) * -1
  333.  
  334. .ifnblank .mid(_n_+2,1, {flagtest}) ; user added clear or set, if token exsits here it must be a clear or set, any other is error
  335. __invert_flag .set .xmatch(.mid(_n_+2,1, {flagtest}), clear) * -1 + .xmatch(.mid(_n_+2,1, {flagtest}), set) * 1
  336. .else
  337. __invert_flag .set 1 ; no clear or set added, that's okay make it a 1
  338. .endif
  339. __invert_flag .set __invert_flag * (_n_ * -2 + 1)
  340. .ifnblank negatefunction ; support for recursive expansion and honor the original NOT operator
  341. __invert_flag .set __invert_flag * (negatefunction * -2 + 1)
  342. .endif
  343.  
  344. flagisset .set ((__flag_set_default * __invert_flag) > 0) ; This will always result in a negative or positive, positive means if flag is set then we branch
  345.  
  346. .if (flag = 0)
  347. ::_EXP_ERROR .set 1
  348. .error .concat( "Unknow flag: ", .string(.mid(_n_,1, flagtest)))
  349. .endif
  350.  
  351. .if (__invert_flag * __flag_set_default) = 0
  352. ::_EXP_ERROR .set 1
  353. .error .concat ( "Unknow flag condition: " , .string(.mid(_n_+1 + (__flag_set_default <> 0),1, {flagtest})))
  354. .endif
  355.  
  356.  
  357. .endmacro
  358.  
  359. .macro checkORAND flagtest ; 'or' was found, make sure no 'or' after any 'and'
  360.  
  361. findposition {flagtest}, _USER_OR_DEFINITION_, ::_OR_POS_, (,) ; look for or
  362. .if (::_AND_POS_ < ::_OR_POS_) .and (::_AND_POS_ > 0)
  363. .error " AND before OR in conditional expression, will not be parsed properly."
  364. ::_EXP_ERROR .set 1
  365. .exitmacro
  366. .elseif .not ::_OR_POS_
  367. checkORAND {flagtest}
  368. .endif
  369.  
  370. .endmacro
  371.  
  372.  
  373. ; *************************IF**********************
  374.  
  375. ; User is expected to only pass flagtest, and nothing more
  376. .macro if flagtest
  377.  
  378. findposition {flagtest}, _USER_GOTO_DEFINITION,::_OR_POS_ , (,)
  379.  
  380.  
  381. .if ::_OR_POS_
  382. ; small error check:
  383. .if .tcount({flagtest}) > ::_OR_POS_ + 2
  384. .error "Label expected after goto"
  385. .endif
  386.  
  387. if_macro {.mid(0,::_OR_POS_ ,{flagtest})},,,,,{.right(1,{flagtest})}
  388. .else
  389. if_macro {flagtest}
  390. .endif
  391.  
  392. .endmacro
  393.  
  394. .macro if_macro flagtest, lastrecursive, recursive, leftsideOR, leftsideAND, gotolabel
  395.  
  396. ; added to help show where an error is due to the error line displayed staying in the macro
  397. .ifdef ::_EXP_ERROR
  398. .if ::_EXP_ERROR
  399. .error " HINT: HL macpac error is in previous conditional expression."
  400. .fatal ""
  401. .endif
  402. .endif
  403.  
  404. ; First, if there are brackets on the very outside of the expression, remove them and try again
  405. checkbrackets {flagtest} ; Uses _AND_POS_ and _OR_POS_ as temps
  406. ; try again with brackets removed
  407. .if ::_AND_POS_ = -1 ; indicates we matched outside bracket
  408. if_macro {.mid(1,::_OR_POS_ -1,{flagtest})}, lastrecursive, recursive, leftsideOR, leftsideAND, gotolabel
  409. .exitmacro
  410. .endif
  411. ; end brackets
  412.  
  413. .if (.blank (recursive) .and .blank(lastrecursive)) ; this means only first call to this macro does this block get executed
  414. ::_IF_ENDIF__IF_label .set ::_IF_ENDIF__IF_label + 1
  415. .ifblank gotolabel ; do not save to endif stack if there is no endif
  416. push "IF_ENDIF_STACK",::_IF_ENDIF__IF_label, ::_IF_ENDIF__SP
  417. .endif
  418. .endif
  419.  
  420. ::_AND_POS_ .set 0
  421. ::_OR_POS_ .set 0
  422.  
  423. ; findposition exp, tok, position, openskip, closeskip
  424.  
  425. findposition {flagtest}, _USER_OR_DEFINITION_, ::_OR_POS_, (,) ; look for or
  426. .if ::_OR_POS_
  427.  
  428. ::_OR_POS_copy .set ::_OR_POS_
  429.  
  430. findposition {flagtest}, _USER_AND_DEFINITION_, ::_AND_POS_, (,) ; look for and in the entire enrty
  431. checkORAND {flagtest} ; make sure there are no ORs after the first AND
  432.  
  433. if_macro {.mid(0,::_OR_POS_copy,{flagtest})},,1,1,, gotolabel
  434.  
  435. findposition {.mid(::_OR_POS_copy+1, .tcount({flagtest})-::_OR_POS_copy-1,{flagtest})}, _USER_OR_DEFINITION_, ::_OR_POS_, (,) ; look for or
  436. findposition {.mid(::_OR_POS_copy+1, .tcount({flagtest})-::_OR_POS_copy-1,{flagtest})}, _USER_AND_DEFINITION_, ::_AND_POS_, (,) ; look for and
  437.  
  438. .if (.not ::_OR_POS_ ) .and (.not ::_AND_POS_)
  439. if_macro {.mid(::_OR_POS_copy+1, .tcount({flagtest})-::_OR_POS_copy-1,{flagtest})},1, , , , gotolabel ; last recursive call
  440. .else
  441. if_macro {.mid(::_OR_POS_copy+1, .tcount({flagtest})-::_OR_POS_copy-1,{flagtest})},,1, , , gotolabel
  442. .endif
  443.  
  444. .exitmacro
  445. .endif
  446.  
  447.  
  448. findposition {flagtest}, _USER_AND_DEFINITION_, ::_AND_POS_, (,) ; look for and
  449. .if ::_AND_POS_
  450.  
  451. ::_AND_POS_copy .set ::_AND_POS_
  452.  
  453. if_macro {.mid(0,::_AND_POS_,{flagtest})},,1,,1, gotolabel
  454.  
  455. findposition {.mid(::_AND_POS_copy+1, .tcount({flagtest})-::_AND_POS_copy-1,{flagtest})}, _USER_OR_DEFINITION_, ::_OR_POS_, (,) ; look for or
  456. findposition {.mid(::_AND_POS_copy+1, .tcount({flagtest})-::_AND_POS_copy-1,{flagtest})}, _USER_AND_DEFINITION_, ::_AND_POS_, (,) ; look for and
  457.  
  458. .if (.not ::_OR_POS_ ) .and (.not ::_AND_POS_)
  459. if_macro {.mid(::_AND_POS_copy+1, .tcount({flagtest})-::_AND_POS_copy-1,{flagtest})},1, , , , gotolabel
  460. .else
  461. if_macro {.mid(::_AND_POS_copy+1, .tcount({flagtest})-::_AND_POS_copy-1,{flagtest})},,1, , , gotolabel
  462. .endif
  463. .exitmacro
  464. .endif
  465.  
  466. process_expression_FLAGS {flagtest}, ::_IF_ENDIF__flagnum, ::_IF_ENDIF__flagset
  467.  
  468. .ifblank gotolabel
  469. ; normal if-endif
  470. .if (.not .blank(leftsideOR)) .or ( ::_LONG_JUMP_ .and .blank(recursive))
  471. codeout .ident (.sprintf("FLAG_%01X_%01X", ::_IF_ENDIF__flagset, ::_IF_ENDIF__flagnum )), .ident ( .sprintf ("%s%04X", "IF_CODE_BLOCK_START_LABEL_", ::_IF_ENDIF__IF_label))
  472. .else
  473. ::_IF_ENDIF__flagset .set .not ::_IF_ENDIF__flagset
  474. .if (.not .blank(leftsideAND)) .and ::_LONG_JUMP_ ; If Leftside and and long jump on
  475. codeout .ident (.sprintf("FLAG_%01X_%01X", ::_IF_ENDIF__flagset, ::_IF_ENDIF__flagnum )), .ident ( .sprintf ("%s%04X", "_IF_ENDIF_JMP_", ::_IF_ENDIF__IF_label))
  476. .else
  477. codeout .ident (.sprintf("FLAG_%01X_%01X", ::_IF_ENDIF__flagset, ::_IF_ENDIF__flagnum )), .ident ( .sprintf ("%s%04X", "_END_IF_", ::_IF_ENDIF__IF_label))
  478. .endif
  479. .endif
  480.  
  481. .else
  482. ; branch to label
  483. .if (.not .blank(leftsideAND)) .or ( ::_LONG_JUMP_ .and .blank(recursive))
  484. ::_IF_ENDIF__flagset .set .not ::_IF_ENDIF__flagset
  485. codeout .ident (.sprintf("FLAG_%01X_%01X", ::_IF_ENDIF__flagset, ::_IF_ENDIF__flagnum )), .ident ( .sprintf ("%s%04X", "IF_CODE_BLOCK_START_LABEL_", ::_IF_ENDIF__IF_label))
  486. .else
  487. .if (.not .blank(leftsideOR)) .and ::_LONG_JUMP_
  488. codeout .ident (.sprintf("FLAG_%01X_%01X", ::_IF_ENDIF__flagset, ::_IF_ENDIF__flagnum )), .ident ( .sprintf ("%s%04X", "_IF_ENDIF_JMP_", ::_IF_ENDIF__IF_label))
  489. .else
  490. codeout .ident (.sprintf("FLAG_%01X_%01X", ::_IF_ENDIF__flagset, ::_IF_ENDIF__flagnum )), gotolabel
  491. .endif
  492. .endif
  493.  
  494. .endif
  495.  
  496. .if .blank (recursive) ; no more branches:
  497. .if ::_LONG_JUMP_
  498.  
  499. .ident ( .sprintf ("%s%04X", "_IF_ENDIF_JMP_", ::_IF_ENDIF__IF_label)):
  500.  
  501. .if ::_BRANCH_LENGTH_CHECKING_
  502. .assert (.ident ( .sprintf ("%s%04X", "_END_IF_", ::_IF_ENDIF__IF_label)) ) - (.ident ( .sprintf ("%s%04X", "IF_CODE_BLOCK_START_LABEL_", ::_IF_ENDIF__IF_label))) > 127, warning, .sprintf("JMP in IF macro could have been reached with a branch at IF block %d",::_IF_ENDIF__IF_label)
  503. .endif
  504.  
  505. .ifblank gotolabel
  506. jmp .ident ( .sprintf ("%s%04X", "_END_IF_", ::_IF_ENDIF__IF_label))
  507. .else
  508. jmp gotolabel
  509. .endif
  510.  
  511. .endif
  512.  
  513. .ident ( .sprintf ("%s%04X", "IF_CODE_BLOCK_START_LABEL_", ::_IF_ENDIF__IF_label)):
  514. .endif
  515.  
  516. .endmacro
  517.  
  518. ; Create a label that will point to the next ENDIF and create an ENDIF/IF for the ELSE
  519.  
  520. .macro else
  521.  
  522. .ifndef ::_IF_ENDIF__IF_label
  523. .error "ELSE without IF"
  524. .fatal ""
  525. .endif
  526.  
  527. ::_IF_ENDIF__IF_label .set ::_IF_ENDIF__IF_label + 1 ; add one to IF count
  528.  
  529. jmp .ident ( .sprintf ("%s%04X", "_END_IF_", ::_IF_ENDIF__IF_label)) ; jump to the next endif (this is like a IF false - it will always jump)
  530. endif ; end if for the IF before this
  531.  
  532. push "IF_ENDIF_STACK",::_IF_ENDIF__IF_label, ::_IF_ENDIF__SP ; next endif will use this label
  533.  
  534.  
  535. .endmacro
  536.  
  537.  
  538. ; Pop if address from the IF stack and make a label
  539. .macro endif
  540.  
  541. .if (.not (.defined(::_IF_ENDIF__IF_label))) .or ((::_IF_ENDIF__SP - 1) < 0)
  542. .error "ENDIF or ELSE without IF"
  543. .fatal ""
  544. .endif
  545.  
  546. pop "IF_ENDIF_STACK",::_IF_ENDIF__END_label, ::_IF_ENDIF__SP
  547.  
  548. .ident ( .sprintf ("%s%04X", "_END_IF_", ::_IF_ENDIF__END_label)):
  549.  
  550. .endmacro
  551.  
  552. ; *************************END IF**********************
  553.  
  554. .macro do ; for do - while
  555.  
  556. ::_DO_WHILE__DO_label .set ::_DO_WHILE__DO_label + 1
  557.  
  558. push "_DO_WHILE_STACK_",::_DO_WHILE__DO_label, ::_DO_WHILE__SP
  559.  
  560.  
  561. .ident ( .sprintf ("%s%04X", "_DO_WHILE_", ::_DO_WHILE__DO_label)):
  562.  
  563. .endmacro
  564.  
  565. .macro while_DO_WHILE flagtest, lastrecursive, recursive, leftsideOR, leftsideAND, INV
  566.  
  567. .local long_jump
  568.  
  569.  
  570. .ifdef ::_EXP_ERROR ; added to help show where an error is due to the error line displayed staying in the macro
  571. .if ::_EXP_ERROR
  572. .error " HINT: Error is in previous flag expression."
  573. .fatal ""
  574. .endif
  575. .endif
  576.  
  577. ::_AND_POS_ .set 0
  578. ::_OR_POS_ .set 0
  579. checkbrackets {flagtest} ; Uses _AND_POS_ and _OR_POS_ as temps
  580. ; try again with brackets removed
  581. .if ::_AND_POS_ = -1
  582. while_DO_WHILE {.mid(1,::_OR_POS_ -1,{flagtest})}, lastrecursive, recursive, leftsideOR, leftsideAND, INV
  583. .exitmacro
  584. .endif
  585. ; end brackets
  586.  
  587. .if (.blank (recursive) .and .blank(lastrecursive)) ; this will only be executed on first call to this macro
  588. .if ((::_DO_WHILE__SP - 1) < 0) ; if accessing the stack will result in a negative value, there are too many whiles
  589. .error "WHILE/UNTIL without DO/REPEAT."
  590. .fatal ""
  591. .endif
  592. pop "_DO_WHILE_STACK_", :: _DO_WHILE__WHILE_label, ::_DO_WHILE__SP
  593. .endif
  594.  
  595. ; do and / or
  596.  
  597. ::_AND_POS_ .set 0
  598. ::_OR_POS_ .set 0
  599.  
  600. ; findposition exp, tok, position, openskip, closeskip
  601.  
  602. findposition {flagtest}, _USER_OR_DEFINITION_, ::_OR_POS_, (,) ; look for or
  603. .if ::_OR_POS_
  604.  
  605. ::_OR_POS_copy .set ::_OR_POS_
  606.  
  607. findposition {flagtest}, _USER_AND_DEFINITION_, ::_AND_POS_, (,) ; look for and in the entire enrty
  608. checkORAND {flagtest} ; make sure there are no ORs after the first AND
  609.  
  610. while_DO_WHILE {.mid(0,::_OR_POS_copy,{flagtest})},,1,1,,INV
  611.  
  612. findposition {.mid(::_OR_POS_copy+1, .tcount({flagtest})-::_OR_POS_copy-1,{flagtest})}, _USER_OR_DEFINITION_, ::_OR_POS_, (,) ; look for or
  613. findposition {.mid(::_OR_POS_copy+1, .tcount({flagtest})-::_OR_POS_copy-1,{flagtest})}, _USER_AND_DEFINITION_, ::_AND_POS_, (,) ; look for and
  614.  
  615. .if (.not ::_OR_POS_ ) .and (.not ::_AND_POS_)
  616. while_DO_WHILE {.mid(::_OR_POS_copy+1, .tcount({flagtest})-::_OR_POS_copy-1,{flagtest})},1 ,,,,INV ; last recursive call
  617. .else
  618. while_DO_WHILE {.mid(::_OR_POS_copy+1, .tcount({flagtest})-::_OR_POS_copy-1,{flagtest})},,1,,,INV
  619. .endif
  620.  
  621. .exitmacro
  622. .endif
  623.  
  624. findposition {flagtest}, _USER_AND_DEFINITION_, ::_AND_POS_, (,) ; look for and
  625. .if ::_AND_POS_
  626.  
  627. ::_AND_POS_copy .set ::_AND_POS_
  628.  
  629. while_DO_WHILE {.mid(0,::_AND_POS_,{flagtest})},,1,,1,INV
  630.  
  631. findposition {.mid(::_AND_POS_copy+1, .tcount({flagtest})-::_AND_POS_copy-1,{flagtest})}, _USER_OR_DEFINITION_, ::_OR_POS_, (,) ; look for or
  632. findposition {.mid(::_AND_POS_copy+1, .tcount({flagtest})-::_AND_POS_copy-1,{flagtest})}, _USER_AND_DEFINITION_, ::_AND_POS_, (,) ; look for and
  633.  
  634. .if (.not ::_OR_POS_ ) .and (.not ::_AND_POS_)
  635. while_DO_WHILE {.mid(::_AND_POS_copy+1, .tcount({flagtest})-::_AND_POS_copy-1,{flagtest})},1, , , ,INV
  636. .else
  637. while_DO_WHILE {.mid(::_AND_POS_copy+1, .tcount({flagtest})-::_AND_POS_copy-1,{flagtest})},,1, , ,INV
  638. .endif
  639. .exitmacro
  640. .endif
  641.  
  642. ; We only get here if there are no AND or ORS left in the current expansion:
  643.  
  644. ; guess if we need long jump:
  645. .if .not ::_LONG_JUMP_
  646. .if * - .ident ( .sprintf ("%s%04X", "_DO_WHILE_", ::_DO_WHILE__WHILE_label)) > 128 ; for sure we need a long jump, but we might need one even if this fails if too many branches
  647. long_jump .set 1
  648. .else
  649. long_jump .set 0
  650. .endif
  651. .else
  652. long_jump .set ::_LONG_JUMP_
  653. .endif
  654.  
  655. process_expression_FLAGS {flagtest}, ::_DO_WHILE__flagnum, ::_DO_WHILE__flagset
  656.  
  657. ;-------------------------------------------------PROCESS UNTIL
  658. .ifnblank INV ; this block of code copied from IF since an UNTIL is just like an IF with different labels
  659. ; IF True BRANCH out of loop
  660.  
  661. .if (.not .blank(leftsideOR)) .or ( long_jump .and .blank(recursive))
  662. codeout .ident (.sprintf("FLAG_%01X_%01X", ::_DO_WHILE__flagset, ::_DO_WHILE__flagnum )), .ident ( .sprintf ("%s%04X", "_END_LOOP_CONTINUE_", ::_DO_WHILE__WHILE_label))
  663. .else
  664. ::_DO_WHILE__flagset .set .not ::_DO_WHILE__flagset
  665. .if (.not .blank(leftsideAND)) .and long_jump ; If Leftside and and long jump on
  666. codeout .ident (.sprintf("FLAG_%01X_%01X", ::_DO_WHILE__flagset, ::_DO_WHILE__flagnum )), .ident ( .sprintf ("%s%04X", "_DO_WHILE_JMP_", ::_DO_WHILE__WHILE_label))
  667. .else
  668. codeout .ident (.sprintf("FLAG_%01X_%01X", ::_DO_WHILE__flagset, ::_DO_WHILE__flagnum )), .ident ( .sprintf ("%s%04X", "_DO_WHILE_", ::_DO_WHILE__WHILE_label))
  669. .endif
  670. .endif
  671.  
  672. ;-------------------------------------------------PROCESS WHILE: ( IF true GOTO begining)
  673. .else
  674.  
  675. .if (.not .blank(leftsideAND)) .or ( long_jump .and .blank(recursive))
  676. ::_DO_WHILE__flagset .set .not ::_DO_WHILE__flagset
  677. codeout .ident (.sprintf("FLAG_%01X_%01X", ::_DO_WHILE__flagset, ::_DO_WHILE__flagnum )), .ident ( .sprintf ("%s%04X", "_END_LOOP_CONTINUE_", ::_DO_WHILE__WHILE_label))
  678. .else
  679. .if (.not .blank(leftsideOR)) .and long_jump
  680. codeout .ident (.sprintf("FLAG_%01X_%01X", ::_DO_WHILE__flagset, ::_DO_WHILE__flagnum )), .ident ( .sprintf ("%s%04X", "_DO_WHILE_JMP_", ::_DO_WHILE__WHILE_label))
  681. .else
  682. codeout .ident (.sprintf("FLAG_%01X_%01X", ::_DO_WHILE__flagset, ::_DO_WHILE__flagnum )), .ident ( .sprintf ("%s%04X", "_DO_WHILE_", ::_DO_WHILE__WHILE_label))
  683. .endif
  684. .endif
  685.  
  686. .endif
  687.  
  688. .ifblank recursive
  689. .if long_jump
  690. .ident ( .sprintf ("%s%04X", "_DO_WHILE_JMP_", ::_DO_WHILE__WHILE_label)) :
  691.  
  692. .if ::_BRANCH_LENGTH_CHECKING_
  693. .assert (.ident ( .sprintf ("%s%04X", "_DO_WHILE_", ::_DO_WHILE__WHILE_label)) ) - (.ident ( .sprintf ("%s%04X", "_END_LOOP_CONTINUE_", ::_DO_WHILE__WHILE_label))) > 127, warning, .sprintf("JMP in do-while loop could have been reached with a branch at do-while block %d",::_DO_WHILE__WHILE_label)
  694. .endif
  695.  
  696. jmp .ident ( .sprintf ("%s%04X", "_DO_WHILE_", ::_DO_WHILE__WHILE_label))
  697. .endif
  698. .ident ( .sprintf ("%s%04X", "_END_LOOP_CONTINUE_",::_DO_WHILE__WHILE_label)):
  699. .endif
  700.  
  701. .endmacro
  702.  
  703. .macro while_WHILE_ENDWHILE flagtest, lastrecursive, recursive, leftsideOR, leftsideAND, INV
  704. ; while for starting a while - endwhile block, if N exists it will negate the test to emulate an 'until'
  705. ; added to help show where an error is due to the error line displayed staying in the macro
  706. .ifdef ::_EXP_ERROR
  707. .if ::_EXP_ERROR
  708. .error " HINT: HL macpac error is in previous conditional expression."
  709. .fatal ""
  710. .endif
  711. .endif
  712.  
  713. ; First, if there are brackets on the very outside of the expression, remove them and try again
  714.  
  715. checkbrackets {flagtest} ; Uses _AND_POS_ and _OR_POS_ as temps
  716. ; try again with brackets removed
  717. .if ::_AND_POS_ = -1 ; indicates we matched outside bracket
  718. while_WHILE_ENDWHILE {.mid(1,::_OR_POS_ -1,{flagtest})}, lastrecursive, recursive, leftsideOR, leftsideAND
  719. .exitmacro
  720. .endif
  721. ; end brackets
  722.  
  723. .if (.blank (recursive) .and .blank(lastrecursive))
  724. ::_WHILE_ENDWHILE__WHILE_label .set ::_WHILE_ENDWHILE__WHILE_label + 1
  725. push "WHILE_ENDWHILE_STACK_",::_WHILE_ENDWHILE__WHILE_label, ::_WHILE_ENDWHILE__SP
  726. .ident ( .sprintf ("%s%04X", "_WHILE_ENDWHILE_REPEAT_", ::_WHILE_ENDWHILE__WHILE_label)):
  727. .endif
  728.  
  729. ::_AND_POS_ .set 0
  730. ::_OR_POS_ .set 0
  731.  
  732. ; findposition exp, tok, position, openskip, closeskip
  733.  
  734. findposition {flagtest}, _USER_OR_DEFINITION_, ::_OR_POS_, (,) ; look for or
  735. .if ::_OR_POS_
  736.  
  737. ::_OR_POS_copy .set ::_OR_POS_
  738.  
  739. findposition {flagtest}, _USER_AND_DEFINITION_, ::_AND_POS_, (,) ; look for and in the entire enrty
  740. checkORAND {flagtest} ; make sure there are no ORs after the first AND
  741.  
  742. while_WHILE_ENDWHILE {.mid(0,::_OR_POS_copy,{flagtest})},,1,1
  743.  
  744. findposition {.mid(::_OR_POS_copy+1, .tcount({flagtest})-::_OR_POS_copy-1,{flagtest})}, _USER_OR_DEFINITION_, ::_OR_POS_, (,) ; look for or
  745. findposition {.mid(::_OR_POS_copy+1, .tcount({flagtest})-::_OR_POS_copy-1,{flagtest})}, _USER_AND_DEFINITION_, ::_AND_POS_, (,) ; look for and
  746.  
  747. .if (.not ::_OR_POS_ ) .and (.not ::_AND_POS_)
  748. while_WHILE_ENDWHILE {.mid(::_OR_POS_copy+1, .tcount({flagtest})-::_OR_POS_copy-1,{flagtest})},1 ; last recursive call
  749. .else
  750. while_WHILE_ENDWHILE {.mid(::_OR_POS_copy+1, .tcount({flagtest})-::_OR_POS_copy-1,{flagtest})},,1
  751. .endif
  752.  
  753. .exitmacro
  754. .endif
  755.  
  756.  
  757. findposition {flagtest}, _USER_AND_DEFINITION_, ::_AND_POS_, (,) ; look for and
  758. .if ::_AND_POS_
  759.  
  760. ::_AND_POS_copy .set ::_AND_POS_
  761.  
  762. while_WHILE_ENDWHILE {.mid(0,::_AND_POS_,{flagtest})},,1,,1
  763.  
  764. findposition {.mid(::_AND_POS_copy+1, .tcount({flagtest})-::_AND_POS_copy-1,{flagtest})}, _USER_OR_DEFINITION_, ::_OR_POS_, (,) ; look for or
  765. findposition {.mid(::_AND_POS_copy+1, .tcount({flagtest})-::_AND_POS_copy-1,{flagtest})}, _USER_AND_DEFINITION_, ::_AND_POS_, (,) ; look for and
  766.  
  767. .if (.not ::_OR_POS_ ) .and (.not ::_AND_POS_)
  768. while_WHILE_ENDWHILE {.mid(::_AND_POS_copy+1, .tcount({flagtest})-::_AND_POS_copy-1,{flagtest})},1
  769. .else
  770. while_WHILE_ENDWHILE {.mid(::_AND_POS_copy+1, .tcount({flagtest})-::_AND_POS_copy-1,{flagtest})},,1
  771. .endif
  772. .exitmacro
  773. .endif
  774.  
  775. process_expression_FLAGS {flagtest}, ::_WHILE_ENDWHILE__flagnum, ::_WHILE_ENDWHILE__flagset
  776.  
  777. ; process special case of unsigned Greater or lessORequal
  778.  
  779. .if (.not .blank(leftsideOR)) .or ( ::_LONG_JUMP_ .and .blank(recursive))
  780. codeout .ident (.sprintf("FLAG_%01X_%01X", ::_WHILE_ENDWHILE__flagset, ::_WHILE_ENDWHILE__flagnum )), .ident ( .sprintf ("%s%04X", "_WHILE_ENDWHILE_CODE_BLOCK_START", ::_WHILE_ENDWHILE__WHILE_label))
  781. .else
  782. ::_WHILE_ENDWHILE__flagset .set .not ::_WHILE_ENDWHILE__flagset
  783. .if (.not .blank(leftsideAND)) .and ::_LONG_JUMP_ ; If Leftside and and long jump on
  784. codeout .ident (.sprintf("FLAG_%01X_%01X", ::_WHILE_ENDWHILE__flagset, ::_WHILE_ENDWHILE__flagnum )), .ident ( .sprintf ("%s%04X", "_WHILE_ENDWHILE_JMP_", ::_WHILE_ENDWHILE__WHILE_label))
  785. .else
  786. codeout .ident (.sprintf("FLAG_%01X_%01X", ::_WHILE_ENDWHILE__flagset, ::_WHILE_ENDWHILE__flagnum )), .ident ( .sprintf ("%s%04X", "_WHILE_ENDWHILE_EXIT_", ::_WHILE_ENDWHILE__WHILE_label))
  787. .endif
  788. .endif
  789.  
  790.  
  791. .if .blank (recursive) ; no more branches:
  792. .if ::_LONG_JUMP_
  793. .ident ( .sprintf ("%s%04X", "_WHILE_ENDWHILE_JMP_", ::_WHILE_ENDWHILE__WHILE_label)):
  794.  
  795. .if ::_BRANCH_LENGTH_CHECKING_
  796. .assert (.ident ( .sprintf ("%s%04X", "_WHILE_ENDWHILE_EXIT_", ::_WHILE_ENDWHILE__WHILE_label)) ) - (.ident ( .sprintf ("%s%04X", "_WHILE_ENDWHILE_CODE_BLOCK_START", ::_WHILE_ENDWHILE__WHILE_label))) > 127, warning, .sprintf("JMP in IF macro could have been reached with a branch at IF block %d",::_WHILE_ENDWHILE__WHILE_label)
  797. .endif
  798.  
  799. jmp .ident ( .sprintf ("%s%04X", "_WHILE_ENDWHILE_EXIT_", ::_WHILE_ENDWHILE__WHILE_label))
  800. .endif
  801.  
  802. .ident ( .sprintf ("%s%04X", "_WHILE_ENDWHILE_CODE_BLOCK_START", ::_WHILE_ENDWHILE__WHILE_label)):
  803. .endif
  804.  
  805.  
  806. .endmacro
  807.  
  808. .macro endwhile
  809.  
  810. .if (::_WHILE_ENDWHILE__SP - 1) < 0 ; if accessing the stack will result in a negative value
  811. .error "ENDWHILE without WHILE"
  812. .fatal ""
  813. .endif
  814.  
  815. pop "WHILE_ENDWHILE_STACK_",::_WHILE_ENDWHILE__END_label, ::_WHILE_ENDWHILE__SP
  816.  
  817. jmp .ident ( .sprintf ("%s%04X", "_WHILE_ENDWHILE_REPEAT_", ::_WHILE_ENDWHILE__END_label))
  818.  
  819. .ident ( .sprintf ("%s%04X", "_WHILE_ENDWHILE_EXIT_", ::_WHILE_ENDWHILE__END_label)):
  820.  
  821. .endmacro
  822.  
  823. .macro while flagtest, INV
  824.  
  825. .if .xmatch(.right(1,{flagtest}),do) ; Is a "while <cond> do" -endwhile
  826. while_WHILE_ENDWHILE {.mid (0,.tcount({flagtest})-1,{flagtest})} ,,,,,INV ; send without 'do' on the end
  827. .else
  828. while_DO_WHILE {flagtest},,,,,INV
  829. .endif
  830.  
  831. .endmacro
  832.  
  833.  
  834. .macro until flagtest
  835. .if .xmatch(.right(1,{flagtest}),do) ; Is a "while <cond> do" -endwhile
  836. .error "until (condition) do - enduntil not supported in this version"
  837. .fatal
  838. .endif
  839. while {flagtest},1 ; invert while test for repeat-until
  840. .endmacro
  841.  
  842. .macro enduntil
  843. endwhile
  844. .endmacro
  845.  
  846. .macro repeat
  847. do
  848. .endmacro
  849.  
  850.  
  851. .macro set_flag_test testflags
  852. ::__MACRO_FUNCTION_COMPLETE_ .set 1
  853. .define _CPU_FLAGS_ testflags
  854. .endmacro
  855.  
  856.  
  857.  
  858. ;*************************************************************************************************************************
  859.  
  860.  
  861. ; function for use with the above:
  862.  
  863. .scope _COMP_MACRO_
  864. INVLAID = 0
  865. GREATER = 1
  866. LESS = -1
  867. GREATEREQUAL = 2
  868. LESSEQUAL = -2
  869. EQUAL = 3
  870. NOTEQUAL = 4
  871.  
  872. REGX = 1
  873. REGY = 2
  874. REGA = 3
  875. .endscope
  876.  
  877. .macro find_operator exp, _pos_, _op_
  878.  
  879. findposition exp, =, _pos_
  880. .if _pos_
  881. _op_ .set _COMP_MACRO_::EQUAL
  882. .else
  883. findposition exp, <>, _pos_
  884. .if _pos_
  885. _op_ .set _COMP_MACRO_::NOTEQUAL
  886. .else
  887. findposition exp, >=, _pos_
  888. .if _pos_
  889. _op_ .set _COMP_MACRO_::GREATEREQUAL
  890. .else
  891. findposition exp, <=, _pos_
  892. .if _pos_
  893. _op_ .set _COMP_MACRO_::LESSEQUAL
  894. .else
  895. findposition exp, >, _pos_,(,)
  896. .if _pos_
  897. _op_ .set _COMP_MACRO_::GREATER
  898. .else
  899. findposition exp, <, _pos_,(,)
  900. .if _pos_
  901. _op_ .set _COMP_MACRO_::LESS
  902. .endif
  903. .endif
  904. .endif
  905. .endif
  906. .endif
  907. .endif
  908.  
  909. .endmacro
  910.  
  911.  
  912. .macro comp exp, withreg
  913.  
  914. ; if immediate or absolute/zero is used, this macro will use reg a to compare
  915.  
  916. _pos_ .set _COMP_MACRO_::INVLAID
  917. _op_ .set _COMP_MACRO_::INVLAID
  918.  
  919. find_operator exp, _pos_, _op_
  920.  
  921. .if (.not _pos_ ).or (.not _op_)
  922. .error "Unknow operator in comparison macro."
  923. .fatal ""
  924. .endif
  925.  
  926.  
  927. ; Check for register on the right side of the expression and adjust (pretend it is always on the left)
  928.  
  929. _left_ .set _COMP_MACRO_::INVLAID
  930. .if .xmatch(.mid((_pos_+1), .tcount({exp}) - _pos_ - 1 , {exp}),x) ; reg x
  931. _left_ .set _COMP_MACRO_::REGX
  932. .elseif .xmatch(.mid((_pos_+1), .tcount({exp}) - _pos_ - 1 , {exp}),y) ; reg y
  933. _left_ .set _COMP_MACRO_::REGY
  934. .elseif .xmatch(.mid((_pos_+1), .tcount({exp}) - _pos_ - 1 , {exp}),a) ; reg a
  935. _left_ .set _COMP_MACRO_::REGA
  936. .endif
  937.  
  938. .if .not (_left_ = _COMP_MACRO_::INVLAID) ; if we found a match on the right side, pretend it is on the left by switching _op_
  939. .if _op_ < 3
  940. _op_ .set _op_ * -1 ; don't switch equal or not equal
  941. .endif
  942. _right_pos_ .set 0
  943. _right_pos_count_ .set _pos_
  944. .else ; right side normal values:
  945. _right_pos_ .set _pos_ + 1
  946. _right_pos_count_ .set .tcount({exp}) - _pos_ - 1
  947. .endif
  948.  
  949.  
  950. .if _left_ = _COMP_MACRO_::INVLAID ; There could be a register on the left side of the expression- find it
  951. .if .xmatch(.mid(0,_pos_,{exp}),x) ; reg x
  952. _left_ .set _COMP_MACRO_::REGX
  953. .elseif .xmatch(.mid(0,_pos_,{exp}),y) ; reg y
  954. _left_ .set _COMP_MACRO_::REGY
  955. .elseif .xmatch(.mid(0,_pos_,{exp}),a) ; reg a
  956. _left_ .set _COMP_MACRO_::REGA
  957. .endif
  958. .endif
  959.  
  960. .if _left_ = _COMP_MACRO_::INVLAID ; no registers found, so first we will load a register
  961. .ifnblank withreg
  962. .if xmatch(withreg, x)
  963. ldx .mid(0,_pos_,{exp})
  964. _left_ .set _COMP_MACRO_::REGX
  965. .elseif xmatch(withreg, y)
  966. ldy .mid(0,_pos_,{exp})
  967. _left_ .set _COMP_MACRO_::REGY
  968. .else
  969. lda .mid(0,_pos_,{exp})
  970. _left_ .set _COMP_MACRO_::REGA
  971. .endif
  972. .else
  973. lda .mid(0,_pos_,{exp})
  974. _left_ .set _COMP_MACRO_::REGA
  975. .out "WARNING: Reg a value assigned in comparison macro."
  976. .endif
  977.  
  978.  
  979. .endif
  980.  
  981. .if _left_ = _COMP_MACRO_::REGX
  982. cpx .mid(_right_pos_,_right_pos_count_, {exp})
  983. .elseif _left_ = _COMP_MACRO_::REGY
  984. cpy .mid(_right_pos_,_right_pos_count_, {exp})
  985. .elseif _left_ = _COMP_MACRO_::REGA
  986. cmp .mid(_right_pos_,_right_pos_count_, {exp})
  987. .endif
  988.  
  989. .if _op_ = _COMP_MACRO_::GREATER
  990. set_flag_test G set
  991. .elseif _op_ = _COMP_MACRO_::LESS
  992. set_flag_test C clear
  993. .elseif _op_ = _COMP_MACRO_::EQUAL
  994. set_flag_test Z set
  995. .elseif _op_= _COMP_MACRO_::GREATEREQUAL
  996. set_flag_test C set
  997. .elseif _op_= _COMP_MACRO_::LESSEQUAL
  998. set_flag_test G clear
  999. .elseif _op_= _COMP_MACRO_::NOTEQUAL
  1000. set_flag_test Z clear
  1001. .endif
  1002.  
  1003. .endmacro
  1004.  
  1005. .macro scomp exp
  1006.  
  1007. ; code algorithm for signed comparision from : Beyond 8-bit Unsigned Comparisons by Bruce Clark , http://www.6502.org/tutorials/compare_beyond.html
  1008. .local jmp_over, jmp_over2
  1009.  
  1010. _pos_ .set _COMP_MACRO_::INVLAID
  1011. _op_ .set _COMP_MACRO_::INVLAID
  1012.  
  1013. find_operator exp, _pos_, _op_
  1014.  
  1015. .if (.not _pos_ ).or (_op_ = _COMP_MACRO_::INVLAID)
  1016. .error "Unknow operator in signed comparison macro."
  1017. .fatal ""
  1018. .endif
  1019.  
  1020. ; Check for register on the right side of the expression and adjust (pretend it is always on the left)
  1021.  
  1022. _left_ .set _COMP_MACRO_::INVLAID
  1023. .if .xmatch(.mid((_pos_+1), .tcount({exp}) - _pos_ - 1 , {exp}),x) ; reg x
  1024. _left_ .set _COMP_MACRO_::REGX
  1025. .elseif .xmatch(.mid((_pos_+1), .tcount({exp}) - _pos_ - 1 , {exp}),y) ; reg y
  1026. _left_ .set _COMP_MACRO_::REGY
  1027. .elseif .xmatch(.mid((_pos_+1), .tcount({exp}) - _pos_ - 1 , {exp}),a) ; reg a
  1028. _left_ .set _COMP_MACRO_::REGA
  1029. .endif
  1030.  
  1031. .if .not (_left_ = _COMP_MACRO_::INVLAID) ; if we found a match on the right side, pretend it is on the left by switching _op_
  1032. .if _op_ < 3
  1033. _op_ .set _op_ * -1 ; only switch if not ( equal or not equal)
  1034. .endif
  1035. _right_pos_ .set 0
  1036. _right_pos_count_ .set _pos_
  1037. .else ; right side normal values:
  1038. _right_pos_ .set _pos_ + 1
  1039. _right_pos_count_ .set .tcount({exp}) - _pos_ - 1
  1040. .endif
  1041.  
  1042. .if _left_ = _COMP_MACRO_::INVLAID ; There could be a register on the left side of the expression- find it
  1043. .if .xmatch(.mid(0,_pos_,{exp}),x) ; reg x
  1044. _left_ .set _COMP_MACRO_::REGX
  1045. .elseif .xmatch(.mid(0,_pos_,{exp}),y) ; reg y
  1046. _left_ .set _COMP_MACRO_::REGY
  1047. .elseif .xmatch(.mid(0,_pos_,{exp}),a) ; reg a
  1048. _left_ .set _COMP_MACRO_::REGA
  1049. .endif
  1050. .endif
  1051.  
  1052. .if _left_ = _COMP_MACRO_::INVLAID ; no registers found, so first we will load a register
  1053. lda .mid(0,_pos_,{exp})
  1054. _left_ .set _COMP_MACRO_::REGA
  1055. .out "WARNING: Reg a value assigned in signed comparison macro."
  1056. .endif
  1057.  
  1058. .if _op_ > 2 ; EQUAL or NOTEQUAL
  1059.  
  1060. .if _left_ = _COMP_MACRO_::REGX
  1061. cpx .mid(_right_pos_,_right_pos_count_, {exp})
  1062. .elseif _left_ = _COMP_MACRO_::REGY
  1063. cpy .mid(_right_pos_,_right_pos_count_, {exp})
  1064. .elseif _left_ = _COMP_MACRO_::REGA
  1065. cmp .mid(_right_pos_,_right_pos_count_, {exp})
  1066. .endif
  1067.  
  1068. .if _op_ = _COMP_MACRO_::EQUAL
  1069. set_flag_test Z set
  1070. .elseif _op_= _COMP_MACRO_::NOTEQUAL
  1071. set_flag_test Z clear
  1072. .endif
  1073.  
  1074. .else
  1075. .out "WARNING: Reg a value changed in signed comparison macro."
  1076.  
  1077. .if _left_ = _COMP_MACRO_::REGX
  1078. txa
  1079. .elseif _left_ = _COMP_MACRO_::REGY
  1080. tya
  1081. .endif
  1082.  
  1083. .if (_op_ = _COMP_MACRO_::LESS) .or (_op_ = _COMP_MACRO_::GREATEREQUAL) ; less or greaterorequal
  1084. sec ; prepare carry for SBC
  1085. sbc .mid(_right_pos_,_right_pos_count_, {exp}) ; A-NUM
  1086. bvc jmp_over ; if V is 0, N eor V = N, otherwise N eor V = N eor 1
  1087. eor #$80 ; A = A eor $80, and N = N eor 1
  1088. jmp_over:
  1089. ; If the N flag is 1, then A (signed) < NUM (signed) and BMI will branch
  1090. ; If the N flag is 0, then A (signed) >= NUM (signed) and BPL will branch
  1091. .if _op_ = _COMP_MACRO_::LESS
  1092. set_flag_test N set
  1093. .elseif _op_= _COMP_MACRO_::GREATEREQUAL
  1094. set_flag_test N clear
  1095. .endif
  1096. .endif
  1097.  
  1098. .if (_op_ = _COMP_MACRO_::GREATER) .or (_op_ = _COMP_MACRO_::LESSEQUAL)
  1099. clc ; Note: CLC, not SEC
  1100. sbc .mid(_right_pos_,_right_pos_count_, {exp})
  1101. bvc jmp_over2
  1102. eor #$80
  1103. jmp_over2:
  1104. ; If the N flag is 1, then A (signed) <= NUM (signed) and BMI will branch
  1105. ; If the N flag is 0, then A (signed) > NUM (signed) and BPL will branch
  1106. .if _op_ = _COMP_MACRO_::GREATER
  1107. set_flag_test N clear
  1108. .elseif _op_= _COMP_MACRO_::LESSEQUAL
  1109. set_flag_test N set
  1110. .endif
  1111. .endif
  1112. .endif
  1113.  
  1114. .endmacro
  1115.  
  1116. ;*************************************************************************************************************************
  1117.  
  1118.  
  1119. .macro mb exp
  1120. _equalpos_ .set 1 ; first check at token 1
  1121. findposition exp, :=, _equalpos_
  1122. .if (_equalpos_ = 0)
  1123. .error "No assignment found in byte assignment macro."
  1124. .exitmacro
  1125. .endif
  1126.  
  1127. .if .xmatch(.mid((_equalpos_+1), .tcount({exp}) - _equalpos_ - 1 , {exp}),x) ; assign reg x
  1128. stx .mid(0,_equalpos_,{exp})
  1129. .elseif .xmatch(.mid((_equalpos_+1), .tcount({exp}) - _equalpos_ - 1 , {exp}),y) ; assign reg y
  1130. sty .mid(0,_equalpos_,{exp})
  1131. .elseif .xmatch(.mid((_equalpos_+1), .tcount({exp}) - _equalpos_ - 1 , {exp}),a) ; assign reg a
  1132. sta .mid(0,_equalpos_,{exp})
  1133. .else
  1134. lda .mid((_equalpos_+1), .tcount({exp}) - _equalpos_ - 1 , {exp})
  1135. sta .mid(0,_equalpos_,{exp})
  1136. .endif
  1137.  
  1138. .endmacro
  1139.  
  1140. .macro mw exp
  1141. _equalpos_ .set 1 ; first check at token 1 since there should be something on the left
  1142. findposition exp, :=, _equalpos_
  1143.  
  1144. .if (_equalpos_ = 0)
  1145. .error "No assignment found in word assignment macro."
  1146. .exitmacro
  1147. .endif
  1148.  
  1149. .if .xmatch(.mid((_equalpos_+1),1, {exp}), #) ; immeidate mode
  1150.  
  1151. lda #<.mid((_equalpos_+2), .tcount({exp}) - _equalpos_ - 2 , {exp})
  1152. sta .mid(0,_equalpos_,{exp})
  1153.  
  1154. lda #>.mid((_equalpos_+2), .tcount({exp}) - _equalpos_ - 2 , {exp})
  1155.  
  1156. sta .mid(0,_equalpos_,{exp}) + 1
  1157.  
  1158. .else
  1159.  
  1160. lda .mid((_equalpos_+1), .tcount({exp}) - _equalpos_ - 1 , {exp})
  1161. sta .mid(0,_equalpos_,{exp})
  1162. lda .mid((_equalpos_+1), .tcount({exp}) - _equalpos_ - 1 , {exp})+1
  1163. sta .mid(0,_equalpos_,{exp}) + 1
  1164.  
  1165. .endif
  1166. .endmacro
  1167.  
  1168. ;*************************************************************************************************************************
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement