tag:blogger.com,1999:blog-4757118446768919900.post8893003854708612064..comments2020-04-01T08:39:35.828-07:00Comments on Retro Programming: Itsy Forth: Implementing the PrimitivesJohn Metcalfhttp://www.blogger.com/profile/09108374348083307900noreply@blogger.comBlogger24125tag:blogger.com,1999:blog-4757118446768919900.post-84810510316892332842014-06-07T16:16:45.583-07:002014-06-07T16:16:45.583-07:00May as well add some more thoughts on extending th...May as well add some more thoughts on extending this through to a Standard ANS Forth (at least as far as ANS Forth CORE).<br /><br />CORE and CORE EXT R operations:<br /><br />Core: R> >R R@<br />Core EXT: 2R> 2>R 2R@ <br />Not Standard but common factor: RDROP<br /><br />If you have R> and >R than you can define the rest ... doing the rest in primitives is therefore a speed vs space tradeoff, not a functional requirement:<br /><br />: R@ ( -- x | R: x -- x ) R> DUP R> ;<br />: 2R> ( -- x y | R: x y -- ) R> R> SWAP ;<br />: 2>R ( x y -- | R: -- x y ) SWAP >R >R ;<br />: 2R@ ( -- x | R: x -- x ) R> DUP R> DUP ROT >R >R ;<br /><br />If you have 0< and 0= and use NAND to get your CORE bitwise logic, you can get the boolean operators 0> < = ><br /><br />: 0> ( x -- fl ) DUP 0= SWAP 0< NAND ;<br />: < ( x y -- fl ) - 0< ;<br />: = ( x y -- fl ) - 0= ;<br />: > ( x y -- fl ) - 0> ;<br />: ABS ( x -- |x| ) dup 0< if negate then ;<br /><br />+! can just be:<br />: +! ( x a -- ) dup >r @ + R> ! ;<br /><br />1+ CHAR+ 2+ and CELL+ are just<br /><br />: 1+ ( x -- y ) 1 + ;<br />: CHAR+ ( ca1 -- ca2 ) 1+ ;<br />: 2+ ( x -- y ) 2 + ;<br />: CELL+ ( a1 -- a2 ) 2+ ;<br /><br />Then 2! and 2@ are (high word first is ANS standard):<br /><br />: 2! ( x y a -- ) dup >r ! r> 2+ ! ;<br />: 2@ ( a -- x y ) dup >r cell+ @ r> @ ;<br /><br />You need 2* and 2/ which then lets you define CELLS with 2* for 16-bit and 2* 2* for 32-bit. CHARS is just a no-op if using ASCII or an 8bit code page:<br /><br />: CHARS ( x -- y ) ;<br /><br />* / */ MOD /MOD M* can all be defined from UM/MOD and UM* and D>S S>D from 0< NEGATE 0 and -1 (defined -1 as a constant if negatives are not yet in the INTERPRET routine) ~ definitions omitted here, but they are mostly sign manipulation with 0< and XOR<br /><br />Whether hardware division is floored or symmetric ~ that is, whether UM/MOD is FM/MOD or SM/REM ~ the other can be derived from the result, and using the hardware integer divide then correcting is both more compact and quicker than writing a division routine in Forth.<br /><br />?DUP is simply<br />: ?dup ( x -- 0 | x x ) dup if dup then ;<br /><br />EVALUATE looks like it would be tricky, but it can be done with your interpret by adding a SOURCE-ID variable and testing it in your INTERPRET. Pushing the current TIB #TIB >IN and SOURCE-ID onto the return stack, store the evaluated string address and count, set SOURCE-ID to -1 >IN to 0 and call INTERPRET, then restore them.<br /><br />: evaluate ( ca u -- )<br /> #tib @ >r tib @ >in @ >r source-id @ >r<br /> #tib ! tib ! 0 >in ! -1 source-id ! interpreter<br /> r> source-id ! r> >in ! r> tib ! r> #tib ! ;<br /><br />Extend INTERPRETER so that the test for whether to refill the buffer is:<br /><br />...<br />#tib @ >in @ =<br /> if<br /> source-id @ if exit then<br /> tib 50 accept #tib ! 0 >in !<br /> then<br />...<br /><br />And the cold start so that 0 is stored in source-id. Now the outer interpreter will loop endlessly for source-id of 0 but will return when called for a single input line by EVALUATE.<br /><br />If you have a DO LOOP, LSHIFT and RSHIFT can be defined from 2* and 2/<br /><br />MAX and MIN are:<br /><br />: max ( x y -- x | y ) 2dup < if swap then drop ;<br />: min ( x y -- x | y ) 2dup < INVERT if swap then drop ;<br /><br />UMAX and UMIN similarly, but they require U<.<br /><br />x U< y ... same as < if both are the same sign<br />x U< y ... same as ... y 0< ... if they are different signs<br /><br />: U< ( ux uy -- fl ) \ defined by using signed < and 0<<br /> 2dup 0< r> 0< XOR if swap drop 0< else < then ;<br /><br />.... though the hardware primitive of subtracting them and setting the flag based on whether there was an overflow carry can easily be shorter, and if so, implement it as a primitive.<br />BruceMcFhttps://www.blogger.com/profile/08502035881761277885noreply@blogger.comtag:blogger.com,1999:blog-4757118446768919900.post-45686360989593653942014-06-06T20:39:52.750-07:002014-06-06T20:39:52.750-07:00Mike, as specified, >NUMBER also supports the l...Mike, as specified, >NUMBER also supports the legacy Forth practice of placing ANY character as a separator to tell the interpreter/compiler to parse a double. Its also used to handle leading + and - flags.<br /><br />So, start with an arbitrary string. Store 0 in the FIXED? 2VARIABLE. Start converting. It stops at the first value. You do an over C@, store it in a variable, and keep going. It stops again. You store the character and the index in the FIXED? 2VARIABLE and keep going. It completes. You look at the leading character, decide what to do (most often its a - and you call DNEGATE. If the routine that called the number parsing routine is treating values with different decimal point locations differently, the required information has been stored.<br /><br />So while this interpreter does not have Forth standard number conversion, a use of the information contained in the >NUMBER routine when stops on a non-numeric would support extending it to include it.Unknownhttps://www.blogger.com/profile/18205598164034939972noreply@blogger.comtag:blogger.com,1999:blog-4757118446768919900.post-56083133200532869802014-06-06T14:10:48.335-07:002014-06-06T14:10:48.335-07:00Add NAND XOR >R and R> and you can synthesiz...Add NAND XOR >R and R> and you can synthesize the rest of the CORE logic and much of the stack manipulation. You can even synthesize ROT so that's three extra primitives rather than four:<br /><br />: rot ( x y z -- y z x ) >r swap r> swap ;<br />: over ( x y -- x y x ) >r dup r> swap ;<br />: 2dup ( x y -- x y x y ) over over ;<br /><br />: invert ( x -- z=NOT{x} ) dup nand ;<br />; and ( x y -- z=A&B ) nand invert ;<br />: or ( x y -- z=A|B ) invert swap invert nand ;<br />: negate ( x -- -x ) invert 1 + ;<br />: - ( x y z=x-y) negate + ;<br /> BruceMcFhttps://www.blogger.com/profile/08502035881761277885noreply@blogger.comtag:blogger.com,1999:blog-4757118446768919900.post-42208089598026701092014-06-06T14:05:09.531-07:002014-06-06T14:05:09.531-07:00Note that if you have NAND R> and >R you can...Note that if you have NAND R> and >R you can get the ANS Forth CORE logic words and most of the rest of the CORE stack manipulation words.<br /><br />nand is ( x y -- z=NOT{x&y} )<br /><br />: invert ( x -- y=NOT{x} ) dup nand ;<br />: and ( x y -- z=x&y ) nand invert ;<br />: over ( x y -- x y x ) >r dup r> swap ;<br />: 2dup ( x y -- x y x y ) over over ;<br />: or ( x y -- z=x|y ) invert swap invert nand ;<br />: xor ( x y -- z=x^y ) 2dup nand dup >r nand swap r> nand nand ;<br /><br />XOR is involved enough that I'd go with at least >R R> NAND XOR<br /><br />We also have a subtraction definition available from the above:<br /><br />: - ( x y -- z=x-y ) invert 1 + + ;<br /><br />You can get >R and R> NAND and XOR for the cost of three additional primitives rather than four, since they allow you to make ROT a Forth definition:<br /><br />: rot ( x y z -- y z x ) >r swap r> swap ;<br />BruceMcFhttps://www.blogger.com/profile/08502035881761277885noreply@blogger.comtag:blogger.com,1999:blog-4757118446768919900.post-61310368569534225002013-07-06T04:53:06.963-07:002013-07-06T04:53:06.963-07:00A Question. If we changed the getchar and outchar ...A Question. If we changed the getchar and outchar to bios calls instead of int 21h <br />would itsy forth then run as a standalone system (ie no operating system)?Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-4757118446768919900.post-21645932722896469992012-08-25T12:12:02.235-07:002012-08-25T12:12:02.235-07:00Hi Mike,
Thanks for the bug report, I'm not s...Hi Mike,<br /><br />Thanks for the bug report, I'm not sure how it slipped through. It can be fixed simply by moving dec bx further down. I've fixed the code above.<br /><br />JohnJohnhttp://retroprogramming.comnoreply@blogger.comtag:blogger.com,1999:blog-4757118446768919900.post-52780695567615605702012-08-25T00:47:43.259-07:002012-08-25T00:47:43.259-07:00Okay, it's time for an OOPS! moment. Seems I m...Okay, it's time for an OOPS! moment. Seems I made my previous comment a bit too hastily. I noticed after the fact that there was another push to the stack BEFORE the jump in question, and it does indeed put the low word of the double number back on the stack as it should if >number aborts. The modification I suggest to the code is not necessary; in fact, making that patch would be a bug in and of itself. The code returns the correct number of items on the stack as it is, regardless of whether it encounters an illegal character or not. I cobbled together some simple numeric output routines and confirmed this.<br /><br />However, just to save you from repeating another mistaken assumption I made, let me warn you that the number at the top of the stack after >number is executed (the length counter) is not a reliable indicator of whether >number has successfully converted a numeric input string. Under some circumstances (such as if the very last character in the string is non-numeric), it can have a value of zero even if >number detects an error and aborts. Looking at the code now, I don't think John intended that number to be used for error-checking as I'd originally thought. It's just a counter, not a fault flag. It would be nice to have one available, though. I may see if I can modify the code so that it can be used as such.<br /><br />My apologies for any confusion my earlier post may have caused.Mike Adamsnoreply@blogger.comtag:blogger.com,1999:blog-4757118446768919900.post-76549769845224499032012-08-17T14:32:10.126-07:002012-08-17T14:32:10.126-07:00Hi John,
I believe there's a minor bug in Its...Hi John,<br /><br />I believe there's a minor bug in Itsy Forth's >number routine. If it completes successfully, it returns four words on the top of the stack, just as you describe in your article: the converted double-precision number, the leftover string pointer, and a 0 that's left after counting through the string. However, if it fails due to a non-numeric string, it does not push both words of the double back onto the stack; it only pushes the high-order word, followed by the string pointer and the non-zero<br />counter value. Three words rather than four. This isn't a problem for interpret, which almost immediately calls abort and clears the stack out anyway, but for somebody else who might try to use >number independently, this could be the source of some serious hair-ripping frustration. It looks to me like it would be easy to fix this simply by changing the "jc to_numh" line to read "jc to_numz".<br /><br />MikeMike Adamsnoreply@blogger.comtag:blogger.com,1999:blog-4757118446768919900.post-79947735339712935682012-07-09T00:59:56.291-07:002012-07-09T00:59:56.291-07:00Hi Eventi, it's all down to size. The assembly...Hi Eventi, it's all down to size. The assembly code is 4 bytes shorter than the compiled Forth :-)Johnhttp://retroprogramming.comnoreply@blogger.comtag:blogger.com,1999:blog-4757118446768919900.post-75770986491275270392012-06-13T13:53:30.525-07:002012-06-13T13:53:30.525-07:00Tsk, tsk. This is *retro* programming. Nothing lat...Tsk, tsk. This is *retro* programming. Nothing later than IBM BASICA, surely?Ian Taylorhttps://www.blogger.com/profile/06869762490434824010noreply@blogger.comtag:blogger.com,1999:blog-4757118446768919900.post-22414884553690434932012-05-28T15:36:52.079-07:002012-05-28T15:36:52.079-07:00hi................
fantastic post .I really impres...hi................<br />fantastic post .I really impressed to see your way of explaining codes .can you tell me what to do to learn the assembly language.error1079http://best-registry-fixer.blogspot.com/2011/12/fix-error-1079.htmlnoreply@blogger.comtag:blogger.com,1999:blog-4757118446768919900.post-48833500814355582402012-05-04T17:05:34.495-07:002012-05-04T17:05:34.495-07:00It's been a very long time since I've done...It's been a very long time since I've done any programming. This does look like a good language to learn.Rattyhttps://www.blogger.com/profile/04062449024949497557noreply@blogger.comtag:blogger.com,1999:blog-4757118446768919900.post-37983440633154255152012-04-20T08:31:33.304-07:002012-04-20T08:31:33.304-07:00Thanks for these posts - I had forgotten how much ...Thanks for these posts - I had forgotten how much fun Forth and asm are :)<br /><br />Can't count be implemented with extant primitives?<br /><br />: count ( addr -- addr2 len ) dup 1 + swap c@ ;eventihttp://th.issh.it/noreply@blogger.comtag:blogger.com,1999:blog-4757118446768919900.post-17562558497419436722012-04-18T06:39:27.920-07:002012-04-18T06:39:27.920-07:00Thanks Mentifix, and thanks to everyone who made I...Thanks Mentifix, and thanks to everyone who made Itsy Forth popular on Reddit :-)Johnhttp://retroprogramming.comnoreply@blogger.comtag:blogger.com,1999:blog-4757118446768919900.post-60661857280369829382012-04-18T06:29:07.467-07:002012-04-18T06:29:07.467-07:00Would GW-Basic be okay?Would GW-Basic be okay?Johnhttp://retroprogramming.comnoreply@blogger.comtag:blogger.com,1999:blog-4757118446768919900.post-61457663865542333252012-04-18T06:17:45.133-07:002012-04-18T06:17:45.133-07:00Hopefully it won't be long before the complete...Hopefully it won't be long before the complete source is ready. I just need to tie up some loose ends. :-)Johnhttp://retroprogramming.comnoreply@blogger.comtag:blogger.com,1999:blog-4757118446768919900.post-56861428944002943862012-04-18T06:12:11.501-07:002012-04-18T06:12:11.501-07:00Thank you, I'm pleased you enjoyed them :-)
I...Thank you, I'm pleased you enjoyed them :-)<br /><br />I compiled the outer interpreter by hand. Also : and ; will be hand compiled. After that I'm hoping everything will be defined from the Itsy prompt.Johnhttp://retroprogramming.comnoreply@blogger.comtag:blogger.com,1999:blog-4757118446768919900.post-82132749580080419552012-04-18T06:09:15.045-07:002012-04-18T06:09:15.045-07:00Thanks Lawrence. This was actually the second atte...Thanks Lawrence. This was actually the second attempt. The first test output "ystI" :-)Johnhttp://retroprogramming.comnoreply@blogger.comtag:blogger.com,1999:blog-4757118446768919900.post-17015576861435980882012-04-18T05:14:34.140-07:002012-04-18T05:14:34.140-07:00You winYou winAnonymousnoreply@blogger.comtag:blogger.com,1999:blog-4757118446768919900.post-40196445156448156162012-04-17T04:19:37.502-07:002012-04-17T04:19:37.502-07:00Thanks for these posts - fascinating!
How did you...Thanks for these posts - fascinating!<br /><br />How did you get this up and running when (unless I've missed it) you don't yet have definitions of the control strucutres (IF, AGAIN) used by the outer interpreter? Did you hand-compile the 0BRANCH calls in the outer interpreter?Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-4757118446768919900.post-15455216370067927682012-04-16T07:45:57.234-07:002012-04-16T07:45:57.234-07:00Feel free to post the complete source code for Its...Feel free to post the complete source code for Itsy Forth :)nlandsberghttps://www.blogger.com/profile/01967033191174886988noreply@blogger.comtag:blogger.com,1999:blog-4757118446768919900.post-90949805510423788122012-04-15T23:35:04.482-07:002012-04-15T23:35:04.482-07:00Could you please provide an example in Visual Basi...Could you please provide an example in Visual Basic .NET. It is not a very good practice to use assembly language in high level software.Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-4757118446768919900.post-56397041377796792182012-04-15T22:40:01.766-07:002012-04-15T22:40:01.766-07:00Well done John. I bet it was a great feeling when...Well done John. I bet it was a great feeling when the interpreter output "Itsy". Keep up the good work.Anonymoushttps://www.blogger.com/profile/03771767918445686208noreply@blogger.comtag:blogger.com,1999:blog-4757118446768919900.post-89874998196104563532012-04-15T14:08:15.921-07:002012-04-15T14:08:15.921-07:00Great to see a Forth resource like this one that I...Great to see a Forth resource like this one that I saw on Reddit.Mentifexhttp://code.google.com/p/mindforthnoreply@blogger.com