+TheBF #51 Posted Wednesday at 04:07 AM For the curious this is the same program as previous except it uses a FOR NEXT loop structure which is just a down-counter with the index held on the return stack. This the output code with comments. You can see how the 9900 instructions map onto Forth quite well. Spoiler 2018 0646 dect R6 ; 3000 # ( pushes R4 accumulator 1st) 201A C584 mov R4,*R6 201C 0204 li R4,>3000 2020 0647 dect R7 2022 C5C4 mov R4,*R7 ; FOR ( loop index on return stack) 2024 C136 mov *R6+,R4 ; DROP 2026 0646 dect R6 ; AAAA # 2028 C584 mov R4,*R6 202A 0204 li R4,>AAAA 202E 0646 dect R6 ; DUP 2030 C584 mov R4,*R6 2032 C204 mov R4,R8 ; SWAP 2034 C116 mov *R6,R4 2036 C588 mov R8,*R6 2038 0646 dect R6 ; OVER 203A C584 mov R4,*R6 203C C126 mov @>0002(R6),R4 2040 06A0 bl @>2004 ; CALL ROT 2044 C136 mov *R6+,R4 ; DROP 2046 0646 dect R6 ; DUP 2048 C584 mov R4,*R6 204A 0556 inv *R6 ; AND 204C 4136 szc *R6+,R4 204E 0646 dect R6 ; DUP 2050 C584 mov R4,*R6 2052 E136 soc *R6+,R4 ; OR 2054 0646 dect R6 ; DUP 2056 C584 mov R4,*R6 2058 2936 xor *R6+,R4 ; XOR 205A 0584 inc R4 ; 1+ 205C 0604 dec R4 ; 1- 205E 05C4 inct R4 ; 2+ 2060 0644 dect R4 ; 2- 2062 0A14 sla R4,1 ; 2* 2064 0814 sra R4,1 ; 2/ 2066 0504 neg R4 ; NEGATE 2068 0744 abs R4 ; ABS 206A A136 a *R6+,R4 ; + 206C 0646 dect R6 ; 2 # 206E C584 mov R4,*R6 2070 0204 li R4,>0002 2074 C0F6 mov *R6+,R3 ; * 2076 38C4 mpy R4,R3 2078 C136 mov *R6+,R4 ; DROP 207A 0617 dec *R7 ; NEXT 207C 18D4 joc >2026 207E 05C7 inct R7 2080 045A b *R10 ; NEXT, (return to ITC Forth) Quote Share this post Link to post Share on other sites
+Lee Stewart #52 Posted Wednesday at 06:16 PM 14 hours ago, TheBF said: For the curious this is the same program as previous except it uses a FOR NEXT loop structure which is just a down-counter with the index held on the return stack. This the output code with comments. You can see how the 9900 instructions map onto Forth quite well. Reveal hidden contents 2018 0646 dect R6 ; 3000 # ( pushes R4 accumulator 1st) 201A C584 mov R4,*R6 201C 0204 li R4,>3000 2020 0647 dect R7 2022 C5C4 mov R4,*R7 ; FOR ( loop index on return stack) 2024 C136 mov *R6+,R4 ; DROP 2026 0646 dect R6 ; AAAA # 2028 C584 mov R4,*R6 202A 0204 li R4,>AAAA 202E 0646 dect R6 ; DUP 2030 C584 mov R4,*R6 2032 C204 mov R4,R8 ; SWAP 2034 C116 mov *R6,R4 2036 C588 mov R8,*R6 2038 0646 dect R6 ; OVER 203A C584 mov R4,*R6 203C C126 mov @>0002(R6),R4 2040 06A0 bl @>2004 ; CALL ROT 2044 C136 mov *R6+,R4 ; DROP 2046 0646 dect R6 ; DUP 2048 C584 mov R4,*R6 204A 0556 inv *R6 ; AND 204C 4136 szc *R6+,R4 204E 0646 dect R6 ; DUP 2050 C584 mov R4,*R6 2052 E136 soc *R6+,R4 ; OR 2054 0646 dect R6 ; DUP 2056 C584 mov R4,*R6 2058 2936 xor *R6+,R4 ; XOR 205A 0584 inc R4 ; 1+ 205C 0604 dec R4 ; 1- 205E 05C4 inct R4 ; 2+ 2060 0644 dect R4 ; 2- 2062 0A14 sla R4,1 ; 2* 2064 0814 sra R4,1 ; 2/ 2066 0504 neg R4 ; NEGATE 2068 0744 abs R4 ; ABS 206A A136 a *R6+,R4 ; + 206C 0646 dect R6 ; 2 # 206E C584 mov R4,*R6 2070 0204 li R4,>0002 2074 C0F6 mov *R6+,R3 ; * 2076 38C4 mpy R4,R3 2078 C136 mov *R6+,R4 ; DROP 207A 0617 dec *R7 ; NEXT 207C 18D4 joc >2026 207E 05C7 inct R7 2080 045A b *R10 ; NEXT, (return to ITC Forth) Is it usual for the FOR limit to not be consumed? ...lee 1 Quote Share this post Link to post Share on other sites
+TheBF #53 Posted Wednesday at 08:46 PM 2 hours ago, Lee Stewart said: Is it usual for the FOR limit to not be consumed? ...lee The DROP following FOR is doing that remembering that this system uses R4 as a cache for the top of stack. So DROP always refills R4 from the memory stack. The return stack works as a normal stack in memory so the inct R7 is removing the limit from the return stack 207A 0617 dec *R7 ; NEXT 207C 18D4 joc >2026 207E 05C7 inct R7 Unless you have found something I am completely missing, which has happened before, that is how I think it should work. 1 Quote Share this post Link to post Share on other sites
GDMike #54 Posted Wednesday at 11:38 PM Not a bad thing to happen 😜. Quote Share this post Link to post Share on other sites
+TheBF #55 Posted Thursday at 02:02 AM 2 hours ago, GDMike said: Not a bad thing to happen 😜. Indeed not. Lee has found so many bugs in my code I want to start calling him "Raid". 2 Quote Share this post Link to post Share on other sites
GDMike #56 Posted Thursday at 02:03 AM Just now, TheBF said: Indeed not. Lee has found so many bugs in my code I want to start calling him "Raid". Mine to, no matter what I was doing. The Eyes have it with him. Lol 1 Quote Share this post Link to post Share on other sites
+TheBF #57 Posted Thursday at 02:39 AM POP/PUSH Optimization This is something that I know should be a part of a good Forth native code compiler but I always created bugs when I tried it in the past. I think I have this working so I am going to explain again to myself and anyone who cares to read about it just to confirm my logic. When you run a Forth machine with a cache register for the top of stack element there are many Forth instructions that end with an instruction to refill the cache register. This is effectively a DROP function in the Forth machine because you are POPPING the stack into the register. Other Forth instructions need to use the cache register when they start, so they push the cache register onto the stack in memory first thing. This is effectively a DUP instruction on the Forth machine. IF a Forth instruction that ends with a DROP is followed immediately by an instruction that does a DUP that is three useless instructions that just thrash the top element of the stack. Three extra instructions on the 9900 can really slow things down, especially inside a loop. The solution was a "SMARTDUP" and I think I have the logic correct this time. Spoiler \ ************* optimizable operations *************** COMPILER : D= ( d d -- ?) ROT = -ROT = AND ; : 1LOOKBACK ( n -- ? ) THERE 1 CELLS - @ = ; : 2LOOKBACK ( d -- ? ) THERE 2 CELLS - [email protected] D= ; : REMOVE ( n -- ) CELLS NEGATE TALLOT ; \ remove n cells from program : ADUP C584 0646 ; \ DUP is 2 instructions, 4 bytes : !, TOS SWAP @@ MOV, ; : DROP, TOS POP, ; : DUP, TOS PUSH, ; : C!, TOS SWPB, TOS SWAP @@ MOVB, ; \ POP/PUSH optimization: \ Some words refill the stack with DROP. If the next word does a DUP \ we should not have compiled the DROP, so SMARTDUP removes it. COMPILER : SMARTDUP OPTIMIZER @ IF 0C136 1LOOKBACK \ did we just emit a drop? IF 1 REMOVE \ YES, so remove it ELSE DUP, \ NO, so we must DUP THEN ELSE DUP, \ regular DUP is compiled THEN ; TARGET : ! ( n variable --) [CC] OPTIMIZER @ IF ADUP 2LOOKBACK \ look back for ADUP IF 2 REMOVE !, ELSE !, DROP, \ un-optimized THEN ELSE !, DROP, \ un-optimized THEN ; TARGET : C! ( c variable --) [CC] OPTIMIZER @ IF ADUP 2LOOKBACK \ look back for DUP IF 2 REMOVE C!, \ optimized ELSE C!, DROP, \ un-optimized THEN ELSE C!, DROP, \ un-optimized THEN ; Using these concepts I also optimized ! and C! for expressions like : 1234 DUP X ! Since ! (store) consumes both of its arguments it always ends with a DROP. I look back 2 cells in the program and if I find a DUP I can remove that dup since 1234 is sitting in R4 ready to go. And since I removed the DUP I don't need the DROP after I store the number in X. * ADUP in the code has the instructions in reverse order to match the way [email protected] reads memory in 2LOOKBACK. 3 Quote Share this post Link to post Share on other sites
senior_falcon #58 Posted Thursday at 11:50 AM 9 hours ago, TheBF said: Indeed not. Lee has found so many bugs in my code I want to start calling him "Raid". The nose knows! 3 1 Quote Share this post Link to post Share on other sites
+TheBF #59 Posted Thursday at 03:16 PM MACHFORTH is getting closer to being useful This little program relocates the code to load at >A000 and it also steals the entire scratchpad for Forth stacks and workspace. And it successfully saves the image to disk. \ MFORTH DEMO #1b Use new workspace and stacks, save binary program \ If running on Classic99 you will see R4 counting down \ This demo shows: \ - compile to >A000 origin \ - create workspace and both stacks in scratchpad memory \ - saves a finished program that can RUN from E/A Option 5 COMPILER NEW. HEX A000 ORIGIN. INCLUDE DSK2.BYE \ a little code to exit program TARGET PROG: DEMO1 0 LIMI, \ disable interrupts to take over the machine 8300 WORKSPACE 8380 RSTACK 8400 DSTACK FFFF # BEGIN 1- \ decrement data stack -UNTIL \ -UNTIL DOES NOT consume the stack parameter DROP \ clean up the stack BYE \ Return to TI title screen END. SAVE DSK2.DEMO1C 4 Quote Share this post Link to post Share on other sites