
AS10k1 Assembler version 1.0 (last updated June 2001)
----------------------------

This is an assembler for the emu10k1 DSP chip present in the creative SB
live, PCI 512, and emu APS sound cards. It is used to make audio effects such 
as a flanger, chorus or reverb.


Author: Daniel Bertrand <d.bertrand@ieee.org>


This program is distributed with the emu10k1 opensource linux drivers
at available at opensource.creative.com

An online emu10k1 programming guide is available here:

http://members.home.com/d-bertrand/

Installation:
-------------

untar the package, cd into as10k1 directory, type "make" enjoy!

type:
	tar zxfv as10k1-DATE.tgz
	cd as10k1
	make

this will create program: as10k1

Type "make install" to install it in /usr/local/bin/	
	
	
Usage: as10k1 <asm file> [options] [bin output file] 
------

Making binary DSP programs:

example, type:

./as10k1 chorus.asm

(it creates chorus.bin)

type "as10k1 -h" for a full list of possible options.


--
Loading Binary DSP files

To load the dsp program use the emu-dspmgr command distributed
with the driver in the utils/libdsp/ directory.


e.g. to load flanger, type:


./emu-dspmgr -lac97_l -fflanger.bin ( after this should hear the flanger effect
				   on the left front analog output)


for more info on loading refer to the the emu-dspmgr man page.


Description of files included
------------------------------


chorus.asm	-- chorus effect
atten.asm	-- Provides a 12dB attenuation
delay.asm	-- generates Echos, this is _not_ a reverb
eq5.asm		-- A 5 band Equalizer (needs a bit more work)
fir.asm		-- A low pass filter (A demo of a fir filter implementation)
flanger.asm	-- flanger effect
gain.asm	-- Provides a 12dB boost
master_r	-- Right Master volume control
master_l	-- Left Master volume control
sine.asm	-- A sinewave generator (can be useful for debuging)
tone.asm	-- A bass/treble tone control effect
tremolo.asm	-- A tremolo effect (or is it a vibrato?)
vibrato.asm	-- A vibrato effect (or is it a tremolo?)
vol_ctrl.asm	-- provides support for the hardware volume control
emu_constants.asm -- not an effect, just contains handy constants and macros



To add support to the "file" command, add the following to:
/usr/share/magic 



#------------------------------------------------------------------------------
# Emu10k1: file(1) magic for emu10k1 dsp files for drivers at:
#             http://opensource.creative.com
#            
0	string		emu10k1-dsp-file	Emu10k1 dsp file,
>17	short		>0			format version %d,
>19	string		>\0			dsp program name: "%s"




 

===============================================================================


Programming Usage:
=================

Assembly Syntax
---------------

Assembly lines generally have four fields seperated by spaces or tabs:


Name_Field   Opcode_field    Operand_Field   Comment_Field
----------   ------------    -------------   -------------
[symbol]      [mnemonic]      [operands]       [text]


With this assembler, each line can have a maximum of 256 characters and each
symbol can be a maximum of 32 characters. Symbols ARE case sensitive, opcodes
ARE NOT.

OPCODES
--------


All instructions require 4 operands, they have the format

	<opcode> R,A,X,Y
	
(note some documentation out there the call the R operand as Z and the A
operand as W).

Here are 16 opcodes.

   0x0 (MACS) : R = A + (X * Y >> 31)   ; saturation
   0x1 (MACS1) : R = A + (-X * Y >> 31)  ; saturation
   0x2 (MACW) : R = A + (X * Y >> 31)   ; wraparound
   0x3 (MACW1) : R = A + (-X * Y >> 31)  ; wraparound
   0x4 (MACINTS) : R = A + X * Y  ; saturation
   0x5 (MACINTW) : R = A + X * Y  ; wraparound (31-bit)
   0x6 (ACC3) : R = A + X + Y  ; saturation
   0x7 (MACMV) : R = A, acc += X * Y >> 31
   0x8 (ANDXOR) : R = (A & X) ^ Y
   0x9 (TSTNEG) : R = (A >= Y) ? X : ~X
   0xa (LIMIT) : R = (A >= Y) ? X : Y
   0xb (LIMIT1): R = (A < Y) ? X : Y
   0xc (LOG) : ...
   0xd (EXP) : ...
   0xe (INTERP) : R = A + (X * (Y - A) >> 31)  ; saturation
   0xf (SKIP) : R,CCR,CC_TEST,COUNT  


Special note on the accumulator: 
mac* instruction with ACCUM as A operand     => uses Most significant 32 bits.
macint* instruction with ACCUM as A operand  => uses Least significant 32 bits.


For more details on the emu10k1 see the dsp.txt file distributed with the
linux driver.



Operands
--------

Operands can be specified as either a symbol or a value. hex values are
prefixed by $, octal by @, and binary by %.

e.g.:

123 decimal value
$123 hex value
@123 octal value
%01101 binary value

The operands for emu10k1 instructions are always addresses of registers, there
are no instruction which take immediate values.

Operands currently support basic arithmetic, It does not support bedmas (or is it bodmas)
so don't try to use (). Infact don't put spaces either (for now, until I fix this).

Summary of assembler directives
-------------------------------

	  NAME "string"			;give a name to the patch

<symbol>  IO				;defines an Input/output pair	
<symbol>  CONTROL <symbol>		;defines a controlable GPR	
<symbol>  DYNamic <number of storage spaces>	;defines a temporary GPR
<symbol>  STAtic <initial value>		;defines a constant GPR /w initial value
<symbol>  EQU <Value equated>		;assembly time constant
<symbol   CONstant <value>		;defines a read-only GPR	

<symbol>  DELAY  <value>		;defines a Delay line
<symbol>  TABLE  <value>		;defines a lookup table

<symbol>  TREAD  <tram id>,<value>	;defines a tram read 
<symbol>  TWRITE <tram id>,<value>	;defines a tram write


	  INCLUDE <"file name">		;includes an external file

	  FOR <variable>=<start>:<finish> ;Assembly-time 'for' statement
	  ENDFOR			;ends a for loop


<symbol>  MACRO	arg1,arg2,arg3....	;used for define a macro
	  ENDM				;end a macro definition

	  END				;ends the code


Detailed description of directives:
----------------------------------

( <> brackets indicate required fields, [] brackets indicate optional fields)

DYNamic  directive (replaces DS):

Defines a storage space from the gpr pool on the emu10k1. The
assembler maintains a pointer to the gpr registers (starting at $100). The
symbol is assigned the value of the address of the gpr pointer. The pointer is
increment by the number following the dynamic directive.

syntax:
<symbol> dynamic <number of storage spaces

or

<symbol> dyn <number of storage spaces>

--
STAtic directive (replaces DC):

Similar to dynamic, but places an initial value in the memory location.

The values specified are slightly different from operands for instructions. 
The values are 32 bit signed intergers so that a maximum magnitude of 2^31 can
be stored. values can be in signed decimal, unsigned octal, binary and hex, 
and in fractional decimal (values between -1 to 1) for filter coefficients.

A fractional decimal is specified using the '#' prefix and can include an 
exponent. These values should be used with the fractional "mac" instructions.

