mirror of
https://github.com/Rockbox/rockbox.git
synced 2026-04-11 16:37:45 -04:00
Nuke GDB stub
It looks like the GDB stub only ever worked for the Archos Recorder and iRiver IFP-7xx, neither of which are in-tree any more. Change-Id: If1910675b88b4707d26df9bc095818902af2d25b
This commit is contained in:
parent
2429e117d0
commit
78542df466
10 changed files with 15 additions and 1071 deletions
|
|
@ -13,12 +13,6 @@ OUTPUT_FORMAT(elf32-littlemips)
|
|||
#error Unknown CPU architecture
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
#define STUBOFFSET 0x10000
|
||||
#else
|
||||
#define STUBOFFSET 0
|
||||
#endif
|
||||
|
||||
#if defined(CPU_PP)
|
||||
#ifdef CPU_PP502x
|
||||
#define NOCACHE_BASE 0x10000000
|
||||
|
|
@ -31,7 +25,7 @@ OUTPUT_FORMAT(elf32-littlemips)
|
|||
#if CONFIG_CPU==IMX31L
|
||||
/* No fudges! */
|
||||
#include "imx31l.h"
|
||||
#define DRAMSIZE ((MEMORYSIZE * 0x100000) - STUBOFFSET - PLUGIN_BUFFER_SIZE \
|
||||
#define DRAMSIZE ((MEMORYSIZE * 0x100000) - PLUGIN_BUFFER_SIZE \
|
||||
- CODEC_SIZE - QHARRAY_SIZE - FRAME_SIZE - TTB_SIZE)
|
||||
|
||||
#elif CONFIG_CPU==DM320
|
||||
|
|
@ -56,25 +50,25 @@ OUTPUT_FORMAT(elf32-littlemips)
|
|||
#define LCD_TTB_AREA (TTB_SIZE + LCD_BUFFER_SIZE)
|
||||
#endif
|
||||
|
||||
#define DRAMSIZE (MEMORYSIZE * 0x100000) - STUBOFFSET - PLUGIN_BUFFER_SIZE - CODEC_SIZE - LCD_TTB_AREA
|
||||
#define DRAMSIZE (MEMORYSIZE * 0x100000) - PLUGIN_BUFFER_SIZE - CODEC_SIZE - LCD_TTB_AREA
|
||||
|
||||
#elif CONFIG_CPU==S3C2440
|
||||
#include "cpu.h"
|
||||
/* must be 16Kb (0x4000) aligned */
|
||||
#define TTB_SIZE (0x4000)
|
||||
#define DRAMSIZE (MEMORYSIZE * 0x100000) - STUBOFFSET - PLUGIN_BUFFER_SIZE - CODEC_SIZE - LCD_BUFFER_SIZE - TTB_SIZE
|
||||
#define DRAMSIZE (MEMORYSIZE * 0x100000) - PLUGIN_BUFFER_SIZE - CODEC_SIZE - LCD_BUFFER_SIZE - TTB_SIZE
|
||||
|
||||
#elif CONFIG_CPU==TCC7801
|
||||
#include "cpu.h"
|
||||
#define DRAMSIZE (MEMORYSIZE * 0x100000) - STUBOFFSET - PLUGIN_BUFFER_SIZE - CODEC_SIZE - TTB_SIZE
|
||||
#define DRAMSIZE (MEMORYSIZE * 0x100000) - PLUGIN_BUFFER_SIZE - CODEC_SIZE - TTB_SIZE
|
||||
|
||||
#elif CONFIG_CPU==AS3525 || CONFIG_CPU==AS3525v2
|
||||
#include "cpu.h"
|
||||
#define DRAMORIG DRAM_ORIG
|
||||
#if defined(AMS_LOWMEM) || (CONFIG_CPU == AS3525v2)
|
||||
#define DRAMSIZE (DRAM_SIZE - PLUGIN_BUFFER_SIZE - STUBOFFSET - TTB_SIZE)
|
||||
#define DRAMSIZE (DRAM_SIZE - PLUGIN_BUFFER_SIZE - TTB_SIZE)
|
||||
#else
|
||||
#define DRAMSIZE (DRAM_SIZE - PLUGIN_BUFFER_SIZE - STUBOFFSET - CODEC_SIZE - TTB_SIZE)
|
||||
#define DRAMSIZE (DRAM_SIZE - PLUGIN_BUFFER_SIZE - CODEC_SIZE - TTB_SIZE)
|
||||
#endif
|
||||
#elif CONFIG_CPU==S5L8702 || CONFIG_CPU==S5L8720
|
||||
#define ASM
|
||||
|
|
@ -85,13 +79,12 @@ OUTPUT_FORMAT(elf32-littlemips)
|
|||
#define DRAMSIZE (DRAM_SIZE - PLUGIN_BUFFER_SIZE - CODEC_SIZE - FRAME_SIZE - TTB_SIZE)
|
||||
#elif CONFIG_CPU==X1000
|
||||
#include "cpu.h"
|
||||
#undef STUBOFFSET
|
||||
#define DRAMSIZE (X1000_DRAM_SIZE - PLUGIN_BUFFER_SIZE - CODEC_SIZE)
|
||||
#endif
|
||||
|
||||
/* default to full RAM (minus codecs&plugins) unless specified otherwise */
|
||||
#ifndef DRAMSIZE
|
||||
#define DRAMSIZE (MEMORYSIZE * 0x100000) - PLUGIN_BUFFER_SIZE - STUBOFFSET - CODEC_SIZE
|
||||
#define DRAMSIZE (MEMORYSIZE * 0x100000) - PLUGIN_BUFFER_SIZE - CODEC_SIZE
|
||||
#endif
|
||||
|
||||
/* MCF5249 have 96KB of IRAM */
|
||||
|
|
@ -119,17 +112,17 @@ OUTPUT_FORMAT(elf32-littlemips)
|
|||
#define IRAMSIZE 0x0c000
|
||||
|
||||
#elif CONFIG_CPU == PNX0101
|
||||
#define DRAMORIG 0xc00000 + STUBOFFSET
|
||||
#define DRAMORIG 0xc00000
|
||||
#define IRAMORIG 0x407000
|
||||
#define IRAMSIZE 0x9000
|
||||
|
||||
#elif CONFIG_CPU == IMX31L || CONFIG_CPU == S3C2440
|
||||
#define DRAMORIG 0x0 + STUBOFFSET
|
||||
#define DRAMORIG 0x0
|
||||
#define IRAM DRAM
|
||||
#define IRAMSIZE 0
|
||||
|
||||
#elif CONFIG_CPU==DM320
|
||||
#define DRAMORIG CONFIG_SDRAM_START + STUBOFFSET
|
||||
#define DRAMORIG CONFIG_SDRAM_START
|
||||
#define IRAM DRAM
|
||||
/* The bit of IRAM that is available is used in the core */
|
||||
#define IRAMSIZE 0
|
||||
|
|
@ -181,13 +174,7 @@ OUTPUT_FORMAT(elf32-littlemips)
|
|||
#define IRAMSIZE (136*1024)
|
||||
|
||||
#elif CONFIG_CPU == JZ4732 || CONFIG_CPU == JZ4760B
|
||||
#undef STUBOFFSET
|
||||
#ifdef DEBUG
|
||||
#define STUBOFFSET 0x14000
|
||||
#else
|
||||
#define STUBOFFSET 0x4000
|
||||
#endif
|
||||
#define DRAMORIG 0x80000000 + STUBOFFSET
|
||||
#define DRAMORIG 0x80004000
|
||||
#define IRAM DRAM
|
||||
#define IRAMSIZE 0
|
||||
/* The bit of IRAM that is available is used in the core */
|
||||
|
|
@ -210,7 +197,7 @@ OUTPUT_FORMAT(elf32-littlemips)
|
|||
#define IRAMSIZE 0
|
||||
|
||||
#else
|
||||
#define DRAMORIG 0x09000000 + STUBOFFSET
|
||||
#define DRAMORIG 0x09000000
|
||||
#endif
|
||||
|
||||
#ifndef NOCACHE_BASE
|
||||
|
|
|
|||
|
|
@ -1178,10 +1178,6 @@ target/coldfire/iaudio/audio-iaudio.c
|
|||
#endif
|
||||
#endif /* IAUDIO_M3 */
|
||||
|
||||
#ifdef STUB
|
||||
libc/sscanf.c
|
||||
#endif /* STUB */
|
||||
|
||||
#if defined(IRIVER_H300_SERIES) || defined(IRIVER_H100_SERIES)
|
||||
target/coldfire/iriver/ata-iriver.c
|
||||
target/coldfire/iriver/lcd-remote-iriver.c
|
||||
|
|
|
|||
|
|
@ -179,8 +179,6 @@ copied_start:
|
|||
mcr p15, 0, r0, c7, c6, 0 /* Invalidate Dcache */
|
||||
mcr p15, 0, r1, c8, c7, 0 /* Invalidate TLB */
|
||||
|
||||
#ifndef STUB
|
||||
|
||||
/* Copy exception handler code to address 0 */
|
||||
mov r2, #0x0
|
||||
ldr r3, =vectors_start
|
||||
|
|
@ -231,7 +229,6 @@ copied_start:
|
|||
strhi r5, [r3], #4
|
||||
bhi 1b
|
||||
#endif /* !BOOTLOADER */
|
||||
#endif /* !STUB */
|
||||
|
||||
/* Initialise bss section to zero */
|
||||
ldr r2, =_edata
|
||||
|
|
|
|||
|
|
@ -9,12 +9,10 @@ STARTUP(target/mips/ingenic_jz47xx/crt0.o)
|
|||
INPUT(target/mips/exception-mips.o)
|
||||
INPUT(target/mips/system-mips.o)
|
||||
|
||||
#define STUBOFFSET 0x4000
|
||||
|
||||
#define DRAMORIG (0x80000000 + STUBOFFSET)
|
||||
#define DRAMSIZE (MEMORYSIZE * 0x100000 - STUBOFFSET)
|
||||
#define IRAMORIG 0x80000000
|
||||
#define IRAMSIZE 16K
|
||||
#define IRAMSIZE 0x4000
|
||||
#define DRAMORIG (IRAMORIG + IRAMSIZE)
|
||||
#define DRAMSIZE (MEMORYSIZE * 0x100000 - IRAMSIZE)
|
||||
|
||||
/* End of the audio buffer, where the codec buffer starts */
|
||||
#define ENDAUDIOADDR (DRAMORIG + DRAMSIZE - PLUGIN_BUFFER_SIZE - CODEC_SIZE)
|
||||
|
|
|
|||
64
gdb/Makefile
64
gdb/Makefile
|
|
@ -1,64 +0,0 @@
|
|||
# __________ __ ___.
|
||||
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
# \/ \/ \/ \/ \/
|
||||
# $Id$
|
||||
#
|
||||
|
||||
ifeq ($(MODELNAME),EXAMPLE)
|
||||
|
||||
INCLUDES= -I$(FIRMDIR)/include -I$(FIRMDIR)/export -I. -I$(OBJDIR) \
|
||||
-I$(BUILDDIR)
|
||||
|
||||
DEPFILE = $(OBJDIR)/dep-stub
|
||||
LDS := linker.cfg
|
||||
|
||||
SRC := $(shell cat SOURCES | $(CC) -DMEMORYSIZE=$(MEMORYSIZE) $(INCLUDES) $(TARGET) $(DEFINES) -E -P -include "config.h" - )
|
||||
DIRS = .
|
||||
|
||||
ifdef APPEXTRA
|
||||
DIRS += $(subst :, ,$(APPEXTRA))
|
||||
INCLUDES += $(patsubst %,-I%,$(subst :, ,$(APPEXTRA)))
|
||||
endif
|
||||
|
||||
ifndef VERSION
|
||||
VERSION=$(shell date +%y%m%d-%H%M)
|
||||
endif
|
||||
|
||||
CFLAGS = $(GCCOPTS) $(INCLUDES) $(TARGET) $(DEFINES) \
|
||||
$(EXTRA_DEFINES) -DMEM=${MEMORYSIZE}
|
||||
|
||||
OBJS := $(SRC:%.c=$(OBJDIR)/%.o)
|
||||
SOURCES = $(SRC)
|
||||
LINKFILE = $(OBJDIR)/linkage.lds
|
||||
|
||||
LIBROCKBOX = $(BUILDDIR)/librockbox.a
|
||||
|
||||
all: $(BUILDDIR)/$(BINARY) $(FLASHFILE)
|
||||
|
||||
dep: $(DEPFILE)
|
||||
|
||||
$(LINKFILE): $(LDS)
|
||||
$(call PRINTS,Build $(@F))cat $< | $(CC) -DMEMORYSIZE=$(MEMORYSIZE) $(INCLUDES) $(TARGET) $(DEFINES) -E -P $(ROMBUILD) - >$@
|
||||
|
||||
$(OBJDIR)/stub.elf : $(OBJS) $(LINKFILE) $(DEPFILE) $(LIBROCKBOX)
|
||||
$(call PRINTS,LD $(@F))$(CC) $(GCCOPTS) -Os -nostdlib -o $@ $(OBJS) -L$(BUILDDIR) -L$(BUILDDIR)/firmware -lrockbox -lgcc -T$(LINKFILE) -Wl,-Map,$(OBJDIR)/stub.map
|
||||
|
||||
$(OBJDIR)/stub.bin : $(OBJDIR)/stub.elf
|
||||
$(call PRINTS,OBJCOPY $(@F))$(OC) -O binary $< $@
|
||||
|
||||
$(BUILDDIR)/$(BINARY) : $(OBJDIR)/stub.bin
|
||||
$(call PRINTS,Build stub file)$(MKFIRMWARE) $< $@
|
||||
|
||||
include $(TOOLSDIR)/make.inc
|
||||
|
||||
clean:
|
||||
$(call PRINTS,cleaning stub)-rm -f $(OBJS) $(BUILDDIR)/$(BINARY) \
|
||||
$(OBJDIR)/stub.bin $(OBJDIR)/stub.elf $(OBJDIR)/*.map \
|
||||
$(LINKFILE) $(DEPFILE)
|
||||
|
||||
-include $(DEPFILE)
|
||||
|
||||
endif
|
||||
95
gdb/README
95
gdb/README
|
|
@ -1,95 +0,0 @@
|
|||
--------------------------------------------------------------------
|
||||
__________ __ ___.
|
||||
Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
\/ \/ \/ \/ \/
|
||||
$Id$
|
||||
|
||||
Copyright (C) 2002 by Linus Nielsen Feltzing
|
||||
|
||||
--------------------------------------------------------------------
|
||||
|
||||
Debugging the Archos Jukebox
|
||||
----------------------------
|
||||
|
||||
To debug using the serial port on the Jukebox, you need to do the following:
|
||||
|
||||
1) Connect the serial port to the PC. This is best done with the "serial
|
||||
port mod" described on the home page, along with a serial port converter
|
||||
for the 3V signals from the Jukebox.
|
||||
|
||||
2) Build or download a GDB SH1 cross debugger
|
||||
|
||||
3) Compile the GDB stub from the CVS "gdb" archive
|
||||
For Player models, just type:
|
||||
# make
|
||||
|
||||
For Recorder, type
|
||||
#make RECORDER=1
|
||||
|
||||
4) Copy the newly built ARCHOS.MOD to the Jukebox.
|
||||
|
||||
5) Start the Jukebox and fire up the GDB with the elf file you want to debug
|
||||
as an argument along with the baud rate:
|
||||
|
||||
For Player:
|
||||
# sh-elf-gdb -b 38400 test.elf
|
||||
|
||||
For Recorder:
|
||||
# sh-elf-gdb -b 115200 test.elf
|
||||
|
||||
6) In GDB, type:
|
||||
|
||||
(gdb) target remote /dev/ttyS0
|
||||
|
||||
/dev/ttyS0 is the serial port you want to use. I guess Windows users
|
||||
would type COM1 or something like that.
|
||||
|
||||
GDB should answer with a message like:
|
||||
|
||||
Remote debugging using /dev/ttyS0
|
||||
0x090014b6 in ?? ()
|
||||
(gdb)
|
||||
|
||||
7) Load the code from the elf file you specified on the command line:
|
||||
|
||||
(gdb) load
|
||||
|
||||
GDB should answer like this:
|
||||
|
||||
Loading section .text, size 0x6b00 lma 0x9018000
|
||||
Loading section .data, size 0x738 lma 0x901eb00
|
||||
Start address 0x9018290, load size 29240
|
||||
Transfer rate: 11696 bits/sec, 102 bytes/write.
|
||||
(gdb)
|
||||
|
||||
8) You're set. Now try to set a breakpoint and run:
|
||||
|
||||
(gdb) b main
|
||||
Breakpoint 1 at 0x9011b2a: file main.c, line 192.
|
||||
(gdb) c
|
||||
Continuing.
|
||||
|
||||
Breakpoint 1, main () at main.c:192
|
||||
192 app_main();
|
||||
(gdb)
|
||||
|
||||
Good luck!
|
||||
|
||||
|
||||
Technical details:
|
||||
|
||||
As for now, the GDB stub occupies the memory from 0x900000 up to
|
||||
0x9018000.
|
||||
|
||||
Compile and link your test program at 0x9018000 and up, and it will work.
|
||||
|
||||
The baud rate is 38400 for Player, 115200 for Recorder, and the settings
|
||||
are 8N1.
|
||||
|
||||
Note that you may have to change the ATA I/O address in the ATA_CONTROL
|
||||
macro in sh-stub.c. go to Menu->Debug (keep out)->View HW info to find out.
|
||||
|
||||
Linus Nielsen Feltzing
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
#ifdef CPU_ARM
|
||||
arm-stub.c
|
||||
#endif
|
||||
716
gdb/arm-stub.c
716
gdb/arm-stub.c
|
|
@ -1,716 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2006 by Tomasz Malesinski
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "sscanf.h"
|
||||
#include "gdb_api.h"
|
||||
|
||||
#define BUFMAX 1024
|
||||
|
||||
#define VEC_UND 1
|
||||
#define VEC_SWI 2
|
||||
#define VEC_PABT 3
|
||||
#define VEC_DABT 4
|
||||
|
||||
static char packet_buf[BUFMAX];
|
||||
static char reply_buf[BUFMAX];
|
||||
|
||||
static const char hexchars[] = "0123456789abcdef";
|
||||
static int gdb_exception_no, gdb_mem_access;
|
||||
static unsigned char watchdog_enabled;
|
||||
static unsigned long registers[17];
|
||||
|
||||
void gdb_api_breakpoint(void);
|
||||
static void gdb_api_log(char *msg);
|
||||
|
||||
__attribute__((section(".gdbapi"))) struct gdb_api gdb_api =
|
||||
{
|
||||
GDB_API_MAGIC,
|
||||
{gdb_api_breakpoint, gdb_api_log}
|
||||
};
|
||||
|
||||
static void watchdog_enable(int on)
|
||||
{
|
||||
(*(volatile unsigned long *)0x80002804) = on;
|
||||
watchdog_enabled = on;
|
||||
}
|
||||
|
||||
static void watchdog_service(void)
|
||||
{
|
||||
if (watchdog_enabled)
|
||||
{
|
||||
(*(volatile unsigned long *)0x80002804) = 0;
|
||||
(*(volatile unsigned long *)0x80002808) = 0;
|
||||
(*(volatile unsigned long *)0x80002804) = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool isxdigit(char c)
|
||||
{
|
||||
return ((c >= '0') && (c <= '9'))
|
||||
|| ((c >= 'a') && (c <= 'f')) || ((c >= 'A') && (c <= 'F'));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static void hex_byte(char *s, int byte) {
|
||||
s[0] = hexchars[(byte >> 4) & 0xf];
|
||||
s[1] = hexchars[byte & 0xf];
|
||||
}
|
||||
|
||||
static void hex_word(char *s, unsigned long val) {
|
||||
int i;
|
||||
for (i = 0; i < 4; i++)
|
||||
hex_byte(s + i * 2, (val >> (i * 8)) & 0xff);
|
||||
}
|
||||
|
||||
static void hex_string(char *d, char *s) {
|
||||
while (*s) {
|
||||
hex_byte(d, *s++);
|
||||
d += 2;
|
||||
}
|
||||
*d = 0;
|
||||
}
|
||||
|
||||
static int get_hex_byte(char *s) {
|
||||
return (hex(s[0]) << 4) + hex(s[1]);
|
||||
}
|
||||
|
||||
static unsigned long get_hex_word(char *s) {
|
||||
int i;
|
||||
unsigned long r = 0;
|
||||
for (i = 3; i >= 0; i--)
|
||||
r = (r << 8) + get_hex_byte(s + i * 2);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void reply_error(int n, char *reply) {
|
||||
reply[0] = 'E';
|
||||
hex_byte(reply + 1, n);
|
||||
reply[3] = 0;
|
||||
}
|
||||
|
||||
static void reply_signal(int n, char *reply) {
|
||||
int signal;
|
||||
reply[0] = 'S';
|
||||
switch (n)
|
||||
{
|
||||
case VEC_UND:
|
||||
signal = 4;
|
||||
break;
|
||||
case VEC_PABT:
|
||||
case VEC_DABT:
|
||||
signal = 7;
|
||||
break;
|
||||
default:
|
||||
signal = 5;
|
||||
break;
|
||||
}
|
||||
hex_byte(reply + 1, signal);
|
||||
reply[3] = 0;
|
||||
}
|
||||
|
||||
static void reply_ok(char *reply) {
|
||||
strcpy(reply, "OK");
|
||||
}
|
||||
|
||||
static int get_byte(void) {
|
||||
int b;
|
||||
while ((b = usb_serial_try_get_byte()) < 0)
|
||||
watchdog_service();
|
||||
watchdog_service();
|
||||
return b;
|
||||
}
|
||||
|
||||
static void put_byte(unsigned char ch) {
|
||||
while (usb_serial_try_put_byte(ch) < 0)
|
||||
watchdog_service();
|
||||
watchdog_service();
|
||||
}
|
||||
|
||||
static void serial_write(unsigned char *buf, int len) {
|
||||
int i;
|
||||
for (i = 0; i < len; i++)
|
||||
put_byte(buf[i]);
|
||||
}
|
||||
|
||||
static void get_packet(char *buf, int len) {
|
||||
int count, checksum, escaped;
|
||||
int ch;
|
||||
|
||||
while (1) {
|
||||
do {
|
||||
ch = get_byte();
|
||||
} while (ch != '$');
|
||||
|
||||
checksum = 0;
|
||||
count = 0;
|
||||
escaped = 0;
|
||||
while (count < len) {
|
||||
ch = get_byte();
|
||||
if (!escaped) {
|
||||
if (ch == '$') {
|
||||
checksum = 0;
|
||||
count = 0;
|
||||
} else if (ch == '#')
|
||||
break;
|
||||
else if (ch == 0x7d) {
|
||||
escaped = 1;
|
||||
checksum += ch;
|
||||
} else {
|
||||
checksum += ch;
|
||||
buf[count] = ch;
|
||||
count++;
|
||||
}
|
||||
} else {
|
||||
escaped = 0;
|
||||
checksum += ch;
|
||||
buf[count] = ch ^ 0x20;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
buf[count] = 0;
|
||||
|
||||
if (ch == '#') {
|
||||
int rchksum;
|
||||
|
||||
ch = get_byte();
|
||||
rchksum = hex(ch) << 4;
|
||||
ch = get_byte();
|
||||
rchksum += hex(ch);
|
||||
|
||||
if ((checksum & 0xff) != rchksum)
|
||||
put_byte('-');
|
||||
else {
|
||||
put_byte('+');
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void put_packet(char *buf) {
|
||||
int i, checksum;
|
||||
int ch;
|
||||
char tmp[3];
|
||||
|
||||
do {
|
||||
put_byte('$');
|
||||
|
||||
checksum = 0;
|
||||
for (i = 0; buf[i]; i++)
|
||||
checksum += buf[i];
|
||||
|
||||
serial_write(buf, i);
|
||||
|
||||
tmp[0] = '#';
|
||||
hex_byte(tmp + 1, checksum & 0xff);
|
||||
serial_write(tmp, 3);
|
||||
|
||||
ch = get_byte();
|
||||
|
||||
} while (ch != '+');
|
||||
}
|
||||
|
||||
static inline unsigned long get_general_reg(int n)
|
||||
{
|
||||
return registers[n + 1];
|
||||
}
|
||||
|
||||
static inline void set_general_reg(int n, unsigned long v)
|
||||
{
|
||||
registers[n + 1] = v;
|
||||
}
|
||||
|
||||
static inline unsigned long get_cpsr(void)
|
||||
{
|
||||
return registers[0];
|
||||
}
|
||||
|
||||
static inline void set_cpsr(unsigned long v)
|
||||
{
|
||||
registers[0] = v;
|
||||
}
|
||||
|
||||
static void g_reply(char *buf) {
|
||||
int i;
|
||||
char *p;
|
||||
|
||||
p = buf;
|
||||
for (i = 0; i < 16; i++) {
|
||||
hex_word(p, get_general_reg(i));
|
||||
p += 8;
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
memset(p, '0', 16);
|
||||
p += 16;
|
||||
}
|
||||
|
||||
hex_word(p, 0);
|
||||
p += 8;
|
||||
hex_word(p, get_cpsr());
|
||||
p[8] = 0;
|
||||
}
|
||||
|
||||
static void cmd_get_register(char *args, char *reply) {
|
||||
int r;
|
||||
|
||||
if (sscanf(args, "%x", &r) != 1) {
|
||||
reply_error(0, reply);
|
||||
return;
|
||||
}
|
||||
|
||||
if (r >= 0 && r < 16) {
|
||||
hex_word(reply, get_general_reg(r));
|
||||
reply[8] = 0;
|
||||
} else if (r == 25) {
|
||||
hex_word(reply, get_cpsr());
|
||||
reply[8] = 0;
|
||||
} else {
|
||||
hex_word(reply, 0);
|
||||
reply[8] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void cmd_set_register(char *args, char *reply) {
|
||||
int r, p;
|
||||
unsigned long v;
|
||||
|
||||
p = -1;
|
||||
sscanf(args, "%x=%n", &r, &p);
|
||||
if (p == -1) {
|
||||
reply_error(0, reply);
|
||||
return;
|
||||
}
|
||||
|
||||
v = get_hex_word(args + p);
|
||||
if (r >= 0 && r < 16)
|
||||
set_general_reg(r, v);
|
||||
else if (r == 25)
|
||||
set_cpsr(v);
|
||||
reply_ok(reply);
|
||||
}
|
||||
|
||||
static void cmd_set_registers(char *args, char *reply) {
|
||||
char *p;
|
||||
int i, len;
|
||||
|
||||
len = strlen(args);
|
||||
|
||||
p = args;
|
||||
for (i = 0; i < 16 && len >= (i + 1) * 8; i++) {
|
||||
set_general_reg(i, get_hex_word(p));
|
||||
p += 8;
|
||||
}
|
||||
|
||||
if (len >= 16 * 8 + 8 * 16 + 2 * 8)
|
||||
{
|
||||
p += 8 * 16 + 8;
|
||||
set_cpsr(get_hex_word(p));
|
||||
}
|
||||
|
||||
reply_ok(reply);
|
||||
}
|
||||
|
||||
static void cmd_get_memory(char *args, char *reply) {
|
||||
unsigned long addr, len, i;
|
||||
|
||||
if (sscanf(args, "%lx,%lx", &addr, &len) != 2) {
|
||||
reply_error(0, reply);
|
||||
return;
|
||||
}
|
||||
|
||||
if (len > (BUFMAX - 16) / 2) {
|
||||
reply_error(1, reply);
|
||||
return;
|
||||
}
|
||||
|
||||
gdb_mem_access = 1;
|
||||
for (i = 0; i < len; i++)
|
||||
hex_byte(reply + i * 2, *((unsigned char *)(addr + i)));
|
||||
gdb_mem_access = 0;
|
||||
|
||||
reply[len * 2] = 0;
|
||||
}
|
||||
|
||||
static void cmd_put_memory(char *args, char *reply) {
|
||||
unsigned long addr, len, i;
|
||||
int pos;
|
||||
|
||||
pos = -1;
|
||||
sscanf(args, "%lx,%lx:%n", &addr, &len, &pos);
|
||||
if (pos == -1) {
|
||||
reply_error(0, reply);
|
||||
return;
|
||||
}
|
||||
|
||||
gdb_mem_access = 1;
|
||||
for (i = 0; i < len; i++)
|
||||
*((unsigned char *)(addr + i)) = get_hex_byte(args + pos + i * 2);
|
||||
gdb_mem_access = 0;
|
||||
|
||||
reply_ok(reply);
|
||||
}
|
||||
|
||||
static void cmd_put_memory_binary(char *args, char *reply) {
|
||||
unsigned long addr, len, i;
|
||||
int pos;
|
||||
|
||||
pos = -1;
|
||||
sscanf(args, "%lx,%lx:%n", &addr, &len, &pos);
|
||||
if (pos == -1) {
|
||||
reply_error(0, reply);
|
||||
return;
|
||||
}
|
||||
|
||||
gdb_mem_access = 1;
|
||||
for (i = 0; i < len; i++)
|
||||
*((unsigned char *)(addr + i)) = args[pos + i];
|
||||
gdb_mem_access = 0;
|
||||
|
||||
reply_ok(reply);
|
||||
}
|
||||
|
||||
static void parse_continue_args(char *args) {
|
||||
int sig;
|
||||
unsigned long addr;
|
||||
|
||||
if (sscanf(args, "%x;%lx", &sig, &addr) == 2) {
|
||||
set_general_reg(15, addr);
|
||||
} else if (sscanf(args, "%lx", &addr) == 1) {
|
||||
set_general_reg(15, addr);
|
||||
}
|
||||
}
|
||||
|
||||
static void cmd_go(char *args) {
|
||||
parse_continue_args(args);
|
||||
|
||||
asm volatile(
|
||||
" mov r1, %0\n"
|
||||
" ldr r12, [r1], #4\n"
|
||||
" mov r0, r12\n"
|
||||
" and r0, r0, #0x1f\n"
|
||||
" cmp r0, #0x10\n"
|
||||
" bne 1f\n"
|
||||
" ldr r14, [r1, #60]\n"
|
||||
" msr spsr_fsxc, r12\n"
|
||||
" ldmia r1, {r0-r14}^\n"
|
||||
" movs r15, r14\n"
|
||||
"1:\n"
|
||||
" msr cpsr_fsxc, r12\n"
|
||||
" ldmia r1, {r0-r15}\n"
|
||||
: : "r" (registers));
|
||||
}
|
||||
|
||||
static void remote_cmd(char *cmd, char *reply) {
|
||||
int i, err;
|
||||
i = 0;
|
||||
err = 0;
|
||||
while ((cmd[i] >= 'a' && cmd[i] <= 'z') || cmd[i] == '_')
|
||||
i++;
|
||||
if (!strncmp(cmd, "reboot", i))
|
||||
{
|
||||
reply_ok(reply);
|
||||
put_packet(reply);
|
||||
watchdog_enable(1);
|
||||
(*(volatile unsigned long *)0x80002804) = 1;
|
||||
while (1);
|
||||
}
|
||||
else if (!strncmp(cmd, "power_off", i))
|
||||
{
|
||||
reply_ok(reply);
|
||||
put_packet(reply);
|
||||
GPIO1_CLR = 1 << 16;
|
||||
GPIO2_SET = 1;
|
||||
while (1);
|
||||
}
|
||||
else if (!strncmp(cmd, "watchdog", i))
|
||||
{
|
||||
int t;
|
||||
if (sscanf(cmd + i, "%d", &t) == 1)
|
||||
watchdog_enable(t != 0);
|
||||
else
|
||||
err = 1;
|
||||
reply_ok(reply);
|
||||
}
|
||||
else
|
||||
hex_string(reply, "Unrecognized command\n");
|
||||
if (err)
|
||||
reply_error(err, reply);
|
||||
}
|
||||
|
||||
static void cmd_query(char *args, char *reply) {
|
||||
if (!strncmp(args, "Rcmd,", 5)) {
|
||||
unsigned i = 0;
|
||||
char *s = args + 5;
|
||||
char cmd[200];
|
||||
while (isxdigit(s[0]) && isxdigit(s[1]) && i < sizeof(cmd) - 1) {
|
||||
cmd[i++] = get_hex_byte(s);
|
||||
s += 2;
|
||||
}
|
||||
cmd[i] = 0;
|
||||
remote_cmd(cmd, reply);
|
||||
} else
|
||||
reply[0] = 0;
|
||||
}
|
||||
|
||||
void gdb_loop(void) {
|
||||
int no_reply;
|
||||
|
||||
gdb_mem_access = 0;
|
||||
|
||||
while (1) {
|
||||
get_packet(packet_buf, sizeof(packet_buf) - 1);
|
||||
|
||||
no_reply = 0;
|
||||
switch (packet_buf[0]) {
|
||||
case '?':
|
||||
reply_signal(gdb_exception_no, reply_buf);
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
cmd_get_register(packet_buf + 1, reply_buf);
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
cmd_set_register(packet_buf + 1, reply_buf);
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
g_reply(reply_buf);
|
||||
break;
|
||||
|
||||
case 'G':
|
||||
cmd_set_registers(packet_buf + 1, reply_buf);
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
cmd_get_memory(packet_buf + 1, reply_buf);
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
cmd_put_memory(packet_buf + 1, reply_buf);
|
||||
break;
|
||||
|
||||
case 'X':
|
||||
cmd_put_memory_binary(packet_buf + 1, reply_buf);
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
cmd_query(packet_buf + 1, reply_buf);
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
cmd_go(packet_buf + 1);
|
||||
reply_error(1, reply_buf);
|
||||
break;
|
||||
|
||||
/* case 's': */
|
||||
/* cmd_go(packet_buf + 1); */
|
||||
/* break; */
|
||||
|
||||
default:
|
||||
reply_buf[0] = 0;
|
||||
}
|
||||
|
||||
if (!no_reply)
|
||||
put_packet(reply_buf);
|
||||
}
|
||||
}
|
||||
|
||||
extern void *vectors[];
|
||||
|
||||
static void gdb_set_vector(int n, void *p)
|
||||
{
|
||||
vectors[n] = p;
|
||||
}
|
||||
|
||||
void gdb_und_exc(void);
|
||||
void gdb_swi_exc(void);
|
||||
void gdb_pabt_exc(void);
|
||||
void gdb_dabt_exc(void);
|
||||
|
||||
static void gdb_set_vectors(void)
|
||||
{
|
||||
gdb_set_vector(VEC_UND, gdb_und_exc);
|
||||
gdb_set_vector(VEC_SWI, gdb_swi_exc);
|
||||
gdb_set_vector(VEC_PABT, gdb_pabt_exc);
|
||||
gdb_set_vector(VEC_DABT, gdb_dabt_exc);
|
||||
}
|
||||
|
||||
void gdb_loop_from_exc(void)
|
||||
{
|
||||
if (gdb_mem_access)
|
||||
reply_error(1, reply_buf);
|
||||
else
|
||||
reply_signal(gdb_exception_no, reply_buf);
|
||||
put_packet(reply_buf);
|
||||
gdb_loop();
|
||||
}
|
||||
|
||||
#define IRQ_REG(reg) (*(volatile unsigned long *)(0x80300000 + (reg)))
|
||||
|
||||
static inline unsigned long irq_read(int reg)
|
||||
{
|
||||
unsigned long v, v2;
|
||||
do
|
||||
{
|
||||
v = IRQ_REG(reg);
|
||||
v2 = IRQ_REG(reg);
|
||||
} while (v != v2);
|
||||
return v;
|
||||
}
|
||||
|
||||
#define IRQ_WRITE_WAIT(reg, val, cond) \
|
||||
do { unsigned long v, v2; \
|
||||
do { \
|
||||
IRQ_REG(reg) = (val); \
|
||||
v = IRQ_REG(reg); \
|
||||
v2 = IRQ_REG(reg); \
|
||||
} while ((v != v2) || !(cond)); \
|
||||
} while (0);
|
||||
|
||||
void fiq(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void system_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
watchdog_enable(0);
|
||||
|
||||
for (i = 0; i < 0x1c; i++)
|
||||
{
|
||||
IRQ_WRITE_WAIT(0x404 + i * 4, 0x1e000001, (v & 0x3010f) == 1);
|
||||
IRQ_WRITE_WAIT(0x404 + i * 4, 0x4000000, (v & 0x10000) == 0);
|
||||
IRQ_WRITE_WAIT(0x404 + i * 4, 0x10000001, (v & 0xf) == 1);
|
||||
}
|
||||
|
||||
GPIO3_CLR = 1;
|
||||
}
|
||||
|
||||
static void gdb_api_log(char *msg)
|
||||
{
|
||||
int i;
|
||||
|
||||
reply_buf[0] = 'O';
|
||||
i = 1;
|
||||
while (*msg && i + 2 <= BUFMAX - 1)
|
||||
{
|
||||
hex_byte(reply_buf + i, *msg++);
|
||||
i += 2;
|
||||
}
|
||||
reply_buf[i] = 0;
|
||||
put_packet(reply_buf);
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
system_init();
|
||||
usb_serial_init();
|
||||
gdb_mem_access = 0;
|
||||
gdb_set_vectors();
|
||||
gdb_api_breakpoint();
|
||||
while (1);
|
||||
}
|
||||
|
||||
#define str(s) #s
|
||||
#define xstr(s) str(s)
|
||||
|
||||
asm (".text\n"
|
||||
"gdb_und_exc:\n"
|
||||
" ldr sp, =_stub_stack\n"
|
||||
" sub r14, r14, #4\n"
|
||||
" stmfd sp!, {r0-r3, r12, r14}\n"
|
||||
" mov r0, #" xstr(VEC_UND) "\n"
|
||||
" b gdb_handle_exception\n"
|
||||
"gdb_swi_exc:\n"
|
||||
" ldr sp, =_stub_stack\n"
|
||||
" stmfd sp!, {r0-r3, r12, r14}\n"
|
||||
" mov r0, #" xstr(VEC_SWI) "\n"
|
||||
" b gdb_handle_exception\n"
|
||||
"gdb_pabt_exc:\n"
|
||||
" ldr sp, =_stub_stack\n"
|
||||
" stmfd sp!, {r0-r3, r12, r14}\n"
|
||||
" mov r0, #" xstr(VEC_PABT) "\n"
|
||||
" b gdb_handle_exception\n"
|
||||
"gdb_dabt_exc:\n"
|
||||
" ldr sp, =_stub_stack\n"
|
||||
" sub r14, r14, #4\n"
|
||||
" stmfd sp!, {r0-r3, r12, r14}\n"
|
||||
" ldr r0, =gdb_mem_access\n"
|
||||
" ldr r0, [r0]\n"
|
||||
" tst r0, r0\n"
|
||||
" bne gdb_data_abort\n"
|
||||
" mov r0, #" xstr(VEC_DABT) "\n"
|
||||
" b gdb_handle_exception\n"
|
||||
"gdb_handle_exception:\n"
|
||||
" ldr r1, =gdb_exception_no\n"
|
||||
" str r0, [r1]\n"
|
||||
" ldr r0, =registers\n"
|
||||
" mrs r12, spsr\n"
|
||||
" str r12, [r0], #4\n"
|
||||
" ldmfd sp!, {r2, r3}\n"
|
||||
" stmia r0!, {r2, r3}\n"
|
||||
" ldmfd sp!, {r2, r3, r12, r14}\n"
|
||||
" str r14, [r0, #52]\n"
|
||||
" stmia r0!, {r2-r12}\n"
|
||||
" mrs r1, spsr\n"
|
||||
" and r2, r1, #0x1f\n"
|
||||
" cmp r2, #0x10\n"
|
||||
" bne 1f\n"
|
||||
" stmia r0, {r13, r14}^\n"
|
||||
" b gdb_data_abort\n"
|
||||
"1:\n"
|
||||
" msr cpsr_c, r1\n"
|
||||
" stmia r0, {r13, r14}\n"
|
||||
"gdb_data_abort:\n"
|
||||
" msr cpsr_c, #0xd3\n"
|
||||
" ldr sp, =_stub_stack\n"
|
||||
" b gdb_loop_from_exc\n"
|
||||
"gdb_api_breakpoint:\n"
|
||||
" stmfd sp!, {r0-r1}\n"
|
||||
" ldr r0, =registers\n"
|
||||
" mrs r1, cpsr\n"
|
||||
" str r1, [r0], #4\n"
|
||||
" ldmfd sp!, {r1}\n"
|
||||
" str r1, [r0], #4\n"
|
||||
" ldmfd sp!, {r1}\n"
|
||||
" str r1, [r0], #4\n"
|
||||
" stmia r0!, {r2-r14}\n"
|
||||
" str r14, [r0]\n"
|
||||
" msr cpsr_c, #0xd3\n"
|
||||
" ldr sp, =_stub_stack\n"
|
||||
" ldr r0, =gdb_exception_no\n"
|
||||
" mov r1, #5\n"
|
||||
" str r1, [r0]\n"
|
||||
" b gdb_loop_from_exc\n");
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
#include "config.h"
|
||||
|
||||
#ifdef CPU_ARM
|
||||
ENTRY(start)
|
||||
STARTUP(crt0.o)
|
||||
OUTPUT_FORMAT(elf32-littlearm)
|
||||
#else
|
||||
#error "Unsupported CPU!"
|
||||
#endif
|
||||
|
||||
#ifdef EXAMPLE
|
||||
MEMORY
|
||||
{
|
||||
IRAM : ORIGIN = 0, LENGTH = 0x10000
|
||||
DRAM : ORIGIN = 0xc00000, LENGTH = 0x6000
|
||||
DRAM_API : ORIGIN = 0xc06000, LENGTH = 0x100
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text :
|
||||
{
|
||||
*(.init*)
|
||||
*(.text)
|
||||
*(.text*)
|
||||
*(.rodata)
|
||||
*(.rodata*)
|
||||
*(.glue_7)
|
||||
*(.glue_7t)
|
||||
} >DRAM
|
||||
|
||||
.gdbapi :
|
||||
{
|
||||
*(.gdbapi)
|
||||
} >DRAM_API
|
||||
|
||||
.data :
|
||||
{
|
||||
*(.data)
|
||||
} >DRAM
|
||||
|
||||
.vectors :
|
||||
{
|
||||
_vectorsstart = .;
|
||||
*(.vectors)
|
||||
_vectorsend = .;
|
||||
} >IRAM AT>DRAM
|
||||
_vectorscopy = LOADADDR(.vectors);
|
||||
|
||||
.stack (NOLOAD) :
|
||||
{
|
||||
stackbegin = .;
|
||||
. += 0x400;
|
||||
_stub_stack = .;
|
||||
. += 0x200;
|
||||
stackend = .;
|
||||
} >DRAM
|
||||
|
||||
.bss (NOLOAD) :
|
||||
{
|
||||
_edata = .;
|
||||
*(.bss)
|
||||
_end = .;
|
||||
} >DRAM
|
||||
}
|
||||
#else
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.vectors 0x09000000 :
|
||||
{
|
||||
*(.vectors);
|
||||
. = ALIGN(0x200);
|
||||
start.o(.text)
|
||||
*(.rodata)
|
||||
}
|
||||
|
||||
.text :
|
||||
{
|
||||
*(.text)
|
||||
}
|
||||
|
||||
.bss :
|
||||
{
|
||||
_stack = . + 0x1000;
|
||||
_stub_stack = _stack + 0x1000;
|
||||
}
|
||||
|
||||
.pad 0x0900C800 :
|
||||
{
|
||||
LONG(0);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
61
gdb/setjmp.S
61
gdb/setjmp.S
|
|
@ -1,61 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2002 by Red Hat Inc
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
.type _setjmp,@function
|
||||
.global _setjmp
|
||||
_setjmp:
|
||||
add #(9*4),r4
|
||||
|
||||
sts.l pr,@-r4
|
||||
|
||||
mov.l r15,@-r4
|
||||
mov.l r14,@-r4
|
||||
mov.l r13,@-r4
|
||||
mov.l r12,@-r4
|
||||
|
||||
mov.l r11,@-r4
|
||||
mov.l r10,@-r4
|
||||
mov.l r9,@-r4
|
||||
mov.l r8,@-r4
|
||||
|
||||
rts
|
||||
mov #0,r0
|
||||
|
||||
.type _longjmp,@function
|
||||
.global _longjmp
|
||||
_longjmp:
|
||||
mov.l @r4+,r8
|
||||
mov.l @r4+,r9
|
||||
mov.l @r4+,r10
|
||||
mov.l @r4+,r11
|
||||
|
||||
mov.l @r4+,r12
|
||||
mov.l @r4+,r13
|
||||
mov.l @r4+,r14
|
||||
mov.l @r4+,r15
|
||||
|
||||
lds.l @r4+,pr
|
||||
|
||||
mov r5,r0
|
||||
tst r0,r0
|
||||
bf retr4
|
||||
movt r0
|
||||
retr4: rts
|
||||
nop
|
||||
Loading…
Add table
Add a link
Reference in a new issue