---------------------------------------------------------------------
---------------------------------------------------------------------
/* 
 * FILE
 *	@(#)syscalls.c	1.5 6/19/96
 *
 * DESCRIPTION
 *	This file contains source code for Cygnus GNU C compiler's low level 
 *	IO routines on SPARClite MB86930EB-01 evaluation board.
 *
 * HISTORY
 *	Thu Jul 21 15:36:38 JST 1994	Masaki Takashima
 *	Thu Oct 20 17:53:47 JST 1994	Masaki Takashima
 *	Fri Apr 14 10:13:50 JST 1995	Masaki Takashima
 *		Timing constant initialization
 */

#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/times.h>

void
update_leds()
{
  static unsigned char *leds = (unsigned char *)0x02000003;
  static unsigned char curled = 0xfe;
  *leds = curled;
  curled = (curled >> 1) | (curled << 7);
}

/*__main(){}*/

/* Operating system stubs */
int close(int file){return(-1);}
int open(char *filename, int mode){return(1);}
int execve(char *name, char **argv, char **env){errno=ENOMEM;return(-1);}
int fork() {errno=EAGAIN;return(-1);}
int fstat(int file, struct stat *st) {st->st_mode = S_IFCHR;return 0;}
int getpid() {return 1;}
int isatty(int file){return 1;}
int kill(int pid, int sig){errno=EINVAL;return(-1);}
int link(char *old, char *new){errno=EMLINK;return(-1);}
int lseek(int file, int ptr, int dir){return 0;}

caddr_t sbrk(int incr){
  extern char end;            /* Defined by the linker */
  static char *heap_end = 0;
  char *prev_heap_end;
  if (heap_end == 0) {
    heap_end = &end;
  }
  prev_heap_end = heap_end;
  heap_end += incr;
  return (caddr_t) prev_heap_end;
}

int stat(const char *file, struct stat *st) {st->st_mode = S_IFCHR;return 0;}

asm("
!
!	ASI4put(unsigned long data, unsigned long address);
!

        .global _ASI4put
_ASI4put:
        sta     %o0, [%o1] 4
        jmpl    %o7+8, %g0
        nop

!
! FUNCTION
!	_ASI4get
! DESCRIPTION
!	This function returns the 32 bit word in the location specified by the
!	caller in ASI 4.
! INPUTS
!	- %o0=address
! RETURNS
!	- Contents of [address] 4
!
	.global	_ASI4get
_ASI4get:
	jmpl	%o7+8, %g0
	  lda	[%o0] 4, %o0
");

void ASI4put();
unsigned long ASI4get();

static unsigned long prs_freq; 	/* Timer 1 prescaler output freq. */

Init_Get_uSec()
{
  unsigned long prescale; 	/* 940 timer 1 prescale reg */
  unsigned long reload; 	/* 940 timer 1 reload reg */
  unsigned long prsval; 	/* timer 1 prescale value */
  unsigned long select; 	/* timer 1 selector value */
  unsigned long freq; 		/* 940 input frequency */

  prescale = (ASI4get(0xffff6050));  	/* read 940 regs */
  reload   = (ASI4get(0xffff6058));
  prsval = prescale & 0xff;
  select = (prescale & 0x700) >> 8;
  select = 1 << select;
  freq = (reload + 1)  * select * prsval * 2;
  freq = ((freq + 500000) / 1000000) * 1000000; 	/* round */
  freq = freq / 2;
  prs_freq = freq / select / prsval;
  ASI4put((prs_freq-1), 0xffff6058);
  *(unsigned long *)0x30003ff8 = 0;			/* reset second */
}

/* Get_uSec() returns time in microsecond units. */
unsigned long Get_uSec(void) 
{
  unsigned long sec, usec, count;
  sec = *(unsigned long *) 0x30003ff8;
  count = prs_freq - (ASI4get(0xffff605c));
                               /* exp.-> sec*1000000+count/prs_freq*1000000 */
  usec = (sec*1000000)+(((count*100000)/prs_freq)*10) ;
#if 0
  printf("sec %d count %d usec %d\n", sec, count, usec);
#endif
  return(usec);
}

clock_t times(struct tms *buf){
  buf->tms_utime = (clock_t)((double)Get_uSec()*(double)60/(double)1000000);
  buf->tms_stime = (clock_t)0;
  buf->tms_cutime = (clock_t)0;
  buf->tms_cstime = (clock_t)0;
  return 0;
}

int unlink(char *name){errno=ENOENT;return(-1);}
int wait(int *status) {errno=ECHILD;return(-1);}

asm("
	.text
	.align 4
	.globl _get_uart1_status
_get_uart1_status:
	set 0xffff6037, %o0
	retl
	  lduba [%o0] 4, %o0

	.globl _xmt_char1
_xmt_char1:
	set 0xffff6033, %o1
	retl
	  stba %o0, [%o1] 4

	.globl _rcv_char1
_rcv_char1:
	set 0xffff6033, %o0
	retl
	  lduba [%o0] 4, %o0
");

#define LEDTIME (20000000 / 500)
int getCharPort1()
{
  unsigned long countdown = LEDTIME;
  update_leds();
  while (1) {
    if ((get_uart1_status(0) & 2) != 0) break;
    if (countdown-- == 0) {
      countdown = LEDTIME;
      update_leds();
    }
  }
  return rcv_char1();
}

/* Output one character to the serial port */

void putCharPort1(int c)
{
  update_leds();
  while ((get_uart1_status() & 1) == 0);
  xmt_char1(c);
}

int write(int fd, unsigned char *data, int length)
{
  int olength = length;

  while (length--)
    putCharPort1(*data++);
  return olength;
}

int read(int fd, unsigned char *data, int length)
{
  int olength = length;
  int c;

  while (length--)
    *data++ = getCharPort1();
  return olength;
}

void _exit(){
  asm(" mov 1,%o0
        sethi %hi(ctrl_d),%o1
        or %o1,%lo(ctrl_d),%o1
        call _write,0
        mov 1,%o2
        jmp %g0		! go to Boot rom
        nop   

        .align 8
ctrl_d:
        .byte 4,0
     ");
}

