File: paulmon2.asm

package info (click to toggle)
as31 2.3.1-2
  • links: PTS
  • area: main
  • in suites: squeeze
  • size: 680 kB
  • ctags: 1,376
  • sloc: asm: 5,377; ansic: 1,502; yacc: 919; sh: 335; makefile: 76
file content (2512 lines) | stat: -rw-r--r-- 61,020 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
; PAULMON2, a user-friendly 8051 monitor, by Paul Stoffregen
; Please email comments, suggestions, bugs to paul@pjrc.com

; It's free.  PAULMON2 is in the public domain.  You may copy
; sections of code from PAULMON2 into your own programs, even
; for commercial purposes.  PAULMON2 should only be distributed
; free of charge, but may be bundled as 'value-added' with other
; products, such as development boards, CDROMs, etc.  Please
; distribute the PAULMON2.DOC file and other files, not just
; the object code!

; The PAULMON2.EQU and PAULMON2.HDR files contain valuable
; information that could help you to write programs for use
; with PAULMON2.

; PAULMON2 is in the public domain. PAULMON2 is distributed in
; the hope that it will be useful, but without any warranty;
; without even the implied warranty of merchantability or fitness
; for a particular purpose. 


; You are probably reading this code to see what it looks like
; and possibly learn something, or to modify it for some reason.
; Either is ok, but please remember that this code uses a number
; of tricks to cram all the functionality into just 4k.  As a
; result, the code can be difficult to read, and adding new
; features can be very difficult without growing beyond 4k.  To
; add or modify commands in PAULMON2, please consider using the
; "external command" functionality.  It is easier to develop
; new commands this way, and you can distribute them to other
; users.  Email paul@pjrc.com if you have new PAULMON2
; commands to contribute to others.  Details about adding new
; commands to PAULMON2 (with examples) can be found at:

; http://www.pjrc.com/tech/8051/pm2_docs/addons.html


;---------------------------------------------------------;
;							  ;
;	    PAULMON2's default configuration		  ;
;							  ;
;---------------------------------------------------------;

; PAULMON2 should be assembled using the modified AS31 assembler,
; originally written by Ken Stauffer, many small changes by Paul
; Stoffregen.  This free assembler is available on the web at
; http://www.pjrc.com/tech/8051/index.html
; As well, these web pages have a fill-out form which makes it
; very easy to custom configure PAULMON2.  Using this form will
; edit the code for you, run the AS31 assmebler, and send you the
; object code to program into your chip.


; These two parameters control where PAULMON2 will be assembled,
; and where it will attempt to LJMP at the interrupt vector locations.

.equ	base, 0x0000		;location for PAULMON2
.equ	vector, 0x2000		;location to LJMP interrupt vectors

; These three parameters tell PAULMON2 where the user's memory is
; installed.  "bmem" and "emem" define the space that will be searched
; for program headers, user installed commands, start-up programs, etc.
; "bmem" and "emem" should be use so they exclude memory areas where
; perphreal devices may be mapped, as reading memory from an io chip
; may reconfigure it unexpectedly.  If flash rom is used, "bmem" and "emem"
; should also include the space where the flash rom is mapped.

.equ	pgm, 0x2000		;default location for the user program
.equ	bmem, 0x1000		;where is the beginning of memory
.equ	emem, 0xFFFF		;end of the memory

