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/09/12 18:56] – 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# | ||
Line 67: | Line 67: | ||
1. Perform LSR on the high byte. The lowest bit will be placed in the carry flag. | 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. | 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 84: | Line 87: | ||
==== 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.1726167394.txt.gz · Last modified: 2024/09/12 18:56 by chris