This chapter documents the backend for the unSP CPU architecture.

Legal
=====

This module is written in 2021-2024 by Adrien Destugues and is covered by the vasm copyright without modifications.

General
=======

Instructions consist of one 16-bit word, sometimes followed by a 16-bit immediate value or address.

Single byte memory accesses are not possible.

The address space is 22 bits, with a segment register which is used by adding a D: prefix to addresses (otherwise, only 16 bit addresses to the "zero page" are accessible). The segment register is adjusted automatically when a post or pre increment or decrement overflows the address register. There is also a segment register for the PC, but that does not require specific handling from the assembler at the moment (except for the presence of an LJMP instruction allowing to call code in another segment).

Conditional jump instructions in unSP are PC relative and allow to jump up to 63 instructions forward or backwards. When the code in a conditional branch is longer than this, a 2-instruction sequence is used: an opposite condition jump to PC+2, followed by a GOTO to the branch target. This is done automatically as needed by vasm if you use the "l" prefix to the jump instruction (for example LJAE instead of JAE). In this case, the long form instruction is used if necessary, and the short form is used if the target is close enough. Without the prefix, the instruction can only use the PC-relative mode and you get an assembler error if you try to jump too far.

Extensions
==========

This backend provides the following specific extensions:

  - The parser understands a lo/hi-modifier to select low- or high-byte of a 22-bit word. The character < is used to select the low-byte and > for the high-byte. It has to be the first character before an expression.

  - When applying the operation /65536, %65536 or &65535 on a label, an appropriate lo/hi-byte relocation will automatically be generated.

Compatibility with other assemblers and disassemblers
=====================================================

This backend accepts instructions in a traditional format, reusing the mnemonics from naken_asm. The official unSP documentation uses an unusual syntax, which would probably require a custom syntax module.

The closest syntax to naken_asm is the oldstyle one, but there are some differences:

  - Instructions must be prefixed by a tab or spaces. Everything on the first column is parsed as a label.

  - Addresses can be represented with parentheses in addition to square brackets: LD R1,(1234) instead of LD R1, [1234]

  - The push/pop instructions list of registers is indicated as two operands instead of a range: PUSH R1, R1, (SP) instead of PUSH R1-R1, [SP]

  - Hexadecimal numbers can be prefixed with $ instead of 0x

The backend internally outputs data in big endian format. This is not compatible with other tools, which use little endian. The endianness can be changed at the output stage when generating a raw binary, by using vasm standard -ole command-line switch.

Known Problems
==============

Only version 1.0 and 1.1 of the ISA is supported (they are identical as far as instruction encoding is concerned, but a few instructions have slight behavior differences). Versions 1.2 and 1.3 are backwards compatible but introduce additional instructions:

  - CPU control: SECBANK ON/OFF; FRACTION ON/OFF; IRQNEST ON/OFF

  - Load and stores of DS and flag registers

  - Bit operations: TSTB, SETB, CLRB, INVB (with registers or indirect addressing)

  - Shift operations: ASR, ASROR, LSL, LSLOR, LSR, LSROR, ROL, ROR

  - Multiplication and MAC: unsigned * unsigned

  - Divisions: DIVQ, DIVS, EXP

  - Jumps: GOTO and CALL with indirect address (GOTO MR, CALL MR)

Version 2.0 is not fully compatible and introduces even more instructions.