Jump to content
IGNORED

INTYBASIC 1.2 problems


artrag

Recommended Posts

I put a warning because I made a mistake several times when putting a constant bigger than 255 in a 8-bit variable.

 

Also a side-effect, is that putting -1 (65535) inside a 8-bit variable although works for adding/subtraction, isn't possible to compare it with -1, because on reading the value is 255.

 

Anyway if you use correctly you don't need to worry about the warning or you can deactivate it with the -w option.

 

As in most compilers there is no need to differentiate signed/unsigned variables, except for comparisons, but I'll address that later.

Link to comment
Share on other sites

The problem is that after the warnings compilation ends and I do not get a rom...
In attach the file in order to allow you to test yourself.

 

Compilation is aborted with this message:

C:\Users\Admin\Documents\IntyBASIC SDK\Projects\gorf>intybuild gorf.bas
IntyBASIC Build Script (INTYBUILD.BAT)
Created by: DZ-Jay
Last updated: 07/13/2015
IntyBASIC compiler v1.2 Aug/24/2015
© 2014-2015 Oscar Toledo G. http://nanochess.org/
Warning: assigning value bigger than 8-bits in line 20
7 used 8-bit variables of 228 available
7 used 16-bit variables of 47 available
Compilation finished
IntyBASIC compilation failed.
Program build aborted.

gorf.bas

Edited by artrag
Link to comment
Share on other sites

In addtion the ABS() function seems broken.

If you do

dx = -1

and test for ABS(dx)>10 you get TRUE (!)

 

 

I just tested this. When moving 8-bit variables from RAM into registers, IntyBASIC does not extend the sign to 16-bits.

 

I prepared this simple test:

        a = -1
        dx = -1
        if (abs(dx) > 10) then a = 1 else a = 0
 

Here's the Assembly Language code generated for that:

        SRCFILE "MyProject.bas",19
        ;[20]   a = -1
        SRCFILE "MyProject.bas",20
        MVII #65535,R0
        MVO R0,V2
        ;[21]   dx = -1
        SRCFILE "MyProject.bas",21
        MVO R0,V3
        ;[22]   if (abs(dx) > 10) then a = 1 else a = 0
        SRCFILE "MyProject.bas",22
        MVI V3,R0
        TSTR R0
        BPL $+3
        NEGR R0
        CMPI #10,R0
        BLE T7
        MVII #1,R0
        MVO R0,V2
        B T8
T7:
        CLRR R0
        MVO R0,V2
T8:

Only 65535 is assigned to R0, which is an 8-bit version of -1 in a 16-bit register. That's fine if it is only going to be stored into an 8-bit variable -- but it doesn't (more on this later*). The problem is when the 8-bit variable is read back to perform the ABS() function, the sign is not extended. Consequently, when testing for negativity, it fails because a 16-bit value of 65535 is much larger than 10.

 

IntyBASIC must sign-extend all 8-bit variables when reading them back from memory into registers.

 

* Here's another side-effect:

        a = -1
        #dx = -1

The above compiles into identical code as the previous example, except that the address of #dx is in 16-bit memory:

        SRCFILE "MyProject.bas",19
        ;[20]   a = -1
        SRCFILE "MyProject.bas",20
        MVII #65535,R0
        MVO R0,V2
        ;[21]   #dx = -1
        SRCFILE "MyProject.bas",21
        MVO R0,V3

