velxio/test/test_circuit/src/avr/asm.js

88 lines
2.4 KiB
JavaScript

/**
* Tiny hand-rolled AVR assembler for the few opcodes we need to build
* test programs without an avr-gcc toolchain.
*
* Only the instructions exercised by the test suites are implemented.
* All addresses / offsets use AVR's word-addressed convention.
*/
/** LDI Rd, K — Rd ∈ [16..31], K ∈ [0..255]
* Encoding: 1110 KKKK dddd KKKK
*/
export const LDI = (rd, k) => {
if (rd < 16 || rd > 31) throw new Error(`LDI: rd=${rd} out of range`);
if (k < 0 || k > 255) throw new Error(`LDI: k=${k} out of range`);
const d = rd - 16;
return 0xE000 | ((k & 0xF0) << 4) | (d << 4) | (k & 0x0F);
};
/** OUT A, Rr — A ∈ [0..63], Rr ∈ [0..31]
* Encoding: 1011 1AAr rrrr AAAA
*/
export const OUT = (A, rr) => {
if (A < 0 || A > 63) throw new Error(`OUT: A=${A} out of range`);
return 0xB800 | ((A & 0x30) << 5) | (rr << 4) | (A & 0x0F);
};
/** IN Rd, A — Rd ∈ [0..31], A ∈ [0..63]
* Encoding: 1011 0AAd dddd AAAA
*/
export const IN = (rd, A) => {
return 0xB000 | ((A & 0x30) << 5) | (rd << 4) | (A & 0x0F);
};
/** STS k, Rr — 32-bit instruction, k ∈ [0..65535], Rr ∈ [0..31]
* Encoding: 1001 001r rrrr 0000 kkkkkkkk kkkkkkkk
* Returns [word1, word2].
*/
export const STS = (k, rr) => {
const w1 = 0x9200 | ((rr & 0x10) << 4) | ((rr & 0x0F) << 4);
return [w1, k & 0xFFFF];
};
/** LDS Rd, k — 32-bit instruction
* Encoding: 1001 000d dddd 0000 kkkkkkkk kkkkkkkk
*/
export const LDS = (rd, k) => {
const w1 = 0x9000 | ((rd & 0x10) << 4) | ((rd & 0x0F) << 4);
return [w1, k & 0xFFFF];
};
/** RJMP — jump by signed word offset from PC+1
* Encoding: 1100 kkkk kkkk kkkk (12-bit signed)
*/
export const RJMP = (offset) => {
const k = offset & 0xFFF;
return 0xC000 | k;
};
/** SBRC Rr, b — Skip if Bit in Register Clear
* Encoding: 1111 110r rrrr 0bbb
*/
export const SBRC = (rr, b) => {
return 0xFC00 | (rr << 4) | (b & 0x07);
};
/** SBRS Rr, b — Skip if Bit in Register Set
* Encoding: 1111 111r rrrr 0bbb
*/
export const SBRS = (rr, b) => {
return 0xFE00 | (rr << 4) | (b & 0x07);
};
/** NOP */
export const NOP = () => 0x0000;
/**
* Assemble a flat list of values (each either a number = 1 word, or an
* array [w1, w2] = two words) into a Uint16Array.
*/
export function assemble(items) {
const flat = [];
for (const it of items) {
if (Array.isArray(it)) flat.push(...it);
else flat.push(it);
}
return Uint16Array.from(flat);
}