| /* 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 |