Added as10k1 tool (EMU10K1 FX8010 DSP assembler).

This commit is contained in:
Jaroslav Kysela 2001-04-12 08:21:01 +00:00
parent a4569af2bb
commit f2d80b5b5d
28 changed files with 3523 additions and 0 deletions

280
as10k1/COPYING Normal file
View file

@ -0,0 +1,280 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS

10
as10k1/Makefile.am Normal file
View file

@ -0,0 +1,10 @@
bin_PROGRAMS = as10k1
as10k1_SOURCES = as10k1.c parse.c assemble.c macro.c
EXTRA_DIST = cvscompile output.doc examples/Makefile examples/*.asm
dsp:
$(MAKE) -C examples
clean:
rm -rf .deps *~
$(MAKE) -C examples clean

432
as10k1/README Normal file
View file

@ -0,0 +1,432 @@
AS10k1 Assembler version A0.99
------------------------------
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.ca>
This version of the assembler was modified for the ALSA driver by
Jaroslav Kysela <perex@suse.cz>.
Usage: as10k1 <asm file> [bin output file]
------
Making binary DSP programs:
example, type:
./as10k1 chorus.asm
(it creates chorus.bin)
--
Loading Binary DSP files
<..TODO..>
Description of files included
------------------------------
Chorus.asm -- chorus effect
Flanger.asm -- flanger effect
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)
sine.asm -- A sinewave generator (can be useful for debuging)
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
===============================================================================
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?

546
as10k1/as10k1.c Normal file
View file

@ -0,0 +1,546 @@
/***************************************************************************
as10k1.c - Main assembler routine
-------------------
Date : May 22, 2000
Copyright : (C) 2000 by Daniel Bertrand
Email : d.bertrand@ieee.ca
***************************************************************************/
/*
* This program was changed to conform the ALSA ideas. Please,
* bug reports and all other things should be discussed on the
* <alsa-devel@alsa-project.org> mailing list.
* Jaroslav Kysela <perex@suse.cz>
*/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include<string.h>
#include "types.h"
#include "as10k1.h"
char *ptralloc[MAXINCLUDES];
static int num_alloc;
int source_line_num=0,file_num=0;
int macro_line_num=0;
FILE *fp=NULL,*listfile;
char *input=NULL,*output=NULL,*listing=NULL,*current_line=NULL,listtemp[60];
int dbg_opt=0;
char version[]="As10k1 assembler version " VERSION;
char help[]="
Usage: as10k1 [option...] asmfile
The as10k1 assembler is for the emu10k1 dsp processor
found in Creative Lab's sblive series of sound cards.
Author: Daniel Bertrand <d.bertrand@ieee.ca>
Options:\n
-l [listfile] Specify a listing file, default is none.
-o [emu10k1 file] Specify an output file, default is based input,
Substituting .asm to .emu10k1
-d [dbg_options...] Turn on debug messages.
s prints all symbols
g prints defined gprs
t prints tram usage
i prints instructions
-h Prints this message
-v Prints version number.
This program is distributed under the GPL.
";
// cli==Command-Line Interface && !Creative Labs Inc.
void parse_cli_args(int argc, char *argv[])
{
int i,j;
for(i=1;i<argc;i++){
if(argv[i][0]=='-'){
switch(argv[i][1]){
case 'o'://specify an output file name
i++;
if((i==argc)||(argv[i][0]=='-')){
printf("Error -o option requires a destination file name\n");
exit(-1);
}
output=argv[i];
break;
case 'd': //turn on debugging messages
j=0;
i++;
printf("Debug on, Displaying:");
if((i==argc)||(argv[i][0]=='-')){
dbg_opt=dbg_opt|DBG_INSTR;//default
i--;
printf(" instructions by default\n");
goto next_cli_arg;
}
while(argv[i][j]!='\0'){
switch(argv[i][j]){
case 's':
dbg_opt=dbg_opt|DBG_SYM;
printf(" Symbols,");
break;
case 'g':
dbg_opt=dbg_opt|DBG_GPR;
printf(" GPRs,");
break;
case 't':
dbg_opt=dbg_opt|DBG_TRAM;
printf(" TRAM,");
break;
case 'i':
dbg_opt=dbg_opt|DBG_INSTR;
printf(" Instructions,");
break;
default:
printf("\b \n**Bad debug option. ");
exit(-1);
}
j++;
}
printf("\b \n");
break;
case 'l'://produce a listing file
//printf("Will save list file to %s\n", );
i++;
if((i==argc)||(argv[i][0]=='-')){
printf("Error -l option requires a destination file name\n");
exit(-1);
}
listing=argv[i];
break;
case 'h'://printf help message
default:
printf("%s",help);
case 'v':
printf("%s\n",version);
exit(0);
}
}else{
if(input==NULL)
input=argv[i];
else{
printf("Error, only one input file can be specified");
as_exit("");
}
}
next_cli_arg:
}
}
int main( int argc, char *argv[] )
{
int i;
char filename[FILENAME_MAX];
extern int ip;
u32 val;
parse_cli_args(argc,argv);
if(input==NULL){
printf("Error, an input file must be specified\n");
exit(-1);
}
//init symbol list:
INIT_LIST_HEAD(&sym_head);
if(listing!=NULL)
if((listfile = fopen(listing, "w"))==NULL){
printf("\nError writing to file %s\n",argv[1]);
as_exit("error");
}
asm_open(input); //opens the source file and starts parsing it.
if(output==NULL){
strcpy(filename, input);
strtok(filename,".\0");
strcat(filename, ".emu10k1");
output = filename;
}
if((fp = fopen(output, "w"))==NULL){
printf("\nError writing to file %s\n",argv[1]);
as_exit("error");
}
if(listing)
fprintf(listfile,"Summary:\n");
/*create header*/
header();
/*output number of instructions*/
val = __cpu_to_le32(ip);
fwrite(&val,sizeof(u16),1,fp);
/* write binary code */
for (i = 0; i < ip; i++) {
val = __cpu_to_le32(dsp_code[i]);
fwrite(&val,sizeof(u32),1,fp);
//for (j = 3; j >= 0; j--)
//fprintf(fp, "%c", ((u8 *) dsp_code)[i * 4 + j]);
}
if(listing)
fclose(listfile);
fclose(fp);
for(i=0;i<num_alloc;i++) //free mem, is this necessary, or will the kernel free it automatically?
free(ptralloc[i]);
return 0; //that's it were done
}
/*this function is called to open a asm file and parse it using the parse function.
this function is called by the main function and also by the parse function
when it encounters an "INCLUDE" directive.
*/
void asm_open(char *name)
{
int fd,i;
int done=0;
char string[MAX_LINE_LENGTH];
struct stat st;
char *next;
int backup_line_num,backup_file_num;
backup_line_num=source_line_num;
backup_file_num=file_num;
if( (include_depth++) > max_depth){
printf("Error: maximum recursive include depth(%d) exceeded\n",max_depth);
as_exit("");
}
buff[num_alloc].name=name;
source_line_num=0;
file_num=num_alloc;
//open the file
if ((unsigned) (fd = open(name, O_RDONLY)) > 255){
as_exit("error opening input file\n");
}
//get it's stats
if ( -1 == fstat( fd, &st)){
printf("Error occured attempting to stat %s\n", name);
as_exit("");
}
if(( ptralloc[num_alloc]=(char *) malloc(st.st_size+2) )== 0){
printf("error allocating memory for file %s\n",name);
close(fd);
as_exit("");
}else{
buff[num_alloc].mem_start=ptralloc[num_alloc];
}
i=num_alloc;
num_alloc++;
buff[i].mem_end = buff[i].mem_start+st.st_size;
read(fd, buff[i].mem_start, st.st_size);
close(fd);
#ifdef DEBUG
printf("File %s opened:\n",name);
#endif
//
//get each line and parse it:
//
current_line=buff[i].mem_start;
source_line_num=1;
next=current_line;
while(next!=buff[i].mem_end){
while((*next!= '\n') && (next!=buff[i].mem_end) )
next++;
listtemp[0]='\0';
*next='\0';
#ifdef DEBUG
printf("%s\n",current_line);
#endif
if(strlen(current_line)>MAX_LINE_LENGTH)
as_exit("Parse error: Line exceeds allowable limit");
strcpy(&string[0],current_line);
done = parse(string,current_line);
if(listing){
if(done==1 &&include_depth!=1)
sprintf(listtemp,"Exiting included file");
if(done!=-3)
fprintf(listfile,"%-50s || %s\n",listtemp,current_line);
}
*next='\n';
if(done==1)
goto done;
if(next!=buff[i].mem_end){
source_line_num++;
next++;
}
current_line=next;
}
if(done==0)
printf("warning no END directive at end of file %s\n",name);
done:
source_line_num=backup_line_num;
file_num=backup_file_num;
include_depth--;
#ifdef DEBUG
printf("File %s closed:\n",name);
#endif
return;
}
void as_exit(const char *message)
{
int i;
if(macro_line_num!=0)
fprintf(stderr, "** Error while expanding macro at line %d\n",macro_line_num);
if(source_line_num!=0)
fprintf(stderr, "** %s.\n** line number %d:\n %s\nIn file: %s\n", message, source_line_num,current_line,buff[file_num].name);
else
fprintf(stderr, "** Error with file:%s\n",buff[file_num].name);
for(i=num_alloc-1;i>=0;i--)
free(ptralloc[i]);
exit(1);
}
inline void output_tram_line( struct list_head *line_head, int type){
struct tram *tram_sym;
struct list_head *entry;
list_for_each(entry, line_head ){
tram_sym=list_entry(entry,struct tram,tram);
if(tram_sym->type==type){
u32 val;
//printf("table read:%s,%x\n",tram_sym->data.name,tram_sym->data.address);
tram_sym->data.address-=TRAM_ADDR_BASE;
fwrite(&(tram_sym->data.address),sizeof(u8),1,fp);
val = __cpu_to_le32(tram_sym->data.value);
fwrite(&val,sizeof(u32),1,fp);
if(listing){
if(type==TYPE_TRAM_ADDR_READ)
fprintf(listfile,"\tRead");
else
fprintf(listfile,"\tWrite");
fprintf(listfile,": 0x3%02x/0x2%02x (%s), offset 0x%07x\n",tram_sym->data.address,tram_sym->data.address,
(prev_sym((&tram_sym->list)))->data.name,tram_sym->data.value);
}
}
}
}
//creates output header
void header(void)
{
int i;
struct sym *sym;
extern struct list_head sym_head;
struct list_head *entry;
if(listing)
fprintf(listfile,"Patch name: \"%s\"\n\n",patch_name);
//patch signature
//1234567890123456
fprintf(fp, "EMU10K1 FX8010 1");
//patchname
fwrite(patch_name,sizeof(char), PATCH_NAME_SIZE,fp);
fwrite(&gpr_input_count,sizeof(u8),1,fp);
//write ins/outs
if(listing)
fprintf(listfile,"*****************************GPR******************************\n");
list_for_each(entry,&sym_head){
sym=list_entry(entry,struct sym,list);
if(sym->type==GPR_TYPE_INPUT){
sym->data.address-=GPR_BASE;
fwrite(&(sym->data.address),sizeof(u8),1,fp);
if(listing)
fprintf(listfile,"%s IN: 0x%03x, OUT: 0x%03x\n",sym->data.name,sym->data.address+GPR_BASE,sym->data.address+GPR_BASE+1);
sym->data.address++;
fwrite(&(sym->data.address),sizeof(u8),1,fp);
}
}
/* dynamic gprs */
fwrite(&gpr_dynamic_count,sizeof(u8),1,fp);
list_for_each(entry,&sym_head){
sym=list_entry(entry,struct sym,list);
if(sym->type==GPR_TYPE_DYNAMIC) {
sym->data.address-=GPR_BASE;
fwrite(&(sym->data.address),sizeof(u8),1,fp);
if(listing)
fprintf(listfile,"GPR Dynamic: 0x%03x(%s)\n",sym->data.address+GPR_BASE,sym->data.name);
}
}
/* static gprs */
fwrite(&gpr_static_count,sizeof(u8),1,fp);
list_for_each(entry,&sym_head){
sym=list_entry(entry,struct sym,list);
if(sym->type==GPR_TYPE_STATIC){
u32 value;
sym->data.address-=GPR_BASE;
fwrite(&(sym->data.address),sizeof(u8),1,fp);
value = __cpu_to_le32(sym->data.value);
fwrite(&value,sizeof(u32),1,fp);
if(listing)
fprintf(listfile,"GPR Static: 0x%03x(%s), Value:0x%08x\n",sym->data.address+GPR_BASE
,sym->data.name,sym->data.value);
}
}
/* control gprs */
fwrite(&gpr_control_count,sizeof(u8),1,fp);
list_for_each(entry,&sym_head){
sym=list_entry(entry,struct sym,list);
if(sym->type==GPR_TYPE_CONTROL){
u32 value;
sym->data.address-=GPR_BASE;
fwrite(&(sym->data.address),sizeof(u8),1,fp);
value = __cpu_to_le32(sym->data.value);
fwrite(&value,sizeof(u32),1,fp);
value = __cpu_to_le32(((struct control *)sym)->min);
fwrite(&value,sizeof(u32),1,fp);
value = __cpu_to_le32(((struct control *)sym)->max);
fwrite(&value,sizeof(u32),1,fp);
fwrite(&(sym->data.name), sizeof(char), MAX_SYM_LEN, fp);
if(listing)
fprintf(listfile,"GPR Control: 0x%03x(%s), value:0x%08x, Min:0x%08x, Max:0x%08x\n",sym->data.address+GPR_BASE,sym->data.name,
sym->data.value,((struct control *)sym)->min,((struct control *)sym)->max);
}
}
/*constant GPRs*/
fwrite(&gpr_constant_count,sizeof(u8),1,fp);
list_for_each(entry,&sym_head){
sym=list_entry(entry,struct sym,list);
if(sym->type==GPR_TYPE_CONSTANT){
sym->data.address-=GPR_BASE;
fwrite(&(sym->data.address),sizeof(u8),1,fp);
fwrite(&(sym->data.value),sizeof(u32),1,fp);
if(listing)
fprintf(listfile,"GPR Constant: 0x%03x(%s), Value:0x%08x\n",sym->data.address+0x100
,sym->data.name,sym->data.value);
}
}
if(listing)
fprintf(listfile,"*****************************TRAM*****************************\n");
/*lookup-tables*/
fwrite(&tram_table_count,sizeof(u8),1,fp);
for(i=0;i<tram_table_count;i++){
u32 value;
value = __cpu_to_le32(tram_lookup[i].size);
fwrite(&value,sizeof(u32),1,fp);
if(listing)
fprintf(listfile,"Lookup-table block:%s, size:0x%08x\n",(&tram_lookup[i])->name,tram_lookup[i].size);
// read lines
fwrite(&(tram_lookup[i].read),sizeof(u8),1,fp);
output_tram_line(&(tram_lookup[i].tram),TYPE_TRAM_ADDR_READ);
//write lines
fwrite(&(tram_lookup[i].write),sizeof(u8),1,fp);
output_tram_line(&(tram_lookup[i].tram),TYPE_TRAM_ADDR_WRITE);
}
/*Delay Lines*/
fwrite(&tram_delay_count,sizeof(u8),1,fp);
for(i=0;i<tram_delay_count;i++){
fwrite(&(tram_delay[i].size),sizeof(u32),1,fp);
if(listing)
fprintf(listfile,"Delay-line block:%s, size:0x%08x\n",tram_delay[i].name,tram_delay[i].size);
// read lines
fwrite(&(tram_delay[i].read),sizeof(u8),1,fp);
output_tram_line(&(tram_delay[i].tram),TYPE_TRAM_ADDR_READ);
//write lines
fwrite(&(tram_delay[i].write),sizeof(u8),1,fp);
output_tram_line(&(tram_delay[i].tram),TYPE_TRAM_ADDR_WRITE);
}
}

