freewheel Posted April 29, 2016 Share Posted April 29, 2016 Your choices are : Juggle, juggle, juggle Optimise what you've done so far so its takes less space. Consider moving to a bank switched game. If you want to optimise first, then post some code and then we can see if can be done in a more efficient way (if you're out of ideas on that). Well, I doubt I'll be able to optimize 25K words down into the 8K "standard" I can use without dealing with memory allocation manually I should be able to manage this, I mostly just wanted confirmation that I'm understanding things here. Quote Link to comment Share on other sites More sharing options...
freewheel Posted April 30, 2016 Share Posted April 30, 2016 And another - when you invoke the JLP logic in IntyBASIC, as1600 pukes out a bunch of warnings in the .lst file: WARNING - forward reference to SET/EQU symbol This warning is mixed in with the JLP handling code 12 times. Is this something to be concerned about? I can't remember if it was mentioned when support was first added... Quote Link to comment Share on other sites More sharing options...
+DZ-Jay Posted April 30, 2016 Share Posted April 30, 2016 (edited) And another - when you invoke the JLP logic in IntyBASIC, as1600 pukes out a bunch of warnings in the .lst file: WARNING - forward reference to SET/EQU symbol This warning is mixed in with the JLP handling code 12 times. Is this something to be concerned about? I can't remember if it was mentioned when support was first added... Not really something to be concerned about, since the assembler will resolve the references on a second pass. However, it's an indicator that a "best practice" was violated. It may be a concern if the value is defined with "SET," since the value may change across the program code, and it is not clear which value applies to the one referenced. It certainly is annoying. I avoid this in Assembly Language by either (ab)using "ORG" instead of EQU, by making sure that the definition is done prior to its use, or by using "stubs" and then going back and "patching" in-line the actual value at the end. -dZ. Edited April 30, 2016 by DZ-Jay Quote Link to comment Share on other sites More sharing options...
intvnut Posted April 30, 2016 Share Posted April 30, 2016 Not really something to be concerned about, since the assembler will resolve the references on a second pass. However, it's an indicator that a "best practice" was violated. It may be a concern if the value is defined with "SET," since the value may change across the program code, and it is not clear which value applies to the one referenced. It certainly is annoying. I avoid this in Assembly Language by either (ab)using "ORG" instead of EQU, by making sure that the definition is done prior to its use, or by using "stubs" and then going back and "patching" in-line the actual value at the end. -dZ. Yeah, I use the ORG trick as well. I agree it is annoying. I've used a macro to hide the ORG trick in the past. Maybe it deserves a separate directive? Or maybe limit the behavior to EQU but not SET? Quote Link to comment Share on other sites More sharing options...
intvnut Posted April 30, 2016 Share Posted April 30, 2016 (edited) Well, I doubt I'll be able to optimize 25K words down into the 8K "standard" I can use without dealing with memory allocation manually I should be able to manage this, I mostly just wanted confirmation that I'm understanding things here. I'm not sure I follow the math here. Which "standard" is this? With JLP RAM, you still get ~42K of usable ROM space, so you'll need to figure out how to condense 8K of code into the rest of your code. That seems like it ought to doable if there's some code that would lend itself to size optimization. I guess a bigger question: Should we consider putting IntyBASIC code size on a diet? It seems really easy to make really big ROMs.... PRINT statements in particular generate huge code. Edited April 30, 2016 by intvnut Quote Link to comment Share on other sites More sharing options...
freewheel Posted April 30, 2016 Share Posted April 30, 2016 I'm not sure I follow the math here. Which "standard" is this? With JLP RAM, you still get ~42K of usable ROM space, so you'll need to figure out how to condense 8K of code into the rest of your code. That seems like it ought to doable if there's some code that would lend itself to size optimization. Disclaimer: as always, I may be explaining myself poorly, or misunderstanding something. By "standard" I meant the way that IntyBASIC assigns memory by default. Which I believe starts at $5000, giving you 8K of safe space before you have to start mucking about with ORG statements. My point was that I'm at 25K already, and I don't see an easy way to "optimize" that down to fitting in to that 8K - so I'm dealing with ORG whether I like it or not. And heck, why not? A couple of assembler directives spaced properly is a hell of a lot less work than hours of code optimization anyway I haven't come close to running out of space (yet) - but I have to more frequently juggle stuff around now. It just caught me off guard to see a nice big 16K chunk get chopped in half, is all. I guess a bigger question: Should we consider putting IntyBASIC code size on a diet? It seems really easy to make really big ROMs.... PRINT statements in particular generate huge code. It's easy if you're me Keep in mind that of my (current) 25K, probably half of that is bitmapped data, screen layouts, etc. The code isn't so much the problem - although you're right about PRINT being a bit of a hog - it's that I cram an awful lot of graphics in because I can. If this becomes problematic for a lot of people, then sure. Right now I'd guess that 95% of these questions about memory allocation problems are coming from me. Which, as we've discussed ad nauseum, will get resolved with a proper memory management model and/or linker - at some point. I can be patient on that, though, so long as you experts don't mind hand-holding me a little when I run into yet another edge case. Quote Link to comment Share on other sites More sharing options...
+DZ-Jay Posted May 2, 2016 Share Posted May 2, 2016 Yeah, I use the ORG trick as well. I agree it is annoying. I've used a macro to hide the ORG trick in the past. Maybe it deserves a separate directive? Or maybe limit the behavior to EQU but not SET? I would recommend throwing the warning on SET but not on EQU. With the latter, you can guarantee that the value is valid by the time the assembler finds it; with the former, you cannot, since it may change throughout the code. -dZ. Quote Link to comment Share on other sites More sharing options...
intvnut Posted May 2, 2016 Share Posted May 2, 2016 I would recommend throwing the warning on SET but not on EQU. With the latter, you can guarantee that the value is valid by the time the assembler finds it; with the former, you cannot, since it may change throughout the code. -dZ. In AS1600, I'm pretty sure SET and EQU are actually synonyms now. You can use them freely interchangeably. That's not true in all assemblers, but I'm pretty sure it's true now in AS1600. So which one does what in the warnings department is up to us to decide. The only place the warning really makes sense is a forward reference to a symbol whose value was set more than once during assembly. Those are likely never correct. Other uses, such as a MVII #foo, where 'foo' is set later (and only set once) are completely benign. Maybe that's the key to the solution here: Only warn on forward references to SET/EQU symbols that have been assigned values more than once. Quote Link to comment Share on other sites More sharing options...
+DZ-Jay Posted May 2, 2016 Share Posted May 2, 2016 In AS1600, I'm pretty sure SET and EQU are actually synonyms now. You can use them freely interchangeably. That's not true in all assemblers, but I'm pretty sure it's true now in AS1600. So which one does what in the warnings department is up to us to decide. Well, that's silly. There is a difference between constant values and variables, right? At least in the versions that I've used of as1600, that distinction existed, which I think is the right way. The only place the warning really makes sense is a forward reference to a symbol whose value was set more than once during assembly. Those are likely never correct. Other uses, such as a MVII #foo, where 'foo' is set later (and only set once) are completely benign. Of course, which is why I mentioned SET vs. EQU, assuming that EQU are constant values that can only be set once, and SET are variables. Maybe that's the key to the solution here: Only warn on forward references to SET/EQU symbols that have been assigned values more than once. Yes, but I still would recommend keeping the distinction between SET and EQU. It just avoid errors if the programmer can expect that his constants will not change and can trust the assembler to tell him when he messed up. -dZ. Quote Link to comment Share on other sites More sharing options...
intvnut Posted May 2, 2016 Share Posted May 2, 2016 Well, that's silly. There is a difference between constant values and variables, right? At least in the versions that I've used of as1600, that distinction existed, which I think is the right way. Of course, which is why I mentioned SET vs. EQU, assuming that EQU are constant values that can only be set once, and SET are variables. Yes, but I still would recommend keeping the distinction between SET and EQU. It just avoid errors if the programmer can expect that his constants will not change and can trust the assembler to tell him when he messed up. -dZ. I had misremembered. I think at one time I had proposed making them equivalent, and you probably (rightfully!) talked me out of it. *blush* So, if you set a value with EQU, you're guaranteed it will only ever have one value. If you set a value with SET, you can keep changing it. (But only with SET; if you try to change it with EQU, EQU will complain.) I just tested those behaviors to be sure. I wasn't able to test when I posted earlier; I was at work. Summarizing: A forward reference to a symbol whose value can never change once set (ie. a label on an instruction, or an EQU) is always safe. I should strongly consider removing this warning. A forward reference to a value that did change (multiple SET statements) is likely never correct. This definitely deserves a warning, if not an outright error. The value assigned due to the forward reference is ambiguous, and that's bad. A forward reference to a value that may change (a single SET statement) is suspicious. I could go either way on whether it deserves a warning. Retaining the status quo here seems OK. Sound reasonable? Quote Link to comment Share on other sites More sharing options...
+DZ-Jay Posted May 2, 2016 Share Posted May 2, 2016 I had misremembered. I think at one time I had proposed making them equivalent, and you probably (rightfully!) talked me out of it. *blush* So, if you set a value with EQU, you're guaranteed it will only ever have one value. If you set a value with SET, you can keep changing it. (But only with SET; if you try to change it with EQU, EQU will complain.) I just tested those behaviors to be sure. I wasn't able to test when I posted earlier; I was at work. OK, that makes sense now. You freaked me out, I thought you had gone crazy again! Summarizing: A forward reference to a symbol whose value can never change once set (ie. a label on an instruction, or an EQU) is always safe. I should strongly consider removing this warning. A forward reference to a value that did change (multiple SET statements) is likely never correct. This definitely deserves a warning, if not an outright error. The value assigned due to the forward reference is ambiguous, and that's bad. A forward reference to a value that may change (a single SET statement) is suspicious. I could go either way on whether it deserves a warning. Retaining the status quo here seems OK. Sound reasonable? Sounds very reasonable. If wouldn't bother too much on the last one, specially if it requires adding extra code to keep state and count the references, etc. Removing warnings for EQU would suffice. -dZ. Quote Link to comment Share on other sites More sharing options...
intvnut Posted May 2, 2016 Share Posted May 2, 2016 (edited) OK, that makes sense now. You freaked me out, I thought you had gone crazy again! Gone crazy again? You mean, I stopped at some point? ;) Edited May 2, 2016 by intvnut Quote Link to comment Share on other sites More sharing options...
intvnut Posted May 2, 2016 Share Posted May 2, 2016 Sounds very reasonable. If wouldn't bother too much on the last one, specially if it requires adding extra code to keep state and count the references, etc. Removing warnings for EQU would suffice. Man... this was a really tough, arduous change... ;) . $ svn diff Index: asm/fraosub.c =================================================================== --- asm/fraosub.c (revision 1232) +++ asm/fraosub.c (working copy) @@ -476,10 +476,9 @@ } else { - if(tsy->seg == SSG_EQU || - tsy->seg == SSG_SET) + if(tsy->seg == SSG_SET) { - frp2warn( "forward reference to SET/EQU symbol"); + frp2warn( "forward reference to SET symbol"); } etop = tsy->value; } . It'll be in the next stable dev release. 1 Quote Link to comment Share on other sites More sharing options...
+DZ-Jay Posted May 2, 2016 Share Posted May 2, 2016 (edited) An entire set of macros to avoid that warning suddenly lost their standing in my library. Watch your back, they are vicious! Edited May 2, 2016 by DZ-Jay Quote Link to comment Share on other sites More sharing options...
intvnut Posted May 3, 2016 Share Posted May 3, 2016 An entire set of macros to avoid that warning suddenly lost their standing in my library. Watch your back, they are vicious! Like the buggy whip manufacturers said to Ford... Quote Link to comment Share on other sites More sharing options...
+DZ-Jay Posted July 19, 2016 Share Posted July 19, 2016 Hi, Óscar, I just took some time to finally review the MULT macro since you had mentioned you encountered some bugs in it, and I think there's still one more bug. When multiplying by $7E (126) and $7F (127), shouldn't we use arithmetic shift instead of logical to extend the sign after the SWAP? ; Multiply by $7E (126) IF (_mul.const = $7E) _mul.done QSET -1 MOVR %reg%, %tmp% SWAP %reg%, 1 SLR %reg%, 1 ; <- Should this be SAR instead? ADDR %tmp%, %tmp% SUBR %tmp%, %reg% ENDI ; Multiply by $7F (127) IF (_mul.const = $7F) _mul.done QSET -1 MOVR %reg%, %tmp% SWAP %reg%, 1 SLR %reg%, 1 ; <- Should this be SAR instead? SUBR %tmp%, %reg% ENDI Also, as Joe recommended in another thread, it may be optimal to restore the SLL 1 instead of breaking the sequences with ADDR on itself. For instance: ; Multiply by $1F (31) IF (_mul.const = $1F) _mul.done QSET -1 MOVR %reg%, %tmp% SLL %reg%, 2 SLL %reg%, 2 ADDR %reg%, %reg% ; <- This should be SLL %reg%, 1 SUBR %tmp%, %reg% ENDI This allows for more contiguous non-interruptible operations (without breaking the limit) and give the CPU a chance to steal a few extra cycles from the STIC interruption. -dZ. 1 Quote Link to comment Share on other sites More sharing options...
GroovyBee Posted July 19, 2016 Share Posted July 19, 2016 I would say no to the SAR. With the previous swap instruction it just executed it only works if the MSB of %reg% was zero before the swap. That tells me that MULT is 8x8 unsigned. Quote Link to comment Share on other sites More sharing options...
+nanochess Posted July 19, 2016 Author Share Posted July 19, 2016 I suspect there is a bug somewhere for these multiplies for some values. Because obviously it doesn't handle well input values starting in $8000. I'll check soon. Quote Link to comment Share on other sites More sharing options...
+DZ-Jay Posted July 19, 2016 Share Posted July 19, 2016 (edited) I would say no to the SAR. With the previous swap instruction it just executed it only works if the MSB of %reg% was zero before the swap. That tells me that MULT is 8x8 unsigned. Yes, you are right, unless we mask the low-order byte after the SWAP... I suspect there is a bug somewhere for these multiplies for some values. Because obviously it doesn't handle well input values starting in $8000. I'll check soon. Yeah, I only tested it with unsigned values. I thought it could work for signed values as well, but perhaps that'll take a bit more work. I'll take a look tonight. It seems that all of us (Joe Z., myself, and nanochess) trusted too much on someone else having tested the macro because we all missed bugs at different levels. -dZ. Edited July 19, 2016 by DZ-Jay 1 Quote Link to comment Share on other sites More sharing options...
GroovyBee Posted July 19, 2016 Share Posted July 19, 2016 Given that the result is 16 bits then the the number of bits in the two operands must equal that, making it an 8x8, 10x6 and so on. In a 16 bit CPU that means neither operand can be signed. Quote Link to comment Share on other sites More sharing options...
+nanochess Posted July 19, 2016 Author Share Posted July 19, 2016 Given that the result is 16 bits then the the number of bits in the two operands must equal that, making it an 8x8, 10x6 and so on. In a 16 bit CPU that means neither operand can be signed. I tend to see all multiplies as signed because technically there is no difference between an unsigned multiply and signed multiply when 16x16 = 16 bits, the differences is only when source operands are smaller like 8x8 signed = 16 bits, then the routines should be different. For IntyBASIC as the input operands are 16-bits, a single multiply routine makes the trick. This is what I'm seeing, that the input operands are badly evaluated for some ranges in the case shown by Dz-Jay. I thought I had tested every routine. Quote Link to comment Share on other sites More sharing options...
+DZ-Jay Posted July 19, 2016 Share Posted July 19, 2016 This is what I'm seeing, that the input operands are badly evaluated for some ranges in the case shown by Dz-Jay. I thought I had tested every routine. So, since the input operands are expected to be signed 16-bit values, should we SAR to extend sign? It won't work for large values anyway due to overflow. Quote Link to comment Share on other sites More sharing options...
GroovyBee Posted July 19, 2016 Share Posted July 19, 2016 As I said earlier what you have here is an 8x8 unsigned multiply. For example: =-3 x 126 =$FFFD x $7E =$FE86 Stepping through the MULT macro code: If %reg% contains -3 MOVR %reg%, %tmp% Now %tmp%=$FFFD SWAP %reg%, 1 Now %reg%=$FDFF SLR %reg%, 1 Now %reg%=$7EFF ADDR %tmp%, %tmp% Now %tmp%=$FFFA SUBR %tmp%, %reg% Finally %reg%=$7EFF-$FFFA=$7F05 Not even close Quote Link to comment Share on other sites More sharing options...
+DZ-Jay Posted July 20, 2016 Share Posted July 20, 2016 As I said earlier what you have here is an 8x8 unsigned multiply. For example: =-3 x 126 =$FFFD x $7E =$FE86 Stepping through the MULT macro code: If %reg% contains -3 MOVR %reg%, %tmp% Now %tmp%=$FFFD SWAP %reg%, 1 Now %reg%=$FDFF SLR %reg%, 1 Now %reg%=$7EFF ADDR %tmp%, %tmp% Now %tmp%=$FFFA SUBR %tmp%, %reg% Finally %reg%=$7EFF-$FFFA=$7F05 Not even close Whoops! That's what I get for posting from my phone and not reading the code. Quote Link to comment Share on other sites More sharing options...
freewheel Posted July 30, 2016 Share Posted July 30, 2016 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. 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.