1 ; PAULMON2, a user-friendly 8051 monitor, by Paul Stoffregen
\r
2 ; Please email comments, suggestions, bugs to paul@pjrc.com
\r
4 ; It's free. PAULMON2 is in the public domain. You may copy
\r
5 ; sections of code from PAULMON2 into your own programs, even
\r
6 ; for commercial purposes. PAULMON2 should only be distributed
\r
7 ; free of charge, but may be bundled as 'value-added' with other
\r
8 ; products, such as development boards, CDROMs, etc. Please
\r
9 ; distribute the PAULMON2.DOC file and other files, not just
\r
12 ; The PAULMON2.EQU and PAULMON2.HDR files contain valuable
\r
13 ; information that could help you to write programs for use
\r
16 ; PAULMON2 is in the public domain. PAULMON2 is distributed in
\r
17 ; the hope that it will be useful, but without any warranty;
\r
18 ; without even the implied warranty of merchantability or fitness
\r
19 ; for a particular purpose.
\r
22 ; You are probably reading this code to see what it looks like
\r
23 ; and possibly learn something, or to modify it for some reason.
\r
24 ; Either is ok, but please remember that this code uses a number
\r
25 ; of tricks to cram all the functionality into just 4k. As a
\r
26 ; result, the code can be difficult to read, and adding new
\r
27 ; features can be very difficult without growing beyond 4k. To
\r
28 ; add or modify commands in PAULMON2, please consider using the
\r
29 ; "external command" functionality. It is easier to develop
\r
30 ; new commands this way, and you can distribute them to other
\r
31 ; users. Email paul@pjrc.com if you have new PAULMON2
\r
32 ; commands to contribute to others. Details about adding new
\r
33 ; commands to PAULMON2 (with examples) can be found at:
\r
35 ; http://www.pjrc.com/tech/8051/pm2_docs/addons.html
\r
38 ;---------------------------------------------------------;
\r
40 ; PAULMON2's default configuration ;
\r
42 ;---------------------------------------------------------;
\r
44 ; PAULMON2 should be assembled using the modified AS31 assembler,
\r
45 ; originally written by Ken Stauffer, many small changes by Paul
\r
46 ; Stoffregen. This free assembler is available on the web at
\r
47 ; http://www.pjrc.com/tech/8051/index.html
\r
48 ; As well, these web pages have a fill-out form which makes it
\r
49 ; very easy to custom configure PAULMON2. Using this form will
\r
50 ; edit the code for you, run the AS31 assmebler, and send you the
\r
51 ; object code to program into your chip.
\r
54 ; These two parameters control where PAULMON2 will be assembled,
\r
55 ; and where it will attempt to LJMP at the interrupt vector locations.
\r
57 .equ base, 0x0000 ;location for PAULMON2
\r
58 .equ vector, 0x2000 ;location to LJMP interrupt vectors
\r
60 ; These three parameters tell PAULMON2 where the user's memory is
\r
61 ; installed. "bmem" and "emem" define the space that will be searched
\r
62 ; for program headers, user installed commands, start-up programs, etc.
\r
63 ; "bmem" and "emem" should be use so they exclude memory areas where
\r
64 ; perphreal devices may be mapped, as reading memory from an io chip
\r
65 ; may reconfigure it unexpectedly. If flash rom is used, "bmem" and "emem"
\r
66 ; should also include the space where the flash rom is mapped.
\r
68 .equ pgm, 0x2000 ;default location for the user program
\r
69 .equ bmem, 0x1000 ;where is the beginning of memory
\r
70 .equ emem, 0xFFFF ;end of the memory
\r
72 ; Flash ROM parameters. If "has_flash" is set to zero, all flash rom
\r
73 ; features are turned off, otherwise "bflash" and "eflash" should specify
\r
74 ; the memory range which is flash rom. Though AMD doesn't suggest it,
\r
75 ; you may be able to map only a part of the flash rom with your address
\r
76 ; decoder logic (and not use the rest), but you should be careful that
\r
77 ; "bflash" and "eflash" don't include and memory which is NOT flash rom
\r
78 ; so that the erase algorithm won't keep applying erase pulses until it
\r
79 ; finally gives up (which will stress the thin oxide and degrade the
\r
80 ; flash rom's life and reliability). "erase_pin" allows you to specify
\r
81 ; the bit address for a pin which (if held low) will tell PAULMON2 to
\r
82 ; erase the flash rom chip when it starts up. This is useful if you
\r
83 ; download programs with the "start-up" headers on them and the code you've
\r
84 ; put in the flash rom crashes!
\r
86 .equ has_flash, 0 ;set to non-zero value if flash installed
\r
87 .equ bflash, 0x8000 ;first memory location of Flash ROM
\r
88 .equ eflash, 0xFFFF ;last memory location of Flash ROM
\r
89 .equ erase_pin, 0 ;00 = disable erase pin feature
\r
90 ;.equ erase_pin, 0xB5 ;B5 = pin 15, P3.5 (T1)
\r
92 ; Please note... much of the memory management code only looks at the
\r
93 ; upper 8 bits of an address, so it's not a good idea to somehow map
\r
94 ; your memory chips (with complex address decoding logic) into chunks
\r
95 ; less than 256 bytes. In other words, only using a piece of a flash
\r
96 ; rom chip and mapping it between C43A to F91B would confuse PAULMON2
\r
97 ; (as well as require quit a bit of address decoding logic circuitry)
\r
100 ; To set the baud rate, use this formula or set to 0 for auto detection
\r
101 ; baud_const = 256 - (crystal / (12 * 16 * baud))
\r
103 .equ baud_const, 0 ;automatic baud rate detection
\r
104 ;.equ baud_const, 255 ;57600 baud w/ 11.0592 MHz
\r
105 ;.equ baud_const, 253 ;19200 baud w/ 11.0592 MHz
\r
106 ;.equ baud_const, 252 ;19200 baud w/ 14.7456 MHz
\r
107 ;.equ baud_const, 243 ;4808 baud w/ 12 MHz
\r
109 .equ line_delay, 6 ;num of char times to pause during uploads
\r
111 ; About download speed: when writing to ram, PAULMON2 can accept data
\r
112 ; at the maximum baud rate (baud_const=255 or 57600 baud w/ 11.0592 MHz).
\r
113 ; Most terminal emulation programs introduce intentional delays when
\r
114 ; sending ascii data, which you would want to turn off for downloading
\r
115 ; larger programs into ram. For Flash ROM, the maximum speed is set by
\r
116 ; the time it takes to program each location... 9600 baud seems to work
\r
117 ; nicely for the AMD 28F256 chip. The "character pacing" delay in a
\r
118 ; terminal emulation program should be sufficient to download to flash
\r
119 ; rom and any baud rate. Some flash rom chips can write very quickly,
\r
120 ; allowing high speed baud rates, but other chips can not. You milage
\r
124 ; Several people didn't like the key definations in PAULMON1.
\r
125 ; Actually, I didn't like 'em either, but I never took the time
\r
126 ; to change it. Eventually I got used to them, but now it's
\r
127 ; really easy to change which keys do what in PAULMON2. You
\r
128 ; can guess what to do below, but don't use lowercase.
\r
130 .equ help_key, '?' ;help screen
\r
131 .equ dir_key, 'M' ;directory
\r
132 .equ run_key, 'R' ;run program
\r
133 .equ dnld_key, 'D' ;download
\r
134 .equ upld_key, 'U' ;upload
\r
135 .equ nloc_key, 'N' ;new memory location
\r
136 .equ jump_key, 'J' ;jump to memory location
\r
137 .equ dump_key, 'H' ;hex dump memory
\r
138 .equ intm_key, 'I' ;hex dump internal memory
\r
139 .equ edit_key, 'E' ;edit memory
\r
140 .equ clrm_key, 'C' ;clear memory
\r
141 .equ erfr_key, 'Z' ;erase flash rom
\r
143 ; timing parameters for AMD Flash ROM 28F256. These parameters
\r
144 ; and pretty conservative and they seem to work with crystals
\r
145 ; between 6 MHz to 24 MHz... (tested with AMD 28F256 chips only)
\r
146 ; unless you know this is a problem, it is probably not a good
\r
147 ; idea to fiddle with these.
\r
149 ;.equ pgmwait, 10 ;22.1184 MHz crystal assumed
\r
150 .equ pgmwait, 19 ;11.0592 MHz
\r
152 ;.equ erwait1, 40 ;fourty delays @22.1184
\r
153 .equ erwait1, 20 ;twenty delays for 11.0592 MHz
\r
154 .equ erwait2, 229 ;each delay .5 ms @22.1184MHz
\r
158 ; These symbols configure paulmon2's internal memory usage.
\r
159 ; It is usually not a good idea to change these unless you
\r
160 ; know that you really have to.
\r
162 .equ psw_init, 0 ;value for psw (which reg bank to use)
\r
163 .equ dnld_parm, 0x10 ;block of 16 bytes for download
\r
164 .equ stack, 0x30 ;location of the stack
\r
165 .equ baud_save, 0x78 ;save baud for warm boot, 4 bytes
\r
167 ;---------------------------------------------------------;
\r
169 ; Interrupt Vectors ;
\r
170 ; (and little bits of code crammed in the empty spaces) ;
\r
172 ;---------------------------------------------------------;
\r
175 ljmp poweron ;reset vector
\r
178 ljmp vector+3 ;ext int0 vector
\r
186 ljmp vector+11 ;timer0 vector
\r
194 ljmp vector+19 ;ext int1 vector
\r
196 dash: mov a, #'-' ;seems kinda trivial, but each time
\r
197 ajmp cout ;this appears in code, it takes 4
\r
198 nop ;bytes, but an acall takes only 2
\r
201 ljmp vector+27 ;timer1 vector
\r
208 ljmp vector+35 ;uart vector
\r
215 ljmp vector+43 ;timer2 vector (8052)
\r
218 ;---------------------------------------------------------;
\r
220 ; The jump table for user programs to call ;
\r
221 ; subroutines within PAULMON ;
\r
223 ;---------------------------------------------------------;
\r
225 .org base+46 ;never change this line!! Other
\r
226 ;programs depend on these locations
\r
227 ;to access paulmon2 functions
\r
240 pcstr_h:ljmp pcstr ;45
\r
251 ljmp cin_filter ;62
\r
255 ;---------------------------------------------------------;
\r
257 ; Subroutines for serial I/O ;
\r
259 ;---------------------------------------------------------;
\r
267 dspace: acall space
\r
270 clr ti ;clr ti before the mov to sbuf!
\r
274 ;clearing ti before reading sbuf takes care of the case where
\r
275 ;interrupts may be enabled... if an interrupt were to happen
\r
276 ;between those two instructions, the serial port will just
\r
277 ;wait a while, but in the other order and the character could
\r
278 ;finish transmitting (during the interrupt routine) and then
\r
279 ;ti would be cleared and never set again by the hardware, causing
\r
280 ;the next call to cout to hang forever!
\r
282 newline2: ;print two newlines
\r
284 newline:push acc ;print one newline
\r
292 ;get 2 digit hex number from serial port
\r
293 ; c = set if ESC pressed, clear otherwise
\r
294 ; psw.5 = set if return w/ no input, clear otherwise
\r
298 acall cin_filter_h ;get first digit
\r
300 cjne a, #27, ghex8f
\r
304 ghex8f: cjne a, #13, ghex8h
\r
312 xch a, r2 ;r2 will hold hex value of 1st digit
\r
315 acall cin_filter_h ;get second digit
\r
317 cjne a, #27, ghex8k
\r
319 ghex8k: cjne a, #13, ghex8m
\r
323 ghex8m: cjne a, #8, ghex8p
\r
326 ghex8p: cjne a, #21, ghex8q
\r
342 ;carry set if esc pressed
\r
343 ;psw.5 set if return pressed w/ no input
\r
345 mov r2, #0 ;start out with 0
\r
347 mov r4, #4 ;number of digits left
\r
353 cjne a, #27, ghex16d
\r
354 setb c ;handle esc key
\r
359 ghex16d:cjne a, #8, ghex16f
\r
361 ghex16f:cjne a, #127, ghex16g ;handle backspace
\r
362 ghex16k:cjne r4, #4, ghex16e ;have they entered anything yet?
\r
368 ghex16g:cjne a, #13, ghex16i ;return key
\r
371 cjne r4, #4, ghex16h
\r
378 ghex16i:mov r5, a ;keep copy of original keystroke
\r
398 ghex16x: ;multiply r3-r2 by 16 (shift left by 4)
\r
414 ghex16y: ;divide r3-r2 by 16 (shift right by 4)
\r
431 ;carry set if invalid input
\r
486 ;a not so well documented feature of pstr is that you can print
\r
487 ;multiple consecutive strings without needing to reload dptr
\r
488 ;(which takes 3 bytes of code!)... this is useful for inserting
\r
489 ;numbers or spaces between strings.
\r
505 upper: ;converts the ascii code in Acc to uppercase, if it is lowercase
\r
509 jc upper2 ;is it a lowercase character
\r
513 add a, #224 ;convert to uppercase
\r
515 upper2: pop acc ;don't change anything
\r
519 lenstr: mov r0, #0 ;returns length of a string in r0
\r
533 esc: ;checks to see if <ESC> is waiting on serial port
\r
534 ;C=clear if no <ESC>, C=set if <ESC> pressed
\r
547 ;---------------------------------------------------------;
\r
549 ; The 'high-level' stuff to interact with the user ;
\r
551 ;---------------------------------------------------------;
\r
554 menu: ;first we print out the prompt, which isn't as simple
\r
555 ;as it may seem, since external code can add to the
\r
556 ;prompt, so we've got to find and execute all of 'em.
\r
557 mov dptr, #prompt1 ;give 'em the first part of prompt
\r
563 ;mov dptr, #prompt2
\r
566 ;now we're finally past the prompt, so let's get some input
\r
567 acall cin_filter_h ;get the input, finally
\r
570 ;push return address onto stack so we can just jump to the program
\r
571 mov b, #(menu & 255) ;we push the return address now,
\r
572 push b ;to save code later...
\r
573 mov b, #(menu >> 8) ;if bogus input, just ret for
\r
574 push b ;another prompt.
\r
578 ;first we'll look through memory for a program header that says
\r
579 ;it's a user installed command which matches what the user pressed
\r
581 ;user installed commands need to avoid changing R6/R7, which holds
\r
582 ;the memory pointer. The stack pointer can't be changed obviously.
\r
583 ;all the other general purpose registers should be available for
\r
584 ;user commands to alter as they wish.
\r
586 menux: mov b, a ;now search for external commands...
\r
589 jnc menuxend ;searched all the commands?
\r
593 cjne a, #254, menux2 ;only FE is an ext command
\r
597 cjne a, b, menux2 ;only run if they want it
\r
600 acall pstr ;print command name
\r
604 jmp @a+dptr ;take a leap of faith and jump to it!
\r
607 cjne a, #((emem+1) >> 8) & 255, menux1
\r
612 ;since we didn't find a user installed command, use the builtin ones
\r
614 menu1a: cjne a, #help_key, menu1b
\r
615 mov dptr, #help_cmd2
\r
618 menu1b: cjne a, #dir_key, menu1c
\r
622 menu1c: cjne a, #run_key, menu1d
\r
626 menu1d: cjne a, #dnld_key, menu1e
\r
627 mov dptr, #dnld_cmd
\r
630 menu1e: cjne a, #upld_key, menu1f
\r
631 mov dptr, #upld_cmd
\r
634 menu1f: cjne a, #nloc_key, menu1g
\r
635 mov dptr, #nloc_cmd
\r
638 menu1g: cjne a, #jump_key, menu1h
\r
639 mov dptr, #jump_cmd
\r
642 menu1h: cjne a, #dump_key, menu1i
\r
643 mov dptr, #dump_cmd
\r
646 menu1i: cjne a, #edit_key, menu1j
\r
647 mov dptr, #edit_cmd
\r
650 menu1j: cjne a, #clrm_key, menu1k
\r
651 mov dptr, #clrm_cmd
\r
654 menu1k: cjne a, #erfr_key, menu1l
\r
657 mov dptr, #erfr_cmd
\r
660 menu1l: cjne a, #intm_key, menu1m
\r
661 mov dptr, #intm_cmd
\r
666 ;invalid input, no commands to run...
\r
667 menu_end: ;at this point, we have not found
\r
668 ajmp newline ;anything to run, so we give up.
\r
669 ;remember, we pushed menu, so newline
\r
670 ;will just return to menu.
\r
672 ;..........................................................
\r
674 ;---------------------------------------------------------;
\r
676 ;dnlds1 = "Begin sending Intel HEX format file <ESC> to abort"
\r
677 ;dnlds2 = "Download aborted"
\r
678 ;dnlds3 = "Download completed"
\r
681 ;16 byte parameter table: (eight 16 bit values)
\r
682 ; * 0 = lines received
\r
683 ; * 1 = bytes received
\r
684 ; * 2 = bytes written
\r
685 ; * 3 = bytes unable to write
\r
686 ; * 4 = incorrect checksums
\r
687 ; * 5 = unexpected begin of line
\r
688 ; * 6 = unexpected hex digits (while waiting for bol)
\r
689 ; * 7 = unexpected non-hex digits (in middle of a line)
\r
693 acall pcstr_h ;"begin sending file <ESC> to abort"
\r
696 dnld0: mov @r0, #0 ;initialize all parameters to 0
\r
700 ;look for begining of line marker ':'
\r
702 cjne a, #27, dnld2 ;Test for escape
\r
704 dnld2: cjne a, #':', dnld2b
\r
708 dnld2b: ;check to see if it's a hex digit, error if it is
\r
714 ;begin taking in the line of data
\r
717 mov r4, #0 ;r4 will count up checksum
\r
719 mov r0, a ;R0 = # of data bytes
\r
721 mov dph, a ;High byte of load address
\r
723 mov dpl, a ;Low byte of load address
\r
724 acall dnld_ghex ;Record type
\r
725 cjne a, #1, dnld4 ;End record?
\r
727 dnld4: jnz dnld_unknown ;is it a unknown record type???
\r
730 acall dnld_ghex ;Get data byte
\r
733 acall dnld_inc ;count total data bytes received
\r
735 lcall smart_wr ;c=1 if an error writing
\r
739 ; 2 = bytes written
\r
740 ; 3 = bytes unable to write
\r
745 acall dnld_ghex ;get checksum
\r
747 jz dnld1 ;should always add to zero
\r
750 acall dnld_inc ;all we can do it count # of cksum errors
\r
753 dnld_unknown: ;handle unknown line type
\r
755 jz dnld_get_cksum ;skip data if size is zero
\r
757 acall dnld_ghex ;consume all of unknown data
\r
759 sjmp dnld_get_cksum
\r
761 dnld_end: ;handles the proper end-of-download marker
\r
763 jz dnld_end_3 ;should usually be zero
\r
765 acall dnld_ghex ;consume all of useless data
\r
768 acall dnld_ghex ;get the last checksum
\r
773 acall pcstr_h ;"download went ok..."
\r
774 ;consume any cr or lf character that may have been
\r
775 ;on the end of the last line
\r
782 dnld_esc: ;handle esc received in the download stream
\r
785 acall pcstr_h ;"download aborted."
\r
788 dnld_dly: ;a short delay since most terminal emulation programs
\r
789 ;won't be ready to receive anything immediately after
\r
790 ;they've transmitted a file... even on a fast Pentium(tm)
\r
791 ;machine with 16550 uarts!
\r
793 dnlddly2:mov r1, #0
\r
794 djnz r1, * ;roughly 128k cycles, appox 0.1 sec
\r
798 dnld_inc: ;increment parameter specified by R1
\r
799 ;note, values in Acc and R1 are destroyed
\r
801 anl a, #00000111b ;just in case
\r
804 mov r1, a ;now r1 points to lsb
\r
812 dnld_gp: ;get parameter, and inc to next one (@r1)
\r
813 ;carry clear if parameter is zero.
\r
814 ;16 bit value returned in dptr
\r
829 ;a spacial version of ghex just for the download. Does not
\r
830 ;look for carriage return or backspace. Handles ESC key by
\r
831 ;poping the return address (I know, nasty, but it saves many
\r
832 ;bytes of code in this 4k ROM) and then jumps to the esc
\r
833 ;key handling. This ghex doesn't echo characters, and if it
\r
834 ;sees ':', it pops the return and jumps to an error handler
\r
835 ;for ':' in the middle of a line. Non-hex digits also jump
\r
836 ;to error handlers, depending on which digit.
\r
841 cjne a, #27, dnldgh3
\r
845 dnldgh3:cjne a, #':', dnldgh5
\r
846 dnldgh4:mov r1, #5 ;handle unexpected beginning of line
\r
850 ajmp dnld3 ;and now we're on a new line!
\r
851 dnldgh5:acall asc2hex
\r
856 dnldgh6:mov r2, a ;keep first digit in r2
\r
859 cjne a, #27, dnldgh8
\r
861 dnldgh8:cjne a, #':', dnldgh9
\r
863 dnldgh9:acall asc2hex
\r
872 add a, r4 ;add into checksum
\r
874 mov a, r2 ;return value in acc
\r
877 ;dnlds4 = "Summary:"
\r
878 ;dnlds5 = " lines received"
\r
879 ;dnlds6a = " bytes received"
\r
880 ;dnlds6b = " bytes written"
\r
882 dnld_sum: ;print out download summary
\r
890 mov r6, #dnlds5 & 255
\r
891 mov r7, #dnlds5 >> 8
\r
893 mov r6, #dnlds6a & 255
\r
894 mov r7, #dnlds6a >> 8
\r
896 mov r6, #dnlds6b & 255
\r
897 mov r7, #dnlds6b >> 8
\r
900 dnld_err: ;now print out error summary
\r
902 dnlder2:acall dnld_gp
\r
903 jc dnlder3 ;any errors?
\r
905 ;no errors, so we print the nice message
\r
910 dnlder3: ;there were errors, so now we print 'em
\r
913 ;but let's not be nasty... only print if necessary
\r
914 mov r1, #(dnld_parm+6)
\r
915 mov r6, #dnlds8 & 255
\r
916 mov r7, #dnlds8 >> 8
\r
918 mov r6, #dnlds9 & 255
\r
919 mov r7, #dnlds9 >> 8
\r
921 mov r6, #dnlds10 & 255
\r
922 mov r7, #dnlds10 >> 8
\r
924 mov r6, #dnlds11 & 255
\r
925 mov r7, #dnlds11 >> 8
\r
927 mov r6, #dnlds12 & 255
\r
928 mov r7, #dnlds12 >> 8
\r
938 acall dnld_gp ;error conditions
\r
940 dnld_i2:acall space
\r
946 dnld_i0:acall dnld_gp ;non-error conditions
\r
950 ;dnlds7: = "Errors:"
\r
951 ;dnlds8: = " bytes unable to write"
\r
952 ;dnlds9: = " incorrect checksums"
\r
953 ;dnlds10: = " unexpected begin of line"
\r
954 ;dnlds11: = " unexpected hex digits"
\r
955 ;dnlds12: = " unexpected non-hex digits"
\r
956 ;dnlds13: = "No errors detected"
\r
960 ;---------------------------------------------------------;
\r
976 jump3: acall newline
\r
981 jump_doit: ;jump to user code @dptr (this used by run command also)
\r
993 mov sp, #8 ;start w/ sp=7, like a real reset
\r
994 push acc ;unlike a real reset, push 0000
\r
995 push acc ;in case they end with a RET
\r
999 ;---------------------------------------------------------;
\r
1002 mov r2, #16 ;number of lines to print
\r
1004 dump1: acall r6r7todptr
\r
1005 acall phex16 ;tell 'em the memory location
\r
1008 mov r3, #16 ;r3 counts # of bytes to print
\r
1013 acall phex ;print each byte in hex
\r
1016 acall dspace ;print a couple extra space
\r
1022 anl a, #01111111b ;avoid unprintable characters
\r
1023 cjne a, #127, dump3b
\r
1024 clr a ;avoid 127/255 (delete/rubout) char
\r
1025 dump3b: add a, #224
\r
1027 clr a ;avoid control characters
\r
1036 djnz r2, dump1 ;loop back up to print next line
\r
1037 dump5: ajmp newline
\r
1039 ;---------------------------------------------------------;
\r
1041 edit: ;edit external ram...
\r
1045 edit1: acall phex16
\r
1054 mov dptr,#prompt10
\r
1066 edit2: mov dptr,#edits2
\r
1069 ;---------------------------------------------------------;
\r
1072 mov dptr, #prompt9
\r
1075 dir0a: acall space
\r
1077 ;mov dptr, #prompt9b
\r
1080 mov dph, #(bmem >> 8)
\r
1081 dir1: acall find ;find the next program in memory
\r
1083 dir_end:ajmp newline ;we're done if no more found
\r
1086 mov dpl, #32 ;print its name
\r
1088 mov dpl, #32 ;how long is the name
\r
1094 mov a, #' ' ;print the right # of spaces
\r
1098 acall phex16 ;print the memory location
\r
1103 mov dpl, #4 ;now figure out what type it is
\r
1106 mov r2, dph ;save this, we're inside a search
\r
1108 dir5: cjne a, #254, dir5b
\r
1109 mov dptr, #type1 ;it's an external command
\r
1111 dir5b: cjne a, #253, dir5c
\r
1112 dir5bb: mov dptr, #type4 ;it's a startup routine
\r
1114 dir5c: cjne a, #35, dir5d
\r
1115 mov dptr, #type2 ;it's an ordinary program
\r
1117 dir5d: cjne a, #249, dir5e
\r
1120 dir6: mov dptr, #type5 ;who knows what the hell it is
\r
1122 dir7: acall pcstr_h ;print out the type
\r
1123 mov dph, r2 ;go back and find the next one
\r
1125 mov a, #(emem >> 8)
\r
1126 cjne a, dph, dir8 ;did we just print the last one?
\r
1130 cjne a, #((emem+1) >> 8) & 255, dir1
\r
1134 ;type1=Ext Command
\r
1139 ;---------------------------------------------------------;
\r
1144 mov r2, #255 ;first print the menu, count items
\r
1149 cjne a, #((emem+1) >> 8) & 255, run2b
\r
1152 jnc run3 ;have we found 'em all??
\r
1158 jz run2 ;this one doesn't run... find next
\r
1161 mov a, #'A' ;print the key to press
\r
1166 acall pstr ;and the command name
\r
1168 ajmp run2 ;and continue doing this
\r
1169 run3: cjne r2, #255, run4 ;are there any to run??
\r
1170 mov dptr, #prompt5
\r
1172 run4: mov dptr, #prompt3 ;ask the big question!
\r
1177 mov a, #'A' ;such user friendliness...
\r
1178 add a, r2 ;even tell 'em the choices
\r
1180 mov dptr, #prompt4
\r
1182 acall cin_filter_h
\r
1183 cjne a, #27, run4aa ;they they hit <ESC>
\r
1195 ;check to see if it's under 32, if so convert to uppercase
\r
1199 jc run4 ;if they typed less than 'A'
\r
1200 mov r3, a ;R3 has the number they typed
\r
1201 mov a, r2 ;A=R2 has the maximum number
\r
1204 jc run4 ;if they typed over the max
\r
1210 cjne a, #((emem+1) >> 8) & 255, run5b
\r
1213 jnc run8 ;Shouldn't ever do this jump!
\r
1219 jz run5 ;this one doesn't run... find next
\r
1220 djnz r3, run5 ;count til we find the one they want
\r
1226 ;---------------------------------------------------------;
\r
1229 mov dptr, #help1txt
\r
1232 mov dptr, #help_cmd
\r
1235 ;mov dptr, #dir_cmd
\r
1238 ;mov dptr, #run_cmd
\r
1241 ;mov dptr, #dnld_cmd
\r
1244 ;mov dptr, #upld_cmd
\r
1247 ;mov dptr, #nloc_cmd
\r
1250 ;mov dptr, #jump_cmd
\r
1253 ;mov dptr, #dump_cmd
\r
1256 ;mov dptr, #intm_cmd
\r
1259 ;mov dptr, #edit_cmd
\r
1262 ;mov dptr, #clrm_cmd
\r
1267 ;mov dptr, #erfr_cmd
\r
1270 mov dptr, #help2txt
\r
1278 cjne a, #254, help3a ;only FE is an ext command
\r
1290 cjne a, #((emem+1) >> 8) & 255, help3
\r
1294 help2: ;print 11 standard lines
\r
1295 acall dspace ;given key in R4 and name in dptr
\r
1302 ;---------------------------------------------------------;
\r
1307 ;assume we've got the beginning address in r3/r2
\r
1308 ;and the final address in r5/r4 (r4=lsb)...
\r
1310 ;print out what we'll be doing
\r
1317 ;mov dptr, #uplds4
\r
1325 ;need to adjust end location by 1...
\r
1332 mov dptr, #prompt7
\r
1335 cjne a, #27, upld2e
\r
1337 upld2e: acall newline
\r
1341 upld3: mov a, r4 ;how many more bytes to output??
\r
1347 jnz upld4 ;if >256 left, then do next 16
\r
1349 jz upld7 ;if we're all done
\r
1351 jnz upld4 ;if >= 16 left, then do next 16
\r
1352 sjmp upld5 ;otherwise just finish it off
\r
1353 upld4: mov r2, #16
\r
1354 upld5: mov a, #':' ;begin the line
\r
1357 acall phex ;output # of data bytes
\r
1358 acall phex16 ;output memory location
\r
1362 mov r3, a ;r3 will become checksum
\r
1364 acall phex ;output 00 code for data
\r
1367 acall phex ;output each byte
\r
1371 djnz r2, upld6 ;do however many bytes we need
\r
1375 acall phex ;and finally the checksum
\r
1379 jnc upld3 ;keep working if no esc pressed
\r
1381 upld7: mov a, #':'
\r
1391 upld8: ajmp newline2
\r
1394 line_dly: ;a brief delay between line while uploading, so the
\r
1395 ;receiving host can be slow (i.e. most windows software)
\r
1398 mov r0, #line_delay*2
\r
1399 line_d2:mov a, th0 ;get baud rate const
\r
1409 ;---------------------------------------------------------;
\r
1411 get_mem: ;this thing gets the begin and end locations for
\r
1412 ;a few commands. If an esc or enter w/ no input,
\r
1413 ;it pops it's own return and returns to the menu
\r
1414 ;(nasty programming, but we need tight code for 4k rom)
\r
1416 mov dptr, #beg_str
\r
1424 mov dptr, #end_str
\r
1441 abort2: mov dptr, #abort
\r
1449 acall cin_filter_h
\r
1451 cjne a, #'Y', abort_it
\r
1453 ;now we actually do it
\r
1455 clrm2: mov dph, r3
\r
1460 cjne a, dph, clrm4
\r
1462 cjne a, dpl, clrm4
\r
1467 ;---------------------------------------------------------;
\r
1470 mov dptr, #prompt6
\r
1478 ;---------------------------------------------------------;
\r
1482 mov dptr, #erfr_cmd
\r
1488 acall cin_filter_h
\r
1490 cjne a, #'Y', abort_it
\r
1493 mov dptr, #erfr_ok
\r
1495 mov dptr, #erfr_err
\r
1501 ;---------------------------------------------------------;
\r
1503 intm: acall newline
\r
1505 intm2: acall newline
\r
1506 cjne r0, #0x80, intm3
\r
1512 intm4: acall space
\r
1525 ;**************************************************************
\r
1526 ;**************************************************************
\r
1528 ;***** 2k page boundry is somewhere near here *****
\r
1529 ;***** (no ajmp or acall past this point) *****
\r
1531 ;**************************************************************
\r
1532 ;**************************************************************
\r
1536 ;---------------------------------------------------------;
\r
1538 ; Subroutines for memory managment and non-serial I/O ;
\r
1540 ;---------------------------------------------------------;
\r
1543 ;finds the next header in the external memory.
\r
1544 ; Input DPTR=point to start search (only MSB used)
\r
1545 ; Output DPTR=location of next module
\r
1546 ; C=set if a header found, C=clear if no more headers
\r
1550 cjne a, #0xA5, find3
\r
1554 cjne a, #0xE5, find3
\r
1558 cjne a, #0xE0, find3
\r
1562 cjne a, #0xA5, find3
\r
1563 mov dpl, #0 ;found one here!
\r
1566 find3: mov a, #(emem >> 8)
\r
1567 cjne a, dph, find4 ;did we just check the end
\r
1570 find4: inc dph ;keep on searching
\r
1575 ;routine that erases the whole flash rom! C=1 if failure, C=0 if ok
\r
1577 erall: mov a, #has_flash
\r
1579 mov dptr, #bflash ;is it already erased ??
\r
1583 jnz erall_b ;do actual erase if any byte not 255
\r
1585 mov a, #((eflash+1) & 255)
\r
1586 cjne a, dpl, erall0
\r
1587 mov a, #(((eflash+1) >> 8) & 255)
\r
1588 cjne a, dph, erall0
\r
1589 ;if we get here, the entire chip was already erased,
\r
1590 ;so there is no need to do anything
\r
1594 mov dptr, #bflash ;first program to all 00's
\r
1597 jz erall2 ;don't waste time!
\r
1599 lcall prgm ;ok, program this byte
\r
1600 ;if the program operation failed... we should abort because
\r
1601 ;they are all likely to fail and it will take a long time...
\r
1602 ;which give the appearance that the program has crashed,
\r
1603 ;when it's really following the flash rom algorithm
\r
1604 ;correctly and getting timeouts.
\r
1609 mov a, #((eflash+1) & 255)
\r
1610 cjne a, dpl, erall1
\r
1611 mov a, #(((eflash+1) >> 8) & 255)
\r
1612 cjne a, dph, erall1 ;after this it's all 00's
\r
1613 mov dptr, #bflash ;beginning address
\r
1614 mov r4, #232 ;max # of trials, lsb
\r
1615 mov r5, #4 ;max # of trials, msb-1
\r
1622 ret ;if it didn't work!
\r
1623 erall3a:mov a, #0x20
\r
1624 mov c, ea ;- ;turn off all interrupts!!
\r
1627 movx @dptr, a ;send the erase setup
\r
1628 movx @dptr, a ;and begin the erase
\r
1630 erwt: mov r2, #erwait2 ;now wait 10ms...
\r
1633 erall4: mov a, #0xA0
\r
1634 movx @dptr, a ;send erase verify
\r
1635 mov r2, #verwait ;wait for 6us
\r
1640 mov ea, c ;- ;turn interrupts back on
\r
1642 jnz erall3 ;erase again if not FF
\r
1644 mov a, #(((eflash+1) >> 8) & 255) ;verify whole array
\r
1645 cjne a, dph, erall4
\r
1646 mov a, #((eflash+1) & 255)
\r
1647 cjne a, dpl, erall4
\r
1650 movx @dptr, a ;reset the flash rom
\r
1652 movx @dptr, a ;and go back to read mode
\r
1659 ;a routine that writes ACC to into flash memory at DPTR
\r
1660 ; assumes that Vpp is active and stable already.
\r
1661 ; C is set if error occurs, C is clear if it worked
\r
1668 mov r2, #25 ;try to program 25 times if needed
\r
1669 prgm2: mov a, #40h
\r
1670 mov c, ea ;- ;turn off all interrupts!!
\r
1673 movx @dptr, a ;send setup programming command
\r
1675 movx @dptr, a ;write to the cell
\r
1676 mov r3, #pgmwait ;now wait for 10us
\r
1679 movx @dptr, a ;send program verify command
\r
1680 mov r3, #verwait ;wait 6us while it adds margin
\r
1685 mov ea, c ;- ;turn interrupts back on
\r
1688 jz prgmok ;note, C is still clear is ACC=0
\r
1690 prgmbad:setb c ;it gets here if programming failure
\r
1692 movx @dptr, a ;and go back into read mode
\r
1697 mov a, b ;restore ACC to original value
\r
1702 ;************************************
\r
1703 ;To make PAULMON2 able to write to other
\r
1704 ;types of memory than RAM and flash rom,
\r
1705 ;modify this "smart_wr" routine. This
\r
1706 ;code doesn't accept any inputs other
\r
1707 ;that the address (dptr) and value (acc),
\r
1708 ;so this routine must know which types
\r
1709 ;of memory are in what address ranges
\r
1710 ;************************************
\r
1713 ;Write to Flash ROM or ordinary RAM. Carry bit will indicate
\r
1714 ;if the value was successfully written, C=1 if not written.
\r
1721 ;do we even have a flash rom?
\r
1724 ;there is a flash rom, but is this address in it?
\r
1726 cjne a, #(eflash >> 8), isfl3
\r
1729 cjne a, #(bflash >> 8), isfl4
\r
1731 isfl4: jnc wr_flash
\r
1742 movx @dptr, a ;write the value to memory
\r
1744 movc a, @a+dptr ;read it back from code memory
\r
1748 movx a, @dptr ;read it back from data memory
\r
1762 ;---------------------------------------------------------;
\r
1764 ; Power-On initialization code and such... ;
\r
1766 ;---------------------------------------------------------;
\r
1768 ;first the hardware has to get initialized.
\r
1775 mov ie, a ;all interrupts off
\r
1777 mov psw, #psw_init
\r
1778 ;clear any interrupt status, just in case the user put
\r
1779 ;"ljmp 0" inside their interrupt service code.
\r
1789 ;Before we start doing any I/O, a short delay is required so
\r
1790 ;that any external hardware which may be in "reset mode" can
\r
1791 ;initialize. This is typically a problem when a 82C55 chip
\r
1792 ;is used and its reset line is driven from the R-C reset
\r
1793 ;circuit used for the 8051. Because the 82C55 reset pin
\r
1794 ;switches from zero to one at a higher voltage than the 8051,
\r
1795 ;any 82C55 chips would still be in reset mode right now...
\r
1798 mov r1, #200 ;approx 100000 cycles
\r
1799 rdly2: mov r2, #249 ;500 cycles
\r
1803 ;Check for the Erase-on-startup signal and erase Flash ROM
\r
1810 mov r0, #250 ;check it 250 times, just to be sure
\r
1814 djnz r1, * ;short delay
\r
1815 jc skip_erase ;skip erase if this bit is not low
\r
1816 djnz r0, chk_erase
\r
1817 lcall erall ;and this'll delete the flash rom
\r
1820 ;run any user initialization programs in external memory
\r
1824 ;initialize the serial port, auto baud detect if necessary
\r
1825 acall autobaud ;set up the serial port
\r
1829 ;run the start-up programs in external memory.
\r
1833 ;now print out the nice welcome message
\r
1837 welcm2: lcall newline
\r
1841 welcm4: lcall cout
\r
1848 mov r6, #(pgm & 255)
\r
1849 mov r7, #(pgm >> 8)
\r
1853 stcode: mov dptr, #bmem ;search for startup routines
\r
1854 stcode2:lcall find
\r
1859 cjne a, b, stcode4 ;only startup code if matches B
\r
1862 mov a, #(stcode3 & 255)
\r
1864 mov a, #(stcode3 >> 8)
\r
1868 jmp @a+dptr ;jump to the startup code
\r
1869 stcode3:pop dph ;hopefully it'll return to here
\r
1873 cjne a, #((emem+1) >> 8) & 255, stcode2
\r
1874 stcode5:ret ;now we've executed all of 'em
\r
1877 ;to do automatic baud rate detection, we assume the user will
\r
1878 ;press the carriage return, which will cause this bit pattern
\r
1879 ;to appear on port 3 pin 0 (CR = ascii code 13, assume 8N1 format)
\r
1881 ; 0 1 0 1 1 0 0 0 0 1
\r
1883 ; start bit----+ +--lsb msb--+ +----stop bit
\r
1885 ;we'll start timer #1 in 16 bit mode at the transition between the
\r
1886 ;start bit and the LSB and stop it between the MBS and stop bit.
\r
1887 ;That will give approx the number of cpu cycles for 8 bits. Divide
\r
1888 ;by 8 for one bit and by 16 since the built-in UART takes 16 timer
\r
1889 ;overflows for each bit. We need to be careful about roundoff during
\r
1890 ;division and the result has to be inverted since timer #1 counts up. Of
\r
1891 ;course, timer #1 gets used in 8-bit auto reload mode for generating the
\r
1892 ;built-in UART's baud rate once we know what the reload value should be.
\r
1896 mov a, #baud_const ;skip if user supplied baud rate constant
\r
1898 mov a, baud_save+3 ;is there a value from a previous boot?
\r
1899 xrl baud_save+2, #01010101b
\r
1900 xrl baud_save+1, #11001100b
\r
1901 xrl baud_save+0, #00011101b
\r
1902 cjne a, baud_save+2, autob1
\r
1903 cjne a, baud_save+1, autob1
\r
1904 cjne a, baud_save+0, autob1
\r
1908 autob1: ;wait for inactivity
\r
1910 mov pcon, #0x80 ;configure uart, fast baud
\r
1911 mov scon, #0x42 ;configure uart, but receive disabled
\r
1912 mov tmod, #0x11 ;get timers ready for action (16 bit mode)
\r
1920 ;make sure there is no activity on the line
\r
1921 ;before we actually begin looking for the carriage return
\r
1923 autob1b:mov r1, #30
\r
1924 autob1c:jnb p3.0, autob1
\r
1928 autob2: ;look for the bits of the carriage return
\r
1929 jb p3.0, autob2 ;wait for start bit
\r
1931 jb p3.0, autob2 ; check it a few more times to make
\r
1932 jb p3.0, autob2 ; sure we don't trigger on some noise
\r
1934 autob2b:jnb p3.0, autob2b ;wait for bit #0 to begin
\r
1935 setb tr1 ;and now we're timing it
\r
1936 autob2c:jb tf1, autob1 ;check for timeout while waiting
\r
1937 jb p3.0, autob2c ;wait for bit #1 to begin
\r
1938 autob2d:jb tf1, autob1 ;check for timeout while waiting
\r
1939 jnb p3.0, autob2d ;wait for bit #2 to begin
\r
1940 autob2e:jb tf1, autob1 ;check for timeout while waiting
\r
1941 jb p3.0, autob2e ;wait for bit #4 to begin
\r
1942 setb tr0 ;start timing last 4 bits
\r
1943 autob2f:jb tf1, autob1 ;check for timeout while waiting
\r
1944 jnb p3.0, autob2f ;wait for stop bit to begin
\r
1945 clr tr1 ;stop timing (both timers)
\r
1948 jb tf1, autob1 ;check for timeout one last time
\r
1950 ;compute the baud rate based on timer1
\r
1956 jc autob1 ;error if timer0 > 32767
\r
1960 inc a ;now a has the value to load into th1
\r
1961 jz autob1 ;error if baud rate too fast
\r
1963 ;after we get the carriage return, we need to make sure there
\r
1964 ;isn't any "crap" on the serial line, as there is in the case
\r
1965 ;were we get the letter E (and conclude the wrong baud rate).
\r
1966 ;unfortunately the simple approach of just looking at the line
\r
1967 ;for silence doesn't work, because we have to accept the case
\r
1968 ;where the user's terminal emulation is configured to send a
\r
1969 ;line feed after the carriage return. The best thing to do is
\r
1970 ;use the uart and look see if it receives anything
\r
1972 autob3: mov th1, a ;config timer1
\r
1973 mov tl1, #255 ;start asap!
\r
1974 mov tmod, #0x21 ;autoreload mode
\r
1975 setb ren ;turn on the uart
\r
1976 setb tr1 ;turn on timer1 for its clock
\r
1982 autob3b:mov r0, #255
\r
1983 autob3c:djnz r0, autob3c
\r
1987 ;if we got here, there was some stuff after the carriage
\r
1988 ;return, so we'll read it and see if it was the line feed
\r
1993 jz autob4 ;ok if 0A, the line feed character
\r
1995 jz autob4 ;of if 05, since we may have missed start bit
\r
1999 ;compute the baud rate based on timer0, check against timer1 value
\r
2006 jc autob1_jmp ;error if timer0 > 32767
\r
2014 jz autob1_jmp ;error if baud too fast!
\r
2017 cjne a, th1, autob1_jmp
\r
2018 ;acc has th1 value at this point
\r
2020 autoend:mov baud_save+3, a
\r
2021 mov baud_save+2, a ;store the baud rate for next warm boot.
\r
2022 mov baud_save+1, a
\r
2023 mov baud_save+0, a
\r
2024 xrl baud_save+2, #01010101b
\r
2025 xrl baud_save+1, #11001100b
\r
2026 xrl baud_save+0, #00011101b
\r
2029 mov tmod, #0x21 ;set timer #1 for 8 bit auto-reload
\r
2030 mov pcon, #0x80 ;configure built-in uart
\r
2032 setb tr1 ;start the baud rate timer
\r
2037 ;---------------------------------------------------------;
\r
2039 ; More subroutines, but less frequent used, so ;
\r
2040 ; they're down here in the second 2k page. ;
\r
2042 ;---------------------------------------------------------;
\r
2046 ;this twisted bit of code looks for escape sequences for
\r
2047 ;up, down, left, right, pageup, and pagedown, as well
\r
2048 ;as ordinary escape and ordinary characters. Escape
\r
2049 ;sequences are required to arrive with each character
\r
2050 ;nearly back-to-back to the others, otherwise the characters
\r
2051 ;are treated as ordinary user keystroaks. cin_filter
\r
2052 ;returns a single byte when it sees the multi-byte escape
\r
2053 ;sequence, as shown here.
\r
2055 ; return value key escape sequence
\r
2056 ; 11 (^K) up 1B 5B 41
\r
2057 ; 10 (^J) down 1B 5B 42
\r
2058 ; 21 (^U) right 1B 5B 43
\r
2059 ; 8 (^H) left 1B 5B 44
\r
2060 ; 25 (^Y) page up 1B 5B 35 7E
\r
2061 ; 26 (^Z) page down 1B 5B 36 7E
\r
2068 cjne a, #esc_char, cinf_end
\r
2069 ;if esc was already in sbuf, just ignore it
\r
2071 cjne a, #esc_char, cinf_end
\r
2072 cinf2: acall cinf_wait
\r
2075 ret ;an ordinary ESC
\r
2077 cinf4: ;if we get here, it's a control code, since a character
\r
2078 ;was received shortly after receiving an ESC character
\r
2080 cjne a, #'[', cinf_consume
\r
2082 jnb ri, cin_filter
\r
2084 cinf5a: cjne a, #'A', cinf5b
\r
2087 cinf5b: cjne a, #'B', cinf5c
\r
2090 cinf5c: cjne a, #'C', cinf5d
\r
2093 cinf5d: cjne a, #'D', cinf5e
\r
2096 cinf5e: cjne a, #0x35, cinf5f
\r
2098 cinf5f: cjne a, #0x36, cinf5g
\r
2100 cinf5g: sjmp cinf_consume ;unknown escape sequence
\r
2102 cinf8: ;when we get here, we've got the sequence for pageup/pagedown
\r
2103 ;but there's one more incoming byte to check...
\r
2106 jnb ri, cinf_restart
\r
2108 cjne a, #0x7E, cinf_notpg
\r
2117 ;unrecognized escape... eat up everything that's left coming in
\r
2118 ;quickly, then begin looking again
\r
2121 jnb ri, cin_filter
\r
2123 cjne a, #esc_char, cinf_consume
\r
2126 ;this thing waits for a character to be received for approx
\r
2127 ;4 character transmit time periods. It returns immedately
\r
2128 ;or after the entire wait time. It does not remove the character
\r
2129 ;from the buffer, so ri should be checked to see if something
\r
2130 ;actually did show up while it was waiting
\r
2131 .equ char_delay, 4 ;number of char xmit times to wait
\r
2135 mov r2, #char_delay*5
\r
2136 cinfw2: mov a, th0
\r
2137 cinfw3: jb ri, cinfw4
\r
2148 pint8u: ;prints the unsigned 8 bit value in Acc in base 10
\r
2153 pint8: ;prints the signed 8 bit value in Acc in base 10
\r
2163 pint8b: mov b, #100
\r
2175 pint8d: add a, #'0'
\r
2186 ;print 16 bit unsigned integer in DPTR, using base 10.
\r
2187 pint16u: ;warning, destroys r2, r3, r4, r5, psw.5
\r
2195 pint16a:mov r4, #16 ;ten-thousands digit
\r
2203 pint16b:mov r4, #232 ;thousands digit
\r
2207 jnb psw.5, pint16d
\r
2208 pint16c:add a, #'0'
\r
2212 pint16d:mov r4, #100 ;hundreds digit
\r
2216 jnb psw.5, pint16f
\r
2217 pint16e:add a, #'0'
\r
2221 pint16f:mov a, r2 ;tens digit
\r
2226 jnb psw.5, pint16h
\r
2227 pint16g:add a, #'0'
\r
2230 pint16h:mov a, b ;and finally the ones digit
\r
2240 ;ok, it's a cpu hog and a nasty way to divide, but this code
\r
2241 ;requires only 21 bytes! Divides r2-r3 by r4-r5 and leaves
\r
2242 ;quotient in r2-r3 and returns remainder in acc. If Intel
\r
2243 ;had made a proper divide, then this would be much easier.
\r
2245 pint16x:mov r0, #0
\r
2267 ;pcstr prints the compressed strings. A dictionary of 128 words is
\r
2268 ;stored in 4 bit packed binary format. When pcstr finds a byte in
\r
2269 ;a string with the high bit set, it prints the word from the dictionary.
\r
2270 ;A few bytes have special functions and everything else prints as if
\r
2271 ;it were an ordinary string.
\r
2273 ; special codes for pcstr:
\r
2274 ; 0 = end of string
\r
2276 ; 14 = CR/LF and end of string
\r
2277 ; 31 = next word code should be capitalized
\r
2294 pcstrs1:cjne a, #13, pcstrs2
\r
2298 pcstrs2:cjne a, #31, pcstrs3
\r
2301 pcstrs3:cjne a, #14, pcstrs4
\r
2317 ;dcomp actually takes care of printing a word from the dictionary
\r
2319 ; dptr = position in packed words table
\r
2320 ; r4=0 if next nibble is low, r4=255 if next nibble is high
\r
2322 decomp: anl a, #0x7F
\r
2323 mov r0, a ;r0 counts which word
\r
2324 jb psw.1, decomp1 ;avoid leading space if first word
\r
2333 ;here we must seek past all the words in the table
\r
2334 ;that come before the one we're supposed to print
\r
2336 dcomp2: acall get_next_nibble
\r
2338 ;when we get here, a word has been skipped... keep doing
\r
2339 ;this until we're pointing to the correct one
\r
2341 dcomp3: ;now we're pointing to the correct word, so all we have
\r
2342 ;to do is print it out
\r
2343 acall get_next_nibble
\r
2345 cjne a, #15, dcomp4
\r
2346 ;the character is one of the 12 least commonly used
\r
2347 acall get_next_nibble
\r
2351 .db "hfwgybxvkqjz"
\r
2352 dcomp4: ;the character is one of the 14 most commonly used
\r
2356 .db "etarnisolumpdc"
\r
2357 dcomp5: ;decide if it should be uppercase or lowercase
\r
2361 cjne r0, #20, dcomp6
\r
2363 dcomp6: cjne r0, #12, dcomp7
\r
2365 dcomp7: lcall cout
\r
2372 get_next_nibble: ;...and update dptr and r4, of course
\r
2386 ;---------------------------------------------------------;
\r
2388 ; Here begins the data tables and strings ;
\r
2390 ;---------------------------------------------------------;
\r
2392 ;this is the dictionary of 128 words used by pcstr.
\r
2395 .db 0x82, 0x90, 0xE8, 0x23, 0x86, 0x05, 0x4C, 0xF8
\r
2396 .db 0x44, 0xB3, 0xB0, 0xB1, 0x48, 0x5F, 0xF0, 0x11
\r
2397 .db 0x7F, 0xA0, 0x15, 0x7F, 0x1C, 0x2E, 0xD1, 0x40
\r
2398 .db 0x5A, 0x50, 0xF1, 0x03, 0xBF, 0xBA, 0x0C, 0x2F
\r
2399 .db 0x96, 0x01, 0x8D, 0x3F, 0x95, 0x38, 0x0D, 0x6F
\r
2400 .db 0x5F, 0x12, 0x07, 0x71, 0x0E, 0x56, 0x2F, 0x48
\r
2401 .db 0x3B, 0x62, 0x58, 0x20, 0x1F, 0x76, 0x70, 0x32
\r
2402 .db 0x24, 0x40, 0xB8, 0x40, 0xE1, 0x61, 0x8F, 0x01
\r
2403 .db 0x34, 0x0B, 0xCA, 0x89, 0xD3, 0xC0, 0xA3, 0xB9
\r
2404 .db 0x58, 0x80, 0x04, 0xF8, 0x02, 0x85, 0x60, 0x25
\r
2405 .db 0x91, 0xF0, 0x92, 0x73, 0x1F, 0x10, 0x7F, 0x12
\r
2406 .db 0x54, 0x93, 0x10, 0x44, 0x48, 0x07, 0xD1, 0x26
\r
2407 .db 0x56, 0x4F, 0xD0, 0xF6, 0x64, 0x72, 0xE0, 0xB8
\r
2408 .db 0x3B, 0xD5, 0xF0, 0x16, 0x4F, 0x56, 0x30, 0x6F
\r
2409 .db 0x48, 0x02, 0x5F, 0xA8, 0x20, 0x1F, 0x01, 0x76
\r
2410 .db 0x30, 0xD5, 0x60, 0x25, 0x41, 0xA4, 0x2C, 0x60
\r
2411 .db 0x05, 0x6F, 0x01, 0x3F, 0x26, 0x1F, 0x30, 0x07
\r
2412 .db 0x8E, 0x1D, 0xF0, 0x63, 0x99, 0xF0, 0x42, 0xB8
\r
2413 .db 0x20, 0x1F, 0x23, 0x30, 0x02, 0x7A, 0xD1, 0x60
\r
2414 .db 0x2F, 0xF0, 0xF6, 0x05, 0x8F, 0x93, 0x1A, 0x50
\r
2415 .db 0x28, 0xF0, 0x82, 0x04, 0x6F, 0xA3, 0x0D, 0x3F
\r
2416 .db 0x1F, 0x51, 0x40, 0x23, 0x01, 0x3E, 0x05, 0x43
\r
2417 .db 0x01, 0x7A, 0x01, 0x17, 0x64, 0x93, 0x30, 0x2A
\r
2418 .db 0x08, 0x8C, 0x24, 0x30, 0x99, 0xB0, 0xF3, 0x19
\r
2419 .db 0x60, 0x25, 0x41, 0x35, 0x09, 0x8E, 0xCB, 0x19
\r
2420 .db 0x12, 0x30, 0x05, 0x1F, 0x31, 0x1D, 0x04, 0x14
\r
2421 .db 0x4F, 0x76, 0x12, 0x04, 0xAB, 0x27, 0x90, 0x56
\r
2422 .db 0x01, 0x2F, 0xA8, 0xD5, 0xF0, 0xAA, 0x26, 0x20
\r
2423 .db 0x5F, 0x1C, 0xF0, 0xF3, 0x61, 0xFE, 0x01, 0x41
\r
2424 .db 0x73, 0x01, 0x27, 0xC1, 0xC0, 0x84, 0x8F, 0xD6
\r
2425 .db 0x01, 0x87, 0x70, 0x56, 0x4F, 0x19, 0x70, 0x1F
\r
2426 .db 0xA8, 0xD9, 0x90, 0x76, 0x02, 0x17, 0x43, 0xFE
\r
2427 .db 0x01, 0xC1, 0x84, 0x0B, 0x15, 0x7F, 0x02, 0x8B
\r
2428 .db 0x14, 0x30, 0x8F, 0x63, 0x39, 0x6F, 0x19, 0xF0
\r
2429 .db 0x11, 0xC9, 0x10, 0x6D, 0x02, 0x3F, 0x91, 0x09
\r
2430 .db 0x7A, 0x41, 0xD0, 0xBA, 0x0C, 0x1D, 0x39, 0x5F
\r
2431 .db 0x07, 0xF2, 0x11, 0x17, 0x20, 0x41, 0x6B, 0x35
\r
2432 .db 0x09, 0xF7, 0x75, 0x12, 0x0B, 0xA7, 0xCC, 0x48
\r
2433 .db 0x02, 0x3F, 0x64, 0x12, 0xA0, 0x0C, 0x27, 0xE3
\r
2434 .db 0x9F, 0xC0, 0x14, 0x77, 0x70, 0x11, 0x40, 0x71
\r
2435 .db 0x21, 0xC0, 0x68, 0x25, 0x41, 0xF0, 0x62, 0x7F
\r
2436 .db 0xD1, 0xD0, 0x21, 0xE1, 0x62, 0x58, 0xB0, 0xF3
\r
2437 .db 0x05, 0x1F, 0x73, 0x30, 0x77, 0xB1, 0x6F, 0x19
\r
2438 .db 0xE0, 0x19, 0x43, 0xE0, 0x58, 0x2F, 0xF6, 0xA4
\r
2439 .db 0x14, 0xD0, 0x23, 0x03, 0xFE, 0x31, 0xF5, 0x14
\r
2440 .db 0x30, 0x99, 0xF8, 0x03, 0x3F, 0x64, 0x22, 0x51
\r
2441 .db 0x60, 0x25, 0x41, 0x2F, 0xE3, 0x01, 0x56, 0x27
\r
2442 .db 0x93, 0x09, 0xFE, 0x11, 0xFE, 0x79, 0xBA, 0x60
\r
2443 .db 0x75, 0x42, 0xEA, 0x62, 0x58, 0xA0, 0xE5, 0x1F
\r
2444 .db 0x53, 0x4F, 0xD1, 0xC0, 0xA3, 0x09, 0x42, 0x53
\r
2445 .db 0xF7, 0x12, 0x04, 0x62, 0x1B, 0x30, 0xF5, 0x05
\r
2446 .db 0xF7, 0x69, 0x0C, 0x35, 0x1B, 0x70, 0x82, 0x2F
\r
2447 .db 0x2F, 0x14, 0x4F, 0x51, 0xC0, 0x64, 0x25, 0x00
\r
2451 logon1: .db "Welcome",128,148,"2, by",31,248,31,254,13,14
\r
2452 logon2: .db 32,32,"See",148,"2.DOC,",148,"2.EQU",164
\r
2453 .db 148,"2.HDR",180,213,141,".",14
\r
2454 abort: .db " ",31,158,31,160,"!",13,14
\r
2455 prompt1:.db 148,"2 Loc:",0
\r
2456 prompt2:.db " >", 160 ;must follow after prompt1
\r
2457 prompt3:.db 134,202,130,'(',0
\r
2458 prompt4:.db "),",149,140,128,200,": ",0
\r
2459 prompt5:.db 31,151,130,195,"s",199,166,131,","
\r
2460 .db 186," JUMP",128,134,161,"r",130,13,14
\r
2461 prompt6:.db 13,13,31,135,131,129,": ",0
\r
2462 prompt7:.db 31,228,251," key: ",0
\r
2463 prompt8:.db 13,13,31,136,128,131,129," (",0
\r
2464 prompt9:.db 13,13,31,130,31,253,0
\r
2465 prompt9b:.db 31,129,32,32,32,32,32,31,201,14 ;must follow prompt9
\r
2466 prompt10:.db ") ",31,135,31,178,": ",0
\r
2467 beg_str:.db "First",31,129,": ",0
\r
2468 end_str:.db "Last",31,129,":",32,32,0
\r
2469 sure: .db 31,185,161," sure?",0
\r
2470 edits1: .db 13,13,31,156,154,146,",",140,128,200,14
\r
2471 edits2: .db " ",31,156,193,",",142,129,247,13,14
\r
2472 dnlds1: .db 13,13,31,159," ascii",249,150,31,152,132,137
\r
2473 .db ",",149,140,128,160,13,14
\r
2474 dnlds2: .db 13,31,138,160,"ed",13,14
\r
2475 dnlds3: .db 13,31,138,193,"d",13,14
\r
2476 dnlds4: .db "Summary:",14
\r
2477 dnlds5: .db " ",198,"s",145,"d",14
\r
2478 dnlds6a:.db " ",139,145,"d",14
\r
2479 dnlds6b:.db " ",139," written",14
\r
2480 dnlds7: .db 31,155,":",14
\r
2481 dnlds8: .db " ",139," unable",128," write",14
\r
2482 dnlds9: .db 32,32,"bad",245,"s",14
\r
2483 dnlds10:.db " ",133,159,150,198,14
\r
2484 dnlds11:.db " ",133,132,157,14
\r
2485 dnlds12:.db " ",133," non",132,157,14
\r
2486 dnlds13:.db 31,151,155," detected",13,14
\r
2487 runs1: .db 13,134,"ning",130,":",13,14
\r
2488 uplds3: .db 13,13,"Sending",31,152,132,137,172,32,32,0
\r
2489 uplds4: .db " ",128,32,32,0 ;must follow uplds3
\r
2490 help1txt:.db 13,13,"Standard",31,158,"s",14
\r
2491 help2txt:.db 31,218,31,244,"ed",31,158,"s",14
\r
2492 type1: .db 31,154,158,0
\r
2493 type2: .db 31,130,0
\r
2494 type4: .db 31,143,31,226,31,170,0
\r
2495 type5: .db "???",0
\r
2496 help_cmd2:.db 31,215,0
\r
2497 help_cmd: .db 31,142,215,209,0 ;these 11 _cmd string must be in order
\r
2498 dir_cmd: .db 31,209,130,"s",0
\r
2499 run_cmd: .db 31,134,130,0
\r
2500 dnld_cmd: .db 31,138,0
\r
2501 upld_cmd: .db 31,147,0
\r
2502 nloc_cmd: .db 31,135,129,0
\r
2503 jump_cmd: .db 31,136,128,131,129,0
\r
2504 dump_cmd: .db 31,132,219,154,131,0
\r
2505 intm_cmd: .db 31,132,219,192,131,0
\r
2506 edit_cmd: .db 31,156,154,146,0
\r
2507 clrm_cmd: .db 31,237,131,0
\r
2508 erfr_cmd: .db 31,203,153,144,0
\r
2509 erfr_ok: .db 31,153,144,203,'d',13,14
\r
2510 erfr_err: .db 31,133,155,13,14
\r