Skip to content →

6502 – almost done

So, of course we choose to use the 6502, that we already finished for the NES. The only thing we need to add, is the BCD ability, that the C64 makes use of in the 6502 (the NES doesn’t, it’s actually completely disabled by a cut trace on the PCB).

BCD often sounds very complex and frustrating, yet it isn’t that bad at all. For this, we have to dive into number systems a tiny bit (which shouldn’t be bothering you at all, given the fact that you read this page in general).

Example
-------

Hex: 0x23
       2  * 16 = 32
    +   3 *  1 =  3
    ---------------
                 35

This is the way that we usually interpret a hex number in our minds, because we are trained to use a base10 number system. This is exactly what BCD makes use of. Instead of treating the hex value for a hex value, we simply treat it as a base10 number.
For the above example, we will treat 0x23 as simple 23, not 35. This is all that BCD takes. Therefore, all numbers that contain letters are invalid.

Extended explanation:

BCD Add

0x45 + 0x33 = 0x78

So, the flagging for the decimal flag inside the PSW we already did for the NES, but now we have to make use of it. The only 2 instructions that actually use BCD are ADC and SBC. Since we made a unified function for both of these opcodes, we can simply implement it at that point.

if (status.decimal == 0) {
	uint16_t sum = registers.A + val + status.carry;
	status.setOverflow((~(registers.A ^ val) & (registers.A ^ sum) & 0x80) > 0);
	status.setCarry(sum > 0xff);
	registers.A = sum & 0xff;
	status.setZero(registers.A == 0);
	status.setNegative(registers.A >> 7);
}
else {
	printf("BCD Arithmetik happening\n");
	uint16_t v1 = (registers.A / 16) * 10 + (registers.A % 16);
	uint16_t v2 = (val / 16) * 10 + (val % 16);
	uint16_t sum = ((v1 + v2 + status.carry) / 10 * 16) + (v1 + v2 + status.carry) % 10;
	status.setCarry((v1 + v2) > 99);
	registers.A = sum & 0xff;
}

Comments

Leave a Reply