Willsy Posted November 25, 2010 Share Posted November 25, 2010 Ok, here we go... +1 and +2 Which is greater? +2, obviously. Ok then: -1 and -2 Which is greater? There is no agreement here in the office! Some say -1 and some say -2. I'm leaning towards -1 being greater, but only when you imagine a conventional number line. If you don't care about 0, then you could say -2 is greater! To put this into a programming context... If I am counting backwards, say from -1 to -10 in a loop, which JMP instruction do I use? (I don't have access to my beloved Classic99 today, otherwise I would knock up some assembly to test it. But, essentially:) CLR R0 ; INITIAL VALUE LI R1,-1 ; INCREMENT VALUE LI R2,-50 ; END POINT AGAIN < DO SOME STUFF HERE > A R1,R0 ; GO BACKWARDS C R0,R2 ; COMPARE TO -50 JGT AGAIN ; LOOP IF NOT GREATER So, I want the code to exit when R0 (in this case) =-51 You are probably thinking "Why not just test for equality then you don't care about positive or negative numbers..." - true, but only true when the incrementor is 1 or -1. If it's 3 or -9 etc then you won't ever get equality, so you are reduced to looking for boundary crosses. This is connected with a nasty, evil bitch of a bug in +LOOP in TurboForth which I now have to correct, after major long-term procrastination. I have to fix it now, because I am just about to document the functionality! So, to summarise, where 'n' is positive, we can test for boundary crossing with JGT to exit a loop: LI R0,0 ; INITIAL VALUE LI R1,10 ; BOUNDARY LI R2,3 ; 'N' LOOP A R2,R0 ; ADD N TO VALUE C R0,R1 ; CROSSED THE BOUNDARY? JGT EXIT ; EXIT IF YES JMP LOOP ; OTHERWISE REPEAT EXIT .... So where N=3 as above, we would get 0 3 6 9 12 and out of the loop. But what about when we are negative? Do we use JGT or JLT? Quote Link to comment Share on other sites More sharing options...
sometimes99er Posted November 25, 2010 Share Posted November 25, 2010 LI R0,0 ; INITIAL VALUE LI R1,10 ; BOUNDARY LI R2,3 ; 'N' LOOP A R2,R0 ; ADD N TO VALUE C R0,R1 ; CROSSED THE BOUNDARY? JGT EXIT ; EXIT IF YES JMP LOOP ; OTHERWISE REPEAT EXIT .... But what about when we are negative? Do we use JGT or JLT? Looks like everyday conversation with teenager. Advice ... Try and stay positive ... Quote Link to comment Share on other sites More sharing options...
Thomas Jentzsch Posted November 25, 2010 Share Posted November 25, 2010 If you use signed numbers then -1 is > -2, for unsigned numbers -1 is < -2. So it depends on the definition of the branch instruction, what is bigger, greater, above etc. Quote Link to comment Share on other sites More sharing options...
matthew180 Posted November 25, 2010 Share Posted November 25, 2010 Thomas nailed it. On the TI there are jump instructions that are very specifically used to branch based on the UNSIGNED or SIGNED results of a comparison. That's why the CPU has two flags in the status register called "Logical Greater Than" (ST0) and "Arithmetic Greater Than" (ST1). The jump instructions that use ST0 are looking at the data as UNSIGNED values, i.e. they will never be considered negative: JH - Jump high JHE - Jump high or equal JL - Jump low JLE - Jump low or equal The ONLY two that consider the numbers as SIGNED are: JGT - Jump greater than JLT - Jump less than The naming of the instructions emphasizes the Logical vs. Arithmetic. The logical instructions use the terms "high" and "low". The arithmetic instructions use "greater" and "less". So, which one you use depends on if you are treating your numbers as SIGNED or UNSIGNED. Because CPUs store numbers in two's complement form, the bits that indicate any signed negative value, when looked at as unsigned value, will always be greater than the values that represent the signed positive numbers. Anyway, two's complement is one of those things you just have to read about and study until you "get it". At that point the answer will be clear. Matthew Quote Link to comment Share on other sites More sharing options...
+adamantyr Posted November 25, 2010 Share Posted November 25, 2010 Yea, only the arithmetic jumps should be used if negative values are a factor. Otherwise, unsigned values invert the number line; -1 is highest positive value, so it messes comparisons up. If I may ask, what exactly are you doing that requires negative values? In my own experience, there isn't a lot that mandates their use that can't be reworked into a base address + positive offset, which is generally easier to work with. Adamantyr Quote Link to comment Share on other sites More sharing options...
Willsy Posted November 25, 2010 Author Share Posted November 25, 2010 Yea, only the arithmetic jumps should be used if negative values are a factor. Otherwise, unsigned values invert the number line; -1 is highest positive value, so it messes comparisons up. If I may ask, what exactly are you doing that requires negative values? In my own experience, there isn't a lot that mandates their use that can't be reworked into a base address + positive offset, which is generally easier to work with. Adamantyr Thanks for the replies everyone. To answer your question, Adamantyr, Forth has a word called +LOOP which is used in conjunction with DO. First the traditional DO with LOOP: : TEST 10 0 DO I . LOOP ; ok TEST 0 1 2 3 4 5 6 7 8 9 ok Each time LOOP is encountered, I (which starts at 0 in this example, and ends on the 10th loop) is incremented by 1 However, +LOOP has a variable incrementor, supplied via the stack: : TEST 10 0 DO I . 2 +LOOP ; ok TEST 0 2 4 6 8 ok So, because you can go in bigger steps than 1, you can no longer test for the index being equal to the maximum loop count, as you can with LOOP - you have to detect crossing a boundary. Furthermore, you could supply a negative incrementer: : TEST -10 -20 DO I . -2 +LOOP ; TEST -10 -12 -14 -16 etc So, if you are going in a positive direction, you want JGT however, if you are going in a negative direction, you want the opposite, as far as I can see. It just means that the code has to look and see if we are adding a positive or negative value to the index and run one of two code paths accordingly. No big deal, but I didn't have access a machine at the time :-) Markk Quote Link to comment Share on other sites More sharing options...
Willsy Posted November 25, 2010 Author Share Posted November 25, 2010 Neat! I wrote the following code today at work, but I couldn't test it. I'm using a different laptop at the moment (an 11.9" NetBook - nice) and I only just got my TI dev environment working due to a missing Microsoft library, so I couldn't do a TurboForth build. Anyway, just tried the code that I wrote today: ;[ +LOOP & (+LOOP) ; note: +LOOP is immediate and compiles a reference to (+LOOP) plooh1 data looph,>8005 text '+LOOP ' ploop1 data docol,lit,docnt,refdn,compile,ploop,exit plooph data plooh1,7 text '(+LOOP)' ploop data $+2 a *stack,@-6(rstack) ; add value on stack to index dect stack ; remove value from stack mov @-4(rstack),r0 ; get limit jlt nll ; if <0 then do 'negative loop limit' leg ; else do 'positive loop limit' leg: c @-6(rstack),@-4(rstack); compare index to limit jgt ploopx ; if index > limit then exit jmp dodo ; else loop again nll c @-6(rstack),@-4(rstack); compare index to limit jlt ploopx ; if index < limit then exit jmp dodo ; else loop again ploopx ai rstack,-8 ; remove DO/LOOP frame from return stack b *next ; NEXT Gives the following results, which looks correct to me : TEST 10 0 DO I . 1 +LOOP ; TEST 0 1 2 3 4 5 6 7 8 9 10 (11 iterations) : TEST 10 0 DO I . 3 +LOOP ; TEST 0 3 6 9 (4 iterations) : TEST -30 -7 DO I . -3 +LOOP ; TEST -7 -10 -13 -16 -19 -22 -25 -28 (8 iterations) Quote Link to comment Share on other sites More sharing options...
sometimes99er Posted November 26, 2010 Share Posted November 26, 2010 Nice. Then you've gotta try something like this too ... : TEST -7 -30 DO I . 3 +LOOP ; : TEST 30 7 DO I . -3 +LOOP ; : TEST 30 -7 DO I . -3 +LOOP ; : TEST -7 30 DO I . -3 +LOOP ; : TEST 30 -7 DO I . 0 +LOOP ; Quote Link to comment Share on other sites More sharing options...
Willsy Posted November 26, 2010 Author Share Posted November 26, 2010 (edited) Nice. Then you've gotta try something like this too ... : TEST -7 -30 DO I . 3 +LOOP ; <--- Produces -30 (1 iteration) This is wrong. Should produce -30 -27 -24 -21 -18 -15 -12 -9. Shit. : TEST 30 7 DO I . -3 +LOOP ; <--- Big humungous loop (obviously!) : TEST 30 -7 DO I . -3 +LOOP ; <--- Big humungous loop : TEST -7 30 DO I . -3 +LOOP ; <--- 30 27 24 31 18 15 12 9 6 3 0 -3 -6 : TEST 30 -7 DO I . 0 +LOOP ; <--- nooooooooooo! Edited November 26, 2010 by Willsy Quote Link to comment Share on other sites More sharing options...
Willsy Posted November 26, 2010 Author Share Posted November 26, 2010 Fixed it, and come up with what I think is some nice code li r0,jgti ; point to "JGT PLOOPX" instruction mov *stack,r1 ; check incrementor jgt ploops ; if positive, skip inct r0 ; else point to "JLT PLOOPX" ploops a *stack,@-6(rstack) ; add value on stack to index dect stack ; remove incrementor from stack c @-6(rstack),@-4(rstack) ; compare index to limit x *r0 ; jump if boundary has been crossed mov @-2(rstack),pc ; else reload PC (computed by DO) b *next ; and do another loop ploopx ai rstack,-8 ; remove DO/LOOP frame from return stack b *next ; NEXT jgti jgt $+10 ; equivalent to "jgt ploopx" jlti jlt $+10 ; equivalent to "jlt ploopx" Note the crafty use of the X instruction - the first time I've ever used it I think (though it wasn't really necessary). I use X to either execute JGT or JLT depending on the sign of the incrementor (passed via the stack). I checked the examples that you and I posted with GForth (ANS compatible) and TurboForth now behaves the same way! Quote Link to comment Share on other sites More sharing options...
JonnyBritish Posted November 26, 2010 Share Posted November 26, 2010 Fixed it, and come up with what I think is some nice code li r0,jgti ; point to "JGT PLOOPX" instruction mov *stack,r1 ; check incrementor jgt ploops ; if positive, skip inct r0 ; else point to "JLT PLOOPX" ploops a *stack,@-6(rstack) ; add value on stack to index dect stack ; remove incrementor from stack c @-6(rstack),@-4(rstack) ; compare index to limit x *r0 ; jump if boundary has been crossed mov @-2(rstack),pc ; else reload PC (computed by DO) b *next ; and do another loop ploopx ai rstack,-8 ; remove DO/LOOP frame from return stack b *next ; NEXT jgti jgt $+10 ; equivalent to "jgt ploopx" jlti jlt $+10 ; equivalent to "jlt ploopx" Note the crafty use of the X instruction - the first time I've ever used it I think (though it wasn't really necessary). I use X to either execute JGT or JLT depending on the sign of the incrementor (passed via the stack). I checked the examples that you and I posted with GForth (ANS compatible) and TurboForth now behaves the same way! Off topic i know but are you planning to run turboforth against the forth test library to fully validate it? Quote Link to comment Share on other sites More sharing options...
Willsy Posted November 26, 2010 Author Share Posted November 26, 2010 Off topic i know but are you planning to run turboforth against the forth test library to fully validate it? Hi there, No. It's largely-kind-of-F83-compatible - whatever that means! However, strict compliance with Forth standards (ANS is a joke) was not at the top of the list - Fast code was! Is there anything in particular you had in mind? Mark Quote Link to comment Share on other sites More sharing options...
sometimes99er Posted November 27, 2010 Share Posted November 27, 2010 : TEST 30 -7 DO I . 0 +LOOP ; <--- nooooooooooo! So I guess the code is accepted (no error), but the loop loops forever ? Also I guess you can manipulate the "I" variable within the loop (if you want to) ? Is it possible to "break" out of a running user program (like a long/forever loop) ? Quote Link to comment Share on other sites More sharing options...
Willsy Posted November 27, 2010 Author Share Posted November 27, 2010 (edited) "So I guess the code is accepted (no error), but the loop loops forever ?" Yep - it's perfectly legal code. Though rather stupid! "Also I guess you can manipulate the "I" variable within the loop (if you want to) ?" No. I always represents the current Index value of the current loop that you are in. I is not actually a variable. It's a word (like a function in C) - It returns (via the stack) the current index of the loop you are in. Loops of course can be nested: : TEST 10 0 DO I . 45 EMIT SPACE 5 0 DO I . LOOP CR LOOP ; ok:0 TEST 0 - 0 1 2 3 4 1 - 0 1 2 3 4 2 - 0 1 2 3 4 3 - 0 1 2 3 4 4 - 0 1 2 3 4 5 - 0 1 2 3 4 6 - 0 1 2 3 4 7 - 0 1 2 3 4 8 - 0 1 2 3 4 9 - 0 1 2 3 4 "Is it possible to "break" out of a running user program (like a long/forever loop) ?" Yes it is, but you have to test for it (by design). This is because scanning the keyboard all the time just in case someone pressed the break key is slow. And maybe you, as the author of the program don't want people to break the program...! So, I have included a word called BREAK? that you insert only where you want to (like in your main game loop , like this: : TEST 10 0 DO I . 45 EMIT SPACE 5 0 DO I . BREAK? LOOP CR LOOP ; ok:0 TEST 0 - 0 1 2 3 4 1 - 0 1 2 3 4 2 - 0 1 2 3 4 3 - 0 1 2 3 4 4 - 0 1 2 [press function & 4] Break Break handles scanning for the F4 key, and takes no action if not detected. If detected, he handles un-winding the return stack for you - doesn't matter how deeply your program is nested when break is pressed - he will unwind the return stack and take you to the command line. Edited November 27, 2010 by Willsy Quote Link to comment Share on other sites More sharing options...
sometimes99er Posted November 27, 2010 Share Posted November 27, 2010 Thanks for answering my questions. All looks good. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.