duckyPad-Pro

duckyScript Bytecode Virtual Machine

Get duckyPad Pro Official Discord Getting Started Table of Contents

Details of duckyPad duckyScript 3 (DPDS3) instruction set, compiler, and binary format.

This is NOT the official implementation, which appears to be close-source.

I designed everything here myself from scratch.

Background

In duckyScript 1, it’s sufficient to simply parse line-by-line, as each line is independent.

duckyScript 3 introduced variables, IF statements, WHILE loops, and function calls.

Being much more complex, it makes sense to compile the script into bytecode and execute it on a virtual machine instead.

Virtual Stack Machine

DPDS3 VM is a simple stack machine with two stacks and a Program Counter (PC).

Compiled binary is loaded into memory, and PC starts executing at the beginning of the program.

Instruction Set

Each DPDS3 instruction has a fixed-length of three bytes.

Compiler

The DPDS3 compiler takes a text file and outputs a executable binary file.

The binary file should have extension .dsb (duckyScript binary).

Normally this is taken care of in the configurator. But you can also try it out on its own:

Let’s say you have a simple script in sample_script.txt:

DEFINE TEN 10
VAR $spam = TEN*7+3
DELAY $spam

Compile with python3 make_bytecode.py sample_script.txt output.dsb

Compiled binary is written to output.dsb, along with some extra info:

--------- Program Listing After Preprocessing: ---------
1    VAR $spam = 10*7+3
2    DELAY $spam

--------- Assembly Listing, Unresolved ---------

PUSHC     10    0xa           ;VAR $spam = 10*7+3
PUSHC     7     0x7           ;VAR $spam = 10*7+3
MULT                          ;VAR $spam = 10*7+3
PUSHC     3     0x3           ;VAR $spam = 10*7+3
ADD                           ;VAR $spam = 10*7+3
POP       spam                ;VAR $spam = 10*7+3
PUSHI     spam                ;DELAY $spam
DELAY                         ;DELAY $spam
HALT

--------- Assembly Listing, Resolved ---------

0    PUSHC     10    0xa           ;VAR $spam = 10*7+3
3    PUSHC     7     0x7           ;VAR $spam = 10*7+3
6    MULT                          ;VAR $spam = 10*7+3
9    PUSHC     3     0x3           ;VAR $spam = 10*7+3
12   ADD                           ;VAR $spam = 10*7+3
15   POP       0     0x0           ;VAR $spam = 10*7+3
18   PUSHI     0     0x0           ;DELAY $spam
21   DELAY                         ;DELAY $spam
24   HALT



--------- Bytecode ---------
0x01 0x0a 0x00 0x01 0x07 0x00 0x11 0x00 0x00
0x01 0x03 0x00 0x0f 0x00 0x00 0x03 0x00 0x00
0x02 0x00 0x00 0x1b 0x00 0x00 0x08 0x00 0x00


Binary Size: 27 Bytes

Binary Executable

When a key is pressed, the corresponding .dsb file is loaded into bin_buf in ds3_vm.c. Execution occurs inside run_dsb() with execute_instruction().

Zero-terminated strings are stored at the end of the binary file.

Variables are stored in var_buf. Up to 64 variables can be declared.

CPU Instructions

All reference to “stack” refers to Arithmetic Stack. Unless noted otherwise.

Opcode
Name
Byte 0
Decimal
Byte 0
Hex
Comment Byte 1 Byte 2
NOP 0 0x0 Do nothing    
PUSHC 1 0x1 Push a constant on stack CONST_LSB CONST_MSB
PUSHI 2 0x2 Push value at ADDR on stack ADDR_LSB ADDR_MSB
POP 3 0x3 Pop one item off top of stack
Write it to ADDR
ADDR_LSB ADDR_MSB
BRZ 4 0x4 Pop one item off top of stack
If value is zero, jump to ADDR
ADDR_LSB ADDR_MSB
JMP 5 0x5 Unconditional Jump ADDR_LSB ADDR_MSB
CALL 6 0x6 Jump to Subroutine
Push PC+1 to call stack
Jump to ADDR
ADDR_LSB ADDR_MSB
RET 7 0x7 Return from Subroutine
Pop one item off call stack
Set PC to its value
   
