6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Fri Nov 22, 2024 7:20 pm

All times are UTC




Post new topic Reply to topic  [ 23 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Comparing Memory
PostPosted: Wed May 25, 2011 12:00 am 
Offline

Joined: Tue May 24, 2011 11:24 pm
Posts: 6
Hi, I'm new to the forum and have only been programming in 6502 assembly language for about a year now. I've been teaching myself for the most part and have visited here from time to time searching for information. My ongoing project is a game I'm writing for the Vic 20 computer. I have been working on a routine to add an extra man or take one away when you lose one. I want it to count up to 99 and stop or count down to zero and stop. The addition is fine. It counts to 99 and stops, but the count down I start at 99 and it stops at 96. Here is the code:
Code:
player_left=    $f0
screen     =    $1e00   

*=$1d00

init
    lda #$39
    sta player_left
    sta player_left+1

example
    jsr store_it
    jsr sub_one
    jsr delay
    jmp example

store_it
    ldx #$01
next_location
    lda player_left,x
    sta screen,x
    dex
    bpl next_location
    rts   
   
add_one
    lda player_left
    and player_left+1
    cmp #$39   
    beq add1_done
    inc player_left+1
    lda player_left+1
    cmp #$3a
    bcc add1_done   
    lda player_left+1
    sbc #$0a   
    sta player_left+1
    inc player_left
add1_done
    rts

sub_one
    lda player_left
    and player_left+1
    cmp #$30
    beq sub1_done
    dec player_left+1
    lda player_left+1
    cmp #$30
    bcs sub1_done   
    lda player_left+1
    adc #$0a   
    sta player_left+1
    dec player_left
sub1_done
    rts

delay
    ldy #$00
loop1
    ldx #$00
loop2
    inx
    bne loop2
    iny
    bne loop1
    rts


I 'AND' the 2 memory locations together checking to see if they are the same. Then, I check to see if it is zeros(screen code for zero is $30) or 9's for sub_one or add_one respectively. Any ideas why the add_one works and the sub_one doesn't? Right now the routine is set up to test the sub_one part.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed May 25, 2011 2:51 am 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
Welcome greyghost. I hope you're enjoying your introduction to the 6502! I am reminded of my own early experiences with the chip -- a happy and exciting time for me, and for you too I bet.

Quote:
I 'AND' the 2 memory locations together checking to see if they are the same.
This reasoning needs a little more thought, I'm afraid. For example it's true you can AND $39 with $39 and get a result of $39. However you also could AND $FF with $39 with the result still being $39. ($FF is only one of several examples.) In other words the test you're using doesn't really allow you to "see if they are the same." (What it does is see whether they both have bit0 set, bit3 set, bit4 set and bit5 set.)

Ironically, this mistake will cause trouble only for your sub_one routine -- not the add_one routine. Forgive me if I don't explain further and give you ALL the details! But be aware that your AND test doesn't prove equality as you hoped it would. You'll get it! The rest of the code is perfectly workable, but could use some comments.

cheers,

Jeff
ps- Examine your final iteration of sub_one (the iteration that erroneously concludes no decrement should occur). The least significant byte, player_left+1, = $36. The MSB, player_left, = $39. $39 AND $36 = $30, the value which sub_one's CMP# looks for.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed May 25, 2011 8:03 am 
Offline
User avatar

Joined: Tue Mar 02, 2004 8:55 am
Posts: 996
Location: Berkshire, UK
You might also consider other approaches, like using a single BCD byte to store the lifes - much easier to increment and decrement - and extract the hi and lo nybbles when you need them.

_________________
Andrew Jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed May 25, 2011 12:13 pm 
Offline

Joined: Tue May 24, 2011 11:24 pm
Posts: 6
Ah yes, I do get it, as you said that bit pair will show up in quite a few numbers, especially if I counted from 0 to 255. I went a more conventional route and came up with this:
Code:
add_one
    lda #$39
    cmp player_left
    bne then_add1   
    cmp player_left+1
    beq add1_done
then_add1
    inc player_left+1
    lda player_left+1
    cmp #$3a
    bcc add1_done   
    lda player_left+1
    sbc #$0a   
    sta player_left+1
    inc player_left
add1_done
    rts

sub_one
    lda #$30
    cmp player_left
    bne then_sub1
    cmp player_left+1
    beq sub1_done
then_sub1
    dec player_left+1
    lda player_left+1
    cmp #$30
    bcs sub1_done   
    lda player_left+1
    adc #$0a   
    sta player_left+1
    dec player_left
sub1_done
    rts


This one checks the numbers exactly. Even though the add_one routine worked the way it was, I changed it so it would be correct. I might want to use the routine some where else. It cost me an extra 4 bytes, but hey I got 3.5k to work with. :D

I might actually try to redo this using BCD. It will make the code alot smaller. Just what a Vic programmer needs. As long as I SED and CLD in each routine, it won't effect any other part of the program, right?

I appreciate the learning experience instead of just spitting out some code for me. Makes me think.

Thanks guys,

Rob


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed May 25, 2011 8:37 pm 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
greyghost wrote:
Ah yes, I do get it, as you said that bit pair will show up in quite a few numbers, especially if I counted from 0 to 255.
Right. With your old code there are quite a few possible matches, only one of which is the value you had in mind. The sneaky thing about this is that all the unintended matches are larger numbers than the intended match. Therefore it makes a difference whether you're counting up or down. Your old add_one routine counts up, thus guarantying that you'll hit the "correct" value before ever reaching the larger numbers. Unfortunately the sub_one routine, which counts down, hits one of the unintended matches first.

As an aside, I'll mention that add_one is an example of "code that shouldn't work -- but does!" That sort of thing can have a programmer tearing their hair out sometimes! It can lead you to false conclusions while debugging... and a result in a real wild goose chase. All part of the fun of programming! :D

Quote:
I might actually try to redo this using BCD. It will make the code alot smaller. Just what a Vic programmer needs. As long as I SED and CLD in each routine, it won't effect any other part of the program, right?
Yeah, you should be fine. Just be aware that in Decimal Mode the status flags (eg: N and V) have some wrinkles to watch out for, especially on an NMOS chip. I'm not up on the details, but there's a good reference here. Also, in future, should you ever write an interrupt service routine (or power-up reset code for an NMOS '02), it is usually imperative that you assume the mode to initially be unknown. If you fail to explicitly set or reset Decimal Mode then you risk experiencing an intermittent bug, potentially a nightmare to track down.

-- Jeff


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed May 25, 2011 8:56 pm 
Offline
User avatar

Joined: Tue Mar 02, 2004 8:55 am
Posts: 996
Location: Berkshire, UK
greyghost wrote:
I might actually try to redo this using BCD. It will make the code alot smaller. Just what a Vic programmer needs. As long as I SED and CLD in each routine, it won't effect any other part of the program, right?

When you try the BCD option remember the LDA instruction sets the Z flag if the byte loaded was zero - makes it easy to test if the life count is zero before you try to decrement it - and adding $01 to $99 in BCD mode will result also result in Z being set - so you can easily detect when incrementing causes an overflow.

_________________
Andrew Jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu May 26, 2011 12:32 pm 
Offline

Joined: Tue May 24, 2011 11:24 pm
Posts: 6
I tried doing a BCD version last night. I don't have the code on hand but was wondering about something. Normally when extracting the nibbles to be displayed on the screen, for the low nibble I would AND #$0f to get it and the high nibble I would LSR 4 times and get that one. Will these work correctly in BCD? Would I do this with the decimal flag still set or can I do it after I clear it and get the same results? I think I read somewhere that when you shift bits in BCD that the resulting number turns to hex.

Any thoughts?


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu May 26, 2011 1:10 pm 
Offline
User avatar

Joined: Tue Mar 02, 2004 8:55 am
Posts: 996
Location: Berkshire, UK
greyghost wrote:
I tried doing a BCD version last night. I don't have the code on hand but was wondering about something. Normally when extracting the nibbles to be displayed on the screen, for the low nibble I would AND #$0f to get it and the high nibble I would LSR 4 times and get that one. Will these work correctly in BCD? Would I do this with the decimal flag still set or can I do it after I clear it and get the same results? I think I read somewhere that when you shift bits in BCD that the resulting number turns to hex.

Any thoughts?

The decimal flag only affects ADC and SBC instructions. Increments, decrements, logical functions (ORA, EOR, AND), shifts and rotates are always binary.

_________________
Andrew Jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu May 26, 2011 3:51 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8505
Location: Midwestern USA
...deleted...

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Last edited by BigDumbDinosaur on Fri May 27, 2011 6:01 pm, edited 1 time in total.

Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu May 26, 2011 3:53 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8505
Location: Midwestern USA
greyghost wrote:
I tried doing a BCD version last night. I don't have the code on hand but was wondering about something. Normally when extracting the nibbles to be displayed on the screen, for the low nibble I would AND #$0f to get it and the high nibble I would LSR 4 times and get that one. Will these work correctly in BCD? Would I do this with the decimal flag still set or can I do it after I clear it and get the same results? I think I read somewhere that when you shift bits in BCD that the resulting number turns to hex.

Any thoughts?

Code:
;display numerals in BCD digit -- digit in .A
;
PHA
LSR A
LSR A
LSR A
LSR A
ORA #%00110000
JSR BSOUT          ;character out sub -- display 10s
PLA
AND #%00001111
ORA #%00110000
JSR BSOUT          ;display units

As Daryl pointed out, BCD mode only affects addition and subtraction. Shifts, rotates and logical operations (AND, OR, etc.) always produce binary results. Hence the above code correctly works whether in BCD or binary mode.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu May 26, 2011 4:19 pm 
Offline

Joined: Tue Jul 05, 2005 7:08 pm
Posts: 1043
Location: near Heidelberg, Germany
BitWise wrote:
The decimal flag only affects ADC and SBC instructions. Increments, decrements, logical functions (ORA, EOR, AND), shifts and rotates are always binary.


Just a quick question. CMP (CPY, CPX) is internally implemented as an SBC. Is it affected as well?

André


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Fri May 27, 2011 12:49 am 
Offline

Joined: Tue May 24, 2011 11:24 pm
Posts: 6
This has kinda deviated from the original subject. This is what I have come up with, with all the help of course. :wink:

Code:
player_left=    $f0
screen     =    $1e00   

*=$1d00

init
    lda #$99            ;a = 99
    sta player_left     ;store in player_left

example
    jsr store_it        ;gosub store_it
    jsr sub_one         ;gosub sub_one
    jsr delay           ;gosub delay
    jmp example         ;goto example

store_it
    lda player_left     ;put player count into a
    and #$0f            ;mask off upper 4 bits
    ora #$30            ;effectively add $30 to it for display code
    sta screen+1        ;store it in screen location
    lda player_left     ;get player count again
    lsr                 ;shift right
    lsr                 ;shift right
    lsr                 ;shift right
    lsr                 ;shift right
    ora #$30            ;effectively add $30 to it for display code
    sta screen          ;store it in screen location   
    rts                 ;return

add_one
    sed                 ;set decimal mode
    lda player_left     ;get player count
    cmp #$99            ;is it 99?
    bcs add1_done       ;yes? then goto add1_done
    adc #$01            ;else add 1(carry already clear)
    sta player_left     ;store it back in player count
add1_done
    cld                 ;clear decimal mode
    rts                 ;return

sub_one
    sed                 ;set decimal mode
    lda player_left     ;get player count
    beq sub1_done       ;is it 0? yes? goto sub1_done
    sec                 ;else set carry
    sbc #$01            ;subtract 1 from player count
    sta player_left     ;store it back in player count
sub1_done
    cld                 ;clear decimal mode
    rts                 ;return

delay
    ldy #$00            ;simple delay loop
loop1
    ldx #$00            ;
loop2
    inx                 ;
    bne loop2           ;
    iny                 ;
    bne loop1           ;
    rts                 ;


A savings from the first version of 19 bytes.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Fri May 27, 2011 9:06 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10985
Location: England
fachat wrote:
BitWise wrote:
The decimal flag only affects ADC and SBC instructions. Increments, decrements, logical functions (ORA, EOR, AND), shifts and rotates are always binary.


Just a quick question. CMP (CPY, CPX) is internally implemented as an SBC. Is it affected as well?

André
Not according to Bruce


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Fri May 27, 2011 9:29 am 
Offline
User avatar

Joined: Tue Mar 02, 2004 8:55 am
Posts: 996
Location: Berkshire, UK
You can simplify the increment:
Code:
add_one
    sed                 ;set decimal mode
    clc
    lda player_left     ;get player count
    adc #$01            ;add 1
    beq add1_done   ; Rolled over from 99 -> 00?
    sta player_left     ;No, store it back in player count
add1_done
    cld                 ;clear decimal mode
    rts                 ;return

_________________
Andrew Jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Fri May 27, 2011 11:58 am 
Offline

Joined: Tue May 24, 2011 11:24 pm
Posts: 6
If the tutorial mentioned above is correct, then that will not be true. Unless I miss read it.

Quote:
However, the N and Z flags do have meaning as described above. What is meant by valid is that the N and Z flags will match the result in the accumulator. For example, on a 6502, after:

SED ; Decimal mode
SEC
LDA #$01
SBC #$01

the accumulator will be $00, and the Z flag will be 1, which matches the result in the accumulator. But after:

SED ; Decimal mode
CLC
LDA #$99
ADC #$01

the accumulator will be $00, but the Z flag will be 0, which does not match the result in the accumulator. So sometimes the Z flag will be correct (in the sense of matching the accumulator), and sometimes it will not. The same is true of the N flag on a 6502


I will try it anyways and see what results I get. A byte saved is a byte saved. :D


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 23 posts ]  Go to page 1, 2  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 16 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: