Mon 16 Mar 11:09:06 CET 2026

This commit is contained in:
sbosse 2026-03-16 11:10:42 +01:00
parent 57ef333953
commit f2d7c2481f

346
src/main.c Normal file
View File

@ -0,0 +1,346 @@
#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;
}
}
}