Jump to content
IGNORED

Screwy 6502 ASM question.....


Recommended Posts

I have some code in a program I am working on.  A snippet is below:

 

 


                    LDA        #low    SCMB1        ; Get the destination address
                    STA        DSTADR
                    LDA        #high SCMB1
                    STA        DSTADR+1
                    
                    LDY        TSTRTL            ; Get the length of the text to copy
                    JSR        TXTCPY
    
                                                        ; Set pointer to screen memory
                    LDA        #low    (SCMB1 +10)
                    STA        P0VAR1
                    LDA        #high (SCMB1+10)
                    STA        P0VAR1+1
                    
                    JSR        NKGCH            ; Get numeric input from user
                    STA        PSTART            ; Store starting bank
nop
                                        
                    CPY        #$00
                    BEQ        CPART2            ; Exit if Esc key pressed (Y = $FF)

                    RTS
CPART2
                    CPX        #$00                    ; Check for overflow error
                    BEQ        CPART3
                                                        ; Process overflow error
                    ; ADD HERE

                    RTS
CPART3    
                    ;Print "End"
                    LDA        #low TEND        ; Get the source address
                    STA        SRCADR
                    LDA        #high TEND
                    STA        SRCADR+1

                    LDY        TENDL                ; Get the length of the text to copy
                    JSR        TXTCPY

 

 

Three lines above CPART2, I have a "nop" in lower case.  If I add the "nop" or any other instruction, the program works as it's supposed to.  Otherwise, the code fails.  I believe one of the RTS instructions are called, either right before CPART2 or right before CPART3.  But I haven't traced out which one.  Does somebody know what may be happening here?

 

Thanks!

 

Brian

 

 

 

 

 

 

Edited by reifsnyderb
  • Like 1
Link to comment
Share on other sites

NOP does nothing except burn cycles.  But can also have effect on offset for nearby branches and change address for subsequent instructions.

But what you have going on there looks normal enough.

CPX #0 type of thing is only needed if there were instructions since X was last modified that could have changed the P flags.

Checking a disassembly can help.  Stuff like landing addresses for JMP/JSR/branches being right, and working variables being in the right place, ie make sure you're not inadvertantly corrupting your own program.

Altirra can come in handy also - single step after halting the program via a read address trap.

  • Like 1
Link to comment
Share on other sites

4 minutes ago, Rybags said:

NOP does nothing except burn cycles.  But can also have effect on offset for nearby branches and change address for subsequent instructions.

But what you have going on there looks normal enough.

CPX #0 type of thing is only needed if there were instructions since X was last modified that could have changed the P flags.

Checking a disassembly can help.  Stuff like landing addresses for JMP/JSR/branches being right, and working variables being in the right place, ie make sure you're not inadvertantly corrupting your own program.

Altirra can come in handy also - single step after halting the program via a read address trap.

 

Thanks!  Is there a document to tell me how to set the read address trap and single step through the code?

 

 

 

 

  • Like 2
Link to comment
Share on other sites

.help in the Altirra debugger lists available commands.

 

There's other ways to do it but you can use BA R <address> which should stop execution when that address is read, including if it's part of the program itself.

Then you can just F11 to single step.

 

The old Atari AsmEd cart was not bad in this regard - it has the T and S commands in Debug to Trace or Step execution.

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

Ok.  It appears not all of the Altirra debugger is working when running on Linux w/Wine.  I am back to writing values to different page 6 addresses to see what's going on by examining the memory.  Of course, everything is working fine now and everything looks ok.  But, it does work when there's extra instructions. 

Link to comment
Share on other sites

Ok, I think I found the problem.

 

I ended up inserting code to write the values of A, X, and Y to different locations in page 6, depending upon where the CPART subroutine returned from.  (Part of CPART is in my original post.)  I found out that the subroutine was prematurely returning because it detected a non-existent overflow.  This had nothing to do with adding other instructions and, even though I tested it a few times, I think it was a pure coincidence.

 

After screwing around, with the program for a while while working on another aspect, it failed again.  Now I had some information to look at and discovered that X was set to $FF.  This led me back to take a close look at the last point whereby X would be set to indicate an overflow.  It was then that I realized it's entirely possible to have a zero in the buffer and the carry set at the same time.  In the code, I am using the carry flag to detect if I overflowed a value.  Here's the piece of code and what I added to fix the problem:

 

MDTHA = *                                    ; Math Decimal to Hex adder loop
                    CLC                                                                                       ;<-------------ADDED TO FIX PROBLEM
                    TYA                            ; Store index to buffer
                    PHA
    
                    TXA                            ; Copy Hex number to A
    
                    LDY        TMP1            ; Get the digit
MDTHA1
                    BEQ        MDTHA2        ; Exit if digit is 0
                    
                    CLC
                    ADC        TMP2            ; Add value of TMP2 to A
                    
                    DEY                            ; Decrement the digit
                    JMP        MDTHA1        ; Loop
MDTHA2                    

                    TAX                            ; Copy Hex number to X
                    PLA                            ; Retrieve index to buffer
                    TAY

                    BCC        MDTHA3        ; If carry is not set, skip
                    LDA        #$FF            ; Carry is set, there was an overflow
                    STA        TMP3
