/**************************************************************************/ /* asmblink.c Written by Matt Begg January '93 */ /**************************************************************************/ /* Sample program for the Analog Devices EZ-Lab board and C compiler 2.0 */ /* or later. */ /* Demonstrates use of asm statements with interrupts and 21020 registers.*/ /* */ /* The asm instruction inserts assembly code directly into the C */ /* compiler's output. You cannot use comments or macros inside the */ /* "quotes" because they will cause assembler errors. The format is: */ /* */ /* asm("instructions":"output_parameters":"input_parameters": \ */ /* "clobbered_registers"); */ /* */ /* Everything in the asm statement must be on one line. "\" means the */ /* next line is part of the current line. */ /* */ /* This example uses the fastest possible interrupt handling. */ /* It involves modifying the run time header, 020_hdr.asm, to call your */ /* interrupt without intervention by the safe, tested, ANSI compliant C */ /* interrupt handler. This means that you are responsible for saving and */ /* restoring any registers or stacks you use. Also, you cannot assume */ /* that l-regs are zero, that there is space on the loop stack, or that */ /* your code will not be interrupted. */ /* There is a potential problem spot in this example where an interrupt */ /* could change astat after it is read but before it is written. Turning */ /* interrupts off during the "or" is an option but using the 21020 bit */ /* set/clr instructions would be better. */ /* */ /* The first thing to do is go to a directory where you do not plan to */ /* compile any other programs. */ /* Then COPY the run time header, 020_hdr.asm from adi_dsp\21k\lib into */ /* your current directory so you don't destroy the original. */ /* Find the "high priority timer interrupt" vector. It should look */ /* something like this: */ /* */ /* * Interrupt vector for high priority timer interrupt: * */ /* ___lib_TMZOI: JUMP ___lib_int_cntrl (DB); */ /* BIT CLR MODE1 0x1000; * Disable interrupts * */ /* BIT SET MODE2 0x00080000; * Freeze cache * */ /* NOP;NOP;NOP;NOP;NOP; * Pad to next vector * */ /* */ /* We want to change it to our own interrupt handler: */ /* */ /* ___lib_TMZOI: rti (db); * return from interrupt * */ /* bit tgl astat 0x200000; * toggle flag 2 * */ /* nop; * use all 8 words * */ /* NOP;NOP;NOP;NOP;NOP; * Pad to next vector * */ /* */ /* Then we need to assemble it. Note that I used "*" for comment chars. */ /* */ /* asm21k 020_hdr.asm */ /* */ /* Then compile: */ /* */ /* g21k blink.c -o blink -a ez.ach -Wall -O2 -save-temps -map */ /* */ /* 020_hdr.obj will be included automatically. If g21k can't find it */ /* here, it will look in adi_dsp\21k\lib. Also, if you compile another */ /* program here, it will pick up your modified 020_hdr.obj */ /* To make sure it worked, look for your interrupt at pm(0x20) then run...*/ #include <21020.h> #include #define SILICON_REVISION(var) \ asm("%0=mode2; \ %0=lshift %0 by -28;" \ :"=d"(var) \ ); void main(void) { int a; /* setup mode2 register so flags 1-3 are output, flag0 is input */ /* turn off leds */ asm("bit set mode2 0x70000; \ bit clr mode2 0x8000; \ bit clr astat 0x700000;"); SILICON_REVISION(a); /* read silicon revision number */ /* if you have a rev. 0 21020 led 3 will come on. Rev. 0 chips has */ /* a subtle anomaly involving flag changes in interrupts. See end of file.*/ if (a == 0) asm("bit set astat 0x400000;"); /* set timer period, current count, enable timer high priority inter- */ /* rupt, and turn timer on */ asm("tperiod = 6250000; \ tcount = 6250000; \ bit set imask 0x10; \ bit set mode2 0x20;"); asm("d: if flag0_in jump d (db);nop;nop;"); for(;;) { /* wait for transition to high using flag bits as condition codes */ /* "=d" indicates an output, %0 which should be a d-reg (r0-r15) */ /* (a) tells the compiler to put the result in variable a */ asm("b: if not flag0_in jump b (db);nop;nop; \ %0=astat;":"=d"(a)); a = a | 0x100000; /* OR led 1 on (in C!) */ /* write the result back into astat from variable a. */ /* wait for transition low and turn off led */ asm("astat=%0; \ c: if flag0_in jump c (db);nop;nop; \ bit clr astat 0x100000; \ "::"d"(a)); } } /* Warning: Do not put subparts of an asm string into separate asm */ /* statements! The optimizer may move them! Use the continuation char. */ /* The optimizer will keep the asm statements inside the for loop, but */ /* otherwise it will feel free to move them around. Because the first */ /* asm statement writes to "a" and the second reads it, the C code, */ /* which reads and writes "a", stays in the middle. */ /* Regarding Rev. 0 21020s: */ /* One anomaly is that the flag bits of the astat register are saved */ /* and restored on sts during interrupts. To get this example */ /* to work with Rev. 0, use the following code: */ /* ___lib_TMZOI: pop sts; bit tgl astat 0x200000; */ /* rti (db); push sts; */ /* NOP;NOP;NOP;NOP; */