/* Julian Stacey's Portable Monitor currently having nasty_ removed to sort out pointer log collusion As at 03.06.2000 I was forcing this to compile on FreeBSD, but there's a whole lot of nastiness in here, some still marked by "JJ" that needs to be sorted out. */ #ifdef MSDOS /* { */ #include "grep_msd.h" /* assist grepping binary of this program */ #endif /* } */ char /* sccsID[] = "\n@(#) Monitor V2.1 : Copyright Julian H. Stacey Jan 1984.\n"; */ sccsID[] = "\n@(#) Monitor V3.0 : Copyright Julian H. Stacey Jan 1984, June 2000.\n"; /* Copyright, Julian Stacey, January 1984 Canterbury, England. * '96 Munich Germany. * * Facilities: * 1 Designed for NS16K system. * 1.5 Converted for MSDOS 8086 * 2 Help List. * 3 Intel Object IO * 4 Shortform hex input. * 5 Chained access (can use '+' & '-' as combined '+' & 'CR' or '-' & 'CR') * 6 Relative + Base addressing. * 7 Interrupt. * 8 To simplify data entry typing during sequential data entry, * instead of terminating data with 'white space' (the normal way), * a '+', '-', or '.' can be used to terminate input, the monitor * then doesn''t need white space until you wish to end chain data entry. * 9 Developed on Xerox CP/M system using C80 compiler. Then MSDOS, then FreeBSD * 10 Uses minimum number of library/(macro ?) calls in order to * ease transportation to ROM. * * Limitations: * 1 Needs ram for variables & stack frame, not a 'ROM only' monitor. * 2 No dis-assembler. * 4 No machine specific features such as * data sectors for normal/system, data/stack/code. * 5 Object IO : only data & EOF records implemented, * no relocatable records. * 6 No Backspace (delete a numeric character by shifting it off the end, * with 6 or less zeros). * 7 No symbolic labels. * * Pending Improvement: * 1 Suppres print of some CRs * 2 SIO Driver * 3 Validate/test case needs to generatethe dram time-out * chain branch code. * 4 SWI needs code to vector to & execute. * 5 + CR + CR + CR squences are tedious, could a CR be assumed * until terminating dot. * * Design Aims: * 1 To have a portable monitor usable on the NS16000 & 8086 series. * 2 To have a 'rich' list of facilities. * 3 Portability: to be usable for other 32 bit & lesser processors * with a minimum of modification. (Hence written in 'C' but with * more explicit entity sizes than C normally provides). * 4 To optimise for minimum code size rather than maximum speed (except * lengthy ram validate case). * * Assumptions: * 1 VDU does a CR LF if sent a CR. * * Notes: * 1 signal(10,1) & signal(11,1) should override segmentation * violations if debugging on a proper unix(though untried !) * 2 JJ & ?? = edit search key implying needs attention later * * Bugs: interrupt, doesnt * disc_rw() sets drive to A, but shouldnt */ #include #include /* for malloc() on FreeBSD */ char *ARGV ; /* Programming entities to aid portability */ #define s32bit long #define x32bit long #define u16bit unsigned #define x16bit int #define s16bit int #define x8bit char #define u8more unsigned #define x8more char #define s8more int #define BEL 7 /* Flags to define mode of operation of the monitor */ u8more size; /* Entity Type */ #define STRING 0 #define BYTE 1 #define WORD 2 #define LONG 3 u8more mod_access; /* Access Modes */ #define READ 1 #define WRITE 2 #define MODIFY READ | WRITE x8more verbose ; /* if flag is off monitor gives no prompts (useful for remote control of monitor by another program) */ x8more ascii ; /* if set & also in byte read mode, prints text as well as hex, else prints just hex */ x8more intrupt ; /* used to indicate when keyboard has interrupted a sequence. */ x8more dump ; /* if 1 write to disc (& possibly screen), if 0 write to screen */ x8more load ; /* if 1 [read from disc & display on screen] if 0 read from keyboard */ x8more supres; /* used to suppress multiple CR LFs coming in from keyboard */ u8more cksum ; /* Checksum for intel loader format*/ FILE *chan; /* used by object io */ x8more hexcom; /* Max length name is a:monitor_.obj + null */ #ifndef unix /* { */ #define FILE_LN 15 #else /* } { */ #define FILE_LN 200 /* JJ tacky */ #endif /* } */ char filnam[FILE_LN]; /* filename for object IO (in RAM) */ char initnam[] = "DUMP.OBJ"; /* initial filename (in EPROM) */ char *name_p ; /* pointer to current filename */ char menu[] = "(For menu type \'?\')"; /* JJLATER hack this to signals */ interupt() { putchar(BEL); intrupt = 1; } x8more intj() { return(0); } x8more isletter(x) char x; { if ((x >= 0x20) && (x <= 0x7E)) return(1) ; else return(0); } /* Put a character to screen after seeing if a control B keyboard interrupt has occured */ putjch(ch_x) char ch_x; { /* JJLATER add something */ ch_x &= 0x7F ; /* make sure I put out no parity, also * make it a litle bit hard to modify the * copyright notice if the recipient only has a binary */ #define BS 8 #define HT 9 #define NL 0xA #define CR 0xD #define NULL_CH 0 if (isletter(ch_x) || ch_x == BEL || ch_x == BS || ch_x == HT || ch_x == NL || ch_x == CR || ch_x == NULL_CH ) /* mask out chars that will cause cursor addressing screen * disturbances, but allow nulls, as they may be used to * implement time delays */ { if (!dump) putchar(ch_x); else if (verbose) putchar(ch_x); } if (dump) putc(ch_x, chan); } /* my_error messages defined so they are consistently the same, & can be recognised by a remote control program */ my_error(x) char *x; { putjch(BEL); prints( "\nError : ") ; prints(x); } /* Ensure same spacing on screen for reads & writes */ #define prompt prints(" ? ") #define space prints(" \040 ") /* Output Routines */ put1h(x) char x; { if (x < 10) putjch(x + '0'); else putjch(x -10 + 'A'); } put2h(x) x8bit x; { cksum += x ; put1h((x >>4 ) & 0xF) ; put1h(x & 0xF); } put4h(x) x16bit x; { put2h((x >> 8) & 0xFF ); put2h(x & 0xFF) ; } put8h(x) x32bit x; { put4h((x >> 16) & 0xFFFF ); put4h(x & 0xFFFF); } putadr(x) x32bit x; { put2h(x >> 16 & 0xFF ); put4h(x & 0xFFFF); } out1h(x) char x; { putjch(' '); put1h(x); } out2h(x) x8bit x; { putjch(' '); put2h(x); } out4h(x) x16bit x; { putjch(' '); put4h(x); } out8h(x) x32bit x; { putjch(' '); put8h(x); } outadr(x) x32bit x; { putjch(' '); putadr(x); } /* Display current location addresses */ out_loc(base_p,kurrent,if_lf) char *base_p; long kurrent ; int if_lf; { if (if_lf) vputjch('\n'); if (base_p != (char *)0) { vprints( "B:" ); putadr(base_p); vprints( "+R:" ); } put8h(kurrent); if (base_p != (char *)0) { vprints( "=T:" ); putadr(kurrent + base_p) ; } putjch(' '); } put_byte(x) x8bit x; { put2h(x); put_letr(x); } put_letr(x) x8bit x; { putjch(' '); if ( ascii && isletter(x)) putjch(x) ; else putjch(' '); } vputjch(x) char x; { if (verbose) putjch(x); } /* String procedures */ vprints(x) char *x; { if (verbose) prints(x); } jgets(name,len) /* Puts a null terminated string into array *'name', where array is of max. size (inc null) 'len' */ char *name ; x8more len; { s8more c ; char *limit ; limit = name + len -1 ; while ( name < limit && (c = getjch()) != '\n' && c != EOF) { *name = (char)c ; name++ ; } *name = '\0'; } prints(x) char *x; { while((*x) && !intrupt) { /* if necessary for VDU if (*x == '\n') putjch('\r'); */ putjch(*x); x++; } } /* Input Routines */ /* Gets a charater from disc or keyboard */ s8more getjjch() { s8more x ; x = ( load ? getc(chan) : #ifdef MSDOS /* { */ getche() #endif /* } */ #ifdef unix /* { */ getchar() /* something else needed */ #endif /* } */ ) ; if ( x != EOF) { if (load && verbose) putchar((char)x); /* show whats coming from disc */ } return(x); } /* Strips multiple CR LF NULL strings to a single LF, to deal with unpleasant terminals.*/ s8more getjch() { s8more x; if (supres) /* ignore 'CR's etc */ { do x = getjjch() ; while (x == '\r' || x == '\n' || x == '\0'); supres = 0; /* allow next time to return a CR */ } else { /* may get a 'CR' etc */ x = getjjch() ; if ( x == '\r' || x == '\n' || x == '\0') { supres = 1 ; x = '\n'; } } return(x); } /* Gets one hex from keyboard returns -1 if a 'white space' character or comma, Assumptions : ASCII */ s8more geth() { s8more data ; hexcom = 0; for(;;) { data = getjch() ; if (data >= '0' && data <= '9') return(data - '0'); if (data >= 'A' && data <= 'F') return(data - 'A' + 10 ); if (data >= 'a' && data <= 'f') return(data - 'a' + 10 ); if (data == ' ' || data == '\t' || data == ',' || data == '\n' || data == EOF ) return((s8more)-1); if (data == '+' || data == '-' || data == '.') { hexcom = data; vprints("\b \n"); return((s8more)-1); } my_error( "\nHex characters only please.\n" ); } } /* The hex input routines below allow number correction by allowing continuous input up to a 'white space' - excess most significant nibbles fall of the left end */ x8bit get2h() /* Get a byte containing 2 hex chars */ { int temp1, temp2; while (( temp1 = geth()) == -1); while (( temp2 = geth() ) != -1 ) temp1 = (temp1 << 4) | temp2 ; return((x8bit)temp1); } u16bit get4h() { int temp; u16bit result; while ((result = geth()) == -1); while ( ( temp = geth() ) != -1 ) result = (result << 4) | temp ; return(result); } x32bit get8h() { int temp; s32bit result; while (( result = geth()) == -1 ) ; while ( ( temp = geth() ) != -1 ) result = (result << 4) | temp ; return(result); } /* 'getadr' jgets an address, it is separate from 'get8h' for 2 reasons : 1 in case fixed format input is one day required. 2 Current NS16K family adresses are 24 bits (= 6 hex) */ char * getadr() { return( (char *) get8h() ); } /* Gets 2 hex chars for object loader, no more, no less, no terminating white space required */ u8more take2h() { x8bit temp; temp = geth() << 4 ; temp |= geth() ; cksum += temp ; return(temp); } /* Display [current, previous, or next] : [byte, word, long, or string] */ present(base_p,kurrent,disp) char *base_p; long kurrent ; s8more disp ; /* Display of next entity to be accessed with case '.' , '+' , or '-' */ { unsigned count ; x8bit tmp; if ( size == BYTE) { kurrent += disp; out_loc(base_p,kurrent,0); if (mod_access & READ) { space; put_byte(*(kurrent + base_p)); } if (mod_access & WRITE) { prompt; *(kurrent + base_p) = get2h(); } } else if ( size == WORD) { kurrent += 2 * disp; out_loc(base_p,kurrent,0); if (mod_access & READ) { space; out4h(*((int *)(kurrent + base_p))); } if (mod_access & WRITE) { prompt; *((int *)(kurrent + base_p)) = get4h(); } } else if ( size == LONG ) { kurrent += 4 * disp; out_loc(base_p,kurrent,0); if (mod_access & READ) { space; out8h(*((long *)(kurrent + base_p))); } if (mod_access & WRITE) { prompt; *((long *)(kurrent + base_p)) = get8h(); } } else /* STRING */ { kurrent += disp; if (mod_access & READ) { out_loc(base_p,kurrent,0); count = 300; /* limit printout to give a feel of where you are, without printing kilobytes (in case the string you are printing is a source file !) */ space; while ((*(kurrent + base_p) != '\0') && count-- && !( intrupt)) putjch(*(kurrent++ + base_p)); } if (mod_access & WRITE) { out_loc(base_p,kurrent,0); prompt; while ((tmp = getjch()) != '\n' && tmp != EOF) *(kurrent++ + base_p) = tmp; /* note null deliberately not appended to string */ } } if (!(mod_access & WRITE)) vputjch('\n'); } /* Procedures used by the ram block validate case */ tstrfrsh() /* test dram refresh (see separate note in hardware document) */ { } /* Initialise Block to x (normally 0 or 0xFF), Returns: 1=success, 0=fail */ int initblk(base_p,kurrent,stop,byte) char *stop ; x8bit byte; char *base_p; long kurrent ; { char *tmp ; for (tmp = kurrent + base_p; kurrent + base_p <= stop; ) *(kurrent++ + base_p) = byte; tstrfrsh(); for (tmp = kurrent + base_p ; kurrent + base_p <= stop; ) { if (*(kurrent++ + base_p) != byte) { check_err(base_p,kurrent,byte); return(0); } } return(1); } x8bit rolb(x) /* rotate byte 1 bit to left */ x8bit x; { if ( x & 0x80 ) return((x << 1 ) | 1); else return(x<<1); } x8bit rorb(x) /* rotate byte 1 bit to right */ x8bit x; {if (x&1) return( ( x >> 1 ) | 0x80); else return( ( x >> 1 ) & 0x7F); } check_err(base_p,kurrent,x) char *base_p; long kurrent ; x8bit x; { my_error("\nData lost at "); out_loc(base_p,kurrent,0); prints("Data is "); put2h(*(kurrent + base_p)); prints(", but should be "); put2h(x); putjch('\n'); } /* check byte block for correctly set rotating 1s or 0s (return 1 if ok, 0 if not) JJLATER extend to int & long blocks */ chec_blok(base_p,kurrent,dir,bits,stop) char *base_p; long kurrent ; s8more dir; int bits ; char *stop ; { x8bit byte; char *tmp ; tstrfrsh(); if (dir == 1) /* increment through block */ { for (tmp = kurrent + base_p, byte = bits; tmp <= stop; tmp++, byte = rolb(byte)) { if ( *tmp != byte ) { check_err(base_p,kurrent,byte); return(0); } } } else /* decrement through block */ { for (tmp = kurrent + base_p, byte = bits; tmp >= stop; tmp--, byte = rorb(byte)) { if ( *tmp != byte ) { check_err(base_p,kurrent,byte); return(0); } } } return(1); } /* Prints my_error message for ram validation case. For when main case validate code has detected either : incompletely decoded address common with a previous address in the ram block under test, OR interference between the block & this monitor''s ram workspace */ shorterr(base_p,kurrent,dir,initial) char *base_p; long kurrent ; s8more dir; x8bit initial; { my_error("Possible incomplete decoding with a "); if (dir == 1) prints("lower"); else prints("higher"); prints(" address"); check_err(base_p,kurrent,initial); } /* Set disc to r/w (if you have changed discs while the monitor is running cpm will have made it read only, so make it now read/write. Side effect: logged disc becomes drive A/0 ) */ /* JJ:ATER may need something for msdos */ disc_rw() { } s8more out_open() { disc_rw(); if ((chan = fopen(name_p, "w")) == 0) { my_error("Cant open ") ;prints(name_p); return(0); } dump = 1; return(1); } s8more in_open(base_p,kurrent) char *base_p; long kurrent ; { if (kurrent == 0 && base_p == (char *)0) { my_error("Probable overwrite of monitor - so aborted"); return(0); } if ((chan = fopen(name_p,"r")) == 0) { my_error("Cant open ") ; prints(name_p); return(0); } load = 1; return(1); } status(base_p,kurrent) /* Print Monitor Status */ char *base_p; long kurrent ; { vprints("Status: "); out_loc(base_p,kurrent,0); if (mod_access & READ ) prints("Read, "); if (mod_access & WRITE ) prints("Write, "); if (( size) == BYTE ) prints("Byte"); if (( size) == WORD ) prints("Word"); if (( size) == LONG ) prints("Long"); if (( size) == STRING ) prints("Text"); prints(", Hex"); if ( ascii ) prints("+Ascii,"); else prints(" Only,"); if ( verbose ) prints(" Verbose,"); else prints(" Quiet,") ; prints(" \'"); prints(name_p); prints("\'\n"); } main(argc,argv) int argc ; char **argv ; { union cludge { char s1; unsigned s2; long s4; } data_union ; char *base_p, *stop_p, *mem_p, *dest ; long kurrent ; long tmp_l ; x8bit invert_mem ; /* memory of if pointers to be inverted */ s8more command; /* command character */ int (*procptr)(); /* procedure pointer */ x8more count1,count2; /* general count variable */ x8more forever; /* loop forever flag */ s8more validir; /* validate case: values 1, 0, -1, represent whether incrementing, or decrementing through block, or finished */ #define FINDSTR 30 char findstr[FINDSTR]; x8bit bits1,bits2,bits3; /* ram validate case: bit patterns of least significant byte in the block */ x8more init0F; /* ram validate case: 0 or FF block initialise data */ s8more chint; /* gen. purpose char declared as int so can get EOF */ u16bit load_tmp; /* used by load object case */ x8more eof_flg; /* used by load object case, 0 until an EOF record encountered, 1 after */ long length ; ARGV = *argv ; colds: /* cold start point */ /* initialise target micro port here */ #ifdef unix /* { */ /* JJ add something */ #endif /* } */ /* ifdef MSDOS nothing necessary */ prints(sccsID); prints("This monitor is not yet debugged. "); prints(menu); kurrent = 0; size = BYTE ; mod_access = READ ; verbose = 1; ascii = 1; supres = 0; name_p = &initnam[0] ; warms: /* Warm Start Point */ hexcom = 0; putchar('\n'); for (;;) /* Main Command Loop Of Monitor */ { if ((hexcom) && ( command == '+' || command == '.' || command == '-' )) { /* user wants to chain write, he has previously typed a '+', '-', or '.' */ command = hexcom ; hexcom = 0 ; } else { intrupt = 0; /* ensure prompt string will appear */ /* vputjch('\n'); only needed if keyboard doesnt have local echo */ vprints( "> " ); command=getjch(); vprints("\b\b\b \x20 \x20 \b\b\b"); } intrupt = 0 ; /* flush any interrupts */ if (command <= 'Z' && command >= 'A') command += 'a' - 'A' ; switch(command) { case EOF:my_error("End of file read.\n"); break ; case'\n':/* NULL :ignore carriage returns & line feeds */ break ; case'0':/* Set monitor back to initial mode */ kurrent = 0 ; base_p = (char *)0 ; size = BYTE ; mod_access = READ ; verbose = 1; ascii = 1; name_p = &initnam[0] ; invert_mem = 0 ; /* no break */ case's':status(base_p,kurrent); break; case'r':vprints("Read mode." );vputjch('\n'); mod_access = READ ; break; case'w':vprints( "Write mode." );vputjch('\n'); mod_access = WRITE ; break; case'm':vprints( "Modify mode (= read then write)." ); vputjch('\n') ; mod_access = MODIFY ; break; case'\"':vprints( "Text mode." );vputjch('\n'); size = STRING ; break; case'1':vprints("Byte mode." ); vputjch('\n') ; size = BYTE ; break; case'2':vprints("Word mode." ); vputjch('\n') ; size = WORD ; break; case'4':vprints("Long mode." ); vputjch('\n') ; size = LONG ; break; case'v':prints( "Verbose mode." ); vputjch('\n') ; verbose = 1; break; case'q':vprints( "Quiet mode." ); vputjch('\n') ; /* Tell user before you stop talking to them */ verbose = 0; break; case'\'':vprints("Ascii+hex mode."); vputjch('\n'); ascii = 1; break; case'h':vprints("Hex only mode." ); vputjch('\n') ; ascii = 0; break; case'a': vprints("how many bytes"); prompt; if ((base_p = malloc((size_t)get8h())) == (char *) 0) my_error("Cant get that much memory.\n") ; break ; case'k':vprints("kurrent address = ? "); kurrent = (long)getadr(); out_loc(base_p,kurrent,0); break ; case'b':vprints( "base_p address = ? "); base_p=(char *)getadr(); out_loc(base_p,kurrent,0); break; case'n':vprints("File name = ? "); jgets(&filnam[0],FILE_LN) ; name_p = &filnam[0] ; break ; case'e':prints( "Exiting Monitor.\n" ); exit(0); break; case'g':vprints("Goto where ? " ); kurrent = get8h() ; prints("\nNot available: Goto "); /* C wont allow a changeable goto (exept by using machine dependant self modifying code). */ out_loc(base_p,kurrent,0); break ; case'x':prints( "Call where ? " ); kurrent = get8h() ; vprints( "Calling"); out_loc(base_p,kurrent,0); procptr = base_p + kurrent ; (*procptr)(); break; case'.':/* Access at same address, (useful if you have just changed modes, or wish to repeatedly access a port) */ present(base_p,kurrent,0) ; break; case'+':/* advance & display */ present(base_p,kurrent,1); break; case'-':/* back & display */ present(base_p,kurrent,-1); break; case'!':prints( "SWI set at " ); out_loc(base_p,kurrent,0); #ifdef CPM #define BREAKPOINT 0xF2 #endif #ifdef MSDOS #define BREAKPOINT 0 /* JJ look up correct value later */ #endif #ifdef ns32000 #define BREAKPOINT 0xF2 #endif #if ( defined i386 || defined __FreeBSD__ /* allow for FreeBSD amd64 */ ) /* Find std includes with: cp /dev/null ~/tmp/tmp.c ; cc -E -dM ~/tmp/tmp.c */ #define BREAKPOINT 0 /* JJ look up correct value later */ #endif /* set as appropriate for machine & remember to type cast for the correct size */ *(kurrent + base_p) = BREAKPOINT; break; /* Processor status */ case'p':my_error( "Processor Status Not Implemented\n"); /* use #ASM, do a SWI (Software Interrupt), then do a stack unwind */ break; case'd': /* a block of text or string */ vprints( "Display"); if (size != STRING) { tmp_l = kurrent ; prints(": LENGTH ? "); length = get8h() ; if (length < 0) { my_error("Negatives not allowed\n"); break ; } if (size == WORD) length *= 2 ; if (size == LONG) length *= 4 ; stop_p = base_p + kurrent + length ; count1 = 0 ; /* count of items on line */ while ((kurrent + base_p < stop_p) && !( intrupt)) { if (!count1) out_loc(base_p,kurrent,1) ; if (size == BYTE) { #define DISP_LEN 0x10 count1 = DISP_LEN; while (count1) { if (!((base_p != (char *)0) && (ascii) && ((count1%4) || (count1 == DISP_LEN) ))) putjch(' '); #define stop stop_p /* JJ probably the same, havent got time to read code now */ if (kurrent + base_p <= stop) put2h(*(kurrent + base_p)); else /* space out to start position for ascii */ vprints(" \040"); count1--; } /* now print ascii equivalent of the previous hex */ if ( ascii) { putjch(' '); count1 = DISP_LEN ; while(count1 && (kurrent + base_p <= stop)) { if (isletter(*(kurrent + base_p))) putjch(*(kurrent + base_p)); else putjch('.'); kurrent++ ; count1-- ; /* if (count1 == 8) putjch(' '); */ } } } else if ( size == WORD) { if (!count1) count1 = 0x8 ; out4h(*(int *)(kurrent + base_p)); kurrent += 2 ; count1--; } else if ( size == LONG ) { if (!count1) count1 = 0x4; out8h(*(long *)(kurrent + base_p)) ; /* JJ curved open bracket before kurrent added 03.06.2000 */ kurrent += 4; count1--; } } kurrent = tmp_l ; } else /* (size == STRING) */ { /* monitor ends at null after displaying */ while (!intrupt && (chint = *(kurrent++ + base_p)) ) /* JJ '+' added to left of base_p 03.06.2000 */ if (isletter((char)chint)) putjch((char)chint); vprints("\nSTART WAS"); /* where string ends */ outadr((x32bit)mem_p); } vputjch('\n') ; break; case')':prints( "Dump Text\n" ); if (!out_open()) goto warms; while (!intrupt) { chint = *(kurrent++ + base_p); if (chint) vputjch(chint); else break; } fclose(chan) ; dump = 0; vputjch('\n'); break; case'(':prints( "Loading Text\n" ); if (!in_open(base_p,kurrent)) goto warms; while(!intrupt && (chint = getjch() ) != EOF) *(kurrent++ + base_p) = chint; *(kurrent + base_p) = '\0'; /* note we do add a null here, unlike elsewhere, where we are merely patching strings */ fclose(chan); load = 0; vputjch('\n'); break; case'>':prints( "Dump Object : Stop Address ? " ); prints(": LENGTH ? "); length = get8h() ; if (length < 0) { my_error("Negatives not allowed\n"); break ; } #define tmp tmp_l /* JJ probably the same, havent got time to read code now */ tmp = kurrent ; if (!out_open()) goto warms; count1 = 0 ; /* count of binary data bytes */ stop = base_p + kurrent + length ; while ((kurrent + base_p <= stop) && !intrupt) { if (count1 == 0) { putjch(':'); cksum = 0 ; #define OBJ_OUT 0xf /* presumably bytes in an intel hex dump */ /* max spec allows is 0x20 */ if (stop - (kurrent + base_p) < OBJ_OUT) put2h((x8bit)(stop - (kurrent + base_p) + 1 ) & 0xFF) ; else put2h((x8bit)OBJ_OUT); put4h((u16bit)kurrent); /* Address of start of record (spec is 16 bit address) */ put2h((x8bit)0); /* record type : data*/ } put2h(*(kurrent + base_p) ); count1++ ; if ((count1 == OBJ_OUT) || #define base base_p /* JJ probably the same, havent got time to read code now */ ((kurrent + base) == stop)) { cksum = ~cksum + 1 ; put2h(cksum & 0xFF); putjch('\r'); putjch('\n'); count1 =0; } kurrent++ ; } /* append an EOF record */ putjch(':'); cksum = 0; put2h(0); put4h((x16bit)base_p); put2h(1); /* record type = data */ cksum = ~cksum + 1 ; put2h(cksum) ; putjch('\r'); putjch('\n'); fclose(chan) ; dump = 0; kurrent = tmp; /* restore 'kurrent' */ break; case'<':prints( "Loading Object\n" ); /* exit by giving a non data record type ( != 0 ). * slight bug : if a checksum my_error occurs, * data record is written to ram regardless, * checksum my_error is not detected until end of line */ tmp = kurrent ; eof_flg = 0; if (!in_open(base_p,kurrent)) goto warms; while(!eof_flg && !intrupt) { /* get beginning of record delimiter */ while((chint = getjch() ) != ':') if ( chint == EOF ) { prints("End of file."); load = 0; fclose(chan); goto warms; } cksum = 0 ; count1 = take2h(); /* get data byte count */ #define OBJ_IN 0x20 /* max allowed by mostek definition */ if(count1 > OBJ_IN && count1 != 0) { my_error("Bad Count"); break; } /* get record start address */ kurrent = take2h() ; kurrent <<= 8 ; #define data data_union /* JJ probably the same, havent got time to read code now */ data.s4 = take2h() ; kurrent |= data.s4 ; if ((load_tmp = take2h()) == 1) eof_flg = 1 ; /* load ram with data */ while (count1--) *(kurrent++ + base_p) = take2h(); /* calculate checksum from data */ data.s1 = ~cksum +1 ; /* compare with checksum from record */ if ( data.s1 != take2h()) { my_error("Bad Checksum"); break; } } /* have we received an EOF record ? */ if (!eof_flg) my_error("No EOF Record."); else { vprints("\nTHE EOF ADDRESS WAS "); putadr((x32bit)load_tmp); putjch('\n'); /* note cannot output this number earlier as it would corrupt checksum */ } fclose(chan); load = 0; kurrent = tmp ; break; case'f':vprints("Fill : "); prints("Length, "); length = get8h(); if (length < 0) { my_error("Negatives not allowed\n"); break ; } tmp_l = kurrent ; if (size != STRING) stop = length + kurrent + base_p ; else { while (*(kurrent++ + base_p)) ; stop = kurrent + base_p - 1 ; /* dont include nul */ } vprints("Data : "); if (( size == BYTE) || ( size== STRING )) { data_union.s1 = get2h(); while(( kurrent + base_p <= stop) && !intj()) { *(kurrent + base_p) = data_union.s1; kurrent++ ; } } else if ( size == WORD) /* Note the byte beyond 'stop' may be affected*/ { data_union.s2 = get4h(); while(( kurrent + base_p <= stop) && !intj()) { *(int *)(kurrent + base_p) = data_union.s2; kurrent += 2; } } else if (size == LONG ) { /* Note up to 3 bytes beyond 'stop' may be affected */ data_union.s4 = get8h(); while(( kurrent + base_p <= stop) && !intj()) { *(long *)(kurrent + base_p) = data_union.s4 ; kurrent += 4; } } break; case'/':prints( "Search : Data ? " ); #define TOP 0x1000000 /* NS 16000 is 24 bit address, not 32 so cut short the search */ if ( size == BYTE) { data_union.s1 = get2h(); do { if (*(kurrent + base_p) == data_union.s1) { vprints( "Search succeeded"); break ; } } while ( (kurrent++ + base_p != (char *)TOP) && !intj()); vprints( "Search failed"); break ; } else if ( size == WORD) { data_union.s2 = get4h(); do { if (*((int *)(kurrent + base_p)) == data_union.s2) { vprints( "Search succeeded"); break ; } } while ( ((kurrent +=2) + base_p < (char *)TOP -1) && !intj()); vprints( "Search failed"); break ; } else if ( size == LONG) { data_union.s4 = get8h(); do { if (*((int *)(kurrent + base_p)) == data_union.s4) { vprints( "Search succeeded"); break ; } } while ( ((kurrent += 3) + base_p < (char *)TOP -1) && !intj()); vprints( "Search failed"); break ; } else /* String */ { jgets(findstr,FINDSTR); prints(" LOOKING FOR \'"); prints(findstr); putjch('\''); do { if ( *(kurrent + base_p) == *findstr) { for (mem_p = findstr + 1 , stop = kurrent + base_p + 1; *(char *)stop == *(char *)mem_p && *(char *)stop != '\0' ;) { stop++ ; if (stop == (char *)TOP) stop = 0; mem_p++ ; } if (*(char *)mem_p == '\0' ) break ; } kurrent + base_p++ ; if (kurrent + base_p == (char *)TOP) kurrent = 0; } while ( kurrent + base_p != dest && !intj()) ; } if (kurrent + base_p == dest) { my_error("Not found.\n"); kurrent = tmp ; } out_loc(base_p,kurrent,0); vputjch('\n'); break; case't':vprints("Test RAM: up to ? "); /* Algorithm enhanced from an article by * Edward J Milner, NASA * Lewis Research Center, * Published Electronic Design News * October 13th 1983. * Synopsis of article : * slide a 1 thru succesive incrementing bytes, * ( having initialised block to 0 ) * 1 dec 0 * 1 inc FF * 1 dec FF * repeat all previous 8 times, shifting start * bit one bit each time, * repeat all with a sliding 0 instead of a 1. * Thus the first test is : Sliding one, Zero initial, * Incrementing addresses, rotate a bit to the left * through succesive bytes in the block, * first testing each byte to see if * a previous cycle of the loop (to * access a lower address) has also erroneously * set the contents of the current address */ dest = (char *)kurrent; stop = getadr(); /* insert code here to generate data for 'tstrfrsh' */ prints("Number of laps (0=infinite) ? "); count1 = get2h(); forever = (count1 != 0) ? 0 : 1 ; while (count1 || forever) { count1--; /* First a sliding 1 test, then a sliding 0 */ for (bits1=1; ; bits1 = ~1) { /*For each of the 8 bits within a byte*/ for (bits2 = bits1, count2 = 0; count2 < 8 ; bits2 = rolb(bits2), count2++) { /* first initialise block low, then high */ for (init0F = 0; ; init0F = 0xFF) { /* Sweep block first incrementing addresses, then decrementing */ for (validir = 1; ; validir = -1) { if (verbose) { putchar('\n'); putadr((x32bit) (dest+(long)base_p)); putchar(':'); putadr((x32bit) (stop+(long)base_p)); if (forever) prints(" FOREVER"); else { prints(" LAP="); put2h(count1); } prints(", sliding "); if (bits1 == 1) putchar('1'); else putchar('0'); prints(", bit "); putchar('0'+count2); prints(", block start "); if(!init0F) prints("00"); else prints("FF"); prints(", sweep "); if (validir == 1) putchar('+'); else putchar('-'); } /* initialise block */ if (!initblk( base_p,kurrent,init0F) ) goto warms; /* set bit pattern in block */ for ( bits3 = bits2, kurrent = (long)dest; (char *)kurrent <= stop; bits3 = rolb(bits3), kurrent++) { if (intj()) goto warms; /* JJ Pre 03.06.2000 there was this code: kurrent + base_p = kurrent + base_p ; as that is rubbish Ive crudely hashed it out, but need to read & restore code !! */ if (*(x8more *)(kurrent + base_p) != init0F) { shorterr(base_p,kurrent,validir ,init0F); goto warms; } *(x8more *)(kurrent + base_p) = bits3 ; } /* check bit pattern in block */ if (validir == 1) { if (!chec_blok(base_p,kurrent,1,bits2)) goto warms; } else { if (!chec_blok(base_p,kurrent,-1, rorb(bits3))) goto warms; } if (validir != 1) break ; } if (init0F != 0) break ; } } if (bits1 != 1) break ; } } kurrent = (long)dest ; putchar('\n'); break; case'c':vprints("Copy: "); if (size != STRING) /* JJ 03.06.2000 upto() ; upto() */ { prints("Up to, "); } prints("destination = ? "); if (size != STRING) /* get top of source block */ { stop = getadr(); stop = stop + (long)base_p; } dest = getadr() ; /* get base_p of destination */ dest = dest + (long)base_p; /* now process */ if ((size == WORD) && (((long)stop - (long)kurrent + (long)base_p) % 2 ) || (size == LONG) && (((long)stop - (long)kurrent + (long)base_p) % 4)) { my_error( "Length quantisation" ); break ; } if (size == STRING ) { /* set 'stop' so we can treat it as a block */ stop = kurrent + base_p; while (*(char *)stop++) ; /* note the null will be copied */ } else if (size == WORD) stop++ ; /* note we will be copying the byte above 'stop' as well. */ else if (size == LONG) stop += 3 ; /* ditto 3 bytes */ if (stop < kurrent + base_p) { mem_p = kurrent + base_p ; /* JJ pre 03.06.2000 Madness needs to be fixed kurrent + base_p = stop ; */ stop = mem_p ; } /* Now do the copy, note this has not been written to copy through zero */ if (dest < kurrent + base_p) { do { dest = kurrent + base_p; dest++ ; kurrent + base_p++ ; } while ( kurrent + base_p <= stop ) ; } else { dest += (long)stop - (long)kurrent + (long)base_p ; do { *(char *)dest = *(char *)stop ; stop-- ; dest-- ; } while ( stop >= kurrent + base_p ) ; } break; case'?': prints("\n"); prints("Set Address : K Current B Base / Search\n"); prints("Set R/W : R Read W Write M Modify=R+W\n"); prints("Set Size : 1 Byte 2 Word 4 Double \" Text\n"); prints("Set Mode : \' Ascii H Hex V Verbose Q Quiet\n"); prints("Entity Access: + Next . Same - Previous ! SWI Set\n"); prints("Block Access : D Display C Copy F Fill T Test\n"); prints("File Access : N Name > Dump Obj < Load Obj ) Dump Text ( Load Text\n"); prints("Status Print : S Monitor P Processor\n"); prints("Memory Adjust: A Alloc()\n"); prints("Control : E Exit ^B Interrupt 0 Restart X Execute G Goto\n\n"); status(base_p,kurrent); break; default:my_error("BAD COMMAND, TRY \'?\'\n"); break; } } }