Jump to content

Lee Stewart

+AtariAge Subscriber
  • Posts

    5,848
  • Joined

  • Last visited

Everything posted by Lee Stewart

  1. Still working on the TODO list for fbForth 3.0, but here is the current list with not very many items left! Of the items left to do, I want to work on a couple before committing to them: fbForth300_TODO.txt The new DSRLNK currently being discussed in its own AA thread, FONTED full-font display screen toggles, Including UDSQRT in the resident dictionary—plenty of room for it and could use it for actual distances instead of their squares in coincidence calculations. Only hesitation is that the result is truncated instead of rounded, which likely does not matter. The recent tasks accomplished are Replacement of all SYSTEM calls with direct B or BL calls, with concomitant removal of the SYSTEM word and the its call table. Removal of many instances of “LIMI 0” due to (1) and addition of same to individual routines. Changing the user variable SCRFNT from a bi-state into a tri-state flag: (=0) default font from bank #3 of cartridge, (<0) user font file, (>0) console font with small caps for lowercase. ...lee
  2. $ is an assembly-time placeholder and represents the current program location wherever it is referenced in the program. It is not evaluated at run-time. And what @apersson850 said. This code will generate object code identical to my previous offering: STWP R1 MOV R1,@NEWWP+2 ; set up new WS LWPI MYWS ; Your code ; Time to return NEWWP LWPI >0000 ; load new WS ; more code ...lee
  3. No—well, partly. LWPI is a 2-word instruction. NEWWP points 1 word (2 bytes) past LWPI to the location of the >0000 word. The >0000 is overwritten with the new WS location. Oh, and I should add that the “LWPI MYWS” is not involved with the “MOV R1,@NEWWP”. Rather, it is copying the old WP to NEWWP so that a proper return to the old WS can be made without the programmer needing to know where it is. Perhaps, it should have been named OLDWP. ...lee
  4. Though the above works, the following would be more efficient in this case: STWP R1 MOV R1,@NEWWP ; set up new WS LWPI MYWS ; Your code ; Time to return NEWWP EQU $+2 ; storage for WS location (points to >0000) LWPI >0000 ; load new WS ; more code ...lee
  5. You are correct—it won’t. This will: STWP R1 MOV R1,@NEWWP ; set up new WS LWPI MYWS ; Your code ; Time to return LI R9,>02E0 X R9 NEWWP DATA >0000 ; storage for WS location ; more code Though there are certainly errors of commission and omission in the E/A manual, the description of the X instruction is correct and quite clear. ...lee
  6. Forgive me for piling on, but because we ALC programmers know we need to preserve R11 when we start/continue a BL-RT cascade, we usually put the “save return” at a the routine’s beginning with the “restore return” at the end just before RT, I would push the link (PUSHL) at the beginning and return after popping the link (RTPL) at the end. Here are the macros for xas99.py: .defm PUSHL DECT RSP MOV R11,*RSP .endm .defm RTPL MOV *RSP+,R11 B *R11 .endm And here is how I would use them: SUB1 .PUSHL * <do stuff> BL @SUB2 * <do stuff> .RTPL SUB2 .PUSHL * <do stuff> BL @SUB3 * <do stuff> .RTPL SUB3 * <do stuff> RT ...lee
  7. I know little about the HFDC DSR, so I may be off base here, but if records are set up the same way as for the TI DSR, a 255-byte fixed record takes up 256 bytes (1 sector) on disk. That would mean that record 1024 should be at file location 1024 x 256 = 0x40000. ...lee
  8. Of course, all of the Forths do this, including yours (CAMEL99 Forth) and mine (fbForth). I do it locally (a second return stack) in the Floating Point Library because I am using a different workspace. ...lee
  9. I don’t know much about the PASCAL stack, but I will bet your making room on the stack should be DECT R10 What you have actually stomps on what was on the stack before that instruction because the MOV writes to an even address by ignoring the least significant bit of the address. Perhaps you mistyped in your message? ...lee
  10. CFMGR is an E/A5 program. With the E/A cartridge in, choose ‘2’ for “EDITOR/ASSEMBLER”, then ‘5’ for “RUN PROGRAM FILE”. When prompted for a file, enter “DSK2.CFMGR”, after which the program is loaded and started. Check in the spoiler for more information than you probably want to know about E/A5 programs. ...lee
  11. It is, indeed, 16-bit RAM, but multiplexed on the 8-bit bus, which, of course, slows down access considerably. The TMS9900 only accesses RAM on even, 16-bit boundaries. @Necrospect’s “not under normal circumstances”, I think, was allowing for those who have modified their consoles with expansion RAM on the 16-bit bus. ...lee
  12. Those low-level functions are stored in the cartridge and copied to low RAM at startup. If you want to wade through it, it is posted on my website (see below), though it is behind a couple of builds: Menu: Source Code-->Bank 1-->Low Level Support One of these days soon I really will update my website. Sorry about its old age. ...lee
  13. Much of a threaded interpretive language like fbForth is put together with high-level colon definitions that are compilations of cfas, which are addresses of executable code that are interpreted by the inner interpreter, that is, they are executed in turn. This is definitely slower than assembly language code (ALC). There are, however, a significant number of words that are written in ALC. The E/A-utility analogs are among them. They are marginally slower than ALC because they still go through the inner interpreter to get executed. ...lee
  14. Yes. The datum that follows BLWP @DSRLNK is the offset into the DSR of the list to search. DATA 8 tells DSRLNK to start at >4000+8 = >4008, containing the address of the start of the device list that contains level 3 devices like DSK1, etc., for the TI floppy DSR. DATA 10 starts the search at the address at >400A, the head of the subprogram list that contains level 1 and 2 subprograms. Probably more information than you wanted, but level 1 and 2 subprograms for the TI DSR do not use a PAB as do level 3 DSRs, but rather, a “transfer block” starting at >834A (level 1) or >834C (level 2), which gets populated with information unique to the subprogram. A given transfer block may require an “additional information block” you can place where you want. Error codes are returned in the byte at >8350. Details for all three levels of DSRs/subprograms are in GPL Interface Specification for the 99_4 Disk Peripheral V2.0 03-28-1983. ...lee
  15. And there you nailed it. All of the low-level code needed for the return stack, bank-agnostic routines ( trampoline functions, block-I/O functions, VRAM functions, etc.) a handful of editable words ( (ABORT) FORTH ASSEMBLER ), and more. Of course, SAMS could be pressed into service as more block-buffer space, but the question had to do with the possibility of loading the E/A utilities from Forth, which seems an exercise in futility in fbForth because they are already part of the language. ...lee
  16. fbForth has its own version of all of the E/A utilities (except for the loader and linker, of course), which are copied to low RAM. If you load the E/A utilities into low RAM (which you can certainly do), you will overwrite those utilities, as well as the Forth block buffers and a host of other low-level stuff fbForth requires to function at all. ...lee
  17. Because of the effort to save bytes by the programmers of this MG GPLLNK code and the fact that, though not checked for overflow by the console ROM’s PUTSTK (at >0864), which manipulates the GPL subroutine stack address in the same way, I suspect this was intentional in both cases. A whole lot would go wrong long before >8373 even got close to >FE. The bottom of the subroutine stack is initialized to >837E (>7E at >8373), so the first item pushed to the stack by INCT sets the pointer to >80 (>8380). Usually(?), neither the data stack (pointer in >8372) nor the subroutine stack (pointer in >8373) is expected to exceed a depth of 32 bytes, though the subroutine stack extent is checked in a couple of places in console ROM for whether it got past >83BA, which means that it is allowed, at times, to overrun the data stack (perhaps not in use then?). The bottom of the data stack is initialized to >9E (>839E) and is incremented/decremented in the console ROM using AB/SB, so only that byte is involved. Given that the use of INCT by MG was intentional, they should, at the very least, have explained why it was OK. ...lee
  18. Haven’t tested the current code, yet. Got sidetracked with the fbForth SYSTEM utilities mods, Rich’s CALL CHAR(), and the E/A utilities thing over in the Assembly thread. ...lee
  19. There is more than one way to handle this. If you want to use the E/A utilities exactly as from the E/A cartridge, you will need to include the source for those utilities in your cartridge code, using the XORG directive to manage the location counter. Your program will then need to copy those utilities to the proper address in low RAM at startup. My source for the source code of those utilities is Thierry Nouspikel’s site. Thierry’s disassembly of the relevant code is on his site, but here it is, as well: You do not need all of this code for your program to work. You can remove the linker and loader and the REF/DEF table as I have done in the following code, which I have not tested but believe I have cut it up properly: The above code will consume 810 bytes of your cartridge space as well as the few bytes of code you will need for copying it to low RAM starting at >2000. You will also need the following EQUates in your cartridge code in order to use the routines: GPLLNK EQU >2100 XMLLNK EQU >2104 KSCAN EQU >2108 VSBW EQU >210C VMBW EQU >2110 VSBR EQU >2114 VMBR EQU >2118 VWTR EQU >211C DSRLNK EQU >2120 [Note: I should add that GPLLNK will not work properly without a little more work. The “xml r11 buffer” at A2030 needs the proper value supplied by the E/A loader before it will function correctly. From looking at that location after a “load and run” (option 3 from the E/A cartridge) in Classic99’s debugger, it would appear that value is >061C. Programs, like TI Forth, that have their own GPLLNK routines get a valid value at start up. I will have a look and report back.] ...lee
  20. Indeed. It saves several trips through the inner interpreter in KEY and a few in KEY8. ...lee
  21. Well...high-level KEY and KEY8 each called (via CFA) a code-defined third word that BLed to the keyboard ALC KY routine (38 bytes). Now, KEY and KEY8 each BL to KY themselves, making the third word unnecessary (20 bytes). ...lee
  22. I have this bad habit of “carefully” changing lots of code before testing any of it! It almost bit me this time. As you know, I have been busy modifying the fbForth SYSTEM calls. I was testing as I went along until I got to the five or so keyboard-related routines, all of which I modified before testing again—definitely not a good idea! Because of where fbForth went into the weeds, I was pretty sure the low-level KY routine (waits for user to press a key) called by the high-level Forth KEY, was the culprit, but I was dreading the debugging process. Probably only @TheBF and @Willsy will care (and might not have made my mistake), but here it is: When the KY routine does not detect a key-press, it does not exit normally by RTing back to its caller. Rather, it causes the high-level KEY to be re-executed by backing up the Interpretive Pointer (IP) and branching to NEXT in the inner interpreter. This works because KEY is a high-level Forth colon definition. I had changed it to an ALC-defined word, which cannot be re-executed in the same manner as a colon-defined word. I had to change the backup code from * Set up to re-enter via fbForth's KEY KEY7 DECT IP re-execute fbForth's KEY B *NEXT to * Set up to re-enter via fbForth's KEY KEY7 DECT W re-execute fbForth's KEY B @DOEXEC not a colon definition anymore which manipulates the current Word pointer (W) rather than the IP. All fixed! Here is the inner interpreter (located in high-speed, scratchpad RAM), in case you were wondering: I will sleep well tonight! ...lee
  23. The file cluster list is in the last 228 bytes of the file’s FDR (File Descriptor Record). Each cluster has a 12-bit pointer and a 12-bit cumulative-sector number, so 3 bytes per cluster, for a total of 76 clusters for a full cluster list. If you want to actually read the information for a cluster, it is a little complicated: If we label the 3 nybbles of the cluster pointer as n1 – n3 and the 3 nybbles of the cumulative sector offset as m1 – m3, with the subscripts indicating the significance of the nybble, then the 3 bytes are laid out as follows: Byte 1: n2n1 Byte 2: m1n3 Byte 3: m3m2 The actual 12-bit numbers, then, are Cluster Pointer: n3n2n1 Sector Offset: m3m2m1 ...lee
×
×
  • Create New...