Jump to content
IGNORED

Intibasic and signed integers


Recommended Posts

My question is also about the CP1600

 

I have this segment of code

	if (#ex(n)/256 > (160+8)) then 			' test both for x<0 and x>160
		gosub en_exits_screen
	elseif (#ex(n)/256 < 0)  then 			' test both for x<0 and x>160
		gosub en_exits_screen
	end if

That is transleted to 

	;[1261] 	if (#ex(n)/256 > (160+8)) then 		
	MVII #array_&EX,R3
	ADD var_N,R3
	MVI@ R3,R0
	SWAP R0
	ANDI #255,R0
	CMPI #168,R0
	BLE T213
	;[1262] 		gosub en_exits_screen
	CALL label_EN_EXITS_SCREEN
	;[1263] 	elseif (#ex(n)/256 < 0)  then 		
	B T214
T213:
	MVII #array_&EX,R3
	ADD var_N,R3
	MVI@ R3,R0
	SWAP R0
	ANDI #255,R0
	CMPI #0,R0
	BGE T215
	;[1264] 		gosub en_exits_screen
	CALL label_EN_EXITS_SCREEN
	;[1265] 	end if
T214:
T215:

Everithing works fine, and en_exits_screen is called only if #ex()/256<0 or if #ex()/256>168

 

Now I wanted to get rid of the division by 256.

 

I was expecting that #ex()/256<0 is the same of #ex()<0 and that  #ex()/256>168 is the same of  #ex()>168*256.

 

So I tried this code

	if (#ex(n)> (160+8)*256) then 			' test both for x<0 and x>160
		gosub en_exits_screen
	elseif (#ex(n) < 0)  then 			' test both for x<0 and x>160
		gosub en_exits_screen
	end if

which translate to this

	;[1262] 	if (#ex(n)> (160+8)*256) then 	
	MVII #array_&EX,R3
	ADD var_N,R3
	MVI@ R3,R0
	CMPI #$A800,R0
	BLE T213
	CALL label_EN_EXITS_SCREEN
	;[1264] 	elseif (#ex(n) < 0)  then 		
	B T214
T213:
	MVII #array_&EX,R3
	ADD var_N,R3
	MVI@ R3,R0
	CMPI #0,R0
	BGE T215
	CALL label_EN_EXITS_SCREEN
	;[1266] 	end if
T214:
T215:

 

The ASM seems correct, but it happen to not work and I suspect it as to do with signed math in the CP1600

More precisely:

- CMPI #0,R0 seems to trigger the jump to en_exits_screen both if #ex()<0 and #ex()/256>127

- CMPI #$A800,R0 seems to trigger the jump to en_exits_screen always, with any value of #ex()

 

This latter in particular is strange.... Any insignt ?

 

 

 

Link to comment
Share on other sites

Ok  some answers to my questions 

$A800 is negative  thus any positive value is larger and the code triggers always the call to en_exits_screen

Also comparing to 0, implies that the max positive is 32.767 which corresponds to 127 one divided by 256. Any larger value is negative and triggers the call to en_exits_screen.

 

I think that BGE and BLE are based on the sign of the result of CMPI. Are they?

 

Is there a way to make intybasic produce  jumps on the carry flag instead of the sign flag?

Link to comment
Share on other sites

18 minutes ago, artrag said:

Ok  some answers to my questions 

$A800 is negative  thus any positive value is larger and the code triggers always the call to en_exits_screen

Also comparing to 0, implies that the max positive is 32.767 which corresponds to 127 one divided by 256. Any larger value is negative and triggers the call to en_exits_screen.

 

I think that BGE and BLE are based on the sign of the result of CMPI. Are they?

Yes.  For unsigned comparisons, you use BNEQ and BNC.

 

http://wiki.intellivision.us/index.php/Extended_Precision_Arithmetic#Comparison

 

http://wiki.intellivision.us/index.php/CP1610#Instruction_Set

 

 

Quote

Is there a way to make intybasic produce  jumps on the carry flag instead of the sign flag?

I haven't tested it (I'm not close to my computer), but have you tried defining the variable with the UNSIGNED modifier?  It prompts the compiler to treat the variable as unsigned during expression evaluation, and I think this extends to comparisons.

 

   dZ.

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

13 hours ago, DZ-Jay said:

I haven't tested it (I'm not close to my computer), but have you tried defining the variable with the UNSIGNED modifier?  It prompts the compiler to treat the variable as unsigned during expression evaluation, and I think this extends to comparisons.

 

Good news!  I just tested this and it worked as expected:  declaring the "#en" array as "unsigned" will prompt the compiler to generate unsigned comparisons.

 

I used the same code from the top of your first post, and it resulted in the following code.  Notice the use of BEQ and BNC instead of BLE and BGE.

; if (#ex(n)/256 > (160+8)) then            ' test both for x<0 and x>160
    MVII #array_&EX,R3
    ADD var_N,R3
    MVI@ R3,R0
    SWAP R0
    ANDI #255,R0
    CMPI #168,R0
    BEQ T7
    BNC T7

; gosub en_exits_screen
    CALL label_EN_EXITS_SCREEN

; elseif (#ex(n)/256 < 0)  then             ' test both for x<0 and x>160
    B T8
T7:
    MVII #array_&EX,R3
    ADD var_N,R3
    MVI@ R3,R0
    SWAP R0
    ANDI #255,R0
    CMPI #0,R0
    BC T9

; gosub en_exits_screen
    CALL label_EN_EXITS_SCREEN

; end if
T8:
T9:

 

The only difference was to use the "UNSIGNED" directive when declaring the variable:

Dim #ex(SOME_VALUE_HERE)
Dim n

Unsigned #ex

 

   -dZ.

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

EDIT:  I've updated this post with some corrections pointed out by @artrag.

 

For clarity, and to help any others who may encounter a similar case, here's the relevant portion from the SDK documentation (intro_to-cp1600.txt) :

    To perform unsigned comparisons, the situation is a little simpler,
    since we don't care about overflows.  Since the numbers are unsigned,
    though, the sign bit doesn't contain the information we're interested
    in.  Instead we can look directly at the carry and zero bits.

        If this      Then so                      And these
        is true...   is this...                   status bits are set.
        -----------------------------------------------------------------
         x < y        x - y < 0                   C = 0, Z = 0, O = ?
         x > y        x - y > 0                   C = 1, Z = 0, O = ?
         x = y        x - y = 0                   C = 1, Z = 1, O = ?

    We can then use the branches that look at the carry bit and zero
    bit to handle greater-than, less-than, and equals on unsigned numbers:

        Mnemonic    Branch if...                  Test
        --------------------------------------------------------------
         BC         Carry is set                  C = 1
         BNC        Carry is not set              C = 0
         BEQ        Zero is set                   Z = 1

    Notice that "BC" is effectively "Branch if Greater or Equal", and
    "BNC" is "Branch if Less Than."  We can use "BEQ" before a "BC"
    to sort out the "Equals" cases from the "Greater" cases.

 

For IntyBASIC programmers who are not familiar with Assembly Language, what all this means is that the CPU treats logical comparisons (i.e., IF expressions) differently depending on whether the expression is "signed" (involving positive and/or negative values), or "unsigned" (involving only absolute values).

 

IntyBASIC automatically handles this for you in the following way:

  • By default, 16-bit variables are signed, meaning that they can be positive or negative.  The most significant bit (i.e., the highest order bit) is reserved to mark the sign, which reduces their range by a power of 2.  Therefore,
    • 16-bit variables are treated really as 15-bit variables (215 + sign), so their range is from -32,768 to +32,768.

      This is important: any positive value in a signed variable that goes over the range above will be interpreted as a negative value, and therefore affect the outcome of your "IF" expressions.  This is essentially the problem @artrag encountered in his first post.

 

  • By default, 8-bit variables are unsigned, meaning that they can never be negative.  (Actually, they are absolute values, just numbers without being positive or negative.)
    • 8-bit variables are treated using all their bits for their value (28), so their range is from 0 to 255.

      This is important: unsigned variables can never have negative values.  A negative value assigned to an unsigned variable will be interpreted as larger positive value -- that is, what would be the sign-bit will be treated as part of the number.  This obviously will affect the outcome of your "IF" expressions.

 

  • You can reverse the default behaviour of variables using the modifiers SIGNED and UNSIGNED, as applicable.  (See the IntyBASIC manual for more details, or take a look at the example in an my earlier post).  When applied to corresponding variables, their range changes as follows:
    • Signed 8-bit variables are treated as 7-bit values (27 + sign), so their range is from -127 to +127.
    • Unsigned 16-bit variables are treated as such (216), so their range is from 0 to 65,536.

 

  • The "signness" of variables in an "IF" expression determines how the expression logic will be handled by the CPU:
    • Any signed variable (either default or marked with the SIGNED modifier) will result in the expression being treated as signed.
    • All unsigned variables (either default or marked with the UNSIGNED modifier) will result in the expression being treated as unsigned.

 

I hope this makes sense.

 

   -dZ.

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

18 hours ago, artrag said:

Dz, the 8 bit variables are by default unsigned, the 16 bit variables are by default signed. The SIGNED and UNSIGNED qualifier can revert the default.

 

Yes, this is what I explained above, in the first bullet point.

 

EDIT: You are right, I corrected the previous post with the correct information.  I am sorry for the confusion.  The rest of my post here is correct.

 

Moreover, you can apply the SIGNED/UNSIGNED modifier at any point, as many times as needed, for instance:

    Dim  #A, #B

    ' Treat #A as unsigned from now on ...
    UNSIGNED #A

    If ((#A > 100) Then
        Goto MainLoop
    End If

    ' Treat it again as signed ...
    SIGNED #A

 

Quote

The exception is that 16 bit multiplications and divisions are always unsigned. 

The 16-bit multiplications are unsigned, yes, but the results of a logical expression (even those including multiplication of 16-bit values) depends on the whether the variables are signed or unsigned.

 

For example, the following code:

    Dim  #A, #B

    If ((#A * #B) < 1) Then
        Goto MainLoop
    End If

 

Compiles to the following:

;[46]     If ((#A * #B) < 1) Then
    MVI var_&A,R0
    MVI var_&B,R1
    CALL qs_mpy16
    MOVR R1,R0
    CMPI #1,R0
    BGE T7

 

The results of the multiplication is unsigned, but when the full expression is evaluated, it only considers the attributes of the variables, which in this case are signed (default).

 

  -dZ.

Edited by DZ-Jay
Corrected an error.
Link to comment
Share on other sites

18 hours ago, artrag said:

Dz, the 8 bit variables are by default unsigned, the 16 bit variables are by default signed. The SIGNED and UNSIGNED qualifier can revert the default. The exception is that 16 bit multiplications and divisions are always unsigned. 

Sorry, I just caught my error -- I don't know how I missed it earlier.  You are right:  by default, 8-bit variables are unsigned and 16-bit variables are signed.  Sorry for the confusion.

 

I've updated the two posts above with the correct information.  Please let me know if you see anything else wrong. :)

 

    Thanks,

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