MDTHA3                    
                    RTS

 

 

So, if the digit in TMP1 is a 0, and the carry is set, the code jumps to MDTHA2 and sets TMP3 with $FF.  Before returning from the main subroutine, X is loaded with TMP3 then evaluated to determine if there was an overflow.

 

This subroutine is called from another subroutine.  Both subroutines are used to convert decimal numbers, in a buffer of up to 3 digits, to hexadecimal.  I was looking for a way to do this and realized that for what I was doing it would be easy to do the following:

 

Start from the right number in the buffer, loop to add ones to a value.  Move left to the next number and loop to add tens to a value.  Finally, move left to the next number and add 100's to the value.  In the above code, TMP2 is either 1, 10, or 100 (in decimal).

 

Here's the entire code to do this:

 

; Math -- Decimal to Hex
; P0VAR1, P0VAR2 = pointer to buffer
; A = number of digits to convert - 1 (zero based)
; Result in A
; Overflow error in X -- $00 is good, $FF is overflow
MDTH = *
                    LDX         #$00                ; Use X for Hex number
                    TAY                            ; Use Y as index to buffer
                    
                    STX        TMP3            ; Use TMP3 to indicate an overflow
                                                    ; Set to $00 to default as ok
                    
                    ; Start with ones place
                    LDA        (P0VAR1),Y    ; Load digit
                    STA        TMP1            ; Store digit in TMP1
                    LDA        #$01                ; Set MDTHA to add 1
                    STA        TMP2
                    JSR        MDTHA        ; Increment for one's place
                    CPY        #$00                ; Is this the last digit?
                    BEQ        MDTH1            ; Yes, exit
                    DEY                            ; Go to next digit

                    ; Do tens place
                    LDA        (P0VAR1),Y    ; Load digit
                    STA        TMP1            ; Store digit in TMP1
                    LDA        #$0A            ; Set MDTHA to add 10
                    STA        TMP2
                    JSR        MDTHA        ; Increment for tens's place
                    CPY        #$00                ; Is this the last digit?
                    BEQ        MDTH1            ; Yes, exit
                    DEY                            ; Go to next digit
                    
                    ; Do hundreds place
                    LDA        (P0VAR1),Y    ; Load digit
                    STA        TMP1            ; Store digit in TMP1
                    LDA        #$64                ; Set MDTHA to add 100
                    STA        TMP2
                    JSR        MDTHA        ; Increment for hundreds place
MDTH1
                    TXA                            ; Copy Hex number to A
                    LDX        TMP3            ; Get the overlow status

                    RTS


MDTHA = *                                    ; Math Decimal to Hex adder loop
                    CLC
                    TYA                            ; Store index to buffer
                    PHA
    
                    TXA                            ; Copy Hex number to A
    
                    LDY        TMP1            ; Get the digit
MDTHA1
                    BEQ        MDTHA2        ; Exit if digit is 0
                    
                    CLC
                    ADC        TMP2            ; Add value of TMP2 to A
                    
                    DEY                            ; Decrement the digit
                    JMP        MDTHA1        ; Loop
MDTHA2                    

                    TAX                            ; Copy Hex number to X
                    PLA                            ; Retrieve index to buffer
                    TAY

                    BCC        MDTHA3        ; If carry is not set, skip
                    LDA        #$FF            ; Carry is set, there was an overflow
                    STA        TMP3
MDTHA3                    
                    RTS

 

 

 

Link to comment
Share on other sites

If what you're doing is taking digits as loose byte values $00-09 and accumulating them into a single binary byte value, you could probably use a shift-and-add routine to multiply by 10:

 

CMP #26         ;max that can fit is 25*10 = 250
BCS overflow
STA temp
ASL             ;x2
ASL             ;x4
ADC temp        ;x5
ASL             ;x10
ADC (ptr),Y     ;add next digit
BCS overflow    ;overflow only possible with 250+digit

 

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

44 minutes ago, phaeron said:

If what you're doing is taking digits as loose byte values $00-09 and accumulating them into a single binary byte value, you could probably use a shift-and-add routine to multiply by 10:

 

CMP #26         ;max that can fit is 25*10 = 250
BCS overflow
STA temp
ASL             ;x2
ASL             ;x4
ADC temp        ;x5
ASL             ;x10
ADC (ptr),Y     ;add next digit
BCS overflow    ;overflow only possible with 250+digit

 

Thanks!  I was wondering how to multiply by 10 with base 2 math.  Admittedly, I didn't do much searching on it as I was looking at a way to convert from decimal to hex.  What I found was rather lengthy.  I do need to go all the way to 255, however.

Link to comment
Share on other sites

Hi!

8 hours ago, reifsnyderb said:

Thanks!  I was wondering how to multiply by 10 with base 2 math.  Admittedly, I didn't do much searching on it as I was looking at a way to convert from decimal to hex.  What I found was rather lengthy.  I do need to go all the way to 255, however.

The code posted by phaeron does go up to 255, and jumps to "overflow" if the result is 256 or bigger.

 

You need to call it multiple times until there are no more digits.

 

Have Fun!

  • Like 2
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...