Page 1 of 2

6502 Emulation of ADC in C

Posted: Mon Jan 30, 2023 8:01 pm
by Sailor
Quote:
uint8_t m,a,c;---------// a=accumulator , m = some memory value , c = carry flag
int tmp_a;-------------------// to store a copy of accumulator
c=0;--------------------------// carry flag initial value
m=0x1;----------------------// memory variable initial value
a=0xFE;----------------------// accumulator variable initial value
tmp_a=a;--------------------// take a copy of accumulator contents
a+=m+c;--------------------// doing the usual addition with carry flag
tmp_a+=m+c;---------------// temporary var can hold a the actual result even if it exceeds 255
if (tmp_a>0xFF)-------------// so that we can check whether carry flag is set or not
c=1;
if (tmp_a<0xFF)
c=0;
I've made this code to emulate ADC (a general idea so far) , it looks a simple method
it works just fine as I tested it with a lot of values
it successfully sets and resets the carry flag
I just wonder is it a nice idea ? or it would affect the emulation's performance ?

Re: 6502 Emulation of ADC in C

Posted: Mon Jan 30, 2023 8:33 pm
by BigEd
It seems about right to me. Exactly what the performance will be depends very much on the compiler (and how much you ask it to optimise.)

I think personally I'd prefer to do the addition once, with the wider destination, and then transfer it to the actual narrow accumulator. But that's just a preference - you might be aiming to write very clear code, or to write very fast code. Probably you can't do both at once!

I should confess I'm a bit hazy on exactly what C specifies when you overflow a narrow result, in the signed and unsigned cases. I'd need to look it up.

Matt Godbolt's Compiler Explorer is a nice way to see the effects of small code changes
https://godbolt.org/

Re: 6502 Emulation of ADC in C

Posted: Mon Jan 30, 2023 8:47 pm
by Sailor
That's right , as an emulation's newbie , I will start to write very clear code at the beginning ,
Then , after I get a sufficient capabilities I would write the fastest one.

Re: 6502 Emulation of ADC in C

Posted: Mon Jan 30, 2023 11:01 pm
by Alarm Siren
BigEd wrote:
It seems about right to me. Exactly what the performance will be depends very much on the compiler (and how much you ask it to optimise.)

I think personally I'd prefer to do the addition once, with the wider destination, and then transfer it to the actual narrow accumulator. But that's just a preference - you might be aiming to write very clear code, or to write very fast code. Probably you can't do both at once!

I should confess I'm a bit hazy on exactly what C specifies when you overflow a narrow result, in the signed and unsigned cases. I'd need to look it up.

Matt Godbolt's Compiler Explorer is a nice way to see the effects of small code changes
https://godbolt.org/
In C unsigned overflow is defined to wrap around. Signed overflow is undefined / implementation specific.

Re: 6502 Emulation of ADC in C

Posted: Tue Jan 31, 2023 4:57 am
by BigEd
Thanks! (I'm not sure when I might start to remember it so clearly!)

Re: 6502 Emulation of ADC in C

Posted: Tue Jan 31, 2023 5:54 am
by barrym95838
You might consider the learning opportunity of attempting to make it more generally useful by emulating its effects regarding the other flags, i.e., N, V, Z and D. No pressure, though ... you should be encouraged to proceed at your own pace.

(If you change your [quote] and [/quote] to [code] and [/code] in your head post you can get a more desirable result.)

Re: 6502 Emulation of ADC in C

Posted: Tue Jan 31, 2023 8:50 am
by Alarm Siren
barrym95838 wrote:
*mulating
I see what you did there 8)

Re: 6502 Emulation of ADC in C

Posted: Tue Jan 31, 2023 2:09 pm
by BigEd
I wish we could get away from that whole thing. It would only take the goodwill of one person.

Re: 6502 Emulation of ADC in C

Posted: Tue Jan 31, 2023 2:59 pm
by Sailor
BigEd wrote:
I wish we could get away from that whole thing. It would only take the goodwill of one person.
OK .. I've ignored the negative posts
Thanks BigEd .

Re: 6502 Emulation of ADC in C

Posted: Wed Feb 01, 2023 10:08 am
by drogon
From the "more than one way to do it department", so just having a ponder over this in an otherwise idle moment... I think i'd use unsigned values all the way to lessen the potential for any sign extensions that might happen, and avoid tests and shifts, so something like:

Code: Select all

#include <stdio.h>
#include <stdint.h>

