/ 2_computers.org
2_computers.org
1 #+title: Computers 2 #+author: Michael Raitza 3 #+subtitle: Barkhausen Institut, Dresden 4 #+options: ^:nil 5 #+startup: showall indent 6 #+property: header-args:uxntal :wrap src text :noweb yes 7 8 * The Computer 9 10 We use the Uxn/Varvara 8-bit virtual computer 11 12 [[https://wiki.xxiivv.com/site/uxn.html][Uxn➚]] :: 8-bit virtual machine 13 [[https://wiki.xxiivv.com/site/varvara.html][Varvara➚]] :: specification of devices communicating with the Uxn machine 14 15 - simple 16 - accessible 17 - supports graphics, sound and interaction 18 - programmed in [[https://wiki.xxiivv.com/site/uxntal.html][Uxntal➚]] 19 20 * The Uxn/Varvara computer 21 22 #+begin_src text 23 Control Unit Random access memory 24 Working Stack (memory) ¦ +------------+ +- - - +--------+--------+ 25 · ··~-+----+----+----+----+---+ ¦ IF / ID ¦ <------> | 0000 | i o i o o i i o | 26 | | | | | <----> ¦ Ex / LS __¦ <--+ +- - - +--------+--------+ 27 · ··~-+----+----+----+----+---+ +--> ¦ |PC¦ | | 0001 | | 28 ¦ | +---------+--+ | ·~ ~ ~ · ~ ~ ~ ~ ~ ~ ~ ~ · 29 Return Stack (memory) ¦ | ↑ | | | 00ff | | 30 · ··~-+----+----+----+----+---+ | | | | +- - - +--------+--------+ 31 | | | | | <-+ | | | | 0100 | | 32 · ··~-+----+----+----+----+---+ | | | ·~ ~ ~ · ~ ~ ~ ~ ~ ~ ~ ~ · 33 ¦ | | | · · · 34 | ↓ | · · · 35 +---------------------+ | 36 ¦ ¦ | Device memory 37 ¦ + / − / ≤ / ∨ / ∧ ¦ | +- + -+--------+--------+ 38 ¦ ¦ +----> | 0:0 | o o o o o o o o | 39 +---------------------+ · ~ ~ · ~ ~ ~ ~ ~ ~ ~ ~ · 40 Arith. Logic Unit | f:f | | 41 +- + -+--------+--------+ 42 #+end_src 43 44 * Instruction cycle – Instruction Fetch 45 46 #+begin_src text 47 Control Unit RAM 48 Stack ¦ +------------+ BYTE +------+------- 49 ----+---+ ¦ IF / ¦ <------- | 0000 | o o o 50 dd | ff <----> ¦ / __¦ +------+------- 51 ----+---+ ¦ |PC¦ -------> | 0001 | 52 ¦ +---------+--+ ADDR +~ ~ ~ + ~ ~ ~ 53 ↑ | | 00ff | 54 | ↓ +------+------- 55 +---------------------+ | 0100 | 56 ¦ ¦ +~ ~ ~ + ~ ~ ~ 57 #+end_src 58 59 * Instruction cycle – Instruction Decode 60 61 #+begin_src text 62 Control Unit 63 Stack ¦ +-----------------------+ 64 ----+---+ ¦ / ID +----- 65 dd | ff <----> ¦ / | ¦ 66 ----+---+ ¦ k r 2 BYTE <-+ ¦ 67 ¦ ¦ o o o o o o o o ¦ 68 ¦ ----- --------- ¦ 69 ¦ flags opcode __¦ 70 ¦ |PC¦ 71 +-----------------------+ 72 #+end_src 73 74 * Instruction cycle – Execute 75 76 #+begin_src text 77 Stack ¦ Control Unit 78 · ··~-+----+----+----+----+---+ pop +------------+ +- 79 Before Ex | dd | ff | 00 | cd -----> ¦ / ¦ <~ ·· ~> | 80 · ··~-+----+----+----+----+---+ ¦ Ex / __¦ +- 81 After Ex | | dd | ff | ab <----- ¦ |PC¦ | 82 · ··~-+----+----+----+----+---+ push +---------+--+ ·~ 83 ¦ ab ↑ | | 84 | ↓ cd, 00 +- 85 +---------------------+ | 86 ¦ ¦ +~ 87 ¦ + / - / ≤ / ∨ / ∧ ¦ · 88 ¦ ¦ · 89 +---------------------+ 90 Arith. Logic Unit 91 #+end_src 92 93 * Instruction cycle – Load/Store 94 95 #+begin_src text 96 Control Unit RAM 97 Stack ¦ +------------+ BYTE +------+------- 98 ----+---+ ¦ / ¦ <------- | 0000 | o o o 99 dd | ff <----- ¦ / LS __¦ +------+------- 100 ----+---+ ¦ |PC¦ -------> | 0001 | 101 ¦ +---------+--+ ADDR +~ ~ ~ + ~ ~ ~ 102 ↑ | | 00ff | 103 | ↓ +------+------- 104 +---------------------+ | 0100 | 105 ¦ ¦ +~ ~ ~ + ~ ~ ~ 106 #+end_src 107 108 * First program 109 #+begin_src uxntal 110 ;text while ( reference 'text' variable defined below ) 111 BRK 112 @while ( &str* -- ) 113 LDAk DUP ?{ 114 POP POP2 JMP2r } 115 #18 DEO 116 INC2 !while 117 118 @text "Hello 20 "World! 0a $1 119 #+end_src 120 121 With cursor inside the source code block: 122 ~C-c C-c~ :: to run the program and see the output 123 ~C-c C-v k~ :: to remove (kill) the result again 124 125 *Try this now!* 126 127 Change the program to print a second line of text after =Hello World!= 128 129 * Behavioural analysis 130 #+begin_src uxntal :eval never 131 ;text while ( reference 'text' variable defined below ) 132 BRK 133 @while ( &str* -- ) 134 LDAk DUP ?{ 135 POP POP2 JMP2r } 136 #18 DEO 137 INC2 !while 138 139 @text "Hello 20 "World! 0a $1 140 #+end_src 141 142 1) program produces the output =Hello␣World!⬎= 143 144 2) output is similar to the line introduced by src_uxntal{@text} 145 146 3) src_uxntal{@text} seems to be a string characters 147 148 4) src_uxntal{@while ( ... -- )} is the program 149 150 5) src_uxntal{@text} is the data 151 152 * Syntax analysis 153 #+begin_src uxntal :eval never 154 ;text while ( reference 'text' variable defined below ) 155 BRK 156 @while ( &str* -- ) 157 LDAk DUP ?{ 158 POP POP2 JMP2r } 159 #18 DEO 160 INC2 !while 161 162 @text "Hello 20 "World! 0a $1 163 #+end_src 164 165 src_uxntal{( ... )} :: commentary 166 167 src_uxntal{DUP BRK POP while !while} :: program text 168 169 src_uxntal{18 20 0a} :: numbers. To the number *base 16* and not 10! 170 171 src_uxntal{"Hello} character strings (ending at the next space, not the second ="=) 172 173 src_uxntal{@text ;text} are variables? 174 175 * Help yourself! 176 #+begin_src uxntal :eval never 177 ;text while ( reference 'text' variable defined below ) 178 BRK 179 @while ( &str* -- ) 180 LDAk DUP ?{ 181 POP POP2 JMP2r } 182 #18 DEO 183 INC2 !while 184 185 @text "Hello 20 "World! 0a $1 186 #+end_src 187 188 With cursor inside the source code block: 189 ~C-c C-h~ :: 190 - on a word prints a short explanation in the echo area 191 - on a number prints the decimal value in parenthesis 192 193 *Try this now!* 194 195 ** Uxntal language reference 196 197 Open =Uxntal-reference.org= and fit the window (~M-x fit-window-to-buffer~) 198 199 Full language reference [[elisp:(man "-l uxntal.7")][manpage]] (open with ~C-c C-o~ while cursor on link) 200 201 * Structural analysis 202 #+begin_src uxntal :eval never 203 ;text while 204 BRK 205 @while ( ### -- ) 206 #### ### ?{ 207 ### #### ### } 208 #18 ### 209 #### !while 210 211 @text "xyz 20 "xyz 0a $1 212 #+end_src 213 214 1) Actions (blue) are grouped by indentation 215 216 2) Actions (blue) and data (green, orange) structured by 217 218 - labelling (=@<word>= notation) 219 220 - curly braces (=?{ ... }= notation) 221 222 3) Program is a series of actions *not* a composition of functions (in mathematical sense) 223 224 4) Processor executes program instruction by instruction, one blue word after another 225 226 * Semantic analysis – simplify 227 #+begin_src uxntal 228 ;text 229 ( @while '( &str* -- )' ) 230 LDAk DUP ?{ 231 POP POP2 BRK } 232 #18 DEO 233 BRK ( INC2 !while ) 234 235 @text "Hello 20 "World! 0a $1 236 #+end_src 237 238 *Try this now!* 239 240 Run the program 241 242 ** Further Simplification 243 244 #+begin_src uxntal 245 LIT "H #18 DEO 246 #+end_src 247 248 *Discussion* 249 250 * Execution by machine 251 252 Memory content (what the machine actually sees) 253 #+begin_src uxntal :rom dis 254 LIT "H #18 DEO 255 #+end_src 256 257 #+RESULTS: 258 #+begin_src text 259 |0100 80 48 ( #48 ) 260 |0102 80 18 ( #18 ) 261 |0104 17 ( DEO ) 262 #+end_src 263 264 ** Example execution 265 #+begin_src text 266 Control Unit Random access memory 267 Working Stack ¦ +------------+ ·~ ~ ~ · ~ ~ ~ ~ ~ ~ ~ ~ · 268 · ··~-+----+----+----+----+---+ ¦ IF / ID ¦ <------> | 0100 | 80 (LIT) | 269 | | | | | <----> ¦ Ex / LS ___¦ <--+ +- - - +-----------------+ 270 · ··~-+----+----+----+----+---+ +--> ¦ | PC¦ | | 0101 | 48 ("H) | 271 ¦ | +--------+---+ | +- - - +-----------------+ 272 Return Stack ¦ | ↑ | | | 0102 | 80 (#) | 273 · ··~-+----+----+----+----+---+ | | | | +- - - +-----------------+ 274 | | | | | <-+ | | | | 0103 | 18 (18) | 275 · ··~-+----+----+----+----+---+ | | | +- - - +-----------------+ 276 ¦ | | | | 0104 | 17 (DEO) | 277 | ↓ | ·~ ~ ~ · ~ ~ ~ ~ ~ ~ ~ ~ · 278 +---------------------+ | 279 ¦ ¦ | Device memory 280 ¦ + / − / ≤ / ∨ / ∧ ¦ | +- + -+-----------------+ 281 ¦ ¦ +----> | 0:0 | | 282 +---------------------+ · ~ ~ · ~ ~ ~ ~ ~ ~ ~ ~ · 283 Arith. Logic Unit | 1:8 | | 284 +- + -+-----------------+ 285 #+end_src 286 287 * Understanding Uxntal 288 289 - Representation :: symbolised language → instructions and data are numbers in memory 290 - Order :: program is the memory image that the UXN computer operates on 291 292 ** Labels 293 #+begin_src uxntal :rom dis 294 ;text 295 @while ( str* -- ) 296 POP POP !while 297 @text "Hello 298 #+end_src 299 300 src_uxntal{@text @while ( -- )}, symbolic references to instructions and data 301 - provide malleable targets, e.g., src_uxntal{;text !while} 302 - *assign names to numbers* 303 - help maintaining consistency and intent 304 - *immaterial* → do not appear in memory 305 306 ** Intrinsics 307 #+begin_src uxntal :rom dis 308 ;text 309 @while ( &str -- ) 310 POP POP !while 311 @text "Text 312 #+end_src 313 314 UXN processor instructions 315 - in capital letters, e.g., src_uxntal{POP INC2 LDA2k} 316 - *material* → appear exactly where you put them 317 - fundamental units of compute 318 - cannot be changed, introspected or taken apart 319 320 Intrinsics have *three modes* appended to their names, e.g., src_uxntal{INC2 STHk JMP2r} 321 - 2 (short) :: operate on *two bytes*, instead of single bytes 322 - k (keep) :: *do not consume* elements on stack 323 - r (return) :: operate on other stack (usually *return stack*) 324 325 ** Runes 326 #+begin_src uxntal :rom dis 327 ;text while 328 BRK 329 @while ( &str* -- ) 330 LDAk DUP ?{ 331 POP POP2 JMP2r } 332 #18 DEO 333 INC2 !while 334 335 @text "Hello 20 "World! 0a $1 336 #+end_src 337 338 Language keywords – single-letter (prefix) symbols 339 - e.g., =@ ; $ # ? { }= 340 - translate symbols (e.g. labels, strings) into numbers and intrinsics 341 - can be either *material* or *immaterial* 342 343 * Runes explained 344 #+begin_src uxntal :rom dis 345 ;text while 346 BRK 347 @while ( str* -- ) 348 LDAk DUP ?{ 349 POP POP2 JMP2r } 350 #18 DEO 351 INC2 !while 352 353 @text "Hello 20 "World! 0a $1 354 #+end_src 355 356 ~;~ :: Refer to a memory location via a label → /Push named memory location onto stack/ *[ ]* 357 358 ~@~ :: Define a label → /Give a memory location a name/ *[ ]* 359 360 ~?{ }~ :: Conditional jump → /Produce code to execute code under condition/ *[ ]* 361 362 ~#~ :: Literal number → /Produce code to push number onto stack/ *[ ]* 363 364 *Which runes are (im-)material? ('i'/'m')* 365 366 * Runes explained (contd.) 367 #+begin_src uxntal :rom dis 368 ;text while 369 BRK 370 @while ( str* -- ) 371 LDAk DUP ?{ 372 POP POP2 JMP2r } 373 #18 DEO 374 INC2 !while 375 376 @text "Hello 20 "World! 0a $1 377 #+end_src 378 379 ~!~ :: Unconditional jump. /Produce code to jump to label/ *[ ]* 380 381 ~"~ :: Raw character string. /Write numeric values of characters into memory/ *[ ]* 382 383 ~$~ :: Relative pad. /Move address of next program fragment by value/ *[ ]* 384 385 * Arithmetic and logic 386 387 Uxntal instructions *do not* take arguments 388 389 They operate on the current bytes on the stack 390 391 ** Example 392 #+begin_src uxntal :run bin 393 #12 #13 ADD byte. 394 #02 #04 MUL byte. 395 #03 #02 DIV byte. ( Integer division! Fractional part truncated! ) 396 #03 #02 GTH byte. 397 #00 #01 acc. #02 acc. #03 acc. 398 399 BRK 400 401 @byte. ( b -- ) 402 #18 DEO JMP2r 403 404 @acc. ( a b -- c ) 405 ADD DUP byte. JMP2r 406 #+end_src 407 408 * Memory operation 409 410 *Data* is either: 411 - loaded :: copied from memory to stack 412 - stored :: moved/copied from stack to memory 413 - consumed :: moved/copied from stack and computed on 414 - produced :: moved from Arith. Logic Unit onto stack 415 - stashed :: moved/copied between stacks 416 417 ** Loading data 418 #+begin_src uxntal :rom dis 419 #12 420 LIT 13 421 LIT2 1415 422 #1617 423 .data 424 ,data 425 ;data 426 427 @data 05 "Hello 428 #+end_src 429 430 ** Consume / produce data 431 #+begin_src uxntal :run bin 432 #02 #03 ADD #01 SUB byte. 433 #03 #04 ADDk SUB SUB byte. 434 BRK 435 @byte. ( b -- ) 436 #18 DEO JMP2r 437 #+end_src 438 439 ** Storing data 440 #+begin_src uxntal :rom dis 441 #12 #05 STZ 442 #13 #06 STR 443 #14 ;data STA 444 445 @data 05 "Hello 446 #+end_src 447 448 * Stack operation (advanced) 449 450 ** Algorithm 451 1) Get number =n= of elements on working stack 452 2) If =n > 0= then goto 3) else Stop 453 3) print top element on working stack 454 4) Goto 1) 455 456 ** Program 457 #+begin_src uxntal :run bin 458 |04 @System/wst 459 460 |100 461 @on-reset ( -> ) 462 #01 #02 #03 #04 #05 463 wst. 464 #05 465 wst. 466 BRK 467 468 @wst. ( ... -- ... ) 469 LITr -System/wst DEIr ( { orig-wst } ) 470 &loop [ 471 LITr -System/wst ( { dev orig-wst } ) 472 DEIr ( { wst orig-wst } ) 473 LITr 01 LTHr ( { done? orig-wst } ) 474 LITr _/done JCNr 475 STH ( { a done? orig-wst } ) 476 LITr 18 DEOr 477 ] !/loop 478 &done 479 LITr -System/wst DEOr 480 JMP2r 481 #+end_src 482 483 * Words 484 485 Intrinsics and labels which are used as instructions are called *words* 486 #+begin_src uxntal :eval never 487 ADD LIT ( intrinsics are words ) 488 @foo ( -- ) JMP2r ( blue labels are words ) 489 @data 1234 "text ( red labels are data ) 490 #+end_src 491 492 No *substantial* difference between data and instructions! 493 494 Colours (red, blue, orange, green) show the *intended* meaning! 495 496 *Actual* meaning is determined by the position in memory. 497 498 Words provide *intention* and make instruction patterns reusable 499 500 * Defining new words 501 502 To define a word =foo=, write 503 #+begin_src uxntal :eval never 504 @foo ( a* b c -- d ) 505 POP POP POP2 506 JMP2r 507 #+end_src 508 509 Consumes *three* elements on stack 510 - =c= :: a byte 511 - =b= :: also a byte 512 - =a*= :: a short (two bytes, signified by =*=) 513 514 Puts *one* elements on stack 515 - =d= :: a byte 516 517 Word definition promises that: 518 - it consumes (pops) *four bytes* off stack (neither more, nor less!) 519 - it pushes back *one byte* onto stack 520 - both effects may not be offset against each other! 521 522 * Calling words 523 524 *Calling a word* means executing instructions from a *different location* 525 526 ** Linear execution 527 #+begin_src uxntal :rom dis :wrap src uxntal 528 #10 DUP INC SWP SUB POP 529 #+end_src 530 531 #+RESULTS: 532 #+begin_src uxntal 533 |0100 80 10 ( #10 ) 534 |0102 06 ( DUP ) 535 |0103 01 ( INC ) 536 |0104 04 ( SWP ) 537 |0105 19 ( SUB ) 538 |0106 02 ( POP ) 539 #+end_src 540 541 Executes always the *next* instruction, =100=, =102=, =103=, ... 542 543 ** Calling a word 544 #+begin_src uxntal :rom dis :wrap src uxntal 545 |100 #00 #20 #02 mac #10 #04 mac 546 @mac ( c a b -- c' ) MUL ADD JMP2r 547 #+end_src 548 549 #+RESULTS: 550 #+begin_src uxntal 551 |0100 80 00 ( #00 ) 552 |0102 80 20 ( #20 ) 553 |0104 80 02 ( #02 ) 554 |0106 60 00 07 ( mac ) 555 |0109 80 10 ( #10 ) 556 |010b 80 04 ( #04 ) 557 |010d 60 00 00 ( mac ) 558 559 @mac 560 |0110 1a ( MUL ) 561 |0111 18 ( ADD ) 562 |0112 6c ( JMP2r ) 563 #+end_src 564 565 *** Observations 566 At call of src_uxntal{|0106 mac} 567 - execution continues at memory location src_uxntal{|0110} 568 - src_uxntal{JMP2r} *returns* to memory location src_uxntal{|0109} 569 - execution continues at that memory location 570 571 Executes =100=, =102=, =104=, =106= → =110=, =111=, =112= → =109= 572 573 * Different types of word calls 574 :PROPERTIES: 575 :CUSTOM_ID: while-loops 576 :END: 577 578 Not all calls are supposed to return 579 #+begin_src uxntal 580 ;text while ( reference 'text' variable defined below ) 581 BRK 582 @while ( &str* -- ) 583 LDAk DUP ?{ 584 POP POP2 JMP2r } 585 #18 DEO 586 INC2 !while 587 588 @text "Hello 20 "World! 0a $1 589 #+end_src 590 591 src_uxntal{!while} jumps without return: 592 - unconditional jump (i.e., *always jump*) 593 - this makes a loop 594 595 src_uxntal{?...} jumps also without return 596 - conditional jump (i.e., *jump if ...*) 597 - loop is terminated inside the construct with src_uxntal{BRK} 598 599 ** Loops 600 #+begin_src text 601 +----------------------+ 602 | lb LDAk (@while) |<---+ 603 | lb DUP | | 604 | lh JCI (?{) |--+ | 605 | lh ... | | | 606 +--| lh BRK | | | 607 | | lb #18 (} ) |<-+ | 608 | | lb ... | | 609 | | lb JMI (!while) |----+ 610 | +----------------------+ 611 | 612 +-> ... 613 #+end_src 614 615 * Stack effect notation (advanced) 616 617 Comment src_uxntal{ @f ( ... -- ... ) } is the *stack effect notation* 618 619 1. Purely informational for assembler 620 2. Used for sanity checking word definitions 621 3. Multiple forms: 622 - src_uxntal{ @f ( ... -- ... ) } :: untyped stack effect 623 - not sanity checked 624 - word returns to call site 625 - src_uxntal{ @f ( ... -: ... ) } :: typed stack effect 626 - sanity checked, bytes counted 627 - word returns to call site 628 - src_uxntal{ @f ( ... -> ... ) } :: vector 629 - sanity checked, bytes *not* counted 630 - word *does not* return 631 632 4. Stack value notations: 633 - src_uxntal{ ( a, a^ ) } :: single-byte value 634 - src_uxntal{ ( b* ) } :: short (two-byte) value 635 - src_uxntal{ ( -- ) } :: *no* values consumed/produced 636 - src_uxntal{ ( ... -- ... ) } :: *unknown* number of values 637 638 * Development tools 639 640 Select what is done with a Uxntal source block via header arguments 641 #+begin_src org :results replace 642 ,#+begin_src uxntal 643 ,|100 644 @on-reset ( -> ) 645 POPk #10 #18 DEO BRK 646 ,#+end_src 647 #+end_src 648 649 Common header arguments: 650 | Header argument | Value | Action | 651 |-----------------+------------------+---------------------------------------------------| 652 | :rom | t | Print ROM contents instead of running program | 653 | | dis | Print disassembled ROM contents | 654 | :run | debug | Run program in graphical debugger | 655 | | | (limited text output, no input) | 656 | | bin | Print output as hexadecimal (to see non-printable | 657 | | | characters or numeric results) | 658 | | interactive | Run program in interactive shell | 659 | | graphical | Run as graphical program | 660 | :results | none | Do not print any output | 661 | :wrap | "src uxntal ..." | Print output as Uxntal source block | 662 663 * Graphical step debugger beetbug 664 #+attr_html: :width 1000px :align center 665 [[file:img/2_beetbug.png]] 666 667 ~F1~ :: scale graphical display by 2x, then 3x ([[https://wiki.xxiivv.com/site/beetbug.html][full doc➚]]) 668 #+begin_src text 669 +-------------------------------------------------------+ 670 | 0100 Work Return ⏮ ▶ → | 671 | program ctr. (PC) Stack Stack reset run step | 672 | | 673 | disassembled code memory content | 674 +-------------------------------------------------------+ 675 #+end_src 676 677 * Debugging a program 678 679 Run the code below 680 681 *Try this now!* 682 683 #+begin_src uxntal :run debug :results none 684 ;text while ( reference 'text' variable defined below ) 685 BRK 686 @while ( &str* -- ) 687 LDAk DUP ?{ 688 POP POP2 JMP2r } 689 #18 DEO 690 INC2 !while 691 692 @text "Hello 20 "World! 0a $1 693 #+end_src 694 695 * Controlling debug – breakpoints 696 697 [[https://wiki.xxiivv.com/site/varvara.html#system][System device➚]] =System/debug= halts execution at point of its access, called *breakpoint* 698 699 *Try this now* 700 #+begin_src uxntal :run debug :results none 701 ;text while ( reference 'text' variable defined below ) 702 BRK 703 @while ( &str* -- ) 704 LDAk DUP ?{ 705 POP POP2 JMP2r } 706 #18 DEO 707 debug ( <- breakpoint ) 708 INC2 !while 709 710 @debug ( -- ) [ LIT2 01 -System/debug ] DEO JMP2r 711 712 @text "Hello 20 "World! 0a $1 713 714 |0e @System/debug 715 #+end_src 716 717 * Excursion: Labels and scope 718 719 - src_uxntal{@... } :: Top-level or *scope* label 720 - src_uxntal{$...} :: Sub-scope label 721 722 *Example* 723 #+begin_src uxntal :eval never 724 @strlen ( str* -- n* ) 725 LIT2r 0000 726 &l ( -- ) 727 LDAk ?{ POP2 STH2r JMP2r } 728 INC2r INC2 !&l 729 #+end_src 730 731 src_uxntal{&l} ≡ src_uxntal{@strlen/l} 732 Benefit: 733 - meaning of =l= limited to scope =strlen= → =l= reusable in different scope 734 - can be called with src_uxntal{!&l} → renaming =strlen= does not break call to =l= 735 736 * Labels – effective use 737 738 ** Constants 739 Define a complex structured constant like the [[https://wiki.xxiivv.com/site/varvara.html#console][Console device➚]] ports 740 #+begin_src uxntal :eval never 741 |10 @Console/vector $2 &read $1 &unused $4 &type $1 &write $1 &error $1 742 743 |100 @on-reset ( -> ) ;on-console .Console/vector DEO BRK 744 @on-console ( -> ) .Console/read DEI POP BRK ( read one char ) 745 #+end_src 746 747 ** Scoped words & data 748 749 Define a fixed buffer with a capacity pointer =cap= 750 #+begin_src uxntal :run interactive :results none 751 <<lib.org:defs()>> 752 |00 @Console/buf [ $1f &cap $1 ] 753 754 |100 @on-reset ( -> ) ;Console/on-console .Console/vector DEO2 BRK 755 756 @Console/on-console ( -> ) 757 .&read DEI 758 DUP #0a NEQ ?{ ;&buf str. #800f DEO BRK } ( print &buf and halt ) 759 [ LIT2 -&cap &ptr -&buf ] ( keep location of last char in &buf here ) 760 ( clamp ) NEQk ?{ POP POP2 BRK } ( do not overrun &cap (size of &buf)! ) 761 INCk ,&ptr STR 762 NIP STZ BRK 763 764 <<lib.org:lib()>> 765 #+end_src 766 767 * Text output 768 769 Run the code below 770 771 With cursor inside source code block: 772 ~C-c C-v C-v~ :: Show full source block in separate window 773 774 With cursor inside full source window: 775 ~C-x C-s~ :: Save expanded code back into original file 776 777 *Try this now!* 778 779 1. Play with the code and find out how it works 780 781 2. Change the code to print the length of the original string as well. 782 783 3. Refactor (rewrite) the code to re-use =Length:␣= prefix string instead of copying it 784 785 *Hint:* Indentation and square brackets =[]= purely cosmetic to clarify *intention* of the code 786 787 Time: *15 minutes* 788 #+begin_src uxntal 789 ( 790 @|Common constants ) 791 <<lib.org:defs()>> 792 793 |100 794 @on-reset ( -> ) 795 { "---- -+ "Text -+ "output -+ "---- -^NL $1 } strr. 796 ;&txt-label str. 797 ;&txt str. 798 ;&cpy-label str. 799 ;&cpy str. 800 801 ;&cpy ;&txt copy-str 802 DUP2 [ 803 ;&txt-label str. str. 804 strlen ] 805 DUP2 [ 806 { "Length: -+ $1 } strr. dec. NL. 807 LIT2 "0x short. hex. NL. ] 808 BRK 809 810 &txt-label "orig: -+ $1 811 &cpy-label "copy: -+ $1 812 &txt "This -+ "is -+ "the -+ "original -^NL $1 813 &cpy "This -+ "is -+ "the -+ "copy -^NL $1 814 815 ( 816 @|Library code ) 817 <<lib.org:lib()>> 818 #+end_src 819 820 * Excursion: numbers and computation 821 822 Common number system: Ten digits. 0 to 9 823 824 825 Simplest decision: Yes / No 826 827 Simplest result: True / False 828 829 830 Simplest number system: Two digits. Say, 0 and 1 831 832 * Control structures 833 834 Control structures make programs compact and versatile 835 836 They must: 837 1) break the linear program flow and *jump* to a remote location 838 2) read data as a *condition* whether to jump or continue 839 840 Uxntal control instructions: 841 - src_uxntal{?} :: continues execution at the location *next in memory* 842 843 Used almost exclusively. New program location known ahead of time. 844 845 - src_uxntal{JCN} :: continues execution at the location *on top of stack* 846 847 Rarely used. New program location depends on other factors unknown ahead of time. 848 849 ** Decisions 850 851 *Try this now!* 852 853 Run the example. Observe the difference in the implementation of =more-than= and =more-than'=. 854 855 *Discussion* 856 857 #+begin_src uxntal 858 <<lib.org:defs()>> 859 |100 #16 #15 [ LIT2r =more-than ] { !more-than' } 2bi BRK 860 861 @more-than ( x y -- ) 862 GTH ?yes 863 !no 864 865 @more-than' ( x y -- ) 866 GTH ?{ { "No -^NL $1 } strr. JMP2r } 867 { "Yes -^NL $1 } strr. JMP2r 868 869 @yes ( -- ) { "Yes -^NL $1 } strr. JMP2r 870 @no ( -- ) { "No -^NL $1 } strr. JMP2r 871 <<lib.org:lib()>> 872 #+end_src 873 874 ** Loops 2 875 :PROPERTIES: 876 :CUSTOM_ID: for-loops 877 :END: 878 879 Up- and down-counting loops. 880 881 See [[file:lib.org::#dotimes-combinators][dotimes-up, dotimes-down combinators]] for general solution 882 #+begin_src uxntal 883 <<lib.org:defs()>> 884 885 |100 #0a dotimes-down' BRK 886 @dotimes-down' ( cnt [q*] -- ) 887 &l ( cnt -- cnt' ) 888 DUP #00 EQU ?{ 889 DUP bdec. { ". -+ "time -^NL $1 } strr. 890 #01 SUB !&l } 891 POP JMP2r 892 <<lib.org:lib()>> 893 #+end_src 894 895 #+begin_src uxntal 896 <<lib.org:defs()>> 897 898 |100 #0a dotimes-up' BRK 899 @dotimes-up' ( lim -- ) 900 #00 ( ctr ) 901 &l ( lim ctr -- lim ctr' ) 902 DUP2 EQU ?{ 903 INC 904 DUP bdec. { ". -+ "time -^NL $1 } strr. 905 !&l } 906 POP JMP2r 907 <<lib.org:lib()>> 908 #+end_src 909 910 * Construction of numbers 911 912 ** Numbers as multiples of a unit length 913 #+begin_src txt 914 + length 0 915 +-+ length 1 916 +-+-+ length 2 917 +-+-+-+-+ length 4 918 +-+-+-+-+-+-+-+-+ length 8 919 920 0 1 2 921 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ length 20 922 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 923 #+end_src 924 925 ** Numbers as strings of digits in order of magnitude 926 927 *Big endian* 928 =142 = ... + 0 × 10ⁿ + ... + 0 × 10³ + 1 × 10² + 4 × 10¹ + 2 × 10⁰= 929 930 *Little endian* 931 =142 = 2 + 10 × (4 + 10 × (1 + 10 × (0 + 10 × ( ... ))))= 932 933 * Alternative number bases 934 935 ** Base 2 – binary 936 #+begin_src text 937 0 1 938 +- - - - - - - - - - - - - - - -+- - - - - - - - - - - - - - - -+ 939 0 1 0 940 +- - - - - - - -+- - - - - - - -+- - - - - - - -+- - - - - - - -+ 941 0 1 0 1 0 942 +- - - -+- - - -+- - - -+- - - -+- - - -+- - - -+- - - -+- - - -+ 943 0 1 0 1 0 1 0 1 0 944 +- -+- -+- -+- -+- -+- -+- -+- -+- -+- -+- -+- -+- -+- -+- -+- -+ 945 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 946 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 947 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 948 #+end_src 949 950 ** Base 16 – hexadecimal 951 #+begin_src text 952 0 1 2 953 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 954 0 1 2 3 4 5 6 7 8 9 a b c d e f 0 1 2 3 4 5 6 7 8 9 a b c d e f 0 955 #+end_src 956 957 * Finite number space 958 959 ** 5 bit (binary digit) number space 960 #+begin_src text 961 0 1 0 962 +- - - - - - - - - - - - - - - -+- - - - - - - - - - - - - - - -+ 963 0 1 0 1 0 964 +- - - - - - - -+- - - - - - - -+- - - - - - - -+- - - - - - - -+ 965 0 1 0 1 0 1 0 1 0 966 +- - - -+- - - -+- - - -+- - - -+- - - -+- - - -+- - - -+- - - -+ 967 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 968 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 969 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 970 ↑ rolling over 971 #+end_src 972 973 *How many different numbers?* 974 975 ** Collections of bits 976 977 - Byte :: string of *8 bits* 978 - Depending on context, ranges from 5–9 bits length 979 - Basic unit of memory: 980 - 1 stack position ≔ 1 byte 981 - 1 memory address / byte 982 - *Notation* =1 B=, =128 B= 983 984 - Nibble :: string of *4 bits*, i.e., one hexadecimal digit 985 986 - Short :: string of *2 bytes*, i.e., 16 bits 987 988 | Notation | Nibble | Byte | Short | 989 |-------------------+--------+------------+------------------------| 990 | Binary (·₂) | 0101 | 1001'0110 | 0111'1011'0000'1000 | 991 | | | | | 992 | Hexadecimal (·₁₆) | 4, a | 00, 0a, 5c | fffe, 0001, abcd, ad8e | 993 994 ** Important relations 995 996 - 1 byte :: 2 nibbles → high nibble, low nibble 997 998 e.g. =1001'0110₂= ≡ =96₁₆= → =1001₂=, =9₁₆= (high n.), =0110₂=, =6₁₆= (low n.) 999 1000 1001 - 1 short :: 2 bytes → high byte, low byte 1002 1003 e.g. =f784₁₆= → =f7₁₆= (high B.), =84₁₆= (low B.) 1004 1005 * Numeric operations 1006 1007 ** Addition / Subtraction 1008 1009 Operations "roll over" at the end of the number space. 1010 Apart from roll over, the operations are complete. 1011 #+begin_src uxntal :run bin 1012 #ff #01 ADD byte. 1013 #00ff #0001 ADD2 short. 1014 #fe #05 ADD byte. 1015 #02 #04 SUB byte. 1016 1017 BRK 1018 @short. ( s* -- ) SWP byte'. !byte'. 1019 @byte. ( b -- ) #cc byte'. ( >> ) 1020 @byte'. ( b -- ) #18 DEO JMP2r 1021 #+end_src 1022 1023 ** Multiplication 1024 1025 Multiplication rolls over as well 1026 #+begin_src uxntal :run bin 1027 #40 DUP MUL byte. 1028 #7f DUP MUL byte. 1029 1030 BRK 1031 @byte. ( b -- ) #cc byte'. ( >> ) 1032 @byte'. ( b -- ) #18 DEO JMP2r 1033 #+end_src 1034 1035 ** Division 1036 1037 Division is *not* mathematically complete and only keeps the integral part 1038 #+begin_src uxntal :run bin 1039 #05 #02 DIV byte. 1040 1041 BRK 1042 @byte. ( b -- ) #cc byte'. ( >> ) 1043 @byte'. ( b -- ) #18 DEO JMP2r 1044 #+end_src 1045 1046 * Text input 1047 1048 Run the code below 1049 1050 *Try this now!* 1051 1052 1. Change the program such that it ends after 3 inputs 1053 2. Study the [[https://wiki.xxiivv.com/site/varvara.html#console][Console device➚]] to learn about =Console/...= 1054 3. Change the program again such that the first user input is the 1055 number of inputs after which the program should end 1056 1057 Time: *30 minutes* 1058 #+begin_src uxntal :run interactive :results none 1059 ( Common constants ) 1060 <<lib.org:defs()>> 1061 1062 |000 1063 @t/buf $2f &cap $1 1064 1065 |100 1066 @on-reset ( -> ) 1067 { "---- -+ "Text -+ "input -+ "---- -^NL $1 } strr. 1068 ;t/on-console .Console/vector DEO2 1069 t/prompt 1070 BRK 1071 1072 @t/prompt ( -- ) 1073 { "Your -+ "input -+ "(end -+ "with -+ "return): -+ $1 } strr. 1074 JMP2r 1075 1076 @t/on-console ( -> ) 1077 [ LIT2 02 -Console/type ] DEI LTH ?{ .Console/read DEI !/on-push } 1078 BRK 1079 1080 @t/on-push ( c -> ) 1081 DUP .^CR EQU ?/on-done ( handle carriage-return control character ) 1082 DUP .^NL EQU ?/on-done ( handle new-line control character ) 1083 DUP #1f GTH ?{ POP BRK } ( drop any other non-printable character ) 1084 [ LIT2 -&cap &ptr -&buf ] ( keep location of last char in &buf here ) 1085 ( clamp ) NEQk ?{ POP POP2 BRK } ( do not overrun &cap (size of &buf)! ) 1086 INCk ,&ptr STR 1087 NIP STZ 1088 BRK 1089 1090 @t/on-done ( c -> ) 1091 POP [ LIT2 -&buf _&ptr ] LDR 1092 ( empty input? ) EQUk ?terminate 1093 { "Got: -+ $1 } strr. 1094 ( 0-term. string ) #00 ,&ptr LDR INCk ,&ptr STR STZ 1095 ;&buf str. NL. 1096 ( reset input ptr ) .&buf ,&ptr STR 1097 t/prompt 1098 BRK 1099 1100 @terminate ( -> ) 1101 #80 .System/state DEO BRK 1102 1103 ( Library code ) 1104 <<lib.org:lib()>> 1105 #+end_src 1106 1107 * Excursion – The Art of Computer Programming 1108 1109 Generally, you need a high frustration tolerance 1110 1111 Your patient (the computer program) 1112 - does neither heal on its own, 1113 - nor does it die when you ignore it 1114 1115 It stays infuriatingly the same (misbehaving program) until *you* fix it 1116 1117 Additionally: 1118 Wrong programs behave *chaotically*! (As opposed to people which behave /irrationally/) 1119 1120 → one single wrong byte can make a program do something entirely different! 1121 1122 read: [[doi:10.1145/3726485]["Analyzing Krazy Kode"]] 1123 1124 ** "Rules of engagement" 1125 1126 1) Note down the expected actions of a program in your own words. 1127 Start with a coarse description 1128 1129 2) Pick a part of the problem that you think, you have understood 1130 (not necessarily the first item). 1131 Implement it as a simple program with synthetic input 1132 1133 3) Make use of documentation and helpful tools (e.g., ~C-c C-h~). 1134 Split the Emacs frame (~C-x 3~, ~C-x 1~) to show docs and code side by side 1135 1136 4) Pick names for words and structure your code that shows your *intention* 1137 1138 5) When unsure /why/ a word does not work, make a copy and work on it in a smaller 1139 program (see point 2). *Copies are cheap.* 1140 1141 6) Do not throw away old code early. It contains thoughts that may turn out valid after all 1142 1143 7) When you understand your misconception, refine your notes from 1) 1144 1145 8) Once your code works, tidy it up, document it 1146 1147 9) Grow your program from your working nucleus. If necessary, rework your code in 1148 isolation until it fits the larger program 1149 1150 * Exercise – Writing a game 1151 1152 1) Write the following game; you may use the code below as a starting point! 1153 1154 Use your knowledge from previous examples on how to structure code, store data and make 1155 decisions. 1156 1157 The rules of the game are: 1158 1) Each turn you roll a die. The points you rolled are added to your total. 1159 2) You may stop at any time and keep the total as your win. 1160 3) If you keep rolling and roll a =1=, you lose all your points and the program ends. 1161 1162 The rolled die and the total is printed after each roll. 1163 1164 2) Instead of ending the program, ask whether the player wants to play another round. 1165 Additionally, print the high score of all rounds at the end of each game. 1166 1167 3) (/Advanced/) Read up on the [[https://wiki.xxiivv.com/site/varvara.html#file][File device]] and implement a permanent high score file! 1168 Print an additional message after each game presenting the current high score and 1169 whether the player has beaten it. Next, implement a high score table with 4 1170 entries and ask for the players name. 1171 1172 Some guidance to help with your task: 1173 1174 1. Read through the rules and write down the steps that the program has to take. E.g.: 1175 1) ask player whether to continue or end the game 1176 2) read user input and decide: yes (→3) no (→n) 1177 3) roll die 1178 4) ... 1179 n) end program with a win 1180 1181 Remember to come back to this list whenever you find an error or when you need to add 1182 more steps! 1183 1184 2. Run src_uxntal{rnd'} in isolation to see what it does. Implement src_uxntal{roll} that 1185 always produces a number between 1 and 6. 1186 1187 #+begin_src uxntal :run interactive 1188 <<lib.org:defs()>> 1189 1190 |100 @on-reset ( -> ) 1191 ( setup ... ) 1192 BRK 1193 1194 @rnd' ( -- r ) 1195 [ LIT2 &r f793 ] 1196 ( 5*R+35 ) #0005 MUL2 #0023 ADD2 1197 ( R-R/6547*6547 ) DUP2 #1993 DIV2 #1993 MUL2 SUB2 1198 .Datetime/minute DEI2 ADD2 { ,&r STR2 JMP2r } keep2 ADD 1199 JMP2r 1200 1201 @input ( -> ) 1202 ( handle user input ) 1203 BRK 1204 1205 ( ... game logic ... ) 1206 1207 <<lib.org:lib()>> 1208 #+end_src