60
as10k1/as10k1.h Normal file
View file

@ -0,0 +1,60 @@
/***************************************************************************
as10k1.h - description
-------------------
Date : May 25, 2000
Copyright : (C) 2000 by Daniel Bertrand
Email : d.bertrand@ieee.ca
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include"types.h"
#include"proto.h"
#define max_depth 3 //max include nesting depth
FILE *dc_fp;
int include_depth=0;
#define MAXINCLUDES 25
struct list_head sym_head;
struct alloc
{
char *mem_start;
char *mem_end;
char *name;
};
struct alloc buff[MAXINCLUDES];
u32 dsp_code[DSP_CODE_SIZE];
int ip=0;
int ds_addr=0x100; // DS start at 0x100 ( start of the general purpose registers).
int tram_addr=0; // tram data/addr read/write counter
struct delay tram_delay[MAX_TANK_ADDR];
struct lookup tram_lookup[MAX_TANK_ADDR];
int gpr_input_count=0;
int gpr_output_count=0;
int gpr_static_count=0;
int gpr_dynamic_count=0;
int gpr_control_count=0;
int tram_delay_count=0;
int tram_table_count=0;
int gpr_constant_count=0;
char patch_name[PATCH_NAME_SIZE]="NO_NAME";
int macro_depth=0;

438
as10k1/assemble.c Normal file
View file

@ -0,0 +1,438 @@
/***************************************************************************
assemble.c - Assembles the parsed lines
-------------------
Date : May 24 2000
Copyright : (C) 2000 by Daniel Bertrand
Email : d.bertrand@ieee.ca
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#include <ctype.h>
#include"types.h"
#include"proto.h"
extern int dbg_opt;
extern FILE *listfile;
extern char *listing;
char type_strings[GPR_TYPE_EQUATE+1][20]={
"Input",
"Output",
"Constant",
"Static",
"Dynamic",
"Control",
"Tram Data Reg",
"Tram Address/Read",
"Tram Address/Write",
"Macro arg",
"Equate"
};
void op(int op, int z,int w,int x,int y)
{
int w0, w1;
extern int dsp_code[DSP_CODE_SIZE];
extern int ip;
extern char op_codes[35][9];
extern char listtemp[60];
if (ip >= 0x200)
as_exit("to many instructions");
if (op >= 0x10 || op < 0x00)
as_exit("illegal op code");
//check if gpr is valid, optional do additional modifications
z=declared(z,1);
declared(w,2);
declared(x,3);
declared(y,4);
if ( (dbg_opt & DBG_INSTR) !=0 )
printf( "0x%03x\t%s(%d) \t0x%03x,0x%03x,0x%03x,0x%03x\n",2*ip,op_codes[op],op,z,w,x,y);
if(listing)
sprintf(listtemp, "0x%03x %-9s(%02d) 0x%03x,0x%03x,0x%03x,0x%03x",2*ip,op_codes[op],op,z,w,x,y);
w0 = (x << 10) | y;
w1 = (op << 20) | (z << 10) | w;
dsp_code[ip * 2] = w0;
dsp_code[ip * 2 + 1] = w1;
ip++;
}
int declared(int operand,int i){
struct sym *sym;
extern struct list_head sym_head;
struct list_head *entry;
if ((operand < 0x040)||(operand >= 0x400)){
printf("** Assembler Error with Operand %d:0x%x\n",i,operand);
as_exit("Operand has value out of range");
}
if((operand < 0x400) && operand >= 0x100)
{
list_for_each(entry,&sym_head){
sym=list_entry(entry,struct sym,list);
if( (sym->data.address == operand ) && sym->type!=GPR_TYPE_EQUATE){
if( ( sym->type==GPR_TYPE_CONSTANT) && (i==1) ){
printf("** Assembler Error with Operand %d:0x%x\n",i,operand);
as_exit("** Error: Destination register is a read-only constant");
}
else if(sym->type!=GPR_TYPE_INPUT)
return(operand);
else
return( i==1? operand + 1 : operand);
}
}
}
else if(operand<0x100)
return(operand);
printf("** Assembler Error with Operand %d:0x%x\n",i,operand);
as_exit("Operand address is undeclared");
return(0);
}
//each operand will be something like : , sym1 + sym2 * sym3 ,
//we will recursively decode each symbol and perform proper operations:
int arg_decode(char *operand, int prev_val)
{
int value;
char oper='0';
//Nothing:
if(operand==NULL)
as_exit("Parse Error: missing operand(s)");
if(*operand==','||*operand=='\n'||*operand=='\0')
return(prev_val);
//skip over leading blanks(if any):
advance_over_whites(operand);
if(*operand==','||*operand=='\n' ||*operand=='\0')
return(prev_val);
//get the operator:
if(*operand=='+' || *operand=='-' || *operand=='/' || *operand== '*'){
oper=*operand;
operand++;
}
//skip over any blanks after the oper
advance_over_whites(operand);
//decode the symbol/value:
value=arg_decode2(operand);
//advance to next symbol
while( *operand!='+' && *operand!='-' && *operand!='/' && *operand!= '*' && *operand != '\0' &&*operand!=',' &&*operand!='\n')
operand++;
switch (oper){
case '+':
return(arg_decode(operand,prev_val+value));
case '-':
return(arg_decode(operand,prev_val-value));
case '/':
return(arg_decode(operand,prev_val/value));
case '*':
return(arg_decode(operand,prev_val*value));
default:
return(arg_decode(operand,value));
}
}
//this function does argument decoding
int arg_decode2(char *operand)
{
extern int ip,ds_addr;
extern unsigned int macro_depth;
struct sym *sym;
extern struct list_head sym_head;
struct list_head *entry;
//printf("operand:%s\n",operand);
if(operand[0]=='.' &&isalpha(operand[1])){
add_symbol(operand,GPR_TYPE_STATIC, ds_addr++, -(long)ip);
return(ds_addr-1);
}
// Hex
if((char)(*operand)=='$')
return((int)strtol(operand+1,NULL,16));
// Octal
if((char)(*operand)=='@')
return((int)strtol(operand+1,NULL,8));
// Binary:
if((char)(*operand)=='%')
return((int)strtol(operand+1,NULL,2));
// Decimal:
if( (operand[0] >= '0' && operand[0] <='9') ||operand[0]=='-')
return((int)strtol(operand,NULL,10));
//Symbol:
list_for_each(entry,&sym_head){
sym=list_entry(entry,struct sym,list);
if(symcmp(sym->data.name,operand)==0){
if(sym->type!=TYPE_MACRO_ARG)
return(sym->data.address);
else if(sym->data.value==(macro_depth))
return(sym->data.address);
}
}
printf("Parse error with operand: \"");
while(!symend(operand))
printf("%c",*(operand++));
printf("\"\n");
as_exit("Bad operand");
//printf("** Parse error with operand: \"%s\"\n",operand);
as_exit("\"\nOperand isn't a defined symbol or value");
return(0);
}
#define FACTOR 0x7fffffff
#define SAMP_FREQ 48000
//used by the DC operation to get a long int:
long arg2long(char *operand){
//Nothing:
if(operand==NULL)
as_exit("Parse Error: missing operand(s)");
advance(operand);
//Fractional ( -1 <= operand <= 1 )
if(operand[0]=='#')
return((long)(atof(operand+1)*FACTOR));
// Time value
if(operand[0]=='&')
return((long)(atof(operand+1)*48000));
// Hex:
if((char)(*operand)=='$')
return(strtoul(operand+1,NULL,16));
// Binary:
if((char)(*operand)=='%')
return(strtoul(operand+1,NULL,2));
// Octal:
if((char)(*operand)=='@')
return(strtoul(operand+1,NULL,8));
// Decimal:
if( (operand[0] >= '0' && operand[0] <='9') || operand[0]=='-' || operand[0]=='.'){
if(atof(operand)<1 && atof(operand)>-1)
return((long)(atof(operand)*FACTOR));
else
return(strtol(operand,NULL,10));
}
printf("Parse error with operand:\"%s\"\n",operand);
// while(!symend(operand))
// printf("%c",*operand);
//printf("\"\n");
as_exit("Bad operand");
return(0);
}
void update_symbol(char *name,u16 type,u16 address,u32 value){
struct sym *sym;
switch(type){
case TYPE_MACRO_ARG:
if( issymbol(name,&sym) == -1 ){
add_symbol(name,type,address,value);
return;
}
if(sym->type!=TYPE_MACRO_ARG){
printf("Error: with argument:%s",name);
as_exit("Error:symbol is already defined");
}
sym->data.address=address;
break;
default:
if( issymbol(name,&sym) == -1 ){
add_symbol(name,type,address,value);
return;
}
break;
}
}
void add_symbol(char *name, u16 type, u16 address, u32 value)
{
extern int gpr_input_count,gpr_output_count,gpr_static_count,gpr_dynamic_count,gpr_control_count,gpr_constant_count;
struct sym *sym;
struct tram *tmp_ptr;
extern struct list_head sym_head;
extern struct delay tram_delay[MAX_TANK_ADDR];
extern struct lookup tram_lookup[MAX_TANK_ADDR];
int tmp;
if(name==NULL)
as_exit("Parse Error: This directive requires a label");
if(symcmp(name,NO_SYM)!=0 &&type== GPR_TYPE_CONSTANT){
if(issymbol(name,&sym)==0){
if(sym->data.value != value)
as_exit("Error: Constant redeclared as another value");
else
return;
}
}
if(symcmp(name,NO_SYM)!=0 && type!=TYPE_MACRO_ARG)
{
if(issymbol(name,&sym)!=-1)
as_exit("Parse Error: Symbol is already defined");
if(ismacro(name)!=-1)
as_exit("Parse Error: Symbol is already defined as a macro");
if(isalpha(*name)==0 && name[0]!='.')
as_exit("Parse Error: Symbol must start with a alpha character (a-z)");
}
switch(type){
case GPR_TYPE_CONTROL:
sym=(struct sym *)malloc(sizeof(struct control));
list_add_tail(&sym->list, &sym_head);
break;
case TYPE_TRAM_ADDR_READ:
case TYPE_TRAM_ADDR_WRITE:
sym=(struct sym *)malloc(sizeof(struct tram));
list_add_tail(&sym->list, &sym_head);
//if ID is that of a delay:
if((tmp=((struct sym * ) sym->list.prev)->data.value)>0xff){
tmp=tmp-0x100;
list_add_tail(&(((struct tram *)sym)->tram) , &(tram_delay[tmp].tram) );
if(type== TYPE_TRAM_ADDR_READ)
tram_delay[tmp].read++;
else
tram_delay[tmp].write++;
}else{
tmp_ptr=(struct tram *)sym;
list_add_tail(&(((struct tram *)sym)->tram) , &(tram_lookup[tmp].tram) );
tmp_ptr=(struct tram *)sym;
if(type== TYPE_TRAM_ADDR_READ)
tram_lookup[tmp].read++;
else
tram_lookup[tmp].write++;
}
break;
default:
sym=(struct sym *)malloc(sizeof(struct sym));
list_add_tail(&sym->list, &sym_head);
}
symcpy(sym->data.name,name);
sym->data.address=address;
sym->type=type;
sym->data.value=value;
//GPR debugging:
if((dbg_opt&DBG_GPR) && type<=GPR_TYPE_CONTROL)
printf("GPR: %-16s 0x%03x Value=0x%08x, Type: %s\n",name,address,value,type_strings[type] );
//tram debugging:
else if((dbg_opt&DBG_TRAM && type == TYPE_TRAM_DATA))
printf("TRAM Access: %-16s",name);
else if((dbg_opt&DBG_TRAM && type == TYPE_TRAM_ADDR_WRITE))
printf(", type: Write, using 0x%03x/0x%03x, offset:0x%07x",address,address-0x100,value );
else if((dbg_opt&DBG_TRAM && type == TYPE_TRAM_ADDR_READ))
printf(", type: Read, using 0x%03x/0x%03x, offset:0x%07x",address,address-0x100,value );
//General Symbol debugging:
else if((dbg_opt&DBG_SYM )){
printf("symbol: %-16s 0x%03x Type: %s\n",name,address,type_strings[type]);
}
switch(type){
case TYPE_MACRO_ARG:
return;
case GPR_TYPE_INPUT:
gpr_input_count++;
return;
case GPR_TYPE_OUTPUT:
gpr_output_count++;
return;
case GPR_TYPE_STATIC:
gpr_static_count++;
return;
case GPR_TYPE_DYNAMIC:
gpr_dynamic_count++;
return;
case GPR_TYPE_CONTROL:
gpr_control_count++;
return;
case GPR_TYPE_CONSTANT:
gpr_constant_count++;
return;
default:
return;
}
}

9
as10k1/configure.in Normal file
View file

@ -0,0 +1,9 @@
AC_INIT(as10k1.c)
AM_INIT_AUTOMAKE(as10k1, A0.99)
AC_PROG_CC
AC_PROG_INSTALL
AC_HEADER_STDC
CFLAGS="$CFLAGS"
LDFLAGS="$LDFLAGS"
AC_OUTPUT(Makefile)

24
as10k1/cvscompile Normal file
View file

@ -0,0 +1,24 @@
#!/bin/bash
if test "x$AUTOMAKE_DIR" = "x"; then
if test -d /usr/local/share/automake; then
AUTOMAKE_DIR=/usr/local/share/automake
fi
if test -d /usr/share/automake; then
AUTOMAKE_DIR="/usr/share/automake"
fi
fi
for f in install-sh mkinstalldirs missing; do
cp -av $AUTOMAKE_DIR/$f .
done
aclocal $ACLOCAL_FLAGS
automake --foreign --add-missing
autoconf
export CFLAGS='-O2 -Wall -pipe -g'
echo "CFLAGS=$CFLAGS"
echo "./configure $@"
./configure $@
unset CFLAGS
make

11
as10k1/examples/Makefile Normal file
View file

@ -0,0 +1,11 @@
TARGETS = blank.emu10k1 chorus.emu10k1 delay.emu10k1 eq2.emu10k1 eq5.emu10k1 \
fir.emu10k1 flanger.emu10k1 sine.emu10k1 tremolo.emu10k1 vibrato.emu10k1 \
vol_ctrl.emu10k1
%.emu10k1: %.asm
../as10k1 $<
all: $(TARGETS)
clean:
rm -f *~ *.emu10k1

View file

@ -0,0 +1,3 @@
;;; A blank file for clearing programs from the emu10k1
end

View file

@ -0,0 +1,87 @@
;;; Simple Chorus
;;; Author:Daniel Bertrand
;;; Date: Oct 12, 2000
;;; This program is free software; you can redistribute it and/or modify
;;; it under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 2 of the License, or
;;; (at your option) any later version.
;;; References:
;;; http://www.harmony-central.com/Effects/Articles/Chorus
;;; speed(formerly "delta")=2*pi*freq/48000
;;; this give us our delta value for a specific freq (0.1-0.3Hz is good)
include "emu_constants.asm"
name "Chorus"
in IO
out equ in
speed control 4e-05 , 0 , 1e-4 ; Controls frequency (radians)
delay control &40e-3 ,&10e-3 , &80e-3; twice (2*) average delay (sec)
width control #0.3 ,0 ,0.5 ; width control
mix control #1 ,0 ,#1 ; forward mix
;; sine generator storage spaces:
sinx sta 0
cosx sta #0.5
tmp dyn
tmp2 dyn
;;; Two Delay Lines:
dly delay &80e-3 ;10msec delay line
write twrite dly,0 ; tram writes
ready tread dly,0 ; tram reads
reada tread dly,0
;;;The code:
;;; two opcode sinewave generator (I love this chip!):
macs sinx,sinx,speed,cosx
macs1 cosx,cosx,speed,sinx
;;; 0.5Asint+0.5:
macs tmp,C_2^30,sinx,width
;;; calculate address:
macs ready.a,write.a,delay,tmp
;second addresses for interpolation:
;(interesting how the emu engineers decided that $800 wasn't a needed value)
macints reada.a,ready.a,C_8,C_256
;;; Write to the delay line:
macs write,C_0,in,C_2^29
;;; output values:
;;; 0x55 is 00100000 (?)
macints tmp,C_0,reada.a,C_LSshift; get least significant part of address
interp tmp2,ready,tmp,reada ;interpolate in-between the two delay line readings
macs out,in,tmp2,mix
end

29
as10k1/examples/delay.asm Normal file
View file

@ -0,0 +1,29 @@
;;; A simple delay routine
include "emu_constants.asm"
name "delay"
level control 0.5, #0 , #1
feedback control #0.3, #0 , #1
delay control &0.2, &0, &0.5
io IO
dly delay &0.5 ; 0.5 sec delay block
write twrite dly,0 ; write at 0 sec
read tread dly,&.2 ; read at 0.2 sec
acc3 read.a,delay,write.a,C_0
macs io,io,level,read
macs write,io,read,feedback
end

View file

@ -0,0 +1,117 @@
;some hardware constants C_[n]<DecimalValue>, 'n' indicates negative value
;
;these are in 2's complement representation
C_0 equ $040 ;;00000000
C_1 equ $041 ;;00000001
C_2 equ $042 ;;00000002
C_3 equ $043 ;;00000003
C_4 equ $044 ;;00000004
C_8 equ $045 ;;00000008
C_16 equ $046 ;;00000010
C_32 equ $047 ;;00000020
C_256 equ $048 ;;00000100
C_65536 equ $049 ;;00010000
C_2^23 equ $04A ;;00080000
C_2^28 equ $04b ;;10000000
C_2^29 equ $04c ;;20000000 (C_max /4) +1
C_2^30 equ $04d ;;40000000 ( C_max / 2 ) + 1 (almost half)
C_nmax equ $04e ;;80000000 most negative number
C_max equ $04f ;;7fffffff most positive number
C_n1 equ $050 ;;ffffffff -1
C_n2 equ $051 ;;fffffffe -2
C_n2^30 equ $052 ;;c0000000 C_nmax /2
C_LSshift equ $55 ;;to left shift an address by using macsints
;;for fractional addresses
ZERO equ C_0;
ONE equ C_1;
;;; Hardware Registers:
ACCUM equ $56
CCR equ $57
NOISE1 equ $58
NOISE2 equ $59
IRQ equ $5A
DBAC equ $5B
and macro dest,srcA,srcB
andxor dest,srcA,srcB,C_0
endm
xor macro dest,srcA,srcB
andxor dest,C_n1,srcA,srcB
endm
not macro dest,src
andxor dest,src,C_n1,C_n1
endm
nand macro dest,srcA,srcB
andxor dest,srcA,srcB,C_n1
endm
or macro dest,srcA,srcB
not C_0,srcA
andxor dest,ACCUM,srcA,srcB
endm
nor macro dest,srcA,scrB
not dest,srcA
andxor dest,srcB,dest,srcA
not dest,dest
endm
neg macro dest,src
macs1 dest,C_0,C_1,C_nmax
endm
;;; branch on:
;;; ==0
beq macro count
skip CCR,CCR,C_8,count
endm
;;; !=0
bne macro count
skip CCR,CCR,C_256,count
endm
;;; <0
blt macro count
skip CCR,CCR,C_4,count
endm
;;; always branch
bra macro count
skip C_0,C_max,C_max,count
endm
;;; on saturation
bsa macro count
skip CCR,CCR,C_16,count
endm
bge macro count
C___80 con $80
skip CCR,CCR,C___80,count
endm
bgt macro count
C___180 con $180
skip CCR,CCR,C___180,count
endm
move macro dest,src
macs dest,src,C_0,C_0
endm
end
;;; usefull for testing values before a skip
test macro test
macs C_0,test,C_0,C_0
endm
cmp macro src1.scr2
macints C_0,src1,C_n1,src2
endm

69
as10k1/examples/eq2.asm Normal file
View file

@ -0,0 +1,69 @@
;;; Bass and Treble Effect
;;; By: Daniel Bertrand
;;; Date: Dec 19th,200
;;; License: GPL v2
;;;
name "Eq2"
include "emu_constants.asm"
;;; a and b coefs for bass:
b_b con 2.736129417e-01 5.240710533e-01 2.620355267e-01
a_b con 9.560258858e-01 -4.576868881e-01
;;; a and b coef for treble:
b_t con -4.982305773e-01 9.964611547e-01 -4.982305773e-01
a_t con 9.317583774e-01 -4.356836381e-01
scalein con 2.449e-05, 1.157407407e-04
scaleout con 128, 16192
bass control 0.25,#0,#1
treble control 0.25,#0,#1
in IO
out equ in
tmp dyn
tmpout dyn
dly_b sta 0,0
dly_t sta 0,0
;;; bass filter(iir):
macw tmp, C_0, dly_b+1, a_b+1
macw tmp, tmp, dly_b , a_b
macw tmp,tmp,in,scalein
macints tmp, C_0, tmp, C_2
macs C_0,C_0,C_0,C_0
macmv dly_b+1,dly_b, dly_b+1, b_b+2
macmv dly_b,tmp, dly_b, b_b+1
macw tmp,ACCUM, tmp, b_b
macs tmp,C_0,bass,tmp
macints tmpout,C_0,tmp,scaleout
;;; treble
macw tmp, C_0, dly_t+1, a_t+1
macw tmp, tmp, dly_t , a_t
macw tmp, tmp, in,scalein+1
macints tmp,C_0,tmp,C_2
macs C_0,C_0,C_0,C_0
macmv dly_t+1,dly_t, dly_t+1, b_t+2
macmv dly_t,tmp, dly_t, b_t+1
macw tmp,ACCUM, tmp, b_t
macs tmp,C_0,treble,tmp
macints out,tmpout,tmp,scaleout+1
end

60
as10k1/examples/eq5.asm Normal file
View file

@ -0,0 +1,60 @@
name "5 band EQ"
include "emu_constants.asm"
c0 con -0.98485626 0.98502633 0.99034926 -0.99034926
c1 con -0.95169465 0.95337028 0.93878619 -0.93878619
c2 con -0.84376963 0.85967945 0.84174451 -0.84174451
c3 con -0.47720462 0.61368058 0.73503304 -0.73503304
c4 con -0.28987550 0.11999291 0.72670869 -0.72670869
scalein sta 0.00013665 0.00134590 0.01265823 0.10000000 0.50000000
scaleout sta 420.00000000 140.00000000 50.00000000 20.00000000 10.00000000
in io
out equ in
F_100Hz control #0.2,0,#1
F_316Hz control #0.1,0,#1
F_1000Hz control #0.1,0,#1
F_3160Hz control #0.1,0,#1
F_10000Hz control #0.2,0,#1
dly0 sta 0 0
dly1 sta 0 0
dly2 sta 0 0
dly3 sta 0 0
dly4 sta 0 0
out_tmp dyn
tmp2 dyn
tmp dyn
;;; Band Pass Filter Macro:
BPF macro OUT , IN , DELAY , COEF , SCALEIN , SCALEOUT , FOO , GAIN
macs tmp,C_0,SCALEIN,IN
macs1 tmp,tmp,DELAY,FOO
macw1 tmp,tmp,DELAY,COEF
macw1 tmp,tmp,DELAY+1,COEF+1
macs tmp2,C_0,DELAY+1,COEF+3
macs DELAY+1,DELAY,C_0,C_0
macs tmp2,tmp2,tmp,COEF+2
macs DELAY,tmp,C_0,C_0
macints tmp2,C_0,tmp2,SCALEOUT
macs OUT,OUT,tmp2,GAIN
endm
macs out_tmp,C_0,C_0,C_0
BPF out_tmp,in,dly0,c0,scalein,scaleout,C_nmax,F_100Hz
BPF out_tmp,in,dly1,c1,scalein+1,scaleout+1,C_nmax,F_316Hz
BPF out_tmp,in,dly2,c2,scalein+2,scaleout+2,C_nmax,F_1000Hz
BPF out_tmp,in,dly3,c3,scalein+3,scaleout+3,C_nmax,F_3160Hz
BPF out_tmp,in,dly4,c4,scalein+4,scaleout+4,C_0,F_10000Hz
macs out,out_tmp,C_0,C_0
end

39
as10k1/examples/fir.asm Normal file
View file

@ -0,0 +1,39 @@
;;; low pass filter with cut off at 0.004pi (96Hz)
name "trebass"
include "emu_constants.asm"
coef con 0.038684406 0.058115275 0.113007075 0.194116501 0.287525429 0.377072924 0.447195555 0.485671998 0.485783252 0.447503000 0.377505237 0.287987288 0.194517783 0.113292922 0.058289230 0.038818213
n equ 15 ; filter order
in io
out equ in
bass control 0,0,#1
delay sta 0,0,0,0,0 ,0,0,0,0,0 ,0,0,0,0,0 ,0
tmp dyn
macints delay,in,C_0,C_0
;;;our filter for the left channel
macs C_0,C_0,C_0,C_0
for i = n : 1
macmv delay+i,delay+i-1,delay+i,coef+i
endfor
macs tmp,ACCUM,delay,coef
macs1 out,in,tmp,bass
end

View file

@ -0,0 +1,83 @@
;;; Simple mono flanger
;;; Author:Daniel Bertrand
;;; Date: May 29,2000
;;; This program is free software; you can redistribute it and/or modify
;;; it under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 2 of the License, or
;;; (at your option) any later version.
;;; References:
;;; http://www.harmony-central.com/Effects/Articles/Flanging/
;;; speed( formerly "delta")=2*pi*freq/48000
;;; this give us our delta value for a specific freq (0.1-0.3Hz is good)
include "emu_constants.asm"
name "flanger"
in IO
out equ in
speed control 2e-05 , 0 , 1e-4 ; Controls frequency (radians)
delay control &7e-3 ,$1600 , 20e-3 ; twice (2*) average delay (sec)
width control #0.33 ,0 ,0.5 ; width control
forward control #1 ,0 ,#1 ; forward mix
feedback control 0.3 ,0 ,0.5 ; feedback level
;; sine generator storage spaces:
sinx sta 0
cosx sta #0.5
tmp dyn
tmp2 dyn
;;; Two Delay Lines:
dly delay &20e-3 ;20msec delay line
write twrite dly,0 ; tram writes
ready tread dly,0 ; tram reads
reada tread dly,0
;;;The code:
;;; two opcode sinewave generator (I love this chip!):
macs sinx,sinx,speed,cosx
macs1 cosx,cosx,speed,sinx
;;; 0.5Asint+0.5:
macs tmp,C_2^30,sinx,width
;;; calculate address:
macs ready.a,write.a,delay,tmp
;second addresses for interpolation:
;(interesting how the emu engineers decided that $800 wasn't a needed value)
macints reada.a,ready.a,C_8,C_256
;;; output values:
;;; 0x55 is 00100000 (?)
macints tmp,C_0,reada.a,C_LSshift; get least significant part of address
interp tmp2,ready,tmp,reada ;interpolate in-between the two delay line readings
macs out,in,tmp2,forward
;;; feedback and write to the delay line:
macs write,in,tmp2,feedback
end

29
as10k1/examples/sine.asm Normal file
View file

@ -0,0 +1,29 @@
name "Sine wave Gen"
include "emu_constants.asm"
in io
out equ in
delta control $3afa691,0,$7fffffff ; controls frequency
cosx control #1,0,#1 ; amplitude of sinewave
sinx sta 0
macs sinx,sinx,delta,cosx
macs1 cosx,cosx,delta,sinx
macmv out,cosx,C_0,C_0
end

View file

@ -0,0 +1,51 @@
;;; Tremolo Effect
;;; By: Daniel Bertrand
;;; Oct 29, 2000
include "emu_constants.asm"
name "tremolo"
in IO
out equ in
;;; sinewave generator:
delta control 10e-4,0,1e-2 ; controls frequency (2*pi*freq/48000)
cosx sta #0.5
sinx sta 0
depth control &0.001,0,&0.001
tmp dyn
delay delay &0.01
wrt twrite delay,0
rd tread delay,0
rd2 tread delay,0
c1000 sta $1000
macs wrt,in,C_0,C_0
;;; sinwave generator:
macs sinx,sinx,delta,cosx
macs1 cosx,cosx,delta,sinx
;;; calulate address = depth*sin(wt)+0.5*depth
macs tmp,c1000,depth,C_2^30
macs tmp,tmp,sinx,depth
acc3 rd.a,tmp,C_0,wrt.a
macints rd2.a,rd.a,C_8,C_256 ;;;next address
;;; get fractional address:
macints tmp,C_0,rd.a,C_LSshift
;;; linear interpolate fraction between the 2 reads
;;; output result
interp out,rd,tmp,rd2
end

View file

@ -0,0 +1,31 @@
;;; written by: Daniel Bertrand <d.bertrand@ieee.ca>
include "emu_constants.asm"
name "Vibro Effect"
in io
out equ in
;;; sinewave generator:
delta control 1.5e-3,0,1e-2 ; controls frequency (2*pi*freq/48000)
cosx sta #0.5
sinx sta 0
depth control #1,0,#1
sin2 dyn 1
macs sinx,sinx,delta,cosx
macs1 cosx,cosx,delta,sinx
;; depth control (and add 0.5 DC offset):
macs sin2,C_2^30,sinx,depth
;;; multiply signals by sinewave
macs out,C_0,in,sin2
end

View file

@ -0,0 +1,13 @@
name "hw vol ctrl"
include "emu_constants.asm"
Vol_ctrl control #1,0,#1
in IO
out equ in
macs out,C_0,in,Vol_ctrl
end

88
as10k1/list.h Normal file
View file

@ -0,0 +1,88 @@
/* From linux kernel source */
#ifndef _LINUX_LIST_H
#define _LINUX_LIST_H
/*
* Simple doubly linked list implementation.
*
* Some of the internal functions ("__xxx") are useful when
* manipulating whole lists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/
struct list_head {
struct list_head *next, *prev;
};
#define LIST_HEAD(name) \
struct list_head name = { &name, &name }
#define INIT_LIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static __inline__ void __list_add(struct list_head *new, struct list_head *prev, struct list_head *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
/*
* Insert a new entry after the specified head..
*/
static __inline__ void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
/*
* Insert a new entry before the specified head..
*/
static __inline__ void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}
/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static __inline__ void __list_del(struct list_head *prev, struct list_head *next)
{
next->prev = prev;
prev->next = next;
}
static __inline__ void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
}
static __inline__ int list_empty(struct list_head *head)
{
return head->next == head;
}
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
#endif

