Jump to content

TheBF

+AtariAge Subscriber
  • Posts

    4,470
  • Joined

  • Last visited

Everything posted by TheBF

  1. Yes the file system is record based, not memory block based (Well... except for programs using the LOAD/SAVE commands . They can do 8K blocks at a time but that's not typically for data) So if you use DV80 files you can only read 80 bytes max at a time. You literally read the file one line at a time for DV80 files. Each time you do a read command a new line appears in the VDP buffer and the number of chars read appear in what I called the PCHARS field as a byte. For fixed files you read 1 fixed size record at a time. So your VDP buffer does not need to be bigger than 128 bytes.
  2. I might be making things worse but to make things clearer you could consider laying out your CPU RAM image of the PAB so that it is easy to remember what is what. Use the CPU PAB as a mirror image of the VDP PAB. Use the mirror for all control and copy it into VDP RAM before calling dsrlink. For I notice that your CPU PAB does not make it clear where the filename text goes (at least to me) and how much space is allocated for the text. SBUFF EQU >1000 * BUFFER ADDRESS SBUFF1 EQU >1FE4 * PADDED WITH 28 SPACES VDPPAB EQU >79E * PAB ADDRESS ********************************************************* * PAB DATA STRUCTURE MIRROR IN CPU RAM CPUPAB * used for writing entire CPUPAB to VDPPAB POPCOD BYTE 00 * error bits & op code PFLAG BYTE 02 * status flag field PBUFF DATA SBUFF * pointer to VDP file buffer PLEN BYTE >80 * record length for fixed length records PCHARS BYTE >00 * no. bytes to write or no. bytes read from file PRECRD DATA 0000 * relative files record number to read/write OFFSET BYTE 00 * cassette use only FNAML BYTE 09 * filename length FNAME BSS 32 * extra room for long device strings ******************************************************** The idea is you now have each field of the PAB available as a named label. Each field is there to get at it by name. When the CPU PAB image is all set the way you want you blast the whole thing over to VDP RAM with a VMBW and call DSRLINK. To get the results READ the VDP back into your CPU RAM mirror PAB and you can check status for example. You can also create lists of opcodes to make it clearer when you are using the PAB to read,write, rewind etc. * FILE OPERATION CODES FOPEN BYTE 00 FCLOSE BYTE 01 FREAD BYTE 02 FWRITE BYTE 03 FRWIND BYTE 04 FLOAD BYTE 05 FSAVE BYTE 06 FDELET BYTE 07 * EXAMPLE MOVB @FOPEN,@POPCOD This kind of thing helps my old brain remember what is going where.
  3. Updated FoxShell *EDIT* See new version for 2021 later in this topic As I put my new kernel through its paces I used the new SAVESYS utility to compile a version of my DV80 disk utilities. It's not Force Command by any stretch but handy for me with a large number of text files in the system. At this time they only work with DV80 files. I am still thinking about the best way deal with other file types to make a simple syntax for the end user. There is an APND command that lets you append files to a second file. You can copy files. It is record by record so not a speed demon. In Classic99 it is very handy to to COPY DSK1.MYFILE CLIP and copy a TI-99 file to the windows clipboard. The zip file includes a 40 column and an 80column version. 80 columns was only tested on Classic99. Latest Source for those interested is here: FSHELL.zip
  4. Does anybody know what these files are made with? The DOC files seem to be non ascii except for the file name. ??? Wonderful example of the problems archivists face with digital media.
  5. Yes perhaps you could make a word called REPEATS. It would compile AGAIN and then a two THEN words Un-tested!!! : REPEATS POSTPONE AGAIN POSTPONE THEN POSTPONE THEN ; IMMEDIATE That would handle 2 while conditions. But I am looking at something right now call THENS : THENS BEGIN ?DUP WHILE POSTPONE THEN REPEAT ; IMMEDIATE This mops up like ENDCASE in the Eaker case statement. So in theory we could do : REPEATS POSTPONE AGAIN POSTPONE THENS ; IMMEDIATE Would that remove any discomfort for you?
  6. I believe they are overlapping and I can accept that in a purely structured paradigm it is a bad idea. However all ALC programmers know that sometimes jumping is more efficient that structured programming albeit more confusing and prone to error. But then force fitting pure structure onto something that just needs a damned jump can loop be ugly too. So this structure, like using EXIT THEN, is letting Forth jump around a bit but in a "structured" manner. But I admit my first look at this made me say "That ain't right". Consider: With these simplified loops structures WHILE is really just IF . ( I guess the SWAP is getting the HERE from BEGIN in the correct order. ? ) : WHILE POSTPONE IF SWAP ; IMMEDIATE And REPEAT is AGAIN followed by THEN to resolve the IF ( ie: WHILE) : REPEAT POSTPONE AGAIN POSTPONE THEN ; IMMEDIATE So after the REPEAT we need that extra THEN to resolve the first WHILE. It almost makes sense to me. I am amazed by the people who come up with this stuff however. I would never have considered this. Today I was studying a faster smaller way to do a CASE statement that came from the mind of the late Neil Baud (aka Wil Baden) When I get a working version on my system I will publish here.
  7. Two Barbers WHILEs, No Waiting I made mention of what you can do with these new ISO loops so here is an example. I have been working on the VIBE block editor by Samuel Falvo and it's working well now in 80 column mode. I was reading the commands in the VI editor and one that is missing in VIBE is $ key which puts the cursor at the end of the text on the editing line. I had read the these double WHILE constructs are handy for string functions and now I can see why. One WHILE is handling the absolute end of the loop. It is resolved by the THEN word which maybe should be renamed to ENDWHILE. (?) The 2nd WHILE is for the processing action of finding the space character. I did this for my own edification because I think -TRAILING would work faster for this job. ( WH sets "where" the cursor is in memory in VIBE, SOL and EOL are just the addresses of the start and end of line in memory) : EOTEXT SOL EOL ( addr1 addr2) \ start & end of edit line BEGIN 2DUP <> WHILE \ while we are not at SOL DUP C@ BL = WHILE \ while the char at EOL is blank 1- \ decrement the EOL address REPEAT \ BOTH loops jumps to BEGIN on true logic THEN \ 1st WHILE jumps to here on false logic - ABS 1+ X ! WH ; \ compute new X coord and set where cursor goes
  8. Yes that's the issue. Thank you for the reminder. The Forth83 committee wanted to leave the loop right away versus the older method where you make limit=index and run the code until LOOP is encountered again.
  9. So... in the course of working on my next revision of Camel99 Forth , I finally found the bug in these new ISO FORTH style loops has eluded me for 2 years. I found it because I was trying to squeak in the code to handle HASHed searches and VOCABULARY variables and a search order array. I ran out of room in 8K and so tried using these new style loops. I had given up on integrating them into Camel Forth because they were flakey, but I needed the space. They are smaller the FIG Forth style I have been using because they do less error checking and have some other neat trick that I will show in my next post. It turned out the bug was probably in the original Camel Forth kernel. At least that is way it worked out using these simpler loops. Since the Forth83 standard, getting out of a DO/LOOP has been a bit more difficult but the details elude me at the moment as to exactly why. Camel Forth's solution uses something called a leave stack to manage the problem. This boils down to the compiler knowing how to branch from where LEAVE is in the code to just past the LOOP word. It's is a lot like compiling an IF/ENDIF into the code to do the jump. It also must clean up any stuff that DO left on the return stack with UNLOOP. The word that resolves where all this jumping is to go is called ENDLOOP in Camel Forth but I called it RAKE because it RAKES the LEAVES! Get it! Damn that's a bad joke. And I think I stole it from eForth source code ... What I found after a million or so crashes (ok not a million) was that RAKE was underflowing when it unwound the LEAVE stack. EDIT: Late night mistake. The array is called L0. LP is the pointer into that array, organizing it like a stack with >L and L> . LP L0 Is 4 CELL array variable and so this was over-writing the Code field address of LP L0 the next time LEAVE was called... Yikes! The fix was to reset the LP stack pointer at the end of RAKE. It all worked reliably after that! Hobbies just don't get better than this! I must be crazy, ok I am. \ ANS/ISO Looping and Branching : >MARK ( -- addr) HERE 0 , ; : <RESOLVE ( addr --) HERE - , ; : THEN ( addr -- ) HERE OVER - SWAP ! ; IMMEDIATE : BEGIN HERE ; IMMEDIATE : IF POSTPONE ?BRANCH >MARK ; IMMEDIATE : AHEAD POSTPONE BRANCH >MARK ; IMMEDIATE : ELSE POSTPONE AHEAD SWAP POSTPONE THEN ; IMMEDIATE : UNTIL POSTPONE ?BRANCH <RESOLVE ; IMMEDIATE : AGAIN POSTPONE BRANCH <RESOLVE ; IMMEDIATE : WHILE POSTPONE IF SWAP ; IMMEDIATE : REPEAT POSTPONE AGAIN POSTPONE THEN ; IMMEDIATE \ CAMEL Forth LEAVE stack pointer is initialized by QUIT : >L ( x -- ) ( L: -- x ) 2 LP +! LP @ ! ; : L> ( -- x ) ( L: x -- ) LP @ @ -2 LP +! ; \ -compile this- - run this now- : DO ( -- ) ?COMP POSTPONE <DO> HERE 0 >L ; IMMEDIATE : ?DO ( -- ) ?COMP POSTPONE <?DO> HERE 0 >L ; IMMEDIATE : LEAVE ( -- ) ( L: -- addr ) POSTPONE UNLOOP POSTPONE BRANCH >MARK >L ; IMMEDIATE : RAKE ( -- ) ( L: 0 a1 a2 .. aN -- ) BEGIN L> ?DUP \ read leave stack, dup if <>0 WHILE POSTPONE THEN \ resolves branch in LEAVE REPEAT L0 LP ! ; IMMEDIATE \ reset the leave stack. *BUG KILLED* : LOOP ( -- ) COMPILE <LOOP> <RESOLVE RAKE ; IMMEDIATE : +LOOP ( -- ) COMPILE <+LOOP> <RESOLVE RAKE ; IMMEDIATE
  10. I am not sure I have the lifespan left to use this computer.
  11. To me it depends on how one sees the world. In the E/A Manual the count and the string are understood to be separate pieces of data. This is an Assembly Language view of the computer IMHO. One can look at the count and the text as part of something called a byte counted string, where the 1st byte is the length. So GDMike's BSS 16 gives you room for this entire data structure. Of course one has to remember in your code that this label is pointing one these "counted strings" but it's not a big thing to remember once you commit to the concept.
  12. Cool so one could do A:>EXEC DSK2.CAMEL99 Is there a technical document on how to write programs for MDOS ? My cross-compiler has a 64K segment reserved for the target program. I could make a very FAT Forth system for Geneve. (not that many would care)
  13. Can Geneve load an regular EA5 program that loads at >A000?
  14. Yes. All modern and commercial Forth systems use files now. MPEForth, SwiftForth, iForth, MeCrisp Forth. Well I actually have a little editor that lives in VDP RAM. Only 40 columns wide an 9K of code. You could load that and use it too. Yes ED99 can do that and it's not a concept really it's how all other compilers work. There is just no linking loading step. Forth does it all at once. And when you are finished you save the while thing as an EA5 program. Just got that working.
  15. Yes I have ED99. With stock 32k card and ED99 loaded there is about 7K to load pieces of code, test them and then forget them. I will get ED99 into a separate vocabulary eventually that lives in the 8K pages at D000..EFFF . The Forth vocabulary will use the default pages up there. I almost have everything in place to make that work. So with SAMS it can be a pretty big integrated develop environment.
  16. There are no screens or blocks. Just normal DV80 files. It's almost like we are in the 21st century! It's like an Asm or C program source code file. And all the libraries are the same. DV80 files. Text files... with names... imagine that! The disadvantage of using native files is that editors are bigger and so keeping the editor in memory is hard to do. With SAMS it can be done. BLOCKS are actually a virtually memory system so they are pretty clever for small footprint machines. See the video below for a quick demonstration. We don't have WORDS in the dictionary, so we INCLUDE the tools file. The tools file knows it needs FORGET, CASE and DEFER so it gets those files first and compiles them. Afterwords tools are available to use. INCLUDE TOOLS DEMO.mp4
  17. When you do it will be different because it doesn't use blocks normally. Just text files. (blocks are a loadable extension) It is mostly compatible with Starting Forth (https://www.forth.com/starting-forth/0-starting-forth/) You use any text editor that you like. EDIT1 from E/A works fine. And the kernel is just the CORE words. Everything else you INCLUDE into the system as needed. I have just finished a new version that is not released yet. I want to get it working for super cart as well which gives you lots of memory.
  18. I used a version published by @insanemultitasker which I seemed to be able to understand better. It works well. I have found some ways to make it smaller but I am actually testing right now to see if I can trust it on real iron.
  19. When I got my X BASIC cartridge I thought ACCEPT at was the most amazing thing I had ever seen with all the variations. VALIDATE() with a string or UALPHA and all that stuff. I am now not happy with that way of bundling everything together into a command. I much prefer Chuck Moore's vision of making those pieces separate but easily combinable as you need to. You are right. It makes it easy. Instead of wishing you had this or that you just put some words together. Here is VALIDATE in Camel99 Forth. It uses an assembly language routine called SCAN. Add some strings of validation chars of your choice and voila! : VALIDATE ( char string -- ?) ROT SCAN NIP 0> ; : PUNCTUATION S" !@#$%^&*()_+" ; CHAR Q PUNCTUATION VALIDATE
  20. For GDMike's benefit he should see what it takes to replicate TI BASIC's INPUT word in Forth. I chose to use two words, one for strings and then use the string version for numbers. You can see how ACCEPT was used to capture a string by making $ACCEPT that sets up the input parameters for you and stores the length as the first byte of the string address on the stack. You can also see how much more goes into doing #INPUT like TI BASIC But it works pretty much as expected for a BASIC progammer, just in reverse. \ $INPUT #INPUT for CAMEL99 Forth V2.6 \ *Difference* there is a separate input for numbers and strings DECIMAL : $ACCEPT ( $addr -- ) CR ." ? " DUP 1+ 80 ACCEPT SWAP C! ; : $INPUT ( $addr -- ) BEEP $ACCEPT ; \ BEEP like TI-BASIC : #INPUT ( variable -- ) \ made to look/work like TI-BASIC BEEP BEGIN PAD $ACCEPT \ $ACCEPT text into temp buffer PAD PAD COUNT NUMBER? \ convert the number in PAD WHILE \ while the conversion is bad we do this CR HONK ." input error " CR DROP REPEAT SWAP ! ; \ store number in the variable on the stack CAMEL99 INPUT WORDS.mp4
  21. Yes I misspoke. It is the address of course. Since that is how Forth uses strings I tend to forget that detail in common parlance. I also forgot about that FigForth WORD doesn't leave the address on the stack. There are a lot of small differences between the old systems and Forth83 and forward. Small wonder it makes folks skittish.
  22. Welcome Grayin99. I think you will find that the resources available are incredible compared to when we first bought our machines. Also the level of talent assembled here never ceases to amaze me.
  23. Just realized I didn't respond to this one. If you didn't already look it up WORD is the primary text parser in Forth83,Forth79 and Fig Forth (Like TI-Forth and FbForth are Fig descendants) It is used by the compiler and interpreter to get each word from the string we feed to them, one word at a time. Here is the "official definition" for Forth 2012. WORD ( char "<chars>ccc<char>" -- c-addr ) Skip leading delimiters. Parse characters ccc delimited by char. An ambiguous condition exists if the length of the parsed string is greater than the implementation-defined length of a counted string. c-addr is the address of a transient region containing the parsed word as a counted string. If the parse area was empty or contained no characters other than the delimiter, the resulting string has a zero length. A program may replace characters within the string. So if that doesn't help you... (amazing) Here is what they are trying to tell us: Take a character delimiter parameter from the data stack. Read the text after the word WORD until you encounter that delimiter character. While reading the text, skip any leading spaces (blanks). Typically WORD stores the string at the address called HERE and appends a space to the end of the string it read. It leaves behind a *byte counted string on the data stack with the delimited text. ( *string where the 1st byte is the length) It is not like INPUT in BASIC. It is really best used if you want to make your own compiler extensions. If you are careful you can use WORD to make commands like the Assembler DATA and BYTE directives for example.
  24. Murphy's law is how I evaluate things like that. Since the old battery is dying or dead it doesn't have a high enough EMF so I suspect it will drain the new one somewhat. And some battery chemistry gets upset when you reverse current through it but that's more your area.
×
×
  • Create New...