/*************************************************************************** 060_link.asm Copyright (c) 1995 Analog Devices Inc. All rights reserved. *************************************************************************** This file is the Link based boot loader of the ADSP21060 processor. Created on 3/7/95 Modified on 6/30/95 for Rev1.0 and on... NOTES: - This Link boot loader is only good for Rev 1.0 and later. ****************************************************************************/ /* Define the addresses of various IOP registers */ #define SYSCON 0x00 #define IMDW0X 0x100 #define IMDW1X 0x200 #define IIVT 0x4 #define SYSTAT 0x03 #define II6 0x40 #define IM6 0x41 #define C6 0x42 #define CP6 0x43 #define EI6 0x45 #define EM6 0x46 #define EC6 0x47 #define DMAC6 0x1c #define LAR 0xc8 #define LCOM 0xc7 #define LCTL 0xc6 #define LSRQ 0xc9 #define LBUF4 0xc4 .SEGMENT/PM seg_ldr; /* The loader begins with the interrupts up to and including the low */ /* priority timer interrupt. */ NOP;NOP;NOP;NOP; /* Reserved interrupt */ ___lib_RSTI: IDLE; /* Implicit IDLE instruction */ JUMP Start_Loader (DB); /* Begin loader */ NOP; /* Pad to next interrupt */ NOP; /* Pad to next interrupt */ NOP;NOP;NOP;NOP; /* Reserved interrupt */ /* Vector for status stack/loop stack overflow or PC stack full: */ ___lib_SOVFI: RTI; RTI; RTI; RTI; /* Vector for high priority timer interrupt: */ ___lib_TMZHI: RTI; RTI; RTI; RTI; /* Vectors for external interrupts: */ ___lib_VIRPTI: RTI; RTI; RTI; RTI; ___lib_IRQ2I: RTI; RTI; RTI; RTI; ___lib_IRQ1I: RTI; RTI; RTI; RTI; ___lib_IRQ0I: RTI; RTI; RTI; RTI; NOP;NOP;NOP;NOP; /* Reserved interrupt */ /* Vectors for Serial port DMA channels: */ ___lib_SPR0I: RTI; RTI; RTI; RTI; ___lib_SPR1I: RTI; RTI; RTI; RTI; ___lib_SPT0I: RTI; RTI; RTI; RTI; ___lib_SPT1I: RTI; RTI; RTI; RTI; /* Vectors for link port DMA channels: */ ___lib_LP2I: RTI; RTI; RTI; RTI; ___lib_LP3I: RTI; RTI; RTI; RTI; /* Vectors for External port DMA channels: */ ___lib_EP0I: R2=DM(DMAC6); /* Get DMAC Control setting */ RTI (DB), R6=R6-R6; nop; DM(DMAC6)=R6; /* zeroed between uses. */ ___lib_EP1I: RTI; RTI; RTI; RTI; ___lib_EP2I: RTI; RTI; RTI; RTI; ___lib_EP3I: RTI; RTI; RTI; RTI; /* Vector for Link service request */ ___lib_LSRQ: RTI; RTI; RTI; RTI; /* Vector for DAG1 buffer 7 circular buffer overflow */ ___lib_CB7I: RTI; RTI; RTI; RTI; /* Vector for DAG2 buffer 15 circular buffer overflow */ ___lib_CB15I: RTI; RTI; RTI; RTI; /* Vector for lower priority timer interrupt */ ___lib_TMZLI: RTI; RTI; RTI; RTI; Start_Loader: ustat1 = dm(SYSCON); bit set ustat1 IMDW0X | IMDW1X | IIVT; dm(SYSCON) = ustat1; L0=0; /* Zero out L-registers so they */ L4=0; /* can be used without wrap */ L8=0; L12=0; L15=0; M5=0; /* Setup M-registers to use for */ M6=1; /* for various memory transfers*/ M13=0; M14=1; R10=DM(SYSCON); /* Read current SYSCON setting */ R12=PASS R10; /* Hold Initial SYSCON setting */ I12 = SYSCON; /* Address of SYSCON */ I15 = 0x20004; R8 = 0x0; /* 1x ( note: 0x10000 would be for lbuf4=2X) */ dm(LCOM)=R8; R8 = 0x0; dm(LSRQ)=R8; R8 = 0x0020; dm(DMAC6) = R8; /* DMAC6 no packing, instruction */ R8 = 0X10030000; /* Lbuf4 enabled, DMA enabled, receive, 48bits */ R7 = 0x10010000; /* Lbuf4 enabled , recieve, 48bits */ dm(LCTL) = R7; /* Lbuf4 enabled, recieve, 48bits */ read_boot_info: CALL read_LINK_word (DB); NOP; NOP; R0=PASS R2; CALL read_LINK_word (DB); NOP; NOP; load_memory: R0=PASS R0; IF NE JUMP (PC, test_dm16_zero); /* After the IDLE completes, the following sequence of instructions will*/ /* be executed: (Remember these are in a loop) */ /* R0=R0-R0, DM(I4,M5)=R9, PM(I12,M13)=R11 */ /* This instructions sets the EQ flag to terminate the loop, writes */ /* the original value to SYSCON, and writes a *new* instruction over */ /* itself. The new instruction is: */ /* PM(0, I8)=PX; */ /* This instruction resets the DMA6 vector to whatever it should be. */ /* The loop will terminate, because of the previous set EQ. Instruction */ /* flow will continue with 0x20005, just like nothing happened! */ final_init: R9=0xb1db0000; /* Load instruction PM(0,I8)=PX; */ R1=0x020000; /* Point to destination */ R2=0x100; /* Load length of last init */ DM(IM6)=M14; /* Set to increment internal ptr */ I4=0x020004; /* Point to 0x020004 for patch */ I8=0x020040; /* Point to DMA6 vector to patch */ R4=PASS R4, R11=R12; /* Clear AZ, hold initial SYSCON */ DO ___lib_RSTI UNTIL EQ; /* Setup dummy loop */ R0=PCSTK; /* Clean off old top-of-loop */ R0=0x20004; /* and replace with new */ PCSTK=R0; /* top-of-loop value */ R0=0x0; DM(II6)=R1; /* Setup DMA to load over ldr */ DM(C6)=R2; /* Load internal count */ DM(CP6)=R0; /* Set CP to 0 */ DM(LCTL)=R8; /* Start DMA transfer */ bit clr irptl 0x10000; /* clear pending EP0 interrupts */ bit set imask 0x10000; /* enable EP0 interrupts */ JUMP 0x20004 (DB); /* Jump to start */ bit set mode1 0x1800; /* allow global interrupts */ IDLE; /* After IDLE, patch then start */ test_dm16_zero: R0=R0-1; IF EQ JUMP (PC, dm16_zero); R0=R0-1; IF NE JUMP (PC, test_dm40_zero); dm32_zero: dm16_zero: R0=R0-R0, I0=R3; LCNTR=R2, DO dm16_zero_loop UNTIL LCE; NOP; dm16_zero_loop: DM(I0,M6)=R0; JUMP read_boot_info; test_dm40_zero: R0=R0-1; IF NE JUMP (PC, test_dm16_init); dm40_zero: PX1=0; PX2=0; R0=R0-R0, I0=R3; LCNTR=R2, DO dm40_zero_loop UNTIL LCE; NOP; dm40_zero_loop: DM(I0,M6)=PX; JUMP read_boot_info; test_dm16_init: R0=R0-1; IF NE JUMP (PC, test_dm32_init); dm16_init: I0=R3; LCNTR=R2, DO dm16_init_loop UNTIL LCE; CALL read_LINK_word (DB); NOP; NOP; dm16_init_loop: DM(I0,M6)=R3; JUMP read_boot_info; test_dm32_init: R0=R0-1; IF NE JUMP (PC, test_dm40_init); dm32_init: I0=R3; LCNTR=R2, DO dm32_init_loop UNTIL LCE; CALL read_LINK_word (DB); NOP; NOP; dm32_init_loop: DM(I0,M6)=R3; JUMP read_boot_info; test_dm40_init: R0=R0-1; IF NE JUMP (PC, test_pm16_zero); dm40_init: I0=R3; LCNTR=R2, DO dm40_init_loop UNTIL LCE; CALL read_LINK_word (DB); NOP; NOP; dm40_init_loop: DM(I0,M6)=PX; JUMP read_boot_info; test_pm16_zero: R0=R0-1; IF EQ JUMP (PC, dm16_zero); R0=R0-1; IF EQ JUMP (PC, dm32_zero); test_pm40_zero: R0=R0-1; IF EQ JUMP (PC, dm40_zero); R0=R0-1; IF NE JUMP (PC, test_pm16_init); pm48_zero: PX1=0; PX2=0; R0=R0-R0, I8=R3; LCNTR=R2, DO pm40_zero_loop UNTIL LCE; NOP; pm40_zero_loop: PM(I8,M14)=PX; JUMP read_boot_info; test_pm16_init: R0=R0-1; IF EQ JUMP (PC, dm16_init); test_pm32_init: R0=R0-1; IF EQ JUMP (PC, dm32_init); test_pm40_init: R0=R0-1; IF EQ JUMP (PC, dm40_init); test_pm48_init: R0=R0-1; IF NE JUMP read_boot_info; pm48_init: I8=R3; LCNTR=R2, DO pm48_init_loop UNTIL LCE; CALL read_LINK_word (DB); NOP; NOP; pm48_init_loop: PM(I8,M14)=PX; JUMP read_boot_info; read_LINK_word: PX=PM(LBUF4); /* Read word from scratch */ RTS (DB); R2=PX1; /* Copy PX values into DREGS */ R2=PASS R2, R3=PX2; /* Test the length */ nop; nop; .ENDSEG;