Forth double loops

Given a double number D on the stack, what's a reasonable way of looping D times? I recently needed to do this to support file reading on a 16-bit Forth.

Clearly you can just make a loop by counting down:

  -1. d+ 2dup d0=

But there is a more elegant arrangement using a nested pair of DO..LOOPs.

The inspiration is this ancient Z80 technique of using two 8-bit loops to form a 16-bit counter:

The Forth equivalent looks quite

: prep over 0<> - ;

  prep 0 do
    0 do
    loop 0
  loop drop

prep adjusts the loop counter, incrementing the high count only if the low count is nonzero.

So for example a loop count of $123456 would be represented on the stack as:

$3456 $12

prep adjusts the high count to $13:

$3456 $13

So the outer DO..LOOP executes $13 times. The first inner do executes $3456 times. The subsequent iterations are all performing:

0 0 DO .. LOOP

and hence execute $10000 times.

This works well, but there does not seem to be an easy way of computing the double counter value.

There is a small further optimization possible. Instead of adjusting the outer loop counter, prep can compute compute a DO..LOOP starting value of either 0 or -1:

: prep over 0<> ;

  prep do
    0 do
    loop 0
  loop drop