1629 lines
48 KiB
C
1629 lines
48 KiB
C
|
/***************************************************************************
|
||
|
* __________ __ ___.
|
||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||
|
* \/ \/ \/ \/ \/
|
||
|
* $Id$
|
||
|
*
|
||
|
* Copyright (C) 2002 by Linus Nielsen Feltzing
|
||
|
*
|
||
|
* All files in this archive are subject to the GNU General Public License.
|
||
|
* See the file COPYING in the source tree root for full license agreement.
|
||
|
*
|
||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||
|
* KIND, either express or implied.
|
||
|
*
|
||
|
****************************************************************************/
|
||
|
/* sh-stub.c -- debugging stub for the Hitachi-SH.
|
||
|
|
||
|
NOTE!! This code has to be compiled with optimization, otherwise the
|
||
|
function inlining which generates the exception handlers won't work.
|
||
|
|
||
|
*/
|
||
|
|
||
|
/* This is originally based on an m68k software stub written by Glenn
|
||
|
Engel at HP, but has changed quite a bit.
|
||
|
|
||
|
Modifications for the SH by Ben Lee and Steve Chamberlain
|
||
|
|
||
|
Even more modifications for GCC 3.0 and The Rockbox by Linus
|
||
|
Nielsen Feltzing
|
||
|
*/
|
||
|
|
||
|
/****************************************************************************
|
||
|
|
||
|
THIS SOFTWARE IS NOT COPYRIGHTED
|
||
|
|
||
|
HP offers the following for use in the public domain. HP makes no
|
||
|
warranty with regard to the software or it's performance and the
|
||
|
user accepts the software "AS IS" with all faults.
|
||
|
|
||
|
HP DISCLAIMS 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.
|
||
|
|
||
|
****************************************************************************/
|
||
|
|
||
|
|
||
|
/* 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 and ready for next packet
|
||
|
- - 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...,
|
||
|
which contains two hex digits for each
|
||
|
byte in the register (target byte
|
||
|
order).
|
||
|
reply OK for success
|
||
|
ENN for an error
|
||
|
(not supported by all stubs).
|
||
|
|
||
|
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.
|
||
|
|
||
|
last signal ? Reply the current reason for stopping.
|
||
|
This is the same reply as is generated
|
||
|
for step or cont : SAA where AA is the
|
||
|
signal number.
|
||
|
|
||
|
There is no immediate reply to step or cont.
|
||
|
The reply comes when the machine stops.
|
||
|
It is SAA AA is the "signal number"
|
||
|
|
||
|
or... TAAn...:r...;n:r...;n...:r...;
|
||
|
AA = signal number
|
||
|
n... = register number
|
||
|
r... = register contents
|
||
|
or... WAA The process exited, and AA is
|
||
|
the exit status. This is only
|
||
|
applicable for certains sorts of
|
||
|
targets.
|
||
|
kill request k
|
||
|
|
||
|
toggle debug d toggle debug flag (see 386 & 68k stubs)
|
||
|
reset r reset -- see sparc stub.
|
||
|
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.
|
||
|
search tAA:PP,MM Search backwards starting at address
|
||
|
AA for a match with pattern PP and
|
||
|
mask MM. PP and MM are 4 bytes.
|
||
|
Not supported by all stubs.
|
||
|
|
||
|
general query qXXXX Request info about XXXX.
|
||
|
general set QXXXX=yyyy Set value of XXXX to yyyy.
|
||
|
query sect offs qOffsets Get section offsets. Reply is
|
||
|
Text=xxx;Data=yyy;Bss=zzz
|
||
|
console output Otext Send text to stdout. Only comes from
|
||
|
remote target.
|
||
|
|
||
|
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 repititions of the character preceding the '*'.
|
||
|
The encoding is n+29, yielding a printable character where n >=3
|
||
|
(which is where rle starts to win). Don't use an n > 126.
|
||
|
|
||
|
So
|
||
|
"0* " means the same as "0000". */
|
||
|
|
||
|
#include "archos.h"
|
||
|
#include "sh.h"
|
||
|
#include <string.h>
|
||
|
#include <setjmp.h>
|
||
|
|
||
|
/* Hitachi SH architecture instruction encoding masks */
|
||
|
|
||
|
#define COND_BR_MASK 0xff00
|
||
|
#define UCOND_DBR_MASK 0xe000
|
||
|
#define UCOND_RBR_MASK 0xf0df
|
||
|
#define TRAPA_MASK 0xff00
|
||
|
|
||
|
#define COND_DISP 0x00ff
|
||
|
#define UCOND_DISP 0x0fff
|
||
|
#define UCOND_REG 0x0f00
|
||
|
|
||
|
/* Hitachi SH instruction opcodes */
|
||
|
|
||
|
#define BF_INSTR 0x8b00
|
||
|
#define BT_INSTR 0x8900
|
||
|
#define BRA_INSTR 0xa000
|
||
|
#define BSR_INSTR 0xb000
|
||
|
#define JMP_INSTR 0x402b
|
||
|
#define JSR_INSTR 0x400b
|
||
|
#define RTS_INSTR 0x000b
|
||
|
#define RTE_INSTR 0x002b
|
||
|
#define TRAPA_INSTR 0xc300
|
||
|
#define SSTEP_INSTR 0xc37f
|
||
|
|
||
|
/* Hitachi SH processor register masks */
|
||
|
|
||
|
#define T_BIT_MASK 0x0001
|
||
|
|
||
|
#define PBDR (*(volatile unsigned short *)(0x5ffffc2)) /* Port B Data */
|
||
|
void lcd_printxy( char x, char y, unsigned char* string, int len );
|
||
|
|
||
|
/*
|
||
|
* BUFMAX defines the maximum number of characters in inbound/outbound
|
||
|
* buffers. At least NUMREGBYTES*2 are needed for register packets.
|
||
|
*/
|
||
|
#define BUFMAX 1024
|
||
|
|
||
|
/*
|
||
|
* Number of bytes for registers
|
||
|
*/
|
||
|
#define NUMREGBYTES 112 /* 92 */
|
||
|
|
||
|
/*
|
||
|
* Forward declarations
|
||
|
*/
|
||
|
|
||
|
static int hex (char);
|
||
|
static char *mem2hex (char *mem, char *buf, int count);
|
||
|
static char *hex2mem (char *buf, char *mem, int count);
|
||
|
static int hex2int (char **ptr, int *intValue);
|
||
|
static unsigned char *getpacket (void);
|
||
|
static void putpacket (register char *buffer);
|
||
|
static int computeSignal (int exceptionVector);
|
||
|
void handle_buserror (void);
|
||
|
void handle_exception (int exceptionVector);
|
||
|
void init_serial();
|
||
|
|
||
|
void serial_putc (char ch);
|
||
|
char serial_getc (void);
|
||
|
|
||
|
/* These are in the file but in asm statements so the compiler can't see them */
|
||
|
void catch_exception_4 (void);
|
||
|
void catch_exception_5 (void);
|
||
|
void catch_exception_6 (void);
|
||
|
void catch_exception_7 (void);
|
||
|
void catch_exception_8 (void);
|
||
|
void catch_exception_9 (void);
|
||
|
void catch_exception_10 (void);
|
||
|
void catch_exception_11 (void);
|
||
|
void catch_exception_12 (void);
|
||
|
void catch_exception_13 (void);
|
||
|
void catch_exception_14 (void);
|
||
|
void catch_exception_15 (void);
|
||
|
void catch_exception_16 (void);
|
||
|
void catch_exception_17 (void);
|
||
|
void catch_exception_18 (void);
|
||
|
void catch_exception_19 (void);
|
||
|
void catch_exception_20 (void);
|
||
|
void catch_exception_21 (void);
|
||
|
void catch_exception_22 (void);
|
||
|
void catch_exception_23 (void);
|
||
|
void catch_exception_24 (void);
|
||
|
void catch_exception_25 (void);
|
||
|
void catch_exception_26 (void);
|
||
|
void catch_exception_27 (void);
|
||
|
void catch_exception_28 (void);
|
||
|
void catch_exception_29 (void);
|
||
|
void catch_exception_30 (void);
|
||
|
void catch_exception_31 (void);
|
||
|
void catch_exception_32 (void);
|
||
|
void catch_exception_33 (void);
|
||
|
void catch_exception_34 (void);
|
||
|
void catch_exception_35 (void);
|
||
|
void catch_exception_36 (void);
|
||
|
void catch_exception_37 (void);
|
||
|
void catch_exception_38 (void);
|
||
|
void catch_exception_39 (void);
|
||
|
void catch_exception_40 (void);
|
||
|
void catch_exception_41 (void);
|
||
|
void catch_exception_42 (void);
|
||
|
void catch_exception_43 (void);
|
||
|
void catch_exception_44 (void);
|
||
|
void catch_exception_45 (void);
|
||
|
void catch_exception_46 (void);
|
||
|
void catch_exception_47 (void);
|
||
|
void catch_exception_48 (void);
|
||
|
void catch_exception_49 (void);
|
||
|
void catch_exception_50 (void);
|
||
|
void catch_exception_51 (void);
|
||
|
void catch_exception_52 (void);
|
||
|
void catch_exception_53 (void);
|
||
|
void catch_exception_54 (void);
|
||
|
void catch_exception_55 (void);
|
||
|
void catch_exception_56 (void);
|
||
|
void catch_exception_57 (void);
|
||
|
void catch_exception_58 (void);
|
||
|
void catch_exception_59 (void);
|
||
|
void catch_exception_60 (void);
|
||
|
void catch_exception_61 (void);
|
||
|
void catch_exception_62 (void);
|
||
|
void catch_exception_63 (void);
|
||
|
void catch_exception_64 (void);
|
||
|
void catch_exception_65 (void);
|
||
|
void catch_exception_66 (void);
|
||
|
void catch_exception_67 (void);
|
||
|
void catch_exception_68 (void);
|
||
|
void catch_exception_69 (void);
|
||
|
void catch_exception_70 (void);
|
||
|
void catch_exception_71 (void);
|
||
|
void catch_exception_72 (void);
|
||
|
void catch_exception_73 (void);
|
||
|
void catch_exception_74 (void);
|
||
|
void catch_exception_75 (void);
|
||
|
void catch_exception_76 (void);
|
||
|
void catch_exception_77 (void);
|
||
|
void catch_exception_78 (void);
|
||
|
void catch_exception_79 (void);
|
||
|
void catch_exception_80 (void);
|
||
|
void catch_exception_81 (void);
|
||
|
void catch_exception_82 (void);
|
||
|
void catch_exception_83 (void);
|
||
|
void catch_exception_84 (void);
|
||
|
void catch_exception_85 (void);
|
||
|
void catch_exception_86 (void);
|
||
|
void catch_exception_87 (void);
|
||
|
void catch_exception_88 (void);
|
||
|
void catch_exception_89 (void);
|
||
|
void catch_exception_90 (void);
|
||
|
void catch_exception_91 (void);
|
||
|
void catch_exception_92 (void);
|
||
|
void catch_exception_93 (void);
|
||
|
void catch_exception_94 (void);
|
||
|
void catch_exception_95 (void);
|
||
|
void catch_exception_96 (void);
|
||
|
void catch_exception_97 (void);
|
||
|
void catch_exception_98 (void);
|
||
|
void catch_exception_99 (void);
|
||
|
void catch_exception_100 (void);
|
||
|
void catch_exception_101 (void);
|
||
|
void catch_exception_102 (void);
|
||
|
void catch_exception_103 (void);
|
||
|
void catch_exception_104 (void);
|
||
|
void catch_exception_105 (void);
|
||
|
void catch_exception_106 (void);
|
||
|
void catch_exception_107 (void);
|
||
|
void catch_exception_108 (void);
|
||
|
void catch_exception_109 (void);
|
||
|
void catch_exception_110 (void);
|
||
|
void catch_exception_111 (void);
|
||
|
void catch_exception_112 (void);
|
||
|
void catch_exception_113 (void);
|
||
|
void catch_exception_114 (void);
|
||
|
void catch_exception_115 (void);
|
||
|
void catch_exception_116 (void);
|
||
|
void catch_exception_117 (void);
|
||
|
void catch_exception_118 (void);
|
||
|
void catch_exception_119 (void);
|
||
|
void catch_exception_120 (void);
|
||
|
void catch_exception_121 (void);
|
||
|
void catch_exception_122 (void);
|
||
|
void catch_exception_123 (void);
|
||
|
void catch_exception_124 (void);
|
||
|
void catch_exception_125 (void);
|
||
|
void catch_exception_126 (void);
|
||
|
void catch_exception_127 (void);
|
||
|
|
||
|
void breakpoint (void);
|
||
|
|
||
|
|
||
|
#define init_stack_size 2*1024 /* if you change this you should also modify BINIT */
|
||
|
#define stub_stack_size 2*1024
|
||
|
|
||
|
int init_stack[init_stack_size] __attribute__ ((section ("stack"))) = {0};
|
||
|
int stub_stack[stub_stack_size] __attribute__ ((section ("stack"))) = {0};
|
||
|
|
||
|
|
||
|
void INIT ();
|
||
|
void start ();
|
||
|
|
||
|
#define CPU_BUS_ERROR_VEC 9
|
||
|
#define DMA_BUS_ERROR_VEC 10
|
||
|
#define NMI_VEC 11
|
||
|
#define INVALID_INSN_VEC 4
|
||
|
#define INVALID_SLOT_VEC 6
|
||
|
#define TRAP_VEC 32
|
||
|
#define IO_VEC 33
|
||
|
#define USER_VEC 127
|
||
|
|
||
|
|
||
|
|
||
|
char in_nmi; /* Set when handling an NMI, so we don't reenter */
|
||
|
int dofault; /* Non zero, bus errors will raise exception */
|
||
|
|
||
|
int *stub_sp;
|
||
|
|
||
|
/* debug > 0 prints ill-formed commands in valid packets & checksum errors */
|
||
|
int remote_debug;
|
||
|
|
||
|
/* jump buffer used for setjmp/longjmp */
|
||
|
jmp_buf remcomEnv;
|
||
|
|
||
|
enum regnames
|
||
|
{
|
||
|
R0, R1, R2, R3, R4, R5, R6, R7,
|
||
|
R8, R9, R10, R11, R12, R13, R14,
|
||
|
R15, PC, PR, GBR, VBR, MACH, MACL, SR,
|
||
|
TICKS, STALLS, CYCLES, INSTS, PLR
|
||
|
};
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
short *memAddr;
|
||
|
short oldInstr;
|
||
|
}
|
||
|
stepData;
|
||
|
|
||
|
int registers[NUMREGBYTES / 4];
|
||
|
stepData instrBuffer;
|
||
|
char stepped;
|
||
|
static const char hexchars[] = "0123456789abcdef";
|
||
|
static char remcomInBuffer[BUFMAX];
|
||
|
static char remcomOutBuffer[BUFMAX];
|
||
|
|
||
|
void blink(void)
|
||
|
{
|
||
|
while(1)
|
||
|
{
|
||
|
int i;
|
||
|
PBDR ^= 0x40; /* toggle PB6 */
|
||
|
for(i = 0;i < 500000;i++)
|
||
|
{
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
char highhex(int x)
|
||
|
{
|
||
|
return hexchars[(x >> 4) & 0xf];
|
||
|
}
|
||
|
|
||
|
char lowhex(int x)
|
||
|
{
|
||
|
return hexchars[x & 0xf];
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Assembly macros
|
||
|
*/
|
||
|
|
||
|
#define BREAKPOINT() asm("trapa #0x20"::);
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Routines to handle hex data
|
||
|
*/
|
||
|
|
||
|
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 the memory, pointed to by mem into hex, placing result in buf */
|
||
|
/* return a pointer to the last char put in buf (null) */
|
||
|
static char *mem2hex (char *mem, char *buf, int count)
|
||
|
{
|
||
|
int i;
|
||
|
int ch;
|
||
|
for (i = 0; i < count; i++)
|
||
|
{
|
||
|
ch = *mem++;
|
||
|
*buf++ = highhex (ch);
|
||
|
*buf++ = lowhex (ch);
|
||
|
}
|
||
|
*buf = 0;
|
||
|
return (buf);
|
||
|
}
|
||
|
|
||
|
/* convert the hex array pointed to by buf into binary, to be placed in mem */
|
||
|
/* return a pointer to the character after the last byte written */
|
||
|
static char *hex2mem (char *buf, char *mem, int count)
|
||
|
{
|
||
|
int i;
|
||
|
unsigned char ch;
|
||
|
for (i = 0; i < count; i++)
|
||
|
{
|
||
|
ch = hex (*buf++) << 4;
|
||
|
ch = ch + hex (*buf++);
|
||
|
*mem++ = ch;
|
||
|
}
|
||
|
return (mem);
|
||
|
}
|
||
|
|
||
|
/**********************************************/
|
||
|
/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
|
||
|
/* RETURN NUMBER OF CHARS PROCESSED */
|
||
|
/**********************************************/
|
||
|
static int hex2int (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);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Routines to get and put packets
|
||
|
*/
|
||
|
|
||
|
/* scan for the sequence $<data>#<checksum> */
|
||
|
|
||
|
unsigned char *getpacket (void)
|
||
|
{
|
||
|
unsigned char *buffer = &remcomInBuffer[0];
|
||
|
unsigned char checksum;
|
||
|
unsigned char xmitcsum;
|
||
|
int count;
|
||
|
char ch;
|
||
|
|
||
|
while (1)
|
||
|
{
|
||
|
/* wait around for the start character, ignore all other characters */
|
||
|
while ((ch = serial_getc ()) != '$')
|
||
|
;
|
||
|
|
||
|
retry:
|
||
|
checksum = 0;
|
||
|
xmitcsum = -1;
|
||
|
count = 0;
|
||
|
|
||
|
/* now, read until a # or end of buffer is found */
|
||
|
while (count < BUFMAX)
|
||
|
{
|
||
|
ch = serial_getc ();
|
||
|
if (ch == '$')
|
||
|
goto retry;
|
||
|
if (ch == '#')
|
||
|
break;
|
||
|
checksum = checksum + ch;
|
||
|
buffer[count] = ch;
|
||
|
count = count + 1;
|
||
|
}
|
||
|
buffer[count] = 0;
|
||
|
|
||
|
if (ch == '#')
|
||
|
{
|
||
|
ch = serial_getc ();
|
||
|
xmitcsum = hex (ch) << 4;
|
||
|
ch = serial_getc ();
|
||
|
xmitcsum += hex (ch);
|
||
|
|
||
|
if (checksum != xmitcsum)
|
||
|
{
|
||
|
serial_putc ('-'); /* failed checksum */
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
serial_putc ('+'); /* successful transfer */
|
||
|
|
||
|
/* if a sequence char is present, reply the sequence ID */
|
||
|
if (buffer[2] == ':')
|
||
|
{
|
||
|
serial_putc (buffer[0]);
|
||
|
serial_putc (buffer[1]);
|
||
|
|
||
|
return &buffer[3];
|
||
|
}
|
||
|
|
||
|
return &buffer[0];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* send the packet in buffer. */
|
||
|
|
||
|
static void putpacket (register char *buffer)
|
||
|
{
|
||
|
register int checksum;
|
||
|
|
||
|
/* $<packet info>#<checksum>. */
|
||
|
do
|
||
|
{
|
||
|
char *src = buffer;
|
||
|
serial_putc ('$');
|
||
|
checksum = 0;
|
||
|
|
||
|
while (*src)
|
||
|
{
|
||
|
int runlen;
|
||
|
|
||
|
/* Do run length encoding */
|
||
|
for (runlen = 0; runlen < 100; runlen ++)
|
||
|
{
|
||
|
if (src[0] != src[runlen])
|
||
|
{
|
||
|
if (runlen > 3)
|
||
|
{
|
||
|
int encode;
|
||
|
/* Got a useful amount */
|
||
|
serial_putc (*src);
|
||
|
checksum += *src;
|
||
|
serial_putc ('*');
|
||
|
checksum += '*';
|
||
|
checksum += (encode = runlen + ' ' - 4);
|
||
|
serial_putc (encode);
|
||
|
src += runlen;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
serial_putc (*src);
|
||
|
checksum += *src;
|
||
|
src++;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
serial_putc ('#');
|
||
|
serial_putc (highhex(checksum));
|
||
|
serial_putc (lowhex(checksum));
|
||
|
}
|
||
|
while (serial_getc() != '+');
|
||
|
}
|
||
|
|
||
|
|
||
|
/* a bus error has occurred, perform a longjmp
|
||
|
to return execution and allow handling of the error */
|
||
|
|
||
|
void handle_buserror (void)
|
||
|
{
|
||
|
longjmp (remcomEnv, 1);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* this function takes the SH-1 exception number and attempts to
|
||
|
* translate this number into a unix compatible signal value
|
||
|
*/
|
||
|
static int computeSignal (int exceptionVector)
|
||
|
{
|
||
|
int sigval;
|
||
|
switch (exceptionVector)
|
||
|
{
|
||
|
case INVALID_INSN_VEC:
|
||
|
sigval = 4;
|
||
|
break;
|
||
|
case INVALID_SLOT_VEC:
|
||
|
sigval = 4;
|
||
|
break;
|
||
|
case CPU_BUS_ERROR_VEC:
|
||
|
sigval = 10;
|
||
|
break;
|
||
|
case DMA_BUS_ERROR_VEC:
|
||
|
sigval = 10;
|
||
|
break;
|
||
|
case NMI_VEC:
|
||
|
sigval = 2;
|
||
|
break;
|
||
|
|
||
|
case TRAP_VEC:
|
||
|
case USER_VEC:
|
||
|
sigval = 5;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
sigval = 7; /* "software generated"*/
|
||
|
break;
|
||
|
}
|
||
|
return (sigval);
|
||
|
}
|
||
|
|
||
|
void doSStep (void)
|
||
|
{
|
||
|
short *instrMem;
|
||
|
int displacement;
|
||
|
int reg;
|
||
|
unsigned short opcode;
|
||
|
|
||
|
instrMem = (short *) registers[PC];
|
||
|
|
||
|
opcode = *instrMem;
|
||
|
stepped = 1;
|
||
|
|
||
|
if ((opcode & COND_BR_MASK) == BT_INSTR)
|
||
|
{
|
||
|
if (registers[SR] & T_BIT_MASK)
|
||
|
{
|
||
|
displacement = (opcode & COND_DISP) << 1;
|
||
|
if (displacement & 0x80)
|
||
|
displacement |= 0xffffff00;
|
||
|
/*
|
||
|
* Remember PC points to second instr.
|
||
|
* after PC of branch ... so add 4
|
||
|
*/
|
||
|
instrMem = (short *) (registers[PC] + displacement + 4);
|
||
|
}
|
||
|
else
|
||
|
instrMem += 1;
|
||
|
}
|
||
|
else if ((opcode & COND_BR_MASK) == BF_INSTR)
|
||
|
{
|
||
|
if (registers[SR] & T_BIT_MASK)
|
||
|
instrMem += 1;
|
||
|
else
|
||
|
{
|
||
|
displacement = (opcode & COND_DISP) << 1;
|
||
|
if (displacement & 0x80)
|
||
|
displacement |= 0xffffff00;
|
||
|
/*
|
||
|
* Remember PC points to second instr.
|
||
|
* after PC of branch ... so add 4
|
||
|
*/
|
||
|
instrMem = (short *) (registers[PC] + displacement + 4);
|
||
|
}
|
||
|
}
|
||
|
else if ((opcode & UCOND_DBR_MASK) == BRA_INSTR)
|
||
|
{
|
||
|
displacement = (opcode & UCOND_DISP) << 1;
|
||
|
if (displacement & 0x0800)
|
||
|
displacement |= 0xfffff000;
|
||
|
|
||
|
/*
|
||
|
* Remember PC points to second instr.
|
||
|
* after PC of branch ... so add 4
|
||
|
*/
|
||
|
instrMem = (short *) (registers[PC] + displacement + 4);
|
||
|
}
|
||
|
else if ((opcode & UCOND_RBR_MASK) == JSR_INSTR)
|
||
|
{
|
||
|
reg = (char) ((opcode & UCOND_REG) >> 8);
|
||
|
|
||
|
instrMem = (short *) registers[reg];
|
||
|
}
|
||
|
else if (opcode == RTS_INSTR)
|
||
|
instrMem = (short *) registers[PR];
|
||
|
else if (opcode == RTE_INSTR)
|
||
|
instrMem = (short *) registers[15];
|
||
|
else if ((opcode & TRAPA_MASK) == TRAPA_INSTR)
|
||
|
instrMem = (short *) ((opcode & ~TRAPA_MASK) << 2);
|
||
|
else
|
||
|
instrMem += 1;
|
||
|
|
||
|
instrBuffer.memAddr = instrMem;
|
||
|
instrBuffer.oldInstr = *instrMem;
|
||
|
*instrMem = SSTEP_INSTR;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Undo the effect of a previous doSStep. If we single stepped,
|
||
|
restore the old instruction. */
|
||
|
|
||
|
void undoSStep (void)
|
||
|
{
|
||
|
if (stepped)
|
||
|
{
|
||
|
short *instrMem;
|
||
|
instrMem = instrBuffer.memAddr;
|
||
|
*instrMem = instrBuffer.oldInstr;
|
||
|
}
|
||
|
stepped = 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
This function does all exception handling. It only does two things -
|
||
|
it figures out why it was called and tells gdb, and then it reacts
|
||
|
to gdb's requests.
|
||
|
|
||
|
When in the monitor mode we talk a human on the serial line rather than gdb.
|
||
|
|
||
|
*/
|
||
|
|
||
|
void gdb_handle_exception (int exceptionVector)
|
||
|
{
|
||
|
char buf[32];
|
||
|
unsigned int r;
|
||
|
int sigval, stepping;
|
||
|
int addr, length;
|
||
|
char *ptr;
|
||
|
|
||
|
/* reply to host that an exception has occurred */
|
||
|
sigval = computeSignal (exceptionVector);
|
||
|
remcomOutBuffer[0] = 'S';
|
||
|
remcomOutBuffer[1] = highhex(sigval);
|
||
|
remcomOutBuffer[2] = lowhex (sigval);
|
||
|
remcomOutBuffer[3] = 0;
|
||
|
|
||
|
putpacket (remcomOutBuffer);
|
||
|
|
||
|
/*
|
||
|
* exception 127 indicates a software trap
|
||
|
* inserted in place of code ... so back up
|
||
|
* PC by one instruction, since this instruction
|
||
|
* will later be replaced by its original one!
|
||
|
*/
|
||
|
if (exceptionVector == USER_VEC
|
||
|
|| exceptionVector == TRAP_VEC)
|
||
|
registers[PC] -= 2;
|
||
|
|
||
|
/*
|
||
|
* Do the thangs needed to undo
|
||
|
* any stepping we may have done!
|
||
|
*/
|
||
|
undoSStep ();
|
||
|
|
||
|
stepping = 0;
|
||
|
|
||
|
buf[0] = highhex(exceptionVector);
|
||
|
buf[1] = lowhex(exceptionVector);
|
||
|
buf[2] = ':';
|
||
|
r = registers[PC];
|
||
|
buf[3] = highhex((r >> 24) & 0xff);
|
||
|
buf[4] = lowhex((r >> 24) & 0xff);
|
||
|
buf[5] = highhex((r >> 16) & 0xff);
|
||
|
buf[6] = lowhex((r >> 16) & 0xff);
|
||
|
buf[7] = highhex((r >> 8) & 0xff);
|
||
|
buf[8] = lowhex((r >> 8) & 0xff);
|
||
|
buf[9] = highhex(r & 0xff);
|
||
|
buf[10] = lowhex(r & 0xff);
|
||
|
|
||
|
lcd_printxy(0, 0, buf, 11);
|
||
|
|
||
|
while (1)
|
||
|
{
|
||
|
remcomOutBuffer[0] = 0;
|
||
|
ptr = getpacket ();
|
||
|
|
||
|
switch (*ptr++)
|
||
|
{
|
||
|
case '?':
|
||
|
remcomOutBuffer[0] = 'S';
|
||
|
remcomOutBuffer[1] = highhex (sigval);
|
||
|
remcomOutBuffer[2] = lowhex (sigval);
|
||
|
remcomOutBuffer[3] = 0;
|
||
|
break;
|
||
|
case 'd':
|
||
|
remote_debug = !(remote_debug); /* toggle debug flag */
|
||
|
break;
|
||
|
case 'g': /* return the value of the CPU registers */
|
||
|
mem2hex ((char *) registers, remcomOutBuffer, NUMREGBYTES);
|
||
|
break;
|
||
|
case 'G': /* set the value of the CPU registers - return OK */
|
||
|
hex2mem (ptr, (char *) registers, NUMREGBYTES);
|
||
|
strcpy (remcomOutBuffer, "OK");
|
||
|
break;
|
||
|
|
||
|
/* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
|
||
|
case 'm':
|
||
|
if (setjmp (remcomEnv) == 0)
|
||
|
{
|
||
|
dofault = 0;
|
||
|
/* TRY, TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
|
||
|
if (hex2int (&ptr, &addr))
|
||
|
if (*(ptr++) == ',')
|
||
|
if (hex2int (&ptr, &length))
|
||
|
{
|
||
|
ptr = 0;
|
||
|
mem2hex ((char *) addr, remcomOutBuffer, length);
|
||
|
}
|
||
|
if (ptr)
|
||
|
strcpy (remcomOutBuffer, "E01");
|
||
|
}
|
||
|
else
|
||
|
strcpy (remcomOutBuffer, "E03");
|
||
|
|
||
|
/* restore handler for bus error */
|
||
|
dofault = 1;
|
||
|
break;
|
||
|
|
||
|
/* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
|
||
|
case 'M':
|
||
|
if (setjmp (remcomEnv) == 0)
|
||
|
{
|
||
|
dofault = 0;
|
||
|
|
||
|
/* TRY, TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
|
||
|
if (hex2int (&ptr, &addr))
|
||
|
if (*(ptr++) == ',')
|
||
|
if (hex2int (&ptr, &length))
|
||
|
if (*(ptr++) == ':')
|
||
|
{
|
||
|
hex2mem (ptr, (char *) addr, length);
|
||
|
ptr = 0;
|
||
|
strcpy (remcomOutBuffer, "OK");
|
||
|
}
|
||
|
if (ptr)
|
||
|
strcpy (remcomOutBuffer, "E02");
|
||
|
}
|
||
|
else
|
||
|
strcpy (remcomOutBuffer, "E03");
|
||
|
|
||
|
/* restore handler for bus error */
|
||
|
dofault = 1;
|
||
|
break;
|
||
|
|
||
|
/* cAA..AA Continue at address AA..AA(optional) */
|
||
|
/* sAA..AA Step one instruction from AA..AA(optional) */
|
||
|
case 's':
|
||
|
stepping = 1;
|
||
|
case 'c':
|
||
|
{
|
||
|
/* tRY, to read optional parameter, pc unchanged if no parm */
|
||
|
if (hex2int (&ptr, &addr))
|
||
|
registers[PC] = addr;
|
||
|
|
||
|
if (stepping)
|
||
|
doSStep ();
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
break;
|
||
|
|
||
|
/* kill the program */
|
||
|
case 'k': /* do nothing */
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
} /* switch */
|
||
|
|
||
|
/* reply to the request */
|
||
|
putpacket (remcomOutBuffer);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/* We've had an exception - go into the gdb stub */
|
||
|
void handle_exception(int exceptionVector)
|
||
|
{
|
||
|
gdb_handle_exception (exceptionVector);
|
||
|
}
|
||
|
|
||
|
/* This function will generate a breakpoint exception. It is used at the
|
||
|
beginning of a program to sync up with a debugger and can be used
|
||
|
otherwise as a quick means to stop program execution and "break" into
|
||
|
the debugger. */
|
||
|
void breakpoint (void)
|
||
|
{
|
||
|
BREAKPOINT ();
|
||
|
}
|
||
|
|
||
|
/**** Processor-specific routines start here ****/
|
||
|
/**** Processor-specific routines start here ****/
|
||
|
/**** Processor-specific routines start here ****/
|
||
|
|
||
|
/* SH1/SH2 exception vector table format */
|
||
|
typedef struct
|
||
|
{
|
||
|
void (*func_cold) ();
|
||
|
int *stack_cold;
|
||
|
void (*func_warm) ();
|
||
|
int *stack_warm;
|
||
|
void (*(handler[128 - 4])) ();
|
||
|
} vec_type;
|
||
|
|
||
|
/* vectable is the SH1/SH2 vector table. It must be at address 0
|
||
|
** or wherever your vbr points.
|
||
|
** Note that we only define the first 128 vectors, since the Jukebox
|
||
|
** firmware has its entry point at 0x200
|
||
|
*/
|
||
|
|
||
|
const vec_type vectable __attribute__ ((section (".vectors"))) =
|
||
|
{
|
||
|
&start, /* 0: Power-on reset PC */
|
||
|
init_stack + init_stack_size, /* 1: Power-on reset SP */
|
||
|
&start, /* 2: Manual reset PC */
|
||
|
init_stack + init_stack_size, /* 3: Manual reset SP */
|
||
|
{
|
||
|
&catch_exception_4, /* 4: General invalid instruction */
|
||
|
&catch_exception_5, /* 5: Reserved for system */
|
||
|
&catch_exception_6, /* 6: Invalid slot instruction */
|
||
|
&catch_exception_7, /* 7: Reserved for system */
|
||
|
&catch_exception_8, /* 8: Reserved for system */
|
||
|
&catch_exception_9, /* 9: CPU bus error */
|
||
|
&catch_exception_10, /* 10: DMA bus error */
|
||
|
&catch_exception_11, /* 11: NMI */
|
||
|
&catch_exception_12, /* 12: User break */
|
||
|
&catch_exception_13, /* 13: Reserved for system */
|
||
|
&catch_exception_14, /* 14: Reserved for system */
|
||
|
&catch_exception_15, /* 15: Reserved for system */
|
||
|
&catch_exception_16, /* 16: Reserved for system */
|
||
|
&catch_exception_17, /* 17: Reserved for system */
|
||
|
&catch_exception_18, /* 18: Reserved for system */
|
||
|
&catch_exception_19, /* 19: Reserved for system */
|
||
|
&catch_exception_20, /* 20: Reserved for system */
|
||
|
&catch_exception_21, /* 21: Reserved for system */
|
||
|
&catch_exception_22, /* 22: Reserved for system */
|
||
|
&catch_exception_23, /* 23: Reserved for system */
|
||
|
&catch_exception_24, /* 24: Reserved for system */
|
||
|
&catch_exception_25, /* 25: Reserved for system */
|
||
|
&catch_exception_26, /* 26: Reserved for system */
|
||
|
&catch_exception_27, /* 27: Reserved for system */
|
||
|
&catch_exception_28, /* 28: Reserved for system */
|
||
|
&catch_exception_29, /* 29: Reserved for system */
|
||
|
&catch_exception_30, /* 30: Reserved for system */
|
||
|
&catch_exception_31, /* 31: Reserved for system */
|
||
|
&catch_exception_32, /* 32: Trap instr (user vectors) */
|
||
|
&catch_exception_33, /* 33: Trap instr (user vectors) */
|
||
|
&catch_exception_34, /* 34: Trap instr (user vectors) */
|
||
|
&catch_exception_35, /* 35: Trap instr (user vectors) */
|
||
|
&catch_exception_36, /* 36: Trap instr (user vectors) */
|
||
|
&catch_exception_37, /* 37: Trap instr (user vectors) */
|
||
|
&catch_exception_38, /* 38: Trap instr (user vectors) */
|
||
|
&catch_exception_39, /* 39: Trap instr (user vectors) */
|
||
|
&catch_exception_40, /* 40: Trap instr (user vectors) */
|
||
|
&catch_exception_41, /* 41: Trap instr (user vectors) */
|
||
|
&catch_exception_42, /* 42: Trap instr (user vectors) */
|
||
|
&catch_exception_43, /* 43: Trap instr (user vectors) */
|
||
|
&catch_exception_44, /* 44: Trap instr (user vectors) */
|
||
|
&catch_exception_45, /* 45: Trap instr (user vectors) */
|
||
|
&catch_exception_46, /* 46: Trap instr (user vectors) */
|
||
|
&catch_exception_47, /* 47: Trap instr (user vectors) */
|
||
|
&catch_exception_48, /* 48: Trap instr (user vectors) */
|
||
|
&catch_exception_49, /* 49: Trap instr (user vectors) */
|
||
|
&catch_exception_50, /* 50: Trap instr (user vectors) */
|
||
|
&catch_exception_51, /* 51: Trap instr (user vectors) */
|
||
|
&catch_exception_52, /* 52: Trap instr (user vectors) */
|
||
|
&catch_exception_53, /* 53: Trap instr (user vectors) */
|
||
|
&catch_exception_54, /* 54: Trap instr (user vectors) */
|
||
|
&catch_exception_55, /* 55: Trap instr (user vectors) */
|
||
|
&catch_exception_56, /* 56: Trap instr (user vectors) */
|
||
|
&catch_exception_57, /* 57: Trap instr (user vectors) */
|
||
|
&catch_exception_58, /* 58: Trap instr (user vectors) */
|
||
|
&catch_exception_59, /* 59: Trap instr (user vectors) */
|
||
|
&catch_exception_60, /* 60: Trap instr (user vectors) */
|
||
|
&catch_exception_61, /* 61: Trap instr (user vectors) */
|
||
|
&catch_exception_62, /* 62: Trap instr (user vectors) */
|
||
|
&catch_exception_63, /* 63: Trap instr (user vectors) */
|
||
|
&catch_exception_64, /* 64: IRQ0 */
|
||
|
&catch_exception_65, /* 65: IRQ1 */
|
||
|
&catch_exception_66, /* 66: IRQ2 */
|
||
|
&catch_exception_67, /* 67: IRQ3 */
|
||
|
&catch_exception_68, /* 68: IRQ4 */
|
||
|
&catch_exception_69, /* 69: IRQ5 */
|
||
|
&catch_exception_70, /* 70: IRQ6 */
|
||
|
&catch_exception_71, /* 71: IRQ7 */
|
||
|
&catch_exception_72,
|
||
|
&catch_exception_73,
|
||
|
&catch_exception_74,
|
||
|
&catch_exception_75,
|
||
|
&catch_exception_76,
|
||
|
&catch_exception_77,
|
||
|
&catch_exception_78,
|
||
|
&catch_exception_79,
|
||
|
&catch_exception_80,
|
||
|
&catch_exception_81,
|
||
|
&catch_exception_82,
|
||
|
&catch_exception_83,
|
||
|
&catch_exception_84,
|
||
|
&catch_exception_85,
|
||
|
&catch_exception_86,
|
||
|
&catch_exception_87,
|
||
|
&catch_exception_88,
|
||
|
&catch_exception_89,
|
||
|
&catch_exception_90,
|
||
|
&catch_exception_91,
|
||
|
&catch_exception_92,
|
||
|
&catch_exception_93,
|
||
|
&catch_exception_94,
|
||
|
&catch_exception_95,
|
||
|
&catch_exception_96,
|
||
|
&catch_exception_97,
|
||
|
&catch_exception_98,
|
||
|
&catch_exception_99,
|
||
|
&catch_exception_100,
|
||
|
&catch_exception_101,
|
||
|
&catch_exception_102,
|
||
|
&catch_exception_103,
|
||
|
&catch_exception_104,
|
||
|
&catch_exception_105,
|
||
|
&catch_exception_106,
|
||
|
&catch_exception_107,
|
||
|
&catch_exception_108,
|
||
|
&catch_exception_109,
|
||
|
&catch_exception_110,
|
||
|
&catch_exception_111,
|
||
|
&catch_exception_112,
|
||
|
&catch_exception_113,
|
||
|
&catch_exception_114,
|
||
|
&catch_exception_115,
|
||
|
&catch_exception_116,
|
||
|
&catch_exception_117,
|
||
|
&catch_exception_118,
|
||
|
&catch_exception_119,
|
||
|
&catch_exception_120,
|
||
|
&catch_exception_121,
|
||
|
&catch_exception_122,
|
||
|
&catch_exception_123,
|
||
|
&catch_exception_124,
|
||
|
&catch_exception_125,
|
||
|
&catch_exception_126,
|
||
|
&catch_exception_127}};
|
||
|
|
||
|
void INIT (void)
|
||
|
{
|
||
|
/* Disable all timer interrupts */
|
||
|
TIER0 = 0;
|
||
|
TIER1 = 0;
|
||
|
TIER2 = 0;
|
||
|
TIER3 = 0;
|
||
|
TIER4 = 0;
|
||
|
|
||
|
init_serial();
|
||
|
|
||
|
in_nmi = 0;
|
||
|
dofault = 1;
|
||
|
stepped = 0;
|
||
|
|
||
|
stub_sp = stub_stack + stub_stack_size;
|
||
|
breakpoint ();
|
||
|
|
||
|
/* We should never come here */
|
||
|
blink();
|
||
|
}
|
||
|
|
||
|
|
||
|
void sr()
|
||
|
{
|
||
|
/* Calling Reset does the same as pressing the button */
|
||
|
asm (".global _Reset\n"
|
||
|
" .global _WarmReset\n"
|
||
|
"_Reset:\n"
|
||
|
"_WarmReset:\n"
|
||
|
" mov.l L_sp,r15\n"
|
||
|
" bra _INIT\n"
|
||
|
" nop\n"
|
||
|
" .align 2\n"
|
||
|
"L_sp: .long _init_stack + 8000");
|
||
|
|
||
|
asm("saveRegisters:\n");
|
||
|
asm(" mov.l @(L_reg, pc), r0\n"
|
||
|
" mov.l @r15+, r1 ! pop R0\n"
|
||
|
" mov.l r2, @(0x08, r0) ! save R2\n"
|
||
|
" mov.l r1, @r0 ! save R0\n"
|
||
|
" mov.l @r15+, r1 ! pop R1\n"
|
||
|
" mov.l r3, @(0x0c, r0) ! save R3\n"
|
||
|
" mov.l r1, @(0x04, r0) ! save R1\n"
|
||
|
" mov.l r4, @(0x10, r0) ! save R4\n"
|
||
|
" mov.l r5, @(0x14, r0) ! save R5\n"
|
||
|
" mov.l r6, @(0x18, r0) ! save R6\n"
|
||
|
" mov.l r7, @(0x1c, r0) ! save R7\n"
|
||
|
" mov.l r8, @(0x20, r0) ! save R8\n"
|
||
|
" mov.l r9, @(0x24, r0) ! save R9\n"
|
||
|
" mov.l r10, @(0x28, r0) ! save R10\n"
|
||
|
" mov.l r11, @(0x2c, r0) ! save R11\n"
|
||
|
" mov.l r12, @(0x30, r0) ! save R12\n"
|
||
|
" mov.l r13, @(0x34, r0) ! save R13\n"
|
||
|
" mov.l r14, @(0x38, r0) ! save R14\n"
|
||
|
" mov.l @r15+, r4 ! save arg to handleException\n"
|
||
|
" add #8, r15 ! hide PC/SR values on stack\n"
|
||
|
" mov.l r15, @(0x3c, r0) ! save R15\n"
|
||
|
" add #-8, r15 ! save still needs old SP value\n"
|
||
|
" add #92, r0 ! readjust register pointer\n"
|
||
|
" mov r15, r2\n"
|
||
|
" add #4, r2\n"
|
||
|
" mov.l @r2, r2 ! R2 has SR\n"
|
||
|
" mov.l @r15, r1 ! R1 has PC\n"
|
||
|
" mov.l r2, @-r0 ! save SR\n"
|
||
|
" sts.l macl, @-r0 ! save MACL\n"
|
||
|
" sts.l mach, @-r0 ! save MACH\n"
|
||
|
" stc.l vbr, @-r0 ! save VBR\n"
|
||
|
" stc.l gbr, @-r0 ! save GBR\n"
|
||
|
" sts.l pr, @-r0 ! save PR\n"
|
||
|
" mov.l @(L_stubstack, pc), r2\n"
|
||
|
" mov.l @(L_hdl_except, pc), r3\n"
|
||
|
" mov.l @r2, r15\n"
|
||
|
" jsr @r3\n"
|
||
|
" mov.l r1, @-r0 ! save PC\n"
|
||
|
" mov.l @(L_stubstack, pc), r0\n"
|
||
|
" mov.l @(L_reg, pc), r1\n"
|
||
|
" bra restoreRegisters\n"
|
||
|
" mov.l r15, @r0 ! save __stub_stack\n"
|
||
|
|
||
|
" .align 2\n"
|
||
|
"L_reg:\n"
|
||
|
" .long _registers\n"
|
||
|
"L_stubstack:\n"
|
||
|
" .long _stub_sp\n"
|
||
|
"L_hdl_except:\n"
|
||
|
" .long _handle_exception");
|
||
|
}
|
||
|
|
||
|
void rr()
|
||
|
{
|
||
|
asm(" .align 2 \n"
|
||
|
" .global _resume\n"
|
||
|
"_resume:\n"
|
||
|
" mov r4,r1\n"
|
||
|
"restoreRegisters:\n"
|
||
|
" add #8, r1 ! skip to R2\n"
|
||
|
" mov.l @r1+, r2 ! restore R2\n"
|
||
|
" mov.l @r1+, r3 ! restore R3\n"
|
||
|
" mov.l @r1+, r4 ! restore R4\n"
|
||
|
" mov.l @r1+, r5 ! restore R5\n"
|
||
|
" mov.l @r1+, r6 ! restore R6\n"
|
||
|
" mov.l @r1+, r7 ! restore R7\n"
|
||
|
" mov.l @r1+, r8 ! restore R8\n"
|
||
|
" mov.l @r1+, r9 ! restore R9\n"
|
||
|
" mov.l @r1+, r10 ! restore R10\n"
|
||
|
" mov.l @r1+, r11 ! restore R11\n"
|
||
|
" mov.l @r1+, r12 ! restore R12\n"
|
||
|
" mov.l @r1+, r13 ! restore R13\n"
|
||
|
" mov.l @r1+, r14 ! restore R14\n"
|
||
|
" mov.l @r1+, r15 ! restore programs stack\n"
|
||
|
" mov.l @r1+, r0\n"
|
||
|
" add #-8, r15 ! uncover PC/SR on stack \n"
|
||
|
" mov.l r0, @r15 ! restore PC onto stack\n"
|
||
|
" lds.l @r1+, pr ! restore PR\n"
|
||
|
" ldc.l @r1+, gbr ! restore GBR\n"
|
||
|
" ldc.l @r1+, vbr ! restore VBR\n"
|
||
|
" lds.l @r1+, mach ! restore MACH\n"
|
||
|
" lds.l @r1+, macl ! restore MACL\n"
|
||
|
" mov.l @r1, r0 \n"
|
||
|
" add #-88, r1 ! readjust reg pointer to R1\n"
|
||
|
" mov.l r0, @(4, r15) ! restore SR onto stack+4\n"
|
||
|
" mov.l r2, @-r15\n"
|
||
|
" mov.l L_in_nmi, r0\n"
|
||
|
" mov #0, r2\n"
|
||
|
" mov.b r2, @r0\n"
|
||
|
" mov.l @r15+, r2\n"
|
||
|
" mov.l @r1+, r0 ! restore R0\n"
|
||
|
" rte\n"
|
||
|
" mov.l @r1, r1 ! restore R1");
|
||
|
}
|
||
|
|
||
|
static __inline__ void code_for_catch_exception(unsigned int n)
|
||
|
{
|
||
|
asm(" .globl _catch_exception_%O0" : : "X" (n) );
|
||
|
asm(" _catch_exception_%O0:" :: "X" (n) );
|
||
|
|
||
|
asm(" add #-4, r15 ! reserve spot on stack ");
|
||
|
asm(" mov.l r1, @-r15 ! push R1 ");
|
||
|
|
||
|
if (n == NMI_VEC)
|
||
|
{
|
||
|
/* Special case for NMI - make sure that they don't nest */
|
||
|
asm(" mov.l r0, @-r15 ! push R0");
|
||
|
asm(" mov.l L_in_nmi, r0");
|
||
|
asm(" tas.b @r0 ! Fend off against addtnl NMIs");
|
||
|
asm(" bt noNMI");
|
||
|
asm(" mov.l @r15+, r0");
|
||
|
asm(" mov.l @r15+, r1");
|
||
|
asm(" add #4, r15");
|
||
|
asm(" rte");
|
||
|
asm(" nop");
|
||
|
asm(".align 2");
|
||
|
asm("L_in_nmi: .long _in_nmi");
|
||
|
asm("noNMI:");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
if (n == CPU_BUS_ERROR_VEC)
|
||
|
{
|
||
|
/* Exception 9 (bus errors) are disasbleable - so that you
|
||
|
can probe memory and get zero instead of a fault.
|
||
|
Because the vector table may be in ROM we don't revector
|
||
|
the interrupt like all the other stubs, we check in here
|
||
|
*/
|
||
|
asm("mov.l L_dofault,r1");
|
||
|
asm("mov.l @r1,r1");
|
||
|
asm("tst r1,r1");
|
||
|
asm("bf faultaway");
|
||
|
asm("bsr _handle_buserror");
|
||
|
asm(".align 2");
|
||
|
asm("L_dofault: .long _dofault");
|
||
|
asm("faultaway:");
|
||
|
}
|
||
|
asm(" mov #15<<4, r1 ");
|
||
|
asm(" ldc r1, sr ! disable interrupts ");
|
||
|
asm(" mov.l r0, @-r15 ! push R0 ");
|
||
|
}
|
||
|
|
||
|
/* Prepare for saving context, we've already pushed r0 and r1, stick
|
||
|
exception number into the frame */
|
||
|
asm(" mov r15, r0 ");
|
||
|
asm(" add #8, r0 ");
|
||
|
asm(" mov %0,r1" :: "X" (n));
|
||
|
asm(" extu.b r1,r1 ");
|
||
|
asm(" bra saveRegisters ! save register values ");
|
||
|
asm(" mov.l r1, @r0 ! save exception # ");
|
||
|
}
|
||
|
|
||
|
/* Here we call all defined exceptions, so the inline assembler gets
|
||
|
generated */
|
||
|
void exceptions (void)
|
||
|
{
|
||
|
code_for_catch_exception (4);
|
||
|
code_for_catch_exception (5);
|
||
|
code_for_catch_exception (6);
|
||
|
code_for_catch_exception (7);
|
||
|
code_for_catch_exception (8);
|
||
|
code_for_catch_exception (9);
|
||
|
code_for_catch_exception (10);
|
||
|
code_for_catch_exception (11);
|
||
|
code_for_catch_exception (12);
|
||
|
code_for_catch_exception (13);
|
||
|
code_for_catch_exception (14);
|
||
|
code_for_catch_exception (15);
|
||
|
code_for_catch_exception (16);
|
||
|
code_for_catch_exception (17);
|
||
|
code_for_catch_exception (18);
|
||
|
code_for_catch_exception (19);
|
||
|
code_for_catch_exception (20);
|
||
|
code_for_catch_exception (21);
|
||
|
code_for_catch_exception (22);
|
||
|
code_for_catch_exception (23);
|
||
|
code_for_catch_exception (24);
|
||
|
code_for_catch_exception (25);
|
||
|
code_for_catch_exception (26);
|
||
|
code_for_catch_exception (27);
|
||
|
code_for_catch_exception (28);
|
||
|
code_for_catch_exception (29);
|
||
|
code_for_catch_exception (30);
|
||
|
code_for_catch_exception (31);
|
||
|
code_for_catch_exception (32);
|
||
|
code_for_catch_exception (33);
|
||
|
code_for_catch_exception (34);
|
||
|
code_for_catch_exception (35);
|
||
|
code_for_catch_exception (36);
|
||
|
code_for_catch_exception (37);
|
||
|
code_for_catch_exception (38);
|
||
|
code_for_catch_exception (39);
|
||
|
code_for_catch_exception (40);
|
||
|
code_for_catch_exception (41);
|
||
|
code_for_catch_exception (42);
|
||
|
code_for_catch_exception (43);
|
||
|
code_for_catch_exception (44);
|
||
|
code_for_catch_exception (45);
|
||
|
code_for_catch_exception (46);
|
||
|
code_for_catch_exception (47);
|
||
|
code_for_catch_exception (48);
|
||
|
code_for_catch_exception (49);
|
||
|
code_for_catch_exception (50);
|
||
|
code_for_catch_exception (51);
|
||
|
code_for_catch_exception (52);
|
||
|
code_for_catch_exception (53);
|
||
|
code_for_catch_exception (54);
|
||
|
code_for_catch_exception (55);
|
||
|
code_for_catch_exception (56);
|
||
|
code_for_catch_exception (57);
|
||
|
code_for_catch_exception (58);
|
||
|
code_for_catch_exception (59);
|
||
|
code_for_catch_exception (60);
|
||
|
code_for_catch_exception (61);
|
||
|
code_for_catch_exception (62);
|
||
|
code_for_catch_exception (63);
|
||
|
code_for_catch_exception (64);
|
||
|
code_for_catch_exception (65);
|
||
|
code_for_catch_exception (66);
|
||
|
code_for_catch_exception (67);
|
||
|
code_for_catch_exception (68);
|
||
|
code_for_catch_exception (69);
|
||
|
code_for_catch_exception (70);
|
||
|
code_for_catch_exception (71);
|
||
|
code_for_catch_exception (72);
|
||
|
code_for_catch_exception (73);
|
||
|
code_for_catch_exception (74);
|
||
|
code_for_catch_exception (75);
|
||
|
code_for_catch_exception (76);
|
||
|
code_for_catch_exception (77);
|
||
|
code_for_catch_exception (78);
|
||
|
code_for_catch_exception (79);
|
||
|
code_for_catch_exception (80);
|
||
|
code_for_catch_exception (81);
|
||
|
code_for_catch_exception (82);
|
||
|
code_for_catch_exception (83);
|
||
|
code_for_catch_exception (84);
|
||
|
code_for_catch_exception (85);
|
||
|
code_for_catch_exception (86);
|
||
|
code_for_catch_exception (87);
|
||
|
code_for_catch_exception (88);
|
||
|
code_for_catch_exception (89);
|
||
|
code_for_catch_exception (90);
|
||
|
code_for_catch_exception (91);
|
||
|
code_for_catch_exception (92);
|
||
|
code_for_catch_exception (93);
|
||
|
code_for_catch_exception (94);
|
||
|
code_for_catch_exception (95);
|
||
|
code_for_catch_exception (96);
|
||
|
code_for_catch_exception (97);
|
||
|
code_for_catch_exception (98);
|
||
|
code_for_catch_exception (99);
|
||
|
code_for_catch_exception (100);
|
||
|
code_for_catch_exception (101);
|
||
|
code_for_catch_exception (102);
|
||
|
code_for_catch_exception (103);
|
||
|
code_for_catch_exception (104);
|
||
|
code_for_catch_exception (105);
|
||
|
code_for_catch_exception (106);
|
||
|
code_for_catch_exception (107);
|
||
|
code_for_catch_exception (108);
|
||
|
code_for_catch_exception (109);
|
||
|
code_for_catch_exception (110);
|
||
|
code_for_catch_exception (111);
|
||
|
code_for_catch_exception (112);
|
||
|
code_for_catch_exception (113);
|
||
|
code_for_catch_exception (114);
|
||
|
code_for_catch_exception (115);
|
||
|
code_for_catch_exception (116);
|
||
|
code_for_catch_exception (117);
|
||
|
code_for_catch_exception (118);
|
||
|
code_for_catch_exception (119);
|
||
|
code_for_catch_exception (120);
|
||
|
code_for_catch_exception (121);
|
||
|
code_for_catch_exception (122);
|
||
|
code_for_catch_exception (123);
|
||
|
code_for_catch_exception (124);
|
||
|
code_for_catch_exception (125);
|
||
|
code_for_catch_exception (126);
|
||
|
code_for_catch_exception (127);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Port B Control Register (PBCR1)
|
||
|
*/
|
||
|
#define PB15MD1 0x8000
|
||
|
#define PB15MD0 0x4000
|
||
|
#define PB14MD1 0x2000
|
||
|
#define PB14MD0 0x1000
|
||
|
#define PB13MD1 0x0800
|
||
|
#define PB13MD0 0x0400
|
||
|
#define PB12MD1 0x0200
|
||
|
#define PB12MD0 0x0100
|
||
|
#define PB11MD1 0x0080
|
||
|
#define PB11MD0 0x0040
|
||
|
#define PB10MD1 0x0020
|
||
|
#define PB10MD0 0x0010
|
||
|
#define PB9MD1 0x0008
|
||
|
#define PB9MD0 0x0004
|
||
|
#define PB8MD1 0x0002
|
||
|
#define PB8MD0 0x0001
|
||
|
|
||
|
#define PB15MD PB15MD1|PB14MD0
|
||
|
#define PB14MD PB14MD1|PB14MD0
|
||
|
#define PB13MD PB13MD1|PB13MD0
|
||
|
#define PB12MD PB12MD1|PB12MD0
|
||
|
#define PB11MD PB11MD1|PB11MD0
|
||
|
#define PB10MD PB10MD1|PB10MD0
|
||
|
#define PB9MD PB9MD1|PB9MD0
|
||
|
#define PB8MD PB8MD1|PB8MD0
|
||
|
|
||
|
#define PB_TXD1 PB11MD1
|
||
|
#define PB_RXD1 PB10MD1
|
||
|
#define PB_TXD0 PB9MD1
|
||
|
#define PB_RXD0 PB8MD1
|
||
|
|
||
|
#define PB7MD PB7MD1|PB7MD0
|
||
|
#define PB6MD PB6MD1|PB6MD0
|
||
|
#define PB5MD PB5MD1|PB5MD0
|
||
|
#define PB4MD PB4MD1|PB4MD0
|
||
|
#define PB3MD PB3MD1|PB3MD0
|
||
|
#define PB2MD PB2MD1|PB2MD0
|
||
|
#define PB1MD PB1MD1|PB1MD0
|
||
|
#define PB0MD PB0MD1|PB0MD0
|
||
|
|
||
|
|
||
|
void handleError (char theSSR);
|
||
|
|
||
|
void nop (void)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
void init_serial (void)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
/* Clear Channel 1's SCR */
|
||
|
SCR1 = 0;
|
||
|
|
||
|
/* Set communication to be async, 8-bit data,
|
||
|
no parity, 1 stop bit and use internal clock */
|
||
|
SMR1 = 0;
|
||
|
/* BRR1 = SYSCLOCK / (9600 * 32) - 1;*/
|
||
|
BRR1 = 9; /* 38400 */
|
||
|
|
||
|
SCR1 &= ~(SCI_CKE1 | SCI_CKE0);
|
||
|
|
||
|
/* let the hardware settle */
|
||
|
for (i = 0; i < 1000; i++)
|
||
|
nop ();
|
||
|
|
||
|
/* Turn on in and out */
|
||
|
SCR1 |= SCI_RE | SCI_TE;
|
||
|
|
||
|
/* Set the PFC to make RXD1 (pin PB8) an input pin
|
||
|
and TXD1 (pin PB9) an output pin */
|
||
|
PBCR1 &= ~(PB_TXD1 | PB_RXD1);
|
||
|
PBCR1 |= PB_TXD1 | PB_RXD1;
|
||
|
}
|
||
|
|
||
|
|
||
|
int serial_waitc(void)
|
||
|
{
|
||
|
char mySSR;
|
||
|
mySSR = SSR1 & ( SCI_PER | SCI_FER | SCI_ORER );
|
||
|
if ( mySSR )
|
||
|
handleError ( mySSR );
|
||
|
return SSR1 & SCI_RDRF ;
|
||
|
}
|
||
|
|
||
|
char serial_getc (void)
|
||
|
{
|
||
|
char ch;
|
||
|
char mySSR;
|
||
|
|
||
|
while ( ! serial_waitc())
|
||
|
;
|
||
|
|
||
|
ch = RDR1;
|
||
|
SSR1 &= ~SCI_RDRF;
|
||
|
|
||
|
mySSR = SSR1 & (SCI_PER | SCI_FER | SCI_ORER);
|
||
|
|
||
|
if (mySSR)
|
||
|
handleError (mySSR);
|
||
|
|
||
|
return ch;
|
||
|
}
|
||
|
|
||
|
void serial_putc (char ch)
|
||
|
{
|
||
|
while (!(SSR1 & SCI_TDRE))
|
||
|
{
|
||
|
;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Write data into TDR and clear TDRE
|
||
|
*/
|
||
|
TDR1 = ch;
|
||
|
SSR1 &= ~SCI_TDRE;
|
||
|
}
|
||
|
|
||
|
void handleError (char theSSR)
|
||
|
{
|
||
|
/* Clear all error bits, otherwise the receiver will stop */
|
||
|
SSR1 &= ~(SCI_ORER | SCI_PER | SCI_FER);
|
||
|
}
|
||
|
|
||
|
#define DC 1
|
||
|
#define CS1 2
|
||
|
#define SDA 4
|
||
|
#define SCK 8
|
||
|
|
||
|
static const unsigned char ascii2lcd[] = {
|
||
|
0x00,0x01,0x02,0x03,0x00,0x84,0x85,0x89,
|
||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||
|
0xec,0xe3,0xe2,0xe1,0xe0,0xdf,0x15,0x00,
|
||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||
|
0x24,0x25,0x26,0x37,0x06,0x29,0x2a,0x2b,
|
||
|
0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,
|
||
|
0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,
|
||
|
0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,
|
||
|
0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,
|
||
|
0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0x53,
|
||
|
0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,
|
||
|
0x5c,0x5d,0x5e,0xa9,0x33,0xce,0x00,0x15,
|
||
|
0x00,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,
|
||
|
0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,
|
||
|
0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,
|
||
|
0x7c,0x7d,0x7e,0x24,0x24,0x24,0x24,0x24,
|
||
|
0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,
|
||
|
0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,
|
||
|
0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,
|
||
|
0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,
|
||
|
0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,
|
||
|
0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,
|
||
|
0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,
|
||
|
0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,
|
||
|
0x45,0x45,0x45,0x45,0x45,0x45,0x24,0x47,
|
||
|
0x49,0x49,0x49,0x49,0x4d,0x4d,0x4d,0x4d,
|
||
|
0x48,0x52,0x53,0x53,0x53,0x53,0x53,0x24,
|
||
|
0x24,0x59,0x59,0x59,0x59,0x5d,0x24,0x24,
|
||
|
0x65,0x65,0x65,0x65,0x65,0x65,0x24,0x67,
|
||
|
0x69,0x69,0x69,0x69,0x6d,0x6d,0x6d,0x6d,
|
||
|
0x73,0x72,0x73,0x73,0x73,0x73,0x73,0x24,
|
||
|
0x24,0x79,0x79,0x79,0x79,0x7d,0x24,0x7d
|
||
|
};
|
||
|
|
||
|
void lcd_write(int byte, int data)
|
||
|
{
|
||
|
int i;
|
||
|
char on,off;
|
||
|
|
||
|
PBDR &= ~CS1; /* enable lcd chip select */
|
||
|
|
||
|
if ( data ) {
|
||
|
on=~(SDA|SCK);
|
||
|
off=SCK|DC;
|
||
|
}
|
||
|
else {
|
||
|
on=~(SDA|SCK|DC);
|
||
|
off=SCK;
|
||
|
}
|
||
|
/* clock out each bit, MSB first */
|
||
|
for (i=0x80;i;i>>=1)
|
||
|
{
|
||
|
PBDR &= on;
|
||
|
if (i & byte)
|
||
|
PBDR |= SDA;
|
||
|
PBDR |= off;
|
||
|
}
|
||
|
|
||
|
PBDR |= CS1; /* disable lcd chip select */
|
||
|
}
|
||
|
|
||
|
void lcd_printxy( char x, char y, unsigned char* string, int len )
|
||
|
{
|
||
|
int i;
|
||
|
lcd_write(0xb0+y*16+x,0);
|
||
|
for (i=0; string[i] && i<len; i++)
|
||
|
lcd_write(ascii2lcd[string[i]],1);
|
||
|
}
|