IntyBASIC detects that it can re-use the -1 value for both variables, except that instead of assigning 0xFFFF (-1) to R0, it assigns only 0x00FF. This is fine for the 8-bit variable, but not for anything else. It would be safer if constants were treated in 16-bits while in registers. The following would work correctly (though it still wouldn't resolve the ABS() issue when the 8-bit variable is read back):

        SRCFILE "MyProject.bas",19
        ;[20]   a = -1
        SRCFILE "MyProject.bas",20
        MVII #$FFFF,R0
        MVO R0,V2
        ;[21]   #dx = -1
        SRCFILE "MyProject.bas",21
        MVO R0,V3

Link to comment
Share on other sites

Isn't more efficient to have two versions of abs(), one for bytes and one for integers?

On bytes you test on bit7 and on its on bit15.

The problem could also be wider and extended to comparisons between bytes

 

How does the compiler interpret

x = 255

Y = x>0

 

What is the value of Y?

It should be false if x is considered signed. True if x is unsigned.

Which assumption have you done for bytes and integers ? Is there a way to specify if variables are signed or unsigned?

Edited by artrag
Link to comment
Share on other sites

Isn't more efficient to have two versions of abs(), one for bytes and one for integers?

On bytes you test on bit7 and on its on bit15

 

I'll leave the implementation to Oscar, since there are additional optimizations that the compiler may take into consideration. But we all agree that ABS() should consider signed and unsigned 8-bit values.

Link to comment
Share on other sites

Currently no way to specify if variables are signed or unsigned.

 

All 8-bit variables are read inside the registers as zero-extended to 16 bits. If you perform arithmetic with signed 8-bit variables and save in 8-bit variables you won't have any problem because the value is truncated in writing (tip).

 

All comparisons are made as 16-bits signed.

 

BTW, there is a bug in IntyBASIC where the warning returns an error code and stops further compilation with SDK, please use the -w switch to turn off warnings while I solve this, or go back to v1.2.1

Link to comment
Share on other sites

All 8-bit variables are read inside the registers as zero-extended to 16 bits. If you perform arithmetic with signed 8-bit variables and save in 8-bit variables you won't have any problem because the value is truncated in writing (tip).

 

Of course they are truncated upon writing, but operations require them to be read back into a 16-bit register and their sign is lost at that point.

 

All comparisons are made as 16-bits signed.

Not quite true, as I showed in my example. Unless by 16-bit signed value you mean an un-extended 8-bit signed value interpreted as a positive value... ;)

 

-dZ.

Link to comment
Share on other sites

 

Of course they are truncated upon writing, but operations require them to be read back into a 16-bit register and their sign is lost at that point.

 

Not quite true, as I showed in my example. Unless by 16-bit signed value you mean an un-extended 8-bit signed value interpreted as a positive value... ;)

 

-dZ.

 

1. All arithmetic is done as 16-bits ;)

2. 8-bits variables are zero-extended to 16-bits.

3. All comparisons are made as 16-bits signed.

 

The quick solution is a macro for converting unsigned 8-bit variables to signed.

 

DEF FN signed(a) = ((a XOR 128) - 128)

 

