From f2d80b5b5df8b6c5f026058f32949f1ff5a9e4ae Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 12 Apr 2001 08:21:01 +0000 Subject: [PATCH] Added as10k1 tool (EMU10K1 FX8010 DSP assembler). --- as10k1/COPYING | 280 +++++++++++++++ as10k1/Makefile.am | 10 + as10k1/README | 432 +++++++++++++++++++++++ as10k1/as10k1.c | 546 ++++++++++++++++++++++++++++++ as10k1/as10k1.h | 60 ++++ as10k1/assemble.c | 438 ++++++++++++++++++++++++ as10k1/configure.in | 9 + as10k1/cvscompile | 24 ++ as10k1/examples/Makefile | 11 + as10k1/examples/blank.asm | 3 + as10k1/examples/chorus.asm | 87 +++++ as10k1/examples/delay.asm | 29 ++ as10k1/examples/emu_constants.asm | 117 +++++++ as10k1/examples/eq2.asm | 69 ++++ as10k1/examples/eq5.asm | 60 ++++ as10k1/examples/fir.asm | 39 +++ as10k1/examples/flanger.asm | 83 +++++ as10k1/examples/sine.asm | 29 ++ as10k1/examples/tremolo.asm | 51 +++ as10k1/examples/vibrato.asm | 31 ++ as10k1/examples/vol_ctrl.asm | 13 + as10k1/list.h | 88 +++++ as10k1/macro.c | 206 +++++++++++ as10k1/output.doc | 50 +++ as10k1/parse.c | 463 +++++++++++++++++++++++++ as10k1/parse.h | 115 +++++++ as10k1/proto.h | 44 +++ as10k1/types.h | 136 ++++++++ 28 files changed, 3523 insertions(+) create mode 100644 as10k1/COPYING create mode 100644 as10k1/Makefile.am create mode 100644 as10k1/README create mode 100644 as10k1/as10k1.c create mode 100644 as10k1/as10k1.h create mode 100644 as10k1/assemble.c create mode 100644 as10k1/configure.in create mode 100644 as10k1/cvscompile create mode 100644 as10k1/examples/Makefile create mode 100644 as10k1/examples/blank.asm create mode 100644 as10k1/examples/chorus.asm create mode 100644 as10k1/examples/delay.asm create mode 100644 as10k1/examples/emu_constants.asm create mode 100644 as10k1/examples/eq2.asm create mode 100644 as10k1/examples/eq5.asm create mode 100644 as10k1/examples/fir.asm create mode 100644 as10k1/examples/flanger.asm create mode 100644 as10k1/examples/sine.asm create mode 100644 as10k1/examples/tremolo.asm create mode 100644 as10k1/examples/vibrato.asm create mode 100644 as10k1/examples/vol_ctrl.asm create mode 100644 as10k1/list.h create mode 100644 as10k1/macro.c create mode 100644 as10k1/output.doc create mode 100644 as10k1/parse.c create mode 100644 as10k1/parse.h create mode 100644 as10k1/proto.h create mode 100644 as10k1/types.h diff --git a/as10k1/COPYING b/as10k1/COPYING new file mode 100644 index 0000000..c7aea18 --- /dev/null +++ b/as10k1/COPYING @@ -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 diff --git a/as10k1/Makefile.am b/as10k1/Makefile.am new file mode 100644 index 0000000..682ae2c --- /dev/null +++ b/as10k1/Makefile.am @@ -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 diff --git a/as10k1/README b/as10k1/README new file mode 100644 index 0000000..c711fc9 --- /dev/null +++ b/as10k1/README @@ -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 + + +This version of the assembler was modified for the ALSA driver by +Jaroslav Kysela . + + +Usage: as10k1 [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 + + 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 + + IO ;defines an Input/output pair + CONTROL ;defines a controlable GPR + DYNamic ;defines a temporary GPR + STAtic ;defines a constant GPR /w initial value + EQU ;assembly time constant + CONstant ;defines a read-only GPR + + DELAY ;defines a Delay line + TABLE ;defines a lookup table + + TREAD , ;defines a tram read + TWRITE , ;defines a tram write + + + INCLUDE <"file name"> ;includes an external file + + FOR =: ;Assembly-time 'for' statement + ENDFOR ;ends a for loop + + + 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: + dynamic dyn + +-- +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: + + static + +or + + sta + +-- +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: + + CONTROL ,, + +-- +IO + +Defines an input and an output register. + + 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 .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: + + constant + +or + + con + + +-- + +DELAY LINES + +Delay lines are defined via three directives: + +-- +DELAY Directive + +Define Delay, used for allocating an amount of TRAM for a delay line. + + DELAY + +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 + + TREAD , + +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 .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. + TWRITE , + +-- +EQU directive: + +Equates a symbol to a be constant which is substituted at assembly time: + +syntax: + + EQU + +-- +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: + + macro arg1,arg2,arg3.... + .... + arg4,arg1,arg2... ;;for example + .... + .... + endm + +were the 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: + + arg1,arg2,arg3.... + +where arg1,arg2,arg3,... are values or symbols. + +-- +Assembly-time For loop + + +usage: + + For =: + ... + ... + macs ,.... + ... + endfor + + and 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? + + + + + + diff --git a/as10k1/as10k1.c b/as10k1/as10k1.c new file mode 100644 index 0000000..9823e47 --- /dev/null +++ b/as10k1/as10k1.c @@ -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 + * mailing list. + * Jaroslav Kysela + */ + +/*************************************************************************** + * * + * 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 +#include +#include +#include +#include +#include +#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 + +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= 0; j--) + //fprintf(fp, "%c", ((u8 *) dsp_code)[i * 4 + j]); + } + + + if(listing) + fclose(listfile); + fclose(fp); + for(i=0;i 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;iname,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 +#include +#include +#include + + +#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; + } + +} + + + + + + + + + + + + + + + diff --git a/as10k1/configure.in b/as10k1/configure.in new file mode 100644 index 0000000..37e9e6c --- /dev/null +++ b/as10k1/configure.in @@ -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) diff --git a/as10k1/cvscompile b/as10k1/cvscompile new file mode 100644 index 0000000..01e8151 --- /dev/null +++ b/as10k1/cvscompile @@ -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 diff --git a/as10k1/examples/Makefile b/as10k1/examples/Makefile new file mode 100644 index 0000000..5d6f391 --- /dev/null +++ b/as10k1/examples/Makefile @@ -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 \ No newline at end of file diff --git a/as10k1/examples/blank.asm b/as10k1/examples/blank.asm new file mode 100644 index 0000000..caa7f1b --- /dev/null +++ b/as10k1/examples/blank.asm @@ -0,0 +1,3 @@ +;;; A blank file for clearing programs from the emu10k1 + + end \ No newline at end of file diff --git a/as10k1/examples/chorus.asm b/as10k1/examples/chorus.asm new file mode 100644 index 0000000..f798c8d --- /dev/null +++ b/as10k1/examples/chorus.asm @@ -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 + + + + + diff --git a/as10k1/examples/delay.asm b/as10k1/examples/delay.asm new file mode 100644 index 0000000..9d31bf2 --- /dev/null +++ b/as10k1/examples/delay.asm @@ -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 + + + + diff --git a/as10k1/examples/emu_constants.asm b/as10k1/examples/emu_constants.asm new file mode 100644 index 0000000..d385104 --- /dev/null +++ b/as10k1/examples/emu_constants.asm @@ -0,0 +1,117 @@ +;some hardware constants C_[n], '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 diff --git a/as10k1/examples/eq2.asm b/as10k1/examples/eq2.asm new file mode 100644 index 0000000..89522a3 --- /dev/null +++ b/as10k1/examples/eq2.asm @@ -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 + diff --git a/as10k1/examples/eq5.asm b/as10k1/examples/eq5.asm new file mode 100644 index 0000000..f6866d3 --- /dev/null +++ b/as10k1/examples/eq5.asm @@ -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 + + + diff --git a/as10k1/examples/fir.asm b/as10k1/examples/fir.asm new file mode 100644 index 0000000..12d7ade --- /dev/null +++ b/as10k1/examples/fir.asm @@ -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 + + + + + + + + diff --git a/as10k1/examples/flanger.asm b/as10k1/examples/flanger.asm new file mode 100644 index 0000000..04a7f4f --- /dev/null +++ b/as10k1/examples/flanger.asm @@ -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 + + + + + diff --git a/as10k1/examples/sine.asm b/as10k1/examples/sine.asm new file mode 100644 index 0000000..1265c9f --- /dev/null +++ b/as10k1/examples/sine.asm @@ -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 + + + + + + + + diff --git a/as10k1/examples/tremolo.asm b/as10k1/examples/tremolo.asm new file mode 100644 index 0000000..fd4033d --- /dev/null +++ b/as10k1/examples/tremolo.asm @@ -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 + diff --git a/as10k1/examples/vibrato.asm b/as10k1/examples/vibrato.asm new file mode 100644 index 0000000..387067e --- /dev/null +++ b/as10k1/examples/vibrato.asm @@ -0,0 +1,31 @@ +;;; written by: Daniel Bertrand + + 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 + + + + + diff --git a/as10k1/examples/vol_ctrl.asm b/as10k1/examples/vol_ctrl.asm new file mode 100644 index 0000000..463638c --- /dev/null +++ b/as10k1/examples/vol_ctrl.asm @@ -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 + + + + diff --git a/as10k1/list.h b/as10k1/list.h new file mode 100644 index 0000000..ad70a5b --- /dev/null +++ b/as10k1/list.h @@ -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 diff --git a/as10k1/macro.c b/as10k1/macro.c new file mode 100644 index 0000000..574b634 --- /dev/null +++ b/as10k1/macro.c @@ -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 +#include +#include"types.h" +#include"proto.h" +#include + +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 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); + } + + } + +} + + + + + + + + + + + + + + + + + + + + + diff --git a/as10k1/output.doc b/as10k1/output.doc new file mode 100644 index 0000000..fe38ded --- /dev/null +++ b/as10k1/output.doc @@ -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 diff --git a/as10k1/parse.c b/as10k1/parse.c new file mode 100644 index 0000000..8523717 --- /dev/null +++ b/as10k1/parse.c @@ -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 +#include +#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;isize = 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;iMAX_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_numdata.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"); + + +} diff --git a/as10k1/parse.h b/as10k1/parse.h new file mode 100644 index 0000000..be71daa --- /dev/null +++ b/as10k1/parse.h @@ -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 + diff --git a/as10k1/proto.h b/as10k1/proto.h new file mode 100644 index 0000000..7f8a736 --- /dev/null +++ b/as10k1/proto.h @@ -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 + + + + + + + diff --git a/as10k1/types.h b/as10k1/types.h new file mode 100644 index 0000000..3aa7564 --- /dev/null +++ b/as10k1/types.h @@ -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 +#include +#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 -- 2.47.1