2002-02-08 Joel Sherrill <joel@OARcorp.com>

* Merged r46kstub.c into RTEMS distribution without modification.
	I got the code from Franz Fischer <Franz.Fischer@franz-fischer.de>
	who had used this with an old version of RTEMS with the mips64orion
	port of RTEMS.  After adding this to the repository, I will tailor
	this to work with the RTEMS exception processing model and trim
	no longer needed parts.
	* ChangeLog, gdb_if.h, ioaddr.h, limits.h, Makefile, mips_opcode.h,
	r4600.h, r46kstub.c, r46kstub.ld, README, stubinit.S:
This commit is contained in:
Joel Sherrill
2002-02-08 20:03:26 +00:00
parent 9b116329db
commit fb63984771
11 changed files with 2664 additions and 0 deletions

View File

@@ -0,0 +1,43 @@
2002-02-08 Joel Sherrill <joel@OARcorp.com>
* Merged r46kstub.c into RTEMS distribution without modification.
I got the code from Franz Fischer <Franz.Fischer@franz-fischer.de>
who had used this with an old version of RTEMS with the mips64orion
port of RTEMS. After adding this to the repository, I will tailor
this to work with the RTEMS exception processing model and trim
no longer needed parts.
* ChangeLog, gdb_if.h, ioaddr.h, limits.h, Makefile, mips_opcode.h,
r4600.h, r46kstub.c, r46kstub.ld, README, stubinit.S:
Sun Sep 29 16:34:53 1996 C. M. Heard <heard@vvnet.com>
* Updated snapshot posted.
* stubinit.S (_reset_exception, _general_exception): Reorder
instructions or insert nops as necessary to ensure that the
target register of mfc0, mfc1, and cfc1 instructions is not
used as a source register in the load delay slot of those
instructions and to ensure that the instruction following
mtc0 is always something other than mfc0. Insert .eject
directives and reformat some of the comments to make the
assembler listing more readable.
* ioaddr.h: add comments pointing out implementation-
specific address definitions.
* limits.h: add comments describing what the implementation-
specific macros in this file are supposed to do.
Tue Aug 06 14:43:04 1995 C. M. Heard <heard@vvnet.com>
* Updated snapshot posted.
* stubinit.S (_general_exception): Use virtual adresses from
kseg0 (cached, unmapped space) instead of kseg1 (uncached,
unmapped space) in cache instructions.
(_reset_exception): Likewise, and use the right
mask to clean the K0 field in the config register.
Fri Jul 26 14:41:49 1995 C. M. Heard <heard@vvnet.com>
* Initial snapshot posted.

View File

@@ -0,0 +1,38 @@
CC = mips64orion-idt-elf-gcc
CFLAGS = -g -Wa,-ahld -Wall -membedded-data -O3
AS = mips64orion-idt-elf-as
ASFLAGS = -ahld
LD = mips64orion-idt-elf-ld
LDFLAGS = -t -s
# Inference rules
.SUFFIXES: $(SUFFIXES) .out .ld
.ld.out:
$(LD) $(LDFLAGS) -T $< -Map $*.map -o $*.out
.c.o:
$(CC) $(CFLAGS) -c $< >$*.L
.S.o:
$(CC) $(CFLAGS) -c $< >$*.L
.s.o:
$(AS) $(ASFLAGS) -o $*.o $< >$*.L
# Targets
r46kstub.hex: r46kstub.out
mips64orion-idt-elf-objcopy -S -R .bss -R .data -R .reginfo \
-O srec r46kstub.out r46kstub.hex
clean:
rm -f *.L *.map *.o *.out *.hex
# Dependencies
r46kstub.out: r46kstub.ld r46kstub.o stubinit.o
r46kstub.o: mips_opcode.h r4600.h limits.h gdb_if.h r46kstub.c
stubinit.o: r4600.h ioaddr.h gdb_if.h stubinit.S

View File

