Alternate FV-1 Assembler

# asfv1

Alternate Assembler for Spin Semi FV-1

An alternate assembler for the Spin Semiconductor FV-1 DSP. This assembler aims to replicate some of the behaviour of the Spin FV-1 assembler in standard Python, for developers who are unable or unwilling to use the Spin provided IDE.

## Requirements

• Python >= 2.6

## Installation

Make sure your system has a python interpreter (preferably python3), then install from the Python Package Index using the pip command:

$pip3 install asfv1  or $ pip install asfv1


For system-specific installation instructions see System Specific Installation below.

## Description

asfv1 reads a single FV-1 DSP program then parses and assembles it. If no errors are encountered, machine code is written to an output file. If the output filename ends with 'hex', an Intel hex encoded output is produced, otherwise raw binary data is written.

usage: asfv1 [-h] [-q] [-v] [-c] [-s] [-p {0,1,2,3,4,5,6,7}] [-b]
infile outfile

• infile : Filename for an ASCII, utf-8 or utf-16 encoded text file containing FV-1 assembly (see Assembly Program Syntax below)

• outfile : Filename for assembled output. If filename ends with 'hex', an Intel hex file is written.

• -h, --help : Show a help message and exit

• -q, --quiet : Suppress warning messages

• -v, --version : Print program version and exit

• -c, --clamp : Clamp out of range instruction operand values without error. A warning message is printed for each clamped operand.

• -s, --spinreals : Interpret integer literals 1 and 2 as 1.0 and 2.0 respectively. This option should be used with SpinASM assembly.

• -p {0,1,2,3,4,5,6,7} : Nominate one of the eight available program slots on an FV-1 eeprom as the target. When this option is used with binary output, machine code is offset appropriately in the target file, allowing for assembly into an existing binary bank file. When Intel HEX output is requested, the output file will include a single program and relevant offset information for the target program.

• -b, --binary : Force output in binary format, even if outfile ends with 'hex'.

## Assembly Program Syntax

An FV-1 assembly program recognised by asfv1 closely resembles the SpinIDE (.spn) format. Input is an ASCII, utf-8 or utf-16 encoded text file containing zero to 128 FV-1 instructions with optional targets, labels, comments and assembly directives. All text is matched case-insensitively and runs of whitespace characters (newline, tab, space) are condensed. Each of the input instructions is assembled into a single 32 bit machine code. If less than 128 assembly instructions are input, the unallocated program space is padded with 'NOP' instructions (0x00000011).

For example:

; A complete, but useless FV-1 assembly program
MEM	delay	int(32767*3/5)	; ~0.6 sec delay
EQU	output	DACL		; use DACL for output
EQU	vol	REG0		; use REG0 for volume
ldax	POT0		; read from POT0
wrax	vol,0.0		; write volume to register
main:	ldax	input		; read from input
mulx	vol		; scale by volume
wra	delay,0.0	; write to delay
rda	delay^,0.5	; read from delay midpoint
rda	delay#,0.5	; read from delay end
wrax	output,0.0	; write to output


When assembled with asfv1, the resulting machine code contains 9 instructions and padding with NOP instructions:

$asfv1 -q example.asm example.bin$ hd example.bin
00000000  80 40 00 11 00 00 02 05  00 00 04 06 00 00 02 85  |.@..............|
00000010  00 00 04 0a 00 00 00 02  20 04 cc c0 20 09 99 80  |........ ... ...|
00000020  00 00 02 c6 00 00 00 11  00 00 00 11 00 00 00 11  |................|
00000030  00 00 00 11 00 00 00 11  00 00 00 11 00 00 00 11  |................|
*
00000200


A semicolon character ';' starts comment text. The assembler will ignore all text including the ';' up to the end of a line. Examples:

; Comment out a whole line
target:	or	0xffffff	; comment to end of line
trget2:		; comment between target and instruction
and	0x000000	; comment follows instruction
; xor 0xa5a5a5		; instruction commented out
; excessive commenting:
addr02: cho			; op=0x14 interpolated memory access
rdal,		; type=0x3 read offset(LFO) into ACC
SIN1,		; lfo=0x1 use SIN1 LFO
COS|REG		; flags=0xb register LFO and use COS output


