linuxha / SmallC68

FLEX 6800 Small C compiler
GNU Lesser General Public License v2.1
10 stars 2 forks source link

Relational operator in run0.asm (6800) #2

Open zu2 opened 2 weeks ago

zu2 commented 2 weeks ago

Relational operator processing does not seem to work correctly in run0.asm for the 6800.

The BCMP routine performs subtraction on SUBB and SBCA. Only the result of SBCA is reflected in the flags. If the result of the subtraction is AccA=0, ZEQ will be T regardless of the value of AccB. Similarly for the others.

Therefore, the Zxx routine needs to be modified so that it also references the lower byte.

linuxha commented 2 weeks ago

OMG, someone is actually using this. :-)

Huge thanks for that. I rushed the code while working on other things. It was a quick macro (subd).

Hmm, will need to figure this out.

  ;*****************************************************
  ;*
  ;*   BASIC COMPARE INSTRUCTION SUBROUTINE
  ;*   Compare the top of Stack to Register and set Condition codes
  ;*
  ;*  Unsigned compare, Carry set if top of stack < A,B
  ;*
  BCMP    TSX
  ;       ldd     2,X             ;* GET TOP OF STACK
          ldaa    2,X             ;* GET TOP OF STACK
          ldab    3,X             ;* GET TOP OF STACK
  ;       subd    zREG            ;* COMPARE
          subb    zREG+1          ;* COMPARE
          sbca    zREG            ;* COMPARE
          RTS

I need to RTS after the subb is it is F

linuxha commented 2 weeks ago

BTW, I'm sure there are other issues like that in the code. I didn't give it a whole lot of thought for edge cases.

zu2 commented 2 weeks ago

The relational operations Zxx require a little extra work to test AccB. Below we show ZEQ and ZNE. The other Zxx operations get more complicated.

diff -u run0.asm.orig run0.asm
--- run0.asm.orig   2024-06-19 09:54:03
+++ run0.asm    2024-06-19 09:57:46
@@ -598,14 +598,18 @@
 ;*-------------------------------
 ;* #33  TEST FOR EQUALITY
 ZEQ     BSR     BCMP
-        BEQ     T
-        BRA     F
+        BNE     F
+        TSTB
+        BNE     F
+        BRA     T

 ;*-------------------------------
 ;* #34  TEST FOR NOT-EQUAL
 ZNE     BSR     BCMP
-        BNE     T
-        BRA     F
+        BEQ     F
+        TSTB
+        BEQ     F
+        BRA     T
linuxha commented 2 weeks ago

I'm thinking a different solution, make BCMP returned a combined 'CC'. I still need to work this out. Need to figure out the zxx and uxx. I really need to create a unit test. I haven't figured out a good way to do that.

