Jump to content

TheBF

+AtariAge Subscriber
  • Posts

    4,059
  • Joined

  • Last visited

Everything posted by TheBF

  1. That's a nice write up Willsy. BF
  2. It could support REF and DEF if I understood the loader better. I am using binary file loaded with menu option 5 on the E/A module. Does that put the DEFs in low memory. I don't see anything there?
  3. Ok thanks for this. I found the Bagneresi code online. It sounds like what I need. I will start there.
  4. OK here's a question. In the E/A Assembler I just state: REF GPLLNK . . BLWP @GPLLNK and I can call the system with what already exists or am I missing something there? I am not using E/A, I am using my own Assembler. Is there an address for GPLLNK or is there code loaded by E/A that I don't have access to and must write myself? BF
  5. With all this support it should be easy. :-) I will keep you apprised of my frustrations here. Thanks everybody. BF.
  6. I have created Camel Forth Kernel for TI-99 and the plan is to add ANS/ISO Forth file words to it so it can extend itself with more source code. I have code that creates and manipulates PABs using the ANS syntax but now I need to interface to the file system, which is black magic to me. Lee Stewart has graciously provided the source for TI-Forth it has the " Universal Device Service Routine Link by MG" It looks great but there many things it does that I don't really understand. So if anybody has a place with stash of secret documents I would be delighted to know about them. Or if you have any gotchas to watch out for I would love to know about them too. Thanks in advance. BF I am thinking about now that there might be simpler hobbies to pursue... nah!
  7. Now my head will have to hurt while I wrap it around the loop cross over implications. My macros are in the code window. \ PUSH & POP on both stacks : PUSH, ( src -- ) SP DECT, *SP MOV, ; \ 10+18 = 28 cycles : POP, ( dst -- ) *SP+ SWAP MOV, ; \ 22 cycles : RPUSH, ( src -- ) RP DECT, *RP MOV, ; : RPOP, ( dst -- ) *RP+ SWAP MOV, ; \ this one allows nested subroutine calls. Never really needed it : CALL, ( dst -- ) \ total cycles 44 to call, 34 to return R11 RPUSH, \ save R11 on forth return stack ( addr) BL, \ branch & link saves the PC in R11 R11 RPOP, ; \ R11 RPOP, is laid down by CALL, in the caller \ We have to lay it in the code after BL so \ when we return from the Branch&link, R11 is \ restored to the original value from the rstack I copied the jump mechanism for my assembler from Win32Forth. It was always confusing going the other way, from conventional Assembler to Forth assembler so that was my solution. Sorry it's confusing going the other way. I understand. <time goes by...> So I just peeked into your code and I think the difference in loop speed is the classic space vs speed trade off. Yours is saving lots of space by JMPing to BRANCH every chance you get which is smart on a TI-99. My BRANCH is far away in scratch pad RAM so I just bit the bullet and took the space. If I can shoehorn (LOOP) into scratch pad RAM I may have something a little faster again. BF
  8. I am not sure I want to use sound lists like the TI system does. I have built a simple music playing system using the PC loudspeaker in Forth that used a defining word called NOTE: It lets you define notes like this : 440 NOTE: A. They I created note definitions that set the time duration as whole notes, half notes etc... So my sound list then becomes a Forth list of words. It's code based solution rather than a data based solution. It's actually up on Rosetta. http://rosettacode.org/wiki/Musical_scale#Forth I figure with the multi-tasker and a lexicon like this I should be able to play 3 part music, but I may need to add a "conductor" type function to keep everybody synced. That's the plan anyway. Please don't stop talking. There are very few people in the world with whom one can share Forth ideas for the TI-99. BF
  9. I STAND CORRECTED. I just wrote a FOR NEXT loop and the speed difference between the above DO LOOP and FOR NEXT is almost non-existent. On an Intel ITC Forth I see a 30% improvement. I am really surprised. But on the 9900 there is only 1 less instruction! Benchmarks are always right.
  10. Well since we are publishing code... I kind of went crazy when I did a sound interface. It's too big, but it works well. This code is written for my XASM99 cross-compiler but it mostly reads like Forth, The biggest difference is the search order control words. (Cross-Assembling, Target-Compiling, Cross-Compiling with shortforms: [TC] [CC] ) Also defining words like CONSTANT have a ':' in the name. I will be changing that. It was my way of staying sane while writing the cross-compiler. :-) When naming Forth words for controlling things, I like to use "units" names if I can, because the syntax looks like English. So that gave rise to and Hz and dB. Note: I did not pay much attention to getting the noise generator correct. That needs work. Not sure if this is of any value to the readers here but this might provide some further ideas for sound control, or maybe how NOT to do it. BF \ TMS9919 SOUND CHIP DRIVER and CONTROL LEXICON Jan 2017 BJF \ need a good timer for sound control MIRROR [undefined] TMR! [if] [CC] include cc9900\ticktock.hsf [then] \ ========================================================================== \ C H I P C O N T R O L C O N S T A N T S [CC] HEX TARGET-COMPILING \ TMS9919 is a memory mapped device on the TI-99 @ >8400 \ 8400 constant: sndport \ only used once so no need to take up name space \ frequency code must be ORed with these numbers to create a sound \ The number is then split into 2 bytes and each one is sent to the chip 8000 constant: osc1 A000 constant: osc2 C000 constant: osc3 E000 constant: noise \ Attenuation values are ORed with these values to change volume (0= max, 15 = off) 90 constant: ATT1 B0 constant: ATT2 D0 constant: ATT3 F0 constant: ATT4 ( noise volume adjust) [cc] decimal [tc] \ I don't have 2constants in the CAMEL compiler so we are doing it manually : f(clk) ( -- d) 4496 17 ; \ this returns 111,860.8 Hz the ACTUAL f(clk) [cc] hex \ =================================================================== \ A S M H E L P E R S F O R S P E E D CROSS-ASSEMBLING \ >FCODE re-arranges Freq. nibbles (4bits) for the TMS9919 \ A HEX frequency value of >0145 must be converted to >0514 CODE: >FCODE ( 0xyz -- 0zxy) \ an fcode is the 12 bits needed to create freq. TOS R1 MOV, \ make copy R1 04 SRL, \ shift 0xyz to 00xy TOS SWPB, \ 0xyz yz0x TOS 0F00 ANDI, \ 0z00 R1 TOS ADD, \ 0zxy) NEXT, END-CODE CODE: SPLIT ( AABB -- BB AA ) TOS R1 MOV, \ make a copy TOS 8 SRL, \ slide 'AA' to the right R1 00FF ANDI, \ mask out AA from the copy R1 PUSH, NEXT, END-CODE TARGET-COMPILING \ for simplicity we will use an "ACTIVE DEVICE" concept using variables variable: THE-OSC \ holds the active OSC value variable: THE-ATT \ holds the active attenuator value \ ================================================================== \ S O U N D P R I M I T I V E S TARGET-COMPILING : hz>fcode ( freq -- fcode ) f(clk) rot UM/MOD NIP 0A / \ convert freq. to bytes and divide by 10) >fcode ; \ fix the nibbles so the work on 9919) [UNDEFINED] SND! [IF] : SND! ( c -- ) 8400 c! ; [THEN] \ : SND! ( c -- ) cr t." >" HEX U. ; \ **for testing** dumps sound data to screen \ ================================================================== \ Set the sound "GENerator that is active. \ Once selected they are used by Hz and db to set the freq and attenuation level. \ The osc and attentuator are selected at the same time : GEN! ( osc att -- ) THE-ATT ! THE-OSC ! ; \ ================================================================== \ S C I E N T I F I C S O U N D C O N T R O L L E X I C O N : GEN1 ( -- ) osc1 att1 gen! ; : GEN2 ( -- ) osc2 att2 gen! ; : GEN3 ( -- ) osc3 att3 gen! ; : GEN4 ( -- ) noise att4 gen! ; : Hz ( n -- ) \ set the freq. in Herz (lowest = 110Hz hz>fcode \ convert n to Fcode# the-OSC @ OR \ OR in the oscillator to use split snd! snd! ; \ split and write bytes to chip \ dB has a range of 0 to -30 in 2 db increments : dB ( level -- ) \ usage: -6 db abs 2/ 0F min \ clip max value to F the-att @ OR snd! ; \ OR new value with the current attenuator and write to chip : MUTE ( -- ) -30 db ; \ mutes active generator : SILENT ( --) 9F snd! BF snd! DF snd! FF snd! ; \ turn off all sounds [cc] decimal [tc] \ Code the classic TI-99 sounds defined in our new language : BEEP ( -- ) GEN1 1398 Hz -4 dB 170 MS MUTE ; : HONK ( -- ) GEN1 218 Hz 0 dB 170 MS MUTE ; [cc] hex [tc]
  11. Well that's pretty cool. Guess I got to get busy creating hooks into the system. BF
  12. You are correct Lee. I have NEXT in PAD RAM along with EXIT, DOCOL, ?BRANCH and BRANCH. When I tested different benchmarks on CAMEL99 without using that speedup, things were 20% slower, so pretty much exactly right with your timing. You are the man. BF
  13. For my CAMEL99 Forth kernel I wanted a way to implement those magic TI sounds. But it had to be small. So here is BEEP and HONK sending raw machine codes to the TMS9919 chip. I put HONK into my ABORT word and it gets very nostalgic when Forth reports an error... I just tested these in Turbo Forth and they work perfectly. : SND! ( c -- ) 8400 C! ; \ write a byte to address of TMS9919 chip : DLY ( n -- ) 0 DO LOOP ; : BEEP ( -- ) 80 SND! 5 SND! \ pre-calculated values for OSC1 1328Hz 91 SND! \ turn on sound at -2 dB 0F00 DLY \ Delay ~ 170 mS 9F SND! ; \ turn off OSC1 : HONK ( -- ) 81 SND! 20 SND! \ pre-calculated values for OSC1 218Hz 90 SND! \ turn on sound at 0 dB 0F00 DLY \ Delay ~ 170 mS 9F SND! ; \ turn off OSC1
  14. Hi Lee, That's interesting. Is FBForth based on TI-Forth? If so then I believe the difference is mostly in the EMIT implementation. If I recall TI EMIT called the system for some stuff and also provided a proper control key interpreter as well. My version of EMIT is very sparse. I tried something weird to try and avoid multiplication in calculating the cursor position. I keep track of the ROW as the VDP address and the column as an offset. That way I only have to add them together in the word VPOS below so it's pretty quick. I use multiplication for manually positioning the cursor with AT-XY however I am intending to use this implementation for cross-compiler tutorial so I am trying to keep a lot of HI-level code with simple support words in Assembler. : EMIT ( char -- ) VPOS C/SCR @ = IF SCROLL THEN \ if we are at last character in the display, scroll (EMIT) \ put the character on the screen & inc. the column VCOL @ C/L @ = \ are we at end of line? IF (CR) THEN ; \ do carriage return math BF
  15. Cool. I am new here but I thought you might be on this site. I used to love XB. I thought is was just great until I wrote something one day and showed my sister in law. She said "Why is it so slow?" She was comparing it to the Commodore 64. I was P.O. ed. :-) Nice to make your acquaintance. I was looking for stuff on youtube when I found your video. Made me curious about how my code compared... of course. It's got me thinking about putting a BASIC wrapper on top of Forth to make something more palatable for people. It's been done in the past on other machines and it should go pretty fast. So much code, so little time. BF
  16. I have never written a BASIC compiler or even an interpreter but I can understand how it would have lots of overhead to make it safe in the way that BASIC is designed to be. I still have grudges with TI over how they implemented the TI-BASIC and XB languages in GPL. Soooo slow. I spent so many hours in the '80s trying to make it go faster. I found this video on youtube demonstrating the speed-up you get using a compiler for XB and it would have made me happy many years ago. I am in the middle of writing a version of CAMEL Forth for the TI-99 and I wondered how it would compare on this simple test. Here is the video I made using version .5 of the system. I shows a bit more of what this ancient platform could have done if the engineers would have been free to make it properly. Camel Forth V.5 Demo.mov
  17. From the album: CAMEL99 Forth

    Video showing 2 different ways to fill the screen with numbers 0 to 9.

    © Brian Fox Markham Canada, 2017

  18. Quick update. I already had EXIT fall thru to NEXT inline so I added inline NEXT to DOCOL. The resulting change in benchmark timing was not material when measured by hand, I could say the times tended to look faster by 100ths of a second, but I would not commit to them. Makes we want to build a better timer. So as they say: "Theory and practice are the same... in theory... but not in practice" BF
  19. Thanks for the advice. I will dig in a little more. I have 9919 driver that uses the Forth word mS coded like this. : MS ( n -- ) 015C MIN 02F * TICKS ; \ max delay= DECIMAL 348 mS And it seems correct when I did this: : BEEP ( -- ) GEN1 1398 Hz -4 dB 170 MS MUTE ; : HONK ( -- ) GEN1 218 Hz 0 dB 170 MS MUTE ; So 1 call to TICKS seems pretty accurate meaning beep and honk seem to have the right sound and I believe the System code uses 170 milliseconds for their duration. Ah well a coder's work is never done. BF
  20. I was having a heck of time with reliability reading the timer in a loop. I noticed on the Classic99 debugger that the machine would crash and end up in the GPL workspace. That seemed weird since I was not doing that so... I masked off interrupts when entering the timer read code and restored them when finished and it works now. CODE: TMR@ ( -- n) \ read the TMS9901 timer 0 LIMI, TOS PUSH, R12 CLR, 0 SBO, \ SET bit 0 TO 1, ie: Enter timer mode TOS 0F STCR, \ READ TIMER (14 bits plus mode bit) into W TOS 1 SRL, \ Get rid of mode bit 0 SBZ, \ SET bit 1 to zero 2 LIMI, NEXT, END-CODE \ these should be 21.3 uS ticks. maximum reliable value is 3FF0 due to Forth loop speed : TICKS ( n -- ) 3FFF SWAP - TMR! BEGIN DUP TMR@ > UNTIL DROP ; So now that it works but the math does not seem to be working to get real time values. For example: 333,000uS / 21.3uS = 15633 ticks (>3D11) Should give a 333mS delay right? But on Classic 99 this code run in a loop that counts to 10, runs in 12.9 seconds : 333MS ( -- ) 3D11 TICKS ; I have to use : 333MS ( -- ) 30C7 TICKS ; to make it come close to 10 secs. Could be Forth loop overhead?? BF
  21. Ha, I completely missed that fall thru on Docol. Don't apologize. I am clearly not OCD enough to be a great coder. (which is why I move to management) :-) OK, So then the question is which one nets the most benefit? EXIT fall thru or DOCOL fall thru? Any thoughts on that? I should probably create a profiler in the code I guess. BF
  22. Sorry, I was using my own terminology without looking at the code. I use Forth as a macro tool to do this kind of thing for NEXT which I am sure you are familiar with. I guess it's not "technically" a macro, but it acts like one so that's what I call it. : NEXT, *NEXT B, ; Turbo Forth in the code you show is spelling out the Branch instruction in full after EXIT. I think we are in violent agreement on placing _EXIT as shown below so that NEXT runs as inline code rather than branching to it through a register after EXIT. I leave it to Willsy on how to incorporate the label _EXIT into a Forth word in his dictionary. (I do it with a cross-compiler so it's kind of like cheating) Am I getting it right yet? _EXIT MOV *RSTACK+,PC ; place saved PC into PC & pop return stack ; NEXT ...loads the next CFA and branches to the address in the CFA. _NEXT MOV *PC+,R6 ; get CFA in r6 MOV *R6+,R7 ; get contents of CFA B *R7 ; execute it
  23. "It can, however, repeat inline the three instructions at NEXT." This is what I meant to communicate un-successfully. Thank you for clarifying. From what I can see he puts EXIT in PAD RAM with a NEXT, macro after it. So it should be NO problem to just transplant it to just before the 3 instructions of NEXT. "That is precisely what TI Forth and fbForth do." Yes this is an old trick for ITC Forths from way back. B
  24. LOL. Well the crown is still safe IMHO. These benchmarks are a hair faster, but your screen driver being mostly code is still faster for sure. However there are some things that might be simpler and maybe a little smaller in CAMEL99. For example here is my KEY word. Instead of counting in code for cursor flash in my own code I just read the interrupt timer in CURS@ and return the cursor or a blank. KEY? does KSCAN like normal and returns true if a key is pressed. ( VC! is just like C! but to VDP RAM. VPOS returns the VDP screen address) It has been fascinating to compare and contrast writing code words versus Forth to keep the size down. CODE: CURS@ ( -- char) \ return cursor or space for flashing cursor TOS PUSH, _CURSR @@ TOS MOV, \ load the cursor char to TOS from memory 8379 @@ W MOVB, \ read interrupt timer to control flash speed W 1800 ANDI, \ AND it with >18. This mask made a pleasant looking flash W W MOV, \ compare result to zero @@1 JEQ, \ if = 0 then we return the cursor char TOS BL LI, \ otherwise return a blank (space) \ 18 bytes @@1: NEXT, END-CODE : KEY ( -- char) BEGIN pause \ multi-tasking switch CURS@ VPOS VC! \ show the flashing cursor KEY? UNTIL \ wait for key press KVAL C@ \ fetch char from KSCAN buffer BL VPOS VC! ; \ erase cursor And in looking over Turbo Forth there is some simple things you could do to speed it up a touch. 1. Place the code for EXIT immediately before NEXT so you don't branch to next after EXIT, but rather run it inline. 2. For the code in PAD ram: Use a JMP instruction to NEXT rather than BRANCH through a register. It's the same size but a 20% faster instruction. So there is the beginning of version 2.x :-) Have at it. I had to get back to work since I am self employed now and that damned cross compiler was taking all my time. Will get back to it one day. BF
×
×
  • Create New...