libc/libgloss/sparc/salib.c

389 lines
7.1 KiB
C

/* Stand-alone library for SPARClite
*
* Copyright (c) 1995 Cygnus Support
*
* The authors hereby grant permission to use, copy, modify, distribute,
* and license this software and its documentation for any purpose, provided
* that existing copyright notices are retained in all copies and that this
* notice is included verbatim in any distributions. No written agreement,
* license, or royalty fee is required for any of the authorized uses.
* Modifications to this software may be copyrighted by their authors
* and need not follow the licensing terms described here, provided that
* the new terms are clearly indicated on the first page of each file where
* they apply.
*/
#include "sparclite.h"
#include "asm.h"
/* LED blinking pattern can be changed by modifying __led_algorithm. */
enum ledtype
{
led_marching, /* marching pattern, only one led on at a time */
led_random, /* pseudo-random pattern */
led_blinking, /* all leds blink on and off */
led_none /* leds off all the time */
};
enum ledtype __led_algorithm = led_marching;
/* Pointer to hook for outbyte, set by stub's exception handler. */
void (*__outbyte_hook) (int c);
#ifdef SL931
#define SDTR_BASE 0x200
#define SDTR_ASI 1
#define SDTR_SHIFT 0
#else
#define SDTR_BASE 0x10000000
#define SDTR_ASI 4
#define SDTR_SHIFT 16
#endif
#define get_uart_status(PORT) \
(read_asi (SDTR_ASI, SDTR_BASE + 0x24 + (PORT) * 0x10) >> SDTR_SHIFT)
#define xmt_char(PORT, C) \
write_asi (SDTR_ASI, SDTR_BASE + 0x20 + (PORT) * 0x10, (C) << SDTR_SHIFT)
#define rcv_char(PORT) \
(read_asi (SDTR_ASI, SDTR_BASE + 0x20 + (PORT) * 0x10) >> SDTR_SHIFT)
void putDebugChar();
#if 0
void
set_uart (cmd)
int cmd;
{
write_asi (SDTR_ASI, SDTR_BASE + 0x24, cmd << SDTR_SHIFT);
}
void
set_timer_3 (val)
int val;
{
write_asi (SDTR_ASI, SDTR_BASE + 0x78, val << SDTR_SHIFT);
}
#endif
asm("
.text
.align 4
! Register window overflow handler. Come here when save would move us
! into the invalid window. This routine runs with traps disabled, and
! must be careful not to touch the condition codes, as PSR is never
! restored.
!
! We are called with %l0 = wim, %l1 = pc, %l2 = npc
.globl " STRINGSYM(win_ovf) "
" STRINGSYM(win_ovf) ":
mov %g1, %l3 ! Save g1, we use it to hold the wim
srl %l0, 1, %g1 ! Rotate wim right
sll %l0, __WINSIZE-1, %l0
or %l0, %g1, %g1
save %g0, %g0, %g0 ! Slip into next window
mov %g1, %wim ! Install the new wim
std %l0, [%sp + 0 * 4] ! save L & I registers
std %l2, [%sp + 2 * 4]
std %l4, [%sp + 4 * 4]
std %l6, [%sp + 6 * 4]
std %i0, [%sp + 8 * 4]
std %i2, [%sp + 10 * 4]
std %i4, [%sp + 12 * 4]
std %i6, [%sp + 14 * 4]
restore ! Go back to trap window.
mov %l3, %g1 ! Restore %g1
jmpl %l1, %g0
rett %l2
! Register window underflow handler. Come here when restore would move us
! into the invalid window. This routine runs with traps disabled, and
! must be careful not to touch the condition codes, as PSR is never
! restored.
!
! We are called with %l0 = wim, %l1 = pc, %l2 = npc
.globl " STRINGSYM(win_unf) "
" STRINGSYM(win_unf) ":
sll %l0, 1, %l3 ! Rotate wim left
srl %l0, __WINSIZE-1, %l0
or %l0, %l3, %l0
mov %l0, %wim ! Install the new wim
restore ! User's window
restore ! His caller's window
ldd [%sp + 0 * 4], %l0 ! restore L & I registers
ldd [%sp + 2 * 4], %l2
ldd [%sp + 4 * 4], %l4
ldd [%sp + 6 * 4], %l6
ldd [%sp + 8 * 4], %i0
ldd [%sp + 10 * 4], %i2
ldd [%sp + 12 * 4], %i4
ldd [%sp + 14 * 4], %i6
save %g0, %g0, %g0 ! Back to trap window
save %g0, %g0, %g0
jmpl %l1, %g0
rett %l2
! Read the TBR.
.globl " STRINGSYM(rdtbr) "
" STRINGSYM(rdtbr) ":
retl
mov %tbr, %o0
");
extern unsigned long rdtbr();
void
die(val)
int val;
{
static unsigned char *leds = (unsigned char *)0x02000003;
*leds = val;
while (1) ;
}
/* Each entry in the trap vector occupies four words. */
struct trap_entry
{
unsigned sethi_filler:10;
unsigned sethi_imm22:22;
unsigned jmpl_filler:19;
unsigned jmpl_simm13:13;
unsigned long filler[2];
};
extern struct trap_entry fltr_proto;
asm ("
.data
.globl " STRINGSYM(fltr_proto) "
.align 4
" STRINGSYM(fltr_proto) ": ! First level trap routine prototype
sethi 0, %l0
jmpl 0+%l0, %g0
nop
nop
.text
.align 4
");
/* Setup trap TT to go to ROUTINE. If TT is between 0 and 255 inclusive, the
normal trap vector will be used. If TT is 256, then it's for the SPARClite
DSU, and that always vectors off to 255 unrelocated.
*/
void
exceptionHandler (tt, routine)
int tt;
unsigned long routine;
{
struct trap_entry *tb; /* Trap vector base address */
if (tt != 256)
tb = (struct trap_entry *) (rdtbr() & ~0xfff);
else
{
tt = 255;
tb = (struct trap_entry *) 0;
}
tb[tt] = fltr_proto;
tb[tt].sethi_imm22 = routine >> 10;
tb[tt].jmpl_simm13 = routine & 0x3ff;
}
void
update_leds()
{
static unsigned char *leds = (unsigned char *)0x02000003;
static enum ledtype prev_algorithm = led_none;
if (prev_algorithm != __led_algorithm)
{
*leds = 0xff; /* turn the LEDs off */
prev_algorithm = __led_algorithm;
}
switch (__led_algorithm)
{
case led_marching:
{
static unsigned char curled = 1;
static unsigned char dir = 0;
*leds = ~curled;
if (dir)
curled <<= 1;
else
curled >>= 1;
if (curled == 0)
{
if (dir)
curled = 0x80;
else
curled = 1;
dir = ~dir;
}
break;
}
case led_random:
{
static unsigned int next = 0;
*leds = next & 0xff;
next = (next * 1103515245 + 12345) & 0x7fff;
break;
}
case led_blinking:
{
static unsigned char next = 0;
*leds = next;
next = ~next;
break;
}
default:
break;
}
}
/* 1/5th of a second? */
#define LEDTIME (20000000 / 500)
unsigned long ledtime = LEDTIME;
int
inbyte()
{
return (getDebugChar());
}
int
getDebugChar()
{
unsigned long countdown = ledtime;
update_leds();
while (1)
{
if ((get_uart_status(0) & 2) != 0) break;
if (countdown-- == 0)
{
countdown = ledtime;
update_leds();
}
}
return rcv_char(0);
}
/* Output one character to the serial port */
void
outbyte(c)
int c;
{
if (__outbyte_hook)
__outbyte_hook (c);
else
putDebugChar(c);
}
void
putDebugChar(c)
int c;
{
update_leds();
while ((get_uart_status(0) & 1) == 0) ;
xmt_char(0, c);
}
#if 0
int
write(fd, data, length)
int fd;
unsigned char *data;
int length;
{
int olength = length;
while (length--)
putDebugChar(*data++);
return olength;
}
int
read(fd, data, length)
int fd;
unsigned char *data;
int length;
{
int olength = length;
int c;
while (length--)
*data++ = getDebugChar();
return olength;
}
#endif
/* Set the baud rate for the serial port, returns 0 for success,
-1 otherwise */
#if 0
int
set_baud_rate(baudrate)
int baudrate;
{
/* Convert baud rate to uart clock divider */
switch (baudrate)
{
case 38400:
baudrate = 16;
break;
case 19200:
baudrate = 33;
break;
case 9600:
baudrate = 65;
break;
default:
return -1;
}
set_timer_3(baudrate); /* Set it */
}
#endif