+Lee Stewart Posted November 17, 2019 Author Share Posted November 17, 2019 Post #1 has been updated with all of the files for the latest build, fbForth 2.0:12. I will update my website later this week. I fixed a couple of bugs: The trigonometric functions in the Floating Point Library returned erroneous results after I hooked the Forth ISR as the system default (in build 9, I believe), DOT (used to plot a pixel in Bitmap mode) ignored half of the color palette you could set with DCOLOR . The latest FBLOCKS has only cosmetic changes—mainly, new binary images for four of the menu options that depend on the build with which they were BSAVEd. Let me know if you find any bugs or need assistance with anything. ...lee 5 1 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted December 10, 2019 Share Posted December 10, 2019 (edited) User defined stacks for FbForth So after you found my 2-! bug everything worked fine. So as a thank you here is a version that works on FbForth. \ STACKS.FTH for FbForth B Fox 2019 \ primitives : CELLS 1 SLA ; : 2/ 1 SRA ; : CELL+ 2+ ; : CELL- 2- ; : 2@ ( adr -- n1 n2 ) DUP 2+ @ SWAP @ ; : LIFO: ( #items -- ) \ "last in first out" creates a stack <BUILDS CELLS DUP , ( # of bytes in the stack) DUP , ( max items on stack ) ALLOT 0 , ( safety cell ? ) DOES> ; : CELL+@ ( addr -- addr' n ) CELL+ DUP @ ; : STACK-SIZE ( 'stack -- n ) @ ; : STACK-DEPTH ( stack-addr -- n ) 2@ - 2/ ABS ; : 2+! ( addr -- ) DUP @ 2+ SWAP ! ; : 2-! ( addr -- ) DUP @ 2- SWAP ! ; : PUSH ( n stack-adr - ) CELL+@ CELL- DUP 0= ABORT" User stack full" OVER 2-! + ! ; : POP ( stack-adr -- n ) DUP 2@ = ABORT" User stack empty" CELL+@ OVER 2+! + @ ; \ test code ................... DECIMAL 10 LIFO: Q 99 Q PUSH 100 Q PUSH 101 Q PUSH Q STACK-DEPTH . Q POP . Q POP . Q POP . Q POP Edited December 10, 2019 by TheBF Dupicate definition 1 1 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted April 28, 2020 Author Share Posted April 28, 2020 On 11/17/2019 at 12:14 AM, Lee Stewart said: Post #1 has been updated with all of the files for the latest build, fbForth 2.0:12. I will update my website later this week. I realize that I have done absolutely nothing to my website (see my signature below) since at least the middle of November—probably even further back than that! And—I probably won’t get to it for a while yet. but I will eventually get to it, I promise. I definitely do not want to disappoint all y’all champing at the bit to have up-to-date Forthy things to peruse there! ...lee 4 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted August 17, 2020 Author Share Posted August 17, 2020 I am starting to look at the SAMS code in fbForth 2.0 to change it to work from whatever low value seems reasonable (256 KiB?) through 16 MiB (the maximum for the 74LS612 chip). Also, I am toying with changing the SAMS flag to save the number of available banks (0 – >1000). 0 would, of course, indicate no SAMS card. Any thoughts? ...lee 1 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted August 17, 2020 Share Posted August 17, 2020 i will need to apprise myself better of your implementation to be truly useful, but I use HEX 10 as the minimum page just to avoid hitting anything in the lower 64K address space. After that, one can use the initialization routine to detect the last available page in the card and fill in your SAMS flag with that. That is something I did not do yet but with the 4Mbyte cards in existence now I guess I should. 2 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted August 18, 2020 Share Posted August 18, 2020 In case it provides any ideas here is my Forth version. It assumes that we only map SAMS into >3000...>3FFF. Compared to the same method with PAGED written in Assembler it has ~45% speed penalty depending on how it's used. I have factored out MAP so that I can quickly map in value only without the overhead of computing the virtual address. Spoiler \ SAMS CARD support for CAMEL99 Forth May 2020 B Fox \ 64K segmented memory model \ HERE DECIMAL 24 USER 'R12 \ address of R12 in any Forth workspace HEX : SAMSCARD ( -- ) 1E00 'R12 ! ; \ select sams card 3000 CONSTANT PMEM \ paged memory block location \ compute SAMS register based on PMEM address PMEM 0B RSHIFT 4000 + CONSTANT SREG VARIABLE SEG \ holds current 64K segment VARIABLE BANK# \ current mapped bank FF CONSTANT LASTPAGE \ true for 1M SAMS card only \ using machine code so we don't need the CRU library HEX \ *set the CRU address in 'R12 before using these words* CODE 0SBO ( -- ) 1D00 , NEXT, ENDCODE CODE 0SBZ ( -- ) 1E00 , NEXT, ENDCODE CODE 1SBO ( -- ) 1D01 , NEXT, ENDCODE CODE 1SBZ ( -- ) 1E01 , NEXT, ENDCODE : SAMS-ON ( --) SAMSCARD 1SBO ; \ enable mapper : SAMS-OFF ( --) SAMSCARD 1SBZ ; \ disable mapper \ safely set the 64K segment that you want to use : SEGMENT ( 1..F -- ) DUP 01 10 WITHIN 0= ABORT" SAMS segment err" SEG ! ; \ don't allow segment 0 1 SEGMENT \ * SAMSINI sets card to "power-up" condition : SAMSINI SAMSCARD \ select SAMS card CRU address 0SBO \ turn card on 0 \ 1st value 4000 20 \ register address, # SAMS regs BOUNDS ( -- 4100 4000) DO DUP I ! \ I is reg. address I @ OVER <> ABORT" SAMS card err" 0100 + \ next value 2 +LOOP 0SBZ \ turn off card DROP ; : MAP ( page -- ) \ map a page at HEX 3000 >< \ swap bytes, bank# must be in left byte SAMSCARD 0SBO \ turn on the card ( bank#) SREG ! \ store bank in SAMS register 0SBZ \ turn off card ; HEX : PAGED ( addr -- addr') SEG @ 1000 UM/MOD ( -- offset bank#) DUP BANK# @ = \ are we using the same PAGE IF DROP \ Yes! Drop bank# and get out ELSE DUP BANK# ! \ update bank# variable MAP THEN PMEM + \ then add offset to paged mem block ; CR HERE SWAP - DECIMAL . .( bytes) SAMSINI SAMS-ON CR .( SAMS card activated) Note: >< is SWPB. 1 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted August 18, 2020 Author Share Posted August 18, 2020 (edited) 11 hours ago, TheBF said: i will need to apprise myself better of your implementation to be truly useful, but I use HEX 10 as the minimum page just to avoid hitting anything in the lower 64K address space. After that, one can use the initialization routine to detect the last available page in the card and fill in your SAMS flag with that. That is something I did not do yet but with the 4Mbyte cards in existence now I guess I should. I used what @Willsy used in TurboForth, which presumed the presence/absence of precisely 1 MiB SAMS: Default mapping of SAMS pages >00F8 – >00FF to RAM >2000, >3000, >A000, >B000, >C000, >D000, >E000, >F000, respectively. This cannot work with a SAMS card less than 1 MiB because it unconditionally maps the top eight pages of a presumed 1 MiB card! Test for presence of SAMS: Write >994A to >E000. Map SAMS page >0001 to >E000. Compare contents of >E000 to written value of >994A. If values match, no SAMS because mapping did not work. Restore default mapping of SAMS page >00FE to >E000, if SAMS found. Because mapping is done per an early scheme of duplicating the LSB of the SAMS page number to the MSB, any SAMS card greater than 1 MiB will not work correctly. This is because the LSN (Leasty Significant Nybble) of the MSB is now necessary for specifying SAMS pages higher than >00FF (the highest page of 1 MiB SAMS). Your prudent avoidance of the lowest 16 SAMS pages notwithstanding, I do not think I need to be quite so careful because SAMS initialization in fbForth 2.0 occurs in ROM before any support code gets copied to RAM. I am torn between defaulting SAMS pages 0 – 7 to expansion RAM and forcing page number correspondence, viz., page 2 to >2000, page 3 to >3000, page 10 (>A) to >A000, ..., page 15 (>F) to >F000. I am inclined to go with the latter for mnemonic reasons, even though it realistically sacrifices 32 KiB of available SAMS. I am still working on it. ...lee Edited August 18, 2020 by Lee Stewart Correction to antepenultimate sentence, “I am torn,,,” 2 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted August 18, 2020 Share Posted August 18, 2020 49 minutes ago, Lee Stewart said: I used what @Willsy used in TurboForth, which presumed the presence/absence of precisely 1 MiB SAMS: Default mapping of SAMS pages >00F8 – >00FF to RAM >2000, >3000, >A000, >B000, >C000, >D000, >E000, >F000, respectively. This cannot work with a SAMS card less than 1 MiB because it unconditionally maps the top eight pages of a presumed 1 MiB card! Test for presence of SAMS: Write >994A to >E000. Map SAMS page >0001 to >E000. Compare contents of >E000 to written value of >994A. If values match, no SAMS because mapping did not work. Restore default mapping of SAMS page >00FE to >E000, if SAMS found. Because mapping is done per an early scheme of duplicating the LSB of the SAMS page number to the MSB, any SAMS card greater than 1 MiB will not work correctly. This is because the LSN (Leasty Significant Nybble) of the MSB is now necessary for specifying SAMS pages higher than >00FF (the highest page of 1 MiB SAMS). Your prudent avoidance of the lowest 16 SAMS pages notwithstanding, I do not think I need to be quite so careful because SAMS initialization in fbForth 2.0 occurs in ROM before any support code gets copied to RAM. I am torn between defaulting SAMS pages 0 – 8 to expansion RAM and forcing page number correspondence, viz., page 2 to >2000, page 3 to >3000, page 10 (>A) to >A000, ..., page 15 (>F) to >F000. I am inclined to go with the latter for mnemonic reasons, even though it realistically sacrifices 32 KiB of available SAMS. I am still working on it. ...lee I found the overhead for a generalize mapper to be more than I could tolerate. I was trying to make a virtual-memory to real-memory convertor. (although that was not clear to me when I began ) For me I need an application to make sense of it. The possibilities are endless otherwise. I like that test. It's simple. I noticed the duplicate LSB/MSB in the code but then found that it wasn't needed (ie it seemed to work ok without it) so again for speed I didn't do it. What did I lose by not doing the duplicate entry? Yes our systems are quite different in realization with FbForth in ROM. It's more important to get it right with ROM. I am still playing around. 1 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted August 18, 2020 Author Share Posted August 18, 2020 1 hour ago, TheBF said: What did I lose by not doing the duplicate entry? Nothing. I think the folks who hit upon doing it that way in the early days were fumbling around trying to discover how the mapper worked. The important thing is to get the actual page number in the word and then swap bytes before MOVing it to a SAMS register. Even though, before swapping bytes for SAMS ≤1 MiB, the MSB should actually be >00, it does not matter what is there because writing the MSB has no effect, i.e., the mapper is only connected to the low-order 8 address lines. For SAMS > 1 MiB, however, that byte absolutely must have the proper value (>00 – >0F) else all hell breaks loose. In this case, it is the MSN of the MSB that does not matter, e.g., >0345 should, after SWPB, map the same page as >F345 because the mapper is now connected to 4 more address lines (now, the low-order 12} for a maximum of 16 MiB SAMS. ...lee 1 1 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted August 21, 2020 Author Share Posted August 21, 2020 OK. After consulting the SAMS docs I have, Thierry’s site and checking with @Ksarul, the powerup state of the SAMS card has SAMS pages >0002, >0003, >000A – >000F mapped to >2000, >3000, >A000 – >F000, respectively. Because that is the initial mapping I had settled on anyway, I was thinking that is how I would leave it, viz., no startup initialization, but I think I should still initialize SAMS in the startup code because BOOT does not invoke DSR powerup routines, as happens with power cycling, but it does reset the Terminal Input Buffer ( TIB ) and the stack base ( S0 ) to the default >FFA0, which implies a reset of SAMS to default values. COLD , on the other hand, resets most everything except S0 and TIB , so should not reset SAMS. Whether I use code that explicitly repages SAMS defaults or simply turn mapping off and back on depends on what actually happens with the latter two operations. I know, from Thierry’s site, that turning mapping off (SBZ 1) reverts to powerup mappings, but what is the state of affairs when mapping is turned back on (SBO 1)? Is the previously set mapping back in effect or does turning mapping off actually reset the mapper registers? I guess the latter is implied, but I could not find it explicitly stated on Thierry’s site. ...lee 1 Quote Link to comment Share on other sites More sharing options...
HOME AUTOMATION Posted August 21, 2020 Share Posted August 21, 2020 (edited) On 8/18/2020 at 1:42 AM, Lee Stewart said: the mapper is only connected to the low-order 8 address lines. Hmm, by low-order 8 address lines, you mean A0 - A8? On 8/21/2020 at 12:34 AM, Lee Stewart said: Is the previously set mapping back in effect or does turning mapping off actually reset the mapper registers? Only direct manipulation of the registers should cause them to change. Spoiler Edited August 23, 2020 by HOME AUTOMATION Clipped and commented the images, for better clarity. Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted August 21, 2020 Author Share Posted August 21, 2020 7 minutes ago, HOME AUTOMATION said: Hmm, by low-order 8 address lines, you mean A0 - A8? A0 – A7 or however the low-order lines are numbered. TI liked to number data lines backwards—I think address lines were ordered the other way round. The point is that, in a 1 MiB SAMS, any value in the MSB (indicating a page number greater than >00FF) is ignored. Of course, this page number must be written to the mapper register with the bytes swapped, viz., >FF00. ...lee 1 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted August 21, 2020 Share Posted August 21, 2020 9 hours ago, Lee Stewart said: OK. After consulting the SAMS docs I have, Thierry’s site and checking with @Ksarul, the powerup state of the SAMS card has SAMS pages >0002, >0003, >000A – >000F mapped to >2000, >3000, >A000 – >F000, respectively. Because that is the initial mapping I had settled on anyway, I was thinking that is how I would leave it, viz., no startup initialization, but I think I should still initialize SAMS in the startup code because BOOT does not invoke DSR powerup routines, as happens with power cycling, but it does reset the Terminal Input Buffer ( TIB ) and the stack base ( S0 ) to the default >FFA0, which implies a reset of SAMS to default values. COLD , on the other hand, resets most everything except S0 and TIB , so should not reset SAMS. Whether I use code that explicitly repages SAMS defaults or simply turn mapping off and back on depends on what actually happens with the latter two operations. I know, from Thierry’s site, that turning mapping off (SBZ 1) reverts to powerup mappings, but what is the state of affairs when mapping is turned back on (SBO 1)? Is the previously set mapping back in effect or does turning mapping off actually reset the mapper registers? I guess the latter is implied, but I could not find it explicitly stated on Thierry’s site. ...lee It gets a little cloudy to me who has responsibility for what in a little system like TI-99. Are we assuming power-up status or returning from another program to main menu etc.? That being said I should think any APP that is going to use the card should set it up as it requires and assume nothing. So if FbForth is going to wakeup with SAMS in play it has to do it. If my FbForth APP is going to use SAMS then I could simply load a block that sets up everything at compile time. That block could be part of the library provided by FbForth. After I figured out how to turn the card on etc. I just used some Forth words to fill it and viewed results on the classic99 debugger in >2000... >3FFF RAM. That way I could see what happens with the mapper on or off. Everything just switches back to what it was before with with SBO 1/SBZ 1 I think if you make 'R12 a constant for your R12 you can run my Forth version with a few word changes to the simple code words. You could compile it and explore. That's what I love about Forth and hardware interfaces. 3 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted August 29, 2020 Author Share Posted August 29, 2020 Woohoo! I now have converted to @ralphb’s xas99 Cross-Assembler for building fbForth 2.0. I have code working with 128 KiB – 16 MiB SAMS. There are still a few patches I need to implement to get the Assembler to work properly for me—two in the Assembler and one in the code. There are a few things I want to change before I release the next build. Hopefully, I will have enough room in ROM. Room is pretty scarce, so it may not be possible without some optimizing—we’ll see. ...lee 3 2 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted September 3, 2020 Author Share Posted September 3, 2020 As indicated in my last post, I have finally moved from Cory Burr’s asm994a Assembler over to Ralph Benzinger’s (@ralphb’s) Python-based Assembler (see xdt99: New TI 99 cross-development tools available) for fbForth 2.0 builds, starting with fbForth 2.0:13. My journey to assembly success is detailed in the xdt99 thread starting with post#336. Build 13 will include: Elimination of the trailing terminator bit in Name Fields of Forth words, which will include modification of all code that uses it: TRAVERSE NFA PFA -FIND (FIND) ID. CREATE <BUILDS .... (See, especially, post#440 for a detailed discussion of my reasoning.) Use of SAMS cards with capacities from 128 KiB to 32 MiB. 32 MiB is currently only available in Classic99, with a current, real-iron maximum of 16 MiB. If there is enough ROM space: Improvements to COINC COINCXY COINCALL SPRDIST SPRDISTXY DSRLNK improvements. ...lee 5 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted September 4, 2020 Author Share Posted September 4, 2020 Knocked most of the way through the first bullet. I have CREATE to change—then <BUILDS and VLIST to check for any necessary modifications. All the code changes except ID. netted only 16 additional bytes. ID. went down 74 bytes!! ...lee 2 1 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted September 5, 2020 Share Posted September 5, 2020 "It's such a good feeling..." ? (Fred Rogers) 1 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted September 5, 2020 Author Share Posted September 5, 2020 CREATE is done. <BUILDS and VLIST are fine without change. Below is the current boot screen in Classic99. Note the “SAMS:” entry on the right side of the eighth line. ...lee 6 1 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted September 6, 2020 Author Share Posted September 6, 2020 (edited) I am not sure there is much I can do to improve the following code for COINC COINCXY COINCALL SPRDIST SPRDISTXY except for removing the JMP between _COIN and _COINC: Spoiler ; BLF2A (routine in low RAM) BL from Forth in Bank 0 to ALC body in another bank ; RTNEXT (routine in low RAM) return to bank 0 and the Forth inner interpreter * * Bank codes for BLF2A routine * BANK0 EQU >C000 BANK1 EQU >8000 BANK2 EQU >4000 BANK3 EQU >0000 * * Register names specific to Inner Interpreter * U EQU 8 <--points to base of User Variable area SP EQU 9 <--Parameter Stack Pointer W EQU 10 <--Inner Interpreter current Word Pointer LINK EQU 11 <--LINKage for subroutines in CODE routines CRU EQU 12 <--Used for CRU instructions IP EQU 13 <--Interpretive Pointer R EQU 14 <--Return Stack Pointer NEXT EQU 15 <--Points to the NEXT instruction fetch routine ; $SATR is the index into the User Variable area where the address of Sprite ; Atribute Table in VRAM is stored. ;[*-- _SPLOC --- popping sprite# to get SATR location of sprite data routine *** *++ Call: BL @_SPLOC *++ Registers: R0 _SPLOC MOV *SP+,R0 ; pop sprite # SLA R0,2 ; multiply by 4 A @$SATR(U),R0 ; get SATR VRAM address of this sprite's data RT ; return to caller ;]* *++ body of SPRGET routine to allow call by other routines in this bank __SPGT LIMI 0 ; disable interrupts because VSBR doesn't BLWP @VSBR ; read sprite dy-1 to R1 SRL R1,8 ; move to right byte, clearing left byte INC R1 ; increment dy AI SP,-4 ; reserve 2 spots on stack MOV R1,*SP ; put dy on top INC R0 ; point to dx BLWP @VSBR ; read sprite dx to R1 SRL R1,8 ; move to right byte, clearing left byte MOV R1,@2(SP) ; put dx under dy RT ; return to caller without re-enabling interrupts ;[*** DXY *** ( x1 y1 x2 y2 --- x^2 y^2 ) * DATA SPGT_N * DXY__N: * .name_field 3, 'DXY' * DXY DATA $+2 * BL @BLF2A * DATA _DXY->6000+BANK1 _DXY BL @__DXY ; branch to body of this routine B @RTNEXT ; back to bank 0 and the inner interpreter *++ body of DXY routine to allow call by other routines in this bank __DXY MOV *SP+,R0 ; pop y2 MOV @2(SP),R1 ; get y1 S R1,R0 ; y2 - y1 * ABS R0 ; |y2-y1| MPY R0,R0 ; |y2-y1|^2 MOV *SP+,R2 ; pop x2 MOV @2(SP),R3 ; get x1 S R3,R2 ; x2 - x1 * ABS R2 ; |x2-x1| MPY R2,R2 ; |x2-x1|^2 MOV R3,@2(SP) ; |x2-x1|^2 just below top of stack MOV R1,*SP ; |y2-y1|^2 to top of stack RT ; return to caller ;] ;[*** SPRDIST *** ( spr#1 spr#2 --- dist^2 | 7FFFh ) * DATA HONK_N * SDST_N: * .name_field 7, 'SPRDIST' * SPRDST DATA $+2 * BL @BLF2A * DATA _SDST->6000+BANK1 _SDST BL @__SDST ; branch to body of this routine B @RTNEXT ; back to bank 0 and the inner interpreter *++ body of SPRDIST routine to allow call by other routines in this bank __SDST MOV LINK,R7 ; save return BL @_SPLOC ; get vaddr2 in R0 MOV R0,R5 ; save to R5 BL @_SPLOC ; get vaddr1 *++ __SPGT disables interrupts for rest of this routine BL @__SPGT ; get dx1, dy1 to stack MOV R5,R0 ; now for vaddr2 *++ from here on, same as SPRDISTXY *++ __SPGT disables interrupts for rest of this routine SDXYEN BL @__SPGT ; get dx2, dy2 to stack BL @__DXY ; pop dx1, dx2, dy1, dy2 and get dx^2, dy^2 to stack MOV *SP,R3 ; get dy^2 ANDI R3,>8000 ; highest bit = 1? JEQ SDST03 ; no SDST01 INCT SP ; yes, reduce stack SDST02 LI R0,>7FFF ; load highest positive integer JMP SDSTEX ; we're outta here! SDST03 MOV @2(SP),R3 ; get dx^2 ANDI R3,>8000 ; highest bit = 1? JEQ SDST04 ; no, add them JMP SDST01 ; yes, finish up with >7FFF SDST04 MOV *SP+,R3 ; pop dy^2 A *SP,R3 ; add dx^2 to dy^2 MOV R3,R0 ; get ready to put result on stack ANDI R3,>8000 ; highest bit = 1? JNE SDST02 ; yes, finish up with >7FFF SDSTEX MOV R0,*SP ; result to stack B *R7 ; return to caller ;] ;[*** SPRDISTXY *** ( dx dy spr# --- dist^2|7FFFh ) * DATA SDST_N * SDXY_N: * .name_field 9, 'SPRDISTXY' * SPDXY DATA $+2 * BL @BLF2A * DATA _SDXY->6000+BANK1 _SDXY BL @__SDXY ; branch to body of this routine B @RTNEXT ; back to bank 0 and the inner interpreter *++ body of SPRDISTXY routine to allow call by other routines in this bank __SDXY MOV LINK,R7 ; save return BL @_SPLOC ; get vaddr in R0 JMP SDXYEN ; jump into SPRDIST routine to finish ;] ;[*** COINC *** ( spr#1 spr#2 tol --- f ) ( 0= no coinc -1= coinc ) * DATA JOY__N * COIN_N: * .name_field 5, 'COINC' * COINC DATA $+2 * BL @BLF2A * DATA _COIN->6000+BANK1 _COIN LI R7,__SDST ; we'll be executing SPRDIST from _COINC JMP _COINC ; jump to coincidence routine ; We can eliminate above JMP to let this fall through to next instruction ; as long as we avoid inserting any instructions here! ;] ;[*-- _COINC --- coincidence routine *** _COINC MOV *SP+,R5 ; pop tol MPY R5,R5 ; square it A R6,R6 ; double it (2*tol^2) BL *R7 ; get dist^2 from SPRDIST or SPRDISTXY S *SP,R6 ; 2*tol^2 - dist^2 JGT COIN01 ; coincidence? CLR *SP ; nope, return 0 JMP COINEX ; we're outta here COIN01 SETO *SP ; yup, return -1 COINEX B @RTNEXT ; back to bank 0 and the inner interpreter ;] ;[*** COINCXY *** ( dx dy spr# tol --- f ) * DATA COIN_N * COXY_N: * .name_field 7, 'COINCXY' * COINXY DATA $+2 * BL @BLF2A * DATA _COXY->6000+BANK1 _COXY LI R7,__SDXY ; we'll be executing SPRDISTXY from _COINC JMP _COINC ; jump to coincidence routine ;] ;[*** COINCALL *** ( --- f ) ( bit set if any two sprites overlap ) * DATA COXY_N * CNCL_N: * .name_field 8, 'COINCALL ' * CNCALL DATA $+2 * BL @BLF2A * DATA _CNCL->6000+BANK1 _CNCL DECT SP ; reserve stack space MOVB @>837B,R0 ; copy VDP status byte to R0 ANDI R0,>2000 ; check coincidence bit JNE CNCL01 ; coincidence bit set? CLR *SP ; no, clear flag JMP CNCLEX ; we're outta here CNCL01 SETO *SP ; yes; set flag to -1 CNCLEX B @RTNEXT ; back to bank 0 and the inner interpreter ;] As you can see in the above code, I am already extensively reusing code. I will look to see whether the code itself can be improved. Feel free to look over my shoulder. ? [EDIT: Please note that I added the code for DXY to the above spoiler. I had forgotten it—sorry.] ...lee Edited September 6, 2020 by Lee Stewart code addition 1 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted September 6, 2020 Share Posted September 6, 2020 The only thing you might consider is writing these in CODE. I kept DIST for computing actual distance but I felt it was too much overhead for coincidence since it's all just sitting there in VDP RAM to read and compare. I think these could be really fast using registers versus the stack juggling in the Forth version. Notice that I purposely have code duplication in COINC rather than calling COINCXY. This is just for a bit of extra speed. CODE overhead with BL would be low enough to allow calling COINCXY IMHO. : COINCXY ( dx dy sp# tol -- ? ) >R SP.Y V@ SPLIT ( -- col row col row ) ROT - ABS R@ < -ROT - ABS R> < AND ; : COINC ( spr#1 spr#2 tol -- ?) \ 1.4 mS, 1.1 mS optimized >R SP.Y V@ SPLIT ROT SP.Y V@ SPLIT ( -- col row col row) ROT - ABS R@ < -ROT - ABS R> < AND ; Just my 2 cents on the matter. 1 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted September 6, 2020 Author Share Posted September 6, 2020 1 hour ago, TheBF said: The only thing you might consider is writing these in CODE. I kept DIST for computing actual distance but I felt it was too much overhead for coincidence since it's all just sitting there in VDP RAM to read and compare. Well, all of my code in my previous post is CODE, that is, it is pure ALC and the reuse is both via JMP and BL. I could not use JMP everywhere because of the need to return to some routines. I just need to take another look to see if there is any chance of paring it down. ...lee Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted September 6, 2020 Author Share Posted September 6, 2020 I just added DXY to the code in post #1569. I had forgotten it is referenced. ...lee 1 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted September 6, 2020 Share Posted September 6, 2020 I am thinking that even in code the extra cycles required to compute distance to determine coincidence if pretty slow compared to subtracting the actual coordinates and comparing each difference to a tolerance value. I have not got around to converting my Forth words to code but with a few temp registers it should be pretty efficient. Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted September 7, 2020 Author Share Posted September 7, 2020 35 minutes ago, TheBF said: I am thinking that even in code the extra cycles required to compute distance to determine coincidence if pretty slow compared to subtracting the actual coordinates and comparing each difference to a tolerance value. Now, you are starting the wheels turning. For a tolerance of 1 or 2 pixels, differences work, but fail at 3 when both differences are 3. Perhaps a small table? Or? ...lee Quote Link to comment Share on other sites More sharing options...
+TheBF Posted September 7, 2020 Share Posted September 7, 2020 The Forth code I posted is used with a tolerance of 8 typically and it seems to work great even in Forth. 1 Quote Link to comment 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.