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

All times are UTC




Post new topic Reply to topic  [ 9 posts ] 
Author Message
PostPosted: Mon Sep 06, 2021 11:54 am 
Offline

Joined: Sat Sep 04, 2021 9:47 am
Posts: 6
Hi, Second poster and after how helpful the first post was, I am hoping for some more gold!

I am writing an NES emulator, and at its core is a 6502 processor without decimal mode.

I have written a 6502 core, and am using an NESTEST cartridge image to test the 6502 behaviour. The test cart comes with a log output of key processor parameters and the idea is, you generate your own log and compare it to the supplied log for accuracy.

BTW apologies in advance if I get my terminology wrong or switch between Hexadecimal and Decimal. I will try to be clear.

I have read up on the overflow or V flag and have written a function that sets or clears the V flag after each ADC or SBC.

Here's what I have surmised.

The V flag is set when the result of ADC or SBC overflows beyond 0x80 for negative numbers or 0x7f for positive.

For additions and subtractions with a positive and negative number, this should never happen (128 negative values, and 128 non negative values (Not sure if 0 is classed as positive)).

For additions and subtractions where the signs are alike, its possible to add two negative values and get a positive value, and vice versa and therefore when this happens, the overflow / V flag is set.

I have written a function and tested it with the example values on 6502.org V-Flag essay, and the V-Flag seems to work fine.

However, when I look at the NESTEST cart output, the V Flag seems to be set under other circumstances. See output log below.

Code:
C94F  69 7F     ADC #$7F                        A:7F X:00 Y:00 P:25 SP:FB PPU:  5, 50 CYC:585 ; ADC Immediate Accumulator and 0x7f + Carry Flag
C951  10 0B     BPL $C95E                       A:FF X:00 Y:00 P:E4 SP:FB PPU:  5, 56 CYC:587 ; P now shows V flag as being set


The guys that write these test cart programs really know what they are doing, so I am inclined to believe that the output log they provide is correct, but it doesn't match with what I have read about the V flag behaviour.

with the example above, 0x7f is a positive number and 0x7f + carry is 0x80 , a negative number. This shouldn't come out as overflow.

In decimal its (+127) + (-128) = -1 or 0xff. The 0xff in the accumulator is correct, but the overflow flag has been set.

Can anyone explain why the V flag has been set in this case please?


Top
 Profile  
Reply with quote  
PostPosted: Mon Sep 06, 2021 12:15 pm 
Offline

Joined: Tue Sep 03, 2002 12:58 pm
Posts: 336
It's not adding $7f to $80 - it's adding $7f, $7f, and 1 (the carry). All of these are positive, so we'd expect a positive result. But we get $ff, which is negative, so that's an overflow.


Top
 Profile  
Reply with quote  
PostPosted: Mon Sep 06, 2021 12:22 pm 
Offline

Joined: Sat Sep 04, 2021 9:47 am
Posts: 6
John West wrote:
It's not adding $7f to $80 - it's adding $7f, $7f, and 1 (the carry). All of these are positive, so we'd expect a positive result. But we get $ff, which is negative, so that's an overflow.


Thank you so much.

This makes perfect sense. I have been handling them as two values, but should be handling as three values.

Thanks again!


Top
 Profile  
Reply with quote  
PostPosted: Mon Sep 06, 2021 12:25 pm 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
One of our forum members wrote several high quality 65xx tutorials. You may wish to refer to The Overflow (V) Flag Explained by Bruce Clark.

