Jump to content


+AtariAge Subscriber
  • Content Count

  • Joined

  • Last visited

Everything posted by TheBF

  1. I got no effect on a small window so I tried full screen and then I get just the beginning of the effect. (but very slight)
  2. Sorry dude. I completely missed that one. I did not run it and saw this other image on a youtube video. You got there first.
  3. Thanks for this. Apologies for not replying faster. You are correct, I could play with the numbers to get what I want. I have been using a multi-tasking system for my Forth system and I re-created the ISR in a little task. Forth handles all this stuff like Assembler so I too use CPU RAM for my position and motion tables and the write the block of sprite positions to VDP RAM all at once. So I am on the right track there at least. :-) I have been reviewing the ISR code and looking at the debugger to see how it works. Here is what I think I see: 1. The Motion values are signed bytes. Positive: 0 to 7F, Negative: 80 to FF 2. The Aux values, beside each motion pair, are incremented every tick of the interrupt, by the amount in the motion value These are the little counters that run for each sprite's X and Y value. 3. When the AUX value rolls over the sprite is moved 1 pixel. So bigger values of Motion cause the AUX register to rollover faster of course therefore those sprite moves faster. So at this stage I am debating how best to handle this in Forth just to see what I can do without writing an ASM version. Forth deals with ints better than bytes so I am thinking that I will use 16 bit tables for motion and timers (AUX) and just shift the motion values to upper byte. Since everything is multiplied by >100 it will all count the same speed as using bytes, but my Forth operators will be faster for 16 bit values. That's all I have at this time. Thanks again for confirming my thoughts on the matter.
  4. You're a mutant. Call professor X
  5. Maybe you can figure out how to do this one. It seems tricky to do with characters. There is a dot at every intersection, but I can only see 3 at time no matter how hard I look!
  6. Yes. That's fun. And I think there is one that is even weirder using that template... I will try it
  7. A 2nd Shade of Gray for TI-BASIC ​ 100 CALL CLEAR 110 CALL SCREEN(16) 120 PAT$="FFFFFFFFFFFFFFFF" 130 CALL CHAR(96,PAT$) 140 CALL CHAR(104,PAT$) 150 CALL COLOR(9,2,1) 160 CALL COLOR(10,15,1) 170 CALL HCHAR(2,9,65) 180 CALL HCHAR(2,23,66) 190 FOR I=4 TO 24 STEP 2 200 CALL HCHAR(I,1,96,32) 210 NEXT I 220 LET COL=7 230 LET ROW=5 240 GOSUB 290 250 LET COL=20 260 LET ROW=6 270 GOSUB 290 280 GOTO 250 290 FOR X=ROW TO 24 STEP 2 300 CALL HCHAR(X,COL,104,6) 310 NEXT X 320 RETURN
  8. My first FB Forth program: I cheated a little bit. I took a CAMEL99 program and added a small set of translation words. And guess what? It works just fine. For those who are just learning Forth it demonstrates how to use the interrupt timer for a precise delay and how to use the number formatting words. Just paste this code into FB Forth and it puts little clock on the screen. \ A simple Clock in FB Forth (FIG Forth dialect) \ Tiny HARNESS for FBFORTH->CAMEL99 translation : 2DROP DROP DROP ; : 2DUP OVER OVER ; : VARIABLE 0 VARIABLE ; : AT-XY ( n n -- ) GOTOXY ; : OFF ( addr -- ) 0 SWAP ! ; : ^C? ?TERMINAL ; \ CAMEL99 version can now compile HEX 8379 CONSTANT TICKER DECIMAL VARIABLE HRS VARIABLE MINS VARIABLE SECS VARIABLE TICKS 58 CONSTANT ':' \ character we will need \ increment no. in the address : 1+! ( addr -- ) 1 SWAP +! ; \ FB FORTH and CAMEL99 Forth run with interrupts enabled \ so the ticker is changing every 1/60 of a second. \ We can wait until ticker changes and know it's 1/60 of a second : 1/60 ( -- ) TICKER DUP @ \ dup ticker & fetch initial timer value BEGIN OVER @ \ read it again OVER - \ subtract initial value UNTIL \ loop until result is not zero 2DROP ; \ drop the initial value : 1SEC ( -- ) 60 0 DO 1/60 LOOP ; : KEEPTIME 1SEC SECS 1+! SECS @ 60 = IF SECS OFF MINS 1+! THEN MINS @ 60 = IF MINS OFF HRS 1+! THEN ; \ formatted output : ## ( n -- ) 0 <# # # #> TYPE ; : :## ( n -- ) 0 <# # # ':' HOLD #> TYPE ; : .TIME ( -- ) SECS @ MINS @ HRS @ ## :## :## ; : SETCLOCK ( hrs mins secs -- ) SECS ! MINS ! HRS ! ; : CLOCK ( row col -- ) BEGIN 2DUP AT-XY .TIME KEEPTIME ^C? \ waits for function clear in FB Forth UNTIL 2DROP ; 1 59 50 SETCLOCK PAGE 10 10 CLOCK
  9. Thanks Lee. That's a much nicer looking listing!
  10. There are Sprites in the air it seems. I stayed up late last night trying to grok the ISR code for Sprite motion. My homemade sprite auto-motion system is wrong, but I don't understand exactly how. I was taking a velocity(x,y) (+ or - ) from an array and simply adding it to the current sprite position. This gave very ragged motion. I checked XB and the sprites are only moved 1 pixel at a time from what I can see regardless of the velocity used. (Classic99 debugger) So if anybody can explain what's going on with this ROM code I would be all ears. Like what is this auxiliary data in the motion table? This is from TI Intern, but I have added some my own comments to help me stay on track 093A C002 MOV 2,0 093C C0A2 MOV @>0002(2),2 Fetch INT address 093E 0002 0940 0692 BL *2 And execute 0942 C090 MOV *0,2 Next Int routine 0944 10F9 JMP >0938 0946 0460 B @>0AB8 End interrupt from CRU 0948 0AB8 094A 1D02 SBO >0002 Clear VDP interrupt 094C D060 MOVB @>83C2,1 Fetch interrupt flag byte 094E 83C2 0950 0A11 SLA 1,1 No interrupt permitted 0952 1702 JNC >0958 0954 0460 B @>0A84 then jump 0956 0A84 0958 0A11 SLA 1,1 095A 1846 JOC >09E8 No sprite move permitted, then jump 095C D320 MOVB @>837A,12 Number sprites -> R12 095E 837A 0960 1343 JEQ >09E8 IF sprite_cnt=0 then skip all this 0962 098C SRL 12,8 Move sprite count to other byte 0964 0202 LI 2,>8800 VDP RD -> R2 0966 8800 0968 0203 LI 3,>8C00 VDP WD -> R3 096A 8C00 096C 0208 LI 8,>0780 Sprite motion table -> R8 096E 0780 * begin loop for each sprite 0970 D7E0 MOVB @>83F1,*15 Write address motion table 0972 83F1 0974 D7C8 MOVB 8,*15 load Spr motion table to VDP Write address *===================================================== 0976 04C4 CLR 4 0978 D112 MOVB *2,4 read Motion table Y velocity ->R4 097A 04C6 CLR 6 097C D192 MOVB *2,6 read Motion table X X velocity->R6 097E 0844 SRA 4,4 ?? shift Y velocity right 4 0980 D152 MOVB *2,5 read Y Auxiliary sprite data->R5 0982 0845 SRA 5,4 shift Aux data 4 right (16/) 0984 A144 A 4,5 ADD R4->R5 *==================================================== 0986 D1D2 MOVB *2,7 Read Y Auxiliary sprite data-> R7 0988 0846 SRA 6,4 Shift X motion by 4 right 098A 0847 SRA 7,4 Shift X aux data 4 right 098C A1C6 A 6,7 Add R6->R7 098E 0228 AI 8,>FB80 Address sprite descriptor table 0990 FB80 0992 D7E0 MOVB @>83F1,*15 Write address 0994 83F1 0996 D7C8 MOVB 8,*15 ==================================================== 0998 04C4 CLR 4 099A D112 MOVB *2,4 Fetch Y position->R4 099C A105 A 5,4 add Y motion+aux+Ypos->R4 099E 0284 CI 4,>C0FF are we at X,Y limits (192,256) 09A0 C0FF 09A2 1209 JLE >09B6 if not off screen, goto 9B6 09A4 0284 CI 4,>E000 are we at start of screen ( 224,00) 09A6 E000 09A8 1B06 JH >09B6 if HI goto 9b6 09AA C145 MOV 5,5 else test for 0 09AC 1502 JGT >09B2 if R5>0 goto 09B2 09AE 0224 AI 4,>C000 ?? what is this for 09B0 C000 09B2 0224 AI 4,>2000 ?? and why add this 09B4 2000 09B6 04C6 CLR 6 *screen limit tests 09B8 D192 MOVB *2,6 09BA A187 A 7,6 09BC 0268 ORI 8,>4000 setup VDP address for writing 09BE 4000 09C0 D7E0 MOVB @>83F1,*15 09C2 83F1 09C4 D7C8 MOVB 8,*15 09C6 D4C4 MOVB 4,*3 Write X,Y positions to Spr. desc. table 09C8 0228 AI 8,>0482 ? 09CA 0482 09CC D4C6 MOVB 6,*3 09CE 06C5 SWPB 5 09D0 D7E0 MOVB @>83F1,*15 Write address motion table 09D2 83F1 09D4 D7C8 MOVB 8,*15 09D6 0945 SRL 5,4 09D8 D4C5 MOVB 5,*3 Write auxiliary values 09DA 06C7 SWPB 7 09DC 0947 SRL 7,4 09DE D4C7 MOVB 7,*3 09E0 0228 AI 8,>C002 New address motion table 09E2 C002 09E4 060C DEC 12 Last sprite? 09E6 15C4 JGT >0970 No, once again * end sprite loop 09E8 0A11 SLA 1,1 START of sound processing...
  11. No problem. CAMEL99 does as well. In fact the standard Forth context switcher should be able to be installed as an ISR. You would just have to be careful with tasks that used shared resources. Create some locks or something like that.
  12. TheBF


    Since I was looking at the code I re-wrote it so it does not look at column 1 by factoring the hardware reading code as a sub-routine. This further improved the speed from 336uS in the old verison to 273uS but cost 4 bytes of space. The screen capture shows the test results using the 9901 timer word '[email protected]" versus calling KSCAN (ASM word KEY? in Forth) This ctrl C reader is over 4X faster than calling KSCAN Here is the new version in case anybody finds it useful. To use this concept in TI ASM just remember that TOS is just a re-name for R4. \ sub routine to read key matrix. Set R1 to the column to read L: _RKEYS R12 0024 LI, \ set CRU address for column select chip R1 3 LDCR, \ Set 3 bits of column R2 SETO, \ R2 gets the bits. set all bits to 1 R12 0006 LI, \ R12-address to read rows R2 8 STCR, \ store 8 row values of current column (bits)->R2 *** R2 INV, \ outputs are low active so flip bits R2 TOS ADD, \ collect all the bits in TOS (R4) RT, CODE: ^C? ( -- ?) \ fast check if ctrl C key pressed TOS PUSH, \ make room in TOS register TOS CLR, \ TOS will accumulate keyboard bits R1 CLR, \ R1 is column to read. starts at 0 _RKEYS @@ BL, \ read keys in column 0 R1 0200 LI, \ set column to 2 _RKEYS @@ BL, \ read keys in column 0 SCRTO @@ CLR, \ Reset TI system screen timeout counter TOS C000 CMPI, \ look for ctrl 'C'. (2 bits set) @@2 JEQ, \ ^C was pressed TOS CLR, \ no ^C, clear TOS, return to forth NEXT, @@2: TOS SETO, \ set TOS to -1 (Forth true flag) NEXT, \ return to Forth END-CODE
  13. TheBF


    Thanks for the corrections Lee, I will update my source code file. I don't remember where I found the table. But I know I didn't derive it all by myself. Yours appears to align with the Thierry Nouspikel Web site. So I will avail myself of yours in my source as well with credit to you as it makes more sense.
  14. LOL. My first attempt at it created what looked like 3 sprites! :-) It was because they were created so fast there were 3 tight clusters of them locked in motion on the screen. I kept looking at the code thinking WT* ! I made 32 sprites!! Where are they???? And of course since I typed the code for the language and libraries I don't trust anything! So round and round you go looking for what you did wrong inside the system. You probably had that happen with RXB. And if you turn over a stone... there are always bugs. But in this case it was the application code. It's a weird hobby. Sometime I think I need a shrink, but then I think it over and realize I just need a drink.
  15. Nice. It looks much better on the darker background. I was just pleased to get mine going. In time I will take a run at porting the tasker to a few blocks in FB Forth. I am pretty sure the conventional version is straightforward. It's fun to make the old 99 run in circles! :-)
  16. I am having flashbacks reviewing your new Forth 2.0 in the 64 col. Editor. Thanks for all your hard work Lee. It's a beautiful thing.
  17. TheBF


    I too wanted a faster way to catch a keystroke. Mine was to break out of loops without slowing the loop down too much. This is little routine will only detect a control C key press. But it could be configured to different keys. It is 4 times faster than using KSCAN. (approx. 250ms vs over 1mS) Here is the matrix I used to understand how to do it. \ R1 TB 0 TB 1 TB 2 TB 3 TB 4 TB 5 TB 6 TB 7 \ --------------------------------------------------------------------- \ 0000 = space enter fctn shift ctrl \ 0100 . L O 9 2 S W X \ 0200 , K I 8 3 D E C \ 0300 M J U 7 4 F R V \ 0400 N H Y 6 5 G T B \ 0500 / ; P 0 1 A Q Z \ 0600 Fire1 Left1 Right1 Down1 Up1 \ 0700 Fire2 Left2 Right2 Down2 Up2 \ --------------------------------------------------------------------- Written in reverse assembler. (put the instruction on the other side for conventional assembler) Weirdness: TOS is just a renamed R4. PUSH is a macro that moves the stack pointer. (SP DECT) and moves a register ( MOV R4,*SP) The method is I collect bits in R4, while looping through the keyboard rows (Register 1) When R4 = C000 I have a ctrl C pressed. So by changing that value you could detect any key. I took this code from a more general routine and I am sure it can be improved. As I look at It, I see it does not need to look at row 0100 at all for a control C. Duh! So I can speed it up more in the future. CODE: ^C? ( -- ?) \ fast check if ctrl C key pressed TOS PUSH, \ make room in TOS register TOS CLR, \ TOS will accumulate keyboard bits R1 CLR, \ R1 is column to read. starts at 0 @@1: R12 0024 LI, \ set CRU address for column select chip R1 3 LDCR, \ Set 3 bits of column R2 SETO, \ R2 gets the bits. set all bits to 1 R12 0006 LI, \ R12-address to read rows R2 8 STCR, \ store 8 column values (bits)->R2 R2 INV, \ outputs are low active so flip bits R2 TOS ADD, \ collect all the bits in TOS (R4) R1 0100 ADDI, \ advance to next row R1 0300 CMPI, \ are we at row 3? @@1 JNE, \ if not jump back SCRTO @@ CLR, \ Reset TI system screen timeout counter TOS C000 CMPI, \ look for ctrl 'C'. (2 bits set) @@2 JEQ, \ ^C was pressed TOS CLR, \ no ^C, clear TOS, return to forth NEXT, @@2: TOS SETO, \ set TOS to -1 (Forth true flag) NEXT, \ return to Forth END-CODE
  18. A while back Sometimes99er created this pretty demo of "Quasi" particles falling from the screen. (can't seem to find it on the site, but I know I didn't imagine it) Since I have little imagination for the visual arts I enjoy trying to emulate XB functionality made by the creative people here with my hobby Forth system. So I whipped up some code and hit return and mine did not look like Sometimers99er's at all! I went away humbled and didn't think much about it for long time, until this week when I realized that I was creating my sprites too fast. :-) The beautiful way the Quasi particles fall from the top of the screen in BASIC was due to the delay created by the BASIC interpreter as it creates a new sprite. I added some appropriate delays in my "particle sprayer" and voila! A thing of beauty. And we all know that a thing of beauty is a joy forever. :-) Doing this helped expose a few more bugs and speed ups for my Sprite file so a big thanks to Sometimes99er. If I ever stop playing and work on my file interface I might have a complete system. Here is the code with lots of comments:
  19. Hey Lee, the product looks great up on Amazon. Good on you! B
  20. Sounds perfect for implementing a Forth BLOCK system. Once you have that it is possible to create a simple file system relatively easily. Something like TI-99 file system functionality would not be too difficult. (?) (never did it so normal warnings apply) Or you could take some ideas from here: http://www.forthos.org/fs.html
  21. This kind of thing is commonly solved using the U< operator. ("un-signed less than" for those not familiar with Forth) If the array size is 1000 for example, and I ask for index 500 500 1000 U< returns TRUE so it's a good index. BUT... if I ask for index 1001 1001 1000 U< gives me FALSE (1001 is NOT less-than 1000) so I should abort with an error. And if I ask for index -1 or -2 those numbers are actually 65,535 and 65,534 unsigned. -1 1000 U< returns FALSE because it is actually 65535 1000 U<. So U< lets you protect against negative values and "too high" positive values with one comparison. Neat trick of twos complement arithmetic. https://en.wikipedia.org/wiki/Two%27s_complement
  22. Have not tried HYPE, but there are quite a few OOP overlays for Forth. Thanks for the link. I will give it a whirl. And yes. Domain specific languages are how Forth is used very frequently. Nobody knows it's Forth under the hood (bonnet) because it looks like something else. :-) OOP Implementations: Bernd Paisons did one called minioof https://www.complang.tuwien.ac.at/forth/gforth/Docs-html/Mini_002dOOF.html The big one was a language called NEON for the Mac. It survives as MOPS Forth for the MAC. It is pretty cool too.
  23. I think is more of a protection from a negative index getting into the mix. Also the error detection uses '>" which is a signed operation so this implementation could only handle an array on **32K cells max. Which of course in a stock TI-99 is big enough since the largest continuous block of memory is 24K **(because any number bigger than HEX 7FFF (32,767) is treated as negative in signed operations on the 9900) The definition for CELLS on a 16 bit CPU is just: : CELLS ( n -- n ) 2* ; And 2* is typically just duplicate the top of stack value and ADD the 2 together ; : 2* ( n -- n) DUP + ; \ in high level Forth. But normally coded in Assembler Nothing is hidden in Forth, but it can be a little harry sifting through all the Assembly language to find the answer.
  • Create New...