Jump to content

Willsy

Members
  • Content Count

    3,144
  • Joined

  • Last visited

Everything posted by Willsy

  1. Ha that is lovely! That would have blown peoples minds if it was published as a snippet in C&VG in 1984
  2. Hi Rich, Some nice ideas. Here's how I would tackle them in TurboForth: (I have no idea why the columns don't line up properly) : HGET ( row column length buffer -- ) >R >R \ buffer address & length to return stack SWAP XMAX * + \ calculate screen address R> \ get length from return stack R> \ get buffer address from return stack SWAP \ stack is now: saddr buffer length VMBR \ read from screen into buffer ; : HPUT ( row column length buffer -- ) >R >R \ buffer address & length to return stack SWAP XMAX * + \ calculate screen address R> \ get length from return stack R> \ get buffer address from return stack SWAP \ stack is now: saddr buffer length VMBW \ write to screen from buffer ; The above just use the built in TurboForth words VMBR and VMBW (which work the same was as the editor assembler equivalents). They are very fast because they don't have to do any limit checks, since they are working on consequtive VDP addresses. Here's the vertical equivalents: 0 VALUE EOS : VGET ( row column length buffer -- ) XMAX 24 * TO EOS \ compute end of screen address >R >R \ move buffer and length out of the way SWAP XMAX * + \ convert row and column to screen address R> \ get length back R> \ get buffer address back SWAP 0 DO \ repeat length times SWAP \ get screen address to top of stack DUP [email protected] \ read a byte from VDP 2 PICK \ get buffer address C! \ store byte in buffer XMAX + \ move down 1 row DUP \ copy new screen address EOS >= IF \ moved off bottom of screen? EOS - 1+ \ move to top of next column THEN SWAP \ get buffer address 1+ \ increase buffer address LOOP \ repeat 2DROP \ drop buffer address and screen address ; : VPUT ( row column length buffer -- ) XMAX 24 * TO EOS \ compute end of screen address >R >R \ move buffer and length out of the way SWAP XMAX * + \ convert row and column to screen address R> \ get length back R> \ get buffer address back SWAP 0 DO \ repeat length times DUP [email protected] \ get a byte from the buffer 2 PICK \ get screen address V! \ write the byte from the buffer to screen 1+ \ move to next buffer address SWAP \ get screen address on top of stack XMAX + \ move down 1 row DUP \ copy new screen address EOS >= IF \ moved off bottom of screen? EOS - 1+ \ move to top of next column THEN SWAP LOOP 2DROP ; Much more complex, as you can see. Because you are moving 'downwards' in VDP memory, you need to do a check to see if you have 'fallen off' the end of the screen, and correct the screen address if you have. Regarding saving and restoring entire areas of the screen, I decided to leverage the above HGET and HPUT code. The code below will save rectangular areas of the screen to a buffer in memory, and allow you to restore it later. You can restore just a portion (relative to the top left of the saved rectangle) if you like. Neat for a windowing system in text mode. 0 VALUE buffer 0 VALUE repeat 0 VALUE length 0 VALUE column 0 VALUE row : RGET ( row column length repeat buffer -- ) TO buffer TO repeat TO length TO column TO row repeat 0 DO row column length buffer HGET 1 +TO row length +TO buffer LOOP ; : RPUT ( row column length repeat buffer -- ) TO buffer TO repeat -ROT TO column TO row repeat 0 DO row column 2 PICK buffer HPUT 1 +TO row length +TO buffer LOOP DROP ; To test, put something on the screen. Use the word WORDS as it writes lots of stuff to the screen. Then, save the entire screen to memory: 0 0 40 24 HERE RGET (HERE is a word that returns the next free address in memory, so we'll be saving our screen data in CPU ram in un-used RAM - it means we don't have to explicitly ALLOT memory to hold our screen data). Now, clear the screen with PAGE. Now, restore a portion of the saved screen, but at a different location: 5 11 12 10 HERE RPUT Finally, here's the code again, but written in the classic horizontal Forth style, as you might see it in a disk block. : HGET ( row column length buffer -- ) >R >R SWAP XMAX * + R> R> SWAP VMBR ; : HPUT ( row column length buffer -- ) >R >R SWAP XMAX * + R> R> SWAP VMBW ; 0 VALUE EOS : VGET ( row column length buffer -- ) XMAX 24 * TO EOS >R >R SWAP XMAX * + R> R> SWAP 0 DO SWAP DUP [email protected] 2 PICK C! XMAX + DUP EOS >= IF EOS - 1+ THEN SWAP 1+ LOOP 2DROP ; : VPUT ( row column length buffer -- ) XMAX 24 * TO EOS >R >R SWAP XMAX * + R> R> SWAP 0 DO DUP [email protected] 2 PICK V! 1+ SWAP XMAX + DUP EOS >= IF EOS - 1+ THEN SWAP LOOP 2DROP ; 0 VALUE buffer 0 VALUE repeat 0 VALUE length 0 VALUE column 0 VALUE row : RGET ( row column length repeat buffer -- ) TO buffer TO repeat TO length TO column TO row repeat 0 DO row column length buffer HGET 1 +TO row length +TO buffer LOOP ; : RPUT ( row column length repeat buffer -- ) TO buffer TO repeat -ROT TO column TO row repeat 0 DO row column 2 PICK buffer HPUT 1 +TO row length +TO buffer LOOP DROP ; Note that all of the above code uses the word XMAX which returns the number of columns on the screen (32, 40 or 80). Thus the above code works in 32, 40 or 80 column modes with no changes at all. I'll tackle the ONKEY example when I get a chance, hopefully over the weekend. Mark
  3. Willsy

    Chicago

    I'm also at the Best Western - The Best Western University Plaza - I think it's a block or two from the Library...?
  4. Can you bring what you have so far of Ultimate Planet? I'm sure plenty of people would like a proper demo of it, myself included! Mark
  5. Willsy

    Chicago

    I guess she's okay with all the whoring? Oh dear. Looks like I'll need to bring some extra ca$h
  6. Nice one! Also, I was thinking yesterday, when testing that a value is within a certain range, TF has a single word that will do this for you! Its called, er, WITHIN WITHIN ( n low high -- true|false ) "Replaces n, low and high with TRUE if n >= low and < high, otherwise replaces n, low and high with false" Example: "Is 40 within 30 and 50?" 40 30 50 WITHIN . -1 ok:0 "is 40 within 40 and 50?" 40 40 50 WITHIN . -1 ok:0 "Is 50 within 40 and 50?" 50 40 50 WITHIN . 0 ok:0 The last one says false (0) because 50 is not < 50 Remember, you get a TRUE if your value is >= to low and < high. I'd personally prefer >= low and <= high, but the Forth-83 standard says < high, which is crap, but there you go...! Of course, with Forth being Forth, you can just change the behaviour of words if you don't like them! So, if you really really want WITHIN to work on >= low and <= high, you can just re-define it! : WITHIN ( n low high -- t|f) 1+ WITHIN ; Here we "re-define WITHIN in terms of the old WITHIN". Crucially, we add 1 to the upper limit, so that if we do something like: 40 30 40 WITHIN Then the upper limit is increased by one, so what actually gets executed is 40 30 41 WITHIN and you get a TRUE! That re-definition will probably confuse some people. Let's take another look at it. We'll use a bit of colour to illustrate. : WITHIN ( n low high -- t|f) 1+ WITHIN ; You would be forgiven for thinking that the word calls itself, recursively, forever, but it doesn't. The new WITHIN adds 1 to the top of the stack, then calls the old WITHIN, which does the work for us. Simple eh? Utterly confusing when you don't know how Forth works, but once you know, you have an "Ohhhhhhhhhh!" moment!
  7. Willsy

    Chicago

    I know exactly what you mean! Luckily, my other half has almost pushed me into it. I don't smoke, I don't drink etc, so her view is "why not?! Go for it!" It will be nice to shake people by the hand and put faces and names together!
  8. Who's going to the faire? I've just booked my flights and hotel!
  9. Regarding your cows example, here's a more compact form: : COWS BEGIN CR KEY 48 - CASE 0 OF ." No cows!" ENDOF 1 OF ." 1 cow!" ENDOF -35 OF EXIT ENDOF DUP DUP 1 > SWAP 9 <= AND IF ." Multiple cows!" ELSE ." Need a number!" THEN ENDCASE AGAIN ;
  10. Yo! It's nearly right, but not quite. Where did you get my code example from? Was it YouTube? I have some dim recollection of doing something like that. I think the problem is that TF changed between recording that demo, and TF's release. Here is the 'stack signature' for DCHAR DCHAR ( address length ascii -- ) What this means is that DCHAR expects three items on the stack before it is called. These are (going from the top of the stack downwards) ascii - the ascii code of the character to define length - the number of words (not bytes) to define address - the address of the character data If we look at the code you posted: HEX 0607 0302 0703 0103 DECIMAL 4 40 DCHAR At runtime what you would get on the stack is 6 items (the 4 items of character data, the 4 and the 40). As you can see, DCHAR would interpret the last item of character data (0103 hex) as the address! It would then read 4 words from 0103 hex and load them into ascii 40! The other three words of character data would be left on the stack! Woops! As I said, this is probably my fault, as I modified DCHAR to take an address. So, we need to supply an address to DCHAR. The word DATA does just that: : UDG HEX DATA 4 0607 0302 0703 0103 DECIMAL 40 DCHAR HEX DATA 4 0707 0E0D 0306 070E DECIMAL 41 DCHAR HEX DATA 4 00C0 E0C0 C0C0 80C0 DECIMAL 42 DCHAR HEX DATA 4 E0E0 F0F0 C0E0 60E0 DECIMAL 43 DCHAR ; : SHOW 1 GMODE UDG 40 EMIT 42 EMIT CR 41 EMIT 43 EMIT CR ; DATA is one of those "clever" words that does one thing at compile time (when the colon definition is being compiled to memory) and another thing at run time. It can only be used in a colon definition! DATA needs to know how many items of data it is to compile, hence the number 4 after the word data (not before!), then your data items follow. At run-time DATA pushes the address of the data that it compiled at compile time, and the number of data items to the stack. This information is used by DCHAR and the definition built. So, this line: HEX DATA 4 0607 0302 0703 0103 DECIMAL 40 Would result in something like the following on the stack: A3B0 4 40 That is the address of the character data, the number of items of data (4) and the ascii code. That information is consumed by DCHAR and hey presto! DATA is useful because you can use words like 'data variables' where just merely executing different words returns different data pointers. Useful for animation. I'll try to post an example later. Anyway, hope that clears up the confusion! Attached: The word glossary for TF V1.0 Mark TurboForth v1-0 Words.pdf
  11. Well, I believe his wife is quite ill, so I guess it's understandable that he doesn't want to be blasted with support requests. Even so, I find it strange that he made a REALLY great emulator, but chose never to engage with his users! I didn't get any assembler stuff, but he worked on the speech core at my request (I had to post on 99er.net - I never did get his email address) and he also upgraded the assembler according to my suggestions (added the ability to create cart files straight from the assembler). I just find it strange that he never engaged with the community at all. Oh well. He sure knows how to write an emulator! There is actually some neat stuff in there: There are extra op-codes defined in the 9900 core to support real stacks (so it's a 9900 with a proper push down stack). This was intended for a C compiler that he was working on. TF could have made GOOD use of that stack, but then it would only run in Win994A. Nice idea though. Wish the 9900 had a few (3) stacks!
  12. Looking again at the cart creator, you can have up to two 8K ROM files, and only a single (6K?) GROM file. If your application has more than one GROM file, then you can't use it with Win994A it would seem. Win994A is pretty much obsolete now. The developer is a little strange: He has written a very good emulator, but chooses not to engage with his 'audience' in any way. He will not publish his contact information, so is not contactable, so I simply choose not to use it. The ASM994A assembler is very good though. I've been using that for TF development since 2009. It compiles my project (>40 files at the last count) in less than 2 seconds!
  13. How many 8k Rom images, and how many GROM images? You need to take your compiled object code and turn it into a number of files. Each ROM file (a raw .bin file) should be no longer than 8k, I'm not sure about the GROM files. You will probably need to write some assembly code to produce the raw memory image files, or do it on the PC side using Java or something. Mark
  14. Unfortunately, sprites in XB use the same characters as the character set, so you don't really gain anything. Use assembly. Or Forth
  15. You just use the code tags. You can either type them yourself, or press the icon that looks like a <> symbol (just below the smiley icon) and it will enter the tags for you. Then you paste your code BETWEEN the tags. Like this: [code ] put your code here [/code ] Do NOT use a space after the word CODE - I just did that so that it would display the tags on the screen. So, when you use the code tags, this: 10 PRINT "HELLO WORLD" 20 GOTO 10 Becomes 10 PRINT "HELLO WORLD" 20 GOTO 10 And it will paste nicely into Classic99 Mark
  16. He he! It's probably a bit longer than 12 hours for me, but worth it!
  17. Yes. Well, it is my intention to be at the Faire, but I haven't booked a ticket yet. It's imminent! 2011 is the 30th anniversary of the 4A (which no one really seems to have picked up on) - I would like to be there, and hopefully convert some more TF disciples, and show them "The Forth Way"
  18. Why don't you just press ALT & PrtSC when your game is running? It will take a picture of the window that has the current focus. You then run MSPAINT and paste the picture in and save it, and you're done.
  19. Lee, Does TF work with the nano? I've got a nano but never plugged it in!
  20. See the first post in this thread
  21. Yep. Carts will be available. Folk will have the following options: Present V1.0 Cart Owners: Turn up in Chicago on the day and Bob Carmany and I will exchange your V1.0 EPROM for a V1.1 EPROM, free of charge Return your V1.0 cart or EPROM to either Bob (USA) or myself (Europe) and we'll send you a V1.1 EPROM for just the cost of the return postage. [*]Peeps who don't currently own a cart: Purchase one from Bob or myself - we should have some available in Chicago Download the EPROM images and make your own cart (I believe a lot of people have done this - I reckon there's well over 100 users of TF now; most users being 'on the metal' rather than emulation users. Interesting).
  22. TF V1.1 will be out soon - much more stable (File IO was a bit dodgy and some other silly bugs), some new words added, and a couple taken away. Also has an optional integrated assembler plus an optional 32-bit math library as loadable add-ons. Struggling with floored integer division at the moment, then it's ready! All being well, it will be released at the Chicago faire, which I'm planning to attend, work etc permitting.
  23. Rich, I'm just watching your videos now. You really have done a fantastic job with this! I'm lucky. I use TF as a batch processor every day. Most BASIC users won't be aware of just how powerful a feature it is. Now they can tap into that power via RXB. The ability to write programs that write programs (and save them) is a massively powerful feature. Seriously - hats off man. You realled nailed this. Will you be doing a cart run when the GROM capable cart board is released? Could RXB be loaded into a HSGPL? Mark
  24. You are correct sir. (In a stupid French accent) "And now, I will change my sig-a-na-ture one more time!"
×
×
  • Create New...