/* * rpl.c * * This file is part of Emu48 * * Copyright (C) 1995 Sebastien Carlier * */ #include "pch.h" #include "Emu48.h" #include "ops.h" #include "io.h" //| 38G | 39G | 40G | 48SX | 48GX | 49G | Name //#F0688 #806E9 #806E9 #7056A #806E9 #806E9 =TEMPOB //#F068D #806EE #806EE #7056F #806EE #806EE =TEMPTOP //#F0692 #806F3 #806F3 #70574 #806F3 #806F3 =RSKTOP (B) //#F0697 #806F8 #806F8 #70579 #806F8 #806F8 =DSKTOP (D1) //#F0DEA #80E9B #80E9B #7066E #807ED #80E9B =AVMEM (D) //#F0705 #8076B #8076B #705B0 #8072F #8076B =INTRPPTR (D0) // #80F02 #80F02 #706C5 #80843 #80F02 =SystemFlags #define TEMPOB ((cCurrentRomType=='S')?0x7056A:0x806E9) #define TEMPTOP ((cCurrentRomType=='S')?0x7056F:0x806EE) #define RSKTOP ((cCurrentRomType=='S')?0x70574:0x806F3) #define DSKTOP ((cCurrentRomType=='S')?0x70579:0x806F8) #define AVMEM ((cCurrentRomType!='X')?((cCurrentRomType=='S')?0x7066E:0x807ED):0x80E9B) #define INTRPPTR ((cCurrentRomType!='X')?((cCurrentRomType=='S')?0x705B0:0x8072F):0x8076B) #define SYSTEMFLAGS ((cCurrentRomType!='X')?((cCurrentRomType=='S')?0x706C5:0x80843):0x80F02) #define DOINT 0x02614 // Precision Integer (HP49G) #define DOLNGREAL 0x0263A // Precision Real (HP49G) #define DOLNGCMP 0x02660 // Precision Complex (HP49G) #define DOMATRIX 0x02686 // Symbolic matrix (HP49G) #define DOFLASHP 0x026AC // Flash PTR (HP49G) #define DOAPLET 0x026D5 // Aplet (HP49G) #define DOMINIFONT 0x026FE // Mini Font (HP49G) #define DOBINT 0x02911 // System Binary #define DOREAL 0x02933 // Real #define DOEREAL 0x02955 // Long Real #define DOCMP 0x02977 // Complex #define DOECMP 0x0299D // Long Complex #define DOCHAR 0x029BF // Character #define DOARRY 0x029E8 // Array #define DOLNKARRY 0x02A0A // Linked Array #define DOCSTR 0x02A2C // String #define DOHSTR 0x02A4E // Binary Integer #define DOLIST 0x02A74 // List #define DORRP 0x02A96 // Directory #define DOSYMB 0x02AB8 // Algebraic #define DOTAG 0x02AFC // Tagged #define DOEXT1 0x02BAA // Extended Pointer #define DOEXT 0x02ADA // Unit #define DOGROB 0x02B1E // Graphic #define DOLIB 0x02B40 // Library #define DOBAK 0x02B62 // Backup #define DOEXT0 0x02B88 // Library Data #define DOEXT2 0x02BCC // Reserved 1, Font (HP49G) #define DOEXT3 0x02BEE // Reserved 2 #define DOEXT4 0x02C10 // Reserved 3 #define DOCOL 0x02D9D // Program #define DOCODE 0x02DCC // Code #define DOIDNT 0x02E48 // Global Name #define DOLAM 0x02E6D // Local Name #define DOROMP 0x02E92 // XLIB Name #define SEMI 0x0312B // ; #define GARBAGECOL 0x0613E // =GARBAGECOL entry for HP48S/G and HP49G // check for Metakernel version #define METAKERNEL Metakernel() // search for "MDGKER:MK2.30" or "MDGKER:PREVIE" in port1 of a HP48GX static BOOL Metakernel(VOID) { BOOL bMkDetect = FALSE; // card in slot1 of a HP48GX enabled if (cCurrentRomType=='G' && Chipset.Port1 && Chipset.cards_status & PORT1_PRESENT) { // check for Metakernel string "MDGKER:" if (!strncmp(&Chipset.Port1[12],"\xD\x4\x4\x4\x7\x4\xB\x4\x5\x4\x2\x5\xA\x3",14)) { bMkDetect = TRUE; // Metakernel detected // check for "MK" if (!strncmp(&Chipset.Port1[26],"\xD\x4\xB\x4",4)) { // get version number WORD wVersion = ((Chipset.Port1[30] * 10) + Chipset.Port1[34]) * 10 + Chipset.Port1[36]; // version newer then V2.30, then compatible with HP OS bMkDetect = (wVersion <= 230); } } } return bMkDetect; } static DWORD RPL_GarbageCol(VOID) // RPL variables must be in system RAM { CHIPSET OrgChipset; DWORD dwAVMEM; // only for HP48SX, HP48GX and HP49G _ASSERT(cCurrentRomType == 'S' || cCurrentRomType == 'G' || cCurrentRomType == 'X'); OrgChipset = Chipset; // save original chipset // entry for =GARBAGECOL Chipset.P = 0; // P=0 Chipset.mode_dec = FALSE; // hex mode Chipset.pc = GARBAGECOL; // =GARBAGECOL entry rstkpush(0xFFFFF); // return address for stopping while (Chipset.pc != 0xFFFFF) // wait for stop address { EvalOpcode(FASTPTR(Chipset.pc)); // execute opcode } dwAVMEM = Npack(Chipset.C,5); // available AVMEM Chipset = OrgChipset; // restore original chipset return dwAVMEM; } BOOL RPL_GetSystemFlag(INT nFlag) { DWORD dwAddr; BYTE byMask,byFlag; _ASSERT(nFlag > 0); // first flag is 1 // calculate memory address and bit mask dwAddr = SYSTEMFLAGS + (nFlag - 1) / 4; byMask = 1 << ((nFlag - 1) & 0x3); Npeek(&byFlag,dwAddr,sizeof(byFlag)); return (byFlag & byMask) != 0; } DWORD RPL_SkipOb(DWORD d) { BYTE X[8]; DWORD n, l; Npeek(X,d,5); n = Npack(X, 5); // read prolog switch (n) { case DOFLASHP: l = (cCurrentRomType!='X') ? 5 : 12; break; // Flash PTR (HP49G) case DOBINT: l = 10; break; // System Binary case DOREAL: l = 21; break; // Real case DOEREAL: l = 26; break; // Long Real case DOCMP: l = 37; break; // Complex case DOECMP: l = 47; break; // Long Complex case DOCHAR: l = 7; break; // Character case DOEXT1: l = 15; break; // Extended Pointer case DOROMP: l = 11; break; // XLIB Name case DOMATRIX: // Symbolic matrix (HP49G) if (cCurrentRomType!='X') { l = 5; break; } case DOLIST: // List case DOSYMB: // Algebraic case DOEXT: // Unit case DOCOL: // Program n=d+5; do { d=n; n=RPL_SkipOb(d); } while (d!=n); return n+5; case SEMI: return d; // SEMI case DOIDNT: // Global Name case DOLAM: // Local Name case DOTAG: // Tagged Npeek(X,d+5,2); n = 7 + Npack(X,2)*2; return RPL_SkipOb(d+n); case DORRP: // Directory d+=8; n = Read5(d); if (n==0) { return d+5; } else { d+=n; Npeek(X,d,2); n = Npack(X,2)*2 + 4; return RPL_SkipOb(d+n); } case DOINT: // Precision Integer (HP49G) case DOAPLET: // Aplet (HP49G) case DOMINIFONT: // Mini Font (HP49G) if (cCurrentRomType!='X') { l = 5; break; } case DOARRY: // Array case DOLNKARRY: // Linked Array case DOCSTR: // String case DOHSTR: // Binary Integer case DOGROB: // Graphic case DOLIB: // Library case DOBAK: // Backup case DOEXT0: // Library Data case DOEXT2: // Reserved 1, Font (HP49G) case DOEXT3: // Reserved 2 case DOEXT4: // Reserved 3 case DOCODE: // Code l = 5+Read5(d+5); break; case DOLNGREAL: // Precision Real (HP49G) l = 5; if (cCurrentRomType=='X') { l += Read5(d+l); l += Read5(d+l); } break; case DOLNGCMP: // Precision Complex (HP49G) l = 5; if (cCurrentRomType=='X') { l += Read5(d+l); l += Read5(d+l); l += Read5(d+l); l += Read5(d+l); } break; default: return d+5; } return d+l; } DWORD RPL_ObjectSize(BYTE *o) { DWORD n, l = 0; n = Npack(o, 5); // read prolog switch (n) { case DOFLASHP: l = (cCurrentRomType!='X') ? 5 : 12; break; // Flash PTR (HP49G) case DOBINT: l = 10; break; // System Binary case DOREAL: l = 21; break; // Real case DOEREAL: l = 26; break; // Long Real case DOCMP: l = 37; break; // Complex case DOECMP: l = 47; break; // Long Complex case DOCHAR: l = 7; break; // Character case DOEXT1: l = 15; break; // Extended Pointer case DOROMP: l = 11; break; // XLIB Name case DOMATRIX: // Symbolic matrix (HP49G) if (cCurrentRomType!='X') { l = 5; break; } case DOLIST: // List case DOSYMB: // Algebraic case DOEXT: // Unit case DOCOL: // Program n=5; do { l+=n; o+=n; n=RPL_ObjectSize(o); } while (n); l += 5; break; case SEMI: l = 0; break; // SEMI case DOIDNT: // Global Name case DOLAM: // Local Name case DOTAG: // Tagged n = 7 + Npack(o+5,2)*2; l = n + RPL_ObjectSize(o+n); break; case DORRP: // Directory n = Npack(o+8,5); if (n==0) // empty dir { l=13; } else { l = 8+n; n = Npack(o+l,2)*2 + 4; l += n; l += RPL_ObjectSize(o+l); } break; case DOINT: // Precision Integer (HP49G) case DOAPLET: // Aplet (HP49G) case DOMINIFONT: // Mini Font (HP49G) if (cCurrentRomType!='X') { l = 5; break; } case DOARRY: // Array case DOLNKARRY: // Linked Array case DOCSTR: // String case DOHSTR: // Binary Integer case DOGROB: // Graphic case DOLIB: // Library case DOBAK: // Backup case DOEXT0: // Library Data case DOEXT2: // Reserved 1, Font (HP49G) case DOEXT3: // Reserved 2 case DOEXT4: // Reserved 3 case DOCODE: // Code l = 5 + Npack(o+5,5); break; case DOLNGREAL: // Precision Real (HP49G) l = 5; if (cCurrentRomType=='X') { l += Npack(o+l,5); l += Npack(o+l,5); } break; case DOLNGCMP: // Precision Complex (HP49G) l = 5; if (cCurrentRomType=='X') { l += Npack(o+l,5); l += Npack(o+l,5); l += Npack(o+l,5); l += Npack(o+l,5); } break; default: l=5; } return l; } DWORD RPL_CreateTemp(DWORD l) { DWORD a, b, c; BYTE *p; l += 6; // memory for link field (5) + marker (1) and end b = Read5(RSKTOP); // tail address of rtn stack c = Read5(DSKTOP); // top of data stack if ((b+l)>c) // there's not enough memory to move DSKTOP { RPL_GarbageCol(); // do a garbage collection b = Read5(RSKTOP); // reload tail address of rtn stack c = Read5(DSKTOP); // reload top of data stack } if ((b+l)>c) return 0; // check if now there's enough memory to move DSKTOP a = Read5(TEMPTOP); // tail address of top object Write5(TEMPTOP, a+l); // adjust new end of top object Write5(RSKTOP, b+l); // adjust new end of rtn stack Write5(AVMEM, (c-b-l)/5); // calculate free memory (*5 nibbles) p = HeapAlloc(hHeap,0,b-a); // move down rtn stack Npeek(p,a,b-a); Nwrite(p,a+l,b-a); HeapFree(hHeap,0,p); Write5(a+l-5,l); // set object length field return (a+1); // return base address of new object } DWORD RPL_Pick(UINT l) { DWORD stkp; _ASSERT(l > 0); // first stack elememt is one if (l==0) return 0; if (METAKERNEL) ++l; // Metakernel support stkp = Read5(DSKTOP) + (l-1)*5; return Read5(stkp); } #if 0 // function not needed yet VOID RPL_Replace(DWORD n) { DWORD stkp; stkp = Read5(DSKTOP); if (METAKERNEL) stkp+=5; // Metakernel support Write5(stkp,n); return; } #endif VOID RPL_Push(DWORD n) { DWORD stkp, avmem; avmem = Read5(AVMEM); // amount of free memory if (avmem==0) return; // no memory free avmem--; // fetch memory Write5(AVMEM,avmem); // save new amount of free memory stkp = Read5(DSKTOP); // get pointer to stack level 1 if (METAKERNEL) // Metakernel running ? { Write5(stkp-5,Read5(stkp)); // copy object pointer of stack level 1 to new stack level 1 entry Write5(stkp,n); // save pointer to new object on stack level 2 stkp-=5; // fetch new stack entry } else { stkp-=5; // fetch new stack entry Write5(stkp,n); // save pointer to new object on stack level 1 } Write5(DSKTOP,stkp); // save new pointer to stack level 1 return; }