uzumaki
uzumaki

Reputation: 1973

Why does the 6502 microcontroller not have a arithmetic right shift?

I'm trying to understand the instruction sets of old microcontrollers, especially the 6502.

The documentation of the instruction set that can be found here lists two shift instructions (beside the rotate instructions):

ASL - arithmetic shift left

LSR - logical shift right

Why are there no arithmetic shift right and logical shift left instructions?

I know that one can simply add a number to itself to logically shift it to the left, but a dedicated instruction would be much more convenient and also faster, even if it does just that. But a missing arithmetic shift right instruction does not make sense to me.

Upvotes: 6

Views: 4057

Answers (4)

cjs
cjs

Reputation: 27271

As others have pointed out, an arithmetic right shift in the A register can be synthesised with

        CMP #$80        ; copy sign bit of A into carry
        ROR A

Note that when you do a LDA before this, it's shorter (by two bytes) and faster than the code given in JeremyP's answer.

To ASR a memory location, you can use the following technique from the Nesdev wiki:

        LDA addr        ; copy memory into A
        ASL A           ; copy sign bit of A into carry (shorter than CMP)
        ROR addr

This leaves the flags set the same as LSR, but unlike LSR it destroys the contents of the accumulator.

Upvotes: 4

Karol S
Karol S

Reputation: 9421

A logical shift left is the same as arithmetic shift left, so there's no need to distinguish the two. Many assemblers for other platforms consider LSL and ASL mnemonics as synonyms (for example ARM).

As for lack of arithmetic shift right, you can always do CMP #80/ROR A to perform the arithmetic shift right on the accumulator.

Upvotes: 6

JeremyP
JeremyP

Reputation: 86661

I've always thought that particular pair of instructions to be a bit of a con. There are no arithmetic shifts at all on the original 6502. Arithmetic shifts preserve the sign of the number being shifted and the so called ASL only does that by virtue of the fact that the 6502 uses 2's complement.

The original 6502 only has two shift operations: shift right and shift left with bit shifted out going to the carry flag and the bit shifted in being set to zero. For shifts left with 2's complement, there is no distinction between arithmetic and logical. However, for shifts right, an arithmetic shift has to preserve the sign bit. This means, to do it, you would need circuitry to propagate the top bit of input into the shifter to the top bit of the output and an extra control line to select between that and 0. These all require more transistors and an arithmetic shift can be simulated with a rotate.

    CLC
    LDA number
    BPL positive
    SEC
positive:
    ROR A

The primary driver behind the design of the 6502 was to make it outperform the Motorola 6800 at a lower price. This was done by stripping inessential features out of the 6800 so they could make the transistor count as low as possible. The 6502 has a transistor count of around 3,500. The earlier 6800 has a transistor count of around 4,500. Inessential features like a proper arithmetic shift were therefore left out.

In fact, given that shifts can be emulated by clearing the carry flag and then doing a rotate, I'm surprised they bothered with them at all. The designers must have found they could add the shift instructions with a minimal increase in complexity, much like the SBC instruction is exactly the same as the ADC instructions but with the bits of the second operand inverted.

Upvotes: 4

Brendan
Brendan

Reputation: 37222

Why is there no arithmetic shift right instruction, why are there so few registers, why is there no multiplication/division instruction, why is there no SIMD, why is there no floating point support, why is there no MMU, ... ?

Back when 6502 was designed there were (relatively severe by modern standards) limits on both the number of transistors and the complexity of the CPU. Sacrifices were made to make it a viable to design and manufacture, and signed integers are "barely needed".

Note: The main reason "signed" is used is that C (and later languages) have the wrong default (it assumes "signed" for almost all integers unless you tell it otherwise) and people are too lazy to type "unsigned" when they don't need signed; so a lot of software uses (slightly more expensive) signed arithmetic for no reason other than laziness. In general, most of the situations where you actually do need signed numbers you're dealing with "real world values" and need floating point anyway (things like array indexes, addressses/pointers, sizes, character/code points, pixel values, distances, ... are all naturally unsigned).

Upvotes: 2

Related Questions