According to http://www.tasking.com/support/c166/c166_user_guide_v2.1.pdf TASKING VX-toolset for C166 User Guide, section "3.3. Operands of an Assembly Instruction", register operand should be of form defined in "3.5. Registers" section:
The following register names, either upper or lower case, should not be used for user-defined symbol names in an assembly language source file:
R0 .. R15 (general purpose registers)
RL0 .. RL7 (byte registers)
RH0 .. RH7 (byte registers)
As I understand, user-defined symbols are for constants or labels; there is no user-defined symbol of type "register" in "3.7.4. Symbol Types and Expression Types". But you may try to use preprocessor with ".DEFINE":
.DEFINE symbol string
Description.
With the .DEFINE directive you define
a substitution string that you can use on all following source lines.
The assembler searches all succeeding lines for an occurrence of
symbol, and replaces it with string. If the symbol occurs in a double
quoted string it is also replaced. Strings between single quotes are
not expanded. This directive is useful for providing better
documentation in the source program. A symbol can consist of letters,
digits and underscore characters (_), and the first character cannot
be a digit.
Try this:
.define loop_i d3
mov16 loop_i, #4
mov16 d3, #4 ; this is what I must use instead
PS: http://www.tasking.com/support/tricore/tc_user_guide_v6.0.pdf "TASKING VX-toolset for TriCore User Guide" has similar assembler capabilities, so try .define. Only allowed set of register names is different from c166:
3.5. Registers
The following register names, either uppercase or lowercase, should not be used for user-defined symbol
names in an assembly language source file:
D0 .. D15 (data registers)
E0 .. E14 (data register pairs, only the even numbers)
A0 .. A15 (address registers)