347 lines
8.6 KiB
C
347 lines
8.6 KiB
C
#include "config.h"
|
||
#include "types.h"
|
||
#include "lexer.h"
|
||
#include "tokens.h"
|
||
#include "mem.h"
|
||
#include "reg.h"
|
||
#include "stack.h"
|
||
#include "ops.h"
|
||
#include "context.h"
|
||
#include "code.h"
|
||
#include "event.h"
|
||
#include "vm.h"
|
||
#include "var.h"
|
||
#include "printf.h"
|
||
#include "ccall.h"
|
||
#include "version.h"
|
||
#include "unix.h"
|
||
#include "debug.h"
|
||
#include "cconst.h"
|
||
#include "net.h"
|
||
#include "run.h"
|
||
#include "log.h"
|
||
|
||
#include "shm.h"
|
||
|
||
#include <sys/select.h>
|
||
|
||
|
||
mem_t M;
|
||
/*
|
||
Primary (main foreground program) and secondary context (commands, temporary background programs)
|
||
Each context has its own register set, data and function stacks, but sharing one heap segment (M).
|
||
*/
|
||
reg_t R0,R1;
|
||
context_t C0,C1;
|
||
stack_t DS0,FS0,DS1,FS1;
|
||
|
||
int verbose = 0;
|
||
int profile = 0;
|
||
int nodeindex = 0;
|
||
|
||
static int _millis(context_t *C) {
|
||
number_t d=POP(C->DS);
|
||
PUSH(C->DS,(number_t)(MILLIS()/(unsigned long)d));
|
||
return 0; // non-blocking
|
||
}
|
||
|
||
static int _status(context_t *C) {
|
||
context_t *c=Context[0];
|
||
while(c) {
|
||
vLog("[C%d] PC=%d DS=%d(%d) FS=%d(%d) ST=%x EV=%x TMO=%d M=[%d:%d](%d)\n",
|
||
CONTEXTID(c),c->R->pc,
|
||
c->DS->sp,c->DS->size,
|
||
c->FS->sp,c->FS->size,
|
||
c->R->state,
|
||
c->evmask,
|
||
c->R->timeout,
|
||
c->M->bottom,
|
||
c->M->top,
|
||
c->M->size);
|
||
c=c->next;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
static int _timer(context_t *C) {
|
||
int millis=(int)POP(C->DS),
|
||
timernum=(int)POP(C->DS);
|
||
#if DEBUG>1
|
||
log(LOGDEBUG1,"timer(%d,%d)\n",timernum,millis);
|
||
#endif
|
||
if (millis==0) timer_stop(timernum);
|
||
else timer_start(timernum, millis);
|
||
return 0;
|
||
}
|
||
// must be sorted by name!
|
||
ccall_t myccalls[]={
|
||
{ "MILLIS", (int (*)())_millis, 1, 1, 0 },
|
||
{ "STATUS", (int (*)())_status,0,0,0 },
|
||
{ "TIMER", (int (*)())_timer,2,0,0 },
|
||
NULL
|
||
};
|
||
|
||
cconst_t mycconst[]={
|
||
{ "PORTALL", -1, NULL, 0},
|
||
{ "PORT0", 0, NULL, 0},
|
||
{ "PORT1", 1, NULL, 0},
|
||
{ "PORT2", 2, NULL, 0},
|
||
{ "PORT3", 3, NULL, 0},
|
||
NULL
|
||
};
|
||
|
||
#if HAS_NET > 0
|
||
static int (*handlers[MSGMAXNUM])()= {
|
||
NULL, // NOP
|
||
(int (*)())MessageHandlerCode, // MSGCOMMAND
|
||
(int (*)())MessageHandlerCode, // MSGPROGRAM
|
||
(int (*)())MessageHandlerCode, // MSGPROGRAMPART
|
||
|
||
NULL, // MSGDATA
|
||
(int (*)())MessageHandlerEvent, // MSGEVENT
|
||
(int (*)())MessageHandlerUser, // MSGUSER
|
||
|
||
NULL, // MSGNET
|
||
NULL // MSGMAXNUM
|
||
};
|
||
#endif
|
||
|
||
// Dummy routine for signal sending
|
||
static int sendSignal(event_t *ev,index_t evindex) {
|
||
printf("NOP: sendSignal (%d:%d)\n",evindex,ev->index);
|
||
return 0;
|
||
}
|
||
|
||
int main(int argc, char *argv[]) {
|
||
#if SHM>0
|
||
// SM segment starting address; must be incremented by a unique ´node number
|
||
void *vaddr=(void *)0xa0000000;
|
||
#endif
|
||
|
||
lexer_t L;
|
||
|
||
char compileOnly=0;
|
||
char service=0;
|
||
int maxrun=10;
|
||
char *input=NULL;
|
||
mem_t *mp=&M;
|
||
int portindex;
|
||
int progopn;
|
||
|
||
if (argc>1) for(int i=1;i<argc;i++) {
|
||
if (argv[i][0]=='-') switch (argv[i][1]) {
|
||
case 'v': verbose++; break;
|
||
}
|
||
}
|
||
if (verbose==1) log_level=LOGINFO;
|
||
if (verbose==2) log_level=LOGDEBUG1;
|
||
if (verbose==3) log_level=LOGDEBUG2;
|
||
if (verbose==4) log_level=LOGDEBUG3;
|
||
|
||
log(LOGINFO,">> PLX VM Ver. %s (c) Dr. Stefan Bosse<<\n",PLX_VERSION);
|
||
|
||
// Primaray context, main program
|
||
StackInit(&DS0,100,NULL);
|
||
StackInit(&FS0,100,NULL);
|
||
ContextInit(&C0,&M,&DS0,&FS0,&R0);
|
||
// Secondary context, command line execution
|
||
StackInit(&DS1,100,NULL);
|
||
StackInit(&FS1,100,NULL);
|
||
ContextInit(&C1,&M,&DS1,&FS1,&R1);
|
||
|
||
IOINIT();
|
||
TIMEINIT();
|
||
#if HAS_NET>0
|
||
NetInit(handlers,NULL,NULL);
|
||
#endif
|
||
|
||
#if 0
|
||
{
|
||
message_t *m1,*m2;
|
||
m1=AllocateMessage(&Links[0],MSGRX|MSGPROGRAM);
|
||
FinalizeMessage(m1);
|
||
m2=AllocateMessage(&Links[0],MSGRX|MSGNORM);
|
||
FinalizeMessage(m2);
|
||
PrintLinkMessages(&Links[0]);
|
||
FreeMessage(m1);
|
||
PrintLinkMessages(&Links[0]);
|
||
FreeMessage(m2);
|
||
PrintLinkMessages(&Links[0]);
|
||
}
|
||
#endif
|
||
timer_init();
|
||
//timer_start(0,500);
|
||
//timer_start(1,800);
|
||
|
||
CCallInit(myccalls);
|
||
CConstInit(mycconst);
|
||
|
||
// LexerInit(&L);
|
||
MemInit(&M,2000,NULL);
|
||
|
||
EventInit(0);
|
||
// add two timer events (indeed event name is shortend to "time" // 4 chars)
|
||
AddEvent("timer",0,EVTIMER);
|
||
AddEvent("timer",1,EVTIMER);
|
||
AddEvent("message",-1,EVMESSAGE); // user message event from all ports
|
||
|
||
AddEvent("signal",0,EVSIGNAL);
|
||
AddEventSender("signal",0,sendSignal);
|
||
AddEvent("signal",1,EVSIGNAL);
|
||
AddEventSender("signal",1,sendSignal);
|
||
|
||
// int sendSignal(event_t *ev, int evindex) {}
|
||
// AddEvent("signal",0,EVSIGNAL);
|
||
// AddEventSender("signal",0, sendSignal);
|
||
//
|
||
//address_t a1=allocate(&M,&R,"a",MVAR,1);
|
||
//print_format("$a1=%d\n",a1);
|
||
//address_t b1=allocate(&M,&R,"b",MVAR,1);
|
||
//print_format("$b1=%d\n",b1);
|
||
|
||
|
||
RegInit(&R0);
|
||
R0.debug=1;
|
||
RegInit(&R1);
|
||
R1.debug=1;
|
||
|
||
if (argc>1) for(int i=1;i<argc;i++) {
|
||
if (argv[i][0]=='-') {
|
||
switch (argv[i][1]) {
|
||
case 'c': compileOnly=1; continue;
|
||
case 'v': continue;
|
||
case 'h':
|
||
printf("plx vm ver. %s (c) Dr. Stefan Bosse\n",PLX_VERSION);
|
||
printf("usage: plx [-c(ompileonly)] [-S(ervice)] [-P(rofile)] [-v(erbose)] [-m(axrun) #] [-n(odeid) #id] [-l(inkto) srcportindex dstfifo] [-p(ort) portindex fifo]\n");
|
||
exit(0);
|
||
break;
|
||
case 'n':
|
||
if ((i+1) >= argc) {
|
||
exit(-1);
|
||
}
|
||
i++;
|
||
nodeindex = atoi(argv[i]);
|
||
continue;
|
||
case 'm':
|
||
if ((i+1) >= argc) {
|
||
exit(-1);
|
||
}
|
||
i++;
|
||
maxrun = atoi(argv[i]);
|
||
continue;
|
||
case 'l':
|
||
if ((i+2) >= argc) {
|
||
exit(-1);
|
||
}
|
||
i++;
|
||
portindex = atoi(argv[i]);
|
||
i++;
|
||
portfilewr[portindex]=argv[i];
|
||
continue;
|
||
case 'p':
|
||
if ((i+2) >= argc) {
|
||
exit(-1);
|
||
}
|
||
i++;
|
||
portindex = atoi(argv[i]);
|
||
i++;
|
||
char *rdfile = (char*)malloc(strlen(argv[i])+10),
|
||
*wrfile = (char*)malloc(strlen(argv[i])+10);
|
||
sprintf(rdfile,"%s:%d:%d:rx",argv[i],nodeindex,portindex);
|
||
sprintf(wrfile,"%s:%d:%d:tx",argv[i],nodeindex,portindex);
|
||
portfilerd[portindex]=rdfile;
|
||
portfilewr[portindex]=wrfile;
|
||
continue;
|
||
case 'P':
|
||
profile++;
|
||
continue;
|
||
case 'S':
|
||
service=1;
|
||
continue;
|
||
}
|
||
}
|
||
if (strlen(argv[i])>4 && strcmp(&argv[i][strlen(argv[i])-4],".plx")==0) {
|
||
input=readFile(argv[i]);
|
||
} else input=argv[i];
|
||
// LexerSetup(&L,input);
|
||
#if HAS_FUNC > 0
|
||
// CODEADD1I(C0->M,SETSP,0);
|
||
#endif
|
||
if (profile>1) {
|
||
int t0=MILLIS();
|
||
for(int i=0;i<10000;i++) {
|
||
Compile(&L,input,&C0,PRUNNING);
|
||
if (R0.error) {
|
||
log(LOGERROR,"Compiler error %d(%s) in line %d\n",R0.error,Errors[R0.error],L.line);
|
||
PrintLexerToken(&L);
|
||
return -1;
|
||
}
|
||
ReleaseSegment(C0.M,C0.S);
|
||
}
|
||
int t1=MILLIS();
|
||
log(100,"Compiler statistics: %d tokens, compile %d ns, %d ns / token, %d kTPS\n",
|
||
L.ntoken,(t1-t0)*100,(100*(t1-t0))/L.ntoken, 1000000/((100*(t1-t0))/L.ntoken) );
|
||
}
|
||
if (input) Compile(&L,input,&C0,i==(argc-1)?PRUNNING:0);
|
||
if (R0.error) {
|
||
log(LOGERROR,"Compiler error %d(%s) in line %d\n",R0.error,Errors[R0.error],L.line);
|
||
PrintLexerToken(&L);
|
||
return -1;
|
||
}
|
||
}
|
||
|
||
port_open();
|
||
|
||
if (verbose || profile) {
|
||
progopn=PrintCode(&M);
|
||
}
|
||
if (compileOnly) return 0;
|
||
|
||
int status;
|
||
R0.state=input?PRUNNING:PIDLE;
|
||
R0.steps=maxrun;
|
||
int t0=MILLIS();
|
||
if (!profile) {
|
||
if (service) {
|
||
do {
|
||
Loop(&C0,service);
|
||
if (R0.error) {
|
||
log(LOGERROR,"Run-time error %d(%s) at pc=%d\n",R0.error,Errors[R0.error],R0.pc);
|
||
ContextResetAll(NULL);
|
||
}
|
||
R0.error=0;
|
||
} while (service);
|
||
} else
|
||
Loop(&C0,0);
|
||
} else {
|
||
R0.steps=10000;
|
||
do {
|
||
status=Run(&C0);
|
||
} while(!R0.error && status==1);
|
||
}
|
||
// TODO: Check all context
|
||
if (R0.error) {
|
||
log(LOGERROR,"Run-time error %d(%s) at pc=%d\n",R0.error,Errors[R0.error],R0.pc);
|
||
return -1;
|
||
}
|
||
int t1=MILLIS();
|
||
if (verbose || profile) {
|
||
log(100,"VM Op Count=%d, %d MOPS, Token Count=%d, Program Op Count=%d\n",R0.opcount,(t1-t0)>0?(R0.opcount/(t1-t0))/1000:0,L.ntoken,progopn);
|
||
}
|
||
if (verbose) {
|
||
PrintCode(&M);
|
||
PrintHeap(&M);
|
||
PrintEvents(&events);
|
||
|
||
context_t *c=Context[0];
|
||
while (c) {
|
||
vLog("+++++++++ Context %d +++++++++\n",CONTEXTID(c));
|
||
PrintState(c->R);
|
||
PrintStack("DS",c->DS);
|
||
PrintStack("FS",c->FS);
|
||
c=c->next;
|
||
}
|
||
}
|
||
}
|
||
|