📄 k4101.s
字号:
/************************************************************** File: k4101.s* Purpose: A serialICE kernel for the BDMR4101 eval board. This* kernel uses the SerialICE-Port interface.* Author: Phil Bunce (pjb@carmel.com)* Revision History:* 970527 Created from k4001.s* 970826 Added wakeup banner (ABCD)* 970828 Added USE_NO_INTS switch* 970828 Fully functional* 970829 Removed call to CpuInit in cstartup.* 971023 Added REV1_WIGGLER switch.* 971105 Removed REV1_WIGGLER switch.* 971205 Fixed 1b bug in put_word (left behind after REV1_WIGGLER)* 980209 Moved savearea from bss to 0xa0000000.* 980312 Switched to version2 savearea format* 980617 Switched to kseg1 link, and noclobber k1.* 980130 Removed savearea and instr_buffer from bss.** 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 BDMR4101 (the 4101 evaluation board).* It uses the ICEport interface to communicate with at 38400* 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 -prom -crt0 -syms -T bfc00000 -o k4101 k4101.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 bdmr4101 -o myprog myprog_files...** To download your application into RAM you should compile/link your * program using the following command.** pmcc -board bdmr4101 -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_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.* *//*#define USE_NO_INTS /* don't use ints for kernel wakeup */#ifndef LR4101#define LR4101#endif#include <mips.h>/* 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 (KSEG1) li s0,INSTR_BUFFER b send_ack#else#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 8utlb_vector: # bfc00100 b gen_vector/************************************************************** gen_vector:* All the exceptions come through here.*/ .align 7 .globl gen_vector .ent gen_vectorgen_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 a2,UART_BASE lw k0,UART_RXHR(a2) li a2,ATTN bne k0,a2,restore_rfe # brif not an attn byte # fall thru .end gen_vector/**************************************************************/ .globl send_ack .ent send_acksend_ack: li a2,UART_BASE # make sure that the tx is ready 1: lw k0,UART_TXS(a2) and k0,TXS_TXRDY beq k0,zero,1b li k0,ACK sw k0,UART_TXHR(a2) # 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_loopice_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,1frestore_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_cmdget_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_wordget_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_wordput_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 bdmr4101 (4101 eval board).* This example is designed to use the SerialICE port for connection* to the IceController.*/ .globl cpu_init .ent cpu_initcpu_init: # set M_CFG4001 # wben, ~tlben, ~dberr, pgsz=111, rdpri, cmode=00, dcen, is1en, icen # isize=int5,int4 dsize=int3,int2 li t0,(CFG_WBEN|CFG_DCEN|CFG_IS1EN|CFG_ICEN) #or t0,(CFG_PGSZ_2K|CFG_CMODE_NORM|CFG_DSNOOP|CFG_ISNOOP) or t0,(CFG_PGSZ_2K|CFG_CMODE_NORM) # setting of DBS0/1 and IBS0/1 is controlled by jumpers on the # board that are connected to the CpCond inputs. But rather than # use a whole bunch of bc1t instructions to test them. I connect # them to the interrupt inputs and then test the CAUSE register. # connect CpCond inputs to interrupt inputs or t0,(CFG_CPC0EN|CFG_CPC1EN|CFG_CPC2EN|CFG_CPC3EN) li t1,M_CFG4001 sw t0,(t1) # write CFG4001 lw zero,(t1) # flush wb .set noreorder # allow time for CFG change to take effect nop nop mfc0 t1,C0_CAUSE nop .set reorder and t2,t1,(CAUSE_INT5|CAUSE_INT4) srl t2,14-2 or t0,t2 and t2,t1,(CAUSE_INT3|CAUSE_INT2) srl t2,12-5 or t0,t2 li t1,M_CFG4001 sw t0,(t1) # disconnect cpCond inputs from interrupt inputs and t0,~(CFG_CPC0EN|CFG_CPC1EN|CFG_CPC2EN|CFG_CPC3EN) li t1,M_CFG4001 sw t0,(t1) # write CFG4001 lw zero,(t1) # flush wb # set refresh timer (timer0) # 60MHz clock 16ms/1024 = 941 li t1,M_TMR4001 li t0,941 sw t0,O_TIC0(t1) # set timer initial count li t0,(TMODE_EN0|TMODE_PULSE0) sw t0,O_TMODE(t1) # write to tmode reg lw zero,O_TMODE(t1) # flush wb #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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -