Initial push of the contents of Dave Hein's latest release.

This commit is contained in:
David Betz 2015-03-22 13:30:10 -04:00
commit bdd3741b10
51 changed files with 18889 additions and 0 deletions

27
Makefile Executable file
View File

@ -0,0 +1,27 @@
TARGET = spinsim
SOURCES = spinsim.c spininterp.c spindebug.c pasmsim.c pasmdebug.c pasmsim2.c pasmdebug2.c eeprom.c debug.c gdb.c
OBJECTS = $(SOURCES:.c=.o)
ifneq ($(OS),msys)
SOURCES += conion.c
endif
CC = gcc
# I'm not sure why these linker flags were being used but the break the build on Mac OS X so I've
# commented them out for the time being
#LDFLAGS = -Wl,--relax -Wl,--gc-sections
LDFLAGS =
OPT := -O3
CFLAGS = -c -g -Wall -Wno-format $(OPT) -I/usr/include -D LINUX
all: $(SOURCES) $(OBJECTS) Makefile
$(CC) $(LDFLAGS) $(OBJECTS) -o $(TARGET)
# Compile .c files into objexts .o
.c.o:
$(CC) $(CFLAGS) $< -o $@
clean: FORCE
rm -f *.o $(TARGET)
FORCE:

135
README.md Executable file
View File

@ -0,0 +1,135 @@
Spinsim 0.75
This version of spinsim supports about two-thirds of the opcodes in the P2
instruction set. The list of implemented opcodes is shown below, along with
the list of opcodes that have not been implemented yet. Spinsim runs in the P1
mode by default. It can be set to run in the P2 mode with the -t parameter.
In the P2 mode, spinsim will load a P2 OBJ file into hub RAM, and start cog 0
with the code located at $E00. A simulated serial port is supported by using
the -b option. The default baud rate is 115,200, but other rates can be used
by specifying it with -b, such as -b9600. The serial port uses pin 31 and 30,
just like with P1.
Spinsim is built using the Makefile, and typing make. I have successfully
built and run it under Cygwin and Ubuntu Linux.
The sample program, pfth.spin can be run by building it with the PNut P2
assembler. PNut is contained in the Terasic_Prop2_Emulation zip file,
which can be downloaded from the first post in the "HUB EXEC Update Here"
thread in the Propeller 2 forum.
There are two demo programs, which are the pfth Forth interpreter and the
p1spin Spin interpreter that runs P1 Spin binaries on the P2 processor.
The pfth program is run under spinsim as follows:
./spinsim -t -b pfth.obj
p1spin runs at a baud rate of 57600, so it is run as follows:
./spinsim -t -b57600 p1spin.obj
Spinsim supports execution from cog memory and hub execution, but it does not
support multi-tasking. Only the core processor is supported, and none of the
counters, video hardware or cordic hardware is simulated. Support for multi-
tasking, peripheral hardware and cordic instructions will be added later.
Spinsim contains a simple debugger, which is enabled with the -d command-line
option. The debugger prints the prompt "DEBUG>" to indicate that it is ready
to accept a command. The "help" command will print the following:
Debug Commands
help - Print command list
exit - Exit spinsim
step - Run one cycle
stepx - Run next executed instruction
run - Run continuously
verbose # - Set verbosity level
reboot - Reboot the Prop
setbr cog addr - Set breakpoint for cog to addr
state cog - Dump cog state
The "step" command will run one cycle, and the "stepx" command will run any
non-executing cycles until it encounters an instruction that is executed.
The previous command can be executed again by just pushing the enter key.
This is useful for stepping where the "step" command is typed once, and
the enter key can then be used to step again.
The "run" command will run until a breakpoint is encountered or ^] is typed.
^] is typed by holding down the control key and pressing the "]" key.
While running, spinsim will print out the results of each cycle as
controlled by the verbosity level, which is set by the "verbose" command.
The verbosity level can also be set with the command-line parameter "-v#".
The verbosity levels are as follows:
0 - Disable printing
1 - Print only the executed instructions
2 - Print only the executed instructions, and show the execution results
3 - Print executed and instruction not executed due to condition code
4 - Also print instructions invalidated in the pipeline due to jumps
5 - Also print instructions that include hub and hardware waits
6 - Also print instructions that include icache waits
7 - Also print instructions waiting for a pin state
8 - Print all cycles, including waitcnt waits
The verbosity level is entered as a hexadecimal number. If the verbosity level
is entered as a single digit it will apply to all cogs. If more than one digit
is entered each digit will be used for each cog, starting with cog 0 for the
right-most digit. As an example, a value of 456 will cause 6 to be used for
cog 0, 5 for cog 1, and 4 for cog 2. All other cogs will use 0.
Implemented Opcodes
-------------------
abs add addabs addptra addptrb addptrx addptry adds
addsx addx and andn augd augs bingry blmask
call calla callad callb callbd calld callx callxd
cally callyd chkptrx chkptry clkset clracca clraccb clraccs
clrb clrp cmp cmpcnt cmps cmpsub cmpsx cmpx
cogid coginit cognew cogstop dcachex decd decds decmod
decod2 decod3 decod4 decod5 div32 div32u div64 div64d
div64u djnz djnzd djz djzd encod fixinda fixindb
fixindx frac getacah getacal getacbh getacbl getbyte getcnt
getdivq getdivr getmulh getmull getnib getnp getp getptra
getptrb getptrx getptry getsqrt getword icachen icachep icachex
ijnz ijnzd ijz ijzd incd incds incmod isob
jmp jmpd jmpsw jmpswd jnp jnpd jnz jnzd
jp jpd jz jzd locbase locbyte lockclr locknew
lockret lockset loclong locptra locptrb locword maca macb
max maxs mergew min mins mov mul mul32
mul32u muxc muxnc muxnz muxz neg negc negnc
negnz negz not notb notp offp onecnt or
pop popzc push pushzc rcl rcr rdaux rdauxr
rdbyte rdbytec rdlong rdlongc rdwide rdwidec rdword rdwordc
repd reps ret reta retad retb retbd retd
retx retxd rety retyd rev rol ror sar
saracca saraccb saraccs setacca setaccb setb setbc setbnc
setbnz setbyte setbz setd seti setindb setindx setnib
setp setpc setpnc setpnz setptra setptrb setptrx setptry
setpz sets setwide setwidz setword setzc seussf seussr
shl shr splitw sqrt32 sqrt64 sub subabs subcnt
subptra subptrb subptrx subptry subr subs subsx subx
sumc sumnc sumnz sumz test testn wait waitcnt
waitpeq waitpne wraux wrauxr wrbyte wrlong wrwide wrword
xor zercnt
Opcodes Not Implemented
-----------------------
addphsa addphsb addphss addpix bcdbin binbcd blnpix capctra
capctrb capctrs cfgdac0 cfgdac1 cfgdac2 cfgdac3 cfgdacs cfgpins
cmpr decpat eswap4 eswap8 getcntx getcosa getcosb getlfsr
getphsa getphsb getphza getphzb getpix getqx getqy getqz
getsina getsinb grybin incpat jmplist jmptask locinst mergeb
mixpix movbyts mulpix packrgb passcnt polctra polctrb polvid
qartan qexp qlog qrotate qsincos rolbyte rolnib rolword
scl serina serinb serouta seroutb setbyts setctra setctrb
setctrs setdac0 setdac1 setdac2 setdac3 setdacs setfrqa setfrqb
setfrqs setmap setmix setphsa setphsb setphss setpix setpixa
setpixb setpixg setpixr setpixu setpixv setpixw setpixz setpora
setporb setporc setpord setqi setqz setrace setsera setserb
settask setvid setvidi setvidq setvidy setwava setwavb setwavs
setwrds setx setxch setxft splitb subphsa subphsb subphss
synctra synctrb taskid testb unpkrgb waitpf waitpr waitpx
waitvid

136
conio.spin Executable file
View File

@ -0,0 +1,136 @@
'******************************************************************************
' Author: Dave Hein
' Version 1.0
' Copyright (c) 2010, 2011
' See end of file for terms of use.
'******************************************************************************
{{
This object provides console I/O functions for SpinSim. It implements the same methods as FullDuplexSerial.
}}
con
SYS_COMMAND = $12340000
SYS_LOCKNUM = $12340002
SYS_PARM = $12340004
SYS_CON_PUTCH = 1
SYS_CON_GETCH = 2
PUB start(rxpin, txpin, mode, baudrate) : okay
ifnot word[SYS_LOCKNUM]
word[SYS_LOCKNUM] := locknew + 1
return 1
PUB stop
PUB rxflush
'' Flush receive buffer
repeat while rxcheck => 0
PUB rxtime(ms) : rxbyte | t
'' Wait ms milliseconds for a byte to be received
'' returns -1 if no byte received, $00..$FF if byte
t := cnt
repeat until (rxbyte := rxcheck) => 0 or (cnt - t) / (clkfreq / 1000) > ms
PUB rx : rxbyte
'' Receive byte (may wait for byte)
'' returns $00..$FF
repeat while (rxbyte := rxcheck) < 0
PUB rxcheck | locknum
locknum := word[SYS_LOCKNUM] - 1
if locknum == -1
return -1
repeat until not lockset(locknum)
word[SYS_COMMAND] := SYS_CON_GETCH
repeat while word[SYS_COMMAND]
result := long[SYS_PARM]
lockclr(locknum)
PUB tx(txbyte) | locknum
'' Send byte (may wait for room in buffer)
locknum := word[SYS_LOCKNUM] - 1
if locknum == -1
return
repeat until not lockset(locknum)
long[SYS_PARM] := txbyte
word[SYS_COMMAND] := SYS_CON_PUTCH
repeat while word[SYS_COMMAND]
lockclr(locknum)
PUB str(stringptr)
'' Send string
repeat strsize(stringptr)
tx(byte[stringptr++])
PUB dec(value) | i, x
'' Print a decimal number
x := value == NEGX 'Check for max negative
if value < 0
value := ||(value+x) 'If negative, make positive; adjust for max negative
tx("-") 'and output sign
i := 1_000_000_000 'Initialize divisor
repeat 10 'Loop for 10 digits
if value => i
tx(value / i + "0" + x*(i == 1)) 'If non-zero digit, output digit; adjust for max negative
value //= i 'and digit from value
result~~ 'flag non-zero found
elseif result or i == 1
tx("0") 'If zero digit (or only digit) output it
i /= 10 'Update divisor
PUB hex(value, digits)
'' Print a hexadecimal number
value <<= (8 - digits) << 2
repeat digits
tx(lookupz((value <-= 4) & $F : "0".."9", "A".."F"))
'tx(hexdigit[(value <-= 4) & $F])
PUB bin(value, digits)
'' Print a binary number
value <<= 32 - digits
repeat digits
tx((value <-= 1) & 1 + "0")
PUB out(char)
tx(char)
{{
+------------------------------------------------------------------------------------------------------------------------------+
| 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. |
+------------------------------------------------------------------------------------------------------------------------------+
}}

73
conion.c Executable file
View File

@ -0,0 +1,73 @@
#ifdef LINUX
#include <stdio.h>
#include "conion.h"
#ifdef STD_CONSOLE_INPUT
void initialize_console_io()
{
}
void restore_console_io()
{
}
int kbhit(void)
{
return 0;
}
char getch(void)
{
return getchar();
}
#else
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
static struct termios oldt;
static int oldf;
static int lastkey = EOF;
static int initialized = 0;
void initialize_console_io()
{
struct termios newt;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);
initialized = 1;
}
void restore_console_io()
{
if (initialized)
{
initialized = 0;
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
fcntl(STDIN_FILENO, F_SETFL, oldf);
}
}
int kbhit(void)
{
if (lastkey == EOF)
lastkey = getchar();
return (lastkey != EOF);
}
char getch(void)
{
int ch;
while (!kbhit());
ch = lastkey;
lastkey = EOF;
return ch;
}
#endif
#endif

11
conion.h Executable file
View File

@ -0,0 +1,11 @@
#ifndef __CONION_H__
#define __CONION_H__
#undef STD_CONSOLE_INPUT
int kbhit(void);
char getch(void);
void initialize_console_io(void);
void restore_console_io(void);
#endif

222
debug.c Executable file
View File

@ -0,0 +1,222 @@
/*******************************************************************************
' Author: Dave Hein
' Version 0.54
' Copyright (c) 2012
' See end of file for terms of use.
'******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#ifdef LINUX
#include <dirent.h>
#include <sys/stat.h>
#include "conion.h"
#else
#include <conio.h>
#include <direct.h>
#endif
#include "interp.h"
#include "spindebug.h"
#include "eeprom.h"
#include "spinsim.h"
extern int32_t loopcount;
extern int32_t printflag;
extern int32_t baudrate;
extern int32_t eeprom;
extern char *hubram;
extern int32_t printbreak;
extern PasmVarsT PasmVars[8];
void GetDebugString(char *ptr);
int32_t RunProp(int32_t maxloops);
void Help(void)
{
printf("Debug Commands\n");
printf("help - Print command list\n");
printf("exit - Exit spinsim\n");
printf("step - Run one cycle\n");
printf("stepx - Run next executed instruction\n");
printf("run - Run continuously\n");
printf("verbose # - Set verbosity level\n");
printf("reboot - Reboot the Prop\n");
printf("setbr cog addr - Set breakpoint for cog to addr\n");
printf("state cog - Dump cog state\n");
}
char *SkipChar(char *str, int value)
{
while (*str)
{
if (*str != value) break;
str++;
}
return str;
}
void DumpState(PasmVarsT *pasmvars)
{
printf("cflag = %d, zflag = %d, waitflag = %d\n",
pasmvars->cflag, pasmvars->zflag, pasmvars->waitflag);
printf("ptra = %5.5x, ptrb = %5.5x, ptrx = %2.2x, ptry = %2.2x, inda = %3.3x, indb = %3.3x\n",
pasmvars->ptra, pasmvars->ptra, pasmvars->ptrx,
pasmvars->ptry, pasmvars->inda, pasmvars->indb);
printf("pc1 = %8.8x, instruct1 = %8.8x\n", pasmvars->pc1, pasmvars->instruct1);
printf("pc2 = %8.8x, instruct2 = %8.8x\n", pasmvars->pc2, pasmvars->instruct2);
printf("pc3 = %8.8x, instruct3 = %8.8x\n", pasmvars->pc3, pasmvars->instruct3);
printf("pc4 = %8.8x, instruct4 = %8.8x\n", pasmvars->pc4, pasmvars->instruct4);
}
void Debug(void)
{
int runflag = 1;
char buffer[200];
char lastcmd[200];
int maxloops;
int stepflag = 0;
int saveprintflag = 0;
strcpy(lastcmd, "help");
while (runflag)
{
while (1)
{
printf("\nDEBUG> ");
fflush(stdout);
GetDebugString(buffer);
if (buffer[0] == 0) strcpy(buffer, lastcmd);
strcpy(lastcmd, buffer);
if (!strcmp(buffer, "exit"))
{
runflag = 0;
break;
}
else if (!strcmp(buffer, "step"))
{
stepflag = 1;
saveprintflag = printflag;
printflag = 0xffffffff;
LONG(SYS_DEBUG) = printflag;
maxloops = loopcount + 1;
break;
}
else if (!strcmp(buffer, "stepx"))
{
stepflag = 1;
saveprintflag = printflag;
printflag = 0x22222222;
LONG(SYS_DEBUG) = printflag;
printbreak = 1;
maxloops = -1;
break;
}
else if (!strncmp(buffer, "verbose", 7))
{
char *ptr = SkipChar(buffer+7, ' ');
if (*ptr == 0)
printflag = 0xffffffff;
else
{
sscanf(ptr, "%x", &printflag);
if (ptr[1] == 0)
printflag *= 0x11111111;
}
LONG(SYS_DEBUG) = printflag;
}
else if (!strcmp(buffer, "help"))
{
Help();
}
else if (!strcmp(buffer, "run"))
{
maxloops = -1;
break;
}
else if (!strncmp(buffer, "setbr ", 6))
{
int cognum, address;
sscanf(buffer+6, "%x %x", &cognum, &address);
PasmVars[cognum&7].breakpnt = address;
LONG(SYS_DEBUG) = printflag;
}
else if (!strcmp(buffer, "reboot"))
{
RebootProp();
}
else if (!strncmp(buffer, "state ", 6))
{
int cognum = buffer[6] & 7;
DumpState(&PasmVars[cognum]);
}
else
printf("?\n");
}
if (runflag) RunProp(maxloops);
if (stepflag)
{
stepflag = 0;
printbreak = 0;
printflag = saveprintflag;
LONG(SYS_DEBUG) = printflag;
}
}
}
void GetDebugString(char *ptr)
{
int value;
while (1)
{
#ifndef STD_CONSOLE_INPUT
while (!kbhit());
#endif
value = getch();
putchx(value);
if (value == 13 || value == 10)
{
*ptr = 0;
return;
}
*ptr++ = value;
}
}
int32_t RunProp(int32_t maxloops)
{
int32_t runflag = 1;
while (runflag && (maxloops < 0 || loopcount < maxloops))
{
runflag = step_chip();
CheckCommand();
if (baudrate)
{
CheckSerialOut();
if (CheckSerialIn()) return 1;
}
if (eeprom)
CheckEEProm();
}
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. |
+------------------------------------------------------------------------------------------------------------------------------+
*/

223
eeprom.c Executable file
View File

@ -0,0 +1,223 @@
/*******************************************************************************
' Author: Dave Hein
' Version 0.54
' Copyright (c) 2012
' See end of file for terms of use.
'******************************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include "spinsim.h"
extern int32_t pin_val;
extern int32_t eeprom;
static int32_t scl_prev = 1;
static int32_t sda_prev = 1;
static int32_t state = 0;
static int32_t count = 0;
static int32_t value = 0;
static int32_t control = 0;
static int32_t address = 0;
static int32_t drivepin = 0;
static int32_t driveval = 0;
static unsigned char memory[256*256];
void CheckEEProm()
{
int32_t scl = (pin_val >> 28) & 1;
int32_t sda = (pin_val >> 29) & 1;
if (!eeprom) return;
//printf("scl = %d, sda = %d\n", scl, sda);
if (!drivepin && scl_prev && sda_prev && scl && !sda)
{
//printf("Start\n");
count = 0;
state = 1;
control = 0;
drivepin = 0;
}
else if (!drivepin && scl_prev && !sda_prev && scl && sda)
{
//printf("Stop\n");
state = 0;
drivepin = 0;
}
else if (state && scl_prev && !scl)
{
drivepin = 0;
if (state == 1)
{
if (count) control = (control << 1) | sda_prev;
count++;
if (count == 9)
{
//printf("control = %2.2x\n", control);
if ((control & 0xf0) == 0xa0)
{
drivepin = 1;
driveval = 0;
count = 0;
if (control & 1)
state = 5;
else
state = 2;
}
else
{
state = 0;
}
}
}
else if (state == 2 || state == 3)
{
if (count) address = (address << 1) | sda_prev;
else if (state == 2) address = 0;
count++;
if (count == 9)
{
//if (state == 3) printf("address = %2.2x\n", address);
state++;
drivepin = 1;
driveval = 0;
count = 0;
}
}
else if (state == 4)
{
if (count) value = (value << 1) | sda_prev;
count++;
if (count == 9)
{
//printf("value = %2.2x\n", value);
memory[address] = value;
address = (address + 1) & 0xffff;
drivepin = 1;
driveval = 0;
count = 0;
eeprom = 2;
}
}
else if (state == 5)
{
if (count == 0)
{
if (sda_prev)
state = 0;
else
{
value = memory[address];
drivepin = 1;
driveval = (value >> 7) & 1;
value <<= 1;
count++;
address = (address + 1) & 0xffff;
}
}
else if (count < 8)
{
drivepin = 1;
driveval = (value >> 7) & 1;
value <<= 1;
count++;
}
else
{
count = 0;
drivepin = 0;
}
}
}
if (drivepin)
{
pin_val = (pin_val & (~(1 << 29))) | (driveval << 29);
sda = driveval;
}
scl_prev = scl;
sda_prev = sda;
}
static FILE *OpenFile(char *fname, char *mode)
{
FILE *file = fopen(fname, mode);
if (!file)
{
printf("Could not open %s\n", fname);
spinsim_exit(1);
}
return file;
}
void EEPromInit(char *fname)
{
FILE *file;
if (!eeprom) return;
//printf("EEPromInit(%s)\n", fname);
if (fname)
{
file = fopen("eeprom.dat", "r");
if (file)
{
fread(memory, 1, 65536, file);
fclose(file);
memset(memory, 0, 32768);
}
else
memset(memory, 0, 65536);
file = OpenFile(fname, "r");
fread(memory, 1, 65536, file);
fclose(file);
file = OpenFile("eeprom.dat", "w");
fwrite(memory, 1, 65536, file);
fclose(file);
return;
}
file = OpenFile("eeprom.dat", "r");
fread(memory, 1, 65536, file);
fclose(file);
}
void EEPromClose(void)
{
FILE *file;
if (eeprom == 2)
{
file = OpenFile("eeprom.dat", "w");
fwrite(memory, 1, 65536, file);
fclose(file);
}
}
void EEPromCopy(char *mem)
{
if (!eeprom) return;
//printf("EEPromCopy\n");
memcpy(mem, memory, 32768);
}
/*
+------------------------------------------------------------------------------------------------------------------------------+
| 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. |
+------------------------------------------------------------------------------------------------------------------------------+
*/

4
eeprom.h Executable file
View File

@ -0,0 +1,4 @@
void CheckEEProm(void);
void EEPromInit(char *fname);
void EEPromCopy(char *mem);
void EEPromClose(void);

189
fileio.spin Executable file
View File

@ -0,0 +1,189 @@
'******************************************************************************
' Author: Dave Hein
' Version 1.0
' Copyright (c) 2010, 2011
' See end of file for terms of use.
'******************************************************************************
{{
This object provide file I/O functions for SpinSim. It currently implements only popen, pclose and pread.
The methods a similar to the ones the FSRW object. A dummy mount routine is provide for compatibility.
}}
con
SYS_COMMAND = $12340000
SYS_LOCKNUM = $12340002
SYS_PARM = $12340004
SYS_FILE_OPEN = 3
SYS_FILE_CLOSE = 4
SYS_FILE_READ = 5
SYS_FILE_WRITE = 6
SYS_FILE_OPENDIR = 7
SYS_FILE_CLOSEDIR = 8
SYS_FILE_READDIR = 9
SYS_FILE_SEEK = 10
SYS_FILE_TELL = 11
SYS_FILE_REMOVE = 12
SYS_FILE_CHDIR = 13
SYS_FILE_GETCWD = 14
SYS_FILE_MKDIR = 15
SYS_FILE_GETMOD = 16
dat
handle0 long 0
dirhand0 long 0
direntbuf long 0[20]
'****************************
' FSRW Routines
'****************************
pub mount(pin)
ifnot word[SYS_LOCKNUM]
word[SYS_LOCKNUM] := locknew + 1
pub mount_explicit(DO, CLK, DI, CS)
ifnot word[SYS_LOCKNUM]
word[SYS_LOCKNUM] := locknew + 1
pub popen(fname, mode)
pclose
handle0 := hopen(fname, mode)
ifnot handle0
return -1
pub pclose
if handle0
hclose(handle0)
handle0~
pub pread(buffer, num)
return hread(handle0, buffer, num)
pub pwrite(buffer, num)
return hwrite(handle0, buffer, num)
pub opendir
if dirhand0
hclosedir(dirhand0)
dirhand0 := hopendir
ifnot dirhand0
return -1
pub nextfile(fbuf)
return hnextfile(dirhand0, fbuf)
pub seek(position)
result := hseek(handle0, position)
pub tell
result := htell(handle0)
pub get_filesize
result := hget_filesize(handle0)
'****************************
' handle Routines
'****************************
pub hopen(fname, mode)
if mode => "a" and mode =< "z"
mode -= "a" - "A"
if mode == "R"
mode := string("rb")
elseif mode == "W"
mode := string("wb")
elseif mode == "A"
mode := string("ab")
elseif mode == "D"
return SystemCall(SYS_FILE_REMOVE, fname)
else
return 0
result := SystemCall(SYS_FILE_OPEN, @fname)
pub hclose(handle)
result := SystemCall(SYS_FILE_CLOSE, handle)
pub hread(handle, buffer, num)
result := SystemCall(SYS_FILE_READ, @handle)
pub hwrite(handle, buffer, num)
result := SystemCall(SYS_FILE_WRITE, @handle)
pub hopendir
result := SystemCall(SYS_FILE_OPENDIR, 0)
pub hclosedir(handle)
result := SystemCall(SYS_FILE_CLOSEDIR, handle)
pub hnextfile(handle, fbuf) | num
result := hreaddir(handle)
if result
num := strsize(@direntbuf[2])
if num > 31
num := 31
bytemove(fbuf, @direntbuf[2], num)
byte[fbuf][num] := 0
pub hreaddir(handle) | pdirent
pdirent := @direntbuf
result := SystemCall(SYS_FILE_READDIR, @handle)
if result
result := @direntbuf
pub hseek(handle, position) | whence
whence~
result := SystemCall(SYS_FILE_SEEK, @handle)
pub htell(handle)
result := SystemCall(SYS_FILE_TELL, handle)
pub hget_filesize(handle) | offset, whence, position, filesize
position := SystemCall(SYS_FILE_TELL, handle)
offset~
whence := 2
SystemCall(SYS_FILE_SEEK, @handle)
filesize := SystemCall(SYS_FILE_TELL, handle)
offset := position
whence~
SystemCall(SYS_FILE_SEEK, @handle)
return filesize
pub chdir(path)
result := SystemCall(SYS_FILE_CHDIR, path)
pub getcwd(str, num)
result := SystemCall(SYS_FILE_CHDIR, @str)
pub mkdir(path)
result := SystemCall(SYS_FILE_MKDIR, path)
pub getmod(fname)
result := SystemCall(SYS_FILE_GETMOD, fname)
pub SystemCall(command, parm) | locknum
locknum := word[SYS_LOCKNUM] - 1
if locknum == -1
return -1
repeat until not lockset(locknum)
long[SYS_PARM] := parm
word[SYS_COMMAND] := command
repeat while word[SYS_COMMAND]
result := long[SYS_PARM]
lockclr(locknum)
{{
+------------------------------------------------------------------------------------------------------------------------------+
| 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. |
+------------------------------------------------------------------------------------------------------------------------------+
}}