### Label Assignment

EQU	LABEL	EXPRESSION


Directive 'EQU' assigns the constant value resulting from the evaluation of 'EXPRESSION' (see Operand Expressions below) to the text label 'LABEL'. LABEL must begin with one alphabetic character in the set [A-Z,a-z] followed by any number of alphanumeric characters or underscores: [A-Z,a-z,0-9,_]. EXPRESSION can contain any previously assigned labels, including those pre-defined by the assembler (see Pre-defined Labels below). For compatibility with SpinASM, the order of 'EQU' and 'LABEL' may be swapped. Examples:

EQU	input	ADCL		; assign value of ADCL (0x14) to 'input'
EQU	r3_7	3/7		; assign the value 3/7 to 'r3_7'
inve	EQU	1/r3_7		; assign the inverse of 'r3_7' to 'inve'


EQU does not generate any code in the program, it merely reserves the name for subsequent use. The parser evaluates all expressions in-place so a label must be declared before it is used:

	or	missing		; error
EQU	missing	123		; missing is used before definition

parse error: Undefined label missing on line ...


Re-defining an already assigned label is allowed, but will generate a warning message:

EQU	POT0	POT1		; point POT0 to POT1

warning: Label POT0 re-defined on line ...


Labels, mnemonics and operators are matched case insensitively:

EQU	Label_One	-1.0	; assign 1.0 to 'LABEL_ONE'
eQu	lABEL_oNE	-1.0	; assign 1.0 to 'LABEL_ONE' again
Or	label_one	; or -1.0
oR	LABEL_ONE	; or -1.0
OR	LABEL_ONE	; or -1.0
or	lAbEl_OnE	; or -1.0


### Memory Allocation

MEM	LABEL	EXPRESSION


Addresses in the FV-1's 32768 sample circular buffer can be assigned by the assembler using the 'MEM' directive. MEM reserves a portion of memory that represents a delay of 'EXPRESSION' samples between the start point and end point, and assigns three labels:

LABEL	start of delay segment
LABEL^	midpoint of delay segment
LABEL#	end of delay segment


EXPRESSION must define an integer number of samples or a parse error will be generated:

MEM	invalid	123.4556	; invalid memory definition

Memory INVALID length 123.4556 not integer on line 42

MEM	third	32767//3	; valid due to integer divide
MEM	d0_13	int(0.13*32767)	; valid due to explicit type cast


LABEL has the same requirements as for EQU, and the assigned labels can be used in any expression. Eg:

MEM	Del_A	375		; declare a 375 sample delay called 'DEL_A'
wra	DEL_A,0.0	; write to start of delay, DEL_A=0
rda	del_a^,0.5	; read 0.5*midpoint of delay, DEL_A^=187
rda	DeL_A#,0.5	; add to 0.5*end of delay, DEL_A#=375


The assembler keeps track of allocated memory, placing each new segment immediately after those previously defined. Each segment with a delay of LENGTH, will consume LENGTH+1 samples of memory. An attempt to use more than the available space will trigger a parse error:

MEM	long	0x7f00		; long:0 long#:0x7f00
MEM	short	0x00ff		; short:0x7f01 short#:0x8000 (error)

parse error: Delay exhausted: requested 255 exceeds 254 available on line ...


The caret character '^' is also used in expressions as the bitwise XOR operator, so expressions which reference a delay may need to be explicitly parenthesised if used with '^':

	or	delay^0xffff	; parse error - delay label takes caret

parse error: Unexpected INTEGER 0xffff on line ...

or	(delay)^0xffff	; OK - parentheses enforce ordering
or	delay^^0xffff	; OK


### Jump Targets

Jump targets label a particular address in the program output and can be placed between instructions anywhere in a source file. A jump target is a text label followed by a colon ':' character:

		skp	1,TARGET1	; skip offset is 3
