6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Thu Apr 25, 2024 9:10 pm

All times are UTC




Post new topic Reply to topic  [ 10 posts ] 
Author Message
PostPosted: Thu Nov 06, 2014 3:12 pm 
Offline

Joined: Wed Jun 25, 2014 4:28 pm
Posts: 21
Hi,

Earlier this year I posted about my KIM Uno, a handheld KIM-I clone extended
with a 6502 programmable calculator mode (based on CR Bond's fltpt65).
Also added are microchess and 6502 disassembler in ROM.

The first batch of 75 kits has been sent out, so I'm sampling interest for a second run.
(just to make sure: this is done as a strictly non-profit hobby project)

Costs: $10 for the kit (board & parts). Using Paypal adds $1.50 to that.
Plus shipping: $10 Europe or $15 Rest-of-World.

The Uno uses an atMega328, running Mike Chambers' 6502 emulator.
PCB gerbers and firmware will remain on my web site if anyone wants to create the board afterwards.

Here is the site:
http://obsolescence.wix.com/obsolescence#!kim-uno-summary/c1uuh
And here's the subpage on the 6502 programmable calculator part I'm particularly proud of :) :
http://obsolescence.wix.com/obsolescence#!kim-uno-calculator/cgru

Some pictures:
Image

If you're interested, please leave a message here:
http://obsolescence.wix.com/obsolescence#!contact/con8.

Regards,

Oscar.


Top
 Profile  
