22

I'm "re-learning" 68000 assembly language and came across the "MOVEQ" command that is labeled "MOVE QUICK".

According to the NXP Programmers Reference Manual (reference below), the command MOVEQ (MOVE QUICK) is described as:

Moves a byte of immediate data to a 32-bit data register. The data in an 8-bit
field within the operation word is sign- extended to a long operand in the data
register as it is transferred.

I've searched the manual and cannot find why it's "quick".

Meaning, what's the difference (in performance) in the following instructions?

MOVEQ #100, D0
MOVE #100, D0

I gather the MOVEQ is a better fit for moving 8-bit data. Or, is it ONLY 8-bits of data as I cannot seem to confirm.

REF:

https://www.nxp.com/files-static/archives/doc/ref_manual/M68000PRM.pdf

3 Answers 3

35

The MOVE immediate instruction takes 8 cycles in byte and word modes. There are two memory reads, one for the instruction and one for the immediate value.

The MOVEQ instruction encodes the immediate value into the instruction op-code itself, so only takes 4 cycles and 1 memory read. It can only take a byte immediate value.

Instruction Performance
MOVEQ #1, D0 4 clocks, 1 memory read
MOVE.b #1, D0 8 clocks, 2 memory reads
MOVE.w #1000, D0 8 clocks, 2 memory reads

Note that the immediate value loaded for byte and word size moves overwrites the entire 32 bits of the register, and is sign extended.

As such, for loading values $00-$FF, it is twice as fast in instruction cycles and uses half as much memory bandwidth (important on systems where it is shared with DMA).

11
  • 10
    "for loading values 0-255..." - more precisely, it loads a 32 bit value between -128 and +127.This is 3 times faster than doing it the normal way with move.l #... Jul 19, 2019 at 1:20
  • 1
    @BruceAbbott that's a good point, it does sign extend to 32 bits.
    – user
    Jul 19, 2019 at 7:54
  • 4
    Showing the actual hex codes of the three instructions will improve the answer.
    – Leo B.
    Jul 19, 2019 at 23:17
  • Isn't this design of MOVE.b/w/l a little toxic? E.g. the immediate that follow the MOVE could decode into an invalid instruction had it been done speculatively? I believe modern RISC ISAs have all removed support for long immediate values if the opcode and the value can not both fit into one instruction word? Dec 25, 2021 at 5:14
  • 1
    Why did it need its own instruction rather than MOVE.b being translated into MOVEQ's opcode by the assembler? Is there any value in providing the "slow" MOVE.b instruction?
    – Luca Citi
    Dec 25, 2021 at 7:56
13

To give the exact cycle-by-cycle breakdown:

MOVEQ is a one word instruction so will nominally perform in four cycles; in practice it can occur immediately following operation decoding because all necessary information is within the instruction word. Four cycles are then expended fetching the next value to feed into the instruction prefetch queue.

Both MOVE.b MOVE.w are two-word instructions. The 68000 actually knows both words before either instruction begins, so both can occur pretty much immediately but both then require that a further two words be fetched to repopulate the instruction prefetch queue, which occupies eight cycles before the next instruction can begin.

MOVE.l is a three-word instruction. The 68000's prefetch queue is only two words long. So after decoding it can't actually be completed until a further word has been fetched, and after that fetch a further two will be needed to repopulate the queue. So twelve cycles total.

MOVEs are the most primitive operation available; the general rule is that the number of words needed to complete an operation plus the number needed then to [re]populate the prefetch queue is only a floor for cycle counting. See Yacht.txt for a more detailed summary of the work each instruction does; bear in mind that things like RTS are only one word long but imply two further prefetches since the whole queue needs to be replenished, and anything that might change the supervisor flag will often result in a refetch of data that's ostensibly already in the queue, in case the memory subsystem is designed to serve conditional results.

6
  • (obiter: this answer was offered despite the other answer already being present because I felt the fact of the prefetch queue makes it a different answer, technically. Even if very similar)
    – Tommy
    Jul 19, 2019 at 20:56
  • 1
    Comment only: Your last paragraph doesn't seem to quite 'scan' correctly - or I'm still half asleep :-). I think "that anything that things" contains at least one typo (but may not) and " in case the ..." may not say what you want as precisely as it could (but may :-) ). Jul 19, 2019 at 22:32
  • Are there any circumstances in which the time to execute a 68000 instruction would vary with context? For example, how would the timing of muls r0,r1 / moveq r0,#0 / rts compare to muls r0,r1 / move.l r0,#0 / rts?
    – supercat
    Jul 19, 2019 at 22:33
  • @supercat I can't think of anything, as every instruction is microcoded to make sure the prefetch queue is exactly full again within its execution time. It's not intelligent like, say, the instruction queue on an 8086.
    – Tommy
    Jul 20, 2019 at 13:40
  • @Tommy: I can't think of any advantage to waiting before the second fetch is complete before starting instruction execution, but could easily imagine that instruction execution decode couldn't start until the cycle after the first fetch was complete, starting the fetch of the second word immediately without regard for whether it's needed would allow it to begin a cycle or two sooner than would otherwise be possible. It may have been possible to design the 68000 shave two cycles off an RTS if the attached memory system could process a two-cycle "ignored value" read, but...
    – supercat
    Jul 20, 2019 at 16:34
8

I've searched the manual and cannot find why it's "quick".

Simply because MOVEQ is a single word (two byte) instruction, which can be fetched in a single memory cycle, while an equal constant move will be 2 (MOVE.W) or 3 words (MOVE.L) and need one/two additional memory cycles - each four clocks.

So effectively you'll get the following execution timing:

  • MOVEQ #5,D0 - 4 Clocks,
  • MOVE.B #5,D0 - 8 Clocks,
  • MOVE.W #5,D0 - 8 Clocks,
  • MOVE.L #5,D0 - 12 Clocks,

making MOVEQ about 50/66% faster.

MOVEQ even got it's own opcode (7) to squeeze all into a single word.

ADDQ and SUBQ works similar (*1) - except mixed into the Scc/DBcc/TRAPcc group (5).

I gather the MOVEQ is a better fit for moving 8-bit data. Or, is it ONLY 8-bits of data as I cannot seem to confirm.

Only. There is no room for more than 8 bits of constant within the 16 bit instruction word (*2), as the encoding is

|OPCODE|Dest.| Res || Data      |
|Group |Reg. |     ||           |
| 0111 | xxx |  0  || yyyy yyyy |

*1 - Not exactly like it as they may have additional parameters.

*2 - Well, in the original 68000 encoding there was one unused bit, but won't get far.

7
  • Don't forget the move.b instruction...
    – UncleBod
    Jul 18, 2019 at 16:14
  • @UncleBod MOVE.B is exactly like MOVE.W
    – Raffzahn
    Jul 18, 2019 at 16:40
  • "making MOVEQ about 50/66% faster." - math.stackexchange.com/questions/1404234/… Jul 20, 2019 at 23:20
  • @BruceAbbott And your point is?
    – Raffzahn
    Jul 21, 2019 at 10:19
  • 1
    @DanSheppard Oh, I'm all with you, except, a percentage is always relative notation between two values. and faster (or slower) is as well a relation, one that marks a direction. In this case the direction is clear, as MOVEQ is faster than MOVE in absolute numbers. So a relation using the term 'faster (than)' must be based on the slower, isn't it, so MOVE with 8 clocks is 100%. MOVE-W is 4, so it's 50% faster. 100% would simply mean it being executed in zero clocks :))
    – Raffzahn
    Dec 24, 2021 at 16:27

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .