Remix.run Logo
Findecanor 12 hours ago

I read through its instruction set manual, and found an instruction with unusual behaviour: Its 'ASL` (arithmetic shift left) instruction.

It shifts all bits except for the sign bit, leaving it unchanged.

I have read many ISA's manuals and not seen this elsewhere. Most ISAs don't have separate arithmetic and logic left shift instructions. On M68K, which does, the difference between `ASL` and `LSL' is only that the former sets the Overflow flag if any of the bits shifted out is different from the resulting sign bit whereas the latter clears it.

RetroTechie 10 hours ago | parent [-]

Z80 has a Shift Right Arithmetic (SRA) instruction. From Zilog Z80 User Manual:

"An arithmetic shift right 1 bit position is performed on the contents of operand m. The contents of bit 0 are copied to the Carry flag and the previous contents of bit 7 remain unchanged. Bit 0 is the least-significant bit."

So if value was used as signed integer, that's a sign-preserving /2 (and easy to expand to 16 or more bits).

Z80 also has a SLA, which does shift all bits.

roelschroeven 9 hours ago | parent | next [-]

For right shifts, yes, instruction sets commonly have the distinction between arithmetic and logic.

Findecanor was talking about left shifts though.

Joker_vD 7 hours ago | parent | prev [-]

> So if value was used as signed integer, that's a sign-preserving /2

Only if you define your integer division as rounding towards minus infinity which almost none of the languages do (they usually round towards zero). See e.g. [0] for the additional instructions needed to correct the result.

Now, I personally think this is a mistake and my PLs always round integers down instead of towards zero, but others may disagree.

[0] https://godbolt.org/z/1z7eYPT48

Findecanor 7 hours ago | parent [-]

It's a bit inconsistent that most ISAs out there have division that rounds towards zero but only right shift that rounds down.

PowerPC is the only production-ISA I've found that has an arithmetic right-shift instruction designed for rounding towards zero. It sets the Carry flag if a 1 is shifted out and the result is negative. Then only an "add with carry" instruction is needed to adjust the result.

Joker_vD 6 hours ago | parent [-]

From what I can tell, it literally is a holdover from the FORTRAN days when IBM machines used a sign-magnitude integers, so truncating division was an obvious choice for hardware dividers; and then nobody dared to change the semantics of neither the hardware nor the programming languages for some reason, and it carried all the way forwards to nowadays.

I am fairly certain that restoring/non-restoring unsigned binary division algorithms can be made to do signed division that would round down with minimal change that is not "divide the absolute values and then fix the signs", and for algorithms used in high-speed division hardware the choice of rounding doesn't really matter.