Jump to content
IGNORED

IntyBASIC compiler v1.2.9: The good things are now better!


Recommended Posts

Your choices are :
  • Juggle, juggle, juggle :P
  • 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.

Link to comment
Share on other sites

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...

Link to comment
Share on other sites

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 by DZ-Jay
Link to comment
Share on other sites

 

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?

Link to comment
Share on other sites

 

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 by intvnut
Link to comment
Share on other sites

 

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.

Link to comment
Share on other sites

 

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.

Link to comment
Share on other sites

 

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.

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

 

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?

Link to comment
Share on other sites

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! :P

 

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.

Link to comment
Share on other sites

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. :)

  • Like 1
Link to comment
Share on other sites

  • 2 months later...

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.

  • Like 1
Link to comment
Share on other sites

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. :dunce:

 

-dZ.

Edited by DZ-Jay
  • Like 1
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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 ;)

Link to comment
Share on other sites

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. :dunce:

Link to comment
Share on other sites

  • 2 weeks later...

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.

Link to comment
Share on other sites

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...