CodeM0lite.fth (62772B)
1 \ CodeM0lite.fth - ARM Cortex-M0 code file 2 3 (( 4 Copyright (c) 2009, 2010, 2011, 2014 5 MicroProcessor Engineering 6 133 Hill Lane 7 Southampton SO15 5AF 8 England 9 10 tel: +44 (0)23 8063 1441 11 fax: +44 (0)23 8033 9691 12 net: mpe@mpeforth.com 13 tech-support@mpeforth.com 14 web: www.mpeforth.com 15 16 From North America, our telephone and fax numbers are: 17 011 44 23 8063 1441 18 011 44 23 8033 9691 19 20 21 To do 22 ===== 23 Recode FILL to check for word start address, and copy words if possible. 24 This change may have a good speed/size trade-off. 25 26 Change history 27 ============== 28 20140107 SFP006 Corrected FM/MOD. 29 20110601 SFP005 Cortex M0/M1 conversion. 30 20100430 SFP004 Corrected !LCALL and (;CODE). 31 20100427 SFP003 Corrected ROLL. 32 20100108 MPE002 First release 33 20091209 SFP001 Started 34 )) 35 36 \ ========== 37 \ *! codem0m1lite 38 \ *T Cortex code definitions 39 \ ========== 40 \ *P The file *\i{Cortex/CodeM0lite.fth} contains primitives for 41 \ ** the standalone Lite Forth kernel. 42 43 \ ******** 44 \ *S Notes 45 \ ******** 46 \ *P Some words and code routines are marked in the documentation 47 \ ** as *\fo{INTERNAL}. These are factors used by other words and do 48 \ ** not have dictionary entries in the standalone Forth. They 49 \ ** are only accessible to users of the VFX Forth ARM Cross 50 \ ** Compiler. This also applies to definitions of the form: 51 \ *C n EQU <name> 52 \ *C PROC <name> 53 \ *C L: <name> 54 55 \ ***************** 56 \ *S Register usage 57 \ ***************** 58 \ *P For Cortex-M0/M1 the following register usage is the default: 59 \ *E r15 pc program counter 60 \ ** r14 link link register; bit0=1=Thumb, usually set 61 \ ** r13 rsp return stack pointer 62 \ ** r12 -- 63 \ ** r11 up user area pointer 64 \ ** r10 -- 65 \ ** r9 lp locals pointer 66 \ ** r8 -- 67 \ ** r7 tos cached top of stack 68 \ ** r6 psp data stack pointer 69 \ ** r0-r5 scratch 70 \ *P The VFX optimiser reserves R0 and R1 for internal operations. 71 \ ** *\fo{CODE} definitions must use R7 as TOS with NOS pointed 72 \ ** to by R6 as a full descending stack in ARM terminology. 73 \ ** R0..R5, R12 are free for use by *\fo{CODE} definitions and 74 \ ** need not be preserved or restored. You should assume that 75 \ ** any register can be affected by other words. 76 77 only forth definitions 78 decimal 79 80 81 \ *********************************** 82 \ *S Logical and relational operators 83 \ *********************************** 84 85 : AND \ x1 x2 -- x3 86 \ *G Perform a logical AND between the top two stack items and retain 87 \ ** the result in top of stack. 88 and ; 89 90 : OR \ x1 x2 -- x3 91 \ *G Perform a logical OR between the top two stack items and retain 92 \ ** the result in top of stack. 93 or ; 94 95 : XOR \ x1 x2 -- x3 96 \ *G Perform a logical XOR between the top two stack items and retain 97 \ ** the result in top of stack. 98 xor ; 99 100 : INVERT \ x -- x' 101 \ *G Perform a bitwise inversion. 102 invert ; 103 104 : 0= \ x -- flag 105 \ *G Compare the top stack item with 0 and return TRUE if equals. 106 0= ; 107 108 : 0<> \ x -- flag 109 \ *G Compare the top stack item with 0 and return TRUE if not-equal. 110 0<> ; 111 112 : 0< \ x -- flag 113 \ *G Return TRUE if the top of stack is less-than-zero. 114 0< ; 115 116 : 0> \ x -- flag 117 \ *G Return TRUE if the top of stack is greater-than-zero. 118 0> ; 119 120 : = \ x1 x2 -- flag 121 \ *G Return TRUE if the two topmost stack items are equal. 122 = ; 123 124 : <> \ x1 x2 -- flag 125 \ *G Return TRUE if the two topmost stack items are different. 126 <> ; 127 128 : < \ n1 n2 -- flag 129 \ *G Return TRUE if n1 is less than n2. 130 < ; 131 132 : > \ n1 n2 -- flag 133 \ *G Return TRUE if n1 is greater than n2. 134 > ; 135 136 : <= \ n1 n2 -- flag 137 \ *G Return TRUE if n1 is less than or equal to n2. 138 <= ; 139 140 : >= \ x1 x2 -- flag 141 \ *G Return TRUE if n1 is greater than or equal to n2. 142 >= ; 143 144 : U> \ u2 u2 -- flag 145 \ *G An UNSIGNED version of >. 146 u> ; 147 148 : U< \ u1 u2 -- flag 149 \ *G An UNSIGNED version of <. 150 u< ; 151 152 : D0< \ d -- flag 153 \ *G Returns true if signed double d is less than zero. 154 nip 0< ; 155 156 : D0= \ xd -- flag 157 \ *G Returns true if xd is 0. 158 or 0= ; 159 160 CODE D= \ xd1 xd2 -- flag 161 \ *G Return TRUE if the two double numbers are equal. 162 ldmia psp ! { r0-r2 } \ r0=d2 low, r1=d1 high, r2=d1 low 163 mov .s r3, tos \ r3=d2h 164 mov .s tos, # 0 \ assume false 165 sub .s r0, r0, r2 \ d2l - d1l 166 sbc .s r3, r3, r1 \ d2h - d1h 167 orr .s r0, r0, tos 168 eq, if, 169 mvn .s tos, tos \ true 170 endif, 171 next, 172 END-CODE 173 174 (( 175 CODE D< \ d1 d2 -- flag 176 \ *G Return TRUE if the double number d1 is (signed) less than the 177 \ ** double number d2. 178 ldmia psp ! { r0-r2 } \ r0=d2 low, r1=d1 high, r2=d1 low 179 mov .s r3, tos \ r3=d2h 180 mov .s tos, # 0 \ assume false 181 sub .s r2, r2, r0 \ d1l - d2l 182 sbc .s r1, r1, r3 \ d1h - d2h 183 lt, if, 184 mvn .s tos, tos \ true 185 endif, 186 next, 187 END-CODE 188 189 : D> \ d1 d2 -- flag 190 \ *G Return TRUE if the double number d1 is (signed) greater than the 191 \ ** double number d2. 192 2swap d< ; 193 )) 194 195 (( 196 CODE DU< \ ud1 ud2 -- flag 197 \ *G Returns true if ud1 (unsigned double) is less than ud2. 198 ldmia psp ! { r0-r2 } \ r0=d2 low, r1=d1 high, r2=d1 low 199 mov .s r3, tos \ r3=d2h 200 mov .s tos, # 0 \ assume false 201 sub .s r2, r2, r0 \ d1l - d2l 202 sbc .s r1, r1, r3 \ d1h - d2h 203 cc, if, 204 mvn .s tos, tos 205 endif, 206 next, 207 END-CODE 208 209 : DU> \ ud1 ud2 -- flag 210 \ *G Returns true if ud1 (unsigned double) is greater than ud2. 211 2swap du< ; 212 )) 213 (( 214 : DMAX \ d1 d2 -- d3 ; d3=max of d1/d2 215 \ *G Return the maximum double number from the two supplied. 216 2over 2over d< 217 if 2swap then 218 2drop 219 ; 220 221 : DMIN \ d1 d2 -- d3 ; d3=min of d1/d2 222 \ *G Return the minimum double number from the two supplied. 223 2over 2over d> 224 if 2swap then 225 2drop 226 ; 227 )) 228 229 CODE MIN \ n1 n2 -- n1|n2 230 \ *G Given two data stack items preserve only the smaller. 231 ldmia psp, ! { r0 } 232 cmp tos, r0 233 gt, if, 234 mov tos, r0 235 endif, 236 next, 237 END-CODE 238 239 CODE MAX \ n1 n2 -- n1|n2 240 \ *G Given two data stack items preserve only the larger. 241 ldmia psp, ! { r0 } 242 cmp tos, r0 243 lt, if, 244 mov tos, r0 245 endif, 246 next, 247 END-CODE 248 249 (( 250 CODE WITHIN? \ n1 n2 n3 -- flag 251 \ *G Return TRUE if N1 is within the range N2..N3. 252 \ ** This word uses signed arithmetic. 253 ldmia psp ! { r0, r1 } 254 mov .s r2, # 0 255 mov .s r3, # 0 256 cmp r1, r0 257 ge, if, 258 mov .s r2, # 1 259 endif, 260 cmp r1, tos 261 le, if, 262 mov .s r3, # 1 263 endif, 264 mov .s tos, # 0 \ flag=0 265 tst r2, r3 266 ne, if, 267 mvn .s tos, tos \ flag=-1 268 endif, 269 next, 270 END-CODE 271 )) 272 273 : within \ n1|u1 n2|u2 n3|u3 -- flag 274 \ *G Return true for *\i{n2 <= n1 < n3}. 275 \ ** This word uses unsigned arithmetic, so that signed compares are 276 \ ** treated as existing on a number circle. 277 over - -rot \ -- n3-n2 n1 n2 278 - \ -- n3-n2 n1-n2 279 swap u< \ (n1-n2)-(n3-n2), cy -> -1, ncy -> 0 280 ; 281 282 code lshift \ x1 u -- x2 283 \ *G Logically shift X1 by U bits left. 284 mov r0, tos 285 ldmia psp ! { tos } 286 lsl .s tos, r0 287 next, 288 end-code 289 290 code rshift \ x1 u -- x2 291 \ *G Logically shift X1 by U bits right. 292 mov r0, tos 293 ldmia psp ! { tos } 294 lsr .s tos, r0 295 next, 296 end-code 297 298 code arshift \ x1 u -- x2 299 \ *G Arithmetic shift right X1 by U bits. 300 mov r0, tos 301 ldmia psp ! { tos } 302 asr .s tos, r0 303 next, 304 end-code 305 306 307 \ *************** 308 \ *S Control flow 309 \ *************** 310 311 CODE EXECUTE \ xt -- 312 \ *G Execute the code described by the XT. This is a Forth equivalent 313 \ ** of an assembler JSR/CALL instruction. 314 mov .s r0, # 1 315 orr .s r0, tos \ move CFA, setting Thumb bit 316 ldmia psp ! { tos } 317 bx r0 \ execute CFA - link contains ret addr of execute 318 END-CODE 319 320 internal 321 322 CODE BRANCH \ -- 323 \ +G The run time action of unconditional branches compiled on the target. 324 \ +* The branch target address is in-line and must have the T bit set. 325 \ +* INTERNAL. 326 l: takebranch 327 mov .s r1, # 1 328 mov r0, link 329 bic .s r0, r1 330 ldr r2, [ r0 ] \ get address and branch 331 bx r2 332 END-CODE 333 334 CODE ?BRANCH \ n -- 335 \ +G The run time action of conditional branches compiled on the target. 336 \ +* The branch target address is in-line and must have the T bit set. 337 \ +* INTERNAL. 338 mov .s r1, tos 339 ldmia psp ! { tos } 340 b .eq takebranch 341 l: skipbranch 342 mov r0, link 343 add .s r0, # 4 344 bx r0 345 END-CODE 346 347 CODE (OF) \ n1 n2 -- n1|-- 348 \ +G The run time action of OF compiled on the target. 349 \ +* The branch target address is in-line and must have the T bit set. 350 \ +* INTERNAL. 351 ldmia psp ! { r0 } \ get n1 352 cmp r0, tos \ compare n1 and n2 353 b .ne takebranch 354 ldmia psp ! { tos } \ equal so get new tos 355 b skipbranch 356 END-CODE 357 358 CODE (LOOP) \ -- 359 \ +G The run time action of *\fo{LOOP} compiled on the target. 360 \ +* The branch target address is in-line and must have the T bit set. 361 \ +* INTERNAL. 362 ldr r1, [ rsp ] \ fetch index 363 add .s r1, r1, # 1 \ increment index 364 str r1, [ rsp ] \ store new index] 365 b .vc takebranch 366 add rsp, rsp, # $0C \ drop 3 items from return stack 367 b skipbranch 368 END-CODE 369 370 CODE (+LOOP) \ n -- 371 \ +G The run time action of *\fo{+LOOP} compiled on the target. 372 \ +* The branch target address is in-line and must have the T bit set. 373 \ +* INTERNAL. 374 ldr r1, [ rsp ] \ fetch index 375 add .s r1, r1, tos \ increment index by n 376 str r1, [ rsp ] \ store new index 377 ldmia psp ! { tos } \ update tos 378 b .vc takebranch 379 add rsp, rsp, # $0C \ drop 3 items from return stack 380 b skipbranch 381 END-CODE 382 383 CODE (DO) \ limit index -- 384 \ +G The run time action of *\fo{DO} compiled on the target. 385 \ +* The branch target address is in-line and must have the T bit set. 386 \ +* INTERNAL. 387 ldmia psp ! { r1 } \ get limit 388 L: PDO 389 mov .s r4, # 1 390 lsl .s r4, r4, # #31 \ r4 := $8000:0000 391 mov r3, link 392 sub .s r3, r3, # 1 \ clear T bit 393 ldr r2, [ r3 ] \ get LEAVE address, compiler sets T bit 394 add .s r1, r1, r4 \ limit+$8000:0000 395 sub .s r0, tos, r1 \ index-limit-$8000:0000 396 397 push { r0, r1, r2 } \ push LEAVE then limit, then index on ret. stack 398 ldmia psp ! { tos } \ update tos 399 b skipbranch 400 END-CODE 401 402 CODE (?DO) \ limit index -- 403 \ +G The run time action of *\fo{?DO} compiled on the target. 404 \ +* The branch target address is in-line and must have the T bit set. 405 \ +* INTERNAL. 406 ldmia psp ! { r1 } \ get limit 407 cmp r1, tos \ check not equal 408 b .ne pdo \ take DO ? 409 ldmia psp ! { tos } \ update tos 410 b takebranch 411 END-CODE 412 413 external 414 415 CODE LEAVE \ -- 416 \ *G Remove the current *\fo{DO..LOOP} parameters and jump to the 417 \ ** end of the *\fo{DO..LOOP} structure. 418 add rsp, rsp, # 8 \ remove limit, index 419 pop { pc } \ jump to exit address, Thumb bit set by DO/?DO 420 END-CODE 421 422 CODE ?LEAVE \ flag -- 423 \ *G If flag is non-zero, remove the current *\fo{DO..LOOP} parameters 424 \ ** and jump to the end of the *\fo{DO..LOOP} structure. 425 mov .s tos, tos \ set flags 426 ldmia psp ! { tos } \ update tos 427 eq, if, 428 bx r14 \ flag false so continue 429 endif, 430 add rsp, rsp, # 8 \ flag true so remove limit, index - if old TOS<>0 431 pop { pc } \ flag true so jump to exit address 432 END-CODE 433 434 CODE I \ -- n 435 \ *G Return the current index of the inner-most DO..LOOP. 436 sub .s psp, psp, # 4 437 str tos, [ psp ] 438 ldr tos, [ rsp, # 0 ] 439 ldr r0, [ rsp, # 4 ] 440 add .s tos, tos, r0 441 next, 442 END-CODE 443 444 CODE J \ -- n 445 \ *G Return the current index of the second DO..LOOP. 446 sub .s psp, psp, # 4 447 str tos, [ psp ] 448 ldr tos, [ rsp, # $0C ] \ index 449 ldr r0, [ rsp, # $010 ] 450 add .s tos, tos, r0 451 next, 452 END-CODE 453 454 CODE UNLOOP \ -- ; R: loop-sys -- 455 \ *G Remove the DO..LOOP control parameters from the return stack. 456 add rsp, rsp, # $0C \ remove loop parameters from return stack 457 next, \ jump to return address 458 END-CODE 459 460 461 \ ******************* 462 \ *S Basic arithmetic 463 \ ******************* 464 465 : S>D \ n -- d 466 \ *G Convert a single number to a double one. 467 s>d ; 468 469 (( 470 : D>S \ d -- n 471 \ *G Convert a double number to a single. 472 drop ; 473 )) 474 475 : NOOP ; \ -- 476 \ *G A NOOP, null instruction. 477 478 CODE M+ \ d1|ud1 n -- d2|ud2 479 \ *G Add double d1 to sign extended single n to form double d2. 480 ldmia psp ! { r0 r1 } \ r0 = d1 high, r1 = d1 low 481 asr .s r2, tos, # 31 \ d2h = sex(n) 482 add .s r1, r1, tos \ d2l = d1l + n 483 adc .s r0, r0, r2 \ d2h = d1h + d2h + c 484 mov tos, r0 485 sub .s psp, psp, # 4 486 str r1, [ psp ] 487 next, 488 END-CODE 489 490 : 1+ \ n1|u1 -- n2|u2 491 \ *G Add one to top-of stack. 492 1 + ; 493 494 : 1- \ n1|u1 -- n2|u2 495 \ *G Subtract one from top-of stack. 496 1 - ; 497 498 (( 499 : 2+ \ n1|u1 -- n2|u2 500 \ *G Add two to top-of stack. 501 2 + ; 502 503 : 4+ \ n1|u1 -- n2|u2 504 \ *G Add four to top-of stack. 505 4 + ; 506 507 : 2- \ n1|u1 -- n2|u2 508 \ *G Subtract two from top-of stack. 509 2 - ; 510 511 : 4- \ n1|u1 -- n2|u2 512 \ *G Subtract four from top-of stack. 513 4 - ; 514 515 : 2* \ x1 -- x2 516 \ *G Multiply top of stack by 2. 517 1 lshift ; 518 519 : 4* \ x1 -- x2 520 \ *G Multiply top of stack by 4. 521 2 lshift ; 522 523 : 2/ \ x1 -- x2 524 \ *G Signed divide top of stack by 2. 525 1 arshift ; 526 527 : U2/ \ x1 -- x2 528 \ *G Unsigned divide top of stack by 2. 529 1 rshift ; 530 531 : 4/ \ x1 -- x2 532 \ *G Signed divide top of stack by 4. 533 2 arshift ; 534 535 : U4/ \ x1 -- x2 536 \ *G Unsigned divide top of stack by 4. 537 2 rshift ; 538 )) 539 540 CODE + \ n1|u1 n2|u2 -- n3|u3 541 \ *G Add two single precision integer numbers. 542 ldr r0, [ psp ] 543 add .s psp, psp, # 4 544 add .s tos, tos, r0 545 next, 546 END-CODE 547 548 CODE - \ n1|u1 n2|u2 -- n3|u3 549 \ *G Subtract two integers. N3|u3=n1|u1-n2|u2. 550 ldr r0, [ psp ] 551 add .s psp, psp, # 4 552 sub .s tos, r0, tos 553 next, 554 END-CODE 555 556 CODE NEGATE \ n1 -- n2 557 \ *G Negate an integer. 558 rsb .s tos, tos, # 0 559 next, 560 END-CODE 561 562 CODE D+ \ d1 d2 -- d3 563 \ *G Add two double precision integers. 564 ldmia psp ! { r0-r2 } \ r0 = d2 low, r1 = d1 high, r2 = d1 low 565 add .s r0, r0, r2 \ d3l = d2l + d1l 566 adc .s tos, tos, r1 \ d3h = d2h + d1h 567 sub .s psp, psp, # 4 568 str r0, [ psp ] \ push d3l 569 next, 570 END-CODE 571 572 CODE D- \ d1 d2 -- d3 573 \ *G Subtract two double precision integers. D3=D1-D2. 574 ldmia psp ! { r0-r2 } \ r0 = d2 low, r1 = d1 high, r2 = d1 low 575 sub .s r0, r2, r0 \ d3l = d2l - d1l 576 sbc .s r1, r1, tos \ d3h = d2h - d1h 577 mov tos, r1 578 sub .s psp, psp, # 4 579 str r0, [ psp ] \ push d3l 580 next, 581 END-CODE 582 583 CODE DNEGATE \ d1 -- -d1 584 \ *G Negate a double number. 585 L: DNEG1 586 ldr r0, [ psp ] \ r0 = d1l, tos = d1h 587 mov .s r1, # 0 588 rsb .s r0, r0, # 0 \ negate low 589 sbc .s r1, r1, tos \ negate high carrying through 590 mov tos, r1 591 str r0, [ psp ] 592 next, 593 END-CODE 594 595 CODE ?NEGATE \ n1 flag -- n1|n2 596 \ *G If flag is negative, then negate n1. 597 mov .s tos, tos \ set processor flags 598 ldmia psp ! { tos } 599 mi, if, 600 rsb .s tos, tos, # 0 \ negate n1 if flag=true 601 endif, 602 next, 603 END-CODE 604 605 (( 606 CODE ?DNEGATE \ d1 flag -- d1|d2 607 \ *G If flag is negative, then negate d1. 608 mov .s tos, tos \ set processor flags 609 ldmia psp ! { tos } \ discard flag 610 b .mi DNEG1 611 next, 612 END-CODE 613 )) 614 615 CODE ABS \ n -- u 616 \ *G If n is negative, return its positive equivalent (absolute value). 617 cmp tos, # 0 618 mi, if, 619 rsb .s tos, tos, # 0 620 endif, 621 next, 622 END-CODE 623 624 CODE DABS \ d -- ud 625 \ *G If d is negative, return its positive equivalent (absolute value). 626 mov .s tos, tos \ set processor flags 627 b .mi DNEG1 \ negate d if flag=true 628 bx r14 \ restore link and exit 629 END-CODE 630 631 CODE D2* \ xd1 -- xd2 632 \ *G Multiply the given double number by two. 633 ldr r0, [ psp ] \ low portion 634 add .s r0, r0, r0 635 adc .s tos, tos, tos 636 str r0, [ psp ] 637 next, 638 END-CODE 639 640 CODE D2/ \ xd1 -- xd2 641 \ *G Divide the given double number by two. 642 ldr r0, [ psp ] \ low portion 643 asr .s r0, r0, # 1 \ low portion shift right 644 asr .s tos, tos, # 1 \ high portion shift right 645 sbc .s r1, r1, r1 \ r1 -> 0/-1 646 lsl .s r1, r1, # #31 \ r1 -> 8/$8000:0000 647 orr .s r0, r0, r1 \ apply to low portion 648 str r0, [ psp ] 649 next, 650 END-CODE 651 652 653 \ ***************** 654 \ *S Multiplication 655 \ ***************** 656 657 : * \ n1 n2 -- n3 658 \ *G Standard signed multiply. N3 = n1 * n2. 659 * ; 660 661 get-tos 7 = get-psp 6 = and [if] 662 code UM* \ u1 u2 -- ud 663 \ *G Perform unsigned-multiply between two numbers and return double 664 \ ** result. 665 mov r0, tos \ r0=u2 666 ldr r1, [ psp, # 0 ] \ r1=u1 667 push { psp } 668 \ build result in r7:r6 669 \ build temps in r5:r4:r3:r2 670 lsl .s r2, r1 # #16 671 lsr .s r2, r2 # #16 \ r2=u1l 672 lsr .s r3, r1 # #16 \ r3=u1h 673 lsl .s r4, r0 # 16 674 lsr .s r4, r4 # 16 \ r4=u2l 675 lsr .s r5, r0 # 16 \ r5=u2h 676 \ scratch = r0, r1 677 \ multiply low portions 678 mov r6, r2 679 mul .s r6, r4 \ r6=u1l*u2l 680 \ multiply high portions 681 mov r7, r3 682 mul .s r7, r5 \ r7=u1h*u2h 683 \ multiply and accumulate u1h * u2l 684 mov r0, r3 685 mul .s r0, r4 \ r0=u1h*u2l=xxxx.yyyy 686 lsr .s r1, r0 # #16 \ r1=r0h 687 lsl .s r0, r0 # #16 \ r1:r0=0000.xxxx:yyyy.0000 688 add .s r6, r6, r0 \ add into result 689 adc .s r7, r7, r1 690 \ multiply and accumulate u2h * u1l 691 mov r0, r5 692 mul .s r0, r2 \ r0=u2h*u1l=xxxx.yyyy 693 lsr .s r1, r0 # #16 \ r1=r0h 694 lsl .s r0, r0 # #16 \ r1:r0=0000.xxxx:yyyy.0000 695 add .s r6, r6, r0 \ add into result 696 adc .s r7, r7, r1 697 698 mov r5, r6 699 pop { psp } 700 str r5, [ psp, # 0 ] 701 702 next, 703 end-code 704 [then] 705 706 : m* \ n1 n2 -- d 707 \ *G Signed multiply yielding double result. 708 2dup xor >r \ sign of result 709 abs swap abs swap um* \ process unsigned 710 r> 0< \ apply sign of result 711 if dnegate then 712 ; 713 714 715 \ *********** 716 \ *S Division 717 \ *********** 718 \ *P ARM Cortex-M0 provides no division instructions. 719 720 code um/mod \ ud1 u2 -- urem uquot 721 \ *G Full 64 by 32 unsigned division subroutine. 722 ldmia psp ! { r0 } \ dividend high 723 ldr r1, [ psp ] \ dividend low 724 mov .s r4, # #32 \ loop counter 725 mov .s r2, # 0 \ always 0 726 begin, 727 \ udiv64_step 728 add .s r1, r1, r1 \ 64 bit shift of dividend 729 adc .s r0, r0, r0 730 mov r3, r2 \ must not affect flags 731 adc .s r3, r3, r2 \ preserve dividend bit 63, R2=0 732 sub .s r0, r0, tos \ trial subtraction, carry set (no borrow) if ok 733 adc .s r3, r3, r3 \ success if bit 0 or 1 set 734 ne, if, 735 add .s r1, r1, # 1 \ succeeded, update quotient 736 else, 737 add .s r0, r0, tos \ failed, undo subtraction 738 endif, 739 sub .s r4, r4, # 1 740 eq, until, 741 mov tos, r1 \ move quotient 742 str r0, [ psp ] \ move remainder 743 next, 744 end-code 745 746 : fm/mod \ d n -- rem quot ; floored division 747 \ *G Perform a signed division of double number *\i{d} by single 748 \ ** number *\i{n} and return remainder and quotient using floored 749 \ ** division. See the ANS Forth specification for more details 750 \ ** of floored division. 751 dup >r \ sign of divisor 752 2dup xor >r \ sign of quotient 753 >r \ divisor 754 dabs r@ abs um/mod $7FFF:FFFF and \ unsigned divide, truncate overflow ; SFP006 755 swap r> 0< ?negate swap \ remainder takes sign of divisor 756 r> 0< if \ if quotient negative 757 negate \ apply sign of quotient 758 over if \ if remainder non-zero 759 1- \ decrement quotient 760 r@ rot - swap \ rem := divisor - rem 761 endif 762 endif 763 r> drop 764 ; 765 766 : sm/rem \ d n -- rem quot ; symmetric division 767 \ *G Perform a signed division of double number *\i{d} by single 768 \ ** number *\i{n} and return remainder and quotient using 769 \ ** symmetric (normal) division. 770 over >r \ save sign of dividend 771 >r dabs r@ abs um/mod \ unsigned division 772 r> r@ xor ?negate \ correct sign of quot. 773 swap r> ?negate swap \ correct sign of rem. 774 ; 775 776 : /mod \ n1 n2 -- rem quot 777 \ *G Signed symmetric division of N1 by N2 single-precision 778 \ ** returning remainder and quotient. Symmetric. 779 >r s>d r> sm/rem 780 ; 781 782 : / \ n1 n2 -- n3 783 \ *G Standard signed division operator. n3 = n1/n2. Symmetric. 784 >r s>d r> sm/rem nip 785 ; 786 787 : u/ \ u1 u2 -- u3 788 \ *G Unsigned division operator. u3 = u1/u2. 789 0 swap um/mod nip 790 ; 791 792 : MOD \ n1 n2 -- n3 793 \ *G Return remainder of division of N1 by N2. n3 = n1 mod n2. 794 /mod drop ; 795 796 : M/ \ d n1 -- n2 797 \ *G Signed divide of a double by a single integer. 798 sm/rem nip ; 799 800 : MU/MOD \ d n -- rem d#quot 801 \ *G Perform an unsigned divide of a double by a single, returning 802 \ ** a single remainder and a double quotient. 803 >r 0 r@ um/mod r> swap >r um/mod r> ; 804 805 806 \ ********************************* 807 \ *S Scaling - multiply then divide 808 \ ********************************* 809 \ *P These operations perform a multiply followed by a divide. 810 \ ** The intermediate result is in an extended form. The point 811 \ ** of these operations is to avoid loss of precision. 812 813 : */MOD \ n1 n2 n3 -- n4 n4 814 \ *G Multiply n1 by n2 to give a double precision result, and then 815 \ ** divide it by n3 returning the remainder and quotient. 816 >r m* r> sm/rem ; 817 818 : */ \ n1 n2 n3 -- n4 819 \ *G Multiply n1 by n2 to give a double precision result, and then 820 \ ** divide it by n3 returning the quotient. 821 */mod nip ; 822 823 (( 824 : m*/ \ d1 n2 n3 -- dquot 825 \ *G The result dquot=(d1*n2)/n3. The intermediate value d1*n2 826 \ ** is triple-precision to avoid loss of precision. In an ANS 827 \ ** Forth standard program n3 can only be a positive signed 828 \ ** number and a negative value for n3 generates an ambiguous 829 \ ** condition, which may cause an error on some implementations, 830 \ ** but not in this one. 831 s>d >r abs >r \ -- d1 n2 ; R: -- sign(n3) |n3| 832 s>d >r abs \ -- d1 |n2| ; R: -- sign(n3) |n3| sign(n2) 833 -rot \ -- |n2| d1 ; R: -- sign(n3) |n3| sign(n2) 834 s>d r> xor \ -- |n2| d1 sign(d1*n2) ; R: -- sign(n3) |n3| 835 r> swap >r >r \ -- |n2| d1 ; R: -- sign(n3) sign(d1*n2) |n3| 836 dabs rot \ -- |d1| |n2| ; R: -- sign(n3) sign(d1*n2) |n3| 837 tuck um* 2swap um* \ -- d1h*n2 d1l*n2 ; R: -- sign(n3) sign(d1*n2) |n3| 838 swap >r 0 d+ r> -rot \ -- t ; R: -- sign (n3) sign(d1*n2) |n3| 839 r@ um/mod -rot r> um/mod nip swap \ -- d ; R: -- sign(n3) sign(d1*n2) 840 r> r> xor IF dnegate THEN \ -- d 841 ; 842 )) 843 844 \ ********************* 845 \ *S Stack manipulation 846 \ ********************* 847 848 : NIP \ x1 x2 -- x2 849 \ *G Dispose of the second item on the data stack. 850 nip ; 851 852 : TUCK \ x1 x2 -- x2 x1 x2 853 \ *G Insert a copy of the top data stack item underneath the current 854 \ ** second item. 855 tuck ; 856 857 : PICK \ xu .. x0 u -- xu .. x0 xu 858 \ *G Get a copy of the Nth data stack item and place on top of stack. 859 \ ** 0 PICK is equivalent to DUP. 860 pick ; 861 862 CODE ROLL \ xu xu-1 .. x0 u -- xu-1 .. x0 xu 863 \ *G Rotate the order of the top N stack items by one place such that 864 \ ** the current top of stack becomes the second item and the Nth item 865 \ ** becomes TOS. See also *\fo{ROT}. 866 lsl .s r0, tos # 2 \ r0=position of xu in bytes 867 cmp r0, # 0 \ u is valid? 868 le, if, 869 ldmia psp ! { tos } \ no - get new tos 870 bx link \ no - exit 871 endif, 872 ldr tos, [ psp ++ r0 ] \ put xu in tos 873 L: ROLL1 874 sub .s r1, r0, # 4 875 ldr r2, [ psp ++ r1 ] 876 str r2, [ psp ++ r0 ] 877 mov .s r0, r1 878 b .ne ROLL1 879 add .s psp, psp, # 4 880 next, 881 END-CODE 882 883 : ROT \ x1 x2 x3 -- x2 x3 x1 884 \ *G ROTate the positions of the top three stack items such that the 885 \ ** current top of stack becomes the second item. 886 rot ; 887 888 : -ROT \ x1 x2 x3 -- x3 x1 x2 889 \ *G The inverse of *\fo{ROT}. 890 -rot ; 891 892 CODE >R \ x -- ; R: -- x 893 \ *G Push the current top item of the data stack onto the top of the 894 \ ** return stack. 895 push { tos } 896 ldmia psp ! { tos } 897 next, 898 END-CODE 899 900 CODE R> \ -- x ; R: x -- 901 \ *G Pop the top item from the return stack to the data stack. 902 sub .s psp, psp, # 4 903 str tos, [ psp ] 904 pop { tos } 905 next, 906 END-CODE 907 908 CODE R@ \ -- x ; R: x -- x 909 \ *G Copy the top item from the return stack to the data stack. 910 sub .s psp, psp, # 4 911 str tos, [ psp ] 912 ldr tos, [ rsp ] 913 next, 914 END-CODE 915 916 CODE 2>R \ x1 x2 -- ; R: -- x1 x2 917 \ *G Transfer the two top data stack items to the return stack. 918 ldmia psp ! { r0, r1 } \ r0=x1, r1=new tos 919 push { r0 } \ push x1 920 push { tos } \ push x2 921 mov .s tos, r1 \ new tos=r1 922 next, 923 END-CODE 924 925 CODE 2R> \ -- x1 x2 ; R: x1 x2 -- 926 \ *G Transfer the top two return stack items to the data stack. 927 pop { r0 r1 } \ r0=x2, r1=x1 928 sub .s psp, psp, # 8 929 str r1 [ psp, # 0 ] 930 str tos [ psp, # 4 ] 931 mov tos, r0 \ tos=x2 932 next, 933 END-CODE 934 935 CODE 2R@ \ -- x1 x2 ; R: x1 x2 -- x1 x2 936 \ *G Copy the top two return stack items to the data stack. 937 ldr r0, [ rsp, # 0 ] \ r0=x2 938 ldr r1, [ rsp, # 4 ] \ r1=x1 939 sub .s psp, psp, # 8 940 str r1 [ psp, # 0 ] 941 str tos [ psp, # 4 ] 942 mov tos, r0 \ tos=x2 943 next, 944 END-CODE 945 946 : SWAP \ x1 x2 -- x2 x1 947 \ *G Exchange the top two data stack items. 948 swap ; 949 950 : DUP \ x -- x x 951 \ *G DUPlicate the top stack item. 952 dup ; 953 954 : OVER \ x1 x2 -- x1 x2 x1 955 \ *G Copy NOS to a new top-of-stack item. 956 over ; 957 958 : DROP \ x -- 959 \ *G Lose the top data stack item and promote NOS to TOS. 960 drop ; 961 962 : 2DROP \ x1 x2 -- ) 963 \ *G Discard the top two data stack items. 964 2drop ; 965 966 : 2SWAP \ x1 x2 x3 x4 -- x3 x4 x1 x2 967 \ *G Exchange the top two cell-pairs on the data stack. 968 2swap ; 969 970 (( 971 code 2ROT \ x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2 972 \ *G Perform the *\fo{ROT} operation on three cell-pairs. 973 ldmia psp ! { r0-r4 } \ tos=x6, r0=x5, r4=x1 974 sub .s psp, psp, # 5 cells \ restore stack depth 975 str r4, [ psp, # 0 cells ] \ x1 976 str tos [ psp, # 1 cells ] \ x6 977 str r0, [ psp, # 2 cells ] \ x5 978 str r1, [ psp, # 3 cells ] \ x4 979 str r2, [ psp, # 4 cells ] \ x3 980 mov tos, r3 \ x2 to tos 981 next, 982 END-CODE 983 )) 984 985 : 2DUP \ x1 x2 -- x1 x2 x1 x2 986 \ *G DUPlicate the top cell-pair on the data stack. 987 2dup ; 988 989 : 2OVER \ x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2 990 \ *G As *\fo{OVER} but works with cell-pairs rather than single-cell items. 991 2over ; 992 993 : ?DUP \ x -- | x 994 \ *G DUPlicate the top stack item only if it non-zero. 995 ?dup ; 996 997 CODE SP@ \ -- x 998 \ *G Get the current address value of the data-stack pointer. 999 sub .s psp, psp, # 4 1000 str tos, [ psp ] 1001 mov tos, psp 1002 next, 1003 END-CODE 1004 1005 CODE SP! \ x -- 1006 \ *G Set the current address value of the data-stack pointer. 1007 mov psp, tos 1008 ldmia psp ! { tos } 1009 next, 1010 END-CODE 1011 1012 CODE RP@ \ -- x 1013 \ *G Get the current address value of the return-stack pointer. 1014 sub .s psp, psp, # 4 1015 str tos, [ psp ] 1016 mov tos, rsp 1017 next, 1018 END-CODE 1019 1020 CODE RP! \ x -- 1021 \ *G Set the current address value of the return-stack pointer. 1022 mov rsp, tos 1023 ldmia psp ! { tos } 1024 next, 1025 END-CODE 1026 1027 (( 1028 CODE >RR \ x -- ; R: -- x 1029 \ *G Push the current top item of the data stack onto the top of the 1030 \ ** return stack as a return address 1031 mov .s r0, # 1 \ set the T bit 1032 orr .s tos, tos, r0 1033 push { tos } 1034 ldmia psp ! { tos } 1035 next, 1036 END-CODE 1037 1038 CODE RR> \ -- x ; R: x -- 1039 \ *G Pop the caller's return address from the return stack. 1040 sub .s psp, psp, # 4 1041 str tos, [ psp ] 1042 pop { tos } 1043 mov .s r0, # 1 \ clear the T bit 1044 bic .s tos, tos, r0 1045 next, 1046 END-CODE 1047 1048 CODE RR@ \ -- x ; R: x -- x 1049 \ *G Copy the top item from the return stack to the data stack. 1050 sub .s psp, psp, # 4 1051 str tos, [ psp ] 1052 ldr tos, [ rsp ] 1053 mov .s r0, # 1 \ clear the T bit 1054 bic .s tos, tos, r0 1055 next, 1056 END-CODE 1057 )) 1058 1059 1060 \ ****************************** 1061 \ *S String and memory operators 1062 \ ****************************** 1063 1064 : COUNT \ c-addr1 -- c-addr2' u 1065 \ *G Given the address of a counted string in memory this word will 1066 \ ** return the address of the first character and the length in 1067 \ ** characters of the string. 1068 count ; 1069 1070 : /STRING \ c-addr1 u1 n -- c-addr2 u2 1071 \ *G Modify a string address and length to remove the first N characters 1072 \ ** from the string. 1073 /string ; 1074 1075 CODE SKIP \ c-addr1 u1 char -- c-addr2 u2 1076 \ *G Modify the string description by skipping over leading occurrences of 1077 \ ** 'char'. 1078 ldmia psp ! { r0, r1 } \ tos=char, r0=len, r1=adr1 1079 add .s r0, r0, # 1 1080 L: SK1 1081 sub .s r0, r0, # 1 1082 b .eq SKIPDONE 1083 ldrb r2, [ r1 ] 1084 cmp r2, tos 1085 eq, if, 1086 add .s r1, r1, # 1 1087 b SK1 1088 endif, 1089 L: SKIPDONE 1090 sub .s psp, psp, # 4 1091 str r1, [ psp ] \ push c-addr2 1092 mov tos, r0 \ u2 1093 next, 1094 END-CODE 1095 1096 CODE SCAN \ c-addr1 u1 char -- c-addr2 u2 1097 \ *G Look for first occurrence of *\i{char} in the string and 1098 \ ** return a new string. *\i{C-addr2/u2} describes the string 1099 \ ** with *\i{char} as the first character. 1100 ldmia psp ! { r0, r1 } \ tos=char, r0=len, r1=adr1 1101 add .s r0, r0, # 1 1102 L: SC1 1103 sub .s r0, r0, # 1 1104 b .eq SCANDONE 1105 ldrb r2, [ r1 ] 1106 cmp r2, tos 1107 ne, if, 1108 add .s r1, r1, # 1 1109 b SC1 1110 endif, 1111 L: SCANDONE 1112 sub .s psp, psp, # 4 1113 str r1, [ psp ] \ push c-addr2 1114 mov tos, r0 \ u2 1115 next, 1116 END-CODE 1117 1118 CODE S= \ c-addr1 c-addr2 u -- flag 1119 \ *G Compare two same-length strings/memory blocks, returning TRUE if 1120 \ ** they are identical. 1121 ldmia psp ! { r0, r1 } \ r0=adr2, r1=adr1 1122 mov .s tos, tos 1123 b .eq S=X \ TRUE as len=0 1124 L: S=1 1125 ldrb r2, [ r0 ] 1126 ldrb r3, [ r1 ] 1127 add .s r0, r0, # 1 1128 add .s r1, r1, # 1 1129 cmp r2, r3 1130 b .ne S=X \ FALSE as mismatched chars 1131 sub .s tos, tos, # 1 1132 b .ne S=1 \ if count=0 then TRUE 1133 L: S=X 1134 eq, if, 1135 mov .s tos, # 1 1136 neg .s tos, tos \ TRUE 1137 else, 1138 mov .s tos, # 0 \ FALSE 1139 then, 1140 next, 1141 END-CODE 1142 1143 : compare \ c-addr1 u1 c-addr2 u2 -- n 17.6.1.0935 1144 \ *G Compare two strings. The return result is 0 for a match or can be 1145 \ ** -ve/+ve indicating string differences. 1146 \ ** If the two strings are identical, n is zero. If the two strings 1147 \ ** are identical up to the length of the shorter string, n is 1148 \ ** minus-one (-1) if u1 is less than u2 and one (1) otherwise. 1149 \ ** If the two strings are not identical up to the length of the 1150 \ ** shorter string, n is minus-one (-1) if the first non-matching 1151 \ ** character in the string specified by c-addr1 u1 has a lesser 1152 \ ** numeric value than the corresponding character in the string 1153 \ ** specified by c-addr2 u2 and one (1) otherwise. 1154 rot swap \ c-addr1 c-addr2 u1 u2 1155 2dup - >r min \ c-addr1 c-addr2 minlen -- R: lendiff? -- 1156 1157 begin 1158 dup 1159 while 1160 -rot over c@ over c@ - \ length c-addr1 c-addr2 (char1-char2) 1161 dup if \ If chars are different 1162 r> drop >r \ replace lendiff result with error code 1163 drop 0 \ and put 0 on TOS (make len==0 at BEGIN) 1164 else \ otherwise 1165 drop \ discard difference 1166 1+ swap 1+ swap rot 1- \ increment addresses and decrement length 1167 then 1168 repeat 1169 drop 2drop \ remove addresses and null count from stack 1170 \ -- ; R: result -- 1171 r> dup if 0< 1 or then \ make nice flag, 0 becomes 0, -ve becomes -1 1172 \ and +ve becomes 1 1173 ; 1174 1175 internal 1176 : (search) { c-addr1 u1 c-addr2 u2 -- c-addr3 u3 flag } 1177 c-addr1 u1 u2 - 1+ bounds \ Search for first char of $2 in $1. Note that 1178 ?do \ we only check LEN($1)-LEN($2)+1 chars of $1. 1179 i c@ c-addr2 c@ = if \ Compare next char of $1 with first char of $2. 1180 i c-addr2 u2 s= if \ Is the whole of $2 present? 1181 i u1 i c-addr1 - - true \ Yes - build return stack parameters... 1182 unloop exit \ ...and bail out. 1183 then 1184 then 1185 loop 1186 c-addr1 u1 false \ End of loop and first char not found - no match. 1187 ; 1188 external 1189 1190 : SEARCH ( c-addr1 u1 c-addr2 u2 -- c-addr3 u3 flag ) 1191 \ *G Search the string c-addr1/u1 for the string c-addr2/u2. If a match 1192 \ ** is found return c-addr3/u3, the address of the start of the match 1193 \ ** and the number of characters remaining in c-addr1/u1, plus flag f 1194 \ ** set to true. If no match was found return c-addr1/u1 and f=0. 1195 2 pick over < \ Is $1 shorter than $2? 1196 if 2drop false exit then \ Yes - $2 *can't* be in $1. 1197 dup 0 <= \ Is $2 zero length? 1198 if 2drop true exit then \ Yes - we have found it at the start of $1. 1199 2 pick 0 <= \ Is $1 zero length? 1200 if 2drop false exit then \ Yes - string not found. 1201 (search) 1202 ; 1203 1204 code cmove \ asrc adest len -- 1205 \ *G Copy *\i{len} bytes of memory forwards from *\i{asrc} to *\i{adest}. 1206 mov .s r3, tos \ r3=len 1207 ldmia psp ! { r0, r1, tos } \ r0=addr2, r1=addr1, r3=len, tos restored 1208 eq, if, 1209 bx link \ return if len=0, nothing to do 1210 endif, 1211 mov .s r2, r0 1212 orr .s r2, r2, r1 \ check alignment 1213 orr .s r2, r2, r3 \ R2 := adr1|addr2|len 1214 mov .s r4, # 3 1215 and .s r4, r4, r2, \ will be zero if aligned 1216 b .ne cmovx3 \ if not aligned 1217 L: CMOVX1 1218 ldr r2, [ r1 ] 1219 str r2, [ r0 ] 1220 add .s r1, r1, # 4 1221 add .s r0, r0, # 4 1222 sub .s r3, r3, # 4 1223 b .ne CMOVX1 1224 next, 1225 L: CMOVX3 1226 ldrb r2, [ r1 ] 1227 strb r2, [ r0 ] 1228 add .s r1, r1, # 1 1229 add .s r0, r0, # 1 1230 sub .s r3, r3, # 1 1231 b .ne CMOVX3 1232 next, 1233 END-CODE 1234 1235 CODE CMOVE> \ c-addr1 c-addr2 u -- 1236 \ *G As *\fo{CMOVE} but working in the opposite direction, 1237 \ ** copying the last character in the string first. 1238 mov .s r3, tos \ r3=len 1239 ldmia psp ! { r0, r1, tos } \ r0=addr2, r1=addr1, r3=len, tos restored 1240 eq, if, 1241 bx link \ return if len=0, nothing to do 1242 endif, 1243 add .s r0, r0, r3 \ addr2+len 1244 add .s r1, r1, r3 \ addr1+len 1245 mov .s r2, r0 1246 orr .s r2, r2, r1 \ check alignment 1247 orr .s r2, r2, r3 \ R2 := adr1|addr2|len 1248 mov .s r4, # 3 1249 and .s r4, r4, r2, \ will be zero if aligned 1250 b .ne CMV>3 \ byte by byte if not aligned 1251 L: CMV>1 \ copy by 4 byte units 1252 sub .s r1, r1, # 4 1253 sub .s r0, r0, # 4 1254 ldr r2, [ r1 ] 1255 str r2, [ r0 ] 1256 sub .s r3, r3, # 4 1257 b .ne CMV>1 1258 next, 1259 L: CMV>3 \ copy byte by byte 1260 sub .s r1, r1, # 1 1261 sub .s r0, r0, # 1 1262 ldrb r2, [ r1 ] 1263 strb r2, [ r0 ] 1264 sub .s r3, r3, # 1 1265 b .ne CMV>3 1266 next, 1267 END-CODE 1268 1269 : upc \ char -- char' ; force upper case 1270 \ *G Convert char to upper case. 1271 dup [char] a >= if 1272 dup [char] z <= if 1273 $DF and 1274 endif 1275 endif 1276 ; 1277 1278 : upper \ c-addr len -- 1279 \ *G Convert the ASCII string described to upper-case. This operation 1280 \ ** happens in place. 1281 bounds ?do i c@ upc i c! loop 1282 ; 1283 1284 : PLACE \ c-addr1 u c-addr2 -- 1285 \ *G Place the string c-addr1/u as a counted string at c-addr2. 1286 2dup 2>r 1+ swap move 2r> c! 1287 ; 1288 1289 : ON \ a-addr -- 1290 \ *G Given the address of a CELL this will set its contents to TRUE (-1). 1291 on ; 1292 1293 : OFF \ a-addr -- 1294 \ *G Given the address of a CELL this will set its contents to FALSE (0). 1295 off ; 1296 1297 (( 1298 CODE C+! \ b c-addr -- 1299 \ *G Add N to the character (byte) at memory address ADDR. 1300 ldmia psp ! { r0 } 1301 ldrb r1, [ tos ] 1302 add .s r1, r1, r0 1303 strb r1, [ tos ] 1304 ldmia psp ! { tos } 1305 next, 1306 END-CODE 1307 )) 1308 1309 CODE 2@ \ a-addr -- x1 x2 1310 \ *G Fetch and return the two CELLS from memory ADDR and ADDR+sizeof(CELL). 1311 \ ** The cell at the lower address is on the top of the stack. 1312 ldmia tos ! { r0 r1 } \ r0 from low address 1313 sub .s psp, psp, # 4 1314 mov tos, r0 1315 str r1, [ psp ] 1316 next, 1317 END-CODE 1318 1319 CODE 2! \ x1 x2 a-addr -- 1320 \ *G Store the two CELLS x1 and x2 at memory ADDR. 1321 \ ** X2 is stored at ADDR and X1 is stored at ADDR+CELL. 1322 mov .s r2, tos 1323 ldmia psp ! { r0, r1, tos } \ r0=x2, r1=x1 1324 stmia r2 ! { r0 r1 } 1325 next, 1326 END-CODE 1327 1328 CODE FILL \ c-addr u char -- 1329 \ *G Fill LEN bytes of memory starting at ADDR with the byte information 1330 \ ** specified as CHAR. 1331 mov .s r2, tos 1332 ldmia psp ! { r0, r1, tos } \ r2=char, r0=count, r1=addr 1333 cmp r0, # 0 1334 b .eq FILX 1335 L: FIL1 1336 strb r2, [ r1 ] 1337 add .s r1, r1, # 1 1338 sub .s r0, r0, # 1 1339 b .ne FIL1 1340 L: FILX 1341 next, 1342 END-CODE 1343 1344 : +! \ n|u a-addr -- 1345 \ *G Add N to the CELL at memory address ADDR. 1346 +! ; 1347 1348 : INCR \ a-addr -- 1349 \ *G Increment the data cell at a-addr by one. 1350 incr ; 1351 1352 : DECR \ a-addr -- 1353 \ *G Decrement the data cell at a-addr by one. 1354 decr ; 1355 1356 : @ \ a-addr -- x 1357 \ *G Fetch and return the CELL at memory ADDR. 1358 @ ; 1359 1360 : W@ \ a-addr -- w 1361 \ *G Fetch and 0 extend the word (16 bit) at memory ADDR. 1362 w@ ; 1363 1364 : C@ \ c-addr -- char 1365 \ *G Fetch and 0 extend the character at memory ADDR and return. 1366 c@ ; 1367 1368 : ! \ x a-addr -- 1369 \ *G Store the CELL quantity X at memory A-ADDR. 1370 ! ; 1371 1372 : W! \ w a-addr -- 1373 \ *G Store the word (16 bit) quantity w at memory ADDR. 1374 w! ; 1375 1376 : C! \ char c-addr -- 1377 \ *G Store the character CHAR at memory C-ADDR. 1378 c! ; 1379 1380 : TEST-BIT \ mask c-addr -- flag 1381 \ *G AND the mask with the contents of addr and return the result. 1382 c@ and ; 1383 1384 : SET-BIT \ mask c-addr -- 1385 \ *G Apply the mask ORred with the contents of c-addr. 1386 \ ** Byte operation. 1387 bor! ; 1388 1389 : RESET-BIT \ mask c-addr -- 1390 \ *G Apply the mask inverted and ANDed with the contents of c-addr. 1391 \ ** Byte operation. 1392 bbic! ; 1393 1394 (( 1395 CODE TOGGLE-BIT \ u c-addr -- 1396 \ *G Invert the bits at c-addr specified by the mask. Byte operation. 1397 ldmia psp ! { r0 } \ get mask 1398 ldrb r1, [ tos ] \ get byte from addr 1399 eor .s r1, r1, r0 \ apply mask 1400 strb r1, [ tos ] \ store byte 1401 ldmia psp ! { tos } \ get new tos 1402 next, 1403 END-CODE 1404 )) 1405 1406 1407 \ ********************** 1408 \ *S Miscellaneous words 1409 \ ********************** 1410 1411 : NAME> \ nfa -- cfa 1412 \ *G Move a pointer from an NFA to the XT.. 1413 dup c@ $1F and + 4 + -4 and ; \ 1 for count byte, 3 for aligning 1414 1415 \ On Cortex, name field is a multiple of 4 bytes so we only need to 1416 \ check top bit of every fourth byte when working back from the cfa 1417 \ to find the nfa 1418 : >NAME \ cfa -- nfa 1419 \ *G Move a pointer from an XT back to the NFA or name-pointer. 1420 \ ** If the original pointer was not an XT or if the definition 1421 \ ** in question has no name header in the dictionary the 1422 \ ** returned pointer will be useless. Care should be taken when 1423 \ ** manipulating or scanning the Forth dictionary in this way. 1424 begin 4 - dup @ $80 and until \ nfa in low byte 1425 ; 1426 1427 internal 1428 : (SEARCH-WORDLIST) ( c-addr u ^^nfa -- 0 | xt 1 | xt -1 ) 1429 begin 1430 @ dup 1431 while 1432 dup c@ $1F and \ -- c-addr u ^nfa nfalen ; 1433 2 pick = if \ Are the names the same *length*? 1434 dup 1+ 3 pick 3 pick s= if \ Are they the same *name*? 1435 nip nip 1436 dup name> swap 1437 c@ $40 and ( 0= ) \ check for immediacy (0=immediate) 1438 if -1 else 1 then 1439 exit 1440 then 1441 then 1442 ( n>link ) cell - 1443 repeat 1444 drop 2drop 0 1445 ; 1446 1447 : SEARCH-WORDLIST \ c-addr u wid -- 0|xt 1|xt -1 1448 \ *G Search the given wordlist for a definition. If the definition is 1449 \ ** not found then 0 is returned, otherwise the XT of the definition 1450 \ ** is returned along with a non-zero code. A -ve code indicates a 1451 \ ** "normal" definition and a +ve code indicates an *\fo{IMMEDIATE} word. 1452 dup 0= if 1453 nip nip 1454 else \ -- c-addr u wid 1455 over 3 pick c@ + over @ 1- and \ -- c-addr u wid thread# 1456 1+ cells + \ -- c-addr u ^nfa 1457 (search-wordlist) 1458 then 1459 ; 1460 1461 CODE DIGIT \ char n -- 0|n true 1462 \ *G If the ASCII value *\i{CHAR} can be treated as a digit for a number 1463 \ ** within the radix *\i{N} then return the digit and a TRUE flag, otherwise 1464 \ ** return FALSE. 1465 ldmia psp ! { r0 } \ base in tos, char in r0 1466 sub .s r0, r0, # $30 \ '0' 1467 b .mi DIG2 \ fail if char < '0' 1468 cmp r0, # $0A 1469 b .lt DIG1 \ true, '0' <= char <= '9@ 1470 sub .s r0, r0, # 7 \ convert 'A'..'F' 1471 cmp r0, # $0A 1472 b .lt DIG2 \ fail if result < 'A' 1473 L: DIG1 1474 cmp r0, tos \ in range of base? 1475 lt, if, 1476 mov .s tos, # 1 \ yes, tos=true 1477 neg .s tos, tos 1478 sub .s psp, psp, # 4 1479 str r0, [ psp ] \ push n 1480 next, 1481 endif, \ exit 1482 L: DIG2 1483 mov .s tos, # 0 \ tos=false 1484 next, \ exit 1485 END-CODE 1486 1487 1488 \ ********************** 1489 \ *S Portability helpers 1490 \ ********************** 1491 \ *P Using these words will make code easier to port between 1492 \ ** 16, 32 and 64 bit targets. 1493 1494 CODE CELL+ \ a-addr1 -- a-addr2 1495 \ *G Add the size of a CELL to the top-of stack. 1496 add .s tos, tos, # 4 1497 next, 1498 END-CODE 1499 1500 CODE CELLS \ n1 -- n2 1501 \ *G Return the size in address units of N1 cells in memory. 1502 mov .s tos, tos .lsl # 2 1503 next, 1504 END-CODE 1505 1506 CODE CELL- \ a-addr1 -- a-addr2 1507 \ *G Decrement an address by the size of a cell. 1508 sub .s tos, tos, # 4 1509 next, 1510 END-CODE 1511 1512 CODE CELL \ -- n 1513 \ *G Return the size in address units of one CELL. 1514 sub .s psp, psp, # 4 1515 str tos, [ psp ] \ save TOS 1516 mov .s tos, # 4 \ return cell size 1517 next, 1518 END-CODE 1519 1520 (( 1521 CODE CHAR+ \ c-addr1 -- c-addr2 1522 \ *G Increment an address by the size of a character. 1523 add .s tos, tos, # 1 1524 next, 1525 END-CODE 1526 1527 : CHARS \ n1 -- n2 1528 \ *G Return size in address units of N1 characters. 1529 ; immediate 1530 )) 1531 1532 1533 \ ************************************** 1534 \ *S Supporting complation on the target 1535 \ ************************************** 1536 \ *P Compilation on the target is supported for compilation into 1537 \ ** Flash. The target's compiler is simplistic and gives neither 1538 \ ** the code size nor the performance of cross-compiled code. 1539 \ ** The support words are compiled without heads. 1540 1541 interpreter also asm-access \ black magic here! 1542 get-rsp get-psp get-tos 1543 previous target 1544 equ tos-reg equ psp-reg equ rsp-reg 1545 1546 internal 1547 : opc32, \ opc32 -- ; compile 32 bit opcode 1548 dup #16 rshift w, w, ; 1549 1550 : opc32! \ opc32 addr -- ; store a 32 bit opcode 1551 over #16 rshift over w!f 2 + w!f ; 1552 1553 (( 1554 : opc32@ \ addr -- opc32 ; fetch a 32 bit opcode 1555 dup w@ #16 lshift swap 2 + w@ or ; 1556 )) 1557 1558 (( 1559 \ Short form for calls 1560 bl <dest> \ $+00 1561 ... \ $+04, returns here 1562 \ Long form for calls, start is NOT aligned 1563 ldr r0, $ 6 + \ $+00 1564 blx r0 \ $+02 1565 b $ 6 + \ $+04 skip address 1566 addr \ $+06 location must be aligned 1567 )) 1568 1569 (( 1570 : inRange24? \ dest -- flag ; true if +/-24 bit 1571 here 4 + - $FF00:0000 $00FF:FFFE within? ; 1572 )) 1573 1574 : GenJ \ offset mask -- Jx ; J := (notI) xor S 1575 over and 0= swap 0< xor ; 1576 1577 : CalcTrel24 \ dest orig -- field24 1578 \ calculate field for 24 bit Thumb branch 1579 4 + - 1 arshift \ half word align 1580 dup $7FF and \ offset imm11 ; bits 10..0 -> 10..0 1581 over #11 rshift $3FF and #16 lshift or \ merge imm10 ; bits 20..11 -> 25..16 1582 over $0020:0000 GenJ $0000:2000 and or \ merge J1/bit13 ; I1=bit21 -> 13 1583 over $0040:0000 GenJ $0000:0800 and or \ merge J2/bit11 ; I2=bit22 -> 11 1584 swap 0< $0400:0000 and or \ merge S to bit26 1585 ; 1586 1587 : bl24 \ dest orig -- opc 1588 calcTrel24 $F000:D000 or ; 1589 1590 : pushLR.n, \ -- ; lay 16 bit push of LR to return stack 1591 $B500 w, ; \ push { lr } 1592 1593 : nop.n, \ -- ; lay 16 bit NOP 1594 $BF00 w, ; \ nop .n 1595 1596 : !scall \ dest addr -- 1597 \ +G Patch a BL DEST opcode at addr. 1598 tuck bl24 swap opc32! ; 1599 1600 $1E00 4 6 lshift or psp-reg 3 lshift or psp-reg or equ subPspIns 1601 \ Instruction opcode for SUB psp, psp, # 4 1602 $6000 psp-reg 3 lshift or tos-reg or equ strTosIns 1603 \ Instruction opcode for STR tos, [ psp # 0 ] 1604 1605 : saveTos, \ -- ; compiles push of tos to data stack 1606 subPspIns w, \ sub psp, psp, # 4 1607 strTosIns w, \ template for str rt, [ rn, # 0 ] 1608 ; 1609 1610 : dataPtr@, \ -- ; compiles fetch to TOS through LR 1611 $4670 w, \ mov r0, link 1612 $1E40 w, \ sub .s r0, r0, # 1 1613 $6800 tos-reg or w, \ ldr tos, [ r0, # 0 ] 1614 ; 1615 1616 : scall, \ addr -- 1617 \ +G Compile a machine code BL to addr. No range checking is performed. 1618 here bl24 opc32, ; 1619 1620 : compileAligned, \ xt -- 1621 here 2 and 1622 if nop.n, endif 1623 scall, 1624 ; 1625 1626 : DOCOLON, \ -- 1627 \ +G Compile the runtime entry code required by colon definitions. 1628 \ +* INTERNAL. 1629 pushLR.n, ; \ push { r14 } 1630 1631 CODE LIT \ -- x 1632 \ *G Code which when CALLED at runtime will return an inline cell 1633 \ ** value. The call must be at a four byte boundary. INTERNAL. 1634 sub .s psp, psp, # 4 \ save TOS 1635 str tos, [ psp, # 0 ] 1636 mov r0, link \ LINK is high register 1637 sub .s r0, r0, # 1 \ remove T bit 1638 ldr tos, [ r0, # 0 ] \ get data (in-line) 1639 add .s r0, r0, # 5 \ restore T bit, step over data 1640 bx r0 1641 END-CODE 1642 1643 CODE (") \ -- a-addr ; return address of string, skip over it 1644 \ *G Return the address of a counted string that is inline after the 1645 \ ** CALLING word, and adjust the CALLING word's return address to 1646 \ ** step over the inline string. The adjusted return address will 1647 \ ** be at a four byte boundary. 1648 \ ** See the definition of *\fo{(.")} for an example. 1649 sub .s psp, psp, # 4 \ save TOS 1650 str tos, [ psp, # 0 ] 1651 ldr tos, [ rsp, # 0 ] \ get return address of CALLER 1652 sub .s tos, tos, # 1 \ remove Thumb bit 1653 ldrb r1, [ tos, # 0 ] \ length byte 1654 add .s r1, r1, tos \ r1=address+length 1655 add .s r1, r1, # 4 \ +1 for count byte, +3 to align 1656 mov .s r2, # 3 \ -4 AND -> 3 BIC 1657 bic .s r1, r1, r2 1658 add .s r1, r1, # 1 \ restore Thumb bit 1659 str r1, [ rsp, # 0 ] \ update return address 1660 next, 1661 END-CODE 1662 1663 external 1664 1665 1666 \ ************************************* 1667 \ *S Defining words and runtime support 1668 \ ************************************* 1669 1670 : aligned \ addr -- addr' 1671 \ *G Given an address pointer this word will return the next ALIGNED 1672 \ ** address subject to system wide alignment restrictions. 1673 3 + -4 and 1674 ; 1675 compiler 1676 : aligned \ addr -- addr' 1677 3 + -4 and 1678 ; 1679 target 1680 1681 1682 ASMCODE 1683 align L: DOCREATE \ -- addr 1684 \ +G The run time action of *\fo{CREATE}. The call must be on a 1685 \ +* four byte boundary. INTERNAL. 1686 sub .s psp, psp, # 4 \ save TOS 1687 str tos, [ psp, # 0 ] 1688 mov r0, link \ LINK is high register 1689 sub .s r0, r0, # 1 \ remove T bit 1690 ldr tos, [ r0, # 0 ] \ get data address (in-line) 1691 pop { pc } 1692 end-code 1693 1694 : compile, \ xt -- 1695 \ *G Compile the word specified by xt into the current definition. 1696 scall, ; 1697 1698 : >BODY \ xt -- a-addr 1699 \ *G Move a pointer from a CFA or "XT" to the definition's data 1700 \ ** area. *\fo{>BODY} should only be used with children of 1701 \ ** *\fo{CREATE}. If *\fo{FOOBAR} is defined with *\fo{CREATE foobar}, 1702 \ ** then the phrase *\fo{' FOOBAR >BODY} would give the same 1703 \ ** result as executing *\fo{FOOBAR}. 1704 8 + @ ; 1705 1706 internal 1707 : (docreate,) \ -- 1708 nop.n, pushLR.n, DOCREATE scall, 1709 ; 1710 1711 : (dobuild,) \ -- ; lay dummy cfa 1712 nop.n, pushLR.n, 4 allot \ lay down m/c call for later patching 1713 \ nop.n, pushLR.n, $F7FF:FFFF , \ lay down m/c call for later patching 1714 ; 1715 1716 : namedBuild, \ val -- 1717 \ +G Start a target defining word. 1718 [ROM header, (dobuild,) swap , ROM] 1719 ; 1720 1721 : (;CODE) \ -- ; R: a-addr -- 1722 \ *G Performed at compile time by *\fo{;CODE} and *\fo{DOES>}. 1723 \ ** Patch the last word defined (by *\fo{CREATE}) to have the 1724 \ ** run time actions that follow immediately after *\fo{(;CODE)}. 1725 \ ** INTERNAL. 1726 r> -2 and latest name> 4 + !scall ; \ SFP004 1727 1728 variable immheader \ -- addr 1729 external 1730 1731 : Imm \ -- 1732 \ *G Used before a definition to indicate that it is *\fo{IMMEDIATE}, 1733 \ ** which means that it will execute whenever encountered regardless 1734 \ ** of whether the system is compiling. 1735 immheader on 1736 ; 1737 1738 target-only 1739 : : \ C: "<spaces>name" -- colon-sys ; Exec: i*x -- j*x ; R: -- nest-sys 1740 \ *G Begin a new definition called *\fo{name}. 1741 ?EXEC !CSP header, hide ] docolon, 1742 ; immediate 1743 host&target 1744 1745 target-only 1746 : :NONAME \ C: -- colon-sys ; Exec: i*x -- i*x ; R: -- nest-sys 1747 \ *G Begin a new code definition which does not have a name. After the 1748 \ ** definition is complete the semi-colon operator returns the XT of 1749 \ ** newly compiled code on the stack. 1750 !csp \ compiler stack security 1751 align here last ! 0 , \ lay null header to fool SMUDGE 1752 here ] docolon, \ compiler on, lay entry code 1753 ; 1754 host&target 1755 1756 : DOES> \ C: colon-sys1 -- colon-sys2 ; Run: -- ; R: nest-sys -- 1757 \ *G Begin definition of the runtime-action of a child of a defining word. 1758 \ ** See the section about defining words in *\i{Programming Forth}. 1759 \ ** You should not use *\fo{RECURSE} after *\fo{DOES>}. 1760 cr ." DOES>" 1761 ['] (;code) compile, 1762 cr ." a" 1763 saveTos, 1764 cr ." b" 1765 dataPtr@, 1766 cr ." c" 1767 ; 1768 IMMEDIATE 1769 1770 : CREATE \ -- 1771 \ *G Create a new definition in the dictionary. When the new 1772 \ ** definition is executed it will return the address of the 1773 \ ** definition's data area. As compilation is into Flash, 1774 \ ** *\fo{CREATE} cannot be used with *\fo{DOES>} and 1775 \ ** *\fo{ <BUILDS ... DOES> ...} must be used instead. 1776 ROM? [ROM swap \ old flag 1777 header, (docreate,) dataAddr, \ header, m/c call, address 1778 ROM] 1779 ; 1780 1781 : <BUILDS \ -- 1782 \ *G Always used in the form: 1783 \ *C : defword <BUILDS ... DOES> ... ; 1784 \ *P When *\fo{defword} is executed a new definition is created 1785 \ ** with the data defined between *\fo{<BUILDS} and *\fo{DOES>} 1786 \ ** and the action defined between *\fo{DOES>} and *\fo{;}. 1787 \ ** You must use *\fo{<BUILDS} and *\fo{DOES>} together, otherwise 1788 \ ** there will be a crash. Treat *\fo{<BUILDS} as a special case 1789 \ ** of *\fo{CREATE} for use with *\fo{DOES>} and compilation into 1790 \ ** Flash. 1791 ROM? [ROM swap \ old flag 1792 header, (dobuild,) dataAddr, \ header, m/c call, address 1793 ROM] 1794 ; 1795 1796 : CONSTANT \ x "<spaces>name" -- ; Exec: -- x 1797 \ *G Create a new *\fo{CONSTANT} called *\fo{name} which has the 1798 \ ** value *\i{x}. When *\fo{NAME} is executed *\i{x} is returned. 1799 namedBuild, ;CODE 1800 sub .s psp, psp, # 4 \ save TOS 1801 str tos, [ psp, # 0 ] 1802 mov r0, link \ LINK is high register 1803 sub .s r0, r0, # 1 \ remove T bit 1804 ldr tos, [ r0, # 0 ] \ get data address (in-line) 1805 pop { pc } 1806 END-CODE 1807 1808 : 2CONSTANT \ Comp: x1 x2 "<spaces>name" -- ; Run: -- x1 x2 1809 \ *G A two-cell equivalent of *\fo{CONSTANT}. 1810 namedBuild, , ;CODE 1811 sub .s psp, psp, # 8 \ save TOS 1812 str tos, [ psp, # 4 ] 1813 mov r0, link \ LINK is high register 1814 sub .s r0, r0, # 1 \ remove T bit 1815 ldr tos, [ r0, # 0 ] \ get data high 1816 ldr r1, [ r0, # 4 ] \ get data low 1817 str r1, [ psp, # 0 ] 1818 pop { pc } \ exit 1819 END-CODE 1820 1821 : VARIABLE \ "<spaces>name" -- ; Exec: -- a-addr 1822 \ *G Create a new variable called *\fo{name}. When *\fo{name} is 1823 \ ** executed the address of the data-cell is returned for use 1824 \ ** with *\fo{@} and *\fo{!} operators. 1825 \ ** The RAM is not initialised. 1826 rhere namedBuild, cell rallot ;CODE 1827 sub .s psp, psp, # 4 \ save TOS 1828 str tos, [ psp, # 0 ] 1829 mov r0, link \ LINK is high register 1830 sub .s r0, r0, # 1 \ remove T bit 1831 ldr tos, [ r0, # 0 ] \ get address 1832 pop { pc } 1833 END-CODE 1834 1835 (( 1836 : 2VARIABLE \ Comp: "<spaces>name" -- ; Run: -- a-addr 1837 \ *G A two-cell equivalent of *\fo{VARIABLE}. 1838 \ ** The RAM is not initialised. 1839 rhere namedBuild, 8 rallot ;CODE 1840 sub .s psp, psp, # 4 \ save TOS 1841 str tos, [ psp, # 0 ] 1842 mov r0, link \ LINK is high register 1843 sub .s r0, r0, # 1 \ remove T bit 1844 ldr tos, [ r0, # 0 ] \ get address 1845 pop { pc } 1846 END-CODE 1847 )) 1848 1849 : BUFFER: \ n "<spaces>name" -- 1850 \ *G Create a named buffer in RAM of *\i{n} bytes. 1851 rhere constant rallot 1852 ; 1853 1854 : USER \ u "<spaces>name" -- ; Exec: -- addr ; SFP009 1855 \ *G Create a new *\fo{USER} variable called *\fo{name}. The *\i{u} 1856 \ ** parameter specifies the index into the user-area table at which 1857 \ ** to place the* data. *\fo{USER} variables are located in a 1858 \ ** separate area of memory for each task or interrupt. Use in 1859 \ ** the form: 1860 \ *C $400 USER TaskData 1861 namedBuild, ;code \ ugly, but works 1862 sub .s psp, psp, # 4 \ save TOS 1863 str tos, [ psp, # 0 ] 1864 mov r0, link \ LINK is high register 1865 sub .s r0, r0, # 1 \ remove T bit 1866 ldr tos, [ r0, # 0 ] \ get offset 1867 add tos, tos, up \ add user pointer to user offset 1868 pop { pc } 1869 end-code 1870 1871 interpreter 1872 : u# \ "<name>"-- u 1873 \ *G An *\fo{INTERPRETER} word that returns the index of the 1874 \ ** *\fo{USER} variable whose name follows, e.g. 1875 \ *C u# S0 1876 ' >body 1877 ; 1878 target 1879 1880 internal 1881 : CRASH \ -- ; used as action of DEFER 1882 \ *G The default action of a *\fo{DEFER}ed word, which is *\fo{NOOP}, 1883 ; 1884 external 1885 1886 : DEFER \ Comp: "<spaces>name" -- ; Run: i*x -- j*x 1887 \ *G Creates a new *\fo{DEFER}ed word. No default action is 1888 \ ** assigned. User-defined *\fo{DEFER}ed words *\b{must} be 1889 \ ** initialised by the application before use. 1890 \ *C ' <action> IS <deferredword> 1891 \ *P or (when compiled) 1892 \ *C ['] <action> IS <deferredword> 1893 rhere namedBuild, cell rallot ;CODE 1894 mov r0, link \ LINK is high register 1895 sub .s r0, r0, # 1 \ remove T bit 1896 ldr r0, [ r0, # 0 ] \ get data address 1897 ldr r1, [ r0, # 0 ] \ get xt 1898 mov .s r2, # 1 1899 orr .s r1, r1, r2 \ force T bit 1900 pop { r3 } \ get return address 1901 mov link, r3 1902 bx r1 1903 END-CODE 1904 1905 (( 1906 : FIELD \ size n "<spaces>name" -- size+n ; Exec: addr -- addr+n 1907 \ *G Create a new field of *\i{n} bytes within a structure so far 1908 \ ** of *\i{size} bytes. 1909 over namedBuild, + ;CODE 1910 mov r0, link \ LINK is high register 1911 sub .s r0, r0, # 1 \ remove T bit 1912 ldr r1 [ r0, # 0 ] \ get offset 1913 add .s tos, tos, r1 \ add to base addr 1914 pop { pc } 1915 END-CODE 1916 )) 1917 1918 internal 1919 variable OPERATORTYPE \ -- addr ; used at compile time for prefix operator 1920 1921 : VAL-COMPILE/EXECUTE \ value xt[c] xt[e] -- 1922 state @ if 1923 drop compileAligned, , 1924 else 1925 nip execute 1926 endif 1927 ; 1928 1929 : bad-method \ -- ; error action 1930 cr ." Invalid operator for this type" 1931 #-13 throw 1932 ; 1933 1934 CODE VAL! \ n -- ; store value address in-line 1935 \ *G Store n at the inline address following this word. 1936 \ ** INTERNAL. 1937 \ N.B. The call to VAL! must be four-byte aligned 1938 mov r1, link 1939 sub .s r1, r1, # 1 \ inline address 1940 ldr r0, [ r1 ] \ get data address (in-line) 1941 add .s r1, r1, # 5 \ step over, restore T bit 1942 mov link, r1 1943 str tos, [ r0 ] \ and write data from tos 1944 ldmia psp ! { tos } \ restore TOS 1945 next, 1946 END-CODE 1947 1948 CODE VAL@ \ -- n ; read value data address in-line 1949 \ *G Read n from the inline address following this word. 1950 \ ** INTERNAL. 1951 \ N.B. The call to VAL@ must be four-byte aligned 1952 sub .s psp, psp, # 4 1953 str tos, [ psp ] 1954 mov r1, link 1955 sub .s r1, r1, # 1 \ inline address 1956 ldr r0, [ r1 ] \ get data address (in-line) 1957 add .s r1, r1, # 5 \ step over, restore T bit 1958 mov link, r1 1959 ldr tos, [ r0 ] \ read data into tos 1960 next, 1961 END-CODE 1962 1963 \ VAL generates a literal, and so LIT is used instead. 1964 1965 external 1966 1967 : VALUE \ n -- ; -- n ; n VALUE <name> 1968 \ *G Creates a variable of initial value n that returns its contents 1969 \ ** when referenced. To store to a child of VALUE use "n to <child>". 1970 \ ** Application programs must explicity re-initialise children of 1971 \ ** *\fo{VALUE}. 1972 Imm 1973 >r rhere namedBuild, r> rhere ! cell rallot 1974 does> 1975 case operatortype @ operatortype off 1976 0 of ['] val@ ['] @ val-compile/execute endof 1977 1 of ['] val! ['] ! val-compile/execute endof 1978 \ 2 of state @ if c_lit endif endof 1979 bad-method 1980 endcase 1981 ; 1982 1983 : to \ -- 1984 \ *G store operator for use with *\fo{VALUE}s. 1985 1 OPERATORTYPE ! 1986 ; immediate 1987 1988 1989 \ ******************* 1990 \ *S Multitasker hook 1991 \ ******************* 1992 1993 defer pause \ -- ; multitasker hook 1994 \ *G Allows the sytem multitasker to get a look in. If the 1995 \ ** multitasker has not been compiled, *\fo{PAUSE} is set 1996 \ ** to *\fo{NOOP}. 1997 assign noop to-do pause 1998 1999 2000 \ ************************ 2001 \ *S Structure compilation 2002 \ ************************ 2003 \ *P These words define high level branches. They are used by the structure 2004 \ ** words such as *\fo{IF} and *\fo{AGAIN}. 2005 2006 internal 2007 2008 : >mark \ -- addr 2009 \ *G Mark the start of a forward branch. HIGH LEVEL CONSTRUCTS ONLY. 2010 \ ** INTERNAL. 2011 here ( 0 , ) cell allot ; 2012 2013 : >resolve \ addr -- 2014 \ *G Resolve absolute target of forward branch. HIGH LEVEL CONSTRUCTS ONLY. 2015 \ ** INTERNAL. 2016 here 1 or swap !f ; \ absolute dest+bit0 2017 2018 : <mark \ -- addr 2019 \ *G Mark the start (destination) of a backward branch. 2020 \ ** HIGH LEVEL CONSTRUCTS ONLY. 2021 \ ** INTERNAL. 2022 here ; 2023 2024 : <resolve \ addr -- 2025 \ *G Resolve a backward branch to addr. 2026 \ ** HIGH LEVEL CONSTRUCTS ONLY. 2027 \ ** INTERNAL. 2028 1 or , ; \ absolute + bit0 for target 2029 2030 synonym >c_res_branch >resolve \ addr -- ; fix up forward referenced branch 2031 \ *G See >RESOLVE. 2032 \ ** INTERNAL. 2033 synonym c_mrk_branch< <mark \ -- addr ; mark destination of backward branch 2034 \ *G See >MARK. 2035 \ ** INTERNAL. 2036 2037 2038 \ ********************** 2039 \ *S Branch constructors 2040 \ ********************** 2041 \ *P Used when compiling code on the target. 2042 2043 : c_branch< \ addr -- 2044 \ *G Lay the code for an unconditional backward branch. 2045 \ ** INTERNAL. 2046 ['] branch compileAligned, <resolve ; 2047 2048 : c_?branch< \ addr -- 2049 \ *G Lay the code for a conditional backward branch. 2050 ['] ?branch compileAligned, <resolve ; 2051 2052 : c_branch> \ -- addr 2053 \ *G Lay the code for a forward referenced unconditional branch. 2054 \ ** INTERNAL. 2055 ['] branch compileAligned, >mark ; 2056 2057 : c_?branch> \ -- addr 2058 \ *G Lay the code for a forward referenced conditional branch. 2059 \ ** INTERNAL. 2060 ['] ?branch compileAligned, >mark ; 2061 2062 2063 \ ***************** 2064 \ *S Main compilers 2065 \ ***************** 2066 2067 : c_lit \ lit -- 2068 \ *G Compile the code for a literal of value *\i{lit}. 2069 \ ** INTERNAL. 2070 ['] lit compileAligned, , ; 2071 2072 : c_drop \ -- 2073 \ *G Compile the code for *\fo{DROP}. 2074 \ ** INTERNAL. 2075 postpone drop ; 2076 2077 : c_exit \ -- 2078 \ *G Compile the code for *\fo{EXIT}. 2079 \ ** INTERNAL. 2080 $BD00 w, ; \ pop { pc } 2081 2082 : c_do \ C: -- do-sys ; Run: n1|u1 n2|u2 -- ; R: -- loop-sys 2083 \ *G Compile the code for *\fo{DO}. 2084 \ ** INTERNAL. 2085 ['] (do) compileAligned, >mark <mark ; 2086 2087 : c_?DO \ C: -- do-sys ; Run: n1|u1 n2|u2 -- ; R: -- | loop-sys 2088 \ *G Compile the code for *\fo{?DO}. 2089 \ ** INTERNAL. 2090 ['] (?do) compileAligned, >mark <mark ; 2091 2092 : c_LOOP \ C: do-sys -- ; Run: -- ; R: loop-sys1 -- | loop-sys2 2093 \ *G Compile the code for *\fo{LOOP}. 2094 \ ** INTERNAL. 2095 ['] (loop) compileAligned, <resolve >resolve ; 2096 2097 : c_+LOOP \ C: do-sys -- ; Run: -- ; R: loop-sys1 -- | loop-sys2 2098 \ *G Compile the code for *\fo{+LOOP}. 2099 \ ** INTERNAL. 2100 ['] (+loop) compileAligned, <resolve >resolve ; 2101 2102 variable NextCaseTarg \ -- addr 2103 \ *G Holds the entry point of the current *\fo{CASE} structure. 2104 \ ** INTERNAL. 2105 2106 : c_case \ -- addr 2107 \ *G Compile the code for *\fo{CASE}. 2108 \ ** INTERNAL. 2109 NextCaseTarg @ <mark NextCaseTarg ! ; 2110 2111 : c_OF \ C: -- of-sys ; Run: x1 x2 -- | x1 2112 \ *G Compile the code for *\fo{OF}. 2113 \ ** INTERNAL. 2114 ['] (of) compileAligned, >mark ; 2115 2116 : c_ENDOF \ C: case-sys1 of-sys -- case-sys2 ; Run: -- 2117 \ *G Compile the code for *\fo{ENDOF}. 2118 \ ** INTERNAL. 2119 c_branch> swap >c_res_branch ; 2120 2121 : FIX-EXITS \ n1..nn -- 2122 \ *G Compile the code to resolve the forward branches at the end 2123 \ ** of a *\fo{CASE} structure. 2124 \ ** INTERNAL. 2125 begin 2126 sp@ csp @ <> 2127 while 2128 >c_res_branch 2129 repeat 2130 ; 2131 2132 : c_ENDCASE \ C: case-sys -- ; Run: x -- 2133 \ *G Compile the code for *\fo{ENDCASE}. 2134 \ ** INTERNAL. 2135 c_drop fix-exits NextCaseTarg ! ; 2136 2137 (( 2138 : c_END-CASE \ C: case-sys -- ; Run: x -- 2139 \ *G Compile the code for *\fo{END-CASE}. 2140 \ ** INTERNAL. Only compiled if the equate *\fo{FullCase?} is non-zero. 2141 fix-exits NextCaseTarg ! ; 2142 )) 2143 2144 : c_NEXTCASE \ C: case-sys -- ; Run: x -- 2145 \ *G Compile the code for *\fo{NEXTCASE}. 2146 \ ** INTERNAL. 2147 c_drop NextCaseTarg @ c_branch< fix-exits NextCaseTarg ! ; 2148 2149 : c_?OF \ C: -- of-sys ; Run: flag -- 2150 \ *G Compile the code for *\fo{?OF}. 2151 \ ** INTERNAL. 2152 c_?branch> ; 2153 2154 external 2155 2156 2157 \ **************** 2158 \ *S Miscellaneous 2159 \ **************** 2160 2161 code di \ -- 2162 \ *G Disable interrupts. 2163 cps .id .i 2164 next, 2165 end-code 2166 2167 code ei \ -- 2168 \ *G Enable interrupts. 2169 cps .ie .i 2170 next, 2171 end-code 2172 2173 code [I \ R: -- x1 x2 2174 \ *G Preserve interrupt/exception status on the return stack, 2175 \ ** and disable interrupts/exceptions except reset, NMI and 2176 \ ** HardFault. The state is restored by *\fo{I]}. 2177 mrs r0, PRIMASK \ get status 2178 cps .id .i 2179 push .n { r0 } 2180 next, 2181 end-code 2182 2183 code I] \ R: x1 x2 -- 2184 \ *G Restore interrupt status saved by *\fo{[I} from the return 2185 \ ** stack. 2186 pop .n { r0 } 2187 msr PRIMASK r0 2188 next, 2189 end-code 2190 2191 : setMask \ value mask addr -- ; cell operation 2192 \ *G Clear the *\i{mask} bits at *\i{addr} and set (or) the 2193 \ ** bits defined by *\i{value}. 2194 tuck @ \ -- value addr mask x 2195 swap invert and \ -- value addr x' 2196 rot or \ -- addr x'' 2197 swap ! 2198 ; 2199 2200 : init-io \ addr -- 2201 \ *G Copy the contents of the I/O set up table to an I/O device. 2202 \ ** Each element of the table is of the form addr (cell) followed 2203 \ ** by data (cell). The table is terminated by an address of 0. 2204 begin 2205 dup @ 2206 while 2207 dup 2@ ! 2 cells + 2208 repeat 2209 drop 2210 ; 2211 2212 2213 \ ****** 2214 \ *> ### 2215 \ ****** 2216 2217 decimal