1. Contest #2... Example Programs
- Posted by jeremy (admin) Dec 08, 2010
- 3075 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
- 3090 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
- 3051 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
- 3036 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
- 3021 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
- 2991 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
- 2944 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
- 2932 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
- 3045 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
- 5246 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
- 2882 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
- 2861 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
- 2821 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
- 2724 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
- 2742 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
- 2732 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
- 2750 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
- 2758 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
- 2759 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
- 2728 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
- 2705 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
- 2660 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
- 2634 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
- 2603 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
- 2589 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
- 2548 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
- 2560 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
- 2524 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
- 2612 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
- 2541 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
- 2428 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
- 2511 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
- 2366 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
- 2316 views
Can you read the message?
Yes! Very nicely done.
36. Re: Contest #2... Example Programs
- Posted by unkmar Dec 19, 2010
- 2346 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
- 2177 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)