+Lee Stewart Posted July 18, 2012 Share Posted July 18, 2012 (edited) Hee, I was going to say! It's not referenced anywhere else, not even in a DEF, so it never appears in the object file. But yeah. Win994a didn't get quite enough development time. it's a shame, because with a few tweaks and bugfixes it would be truly amazing. It's still my assembler of choice, but I carefully study the listing file anytime anything wierd happens (that's not always enough either.) Yeah. It's a great assembler, especially when you consider it was just an 'add on' to the main-course! There are some undocumented features in the assembler. For example, IIRC, it supports conditional assembly and macros; they're just undocumented (and maybe unstable) so we don't know how to use them. If you look at the ASM994A exe in a hex editor you'll find references (IIRC) to IF THEN ELSE et al, so they're actually reserved key-words/directives in ASM994A, hence the full on tilt when encountered in your source code! The IF/THEN/ELSE does work. I've used it in Cortex BASIC for conditional compilation for the TI-99 and my TM990 system. Note that the "IF", "THEN" and "ELSE" need to be indented by two spaces. ************* TM990 EQU 1 **** Set to 1 to assemble for the TM990 ************* **** Set to 0 to assemble for the TI-99 IF TM990 ELSE *TI-99 DEF START For the TI-99 so program can be run from E/A option 3. REF KSCAN TI-99 key scan routine. REF DSRLNK File I/O operations. ENDIF *CRU definitions. EIA02 EQU >0040 Main 9902 hardware base address. *Memory mapped I/O definitions. IF TM990 VRAMW EQU >E400 VDP VRAM data write address. VDPREG EQU >E402 VDP VRAM address and register access address. VRAMR EQU >E404 VDP VRAM data read address. VDPSTTS EQU >E406 VDP status read address. ELSE *TI-99 VRAMW EQU >8C00 VDP VRAM data write address. VDPREG EQU >8C02 VDP VRAM address and register access address. VRAMR EQU >8800 VDP VRAM data read address. VDPSTTS EQU >8802 VDP status read address. ENDIF Stuart. That is curious because my, rather, TI's offending code is *** ELSE *** DATA L111F L1120 DATA >C445,>4C53,>45A0 ELSE DATA DOCOL,QCOMP,TWO,QPAIRS,COMPIL,BRANCH DATA HERE,ZERO,COMMA,SWAP,TWO,ENDIF,TWO DATA SEMIS The ELSE is against the left margin. ...lee Edited July 18, 2012 by Lee Stewart Quote Link to comment https://forums.atariage.com/topic/179103-assembly-under-emulation/page/4/#findComment-2561659 Share on other sites More sharing options...
+Lee Stewart Posted July 18, 2012 Share Posted July 18, 2012 It's the label "ELSE" on line 388 that's crashing it, it must be looking for some kind of conditional assembly operation. (Found by binary search - delete half the lines each time, see if it gets through assembly ). You can't even change it to something like "ELSE2", you have to change the word. Changing the first letter works, though, I tested as 'QELSE' It's not referenced anywhere at all, so removing the label seems to let it build too. It also doesn't like the RORG on line 330 of asmsrc2.a99 (though it tells you sort of why but puts the error on like 333). I had to put a number after it (RORG 0). that is definately not the right answer, since it started counting from 0 again and there was already data at zero. Might want to double check the usage of RORG and DORG in this one and then make sure the Asm994A output is what you expect (use the listing file). Thanks for your input, Tursi! I did discover the problem with RORG. Asm994A is wrong. RORG does not require an operand. However, if I put a label "_rlast equ $" just ahead of the "DORG 0" and then use "RORG _rlast", it gets the right value when it continues. I have no choice regarding ELSE. That is the definition of the eponymous TI Forth word. ...lee If I use "else" instead of "ELSE", it works. If the object file stores it as uppercase only, I'm OK. Otherwise, I will have to think of something else. ...lee Hm-m-m-m... Forth does not use the Assembly label to find the word. It uses the name in the DATA statement above it. It appears, as you say, Tursi, to be an idle label! ...lee Yeah. That label will only come into play if you want to write Forth code in assembly. That is to say, pre-compiled Forth code, which is a list of entry points: DATA OVER,DUP,LIT,42,ADD etc... In the case of ELSE, I would imagine pre-compiled Forth words are going to be written in terms of 0BRANCH rather than IF...ELSE...THEN, as that is how they would be compiled (having been translated by the immediate words IF...ELSE etc). Virtually all of the resident Forth vocabulary in TI Forth is defined in ASMSRC and there are no DEFines or REFerences at all---only a few EQUates for the inner and outer interpreters and utilities. The object code is at 7282 bytes, so I have a little room to add to the resident vocabulary and can deal with any modified assembly labels I might need at that time. Of course, I have not studied your TurboForth code well enough to know what additional code I will need when I decide to try to hoist TI Forth into cartridge ROM. Quote Link to comment https://forums.atariage.com/topic/179103-assembly-under-emulation/page/4/#findComment-2561678 Share on other sites More sharing options...
Willsy Posted July 18, 2012 Share Posted July 18, 2012 Hi Lee At a guess, you'll need code to: Connect to DSRs (DSRLNK equivalent) (I presume the TI Forth authors relied on EAs DSRLNK) Connect to GPL routines (GPLLNK) Connect to ROM routines (XMLLNK) Scan the keyboard All in TurboForth, and can be found elsewhere. My main source of information for this low-level stuff was Theirry's web site. Feel free to pillage the TF source for anything that's useful. That's what it's there for! [Edit: TF only uses GPLLNK at startup (after you select the TF option from the menu) to load the character sets from GROM. After that, it's not used at all. Meh. All that, and the lower case characters are overwritten with true lower case anyway! I wonder if it was worth the effort!] Quote Link to comment https://forums.atariage.com/topic/179103-assembly-under-emulation/page/4/#findComment-2561769 Share on other sites More sharing options...
Willsy Posted July 18, 2012 Share Posted July 18, 2012 Regarding labels and dictionary structure, I used a loose self-imposed convention in TurboForth. Here's the implementation for DUP: duph data droph data 3 text 'DUP ' dup data $+2 mov *stack+,*stack b *next So, duph = address of the beginning of this dictionary entry ('h' duph meaning 'header') data droph = pointer to top of previous entry in the dictionary data 3 = number of characters in this dictionary entry (also used for immediate and hidden flags, and also to encode the block number for the WHERE query) DUP = the word name, with a trailing space to pad it to an even number of characters dup = CFA. When assembled, dup is a label that points to the CFA of this word. Thus it can be used in data statements to call DUP. DATA $+2 = Indirect threaded code, so points to the machine code. High level point to DOCOL in scratch-pad b *next = B *R12. At the very start of the TF source you'll see a "next EQU R12" equate. Just helps the source code to be a bit more readable. I've also equated the PC (R3), the data stack (R4) and the return stack (R5) IIRC. Quote Link to comment https://forums.atariage.com/topic/179103-assembly-under-emulation/page/4/#findComment-2561780 Share on other sites More sharing options...
+Lee Stewart Posted July 18, 2012 Share Posted July 18, 2012 Hi Lee At a guess, you'll need code to: Connect to DSRs (DSRLNK equivalent) (I presume the TI Forth authors relied on EAs DSRLNK) Connect to GPL routines (GPLLNK) Connect to ROM routines (XMLLNK) Scan the keyboard All in TurboForth, and can be found elsewhere. My main source of information for this low-level stuff was Theirry's web site. Feel free to pillage the TF source for anything that's useful. That's what it's there for! [Edit: TF only uses GPLLNK at startup (after you select the TF option from the menu) to load the character sets from GROM. After that, it's not used at all. Meh. All that, and the lower case characters are overwritten with true lower case anyway! I wonder if it was worth the effort!] Mark... Thanks for all this and what you wrote in subsequent posts! The TI Forth authors wrote all their own links (DSRLNK, GPLLNK, XMLLNK, KSCAN, VSBW, VMBW, VSBR, VMBR and VWTR)! Only the Forth boot program (FORTH) relies on E/A's DSRLNK, VMBR, VMBW and VWTR to load the TI Forth system (FORTHSAVE) and set up VDP RAM before it hands off control to TI Forth. One primary reason for all the rewriting of the links was that the authors used E/A's utility space for TI Forth's 5 disk buffers. Once the boot program loads the system, it uses TI Forth's GPLLNK a couple of times before actually starting TI Forth. Once that happens, the E/A utility space is pretty much trashed. Obviously, for a cartridge system, I won't need the boot program to load from disk, so I should not need any of E/A's utilities that have not been written into the TI Forth system's support utilities. Rewriting TI Forth to work in a cartridge will be instructive for sure and, I hope, fun. I will undoubtedly need plenty of assistance from the experts on this forum! ...lee Quote Link to comment https://forums.atariage.com/topic/179103-assembly-under-emulation/page/4/#findComment-2561875 Share on other sites More sharing options...
+Lee Stewart Posted July 18, 2012 Share Posted July 18, 2012 Regarding labels and dictionary structure, I used a loose self-imposed convention in TurboForth. Here's the implementation for DUP: duph data droph data 3 text 'DUP ' dup data $+2 mov *stack+,*stack b *next So, duph = address of the beginning of this dictionary entry ('h' duph meaning 'header') data droph = pointer to top of previous entry in the dictionary data 3 = number of characters in this dictionary entry (also used for immediate and hidden flags, and also to encode the block number for the WHERE query) DUP = the word name, with a trailing space to pad it to an even number of characters dup = CFA. When assembled, dup is a label that points to the CFA of this word. Thus it can be used in data statements to call DUP. DATA $+2 = Indirect threaded code, so points to the machine code. High level point to DOCOL in scratch-pad b *next = B *R12. At the very start of the TF source you'll see a "next EQU R12" equate. Just helps the source code to be a bit more readable. I've also equated the PC (R3), the data stack (R4) and the return stack (R5) IIRC. This will certainly help me understand TF as I move forward to cartridge space; but, for now, at least, I will be trying to change as little of TIF as I can---its structure for a dictionary entry is definitely different from TF's and I do understand that pretty well. ...lee Quote Link to comment https://forums.atariage.com/topic/179103-assembly-under-emulation/page/4/#findComment-2561935 Share on other sites More sharing options...
+Lee Stewart Posted April 3, 2014 Share Posted April 3, 2014 I have a question concerning the interrupt service routine (ISR) in the console ROM. I tried to get an answer over in my fbForth thread here without much success. Maybe it'll get more traction in this thread. In the following full excerpt of the console ISR from TI99/4A INTERN, Heiner Martin's comment on line 226 (CLR R8) is "Clear GROM search pointer"; but, the E/A Manual says the GROM search pointer is in the INTWS (at this point in the ISR, the GPL workspace is in use). Which one is correct? And, if the the E/A Manual is correct, why clear GPLWS R8 (>83F0) just before ending interrupt processing? The reason I ask the question is that I am working on hoisting fbForth into cartridge space and I'm trying to reconcile what the TI programmers of TI Forth did (omitted that "CLR R8" line) with what the earlier TI programmers of the console ROM's ALC did by including it. Interrupt routine 0900 0300 LIMI >0000 Disable interrupt 0902 0000 0904 02E0 LWPI >83E0 Load GPLWS! 0906 83E0 0908 04CC CLR 12 Clear CRU 090A 23A0 COC @>0032,14 Cassette interrupt? 090C 0032 090E 1602 JNE >0914 No, jump 0910 0460 B @>1404 0912 1404 0914 1F02 TB >0002 0916 1619 JNE >094A Jump, if VDP interrupt 0918 020C LI 12,>0F00 Clear CRU 091A 0F00 091C 1D01 SBO >0001 091E 1E00 SBZ >0000 0920 022C AI 12,>0100 0922 0100 0924 028C CI 12,>2000 0926 2000 0928 130E JEQ >0946 End CRU 092A 1D00 SBO >0000 092C 9820 CB @>4000,@>000D ROM exists 092E 4000 0930 000D 0932 16F5 JNE >091E No, next 0934 C0A0 MOV @>400C,2 Intlnk? 0936 400C 0938 13F2 JEQ >091E No, next ROM 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 095E 837A 0960 1343 JEQ >09E8 No sprite end 0962 098C SRL 12,8 0964 0202 LI 2,>8800 VDP RD 0966 8800 0968 0203 LI 3,>8C00 VDP WD 096A 8C00 096C 0208 LI 8,>0780 Sprite motion table 096E 0780 0970 D7E0 MOVB @>83F1,*15 Write address motion table 0972 83F1 0974 D7C8 MOVB 8,*15 0976 04C4 CLR 4 0978 D112 MOVB *2,4 Datas Y velocity 097A 04C6 CLR 6 097C D192 MOVB *2,6 Datas X velocity 097E 0844 SRA 4,4 0980 D152 MOVB *2,5 Auxiliary datas 0982 0845 SRA 5,4 0984 A144 A 4,5 0986 D1D2 MOVB *2,7 0988 0846 SRA 6,4 098A 0847 SRA 7,4 098C A1C6 A 6,7 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 position 099C A105 A 5,4 099E 0284 CI 4,>C0FF 09A0 C0FF 09A2 1209 JLE >09B6 09A4 0284 CI 4,>E000 Compute new position 09A6 E000 09A8 1B06 JH >09B6 09AA C145 MOV 5,5 09AC 1502 JGT >09B2 09AE 0224 AI 4,>C000 09B0 C000 09B2 0224 AI 4,>2000 09B4 2000 09B6 04C6 CLR 6 09B8 D192 MOVB *2,6 09BA A187 A 7,6 09BC 0268 ORI 8,>4000 VDP address for writing 09BE 4000 09C0 D7E0 MOVB @>83F1,*15 09C2 83F1 09C4 D7C8 MOVB 8,*15 09C6 D4C4 MOVB 4,*3 Write positions 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 09E8 0A11 SLA 1,1 09EA 183D JOC >0A66 No sound process jump 09EC D0A0 MOVB @>83CE,2 Number of sound byte 09EE 83CE 09F0 133A JEQ >0A66 None, then end 09F2 780E SB 14,@>83CE -1 09F4 83CE 09F6 1637 JNE >0A66 Not 0, then end 09F8 C0E0 MOV @>83CC,3 Pointer sound list 09FA 83CC 09FC C14E MOV 14,5 09FE 0915 SRL 5,1 GROM or VDP? 0A00 180A JOC >0A16 1=VDP, then jump 0A02 06A0 BL @>0864 Push GROM address on substack 0A04 0864 0A06 0205 LI 5,>0402 0A08 0402 0A0A A14D A 13,5 GROM write address 0A0C D543 MOVB 3,*5 Write GROM address 0A0E D560 MOVB @>83E7,*5 0A10 83E7 0A12 C18D MOV 13,6 Read address 0A14 1007 JMP >0A24 0A16 0205 LI 5,>8C02 VDPWA 0A18 8C02 0A1A D560 MOVB @>83E7,*5 Write VDP address 0A1C 83E7 0A1E D543 MOVB 3,*5 0A20 0206 LI 6,>8800 VDPRD 0A22 8800 0A24 D216 MOVB *6,8 Fetch byte 0A26 130F JEQ >0A46 0? 0A28 9220 CB @>0A9C,8 0A2A 0A9C 0A2C 130A JEQ >0A42 >FF? Yes,switch to another(well possible)! 0A2E 0988 SRL 8,8 Number 0A30 A0C8 A 8,3 To address 0A32 D816 MOVB *6,@>8400 Load sound process 0A34 8400 0A36 0608 DEC 8 How many bytes? 0A38 16FC JNE >0A32 Next byte 0A3A 05C3 INCT 3 0A3C D096 MOVB *6,2 Fetch duration 0A3E 1309 JEQ >0A52 0A40 1009 JMP >0A54 Go on 0A42 2BA0 XOR @>0378,14 Change system flags 0A44 0378 0A46 D0D6 MOVB *6,3 Fetch new address 0A48 0202 LI 2,>0100 Sound byte >01 0A4A 0100 0A4C D816 MOVB *6,@>83E7 Complete address 0A4E 83E7 0A50 1001 JMP >0A54 Once again 0A52 7082 SB 2,2 0A54 C803 MOV 3,@>83CC New pointer sound list 0A56 83CC 0A58 D802 MOVB 2,@>83CE Sound byte 0A5A 83CE 0A5C 0285 CI 5,>8C02 From VDP? 0A5E 8C02 0A60 1302 JEQ >0A66 0A62 06A0 BL @>0842 POP GROM address from substack 0A64 0842 0A66 0A11 SLA 1,1 0A68 180D JOC >0A84 No QUIT key, then jump 0A6A 020C LI 12,>0024 Load CRU 0A6C 0024 0A6E 30E0 LDCR @>0012,3 0A70 0012 0A72 0B7C SRC 12,7 0A74 020C LI 12,>0006 0A76 0006 0A78 3605 STCR 5,8 Fetch CRU 0A7A 2560 CZC @>004C,5 QUIT key? 0A7C 004C 0A7E 1602 JNE >0A84 0A80 0420 BLWP @>0000 Software reset 0A82 0000 0A84 D82F MOVB @>FC00(15),@>837B VDP status in copy RAM 0A86 FC00 0A88 837B 0A8A 02E0 LWPI >83C0 INTWS 0A8C 83C0 0A8E 05CB INCT 11 Screen timeout counter 0A90 160B JNE >0AA8 Not 0 Interrupt level 2: 0A92 D30A MOVB 10,12 VDP register 1 0A94 098C SRL 12,8 0A96 026C ORI 12,>8160 Basis value 0A98 8160 0A9A 024C ANDI 12,>FFBF Turn off screen 0A9C FFBF 0A9E D820 MOVB @>83D9,@>8C02 Load VDP register 0AA0 83D9 0AA2 8C02 0AA4 D80C MOVB 12,@>8C02 0AA6 8C02 0AA8 02E0 LWPI >83E0 GPLWS 0AAA 83E0 0AAC B80E AB 14,@>8379 VDP interrupt timer (system flags!) 0AAE 8379 0AB0 C320 MOV @>83C4,12 User defined interrupt 0AB2 83C4 0AB4 1301 JEQ >0AB8 None, then jump 0AB6 069C BL *12 Otherwise execute 0AB8 04C8 CLR 8 Clear GROM search pointer 0ABA 02E0 LWPI >83C0 INTWS 0ABC 83C0 0ABE 0380 RTWP And end interrupt ...lee Quote Link to comment https://forums.atariage.com/topic/179103-assembly-under-emulation/page/4/#findComment-2962162 Share on other sites More sharing options...
Willsy Posted April 4, 2014 Share Posted April 4, 2014 Total guess: The inference is that GROM based devices can emit interrupts and have them serviced by the console ISR (which will in turn invoke a GPL ISR in the device emitting the interrupt). By omitting the CLR R8, the TI Forth programmers are assuming that no interrupt-emitting GPL devices are connected to the computer. *Total* stab in the dark! Tursi? Quote Link to comment https://forums.atariage.com/topic/179103-assembly-under-emulation/page/4/#findComment-2962365 Share on other sites More sharing options...
+mizapf Posted April 4, 2014 Share Posted April 4, 2014 (edited) I do not know of any GROM-based device that raised interrupts; GROMs may, however, slow down the CPU using the READY line. No, honestly, as I said in the other thread, I believe CLR R8 in GPLWS in the console is meaningless. It does not hurt, so it is not a bug in a proper sense, just a useless line. Maybe Heiner Martin was deceived by this code in the same way and believed that it clears the GROM search pointer, so he added this comment. Or let's turn it this way - they may have had something in mind with clearing the GROM search pointer, but it was obviously unneeded. Edited April 4, 2014 by mizapf Quote Link to comment https://forums.atariage.com/topic/179103-assembly-under-emulation/page/4/#findComment-2962376 Share on other sites More sharing options...
+Lee Stewart Posted April 4, 2014 Share Posted April 4, 2014 Thanks, Guys! I would now agree that Heiner Martin was deceived because the "meaning" of R8 in the interrupt workspace as stated in the E/A manual was confirmed by a second source, viz., TI's Graphics Programming Language: Programmer"s Guide. Perhaps the programmers of the console ISR were hedging their bets because the ISR uses GPLWS R8 as a work register for VDP processing etc., which, I agree, seems pretty useless to clear because the GPL interpreter uses it as a work register as well, so far as I can tell. If, on the other hand, their intent was, indeed, to clear the INTWS GROM search pointer, they have the two instructions reversed, i.e., lines 226 and 227, in the spoiler in my last post, should be reversed. The only other possibility that comes to mind (and I don't think I care to research it) is that the console cassette routines rely on GPLWS R8 in places they can be interrupted and the console ISR clears it to be safe. The fact that the TI Forth programmers ignored it as a useless instruction (and, of course, allowing that the console ROM programmers actually knew what they were doing by clearing GPLWS R8) makes a little more sense in this context because TI Forth did not provide for cassette use. I suppose I should consider this horse well and truly dead! ...lee Quote Link to comment https://forums.atariage.com/topic/179103-assembly-under-emulation/page/4/#findComment-2962517 Share on other sites More sharing options...
Tursi Posted April 4, 2014 Share Posted April 4, 2014 Total guess: The inference is that GROM based devices can emit interrupts and have them serviced by the console ISR (which will in turn invoke a GPL ISR in the device emitting the interrupt). By omitting the CLR R8, the TI Forth programmers are assuming that no interrupt-emitting GPL devices are connected to the computer. *Total* stab in the dark! Tursi? Mizapf already covered it, GROMs are only memory devices. The only hardware they can control is the HOLD line on the CPU, and that is gated only during a GROM access (GROMs actually hold that line active in their idle state, so the console ensures that the CPU doesn't see it when GROMs are not being accessed). Quote Link to comment https://forums.atariage.com/topic/179103-assembly-under-emulation/page/4/#findComment-2962679 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.