BTW, IntyBASIC compiles right your example, because the register R0 still contains 65535 (-1) after writing the 8-bits variable, so the 16-bits variable receives the right value (the value written to the 8-bits variable isn't important at this point, because there is no code reusing the content of that very variable)

 

Note MVO doesn't destroy the source value (R0 in this case)

Link to comment
Share on other sites

extending to 16 bits with 0s makes comparisons in 16 bit fail.

It also leads to problems when one or more of the operand is signed and you keep the 16 bit result.

I think that in the end the simplest way to deal with casting and with expressiona where you mix bytes and integers is to introduce explicitly signed variables

Edited by artrag
Link to comment
Share on other sites

Oscar, we're going to have to disagree on this. While the compiler may be technically correct in reading 65535 from an 8-bit variable with a value of -1, it is then not correct to treat this specific value as signed. Requiring the programmer to extend his own signs or treat signed values as unsigned values is an undue burden that the compiler should handle automatically.

 

In any language, if I say "a = -1", I do not care whether the compiler translated that into a 16-bit signed or unsigned value, or whether it is stored in 8-bit or 16-bit memory. When I later do "if (a < 0)" I expect the compiler to do the right thing. I do not expect to say "a = -1 : if (a >= 255)".

 

-dZ.

Link to comment
Share on other sites

extending to 16 bits with 0s makes comparisons in 16 bit fail.

It also leads to problems when one or more of the operand is signed and you keep the 16 bit result.

I think that in the end the simplest way to deal with casting and with expressiona where you mix bytes and integers is to introduce explicitly signed variables

 

There are various alternatives. Like in C, the language could treat all integers as signed unless explicitly cast as unsigned. Another option is like GroovyBee has suggested, to account for "sign-ness" when comparing 8-bit values in functions like ABS() and SIGNED(), and to truncate values in registers when operating on 8-bit values.

Link to comment
Share on other sites

Oscar, we're going to have to disagree on this. While the compiler may be technically correct in reading 65535 from an 8-bit variable with a value of -1, it is then not correct to treat this specific value as signed. Requiring the programmer to extend his own signs or treat signed values as unsigned values is an undue burden that the compiler should handle automatically.

 

In any language, if I say "a = -1", I do not care whether the compiler translated that into a 16-bit signed or unsigned value, or whether it is stored in 8-bit or 16-bit memory. When I later do "if (a < 0)" I expect the compiler to do the right thing. I do not expect to say "a = -1 : if (a >= 255)".

 

-dZ.

 

IntyBASIC has been this way since v0.1, besides you should take in account this:

 

1. The CP1610 processor automatically reads 8-bits values zero-extending them.

2. So it's faster to process unsigned values than signed.

3. I'll insist, that arithmetic like a=a+dx works just fine.

4. The signedness problems are only in comparisons (including ABS, SGN)

5. There are ways to work around this, including the macro I just published.

 

The macro would be what IntyBASIC would include in each 8-bit variable reading when typed SIGNED (2 instructions), it's a thing in my TODO list, but really not so urgent because is easy to work around it.

Link to comment
Share on other sites

extending to 16 bits with 0s makes comparisons in 16 bit fail.

It also leads to problems when one or more of the operand is signed and you keep the 16 bit result.

I think that in the end the simplest way to deal with casting and with expressiona where you mix bytes and integers is to introduce explicitly signed variables

 

Yep, a "SIGNED var" statement would mark it for IntyBASIC and would add two instructions to the variable reading:

 

 

    XORI #$0080,R0
    SUBI #$0080,R0

 

Exactly the same code generated by this macro that you can use right away.

 

 

DEF FN signed(var) = ((var XOR 128) - 128)

 

Probably I would add also an UNSIGNED statement, to be able to make unsigned 16-bits comparisons.

Link to comment
Share on other sites

A=127

B=255 'i.e. -1

#C=A*B

 

What should the poor compiler put in #C ?

 

The result of 127 * 255.

 

Don't worry, the unsigned behavior of IntyBASIC is implicit since version 0.1 and everyone has been working around it when needed.

 

Of course you would prefer signed behavior by default, but I insist, the unsigned nature of CP1610 processor makes this faster, is better to make it signed only when you really need it because it's slower.

 

In particular I always use 8-bits variables, for example:

 

 

     x= 20
     y = 20
     dx = -1
     dy = -1
loop:
     WAIT
     SPRITE 0,$0308+x,$0108+y,$0807
     x = x + dx
     y = y + dy
     IF x = 0 THEN dx = - dx
     IF x = 159 THEN dx = - dx
     IF y = 0 THEN dy = - dy
     IF y = 95 THEN dy = - dy
     GOTO loop
 

 

These are all 8-bits operations.

Link to comment
Share on other sites

 

IntyBASIC has been this way since v0.1, besides you should take in account this:

 

1. The CP1610 processor automatically reads 8-bits values zero-extending them.

2. So it's faster to process unsigned values than signed.

3. I'll insist, that arithmetic like a=a+dx works just fine.

4. The signedness problems are only in comparisons (including ABS, SGN)

5. There are ways to work around this, including the macro I just published.

 

The macro would be what IntyBASIC would include in each 8-bit variable reading when typed SIGNED (2 instructions), it's a thing in my TODO list, but really not so urgent because is easy to work around it.

 

I take all that into account. What I disagree with you is that, those "ways to work around this" should be imposed on the programmer.

 

That's a perfectly understandable position to take as a language designer. I am playing the devil's advocate here. ;)

 