; Flash ROM parameters.	 If "has_flash" is set to zero, all flash rom
; features are turned off, otherwise "bflash" and "eflash" should specify
; the memory range which is flash rom.	Though AMD doesn't suggest it,
; you may be able to map only a part of the flash rom with your address
; decoder logic (and not use the rest), but you should be careful that
; "bflash" and "eflash" don't include and memory which is NOT flash rom
; so that the erase algorithm won't keep applying erase pulses until it
; finally gives up (which will stress the thin oxide and degrade the
; flash rom's life and reliability).  "erase_pin" allows you to specify
; the bit address for a pin which (if held low) will tell PAULMON2 to
; erase the flash rom chip when it starts up.  This is useful if you
; download programs with the "start-up" headers on them and the code you've
; put in the flash rom crashes!

.equ	has_flash, 0		;set to non-zero value if flash installed
.equ	bflash, 0x8000		;first memory location of Flash ROM
.equ	eflash, 0xFFFF		;last memory location of Flash ROM
.equ	erase_pin, 0		;00 = disable erase pin feature
;.equ	erase_pin, 0xB5		;B5 = pin 15, P3.5 (T1)

; Please note... much of the memory management code only looks at the
; upper 8 bits of an address, so it's not a good idea to somehow map
; your memory chips (with complex address decoding logic) into chunks
; less than 256 bytes.	In other words, only using a piece of a flash
; rom chip and mapping it between C43A to F91B would confuse PAULMON2
; (as well as require quit a bit of address decoding logic circuitry)


; To set the baud rate, use this formula or set to 0 for auto detection
; baud_const = 256 - (crystal / (12 * 16 * baud))

.equ	baud_const, 0		;automatic baud rate detection
;.equ	baud_const, 255		;57600 baud w/ 11.0592 MHz
;.equ	baud_const, 253		;19200 baud w/ 11.0592 MHz
;.equ	baud_const, 252		;19200 baud w/ 14.7456 MHz
;.equ	baud_const, 243		;4808 baud w/ 12 MHz

.equ	line_delay, 6		;num of char times to pause during uploads

; About download speed: when writing to ram, PAULMON2 can accept data
; at the maximum baud rate (baud_const=255 or 57600 baud w/ 11.0592 MHz).
; Most terminal emulation programs introduce intentional delays when
; sending ascii data, which you would want to turn off for downloading
; larger programs into ram.  For Flash ROM, the maximum speed is set by
; the time it takes to program each location... 9600 baud seems to work
; nicely for the AMD 28F256 chip.  The "character pacing" delay in a
; terminal emulation program should be sufficient to download to flash
; rom and any baud rate.  Some flash rom chips can write very quickly,
; allowing high speed baud rates, but other chips can not.  You milage
; will vary...


; Several people didn't like the key definations in PAULMON1.
; Actually, I didn't like 'em either, but I never took the time
; to change it.	 Eventually I got used to them, but now it's
; really easy to change which keys do what in PAULMON2.	 You
; can guess what to do below, but don't use lowercase.

.equ	help_key, '?'		;help screen
.equ	dir_key,  'M'		;directory
.equ	run_key,  'R'		;run program
.equ	dnld_key, 'D'		;download
.equ	upld_key, 'U'		;upload
.equ	nloc_key, 'N'		;new memory location
.equ	jump_key, 'J'		;jump to memory location
.equ	dump_key, 'H'		;hex dump memory
.equ	intm_key, 'I'		;hex dump internal memory
.equ	edit_key, 'E'		;edit memory
.equ	clrm_key, 'C'		;clear memory
.equ	erfr_key, 'Z'		;erase flash rom

; timing parameters for AMD Flash ROM 28F256.  These parameters
; and pretty conservative and they seem to work with crystals
; between 6 MHz to 24 MHz... (tested with AMD 28F256 chips only)
; unless you know this is a problem, it is probably not a good
; idea to fiddle with these.

;.equ	pgmwait, 10		;22.1184 MHz crystal assumed
.equ	pgmwait, 19		;11.0592 MHz
.equ	verwait, 5
;.equ	erwait1, 40		;fourty delays @22.1184
.equ	erwait1, 20		;twenty delays for 11.0592 MHz
.equ	erwait2, 229		;each delay .5 ms @22.1184MHz



; These symbols configure paulmon2's internal memory usage.
; It is usually not a good idea to change these unless you
; know that you really have to.

.equ	psw_init, 0		;value for psw (which reg bank to use)
.equ	dnld_parm, 0x10		;block of 16 bytes for download
.equ	stack, 0x30		;location of the stack
.equ	baud_save, 0x78		;save baud for warm boot, 4 bytes

;---------------------------------------------------------;
;							  ;
;		     Interrupt Vectors			  ;
;  (and little bits of code crammed in the empty spaces)  ;
;							  ;
;---------------------------------------------------------;

	.org	base
	ljmp	poweron		;reset vector

	.org	base+3
	ljmp	vector+3	;ext int0 vector

r6r7todptr:
	mov	dpl, r6
	mov	dph, r7
	ret

	.org	base+11
	ljmp	vector+11	;timer0 vector

dptrtor6r7:
	mov	r6, dpl
	mov	r7, dph
	ret

	.org	base+19
	ljmp	vector+19	;ext int1 vector

dash:	mov	a, #'-'		;seems kinda trivial, but each time
	ajmp	cout		;this appears in code, it takes 4
	nop			;bytes, but an acall takes only 2

	.org	base+27
	ljmp	vector+27	;timer1 vector

cout_sp:acall	cout
	ajmp	space
	nop

	.org	base+35
	ljmp	vector+35	;uart vector

dash_sp:acall	dash
	ajmp	space
	nop

	.org	base+43
	ljmp	vector+43	;timer2 vector (8052)


;---------------------------------------------------------;
;							  ;
;	The jump table for user programs to call	  ;
;	      subroutines within PAULMON		  ;
;							  ;
;---------------------------------------------------------;

.org	base+46		;never change this line!!  Other
			;programs depend on these locations
			;to access paulmon2 functions

	ajmp	phex1		;2E
	ajmp	cout		;30
	ajmp	cin		;32
	ajmp	phex		;34
	ajmp	phex16		;36
	ajmp	pstr		;38
	ajmp	ghex		;3A
	ajmp	ghex16		;3C
	ajmp	esc		;4E
	ajmp	upper		;40
	ljmp	autobaud	;42
pcstr_h:ljmp	pcstr		;45
	ajmp	newline		;48
	ljmp	lenstr		;4A
	ljmp	pint8u		;4D
	ljmp	pint8		;50
	ljmp	pint16u		;53
	ljmp	smart_wr	;56
	ljmp	prgm		;59
	ljmp	erall		;5C
	ljmp	find		;5F
cin_filter_h:
	ljmp	cin_filter	;62
	ajmp	asc2hex		;64


;---------------------------------------------------------;
;							  ;
;	       Subroutines for serial I/O		  ;
;							  ;
;---------------------------------------------------------;


cin:	jnb	ri, cin
	clr	ri
	mov	a, sbuf
	ret

dspace: acall	space
space:	mov	a, #' '
cout:	jnb	ti, cout
	clr	ti		;clr ti before the mov to sbuf!
	mov	sbuf, a
	ret

;clearing ti before reading sbuf takes care of the case where
;interrupts may be enabled... if an interrupt were to happen
;between those two instructions, the serial port will just
;wait a while, but in the other order and the character could
;finish transmitting (during the interrupt routine) and then
;ti would be cleared and never set again by the hardware, causing
;the next call to cout to hang forever!

newline2:			;print two newlines
	acall	newline
newline:push	acc		;print one newline
	mov	a, #13
	acall	cout
	mov	a, #10
	acall	cout
	pop	acc
	ret

	;get 2 digit hex number from serial port
	; c = set if ESC pressed, clear otherwise
	; psw.5 = set if return w/ no input, clear otherwise
ghex:
ghex8:	clr	psw.5
ghex8c:
	acall	cin_filter_h	;get first digit
	acall	upper
	cjne	a, #27, ghex8f
ghex8d: setb	c
	clr	a
	ret
ghex8f: cjne	a, #13, ghex8h
	setb	psw.5
	clr	c
	clr	a
	ret
ghex8h: mov	r2, a
	acall	asc2hex
	jc	ghex8c
	xch	a, r2		;r2 will hold hex value of 1st digit
	acall	cout
ghex8j:
	acall	cin_filter_h	;get second digit
	acall	upper
	cjne	a, #27, ghex8k
	sjmp	ghex8d
ghex8k: cjne	a, #13, ghex8m
	mov	a, r2
	clr	c
	ret
ghex8m: cjne	a, #8, ghex8p
ghex8n: acall	cout
	sjmp	ghex8c
ghex8p: cjne	a, #21, ghex8q
	sjmp	ghex8n
ghex8q: mov	r3, a
	acall	asc2hex
	jc	ghex8j
	xch	a, r3
	acall	cout
	mov	a, r2
	swap	a
	orl	a, r3
	clr	c
	ret




	;carry set if esc pressed
	;psw.5 set if return pressed w/ no input
ghex16:
	mov	r2, #0		;start out with 0
	mov	r3, #0
	mov	r4, #4		;number of digits left
	clr	psw.5

ghex16c:
	acall	cin_filter_h
	acall	upper
	cjne	a, #27, ghex16d
	setb	c		;handle esc key
	clr	a
	mov	dph, a
	mov	dpl, a
	ret
ghex16d:cjne	a, #8, ghex16f
	sjmp	ghex16k
ghex16f:cjne	a, #127, ghex16g  ;handle backspace
ghex16k:cjne	r4, #4, ghex16e	  ;have they entered anything yet?
	sjmp	ghex16c
ghex16e:acall	cout
	acall	ghex16y
	inc	r4
	sjmp	ghex16c
ghex16g:cjne	a, #13, ghex16i	  ;return key
	mov	dph, r3
	mov	dpl, r2
	cjne	r4, #4, ghex16h
	clr	a
	mov	dph, a
	mov	dpl, a
	setb	psw.5
ghex16h:clr	c
	ret
ghex16i:mov	r5, a		  ;keep copy of original keystroke
	acall	asc2hex
	jc	ghex16c
	xch	a, r5
	lcall	cout
	mov	a, r5
	push	acc
	acall	ghex16x
	pop	acc
	add	a, r2
	mov	r2, a
	clr	a
	addc	a, r3
	mov	r3, a
	djnz	r4, ghex16c
	clr	c
	mov	dpl, r2
	mov	dph, r3
	ret

ghex16x:  ;multiply r3-r2 by 16 (shift left by 4)
	mov	a, r3
	swap	a
	anl	a, #11110000b
	mov	r3, a
	mov	a, r2
	swap	a
	anl	a, #00001111b
	orl	a, r3
	mov	r3, a
	mov	a, r2
	swap	a
	anl	a, #11110000b
	mov	r2, a
	ret

ghex16y:  ;divide r3-r2 by 16 (shift right by 4)
	mov	a, r2
	swap	a
	anl	a, #00001111b
	mov	r2, a
	mov	a, r3
	swap	a
	anl	a, #11110000b
	orl	a, r2
	mov	r2, a
	mov	a, r3
	swap	a
	anl	a, #00001111b
	mov	r3, a
	ret


	;carry set if invalid input
asc2hex:
	clr	c
	add	a, #208
	jnc	hex_not
	add	a, #246
	jc	hex_maybe
	add	a, #10
	clr	c
	ret
hex_maybe:
	add	a, #249
	jnc	hex_not
	add	a, #250
	jc	hex_not
	add	a, #16
	clr	c
	ret
hex_not:setb	c
	ret



phex:
phex8:
	push	acc
	swap	a
	anl	a, #15
	add	a, #246
	jnc	phex_b
	add	a, #7
phex_b: add	a, #58
	acall	cout
	pop	acc
phex1:	push	acc
	anl	a, #15
	add	a, #246
	jnc	phex_c
	add	a, #7
phex_c: add	a, #58
	acall	cout
	pop	acc
	ret


phex16:
	push	acc
	mov	a, dph
	acall	phex
	mov	a, dpl
	acall	phex
	pop	acc
	ret


;a not so well documented feature of pstr is that you can print
;multiple consecutive strings without needing to reload dptr
;(which takes 3 bytes of code!)... this is useful for inserting
;numbers or spaces between strings.

pstr:	push	acc
pstr1:	clr	a
	movc	a, @a+dptr
	inc	dptr
	jz	pstr2
	mov	c, acc.7
	anl	a, #0x7F
	acall	cout
	jc	pstr2
	sjmp	pstr1
pstr2:	pop	acc
	ret


upper:	;converts the ascii code in Acc to uppercase, if it is lowercase
	push	acc
	clr	c
	subb	a, #97
	jc	upper2		;is it a lowercase character
	subb	a, #26
	jnc	upper2
	pop	acc
	add	a, #224		;convert to uppercase
	ret
upper2: pop	acc		;don't change anything
	ret


lenstr: mov	r0, #0	  ;returns length of a string in r0
	push	acc
lenstr1:clr	a
	movc	a,@a+dptr
	jz	lenstr2
	mov	c,acc.7
	inc	r0
	Jc	lenstr2
	inc	dptr
	sjmp	lenstr1
lenstr2:pop	acc
	ret


esc:  ;checks to see if <ESC> is waiting on serial port
      ;C=clear if no <ESC>, C=set if <ESC> pressed
      ;buffer is flushed
	push	acc
	clr	c
	jnb	ri,esc2
	mov	a,sbuf
	cjne	a,#27,esc1
	setb	c
esc1:	clr	ri
esc2:	pop	acc
	ret


;---------------------------------------------------------;
;							  ;
;    The 'high-level' stuff to interact with the user	  ;
;							  ;
;---------------------------------------------------------;


menu: ;first we print out the prompt, which isn't as simple
      ;as it may seem, since external code can add to the
      ;prompt, so we've got to find and execute all of 'em.
	mov	dptr, #prompt1	  ;give 'em the first part of prompt
	acall	pcstr_h
	mov	a, r7
	acall	phex
	mov	a, r6
	acall	phex
	;mov	 dptr, #prompt2
	acall	pstr

;now we're finally past the prompt, so let's get some input
	acall	cin_filter_h	;get the input, finally
	acall	upper

;push return address onto stack so we can just jump to the program
	mov	b, #(menu & 255)  ;we push the return address now,
	push	b		  ;to save code later...
	mov	b, #(menu >> 8)	  ;if bogus input, just ret for
	push	b		  ;another prompt.



;first we'll look through memory for a program header that says
;it's a user installed command which matches what the user pressed

;user installed commands need to avoid changing R6/R7, which holds
;the memory pointer.  The stack pointer can't be changed obviously.
;all the other general purpose registers should be available for
;user commands to alter as they wish.

menux:	mov	b, a		;now search for external commands...
	mov	dptr, #bmem
menux1: acall	find
	jnc	menuxend	   ;searched all the commands?
	mov	dpl, #4
	clr	a
	movc	a,@a+dptr
	cjne	a, #254, menux2	 ;only FE is an ext command
	inc	dpl
	clr	a
	movc	a,@a+dptr
	cjne	a, b, menux2	  ;only run if they want it
	acall	space
	mov	dpl, #32
	acall	pstr		   ;print command name
	acall	newline
	mov	dpl, #64
	clr	a
	jmp	@a+dptr		;take a leap of faith and jump to it!
menux2: inc	dph
	mov	a, dph
	cjne	a, #((emem+1) >> 8) & 255, menux1
menuxend:
	mov	a, b


;since we didn't find a user installed command, use the builtin ones

menu1a: cjne	a, #help_key, menu1b
	mov	dptr, #help_cmd2
	acall	pcstr_h
	ajmp	help
menu1b: cjne	a, #dir_key, menu1c
	mov	dptr, #dir_cmd
	acall	pcstr_h
	ajmp	dir
menu1c: cjne	a, #run_key, menu1d
	mov	dptr, #run_cmd
	acall	pcstr_h
	ajmp	run
menu1d: cjne	a, #dnld_key, menu1e
	mov	dptr, #dnld_cmd
	acall	pcstr_h
	ajmp	dnld
menu1e: cjne	a, #upld_key, menu1f
	mov	dptr, #upld_cmd
	acall	pcstr_h
	ajmp	upld
menu1f: cjne	a, #nloc_key, menu1g
	mov	dptr, #nloc_cmd
	acall	pcstr_h
	ajmp	nloc
menu1g: cjne	a, #jump_key, menu1h
	mov	dptr, #jump_cmd
	acall	pcstr_h
	ajmp	jump
menu1h: cjne	a, #dump_key, menu1i
	mov	dptr, #dump_cmd
	acall	pcstr_h
	ajmp	dump
menu1i: cjne	a, #edit_key, menu1j
	mov	dptr, #edit_cmd
	acall	pcstr_h
	ajmp	edit
menu1j: cjne	a, #clrm_key, menu1k
	mov	dptr, #clrm_cmd
	acall	pcstr_h
	ajmp	clrm
menu1k: cjne	a, #erfr_key, menu1l
	mov	a, #has_flash
	jz	menu_end
	mov	dptr, #erfr_cmd
	acall	pcstr_h
	ajmp	erfr
menu1l: cjne	a, #intm_key, menu1m
	mov	dptr, #intm_cmd
	acall	pcstr_h
	ljmp	intm
menu1m:

    ;invalid input, no commands to run...
menu_end:			;at this point, we have not found
	ajmp	newline		;anything to run, so we give up.
				;remember, we pushed menu, so newline
				;will just return to menu.

;..........................................................

;---------------------------------------------------------;

;dnlds1 = "Begin sending Intel HEX format file <ESC> to abort"
;dnlds2 = "Download aborted"
;dnlds3 = "Download completed"


;16 byte parameter table: (eight 16 bit values)
;  *   0 = lines received
;  *   1 = bytes received
;  *   2 = bytes written
;  *   3 = bytes unable to write
;  *   4 = incorrect checksums
;  *   5 = unexpected begin of line
;  *   6 = unexpected hex digits (while waiting for bol)
;  *   7 = unexpected non-hex digits (in middle of a line)

dnld:
	mov	dptr, #dnlds1		 
	acall	pcstr_h		   ;"begin sending file <ESC> to abort"
	mov	r0, #dnld_parm
	mov	r2, #16
dnld0:	mov	@r0, #0		;initialize all parameters to 0
	inc	r0
	djnz	r2, dnld0

	  ;look for begining of line marker ':'
dnld1:	acall	cin
	cjne	a, #27, dnld2	;Test for escape
	sjmp	dnld_esc
dnld2:	cjne	a, #':', dnld2b
	mov	r1, #0
	acall	dnld_inc
	sjmp	dnld3
dnld2b:	  ;check to see if it's a hex digit, error if it is
	acall	asc2hex
	jc	dnld1
	mov	r1, #6
	acall	dnld_inc
	sjmp	dnld1
	  ;begin taking in the line of data
dnld3:	mov	a, #'.'
	acall	cout
	mov	r4, #0		;r4 will count up checksum
	acall	dnld_ghex
	mov	r0, a		;R0 = # of data bytes
	acall	dnld_ghex
	mov	dph, a		;High byte of load address
	acall	dnld_ghex
	mov	dpl, a		;Low byte of load address
	acall	dnld_ghex	;Record type
	cjne	a, #1, dnld4	;End record?
	sjmp	dnld_end
dnld4:	jnz	dnld_unknown	;is it a unknown record type???
dnld5:	mov	a, r0
	jz	dnld_get_cksum
	acall	dnld_ghex	;Get data byte
	mov	r2, a
	mov	r1, #1
	acall	dnld_inc	;count total data bytes received
	mov	a, r2
	lcall	smart_wr	;c=1 if an error writing
	clr	a
	addc	a, #2
	mov	r1, a
;     2 = bytes written
;     3 = bytes unable to write
	acall	dnld_inc
	inc	dptr
	djnz	r0, dnld5
dnld_get_cksum:
	acall	dnld_ghex	;get checksum
	mov	a, r4
	jz	dnld1		;should always add to zero
dnld_sumerr:
	mov	r1, #4
	acall	dnld_inc	;all we can do it count # of cksum errors
	sjmp	dnld1

dnld_unknown:	;handle unknown line type
	mov	a, r0
	jz	dnld_get_cksum	;skip data if size is zero
dnld_ukn2:
	acall	dnld_ghex	;consume all of unknown data
	djnz	r0, dnld_ukn2
	sjmp	dnld_get_cksum

dnld_end:   ;handles the proper end-of-download marker
	mov	a, r0
	jz	dnld_end_3	;should usually be zero
dnld_end_2:
	acall	dnld_ghex	;consume all of useless data
	djnz	r0, dnld_ukn2
dnld_end_3:
	acall	dnld_ghex	;get the last checksum
	mov	a, r4
	jnz	dnld_sumerr
	acall	dnld_dly
	mov	dptr, #dnlds3
	acall	pcstr_h		   ;"download went ok..."
	;consume any cr or lf character that may have been
	;on the end of the last line
	jnb	ri, dnld_sum
	acall	cin
	sjmp	dnld_sum



dnld_esc:   ;handle esc received in the download stream
	acall	dnld_dly
	mov	dptr, #dnlds2	 
	acall	pcstr_h		   ;"download aborted."
	sjmp	dnld_sum

dnld_dly:   ;a short delay since most terminal emulation programs
	    ;won't be ready to receive anything immediately after
	    ;they've transmitted a file... even on a fast Pentium(tm)
	    ;machine with 16550 uarts!
	mov	r0, #0
dnlddly2:mov	r1, #0
	djnz	r1, *		;roughly 128k cycles, appox 0.1 sec
	djnz	r0, dnlddly2
	ret

dnld_inc:     ;increment parameter specified by R1
	      ;note, values in Acc and R1 are destroyed
	mov	a, r1
	anl	a, #00000111b	;just in case
	rl	a
	add	a, #dnld_parm
	mov	r1, a		;now r1 points to lsb
	inc	@r1
	mov	a, @r1
	jnz	dnldin2
	inc	r1
	inc	@r1
dnldin2:ret

dnld_gp:     ;get parameter, and inc to next one (@r1)
	     ;carry clear if parameter is zero.
	     ;16 bit value returned in dptr
	setb	c
	mov	dpl, @r1
	inc	r1
	mov	dph, @r1
	inc	r1
	mov	a, dpl
	jnz	dnldgp2
	mov	a, dph
	jnz	dnldgp2
	clr	c
dnldgp2:ret



;a spacial version of ghex just for the download.  Does not
;look for carriage return or backspace.	 Handles ESC key by
;poping the return address (I know, nasty, but it saves many
;bytes of code in this 4k ROM) and then jumps to the esc
;key handling.	This ghex doesn't echo characters, and if it
;sees ':', it pops the return and jumps to an error handler
;for ':' in the middle of a line.  Non-hex digits also jump
;to error handlers, depending on which digit.
	  
dnld_ghex:
dnldgh1:acall	cin
	acall	upper
	cjne	a, #27, dnldgh3
dnldgh2:pop	acc
	pop	acc
	sjmp	dnld_esc
dnldgh3:cjne	a, #':', dnldgh5
dnldgh4:mov	r1, #5		;handle unexpected beginning of line
	acall	dnld_inc
	pop	acc
	pop	acc
	ajmp	dnld3		;and now we're on a new line!
dnldgh5:acall	asc2hex
	jnc	dnldgh6
	mov	r1, #7
	acall	dnld_inc
	sjmp	dnldgh1
dnldgh6:mov	r2, a		;keep first digit in r2
dnldgh7:acall	cin
	acall	upper
	cjne	a, #27, dnldgh8
	sjmp	dnldgh2
dnldgh8:cjne	a, #':', dnldgh9
	sjmp	dnldgh4
dnldgh9:acall	asc2hex
	jnc	dnldghA
	mov	r1, #7
	acall	dnld_inc
	sjmp	dnldgh7
dnldghA:xch	a, r2
	swap	a
	orl	a, r2
	mov	r2, a
	add	a, r4		;add into checksum
	mov	r4, a
	mov	a, r2		;return value in acc
	ret

;dnlds4 =  "Summary:"
;dnlds5 =  " lines received"
;dnlds6a = " bytes received"
;dnlds6b = " bytes written"

dnld_sum:    ;print out download summary
	mov	a, r6
	push	acc
	mov	a, r7
	push	acc
	mov	dptr, #dnlds4
	acall	pcstr_h
	mov	r1, #dnld_parm
	mov	r6, #dnlds5 & 255
	mov	r7, #dnlds5 >> 8
	acall	dnld_i0
	mov	r6, #dnlds6a & 255
	mov	r7, #dnlds6a >> 8
	acall	dnld_i0
	mov	r6, #dnlds6b & 255
	mov	r7, #dnlds6b >> 8
	acall	dnld_i0

dnld_err:    ;now print out error summary
	mov	r2, #5
dnlder2:acall	dnld_gp
	jc	dnlder3		;any errors?
	djnz	r2, dnlder2
	 ;no errors, so we print the nice message
	mov	dptr, #dnlds13
	acall	pcstr_h
	sjmp	dlnd_sum_done

dnlder3:  ;there were errors, so now we print 'em
	mov	dptr, #dnlds7
	acall	pcstr_h
	  ;but let's not be nasty... only print if necessary
	mov	r1, #(dnld_parm+6)
	mov	r6, #dnlds8 & 255
	mov	r7, #dnlds8 >> 8
	acall	dnld_item
	mov	r6, #dnlds9 & 255
	mov	r7, #dnlds9 >> 8
	acall	dnld_item
	mov	r6, #dnlds10 & 255
	mov	r7, #dnlds10 >> 8
	acall	dnld_item
	mov	r6, #dnlds11 & 255
	mov	r7, #dnlds11 >> 8
	acall	dnld_item
	mov	r6, #dnlds12 & 255
	mov	r7, #dnlds12 >> 8
	acall	dnld_item
dlnd_sum_done:
	pop	acc
	mov	r7, a
	pop	acc
	mov	r6, a
	ajmp	newline

dnld_item:
	acall	dnld_gp		;error conditions
	jnc	dnld_i3
dnld_i2:acall	space
	lcall	pint16u
	acall	r6r7todptr
	acall	pcstr_h
dnld_i3:ret

dnld_i0:acall	dnld_gp		;non-error conditions
	sjmp	dnld_i2


;dnlds7:  = "Errors:"
;dnlds8:  = " bytes unable to write"
;dnlds9:  = " incorrect checksums"
;dnlds10: = " unexpected begin of line"
;dnlds11: = " unexpected hex digits"
;dnlds12: = " unexpected non-hex digits"
;dnlds13: = "No errors detected"



;---------------------------------------------------------;


jump:
	mov	dptr, #prompt8
	acall	pcstr_h
	acall	r6r7todptr
	acall	phex16
	mov	dptr, #prompt4
	acall	pcstr_h
	acall	ghex16
	jb	psw.5, jump3
	jnc	jump2
	ajmp	abort2
jump2:
	acall	dptrtor6r7
jump3:	acall	newline
	mov	dptr, #runs1
	acall	pcstr_h
	acall	r6r7todptr

jump_doit:  ;jump to user code @dptr (this used by run command also)
	clr	a
	mov	psw, a
	mov	b, a
	mov	r0, a
	mov	r1, a
	mov	r2, a
	mov	r3, a
	mov	r4, a
	mov	r5, a
	mov	r6, a
	mov	r7, a
	mov	sp, #8		;start w/ sp=7, like a real reset
	push	acc		;unlike a real reset, push 0000
	push	acc		;in case they end with a RET
	jmp	@a+dptr


;---------------------------------------------------------;

dump:	
	mov	r2, #16		;number of lines to print
	acall	newline2
dump1:	acall	r6r7todptr
	acall	phex16		;tell 'em the memory location
	mov	a,#':'
	acall	cout_sp
	mov	r3, #16		;r3 counts # of bytes to print
	acall	r6r7todptr
dump2:	clr	a
	movc	a, @a+dptr
	inc	dptr
	acall	phex		;print each byte in hex
	acall	space
	djnz	r3, dump2
	acall	dspace		;print a couple extra space
	mov	r3, #16
	acall	r6r7todptr
dump3:	clr	a
	movc	a, @a+dptr
	inc	dptr
	anl	a, #01111111b	;avoid unprintable characters
	cjne	a, #127, dump3b
	clr	a		;avoid 127/255 (delete/rubout) char
dump3b: add	a, #224
	jc	dump4
	clr	a		;avoid control characters
dump4:	add	a, #32
	acall	cout
	djnz	r3, dump3
	acall	newline
	acall	line_dly
	acall	dptrtor6r7
	acall	esc
	jc	dump5
	djnz	r2, dump1	;loop back up to print next line
dump5:	ajmp	newline

;---------------------------------------------------------;

edit:	   ;edit external ram...
	mov	dptr, #edits1
	acall	pcstr_h
	acall	r6r7todptr
edit1:	acall	phex16
	mov	a,#':'
	acall	cout_sp
	mov	a,#'('
	acall	cout
	acall	dptrtor6r7
	clr	a
	movc	a, @a+dptr
	acall	phex
	mov	dptr,#prompt10
	acall	pcstr_h
	acall	ghex
	jb	psw.5,edit2
	jc	edit2
	acall	r6r7todptr
	lcall	smart_wr
	acall	newline
	acall	r6r7todptr
	inc	dptr
	acall	dptrtor6r7
	ajmp	edit1
edit2:	mov	dptr,#edits2
	ajmp	pcstr_h

;---------------------------------------------------------;

dir:
	mov	dptr, #prompt9
	acall	pcstr_h
	mov	r0, #21
dir0a:	acall	space
	djnz	r0, dir0a
	;mov	dptr, #prompt9b
	acall	pcstr_h

	mov	dph, #(bmem >> 8)
dir1:	acall	find		;find the next program in memory
	jc	dir2
dir_end:ajmp	newline		;we're done if no more found
dir2:
	acall	dspace
	mov	dpl, #32	;print its name
	acall	pstr
	mov	dpl, #32	;how long is the name
	acall	lenstr
	mov	a, #33
	clr	c
	subb	a, r0
	mov	r0, a
	mov	a, #' '		;print the right # of spaces
dir3:	acall	cout
	djnz	r0, dir3
	mov	dpl, #0
	acall	phex16		;print the memory location
	mov	r0, #6
	mov	a, #' '
dir4:	acall	cout
	djnz	r0, dir4
	mov	dpl, #4		;now figure out what type it is
	clr	a
	movc	a, @a+dptr
	mov	r2, dph		;save this, we're inside a search

dir5:	cjne	a, #254, dir5b
	mov	dptr, #type1	;it's an external command
	sjmp	dir7
dir5b:	cjne	a, #253, dir5c
dir5bb: mov	dptr, #type4	;it's a startup routine
	sjmp	dir7
dir5c:	cjne	a, #35, dir5d
	mov	dptr, #type2	;it's an ordinary program
	sjmp	dir7
dir5d:	cjne	a, #249, dir5e
	sjmp	dir5bb
dir5e:
dir6:	mov	dptr, #type5	;who knows what the hell it is

dir7:	acall	pcstr_h		   ;print out the type
	mov	dph, r2		;go back and find the next one
	acall	newline
	mov	a, #(emem >> 8)
	cjne	a, dph, dir8	;did we just print the last one?
	ajmp	dir_end
dir8:	inc	dph
	mov	a, dph
	cjne	a, #((emem+1) >> 8) & 255, dir1
	ajmp	dir_end


;type1=Ext Command
;type4=Startup
;type2=Program
;type5=???

;---------------------------------------------------------;


run:   
	acall	newline2
	mov	r2, #255	;first print the menu, count items
	mov	dptr, #bmem
	dec	dph
run2:	inc	dph
	mov	a, dph
	cjne	a, #((emem+1) >> 8) & 255, run2b
	sjmp	run3
run2b:	acall	find
	jnc	run3		;have we found 'em all??
	mov	dpl, #4
	clr	a
	movc	a, @a+dptr
	orl	a, #00000011b
	cpl	a
	jz	run2		;this one doesn't run... find next
	acall	dspace
	inc	r2
	mov	a, #'A'		;print the key to press
	add	a, r2
	acall	cout_sp
	acall	dash_sp
	mov	dpl, #32
	acall	pstr		;and the command name
	acall	newline
	ajmp	run2		;and continue doing this
run3:	cjne	r2, #255, run4	;are there any to run??
	mov	dptr, #prompt5
	ajmp	pcstr_h
run4:	mov	dptr, #prompt3	;ask the big question!
	acall	pcstr_h
	mov	a, #'A'
	acall	cout
	acall	dash
	mov	a, #'A'		;such user friendliness...
	add	a, r2		;even tell 'em the choices
	acall	cout
	mov	dptr, #prompt4
	acall	pcstr_h
	acall	cin_filter_h
	cjne	a, #27, run4aa	;they they hit <ESC>
	ajmp	newline
run4aa: mov	r3, a
	mov	a, #31
	clr	c
	subb	a, r2
	mov	a, r3
	jc	run4a
	acall	upper
run4a:	acall	cout
	mov	r3, a
	acall	newline
	;check to see if it's under 32, if so convert to uppercase
	mov	a, r3
	clr	c
	subb	a, #'A'
	jc	run4		;if they typed less than 'A'
	mov	r3, a		;R3 has the number they typed
	mov	a, r2		;A=R2 has the maximum number
	clr	c
	subb	a, r3
	jc	run4		;if they typed over the max
	inc	r3
	mov	dptr, #bmem
	dec	dph
run5:	inc	dph
	mov	a, dph
	cjne	a, #((emem+1) >> 8) & 255, run5b
	sjmp	run8
run5b:	acall	find
	jnc	run8		;Shouldn't ever do this jump!
	mov	dpl, #4
	clr	a
	movc	a, @a+dptr
	orl	a, #00000011b
	cpl	a
	jz	run5		;this one doesn't run... find next
	djnz	r3, run5	;count til we find the one they want
	acall	newline
	mov	dpl, #64
	ajmp	jump_doit
run8:	ret

;---------------------------------------------------------;

help:
	mov	dptr, #help1txt
	acall	pcstr_h
	mov	r4, #help_key
	mov	dptr, #help_cmd
	acall	help2
	mov	r4, #dir_key
	;mov	 dptr, #dir_cmd
	acall	help2
	mov	r4, #run_key
	;mov	 dptr, #run_cmd
	acall	help2
	mov	r4, #dnld_key
	;mov	 dptr, #dnld_cmd
	acall	help2
	mov	r4, #upld_key
	;mov	 dptr, #upld_cmd
	acall	help2
	mov	r4, #nloc_key
	;mov	 dptr, #nloc_cmd
	acall	help2
	mov	r4, #jump_key
	;mov	 dptr, #jump_cmd
	acall	help2
	mov	r4, #dump_key
	;mov	 dptr, #dump_cmd
	acall	help2
	mov	r4, #intm_key
	;mov	dptr, #intm_cmd
	acall	help2
	mov	r4, #edit_key
	;mov	 dptr, #edit_cmd
	acall	help2
	mov	r4, #clrm_key
	;mov	 dptr, #clrm_cmd
	acall	help2
	mov	a, #has_flash
	jz	help_skerfm
	mov	r4, #erfr_key
	;mov	 dptr, #erfr_cmd
	acall	help2
help_skerfm:
	mov	dptr, #help2txt
	acall	pcstr_h
	mov	dptr, #bmem
help3:	acall	find
	jnc	help4
	mov	dpl, #4
	clr	a
	movc	a,@a+dptr
	cjne	a, #254, help3a	   ;only FE is an ext command
	acall	dspace
	inc	dpl
	clr	a
	movc	a,@a+dptr
	acall	cout
	acall	dash_sp
	mov	dpl, #32
	acall	pstr
	acall	newline
help3a: inc	dph
	mov	a, dph
	cjne	a, #((emem+1) >> 8) & 255, help3
help4:	
	ajmp	newline

help2:				;print 11 standard lines
	acall	dspace		;given key in R4 and name in dptr
	mov	a, r4
	acall	cout
	acall	dash_sp
	acall	pcstr_h
	ajmp	newline

;---------------------------------------------------------;

upld:

	acall	get_mem
	;assume we've got the beginning address in r3/r2
	;and the final address in r5/r4 (r4=lsb)...

	;print out what we'll be doing
	mov	dptr, #uplds3
	acall	pcstr_h
	mov	a, r3
	acall	phex
	mov	a, r2
	acall	phex
	;mov	 dptr, #uplds4
	acall	pcstr_h
	mov	a, r5
	acall	phex
	mov	a, r4
	acall	phex
	acall	newline

	;need to adjust end location by 1...
	mov	dph, r5
	mov	dpl, r4
	inc	dptr
	mov	r4, dpl
	mov	r5, dph

	mov	dptr, #prompt7
	acall	pcstr_h
	acall	cin
	cjne	a, #27, upld2e
	ajmp	abort_it
upld2e: acall	newline
	mov	dpl, r2
	mov	dph, r3

upld3:	mov	a, r4		;how many more bytes to output??
	clr	c
	subb	a, dpl
	mov	r2, a
	mov	a, r5
	subb	a, dph
	jnz	upld4		;if >256 left, then do next 16
	mov	a, r2
	jz	upld7		;if we're all done
	anl	a, #11110000b
	jnz	upld4		;if >= 16 left, then do next 16
	sjmp	upld5		;otherwise just finish it off
upld4:	mov	r2, #16
upld5:	mov	a, #':'		;begin the line
	acall	cout
	mov	a, r2
	acall	phex		;output # of data bytes
	acall	phex16		;output memory location
	mov	a, dph
	add	a, dpl
	add	a, r2
	mov	r3, a		;r3 will become checksum
	clr	a
	acall	phex		;output 00 code for data
upld6:	clr	a
	movc	a, @a+dptr
	acall	phex		;output each byte
	add	a, r3
	mov	r3, a
	inc	dptr
	djnz	r2, upld6	;do however many bytes we need
	mov	a, r3
	cpl	a
	inc	a
	acall	phex		;and finally the checksum
	acall	newline
	acall	line_dly
	acall	esc
	jnc	upld3		;keep working if no esc pressed
	sjmp	abort_it
upld7:	mov	a, #':'
	acall	cout
	clr	a
	acall	phex
	acall	phex
	acall	phex
	inc	a
	acall	phex
	mov	a, #255
	acall	phex
upld8:	ajmp	newline2


line_dly: ;a brief delay between line while uploading, so the
	;receiving host can be slow (i.e. most windows software)
	mov	a, r0
	push	acc
	mov	r0, #line_delay*2
line_d2:mov	a, th0		;get baud rate const
line_d3:inc	a
	nop
	nop
	jnz	line_d3
	djnz	r0, line_d2
	pop	acc
	mov	r0, a
	ret

;---------------------------------------------------------;

get_mem:     ;this thing gets the begin and end locations for
	     ;a few commands.  If an esc or enter w/ no input,
	     ;it pops it's own return and returns to the menu
	     ;(nasty programming, but we need tight code for 4k rom)
	acall	newline2
	mov	dptr, #beg_str
	acall	pcstr_h
	acall	ghex16
	jc	pop_it
	jb	psw.5, pop_it
	push	dph
	push	dpl
	acall	newline
	mov	dptr, #end_str
	acall	pcstr_h
	acall	ghex16
	mov	r5, dph
	mov	r4, dpl
	pop	acc
	mov	r2, a
	pop	acc
	mov	r3, a
	jc	pop_it
	jb	psw.5, pop_it
	ajmp	newline

pop_it: pop	acc
	pop	acc
abort_it:
	acall	newline
abort2: mov	dptr, #abort
	ajmp	pcstr_h


clrm:
	acall	get_mem
	mov	dptr, #sure
	acall	pcstr_h
	acall	cin_filter_h
	acall	upper
	cjne	a, #'Y', abort_it
	acall	newline2
     ;now we actually do it

clrm2:	mov	dph, r3
	mov	dpl, r2
clrm3:	clr	a
	lcall	smart_wr
	mov	a, r5
	cjne	a, dph, clrm4
	mov	a, r4
	cjne	a, dpl, clrm4
	ret
clrm4:	inc	dptr
	sjmp	clrm3

;---------------------------------------------------------;

nloc:
	mov	dptr, #prompt6
	acall	pcstr_h
	acall	ghex16
	jc	abort2
	jb	psw.5, abort2
	acall	dptrtor6r7
	ajmp	newline2

;---------------------------------------------------------;

erfr:
	acall	newline2
	mov	dptr, #erfr_cmd
	acall	pcstr_h
	mov	a, #','
	acall	cout_sp
	mov	dptr, #sure
	acall	pcstr_h
	acall	cin_filter_h
	acall	upper
	cjne	a, #'Y', abort_it
	acall	newline2
	lcall	erall
	mov	dptr, #erfr_ok
	jnc	erfr_end
	mov	dptr, #erfr_err
erfr_end:
	ajmp	pcstr_h



;---------------------------------------------------------;

intm:	acall	newline
	mov	r0, #0
intm2:	acall	newline
	cjne	r0, #0x80, intm3 
	ajmp	newline
intm3:	mov	a, r0
	acall	phex
	mov	a, #':'
	acall	cout
intm4:	acall	space
	mov	a, @r0
	acall	phex
	inc	r0
	mov	a, r0
	anl	a, #00001111b
	jnz	intm4
	sjmp	intm2





;**************************************************************
;**************************************************************
;*****							  *****
;*****	     2k page boundry is somewhere near here	  *****
;*****	       (no ajmp or acall past this point)	  *****
;*****							  *****
;**************************************************************
;**************************************************************



;---------------------------------------------------------;
;							  ;
;   Subroutines for memory managment and non-serial I/O	  ;
;							  ;
;---------------------------------------------------------;


;finds the next header in the external memory.
;  Input DPTR=point to start search (only MSB used)
;  Output DPTR=location of next module
;    C=set if a header found, C=clear if no more headers
find:	mov	dpl, #0
	clr	a
	movc	a, @a+dptr
	cjne	a, #0xA5, find3
	inc	dptr
	clr	a
	movc	a, @a+dptr
	cjne	a, #0xE5, find3
	inc	dptr
	clr	a
	movc	a, @a+dptr
	cjne	a, #0xE0, find3
	inc	dptr
	clr	a
	movc	a, @a+dptr
	cjne	a, #0xA5, find3
	mov	dpl, #0			;found one here!
	setb	c
	ret
find3:	mov	a, #(emem >> 8)
	cjne	a, dph, find4		;did we just check the end
	clr	c
	ret
find4:	inc	dph			;keep on searching
	sjmp	find



;routine that erases the whole flash rom!  C=1 if failure, C=0 if ok

erall:	mov	a, #has_flash
	jz	erallno
	mov	dptr, #bflash		;is it already erased ??
erall0: clr	a
	movc	a, @a+dptr
	cpl	a
	jnz	erall_b			;do actual erase if any byte not 255
	inc	dptr
	mov	a, #((eflash+1) & 255)
	cjne	a, dpl, erall0
	mov	a, #(((eflash+1) >> 8) & 255)
	cjne	a, dph, erall0
	;if we get here, the entire chip was already erased,
	;so there is no need to do anything
	clr	c
	ret
erall_b:
	mov	dptr, #bflash		;first program to all 00's
erall1: clr	a
	movc	a, @a+dptr
	jz	erall2			;don't waste time!
	clr	a
	lcall	prgm			;ok, program this byte
	;if the program operation failed... we should abort because
	;they are all likely to fail and it will take a long time...
	;which give the appearance that the program has crashed,
	;when it's really following the flash rom algorithm
	;correctly and getting timeouts.
	jc	erallno
	;mov	a, #'.'
	;lcall	cout
erall2: inc	dptr
	mov	a, #((eflash+1) & 255)
	cjne	a, dpl, erall1
	mov	a, #(((eflash+1) >> 8) & 255)
	cjne	a, dph, erall1		;after this it's all 00's
	mov	dptr, #bflash		;beginning address
	mov	r4, #232		;max # of trials, lsb
	mov	r5, #4			;max # of trials, msb-1
erall3: 
	;mov	a, #'#'
	;lcall	cout
	djnz	r4, erall3a
	djnz	r5, erall3a
erallno:setb	c
	ret				;if it didn't work!
erall3a:mov	a, #0x20
	mov	c, ea		 ;-	;turn off all interrupts!!
	mov	psw.1, c
	clr	ea
	movx	@dptr, a		;send the erase setup
	movx	@dptr, a		;and begin the erase
	mov	r3, #erwait1
erwt:	mov	r2, #erwait2		;now wait 10ms...
	djnz	r2, *
	djnz	r3, erwt
erall4: mov	a, #0xA0
	movx	@dptr, a		;send erase verify
	mov	r2, #verwait		;wait for 6us
	djnz	r2, *
	clr	a
	movc	a, @a+dptr
	mov	c, psw.1
	mov	ea, c		;-     ;turn interrupts back on
	cpl	a
	jnz	erall3			;erase again if not FF
	inc	dptr
	mov	a, #(((eflash+1) >> 8) & 255)  ;verify whole array
	cjne	a, dph, erall4
	mov	a, #((eflash+1) & 255)
	cjne	a, dpl, erall4
	mov	a, #255
	mov	dptr, #bflash
	movx	@dptr, a		;reset the flash rom
	clr	a
	movx	@dptr, a		;and go back to read mode
	clr	c
	ret




;a routine that writes ACC to into flash memory at DPTR
; assumes that Vpp is active and stable already.
; C is set if error occurs, C is clear if it worked

prgm:	mov	b, a
	mov	a, r2
	push	acc
	mov	a, r3
	push	acc
	mov	r2, #25	       ;try to program 25 times if needed
prgm2:	mov	a, #40h
	mov	c, ea		 ;-	;turn off all interrupts!!
	mov	psw.1, c
	clr	ea
	movx	@dptr, a	;send setup programming command
	mov	a, b
	movx	@dptr, a	;write to the cell
	mov	r3, #pgmwait	;now wait for 10us
	djnz	r3, *
	mov	a, #0xC0
	movx	@dptr, a	;send program verify command
	mov	r3, #verwait	;wait 6us while it adds margin
	djnz	r3, *
	clr	a
	movc	a, @a+dptr
	mov	c, psw.1
	mov	ea, c		;-     ;turn interrupts back on
	clr	c
	subb	a, b
	jz	prgmok		;note, C is still clear is ACC=0
	djnz	r2, prgm2
prgmbad:setb	c		;it gets here if programming failure
prgmok: clr	a
	movx	@dptr, a	;and go back into read mode
	pop	acc
	mov	r3, a
	pop	acc
	mov	r2, a
	mov	a, b		;restore ACC to original value
	ret



;************************************
;To make PAULMON2 able to write to other
;types of memory than RAM and flash rom,
;modify this "smart_wr" routine.  This
;code doesn't accept any inputs other
;that the address (dptr) and value (acc),
;so this routine must know which types
;of memory are in what address ranges
;************************************


;Write to Flash ROM or ordinary RAM.  Carry bit will indicate
;if the value was successfully written, C=1 if not written.


smart_wr:
	push	acc
	push	b
	mov	b, a
	;do we even have a flash rom?
	mov	a, #has_flash
	jz	wr_ram
	;there is a flash rom, but is this address in it?
	mov	a, dph
	cjne	a, #(eflash >> 8), isfl3
	sjmp	wr_flash
isfl3:	jnc	wr_ram
	cjne	a, #(bflash >> 8), isfl4
	sjmp	wr_flash
isfl4:	jnc	wr_flash
	sjmp	wr_ram

wr_flash:
	mov	a, b
	acall	prgm
	pop	b
	pop	acc
	ret

wr_ram: mov	a, b
	movx	@dptr, a	;write the value to memory
	clr	a
	movc	a, @a+dptr	;read it back from code memory
	clr	c
	subb	a, b
	jz	smwrok
	movx	a, @dptr	;read it back from data memory
	clr	c
	subb	a, b
	jz	smwrok
smwrbad:setb	c
	sjmp	smwrxit
smwrok: clr	c
smwrxit:pop	b
	pop	acc
	ret




;---------------------------------------------------------;
;							  ;
;	Power-On initialization code and such...	  ;
;							  ;
;---------------------------------------------------------;

;first the hardware has to get initialized.

intr_return:
	reti

poweron:
	clr	a
	mov	ie, a		;all interrupts off
	mov	ip, a
	mov	psw, #psw_init
	;clear any interrupt status, just in case the user put
	;"ljmp 0" inside their interrupt service code.
	acall	intr_return
	acall	intr_return
	cpl	a
	mov	p0, a
	mov	p1, a
	mov	p2, a
	mov	p3, a
	mov	sp, #stack

;Before we start doing any I/O, a short delay is required so
;that any external hardware which may be in "reset mode" can
;initialize.  This is typically a problem when a 82C55 chip
;is used and its reset line is driven from the R-C reset
;circuit used for the 8051.  Because the 82C55 reset pin
;switches from zero to one at a higher voltage than the 8051,
;any 82C55 chips would still be in reset mode right now...

rst_dly:
	mov	r1, #200	;approx 100000 cycles
rdly2:	mov	r2, #249	;500 cycles
	djnz	r2, *
	djnz	r1, rdly2

;Check for the Erase-on-startup signal and erase Flash ROM 
;if it's there.

	mov	a, #has_flash
	jz	skip_erase
	mov	a, #erase_pin
	jz	skip_erase
	mov	r0, #250	;check it 250 times, just to be sure
chk_erase:
	mov	c, erase_pin
	mov	r1, #200
	djnz	r1, *		;short delay
	jc	skip_erase	;skip erase if this bit is not low
	djnz	r0, chk_erase
	lcall	erall		;and this'll delete the flash rom
skip_erase:

;run any user initialization programs in external memory
	mov	b, #249
	acall	stcode

;initialize the serial port, auto baud detect if necessary
	acall	autobaud	;set up the serial port
	;mov	a, th1
	;lcall	phex

;run the start-up programs in external memory.
	mov	b, #253
	acall	stcode

;now print out the nice welcome message

welcome:
	mov	r0, #24
welcm2: lcall	newline
	djnz	r0, welcm2
	mov	r0, #15
	mov	a, #' '
welcm4: lcall	cout
	djnz	r0, welcm4
	mov	dptr, #logon1
	lcall	pcstr
	mov	dptr, #logon2
	lcall	pcstr
	lcall	dir
	mov	r6, #(pgm & 255)
	mov	r7, #(pgm >> 8)
	ljmp	menu


stcode: mov	dptr, #bmem	 ;search for startup routines
stcode2:lcall	find
	jnc	stcode5
	mov	dpl, #4
	clr	a
	movc	a, @a+dptr
	cjne	a, b, stcode4	;only startup code if matches B
	push	b
	push	dph
	mov	a, #(stcode3 & 255)
	push	acc
	mov	a, #(stcode3 >> 8)
	push	acc
	mov	dpl, #64
	clr	a
	jmp	@a+dptr		;jump to the startup code
stcode3:pop	dph		;hopefully it'll return to here
	pop	b
stcode4:inc	dph
	mov	a, dph
	cjne	a, #((emem+1) >> 8) & 255, stcode2
stcode5:ret			;now we've executed all of 'em


;to do automatic baud rate detection, we assume the user will
;press the carriage return, which will cause this bit pattern
;to appear on port 3 pin 0 (CR = ascii code 13, assume 8N1 format)
;
;	       0 1 0 1 1 0 0 0 0 1
;	       | |	       | |
; start bit----+ +--lsb	  msb--+ +----stop bit
;
;we'll start timer #1 in 16 bit mode at the transition between the
;start bit and the LSB and stop it between the MBS and stop bit.
;That will give approx the number of cpu cycles for 8 bits.  Divide
;by 8 for one bit and by 16 since the built-in UART takes 16 timer
;overflows for each bit.  We need to be careful about roundoff during
;division and the result has to be inverted since timer #1 counts up.  Of
;course, timer #1 gets used in 8-bit auto reload mode for generating the
;built-in UART's baud rate once we know what the reload value should be.


autobaud:
	mov	a, #baud_const	;skip if user supplied baud rate constant
	jnz	autoend_jmp
	mov	a, baud_save+3	;is there a value from a previous boot?
	xrl	baud_save+2, #01010101b
	xrl	baud_save+1, #11001100b
	xrl	baud_save+0, #00011101b
	cjne	a, baud_save+2, autob1
	cjne	a, baud_save+1, autob1
	cjne	a, baud_save+0, autob1
autoend_jmp:
	ajmp	autoend

autob1: ;wait for inactivity

	mov	pcon, #0x80	;configure uart, fast baud
	mov	scon, #0x42	;configure uart, but receive disabled
	mov	tmod, #0x11	;get timers ready for action (16 bit mode)
	clr	a
	mov	tcon, a
	mov	tl0, a
	mov	th0, a
	mov	tl1, a
	mov	th1, a

	;make sure there is no activity on the line
	;before we actually begin looking for the carriage return
	mov	r0, #200
autob1b:mov	r1, #30
autob1c:jnb	p3.0, autob1
	djnz	r1, autob1c
	djnz	r0, autob1b

autob2: ;look for the bits of the carriage return
	jb	p3.0, autob2	;wait for start bit
	jb	p3.0, autob2
	jb	p3.0, autob2	;  check it a few more times to make
	jb	p3.0, autob2	;  sure we don't trigger on some noise
	jb	p3.0, autob2
autob2b:jnb	p3.0, autob2b	;wait for bit #0 to begin
	setb	tr1		;and now we're timing it
autob2c:jb	tf1, autob1	;check for timeout while waiting
	jb	p3.0, autob2c	;wait for bit #1 to begin
autob2d:jb	tf1, autob1	;check for timeout while waiting
	jnb	p3.0, autob2d	;wait for bit #2 to begin
autob2e:jb	tf1, autob1	;check for timeout while waiting
	jb	p3.0, autob2e	;wait for bit #4 to begin
	setb	tr0		;start timing last 4 bits
autob2f:jb	tf1, autob1	;check for timeout while waiting
	jnb	p3.0, autob2f	;wait for stop bit to begin
	clr	tr1		;stop timing (both timers)
	clr	tr0

	jb	tf1, autob1	;check for timeout one last time

	;compute the baud rate based on timer1
	mov	a, tl1
	rlc	a
	mov	b, a
	mov	a, th1
	rlc	a
	jc	autob1		;error if timer0 > 32767
	mov	c, b.7
	addc	a, #0
	cpl	a
	inc	a		;now a has the value to load into th1
	jz	autob1		;error if baud rate too fast

	;after we get the carriage return, we need to make sure there
	;isn't any "crap" on the serial line, as there is in the case
	;were we get the letter E (and conclude the wrong baud rate).
	;unfortunately the simple approach of just looking at the line
	;for silence doesn't work, because we have to accept the case
	;where the user's terminal emulation is configured to send a
	;line feed after the carriage return.  The best thing to do is
	;use the uart and look see if it receives anything

autob3: mov	th1, a		;config timer1
	mov	tl1, #255	;start asap!
	mov	tmod, #0x21	;autoreload mode
	setb	ren		;turn on the uart
	setb	tr1		;turn on timer1 for its clock

	mov	a, th1
	cpl	a
	inc	a
	mov	r1, a
autob3b:mov	r0, #255
autob3c:djnz	r0, autob3c
	djnz	r1, autob3b

	jnb	ri, autob4
	;if we got here, there was some stuff after the carriage
	;return, so we'll read it and see if it was the line feed
	clr	ri
	mov	a, sbuf
	anl	a, #01111111b
	add	a, #246
	jz	autob4		;ok if 0A, the line feed character
	add	a, #5
	jz	autob4		;of if 05, since we may have missed start bit
autob1_jmp:
	ljmp	autob1
autob4:
	;compute the baud rate based on timer0, check against timer1 value
	mov	a, tl0
	rlc	a
	mov	r0, a
	mov	a, th0
	rlc	a
	mov	r1, a
	jc	autob1_jmp	;error if timer0 > 32767
	mov	a, r0
	rlc	a
	mov	b, a
	mov	a, r1
	rlc	a
	mov	c, b.7
	addc	a, #0
	jz	autob1_jmp	;error if baud too fast!
	cpl	a
	inc	a
	cjne	a, th1, autob1_jmp
	;acc has th1 value at this point

autoend:mov	baud_save+3, a
	mov	baud_save+2, a	;store the baud rate for next warm boot.
	mov	baud_save+1, a
	mov	baud_save+0, a
	xrl	baud_save+2, #01010101b
	xrl	baud_save+1, #11001100b 
	xrl	baud_save+0, #00011101b 
	mov	th1, a
	mov	tl1, a
	mov	tmod, #0x21	;set timer #1 for 8 bit auto-reload
	mov	pcon, #0x80	;configure built-in uart
	mov	scon, #0x52
	setb	tr1		;start the baud rate timer
	ret



;---------------------------------------------------------;
;							  ;
;     More subroutines, but less frequent used, so	  ;
;     they're down here in the second 2k page.		  ;
;							  ;
;---------------------------------------------------------;



;this twisted bit of code looks for escape sequences for
;up, down, left, right, pageup, and pagedown, as well
;as ordinary escape and ordinary characters.  Escape
;sequences are required to arrive with each character
;nearly back-to-back to the others, otherwise the characters
;are treated as ordinary user keystroaks.  cin_filter
;returns a single byte when it sees the multi-byte escape
;sequence, as shown here.

; return value	 key	      escape sequence
;   11 (^K)	 up	      1B 5B 41
;   10 (^J)	 down	      1B 5B 42
;   21 (^U)	 right	      1B 5B 43
;    8 (^H)	 left	      1B 5B 44
;   25 (^Y)	 page up      1B 5B 35 7E
;   26 (^Z)	 page down    1B 5B 36 7E

.equ	esc_char, 27

cin_filter:
	jnb	ri, cinf1
	lcall	cin
	cjne	a, #esc_char, cinf_end
	;if esc was already in sbuf, just ignore it
cinf1:	lcall	cin
	cjne	a, #esc_char, cinf_end
cinf2:	acall	cinf_wait
	jb	ri, cinf4
	mov	a, #esc_char
	ret			;an ordinary ESC

cinf4:	;if we get here, it's a control code, since a character
	;was received shortly after receiving an ESC character
	lcall	cin
	cjne	a, #'[', cinf_consume
	acall	cinf_wait
	jnb	ri, cin_filter
	lcall	cin
cinf5a: cjne	a, #'A', cinf5b
	mov	a, #11
	ret
cinf5b: cjne	a, #'B', cinf5c
	mov	a, #10
	ret
cinf5c: cjne	a, #'C', cinf5d
	mov	a, #21
	ret
cinf5d: cjne	a, #'D', cinf5e
	mov	a, #8
	ret
cinf5e: cjne	a, #0x35, cinf5f
	sjmp	cinf8
cinf5f: cjne	a, #0x36, cinf5g
	sjmp	cinf8
cinf5g: sjmp	cinf_consume		;unknown escape sequence

cinf8:	;when we get here, we've got the sequence for pageup/pagedown
	;but there's one more incoming byte to check...
	push	acc
	acall	cinf_wait
	jnb	ri, cinf_restart
	lcall	cin
	cjne	a, #0x7E, cinf_notpg
	pop	acc
	add	a, #228
cinf_end: ret
cinf_restart:
	pop	acc
	sjmp	cin_filter
cinf_notpg:
	pop	acc
;unrecognized escape... eat up everything that's left coming in
;quickly, then begin looking again
cinf_consume:
	acall	cinf_wait
	jnb	ri, cin_filter
	lcall	cin
	cjne	a, #esc_char, cinf_consume
	sjmp	cinf2

;this thing waits for a character to be received for approx
;4 character transmit time periods.  It returns immedately
;or after the entire wait time.	 It does not remove the character
;from the buffer, so ri should be checked to see if something
;actually did show up while it was waiting
	.equ	char_delay, 4		;number of char xmit times to wait
cinf_wait:
	mov	a, r2
	push	acc
	mov	r2, #char_delay*5
cinfw2: mov	a, th0
cinfw3: jb	ri, cinfw4
	inc	a
	jnz	cinfw3
	djnz	r2, cinfw2
cinfw4: pop	acc
	mov	r2, a
	ret




pint8u: ;prints the unsigned 8 bit value in Acc in base 10
	push	b
	push	acc
	sjmp	pint8b

pint8:	;prints the signed 8 bit value in Acc in base 10
	push	b
	push	acc
	jnb	acc.7, pint8b
	mov	a, #'-'
	lcall	cout
	pop	acc
	push	acc
	cpl	a
	add	a, #1
pint8b: mov	b, #100
	div	ab
	setb	f0
	jz	pint8c
	clr	f0
	add	a, #'0'
	lcall	cout
pint8c: mov	a, b
	mov	b, #10
	div	ab
	jnb	f0, pint8d
	jz	pint8e
pint8d: add	a, #'0'
	lcall	cout
pint8e: mov	a, b
	add	a, #'0'
	lcall	cout
	pop	acc
	pop	b
	ret



	;print 16 bit unsigned integer in DPTR, using base 10.
pint16u:	;warning, destroys r2, r3, r4, r5, psw.5
	push	acc
	mov	a, r0
	push	acc
	clr	psw.5
	mov	r2, dpl
	mov	r3, dph

pint16a:mov	r4, #16		;ten-thousands digit
	mov	r5, #39
	acall	pint16x
	jz	pint16b
	add	a, #'0'
	lcall	cout
	setb	psw.5

pint16b:mov	r4, #232	;thousands digit
	mov	r5, #3
	acall	pint16x
	jnz	pint16c
	jnb	psw.5, pint16d
pint16c:add	a, #'0'
	lcall	cout
	setb	psw.5

pint16d:mov	r4, #100	;hundreds digit
	mov	r5, #0
	acall	pint16x
	jnz	pint16e
	jnb	psw.5, pint16f
pint16e:add	a, #'0'
	lcall	cout
	setb	psw.5

pint16f:mov	a, r2		;tens digit
	mov	r3, b
	mov	b, #10
	div	ab
	jnz	pint16g
	jnb	psw.5, pint16h
pint16g:add	a, #'0'
	lcall	cout

pint16h:mov	a, b		;and finally the ones digit
	mov	b, r3
	add	a, #'0'
	lcall	cout

	pop	acc
	mov	r0, a
	pop	acc
	ret

;ok, it's a cpu hog and a nasty way to divide, but this code
;requires only 21 bytes!  Divides r2-r3 by r4-r5 and leaves
;quotient in r2-r3 and returns remainder in acc.  If Intel
;had made a proper divide, then this would be much easier.

pint16x:mov	r0, #0
pint16y:inc	r0
	clr	c
	mov	a, r2
	subb	a, r4
	mov	r2, a
	mov	a, r3
	subb	a, r5
	mov	r3, a
	jnc	pint16y
	dec	r0
	mov	a, r2
	add	a, r4
	mov	r2, a
	mov	a, r3
	addc	a, r5
	mov	r3, a
	mov	a, r0
	ret



;pcstr prints the compressed strings.  A dictionary of 128 words is
;stored in 4 bit packed binary format.	When pcstr finds a byte in
;a string with the high bit set, it prints the word from the dictionary.
;A few bytes have special functions and everything else prints as if
;it were an ordinary string.

; special codes for pcstr:
;    0 = end of string
;   13 = CR/LF
;   14 = CR/LF and end of string
;   31 = next word code should be capitalized

pcstr:	push	acc
	mov	a, r0
	push	acc
	mov	a, r1
	push	acc
	mov	a, r4
	push	acc
	setb	psw.1
	setb	psw.5
pcstr1: clr	a
	movc	a, @a+dptr
	inc	dptr
	jz	pcstr2
	jb	acc.7, decomp
	anl	a, #0x7F
pcstrs1:cjne	a, #13, pcstrs2
	lcall	newline
	setb	psw.1
	sjmp	pcstr1
pcstrs2:cjne	a, #31, pcstrs3
	clr	psw.5
	sjmp	pcstr1
pcstrs3:cjne	a, #14, pcstrs4
	lcall	newline
	sjmp	pcstr2
pcstrs4:
	clr	psw.1
	lcall	cout
	sjmp	pcstr1
pcstr2: pop	acc
	mov	r4, a
	pop	acc
	mov	r1, a
	pop	acc
	mov	r0, a
	pop	acc
	ret

;dcomp actually takes care of printing a word from the dictionary

; dptr = position in packed words table
; r4=0 if next nibble is low, r4=255 if next nibble is high

decomp: anl	a, #0x7F
	mov	r0, a		;r0 counts which word
	jb	psw.1, decomp1	;avoid leading space if first word
	lcall	space
decomp1:clr	psw.1
	push	dpl
	push	dph
	mov	dptr, #words
	mov	r4, #0
	mov	a, r0
	jz	dcomp3
	;here we must seek past all the words in the table
	;that come before the one we're supposed to print
	mov	r1, a
dcomp2: acall	get_next_nibble
	jnz	dcomp2
	;when we get here, a word has been skipped... keep doing
	;this until we're pointing to the correct one
	djnz	r1, dcomp2
dcomp3: ;now we're pointing to the correct word, so all we have
	;to do is print it out
	acall	get_next_nibble
	jz	dcomp_end
	cjne	a, #15, dcomp4
	;the character is one of the 12 least commonly used
	acall	get_next_nibble
	inc	a
	movc	a, @a+pc
	sjmp	dcomp5
	.db	"hfwgybxvkqjz"
dcomp4: ;the character is one of the 14 most commonly used
	inc	a
	movc	a, @a+pc
	sjmp	dcomp5
	.db	"etarnisolumpdc"
dcomp5: ;decide if it should be uppercase or lowercase
	mov	c, psw.5
	mov	acc.5, c
	setb	psw.5
	cjne	r0, #20, dcomp6
	clr	acc.5
dcomp6: cjne	r0, #12, dcomp7
	clr	acc.5
dcomp7: lcall	cout
	sjmp	dcomp3
dcomp_end:
	pop	dph
	pop	dpl
	ajmp	pcstr1

get_next_nibble:	;...and update dptr and r4, of course
	clr	a
	movc	a, @a+dptr
	cjne	r4, #0, gnn2
	mov	r4, #255
	anl	a, #00001111b
	ret
gnn2:	mov	r4, #0
	inc	dptr
	swap	a
	anl	a, #00001111b
	ret


;---------------------------------------------------------;
;							  ;
;	 Here begins the data tables and strings	  ;
;							  ;
;---------------------------------------------------------;

;this is the dictionary of 128 words used by pcstr.

words:
	.db	0x82, 0x90, 0xE8, 0x23, 0x86, 0x05, 0x4C, 0xF8
	.db	0x44, 0xB3, 0xB0, 0xB1, 0x48, 0x5F, 0xF0, 0x11
	.db	0x7F, 0xA0, 0x15, 0x7F, 0x1C, 0x2E, 0xD1, 0x40
	.db	0x5A, 0x50, 0xF1, 0x03, 0xBF, 0xBA, 0x0C, 0x2F
	.db	0x96, 0x01, 0x8D, 0x3F, 0x95, 0x38, 0x0D, 0x6F
	.db	0x5F, 0x12, 0x07, 0x71, 0x0E, 0x56, 0x2F, 0x48
	.db	0x3B, 0x62, 0x58, 0x20, 0x1F, 0x76, 0x70, 0x32
	.db	0x24, 0x40, 0xB8, 0x40, 0xE1, 0x61, 0x8F, 0x01
	.db	0x34, 0x0B, 0xCA, 0x89, 0xD3, 0xC0, 0xA3, 0xB9
	.db	0x58, 0x80, 0x04, 0xF8, 0x02, 0x85, 0x60, 0x25
	.db	0x91, 0xF0, 0x92, 0x73, 0x1F, 0x10, 0x7F, 0x12
	.db	0x54, 0x93, 0x10, 0x44, 0x48, 0x07, 0xD1, 0x26
	.db	0x56, 0x4F, 0xD0, 0xF6, 0x64, 0x72, 0xE0, 0xB8
	.db	0x3B, 0xD5, 0xF0, 0x16, 0x4F, 0x56, 0x30, 0x6F
	.db	0x48, 0x02, 0x5F, 0xA8, 0x20, 0x1F, 0x01, 0x76
	.db	0x30, 0xD5, 0x60, 0x25, 0x41, 0xA4, 0x2C, 0x60
	.db	0x05, 0x6F, 0x01, 0x3F, 0x26, 0x1F, 0x30, 0x07
	.db	0x8E, 0x1D, 0xF0, 0x63, 0x99, 0xF0, 0x42, 0xB8
	.db	0x20, 0x1F, 0x23, 0x30, 0x02, 0x7A, 0xD1, 0x60
	.db	0x2F, 0xF0, 0xF6, 0x05, 0x8F, 0x93, 0x1A, 0x50
	.db	0x28, 0xF0, 0x82, 0x04, 0x6F, 0xA3, 0x0D, 0x3F
	.db	0x1F, 0x51, 0x40, 0x23, 0x01, 0x3E, 0x05, 0x43
	.db	0x01, 0x7A, 0x01, 0x17, 0x64, 0x93, 0x30, 0x2A
	.db	0x08, 0x8C, 0x24, 0x30, 0x99, 0xB0, 0xF3, 0x19
	.db	0x60, 0x25, 0x41, 0x35, 0x09, 0x8E, 0xCB, 0x19
	.db	0x12, 0x30, 0x05, 0x1F, 0x31, 0x1D, 0x04, 0x14
	.db	0x4F, 0x76, 0x12, 0x04, 0xAB, 0x27, 0x90, 0x56
	.db	0x01, 0x2F, 0xA8, 0xD5, 0xF0, 0xAA, 0x26, 0x20
	.db	0x5F, 0x1C, 0xF0, 0xF3, 0x61, 0xFE, 0x01, 0x41
	.db	0x73, 0x01, 0x27, 0xC1, 0xC0, 0x84, 0x8F, 0xD6
	.db	0x01, 0x87, 0x70, 0x56, 0x4F, 0x19, 0x70, 0x1F
	.db	0xA8, 0xD9, 0x90, 0x76, 0x02, 0x17, 0x43, 0xFE
	.db	0x01, 0xC1, 0x84, 0x0B, 0x15, 0x7F, 0x02, 0x8B
	.db	0x14, 0x30, 0x8F, 0x63, 0x39, 0x6F, 0x19, 0xF0
	.db	0x11, 0xC9, 0x10, 0x6D, 0x02, 0x3F, 0x91, 0x09
	.db	0x7A, 0x41, 0xD0, 0xBA, 0x0C, 0x1D, 0x39, 0x5F
	.db	0x07, 0xF2, 0x11, 0x17, 0x20, 0x41, 0x6B, 0x35
	.db	0x09, 0xF7, 0x75, 0x12, 0x0B, 0xA7, 0xCC, 0x48
	.db	0x02, 0x3F, 0x64, 0x12, 0xA0, 0x0C, 0x27, 0xE3
	.db	0x9F, 0xC0, 0x14, 0x77, 0x70, 0x11, 0x40, 0x71
	.db	0x21, 0xC0, 0x68, 0x25, 0x41, 0xF0, 0x62, 0x7F
	.db	0xD1, 0xD0, 0x21, 0xE1, 0x62, 0x58, 0xB0, 0xF3
	.db	0x05, 0x1F, 0x73, 0x30, 0x77, 0xB1, 0x6F, 0x19
	.db	0xE0, 0x19, 0x43, 0xE0, 0x58, 0x2F, 0xF6, 0xA4
	.db	0x14, 0xD0, 0x23, 0x03, 0xFE, 0x31, 0xF5, 0x14
	.db	0x30, 0x99, 0xF8, 0x03, 0x3F, 0x64, 0x22, 0x51
	.db	0x60, 0x25, 0x41, 0x2F, 0xE3, 0x01, 0x56, 0x27
	.db	0x93, 0x09, 0xFE, 0x11, 0xFE, 0x79, 0xBA, 0x60
	.db	0x75, 0x42, 0xEA, 0x62, 0x58, 0xA0, 0xE5, 0x1F
	.db	0x53, 0x4F, 0xD1, 0xC0, 0xA3, 0x09, 0x42, 0x53
	.db	0xF7, 0x12, 0x04, 0x62, 0x1B, 0x30, 0xF5, 0x05
	.db	0xF7, 0x69, 0x0C, 0x35, 0x1B, 0x70, 0x82, 0x2F
	.db	0x2F, 0x14, 0x4F, 0x51, 0xC0, 0x64, 0x25, 0x00

;STR

logon1: .db	"Welcome",128,148,"2, by",31,248,31,254,13,14
logon2: .db	32,32,"See",148,"2.DOC,",148,"2.EQU",164
	.db	148,"2.HDR",180,213,141,".",14
abort:	.db	" ",31,158,31,160,"!",13,14
prompt1:.db	148,"2 Loc:",0
prompt2:.db	" >", 160	;must follow after prompt1
prompt3:.db	134,202,130,'(',0
prompt4:.db	"),",149,140,128,200,": ",0
prompt5:.db	31,151,130,195,"s",199,166,131,","
	.db	186," JUMP",128,134,161,"r",130,13,14
prompt6:.db	13,13,31,135,131,129,": ",0
prompt7:.db	31,228,251," key: ",0
prompt8:.db	13,13,31,136,128,131,129," (",0
prompt9:.db	13,13,31,130,31,253,0
prompt9b:.db	 31,129,32,32,32,32,32,31,201,14	;must follow prompt9
prompt10:.db	") ",31,135,31,178,": ",0
beg_str:.db	"First",31,129,": ",0
end_str:.db	"Last",31,129,":",32,32,0
sure:	.db	31,185,161," sure?",0
edits1: .db	13,13,31,156,154,146,",",140,128,200,14
edits2: .db	"  ",31,156,193,",",142,129,247,13,14
dnlds1: .db	13,13,31,159," ascii",249,150,31,152,132,137
	.db	",",149,140,128,160,13,14
dnlds2: .db	13,31,138,160,"ed",13,14
dnlds3: .db	13,31,138,193,"d",13,14
dnlds4: .db	"Summary:",14
dnlds5: .db	" ",198,"s",145,"d",14
dnlds6a:.db	" ",139,145,"d",14
dnlds6b:.db	" ",139," written",14
dnlds7: .db	31,155,":",14
dnlds8: .db	" ",139," unable",128," write",14
dnlds9: .db	32,32,"bad",245,"s",14
dnlds10:.db	" ",133,159,150,198,14
dnlds11:.db	" ",133,132,157,14
dnlds12:.db	" ",133," non",132,157,14
dnlds13:.db	31,151,155," detected",13,14
runs1:	.db	13,134,"ning",130,":",13,14
uplds3: .db	13,13,"Sending",31,152,132,137,172,32,32,0
uplds4: .db	" ",128,32,32,0		;must follow uplds3
help1txt:.db	13,13,"Standard",31,158,"s",14
help2txt:.db	31,218,31,244,"ed",31,158,"s",14
type1:	.db	31,154,158,0
type2:	.db	31,130,0
type4:	.db	31,143,31,226,31,170,0
type5:	.db	"???",0
help_cmd2:.db	31,215,0
help_cmd: .db	31,142,215,209,0	;these 11 _cmd string must be in order
dir_cmd:  .db	31,209,130,"s",0
run_cmd:  .db	31,134,130,0
dnld_cmd: .db	31,138,0
upld_cmd: .db	31,147,0
nloc_cmd: .db	31,135,129,0
jump_cmd: .db	31,136,128,131,129,0
dump_cmd: .db	31,132,219,154,131,0
intm_cmd: .db	31,132,219,192,131,0
edit_cmd: .db	31,156,154,146,0
clrm_cmd: .db	31,237,131,0
erfr_cmd: .db	31,203,153,144,0
erfr_ok:  .db	31,153,144,203,'d',13,14
erfr_err: .db	31,133,155,13,14