int main (void)
{
  uint8_t  a,m,c ;

  union
  {
    uint16_t t16 ;
    uint8_t  tt0 [2] ;
  } temp ;
  
  m = 0xFF ;  c = 0 ;  a = 0xFE ; // Test values

  temp.t16 = a + m + c ;
  a = temp.tt0 [0] ; 
  c = temp.tt0 [1] ; 
  
  printf ("A: %02X, M: %02X, C: %02X, temp: %04X\n", a, m, c, temp.t16) ;
  
  return 0 ;
} 
Test output:

Code: Select all

A: FD, M: FF, C: 01, temp: 01FD
The compiler ought to be able to optimise that into something quite efficient... Hopefully. :-)

-Gordon

Re: 6502 Emulation of ADC in C

Posted: Wed Feb 01, 2023 11:45 am
by Sailor
Hello Gordon
I tested your code , it is great

Update :

can your code be extended to test / set overflow flag as well ?

Re: 6502 Emulation of ADC in C

Posted: Fri Feb 03, 2023 1:47 pm
by drogon
Sailor wrote:
Hello Gordon
I tested your code , it is great

Update :

can your code be extended to test / set overflow flag as well ?
The overflow (V) flag is a somewhat tricky one and often mis-understood. I suggest you do a lot of reading and this is a good place to start:

http://www.righto.com/2012/12/the-6502- ... ained.html

Adapting my code to set it on an ADC - well, it's literally one line of code, but a somewhat complex line of code at that.

Adding this into the code would give you a true/false result:

Code: Select all

#include <stdio.h>
#include <stdint.h>

int main (void)
{
  uint8_t  a,m,c,v ;

  union
  {
    uint16_t t16 ;
    uint8_t  tt0 [2] ;
  } temp ;

  m = 0x7E ;  c = 0 ;  a = 0x82 ; // Test values

  temp.t16 = a + m + c ;

  v = (m ^ temp.t16) & (a ^ temp.t16) & 0x80 ;
  a = temp.tt0 [0] ;
  c = temp.tt0 [1] ;

  printf ("A: %02X, M: %02X, C: %02X, V: %02X, temp: %04X\n", a, m, c, v, temp.t16) ;
  printf ("   Carry: %s\n", c ? "Yes" : "No") ;
  printf ("Overflow: %s\n", v ? "Yes" : "No") ;

  return 0 ;
}
Note that this yields a true (non-zero) or false (zero) result. It's actually either 0X80 or 0x00, so don't test for 1 or 0. Do test it if you use it.

-Gordon

Re: 6502 Emulation of ADC in C

Posted: Fri Feb 03, 2023 3:32 pm
by Arlet
If you're using GCC, you may be able to use the builtin overflow functions.

https://gcc.gnu.org/onlinedocs/gcc/Inte ... ltins.html

If the platform supports it, these should be translated to native overflow flag detections.

Re: 6502 Emulation of ADC in C

Posted: Fri Feb 03, 2023 7:45 pm
by Sailor
@Gordon , your code is great as usual ,
I've already read a lot about overflow flag , and how to test it and got the following facts :

1. it occurs when adding two signed numbers with similar sign , resulting in a number different in sign .
2. it occurs when (carry in) bit different than (carry out) bit (bit6 through bit7) after the addition .
3. it's similar to carry flag test , except it's for signed numbers .

6502 don't care or even have recognition between signed OR unsigned numbers though
it maybe mean 0 - 127 are positive numbers , while 128 - 255 are negative (while testing for overflow) ?

@Arlet , Yes I am using TDM GCC 4.9.2 compiler with DEV C++ IDE
and that feature looks awesome , it would simplify the whole code a lot

Many thanks guys for your help .

Re: 6502 Emulation of ADC in C

Posted: Wed Feb 22, 2023 2:52 pm
by strik
@drogon, are you aware that your union and its usage assumes a little endian machine on which this code is running?

Using

Code: Select all

  a = temp.t16 & 0xFFu;
  c = (temp.t16 >> 8) & 0xFFu;
and, even better, getting rid of this union at all would be much more portable.
I hope the compiler will be able to optimize it to the same code on a little endian machine, and to a similar code on a big endian machine.

If there is a speed penalty, ANDing before the shift for c also help to use

Code: Select all

  c = (temp.t16 & 0xFF00u) >> 8;
instead, or

Code: Select all

  c = temp.t16 >= 0x100u;