1. Contest #2... Example Programs
- Posted by jeremy (admin) Dec 08, 2010
- 3301 views
- Last edited Dec 09, 2010
Sample programs are wanted. Do you have one that does something pretty cool? Please post the program here and let us know what it does. Remember to include the program inside of {{{ }}} tags.
See message:113859 for contest details
Jeremy
2. Re: Contest #2... Example Programs
- Posted by jimcbrown (admin) Dec 08, 2010
- 3311 views
Here is a very simple program that just starts a counter at 1, and goes into a loop forever incrementing and printing the counter out.
201 213 223 ?0 301 012
3. Re: Contest #2... Example Programs
- Posted by jimcbrown (admin) Dec 08, 2010
- 3263 views
Here is a more complex program that counts from 1 to 5
201 240 904 241 904 242 904 243 904 244 904 245 904 219 316 ?0 301 820 012 100
4. Re: Contest #2... Example Programs
- Posted by PeteE Dec 09, 2010
- 3265 views
- Last edited Dec 12, 2010
201 r0=1 *** count to 100 *** 215 r1=5 611 r1+=r1 (10) 711 r1*=r1 (100) 901 [r1]=r0 (1) 236 r3=6 (address of next line) ?0 ? r0 990 [r0]=r9 (0) 301 r0+=1 821 r2=[r1] 032 goto r3 if r2 100 halt
201 r0=1 *** print fibonacci sequence *** 215 r1=5 711 r1*=r1 (25) 901 [r1]=r0 (1) 240 r4=0 251 r5=1 ?5 ? r5 237 r3=8 (address of next line) 564 r6=r4 665 r6+=r5 ?6 ? r6 545 r4=r5 556 r5=r6 990 [r0]=r9 (0) 301 r0+=1 821 r2=[r1] 032 goto r3 if r2edit: Dec 11
866 r6=[r6] (-1) *** primes up to 1000 *** 278 r7=8 475 r7*=5 (40) 475 r7*=5 (200) 475 r7*=5 (1000) 776 r7*=r6 (-1000) 202 r0=2 (2 is first prime) 810 r1=[r0] (is prime when r1=0) 295 r9=5 494 r9*=4 (20) 091 if r1 not_prime ?0 (print prime) 530 r3=r0 (init counter) 540 r4=r0 (init index) 341 r4+=1 554 r5=r4 (label2:) 657 r5+=r7 (subtract 1000) 299 r9=9 493 r9*=3 (27) 095 if r5 label3 301 r0+=1 550 r5=r0 657 r5+=r7 (subtract 1000) 297 r9=7 095 if r5 main_loop 100 halt 300 nop 636 r3+=r6 (subtract 1) 299 r9=9 398 r9+=8 (17) 492 r9*=2 (34) 093 if r3 label4 904 [r4]=r0 (write nonzero to ram) 530 r3=r0 (reset counter) 341 r4+=1 295 r9=5 493 r9*=3 (15) 094 if r4 label2
5. Re: Contest #2... Example Programs
- Posted by jeremy (admin) Dec 09, 2010
- 3240 views
fibonacii (25)
NOTE This requires the amended spec that ram address zero is initialized to -1.
295 - r9 = 5 (loop counter) 799 - r9 *= r9 (25) 210 - r0 = 0 (first) 221 - r1 = 1 (second) 561 - r6 = r1 (first) ---> Loop point <--- 572 - r7 = r2 (second) 667 - r6 += r7 (tmp = first + second) 512 - r1 = r2 (first = second 526 - r2 = r6 (second = tmp) 280 - r8 = 0 (location of our -1) 888 - r8 = -1 (set r8 from ram addr 0) 698 - r9 += r8 (deincrement loop counter) 234 - r3 = 4 (loop point) 039 - (goto r3 if r9 != 0) ?1 - (print first)
Jeremy
6. Re: Contest #2... Example Programs
- Posted by jimcbrown (admin) Dec 09, 2010
- 3222 views
This program prints out "9 8 7 6 5 4 3 2 1 "
224 set R2,4 Set loop start location 239 set R3,9 Set the first number to be output 210 set R1,0 Load RAM[0] (-1) ... 811 set R1,[R1] into R1 ??3 put R3 Output number 631 add R3,R1 Subtract 1 from number 023 jmp R2,R3 Loop back if number not zero
Annotated by DerekParnell
7. Re: Contest #2... Example Programs
- Posted by ChrisB (moderator) Dec 10, 2010
- 3161 views
Bouncing 1s
201000000000 set reg 0 to 1000000000 211 set reg 1 to 1 2210 set reg 2 to 10 259 set reg 5 to 9 - loop counter 240 set reg 4 to 1 - RAM address loop 560 set reg 6 to reg 0 661 add reg 1 to reg 6 ??6 set RAM to reg 6 241 set reg 4 to 1 645 add reg 5 to reg 4 (offsets by 1, so don't use RAM 0) 964 set ram[4] to reg 6 275 set reg 7 to 6 -loop destination 883 set reg 8 to [3] (which is RAM 0 or -1) 658 add reg 8 to reg 5 712 multiply reg 1 by reg 2 075 jump to reg 7, unless reg 5 = 0 now have ram pattern set up, so count up and down reg 8 subtraction unit reg 0 direction indicator (up or down) reg 5 loop counter reg 4 ram address reg 1 current number reg 2 loop 2 address reg 6, reg 7 delay loops 259 set reg 5 to 9 201 set reg 0 to 1 - going up 241 set reg 4 to 1 - first ram address loop 2 2232 set reg 2 to 32 (loop2) 814 get ram in reg[4] ??1 print it 2699 set reg 6 delay loop delay 1 279 set reg 7 delay loop delay 2 678 decrement reg 7 2340 set reg 3 to 40 037 go reg 3 unless reg 7=0 loop delay 2 668 decrement reg 6 2338 set reg 3 to 38 036 goto reg 3 unless reg 6=0 loop delay 1 640 add direction indicator (reg 0) to ram address (reg 4) --?4 658 decrement loop counter (or add reg 8 to reg 5) 025 goto loop 2, unless 0 259 set reg 5 to 9 708 flip direction counter 022 always goto loop 2
8. Re: Contest #2... Example Programs
- Posted by jimcbrown (admin) Dec 10, 2010
- 3150 views
My interpreter won't run this. A lot of this stuff requires advanced features that's out of spec (such as setting reg 2 to 10 or treating lines with no valid instructions in them as comments).
Bouncing 1s
201000000000 set reg 0 to 1000000000 211 set reg 1 to 1 2210 set reg 2 to 10 259 set reg 5 to 9 - loop counter 240 set reg 4 to 1 - RAM address loop 560 set reg 6 to reg 0 661 add reg 1 to reg 6 ??6 set RAM to reg 6 241 set reg 4 to 1 645 add reg 5 to reg 4 (offsets by 1, so don't use RAM 0) 964 set ram[4] to reg 6 275 set reg 7 to 6 -loop destination 883 set reg 8 to [3] (which is RAM 0 or -1) 658 add reg 8 to reg 5 712 multiply reg 1 by reg 2 075 jump to reg 7, unless reg 5 = 0 now have ram pattern set up, so count up and down reg 8 subtraction unit reg 0 direction indicator (up or down) reg 5 loop counter reg 4 ram address reg 1 current number reg 2 loop 2 address reg 6, reg 7 delay loops 259 set reg 5 to 9 201 set reg 0 to 1 - going up 241 set reg 4 to 1 - first ram address loop 2 2232 set reg 2 to 32 (loop2) 814 get ram in reg[4] ??1 print it 2699 set reg 6 delay loop delay 1 279 set reg 7 delay loop delay 2 678 decrement reg 7 2340 set reg 3 to 40 037 go reg 3 unless reg 7=0 loop delay 2 668 decrement reg 6 2338 set reg 3 to 38 036 goto reg 3 unless reg 6=0 loop delay 1 640 add direction indicator (reg 0) to ram address (reg 4) --?4 658 decrement loop counter (or add reg 8 to reg 5) 025 goto loop 2, unless 0 259 set reg 5 to 9 708 flip direction counter 022 always goto loop 2
9. Re: Contest #2... Example Programs
- Posted by jeremy (admin) Dec 10, 2010
- 3265 views
My interpreter won't run this. A lot of this stuff requires advanced features that's out of spec (such as setting reg 2 to 10 or treating lines with no valid instructions in them as comments).
I think the revelant portion of the spec is
"Anything after the 3 digit instruction is a comment"
I guess I should have made that a little more clear. I'm sorry Chris, my interpreter will not run it either. You have to do things such as:
225 ; set register 2 to 5 325 ; add to register 2 the number 5
Register 2 will then contain 10.
Jeremy
10. Re: Contest #2... Example Programs
- Posted by jimcbrown (admin) Dec 10, 2010
- 5469 views
Phew! I was worried for a moment that I'd be disqualified for not having a sufficiently advanced magic - er, interpreter.
My interpreter won't run this. A lot of this stuff requires advanced features that's out of spec (such as setting reg 2 to 10 or treating lines with no valid instructions in them as comments).
I think the revelant portion of the spec is
"Anything after the 3 digit instruction is a comment"
I guess I should have made that a little more clear. I'm sorry Chris, my interpreter will not run it either. You have to do things such as:
225 ; set register 2 to 5 325 ; add to register 2 the number 5
Register 2 will then contain 10.
Jeremy
11. Re: Contest #2... Example Programs
- Posted by ChrisB (moderator) Dec 10, 2010
- 3096 views
Then according to the spec, I win!
LOL
My interpreter runs all your programs, does this also mean mines better, more versatile, and more robust than yours too!
What are your errors, lets see if I can help you!
Chris (chuckling lots)
(Back to drawing board, to 'dumb' down my VM, and only allow 3 digits in the instruction - this is fun)
12. Re: Contest #2... Example Programs
- Posted by PeteE Dec 11, 2010
- 3073 views
This one's for Matt:
265 r6=5 (width) *** game of life *** 462 r6*=2 (10) 275 r7=5 (height) 472 r7*=2 (10) 289 r8=9 (stack pointer) 484 r8*=4 (36) 381 r8+=1 (37) 483 r8*=3 (111) 483 r8*=3 (333) 483 r8*=3 (999) 211 r1=1 855 r5=[r5] (-1) 209 r0=9 (glider) 304 r0+=4 (13) 910 [r0]=r1 1 606 r0+=r6 1 301 r0+=1 1 1 1 910 [r0]=r1 606 r0+=r6 910 [r0]=r1 605 r0+=r5 910 [r0]=r1 605 r0+=r5 910 [r0]=r1 456 r5*=6 455 r5*=5 (how many iterations) 506 r0=r6 (cell address) <-- main_loop 302 r0+=2 230 r3=0 (row counter) 833 r3=[r3] (-1) 737 r3*=r7 220 r2=0 (col counter) <-- row_loop 822 r2=[r2] (-1) 726 r2*=r6 (-width) 321 r2+=1 810 r1=[r0] (cell state) 301 r0+=1 ??1 321 r2+=1 297 r9=7 495 r9*=5 (35) 092 if r2 col_loop 810 r1=[r0] (cell state) 301 r0+=1 ?1 331 r3+=1 296 r9=6 495 r9*=5 (30) 391 r9+=1 (31) 093 if r3 row_loop 200 r0=0 506 r0=r6 (cell address) 302 r0+=2 230 r3=0 (counter = -width*height) 833 r3=[r3] (-1) 736 r3*=r6 737 r3*=r7 220 r2=0 (counter of living neighbors) <-- neighbor_loop 842 r4=[r2] (-1) 514 r1=r4 716 r1*=r6 614 r1+=r4 610 r1+=r0 891 r9=[r1] (load neighbor northwest) 629 r2+=r9 311 r1+=1 891 r9=[r1] (load neighbor north) 629 r2+=r9 311 r1+=1 891 r9=[r1] (load neighbor northeast) 629 r2+=r9 616 r1+=r6 891 r9=[r1] (load neighbor east) 629 r2+=r9 616 r1+=r6 891 r9=[r1] (load neighbor southeast) 629 r2+=r9 614 r1+=r4 891 r9=[r1] (load neighbor south) 629 r2+=r9 614 r1+=r4 891 r9=[r1] (load neighbor southwest) 629 r2+=r9 640 r4+=r0 894 r9=[r4] (load neighbor west) 629 r2+=r9 300 nop ??2 810 r1=[r0] (load cell) 299 r9=9 495 r9*=5 (45) 493 r9*=3 (135) 392 r9+=2 (137) 091 if r1 cell_alive 240 r4=0 <-- dead_cell 844 r4=[r4] (-1) 443 r4*=3 (-3) 642 r4+=r2 (dead cells live when 3 neighbors) 297 r9=7 497 r9*=7 (49) 394 r9+=4 (53) 492 r9*=2 (106) 094 if r4 next_cell 240 r4=0 <-- push_cell 844 r4=[r4] (-1) 684 r8+=r4 908 [r8]=r0 (put cell on the stack to invert later) 301 r0+=1 <-- next_cell 331 r3+=1 299 r9=9 492 r9*=2 (18) 391 r9+=1 (19) 493 r9*=3 (57) 093 if r3 neighbor_loop 808 r0=[r8] <-- invert_loop 295 r9=5 495 r9*=5 (25) 495 r9*=5 (125) 090 if r0 invert_cell ?0 351 r5+=1 299 r9=9 394 r9+=4 (13) 492 r9*=2 (26) 095 if r5 main_loop 100 halt 810 r1=[r0] <-- invert_cell 220 r2=0 822 r2=[r2] (-1) 712 r1*=r2 311 r1+=1 910 [r0]=r1 381 r8+=1 298 r9=8 497 r9*=7 (56) 492 r9*=2 (112) 391 r9+=1 (113) 099 if r9 invert_loop 240 r4=0 <-- cell_alive 844 r4=[r4] (-1) 443 r4*=3 (-3) 642 r4+=r2 299 r9=9 398 r9+=8 (17) 493 r9*=3 (51) 493 r9*=3 (153) 094 if r4 cell_alive2 (if neighbors!=3) 300 nop 297 r9=7 497 r9*=7 (49) 394 r9+=4 (53) 492 r9*=2 (106) 099 if r9 next_cell 300 nop 341 r4+=1 <-- cell_alive2 299 r9=9 398 r9+=8 (17) 493 r9*=3 (51) 492 r9*=2 (102) 094 if r4 push_cell (if neighbors!=2) 297 r9=7 497 r9*=7 (49) 394 r9+=4 (53) 492 r9*=2 (106) 099 if r9 next_cell
13. Re: Contest #2... Example Programs
- Posted by PeteE Dec 12, 2010
- 3040 views
Quicksort: recursive function using a stack. The quicksort function prints the upper index, pivot index, and upper index at each invocation, and displays the partially sorted array after partitioning. The stack grows downward from the top of ram, and is used for return address and saving local registers. Function arguments and return values are passed in registers.
288 r8=8 (stack pointer) *** quicksort *** 485 r8*=5 (40) 485 r8*=5 (200) 485 r8*=5 (1000) 877 r7=[r7] (-1, keep it constant throughout) 211 r1=1 (load the initial array starting at ram[1]) 209 r0=9 304 r0+=4 (13) 403 r0*=3 (39) 402 r0*=2 (78) 901 [r1]=r0 311 r1+=1 207 r0=7 403 r0*=3 (21) 302 r0+=2 (23) 901 [r1]=r0 311 r1+=1 209 r0=9 405 r0*=5 (45) 402 r0*=2 (90) 901 [r1]=r0 311 r1+=1 208 r0=8 901 [r1]=r0 311 r1+=1 207 r0=7 405 r0*=5 (35) 901 [r1]=r0 311 r1+=1 209 r0=9 304 r0+=4 (13) 901 [r1]=r0 311 r1+=1 207 r0=7 407 r0*=7 (49) 901 [r1]=r0 311 r1+=1 209 r0=9 409 r0*=9 (81) 302 r0+=2 (83) 901 [r1]=r0 311 r1+=1 209 r0=9 406 r0*=6 (54) 901 [r1]=r0 311 r1+=1 208 r0=8 407 r0*=7 (56) 305 r0+=5 (61) 901 [r1]=r0 561 r6=r1 (upper index, constant throughout) 208 r0=8 407 r0*=7 (56) 305 r0+=5 (61) 687 r8+=r7 908 [r8]=r0 (push return address) 299 r9=9 494 r9*=4 (36) 391 r9+=1 (37) 492 r9*=2 (74) 099 if r9 show_array 209 r0=9 408 r0*=8 (72) 301 r0+=1 (73) 687 r8+=r7 908 [r8]=r0 (push return address) 201 r0=1 (lower index) 516 r1=r6 (upper index) 296 r9=6 495 r9*=5 (30) 391 r9+=1 (31) 493 r9*=3 (93) 099 if r9 quicksort 100 halt 201 r0=1 (lower index) <-- show_array 517 r1=r7 (-1) 716 r1*=r6 (-upper index) 610 r1+=r0 (loop counter) 890 r9=[r0] <-- show_loop 301 r0+=1 ??9 (print value) 311 r1+=1 299 r9=9 394 r9+=4 (13) 493 r9*=3 (39) 492 r9*=2 (78) 091 if r1 show_loop 890 r9=[r0] ?9 (print value) 898 r9=[r8] (pop return address) 381 r8+=1 099 goto r9 (ret) 300 nop 687 r8+=r7 <-- quicksort (r0: lower index, r1: upper index, [r8]=return address) 918 [r8]=r1 (push upper index) 687 r8+=r7 908 [r8]=r0 (push lower index) 717 r1*=r7 520 r2=r0 621 r2+=r1 299 r9=9 392 r9+=2 (11) 495 r9*=5 (55) 492 r9*=2 (110) 092 if r2 check_index 300 nop 382 r8+=2 (pop upper and lower index) <-- quicksort_done 898 r9=[r8] (pop return address) 381 r8+=1 099 goto r9 (ret) 627 r2+=r7 <-- check_index 298 r9=8 495 r9*=5 (40) 493 r9*=3 (120) 092 if r2 calculate_pivot1 297 r9=7 497 r9*=7 (49) 394 r9+=4 (53) 492 r9*=2 (106) 099 if r9 quicksort_done (lower index > upper index) 311 r1+=1 <-- calculate_pivot1 520 r2=r0 621 r2+=r1 299 r9=9 492 r9*=2 (18) 391 r9+=1 (19) 497 r9*=7 (133) 092 if r2 calculate_pivot2 299 r9=9 495 r9*=5 (45) 392 r9+=2 (47) 493 r9*=3 (141) 099 if r9 found_pivot 301 r0+=1 <-- calculate_pivot2 520 r2=r0 621 r2+=r1 298 r9=8 495 r9*=5 (40) 493 r9*=3 (120) 092 if r2 calculate_pivot1 300 nop 520 r2=r0 (pivot index) <-- found_pivot 838 r3=[r8] (lower index) 381 r8+=1 848 r4=[r8] (upper index) 687 r8+=r7 ??3 (print lower index) ??2 (print pivot index) ?4 (print upper index) 802 r0=[r2] (pivot value) 814 r1=[r4] (upper value) 912 [r2]=r1 (swap them) 904 [r4]=r0 523 r2=r3 (store index) 554 r5=r4 757 r5*=r7 653 r5+=r3 (loop counter) 300 nop 803 r0=[r3] (index value) <-- quicksort_loop 814 r1=[r4] (pivot value) 298 r9=8 497 r9*=7 (56) 493 r9*=3 (168) 395 r9+=5 (173) 687 r8+=r7 998 [r8]=r9 (push return address) 298 r9=8 495 r9*=5 (40) 493 r9*=3 (120) 391 r9+=1 (121) 492 r9*=2 (242) 099 if r9 compare 300 nop 299 r9=9 494 r9*=4 (36) 391 r9+=1 (37) 495 r9*=5 (185) 090 if r0 quicksort_loop_next 803 r0=[r3] (index value) 812 r1=[r2] (store value) 913 [r3]=r1 (swap them) 902 [r2]=r0 321 r2+=1 300 nop 300 nop 331 r3+=1 <-- quicksort_loop_next 351 r5+=1 299 r9=9 498 r9*=8 (72) 397 r9+=7 (79) 492 r9*=2 (158) 095 if r5 quicksort_loop 804 r0=[r4] (pivot value) 812 r1=[r2] (store value) 914 [r4]=r1 (swap them) 902 [r2]=r0 298 r9=8 495 r9*=5 (40) 495 r9*=5 (200) 399 r9+=9 (209) 687 r8+=r7 998 [r8]=r9 (push return address) 299 r9=9 494 r9*=4 (36) 391 r9+=1 (37) 492 r9*=2 (74) 099 if r9 show_array 300 nop 300 nop 808 r0=[r8] (lower index) 687 r8+=r7 928 [r8]=r2 (push pivot index) 512 r1=r2 617 r1+=r7 (pivot index - 1) 299 r9=9 495 r9*=5 (45) 495 r9*=5 (225) 687 r8+=r7 998 [r8]=r9 (push return address) 296 r9=6 495 r9*=5 (30) 391 r9+=1 (31) 493 r9*=3 (93) 099 if r9 quicksort (recursively call quicksort) 300 nop 808 r0=[r8] (pop pivot index) 381 r8+=1 301 r0+=1 (pivot index + 1) 381 r8+=1 818 r1=[r8] (load upper index) 687 r8+=r7 297 r9=7 497 r9*=7 (49) 394 r9+=4 (53) 492 r9*=2 (106) 687 r8+=r7 998 [r8]=r9 (push return address) 296 r9=6 495 r9*=5 (30) 391 r9+=1 (31) 493 r9*=3 (93) 099 if r9 quicksort (recursively call quicksort) 707 r0*=r7 <-- compare (returns with r0=0 if r0<=r1, r0=1 otherwise) 610 r1+=r0 (find the difference and make a copy. increment the first copy 501 r0=r1 and decrement the second copy until one of them reaches zero.) 300 nop 311 r1+=1 <-- compare_1 298 r9=8 498 r9*=8 (64) 494 r9*=4 (256) 090 if r0 compare_2 (return 0 if r0 <= r1) 898 r9=[r8] (pop return address) 381 r8+=1 099 goto r9 (ret) 300 nop 300 nop 607 r0+=r7 <-- compare_2 298 r9=8 495 r9*=5 (40) 391 r9+=1 (41) 493 r9*=3 (123) 492 r9*=2 (246) 091 if r1 compare_1 201 r0=1 (return 1 if r0 > r1) 898 r9=[r8] (pop return address) 381 r8+=1 099 goto r9 (ret)
14. Re: Contest #2... Example Programs
- Posted by coconut Dec 12, 2010
- 2936 views
tried to run you game of life on my VM but it crash.
C:\euphoria-40\work\win32\temp>eui hc1 PeteE-life.hc -1 1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 1 -1 -1 -1 -1 -1 -1 -1 1 1 1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 c:\euphoria-40\work\win32\temp\hc1.ex:102 subscript value 0 is out of bounds, reading from a sequence of length 1000 --> See ex.err
here the code of my vm
ED... SNIP... VM code removed as contest submissions shouldn't be submitted yet. ... BY JEREMY
15. Re: Contest #2... Example Programs
- Posted by jimcbrown (admin) Dec 12, 2010
- 2958 views
tried to run you game of life on my VM but it crash.
C:\euphoria-40\work\win32\temp>eui hc1 PeteE-life.hc -1 1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 1 -1 -1 -1 -1 -1 -1 -1 1 1 1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 c:\euphoria-40\work\win32\temp\hc1.ex:102 subscript value 0 is out of bounds, reading from a sequence of length 1000 --> See ex.err
here the code of my vm
ED... SNIP... VM code removed as contest submissions shouldn't be submitted yet. ... BY JEREMY
I think the issue is that your RAM is not compliant with the spec.
RAM[0] = -1, RAM[1..999] = 0
If it's anything different, then it's not compliant and will (probably) fail the tests.
16. Re: Contest #2... Example Programs
- Posted by coconut Dec 12, 2010
- 2945 views
Pete, It was my error, my vm was initializing all ram to -1. After reading the constest rule once again I realized it must me all zero's except for ram[1]=-1
I corrected the error an now game of life work.
17. Re: Contest #2... Example Programs
- Posted by heber Dec 12, 2010
- 2967 views
edit: never mind its already answered.
looks like you need to add 1 to the ram value returned
18. Re: Contest #2... Example Programs
- Posted by ChrisB (moderator) Dec 13, 2010
- 2977 views
- Last edited Dec 14, 2010
Corrected bouncing 1s (or a triangle wave)
300 ; bouncing 1s ver 2 300 ; using nops to allow for less 'advanced' interpreters 300 ; set reg 0 to -1, allows countdowns, not ued for anything else 200 800 300 ; reg 1 will contain the number 300 ; reg 2 will contain 10 225 ; set reg 2 to 5 422 ; reg 2 * 2 = 10 211 ; reg 1 = 1 300 300 ; set base ram address to 100, hold 100 in ram[1] 251 ; set reg 5 to 1 752 ; reg 5 = reg 5 * reg 2 752 ; reg 5 = reg 5 * reg 2 ( = 100) 951 ; set ram[1] to reg 5 (100) 595 ; set reg 9 to reg 5 (100) - this will be the base address for the ram pattern 300 ; using reg 9 as mem address reg 300 278 ; r7 = 8 300 672 ; r7 += r2 (12) - exceeds size of an integer 292 ; r9 = 2 979 ; [r9] = r7 (RAM 2 = 12 for quick recall) 300 300 ; set r9 back to 100 291 899 300 ; set each of the ram memory cells 919 ; [9] = r1 ?1 712 ; r1 *= r2 670 ; r7 += r0 (-1) 300 ; set r8 to jmp address (27) 289 ; r8 = 9 483 ; r8 *= 3 (27) 391 ; inc r9 087 ; jmp r8 r7!=0 300 272 ; r5 = 2 877 ; r7 = [5] (back to 12) 371 ; r7 += 1 (finishes at 0, so need extra 1) 291 ; r9 = 1 899 ; r9 = [9] (back to 100) 300 300 ; calculate jmp address 285 ; r8 = 5 489 ; r8 *= 9 384 ; r8 += 4 (jmp address = 49) 670 ; r7 += r0 (12 -1) 300 ; now add r1 to each of the cells, except the last one 839 ; r3 = [9] 631 ; r3 += r1 939 ; [9] = r3 391 ; inc r9 670 ; dec r7 (r7 += r0) ?3 087 ; jmp r8 r7!=0 300 300 ; now start cycling up and down ram, and printing it out 300 ; set r9 back to 100 291 ; r9 = 1 899 ; r9 = [9] 272 ; r7 = 2 877 ; r7 = [7] (back to 12) 670 ; r7 += 1 (finishes at 0, so need extra 1) 241 ; r4 = 1 will be direction switch - first up 300 300 ; r5 and r6 will be delay counters 300 ; will store in [5] and [6] 259 ; r5 = 9 459 ; r5 *= 9 <- delay 285 ; r8 = 5 958 ; [8] = r5 269 ; r6 = 9 461 ; r6 *= 1 <- delay 286 ; r8 = 6 968 ; [8] = r6 300 300 ; calculate jmp address 285 ; r8 = 5 482 ; r8 *= 2 487 ; r8 *= 8 384 ; r8 += 7 (87) 300 300 300 300 ; main loop 839 ; r3 = [9] ?3 ; ?r3 300 ; temporariliy store main loop jmp in [9] 259 ; r5 = 9 985 ; [5] = r8 255 ; r5 = 5 855 ; r5 = [5] 300 ; outer delay loop 266 ; r6 = 6 866 ; r6 = [6] 300 ; inner delay loop 285 ; r8 = 5 482 ; r8 *= 2 489 ; r8 *= 9 387 ; r8 += 7 (97) 660 ; r6 += r0 086 ; jmp r8 r6!=0 266 ; r6 = 6 866 ; r6 = [6] 285 ; r8 = 5 482 ; r8 *= 2 489 ; r8 *= 9 384 ; r8 += 4 (94) 650 ; r5 += r0 085 ; jmp r8 r6!=0 255 ; r5 = 5 855 ; r5 = [5] 300 300 ; pull off temp main loop loc 289 ; r8 = 9 888 ; r8 = [8] 694 ; r9 += r4 inc address 670 ; r7 += r0 dec conter 087 ; loop r8 if r7 740 ; r4 *= r0 flip direction 272 ; r7 = 2 877 ; r7 = [7] (back to 12) 670 ; r7 += r0 dec counter 088 ; jmp r8
Fixed newly found fundamental error!
19. Re: Contest #2... Example Programs
- Posted by mattlewis (admin) Dec 13, 2010
- 2981 views
Corrected bouncing 1s (or a triangle wave)
Pretty neat. I was getting type check errors, so I changed lines 20-21:
278 ; r7 = 8 300 ;
Matt
20. Re: Contest #2... Example Programs
- Posted by ChrisB (moderator) Dec 13, 2010
- 2951 views
Hi
Thanks Matt, high praise indeed.
This may may mean my VM is not 'in spec', so could JC clarify this - do we need to type check integers so they comply with euphoria integers or are euphoria atoms acceptable?
Chris
Sorry, just re read - RAM should store a euphoria integer, looks like atoms are unacceptable.
21. Re: Contest #2... Example Programs
- Posted by mattlewis (admin) Dec 13, 2010
- 2927 views
I've posted source code for calculating the GCD of 47250 and 39690 (other numbers are possible, of course). You'll have to assemble the code. Get it here (zip file) or check out the mercurial repo at http://scm.openeuphoria.org/hg/contest (branch: matt-assembler).
To assemble:
$ eui assem.ex euclid.cpa division.cpa stack.cpa less-than.cpa > gcd.cpu
Then you can run the gcd.cpu file with your interpreter. It prints the two numbers and then their GCD. Assembled, it comes out to just under 600 instructions, and should run for 388,834 steps.
Matt
22. Re: Contest #2... Example Programs
- Posted by coconut Dec 13, 2010
- 2894 views
I just looked at Derek And Matt assembler to compare it to the one I written last weekend. I do the label fixup very differently. each time my assembler hit a forward reference to a label it reserve a fixed number of code instructions. Derek and Matt assembler use addition of power of 2, mine use power of tens. I reserve a register to hold number 10 and multiply the targer register with that number. I grow the address by a serie of "addi Rt n" and "mult Rt Rm". It doesn't need a second pass to fix the labels. When a label is met in the code the assembler immediatly lookup the pending fix and resolve them. There is 2 limitations to my system: to space allocated is always the same so it is oversized for small address. Secondly It limit the program address space to 0 - 9999. I could increase it but it would means more space lost. The main advantage of my system is it simplicity. Here my assembler code
/*
NAME: hcasm.ex
DESC: assembler for contest #2 cpu
AUTHOR: Jacques DeschĂȘnes
NOTE:
assembler syntax:
INSTRUCTION::= [:LABEL] OPCODE | OPCODE DEST INT | OPCODE DEST SOURCE
OPCODE::=JNZ|HALT|SETI|ADDI|MULTI|CPY|ADD|MUL|LOAD|STOR|PRNL|PRSP
DEST::=R0|R1|R2|R3|R4|R5|R6|R7|R8|R9
SOURCE::=R0|R1|R2|R3|R4|R5|R6|R7|R8|R9
INT::=[0..9]
COMMENT::= ; any text
exemples:
ADDI R0 9 ;add 9 to R0
STOR R0 R2 ;store contain of R0 in ram pointed by R2
MULI R2 8 ;multiply r2 by 8
symbols can be used for ram locations and goto's
a goto label begin with ':' and should be the first token on the line
to define a ram symbol or any constant use the keyword .sym
.sym name value
mnemonic and keywords are not case sensitive all code is converted to upper case.
*/
include std/sequence.e
include std/text.e
include std/get.e
with trace
object _
constant --OPCODE MNEMONICS
MNEMONICS={
"JNZ", -- jump if not zero
"HALT", -- halt execution
"SETI", -- set register immediate
"ADDI", -- add register immediate
"MULI", -- multiply register immediate
"CPY", -- copy register
"ADD", -- add register to register
"MUL", -- multiply register to register
"LOAD", -- load register
"STOR", -- store register
"PRNL", -- print line.
"PRSP" -- print with space
}
constant -- number of arguments used by each mnemonic
ARG_COUNT={2,0,2,2,2,2,2,2,2,2,1,1}
enum SYM_NAME, SYM_VAL
enum URES_LBL, URES_LOC
enum LBL_NAME, LBL_LOC
sequence symbols={{"MINUS1"},{0}}, labels={{},{}}, file="", asm={}, hc={}, unresolved={{},{}}
type digit(integer i)
return (i>='0' and i<='9')
end type
procedure read_file()
object line
integer fh
fh=open(file,"r")
if fh=-1 then
printf(1,"unknown file %s\n",{file})
abort(2)
end if
line=gets(fh)
while sequence(line) do
if line[$]='\n' then line=line[1..$-1] end if
if length(line) and line[$]='\r' then line=line[1..$-1] end if
asm=append(asm,line)
line=gets(fh)
end while
close(fh)
end procedure
integer asm_line=0
enum ERR_NONE=0, ERR_UNKNOWN_SYMBOL, ERR_MISSING_ARG, ERR_BAD_ARG, ERR_UNKNOWN_LABEL,
ERR_LOC_RESOLV, ERR_ALREADY_DEFINED, ERR_UNKNOWN_KEYWORD
constant ERR_MSG={
"unknown symbol",
"missing argument",
"bad argument",
"unknown label",
"error while resolving back location",
"this symbol already exist",
"unknown keyword"
}
procedure error(integer err_code)
printf(1,"assembler error code %d: %s, at line %d\n",{err_code,ERR_MSG[err_code],asm_line})
puts(1,asm[asm_line]&'\n')
abort(1)
end procedure
/*
keywords procedures
keywords are asembler directives and does not generate code
all keywords begin with a '.'
*/
constant KEYWORDS={
".SYM"
}
-- add a symbol to symbols table
-- tokens[1] is symbol name, tokens[2] is value
procedure add_symbol(sequence tokens)
sequence t1, t2
t1=tokens[1]
if find(t1,symbols[SYM_NAME]) then
error(ERR_ALREADY_DEFINED)
end if
t2=value(tokens[2])
if t2[1]!=GET_SUCCESS then
error(ERR_BAD_ARG)
end if
symbols[SYM_NAME]=append(symbols[SYM_NAME],t1)
symbols[SYM_VAL]=append(symbols[SYM_VAL],t2[2])
end procedure
constant rid_keywords={
routine_id("add_symbol")
}
procedure add_unresolved(sequence lbl, integer loc)
integer p
--trace(1)
p=find(lbl,unresolved[URES_LBL])
if not p then
unresolved[URES_LBL]=append(unresolved[URES_LBL],lbl)
unresolved[URES_LOC]=append(unresolved[URES_LOC],{loc})
else
unresolved[URES_LOC][p] &= loc
end if
end procedure
procedure resolve(sequence lbl, integer addr)
sequence loc2resolv, saddr
integer p, pc, completed
--trace(1)
p = find(lbl,unresolved[URES_LBL])
if not p then return end if
loc2resolv=unresolved[URES_LOC][p]
saddr=sprintf("%04d",addr)
for i = 1 to length(loc2resolv) do
pc=loc2resolv[i]
completed=0
for j = 1 to 4 do
if hc[pc+(j-1)*2][1]!='3' then
exit
end if
hc[pc+(j-1)*2][3]=saddr[j]
if j=4 then
completed=1
end if
end for
if not completed then error(ERR_LOC_RESOLV) end if
end for
unresolved[URES_LBL]=unresolved[URES_LBL][1..p-1]&unresolved[URES_LBL][p+1..$]
unresolved[URES_LOC]=unresolved[URES_LOC][1..p-1]&unresolved[URES_LOC][p+1..$]
end procedure
/*
macros expansion routines
*/
--MACRO: SETREG expansion: generate code to set a register 'r' with arbitrary integer
-- if r <> 0 then use R0 to store multiplier else use R1
function set_reg(sequence tokens)
integer p,d,m, neg=0, val
sequence r={}, t2={}, opcode={}, hc_lines={}
r=tokens[1]
if r[1]!='R' then
error(ERR_BAD_ARG)
end if
d=r[2]
t2=tokens[2]
if t2[1]=':' then --label reference
p=find(t2[2..$],labels[LBL_NAME])
if p then
val=labels[LBL_LOC][p]
t2=sprintf("%04d",val)
else -- unresolved label
add_unresolved(t2[2..$],length(hc)+4)
val=9999
t2="0000"
end if
elsif t2[1]='-' and digit(t2[2]) then --negative number
neg=1
t2=value(t2[2..$])
val=t2[2]
t2=sprintf("%d",val)
elsif digit(t2[1]) then --positive number
t2=value(t2)
if t2[1]!=GET_SUCCESS then
error(ERR_BAD_ARG)
end if
val=floor(t2[2])
t2=sprintf("%d",val)
else -- symbol reference
p=find(t2,symbols[SYM_NAME])
if not p then
error(ERR_UNKNOWN_SYMBOL)
end if
val=symbols[SYM_VAL][p]
if val<0 then
neg=1
val = -val
end if
t2=sprintf("%d",val)
end if
if d>'0' then
m='0'
else
m='1'
end if
if val < 10 then
opcode='2' & d & (val + '0')
hc_lines={opcode}
else
-- set d=0
opcode='2'&d&'0' -- SETI Rd 0
hc_lines={opcode}
-- set m=10 ; multiplier
opcode='2'&m&'9' -- SETI Rm 9
hc_lines&={opcode}
opcode='3'&m&'1' -- ADDI Rm 1 -> Rm=10
hc_lines&={opcode}
for i=1 to length(t2) do
opcode='3'& d & t2[i] -- ADDI Rd t2[i]
hc_lines &= {opcode}
if i<length(t2) then
opcode='7'&d&m -- MUL Rd Rm -> Rd = Rd * 10
hc_lines&={opcode}
end if
end for
end if
if neg then
opcode='2'&m&'0' -- STI Rm 0
hc_lines&={opcode}
opcode='8'&m&m -- LOAD Rm Rm -> Rm = -1
hc_lines&={opcode}
opcode='7'&d&m -- MUL Rd Rm -> Rd = -Rd
hc_lines&={opcode}
end if
return hc_lines
end function
-- MACRO: SETRAM expansion: generate code to set ram to an arbitrary integer
-- use R2 to store ram_address and R1 store value
function set_ram(sequence tokens) -- SETRAM ram_address value
sequence hc_lines
hc_lines=set_reg({"R2",tokens[1]})&set_reg({"R1",tokens[2]}) -- R2 = ram_address, R1=value
hc_lines&={"912"} -- STOR R1 R2 -> ram_address [R2]=R1
return hc_lines
end function
--MACRO: GOTO expansion: generate code for unconditional goto
-- use R2 to store PC address and R0 set to 1
function goto_(sequence tokens) -- GOTO code_address
sequence address,hc_lines
integer p
hc_lines= set_reg({"R2"} & tokens)
hc_lines &={"201","020"} -- SETI R0 0 and JNZ R1 R0
return hc_lines
end function
--MACRO: STVAR var_address Rv expansion
-- tokens[1] var_address, tokens[2] register containing value
function store_var(sequence tokens)
sequence t2, hc_lines={}
integer s
t2=tokens[2]
if t2[1]!='R' then
error(ERR_BAD_ARG)
end if
s=tokens[2][2]
hc_lines=set_reg({"R1"}&{tokens[1]})--set address in R1
hc_lines&={'9'&s&'1'} -- STORE Rs R1
return hc_lines
end function
--MACRO: LDVAR Rv var_address expansion
-- tokens[1] register to store value, tokens[2] var_address
function load_var(sequence tokens)
sequence t1, hc_lines={}
integer rv
t1= tokens[1]
if t1[1]!='R' then
error(ERR_BAD_ARG)
end if
rv=t1[2]
hc_lines=set_reg(tokens)
hc_lines&={"8"&rv&rv}
return hc_lines
end function
--MACRO: NOP expansion
-- nop operation by adding constant 0 to R0
function nop(sequence tokens)
sequence comment
integer p
comment=asm[asm_line]
p = find(';',comment)
if p then
comment=comment[p..$]
else
comment=""
end if
return {"300 "&comment}
end function
--MACRO: LPNZ :label Rc expansion
-- R2 is used to store label address
-- :label is label to loop back, Rc is control register for zero value
function loop_not_zero(sequence tokens)
sequence t2,hc_lines={}
integer rc
t2=tokens[2]
if t2[1]!='R' then
error(ERR_BAD_ARG)
end if
rc=t2[2]
hc_lines=set_reg({"R2",tokens[1]})
hc_lines&={"0"&'2'&rc}
return hc_lines
end function
constant -- list of macros
MACROS={
"SETREG",
"SETRAM",
"GOTO",
"STVAR",
"NOP",
"LPNZ",
"LDVAR"
}
constant-- number of arguments used by macro
MAC_ARG_COUNT={2,2,1,2,0,2,2}
constant rid_macros={
routine_id("set_reg"),
routine_id("set_ram"),
routine_id("goto_"),
routine_id("store_var"),
routine_id("nop"),
routine_id("loop_not_zero"),
routine_id("load_var")
}
enum ST_IDLE, ST_ARG1, ST_ARG2, ST_COMPLETED
procedure parse(sequence tokens)
integer p,i,m,acount, state=ST_IDLE
sequence opcode, t
--trace(1)
--if asm_line=90 then trace(1) end if
if not length(tokens) then return end if -- empty or comment line
i=1
while state!=ST_COMPLETED and i <= length(tokens) do
t=tokens[i]
m=find(t,MNEMONICS)
switch state do
case ST_IDLE then
if t[1]=':' then
labels[1]=append(labels[1],t[2..$]) -- label symbol
labels[2]=append(labels[2],length(hc)) -- label address
resolve(t[2..$],length(hc))
elsif t[1]='.' then -- keyword
m=find(t,KEYWORDS)
if not m then
error(ERR_UNKNOWN_KEYWORD)
end if
call_proc(rid_keywords[m],{tokens[2..$]})
state=ST_COMPLETED
opcode={}
elsif m then
acount=ARG_COUNT[m]
if length(tokens[i+1..$])<acount then error(ERR_MISSING_ARG) end if
if ARG_COUNT[m]=0 then
opcode={"100"} -- HALT is the only mnemonic without argument
state=ST_COMPLETED
exit
elsif m<11 then
opcode ={m-1+'0'}
elsif equal(t,"PRNL") then
opcode="?"
else
opcode="??"
end if
state=ST_ARG1
else
m=find(t,MACROS)
if not m then error(ERR_UNKNOWN_SYMBOL) end if
acount=MAC_ARG_COUNT[m]
if length(tokens[i+1..$])<acount then error(ERR_MISSING_ARG) end if
opcode=call_func(rid_macros[m],{tokens[i+1..$]})
state=ST_COMPLETED
end if
case ST_ARG1 then
if t[1]!='R' then error(ERR_BAD_ARG) end if -- first arg always a register
p=t[2]
if p<'0' or p>'9' then error(ERR_BAD_ARG) end if
opcode&=p
if acount=1 then
opcode&=' '
opcode={opcode}
state=ST_COMPLETED
else
state=ST_ARG2
end if
case ST_ARG2 then
if t[1]='R' then
p=t[2]
else
if digit(t[1]) then
p=t[1]
else
p=find(t,symbols[SYM_NAME])
if p then
p=symbols[SYM_VAL][p]
if p<0 or p>9 then
p=' '
else
p+='0'
end if
else
p=' '
end if
end if
end if
if p<'0' or p>'9' then error(ERR_BAD_ARG) end if
opcode&=p & ' '
opcode={opcode}
state=ST_COMPLETED
end switch
i += 1
end while
if state=ST_COMPLETED then
if length(opcode) then hc&=opcode end if
else
error(ERR_MISSING_ARG)
end if
end procedure
_ = date()
_[1] += 1900
constant CODE_HEADER={
"300 ;GENERATOR: hcasm.ex (macro assembler for contest #2 cpu)",
sprintf("300 ;TIMESTAMP: %4d-%02d-%02d %02d:%02d:%02d",_)
}
hc=CODE_HEADER
procedure generate_code()
sequence tokens, code, f_name
integer p, fh, lc
for i = 1 to length(asm) do
asm_line=i
p=find(';',asm[i])
if p then
code=upper(asm[i][1..p-1])
else
code=upper(asm[i])
end if
if length(code) then
lc=length(hc)
tokens=split(code,' ',1)
parse(tokens)
for j= lc+1 to length(hc) do
if length(hc[j])<4 then hc[j] &= repeat(32,4-length(hc[j])) end if
end for
if length(hc)>lc then
lc+=1
hc[lc] &= code
end if
end if
end for
p=find('.',file)
f_name=file[1..p]&"hc"
fh=open(f_name,"w")
for i=1 to length(hc) do
puts(fh,hc[i]&'\n')
end for
close(fh)
end procedure
procedure parse_args()
sequence args
args=command_line()
if length(args)<3 then
puts(1,"USAGE: eui hcasm.ex asm_file\n")
abort(1)
end if
file=args[3]
end procedure
procedure main()
parse_args()
read_file()
generate_code()
end procedure
main()
23. Re: Contest #2... Example Programs
- Posted by mattlewis (admin) Dec 13, 2010
- 2845 views
Here my assembler code
Cool! Now where are some example programs!
Matt
24. Re: Contest #2... Example Programs
- Posted by coconut Dec 13, 2010
- 2824 views
Here my assembler code
Cool! Now where are some example programs!
Matt
here my version of game of life for this assembler
nop ; TITLE: game of life
nop ; AUTHOR: Jacques DeschĂȘnes
nop ; life rules:
nop ; 3 neighbor -> birth
nop ; 2|3 neighbor -> survive
nop ; <2|>3 neighbor -> die
nop ;
nop ; glider initial shape
nop ; *
nop ; *
nop ; ***
.sym t1 9 ; cell array 1
.sym t2 409 ; cell array 2
.sym max_gen -40 ; stop after 25 generation
.sym size 20 ; size of grid
.sym gencount 2 ; address of generation counter variable
seti R0 1
stvar gencount R0 ; generation counter
nop ; initialize the arrays
setreg R3 800 ; loop counter
seti R4 t1 ; first array address
:L1 ldvar R0 minus1 ; load -1 in R0
seti R2 0 ; memset to 0
stor R2 R4
addi R4 1
add R3 R0
lpnz :L1 R3 ; loop if R3 not 0
nop ;initialize t1 with a single glider in the top left corner
seti R3 1 ; value to store
setreg R4 31 ; store address
stor R3 R4
setreg R4 52
stor R3 R4
setreg R4 70
stor R3 R4
addi R4 1
stor R3 R4
addi R4 1
stor R3 R4
nop ; print generation 0
seti R0 0
prnl R0
setreg R5 30 ; t1
setreg R6 18
setreg R7 18
:LC load R0 R5
prsp R0
addi R5 1
ldvar R0 minus1
add R7 R0
setreg R2 :LC
jnz R2 R7
setreg R7 18
addi R5 2
ldvar R0 minus1
add R6 R0
prnl R6
setreg R2 :LC
jnz R2 R6
nop ; print generation number
:glp ldvar R3 gencount
prnl R3 ; print generation number
setreg R4 size ; row increment
setreg R5 30 ; t1 first cell
setreg R6 18 ; row counter
setreg R7 18 ; column counter
setreg R8 430; t2 first cell
:g2 seti R9 0 ; neighbor counter
ldvar R0 minus1 ; put -1 in R0
cpy R1 R4 ; 20 -> R1
mul R1 R0 ; -20 -> R1
cpy R2 R5 ; &t1 -> R2
add R2 R1 ; &t1-20 -> R2
add R2 R0 ; &t1-21 -> R2
load R1 R2 ; begin row over neighbor count
add R9 R1 ;
addi R2 1 ;
load R1 R2
add R9 R1
addi R2 1
load R1 R2
add R9 R1 ; row over neighbord count completed
add R2 R4 ; begin current neighbor count
load R1 R2
add R9 R1
add R2 R0
add R2 R0
load R1 R2
add R9 R1 ;count complted for this row
add R2 R4 ; begin row under count
load R1 R2
add R9 R1
addi R2 1
load R1 R2
add R9 R1
addi R2 1
load R1 R2
add R9 R1 ;all neighbors counted.
setreg R2 :GT0
jnz R2 R9
goto :die ; 0 neighbor die
:GT0 ldvar R0 minus1 ; count >= 1
mul R9 R0 ; negate count
addi R9 1 ; check status of this cell
setreg R2 :GT1
jnz R2 R9
goto :die ; 1 neighbor die
:GT1 addi R9 1
setreg R2 :GT2
jnz R2 R9
goto :stabl ; 2 neighbor stay as is.
:GT2 addi R9 1
setreg R2 :die
jnz R2 R9 ; more than 3 neighbor die
seti R0 1
stor R0 R8 ; store 1 in t2 array
prsp R0
goto :nextc
:stabl load R0 R5
stor R0 R8 ; copy cell t1 to t2
prsp R0
goto :nextc
:die seti R0 0
stor R0 R8 ; store 0 in t2
prsp R0
:nextc addi R5 1 ; next cell
addi R8 1
ldvar R0 minus1
add R7 R0
setreg R2 :nxc1
jnz R2 R7
setreg R7 18
ldvar R0 minus1
add R6 R0
prnl R6
setreg R2 :nxc0
jnz R2 R6
goto :gend
:nxc0 ldvar R0 minus1
addi R5 2
addi R8 2
:nxc1 goto :g2
nop ; check gencount stop if = max_gen
:gend ldvar R3 gencount
addi R3 1
stvar gencount R3
setreg R0 max_gen
add R3 R0
setreg R2 :cpy
jnz R2 R3
halt
:cpy nop ; copy t2 to 1
setreg r5 9
setreg r6 409
setreg r7 400
:cpy1 load r0 r6
stor r0 r5
addi r5 1
addi r6 1
ldvar r3 minus1
add r7 r3
setreg r2 :cpy1
jnz r2 r7
goto :glp
halt
25. Re: Contest #2... Example Programs
- Posted by ChrisB (moderator) Dec 14, 2010
- 2802 views
Hi
There are two assemblers for a certain computer?
Clearly, you boys have too much time on your hands!
Chris
26. Re: Contest #2... Example Programs
- Posted by coconut Dec 14, 2010
- 2758 views
Hi
There are two assemblers for a certain computer?
Clearly, you boys have too much time on your hands!
Chris
Some like to watch TV, some like to play video games, and some like programming... And BTW it was rainy all weekend. And if I had more time, I have many ideas to improve my hcasm.ex: macros for logical operators et comparisons, support for subroutine call with parameters passing reserving R9 as a stack pointer.
I already figured out how to do that but don't have the time... have to go to work...
Jacques
28. Re: Contest #2... Example Programs
- Posted by ChrisB (moderator) Dec 14, 2010
- 2774 views
Hi
Just found another error in my vm - running bouncing 1s on yours will look much nicer now!
Chris
29. Re: Contest #2... Example Programs
- Posted by PeteE Dec 14, 2010
- 2744 views
- Last edited Dec 15, 2010
I do the label fixup very differently. each time my assembler hit a forward reference to a label it reserve a fixed number of code instructions. Derek and Matt assembler use addition of power of 2, mine use power of tens. I reserve a register to hold number 10 and multiply the targer register with that number. I grow the address by a serie of "addi Rt n" and "mult Rt Rm". It doesn't need a second pass to fix the labels. When a label is met in the code the assembler immediatly lookup the pending fix and resolve them. There is 2 limitations to my system: to space allocated is always the same so it is oversized for small address. Secondly It limit the program address space to 0 - 9999. I could increase it but it would means more space lost.
Very interesting, Jacques. I took another different approach to resolving labels in my (unreleased) cpu assembler. Instead of powers of 2 or 10, I wrote a general purpose function to generate instructions to load an arbitrary integer into a register using add and mul operations. To generate a jump offset, it loads the address of the label into the register using that function. For example, to load 999 into a register, the instructions emitted are:
289 r8=9 484 r8*=4 (36) 381 r8+=1 (37) 483 r8*=3 (111) 483 r8*=3 (333) 483 r8*=3 (999)
There's an obvious optimization missed there: it should use a *=9 instead of two *=3. There's also a problem when there's a backward reference and forward reference that overlap: the size of the label loads may shift the label address up and down, and the assembler doesn't terminate until the label addresses stop fluctuating. One solution is to manually put nops into the code in random places to try to get it to converge, but requires luck. I ended up making the assembler insert nops for me to keep a label address fixed when it takes too many tries to get them to settle.
It was rainy here too in Oregon this past weekend. I initially wasn't going to write my own assembler for a cpu that won't be used after a week, but it turns out I couldn't resist. I'll post the code later tonight.
Edit: and here it is. I also solved that number optimization bug.
-- User: PeteE
-- Contest 2 virtual machine assembler
-- Usage: vmasm.ex prog.src > prog.cpu
include std/io.e
include std/text.e
include std/cmdline.e
include std/convert.e
include std/map.e as map
include std/regex.e as re
re:regex
set_val = re:new(`^r([0-9])=(-?[0-9]+)`),
set_reg = re:new(`^r([0-9])=r([0-9])`),
add = re:new(`^r([0-9])\+=([0-9])`),
add_reg = re:new(`^r([0-9])\+=r([0-9])`),
mul = re:new(`^r([0-9])\*=([0-9])`),
mul_reg = re:new(`^r([0-9])\*=r([0-9])`),
load = re:new(`^r([0-9])=\[r([0-9])\]`),
store = re:new(`^\[r([0-9])\]=r([0-9])`),
set_lbl = re:new(`^r([0-9])=@([A-Za-z0-9_]+)`),
if_reg = re:new(`^if r([0-9]) ([A-Za-z0-9_]+)`),
a_label = re:new(`^([A-Za-z0-9_]+):`),
halt = re:new(`^halt`),
nop = re:new(`^nop`)
map:map nums = map:new() -- memoized num()
-- return a sequence of instructions which load the value n into a register r
function num(integer r, integer n, integer limit)
sequence
result,
tmp
if n < 0 then
result = {sprintf("2%s0 r%s=0",{r,r}),
sprintf("8%s%s r%s=[r%s] (-1)",{r,r,r,r})}
if n != -1 then
result &= num(r, -n, 0)
result[3][1] = '4' -- convert first set op to a mul
result[3] = insert(result[3], '*', 7)
end if
return result
end if
result = map:get(nums, n, {})
if length(result) then -- we've seen n before
for i = 1 to length(result) do
result[i][2] = r -- rewrite the dest register
result[i][6] = r
end for
return result
elsif n >= 0 and n <= 9 then
result = {sprintf("2%s%d r%s=%d",{r,n,r,n})}
elsif limit = 0 or limit > 2 then
if limit != 0 then
limit -= 1
end if
for i = 2 to 9 do -- factors
if i*floor(n/i) = n then
tmp = num(r, floor(n/i), limit)
if length(tmp) then
tmp &= {sprintf("4%s%d r%s*=%d (%d)", {r,i,r,i,n})}
if limit = 0 or length(tmp) < limit then
result = tmp
limit = length(tmp)
end if
end if
end if
end for
for i = 1 to 9 do -- sums
tmp = num(r, n-i, limit)
if length(tmp) then
tmp &= {sprintf("3%s%d r%s+=%d (%d)", {r,i,r,i,n})}
if limit = 0 or length(tmp) < limit then
result = tmp
limit = length(tmp)
end if
end if
end for
end if
map:put(nums, n, result) -- memoize this result
return result
end function
function assemble(sequence prog)
sequence s
object ref
integer
n = 0,
done = 0,
tries = 0
map:map labels = map:new()
for i = 1 to length(prog) do
prog[i] = trim(prog[i])
end for
-- first pass: assemble instructions and remove blank lines
n = 1
while n <= length(prog) do
s = prog[n]
if length(s) = 0 then
prog = remove(prog, n)
continue
end if
ref = re:find(if_reg, s)
if sequence(ref) then
s = {"r9=@" & s[ref[3][1]..ref[3][2]],
"09" & s[ref[2][1]] & " " & s}
prog = replace(prog, s, n)
n += 2
continue
end if
ref = re:find(set_val, s)
if sequence(ref) then
s = num(s[ref[2][1]], to_integer(s[ref[3][1]..ref[3][2]]), 0)
s[1] &= prog[n][ref[1][2]+1..$]
prog = replace(prog, s, n)
n += length(s)
continue
end if
s = re:find_replace(add, s, `3\1\2 r\1+=\2`)
s = re:find_replace(mul, s, `4\1\2 r\1*=\2`)
s = re:find_replace(set_reg, s, `5\1\2 r\1=r\2`)
s = re:find_replace(add_reg, s, `6\1\2 r\1+=r\2`)
s = re:find_replace(mul_reg, s, `7\1\2 r\1*=r\2`)
s = re:find_replace(load, s, `8\1\2 r\1=[r\2]`)
s = re:find_replace(store, s, `9\2\1 [r\1]=r\2`)
s = re:find_replace(halt, s, `100 halt`)
s = re:find_replace(nop, s, `300 nop`)
prog[n] = s
n += 1
end while
-- middle pass: presize label loads and check each label address
while not done do
done = 1
tries += 1
n = 0
for i = 1 to length(prog) do
ref = re:find(a_label, prog[i])
if sequence(ref) then
s = prog[i][ref[2][1]..ref[2][2]]
if map:get(labels, s, -1) != n then
-- recalculate label
if tries > 20 and map:get(labels, s) = n + 1 then
n = map:get(labels, s) + 1 -- give up and pad later with nops
elsif tries > 30 and map:get(labels, s) > n then
n = map:get(labels, s) + 1 -- give up and pad later with nops
else
done = 0
--if length(num('0', n, 0)) > length(num('0', n+1, 0)) and tries < 10 then
-- n += 1
--end if
map:put(labels, s, n)
end if
--printf(2, "%s is %d\n", {s, n})
end if
continue
end if
ref = re:find(set_lbl, prog[i])
if sequence(ref) then
s = prog[i][ref[3][1]..ref[3][2]]
n += length(num('0', map:get(labels, s), 0))
continue
end if
n += 1
end for
end while
--printf(2, "tries=%d\n", tries)
-- final pass: assemble label loads and remove labels
n = 1
while n <= length(prog) do
ref = re:find(set_lbl, prog[n])
if sequence(ref) then
s = prog[n][ref[3][1]..ref[3][2]]
if not map:has(labels, s) then
printf(2, "undefined label: %s\n", {s})
abort(1)
end if
s = num(prog[n][ref[2][1]], map:get(labels, s), 0)
s[1] &= prog[n][ref[1][2]+1..$]
prog = replace(prog, s, n)
n += length(s)
continue
end if
ref = re:find(a_label, prog[n])
if sequence(ref) then
s = prog[n][ref[2][1]..ref[2][2]]
--printf(2,"label %s is at %d n is %d\n", {s, map:get(labels, s), n})
s = repeat("300 nop", map:get(labels, s) - n + 1) -- nop padding
prog = replace(prog, s, n)
n += length(s)
continue
end if
n += 1
end while
return prog
end function
constant cmd_line = command_line()
write_lines(1, assemble(read_lines(cmd_line[3])))
30. Re: Contest #2... Example Programs
- Posted by mattlewis (admin) Dec 14, 2010
- 2833 views
There's also a problem when there's a backward reference and forward reference that overlap: the size of the label loads may shift the label address up and down, and the assembler doesn't terminate until the label addresses stop fluctuating.
Yeah, that's why I went with the powers of two. It was easy to calculate. Also, I was more interested in inefficient code, in order to get longer benchmarks for interpreters.
Matt
31. Re: Contest #2... Example Programs
- Posted by coconut Dec 14, 2010
- 2770 views
This crippled cpu triggered a lot of thinking ascribed to its own nature. I guess everyone was wondering how to code real programs witch such a poor cpu.
No status register
logical operations reduce to a single jnz
RISC takes a new meaning with that cpu.
Anyway as I was arriving from work I found in my mailbox "Operating systems design and implementation" by Tanembaum and Woodhull.
Thanks to Amazon used books, I got it for cheap. So my curiosity will follow another path for a while.
Jacques
32. Re: Contest #2... Example Programs
- Posted by DerekParnell (admin) Dec 14, 2010
- 2649 views
This crippled cpu triggered a lot of thinking ascribed to its own nature. I guess everyone was wondering how to code real programs witch such a poor cpu.
- No status register
- logical operations reduce to a single jnz
RISC takes a new meaning with that cpu
Jacques
This really is a RISC chip ... so risky I'd never buy one.
33. Re: Contest #2... Example Programs
- Posted by unkmar Dec 15, 2010
- 2740 views
Generates a grid like this.
1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1
800 ; r[0] = -1 292 ; \ (2*3-1) 493 ; > Tinker with these lines to change the size 690 ; / -- Subtract 1 519 ; loop 1 529 ; loop 2 620 237 ; jump point (this_line # - 1) 553 359 352 260 540 742 641 640 054 ; skip if r[4] != 0 261 620 ??6 032 ; end loop 2 610 630 630 355 359 260 540 742 641 054 ; skip if r[4] != 0 261 ?6 031 ; end loop 1 100 ; Halt
34. Re: Contest #2... Example Programs
- Posted by unkmar Dec 19, 2010
- 2587 views
Can you read the message? This program has a few extra goodies in it. It is guaranteed to test every function and is usable as a bench mark if you change line 425 to 100, A HALT I will post a follow-up message creator program with some instructions on how to use it.
399 ; Goto line 32 to control the Delay speed
395 ;
099 ;
511 ; This CPU program created by:
511 ; Lucius L. Hilley III
511 ; aka: Unkmar
511 ; http://www.hilleyonline.com/
511 ; http://www.unkmar.com/
511 ;
511 ; [ 2010-12-18 22:52:15 EST ]
511 ;
511 ;
511 ;
511 ;
399 ; --=<{([ Push Message ]})>=-
398 ; IP will be stored at r[9]
099 ; IP = Instruction Pointer
511 ; Maintain the IP and usually
511 ; Things work.
511 ; ------------------------------
511 ; Message encoding font is 1-based
511 ; Character set is:
511 ; "ABCDEFGHIJKLMNOPQRSTUVWXYZ "
511 ; A = 1, Z = 26, ' ' = 27
511 ; 0 = End of Message
511 ; Max length = 980
511 ; ------------------------------
511 ; mem[1..9] Reserved for
511 ; Function Pointers
511 ; mem[10] = Delay Count
511 ; ------------------------------
399 ; -- First CODE
399 ; Set Delay Count
215 ; x = 5
711 ; ((x^2)^2)^2
711
711
411
411
411
411
200 ; POP -1
800 ;
710 ; r[1] *= -1 (Negate r[1])
205 ;
305 ;
910 ; [PUSH] Delay Count
200 ; Reset used registers
210 ; ------------------------------
393
229 ; MP = 11 --Prime Message Pointer
322 ;
391 ; ------------------------------
396 ; --==[ Letter START ]==-
321 ; MP += 1
219 ; W (Letter goes here)
319
315
912 ; [PUSH] --==[ Letter END ]==-
394 ; --==[ Letter START ]==-
321 ; MP += 1
215 ; E (Letter)
912 ; [PUSH]
395 ; --==[ Letter START ]==-
321 ; MP += 1
219 ; L (Letter)
313
912 ; [PUSH]
394 ; --==[ Letter START ]==-
321 ; MP += 1
213 ; C (Letter)
912 ; [PUSH]
395 ; --==[ Letter START ]==-
321 ; MP += 1
219 ; O (Letter)
316
912 ; [PUSH]
395 ; --==[ Letter START ]==-
321 ; MP += 1
219 ; M (Letter)
314
912 ; [PUSH]
394 ; --==[ Letter START ]==-
321 ; MP += 1
215 ; E (Letter)
912 ; [PUSH]
396 ; --==[ Letter START ]==-
321 ; MP += 1
219 ; (Letter)
319
319
912 ; [PUSH]
396 ; --==[ Letter START ]==-
321 ; MP += 1
219 ; T (Letter)
319
312
912 ; [PUSH]
395 ; --==[ Letter START ]==-
321 ; MP += 1
219 ; O (Letter)
316
912 ; [PUSH]
396 ; --==[ Letter START ]==-
321 ; MP += 1
219 ; (Letter)
319
319
912 ; [PUSH]
396 ; --==[ Letter START ]==-
321 ; MP += 1
219 ; T (Letter)
319
312
912 ; [PUSH]
394 ; --==[ Letter START ]==-
321 ; MP += 1
218 ; H (Letter)
912 ; [PUSH]
394 ; --==[ Letter START ]==-
321 ; MP += 1
215 ; E (Letter)
912 ; [PUSH]
396 ; --==[ Letter START ]==-
321 ; MP += 1
219 ; (Letter)
319
319
912 ; [PUSH]
394 ; --==[ Letter START ]==-
321 ; MP += 1
213 ; C (Letter)
912 ; [PUSH]
395 ; --==[ Letter START ]==-
321 ; MP += 1
219 ; P (Letter)
317
912 ; [PUSH]
396 ; --==[ Letter START ]==-
321 ; MP += 1
219 ; U (Letter)
319
313
912 ; [PUSH]
396 ; --==[ Letter START ]==-
321 ; MP += 1
219 ; (Letter)
319
319
912 ; [PUSH]
396 ; --==[ Letter START ]==-
321 ; MP += 1
219 ; T (Letter)
319
312
912 ; [PUSH]
394 ; --==[ Letter START ]==-
321 ; MP += 1
218 ; H (Letter)
912 ; [PUSH]
394 ; --==[ Letter START ]==-
321 ; MP += 1
211 ; A (Letter)
912 ; [PUSH]
396 ; --==[ Letter START ]==-
321 ; MP += 1
219 ; T (Letter)
319
312
912 ; [PUSH]
396 ; --==[ Letter START ]==-
321 ; MP += 1
219 ; (Letter)
319
319
912 ; [PUSH]
394 ; --==[ Letter START ]==-
321 ; MP += 1
215 ; E (Letter)
912 ; [PUSH]
396 ; --==[ Letter START ]==-
321 ; MP += 1
219 ; U (Letter)
319
313
912 ; [PUSH]
395 ; --==[ Letter START ]==-
321 ; MP += 1
219 ; P (Letter)
317
912 ; [PUSH]
394 ; --==[ Letter START ]==-
321 ; MP += 1
218 ; H (Letter)
912 ; [PUSH]
395 ; --==[ Letter START ]==-
321 ; MP += 1
219 ; O (Letter)
316
912 ; [PUSH]
395 ; --==[ Letter START ]==-
321 ; MP += 1
219 ; R (Letter)
319
912 ; [PUSH]
394 ; --==[ Letter START ]==-
321 ; MP += 1
219 ; I (Letter)
912 ; [PUSH]
394 ; --==[ Letter START ]==-
321 ; MP += 1
211 ; A (Letter)
912 ; [PUSH]
396 ; --==[ Letter START ]==-
321 ; MP += 1
219 ; (Letter)
319
319
912 ; [PUSH]
394 ; --==[ Letter START ]==-
321 ; MP += 1
212 ; B (Letter)
912 ; [PUSH]
396 ; --==[ Letter START ]==-
321 ; MP += 1
219 ; U (Letter)
319
313
912 ; [PUSH]
394 ; --==[ Letter START ]==-
321 ; MP += 1
219 ; I (Letter)
912 ; [PUSH]
395 ; --==[ Letter START ]==-
321 ; MP += 1
219 ; L (Letter)
313
912 ; [PUSH]
396 ; --==[ Letter START ]==-
321 ; MP += 1
219 ; T (Letter)
319
312
912 ; [PUSH]
396 ; --==[ Letter START ]==-
321 ; MP += 1
219 ; (Letter)
319
319
912 ; [PUSH]
396 ; --==[ Letter START ]==-
321 ; MP += 1
219 ; (Letter)
319
319
912 ; [PUSH]
396 ; --==[ Letter START ]==-
321 ; MP += 1
219 ; (Letter)
319
319
912 ; [PUSH]
396 ; --==[ Letter START ]==-
321 ; MP += 1
219 ; (Letter)
319
319
912 ; [PUSH]
519 ; IP will be stored at r[9]
318 ; Skip (21) --------------------
201 ; r[0] will enum functions
910 ;
393 ;
399 ; -=[ Using 39x's to maintain IP ]=-
399 ; -=[ 20 = 392 + 399 + 399 ]=-
099 ; Display Registers
??0 ; 0--------- > r[0] = -1
??1 ; -1-------- > r[1] = PUSH/POP Message
??2 ; --2------- > r[2] = Message Pointer
??3 ; ---3------ > r[3] = POP Message (Copy)
??4 ; ----4----- > r[4] = Loop IP
??5 ; -----5---- > r[5] = Offset to Characters
??6 ; ------6--- > r[6] = Character Size
??7 ; -------7-- > r[7] = Foregrond (Text)
??8 ; --------8- > r[8] = Background
?9 ; ---------9 > r[9] = IP - instruction pointer
200 ; (393 399 ??0 ??1 ??2 ??3 ??4 ??5 ??6 ??7 ??8 ?9)-:s:\s:\r:g
800 ;
099 ; RETURN - {1}Display Registers (11 of 21)
519 ; Skip (32) --------------------
318 ;
301 ; enum
910 ;
218 ;
414 ;
691 ;
099 ;
202 ; [POP] Registers
309 ; -=( Uses r[0] as mem[r[0]..r[0]+7])=-
402 ;
409 ;
405 ;
511 ; Padding for Choosing other locations. Needs to match POP
810 ; POP r[1]
301 ;
820 ; POP r[2]
301 ;
830 ; POP r[3]
301 ;
840 ; POP r[4]
301 ;
850 ; POP r[5]
301 ;
860 ; POP r[6]
301 ;
870 ; POP r[7]
301 ;
880 ; POP r[8]
200 ;
800 ; -=( Restores r[0] from mem[0] )=-
099 ; RETURN - {2}POP (25 of 32)
519 ; Skip (32) --------------------
318 ;
301 ; enum
910 ;
218 ;
414 ;
691 ;
099 ; ------------------------------
202 ; [PUSH] Registers
309 ; -=( Uses r[0] as mem[r[0]..r[0]+7])=-
402 ;
409 ;
405 ;
511 ; Padding for Choosing other locations. Needs to match POP
910 ; PUSH r[1]
301 ;
920 ; PUSH r[2]
301 ;
930 ; PUSH r[3]
301 ;
940 ; PUSH r[4]
301 ;
950 ; PUSH r[5]
301 ;
960 ; PUSH r[6]
301 ;
970 ; PUSH r[7]
301 ;
980 ; PUSH r[8]
200 ;
800 ; -=( Restores r[0] from mem[0] )=-
099 ; RETURN - {3}PUSH (25 of 32)
519 ; Skip (12) --------------------
317 ;
301 ; enum
910 ;
393 ;
399 ;
099 ; ------------------------------
311 ; Count += 1
001 ; Goto Count += 1 until Count = 0
200 ;
800 ;
099 ; RETURN - {4}Delay(r[1])
394 ;
210 ; Cleanup r[0..1] = 0
200 ;
099 ;
399 ; --=<{([ Start Program ]})>=-
397 ; Plus (17)
800 ; -=( POP -1 into r[0] )=-
277 ; Set Foreground
288 ; Set Background
259 ; { Character
352 ; width = 11 }
269 ; { Character
364 ; height 13 }
765 ; Combine Character size
361 ; Add RETURN Instruction
250 ; Clean-up
099 ; ------------------------------
511 ; Now using r[0,2] and r[6..9]
511 ; ------------------------------
511 ; SKIP mem[0..9] (MP = 9)
399 ; ------------------------------
394 ; ------------------------------
321 ; MP += 1
210 ; Force a NULL
912 ; [PUSH]
229 ; MP = 11 --Reset Message Pointer
322 ; -=<({[ Last SAFE Command ]})>=-
511 ; -=<({[ Crazy Loops and Jumps Below ]})>=-
511 ; -=<({[ 3 values Must be Maintained ]})>=-
511 ; *** WARNING *** Do not edit below this point
549 ; Set r[4] = r[9] as (Loop IP) -->\
399 ; ------------------------------ |
393 ; /
321 ; MP += 1 (r[4] Points here) <---/
812 ; Grab Char of Message
832 ; Copy to r[3]
610 ; Subtract 1 to convert to 0-index
716 ; Multiply Character size
554 ; Grab IP of r[4]
359 ; Add Offset to Characters
359 ;
359 ;
359 ; (Skips HALT)
615 ; Add Offset
013 ; Gosub Character(r[3])
399 ; ------------------------------
219 ; Get Delay Counter
311 ; r[1] = 10
811 ; POP mem[10]
511 ; Not safe for me to remove
511 ; 2 nop's :( Crazy jumps down here ):
204 ; Select Delay(r[1])
800
000
409 ; -- (r[9] Points here)
690
200
800
043
290 100 ; -=[HALT]=-
280
270
260
250
240
230
220
210
010
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??8
??8
??8
??7
??7
??7
??8
??8
??8
?8
??8
??8
??8
??7
??7
??7
??7
??7
??8
??8
?8
??8
??8
??7
??7
??7
??8
??7
??7
??7
??8
?8
??8
??8
??7
??7
??8
??8
??8
??7
??7
??8
?8
??8
??7
??7
??7
??8
??8
??8
??7
??7
??7
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??7
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
099
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??7
??7
??7
??7
??7
??8
??8
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??8
?8
??8
??7
??7
??8
??8
??8
??8
??7
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??7
??7
??7
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??8
?8
??8
??7
??7
??7
??7
??7
??7
??7
??8
??8
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??8
?8
??8
??7
??7
??8
??8
??8
??8
??7
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??7
??7
??7
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??8
?8
??8
??7
??7
??7
??7
??7
??7
??7
??8
??8
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
099
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??8
??8
??7
??7
??7
??7
??7
??8
??8
?8
??8
??8
??7
??7
??7
??7
??7
??7
??7
??8
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??7
?8
??8
??7
??7
??7
??8
??8
??8
??7
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??7
??8
??8
??8
??7
??7
??7
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??7
?8
??8
??8
??7
??7
??7
??7
??7
??7
??7
??8
?8
??8
??8
??8
??7
??7
??7
??7
??7
??8
??8
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
099
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??7
??7
??7
??7
??7
??8
??8
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??8
?8
??8
??7
??7
??8
??8
??8
??7
??7
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??7
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??7
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??7
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??7
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??7
??7
??7
?8
??8
??7
??7
??8
??8
??8
??7
??7
??7
??7
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??8
?8
??8
??7
??7
??7
??7
??7
??7
??7
??8
??8
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
099
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??7
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??7
??7
??7
??7
??7
??8
??8
?8
??8
??7
??7
??7
??7
??7
??7
??7
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??7
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??7
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
099
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??7
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??7
??7
??7
??7
??7
??8
??8
?8
??8
??7
??7
??7
??7
??7
??7
??7
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??8
??8
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
099
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??8
??8
??7
??7
??7
??7
??7
??8
??8
?8
??8
??8
??7
??7
??7
??7
??7
??7
??7
??8
?8
??8
??7
??7
??7
??8
??8
??8
??7
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??8
??8
??7
??7
??7
??7
??7
?8
??8
??7
??7
??8
??8
??7
??7
??7
??7
??7
?8
??8
??7
??7
??7
??8
??8
??8
??7
??7
??7
?8
??8
??8
??7
??7
??7
??7
??7
??7
??7
??7
?8
??8
??8
??8
??7
??7
??7
??7
??8
??7
??7
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
099
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??7
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
099
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??7
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??7
?8
??8
??8
??8
??8
??7
??7
??7
??8
??8
??8
?8
??8
??8
??8
??8
??7
??7
??7
??8
??8
??8
?8
??8
??8
??8
??8
??7
??7
??7
??8
??8
??8
?8
??8
??8
??8
??8
??7
??7
??7
??8
??8
??8
?8
??8
??8
??8
??8
??7
??7
??7
??8
??8
??8
?8
??8
??8
??8
??8
??7
??7
??7
??8
??8
??8
?8
??8
??8
??8
??8
??7
??7
??7
??8
??8
??8
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??7
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??7
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
099
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??8
??8
??7
??7
??7
??7
??7
??7
??7
?8
??8
??8
??8
??7
??7
??7
??7
??7
??7
??7
?8
??8
??8
??8
??8
??8
??8
??7
??7
??8
??8
?8
??8
??8
??8
??8
??8
??8
??7
??7
??8
??8
?8
??8
??8
??8
??8
??8
??8
??7
??7
??8
??8
?8
??8
??8
??8
??8
??8
??8
??7
??7
??8
??8
?8
??8
??8
??8
??8
??8
??8
??7
??7
??8
??8
?8
??8
??8
??8
??8
??8
??8
??7
??7
??8
??8
?8
??8
??7
??7
??8
??8
??7
??7
??7
??8
??8
?8
??8
??7
??7
??7
??7
??7
??7
??7
??8
??8
?8
??8
??8
??7
??7
??7
??7
??7
??8
??8
??8
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
099
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??7
??7
??7
?8
??8
??7
??7
??8
??8
??8
??7
??7
??7
??8
?8
??8
??7
??7
??8
??8
??7
??7
??7
??8
??8
?8
??8
??7
??7
??7
??7
??7
??7
??8
??8
??8
?8
??8
??7
??7
??7
??7
??7
??8
??8
??8
??8
?8
??8
??7
??7
??7
??7
??7
??7
??8
??8
??8
?8
??8
??7
??7
??8
??8
??7
??7
??7
??8
??8
?8
??8
??7
??7
??8
??8
??8
??7
??7
??7
??8
?8
??8
??7
??7
??8
??8
??8
??8
??7
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
099
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??7
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??7
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??7
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
099
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??7
??8
??8
??8
??7
??7
??7
?8
??8
??7
??7
??7
??7
??8
??7
??7
??7
??7
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??7
?8
??8
??7
??7
??8
??7
??7
??7
??8
??7
??7
?8
??8
??7
??7
??8
??8
??7
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
099
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??7
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??7
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??7
??7
??8
??8
??8
??7
??7
?8
??8
??7
??7
??7
??7
??7
??8
??8
??7
??7
?8
??8
??7
??7
??7
??7
??7
??7
??8
??7
??7
?8
??8
??7
??7
??8
??7
??7
??7
??7
??7
??7
?8
??8
??7
??7
??8
??8
??7
??7
??7
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??7
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??7
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
099
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??8
??8
??7
??7
??7
??7
??7
??8
??8
?8
??8
??8
??7
??7
??7
??7
??7
??7
??7
??8
?8
??8
??7
??7
??7
??8
??8
??8
??7
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??7
??8
??8
??8
??7
??7
??7
?8
??8
??8
??7
??7
??7
??7
??7
??7
??7
??8
?8
??8
??8
??8
??7
??7
??7
??7
??7
??8
??8
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
099
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??7
??7
??7
??7
??7
??8
??8
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??8
?8
??8
??7
??7
??8
??8
??8
??8
??7
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??7
??7
??7
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??8
?8
??8
??7
??7
??7
??7
??7
??7
??7
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??8
??8
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
099
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??8
??8
??7
??7
??7
??7
??7
??8
??8
?8
??8
??8
??7
??7
??7
??7
??7
??7
??7
??8
?8
??8
??7
??7
??7
??8
??8
??8
??7
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??7
??7
??8
??7
??7
?8
??8
??7
??7
??8
??8
??7
??7
??7
??7
??7
?8
??8
??7
??7
??7
??8
??8
??7
??7
??7
??8
?8
??8
??8
??7
??7
??7
??7
??7
??7
??7
??7
?8
??8
??8
??8
??7
??7
??7
??7
??8
??7
??7
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
099
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??7
??7
??7
??7
??7
??8
??8
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??8
?8
??8
??7
??7
??8
??8
??8
??8
??7
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??7
??7
??7
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??8
?8
??8
??7
??7
??7
??7
??7
??7
??7
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??7
??7
??8
?8
??8
??7
??7
??8
??8
??8
??8
??7
??7
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
099
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??8
??8
??7
??7
??7
??7
??7
??8
??8
?8
??8
??8
??7
??7
??7
??7
??7
??7
??7
??8
?8
??8
??7
??7
??7
??8
??8
??8
??7
??7
??7
?8
??8
??7
??7
??7
??8
??8
??8
??8
??8
??8
?8
??8
??8
??7
??7
??7
??7
??8
??8
??8
??8
?8
??8
??8
??7
??7
??7
??7
??7
??7
??8
??8
?8
??8
??8
??8
??8
??7
??7
??7
??7
??7
??8
?8
??8
??8
??8
??8
??8
??8
??7
??7
??7
??7
?8
??8
??7
??7
??7
??8
??8
??8
??7
??7
??7
?8
??8
??8
??7
??7
??7
??7
??7
??7
??7
??8
?8
??8
??8
??8
??7
??7
??7
??7
??7
??8
??8
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
099
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??7
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??7
?8
??8
??8
??8
??8
??7
??7
??7
??8
??8
??8
?8
??8
??8
??8
??8
??7
??7
??7
??8
??8
??8
?8
??8
??8
??8
??8
??7
??7
??7
??8
??8
??8
?8
??8
??8
??8
??8
??7
??7
??7
??8
??8
??8
?8
??8
??8
??8
??8
??7
??7
??7
??8
??8
??8
?8
??8
??8
??8
??8
??7
??7
??7
??8
??8
??8
?8
??8
??8
??8
??8
??7
??7
??7
??8
??8
??8
?8
??8
??8
??8
??8
??7
??7
??7
??8
??8
??8
?8
??8
??8
??8
??8
??7
??7
??7
??8
??8
??8
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
099
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??7
?8
??8
??8
??7
??7
??7
??7
??7
??7
??7
??8
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
099
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??7
??8
??8
??8
??7
??7
??7
?8
??8
??8
??7
??7
??8
??8
??8
??7
??7
??8
?8
??8
??8
??7
??7
??8
??8
??8
??7
??7
??8
?8
??8
??8
??7
??7
??7
??8
??7
??7
??7
??8
?8
??8
??8
??8
??7
??7
??8
??7
??7
??8
??8
?8
??8
??8
??8
??7
??7
??7
??7
??7
??8
??8
?8
??8
??8
??8
??8
??7
??7
??7
??8
??8
??8
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
099
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??8
??8
??7
??8
??8
??7
??7
?8
??8
??7
??7
??8
??7
??7
??7
??8
??7
??7
?8
??8
??7
??7
??8
??7
??7
??7
??8
??7
??7
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??7
?8
??8
??7
??7
??7
??7
??8
??7
??7
??7
??7
?8
??8
??8
??7
??7
??8
??8
??8
??7
??7
??8
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
099
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??7
??8
??8
??8
??7
??7
??7
?8
??8
??7
??7
??7
??8
??8
??8
??7
??7
??7
?8
??8
??8
??7
??7
??7
??8
??7
??7
??7
??8
?8
??8
??8
??8
??7
??7
??7
??7
??7
??8
??8
?8
??8
??8
??8
??8
??7
??7
??7
??8
??8
??8
?8
??8
??8
??8
??7
??7
??7
??7
??7
??8
??8
?8
??8
??8
??7
??7
??7
??8
??7
??7
??7
??8
?8
??8
??7
??7
??7
??8
??8
??8
??7
??7
??7
?8
??8
??7
??7
??7
??8
??8
??8
??7
??7
??7
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
099
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??8
??8
??8
??8
??8
??7
??7
?8
??8
??7
??7
??7
??8
??8
??8
??7
??7
??7
?8
??8
??7
??7
??7
??8
??8
??8
??7
??7
??7
?8
??8
??8
??7
??7
??7
??8
??7
??7
??7
??8
?8
??8
??8
??8
??7
??7
??7
??7
??7
??8
??8
?8
??8
??8
??8
??8
??7
??7
??7
??8
??8
??8
?8
??8
??8
??8
??8
??7
??7
??7
??8
??8
??8
?8
??8
??8
??8
??8
??7
??7
??7
??8
??8
??8
?8
??8
??8
??8
??8
??7
??7
??7
??8
??8
??8
?8
??8
??8
??8
??8
??7
??7
??7
??8
??8
??8
?8
??8
??8
??8
??8
??7
??7
??7
??8
??8
??8
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
099
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??7
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??7
?8
??8
??8
??8
??8
??8
??8
??7
??7
??7
??8
?8
??8
??8
??8
??8
??8
??7
??7
??7
??8
??8
?8
??8
??8
??8
??8
??7
??7
??7
??8
??8
??8
?8
??8
??8
??8
??7
??7
??7
??7
??8
??8
??8
?8
??8
??8
??8
??7
??7
??7
??8
??8
??8
??8
?8
??8
??8
??7
??7
??7
??8
??8
??8
??8
??8
?8
??8
??7
??7
??7
??8
??8
??8
??8
??8
??8
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??7
?8
??8
??7
??7
??7
??7
??7
??7
??7
??7
??7
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
099
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
??8
??8
??8
??8
??8
??8
??8
??8
??8
??8
?8
099
100 ; -=[HALT]=-
35. Re: Contest #2... Example Programs
- Posted by DerekParnell (admin) Dec 19, 2010
- 2527 views
Can you read the message?
Yes! Very nicely done.
36. Re: Contest #2... Example Programs
- Posted by unkmar Dec 19, 2010
- 2557 views
The font set was hand crafted as a grid in vim and then I used vim's regex to produce the print statements. The choice of using registers 7 and 8 for foreground were actually accidental. I felt those numbers provided a high contrast display. Afterwards I was getting blank squares because I had not set those registers to a value.
The approximate 400 lines of code were hand written. I did not use any assembler or translator to manage the jump points. At this point I have committed the instruction set to memory. I can read and write the codes without having to reference the guide. or look at the comments.
I setup a handful of conceptual ideas that made it easier for me to manage the code. I reserved r[9] as an Instruction Pointer (IP), I would maintain the pointer throughout the code. It made functions such as each character in the font a very easy task. Like others I had reserved r[0] for -1. At some point I started running out of registers. I wasn't storing much of anything in RAM yet. And so I was having trouble finding a register to use for manipulating numbers or jumping into functions, mainly my delay function. Then I realized that r[0] could easily pull double duty if I restore it before return from the function. That requires just 2 instructions. 200, 800.
As I was adding functions I was having to go back and update the sections of code that would jump into the function. The addresses would move around a little as I was altering functionality. So, I decided to do 2 things. Store the addresses to the functions in RAM, (At early points, mem[1..9]), And to use an enum to automatically append the function at the next address. The code became much easier to maintain and... The functions now had a LOT more overhead. Before, I could put 7 instructions in a 9 instruction block. Only 2 instructions for overhead. One for maintaining the IP and one for the return instruction. Afterwards, 9 instructions make up an empty function with 0 instruction space to actually do anything. So, that is minimum of 10, NOT 9 instructions of overhead. Remember, I am maintaining an IP using only addition for offsets. 399 just to have an empty function, Meaning I can't just increase that last digit. I have to use another instruction just to give me some room for code. So the smallest function has room for 8 instructions. 399 is one instruction leaving you the remaining 8.
I found it easiest to maintain the IP's if I coded in sections that were multiples of 10. (Reminds me of the old BASIC programming days. 10 print "Hello "; 20 goto 10). A section of 10 has 8 usable instructions with 2 for overhead 391 399. A section of 20 allows for 1 more instruction, 17 instead of 16. (Instead of 391 399 391 399, you have 392 399 399.) The size starts to get easy to spot if you use the convention of using the smaller number first. 391 399 = 10. Notice the 1=10. And 392 399 399 = 20.
The IP points that double as jump points are easy to spot when at 10 base boundaries. 1, 11, 21, 31. Just look for that last digit. After a bit I was able to use multiples of 5 easily enough, 1, 11, 26, 36, 51. The last digit is a 1 or 6.
Maintaining an IP at r[9] works great for commenting code. I can start a comment section of 10 lines with 391 399 099, Those 3 instructions are the only ones that will be executed. The 099 Jumps past the other 7. Thus allowing you to have sections of code for comments without a major slow down. I could have a really large section with 393 399 399 399 099. That is 5 lines of execution followed by 25 lines of any valid code that will be completely ignored or skipped. HINT: repeated codes are more visible, ignored or not.
There are plenty of NOP's from which to choose. such as, 3x0 4x1 5xx, where x is any digit. I decided to go with 511 in most cases because the 11's are skinny and easy spot. In areas where I may be tweaking the code I might use a 4x1 or 3x0. I might change the 3x0 to a 3x3 or the 4x1 to a 4x2 or 4x4. Interpreter wise, I'm not sure which opcode would be faster and that may depend on which one of the many interpreters you choose to use.
37. Re: Contest #2... Example Programs
- Posted by unkmar Dec 21, 2010
- 2406 views
File: message.ex
#!/usr/bin/eui include std/text.e include get.e with trace constant VALIDS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ " function purify(sequence msg) integer rp, vcp sequence temp, result temp = upper(msg) result = temp rp = 1 -- Result Pointer for A = 1 to length(temp) do vcp = find(temp[A], VALIDS) if vcp then result[rp] = temp[A] rp += 1 end if end for return result[1..rp-1] end function function convert(sequence msg) integer rp, vcp sequence result result = msg rp = 1 -- Result Pointer for A = 1 to length(result) do vcp = find(result[A], VALIDS) if vcp then result[rp] = {} while (vcp > 9) do result[rp] &= 9 vcp -= 9 end while result[rp] &= vcp rp += 1 end if end for return result[1..rp-1] end function integer fp integer comments sequence YesNo, msg, cmsg fp = open("message.txt", "w") comments = 0 YesNo = "YyNn" puts(1, "\tYour message code will be output to message.txt\n") puts(1, "\tMax Message length is 989\n\n") puts(1, "\t Longer codes can be generated\n") puts(1, "\t And will crash the cpu program\n") puts(1, "\tDo you want to output code Comments? [Y/n]") while (0 = find(comments, YesNo)) do comments = wait_key() if find(comments, "\r\n") then comments = 'Y' end if end while if comments = 'Y' or comments = 'y' then puts(1, " Yes\n") else puts(1, " No\n") end if puts(1, "\n") puts(1, "Message: ") msg = gets(0) msg = purify(msg) cmsg = convert(msg) puts(1, "\n") if comments = 'Y' then if (40 > length(msg)) then printf (fp, "391 ; %s\n", {34 & msg & 34}) end if printf(fp, "39%d ; --==[ Letter START ]==-\n", length(cmsg[1]) + 3) puts(fp, "321 ; MP += 1\n") printf(fp, "21%d ; %s (Letter goes here)\n", {cmsg[1][1], msg[1]}) for B = 2 to length(cmsg[1]) do printf(fp, "31%d\n", cmsg[1][B]) end for puts(fp, "912 ; [PUSH] --==[ Letter END ]==-\n") else printf(fp, "39%d\n", length(cmsg) + 3) puts(fp, "321\n") printf(fp, "215\n", cmsg[1][1]) for B = 2 to length(cmsg[1]) do printf(fp, "31%d\n", cmsg[1][B]) end for puts(fp, "912\n") end if for A = 2 to length(msg) do if comments = 'Y' then printf(fp, "39%d ; --==[ Letter START ]==-\n", length(cmsg[A]) + 3) puts(fp, "321 ; MP += 1\n") printf(fp, "21%d ; %s (Letter)\n", {cmsg[A][1], msg[A]}) for B = 2 to length(cmsg[A]) do printf(fp, "31%d\n", cmsg[A][B]) end for puts(fp, "912 ; [PUSH]\n") else printf(fp, "39%d\n", length(cmsg) + 3) puts(fp, "321\n") printf(fp, "215\n", cmsg[A][1]) for B = 2 to length(cmsg[A]) do printf(fp, "31%d\n", cmsg[A][B]) end for puts(fp, "912\n") end if end for close(fp)