NEW! fractional numbers are now handle automatically, a value between 1 and 
-1 will be converted into fractional form. The old # form still works though.
(BUG:confusion occurs at 1 and -1 however, should 1 be represented as $1
 or $7ffffff?, currently defaults to $1, so #1 still has some importance)

examples:
	.03412
	123E-3
	#-0.1236

syntax:

<symbol> static <initial value>

or

<symbol> sta <initial value>

--
CONTROL

Control registers are similar to DC, but they also include a min and max value. The control register is used
by a mixer app to change values in a GPR (a volume control, for example). 

syntax:

<symbol> CONTROL <initial value>,<min>,<max>

--
IO

Defines an input and an output register.

<symbol> IO

It defines two register, but they both use the symbol. The assembler handles it automagically
depending on whether you're performing a read (X, Y or Z operand) or a write (R operand) to the GPR.

-
If you insist on having two different symbols for read/write (for readability or whatever), use an EQU, 

i.e.:

IN   IO
OUT  EQU  IN

-
To force a read from the output (for whatever reason) use <symbol>.o (i.e. OUT.o)

Writing to an input is not allowed.
--
CONSTANT

defines a read-only constant GPR

When the assembler encounters a CONSTANT define, it'll try three things. First 
it'll check to see if the defined constant is a hardware constant, if so 
substitutes that instead. Next the assembler check to see if another constant 
has alrady been declared with the same value, if so it'll substitute it. Else
it'll declare a new GPR for holding the value of the constant.  

syntax:

<symbol> constant  <value>

or

<symbol> con  <value>


--

DELAY LINES

Delay lines are defined via three directives:

--
DELAY Directive	

Define Delay, used for allocating an amount of TRAM for a delay line.

<symbol>  DELAY  <value>

The symbol is used to identify this delay line.The value is the amount of TRAM 
allocated, it may be specified as a decimal,hex, octal, binary or time value. 

The time value is prefixed with '&' and represents seconds of time.

e.g.

foo DELAY &100e-3  ;;a 100msec delay line
bar DELAY 1000	;;a 1000 sample delay line

--
TABLE directive

Define lookup Table

same as DELAY but for lookup tables. 

--
TREAD Directive

Define read: used for defining a TRAM read point

<symbol1>  TREAD <symbol2>,<value>

The value represents the read point within the delay line. symbol2 defines 
which delay line this read belongs to.

Symbol1 is a pointer to TRAM data register associated with this TRAM read 
operation. The assembler will create <symbol1>.a which points to the TRAM
address register.

example:

fooread TREAD 100e-3,foo
	macs  fooread.a,one,two,three   ; writes a new tram read address 
	macs  temp,fooread,one,two	; reads the data from the delay line 

--
WRITE Direcive

Define write: same as TREAD but used for writing data to a delay line.
<symbol1>  TWRITE <symbol2>,<value>

--
EQU directive:

Equates a symbol to a be constant which is substituted at assembly time:

syntax:

<symbol> EQU <Value equated>

--
END directive

The END directive should be placed at the end of the assembly source file. If
the END directive is not found, a warning will be generated. All text located
after the END directive is ignored.

Syntax:

[symbol]  END

--
INCLUDE Directive

The include directive is used to include external asm files into the current 
asm file.

Syntax:

	INCLUDE <"file name">

The file name Must be enclosed in "" or '' .

examples:

	include 'qwerty.asm'
	include "foobar.asm"
	

--	

MACRO directive 

Used for defining a macro

Defining Macro:

<symbol> macro arg1,arg2,arg3....
	....
	<opcode>  arg4,arg1,arg2...  ;;for example
	....	
	....
	endm

were the <symbol> used is the nmeumonic representing the macro. 

arg1,arg2,arg3... can be any symbols (auto-defining and local to a macro)
as long as the symbol is not already in use outside the macro (i.e. as 
a DC, DS, etc.).

There's no limit to how many arguments can be used.


Using Macro:

	<macro nmeumonic> arg1,arg2,arg3....

where arg1,arg2,arg3,... are values or symbols.

--
Assembly-time For loop


usage:

	For <symbol>=<start>:<stop>
		...
		...
		macs <symbol>,....
		...
	endfor
	
<start> and <stop> must be integers


--
Handling Skips

the as10k1 assembler handles skips in a special way explained best by an example:

	skip CRR,CRR,CC_test,.foo
	...
	...
	...
.foo	...

the "." tell the assembler that the symbol is for skipping purposes, it will
automatically define a GPR when parsing the skip instruction, and when the second
.foo is encountered it will insert the number of instructions to skip. (the skip
instruction needs a GPR by design, so don't blame me for the half-assness of it). 



Features NOT YET Supported
==========================

any ideas?






