389 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			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
 |