206
as10k1/macro.c Normal file
View file

@ -0,0 +1,206 @@
/***************************************************************************
macro.c - various functions to handle macros
-------------------
Date : May 23 2000
Copyright : (C) 2000 by Daniel Bertrand
Email : d.bertrand@ieee.ca
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include<string.h>
#include<stdio.h>
#include"types.h"
#include"proto.h"
#include <ctype.h>
int macro_ctn;
struct macrdef macro[MAX_DEF_MACRO];
extern char *listing,listtemp[60];
extern FILE *listfile;
//determines if an opcode neumonic is a macro
int ismacro(char *mac)
{
int i;
for(i=0;i<macro_ctn; i++){
if(strcasecmp(macro[i].name,mac)==0){
return(i);
}
}
return(-1);
}
//defines a new macro, adds it to the macro list
void new_macro(char *symbol, char *line, char *operand)
{
extern int source_line_num;
struct sym *sym;
if(isalpha(*symbol)==0)
as_exit("Parse Error: Symbol must start with an alpha character");
if(ismacro(symbol)!=-1)
as_exit("Parsed Error: macro is already defined");
if(issymbol(symbol,&sym)!=-1)
as_exit("Parse Error: Symbol is already defined");
macro[macro_ctn].line_num=source_line_num;
macro[macro_ctn].ptr=line;
strcpy(macro[macro_ctn].name,symbol);
macro[macro_ctn].operands=operand;
macro_ctn++;
}
//called from parsed() when a macro is used, stores the arguments and recursively calls the parse().
void macro_expand(int macnum,char *operand )
{
char *line,*next;
int done=0,i,old;
extern unsigned int macro_depth;
extern int macro_line_num;
char string[MAX_LINE_LENGTH];
//initialize macro use:
i=0;
if(macro_depth+1> MAX_MAC_DEPTH)
as_exit("Error exceeded maximum number of recursive macro calls");
old=macro_line_num;
macro_line_num=macro[macnum].line_num;
macro_operand(macro[macnum].operands,operand);
macro_depth++;
line=macro[macnum].ptr;
next=line;
while((*next!= '\n') ) //skip to the line after the macro definition
next++;
line=next;
//Expand the macro calling parse()
while(done!=-1)
{
while((*next!= '\n') )
next++;
*next='\0';
strcpy(&string[0],line);
listtemp[0]='\0';
done=parse(string, line);
macro_line_num++;
*next='\n';
if(listing){
if(done==1)
sprintf(listtemp,"macro expansion done");
if(done!=-3)
fprintf(listfile,"%-50s || %s\n",listtemp,line);
}
if(done==-1)
break;
next++;
line=next;
}
macro_line_num=old;
macro_depth--;
return;
}
//assigns calling arguments with defined symbols.
void macro_operand(char *symbols,char *val)
{
char tmp[MAX_LINE_LENGTH],*ptr=symbols,*sym=tmp,*next_sym=sym,*next_val=val;
extern unsigned int macro_depth;
if(symbols==NULL&&val==NULL)
return;
if(symbols==NULL||val==NULL)
as_exit("error in macro_operand, Null operand list");
while(*ptr!='\n' && *ptr!=';')
ptr++;
*ptr='\0';
strcpy(tmp,symbols);
//#ifdef DEBUG
// printf("syms:\"%s\",vals:\"%s\"\n",sym,val);
//#endif
*ptr='\n';
while(1){
//skip over blanks:
advance(next_sym);
advance(next_val);
sym = next_sym;
val = next_val;
if(*next_val=='\0' && *next_sym=='\0')
return;
if(*next_sym=='\0')
as_exit("Error, To many arguments for defined Macro");
if(*next_val=='\0')
as_exit("Error, Not enough arguments for defined macro");
while(*next_sym != '\0' && *next_sym!= ',' )
next_sym++;
while(*next_val != '\0' && *next_val!= ',' )
next_val++;
// printf("sym=\"%s\";val=\"%s\"(=0x%x)\n",sym, val,arg_decode(val,0) );
if( sym!=next_sym || val!=next_val ){
update_symbol(sym,TYPE_MACRO_ARG,arg_decode(val,0),macro_depth+1);
}
}
}

50
as10k1/output.doc Normal file
View file

@ -0,0 +1,50 @@
EMU10K1 patch binary file format (.emu10k1)
-------------------------------------------
Notice: this format is a bit different from the original as10k1 assembler.
16 bytes signature 'EMU10K1 FX8010 1' ; last number means the patch version
32 bytes name ; ASCIIZ patch name
1 byte count of input/output GPRS
? bytes input/output GPRS
1 byte count of dynamic GPRS
? bytes dynamic GPRS
1 byte count of static GPRS
? pairs
1 byte static GPRS
1 dword (little-endian, 32-bit) value
1 byte count of control GPRS
? entries
1 byte control GPRS
1 dword (little-endian, 32-bit) value
1 dword (little-endian, 32-bit) range - min
1 dword (little-endian, 32-bit) range - max
32 bytes symbol name ; ASCIIZ symbol name
1 byte count of constant GPRS
? pairs
1 byte constant GPRS
1 dword (little-endian, 32-bit) value
1 byte count of TRAM lookup tables
? entries
1 dword (little-endian, 32-bit) size
1 byte count of read lines
? pairs
1 char address of the TRAM line
1 dword (little-endian, 32-bit) size in samples
1 byte count of write lines
? pairs
1 char address of the TRAM line
1 dword (little-endian, 32-bit) size in samples
1 byte count of TRAM delay tables
? entries
1 dword (little-endian, 32-bit) size
1 byte count of read lines
? pairs
1 char address of the TRAM line
1 dword (little-endian, 32-bit) size in samples
1 byte count of write lines
? pairs
1 char address of the TRAM line
1 dword (little-endian, 32-bit) size in samples
2 word (little-endian, 16-bit), count of 64-bit instructions
? double-dwords (little-endian, 64-bit) instruction

463
as10k1/parse.c Normal file
View file

@ -0,0 +1,463 @@
/***************************************************************************
parse.c - parses each line, stores in temp space
-------------------
Date : May 23 2000
Copyright : (C) 2000 by Daniel Bertrand
Email : d.bertrand@ieee.ca
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include<string.h>
#include<stdio.h>
#include"types.h"
#include"parse.h"
#include"proto.h"
/*
This function parses the asm file calling appropriate functions to blow up macros, include files,
define constants, keep track of equates, and handling assembler directives.
This function is called on a line by line basis.
normally returns value 0 except when "end" directive is encountered in which case it returns 1,
the "endm" directive which return -1, or the "endfor" deirective which returns -2
*/
extern char type_strings[GPR_TYPE_EQUATE+1][20];
extern int dbg_opt;
extern char *listing,listtemp[60];
extern FILE *listfile;
int parse( char line_string[MAX_LINE_LENGTH], char *line)
{
int tmp,i,arg[4];
static int defmacro=0; //set to 0 unless we're in a macro definition
int op_num;
char *leading_symbol=NULL, *op_name_ptr,*tmpc;
extern char patch_name[PATCH_NAME_SIZE];
extern int ds_addr,ip,tram_addr,tram_delay_count,tram_table_count;
extern unsigned int macro_depth;
struct sym *sym;
struct control *control;
extern struct delay tram_delay[MAX_TANK_ADDR];
extern struct lookup tram_lookup[MAX_TANK_ADDR];
if( line_string[0]=='\0' || line_string[0]==';'||line_string[0]=='%'||line_string[0]=='*')
return(0);
//remove anything after a ; if one exist
tmpc=line_string;
while( *tmpc != ';' &&*tmpc != '\0')
tmpc++;
*tmpc='\0';
//check for a leading symbol
if( line_string[0] != ' ' && line_string[0] != '\t'){
if(strlen(leading_symbol=strtok(line_string,": \t\n"))>MAX_SYM_LEN ){
printf("symbol \"%s\" is more than %d characters long\n",leading_symbol,MAX_SYM_LEN );
as_exit("Parse error");
}
//address ref for skip command:
if(*leading_symbol=='.'){
if( issymbol(leading_symbol,&sym)!=-1)
(sym->data.value)+=ip-1;
}
op_name_ptr=strtok(NULL, " \t\n");
}else{
op_name_ptr=strtok(line_string, " \t\n");
}
if(op_name_ptr==NULL)
return(0);
//check if it a macro:
if((tmp=ismacro(op_name_ptr)) != -1 ){
if(defmacro==0)
macro_expand(tmp,strtok(NULL,""));
return(0);
}
if( (op_num=op_decode(op_name_ptr))==-1) {
printf("**Parse Error with op code field \"%s\"\n",op_name_ptr);
as_exit("Parse Error: Bad neumonic");
}
//check to see if we're defining a macro
if(leading_symbol!=NULL && defmacro!=0 && op_num!=CON && op_num!=CONSTANT)
as_exit("Parse error: Cannot define symbols inside of a macro");
switch(op_num){
case EQU:
add_symbol(leading_symbol,GPR_TYPE_EQUATE,arg_decode(strtok(NULL, " \t\n"),0),0);
return(0);
case DS:
printf("**Assembler warning: \"DS\" will be obsoleted\n");
case DYNAMIC:
case DYN:
add_symbol(leading_symbol,GPR_TYPE_DYNAMIC,ds_addr++,0);
if( (tmpc=strtok(NULL, " \t\n"))==NULL)
tmp=0;
else if((tmp=arg_decode(tmpc,0)) <=0)
tmp=1;
for(i=1;i<tmp;i++){
add_symbol( (char *)NO_SYM ,GPR_TYPE_DYNAMIC,ds_addr++,0);
}
return(0);
case MACRO:
new_macro(leading_symbol,line,strtok(NULL, "")-line_string+line);
defmacro++;
return(0);
case DC:
printf("**Assembler warning: \"DC\" will be obsoleted\n");
case STA:
case STATIC:
tmpc = strtok(NULL, " ,\t\n") ;
if(tmpc == NULL)
as_exit("Error DC directive must contain an initial value");
while(tmpc!=NULL ){
if( tmpc[0] == '&' )
tmp=arg2long(tmpc)*0x800; //account for 11 bit shift of addresses
else
tmp=arg2long(tmpc);
add_symbol(leading_symbol,GPR_TYPE_STATIC,ds_addr++,tmp);
leading_symbol=(char *)NO_SYM;
tmpc=strtok(NULL, " ,\t");
}
return(0);
case CONSTANT:
case CON:
//declaring constants inside of a macro is legal and needed for branch macros
if(defmacro!=0)
return (0);
tmpc = strtok(NULL, " ,\t\n") ;
if(tmpc == NULL)
as_exit("Error Constant directive must contain a value");
while(tmpc!=NULL ){
if( tmpc[0] == '&' )
tmp=arg2long(tmpc)*0x800; //account for 11 bit shift of addresses
else
tmp=arg2long(tmpc);
// add_constant(leading_symbol,tmp);
add_symbol(leading_symbol,GPR_TYPE_CONSTANT,ds_addr++,tmp);
leading_symbol=(char *)NO_SYM;
tmpc=strtok(NULL, " ,\t");
}
return(0);
case IO:
add_symbol(leading_symbol,GPR_TYPE_INPUT,ds_addr++,0);
add_symbol(strcat(leading_symbol,".o"),GPR_TYPE_OUTPUT,ds_addr++,0);
return(0);
case DIN:
as_exit("DIN is obsoleted, use IO instead");
add_symbol(leading_symbol,GPR_TYPE_INPUT,ds_addr++,0);
return(0);
case DOUT:
as_exit("DOUT is obsoleted, use IO instead");
add_symbol(leading_symbol,GPR_TYPE_OUTPUT,ds_addr++,0);
return(0);
case DD:
add_symbol(leading_symbol,GPR_TYPE_EQUATE,0x100+tram_delay_count,0);
(&tram_delay[tram_delay_count])->size = arg2long( strtok(NULL, " \t\n" ) ) +1;
INIT_LIST_HEAD( &(tram_delay[tram_delay_count].tram ) );
strcpy((&tram_delay[tram_delay_count])->name,leading_symbol);
if((dbg_opt&DBG_TRAM))
printf("Delay Line: %-16s, length: 0x%05x samples,\n",(&tram_delay[tram_delay_count])->name, (&tram_delay[tram_delay_count])->size);
tram_delay_count++;
return(0);
case DT:
add_symbol(leading_symbol,GPR_TYPE_EQUATE,tram_table_count,0);
(&tram_lookup[tram_table_count])->size = arg2long( strtok(NULL, " \t\n" ) );
INIT_LIST_HEAD( &(tram_lookup[tram_table_count].tram) );
strcpy((&tram_lookup[tram_table_count])->name,leading_symbol);
if((dbg_opt&DBG_TRAM))
printf("Lookup table: %-16s, length: 0x%05x samples\n",leading_symbol, (&tram_delay[tram_delay_count])->size);
tram_table_count++;
return(0);
case DW:
//two symbols are created, "symbol" -> addr:0x2xx ; value: tram id #
// "symbol.a" -> addr:0x3xx ; value: write offset
add_symbol(leading_symbol,TYPE_TRAM_DATA,tram_addr+0x200, arg_decode(tmpc=strtok(NULL, " \t," ),0) );
add_symbol( strcat(leading_symbol,".a") ,TYPE_TRAM_ADDR_WRITE, (tram_addr++)+0x300 ,
arg2long(strtok(NULL," \t\n")));
if(dbg_opt&DBG_TRAM)
printf(", in segment: \"%s\"\n",tmpc);
return(0);
case DR:
add_symbol(leading_symbol,TYPE_TRAM_DATA,tram_addr+0x200,arg_decode(tmpc=strtok(NULL, " \t," ),0) );
add_symbol(strcat(leading_symbol,".a"),TYPE_TRAM_ADDR_READ,(tram_addr++)+0x300,
arg2long(strtok(NULL," \t\n")));
if(dbg_opt&DBG_TRAM)
printf(", in segment: \"%s\"\n",tmpc);
return(0);
case CONTROL:
if( (tmpc = strtok(NULL, "\t ,\n")) ==NULL)
as_exit("Parse Error: missing operand(s)");
if( tmpc[0] == '&' )
tmp=arg2long(tmpc)<<11; //account for 11 bit shift of addresses
else
tmp=arg2long(tmpc);
add_symbol(leading_symbol,GPR_TYPE_CONTROL,ds_addr++,tmp);
issymbol(leading_symbol,(struct sym **)(&control));
if( (tmpc = strtok(NULL, "\t ,\n") )==NULL)
as_exit("Parse Error: missing operand(s)");
if( tmpc[0] == '&' )
control->min=arg2long(tmpc)<<11; //account for 11 bit shift of addresses
else
control->min=arg2long(tmpc);
if( (tmpc = strtok(NULL, "\t ,\n")) ==NULL)
as_exit("Parse Error: missing operand(s)");
if( tmpc[0] == '&' )
control->max=arg2long(tmpc)<<11; //account for 11 bit shift of addresses
else
control->max=arg2long(tmpc);
return(0);
case ENDM:
if(defmacro==1) {
defmacro--;
return(0);
}else if(macro_depth!=0)
return(-1);
else
as_exit("Error, stray ENDM directive");
case END:
if(defmacro==1)
as_exit("Error end directive in macro definition");
return(1);
case INCLUDE:
if(defmacro==1)
as_exit("Error, cannot include file from within macro definition");
if(listing){
sprintf(listtemp,"including file");
fprintf(listfile,"%-50s || %s\n",listtemp,line);
}
asm_open(strtok(NULL, "\'\""));
return(-3);
case NAME:
advance_to_end(op_name_ptr);
op_name_ptr++;
advance_over_whites(op_name_ptr);
if(dbg_opt)
printf("Patch name:%s\n",op_name_ptr);
// printf("%s\n",op_name_ptr);
tmpc=strtok(op_name_ptr,"\"");
if(tmpc==NULL)
as_exit("Bad name string, did you remember quotes\"\"");
if(strlen(tmpc)>PATCH_NAME_SIZE)
as_exit("Error Patch name exceeds maximum allowed amount (16)");
memset(patch_name,0,PATCH_NAME_SIZE);
strcpy(patch_name,tmpc);
return(0);
case FOR:
if(listing){
sprintf(listtemp,"FOR LOOP");
fprintf(listfile,"%-50s || %s\n",listtemp,line);
}
for_handler(line,strtok(NULL,""));
return(-3);
case ENDFOR:
sprintf(listtemp,"FOR LOOP DONE");
return(-2);
default:
if(defmacro==0){
for(i=0;i<=3;i++)
arg[i]=arg_decode(strtok(NULL,","),0);
op(op_num,arg[0],arg[1],arg[2],arg[3]);
return(0);
}else
return(0);
}
return(0);
}
//assembly-time for loop handling:
void for_handler(char *begin, char *operand )
{
char *ptr,*next,*line,string[MAX_LINE_LENGTH];
int start,end,i,done;
int diff, incr=1;
struct sym *sym;
ptr=strtok(operand,"=");
start= arg_decode(strtok(NULL,":"),0);
end = arg_decode(strtok(NULL," \t"),0);
if(end>start)
diff=end-start;
else{
diff=start-end;
incr=-1;
}
if( (issymbol(ptr,&sym))!=-1)
sym->data.address=start;
else
add_symbol(ptr,GPR_TYPE_EQUATE, start,0);
issymbol(ptr,&sym);
while(*begin!='\0')
begin++;
begin++;
for(i=0;i<diff;i++){
next=begin;
line=next;
done=0;
while(done==0)
{
while((*next!= '\n') )
next++;
listtemp[0]='\0';
*next='\0';
if(strlen(line)>MAX_LINE_LENGTH)
as_exit("Parse error: Line exceeds allowable limit");
strcpy(&string[0],line);
//printf("%s\n",string);
done=parse(string, line);
if(listing)
if(done!=-2)
fprintf(listfile,"%-50s || %s\n",listtemp,line);
*next='\n';
if(done==-2)
break;
next++;
line=next;
}
sym->data.address = start+(incr*(i+1));
}
}
int op_decode(char *op_name_ptr)
{
int op_num;
for(op_num=0;op_num<NUM_OPS;op_num++){
if( strcasecmp(&op_codes[op_num][0],op_name_ptr) == 0 )
return(op_num);
}
return(-1);
}
//check if a symbol is used and returns it's pointer value in sym
//normally returns 0, if symbol is non exitant, return -1
int issymbol(char *symbol,struct sym **sym)
{
extern unsigned int macro_depth;
extern struct list_head sym_head;
struct list_head *entry;
list_for_each(entry,&sym_head){
(*sym)=list_entry(entry,struct sym,list);
if(symcmp((char *)&(*sym)->data.name,symbol)==0){
if((*sym)->type!=TYPE_MACRO_ARG)
return(0);
else if( (*sym)->data.value==(macro_depth+1) )
return(0);
}
}
return(-1);
}
//compares to words, the words can be terminated with a ' ', '\t', ',' or '\0'
int symcmp (char *symbol1,char *symbol2)
{
while(1){
if(*symbol1!=*symbol2)
return(-1);
symbol1++;
symbol2++;
if(symend(symbol1) && symend(symbol2))
return(0);
}
}
//copies a symbol, symbols can be terminated with a ' ' , '\t' , ',' , '\n' , a '\0'
void symcpy (char *dest, char *source)
{ int i=0;
for(i=0;i<=MAX_SYM_LEN;i++){
if(source[i]== ' ' || source[i]=='\0' ||source[i]==',' ||source[i]=='\n' || source[i]=='\t' ) {
dest[i]='\0';
return;
}
dest[i]=source[i];
}
as_exit("Error, Maximum symbol length exceeded");
}

