**MACHINE LANGUAGE**

Jim Butterfield, Associate Editor

**Decimal Mode**

**Part 1**

The 6502 has an option which affects only the add (ADC) and subtract (SBC) instructions: decimal mode.

Decimal mode is invoked with the Set Decimal (SED) command, and canceled with Clear Decimal (CLD). It may be affected by stack activities that pull the status register—PLP for Pull Processor status, and RTI—but this is unusual. In most computer environments you can assume that decimal mode is not in force when your program is invoked; but if you're not sure, it won't hurt to give a CLD.

Decimal mode is intended to help with certain types of numbers: Binary Coded Decimal (BCD) numbers. You might want to use this type of number system when the values are used mostly for input and output with little calculation involved.

Binary numbers—the computer's usual numeric values—are good for advanced calculations. Multiplication and division are easy to do in binary, and more advanced calculations can readily be developed. The only problem with binary numbers is this: They must be converted to decimal at the time of input or output.

Decimal numbers, or more accurately BCD numbers, are easy to input and output since they are held in the same decimal notation as was entered or will be seen by the user. With decimal mode, we may add or subtract these numbers without converting them to binary. But if we want to do more advanced mathematics, we'll certainly go to binary.

Accounting programs often use decimal mode. Similarly, many games keep scores in decimal format, since the only activities are adding points as they are scored and displaying the results.

**What Is BCD?**

The easiest way to describe a number held in Binary Coded Decimal is this: When you display it in hexadecimal format, you see the correct decimal value. Let's explain this with a few examples.

A value of 9 is held within a byte as binary 00001001. This is true whether you are using binary or BCD numbering. If we print the contents of this byte in hexadecimal, it is displayed as 09. Now, this not only represents the value nine, it looks like nine.

If we are in binary mode and add one to the above value, we'll get 00001010. The value is ten but the number displays in hex as 0A. This doesn't look like ten to those of us who are not trained to read hex. Worse: If we add six, we'll get a value of 16, which prints as hex value 10. This doesn't look like 16—if we didn't know it was a hexadecimal number, we might think it was ten.

Let's go back to our original value of nine, but switch to decimal mode. If we add one, using the ADC instruction, we'll end up with binary 00010000. We know that the value must represent ten, and when we print the hexadecimal it shows up as 10—which looks like ten. We must ignore the usual binary rules, which would tell us that binary 00010000 is equivalent to decimal 16. In BCD, this binary number has a value of 10. If we add a six in decimal mode, we'll get 00010110 which has a value of 16 and prints out as hexadecimal 16.

We've decided to use the bits in a different way. The four high bits—the high nybble, as it's sometimes called—represent a tens digit; the four low bits, or low nybble, represent units. Each nybble may have a value from 0 to 9, but the six highest combinations corresponding to hex A, B, C, D, E, and F will never be used.

This makes BCD less efficient than binary for storing numbers. The highest BCD number that we can store within a single byte is 99, as compared to 255 for binary. We can use several bytes together to hold larger numbers, but BCD always holds less: A two-byte BCD number can go from 0000 to 9999, compared to a two-byte unsigned binary number which can range from 0 to 65535.

But it's convenient. When we wish to output such a number, we extract each digit, convert it to ASCII with an ORA #$30, and print it. (We get the left digit by using four LSR instructions, and the right digit with AND #$0F.) An equivalent binary number would need a divide-by-ten routine before it could be output.

Similarly, input is a snap. As each ASCII digit arrives, it has its high bits stripped (with AND #$0F) and gets packed together with another digit to generate the two-to-a-byte BCD value.

**An Example**

Here's a sample program to show the power of BCD numbers and ease of programming with them. We'll have the computer (PET, VIC, or 64) output a table of multiples of the number 142857. This is a favorite peculiar number of mine; you'll see why when we print the table.

;set value to zero033C A2 00 LDX #$00033E 8E 90 03 STX LOW0341 8E 91 03 STX MED0344 8E 92 03 STX HIGH;do the addition0347 18 LOOP CLC0348 78 SEI0349 F8 SED034A AD 90 03 LDA LOW034D 69 57 ADC #$57034F 8D 90 03 STA LOW0352 Ad 91 03 LDA MED0355 69 28 ADC #$280357 8D 91 03 STA MED035a AD 92 03 LDA HIGH035D 69 14 ADC #$140362 D8 CLD0363 58 CLI;print the number0364 A0 02 LDY #$020366 B9 90 03 LP LDA LOW, Y0369 4A LSR A036A 4A LSR A036B 4A LSR A036C 4A LSR A036D 09 30 ORA #$30036F 20 D2 FF JSR $FFD20372 B9 90 03 LDA LOW,Y0375 29 0F AND #$0F0377 09 30 ORA #$300379 20 D2 FF JSR $FFD2037C 88 DEY037D 10 E7 BPL LP;print RETURN and loop0381 A9 0D LDA #$0D0381 20 D2 FF JSR $FFD20384 E8 INX0385 E0 07 CPX #$070389 60 RTS

Note that we hold the value we are calculating in three bytes; called LOW, MED, and HIGH; we add starting at the low byte and working up. The Carry flag works the same way as is usual for addition. While we're in decimal mode, we lock out the interrupt so that the interrupt routines won't do their arithmetic in the wrong mode. The addition sequences could have been written as a loop; for the sake of clarity, it was done using "straight line" coding.

For printing, we start from the high byte, of course. The output routine for BCD is simple compared to what we would need to do with binary values.

If you'd rather enter the program from BASIC, here's the same program in DATA statements. It will work on all Commodore machines.

100 DATA 162, 0, 142, 144, 3, 142, 145, 3110 DATA 142, 146, 3, 24, 120, 248, 173, 144, 3120 DATA 105, 87, 141, 144, 3, 173, 145, 3130 DATA 105, 40, 141, 145, 3, 173, 146, 3140 DATA 105, 20, 141, 146, 3, 216, 88, 160, 2150 DATA 185, 144, 3, 74, 74, 74, 74, 9, 48160 DATA 32, 210, 255, 185, 144, 3, 41, 15, 9, 48170 DATA 32, 210, 255, 136, 16, 231, 169, 13180 DATA 32, 210, 255, 232, 224, 7, 208, 190, 96200 FOR J = 828 TO 905210 READ X: T = T + X220 POKE J, X230 NEXT J240 SYS 828

You might like to examine the output of the program to see what's so special about the first seven multiples of the number 142857.

Next month, we'll discuss special features and wrinkles of decimal mode.