reifsnyderb Posted September 26, 2023 Share Posted September 26, 2023 (edited) 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 September 26, 2023 by reifsnyderb 1 Quote Link to comment Share on other sites More sharing options...
Rybags Posted September 26, 2023 Share Posted September 26, 2023 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. 1 Quote Link to comment Share on other sites More sharing options...
reifsnyderb Posted September 26, 2023 Author Share Posted September 26, 2023 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? 2 Quote Link to comment Share on other sites More sharing options...
Rybags Posted September 26, 2023 Share Posted September 26, 2023 .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. 1 1 Quote Link to comment Share on other sites More sharing options...
TGB1718 Posted September 26, 2023 Share Posted September 26, 2023 @Teapot produced this, it makes using the help so much easier, just click on the command and it shows the help for each topic. Altirra410DebugHelp.html 3 2 Quote Link to comment Share on other sites More sharing options...
invisible kid Posted September 26, 2023 Share Posted September 26, 2023 Be sure to update us! Quote Link to comment Share on other sites More sharing options...
reifsnyderb Posted September 27, 2023 Author Share Posted September 27, 2023 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. Quote Link to comment Share on other sites More sharing options...
reifsnyderb Posted September 27, 2023 Author Share Posted September 27, 2023 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 Quote Link to comment Share on other sites More sharing options...
phaeron Posted September 27, 2023 Share Posted September 27, 2023 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 1 1 Quote Link to comment Share on other sites More sharing options...
reifsnyderb Posted September 27, 2023 Author Share Posted September 27, 2023 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. Quote Link to comment Share on other sites More sharing options...
dmsc Posted September 27, 2023 Share Posted September 27, 2023 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! 2 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.