Reply with quote  
PostPosted: Thu Nov 06, 2014 11:48 pm 
Online
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1926
Location: Sacramento, CA, USA
That's a nice looking unit! If you plan to experiment with BCD arithmetic, be aware that Mike Chambers' emulation does not do it properly (at least the version that I downloaded doesn't).

viewtopic.php?f=8&t=2819&p=31420&hilit=Mike+Chambers#p31420

Modifying the code to produce correct results is left as an exercise for the reader, but I could be convinced to give it a try if nobody else volunteers.

Mike


Top
 Profile  
Reply with quote  
PostPosted: Fri Nov 07, 2014 3:39 am 
Online
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1926
Location: Sacramento, CA, USA
I decided to give it a try, and I think that I got it, but need to run some tests to be sure.

Here is Mike Chambers' adc():
Code:
static void adc() {
    penaltyop = 1;
    value = getvalue();
    result = (uint16_t)a + value + (uint16_t)(status & FLAG_CARRY);

    carrycalc(result);
    zerocalc(result);
    overflowcalc(result, a, value);
    signcalc(result);

    #ifndef NES_CPU
    if (status & FLAG_DECIMAL) {
        clearcarry();

        if ((a & 0x0F) > 0x09) {
            a += 0x06;
        }
        if ((a & 0xF0) > 0x90) {
            a += 0x60;
            setcarry();
        }

        clockticks6502++;
    }
    #endif

    saveaccum(result);
}


and here's my attempted correction:
Code:
static void adc() {
    penaltyop = 1;
    value = getvalue();
    result = (uint16_t)a + value + (uint16_t)(status & FLAG_CARRY);

    zerocalc(result);
    overflowcalc(result, a, value);
    signcalc(result);

    #ifndef NES_CPU
    if (status & FLAG_DECIMAL)       /* detect and apply BCD nybble carries */
        result += ((((result + 0x66) ^ (uint16_t)a ^ value) >> 3) & 0x22) * 3;
    #endif

    carrycalc(result);
    saveaccum(result);
}


I'm gonna take it for a spin to try to see if it works for all possible 2^17 inputs, but I certainly welcome any comments or critiques. I am trying to duplicate the original NMOS flag behavior here.

Mike


Top
 Profile  
Reply with quote  
PostPosted: Fri Nov 07, 2014 9:57 am 
Offline

Joined: Wed Jun 25, 2014 4:28 pm
Posts: 21
Mike,

Yes, I learned about BCD not being handled yet in the emulator correctly the hard way - I fixed it, although my fix looks a lot more verbose than yours. I'll give your variant a try!

When I say 'the hard way', that's because I was struggling with two small bugs in the fltpt65 code at the same time. So it took me a while to figure out it was two separate issues I was debugging...

In case anyone else is working on fltpt65 (which is quite a coding masterpiece): last time I checked, Charles Bond had not updated the source on his site yet. There's two small bugs, one of which only occurs when you relocate the code. The KIM Uno sources on my site have a corrected version. That also goes for the BCD buglet in Mike Chambers' 6502 emulator.

Kind regards,

Oscar.


Top
 Profile  
Reply with quote  
PostPosted: Fri Nov 07, 2014 12:34 pm 
Offline

Joined: Wed Jun 25, 2014 4:28 pm
Posts: 21
barrym95838 wrote:
I decided to give it a try, and I think that I got it, but need to run some tests to be sure.


I have to spend some brain cycles to understand your very concise BCD fix. One immediate question is re the flags under BCD. The way I understood it (not necessarily the way it is!), Negative and Overflow flags are never set in BCD mode?

Here is my significantly more horrible BCD fix for ADC:

Code:
void adc()
{
    value = getvalue();

    if ((cpustatus & FLAG_DECIMAL)==0)
    {
          result = (uint16_t)a + value + (uint16_t)(cpustatus & FLAG_CARRY);

          carrycalc(result);
          zerocalc(result);
          overflowcalc(result, a, value);
          signcalc(result);
    }   
    else  // Decimal mode
    {   
          lxx = (a & 0x0f) + (value & 0x0f) + (uint16_t)(cpustatus & FLAG_CARRY);
          if ((lxx & 0xFF) > 0x09) lxx += 0x06;
          hxx = (a >> 4) + (value >> 4) + (lxx > 15 ? 1 : 0);
          if ((hxx & 0xff) > 9) hxx += 6;
          result = (lxx & 0x0f);
          result += (hxx << 4);
          result &= 0xff;

          // deal with flags:
          if (hxx>15) setcarry();
          else clearcarry();
          zerocalc(result);
          clearsign();   // negative flag never set for decimal mode.
          clearoverflow();   // overflow never set for decimal mode.

          clockticks6502++;
    }
    saveaccum(result);
}


Did you look at SBC as well? It has the same issue.

Regards,

Oscar.


Top
 Profile  
Reply with quote  
PostPosted: Fri Nov 07, 2014 1:55 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10793
Location: England
There's just been an exploration of BCD in the jsbeeb emulator: there are useful tips and experiences to be found at
http://stardot.org.uk/forums/viewtopic.php?f=4&t=8793

Cheers
Ed


Top
 Profile  
Reply with quote  
PostPosted: Fri Nov 07, 2014 2:37 pm 
Offline

Joined: Wed Jun 25, 2014 4:28 pm
Posts: 21
BigEd wrote:
There's just been an exploration of BCD in the jsbeeb emulator

I never realised BCD was such a stumbling block. Half of the 6502 emulators I tested broke on the BCD code in fltpt65. Including very nice ones like Mayrat Fayzullin's M6502 and Piumarta's lib6502.

Regards,

Oscar.


Top
 Profile  
Reply with quote  
PostPosted: Sat Nov 08, 2014 3:37 am 
Online
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1926
Location: Sacramento, CA, USA
oscarv wrote:
I have to spend some brain cycles to understand your very concise BCD fix.

I can't take credit for the exclusive-or magic ... that came from elsewhere. What it (hopefully) does is simultaneously detect both nybble carries in bits 8 and 4 of result, then shift, mask, and convert them to sixes or zeros to be added to the appropriate place ($00, $06, $60, or $66). I still need to whip out a test suite for it ... darn full-time job, always getting in the way of my fun!

Quote:
One immediate question is re the flags under BCD. The way I understood it (not necessarily the way it is!), Negative and Overflow flags are never set in BCD mode?

Yeah, my comment about flag behavior was a bit hasty, and was based on my foggy recollection that flags were changed as in binary ADC, but only carry was guaranteed to be valid. I could be wrong. I also have not carefully studied the effects of invalid BCD bit patterns on my code.

Quote:
Here is my significantly more horrible BCD fix for ADC:
Code:
... [snip] ...

Hey, if it gets the job done, I don't see anything wrong with it. My proposed solution looks shorter in C, but it may well be longer than yours after compiling.
Quote:
Did you look at SBC as well? It has the same issue.

Sorry, I did not. I forgot how Mike Chambers did it, but my 65m32 emulator's sbc() just checks the D flag, takes the one's complement or nine's complement of the operand, and passes everything off to adc(). Isn't that how the original NMOS hardware did it as well? I'm not sure ...
Code:
static void sbc() {
    value = ~getvalue() & 0x00ff;

    #ifndef NES_CPU
    if (status & FLAG_DECIMAL)
        value = (0x0099 - ~value) & 0x00ff;
    #endif

    adc();
}

Meh, that won't work, will it, because adc() calls getvalue() again, dang it! It works in my 65m32 emulator (er, simulator), because my instruction dispatcher does more pre- and post- processing work than Mike Chambers' does. A lot of my instruction simulator functions contain one statement!
Code:
static void plp(void) {
    p = pull(STACK_PTR);
}

static void rti(void) {
    plp();
    branch(pull(STACK_PTR));
}

static void php(void) {
    push(p);
}

static void rep(void) {
    p &= ~operand;
}

static void sep(void) {
    p |= operand;
}

static void sta(void) {
    operand = A;
}

static void stx(void) {
    operand = X;
}

static void sty(void) {
    operand = Y;
}

static void stz(void) {
    operand = Z;
}


Mike


Top
 Profile  
Reply with quote  
PostPosted: Fri Nov 14, 2014 3:18 am 
Offline
User avatar

Joined: Mon Apr 23, 2012 12:28 am
Posts: 760
Location: Huntsville, AL
Oscar/Mike:

Let's try this again. I meant to post a response to this thread a few days ago but work intervened. I wanted to offer up the model that I used to validate the BCD operation of my 65C02 cores. It is in Verilog, but should be easily translated into C/C++.

The model supports BCD addition/subtraction and generates the digit adjustments as needed to pass Klaus' BCD tests. I've posted the arithmetic unit model below, and I'll provide some commentary below the source in the hope that you may be able to use its algorithm in your project:
Code:
////////////////////////////////////////////////////////////////////////////////
//
//  Test Adder Unit (AU)
//

//  Task AU_Model provides a logical model of the binary/decimal mode adder that
//      is implemented in the UUT. Its purpose is not to functionally represent
//      the implementation in the UUT, but to logically compute the expected
//      outputs (sum and status) for the various operations that the UUT adder
//      is expected to perform.

task AU_Model;
    input   iOp;
    input   [7:0] iA, iB;
    input   [7:0] iPSW;
    input   [7:0] iMsk;
    output  [7:0] oSum;
    output  [7:0] oPSW;
   
    reg     D, Ci;
    reg     [4:0] LSN, MSN;
    reg     [7:0] A, B, ALU;
    reg     C7, C3;
    reg     N, V, Z, C;     

begin
    D  = iPSW[3];
    Ci = iPSW[0];
    A  = iA;
    B  = ((iOp) ? ~iB : iB);

    if(D) begin         // Decimal Mode Operations
        if(iOp) begin   // Decimal Mode Subtraction
            LSN[4:0] = A[3:0] + B[3:0] + Ci;
            C3       = LSN[4] & ~(LSN[3] & (LSN[2] | LSN[1]));
            ALU[3:0] = ((C3) ? (LSN[3:0] + 0) : (LSN[3:0] + 10));

            MSN[4:0] = A[7:4] + B[7:4] + C3;
            C7       = MSN[4] & ~(MSN[3] & (MSN[2] | MSN[1]));
            ALU[7:4] = ((C7) ? (MSN[3:0] + 0) : (MSN[3:0] + 10));       
        end else begin  // Decimal Mode Addition
            LSN[4:0] = A[3:0] + B[3:0] + Ci;
            C3       = LSN[4] | (LSN[3] & (LSN[2] | LSN[1]));
            ALU[3:0] = ((C3) ? (LSN[3:0] + 6) : (LSN[3:0] + 0));

            MSN[4:0] = A[7:4] + B[7:4] + C3;
            C7       = MSN[4] | (MSN[3] & (MSN[2] | MSN[1]));
            ALU[7:4] = ((C7) ? (MSN[3:0] + 6) : (MSN[3:0] + 0));
        end

        N = ALU[7]; V = ((Op) ? ~C7 : C7); Z = ~|ALU; C = C7;
    end else begin      // Binary Mode Operations
            LSN[4:0] = A[3:0] + B[3:0] + Ci;
            C3       = LSN[4];
            ALU[3:0] = LSN[3:0];

            MSN[3:0] = A[6:4] + B[6:4] + C3;
            MSN[4]   = (MSN[3] & (A[7] ^ B[7]) | (A[7] & B[7]));
            C7       = MSN[4];
            ALU[7:4] = {A[7] ^ B[7] ^ MSN[3], MSN[2:0]};       

            N = ALU[7]; V = (MSN[4] ^ MSN[3]); Z = ~|ALU; C = C7;
     end
   
    oSum = ALU;
    oPSW = ((iPSW & ~iMsk) | ({N, V, 4'b0, Z, C} & iMsk));
end

endtask;

A Verilog task is equivalent to a Pascal procedure. Verilog's syntax is a bit primitive, so the input/output statements at the top provide an ordered list of the task's parameter list. Following that is a declaration of a number of local variables.

The operation of the module is controlled by the iOp input: 1 - subtraction; 0 - addition. The left input operand, iA, is assigned to the local variable A, and the right input operand, iB, is assigned to B. iB is directly assigned for addition operations and the complement of iB is assigned to B when a subtraction is to take place. The D flag and the C flag are extracted from the input PSW. The D flag is used to select one of two groups of equations: the BCD group and the binary group. The C flag will be added into the sum/difference.

A five bit sum is performed for the lower and upper nibbles. They are performed in sequence in order to generate and preserve the nibble carries, C3 (low nibble) and C7 (high nibble). The unadjusted sums are maintained in the variables LSN (least significant nibble) and MSN (most significant nibble).

The key to the implementation are the generation of C3 and C7. These signals are formed by the binary mode carries (LSN[4] and MSN[4]), plus an equation that determines if the nibble value is greater than 9. Notice that for SBC the adjustment factor applied to each nibble, if required, is 10, and that for ADC, the adjustment factor applied to each nibble, ir required, is 6. Also notice in that the application of a nibble adjustment is complementary between subtraction and addition.

Don't pay any mind to the two values that assigned the N and V flags for BCD mode operations. From my recollection, Klaus' test programs doesn't try to test and enforce any specific behavior on these two flags for BCD mode operations. The C and Z flags are set appropriately, but the values that I assign to N and V are just those that I considered appropriate. N is set according the value of the most significant bit as it would in a two's complement binary mode operation. V is set in BCD mode if there is a carry out, which means that it is essentially the same as the C flag.

_________________
Michael A.


Top
 Profile  
Reply with quote  
PostPosted: Mon Nov 17, 2014 12:58 pm 
Offline

Joined: Wed Jun 25, 2014 4:28 pm
Posts: 21
Michael (A):

Thanks! The algorithm is more concise than the one I used to fix the 6502 emulator, I'll bring it across. Looks better...

Kind regards,

Oscar.


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

All times are UTC


Who is online

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