Also note that I've reversed the A & B, I think I had them backwards (dyslexic). That drives me crazy.

 BCMP    tsx
         ldab    3,X             ;* GET TOP OF STACK (lo)
         ldaa    2,X             ;* GET TOP OF STACK (hi)
         psha                    ;* doesn't affect CC
 ;
 ; The BCMP routine performs subtraction on SUBB and SBCA. Only the result of
 ; SBCA is reflected in the flags. If the result of the subtraction is AccA=0,
 ; ZEQ will be T regardless of the value of AccB. Similarly for the others.
 ;
 ; Therefore, the Zxx routine needs to be modified so that it also references the lower byte.
 ;
         subb    zREG+1          ;* COMPARE (lo)
         tpa                     ;* doesn't affect CC
         staa    CC              ;* Temp save CC
         pula                    ;* Restore A (doesn't affect CC)
         sbca    zREG            ;* COMPARE (hi)
         tpa                     ;* doesn't affect CC
         oraa    CC              ;* A <- A OR CC, combines CC and A
         tap                     ;* Restore combined to PCR
         rts

I'll need to check the results against the 6809 version.

I don't have this checked in yet.

zu2 commented 2 weeks ago

Unfortunately, I don't think this strategy works well for anything other than ZNE/ZEQ. For example, if the V/N flag is set as a result of SUBB, BLT and BGE will be messed up. And if the C flag is affected by the result of SUBB, Uxx will also be messed up.

linuxha commented 2 weeks ago

I was afraid of that. I'll need to sit down and make notes to get this right. Thanks for checking

linuxha commented 1 week ago

BCMP needs to be rewritten, the 16 bit subtraction is all wrong. I haven't found any good examples of 16 bit subtraction but I am working on it.

I think will be interesting as I think Small C creates a -1 signed char as 0x8001. SUBA MEMORY will return a 2s complement result if negative (COMA, B-1 if ... gets messy).

linuxha commented 1 week ago

Okay a bit more work but not fully tested, basically only tested with a few value. A & B return values are not correct when done. This is probably okay for Zxx, not sure of Uxx yet.

;*-------------------------------
BCMP    TSX
;       ldd     2,X             ;* GET TOP OF STACK
        nop                     ;* SWI
        ldab    3,X             ;* GET TOP OF STACK (lo)
        ldaa    2,X             ;* GET TOP OF STACK (hi)
;       subd    zREG            ;* COMPARE
;
; The BCMP routine performs subtraction on SUBB and SBCA. Only the result of
; SBCA is reflected in the flags. If the result of the subtraction is AccA=0,
; ZEQ will be T regardless of the value of AccB. Similarly for the others.
;
; Therefore, the Zxx routine needs to be modified so that it also references the lower byte.
;
        subb    zREG+1          ;* COMPARE
        bpl     PLUS
        comb                    ;* Turn the negative to a positive
        incb
        ;; Hi -1
        ;; and correct for negative
        ;; @TODO: 16 bit sub
        sec                     ;*
PLUS    sbca    zREG            ;* COMPARE
        ;; Problem, Z gets set if A is 00 and B is not 0 (sometimes)
        bne     DONE
        aba
DONE    rts
linuxha commented 6 days ago

Just found this on a Small C disk for the 6800:

  BCMP  TSX
        LDAA    2,X             ;* GET TOP OF STACK
        LDAB    3,X
        CMPA    zREG            ;* CHECK TOP BYTE
        BNE     BCMP1
        CMPB    zREG+1
  BCMP1 RTS

I'll test this later

zu2 commented 4 days ago

This method does not seem to work correctly for branches that refer to the N flag (BGE, BGT, BLE, BLT).

Let's look at the ZLT subroutine. Note that the comparison is done in two's complement.

BCMP TSX
LDAA 2,X ;* GET TOP OF STACK
LDAB 3,X
CMPA zREG ;* CHECK TOP BYTE
BNE BCMP1
CMPB zREG+1
BCMP1 RTS

ZLT BSR BCMP
BLT T
BRA F

The BCMP routine compares TOS and zREG starting from the upper byte.

As an example, we will use TOS:$0080 and zREG:$0000. In decimal, these are 128 and 0.

Since both upper byte are 0, BNE does not hold, so we compare the lower byte.

Subtract $00 from $80. The result is $80. The flags are N=1, C=V=Z=0.

Since N=1, V=0, the BLT is successful and the result is True.

Next, we use TOS:$007F and zREG:$0000. In decimal, these are 127 and 0.

This time the N flag is 0. Therefore, the BLT is not successful and the result is False.

The reason the results are different when the value is 128 and when the value is 127 is because the sign in the lower byte was looked at.

linuxha commented 4 days ago

I'll have another set of changes to cover that. Found a Small C disk with ccint.txt that splits the signed (SBCMP) and everything else (BCMP) but has a few changes for the < <= == != >= > functions also.

linuxha commented 3 days ago

Okay I've added an updated run0.asm . I've stolen ccint.txt from a Small C Flex Floppy. The ccint.asm has self modifying code and also looks a bit trimmer. I'm still reformatting it for use with the asl macro assembler (and to make it pretty). I'll add the rest of the code later but we now have a BCMP (unsigned) and SBCMP (signed) and changed <= == != >= > functions.

I also need to create a Small C program that I can toss into the sim6800 to test if all these changes really work as expected.