418
gdb.c Executable file
View File

@ -0,0 +1,418 @@
/*******************************************************************************
' Version 0.54
' Copyright (c) 2010, 2011, 2012
' See end of file for terms of use.
'******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#ifdef LINUX
#include <dirent.h>
#include <sys/stat.h>
#include "conion.h"
#else
#include <conio.h>
#include <direct.h>
#endif
#include "interp.h"
#include "spinsim.h"
#define GCC_REG_BASE 0
extern FILE *logfile;
extern FILE *tracefile;
extern FILE *cmdfile;
extern PasmVarsT PasmVars[8];
extern char *hubram;
char cmd[1028];
extern int32_t proptwo;
extern int32_t profile;
extern int32_t loopcount;
void reply(char *ptr, int len){
unsigned char cksum = 0;
int i;
putc('$', stdout);
if(logfile) fprintf(logfile, "sim>$");
for(i = 0; i < len; i++){
putc(ptr[i], stdout);
if(logfile) putc(ptr[i], logfile);
cksum += ptr[i];
}
fprintf(stdout, "#%02x", cksum);
if(logfile) fprintf(logfile, "#%02x", cksum);
if(logfile) putc('\n', logfile);
fflush(stdout);
if(logfile) fflush(logfile);
}
char parse_byte(char *ch){
char s[3];
char val;
s[0] = ch[0];
s[1] = ch[1];
s[2] = 0;
val = 0xff & strtol(s, NULL, 16);
return val;
}
char get_byte(uint32_t addr){
if(addr & 0x80000000){
int cog = (addr >> 28) - 8;
uint32_t tmp;
tmp = PasmVars[cog].mem[(addr & 0x000007ff) >> 2];
return (tmp >> 8*(addr & 0x3)) & 0xff;
} else {
return BYTE(addr);
}
}
void put_byte(uint32_t addr, unsigned char val){
if(addr & 0x80000000){
int cog = (addr >> 28) - 8;
uint32_t tmp;
tmp = PasmVars[cog].mem[(addr & 0x000007ff) >> 2];
switch(addr & 3){
case 0:
tmp &= 0xffffff00;
tmp |= val;
break;
case 1:
tmp &= 0xffff00ff;
tmp |= val << 8;
break;
case 2:
tmp &= 0xff00ffff;
tmp |= val << 16;
break;
case 3:
tmp &= 0x00ffffff;
tmp |= val << 24;
break;
}
PasmVars[cog].mem[(addr & 0x000007ff) >> 2] = tmp;
return;
} else {
BYTE(addr) = val;
return;
}
}
void get_cmd(){
int i = 0;
int ch;
do{
ch = getc(cmdfile);
} while(ch != '$');
if(logfile) fprintf(logfile, "gdb>");
if(logfile) putc(ch, logfile);
for(i = 0; i < sizeof(cmd); i++){
ch = getc(cmdfile);
if(logfile) putc(ch, logfile);
if(ch == '#') break;
cmd[i] = ch;
}
cmd[i] = 0;
// eat the checksum
ch = getc(cmdfile);
if(logfile) putc(ch, logfile);
ch = getc(cmdfile);
if(logfile) putc(ch, logfile);
if(logfile) putc('\n', logfile);
// send an ACK
putchar('+');
fflush(stdout);
if(logfile) fflush(logfile);
}
int tohex(char x){
if(x >= '0' && x <= '9') return x - '0';
if(x >= 'a' && x <= 'f') return 10 + x - 'a';
if(x >= 'A' && x <= 'F') return 10 + x - 'A';
return 0;
}
int32_t get_addr(int *i){
int32_t reg;
reg = tohex(cmd[(*i)++]) << 4;
reg |= tohex(cmd[(*i)++]) << 0;
reg |= tohex(cmd[(*i)++]) << 12;
reg |= tohex(cmd[(*i)++]) << 8;
reg |= tohex(cmd[(*i)++]) << 20;
reg |= tohex(cmd[(*i)++]) << 16;
reg |= tohex(cmd[(*i)++]) << 28;
reg |= tohex(cmd[(*i)++]) << 24;
return reg;
}
struct bkpt {
struct bkpt *next;
uint32_t addr;
uint32_t len;
};
struct bkpt *bkpt = 0;
// Check the cog's PC to see if the LMM microcode is at an appropriate place
// for a breakpoint to occur. We don't want to break on LMM administrative
// instructions.
// FIXME we need a more general way to do this. This is too dependent on special knowledge.
int breakable_point(int i){
int32_t pc = PasmVars[i].pc;
if ((pc == 0x0000004c/4)
|| (pc == 0x00000058/4)
|| (pc == 0x00000064/4)
|| (pc == 0x00000070/4)
|| (pc == 0x0000007c/4)
|| (pc == 0x00000088/4)
|| (pc == 0x00000094/4)
|| (pc == 0x000000a0/4))
return 1;
else
return 0;
}
void gdb(void)
{
int i;
int j;
char response[1024];
unsigned int addr;
int len;
char *end;
char val;
int32_t reg;
int cog = 0;
char *halt_code = "S05";
if(logfile) fprintf(logfile, "\n\nStarting log:\n");
RebootProp();
for(;;){
get_cmd();
i = 0;
switch(cmd[i++]){
case 'g':
for(i = 0; i < 18; i++){
reg = PasmVars[cog].mem[GCC_REG_BASE + i];
sprintf(response+8*i,
"%02x%02x%02x%02x",
(unsigned char)(reg & 0xff),
(unsigned char)((reg>>8) & 0xff),
(unsigned char)((reg>>16) & 0xff),
(unsigned char)((reg>>24) & 0xff));
}
reg = PasmVars[cog].pc * 4 + 0x80000000 + cog * 0x10000000;
sprintf(response+8*i,
"%02x%02x%02x%02x",
(unsigned char)(reg & 0xff),
(unsigned char)((reg>>8) & 0xff),
(unsigned char)((reg>>16) & 0xff),
(unsigned char)((reg>>24) & 0xff));
reply(response, 8*18+8);
break;
case 'G':
for(j = 0; j < 18; j++){
PasmVars[cog].mem[GCC_REG_BASE + j] = get_addr(&i);
}
// Ignore writes to cog pc. Instead, reset it to be
// ready for a fresh instruction.
// This is too magical. How do we fix it?
PasmVars[cog].pc = 0x12;
reply("OK",2);
break;
case 'm':
addr = strtol(&cmd[i], &end, 16);
i = (size_t)end - (size_t)cmd;
i++;
len = strtol(&cmd[i], NULL, 16);
if(len > 512) len = 512;
j = 0;
while(len--){
val = get_byte(addr);
addr++;
sprintf(&response[j], "%02x", (unsigned char)val);
j += 2;
}
reply(response, j);
break;
case 'M':
addr = strtol(&cmd[i], &end, 16);
i = (size_t)end - (size_t)cmd;
i++;
len = strtol(&cmd[i], &end, 16);
i = (size_t)end - (size_t)cmd;
i++;
while(len--){
val = parse_byte(&cmd[i]);
i += 2;
put_byte(addr, val & 0xff);
addr++;
}
reply("OK",2);
break;
case 's':
if(cmd[i]){
// Get the new LMM PC, reset the microcode
PasmVars[cog].mem[GCC_REG_BASE + 17] = get_addr(&i);
PasmVars[cog].pc = 0x12;
}
{
int brk = 0;
do {
int i;
// Step through a full LMM instruction
step_chip();
for(i = 0; i < 8; i++){
if(breakable_point(i)) brk = 1;
}
} while (!brk);
}
halt_code = "S05";
reply(halt_code, 3);
break;
case 'c':
if(cmd[i]){
PasmVars[cog].mem[GCC_REG_BASE + 17] = get_addr(&i);
PasmVars[cog].pc = 0x12;
}
halt_code = "S02";
do {
int brk = 0;
struct bkpt *b;
for (i = 0; i < 8; i++) {
if(breakable_point(i)){
// Look to see if the cog's LMM PC is at a breakpoint
for(b = (struct bkpt *)&bkpt; b->next; b = b->next){
if((PasmVars[i].mem[GCC_REG_BASE + 17] >= b->next->addr)
&& (PasmVars[i].mem[GCC_REG_BASE + 17] <= b->next->addr + b->next->len)){
brk = 1;
}
}
}
}
if(brk){
halt_code = "S05";
break;
} else {
step_chip();
}
} while(getch() != 0x03); // look for a CTRL-C
reply(halt_code, 3);
break;
case 'H':
if((cmd[i] == 'g') && (cmd[i+1] == '0')){
reply("OK", 2);
} else {
reply("", 0);
}
break;
case 'k':
reply("OK", 2);
goto out;
case 'z':
/* Remove breakpoint */
if(cmd[i++] == '0'){
long addr;
long len;
struct bkpt *b;
char *p = &cmd[i];
p++; /* Skip the comma */
addr = strtol(p, &p, 16);
p++; /* Skip the other comma */
len = strtol(p, NULL, 16);
for(b = (struct bkpt *)&bkpt; b && b->next; b = b->next){
if((b->next->addr == addr) && (b->next->len == len)){
struct bkpt *t = b->next;
b->next = t->next;
free(t);
}
}
reply("OK", 2);
} else {
reply("", 0);
}
break;
case 'Z':
/* Set breakpoint */
if(cmd[i++] == '0'){
long addr;
long len;
struct bkpt *b;
char *p = &cmd[i];
p++; /* Skip the comma */
addr = strtol(p, &p, 16);
p++; /* Skip the other comma */
len = strtol(p, NULL, 16);
for(b = (struct bkpt *)&bkpt; b->next; b = b->next){
if((b->addr == addr) && (b->len == len)){
/* Duplicate; bail out */
break;
}
}
if(b->next){
/* Was a duplicate, do nothing */
} else {
struct bkpt *t = (struct bkpt *)malloc(sizeof(struct bkpt));
if(!t){
fprintf(stderr, "Failed to allocate a breakpoint structure\n");
spinsim_exit(1);
}
t->addr = addr;
t->len = len;
t->next = bkpt;
bkpt = t;
}
reply("OK", 2);
} else {
reply("", 0);
}
break;
case '?':
reply(halt_code, 3);
break;
default:
reply("", 0);
break;
}
}
out:
;
}
/*
+------------------------------------------------------------------------------------------------------------------------------+
| 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. |
+------------------------------------------------------------------------------------------------------------------------------+
*/

151
interp.h Executable file
View File

@ -0,0 +1,151 @@
/*******************************************************************************
' Author: Dave Hein
' Version 0.21
' Copyright (c) 2010, 2011
' See end of file for terms of use.
'******************************************************************************/
//#include <sys/types.h>
#include <stdint.h>
#define BYTE(addr) (((uint8_t *)hubram)[MAP_ADDR(addr)])
#define WORD(addr) (((uint16_t *)hubram)[MAP_ADDR(addr) >> 1])
#define LONG(addr) (((int32_t *)hubram)[MAP_ADDR(addr) >> 2])
// Define system I/O addresses and commands
#define SYS_COMMAND 0x12340000
#define SYS_LOCKNUM 0x12340002
#define SYS_PARM 0x12340004
#define SYS_DEBUG 0x12340008
#define INVALIDATE_INSTR 0x80000000
// This struct is used by the PASM simulator
typedef struct PasmVarsS {
int32_t mem[512];
int32_t state;
int32_t pc;
int32_t cflag;
int32_t zflag;
int32_t cogid;
int32_t waitflag;
int32_t waitmode;
int32_t breakpnt;
// P2 variables
int32_t instruct1;
int32_t instruct2;
int32_t instruct3;
int32_t instruct4;
int32_t pc1;
int32_t pc2;
int32_t pc3;
int32_t pc4;
int32_t dcachehubaddr;
int32_t dcachecogaddr;
int32_t icachehubaddr[4];
int32_t icachenotused[4];
int32_t ptra;
int32_t ptra0;
int32_t ptrb;
int32_t ptrb0;
int32_t ptrx;
int32_t ptry;
int32_t inda;
int32_t inda0;
int32_t indabot;
int32_t indatop;
int32_t indb;
int32_t indb0;
int32_t indbbot;
int32_t indbtop;
int32_t repcnt;
int32_t repbot;
int32_t reptop;
int32_t repforever;
int32_t dcache[8];
int32_t icache[4][8];
int32_t retstack[4];
int32_t auxram[256];
int32_t printflag;
int32_t retptr;
int32_t divq;
int32_t divr;
int32_t divisor;
int32_t mulcount;
int32_t augsvalue;
int32_t augsflag;
int32_t augdvalue;
int32_t augdflag;
int32_t prefetch;
int32_t sqrt;
int32_t lastd;
int64_t acca;
int64_t accb;
int64_t mul;
} PasmVarsT;
// This struct is used by the Spin simulator
// It is a subset of PasmVarsT starting at mem[0x1e0]
typedef struct SpinVarsS {
int32_t x1e0; // $1e0
int32_t x1e1; // $1e1
int32_t x1e2; // $1e2
int32_t x1e3; // $1e3
int32_t x1e4; // $1e4
int32_t masklong; // $1e5
int32_t masktop; // $1e6
int32_t maskwr; // $1e7
int32_t lsb; // $1e8
int32_t id; // $1e9
int32_t dcall; // $1ea
int32_t pbase; // $1eb
int32_t vbase; // $1ec
int32_t dbase; // $1ed
int32_t pcurr; // $1ee
int32_t dcurr; // $1ef
int32_t par; // $1f0
int32_t cnt; // $1f1
int32_t ina; // $1f2
int32_t inb; // $1f3
int32_t outa; // $1f4
int32_t outb; // $1f5
int32_t dira; // $1f6
int32_t dirb; // $1f7
int32_t ctra; // $1f8
int32_t ctrb; // $1f9
int32_t frqa; // $1fa
int32_t frqb; // $1fb
int32_t phsa; // $1fc
int32_t phsb; // $1fd
int32_t vcfg; // $1fe
int32_t vscl; // $1ff
int32_t state;
} SpinVarsT;
void RebootProp(void);
int32_t GetCnt(void);
void UpdatePins(void);
int32_t MAP_ADDR(int32_t addr);
void DebugPasmInstruction(PasmVarsT *pasmvars);
int ExecutePasmInstruction(PasmVarsT *pasmvars);
void DebugPasmInstruction2(PasmVarsT *pasmvars);
int ExecutePasmInstruction2(PasmVarsT *pasmvars);
void StartCog(SpinVarsT *spinvars, int par, int cogid);
void StartPasmCog(PasmVarsT *pasmvars, int par, int addr, int cogid);
void StartPasmCog2(PasmVarsT *pasmvars, int par, int addr, int cogid);
/*
+ -----------------------------------------------------------------------------------------------------------------------------+
| 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. |
+------------------------------------------------------------------------------------------------------------------------------+
*/

250
opcodes.h Executable file
View File