@@ -0,0 +1,115 @@
/* r46kstub 9/29/96 c. m. heard */
/* 7/26/96 -- original posting */
/* 8/06/96 -- cache initialization/flushing logic fixed */
/* 9/29/96 -- coprocessor load delay slots respected, documentation improved */
The r46kstub directory and its compressed archive (r46kstub.tar.gz) contain
the 9/29/96 source code snapshot for a ROM-resident gdb-4.16 debug agent
(aka stub) for the IDT R4600 Orion processor. It is based on the stub for
the Hitachi SH processor written by Ben Lee and Steve Chamberlain and
supplied with the gdb-4.16 distribution; that stub in turn was "originally
based on an m68k software stub written by Glenn Engel at HP, but has changed
quite a bit". The modifications for the R4600 were contributed by C. M.
Heard of VVNET, Inc. and were based in part on the Algorithmics R4000 version
of Phil Bunce's PMON program.
The distribution consists of the following files:
-rw-r--r-- 1 1178 Sep 29 16:34 ChangeLog
-rw-r--r-- 1 748 Jul 26 01:18 Makefile
-rw-r--r-- 1 6652 Sep 29 16:34 README
-rw-r--r-- 1 1829 May 21 02:02 gdb_if.h
-rw-r--r-- 1 3745 Sep 29 14:03 ioaddr.h
-rw-r--r-- 1 2906 Sep 29 14:39 limits.h
-rw-r--r-- 1 6552 May 23 00:17 mips_opcode.h
-rw-r--r-- 1 14017 May 21 02:04 r4600.h
-rw-r--r-- 1 23874 Jul 21 20:31 r46kstub.c
-rw-r--r-- 1 1064 Jul 3 12:35 r46kstub.ld
-rw-r--r-- 1 13299 Sep 29 16:24 stubinit.S
With the exception of mips_opcode.h, which is a slightly modified version
of a header file contributed by Ralph Campbell to 4.4 BSD and is therefore
copyrighted by the UC Regents, all of the source files have been dedicated
by their authors to the public domain. Use them as you wish, but do so
at your own risk! The authors accept _no_ responsibility for any errors.
The debug agent contained herein is at this writing in active use at VVNET
supporting initial hardware debug and board bring-up of an OC-12 ATM probe
board. It uses polled I/O on a 16C450 UART. We had originally intended to
add support for interrupts to allow gdb to break in on a running program,
but we have found that this is not really necessary since the reset button
will accomplish the same purpose (thanks to the MIPS feature of saving the
program counter in the ErrorEPC register when a reset exception occurs).
Be aware that this stub handles ALL interrupts and exceptions except for
reset (or NMI) in the same way -- by passing control to the debug command
loop. It of course uses the ROM exception vectors to do so. In order to
support code that actally needs to use interrupts we use use a more elaborate
stub that is linked with the downloaded program. It hooks the RAM exception
vectors and clears the BEV status bit to gain control. The ROM-based stub
is still used in this case for initial program loading.
In order to port this stub to a different platform you will at a minimum
need to customize the macros in limits.h (which define the limits of readable,
writeable, and steppable address space) and the I/O addresses in ioaddr.h
(which define the 16C450 MMIO addresses). If you use something other than
a 16C450 UART you will probably also need to modify the portions of stubinit.S
which deal with the serial port. I've tried to be careful to respect all the
architecturally-defined hazards as described in Appendix F of Kane and
Heinrich, MIPS RISC Architecture, in order to minimize the work in porting
to 4000-series processors other than the R4600, but no guarantees are offered.
Support is presently restricted to big-endian addressing, and I've not even
considered what changes would be needed for little-endian support.
When this stub is built with gcc-2.7.2 and binutils-2.6 you will see a few
warning messages from the single-step support routine where a cast is used
to sign-extend a pointer (the next instruction address) into a long long
(the PC image). Those warnings are expected; I've checked the generated
code and it is doing what I had intended. But you should not see any other
warnings or errors. Here is a log of the build:
mips64orion-idt-elf-gcc -g -Wa,-ahld -Wall -membedded-data \
-O3 -c r46kstub.c >r46kstub.L
r46kstub.c: In function `doSStep':
r46kstub.c:537: warning: cast to pointer from integer of different size
r46kstub.c:539: warning: cast to pointer from integer of different size
r46kstub.c:547: warning: cast to pointer from integer of different size
r46kstub.c:561: warning: cast to pointer from integer of different size
r46kstub.c:563: warning: cast to pointer from integer of different size
r46kstub.c:572: warning: cast to pointer from integer of different size
r46kstub.c:574: warning: cast to pointer from integer of different size
r46kstub.c:582: warning: cast to pointer from integer of different size
r46kstub.c:589: warning: cast to pointer from integer of different size
r46kstub.c:591: warning: cast to pointer from integer of different size
r46kstub.c:597: warning: cast to pointer from integer of different size
r46kstub.c:599: warning: cast to pointer from integer of different size
r46kstub.c:605: warning: cast to pointer from integer of different size
r46kstub.c:607: warning: cast to pointer from integer of different size
r46kstub.c:613: warning: cast to pointer from integer of different size
r46kstub.c:615: warning: cast to pointer from integer of different size
r46kstub.c:624: warning: cast to pointer from integer of different size
r46kstub.c:628: warning: cast to pointer from integer of different size
r46kstub.c:635: warning: cast to pointer from integer of different size
r46kstub.c:637: warning: cast to pointer from integer of different size
mips64orion-idt-elf-gcc -g -Wa,-ahld -Wall -membedded-data \
-O3 -c stubinit.S >stubinit.L
mips64orion-idt-elf-ld -t -s -T r46kstub.ld -Map r46kstub.map -o r46kstub.out
mips64orion-idt-elf-ld: mode elf32bmip
stubinit.o
r46kstub.o
mips64orion-idt-elf-objcopy -S -R .bss -R .data -R .reginfo \
-O srec r46kstub.out r46kstub.hex
Limitations: stubinit.S deliberately forces the PC (which is a 64-bit
register) to contain a legitimate sign-extended 32-bit value. This was
done to cope with a bug in gdb-4.16, which does _not_ properly sign-extend
the initial PC when it loads a program. This means that you cannot use
the "set" command to load an unmapped sixty-four bit virtual address into
the PC, as you can for all other registers.
Please send bug reports, comments, or suggestions for improvement to:
C. M. Heard
VVNET, Inc. phone: +1 408 247 9376
4040 Moorpark Ave. Suite 206 fax: +1 408 244 3651
San Jose, CA 95117 USA e-mail: heard@vvnet.com

View File

@@ -0,0 +1,105 @@
/*
* gdb_if.h - definition of the interface between the stub and gdb
*
* THIS SOFTWARE IS NOT COPYRIGHTED
*
* The following software is offered for use in the public domain.
* There is no warranty with regard to this software or its performance
* and the user must accept the software "AS IS" with all faults.
*
* THE CONTRIBUTORS DISCLAIM ANY WARRANTIES, EXPRESS OR IMPLIED, WITH
* REGARD TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef _GDB_IF_H
#define _GDB_IF_H
/*
* R4600 registers, numbered in the order in which gdb expects to see them.
*/
#define ZERO 0
#define AT 1
#define V0 2
#define V1 3
#define A0 4
#define A1 5
#define A2 6
#define A3 7
#define T0 8
#define T1 9
#define T2 10
#define T3 11
#define T4 12
#define T5 13
#define T6 14
#define T7 15
#define S0 16
#define S1 17
#define S2 18
#define S3 19
#define S4 20
#define S5 21
#define S6 22
#define S7 23
#define T8 24
#define T9 25
#define K0 26
#define K1 27
#define GP 28
#define SP 29
#define S8 30
#define RA 31
#define SR 32
#define LO 33
#define HI 34
#define BAD_VA 35
#define CAUSE 36
#define PC 37
#define F0 38
#define F1 39
#define F2 40
#define F3 41
#define F4 42
#define F5 43
#define F6 44
#define F7 45
#define F8 46
#define F9 47
#define F10 48
#define F11 49
#define F12 50
#define F13 51
#define F14 52
#define F15 53
#define F16 54
#define F17 55
#define F18 56
#define F19 57
#define F20 58
#define F21 59
#define F22 60
#define F23 61
#define F24 62
#define F25 63
#define F26 64
#define F27 65
#define F28 66
#define F29 67
#define F30 68
#define F31 69
#define FCSR 70
#define FIRR 71
#define NUM_REGS 72
#endif /* _GDB_IF_H */

View File

@@ -0,0 +1,113 @@
/*
* ioaddr.h - 16C450 serial port memory-mapped I/O address definitions
*
* THIS SOFTWARE IS NOT COPYRIGHTED
*
* The following software is offered for use in the public domain.
* There is no warranty with regard to this software or its performance
* and the user must accept the software "AS IS" with all faults.
*
* THE CONTRIBUTORS DISCLAIM ANY WARRANTIES, EXPRESS OR IMPLIED, WITH
* REGARD TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef _IOADDR_H
#define _IOADDR_H
/*
* The following addresses are implementation-specific.
* Note that big-endian memory addressing is assumed.
*/
#define ISA_IO_BASE 0xb8000000
#define BYTE_IO(ioaddr) ((ioaddr<<3)+7)
#define WORD_IO(ioaddr) ((ioaddr<<3)+6)
#define ISA_IRQ9_RESET 0xb8043000
#define ISA_IRQ5_RESET 0xb8042000
#define ISA_IRQ4_RESET 0xb8041000
#define ISA_IRQ3_RESET 0xb8040000
#define ISA_IRQ_STATUS 0xb8040000
/* ISA IRQ Status Register fields */
#define ISA_IRQ9_STATUS 0x08
#define ISA_IRQ5_STATUS 0x04
#define ISA_IRQ4_STATUS 0x02
#define ISA_IRQ3_STATUS 0x01
/*
* Serial Port 1 (COM1) I/O Addresses. These definitions
* follows the standard IBM AT I/O address assignments.
* Note that IRQ4 is normally assigned to serial port 1.
*/
#define DIV_LO_COM1 BYTE_IO(0x3f8) /* Div latch lo (line ctl bit 7 = 1) */
#define DIV_HI_COM1 BYTE_IO(0x3f9) /* Div latch hi (line ctl bit 7 = 1) */
#define DATA_REG_COM1 BYTE_IO(0x3f8) /* TX Buf (write)/RX Buf (read) */
#define INT_ENA_COM1 BYTE_IO(0x3f9) /* Interrupt Enable Register */
#define INT_ID_COM1 BYTE_IO(0x3fa) /* Interrupt ID Register */
#define LINE_CTL_COM1 BYTE_IO(0x3fb) /* Line Control Register */
#define MODEM_CTL_COM1 BYTE_IO(0x3fc) /* Modem Control Register */
#define LINE_STS_COM1 BYTE_IO(0x3fd) /* Line Status Register */
#define MODEM_STS_COM1 BYTE_IO(0x3fe) /* Modem Status Register */
/*
* Serial Port 2 (COM1) I/O Addresses. These definitions
* follows the standard IBM AT I/O address assignments.
* Note that IRQ3 is normally assigned to serial port 2.
*/
#define DIV_LO_COM2 BYTE_IO(0x2f8) /* Div latch lo (line ctl bit 7 = 1) */
#define DIV_HI_COM2 BYTE_IO(0x2f9) /* Div latch hi (line ctl bit 7 = 1) */
#define DATA_REG_COM2 BYTE_IO(0x2f8) /* TX Buf (write)/RX Buf (read) */
#define INT_ENA_COM2 BYTE_IO(0x2f9) /* Interrupt Enable Register */
#define INT_ID_COM2 BYTE_IO(0x2fa) /* Interrupt ID Register */
#define LINE_CTL_COM2 BYTE_IO(0x2fb) /* Line Control Register */
#define MODEM_CTL_COM2 BYTE_IO(0x2fc) /* Modem Control Register */
#define LINE_STS_COM2 BYTE_IO(0x2fd) /* Line Status Register */
#define MODEM_STS_COM2 BYTE_IO(0x2fe) /* Modem Status Register */
/* Interrupt Enable Register fields */
#define IENA_MODEM 0x08
#define IENA_LINE 0x04
#define IENA_TX 0x02
#define IENA_RX 0x01
/* Interrupt Identification Register fields */
#define INT_ID_MASK 0x06
#define INT_PENDING 0x01
/* Line Control Register fields */
#define DIV_LATCH_EN 0x80
#define SET_BREAK 0x40
#define STICK_PARITY 0x20
#define EVEN_PARITY 0x10
#define PARITY_ENA 0x08
#define STOP_BITS 0x04
#define WORD_LEN_MASK 0x03
/* Line Status Register fields */
#define TX_SHR_EMPTY 0x40
#define TX_BUF_EMPTY 0x20
#define BRK_RCVD 0x10
#define FRAMING_ERR 0x08
#define PARITY_ERR 0x04
#define OVRUN_ERR 0x02
#define RX_CHAR_AVA 0x01
/* Modem Control Register fields */
#define LOOPBACK 0x10
#define OUT2 0x08
#define OUT1 0x04
#define RTS 0x02
#define DTR 0x01
/* Modem Status Register fields */
#define RLSD 0x80
#define RI 0x40
#define DSR 0x20
#define CTS 0x10
#define DELTA_RLSD 0x08
#define TRAIL_EDGE_RI 0x04
#define DELTA_DSR 0x02
#define DELTA_CTS 0x01
#endif /* _IOADDR_H */

View File

@@ -0,0 +1,70 @@
/*
* limits.h - definition of machine & system dependent address limits
*
* THIS SOFTWARE IS NOT COPYRIGHTED
*
* The following software is offered for use in the public domain.
* There is no warranty with regard to this software or its performance
* and the user must accept the software "AS IS" with all faults.
*
* THE CONTRIBUTORS DISCLAIM ANY WARRANTIES, EXPRESS OR IMPLIED, WITH
* REGARD TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef _LIMITS_H_
#define _LIMITS_H_
/*
* The macros in this file are specific to a given implementation.
* The general rules for their construction are as follows:
*
* 1.) is_readable(addr,length) should be true if and only if the
* region starting at the given virtual address can be read
* _without_ causing an exception or other fatal error. Note
* that the stub will use the strictest alignment satisfied
* by _both_ addr and length (e.g., if both are divisible by
* 8 then the region will be read in double-word chunks).
*
* 2.) is_writeable(addr,length) should be true if and only if the
* region starting at the given virtual address can be written
* _without_ causing an exception or other fatal error. Note
* that the stub will use the strictest alignment satisfied
* by _both_ addr and length (e.g., if both are divisible by
* 8 then the region will be written in double-word chunks).
*
* 3.) is-steppable(ptr) whould be true if and only if ptr is the
* address of a writeable region of memory which may contain
* an executable instruction. At a minimum this requires that
* ptr be word-aligned (divisible by 4) and not point to EPROM
* or memory-mapped I/O.
*
* Note: in order to satisfy constraints related to cacheability
* of certain memory subsystems it may be necessary for regions
* of kseg0 and kseg1 which map to the same physical addresses
* to have different readability and/or writeability attributes.
*/
#define K0_LIMIT_FOR_READ (K0BASE+0x18000000)
#define K1_LIMIT_FOR_READ (K1BASE+K1SIZE)
#define is_readable(addr,length) \
(((K0BASE <= addr) && ((addr + length) <= K0_LIMIT_FOR_READ)) \
|| ((K1BASE <= addr) && ((addr + length) <= K1_LIMIT_FOR_READ)))
#define K0_LIMIT_FOR_WRITE (K0BASE+0x08000000)
#define K1_LIMIT_FOR_WRITE (K1BASE+0x1e000000)
#define is_writeable(addr,length) \
(((K0BASE <= addr) && ((addr + length) <= K0_LIMIT_FOR_WRITE)) \
|| ((K1BASE <= addr) && ((addr + length) <= K1_LIMIT_FOR_WRITE)))
#define K0_LIMIT_FOR_STEP (K0BASE+0x08000000)
#define K1_LIMIT_FOR_STEP (K1BASE+0x08000000)
#define is_steppable(ptr) \
((((int)ptr & 0x3) == 0) \
&& (((K0BASE <= (int)ptr) && ((int)ptr < K0_LIMIT_FOR_STEP)) \
|| ((K1BASE <= (int)ptr) && ((int)ptr < K1_LIMIT_FOR_STEP))))
#endif /* _LIMITS_H_ */

View File

@@ -0,0 +1,295 @@
/*-
* Copyright (c) 1992 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Ralph Campbell.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* from: @(#)mips_opcode.h 7.1 (Berkeley) 3/19/92
* via: mips_opcode.h,v 1.1 1994/03/10 16:15:10 (algorithmics)
*/
/*
* Define the instruction formats and opcode values for the
* MIPS instruction set.
*/
#ifndef _MIPS_OPCODE_H
#define _MIPS_OPCODE_H
/*
* Define the instruction formats.
*/
typedef union {
unsigned word;
#ifdef MIPSEL
struct {
unsigned imm: 16;
unsigned rt: 5;
unsigned rs: 5;
unsigned op: 6;
} IType;
struct {
unsigned target: 26;
unsigned op: 6;
} JType;
struct {
unsigned func: 6;
unsigned shamt: 5;
unsigned rd: 5;
unsigned rt: 5;
unsigned rs: 5;
unsigned op: 6;
} RType;
struct {
unsigned func: 6;
unsigned fd: 5;
unsigned fs: 5;
unsigned ft: 5;
unsigned fmt: 4;
unsigned : 1; /* always '1' */
unsigned op: 6; /* always '0x11' */
} FRType;
#else
struct {
unsigned op: 6;
unsigned rs: 5;
unsigned rt: 5;
unsigned imm: 16;
} IType;
struct {
unsigned op: 6;
unsigned target: 26;
} JType;
struct {
unsigned op: 6;
unsigned rs: 5;
unsigned rt: 5;
unsigned rd: 5;
unsigned shamt: 5;
unsigned func: 6;
} RType;
struct {
unsigned op: 6; /* always '0x11' */
unsigned : 1; /* always '1' */
unsigned fmt: 4;
unsigned func: 6;
unsigned ft: 5;
unsigned fs: 5;
unsigned fd: 5;
} FRType;
#endif
} InstFmt;
/*
* Values for the 'op' field.
*/
#define OP_SPECIAL 000
#define OP_REGIMM 001
#define OP_J 002
#define OP_JAL 003
#define OP_BEQ 004
#define OP_BNE 005
#define OP_BLEZ 006
#define OP_BGTZ 007
#define OP_ADDI 010
#define OP_ADDIU 011
#define OP_SLTI 012
#define OP_SLTIU 013
#define OP_ANDI 014
#define OP_ORI 015
#define OP_XORI 016
#define OP_LUI 017
#define OP_COP0 020
#define OP_COP1 021
#define OP_COP2 022
#define OP_BEQL 024
#define OP_BNEL 025
#define OP_BLEZL 026
#define OP_BGTZL 027
#define OP_DADDI 030
#define OP_DADDIU 031
#define OP_LDL 032
#define OP_LDR 033
#define OP_LB 040
#define OP_LH 041
#define OP_LWL 042
#define OP_LW 043
#define OP_LBU 044
#define OP_LHU 045
#define OP_LWR 046
#define OP_LWU 047
#define OP_SB 050
#define OP_SH 051
#define OP_SWL 052
#define OP_SW 053
#define OP_SDL 054
#define OP_SDR 055
#define OP_SWR 056
#define OP_CACHE 057
#define OP_LL 060
#define OP_LWC1 061
#define OP_LWC2 062
#define OP_LLD 064
#define OP_LDC1 065
#define OP_LDC2 066
#define OP_LD 067
#define OP_SC 070
#define OP_SWC1 071
#define OP_SWC2 072
#define OP_SCD 074
#define OP_SDC1 075
#define OP_SDC2 076
#define OP_SD 077
/*
* Values for the 'func' field when 'op' == OP_SPECIAL.
*/
#define OP_SLL 000
#define OP_SRL 002
#define OP_SRA 003
#define OP_SLLV 004
#define OP_SRLV 006
#define OP_SRAV 007
#define OP_JR 010
#define OP_JALR 011
#define OP_SYSCALL 014
#define OP_BREAK 015
#define OP_SYNC 017
#define OP_MFHI 020
#define OP_MTHI 021
#define OP_MFLO 022
#define OP_MTLO 023
#define OP_DSLLV 024
#define OP_DSRLV 026
#define OP_DSRAV 027
#define OP_MULT 030
#define OP_MULTU 031
#define OP_DIV 032
#define OP_DIVU 033
#define OP_DMULT 034
#define OP_DMULTU 035
#define OP_DDIV 036
#define OP_DDIVU 037
#define OP_ADD 040
#define OP_ADDU 041
#define OP_SUB 042
#define OP_SUBU 043
#define OP_AND 044
#define OP_OR 045
#define OP_XOR 046
#define OP_NOR 047
#define OP_SLT 052
#define OP_SLTU 053
#define OP_DADD 054
#define OP_DADDU 055
#define OP_DSUB 056
#define OP_DSUBU 057
#define OP_TGE 060
#define OP_TGEU 061
#define OP_TLT 062
#define OP_TLTU 063
#define OP_TEQ 064
#define OP_TNE 066
#define OP_DSLL 070
#define OP_DSRL 072
#define OP_DSRA 073
#define OP_DSLL32 074
#define OP_DSRL32 076
#define OP_DSRA32 077
/*
* Values for the 'func' field when 'op' == OP_REGIMM.
*/
#define OP_BLTZ 000
#define OP_BGEZ 001
#define OP_BLTZL 002
#define OP_BGEZL 003
#define OP_TGEI 010
#define OP_TGEIU 011
#define OP_TLTI 012
#define OP_TLTIU 013
#define OP_TEQI 014
#define OP_TNEI 016
#define OP_BLTZAL 020
#define OP_BGEZAL 021
#define OP_BLTZALL 022
#define OP_BGEZALL 023
/*
* Values for the 'rs' field when 'op' == OP_COPz.
*/
#define OP_MF 000
#define OP_DMF 001
#define OP_CF 002
#define OP_MT 004
#define OP_DMT 005
#define OP_CT 006
#define OP_BC 010
/*
* Values for the 'rt' field when 'op' == OP_COPz and 'rt' == OP_BC.
*/
#define COPz_BCF 0x00
#define COPz_BCT 0x01
#define COPz_BCFL 0x02
#define COPz_BCTL 0x03
/*
* Instructions with specal significance to debuggers.
*/
#define BREAK_INSTR 0x0000000d /* instruction code for break */
#define NOP_INSTR 0x00000000 /* instruction code for no-op */
#endif /* _MIPS_OPCODE_H */

View File

@@ -0,0 +1,372 @@
/*
* r4600.h - register and address space definitions for the R4600 processor
*
* THIS SOFTWARE IS NOT COPYRIGHTED
*
* The following software is offered for use in the public domain.
* There is no warranty with regard to this software or its performance
* and the user must accept the software "AS IS" with all faults.
*
* THE CONTRIBUTORS DISCLAIM ANY WARRANTIES, EXPRESS OR IMPLIED, WITH
* REGARD TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef _R4600_H
#define _R4600_H
/*
* R4600 general registers
*/
#define zero $0
#define at $1 /* assembler temporary */
#define v0 $2 /* value holders */
#define v1 $3
#define a0 $4 /* arguments */
#define a1 $5
#define a2 $6
#define a3 $7
#define t0 $8 /* temporaries */
#define t1 $9
#define t2 $10
#define t3 $11
#define t4 $12
#define t5 $13
#define t6 $14
#define t7 $15
#define s0 $16 /* saved registers */
#define s1 $17
#define s2 $18
#define s3 $19
#define s4 $20
#define s5 $21
#define s6 $22
#define s7 $23
#define t8 $24 /* temporaries */
#define t9 $25
#define k0 $26 /* kernel registers */
#define k1 $27
#define gp $28 /* global pointer */
#define sp $29 /* stack pointer */
#define s8 $30 /* saved register */
#define fp $30 /* frame pointer (obsolete usage) */
#define ra $31 /* return address */
/*
* Kernel address space definitions (32 bit/64 bit compatibility spaces)
*/
#define K0BASE 0x80000000
#define K0SIZE 0x20000000
#define K1BASE 0xa0000000
#define K1SIZE 0x20000000
#define PHYS_TO_K0(pa) ((pa)|K0BASE)
#define PHYS_TO_K1(pa) ((pa)|K1BASE)
#define K0_TO_PHYS(va) ((va)&(K0SIZE-1))
#define K1_TO_PHYS(va) ((va)&(K1SIZE-1))
#define K0_TO_K1(va) ((va)|K1SIZE)
#define K1_TO_K0(va) ((va)&~K1SIZE)
/*
* System Control Coprocessor (CP0) memory-management registers
*/
#define C0_INDEX $0 /* TLB Index */
#define C0_RANDOM $1 /* TLB Random */
#define C0_ENTRYLO0 $2 /* TLB EntryLo0 */
#define C0_ENTRYLO1 $3 /* TLB EntryLo1 */
#define C0_PAGEMASK $5 /* TLB PageMask */
#define C0_WIRED $6 /* TLB Wired */
#define C0_ENTRYHI $10 /* TLB EntryHi */
#define C0_PRID $15 /* Processor Revision Indentifier */
#define C0_CONFIG $16 /* Config */
#define C0_LLADDR $17 /* LLAddr */
#define C0_TAGLO $28 /* TagLo */
#define C0_TAGHI $29 /* TagHi (always zero on the R4600) */
/* EntryHi register fields */
#define EH_REGION_MASK 0xc000000000000000 /* 11=krnl, 01=supv, 00=user */
#define EH_REGION_SHIFT 62
#define EH_FILL_MASK 0x3fffff0000000000 /* (holds replica of bit 63) */
#define EH_FILL_SHIFT 40
#define EH_VPN2_MASK 0x000000ffffffe000 /* Virtual pageno div 2 */
#define EH_VPN2_SHIFT 13
#define EH_ASID_MASK 0x00000000000000ff /* Address space ID */
#define EH_ASID_SHIFT 0
/* EntryLo register fields */
#define EL_PFN_MASK 0x000000003fffffc0 /* Page Frame Number */
#define EL_PFN_SHIFT 6
#define EL_C_MASK 0x0000000000000038 /* Cacheability attributes */
#define EL_C_SHIFT 3
#define EL_D_MASK 0x0000000000000004 /* Dirty bit */
#define EL_D_SHIFT 2
#define EL_V_MASK 0x0000000000000002 /* Valid bit */
#define EL_V_SHIFT 1
#define EL_G_MASK 0x0000000000000001 /* Global bit */
#define EL_G_SHIFT 0
/* PageMask register fields */
#define PM_MASK 0x01ffe000 /* Page size mask: */
#define PM_M_4K 0x00000000 /* 4K bytes */
#define PM_M_16K 0x00006000 /* 16K bytes */
#define PM_M_64K 0x0001e000 /* 64K bytes */
#define PM_M_256K 0x0007e000 /* 256K bytes */
#define PM_M_1M 0x001fe000 /* 1M bytes */
#define PM_M_4M 0x007fe000 /* 4M bytes */
#define PM_M_16M 0x01ffe000 /* 16M bytes */
/* Index register fields */
#define IR_P_MASK 0x80000000 /* TLB Probe (TLBP) failure */
#define IR_INDEX_MASK 0x0000003f /* Index of TLB entry for TLBR/TLBWI */
/* Random register */
#define RR_INDEX_MASK 0x0000003f /* Index of TLB entry for TLBWR */
#define NTLBENTRIES 48 /* Max TLB index is one less */
/* Wired register */
#define WR_INDEX_MASK 0x0000003f /* Number of wired TLB entries */
/* PrID register fields */
#define PRID_IMP_MASK (0xff<<8) /* Implementation number */
#define PRID_REV_MASK (0xff<<0) /* Revision number */
/* Config register fields (read only except for K0 cacheability attributes) */
#define CFG_ECMASK 0x70000000 /* System Clock Ratio: */
#define CFG_ECBY2 0x00000000 /* processor clock divided by 2 */
#define CFG_ECBY3 0x10000000 /* processor clock divided by 3 */
#define CFG_ECBY4 0x20000000 /* processor clock divided by 4 */
#define CFG_ECBY5 0x30000000 /* processor clock divided by 5 */
#define CFG_ECBY6 0x40000000 /* processor clock divided by 6 */
#define CFG_ECBY7 0x50000000 /* processor clock divided by 7 */
#define CFG_ECBY8 0x60000000 /* processor clock divided by 8 */
#define CFG_EC_RESERVED 0x70000000 /* (reserved) */
#define CFG_EPMASK 0x0f000000 /* Writeback pattern: */
#define CFG_EPD 0x00000000 /* DDDD (one dword every cycle) */
#define CFG_EPDDx 0x01000000 /* DDxDDx (2 dword/3 cyc) */
#define CFG_EPDDxx 0x02000000 /* DDxDDx (2 dword/4 cyc) */
#define CFG_EPDxDx 0x03000000 /* DxDxDxDx (2 dword/4 cyc) */
#define CFG_EPDDxxx 0x04000000 /* DDxxxDDxxx (2 dword/5 cyc) */
#define CFG_EPDDxxxx 0x05000000 /* DDxxxxDDxxxx (2 dword/6 cyc) */
#define CFG_EPDxxDxx 0x06000000 /* DxxDxxDxxDxx (2 dword/6 cyc) */
#define CFG_EPDDxxxxx 0x07000000 /* DDxxxxxDDxxxxx (2 dword/7 cyc) */
#define CFG_EPDDxxxxxx 0x08000000 /* DDxxxxxxDDxxxxxx (2 dword/8 cyc) */
#define CFG_BEMASK 0x00008000 /* Big Endian */
#define CFG_EMMASK 0x00004000 /* set to 1 => Parity mode enabled */
#define CFG_EBMASK 0x00002000 /* set to 1 => Sub-block ordering */
#define CFG_ICMASK 0x00000e00 /* I-cache size = 2**(12+IC) bytes */
#define CFG_ICSHIFT 9
#define CFG_DCMASK 0x000001c0 /* D-cache size = 2**(12+DC) bytes */
#define CFG_DCSHIFT 6
#define CFG_IBMASK 0x00000020 /* set to 1 => 32 byte I-cache line */
#define CFG_DBMASK 0x00000010 /* set to 1 => 32 byte D-cache line */
#define CFG_K0C_MASK 0x00000007 /* KSEG0 cacheability attributes: */
#define CFG_C_WTNOALLOC 0 /* write thru, no write allocate */
#define CFG_C_WTALLOC 1 /* write thru, write allocate */
#define CFG_C_UNCACHED 2 /* uncached */
#define CFG_C_WRITEBACK 3 /* writeback, non-coherent */
/* Primary Cache TagLo */
#define TAG_PTAG_MASK 0xffffff00 /* P-Cache Tag (Addr 35:12) */
#define TAG_PTAG_SHIFT 8
#define TAG_PSTATE_MASK 0x000000c0 /* P-Cache State */
#define TAG_PSTATE_SHIFT 6
#define TAG_FIFO_BIT_MASK 0x00000002 /* P-Cache FIFO bit */
#define TAG_FIFO_BIT_SHIFT 1
#define TAG_PARITY_MASK 0x00000001 /* P-Cache Tag Parity */
#define TAG_PARITY_SHIFT 0
#define PSTATE_INVAL 0 /* Invalid */
#define PSTATE_SHARED 1 /* Should not occur */
#define PSTATE_CLEAN_EXCL 2 /* Should not occur */
#define PSTATE_DIRTY_EXCL 3 /* Dirty exclusive */
/*
* System Control Coprocessor (CP0) exception processing registers
*/
#define C0_CONTEXT $4 /* Context */
#define C0_BADVADDR $8 /* Bad Virtual Address */
#define C0_COUNT $9 /* Count */
#define C0_COMPARE $11 /* Compare */
#define C0_STATUS $12 /* Processor Status */
#define C0_CAUSE $13 /* Exception Cause */
#define C0_EPC $14 /* Exception PC */
#define C0_XCONTEXT $20 /* XContext */
#define C0_ECC $26 /* ECC */
#define C0_CACHEERR $27 /* CacheErr */
#define C0_ERROREPC $30 /* ErrorEPC */
/* Status register fields */
#define SR_CUMASK 0xf0000000 /* Coprocessor usable bits */
#define SR_CU3 0x80000000 /* Coprocessor 3 usable */
#define SR_CU2 0x40000000 /* coprocessor 2 usable */
#define SR_CU1 0x20000000 /* Coprocessor 1 usable */
#define SR_CU0 0x10000000 /* Coprocessor 0 usable */
#define SR_FR 0x04000000 /* Enable 32 floating-point registers */
#define SR_RE 0x02000000 /* Reverse Endian in user mode */
#define SR_BEV 0x00400000 /* Bootstrap Exception Vector */
#define SR_TS 0x00200000 /* TLB shutdown (reserved on R4600) */
#define SR_SR 0x00100000 /* Soft Reset */
#define SR_CH 0x00040000 /* Cache Hit */
#define SR_CE 0x00020000 /* ECC register modifies check bits */
#define SR_DE 0x00010000 /* Disable cache errors */
#define SR_IMASK 0x0000ff00 /* Interrupt Mask */
#define SR_IMASK8 0x00000000 /* Interrupt Mask level=8 */
#define SR_IMASK7 0x00008000 /* Interrupt Mask level=7 */
#define SR_IMASK6 0x0000c000 /* Interrupt Mask level=6 */
#define SR_IMASK5 0x0000e000 /* Interrupt Mask level=5 */
#define SR_IMASK4 0x0000f000 /* Interrupt Mask level=4 */
#define SR_IMASK3 0x0000f800 /* Interrupt Mask level=3 */
#define SR_IMASK2 0x0000fc00 /* Interrupt Mask level=2 */
#define SR_IMASK1 0x0000fe00 /* Interrupt Mask level=1 */
#define SR_IMASK0 0x0000ff00 /* Interrupt Mask level=0 */
#define SR_IBIT8 0x00008000 /* (Intr5) */
#define SR_IBIT7 0x00004000 /* (Intr4) */
#define SR_IBIT6 0x00002000 /* (Intr3) */
#define SR_IBIT5 0x00001000 /* (Intr2) */
#define SR_IBIT4 0x00000800 /* (Intr1) */
#define SR_IBIT3 0x00000400 /* (Intr0) */
#define SR_IBIT2 0x00000200 /* (Software Interrupt 1) */
#define SR_IBIT1 0x00000100 /* (Software Interrupt 0) */
#define SR_KX 0x00000080 /* xtlb in kernel mode */
#define SR_SX 0x00000040 /* mips3 & xtlb in supervisor mode */
#define SR_UX 0x00000020 /* mips3 & xtlb in user mode */
#define SR_KSU_MASK 0x00000018 /* ksu mode mask */
#define SR_KSU_USER 0x00000010 /* user mode */
#define SR_KSU_SUPV 0x00000008 /* supervisor mode */
#define SR_KSU_KERN 0x00000000 /* kernel mode */
#define SR_ERL 0x00000004 /* error level */
#define SR_EXL 0x00000002 /* exception level */
#define SR_IE 0x00000001 /* interrupt enable */
/* Cause register fields */
#define CAUSE_BD 0x80000000 /* Branch Delay */
#define CAUSE_CEMASK 0x30000000 /* Coprocessor Error */
#define CAUSE_CESHIFT 28 /* Right justify CE */
#define CAUSE_IPMASK 0x0000ff00 /* Interrupt Pending */
#define CAUSE_IPSHIFT 8 /* Right justify IP */
#define CAUSE_IP8 0x00008000 /* (Intr5) */
#define CAUSE_IP7 0x00004000 /* (Intr4) */
#define CAUSE_IP6 0x00002000 /* (Intr3) */
#define CAUSE_IP5 0x00001000 /* (Intr2) */
#define CAUSE_IP4 0x00000800 /* (Intr1) */
#define CAUSE_IP3 0x00000400 /* (Intr0) */
#define CAUSE_SW2 0x00000200 /* (Software Interrupt 1) */
#define CAUSE_SW1 0x00000100 /* (Software Interrupt 0) */
#define CAUSE_EXCMASK 0x0000007c /* Exception Code */
#define CAUSE_EXCSHIFT 2 /* Right justify EXC */
/* Exception Codes */
#define EXC_INT 0 /* External interrupt */
#define EXC_MOD 1 /* TLB modification exception */
#define EXC_TLBL 2 /* TLB miss (Load or Ifetch) */
#define EXC_TLBS 3 /* TLB miss (Store) */
#define EXC_ADEL 4 /* Address error (Load or Ifetch) */
#define EXC_ADES 5 /* Address error (Store) */
#define EXC_IBE 6 /* Bus error (Ifetch) */
#define EXC_DBE 7 /* Bus error (data load or store) */
#define EXC_SYS 8 /* System call */
#define EXC_BP 9 /* Break point */
#define EXC_RI 10 /* Reserved instruction */
#define EXC_CPU 11 /* Coprocessor unusable */
#define EXC_OVF 12 /* Arithmetic overflow */
#define EXC_TRAP 13 /* Trap exception */
#define EXC_FPE 15 /* Floating Point Exception */
/* CacheErr register */
#define CACHEERR_TYPE 0x80000000 /* reference type:
0=Instr, 1=Data */
#define CACHEERR_LEVEL 0x40000000 /* cache level:
0=Primary, 1=Secondary */
#define CACHEERR_DATA 0x20000000 /* data field:
0=No error, 1=Error */
#define CACHEERR_TAG 0x10000000 /* tag field:
0=No error, 1=Error */
#define CACHEERR_REQ 0x08000000 /* request type:
0=Internal, 1=External */
#define CACHEERR_BUS 0x04000000 /* error on bus:
0=No, 1=Yes */
#define CACHEERR_BOTH 0x02000000 /* Data & Instruction error:
0=No, 1=Yes */
#define CACHEERR_REFILL 0x01000000 /* Error on Refill:
0=No, 1=Yes */
#define CACHEERR_SIDX_MASK 0x003ffff8 /* PADDR(21..3) */
#define CACHEERR_SIDX_SHIFT 0
#define CACHEERR_PIDX_MASK 0x00000007 /* VADDR(14..12) */
#define CACHEERR_PIDX_SHIFT 12
/*
* R4600 Cache operations
*/
#define Index_Invalidate_I 0x0 /* 0 0 */
#define Index_Writeback_Inv_D 0x1 /* 0 1 */
#define Index_Load_Tag_I 0x4 /* 1 0 */
#define Index_Load_Tag_D 0x5 /* 1 1 */
#define Index_Store_Tag_I 0x8 /* 2 0 */
#define Index_Store_Tag_D 0x9 /* 2 1 */
#define Create_Dirty_Exc_D 0xD /* 3 1 */
#define Hit_Invalidate_I 0x10 /* 4 0 */
#define Hit_Invalidate_D 0x11 /* 4 1 */
#define Fill_I 0x14 /* 5 0 */
#define Hit_Writeback_Inv_D 0x15 /* 5 1 */
#define Hit_Writeback_I 0x18 /* 6 0 */
#define Hit_Writeback_D 0x19 /* 6 1 */
/*
* Floating Point Coprocessor (CP1) registers
*/
#define C1_IRR $0 /* Implementation/Revision register */
#define C1_CSR $31 /* FPU Control/Status register */
/* Implementation/Revision reg fields */
#define IRR_IMP_MASK (0xff<<8) /* Implementation number */
#define IRR_REV_MASK (0xff<<0) /* Revision number */
/* FPU Control/Status register fields */
#define CSR_FS 0x01000000 /* Set to flush denormals to zero */
#define CSR_C 0x00800000 /* Condition bit (set by FP compare) */
#define CSR_CMASK (0x3f<<12)
#define CSR_CE 0x00020000
#define CSR_CV 0x00010000
#define CSR_CZ 0x00008000
#define CSR_CO 0x00004000
#define CSR_CU 0x00002000
#define CSR_CI 0x00001000
#define CSR_EMASK (0x1f<<7)
#define CSR_EV 0x00000800
#define CSR_EZ 0x00000400
#define CSR_EO 0x00000200
#define CSR_EU 0x00000100
#define CSR_EI 0x00000080
#define CSR_FMASK (0x1f<<2)
#define CSR_FV 0x00000040
#define CSR_FZ 0x00000020
#define CSR_FO 0x00000010
#define CSR_FU 0x00000008
#define CSR_FI 0x00000004
#define CSR_RMODE_MASK (0x3<<0)
#define CSR_RM 0x00000003
#define CSR_RP 0x00000002
#define CSR_RZ 0x00000001
#define CSR_RN 0x00000000
#endif /* _R4600_H */

View File

@@ -0,0 +1,844 @@
/*******************************************************************************
THIS SOFTWARE IS NOT COPYRIGHTED
The following software is offered for use in the public domain.
There is no warranty with regard to this software or its performance
and the user must accept the software "AS IS" with all faults.
THE CONTRIBUTORS DISCLAIM ANY WARRANTIES, EXPRESS OR IMPLIED, WITH
REGARD TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
********************************************************************************
*
* r46kstub.c -- target debugging stub for the IDT R4600 Orion processor
*
* This module is based on the stub for the Hitachi SH processor written by
* Ben Lee and Steve Chamberlain and supplied with gdb 4.16. The latter
* in turn "is originally based on an m68k software stub written by Glenn
* Engel at HP, but has changed quite a bit." The changes for the R4600
* were written by C. M. Heard at VVNET. They were based in part on the
* Algorithmics R4000 version of Phil Bunce's PMON program.
*
* Remote communication protocol:
*
* A debug packet whose contents are <data>
* is encapsulated for transmission in the form:
*
* $ <data> # CSUM1 CSUM2
*
* <data> must be ASCII alphanumeric and cannot include characters
* '$' or '#'. If <data> starts with two characters followed by
* ':', then the existing stubs interpret this as a sequence number.
*
* CSUM1 and CSUM2 are ascii hex representation of an 8-bit
* checksum of <data>, the most significant nibble is sent first.
* the hex digits 0-9,a-f are used.
*
* Receiver responds with:
*
* + if CSUM is correct
* - if CSUM is incorrect
*
* <data> is as follows. All values are encoded in ascii hex digits.
*
* Request Packet
*
* read registers g
* reply XX....X Each byte of register data
* is described by two hex digits.
* Registers are in the internal order
* for GDB, and the bytes in a register
* are in the same order the machine uses.
* or ENN for an error.
*
* write regs GXX..XX Each byte of register data
* is described by two hex digits.
* reply OK for success
* ENN for an error
*
* write reg Pn...=r... Write register n... with value r....
* reply OK for success
* ENN for an error
*
* read mem mAA..AA,LLLL AA..AA is address, LLLL is length.
* reply XX..XX XX..XX is mem contents
* Can be fewer bytes than requested
* if able to read only part of the data.
* or ENN NN is errno
*
* write mem MAA..AA,LLLL:XX..XX
* AA..AA is address,
* LLLL is number of bytes,
* XX..XX is data
* reply OK for success
* ENN for an error (this includes the case
* where only part of the data was
* written).
*
* cont cAA..AA AA..AA is address to resume
* If AA..AA is omitted,
* resume at same address.
*
* step sAA..AA AA..AA is address to resume
* If AA..AA is omitted,
* resume at same address.
*
* There is no immediate reply to step or cont.
* The reply comes when the machine stops.
* It is SAA AA is the "signal number"
*
* last signal ? Reply with the reason for stopping.
* This is the same reply as is generated
* for step or cont: SAA where AA is the
* signal number.
*
* detach D Host is detaching. Reply OK and
* end remote debugging session.
*
* reserved <other> On other requests, the stub should
* ignore the request and send an empty
* response ($#<checksum>). This way
* we can extend the protocol and GDB
* can tell whether the stub it is
* talking to uses the old or the new.
*
* Responses can be run-length encoded to save space. A '*' means that
* the next character is an ASCII encoding giving a repeat count which
* stands for that many repetitions of the character preceding the '*'.
* The encoding is n+29, yielding a printable character when n >=3
* (which is where rle starts to win). Don't use n > 99 since gdb
* masks each character is receives with 0x7f in order to strip off
* the parity bit.
*
* As an example, "0* " means the same thing as "0000".
*
*******************************************************************************/
#include <string.h>
#include <signal.h>
#include "mips_opcode.h"
#include "r4600.h"
#include "limits.h"
#include "gdb_if.h"
/*
* Saved register information. Must be prepared by the exception
* preprocessor before handle_exception is invoked.
*/
extern long long registers[NUM_REGS];
/*
* The following external functions provide character input and output.
*/
extern char getDebugChar (void);
extern void putDebugChar (char);
/*
* BUFMAX defines the maximum number of characters in the inbound & outbound
* packet buffers. At least 4+(sizeof registers)*2 bytes will be needed for
* register packets. Memory dump packets can profitably use even more.
*/
#define BUFMAX 1500
static char inBuffer[BUFMAX];
static char outBuffer[BUFMAX];
/*
* Convert an int to hex.
*/
static const char hexchars[] = "0123456789abcdef";
#define highhex(x) hexchars [(x >> 4) & 0xf]
#define lowhex(x) hexchars [x & 0xf]
/*
* Convert length bytes of data starting at addr into hex, placing the
* result in buf. Return a pointer to the last (null) char in buf.
*/
static char *
mem2hex (int addr, int length, char *buf)
{
if (((addr & 0x7) == 0) && ((length & 0x7) == 0)) /* dword aligned */
{
long long *source = (long long *) (addr);
long long *limit = (long long *) (addr + length);
while (source < limit)
{
int i;
long long k = *source++;
for (i = 15; i >= 0; i--)
*buf++ = hexchars [(k >> (i*4)) & 0xf];
}
}
else if (((addr & 0x3) == 0) && ((length & 0x3) == 0)) /* word aligned */
{
int *source = (int *) (addr);
int *limit = (int *) (addr + length);
while (source < limit)
{
int i;
int k = *source++;
for (i = 7; i >= 0; i--)
*buf++ = hexchars [(k >> (i*4)) & 0xf];
}
}
else if (((addr & 0x1) == 0) && ((length & 0x1) == 0)) /* halfword aligned */
{
short *source = (short *) (addr);
short *limit = (short *) (addr + length);
while (source < limit)
{
int i;
short k = *source++;
for (i = 3; i >= 0; i--)
*buf++ = hexchars [(k >> (i*4)) & 0xf];
}
}
else /* byte aligned */
{
char *source = (char *) (addr);
char *limit = (char *) (addr + length);
while (source < limit)
{
int i;
char k = *source++;
for (i = 1; i >= 0; i--)
*buf++ = hexchars [(k >> (i*4)) & 0xf];
}
}
*buf = '\0';
return (buf);
}
/*
* Convert a hex character to an int.
*/
static int
hex (char ch)
{
if ((ch >= 'a') && (ch <= 'f'))
return (ch - 'a' + 10);
if ((ch >= '0') && (ch <= '9'))
return (ch - '0');
if ((ch >= 'A') && (ch <= 'F'))
return (ch - 'A' + 10);
return (-1);
}
/*
* Convert a string from hex to int until a non-hex digit
* is found. Return the number of characters processed.
*/
static int
hexToInt (char **ptr, int *intValue)
{
int numChars = 0;
int hexValue;
*intValue = 0;
while (**ptr)
{
hexValue = hex (**ptr);
if (hexValue >= 0)
{
*intValue = (*intValue << 4) | hexValue;
numChars++;
}
else
break;
(*ptr)++;
}
return (numChars);
}
/*
* Convert a string from hex to long long until a non-hex
* digit is found. Return the number of characters processed.
*/
static int
hexToLongLong (char **ptr, long long *intValue)
{
int numChars = 0;
int hexValue;
*intValue = 0;
while (**ptr)
{
hexValue = hex (**ptr);
if (hexValue >= 0)
{
*intValue = (*intValue << 4) | hexValue;
numChars++;
}
else
break;
(*ptr)++;
}
return (numChars);
}
/*
* Convert the hex array buf into binary, placing the result at the
* specified address. If the conversion fails at any point (i.e.,
* if fewer bytes are written than indicated by the size parameter)
* then return 0; otherwise return 1.
*/
static int
hex2mem (char *buf, int addr, int length)
{
if (((addr & 0x7) == 0) && ((length & 0x7) == 0)) /* dword aligned */
{
long long *target = (long long *) (addr);
long long *limit = (long long *) (addr + length);
while (target < limit)
{
int i, j;
long long k = 0;
for (i = 0; i < 16; i++)
if ((j = hex(*buf++)) < 0)
return 0;
else
k = (k << 4) + j;
*target++ = k;
}
}
else if (((addr & 0x3) == 0) && ((length & 0x3) == 0)) /* word aligned */
{
int *target = (int *) (addr);
int *limit = (int *) (addr + length);
while (target < limit)
{
int i, j;
int k = 0;
for (i = 0; i < 8; i++)
if ((j = hex(*buf++)) < 0)
return 0;
else
k = (k << 4) + j;
*target++ = k;
}
}
else if (((addr & 0x1) == 0) && ((length & 0x1) == 0)) /* halfword aligned */
{
short *target = (short *) (addr);
short *limit = (short *) (addr + length);
while (target < limit)
{
int i, j;
short k = 0;
for (i = 0; i < 4; i++)
if ((j = hex(*buf++)) < 0)
return 0;
else
k = (k << 4) + j;
*target++ = k;
}
}
else /* byte aligned */
{
char *target = (char *) (addr);
char *limit = (char *) (addr + length);
while (target < limit)
{
int i, j;
char k = 0;
for (i = 0; i < 2; i++)
if ((j = hex(*buf++)) < 0)
return 0;
else
k = (k << 4) + j;
*target++ = k;
}
}
return 1;
}
/*
* Scan the input stream for a sequence for the form $<data>#<checksum>.
*/
static void
getpacket (char *buffer)
{
unsigned char checksum;
unsigned char xmitcsum;
int i;
int count;
char ch;
do
{
/* wait around for the start character, ignore all other characters */
while ((ch = getDebugChar ()) != '$');
checksum = 0;
xmitcsum = -1;
count = 0;
/* now, read until a # or end of buffer is found */
while ( (count < BUFMAX-1) && ((ch = getDebugChar ()) != '#') )
checksum += (buffer[count++] = ch);
/* make sure that the buffer is null-terminated */
buffer[count] = '\0';
if (ch == '#')
{
xmitcsum = hex (getDebugChar ()) << 4;
xmitcsum += hex (getDebugChar ());
if (checksum != xmitcsum)
putDebugChar ('-'); /* failed checksum */
else
{
putDebugChar ('+'); /* successful transfer */
/* if a sequence char is present, reply the sequence ID */
if (buffer[2] == ':')
{
putDebugChar (buffer[0]);
putDebugChar (buffer[1]);
/* remove sequence chars from buffer */
for (i = 3; i <= count; i++)
buffer[i - 3] = buffer[i];
}
}
}
}
while (checksum != xmitcsum);
}
/*
* Send the packet in buffer and wait for a positive acknowledgement.
*/
static void
putpacket (char *buffer)
{
int checksum;
/* $<packet info>#<checksum> */
do
{
char *src = buffer;
putDebugChar ('$');
checksum = 0;
while (*src != '\0')
{
int runlen = 0;
/* Do run length encoding */
while ((src[runlen] == src[0]) && (runlen < 99))
runlen++;
if (runlen > 3)
{
int encode;
/* Got a useful amount */
putDebugChar (*src);
checksum += *src;
putDebugChar ('*');
checksum += '*';
checksum += (encode = (runlen - 4) + ' ');
putDebugChar (encode);
src += runlen;
}
else
{
putDebugChar (*src);
checksum += *src;
src++;
}
}
putDebugChar ('#');
putDebugChar (highhex (checksum));
putDebugChar (lowhex (checksum));
}
while (getDebugChar () != '+');
}
/*
* Saved instruction data for single step support
*/
static struct
{
unsigned *targetAddr;
unsigned savedInstr;
}
instrBuffer;
/*
* If a step breakpoint was planted restore the saved instruction.
*/
static void
undoSStep (void)
{
if (instrBuffer.targetAddr != NULL)
{
*instrBuffer.targetAddr = instrBuffer.savedInstr;
instrBuffer.targetAddr = NULL;
}
instrBuffer.savedInstr = NOP_INSTR;
}
/*
* If a single step is requested put a temporary breakpoint at the instruction
* which logically follows the next one to be executed. If the next instruction
* is a branch instruction then skip the instruction in the delay slot. NOTE:
* ERET instructions are NOT handled, as it is impossible to single-step through
* the exit code in an exception handler. In addition, no attempt is made to
* do anything about BC0T and BC0F, since a condition bit for coprocessor 0
* is not defined on the R4600. Finally, BC2T and BC2F are ignored since there
* is no coprocessor 2 on a 4600.
*/
static void
doSStep (void)
{
InstFmt inst;
instrBuffer.targetAddr = (unsigned *)(registers[PC]+4); /* set default */
inst.word = *(unsigned *)registers[PC]; /* read the next instruction */
switch (inst.RType.op) { /* override default if branch */
case OP_SPECIAL:
switch (inst.RType.func) {
case OP_JR:
case OP_JALR:
instrBuffer.targetAddr =
(unsigned *)registers[inst.RType.rs];
break;
};
break;
case OP_REGIMM:
switch (inst.IType.rt) {
case OP_BLTZ:
case OP_BLTZL:
case OP_BLTZAL:
case OP_BLTZALL:
if (registers[inst.IType.rs] < 0 )
instrBuffer.targetAddr =
(unsigned *)(((signed short)inst.IType.imm<<2)
+ (registers[PC]+4));
else
instrBuffer.targetAddr = (unsigned*)(registers[PC]+8);
break;
case OP_BGEZ:
case OP_BGEZL:
case OP_BGEZAL:
case OP_BGEZALL:
if (registers[inst.IType.rs] >= 0 )
instrBuffer.targetAddr =
(unsigned *)(((signed short)inst.IType.imm<<2)
+ (registers[PC]+4));
else
instrBuffer.targetAddr = (unsigned*)(registers[PC]+8);
break;
};
break;
case OP_J:
case OP_JAL:
instrBuffer.targetAddr =
(unsigned *)((inst.JType.target<<2) + ((registers[PC]+4)&0xf0000000));
break;
case OP_BEQ:
case OP_BEQL:
if (registers[inst.IType.rs] == registers[inst.IType.rt])
instrBuffer.targetAddr =
(unsigned *)(((signed short)inst.IType.imm<<2) + (registers[PC]+4));
else
instrBuffer.targetAddr = (unsigned*)(registers[PC]+8);
break;
case OP_BNE:
case OP_BNEL:
if (registers[inst.IType.rs] != registers[inst.IType.rt])
instrBuffer.targetAddr =
(unsigned *)(((signed short)inst.IType.imm<<2) + (registers[PC]+4));
else
instrBuffer.targetAddr = (unsigned*)(registers[PC]+8);
break;
case OP_BLEZ:
case OP_BLEZL:
if (registers[inst.IType.rs] <= 0)
instrBuffer.targetAddr =
(unsigned *)(((signed short)inst.IType.imm<<2) + (registers[PC]+4));
else
instrBuffer.targetAddr = (unsigned*)(registers[PC]+8);
break;
case OP_BGTZ:
case OP_BGTZL:
if (registers[inst.IType.rs] > 0)
instrBuffer.targetAddr =
(unsigned *)(((signed short)inst.IType.imm<<2) + (registers[PC]+4));
else
instrBuffer.targetAddr = (unsigned*)(registers[PC]+8);
break;
case OP_COP1:
if (inst.RType.rs == OP_BC)
switch (inst.RType.rt) {
case COPz_BCF:
case COPz_BCFL:
if (registers[FCSR] & CSR_C)
instrBuffer.targetAddr = (unsigned*)(registers[PC]+8);
else
instrBuffer.targetAddr =
(unsigned *)(((signed short)inst.IType.imm<<2)
+ (registers[PC]+4));
break;
case COPz_BCT:
case COPz_BCTL:
if (registers[FCSR] & CSR_C)
instrBuffer.targetAddr =
(unsigned *)(((signed short)inst.IType.imm<<2)
+ (registers[PC]+4));
else
instrBuffer.targetAddr = (unsigned*)(registers[PC]+8);
break;
};
break;
}
if is_steppable (instrBuffer.targetAddr)
{
instrBuffer.savedInstr = *instrBuffer.targetAddr;
*instrBuffer.targetAddr = BREAK_INSTR;
}
else
{
instrBuffer.targetAddr = NULL;
instrBuffer.savedInstr = NOP_INSTR;
}
return;
}
/*
* Translate the R4600 exception code into a Unix-compatible signal.
*/
static int
computeSignal (void)
{
int exceptionCode = (registers[CAUSE] & CAUSE_EXCMASK) >> CAUSE_EXCSHIFT;
switch (exceptionCode)
{
case EXC_INT:
/* External interrupt */
return SIGINT;
case EXC_RI:
/* Reserved instruction */
case EXC_CPU:
/* Coprocessor unusable */
return SIGILL;
case EXC_BP:
/* Break point */
return SIGTRAP;
case EXC_OVF:
/* Arithmetic overflow */
case EXC_TRAP:
/* Trap exception */
case EXC_FPE:
/* Floating Point Exception */
return SIGFPE;
case EXC_IBE:
/* Bus error (Ifetch) */
case EXC_DBE:
/* Bus error (data load or store) */
return SIGBUS;
case EXC_MOD:
/* TLB modification exception */
case EXC_TLBL:
/* TLB miss (Load or Ifetch) */
case EXC_TLBS:
/* TLB miss (Store) */
case EXC_ADEL:
/* Address error (Load or Ifetch) */
case EXC_ADES:
/* Address error (Store) */
return SIGSEGV;
case EXC_SYS:
/* System call */
return SIGSYS;
default:
return SIGTERM;
}
}
/*
* This function handles all exceptions. It only does two things:
* it figures out why it was activated and tells gdb, and then it
* reacts to gdb's requests.
*/
void
handle_exception (void)
{
int host_has_detached = 0;
int sigval;
int regno, addr, length;
long long regval;
char *ptr;
/* reply to host that an exception has occurred */
sigval = computeSignal ();
outBuffer[0] = 'S';
outBuffer[1] = highhex (sigval);
outBuffer[2] = lowhex (sigval);
outBuffer[3] = '\0';
putpacket (outBuffer);
/*
* Restore the saved instruction at
* the single-step target address.
*/
undoSStep ();
while (!(host_has_detached))
{
outBuffer[0] = '\0';
getpacket (inBuffer);
switch (inBuffer[0])
{
case '?':
outBuffer[0] = 'S';
outBuffer[1] = highhex (sigval);
outBuffer[2] = lowhex (sigval);
outBuffer[3] = '\0';
break;
case 'g':
/* return the values of the CPU registers */
mem2hex ((int) registers, sizeof registers, outBuffer);
break;
case 'G':
/* set the values of the CPU registers - return OK */
if (hex2mem (&inBuffer[1], (int) registers, sizeof registers))
strcpy (outBuffer, "OK");
else
strcpy (outBuffer, "E00"); /* E00 = bad "set register" command */
break;
case 'P':
/* Pn...=r... Write register n... with value r... - return OK */
ptr = &inBuffer[1];
if (hexToInt(&ptr, &regno) &&
*ptr++ == '=' &&
hexToLongLong(&ptr, &regval))
{
registers[regno] = regval;
strcpy (outBuffer, "OK");
}
else
strcpy (outBuffer, "E00"); /* E00 = bad "set register" command */
break;
case 'm':
/* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
ptr = &inBuffer[1];
if (hexToInt (&ptr, &addr)
&& *ptr++ == ','
&& hexToInt (&ptr, &length)
&& is_readable (addr, length)
&& (length < (BUFMAX - 4)/2))
mem2hex (addr, length, outBuffer);
else
strcpy (outBuffer, "E01"); /* E01 = bad 'm' command */
break;
case 'M':
/* MAA..AA,LLLL: Write LLLL bytes at address AA..AA - return OK */
ptr = &inBuffer[1];
if (hexToInt (&ptr, &addr)
&& *ptr++ == ','
&& hexToInt (&ptr, &length)
&& *ptr++ == ':'
&& is_writeable (addr, length)
&& hex2mem (ptr, addr, length))
strcpy (outBuffer, "OK");
else
strcpy (outBuffer, "E02"); /* E02 = bad 'M' command */
break;
case 'c':
/* cAA..AA Continue at address AA..AA(optional) */
case 's':
/* sAA..AA Step one instruction from AA..AA(optional) */
{
/* try to read optional parameter, pc unchanged if no parm */
ptr = &inBuffer[1];
if (hexToInt (&ptr, &addr))
registers[PC] = addr;
if (inBuffer[0] == 's')
doSStep ();
}
return;
case 'D':
/* remote system is detaching - return OK and exit from debugger */
strcpy (outBuffer, "OK");
host_has_detached = 1;
break;
default:
/* do nothing */
break;
} /* switch */
/* reply to the request */
putpacket (outBuffer);
}
return;
}

View File

@@ -0,0 +1,53 @@
MEMORY
{
NUL : ORIGIN = 0xa00f0000, LENGTH = 0
RAM : ORIGIN = 0xa00fe000, LENGTH = 8K
ROM : ORIGIN = 0xbfc00000, LENGTH = 8K
}
SECTIONS
{
/* Initialized data is _not_ supported. */
/* Assign it to an empty region in order */
/* to force a link error if any exists. */
.data 0xa00f0000 (NOLOAD): {
_fdata = .;
*(.data)
. = ALIGN(8);
_gp = . + 0x8000;
*(.sdata)
. = ALIGN(8);
_edata = .;
} >NUL
/* Assign uninitialized read/write data to RAM. */
.bss 0xa00fe000 (NOLOAD): {
_fbss = .;
stubinit.o(.bss)
*(.sbss)
*(.bss)
*(.scommon)
*(COMMON)
. = ALIGN(8);
_end = .;
} >RAM
/* Assign code and read-only data to ROM. This */
/* section MUST start at the reset address, */
/* and the reset code MUST be linked first. */
.text 0xbfc00000: {
_ftext = .;
stubinit.o(.text)
. = ALIGN(8);
r46kstub.o(.text)
. = ALIGN(8);
*(.rdata)
. = ALIGN(8);
*(.rodata)
. = ALIGN(8);
_etext = .;
} >ROM = 0
}
ENTRY(_reset_exception)

View File

@@ -0,0 +1,616 @@
/*
* stubinit.S - low level startup code for the ROM-based R4600 gdb stub
*
* THIS SOFTWARE IS NOT COPYRIGHTED
*
* The following software is offered for use in the public domain.
* There is no warranty with regard to this software or its performance
* and the user must accept the software "AS IS" with all faults.
*
* THE CONTRIBUTORS DISCLAIM ANY WARRANTIES, EXPRESS OR IMPLIED, WITH
* REGARD TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
.nolist
#include "r4600.h"
#include "ioaddr.h"
#include "gdb_if.h"
.list
#define SERIAL_SPEED 19200 /* use 19200 bps serial link */
#define FORCE_PC_TO_32_BITS /* to work around a bug in gdb-4.16 */
#define STACKSIZE 4096 /* allocate 4K bootstack */
.sdata
.globl _gp /* value to put in gp register */
.bss
.globl _fbss /* start of .bss area */
.space STACKSIZE /* allocate the exception stack */
_stack: /* stack top here (stack grows DOWN) */
.globl registers /* register save area */
registers:
.space NUM_REGS*8
.globl _end /* end of .bss area */
.eject
.text
.globl handle_exception /* C exception handler */
.set noreorder
.set noat
.globl _reset_exception /* entry point into the EPROM */
/* it MUST reside at bfc00000 */
/*
* Set the STATUS register initial state: mark CP1 usable, MIPS-3
* floating point registers enabled, boot exception vectors selected,
* cache parity exceptions disabled, kernel TLB miss to XTLB refill
* vector, machine in kernel mode, exception level cleared, error
* level set, interrupt enable cleared, all interrupts masked. Note
* that the value written here is what will saved in the register
* image; this will put the machine in a reasonable default state
* even if the debug exception handler does nothing to the status
* register image.
*/
_reset_exception:
li k0,SR_CU1 + SR_FR + SR_BEV + SR_DE + SR_KX \
+ SR_KSU_KERN + SR_ERL
mtc0 k0,C0_STATUS
/*
* Mark each TLB entry as "invalid" and fill the tag field with a VPN that
* cannot occur and an ASID that will not match the value left in EntryHi.
*/
li k0,K1BASE+EH_ASID_MASK /* EntryHi = unmapped VPN2, ASID 255 */
dmtc0 zero,C0_ENTRYLO0 /* EntryLo0 = invalid */
dmtc0 zero,C0_ENTRYLO1 /* EntryLo1 = invalid */
mtc0 zero,C0_PAGEMASK /* PageSize = 4K */
li k1,(NTLBENTRIES-1) /* TLB index */
1:
dmtc0 k0,C0_ENTRYHI
mtc0 k1,C0_INDEX
addu k0,(1<<EH_VPN2_SHIFT) /* incr VPN2 */
tlbwi
bnel k1,zero,1b
addiu k1,k1,-1 /* decr INDEX */
dmtc0 zero,C0_ENTRYHI /* Clear EntryHi to select ASID = 0 */
nop /* wait for update to take effect */
.eject
/*
* Invalidate each line in both of the caches, then
* set kseg0 config to cached/writeback/non-coherent.
*/
mtc0 zero,C0_TAGLO /* clear TAGLO and TAGHI - used below */
mtc0 zero,C0_TAGHI /* to set cache line state to invalid */
nop
mfc0 k0,C0_CONFIG /* read config info */
li k1,(1<<12) /* base size is 4K */
and k0,CFG_ICMASK /* isolate I-cache shift count param */
srl k0,CFG_ICSHIFT /* which determines the actual size */
sll k1,k0 /* shift left to get actual size */
mfc0 k0,C0_CONFIG /* read config info */
nop /* wait for CP0 read to take effect */
and k0,CFG_IBMASK /* isolate line size config bit */
bne k0,zero,2f /* jump if line size is 32 bytes */
lui k0,((K0BASE>>16)&0xffff)/* set lower limit to unmapped addr */
addu k1,k0 /* this prevents a TLB exception */
addiu k1,-16 /* set upper limit for 16 byte line */
1:
cache Index_Store_Tag_I,(k0) /* write TAGLO/TAGHI to the cache */
bnel k0,k1,1b /* do that by index so that a */
addiu k0,k0,16 /* cache hit is not required */
b 4f
nop
2:
addu k1,k0 /* come here for 32 byte line size */
addiu k1,-32
3:
cache Index_Store_Tag_I,(k0)
bnel k0,k1,3b
addiu k0,k0,32
4:
.eject
mfc0 k0,C0_CONFIG /* repeat for D-cache */
li k1,(1<<12)
and k0,CFG_DCMASK
srl k0,CFG_DCSHIFT
sll k1,k0
mfc0 k0,C0_CONFIG
nop
and k0,CFG_DBMASK
bne k0,zero,6f
lui k0,((K0BASE>>16)&0xffff)
addu k1,k0
addiu k1,-16
5:
cache Index_Store_Tag_D,(k0)
bnel k0,k1,5b
addiu k0,k0,16
b 8f
nop
6:
addu k1,k0
addiu k1,-32
7:
cache Index_Store_Tag_D,(k0)
bnel k0,k1,7b
addiu k0,k0,32
8:
mfc0 k0,C0_CONFIG /* read config info one last time */
li k1,~CFG_K0C_MASK /* clear K0 config field */
and k0,k1 /* in CONFIG image register image */
or k0,CFG_C_WRITEBACK /* set config to cached/writeback */
mtc0 k0,C0_CONFIG /* write back to CP0 */
nop /* wait for update to take effect */
.eject
/*
* Initialize the serial port
*/
li k0,DIV_LATCH_EN + WORD_LEN_MASK
la k1,ISA_IO_BASE /* set 8/bits char, no parity, and */
sb k0,LINE_CTL_COM1(k1) /* enable access to divisor latch */
li k0,(1843200/(16*SERIAL_SPEED))
sb k0,DIV_LO_COM1(k1) /* set clock divisor low byte */
sra k0,8
sb k0,DIV_HI_COM1(k1) /* set clock divisor high byte */
li k0,WORD_LEN_MASK /* set 8/bits char, no parity, and */
sb k0,LINE_CTL_COM1(k1) /* disable access to divisor latch */
lbu k0,DATA_REG_COM1(k1) /* read & discard any existing char */
sb zero,INT_ENA_COM1(k1) /* disable all interrupt sources */
li k0,RTS + DTR /* turn RTS and DTR on */
sb k0,MODEM_CTL_COM1(k1)
/*
* Reset all pending ISA interrupts
*/
la k1,ISA_IRQ3_RESET
sd zero,(k1)
la k1,ISA_IRQ4_RESET
sd zero,(k1)
la k1,ISA_IRQ5_RESET
sd zero,(k1)
la k1,ISA_IRQ9_RESET
sd zero,(k1)
.eject
/*
* Clear the CAUSE register to indicate the
* absence of software-initiated exceptions.
*/
mtc0 zero,C0_CAUSE
/*
* Clear floating point errors and configure
* the FPU to flush denormals to zero.
*/
li k0,CSR_FS
ctc1 k0,C1_CSR
/*
* Clear the .bss area
*/
la k0,_fbss
la k1,_end
1:
addiu k1,k1,-8
bne k1,k0,1b
sd zero,(k1)
/*
* Save the ErrorEPC register, in case of a pushbutton
* reset, and join the general exception-handling path.
*/
la k0,registers
dmfc0 k1,C0_ERROREPC
j _common_path_join
sd k1,8*PC(k0)
.align 9
.eject
_tlbmiss_exception: /* bfc00200: tlbmiss exception */
j _general_exception
nop
.align 7
_xtlbmiss_exception: /* bfc00280: xtlbmiss exception */
j _general_exception
nop
.align 7
_cache_parity_error: /* bfc00300: cache parity error */
j _reset_exception
nop
.align 7
/* bfc00380: general exception */
/*
* Clear the register save area
*/
_general_exception:
la k0,registers
addiu k1,k0,8*(NUM_REGS-1)
1:
sd zero,(k1)
bnel k1,k0,1b
addiu k1,k1,-8
/*
* Save the PC
*/
dmfc0 k1,C0_EPC
nop
sd k1,8*PC(k0)
.eject
/*
* Save the SR, CAUSE, and BAD_VA registers.
*/
_common_path_join:
mfc0 k1,C0_STATUS
nop
sd k1,8*SR(k0)
mfc0 k1,C0_CAUSE
nop
sd k1,8*CAUSE(k0)
mfc0 k1,C0_BADVADDR
nop
sd k1,8*BAD_VA(k0)
/*
* Save LO, HI, and the general registers.
* Note that zero, k0 & k1 are not saved.
*/
mflo k1
sd k1,8*LO(k0)
mfhi k1
sd k1,8*HI(k0)
/* zero is hard-wired */
sd at,8*AT(k0)
sd v0,8*V0(k0)
sd v1,8*V1(k0)
sd a0,8*A0(k0)
sd a1,8*A1(k0)
sd a2,8*A2(k0)
sd a3,8*A3(k0)
sd t0,8*T0(k0)
sd t1,8*T1(k0)
sd t2,8*T2(k0)
sd t3,8*T3(k0)
sd t4,8*T4(k0)
sd t5,8*T5(k0)
sd t6,8*T6(k0)
sd t7,8*T7(k0)
.eject
sd s0,8*S0(k0)
sd s1,8*S1(k0)
sd s2,8*S2(k0)
sd s3,8*S3(k0)
sd s4,8*S4(k0)
sd s5,8*S5(k0)
sd s6,8*S6(k0)
sd s7,8*S7(k0)
sd t8,8*T8(k0)
sd t9,8*T9(k0)
/* k0 is not saved */
/* k1 is not saved */
sd gp,8*GP(k0)
sd sp,8*SP(k0)
sd s8,8*S8(k0)
sd ra,8*RA(k0)
/*
* Save the floating point control registers.
*/
cfc1 k1,C1_CSR
nop
sd k1,8*FCSR(k0)
cfc1 k1,C1_IRR
nop
sd k1,8*FIRR(k0)
/*
* Save the even-numbered floating point registers.
*/
sdc1 $0,8*F0(k0)
sdc1 $2,8*F2(k0)
sdc1 $4,8*F4(k0)
sdc1 $6,8*F6(k0)
sdc1 $8,8*F8(k0)
sdc1 $10,8*F10(k0)
sdc1 $12,8*F12(k0)
sdc1 $14,8*F14(k0)
sdc1 $16,8*F16(k0)
sdc1 $18,8*F18(k0)
sdc1 $20,8*F20(k0)
sdc1 $22,8*F22(k0)
sdc1 $24,8*F24(k0)
sdc1 $26,8*F26(k0)
sdc1 $28,8*F28(k0)
sdc1 $30,8*F30(k0)
.eject
/*
* If they are enabled, save the odd-numbered
* floating point registers as well.
*/
mfc0 k1,C0_STATUS
li at,SR_FR
and k1,at
beq k1,zero,1f
nop
sdc1 $1,8*F1(k0)
sdc1 $3,8*F3(k0)
sdc1 $5,8*F5(k0)
sdc1 $7,8*F7(k0)
sdc1 $9,8*F9(k0)
sdc1 $11,8*F11(k0)
sdc1 $13,8*F13(k0)
sdc1 $15,8*F15(k0)
sdc1 $17,8*F17(k0)
sdc1 $19,8*F19(k0)
sdc1 $21,8*F21(k0)
sdc1 $23,8*F23(k0)
sdc1 $25,8*F25(k0)
sdc1 $27,8*F27(k0)
sdc1 $29,8*F29(k0)
sdc1 $31,8*F31(k0)
1:
/*
* Set up the global pointer and the stack
* and invoke the exception handler.
*/
la gp,_gp
la sp,_stack
jal handle_exception
addiu fp,sp,0
.eject
/*
* On exit from the exception handler invalidate each line in the I-cache
* and write back each dirty line in the D-cache. This needs to be done
* before the target program is resumed in order to ensure that software
* breakpoints and downloaded code will actually take effect.
*/
mfc0 t0,C0_CONFIG /* read config info into t0 */
nop /* wait for CP0 read to take effect */
and t1,t0,CFG_ICMASK /* isolate I-cache shift */
srl t1,t1,CFG_ICSHIFT /* count param into t1 */
li t2,(1<<12) /* put base size in t2 */
sllv t2,t2,t1 /* shift left to get actual size */
and t1,t0,CFG_IBMASK /* isolate linesize config bit */
bne t1,zero,1f /* guess line size is 32 bytes */
addiu t3,zero,32 /* skip next load if guessed right */
addiu t3,zero,16 /* else set size to 16 bytes */
1:
la t1,K0BASE /* set lower & upper address limits */
addu t2,t2,t1 /* use kseg0 to avoid TLB exception */
subu t2,t2,t3
2:
cache Index_Invalidate_I,(t1) /* invalidate each I-cache line */
bnel t1,t2,2b /* do this by index so that */
addu t1,t1,t3 /* a hit is not required */
and t1,t0,CFG_DCMASK /* repeat for D-cache with writeback */
srl t1,t1,CFG_DCSHIFT
li t2,(1<<12)
sllv t2,t2,t1
and t1,t0,CFG_DBMASK
bne t1,zero,3f
addiu t3,zero,32
addiu t3,zero,16
3:
la t1,K0BASE
addu t2,t2,t1
subu t2,t2,t3
4:
cache Index_Writeback_Inv_D,(t1)
bnel t1,t2,4b
addu t1,t1,t3
.eject
/*
* Now restore the registers. Note that they may
* have been modified while within the debugger.
* Start with even-numbered floating point registers.
*/
la k0,registers
ldc1 $0,8*F0(k0)
ldc1 $2,8*F2(k0)
ldc1 $4,8*F4(k0)
ldc1 $6,8*F6(k0)
ldc1 $8,8*F8(k0)
ldc1 $10,8*F10(k0)
ldc1 $12,8*F12(k0)
ldc1 $14,8*F14(k0)
ldc1 $16,8*F16(k0)
ldc1 $18,8*F18(k0)
ldc1 $20,8*F20(k0)
ldc1 $22,8*F22(k0)
ldc1 $24,8*F24(k0)
ldc1 $26,8*F26(k0)
ldc1 $28,8*F28(k0)
ldc1 $30,8*F30(k0)
/*
* If they are enabled, restore the odd-numbered
* floating point registers as well.
*/
mfc0 k1,C0_STATUS
li at,SR_FR
and k1,at
beq k1,zero,1f
nop
ldc1 $1,8*F1(k0)
ldc1 $3,8*F3(k0)
ldc1 $5,8*F5(k0)
ldc1 $7,8*F7(k0)
ldc1 $9,8*F9(k0)
ldc1 $11,8*F11(k0)
ldc1 $13,8*F13(k0)
ldc1 $15,8*F15(k0)
ldc1 $17,8*F17(k0)
ldc1 $19,8*F19(k0)
ldc1 $21,8*F21(k0)
ldc1 $23,8*F23(k0)
ldc1 $25,8*F25(k0)
ldc1 $27,8*F27(k0)
ldc1 $29,8*F29(k0)
ldc1 $31,8*F31(k0)
1:
.eject
/*
* Restore the floating point control & status register.
* FIRR is not restored because it is read-only.
*/
ld k1,8*FCSR(k0)
ctc1 k1,C1_CSR
/*
* Restore LO, HI, and the general registers.
*/
ld k1,8*LO(k0)
mtlo k1
ld k1,8*HI(k0)
mthi k1
/* zero is hard-wired */
ld at,8*AT(k0)
ld v0,8*V0(k0)
ld v1,8*V1(k0)
ld a0,8*A0(k0)
ld a1,8*A1(k0)
ld a2,8*A2(k0)
ld a3,8*A3(k0)
ld t0,8*T0(k0)
ld t1,8*T1(k0)
ld t2,8*T2(k0)
ld t3,8*T3(k0)
ld t4,8*T4(k0)
ld t5,8*T5(k0)
ld t6,8*T6(k0)
ld t7,8*T7(k0)
ld s0,8*S0(k0)
ld s1,8*S1(k0)
ld s2,8*S2(k0)
ld s3,8*S3(k0)
ld s4,8*S4(k0)
ld s5,8*S5(k0)
ld s6,8*S6(k0)
ld s7,8*S7(k0)
ld t8,8*T8(k0)
ld t9,8*T9(k0)
/* k0 is not restored */
/* k1 is not restored */
ld gp,8*GP(k0)
ld sp,8*SP(k0)
ld s8,8*S8(k0)
ld ra,8*RA(k0)
.eject
/*
* Restore the cause register, the status register, and the PC. Note
* that the saved PC is loaded into the ErrorEPC if ERL is set in the
* status register image and is loaded into the EPC otherwise.
*/
ld k1,8*CAUSE(k0)
mtc0 k1,C0_CAUSE
ld k1,8*SR(k0)
mtc0 k1,C0_STATUS
andi k1,k1,SR_ERL
beq k1,zero,1f
ld k1,8*PC(k0)
#if !defined(FORCE_PC_TO_32_BITS)
b 2f
dmtc0 k1,C0_ERROREPC
1:
dmtc0 k1,C0_EPC
2:
#else
addu k1,k1,zero
b 2f
dmtc0 k1,C0_ERROREPC
1:
addu k1,k1,zero
dmtc0 k1,C0_EPC
2:
#endif
/*
* Flush the write buffer to memory.
*/
sync
/*
* Hide the contents of k0 & k1
* and return to the user program.
*/
move k0,zero
move k1,zero
eret
.eject
/*
* char getDebugChar (void);
*/
.set reorder
.globl getDebugChar
.ent getDebugChar
getDebugChar:
la t0,ISA_IO_BASE /* point to ISA slot I/O */
1:
lbu t1,LINE_STS_COM1(t0) /* read line status register */
and t1,RX_CHAR_AVA /* isolate RX status bit */
beqz t1,1b /* loop until char is available */
lbu v0,DATA_REG_COM1(t0) /* read the character */
j ra /* and return */
.end getDebugChar
/*
* void putDebugChar (char);
*/
.set reorder
.globl putDebugChar
.ent putDebugChar
putDebugChar:
la t0,ISA_IO_BASE /* point to ISA slot I/O */
1:
lbu t1,LINE_STS_COM1(t0) /* read line status register */
and t1,TX_BUF_EMPTY /* isolate TX status bit */
beqz t1,1b /* loop while buffer is full */
sb a0,DATA_REG_COM1(t0) /* write the outgoing character */
sync /* flush the write buffer to memory */
j ra /* and return */
.end putDebugChar