HALT 8 0x8 Stop execution    
VMVER 255 0xFF VM Version   VM VER

Binary Operator Instructions

Binary as in involving two operands.

All instructions here:

Opcode
Name
Byte 0
Decimal
Byte 0
Hex
Comment
EQ 9 0x9 Equal
NOTEQ 10 0xa Not equal
LT 11 0xb Less than
LTE 12 0xc Less than or equal
GT 13 0xd Greater than
GTE 14 0xe Greater than or equal
ADD 15 0xf Add
SUB 16 0x10 Subtract
MULT 17 0x11 Multiply
DIV 18 0x12 Integer division
MOD 19 0x13 Modulus
POW 20 0x14 Power of
LSHIFT 21 0x15 Logical left shift
RSHIFT 22 0x16 Logical right shift
BITOR 23 0x17 Bitwise OR
BITAND 24 0x18 Bitwise AND
LOGIAND 25 0x19 Logical AND
LOGIOR 26 0x1a Logical OR

duckyScript Command Instructions

All reference to “stack” refers to Arithmetic Stack. Unless noted otherwise.

Opcode
Name
Byte 0
Decimal
Byte 0
Hex
Comment Byte 1 Byte 2
DELAY 27 0x1b Pop one item off top of stack
Delay the amount in milliseconds
   
KUP 28 0x1c Release Key
Pop ONE item
Upper byte: KEYTYPE
Lower byte: KEYCODE
   
KDOWN 29 0x1d Press Key
Pop ONE item
Upper byte: KEYTYPE
Lower byte: KEYCODE
   
MSCL 30 0x1e Mouse Scroll
Pop ONE item
Scroll number of lines
   
MMOV 31 0x1f Mouse Move
Pop TWO items
Move X and Y
   
SWCF 32 0x20 Switch Color Fill
Pop THREE items
Red, Green, Blue
Set ALL LED color to the RGB value
   
SWCC 33 0x21 Switch Color Change
Pop FOUR items
N, Red, Green, Blue
Set N-th switch to the RGB value
If N is 0, set current switch.
   
SWCR 34 0x22 Switch Color Reset
Pop one item off top of stack
If value is 0, reset color of current key
If value is between 1 and 15, reset color of that key
If value is 99, reset color of all keys
   
STR 35 0x23 Print zero-terminated string at ADDR ADDR_LSB ADDR_MSB
STRLN 36 0x24 Same as above, presses ENTER at end    
—- 37 0x25 Deprecated
Do not use
   
OLC 38 0x26 OLED_CURSOR
Pop TWO items
X and Y
   
OLP 39 0x27 Print zero-terminated string at ADDR to OLED ADDR_LSB ADDR_MSB
OLU 40 0x28 OLED_UPDATE    
OLB 41 0x29 OLED_CLEAR    
OLR 42 0x2a OLED_RESTORE    
BCLR 43 0x2b Clear switch event queue    
PREVP 44 0x2c Previous profile    
NEXTP 45 0x2d Next profile    
GOTOP 46 0x2e Pop one item
Go to profile of its value
   
SLEEP 47 0x2f Put duckyPad to sleep
Terminates execution
   

Table of Contents

Main page

Getting Started Guide

Kit Assembly Guide

Using duckyScript

duckyScript VM

Tinkering Guide

Troubleshooting

Firmware Update

Questions or Comments?

Please feel free to open an issue, ask in the official duckyPad discord, or email dekuNukem@gmail.com!

DSVM changelog

2024 09 07

MOUSE_WHEEL argument on stack

MOUSE_MOVE argument on stack

removed MOUSE_MOVE preprocessor expansion, to be done at instruction level

evaluate_expr handles unary operations such as -1

SWC_SET SWC_FILL SWC_RESET arguments now on stack

OLED_CURSOR arguments now on stack

2024 09 08

KEYUP KEYDOWN and key combos argument on stack

MOUSE_WHEEL FW implementation

MOUSE_MOVE FW implementation

MOUSE_MOVE FW level expansion

KEYUP KEYDOWN FW level implementation