skp	2,TARGET2	; skip offset is 2
skp	4,TARGET3	; skip offset is 1
or	0xff	Target1:	; target after instr
TARGET2:			; target on its own line
tarGET3:	and	0x12	; all three targets point to this instruction


Use of an already defined label for a target will result in a parse error:

EQU	error	-1
error:	or	0x800000

parse error: Target ERROR already assigned on line ...


Target labels are not assigned values until parsing is complete and they can only be used as a destination for a skip instruction. For example, the following attempt to offset from a target generates a parse error:

	skp	NEG,target	; skip to target if negative
skp	0,target+1	; error - invalid expression
target:	clr			; clear ACC
wrax	DACL,0.0	; output only positive

parse error: Unexpected OPERATOR + on line ...


To achieve the desired if/else behaviour, use a second target:

	skp	NEG,ifpart	; skip to target if negative
skp	0,elsept	; else, skip ahead
ifpart:	clr			; clear ACC
elsept:	wrax	DACL,0.0	; output >= 0


### Instructions

An instruction is represented by a mnemonic text followed by zero or more operand expressions separated by commas:

Mnemonic Operands Description
rmpa MULTIPLER multiply delay[(*ADDR_PTR)] and accumulate
rdax REGISTER,MULTIPLIER multiply (*REGISTER) and accumulate
rdfx REGISTER,MULTIPLIER subtract (*REGISTER), multiply and add (*REGISTER)
wrax REGISTER,MULTIPLIER write (*REGISTER) and multiply
wrhx REGISTER,MULTIPLIER write (*REGISTER) and highpass shelf
wrlx REGISTER,MULTIPLIER write (*REGISTER) and lowpass shelf
maxx REGISTER,MULTIPLIER load maximum of absolute values
absa load absolute value of ACC
mulx REGISTER multiply by (*REGISTER)
log MULTIPLIER,OFFSET log2(ACC), multiply and offset
exp MULTIPLIER,OFFSET 2**(ACC), multiply and offset
sof MULTIPLIER,OFFSET multiply and offset
and VALUE bitwise AND
clr clear ACC
or VALUE bitwise OR
xor VALUE bitwise XOR
not bitwise negation
skp CONDITIONS,OFFSET skip offset instructions if all conditions met
jmp OFFSET jump offset instructions
nop no operation
wlds LFO,FREQUENCY,AMPLITUDE ajdust SIN LFO
jam LFO reset LFO
raw U32 insert U32 opcode

Each operand must evaluate to a single constant numeric value. The sizes and types are specific to each instruction (see Instruction Reference below).

### Operand Expressions

Operand expressions are any valid combination of labels, numbers, parentheses and the following operators, listed from highest to lowest precedence. Operators on the same line have the same precedence, and are evaluated left to right - except for '**' (power) which works as in the python intepreter.

Operator Function Note
| bitwise or valid for integers only
^ bitwise xor valid for integers only
& bitwise and valid for integers only
<< >> shift left, shift right valid for integers only
+ - add, subtract
* // / multiply, divide // forces integer divide
+ - ~ int unary plus, minus, invert bits, integer cast ! is an alias for ~
** power Binds right: -10**-2 = -0.01

The following numeric entry formats are recognised:

Literal Value Type
123 123 Decimal integer
0x123 291 Hexadecimal integer
$pip install asfv1  ### MacOS Download a copy of the "Latest Python 3 Release" for Mac OS from python.org. Install the package, then open a terminal and run: $ pip3 install asfv1


### Windows

Download a copy of the "Latest Python 3 Release" for Windows from python.org. Install the package, then open a command prompt and run:

C:\> pip3 install asfv1


For more detailed information, please refer to the Python package installation documentation and installing pip with packaging managers at packaging.python.org.

### Install from Source

If you would prefer to not use pip, or if your system is provided with and older version of Python (eg MacOS), asfv1 can be installed using the included setup.py script. Fetch a copy of the latest source package, unpack it and then run the installer as root:

$sudo python ./setup.py install  Alternatively, the main source file can be run directly with a python interpreter without the need to install any files: $ python ./asfv1.py infile.asm outfile.bin


## Project details

Uploaded source
Uploaded py3