plxvm/src/main.c

347 lines
8.6 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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;
}
}
}