/*************************************************************************** 060_prom.asm Copyright (c) 1994 Analog Devices Inc. All rights reserved. ***************************************************************************/ /* This file is the PROM based boot loader of the ADSP21060 processor. Gordon A. Sterling (617) 461 - 3076 Systems Software Engineering Analog Devices, Inc. Created on 1/4/94 */ /* Define the addresses of various IOP registers */ #define SYSCON 0x00 #define SYSTAT 0x03 #define II6 0x40 #define IM6 0x41 #define C6 0x42 #define EI6 0x45 #define EM6 0x46 #define EC6 0x47 #define DMAC6 0x1c .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=0; 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: L0=0; /* Zero out L-registers so they */ L4=0; /* can be used without wrap */ L7=0; 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 */ R11=BSET R10 BY 1; /* Set BSO bit for reading ROM */ R10=BCLR R10 BY 1; /* Clear BSO bit for ext write */ DM(SYSCON)=R10; /* Clear BSO bit for writing RAM*/ BIT SET IMASK 0x10000; /* Enable EP0 interrupt */ BIT SET MODE1 0x1800; /* Enable interrupts and nesting*/ R14=0x0221; /* Remove for universal loader */ /* R14=PASS R2; Use this for universal loader */ R15=3; /* EC to load one 48-bit word */ R0=DM(SYSTAT); /* Load the Host ID for use with*/ R0=FEXT R0 BY 8:3; /* the PROM loader. */ BTST R14 BY 9; /* Is this a PROM load? */ IF SZ R11=PASS R10, R0=M5;/* No, don't change BSO bit */ IF NOT SZ R15=R15+R15; /* Yes, set to 6 bytes/48-bit */ BTST R14 BY 0; /* Is this a LINK load? */ IF SZ R11=PASS R10, R0=M5;/* Yes, don't change BSO bit */ IF SZ R15=ASHIFT R15 BY 2;/* Yes, set to 12 nibs/48-bit */ DM(IM6)=M13; /* Setup the DMA registers for */ DM(EM6)=M14; I4 = 0x400600; /* Address of boot rom */ I7 = SYSCON; /* Address of SYSCON */ I12 = SYSCON; /* Address of SYSCON */ I15 = 0x20004; R0=PASS R0; /* Test for HostID == 0 */ IF EQ JUMP read_boot_info; /* Skip over multi-boot */ get_addr: CALL read_PROM_word (DB); NOP; NOP; COMP(R0, R2); IF NE JUMP get_addr (DB); NOP; NOP; DM(EI6)=R3; /* Point to address in PROM */ read_boot_info: CALL read_PROM_word (DB); NOP; NOP; R0=PASS R2; CALL read_PROM_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;*/ R11=BSET R11 BY 8; /* Set IDW to 1 for inst write */ DM(SYSCON)=R11; /* Setup to read PROM, inst wrt */ R1=0x020000; /* Point to destination */ R2=0x100; /* Load length of last init */ R4=R2*R15 (SSI); /* Compute external length */ 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 */ DM(II6)=R1; /* Setup DMA to load over ldr */ DM(C6)=R2; /* Load internal count */ DM(EC6)=R4; /* Load external count */ JUMP 0x20004 (DB); /* Jump to start */ DM(DMAC6)=R14; /* Start DMA transfer */ 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_PROM_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_PROM_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_PROM_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_PROM_word (DB); NOP; NOP; pm48_init_loop: PM(I8,M14)=PX; JUMP read_boot_info; read_PROM_word: R13=DM(SYSCON); /* Save old value of SYSCON */ DM(SYSCON)=R11; /* Set BSO bit for ROM read */ DM(II6)=I15; /* Setup DMA destination address*/ DM(C6)=M14; /* Setup DMA internal length */ DM(EC6)=R15; /* Setup DMA external count */ DM(DMAC6)=R14; /* Start DMA */ IDLE; /* Wait for DMA to complete */ PX=PM(0x020004); /* Read word from scratch */ DM(SYSCON)=R13; /* Reset SYSCON to previous */ RTS (DB); R2=PX1; /* Copy PX values into DREGS */ R2=PASS R2, R3=PX2; /* Test the length */ .ENDSEG;