@ -0,0 +1,250 @@
/*******************************************************************************
' Author: Dave Hein
' Version 0.21
' Copyright (c) 2010, 2011
' See end of file for terms of use.
'******************************************************************************/
typedef struct OpCodeS {
unsigned char opform;
unsigned char opcode;
char *opname;
} OpCodeT;
static OpCodeT optable[] = {
{0x00, 0x00, "ldfrmr"},
{0x00, 0x01, "ldfrm"},
{0x00, 0x02, "ldfrmar"},
{0x00, 0x03, "ldfrma"},
{0x05, 0x04, "jmp"},
{0x0a, 0x05, "call"},
{0x07, 0x06, "callobj"},
{0x07, 0x07, "callobjx"},
{0x05, 0x08, "tjz"},
{0x05, 0x09, "djnz"},
{0x05, 0x0a, "jz"},
{0x05, 0x0b, "jnz"},
{0x00, 0x0c, "casedone"},
{0x08, 0x0d, "casevalue"},
{0x08, 0x0e, "caserange"},
{0x00, 0x0f, "lookdone"},
{0x00, 0x10, "lookupval"},
{0x00, 0x11, "lookdnval"},
{0x00, 0x12, "lookuprng"},
{0x00, 0x13, "lookdnrng"},
{0x00, 0x14, "pop"},
{0x00, 0x15, "run"},
{0x00, 0x16, "strsize"},
{0x00, 0x17, "strcomp"},
{0x00, 0x18, "bytefill"},
{0x00, 0x19, "wordfill"},
{0x00, 0x1a, "longfill"},
{0x00, 0x1b, "waitpeq"},
{0x00, 0x1c, "bytemove"},
{0x00, 0x1d, "wordmove"},
{0x00, 0x1e, "longmove"},
{0x00, 0x1f, "waitpne"},
{0x00, 0x20, "clkset"},
{0x00, 0x21, "cogstop"},
{0x00, 0x22, "lockret"},
{0x00, 0x23, "waitcnt"},
{0x00, 0x24, "ldregx"},
{0x00, 0x25, "stregx"},
{0x20, 0x26, "exregx"},
{0x00, 0x27, "waitvid"},
{0x00, 0x28, "coginitret"},
{0x00, 0x29, "locknewret"},
{0x00, 0x2a, "locksetret"},
{0x00, 0x2b, "lockclrret"},
{0x00, 0x2c, "coginit"},
{0x00, 0x2d, "locknew"},
{0x00, 0x2e, "lockset"},
{0x00, 0x2f, "lockclr"},
{0x00, 0x30, "abort"},
{0x00, 0x31, "abortval"},
{0x00, 0x32, "ret"},
{0x00, 0x33, "retval"},
{0x00, 0x34, "ldlim1"},
{0x00, 0x35, "ldli0"},
{0x00, 0x36, "ldli1"},
{0x09, 0x37, "ldlip"},
{0x0a, 0x38, "ldbi"},
{0x0b, 0x39, "ldwi"},
{0x0c, 0x3a, "ldmi"},
{0x0d, 0x3b, "ldli"},
{0x00, 0x3c, "lmm"},
{0x0f, 0x3d, "ldregbit"},
{0x0e, 0x3d, "stregbit"},
{0x0e, 0x3d, "exregbit"},
{0x0f, 0x3e, "ldregbits"},
{0x0e, 0x3e, "stregbits"},
{0x0e, 0x3e, "exregbits"},
{0x0f, 0x3f, "ldreg"},
{0x06, 0x3f, "streg"},
{0x0e, 0x3f, "exreg"},
{0x10, 0x40, "ldlvc"},
{0x10, 0x41, "stlvc"},
{0x30, 0x42, "exlvc"},
{0x10, 0x43, "lalvc"},
{0x11, 0x60, "ldllc"},
{0x11, 0x61, "stllc"},
{0x31, 0x62, "exllc"},
{0x11, 0x63, "lallc"},
{0x00, 0x80, "ldba"},
{0x00, 0x81, "stba"},
{0x20, 0x82, "exba"},
{0x00, 0x83, "laba"},
{0x01, 0x84, "ldbo"},
{0x01, 0x85, "stbo"},
{0x21, 0x86, "exbo"},
{0x01, 0x87, "labo"},
{0x02, 0x88, "ldbv"},
{0x02, 0x89, "stbv"},
{0x22, 0x8a, "exbv"},
{0x02, 0x8b, "labv"},
{0x03, 0x8c, "ldbl"},
{0x03, 0x8d, "stbl"},
{0x23, 0x8e, "exbl"},
{0x03, 0x8f, "labl"},
{0x00, 0x90, "ldbax"},
{0x00, 0x91, "stbax"},
{0x20, 0x92, "exbax"},
{0x00, 0x93, "labax"},
{0x01, 0x94, "ldbox"},
{0x01, 0x95, "stbox"},
{0x21, 0x96, "exbox"},
{0x01, 0x97, "labox"},
{0x02, 0x98, "ldbvx"},
{0x02, 0x99, "stbvx"},
{0x22, 0x9a, "exbvx"},
{0x02, 0x9b, "labvx"},
{0x03, 0x9c, "ldblx"},
{0x03, 0x9d, "stblx"},
{0x23, 0x9e, "exblx"},
{0x03, 0x9f, "lablx"},
{0x00, 0xa0, "ldwa"},
{0x00, 0xa1, "stwa"},
{0x20, 0xa2, "exwa"},
{0x00, 0xa3, "lawa"},
{0x01, 0xa4, "ldwo"},
{0x01, 0xa5, "stwo"},
{0x21, 0xa6, "exwo"},
{0x01, 0xa7, "lawo"},
{0x02, 0xa8, "ldwv"},
{0x02, 0xa9, "stwv"},
{0x22, 0xaa, "exwv"},
{0x02, 0xab, "lawv"},
{0x03, 0xac, "ldwl"},
{0x03, 0xad, "stwl"},
{0x23, 0xae, "exwl"},
{0x03, 0xaf, "lawl"},
{0x00, 0xb0, "ldwax"},
{0x00, 0xb1, "stwax"},
{0x20, 0xb2, "exwax"},
{0x00, 0xb3, "lawax"},
{0x01, 0xb4, "ldwox"},
{0x01, 0xb5, "stwox"},
{0x21, 0xb6, "exwox"},
{0x01, 0xb7, "lawox"},
{0x02, 0xb8, "ldwvx"},
{0x02, 0xb9, "stwvx"},
{0x22, 0xba, "exwvx"},
{0x02, 0xbb, "lawvx"},
{0x03, 0xbc, "ldwlx"},
{0x03, 0xbd, "stwlx"},
{0x23, 0xbe, "exwlx"},
{0x03, 0xbf, "lawlx"},
{0x00, 0xc0, "ldla"},
{0x00, 0xc1, "stla"},
{0x20, 0xc2, "exla"},
{0x00, 0xc3, "lala"},
{0x01, 0xc4, "ldlo"},
{0x01, 0xc5, "stlo"},
{0x21, 0xc6, "exlo"},
{0x01, 0xc7, "lalo"},
{0x02, 0xc8, "ldlv"},
{0x02, 0xc9, "stlv"},
{0x22, 0xca, "exlv"},
{0x02, 0xcb, "lalv"},
{0x03, 0xcc, "ldll"},
{0x03, 0xcd, "stll"},
{0x23, 0xce, "exll"},
{0x03, 0xcf, "lall"},
{0x00, 0xd0, "ldlax"},
{0x00, 0xd1, "stlax"},
{0x20, 0xd2, "exlax"},
{0x00, 0xd3, "lalax"},
{0x01, 0xd4, "ldlox"},
{0x01, 0xd5, "stlox"},
{0x21, 0xd6, "exlox"},
{0x01, 0xd7, "lalox"},
{0x02, 0xd8, "ldlvx"},
{0x02, 0xd9, "stlvx"},
{0x22, 0xda, "exlvx"},
{0x02, 0xdb, "lalvx"},
{0x03, 0xdc, "ldllx"},
{0x03, 0xdd, "stllx"},
{0x23, 0xde, "exllx"},
{0x03, 0xdf, "lallx"},
{0x40, 0xe0, "ror"},
{0x40, 0xe1, "rol"},
{0x40, 0xe2, "shr"},
{0x40, 0xe3, "shl"},
{0x40, 0xe4, "minlim"},
{0x40, 0xe5, "maxlim"},
{0x40, 0xe6, "neg"},
{0x40, 0xe7, "com"},
{0x40, 0xe8, "and"},
{0x40, 0xe9, "abs"},
{0x40, 0xea, "or"},
{0x40, 0xeb, "xor"},
{0x40, 0xec, "add"},
{0x40, 0xed, "sub"},
{0x40, 0xee, "sar"},
{0x40, 0xef, "rev"},
{0x40, 0xf0, "andl"},
{0x40, 0xf1, "encode"},
{0x40, 0xf2, "orl"},
{0x40, 0xf3, "decode"},
{0x40, 0xf4, "mul"},
{0x40, 0xf5, "mulh"},
{0x40, 0xf6, "div"},
{0x40, 0xf7, "mod"},
{0x40, 0xf8, "sqrt"},
{0x40, 0xf9, "cmplt"},
{0x40, 0xfa, "cmpgt"},
{0x40, 0xfb, "cmpne"},
{0x40, 0xfc, "cmpeq"},
{0x40, 0xfd, "cmple"},
{0x40, 0xfe, "cmpge"},
{0x40, 0xff, "notl"},
{0x60, 0x00, "store"},
{0x60, 0x02, "repeat"},
{0x60, 0x06, "repeats"},
{0x60, 0x08, "randf"},
{0x60, 0x0c, "randr"},
{0x60, 0x10, "sexb"},
{0x60, 0x14, "sexw"},
{0x60, 0x18, "postclr"},
{0x60, 0x1c, "postset"},
{0x60, 0x20, "preinc"},
{0x60, 0x28, "postinc"},
{0x60, 0x30, "predec"},
{0x60, 0x38, "postdec"},
{0, 0, 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. |
+------------------------------------------------------------------------------------------------------------------------------+
*/

BIN
p1spin/Simple_Serial.spin Executable file

Binary file not shown.

243
p1spin/dry11.spin Executable file
View File

@ -0,0 +1,243 @@
'**********************************************
' Dhrystone 1.1
'**********************************************
OBJ
ser : "Simple_Serial"
CON
_clkmode = xtal1+pll16x
_clkfreq = 80000000
LOOPS = 500
Ident1 = 1
Ident2 = 2
Ident3 = 3
Ident4 = 4
Ident5 = 5
' typedef struct Record
PtrComp = 0
Discr = 4
EnumComp = 8
IntComp = 12
StringComp = 16
NULL = 0
DAT
Version byte "1.1", 0
Array1Glob long 0[51]
Array2Glob long 0[51*51]
xxx long 0[12]
yyy long 0[12]
PtrGlb long 0
PtrGlbNext long 0
IntGlob long 0
BoolGlob long 0
Char1Glob long 0
Char2Glob long 0
String1Loc long 0[8]
String2Loc long 0[8]
starttime long 0
benchtime long 0
nulltime long 0
PUB Dhrystone11
PtrGlb := @xxx
PtrGlbNext := @yyy
Proc0
{
* Package 1
}
PUB Proc0 | IntLoc1, IntLoc2, IntLoc3, CharLoc, CharIndex, EnumLoc, i
starttime := time_msec
i := 0
repeat while (i < LOOPS)
++i
nulltime := time_msec - starttime { Computes o'head of loop }
long[PtrGlb + PtrComp] := PtrGlbNext
long[PtrGlb + Discr] := Ident1
long[PtrGlb + EnumComp] := Ident3
long[PtrGlb + IntComp] := 40
strcpy((PtrGlb + StringComp), string("DHRYSTONE PROGRAM, SOME STRING"))
strcpy(@String1Loc, string("DHRYSTONE PROGRAM, 1'ST STRING")) {GOOF}
long[@Array2Glob][8 * 51 + 7] := 10 { Was missing in published program }
{****************
-- Start Timer --
****************}
starttime := time_msec
i := 0
repeat while (i < LOOPS)
Proc5
Proc4
IntLoc1 := 2
IntLoc2 := 3
strcpy(@String2Loc, string("DHRYSTONE PROGRAM, 2'ND STRING"))
EnumLoc := Ident2
BoolGlob := not Func2(@String1Loc, @String2Loc)
repeat while (IntLoc1 < IntLoc2)
IntLoc3 := 5 * IntLoc1 - IntLoc2
Proc7(IntLoc1, IntLoc2, @IntLoc3)
++IntLoc1
Proc8(@Array1Glob, @Array2Glob, IntLoc1, IntLoc3)
Proc1(PtrGlb)
byte[@CharIndex] := "A"
repeat while (byte[@CharIndex] =< Char2Glob)
if (EnumLoc == Func1(byte[@CharIndex], "C"))
Proc6(Ident1, @EnumLoc)
byte[@CharIndex] := byte[@charIndex] + 1
IntLoc3 := IntLoc2 * IntLoc1
IntLoc2 := IntLoc3 / IntLoc1
IntLoc2 := 7 *(IntLoc3 - IntLoc2) - IntLoc1
Proc2(@IntLoc1)
++i
{****************
-- Stop Timer --
****************}
benchtime := time_msec - starttime - nulltime
ser.str(string("Dhrystone("))
ser.str(@Version)
ser.str(string(") time for "))
ser.dec(LOOPS)
ser.str(string(" passes = "))
ser.dec(benchtime)
ser.str(string(" msec", 13))
ser.str(string("This machine benchmarks at "))
ser.dec(LOOPS * 1000 / benchtime)
ser.str(string(" dhrystones/second", 13))
PUB Proc1(PtrParIn)
memcpy(long[PtrParIn + PtrComp], PtrGlb, 48)
long[PtrParIn + IntComp] := 5
long[long[PtrParIn + PtrComp] + IntComp] := long[PtrParIn + IntComp]
long[long[PtrParIn + PtrComp] + PtrComp] := long[PtrParIn + PtrComp]
Proc3(long[long[PtrParIn + PtrComp] + PtrComp])
if (long[long[PtrParIn + PtrComp] + Discr] == Ident1)
long[long[PtrParIn + PtrComp] + IntComp] := 6
Proc6(long[PtrParIn + EnumComp], long[PtrParIn + PtrComp] + EnumComp)
long[long[PtrParIn + PtrComp] + PtrComp] := long[PtrGlb + PtrComp]
Proc7(long[long[PtrParIn + PtrComp] + IntComp], 10, long[PtrParIn + PtrComp] + IntComp)
else
memcpy(PtrParIn, long[PtrParIn + PtrComp], 48)
PUB Proc2(IntParIO) | IntLoc, EnumLoc
IntLoc := long[IntParIO] + 10
repeat 'while ()
if (Char1Glob == "A")
--IntLoc
long[IntParIO] := IntLoc - IntGlob
EnumLoc := Ident1
if (EnumLoc == Ident1)
quit
PUB Proc3(PtrParOut)
if (PtrGlb <> NULL)
PtrParOut := long[PtrGlb + PtrComp]
else
IntGlob := 100
Proc7(10, IntGlob, PtrGlb + IntComp)
PUB Proc4 | BoolLoc
BoolLoc := Char1Glob == "A"
BoolLoc |= BoolGlob
Char2Glob := "B"
PUB Proc5
Char1Glob := "A"
BoolGlob := FALSE
PUB Proc6(EnumParIn, EnumParOut)
long[EnumParOut] := EnumParIn
ifnot Func3(EnumParIn)
long[EnumParOut] := Ident4
if EnumParIn == Ident1
long[EnumParOut] := Ident1
elseif EnumParIn == Ident2
if (IntGlob > 100)
long[EnumParOut] := Ident1
else
long[EnumParOut] := Ident4
elseif EnumParIn == Ident3
long[EnumParOut] := Ident2
elseif (EnumParIn == Ident4) or (EnumParIn == Ident5)
long[EnumParOut] := Ident3
PUB Proc7(IntParI1, IntParI2, IntParOut) | IntLoc
IntLoc := IntParI1 + 2
long[IntParOut] := IntParI2 + IntLoc
PUB Proc8(Array1Par, Array2Par, IntParI1, IntParI2) | IntLoc, IntIndex
IntLoc := IntParI1 + 5
long[Array1Par][IntLoc] := IntParI2
long[Array1Par][IntLoc + 1] := long[Array1Par][IntLoc]
long[Array1Par][IntLoc + 30] := IntLoc
IntIndex := IntLoc
repeat while (IntIndex =<(IntLoc + 1))
long[Array2Par][IntLoc * 51 + IntIndex] := IntLoc
++IntIndex
++long[Array2Par][IntLoc * 51 + IntLoc - 1]
long[Array2Par][(IntLoc + 20) * 51 + IntLoc] := long[Array1Par][IntLoc]
IntGlob := 5
PUB Func1(CharPar1, CharPar2) | CharLoc1, CharLoc2
byte[@CharLoc1] := byte[@CharPar1]
byte[@CharLoc2] := byte[@CharLoc1]
if (byte[@CharLoc2] <> byte[@CharPar2])
return (Ident1)
else
return (Ident2)
PUB Func2(StrParI1, StrParI2) | IntLoc, CharLoc
IntLoc := 1
repeat while (IntLoc =< 1)
if (Func1(byte[StrParI1][IntLoc], byte[StrParI2][IntLoc + 1]) == Ident1)
byte[@CharLoc] := "A"
++IntLoc
if (byte[@CharLoc] => "W" and byte[@CharLoc] =< "Z")
IntLoc := 7
if (byte[@CharLoc] == "X")
return (TRUE)
else
if (strcmp(StrParI1, StrParI2) > 0)
IntLoc += 7
return (TRUE)
else
return (FALSE)
PUB Func3(EnumParIn) | EnumLoc
EnumLoc := EnumParIn
if (EnumLoc == Ident3)
return (TRUE)
return (FALSE)
PUB strcpy(dst, src)
bytemove(dst, src, strsize(src) + 1)
{
repeat strsize(src)
byte[dst++] := byte[src++]
}
PUB memcpy(dst, src, num)
bytemove(dst, src, num)
{
repeat num
byte[dst++] := byte[src++]
}
PUB strcmp(str1, str2)
result := not strcomp(str1, str2)
{
repeat while byte[str1]
if byte[str1] <> byte[str2]
quit
str1++
str2++
return byte[str1] - byte[str2]
}
PUB time_msec
return cnt / (_clkfreq/1000)

2069
p1spin/p1spin.spin Executable file

File diff suppressed because it is too large Load Diff

351
p1spin/spasm.txt Executable file
View File

@ -0,0 +1,351 @@
SPASM(1) User Commands SPASM(1)
NAME
spasm - spin assembler
SYNOPSIS
spasm [-l] [-d] FILE
DESCRIPTION
Spasm assembles the source file given by FILE. The file name may
include the extension, or .spa will be assumed if no extension is
specified. The assembled binary program will written to a file with
the same root name plus a .bin extension. If -l is specified, it will
print an assembly listing. If -d is specified, spasm will print debug
information.
Spasm is an assembly language that defines mnemonics for Spin
bytecodes. Spin bytecodes are executed by the Spin interpreter, which
is loaded at boot time from the internal ROM. The Spin interpreter is
a stack-based virtual machine that uses the stack to store parameters
that are used by operators, such as add, sub, etc. The operators store
their results back onto the stack. There are other operators that
transfer data back and forth between the stack and hub RAM.
The Spin bytecodes are listed below. They are separated into four
major groups -- lower, memory, math and extened operators. The lower
group contains a mix of operators, including those that handle program
flow, lookup, lookdown, case, and several other miscellaneous functions.
The math operators implement the various math and logic functions that
use two arguments.
The memory operators implement load, store, execute and address
functions. A load operation reads data from the hub RAM and pushes it
onto the stack. A store operation pops a value off the stack and
stores it in RAM. The address operator is used to push the absolute
address of a hub RAM location onto the stack.
The execute operation is used to execute an operation directly on a RAM
location. The result can be optionally pushed to the stack. The
operations that can be executed directly on a hub RAM location include
the standard 32 math operations plus a small number of extended
operations. The extended operators include pre and post increment and
decrement, sign extension and the random function.
The format of the memory mnemonics is as follows:
<operation><size><type><mode>
operation = {ld, st, ex, la},
size = {b, w, l},
type = {i, l, o, a, v, s}
mode = {c, x, 0, 1, m1, p}
The operations are load, store, execute and load address as stated
earlier. The size refers to byte, word and long. The types are
immediate, local, object, absolute, variable and stack. The modes
are compact, indexed, zero, one, minus one and packed.
As an example, the instruction ldwi means load-word-immediate. It
will load an immediate value onto the stack. The instruction stba
will store a byte at the absolute address residing in the stack.
There are compact instructions that use a single byte to address
the first 8 long values residing in the method's stack frame or in
an object's variable space. These use the size, type and mode
characters "llc". As an example, the method result value can be
set with the "stllc 0" instruction. The fourth long in the objet's
variable section could be loaded with "ldllc 12".
When an execute memory operation is specified it is followed by one of
the math operators or an extended operator. An execute instruction may
also specify the "load" extended operator to save the result on the
stack. Examples of using execute instructions are as follows:
exlo $8 add ' Add value on stack to the object long at offset $8
exwv $20 preinc ' Increment the VAR word at offset $20
exll $10 postdec load ' Decrement stack location $10 and load
Spasm also includes psuedo-ops, which are shortened versions of the
memory mnenomics. The psuedo-ops are made up only of the operation
and size fields, plus the "x" charater if it is indexed. The
psuedo-ops are mapped to explicit opcodes depending on the context
of the operand. As an example "ldl 1" maps into "ldli1", and
"ldl result" maps into "ldllc 0".
The Spasm opcodes are listed below. The offsets used for the jump
instructions are signed offsets that are relative to the address of the
next instruction. A "jmp 0" instruction will just execute the next
instruction.
Signed offsets are encoded in either one or two bytes depending
on the value of the most significant bit in the first byte. If the
MSB is zero the remaining seven bits are treated as a signed 7-bit
number in the range from -64 to 63. If the MSB is non-zero, the
remaining seven bits are used as the most significant bits of a 15-bit
signed number, and the next byte provides the eight least sigficant
bits. The 15-bit signed offset has a range from -16384 to 16383.
The memory opcodes use an unsigned offset that can also be encoded in
one or two bytes. The MSB is used to determine whether it is one or
two bytes just like for signed offset. However, since it is unsigned,
the range for the one-byte offset is 0 to 128, and for two bytes it is
0 to 32768.
Lower Opcodes
-------------
00 ldfrmr - Load call frame with return value required
01 ldfrm - Load call frame
02 ldfrmar - Load call frame with abort trap & return value
03 ldfrma - Load call frame with abort trap
04 jmp offset - Jump to signed object offset
05 call meth - Call method
06 callobj meth, obj - Call method in object
07 callobjx meth, obj - Call method in object with index
08 tjz offset - Test and jump if zero
09 djnz offset - Decrement and jump if not zero
0a jz offset - Jump if zero
0b jnz offset - Jump if not zero
0c casedone - Case done without a match
0d casevalue - Execute if value matches case value
0e caserange - Execute if case value within range
0f lookdone - Look up/down done without a match
10 lookupval -
11 lookdnval
12 lookuprng
13 lookdnrng
14 pop - Discard N bytes from the stack
15 run - Prepare new spin cog stack for execution
16 strsize - Determine the size of a string
17 strcomp - Compare two strings
18 bytefill - Fill memory with a constant byte value
19 wordfill - Fill memory with a constant word value
1a longfill - Fill memory with a constant long value
1b waitpeq - Wait till pins are equal to a value
1c bytemove - Copy bytes to a new location
1d wordmove - Copy words to a new location
1e longmove - Copy longs to a new location
1f waitpne - Wait till pins are not equal to value
20 clkset - Change the clock frequency and mode
21 cogstop - Stop the specified cog
22 lockret - Return a lock
23 waitcnt - Wait for cnt to equal a specified value
24 ldlsx
25 stlsx
26 exlsx
27 waitvid - Wait on video
28 coginitret - Start a cog and return the cog number
29 locknewret - Allocate a lock and return the lock number
2a locksetret - Set a lock and return the previous value
2b lockclrret - Clear a lock and return the previous value
2c coginit - Start a cog
2d locknew - Allocate a lock with no return value
2e lockset - Set a lock with no return value
2f lockclr - Clear a lock with no return value
30 abort - Perform an abort to the next abort trap
31 abortval - Perform an abort and return a value
32 ret - Return without loading a return value
33 retval - Return and load a return value on the stack
34 ldlim1 - Load a minus 1
35 ldli0 - Load zero
36 ldli1 - Load 1
37 ldlip value - Load a packed-byte constant
38 ldbi value - Load a single-byte constant
39 ldwi value - Load a two-byte constant
3a ldmi value - Load a three-byte constant
3b ldli value - Load a four-byte constant
3c --- - Unused opcode
3d ldregbit - Load a bit from a register
3d stregbit - Store a bit to a register
3e ldregbits - Load bits from a register
3e stregbits - Store bit to a register
3f ldreg - Load a register
3f streg - Store a register
Compact Memory Opcodes
--------------
40 ldlvc offset - Load long variable compact
41 stlvc offset - Store long variable compact
42 exlvc offset - Execute on a long variable compact
43 lalvc offset - Load address of a long variable compact
60 ldllc offset - Load long local compact
61 stllc offset - Store long local compact
62 exllc offset - Execute on a long local compact
63 lallc offset - Load address of a long local compact
Byte Memory Opcodes
--------------
80 ldba - Load byte absolute
81 stba - Store byte absolute
82 exba - Execute on a byte absolute
83 laba - Load address of a byte absolute
84 ldbo offset - Load byte object offset
85 stbo offset
86 exbo offset
87 labo offset
88 ldbv offset - Load byte variable offset
89 stbv offset
8a exbv offset
8b labv offset
8c ldbl offset - Load byte local offset
8d stbl offset
8e exbl offset
8f labl offset
90 ldbax - Load byte absolute with index
91 stbax
92 exbax
93 labax
94 ldbox offset - Load byte object offset with index
95 stbox offset
96 exbox offset
97 labox offset
98 ldbvx offset - Load byte variable offset with index
99 stbvx offset
9a exbvx offset
9b labvx offset
9c ldblx offset - Load byte local offset with index
9d stblx offset
9e exblx offset
9f lablx offset
Word Memory Opcodes
-------------------
a0 ldwa - Load word absolute
a1 stwa
a2 exwa
a3 lawa
a4 ldwo offset
a5 stwo offset
a6 exwo offset
a7 lawo offset
a8 ldwv offset
a9 stwv offset
aa exwv offset
ab lawv offset
ac ldwl offset
ad stwl offset
ae exwl offset
af lawl offset
b0 ldwax - Load word absolute with index
b1 stwax
b2 exwax
b3 lawax
b4 ldwox offset
b5 stwox offset
b6 exwox offset
b7 lawox offset
b8 ldwvx offset
b9 stwvx offset
ba exwvx offset
bb lawvx offset
bc ldwlx offset
bd stwlx offset
be exwlx offset
bf lawlx offset
Long Memory Opcodes
-------------------
c0 ldla - Load long absolute
c1 stla
c2 exla
c3 lala
c4 ldlo offset
c5 stlo offset
c6 exlo offset
c7 lalo offset
c8 ldlv offset
c9 stlv offset
ca exlv offset
cb lalv offset
cc ldll offset
cd stll offset
ce exll offset
cf lall offset
d0 ldlax - Load long absolute with index
d1 stlax
d2 exlax
d3 lalax
d4 ldlox offset
d5 stlox offset
d6 exlox offset
d7 lalox offset
d8 ldlvx offset
d9 stlvx offset
da exlvx offset
db lalvx offset
dc ldllx offset
dd stllx offset
de exllx offset
df lallx offset
Math Opcodes
------------
e0 ror - Rotate right
e1 rol - Rotate left
e2 shr - Shift right
e3 shl - Shift left
e4 min - Maximum
e5 max - Minimum
e6 neg - Negate
e7 com - Compliment
e8 and - Bitwise and
e9 abs - Absolute value
ea or - Bitwise or
eb xor - Bitwise exclusive or
ec add - Add
ed sub - Subtract
ee sar - Shift arithmetic right
ef rev - Bit reverse
f0 andl - Logical and
f1 encode - Shift "1" left
f2 orl - Logical or
f3 decode - Find left-most "1" bit
f4 mul - Multiply
f5 mulh - Multiply high
f6 div - Divide
f7 mod - Modulus
f8 sqrt - Square root
f9 cmplt - Less than
fa cmpgt - Greater than
fb cmpne - Not equal
fc cmpeq - Equal
fd cmple - Less than or equal
fe cmpge - Greater than or equal
ff notl - Logical not
Extended opcodes
----------------
00 load - Load the value
02 repeat - Repeat index from first to last
06 repeats - Repeat index from first to last with step
08 randf - Forward random number
0c randr - Reverse random number
10 sexb - Sign extend byte
14 sexw - Sign extend word
18 postclr - Post clear to zero
1c postset - Post set to all ones
26 preinc - Pre-increment
2e postinc - Post-increment
36 predec - Pre-decrement
3e postdec - Post-decrement
AUTHOR
Dave Hein
COPYRIGHT
Copyright (c) 2011, 2012, Dave Hein
MIT License (See license.txt in the root directory)
This is free software: you are free to change and redistribute it.
There is no warranty, to the extent permitted by law.
SPASM March 2012 SPASM(1)

BIN
p1spin/test.binary Executable file

Binary file not shown.

14
p1spin/test.spin Executable file
View File

@ -0,0 +1,14 @@
CON
_clkmode = xtal1+pll16x
_clkfreq = 80_000_000
OBJ
ser : "Simple_Serial"
dry : "dry11"
PUB main | ptr, count
'waitcnt(clkfreq*3+cnt)
ser.init(31, 30, 19200)
ser.str(string(13, "Testing Spin Interpreter", 13))
dry.Dhrystone11
waitcnt(clkfreq/10+cnt)

231
pasmdebug.c Executable file
View File

@ -0,0 +1,231 @@
/*******************************************************************************
' Author: Dave Hein
' Version 0.21
' Copyright (c) 2010, 2011
' See end of file for terms of use.
'******************************************************************************/
#include <stdio.h>
#include <string.h>
#include "interp.h"
char *FindChar(char *str, int32_t val);
int32_t CheckWaitFlag(PasmVarsT *pasmvars, int mode);
extern char *hubram;
extern int32_t memsize;
extern int32_t loopcount;
extern int32_t cycleaccurate;
extern FILE *tracefile;
static char *condnames[16] = {
"if_never ", "if_nz_and_nc", "if_z_and_nc ", "if_nc ",
"if_nz_and_c ", "if_nz ", "if_z_ne_c ", "if_nz_or_nc ",
"if_z_and_c ", "if_z_eq_c ", "if_z ", "if_z_or_nc ",
"if_c ", "if_nz_or_c ", "if_z_or_c ", " "};
static char *opnames[64][2] = {
{"wrbyte", "rdbyte"}, {"wrword", "rdword"}, {"wrlong", "rdlong"},
{"hubop nr", "hubop"}, {"undef nr", "undef"}, {"undef nr", "undef"},
{"undef nr", "undef"}, {"undef nr", "undef"}, {"ror nr", "ror"},
{"rol nr", "rol"}, {"shr nr", "shr"}, {"shl nr", "shl"},
{"rcr nr", "rcr"}, {"rcl nr", "rcl"}, {"sar nr", "sar"},
{"rev nr", "rev"}, {"mins nr", "mins"}, {"maxs nr", "maxs"},
{"min nr", "min"}, {"max nr", "max"}, {"movs nr", "movs"},
{"movd nr", "movd"}, {"movi nr", "movi"}, {"jmp", "call"},
{"test", "and"}, {"testn", "andn"}, {"or nr", "or"},
{"xor nr", "xor"}, {"muxc nr", "muxc"}, {"muxnc nr", "muxnc"},
{"muxz nr", "muxz"}, {"muxnz nr", "muxnz"}, {"add nr", "add"},
{"cmp", "sub"}, {"addabs nr", "addabs"}, {"subabs nr", "subabs"},
{"sumc nr", "sumc"}, {"sumnc nr", "sumnc"}, {"sumz nr", "sumz"},
{"sumnz nr", "sumnz"}, {"mov nr", "mov"}, {"neg nr", "neg"},
{"abs nr", "abs"}, {"absneg nr", "absneg"}, {"negc nr", "negc"},
{"negnc nr", "negnc"}, {"negz nr", "negz"}, {"negnz nr", "negnz"},
{"cmps", "cmps wr"}, {"cmpsx", "cmpsx wr"}, {"addx nr", "addx"},
{"cmpx", "subx"}, {"adds nr", "adds"}, {"subs nr", "subs"},
{"addsx nr", "addsx"}, {"subsx nr", "subsx"}, {"cmpsub nr", "cmpsub"},
{"djnz nr", "djnz"}, {"tjnz", "tjnz wr"}, {"tjz", "tjz wr"},
{"waitpeq", "waitpeq wr"}, {"waitpne", "waitpne wr"},
{"waitcnt nr", "waitcnt"}, {"waitvid", "waitvid wr"}};
static char *hubops[8][2] = {
{"clkset", "clkset wr"}, {"cogid nr", "cogid"},
{"coginit", "coginit wr"}, {"cogstop", "cogstop wr"},
{"locknew nr", "locknew"}, {"lockret", "lockret wr"},
{"lockset", "lockset wr"}, {"lockclr", "lockclr wr"}};
static int32_t swapshift[32] = {
28, 23, 8, 16, 21, 7, 21, 7, 3, 7, 13, 9, 19, 4,-13, 15,
-8,-17, -3, 7, 2, -8,-16, 6,-21,-16, -8,-23,-26,-22,-25,-10};
static uint32_t swapmask[32] = {
0x00000008, 0x00000080, 0x00200000, 0x00001000, 0x00000040, 0x00080000,
0x00000010, 0x00020000, 0x00100000, 0x00008000, 0x00000100, 0x00000800,
0x00000001, 0x00004000, 0x40000000, 0x00000002, 0x00800000, 0x80000000,
0x00010000, 0x00000020, 0x00000200, 0x00040000, 0x02000000, 0x00000004,
0x10000000, 0x00400000, 0x00002000, 0x08000000, 0x20000000, 0x01000000,
0x04000000, 0x00000400};
static uint32_t swapit(uint32_t val1)
{
int32_t i, shift;
uint32_t mask;
uint32_t val2;
val2 = 0;
for (i = 0; i < 32; i++)
{
mask = swapmask[i];
shift = swapshift[i];
if (shift >= 0)
val2 |= (val1 & mask) << shift;
else
val2 |= (val1 & mask) >> -shift;
}
return val2;
}
void StartPasmCog(PasmVarsT *pasmvars, int32_t par, int32_t addr, int32_t cogid)
{
int32_t i;
pasmvars->waitflag = 0;
pasmvars->cflag = 0;
pasmvars->zflag = 0;
pasmvars->pc = 0;
pasmvars->pc1 = 512;
pasmvars->pc2 = 512;
pasmvars->instruct1 = 0;
pasmvars->instruct2 = 0;
pasmvars->cogid = cogid;
pasmvars->state = 5;
pasmvars->mem[496] = par;
for (i = 0; i < 496; i++)
{
if (addr & 0x8000)
pasmvars->mem[i] = swapit(LONG(addr));
else
pasmvars->mem[i] = LONG(addr);
addr += 4;
}
}
void DebugPasmInstruction(PasmVarsT *pasmvars)
{
int32_t i;
int32_t cflag = pasmvars->cflag;
int32_t zflag = pasmvars->zflag;
int32_t instruct, cond, pc;
int32_t opcode, value2, value1, zcri;
int32_t srcaddr, dstaddr;
char *wzstr;
char *wcstr;
char *wrstr;
char *ptr;
char opstr[20];
char *istr[2] = {" ", "#"};
char *xstr[4] = {"X", " ", "W", "I"};
int32_t xflag;
// Fetch the instruction
if (pasmvars->waitflag)
{
pc = pasmvars->pc2;
instruct = pasmvars->instruct2;
}
else
{
pc = pasmvars->pc1;
instruct = pasmvars->instruct1;
}
cond = (instruct >> 18) & 15;
xflag = ((cond >> ((cflag << 1) | zflag)) & 1);
// Check if the instruction is invalidated in the pipeline
if (pc & 0xfffffe00)
{
pc &= 0x1ff;
xflag = 3;
}
// Extract parameters from the instruction
opcode = (instruct >> 26) & 63;
srcaddr = instruct & 511;
dstaddr = (instruct >> 9) & 511;
zcri = (instruct >> 22) & 15;
// Get the two operands
value1 = pasmvars->mem[dstaddr];
if (zcri & 1)
value2 = srcaddr;
else
value2 = pasmvars->mem[srcaddr];
// Check for wait cycles for djnz, tjnz, tjz or hubop
if (cycleaccurate && xflag == 1)
{
if (opcode <= 0x07) // hubop
{
if (CheckWaitFlag(pasmvars, 3)) xflag = 2;
}
else if (opcode == 0x3e) // waitcnt
{
int32_t result = GetCnt() - value1;
if (result < 0 || result >= 4) xflag = 2;
}
}
if (zcri&8) wzstr = " wz";
else wzstr = "";
if (zcri&4) wcstr = " wc";
else wcstr = "";
wrstr = "";
if (opcode == 3)
strcpy(opstr, hubops[value2 & 7][(zcri>>1)&1]);
else
strcpy(opstr, opnames[opcode][(zcri>>1)&1]);
ptr = FindChar(opstr, ' ');
if (*ptr)
{
*ptr++ = 0;
if (*ptr == 'w')
wrstr = " wr";
else if (*ptr == 'n')
wrstr = " nr";
}
i = strlen(opstr);
while (i < 7) opstr[i++] = ' ';
opstr[i] = 0;
#if 0
fprintf(tracefile, "%3.3x %8.8x %d %d %s %s %s %3.3x %s%3.3x %8.8x %8.8x", pasmvars->pc,
instruct, zflag, cflag, xstr[xflag], condnames[cond], opstr, dstaddr,
istr[zcri & 1], srcaddr, value1, value2);
#else
fprintf(tracefile, "%6d %3.3x %8.8x %s %s %s %3.3x, %s%3.3x%s%s%s", loopcount * 4, pc,
instruct, xstr[xflag], condnames[cond], opstr, dstaddr,
istr[zcri & 1], srcaddr, wzstr, wcstr, wrstr);
#endif
}
/*
+------------------------------------------------------------------------------------------------------------------------------+
| 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. |
+------------------------------------------------------------------------------------------------------------------------------+
*/

448
pasmdebug2.c Executable file
View File

@ -0,0 +1,448 @@
/*******************************************************************************
' Author: Dave Hein
' Version 0.21
' Copyright (c) 2010, 2011
' See end of file for terms of use.
'******************************************************************************/
#include <stdio.h>
#include <string.h>
#include "interp.h"
#include "spinsim.h"
#define REG_PINA 0x1f4
extern char *hubram;
extern int32_t memsize;
extern int32_t loopcount;
extern int32_t cycleaccurate;
extern int32_t pin_val;
extern FILE *tracefile;
static char *condnames[16] = {
"if_never ", "if_nz_and_nc", "if_z_and_nc ", "if_nc ",
"if_nz_and_c ", "if_nz ", "if_z_ne_c ", "if_nz_or_nc ",
"if_z_and_c ", "if_z_eq_c ", "if_z ", "if_z_or_nc ",
"if_c ", "if_nz_or_c ", "if_z_or_c ", " "};
char *opcodes_lower[64] = {
"rdbyte","rdbytec","rdword","rdwordc","rdlong","rdlongc","rdaux","rdauxr",
"isob","notb","clrb","setb","setbc","setbnc","setbz","setbnz",
"andn","and","or","xor","muxc","muxnc","muxz","muxnz",
"ror","rol","shr","shl","rcr","rcl","sar","rev",
"mov","not","abs","neg","negc","negnc","negz","negnz",
"add","sub","addx","subx","adds","subs","addsx","subsx",
"sumc","sumnc","sumz","sumnz","min","max","mins","maxs",
"addabs","subabs","incmod","decmod","cmpsub","subr","mul","scl"};
char *opcodes_upper[62][4] = {
{"decod2", "decod2", "decod2", "decod2"},
{"decod3", "decod3", "decod3", "decod3"},
{"decod4", "decod4", "decod4", "decod4"},
{"decod5", "decod5", "decod5", "decod5"},
{"encod", "blmask", "encod", "blmask"},
{"onecnt", "zercnt", "onecnt", "zercnt"},
{"incpat", "incpat", "decpat", "decpat"},
{"splitb", "mergeb", "splitw", "mergew"},
{"getnib", "setnib", "getnib", "setnib"},
{"getnib", "setnib", "getnib", "setnib"},
{"getnib", "setnib", "getnib", "setnib"},
{"getnib", "setnib", "getnib", "setnib"},
{"getword","setword","getword","setword"},
{"setwrds","rolnib", "rolbyte","rolword"},
{"sets", "setd", "setx", "seti"},
{"cognew", "cognew", "waitcnt","waitcnt"},
{"getbyte","setbyte","getbyte","setbyte"},
{"getbyte","setbyte","getbyte","setbyte"},
{"setbyts","movbyts","packrgb","unpkrgb"},
{"addpix", "mulpix", "blnpix", "mixpix"},
{"jmpsw", "jmpsw", "jmpsw", "jmpsw"},
{"jmpswd", "jmpswd", "jmpswd", "jmpswd"},
{"ijz", "ijzd", "ijnz", "ijnzd"},
{"djz", "djzd", "djnz", "djnzd"},
{"testb", "testb", "testb", "testb"},
{"testn", "testn", "testn", "testn"},
{"test", "test", "test", "test"},
{"cmp", "cmp", "cmp", "cmp"},
{"cmpx", "cmpx", "cmpx", "cmpx"},
{"cmps", "cmps", "cmps", "cmps"},
{"cmpsx", "cmpsx", "cmpsx", "cmpsx"},
{"cmpr", "cmpr", "cmpr", "cmpr"},
{"coginit","waitvid","coginit","waitvid"},
{"coginit","waitvid","coginit","waitvid"},
{"coginit","waitvid","coginit","waitvid"},
{"coginit","waitvid","coginit","waitvid"},
{"waitpeq","waitpeq","waitpeq","waitpeq"},
{"waitpeq","waitpeq","waitpeq","waitpeq"},
{"waitpne","waitpne","waitpne","waitpne"},
{"waitpne","waitpne","waitpne","waitpne"},
{"wrbyte", "wrbyte", "wrword", "wrword"},
{"wrlong", "wrlong", "frac", "frac"},
{"wraux", "wraux", "wrauxr", "wrauxr"},
{"setacca","setacca","setaccb","setaccb"},
{"maca", "maca", "macb", "macb"},
{"mul32", "mul32", "mul32u", "mul32u"},
{"div32", "div32", "div32u", "div32u"},
{"div64", "div64", "div64u", "div64u"},
{"sqrt64", "sqrt64", "qsincos","qsincos"},
{"qarctan","qarctan","qrotate","qrotate"},
{"setsera","setsera","setserb","setserb"},
{"setctrs","setctrs","setwavs","setwavs"},
{"setfrqs","setfrqs","setphss","setphss"},
{"addphss","addphss","subphss","subphss"},
{"jp", "jp", "jpd", "jpd"},
{"jnp", "jnp", "jnpd", "jnpd"},
{"cfgpins","cfgpins","cfgpins","cfgpins"},
{"cfgpins","cfgpins","jmptask","jmptask"},
{"setxfr", "setxfr", "setmix", "setmix"},
{"jz", "jzd", "jnz", "jnzd"},
{"locbase","locbyte","locword","loclong"},
{"jmplist","locinst","augs", "augd"}};
int zci_upper[62][4] = {
{7, 7, 7, 7}, {7, 7, 7, 7}, {7, 7, 7, 7}, {7, 7, 7, 7},
{5, 5, 5, 5}, {5, 5, 5, 5}, {3, 3, 3, 3}, {1, 1, 1, 1},
{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1},
{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {3, 3, 3, 3},
{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1},
{7, 7, 7, 7}, {7, 7, 7, 7}, {1, 1, 1, 1}, {1, 1, 1, 1},
{7, 7, 7, 7}, {7, 7, 7, 7}, {7, 7, 7, 7}, {7, 7, 7, 7},
{7, 7, 7, 7}, {7, 7, 7, 7}, {7, 7, 7, 7}, {7, 7, 7, 7},
{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1},
{3, 3, 3, 3}, {3, 3, 3, 3}, {3, 3, 3, 3}, {3, 3, 3, 3},
{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1},
{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1},
{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1},
{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1},
{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}};
char *opcodes_ind[16] = {
"invalid", "fixinda", "setinda", "setinda",
"fixindb", "fixinds", "invalid", "invalid",
"setindb", "invalid", "setinds", "setinds",
"setindb", "invalid", "setinds", "setinds"};
char *opcodes_16[14] = {
"locptra","locptrb","jmp","jmpd","call","calld","calla",
"callad","callb","callbd","callx","callxd","cally","callyd"};
char *opcodes_set1[49] = {
"cogid","taskid","locknew","getlfsr","getcnt","getcntx","getacal","getacah",
"getacbl","getacbh","getptra","getptrb","getptrx","getptry","serina","serinb",
"getmull","getmulh","getdivq","getdivr","getsqrt","getqx","getqy","getqz",
"getphsa","getphza","getcosa","getsina","getphsb","getphzb","getcosb","getsinb",
"pushzc","popzc","subcnt","getpix","binbcd","bcdbin","bingry","grybin",
"eswap4","eswap8","seussf","seussr","incd","decd","incds","decds","pop"};
char *opcodes_set2[] = {
"clkset", "cogstop", "lockset", "lockclr", "lockret", "rdwidec", "rdwide",
"wrwide", "getp", "getnp", "serouta", "seroutb", "cmpcnt", "waitpx",
"waitpr", "waitpf", "setzc", "setmap", "setxch", "settask", "setrace",
"saracca", "saraccb", "saraccs", "setptra", "setptrb", "addptra", "addptrb",
"subptra", "subptrb", "setwide", "setwidz", "setptrx", "setptry",
"addptrx", "addptry", "subptrx", "subptry", "passcnt", "wait", "offp",
"notp", "clrp", "setp", "setpc", "setpnc", "setpz", "stpnz", "div64d",
"sqrt32", "qlog", "qexp", "setqi", "setqz", "cfgdacs", "setdacs",
"cfgdac0", "cfgdac1", "cfgdac2", "cfgdac3", "setdac0", "setdac1",
"setdac2", "seddac3", "setctra", "setwava", "setfrqa", "setphsa",
"addphsa", "subphsa", "setvid", "setvidy", "setctrb", "setwavb", "setfrqb",
"setphsb", "addphsb", "subphsb", "setvidi", "setvidq", "setpix", "setpixz",
"setpixu", "setpixv", "setpixa", "setpixr", "setpixg", "setpixb",
"setpora", "setporb", "setporc", "setpord", "push"};
char *opcodes_set3[40] = {
"jmp", "jmpd", "call", "calld", "calla", "callad", "callb", "callbd",
"callx", "callxd", "cally", "callyd", "reta", "retad", "retb", "retbd",
"retx", "retxd", "rety", "retyd", "ret", "retd", "polctra", "polctrb",
"polvid", "capctra", "capctrb", "capctrs", "setpixw", "clracca", "clraccb",
"clraccs", "chkptrx", "chkptry", "syntra", "synctrb", "dcachex", "icachex",
"icachep", "icachen"};
int zci_set3[40] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0,
0, 0, 0, 0, 6, 6, 0, 0, 0, 0, 0, 0};
char *GetOpname2(unsigned int instr, int *pzci)
{
int opcode = instr >> 25;
int zci = (instr >> 22) & 7;
int cond = (instr >> 18) & 15;
int src = instr & 0x1ff;
int dst = (instr >> 9) & 0x1ff;
int zc = zci >> 1;
//printf("opcode = $%2.2x, zci = %d\n", opcode, zci);
if (opcode < 64)
{
*pzci = 7;
return opcodes_lower[opcode];
}
else if(opcode < 126)
{
*pzci = zci_upper[opcode-64][zc];
return opcodes_upper[opcode-64][zc];
}
else if (opcode == 126 && zci == 0)
{
*pzci = 0;
return opcodes_ind[cond];
}
else if (opcode == 126)
{
*pzci = 0;
return opcodes_16[(zci-1)*2 + (dst >> 8)];
}
else if (src <= 48)
{
if (src < 44 || src == 48)
*pzci = 7;
else
*pzci = 5;
return opcodes_set1[src];
}
if (src < 64)
{
*pzci = 0;
return "invalid";
}
if (src < 128)
{
*pzci = 1;
return "repd";
}
if (src < 220)
{
if (src == 136 || src == 137 || src == 144)
*pzci = 7;
else if (src == 130 || src == 131)
*pzci = 3;
else
*pzci = 1;
return opcodes_set2[src-128];
}
if (src < 0xf4)
{
*pzci = 0;
return "invalid";
}
if (src <= 0x11b)
{
*pzci = zci_set3[src-0xf4];
return opcodes_set3[src-0xf4];
}
*pzci = 0;
return "invalid";
}
void StartPasmCog2(PasmVarsT *pasmvars, int32_t par, int32_t addr, int32_t cogid)
{
int32_t i;
// printf("\nStartPasmCog2: %8.8x, %8.8x, %d\n", par, addr, cogid);
par &= 0x3ffff;
addr &= 0x3fffc;
pasmvars->waitflag = 0;
pasmvars->cflag = 0;
pasmvars->zflag = 0;
pasmvars->pc = 0;
pasmvars->cogid = cogid;
pasmvars->state = 5;
pasmvars->ptra = par;
pasmvars->ptrb = addr;
pasmvars->ptrx = 0;
pasmvars->ptry = 0;
pasmvars->inda = 0x1f2;
pasmvars->indatop = 0;
pasmvars->indabot = 0;
pasmvars->indb = 0x1f3;
pasmvars->indbtop = 0;
pasmvars->indbbot = 0;
pasmvars->repcnt = 0;
pasmvars->repbot = 0;
pasmvars->reptop = 0;
pasmvars->repforever = 0;
pasmvars->dcachehubaddr = 0xffffffff;
pasmvars->dcachecogaddr = 0xffffffff;
pasmvars->instruct1 = 0;
pasmvars->instruct2 = 0;
pasmvars->instruct3 = 0;
pasmvars->instruct4 = 0;
pasmvars->pc1 = INVALIDATE_INSTR;
pasmvars->pc2 = INVALIDATE_INSTR;
pasmvars->pc3 = INVALIDATE_INSTR;
pasmvars->pc4 = INVALIDATE_INSTR;
pasmvars->retptr = 0;
pasmvars->acca = 0;
pasmvars->accb = 0;
pasmvars->mulcount = 0;
pasmvars->breakpnt = -1;
pasmvars->augsflag = 0;
pasmvars->augsvalue = 0;
pasmvars->augdflag = 0;
pasmvars->augdvalue = 0;
pasmvars->icachehubaddr[0] = 0xffffffff;
pasmvars->icachehubaddr[1] = 0xffffffff;
pasmvars->icachehubaddr[2] = 0xffffffff;
pasmvars->icachehubaddr[3] = 0xffffffff;
pasmvars->icachenotused[0] = 0;
pasmvars->icachenotused[1] = 0;
pasmvars->icachenotused[2] = 0;
pasmvars->icachenotused[3] = 0;
pasmvars->prefetch = 1;
for (i = 0; i < 0x1f4; i++)
{
pasmvars->mem[i] = LONG(addr);
addr += 4;
}
for (i = 0x1f4; i < 512; i++) pasmvars->mem[i] = 0;
}
void DebugPasmInstruction2(PasmVarsT *pasmvars)
{
int32_t i;
int32_t cflag = pasmvars->cflag;
int32_t zflag = pasmvars->zflag;
int32_t instruct, pc, cond, xflag;
int32_t opcode, zci;
int32_t srcaddr, dstaddr;
char *wzstr = "";
char *wcstr = "";
char opstr[20];
char *istr[3] = {" ", "#", "@"};
char *xstr[8] = {" ", "X", "I", "H", "C", "P", "W", "?"};
int zci_mask;
int32_t sflag, dflag, indirect, opcode_zci;
// Fetch the instruction
pc = pasmvars->pc4;
instruct = pasmvars->instruct4;
cond = (instruct >> 18) & 15;
// Extract parameters from the instruction
opcode = (instruct >> 25) & 127;
srcaddr = instruct & 511;
dstaddr = (instruct >> 9) & 511;
zci = (instruct >> 22) & 7;
opcode_zci = (opcode << 3) | zci;
// Decode the immediate flags for the source and destination fields
sflag = (opcode_zci >= 0x3ea) | (zci & 1);
dflag = (opcode >= 0x68 && opcode <= 0x7a && (zci & 2)) |
(opcode_zci >= 0x302 && opcode_zci <= 0x31f) |
(opcode != 0x7f && opcode_zci >= 0x3eb) |
(opcode == 0x7f && srcaddr >= 0x40 && srcaddr <= 0xdc && (zci & 1)) |
(opcode == 0x7f && srcaddr >= 0x100);
// Determine if indirect registers are used
indirect = (!sflag && (srcaddr & 0x1fe) == 0x1f2) |
(!dflag && (dstaddr & 0x1fe) == 0x1f2) |
(opcode_zci == 0x3f0);
if (indirect) cond = 0xf;
xflag = ((cond >> ((cflag << 1) | zflag)) & 1);
xflag ^= 1;
// Check if the instruction is invalidated in the pipeline
if (pc & INVALIDATE_INSTR)
{
pc &= ~INVALIDATE_INSTR;
xflag = 2;
}
if (pasmvars->waitflag && pasmvars->waitmode == WAIT_CACHE) xflag = 4;
else if (xflag == 4) xflag = 5;
if (pasmvars->waitflag)
{
if (pasmvars->waitmode == WAIT_CACHE)
xflag = 4;
else if (pasmvars->waitmode == WAIT_CNT)
xflag = 6;
else if (pasmvars->waitmode == WAIT_PIN)
xflag = 5;
else if (pasmvars->waitmode == WAIT_HUB)
xflag = 3;
else
xflag = 7;
}
strcpy(opstr, GetOpname2(instruct, &zci_mask));
zci &= zci_mask;
if (zci & 4) wzstr = " wz";
if (zci & 2) wcstr = " wc";
i = strlen(opstr);
while (i < 7) opstr[i++] = ' ';
opstr[i] = 0;
// Check for NOP
if (!instruct)
{
cond = 15;
if (xflag == 1) xflag = 0;
strcpy(opstr, "nop ");
}
// Check for REPS
if ((instruct & 0xffc00000) == 0xfac00000)
{
cond = 15;
if (xflag == 1) xflag = 0;
strcpy(opstr, "reps ");
}
// Check for AUGS or AUGD
if (opcode_zci >= 0x3ec && opcode_zci <= 0x3ef)
{
cond = 15;
if (xflag == 1) xflag = 0;
}
if (pasmvars->printflag - 2 < xflag && xflag != 0)
{
pasmvars->printflag = 0;
return;
}
fprintf(tracefile, "Cog %d: %8.8x ", pasmvars->cogid, loopcount);
fprintf(tracefile, "%4.4x %8.8x %s %s %s %s%3.3x, %s%3.3x%s%s", pc,
instruct, xstr[xflag], condnames[cond], opstr, istr[dflag], dstaddr,
istr[sflag], srcaddr, wzstr, wcstr);
}
/*
+------------------------------------------------------------------------------------------------------------------------------+
| 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. |
+------------------------------------------------------------------------------------------------------------------------------+
*/

742
pasmsim.c Executable file
View File

@ -0,0 +1,742 @@
/*******************************************************************************
' Author: Dave Hein
' Version 0.21
' Copyright (c) 2010, 2011
' See end of file for terms of use.
'******************************************************************************/
#include <stdio.h>
#include "interp.h"
extern char *hubram;
extern int32_t memsize;
extern char lockstate[8];
extern char lockalloc[8];
extern PasmVarsT PasmVars[8];
extern int32_t pasmspin;
extern int32_t cycleaccurate;
extern int32_t loopcount;
extern int32_t proptwo;
extern int32_t pin_val;
extern FILE *tracefile;
void PrintResults(int32_t zcri, int32_t zflag, int32_t cflag, int32_t result)
{
if (zcri & 8) printf(" Z=%d", zflag);
if (zcri & 4) printf(" C=%d", cflag);
if (zcri & 2) printf(" R=%8.8x", result);
}
static int32_t parity(int32_t val)
{
val ^= val >> 16;
val ^= val >> 8;
val ^= val >> 4;
val ^= val >> 2;
val ^= val >> 1;
return val & 1;
}
static int32_t abs(int32_t val)
{
return val < 0 ? -val : val;
}
int32_t CheckWaitFlag(PasmVarsT *pasmvars, int mode)
{
int32_t hubmode = mode & 1;
int32_t debugmode = mode & 2;
int32_t waitflag = pasmvars->waitflag;
if (waitflag)
{
waitflag--;
}
else if (hubmode)
{
if (proptwo)
waitflag = (pasmvars->cogid - loopcount) & 7;
else
waitflag = ((pasmvars->cogid >> 1) - loopcount) & 3;
waitflag++;
}
else
{
if (proptwo)
waitflag = 2;
else
waitflag = 1;
}
if (!debugmode)
{
//if (waitflag)
//pasmvars->pc = (pasmvars->pc - 1) & 511;
pasmvars->waitflag = waitflag;
}
return waitflag;
}
void AdjustPipeForJump(PasmVarsT *pasmvars, int32_t value, int32_t jump)
{
int32_t pc = value & 0x1ff;
pasmvars->instruct1 = pasmvars->mem[pc];
if (jump)
{
pasmvars->pc = (pc + 1) & 511;
pasmvars->pc1 = pc;
}
else
{
pasmvars->pc = pasmvars->pc1;
pasmvars->pc1 = pc | 512;
}
}
int32_t ExecutePasmInstruction(PasmVarsT *pasmvars)
{
int32_t cflag = pasmvars->cflag;
int32_t zflag = pasmvars->zflag;
int32_t instruct, cond, pc;
int32_t opcode, value2, value1, zcri;
int32_t srcaddr, dstaddr;
int32_t result = 0;
// Fetch a new instruction and update the pipeline
if (!pasmvars->waitflag)
{
//printf("Fetch new instruction\n");
pasmvars->instruct2 = pasmvars->instruct1;
pasmvars->instruct1 = pasmvars->mem[pasmvars->pc];
pasmvars->pc2 = pasmvars->pc1;
pasmvars->pc1 = pasmvars->pc;
pasmvars->pc = (pasmvars->pc + 1) & 511;
}
// Get the instruction and pc at the end of the pipeline
instruct = pasmvars->instruct2;
pc = pasmvars->pc2;
cond = (instruct >> 18) & 15;
// Return if not executed
if ((!((cond >> ((cflag << 1) | zflag)) & 1)) || (pc & 0xfffffe00))
{
return 0;
}
// Check for a hub wait
if (cycleaccurate && !(instruct & 0xe0000000))
{
if (CheckWaitFlag(pasmvars, 1)) return 0;
}
// Extract parameters from the instruction
opcode = (instruct >> 26) & 63;
srcaddr = instruct & 511;
dstaddr = (instruct >> 9) & 511;
zcri = (instruct >> 22) & 15;
// Get the two operands
value1 = pasmvars->mem[dstaddr];
if (zcri & 1)
value2 = srcaddr;
else if (srcaddr == 0x1f1)
value2 = GetCnt();
else if (srcaddr == 0x1f2)
value2 = pin_val;
else
value2 = pasmvars->mem[srcaddr];
// Decode the three most significant bits of the opcode
switch(opcode >> 3)
{
// Hub access opcodes
case 0:
switch (opcode & 7)
{
case 0: // wrbyte, rdbyte
case 1: // wrword, rdword
case 2: // wrlong, rdlong
if (zcri & 2) // read
{
if ((opcode & 7) == 0)
result = BYTE(value2);
else if ((opcode & 7) == 1)
result = WORD(value2);
else
result = LONG(value2);
zflag = (result == 0);
}
else // write
{
if ((opcode & 7) == 0)
BYTE(value2) = pasmvars->mem[dstaddr];
else if ((opcode & 7) == 1)
WORD(value2) = pasmvars->mem[dstaddr];
else
LONG(value2) = pasmvars->mem[dstaddr];
}
break;
case 3: // misc hubops
switch (value2 & 7)
{
int32_t par, addr;
case 0: // clkset
result = value1 & 0xff;
if (result & 0x80)
{
RebootProp();
return 0;
}
break;
case 1: // cogid
result = pasmvars->cogid;
//pasmvars->mem[dstaddr] = result;
break;
case 2: // coginit
par = (value1 >> 16) & 0xfffc;
addr = (value1 >> 2) & 0xfffc;
if (value1 & 8) // Start new cog
{
// Look for next available cog
for (result = 0; result < 8; result++)
{
if (!PasmVars[result].state) break;
}
if (result == 8) // Check if none available
{
cflag = 1;
result = 7;
zflag = 0;
break;
}
}
else
{
result = value1 & 7;
}
cflag = 0;
zflag = (result == 0);
if (addr == 0xf004 && !pasmspin)
{
SpinVarsT *spinvars = (SpinVarsT *)&PasmVars[result].mem[0x1e0];
StartCog(spinvars, par, result);
}
else
{
StartPasmCog(&PasmVars[result], par, addr, result);
}
UpdatePins();
// Return without saving if we restarted this cog
if (result == pasmvars->cogid) return result;
break;
case 3: // cogstop
for (result = 0; result < 8; result++)
{
if (!PasmVars[result].state) break;
}
cflag = (result == 8);
result = value1 & 7;
zflag = (result == 0);
PasmVars[result].state = 0;
UpdatePins();
// Return without saving if we stopped this cog
if (result == pasmvars->cogid) return result;
break;
case 4: // locknew
for (result = 0; result < 8; result++)
{
if (!lockalloc[result]) break;
}
if (result == 8)
{
cflag = 1;
result = 7;
}
else
{
cflag = 0;
lockalloc[result] = 1;
}
zflag = (result == 0);
break;
case 5: // lockret
for (result = 0; result < 8; result++)
{
if (!lockalloc[result]) break;
}
cflag = (result == 8);
result = value1 & 7;
zflag = (result == 0);
lockalloc[result] = 0;
break;
case 6: // lockset
result = value1 & 7;
zflag = (result == 0);
cflag = lockstate[result] & 1;
lockstate[result] = -1;
break;
case 7: // lockclr
result = value1 & 7;
zflag = (result == 0);
cflag = lockstate[result] & 1;
lockstate[result] = 0;
break;
}
break;
default: // Not defined
//printf("Undefined op - %8.8x\n", instruct);
break;
}
break;
// Rotate and shift
case 1:
value2 &= 0x1f; // Get five LSB's
switch (opcode & 7)
{
case 0: // ror
result = (((uint32_t)value1) >> value2) | (value1 << (32 - value2));
cflag = value1 & 1;
break;
case 1: // rol
result = (((uint32_t)value1) >> (32 - value2)) | (value1 << value2);
cflag = (value1 >> 31) & 1;
break;
case 2: // shr
result = (((uint32_t)value1) >> value2);
cflag = value1 & 1;
break;
case 3: // shl
result = (value1 << value2);
cflag = (value1 >> 31) & 1;
break;
case 4: // rcr
if (value2)
{
result = (cflag << 31) | (((uint32_t)value1) >> 1);
result >>= (value2 - 1);
}
else
result = value1;
cflag = value1 & 1;
break;
case 5: // rcl
result = cflag ? (1 << value2) - 1 : 0;
result |= (value1 << value2);
cflag = (value1 >> 31) & 1;
break;
case 6: // sar
result = value1 >> value2;
cflag = value1 & 1;
break;
case 7: // rev
cflag = value1 & 1;
value2 = 32 - value2;
result = 0;
while (value2-- > 0)
{
result = (result << 1) | (value1 & 1);
value1 >>= 1;
}
break;
}
zflag = (result == 0);
break;
// Jump, call, return and misc.
case 2:
switch (opcode & 7)
{
case 0: // mins
cflag = (value1 < value2);
zflag = (value2 == 0);
result = cflag ? value2 : value1;
break;
case 1: // maxs
cflag = (value1 < value2);
zflag = (value2 == 0);
result = cflag ? value1 : value2;
break;
case 2: // min
cflag = (((uint32_t)value1) < ((uint32_t)value2));
zflag = (value2 == 0);
result = cflag ? value2 : value1;
break;
case 3: // max
cflag = (((uint32_t)value1) < ((uint32_t)value2));
zflag = (value2 == 0);
result = cflag ? value1 : value2;
break;
case 4: // movs
cflag = ((uint32_t)value1) < ((uint32_t)value2);
result = (value1 & 0xfffffe00) | (value2 &0x1ff);
zflag = (result == 0);
break;
case 5: // movd
cflag = ((uint32_t)value1) < ((uint32_t)value2);
result = (value1 & 0xfffc01ff) | ((value2 &0x1ff) << 9);
zflag = (result == 0);
break;
case 6: // movi
cflag = ((uint32_t)value1) < ((uint32_t)value2);
result = (value1 & 0x007fffff) | ((value2 &0x1ff) << 23);
zflag = (result == 0);
break;
case 7: // ret, jmp, call, jmpret
cflag = ((uint32_t)value1) < ((uint32_t)value2);
result = (value1 & 0xfffffe00) | ((pc + 1) & 0x1ff);
//pasmvars->pc = value2 & 0x1ff;
AdjustPipeForJump(pasmvars, value2, 1);
zflag = (result == 0);
break;
}
break;
// Logical operations
case 3:
switch (opcode & 7)
{
case 0: // test, and
result = value1 & value2;
break;
case 1: // testn, andn
result = value1 & (~value2);
break;
case 2: // or
result = value1 | value2;
break;
case 3: // xor
result = value1 ^ value2;
break;
case 4: // muxc
result = (value1 & (~value2)) | (value2 & (-cflag));
break;
case 5: // muxnc
result = (value1 & (~value2)) | (value2 & (~(-cflag)));
break;
case 6: // muxz
result = (value1 & (~value2)) | (value2 & (-zflag));
break;
case 7: // muxnz
result = (value1 & (~value2)) | (value2 & (~(-zflag)));
break;
}
zflag = (result == 0);
cflag = parity(result);
break;
// Add and subtract
case 4:
switch (opcode & 7)
{
case 0: // add
result = value1 + value2;
cflag = (((value1 & value2) | ((value1 | value2) & (~result))) >> 31) & 1;
break;
case 1: // cmp, sub
result = value1 - value2;
cflag = ((uint32_t)value1) < ((uint32_t)value2);
break;
case 2: // addabs
cflag = (value2 >> 31) & 1;
value2 = abs(value2);
result = value1 + value2;
cflag ^= (((value1 & value2) | ((value1 | value2) & (~result))) >> 31) & 1;
break;
case 3: // subabs
result = abs(value2);
cflag = ((value2 >> 31) & 1) ^
(((uint32_t)value1) < ((uint32_t)result));
result = value1 - result;
break;
case 4: // sumc
result = cflag ? value1 - value2 : value1 + value2;
cflag = (~cflag) << 31;
cflag = (((cflag ^ value1 ^ value2) & (value1 ^ result)) >> 31) & 1;
break;
case 5: // sumnc
result = cflag ? value1 + value2 : value1 - value2;
cflag = cflag << 31;
cflag = (((cflag ^ value1 ^ value2) & (value1 ^ result)) >> 31) & 1;
break;
case 6: // sumz
result = zflag ? value1 - value2 : value1 + value2;
cflag = (~zflag) << 31;
cflag = (((cflag ^ value1 ^ value2) & (value1 ^ result)) >> 31) & 1;
break;
case 7: // sumnz
result = zflag ? value1 + value2 : value1 - value2;
cflag = zflag << 31;
cflag = (((cflag ^ value1 ^ value2) & (value1 ^ result)) >> 31) & 1;
break;
}
zflag = (result == 0);
break;
// Move, absolute and negate
case 5:
switch (opcode & 7)
{
case 0: // mov
result = value2;
cflag = (value2 >> 31) & 1;
break;
case 1: // neg
cflag = value2 < 0;
result = -value2;
break;
case 2: // abs
cflag = (value2 >> 31) & 1;
result = abs(value2);
break;
case 3: // absneg
cflag = (value2 >> 31) & 1;
result = -abs(value2);
break;
case 4: // negc
result = cflag ? -value2 : value2;
cflag = (value2 >> 31) & 1;
break;
case 5: // negnc
result = cflag ? value2 : -value2;
cflag = (value2 >> 31) & 1;
break;
case 6: // negz
result = zflag ? -value2 : value2;
cflag = (value2 >> 31) & 1;
break;
case 7: // negnz
result = zflag ? value2 : -value2;
cflag = (value2 >> 31) & 1;
break;
}
zflag = (result == 0);
break;
// More add and subtract
case 6:
switch (opcode & 7)
{
case 0: // cmps
result = value1 - value2;
cflag = value1 < value2;
zflag = (result == 0);
break;
case 1: // cmpsx
result = value1 - value2 - cflag;
cflag = value1 < (value2 + cflag);
zflag = (result == 0) & zflag;
break;
case 2: // addx
result = value1 + value2 + cflag;
cflag = (((value1 & value2) | ((value1 | value2) & (~result))) >> 31) & 1;
zflag = (result == 0) & zflag;
break;
case 3: // cmpx, subx
result = value1 - value2 - cflag;
if (value2 != 0xffffffff || !cflag)
cflag = ((uint32_t)value1) < ((uint32_t)(value2 + cflag));
zflag = (result == 0) & zflag;
break;
case 4: // adds
result = value1 + value2;
cflag = (((~(value1 ^ value2)) & (value1 ^ result)) >> 31) & 1;
zflag = (result == 0);
break;
case 5: // subs
result = value1 - value2;
zflag = (result == 0);
cflag = (((value1 ^ value2) & (value1 ^ result)) >> 31) & 1;
break;
case 6: // addsx
result = value1 + value2 + cflag;
cflag = (((~(value1 ^ value2)) & (value1 ^ result)) >> 31) & 1;
zflag = (result == 0) & zflag;
break;
case 7: // subsx
result = value1 - value2 - cflag;
cflag = (((value1 ^ value2) & (value1 ^ result)) >> 31) & 1;
zflag = (result == 0) & zflag;
break;
}
break;
// Test and jump and wait ops
case 7:
switch (opcode & 7)
{
case 0: // cmpsub
cflag = (((uint32_t)value1) >= ((uint32_t)value2));
result = cflag ? value1 - value2 : value1;
zflag = (result == 0);
break;
case 1: // djnz
result = value1 - 1;
zflag = (result == 0);
cflag = (result == -1);
AdjustPipeForJump(pasmvars, value2, !zflag);
break;
case 2: // tjnz
result = value1;
zflag = (result == 0);
cflag = 0;
AdjustPipeForJump(pasmvars, value2, !zflag);
break;
case 3: // tjz
result = value1;
zflag = (result == 0);
cflag = 0;
AdjustPipeForJump(pasmvars, value2, zflag);
break;
case 4: // waitpeq - result, zflag and cflag not validated
result = (pin_val & value2) ^ value1;
if (result)
{
//pasmvars->state = 6;
//pasmvars->pc = (pasmvars->pc - 1) & 511;
pasmvars->waitflag = 1;
return 0;
}
else
{
//pasmvars->state = 5;
zflag = (result == 0);
cflag = 0;
}
break;
case 5: // waitpne - result, zflag and cflag not validated
result = (pin_val & value2) ^ value1;
if (!result)
{
//pasmvars->state = 6;
//pasmvars->pc = (pasmvars->pc - 1) & 511;
pasmvars->waitflag = 1;
return 0;
}
else
{
//pasmvars->state = 5;
zflag = (result == 0);
cflag = zflag;
}
break;
case 6: // waitcnt
result = GetCnt() - value1;
if (result < 0 || result >= 4)
{
//pasmvars->state = 6;
//pasmvars->pc = (pasmvars->pc - 1) & 511;
pasmvars->waitflag = 1;
return 0;
}
else
{
//pasmvars->state = 5;
pasmvars->waitflag = 0;
result = value1 + value2;
zflag = (result == 0);
cflag = (((value1 & value2) | ((value1 | value2) & (~result))) >> 31) & 1;
}
break;
case 7: // waitvid
break;
}
break;
}
// Conditionally update flags and write result
if (zcri & 8) pasmvars->zflag = zflag;
if (zcri & 4) pasmvars->cflag = cflag;
if (zcri & 2)
{
//if (dstaddr == 0x1f4) printf("outa = %8.8x\n", result);
pasmvars->mem[dstaddr] = result;
// Check if we need to update the pins
if (dstaddr == 0x1f4 || dstaddr == 0x1f6) UpdatePins();
}
//CheckSerialOut(pasmvars);
if (pasmvars->waitflag)
{
fprintf(tracefile, "XXXXXXXXXX BAD XXXXXXXXXXXXXXX\n");
pasmvars->waitflag--;
}
if (pasmvars->printflag)
PrintResults(zcri, zflag, cflag, result);
return result;
}
/*
+------------------------------------------------------------------------------------------------------------------------------+
| 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. |
+------------------------------------------------------------------------------------------------------------------------------+
*/

3377
pasmsim2.c Executable file

File diff suppressed because it is too large Load Diff

89
pfth103_p2/bufser.fth Executable file
View File

@ -0,0 +1,89 @@
\ Define data space that will be used by the serial cog
create bufserstack 40 allot \ Data stack space
create bufserreturn 40 allot \ Return stack space
create bufserbuffer 32 allot \ Serial buffer
create bufserrdindex 0 , \ Read index
create bufserwrindex 0 , \ Write index
\ This word runs in a separate cog and writes input characters into the buffer
: bufsercog
bufserbuffer
begin
getchar over bufserwrindex @ + c!
bufserwrindex dup @ 1 + 31 and swap !
again ;
\ This word replaces the old KEY word with one that reads from the buffer
: bufkey
bufserrdindex @
begin
dup
bufserwrindex @
-
until
bufserbuffer + c@
bufserrdindex dup @ 1 + 31 and swap !
;
\ This is the cog configuration structure used by the serial cog
create bufserconfig \ Forth cog config structure
' bufsercog >body , \ Get execution token for TOGGLE
bufserstack , \ Initial value of stack ptr
bufserstack , \ Empty value for stack ptr
bufserreturn , \ Initial value of return ptr
bufserreturn , \ Empty value for return ptr
\ This word starts a cog running the BUFSER word
: startbufsercog forth @ bufserconfig cognew ;
\ This word starts the serial cog and sets key to the new one
: bufser startbufsercog ['] bufkey is key ;
\ Buffer the serial input into memory until an ESC is received
: bufferit here 256 + dup
." Buffering serial input to memory" cr
." Enter <ESC> to exit" cr
begin
key dup 27 <>
while
over c! 1+
repeat
drop over -
\ over infile cog!
;
\ Determine the length of the current line
: linelen ( addr count -- addr len )
>r dup ( addr ptr ) ( left )
begin
r@ 0 <=
if over - r> drop exit then
dup c@ dup 10 = swap 13 = or
if over - r> drop exit then
1+ r> 1- >r
again
;
\ Variables to store the buffer address and count
variable evalbufaddr
variable evalbufcount
\ Evaluate a buffer containing multiple lines
: evalbuf ( addr count )
evalbufcount !
evalbufaddr !
begin
evalbufcount @ 0 >
while
evalbufaddr @ evalbufcount @
linelen
dup 1+ dup
evalbufaddr @ + evalbufaddr !
evalbufcount @ swap - evalbufcount !
over over type cr
evaluate
repeat
;
\ Redefine switch to use buffered serial
\ : switch bufser ;

94
pfth103_p2/changes.txt Executable file
View File

@ -0,0 +1,94 @@
Changes in pfth 1.03
1. Added umod and u/ words
2. Fixed the #, udmod and ud/ words to handle numbers with the MSB set.
These changes fix a problem with the u. word when the MSB is set.
3. Fixed the putch PASM routine so that it only writes P30 in OUTA
Changes in pfth 1.02
1. Added ospfth.spin, which runs under Spinix
2. Added support for two simultaneous open files
3. Added bye and reboot words
4. Added sub-directory support
5. Added CD word to change the working directory
6. Modified the s" word to work in the interpretation mode
7. Added a kernel word to make constants and values more efficient
Changes in pfth 1.00
1. Fixed the FOR and NEXT words
2. Fixed a bug in UNLOOP
3. Added create-file, file-write, file-line, file-flush, file-close and
delete-file
4. Added linux.fth that implements simple ls, rm, cp and cat commands
5. Added sdutils.fth that contains some file utilities
6. Added TED -- a tiny text editor
7. Changed SAVE to EESAVE in i2c.fth
Changes in pfth 0.89
1. Changed the dictionary word structure to use 16-bit pointers instead of 32
bits.
2. Changed the execution list in compiled words to use 16-bit execution tokens
instead of 32 bits.
3. Changed the positions of the code pointer and DOES pointer to make the inner
loop more efficient. It now runs about 25% faster.
4. Changed SEE back to printing "_lit" for numbers.
5. Implemented a _loop kernel word to make DO-LOOP faster.
Changes in pfth 0.83
1. Changed SEE in see.fth so that it doesn't print "_lit" for numbers
2. Added bufser.fth that contains a buffered serial driver
3. Added a BUFFERIT word in bufser.fth that reads the serial input into memory
until it encounters an "ESC" character.
4. Added an EVALBUF word in bufser.fth that will evaluate multiple lines in a
memory buffer
5. Updated the readme.txt file with text contributed by Loopy
6. Updated the readme.txt file with a description of the dictionary word format
7. Added a SAVE word to i2c.fth that will write the current hub RAM image to
EEPROM. Note: The small Spin program at the end of memory must have been
preserved for this to boot properly.
8. Changed the CR word so that it emits both a carriage return and a line feed.
9. Added CASE, ENDCASE, OF and ENDOF to init.fth
10. Improved WAITCNT and MS in propwords.fth. Removed INA!
11. Fixed LIST-FILES in sd.fth to skip over deleted files in the directory
12. Changed the execution token so that it points to the code pointer instead
of the beginning of the word in the dictionary
13. Made KEY a deferred word so that it can be re-assigned to the serial input
after reading the FILEs in memory

608
pfth103_p2/chess.fth Executable file
View File

@ -0,0 +1,608 @@
\ This program was written by Lennart Benschop and converted to ANS Forth by
\ by Jeff Fox. It was further modified by Dave Hein to run under pfth. The
\ orignal source is available at http://www.ultatechnology.com/chess.html.
HEX
: scroll cr ;
: cls page ;
: key? 1 ;
: off false swap ! ;
: >defer 2 + w@ 4 - ;
3 constant maxlevel
create bp0
maxlevel 1 + c0 * allot
variable bpv
: bp bpv @ ;
: b@ bpv @ + c@ ;
: b! bpv @ + c! ;
: boardvar create ,
does> c@ bpv @ + ;
0c boardvar start
0d boardvar castlew
0e boardvar castleb
0f boardvar ep
1c boardvar starting
1d boardvar piece
1e boardvar best
1f boardvar farther?
2c boardvar wlcastle?
2d boardvar blcastle?
2e boardvar check
2f boardvar pawnmove
3c boardvar kingw
3d boardvar kingb
3e boardvar inpassing
3f boardvar advance
4c boardvar valuew
5c boardvar alfa
6c boardvar beta
7c boardvar (eval)
8c boardvar highest
9c boardvar cutoff
ac boardvar valueb
bc boardvar played
variable level
variable lastcnt
: +level
bp dup c0 + c0 cmove
c0 bpv +! 1 level +! ;
: -level
-c0 bpv +! -1 level +! ;
create symbols
CHAR . , CHAR p , CHAR k , CHAR b ,
CHAR r , CHAR q , CHAR K ,
create values
0 , 40 , c0 , c0 , 140 , 240 , 3000 ,
: .board
cls
0 0 at-xy 20 spaces
cr 2 spaces
[CHAR] H 1 + [CHAR] A do i emit 2 spaces loop
bp 20 + 8 0 do
cr 20 spaces
cr [CHAR] 8 i - emit
0a 2 do space
dup i + c@ dup
07 and cells symbols + 1 type
dup 80 and if ." W" drop else
if ." B" else ." ." then
then
loop
10 +
loop cr drop ;
: .pos
10 /mod
swap 2 - [CHAR] A + emit
[CHAR] 8 2 + swap - emit ;
\ constants that indicate the directions on the board
-11 constant nw -0f constant no
0f constant zw 11 constant zo
-10 constant n 10 constant z
-1 constant w 1 constant o
create spring
-12 , -21 , -1f , -0e , 12 , 21 , 1f , 0e ,
defer tmove
defer attacktest
: mine?
b@ dup 0= 0= swap 80 and start c@ = and ;
variable movits
: moveit
starting c@ best c! 1 farther? c!
begin
best c@ over + dup best c!
dup mine? over b@ 87 = or 0=
farther? c@ and while
tmove
b@ 0= farther? c!
repeat
drop drop
1 movits +! ;
: Bishop
no nw zo zw moveit moveit moveit moveit ;
: Rook
n o z w moveit moveit moveit moveit ;
: Queen
n o z w no nw zo zw 8 0 do moveit loop ;
: Knight
8 0 do
i cells spring + @
starting c@ + dup best c!
dup mine? swap b@ 87 = or 0=
if tmove then
loop ;
: ?castle
start c@ 80 = if castlew else castleb then c@ check c@ 0= and ;
: ?lcastle
start c@ 80 = if wlcastle? else blcastle? then c@ check c@ 0= and ;
: king
n o z w no nw zo zw 8 0 do
starting c@ + dup best c!
dup mine? swap b@ 87 = or 0=
if tmove then
loop
?castle if 28 start c@ if 70 + then
dup bp + 1- @ 0=
if
dup 1- attacktest 0=
if
best c! tmove
else drop then
else drop then
then
?lcastle if 24 start c@ if 70 + then
dup bp + @ over bp + 1- @ or 0=
if
dup 1 + attacktest 0=
if
best c! tmove
else drop then
else drop then
then ;
: Pawnrow
start c@ if negate then ;
: Pawnz
dup best c!
f0 and start c@ if 20 else 90 then =
if 6 2 do i advance c! tmove loop
else tmove then
0 pawnmove c! 0 inpassing c! 0 advance c! ;
: Pawn
starting c@ z Pawnrow +
dup b@ if
drop
else
dup Pawnz
z Pawnrow + dup b@ if
drop
else
starting c@ f0 and
start c@ if 80 else 30 then =
if starting c@ 0f and pawnmove c!
Pawnz
else drop
then
then
then
zw zo 2 0 do
Pawnrow starting c@ +
dup f0 and start c@ if 40 else 70 then =
over 0f and ep c@ = and
if 1 inpassing c!
dup Pawnz
then
dup b@ dup 0= 2 pick mine? or
swap 87 = or
if drop else Pawnz then
loop ;
create pieces
' noop , ' Pawn , ' Knight , ' Bishop , ' Rook , ' Queen , ' king ,
: piecemove
\ using above jump table for each type of piece - jump table uses , (CELLS)
piece c@ cells pieces + @ execute ;
: ?piecemove
starting c@ dup mine? if
b@ 07 and piece c!
0 pawnmove c! 0 inpassing c! 0 advance c!
piecemove
else drop then ;
: allmoves
[char] . emit
start c@ 0= if
22 starting c!
8 0 do
8 0 do
?piecemove starting c@ 1 + starting c!
loop
starting c@ 8 + starting c!
loop
else
92 starting c!
8 0 do
8 0 do
?piecemove starting c@ 1 + starting c!
loop
starting c@ 18 - starting c!
loop
then ;
variable attack
: ?attack
best c@ dup mine? 0=
swap b@ 07 and piece c@ = and
attack @ or attack ! ;
: attacked?
attack off 0 7 1 do
i piece c!
piecemove
attack @ if drop 1 leave then
loop ;
variable starting'
variable best'
variable start'
variable tmove'
: settest
starting c@ starting' c!
best c@ best' c!
start c@ start' c!
['] tmove >defer tmove' !
['] ?attack is tmove ;
: po@
starting' c@ starting c!
best' c@ best c!
start' c@ start c!
tmove' @ is tmove ;
: changecolor
start c@ 80 xor start c! ;
variable endf
variable playlevel
variable #legal
variable selected
variable compcolor
variable move#
create bp1 c0 allot
: endgame?
start c@ if valueb else valuew then @ c1 < ;
: evalboard
valueb @ valuew @ - start c@ if negate then
55 mine? 1 and + 56 mine? 1 and + 65 mine? 1 and + 66 mine? 1 and +
changecolor 55 mine? + 56 mine? + 65 mine? + 66 mine? + changecolor
endgame? if
start c@ if kingb else kingw then c@
dup f0 and dup 20 = swap 90 = or 7 and
swap 0f and dup 2 = swap 9 = or 7 and + +
then ;
: ?check
settest
start c@ if kingw else kingb then c@
starting c! attacked? check c!
po@ ;
: (attacktest)
['] tmove >defer ['] ?attack <> if
settest
starting c!
attacked?
po@
else drop true
then ;
' (attacktest) is attacktest
variable seed
: rnd
seed @ 743 * 43 + dup seed ! ;
\ 1 ;
: domove
best c@ b@ 7 and cells values + @ negate start c@
if valueb else valuew then +!
starting c@ b@ best c@ b!
0 starting c@ b!
advance c@ if
advance c@ dup cells values + @ 40 - start c@
if valueb else valueb then +!
start c@ or best c@ b!
then
piece c@ 4 = if
starting c@ 0f and 2 =
if
0 start c@ if wlcastle? else blcastle? then c!
then
starting c@ 0f and 9 =
if
0 start c@ if castlew else castleb then c!
then
then
piece c@ 6 = if
0 0 start c@ if castlew else castleb then dup >r c!
r> 1f + c!
best c@ starting c@ - 2 =
if
4 start c@ or best c@ 1- b!
0 best c@ 1 + b!
then
best c@ starting c@ - -2 =
if
4 start c@ or best c@ 1 + b!
0 best c@ 2 - b!
then
best c@ start c@ if kingw else kingb then c!
then
inpassing c@ if
0 best c@ n Pawnrow + b!
-40 start c@ if valueb else valuew then +!
then
pawnmove c@ ep c! ;
: deeper
cutoff @
invert if
+level
domove
?check check c@ if -level exit then
-1 played c0 - !
level @ playlevel @ = if
evalboard
(eval) c0 - !
else
alfa @ highest !
alfa @ negate beta @ negate alfa ! beta !
changecolor
0 played !
allmoves
played @ 0= if
?check check c@ if -2000 highest ! else 0 highest ! then
then
highest @ negate
(eval) c0 - !
then
-level
(eval) @ highest @ max
highest !
highest @ beta @ > if TRUE cutoff ! then
then ;
: analyse
+level
domove
?check check c@ 0= if
1 #legal +!
changecolor
['] tmove >defer
['] deeper is tmove
0 played !
allmoves
is tmove
played @ 0= if
?check check c@ if -2000 highest ! else 0 highest ! then
then
highest @ beta c0 - @ = if
rnd 2000 > if #legal @ selected ! then
then
highest @ beta c0 - @ < if
#legal @ selected !
highest @ beta c0 - !
then
then
-level ;
: select
+level
domove
?check check c@ 0= if
1 #legal +!
#legal @ selected @ = if
bp bp1 c0 cmove
starting c@ .pos ." -" best c@ .pos space
then
then
-level ;
: against
+level
domove
?check check c@ 0= if
1 #legal +!
then
-level ;
: compmove
.board
['] analyse is tmove
0 #legal !
-4000 alfa ! 4000 beta !
\ 0 18 at-xy cr
scroll
\ 28 spaces
start c@ if 1 move# +! move# @ 3 .r space else 4 spaces then
?check check c@ if ." Check" then
1 selected !
allmoves
#legal @ 0= if
check c@ if
." mate"
else
." Pat"
then
TRUE endf !
else
['] select is tmove
0 #legal !
allmoves
bp1 bp0 c0 cmove
changecolor
['] against is tmove
0 #legal !
allmoves
?check check c@ if ." Check" then
#legal @ 0= if
check c@ if
." mate"
else
." Pat"
then
TRUE endf !
then
then
.board ;
variable startingm
variable bestm
variable personmove
: legal
startingm @ starting c@ =
bestm @ best c@ = and
personmove @ advance c@ = and
if
+level
domove
?check check c@ 0= if
1 #legal !
bp bp1 c0 cmove
then
-level
then ;
create inputbuf 6 allot
: inpos
dup inputbuf + c@ [CHAR] A -
dup 8 u<
rot inputbuf + 1 + c@ [CHAR] 1 -
dup 8 u< rot and
swap 7 swap - 10 * rot + 22 + ;
: promote
0 6 2 do over symbols i cells + c@ = if drop i then loop ;
: person
begin
.board
scroll
\ 28 spaces
start c@ if 1 move# +! move# @ 3 .r else 3 spaces then
inputbuf 5 expect cr
\ [char] X emit inputbuf 5 type [char] X emit
inputbuf c@ [CHAR] Q = if quit then
0 inpos startingm !
2 inputbuf + c@ [CHAR] - = and
3 inpos bestm !
and
bestm @ f0 and start c@ if 20 else 90 then =
startingm b@ 07 and 1 = and
if
." What piece? " 0 0 begin drop drop key promote dup until
personmove ! emit
else
0 personmove !
then
if
['] legal is tmove
0 #legal !
startingm c@ starting c! ?piecemove
#legal @
else
0
then
dup 0= start c@ and if -1 move# +! then
until
bp1 bp0 c0 cmove
changecolor
cr
.board ;
: setmove
compcolor @ 0< start c@ 80 = = if compmove else person then ;
variable manVsMachine
: askcolor
manVSmachine @
if ." Do you want White Y/N"
key dup [CHAR] Y = swap [CHAR] y = or
if 1 else -1 then compcolor !
then ;
: asklevel
cr ." Level? 2-"
maxlevel . key [CHAR] 0 - 2 max maxlevel min playlevel !
cls ;
: init
0 level ! bp0 bpv !
bp c0 87 fill
4 2 3 6 5 3 2 4 8 0 do bp 22 + i + c! loop
bp 32 + 8 01 fill
bp 42 + 8 00 fill bp 52 + 8 00 fill
bp 62 + 8 00 fill bp 72 + 8 00 fill
bp 82 + 8 81 fill
84 82 83 86 85 83 82 84 8 0 do bp 92 + i + c! loop
1 castlew c! 1 castleb c! 0 ep c! 1 wlcastle? c! 1 blcastle? c! 0 advance c!
80 start c! 96 kingw c! 26 kingb c!
askcolor cr asklevel
0 move# ! 0 endf !
0 check c! 9c0 valuew ! 9c0 valueb ! ;
: play
begin setmove endf @ until ;
: games
begin init play again ;
: autoplay
begin setmove compcolor @ negate compcolor ! key? if quit then endf @ until ;
: auto
init -1 compcolor ! autoplay ;
: chess
cls
." ANS Forth Chess" cr
." Do you want to play against the computer? Y/N" cr
begin rnd drop key? until key
dup [CHAR] Y = swap [CHAR] y = or dup manVsMachine !
if games else auto then ;
decimal

145
pfth103_p2/chkcore.fth Executable file
View File

@ -0,0 +1,145 @@
( This program checks for all 133 ANS Forth core words )
: checkword 1 + ' 0 =
if swap 1 + swap source type ." failed" 13 emit 10 emit then ;
: checkdone swap dup
if swap dup rot rot swap - . ." out of "
else drop ." All " then
. ." ANS Forth core words implemented" 13 emit 10 emit ;
0 0
checkword !
checkword #
checkword #>
checkword #S
checkword '
checkword (
checkword *
checkword */
checkword */MOD
checkword +
checkword +!
checkword +LOOP
checkword ,
checkword -
checkword .
checkword ."
checkword /
checkword /MOD
checkword 0<
checkword 0=
checkword 1+
checkword 1-
checkword 2!
checkword 2*
checkword 2/
checkword 2@
checkword 2DROP
checkword 2DUP
checkword 2OVER
checkword 2SWAP
checkword :
checkword ;
checkword <
checkword <#
checkword =
checkword >
checkword >BODY
checkword >IN
checkword >NUMBER
checkword >R
checkword ?DUP
checkword @
checkword ABORT
checkword ABORT"
checkword ABS
checkword ACCEPT
checkword ALIGN
checkword ALIGNED
checkword ALLOT
checkword AND
checkword BASE
checkword BEGIN
checkword BL
checkword C!
checkword C,
checkword C@
checkword CELL+
checkword CELLS
checkword CHAR
checkword CHAR+
checkword CHARS
checkword CONSTANT
checkword COUNT
checkword CR
checkword CREATE
checkword DECIMAL
checkword DEPTH
checkword DO
checkword DOES>
checkword DROP
checkword DUP
checkword ELSE
checkword EMIT
checkword ENVIRONMENT?
checkword EVALUATE
checkword EXECUTE
checkword EXIT
checkword FILL
checkword FIND
checkword FM/MOD
checkword HERE
checkword HOLD
checkword I
checkword IF
checkword IMMEDIATE
checkword INVERT
checkword J
checkword KEY
checkword LEAVE
checkword LITERAL
checkword LOOP
checkword LSHIFT
checkword M*
checkword MAX
checkword MIN
checkword MOD
checkword MOVE
checkword NEGATE
checkword OR
checkword OVER
checkword POSTPONE
checkword QUIT
checkword R>
checkword R@
checkword RECURSE
checkword REPEAT
checkword ROT
checkword RSHIFT
checkword S"
checkword S>D
checkword SIGN
checkword SM/REM
checkword SOURCE
checkword SPACE
checkword SPACES
checkword STATE
checkword SWAP
checkword THEN
checkword TYPE
checkword U.
checkword U<
checkword UM*
checkword UM/MOD
checkword UNLOOP
checkword UNTIL
checkword VARIABLE
checkword WHILE
checkword WORD
checkword XOR
checkword [
checkword [']
checkword [CHAR]
checkword ]
checkdone

57
pfth103_p2/chkcorex.fth Executable file
View File

@ -0,0 +1,57 @@
( This program checks for all 45 ANS Forth core ext words )
: checkword 1 + ' 0 =
if swap 1 + swap source type ." failed" 13 emit 10 emit then ;
: checkdone swap dup
if swap dup rot rot swap - . ." out of "
else drop ." All " then
. ." ANS Forth core ext words implemented" 13 emit 10 emit ;
0 0
checkword #tib
checkword .(
checkword .r
checkword 0<>
checkword 0>
checkword 2>r
checkword 2r>
checkword 2r@
checkword :noname
checkword <>
checkword ?do
checkword again
checkword c"
checkword case
checkword compile,
checkword convert
checkword endcase
checkword endof
checkword erase
checkword expect
checkword false
checkword hex
checkword marker
checkword nip
checkword of
checkword pad
checkword parse
checkword pick
checkword query
checkword refill
checkword restore-input
checkword roll
checkword save-input
checkword source-id
checkword span
checkword tib
checkword to
checkword true
checkword tuck
checkword u.r
checkword u>
checkword value
checkword within
checkword [compile]
checkword \
checkdone

29
pfth103_p2/comus.fth Executable file
View File

@ -0,0 +1,29 @@
( Useful non-standard words )
: @+ dup cell+ swap @ ;
: !+ over ! cell+ ;
: c@+ dup char+ swap c@ ;
: c!+ over c! char+ ;
: between 1+ within ;
: bounds over + swap ;
: buffer: create allot ;
: cell 4 ;
: cell- cell - ;
: not 0= ;
: parse-word bl word count ;
: perform @ execute ;
: >= < 0= ;
: <= > 0= ;
: -rot rot rot ;
: 2- 2 - ;
: 2+ 2 + ;
: 3dup dup 2over rot ;
: 4dup 2over 2over ;
: noop ;
: off false swap ! ;
: on true swap ! ;
: for ['] >r compile, ['] _lit compile, 0 compile, ['] >r compile, here ;
immediate
: next ['] _lit compile, 1 compile, ['] _loop compile, ['] _jz compile,
compile, ['] r> compile, ['] r> compile, ['] 2drop compile, ; immediate
: zstrlen dup begin dup c@ while 1+ repeat swap - ;
: zcount dup zstrlen ;

88
pfth103_p2/fds.fth Executable file
View File

@ -0,0 +1,88 @@
\ ############################################################################
\ # fds.fth - This program implements a full duplex serial port. It is base
\ # on the FullDuplexSerial Spin object.
\ #
\ # Copyright (c) 2012 Dave Hein
\ # MIT Licensed
\ ############################################################################
0 value fds_cog
create fds_vars 68 allot
: fds_var create , does> @ fds_vars + ;
0 fds_var rx_head
4 fds_var rx_tail
8 fds_var tx_head
12 fds_var tx_tail
16 fds_var rx_pin
20 fds_var tx_pin
24 fds_var rxtx_mode
28 fds_var bit_ticks
32 fds_var buffer_ptr
36 fds_var rx_buffer
52 fds_var tx_buffer
hex
create fds_entry
a0bca9f0 , 80fca810 , 08bcaa54 , a0fcb201 , 2cbcb255 , 80fca804 , 08bcaa54 ,
a0fcbe01 , 2cbcbe55 , 80fca804 , 08bcae54 , 80fca804 , 08bcb054 , 80fca804 ,
08bcb454 , a0bcc05a , 80fcc010 , 627cae04 , 617cae02 , 689be85f , 68abec5f ,
a0fcc833 , 5cbcbc64 , 627cae01 , 613cb3f2 , 5c640016 , a0fcb809 , a0bcba58 ,
28fcba01 , 80bcbbf1 , 80bcba58 , 5cbcbc64 , a0bca85d , 84bca9f1 , c17ca800 ,
5c4c001f , 613cb3f2 , 30fcb601 , e4fcb81e , 28fcb617 , 60fcb6ff , 627cae01 ,
6cd4b6ff , 08bcabf0 , 80bcaa5a , 003cb655 , 84bcaa5a , 80fcaa01 , 60fcaa0f ,
083cabf0 , 5c7c0016 , 5cbcc85e , a0bca9f0 , 80fca808 , 08bcaa54 , 80fca804 ,
08bcac54 , 863caa56 , 5c680033 , 80bcac60 , 00bcc256 , 84bcac60 , 80fcac01 ,
60fcac0f , 083cac54 , 68fcc300 , 2cfcc202 , 68fcc201 , a0fcc40b , a0bcc7f1 ,
627cae04 , 617cae02 , 6ce0c201 , 29fcc201 , 70abe85f , 7497ec5f , 80bcc658 ,
5cbcc85e , a0bca863 , 84bca9f1 , c17ca800 , 5c4c004d , e4fcc446 , 5c7c0033 ,
decimal
: fds_start ( rxpin txpin mode baudrate ... )
>r
fds_vars 16 0 fill
rxtx_mode ! tx_pin ! rx_pin !
clkfreq@ r> / bit_ticks !
rx_buffer buffer_ptr !
0 dira!
fds_entry rx_head cognew
1+ dup to fds_cog
;
: fds_stop fds_cog if fds_cog 1- cogstop 0 to fds_cog then ;
: fds_rxcheck rx_tail @ rx_head @ 2dup . . cr =
if
-1
else
rx_tail @ rx_buffer + c@
rx_tail @ 1+ 15 and rx_tail !
then
;
: fds_rx begin fds_rxcheck dup -1 = while drop repeat ;
: fds_tx begin tx_tail @ tx_head @ 1+ 15 and <> until
tx_head @ tx_buffer + c!
tx_head @ 1+ 15 and tx_head !
rxtx_mode @ 8 and if fds_rx then
;
: fdstest
." Type 'q' to quit" cr
31 30 0 115200 fds_start
drop
begin
fds_rx
dup [char] q <>
while
[char] < fds_tx fds_tx [char] > fds_tx
repeat
drop
fds_stop
1 30 lshift dira!
;

217
pfth103_p2/i2c.fth Executable file
View File

@ -0,0 +1,217 @@
\ ############################################################################
\ # i2c.fth - This program reads and writes EEPROMs using the I2C protocol.
\ # This program is based on Mike Green's basic_i2c_driver, which is found in
\ # the Parallax Object Exchange (OBEX).
\ #
\ # The first parameter for all routines is the pin number of the clock. It
\ # is assumed that the data pin number is one greater than the clock pin
\ # number.
\ #
\ # Copyright (c) 2012 Dave Hein
\ # MIT Licensed
\ ############################################################################
: i2c_dira_sda_high dup dira@ or dira! ;
: i2c_outa_sda_high dup outa@ or outa! ;
: i2c_dira_scl_high over dira@ or dira! ;
: i2c_outa_scl_high over outa@ or outa! ;
: i2c_dira_sda_low dup invert dira@ and dira! ;
: i2c_outa_sda_low dup invert outa@ and outa! ;
: i2c_dira_scl_low over invert dira@ and dira! ;
: i2c_outa_scl_low over invert outa@ and outa! ;
\ This routine should be called before calling any of the other ones to ensure
\ that the EEPROM is in a known ready state.
: i2c_init ( scl ... )
1 swap lshift dup 2* \ sda := scl + 1
i2c_outa_scl_high \ outa[scl] := 1
i2c_dira_scl_high \ dira[scl] := 1
i2c_dira_sda_low \ dira[sda] := 0
9 0 do \ repeat 9
i2c_outa_scl_low \ outa[scl] := 0
i2c_outa_scl_high \ outa[scl[ := 1
dup ina@ and if leave then \ if ina[sda] quit
loop
2drop
;
\ This routine sends a start bit
: i2c_start ( scl ... )
1 swap lshift dup 2* \ sda := scl + 1
i2c_outa_scl_high \ outa[scl]~~
i2c_dira_scl_high \ dira[scl]~~
i2c_outa_sda_high \ outa[sda]~~
i2c_dira_sda_high \ dira[sda]~~
i2c_outa_sda_low \ outa[sda]~
i2c_outa_scl_low \ outa[scl]~
2drop
;
\ This routine sends a stop bit
: i2c_stop ( scl ... )
1 swap lshift dup 2* \ sda := scl + 1
i2c_outa_scl_high \ outa[scl]~~
i2c_outa_sda_high \ outa[sda]~~
i2c_dira_scl_low \ dira[scl]~
i2c_dira_sda_low \ dira[sda]~
2drop
;
\ This routine sends one byte and returns the ACK bit
: i2c_write ( scl data ... ackbit )
23 lshift swap \ data <<= 23
1 swap lshift dup 2* \ sda := scl + 1
8 0 do \ repeat 8
rot 2* dup 0<
if
rot rot
i2c_outa_sda_high \ outa[sda] := 1
else
rot rot
i2c_outa_sda_low \ outa[sda] := 0
then
i2c_outa_scl_high \ outa[scl]~~
i2c_outa_scl_low \ dira[scl]~
loop
i2c_dira_sda_low \ dira[sda]~
i2c_outa_scl_high \ outa[scl]~~
dup ina@ and >r \ ackbit := ina[sda]
i2c_outa_scl_low \ outa[scl]~
i2c_outa_sda_low \ outa[sda]~
i2c_dira_sda_high \ dira[sda]~~
2drop drop
r> \ return ackbit
;
\ This routine reads one byte from the EEPROM
: i2c_read ( scl ackbit ... data )
>r \ save ackbit
0 swap \ data := 0
1 swap lshift dup 2* \ sda := scl + 1
i2c_dira_sda_low \ dira[sda]~
8 0 do \ repeat 8
i2c_outa_scl_high \ outa[scl]~~
rot 2* \ data <<= 1
over ina@ and if 1 or then \ if ina[sda] data |= 1
rot rot
i2c_outa_scl_low \ outa[scl]~
loop
r> if
i2c_outa_sda_high \ outa[sda]~~
else
i2c_outa_sda_low \ outa[sda]~
then
i2c_dira_sda_high \ dira[sda]~~
i2c_outa_scl_high \ outa[scl]~~
i2c_outa_scl_low \ outa[scl]~
i2c_outa_sda_low \ outa[sda]~
2drop \ return data
;
\ This routine reads up to one page of data from the EEPROM
: i2c_readpage ( scl devsel addrreg dataptr count ... ackbit )
>r >r \ Move count and dataptr to the return stack
dup 15 rshift 14 and rot or \ Assemble the devsel byte
dup >r rot dup dup >r \ Copy devsel and scl to the return stack
i2c_start \ Send a start bit
swap \ Arrange the scl and devsel on the stack
i2c_write drop \ Send the devsel byte
dup 8 rshift 255 and r@ swap \ Extract the second address byte
i2c_write drop \ Send the second address byte
255 and r@ swap \ Extract the third address byte
i2c_write drop \ Send it
r@ \ Get the scl from the return stack
i2c_start \ Send a start bit
r> r> 1 or over >r \ Get the scl and devsel byte and set the LSB
i2c_write drop \ Send the devsel byte
r> r> r> 1 ?do \ Get scl, dataptr and count and start do loop
over 0 i2c_read over c! 1+ \ Read a byte from the EEPROM and save it
loop
over 1 i2c_read swap c! \ Read the last byte from the EEPROM
i2c_stop \ Send a stop bit
0 \ Return the ack bit
;
variable i2c_var
\ This routine reads a byte from the specified address
: i2c_readbyte ( scl devsel addrreg )
i2c_var 1 i2c_readpage drop i2c_var c@ ;
\ This routine reads a word from the specified address
: i2c_readword ( scl devsel addrreg )
0 i2c_var ! i2c_var 2 i2c_readpage drop i2c_var @ ;
\ This routine reads a long from the specified address
: i2c_readlong ( scl devsel addrreg )
i2c_var 4 i2c_readpage drop i2c_var @ ;
\ This routine writes up to one page of data to the EEPROM
: i2c_writepage ( scl devsel addrreg dataptr count ... ackbit )
>r >r \ ( scl devsel addrreg ) r( count dataptr )
dup 15 rshift 14 and rot or \ ( scl addrreg devsel )
rot dup >r \ ( addrreg devsel scl ) r( count dataptr scl )
i2c_start \ ( addrreg devsel ) r( count dataptr scl )
r@ swap \ ( addrreg slc devsel ) r( count dataptr scl )
i2c_write drop \ ( addrreg ) r( count dataptr scl )
dup 8 rshift 255 and r@ swap
i2c_write drop
255 and r@ swap
i2c_write drop
r> r> r> 0 ?do
2dup c@ i2c_write drop 1+
loop
drop
i2c_stop
0
;
\ This routine writes a byte to the specified address
: i2c_writebyte ( scl devsel addrreg data )
i2c_var ! i2c_var 1 i2c_writepage drop ;
\ This routine writes a word to the specified address
: i2c_writeword ( scl devsel addrreg data )
i2c_var ! i2c_var 2 i2c_writepage drop ;
\ This routine writes a long to the specified address
: i2c_writelong ( scl devsel addrreg data )
i2c_var ! i2c_var 4 i2c_writepage drop ;
\ This routine returns a zero if the EEPROM is ready after a write
\ Otherwise it returns a non-zero value
: i2c_writewait ( scl devsel addrreg )
15 rshift 14 and or
over i2c_start
over >r i2c_write
r> i2c_stop
;
\ This word will be run at startup
: startup
1 30 lshift dup outa! dira!
pfthversion type cr
;
\ Set up the cog config struct
: setupconfig
496 cog@ \ Get config struct address from PAR
dup 16 + @ \ Get the address of the return stack
4 + over 12 + ! \ Add four and set initial address of return stack
['] interpret >body \ Get the address of the Forth interpreter
over 16 + @ ! \ Write it to the return stack
['] startup >body \ Get the address of the startup word
swap ! \ Write it to the intial value of the program counter
;
\ Save the hub RAM to EEPROM
: eesave
setupconfig
28 i2c_init
512 0
do
28 160 i 64 * dup 64 i2c_writepage drop
begin 28 160 0 i2c_writewait 0= until
i 7 and 7 = if [char] . emit then
loop
;

400
pfth103_p2/init.fth Executable file
View File

@ -0,0 +1,400 @@
: link>flags 2 + ;
: immediate 81 last @ link>flags c! ;
: \ 100 word drop ; immediate
\ The above lines implement the words to allow for "\" comments
\ All numbers are in hex at this point.
\ DEFINE CELL SIZE
: cellsize 4 ;
: cellmask 3 ;
: compsize 2 ;
: compmask 1 ;
\ BASIC STACK WORDS
: rot 2 roll ;
: over 1 pick ;
: 2dup over over ;
: 2drop drop drop ;
: 2swap 3 roll 3 roll ;
: 2over 3 pick 3 pick ;
\ WORD HEADER ACCESSORS
: >does 2 + ;
: >body 4 + ;
: name>xt dup c@ + 4 + 0 4 - and ;
: link>name 3 + ;
: link>xt link>name name>xt ;
: link>does link>xt 2 + ;
: link>body link>xt 4 + ;
\ DEFINE BASIC WORD BUILDERS
: source tib #tib @ ;
\ : compile, , ;
: ' 20 word find 0 = 0 = and ;
: _does r> dup >r 2 + last @ link>does w! ;
: _setjmp 0a last @ link>flags c! ;
: literal 0 compile, compile, ; immediate
last @ link>body dup @ swap 2 + w! \ Patch in address of _lit
: postpone ' compile, ; immediate
: ['] ' postpone literal ; immediate
: [compile] ' postpone literal ['] compile, compile, ; immediate
: does> [compile] _does [compile] exit ; immediate
\ CONDITIONAL EXECUTION AND LOOPING
: if ['] _jz compile, here 2 allot ; immediate
: else ['] _jmp compile, here 2 + swap w! here 2 allot ; immediate
: then here swap w! ; immediate
: begin here ; immediate
: until ['] _jz compile, compile, ; immediate
: again ['] _jmp compile, compile, ; immediate
: while ['] _jz compile, here 2 allot ; immediate
: repeat ['] _jmp compile, here 2 + swap w! compile, ; immediate
: do ['] _lit compile, here 2 allot ['] drop compile,
['] swap compile, ['] >r compile, ['] >r compile, here ; immediate
: ?do ['] 2dup compile, ['] > compile, ['] _jz compile, here 2 allot
['] swap compile, ['] >r compile, ['] >r compile, here ; immediate
\ : _loop r> swap r> + r> dup >r swap dup >r > 0 = swap >r ;
: loop ['] _lit compile, 1 compile, ['] _loop compile, ['] _jz compile, compile, ['] r> compile,
['] r> compile, here swap w! ['] 2drop compile, ; immediate
: +loop ['] _loop compile, ['] _jz compile, compile, ['] r> compile,
['] r> compile, here swap w! ['] 2drop compile, ; immediate
: leave r> r> drop r> dup >r >r >r ;
: i r> r> dup >r swap >r ;
: j r> r> r> r> dup >r swap >r swap >r swap >r ;
\ DEFINE >FLAGS AND >LINK
: >flags begin 1 - dup c@ 80 and until ;
: >link >flags 2 - ;
\ DEFINE DEFER AND IS
\ Change code pointer from varfunc to deferfunc
: defer create last @ link>xt dup w@ 3 + swap w! ;
: is state @
if [compile] >body ' >does postpone literal [compile] w!
else >body ' >does w!
then ; immediate
\ REDEFINE REFILL AS A DEFERRED WORD
' refill
defer refill
is refill
\ DEFINE "(" COMMENT WORD NOW THAT WE CAN LOOP
: ( begin
#tib @ >in @
?do tib i + c@ 29 = if i 1 + >in ! r> r> drop drop exit then loop
refill 0 =
until ; immediate
( PAD AND PRINT SUPPORT )
create pad 100 allot
create printptr 4 allot
: _d2a dup 0a < if 30 else 57 then + ;
: _a2d dup 30 <
if
drop 0 1 -
else
dup 39 >
if
dup 41 <
if
drop 0 1 -
else
dup 5a >
if
dup 61 <
if
drop 0 1 -
else
dup 7a >
if
drop 0 1 -
else
57 -
then
then
else
37 -
then
then
else
30 -
then
then
dup base @ < 0 =
if
drop 0 1 -
then
;
: c!-- dup >r c! r> 1 - ;
: cprint printptr @ c! printptr @ 1 - printptr ! ;
( DOUBLE WORDS )
: s>d 0 pick 0 < ;
: m* * s>d ;
: um* * 0 ;
: d+ drop 1 roll drop + s>d ;
: d- drop 1 roll drop - s>d ;
: d* drop 1 roll drop * s>d ;
: d/ drop 1 roll drop / s>d ;
: dmod drop 1 roll drop mod s>d ;
: _u/ over over swap 1 rshift swap / dup + dup >r over * rot swap - swap < 1 + r> + ;
: u/ over 0 < if _u/ else / then ;
: ud/ drop 1 roll drop u/ 0 ;
: _umod swap dup 1 rshift 2 pick mod dup + swap 1 and + swap mod ;
: umod over 0 < if _umod else mod then ;
: udmod drop 1 roll drop umod 0 ;
( CORE WORDS )
: +! dup @ rot + swap ! ;
: /mod over over >r >r mod r> r> / ;
: [ state 0 ! ;
: ] state 1 ! ;
: r@ r> r> dup >r swap >r ;
: sm/rem >r 2dup r@ s>d d/ drop r> swap >r s>d dmod drop r> ;
: um/mod >r 2dup r@ s>d ud/ drop r> swap >r s>d udmod drop r> ;
: fm/mod over over xor 1 31 lshift and if sm/rem else sm/rem then ; ( TODO )
: */mod >r m* r> sm/rem ;
: */ */mod swap drop ;
: <# pad ff + printptr ! ;
: hold cprint ;
: # drop dup base @ umod _d2a cprint base @ u/ 0 ;
: #s begin # over over or 0 = until ;
: #> drop drop printptr @ 1 + dup pad 100 + swap - ;
: sign 0 < if 2d hold then ;
: abs dup 0 < if 0 swap - then ;
: type 0 ?do dup c@ emit 1 + loop drop ;
: ._ dup abs 0 <# #s rot sign #> type ;
: . ._ 20 emit ;
: >number dup 0 ?do >r dup c@ _a2d dup 0 < if drop r> leave else swap >r >r
base @ 0 d* r> 0 d+ r> 1 + r> 1 - then loop ;
: 0= 0 = ;
: 0< 0 < ;
: 1+ 1 + ;
: 1- 1 - ;
: 2! swap over ! cellsize + ! ;
: 2* dup + ;
: 2/ dup 80000000 and swap 1 rshift or ;
: 2@ dup cellsize + @ swap @ ;
: ?dup dup if dup then ;
: aligned cellmask + 0 cellsize - and ;
: align here aligned here - allot ;
: bl 20 ;
: c, here c! 1 allot ;
: cell+ cellsize + ;
: cells cellsize * ;
: char+ 1 + ;
: chars ;
\ : count dup char+ swap c@ ;
: char 20 word count 0= if drop 0 else c@ then ;
: [char] char postpone literal ; immediate
\ : constant create here ! cellsize allot does> @ ;
: constant create , last @ link>xt dup w@ 3 - swap w! ;
: cr 0a emit 0d emit ;
: decimal 0a base ! ;
: environment? drop drop 0 ;
: fill swap >r swap r> 0 ?do 2dup c! 1 + loop 2drop ;
: hex 10 base ! ;
: invert 0 1 - xor ;
: max 2dup < if swap then drop ;
: min 2dup > if swap then drop ;
\ : cmove >r swap r> 0 ?do 2dup c@ swap c! 1+ swap 1+ swap loop 2drop ;
: cmove> >r swap r> dup >r 1- dup >r + swap r> + swap r> ?do 2dup c@ swap c!
1- swap 1- swap loop 2drop ;
: move r> 2dup > if r> cmove else r> cmove> then ;
: negate 0 swap - ;
: recurse last @ , ; immediate
: _lit" r> dup 1 + swap dup c@ dup rot + compsize + 0 compsize - and >r ;
84 last @ link>flags c! ( Set STRING flag )
: _compile" [char] " word count dup >r dup >r c, here r> cmove r> allot
compsize here - compmask and allot ; immediate
create s"buf 50 allot
: s" state @ if ['] _lit" compile, postpone _compile" else
[char] " word count >r s"buf r@ cmove s"buf r> then ; immediate
: ." postpone s" ['] type compile, ; immediate
: _abort" if type abort else drop drop then ;
\ : abort" postpone s" ['] _abort" compile, ; immediate
: abort" postpone s" ['] _abort" compile, ;
: space 20 emit ;
: spaces 0 ?do space loop ;
: u._ 0 <# #s #> type ;
: u. u._ 20 emit ;
: u< over over xor 1 31 lshift and if swap then < ;
: unloop r> r> r> drop drop >r ;
: variable create cellsize allot ;
( CORE EXT )
: 0<> 0= invert ;
: 0> 0 > ;
: 2>r r> rot >r swap >r >r ;
: 2r> r> r> r> rot >r swap ;
: 2r@ r> r> r> 2dup >r >r swap rot >r ;
: <> = 0= ;
: erase 0 ?do dup 0 swap ! 1 + loop drop ;
variable span
: expect accept span ! ;
: false 0 ;
: marker create last @ , does> @ dup dp ! @ last ! ;
: nip swap drop ;
: parse word count ;
: true 0 1 - ;
: tuck swap over ;
: to ' >body state @ if postpone literal [compile] ! else ! then ; immediate
\ : value create here ! cellsize allot does> @ ;
: value create , last @ link>xt dup w@ 3 - swap w! ;
: within over - >r - r> u< ;
: .r_ >r dup abs 0 <# #s rot sign #> dup r> swap - spaces type ;
: .r .r_ 20 emit ;
: u.r_ >r 0 <# #s #> dup r> swap - spaces type ;
: u.r .r_ 20 emit ;
: u> over over xor 80000000 and if swap then > ;
: unused 8000 here - ;
: case 0 ; immediate
: of ['] over compile, ['] = compile,
['] _jz compile, here 4 allot ['] drop compile, ; immediate
: endof ['] _jmp compile, here 2 + swap w! here 2 allot ; immediate
: endcase ['] drop compile, begin ?dup while here swap w! repeat ; immediate
: c" ['] _lit" compile, postpone _compile" ['] drop compile, ['] 1- compile, ; immediate
: .( [char] ) word count type ; immediate
: :noname align here ['] words @ , [ ;
( DOUBLE )
: d= rot = rot rot = and ;
: d0= or 0 = ;
: 2constant create swap , , does> dup @ swap cellsize + @ ;
( STRING )
: blank 0 ?do dup bl swap c! 1+ loop drop ;
: -trailing dup 0 ?do 2dup + 1- c@ bl = if 1- else leave then loop ;
: /string dup >r - swap r> + swap ;
( TOOLS )
: ? @ . ;
: .s 3c emit depth ._ 3e emit 20 emit depth 0 ?do depth i - 1 - pick . loop ;
: dump 0 ?do i 0f and 0 = if cr dup . then dup c@ 3 .r 1 + loop drop cr ;
: forget 20 word find if >link dup dp ! w@ last ! else abort" ?" then ;
: .name dup link>name count type space ;
: ?newline dup >r link>name c@ dup rot + 1 + dup 4e > if cr else swap then drop r> ;
: words 0 last @ begin dup while ?newline .name w@ repeat 2drop ;
( UTILITY )
: at-xy 2 emit swap emit emit ;
: page 0 emit ;
( VERSION STRING )
: pfthversion s" pfth 1.03" ;
create evalmode 0 ,
0 value source-id
create srcstk0 30 allot
srcstk0 value srcstk
: resetstack depth 0 <
if
begin depth while 0 repeat
else
begin depth while drop repeat
then
;
: getnumber 2dup >r >r swap dup c@ [char] - =
if
swap
dup 1 <
if
2drop 2drop r> r> 1
else
swap 1 + swap 1 -
>number dup
if
2drop 2drop r> r> 1
else
2drop drop negate 0 r> r> 2drop
then
then
else
swap
>number dup
if
2drop 2drop r> r> 1
else
2drop drop 0 r> r> 2drop
then
then
;
: compilenumber
dup ['] _lit compile, compile,
dup ffff 10 lshift and
if
10 rshift
['] _lit compile, compile,
['] _lit compile, 10 compile,
['] lshift compile,
['] or compile,
else
drop
then
;
: _interpret
begin
20 word dup c@
while
find dup
if
state @ =
if
compile,
else
execute
then
else
dup rot count getnumber
if
type ." ?" cr
else
state @
if
compilenumber
then
then
then
repeat
drop
;
: .savesrc ." _savesrc " srcstk0 . srcstk . cr ;
: .loadsrc ." _loadsrc " srcstk0 . srcstk . cr ;
: _savesrc ( .savesrc ) tib srcstk ! #tib @ srcstk 4 + ! >in @ srcstk 8 + ! source-id srcstk 0c + ! srcstk 10 + to srcstk ;
: _loadsrc srcstk 10 - to srcstk ( .loadsrc ) srcstk @ to tib srcstk 4 + @ #tib ! srcstk 8 + @ >in ! srcstk 0c + @ to source-id ;
: evaluate _savesrc 0 1 - to source-id #tib ! to tib 0 >in ! _interpret _loadsrc ;
( INTERPRETER )
: interpret
begin
_interpret
depth 0 <
if
." Stack Underflow" cr
resetstack
else
source-id 0 1 - =
if
_loadsrc
\ 0 to source-id
else
source-id 0=
if ." ok" cr then
refill
then
then
again
;
decimal
interpret

22
pfth103_p2/license.txt Executable file
View File

@ -0,0 +1,22 @@
+--------------------------------------------------------------------
| 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.
+------------------------------------------------------------------

1
pfth103_p2/pfth.TXT Executable file
View File

@ -0,0 +1 @@
Object "pfth.spin" Interface: Program: 0 Longs Variable: 0 Longs

BIN
pfth103_p2/pfth.obj Executable file

Binary file not shown.

1606
pfth103_p2/pfth.spin Executable file

File diff suppressed because it is too large Load Diff

62
pfth103_p2/primes.fth Executable file
View File

@ -0,0 +1,62 @@
\ primes.4th
\
\ Example code for kForth
\ Copyright (c) 1998 Creative Consulting for Research and Education
\
\ Test for a prime number. Return the largest divisor (< n )
\ and a flag indicating whether the number is prime or not.
: ?prime ( n -- m flag | is n a prime number? )
\ if flag is false (0), m is the largest divisor of n
abs
dup 3 > \ is n > 3 ?
if
abs
dup 2 /mod
swap 0=
if \ is n divisible by 2 ?
nip false
else
1- \ check for divisibility starting
begin \ with n/2 - 1 and counting down
2dup mod
over 1 >
and
while
1-
repeat
nip
dup 1 <=
then
else
dup 1 > IF drop 1 true ELSE false THEN
then
;
: test_prime ( n -- | test for prime number and display result )
?prime
if
." is a prime number" drop
else
." is NOT prime. Its largest divisor is " .
then
cr
;
: list_primes ( n -- | list all the prime numbers from 2 to n )
abs
dup 0>
if
1+ 2 do
i ?prime
if
i . cr
then
drop
loop
else
drop
then
;

40
pfth103_p2/propwords.fth Executable file
View File

@ -0,0 +1,40 @@
( PROP WORDS)
hex
( REGISTER ACCESS )
: cnt@ 1f1 cog@ ;
: ina@ 1f2 cog@ ;
: outa@ 1f4 cog@ ;
: outa! 1f4 cog! ;
: dira@ 1f6 cog@ ;
: dira! 1f6 cog! ;
: clkfreq@ 0 @ ;
( BIT SETTING AND CLEARING )
: dirasetbit dira@ or dira! ;
: diraclrbit invert dira@ and dira! ;
: outasetbit outa@ or outa! ;
: outaclrbit invert outa@ and outa! ;
( HUBOPS )
: cogid ( ... cogid ) 0 0cfc0001 cogx1 ;
: locknew ( ... locknum ) 0 0cfc0004 cogx1 ;
: lockret ( locknum ... ) 0cfc0005 cogx1 drop ;
: cogstop ( cognum ... ) 0c7c0003 cogx1 drop ;
: coginit ( codeptr dataptr cognum ... cognum )
>r 0e lshift or 2 lshift r> or 0ffc0002 cogx1 ;
: cognew ( codeptr dataptr ... cognum ) 8 coginit ;
: waitcnt ( count ... count ) f8fc0000 cogx1 ;
: reboot 80 0cfc0000 cogx1 ;
decimal
( ANS UTILITY )
: ms ( msec ... ) cnt@ swap clkfreq@ 1000 / * + waitcnt drop ;
( ANS TOOLS EXT )
: bye reboot ;
( ENABLE SERIAL OUTPUT )
1 30 lshift dup outa! dira!

42
pfth103_p2/rc4.fth Executable file
View File

@ -0,0 +1,42 @@
0 value ii 0 value jj
0 value KeyAddr 0 value KeyLen
create SArray 256 allot \ state array of 256 bytes
: KeyArray KeyLen mod KeyAddr ;
: get_byte + c@ ;
: set_byte + c! ;
: as_byte 255 and ;
: reset_ij 0 TO ii 0 TO jj ;
: i_update 1 + as_byte TO ii ;
: j_update ii SArray get_byte + as_byte TO jj ;
: swap_s_ij
jj SArray get_byte
ii SArray get_byte jj SArray set_byte
ii SArray set_byte
;
: rc4_init ( KeyAddr KeyLen -- )
256 min TO KeyLen TO KeyAddr
256 0 DO i i SArray set_byte LOOP
reset_ij
BEGIN
ii KeyArray get_byte jj + j_update
swap_s_ij
ii 255 < WHILE
ii i_update
REPEAT
reset_ij
;
: rc4_byte
ii i_update jj j_update
swap_s_ij
ii SArray get_byte jj SArray get_byte + as_byte SArray get_byte xor
;
hex
create AKey 61 c, 8A c, 63 c, D2 c, FB c,
\ create AKey 97 c, 8A c, 99 c, D2 c, FB c,
: test cr 0 DO rc4_byte . LOOP cr ;
AKey 5 rc4_init
2C F9 4C EE DC 5 test \ output should be: F1 38 29 C9 DE

49
pfth103_p2/rc4time.fth Executable file
View File

@ -0,0 +1,49 @@
0 value ii 0 value jj
0 value KeyAddr 0 value KeyLen
create SArray 256 allot \ state array of 256 bytes
create Results 100 allot
: KeyArray KeyLen mod KeyAddr ;
: get_byte + c@ ;
: set_byte + c! ;
: as_byte 255 and ;
: reset_ij 0 TO ii 0 TO jj ;
: i_update 1 + as_byte TO ii ;
: j_update ii SArray get_byte + as_byte TO jj ;
: swap_s_ij
jj SArray get_byte
ii SArray get_byte jj SArray set_byte
ii SArray set_byte
;
: rc4_init ( KeyAddr KeyLen -- )
256 min TO KeyLen TO KeyAddr
256 0 DO i i SArray set_byte LOOP
reset_ij
BEGIN
ii KeyArray get_byte jj + j_update
swap_s_ij
ii 255 < WHILE
ii i_update
REPEAT
reset_ij
;
: rc4_byte
ii i_update jj j_update
swap_s_ij
ii SArray get_byte jj SArray get_byte + as_byte SArray get_byte xor
;
\ : cnt@ 0 ;
hex
create AKey 61 c, 8a c, 63 c, d2 c, fb c,
\ create AKey 97 c, 8a c, 99 c, d2 c, fb c,
: test 0 DO rc4_byte Results i + c! LOOP ;
: test1 cr 0 do Results i + c@ . loop cr ;
: time hex cnt@
AKey 5 rc4_init
2c f9 4c ee dc 5 test \ output should be: f1 38 29 c9 de
cnt@ 5 test1 swap - 13880 / decimal . ." msec" cr ;
decimal

244
pfth103_p2/readme.txt Executable file
View File

@ -0,0 +1,244 @@
pfth Version 1.03
November 8, 2013
Dave Hein
(with additions from G. Herzog)
INTRODUCTION
------------
pfth is an ANS Forth interpreter that runs on the Propeller. It is written in
PASM and Forth, and it can be built using the Prop Tool or BST. pfth
implements all 133 of the ANS Forth core words, and 38 of the 45 core ext
words. pfth will run on any Propeller board that supports the standard serial
interface. The default settings of the serial port are 115200 baud, 8 bits, no
parity and 1 stop bit.
After loading and communications is established, use 'words' to verify that the
display is correct. The CR word is defined to emit both a carriage return and
a line feed. If your terminal displays an extra line you can either disable
the linefeed character on your terminal, or re-define CR to only emit a
carriage return.
VERSIONS OF SPIN FILES
----------------------
There are four versions of pfth.
The first version can be used to build stand-alone Forth applications. It is
in pfth.spin. In this version, Forth programs are included using the Spin FILE
directive.
A second version interfaces to an SD card and can execute Forth programs on
the SD card. This version is in sdpfth.spin. The program is set up for the C3
card, but it can be modified to support other cards.
The third version is named ospfth.spin, and runs under the Spinix operating
system. When Spinix starts up pfth it provides information about the SD pins,
the current working directory and a parameter list. The OS version of pfth
uses this information to initialize the SD card driver and change to the
working directory. It includes the file given by the parameter list.
The final version is called chess.spin, and implements a chess program. After
the program is loaded type "chess" to start playing. A move is entered by
typing the source and destination postions separated by a "-". As an example,
the move "D2-D4" will move the white queen's pawn two spaces ahead.
LEXICON
-------
pfth has over 50 kernel words, with most of them from the ANS core word set.
The source code for pfth is contained in pfth.spin, init.fth and other Forth
programs included at the end of pfth.spin.
Two of the non-standard words implemented by pfth are cog@ and cog!. These are
are used to read and write cog memory locations. Their main purpose is to
access the Prop registers, such as CNT, INA and OUTA.
Another non-standard word is cogx1, which is used to execute native Prop
instructions. The TOS contains the Prop instruction, and the next value on the
stack is used for the destination register value. The result of the execution
of the instruction is returned on the stack.
Some other non-standard words are _lit, _gethex, _jz and .x.
_lit is used to encode literal values.
_gethex is used during the boot phase to convert numeric strings to hex values.
_jz implements a jump-on-zero primitive.
.x is used for debug purposes, and it prints values as 8-digit hex numbers.
Some of the kernel words are shown below.
Interpreter Words Math and Logical Words Memory Access
----------------- ---------------------- -------------
evaluate + !
execute - @
find * c!
word / c@
refill mod
create and Console I/O
: or -----------
; xor emit
< key
= accept
Program Termination >
------------------- lshift Primitive Words
abort rshift ---------------
exit _lit
quit Variables _gethex
--------- _jz
Stack Operations #tib .x
---------------- tib
drop >in Propeller Words
pick base ---------------
roll dp cog!
>r last cog@
r> state cogx1
depth
swap
dup
pfth also contains a small number of pre-compiled Forth words written
in Forth. These words are here, allot, ",", _jmp and count. The definition
of these words is as follows.
: here dp @ ;
: allot dp @ + dp ! ;
: , here ! 4 allot ;
: _jmp r> @ >r ;
: count 0 pick 1 + 1 roll c@ ;
AT START UP
-----------
When pfth starts up, it runs a small boot interpreter that compiles
the ANS dictionary contained in init.fth. This file is included in the
PASM binary image using the PASM FILE directive. Other Forth source files
may be included after init.fth to add additional words and to implement a
specific application.
The boot interpreter can only handle 16-bit hex numbers, so pfth is in the hex
mode when first starting up. The boot interpreter has no error handling
capability, and is only used to build the initial dictionary. The boot
interpreter uses a limited vocabulary consisting of the following 20
kernel words.
dp state _lit _gethex : ; c@ @ ! + = pick roll drop
r> >r word find execute refill
The boot interpreter is shown below in a pseudo-Forth language. The
labels (label1), (label2), etc. are actually encoded as PASM labels, but
they are shown symbolically in the code below.
: xboot
(label1)
20 word 0 pick c@ _jz (label2) ( Get word, refill if empty )
find 0 pick _jz (label3) ( Find word, get number if not found )
state @ = _jz (label4) ( Go execute if not compile mode or immediate )
, _jmp (label1) ( Otherwise, compile and loop again )
(label4)
execute _jmp (label1) ( Execute and loop again )
(label3)
drop count _gethex ( Get number )
state @ _jz (label1) ( Loop again if not compile mode )
_lit _lit , , _jmp (label1) ( Otherwise, compile number and loop again )
(label2)
drop refill _jmp (label1) ( Refill and loop again )
;
The boot interpreter compiles init.fth, which then runs the main interpreter.
The main interpreter performs some error handling by checking for undefined
words and stack underflows. It also handles negative numbers and numbers in
any base.
SOURCE PROGRAMS
---------------
There are a number of additional Forth source programs included in this
distribution that can be run by pfth. Open and read these as text files to
learn more details.
comus.fth - provides a several useful non-standard words that are commonly
used.
starting.fth - contains samples of code from the "Starting Forth" tutorial.
rc4time.fth - implements the RC4 code included in the Wikipedia Forth entry.
It also displays the time required to run the RC4 code.
i2c.fth - is a Forth implementation of Mike Green's basic_i2c_driver from
the OBEX.
fds.fth - implementes some of the functions from the FullDuplexSerial
driver. It uses the binary PASM code from FullDuplexSerial.
toggle.fth - will start up a cog running the Forth interpreter. It toggles
P15, but it can easily be modified to toggle another pin.
ted.fth - a simple line-oriented text editor based on the ED text editor.
linux.fth - implements some basic linux commands, such as ls, cat, rm and cp.
STARTING FORTH COGS
-------------------
Forth cogs are started with cognew or coginit by specifying the Forth cog image
as the execution pointer and a 5-long structure as the data pointer. The
5-long structure is defined as follow
First long: Address of the body of a word that will be executed on startup
Second long: Initial value of the stack pointer
Third long: Address of the beginning of the stack
Fourth long: Initial value of the return stack pointer
Fifth long: Address of the beginning the the return stack
CELL SIZE
---------
The cell size for pfth is 32 bits. The words !, @ and "," words access 32-bit
values that are 32-bit aligned. Additional words are provide for smaller unit
access, such as w! and w@ for word access, and c! and c@ for byte access.
The compiled list cell size is 16 bits. The compile, word must be used when
compiling execution tokens into a list rather than just using the "," word.
DICTIONARY ENTRY FORMAT
-----------------------
The format for the pfth dictionary entry is shown below. The beginning of a
word entry and its body are long-aligned. The link pointer contains the
address of the previous word in the dictionary.
The flags byte contains various flag bits that indicate if the word is an
immediate word, a literal number or string, or a jump word. The name length
byte and the name string specify the name of the word. It is followed by
padding bytes that ensure long alignment.
The code pointer contains the cog address of the PASM code that is to be
executed. The execution token for a word points to this field. The does>
pointer contains the hub address of a list of execution tokens that is to be
called.
The body is a variable length field that contains the contents of a variable or
the list of execution tokens for a compiled word. The list for a compiled word
consists of one execution token per word, and is terminated by a zero-valued
word.
Offset Content Size
------ ------- ----
0 Link Pointer word
2 Flags byte
3 Name Length byte
4 Name String Len bytes
4+Len Padding (-Len) & 3 bytes
4+(Len+3)&(-4) Code Pointer word
6+(Len+3)&(-4) DOES> Pointer word
8+(Len+3)&(-4) Body Variable

65
pfth103_p2/see.fth Executable file
View File

@ -0,0 +1,65 @@
: cond.name ( link )
dup link>flags c@ dup 2 and ( link flag literal )
if
8 and
if
.name
then
else
4 and
if
[char] s emit [char] " emit bl emit
else
.name
then
then
;
: seefunc ( xt )
>body ( listptr )
begin
dup w@ ( listptr xt )
while
dup w@ ( listptr xt )
>link .name link>flags c@ dup 2 and ( listptr flags literal )
if
8 and ( listptr flags jump )
if
2 + dup dup w@ swap - 2 - 2 / .
else
2 + dup w@ .
then
else
4 and ( listptr string )
if
2 + dup count type [char] " emit space
dup c@ + 0 2 - and
then
then
compsize + ( listptr+=compsize)
repeat
drop
;
: see
' dup ( xt xt )
if
dup >flags c@ dup 16 and ( xt flags kernel )
if
drop
drop
." Kernel Word"
else
32 and
if
drop
." Variable"
else
seefunc
then
then
else
drop
." ?"
then
;

20
pfth103_p2/serial.fth Executable file
View File

@ -0,0 +1,20 @@
: waitcnt begin dup cnt@ - 0< until ;
: putch 256 or dup + clkfreq@ 9600 /
11 >r
cnt@
begin
r> 1- dup >r
while
rot dup
30 lshift
outa!
1 rshift
swap rot dup rot +
waitcnt
repeat
r> 2drop 2drop
;
: test cnt@ 65 putch cnt@ swap - 80 / . ;

65
pfth103_p2/starting.fth Executable file
View File

@ -0,0 +1,65 @@
: STAR 42 EMIT ;
: MARGIN CR 30 SPACES ;
: BLIP MARGIN STAR ;
: STARS 0 DO STAR LOOP ;
: BAR MARGIN 5 STARS ;
: F BAR BLIP BAR BLIP BLIP CR ;
: MULT CR 11 1 DO DUP I * . LOOP DROP ;
: TABLE CR 11 1 DO I MULT LOOP ;
: TABLE1 CR 11 1 DO 11 1 DO I J * . LOOP CR LOOP ;
: DUB 32767 1 DO I . I +LOOP ;
: GREET ." Hello, I speak Forth " ;
: GIFT ." chocolate" ;
: GIVER ." Mum" ;
: THANKS CR ." Dear " GIVER ." ,"
CR ." Thanks for the " GIFT ." . " ;
: EGGSIZE DUP 18 < IF ." reject " ELSE
DUP 21 < IF ." small " ELSE
DUP 24 < IF ." medium " ELSE
DUP 27 < IF ." large " ELSE
DUP 30 < IF ." extra large " ELSE
." error "
THEN THEN THEN THEN THEN DROP ;
: FALSE 0 ;
: TRUE -1 ;
: TEST IF ." non-" THEN ." zero " ;
: /CHECK ?DUP IF / THEN ;
: UNCOUNT DROP 1 - ;
: max-int -1 1 rshift ;
: min-int max-int negate 1 - ;
: max-uint -1 ;
: OUTPUT-TEST
." YOU SHOULD SEE THE STANDARD GRAPHIC CHARACTERS:" CR
41 BL DO I EMIT LOOP CR
61 41 DO I EMIT LOOP CR
127 61 DO I EMIT LOOP CR
." YOU SHOULD SEE 0-9 SEPARATED BY A SPACE:" CR
9 1+ 0 DO I . LOOP CR
." YOU SHOULD SEE 0-9 (WITH NO SPACES):" CR
57 1+ 48 DO I 0 SPACES EMIT LOOP CR
." YOU SHOULD SEE A-G SEPARATED BY A SPACE:" CR
71 1+ 65 DO I EMIT SPACE LOOP CR
." YOU SHOULD SEE 0-5 SEPARATED BY TWO SPACES:" CR
5 1+ 0 DO I 48 + EMIT 2 SPACES LOOP CR
." YOU SHOULD SEE TWO SEPARATE LINES:" CR
." LINE 1" CR ." LINE 2" CR
." YOU SHOULD SEE THE NUMBER RANGES OF SIGNED AND UNSIGNED NUMBERS:" CR
." SIGNED: " MIN-INT . MAX-INT . CR
." UNSIGNED: " 0 . MAX-UINT U. CR
;
output-test
f
10 mult
table
table1
dub
greet
thanks cr
17 eggsize cr
22 eggsize cr
25 eggsize cr
28 eggsize cr
32 eggsize cr
0 test cr
1 test cr

2
pfth103_p2/time.fth Executable file
View File

@ -0,0 +1,2 @@
: TIME CNT@ 100000 BEGIN 1 - DUP 0 = UNTIL DROP CNT@ SWAP - 8000 / . ;

33
pfth103_p2/toggle.fth Executable file
View File

@ -0,0 +1,33 @@
\ ############################################################################
\ # toggle.fth - This program starts up a Forth cog that toggles P15
\ #
\ # Copyright (c) 2012 Dave Hein
\ # MIT Licensed
\ ############################################################################
create cogstack 80 allot \ Allocate data stack space
create cogreturn 80 allot \ Allocate return stack space
create delaycnt 80000000 , \ This variable controls the blink rate
hex
\ This word toggles bit P15 every "delaycnt" cycles
: toggle
8000 dirasetbit cnt@ \ Set P15 for output and get CNT
begin
delaycnt @ + waitcnt \ Wait "delaycnt" cycles
8000 outasetbit \ Set P15
delaycnt @ + waitcnt \ Wait "delaycnt" cycles
8000 outaclrbit \ Clear P15
again ; \ Repeat forever
decimal
create cogconfig \ Forth cog config structure
' toggle >body , \ Get execution token for TOGGLE
cogstack , \ Initial value of stack ptr
cogstack , \ Empty value for stack ptr
cogreturn , \ Initial value of return ptr
cogreturn , \ Empty value for return ptr
\ This word starts a cog running the TOGGLE word
: starttoggle forth @ cogconfig cognew ;

2756
rom.h Executable file

File diff suppressed because it is too large Load Diff

592
spindebug.c Executable file
View File

@ -0,0 +1,592 @@
/*******************************************************************************
' Author: Dave Hein
' Version 0.21
' Copyright (c) 2010, 2011
' See end of file for terms of use.
'******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef LINUX
#include "conion.h"
#else
#include <conio.h>
#endif
#include <ctype.h>
#include "interp.h"
#include "opcodes.h"
#define OP_NONE 0
#define OP_UNSIGNED_OBJ_OFFSET 1
#define OP_UNSIGNED_VAR_OFFSET 2
#define OP_UNSIGNED_LOC_OFFSET 3
#define OP_DATA 4
#define OP_SIGNED_JMP_OFFSET 5
#define OP_MEMORY_OPCODE_WRITE 6
#define OP_OBJ_CALL_PAIR 7
#define OP_SIGNED_OFFSET 8
#define OP_PACKED_LITERAL 9
#define OP_BYTE_LITERAL 10
#define OP_WORD_LITERAL 11
#define OP_NEAR_LONG_LITERAL 12
#define OP_LONG_LITERAL 13
#define OP_MEMORY_OPCODE 14
#define OP_MEMORY_OPCODE_READ 15
#define OP_COMPACT_VAR_OFFSET 16
#define OP_COMPACT_LOC_OFFSET 17
extern char *hubram;
extern int32_t memsize;
extern int32_t symflag;
extern FILE *tracefile;
void RemoveCRLF(char *str)
{
int32_t len = strlen(str);
if(len == 0) return;
str += len-1;
while (len > 0)
{
if (*str != 10 && *str != 13) break;
*str-- = 0;
len--;
}
}
char *FindOpcode(int32_t pcurr, int32_t *ops_format, int32_t mode)
{
int32_t opcode;
int32_t i;
opcode = BYTE(pcurr);
if (mode)
{
opcode &= 0x7f;
if (opcode >= 0x40)
opcode += 0xe0 - 0x40;
else if (opcode >= 0x20)
opcode &= 0x78;
else if (opcode >= 0x08)
opcode &= 0x7c;
else
opcode &= 0x7e;
}
else
{
if (opcode >= 0x40 && opcode <= 0x7f) opcode &= 0x63;
}
for (i = 0; optable[i].opname; i++)
{
if (opcode != optable[i].opcode) continue;
if (mode == 0 || (optable[i].opform >> 5) >= 2) break;
}
if (!optable[i].opname) return 0;
*ops_format = optable[i].opform;
return optable[i].opname;
}
extern char objname[100][20];
extern int32_t methodnum[100];
extern int32_t methodlev;
char *FindChar(char *str, int32_t val)
{
while (*str && *str != val)
str++;
return str;
}
void ProcessRet(void)
{
if (!symflag) return;
methodlev--;
fprintf(tracefile, "return %s\n\n", objname[methodlev]);
}
static char linebuf[200];
void ProcessCall(int32_t subnum, int32_t mode)
{
int32_t methnum = 0;
FILE *infile;
if (!symflag) return;
infile = fopen(objname[methodlev], "r");
if (mode)
{
methodlev++;
strcpy(objname[methodlev], objname[methodlev-1]);
}
methodnum[methodlev] = subnum;
if (!infile) return;
// Count pubs
while (fgets(linebuf, 200, infile))
{
if (strncmp(linebuf, "PUB", 3) == 0 || strncmp(linebuf, "pub", 3) == 0)
{
methnum++;
if (methnum == subnum)
{
fprintf(tracefile, "call %s:%s\n", objname[methodlev], linebuf);
fclose(infile);
return;
}
}
}
fclose(infile);
infile = fopen(objname[methodlev], "r");
// Count pris
while (fgets(linebuf, 200, infile))
{
if (strncmp(linebuf, "PRI", 3) == 0 || strncmp(linebuf, "pri", 3) == 0)
{
methnum++;
if (methnum == subnum)
{
fprintf(tracefile, "call %s:%s\n", objname[methodlev], linebuf);
fclose(infile);
return;
}
}
}
}
void ProcessObjCall(int32_t objnum, int32_t subnum)
{
int32_t mode = 0;
int32_t methnum = 0;
int32_t commentmode = 0;
int32_t found = 0;
FILE *infile;
if (!symflag) return;
infile = fopen(objname[methodlev], "r");
methodlev++;
strcpy(objname[methodlev], objname[methodlev-1]);
methodnum[methodlev] = subnum;
if (!infile) return;
// Count pubs and pris
while (fgets(linebuf, 200, infile))
{
if (linebuf[0] == '}')
{
commentmode--;
if (commentmode < 0) commentmode = 0;
continue;
}
else if (linebuf[0] == '{')
{
if (*FindChar(linebuf, '}') == 0)
commentmode++;
}
if (commentmode) continue;
if (strncmp(linebuf, "PUB", 3) == 0 || strncmp(linebuf, "pub", 3) == 0 ||
strncmp(linebuf, "PRI", 3) == 0 || strncmp(linebuf, "pri", 3) == 0)
{
methnum++;
}
}
fclose(infile);
infile = fopen(objname[methodlev], "r");
// Count objs
commentmode = 0;
while (fgets(linebuf, 200, infile))
{
if (linebuf[0] == '}')
{
commentmode--;
if (commentmode < 0) commentmode = 0;
continue;
}
else if (linebuf[0] == '{')
{
if (*FindChar(linebuf, '}') == 0)
commentmode++;
}
if (commentmode) continue;
if (mode == 0)
{
if (strncmp(linebuf, "OBJ", 3) == 0 || strncmp(linebuf, "obj", 3) == 0)
mode = 1;
}
else
{
methnum++;
if (linebuf[0] != ' ') break;
if (methnum == objnum)
{
char *ptr1;
char *ptr2;
int32_t num;
// Locate filename
ptr1 = FindChar(linebuf, '"');
if (*ptr1)
ptr1++;
ptr2 = FindChar(ptr1, '"');
if (*ptr2) ptr2--;
else
ptr2 = ptr1;
num = ptr2 - ptr1 + 1;
if (num < 1) num = 1;
memcpy(objname[methodlev], ptr1, num);
objname[methodlev][num] = 0;
if (symflag == 2)
strcat(objname[methodlev], ".spn");
else
strcat(objname[methodlev], ".spin");
fclose(infile);
found = 1;
break;
}
}
}
if (!found)
{
fclose(infile);
return;
}
ProcessCall(subnum, 0);
}
static int GetOpIndex(int opcode);
static int GetExOpIndex(int opcode);
void PrintOp(SpinVarsT *spinvars)
{
long pcurr = spinvars->pcurr;
int32_t opcode;
int32_t opform = 0;
char *opstr;
int exop1, exop2;
int32_t val;
int32_t operand;
char *regop[] = {"ldreg", "streg", "exreg", "??reg"};
char *regname[] = {"par", "cnt", "ina", "inb", "outa", "outb", "dira",
"dirb", "ctra", "ctrb", "frqa", "frqb", "phsa", "phsb", "vcfg", "vscl"};
char bytestr[40], symstr[100];
if (spinvars->state != 1) return;
opcode = BYTE(pcurr);
exop1 = GetOpIndex(opcode);
exop2 = -1;
opstr = FindOpcode(pcurr, &opform, 0);
memset(bytestr, ' ', 40);
bytestr[20] = 0;
sprintf(bytestr, "%4.4x %2.2x", (unsigned int)pcurr, opcode);
symstr[0] = 0;
switch (opform & 0x1f)
{
case OP_NONE:
strcpy(symstr, opstr);
if (strncmp(opstr, "ret", 3) == 0)
ProcessRet();
pcurr++;
break;
case OP_UNSIGNED_OBJ_OFFSET:
case OP_UNSIGNED_VAR_OFFSET:
case OP_UNSIGNED_LOC_OFFSET:
operand = BYTE(pcurr+1);
if (operand & 0x80)
{
operand = ((operand & 0x7f) << 8) | BYTE(pcurr+2);
sprintf(bytestr + strlen(bytestr), " %2.2x %2.2x", BYTE(pcurr+1), BYTE(pcurr+2));
pcurr += 3;
}
else
{
sprintf(bytestr + strlen(bytestr), " %2.2x", BYTE(pcurr+1));
pcurr += 2;
}
sprintf(symstr, "%s $%x", opstr, operand);
break;
case OP_DATA:
sprintf(symstr, "%s - ******** TBD ********", opstr);
pcurr++;
break;
case OP_SIGNED_OFFSET:
case OP_SIGNED_JMP_OFFSET:
operand = BYTE(pcurr+1);
if (operand & 0x80)
{
operand = ((operand & 0x7f) << 8) | BYTE(pcurr+2);
operand = (operand << 17) >> 17;
sprintf(bytestr + strlen(bytestr), " %2.2x %2.2x", BYTE(pcurr+1), BYTE(pcurr+2));
pcurr += 3;
}
else
{
operand = (operand << 25) >> 25;
sprintf(bytestr + strlen(bytestr), " %2.2x", BYTE(pcurr+1));
pcurr += 2;
}
sprintf(symstr, "%s %d", opstr, operand);
break;
case OP_MEMORY_OPCODE_READ:
case OP_MEMORY_OPCODE_WRITE:
operand = (BYTE(pcurr+1) >> 5) & 3;
opstr = regop[operand];
if (operand == 2) opform |= 1 << 5;
operand = (BYTE(pcurr+1) & 31);
sprintf(bytestr + strlen(bytestr), " %2.2x", BYTE(pcurr+1));
if (operand <= 15)
{
sprintf(symstr, "%s $%3.3x", opstr, operand + 0x1e0);
}
else
{
sprintf(symstr, "%s %s", opstr, regname[operand-16]);
}
pcurr += 2;
break;
case OP_OBJ_CALL_PAIR:
sprintf(bytestr + strlen(bytestr), " %2.2x %2.2x", BYTE(pcurr+1), BYTE(pcurr+2));
sprintf(symstr, "%s %d %d", opstr, BYTE(pcurr+1), BYTE(pcurr+2));
ProcessObjCall(BYTE(pcurr+1), BYTE(pcurr+2));
pcurr += 3;
break;
case OP_PACKED_LITERAL:
operand = BYTE(pcurr+1);
val = 2 << (operand & 31);
if (operand & 0x20) val--;
if (operand & 0x40) val = ~val;
sprintf(bytestr + strlen(bytestr), " %2.2x", operand);
sprintf(symstr, "%s $%x", opstr, val);
pcurr += 2;
break;
case OP_BYTE_LITERAL:
operand = BYTE(pcurr+1);
sprintf(bytestr + strlen(bytestr), " %2.2x", operand);
sprintf(symstr, "%s %d", opstr, operand);
if (strcmp(opstr, "call") == 0)
ProcessCall(operand, 1);
pcurr += 2;
break;
case OP_WORD_LITERAL:
operand = BYTE(pcurr+1);
operand = (operand << 8) | BYTE(pcurr+2);
sprintf(bytestr + strlen(bytestr), " %2.2x %2.2x", BYTE(pcurr+1), BYTE(pcurr+2));
sprintf(symstr, "%s %d", opstr, operand);
pcurr += 3;
break;
case OP_NEAR_LONG_LITERAL:
operand = BYTE(pcurr+1);
operand = (operand << 8) | BYTE(pcurr+2);
operand = (operand << 8) | BYTE(pcurr+3);
sprintf(bytestr + strlen(bytestr), " %2.2x %2.2x %2.2x",
BYTE(pcurr+1), BYTE(pcurr+2), BYTE(pcurr+3));
sprintf(symstr, "%s %d", opstr, operand);
pcurr += 4;
break;
case OP_LONG_LITERAL:
operand = BYTE(pcurr+1);
operand = (operand << 8) | BYTE(pcurr+2);
operand = (operand << 8) | BYTE(pcurr+3);
operand = (operand << 8) | BYTE(pcurr+4);
sprintf(bytestr + strlen(bytestr), " %2.2x %2.2x %2.2x %2.2x",
BYTE(pcurr+1), BYTE(pcurr+2), BYTE(pcurr+3), BYTE(pcurr+4));
sprintf(symstr, "%s %d", opstr, operand);
pcurr += 5;
break;
case OP_MEMORY_OPCODE:
sprintf(symstr, "%s - ******** TBD ********", opstr);
pcurr++;
break;
case OP_COMPACT_VAR_OFFSET:
case OP_COMPACT_LOC_OFFSET:
operand = opcode & 0x1c;
sprintf(symstr, "%s $%x", opstr, operand);
pcurr++;
break;
}
if ((opform >> 5) == 1)
{
char *loadstr = "";
opcode = BYTE(pcurr);
exop2 = GetExOpIndex(opcode);
if (opcode & 0x80)
{
loadstr = "load";
opcode &= 0x7f;
}
opstr = FindOpcode(pcurr, &opform, 1);
if (opcode != 0x02)
{
sprintf(symstr + strlen(symstr), " %s %s", opstr, loadstr);
sprintf(bytestr + strlen(bytestr), " %2.2x", BYTE(pcurr));
}
else
{
operand = BYTE(pcurr+1);
if (operand < 0x80)
{
operand = (operand << 25) >> 25;
sprintf(bytestr + strlen(bytestr), " %2.2x %2.2x",
BYTE(pcurr), BYTE(pcurr+1));
pcurr++;
}
else
{
operand = (operand << 8) | BYTE(pcurr+2);
operand = (operand << 17) >> 17;
sprintf(bytestr + strlen(bytestr), " %2.2x %2.2x %2.2x",
BYTE(pcurr), BYTE(pcurr+1), BYTE(pcurr+2));
pcurr += 2;
}
sprintf(symstr + strlen(symstr), " %s %d %s", opstr, operand, loadstr);
}
pcurr++;
}
bytestr[strlen(bytestr)] = ' ';
fprintf(tracefile, "%s %s\n", bytestr, symstr);
//fprintf(tracefile, "%s [%2d,%2d] %s\n", bytestr, exop1, exop2, symstr);
}
static int opcount[256];
static int exopcount[27][45];
static int GetExOpIndex(int opcode)
{
int index;
opcode &= 0x7f;
if (opcode >= 0x40)
index = (opcode & 0x1f) + 13;
else if (opcode >= 0x20)
index = (opcode >> 3) + 5;
else if (opcode >= 0x02)
index = (opcode >> 2) + 1;
else
index = 0;
return index;
}
static int GetOpIndex(int opcode)
{
int index = -1;
if (opcode == 0x26)
index = 0;
else if ((opcode >= 0x40 && opcode <= 0x7f) && (opcode & 3) == 2)
index = ((opcode - 0x40) >> 7) + 1;
else if ((opcode >= 0x80 && opcode < 0xe0) && (opcode & 3) == 2)
index = ((opcode - 0x80) >> 2) + 3;
return index;
}
void ResetStats(void)
{
memset(opcount, 0, 256 * 4);
memset(exopcount, 0, 27 * 45 * 4);
}
void CountOp(SpinVarsT *spinvars)
{
int pcurr = spinvars->pcurr;
int opcode = BYTE(pcurr++);
int opindex, exopindex;
if (opcode >= 0x40 && opcode <= 0x7f) opcode &= 0x63;
opcount[opcode]++;
opindex = GetOpIndex(opcode);
if (opindex < 0) return;
if (opcode >= 0x80 && ((opcode >> 2) & 3))
{
opcode = BYTE(pcurr++);
if (opcode & 0x80) pcurr++;
}
opcode = BYTE(pcurr);
exopindex = GetExOpIndex(opcode);
exopcount[opindex][exopindex]++;
}
void PrintStats(void)
{
int i, j;
int opcode;
int opindex;
int exop, k;
char *exname;
char *opname;
static char *exopname[13] = {
"store", "repeat", "repeats", "randf", "randr", "sexb", "sexw",
"postclr", "postset", "preinc", "postinc", "predec", "postdec"};
static unsigned char exopcode[13] = { 0x00, 0x02, 0x06, 0x08,
0x0c, 0x10, 0x14, 0x18, 0x1c, 0x20, 0x28, 0x30, 0x38};
for (i = 0; i < 256; i++)
{
if (opcount[i] == 0) continue;
opcode = i;
if (opcode >= 0x40 && opcode <= 0x7f) opcode &= 0x63;
for (j = 0; optable[j].opname; j++)
{
if (opcode == optable[j].opcode) break;
}
opname = optable[j].opname;
opindex = GetOpIndex(i);
if (opindex >= 0)
{
for (j = 0; j < 45; j++)
{
if (exopcount[opindex][j] == 0) continue;
if (j < 13)
{
exop = exopcode[j];
exname = exopname[j];
}
else
{
exop = j - 13 + 0xe0;
for (k = 0; optable[k].opname; k++)
{
if (exop == optable[k].opcode) break;
}
exname = optable[k].opname;
}
fprintf(tracefile, "%10d, %2.2x:%2.2x, %s:%s\n",
exopcount[opindex][j], i, exop, opname, exname);
}
}
else
{
fprintf(tracefile, "%10d, %2.2x, %s\n", opcount[i], i, opname);
}
}
}
/*
+------------------------------------------------------------------------------------------------------------------------------+
| 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. |
+------------------------------------------------------------------------------------------------------------------------------+
*/

3
spindebug.h Executable file
View File

@ -0,0 +1,3 @@
void ResetStats(void);
void CountOp(SpinVarsT *spinvars);
void PrintStats(void);

1313
spininterp.c Executable file

File diff suppressed because it is too large Load Diff

920
spinsim.c Executable file
View File

@ -0,0 +1,920 @@
/*******************************************************************************
' Author: Dave Hein
' Version 0.75
' Copyright (c) 2010 - 2014
' See end of file for terms of use.
'******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#ifdef LINUX
#include <dirent.h>
#include <sys/stat.h>
#include "conion.h"
#else
#include <conio.h>
#include <direct.h>
#endif
#include "interp.h"
#include "rom.h"
#include "spindebug.h"
#include "eeprom.h"
// Define system I/O addresses and commands
//#define SYS_COMMAND 0x12340000
//#define SYS_LOCKNUM 0x12340002
//#define SYS_PARM 0x12340004
//#define SYS_DEBUG 0x12340008
#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;
char lockstate[8];
char lockalloc[8];
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;
int32_t proptwo = 0;
int32_t baudrate = 0;
int32_t pin_val = -1;
int32_t gdbmode = 0;
int32_t eeprom = 0;
int32_t debugmode = 0;
int32_t printbreak = 0;
FILE *logfile = NULL;
FILE *tracefile = NULL;
FILE *cmdfile = NULL;
PasmVarsT PasmVars[8];
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);
void spinsim_exit(int32_t exitcode)
{
restore_console_io();
exit(exitcode);
}
void usage(void)
{
fprintf(stderr, "Spinsim Version 0.75\n");
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");
fprintf(stderr, " -t Enable the Prop 2 mode\n");
fprintf(stderr, " -b# Enable the serial port and set the baudrate to # (default 115200)\n");
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");
spinsim_exit(1);
}
void putchx(int32_t val)
{
putchar(val);
fflush(stdout);
}
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;
}
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)
{
#ifdef LINUX
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];
char *ptr;
if (path[0] == '/')
{
strcpy(fullpath, rootdir);
strcat(fullpath, path);
}
else
strcpy(fullpath, path);
ptr = fullpath;
#ifndef LINUX
while (*ptr)
{
if (*ptr == '/') *ptr = 0x5c;
ptr++;
}
#endif
parm = chdir(fullpath);
LONG(SYS_PARM) = parm;
}
else if (command == SYS_FILE_GETCWD)
{
char *ptr;
char *str = (char *)&BYTE(LONG(parm));
int32_t num = LONG(parm+4);
ptr = getcwd(str, num);
LONG(SYS_PARM) = LONG(parm);
}
else if (command == SYS_FILE_MKDIR)
{
//char *fname = (char *)&BYTE(parm);
#ifdef LINUX
#if 0
LONG(SYS_PARM) = mkdir(fname, S_IRWXU | S_IRWXG | S_IRWXO);
#endif
#else
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)
{
#ifdef LINUX
#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;
}
int CheckSerialIn(void)
{
static int state = 0;
static int count = 0;
static int val;
if (state == 0)
{
if (kbhit1())
{
val = getch();
if (val == 0x1d) return 1;
val |= 0x300;
if (proptwo)
count = 80000000 / baudrate;
else
{
count = LONG(0) / baudrate;
count >>= 2;
}
//if (!proptwo) count >>= 2;
pin_val &= 0x7fffffff;
state = 1;
}
}
else if (--count <= 0)
{
if (++state > 11)
{
state = 0;
}
else
{
pin_val = (pin_val & 0x7fffffff) | ((val & 1) << 31);
val >>= 1;
#if 0
count = LONG(0) / baudrate;
if (!proptwo) count >>= 2;
#endif
if (proptwo)
count = 80000000 / baudrate;
else
{
count = LONG(0) / baudrate;
count >>= 2;
}
}
}
return 0;
}
void CheckSerialOut(void)
{
int txbit = 0;
static int val;
static int state = -2;
static int count;
//static int txbit0 = 0;
txbit = (pin_val >> 30) & 1;
//if (txbit != txbit0) fprintf(stderr, "txbit = %d, loopcount = %d\n", txbit, loopcount);
//txbit0 = txbit;
if (state == -2)
{
if (txbit)
{
state = -1;
//fprintf(stderr, "Start Serial\n");
}
}
else if (state == -1)
{
if (!txbit)
{
val = 0;
state = 0;
#if 0
count = LONG(0) / baudrate;
if (!proptwo) count >>= 2;
#endif
if (proptwo)
count = 80000000 / baudrate;
else
{
count = LONG(0) / baudrate;
count >>= 2;
}
count += count >> 1;
}
}
else
{
if (--count <= 0)
{
if (state > 7)
{
state = -1;
#if 1
if (val == 13)
putchx(10);
else
putchx(val);
#else
printf("<%2.2x>\n", val);
#endif
}
else
{
//fprintf(stderr, "%d", txbit);
val |= txbit << state;
#if 0
count = LONG(0) / baudrate;
if (!proptwo) count >>= 2;
#endif
if (proptwo)
count = 80000000 / baudrate;
else
{
count = LONG(0) / baudrate;
count >>= 2;
}
state++;
}
}
}
}
void PrintStack(SpinVarsT *spinvars)
{
int32_t dcurr = spinvars->dcurr;
printf("PrintStack: %4.4x %8.8x %8.8x %8.8x\n",
dcurr, LONG(dcurr-4), LONG(dcurr-8), LONG(dcurr-12));
}
char *bootfile;
void RebootProp(void)
{
int32_t i;
int32_t dbase;
char *ptr;
FILE *infile;
if (!proptwo) memset(hubram, 0, 32768);
memset(lockstate, 0, 8);
memset(lockalloc, 0, 8);
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);
}
i = fread(hubram, 1, 32768, infile);
fclose(infile);
}
// Copy in the ROM contents
if (!proptwo)
{
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;
for (i = 0; i < 8; i++) PasmVars[i].state = 0;
if (pasmspin)
{
if (proptwo)
StartPasmCog2(&PasmVars[0], 0, 0x0e00, 0);
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;
}
//LONG(SYS_DEBUG) = printflag;
}
int step_chip(void)
{
int i;
int state;
int runflag = 0;
int breakflag = 0;
SpinVarsT *spinvars;
for (i = 0; i < 8; i++)
{
state = PasmVars[i].state;
PasmVars[i].printflag = (LONG(SYS_DEBUG) >> (i*4)) & 15;
if (state & 4)
{
if (PasmVars[i].printflag && state == 5)
{
if (!proptwo)
{
fprintf(tracefile, "Cog %d: ", i);
DebugPasmInstruction(&PasmVars[i]);
}
}
if (proptwo)
{
breakflag = ExecutePasmInstruction2(&PasmVars[i]);
if (PasmVars[i].printflag && state == 5)
fprintf(tracefile, "\n");
}
else
{
ExecutePasmInstruction(&PasmVars[i]);
if (PasmVars[i].printflag && state == 5) printf("\n");
}
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 *ptr;
char *fname = 0;
int32_t i;
int32_t maxloops = -1;
tracefile = stdout;
ptr = getcwd(rootdir, 100);
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);
}
} else if (strcmp(argv[i], "-t") == 0)
{
proptwo = 1;
pasmspin = 1;
memsize = 256;
cycleaccurate = 1;
}
else if (strcmp(argv[i], "-p") == 0)
{
pasmspin = 1;
cycleaccurate = 1;
}
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();
initialize_console_io();
if (gdbmode)
gdb();
else if (debugmode)
Debug();
else
RunProp(maxloops);
restore_console_io();
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. |
+------------------------------------------------------------------------------------------------------------------------------+
*/

13
spinsim.h Executable file
View File

@ -0,0 +1,13 @@
int step_chip(void);
int CheckSerialIn(void);
void CheckCommand(void);
void putchx(int32_t val);
void CheckSerialOut(void);
void spinsim_exit(int32_t exitcode);
#define WAIT_CNT 01
#define WAIT_MULT 02
#define WAIT_PIN 03
#define WAIT_HUB 16
#define WAIT_CACHE 17