spo600:6502_math
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| spo600:6502_math [2024/01/23 15:10] – [6502 Math] chris | spo600:6502_math [2025/01/23 22:27] (current) – [Multiplication and Division] chris | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| ====== | ====== | ||
| - | The 6502 processor is limited to very simple math operations, and various processor flags affect these operations. | + | The [[6502]] processor is limited to very simple math operations, and various |
| ==== Decimal Mode ==== | ==== Decimal Mode ==== | ||
| Line 9: | Line 9: | ||
| In binary mode, operations are performed on a single 8-bit value. Numbers may be treated as signed or unsigned (the math is the same). | In binary mode, operations are performed on a single 8-bit value. Numbers may be treated as signed or unsigned (the math is the same). | ||
| - | In decimal mode, the each byte is treated as two decimal digits - the lower 4 bits represent the lower digit, and the upper 4 bits represent the upper digit. Numbers are counted as positive, and values greater than 9 are invalid. | + | In decimal mode, the each byte is treated as two decimal digits - the lower 4 bits represent the lower digit, and the upper 4 bits represent the upper digit. Numbers are counted as positive, and digit values greater than 9 are invalid. |
| Decimal mode is selected by setting the D (Decimal) flag in the [[6502# | Decimal mode is selected by setting the D (Decimal) flag in the [[6502# | ||
| - | The rest of this page deals with binary mode (decimal mode operates in mostly the same way). | + | The rest of this page deals with binary mode (decimal mode operates in mostly the same way). Note that decimal mode is only applicable to '' |
| ==== Addition | ==== Addition | ||
| Line 62: | Line 62: | ||
| ==== Rotate Right/ | ==== Rotate Right/ | ||
| - | The Rotate Right and Rotate Left (ROR/ROL) instructions are like the LSR/ASL instructions, | + | The Rotate Right and Rotate Left (ROR/ROL) instructions are like the LSR/ASL instructions, |
| + | |||
| + | For example, to perform a 16-bit right shift: | ||
| + | |||
| + | 1. Perform LSR on the high byte. The lowest bit will be placed in the carry flag. | ||
| + | |||
| + | 2. Perform ROR on the low byte. The carry flag, containing the lowest bit from the high byte, will be shifted in to the highest bit of the low byte. | ||
| + | |||
| + | The original version of the 6502 had a bug in the ROR instruction, | ||
| ==== Bitwise Operations | ==== Bitwise Operations | ||
| Line 69: | Line 77: | ||
| < | < | ||
| - | ROR Rotate right - 9-bit rotate (one byte plus C flag) | ||
| - | ROL Rotate left - 9-bit rotate left (one byte plus C flag) | ||
| - | ASL Arithmetic shift left - bit 7 -> C flag, bits 0:6 -> 1:7, 0 -> bit 0 | ||
| - | LSR Logical shift right - bit 0 -> C flag, bits 7:1 -> 6:0, 0 -> bit 7 | ||
| EOR Exclusive-OR (sometimes written XOR in other languages) | EOR Exclusive-OR (sometimes written XOR in other languages) | ||
| - | ORA OR (accumulator) | + | ORA OR (Accumulator) |
| AND AND</ | AND AND</ | ||
| A NOT operation can be performed using EOR with an immediate value of #$FF, and this can be combined with ORA and AND instructions to build NOR and NAND operations. | A NOT operation can be performed using EOR with an immediate value of #$FF, and this can be combined with ORA and AND instructions to build NOR and NAND operations. | ||
| - | The BIT instruction performs a bitwise AND, sets the Z flag based on the result, and transfers bits 6 and 7 of the operand into the N and V flags. | + | In addition, the BIT instruction performs a bitwise AND, sets the Z flag based on the result, and transfers bits 6 and 7 of the operand into the N and V flags. |
| ==== Multiplication and Division | ==== Multiplication and Division | ||
| - | There are no multiplication or division instructions on the 6502; it is up to the programmer to provide the appropriate logic. | + | There are no multiplication or division instructions on the 6502; it is up to the programmer to provide the appropriate logic. |
| + | |||
| + | Here is a simple example subroutine which multiplies two 8-bit values, producing a 16-bit product as the result (this code can be tested on the [[6502 Emulator]]): | ||
| + | |||
| + | < | ||
| + | ; | ||
| + | ; Example of 8-bit x 8-bit multiply with | ||
| + | ; 16-bit result on a 6502 | ||
| + | ; | ||
| + | ; This code uses shift-and-add | ||
| + | ; | ||
| + | ; Chris Tyler 2025-01-23 for the SPO600 course | ||
| + | ; | ||
| + | ; Copyright (C)2025 Seneca Polytechnic | ||
| + | ; Licensed under the terms of the GPLv2+ | ||
| + | ; See the file LICENSE for details | ||
| + | |||
| + | ; ######### MACRO DEFINITIONS | ||
| + | ; === ZERO-PAGE MEMORY LOCATIONS | ||
| + | |||
| + | ; INPUT PARAMETERS AND RESULT | ||
| + | define M1 | ||
| + | |||
| + | define M2 | ||
| + | |||
| + | define RESULT | ||
| + | define RESULT_L $12 | ||
| + | define RESULT_H $13 | ||
| + | |||
| + | ; TEMPORARY COPIES OF M1, M2 | ||
| + | define T1 | ||
| + | |||
| + | define T2 | ||
| + | define T2_L $21 | ||
| + | define T2_H $22 | ||
| + | |||
| + | ; ######### TEST CODE | ||
| + | |||
| + | ; NOTE: THE NEXT TWO OPERANDS ARE IN DECIMAL! | ||
| + | ; THIS IS DUE TO THE LACK OF $ | ||
| + | |||
| + | LDA #7 ; FIRST MULTIPLICAND | ||
| + | STA M1 | ||
| + | |||
| + | LDA #9 ; SECOND MULTIPLICAND | ||
| + | STA M2 | ||
| + | |||
| + | JSR MULTIPLY ; MULTIPLY THE VALUES | ||
| + | |||
| + | BRK ; SEE 16 BIT RESULT AT ' | ||
| + | |||
| + | ; ######### MULTIPLY SUBROUTINE | ||
| + | ; MULTIPLY THE CONTENTS OF M1 BY THE CONTENTS | ||
| + | ; OF M2 AND STORE THE RESULT IN ' | ||
| + | ; | ||
| + | ; Operation: | ||
| + | ; 0. Multiplicand M1 is copied to temporary | ||
| + | ; variable T1. Multiplicand M2 is copied to | ||
| + | ; the 16-bit temporary variable T2. The | ||
| + | ; RESULT is zeroed out. | ||
| + | ; 1. If either multiplicand is zero, the | ||
| + | ; product is zero, so the routine returns | ||
| + | ; immediately with RESULT=0. | ||
| + | ; 2. T1 is shifted right. If the bit shifted | ||
| + | ; out (formerly bit 0) is a ' | ||
| + | ; value of T2 is added to the RESULT. | ||
| + | ; 4. If T1 is zero after the shift, the | ||
| + | ; multiplication is complete and the routine | ||
| + | ; returns. | ||
| + | ; 5. T2 is rotated left (multiplied by 2). | ||
| + | ; 6. Processing continues at step 2. | ||
| + | |||
| + | MULTIPLY: | ||
| + | LDA #$00 ; ZERO OUT THE RESULT AND Tn_H | ||
| + | STA RESULT_L | ||
| + | STA RESULT_H | ||
| + | STA T2_H | ||
| + | |||
| + | LDA M1 ; COPY M1 TO T1 | ||
| + | BEQ MULT_DONE | ||
| + | STA T1 | ||
| + | |||
| + | LDA M2 ; COPY M2 TO T2 | ||
| + | BEQ MULT_DONE | ||
| + | STA T2_L | ||
| + | |||
| + | JMP MULT_FIRST | ||
| + | |||
| + | MULT_NEXT: | ||
| + | ASL T2_L ; SHIFT T2 LEFT | ||
| + | ROL T2_H | ||
| + | |||
| + | MULT_FIRST: | ||
| + | LSR T1 ; SHIFT T1 RIGHT | ||
| + | BEQ MULT_LAST | ||
| + | BCC MULT_NEXT | ||
| + | |||
| + | LDA T2_L ; IF BIT0 WAS 1: | ||
| + | CLC ; T2 + RESULT-> RESULT | ||
| + | ADC RESULT_L | ||
| + | STA RESULT_L | ||
| + | LDA T2_H | ||
| + | ADC RESULT_H | ||
| + | STA RESULT_H | ||
| + | JMP MULT_NEXT | ||
| + | |||
| + | MULT_LAST: | ||
| + | LDA T2_L ; PRECEEDING BLOCK, BUT | ||
| + | CLC ; WE'VE AVOIDED A SECOND | ||
| + | ADC RESULT_L | ||
| + | STA RESULT_L | ||
| + | LDA T2_H ; PER LOOP ITERATION OR | ||
| + | ADC RESULT_H | ||
| + | STA RESULT_H | ||
| + | |||
| + | MULT_DONE: | ||
| + | RTS | ||
| + | </ | ||
| + | This code is available in the [[spo600: | ||
spo600/6502_math.1706022625.txt.gz · Last modified: 2024/04/16 18:10 (external edit)
