Files
Digital-Research-Source-Code/CPM OPERATING SYSTEMS/CPM 68K/1.2 SOURCE IMG/68_12_02.img
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

6756 lines
250 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹REAR SUBEXCEPTN S K
BDOSDEF H L
CONBDOS C S !裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹MAKE SUB<>FILEIO C €劒屆撼泛。「」、・ヲァィFILEIO C ゥェォFILETYPSS ャュョッ1 $2
l.o fileio.o bdosrw.o bdosmain.o
$2ar68 rf $1 cpmlib iosys.o pgmld.o except.o filetyps.o stack.o
BDOSMISCC K"#$%&'()*+CCPLOAD S B,-./01234MAKE SUB5BDOSIF S (6789:裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹IOSYS C ーアイウPGMLD S €エオカキクケコサシスセソタチツテPGMLD S トナニPKTIO H ヌネノ $2
l.o fileio.o bdosrw.o bdosmain.o
$2ar68 rf $1 cpmlib iosys.o pgmld.o except.o filetyps.o stack.o
BDOSINC H ";<=>?BDOSMAINC g@ABCDEFGHIJKLBDOSRW C ^MNOPQRSTUVWXBIOSDEF H YZ[\裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹*************************************************
* *
* CP/M-68k Basic Disk Operating System *
* Exception Handling MoSTACK S LOADR S >ヒフヘホマミムメOVHDLR S モヤユヨMACHINE 68K $2
l.o fileio.o bdosrw.o bdosmain.o
$2ar68 rf $1 cpmlib iosys.o pgmld.o except.o filetyps.o stack.o
CCP C €]^_`abcdefghijklCCP C €mnopqrstuvwxyz{|CCP C $}~€<7F>CCPBDOS S <08>era cpmlib
$2ar68 rf $1 cpmlib ccpif.o except10.o ccpbdos.o ccpload.o ccp.o bdosif.o
$2ar68 rf $1 cpmlib conbdos.o bdosmisc.o裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹dule *
* *
* Version 0.0 -- July 21, 1982 *
* Version 0.1 -- July 25, 1982 *
* Version 0.2 -- October 6, 1982 MACHINE VAXMACHINE H 裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹CCPDEF H $ヤ<><E383A4>CCPIF S <13><>CPMC DOC
DSKUTIL C B克署葬灯<E891AC> dskutil.o fileio.o bdosrw.o bdosmain.o
$2ar68 rf $1 cpmlib iosys.o pgmld.o except.o filetyps.o stack.o
era *.o
user 3!make $ *
* Version 0.3 -- December 21, 1982 *
* *
* Modified 2/15/84 sw for 68010 support *
* *
***********************f M68010
bsr.w except * 2 Buserr
excrtn0:
bsr.w except * 3 Addressing error
bsr.w except * 4 Illegal Instruction
#d4 = new high TPA limit
move #17,d0
movea.l 4(sp),a0
move.l a0,evec_adr * save exception vector address
init4:
cmp.l (adef M68010
*
* Here if the exception in question was a buserr/addressing error.
* We reformat the stack to look like a 68000.dq #1,d1
add.l #4,d2
cmpi #spurious,d1
bne init3
move #trap0,d1
init3: cmpi #trap2,d1
beq init2 * don't init trap 2 r.w except * 16
bsr.w except * 17
bsr.w except * 18
bsr.w except * 19
bsr.w except * 20
bsr.w except * 21
bsr.**************************
.globl _initexc
.globl _tpa_lp
.globl _tpa_hp
.globl gouser *sw RTE routine
bgetsegelse
.globl m68010 * Note case difference!
m68010: * For build process
bsr.w berr * 2 Buserr
excrtn0:
bsr.w berr 0),d1
bhi do_init * if old exception outside orig TPA, clear it
cmp.l (a0),d2
bls do_init
* current exception array entr
*
* Entered with a standard 68010 exception stack frame with a return
* address on top (at 0(sp)).
*
berr:
move.l $0(sp)or trap 3
cmpi #trap3,d1
beq init2
cmpi #endvec,d1
blt init1
* initialize the exception vector array
moveq #bgetw except * 22
bsr.w except * 23
bsr.w except * 24
bsr.w except * 25
bsr.w except * 26
bsr.w except * 27
bsr.w = 18
bsetexc = 22
buserr = 2
spurious = 24
trap0 = 32
trap2 = 34
trap3 = 35
endvec = 48
_initexc:
* Initialize Excep* 3 Addressing error
bsr.w except * 4 Illegal Instruction
#endif
bsr.w except * 5
bsr.w except * 6
bsr.w except y is in original TPA
cmp.l (a0),d3
bhi dontinit * if old exception in old TPA but outside new
cmp.l (a0),d4 * TPA, don't ,$2a(sp) * Move return address
move.w $0c(sp),$2e(sp) * Move Status word
andi.w #7,$2e(sp) * Clear all but FC0-2
movseg,d0
trap #3 * get the original TPA limits
movea.l d0,a0
tst.w (a0)+
move.l (a0)+,d1 * d1 = original low TPA limit
except * 28
bsr.w except * 29
bsr.w except * 30
bsr.w except * 31
bsr.w except * 32
bsr.w except * 33
bsr.w extion Vector Handlers
* It has 1 passed parameter: the address of the exception vector array
move #bsetexc,d0
moveq #2,d1
* 7
#ifndef M68010
bsr.w except * 8
#else * Privilege violation
bsr.w privviol * 8
#endif
bsr.w except * 9
clear it
bls dontinit
do_init:
clr.l (a0)
dontinit:
tst.l (a0)+
dbf d0,init4
rts
.page
exchndl:.equ *
#ifndee.l $0e(sp),$30(sp) * Copy Fault address
move.w $1c(sp),$34(sp) * Move IR
move.w $4(sp),$36(sp) * Move SR
move.l $6(move.l d1,d2
add.l (a0),d2 * d2 = original high TPA limit
move.l _tpa_lp,d3 * d3 = new low TPA limit
move.l _tpa_hp,d4 * cept * 34
bsr.w except * 35
bsr.w except * 36
bsr.w except * 37
bsr.w except * 38
bsr.w except * 39
.page
#ifmove.l #exchndl,d2
init1:
movem.l d0-d2,-(sp)
trap #3 * BIOS call to set exception vector
movem.l (sp)+,d0-d2
init2: adbsr.w except * 10
bsr.w except * 11
bsr.w except * 12
bsr.w except * 13
bsr.w except * 14
bsr.w except * 15
bssp),$38(sp) * Move PC
move.w $0a(sp),$3c(sp) * Move format word
adda.l #$2a,sp * Make sp -> new frame
bra except format word)|
move.l 10(sp),d0 * get return address from above array
sub.l #excrtn0,d0 * d0 now has 4 * (encoded excptn nmbrsr: movem.l (sp)+,d0/a0 * Abandon hope, all ye ..
.page
#endif
except:
clr.w -(sp)
movem.l a0/d0,-(sp) * 10 (11) wordsi #2,d0
cmpi #23,d0 * get back real excptn nmbr in [2..23,32..47]
ble lowexc
addi #8,d0
lowexc: move d0,-(sp) * save excruction exception. *
******************************************************************************
privviol:
movem.l ected
bne usrexc
* not redirected, do default handler
supexc: * Here for supervisor state
cmpi #40,d0
blt dfltexc
* Merge
******************************************************************************
* Here we make up for a faux pas in th), where
* encoded excptn nmbr is in [0..21,22..37]
* representing [2..23,32..47]
cmpi #36,d0 * if d0/4 is now on stack in following order
* _______________________________
* |____________D0.L_______________|
* |_________ptn nmbr
lea excmsg1,a0
bsr print * print default exception message
move (sp)+,d0
bsr prtbyte
lea excmsg2, a0
bsr pd0/a0,-(sp) * Save some regs
move.l $0e(sp),a0 * A0 -> Instruction
move.w (a0),d0 * d0 = Instruction
andi.w #$FFC0
addi #48,d0 * add 4*12 that was sub'd above
dfltexc:
adda #14,sp * throw away 7 words that we added to stack
asr #2,d0 e C compiler. Change all *
* move from SR instructions ($40CX) to move from CCR ($42CX). *
* Precludes executin [0..9,22..29] then
ble chkredir * the exception may be redirected
cmpi #88,d0
blt dfltexc
cmpi #116,d0
bgt dflt___A0.L_______________|
* |____0000______|________________
* |_______Handler Return__________|
* If bus error, extrarint
move.l (sp)+,d0
bsr prtlong
lea excmsg3, a0
bsr print
clr.l d0
trap #2 * warm boot
rte
usrexc:
* Call us,d0 * Mask off <EA> field
cmpi.w #$40C0,d0 * Move from SR?
bne notsr * No, handle normally
ori.w #$0200,(a0) * Ch * divide d0 by 4
* now d0 is in [0..21,22..37]
* to represent [2..23,32..47]
cmpi #2,d0 * bus or address error?
bging 68000 programs in ROM on a 68010. *
* exc
* in range of redirected exceptions
subi #48,d0 * subtract 4*12 to normalize [0..9,22..29]
* into [0..9,10..17 2 longs are here
* ______________
* |__Status Reg__|________________
* |_____Exception Return__________|
* |_(er exception handler
* make sure exception information is on his stack
cmpi #8,d0 * address or bus error?
blt addrexc * iange to move from CCR
movem.l (sp)+,d0/a0 * Restore regs
tst.l (sp)+ * Pop return address
rte * Try it again
note nobusexc
movem.l (sp)+,a0-a1 * if yes, throw away 4 words from stack
nobusexc:
tst.w (sp)+ * throw away stacked SR
add *
* Relies on the fact that the exception PC (Stack offset 0E below) *
* points to the instruction on an illegal inst]
chkredir:
movea.l evec_adr,a0
adda d0,a0 * index into exception vector array
tst.l (a0) * if 00000000, then not redirf yes, skip
btst #13,14(sp) * exception occured in user state?
bne supexc *sw if no, go to supervisor handler
move.l (a0)M68010
clr.w -(sp) * Push format word
#endif
move.l a0,-(sp) * Push epa
clr.w -(sp) * and SR
rte * Do it. Iove address of user handler to excptn rtn
#ifdef M68010
clr.w 20(sp) *sw Clear format word
#endif
adda #14,sp * clear ju裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹dler
addrexc:
btst #13,22(sp) * exception occured in user state?
bne supexc *sw if no, go to supervisor handler
move.l (9'-1,d0
lt10:
addi.b #'0',d0
move d0,d1
move #2,d0
trap #2
rts
.data
excmsg1:
.dc.b 13,10,10,'Exception $',10(sp) * put user handler address on our stack
move.l usp,a0 * user stack pointer to a0
move.l 16(sp),-(a0) * put exceptionto user program.
.page
*
* Subroutines
*
print:
clr.l d1
move.b (a0)+, d1
beq prtdone
move #2, d0
trap #2
bnk from stack
andi #$7fff,(sp) * clear trace bit
rte * go to user handler
.page
*************************************裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹a0),10(sp) * put user handler address on our stack
move.l usp,a0 * user stack pointer to a0
move.l 24(sp),-(a0) * put excep,0
excmsg2:
.dc.b ' at user address $',0
excmsg3:
.dc.b '. Aborted.',0
.bss
evec_adr:
.ds.l 1
.end
n return on user stack
move.w 14(sp),-(a0) * put SR on user stack
move.l a0,usp * update user stack pointer
movem.l (sp)+ra print
prtdone:
rts
prtlong:
* Print d0.l in hex format
move d0,-(sp)
swap d0
bsr prtword
move (sp)+,d0
prt******************************************
*
* gouser routine. This routine performs an RTE to go to the user program
* U裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹tion return on user stack
move.w 22(sp),-(a0) * put SR on user stack
move.l 18(sp),-(a0) * put extra 2 longs on user stack
0
excmsg2:
.dc.b ' at user address $',0
excmsg3:
.dc.b '. Aborted.',0
.bss
evec_adr:
.ds.l 1
.end
,a0/d0 * restore regs
move.l 2(sp),8(sp) * move address of user handler to excptn rtn
#ifdef M68010
clr.w 12(sp) *sw Clearword:
* Print d0.w in hex format
move d0,-(sp)
lsr #8,d0
bsr prtbyte
move (sp)+,d0
prtbyte:
* Print d0.b in hex fser EPA is passed in A0.L.
*
*******************************************************************************
gouser:
#ifdef 裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹 move.l 14(sp),-(a0)
move.l a0,usp * update user stack pointer
movem.l (sp)+,a0/d0 * restore regs
move.l 2(sp),16(sp) * m裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹 out the format word
#endif
addq #6,sp * clear junk from stack
andi #$7fff,(sp) * clear trace bit
rte * go to user hanormat
move d0,-(sp)
lsr #4,d0
bsr prtnib
move (sp)+,d0
prtnib:
andi #$f,d0
cmpi #10,d0
blt lt10
addi.b #'A'-'/********************************************************
* *
* imple structure for the single thread environment while leaving the
possibilities open for the multi-thread environment.
*****
Only a few "globals" are really global in this sense.
The majority of the "global" variables are actually state variables th to the manipulation of
the allocation vector. This isn't a problem in a single-thread model, but
must be provided for *********************************************************************
The BDOS data structures, especially those relating to gltern structure */
#endif
#if ! snglthrd
#define GBL (*statep)
/* If multi-task, state vars CP/M-68K header file *
* Copyright (c) 1982 by Digital Research, Inc. *
* Structure defin***********************************************************************/
#define snglthrd TRUE
/* TRat
relate to the state of the task using the file system. In CP/M-68K, these
are "global", since there's only one task, but iin a multi-tasking file system. Consequently, the
primitives LOCK and UNLOCK are defined and used where necessary in the
obal variables,
are structured in a way that hopefully will enable this BDOS, in the future,
to easily become a re-entrant mu are based */
#define BSETUP REG struct stvars *statep; \
statep = &gbls;
/* set uitions for BDOS globals *
* and BDOS data structures *
* UE for single-thread environment
FALSE to create based structure for re-entrant model */
#if snglthrd
n a multi-thread model they're
not. This type of variables is put into a data structure, with the
intention that in the multi file system. For the single thread model, they are null routines */
#define LOCK /**/
#define UNLOCK /**/
/*lti-tasking file system. Consequently,
the BDOS global variables are divided into two classes. Those that are
truly global,p pointer to state variables */
/* This is intended as an example to show the intent */
#endif
/* *
* Desecrated 6-Aug-83 (sw) for type-ahead *
* Again 17-Mar-84 (sw) for chaining *
#define GBL gbls
/* In single thread case, GBL just names
-task environment this structure will be based.
The following declarations take this philosophy into account, and define
a s Be sure LOCK and UNLOCK are implemented to allow recursive calls to LOCK.
That is, if a process that calls LOCK already own even in the case of multiple tasks using the file system
concurrently, are simply declared as global variables in bdosmain.c.
Note that there are a few critical regions in the file system that must
execute without interruption. They pertain mostly
* *
********************************************************/
/***** the structure */
#define BSETUP EXTERN struct stvars gbls;
/* and BSETUP defines the exs the lock, let it proceed,
but remember that only the outer-most call to UNLOCK really releases the
file system. */
UBYTE fname[8]; /* File name (ASCII) */
UBYTE ftype[3]; /* File t
WORD big[8]; /* or 8 block numbers of 1 word */
} dskmap;
UBYTE cur_rec; UWORD dsm; /* max disk size in blocks */
UWORD drm; /* max directory entries */
II) */
UBYTE ftype[3]; /* File type (ASCII) */
UBYTE extent; */
} dskmap;
};
/* Declaration of disk parameter tables */
struct dpb /* */
#define VERSION 0x2022 /* Version number for CP/M-68K */
#define robit 0 /* reaype (ASCII) */
UBYTE extent; /* Extent number (bits 0..4 used) */
UBYTE s /* current record field */
UBYTE ran0; /* random record field (3 bytes) */
UWORD dir_al; /* initial allocation for dir */
UWORD cks; /* number dir sectors to ch /* Extent number (bits 0..4 used) */
UBYTE s1; /* Reserved */
disk parameter table */
{
UWORD spt; /* sectors per track */
UBYTE bsh; d-only bit in file type field of fcb */
#define arbit 2 /* archive bit in file type field of fcb */
#define 1; /* Reserved */
UBYTE s2; /* Module field (bits 0..5), write fl UBYTE ran1;
UBYTE ran2;
};
/* Declaration of directory entry */
struct dirent
{
UBYTE ecksum */
UWORD trk_off; /* track offset */
};
struct dph /* disk par UBYTE s2; /* Module field (bits 0..5), write flag (7) */
UBYTE rcdcnt; /* Nmbr rcrds in /* block shift factor */
UBYTE blm; /* block mask */
UBYTE SECLEN 128 /* length of a CP/M sector */
/* File Control Block definition */
struct fcb
{
ag (7) */
UBYTE rcdcnt; /* Nmbr rcrds in last block, 0..128 */
union
{
UBYTE entry; /* 0 - 15 for user numbers, E5 for empty */
/* the rest are reserved ameter header */
{
UBYTE *xlt; /* pointer to sector translate table */
UWORD hiwater;last block, 0..128 */
union
{
UBYTE small[16]; /* 16 block numbers of 1 byte */
exm; /* extent mask */
UBYTE dpbdum; /* dummy byte for fill */
UBYTE drvcode; /* 0 = default drive, 1..16 are drives A..P */
UBYTE fname[8]; /* File name (ASC small[16]; /* 16 block numbers of 1 byte */
WORD big[8]; /* or 8 block numbers of 1 word /* high water mark for this disk */
UWORD dum1; /* dummy (unused) */
/* disk. Stored here to save ref calc */
UWORD srchpos; /* position in directory fast selected by fcn 14) */
UBYTE user; /* Current user number */
struct dph * */
};
E kbchar; /* keyboard type-ahead buffer count */
UBYTE delim; /* Delimiter for function 9 ved next line from structure */
UBYTE *chainp; /* Used for chain to program call */
/* Consol UWORD dum2;
UBYTE *dbufp; /* pointer to 128 byte directory buffer */
struct dpb *dpbp; or search next */
UBYTE *dmaadr; /* Disk dma address */
struct fcb *srchp; dphp; /* pointer to disk parm hdr for cur disk */
struct dirent *dirbufp; /* pointer for directory buff for pro */
};
 */
BOOLEAN lstecho; /* True if echoing console output to lst: */
BOOLEAN echodel; e buffer structure declaration */
struct conbuf
{
UBYTE maxlen; /* Maximum length from calling routine */
/* pointer to disk parameter block */
UBYTE *csv; /* pointer to check vector */
/* Pointer to search FCB for function 17 */
UBYTE *excvec[18]; /* Array of exception vectors */cess */
/* stored here so that each process can */
/* have裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹 /* Echo char when getting <del> ? */
UWORD column; /* CRT column number for expanding tabs */
UBYTE retlen; /* Length actually found by BDOS */
UBYTE cbuf[]; /* Console data UBYTE *alv; /* pointer to allocation vector */
};
/* Declaration of structure containing "global" s
UBYTE *insptr; /*sw Insertion pointer for typeahead */
UBYTE *remptr; /*sw Removal po a separate dirbuf. */
struct dpb *parmp; /* pointer to disk parameter block for cur */
裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹 UBYTE curdsk; /* Currently selected disk */
UBYTE dfltdsk; /* Default disk (l */
};
tate variables */
#define TBUFSIZ 126 /*sw # typed-ahead characters */
struct stvars
{
UBYTinter for typeahead */
UBYTE t_buff[TBUFSIZ]; /*sw Type-ahead buffer itself */
};
/*sw remo裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹fine ctrlr 0x12
#define ctrls 0x13
#define ctrlu 0x15
#define ctrlx 0x18
#define cr 0x0d
#define lf yright (c) 1982 Digital Research, Inc. *
* *
* Modified 2/5/84 sw */
{ /************************************/
*GBL.ing functions which *
* are called from the BDOS main routine: *
* constat(); op = FALSE;
if ( bconstat() ) do
{
if ( (ch = bconin()) == ctrlc ) warmboot(2); /*sw from (1) */
if 裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹 0x0a
#define tab 0x09
#define rub 0x7f
#define bs 0x08
#define space 0x20
EXTERN warmbooAllow typeahead *
* ^C warmboot modifications *
* Again 3/17/84 sw Chain hack *
* insptr++ = ch; /* Yes, insert the character in buff*/
GBL.kbchar++; /* Up count *
* conin(); *
* tabout(); ( ch == ctrls ) stop = TRUE;
else if (ch == ctrlq) stop = FALSE;
else if (ch == ctrlp) GBL.lstecho = !GBL.lste/********************************************************
* *
* CPt(); /* External function definition */
/******************/
/* console status */
/******************/
BOO *
********************************************************/
#include "bdosinc.h"
#include "bdosdef */
} /************************************/
} *
* rawconio(); *
* prt_line(); *
*cho;
/*sw What Follows is new... */
else /* Insert character in ring buffer */
/M-68K BDOS Character I/O Routines *
* *
* This module LEAN constat()
{
BSETUP
return( GBL.kbchar ? TRUE : bconstat() );
}
/********************/
/* check for ctrl/s.h"
#include "biosdef.h"
#define ctrlc 0x03
#define ctrle 0x05
#define ctrlp 0x10
#define ctrlq 0x11
#de /* Note if no room, character is */
/* Ignomiously discarded (!) */
readline(); *
* *
* Cop { /* */
if(GBL.kbchar < TBUFSIZ) /* Room? does BDOS functions 1 thru 11 *
* *
* It contains the follow */
/* used internally */
/********************/
conbrk()
{
REG UBYTE ch;
REG BOOLEAN stop;
BSETUP
st /*sw End of new stuff */
/************************************/
} while ( REG UBYTE temp;
BSETUP
if(GBL.kbchar)
{
temp = *GBL.remptr++; /* Fetch the character */ /* character to output to console */
{
if (ch == tab) tabout(ch); /* if tab, expand it */
else
p != GBL.delim ) tabout( *p++ );
}
/**********************************************/
/* read line with editing and bounds .column--;
}
/*************************************/
/* console output with tab expansion */
/******************************************
* raw console i/o *
******************/
UBYTE rawconio(parm) /* BDOS raw console I/O function */
REGstop);
}
/******************/
/* console output */
/* used internally*/
/******************/
conout(ch)
REG UBYTE c
GBL.kbchar--; /* Decrement the count */
if(!GBL.kbchar) /* Gone to zero? {
if ( (UWORD)ch < (UWORD)' ' )
{
conout( '^' );
ch |= 0x40;
}
conochecking */
/**********************************************/
/* Two subroutines first */
newline(startcol)
REG UWORD sta***********/
tabout(ch)
REG UBYTE ch; /* character to output to console */
{
BSETUP
if (ch == t UWORD parm;
{
BSETUP
if (parm == 0xff) return(getch());
else if (parm == 0xfe) return(constat());
else bh;
{
BSETUP
conbrk(); /* check for control-s break */
bconout(ch); /* output */
GBL.remptr = GBL.insptr = &(GBL.t_buff[0]);
return(temp);
}
return( bconin() );ut(ch); /* output the character */
}
}
/*****************/
/* console input */
/*****************/
rtcol;
{
BSETUP
conout(cr); /* go to new line */
conout(lf);
while(startcol)
{
ab) do
conout(' ');
while (GBL.column & 7);
else conout(ch);
}
/*******************************/
/* consconout(parm & 0xff);
}
/****************************************************/
/* print line up to delimiter($) with tab echaracter to console */
if (GBL.lstecho) blstout(ch); /* if ctrl-p on, echo to list dev */
if ((UWORD)ch >= (UWO /* else get char from bios */
}
UBYTE conin() /* BDOS console input function */
{
REG U
UBYTE getch() /* Get char from buffer or bios */
/* For internal use only */
{
conout(' ');
startcol -= 1; /* start output at starting column */
}
}
backsp(bufp, col)
/* bacole output with tab and */
/* control character expansion */
/*******************************/
cookdout(ch)
REG UBYTE ch; xpansion */
/****************************************************/
prt_line(p)
REG UBYTE *p;
{
BSETUP
while( *RD)' ')
GBL.column++; /* keep track of screen column */
else if (ch == cr) GBL.column = 0;
else if (ch == bs) GBLBYTE ch;
BSETUP
conout( ch = getch() );
if (ch == ctrlp) GBL.lstecho = !GBL.lstecho;
return(ch);
}
/**kspace one character position */
REG struct conbuf *bufp; /* pointer to console buffer */
REG WORD col;
{
i = UBWORD(*(GBL.chainp++));
j = UBWORD(p->maxlen);
if (j < i) i = j; /* don't o conout(bs); /* backspace until we get to proper column */
conout(' ');
conout(bs);
}
}
>retlen)
{
i = UBWORD(--(p->retlen));
conout( p->cbuf[i] );
ulate column position */
{ /* across entire char buffer */
ch = *p++; && !(p->retlen) )
{
cookdout(ctrlc);
warmboot(2); /*sw From warmboot(1) */
}
/* starting console column */
{
REG UBYTE ch; /* current character */
REG WORverflow console buffer! */
p->retlen = (UBYTE)i;
q = p->cbuf;
while (i)
{
cookd
readline(p) /* BDOS function 10 */
REG struct conbuf *p;
{
REG UBYTE ch;
REG UWORD i; }
}
else backsp(p, stcol);
}
else if (ch == ctrlp) GBL.lstecho = !GBL.lste /* get next char */
if ( ch == tab )
{
col += 8;
col &= ~7; else if ( (ch == cr) || (ch == lf) )
{ /* if cr or lf, exit */
conout(D i;
REG UBYTE *p; /* character pointer */
BSETUP
if (bufp->retlen) --(bufp->retlenout( *q++ = *(GBL.chainp++) );
i -= 1;
}
GBL.chainp = NULL;
return;
}
#endif /*
REG UWORD j;
REG UBYTE *q;
UWORD stcol;
BSETUP
stcol = GBL.column; /* set up starting colucho;
/* control-p */
else if (ch == ctrlx) /* contro /* for tab, go to multiple of 8 */
}
else if ( (UWORD)ch < (UWORD)' ' ) col += 2;
cr);
break;
}
else if (ch == bs) backsp(p, stcol); /* backspace */
else if (ch ==);
/* if buffer non-empty, decrease it by 1 */
i = UBWORD(bufp->retlen); /* get new charsw NFG chain code */
p->retlen = 0; /* start out with empty buffer */
while ( UBWORD(p->retlen) < UBWOmn */
#ifdef NFG /*sw This didn't work for SUBMIT files...*/
if (GBL.chainp != NULL) /* chain to program code */
l-x */
do backsp(p,stcol); while (p->retlen);
else if (ch == ctrle) newline(stcol); /* control-e */
/* control chars put out 2 printable chars */
else col += 1;
}
while (GBL.column > col)
{
rub) /* delete character */
{
if (GBL.echodel)
{
if (p-acter count */
p = &(bufp->cbuf[0]); /* point to character buffer */
while (i--) /* calcRD(p->maxlen) )
{ /* main loop for read console buffer */
if ( ((ch=getch()) == ctrlc)
else if (ch == ctrlu) /* control-u */
{
conout('#');
newline(stco *
* CP/M-68K BDOS Miscellaneous Module *
* 裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹ied 2/5/84 sw for ^C disk reset. *
* Again 3/17/84 for chain hack *
* *
*************************************uf[UBWORD((p->retlen)++)] = ch );
}
}
DOS read-only file error routine *
* setexc() - BDOS set exception vector *
* set_tpa()l);
p->retlen = 0;
}
else if (ch == ctrlr) /* control-r */
{
*
* This module contains miscellaneous loose ends for *
* CP/M-68K. Included are: 裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹***************************/
#include "bdosinc.h" /* Standard I/O declarations */
#include "bdosdef.h" uf[UBWORD((p->retlen)++)] = ch );
}
}
 - BDOS get/set TPA limits *
* serial # and copyright notice, machine readable *
* conout('#');
newline(stcol);
for (i=0; i < UBWORD(p->retlen); i++)
cookdout *
* *
* bdosinit() - BDOS initiali裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹 /* Type and structure declarations for BDOS */
#include "biosdef.h" /* BIOS definitions, needed for bios wboot 裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹 *
* *
* Confi( p->cbuf[i] );
}
else /* normal character */
cookdout( p->czation routine *
* called from CCP for system init *
* warmboot() - BDOS wa/****************************************************************
* */
/* serial # and copyright notice */
char *copyrt="CP/M-68K(tm), Version 1.2, Copyright (c) 1984, Digital Research";
裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹gured for Alcyon C on the VAX *
* *
* Modifbuf[UBWORD((p->retlen)++)] = ch );
}
}
rm boot exit routine *
* error() - BDOS error printing routine *
* ro_err() - Bchar *serial="XXXX-0000-654321";
/* Declare external functions */
EXTERN conout(); /* Console Ou*************************
* bdos initialization routine *
********************************/
bdosinit()
/* Initialize thelower limit (temporary) */
EXTERN BYTE *tpa_lp; /* TPA lower limit (permanent) */
EXTERN BYTE *tpa_ht else
log_dsk &= (1 << GBL.curdsk); /*sw Log off all but current drive, as */
/* per manual. (^C only) * /* Directory scanning routine */
EXTERN BOOLEAN set_attr(); /* Set File attributes function */
EXTER
segp = bgetseg(); /* get pointer to memory segment table */
tpa_lt = tpa_lp = segp->low;
tpa_ht = tpa_tput function */
EXTERN UBYTE conin(); /* Console Input function */
EXTERN prt_line(); File System */
{
REG struct
{
WORD nmbr;
BYTE *low;
LONG length;
} *segp;
; /* TPA upper limit (temporary) */
EXTERN BYTE *tpa_hp; /* TPA upper limit (permanent) */
/
/* note that this code is specifically for a single-
thread system. ItN UWORD dir_rd(); /* Read directory sector routine */
/* Declare external variables */
EXTERN UWORD loghp = tpa_lp + segp->length;
initexc( &(GBL.excvec[0]) );
}
/************************
* warmboot entry point *
**** /* Print String function */
EXTERN UWORD _bdos(); /* BDOS main routine */
EXTER BSETUP
bsetvec(trap2v, &traphndl); /* set up trap vector */
GBL.kbchar = 0; /* initialize the "globa
EXTERN BOOLEAN submit; /* external variables from CCP */
EXTERN BOOLEAN morecmds;
#define trap2v 34 won't work in a multi-task sys */
/*sw The above is still very much true */
ro_dsk = 0;
crit_dsk = 0;
if (pa_dsk; /* logged-on disk vector */
EXTERN UWORD ro_dsk; /* read-only disk vector ********************/
warmboot(parm)
/* Warm Boot the system */
WORD parm; /* 1 to reset submit flag *N UBYTE *traphndl(); /* assembly language trap handler */
EXTERN initexc(); /* init the excl" variables */
GBL.insptr = GBL.remptr = &(GBL.t_buff[0]);
GBL.delim = '$';
GBL.lstecho = FALSE;
GBL.echod /* trap 2 vector number */
#define ctrlc 3 /* control-c */
/*******rm)
submit = morecmds = FALSE;
GBL.curdsk = 0xff; /* set current disk to "unknown" */
tpa_lt */
EXTERN UWORD crit_dsk; /* vector of critical disks */
EXTERN BYTE *tpa_lt; /* TPA /
{
BSETUP
if(parm != 2) /*sw Not ^C */
log_dsk &= ~ro_dsk; /* log off any disk marked read-only */
eption handler in */
/* exceptn.s */
EXTERN UWORD dirscan(); el = TRUE;
chainp = NULL; /*sw Used to be GBL.chainp */
_bdos(13); /* reset disk system function */ = tpa_lp;
tpa_ht = tpa_hp;
initexc( &(GBL.excvec[0]) );
bwboot();
}
/*************************/
/* disk = 8;
do conout(*++p & 0x7f); while (--i);
conout('.');
i = 3;
do conout(*++p & 0x7f); while (--i);
prt_: warmboot(1);
case 'C': if (cont) return(1);
break;
case 'R': return(0/
case 2: abrt_err("select$");
/* break; */
case 3: return( ext_err(FALSE,"select$") ) /* Boolean for whether continuing is allowed */
BYTE *p; /* pointer to error message */
{
eset the directory buffer !!!! */
} while (TRUE);
}
/************************
* error entry point *
*********error handlers */
/*************************/
prt_err(p)
/* print the error message */
BYTE *p;
{
BSETUP
line(" is read-only.$");
prt_line(warning);
do
{
prt_line("\r\nDo you want to: Change it to read/write (C), or );
}
} while (TRUE);
}
/********************************/
/* Read-only File Error Routine */
/**********;
/* break; */
case 4: abrt_err("change$");
/* break; */
}
}
/***** REG UBYTE ch;
prt_err(p);
prt_line(warning);
do
{
prt_line("\n\rDo you want to: Abort (A), Re***************/
error(errnum)
/* Print error message, do appropriate response */
UWORD errnum; /* erro prt_line(p);
prt_line(" error on drive $");
conout(GBL.curdsk + 'A');
}
abrt_err(p)
/* print the error messaAbort (A)? $");
ch = conin() & 0x5f;
prt_line("\r\n$");
switch ( ch )
{
case **********************/
ro_err(fcbp,dirindx)
/* File R/O error */
REG struct fcb *fcbp;
WORD dirindx;
{
************************
* set exception entry point *
*****************************/
setexc(epbp)
/* Set Exception Vectotry (R)$");
if (cont) prt_line(", or Continue with bad data (C)$");
prt_line("? $");
ch = conin() & 0r number */
{
BSETUP
prt_line("\r\nCP/M Disk $");
switch (errnum)
{
case 0: return( ext_err(TRUge and always abort */
BYTE *p;
{
prt_err(p);
warmboot(1);
}
char *warning = "\r\nWARNING -- Do not attempt tctrlc: warmboot(1);
case 'A': warmboot(1);
case 'C': fcbp->ftype[robit] &= 0x7f;
REG BYTE *p;
REG UWORD i;
REG UBYTE ch;
p = (BYTE *)fcbp;
prt_line("CP/M Disk file error: $");
i r */
REG struct
{
WORD vecnum;
BYTE *newvec;
BYTE *oldvec;
} *epbp;
{
REG WORD i;
BSETUP
ix5f;
prt_line("\r\n$");
switch ( ch )
{
case ctrlc: warmboot(1);
case 'A'E,"read$") );
/* break; */
case 1: return( ext_err(TRUE,"write$") );
/* break; *o change disks$";
ext_err(cont,p)
/* print the error message, and allow for retry, abort, or ignore */
REG BOOLEAN cont; dirscan(set_attr, fcbp, 2);
return(dir_rd(dirindx >> 2));
} /* R = epbp->vecnum-2;
if ( i==32 || i==33) return(-1);
if ( (30 <= i) && (i <= 37) ) i -= 20;
else if ( (i < 0) || (裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹 call the BDOS to obtain the boundries *
* of the TPA. The load parameter block *
* a_lp = tpa_lt;
tpa_hp = tpa_ht;
}
}
else
{
p->low = tpa_lt;
p->high = tpa *
* THIS IS THE DUAL PROCESSOR,ROMABLE CP/M-68K SYSTEM *
* =============================i > 9) ) return(255);
epbp->oldvec = GBL.excvec[i];
GBL.excvec[i] = epbp->newvec;
return(0);
}
/****************************************************************************
* 裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹 defined in this loader holds all the *
* memory size and location details. *
* _ht;
}
}
===================== *
* *
* Description: ******************
* get/set TPA entry point *
*****************************/
set_tpa(p)
/* Get/Set TPA Limits */
REG *
* COMMAND FILE LOADER FOR CPM68K *
* ============================== 裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹 Next the loader returns the system to *
* its original user #. The CCP might *
*ht;
}
}
 *
* ----------- The command file loader is envoked by *
* tstruct
{
UWORD parms;
BYTE *low;
BYTE *high;
} *p;
#define set 1
#define sticky 2
{
if (p->par *
* *
* (c) COPYRIGHT Digital Research 1983 裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹 have switched to user zero during its *
* search for the file. Next the defaultht;
}
}
he CCP after the CCP has successfully *
* opened that file. The loader must *
* ms & set)
{
tpa_lt = p->low;
tpa_ht = p->high;
if (p->parms & sticky)
{
tp *
* all rights reserved *
* *
* dma address is set for the loaded *
* program. Next the command tail -------
*
.text
move.l #TPAB,d1 * move in address of tpa parameter block
move.w #gettpa, .globl _cmdfcb * parsed fcb
.globl _tail * global pointer to command tail
.globl _fill_ #$80,d1 * d1 points to default dma in base page
movea.l d1,a1 * save it for later use
mov *
* Created by: Tom Saulpaugh *
* err * if not print error message and return
*
* return to original user #
* -------------------------
is *
* placed,along with the first two parsed *
* fcb's,into the user basepad0 * get function number
trap #2 * get the tpa limits
move.l low,lowadr * put it ifcb * procedure to fill fcb's
.globl flags * ROM SYSTEM INITIALIZATION
.globl TPAB e #setdma,d0 * move in bdos function no
trap #2 * set the default dma address
*
* move *
* Last Modified: 2/17/84 sw 68010 support *
* move.w _user,d1 * put user # to switch to in d1
move.l #chuser,d0 * put bdos func # in d0
ge. *
* Lastly the user stack pointer is set up *
* and the return addren the lpb
move.l high,hiadr * put high tpa addr in lpb
move.l #_cmdfcb,LPB * get address of opened f * ROM SYSTEM INITIALIZATION
.globl gouser *sw 68000/68010 rte routine
reboot = 0
printstr = 9
setdma = 26
chusin the command tail
* ------------------------
move.l a1,a2 * save a pointer to the count field
*
*****************************************************************
trap #2 * do the user # change
*
* set the default dma address
* ---------------------------
ss is put on the *
* user stack. An RTE transferes control. *
* If a load was cb
move.l #pgmldf,d0 * move in bdos function no
move.l #LPB,d1 * d1 points to load block
er = 32
pgmldf = 59
gettpa = 63
_load68k:
*
* Load the 68k file into the TPA
* ----------------------- add.l #$01,a1 * point past count field
move.l _tail,a0 * point to command tail
clr.l d.globl _load68k * make this procedure public
.globl _user * global user # before load occured
clr.l d1 * clear d1 register
move.l baspag,d1 * d1 points to user base page
add not successfull, the *
* appropriate error message is printed. *
* trap #2 * do the program load
tst d0 * was the load successful?
bne ld0 * clear out d0
mvtail: cmpi.b #$00,(a0) * check for a NULL ending byte
beq done * move.l baspag,a1 * get basepage address
*sw move.l 8(a1),-(sp) * push address we want to jump to
*sw ck
move.w #2,-(sp) * put 2 on stack(parm2)
jsr _fill_fcb * jump to 'C' code & fill cmdfcb wive a byte into the basepage
dbf d0,mov1 * if not done branch to mov1
rts
move.l #_cmdfcb,-(sp) * put address of fcb buffer onto stack
move.w #1,-(sp) * put 1 on stack(parm1)
rror
* ----------
lderr:
rts * return with error code in d0
cmdrtn:
move #rebo NULL byte terminates command
cmpi.b #$21,(a0) * check for an '!'
beq done * '!' ends th move sr,d0 * get the status register in d0
*sw andi #$5f00,d0 * mask trace,system bits,user flags
th parm2
add.l #6,sp * clean off the stack
clr.l d0 * clear register d0
mo.bss
.even
*
* LOAD PARAMETER BLOCK
*
LPB: .ds.l 1
lowadr: .ds.l 1
hiadr: .ds.l 1
baspag: .ds.l
jsr _fill_fcb * jump to 'C' code & fill cmdfcb with parm1
add.l #6,sp * clean off the stot,d0 * reboot CPM
trap #2
movfcb:
add.l baspag,d0 * get offset into basepage
move.e command
move.b (a0)+,(a1)+ * move a byte of the command tail
addq #1,d0 * bump up the char*sw move.w d0,-(sp) * push it on stack
move.l a1,-(a0) * push addr of basepage onto user stack
veq #$38,d0 * put basepage address of fcb1 in d0
bsr movfcb * put fcb2 in the basepage
*
* 1
usrstk: .ds.l 1
flags: .ds.w 1
*
* TPA Parameter Block
*
.even
TPAB: .ds.w 1
low: .ds.l 1
ack
clr.l d0 * clear register d0
moveq #$5c,d0 * put basepage address of fcb1 in d0
l d0,a0 * move address into a0
move.l #_cmdfcb,a1 * a1 points to fcb to be moved
clr.l d0 acter count
bra mvtail * continue byte move
done: move.b d0,(a2) * put in the character count
move.l #cmdrtn,-(a0) * push return address onto user stack
move.l a0,usp * set up user stack pointer
now push rte stuff on stack
* ---------------------------
movea.l usrstk,a0 * get user stack pointer
high: .ds.l 1
.end
 bsr movfcb * put fcb1 in the basepage
move.l #_cmdfcb,-(sp) * put address of fcb buffer onto sta * clear register d0
moveq #35,d0 * get length of fcb
mov1:
move.b (a1)+,(a0)+ * mo
move.b #$00,(a1) * terminate cmd tail with a NULL byte
*
* fill fcb1 & fcb2
* ----------------
move.l 8(a1),a0 *sw a0 -> User program epa
jmp gouser *sw Jump to exit routine in exceptn.s
*sw rte
*
* load ehigh: .ds.l 1
.end
proc.o lnkmess.o 0$2clib
era *.o
$2as68 -s 0$1 -f $1 -l -u loadr.s
$2as68 -s 0$1 -f $1 -l -u ovhdlr.s
user 4!make $1 $.s
era $1x.1
era $1x.2
$2as68 -s 0$1 -f $1 -l -u link68.s
era link68.s
$2cp68 -i 0$1 lnkmess.c $1x.i
$2c068 $1x.i $1x.1 .globl _bios2
.globl _bios3
.globl _bios4
.globl _bios5
.globl _bios6
.裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹 *
* *
* Copyright (c) 1982 Digital Research, Inc.high: .ds.l 1
.end
2
$1x.2 $1x.3
era $1x.i
$2c168 $1x.1 $1x.2 lnkmess.s
era $1x.1
era $1x.2
$2as68 -s 0$1 -f $1 -l -u lnkmess.s
era lnkmess.s
globl _traphnd * trap #2 handler
.globl _swap * byte swapper
.globl _udiv * unsi裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹 *
* *
* Version 0.2 -- September 22, 1982 裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹

$2cp68 -i 0$1 preproc.c $1x.i
$2c068 $1x.i $1x.1 $1x.2 $1x.3
era $1x.i
$2c168 $1x.1 $1x.2 preproc.s
era $1x.1
era $1x.2
gned divide routine
* Declare external routines
.globl __bdos * BDOS entry point in bdosmain
* The foll裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹 *
* *
*************************************裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹*****************************************************************
* $2as68 -s 0$1 -f $1 -l -u preproc.s
era preproc.s
$2lo68 -s -u_nofloat -u_nowildc -r -o link68.rel -f $1 0$1s.o link68.o preowing external references were put in just to make sure that all
* the BDOS modules were referenced, so we could put them$2pip machine.h=machine.68k
$2cp68 -i 0$1 link68.c $1x.i
$2c068 $1x.i $1x.1 $1x.2 $1x.3
era $1x.i
$2c168 $1x.1 $1x.2 link68****************************
* Declare Public Routines
.globl _bios1 * 6 BIOS entry points from BDOS
裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹 *
* CP/M-68K Basic Disk Operating System interface module *
* For "C" version of CP/M-68K in a library
.globl _constat * references conbdos.o
.globl _dirscan * references dskutil.o
long word
move.l 8(sp),d2 * get 2nd parameter (long word)
bra _bios2 * join common routi
move.w (a0)+,d0
movem.l (a0)+,d1-d2
trap #3
bra bdone
*
* Set supervisor mode pr bytes of a word, return swapped value in d0
move.b 5(sp),d0
lsl #8,d0
movD1.W
* address parameters are passed in D1.L
*
move.l d1,-(a7)
move.w d1,-(a7)
move.w d0,-mber
move.w 6(sp),d1 * get 1st parameter (word)
_bios6:
_bios1:
* For all BIOS functions that have no para .globl _create * references fileio.o
.globl _bdosrw * references bdosrw.o
biosf =ne
_bios4:
* For BIOS function seldsk
* Has function number followed by 2 word parameters
move.w 8(sp),d2 ocedure
*
setsup:
ori #$2000,(sp) * turn on supervisor bit in SR
rte
*
* BIOS Interface Routinese.b 4(sp),d0
rts
_udiv:
* Unsigned divide routine
* returns unsigned quotient in D0.W
* UWORD udiv( divisor,(a7)
jsr __bdos * call BDOS
*
* now restore the regs
*
ext.l d0
addq meter other than function number
move.w 4(sp),d0 * get function number
movem.l d3-d7/a3-a6,-(sp)
* 50
setsupf = 62
_traphnd:
*
* first save the registers and
* check for functions handled by assembly* get 2nd parameter (word)
bra _bios2 * join common routine
_bios3:
* For BIOS function set dma
* Has
*
*
* Note - there are 6 BIOS entry points from the BDOS, labelled BIOS1 -
* BIOS6, depending on the parameters passed. dividend, remp )
*
* REG LONG divisor;
* UWORD dividend;
* UWORD *remp /* pointer to remainder (re #8,sp * fix up the stack
bdone:
movem.l (sp)+,a0-a6/d1-d7
rte * save C register variables
trap #3 * do BIOS call
* language routines
*
cmpi #setsupf,d0
beq setsup
movem.l d1-d7/a0-a6,-(sp)
cmpi # function number followed by 1 long parameter
move.l 6(sp),d1 * get long word parameter
bra _bios1
_bios5:
* For BIOS functions sectran and set exception vector
* Has function number and 2 parameters, a word followed by aturned) */
move.l 4(sp), d0 * get dividend
divu 8(sp), d0 * do the divide
movea.l 1 * return from trap call
*
* direct BIOS call function
*
bioscall:
move.l d1,a0 * get address of CPB
* returns value in d0
movem.l (sp)+,d3-d7/a3-a6
rts
*
* Utility Subroutines
*
_swap:
* Swapbiosf,d0
beq bioscall
*
* function number is passed in D0
* byte and word pararmeters are passed in * join common routine
_bios2:
* For all BIOS functions with a word parameter
* Word parameter follows function nu0(sp),a0
swap d0
move.w d0, (a0) * store remainder
clr.w d0
swap d0 r /* register variable */
#define LOCAL auto /* Local var on 68000 ************/
#define BYTE char /* Signed byte */
#define BOOLEAN char /* Function success return val */
#define YES 1 /* "TRUE" */
#define F I L E
* -----------------------------------
* Copyright 1982 by Digital Research Inc. All rightsbyte to word cast */
#else
#define UBYTE unsigned char /* Unsigned byte */
#define UBWORD(a) * word quotient in d0
rts
.end
 */
#define EXTERN extern /* External variable */
#define MLOCAL static /* 2 valued (true/false) */
#define WORD short /* Signed word (16 bits) */
#defNO 0 /* "FALSE" */
#define FOREVER for(;;) /* Infinite reserved.
*
* This is an include file for assisting the user to write portable
* programs for C.
*
***********(UWORD)a
#endif
/****************************************************************************/
/* Miscellaneous De * word quotient in d0
rts
.end
 /* Local to module */
#define GLOBAL /**/ /* Global variable */
#define VOIDine UWORD unsigned int /* unsigned word */
#define LONG long /* si loop declaration */
#define NULL (BYTE *)0 /* Null pointer value */
#define EOF (-1) ******************************************************************/
#define ALCYON 1 /* using Alfinitions: */
/*********************************************************************** * word quotient in d0
rts
.end
 /**/ /* Void function return */
/************gned long (32 bits) */
#define ULONG unsigned long /* Unsigned long */
#define REG registe /* EOF Value */
#define TRUE (1) /* Function TRUE value cyon compiler */
/*
* Standard type definitions
*/
/********************/
#define FAILURE (-1) /* Function failure return val */
#define SUCCESS (0) /*****************************************************************************
*
* C P / M C H E A D E R***************/
#ifdef ALCYON
#define UBYTE char
#define UBWORD(a) ((UWORD)a & 0xff)
/* Unsigned */
#define FALSE (0) /* Function FALSE value */
/***********************************裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹******************************/
r (integer) and an *
* information parameter (which is passed from bdosif as *
* both an integer and a pointer */
/****************************************************************************/
#define abs(x) ((x) < 0 ? -(x) : /****************************************************************
* *****************************************/
/* */
/* 裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹******************************/
). *
* The BDOS can potentially return a pointer, long word, *
* or word (x)) /* Absolute value function */
#define max(x,y) (((x) > (y)) ? (x) : (y)) /* Max function */
*
* CP/M-68K BDOS Main Routine *
* M A C R O S */
/* ----------- 裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹******************************/
 *
* *
* Configured for Alcyon C on the VAX #define min(x,y) (((x) < (y)) ? (x) : (y)) /* Min function */
/*************************** end of stdio.h ** *
* This is the main routine for the BDOS for CP/M-68K *
* It has one entry point, _bdos, which is */
/* */
/* Define some 裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹 *
* *
***********************************************************************/
called from *
* the assembly language trap handler found in bdosif.s. *
* The parameters are a function numbestuff as macros .... */
/* 裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹************************/
#include "bdosinc.h" /* Standard I/O declarations */
#include "bdosdef.h"
EXTERN UWORD flushit(); /* Flush Buffers */
EXTERN UWORD pgmld(); /* Program Load ntial and Random disk read/write */
EXTERN BOOLEAN create(); /* Create file */
EXTERN BOOLEAN delete(he "state variables". These are globals for the single-thread
version of the file system, but are put in a structure so th prt_line(); /* Print line until delimiter */
EXTERN readline(); /* Buffered console read */
EX* 16-bit vector of read-only drives */
GLOBAL UWORD crit_dsk; /* 16-bit vector of drives in "critical"
/* Type and structure declarations for BDOS */
#include "biosdef.h" /* Declarations of BIOS functions */
/* De */
EXTERN UWORD setexc(); /* Set Exception Vector */
EXTERN set_tpa(); /* Get/Set TPA Limi); /* Delete file */
EXTERN BOOLEAN rename(); /* Rename file */
EXTERN BOOLEAN ey can be
based, with a pointer coming from the calling process */
GLOBAL struct stvars gbls;
struct teTERN seldsk(); /* Select disk */
EXTERN BOOLEAN openfile(); /* Open File state. Used to control dir checksums */
GLOBAL BYTE *tpa_lp; /* TPA lower boundary (permanent)clare EXTERN functions */
EXTERN warmboot(); /* Warm Boot function */
EXTERN BOOLEAN constat(); ts */
EXTERN move(); /* general purpose byte mover */
/* Declare "true" global variables; i. set_attr(); /* Set file attributes */
EXTERN getsize(); /* Get File Size */
EXTERN mpstr
{
UBYTE tempdisk;
BOOLEAN reselect;
struct fcb *fptr;
};
/******************************** */
EXTERN UWORD close_fi(); /* Close File */
EXTERN UWORD search(); /* Search first and ne */
GLOBAL BYTE *tpa_lt; /* TPA lower boundary (temporary) */
GLOBAL BYTE *tpa_hp; /* TPA up /* Console status */
EXTERN UBYTE conin(); /* Console Input function */
EXTERN tabout(e., those which will pertain to the
entire file system and thus will remain global even when this becomes
a multi-task setran(); /* Set Random Record */
EXTERN free_sp(); /* Get Disk Free Space */
********************************
* *
* _bdos MAIN xt fcns */
EXTERN UWORD dirscan(); /* General directory scanning routine */
EXTERN UWORD bdosrw(); /* Sequeper boundary (permanent) */
GLOBAL BYTE *tpa_ht; /* TPA upper boundary (temporary) */
/* Declare t); /* Console output with tab expansion */
EXTERN UBYTE rawconio(); /* Raw console I/O */
EXTERN ing file system */
GLOBAL UWORD log_dsk; /* 16-bit vector of logged in drives */
GLOBAL UWORD ro_dsk; /ROUTINE *
* *
* Called with /* punch output to bios */
break;
case 5: blstout((UBYTE)info); /* list output fwarmboot(0); /* warm boot function */
/* break; */
case 1: return((UWORD)coni break;
case 14: seldsk((UBYTE)info); /* select disk */
GBL.dfltdsk = (UBYT *
****************************************************************/
UWORD _bdos(func,info,infop)
REG WORD func; /* read buffered con input */
break;
case 11: return((UWORD)constat()); /* console sta_bdos(func, info, infop) *
* *
* rom bios */
break;
case 6: return((UWORD)rawconio(info)); /* raw console I/O */
n()); /* console input function */
/* break; */
case 2: tabout((UBYTE)info); /* cE)info;
break;
case 15: tmp_sel(&temp); /* open file */
info /* BDOS function number */
REG UWORD info; /* d1.w word parameter */
REG UBYTE *infop; /* d1.l pointer ptus */
/* break; */
case 12: return(VERSION); /* return version number */
Where: *
* func is the BDOS function number (d0.w) *
* /* break; */
case 7: return(bgetiob()); /* get i/o byte */
/* break; */
onsole output with */
break; /* tab expansion */
case 3: returnp->extent = 0;
infop->s2 = 0;
rtnval = dirscan(openfile, infop, 0);
arameter */
{
REG UWORD rtnval;
LOCAL struct tempstr temp;
BSETUP
temp.reselect = FALSE;
tem /* break; */
case 13: log_dsk = 0; /* reset disk system */
ro_dsk info is the word parameter (d1.w) *
* infop is the pointer parameter (d1.l)
case 8: bsetiob(info); /* set i/o byte function */
break;
case 9: ((UWORD)brdr()); /* get reader from bios */
/* break; */
case 4: bpun((UBYTE)info); break;
case 16: tmp_sel(&temp); /* close file */
rtnval = close_fi(infop);
p.fptr = infop;
rtnval = 0;
switch (func) /* switch on function number */
{
case 0: = 0;
crit_dsk= 0;
GBL.curdsk = 0xff;
GBL.dfltdsk = 0;
*
* note that info is the word form of infop*
* prt_line(infop); /* print line function */
break;
case 10: readline(infop); break;
case 17: GBL.srchp = infop; /* search first */
rtnval = seaess */
break;
/* No function 27 -- Get Allocation Vector */
case 28: ro_dsk |= 1 rtnval = dirscan(create, infop, 8);
break;
case 23: tmp_sel(&temp); /* renamw(infop, FALSE, 1);
break;
case 35: tmp_sel(&temp); /* get file size */
TRUE, 0);
break;
case 21: tmp_sel(&temp); /* write sequential */
break; /* return disk parameters */
case 32: if ( (info & 0xff) <= 15 ) /* get/set user number */
rch(infop, 0, &temp);
break;
case 18: infop = GBL.srchp; /* search next */
<<GBL.dfltdsk; /* set disk read-only */
break;
case 29: return(ro_dsk); /* get e file */
rtnval = dirscan(rename, infop, 2);
break;
case 24: return(log getsize(infop);
break;
case 36: tmp_sel(&temp); /* set random record rtnval = bdosrw(infop, FALSE, 0);
break;
case 22: tmp_sel(&temp); /* create GBL.user = (UBYTE)info;
return(UBWORD(GBL.user));
/* break; */
temp.fptr = infop;
rtnval = search(infop, 1, &temp);
break;
cread-only vector */
/* break; */
case 30: tmp_sel(&temp); /* set file attributes _dsk); /* return login vector */
/* break; */
case 25: return(UBWORD(GBL.dfltdsk))*/
setran(infop);
break;
case 37: info = ~info; /* reset d file */
infop->extent = 0;
infop->s1 = 0;
infop->s2 = 0;
case 33: tmp_sel(&temp); /* random read */
rtnval = bdosrw(infop, TRUE, 1);
ase 19: tmp_sel(&temp); /* delete file */
rtnval = dirscan(delete, infop, 2);
*/
rtnval = dirscan(set_attr, infop, 2);
break;
case 31: if (GBL.curdsk ; /* return current disk */
/* break; */
case 26: GBL.dmaadr = infop; /* set dma addrrive */
log_dsk &= info;
ro_dsk &= info;
crit_dsk &= info;
infop->rcdcnt = 0;
/* Zero extent, S1, S2, rcrdcnt. create zeros rest */
break;
case 34: tmp_sel(&temp); /* random write */
rtnval = bdosr break;
case 20: tmp_sel(&temp); /* read sequential */
rtnval = bdosrw(infop,!= GBL.dfltdsk) seldsk(GBL.dfltdsk);
move( (GBL.parmp), infop, sizeof *(GBL.parmp) );
break;
case 40: tmp_sel(&temp); /* write random with 0 fill */
rtmpdisk = fcbp->drvcode);
seldsk( tmp_dsk ? tmp_dsk - 1 : GBL.dfltdsk );
fcbp->drvcode = GBL.user;
temptr->reselode = temp.tempdisk;
/* if reselected disk, restore it now */
return(rtnval); functions: *
* *
* bdosrw() - sequenmaadr)); /* program load */
/* break; */
case 61: return(setexc(infop)); /* set excepti
/****************************************************************
* nval = bdosrw(infop, FALSE, 2);
break;
case 46: free_sp(info); /* get disk free ect = TRUE;
}
 /* return the BDOS return value */
} /* end _bdos */
tmp_sel(temptr) tial and random disk I/O *
* *
* on vector */
/* break; */
case 63: set_tpa(infop); /* get/set TPA limits */
*
* CP/M-68K BDOS Disk Read/Write Module *
* space */
break;
case 47: chainp = GBL.dmaadr; /*sw chain to program */
ct = TRUE;
}
 /* temporarily select disk pointed to by fcb */
REG struct tempstr *temptr;
{
REG struct fcb *fcbp;
REG U *
* Compiled with Alcyon C on the VAX *
* break;
default: return(-1); /* bad function number */
/* br *
* This module contains functions to perform sequential *
* or random access read or write to the di warmboot(0); /* terminate calling program */
/* break; */
case 48: return( ct = TRUE;
}
BYTE tmp_dsk;
BSETUP
fcbp = temptr->fptr; /* get local copy of fcb pointer */
tmp_dsk = (temptr->te *
****************************************************************/
#include "bdosineak; */
}; /* end of switch statement */
if (temp.reselect) infop->drvcsk for CP/M-68K *
* *
* It includes the following externalflushit() ); /* flush buffers */
/* break; */
case 59: return(pgmld(infop,GBL.d裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹c.h" /* Standard I/O declarations */
#include "bdosdef.h" /* Type and structure declarationsm(fcbp, index, wrdfcb)
/* return block number in fcb indicated by index */
REG struct fcb *fcbp; /* pointer to fcb routines *
******************************/
WORD blkindx(fcbp)
/* return index into fcb disk map */
REG structlock; /* block number */
UBYTE rcrd; /* record number */
REG WORD parm; /* write XTERN BOOLEAN create(); /* create file function passed to dirscan */
EXTERN UWORD ro_err(); /* read-only file e of fcb */
WORD wrdfcb; /* boolean, fcb disk map of words */
REG UWORD block; for BDOS */
/* External function definitions */
EXTERN UWORD rdwrt(); /* disk read/write routine * */
REG WORD index; /* index into disk map of fcb */
WORD wrdfcb; fcb *fcbp; /* pointer to fcb */
{
REG struct dpb *dparmp; /* pointer to disk parameter */
{
REG LONG lsec;
REG struct dpb *dparmp;
BSETUP
dparmp = GBL.parmp; rror handler */
/* External variable definitions */
EXTERN UWORD ro_dsk; /* read-only disk vector /* block number */
{
fcbp->s2 &= 0x7f; /* set file write flag */
/
EXTERN WORD getaloc(); /* allocate a block of disk space */
EXTERN WORD swap(); /* assembly langu /* boolean, fcb disk map of words */
{
if (wrdfcb)
return( swap(fcbp->dskmap.big[index]) );
elsparameter block */
REG WORD i;
REG WORD blkshf;
BSETUP
dparmp = GBL.parmp;
blkshf = dparmp->bsh;
/* init dpb pointer */
lsec = ((LONG)block << (dparmp->bsh)) +
(LONG)(rcrd & (dparmp->blm));
ret */
/**********************************************************/
/* First, some utility functions used by seqio an if (wrdfcb)
fcbp->dskmap.big[index] = swap(block);
else fcbp->dskmap.small[index] = (UBYTE)block;
}
/******age byte swapper */
EXTERN UWORD dirscan(); /* directory scanning routine */
EXTERN BOOLEAN openfile(e return( UBWORD(fcbp->dskmap.small[index]) );
}
setblk(fcbp, index, wrdfcb, block)
/* put block number into fcb */
RE i = ((fcbp->extent) & dparmp->exm) << (7 - blkshf);
return (i + (UBWORD(fcbp->cur_rec) >> blkshf) );
}
UWORD blknuurn( rdwrt(lsec, GBL.dmaadr, parm) );
}
/*******************************************
* routine for crossing extent boundd ranio */
/**********************************************************/
/******************************
* FCB block number*********************
* disk read/write routine *
***************************/
UWORD do_io(block, rcrd, parm)
UWORD b); /* open file function passed to dirscan */
EXTERN UWORD close_fi(); /* close file function */
EG struct fcb *fcbp; /* pointer to fcb */
REG WORD index; /* index into disk maparies *
*******************************************/
WORD new_ext(fcbp, reading, ran)
/* If sequential I/O, open the nextclose old extent */
t_mod = fcbp->s2;
t_ext = fcbp->extent;
fcbp->s2 = mod;
fcbp->extent = ext;
if ( di >= 64) return(6); /* past maximum file size */
if ( mod == ((fcbp->s2) & 0x3f) )
if ( ! ((ext ^ (fcbp->) & 0x1f | i );
}
/*********************************
* Routine to get the actual *
* record count of the currently ran)
{
mod = ( (fcbp->ran0) << 4) | ( (fcbp->ran1) >> 4);
ext = ( ((fcbp->ran1) & 0x0f) << 1);
i a *
* extent-folded environment *
************************************/
UWORD calcext(fcbp)
REG struct fcb extent */
/* If random I/O, compute new extent from random record field */
REG struct fcb *fcbp; rscan(openfile, fcbp, 0) >= 255 ) /* open extent */
{
if (reading)
{ /* rextent)) & ~((GBL.parmp)->exm) & 0x1f) )
{ /* we're in same logical extent */
*
* active logical extent of a FCB *
*********************************/
UWORD get_rc(fcbp)
REG struct fcb *fcbp;
{
f ((fcbp->ran2) & 0x80) ext |= 1;
/* the calculation of ext was coded this way because of a */
*fcbp;
{
REG UWORD i;
REG BYTE *p;
BSETUP
i = 15;
p = &(fcbp->dskmap.small[16]);
do
{
/* pointer to fcb */
BOOLEAN reading; /* read/write flag */
WORD ran; /* random I/eading unwritten extent */
fcbp->s2 = t_mod;
fcbp->extent = t_ext;
return(4);
}
fcbp->extent = ext;
return(0);
}
/* Extent or Module numbers don't match */
/* Close the o REG UWORD ext;
ext = calcext(fcbp); /* find last active extent in fcb */
if (ext == fcbp->extent) return( /* compiler bug from Alcyon */
}
else
{
mod = (fcbp->s2) & 0x3f;
ext = (fcbp->extent) + 1; if (*--p) break;
i -= 1;
} while (i);
/* Now i contains the index of the last non-zero block in the FCB *O flag */
{
REG UBYTE mod; /* module number */
REG UBYTE ext; /* extent number */
if ( dirscan(create, fcbp, 8) >= 255 )
return(5); /* can't create new extent */
}
ld extent and open a one */
if ( close_fi(fcbp) >= 255 ) return(3);
/* can't UBWORD(fcbp->rcdcnt));
/* if this is the last active fcb, return fcb's rc */
else if (ext > fcbp-> /* for sequential, incr extent */
}
if (ext >= 32)
{
ext = 0;
mod += 1;
}
if (mod/
if ((GBL.parmp)->dsm > 255) i >>= 1;
i >>= 7 - ((GBL.parmp)->bsh);
return ( (fcbp->extent) & ~((GBL.parmp)->exmREG UBYTE t_mod; /* temp mod number */
REG UBYTE t_ext; /* temp extent */
BSETUP
if ( return(0);
}
/************************************
* Routine to calculate the maximum *
* extent number of an FCB inextent) return(128);
/* if the fcb has more extents past this one, then */
/* if (fcbp->cur_rec == 128)
{ /* time to try next extent */
if ( new_ext(fcbp, r rcdcnt */
BSETUP
bigfile = ((GBL.parmp)->dsm) & ~0xff;
if ( ( ! reading) && (fcbp->ftype[robit] & 0x80) */
block = getaloc(blknum(fcbp, (index ? (index - 1) : 0), bigfile));
if (block == ~0) return(2); /* 2 = random with zero fill */
{
REG UWORD block; /* block number from fcb */
RE* get index into fcb disk map */
block = blknum(fcbp, index, bigfile);
if (block) parm = (reading ? 0 : 1);
else the current one is logically full */
else return (0);
/* if we seeked past the last active extereading, FALSE) )
return(1); /* if can't open new extent, error */
fcbp->cur_rec = 0; /* ope)
ro_err(fcbp,((GBL.dpbp)->dpbp)->drm);
/* check for read-only file */
i /* out of space */
setblk(fcbp, index, bigfile, block);
parm = 3;
if (random == 2)
{ G WORD index; /* index into disk map of fcb */
REG BYTE *old_dma; /* temp holding spot for dmaadr */ /* if allocated block, parm is just read or write */
{ /* unallocated blocnt, rc = 0 */
}
/************************
* bdosrw entry point *
************************/
UWORD bdosrw(fcbp, readned new extent, zero cur_rec */
}
/* record is now in active fcb */
rc = fcbp->rcdcnt;
if ( UBWORD(fcbf (random)
{
if ( rtn = new_ext(fcbp, reading, TRUE) ) return(rtn);
/* open new extent if /* Write random with zero fill */
old_dma = GBL.dmaadr;
GBL.dmaadr = GBL.di
REG WORD parm; /* parameter to do-io */
REG WORD bigfile; /* file system is in word k */
if (reading) return(1); /* reading unwritten data */
/* Writing to new block */
/* ing, random)
REG struct fcb *fcbp; /* fcbp is a pointer to a fcb */
REG BOOLEAN reading; /* boolean to p->cur_rec) >= get_rc(fcbp) )
{
if (reading) return(1); /* reading unwritten data */
fcbp->s2 &= necessary, return if error */
fcbp->cur_rec = (fcbp->ran2) & 0x7f;
}
else /* sequential */
rbufp; /* Do DMA from dir_buf */
index = SECLEN;
do GBL.dmaadr[--index] = 0;
while mode */
REG UWORD rtn; /* return parameter */
REG UBYTE rc; /* temp storage foThe parm passed to getaloc is the previously allocated block */
/* or 0, if the previous block is not allocated tell whether to read or write */
WORD random; /* 0 = sequential, 1 = random (normal), */
0x7f; /* set file write flag */
rc = fcbp->cur_rec + 1;
}
index = blkindx(fcbp); /(index); /* zero the dma buffer */
for (index = 0; index <= ((GBL.parmp)->blm); index++)
{
ply defines the BIOS calls *
* *
***************************************裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹 brdr() bios1(7) /* reader input */
#define bhome() bios1(8) /* recalibrate drive */
bp->rcdcnt = rc;
if ( ! random ) fcbp->cur_rec += 1;
}
return(rtn);
}
ception */
EXTERN BYTE *bios6(); /* for get memory segment table */
#define bwboot() bios1(1) do_io(block, (UBYTE)index, parm);
/* write zeros to the block */
*****************/
EXTERN UBYTE bios1(); /* used for character I/O functions */
EXTERN bios2(); /*
/********************************************************
* *
* B
#define bseldsk(parm1,parm2) bios4(9,parm1,parm2)
/* select disk and return info */
#bp->rcdcnt = rc;
if ( ! random ) fcbp->cur_rec += 1;
}
return(rtn);
}
 /* warm boot */
#define bconstat() bios1(2) /* console status */
#define bconin() parm = 1; /* next write is not to new block */
}
GBL.dmaadr = old_dma; / parm1 is word, no return value */
EXTERN bios3(); /* used for set dma only */
IOS definitions for CP/M-68K *
* *
* Copyright (define bsettrk(parm) bios2(10,parm) /* set track on disk */
#define bsetsec(parm) bios2(11,parm) /* set sector for disbp->rcdcnt = rc;
if ( ! random ) fcbp->cur_rec += 1;
}
return(rtn);
}
 bios1(3) /* console input */
#define bconout(parm) bios2(4,parm) /* console output parm */
#define blstout* restore dma address */
}
}
rtn = do_io(block, fcbp->cur_rec, parm);
if ( rtn == 0 )
{
f /* parm1 is a pointer, no return */
EXTERN UBYTE *bios4(); /* seldsk only, parm1 and parm2 are */
c) 1982 Digital Research, Inc. *
* *
* This include file simk */
#define bsetdma(parm) bios3(12,parm) /* set dma address */
#define bread() bios1(13) /* read secto裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹(parm) bios2(5,parm) /* list device output */
#define bpun(parm) bios2(6,parm) /* punch char output */
#definecbp->rcdcnt = rc;
if ( ! random ) fcbp->cur_rec += 1;
}
return(rtn);
}
 /* words, returns a pointer to dph */
EXTERN UWORD bios5(); /* for sectran and set exr from disk */
#define bwrite(parm) bios2(14,parm) /* write sector to disk */
#define blistst() bios1(15) /* l裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹iented |
| interface for the console user to the |
| information maintained by the BDOS on |
| disk storage. * set exception vector */
 *==================================================* |
| *==================================================* |
| *ist device status */
#define bsectrn(parm1,parm2) bios5(16,parm1,parm2)
/* sector tr裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹 |
| |
| created by : Tom Saulpaugh Date created: 7/13/82 |
| ---------- ------------ |
| last modif set exception vector */
THIS IS THE DUAL PROCESSOR,ROMABLE CP/M-68K SYSTEM* |
| *==================================================* |
| *==anslate */
#define bgetseg() bios6(18) /* get memory segment tbl */
#define bgetiob() bios1(19) /裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹ied: 03/17/84 sw St. Patrick's Day!!! |
| ------------- Chain hack -------------------- |
| |
| (c) COPY set exception vector */
================================================* |
| |
| Description: |
| ----------- |
| * get I/O byte */
#define bsetiob(parm) bios2(20,parm) /* set I/O byte */
#define bflush() bios1(21)/*--------------------------------------------------------------*\
| ccp.c CONSOLE COMMAND PROCESSOR v1.1 |
裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹RIGHT Digital Research 1983, 1984 |
| all rights reserved |
| |
\*------------------------------- set exception vector */
 The Console Command Processor is a |
| distinct program which references |
| the BDOS to provide a human-or /* flush buffers */
#define bsetvec(parm1,parm2) bios5(22,parm1,parm2)
/ | ========================= |
| |
| CP/M 68k: A CP/M derived operating system |
| |
| -------------------------------*/
/*--------------------------------------------------------------*\
| CCP Macro D
BYTE msg12[] = "User # range is [0-15]$";
BYTE msg13[] = "Too many arguments: $";
BYTE lderr1[] = "Insufficient memory oPrompts and Messages |
\*--------------------------------------------------------------*/
BYTE msg[] = "NON-SYSTEM FILE(S) Ent default disk drive */
BYTE subcom[CMD_LEN+1]; /* submit command buffer */
BYTE subdma[CMD_LEN]; /* buffer to fill from ,DIRSCMD,
"TYPE",TYPECMD,
"REN",RENCMD,
"ERA",ERACMD,
"USER",UCMD,
"SUBMIT",SUBCMD,
NULL,-1
};
chaining flag */
extern BYTE submit; /* submit file flag */
BYTE end_of_file; /* submit end of file flag */
BYTE dirflagefinitions |
\*--------------------------------------------------------------*/
#include "ccpdef.h" /* include CCP definesr bad file header$";
BYTE lderr2[] = "Read error on program load$";
BYTE lderr3[] = "Bad relocation information bits$";
BYTXIST$";
BYTE msg2[] = "Enter Filename: $";
BYTE msg3[] = "Enter Old Name: $";
BYTE msg4[] = "Enter New Name: $";
BYTE msg5[]sub file */
extern BYTE usercmd[CMD_LEN+2]; /* user command buffer */
BYTE *user_ptr; /* next user command to execute */
B/*--------------------------------------------------------------*\
| CP/M-68K COMMAND FILE LOADER TABLE |
\*---------------; /* used by fill_fcb(? or blanks)*/
BYTE subprompt; /* submit file was prompted for */
extern BYTE morecmds; /* command */
/*--------------------------------------------------------------*\
| CP/M Builtin Command Table |
\*------E lderror[] = "Program load error$";
/*--------------------------------------------------------------*\
| Global Arrays = "File already exists$";
BYTE msg6[] = "No file$";
BYTE msg7[] = "No wildcard filenames$";
BYTE msg8[] = "Syntax: REN NewfiYTE *glb_index; /* points to current command */
BYTE save_sub[CMD_LEN+1]; /* saves cur cmd line for submit*/
BYTE subfcb[FCB_-----------------------------------------------*/
extern struct _filetyps
{
BYTE *typ;
UWORD (*loader) ();
BYTE user_c;
after warmboot flag */
UWORD sub_index; /* index for subdma buffer */
UWORD index; /* index into cmd argument array*/
UW--------------------------------------------------------*/
struct _cmd_tbl
{
BYTE *ident; /* command identifer field */
U& Variables |
\*--------------------------------------------------------------*/
/********************************/
Ble=Oldfile$";
BYTE msg9[] = "Confirm(Y/N)? $";
BYTE msg10[] = "Enter User No: $";
BYTE msg11[] = ".SUB file not found$";
LEN]; /* global fcb for sub files */
BYTE cmdfcb[FCB_LEN]; /* global fcb for 68k files */
BYTE *tail; /* pointer to comman
BYTE user_0;
}
load_tbl[];
/*--------------------------------------------------------------*\
| Table of User ORD sub_user; /* submit file user number */
UWORD user; /* current default user number */
UWORD cur_disk; /* curreWORD cmd_code; /* command code field */
}
cmd_tbl[8] = /* declare CP/M built-in table */
{
"DIR",DIRCMD,
"DIRS"YTE load_try; /* flag to mark a load try */
BYTE first_sub; /* flag to save current cmd ptr */
BYTE chain_sub; /* submitd tail */
extern BYTE autost; /* autostart flag */
BYTE autorom; /* needed for ROM system autost */
BYTE dma[DMA_LENCONSOLE_OUTPUT,CR);
bdos(CONSOLE_OUTPUT,LF);
}
/********************************/
VOID cpy(source,dest) /* copy sourcWORD chk_colon(); /* this returns a word */
UWORD user_cmd(); /* this returns a word */
UWORD cmd_file(); /* this returns NULL;
}
/********************************/
VOID prompt() /* print the CCP prompt */
/*********************/
extern UWORD bdos(); /* this returns a word */
extern UWORD load68k(); /* this returns a word(1-3) */
e command which */
/* started a submit file */
/* Parameter substituion will */
/* need this command ta+3]; /* 128 byte dma buffer */
BYTE parm[MAX_ARGS][ARG_LEN]; /* cmd argument array */
BYTE *chainp; /*sw -> User-specifiee to destination */
/********************************/
REG BYTE *source;
REG BYTE *dest;
{
while(*dest++ = *source++) a word */
UWORD sub_read(); /* this returns a word */
UWORD dollar(); /* this returns a word */
UWORD comments(); /* *********************/
{
REG UWORD cur_drive,cur_user_no;
BYTE buffer[3];
cur_user_no = bdos(GET_USER_NO,(long)255BYTE *scan_cmd(); /* this returns a ptr to a byte */
UWORD strcmp(); /* this returns a word */
UWORD decode(); /* this ril. */
/* The buffer save_sub is used */
/* to store the command. */
/********************************/
REG Bd command */
BYTE del[] = /* CP/M-68K set of delimeters */
{'>','<','.',',','=','[',']',';','|','&','/','(',')','+','-',;
}
/********************************/
UWORD strcmp(s1,s2) /* compare 2 char strings */
/*****************this returns a word */
UWORD submit_cmd(); /* this returns a word */
/********************************/
/******);
cur_drive = bdos(RET_CUR_DISK,(long)0);
cur_drive += 'A';
cr_lf();
if(cur_user_no)
{
if(cur_user_no >= 10)
eturns a word */
UWORD delim(); /* this returns a word */
BYTE true_char(); /* this returns a byte */
UWORD fill_fcb();YTE *com_index;
{
REG BYTE *t1,*temp;
temp = save_sub;
if(subprompt)
{
t1 = parm;
while(*t1)
*temp++ = *t1+'\\'};
/********************************/
/*--------------------------------------------------------------*\
| ***************/
REG BYTE *s1,*s2;
{
while(*s1)
{
if(*s1 > *s2)
return(1);
if(*s1 < *s2)
return(-1);
s1**************************/
VOID cr_lf() /* print a CR and a Linefeed */
/********************************/
{
bdos( {
buffer[0] = '1';
buffer[1] = ((cur_user_no-10) + '0');
buffer[2] = '$';
}
else
{
buffer[0] = (cur_us /* this returns a word */
UWORD too_many(); /* this returns a word */
UWORD find_colon(); /* this returns a word */
U+;
*temp++ = ' ';
subprompt = FALSE;
}
while(*com_index && *com_index != EXLIMPT)
*temp++ = *com_index++;
*temp = Function Definitions |
\*--------------------------------------------------------------*/
/**********************++; s2++;
}
return((*s2 == NULL) ? 0 : -1);
}
/********************************/
VOID copy_cmd(com_index) /* Save ther_no + '0');
buffer[1] = '$';
}
bdos(PRINT_STRING,buffer);
}
bdos(CONSOLE_OUTPUT,(long)cur_drive);
bdos(CONSOLEDelimeter */
/*****************************************************/
if(fill_fcb(0,cmdfcb) > 0)
return(-1);
if(iand */
/********************************************************/
i = 0;
while(i < (ARG_LEN-1) && parm[0][i] != ':')
i+
if(*user_ptr)
morecmds = TRUE;
}
}
else
morecmds = FALSE;
}
/************************/
VOcognize the command as: */
/* --------- */
/* 1. Builtin */
/* 2. File */
/***************************a warmboot */
/*----------------------------*/
if(*tcmd++ == EXLIMPT && *tcmd)
{
morecmds = TRUE;
while(*tcmd ==_OUTPUT,ARROW);
}
/********************************/
VOID echo_cmd(cmd,mode) /* echo any multiple commands */
== 1)
i = 2;
else
i = 0;
if(delim(&parm[0][i]))
return(-1);
for(n = 0;n < ARG_LEN-1 && parm[0][n];n++)
if(par+;
if(i == 1 && parm[0][2] == NULL && parm[1][0] == NULL)
if((parm[0][0] >= 'A') && (parm[0][0] <= 'P'))
return(CH_DIID get_cmd(cmd,max_chars) /* Read in a command */
/*Strip off extra blanks*/
/************************/
*****/
REG BYTE *cmd;
{
REG UWORD i,n;
/****************************************/
/* Check for a CP/M builtin comman ' ')
tcmd++;
user_ptr = tcmd;
}
else
if(submit) /* check original cmd line */
{
if(!(end_of_file))
mo /* or any illegal commands */
/********************************/
REG BYTE *cmd;
REG UWORD mode;
{
if(mode == GOOD &m[0][n] < ' ')
return(-1);
return(FILE);
}
/************************/
VOID check_cmd(tcmd) /* Check end of cSK);
if(i == 1 && ((parm[0][0] < 'A') || (parm[0][0] > 'P')))
return(-1);
if(i != 1 && parm[0][i] == ':')
return(-1);
REG BYTE *cmd;
REG long max_chars;
{
REG BYTE *c;
max_chars += (cmd - 1);
dma[0] = CMD_LEN; /* set maximum chars tod */
/****************************************/
for(i = 0; i < 7;i++)
if (strcmp(cmd,cmd_tbl[i].ident) == MATCH)
returecmds = TRUE;
/*--------------------------*/
else /* restore cmd to where user*/
/* ptr points to. User_ptr */
& (!(autost && autorom)))
prompt();
while(*cmd && *cmd != EXLIMPT)
bdos(CONSOLE_OUTPUT,(long)*cmd++);
if(mode == BAD)
md */
/* for an '!' which */
/* starts another cmd */
REG BYTE *tcmd; /************************/
{
whil
/*****************************************************/
/* Check for Wildcard Filenames */
/* Check Filename for a read */
bdos(READ_CONS_BUF,dma); /* then read console */
if(dma[1] != 0 && dma[2] != ';')
cr_lf();
dma[((UWORD)dma[rn(cmd_tbl[i].cmd_code);
/********************************************************/
/* Check for a change of disk drive comm /* always points to next */
/* console command to exec */
{ /*--------------------------*/
submit = FALSE;
bdos(CONSOLE_OUTPUT,(long)'?');
else
cr_lf();
}
/********************************/
UWORD decode(cmd) /* Ree(*tcmd && *tcmd != EXLIMPT)
tcmd++;
/*----------------------------*/
/* check for multiple command */
/* in case of 1] & 0xFF)+2] = '\n'; /* tack on end of line char */
if(dma[2] == ';') /* ';' denotes a comment */
dma[2] = '\n';
c***************/
/* separate command line at blanks,exlimation pts */
/***************************************************//
/* parmeters associated with the command are put*/
/* in in sequential order in parm[1],parm[2], */
/* and parm[3]. A return(*ch);
}
return(' '); /* pad field with blank */
}
/************************/
UWORD fill_fcb(which_parmcom_index++;
while(*com_index == EXLIMPT || *com_index == ' ' ||
*com_index == TAB)
com_index++;
return(com_indexa delimeter */
/************************/
REG BYTE *ch;
{
REG UWORD i;
if(*ch <= ' ')
return(TRUE);
for(i = = &dma[2];
while(*c == ' ' || *c == TAB)
c++;
while(*c != '\n' && cmd < max_chars)
{
*cmd++ = toupper(*c);
if
while(*cmd != NULL &&
*cmd != EXLIMPT &&
i < MAX_ARGS)
{
j = 0;
while(*cmd != EXLIMPT &&
command ends at a NULL or */
/* an exlimation point. */
/************************************************/
REG B,fcb) /* fill the fields of */
/* the file control blk */
/************************/
REG UWORD which_parm;
REG );
}
/************************/
VOID get_parms(cmd) /* extract cmd arguments*/
/* from command line */
REG0;i < sizeof (del);i++)
if(*ch == del[i]) return(TRUE);
return(FALSE);
}
/************************/
BYTE true(*c == ' ' || *c == TAB)
while(*++c == ' ' || *c == TAB);
else
c++;
}
*cmd = NULL; /* tack a null character
*cmd != ' ' &&
*cmd != TAB &&
*cmd)
{
if(j < (ARG_LEN-1))
parm[i][j++] = *cmd;
YTE *line; /* pointer to parm array */
REG UWORD i; /* Row Index */
REG UWORD j; /* Column Index */
BYTE *fcb;
{
REG BYTE *ptr;
REG BYTE fillch;
REG UWORD j,k;
*fcb = 0;
for(k = 12;k <= 35; k++) /* fill fc BYTE *cmd; /************************/
{
/************************************************/
/* This function parse_char(ch) /* return the desired */
/* character for fcb */
/************************/
REG BYTE *ch;
{
if(*chon the end*/
}
/************************/
BYTE *scan_cmd(com_index) /* move ptr to next cmd */
/* in the command cmd++;
}
parm[i++][j] = NULL;
if(*cmd == ' ' || *cmd == TAB)
cmd++;
if(i == 1)
tail = cmd; /* mark the be
line = parm;
for(i = 0; i < (MAX_ARGS * ARG_LEN); i++)
*line++ = NULL;
i = 0;
/************************************b with zero */
fcb[k] = ZERO;
for(k = 1;k <= 11;k++)
fcb[k] = BLANK; /* blank filename+type */
/******************s the command line */
/* read in by get_cmd(). The expected command */
/* from that line is put into parm[0]. All * == '*') return('?'); /* wildcard */
if(!delim(ch)) /* ascii character */
{
index++; /* increment cmd index */
line */
/************************/
REG BYTE *com_index;
{
while((*com_index != EXLIMPT) &&
(*com_index))
ginning of the tail */
}
}
/************************/
UWORD delim(ch) /* check ch to see */
/* if it's *************************/
/* extract drivecode,filename and filetype */
/* from parmeter blk */
/*******************colon */
{ /************************/
REG UWORD i;
i = 0;
while(parm[1][i] && parm[1][i] != ':') i++;
return(i); 3;j++) /* get extension */
*ptr++ = true_char(&parm[which_parm][index]);
}
k = 0;
for(j = 1;j <= 11;j++)
if(fcbnt = 0;
while(dir_index != 255)
{
if(((attrib) && (dma[save+9] & 0x80)) ||
(!(attrib) && (!(dma[save+9] & 0x 1;j <= 11;j++)
*ptr++ = fillch;
if(dirflag)
return(11);
else
return(0);
}
}
else /* fill d/
/* attrib->1 (sysfiles) */
/* attrib->0 (dirfiles) */
/************************/
REG UWORD attrib;
{
BYT************************/
if(dirflag)
fillch = '?';
else
fillch = ' ';
index = ZERO;
ptr = fcb;
if(parm[whic
}
/************************/
UWORD chk_colon(j) /* check the position of*/
UWORD j; /* the colon and for */
{[j] == '?') k++;
return(k); /* return the number of question marks */
}
/************************/
UWORD too_many() 80))))
{
if(needcr_lf)
{
cr_lf();
needcr_lf = FALSE;
}
if(file_cnt == 0)
bdos(CONSOLE_Orivecode with the default disk */
*fcb = (bdos(RET_CUR_DISK,(long)0) + 1);
ptr = fcb;
ptr++; /* set poiE needcr_lf;
REG UWORD dir_index,file_cnt;
REG UWORD save,j,k,curdrive,exist;
exist = FALSE; needcr_lf = FALSE;
if(th_parm][index] == NULL) /* no parmemters */
{
ptr++;
for(j = 1;j <= 11;j++)
*ptr++ = fillch;
*fcb = (bdos(RET_C /* a legal drive letter */
if(parm[1][j] == ':') /************************/
{
if(j != 1 || parm[1][0] < 'A' || parm /* too many args ? */
{ /************************/
if(parm[2][0])
{
bdos(PRINT_STRING,msg13);
echo_cmd(&paUTPUT,(long)curdrive);
}
else
{
exist = TRUE;
dir_index = bdos(SEARCH_NEXT);
save = (32 * dir_indnter to fcb filename */
for(j = 1;j <= 8;j++) /* get filename */
*ptr++ = true_char(&parm[which_parm][index]);
while((!(oo_many()) return;
j = find_colon();
if(!chk_colon(j)) return;
fill_fcb(1,cmdfcb);
curdrive = (cmdfcb[0] + 'A' - 1);
dUR_DISK,(long)0)+1);
if(dirflag)
return(11);
else
return(0);
}
if(parm[which_parm][index+1] == ':')
{
*pt[1][0] > 'P')
{
echo_cmd(&parm[1][0],BAD);
return(FALSE);
}
}
return(TRUE);
}
/***************rm[2][0],BAD);
return(TRUE);
}
return(FALSE);
}
/************************/
UWORD find_colon() /* search for a ex) + 1;
continue;
}
dir_index = (32 * dir_index) + 1;
bdos(CONSOLE_OUTPUT,COLON);
bdos(CONSOLE_OUTPUT,BLANKS)delim(&parm[which_parm][index])))) index++;
if(parm[which_parm][index] == PERIOD)
{
index++;
for(j = 1;j <=ir_index = bdos(SEARCH_FIRST,cmdfcb);
if(dir_index == 255)
bdos(PRINT_STRING,msg6);
save = (32 * dir_index) + 1;
file_cr = parm[which_parm][index] - 'A' + 1;
index += 2;
if(parm[which_parm][index] == NULL)
{
ptr = &fcb[1];
for(j =*********/
VOID dir_cmd(attrib) /* print out a */
/* directory listing */
/*----------------------*;
j = 1;
while(j <= 11)
{
if(j == 9)
bdos(CONSOLE_OUTPUT,BLANKS);
bdos(CONSOLE_OUTPUT,(long)(dma[dir_index*/
VOID ren_cmd() /* rename a file */
/************************/
{
BYTE new_fcb[FCB_LEN];
REG UWOR
if(!chk_colon(i)) return;
i = fill_fcb(1,cmdfcb); /*fill a file control block*/
if(i == 0 && parm[1][0] && (bdos(OPEN_FIL while(parm[j][k] != ':' && parm[j][k])
k++;
if(k > 1 && parm[j][k] == ':')
bad_cmd = TRUE;
for(i = 0;i < sizeof e */
{ /*----------------------------------------*/
cr_lf();
if(attrib)
bdos(PRINT_STRING,msg);
else
bdos(------------*/
i = 0;
while(parm[1][i] != '=' && parm[1][i]) i++;
if(parm[1][i] == '=')
{
if(!(i > 0 && parm[1][++] & CMASK));
j++;
}
bdos(CONSOLE_OUTPUT,BLANKS);
dir_index = bdos(SEARCH_NEXT);
if(dir_index == 255)
breakD i,j,k,bad_cmd;
bad_cmd = FALSE; /*-------------------------*/
if(parm[1][0] == NULL) /*prompt user for fiE,cmdfcb) <= 3))
{
while(bdos(READ_SEQ,cmdfcb) == 0)
{
for(i = 0;i <= 127;i++)
if(dma[i] != EOF)
bdos(del;i++)
if(parm[j][0] == del[i])
{
echo_cmd(&parm[j][0],BAD);
return;
}
}
if(!bad_cmd && parm[1][0] &PRINT_STRING,&msg[4]);
}
}
/************************/
VOID type_cmd() /* type out a file */
/* i+1] &&
parm[2][0] == NULL))
bad_cmd = TRUE;
}
else
if(!(parm[2][0] == '=' &&
parm[2][1] == NU;
file_cnt++;
save = (32 * dir_index) + 1;
if(file_cnt == 5)
{
file_cnt = 0;
if((attrib && (dma[save+9] & 0xlenames*/
{ /*-------------------------*/
bdos(PRINT_STRING,msg3);
get_cmd(&parm[3][0],(long)(ARG_LEN-1));
CONSOLE_OUTPUT,(long)dma[i]);
else
break;
}
bdos(RESET_DRIVE,(long)cmdfcb[0]);
} else
if(parm[1][0])
{
& parm[3][0])
{
i = fill_fcb(1,new_fcb);
j = fill_fcb(3,cmdfcb);
if(i == 0 && j == 0)
{
if(new_fcb[0] != cmdfc to the console */
/************************/
{
REG UWORD i;
if(parm[1][0] == NULL) /*prompt user for filename*/LL &&
parm[3][0]))
bad_cmd = TRUE;
if(!bad_cmd && parm[1][i] == '=')
{
parm[1][i] = NULL;
i++;
j80)) ||
(!(attrib) && (!(dma[save+9] & 0x80))))
cr_lf();
else
needcr_lf = TRUE;
}
} /*------------ if(parm[3][0] == NULL)
return;
bdos(PRINT_STRING,msg4);
get_cmd(&parm[1][0],(long)(ARG_LEN-1));
parm[2][0] = '='
if(i > 0)
bdos(PRINT_STRING,msg7);
else
bdos(PRINT_STRING,msg6);
}
}
/***********************b[0])
{
if(parm[1][1] == ':' && parm[3][1] != ':')
cmdfcb[0] = new_fcb[0];
else
if(parm[1][1] != ':' &&
{
bdos(PRINT_STRING,msg2);
get_cmd(&parm[1][0],(long)(ARG_LEN-1));
}
if(too_many())
return;
i = find_colon();
= 0;
while((parm[3][j++] = parm[1][i++]) != NULL);
parm[2][0] = '=';
}
}
for(j = 1;j < 4;j += 2)
{
k = 0;
----------------------------*/
if(exist) /* if files exist that were not displayed */
/* print out a message to the consol;
} /*--------------------------------*/
else /*check for correct command syntax*/
{ /*-------------------- parm[3][1] == ':')
new_fcb[0] = cmdfcb[0];
else
bad_cmd = TRUE;
}
if(new_fcb[0] < 1 || new_fcb[0] > 16)********/
{
REG UWORD i;
if(parm[1][0] == NULL) /* prompt for a number */
{
bdos(PRINT_STRING,msg10);
get_cmd( return;
}
i = fill_fcb(1,cmdfcb); /* fill an fcb */
if(i > 0 && !(submit)) /* no confirmation */
{ /* if subm /* search the current */
/* user # then user 0 */
/* */
/************************/
UWORD mode;
{
BYerase a file from */
/* the directory */
/************************/
{
REG UWORD i;
/*-------======== */
/* */
/* 1. 68K type on the */
/* current user # */
/* 2. BLANK type on */
bad_cmd = TRUE;
if(!(bad_cmd) && bdos(SEARCH_FIRST,new_fcb) != 255)
bdos(PRINT_STRING,msg5);
else{
k = 0&parm[1][0],(long)(ARG_LEN-1));
}
if(parm[1][0] == NULL)
return(TRUE);
if(too_many())
return(TRUE);
if(parm[1][0] it file */
bdos(PRINT_STRING,msg9);
parm[2][0] = bdos(CONIN,(long)0);
parm[2][0] = toupper(parm[2][0]);
cr_lf();
TE done,open,sub_open;
BYTE found;
REG UWORD i,n;
UWORD (*ldrpgm) ();
REG BYTE *top;
REG struct _filetyps *p;
dirf---------------*/
if(parm[1][0] == NULL) /* prompt for a file */
{ /*----------------------*/
bdos(PRINT_STRING,msg2)/* current user # */
/* 3. SUB type on the */
/* current user # */
/* 4. 68K type on */
/* us;
for(i = 16;i <= 35;i++)
cmdfcb[i] = new_fcb[k++];
if(cmdfcb[0] < 0 || cmdfcb[0] > 15)
bad_cmd = TRUE;
< '0' || parm[1][0] > '9')
return(FALSE);
i = (parm[1][0] - '0');
if(i > 9)
return(FALSE);
if(parm[1][1])
i = ((i if(parm[2][0] != 'N' && parm[2][0] != 'Y')
return;
}
if(parm[2][0] != 'N')
if(bdos(DELETE_FILE,cmdfcb) > 0)
bdoslag = FALSE;
load_try = TRUE;
done = FALSE;
found = FALSE;
sub_open = FALSE;
open = FALSE;
user = bdos(GET_USER_NO;
get_cmd(&parm[1][0],(long)(ARG_LEN-1));
}
if(parm[1][0] == NULL)
return;
if(too_many())
return;
i = find_coloer 0 */
/* 5. BLANK type on the */
/* user 0 */
/* 6. SUB type on */
/* user 0 */
if(!(bad_cmd) &&
bdos(RENAME_FILE,cmdfcb) > 0)
bdos(PRINT_STRING,msg6);
}
}
else
bdos(PRINT_STRI * 10) + (parm[1][1] - '0'));
if(i < 16 && parm[1][2] == NULL)
bdos(GET_USER_NO,(long)i);
else
return(FALSE);
return(PRINT_STRING,msg6);
}
/************************/
UWORD user_cmd() /* change user number */
/****************,(long)255);
cur_disk = bdos(RET_CUR_DISK,(long)0);
if(mode == SEARCH) i = 0; else i = 1;
i = fill_fcb(i,cmdfcb);
if(i >n();
if(!chk_colon(i))
return;
else
if(parm[1][1] == ':' && parm[1][2] == NULL)
{
echo_cmd(&parm[1][0],BAD);
/* */
/*----------------------*/
/* */
/* If a filetype is */
/* specified then I */
NG,msg7);
}
if(bad_cmd)
bdos(PRINT_STRING,msg8);
}
/************************/
VOID era_cmd() /* (TRUE);
}
UWORD cmd_file(mode)
/************************/
/* */
/* SEARCH ORDER */
/* ==== 0)
{
bdos(PRINT_STRING,msg7);
return(FALSE);
}
p = &load_tbl;
top = p->typ;
if(cmdfcb[9] == ' ')
{
whilemdfcb[11] == 'B')
{
sub_open = TRUE;
sub_user = bdos(GET_USER_NO,(long)255);
if(submit) chain_sub = TRUE;
fill_fcb(1,cmdfcb);
p = &load_tbl;
while(*(p->typ))
{
if(p->user_c || p->user_0)
{
if(mode == SEARd_try = FALSE;
morecmds = FALSE;
return((sub_open || open));
}
/************************/
UWORD sub_read() /* R MATCH)
{
found = TRUE;
if(dma[i] == user) p->user_c = TRUE;
else p->user_0 = TRUE;
if(m
else p++;
}
if(*(p->typ))
ldrpgm = p->loader;
else
ldrpgm = load68k; /* default */
/* ATTEMP(*(p->typ)) /* clear flags in table */
{
p->user_c = p->user_0 = FALSE;
p++;
}
bdos(SELECT_DISK,(long)(cmdf else first_sub = TRUE;
for(i = 0;i < FCB_LEN;i++)
subfcb[i] = cmdfcb[i];
if(mode == SEARCH) subpromptCH) break;
if(strcmp(p->typ,"SUB") == MATCH) break;
}
p++;
}
if(*(p->typ))
{
if(!(p->user_c)) bead the submit file */
{ /************************/
if(bdos(READ_SEQ,subfcb))
{
end_of_file = TRUE;
return(FALSE)ode == SEARCH &&
strcmp(p->typ,top) == MATCH && p->user_c)
done = TRUE;
}
p++;
}
}
i =T THE PROGRAM LOAD */
switch( (*ldrpgm) (glb_index) )
{
case 1: bdos(PRINT_STRING,lderr1); break;
case 2: bdoscb[0]-1));
cmdfcb[0] = '?'; cmdfcb[12] = NULL;
i = bdos(SEARCH_FIRST,cmdfcb);
while(i != 255 && !(done))
{
= FALSE;
submit = TRUE;
end_of_file = FALSE;
}
else if(mode != SUB_FILE)
open = TRUE;
break;
}
dos(GET_USER_NO,(long)0);
cpy(p->typ,&cmdfcb[9]);
}
}
bdos(SELECT_DISK,(long)cur_disk);
while(1)
{
if(bd;
}
return(TRUE);
}
/************************/
UWORD dollar(k,mode,com_index) /* Translate $n to */
bdos(SEARCH_NEXT);
}
if(!(found))
{
if(mode == SUB_FILE) bdos(PRINT_STRING,msg11);
dirflag = TRUE; load_tr(PRINT_STRING,lderr2); break;
case 3: bdos(PRINT_STRING,lderr3); break;
default : bdos(PRINT_STRING,lderror);
}
i *= 32;
if(dma[i] == 0 || dma[i] == user)
{
for(n = 9;n <= 11;n++) dma[i+n] &= CMASK;
dma[i+12] = NULL;
else if(bdos(GET_USER_NO,(long)255) == 0) break;
else bdos(GET_USER_NO,(long)0);
}
if(open)
{
check_cmos(OPEN_FILE,cmdfcb) <= 3)
{
for(n = 9;n <= 11;n++) cmdfcb[n] &= CMASK;
if(cmdfcb[9] == 'S' && cmdfcb[10] == 'U' && c /* nth argument on the */
/* command line */
/************************/
REG UWORD k;
REG UWORD mode;
REG By = FALSE;
bdos(SELECT_DISK,(long)cur_disk); return(FALSE);
}
if(mode == SEARCH)
fill_fcb(0,cmdfcb);
else
}
if(!(sub_open) && mode == SUB_FILE)
bdos(PRINT_STRING,msg11);
bdos(GET_USER_NO,(long)user);
dirflag = TRUE;
loa
p = &load_tbl;
while(*(p->typ))
{
cpy(p->typ,&cmdfcb[9]);
if(strcmp(&cmdfcb[1],&dma[i+1]) ==d(glb_index);
if(!(found))
{
p = &load_tbl;
while(*(p->typ))
if(strcmp(p->typ,&cmdfcb[9]) == MATCH) break;YTE *com_index;
{
REG UWORD n,j,p_index;
REG BYTE *p1;
j = sub_index;
if(k >= CMD_LEN)
{
k = 0;
if(!sub_refile = TRUE;
done = TRUE;
}
}while(!(done));
return(k);
}
/************************/
VOID translate(com_inprompt();
do
{
while(k < CMD_LEN &&
subdma[k] != EOF &&
subdma[k] != Cr)
{
if(subdma[k] == '$(k >= CMD_LEN)
{
k = 0;
sub_read();
}
}
}
/*--------------------------------------------p1++;
else
bdos(CONSOLE_OUTPUT,(long)*p1++);
k++;
}
else
{
if(mode == FILL)
subcom[j++] = '$';
else
dma[k] == TAB))
k++;
if(k >= CMD_LEN)
{
k = 0;
if(!sub_read());
else
goto blankoutad())
return(k);
}
if((subdma[k] >= '0') && (subdma[k] <= '9'))
{
p_index = (subdma[k] - '0');
p1 = com_index;
dex) /* TRANSLATE the subfile*/
/* and fill sub buffer. */
/************************/
REG BYTE *com_index;
{
RE')
{
k++;
k = dollar(k,NOFILL,com_index);
}
else
bdos(CONSOLE_OUTPUT,(long)subdma[k++]);
}
if(k----------------------*/
/* TRANSLATION OF A COMMAND IS COMPLETE */
/* -Now move sub_index to next comman
bdos(CONSOLE_OUTPUT,(long)'$');
if(subdma[k] == '$')
k++;
}
sub_index = j;
if(k >= CMD_LEN)
{
k = 0;
su;
}
break;
case '$': k++;
sub_index = j;
k = dollar(k,FILL,com_index);
j = sub_index;
if(*p1++ == 'S' &&
*p1++ == 'U' &&
*p1++ == 'B' &&
*p1++ == 'M' &&
*p1++ == 'I' &&
*p1++ == 'TG BYTE *p1;
REG UWORD j,n,k,p_index;
j = 0;
k = sub_index;
while(!(end_of_file) && j < CMD_LEN
&& subdma[k] != Cr & == CMD_LEN && subdma[k] != EOF && subdma[k] != Cr)
{
k = 0;
if(!sub_read()) done = TRUE;
}
else
{
if(sud- */
/*------------------------------------------------------------------*/
if(subdma[k] == Cr || sub_read();
}
return(k);
}
/************************/
UWORD comments(k,com_index) /* Strip and echo submit*/
/* break;
case Lf: k++;
if(k >= CMD_LEN)
{
k = 0;
sub_read();
}
break;' &&
*p1 == ' ')
p_index++;
p1 = com_index;
for(n = 1; n <= p_index; n++)
{
while(*p1 != ' ' && *p1)
& subdma[k] != EXLIMPT)
{
switch(subdma[k])
{
case ';': k = comments(k,com_index);
break;
case TAB:
bdma[k] == Cr)
{
k += 2;
if(k >= CMD_LEN)
{
k = 0;
sub_read();
}
}
else
end_of_bdma[k] == EXLIMPT)
do
{
while(k < CMD_LEN &&
(subdma[k] == Cr ||
subdma[k] == Lf ||
subdma[k] file comments */
/************************/
REG UWORD k;
REG BYTE *com_index;
{
REG UWORD done;
done = FALSE;
case EOF:
end_of_file = TRUE;
break;
default: subcom[j++] = subdma[k++];
if p1++;
if(*p1 == ' ')
p1++;
}
while(*p1 != ' ' && *p1 && j < CMD_LEN)
if(mode == FILL)
subcom[j++] = *case ' ': if(j > 0)
subcom[j++] = subdma[k++];
blankout: while(k < CMD_LEN &&
(subdma[k] == ' ' || sub == EXLIMPT))
k++;
if(k == CMD_LEN)
{
k = 0;
if(!sub_read())
break;
}
else
{
if(subdma[k]
/************************/
VOID execute_cmd(cmd) /* branch to */
/* appropriate routine */
/********/
REG BYTE *com_index;
{
REG UWORD i,cur_user;
for(i = 0;i <= CMD_LEN;i++)
subcom[i] = NULL;
cur_user = bdos(GET
main()
{ /*---------------------*/
REG BYTE *com_index; /* cmd execution ptr */
/*--------------------ng submit_cmd,the variable |
| sub_index points to the beginning of the next command |
| to translate and execute. The {
bdos(PRINT_STRING,msg2);
get_cmd(subdma,(long)(CMD_LEN-1));
i = 0;
while(subdma[i] != ' ' &&
== EOF)
end_of_file = TRUE;
break;
}
}while(TRUE);
sub_index = k;
}
/************************/
UWORD *****************/
REG BYTE *cmd;
{
REG UWORD i,flag;
switch( decode(cmd) )
{
case DIRCMD: dir_cmd(0);
brea_USER_NO,(long)255);
bdos(GET_USER_NO,(long)sub_user);
bdos(SET_DMA_ADDR,subdma);
if(first_sub || chain_sub)
{
for(i -*/
dirflag = TRUE; /* init fcb fill flag */
bdos(SET_DMA_ADDR,dma); /* set system dma addr */
/* buffer subdma is used |
| to hold the UN-translated submit file contents. |
| The buffer subcom holds a translate subdma[i] &&
i < ARG_LEN-1 )
parm[1][i] = subdma[i++];
parm[1][i] = NULL;
if(i != 0) subpromsubmit_cmd(com_index) /* fill up the subcom */
/* buffer */
/************************/
/*----------------k;
case DIRSCMD: dir_cmd(1);
break;
case TYPECMD: type_cmd();
break;
case RENCMD: ren_cmd();
break;
= 0;i < CMD_LEN;i++)
subdma[i] = NULL;
sub_read();
sub_index = 0;
}
if(!(end_of_file))
translate(com_index);
---------------------*/
if(load_try)
{
bdos(SELECT_DISK,(long)cur_disk);
bdos(GET_USER_NO,(long)user);
load_try = Fd command. |
| Comments are echoed to the screen by the procedure |
| "comments". Parameters are substituted in commept = TRUE;
else break;
}
else
subprompt = FALSE;
goto gosub;
case FILE: flag = SEARCH;
gosu----------------------------------------------*\
| |
| Submit_Cmd is a Procedure that returns exactly |
| one commcase ERACMD: era_cmd();
break;
case UCMD: if(!(user_cmd()))
bdos(PRINT_STRING,msg12);
break;
case CH_Dfor(i = 0;i < CMD_LEN;i++)
subcom[i] = toupper(subcom[i]);
bdos(SET_DMA_ADDR,dma);
bdos(GET_USER_NO,(long)cur_user);
}
ALSE;
}
if(chainp) /*sw Chain? */
{ /*sw Yes. */
com_index = chainp + 1; /*sw Set-um pointer */
com_indents |
| as well as command lines. |
| |
\*--------------------------------------------------------------b: if(cmd_file(flag))
break;
if(flag == SUB_FILE)
break;
default : echo_cmd(parm,BAD);
}
}
and from the submit file. Submit_Cmd is |
| called only when the end of file marker has not |
| been read yet. Upon leaviISK: bdos(SELECT_DISK,(long)(parm[0][0]-'A'));
break;
case SUBCMD: flag = SUB_FILE;
if(parm[1][0] == NULL)
x[((WORD)(*chainp))&0xff] = NULL; /*sw Add null*/
chainp = NULL; /*sw Clear chain flag */
} /*sw *******************e */
if(parm[0][0] && parm[0][0] != ';')/*-----------*/
execute_cmd(parm); /* execute command */
/*---------************************/
} /*sw if(chainp) */
/************************/
/*-------------------------------------裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹 if(*com_index)
echo_cmd(com_index,GOOD);
}
else
{ /*----------------------*/
prompt(); /* pFALSE;
break;
}
else
submit_cmd(save_sub);
}
}
if(*com_index)
echo_cmd(com_index,GOOD);
/
else /*sw Submit or normal */
{ /*---------------------*/
if(morecmds) /* if a warmboot */
{ /*-----------*/
if(!(submit))
com_index = scan_cmd(com_index);/* inc pointer */
else
{
com_index = subcom;-------------------------*\
| |
| MAIN CCP PARSE LOOP |
| =================== |
| |
\裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹rompt for command */
com_index = usercmd; /* set execution pointer*/
if(autost && autorom) /* check for COLD}
}
 occurred & there were*/
/* more cmds to do */
if(submit) /*---------------------*/
{
com_index = subcom;
if(first_sub || chain_sub)
{
if(subprompt)
copy_cmd(subdma);
else
copy_cmd(glb_index);
if(fi*--------------------------------------------------------------*/
while(*com_index)
{ /*--------------------*/
裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹BOOT cm*/
{ /* */
echo_cmd(usercmd,GOOD); /* echo the command */
autorom = FALSE; /* turn off .bss flag 
}
 submit_cmd(save_sub);
while(!*com_index)
{
if(end_of_file)
{
com_index = user_ptr;
submit = Frst_sub)
user_ptr = scan_cmd(glb_index);
submit_cmd(save_sub);
first_sub = chain_sub = FALSE;
}
else
glb_index = com_index; /* save for use in */
/* check_cmd call */
get_parms(com_index); /* parse command lin裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹 */
} /* */
else /* otherwise....... */
get_cmd(usercmd,(long)(CMD_LEN));/*read a cmd */
} /
}
ALSE;
break;
}
else submit_cmd(save_sub);
}
}
else
com_index = user_ptr;
morecmds = FALSE;
*com_index = NULL;
while(*com_index == NULL)
{
if(end_of_file)
{
com_index = user_ptr;
submit = *************************************************************************
* *
* INTERFACE MODULE BETWEEN *
* |
\*--------------------------------------------------------------*/
/*-------------------------------------------*\ ======= |
| |
| CP/M 68k: A CP/M derived operating system |
| |
| File contents: |
ine NO_READ 255
#define BLANK ' '
#define BACKSLH '\\'
#define EXLIMPT '!'
#define CMASK 0177
#define ONE (long)49
(sp),d0
move.l 6(sp),d1
trap #2
rts
 OFF 0
#define MATCH 0
#define GOOD 1
#define BAD 0
#define FILL 1
#define NOFILL 0
#define VOID /*no return valu CCP and THE BDOS *
* *
* *
* THIS IS THE DUAL PROCESSOR,ROMABLE CP/M-68K SYSTEM *
* ==========
| CP/M Transient Commands |
\*-------------------------------------------*/
#define DIRCMD 0
#def | ------------- |
| This file contains all of the #defines |
| used by the console command processor. |
|
#define TAB 9
#define Cr 13
#define Lf 10
#define CR (long)13
#define LF (long)10
#define EOF 26
#define BLAN(sp),d0
move.l 6(sp),d1
trap #2
rts
e*/
#define NO_FILE 98
#define STOP 99
#define USER_ZERO 0
#define DISK_A 1
#define SOURCEDRIVE 88
#define DESTDR======================================== *
* *
* (C) Copyright Digital Research 1983 all rights reserved *
ine TYPECMD 1
#define RENCMD 2
#define ERACMD 3
#define UCMD 4
#define CH_DISK 5
#define SUBCMD 6
#defi |
| created by : Tom Saulpaugh Date: 7/13/82 |
| ---------- |
| last modified: 10/29/82 KS (long)32
#define PERIOD (long)46
#define COLON (long)58
#define ARROW (long)62
/*----------------------------(sp),d0
move.l 6(sp),d1
trap #2
rts
IVE 99
#define BYTE char
#define REG register
#define WORD short
#define UWORD unsigned int
#define LONG long
#defi
* *
*************************************************************************
.globl _bdos
_bdos: move.w ne SUB_FILE 7
#define FILE 8
#define DIRSCMD 9
#define SEARCH 10
/*-------------------------------------- |
| ------------- |
| |
| (c) COPYRIGHT Digital Research 1982 |
| all rights reserved |
| ---------------*\
| Data Structure Size Constants |
\*-------------------------------------------*/
#define CMD_/*--------------------------------------------------------------*\
| ccp_def.c DEFINES v1.0 |
| ne ULONG unsigned long
#define GET_MEM_REG 18
#define ZERO 0
#define NULL '\0'
#define TRUE 1
#define FALSE 0
#def4(sp),d0
move.l 6(sp),d1
trap #2
rts
-----*\
| Modes and Flags |
\*-------------------------------------------*/
#define ON 1
#define LEN 128
#define BIG_CMD_LEN 255
#define MAX_ARGS 4
#define ARG_LEN 30
#define NO_OF_DRIVES 16
#define NUMDELS 16supper(c))
#define islower(c) ('a' <= (c) && (c) <= 'z')
#define isupper(c) ('A' <= (c) && (c) <= 'Z')
#define tolower(c) PROT_DISK 28
#define GET_READ/O_VEC 29
#define SET_FILE_ATTRIB 30
#define GET_ADDR_D_PARM 31
#define GET_USER_NO 32*************************************************************************
* *
* CPM68K INTERFACE MO/O_BYTE 8
#define PRINT_STRING 9
#define READ_CONS_BUF 10
#define GET_CONS_STAT 11
#define RET_VERSION_NO 12
#define R裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹
#define FCB_LEN 36
#define DMA_LEN 128
#define FILES_PER_LINE 5
#define SCR_HEIGHT 23
#define BIG_WIDTH 80
(isupper(c) ? ((c)+040):(c))
#define toupper(c) (islower(c) ? ((c)-040):(c))
#define isdigit(c) ('0' <= (c) && (c) <= '9')
#define READ_RANDOM 33
#define WRITE_RANDOM 34
#define COMP_FILE-SIZE 35
#define SET_RANDOM_REC 36
#define RESET_DRIVDULE FOR *
* THE CONSOLE COMMAND PROCESSOR *
* *
* THIS IS THE DUAL-PROCESSOR,ROMABLE CP/M-68K SYSTEM ESET_DISK_SYS 13
#define SELECT_DISK 14
#define OPEN_FILE 15
#define CLOSE_FILE 16
#define SEARCH_FIRST 17
#define SEA裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹
#define SMALL_WIDTH 40
/*-------------------------------------------*\
| BDOS Function Calls |
E 37
#define WRITE_RAN_ZERO 40
#define BIOS_CALL 50
#define LOAD_PROGRAM 59
/*------------------------------------*
* ================================================== *
* *
* (C) Copyright Digital Research 1983 all rigRCH_NEXT 18
#define DELETE_FILE 19
#define READ_SEQ 20
#define WRITE_SEQ 21
#define MAKE_FILE 22
#define RENAME_FILE 2裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹\*-------------------------------------------*/
#define WARMBOOT 0
#define CONIN 1
#define CONSOLE_OUTPUT 2
#define R
----------*\
| MACROS |
\*----------------------------------------------*/
#define isalpha(c) (islower(c) || ihts reserved *
* *
*************************************************************************
.globl _bios1
.3
#define RET_LOGIN_VEC 24
#define RET_CUR_DISK 25
#define SET_DMA_ADDR 26
#define GET_ADDR(ALLOC) 27
#define WRITE_裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹EADER_INPUT 3
#define PUNCH_OUTPUT 4
#define LIST_OUTPUT 5
#define DIR_CONS_I/O 6
#define GET_I/O_BYTE 7
#define SET_I
globl _bdos
.globl _load68k
.globl _load_tbl
.globl init_tbl
.globl _load_try
.globl _autorom
.globl flags
.gluser: .ds.w 1
.even
_submit: .ds.b 1
.even
_morecmds: .ds.b 1
.even
_patch .ds.l 25
.end
d1
move.b dskuser,d1 * get the user #
trap #2 * set the user number
clr.l d0 * clear d0
move.w #14,d0 * select func BDOS functions 1 thru 11 (console functions)
bdosmisc.c - BDOS initialization, warmboot, error handler, set exception,
t
ccpclear:
clr.b _autost * clear the autostart flag
ccpstart:
lea stack,sp * set up the stack pointer
clr.b _autos裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹obl TPAB
.globl stack
.globl _bdosini
.globl _main
.globl _submit
.globl _morecmds
.globl _autost
.globl _ususer: .ds.w 1
.even
_submit: .ds.b 1
.even
_morecmds: .ds.b 1
.even
_patch .ds.l 25
.end
tion
clr.l d1 * clear d1
move.w dskuser,d1 * get disk to be selected
andi #$0ff,d1 * mask off the user #
trap #2 * (used for miscellaneous BDOS routines)
dskutil.c - bit map handlers, directory read & write, dirscan
t * clear the auto start flag
jsr _init * call bios init
move.w d0,dskuser * save user # & disk
*
*
* ROM SYSTEM INITIA裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹ercmd
.globl _init
.globl _ccp
.globl _patch
.globl cpm
.text
cpm:
jmp.l ccpstart * start ccp with possible in裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹select the disk
_ccp:
lea stack,sp * set up the stack pointer
jsr _main * call the CCP
bra _ccp
.bss
.even
ds (miscellaneous disk handling utilities)
fileio.c - all file handling calls except read & write
LIZATION
* OF BSS VARIABLES
*
*
clr.b _load_try
clr.b _submit
clr.b _morecmds
move.b #$1,_autorom
clr.w flags
The following is a list of the modules that form the BDOS for the
C language version of CP/M-68K:
SOURCE FILES
bdosif.sitial command
jmp.l ccpclear * clear auto start flag
.bss
_autost: .ds.b 1 * autostart command flag
_usercmd: .裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹kuser: .ds.w 1
.even
_submit: .ds.b 1
.even
_morecmds: .ds.b 1
.even
_patch .ds.l 25
.end
includes open, close, delete, rename, etc.
bdosrw.c - sequential and random read & write
bdosmain.c - the BDOS case clr.w TPAB
jsr init_tbl
jsr _bdosini * do bdos init
move.w #32,d0 * get user bdos func #
clr.l d1 * clear out - assembly language interface, trap handler,
BIOS caller, function 62 (set supervisor)
conbdos.c - ds.b 130 * user command buffer
.text
copy: .dc.b ' CP/M-68K V1.2 COPYRIGHT (C) 1982,1984, Digital Research '
.tex裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹statement, global variable declarations
iosys.c - packet I/O to BIOS interface
pgmld.s - program load (function t in allocation vector *
* getaloc() - get free allocation block *
* dchksum() - directory checksum calculator *
* di裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹ecnum; /* logical sector number to read/write */
UBYTE *dma; /* dma address */
REG WORD parm; /* 0 for read, write pation of data structure for packet I/O
WORD do_phio(); /* external physical disk I/O routine */
EXTERN UWORD error(); /* external error routine */
EXTERN UWORD log59)
exceptn.s - exception handler
INCLUDE FILES
bdosinc.h - standard i/o stuff, universal declarations
bdosdr_rd() - read directory sector *
* dir_wr() - write directory sector *
* rdwrt() - read/write disk sector *
* /****************************************************************
* *
* CP/M-68K BDOS Disk Utilities Module *
* rm + 1 for write */
{
struct iopb rwpkt;
BSETUP
rwpkt.devnum = GBL.curdsk; /* disk to read/write */
iftion of data structure for packet I/O
_dsk; /* logged-on disk vector */
EXTERN UWORD ro_dsk; /* read-only disk vector */
EXTERN UWORD crit_dsk; /* critical disk veef.h - BDOS data structure declarations
biosdef.h - procedure declarations to interface to BIOS
pktio.h - defin *
* *
* Configured for Alcyon C on the VAX *
* *
**************************************************** *
* This module contains the miscellaneous utilities *
* for manipulating the disk in CP/M-68K. Included are: *
* (parm)
{
rwpkt.iofcn = (BYTE)write; /* if parm non-zero, we're doing a write */
rwpkt.ioflags = (BYTE)(parm-1); /* pas裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹ctor */
UBYTE dchksum();
/**********************
* read/write routine *
**********************/
UWORD rdwrt(secnum, ition of data structure for packet I/O
************/
#include "bdosinc.h" /* Standard I/O declarations */
#include "bdosdef.h" /* Type and structure declaratio *
* dirscan() - general purpose dir scanning *
* setaloc() - set bit in allocation vector *
* clraloc() - clear bis write parm */
if ( ro_dsk & (1 << (rwpkt.devnum)) ) error(4);
/* don't write on read-only disk */
}
el裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹dma, parm)
/* General disk sector read/write routine */
/* It simply sets up a I/O packet and sends it to do_phio */
LONG stion of data structure for packet I/O
ns for BDOS */
#include "pktio.h" /* Packet I/O definitions */
/* declare external functions and variables */
EXTERN Use
{
rwpkt.iofcn = (BYTE)read;
rwpkt.ioflags = (BYTE)0;
}
rwpkt.devadr = secnum; /* sector number */
rxff) );
}
/************************
* dirscan entry point *
************************/
UWORD dirscan(funcp, fcbp, parhis implementation is dependant on the representation */
/* of a LONG and is therefore not very portable. But it's fast */tinue) ? GBL.srchpos + 1 : 0 );
while ( (parms & pasthw) || (i <= ((GBL.dphp)->hiwater + 1)) )
{ /* main directory ***************************
* directory write routine *
****************************/
UWORD dir_wr(secnum)
REG WORD sedefine full 2
#define initckv 4
#define pasthw 8
{
REG UWORD i; /* loop counter */
REG struct dpb *dparmp;wpkt.xferadr = dma; /* dma address */
/* parameters that are currently not used by do_phio
rwpkt.devtype = disk;
ms)
BOOLEAN (*funcp)(); /* funcp is a pointer to a Boolean function */
REG struct fcb *fcbp; /* fcbp is a pointer to a fcb
{
REG LONG *p; /* local temp variables */
REG LONG lsum;
REG WORD i;
BSETUP
p = GBL.dirbufp; /*scanning loop */
if ( i > dparmp->drm ) break;
if ( ! (i & 3) )
{ /* inside loop happens when we need to
read cnum;
{
REG UWORD rtn;
BSETUP
rtn = rdwrt( (LONG)secnum, GBL.dirbufp, 2);
if ( secnum < (GBL.parmp)->cks /* pointer to disk parm block */
REG UWORD dirsec; /* sector number we're working on */
REG UWORD rtn; /* return rwpkt.xferlen = 1;
*/
rwpkt.infop = GBL.dphp; /* pass ptr to dph */
while ( do_phio(&rwpkt) )
if ( error( p */
REG UWORD parms; /* parms is 16 bit set of bit parameters */
/* Parms & 1 = 0 to start at beginning of dir, 1 to conti point to directory buffer */
lsum = 0;
i = SECLEN / (sizeof lsum);
do
{
lsum += *p++; /* add next 4 byteanother directory sector */
retry: dirsec = i >> 2;
dir_rd(dirsec); /* read the directory sector */
if ( dirsec)
*((GBL.dphp)->csv + secnum) = dchksum();
return(rtn);
}
/*******************************
* directory checksum r value */
REG UBYTE *p; /* scratch pointer */
REG UWORD bitvec; /* disk nmbr represented as a vector */
BSETarm ? 1 : 0 ) ) break;
return(0);
}
/***************************
* directory read routine *
********************nue from last */
/* Parms & 2 = 0 to stop when *funcp is true, 1 to go until end */
/* Parms & 4 = 0 to check the dir checkss of directory */
i -= 1;
} while (i);
lsum += (lsum >> 16);
lsum += (lsum >> 8);
return( (UBYTE)(lsum & 0 < (dparmp->cks) ) /* checksumming on this sector? */
{
p = ((GBL.dphp)->csv) + dirsec;
/* point to checksum vecoutine *
*******************************/
UBYTE dchksum()
/* Compute checksum over one directory sector */
/* Note that tUP
dparmp = GBL.parmp; /* init ptr to dpb */
rtn = 255; /* assume it doesn't work */
i = ( (parms & con*******/
UWORD dir_rd(secnum)
WORD secnum;
{
BSETUP
return( rdwrt((LONG)secnum, GBL.dirbufp, 0) );
}
/*um, 1 to store new checksum */
/* Parms & 8 = 0 to stop at hiwater, 1 to go until end of directory */
#define continue 1
#tor byte */
if (parms & initckv) *p = dchksum();
else if (*p != dchksum())
{ /* checksum error! */
(GBL.dphp)v + (i >> 3) )) & (0x80 >> (i&7)) );
}
UWORD getaloc(leftblk)
/* Get a free block in the file system and set the bit in a if (bitnum >= 0 && bitnum <= (GBL.parmp)->dsm)
*((GBL.dphp)->alv + (bitnum>>3)) |= 0x80 >> (bitnum & 7);
}
clral UNLOCK
return(blk);
}
 to directory entry, and
(3) directory index */
{
if (parms & full) rtn = 0; /* found a match, but keep goet disk max field from dpb */
rtblk = leftblk;
blk = ~0; /* -1 returned if no free block found */
while (leftb->hiwater = dparmp->drm; /* reset hi water */
bitvec = 1 << (GBL.curdsk);
if (crit_dsk & bitvec) /* if disk in crllocation vector */
/* It is passed the block number of the last block allocated to the file */
/* It tries to allocate theoc(bitnum)
/* Clear bit in allocation vector */
REG UWORD bitnum;
{
BSETUP
if (bitnum > 0 && bitnum <= (GBL.parmp UNLOCK
return(blk);
}
ing */
else return(i & 3); /* return directory code */
}
i += 1;
}
return(rtn);
}
/******************lk || rtblk < diskmax)
{
if (leftblk)
if (chkaloc(--leftblk))
{
blk = leftblk;
break;
}
if (rtbitical mode */
ro_dsk |= bitvec; /* then set it to r/o */
else
{
log_dsk &= ~bitvec; /* else log it off * block closest to the block that was passed */
REG UWORD leftblk;
{
REG UWORD blk; /* block number to allocate */
)->dsm)
*((GBL.dphp)->alv + (bitnum>>3)) &= ~(0x80 >> (bitnum & 7));
}
UWORD chkaloc(i)
/* Check bit i in allocation ve裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹**********************
* Routines to manage allocation vector *
* setaloc() *
* clraloc() *
* getaloc() *
**********lk < diskmax)
if (chkaloc(++rtblk))
{
blk = rtblk;
break;
}
}
if (blk != ~0) setaloc(blk);
/
seldsk(GBL.curdsk); /* and re-select it */
goto retry; /* and re-do current op */
}
}
}
}
GBL.s REG UWORD rtblk; /* high block number to try */
REG UWORD diskmax; /* # bits in alv - 1 */
BSETUP
LOCK /ctor */
/* Return non-zero if block free, else return zero */
REG UWORD i;
{
BSETUP
return( ~(*( (GBL.dphp)->al裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹******************************/
setaloc(bitnum)
/* Set bit in allocation vector */
REG UWORD bitnum;
{
BSETUP
UNLOCK
return(blk);
}
rchpos = i;
if ( (*funcp)(fcbp, (GBL.dirbufp) + (i&3), i) )
/* call function with parms of (1) fcb ptr,
(2) pointer* need to lock the file system while messing
with the allocation vector */
diskmax = (GBL.parmp)->dsm;
/* g裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹era $1x.1
era $1x.2
$2as68 -s 0$1 -l -u -f $1 iosys.s
era iosys.s
$2cp68 ccp.c $1x.i
$2c068 $1x.i $1x.1 $1x.2 $1x.3 -f
e1
era $1x.2
$2as68 -s 0$1 -l -u -f $1 conbdos.s
era conbdos.s
$2cp68 dskutil.c $1x.i
$2c068 $1x.i $1x.1 $1x.2 $1x.3 -f
e裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹68 -s 0$1 -l -u -f $1 bdosmain.s
era bdosmain.s
$2cp68 bdosmisc.c $1x.i
$2c068 $1x.i $1x.1 $1x.2 $1x.3 -f
era $1x.i
$2c16f $1 stack.s
rear $1 $2
裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹ra $1x.i
$2c168 $1x.1 $1x.2 ccp.s
era $1x.1
era $1x.2
$2as68 -s 0$1 -l -u -f $1 ccp.s
era ccp.s
$2as68 -s 0$1 -l -u -f $ra $1x.i
$2c168 $1x.1 $1x.2 dskutil.s
era $1x.1
era $1x.2
$2as68 -s 0$1 -l -u -f $1 dskutil.s
era dskutil.s
$2cp68 filei裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹8 $1x.1 $1x.2 bdosmisc.s
era $1x.1
era $1x.2
$2as68 -s 0$1 -l -u -f $1 bdosmisc.s
era bdosmisc.s
$2cp68 bdosrw.c $1x.i
$ $1 stack.s
rear $1 $2
裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹1 bdosif.s
$2cp68 exceptn.s except.s
$2as68 -s 0$1 -f $1 -l -n except.s
era except.s
$2cp68 -dm68010 exceptn.s except10.s
$o.c $1x.i
$2c068 $1x.i $1x.1 $1x.2 $1x.3 -f
era $1x.i
$2c168 $1x.1 $1x.2 fileio.s
era $1x.1
era $1x.2
$2as68 -s 0$1 -l -u 裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹2c068 $1x.i $1x.1 $1x.2 $1x.3 -f
era $1x.i
$2c168 $1x.1 $1x.2 bdosrw.s
era $1x.1
era $1x.2
$2as68 -s 0$1 -l -u -f $1 bdosrw $1 stack.s
rear $1 $2
裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹2as68 -s 0$1 -f $1 -l -n except10.s
era except10.s
$2as68 -s 0$1 -l -u -f $1 pgmld.s
$2as68 -s 0$1 -l -u -f $1 ccpbdos.s
$2a-f $1 fileio.s
era fileio.s
$2cp68 iosys.c $1x.i
$2c068 $1x.i $1x.1 $1x.2 $1x.3 -f
era $1x.i
$2c168 $1x.1 $1x.2 iosys.s
裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹.s
era bdosrw.s
$2cp68 conbdos.c $1x.i
$2c068 $1x.i $1x.1 $1x.2 $1x.3 -f
era $1x.i
$2c168 $1x.1 $1x.2 conbdos.s
era $1x.裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹$2cp68 bdosmain.c $1x.i
$2c068 $1x.i $1x.1 $1x.2 $1x.3 -f
era $1x.i
$2c168 $1x.1 $1x.2 bdosmain.s
era $1x.1
era $1x.2
$2ass68 -s 0$1 -l -u -f $1 ccpif.s
$2as68 -s 0$1 -l -u -f $1 ccpload.s
$2as68 -s 0$1 -l -u -f $1 filetyps.s
$2as68 -s 0$1 -l -u -裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹 Compiled with Alcyon C on the VAX *
* - rename file *
* set_attr() - set file attributes *
* get(); /* calc max extent allocated for fcb */
EXTERN UWORD udiv(); /* unsigned divide routine */
/* decIncluded are: *
* *
* seldsk() - select disk */
EXTERN UWORD ro_err(); /* read-only file error routine */
EXTERN UWORD do_phio(); /* packet disk 裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹 *
* Modified 2/5/84 sw Allow odd DMA on get free space *
* *
*******************************************************size() - get file size *
* setran() - set random record field *
* lare external variables */
EXTERN UWORD log_dsk; /* logged-on disk vector */
EXTERN UWORD ro_dsk; *
* openfile() - open file *
* close_fi() - close fi/o handler */
EXTERN clraloc(); /* clear bit in allocation vector */
EXTERN setaloc(); /* se/****************************************************************
* *********/
#include "bdosinc.h" /* Standard I/O declarations */
#include "bdosdef.h" /* Type and str free_sp() - get disk free space *
* move() - general purpose byte mover *
* /* read-only disk vector */
EXTERN UWORD crit_dsk; /* vector of disks in critical state */
/***********ile *
* search() - search for first/next file match *
* create() - ct bit in allocation vector */
EXTERN UWORD swap(); /* assembly language byte swapper */
EXTERN UWORD dir_wr(); *
* CP/M-68K BDOS File I/O Module *
* ucture declarations for BDOS */
#include "pktio.h" /* Packet I/O definitions */
/* declare external fucntions *
* *
**************************
* This function passed to dirscan *
* from seldsk (below) *
***********************reate file *
* delete() - delete file *
* rename() /* directory write routine */
EXTERN tmp_sel(); /* temporary select disk routine */
EXTERN UWORD calcext *
* This module contains all file handling BDOS functions *
* except for read and write for CP/M-68K. */
EXTERN UWORD dirscan(); /* directory scanning routine */
EXTERN UWORD error(); /* disk error routine *************/
BOOLEAN alloc(fcbp, dirp, dirindx)
/* Set up allocation vector for directory entry pointed to by dirp */
s GBL.dirbufp = (GBL.dphp)->dbufp;
/* set up GBL copies of dir_buf and dpb ptrs */
GBL.parmgflag = ~(log_dsk >> dsknum) & 1;
if ((GBL.curdsk != dsknum) || logflag)
{ /* if not last us*************
* General purpose filename matcher *
*************************************/
BOOLEAN match(p1, p2, chk_ext)
do setaloc( UBWORD(dirp->dskmap.small[i++]) );
while (i <= 15);
}
else
{
/* round up */
do setaloc(--i); while (i); /* alloc directory blocks */
dirscan(alloc, NULL, truct fcb *fcbp; /* not used in this function */
REG struct dirent *dirp; /* pointer to directory entryp = (GBL.dphp)->dpbp;
}
if (logflag)
{ /* if disk not previously logged on, do it now */
LOCK ed disk or not logged on */
selpkt.iofcn = sel_info;
GBL.curdsk = (selpkt.devnum = dsknum);
if (UBWOR
REG UBYTE *p1;
REG UBYTE *p2;
BOOLEAN chk_ext;
{
REG WORD i;
REG UBYTE temp;
BSETUP
i = 12;
do setaloc(swap(dirp->dskmap.big[i++]));
while (i <= 7);
}
}
}
/*********************0x0e); /* do directory scan & alloc blocks */
log_dsk |= 1 << dsknum; /* mark disk as logged in */
*/
WORD dirindx; /* index into directory for *dirp */
{
REG WORD i; /* loop counter /* must lock the file system while messing with alloc vec */
i = (GBL.parmp)->dsm;
do clraloc(i); while (i-D(dsknum) > 15) error(2);
selpkt.ioflags = logflag ^ 1;
do
{
do_phio(&selpkt); /* actu do
{
temp = (*p1 ^ '?');
if ( ((*p1++ ^ *p2++) & 0x7f) && temp )
return(FALSE);
i ***
* seldsk entry point *
************************/
seldsk(dsknum)
REG UBYTE dsknum; /* disk number to }
}
/*******************************
* General purpose byte mover *
*******************************/
move(p1, p2*/
BSETUP
if ( UBWORD(dirp->entry) < 0x10 ) /* skip MP/M 2.x and CP/M 3.x XFCBs */
{
(GBL.dphp)->hiw-); /* clear the allocation vector */
i = udiv( (LONG)(((GBL.parmp)->drm) + 1),
4 * (((GBL.parmally do the disk select */
if ( (GBL.dphp = selpkt.infop) != NULL ) break;
} while ( ! error(3) );
-= 1;
} while (i);
if (chk_ext)
{
if ( (*p1 != '?') && ((*p1 ^ *p2) & ~((GBL.parmp)->exm)) )
select */
{
struct iopb selpkt;
REG WORD i;
UWORD j;
REG UBYTE logflag;
BSETUP
lo, i)
REG BYTE *p1;
REG BYTE *p2;
REG WORD i;
{
while (i--)
*p2++ = *p1++;
}
/************************ater = dirindx; /* set up high water mark for disk */
i = 0;
if ((GBL.parmp)->dsm < 256)
{
p)->blm) + 1), &j);
/* calculate nmbr of directory blks */
if (j) i++; return(FALSE);
p1 += 2;
p2 += 2;
if ((*p1 ^ *p2) & 0x3f) return(FALSE);
}
return(TRUE);
EG WORD i;
REG UBYTE *fp;
REG UBYTE *dp;
REG UWORD fcb_ext;
REG UWORD dir_ext;
BSETUP
if ( matc /* I/O packet for flush buffers call */
flushpkt.iofcn = flush;
while ( rtn = do_phio(&flushpkt) )
if {
if (*(UWORD *)dp != *(UWORD *)fp) goto badmerge;
}
fcb */
move(dirp, fcbp, sizeof *dirp);
/* copy dir entry into user's fcb */
{
if (*dp != *fp) goto badmerge;
}
else *fp = *dp;
}
/************************
* openfile entry point *
************************/
BOOLEAN openfile(fcbp, dirp, dirindx)
h(fcbp, dirp, TRUE) )
{ /* Note that FCB merging is done here as a final
conf( error(1) ) break;
return(rtn);
}
/*********************************
* file close routine for dirscan *
********** else *(UWORD *)fp = *(UWORD *)dp;
}
else *(UWORD *)dp = *(UWORD *)fp;
(UWO fcbp->extent = fcb_ext;
fcbp->s2 |= 0x80; /* set hi bit of S2 (write flag) */
crit_dsk |= 1 << ( }
else *dp = *fp;
fp += 1;
dp += 1;
i -= 1;
REG struct fcb *fcbp; /* pointer to fcb for file to open */
struct dirent *dirp; /* pointer to directorirmation that disks haven't been swapped */
LOCK
fp = &(fcbp->dskmap.small[0]);
dp = &(dirp->dskmap.s***********************/
BOOLEAN close(fcbp, dirp, dirindx)
REG struct fcb *fcbp; /* pointer to fcb */
REG struRD *)fp += 1;
(UWORD *)dp += 1;
i -= 1;
} while (i);
}
/* Disk GBL.curdsk);
}
return(rtn);
}
/*************************/
/* flush buffers routine */
/************************ } while (i);
}
else
{ /* Large disk map merge routine */
i = 8;
y entry */
WORD dirindx;
{
REG UBYTE fcb_ext; /* extent field from fcb */
REG BOOLEAN rtn;
mall[0]);
if ((GBL.parmp)->dsm < 256)
{ /* Small disk map merge routine */
i = 16;ct dirent *dirp; /* pointer to directory entry */
WORD dirindx; /* index into directory */
{
Rmap merging complete */
fcb_ext = calcext(fcbp); /* calc max extent for fcb */
dir_ext = (UWORD)(dirp->*/
UWORD flushit()
{
REG UWORD rtn; /* return code from flush buffers call */
struct iopb flushpkt; do
{
if (*(UWORD *)dp)
{
if (*(UWORD *)fp)
BSETUP
if ( rtn = match(fcbp, dirp, TRUE) )
{
fcb_ext = fcbp->extent; /* save extent number from user's
do
{
if (*dp)
{
if (*fp)
extent) & 0x1f;
if ( (fcb_ext > dir_ext) ||
((fcb_ext == dir_ext) &&
(UBWORD(fcbp->rcdctry point */
UWORD search(fcbp, dsparm, p)
REG struct fcb *fcbp; /* pointer to fcb for file to search */
REG UWO
don't need to do physical close */
return( dirscan(close, fcbp, 0)); /* call if ( rtn = ((dirp->entry) == 0xe5) )
{
p = &(fcbp->rcdcnt);
i = 17;
do
{ dirindx >> 2);
UNLOCK
return(TRUE);
badmerge:
UNLOCK
ro_dsk |= (1 << GBL.curdsk);
an(matchit, fcbp, dsparm);
}
move( GBL.dirbufp, GBL.dmaadr, SECLEN);
return(rtn);
}
/**********************nt) > UBWORD(dirp->rcdcnt))) )
/* if fcb points to larger file than dirp */
{
dirRD dsparm; /* parameter to pass through to dirscan */
UBYTE *p; /* pointer to pass through dirscan with close function */
}
/************************
* search entry point *
************************/
/* Fi /* clear fcb rcdcnt and disk map */
*p++ = 0;
i -= 1;
} while (i);
move( return(FALSE);
}
else return(FALSE);
}
/************************
* close_fi entry point *
*******************
* create entry point *
************************/
BOOLEAN create(fcbp, dirp, dirindx)
REG struct fcb *fcbp; p->rcdcnt = fcbp->rcdcnt; /* set up rc, ext from fcb */
dirp->extent = (BYTE)fcb_ext;
}
dito tmp_sel */
{
REG UWORD rtn; /* return value */
BSETUP
if (fcbp->drvcode == '?')
{
rst two functions for dirscan */
BOOLEAN alltrue(p1, p2, i)
UBYTE *p1;
UBYTE *p2;
WORD i;
{
return(TRUE);
}
fcbp, dirp, sizeof *dirp); /* move the fcb to the directory */
dir_wr(dirindx >> 2); /* write the directory s*******/
UWORD close_fi(fcbp)
struct fcb *fcbp; /* pointer to fcb for file to close */
{
flushit(); /* pointer to fcb for file to create */
REG struct dirent *dirp; /* pointer to directory entry */
REG WORD dirindxrp->s1 = fcbp->s1;
if ( (dirp->ftype[robit]) & 0x80) ro_err(fcbp,dirindx);
seldsk(GBL.dfltdsk);
rtn = dirscan(alltrue, fcbp, dsparm);
}
else
{
tmp_sel(p);
BOOLEAN matchit(p1, p2, i)
UBYTE *p1;
UBYTE *p2;
WORD i;
{
return(match(p1, p2, TRUE));
}
/* search enector */
if ( dirindx > (GBL.dphp)->hiwater )
(GBL.dphp)->hiwater = dirindx;
crit_dsk |= 1 << (GB /* first, flush the buffers */
if ((fcbp->s2) & 0x80) return(0); /* if file write flag not on,; /* index into directory */
{
REG BYTE *p;
REG WORD i;
REG BOOLEAN rtn;
BSETUP
/* read-only file error */
dirp->ftype[arbit] &= 0x7f; /* clear archive bit */
dir_wr( /* temporarily select disk */
if (fcbp->extent != '?') fcbp->extent = 0;
fcbp->s2 = 0;
rtn = dirscL.curdsk);
}
return(rtn);
}
/************************
* delete entry point *
************************/
B ) ro_err(fcbp,dirindx);
/* check for read-only file */
p = &(fcbp->dskmap.small[1]);
*
************************/
BOOLEAN rename(fcbp, dirp, dirindx)
REG struct fcb *fcbp; /* pointer to fcb for fil | ((LONG)(fcbp->s2 & 0x3f) << 12) );
}
/************************
* setran entry point *
***************
LOCK
dir_wr(dirindx >> 2);
/* Now free up the space in the allocation vector */
if ((GBL.paindex into directory */
{
REG BOOLEAN rtn;
BSETUP
if ( rtn = match(fcbp, dirp, FALSE) )
{
OOLEAN delete(fcbp, dirp, dirindx)
REG struct fcb *fcbp; /* pointer to fcb for file to delete */
REG struct dirent
q = &(dirp->fname[0]);
i = 11;
do
{
*q++ = *p++ & 0x7f;
i -= 1;
e to delete */
REG struct dirent *dirp; /* pointer to directory entry */
REG WORD dirindx; /* index int*********/
setran(fcbp)
REG struct fcb *fcbp; /* pointer to fcb for file to set ran rec */
{
struct
rmp)->dsm < 256)
{
i = 16;
do clraloc(UBWORD(dirp->dskmap.small[--i]));
whil move(&fcbp->fname[0], &dirp->fname[0], 11);
dir_wr(dirindx >> 2);
}
return(rtn);
}
/*************** *dirp; /* pointer to directory entry */
REG WORD dirindx; /* index into directory */
{
} while (i);
dir_wr(dirindx >> 2);
}
return(rtn);
}
/************************
* set_attr entryo directory */
{
REG UWORD i;
REG BYTE *p; /* general purpose pointers */
REG BYTE *q;
{
BYTE b3;
BYTE b2;
BYTE b1;
BYTE b0;
};
LONG random;
random = (LONG)UBWORe (i);
}
else
{
i = 8;
do clraloc(swap(dirp->dskmap.big[--i]));
*************
* utility routine used by *
* setran and getsize *
****************************/
LONG extsize(fcbp)REG WORD i;
REG BOOLEAN rtn;
BSETUP
if ( rtn = match(fcbp, dirp, FALSE) )
{
if ( (dirp->ftype[rob point *
************************/
BOOLEAN set_attr(fcbp, dirp, dirindx)
REG struct fcb *fcbp; /* pointer to fc
REG BOOLEAN rtn;
BSETUP
if ( rtn = match(fcbp, dirp, FALSE) )
{
if ( (dirp->ftype[robit]) & 0x80D(fcbp->cur_rec) + extsize(fcbp);
/* compute random record field */
fcbp->ran0 = random.b while (i);
}
UNLOCK
}
return(rtn);
}
/************************
* rename entry point
/* Return size of extent pointed to by fcbp */
REG struct fcb *fcbp;
{
return( ((LONG)(fcbp->extent & 0x1f) << 7)
it]) & 0x80 ) ro_err(fcbp,dirindx);
/* check for read-only file */
dirp->entry = 0xe5;b for file to delete */
REG struct dirent *dirp; /* pointer to directory entry */
REG WORD dirindx; /* 2;
fcbp->ran1 = random.b1;
fcbp->ran2 = random.b0;
}
/**********************************/
/* fsize is a funtionp->ran2 = maxrcd.b0;
}
/************************
* free_sp entry point *
************************/
free_sp(dsknum)
EG WORD dsparm;
struct
{
BYTE b3;
BYTE b2;
BYTE b1;
BYTE b0;
};
maxrcdory */
move(&temp,GBL.dmaadr,sizeof(LONG)); /*sw Move to user's DMA */
}
 dirp, FALSE) )
{
temp = (LONG)UBWORD(dirp->rcdcnt) + extsize(dirp);
/* compute ftmask)
{
bitmask = 0x8000;
alvword = ~(*alvec++);
}
if ( alvword & bitmask) for dirscan */
/* passed from getsize */
/**********************************/
BOOLEAN fsize(fcbp, dirp, dirindx
UBYTE dsknum; /* disk number to get free space of */
{
REG LONG records;
REG UWORD *alvec;
REG UW = 0;
dsparm = 0;
temp = 0;
while ( dirscan(fsize, fcbp, dsparm) < 255 )
{ /* loop裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹ile size */
fcbp->ran0 = temp.b2;
fcbp->ran1 = temp.b1;
fcbp->ran2 = temp.b0;
}
return(r
records += (LONG)( ((GBL.parmp)->blm) + 1 );
bitmask >>= 1;
}
temp = records; /*sw Put in me)
REG struct fcb *fcbp; /* pointer to fcb for file to delete */
REG struct dirent *dirp; /* pointer to direORD bitmask;
REG UWORD alvword;
REG WORD i;
LONG temp; /*sw For DMA Odd problem */
BSETUP
seldsk until no more matches */
temp.b2 = fcbp->ran0;
temp.b1 = fcbp->ran1;
temp.b0 = fcbp->ran2;
*
* CP/M-68K table driven file search module
* ========================================
*
* GLOBALS
tn);
}
/************************
* getsize entry point *
************************/
getsize(fcbp)
/* get file size mory */
move(&temp,GBL.dmaadr,sizeof(LONG)); /*sw Move to user's DMA */
}
ctory entry */
WORD dirindx; /* index into directory */
{
REG BOOLEAN rtn;
struct
(dsknum); /* select the disk */
records = (LONG)0; /* initialize the variables */
alvec = (GBL.dpif (temp > maxrcd) maxrcd = temp;
dsparm = 1;
}
fcbp->ran0 = maxrcd.b2;
fcbp->ran1 = maxrcd.b1;
fcb
.globl _load_tbl * loader table
.globl _load68k * default load program
*/
REG struct fcb *fcbp; /* pointer to fcb to get file size for */
{
LONG maxrcd;
LONG temp;
Rory */
move(&temp,GBL.dmaadr,sizeof(LONG)); /*sw Move to user's DMA */
}
 {
BYTE b3;
BYTE b2;
BYTE b1;
BYTE b0;
};
LONG temp;
if ( rtn = match(fcbp,hp)->alv;
bitmask = 0;
for (i = 0; i <= (GBL.parmp)->dsm; i++) /* for loop to compute */
{
if ( ! bi .globl init_tbl * initializes table on COLD BOOT
.text
******************************************* *
*-----------------------------------------------------------------------*
* ointers to the loaders
move.l #_load68k,pgld3
move.l #_load68k,pgld4
rts
.bss
.
*****************************************
* *
* FILETYPE TABLE *
*************************************************************************
*
* *
* *
*******************************************
* *
* This is the D *
* STRUCTURE OF A LOADER TABLE ENTRY: *
* ==================even
.page
*************************************************************************
* *
* ============== *
* *
*************************************** The following code allows CP/M-68K to be ROM-able.
* -------------------------------------------------
*
init_tb************************************************************
_load_tbl:
typ1p: .ds.l 1
pgld1: .ds.l 1
.ds.UAL PROCESSOR,ROMABLE version of CP/M-68K *
* ====================================================== *
=============== *
* *
* *
* CP/M-68K LOADER TABLE *
* **
.data
.even
typ1: .dc.b '68K',0
.even
typ2: .dc.b ' ',0
.even
typ3: .dl:
move.l #typ1,typ1p
move.l #typ2,typ2p * init the pointers to the filetypes
move.l #b 1
.ds.b 1
typ2p: .ds.l 1
pgld2: .ds.l 1
.ds.b 1
.ds.b 1
typ3p: .ds.l 1
pgld3:
* *
* (c) Copyright Digital Research 1983 (1) LONG WORD pointer to a filetype *
* (2) LONG WORD address of the program loader for ===================== *
* c.b 'SUB',0
.even
null: .dc.l 0
.end
typ3,typ3p
move.l #null,typ4p
move.l #_load68k,pgld1
move.l #_load68k,pgld2 * init the p .ds.l 1
.ds.b 1
.ds.b 1
typ4p: .ds.l 1
pgld4: .ds.l 1
.ds.b 1
.ds.b 1
*
* all rights reserved *
* the above type *
* (3) BYTE flag #1 *
* (4) BYTE flag #2 .b 'SUB',0
.even
null: .dc.l 0
.end
def.h" /* Declarations for BIOS entry points */
EXTERN udiv(); /* Assembly language unsigned divi *
* *
* Configured for Alcyon C on the VAX iop->infop = bseldsk(last_dsk, iop->ioflags);
break;
case read:
case write:
*
* CP/M-68K BDOS Disk I/O System Module *
*
REG struct dph *hdrp; /* pointer to disk parameter header */
REG struct dpb *dparmp; /* pointer to dis.b 'SUB',0
.even
null: .dc.l 0
.end
de routine */
/* in bdosif.s. It's used because Alcyon C */
*
* *
**************************************** if (last_dsk != iop->devnum)
bseldsk((last_dsk = iop->devnum), 0);
/* guarant *
* This module translates from the packet oriented I/O *
* passed from the other BDOS modules into Bk parameter block */
REG UWORD rtn; /* return parameter */
UWORD iosect; 裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹/* can't do / or % without an external */
/************************
* do_phio entry point *
************************/
************************/
#include "bdosinc.h" /* Standard I/O declarations */
#include "bdosdef.h" eed disk is logged on, because temp_sel in
BDOSMAIN does it */
hdrp = iop->infoIOS calls. *
* *
* It includes only one external entry /* sector number returned from divide rtn */
LOCK /* lock the disk system while doing physical i/o 裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹UWORD do_phio(iop)
REG struct iopb *iop; /* iop is a pointer to a i/o parameter block */
{
MLOCAL UBYTE las/* Type and structure declarations for BDOS */
#include "pktio.h" /* Packet I/O definitions */
#include "biosp;
dparmp = hdrp->dpbp;
bsettrk( udiv( iop->devadr, dparmp->spt, &iosect )
point:
* do_phio() - do physical i/o *
* */
rtn = 0;
switch (iop->iofcn)
{
case sel_info:
last_dsk = iop->devnum;
/****************************************************************
* t_dsk; /* static variable to tell which disk
was last used, to avoid disk selects */
+ dparmp->trk_off );
bsetsec( bsectrn( iosect, hdrp->xlt ) );
bsetdma(iop->xferadr);
0 always contains the return parameter from pgmld
* d1 is the return register from local subroutines
* a0 contains the pointer裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹location if necessary
noreloc:
tst d0
bne lddone
bsr setrtn * set up return park;
case flush:
rtn = bflush();
}
UNLOCK
return(rtn);
}
r * get header
tst d0
bne lddone * if unsuccessful, return
bsr setaddr
if ((iop->iofcn) == read) rtn = bread();
else rtn = bwrite(iop->ioflags);
bre to the Load Parm Block passed to pgmld
* Return parameters in d0 are:
* 00 - function successful
* 01 - insuff
*********************************
* *
* Function 59 -- Program Load *
* Assembly language ameters
lddone:
move.l 64(sp), d1
bsr setdma * restore dma address
movem.l (sp)+,d1-d7裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹 * set up load addresses
tst d0
bne lddone * if unsuccessful, return
bsr ak;
case flush:
rtn = bflush();
}
UNLOCK
return(rtn);
}
icient memory or bad header in file
* 02 - read error on file
* 03 - bad relocation information in file
* Entversion *
* *
* June 8, 1982 *
* *
**********/a0-a6
rts
* Subroutines
readseq:
* CP/M read sequential function
move.l d0,-(sp) * save return裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹rdtxt * read code and data text segments into mem
tst d0
bne lddone * if unsuccessfk;
case flush:
rtn = bflush();
}
UNLOCK
return(rtn);
}
ry point for Program Load routine
_pgmld:
movem.l d1-d7/a0-a6, -(sp) * save everything, just to be safe
move.***********************
.globl _pgmld * this routine is public
secsize = 128 * CP/M sector size
* d parm
move.l FCBPtr(a0),d1
moveq #20,d0 * read seq function
trap #2 * cal裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹ul, return
move.l tstart,d7
cmp.l cseg,d7
beq noreloc
bsr reloc * do rek;
case flush:
rtn = bflush();
}
UNLOCK
return(rtn);
}
l 60(sp),a0 * get pointer to LPB
clr.l d0 * start with return parm cleared
bsr gethdl bdos
move.l d0,d1 * return parm in d1
move.l (sp)+,d0
rts
setdma:
* CP/M set dma st seg?
ble confgd * if no, we're ok
confbd: moveq.l #1,d1
confgd: rts
trymemtp:
* entry: d2 is a move.l 0(a2,d2),d7 * get 1st seg start
cmp.l 0(a2,d3),d7 * is 1st seg above 2nd seg?
bge l #4,d3
tst.l d1 * conflict with this seg?
dbne d6,chk1 * if no, try next
ovea.l #hdr,a6
geth1: move.w (a5)+,(a6)+ * move header into hdr
dbf d7,geth1
rts
badhdr: moveq #eturn 0 in d1 if no conflicts, else d1 = 1
* uses d3, a5, a6
movea.l #cseg,a5
movea.l #csize,a6
sub.function
move.l d0,-(sp) * save return parm
moveq #26,d0 * set dma function
trap segment nmbr [0..4]
* try to fit it at top of memory
* uses d3, d6, d7, a5, a6
* returns 0 in d1 if ok
move.l d2,d6 conf1
add.l 0(a3,d2),d7 * yes, find top of 1st seg
cmp.l 0(a2,d3),d7 * above start of 2nd seg?
rts
fndseg:
* entry: d2 is a segment nmbr [0..4]
* try to fit segment d2 directly below segments 0..(d2-1)
* uses d3-d7,2,d0
rts
conflict:
* input parms: d2, d3 = 4 * segment nmbr
* if segment d2/4 overlaps segment d3/4, then returnl 0(a6,d2),d7 * subtract size of segment to try
bclr #0,d7 * make it even address
move.l d #2 * call bdos
move.l (sp)+,d0 * restore d0
rts
gethdr:
* Get header into buffer * d6 is loop counter for chksegs
subq #1,d6
lsl #2,d2 * multiply d2 by 4
bgt confbd * if yes, we have a conflict
rts * else, return good
conf1:
a5, a6
move.l d2,d5 * d5 is loop counter to find fit
subq.l #1,d5
move.l d5,temp
1 in d1
* else return 0 in d1
* uses d7, a2, a3
clr.l d1 * assume it will work
movea.l #cseg7,0(a5,d2) * insert address in segment table
cmp.l LoAdr(a0),d7 * check for conflict with low memory
in data segment
move.l LoAdr(a0),d1
bsr setdma
bsr readseq
tst d1 move.l HiAdr(a0),d7 * top of mem to d7
chksegs:
* entry: d2 = 4 * (segment nmbr to try)
* d6 = (d2/4) - 1 (loop move.l 0(a2,d3),d7
add.l 0(a3,d3),d7 * find top of 2nd seg
cmp.l 0(a2,d2),d7 * above start of 1 lsl.l #2,d2 * multiply segment by 4
clr.l d4 * d4 is segment to try to fit below
fnd1:
,a2 * a2 points to start of segment addresses
movea.l #csize,a3 * a3 points to start of segment lengths
blt confbd
clr.l d3 * check for conflicts with 0..d6
chk1:
bsr conflict
addq.* read ok?
bne badhdr * if no, return bad
moveq #18,d7
movea.l LoAdr(a0),a5
m counter)
* d7 = address below which to try it
* check for conflicts with segments [0..d6] and low memory boundary
* r move.l temp,d6 * d6 is loop counter for chksegs
movea.l #cseg,a5
move.l 0(a5,d4),d7 * sedseg, bseg
cmpi.w #$601b,magic
bne set3
* if magic # = 601b, take addr from hdr
move.l dstart, #$101,d7 * leave room for base page
bclr #0,d7
move.l d7,cseg * cseg is bottom of mem + adr
set6:
* now check all segments for conflicts with low and high memory boundaries
movea.l #cseg,a5
movea.e page is 256 bytes
lea stksize,a2
cmp (a2),d7
blt set0 * if stack size < 256,
tst.l d1
beq set5 * if found, skip
moveq.l #3,d2
bsr trymemtp * gment address to d7
bsr chksegs * check for conflicts
addq.l #4,d4
tst.l d1
ddseg
move.l bstart,bseg
bra set4
set3:
* if short header, dseg and bseg follow cseg
move.l cs$100 (even boundary)
bra set2
sldhi:
* relocatable, load high
move.l HiAdr(a0),d7
sub.l csizl #csize,a6
clr.l d2
moveq #4,d3 * loop counter
set7: move.l 0(a5,d2),d7 * get segment b set to 256
move.l d7,(a2)
set0: cmpi.w #$601b,magic
beq seta
tst.w rlbflg
beq else, try top of memory
tst.l d1
bne badadr * if fail, exit
set5: moveq.l #4,d2
bsrbeq d5,fnd1 * if conflict, try next
rts
setaddr:
* Set up load addresses for cseg, dseg, bss, basepg, eg,d7
add.l csize,d7
addq.l #1,d7
bclr #0,d7
move.l d7,dseg
add.l dsize,d7e,d7
sub.l dsize,d7
sub.l bsize,d7
subq.l #4,d7
bclr #0,d7 * put cseg at nase
cmp.l LoAdr(a0),d7 * above bottom of memory?
blt badadr
add.l 0(a6,d2),d7 * find t set1
seta: move.l tstart,cseg * if not relocatable or hdr = $601b,
bra set2 * cseg starts at t trymemtp * try to fit stack at top of memory
tst.l d1
beq set6 * if ok, skip
and stack
move.w magic,d6
andi.w #$fffe,d6
cmpi.w #$601a,d6
bne badadr * if
addq.l #1,d7
bclr #0,d7
move.l d7,bseg
set4:
* cseg, dseg, bseg set up
* now find a place foext even address below
move.l d7,cseg * high memory - (sum of sizes)
set2:
* Cseg has been set up. Now do op of segment
cmp.l HiAdr(a0),d7 * below top of memory?
bgt badadr
addq.l #4,d2 *start
set1: btst #0,Flags(a0)
bne sldhi
* relocatable, load low
move.l LoAdr(a0),d7
add.l moveq.l #4,d2
bsr fndseg * else, try to fit below other segs
tst.l d1
bne badmagic nmbr <> 601a or 601b, skip
move.l bpsize,symsize
move.l #256,d7
move.l d7,bpsize * basr the base page and stack
moveq.l #3,d2
bsr fndseg * try to fit base page below cseg, dseg, bseg
point to next segment
dbf d3,set7
rts
badadr: moveq.l #1,d0
rts
movebuf:
* move (d3) byted3 = secsize fo following loop
rdtxt5:
cmp.l d3,d2 * have at least one more full sector?
blt ,a2 * start at cseg
move.l csize,d2 * for csize bytes
rdtxt3:
clr.l d3
move.w buf clr.b (a2)+
subq.l #1,d2
bne rdtxt7
rdtxt8: rts
rdbad: moveq.l #2,d0
rts
relocword: d2 is number of bytes left to load
moveq #63,d7
movea.l LoAdr(a0),a5
movea.l b readseq * if yes, read into base page
tst.w d1
bne rdbad
move.w d3,bufbyts *s from the base page buffer to (a2)
* uses d6
movea.l basepg,a1
move.l #secsize,d6
sub.w bufbyts,rdtxt6
move.l a2,d1
bsr setdma * if yes, set up dma address
bsr readseq * rbyts,d3
cmp.l d2,d3 * # bytes in buffer >= # bytes to load?
blt rdtxt4
move.l d2,d3
* relocate word at (a2) based on reloc bits at (a3)
* lsb of d2 indicates whether previous word was 1st half of long-word
asepg,a6
rdtxt1: move.w (a5)+,(a6)+ * move header sector to base page
dbf d7,rdtxt1
move.w #secsize indicate that we've buffered a sector
move.l d2,d3
bsr movebuf * move remainder of segment
finrd6 * address to move from =
adda.w d6,a1 * (basepg) + secsize - (bufbyts)
sub.w d3,bufead next sector
tst.w d1
bne rdbad * if no good, exit
sub.l d3,d2 * decre
bsr movebuf * if yes, move # bytes to load
bra finrd
rdtxt4:
sub.l d3,d2 move.w (a3)+,d7 * get relocation info
andi.w #7,d7 * strip off symbol table bits
lsl -28,d7
cmpi.w #$601a,magic * short header?
beq rdtxt2
subq.w #8,d7
rdtxt2: move.w d7,bufbyd:
move.l dseg,a2 * set up to load data segment
move.l dsize,d2
sub.w #1,loop
bnbyts * update # bytes buffered
bra moveb2
moveb1: move.b (a1)+,(a2)+ * do the move
moveb2: dbf d3,mment # bytes to load
adda.l #secsize,a2 * increment dma address
bra rdtxt5
rdtxt6:
tst.l * if no, update # bytes to load
bsr movebuf * move remainder of buffer
move.l #secsize,d3 * #1,d7 * multiply by 2
jmp 2(pc,d7)
bra relabs
bra reldata
bra ts * indicate # bytes of text in buffer
move.w #2,loop * do for code, data segments
move.l csege rdtxt3
move.l bseg,a2 * clear the bss segment
move.l bsize,d2
beq rdtxt8
rdtxt7:oveb1
rts
rdtxt:
* Read code and data text into memory
* during this routine, a2 is always the load address,
* d2 * any more bytes to read?
beq finrd
move.l basepg,d1
bsr setdma
bsr relcode
bra relbss
bra relbad
bra rellong
bra relbad
bra relod7,d6 * d6 is nmbr sectors to skip
swap d7 * d7 is nmbr bytes to skip
move.w bufbytcation word in basepg
* lsb of d2 is long word flag (set on reloc type 5, reset on next word)
* d3 is # words in relocation bu * make d4 indicate # words
bra reloc4
reloc2:
subq.w #1,d3
bpl reloc3
bsr reag set?
bne relc1 * if yes, skip
move.w (a2),d6
add.w d5,d6
move.w d6,(a2)+ tst.w d1
bne rdbad
skip3: dbf d6,skip2
* we got past symbol table
* a3, d3 are set up
move.l p
relbad: move.l (sp)+,d0 * pop return address
moveq #3,d0 * return bad relocation to main routis,d3
sub.w d7,d3 * subtract bytes to skip from buffer
bge skip1
addi #secsize,d3 ffer
* d4 is nmbr of words left to relocate
* d5 is relocation offset
move.l basepg,d1
bsr setdma dseq * if no more words in buffer, refill it
tst.w d1
bne rdbad
move.l basepg,a3
rts
relc1: tst.w -(a2) * point to first word of long
move.l (a2),d6
add.l d5,d6
cseg,d5
move.l d5,a2 * relocate cseg first
sub.l tstart,d5 * d5 contains the relocation offne
rts
relabs:
relop: bclr #0,d2 * reset long word flag
tst.w (a2)+ * point to n *if amt in buffer < # bytes to skip,
addq #1,d6 * read in 1 extra sector
skip1: move.l basepg,a3
* we will always read into base page
* skip past the symbol table
move.l symsize,d7
divu #secsize,d move.w #(secsize/2)-1,d3
reloc3:
bsr relocword * relocate one word
subq.l #1,d4
reloc4:
move.l d6,(a2)+ * note that a2 points past long word
rts
reloc:
* Modify address references of coset
move.l csize,d4 * nmbr of bytes to relocate
move.w #2,loop * we're going to relocate 2 seext word of segment
rts
rellong:
bset #0,d2 * set long word flag
tst.w (a2)+ adda #secsize,a3
suba.w d3,a3 * set up a3 to point to buffer
lsr #1,d3 * d37 * calculate how many sectors to skip
* note that max # symbols is 8k, which is 896 sectors of 128 bytes
move.w tst.l d4 * any more to relocate in this segment?
bne reloc2 * if yes, do it
mde and data segments based on relocation bits
* During this routine,
* a2 points to text file to relocate
* a3 points to relogments
reloc1:
* relocate one segment
clr.l d2 * clear long word flag
lsr.l #1,d4 * point to next word of segment
rts
reldata:
relbss:
relcode:
bclr #0,d2 * long word fla is nmbr words in buffer
bra skip3
skip2:
bsr readseq * read next symbol table sector
ove.l dseg,a2 * else, set up for dseg
move.l dsize,d4
sub.w #1,loop
bne reloc1
trap #2 * get default disk
addq #1,d0 * we want it in range of 1..16
setb3: move.b ds it below previous?
bls setb2
move.l (a6),d7
setb2: tst.l (a6)+ * point to next segment
w 1
bufbyts: .ds.w 1
.end
 after bss segment
move.l HiAdr(a0),d7 * d7 contains next segment above bss
move.l -4(a1),d6
addsize is swapped with base page size
stksize: .ds.l 1
tstart: .ds.l 1
rlbflg: .ds.w 1
dstart: rts
setrtn:
* Set up the return parameters in Ld Parm Blk and Base Page
move.l basepg,BasPage(a0)
mo0,(a1)+ * move disk number into base page
clr.l d0 * function OK
rts
.bss
dbf d5,setb1
sub.l d6,d7 * diff between bss top and next segment abv
move.l d7,(a1)+
w 1
bufbyts: .ds.w 1
.end
.l (a1)+,d6 * d6 points to start of free mem after bss
movea.l #cseg,a6 * a6 points to segment to try
.ds.l 1
bstart: .ds.l 1
cseg: .ds.l 1
dseg: .ds.l 1
bseg: .ds.l 1
bve.l stk,d7
add.l stksize,d7
bclr #0,d7
move.l d7,Stack(a0)
move.l basepg,a1
* offsets from start of parameter block
FCBPtr = 0
LoAdr = 4
HiAdr = 8
BasPage = 12 * return parameters
S* now put disk number that we loaded from into base page
movea.l FCBPtr(a0),a2
move.b (w 1
bufbyts: .ds.w 1
.end
 moveq #4,d5 * try for all segments
clr.l bseg * but force bss not to appear
setb1:asepg: .ds.l 1
stk: .ds.l 1
symsize: .ds.l 1
temp: .ds.l 1
loop: .ds move.l LoAdr(a0),(a1)+
move.l HiAdr(a0),(a1)+
move.l cseg,(a1)+
move.l csize,(a1)+
movtack = 16
Flags = 21
hdr:
* load file header is read into here
magic: .ds.w a2),d0 * get disk select byte
bne setb3 * if not auto-select, skip
move #25,d0
裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹 cmp.l (a6),d6 * segment above bss?
bhi setb2
cmp.l (a6),d7 * segment is above bss. I.w 1
bufbyts: .ds.w 1
.end
e.l dseg,(a1)+
move.l dsize,(a1)+
move.l bseg,(a1)+
move.l bsize,(a1)
* find size of free memory 1
csize: .ds.l 1
dsize: .ds.l 1
bsize: .ds.l 1
bpsize: .ds.l 1 * symb tbl 裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹mber */
LONG devadr; /* item nmbr on device to start xfer at */
/* note -- item is sector for disks, byte for char devs *uture, but for now it's unused
struct dskinfo
{
UBYTE *dbuffp;
UBYTE *csv;
UBYTE *alv;
UBYTE blksize;
UBYTE didummy;#define redir 4 /* read/write IOByte */
#define exc_vec 5 /* set exception vector */
裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹ot currently used */
#define console 0
#define printer 1
#define disk 2
#define memory 3 /* gets TPA boundaries */
裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹/
UWORD xferlen; /* number items to transfer */
UBYTE *xferadr; /* memory address to xfer to/from */
struct dph *infop;
UWORD dskmax;
UWORD dirmax;
UWORD chksize;
};
*/
struct iopb
{
UBYTE iofcn; /* function number, see defines 裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹/********************************************************
* *
* CP/M-68K header file *
* Copyright (c) 1982 by D
#define redir 4 /* read/write IOByte */
#define exc_vec 5 /* set exception vector */
裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹 /* pointer to disk parameter header */
/* return parm for fcn 0, input for rest */
};
/* Definitions for iofcn, tbelow */
UBYTE ioflags; /* used for login flag and write flag */
UBYTE devtype; /* device type, see defines below */
裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹igital Research, Inc. *
* Structure definitions for doing I/O in packets *
* *
*************************************#define redir 4 /* read/write IOByte */
#define exc_vec 5 /* set exception vector */
裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹he function number */
#define sel_info 0 /* select and return info on device */
#define read 1
#define write 2
#define /* currently unused */
UBYTE devnum; /* device number, or, devtype and devnum
taken together form int device nu裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹*******************/
/* May use this information structure instead of disk parameter header and
disk parameter block in f#define redir 4 /* read/write IOByte */
#define exc_vec 5 /* set exception vector */
裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹 flush 3
#define status 4 /* not currently used */
/* Definitions for devtype, the device type */
/* This field n裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹am Load *
* *
* March 17, 1983 *
* *
* Does not load program root. *
* Leaves base page and stack as *
* set0
stack:
.ds.w 1
.end
es
readseq:
* CP/M read sequential function
move.l d0,-(sp) * save return parm
move.l FCBPtr(a0),d1
moveq #20,d0 * re*
* *
* *
* THIS IS THE DUAL PROCESSOR,ROMABLE CP/M-68K SYSTEM *
* ==================================ntry point for Program Load routine
_loadr:
clr.l d0 * start with return parm cleared
bsr gethdr * get header
tst d0
裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹 up by actual BDOS 59 *
* *
*********************************
.globl _loadr * this routine is public
secsize = 128 0
stack:
.ds.w 1
.end
ad seq function
trap #2 * call bdos
move.l d0,d1 * return parm in d1
move.l (sp)+,d0
rts
setdma:
* CP/M set dma ================ *
*************************************************************************
.globl stack
.bss
.ds.l 4bne lddone * if unsuccessful, return
bsr setaddr * set up load addresses
tst d0
bne lddone * if unsuccessful, return
裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹 * CP/M sector size
* d0 always contains the return parameter from pgmld
* d1 is the return register from local subroutines
裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹function
move.l d0,-(sp) * save return parm
moveq #26,d0 * set dma function
trap #2 * call bdos
move.l (sp)+,d0 * rest00
stack:
.ds.w 1
.end
bsr rdtxt * read code and data text segments into mem
tst d0
bne lddone * if unsuccessful, return
move.l tstart,d7
cmp裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹
* a0 contains the pointer to the Load Parm Block passed to pgmld
* Return parameters in d0 are:
* 00 - function successful
*********************************
* *
* Relocating overlay loader *
* modified from *
* Function 59 -- Progrore d0
rts
gethdr:
* Get header into buffer in data segment
move.l BasPage(a0),d1
move.l d1,basepg
bsr setdma
bs0
stack:
.ds.w 1
.end
.l cseg,d7
beq noreloc
bsr reloc * do relocation if necessary
noreloc:
tst d0
bne lddone
lddone:
rts
* Subroutin*************************************************************************
* *
* THIS IS THE SYSTEM STACK AREA
* 01 - insufficient memory or bad header in file
* 02 - read error on file
* 03 - bad relocation information in file
* Er readseq
tst d1 * read ok?
bne badhdr * if no, return bad
moveq #18,d7
movea.l BasPage(a0),a5
movea.l #hdr,a6
geth
cmp.l d3,d2 * have at least one more full sector?
blt rdtxt6
move.l a2,d1
bsr setdma * if yes, set up dma address
bsve.w d7,bufbyts * indicate # bytes of text in buffer
move.w #2,loop * do for code, data segments
move.l cseg,a2 * start atrelcode
bra relbss
bra relbad
bra rellong
bra relbad
bra relop
relbad: move.l (sp)+,d0 * pop return address
moveqbuf:
* move (d3) bytes from the base page buffer to (a2)
* uses d6
movea.l basepg,a1
move.l #secsize,d6
sub.w bufbyts,d6e.l dsize,d2
sub.w #1,loop
bne rdtxt3
move.l bseg,a2 * clear the bss segment
move.l bsize,d2
beq rdtxt8
rdtxt7: clr.1: move.w (a5)+,(a6)+ * move header into hdr
dbf d7,geth1
rts
badhdr: moveq #2,d0
rts
setaddr:
* Set up load addresr readseq * read next sector
tst.w d1
bne rdbad * if no good, exit
sub.l d3,d2 * decrement # bytes to load
adda.l #se cseg
move.l csize,d2 * for csize bytes
rdtxt3:
clr.l d3
move.w bufbyts,d3
cmp.l d2,d3 * # bytes in buffer >= # bytes #3,d0 * return bad relocation to main routine
rts
relabs:
relop: bclr #0,d2 * reset long word flag
tst.w (a2)+ * poi * address to move from =
adda.w d6,a1 * (basepg) + secsize - (bufbyts)
sub.w d3,bufbyts * update # bytes buffered
bra mob (a2)+
subq.l #1,d2
bne rdtxt7
rdtxt8: rts
rdbad: moveq.l #2,d0
rts
relocword:
* relocate word at (a2) based onses for cseg, dseg, bss, basepg, and stack
move.w magic,d6
cmpi.w #$601a,d6
bne badadr * if magic nmbr <> 601a, skip
mocsize,a2 * increment dma address
bra rdtxt5
rdtxt6:
tst.l d2 * any more bytes to read?
beq finrd
move.l basepg,d1
bsto load?
blt rdtxt4
move.l d2,d3
bsr movebuf * if yes, move # bytes to load
bra finrd
rdtxt4:
sub.l d3,d2 * if no, nt to next word of segment
rts
rellong:
bset #0,d2 * set long word flag
tst.w (a2)+ * point to next word of segment
veb2
moveb1: move.b (a1)+,(a2)+ * do the move
moveb2: dbf d3,moveb1
rts
rdtxt:
* Read code and data text into memory
reloc bits at (a3)
* lsb of d2 indicates whether previous word was 1st half of long-word
move.w (a3)+,d7 * get relocation inve.l bpsize,symsize
move.l LoAdr(a0),cseg
move.l cseg,d7
add.l csize,d7
addq.l #1,d7
bclr #0,d7
move.l d7,dseg
addr setdma
bsr readseq * if yes, read into base page
tst.w d1
bne rdbad
move.w d3,bufbyts * indicate that we've buffered update # bytes to load
bsr movebuf * move remainder of buffer
move.l #secsize,d3 * d3 = secsize fo following loop
rdtxt5:
rts
reldata:
relbss:
relcode:
bclr #0,d2 * long word flag set?
bne relc1 * if yes, skip
move.w (a2),d6
add.w d5,* during this routine, a2 is always the load address,
* d2 is number of bytes left to load
move.w #secsize-28,d7
mofo
andi.w #7,d7 * strip off symbol table bits
lsl #1,d7 * multiply by 2
jmp 2(pc,d7)
bra relabs
bra reldata
bra .l dsize,d7
addq.l #1,d7
bclr #0,d7
move.l d7,bseg
* cseg, dseg, bseg set up
rts
badadr: moveq.l #1,d0
rts
movea sector
move.l d2,d3
bsr movebuf * move remainder of segment
finrd:
move.l dseg,a2 * set up to load data segment
movd6
move.w d6,(a2)+
rts
relc1: tst.w -(a2) * point to first word of long
move.l (a2),d6
add.l d5,d6
move.l d6,(a2)+s
bra reloc4
reloc2:
subq.w #1,d3
bpl reloc3
bsr readseq * if no more words in buffer, refill it
tst.w d1
bne rdba#1,d3 * d3 is nmbr words in buffer
bra skip3
skip2:
bsr readseq * read next symbol table sector
tst.w d1
bne rdbad
s裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹l table
move.l symsize,d7
divu #secsize,d7 * calculate how many sectors to skip
* note that max # symbols is 8k, which is 8ize: .ds.l 1 * symb tbl size is swapped with base page size
stksize: .ds.l 1
tstart: .ds.l 1
rlbflg: .ds.w 1
dstart: .ds * note that a2 points past long word
rts
reloc:
* Modify address references of code and data segments based on relocatid
move.l basepg,a3
move.w #(secsize/2)-1,d3
reloc3:
bsr relocword * relocate one word
subq.l #1,d4
reloc4:
tst.l d4 kip3: dbf d6,skip2
* we got past symbol table
* a3, d3 are set up
move.l cseg,d5
move.l d5,a2 * relocate cseg first
sub裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹96 sectors of 128 bytes
move.w d7,d6 * d6 is nmbr sectors to skip
swap d7 * d7 is nmbr bytes to skip
move.w bufbyts,d3
.l 1
bstart: .ds.l 1
cseg: .ds.l 1
dseg: .ds.l 1
bseg: .ds.l 1
basepg: .ds.l 1
symsize: .ds.l 1
temp: .ds.l 1
on bits
* During this routine,
* a2 points to text file to relocate
* a3 points to relocation word in basepg
* lsb of d2 is * any more to relocate in this segment?
bne reloc2 * if yes, do it
move.l dseg,a2 * else, set up for dseg
move.l dsize,.l tstart,d5 * d5 contains the relocation offset
move.l csize,d4 * nmbr of bytes to relocate
move.w #2,loop * we're going t*
* BDOS Function Definitions
*
reboot = 0
printstr = 9
open = 15
setdma = 26
pgmldf = 59
gettpa sub.w d7,d3 * subtract bytes to skip from buffer
bge skip1
addi #secsize,d3 *if amt in buffer < # bytes to skip,
addq #1loop: .ds.w 1
bufbyts: .ds.w 1
.end
long word flag (set on reloc type 5, reset on next word)
* d3 is # words in relocation buffer
* d4 is nmbr of words left to red4
sub.w #1,loop
bne reloc1
rts
.bss
* offsets from start of parameter block
FCBPtr = 0
LoAdr = 4
BasPageo relocate 2 segments
reloc1:
* relocate one segment
clr.l d2 * clear long word flag
lsr #1,d4 * make d4 indicate # word = 63
*
.globl _ovhdlr
.xdef _loadr
.text
*
_ovhdlr:move sr,savecc * save condition codes
movem.l d1-d7/a0-a6,saver,d6 * read in 1 extra sector
skip1: move.l basepg,a3
adda #secsize,a3
suba.w d3,a3 * set up a3 to point to buffer
lsr oop: .ds.w 1
bufbyts: .ds.w 1
.end
locate
* d5 is relocation offset
move.l basepg,d1
bsr setdma * we will always read into base page
* skip past the symbo = 12
hdr:
* load file header is read into here
magic: .ds.w 1
csize: .ds.l 1
dsize: .ds.l 1
bsize: .ds.l 1
bps * save all registers
movea.l (a7)+,a6 * pop pointer to inline parameter
move.l #4,d6 * adjust return address
add.l a6,#printstr,d0 *get BDOS function number
trap #2 *print the message
move.b #36,ex *mark end of filename
move.linto register a0
jsr _loadr *load the module
tst d0 *was the load successful?
bne lderr *if not then print error messag *Base page address of loaded program
usrstk: .ds.l 1 *Loaded program's initial stack pointer
flags: .ds.w 1 *int address
*
* OPEN OVERLAY FILE
*
move.l #fcb,d1
movea.l d1,a1
move.w #open,d0 *put BDOS function number in register.ds.w 64 * input buffer (like basepage) for loadr
*
* FILE CONTROL BLOCK
*
.even
fcb: .ds.b 1 * file control block
fnamd6 * to skip over table pointer
move.l d6,-(a7) * push return address
*
* GET FILE NAME AND LOAD PT
*
movea.l (a6),a6 #fname,d1 *get address of filename
move.w #printstr,d0 *set up for BDOS call
trap #2 *print the filename
cmdrtn: move.w #e
*
* RESTORE AND RETURN
*
done: movem.l saver,d1-d7/a0-a6 * restore all registers
move savecc,ccr * restore condition coLoad program function control flags
.end
 d0
trap #2 *try to open the file to be loaded
cmpi #255,d0 *test d0 for BDOS error return code
beq openerr *if d0 = 25e: .ds.b 11
ex: .ds.b 1
sysjnk: .ds.b 19
cr: .ds.b 1
*
* LOAD PARAMETER BLOCK
*
.even
LPB: .ds.l 1 *FCB address * get ovl table address
move.l a6,d5 * check address with last loaded
cmp.l oldadd,d5 * if it's the same,
beq donereboot,d0 *get BDOS function number
trap #2 *warmboot and return to the CCP
*
* DATA
*
.data
*
* ERROR Mdes
rts
*
* PRINT ERROR MESSAGE
*
openerr:
move.l #openmsg,d1 *get address of error message
* oad program function control flags
.end
5 then goto openerr
move.b #0,cr *zero record number in fcb
*
* FILL THE LPB
*
lea ovbspg,a3 * get address of input buff of program file
lowadr: .ds.l 1 *Low boundary of area in which
* *to load program
hiad * file is already loaded.
move.l a6,oldadd * save address for next time
lea.l fname,a5 * get address of name in fcb
ESSAGE STRINGS
*
.even
loaderr: .dc.b 13,10,'Error Loading Overlay File $'
openmsg: .dc.b 13,10,'Unable to Open Overlay F *to be printed
bra print
lderr: move.l #loaderr,d1 *get address of error message to
* *be printed
print: move.w 裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹er
move.l a3,baspag * put it in LPB
move.l a1,LPB *put address of open FCB into LPB
move.l #LPB,a0 *put address of LPB r: .ds.l 1 *High boundary of area in which to
* *to load program
baspag: .ds.l 1 move.l #11,d5 * set up loop counter (l2 cycles)
gfnm: move.b (a6)+,(a5)+
dbf d5,gfnm
move.l (a6),lowadr * store load poile $'
*
* BSS
*
.bss
.even
oldadd: .ds.l 1 * table for last loaded overlay
savecc: .ds.w 1
saver: .ds.l 14
ovbspg: 裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹/ /* 68000 version */
#define VAX 1 /* VAX Version */
/*#define PDP11 1*/ /* PDP-11 Version*/
/*#define CPM 1*/ /* CP/M Ope FOOBAZ2$'
.end
 System*/
/*#define UNIX 1*/ /* UNIX Operating System*/
/*#define VMS 1*/ /* VMS Operating System*/
8000 version */
/*#define VAX 1*/ /* VAX Version */
/*#define PDP11 1*/ /* PDP-11 Version*/
#define CPM 1 /* CP/M Operating裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹rating System*/
/*#define UNIX 1*/ /* UNIX Operating System*/
#define VMS 1 /* VMS Operating System*/
裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹System*/
/*#define UNIX 1*/ /* UNIX Operating System*/
/*#define VMS 1*/ /* VMS Operating System*/
 System*/
/*#define UNIX 1*/ /* UNIX Operating System*/
/*#define VMS 1*/ /* VMS Operating System*/
裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹ating System*/
/*#define UNIX 1*/ /* UNIX Operating System*/
#define VMS 1 /* VMS Operating System*/
裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹System*/
/*#define UNIX 1*/ /* UNIX Operating System*/
/*#define VMS 1*/ /* VMS Operating System*/
/*
* Use this file to determine what kind of machine you want the
* Alcyon stuff to run on ....
*/
#define MC68000 1 /* 6裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹
/*
* Use this file to determine what kind of machine you want the
* Alcyon stuff to run on ....
*/
/*#define MC68000 1*裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹M FOOBAZ2$'
.end
8000 version */
/*#define VAX 1*/ /* VAX Version */
/*#define PDP11 1*/ /* PDP-11 Version*/
#define CPM 1 /* CP/M Operating/*
* Use this file to determine what kind of machine you want the
* Alcyon stuff to run on ....
*/
#define MC68000 1 /* 6裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹裹