/************************************************************************* ** RSXMAP RSXMAP RSXMAP RSXMAP RSXMAP RSXMAP RSXMAP RSXMAP ** ** ** ** This little program is used to display the current dynamic ** ** memory map of a CP/M Plus (3.x) system. It shows the amount ** ** of Transient Program Area (TPA) memory that is available. ** ** Next, each each installed RSX is shown by displaying its ** ** load address, name and size in pages. ** ** ** ** There is currently a problem when using RSXMAP as a command ** ** in a multiple command line, i.e.: ** ** A>rsxmap ! dir ** ** In this example the "dir" command is stored by the CCP as a ** ** quick & dirty RSX while the RSXMAP is being run. The 1k size ** ** of the RSX is correct BUT the name is GARBAGE!! ** ** Jim Lopushinsky of the Meadowlark RCPM expects to have a fix ** ** for this in the next release of his CCP+. ** ** ** ** This program was developed under Manx Aztec C version 1.06D ** ** ** ** Developed by Sparrow Software Version 1.00 ** ** Released into the Public Domain 10 Feb 1986 ** ** ** ** Jim Dunn ** ** Sparrow Software ** ** 30 Birch Lane ** ** Fairport, NY 14450 ** ** ** ** Sparrow RCPM: (716) 377-1113 [300/1200/2400 bps] ** ** Voice: (716) 377-7036 ** ** CompuServe: 70245,170 ** *************************************************************************/ #include #define SML_STR 20 /* bytes in a small string */ #define MAX_RSX 20 /* maximum expected amount of RSXes */ int i,j,k, /* my favorite 3 little worker ints */ ver, /* CP/M version variable */ lhv, /* last high value, used in RSX size calc */ rsxct, /* RSX counter variable */ oc, /* output counter (inverse of above) */ *nextp, /* pointer to next RSX header - initial */ *nrsxp, /* pointer to next RSX header - result */ *biosp, /* BIOS pointer */ *bdosp; /* BDOS pointer */ long li; /* long integer needed for TPA size */ char gof[SML_STR], /* gofer char array */ str[SML_STR], /* another char array */ *cp; /* general purpose char pointer */ /* Let's make a new data type to hold RSX info */ typedef struct { char addr[4+1], /* RSX address */ name[8+1]; /* RSX name */ } RSXREC; RSXREC /* array of pointers to RSX records */ *rsxary[MAX_RSX]; int bdos(), /* returns an int */ isrsx(); /* returns an int */ char *strncpy(), /* returns a pointer to a char */ *malloc(); /* returns a pointer to a char */ void exit(), /* returns nothing */ storrsx(); /* returns absolutely nothing (like my dog) */ main() { /****************************************************************/ /********** Let's see what version of CP/M we are riding on */ /***** BDOS function 12 */ i = bdos(12, 0); /***** Quick and Dirty hex to decimal conversion */ sprintf(str, "%04x", i); sscanf(str, "%d", &ver); /***** Split tens and ones to insert decimal point */ i = ver / 10; j = ver - (i * 10); /***** Exit if not running under CP/M Plus */ if (i != 3) { printf("This will only work under CP/M Plus\n"); exit(1); } /****************************************************************/ /********** Now let's display the TPA size */ /********** This BDOS pointer will point to the begining of */ /********** any and all installed RSXes, so it will show the */ /********** current TPA, not the "ideal" TPA */ /***** Get value at 0006H, subtract 3 words (6 bytes) */ /***** Assign to BDOS pointer */ bdosp = (int *) (*(int *)6) - 3; /***** Subtract the CP/M base page from the TPA */ li = ((long)bdosp) - (long)256; /***** Now its time to display these values */ printf("CP/M Version %d.%d", i,j); printf(" TPA is %ld bytes\n", li); printf("==================================================\n"); /****************************************************************/ /********** Where is the BIOS entry table */ /***** Get value at 0001H, assign to BIOS pointer */ biosp = (int *) (*(int *)1); /***** Subtract 3 bytes to get to page boundary */ biosp = (int *) (((char *) biosp) - 3); /***** Last high value (lvh) holds the current high map address */ /***** it is used to calculate the difference between it and */ /***** bottom (begining) of the next RSX. */ lhv = (int) biosp; /***** Convert to upper case hex value and display it */ sprintf(gof, "%04x", biosp); for (cp = gof; *cp != '\0'; ++cp) { *cp = (char)toupper(*cp); } printf("BIOS entry at %s\n", gof); /****************************************************************/ /********** Let's find the lowest (last) RSX */ /***** Get value at 0006H, subtract 3 words (6 bytes) */ /***** Assign to BDOS pointer */ bdosp = (int *) (*(int *)6) - 3; /***** Move from the serial entry point to the start entry */ /***** point by adding 3 words (6 bytes) */ nextp = bdosp + 3; /***** cycle through the RSXes till we hit the BDOS */ /***** each RSX has its information stored via storrsx() */ while ((nrsxp = (int *) isrsx(nextp)) != 0) { storrsx(nextp, rsxct); ++rsxct; nextp = nrsxp; } /****************************************************************/ /***** This must now be the real BDOS entry */ /***** Get some heap storage for the BDOS record */ /***** Backup by 6 bytes for the top of the page (xx00H) */ /***** Convert first 2 charcters to upper case */ if ((rsxary[rsxct] = malloc(sizeof(RSXREC))) == NULL) { printf("malloc says:: out of memory!\n"); exit(1); } else { sprintf(rsxary[rsxct]->addr, "%04x", ((int)nextp) - 6); rsxary[rsxct]->addr[0] = (char)toupper(rsxary[rsxct]->addr[0]); rsxary[rsxct]->addr[1] = (char)toupper(rsxary[rsxct]->addr[1]); } /****************************************************************/ /***** time to display the upside down rsx table */ for (i = rsxct, oc = 0; i >= 0; --i, ++oc) { /* Convert hex addr string into integer k */ sscanf(rsxary[i]->addr, "%4x", &k); /* Subtract this current RSX address from last */ /* high value and covert into 256 byte pages */ j = (lhv - k) / 256; /*Iif (i == rsxct) then we are at BDOS entry */ if (i == rsxct) printf("BDOS entry at %s and is %2d pages\n", rsxary[i]->addr, j); else { printf("RSX %2d) is at %s and is %2d pages named %s\n", oc, rsxary[i]->addr, j, rsxary[i]->name); } /* Move current RSX address into last high value */ /* for next cycle. */ lhv = k; } printf("==================================================\n"); return(0); } int isrsx(upp) int *upp; { /***** We try to decide if this is an RSX by looking 9 bytes */ /***** past the start entry point. If in an RSX this is the */ /***** non-bank flag which will either be 00H or FFH. If we */ /***** made it all the way to the BDOS, this byte will be a */ /***** C3H jump command to whatever. */ if (((char *)upp)[9] == 0xc3) return (0); else /***** return with an integer value which is actually a pointer */ /***** to the next RSX. This value is obtained by moving */ /***** 4 bytes up from the start entry point. */ return (upp[2]); } void storrsx(upp, ct) int *upp, /* pointer to next high RSX */ ct; /* RSX count */ { /***** get someheap storage and store RSX record */ /***** Backup by 6 bytes for the top of the page (xx00H) */ /***** Move address hex value into RSX record */ /***** Move name into RSX record and delimit end of string */ /***** Convert first 2 charcters to upper case */ if ((rsxary[ct] = malloc(sizeof(RSXREC))) == NULL) { printf("malloc says:: out of memory!\n"); exit(1); } else { sprintf(rsxary[ct]->addr, "%04x", (int)upp - 6); strncpy(rsxary[ct]->name, (char *)upp + 10, 8); rsxary[ct]->name[8] = '\0'; rsxary[ct]->addr[0] = (char)toupper(rsxary[ct]->addr[0]); rsxary[ct]->addr[1] = (char)toupper(rsxary[ct]->addr[1]); } }