( Tutorials by him and other authors are listed at http://6502.org/tutorials/ )

-- Jeff

_________________
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html


Top
 Profile  
Reply with quote  
PostPosted: Tue Sep 07, 2021 1:48 am 
Offline
User avatar

Joined: Sat Dec 01, 2018 1:53 pm
Posts: 730
Location: Tokyo, Japan
Raandaall_Flaagg wrote:
(Not sure if 0 is classed as positive)

Well, if you're talking there about whether the 6502 classes zero as positive, you just need to ask yourself what `BPL` does when the last test tested a 0 value.

Raandaall_Flaagg wrote:
This makes perfect sense. I have been handling them as two values, but should be handling as three values.

Right. But you were handling them as three values at some point, so it's really more a question of where you handle the values. This misconception burned me as well in my 6800 simulator's first implementation of ADC and SBC. It originally looked like this:

Code:
def sub(m, minuend, subtrahend, affectC=True):             # `m` is the "machine" object
    # ...calculate, set flags, return result...

def suba(m):    m.a = sub(m, m.a, readbyte(m))             # immediate; readbyte(m) reads byte at PC++
def subaz(m):   m.a = sub(m, m.a, m.mem[readbyte(m)])      # zero page addressing
def sbca(m):    m.a = sub(m, m.a, readbyte(m)+m.C)         # adding because C is the "borrow" flag on 6800
def sbcaz(m):   m.a = sub(m, m.a, m.mem[readbyte(m)]+m.C)
# etc. for other addressing modes

(Side note: when comparing 6800 code with 6502 code, remember that the 6502 uses the C flag differently: when subtracting C is a "not borrow" flag on the 6502.)

You can probably now see the conceptual problem there in the structure of the simulator: the routine that does the arithmetic for subtract instructions doesn't do all of the arithemtic calculations; in the case of the SBC instruction some of the calculations are done outside that routine, before it is called. Thus the "ALU" doesn't actually see the original inputs, and what it sees as the subtrahend is sometimes not actually the real subtrahend. Oops!

The solution, of course, is to stop doing arithmetic on parameters outside of sub() and instead pass in all of the parameters:

Code:
def sub(m, minuend, subtrahend, borrow=0, affectC=True):
    ...
    # just one line added to the body:
    difference = incbyte(difference, -borrow)
    ...

def sbca(m):    m.a = sub(m, m.a, readbyte(m), borrow=m.C)
# etc.

In my case that alone, with no changes to the flag calculations in sub(), fixed the problem. (I was setting flags based on the equations handily provided by Motorola in their reference guide; the flags were wrong because I was calculating them based on the subtrahend plus the borrow, rather than the actual subtrahend.)

You may find it worthwhile having a look to see if your code design and/or something in your conception of your emulator's CPU model helped lead toward this bug, too, since such conceptual errors can lead to other bugs as well (either now or in the future when someone tweaks something).

_________________
Curt J. Sampson - github.com/0cjs


Top
 Profile  
Reply with quote  
PostPosted: Wed Sep 08, 2021 12:17 pm 
Offline

Joined: Sat Sep 04, 2021 9:47 am
Posts: 6
As always, Thank you very much for the useful help and advice!

@Dr Jefyll - Yes have had a look through some of the useful documents and have already probably answered my next two conundrums from them.

I can see that I have implemented the Stack incorrectly. I went for Intel 8080 style where the value is pushed to SP-1 and then SP is decremented by 1 to point at the value to be pulled from the stack first. I can see from the Stack essay that I should be pushing the value to SP, and then decrementing SP by 1 to point at the next available slot in the stack....

I have some coding to do! Thanks again.


Top
 Profile  
Reply with quote  
PostPosted: Wed Sep 08, 2021 3:05 pm 
Offline
User avatar

Joined: Sun Nov 01, 2020 10:36 am
Posts: 37
Location: Tatooine
The V flag is set when:
ADC: the operands have the same sign and the result has an opposite sign.
SBC: the operands have different signs and the result has the sign of the second operand.

otherwise the V flag is cleared.
The Carry flag doesn't 'belong' to any of the operands.


Top
 Profile  
Reply with quote  
PostPosted: Wed Sep 08, 2021 8:07 pm 
Offline

Joined: Sat Sep 04, 2021 9:47 am
Posts: 6
As I’m emulating, I’ve taken a more literal approach to the V Flag.

I do the ADC or SBC calculation without an 8 bit wrap, and if the result is less than -$80 or greater than $7f, the flag is set. Seems to work fine.


Top
 Profile  
Reply with quote  
PostPosted: Wed Sep 08, 2021 9:57 pm 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1949
Location: Sacramento, CA, USA
I think some efficiency can be gained if your host *mulator has a native ALU that's wider than eight bits, as long as you're careful about sign-extending the operands and trimming the results. I seem to recall reading about an ARM assembly language solution that shifted the 8-bit operands 24-bits to the left to facilitate the derivation of the condition codes.

_________________
Got a kilobyte lying fallow in your 65xx's memory map? Sprinkle some VTL02C on it and see how it grows on you!

Mike B. (about me) (learning how to github)


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 9 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 42 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: