intvnut Posted July 31, 2016 Share Posted July 31, 2016 (edited) Speaking of multiplication bugs.. I thought I had this logic worked out months ago, but clearly I've never really tested it. I'd love it if someone else could try this code, and see if I'm crazy (I'm kinda hoping maybe I have a corrupt prologue or epilogue or something): GOSUB print_test loop: goto loop print_test: PROCEDURE num_1 = 35 num_2 = 85 num_1_tens=num_1/10 num_1_ones=num_1-num_1_tens*10 'print at 0,<3>num_1_tens 'print at 20,<3>num_1_ones num_2_tens=num_2/10 num_2_ones=num_2-num_2_tens*10 print at 120,<3>num_2_tens print at 140,<3>num_2_ones END What we SHOULD see is 8, followed by 5. What *I* see is 030, followed by 041. The math should work, and I can verify it two ways: 1. Uncomment one or both of the other PRINT statements 2. Change the first multiplication to num_1_ones=num_1-num_1_tens*8 Do either of those things, and the calculation that matters magically works as expected. I can understand maybe how the *8 fixes things if we have some kind of deep-seated bug with multiplication by 10, but how the PRINT does it is a little beyond me. Interestingly the division by 10 is not the problem. But it's like there's some kind of 'memory' of the previous *10 - maybe a register that goes wonky? (And before anyone points it out, I'm aware that IntyBASIC has built in routines to print numbers without breaking them out like this. I have a reason for my madness) Edit: well, I have a workaround, Every time I call anything with *10, I jump to this and it fixes whatever the problem is: cleanup_print_hack: PROCEDURE PRINT AT 220,<1>num_1_tens PRINT AT 220,$603 END As I have a blank card at that position, I can get away with it. And this is only hitting me on static screens, so it's acceptable. Still... seems like a nasty bug. Hopefully my "fix" gives a clue as to what's going on under the covers. I just cut and pasted your example into a file, compiled it and ran it with a stock IntyBASIC 1.2.5. I see this: That looks right to me. Interestingly, it looks broken if I turn on --jlp, though. (Reporting how you invoke the tools is important!) The issue appears to be the divide: . ;[17] num_2_tens=num_2/10 SRCFILE "/tmp/fw.bas",17 MVI V2,R0 MVII #10,R4 MVO R0,40842 MVO R4,40843 MOVR R1,R0 NOP MVO R0,V5 . I don't see where it's reading in the result of the division. There's that weird NOP there though. At this point in the generated code, R1 holds the previous result of num_1_tens*10. I suspect IntyBASIC is doing some value tracking of some sort, saying "Hey, I know R1 holds the last value read from location 40846, so I don't need to re-load it!" The JLP accelerators, though, change the values in memory out from under it. If that's what's going on, there's your bug. The reason it doesn't happen more places likely has to do with the order IntyBASIC picks registers. Most of the time, stuff read from the accelerators will end up in R0. But, since you're subtracting the accelerator's result from something else, the tree walker ends up putting it in R1. And since R1 doesn't get clobbered by anything else between these two expressions, it looks like the most likely cause to me. Here's a bigger piece of the assembly, showing the connection: . ;[12] num_1_ones=num_1-num_1_tens*10 SRCFILE "/tmp/fw.bas",12 MVI V1,R0 MVI V3,R1 MVII #10,R4 MVO R1,40838 MVO R4,40839 MVI 40846,R1 ; <<<< loads the accelerator result into R1 SUBR R1,R0 MVO R0,V4 ;[13] SRCFILE "/tmp/fw.bas",13 ;[14] 'print at 0,<3>num_1_tens SRCFILE "/tmp/fw.bas",14 ;[15] 'print at 20,<3>num_1_ones SRCFILE "/tmp/fw.bas",15 ;[16] SRCFILE "/tmp/fw.bas",16 ;[17] num_2_tens=num_2/10 SRCFILE "/tmp/fw.bas",17 MVI V2,R0 MVII #10,R4 MVO R0,40842 MVO R4,40843 MOVR R1,R0 ; <<<< incorrectly reuses the accelerator result from above NOP ; <<<< unnecessary NOP MVO R0,V5 . On the topic of multiply bugs, there were some bugs at one time in my multiply macros, and those bugs survived through dZ's tweak of them and on into IntyBASIC, where nanochess then fixed (some of? all of?) them manually as I understand it. I'm pretty certain *10 was heavily tested, given the number of games that print scores in decimal. FWIW, I believe I fixed the error in my "mult_by_constant" generator. If folks are inclined to play with it, have a look. All the tests above, though, were run with stock IntyBASIC 1.2.5, irrespective of my tweaked multiply generator. updated_multiplies.zip Edited July 31, 2016 by intvnut Quote Link to comment Share on other sites More sharing options...
freewheel Posted July 31, 2016 Share Posted July 31, 2016 Oh wow, thanks man. I suspected it had to be something unusual - and now I understand. I KNEW I tested this code at some point. JLP would be a relatively recent addition (months ago, but time flies). I had snooped a bit on the registers but I won't lie, I get lost quickly enough doing that. The one thing I now realize that I *didn't* try, was to put the mult into a temporary variable and then do the subtraction. That magically fixes things, for obvious reasons. Interestingly I only have to do this on the first value and it fixes both of them. Probably a better workaround than my PRINT hack. Excellent sleuthing! Quote Link to comment Share on other sites More sharing options...
+nanochess Posted July 31, 2016 Author Share Posted July 31, 2016 And big oopsie for me! I'll correct this Thanks intvnut and freewheel! 1 Quote Link to comment Share on other sites More sharing options...
+nanochess Posted August 1, 2016 Author Share Posted August 1, 2016 Just updated IntyBASIC to v1.2.6, a bug fix version the only new feature is DATA VARPTR. Check first post! 6 Quote Link to comment Share on other sites More sharing options...
intvnut Posted August 1, 2016 Share Posted August 1, 2016 Just updated IntyBASIC to v1.2.6, a bug fix version the only new feature is DATA VARPTR. Out of curiosity, was the bug what I thought it was? I admit I didn't look at the source. Quote Link to comment Share on other sites More sharing options...
+nanochess Posted August 1, 2016 Author Share Posted August 1, 2016 Out of curiosity, was the bug what I thought it was? I admit I didn't look at the source. Exactly what you thought man, you're reading my buggy mind 1 Quote Link to comment Share on other sites More sharing options...
artrag Posted August 1, 2016 Share Posted August 1, 2016 (edited) I will update the voice player asap! Thanks a lot! DATA VARPTR will simplify a lot the current code. Thanks! Edited August 1, 2016 by artrag 1 Quote Link to comment Share on other sites More sharing options...
freewheel Posted August 2, 2016 Share Posted August 2, 2016 Bigtime cheers, nanochess. I don't mind putting in the odd workaround (in fact sometimes I'm a bit proud when I come up with a clever one) but I'd much rather just have the production code done right. This will take another one off my issue list Only 50 or so to go... sigh. (Problems for me, not bugs!) 1 Quote Link to comment Share on other sites More sharing options...
freewheel Posted August 6, 2016 Share Posted August 6, 2016 Bloody hell, guys, I swear this was JUST discussed recently but I can't for the life of me find it... How can we detect if an ECS is plugged in, in IntyBASIC? I seem to recall POKEing or PEEKing something, but I just can't find it. Also, consider this an IntyBASIC feature request, like the NTSC check Quote Link to comment Share on other sites More sharing options...
+Tarzilla Posted August 6, 2016 Share Posted August 6, 2016 Bloody hell, guys, I swear this was JUST discussed recently but I can't for the life of me find it... How can we detect if an ECS is plugged in, in IntyBASIC? I seem to recall POKEing or PEEKing something, but I just can't find it. Also, consider this an IntyBASIC feature request, like the NTSC check I recall it was discussed but couldn't find it here either. I do have this saved in my notes https://groups.yahoo.com/neo/groups/intvprog/conversations/topics/7731 Quote Link to comment Share on other sites More sharing options...
intvnut Posted August 6, 2016 Share Posted August 6, 2016 Bloody hell, guys, I swear this was JUST discussed recently but I can't for the life of me find it... How can we detect if an ECS is plugged in, in IntyBASIC? I seem to recall POKEing or PEEKing something, but I just can't find it. Also, consider this an IntyBASIC feature request, like the NTSC check Well, you could check for the ECS EXEC to be present ($2000 - $2FFF, $7000 - $7FFF, $E000 - $EFFF), or the second PSG ($F0 - $FF), or the UART ($E0 - $E2), or the extra 8-it RAM ($4000 - $47FF). If you're only using the ECS for the PSG, I'd recommend just checking for that. The ROMs can be page-flipped out (and will need to be page-flipped out for large games), and—blush—jzIntv doesn't implement the UART. To test for the second PSG, you'll need to write and read one of its registers. e.g. tmp = PEEK($F0) : POKE $F0, tmp + 1 : IF PEEK($F0) = tmp THEN .... The reason for needing both a write and a read is that the Intellivoice also responds on the same range of addresses for its expansion bus. (Yes, there's a buffer fight here, and the Intellivoice is actually designed to tolerate it. It fights with the other PSG too, to allow the planned wireless hand controllers to work.) Alternately, POKE/PEEK some locations in the ECS 8-bit RAM at $4000 - $47FF. Hopefully, IntyBASIC doesn't use the addresses that also alias the STIC ($4000 - $403F), so those won't have any variables allocated to them. Options, options, options. :-) Quote Link to comment Share on other sites More sharing options...
freewheel Posted August 6, 2016 Share Posted August 6, 2016 I started with the 8-bit RAM check from the Yahoo discussion, had no luck. So I figured I'd give the PSG idea a go. The idea being that if we can write to $F0, and the result returns the same, that we have an ECS? So, I think you made a typo - correct me if I'm wrong. The comparison should be IF PEEK($F0) = tmp+1, no? That seems to work for me. Also, I notice that the first read returns different values depending on if I have the ECS attached or not, but I assume that's not sufficient. I can confirm that IntyBASIC entirely avoids $3000-$47FF, so we're good on that front. I have it marked as a no-fly zone in my own notes so I don't accidentally map ROM anywhere in there. Quote Link to comment Share on other sites More sharing options...
intvnut Posted August 6, 2016 Share Posted August 6, 2016 I started with the 8-bit RAM check from the Yahoo discussion, had no luck. So I figured I'd give the PSG idea a go. The idea being that if we can write to $F0, and the result returns the same, that we have an ECS? Hmmm, I wonder why it didn't work. You should be able to change a value and read it back, just as with the PSG. So, I think you made a typo - correct me if I'm wrong. The comparison should be IF PEEK($F0) = tmp+1, no? That seems to work for me. Also, I notice that the first read returns different values depending on if I have the ECS attached or not, but I assume that's not sufficient. It's not a typo actually. You just need to be able to discriminate between "did I change the value, or not?" Either test would suffice, and one of them is likely to be cheaper than the other, either in size or speed. (Size probably matters more if it's a "once at the start of time" type of test.) I can confirm that IntyBASIC entirely avoids $3000-$47FF, so we're good on that front. I have it marked as a no-fly zone in my own notes so I don't accidentally map ROM anywhere in there. OK, I didn't know if IntyBASIC had a flag that would allocate 8-bit variables in the ECS's 2K RAM. Quote Link to comment Share on other sites More sharing options...
+DZ-Jay Posted August 6, 2016 Share Posted August 6, 2016 (edited) This is the code I use in P-Machinery to detect the ECS. It is based on code provided by Joe Z. and Arnauld Chevallier. I believe I have tested it on the real hardware in the past and it works. ;; ======================================================================== ;; ;; .BOOT.REQ_ECS ;; ;; Check if the ECS is present and fail boot sequence if not. ;; ;; ;; ;; Detection is performed by writing a word to ECS 8-bit RAM and reading a ;; ;; byte back, twice. If the process succeeds, we can assume the ECS unit ;; ;; is present. :: ;; ;; ;; INPUT for .BOOT.REQ_ECS ;; ;; R5 Pointer to return address. ;; ;; ;; ;; OUTPUT ;; ;; None. ;; ;; ======================================================================== ;; .BOOT.ECS_CHECK PROC _b.ecs_byte QEQU MEMMAP.EcsRam8bit ; Chosen arbitrarily (any address in ECS RAM will do) ; -------------------------------------- ; Attempt to detect ECS ; -------------------------------------- MVII #_b.ecs_byte, R1 ; \_ Pick an ECS RAM address and read what's there MVI@ R1, R0 ; / COMR R0 ; \_ Complement it, including upper byte, MVO@ R0, R1 ; / and store it back. XOR@ R1, R0 ; XOR the stored value with original inverted one CMPI #PM.MSB_MASK, R0 ; Make sure only the lower-byte is cancelled BNEQ .BOOT.ECS_FAIL ; No? halt boot sequence with an error message JR R5 ; Yes? continue with main program ENDP I guess in IntyBASIC you could do that with PEEK and POKE: TMP = PEEK($4040) XOR $FFFF POKE $4040, TMP IF ((PEEK($4040) XOR TMP) = $FF) THEN ' Succes ELSE ' Failure END IF Or something like that...? Edited August 6, 2016 by DZ-Jay 1 Quote Link to comment Share on other sites More sharing options...
GroovyBee Posted August 6, 2016 Share Posted August 6, 2016 Started a new thread on ECS detection here. Quote Link to comment Share on other sites More sharing options...
freewheel Posted August 6, 2016 Share Posted August 6, 2016 It's not a typo actually. You just need to be able to discriminate between "did I change the value, or not?" Either test would suffice, and one of them is likely to be cheaper than the other, either in size or speed. (Size probably matters more if it's a "once at the start of time" type of test.) Oh. Just to be clear, your IF..THEN is implied to be NOT ECS in your example (ie: you couldn't change the value). Ya know, I swear I tried this last night and could never get it to work. I flipped it to comparing to tmp+1 and things worked, so I assumed my peabrain wasn't following something. Of course, I try it again this morning, and yeah - I can make either way work. No idea why I couldn't get the 8-bit RAM check working, but probably for a similar reason. Thanks! You got me moved on last night at any rate. Quote Link to comment Share on other sites More sharing options...
intvnut Posted August 6, 2016 Share Posted August 6, 2016 Oh. Just to be clear, your IF..THEN is implied to be NOT ECS in your example (ie: you couldn't change the value). Yep, I had written it "in the negative." I suppose I could have said "<> tmp" and that would have worked as well. Quote Link to comment Share on other sites More sharing options...
+nanochess Posted September 9, 2016 Author Share Posted September 9, 2016 I've been using IntyBASIC to develop Sydney Hunter & the Sacred Tribe, corrected some bugs in compiler and just updated it to v1.2.7 (check first post) Allows to concatenate lines using the character \ at the end of a line. (suggested by GroovyBee) Now optimizes access to arrays when using same index even if different array or offset. (double speed in common cases!!! intvnut suggested it a long of time ago) Solved bug where DEFINE VARPTR swallowed one extra lexical component. Solved bug where 1024-x*x generated wrong code. Solved bug where PRINT "string" as first statement would write in non-screen memory. Minor edit in manual (definition of BORDER) 7 Quote Link to comment Share on other sites More sharing options...
+nanochess Posted September 11, 2016 Author Share Posted September 11, 2016 Just as a side note, when using this new version of IntyBASIC, don't forget to copy the intybasic_prologue.asm and intybasic_epilogue.asm files, as these have suffered small changes. 1 Quote Link to comment Share on other sites More sharing options...
First Spear Posted September 12, 2016 Share Posted September 12, 2016 That looks great! Can you show an example of an array access pattern hat shows the speed improvement? Thanks sir! I've been using IntyBASIC to develop Sydney Hunter & the Sacred Tribe, corrected some bugs in compiler and just updated it to v1.2.7 (check first post) Allows to concatenate lines using the character \ at the end of a line. (suggested by GroovyBee) Now optimizes access to arrays when using same index even if different array or offset. (double speed in common cases!!! intvnut suggested it a long of time ago) Solved bug where DEFINE VARPTR swallowed one extra lexical component. Solved bug where 1024-x*x generated wrong code. Solved bug where PRINT "string" as first statement would write in non-screen memory. Minor edit in manual (definition of BORDER) Quote Link to comment Share on other sites More sharing options...
+nanochess Posted September 14, 2016 Author Share Posted September 14, 2016 For this test code: DIM array(10) DIM array2(20) array(4) = array(3) array(4+a) = array(3+a) array(a+4) = array(a+3) array(a+5) = array(a) array2(a) = array(a) array2(4+a) = array(4+a) array2(2+a) = array(4+a) array2(4+a) = array(2+a) The newest version of the compiler generates this code: (note the pattern saving array pointer in r3) ;FILE test39.bas ;[1] DIM array(10) ;[2] DIM array2(20) ;[3] ;[4] array(4) = array(3) MVI Q3+3,R0 MVO R0,Q3+4 ;[5] array(4+a) = array(3+a) MVII #Q3+3,R3 ADD V1,R3 MVI@ R3,R0 INCR R3 MVO@ R0,R3 ;[6] array(a+4) = array(a+3) DECR R3 MVI@ R3,R0 INCR R3 MVO@ R0,R3 ;[7] array(a+5) = array(a) SUBI #4,R3 MVI@ R3,R0 ADDI #5,R3 MVO@ R0,R3 ;[8] ;[9] array2(a) = array(a) SUBI #5,R3 MVI@ R3,R0 ADDI #Q4-Q3,R3 MVO@ R0,R3 ;[10] array2(4+a) = array(4+a) ADDI #Q3-Q4+4,R3 MVI@ R3,R0 ADDI #Q4-Q3,R3 MVO@ R0,R3 ;[11] array2(2+a) = array(4+a) ADDI #Q3-Q4,R3 MVI@ R3,R0 ADDI #Q4-Q3-2,R3 MVO@ R0,R3 ;[12] array2(4+a) = array(2+a) ADDI #Q3-Q4,R3 MVI@ R3,R0 ADDI #Q4-Q3+2,R3 MVO@ R0,R3 While the oldest version generates this code: ;[1] DIM array(10) ;[2] DIM array2(20) ;[3] ;[4] array(4) = array(3) MVI Q2+3,R0 MVO R0,Q2+4 ;[5] array(4+a) = array(3+a) MVII #Q2,R1 MVII #3,R2 ADD V1,R2 ADDR R2,R1 MVI@ R1,R0 MVII #Q2,R1 MVII #4,R2 ADD V1,R2 ADDR R2,R1 MVO@ R0,R1 ;[6] array(a+4) = array(a+3) MVII #Q2+3,R3 ADD V1,R3 MVI@ R3,R0 MVII #Q2+4,R3 ADD V1,R3 MVO@ R0,R3 ;[7] array(a+5) = array(a) MVII #Q2,R3 ADD V1,R3 MVI@ R3,R0 MVII #Q2+5,R3 ADD V1,R3 MVO@ R0,R3 ;[8] ;[9] array2(a) = array(a) MVII #Q2,R3 ADD V1,R3 MVI@ R3,R0 MVII #Q3,R3 ADD V1,R3 MVO@ R0,R3 ;[10] array2(4+a) = array(4+a) MVII #Q2,R1 MVII #4,R2 ADD V1,R2 ADDR R2,R1 MVI@ R1,R0 MVII #Q3,R1 MVII #4,R2 ADD V1,R2 ADDR R2,R1 MVO@ R0,R1 ;[11] array2(2+a) = array(4+a) MVII #Q2,R1 MVII #4,R2 ADD V1,R2 ADDR R2,R1 MVI@ R1,R0 MVII #Q3,R1 MVII #2,R2 ADD V1,R2 ADDR R2,R1 MVO@ R0,R1 ;[12] array2(4+a) = array(2+a) MVII #Q2,R1 MVII #2,R2 ADD V1,R2 ADDR R2,R1 MVI@ R1,R0 MVII #Q3,R1 MVII #4,R2 ADD V1,R2 ADDR R2,R1 MVO@ R0,R1 This improves code in any point where arrays are used as most of time the same index is used again and again, this happens to be the most common case. 1 Quote Link to comment Share on other sites More sharing options...
intvnut Posted September 14, 2016 Share Posted September 14, 2016 The newest version of the compiler generates this code: (note the pattern saving array pointer in r3) ...snip... ;[5] array(4+a) = array(3+a) MVII #Q3+3,R3 ADD V1,R3 MVI@ R3,R0 INCR R3 MVO@ R0,R3 ;[6] array(a+4) = array(a+3) DECR R3 MVI@ R3,R0 INCR R3 MVO@ R0,R3 ...snip...While the oldest version generates this code: ...snip... ;[5] array(4+a) = array(3+a) MVII #Q2,R1 MVII #3,R2 ADD V1,R2 ADDR R2,R1 MVI@ R1,R0 MVII #Q2,R1 MVII #4,R2 ADD V1,R2 ADDR R2,R1 MVO@ R0,R1 ;[6] array(a+4) = array(a+3) MVII #Q2+3,R3 ADD V1,R3 MVI@ R3,R0 MVII #Q2+4,R3 ADD V1,R3 MVO@ R0,R3 ...snip...This improves code in any point where arrays are used as most of time the same index is used again and again, this happens to be the most common case. Trimmed down the example in the quote... That is a marked improvement! Impressive! 1 Quote Link to comment Share on other sites More sharing options...
Kiwi Posted September 24, 2016 Share Posted September 24, 2016 (edited) Just a very quick question. How do you use the RANDOM function to force IntyBASIC to invoke a new random number on a frame? Do you use it by doing, enemydir=RANDOM/32 or do it as for i=0 to 3 RANDOM enemydir(i)=RAND/32 next i Both of these don't work. Got it, RANDOM(range) Means: RANDOM 8 to get number 0-7 Question aborted. *pulls lever* Edited September 24, 2016 by Kiwi Quote Link to comment Share on other sites More sharing options...
+nanochess Posted October 6, 2016 Author Share Posted October 6, 2016 Ok. No questions in a while. So now we are all pros? Quote Link to comment Share on other sites More sharing options...
+Tarzilla Posted October 6, 2016 Share Posted October 6, 2016 Ok. No questions in a while. So now we are all pros? depends on what "pro" is short for I know a couple of us are so busy actually finishing up creations for PRGE with your wonderful compiler, we don't have time to ask questions 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.