/************************************************************* * File: lib/k4102.s * Purpose: A serialICE kernel for the BDMR4102 eval board. This * kernel uses the SerialICE-Port interface. * Author: Phil Bunce (pjb@carmel.com) * Revision History: * 980615 Created from k4101.s * 980615 Put data back into bss section, recommend link kseg1. No app. * 981026 Added changes from email 981025. * 981028 Moved alt ram addr to a2000000. * 980130 Removed savearea and instr_buffer from bss. * 990317 Added mrally's 990315 update * * This file contains the PROM resident code (the IceKernel) necessary to * permit programs to be debugged using LSI Logic's SerialIce. This * implementation is for the BDMR4102 (the 4102 evaluation board). * It uses the ICEport interface to communicate with * with the ICEmonitor. * * The code in this module executes in kseg1 (non cacheable), leaves * BEV=1, and does not initialize the caches. * * Example compile/link command for this file: * * pmcc -crt0 -prom -syms -T bfc00000 -o k4102 k4102.s * * You can either merge your application with this file and include it in * the PROM, or download your application into RAM and execute it there. * * To merge this file with you application. Use the following command line. * * pmcc -prom -board bdmr4102 -o myprog myprog_files... * * To download your application into RAM you should compile/link your * program using the following command. * * pmcc -board bdmr4102 -o myprog myprog_files... * * This file contains the following blocks of code: * reset_vector - The start of execution * utlb_vector - UTLB exception handler * gen_vector - Handler for all other exceptions * ice_loop - Main loop of ICE * get_cmd - Get one command word from serial interface * get_word - Get one word from serial interface * put_word - Put one word to serial interface * cpu_init - Perform CPU-specific initialization * * This module requires the following areas of RAM: * INSTR_BUFFER - This is where the instructions that have been * received from the host are saved. * SAVEAREA - This is where I save the context of the * downloaded program. * */ /* one and only one of these two lines MUST be enabled */ #define BOOT_SDRAM /* SDRAM=0 SRAM=0xa2000000 */ /*#define BOOT_SRAM /* SRAM=0 SDRAM=0xa2000000 */ /*#define NO_SDRAM /* don't enable SDRAM at all. Use w BOOT_SRAM */ /*#define USE_NO_INTS /* don't use ints for kernel wakeup */ #ifndef LR4102 #define LR4102 #endif #include /* Commands that are sent by the IceController */ #define SENDA0 0x12345678 /* execute INSTR_BUFFER */ #define RUN_MODE 0x87654321 /* run application */ #define SENDSAP 0xDEADBEEF /* send SAVEAREA pointer */ #define ATTN 0x55 /* transfer control to IceKernel */ #define ACK 0xaa /* reply to ATTN */ /* Offsets into the SAVEAREA */ #define SA_VERS 2 #define ICE_SAV 0 /* save area version */ #define ICE_SAH 1 /* save area header size */ #define ICE_MAP 2 /* bit-map for SAVEAREA */ #define ICE_IBS 3 /* size of instr buffer */ #define ICE_GWP 4 /* pointer to get_word routine */ #define ICE_PWP 5 /* pointer to put_word routine */ #define ICE_EPC 6 /* saved so that it can be set */ #define ICE_LE 7 /* set if little endian */ #define ICE_SAHSIZE 8 /* size of save area header */ /* end of header. The remainder is kernel-specific */ #define ICE_AT (ICE_SAHSIZE+0) /* v0 is used to hold the value received */ #define ICE_V0 (ICE_SAHSIZE+1) /* v0 is used to hold the value received */ #define ICE_A0 (ICE_SAHSIZE+2) /* a0 is used to hold the value to be sent */ #define ICE_A1 (ICE_SAHSIZE+3) /* a1 is used as a temp */ #define ICE_A2 (ICE_SAHSIZE+4) /* a1 is used as a temp */ #define ICE_A3 (ICE_SAHSIZE+5) /* a1 is used as a temp */ #define ICE_T0 (ICE_SAHSIZE+6) /* t0 is used by the host as a temp */ #define ICE_T1 (ICE_SAHSIZE+7) /* t1 is used by the host as a temp */ #define ICE_T2 (ICE_SAHSIZE+8) /* t2 temp */ #define ICE_T3 (ICE_SAHSIZE+9) /* t3 temp */ #define ICE_T4 (ICE_SAHSIZE+10) /* t4 temp */ #define ICE_S0 (ICE_SAHSIZE+11) /* pointer to INSTR_BUFFER */ #define ICE_RA (ICE_SAHSIZE+12) /* ra is needed for bal/jal instrs */ #define ICE_SIZE (ICE_SAHSIZE+13) #define REG_MAP 0x80011ff6 /* gp regs in SAVEAREA */ /* ICE_MAP is used to tell the driver which of the gp regs have been * saved in the SAVEAREA. One bit it used to represent each register, * and they must be saved in order. eg. 0x80000000=$31=ra, * 0x00000006=$1&$2=at&v0. */ #define UART_BASE 0xbfff0200 #define UART_RXS 0x0 /* rx status */ #define UART_RXC 0x0 /* rx control */ #define UART_RXHR 0x4 /* rx holding reg */ #define UART_TXS 0x8 /* tx status */ #define UART_TXHR 0xc /* tx holding reg */ #define UART_INTBIT SR_INT2 #define RXS_RXRDY (1<<0) /* rx ready */ #define RXS_OVR (1<<1) /* rx overrun */ #define RXC_IE (1<<0) /* interrupt enable */ #define TXS_TXRDY (1<<0) /* tx ready */ #define J_RA_INSTR 0x03e00008 #define SAVEAREA 0xa0000100 #define INSTR_BUFFER 0xa0000180 #define IBUFSIZE ((0xa0000300-INSTR_BUFFER)/4) /************************************************************* * reset_vector: * This is where execution starts. * A maximum of 64 instructions allowed in this section */ .globl _start _start: reset_vector: # bfc00000 bal cpu_init # make sure the sw bits of the CAUSE register are zero .set noreorder mtc0 zero,C0_CAUSE .set reorder # enable ints in SR MASK+IEC li k0,(SR_BEV|SR_IEC|UART_INTBIT) .set noreorder mtc0 k0,C0_SR .set reorder la k0,SAVEAREA la t0,get_word sw t0,ICE_GWP*4(k0) la t0,put_word sw t0,ICE_PWP*4(k0) li t0,IBUFSIZE sw t0,ICE_IBS*4(k0) li t0,REG_MAP sw t0,ICE_MAP*4(k0) li t0,SA_VERS sw t0,ICE_SAV*4(k0) li t0,ICE_SAHSIZE sw t0,ICE_SAH*4(k0) #ifdef MIPSEB li t0,0 #else li t0,1 #endif sw t0,ICE_LE*4(k0) # print banner li a0,0x44434241 # DCBA bal put_word # wait here for the host to speak to me #ifdef USE_NO_INTS 2: li a2,UART_BASE # wait for rxrdy 1: lw k0,UART_RXS(a2) and k0,RXS_RXRDY beq k0,zero,1b # make sure that this is a *real* attn byte # read the byte lw k0,UART_RXHR(a2) #if 0 /* debug */ not k0 # write the byte sw k0,UART_TXHR(a2) b 2b #endif li a2,ATTN bne k0,a2,2b # brif not an attn byte # init s0 li s0,INSTR_BUFFER b send_ack #else /* use ints */ #ifdef RUN_APP j bspstart #else 1: b 1b #endif #endif /************************************************************* * Start of interrupt-level code * *************************************************************/ .set noat /************************************************************* * utlb_vector: * We should never get one of these. But just in case. */ .align 8 utlb_vector: # bfc00100 b gen_vector /************************************************************* * gen_vector: * All the exceptions come through here. */ .align 7 .globl gen_vector .ent gen_vector gen_vector: # bfc00180 # save regs la k0,SAVEAREA sw AT,ICE_AT*4(k0) sw v0,ICE_V0*4(k0) sw a0,ICE_A0*4(k0) sw a1,ICE_A1*4(k0) sw a2,ICE_A2*4(k0) sw a3,ICE_A3*4(k0) # make sure that we are in kseg1 la a3,1f li a2,K1BASE or a3,a2 j a3 1: sw t0,ICE_T0*4(k0) sw t1,ICE_T1*4(k0) sw t2,ICE_T2*4(k0) sw t3,ICE_T3*4(k0) sw t4,ICE_T4*4(k0) sw s0,ICE_S0*4(k0) sw ra,ICE_RA*4(k0) .set noreorder mfc0 t0,C0_EPC nop .set reorder sw t0,ICE_EPC*4(k0) # init s0 (KSEG1) li s0,INSTR_BUFFER # read the CAUSE register .set noreorder mfc0 a0,C0_CAUSE nop .set reorder # hw int? and t0,a0,CAUSE_EXCMASK bne t0,zero,send_ack # brif not a hw int # It is a hw int. But is it my int? .set noreorder mfc0 t0,C0_SR nop .set reorder and t0,a0 # qualify the CAUSE bits and t0,UART_INTBIT beq t0,zero,send_ack # brif not mine # make sure that this is a *real* attn byte # read the byte li t0,UART_BASE lw k0,UART_RXHR(t0) li t0,ATTN bne k0,t0,restore_rfe # brif not an attn byte # fall thru .end gen_vector /************************************************************* */ .globl send_ack .ent send_ack send_ack: li t0,UART_BASE # make sure that the tx is ready 1: lw k0,UART_TXS(t0) and k0,TXS_TXRDY beq k0,zero,1b li k0,ACK sw k0,UART_TXHR(t0) # make sure that r8 and r9 are zero. li t0,0 li t1,0 # fall thru .end send_ack /************************************************************* * ice_loop: * This is the main loop. We get words and process them. * There are 3 special types of word. * 1. RUN_MODE - transfer control to the customer's program. * 2. SENDSAP - Send the address of the SAVEAREA * 3. SENDA0 - Execute the code in INSTR_BUFFER and send * the value of register a0. * All other values are added to the INSTR_BUFFER. */ .globl ice_loop .ent ice_loop ice_loop: bal get_cmd #if 0 /* echo the input. Useful for debug */ move a0,v0 bal put_word b ice_loop #endif # check for SENDA0 li a2,SENDA0 bne a2,v0,1f # It is SENDA0. Execute the code in INSTR_BUFFER and send # the value of register a0. # Make sure that the routine ends with a "j ra". sw zero,(s0) li k0,J_RA_INSTR sw k0,4(s0) sw zero,8(s0) # Make sure that the writes complete before the jal. .set noreorder nop nop nop .set reorder # Reset s0 to point to start of INSTR_BUFFER. li s0,INSTR_BUFFER jal s0 # execute INSTR_BUFFER bal put_word # send A0 b ice_loop 1: # check for RUN_MODE li a2,RUN_MODE bne a2,v0,1f restore_rfe: # It is RUN_MODE. Transfer control to the client. # restore regs la k0,SAVEAREA lw AT,ICE_AT*4(k0) lw v0,ICE_V0*4(k0) lw a0,ICE_A0*4(k0) lw a1,ICE_A1*4(k0) lw a2,ICE_A2*4(k0) lw a3,ICE_A3*4(k0) lw t0,ICE_T0*4(k0) lw t1,ICE_T1*4(k0) lw t2,ICE_T2*4(k0) lw t3,ICE_T3*4(k0) lw t4,ICE_T4*4(k0) lw s0,ICE_S0*4(k0) lw ra,ICE_RA*4(k0) .set noreorder lw k0,ICE_EPC*4(k0) nop j k0 # jump to client rfe .set reorder 1: # check for SENDSAP li a2,SENDSAP bne a2,v0,1f # It is SENDSAP. Send address of SAVEAREA. la a0,SAVEAREA or a0,1 # indicate new format bal put_word b ice_loop 1: # else. Not a special word. sw v0,(s0) # save word in INSTR_BUFFER addu s0,4 # ready for next word b ice_loop .end ice_loop .set at /************************************************************* * get_cmd() * Get one word from the serial interface. The result goes * in v0. */ .globl get_cmd .ent get_cmd get_cmd: li a2,UART_BASE li a1,4 # get 4 bytes # wait for rxrdy 3: lw k0,UART_RXS(a2) and k0,RXS_RXRDY beq k0,zero,3b # get the byte lw k0,UART_RXHR(a2) # first byte? bne a1,4,2f # brif not first byte # is the byte a wakeup? bne k0,ATTN,2f # brif not a wakeup # wait for txrdy 1: lw k0,UART_TXS(a2) and k0,TXS_TXRDY beq k0,zero,1b # send an ack li k0,ACK sw k0,UART_TXHR(a2) b 3b 2: sll v0,8 # move word into position or v0,k0 # merge byte with word subu a1,1 # bytecount-- bne a1,zero,3b # do next byte j ra .end get_cmd /************************************************************* * get_word() * Get one word from the serial interface. The result goes * in v0. */ .globl get_word .ent get_word get_word: li a2,UART_BASE li a1,4 1: lw k0,UART_RXS(a2) and k0,RXS_RXRDY beq k0,zero,1b lw k0,UART_RXHR(a2) sll v0,8 or v0,k0 subu a1,1 bne a1,zero,1b j ra .end get_word /************************************************************* * put_word() * Put one word to the serial interface. The word to be sent * comes from a0. */ .globl put_word .ent put_word put_word: li a2,UART_BASE li a1,4 1: lw k0,UART_TXS(a2) and k0,TXS_TXRDY beq k0,zero,1b sw a0,UART_TXHR(a2) srl a0,8 subu a1,1 bne a1,zero,1b j ra .end put_word /************************************************************* * End of interrupt-level code * *************************************************************/ .set at /************************************************************* * cpu_init() * This is where the CPU-specific init code lives. * This implementation is for the bdmr4102 (4102 eval board). * This example is designed to use the SerialICE port for connection * to the IceController. */ .globl cpu_init .ent cpu_init cpu_init: # ============ Set up FLASH in addr space assign to CS0 =================== # # Note: FACMP0 and FACMP1 are initialized on startup to a 2M space starting # at address 0x1fc00000. These registers only need to be changed if you # have a boot flash larger than 2 Meg in size. li t1, M_FBUSTA li t2, 0x00160111 # 990317 sw t2, (t1) # Set FBUSTA = 1 turn around time li t1, M_FACFG0 li t0, 0x02949517 # Set 8 bit, 11 wait states sw t0, (t1) # Store Flash Timing settings # ============ Setup SRAM in addr space assign to CS3 ================== li t1, M_FACMP3 # Assign CS3 to SRAM in address range #ifdef BOOT_SRAM li t0, 0x00010000 # 0x00000000 to 0x0001ffff #else li t0, 0x00010e00 # 0x0e000000 to 0x0e01ffff #endif sw t0, (t1) # Assign CS3 address range li t1, M_FACFG3 li t0, 0xc2100005 # 990317 Set 32 bit, 2 wait states sw t0, (t1) # Store SRAM timing settings lw zero, (t1) # Setup BBCC System Configuration Register # # Initialize Bus Unit interface. This routine enables all caches. #ifdef MIPSEB li s1, M_SCR1 li s0, 0x300010db # Enable Caches, # snooping, turn off TLB sw s0, (s1) # Configure SCR1, pg size = 256 #else /* LE needs refill sizes set to 1 */ li s1, M_SCR1 li s0, 0x30001093 # Enable Caches, # snooping, turn off TLB sw s0, (s1) # Configure SCR1, pg size = 256 #endif #ifndef NO_SDRAM # Initialize SDRAM controller # # This routine inits the SDRAM controller on the 4102. It begins by # configuring the address range for the SDRAM and all of the timing # parameters. It then waits for 100 usec using the timer0 as a count # down. Finally it issues a precharge to bank 0, 1, 2 & 3 followed by 2 # refreshes and configures the SDRAM for 1 word burst. # The SDRAM controller strobes out a new address with each read request. # The SDRAM must start on a 32MB boundary. # Set SDRAM clock li s0, M_SCR2 # Set bclkp to run at # pclk speed lw s2, (s0) # Read current PLL jumper status and s2, 0x00000010 # Mask off all but the PLL bit li s1, 0x000200a8 # and dclkp to run at or s1, s2 # bclk or 100MHz sw s1, (s0) # and enable 4101 # compatibility mode # Issue COMMAND INHIBIT by not reading or writing to # DRAM and wait for 100 us li s0, M_TMR4001+O_TIC0 li s1, M_TMR4001+O_TCC0 li s2, 0x00000100 # Setup Timer to wait # 100us 0x2710 sw s2, (s0) # Store data li s0, M_TMR4001+O_TMODE li s2, 0x00000011 # Enable Timer 0 Disable # Timer 1 sw s2, (s0) # Store in Register 1: lw s2, (s1) # Read from Counter bne zero, s2, 1b # Loop till done # Enable SDRAM in addr range 2 li s0, M_FACMP2 # Set FACMP2 to 0x00ff0100 #ifdef BOOT_SDRAM li s2, 0x07ff0000 # Address range 2 covers # 0x00000000 to sw s2, (s0) # 0x00ffffff, 16MB Dram #else li s2, 0x00ff0200 # Address range 2 covers # 0x02000000 to sw s2, (s0) # 0x02ffffff, 16MB Dram #endif # Set SDRAM Configuration li s0, M_FSDRAM li s2, 0x000d8609 # Set SDRAM to 4 banks, # 15.6 usec refresh sw s2, (s0) # 8 bit page size, 4 Meg # bank size # Enable SDRAM li s0, M_FACFG2 li s1, 0xd0000001 # enable SDRAM 32 bit # wide bus sw s1, (s0) # Set FSDRAMT timing register li s0, M_FSDRAMT # Set SDRAM Timing for # Lat = 3 cks li s2, 0x000057a4 # 990317 tRC = 2 cks, tCL = 3 cks, # tRAS = 7 cks sw s2, (s0) # Set Init Bit so that next # read is a bank # Precharge. Set for MODE # Register write # on next Write to SDRAM # Issue a Precharge to each bank of SDRAM #ifdef BOOT_SDRAM li s1, 0xa0000000 # Execute dummy read to # uncached SDRAM #else li s1, 0xa2000000 # Execute dummy read to # uncached SDRAM #endif lw zero, (s1) # Read Banks in order to # precharge # Issue 2 Refresh cycles to SDRAM li s0, M_FSDRAM li s2, 0x000d8609 # Set SDRAM Config sw s2, (s0) # Store in FSDRAM to cause # a refresh lw zero, (s0) # Flush write buffers ori s0, s0, 0x0 # Flush write buffers sw s2, (s0) # Store in FSDRAM to cause # a second refresh lw zero, (s0) # Flush write buffers ori s0, s0, 0x0 # Flush write buffers # Set SDRAM mode register li t0, M_FSDRAMT lw t4,(t0) or t4,0x8000 sw t4,(t0) #ifdef BOOT_SDRAM li s1, 0xa008c000 # Set SDRAM Mode Reg to #else li s1, 0xa208c000 # Set SDRAM Mode Reg to #endif lb zero,(s1) li t0, M_FSDRAMT and t4,~0xc000 sw t4,(t0) #endif #ifndef USE_NO_INTS # enable the ICEport's interrupt enable li t0,UART_BASE li t1,RXC_IE sw t1,UART_RXC(t0) #endif j ra .end cpu_init