115
as10k1/parse.h Normal file
View file

@ -0,0 +1,115 @@
/***************************************************************************
parse.h - description
-------------------
Date : May 23 2000
Copyright : (C) 2000 by Daniel Bertrand
Email : d.bertrand@ieee.ca
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
//#define NUM_OPS 17 //number of op code mneumonic and directives
enum foo {
MACS=0,
MACS1,
MACW,
MACW1,
MACINTS,
MACINTW,
ACC3,
MACMV,
ANDXOR,
TSTNEG,
LIMIT,
LIMIT1,
LOG,
EXP,
INTERP,
SKIP,
EQU,
DS,
DYNAMIC,
DYN,
MACRO,
DC,
STATIC,
STA,
DIN,
DOUT,
DD,
DT,
DW,
DR,
CONTROL,
ENDM,
END,
INCLUDE,
NAME,
FOR,
ENDFOR,
IO,
CONSTANT,
CON,
NUM_OPS
};
char op_codes[NUM_OPS+1][9]=
{
"MACS",
"MACS1",
"MACW",
"MACW1",
"MACINTS",
"MACINTW",
"ACC3",
"MACMV",
"ANDXOR",
"TSTNEG",
"LIMIT",
"LIMIT1",
"LOG",
"EXP",
"INTERP",
"SKIP",
"equ",
"ds",
"dynamic",
"dyn",
"macro",
"dc",
"static",
"sta",
"din",
"dout",
"delay",
"table",
"twrite",
"tread",
"control",
"endm",
"end",
"include",
"name",
"for",
"endfor",
"IO",
"constant",
"con",
"NotAnOp"
};
//extern int file_num,source_line_num

44
as10k1/proto.h Normal file
View file

@ -0,0 +1,44 @@
#ifndef PROTO_H
#define PROTO_H
//as10k1.c:
void as_exit(const char *message);
void asm_open(char *name);
void header(void);
//assemble.c:
void op(int,int,int,int,int);
int arg_decode(char *operand,int prev_val);
int arg_decode2(char *operand);
int symbol2index(char *operand, int *flag);
long arg2long(char *operand);
void update_symbol(char *name,u16 type,u16 address, u32 value);
void add_symbol(char *name,u16 type,u16 address, u32 value);
int declared(int operand,int i);
//parse.c:
int parse( char line_string[MAX_LINE_LENGTH], char *line);
int op_decode(char *op_name_ptr);
void new_symbol( char *name_ptr, int constant);
void new_dc(char *symbol,long value, int addr);
int issymbol(char *symbol,struct sym **sym);
void for_handler(char *begin, char *operand );
int symcmp (char *symbol1,char *symbol2);
void symcpy (char *dest, char *source);
//macro.c
void new_macro(char *symbol, char *line, char *operands);
void macro_expand(int macnum,char * operand);
void macro_operand(char *line,char *value);
int ismacro(char *mac);
#define DSP_CODE_SIZE 0x400
#endif

136
as10k1/types.h Normal file
View file

@ -0,0 +1,136 @@
#ifndef TYPES_H
#define TYPES_H
#include "list.h"
//i'm not sure about these type definitions, especially on non-x86
#ifdef NO_LINUX //in the event this actually is used on non-linux platforms
#define u8 unsigned char
#define u16 unsigned short int
#define u32 unsigned int
#else
#include <linux/types.h>
#include <asm/byteorder.h>
#define u8 __u8
#define u16 __u16
#define u32 __u32
#endif
#define MAX_SYM_LEN 32
#define PATCH_NAME_SIZE 32
#define MAX_TANK_ADDR 0x9f //maximum number of tank address
#define MAX_LINE_LENGTH 256 //max length of a source code line
#define GPR_TYPE_INPUT 0x0
#define GPR_TYPE_OUTPUT 0x1
#define GPR_TYPE_CONSTANT 0x2
#define GPR_TYPE_STATIC 0x3
#define GPR_TYPE_DYNAMIC 0x4
#define GPR_TYPE_CONTROL 0x5
#define TYPE_TRAM_DATA 0x6
#define TYPE_TRAM_ADDR_READ 0x7
#define TYPE_TRAM_ADDR_WRITE 0x8
#define TYPE_MACRO_ARG 0x9
#define GPR_TYPE_EQUATE 0xa //just a symbol
#define TRAM_READ 0x1
#define TRAM_WRITE 0x2
#define DBG_SYM 1
#define DBG_GPR 2
#define DBG_TRAM 4
#define DBG_INSTR 8
struct symbol{
char name[MAX_SYM_LEN ];
u32 value; //initial value of GPR, or the value (if it's an equate);
u16 address; //address of GPR
};
struct sym{
struct list_head list;
u16 type;
struct symbol data;
};
struct control{
struct list_head list;
u16 type;
struct symbol data;
u32 max;
u32 min;
};
//all tram read/writes from a linked-list with list head in the delay/lookup-table definition block.
struct tram{
struct list_head list;
u16 type;
struct symbol data;
struct list_head tram;
};
//a delay block
struct delay{
u32 size;
u8 read;
u8 write;
struct list_head tram;
char name[MAX_SYM_LEN];
};
//a lookup-table block
struct lookup{
u32 size;
u8 read;
u8 write;
struct list_head tram;
char name[MAX_SYM_LEN];
};
struct macrdef{
char *ptr;
char name[MAX_SYM_LEN ];
char *operands;
int line_num;
};
#define NO_SYM "__NO_NAME"
#define MAX_DEF_MACRO 25
#define MAX_MAC_DEPTH 5
//some C macros:
//blank ptr:
#define blank(PTR) (*PTR==' ' || *PTR=='\t')
//value is end of a symbol:
#define symend(ptr) ( blank(ptr) || *ptr=='\0'|| *ptr==','||*ptr=='+'||*ptr=='-'||*ptr=='/'||*ptr=='*')
//used for advancing over white spaces and comma:
#define advance(ptr) while( *ptr == ' ' || *ptr== '\t' ||*ptr==',' ){ ptr++;}
//advance over white spaces only:
#define advance_over_whites(ptr) while(*ptr == ' ' || *ptr== '\t'){ptr++;}
//advances to end of symbol
#define advance_to_end(ptr) while(!symend(ptr)){ptr++;}
//"returns" pointer to the previous entry:
#define prev_sym(entry) list_entry(entry->prev,struct sym,list)
#endif
#define GPR_BASE 0x100
#define TRAM_DATA_BASE 0x200
#define TRAM_ADDR_BASE 0x300