2015-03-22 17:30:10 +00:00
|
|
|
/*******************************************************************************
|
|
|
|
' Author: Dave Hein
|
2018-06-19 14:00:25 +00:00
|
|
|
' Version 0.99
|
2018-04-14 16:31:57 +00:00
|
|
|
' Copyright (c) 2010 - 2018
|
2015-03-22 17:30:10 +00:00
|
|
|
' See end of file for terms of use.
|
|
|
|
'******************************************************************************/
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <dirent.h>
|
|
|
|
#include <sys/stat.h>
|
2018-04-13 02:20:22 +00:00
|
|
|
#include "spinsim.h"
|
2015-03-22 17:30:10 +00:00
|
|
|
#include "conion.h"
|
|
|
|
#include "interp.h"
|
|
|
|
#include "rom.h"
|
|
|
|
#include "spindebug.h"
|
|
|
|
#include "eeprom.h"
|
|
|
|
|
|
|
|
#define SYS_CON_PUTCH 1
|
|
|
|
#define SYS_CON_GETCH 2
|
|
|
|
#define SYS_FILE_OPEN 3
|
|
|
|
#define SYS_FILE_CLOSE 4
|
|
|
|
#define SYS_FILE_READ 5
|
|
|
|
#define SYS_FILE_WRITE 6
|
|
|
|
#define SYS_FILE_OPENDIR 7
|
|
|
|
#define SYS_FILE_CLOSEDIR 8
|
|
|
|
#define SYS_FILE_READDIR 9
|
|
|
|
#define SYS_FILE_SEEK 10
|
|
|
|
#define SYS_FILE_TELL 11
|
|
|
|
#define SYS_FILE_REMOVE 12
|
|
|
|
#define SYS_FILE_CHDIR 13
|
|
|
|
#define SYS_FILE_GETCWD 14
|
|
|
|
#define SYS_FILE_MKDIR 15
|
|
|
|
#define SYS_FILE_GETMOD 16
|
|
|
|
#define SYS_EXTMEM_READ 17
|
|
|
|
#define SYS_EXTMEM_WRITE 18
|
|
|
|
#define SYS_EXTMEM_ALLOC 19
|
|
|
|
|
|
|
|
#define GCC_REG_BASE 0
|
|
|
|
|
|
|
|
static char rootdir[100];
|
|
|
|
char *hubram;
|
|
|
|
char *extram[4];
|
|
|
|
int32_t extmemsize[4];
|
|
|
|
uint32_t extmembase[4];
|
|
|
|
int32_t extmemnum = 0;
|
2018-04-13 02:20:22 +00:00
|
|
|
char lockstate[16];
|
|
|
|
char lockalloc[16];
|
2015-03-22 17:30:10 +00:00
|
|
|
|
|
|
|
char objname[100][20];
|
|
|
|
int32_t methodnum[100];
|
|
|
|
int32_t methodlev = 0;
|
|
|
|
|
|
|
|
int32_t printflag = 0;
|
|
|
|
int32_t symflag = 0;
|
|
|
|
int32_t pasmspin = 0;
|
|
|
|
int32_t profile = 0;
|
|
|
|
int32_t memsize = 64;
|
|
|
|
int32_t cycleaccurate = 0;
|
|
|
|
int32_t loopcount = 0;
|
2018-04-13 02:20:22 +00:00
|
|
|
int32_t propmode = 0;
|
2015-03-22 17:30:10 +00:00
|
|
|
int32_t baudrate = 0;
|
2018-04-13 02:20:22 +00:00
|
|
|
int32_t pin_val_a = -1;
|
|
|
|
int32_t pin_val_b = -1;
|
2015-03-22 17:30:10 +00:00
|
|
|
int32_t gdbmode = 0;
|
|
|
|
int32_t eeprom = 0;
|
|
|
|
int32_t debugmode = 0;
|
|
|
|
int32_t printbreak = 0;
|
2018-04-13 02:20:22 +00:00
|
|
|
SerialT serial_in;
|
|
|
|
SerialT serial_out;
|
|
|
|
int32_t fjmpflag = 0;
|
|
|
|
int32_t nohubslots = 0;
|
|
|
|
int32_t pstmode = 0;
|
|
|
|
int32_t kludge = 0;
|
2015-03-22 17:30:10 +00:00
|
|
|
|
|
|
|
FILE *logfile = NULL;
|
|
|
|
FILE *tracefile = NULL;
|
2018-10-22 17:15:56 +00:00
|
|
|
FILE *serialfile = NULL;
|
2015-03-22 17:30:10 +00:00
|
|
|
FILE *cmdfile = NULL;
|
|
|
|
|
2018-04-13 02:20:22 +00:00
|
|
|
PasmVarsT PasmVars[16];
|
2015-03-22 17:30:10 +00:00
|
|
|
|
|
|
|
void PrintOp(SpinVarsT *spinvars);
|
|
|
|
void ExecuteOp(SpinVarsT *spinvars);
|
|
|
|
char *FindChar(char *str, int32_t val);
|
|
|
|
void Debug(void);
|
|
|
|
int32_t RunProp(int32_t maxloops);
|
|
|
|
void gdb(void);
|
2018-04-13 02:20:22 +00:00
|
|
|
void UpdateRWlongFlags(void);
|
2015-03-22 17:30:10 +00:00
|
|
|
|
|
|
|
void spinsim_exit(int32_t exitcode)
|
|
|
|
{
|
2018-04-13 02:20:22 +00:00
|
|
|
#ifndef __MINGW32__
|
|
|
|
restore_console_io();
|
|
|
|
#endif
|
2015-03-22 17:30:10 +00:00
|
|
|
exit(exitcode);
|
|
|
|
}
|
|
|
|
|
|
|
|
void usage(void)
|
|
|
|
{
|
2018-06-19 14:00:25 +00:00
|
|
|
fprintf(stderr, "Spinsim Version 0.99\n");
|
2015-03-22 17:30:10 +00:00
|
|
|
fprintf(stderr, "usage: spinsim [options] file\n");
|
|
|
|
fprintf(stderr, "The options are as follows:\n");
|
|
|
|
fprintf(stderr, " -v# Set verbosity level\n");
|
|
|
|
//fprintf(stderr, " -l List executed instructions\n");
|
|
|
|
fprintf(stderr, " -l <filename> List executed instructions to <filename>\n");
|
|
|
|
fprintf(stderr, " -p Use PASM Spin interpreter\n");
|
|
|
|
fprintf(stderr, " -# Execute # instructions\n");
|
|
|
|
fprintf(stderr, " -P Profile Spin opcode usage\n");
|
|
|
|
fprintf(stderr, " -m# Set the hub memory size to # K-bytes\n");
|
|
|
|
//fprintf(stderr, " -c Enable cycle-accurate mode for pasm cogs\n");
|
2018-04-13 02:20:22 +00:00
|
|
|
fprintf(stderr, " -t# Enable the Prop 2 mode. # specifies options\n");
|
2015-03-22 17:30:10 +00:00
|
|
|
fprintf(stderr, " -b# Enable the serial port and set the baudrate to # (default 115200)\n");
|
2018-10-22 17:15:56 +00:00
|
|
|
fprintf(stderr, " -B <filename> Redirects serial output to filename\n");
|
2015-03-22 17:30:10 +00:00
|
|
|
fprintf(stderr, " -gdb Operate as a GDB target over stdin/stdout\n");
|
|
|
|
fprintf(stderr, " -L <filename> Log GDB remote comm to <filename>\n");
|
|
|
|
fprintf(stderr, " -r <filename> Replay GDB session from <filename>\n");
|
|
|
|
//fprintf(stderr, " -x# Set the external memory size to # K-bytes\n");
|
|
|
|
fprintf(stderr, " -e Use eeprom.dat\n");
|
|
|
|
fprintf(stderr, " -d Use debugger\n");
|
2018-04-13 02:20:22 +00:00
|
|
|
fprintf(stderr, " -pst Use PST mode\n");
|
2015-03-22 17:30:10 +00:00
|
|
|
spinsim_exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void putchx(int32_t val)
|
|
|
|
{
|
|
|
|
putchar(val);
|
2018-10-22 17:28:10 +00:00
|
|
|
fflush(tracefile);
|
2015-03-22 17:30:10 +00:00
|
|
|
}
|
|
|
|
|
2018-10-22 17:15:56 +00:00
|
|
|
void putschx(int32_t val)
|
|
|
|
{
|
|
|
|
fputc(val, serialfile);
|
|
|
|
fflush(serialfile);
|
|
|
|
}
|
|
|
|
|
2018-04-13 02:20:22 +00:00
|
|
|
#if 0
|
2015-03-22 17:30:10 +00:00
|
|
|
int32_t getchx(void)
|
|
|
|
{
|
|
|
|
uint8_t val = 0;
|
|
|
|
// GCC compiler issues warning for ignored fread return value
|
|
|
|
if(fread(&val, 1, 1, cmdfile /*stdin*/))
|
|
|
|
if (val == 10) val = 13;
|
|
|
|
return val;
|
|
|
|
}
|
2018-04-13 02:20:22 +00:00
|
|
|
#endif
|
2015-03-22 17:30:10 +00:00
|
|
|
|
|
|
|
char *FindExtMem(uint32_t addr, int32_t num)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
char *ptr = 0;
|
|
|
|
uint32_t addr1 = addr + num - 1;
|
|
|
|
uint32_t curraddr, curraddr1;
|
|
|
|
|
|
|
|
//fprintf(stderr, "FindExtMem(%d, %d)\n", addr, num);
|
|
|
|
|
|
|
|
for (i = 0; i < extmemnum; i++)
|
|
|
|
{
|
|
|
|
//fprintf(stderr, "i = %d\n", i);
|
|
|
|
curraddr = extmembase[i];
|
|
|
|
curraddr1 = curraddr + extmemsize[i] - 1;
|
|
|
|
if (curraddr <= addr && addr <= curraddr1)
|
|
|
|
{
|
|
|
|
//fprintf(stderr, "1: %d %d %d\n", addr, curraddr, curraddr1);
|
|
|
|
//fprintf(stderr, "2: %d %d %d\n", addr1, curraddr, curraddr1);
|
|
|
|
if (curraddr <= addr1 && addr1 <= curraddr1)
|
|
|
|
ptr = extram[i] + addr - extmembase[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This routine prevents us from calling kbhit too often. This improves
|
|
|
|
// the performance of the simulator when calling kbhit in a tight loop.
|
|
|
|
int kbhit1(void)
|
|
|
|
{
|
|
|
|
static int last = 0;
|
|
|
|
|
|
|
|
if (loopcount - last < 6000) return 0;
|
|
|
|
last = loopcount;
|
|
|
|
return kbhit();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CheckCommand(void)
|
|
|
|
{
|
|
|
|
int32_t parm;
|
|
|
|
int32_t command = WORD(SYS_COMMAND);
|
|
|
|
FILE *stream;
|
|
|
|
DIR *pdir;
|
|
|
|
struct dirent *pdirent;
|
|
|
|
|
|
|
|
if (!command) return;
|
|
|
|
|
|
|
|
parm = LONG(SYS_PARM);
|
|
|
|
|
|
|
|
if (command == SYS_CON_PUTCH)
|
|
|
|
{
|
|
|
|
if (parm == 13)
|
|
|
|
putchx(10);
|
|
|
|
else
|
|
|
|
putchx(parm);
|
|
|
|
}
|
|
|
|
else if (command == SYS_CON_GETCH)
|
|
|
|
{
|
|
|
|
if (kbhit1())
|
|
|
|
parm = getch();
|
|
|
|
else
|
|
|
|
parm = -1;
|
|
|
|
LONG(SYS_PARM) = parm;
|
|
|
|
}
|
|
|
|
else if (command == SYS_FILE_OPEN)
|
|
|
|
{
|
|
|
|
char *fname;
|
|
|
|
char *fmode;
|
|
|
|
|
|
|
|
fname = (char *)&BYTE(LONG(parm));
|
|
|
|
fmode = (char *)&BYTE(LONG(parm+4));
|
|
|
|
stream = fopen(fname, fmode);
|
|
|
|
LONG(SYS_PARM) = (long)stream;
|
|
|
|
}
|
|
|
|
else if (command == SYS_FILE_CLOSE)
|
|
|
|
{
|
|
|
|
if (parm) fclose((FILE *)(long)parm);
|
|
|
|
LONG(SYS_PARM) = 0;
|
|
|
|
}
|
|
|
|
else if (command == SYS_FILE_READ)
|
|
|
|
{
|
|
|
|
int32_t num;
|
|
|
|
char *buffer;
|
|
|
|
|
|
|
|
if (!parm) LONG(SYS_PARM) = -1;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
stream = (FILE *)(long)LONG(parm);
|
|
|
|
buffer = (char *)&BYTE(LONG(parm+4));
|
|
|
|
num = LONG(parm+8);
|
|
|
|
LONG(SYS_PARM) = fread(buffer, 1, num, stream);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (command == SYS_FILE_WRITE)
|
|
|
|
{
|
|
|
|
int32_t num;
|
|
|
|
char *buffer;
|
|
|
|
|
|
|
|
if (!parm) LONG(SYS_PARM) = -1;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
stream = (FILE *)(long)LONG(parm);
|
|
|
|
buffer = (char *)&BYTE(LONG(parm+4));
|
|
|
|
num = LONG(parm+8);
|
|
|
|
LONG(SYS_PARM) = fwrite(buffer, 1, num, stream);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (command == SYS_FILE_OPENDIR)
|
|
|
|
{
|
|
|
|
char *dname = ".";
|
|
|
|
|
|
|
|
pdir = opendir(dname);
|
|
|
|
LONG(SYS_PARM) = (long)pdir;
|
|
|
|
}
|
|
|
|
else if (command == SYS_FILE_CLOSEDIR)
|
|
|
|
{
|
|
|
|
if (parm) closedir((DIR *)(long)parm);
|
|
|
|
LONG(SYS_PARM) = 0;
|
|
|
|
}
|
|
|
|
else if (command == SYS_FILE_READDIR)
|
|
|
|
{
|
|
|
|
int32_t *buffer;
|
|
|
|
pdir = (DIR *)(long)LONG(parm);
|
|
|
|
buffer = (int32_t *)&BYTE(LONG(parm+4));
|
|
|
|
if (!pdir) LONG(SYS_PARM) = 0;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pdirent = readdir(pdir);
|
|
|
|
if (pdirent)
|
|
|
|
{
|
2018-04-13 02:20:22 +00:00
|
|
|
#if 1
|
2015-03-22 17:30:10 +00:00
|
|
|
FILE *infile;
|
|
|
|
int32_t d_size = 0;
|
|
|
|
int32_t d_attr = 0;
|
|
|
|
#if 0
|
|
|
|
int32_t d_type = pdirent->d_type;
|
|
|
|
|
|
|
|
if (d_type & DT_DIR) d_attr |= 0x10;
|
|
|
|
if (d_type & S_IXUSR) d_attr |= 0x20;
|
|
|
|
if (!(d_type & S_IWUSR)) d_attr |= 0x01;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if ((infile = fopen(pdirent->d_name, "r")))
|
|
|
|
{
|
|
|
|
fseek(infile, 0, SEEK_END);
|
|
|
|
d_size = ftell(infile);
|
|
|
|
fclose(infile);
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer[0] = d_size;
|
|
|
|
buffer[1] = d_attr;
|
|
|
|
#else
|
|
|
|
buffer[0] = pdirent->d_size;
|
|
|
|
buffer[1] = pdirent->d_attr;
|
|
|
|
#endif
|
|
|
|
strcpy((char *)&buffer[2], pdirent->d_name);
|
|
|
|
}
|
|
|
|
LONG(SYS_PARM) = (long)pdirent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (command == SYS_FILE_SEEK)
|
|
|
|
{
|
|
|
|
int32_t offset, whence;
|
|
|
|
stream = (FILE *)(long)LONG(parm);
|
|
|
|
offset = LONG(parm+4);
|
|
|
|
whence = LONG(parm+8);
|
|
|
|
LONG(SYS_PARM) = fseek(stream, offset, whence);
|
|
|
|
}
|
|
|
|
else if (command == SYS_FILE_TELL)
|
|
|
|
{
|
|
|
|
stream = (FILE *)(long)parm;
|
|
|
|
LONG(SYS_PARM) = ftell(stream);
|
|
|
|
}
|
|
|
|
else if (command == SYS_FILE_REMOVE)
|
|
|
|
{
|
|
|
|
char *fname = (char *)&BYTE(parm);
|
|
|
|
LONG(SYS_PARM) = remove(fname);
|
|
|
|
}
|
|
|
|
else if (command == SYS_FILE_CHDIR)
|
|
|
|
{
|
|
|
|
char *path = (char *)&BYTE(parm);
|
|
|
|
char fullpath[200];
|
|
|
|
if (path[0] == '/')
|
|
|
|
{
|
|
|
|
strcpy(fullpath, rootdir);
|
|
|
|
strcat(fullpath, path);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
strcpy(fullpath, path);
|
|
|
|
|
2018-04-13 02:20:22 +00:00
|
|
|
#if 0
|
|
|
|
char *ptr = fullpath;
|
2015-03-22 17:30:10 +00:00
|
|
|
while (*ptr)
|
|
|
|
{
|
|
|
|
if (*ptr == '/') *ptr = 0x5c;
|
|
|
|
ptr++;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
parm = chdir(fullpath);
|
|
|
|
LONG(SYS_PARM) = parm;
|
|
|
|
}
|
|
|
|
else if (command == SYS_FILE_GETCWD)
|
|
|
|
{
|
|
|
|
char *str = (char *)&BYTE(LONG(parm));
|
|
|
|
int32_t num = LONG(parm+4);
|
2018-04-13 02:20:22 +00:00
|
|
|
getcwd(str, num);
|
2015-03-22 17:30:10 +00:00
|
|
|
LONG(SYS_PARM) = LONG(parm);
|
|
|
|
}
|
|
|
|
else if (command == SYS_FILE_MKDIR)
|
|
|
|
{
|
|
|
|
#if 0
|
2018-04-13 02:20:22 +00:00
|
|
|
char *fname = (char *)&BYTE(parm);
|
2015-03-22 17:30:10 +00:00
|
|
|
LONG(SYS_PARM) = mkdir(fname);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else if (command == SYS_FILE_GETMOD)
|
|
|
|
{
|
|
|
|
char *fname = (char *)&BYTE(parm);
|
|
|
|
int32_t attrib = -1;
|
|
|
|
|
|
|
|
pdir = opendir(".");
|
|
|
|
while (pdir)
|
|
|
|
{
|
|
|
|
pdirent = readdir(pdir);
|
|
|
|
if (!pdirent) break;
|
|
|
|
if (strcmp(pdirent->d_name, fname) == 0)
|
|
|
|
{
|
2018-04-13 02:20:22 +00:00
|
|
|
#if 1
|
2015-03-22 17:30:10 +00:00
|
|
|
#if 0
|
|
|
|
int32_t d_type = pdirent->d_type;
|
|
|
|
attrib = 0;
|
|
|
|
if (d_type & DT_DIR) attrib |= 0x10;
|
|
|
|
if (d_type & S_IXUSR) attrib |= 0x20;
|
|
|
|
if (!(d_type & S_IWUSR)) attrib |= 0x01;
|
|
|
|
#else
|
|
|
|
attrib = 0;
|
|
|
|
#endif
|
|
|
|
#else
|
|
|
|
attrib = pdirent->d_attr;
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (pdir) closedir(pdir);
|
|
|
|
LONG(SYS_PARM) = attrib;
|
|
|
|
}
|
|
|
|
else if (command == SYS_EXTMEM_READ)
|
|
|
|
{
|
|
|
|
uint32_t extaddr = (uint32_t)LONG(parm);
|
|
|
|
char *hubaddr = (char *)&BYTE(LONG(parm+4));
|
|
|
|
int32_t num = LONG(parm+8);
|
|
|
|
char *extmemptr = FindExtMem(extaddr, num);
|
|
|
|
if (extmemptr)
|
|
|
|
{
|
|
|
|
memcpy(hubaddr, extmemptr, num);
|
|
|
|
LONG(SYS_PARM) = num;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LONG(SYS_PARM) = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (command == SYS_EXTMEM_WRITE)
|
|
|
|
{
|
|
|
|
uint32_t extaddr = (int32_t)LONG(parm);
|
|
|
|
char *hubaddr = (char *)&BYTE(LONG(parm+4));
|
|
|
|
int32_t num = LONG(parm+8);
|
|
|
|
char *extmemptr = FindExtMem(extaddr, num);
|
|
|
|
if (extmemptr)
|
|
|
|
{
|
|
|
|
memcpy(extmemptr, hubaddr, num);
|
|
|
|
LONG(SYS_PARM) = num;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LONG(SYS_PARM) = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (command == SYS_EXTMEM_ALLOC)
|
|
|
|
{
|
|
|
|
uint32_t extaddr = (int32_t)LONG(parm);
|
|
|
|
int32_t num = LONG(parm+4);
|
|
|
|
uint32_t extaddr1 = extaddr + num - 1;
|
|
|
|
|
|
|
|
if (num <= 0 || extmemnum >= 4) num = 0;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
uint32_t curraddr, curraddr1;
|
|
|
|
for (i = 0; i < extmemnum; i++)
|
|
|
|
{
|
|
|
|
curraddr = extmembase[i];
|
|
|
|
curraddr1 = curraddr + extmemsize[i] - 1;
|
|
|
|
if (curraddr <= extaddr && extaddr <= curraddr1) break;
|
|
|
|
if (curraddr <= extaddr1 && extaddr1 <= curraddr1) break;
|
|
|
|
if (extaddr <= curraddr && curraddr <= extaddr1) break;
|
|
|
|
if (extaddr <= curraddr1 && curraddr1 <= extaddr1) break;
|
|
|
|
}
|
|
|
|
if (i != extmemnum) num = 0;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
extram[extmemnum] = malloc(num);
|
|
|
|
if (extram[extmemnum] == 0) num = 0;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
extmemsize[extmemnum] = num;
|
|
|
|
extmembase[extmemnum] = extaddr;
|
|
|
|
extmemnum++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
LONG(SYS_PARM) = num;
|
|
|
|
}
|
|
|
|
WORD(SYS_COMMAND) = 0;
|
|
|
|
}
|
|
|
|
|
2018-04-13 02:20:22 +00:00
|
|
|
void SerialInit(SerialT *serial, int pin_num, int bitcycles, int mode)
|
2015-03-22 17:30:10 +00:00
|
|
|
{
|
2018-04-13 02:20:22 +00:00
|
|
|
serial->flag = 0;
|
|
|
|
serial->state = 0;
|
|
|
|
serial->count = 0;
|
|
|
|
serial->mode = mode;
|
|
|
|
serial->pin_num = pin_num;
|
|
|
|
serial->bitcycles = bitcycles;
|
|
|
|
}
|
|
|
|
|
|
|
|
int SerialSend(SerialT *serial, int portval)
|
|
|
|
{
|
|
|
|
int bitval;
|
|
|
|
int flipbit = serial->mode & 1;
|
|
|
|
int pin_num = serial->pin_num;
|
2015-03-22 17:30:10 +00:00
|
|
|
|
2018-04-13 02:20:22 +00:00
|
|
|
if (serial->state == 0)
|
2015-03-22 17:30:10 +00:00
|
|
|
{
|
2018-04-13 02:20:22 +00:00
|
|
|
if (serial->flag)
|
2015-03-22 17:30:10 +00:00
|
|
|
{
|
2018-04-13 02:20:22 +00:00
|
|
|
serial->value |= 0x300;
|
|
|
|
serial->count = serial->bitcycles;
|
|
|
|
portval = (portval & ~(1 << pin_num)) | (flipbit << pin_num);
|
|
|
|
serial->state = 1;
|
|
|
|
//printf("portval = %8.8x\n", portval);
|
2015-03-22 17:30:10 +00:00
|
|
|
}
|
|
|
|
}
|
2018-04-13 02:20:22 +00:00
|
|
|
else if (--serial->count <= 0)
|
2015-03-22 17:30:10 +00:00
|
|
|
{
|
2018-04-13 02:20:22 +00:00
|
|
|
if (++serial->state > 11)
|
2015-03-22 17:30:10 +00:00
|
|
|
{
|
2018-04-13 02:20:22 +00:00
|
|
|
serial->flag = 0;
|
|
|
|
serial->state = 0;
|
2015-03-22 17:30:10 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-04-13 02:20:22 +00:00
|
|
|
bitval = (serial->value & 1) ^ flipbit;
|
|
|
|
portval = (portval & ~(1 << pin_num)) | (bitval << pin_num);
|
|
|
|
serial->value >>= 1;
|
|
|
|
serial->count = serial->bitcycles;
|
|
|
|
//printf("portval = %8.8x\n", portval);
|
2015-03-22 17:30:10 +00:00
|
|
|
}
|
|
|
|
}
|
2018-04-13 02:20:22 +00:00
|
|
|
return portval;
|
2015-03-22 17:30:10 +00:00
|
|
|
}
|
|
|
|
|
2018-04-13 02:20:22 +00:00
|
|
|
int CheckSerialIn(SerialT *serial)
|
2015-03-22 17:30:10 +00:00
|
|
|
{
|
2018-04-13 02:20:22 +00:00
|
|
|
int value;
|
2015-03-22 17:30:10 +00:00
|
|
|
|
2018-04-13 02:20:22 +00:00
|
|
|
if (propmode == 2)
|
|
|
|
pin_val_b = SerialSend(serial, pin_val_b);
|
|
|
|
else
|
|
|
|
pin_val_a = SerialSend(serial, pin_val_a);
|
|
|
|
if (!serial->flag && kbhit1())
|
|
|
|
{
|
|
|
|
value = getch();
|
|
|
|
//printf("CheckSerialIn: value = %x\n", value);
|
|
|
|
if (value == 0x1d) return 1;
|
|
|
|
serial->flag = 1;
|
|
|
|
serial->value = value;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SerialReceive(SerialT *serial, int portval)
|
|
|
|
{
|
|
|
|
int bitval = ((portval >> serial->pin_num) & 1) ^ (serial->mode & 1);
|
2015-03-22 17:30:10 +00:00
|
|
|
|
2018-04-13 02:20:22 +00:00
|
|
|
if (serial->state == 0)
|
2015-03-22 17:30:10 +00:00
|
|
|
{
|
2018-04-13 02:20:22 +00:00
|
|
|
if (bitval)
|
|
|
|
serial->state = 1;
|
2015-03-22 17:30:10 +00:00
|
|
|
}
|
2018-04-13 02:20:22 +00:00
|
|
|
else if (serial->state == 1)
|
2015-03-22 17:30:10 +00:00
|
|
|
{
|
2018-04-13 02:20:22 +00:00
|
|
|
if (!bitval)
|
2015-03-22 17:30:10 +00:00
|
|
|
{
|
2018-04-13 02:20:22 +00:00
|
|
|
serial->value = 0;
|
|
|
|
serial->state = 2;
|
|
|
|
serial->count = serial->bitcycles;
|
|
|
|
serial->count += serial->count >> 1;
|
2015-03-22 17:30:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-04-13 02:20:22 +00:00
|
|
|
if (--serial->count <= 0)
|
2015-03-22 17:30:10 +00:00
|
|
|
{
|
2018-04-13 02:20:22 +00:00
|
|
|
if (serial->state > 9)
|
2015-03-22 17:30:10 +00:00
|
|
|
{
|
2018-04-13 02:20:22 +00:00
|
|
|
serial->flag = 1;
|
|
|
|
serial->state = 1;
|
2015-03-22 17:30:10 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-04-13 02:20:22 +00:00
|
|
|
serial->value |= bitval << (serial->state - 2);
|
|
|
|
serial->count = serial->bitcycles;
|
|
|
|
serial->state++;
|
2015-03-22 17:30:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-13 02:20:22 +00:00
|
|
|
void CheckSerialOut(SerialT *serial)
|
|
|
|
{
|
|
|
|
if (propmode == 2)
|
|
|
|
SerialReceive(serial, pin_val_b);
|
|
|
|
else
|
|
|
|
SerialReceive(serial, pin_val_a);
|
|
|
|
if (serial->flag)
|
|
|
|
{
|
|
|
|
serial->flag = 0;
|
|
|
|
if (serial->value == 13 && pstmode)
|
2018-10-22 17:15:56 +00:00
|
|
|
putschx(10);
|
2018-04-13 02:20:22 +00:00
|
|
|
else
|
2018-10-22 17:15:56 +00:00
|
|
|
putschx(serial->value);
|
2018-04-13 02:20:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-22 17:30:10 +00:00
|
|
|
void PrintStack(SpinVarsT *spinvars)
|
|
|
|
{
|
|
|
|
int32_t dcurr = spinvars->dcurr;
|
2018-04-13 02:20:22 +00:00
|
|
|
printf("PrintStack: %4.4x %8.8x %8.8x %8.8x%s",
|
|
|
|
dcurr, LONG(dcurr-4), LONG(dcurr-8), LONG(dcurr-12), NEW_LINE);
|
2015-03-22 17:30:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
char *bootfile;
|
|
|
|
|
|
|
|
void RebootProp(void)
|
|
|
|
{
|
|
|
|
int32_t i;
|
|
|
|
int32_t dbase;
|
|
|
|
char *ptr;
|
|
|
|
FILE *infile;
|
2018-04-13 02:20:22 +00:00
|
|
|
int32_t bitcycles;
|
2015-03-22 17:30:10 +00:00
|
|
|
|
2018-04-13 02:20:22 +00:00
|
|
|
if (!propmode) memset(hubram, 0, 32768);
|
|
|
|
memset(lockstate, 0, 16);
|
|
|
|
memset(lockalloc, 0, 16);
|
2015-03-22 17:30:10 +00:00
|
|
|
|
|
|
|
chdir(rootdir);
|
|
|
|
|
|
|
|
if(!gdbmode && eeprom){
|
|
|
|
EEPromCopy(hubram);
|
|
|
|
} else
|
|
|
|
if(!gdbmode){
|
|
|
|
infile = fopen(bootfile, "rb");
|
|
|
|
|
|
|
|
if (infile == 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Could not open %s\n", bootfile);
|
|
|
|
spinsim_exit(1);
|
|
|
|
}
|
|
|
|
|
2018-04-13 02:20:22 +00:00
|
|
|
i = fread(hubram, 1, memsize, infile);
|
2015-03-22 17:30:10 +00:00
|
|
|
fclose(infile);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Copy in the ROM contents
|
2018-04-13 02:20:22 +00:00
|
|
|
if (!propmode)
|
2015-03-22 17:30:10 +00:00
|
|
|
{
|
|
|
|
memcpy(hubram + 32768, romdata, 32768);
|
|
|
|
dbase = WORD(10);
|
|
|
|
LONG(dbase-8) = 0xfff9ffff;
|
|
|
|
LONG(dbase-4) = 0xfff9ffff;
|
|
|
|
LONG(dbase) = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
WORD(SYS_COMMAND) = 0;
|
|
|
|
WORD(SYS_LOCKNUM) = 1;
|
|
|
|
lockalloc[0] = 1;
|
|
|
|
|
2018-04-13 02:20:22 +00:00
|
|
|
for (i = 0; i < 16; i++) PasmVars[i].state = 0;
|
2015-03-22 17:30:10 +00:00
|
|
|
|
|
|
|
if (pasmspin)
|
|
|
|
{
|
2018-04-13 02:20:22 +00:00
|
|
|
if (propmode == 2)
|
|
|
|
{
|
|
|
|
//StartPasmCog2(&PasmVars[0], 0, 0x0e00, 0);
|
|
|
|
StartPasmCog2(&PasmVars[0], 0, 0x0000, 0, 0);
|
|
|
|
}
|
2015-03-22 17:30:10 +00:00
|
|
|
else
|
|
|
|
StartPasmCog(&PasmVars[0], 0x0004, 0xf004, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
StartCog((SpinVarsT *)&PasmVars[0].mem[0x1e0], 4, 0);
|
|
|
|
|
|
|
|
if(!gdbmode){
|
|
|
|
strcpy(objname[0], "xxx");
|
|
|
|
if (bootfile)
|
|
|
|
strcpy(objname[1], bootfile);
|
|
|
|
else
|
|
|
|
strcpy(objname[1], "");
|
|
|
|
ptr = FindChar(objname[1], '.');
|
|
|
|
if (*ptr)
|
|
|
|
{
|
|
|
|
*ptr = 0;
|
|
|
|
if (symflag && strcmp(ptr + 1, "bin") == 0)
|
|
|
|
symflag = 2;
|
|
|
|
}
|
|
|
|
if (symflag == 2)
|
|
|
|
strcat(objname[1], ".spn");
|
|
|
|
else
|
|
|
|
strcat(objname[1], ".spin");
|
|
|
|
methodnum[0] = 1;
|
|
|
|
methodnum[1] = 1;
|
|
|
|
methodlev = 1;
|
|
|
|
}
|
|
|
|
|
2018-04-13 02:20:22 +00:00
|
|
|
|
|
|
|
if (baudrate)
|
|
|
|
{
|
|
|
|
if (propmode)
|
2018-04-14 16:31:57 +00:00
|
|
|
bitcycles = 80000000 / baudrate;
|
2018-04-13 02:20:22 +00:00
|
|
|
else
|
|
|
|
bitcycles = (LONG(0) / baudrate) >> 2;
|
|
|
|
SerialInit(&serial_in, 31, bitcycles, 2);
|
|
|
|
SerialInit(&serial_out, 30, bitcycles, 2);
|
|
|
|
}
|
2015-03-22 17:30:10 +00:00
|
|
|
//LONG(SYS_DEBUG) = printflag;
|
|
|
|
}
|
|
|
|
|
|
|
|
int step_chip(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int state;
|
|
|
|
int runflag = 0;
|
|
|
|
int breakflag = 0;
|
|
|
|
SpinVarsT *spinvars;
|
2018-04-13 02:20:22 +00:00
|
|
|
if (propmode == 2) UpdateRWlongFlags();
|
|
|
|
for (i = 0; i < 16; i++)
|
2015-03-22 17:30:10 +00:00
|
|
|
{
|
|
|
|
state = PasmVars[i].state;
|
|
|
|
PasmVars[i].printflag = (LONG(SYS_DEBUG) >> (i*4)) & 15;
|
|
|
|
if (state & 4)
|
|
|
|
{
|
|
|
|
if (PasmVars[i].printflag && state == 5)
|
|
|
|
{
|
2018-04-13 02:20:22 +00:00
|
|
|
if (!propmode)
|
2015-03-22 17:30:10 +00:00
|
|
|
{
|
|
|
|
fprintf(tracefile, "Cog %d: ", i);
|
|
|
|
DebugPasmInstruction(&PasmVars[i]);
|
|
|
|
}
|
|
|
|
}
|
2018-04-13 02:20:22 +00:00
|
|
|
if (propmode == 2)
|
2015-03-22 17:30:10 +00:00
|
|
|
{
|
|
|
|
breakflag = ExecutePasmInstruction2(&PasmVars[i]);
|
|
|
|
if (PasmVars[i].printflag && state == 5)
|
2018-04-13 02:20:22 +00:00
|
|
|
fprintf(tracefile, NEW_LINE);
|
2015-03-22 17:30:10 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ExecutePasmInstruction(&PasmVars[i]);
|
2018-04-13 02:20:22 +00:00
|
|
|
if (PasmVars[i].printflag && state == 5) fprintf(tracefile, NEW_LINE);
|
2015-03-22 17:30:10 +00:00
|
|
|
}
|
|
|
|
if (!breakflag &&
|
|
|
|
!(printbreak && PasmVars[i].printflag && state == 5))
|
|
|
|
runflag = 1;
|
|
|
|
}
|
|
|
|
else if (state)
|
|
|
|
{
|
|
|
|
spinvars = (SpinVarsT *)&PasmVars[i].mem[0x1e0];
|
|
|
|
if (PasmVars[i].printflag && state == 1)
|
|
|
|
{
|
|
|
|
int32_t dcurr = spinvars->dcurr;
|
|
|
|
fprintf(tracefile, "Cog %d: %4.4x %8.8x - ", i, dcurr, LONG(dcurr - 4));
|
|
|
|
PrintOp(spinvars);
|
|
|
|
}
|
|
|
|
if (profile) CountOp(spinvars);
|
|
|
|
ExecuteOp(spinvars);
|
|
|
|
runflag = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
loopcount++;
|
|
|
|
return runflag;
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
char *fname = 0;
|
|
|
|
int32_t i;
|
|
|
|
int32_t maxloops = -1;
|
|
|
|
|
|
|
|
tracefile = stdout;
|
2018-10-22 17:15:56 +00:00
|
|
|
serialfile = stdout;
|
2018-04-13 02:20:22 +00:00
|
|
|
getcwd(rootdir, 100);
|
2015-03-22 17:30:10 +00:00
|
|
|
|
|
|
|
for (i = 1; i < argc; i++)
|
|
|
|
{
|
|
|
|
if (strcmp(argv[i], "-l") == 0){
|
|
|
|
if (i+1 == argc || argv[i+1][0] == '-')
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Trace file not specified\n");
|
|
|
|
spinsim_exit(1);
|
|
|
|
}
|
|
|
|
if (!printflag) printflag = 0xffffffff;
|
|
|
|
i++;
|
|
|
|
tracefile = fopen(argv[i], "wt");
|
|
|
|
if(!tracefile){
|
|
|
|
fprintf(stderr, "Unable to open trace file %s.\n", argv[i]);
|
|
|
|
spinsim_exit(1);
|
|
|
|
}
|
2018-04-13 02:20:22 +00:00
|
|
|
}
|
2018-10-22 17:15:56 +00:00
|
|
|
else if (strcmp(argv[i], "-B") == 0){
|
|
|
|
if (i+1 == argc || argv[i+1][0] == '-')
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Serial file not specified\n");
|
|
|
|
spinsim_exit(1);
|
|
|
|
}
|
|
|
|
if (!printflag) printflag = 0xffffffff;
|
|
|
|
i++;
|
|
|
|
serialfile = fopen(argv[i], "wt");
|
|
|
|
if(!serialfile){
|
|
|
|
fprintf(stderr, "Unable to open serial file %s.\n", argv[i]);
|
|
|
|
spinsim_exit(1);
|
|
|
|
}
|
|
|
|
}
|
2018-04-13 02:20:22 +00:00
|
|
|
else if (strncmp(argv[i], "-t", 2) == 0)
|
2015-03-22 17:30:10 +00:00
|
|
|
{
|
2018-04-13 02:20:22 +00:00
|
|
|
propmode = 2;
|
2015-03-22 17:30:10 +00:00
|
|
|
pasmspin = 1;
|
2018-04-13 02:20:22 +00:00
|
|
|
memsize = 512;
|
2015-03-22 17:30:10 +00:00
|
|
|
cycleaccurate = 1;
|
2018-04-13 02:20:22 +00:00
|
|
|
fjmpflag = argv[i][2] & 1;
|
|
|
|
nohubslots = (argv[i][2] & 2) >> 1;
|
2015-03-22 17:30:10 +00:00
|
|
|
}
|
|
|
|
else if (strcmp(argv[i], "-p") == 0)
|
|
|
|
{
|
|
|
|
pasmspin = 1;
|
|
|
|
cycleaccurate = 1;
|
|
|
|
}
|
2018-04-13 02:20:22 +00:00
|
|
|
else if (strcmp(argv[i], "-pst") == 0)
|
|
|
|
pstmode = 1;
|
|
|
|
else if (strcmp(argv[i], "-k") == 0)
|
|
|
|
kludge = 1;
|
2015-03-22 17:30:10 +00:00
|
|
|
else if (strcmp(argv[i], "-s") == 0)
|
|
|
|
symflag = 1;
|
|
|
|
else if (strcmp(argv[i], "-P") == 0)
|
|
|
|
profile = 1;
|
|
|
|
else if (strncmp(argv[i], "-m", 2) == 0)
|
|
|
|
{
|
|
|
|
sscanf(&argv[i][2], "%d", &memsize);
|
|
|
|
}
|
|
|
|
else if (strncmp(argv[i], "-b", 2) == 0)
|
|
|
|
{
|
|
|
|
pasmspin = 1;
|
|
|
|
cycleaccurate = 1;
|
|
|
|
if (argv[i][2] == 0)
|
|
|
|
baudrate = 115200;
|
|
|
|
else
|
|
|
|
sscanf(&argv[i][2], "%d", &baudrate);
|
|
|
|
}
|
|
|
|
else if (strcmp(argv[i], "-gdb") == 0)
|
|
|
|
{
|
|
|
|
gdbmode = 1;
|
|
|
|
cycleaccurate = 1;
|
|
|
|
pasmspin = 1;
|
|
|
|
}
|
|
|
|
else if (strcmp(argv[i], "-L") == 0)
|
|
|
|
{
|
|
|
|
logfile = fopen(argv[++i], "wt");
|
|
|
|
}
|
|
|
|
else if (strcmp(argv[i], "-r") == 0)
|
|
|
|
{
|
|
|
|
cmdfile = fopen(argv[++i], "rt");
|
|
|
|
}
|
|
|
|
else if (strcmp(argv[i], "-e") == 0)
|
|
|
|
{
|
|
|
|
eeprom = 1;
|
|
|
|
}
|
|
|
|
else if (strncmp(argv[i], "-v", 2) == 0)
|
|
|
|
{
|
|
|
|
if (argv[i][2])
|
|
|
|
{
|
|
|
|
sscanf(&argv[i][2], "%x", &printflag);
|
|
|
|
if (!argv[i][3])
|
|
|
|
printflag *= 0x11111111;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
printflag = 0xffffffff;
|
|
|
|
}
|
|
|
|
else if (strcmp(argv[i], "-d") == 0)
|
|
|
|
{
|
|
|
|
debugmode = 1;
|
|
|
|
}
|
|
|
|
#if 0
|
|
|
|
else if (strncmp(argv[i], "-x", 2) == 0)
|
|
|
|
{
|
|
|
|
sscanf(&argv[i][2], "%d", &extmemsize);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
else if (argv[i][0] == '-' && argv[i][1] >= '0' && argv[i][1] <= '9')
|
|
|
|
sscanf(argv[i] + 1, "%d", &maxloops);
|
|
|
|
else if (argv[i][0] == '-')
|
|
|
|
usage();
|
|
|
|
else if (!fname)
|
|
|
|
fname = argv[i];
|
|
|
|
else
|
|
|
|
usage();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (eeprom)
|
|
|
|
EEPromInit(fname);
|
|
|
|
|
|
|
|
if(!cmdfile) cmdfile = stdin;
|
|
|
|
|
|
|
|
// Check the hub memory size and allocate it
|
|
|
|
if (memsize < 32)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Specified memory size is too small\n");
|
|
|
|
spinsim_exit(1);
|
|
|
|
}
|
|
|
|
if (memsize < 64) memsize = 64;
|
|
|
|
memsize <<= 10; // Multiply it by 1024
|
|
|
|
hubram = malloc(memsize + 16 + 3);
|
|
|
|
if (!hubram)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Specified memory size is too large\n");
|
|
|
|
spinsim_exit(1);
|
|
|
|
}
|
|
|
|
// Make sure it's long aligned
|
|
|
|
#ifdef __LP64__
|
|
|
|
hubram = (char *)(((uint64_t)hubram) & 0xfffffffffffffffc);
|
|
|
|
#else
|
|
|
|
hubram = (char *)(((uint32_t)hubram) & 0xfffffffc);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
LONG(SYS_DEBUG) = printflag;
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
// Check the ext memory size and allocate it if non-zero
|
|
|
|
if (extmemsize < 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Invalid external memory size\n");
|
|
|
|
spinsim_exit(1);
|
|
|
|
}
|
|
|
|
else if (extmemsize)
|
|
|
|
{
|
|
|
|
extmemsize <<= 10; // Multiply it by 1024
|
|
|
|
extram = malloc(extmemsize);
|
|
|
|
if (!extram)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Specified external memory size is too large\n");
|
|
|
|
spinsim_exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (profile) ResetStats();
|
|
|
|
|
|
|
|
bootfile = fname;
|
|
|
|
|
|
|
|
if (!fname && !gdbmode && !eeprom) usage();
|
|
|
|
|
|
|
|
RebootProp();
|
2018-04-13 02:20:22 +00:00
|
|
|
#ifndef __MINGW32__
|
|
|
|
initialize_console_io();
|
|
|
|
#endif
|
2015-03-22 17:30:10 +00:00
|
|
|
if (gdbmode)
|
|
|
|
gdb();
|
|
|
|
else if (debugmode)
|
|
|
|
Debug();
|
|
|
|
else
|
|
|
|
RunProp(maxloops);
|
2018-04-13 02:20:22 +00:00
|
|
|
#ifndef __MINGW32__
|
|
|
|
restore_console_io();
|
|
|
|
#endif
|
2015-03-22 17:30:10 +00:00
|
|
|
if (eeprom) EEPromClose();
|
|
|
|
if (profile) PrintStats();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
+------------------------------------------------------------------------------------------------------------------------------+
|
|
|
|
| TERMS OF USE: MIT License |
|
|
|
|
+------------------------------------------------------------------------------------------------------------------------------+
|
|
|
|
|Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation |
|
|
|
|
|files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, |
|
|
|
|
|modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software|
|
|
|
|
|is furnished to do so, subject to the following conditions: |
|
|
|
|
| |
|
|
|
|
|The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.|
|
|
|
|
| |
|
|
|
|
|THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
|
|
|
|
|WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR |
|
|
|
|
|COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
|
|
|
|
|ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
|
|
|
+------------------------------------------------------------------------------------------------------------------------------+
|
|
|
|
*/
|