-dZ.

  • Like 1
Link to comment
Share on other sites

Just speculating...

In the intellivision all math is between 16 registers (is it?).

 

Actually if you declare signed a and b and you use them in expressions that return its value in a 8 bit variable you do not need to extend their sign to 16 bit as the wrong part would fall outside the result

 

In conclusion, I may be wrong, but the compiler could decide if extend the signs or not for signed variables according to the fact that the result of the expression is on 8 or 16 bits

Link to comment
Share on other sites

Sgn() and abs() should ideally have 4 separate implementations for 8 and 16 bit signed and unsigned.

Anyway their current implementation expects a 16bit signed argument and work on bytes if you use the sign extension macro posted above

Edited by artrag
Link to comment
Share on other sites

Sgn() and abs() should ideally have 4 separate implementations for 8 and 16 bit signed and unsigned.

Anyway their current implementation expects a 16bit signed argument and work on bytes if you use the sign extension macro posted above

 

Uh... if you are using unsigned values, you do not need SGN() or ABS(). :lol:

Link to comment
Share on other sites

Just speculating...

In the intellivision all math is between 16 registers (is it?).

The Intellivision has a 16-bit processor, with 16-bit registers. It was designed in an era were the "bit-ness" of memory chips was expensive. Moreover, I believe that General Instruments (the producers of the processor and the chipset of the Intellivision) had a near-monopoly on 10-bit ROM chips and designed the Intellivision to support 10- or 16-bit memory by doing some trickery in the bus.

 

Then you have Scratch RAM, which is 8-bits; and System RAM, which is 16-bits. And things start getting fun!

 

Most early games used 10-bit ROMs (this is why the data unit word is called a "DECLE": You have a 4-bit Nybble, an 8-bit Byte, and a 10-bit Decle); but nowadays we never even bother with that.

In the world of IntyBASIC, ROM is 16-bits, Scratch RAM is 8-bit and System RAM is 16-bits -- but whenever you operate on any of them, e.g., to perform arithmetic, or to copy memory, or whatever; they all pass through a 16-bit CPU register, which is where the fun comes in.

 

The CPU doesn't care: all values to it are 16-bits, so -1 is $FFFF (65,553). When you persist that in an 8-bit variable, its high-order byte will be magically truncated. When you read the variable back into a register, it comes in as $FF (255), missing the high-order byte that was discarded. The CPU is none the wiser.

 

So when operating on values read from 8-bit RAM, someone needs to make that the value is treated properly. In Assembly Language, for lack of any language facilities, this someone is the programmer. I argue that in higher-level languages like BASIC, it should be the compiler or the language run-time (if there is one).

 

To be sure, these are not trivial problems. The cheap and easy way to cope with them is to abdicate responsibility for the problem, and let the programmer figure it out himself. On the other side of the spectrum, you can have a highly complex typing system that goes out of its way to magically divine the intent of the programmer in order to know whether the sign is needed or wanted at any given time.

 

IntyBASIC should exist somewhere in the middle-to-low range.

 

In conclusion, I may be wrong, but the compiler could decide if extend the signs or not for signed variables according to the fact that the result of the expression is on 8 or 16 bits

Don't worry about the implementation. The truth is that we should not have been discussing implementation here at all. That is not to say that your feedback is not valuable, on the contrary. However, the technical details of how the compiler operates is the domain of the language designer, since only he has a specific vision of how he wants the language to behave. Oscar is very experienced in language design and low-level programming, so I'm sure he will find the most optimal way to implement any new feature. He has so far.

 

What we can and should offer is suggestions on improving the interface (i.e., the programming model and/or language grammar). On this, I think we've all reached a good consensus: default to unsigned values and only deal with sign when the programmer explicitly dictates it, say, with a SIGNED keyword.

 

-dZ.

Edited by DZ-Jay
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...