mirror of
https://github.com/SEPPDROID/Digital-Research-Source-Code.git
synced 2025-10-26 18:04:07 +00:00
Upload
Digital Research
This commit is contained in:
18032
CONTRIBUTIONS/MOSS 2.2/8800-Manual/CCS_2810_Z80_CPU_1980.pdf
Normal file
18032
CONTRIBUTIONS/MOSS 2.2/8800-Manual/CCS_2810_Z80_CPU_1980.pdf
Normal file
File diff suppressed because one or more lines are too long
BIN
CONTRIBUTIONS/MOSS 2.2/8800-Manual/MOSS22.PDF
Normal file
BIN
CONTRIBUTIONS/MOSS 2.2/8800-Manual/MOSS22.PDF
Normal file
Binary file not shown.
1528
CONTRIBUTIONS/MOSS 2.2/8800-Manual/MOSS22.TXT
Normal file
1528
CONTRIBUTIONS/MOSS 2.2/8800-Manual/MOSS22.TXT
Normal file
File diff suppressed because it is too large
Load Diff
1531
CONTRIBUTIONS/MOSS 2.2/MOSS22/MOSS22.ASM
Normal file
1531
CONTRIBUTIONS/MOSS 2.2/MOSS22/MOSS22.ASM
Normal file
File diff suppressed because it is too large
Load Diff
116
CONTRIBUTIONS/MOSS 2.2/MOSS22/MOSS22.HEX
Normal file
116
CONTRIBUTIONS/MOSS 2.2/MOSS22/MOSS22.HEX
Normal file
@@ -0,0 +1,116 @@
|
||||
:10F00000C35BF0C346F6C356F6C300F6C37CF6C333
|
||||
:10F0100010F6C323F6C36AF1C365F1C38AF0C39443
|
||||
:10F02000F6C394F6C3CFF3F8F009F109F1ACF1F6A9
|
||||
:10F03000F43CF1FDF1D0F54DF209F109F10EF55D69
|
||||
:10F04000F209F155F209F121F54CF567F28FF20959
|
||||
:10F05000F191F18DF5ECF29FF482F1F3313F002153
|
||||
:10F0600000C311B2F60610D5E510FC3195F03E0054
|
||||
:10F06F00C50100F021FFFF247E2F77BE2F772004EC
|
||||
:10F07F007CB820F32501DEFF09C1C9E5CD6FF07D16
|
||||
:10F08F00D63C30012544E1C999F0F91145F4EB0163
|
||||
:10F09F001D00EDB0010600D5E12BEDB021E8FF39E1
|
||||
:10F0AF00E52323220600160AC51520FCCD94F6CDC4
|
||||
:10F0BF009FF4CD94F62190F4CD95F61843060121D7
|
||||
:10F0CF000000180C1079203205C8210000CD7BF309
|
||||
:10F0DF004FCDB0F3380829292929B56F18EFE3E58B
|
||||
:10F0EF0079CDC3F330E01012C9CD7BF3216EF1114E
|
||||
:10F0FF0005000604BE28421910FA218CF4CD98F6AB
|
||||
:10F10F002A0600F9210FF1E52201003EC33200006B
|
||||
:10F11F00CDA9F6CD78F3D64138E0FE1A30DC875F03
|
||||
:10F12F00160006022127F0197E23666FE9CD86F3BC
|
||||
:10F13F0071CD8FF330FAD118C7500604CD78F32371
|
||||
:10F14F00BE2081682D422603052804292910FC3A88
|
||||
:10F15F000300B4ACB54F79320300C93A0300C94C70
|
||||
:10F16F0032314C5450323150545232315054433169
|
||||
:10F17F004243540602CD8FF6FE0720F7CD7EF310E3
|
||||
:10F18F00F4C9CD86F30AC546B8280CF5CDFBF57842
|
||||
:10F19F00CDF4F5F1CDE6F5C1CD9BF318E8CDA4F68E
|
||||
:10F1AF00CDFBF57DCDF0F1E57ECDE6F5CD8FF338D6
|
||||
:10F1BF002ACDFEF57DE60F20EFE17DE60FCDF5F1CF
|
||||
:10F1CF007EE67F4FFE203804FE7E38020E2ECD09DC
|
||||
:10F1DF00F0CD9CF37DE60F20E718C593CDF0F11825
|
||||
:10F1EF00D8E60F4787804704CDFEF510FBC9CDC089
|
||||
:10F1FF00F338372810CDCCF0D121340039722B736E
|
||||
:10F20F0079FE0D2825060221350039C5E50602CD08
|
||||
:10F21F00D7F0D1E17AB3280A732372231A77233EEA
|
||||
:10F22F00CF1279FE0DC1280210E1CDA9F6E12143DD
|
||||
:10F23F00F4E521CFF322090021180039D1E9CDD708
|
||||
:10F24F00F0C1ED581851CDD9F0D1C1ED59C9CD86C6
|
||||
:10F25F00F37E02CD9BF318F9CDD7F0E17ECDF4F517
|
||||
:10F26F00CDC0F3D8280FFE0A280DE5CDCCF0D1E1A3
|
||||
:10F27F007379FE0DC823232B7DE607CCFBF518DC35
|
||||
:10F28F00CDA4F67EF52F77AEC4A1F2F177CD9CF326
|
||||
:10F29F0018F1D55FCDFBF506087B075F3E18174FBA
|
||||
:10F2AF00CD09F010F4D1C9232334C8F2C1F2F6808E
|
||||
:10F2BF001802E67F35BE20EFCDFEF5CD15F3CDF765
|
||||
:10F2CF00F5CDC0F3D82812E5CDCCF0E17D1312E3D4
|
||||
:10F2DF007EE3073003137C12E179FE0DC8213DF365
|
||||
:10F2EF00CDC0F3380B28F9FE2720BE2155F318F0B7
|
||||
:10F2FF007E4F3CC8FCA9F6CD09F0CDF7F5CD15F33F
|
||||
:10F30F00CDFEF52318EA237EE63FC602EB6F2600FB
|
||||
:10F31F0039EB7E060107300E0407300AE51A671B2A
|
||||
:10F32F001A6F7EE110011ACDE6F51B10F9C9C11550
|
||||
:10F33F004213431244114510461448314C30CDF15D
|
||||
:10F34F0050B453974903C109420B430A440D450C6E
|
||||
:10F35F004608480F4C0ECDCF588759855202FFE60D
|
||||
:10F36F000FC69027CE40274FC9CDF7F5CD8FF6C5E5
|
||||
:10F37F004FCD09F079C1C904CDD9F0C1D1C3AAF6D7
|
||||
:10F38F00237CB537C87B957A9CC9D1C903CD8FF340
|
||||
:10F39F0038F8CD12F0B7C8CD8FF6FE1320ECC38F1F
|
||||
:10F3AF00F6D630D8FE173FD8FE0A3FD0D607FE0A52
|
||||
:10F3BF00C9CD7BF3FE20C8FE2CC8FE0D37C83FC950
|
||||
:10F3CF00E5D5C5F5CD6FF0EB210A00390604EB2B1F
|
||||
:10F3DF00722B73D110F9C10BF921250039D5160203
|
||||
:10F3EF007E91237E98280623231520F403212000E5
|
||||
:10F3FF00D139732372C50E2ACD09F0D13EF4BA2844
|
||||
:10F40F00092323732372EBCDE1F521250039010088
|
||||
:10F41F00025E71235671237BB228027E122310F1F4
|
||||
:10F42F0008D9E5D5C5F5DDE5FDE5ED5747ED5F4FAE
|
||||
:10F43F00C5C313F1E5CFC179ED4F78ED47DDE1FDA0
|
||||
:10F44F00E1F1C1D1E108D9D1C1F1E1F90021000009
|
||||
:10F45F00C30000AF320300216CF4C3B5F6492F4F40
|
||||
:10F46F00204552D2CDE8F6B047825778C90E0DCD60
|
||||
:10F47F007CF60E0AC37CF6CD56F6E67FC93F3F3FBA
|
||||
:10F48F00BF4D4F5353205645525320322E320D8AC3
|
||||
:10F49F003E0FD324114000626ADB26A328FBDB2634
|
||||
:10F4AF0023A3A3C2ADF4E5295C1919E52929DB20B3
|
||||
:10F4BF002B7DB4C2BDF4E13E83D3237DD3207CD317
|
||||
:10F4CF00213E03D323AFD321D325CDCEF6E67FFE46
|
||||
:10F4DF000DE1C85D54CDEEF4CDEEF419E518D8B7B3
|
||||
:10F4EF007C1F677D1F6FC9CDA4F6D5CDC8F5AF576B
|
||||
:10F4FF00CDF6F63E01CDFEF6AF92CDFEF61803CD5A
|
||||
:10F50F00D7F0C178B1410E002002063CCD0CF010AF
|
||||
:10F51F00FBC93A03000604217DF111FBFFF5CDFE77
|
||||
:10F52F00F54ECD09F0CDF7F5F1F5E5233CE60320D7
|
||||
:10F53F00FA4ECD09F0E1F11F1F1910E1C9CDD7F037
|
||||
:10F54F00E1E5CD86F4DE3A20F957CD73F428235F39
|
||||
:10F55F00CD73F4F5CD73F4C14F09CD73F4CD73F4BE
|
||||
:10F56F00772FAEC4A1F2231D20F3CD73F4C209F19E
|
||||
:10F57F0018CECD73F467CD73F46FB4D1C8E9CD86CF
|
||||
:10F58F00F3AF47B120020E10E509B7ED52E1380A8B
|
||||
:10F59F00D5EBB7ED5223E3EBC1D8C5D55041CDC85C
|
||||
:10F5AF00F578CDF6F6AFCDFEF67E23CDFEF610F94B
|
||||
:10F5BF00AF92CDFEF6D1C118CFCD7CF40E3AC37CFD
|
||||
:10F5CF00F6CDA4F6E519CDFBF5E1B7ED521803CD55
|
||||
:10F5DF00A9F67CCDE6F57DF50F0F0F0FCDEFF5F109
|
||||
:10F5EF00CD6EF3180CCDE6F50E2D1805CDDEF50E0C
|
||||
:10F5FF00203A0300E603CADEF6FE02FA62F4C262A4
|
||||
:10F60F00F43A0300E6C0CADEF6FE80FA62F4CA627C
|
||||
:10F61F00F4C362F43A0300E603CAC6F6FE02FA62C6
|
||||
:10F62F00F4C262F43A0300E60CCAC6F6FE08FA62A8
|
||||
:10F63F00F4CA62F4C362F43A0300E603CACEF6FEDC
|
||||
:10F64F0002FA62F4C262F43A0300E60CCACEF6FE86
|
||||
:10F65F0008FA62F4CA62F4C362F43A0300E6C0CA5D
|
||||
:10F66F00D6F6FE80FA62F4CA62F4C362F43A03007B
|
||||
:10F67F00E630CADEF6FE20FA62F4CA62F4C362F420
|
||||
:10F68F00CD46F6E67FC9CDA9F6C54ECD00F6237956
|
||||
:10F69F000730F7C1C9CDD9F0D1E1E521C2F6CD9838
|
||||
:10F6AF00F6E1C921BBF6CD95F6C3000052535420A5
|
||||
:10F6BF004552D20D0A0080DB25E601C8C6FEC9DB24
|
||||
:10F6CF00251F30FBDB20C9DB25E620C8C6BFC9DB01
|
||||
:10F6DF0025E62028FA79D320C9CDF0F607070707CA
|
||||
:10F6EF0047CD86F4C3B0F3CDFEF67CCDFEF67DF5A7
|
||||
:10F6FF000F0F0F0FCD6EF3CD0CF0F1F5CD6EF3CDE7
|
||||
:06F70F000CF0F18257C965
|
||||
:0000000000
|
||||
|
||||
1688
CONTRIBUTIONS/MOSS 2.2/MOSS22/MOSS22.PRN
Normal file
1688
CONTRIBUTIONS/MOSS 2.2/MOSS22/MOSS22.PRN
Normal file
File diff suppressed because it is too large
Load Diff
52
CONTRIBUTIONS/MOSS 2.2/MOSS22/MOSS22.SYM
Normal file
52
CONTRIBUTIONS/MOSS 2.2/MOSS22/MOSS22.SYM
Normal file
@@ -0,0 +1,52 @@
|
||||
F17D ACT F33D ACTBL 0015 ALOC F16E ALT 0009 APLOC
|
||||
F173 APT F178 ART F103 AS0 F148 AS1 F14E AS2
|
||||
F0D3 AS3 F15A AS4 F15E AS5 F0F8 ASGN F633 BATST
|
||||
0000 BC 0007 BELL F2A8 BITS1 F2A6 BITS2 F2A1 BITS
|
||||
F5FE BLK 0013 BLOC 000B BPLOC F182 BYE F184 BYE1
|
||||
F473 BYTE F6E8 BYT F000 CBOOT F646 CI 0012 CLOC
|
||||
F194 CMPA F1A6 CMPB F6B5 COMERR F191 COMP F68F CONI
|
||||
F003 CONIN F009 CONOUT F600 CO F012 CONST F36E CONV
|
||||
000A CPLOC 000D CR F6A9 CRLF F6AA CRLFA F6C2 CRMSG
|
||||
F462 CRTIN F462 CRTOST F462 CRTOUT F462 CRTST F623 CSTS
|
||||
0013 CTRLS F462 CUSI1 F462 CUSO1 F462 CUST1 F5F4 DASH1
|
||||
F5F7 DASH 0002 DE F378 DECHO F1AF DIS1 F1B7 DIS2
|
||||
F1C8 DIS3 F1CF DIS4 F1DB DIS5 F1DD DIS6 F1EA DIS7
|
||||
F1AC DISP F4EE DIV2 0011 DLOC 000D DPLOC F37E ECH1
|
||||
F37B ECHO 0010 ELOC F462 ENDX F4F6 EOF F4FA EOFA
|
||||
000C EPLOC F0DC EX0 F0DF EX1 F0ED EX2 F0D5 EX3
|
||||
F0CC EXF F445 EXIT F6A4 EXLF F0D7 EXPR1 F0D9 EXPR
|
||||
F386 EXPR3 F097 FAKE F13C FILL F13F FIO 0014 FLOC
|
||||
000C FMFD 0008 FPLOC F214 GO0 F21A GO1 F231 GO2
|
||||
F239 GO3 F1FD GOTO F5E6 HEX1 F5EF HEX2 F5D0 HEXN
|
||||
F38F HILO F399 HILOD F39B HILOXB F39C HILOX 0004 HL
|
||||
0031 HLOC 000F HPLOC F462 HSP F462 HSPST F49F I8250
|
||||
F4A8 I8250A F4AD I8250B F4BD I8250C F4C6 I8250D 0003 ILOC
|
||||
F05B INIT F067 INIT1 F0B7 INIT2 F24D INPT 0003 IOBYTE
|
||||
F16A IOCHK F462 IOER F46C IOMSG F165 IOSET 0004 IX
|
||||
0004 IY F5DE LADRA F5FB LADRB F5E1 LADR F51B LE1
|
||||
F50E LEADER F511 LEO 000A LF F00F LIST 0030 LLOC
|
||||
0020 LLOCX F610 LO F490 LOGMSG 000E LPLOC F462 LPRST
|
||||
F462 LPRT F669 LSTAT F462 LUSE1 F462 LUST1 F08A MEMCK
|
||||
F094 MEMCK0 F06F MEMSIZ F076 MEMSZ1 F083 MEMSZ2 F000 MOSS
|
||||
F260 MOV1 F25D MOVE F28F MTEST F292 MTEST1 F29A MTEST2
|
||||
0002 NBKPTS F3B0 NIBBLE F255 OUPT F3C3 P2C F6F9 PADR
|
||||
F6F6 PBADR F6FE PBYTE F3C0 PCHK F47C PEOL 0034 PLOC
|
||||
F67C PO F355 PRMTB F699 PRTA F6A2 PRTB F315 PRTVAL
|
||||
F698 PRTWA F695 PRTWD F5C8 PSOR F462 PTRIN F462 PTRST
|
||||
F00C PUNCH F462 PUSO1 F462 PUSO2 F335 PV1 F336 PV2
|
||||
F48C QMSG F109 QPRT F52C QUE1 F53A QUE2 F521 QUERY
|
||||
F006 READER F54C READ F551 RED1 F56C RED2 F581 RED3
|
||||
F54F REDO F3CF REST F656 RI F6F0 RIBBLE F486 RIX
|
||||
0002 RLOC F000 ROM F3DE RS1 F3EF RS2 F3F6 RS3
|
||||
F3FB RS4 F3FC RS5 F419 RS6 F420 RS7 F42C RS8
|
||||
F443 RS9 F6B2 RSTER F6BB RSTMSG F694 RTS F462 RUSI1
|
||||
F462 RUSI2 F462 RUST1 F462 RUST2 0020 SDATA 0022 SIDENT
|
||||
0021 SINTEN 0023 SLCTRL 0017 SLOC 0025 SLSTAT 0024 SMDMCT
|
||||
0026 SMDMST 0006 SPSV F26B SUB1 F284 SUB2 F286 SUB3
|
||||
F267 SUBS F027 TBL 0035 TLOC 0025 TLOCX F1F7 TRPL1
|
||||
F1F5 TRPL2 F1F0 TRPLSP F6D6 TTOST F6DE TTPNCH F6C6 TTST
|
||||
F6CE TTYIN F6DE TTYOUT F6CE TTYRDR F10F WINIT F113 WINITA
|
||||
F597 WRI1 F5A9 WRI2 F5B8 WRI3 F58D WRITE 0000 WSVEC
|
||||
F2B6 XAA F2B8 XA F2C1 XAB F2C3 XAC F2E7 XE
|
||||
F2E8 XF F2FF XG 0007 XLOC F2EC XMNE F2EF XMNE1
|
||||
0005 YLOC
|
||||
419
CONTRIBUTIONS/MOSS 2.2/Z80LIB/Z80.DOC
Normal file
419
CONTRIBUTIONS/MOSS 2.2/Z80LIB/Z80.DOC
Normal file
@@ -0,0 +1,419 @@
|
||||
Z-80 Macro Library Documentation
|
||||
--------------------------------
|
||||
|
||||
I.
|
||||
The purpose of this library is to enable the assembly of the Z-80
|
||||
instruction set on a CP/M sytem using the CP/M MAC macro assembler.
|
||||
|
||||
This library is invoked with the pseudo-op:
|
||||
|
||||
" MACLIB Z80 "
|
||||
|
||||
II.
|
||||
The following symbols and notations are used in the individual macro
|
||||
descriptions;
|
||||
|
||||
r - Any of the 8 bit registers: A, B, C, D, E, H, L, or M
|
||||
rr - Any of the 16 bit register pairs: BC, DE, HL, or SP
|
||||
nn - 8 bit immediate data (0 through 255)
|
||||
d - 8 bit signed displacment (-128 through +127)
|
||||
nnnn - 16 bit address or immediate data (0 through 65535)
|
||||
b - bit number (0-7, 7 is most significant, 0 is least)
|
||||
addr - 16 bit address within PC+127 through PC-128
|
||||
m(zzz) - Memory at address "zzz"
|
||||
|
||||
III.
|
||||
|
||||
MACLIB ver. Zilog ver TDL ver
|
||||
-------------- ------------- -------------
|
||||
|
||||
LDX r,d LD r,(IX+d) MOV r,d(IX)
|
||||
Load register from indexed memory (with IX)
|
||||
|
||||
LDY r,d LD r,(IY+d) MOV r,d(IY)
|
||||
Load register from indexed memory (with IY)
|
||||
|
||||
STX r,d LD (IX+d),r MOV d(IX),r
|
||||
Store register to indexed memory (with IX)
|
||||
|
||||
STY r,d LD (IY+d),r MOV d(IY),r
|
||||
Store register to indexed memory (with IY)
|
||||
|
||||
MVIX nn,d LD (IX+d),nn MVI d(IX)
|
||||
Move immediate to indexed memory (with IX)
|
||||
|
||||
MVIY nn,d LD (IY+d),nn MVI d(IY)
|
||||
Move immediate to indexed memory (with IY)
|
||||
|
||||
LDAI LD A,I LDAI
|
||||
Move I to A
|
||||
|
||||
LDAR LD A,R LDAR
|
||||
Move R to A
|
||||
|
||||
STAI LD I,A STAI
|
||||
Move A to I
|
||||
|
||||
STAR LD R,A STAR
|
||||
Move A to R
|
||||
|
||||
LXIX nnnn LD IX,nnnn LXI IX,nnnn
|
||||
Load IX immediate (16 bits)
|
||||
|
||||
LXIY nnnn LD IY,nnnn LXI IY,nnnn
|
||||
Load IY immediate (16 bits)
|
||||
|
||||
LBCD nnnn LD BC,(nnnn) LBCD nnnn
|
||||
Load BC direct (from memory at nnnn)
|
||||
|
||||
LDED nnnn LD DE,(nnnn) LDED nnnn
|
||||
Load DE direct
|
||||
|
||||
LSPD nnnn LD SP,(nnnn) LSPD nnnn
|
||||
Load SP direct
|
||||
|
||||
LIXD nnnn LD IX,(nnnn) LIXD nnnn
|
||||
Load IX direct
|
||||
|
||||
LIYD nnnn LD IY,(nnnn) LIYD nnnn
|
||||
Load IY direct
|
||||
|
||||
SBCD nnnn LD (nnnn),BC SBCD nnnn
|
||||
Store BC direct (to memory at nnnn)
|
||||
|
||||
SDED nnnn LD (nnnn),DE SDED nnnn
|
||||
Store DE direct
|
||||
|
||||
SSPD nnnn LD (nnnn),SP SSPD nnnn
|
||||
Store SP direct
|
||||
|
||||
SIXD nnnn LD (nnnn),IX SIXD nnnn
|
||||
Store IX direct
|
||||
|
||||
SIYD nnnn LD (nnnn),IY SIYD nnnn
|
||||
Store IY direct
|
||||
|
||||
SPIX LD SP,IX SPIX
|
||||
Copy IX to the SP
|
||||
|
||||
SPIY LD SP,IY SPIY
|
||||
Copy IY to the SP
|
||||
|
||||
PUSHIX PUSH IX PUSH IX
|
||||
Push IX into the stack
|
||||
|
||||
PUSHIY PUSH IY PUSH IY
|
||||
Push IY into the stack
|
||||
|
||||
POPIX POP IX POP IX
|
||||
Pop IX from the stack
|
||||
|
||||
POPIY POP IY POP IY
|
||||
Pop IY from the stack
|
||||
|
||||
EXAF EX AF,AF' EXAF
|
||||
Exchange AF and the alternate, AF'
|
||||
|
||||
EXX EXX EXX
|
||||
Exchange BC DE HL with BC' DE' HL'
|
||||
|
||||
XTIX EX (SP),IX XTIX
|
||||
Exchange IX with the top of the stack
|
||||
|
||||
XTIY EX (SP),IY XTIY
|
||||
Exchange IY with the top of the stack
|
||||
|
||||
LDI LDI LDI
|
||||
Move m(HL) to m(DE), increment DE and HL, decrement BC
|
||||
|
||||
LDIR LDIR LDIR
|
||||
Repeat LDI until BC = 0
|
||||
|
||||
LDD LDD LDD
|
||||
Move m(HL) to m(DE), decrement HL, DE, and BC
|
||||
|
||||
LDDR LDDR LDDR
|
||||
Repeat LDD until BC = 0
|
||||
|
||||
CCI CPI CCI
|
||||
Compare A with m(HL), increment HL, decrement BC
|
||||
|
||||
CCIR CPIR CCIR
|
||||
Repeat CCI until BC = 0 or A = m(HL)
|
||||
|
||||
CCD CPD CCD
|
||||
Compare A with m(HL), decrement HL and BC
|
||||
|
||||
CCDR CPDR CCDR
|
||||
Repeat CCD until BC = 0 or A = m(HL)
|
||||
|
||||
ADDX d ADD (IX+d) ADD d(IX)
|
||||
Indexed add to A
|
||||
|
||||
ADDY d ADD (IY+d) ADD d(IY)
|
||||
Indexed add to A
|
||||
|
||||
ADCX d ADC (IX+d) ADC d(IX)
|
||||
Indexed add with carry
|
||||
|
||||
ADCY d ADC (IY+d) ADC d(IY)
|
||||
Indexed add with carry
|
||||
|
||||
SUBX d SUB (IX+d) SUB d(IX)
|
||||
Indexed subtract
|
||||
|
||||
SUBY d SUB (IY+d) SUB d(IY)
|
||||
Indexed Subtract
|
||||
|
||||
SBCX d SBC (IX+d) SBB d(IX)
|
||||
Indexed subtract with "borrow"
|
||||
|
||||
SBCY d SBC (IY+d) SBB d(IY)
|
||||
Indexed subtract with borrow
|
||||
|
||||
ANDX d AND (IX+d) ANA d(IX)
|
||||
Indexed logical and
|
||||
|
||||
ANDY d AND (IY+d) ANA d(IY)
|
||||
Indexed logical and
|
||||
|
||||
XORX d XOR (IX+d) XRA d(IX)
|
||||
Indexed logical exclusive or
|
||||
|
||||
XORY d XOR (IY+d) XRA d(IY)
|
||||
Indexed logical exclusive or
|
||||
|
||||
ORX d OR (IX+d) ORA d(IX)
|
||||
Indexed logical or
|
||||
|
||||
ORY d OR (IY+d) ORA d(IY)
|
||||
Indexed logical exclusive or
|
||||
|
||||
CMPX d CP (IX+d) CMP d(IX)
|
||||
Indexed compare
|
||||
|
||||
CMPY d CP (IY+d) CMP d(IY)
|
||||
Index compare
|
||||
|
||||
INRX d INC (IX+d) INR d(IX)
|
||||
Increment memory at m(IX+d)
|
||||
|
||||
INRY d INC (IY+d) INR d(IY)
|
||||
Increment memory at m(IY+d)
|
||||
|
||||
DCRX d INC (IX+d) INR d(IX)
|
||||
Decrement memory at m(IX+d)
|
||||
|
||||
DCRY d DEC (IY+d) DCR d(IY)
|
||||
Decrement memory at m(IX+d)
|
||||
|
||||
NEG NEG NEG
|
||||
Negate A (two's complement)
|
||||
|
||||
IM0 IM0 IM0
|
||||
Set interrupt mode 0
|
||||
|
||||
IM1 IM1 IM1
|
||||
Set interrupt mode 1
|
||||
|
||||
IM2 IM2 IM2
|
||||
Set interrupt mode 2
|
||||
|
||||
DADC rr ADC HL,rr DADC rr
|
||||
Add with carry rr to HL
|
||||
|
||||
DSBC rr SBC HL,rr DSBC rr
|
||||
Subtract with "borrow" rr from HL
|
||||
|
||||
DADX rr ADD IX,rr DADX rr
|
||||
Add rr to IX (rr may be BC, DE, SP, IX)
|
||||
|
||||
DADY rr ADD IY,rr DADY rr
|
||||
Add rr to IY (rr may be BC, DE, SP, IY)
|
||||
|
||||
INXIX INC IX INX IX
|
||||
Increment IX
|
||||
|
||||
INXIY INC IY INX IY
|
||||
Increment IY
|
||||
|
||||
DCXIX DEC IX DCX IX
|
||||
Decrement IX
|
||||
|
||||
DCXIY DEC IY DCX IY
|
||||
Decrement IY
|
||||
|
||||
BIT b,r BIT b,r BIT b,r
|
||||
Test bit b in register r
|
||||
|
||||
SETB b,r SET b,r SET b,r
|
||||
Set bit b in register r
|
||||
|
||||
RES b,r RES b,r RES b,r
|
||||
Reset bit b in register r
|
||||
|
||||
BITX b,d BIT b,(IX+d) BIT b,d(IX)
|
||||
Test bit b in memory at m(IX+d)
|
||||
|
||||
BITY b,d BIT b,(IY+d) BIT b,d(IY)
|
||||
Test bit b in memory at m(IY+d)
|
||||
|
||||
SETX b,d SET b,(IX+d) SET b,d(IX)
|
||||
Set bit b in memory at m(IX+d)
|
||||
|
||||
SETY b,d SET b,(IY+d) SET b,d(IY)
|
||||
Set bit b in memory at m(IY+d)
|
||||
|
||||
RESX b,d RES b,(IX+d) RES b,d(IX)
|
||||
Reset bit b in memory at m(IX+d)
|
||||
|
||||
RESY b,d RES b,(IY+d) RES b,d(IY)
|
||||
Reset bit b in memory at m(IY+d)
|
||||
|
||||
JR addr JR addr-$ JMPR addr
|
||||
Jump relative unconditional
|
||||
|
||||
JRC addr JR C,addr-$ JRC addr
|
||||
Jump relative if Carry indicator true
|
||||
|
||||
JRNC addr JR NC,addr-$ JRNC addr
|
||||
Jump relative if carry indicator false
|
||||
|
||||
JRZ addr JR Z,addr-$ JRC addr
|
||||
Jump relative if Zero indicator true
|
||||
|
||||
JRNZ addr JR NZ,addr-$ JRNZ addr
|
||||
Jump relative if Zero indicator false
|
||||
|
||||
DJNZ addr DJNZ addr-$ DJNZ addr
|
||||
Decrement B, jump relative if non-zero
|
||||
|
||||
PCIX JMP (IX) PCIX
|
||||
Jump to address in IX ie, Load PC from IX
|
||||
|
||||
PCIY JMP (IY) PCIY
|
||||
Jump to address in IY
|
||||
|
||||
RETI RETI RETI
|
||||
Return from interrupt
|
||||
|
||||
RETN RETN RETN
|
||||
Return from non-maskable interrupt
|
||||
|
||||
INP r IN r,(C) INP r
|
||||
Input from port C to register r
|
||||
|
||||
OUTP r OUT (C),r OUTP r
|
||||
Output from register r to port (C)
|
||||
|
||||
INI INI INI
|
||||
Input from port (C) to m(HL), increment HL, decrement b
|
||||
|
||||
INIR INIR INIR
|
||||
Input from port (C) to m(HL), increment HL, decrement B, repeat if B <> 0
|
||||
|
||||
OUTI OTI OUTI
|
||||
Output from m(HL) to port (C), increment HL, decrement B
|
||||
|
||||
OUTIR OTIR OUTIR
|
||||
Repeat OUTI until B = 0
|
||||
|
||||
IND IND IND
|
||||
Input from port (C) to m(HL), decrement HL & B
|
||||
|
||||
INDR INDR INDR
|
||||
Repeat IND until B = 0
|
||||
|
||||
OUTD OTD OUTD
|
||||
Output from m(HL) to port (C), decrement HL & B
|
||||
|
||||
OUTDR OTDR OUTDR
|
||||
Repeat OUTD until B = 0
|
||||
|
||||
RLCR r RLC r RLCR r
|
||||
Rotate left circular register
|
||||
|
||||
RLCX d RLC (IX+d) RLCR d(IX)
|
||||
Rotate left circular indexed memory
|
||||
|
||||
RLCY d RLC (IY+d) RLCR d(IY)
|
||||
Rotate left circular indexed memory
|
||||
|
||||
RALR r RL r RALR r
|
||||
Rotate left arithmetic register
|
||||
|
||||
RALX d RL (IX+d) RALR d(IX)
|
||||
Rotate left arithmetic indexed memory
|
||||
|
||||
RALY d RL (IY+d) RALR d(IY)
|
||||
Rotate left arithmetic indexed memory
|
||||
|
||||
RRCR r RRC r RRCR r
|
||||
Rotate right circular register
|
||||
|
||||
RRCX d RRC (IX+d) RRCR d(IX)
|
||||
Rotate right circular indexed
|
||||
|
||||
RRCY d RRC (IY+d) RRCR d(IY)
|
||||
Rotate right circular indexed
|
||||
|
||||
RARR r RR r RARR r
|
||||
Rotate right arithmetic register
|
||||
|
||||
RARX d RR (IX+d) RARR d(IX)
|
||||
Rotate right arithmetic indexed memory
|
||||
|
||||
RARY d RR (IY+d) RARR d(IY)
|
||||
Rotate right arithmetic indexed memory
|
||||
|
||||
SLAR r SLA r SLAR r
|
||||
Shift left register
|
||||
|
||||
SLAX d SLA (IX+d) SLAR d(IX)
|
||||
Shift left indexed memory
|
||||
|
||||
SLAY d SLA (IY+d) SLAR d(IY)
|
||||
Shift left indexed memory
|
||||
|
||||
SRAR r SRA r SRAR r
|
||||
Shift right arithmetic register
|
||||
|
||||
SRAX d SRA (IX+d) SRAR d(IX)
|
||||
Shift right arithmetic indexed memory
|
||||
|
||||
SRAY d SRA (IY+d) SRAR d(IY)
|
||||
Shift right arithmetic indexed memory
|
||||
|
||||
SRLR r SRL r SRLR r
|
||||
Shift right logical register
|
||||
|
||||
SRLX d SRL (IX+d) SRLR d(IX)
|
||||
Shift right logical indexed memory
|
||||
|
||||
SRLY d SRL (IY+d) SRLR d(IY)
|
||||
Shift right logical indexed memory
|
||||
|
||||
RLD RLD RLD
|
||||
Rotate left digit
|
||||
|
||||
RRD RRD RRD
|
||||
Rotate right digit
|
||||
|
||||
HK ?D
|
||||
DB 0FDH, 0CBH, ?D, 16H
|
||||
ENDM
|
||||
RRCR MACRO ?R
|
||||
DB 0CBH, 08H + ?R
|
||||
ENDM
|
||||
RRCX MACRO ?D
|
||||
@CHK ?D
|
||||
DB 0DDH, 0CBH, ?D, 0EH
|
||||
ENDM
|
||||
RRCY MACRO ?D
|
||||
@CHK ?D
|
||||
DB 0FDH, 0CBH, ?D, 0EH
|
||||
ENDM
|
||||
RARR MACRO ?R
|
||||
DB 0CBH, 18H + ?R
|
||||
ENDM
|
||||
RARX MACRO ?D
|
||||
630
CONTRIBUTIONS/MOSS 2.2/Z80LIB/Z80.LIB
Normal file
630
CONTRIBUTIONS/MOSS 2.2/Z80LIB/Z80.LIB
Normal file
@@ -0,0 +1,630 @@
|
||||
;;
|
||||
;; Z-80 MACRO LIBRARY
|
||||
;;
|
||||
;; THE FOLLOWING MACROS ENABLE ASSEMBLING Z-80 INSTRUCTIONS
|
||||
;; WITH THE DIGITAL RESEARCH MACRO ASSEMBLER.
|
||||
;;
|
||||
;; INVOKE WITH "MACLIB Z80"
|
||||
;;
|
||||
;;
|
||||
;; Macro's added to support Z80 Opcodes by Garry Kraemer - Senior Software Engineer
|
||||
;;
|
||||
;;
|
||||
;; MACRO FORMATS
|
||||
;; ----- -------
|
||||
;;
|
||||
;;
|
||||
;; MACRO ZILOG TDL
|
||||
;; ----- ----- ---
|
||||
;;
|
||||
;; LDX R,D LD R,(IX+D) MOV R,D(IX)
|
||||
;; LDY R,D LD R,(IY+D) MOV R,D(IY)
|
||||
;; STX R,D LD (IX+D),R MOV D(IX),R
|
||||
;; STY R,D LD (IY+D),R MOV D(IY),R
|
||||
;; MVIX NN,D LD (IX+D),NN MVI D(IX)
|
||||
;; MVIY NN,D LD (IY+D),NN MVI D(IY)
|
||||
;; LDAI LD A,I LDAI
|
||||
;; LDAR LD A,R LDAR
|
||||
;; STAI LD I,A STAI
|
||||
;; STAR LD R,A STAR
|
||||
;; LXIX NNNN LD IX,NNNN LXI IX,NNNN
|
||||
;; LXIY NNNN LD IY,NNNN LXI IY,NNNN
|
||||
;; LBCD NNNN LD BC,(NNNN) LBCD NNNN
|
||||
;; LDED NNNN LD DE,(NNNN) LDED NNNN
|
||||
;; LSPD NNNN LD SP,(NNNN) LSPD NNNN
|
||||
;; LIXD NNNN LD IX,(NNNN) LIXD NNNN
|
||||
;; LIYD NNNN LD IY,(NNNN) LIYD NNNN
|
||||
;; SBCD NNNN LD (NNNN),BC SBCD NNNN
|
||||
;; SDED NNNN LD (NNNN),DE SDED NNNN
|
||||
;; SSPD NNNN LD (NNNN),SP SSPD NNNN
|
||||
;; SIXD NNNN LD (NNNN),IX SIXD NNNN
|
||||
;; SIYD NNNN LD (NNNN),IY SIYD NNNN
|
||||
;; SPIX LD SP,IX SPIX
|
||||
;; SPIY LD SP,IY SPIY
|
||||
;; PUSHIX PUSH IX PUSH IX
|
||||
;; PUSHIY PUSH IY PUSH IY
|
||||
;; POPIX POP IX POP IX
|
||||
;; POPIY POP IY POP IY
|
||||
;; EXAF EX AF,AF' EXAF
|
||||
;; EXX EXX EXX
|
||||
;; XTIX EX (SP),IX XTIX
|
||||
;; XTIY EX (SP),IY XTIY
|
||||
;; LDI LDI LDI
|
||||
;; LDIR LDIR LDIR
|
||||
;; LDD LDD LDD
|
||||
;; LDDR LDDR LDDR
|
||||
;; CCI CPI CCI
|
||||
;; CCIR CPIR CCIR
|
||||
;; CCD CPD CCD
|
||||
;; CCDR CPDR CCDR
|
||||
;; ADDX D ADD (IX+D) ADD D(IX)
|
||||
;; ADDY D ADD (IY+D) ADD D(IY)
|
||||
;; ADCX D ADC (IX+D) ADC D(IX)
|
||||
;; ADCY D ADC (IY+D) ADC D(IY)
|
||||
;; SUBX D SUB (IX+D) SUB D(IX)
|
||||
;; SUBY D SUB (IY+D) SUB D(IY)
|
||||
;; SBCX D SBC (IX+D) SBB D(IX)
|
||||
;; SBCY D SBC (IY+D) SBB D(IY)
|
||||
;; ANDX D AND (IX+D) ANA D(IX)
|
||||
;; ANDY D AND (IY+D) ANA D(IY)
|
||||
;; XORX D XOR (IX+D) XRA D(IX)
|
||||
;; XORY D XOR (IY+D) XRA D(IY)
|
||||
;; ORX D OR (IX+D) ORA D(IX)
|
||||
;; ORY D OR (IY+D) ORA D(IY)
|
||||
;; CMPX D CP (IX+D) CMP D(IX)
|
||||
;; CMPY D CP (IY+D) CMP D(IY)
|
||||
;; INRX D INC (IX+D) INR D(IX)
|
||||
;; INRY D INC (IY+D) INR D(IY)
|
||||
;; DCRX D INC (IX+D) INR D(IX)
|
||||
;; DCRY D DEC (IY+D) DCR D(IY)
|
||||
;; NEG NEG NEG
|
||||
;; IM0 IM0 IM0
|
||||
;; IM1 IM1 IM1
|
||||
;; IM2 IM2 IM2
|
||||
;; DADC RR ADC HL,RR DADC RR
|
||||
;; DSBC RR SBC HL,RR DSBC RR
|
||||
;; DADX RR ADD IX,RR DADX RR
|
||||
;; DADY RR ADD IY,RR DADY RR
|
||||
;; INXIX INC IX INX IX
|
||||
;; INXIY INC IY INX IY
|
||||
;; DCXIX DEC IX DCX IX
|
||||
;; DCXIY DEC IY DCX IY
|
||||
;; BIT B,R BIT B,R BIT B,R
|
||||
;; SETB B,R SET B,R SET B,R
|
||||
;; RES B,R RES B,R RES B,R
|
||||
;; BITX B,D BIT B,(IX+D) BIT B,D(IX)
|
||||
;; BITY B,D BIT B,(IY+D) BIT B,D(IY)
|
||||
;; SETX B,D SET B,(IX+D) SET B,D(IX)
|
||||
;; SETY B,D SET B,(IY+D) SET B,D(IY)
|
||||
;; RESX B,D RES B,(IX+D) RES B,D(IX)
|
||||
;; RESY B,D RES B,(IY+D) RES B,D(IY)
|
||||
;; JR ADDR JR ADDR-$ JMPR ADDR
|
||||
;; JRC ADDR JR C,ADDR-$ JRC ADDR
|
||||
;; JRNC ADDR JR NC,ADDR-$ JRNC ADDR
|
||||
;; JRZ ADDR JR Z,ADDR-$ JRC ADDR
|
||||
;; JRNZ ADDR JR NZ,ADDR-$ JRNZ ADDR
|
||||
;; DJNZ ADDR DJNZ ADDR-$ DJNZ ADDR
|
||||
;; PCIX JMP (IX) PCIX
|
||||
;; PCIY JMP (IY) PCIY
|
||||
;; RETI RETI RETI
|
||||
;; RETN RETN RETN
|
||||
;; INP R IN R,(C) INP R
|
||||
;; OUTP R OUT (C),R OUTP R
|
||||
;; INI INI INI
|
||||
;; INIR INIR INIR
|
||||
;; OUTI OTI OUTI
|
||||
;; OUTIR OTIR OUTIR
|
||||
;; IND IND IND
|
||||
;; INDR INDR INDR
|
||||
;; OUTD OTD OUTD
|
||||
;; OUTDR OTDR OUTDR
|
||||
;; RLCR R RLC R RLCR R
|
||||
;; RLCX D RLC (IX+D) RLCR D(IX)
|
||||
;; RLCY D RLC (IY+D) RLCR D(IY)
|
||||
;; RALR R RL R RALR R
|
||||
;; RALX D RL (IX+D) RALR D(IX)
|
||||
;; RALY D RL (IY+D) RALR D(IY)
|
||||
;; RRCR R RRC R RRCR R
|
||||
;; RRCX D RRC (IX+D) RRCR D(IX)
|
||||
;; RRCY D RRC (IY+D) RRCR D(IY)
|
||||
;; RARR R RR R RARR R
|
||||
;; RARX D RR (IX+D) RARR D(IX)
|
||||
;; RARY D RR (IY+D) RARR D(IY)
|
||||
;; SLAR R SLA R SLAR R
|
||||
;; SLAX D SLA (IX+D) SLAR D(IX)
|
||||
;; SLAY D SLA (IY+D) SLAR D(IY)
|
||||
;; SRAR R SRA R SRAR R
|
||||
;; SRAX D SRA (IX+D) SRAR D(IX)
|
||||
;; SRAY D SRA (IY+D) SRAR D(IY)
|
||||
;; SRLR R SRL R SRLR R
|
||||
;; SRLX D SRL (IX+D) SRLR D(IX)
|
||||
;; SRLY D SRL (IY+D) SRLR D(IY)
|
||||
;; RLD RLD RLD
|
||||
;; RRD RRD RRD
|
||||
;;
|
||||
;;******************************************************************
|
||||
;;
|
||||
;; @CHK MACRO USED FOR CHECKING 8 BIT DISPLACMENTS
|
||||
;;
|
||||
@CHK MACRO ?DD ;; USED FOR CHECKING RANGE OF 8-BIT DISP.S
|
||||
IF (?DD GT 07FH) AND (?DD LT 0FF80H)
|
||||
'DISPLACEMENT RANGE ERROR - Z80 LIB'
|
||||
ENDIF
|
||||
ENDM
|
||||
@CHECK MACRO ?N
|
||||
?DD SET ?N-$-2
|
||||
IF (?DD GT 07FH) AND (?DD LT 0FF80H)
|
||||
'RANGE ERROR - Z80 LIB'
|
||||
?DD SET 0FEH
|
||||
ENDIF
|
||||
ENDM
|
||||
;;
|
||||
;;
|
||||
LDX MACRO ?R,?D ;;LOAD REG R FROM MEMORY AT (IX+D)
|
||||
@CHK ?D
|
||||
DB 0DDH,?R*8+46H,?D
|
||||
ENDM
|
||||
LDY MACRO ?R,?D ;;LOAD REG R FROM MEMORY AT (IY+D)
|
||||
@CHK ?D
|
||||
DB 0FDH,?R*8+46H,?D
|
||||
ENDM
|
||||
STX MACRO ?R,?D ;;STORE REG R AT MEMORY (IX+D)
|
||||
@CHK ?D
|
||||
DB 0DDH,70H+?R,?D
|
||||
ENDM
|
||||
STY MACRO ?R,?D ;;STORE REG R AT MEMORY (IY+D)
|
||||
@CHK ?D
|
||||
DB 0FDH,70H+?R,?D
|
||||
ENDM
|
||||
MVIX MACRO ?N,?D ;;MOV #N (8 BITS) INTO MEMORY AT (IX+D)
|
||||
@CHK ?D
|
||||
DB 0DDH,36H,?D,?N
|
||||
ENDM
|
||||
MVIY MACRO ?N,?D ;;MOV #N (8 BITS) INTO MEMORY AT (IY+D)
|
||||
@CHK ?D
|
||||
DB 0FDH,36H,?D,?N
|
||||
ENDM
|
||||
LDAI MACRO ;;LOAD ACC WITH REG I (INTERRUPT VECTOR)
|
||||
DB 0EDH,57H
|
||||
ENDM
|
||||
LDAR MACRO ;;LOAD ACC WITH THE REFRESH REG
|
||||
DB 0EDH,5FH
|
||||
ENDM
|
||||
STAI MACRO ;;STORE ACC INTO REG I
|
||||
DB 0EDH,47H
|
||||
ENDM
|
||||
STAR MACRO ;;STORE ACC INTO THE REFRESH REG
|
||||
DB 0EDH,4FH
|
||||
ENDM
|
||||
LXIX MACRO ?NNNN ;;LOAD IMMEDIATE (LDI) IX WITH #NNNN (16 BITS)
|
||||
DB 0DDH,21H
|
||||
DW ?NNNN
|
||||
ENDM
|
||||
LXIY MACRO ?NNNN ;;LDI REG PAIR IY WITH #NNNN (16 BITS)
|
||||
DB 0FDH,21H
|
||||
DW ?NNNN
|
||||
ENDM
|
||||
LDED MACRO ?NNNN ;;LOAD DE WITH CONTENTS OF MEMORY AT NNNN
|
||||
DB 0EDH,5BH ;; (E)=((NN)(NN))
|
||||
DW ?NNNN ;; (D)=((NN)(NN+1))
|
||||
ENDM
|
||||
LBCD MACRO ?NNNN ;;LOAD BC WITH CONTENTS OF MEMORY AT NNNN
|
||||
DB 0EDH,4BH
|
||||
DW ?NNNN
|
||||
ENDM
|
||||
LSPD MACRO ?NNNN ;;LOAD STACK POINTER WITH CONTENTS OF MEMORY
|
||||
DB 0EDH,07BH ;; AT NNNN
|
||||
DW ?NNNN
|
||||
ENDM
|
||||
LIXD MACRO ?NNNN ;;LOAD IX WITH CONTENTS OF MEMORY AT NNNN
|
||||
DB 0DDH,2AH
|
||||
DW ?NNNN
|
||||
ENDM
|
||||
LIYD MACRO ?NNNN ;;LOAD IY WITH CONTENTS OF MEMORY AT NNNN
|
||||
DB 0FDH,2AH
|
||||
DW ?NNNN
|
||||
ENDM
|
||||
SBCD MACRO ?NNNN ;;STORE BC IN MEMORY LOCATION NNNN
|
||||
DB 0EDH,43H ;; ((NN)(NN))=(C)
|
||||
DW ?NNNN ;; ((NN)(NN+1))=(B)
|
||||
ENDM
|
||||
SDED MACRO ?NNNN ;;STORE DE IN MEMORY LOC NNNN
|
||||
DB 0EDH,53H
|
||||
DW ?NNNN
|
||||
ENDM
|
||||
SSPD MACRO ?NNNN ;;STORE STACK POINTER IN MEMORY LOC NNNN
|
||||
DB 0EDH,73H
|
||||
DW ?NNNN
|
||||
ENDM
|
||||
SIXD MACRO ?NNNN ;;STORE IX IN MEMORY LOC NNNN
|
||||
DB 0DDH,22H
|
||||
DW ?NNNN
|
||||
ENDM
|
||||
SIYD MACRO ?NNNN ;;STORE IY IN MEMORY LOC NNNN
|
||||
DB 0FDH,22H
|
||||
DW ?NNNN
|
||||
ENDM
|
||||
SPIX MACRO ;;MOV IX INTO STACK POINTER (SP)
|
||||
DB 0DDH,0F9H
|
||||
ENDM
|
||||
SPIY MACRO ;;MOV IY INTO STACK POINTER (SP)
|
||||
DB 0FDH,0F9H
|
||||
ENDM
|
||||
PUSHIX MACRO ;;PUSH IX ONTO STACK
|
||||
DB 0DDH,0E5H
|
||||
ENDM
|
||||
PUSHIY MACRO ;;PUSH IY ONTO STACK
|
||||
DB 0FDH,0E5H
|
||||
ENDM
|
||||
POPIX MACRO ;;POP IX OFF STACK
|
||||
DB 0DDH,0E1H
|
||||
ENDM
|
||||
POPIY MACRO ;;POP IY OFF STACK
|
||||
DB 0FDH,0E1H
|
||||
ENDM
|
||||
EXAF MACRO ;;EXCHANGE AF AND AF' REGS
|
||||
DB 08H
|
||||
ENDM
|
||||
EXX MACRO ;;EXCHANGE BC AND BC'
|
||||
DB 0D9H ;; DE AND DE'
|
||||
;; HL AND HL'
|
||||
ENDM
|
||||
XTIX MACRO ;;EXCHANGE TOP OF STACK WITH IX
|
||||
DB 0DDH,0E3H
|
||||
ENDM
|
||||
XTIY MACRO ;;EXCHANGE TOP OF STACK WITH IY
|
||||
DB 0FDH,0E3H
|
||||
ENDM
|
||||
|
||||
LDI MACRO ;;LOAD MEMORY AT (H,L) TO MEMORY AT (D,E)
|
||||
DB 0EDH,0A0H ;; INC D,E INC H,L DEC B,C
|
||||
ENDM
|
||||
LDIR MACRO ;;AS ABOVE REPEAT UNTIL B=0
|
||||
DB 0EDH,0B0H
|
||||
ENDM
|
||||
LDD MACRO ;;LOAD MEMORY AT (H,L) TO MEMORY AT (D,E)
|
||||
DB 0EDH,0A8H ;; DEC H,L DEC D,E DEC B,C
|
||||
ENDM
|
||||
LDDR MACRO ;;AS ABOVE REPEAT UNTIL B=0
|
||||
DB 0EDH,0B8H
|
||||
ENDM
|
||||
CCI MACRO ;;COMPARE ACC WITH MEMORY AT (H,L)
|
||||
DB 0EDH,0A1H ;; INC H,L DEC B,C (P/V=0 IF B=0)
|
||||
;; (ACC=(H,L) IF Z=0)
|
||||
ENDM
|
||||
CCIR MACRO ;;AS ABOVE REPEAT UNTIL (B,C) = 0 OR
|
||||
;; (A) = (H,L)
|
||||
DB 0EDH,0B1H
|
||||
ENDM
|
||||
CCD MACRO ;;COMPARE ACC WITH MEMORY AT (H,L)
|
||||
DB 0EDH,0A9H ;; DEC H,L DEC B,C
|
||||
ENDM
|
||||
CCDR MACRO ;;AS ABOVE REPEAT UNTIL (BC) = 0 OR
|
||||
;; (A) = (H,L)
|
||||
DB 0EDH,0B9H
|
||||
ENDM
|
||||
ADDX MACRO ?D ;;ACC=ACC+CONTENTS OF MEMORY AT (IX+D)
|
||||
@CHK ?D ;; ACC=ACC+((IX+D))
|
||||
DB 0DDH,86H,?D
|
||||
ENDM
|
||||
ADDY MACRO ?D ;;ACC=ACC+((IY+D))
|
||||
@CHK ?D
|
||||
DB 0FDH,86H,?D
|
||||
ENDM
|
||||
ADCX MACRO ?D ;;ACC=ACC+((IX+D))+CARRY
|
||||
@CHK ?D
|
||||
DB 0DDH,8EH,?D
|
||||
ENDM
|
||||
ADCY MACRO ?D ;;ACC=ACC+((IY+D))+CARRY
|
||||
@CHK ?D
|
||||
DB 0FDH,8EH,?D
|
||||
ENDM
|
||||
SUBX MACRO ?D ;;ACC=ACC-((IX+D))
|
||||
@CHK ?D
|
||||
DB 0DDH,96H,?D
|
||||
ENDM
|
||||
SUBY MACRO ?D ;;ACC=ACC-((IY+D))
|
||||
@CHK ?D
|
||||
DB 0FDH,96H,?D
|
||||
ENDM
|
||||
SBCX MACRO ?D ;;ACC=ACC-((IX+D))-BORROW
|
||||
@CHK ?D
|
||||
DB 0DDH,9EH,?D
|
||||
ENDM
|
||||
SBCY MACRO ?D ;;ACC=ACC-((IY+D))-BORROW
|
||||
@CHK ?D
|
||||
DB 0FDH,9EH,?D
|
||||
ENDM
|
||||
ANDX MACRO ?D ;;AND ACC WITH CONTENTS OF MEMORY (IX+D)
|
||||
@CHK ?D
|
||||
DB 0DDH,0A6H,?D
|
||||
ENDM
|
||||
ANDY MACRO ?D ;;AND ACC WITH CONTENTS OF MEMORY (IY+D)
|
||||
@CHK ?D
|
||||
DB 0FDH,0A6H,?D
|
||||
ENDM
|
||||
XORX MACRO ?D ;;EXCLUSIVE OR THE ACC WITH CONTEMTS OF
|
||||
@CHK ?D ;; MEMORY AT (IX+D)
|
||||
DB 0DDH,0AEH,?D
|
||||
ENDM
|
||||
XORY MACRO ?D ;;XOR ACC WITH CONTENTS OF MEMORY (IY+D)
|
||||
@CHK ?D
|
||||
DB 0FDH,0AEH,?D
|
||||
ENDM
|
||||
ORX MACRO ?D ;;OR THE ACC WITH CONTENTS OF MEMORY (IX+D)
|
||||
@CHK ?D
|
||||
DB 0DDH,0B6H,?D
|
||||
ENDM
|
||||
ORY MACRO ?D ;;OR ACC WITH CONTENTS OF MEMORY (IY+D)
|
||||
@CHK ?D
|
||||
DB 0FDH,0B6H,?D
|
||||
ENDM
|
||||
CMPX MACRO ?D ;;COMPARE THE ACC WITH CONTENTS OF MEMORY
|
||||
@CHK ?D ;; AT LOC (IX+D)
|
||||
DB 0DDH,0BEH,?D
|
||||
ENDM
|
||||
CMPY MACRO ?D ;;CMP ACC WITH CONTENTS OF MEMORY (IY+D)
|
||||
@CHK ?D
|
||||
DB 0FDH,0BEH,?D
|
||||
ENDM
|
||||
INRX MACRO ?D ;;INC MEMORY CONTENTS AT (IX+D)
|
||||
@CHK ?D
|
||||
DB 0DDH,34H,?D
|
||||
ENDM
|
||||
INRY MACRO ?D ;;INC MEMORY CONTENTS AT (IY+D)
|
||||
@CHK ?D
|
||||
DB 0FDH,34H,?D
|
||||
ENDM
|
||||
DCRX MACRO ?D ;;DEC MEMORY CONTENTS AT (IX+D)
|
||||
@CHK ?D
|
||||
DB 0DDH,035H,?D
|
||||
ENDM
|
||||
DCRY MACRO ?D ;;DEC MEMORY CONTENTS AT (IY+D)
|
||||
@CHK ?D
|
||||
DB 0FDH,35H,?D
|
||||
ENDM
|
||||
NEG MACRO ;;NEGATE ACC (2'S COMPLEMENT)
|
||||
DB 0EDH,44H
|
||||
ENDM
|
||||
IM0 MACRO ;;SET INTERRUPT MODE #0
|
||||
DB 0EDH,46H
|
||||
ENDM
|
||||
IM1 MACRO ;;SET INTERRUPT MODE #1 (RESTART 0038H)
|
||||
DB 0EDH,56H
|
||||
ENDM
|
||||
IM2 MACRO ;;SET INTERRUPT MODE #2
|
||||
DB 0EDH,5EH ;; RESTART AT LOC (INT REG I)(DEV SUPPLIED)
|
||||
ENDM
|
||||
BC EQU 0
|
||||
DE EQU 2
|
||||
HL EQU 4
|
||||
IX EQU 4
|
||||
IY EQU 4
|
||||
DADC MACRO ?R ;;DOUBLE ADD (H,L)=(H,L)+(RP)+CARRY
|
||||
DB 0EDH,?R*8+4AH
|
||||
ENDM
|
||||
DSBC MACRO ?R ;;DOUBLE SUB (H,L)=(H,L)-(RP)-CARRY
|
||||
DB 0EDH,?R*8+42H
|
||||
ENDM
|
||||
DADX MACRO ?R ;;DOUBLE ADD (IX)=(IX)+(RP)
|
||||
DB 0DDH,?R*8+09H
|
||||
ENDM
|
||||
DADY MACRO ?R ;;DOUBLE ADD (IY)=(IY)+(RP)
|
||||
DB 0FDH,?R*8+09H
|
||||
ENDM
|
||||
INXIX MACRO ;;INC (IX)
|
||||
DB 0DDH,23H
|
||||
ENDM
|
||||
INXIY MACRO ;;INC (IY)
|
||||
DB 0FDH,23H
|
||||
ENDM
|
||||
DCXIX MACRO ;;DEC (IX)
|
||||
DB 0DDH,2BH
|
||||
ENDM
|
||||
DCXIY MACRO ;;DEC (IY)
|
||||
DB 0FDH,2BH
|
||||
ENDM
|
||||
BIT MACRO ?N,?R ;;TEST BIT N IN REG R
|
||||
DB 0CBH,?N*8+?R+40H
|
||||
ENDM
|
||||
SETB MACRO ?N,?R ;;SET BIT N IN REG R
|
||||
DB 0CBH,?N*8+?R+0C0H
|
||||
ENDM
|
||||
RES MACRO ?N,?R ;;RESET BIT N IN REG R
|
||||
DB 0CBH,?N*8+?R+80H
|
||||
ENDM
|
||||
BITX MACRO ?N,?D ;;TEST BIT N IN MEMORY LOC (IX+D)
|
||||
@CHK ?D
|
||||
DB 0DDH,0CBH,?D,?N*8+46H
|
||||
ENDM
|
||||
BITY MACRO ?N,?D ;;TEST BIT N IN MEMORY LOC (IY+D)
|
||||
@CHK ?D
|
||||
DB 0FDH,0CBH,?D,?N*8+46H
|
||||
ENDM
|
||||
SETX MACRO ?N,?D ;;SET BIT N IN MEMORY LOC (IX+D)
|
||||
@CHK ?D
|
||||
DB 0DDH,0CBH,?D,?N*8+0C6H
|
||||
ENDM
|
||||
SETY MACRO ?N,?D ;;SET BIT N IN MEMORY LOC (IY+D)
|
||||
@CHK ?D
|
||||
DB 0FDH,0CBH,?D,?N*8+0C6H
|
||||
ENDM
|
||||
RESX MACRO ?N,?D ;;RESET BIT N IN MEMORY LOC (IX+D)
|
||||
@CHK ?D
|
||||
DB 0DDH,0CBH,?D,?N*8+86H
|
||||
ENDM
|
||||
RESY MACRO ?N,?D ;;RESET BIT N IN MEMORY LOC (IY+D)
|
||||
@CHK ?D
|
||||
DB 0FDH,0CBH,?D,?N*8+86H
|
||||
ENDM
|
||||
JR MACRO ?N ;;JUMP RELATIVE
|
||||
@CHECK ?N
|
||||
DB 18H,?DD
|
||||
ENDM
|
||||
JMPR MACRO ?N ;;JUMP RELATIVE AS ABOVE
|
||||
@CHECK ?N
|
||||
DB 18H,?DD
|
||||
ENDM
|
||||
JRC MACRO ?N ;;JUMP RELATIVE ON CARRY
|
||||
@CHECK ?N
|
||||
DB 38H,?DD
|
||||
ENDM
|
||||
JRNC MACRO ?N ;;JUMP RELATIVE ON NOT CARRY
|
||||
@CHECK ?N
|
||||
DB 30H,?DD
|
||||
ENDM
|
||||
JRZ MACRO ?N ;;JUMP RELATIVE ON ZERO
|
||||
@CHECK ?N
|
||||
DB 28H,?DD
|
||||
ENDM
|
||||
JRNZ MACRO ?N ;;JUMP RELATIVE ON NOT ZERO
|
||||
@CHECK ?N
|
||||
DB 20H,?DD
|
||||
ENDM
|
||||
DJNZ MACRO ?N ;;DEC B AND JUMP RELATIVE ON B NOT ZERO
|
||||
@CHECK ?N
|
||||
DB 10H,?DD
|
||||
ENDM
|
||||
PCIX MACRO ;;MOV IX INTO PROGRAM COUNTER
|
||||
DB 0DDH,0E9H
|
||||
ENDM
|
||||
PCIY MACRO ;;MOV IY INTO PROGRAM COUNTER
|
||||
DB 0FDH,0E9H
|
||||
ENDM
|
||||
RETI MACRO ;;RETURN FROM INTERRUPT (EI NOT ENABLED)
|
||||
DB 0EDH,4DH
|
||||
ENDM
|
||||
RETN MACRO ;;RETURN FROM NON-MASKABLE INTERRUPT
|
||||
DB 0EDH,45H
|
||||
ENDM
|
||||
RETEI MACRO ;;RETURN FROM INTERRUPT (EI ENABLED)
|
||||
DB EI,0EDH,4DH
|
||||
ENDM
|
||||
INP MACRO ?R ;;GO TO INPUT PORT (SPECIFIED BY REG C)
|
||||
DB 0EDH,?R*8+40H ;; AND LOAD INTO REG R
|
||||
ENDM
|
||||
OUTP MACRO ?R ;;OUTPUT TO PORT (SPECIFIED BY REG C)
|
||||
DB 0EDH,?R*8+41H ;; FROM REG R
|
||||
ENDM
|
||||
INI MACRO ;;LOAD MEMORY (H,L) WITH INPUT PORT
|
||||
DB 0EDH,0A2H ;; (SPECIFIED BY REG C) INC H,L DEC B
|
||||
ENDM
|
||||
INIR MACRO ;;AS ABOVE REPEAT UNTIL B=0
|
||||
DB 0EDH,0B2H
|
||||
ENDM
|
||||
IND MACRO ;;LOAD MEMORY (H,L) WITH INPUT PORT
|
||||
DB 0EDH,0AAH ;; (SPECIFIED BY REG C) DEC H,L DEC B
|
||||
ENDM
|
||||
INDR MACRO ;;AS ABOVE REPEAT UNTIL B=0
|
||||
DB 0EDH,0BAH
|
||||
ENDM
|
||||
OUTI MACRO ;;OUTPUT TO PORT (SPECIFIED BY REG C)
|
||||
DB 0EDH,0A3H ;; FROM MEMORY (H,L) INC H,L DEC B
|
||||
ENDM
|
||||
OUTIR MACRO ;;AS ABOVE REPEAT UNTIL B=0
|
||||
DB 0EDH,0B3H
|
||||
ENDM
|
||||
OUTD MACRO ;;OUTPUT TO PORT (SPECIFIED BY REG C)
|
||||
DB 0EDH,0ABH ;; FROM MEMORY (H,L) DEC H,L DEC B
|
||||
ENDM
|
||||
OUTDR MACRO ;;AS ABOVE REPEAT UNTIL B=0
|
||||
DB 0EDH,0BBH
|
||||
ENDM
|
||||
RLCR MACRO ?R ;;ROTATE LEFT CIRCULAR REG R
|
||||
DB 0CBH, 00H + ?R
|
||||
ENDM
|
||||
RLCX MACRO ?D ;;ROTATE LEFT CIRCULAR CONTENTS OF MEMORY
|
||||
;; AT (IX+D)
|
||||
@CHK ?D
|
||||
DB 0DDH, 0CBH, ?D, 06H
|
||||
ENDM
|
||||
RLCY MACRO ?D ;;ROTATE LEFT CIRCULAR CONTENTS OF MEMORY
|
||||
;; AT (IY+D)
|
||||
@CHK ?D
|
||||
DB 0FDH, 0CBH, ?D, 06H
|
||||
ENDM
|
||||
RALR MACRO ?R ;;ROTATE ARITHMETIC LEFT REG R
|
||||
DB 0CBH, 10H+?R
|
||||
ENDM
|
||||
RALX MACRO ?D ;;ROTATE ARITHMETIC LEFT CONTENTS OF MEMORY
|
||||
;; AT (IX+D)
|
||||
@CHK ?D
|
||||
DB 0DDH, 0CBH, ?D, 16H
|
||||
ENDM
|
||||
RALY MACRO ?D ;;ROTATE ARITHMETIC LEFT CONTENTS OF MEMORY
|
||||
;; AT (IY+D)
|
||||
@CHK ?D
|
||||
DB 0FDH, 0CBH, ?D, 16H
|
||||
ENDM
|
||||
RRCR MACRO ?R ;;ROTATE RIGHT CIRCULAR REG R
|
||||
DB 0CBH, 08H + ?R
|
||||
ENDM
|
||||
RRCX MACRO ?D ;;ROTATE RIGHT CIRCULAR CONTENTS OF MEMORY
|
||||
;; AT (IX+D)
|
||||
@CHK ?D
|
||||
DB 0DDH, 0CBH, ?D, 0EH
|
||||
ENDM
|
||||
RRCY MACRO ?D ;;ROTATE RIGHT CIRCULAR CONTENTS OF MEMORY
|
||||
;; AT (IY+D)
|
||||
@CHK ?D
|
||||
DB 0FDH, 0CBH, ?D, 0EH
|
||||
ENDM
|
||||
RARR MACRO ?R ;;ROTATE ARITHMETIC RIGHT REG R
|
||||
DB 0CBH, 18H + ?R
|
||||
ENDM
|
||||
RARX MACRO ?D ;;ROTATE ARITHMETIC RIGHT CONTENTS OF MEMORY
|
||||
;; AT (IX+D)
|
||||
@CHK ?D
|
||||
DB 0DDH, 0CBH, ?D, 1EH
|
||||
ENDM
|
||||
RARY MACRO ?D ;;ROTATE ARITHMETIC RIGHT CONTENTS OF MEMORY
|
||||
;; AT (IY+D)
|
||||
@CHK ?D
|
||||
DB 0FDH, 0CBH, ?D, 1EH
|
||||
ENDM
|
||||
SLAR MACRO ?R ;;SHIFT LEFT ARITHMETIC REG R
|
||||
DB 0CBH, 20H + ?R
|
||||
ENDM
|
||||
SLAX MACRO ?D ;;SHIFT LEFT ARITHMETIC CONTENTS OF MEMORY
|
||||
;; AT(IX+D)
|
||||
@CHK ?D
|
||||
DB 0DDH, 0CBH, ?D, 26H
|
||||
ENDM
|
||||
SLAY MACRO ?D ;;SHIFT LEFT ARITHMETIC CONTENTS OF MEMORY
|
||||
;; AT (IY+D)
|
||||
@CHK ?D
|
||||
DB 0FDH, 0CBH, ?D, 26H
|
||||
ENDM
|
||||
SRAR MACRO ?R ;;SHIFT RIGHT ARITHMETIC REG R
|
||||
DB 0CBH, 28H+?R
|
||||
ENDM
|
||||
SRAX MACRO ?D ;;SHIFT RIGHT ARITHMETIC CONTENTS OF MEMORY
|
||||
;; AT (IX+D)
|
||||
@CHK ?D
|
||||
DB 0DDH, 0CBH, ?D, 2EH
|
||||
ENDM
|
||||
SRAY MACRO ?D ;;SHIFT RIGHT ARITHMETIC CONTENTS OF MEMORY
|
||||
;; AT (IY+D)
|
||||
@CHK ?D
|
||||
DB 0FDH, 0CBH, ?D, 2EH
|
||||
ENDM
|
||||
SRLR MACRO ?R ;;SHIFT RIGHT LOGICALLY REG R
|
||||
DB 0CBH, 38H + ?R
|
||||
ENDM
|
||||
SRLX MACRO ?D ;;SHIFT RIGHT LOGICALLY CONTENTS OF MEMORY
|
||||
;; AT (IX+D)
|
||||
@CHK ?D
|
||||
DB 0DDH, 0CBH, ?D, 3EH
|
||||
ENDM
|
||||
SRLY MACRO ?D ;;SHIFT RIGHT LOGICALLY CONTENTS OF MEMORY
|
||||
;; AT (IY+D)
|
||||
@CHK ?D
|
||||
DB 0FDH, 0CBH, ?D, 3EH
|
||||
ENDM
|
||||
RLD MACRO ;;ROTATE NIBBLE LEFT & RIGHT BETWEEN ACC
|
||||
DB 0EDH, 6FH ;; AND CONTENTS AT (H,L)
|
||||
ENDM
|
||||
RRD MACRO ;;ROTATE NIBBLE RIGHT & LEFT BETWEEN ACC
|
||||
DB 0EDH, 67H ;; AND CONTENTS AT (H,L)
|
||||
ENDM
|
||||
|
||||
88
CONTRIBUTIONS/MOSS 2.2/readme.1st
Normal file
88
CONTRIBUTIONS/MOSS 2.2/readme.1st
Normal file
@@ -0,0 +1,88 @@
|
||||
|
||||
|
||||
This is the Text Document for MOSS22, the Altair 8800 Monitor Program - MOSS Ver 2.2
|
||||
|
||||
The files contained in folder 8800-Manual are:
|
||||
CCS_2810_Z80_CPU_1980.pdf - Original manual
|
||||
MOSS22.PDF - Monitor Pages - extracted
|
||||
MOSS22.TXT - Text
|
||||
|
||||
The Monitor (MOSS22) is described in detail in Chapter 3 of the Original Manual.
|
||||
|
||||
The appropriate PDF Pages that contain the Monitor Source Code are included in MOSS22.PDF.
|
||||
|
||||
The files contained in folder tif are the *.tif images of the PDF pages to be OCR'd.
|
||||
page1.tif
|
||||
page2.tif
|
||||
page3.tif
|
||||
page4.tif
|
||||
page5.tif
|
||||
page6.tif
|
||||
page7.tif
|
||||
page8.tif
|
||||
page9.tif
|
||||
page10.tif
|
||||
page11.tif
|
||||
page12.tif
|
||||
page13.tif
|
||||
page14.tif
|
||||
page15.tif
|
||||
page16.tif
|
||||
page17.tif
|
||||
page18.tif
|
||||
page19.tif
|
||||
page20.tif
|
||||
page21.tif
|
||||
page22.tif
|
||||
page23.tif
|
||||
page24.tif
|
||||
|
||||
|
||||
Those pages were extracted, converted to tif files (450 DPI) and OCR'd with TextBridge Classic.
|
||||
The Text file was then edited, aligned, and proof read several times to give the MOSS22.ASM file.
|
||||
|
||||
The files contained in folder MOSS22 are:
|
||||
MOSS22.ASM
|
||||
MOSS22.PRN
|
||||
MOSS22.HEX
|
||||
MOSS22.SYM
|
||||
|
||||
|
||||
The files contained in folder Z80LIB are:
|
||||
Z80.LIB
|
||||
Z80.DOC
|
||||
|
||||
The Z80.LIB has to be the file with 9856 Bytes, and needs to be modified so the source assembles properly.
|
||||
The above file, has already been modified.
|
||||
|
||||
References:
|
||||
http://z80cpu.eu/files/archive/roche/Z80LIB.TXT
|
||||
http://www.retroarchive.org/cpm/os/
|
||||
Z80.LIB = 9856 Bytes
|
||||
|
||||
|
||||
The DRI Assemblers and Manuals can be downloaded from:
|
||||
http://www.s100computers.com/Software%20Folder/Assembler%20Collection/Assembler%20Collection.htm
|
||||
|
||||
Copy the following files to B:
|
||||
MAC.COM
|
||||
MOSS22.ASM
|
||||
Z80.LIB
|
||||
Z80.DOC
|
||||
|
||||
Execute the DRI Assembler MAC.COM in CP/M 2.2 with:
|
||||
B:
|
||||
MAC MOSS22.ASM
|
||||
|
||||
It will Build:
|
||||
MOSS22.HEX
|
||||
MOSS22.PRN
|
||||
MOSS22.SYM
|
||||
|
||||
Compare the MOSS22.PRN file with the MOS22.PDF file for identical bytes.
|
||||
|
||||
|
||||
Larry Kraemer & Garry Kraemer
|
||||
|
||||
|
||||
|
||||
90
CONTRIBUTIONS/MOSS 2.2/readme.md
Normal file
90
CONTRIBUTIONS/MOSS 2.2/readme.md
Normal file
@@ -0,0 +1,90 @@
|
||||
Altair 8800 Monitor (MOS Ver 2.2) Source Code, thanks to Larry Kraemer.
|
||||
|
||||
/readme.1st
|
||||
|
||||
This is the Text Document for MOSS22, the Altair 8800 Monitor Program - MOSS Ver 2.2
|
||||
|
||||
The files contained in folder 8800-Manual are:
|
||||
CCS_2810_Z80_CPU_1980.pdf - Original manual
|
||||
MOSS22.PDF - Monitor Pages - extracted
|
||||
MOSS22.TXT - Text
|
||||
|
||||
The Monitor (MOSS22) is described in detail in Chapter 3 of the Original Manual.
|
||||
|
||||
The appropriate PDF Pages that contain the Monitor Source Code are included in MOSS22.PDF.
|
||||
|
||||
The files contained in folder tif are the *.tif images of the PDF pages to be OCR'd.
|
||||
page1.tif
|
||||
page2.tif
|
||||
page3.tif
|
||||
page4.tif
|
||||
page5.tif
|
||||
page6.tif
|
||||
page7.tif
|
||||
page8.tif
|
||||
page9.tif
|
||||
page10.tif
|
||||
page11.tif
|
||||
page12.tif
|
||||
page13.tif
|
||||
page14.tif
|
||||
page15.tif
|
||||
page16.tif
|
||||
page17.tif
|
||||
page18.tif
|
||||
page19.tif
|
||||
page20.tif
|
||||
page21.tif
|
||||
page22.tif
|
||||
page23.tif
|
||||
page24.tif
|
||||
|
||||
|
||||
Those pages were extracted, converted to tif files (450 DPI) and OCR'd with TextBridge Classic.
|
||||
The Text file was then edited, aligned, and proof read several times to give the MOSS22.ASM file.
|
||||
|
||||
The files contained in folder MOSS22 are:
|
||||
MOSS22.ASM
|
||||
MOSS22.PRN
|
||||
MOSS22.HEX
|
||||
MOSS22.SYM
|
||||
|
||||
|
||||
The files contained in folder Z80LIB are:
|
||||
Z80.LIB
|
||||
Z80.DOC
|
||||
|
||||
The Z80.LIB has to be the file with 9856 Bytes, and needs to be modified so the source assembles properly.
|
||||
The above file, has already been modified.
|
||||
|
||||
References:
|
||||
http://z80cpu.eu/files/archive/roche/Z80LIB.TXT
|
||||
http://www.retroarchive.org/cpm/os/
|
||||
Z80.LIB = 9856 Bytes
|
||||
|
||||
|
||||
The DRI Assemblers and Manuals can be downloaded from:
|
||||
http://www.s100computers.com/Software%20Folder/Assembler%20Collection/Assembler%20Collection.htm
|
||||
|
||||
Copy the following files to B:
|
||||
MAC.COM
|
||||
MOSS22.ASM
|
||||
Z80.LIB
|
||||
Z80.DOC
|
||||
|
||||
Execute the DRI Assembler MAC.COM in CP/M 2.2 with:
|
||||
B:
|
||||
MAC MOSS22.ASM
|
||||
|
||||
It will Build:
|
||||
MOSS22.HEX
|
||||
MOSS22.PRN
|
||||
MOSS22.SYM
|
||||
|
||||
Compare the MOSS22.PRN file with the MOS22.PDF file for identical bytes.
|
||||
|
||||
|
||||
Larry Kraemer & Garry Kraemer
|
||||
|
||||
|
||||
|
||||
37
CONTRIBUTIONS/MOSS 2.2/tif/moss22.sh
Normal file
37
CONTRIBUTIONS/MOSS 2.2/tif/moss22.sh
Normal file
@@ -0,0 +1,37 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
#This script will extrace all pages of a PDF to Sequential pages, then convert those PDF
|
||||
#pages to text using TextBridge
|
||||
#
|
||||
#
|
||||
#Larry Kraemer 09-21-2014 Chaffee, MO
|
||||
#
|
||||
#Splitting files
|
||||
#
|
||||
#Splitting PDF files with pdftk was an interesting experience. The burst option breaks a PDF into #multiple files -- one file for each page:
|
||||
#
|
||||
# To test the conversion try these commands: (I have better luck with TextBridge Conversions)
|
||||
# convert -monochrome -density 300 pg_0001.pdf pg001.tif
|
||||
# tesseract pg001.tif pg001 -psm 6
|
||||
# OR Use Textbridge to convert tif files to TXT as spreadsheet or table
|
||||
#
|
||||
#
|
||||
PAGES=24 # set to the number of PDF pages to process
|
||||
SOURCE=MOSS22.pdf # set to the file name of the multipage PDF
|
||||
#OUTPUT=moss22.txt # creates the final "output file"
|
||||
RESOLUTION=400 # set to the resolution the scanner used (the higher, the better)
|
||||
#
|
||||
touch $OUTPUT
|
||||
for i in `seq 1 $PAGES`; do
|
||||
convert -monochrome -density $RESOLUTION $SOURCE\[$(($i - 1 ))\] page$i.tif
|
||||
# tesseract page$i.tif page$i -psm 6
|
||||
# cat $OUTPUT page$i.txt > temp.txt
|
||||
# rm $OUTPUT
|
||||
# rm page$i.tif
|
||||
# rm page$i.txt
|
||||
# mv temp.txt $OUTPUT
|
||||
#
|
||||
# OR Use Textbridge to convert tif files to TXT as spreadsheet or table
|
||||
#
|
||||
done
|
||||
|
||||
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page1.tif
Normal file
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page1.tif
Normal file
Binary file not shown.
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page10.tif
Normal file
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page10.tif
Normal file
Binary file not shown.
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page11.tif
Normal file
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page11.tif
Normal file
Binary file not shown.
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page12.tif
Normal file
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page12.tif
Normal file
Binary file not shown.
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page13.tif
Normal file
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page13.tif
Normal file
Binary file not shown.
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page14.tif
Normal file
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page14.tif
Normal file
Binary file not shown.
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page15.tif
Normal file
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page15.tif
Normal file
Binary file not shown.
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page16.tif
Normal file
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page16.tif
Normal file
Binary file not shown.
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page17.tif
Normal file
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page17.tif
Normal file
Binary file not shown.
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page18.tif
Normal file
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page18.tif
Normal file
Binary file not shown.
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page19.tif
Normal file
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page19.tif
Normal file
Binary file not shown.
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page2.tif
Normal file
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page2.tif
Normal file
Binary file not shown.
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page20.tif
Normal file
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page20.tif
Normal file
Binary file not shown.
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page21.tif
Normal file
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page21.tif
Normal file
Binary file not shown.
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page22.tif
Normal file
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page22.tif
Normal file
Binary file not shown.
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page23.tif
Normal file
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page23.tif
Normal file
Binary file not shown.
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page24.tif
Normal file
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page24.tif
Normal file
Binary file not shown.
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page3.tif
Normal file
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page3.tif
Normal file
Binary file not shown.
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page4.tif
Normal file
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page4.tif
Normal file
Binary file not shown.
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page5.tif
Normal file
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page5.tif
Normal file
Binary file not shown.
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page6.tif
Normal file
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page6.tif
Normal file
Binary file not shown.
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page7.tif
Normal file
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page7.tif
Normal file
Binary file not shown.
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page8.tif
Normal file
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page8.tif
Normal file
Binary file not shown.
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page9.tif
Normal file
BIN
CONTRIBUTIONS/MOSS 2.2/tif/page9.tif
Normal file
Binary file not shown.
88
CONTRIBUTIONS/cpm-handbook/READ-ME.txt
Normal file
88
CONTRIBUTIONS/cpm-handbook/READ-ME.txt
Normal file
@@ -0,0 +1,88 @@
|
||||
[READ.ME]
|
||||
The Programmer's CP/M Handbook Source Code Examples
|
||||
Version 1.0 August 18, 1983
|
||||
(c) 1983 Johnson-Laird Inc.
|
||||
|
||||
We have tried to include as many of the examples from the CP/M
|
||||
Programmer's Handbook as was possible to fit onto 2 single-sided
|
||||
single-density diskettes (or alternately, 1 single-density
|
||||
double-sided "flippy" diskette). Our original intention was to
|
||||
include the source code for every figure in the book as well as all
|
||||
the example listings in Chapter 5. Since this proved to be impossible
|
||||
to fit onto two diskettes, we have chosen those figures and examples
|
||||
which we felt would be the most useful. The only major omission is
|
||||
Figure 9-4 which deals with bad sector management.
|
||||
|
||||
We have fixed one bug and added one line to Figure 8-10. This is
|
||||
noted in the source code. The lines which were left out in the book
|
||||
after page 261 are also included. You may notice some minor
|
||||
differences in capitalization, indentation, etc. in the comments where
|
||||
we have not included changes made in copyediting.
|
||||
|
||||
We would appreciate hearing from you, especially about any bugs,
|
||||
typos, other horrible goofs, suggestions for improvements.
|
||||
|
||||
Contents of Diskette No 1
|
||||
|
||||
Filename Page No. Figure Title
|
||||
|
||||
FIG5-2.ASM 70 Equates for BDOS function code numbers
|
||||
FIG5-3.ASM 74 Write console byte example, output null-byte
|
||||
terminated message from specified address
|
||||
FIG5-4.ASM 74 Write console byte example, output null-byte
|
||||
terminated message following call to subroutine
|
||||
FIG5-5.ASM 76 Read line from reader device
|
||||
FIG5-6.ASM 78 Write line to punch device
|
||||
FIG5-7.ASM 79 Write line to list device
|
||||
FIG5-8.ASM 81 Read/Write string from/to console using raw I/O
|
||||
FIG5-10.ASM 86 IOBYTE equates
|
||||
FIG5-11.ASM 87 Simple terminal emulator
|
||||
FIG5-12.ASM 89 Display $-terminated message on console
|
||||
FIG5-13.ASM 92 Read console string for keyboard options
|
||||
FIG5-14.ASM 95 Determine the CP/M version number
|
||||
FIG5-15.ASM 96 Reset requested disk drive
|
||||
FIG5-16.ASM 100 Open file request
|
||||
FIG5-17.ASM 104 Search first/next calls for ambiguous filename
|
||||
FIG5-18.ASM 110 Read next character from sequential disk file
|
||||
FIG5-19.ASM 113 Write next character to sequential disk file
|
||||
FIG5-20.ASM 115 Create file request
|
||||
FIG5-21.ASM 117 Rename file request
|
||||
FIG5-22.ASM 122 Set file attributes
|
||||
FIG5-23.ASM 123 Get file attributes
|
||||
FIG5-24.ASM 126 Accessing disk parameter block data
|
||||
FUNCTN33.ASM 131 Example for function 33, read random
|
||||
FIG5-25.ASM 135 Create random file
|
||||
FIG5-26.ASM 136 Read/write variable length records randomly
|
||||
FIG6-4.ASM 159 Simple BIOS listing
|
||||
FIG7-5.ASM 191 Example PUTCP/M
|
||||
FIG7-7.ASM 198 Example CP/M cold bootstrap loader
|
||||
FIG8-6.ASM 226 Device table equates
|
||||
FIG10-5.ASM 363 Testbed for real time clock driver in the BIOS
|
||||
FIG10-6.ASM 365 Testbed for disk I/O drivers in the BIOS
|
||||
ERASE.C 410 Figure 11-3, requests confirmation before erasing
|
||||
UNERASE.C 412 Figure 11-4, "revives" erased files
|
||||
FIND.C 417 Figure 11-5, locates specific files or groups of files
|
||||
SPACE.C 420 Figure 11-6, displays how much disk storage is used
|
||||
or available
|
||||
MOVE.C 424 Figure 11-7, "moves" files from one user to another
|
||||
MAKE.C 428 Figure 11-8, makes files "invisible" and protected
|
||||
or makes them "visible," accessible and unprotected
|
||||
SPEED.C 431 Figure 11-9, sets the baud rate for a specific device
|
||||
PROTOCOL.C 435 Figure 11-10, sets the protocol governing input and output
|
||||
of a specified serial device
|
||||
ASSIGN.C 439 Figure 11-11, assigns a logical devices input and output
|
||||
to two or more physical devices
|
||||
DATE.C 443 Figure 11-12, makes the current date part of the system
|
||||
TIME.C 444 Figure 11-13, makes the current time part of the system
|
||||
FUNKEY.C 446 Figure 11-14, sets the character strings associated with
|
||||
specific function keys
|
||||
|
||||
Contents of Diskette 2
|
||||
|
||||
FIG8-10.ASM 237 Enhanced BIOS listing
|
||||
FIG9-5.ASM 312 User-friendly disk error processor
|
||||
FIG10-2.ASM 331 Debug subroutines
|
||||
FIG10-4.ASM 355 Testbed for character I/O drivers
|
||||
LIBRARY.C 372 Figure 11-1, commonly used functions in C
|
||||
LIBRARY.H 390 Figure 11-2, code to be included at the beginning of
|
||||
any program that calls LIBRARY functions in Figure 11-1
|
||||
121
CONTRIBUTIONS/cpm-handbook/README.MARKDOWN
Normal file
121
CONTRIBUTIONS/cpm-handbook/README.MARKDOWN
Normal file
@@ -0,0 +1,121 @@
|
||||
Source code examples from "The Programmers CP/M Handbook": by Andy Johnson-Laird, copyright 1983 by Osborne/McGraw-Hill. Andy has given his permission to share this code for non-commercial use.
|
||||
|
||||
/READ-ME.txt
|
||||
|
||||
[READ.ME]
|
||||
The Programmer's CP/M Handbook Source Code Examples
|
||||
Version 1.0 August 18, 1983
|
||||
(c) 1983 Johnson-Laird Inc.
|
||||
|
||||
We have tried to include as many of the examples from the CP/M
|
||||
Programmer's Handbook as was possible to fit onto 2 single-sided
|
||||
single-density diskettes (or alternately, 1 single-density
|
||||
double-sided "flippy" diskette). Our original intention was to
|
||||
include the source code for every figure in the book as well as all
|
||||
the example listings in Chapter 5. Since this proved to be impossible
|
||||
to fit onto two diskettes, we have chosen those figures and examples
|
||||
which we felt would be the most useful. The only major omission is
|
||||
Figure 9-4 which deals with bad sector management.
|
||||
|
||||
We have fixed one bug and added one line to Figure 8-10. This is
|
||||
noted in the source code. The lines which were left out in the book
|
||||
after page 261 are also included. You may notice some minor
|
||||
differences in capitalization, indentation, etc. in the comments where
|
||||
we have not included changes made in copyediting.
|
||||
|
||||
We would appreciate hearing from you, especially about any bugs,
|
||||
typos, other horrible goofs, suggestions for improvements.
|
||||
|
||||
Contents of Diskette No 1
|
||||
|
||||
Filename Page No. Figure Title
|
||||
|
||||
FIG5-2.ASM 70 Equates for BDOS function code numbers
|
||||
FIG5-3.ASM 74 Write console byte example, output null-byte
|
||||
terminated message from specified address
|
||||
FIG5-4.ASM 74 Write console byte example, output null-byte
|
||||
terminated message following call to subroutine
|
||||
FIG5-5.ASM 76 Read line from reader device
|
||||
FIG5-6.ASM 78 Write line to punch device
|
||||
FIG5-7.ASM 79 Write line to list device
|
||||
FIG5-8.ASM 81 Read/Write string from/to console using raw I/O
|
||||
FIG5-10.ASM 86 IOBYTE equates
|
||||
FIG5-11.ASM 87 Simple terminal emulator
|
||||
FIG5-12.ASM 89 Display $-terminated message on console
|
||||
FIG5-13.ASM 92 Read console string for keyboard options
|
||||
FIG5-14.ASM 95 Determine the CP/M version number
|
||||
FIG5-15.ASM 96 Reset requested disk drive
|
||||
FIG5-16.ASM 100 Open file request
|
||||
FIG5-17.ASM 104 Search first/next calls for ambiguous filename
|
||||
FIG5-18.ASM 110 Read next character from sequential disk file
|
||||
FIG5-19.ASM 113 Write next character to sequential disk file
|
||||
FIG5-20.ASM 115 Create file request
|
||||
FIG5-21.ASM 117 Rename file request
|
||||
FIG5-22.ASM 122 Set file attributes
|
||||
FIG5-23.ASM 123 Get file attributes
|
||||
FIG5-24.ASM 126 Accessing disk parameter block data
|
||||
FUNCTN33.ASM 131 Example for function 33, read random
|
||||
FIG5-25.ASM 135 Create random file
|
||||
FIG5-26.ASM 136 Read/write variable length records randomly
|
||||
FIG6-4.ASM 159 Simple BIOS listing
|
||||
FIG7-5.ASM 191 Example PUTCP/M
|
||||
FIG7-7.ASM 198 Example CP/M cold bootstrap loader
|
||||
FIG8-6.ASM 226 Device table equates
|
||||
FIG10-5.ASM 363 Testbed for real time clock driver in the BIOS
|
||||
FIG10-6.ASM 365 Testbed for disk I/O drivers in the BIOS
|
||||
ERASE.C 410 Figure 11-3, requests confirmation before erasing
|
||||
UNERASE.C 412 Figure 11-4, "revives" erased files
|
||||
FIND.C 417 Figure 11-5, locates specific files or groups of files
|
||||
SPACE.C 420 Figure 11-6, displays how much disk storage is used
|
||||
or available
|
||||
MOVE.C 424 Figure 11-7, "moves" files from one user to another
|
||||
MAKE.C 428 Figure 11-8, makes files "invisible" and protected
|
||||
or makes them "visible," accessible and unprotected
|
||||
SPEED.C 431 Figure 11-9, sets the baud rate for a specific device
|
||||
PROTOCOL.C 435 Figure 11-10, sets the protocol governing input and output
|
||||
of a specified serial device
|
||||
ASSIGN.C 439 Figure 11-11, assigns a logical devices input and output
|
||||
to two or more physical devices
|
||||
DATE.C 443 Figure 11-12, makes the current date part of the system
|
||||
TIME.C 444 Figure 11-13, makes the current time part of the system
|
||||
FUNKEY.C 446 Figure 11-14, sets the character strings associated with
|
||||
specific function keys
|
||||
|
||||
Contents of Diskette 2
|
||||
|
||||
FIG8-10.ASM 237 Enhanced BIOS listing
|
||||
FIG9-5.ASM 312 User-friendly disk error processor
|
||||
FIG10-2.ASM 331 Debug subroutines
|
||||
FIG10-4.ASM 355 Testbed for character I/O drivers
|
||||
LIBRARY.C 372 Figure 11-1, commonly used functions in C
|
||||
LIBRARY.H 390 Figure 11-2, code to be included at the beginning of
|
||||
any program that calls LIBRARY functions in Figure 11-1
|
||||
|
||||
|
||||
|
||||
|
||||
/_dedication.txt
|
||||
|
||||
The included files are the source code examples from Andy Johnson-Laird's book, "The Programmers CP/M Handbook", copyright 1983 by Osborne/McGraw-Hill.
|
||||
|
||||
Andy has given his permission to share this code for non-commercial use and asked that the following information be included with this distribution -
|
||||
|
||||
*******************************************
|
||||
|
||||
Please give me credit for the code.
|
||||
|
||||
You might even consider putting in a two line tribute to the late Gary Kildall.
|
||||
|
||||
Andy has requested that those who use this code pause to consider where we would
|
||||
be if the late Gary Kildall, a pioneer's pioneer, had not taken the time to write CP/M.
|
||||
|
||||
If you want to know the *real* story, I can recommend the book "They Made America" by Sir Harold Evans. It will tell you just how significant Gary's work was, and how Mr. Gates got to where he is.
|
||||
The second edition has a far more complete story.
|
||||
|
||||
Regards
|
||||
Andy
|
||||
|
||||
********************************************
|
||||
|
||||
Posted 10/8/07
|
||||
Jack Rubin
|
||||
23
CONTRIBUTIONS/cpm-handbook/_dedication.txt
Normal file
23
CONTRIBUTIONS/cpm-handbook/_dedication.txt
Normal file
@@ -0,0 +1,23 @@
|
||||
The included files are the source code examples from Andy Johnson-Laird's book, "The Programmers CP/M Handbook", copyright 1983 by Osborne/McGraw-Hill.
|
||||
|
||||
Andy has given his permission to share this code for non-commercial use and asked that the following information be included with this distribution -
|
||||
|
||||
*******************************************
|
||||
|
||||
Please give me credit for the code.
|
||||
|
||||
You might even consider putting in a two line tribute to the late Gary Kildall.
|
||||
|
||||
Andy has requested that those who use this code pause to consider where we would
|
||||
be if the late Gary Kildall, a pioneer's pioneer, had not taken the time to write CP/M.
|
||||
|
||||
If you want to know the *real* story, I can recommend the book "They Made America" by Sir Harold Evans. It will tell you just how significant Gary's work was, and how Mr. Gates got to where he is.
|
||||
The second edition has a far more complete story.
|
||||
|
||||
Regards
|
||||
Andy
|
||||
|
||||
********************************************
|
||||
|
||||
Posted 10/8/07
|
||||
Jack Rubin
|
||||
230
CONTRIBUTIONS/cpm-handbook/cpmsrc/ASSIGN.C
Normal file
230
CONTRIBUTIONS/cpm-handbook/cpmsrc/ASSIGN.C
Normal file
@@ -0,0 +1,230 @@
|
||||
#define VN "\nASSIGN Vn 1.0 02/17/83"
|
||||
|
||||
#include <LIBRARY.H>
|
||||
|
||||
struct _ct ct_pdev[MAXPDEV + 2]; /* physical device table */
|
||||
|
||||
|
||||
/* names of logical devices */
|
||||
#define LN_C "CONSOLE"
|
||||
#define LN_A "AUXILIARY"
|
||||
#define LN_L "LIST"
|
||||
struct _ct ct_ldev[4]; /* logical device table */
|
||||
|
||||
struct _ct ct_io[3]; /* input, output */
|
||||
|
||||
/* parameters on the command line */
|
||||
#define LDEV argv[1] /* logical device */
|
||||
#define IO argv[2] /* input/output */
|
||||
|
||||
|
||||
main(argc,argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
|
||||
printf(VN); /* display signon message */
|
||||
setup(); /* setup code tables */
|
||||
chk_use(argc); /* check correct usage */
|
||||
|
||||
/* check if request to show current settings */
|
||||
if (usstrcmp("SHOW",argv[1]))
|
||||
{ /* no, assume a set is required */
|
||||
/* NOTE : the number of physical devices to
|
||||
process is given by argc -3 */
|
||||
set_assign(get_ldev(LDEV),get_io(IO),argc - 3,argv);
|
||||
}
|
||||
show_assign();
|
||||
|
||||
}
|
||||
|
||||
setup() /* setup the code tables for this program */
|
||||
{
|
||||
/* initialize the physical device table */
|
||||
ct_init(ct_pdev[0],0,PN_T); /* terminal */
|
||||
ct_init(ct_pdev[1],1,PN_P); /* printer */
|
||||
ct_init(ct_pdev[2],2,PN_M); /* modem */
|
||||
ct_init(ct_pdev[3],CT_SNF,"*"); /* terminator */
|
||||
|
||||
/* initialize the logical device table */
|
||||
ct_init(ct_ldev[0],0,LN_C); /* terminal */
|
||||
ct_init(ct_ldev[1],1,LN_A); /* auxiliary */
|
||||
ct_init(ct_ldev[2],2,LN_L); /* list */
|
||||
ct_init(ct_ldev[3],CT_SNF,"*"); /* terminator */
|
||||
|
||||
/* initialize the input/output table */
|
||||
ct_init(ct_io[0],0,"INPUT");
|
||||
ct_init(ct_io[1],1,"OUTPUT");
|
||||
ct_init(ct_io[2],CT_SNF,"*"); /* terminator */
|
||||
|
||||
}
|
||||
|
||||
unsigned
|
||||
get_ldev(pldev) /* get logical device */
|
||||
/* This function returns the logical device code
|
||||
specified by the user in the command line. */
|
||||
char *pldev; /* pointer to character string */
|
||||
{
|
||||
unsigned retval; /* return value */
|
||||
retval = ct_parc(ct_ldev,pldev); /* get code for ASCII string */
|
||||
if (retval == CT_SNF) /* if string not found */
|
||||
{
|
||||
printf("\n\007Logical Device '%s' is invalid or ambiguous.",
|
||||
pldev);
|
||||
printf("\nLegal Logical Devices are : ");
|
||||
ct_disps(ct_ldev); /* display all values */
|
||||
exit();
|
||||
}
|
||||
return retval; /* return code */
|
||||
}
|
||||
|
||||
unsigned
|
||||
get_io(pio) /* get input/output parameter */
|
||||
char *pio; /* pointer to character string */
|
||||
{
|
||||
unsigned retval; /* return value */
|
||||
|
||||
retval = ct_parc(ct_io,pio); /* get code for ASCII string */
|
||||
if (retval == CT_SNF) /* if string not found */
|
||||
{
|
||||
printf("\n\007Input/Output direction '%s' is invalid or ambiguous.",
|
||||
pio);
|
||||
printf("\nLegal values are : ");
|
||||
ct_disps(ct_io); /* display all values */
|
||||
exit();
|
||||
}
|
||||
return retval; /* return code */
|
||||
}
|
||||
|
||||
set_assign(ldevc,output,argc,argv) /* set assignment (i/o redirection) */
|
||||
int ldevc; /* logical device code */
|
||||
int output; /* i/o redirection code */
|
||||
int argc; /* count of arguments to process */
|
||||
char *argv[]; /* replica of parameter to main function */
|
||||
{
|
||||
unsigned *redir; /* pointer to redirection word */
|
||||
int pdevc; /* physical device code */
|
||||
unsigned rd_val; /* redirection value */
|
||||
|
||||
/* get the address of the i/o redirection word.
|
||||
this code assumes that get_cba code values
|
||||
are ordered :
|
||||
Device #0, Input & Output
|
||||
Device #1, Input & Output
|
||||
Device #2, Input & Output.
|
||||
the get_cba code is computed by multiplying the
|
||||
logical device code * 2 (that is, shift left 1)
|
||||
and added onto the code for Device #0, Input.
|
||||
then the output variable (0 = Input, 1 = Output)
|
||||
is added on. */
|
||||
redir = get_cba(CB_CI + (ldevc << 1) + output);
|
||||
|
||||
rd_val = 0; /* initialize redirection value */
|
||||
|
||||
/* for output, assignment can be made to several physical
|
||||
devices, so this code may be executed several times. */
|
||||
do
|
||||
{
|
||||
/* get code for ASCII string */
|
||||
/* NOTE : the physical device parameters start
|
||||
with parameter #3 (argv[3]). However argc
|
||||
is a decreasing count of the number of physical
|
||||
devices to be processed - therefore argc + 2
|
||||
causes them to be processed in reverse order
|
||||
(i.e. from right to left on the command line) */
|
||||
|
||||
pdevc = ct_parc(ct_pdev,argv[argc + 2]);
|
||||
|
||||
if (pdevc == CT_SNF) /* if string not found */
|
||||
{
|
||||
printf("\n\007Physical Device '%s' is invalid or ambiguous.",
|
||||
argv[argc + 2]);
|
||||
printf("\nLegal Physical Devices are : ");
|
||||
ct_disps(ct_pdev); /* display all values */
|
||||
exit();
|
||||
}
|
||||
/* repeat this loop for as long as there are
|
||||
more parameters (for output only) */
|
||||
else
|
||||
{
|
||||
/* build new redirection value by OR'ing in
|
||||
a 1-bit shifted left pdevc places. */
|
||||
rd_val |= (1 << pdevc);
|
||||
}
|
||||
} while (--argc && output);
|
||||
|
||||
*redir = rd_val; /* set the value into the config. block */
|
||||
}
|
||||
|
||||
show_assign() /* show current baud rate */
|
||||
{
|
||||
int rd_code; /* redirection code for get_cba */
|
||||
int ldevn; /* logical device number */
|
||||
int pdevn; /* physical device number */
|
||||
unsigned rd_val; /* re-direction value */
|
||||
unsigned *prd_val; /* pointer to the redirection value */
|
||||
|
||||
/* Note : the respective codes for accessing the redirection values
|
||||
via the get_cba (get configuration block address) function are:
|
||||
Device #0 Console Input - 5
|
||||
Device #0 Console Output - 6
|
||||
Device #1 Auxiliary Input - 7
|
||||
Device #1 Auxiliary Output - 8
|
||||
Device #2 List Input - 9
|
||||
Device #2 List Output - 10
|
||||
|
||||
This function uses this mathematical relationship. */
|
||||
|
||||
printf("\nCurrent Device Assignments are :");
|
||||
|
||||
|
||||
/* for all get_cba codes */
|
||||
for (rd_code = CB_CI; rd_code <= CB_LO; rd_code++)
|
||||
{
|
||||
/* set pointer to redirection value */
|
||||
prd_val = get_cba(rd_code);
|
||||
/* get the input redirection value */
|
||||
rd_val = *prd_val; /* this also performs byte-reversal */
|
||||
|
||||
/* display device name. rd_code is converted to a
|
||||
device number by subtracting the first code number
|
||||
from it and dividing by 2 (shift right one place).
|
||||
the input/output direction is derived from the
|
||||
least significant bit of the rd_code. */
|
||||
|
||||
printf("\n\t%s %s is assigned to - ",
|
||||
ct_strc(ct_ldev,(rd_code - CB_CI) >> 1),
|
||||
ct_strc(ct_io,((rd_code & 0x01) ^ 1)));
|
||||
|
||||
/* for all physical devices */
|
||||
for (pdevn = 0; pdevn < 16; pdevn++)
|
||||
{
|
||||
/* check if current physical device is assigned
|
||||
by ANDing with a 1-bit shifted left pdevn times */
|
||||
if (rd_val & (1 << pdevn)) /* is device active */
|
||||
{ /* display physical device name */
|
||||
printf(" %s",ct_strc(ct_pdev,pdevn) );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
chk_use(argc) /* check for correct usage */
|
||||
int argc; /* argument count on commmand line */
|
||||
{
|
||||
if (argc == 1)
|
||||
{
|
||||
printf("\nASSIGN sets the Input/Output redirection.");
|
||||
printf("\n\tASSIGN logical-device INPUT physical-device");
|
||||
printf("\n\tASSIGN logical-device OUTPUT physical-dev1 {phy_dev2..}");
|
||||
printf("\n\tASSIGN SHOW (to show current assignments)");
|
||||
printf("\n\nLegal logical devices are :");
|
||||
ct_disps(ct_ldev);
|
||||
printf("\nLegal physical devices are :");
|
||||
ct_disps(ct_pdev);
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
79
CONTRIBUTIONS/cpm-handbook/cpmsrc/DATE.C
Normal file
79
CONTRIBUTIONS/cpm-handbook/cpmsrc/DATE.C
Normal file
@@ -0,0 +1,79 @@
|
||||
#define VN "\nDATE Vn 1.0 02/18/83"
|
||||
/* This utility accepts the current date from the command tail
|
||||
validates it, and set the internal system date in the BIOS.
|
||||
Alternatively, it can be requested just to display the current
|
||||
system date. */
|
||||
|
||||
#include <LIBRARY.H>
|
||||
|
||||
char *date; /* pointer to the date in the config. block */
|
||||
char *date_flag; /* pointer to date set flag */
|
||||
int mm,dd,yy; /* variables to hold month, day, year */
|
||||
int mcount; /* match count of numeric values entered */
|
||||
int count; /* count used to add leading 0's to date */
|
||||
|
||||
main(argc,argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
printf(VN); /* display signon message */
|
||||
date = get_cba(CB_DATE); /* set pointer to date */
|
||||
date_flag = get_cba(CB_DTFLAGS); /* set pointer to "date set" flag */
|
||||
|
||||
if (argc != 2) /* check if help requested (or needed) */
|
||||
show_use(); /* display correct usage and exit */
|
||||
|
||||
if (usstrcmp("SHOW",argv[1])) /* check if not SHOW option */
|
||||
{
|
||||
/* convert specified time into month, day, year */
|
||||
mcount = sscanf(argv[1],"%d/%d/%d",&mm,&dd,&yy);
|
||||
if (mcount != 3) /* input not numeric */
|
||||
show_use(); /* display correct usage and exit */
|
||||
|
||||
/* NOTE : The following validity checking is VERY
|
||||
simplistic - this could be expanded to accomodate
|
||||
more context-sensitive checking, days in the month,
|
||||
leap years, etc. */
|
||||
if (mm > 12 || mm < 1) /* check valid month, day, year */
|
||||
{
|
||||
printf("\nMonth = %d is illegal.",mm);
|
||||
show_use(); /* display correct usage and exit */
|
||||
}
|
||||
if (dd > 31 || dd < 1)
|
||||
{
|
||||
printf("\nDay = %d is illegal.",dd);
|
||||
show_use(); /* display correct usage and exit */
|
||||
}
|
||||
if (yy > 90 || yy < 83) /* <=== NOTE ! */
|
||||
{
|
||||
printf("\nYear = %d is illegal.",yy);
|
||||
show_use(); /* display correct usage and exit */
|
||||
}
|
||||
|
||||
/* convert integers back into a formatted string */
|
||||
sprintf(date,"%2d/%2d/%2d",mm,dd,yy);
|
||||
date[8] = 0x0A; /* terminate with line feed */
|
||||
date[9] = '\0'; /* new string terminator */
|
||||
|
||||
/* change " 1/ 2/ 3" into "01/02/03" */
|
||||
for (count = 0; count < 7; count+=3)
|
||||
{
|
||||
if (date[count] == ' ')
|
||||
date[count] = '0';
|
||||
}
|
||||
|
||||
/* turn flag on to indicate that the user has set the date */
|
||||
*date_flag |= DATE_SET;
|
||||
}
|
||||
printf("\n\tCurrent Date is %s",date);
|
||||
}
|
||||
|
||||
show_use() /* display correct usage and exit */
|
||||
{
|
||||
printf("\nDATE sets the system date. Usage is :");
|
||||
printf("\n\tDATE mm/dd/yy");
|
||||
printf("\n\tDATE SHOW (to display current date)\n");
|
||||
exit();
|
||||
}
|
||||
|
||||
|
||||
107
CONTRIBUTIONS/cpm-handbook/cpmsrc/ERASE.C
Normal file
107
CONTRIBUTIONS/cpm-handbook/cpmsrc/ERASE.C
Normal file
@@ -0,0 +1,107 @@
|
||||
#define VN "1.0 02/24/83"
|
||||
/* ERASE
|
||||
This utility erases the specified file(s). It performs a logical
|
||||
erasure by using a BDOS Delete function. */
|
||||
|
||||
#include <LIBRARY.H>
|
||||
|
||||
struct _fcb amb_fcb; /* ambiguous name file control block */
|
||||
struct _fcb fcb; /* used for BDOS Search Functions */
|
||||
|
||||
char file_name[20]; /* formatted for display : d:FILENAME.TYP */
|
||||
short cur_disk; /* current logical disk at start of program */
|
||||
/* ERASE saves up the FCB's of the all the
|
||||
files that need to be erased in the
|
||||
following array. */
|
||||
#define MAXERA 1024
|
||||
struct _fcb era_fcb[MAXERA];
|
||||
int ecount; /* count of number of files to be erased */
|
||||
int count; /* used to access era_fcb during erasing */
|
||||
|
||||
main(argc,argv)
|
||||
short argc; /* argument count */
|
||||
char *argv[]; /* argument vector (pointer to an array of chars) */
|
||||
{
|
||||
|
||||
printf("\nERASE Version %s (Library %s)",VN,LIBVN);
|
||||
chk_use(argc); /* check usage */
|
||||
cur_disk = bdos(GETDISK); /* get current default disk */
|
||||
|
||||
ecount = 0; /* initialize count of files to erase */
|
||||
|
||||
setfcb(amb_fcb,argv[1]); /* set ambiguous file name */
|
||||
if (amb_fcb.fcb_disk) /* check if default disk to be used */
|
||||
{
|
||||
bdos(SETDISK,amb_fcb.fcb_disk + 1); /* set to specified disk */
|
||||
}
|
||||
|
||||
/* convert ambiguous file name for output */
|
||||
conv_fname(amb_fcb,file_name);
|
||||
printf("\n\nSearching for file(s) matching %s.",file_name);
|
||||
|
||||
/* set the file control block to indicate a "first" search */
|
||||
fcb.fcb_disk |= 0x80; /* OR in the ms bit */
|
||||
|
||||
/* while not at the end of the directory, set the FCB
|
||||
to the next name that matches */
|
||||
while(get_nfn(amb_fcb,fcb))
|
||||
{
|
||||
conv_fname(fcb,file_name);
|
||||
/* ask whether to erase file or not */
|
||||
printf("\n\tErase %s y/n? ",file_name);
|
||||
if (toupper(getchar()) == 'Y')
|
||||
{
|
||||
printf(" <== Will be Erased!");
|
||||
/* add current fcb to array of fcb's */
|
||||
movmem(fcb,&era_fcb[ecount++],FCBSIZE);
|
||||
/* check that the table is not full */
|
||||
if (ecount == MAXERA)
|
||||
{
|
||||
printf("\nWarning : Internal Table now full. No more files can be erased");
|
||||
printf("\n until those already specified have been erased.");
|
||||
break; /* break out of while loop */
|
||||
}
|
||||
}
|
||||
} /* all directory entries processed */
|
||||
|
||||
if (ecount)
|
||||
printf("\n\nErasing files now...");
|
||||
|
||||
/* now process each fcb in the array, erasing the files */
|
||||
for (count = 0; /* starting with the first file in the array */
|
||||
count < ecount; /* until all active entries processed */
|
||||
count++) /* move to next fcb */
|
||||
{
|
||||
conv_fname(&era_fcb[count],file_name);
|
||||
if (bdos(DELETEF,&era_fcb[count]) == -1) /* error? */
|
||||
printf("\n\007Error trying to erase %s",file_name);
|
||||
else /* file erased */
|
||||
printf("\n\tFile %s erased.",file_name);
|
||||
}
|
||||
bdos(SETDISK,cur_disk); /* reset to current disk */
|
||||
}
|
||||
|
||||
|
||||
chk_use(argc) /* check usage */
|
||||
/* This function checks that the correct number of
|
||||
parameters has been specified, outputting instructions
|
||||
if not. */
|
||||
|
||||
/* Entry Parameter */
|
||||
int argc; /* Count of the number of arguments on the command line */
|
||||
{
|
||||
|
||||
/* The minimum value of argc is 1 (for the program name itself),
|
||||
so argc is always one greater than the number of parameters
|
||||
on the command line */
|
||||
|
||||
if (argc != 2)
|
||||
{
|
||||
printf("\nUsage :");
|
||||
printf("\n\tERASE {d:}file_name.typ");
|
||||
exit();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
1423
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG10-2.ASM
Normal file
1423
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG10-2.ASM
Normal file
File diff suppressed because it is too large
Load Diff
95
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG10-4.ASM
Normal file
95
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG10-4.ASM
Normal file
@@ -0,0 +1,95 @@
|
||||
; Figure 10-4
|
||||
;
|
||||
; Testbed for Character I/O drivers in the BIOS.
|
||||
;
|
||||
; The complete source file consists of three components:
|
||||
;
|
||||
; 1. The testbed code shown here.
|
||||
; 2. The Character I/O drivers destined for the BIOS.
|
||||
; 3. The debug package shown in Figure 10-2.
|
||||
;
|
||||
TRUE EQU 0FFFFH
|
||||
FALSE EQU NOT TRUE
|
||||
|
||||
DEBUG EQU TRUE ;For conditional assembly of RST
|
||||
; instructions in place of IN and
|
||||
; OUT instructions in the drivers.
|
||||
RST6 EQU 30H ;Use RST 6 for fake incoming character
|
||||
; interrupt.
|
||||
ORG 100H
|
||||
START:
|
||||
LXI SP,Test$Stack ;Use a local stack
|
||||
CALL DB$Init ;Initialize the debug package
|
||||
MVI A,JMP ;Setup RST 6 with JMP opcode
|
||||
STA RST6
|
||||
LXI H,Character$Interrupt ;Setup RST 6 JMP address
|
||||
SHLD RST6 + 1
|
||||
;
|
||||
; Make repeated entry to Character Interrupt routine
|
||||
; to ensure that characters can be captured and stored in
|
||||
; an input buffer
|
||||
;
|
||||
Testbed$Loop:
|
||||
MVI A,0AAH ;Set registers to known pattern
|
||||
LXI B,0BBCCH
|
||||
LXI D,0DDEEH
|
||||
LXI H,0FF11H
|
||||
RST 6 ;Fake interrupt for incoming character
|
||||
|
||||
CALL DB$MSGI ;Display in-line message
|
||||
DB 0DH,0AH,'Enter I to Input Char., O to Output, D to enter '
|
||||
DB 'DDT : ',0
|
||||
|
||||
CALL DB$CONINU ;Get upper case character
|
||||
CPI 'I' ;CONIN?
|
||||
JZ Go$CONIN
|
||||
CPI 'D' ;DDT?
|
||||
JZ Go$DDT
|
||||
CPI 'O' ;CONOUT?
|
||||
JZ Go$CONOUT
|
||||
JMP Testbed$Loop ;Loop back to interrupt again
|
||||
Go$DDT:
|
||||
RST 7 ;Enter DDT (RST 7 setup by DDT)
|
||||
JMP Testbed$Loop
|
||||
Go$CONIN:
|
||||
CALL CONST ;Get Console Status
|
||||
JZ Testbed$Loop ;No Data waiting
|
||||
CALL CONIN ;Get data from buffer
|
||||
|
||||
CALL DB$Display ;Display character returned
|
||||
DB DB$A ; in A register
|
||||
DB 'CONIN returned',0
|
||||
|
||||
JMP Go$CONIN ;Repeat CONIN loop until no chars.
|
||||
; waiting.
|
||||
;
|
||||
Go$CONOUT:
|
||||
CALL CONST ;Get Console Status
|
||||
JZ Testbed$Loop ;No data waiting
|
||||
CALL CONIN
|
||||
MOV C,A ;Ready for output
|
||||
CALL CONOUT ;Output to Console
|
||||
JMP Go$CONOUT ;Repeat while there is still data
|
||||
;
|
||||
DW 9999H,9999H,9999H,9999H,9999H,9999H,9999H,9999H
|
||||
DW 9999H,9999H,9999H,9999H,9999H,9999H,9999H,9999H
|
||||
DW 9999H,9999H,9999H,9999H,9999H,9999H,9999H,9999H
|
||||
Test$Stack:
|
||||
;
|
||||
; Dummy routines for those shown in other figures
|
||||
;
|
||||
; BIOS routines (Figure 8-10)
|
||||
;
|
||||
CONST: ;BIOS Console Status
|
||||
CONIN: ;BIOS Console Input
|
||||
CONOUT: ;BIOS Console Output;
|
||||
Character$Interrupt: ;Interrupt service routine for incoming chars.
|
||||
;
|
||||
; Debug routines (Figure 10-2)
|
||||
;
|
||||
DB$Init: ;Debug initialization
|
||||
DB$MSGI: ;Display message in-line
|
||||
DB$CONINU: ;Get upper case character from keyboard
|
||||
DB$Display: ;Main debug display routine
|
||||
DB$A EQU 02 ;Display code for DB$Display
|
||||
|
||||
83
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG10-5.ASM
Normal file
83
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG10-5.ASM
Normal file
@@ -0,0 +1,83 @@
|
||||
; Figure 10-5
|
||||
;
|
||||
; Testbed for Real Time Clock driver in the BIOS.
|
||||
;
|
||||
; The complete source file consists of three components:
|
||||
;
|
||||
; 1. The testbed code shown here.
|
||||
; 2. The Real Time Clock driver destined for the BIOS.
|
||||
; 3. The debug package shown in Figure 10-2.
|
||||
;
|
||||
TRUE EQU 0FFFFH
|
||||
FALSE EQU NOT TRUE
|
||||
|
||||
DEBUG EQU TRUE ;For conditional assembly of RST
|
||||
; instructions in place of IN and
|
||||
; OUT instructions in the drivers.
|
||||
RST6 EQU 30H ;Use RST 6 for fake clock tick.
|
||||
|
||||
ORG 100H
|
||||
START:
|
||||
LXI SP,Test$Stack ;Use local stack
|
||||
CALL DB$Init ;Initialize the debug package
|
||||
MVI A,JMP ;Setup RST 6 with JMP opcode
|
||||
STA RST6
|
||||
LXI H,RTC$Interrupt ;Setup RST 6 JMP address
|
||||
SHLD RST6 + 1
|
||||
|
||||
JMP Testbed$Loop ;<=== REMOVE THIS JMP WHEN READY TO
|
||||
; TEST WATCHDOG ROUTINES
|
||||
|
||||
LXI B,50 ;50 ticks before timeout
|
||||
LXI H,WD$Timeout ;Address to transfer to
|
||||
CALL Set$Watchdog ;Set the watchdog timer
|
||||
;
|
||||
;
|
||||
; Make repeated entry to RTC Interrupt routine
|
||||
; to ensure that clock is correctly updated.
|
||||
;
|
||||
Testbed$Loop:
|
||||
MVI A,0AAH ;Set registers to known pattern
|
||||
LXI B,0BBCCH
|
||||
LXI D,0DDEEH
|
||||
LXI H,0FF11H
|
||||
RST 6 ;Fake interrupt clock
|
||||
|
||||
CALL DB$MSGI ;Display in-line message
|
||||
DB 'Clock =',0
|
||||
|
||||
LXI H,Time$In$ASCII ;Get address of clock in driver
|
||||
CALL DB$MSG ;Display current clock value
|
||||
; (Note : Time$In$ASCII already has
|
||||
; a Line Feed character in it)
|
||||
CALL DB$MSGI ;Display in-line message
|
||||
DB 0DH,0 ;Carriage Return
|
||||
|
||||
JMP Testbed$Loop
|
||||
;
|
||||
; Control arrives here when the watchdog timer times
|
||||
; out.
|
||||
WD$Timeout:
|
||||
CALL DB$MSGI
|
||||
DB 0DH,0AH,'Watchdog timed out',0
|
||||
RET ;Return to watchdog routine
|
||||
;
|
||||
DW 9999H,9999H,9999H,9999H,9999H,9999H,9999H,9999H
|
||||
DW 9999H,9999H,9999H,9999H,9999H,9999H,9999H,9999H
|
||||
DW 9999H,9999H,9999H,9999H,9999H,9999H,9999H,9999H
|
||||
Test$Stack:
|
||||
;
|
||||
; Dummy routines for those shown in other figures
|
||||
;
|
||||
; BIOS routines (Figure 8-10)
|
||||
;
|
||||
RTC$Interrupt: ;Interrupt service routine for clock tick
|
||||
Set$Watchdog: ;Set Watchdog timer
|
||||
Time$In$ASCII: ;ASCII string of HH:MM:SS, LF, 0
|
||||
;
|
||||
; Debug routines (Figure 10-2)
|
||||
;
|
||||
DB$Init: ;Debug initialization
|
||||
DB$MSGI: ;Display message in-line
|
||||
DB$MSG: ;Display message
|
||||
|
||||
168
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG10-6.ASM
Normal file
168
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG10-6.ASM
Normal file
@@ -0,0 +1,168 @@
|
||||
; Figure 10-6
|
||||
;
|
||||
; Testbed for Disk I/O drivers in the BIOS.
|
||||
;
|
||||
; The complete source file consists of three components:
|
||||
;
|
||||
; 1. The testbed code shown here.
|
||||
; 2. The Disk I/O drivers destined for the BIOS.
|
||||
; 3. The debug package shown in Figure 10-2.
|
||||
;
|
||||
TRUE EQU 0FFFFH
|
||||
FALSE EQU NOT TRUE
|
||||
|
||||
DEBUG EQU TRUE ;For conditional assembly of RST
|
||||
; instructions in place of IN and
|
||||
; OUT instructions in the drivers.
|
||||
ORG 100H
|
||||
START:
|
||||
LXI SP,Test$Stack ;Use a local stack
|
||||
CALL DB$Init ;Initialize the debug package
|
||||
;
|
||||
; Make calls to SELDSK, SETTRK, SETSEC and SETDMA,
|
||||
; then either a Read or Write routine.
|
||||
;
|
||||
Testbed$Loop:
|
||||
LXI SP,Test$Stack ;Use local stack
|
||||
|
||||
LDA Logical$Disk ;Setup for SELDSK call
|
||||
MOV C,A
|
||||
CALL SELDSK
|
||||
|
||||
CALL DB$Display ;Display return value in HL
|
||||
DB DB$HL
|
||||
DB 'SELDSK returned',0
|
||||
|
||||
SHLD DPH$Start ;Setup to display Disk Parameter Header
|
||||
LXI D,16 ;Compute end address
|
||||
DAD D
|
||||
SHLD DPH$End ;Store into debug call
|
||||
|
||||
CALL DB$Display ;Display DPH
|
||||
DB DB$M ;Memory
|
||||
DPH$Start:
|
||||
DW 0
|
||||
DPH$End:
|
||||
DW 0
|
||||
DB 'Selected DPH',0
|
||||
|
||||
LHLD Track ;Call SETTRK
|
||||
PUSH H
|
||||
POP B ;SETTRK needs track in BC
|
||||
CALL SETTRK
|
||||
|
||||
LDA Sector ;Call SETSEC
|
||||
MOV C,A ;SETSEC need sector in C
|
||||
CALL SETSEC
|
||||
|
||||
LXI B,Test$Buffer ;Set DMA address
|
||||
CALL SETDMA
|
||||
|
||||
LDA Write$Disk ;Check if reading or writing
|
||||
ORA A
|
||||
JNZ Test$Write
|
||||
|
||||
CALL Read$No$Deblock ;*** or Read$Physical depending on which
|
||||
;*** drivers you are testing.
|
||||
CALL DB$Display ;Display return code
|
||||
DB DB$A
|
||||
DB 'Test Read returned',0
|
||||
|
||||
CALL Check$Ripple ;Check if ripple pattern in buffer
|
||||
JZ Testbed$Loop ;Yes, it is correct
|
||||
|
||||
CALL DB$MSGI ;Indicate problem
|
||||
DB DB$HL ;Display HL (points to offending byte)
|
||||
DB 'Ripple pattern incorrect. HL -> failure.',0
|
||||
|
||||
CALL DB$Display ;Display test buffer
|
||||
CALL DB$M ;Memory
|
||||
DW Test$Buffer
|
||||
DW Test$Buffer$Size
|
||||
DB 'Contents of Test$Buffer',0
|
||||
|
||||
JMP Testbed$Loop
|
||||
|
||||
Test$Write:
|
||||
CALL Fill$Ripple ;Fill the test buffer with ripple pattern
|
||||
CALL Write$No$Deblock;*** or Write$Physical depending on which
|
||||
;*** drivers you are testing.
|
||||
|
||||
CALL DB$Display ;Display return code
|
||||
DB DB$A
|
||||
DB 'Test Write returned',0
|
||||
|
||||
JMP Testbed$Loop
|
||||
|
||||
Fill$Ripple: ;Fills the Test$Buffer with a pattern
|
||||
; formed by putting into each byte, the
|
||||
; least significant 8-bits of the byte's
|
||||
; address.
|
||||
LXI B,Test$Buffer$Size
|
||||
LXI H,Test$Buffer
|
||||
FR$Loop:
|
||||
MOV M,L ;Set pattern value into buffer
|
||||
INX H ;Update buffer pointer
|
||||
DCX B ;Down date count
|
||||
MOV A,C ;Check if count zero
|
||||
ORA B
|
||||
JNZ FR$Loop ;Repeat until zero
|
||||
RET
|
||||
;
|
||||
Check$Ripple: ;Check that the buffer is filled with the
|
||||
; correct ripple pattern.
|
||||
; Returns with Zero status if this is true,
|
||||
; non-zero status if the ripple is not
|
||||
; correct. HL point to the offending byte
|
||||
; (which should = L)
|
||||
LXI B,Test$Buffer$Size
|
||||
LXI H,Test$Buffer
|
||||
CR$Loop:
|
||||
MOV A,L ;Get correct value
|
||||
CMP M ;Compare to that in the buffer
|
||||
RNZ ;Mismatch - Non-zero already indicated
|
||||
INX H ;Update buffer pointer
|
||||
DCX B ;Down date count
|
||||
MOV A,C ;Check count zero
|
||||
ORA B
|
||||
JNZ CR$Loop ;Repeat until zero
|
||||
RET ;Zero flag will already be set
|
||||
;
|
||||
; Testbed variables
|
||||
;
|
||||
Logical$Disk: DB 0 ;A = 0, B = 1,...
|
||||
Track: DW 0 ;Disk track number
|
||||
Sector: DB 0 ;Disk sector number
|
||||
Write$Disk: DB 0 ;NZ to write to disk
|
||||
;
|
||||
Test$Buffer$Size EQU 512 ;<=== Alter as required
|
||||
Test$Buffer: DS Test$Buffer$Size
|
||||
;
|
||||
DW 9999H,9999H,9999H,9999H,9999H,9999H,9999H,9999H
|
||||
DW 9999H,9999H,9999H,9999H,9999H,9999H,9999H,9999H
|
||||
DW 9999H,9999H,9999H,9999H,9999H,9999H,9999H,9999H
|
||||
Test$Stack:
|
||||
;
|
||||
; Dummy routines for those shown in other figures
|
||||
;
|
||||
; BIOS routines (Figure 8-10)
|
||||
;
|
||||
SELDSK: ;Select logical disk
|
||||
SETTRK: ;Set track number
|
||||
SETSEC: ;Set sector number
|
||||
SETDMA: ;Set DMA address
|
||||
Read$No$Deblock: ;Driver read routines
|
||||
Read$Physical:
|
||||
Write$No$Deblock: ;Driver write routines
|
||||
Write$Physical:
|
||||
|
||||
;
|
||||
; Debug routines (Figure 10-2)
|
||||
;
|
||||
DB$Init: ;Debug initialization
|
||||
DB$MSGI: ;Display message in-line
|
||||
DB$Display: ;Main debug display routine
|
||||
DB$A EQU 02 ;Display codes for DB$Display
|
||||
DB$HL EQU 20
|
||||
DB$M EQU 24
|
||||
|
||||
40
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-10.ASM
Normal file
40
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-10.ASM
Normal file
@@ -0,0 +1,40 @@
|
||||
; Figure 5-10
|
||||
;
|
||||
; IOBYTE Equates
|
||||
; These are for accessing the IOBYTE.
|
||||
;
|
||||
; Mask Values to isolate specific devices.
|
||||
; (These can also be inverted to preserve all BUT the
|
||||
; specific device)
|
||||
;
|
||||
IO$CONM EQU 0000$0011B ;Console Mask
|
||||
IO$RDRM EQU 0000$1100B ;Reader Mask
|
||||
IO$PUNM EQU 0011$0000B ;Punch Mask
|
||||
IO$LSTM EQU 1100$0000B ;List Mask
|
||||
;
|
||||
;Console Values
|
||||
IO$CTTY EQU 0 ;Console -> TTY:
|
||||
IO$CCRT EQU 1 ;Console -> CRT:
|
||||
IO$CBAT EQU 2 ;Console Input <- RDR:
|
||||
;Console Output -> LST:
|
||||
IO$CUC1 EQU 3 ;Console -> UC1: (User console 1)
|
||||
;
|
||||
;Reader Values
|
||||
IO$RTTY EQU 0 SHL 2 ;Reader <- TTY:
|
||||
IO$RRDR EQU 1 SHL 2 ;Reader <- RDR:
|
||||
IO$RUR1 EQU 2 SHL 2 ;Reader <- UR1: (User Reader 1)
|
||||
IO$RUR2 EQU 3 SHL 2 ;Reader <- UR2: (user Reader 2)
|
||||
;
|
||||
;Punch Values
|
||||
IO$PTTY EQU 0 SHL 4 ;Punch -> TTY:
|
||||
IO$PPUN EQU 1 SHL 4 ;Punch -> PUN:
|
||||
IO$PUP1 EQU 2 SHL 4 ;Punch -> UP1: (User Punch 1)
|
||||
IO$PUP2 EQU 3 SHL 4 ;Punch -> UP2: (User Punch 2)
|
||||
;
|
||||
;List Values
|
||||
IO$LTTY EQU 0 SHL 6 ;List -> TTY:
|
||||
IO$LCRT EQU 1 SHL 6 ;List -> CRT:
|
||||
IO$LLPT EQU 2 SHL 6 ;List -> LPT: (Physical Line Printer)
|
||||
IO$LUL1 EQU 3 SHL 6 ;List -> UL1: (User List 1)
|
||||
;
|
||||
|
||||
75
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-11.ASM
Normal file
75
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-11.ASM
Normal file
@@ -0,0 +1,75 @@
|
||||
; Figure 5-11
|
||||
;
|
||||
; This example shows how to use the Get and Set IOBYTE
|
||||
; functions to implement a simple Terminal emulator.
|
||||
; For this example to work, the BIOS must detect the
|
||||
; Console Value being set to 3 (IO$CUC1) and connect
|
||||
; Console Status, Input and Output functions to the
|
||||
; Communications line.
|
||||
;
|
||||
B$DIRCONIO EQU 6 ;Direct Console Input/Output
|
||||
B$GETIO EQU 7 ;Get IOBYTE
|
||||
B$SETIO EQU 8 ;Set IOBYTE
|
||||
B$CONST EQU 11 ;Get Console Status (sneak preview)
|
||||
BDOS EQU 5 ;BDOS entry point
|
||||
;
|
||||
IO$CONM EQU 0000$0011B ;Console Mask for IOBYTE
|
||||
IO$CCRT EQU 1 ;Console -> CRT:
|
||||
IO$CUC1 EQU 3 ;Console -> User Console #1
|
||||
;
|
||||
TERM:
|
||||
CALL SETCRT ;Connect Console -> CRT:
|
||||
TERM$CKS:
|
||||
CALL CONST ;Get CRT status
|
||||
JZ TERM$NOKI ;No console input
|
||||
CALL CONIN ;Get keyboard character
|
||||
CALL SETCOMM ;Connect Console -> Comm. Line
|
||||
CALL CONOUT ;Output to Comm. Line
|
||||
TERM$CCS: ;Check Comm. Status
|
||||
CALL CONST ;Get "Console" status
|
||||
JZ TERM ;No incoming Comm. character
|
||||
CALL CONIN ;Get incoming Comm. character
|
||||
CALL SETCRT ;Connect Console -> CRT:
|
||||
CALL CONOUT ;Output to CRT
|
||||
JMP TERM$CKS ;Loop back to check keyboard status
|
||||
TERM$NOKI:
|
||||
CALL SETCOMM ;Connect Console -> Comm. Line
|
||||
JMP TERM$CCS ;Loop back to check Comm. status
|
||||
;
|
||||
SETCRT: ;Connect Console -> CRT:
|
||||
PUSH PSW ;Save possible data character
|
||||
MVI B,IO$CCRT ;Connect Console -> CRT:
|
||||
JMP SETCON ;Common Code
|
||||
|
||||
SETCOMM: ;Connect Console -> Comm. Line
|
||||
PUSH PSW ;Save possible data character
|
||||
MVI B,IO$CUC1 ;Connect Console -> Comm. Line
|
||||
;Drop into SETCON
|
||||
|
||||
SETCON: ;Set Console Device
|
||||
;New code in B (in bits 1,0)
|
||||
PUSH B ;Save code
|
||||
MVI C,B$GETIO ;Get current IOBYTE
|
||||
CALL BDOS
|
||||
ANI (NOT IO$CONM) AND 0FFH ;Preserve all but console
|
||||
POP B ;Recover required code
|
||||
ORA B ;OR in new bits
|
||||
MOV E,A ;Ready for setting
|
||||
MVI C,B$SETIO ;Function code
|
||||
CALL BDOS
|
||||
POP PSW ;Recover possible data character
|
||||
RET
|
||||
CONOUT:
|
||||
MOV E,A ;Get data byte for output
|
||||
MVI C,B$DIRCONIO ;Function code
|
||||
JMP BDOS ;BDOS returns to CONOUT's caller
|
||||
CONIN:
|
||||
MVI C,B$DIRCONIO ;Function Code
|
||||
MVI E,0FFH ;Indicate Console Input
|
||||
JMP BDOS ;BDOS returns to CONIN's caller
|
||||
CONST:
|
||||
MVI C,B$CONST ;Function Code
|
||||
CALL BDOS
|
||||
ORA A ;Set Z-flag to result
|
||||
RET
|
||||
|
||||
79
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-12.ASM
Normal file
79
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-12.ASM
Normal file
@@ -0,0 +1,79 @@
|
||||
; Figure 5-12
|
||||
;
|
||||
; OM
|
||||
; Output Message
|
||||
; This subroutine selects one of several messages based on
|
||||
; the contents of the A register on entry. It then displays
|
||||
; this message on the console.
|
||||
;
|
||||
; Each message is declared with a '$' as its last character.
|
||||
; If the A register contains a value larger than the number
|
||||
; of messages declared, OM will output "Unknown Message".
|
||||
;
|
||||
; As an option, OM can output Carriage Return / Line Feed
|
||||
; prior to outputting the message text.
|
||||
;
|
||||
; Entry Parameters
|
||||
;
|
||||
; HL -> Message Table
|
||||
; This has the form :
|
||||
; DB 3 ;Number of Messages in table
|
||||
; DW MSG0 ;Address of text (A = 0)
|
||||
; DW MSG1 ;(A = 1)
|
||||
; DW MSG2 ;(A = 2)
|
||||
;
|
||||
; MSG0: DB 'Message text$'
|
||||
; ...etc.
|
||||
;
|
||||
; A = Message Code (from 0 on up)
|
||||
; B = Output CR/LF if Non-zero
|
||||
;
|
||||
; Calling sequence
|
||||
;
|
||||
; LXI H,MSG$TABLE
|
||||
; LDA MSGCODE
|
||||
; MVI B,0 ;Suppress CR/LF
|
||||
; CALL OM
|
||||
;
|
||||
B$PRINTS EQU 9 ;Print $-terminated string
|
||||
BDOS EQU 5 ;BDOS Entry Point
|
||||
;
|
||||
CR EQU 0DH ;Carriage Return
|
||||
LF EQU 0AH ;Line Feed
|
||||
;
|
||||
OM$CRLF: DB CR,LF,'$'
|
||||
OM$UM: DB 'Unknown Message$'
|
||||
;
|
||||
;
|
||||
OM:
|
||||
PUSH PSW ;Save message code
|
||||
PUSH H ;Save message table pointer
|
||||
MOV A,B ;Check if CR/LF required
|
||||
ORA A
|
||||
JZ OM$NOCR ;No
|
||||
LXI D,OM$CRLF ;Output CR/LF
|
||||
MVI C,B$PRINTS
|
||||
CALL BDOS
|
||||
OM$NOCR:
|
||||
POP H ;Recover message table pointer
|
||||
POP PSW ;Recover message code
|
||||
CMP M ;Compare message to max. value
|
||||
JNC OM$ERR ;Error - code not <= max.
|
||||
INX H ;Bypass max. value in table
|
||||
ADD A ;Message Code * 2
|
||||
MOV E,A ;Make Code * 2 a word value
|
||||
MVI D,0
|
||||
DAD D ;HL -> Address of message text
|
||||
MOV E,M ;Get LS Byte
|
||||
INX H ;HL -> MS Byte
|
||||
MOV D,M ;Get MS Byte
|
||||
;DE -> Message text itself
|
||||
OM$PS: ;Print string entry point
|
||||
MVI C,B$PRINTS ;Function Code
|
||||
CALL BDOS
|
||||
RET ;Return to caller
|
||||
;
|
||||
OM$ERR: ;Error
|
||||
LXI D,OM$UM ;Point to "Unknown Message"
|
||||
JMP OM$PS ;Print string
|
||||
|
||||
159
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-13.ASM
Normal file
159
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-13.ASM
Normal file
@@ -0,0 +1,159 @@
|
||||
; Figure 5-13
|
||||
;
|
||||
; RSA
|
||||
; Return Subprocessor Address
|
||||
; This subroutine returns one of several addresses selected
|
||||
; from a table by matching keyboard input against
|
||||
; specified strings. It is normally used to switch control
|
||||
; to a particular subprocessor according to an option entered
|
||||
; by the operator from the keyboard.
|
||||
;
|
||||
; Character string comparisons are performed with case-folding,
|
||||
; that is lower-case letters are converted to upper-case.
|
||||
;
|
||||
; If the operator input fails to match any of the specified
|
||||
; strings, then the Carry flag is set, otherwise it is cleared.
|
||||
;
|
||||
; Entry Parameters
|
||||
;
|
||||
; HL -> Subprocessor Select Table
|
||||
; This has the form :
|
||||
; DW TEXT0,SUBPROC0
|
||||
; DW TEXT1,SUBPROC1
|
||||
; DW 0 ;Terminator
|
||||
;
|
||||
; TEXT0: DB 'add',0 ;00H-byte terminated
|
||||
; TEXT1: DB 'subtract',0
|
||||
;
|
||||
; SUBPROC0:
|
||||
; Code for processing ADD function.
|
||||
; SUBPROC1:
|
||||
; Code for processing SUBTRACT function.
|
||||
;
|
||||
; Exit Parameters
|
||||
;
|
||||
; DE -> operator input string (00H-terminated input string).
|
||||
; Carry Clear, HL -> Subprocessor.
|
||||
; Carry Set, HL = 0000H.
|
||||
;
|
||||
; Calling Sequence
|
||||
;
|
||||
; LXI H,SUBPROCTAB ;Subprocessor Table
|
||||
; CALL RSA
|
||||
; JC ERROR ;Carry set only on error
|
||||
; LXI D,RETURN ;Fake CALL instruction
|
||||
; PUSH D ;Push Return address on stack
|
||||
; PCHL ;"CALL" to Subprocessor
|
||||
; RETURN:
|
||||
;
|
||||
B$READCONS EQU 10 ;Read Console String into Buffer
|
||||
BDOS EQU 5 ;BDOS Entry Point
|
||||
;
|
||||
RSA$BL EQU 80 ;Buffer Length
|
||||
RSA$BUF: DB RSA$BL ;Max. no. of characters
|
||||
RSA$ACTC: DB 0 ;Actual no. of characters
|
||||
RSA$BUFC: DS RSA$BL ;Buffer characters
|
||||
DB 0 ;Safety terminator
|
||||
;
|
||||
;
|
||||
RSA:
|
||||
DCX H ;Adjust Subproc. pointer for code below
|
||||
DCX H
|
||||
PUSH H ;Top of Stack (TOS) -> Subproc. table - 2
|
||||
MVI C,B$READCONS ;Function Code
|
||||
LXI D,RSA$BUF ;DE -> Buffer
|
||||
CALL BDOS ;Read operator input
|
||||
;Convert input to 00H-terminated
|
||||
LXI H,RSA$ACTC ;HL -> Actual no. of chars input
|
||||
MOV E,M ;Get Actual no. of chars input
|
||||
MVI D,0 ;Make into word value
|
||||
INX H ;HL -> first data character
|
||||
DAD D ;HL -> first UNUSED character in buffer
|
||||
MVI M,0 ;Make input buffer 00H-terminated
|
||||
;Compare input to specified values
|
||||
;Main loop
|
||||
RSA$ML:
|
||||
POP H ;Recover subprocessor table pointer
|
||||
INX H ;Move to top of next entry
|
||||
INX H ;HL -> Text Address
|
||||
MOV E,M ;Get text address
|
||||
INX H
|
||||
MOV D,M ;DE -> text
|
||||
|
||||
MOV A,D ;Check if at end of subproc. table
|
||||
ORA E
|
||||
JZ RSA$NFND ;Match not Found
|
||||
|
||||
INX H ;HL -> subprocessor address
|
||||
PUSH H ;Save ptr to subprocessor table
|
||||
LXI H,RSA$BUFC ;HL -> input characters
|
||||
CALL FSCMP ;Folded string compare
|
||||
JNZ RSA$ML ;No match, move to next entry
|
||||
POP H ;Match found, recover subproc. ptr
|
||||
MOV E,M ;Get actual subprocessor address
|
||||
INX H
|
||||
MOV D,M ;DE -> Subprocessor code
|
||||
XCHG ;HL -> Subprocessor code
|
||||
ORA A ;Clear carry (match found)
|
||||
RET
|
||||
;
|
||||
RSA$NFND:
|
||||
LXI H,0 ;Indicate no match found
|
||||
STC ;Set carry
|
||||
RET
|
||||
;
|
||||
;
|
||||
; FSCMP
|
||||
; Folded (lower case to upper) string compare.
|
||||
; This subroutine compares two 00H-byte terminated
|
||||
; strings and returns with the condition flags set
|
||||
; to indicate their relationship.
|
||||
;
|
||||
; Entry parameters
|
||||
;
|
||||
; DE -> String 1
|
||||
; HL -> String 2
|
||||
;
|
||||
; Exit parameters
|
||||
;
|
||||
; Flags set (based on String1 - String2, on a
|
||||
; character-by-character basis)
|
||||
;
|
||||
;
|
||||
FSCMP:
|
||||
LDAX D ;Get String 1 character
|
||||
CALL FOLD ;Fold to upper case
|
||||
PUSH PSW ;Save String 1 character
|
||||
MOV A,M ;Get String 2 character
|
||||
CALL FOLD ;Fold to upper case
|
||||
MOV B,A ;Save String 2 character
|
||||
POP PSW ;Recover String 1 character
|
||||
CMP B ;String 1 - String 2
|
||||
RNZ ;Return if not equal
|
||||
ORA A ;Equal, so check if end of strings
|
||||
RZ ;Yes
|
||||
INX D ;No, update String 1 pointer
|
||||
INX H ; and String 2 pointer
|
||||
JMP FSCMP ;Check next character
|
||||
;
|
||||
;
|
||||
; FOLD
|
||||
; Folds a lower case letter (a-z) to UPPER CASE (A-Z)
|
||||
;
|
||||
; The character to be folded is in A on entry and on exit.
|
||||
;
|
||||
FOLD:
|
||||
MOV C,A ;Preserve input character
|
||||
MVI A,'a'-1 ;Check if folding needed
|
||||
CMP C ;Compare to input character
|
||||
JNC FOLDX ;No, char. is <= 'a'
|
||||
MVI A,'z' ;Check if < 'z'
|
||||
CMP C
|
||||
JC FOLDX ;No, char. is > 'z'
|
||||
MVI A,0DFH ;Fold character
|
||||
ANA C
|
||||
RET
|
||||
FOLDX:
|
||||
MOV A,C ;Recover original input char.
|
||||
RET
|
||||
|
||||
46
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-14.ASM
Normal file
46
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-14.ASM
Normal file
@@ -0,0 +1,46 @@
|
||||
; Figure 5-14
|
||||
;
|
||||
; CCPM
|
||||
; Check if CP/M
|
||||
; This subroutine determines the version number of the
|
||||
; Operating System and, if not CP/M version 2, displays
|
||||
; an error message and executes a warm boot.
|
||||
;
|
||||
; Entry and Exit Parameters
|
||||
;
|
||||
; None
|
||||
;
|
||||
; Calling sequence
|
||||
;
|
||||
; CALL CCPM ;Warm boots if not CP/M 2
|
||||
;
|
||||
B$PRINTS EQU 9 ;Display $-terminated string
|
||||
B$GETVER EQU 12 ;Get version number
|
||||
BDOS EQU 5 ;BDOS Entry Point
|
||||
;
|
||||
CR EQU 0DH ;Carriage Return
|
||||
LF EQU 0AH ;Line Feed
|
||||
;
|
||||
CCPMM: DB CR,LF
|
||||
DB 'This program can only run under CP/M version 2.'
|
||||
DB CR,LF,'$'
|
||||
;
|
||||
;
|
||||
CCPM:
|
||||
MVI C,B$GETVER ;Get version number
|
||||
CALL BDOS
|
||||
MOV A,H ;H must be 0 for CP/M
|
||||
ORA A
|
||||
JNZ CCPME ;Must be MP/M
|
||||
MOV A,L ;L = version number of CP/M
|
||||
ANI 0F0H ;Version number in MS Nibble
|
||||
CPI 20H ;Check if version 2
|
||||
JNZ CCPME ;Must be an earlier version
|
||||
RET ;Yes, we under CP/M version 2
|
||||
;
|
||||
CCPME: ;Error
|
||||
MVI C,B$PRINTS ;Display error message
|
||||
LXI D,CCPMM
|
||||
CALL BDOS
|
||||
JMP 0 ;Warm Boot
|
||||
|
||||
50
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-15.ASM
Normal file
50
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-15.ASM
Normal file
@@ -0,0 +1,50 @@
|
||||
; Figure 5-15
|
||||
;
|
||||
; CDISK
|
||||
; Change Disk
|
||||
; This subroutine displays a message requesting the
|
||||
; to change the specified logical disk, then waits for
|
||||
; a Carriage Return to be pressed. It then issues
|
||||
; a Disk Reset and returns to the caller.
|
||||
;
|
||||
; Entry Parameters
|
||||
;
|
||||
; A = Logical disk to be changed (A = 0, B = 1)
|
||||
;
|
||||
; Exit Parameters
|
||||
;
|
||||
; None
|
||||
;
|
||||
; Calling Sequence
|
||||
;
|
||||
; MVI A,0 ;Change drive A:
|
||||
; CALL CDISK
|
||||
;
|
||||
;
|
||||
B$DSKRESET EQU 13 ;Disk Reset function code
|
||||
B$PRINTS EQU 9 ;Print $-terminated string
|
||||
B$CONIN EQU 1 ;Get console input
|
||||
BDOS EQU 5 ;BDOS Entry Point
|
||||
;
|
||||
CR EQU 0DH
|
||||
LF EQU 0AH
|
||||
;
|
||||
CDISKM: DB CR,LF,'Change logical disk '
|
||||
CDISKD: DB 0
|
||||
DB ': and press Carriage Return to continue$'
|
||||
;
|
||||
CDISK:
|
||||
ADI 'A'-1 ;Convert to Letter
|
||||
STA CDISKD ;Store into message
|
||||
MVI C,B$PRINTS ;Display Message
|
||||
LXI D,CDISKM
|
||||
CALL BDOS
|
||||
CDISKW:
|
||||
MVI C,B$CONIN ;Get keyboard character
|
||||
CALL BDOS
|
||||
CPI CR
|
||||
JNZ CDISKW
|
||||
MVI C,B$DSKRESET ;Now reset disk system
|
||||
CALL BDOS
|
||||
RET
|
||||
|
||||
176
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-16.ASM
Normal file
176
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-16.ASM
Normal file
@@ -0,0 +1,176 @@
|
||||
; Figure 5-16
|
||||
;
|
||||
; OPENF
|
||||
; Open File
|
||||
;
|
||||
; Given a pointer to a 00H-byte terminated file name,
|
||||
; and an area that can be used for a File Control Block,
|
||||
; this subroutine builds a valid File Control Block, and
|
||||
; attempts to open the File.
|
||||
;
|
||||
; If the file is opened, it returns with Carry Flag clear.
|
||||
; If the file cannot be opened, this subroutine returns
|
||||
; with the Carry Flag set.
|
||||
;
|
||||
; Entry Parameters
|
||||
;
|
||||
; DE -> 36-byte area for File Control Block
|
||||
; HL -> 00H-byte terminated file name of the form
|
||||
; {disk:} Name {.typ}
|
||||
; (That is, the disk and typ are optional)
|
||||
;
|
||||
; Exit Parameters
|
||||
;
|
||||
; Carry Clear : File opened correctly.
|
||||
; Carry Set : File not opened.
|
||||
;
|
||||
; Calling Sequence
|
||||
;
|
||||
; LXI D,FCB
|
||||
; LXI H,FNAME
|
||||
; CALL OPENF
|
||||
; JC ERROR
|
||||
;
|
||||
; where
|
||||
;
|
||||
; FCB: DS 36 ;Space for File Control Block
|
||||
; FNAME: DB 'A:TESTFILE.DAT',0
|
||||
;
|
||||
;
|
||||
B$OPEN EQU 15 ;File Open Function Code
|
||||
BDOS EQU 5 ;BDOS Entry Point
|
||||
;
|
||||
;
|
||||
OPENF:
|
||||
PUSH D ;Preserve pointer to FCB
|
||||
CALL BF ;Build File Control Block (FCB)
|
||||
MVI C,B$OPEN
|
||||
POP D ;Recover Pointer to FCB
|
||||
CALL BDOS
|
||||
RAL ;If A=0FFH, Carry set
|
||||
;otherwise Carry Clear
|
||||
RET
|
||||
;
|
||||
; BF
|
||||
; Build File Control Block
|
||||
; This subroutine formats a 00H-byte terminated string
|
||||
; (presumed to be a File Name) into an FCB, setting the
|
||||
; Disk, File name and Type and clearing the remainder of the
|
||||
; FCB to 0's.
|
||||
;
|
||||
; Entry Parameters
|
||||
;
|
||||
; DE -> File Control Block (36 Bytes)
|
||||
; HL -> File Name String (00H-byte terminated)
|
||||
;
|
||||
; Exit Parameters
|
||||
;
|
||||
; The built File Control block.
|
||||
;
|
||||
; Calling Sequence
|
||||
;
|
||||
; LXI D,FCB
|
||||
; LXI H,FILENAME
|
||||
; CALL BF
|
||||
;
|
||||
;
|
||||
BF:
|
||||
INX H ;Check if 2nd char. is ":"
|
||||
MOV A,M ;Get character from file name
|
||||
DCX H ;HL -> now back at 1st char
|
||||
CPI ':' ;If ":", then Disk specified
|
||||
JNZ BF$ND ;No disk
|
||||
MOV A,M ;Get disk letter
|
||||
ANI 0001$1111B ;A (41H) -> 1, B (42H) -> 2 ...
|
||||
INX H ;Bypass disk letter
|
||||
INX H ;Bypass ":"
|
||||
JMP BF$SD ;Store disk in FCB
|
||||
BF$ND: ;No disk present
|
||||
XRA A ;Indicate default disk
|
||||
BF$SD:
|
||||
STAX D ;Store disk in FCB
|
||||
INX D ;DE -> 1st char. of name in FCB
|
||||
MVI C,8 ;File name length
|
||||
CALL BF$GT ;Get token
|
||||
;Note - at this point, BF$GT will
|
||||
;have advanced the string pointer to
|
||||
;either a '.' or 00H byte
|
||||
CPI '.' ;Check terminating character
|
||||
JNZ BF$NT ;No file type specified
|
||||
INX H ;Bypass '.' in file name
|
||||
BF$NT:
|
||||
MVI C,3 ;File Type Length
|
||||
CALL BF$GT ;Get Token
|
||||
;Note - if no file type is present
|
||||
;BF$GT will merely spacefill the FCB
|
||||
MVI B,0 ;0-fill the remainder of the FCB
|
||||
MVI C,24 ;36 - 12 (Disk, Name, Type = 12 chars.)
|
||||
CALL BF$FT ;Re-use Fill Token S/R
|
||||
RET
|
||||
;
|
||||
; BF$GT
|
||||
; Build FCB - Get Token
|
||||
;
|
||||
; This subroutine scans a file name string,
|
||||
; placing characters into a File Control Block.
|
||||
; On encountering a terminator character ("." or 00H),
|
||||
; the remainder of the token is space filled.
|
||||
; If an "*" is encountered, the remainder of the token
|
||||
; is filled with "?".
|
||||
;
|
||||
; Entry Parameters
|
||||
;
|
||||
; DE -> Into File Control Block
|
||||
; HL -> Into File Name String
|
||||
; C = Maximum no. of characters in token
|
||||
;
|
||||
; Exit Parameters
|
||||
;
|
||||
; File Control Block contains next token.
|
||||
; A = Terminating Character.
|
||||
BF$GT:
|
||||
MOV A,M ;Get next string character
|
||||
ORA A ;Check if end of string
|
||||
JZ BF$SFT ;Yes, space fill token
|
||||
CPI '*' ;Check if ?-fill required
|
||||
JZ BF$QFT ;Yes, fill with ?
|
||||
CPI '.' ;Assume current token is Filename
|
||||
;check if file type coming up
|
||||
;(If current token is File type this
|
||||
;check is benignly redundant)
|
||||
JZ BF$SFT ;Yes, space fill token
|
||||
STAX D ;None of the above, so store in FCB
|
||||
INX D ;Update FCB Pointer
|
||||
INX H ;Update String Pointer
|
||||
DCR C ;Countdown on token length
|
||||
JNZ BF$GT ;Still more characters to go
|
||||
BF$SKIP: ;Skip chars. until '.' or 00H
|
||||
MOV A,M ;Get next string character
|
||||
ORA A ;Check if 00H
|
||||
RZ ;Yes
|
||||
CPI '.' ;Check if '.'
|
||||
RZ ;Yes
|
||||
INX H ;Update string pointer (only)
|
||||
JMP BF$SKIP ;Try next character
|
||||
|
||||
BF$SFT: ;Space fill token
|
||||
MVI B,' '
|
||||
JMP BF$FT ;Common Fill Token code
|
||||
;BF$FT returns to caller
|
||||
|
||||
BF$QFT: ;Question Mark Fill Token
|
||||
MVI B,'?'
|
||||
CALL BF$FT ;Common Fill Token Code
|
||||
JMP BF$SKIP ;Bypass multiple '*' etc.
|
||||
|
||||
BF$FT: ;Fill Token
|
||||
PUSH PSW ;Save terminating character
|
||||
MOV A,B ;Get fill characer
|
||||
BF$FTL: ;Inner loop
|
||||
STAX D ;Store in FCB
|
||||
INX D ;Update FCB Pointer
|
||||
DCR C ;Downdate residual count
|
||||
JNZ BF$FTL ;Keep going
|
||||
POP PSW ;Recover terminating character
|
||||
RET
|
||||
|
||||
189
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-17.ASM
Normal file
189
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-17.ASM
Normal file
@@ -0,0 +1,189 @@
|
||||
; Figure 5-17
|
||||
;
|
||||
; GNF
|
||||
; This subroutine returns an FCB setup with either the first
|
||||
; file matched by an ambiguous file name, or (if specified
|
||||
; by entry parameter) the next file name.
|
||||
;
|
||||
; Note : this subroutine is context sensitive. You must not
|
||||
; have more than one ambiguous file name sequence in
|
||||
; process at any given time.
|
||||
;
|
||||
;>>> Warning : This subroutine changes the DMA Address inside
|
||||
;>>> the BDOS.
|
||||
;
|
||||
; Entry Parameters
|
||||
;
|
||||
; DE -> Possibly Ambiguous File Name
|
||||
; (00-byte terminated)
|
||||
; (Only needed for FIRST request)
|
||||
; HL -> File Control Block
|
||||
; A = 0 : Return FIRST file name that matches
|
||||
; = NZ : Return NEXT file name that matches
|
||||
;
|
||||
; Exit Parameters
|
||||
;
|
||||
; Carry set : A = FF, no file name matches
|
||||
; A not = 0FFH, error in input file name
|
||||
; Carry clear : FCB setup with next name
|
||||
; HL -> Directory Entry returned by
|
||||
; Search First/Next
|
||||
;
|
||||
; Calling sequence
|
||||
;
|
||||
; LXI D,FILENAME
|
||||
; LXI H,FCB
|
||||
; MVI A,0 ;or MVI A,1 for NEXT
|
||||
; CALL GNF
|
||||
;
|
||||
B$SEARCHF EQU 17 ;Search for First file name
|
||||
B$SEARCHN EQU 18 ;Search for Next file name
|
||||
B$SETDMA EQU 26 ;Setup DMA Address
|
||||
BDOS EQU 5 ;BDOS Entry Point
|
||||
;
|
||||
GNFDMA EQU 80H ;Default DMA Address
|
||||
GNFSVL EQU 13 ;Save Length (no. of chars to move)
|
||||
GNFFCL EQU 36 ;File Control Block length
|
||||
GNFSV: DS GNFSVL ;Save area for file name/type
|
||||
;
|
||||
GNF:
|
||||
PUSH H ;Save FCB pointer
|
||||
PUSH D ;Save File Name pointer
|
||||
PUSH PSW ;Save First/Next flag
|
||||
|
||||
LXI D,GNFDMA ;Set DMA to known address
|
||||
MVI C,B$SETDMA ;Function code
|
||||
CALL BDOS
|
||||
POP PSW ;Recover First/Next flag
|
||||
POP H ;Recover File Name pointer
|
||||
POP D ;Recover FCB Pointer
|
||||
PUSH D ;Re-save FCB Pointer
|
||||
|
||||
ORA A ;Check if FIRST or NEXT
|
||||
JNZ GNFN ;NEXT
|
||||
CALL BF ;Build File Control BLock
|
||||
POP H ;Recover FCB Pointer (to balance stack)
|
||||
RC ;Return if error in File Name
|
||||
PUSH H ;Resave FCB pointer
|
||||
|
||||
;Move Ambiguous File Name to save area
|
||||
;HL -> FCB
|
||||
LXI D,GNFSV ;DE -> save area
|
||||
MVI C,GNFSVL ;Get save length
|
||||
CALL MOVE
|
||||
POP D ;Recover FCB Pointer
|
||||
PUSH D ;and re-save
|
||||
|
||||
MVI C,B$SEARCHF ;Search FIRST
|
||||
CALL BDOS
|
||||
POP H ;Recover FCB Pointer
|
||||
CPI 0FFH ;Check for error
|
||||
JZ GNFEX ;Error exit
|
||||
JMP GNFC ;Common code
|
||||
;
|
||||
GNFN:
|
||||
;Execute search FIRST to re-establish
|
||||
;contact with previous file
|
||||
;User's FCB still has Name/Type in it
|
||||
CALL GNFZF ;Zero-fill all but File Name/Type
|
||||
POP D ;Recover FCB address
|
||||
PUSH D ;and re-save
|
||||
MVI C,B$SEARCHF ;Re-find the file
|
||||
CALL BDOS
|
||||
POP D ;Recover FCB Pointer
|
||||
PUSH D ;and re-save
|
||||
LXI H,GNFSV ;Move File Name from save area into FCB
|
||||
MVI C,GNFSVL ;Save area length
|
||||
CALL MOVE
|
||||
|
||||
MVI C,B$SEARCHN ;Search NEXT
|
||||
CALL BDOS
|
||||
POP H ;Recover FCB address
|
||||
CPI 0FFH ;Check for error
|
||||
JZ GNFEX ;Error exit
|
||||
GNFC:
|
||||
PUSH H ;Save FCB Address
|
||||
ADD A ;Multiply BDOS Return Code * 32
|
||||
ADD A ;* 4
|
||||
ADD A ;* 8
|
||||
ADD A ;* 16
|
||||
ADD A ;* 32
|
||||
LXI H,GNFDMA ;HL -> DMA Address
|
||||
MOV E,A ;Make Code * 32 a word value in DE
|
||||
MVI D,0
|
||||
DAD D ;HL -> File's directory entry
|
||||
|
||||
;Move File Name into FCB
|
||||
POP D ;Recover FCB Address
|
||||
PUSH H ;Save Directory Entry pointer
|
||||
PUSH D ;and re-save
|
||||
MVI C,GNFSVL ;Length of save area
|
||||
CALL MOVE
|
||||
LDA GNFSV ;Get Disk Drive from save area
|
||||
POP D ;Recover FCB Address
|
||||
STAX D ;Overwrite user number in FCB
|
||||
|
||||
;Setup to zero-fill tail end of FCB
|
||||
CALL GNFZF ;Zero-fill
|
||||
POP H ;Recover Directory Entry Pointer
|
||||
XRA A ;Clear Carry
|
||||
RET
|
||||
;
|
||||
GNFEX:
|
||||
STC ;Set Carry to indicate error
|
||||
RET
|
||||
|
||||
;
|
||||
; GNFZF
|
||||
; Get Next File - Zero Fill
|
||||
; This subroutine Zero-fills the rest of the bytes in an FCB
|
||||
; that follow the File Name and Type.
|
||||
;
|
||||
; Entry Parameters
|
||||
;
|
||||
; DE -> File Control Block
|
||||
;
|
||||
GNFZF:
|
||||
LXI H,GNFSVL ;Bypass area that holds file name
|
||||
DAD D ;HL -> FCB + GNFSVL
|
||||
MOV D,H ;DE -> FCB + GNFSVL
|
||||
MOV E,L
|
||||
INX D ;DE -> FCB + GNFSVL + 1
|
||||
MVI M,0 ;FCB + GNFSVL = 0
|
||||
MVI C,GNFFCL-GNFSVL ;Remainder of File Control Block
|
||||
; Drop into MOVE ;Spread 0's through remainder of FCB
|
||||
; v
|
||||
;
|
||||
; MOVE
|
||||
; This subroutine moves C bytes from (HL) to (DE).
|
||||
;
|
||||
MOVE:
|
||||
MOV A,M ;Get source byte
|
||||
STAX D ;Save destination byte
|
||||
INX D ;Increment destination pointer
|
||||
INX H ;Increment source pointer
|
||||
DCR C ;Downdate count
|
||||
JNZ MOVE ;Go back for more
|
||||
RET
|
||||
;
|
||||
; BF
|
||||
; Build File Control Block
|
||||
;
|
||||
; This subroutine formats a 00H-byte terminated string
|
||||
; (presumed to be a File Name) into an FCB, setting the
|
||||
; Disk, File name and Type and clearing the remainder of the
|
||||
; FCB to 0's.
|
||||
;
|
||||
; Entry Parameters
|
||||
;
|
||||
; DE -> File Control Block (36 Bytes)
|
||||
; HL -> File Name String (00H-byte terminated)
|
||||
;
|
||||
; Exit Parameters
|
||||
;
|
||||
; The built File Control block.
|
||||
;
|
||||
; This subroutine is shown in full in Figure 5.32
|
||||
;
|
||||
BF: RET ;Dummy subroutine for this example
|
||||
|
||||
73
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-18.ASM
Normal file
73
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-18.ASM
Normal file
@@ -0,0 +1,73 @@
|
||||
; Figure 5-18
|
||||
;
|
||||
; GETC
|
||||
; This subroutine gets the next character from a
|
||||
; Sequential disk file. It assumes that the file has
|
||||
; already been opened.
|
||||
;
|
||||
;>>> Note : this subroutine changes CP/M's DMA Address.
|
||||
;
|
||||
; Entry Parameters
|
||||
;
|
||||
; DE -> File Control Block.
|
||||
;
|
||||
; Exit Parameters
|
||||
;
|
||||
; A = next character from file.
|
||||
; (= 0FFH on physical End of File).
|
||||
; Note : 1AH is normal EOF character for
|
||||
; ASCII Files.
|
||||
;
|
||||
; Calling sequence
|
||||
;
|
||||
; LXI DE,FCB
|
||||
; CALL GETC
|
||||
; CPI 1AH
|
||||
; JZ EOFCHAR
|
||||
; CPI 0FFH
|
||||
; JZ ACTUALEOF
|
||||
;
|
||||
B$READSEQ EQU 20 ;Read Sequential
|
||||
B$SETDMA EQU 26 ;Set DMA Address
|
||||
BDOS EQU 5 ;BDOS Entry Point
|
||||
;
|
||||
GETCBS EQU 128 ;Buffer Size
|
||||
GETCBF: DS GETCBS ;Declare buffer
|
||||
GETCCC: DB 0 ;Char. count (initially 'empty')
|
||||
;
|
||||
GETC:
|
||||
LDA GETCCC ;Check if buffer is empty
|
||||
ORA A
|
||||
JZ GETCFB ;Yes, fill buffer
|
||||
GETCRE: ;Re-entry point after buffer filled
|
||||
DCR A ;No, downdate count
|
||||
STA GETCCC ;Save downdated count
|
||||
|
||||
MOV B,A ;Compute offset of next character
|
||||
MVI A,GETCBS-1 ;By subtracting
|
||||
SUB B ;(buffer size - downdated count)
|
||||
MOV E,A ;Make result into word value
|
||||
MVI D,0
|
||||
LXI H,GETCBF ;HL -> Base of Buffer
|
||||
DAD D ;HL -> Next character in buffer
|
||||
MOV A,M ;Get next character
|
||||
RET
|
||||
;
|
||||
GETCFB: ;Fill Buffer
|
||||
PUSH D ;Save FCB Pointer
|
||||
LXI D,GETCBF ;Set DMA Address to Buffer
|
||||
MVI C,B$SETDMA ;Function Code
|
||||
CALL BDOS
|
||||
POP D ;Recover FCB Pointer
|
||||
MVI C,B$READSEQ ;Read Sequential 'record' (sector)
|
||||
CALL BDOS
|
||||
ORA A ;Check if read unsuccessful (A = NZ)
|
||||
JNZ GETCX ;Yes
|
||||
MVI A,GETCBS ;Reset count
|
||||
STA GETCCC
|
||||
JMP GETCRE ;Re-enter subroutine
|
||||
;
|
||||
GETCX: ;Physical end of file
|
||||
MVI A,0FFH ;Indicate such
|
||||
RET
|
||||
|
||||
95
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-19.ASM
Normal file
95
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-19.ASM
Normal file
@@ -0,0 +1,95 @@
|
||||
; Figure 5-19
|
||||
;
|
||||
; PUTC
|
||||
; This subroutine either puts the next chararacter out
|
||||
; to a sequential file, writing out completed 'records'
|
||||
; (128-byte sectors) or, if requested to, will fill the
|
||||
; remainder of the current 'record' with 1AH's to indicate
|
||||
; End of File to CP/M.
|
||||
;
|
||||
; Entry Parameters
|
||||
;
|
||||
; DE -> File Control Block
|
||||
; B = 0, A = next data character to be output
|
||||
; B /= 0, fill the current 'record' with 1AH's
|
||||
;
|
||||
; Exit Parameters
|
||||
;
|
||||
; None.
|
||||
;
|
||||
; Calling sequence
|
||||
;
|
||||
; LXI D,FCB
|
||||
; MVI B,0 ;Not end of File
|
||||
; LDA CHAR
|
||||
; CALL PUTC
|
||||
; ..or
|
||||
; LXI D,FCB
|
||||
; MVI B,1 ;Indicate end of file
|
||||
; CALL PUTC
|
||||
;
|
||||
B$WRITESEQ EQU 21 ;Write Sequential
|
||||
B$SETDMA EQU 26 ;Set DMA Address
|
||||
BDOS EQU 5 ;BDOS Entry Point
|
||||
;
|
||||
PUTCBS EQU 128 ;Buffer Size
|
||||
PUTCBF: DS PUTCBS ;Declare buffer
|
||||
PUTCCC: DB 0 ;Char. count (initially 'empty')
|
||||
;
|
||||
PUTC:
|
||||
PUSH D ;Save FCB Address
|
||||
PUSH PSW ;Save data character
|
||||
MOV A,B ;Check if end of file requested
|
||||
ORA A
|
||||
JNZ PUTCEF ;Yes
|
||||
CALL PUTCGA ;No, get address of next free byte
|
||||
;HL -> next free byte
|
||||
;E = Current Char. count (as well as A)
|
||||
POP PSW ;Recover data character
|
||||
MOV M,A ;Save in buffer
|
||||
MOV A,E ;Get current character count
|
||||
INR A ;Update character count
|
||||
CPI PUTCBS ;Check if buffer full
|
||||
JZ PUTCWB ;Yes, write buffer
|
||||
STA PUTCCC ;No, save updated count
|
||||
POP D ;Dump FCB Address for return
|
||||
RET
|
||||
;
|
||||
PUTCEF: ;End of file
|
||||
POP PSW ;Dump data character
|
||||
CALL PUTCGA ;HL -> next free byte
|
||||
;A = Current character count
|
||||
PUTCCE: ;Copy EOF character
|
||||
CPI PUTCBS ;Check for end of buffer
|
||||
JZ PUTCWB ;Yes, write out the buffer
|
||||
MVI M,1AH ;No, store EOF in buffer
|
||||
INR A ;Update count
|
||||
INX H ;Update buffer pointer
|
||||
JMP PUTCCE ;Continue until end of buffer
|
||||
;
|
||||
PUTCWB: ;Write buffer
|
||||
XRA A ;Reset character count to 0
|
||||
STA PUTCCC
|
||||
LXI D,PUTCBF ;DE -> Buffer
|
||||
MVI C,B$SETDMA ;Set DMA Address -> Buffer
|
||||
CALL BDOS
|
||||
POP D ;Recover FCB Address
|
||||
MVI C,B$WRITESEQ ;Write Sequential Record
|
||||
CALL BDOS
|
||||
ORA A ;Check if error
|
||||
JNZ PUTCX ;Yes if A = NZ
|
||||
RET ;No, return to caller
|
||||
;
|
||||
PUTCX: ;Error exit
|
||||
MVI A,0FFH ;Indicate such
|
||||
RET
|
||||
;
|
||||
PUTCGA: ;Return with HL -> next free char.
|
||||
;and A = current char. count
|
||||
LDA PUTCCC ;Get current character count
|
||||
MOV E,A ;Make word value in DE
|
||||
MVI D,0
|
||||
LXI H,PUTCBF ;HL -> Base of buffer
|
||||
DAD D ;HL -> next free character
|
||||
RET
|
||||
|
||||
47
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-2.ASM
Normal file
47
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-2.ASM
Normal file
@@ -0,0 +1,47 @@
|
||||
; Figure 5-2
|
||||
;
|
||||
; EQUates for BDOS Function Code numbers.
|
||||
;
|
||||
B$SYSRESET EQU 0 ;System Reset
|
||||
B$CONIN EQU 1 ;Read Console Byte
|
||||
B$CONOUT EQU 2 ;Write Console Byte
|
||||
B$READIN EQU 3 ;Read "Reader" Byte
|
||||
B$PUNOUT EQU 4 ;Write "Punch" Byte
|
||||
B$LISTOUT EQU 5 ;Write Printer Byte
|
||||
B$DIRCONIO EQU 6 ;Direct Console I/O
|
||||
B$GETIO EQU 7 ;Get IOBYTE
|
||||
B$SETIO EQU 8 ;Set IOBYTE
|
||||
B$PRINTS EQU 9 ;Print String
|
||||
B$READCONS EQU 10 ;Read Console String
|
||||
B$CONST EQU 11 ;Read Console Status
|
||||
B$GETVER EQU 12 ;Get CP/M Version Number
|
||||
B$DSKRESET EQU 13 ;Disk System Reset
|
||||
B$SELDSK EQU 14 ;Select Disk
|
||||
B$OPEN EQU 15 ;Open File
|
||||
B$CLOSE EQU 16 ;Close File
|
||||
B$SEARCHF EQU 17 ;Search for First Name Match
|
||||
B$SEARCHN EQU 18 ;Search for Next Name Match
|
||||
B$ERASE EQU 19 ;Erase (delete) File
|
||||
B$READSEQ EQU 20 ;Read Sequential
|
||||
B$WRITESEQ EQU 21 ;Write Sequential
|
||||
B$CREATE EQU 22 ;Create File
|
||||
B$RENAME EQU 23 ;Rename File
|
||||
B$GETACTDSK EQU 24 ;Get Active (Logged-in) Disks
|
||||
B$GETCURDSK EQU 25 ;Get Current Default Disk
|
||||
B$SETDMA EQU 26 ;Set DMA (Read/Write) Address
|
||||
B$GETALVEC EQU 27 ;Get Allocation Vector Address
|
||||
B$SETDSKRO EQU 28 ;Set Disk to Read Only
|
||||
B$GETRODSKS EQU 29 ;Get Read Only Disks
|
||||
B$SETFAT EQU 30 ;Set File Attributes
|
||||
B$GETDPB EQU 31 ;Get Disk Parameter Block Address
|
||||
B$SETGETUN EQU 32 ;Set/Get User Number
|
||||
B$READRAN EQU 33 ;Read Random
|
||||
B$WRITERAN EQU 34 ;Write Random
|
||||
B$GETFSIZ EQU 35 ;Get File Size
|
||||
B$SETRANREC EQU 36 ;Set Random Record number
|
||||
B$RESETD EQU 37 ;Reset Drive
|
||||
B$WRITERANZ EQU 40 ;Write Random with Zero Fill
|
||||
;
|
||||
BDOS EQU 5 ;BDOS Entry Point
|
||||
|
||||
|
||||
38
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-20.ASM
Normal file
38
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-20.ASM
Normal file
@@ -0,0 +1,38 @@
|
||||
; Figure 5-20
|
||||
;
|
||||
; CF
|
||||
; Create File
|
||||
; This subroutine creates a file. It erases any previous
|
||||
; File before creating the new one.
|
||||
;
|
||||
; Entry Parameters
|
||||
;
|
||||
; DE -> File Control Block for new file
|
||||
;
|
||||
; Exit Parameters
|
||||
;
|
||||
; Carry Clear if operation successful (A = 0,1,2,3)
|
||||
; Carry Set if error (A = 0FFH)
|
||||
;
|
||||
; Calling Sequence
|
||||
;
|
||||
; LXI D,FCB
|
||||
; CALL CF
|
||||
; JC ERROR
|
||||
;
|
||||
B$ERASE EQU 19 ;Erase File
|
||||
B$CREATE EQU 22 ;Create File
|
||||
BDOS EQU 5 ;BDOS Entry Point
|
||||
;
|
||||
;
|
||||
CF:
|
||||
PUSH D ;Preserve FCB Pointer
|
||||
MVI C,B$ERASE ;Erase any existing file
|
||||
CALL BDOS
|
||||
POP D ;Recover FCB Pointer
|
||||
MVI C,B$CREATE ;Create (and open new file)
|
||||
CALL BDOS
|
||||
CPI 0FFH ;Carry set if OK, Clear if Error
|
||||
CMC ;Complete to use Carry set if Error
|
||||
RET
|
||||
|
||||
84
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-21.ASM
Normal file
84
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-21.ASM
Normal file
@@ -0,0 +1,84 @@
|
||||
; Figure 5-21
|
||||
;
|
||||
; RF
|
||||
; Rename File
|
||||
; This subroutine renames a file.
|
||||
; It uses the BF (Build FCB) subroutine shown in Figure 5.32
|
||||
;
|
||||
; Entry Parameters
|
||||
;
|
||||
; *** No case-folding of file names occurs ***
|
||||
; HL -> Old File Name (00-byte terminated)
|
||||
; DE -> New File Name (00-byte terminated)
|
||||
;
|
||||
; Exit Parameters
|
||||
;
|
||||
; Carry clear if operation successful (A = 0,1,2,3)
|
||||
; Carry set if error (A =0FFH)
|
||||
;
|
||||
; Calling sequence
|
||||
;
|
||||
; LXI H,OLDNAME ;HL -> Old Name
|
||||
; LXI D,NEWNAME ;DE -> New Name
|
||||
; CALL RF
|
||||
; JC ERROR
|
||||
;
|
||||
B$OPEN EQU 15 ;Open File
|
||||
B$RENAME EQU 23 ;Rename File
|
||||
BDOS EQU 5 ;BDOS Entry Point
|
||||
;
|
||||
RFFCB: DW 0,0,0,0,0,0,0,0,0 ;1 1/2 FCB's long
|
||||
DW 0,0,0,0,0,0,0,0,0
|
||||
DW 0,0,0,0,0,0,0,0,0
|
||||
;
|
||||
;
|
||||
RF:
|
||||
PUSH D ;Save New Name pointer
|
||||
LXI D,RFFCB ;Build Old Name FCB
|
||||
;HL already -> Old Name
|
||||
CALL BF
|
||||
|
||||
POP H ;Recover New Name pointer
|
||||
LXI D,RFFCB+16 ;Build new name in second part
|
||||
CALL BF ;of File Control Block
|
||||
|
||||
LXI D,RFFCB+16 ;Experimentally try
|
||||
MVI C,B$OPEN ;to Open the new File
|
||||
CALL BDOS ;to ensure it does not
|
||||
CPI 0FFH ;already exist
|
||||
MVI A,0FEH ;Assume error (flags unchanged)
|
||||
RC ;Carry set if A was 0,1,2,3
|
||||
|
||||
LXI D,RFFCB ;Rename the file
|
||||
MVI C,B$RENAME
|
||||
CALL BDOS
|
||||
CPI 0FFH ;Carry set if OK, clear if error
|
||||
CMC ;Invert to use Carry set if error
|
||||
RET
|
||||
;
|
||||
; BF
|
||||
; Build File Control Block
|
||||
; This subroutine formats a 00H-byte terminated string
|
||||
; (presumed to be a File Name) into an FCB, setting the
|
||||
; Disk, File name and Type and clearing the remainder of the
|
||||
; FCB to 0's.
|
||||
;
|
||||
; Entry Parameters
|
||||
;
|
||||
; DE -> File Control Block (36 Bytes)
|
||||
; HL -> File Name String (00H-byte terminated)
|
||||
;
|
||||
; Exit Parameters
|
||||
;
|
||||
; The built File Control block.
|
||||
;
|
||||
; Calling Sequence
|
||||
;
|
||||
; LXI D,FCB
|
||||
; LXI H,FILENAME
|
||||
; CALL BF
|
||||
;
|
||||
;
|
||||
BF:
|
||||
RET ;Dummy subroutine : see Figure 5.32.
|
||||
|
||||
79
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-22.ASM
Normal file
79
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-22.ASM
Normal file
@@ -0,0 +1,79 @@
|
||||
; Figure 5-22
|
||||
;
|
||||
; SFA
|
||||
; Set File Attributes
|
||||
; This subroutine takes a compressed bit map of all the
|
||||
; File Attribute bits, expands them out into an existing
|
||||
; File Control Block and then requests CP/M to set the
|
||||
; Attributes in the File Directory.
|
||||
;
|
||||
; Entry Parameters
|
||||
;
|
||||
; DE -> File Control Block
|
||||
; HL = Bit Map. Only the most significant 11 bits
|
||||
; are used, and correspond directly with the
|
||||
; possible attribute bytes.
|
||||
;
|
||||
; Exit Parameters
|
||||
;
|
||||
; Carry Clear if operation successful (A = 0,1,2,3)
|
||||
; Carry Set if error (A = 0FFH)
|
||||
;
|
||||
; Calling Sequence
|
||||
;
|
||||
; LXI D,FCB
|
||||
; LXI H,0000$0000$1100$0000B ;Bit Map
|
||||
; CALL SFA
|
||||
; JC ERROR
|
||||
;
|
||||
; File Attribute Equates
|
||||
;
|
||||
FA$F1 EQU 1000$0000$0000$0000B ;F1' )
|
||||
FA$F2 EQU 0100$0000$0000$0000B ;F2' ) Available for use
|
||||
FA$F3 EQU 0010$0000$0000$0000B ;F3' ) by Application Programs
|
||||
FA$F4 EQU 0001$0000$0000$0000B ;F4' )
|
||||
FA$F5 EQU 0000$1000$0000$0000B ;F5' ]
|
||||
FA$F6 EQU 0000$0100$0000$0000B ;F6' ] Reserved for CP/M
|
||||
FA$F7 EQU 0000$0010$0000$0000B ;F7' ]
|
||||
FA$F8 EQU 0000$0001$0000$0000B ;F8' ]
|
||||
;
|
||||
FA$T1 EQU 0000$0000$1000$0000B ;T1' - Read/Only File
|
||||
FA$RO EQU FA$T1
|
||||
FA$T2 EQU 0000$0000$0100$0000B ;T2' - System Files
|
||||
FA$SYS EQU FA$T2
|
||||
FA$T3 EQU 0000$0000$0010$0000B ;T3' - Reserved for CP/M
|
||||
;
|
||||
;
|
||||
B$SETFAT EQU 30 ;Set File Attributes
|
||||
BDOS EQU 5 ;BDOS Entry Point
|
||||
;
|
||||
;
|
||||
SFA:
|
||||
PUSH D ;Save FCB Pointer
|
||||
INX D ;HL -> 1st character of file name
|
||||
MVI C,8+3 ;Loop Count for File Name and Type
|
||||
SFAL: ;Main Processing Loop
|
||||
XRA A ;Clear Carry and A
|
||||
DAD H ;Shift next MS Bit into Carry
|
||||
ACI 0 ;A = 0 or 1 depending on Carry
|
||||
RRC ;Rotate LS bit of A into MS bit
|
||||
MOV B,A ;Save result (00H or 80H)
|
||||
XCHG ;HL -> FCB character
|
||||
MOV A,M ;Get FCB character
|
||||
ANI 7FH ;Isolate all but Attribute bit
|
||||
ORA B ;Set Attribute with result
|
||||
MOV M,A ;and store back into FCB
|
||||
XCHG ;DE -> FCB, HL = remaining bit map
|
||||
INX D ;DE -> Next character in FCB
|
||||
DCR C ;Downdate character count
|
||||
JNZ SFAL ;Loop back for next character
|
||||
MVI C,B$SETFAT ;Set File Attribute function code
|
||||
POP D ;Recover FCB Pointer
|
||||
CALL BDOS
|
||||
CPI 0FFH ;Carry set if OK, clear if error
|
||||
CMC ;Invert to use Carry set if error
|
||||
RET
|
||||
|
||||
|
||||
|
||||
|
||||
34
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-3.ASM
Normal file
34
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-3.ASM
Normal file
@@ -0,0 +1,34 @@
|
||||
; Figure 5-3
|
||||
;
|
||||
; Useful subroutines using the Write Console Byte
|
||||
; BDOS Function.
|
||||
;
|
||||
; MSGOUT
|
||||
; Output null-byte terminated message
|
||||
;
|
||||
; Calling sequence
|
||||
;
|
||||
; MESSAGE: DB 'Message',0
|
||||
; :
|
||||
; LXI H,MESSAGE
|
||||
; CALL MSGOUT
|
||||
;
|
||||
; Exit Parameters
|
||||
; HL -> Null byte terminator
|
||||
;
|
||||
B$CONOUT EQU 2 ;Write console byte
|
||||
BDOS EQU 5 ;BDOS Entry Point
|
||||
;
|
||||
MSGOUT:
|
||||
MOV A,M ;Get next byte for output
|
||||
ORA A
|
||||
RZ ;Return when null-byte
|
||||
INX H ;Update message pointer
|
||||
PUSH H ;Save updated pointer
|
||||
MOV E,A ;Ready for BDOS
|
||||
MVI C,B$CONOUT ;Function code
|
||||
CALL BDOS
|
||||
POP H ;Recover message pointer
|
||||
JMP MSGOUT ;Go back for next character
|
||||
|
||||
|
||||
37
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-4.ASM
Normal file
37
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-4.ASM
Normal file
@@ -0,0 +1,37 @@
|
||||
; Figure 5-4
|
||||
;
|
||||
; Useful subroutines using the Write Console Byte
|
||||
; BDOS Function.
|
||||
;
|
||||
; MSGOUTI (Message Out In-line)
|
||||
; Output null-byte terminated message that follows the
|
||||
; CALL to MSGOUTI.
|
||||
;
|
||||
; Calling sequence
|
||||
;
|
||||
; CALL MSGOUTI
|
||||
; DB 'Message',0
|
||||
; ... next instruction
|
||||
;
|
||||
; Exit Parameters
|
||||
; HL -> instruction following message
|
||||
;
|
||||
B$CONOUT EQU 2 ;Write console byte
|
||||
BDOS EQU 5 ;BDOS Entry Point
|
||||
;
|
||||
MSGOUTI:
|
||||
POP H ;HL -> Message
|
||||
MOV A,M ;Get next data byte
|
||||
INX H ;Update message pointer
|
||||
ORA A ;Check if null byte
|
||||
JNZ MSGOUTIC ;No, continue
|
||||
PCHL ;Yes, return to next instruction
|
||||
;after in-line message
|
||||
MSGOUTIC:
|
||||
PUSH H ;Save message pointer
|
||||
MOV E,A ;Ready for BDOS
|
||||
MVI C,B$CONOUT ;Function code
|
||||
CALL BDOS
|
||||
JMP MSGOUTI ;Go back for next char.
|
||||
|
||||
|
||||
55
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-5.ASM
Normal file
55
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-5.ASM
Normal file
@@ -0,0 +1,55 @@
|
||||
; Figure 5-5
|
||||
;
|
||||
; RL$RDR
|
||||
; Read Line from Reader Device.
|
||||
; Carriage Returns are ignored, and input terminates
|
||||
; when specified number of characters have been read
|
||||
; or a Line Feed is input.
|
||||
;
|
||||
; Note : Potential weakness is that there is no
|
||||
; timeout in this subroutine. It will wait forever
|
||||
; if no more characters arrive at the Reader device.
|
||||
;
|
||||
; Calling sequence
|
||||
;
|
||||
; LXI H,BUFFER
|
||||
; LXI B,MAXCOUNT
|
||||
; CALL RL$RDR
|
||||
;
|
||||
; Exit Parameters
|
||||
;
|
||||
; HL -> 00H byte terminating string
|
||||
; BC = Residual Count (0 if Max. chars read)
|
||||
; E = Last Character Read
|
||||
;
|
||||
B$READIN EQU 3 ;Reader Input
|
||||
BDOS EQU 5 ;BDOS Entry Point
|
||||
;
|
||||
CR EQU 0DH ;Carriage Return
|
||||
LF EQU 0AH ;Line Feed (Terminator)
|
||||
;
|
||||
RL$RDR:
|
||||
MOV A,C ;Check if count 0
|
||||
ORA B ;If count 0 on entry,
|
||||
MOV E,A ; fake last char. read (00H)
|
||||
JZ RL$RDRX ;Yes, exit
|
||||
PUSH B ;Save Max. Chars count
|
||||
PUSH H ;Save Buffer Pointer
|
||||
RL$RDRI: ;Loop back here to ignore char.
|
||||
MVI C,B$READIN
|
||||
CALL BDOS ;A = Character input
|
||||
MOV E,A ;Preserve copy of characters
|
||||
CPI CR ;Check if Carriage Return
|
||||
JZ RL$RDRI ;Yes, ignore it
|
||||
POP H ;Recover Buffer pointer
|
||||
POP B ;Recover Max. Count
|
||||
CPI LF ;Check if Line Feed
|
||||
JZ RL$RDRX ;Yes, exit
|
||||
MOV M,A ;No, store character in buffer
|
||||
INX H ;Update Buffer pointer
|
||||
DCX B ;Downdate count
|
||||
JMP RL$RDR ;Loop back for next char.
|
||||
RL$RDRX:
|
||||
MVI M,0 ;Null byte terminate buffer
|
||||
RET
|
||||
|
||||
46
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-6.ASM
Normal file
46
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-6.ASM
Normal file
@@ -0,0 +1,46 @@
|
||||
; Figure 5-6
|
||||
;
|
||||
; WL$PUN
|
||||
; Write Line to Punch device. Output terminates
|
||||
; when a 00H byte is encountered.
|
||||
; A Carriage Return is output when a Line Feed is
|
||||
; encountered.
|
||||
;
|
||||
; Calling sequence
|
||||
;
|
||||
; LXI H,BUFFER
|
||||
; CALL WL$PUN
|
||||
;
|
||||
; Exit Parameters
|
||||
;
|
||||
; HL -> 00H byte terminator
|
||||
;
|
||||
B$PUNOUT EQU 4
|
||||
BDOS EQU 5
|
||||
;
|
||||
CR EQU 0DH ;Carriage Return
|
||||
LF EQU 0AH ;Line Feed
|
||||
;
|
||||
WL$PUN:
|
||||
PUSH H ;Save Buffer pointer
|
||||
MOV A,M ;Get next character
|
||||
ORA A ;Check if 00H
|
||||
JZ WL$PUNX ;Yes, exit
|
||||
CPI LF ;Check if Line Feed
|
||||
CZ WL$PUNLF ;Yes, O/P CR
|
||||
MOV E,A ;Character to be output
|
||||
MVI C,B$PUNOUT ;Function Code
|
||||
CALL BDOS ;Output character
|
||||
POP H ;Recover Buffer pointer
|
||||
INX H ;Update to next char.
|
||||
JMP WL$PUN ;Output next char
|
||||
WL$PUNLF: ;Line Feed encountered
|
||||
MVI C,B$PUNOUT ;Function Code
|
||||
MVI E,CR ;Output a CR
|
||||
CALL BDOS
|
||||
MVI A,LF ;Recreate Line Feed
|
||||
RET ;Output LF
|
||||
WL$PUNX: ;Exit
|
||||
POP H ;Balance the stack
|
||||
RET
|
||||
|
||||
46
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-7.ASM
Normal file
46
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-7.ASM
Normal file
@@ -0,0 +1,46 @@
|
||||
; Figure 5-7
|
||||
;
|
||||
; WL$LST
|
||||
; Write Line to List device. Output terminates
|
||||
; when a 00H byte is encountered.
|
||||
; A Carriage Return is output when a Line Feed is
|
||||
; encountered.
|
||||
;
|
||||
; Calling sequence
|
||||
;
|
||||
; LXI H,BUFFER
|
||||
; CALL WL$LST
|
||||
;
|
||||
; Exit Parameters
|
||||
;
|
||||
; HL -> 00H byte terminator
|
||||
;
|
||||
B$LSTOUT EQU 5
|
||||
BDOS EQU 5
|
||||
;
|
||||
CR EQU 0DH ;Carriage Return
|
||||
LF EQU 0AH ;Line Feed
|
||||
;
|
||||
WL$LST:
|
||||
PUSH H ;Save Buffer pointer
|
||||
MOV A,M ;Get next character
|
||||
ORA A ;Check if 00H
|
||||
JZ WL$LSTX ;Yes, exit
|
||||
CPI LF ;Check if Line Feed
|
||||
CZ WL$LSTLF ;Yes, O/P CR
|
||||
MOV E,A ;Character to be output
|
||||
MVI C,B$LSTOUT ;Function Code
|
||||
CALL BDOS ;Output character
|
||||
POP H ;Recover Buffer pointer
|
||||
INX H ;Update to next char.
|
||||
JMP WL$LST ;Output next char
|
||||
WL$LSTLF: ;Line Feed encountered
|
||||
MVI C,B$LSTOUT ;Function Code
|
||||
MVI E,CR ;Output a CR
|
||||
CALL BDOS
|
||||
MVI A,LF ;Recreate Line Feed
|
||||
RET ;Output LF
|
||||
WL$LSTX: ;Exit
|
||||
POP H ;Balance the stack
|
||||
RET
|
||||
|
||||
284
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-8.ASM
Normal file
284
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG5-8.ASM
Normal file
@@ -0,0 +1,284 @@
|
||||
; Figure 5-8
|
||||
;
|
||||
;--------------------------------------------------------------
|
||||
; TESTBED CODE
|
||||
; Because of the complexity of this subroutine, the actual
|
||||
; testbed code has been left in this example. It assumes
|
||||
; that DDT or ZSID will be used to checkout
|
||||
IF 1 ;Change to IF 0 to disable testbed
|
||||
ORG 100H
|
||||
JMP START ;Bypass "variables" setup by DDT
|
||||
OPTIONS: DB 0 ;Option Flags
|
||||
TERMS: DB 'A','E','I',0 ;Terminators
|
||||
BUFFER DB 5 ;Max. Characters in Buffer
|
||||
DB 0 ;Actual Count
|
||||
DB 99,99,99,99,99,99,99 ;Data Bytes
|
||||
START:
|
||||
LXI H,BUFFER ;Get address of buffer
|
||||
LXI D,TERMS ;Address of terminator table
|
||||
LDA OPTIONS ;Get options set by DDT
|
||||
MOV B,A ;Put in correct register
|
||||
CALL RCS ;Enter subroutine
|
||||
CALL 38H ;Force DDT breakpoint
|
||||
JMP START ;Test again
|
||||
ENDIF ;End of testbed x`ce
|
||||
;---------------------------------------------------------------
|
||||
;
|
||||
; RCS : Read Console String (using Raw Input)
|
||||
;
|
||||
; Reads a string of characters into a memory buffer using
|
||||
; Raw Input. Supports options :
|
||||
;
|
||||
; * to echo characters or not (when echoing, a Carriage
|
||||
; Return will be echoed followed by Line Feed)
|
||||
; * warm boot on input of Control-C or not
|
||||
; * terminating input either on :
|
||||
; - max. no of chars input
|
||||
; - matching terminator character
|
||||
;
|
||||
; Calling Sequence
|
||||
;
|
||||
; LXI H,BUFFER Buffer has structure
|
||||
; BUFFER: DB 10 Max. size
|
||||
; DB 0 Actual Read
|
||||
; DS 10+1 Buffer area
|
||||
; MVI B,OPTIONS Options required (see EQUates)
|
||||
; LXI D,TERMS Pointer to 00H-byte terminated
|
||||
; Chars, any one of which is a terminator.
|
||||
; CALL RCS
|
||||
;
|
||||
; Exit Parameters
|
||||
;
|
||||
; BUFFER : Updated with data bytes and actual character count
|
||||
; input. (Does not include the terminator).
|
||||
; A = Terminating Code
|
||||
; 0 = Maximum number of characters input.
|
||||
; NZ = Terminator character found.
|
||||
;
|
||||
RCS$ECHO EQU 0000$0001B ;Input characters to be echoed
|
||||
RCS$ABORT EQU 0000$0010B ;Abort on Control-C
|
||||
RCS$FOLD EQU 0000$0100B ;Fold lower case to upper
|
||||
RCS$TERM EQU 0000$1000B ;DE -> Term. char. set
|
||||
;
|
||||
B$DIRCONIO EQU 6 ;Direct console I/O
|
||||
BDOS EQU 5 ;BDOS entry point
|
||||
|
||||
CTL$C EQU 03H ;Control-C
|
||||
CR EQU 0DH ;Carriage Return
|
||||
LF EQU 0AH ;Line Feed
|
||||
BS EQU 08H ;Backspace
|
||||
|
||||
RCS$ST: ;Internal standard terminator table
|
||||
DB 0DH ;Carriage return
|
||||
DB 0AH ;Line feed
|
||||
DB 0 ;End of table
|
||||
;
|
||||
RCS$BSS: ;Destructive backspace sequence
|
||||
DB BS,' ',BS,0
|
||||
;
|
||||
RCS: ;<<<<< Main Entry
|
||||
INX H ;HL -> Actual count
|
||||
MVI M,0 ;Reset to initial state
|
||||
DCX H ;HL -> Max. count
|
||||
RCS$L:
|
||||
PUSH H ;Save buffer pointer
|
||||
CALL RCS$GC ;Get character and execute :
|
||||
; ECHO, ABORT, and FOLD options
|
||||
;C = character input
|
||||
POP H ;Recover buffer pointer
|
||||
MVI A,RCS$TERM ;Check if user-specified terminator
|
||||
ANA B ;B = options
|
||||
JNZ RCS$UST ;User specified terminators
|
||||
LXI D,RCS$ST ;Standard terminators
|
||||
RCS$UST:
|
||||
CALL RCS$CT ;Check for terminator
|
||||
JZ RCS$NOTT ;Not terminator
|
||||
MOV B,A ;Preserve terminating char
|
||||
RCS$MCI: ;(Max. char input shares this code)
|
||||
MVI C,0 ;Terminate buffer
|
||||
CALL RCS$SC ;Save character
|
||||
MOV A,B ;Recover terminating char
|
||||
ORA A ;Set flags
|
||||
RET
|
||||
RCS$NOTT: ;Not a terminator
|
||||
MVI A,BS ;Check for backspace
|
||||
CMP C
|
||||
JZ RCS$BS ;Backspace entered
|
||||
CALL RCS$SC ;Save character in buffer
|
||||
CALL RCS$UC ;Update count
|
||||
JNZ RCS$L ;Not max. so get another char
|
||||
MVI B,0 ;Fake terminating char
|
||||
JMP RCS$MCI ;A = 0 for max. chars input
|
||||
;
|
||||
RCS$BS: ;Backspace entered
|
||||
PUSH H ;Save buffer pointer
|
||||
INX H ;HL -> actual count
|
||||
DCR M ;Backup one
|
||||
JM RCS$NBS ;Check if count now -ve
|
||||
LXI H,RCS$BSS ;HL -> Backspacing sequence
|
||||
MVI A,RCS$ECHO ;No, check if echoing
|
||||
ANA B ;(BS will have been echoed if so)
|
||||
JZ RCS$BSNE ;No, input BS not echoed
|
||||
INX H ;Bypass initial Backspace
|
||||
RCS$BSNE:
|
||||
PUSH B ;Save Options and character
|
||||
PUSH D ;Save terminator table pointer
|
||||
CALL WCS ;Write console string
|
||||
POP D ;Recover terminator table pointer
|
||||
POP B ;Recover options and character
|
||||
JMP RCS$BSX ;Exit from Backspace logic
|
||||
RCS$NBS:
|
||||
INR M ;Reset count to 0
|
||||
RCS$BSX:
|
||||
POP H ;Recover buffer pointer
|
||||
JMP RCS$L ;Get next character
|
||||
|
||||
RCS$SC: ;Save character in C in buffer
|
||||
;HL -> buffer pointer
|
||||
PUSH D ;Save terminator table pointer
|
||||
PUSH H ;Save buffer pointer
|
||||
INX H ;HL -> actual count in buffer
|
||||
MOV E,M ;Get actual count
|
||||
INR E ;Count of 0 points to first data byte
|
||||
MVI D,0 ;Make word value of actual count
|
||||
DAD D ;HL -> next free data byte
|
||||
MOV M,C ;Save data byte away
|
||||
POP H ;Recover buffer pointer
|
||||
POP D ;Recover terminator table pointer
|
||||
RET
|
||||
;
|
||||
RCS$UC: ;Update buffer count and check for max.
|
||||
;Return Z set if = to max, NZ if not
|
||||
;HL -> buffer on entry
|
||||
PUSH H ;Save buffer pointer
|
||||
MOV A,M ;Get max. count
|
||||
INX H ;HL -> actual count
|
||||
INR M ;Increase actual count
|
||||
CMP M ;Compare max. to actual
|
||||
POP H ;Recover buffer pointer
|
||||
RET ;Z-flag set
|
||||
;
|
||||
RCS$GC: ;Get character and execute
|
||||
; ECHO, ABORT and FOLD options
|
||||
PUSH D ;Save terminator table pointer
|
||||
PUSH H ;Save buffer pointer
|
||||
PUSH B ;Save option flags
|
||||
RCS$WT:
|
||||
MVI C,B$DIRCONIO ;Function code
|
||||
MVI E,0FFH ;Specify input
|
||||
CALL BDOS
|
||||
ORA A ;Check if data waiting
|
||||
JZ RCS$WT ;Go back and wait
|
||||
POP B ;Recover option flags
|
||||
MOV C,A ;Save data byte
|
||||
MVI A,RCS$ABORT ;Check if abort option enabled
|
||||
ANA B
|
||||
JZ RCS$NA ;No abort
|
||||
MVI A,CTL$C ;Check for control-C
|
||||
CMP C
|
||||
JZ 0 ;Warm boot
|
||||
RCS$NA:
|
||||
MVI A,RCS$FOLD ;Check if folding enabled
|
||||
ANA B
|
||||
CNZ TOUPPER ;Fold to UPPER CASE
|
||||
MVI A,RCS$ECHO ;Check if echo required
|
||||
ANA B
|
||||
JZ RCS$NE ;No echo required
|
||||
PUSH B ;Save options and character
|
||||
MOV E,C ;Move character for output
|
||||
MVI C,B$DIRCONIO ;Function code
|
||||
CALL BDOS ;Echo character
|
||||
POP B ;Recover options and character
|
||||
MVI A,CR ;Check if Carriage Return
|
||||
CMP C
|
||||
JNZ RCS$NE ;No
|
||||
PUSH B ;Save options and character
|
||||
MVI C,B$DIRCONIO ;Function code
|
||||
MVI E,LF ;Output line feed
|
||||
CALL BDOS
|
||||
POP B ;Recover options and character
|
||||
RCS$NE:
|
||||
POP H ;Recover buffer pointer
|
||||
POP D ;Recover terminator table
|
||||
RET ;Character in C
|
||||
;
|
||||
RCS$CT: ;Check for terminator
|
||||
;C = character just input
|
||||
;DE -> 00-byte character string of Term. Chars
|
||||
;Returns Z status if no match found, NZ if found
|
||||
; (with A = C = Terminating character)
|
||||
PUSH D ;Save table pointer
|
||||
RCS$CTL:
|
||||
LDAX D ;Get next terminator character
|
||||
ORA A ;Check for end of table
|
||||
JZ RCS$CTX ;No terminator matched
|
||||
CMP C ;Compare to input character
|
||||
JZ RCS$CTX ;Terminator matched
|
||||
INX D ;Move to next terminator
|
||||
JMP RCS$CTL ;loop to try next character in table
|
||||
RCS$CTX: ;Check terminator exit
|
||||
ORA A ;At this point, A will either be 0
|
||||
; if the end of the table has been
|
||||
; reached, or NZ if a match has been
|
||||
; found. The Z-flag will be set.
|
||||
POP D ;Recover table pointer
|
||||
RET
|
||||
|
||||
;
|
||||
; TOUPPER - Fold lower case letters to upper
|
||||
;
|
||||
; C = Character on entry and exit
|
||||
;
|
||||
TOUPPER:
|
||||
MVI A,'a'-1 ;Check if folding needed
|
||||
CMP C ;Compare to input char
|
||||
JNC TOUPX ;No, char is < or = 'a'-1
|
||||
MVI A,'z' ;Maybe, char is = or > 'a'
|
||||
CMP C
|
||||
JC TOUPX ;No, char is > 'z'
|
||||
MVI A,0DFH ;Fold character
|
||||
ANA C
|
||||
MOV C,A ;Return folded character
|
||||
TOUPX:
|
||||
RET
|
||||
;
|
||||
;
|
||||
; WCS - Write Console String (Using Raw I/O)
|
||||
;
|
||||
; Output terminates when a 00H byte is encountered.
|
||||
; A Carriage Return is output when a Line Feed is
|
||||
; encountered.
|
||||
;
|
||||
; Calling sequence
|
||||
;
|
||||
; LXI H,BUFFER
|
||||
; CALL WCS
|
||||
;
|
||||
; Exit Parameters
|
||||
;
|
||||
; HL -> 00H byte terminator
|
||||
;
|
||||
;
|
||||
WCS:
|
||||
PUSH H ;Save buffer pointer
|
||||
MOV A,M ;Get next character
|
||||
ORA A ;Check if 00H
|
||||
JZ WCSX ;Yes, exit
|
||||
CPI LF ;Check if Line Feed
|
||||
CZ WCSLF ;Yes, O/P CR
|
||||
MOV E,A ;Character to be output
|
||||
MVI C,B$DIRCONIO ;Function Code
|
||||
CALL BDOS ;Output character
|
||||
POP H ;Recover Buffer pointer
|
||||
INX H ;Update to next char.
|
||||
JMP WCS ;Output next char
|
||||
WCSLF: ;Line Feed encountered
|
||||
MVI C,B$DIRCONIO ;Function Code
|
||||
MVI E,CR ;Output a CR
|
||||
CALL BDOS
|
||||
MVI A,LF ;Recreate Line Feed
|
||||
RET ;Output LF
|
||||
WCSX: ;Exit
|
||||
POP H ;Balance the stack
|
||||
RET
|
||||
|
||||
252
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG7-5.ASM
Normal file
252
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG7-5.ASM
Normal file
@@ -0,0 +1,252 @@
|
||||
; Figure 7-5.
|
||||
;
|
||||
; Example Put CP/M
|
||||
;
|
||||
; This program writes out the CP/M Cold Boot Loader, the
|
||||
; CCP, BDOS and BIOS to a floppy diskette. It runs under
|
||||
; CP/M as a normal Transient Program.
|
||||
;
|
||||
Version EQU '01' ;Equates used in the sign on message
|
||||
Month EQU '07'
|
||||
Day EQU '24'
|
||||
Year EQU '82'
|
||||
;
|
||||
;
|
||||
; The actual PUTCPMF5.COM program consists of this code,
|
||||
; plus the BOOTF5.HEX, the CCP, BDOS and BIOS.
|
||||
;
|
||||
; When this program executes, the memory image should
|
||||
; look like this :
|
||||
;
|
||||
; Component Base Address
|
||||
; BIOS 1F80H
|
||||
; BDOS 1180H
|
||||
; CCP 0980H
|
||||
; BOOTF5 0780H
|
||||
;
|
||||
; The components are produced as follows :
|
||||
;
|
||||
; BIOS.HEX By assembling source code
|
||||
; BDOS ) From a CPMnn.COM file output
|
||||
; CCP ) by MOVCPM and SAVEd on disk
|
||||
; BOOTF5.HEX By assembling source code
|
||||
;
|
||||
; The components are pieced together using DDT with the
|
||||
; following commands :
|
||||
;
|
||||
; DDT CPMnn.COM
|
||||
; IPUTCPMF5.HEX
|
||||
; R (Reads in this program)
|
||||
; IBOOTF5.HEX
|
||||
; R680 (Reads in Boot at 0780H)
|
||||
; IBIOS.HEX
|
||||
; R2980 (Reads in BIOS at 1F80H)
|
||||
; G0 (Exit from DDT)
|
||||
; SAVE 40 PUTCPMF5.COM (Create final .COM file)
|
||||
;
|
||||
; The actual layout of the diskette is as follows :
|
||||
;
|
||||
; Track 0 Sector
|
||||
; 1 2 3 4 5 6 7 8 9
|
||||
; Head +-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
; 0 |Boot |<======== CCP ========>|<======= BDOS ========|
|
||||
; +-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
; 1 |====== BDOS ====>|<============= BIOS ============>|
|
||||
; +-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
; 10 11 12 13 14 15 16 17 18
|
||||
; Sector
|
||||
;
|
||||
; Equates for defining memory size and the base address and
|
||||
; length of the system components.
|
||||
;
|
||||
Memory$Size EQU 64 ;Number of Kbytes of RAM
|
||||
;
|
||||
; The BIOS Length must match that declared in the BIOS.
|
||||
;
|
||||
BIOS$Length EQU 0900H
|
||||
;
|
||||
Boot$Length EQU 512
|
||||
CCP$Length EQU 0800H ;Constant
|
||||
BDOS$Length EQU 0E00H ;Constant
|
||||
;
|
||||
Length$In$Bytes EQU CCP$Length + BDOS$Length + BIOS$Length
|
||||
;
|
||||
Start$Image EQU 980H - Boot$Length ;Address of CP/M Image
|
||||
Length$Image EQU Length$In$Bytes + Boot$Length
|
||||
;
|
||||
;
|
||||
; Disk Characteristics
|
||||
;
|
||||
; These equates describe the physical characteristics of
|
||||
; the floppy diskette so that the program can move from
|
||||
; one sector to the next, updating the track and resetting
|
||||
; the sector when necessary.
|
||||
;
|
||||
First$Sector$on$Track EQU 1
|
||||
Last$Sector$on$Track EQU 18
|
||||
Last$Sector$on$Head$0 EQU 9
|
||||
Sector$Size EQU 512
|
||||
;
|
||||
;
|
||||
; Controller Characteristics
|
||||
;
|
||||
; On this computer system, the floppy disk controller can write
|
||||
; multiple sectors in a single command. However, in order to
|
||||
; to produce a more general example it is shown only reading one
|
||||
; sector at a time.
|
||||
;
|
||||
Sectors$Per$Write EQU 1
|
||||
;
|
||||
;
|
||||
; Cold Boot Characteristics
|
||||
;
|
||||
Start$Track EQU 0 ;Initial values for CP/M image
|
||||
Start$Sector EQU 1 ;= " =
|
||||
Sectors$To$Write EQU (Length$Image + Sector$Size - 1) / Sector$Size
|
||||
;
|
||||
|
||||
;
|
||||
B$PRINTS EQU 9 ;Print string terminated by $
|
||||
BDOS EQU 5 ;BDOS Entry Point
|
||||
;
|
||||
;
|
||||
|
||||
ORG 100H
|
||||
Put$CPM:
|
||||
JMP Main$Code ;Enter main code body
|
||||
;For reasons of clarity, the main
|
||||
; data structures are shown before the
|
||||
; executable code.
|
||||
CR EQU 0DH ;Carriage Return
|
||||
LF EQU 0AH ;Line Feed
|
||||
;
|
||||
Signon$Message:
|
||||
DB CR,LF,'Put CP/M on Diskette'
|
||||
DB CR,LF
|
||||
DB 'Version '
|
||||
DW Version
|
||||
DB ' '
|
||||
DW Month
|
||||
DB '/'
|
||||
DW Day
|
||||
DB '/'
|
||||
DW Year
|
||||
DB CR,LF,'$'
|
||||
|
||||
;
|
||||
; Disk Control Tables
|
||||
;
|
||||
Disk$Control$5 EQU 45H ;5 1/4" Control Byte
|
||||
Command$Block$5 EQU 46H ;Control Table Pointer
|
||||
Disk$Status EQU 43H ;Completion status
|
||||
;
|
||||
;
|
||||
; The command table Track and DMA$Address can also be used
|
||||
; as working storage and updated as the load process
|
||||
; continues. The Sector in the command table cannot be
|
||||
; used directly as the disk controller requires it to be
|
||||
; the sector number on the specified head (1 - 9) rather
|
||||
; than the sector number on track. Hence a separate variable
|
||||
; must be used.
|
||||
;
|
||||
Sector: DB Start$Sector
|
||||
;
|
||||
Command$Table: DB 02H ;Command - Write
|
||||
Unit: DB 0 ;Unit (Drive) number = 0 or 1
|
||||
Head: DB 0 ;Head number = 0 or 1
|
||||
Track: DB Start$Track ;Used as working variable
|
||||
Sector$on$head: DB 0 ;Converted by low-level driver
|
||||
Byte$Count: DW Sector$Size * Sectors$Per$Write
|
||||
DMA$Address: DW Start$Image
|
||||
Next$Status: DW Disk$Status ;Pointer to next Status Block
|
||||
; if commands are chained.
|
||||
Next$Control: DW Disk$Control$5 ;Pointer to next Control Byte
|
||||
; if commands are chained.
|
||||
|
||||
Main$Code:
|
||||
LXI SP,Put$CPM ;Stack grows down below code
|
||||
|
||||
LXI D,Signon$Message ;Sign on
|
||||
MVI C,B$PRINTS ;Print string until $
|
||||
CALL BDOS
|
||||
|
||||
LXI H,Command$Table ;Point the disk controller at
|
||||
SHLD Command$Block$5 ; the command block
|
||||
|
||||
MVI C,Sectors$To$Write ;Set sector count
|
||||
Write$Loop:
|
||||
CALL Put$CPM$Write ;Write data onto diskette
|
||||
DCR C ;Downdate sector count
|
||||
JZ 0 ;Warm Boot
|
||||
|
||||
LXI H,Sector ;Update sector number
|
||||
MVI A,Sectors$Per$Write ; by adding on number of sectors
|
||||
ADD M ; by controller
|
||||
MOV M,A ;Save result
|
||||
MVI A,Last$Sector$On$Track + 1 ;Check if at end of track
|
||||
CMP M
|
||||
JNZ Not$End$Track
|
||||
|
||||
MVI M,First$Sector$On$Track ;Yes, reset to beginning
|
||||
LHLD Track ;Update Track number
|
||||
INX H
|
||||
SHLD Track
|
||||
|
||||
Not$End$Track:
|
||||
LHLD DMA$Address ;Update DMA Address
|
||||
LXI D,Sector$Size * Sectors$Per$Write
|
||||
DAD D
|
||||
SHLD DMA$Address
|
||||
JMP Write$Loop ;Write next block
|
||||
;
|
||||
Put$CPM$Write: ;At this point, the description of the
|
||||
; operation required is in the variables
|
||||
; contained in the Command Table, along
|
||||
; with the Sector variable.
|
||||
|
||||
PUSH B ;Save sector count in C
|
||||
|
||||
;------ Change this routine to match the disk controller in use ------
|
||||
|
||||
MVI B,0 ;Assume head 0
|
||||
LDA Sector ;Get requested sector
|
||||
MOV C,A ;Take a copy of it
|
||||
CPI Last$Sector$on$Head$0+1 ;Check if on head 1
|
||||
JC Head$0 ;No
|
||||
SUI Last$Sector$on$Head$0 ;Bias down for head 1
|
||||
MOV C,A ;Save copy
|
||||
INR B ;Set head 1
|
||||
Head$0:
|
||||
MOV A,B ;Get head
|
||||
STA Head
|
||||
MOV A,C ;Get sector
|
||||
STA Sector$On$Head
|
||||
|
||||
LXI H,Disk$Control$5 ;Activate controller
|
||||
MVI M,80H
|
||||
|
||||
Wait$For$Boot$Complete:
|
||||
MOV A,M ;Get status byte
|
||||
ORA A ;Check if complete
|
||||
JNZ Wait$For$Boot$Complete ;No
|
||||
;Yes, check for errors
|
||||
LDA Disk$Status
|
||||
CPI 80H
|
||||
JC Put$CPM$Error ;Yes, an error occurred
|
||||
|
||||
;------ End of Physical Write routine ------
|
||||
|
||||
POP B ;Recover sector count in C
|
||||
RET
|
||||
;
|
||||
Put$CPM$Error:
|
||||
LXI D,Put$CPM$Error$Message
|
||||
MVI C,B$PRINTS ;Print string until $
|
||||
CALL BDOS ;Output error message
|
||||
JMP Main$Code ;Restart the loader
|
||||
;
|
||||
|
||||
Put$CPM$Error$Message:
|
||||
DB CR,LF,'Error in writing CP/M - retrying...',CR,LF,'$'
|
||||
END Put$CPM
|
||||
|
||||
272
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG7-7.ASM
Normal file
272
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG7-7.ASM
Normal file
@@ -0,0 +1,272 @@
|
||||
; Figure 7-7.
|
||||
;
|
||||
; Example CP/M Cold Bootstrap Loader
|
||||
;
|
||||
; This program is written out to Track 0, Head 0, Sector 1
|
||||
; by the PUTCPMF5 program.
|
||||
; It is loaded into memory at location 100H on up by the
|
||||
; PROM-based bootstrap mechanism that gets control of the
|
||||
; CPU on power-up or system reset.
|
||||
;
|
||||
Version EQU '01' ;Equates used in the sign on message
|
||||
Month EQU '07'
|
||||
Day EQU '24'
|
||||
Year EQU '82'
|
||||
;
|
||||
Debug EQU 0 ;Set Non-zero to debug as normal
|
||||
; transient program
|
||||
;
|
||||
; The actual layout of the diskette is as follows :
|
||||
;
|
||||
; Track 0 Sector
|
||||
; 1 2 3 4 5 6 7 8 9
|
||||
; Head +-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
; 0 |Boot |<======== CCP ========>|<======= BDOS ========|
|
||||
; +-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
; 1 |====== BDOS ====>|<============= BIOS ============>|
|
||||
; +-----+-----+-----+-----+-----+-----+-----+-----+-----+
|
||||
; 10 11 12 13 14 15 16 17 18
|
||||
; Sector
|
||||
;
|
||||
; Equates for defining memory size and the base address and
|
||||
; length of the system components.
|
||||
;
|
||||
Memory$Size EQU 64 ;Number of Kbytes of RAM
|
||||
;
|
||||
; The BIOS Length must match that declared in the BIOS.
|
||||
;
|
||||
BIOS$Length EQU 0900H
|
||||
;
|
||||
CCP$Length EQU 0800H ;Constant
|
||||
BDOS$Length EQU 0E00H ;Constant
|
||||
;
|
||||
Length$In$K EQU ((CCP$Length + BDOS$Length + BIOS$Length) / 1024) + 1
|
||||
Length$In$Bytes EQU CCP$Length + BDOS$Length + BIOS$Length
|
||||
;
|
||||
IF NOT Debug
|
||||
CCP$Entry EQU (Memory$Size - Length$In$K) * 1024
|
||||
ENDIF
|
||||
IF Debug
|
||||
CCP$Entry EQU 3980H ;Read into a lower address.
|
||||
;This address is chosen to be above
|
||||
; the area into which DDT initially loads
|
||||
; and the 980H makes the addresses similar
|
||||
; to the SYSGEN values so that the memory
|
||||
; image can be checked with DDT.
|
||||
ENDIF
|
||||
|
||||
BDOS$Entry EQU CCP$Entry + CCP$Length + 6
|
||||
BIOS$Entry EQU CCP$Entry + CCP$Length + BDOS$Length
|
||||
;
|
||||
;
|
||||
; Disk Characteristics
|
||||
;
|
||||
; These equates describe the physical characteristics of
|
||||
; the floppy diskette so that the program can move from
|
||||
; one sector to the next, updating the track and resetting
|
||||
; the sector when necessary.
|
||||
;
|
||||
First$Sector$on$Track EQU 1
|
||||
Last$Sector$on$Track EQU 18
|
||||
Last$Sector$on$Head$0 EQU 9
|
||||
Sector$Size EQU 512
|
||||
;
|
||||
;
|
||||
; Controller Characteristics
|
||||
;
|
||||
; On this computer system, the floppy disk controller can read
|
||||
; multiple sectors in a single command. However, in order to
|
||||
; to produce a more general example it is shown only reading one
|
||||
; sector at a time.
|
||||
;
|
||||
Sectors$Per$Read EQU 1
|
||||
;
|
||||
;
|
||||
; Cold Boot Characteristics
|
||||
;
|
||||
Start$Track EQU 0 ;Initial values for CP/M image
|
||||
Start$Sector EQU 2 ;= " =
|
||||
Sectors$To$Read EQU (Length$In$Bytes + Sector$Size - 1) / Sector$Size
|
||||
;
|
||||
;
|
||||
;
|
||||
|
||||
ORG 100H
|
||||
Cold$Boot$Loader:
|
||||
JMP Main$Code ;Enter main code body
|
||||
;For reasons of clarity, the main
|
||||
; data structures are shown before the
|
||||
; executable code.
|
||||
CR EQU 0DH ;Carriage Return
|
||||
LF EQU 0AH ;Line Feed
|
||||
;
|
||||
Signon$Message:
|
||||
DB CR,LF,'CP/M Bootstrap Loader'
|
||||
IF Debug
|
||||
DB ' (Debug)'
|
||||
ENDIF
|
||||
DB CR,LF
|
||||
DB 'Version '
|
||||
DW Version
|
||||
DB ' '
|
||||
DW Month
|
||||
DB '/'
|
||||
DW Day
|
||||
DB '/'
|
||||
DW Year
|
||||
DB CR,LF,0
|
||||
|
||||
;
|
||||
; Disk Control Tables
|
||||
;
|
||||
Disk$Control$5 EQU 45H ;5 1/4" Control Byte
|
||||
Command$Block$5 EQU 46H ;Control Table Pointer
|
||||
Disk$Status EQU 43H ;Completion status
|
||||
;
|
||||
;
|
||||
; The command table Track and DMA$Address can also be used
|
||||
; as working storage and updated as the load process
|
||||
; continues. The Sector in the command table cannot be
|
||||
; used directly as the disk controller requires it to be
|
||||
; the sector number on the specified head (1 - 9) rather
|
||||
; than the sector number on track. Hence a separate variable
|
||||
; must be used.
|
||||
;
|
||||
Sector: DB Start$Sector
|
||||
;
|
||||
Command$Table: DB 01H ;Command - Read
|
||||
Unit: DB 0 ;Unit (Drive) number = 0 or 1
|
||||
Head: DB 0 ;Head number = 0 or 1
|
||||
Track: DB Start$Track ;Used as working variable
|
||||
Sector$on$head: DB 0 ;Converted by low-level driver
|
||||
Byte$Count: DW Sector$Size * Sectors$Per$Read
|
||||
DMA$Address: DW CCP$Entry
|
||||
Next$Status: DW Disk$Status ;Pointer to next Status Block
|
||||
; if commands are chained.
|
||||
Next$Control: DW Disk$Control$5 ;Pointer to next Control Byte
|
||||
; if commands are chained.
|
||||
|
||||
Main$Code:
|
||||
LXI SP,Cold$Boot$Loader ;Stack grows down below code
|
||||
|
||||
LXI H,Signon$Message ;Sign on
|
||||
CALL Display$Message
|
||||
|
||||
LXI H,Command$Table ;Point the disk controller at
|
||||
SHLD Command$Block$5 ; the command block
|
||||
|
||||
MVI C,Sectors$To$Read ;Set sector count
|
||||
Load$Loop:
|
||||
CALL Cold$Boot$Read ;Read data into memory
|
||||
DCR C ;Downdate sector count
|
||||
|
||||
IF NOT Debug
|
||||
JZ BIOS$Entry ;Enter BIOS when load done
|
||||
ENDIF
|
||||
IF Debug
|
||||
JZ 0 ;Warm Boot
|
||||
ENDIF
|
||||
|
||||
LXI H,Sector ;Update sector number
|
||||
MVI A,Sectors$Per$Read ; by adding on number of sectors
|
||||
ADD M ; by controller
|
||||
MOV M,A ;Save result
|
||||
MVI A,Last$Sector$On$Track + 1 ;Check if at end of track
|
||||
CMP M
|
||||
JNZ Not$End$Track
|
||||
|
||||
MVI M,First$Sector$On$Track ;Yes, reset to beginning
|
||||
LHLD Track ;Update Track number
|
||||
INX H
|
||||
SHLD Track
|
||||
|
||||
Not$End$Track:
|
||||
LHLD DMA$Address ;Update DMA Address
|
||||
LXI D,Sector$Size * Sectors$Per$Read
|
||||
DAD D
|
||||
SHLD DMA$Address
|
||||
JMP Load$Loop ;Read next block
|
||||
;
|
||||
Cold$Boot$Read: ;At this point, the description of the
|
||||
; operation required is in the variables
|
||||
; contained in the Command Table, along
|
||||
; with the Sector variable.
|
||||
|
||||
PUSH B ;Save sector count in C
|
||||
|
||||
;------ Change this routine to match the disk controller in use ------
|
||||
|
||||
MVI B,0 ;Assume head 0
|
||||
LDA Sector ;Get requested sector
|
||||
MOV C,A ;Take a copy of it
|
||||
CPI Last$Sector$on$Head$0+1 ;Check if on head 1
|
||||
JC Head$0 ;No
|
||||
SUI Last$Sector$on$Head$0 ;Bias down for head 1
|
||||
MOV C,A ;Save copy
|
||||
INR B ;Set head 1
|
||||
Head$0:
|
||||
MOV A,B ;Get head
|
||||
STA Head
|
||||
MOV A,C ;Get sector
|
||||
STA Sector$On$Head
|
||||
|
||||
LXI H,Disk$Control$5 ;Activate controller
|
||||
MVI M,80H
|
||||
|
||||
Wait$For$Boot$Complete:
|
||||
MOV A,M ;Get status byte
|
||||
ORA A ;Check if complete
|
||||
JNZ Wait$For$Boot$Complete ;No
|
||||
;Yes, check for errors
|
||||
LDA Disk$Status
|
||||
CPI 80H
|
||||
JC Cold$Boot$Error ;Yes, an error occurred
|
||||
|
||||
;------ End of Physical Read routine ------
|
||||
|
||||
POP B ;Recover sector count in C
|
||||
RET
|
||||
;
|
||||
Cold$Boot$Error:
|
||||
LXI H,Cold$Boot$Error$Message
|
||||
CALL Display$Message ;Output error message
|
||||
JMP Main$Code ;Restart the loader
|
||||
;
|
||||
|
||||
Cold$Boot$Error$Message:
|
||||
DB CR,LF,'Bootstrap Loader Error - retrying...',CR,LF,0
|
||||
;
|
||||
; Equates for Terminal Output
|
||||
;
|
||||
Terminal$Status$Port EQU 01H
|
||||
Terminal$Data$Port EQU 02H
|
||||
;
|
||||
Terminal$Output$Ready EQU 0000$0001B
|
||||
;
|
||||
;
|
||||
Display$Message: ;Displays the specified message on the console.
|
||||
;On entry, HL points to a stream of bytes to be
|
||||
;output. A 00H-byte terminates the message.
|
||||
MOV A,M ;Get next message byte
|
||||
ORA A ;Check if terminator
|
||||
RZ ;Yes, return to caller
|
||||
MOV C,A ;Prepare for output
|
||||
|
||||
Output$Not$Ready:
|
||||
IN Terminal$Status$Port ;Check if ready for output
|
||||
ANI Terminal$Output$Ready
|
||||
JZ Output$Not$Ready ;No, wait
|
||||
MOV A,C ;Get Data character
|
||||
OUT Terminal$Data$Port ;Output to Screen
|
||||
|
||||
INX H ;Move to next byte of message
|
||||
JMP Display$Message ;Loop until complete message output
|
||||
|
||||
;The PROM-based bootstrap loader checks
|
||||
; to see that the characters "CP/M"
|
||||
; are on the diskette bootstrap sector
|
||||
; before it transfers control to it.
|
||||
ORG 2E0H
|
||||
DB 'CP/M'
|
||||
END Cold$Boot$Loader
|
||||
|
||||
4448
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG8-10.ASM
Normal file
4448
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG8-10.ASM
Normal file
File diff suppressed because it is too large
Load Diff
102
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG8-6.ASM
Normal file
102
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG8-6.ASM
Normal file
@@ -0,0 +1,102 @@
|
||||
; Figure 8-6
|
||||
;
|
||||
; Device Table Equates
|
||||
; The drivers use an Device Table for each
|
||||
; Physical Device they service. The EQUates that follow
|
||||
; are used to access the various fields within the
|
||||
; Device Table.
|
||||
;
|
||||
; Port Numbers and Status Bits
|
||||
DT$Status$Port EQU 0 ;Device Status Port number
|
||||
DT$Data$Port EQU DT$Status$Port+1
|
||||
;Device Data Port number
|
||||
DT$Output$Ready EQU DT$DataPort+1
|
||||
;Output ready status mask
|
||||
DT$Input$Ready EQU DT$Output$Ready+1
|
||||
;Input ready status mask
|
||||
DT$DTR$Ready EQU DT$Input$Ready+1
|
||||
;DTR ready to send mask
|
||||
DT$Reset$Int$Port EQU DT$DTR$Ready+1
|
||||
;Port number used to reset an
|
||||
; interrupt
|
||||
DT$Reset$Int$Value EQU DT$Reset$Int$Port+1
|
||||
;Value output to reset interrupt
|
||||
DT$Detect$Error$Port EQU DT$Reset$Int$Value+1
|
||||
;Port number for error detect
|
||||
DT$Detect$Error$Value EQU DT$Detect$Error$Port+1
|
||||
;Mask for detecting error (parity etc.)
|
||||
DT$Reset$Error$Port EQU DT$Detect$Error$Value+1
|
||||
;Output to port to reset error
|
||||
DT$Reset$Error$Value EQU DT$Reset$Error$Port+1
|
||||
;Value to output to reset error
|
||||
DT$RTS$Control$Port EQU DT$Reset$Error$Value+1
|
||||
;Control port for lowering RTS
|
||||
DT$Drop$RTS$Value EQU DT$RTS$Control$Port+1
|
||||
;Value, when output, to drop RTS
|
||||
DT$Raise$RTS$Value EQU DT$Drop$RTS$Value+1
|
||||
;Value, when output, to raise RTS
|
||||
;
|
||||
; Device Logical Status (incl. Protocols)
|
||||
DT$Status EQU DT$Raise$RTS$Value+1
|
||||
;Status Bits
|
||||
DT$Output$Suspend EQU 0000$0001B ;Output suspended pending
|
||||
; Protocol action
|
||||
DT$Input$Suspend EQU 0000$0010B ;Input suspended until
|
||||
; buffer empties
|
||||
DT$Output$DTR EQU 0000$0100B ;Output uses DTR high to send
|
||||
DT$Output$Xon EQU 0000$1000B ;Output uses Xon/Xoff
|
||||
DT$Output$Etx EQU 0001$0000B ;Output uses Etx/Ack
|
||||
DT$Output$Timeout EQU 0010$0000B ;Output uses Timeout
|
||||
DT$Input$RTS EQU 0100$0000B ;Input uses RTS high to receive
|
||||
DT$Input$Xon EQU 1000$0000B ;Input uses Xon/Xoff
|
||||
;
|
||||
DT$Status$2 EQU DT$Status+1 ;Secondary Status Byte
|
||||
DT$Fake$Typeahead EQU 0000$0001B ;Requests Input$Status to
|
||||
;return "Data Ready" when
|
||||
;Control Characters are in
|
||||
;input buffer
|
||||
;
|
||||
DT$Etx$Count EQU DT$Status$2+1
|
||||
;No. of chars sent in Etx protocol
|
||||
DT$Etx$Message$Length EQU DT$Etx$Count+2
|
||||
;Specified message length
|
||||
;
|
||||
; Input Buffer values
|
||||
DT$Buffer$Base EQU DT$Etx$Message$Length+2
|
||||
;Address of Input Buffer
|
||||
DT$Put$Offset EQU DT$Buffer$Base+2
|
||||
;Offset for Putting chars into buffer
|
||||
DT$Get$Offset EQU DT$Put$Offset+1
|
||||
;Offset for Getting chars from buffer
|
||||
DT$Buffer$Length$Mask EQU DT$Get$Offset+1
|
||||
;Length of buffer - 1
|
||||
;Note : Buffer length must always be
|
||||
; a binary number; e.g. 32, 64 or 128
|
||||
;This mask then becomes :
|
||||
; 32 -> 31 (0001$1111B)
|
||||
; 64 -> 63 (0011$1111B)
|
||||
; 128 -> 127 (0111$1111B)
|
||||
;After the Get/Put offset has been
|
||||
;incremented it is ANDed with the mask
|
||||
;to reset it to zero when the end of
|
||||
;the buffer has been reached.
|
||||
DT$Character$Count EQU DT$Buffer$Length$Mask+1
|
||||
;Count of the number of characters
|
||||
; currently in the buffer
|
||||
DT$Stop$Input$Count EQU DT$Character$Count+1
|
||||
;Stop input when the count reaches
|
||||
; this value
|
||||
DT$Resume$Input$Count EQU DT$Stop$Input$Count+1
|
||||
;Resume input when the count reaches
|
||||
; this value
|
||||
DT$Control$Count EQU DT$Resume$Input$Count+1
|
||||
;Count of the number of control
|
||||
; characters in the buffer
|
||||
DT$Function$Delay EQU DT$Control$Count+1
|
||||
;Number of clock ticks to delay to
|
||||
; allow all characters after function
|
||||
; key lead-in to arrive
|
||||
DT$Initialize$Stream EQU DT$Function$Delay+1
|
||||
;Address of byte stream necessary to
|
||||
; initialize this device
|
||||
|
||||
342
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG9-5.ASM
Normal file
342
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIG9-5.ASM
Normal file
@@ -0,0 +1,342 @@
|
||||
; Figure 9-5
|
||||
;
|
||||
; This shows slightly more user-friendly error processor
|
||||
; for disk errors than that shown in the enhanced BIOS
|
||||
; in Figure 8-10.
|
||||
; This version outputs a recommended course of action
|
||||
; depending on the nature of the error detected.
|
||||
; Code that remains unchanged from Figure 8-10 has been
|
||||
; abbreviated.
|
||||
;
|
||||
; Dummy Equates and data declarations needed to get
|
||||
; an error free assembly of this example.
|
||||
;
|
||||
Floppy$Read$Code EQU 01H ;Read Command for controller
|
||||
Floppy$Write$Code EQU 02H ;Write Command for controller
|
||||
;
|
||||
Disk$Hung$Flag: DB 0 ;Set NZ when Watchdog timer times
|
||||
; out.
|
||||
Disk$Timer EQU 600 ;10 seconds delay (16.66ms tick)
|
||||
;
|
||||
Disk$Status$Block EQU 43H ;Address in memory where controller
|
||||
; returns status
|
||||
;Values from controller command table
|
||||
Floppy$Command: DB 0
|
||||
Floppy$Head: DB 0
|
||||
Floppy$Track: DB 0
|
||||
Floppy$Sector: DB 0
|
||||
|
||||
Deblocking$Required: DB 0 ;Flag set by SELDSK according
|
||||
; to selected disk type
|
||||
|
||||
Disk$Error$Flag: DB 0 ;Error flag returned to BDOS
|
||||
;
|
||||
In$Buffer$Disk: DB 0 ;Logical disk Id. relating to current
|
||||
; disk sector in deblocking buffer
|
||||
;
|
||||
; Equates for Messages
|
||||
;
|
||||
BELL EQU 07H ;Sound terminal Bell
|
||||
CR EQU 0DH ;Carriage Return
|
||||
LF EQU 0AH ;Line Feed
|
||||
;
|
||||
BDOS EQU 5 ;BDOS Entry Point (for system reset)
|
||||
;
|
||||
;
|
||||
;
|
||||
;
|
||||
No$Deblock$Retry:
|
||||
;----------------------------------------------------
|
||||
; Omitted code to setup disk controller command table
|
||||
; and initiate the disk operation
|
||||
;----------------------------------------------------
|
||||
JMP Wait$For$Disk$Complete
|
||||
;
|
||||
;
|
||||
Write$Physical: ;Write contents of Disk Buffer to
|
||||
; correct sector.
|
||||
MVI A,Floppy$Write$Code ;Get Write Function code
|
||||
JMP Common$Physical ;Go to common code
|
||||
Read$Physical: ;Read previously selected Sector
|
||||
; into Disk Buffer.
|
||||
MVI A,Floppy$Read$Code ;Get Read Function code
|
||||
Common$Physical:
|
||||
STA Floppy$Command ;Set command table
|
||||
|
||||
;
|
||||
Deblock$Retry: ;Re-entry point to re-try after error
|
||||
;---------------------------------------------------
|
||||
; Omitted code sets up disk controller command block
|
||||
; and initiates the disk operation
|
||||
;---------------------------------------------------
|
||||
;
|
||||
Wait$For$Disk$Complete: ;Wait until Disk Status Block indicates
|
||||
; operation has completed, then check
|
||||
; if any errors occurred.
|
||||
;On entry HL -> Disk Control byte
|
||||
XRA A ;Ensure hung flag clear
|
||||
STA Disk$Hung$Flag
|
||||
|
||||
LXI H,Disk$Timed$Out ;Setup Watchdog timer
|
||||
LXI B,Disk$Timer ;Time delay
|
||||
CALL Set$Watchdog
|
||||
Disk$Wait$Loop:
|
||||
MOV A,M ;Get control byte
|
||||
ORA A
|
||||
JZ Disk$Complete ;Operation done
|
||||
|
||||
LDA Disk$Hung$Flag ;Also check if timed out
|
||||
ORA A
|
||||
JNZ Disk$Error ;Will be set to 40H
|
||||
|
||||
JMP Disk$Wait$Loop
|
||||
|
||||
Disk$Timed$Out: ;Control arrives here from Watchdog
|
||||
; routine itself - so this is effectively
|
||||
; part of the interrupt service routine.
|
||||
MVI A,40H ;Set Disk Hung error code
|
||||
STA Disk$Hung$Flag ; into error flag to pull
|
||||
; control out of loop
|
||||
RET ;Return to Watchdog routine
|
||||
|
||||
Disk$Complete:
|
||||
LXI B,0 ;Reset Watchdog timer
|
||||
;HL is irrelevant here
|
||||
CALL Set$Watchdog
|
||||
|
||||
LDA Disk$Status$Block ;Complete - now check status
|
||||
CPI 80H ;Check if any errors occurred
|
||||
JC Disk$Error ;Yes
|
||||
;
|
||||
Disk$Error$Ignore:
|
||||
XRA A ;No
|
||||
STA Disk$Error$Flag ;Clear error flag
|
||||
RET
|
||||
|
||||
;
|
||||
; Disk Error Message handling
|
||||
;
|
||||
;
|
||||
Disk$Error$Messages: ;This table is scanned, comparing the
|
||||
; Disk Error Status with those in the
|
||||
; table. Given a match, or even when
|
||||
; then end of the table is reached, the
|
||||
; address following the status value
|
||||
; points to the correct advisory message text.
|
||||
; Following this is the address of an
|
||||
; error description message.
|
||||
DB 40H
|
||||
DW Disk$Advice1,Disk$Msg$40
|
||||
DB 41H
|
||||
DW Disk$Advice2,Disk$Msg$41
|
||||
DB 42H
|
||||
DW Disk$Advice3,Disk$Msg$42
|
||||
DB 21H
|
||||
DW Disk$Advice4,Disk$Msg$21
|
||||
DB 22H
|
||||
DW Disk$Advice5,Disk$Msg$22
|
||||
DB 23H
|
||||
DW Disk$Advice5,Disk$Msg$23
|
||||
DB 24H
|
||||
DW Disk$Advice6,Disk$Msg$24
|
||||
DB 25H
|
||||
DW Disk$Advice6,Disk$Msg$25
|
||||
DB 11H
|
||||
DW Disk$Advice7,Disk$Msg$11
|
||||
DB 12H
|
||||
DW Disk$Advice7,Disk$Msg$12
|
||||
DB 13H
|
||||
DW Disk$Advice7,Disk$Msg$13
|
||||
DB 14H
|
||||
DW Disk$Advice7,Disk$Msg$14
|
||||
DB 15H
|
||||
DW Disk$Advice7,Disk$Msg$15
|
||||
DB 16H
|
||||
DW Disk$Advice7,Disk$Msg$16
|
||||
DB 0 ;<== Terminator
|
||||
DW Disk$Advice7,Disk$Msg$Unknown ;Unmatched code
|
||||
;
|
||||
DEM$Entry$Size EQU 5 ;Entry size in Error Message Table
|
||||
;
|
||||
;
|
||||
; Message Texts
|
||||
;
|
||||
Disk$Msg$40: DB 'Hung',0 ;Timeout message
|
||||
Disk$Msg$41: DB 'Not Ready',0
|
||||
Disk$Msg$42: DB 'Write Protected',0
|
||||
Disk$Msg$21: DB 'Data',0
|
||||
Disk$Msg$22: DB 'Format',0
|
||||
Disk$Msg$23: DB 'Missing Data Mark',0
|
||||
Disk$Msg$24: DB 'Bus Timeout',0
|
||||
Disk$Msg$25: DB 'Controller Timeout',0
|
||||
Disk$Msg$11: DB 'Drive Address',0
|
||||
Disk$Msg$12: DB 'Head Address',0
|
||||
Disk$Msg$13: DB 'Track Address',0
|
||||
Disk$Msg$14: DB 'Sector Address',0
|
||||
Disk$Msg$15: DB 'Bus Address',0
|
||||
Disk$Msg$16: DB 'Illegal Command',0
|
||||
Disk$Msg$Unknown: DB 'Unknown',0
|
||||
;
|
||||
Disk$EM$1: ;Main disk error message - part 1
|
||||
DB BELL,CR,LF
|
||||
DB 'Disk ',0
|
||||
;
|
||||
;Error Text output next
|
||||
;
|
||||
Disk$EM$2: ;Main disk error message - part 2
|
||||
DB ' Error ('
|
||||
Disk$EM$Status: DB 0,0 ;Status code in Hex
|
||||
DB ')',CR,LF,' Drive '
|
||||
Disk$EM$Drive: DB 0 ;Disk Drive code, A,B...
|
||||
DB ', Head '
|
||||
Disk$EM$Head: DB 0 ;Head number
|
||||
DB ', Track '
|
||||
Disk$EM$Track: DB 0,0 ;Track number
|
||||
DB ', Sector '
|
||||
Disk$EM$Sector: DB 0,0 ;Sector number
|
||||
DB ', Operation - '
|
||||
DB 0 ;Terminator
|
||||
;
|
||||
Disk$EM$Read: DB 'Read.',0 ;Operation names
|
||||
Disk$EM$Write: DB 'Write.',0
|
||||
;
|
||||
Disk$Advice0: DB CR,LF,' ',0
|
||||
Disk$Advice1: DB 'Check disk loaded, Retry',0
|
||||
Disk$Advice2: DB 'Possible hardware problem',0
|
||||
Disk$Advice3: DB 'Write enable if correct disk, Retry',0
|
||||
Disk$Advice4: DB 'Retry several times',0
|
||||
Disk$Advice5: DB 'Reformat disk or use another disk',0
|
||||
Disk$Advice6: DB 'Hardware error, Retry',0
|
||||
Disk$Advice7: DB 'Hardware or Software error, Retry',0
|
||||
;
|
||||
Disk$Advice9: DB ', or call for help if error persists',CR,LF
|
||||
;
|
||||
Disk$Action$Confirm:
|
||||
DB 0 ;Set to character entered by user
|
||||
DB CR,LF,0
|
||||
;
|
||||
; Disk Error Processor
|
||||
;
|
||||
; This routine builds and outputs an error message.
|
||||
; The user is then given the opportunity to :
|
||||
;
|
||||
; R - Retry the operation that caused the error.
|
||||
; I - Ignore the error and attempt to continue.
|
||||
; A - Abort the program and return to CP/M.
|
||||
;
|
||||
Disk$Error:
|
||||
PUSH PSW ;Preserve error code from controller
|
||||
LXI H,Disk$EM$Status ;Convert code for message
|
||||
CALL CAH ;Converts A to hex
|
||||
|
||||
LDA In$Buffer$Disk ;Convert disk id. for message
|
||||
ADI 'A' ;Make into letter
|
||||
STA Disk$EM$Drive
|
||||
|
||||
LDA Floppy$Head ;Convert head number
|
||||
ADI '0'
|
||||
STA Disk$EM$Head
|
||||
|
||||
LDA Floppy$Track ;Convert track number
|
||||
LXI H,Disk$EM$Track
|
||||
CALL CAH
|
||||
|
||||
LDA Floppy$Sector ;Convert sector number
|
||||
LXI H,Disk$EM$Sector
|
||||
CALL CAH
|
||||
|
||||
LXI H,Disk$EM$1 ;Output first part of message
|
||||
CALL Output$Error$Message
|
||||
|
||||
POP PSW ;Recover error status code
|
||||
MOV B,A ;For comparisons
|
||||
LXI H,Disk$Error$Messages - DEM$Entry$Size
|
||||
;HL -> Table - one entry
|
||||
LXI D,DEM$Entry$Size ;For loop below
|
||||
Disk$Error$Next$Code:
|
||||
DAD D ;Move to next (or first) entry
|
||||
|
||||
MOV A,M ;Get code number from table
|
||||
ORA A ;Check if end of table
|
||||
JZ Disk$Error$Matched ;Yes - pretend a match occurred
|
||||
CMP B ;Compare to actual code
|
||||
JZ Disk$Error$Matched ;Yes - exit from loop
|
||||
JMP Disk$Error$Next$Code ;Check next code
|
||||
;
|
||||
Disk$Error$Matched:
|
||||
INX H ;HL -> Advisory text address
|
||||
MOV E,M
|
||||
INX H
|
||||
MOV D,M ;DE -> Advisory test
|
||||
PUSH D ;Save for later
|
||||
|
||||
INX H ;HL -> Message text address
|
||||
MOV E,M ;Get Address into DE
|
||||
INX H
|
||||
MOV D,M
|
||||
|
||||
XCHG ;HL -> Text
|
||||
CALL Output$Error$Message ;Display explanatory text
|
||||
|
||||
LXI H,Disk$EM$2 ;Display second part of message
|
||||
CALL Output$Error$Message
|
||||
|
||||
LXI H,Disk$EM$Read ;Choose operation text
|
||||
; (assume a read)
|
||||
LDA Floppy$Command ;Get controller command
|
||||
CPI Floppy$Read$Code
|
||||
JZ Disk$Error$Read ;Yes
|
||||
LXI H,Disk$EM$Write ;No - change address in HL
|
||||
Disk$Error$Read:
|
||||
CALL Output$Error$Message ;Display operation type
|
||||
|
||||
LXI H,Disk$Advice0 ;Display leading blanks
|
||||
CALL Output$Error$Message
|
||||
|
||||
POP H ;Recover Advisory text pointer
|
||||
CALL Output$Error$Message
|
||||
|
||||
LXI H,Disk$Advice9 ;Display trailing component
|
||||
CALL Output$Error$Message
|
||||
;
|
||||
Disk$Error$Request$Action: ;Ask the user what to do next
|
||||
CALL Request$User$Choice ;Display prompt and get single
|
||||
; character response (folded to
|
||||
; upper case)
|
||||
CPI 'R' ;Retry?
|
||||
JZ Disk$Error$Retry
|
||||
CPI 'A' ;Abort
|
||||
JZ System$Reset
|
||||
CPI 'I' ;Ignore
|
||||
JZ Disk$Error$Ignore
|
||||
JMP Disk$Error$Request$Action
|
||||
;
|
||||
Disk$Error$Retry: ;The decision on where to return to
|
||||
; depends on whether the operation
|
||||
; failed on a deblocked or
|
||||
; non-deblocked drive
|
||||
LDA Deblocking$Required
|
||||
ORA A
|
||||
JNZ Deblock$Retry
|
||||
JMP No$Deblock$Retry
|
||||
;
|
||||
System$Reset: ;This is a radical approach, but
|
||||
; it does cause CP/M to restart
|
||||
MVI C,0 ;System Reset
|
||||
CALL BDOS
|
||||
|
||||
;
|
||||
; Omitted subroutines (listed in full in Figure 8-10)
|
||||
;
|
||||
Set$Watchdog: ;Set Watchdog timer (to number of "ticks" in BC, and
|
||||
; to transfer control to (HL) if timer hits zero).
|
||||
CAH: ;Convert A to two ASCII hex characters, storing
|
||||
; the output in (HL) and (HL+1)
|
||||
Output$Error$Message: ;Display the 00-byte terminated error message
|
||||
; pointed to by HL. Output is directed only to
|
||||
; those console devices not being used for list
|
||||
; output as well.
|
||||
Request$User$Choice: ;Display prompt "Enter R, A, I..." and return
|
||||
; single keyboard character (upper case) in A
|
||||
RET ;Dummy
|
||||
|
||||
167
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIND.C
Normal file
167
CONTRIBUTIONS/cpm-handbook/cpmsrc/FIND.C
Normal file
@@ -0,0 +1,167 @@
|
||||
#define VN "1.0 02/11/83"
|
||||
/* FIND - This utility displays either a map showing on which disks and
|
||||
in which user numbers files matching the specified ambiguous
|
||||
file name are found, or it can display the actual names matched. */
|
||||
|
||||
#include <LIBRARY.H>
|
||||
|
||||
struct _dirpb dir_pb; /* directory management parameter block */
|
||||
struct _dir *dir_entry; /* pointer to directory entry (somewhere in
|
||||
dir_pb) */
|
||||
struct _scb scb; /* search control block */
|
||||
|
||||
char file_name[20]; /* formatted for display : un/d:FILENAME.TYP */
|
||||
|
||||
short cur_disk; /* current logical disk at start of program */
|
||||
int mcount; /* match count (no. of file names matched) */
|
||||
int dmcount; /* per disk match count */
|
||||
int lcount; /* line count (for lines displayed) */
|
||||
|
||||
int map_flag; /* 0 = show file names of matched files,
|
||||
NZ = show map of number of files */
|
||||
|
||||
/* The array below is used to tabulate the results for each
|
||||
disk drive, and for each user number on the drive.
|
||||
In addition, two extra "users" have been added for "Free"
|
||||
and "Used" values. */
|
||||
|
||||
unsigned disk_map[16][18]; /* Disk A -> P, Users 0 -> 15, Free, Used */
|
||||
#define USED_COUNT 16 /* "user" number for Used entities */
|
||||
#define FREE_COUNT 17 /* "user" number for Free entities */
|
||||
|
||||
|
||||
main(argc,argv)
|
||||
short argc; /* argument count */
|
||||
char *argv[]; /* argument vector (pointer to an array of chars) */
|
||||
{
|
||||
|
||||
printf("\nFIND Version %s (Library %s)",VN,LIBVN);
|
||||
chk_use(argc); /* check usage */
|
||||
cur_disk = bdos(GETDISK); /* get current default disk */
|
||||
|
||||
dm_clr(disk_map); /* reset disk map */
|
||||
|
||||
/* set search control block
|
||||
disks, name, type, user number, extent number,
|
||||
and number of bytes to compare - in this case, match all users,
|
||||
but only extent 0 */
|
||||
setscb(scb,argv[1],'?',0,13); /* set disks, name, type */
|
||||
|
||||
map_flag = usstrcmp("NAMES",argv[2]); /* set flag for map option */
|
||||
|
||||
lcount = dmcount = mcount = 0; /* initialize counts */
|
||||
|
||||
for (scb.scb_disk = 0; /* starting with logical disk A: */
|
||||
scb.scb_disk < 16; /* until logical disk P: */
|
||||
scb.scb_disk++) /* move to next logical disk */
|
||||
{
|
||||
|
||||
/* check if current disk has been selected for search */
|
||||
if (!(scb.scb_adisks & (1 << scb.scb_disk)))
|
||||
continue; /* no - so bypass this disk */
|
||||
|
||||
printf("\nSearching disk : %c",(scb.scb_disk + 'A'));
|
||||
lcount++; /* update line count */
|
||||
|
||||
dir_pb.dp_disk = scb.scb_disk; /* set to disk to be searched*/
|
||||
dmcount = 0; /* reset disk matched count */
|
||||
|
||||
if (!map_flag) /* if file names are to be displayed */
|
||||
putchar('\n'); /* move to column 1 */
|
||||
|
||||
/* set the directory to "closed", and force the get_nde
|
||||
function to open it. */
|
||||
dir_pb.dp_open = 0;
|
||||
|
||||
/* while not at the end of the directory, set a pointer to the
|
||||
next directory entry. */
|
||||
while(dir_entry = get_nde(dir_pb))
|
||||
{
|
||||
/* check if entry in use in order to update
|
||||
the free/used counts */
|
||||
|
||||
if (dir_entry -> de_userno == 0xE5) /* unused */
|
||||
disk_map[scb.scb_disk][FREE_COUNT]++;
|
||||
else /* in use */
|
||||
disk_map[scb.scb_disk][USED_COUNT]++;
|
||||
|
||||
/* select only those active entries that are the
|
||||
first extent (numbered 0) of a file that matches
|
||||
the name supplied by the user. */
|
||||
if (
|
||||
(dir_entry -> de_userno != 0xE5) &&
|
||||
(dir_entry -> de_extent == 0) &&
|
||||
(comp_fname(scb,dir_entry) == NAME_EQ)
|
||||
)
|
||||
{
|
||||
|
||||
mcount++; /* update matched counts */
|
||||
dmcount++; /* per disk count */
|
||||
|
||||
if (map_flag) /* check map option */
|
||||
{
|
||||
/* update disk map */
|
||||
disk_map[scb.scb_disk][dir_entry -> de_userno]++;
|
||||
}
|
||||
else /* display names */
|
||||
{
|
||||
conv_dfname(scb.scb_disk,dir_entry,file_name);
|
||||
printf("%s ",file_name);
|
||||
|
||||
/* check if need to start new line */
|
||||
if (!(dmcount % 4))
|
||||
{
|
||||
putchar('\n');
|
||||
if (++lcount > 18)
|
||||
{
|
||||
lcount = 0;
|
||||
printf("\nPress Space Bar to continue....");
|
||||
getchar();
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} /* end of directory */
|
||||
} /* all disks searched */
|
||||
|
||||
if (map_flag)
|
||||
{
|
||||
printf("\n Numbers show files in each User Number.");
|
||||
printf("\n --- User Numbers --- Dir. Entries");
|
||||
|
||||
dm_disp(disk_map,scb.scb_adisks); /* display disk map */
|
||||
}
|
||||
|
||||
if (mcount == 0)
|
||||
printf("\n --- File Not Found --- ");
|
||||
|
||||
bdos(SETDISK,cur_disk); /* reset to current disk */
|
||||
}
|
||||
|
||||
|
||||
chk_use(argc) /* check usage */
|
||||
/* This function checks that the correct number of
|
||||
parameters has been specified, outputting instructions
|
||||
if not.
|
||||
*/
|
||||
/* Entry Parameter */
|
||||
int argc; /* Count of the number of arguments on the command line */
|
||||
{
|
||||
|
||||
/* The minimum value of argc is 1 (for the program name itself),
|
||||
so argc is always one greater than the number of parameters
|
||||
on the command line */
|
||||
|
||||
if (argc == 1 || argc > 3)
|
||||
{
|
||||
printf("\nUsage :");
|
||||
printf("\n\tFIND d:filename.typ {NAMES}");
|
||||
printf("\n\t *:filename.typ (All disks)");
|
||||
printf("\n\t ABCD..OP:filename.typ (Selected Disks)");
|
||||
printf("\n\tNAMES option shows actual names rather than map.");
|
||||
exit();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
149
CONTRIBUTIONS/cpm-handbook/cpmsrc/FUNKEY.C
Normal file
149
CONTRIBUTIONS/cpm-handbook/cpmsrc/FUNKEY.C
Normal file
@@ -0,0 +1,149 @@
|
||||
#define VN "\nFUNKEY Vn 1.0 02/18/83"
|
||||
|
||||
#include <LIBRARY.H>
|
||||
|
||||
|
||||
int fnum; /* function key number to be programmed */
|
||||
char fstring[20]; /* string for function key */
|
||||
struct _fkt *pfk; /* pointer to function key table */
|
||||
|
||||
main(argc,argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
|
||||
if (argc == 1 || argc > 3)
|
||||
show_use();
|
||||
|
||||
pfk = get_cba(CB_FKT); /* set pointer to function key table */
|
||||
|
||||
if (usstrcmp("SHOW",argv[1]))
|
||||
{
|
||||
if (!isdigit(argv[1][0]))
|
||||
{
|
||||
printf("\n\007'%s' is an illegal function key.",
|
||||
argv[1]);
|
||||
show_use();
|
||||
}
|
||||
|
||||
fnum = atoi(argv[1]); /* convert function key number */
|
||||
|
||||
if (fnum > FK_ENTRIES)
|
||||
{
|
||||
printf("\n\007Function key number %d too large.",fnum);
|
||||
show_use();
|
||||
}
|
||||
|
||||
if (get_fs(fstring) > FK_LENGTH)
|
||||
{
|
||||
printf("\n\007Function key string is too long.");
|
||||
show_use();
|
||||
}
|
||||
|
||||
|
||||
pfk += fnum; /* update pointer to string */
|
||||
/* copy string into function key table */
|
||||
|
||||
/* check if function key input present */
|
||||
if (!(pfk -> fk_input[0]))
|
||||
{
|
||||
printf("\n\007Error : Function Key #%d is not set up to be programmed.",fnum);
|
||||
show_use();
|
||||
}
|
||||
strcpy(pfk -> fk_output,fstring);
|
||||
}
|
||||
else /* SHOW function specified */
|
||||
{
|
||||
printf(VN); /* display signon message */
|
||||
show_fun();
|
||||
}
|
||||
}
|
||||
|
||||
get_fs(string) /* get function string from command tail */
|
||||
char string[]; /* pointer to character string */
|
||||
{
|
||||
char *tail; /* pointer to command tail */
|
||||
short tcount; /* count of TOTAL characters in command tail */
|
||||
int slen; /* string length */
|
||||
|
||||
tail = 0x80; /* command line is in memory at 0080H */
|
||||
tcount = *tail++; /* set TOTAL count of characters in command tail */
|
||||
slen = 0; /* initialize string length */
|
||||
|
||||
while(tcount--) /* for all characters in the command tail */
|
||||
{
|
||||
if (*tail++ == '"') /* scan for first quotes */
|
||||
break;
|
||||
}
|
||||
if (!tcount) /* no quotes found */
|
||||
{
|
||||
printf("\n\007No leading quotes found.");
|
||||
show_use();
|
||||
}
|
||||
|
||||
++tcount; /* adjust tail count */
|
||||
while(tcount--) /* for all remaining characters in tail */
|
||||
{
|
||||
if (*tail == '"')
|
||||
{
|
||||
string[slen] = '\0'; /* add terminator */
|
||||
break; /* exit from loop */
|
||||
}
|
||||
string[slen] = *tail++; /* move char. from tail into string */
|
||||
|
||||
if (string[slen] == '<')
|
||||
string[slen] = 0x0A;
|
||||
++slen;
|
||||
}
|
||||
if (!tcount) /* no terminating quotes found */
|
||||
{
|
||||
printf("\n\007No trailing quotes found.");
|
||||
show_use();
|
||||
}
|
||||
return slen; /* return string length */
|
||||
}
|
||||
|
||||
|
||||
show_fun() /* display settings for all function keys */
|
||||
{
|
||||
struct _fkt *pfkt; /* local pointer to function keys */
|
||||
int count; /* count to access function keys */
|
||||
char *lf; /* pointer to '<' character (line feed) */
|
||||
|
||||
pfkt = get_cba(CB_FKT); /* set pointer to function key table */
|
||||
|
||||
for (count = 0; count <= FK_ENTRIES; count++)
|
||||
{
|
||||
if (pfkt -> fk_input[0]) /* key is programmed */
|
||||
{
|
||||
/* check if at physical end of table */
|
||||
if (pfkt -> fk_input == 0xFF)
|
||||
break; /* yes - break out of for-loop */
|
||||
strcpy(fstring,pfkt -> fk_output);
|
||||
/* convert all 0x0A chars to '<' */
|
||||
while (lf = strscn(fstring,"\012"))
|
||||
{
|
||||
*lf = '<';
|
||||
}
|
||||
|
||||
printf("\n\tKey #%d = '%s'",count,fstring);
|
||||
}
|
||||
++pfkt; /* move to next entry */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
show_use()
|
||||
{
|
||||
printf("\nFUNKEY sets a specific function key string.");
|
||||
printf("\n\tFUNKEY key-number \042string to be programmed<\042 ");
|
||||
printf("\n\t (Note : '<' is changed to line feed.)");
|
||||
printf("\n\t ( key-number is from 0 to %d.)",
|
||||
FK_ENTRIES-1);
|
||||
printf("\n\t ( string can be up to %d chars.)",
|
||||
FK_LENGTH);
|
||||
printf("\n\tFUNKEY SHOW (displays settings for all keys)");
|
||||
exit();
|
||||
}
|
||||
|
||||
|
||||
1363
CONTRIBUTIONS/cpm-handbook/cpmsrc/LIBRARY.C
Normal file
1363
CONTRIBUTIONS/cpm-handbook/cpmsrc/LIBRARY.C
Normal file
File diff suppressed because it is too large
Load Diff
322
CONTRIBUTIONS/cpm-handbook/cpmsrc/LIBRARY.H
Normal file
322
CONTRIBUTIONS/cpm-handbook/cpmsrc/LIBRARY.H
Normal file
@@ -0,0 +1,322 @@
|
||||
#define LIBVN "1.0" /* Library Version Number */
|
||||
/* 12:36 02/21/83 */
|
||||
|
||||
/* This file contains groups of useful definitions.
|
||||
It should be included at the front of any programs
|
||||
that use the functions in BLIB. */
|
||||
|
||||
|
||||
/* Definitions to make minor language modifications to C. */
|
||||
#define short char /* Short is not supported directly */
|
||||
|
||||
/* one of the functions (bv_make) in the library uses the BDS C
|
||||
function, alloc, to allocate memory. The following definitions
|
||||
are provided for alloc. */
|
||||
|
||||
struct _header /* header for block of memory allocated */
|
||||
{
|
||||
struct _header *_ptr; /* pointer to the next header in the chain */
|
||||
unsigned _size; /* number of bytes in the allocated block */
|
||||
};
|
||||
struct _header _base; /* declare the first header of the chain */
|
||||
struct _header *_allocp; /* used by alloc() and free() functions */
|
||||
|
||||
|
||||
/* BDOS Function Call Numbers. */
|
||||
|
||||
#define SETDISK 14 /* Set (Select) Disk */
|
||||
#define SEARCHF 17 /* Search First */
|
||||
#define SEARCHN 18 /* Search Next */
|
||||
#define DELETEF 19 /* Delete File */
|
||||
#define GETDISK 25 /* Get Default Disk (Currently Logged In) */
|
||||
#define SETDMA 26 /* Set DMA (Read/Write) address */
|
||||
#define GETDPARM 31 /* Get Disk Parameter Block address */
|
||||
#define GETUSER 32 /* Get Current User Number */
|
||||
#define SETUSER 32 /* Set Current User Number */
|
||||
|
||||
|
||||
/* Direct BIOS Calls.
|
||||
These definitions are for direct calls into the BIOS.
|
||||
WARNING - Using these makes program less transportable.
|
||||
Each symbol is related to its corresponding Jump in the
|
||||
BIOS Jump Vector.
|
||||
Only the more useful entries are defined. */
|
||||
|
||||
#define CONST 2 /* Console Status */
|
||||
#define CONIN 3 /* Console Input */
|
||||
#define CONOUT 4 /* Console Output */
|
||||
#define LIST 5 /* List Output */
|
||||
#define AUXOUT 6 /* Auxiliary Output */
|
||||
#define AUXIN 7 /* Auxiliary Input */
|
||||
|
||||
#define HOME 8 /* Home disk */
|
||||
#define SELDSK 9 /* Select logical disk */
|
||||
#define SETTRK 10 /* Set track */
|
||||
#define SETSEC 11 /* Set sector */
|
||||
#define SETDMA 12 /* Set DMA Address */
|
||||
#define DREAD 13 /* Disk read */
|
||||
#define DWRITE 14 /* Disk write */
|
||||
#define LISTST 15 /* List status */
|
||||
#define SECTRN 16 /* Sector translate */
|
||||
#define AUXIST 17 /* Auxiliary Input Status */
|
||||
#define AUXOST 18 /* Auxiliary Output Status */
|
||||
|
||||
/* "Private" entries in Jump Vector */
|
||||
#define CIOINIT 19 /* Specific Character I/O Initialization */
|
||||
#define SETDOG 20 /* Set Watchdog timer */
|
||||
#define CBGADDR 21 /* Configuration Block, Get Address */
|
||||
|
||||
|
||||
/* defines for accessing the Configuration Block */
|
||||
|
||||
#define CB_GET 21 /* bios jump number to access routine */
|
||||
#define DEV_INIT 19 /* bios jump to do device initialization */
|
||||
|
||||
#define CB_DATE 0 /* date in ASCII */
|
||||
#define CB_TIMEA 1 /* time in ASCII */
|
||||
#define CB_DTFLAGS 2 /* date, time flags */
|
||||
#define TIME_SET 0x01 /* this bit NZ means date has been set */
|
||||
#define DATE_SET 0x02 /* this bit NZ means time has been set */
|
||||
|
||||
#define CB_FIP 3 /* forced input pointer */
|
||||
#define CB_SUM 4 /* system startup message */
|
||||
|
||||
#define CB_CI 5 /* console input */
|
||||
#define CB_CO 6 /* console output */
|
||||
#define CB_AI 7 /* auxiliary input */
|
||||
#define CB_AO 8 /* auxiliary output */
|
||||
#define CB_LI 9 /* list input */
|
||||
#define CB_LO 10 /* list output */
|
||||
|
||||
#define CB_DTA 11 /* device table addresses */
|
||||
#define CB_C1224 12 /* clock 12/24 format flag */
|
||||
#define CB_RTCTR 13 /* real time clock tick rate (per second) */
|
||||
|
||||
#define CB_WDC 14 /* watchdog count */
|
||||
#define CB_WDA 15 /* watchdog address */
|
||||
|
||||
#define CB_FKT 16 /* function key table */
|
||||
#define CB_COET 17 /* console output escape table */
|
||||
|
||||
#define CB_D0_IS 18 /* device 0 initialization stream */
|
||||
#define CB_D0_BRC 19 /* device 0 baud rate constant */
|
||||
|
||||
#define CB_D1_IS 20 /* device 1 initialization stream */
|
||||
#define CB_D1_BRC 21 /* device 1 baud rate constant */
|
||||
|
||||
#define CB_D2_IS 22 /* device 2 initialization stream */
|
||||
#define CB_D2_BRC 23 /* device 2 baud rate constant */
|
||||
|
||||
#define CB_IV 24 /* interrupt vector */
|
||||
#define CB_LTCBO 25 /* long term config. block offset */
|
||||
#define CB_LTCBL 26 /* long term config. block length */
|
||||
|
||||
#define CB_PUBF 27 /* public files flag */
|
||||
#define CB_MCBUF 28 /* multi-command buffer */
|
||||
#define CB_POLLC 29 /* polled console flag */
|
||||
|
||||
|
||||
/* device numbers and names for physical devices */
|
||||
/* NOTE : Change these definitions for your computer system */
|
||||
|
||||
#define T_DEVN 0 /* Terminal */
|
||||
#define M_DEVN 1 /* Modem */
|
||||
#define P_DEVN 2 /* Printer */
|
||||
|
||||
#define MAXPDEV 2 /* maximum physical device number */
|
||||
|
||||
/* names for the physical devices */
|
||||
#define PN_T "TERMINAL"
|
||||
#define PN_M "MODEM"
|
||||
#define PN_P "PRINTER"
|
||||
|
||||
/* structure and definitions for function keys */
|
||||
|
||||
#define FK_ILENGTH 2 /* number of chars. input when f-key pressed
|
||||
NOTE : This does NOT include the ESCAPE */
|
||||
#define FK_LENGTH 16 /* length of string (not including fk_term) */
|
||||
#define FK_ENTRIES 18 /* number of function key entries in table */
|
||||
|
||||
struct _fkt /* function key table */
|
||||
{
|
||||
char fk_input[FK_ILENGTH]; /* lead-in character is not in table */
|
||||
char fk_output[FK_LENGTH]; /* output character string */
|
||||
char fk_term; /* safety terminating character */
|
||||
};
|
||||
|
||||
|
||||
/* definitions and structure for device tables */
|
||||
|
||||
/* protocol bits */
|
||||
/* Note : if the most significant bit is
|
||||
set = 1, then the set_proto function
|
||||
will logically OR in the value. This
|
||||
permits Input DTR to co-exist with
|
||||
Xon or Etx protocol. */
|
||||
|
||||
#define DT_ODTR 0x8004 /* output dtr high to send (OR'ed in) */
|
||||
#define DT_OXON 0x0008 /* output xon */
|
||||
#define DT_OETX 0x0010 /* output etx/ack */
|
||||
|
||||
#define DT_IRTS 0x8040 /* input RTS (OR'ed in) */
|
||||
#define DT_IXON 0x0080 /* input xon */
|
||||
|
||||
#define ALLPROTO 0xDC /* all protocols combined */
|
||||
|
||||
struct _dt /* device table */
|
||||
{
|
||||
char dt_f1[14]; /* filler */
|
||||
char dt_st1; /* status byte 1 - has protocol flags */
|
||||
char dt_st2; /* status byte 2 */
|
||||
unsigned dt_f2; /* filler */
|
||||
unsigned dt_etxml; /* etx/ack message length */
|
||||
char dt_f3[12]; /* filler */
|
||||
} ;
|
||||
|
||||
|
||||
/* Values returned by the comp_fname (compare file name) */
|
||||
|
||||
#define NAME_EQ 0 /* names equal */
|
||||
#define NAME_LT 1 /* name less than mask */
|
||||
#define NAME_GT 2 /* name greater than mask */
|
||||
#define NAME_NE 3 /* name not equal (and comparison ambiguous) */
|
||||
|
||||
|
||||
/* Structure for Standard CP/M File Control Block */
|
||||
|
||||
#define FCBSIZE 36 /* define the overall length of an FCB */
|
||||
|
||||
struct _fcb
|
||||
{
|
||||
short fcb_disk; /* logical disk (0 = default) */
|
||||
char fcb_fname[11]; /* file name, type (with attributes) */
|
||||
short fcb_extent; /* current extent */
|
||||
unsigned fcb_s12; /* reserved for CP/M */
|
||||
short fcb_reccnt; /* record count used in current extent */
|
||||
union /* allocation blocks can be either */
|
||||
{ /* single or double bytes */
|
||||
short fcbab_short[16];
|
||||
unsigned fcbab_long[8];
|
||||
} _fcbab;
|
||||
short fcb_currec; /* current record within extent */
|
||||
char fcb_ranrec[3]; /* record for random read/write */
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/* parameter block used for calls to the directory management routines */
|
||||
|
||||
#define DIR_BSZ 128 /* directory buffer size */
|
||||
|
||||
struct _dirpb
|
||||
{
|
||||
short dp_open; /* 0 to request directory to be opened */
|
||||
short dp_end; /* NZ when at end of directory */
|
||||
short dp_write; /* NZ to write current sector to disk */
|
||||
struct _dir *dp_entry; /* pointer to directory entry in buffer */
|
||||
char dp_buffer [DIR_BSZ]; /* directory sector buffer */
|
||||
char dp_disk; /* current logical disk */
|
||||
int dp_track; /* start track */
|
||||
int dp_sector; /* start sector */
|
||||
int dp_nument; /* number of directory entries */
|
||||
int dp_entrem; /* entries remaining to process */
|
||||
int dp_sptrk; /* number of sectors per track */
|
||||
int dp_nabpde; /* number of allocation blocks per dir. entry */
|
||||
unsigned dp_nab; /* number of allocation blocks */
|
||||
int dp_absize; /* allocation block size (in Kbytes) */
|
||||
};
|
||||
|
||||
/* The err_dir function is used to report errors found by the
|
||||
directory management routines, open_dir and rw_dir.
|
||||
Err_dir needs an parameter to define the operation being
|
||||
performed when the error occurred. The following #defines
|
||||
represent the operations possible. */
|
||||
|
||||
#define W_DIR 0 /* Writing Directory */
|
||||
#define R_DIR 1 /* Reading Directory */
|
||||
#define O_DIR 2 /* Opening Directory */
|
||||
|
||||
|
||||
/* disk parameter block maintained by CPM */
|
||||
|
||||
struct _dpb
|
||||
{
|
||||
unsigned dpb_sptrk; /* sectors per track */
|
||||
short dpb_bshift; /* block shift */
|
||||
short dpb_bmask; /* block mask */
|
||||
short dpb_emask; /* extent mask */
|
||||
unsigned dpb_maxabn; /* maximum allocation block number */
|
||||
unsigned dpb_maxden; /* maximum directory entry number */
|
||||
short dpb_rab0; /* allocation blocks reserved for */
|
||||
short dpb_rab1; /* directory blocks */
|
||||
unsigned dpb_diskca; /* disk changed workarea */
|
||||
unsigned dpb_trkoff; /* track offset */
|
||||
};
|
||||
|
||||
|
||||
/* disk directory entry format */
|
||||
|
||||
struct _dir {
|
||||
char de_userno; /* user number or 0xE5 if free entry */
|
||||
char de_fname[11]; /* file name [8] and type [3] */
|
||||
int de_extent; /* extent number of this entry */
|
||||
int de_reccnt; /* number of 128-byte records used in last
|
||||
allocation block */
|
||||
union /* allocation blocks can be either */
|
||||
{ /* single or double bytes */
|
||||
short de_short[16];
|
||||
unsigned de_long[8];
|
||||
} _dirab;
|
||||
};
|
||||
|
||||
/* disk request parameters for BIOS-level Read/Writes */
|
||||
|
||||
struct _drb
|
||||
{
|
||||
short dr_disk; /* logical disk A = 0, B = 1... */
|
||||
unsigned dr_track; /* track (for SETTRK) */
|
||||
unsigned dr_sector; /* sector (for SETSEC) */
|
||||
char *dr_buffer; /* buffer address (for SETDMA) */
|
||||
} ;
|
||||
|
||||
|
||||
/* search control block used by directory scanning functions */
|
||||
struct _scb
|
||||
{
|
||||
short scb_userno; /* user number(s) to match */
|
||||
char scb_fname[11]; /* file name and type */
|
||||
short scb_extent; /* extent number */
|
||||
char unused[19]; /* dummy bytes to make this appear like
|
||||
a file control block */
|
||||
short scb_length; /* number of bytes to compare */
|
||||
short scb_disk; /* current disk to be searched */
|
||||
unsigned scb_adisks; /* bit map of disks to be searched.
|
||||
The right-most bit is for disk A:. */
|
||||
} ;
|
||||
|
||||
|
||||
/* code table related definitions */
|
||||
|
||||
#define CT_SNF 0xFFFF /* String Not Found */
|
||||
|
||||
struct _ct /* define structure of code table */
|
||||
{
|
||||
unsigned _ct_code; /* code value */
|
||||
char *_ct_sp; /* string pointer */
|
||||
};
|
||||
|
||||
|
||||
/* Structure for bit-vectors */
|
||||
|
||||
struct _bv
|
||||
{
|
||||
unsigned bv_bytes; /* number of bytes in the vector */
|
||||
char *bv_bits; /* pointer to the first byte in the vector */
|
||||
char *bv_end; /* pointer to byte following bit vector */
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
/* End of LIBRARY.H */
|
||||
|
||||
187
CONTRIBUTIONS/cpm-handbook/cpmsrc/MAKE.C
Normal file
187
CONTRIBUTIONS/cpm-handbook/cpmsrc/MAKE.C
Normal file
@@ -0,0 +1,187 @@
|
||||
#define VN "1.0 02/12/83"
|
||||
/* MAKE - This utility is really two very similar programs
|
||||
according to the parameter specified on the command line.
|
||||
|
||||
INVISIBLE finds all of the specified files and moves them
|
||||
to user number 0 and sets them to be System and Read Only
|
||||
status. These files can then be accessed from user numbers
|
||||
other than 0 when the public files feature is enabled in the
|
||||
BIOS.
|
||||
|
||||
VISIBLE is the "opposite" in that the specified files are
|
||||
moved to the current user number and changed to Directory
|
||||
and Read Write status. */
|
||||
|
||||
#include <LIBRARY.H>
|
||||
|
||||
struct _dirpb dir_pb; /* directory management parameter block */
|
||||
struct _dir *dir_entry; /* pointer to directory entry */
|
||||
struct _scb scb; /* search control block */
|
||||
short to_user; /* user number to which files will be set */
|
||||
short from_user; /* user number from which files will be moved */
|
||||
|
||||
char file_name[20]; /* formatted for display : un/d:FILENAME.TYP */
|
||||
short name_flag; /* NZ to display names of files moved */
|
||||
|
||||
short cur_disk; /* current logical disk at start of program */
|
||||
|
||||
int mcount; /* match count (no. of file names matched) */
|
||||
|
||||
short invisible; /* NZ when parameter specifies Invisible */
|
||||
char *operation; /* pointer to either "Invisible" or "Visible" */
|
||||
|
||||
main(argc,argv)
|
||||
short argc; /* argument count */
|
||||
char *argv[]; /* argument vector (pointer to an array of chars) */
|
||||
{
|
||||
|
||||
printf("\nMAKE Version %s (Library %s)",VN,LIBVN);
|
||||
chk_use(argc); /* check usage */
|
||||
cur_disk = bdos(GETDISK); /* get current default disk */
|
||||
mcount = 0; /* initialize count */
|
||||
|
||||
|
||||
/* set the invisible flag according to the parameter */
|
||||
if (usstrcmp("VISIBLE",argv[2]) == 0)
|
||||
invisible = 0;
|
||||
else if (usstrcmp("INVISIBLE",argv[2]) == 0)
|
||||
invisible = 1;
|
||||
else
|
||||
{
|
||||
printf("\n\007Error : '%s' can only be INVISIBLE/VISIBLE.",argv[2]);
|
||||
exit();
|
||||
}
|
||||
|
||||
/* set the from_user and to_user numbers depending on which
|
||||
program is to be built, and the parameters specified. */
|
||||
|
||||
if (invisible)
|
||||
{
|
||||
from_user = bdos(GETUSER,0xFF); /* get current user number */
|
||||
to_user = 0; /* always move files to user 0 */
|
||||
operation = "Invisible"; /* set pointer to string */
|
||||
}
|
||||
else /* visible */
|
||||
{
|
||||
from_user = 0; /* always move from user 0 */
|
||||
to_user = bdos(GETUSER,0xFF); /* get current user */
|
||||
operation = "Visible"; /* set pointer to string */
|
||||
}
|
||||
|
||||
/* set search control block disks, name, type, user number,
|
||||
extent number and number of bytes to compare - in this
|
||||
case, match the 'from' user, all extents. */
|
||||
setscb(scb,argv[1],from_user,'?',13); /* set disks, name, type */
|
||||
|
||||
name_flag = usstrcmp("NAMES",argv[3]); /* set name suppress flag from param. 3 */
|
||||
|
||||
/* to simplify the logic below, name_flag must be made
|
||||
NZ if it is equal to NAME_EQ, 0 if it is any other value */
|
||||
name_flag = (name_flag == NAME_EQ ? 1 : 0);
|
||||
|
||||
|
||||
/* convert search user number and name for output */
|
||||
conv_dfname(scb.scb_disk,scb,file_name);
|
||||
printf("\n\nMoving files from User %d to %d and making them %s.",
|
||||
from_user,to_user,operation);
|
||||
|
||||
for (scb.scb_disk = 0; /* starting with logical disk A: */
|
||||
scb.scb_disk < 16; /* until logical disk P: */
|
||||
scb.scb_disk++) /* move to next logical disk */
|
||||
{
|
||||
|
||||
/* check if current disk has been selected for search */
|
||||
if (!(scb.scb_adisks & (1 << scb.scb_disk)))
|
||||
continue; /* no - so bypass this disk */
|
||||
|
||||
printf("\nSearching disk : %c",(scb.scb_disk + 'A'));
|
||||
|
||||
dir_pb.dp_disk = scb.scb_disk; /* set to disk to be searched*/
|
||||
|
||||
if (name_flag) /* if file names are to be displayed */
|
||||
putchar('\n'); /* move to column 1 */
|
||||
|
||||
|
||||
/* set the directory to "closed", and force the get_nde
|
||||
function to open it. */
|
||||
dir_pb.dp_open = 0;
|
||||
|
||||
/* while not at the end of the directory,
|
||||
set a pointer to the next directory entry. */
|
||||
while(dir_entry = get_nde(dir_pb))
|
||||
{
|
||||
|
||||
/* match those entries that have the correct
|
||||
user number, file name, type, and any
|
||||
extent number. */
|
||||
if (
|
||||
(dir_entry -> de_userno != 0xE5) &&
|
||||
(comp_fname(scb,dir_entry) == NAME_EQ)
|
||||
)
|
||||
{
|
||||
mcount++; /* update matched counts */
|
||||
|
||||
if (invisible)
|
||||
{ /* set ms bits */
|
||||
dir_entry -> de_fname[8] |= 0x80;
|
||||
dir_entry -> de_fname[9] |= 0x80;
|
||||
}
|
||||
else /* visible */
|
||||
{ /* clear ms bits */
|
||||
dir_entry -> de_fname[8] &= 0x7F;
|
||||
dir_entry -> de_fname[9] &= 0x7F;
|
||||
}
|
||||
|
||||
/* move to correct user number */
|
||||
dir_entry -> de_userno = to_user;
|
||||
|
||||
/* indicate sector to be written back */
|
||||
dir_pb.dp_write = 1;
|
||||
|
||||
/* check if name to be displayed */
|
||||
if (name_flag)
|
||||
{
|
||||
conv_dfname(scb.scb_disk,dir_entry,file_name);
|
||||
printf("\n\t%s made %s in User %d.",
|
||||
file_name,operation,to_user);
|
||||
}
|
||||
}
|
||||
} /* all directory entries processed */
|
||||
} /* all disks processed */
|
||||
|
||||
if (mcount == 0)
|
||||
printf("\n --- No Files Processed --- ");
|
||||
|
||||
bdos(SETDISK,cur_disk); /* reset to current disk */
|
||||
}
|
||||
|
||||
|
||||
chk_use(argc) /* check usage */
|
||||
/* This function checks that the correct number of
|
||||
parameters has been specified, outputting instructions
|
||||
if not.
|
||||
*/
|
||||
/* Entry Parameter */
|
||||
int argc; /* Count of the number of arguments on the command line */
|
||||
{
|
||||
|
||||
/* The minimum value of argc is 1 (for the program name itself),
|
||||
so argc is always one greater than the number of parameters
|
||||
on the command line */
|
||||
|
||||
if (argc == 3 || argc == 4)
|
||||
return;
|
||||
else
|
||||
{
|
||||
printf("\nUsage :");
|
||||
printf("\n\tMAKE d:filename.typ INVISIBLE {NAMES}");
|
||||
printf("\n\t VISIBLE");
|
||||
printf("\n\t *:filename.typ (All disks)");
|
||||
printf("\n\t ABCD..OP:filename.typ (Selected Disks)");
|
||||
printf("\n\tNAMES option shows names of files processed.");
|
||||
exit();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
182
CONTRIBUTIONS/cpm-handbook/cpmsrc/MOVE.C
Normal file
182
CONTRIBUTIONS/cpm-handbook/cpmsrc/MOVE.C
Normal file
@@ -0,0 +1,182 @@
|
||||
#define VN "1.0 02/10/83"
|
||||
/* MOVE - This utility moves file(s) from one user number to another,
|
||||
but on the SAME logical disk. Files are not actually copied -
|
||||
rather their directory entries are changed. */
|
||||
|
||||
#include <LIBRARY.H>
|
||||
|
||||
struct _dirpb dir_pb; /* directory management parameter block */
|
||||
struct _dir *dir_entry; /* pointer to directory entry */
|
||||
struct _scb scb; /* search control block */
|
||||
|
||||
|
||||
#define DIR_BSZ 128 /* directory buffer size */
|
||||
char dir_buffer[DIR_BSZ]; /* directory buffer */
|
||||
|
||||
char file_name[20]; /* formatted for display : un/d:FILENAME.TYP */
|
||||
short name_flag; /* NZ to display names of files moved */
|
||||
|
||||
short cur_disk; /* current logical disk at start of program */
|
||||
int from_user; /* user number from which to move files */
|
||||
int to_user; /* user number to which files will be moved */
|
||||
|
||||
int mcount; /* match count (no. of file names matched) */
|
||||
int dmcount; /* per disk match count */
|
||||
int lcount; /* line count (for lines displayed) */
|
||||
|
||||
|
||||
main(argc,argv)
|
||||
short argc; /* argument count */
|
||||
char *argv[]; /* argument vector (pointer to an array of chars) */
|
||||
{
|
||||
|
||||
printf("\nMOVE Version %s (Library %s)",VN,LIBVN);
|
||||
|
||||
chk_use(argc); /* check usage */
|
||||
|
||||
to_user = atoi(argv[2]); /* convert user no. to integer */
|
||||
/* set and chk destination user number */
|
||||
if(to_user > 15)
|
||||
{
|
||||
printf("\nError - the destination user number can not be greater than 15.");
|
||||
}
|
||||
|
||||
/* set the current user number */
|
||||
from_user = bdos(GETUSER,0xFF);
|
||||
|
||||
/* check if source user number specified */
|
||||
if (isdigit(argv[3][0]))
|
||||
{
|
||||
/* set and check source user number */
|
||||
if((from_user = atoi(argv[3])) > 15)
|
||||
{
|
||||
printf("\nError - the source user number can not be greater than 15.");
|
||||
exit();
|
||||
}
|
||||
|
||||
/* set name suppress flag from parameter #4 */
|
||||
name_flag = usstrcmp("NAMES",argv[4]);
|
||||
}
|
||||
else /* no source user specified */
|
||||
{
|
||||
/* set name suppress flag from parameter #3 */
|
||||
name_flag = usstrcmp("NAMES",argv[3]);
|
||||
}
|
||||
|
||||
/* to simplify the logic below, name_flag must be made
|
||||
NZ if it is equal to NAME_EQ, 0 if it is any other value */
|
||||
name_flag = (name_flag == NAME_EQ ? 1 : 0);
|
||||
|
||||
if (to_user == from_user) /* to = from */
|
||||
{
|
||||
printf("\nError - 'to' user number is the same as the 'from' user number.");
|
||||
exit();
|
||||
}
|
||||
|
||||
/* set the search control block file name, type, user number
|
||||
extent number and length - length matches user number, file
|
||||
name and type. As the extent number does not enter into the
|
||||
comparison, all extents of a given file will be found. */
|
||||
setscb(scb,argv[1],from_user,'?',13);
|
||||
|
||||
cur_disk = bdos(GETDISK); /* get current default disk */
|
||||
lcount = dmcount = mcount = 0; /* initialize counts */
|
||||
|
||||
for (scb.scb_disk = 0; /* starting with logical disk A: */
|
||||
scb.scb_disk < 16; /* until logical disk P: */
|
||||
scb.scb_disk++) /* move to next logical disk */
|
||||
{
|
||||
/* check if current disk has been selected for search */
|
||||
if (!(scb.scb_adisks & (1 << scb.scb_disk)))
|
||||
continue; /* no - so bypass this disk */
|
||||
|
||||
/* convert search user number and name for output */
|
||||
conv_dfname(scb.scb_disk,scb,file_name);
|
||||
printf("\n\nMoving file(s) %s -> User %d.",file_name,to_user);
|
||||
|
||||
lcount++; /* update line count */
|
||||
|
||||
dir_pb.dp_disk = scb.scb_disk; /* set to disk to be searched*/
|
||||
dmcount = 0; /* reset disk matched count */
|
||||
|
||||
if (name_flag) /* if file names are to be displayed */
|
||||
putchar('\n'); /* move to column 1 */
|
||||
|
||||
/* set the directory to "closed" to force the get_nde
|
||||
function to open it. */
|
||||
dir_pb.dp_open = 0;
|
||||
|
||||
/* while not at the end of the directory, set a pointer
|
||||
to the next directory entry */
|
||||
while(dir_entry = get_nde(dir_pb))
|
||||
{
|
||||
/* match those entries that have the correct
|
||||
user number, file name, type, and any
|
||||
extent number. */
|
||||
if (
|
||||
(dir_entry -> de_userno != 0xE5) &&
|
||||
(comp_fname(scb,dir_entry) == NAME_EQ)
|
||||
)
|
||||
{
|
||||
|
||||
dir_entry -> de_userno = to_user; /* move to new user */
|
||||
/* request sector to be written back */
|
||||
dir_pb.dp_write = 1;
|
||||
|
||||
mcount++; /* update matched counts */
|
||||
dmcount++; /* per disk count */
|
||||
|
||||
if (name_flag) /* check map option */
|
||||
{
|
||||
conv_dfname(scb.scb_disk,dir_entry,file_name);
|
||||
printf("%s ",file_name);
|
||||
|
||||
/* check if need to start new line */
|
||||
if (!(dmcount % 4))
|
||||
{
|
||||
putchar('\n');
|
||||
if (++lcount > 18)
|
||||
{
|
||||
lcount = 0;
|
||||
printf("\nPress Space Bar to continue....");
|
||||
getchar();
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mcount == 0)
|
||||
printf("\n --- No Files Moved --- ");
|
||||
|
||||
bdos(SETDISK,cur_disk); /* reset to current disk */
|
||||
}
|
||||
|
||||
|
||||
chk_use(argc) /* check usage */
|
||||
/* This function checks that the correct number of
|
||||
parameters has been specified, outputting instructions
|
||||
if not. */
|
||||
/* Entry Parameter */
|
||||
int argc; /* Count of the number of arguments on the command line */
|
||||
{
|
||||
|
||||
/* The minimum value of argc is 1 (for the program name itself),
|
||||
so argc is always one greater than the number of parameters
|
||||
on the command line */
|
||||
|
||||
if (argc == 1 || argc > 5)
|
||||
{
|
||||
printf("\nUsage :");
|
||||
printf("\n\tMOVE d:filename.typ to_user {from_user} {NAMES}");
|
||||
printf("\n\t *:filename.typ (All disks)");
|
||||
printf("\n\t ABCD..OP:filename.typ (Selected Disks)");
|
||||
printf("\n\tNAMES option shows names of files moved.");
|
||||
exit();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
5
CONTRIBUTIONS/cpm-handbook/cpmsrc/PRODUNIT.SUB
Normal file
5
CONTRIBUTIONS/cpm-handbook/cpmsrc/PRODUNIT.SUB
Normal file
@@ -0,0 +1,5 @@
|
||||
PIP $1:=$2:FIG*.*[V
|
||||
PIP $1:=$2:*.C[V
|
||||
PIP $1:=$2:READ.ME[V
|
||||
MOVEF $1:*.* 0
|
||||
|
||||
264
CONTRIBUTIONS/cpm-handbook/cpmsrc/PROTOCOL.C
Normal file
264
CONTRIBUTIONS/cpm-handbook/cpmsrc/PROTOCOL.C
Normal file
@@ -0,0 +1,264 @@
|
||||
#define VN "\nPROTOCOL Vn 1.0 02/17/83"
|
||||
/* PROTOCOL - This utility sets the serial port protocol for the
|
||||
specified physical device. Alternatively, it displays the
|
||||
current protocols for all of the serial devices. */
|
||||
|
||||
#include <LIBRARY.H>
|
||||
|
||||
/* code tables used to relate ASCII strings to code values */
|
||||
struct _ct ct_iproto[3]; /* code table for input protocols */
|
||||
struct _ct ct_oproto[4]; /* code table for output protocols */
|
||||
struct _ct ct_dproto[7]; /* code table for displaying protocols */
|
||||
struct _ct ct_pdev[MAXPDEV + 2]; /* physical device table */
|
||||
struct _ct ct_io[3]; /* input, output */
|
||||
|
||||
|
||||
/* parameters on the command line */
|
||||
#define PDEV argv[1] /* physical device */
|
||||
#define IO argv[2] /* input/output */
|
||||
#define PROTO argv[3] /* protocol */
|
||||
#define PROTOL argv[4] /* protocol message length */
|
||||
|
||||
|
||||
main(argc,argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
printf(VN); /* display signon message */
|
||||
setup(); /* setup code tables */
|
||||
chk_use(argc); /* check correct usage */
|
||||
|
||||
/* check if request to show current settings */
|
||||
if (usstrcmp("SHOW",argv[1]))
|
||||
{ /* no, assume a set is required */
|
||||
set_proto(get_pdev(PDEV), /* physical device */
|
||||
/* Input/Output and Protocol */
|
||||
get_proto(get_io(IO),PROTO),
|
||||
PROTOL); /* Protocol message length */
|
||||
}
|
||||
show_proto();
|
||||
|
||||
} /* end of program */
|
||||
|
||||
setup() /* setup the code tables for this program */
|
||||
{
|
||||
/* initialize the physical device table */
|
||||
ct_init(ct_pdev[0],0,PN_T); /* terminal */
|
||||
ct_init(ct_pdev[1],1,PN_P); /* printer */
|
||||
ct_init(ct_pdev[2],2,PN_M); /* modem */
|
||||
ct_init(ct_pdev[3],CT_SNF,"*"); /* terminator */
|
||||
|
||||
/* initialize the input/output table */
|
||||
ct_init(ct_io[0],0,"INPUT");
|
||||
ct_init(ct_io[1],1,"OUTPUT");
|
||||
ct_init(ct_io[2],CT_SNF,"*"); /* terminator */
|
||||
|
||||
/* initialize the output protocol table */
|
||||
ct_init(ct_oproto[0],DT_ODTR,"DTR");
|
||||
ct_init(ct_oproto[1],DT_OXON,"XON");
|
||||
ct_init(ct_oproto[2],DT_OETX,"ETX");
|
||||
ct_init(ct_oproto[3],CT_SNF,"*"); /* terminator */
|
||||
|
||||
/* initialize the input protocol table */
|
||||
ct_init(ct_iproto[0],DT_IRTS,"RTS");
|
||||
ct_init(ct_iproto[1],DT_IXON,"XON");
|
||||
ct_init(ct_iproto[2],CT_SNF,"*"); /* terminator */
|
||||
|
||||
/* initialize the display protocol */
|
||||
ct_init(ct_dproto[0],DT_ODTR,"Output DTR");
|
||||
ct_init(ct_dproto[1],DT_OXON,"Output XON");
|
||||
ct_init(ct_dproto[2],DT_OETX,"Output ETX");
|
||||
ct_init(ct_dproto[3],DT_IRTS,"Input RTS");
|
||||
ct_init(ct_dproto[4],DT_IXON,"Input XON");
|
||||
ct_init(ct_dproto[5],CT_SNF,"*");
|
||||
}
|
||||
|
||||
unsigned
|
||||
get_pdev(ppdev) /* get physical device */
|
||||
/* This function returns the physical device code
|
||||
specified by the user in the command line. */
|
||||
char *ppdev; /* pointer to character string */
|
||||
{
|
||||
unsigned retval; /* return value */
|
||||
|
||||
retval = ct_parc(ct_pdev,ppdev); /* get code for ASCII string */
|
||||
if (retval == CT_SNF) /* if string not found */
|
||||
{
|
||||
printf("\n\007Physical Device '%s' is invalid or ambiguous.",
|
||||
ppdev);
|
||||
printf("\nLegal Physical Devices are : ");
|
||||
ct_disps(ct_pdev); /* display all values */
|
||||
exit();
|
||||
}
|
||||
return retval; /* return code */
|
||||
}
|
||||
|
||||
unsigned
|
||||
get_io(pio) /* get input/output parameter */
|
||||
char *pio; /* pointer to character string */
|
||||
{
|
||||
unsigned retval; /* return value */
|
||||
|
||||
retval = ct_parc(ct_io,pio); /* get code for ASCII string */
|
||||
if (retval == CT_SNF) /* if string not found */
|
||||
{
|
||||
printf("\n\007Input/Output direction '%s' is invalid or ambiguous.",
|
||||
pio);
|
||||
printf("\nLegal values are : ");
|
||||
ct_disps(ct_io); /* display all values */
|
||||
exit();
|
||||
}
|
||||
return retval; /* return code */
|
||||
}
|
||||
|
||||
unsigned
|
||||
get_proto(output,pproto)
|
||||
/* This function returns the protocol code for the
|
||||
protocol specified by the user in the command line. */
|
||||
int output; /* =1 for output, =0 for input */
|
||||
char *pproto; /* pointer to character string */
|
||||
|
||||
{
|
||||
unsigned retval; /* return value */
|
||||
|
||||
if (output) /* OUTPUT specified */
|
||||
{
|
||||
/* get code for ASCII string */
|
||||
retval = ct_parc(ct_oproto,pproto);
|
||||
if (retval == CT_SNF) /* if string not found */
|
||||
{
|
||||
printf("\n\007Output Protocol '%s' is invalid or ambiguous.",
|
||||
pproto);
|
||||
printf("\nLegal Output Protocols are : ");
|
||||
ct_disps(ct_oproto); /* display valid protocols */
|
||||
exit();
|
||||
}
|
||||
}
|
||||
else /* INPUT specified */
|
||||
{
|
||||
/* get code for ASCII string */
|
||||
retval = ct_parc(ct_iproto,pproto);
|
||||
if (retval == CT_SNF) /* if string not found */
|
||||
{
|
||||
printf("\n\007Input Protocol '%s' is invalid or ambiguous.",
|
||||
pproto);
|
||||
printf("\nLegal Input Protocols are : ");
|
||||
ct_disps(ct_iproto); /* display valid protocols */
|
||||
exit();
|
||||
}
|
||||
}
|
||||
return retval; /* return code */
|
||||
}
|
||||
|
||||
|
||||
set_proto(pdevc,protoc,pplength) /* set the protocol for physical device */
|
||||
int pdevc; /* physical device code */
|
||||
unsigned protoc; /* protocol byte */
|
||||
char *pplength; /* pointer to protocol length */
|
||||
{
|
||||
struct _ppdt
|
||||
{
|
||||
char *pdt[16]; /* array of 16 pointers to the device tables */
|
||||
} ;
|
||||
struct _ppdt *ppdt; /* pointer to the device table array */
|
||||
struct _dt *dt; /* pointer to a device table */
|
||||
|
||||
ppdt = get_cba(CB_DTA); /* set pointer to array of pointers */
|
||||
dt = ppdt -> pdt[pdevc];
|
||||
|
||||
if (!dt) /* chk if pointer in array is valid */
|
||||
{
|
||||
printf("\nError - Array of Device Table Addresses is not set for device #%d.",
|
||||
pdevc);
|
||||
exit();
|
||||
}
|
||||
|
||||
if (protoc & 0x8000) /* check if protocol byte to be set
|
||||
directly or to be OR'ed in */
|
||||
{ /* OR'ed */
|
||||
dt -> dt_st1 |= (protoc & 0x7F);
|
||||
}
|
||||
else
|
||||
{ /* set directly */
|
||||
dt -> dt_st1 = (protoc & 0x7F);
|
||||
}
|
||||
|
||||
if ((protoc & 0x7F) == DT_OETX) /* if etx/ack, check for message
|
||||
length */
|
||||
{
|
||||
if (isdigit(*pplength)) /* check if length present */
|
||||
{
|
||||
/* convert length to binary and set device
|
||||
table field. */
|
||||
dt -> dt_etxml = atoi(pplength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
show_proto() /* show the current protocol settings */
|
||||
{
|
||||
struct _ppdt
|
||||
{
|
||||
char *pdt[16]; /* array of 16 pointers to the device tables */
|
||||
} ;
|
||||
struct _ppdt *ppdt; /* pointer to the device table array */
|
||||
struct _dt *dt; /* pointer to a device table */
|
||||
int pdevc; /* physical device code */
|
||||
struct _ct *dproto; /* pointer to display protocols */
|
||||
|
||||
ppdt = get_cba(CB_DTA); /* set pointer to array of pointers */
|
||||
|
||||
/* for all physical devices */
|
||||
for (pdevc = 0; pdevc <= MAXPDEV; pdevc++)
|
||||
{
|
||||
/* set pointer to device table */
|
||||
dt = ppdt -> pdt[pdevc];
|
||||
|
||||
if (dt) /* chk if pointer in array is valid */
|
||||
{
|
||||
printf("\n\tProtocol for %s - ",ct_strc(ct_pdev,pdevc));
|
||||
/* check if any protocols set */
|
||||
if (!(dt -> dt_st1 & ALLPROTO))
|
||||
{
|
||||
printf("None.");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* set pointer to display protocol table */
|
||||
dproto = ct_dproto;
|
||||
while (dproto -> _ct_code != CT_SNF)
|
||||
{
|
||||
/* check if protocol bit set */
|
||||
if (dproto -> _ct_code & dt -> dt_st1)
|
||||
{ /* display protocol */
|
||||
printf("%s ",dproto -> _ct_sp);
|
||||
}
|
||||
++dproto; /* move to next entry */
|
||||
}
|
||||
/* chk if etx/ack protocol and
|
||||
message length to be displayed */
|
||||
if (dt -> dt_st1 & DT_OETX)
|
||||
printf(" Message Length %d bytes.",
|
||||
dt -> dt_etxml);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
chk_use(argc) /* check for correct usage */
|
||||
int argc; /* argument count on commmand line */
|
||||
{
|
||||
if (argc == 1)
|
||||
{
|
||||
printf("\nPROTOCOL sets the physical device's serial protocols.");
|
||||
printf("\n\tPROTOCOL physical-device direction protocol {message-length}");
|
||||
printf("\n\nLegal physical devices are :");
|
||||
ct_disps(ct_pdev);
|
||||
printf("\nLegal direction/protocols are :");
|
||||
ct_disps(ct_dproto);
|
||||
printf("\n\tMessage length can be specifed with Output Etx.\n");
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
88
CONTRIBUTIONS/cpm-handbook/cpmsrc/READ.ME
Normal file
88
CONTRIBUTIONS/cpm-handbook/cpmsrc/READ.ME
Normal file
@@ -0,0 +1,88 @@
|
||||
[READ.ME]
|
||||
The Programmer's CP/M Handbook Source Code Examples
|
||||
Version 1.0 August 18, 1983
|
||||
(c) 1983 Johnson-Laird Inc.
|
||||
|
||||
W<EFBFBD> hav<61> trie<69> t<> includ<75> a<> man<61> o<> th<74> example<6C> fro<72> th<74> CP/<2F> <20>
|
||||
Programmer'<27> Handboo<6F> a<> wa<77> possibl<62> t<> fi<66> ont<6E> 2 single-sided
|
||||
single-density diskettes (or alternately, <20> single-densit<69> <20>
|
||||
double-side<64> "flippy" diskette)<29> Ou<4F> origina<6E> intentio<69> wa<77> t<> <20>
|
||||
includ<EFBFBD> th<74> sourc<72> cod<6F> fo<66> ever<65> figur<75> i<> th<74> boo<6F> a<> wel<65> a<> al<61> <20>
|
||||
th<EFBFBD> exampl<70> listing<6E> i<> Chapte<74> 5<> Sinc<6E> thi<68> prove<76> t<> b<> impossibl<62> <20>
|
||||
t<EFBFBD> fi<66> ont<6E> tw<74> diskettes<65> w<> hav<61> chose<73> thos<6F> figure<72> an<61> example<6C> <20>
|
||||
whic<EFBFBD> w<> fel<65> woul<75> b<> th<74> mos<6F> useful<75> Th<54> onl<6E> majo<6A> omissio<69> i<> <20>
|
||||
Figur<EFBFBD> 9-<2D> whic<69> deal<61> wit<69> ba<62> secto<74> management<6E>
|
||||
|
||||
W<EFBFBD> hav<61> fixe<78> on<6F> bu<62> an<61> adde<64> on<6F> lin<69> t<> Figur<75> 8-10<31> Thi<68> i<> <20>
|
||||
note<EFBFBD> i<> th<74> sourc<72> code<64> Th<54> line<6E> whic<69> wer<65> lef<65> ou<6F> i<> th<74> boo<6F> <20>
|
||||
afte<EFBFBD> pag<61> 26<32> ar<61> als<6C> included<65> Yo<59> ma<6D> notic<69> som<6F> mino<6E> <20>
|
||||
difference<EFBFBD> i<> capitalization<6F> indentation<6F> etc<74> i<> th<74> comment<6E> wher<65> <20>
|
||||
w<EFBFBD> hav<61> no<6E> include<64> change<67> mad<61> i<> copyediting.
|
||||
|
||||
W<EFBFBD> woul<75> appreciat<61> hearin<69> fro<72> you<6F> especiall<6C> abou<6F> an<61> bugs<67> <20>
|
||||
typos<EFBFBD> othe<68> horribl<62> goofs<66> suggestion<6F> fo<66> improvements.
|
||||
|
||||
Contents of Diskette No 1
|
||||
|
||||
Filename Page No. Figure Title
|
||||
|
||||
FIG5-2.AS<41> 70 Equate<74> fo<66> BDO<44> functio<69> cod<6F> numbers
|
||||
FIG5-3.ASM 74 Write console byte example, output null-byte
|
||||
terminated message from specified address
|
||||
FIG5-4.AS͠ 7<><37> Writ<69><74>consol<6F><6C>byt<79><74>example<6C><65>outpu<70><75>null-byt<79>
|
||||
terminate<74> messag<61> followin<69> cal<61> t<> subroutine
|
||||
FIG5-5.ASM 76 Read line from reader device
|
||||
FIG5-6.ASM 78 Write line to punch device
|
||||
FIG5-7.ASM 79 Write line to list device
|
||||
FIG5-8.AS<41> 8<> Read/Writ<69> strin<69> from/t<> consol<6F> usin<69> ra<72> I/O
|
||||
FIG5-10.ASM 86 IOBYTE equates
|
||||
FIG5-11.ASM 87 Simple terminal emulator
|
||||
FIG5-12.ASM 89 Display $-terminated message on console
|
||||
FIG5-13.ASM 92 Read console string for keyboard options
|
||||
FIG5-14.ASM 95 Determine the CP/M version number
|
||||
FIG5-15.ASM 96 Reset requested disk drive
|
||||
FIG5-16.ASM 100 Open file request
|
||||
FIG5-17.AS<41> 10<31> Searc<72> first/nex<65> call<6C> fo<66> ambiguou<6F> filenam<61>
|
||||
FIG5-18.ASM 110 Read next character from sequential disk file
|
||||
FIG5-19.ASM 113 Write next character to sequential disk file
|
||||
FIG5-20.ASM 115 Create file request
|
||||
FIG5-21.ASM 117 Rename file request
|
||||
FIG5-22.ASM 122 Set file attributes
|
||||
FIG5-23.ASM 123 Get file attributes
|
||||
FIG5-24.ASM 126 Accessing disk parameter block data
|
||||
FUNCTN33.ASM 131 Example for function 33, read random
|
||||
FIG5-25.ASM 135 Create random file
|
||||
FIG5-26.ASM 136 Read/write variable length records randomly
|
||||
FIG6-4.ASM 159 Simple BIOS listing
|
||||
<EFBFBD>FIG7-5.ASM 191 Example PUTCP/M
|
||||
FIG7-7.ASM 198 Example CP/M cold bootstrap loader
|
||||
FIG8-6.ASM 226 Device table equates
|
||||
FIG10-5.ASM 363 Testbed for real time clock driver in the BIOS
|
||||
FIG10-6.ASM 365 Testbed for disk I/O drivers in the BIOS
|
||||
ERASE.<2E> 41<34> Figur<75> 11-3<> request<73> confirmation before erasing
|
||||
UNERASE.C 412 Figure 11-4, "revives" erased files
|
||||
FIND.C 417 Figure 11-5, locates specific files or groups of files
|
||||
SPACE.<2E> 42<34> Figur<75> 11-6<> display<61> ho<68> muc<75> dis<69> storage is used
|
||||
or available
|
||||
MOVE.C 424 Figure 11-7, "moves" files from one user to another
|
||||
MAKE.C 428 Figure 11-8, makes files "invisible" and protected
|
||||
or makes them "visible," accessible and unprotected
|
||||
SPEED.C 431 Figure 11-9, sets the baud rate for a specific device
|
||||
PROTOCOL.C 435 Figure 11-10, sets the protocol governing input and output
|
||||
of a specified serial device
|
||||
ASSIGN.C 439 Figure 11-11, assigns a logical devices input and output
|
||||
to two or more physical devices
|
||||
DATE.C 443 Figure 11-12, makes the current date part of the system
|
||||
TIME.C 444 Figure 11-13, makes the current time part of the system
|
||||
FUNKEY.C 446 Figure 11-14, sets the character strings associated with
|
||||
specific function keys
|
||||
|
||||
Contents of Diskette 2
|
||||
|
||||
FIG8-10.ASM 237 Enhanced BIOS listing
|
||||
FIG9-5.ASM 312 User-friendly disk error processor
|
||||
FIG10-2.ASM 331 Debug subroutines
|
||||
FIG10-4.ASM 355 Testbed for character I/O drivers
|
||||
LIBRARY.C 372 Figure 11-1, commonly used functions in C
|
||||
LIBRARY.H 390 Figure 11-2, code to be included at the beginning of
|
||||
any program that calls LIBRARY functions in Figure 11-1
|
||||
229
CONTRIBUTIONS/cpm-handbook/cpmsrc/SPACE.C
Normal file
229
CONTRIBUTIONS/cpm-handbook/cpmsrc/SPACE.C
Normal file
@@ -0,0 +1,229 @@
|
||||
#define VN "1.0 02/11/83"
|
||||
/* SPACE - This utility displays a map showing on the amount of space
|
||||
(expressed as relative percentages) occupied in each user number
|
||||
for each logical disk). It also shows the relative amount of space
|
||||
free. */
|
||||
|
||||
#include <LIBRARY.H>
|
||||
|
||||
struct _dirpb dir_pb; /* directory management parameter block */
|
||||
struct _dir *dir_entry; /* pointer to directory entry */
|
||||
struct _scb scb; /* search control block */
|
||||
struct _dpb dpb; /* CP/M's disk parameter block */
|
||||
|
||||
char file_name[20]; /* formatted for display : un/d:FILENAME.TYP */
|
||||
|
||||
short cur_disk; /* current logical disk at start of program
|
||||
NZ = show map of number of files */
|
||||
int count; /* used to access the allocation block numbers
|
||||
in each directory entry */
|
||||
int user; /* used to access the disk map when calculating */
|
||||
|
||||
/* The array below is used to tabulate the results for each
|
||||
disk drive, and for each user number on the drive.
|
||||
In addition, two extra "users" have been added for "Free"
|
||||
and "Used" values.
|
||||
*/
|
||||
unsigned disk_map[16][18]; /* Disk A -> P, Users 0 -> 15, Free, Used */
|
||||
#define USED_COUNT 16 /* "user" number for Used entities */
|
||||
#define FREE_COUNT 17 /* "user" number for Free entities */
|
||||
|
||||
|
||||
main(argc,argv)
|
||||
short argc; /* argument count */
|
||||
char *argv[]; /* argument vector (pointer to an array of chars) */
|
||||
{
|
||||
|
||||
printf("\nSPACE Version %s (Library %s)",VN,LIBVN);
|
||||
chk_use(argc); /* check usage */
|
||||
cur_disk = bdos(GETDISK); /* get current default disk */
|
||||
|
||||
dm_clr(disk_map); /* reset disk map */
|
||||
|
||||
ssetscb(scb,argv[1]); /* special version : set disks,
|
||||
name, type */
|
||||
|
||||
for (scb.scb_disk = 0; /* starting with logical disk A: */
|
||||
scb.scb_disk < 16; /* until logical disk P: */
|
||||
scb.scb_disk++) /* move to next logical disk */
|
||||
{
|
||||
|
||||
/* check if current disk has been selected for search */
|
||||
if (!(scb.scb_adisks & (1 << scb.scb_disk)))
|
||||
continue; /* no - so bypass this disk */
|
||||
|
||||
printf("\nSearching disk : %c",(scb.scb_disk + 'A'));
|
||||
|
||||
dir_pb.dp_disk = scb.scb_disk; /* set to disk to be searched*/
|
||||
|
||||
/* set the directory to "closed", and force the get_nde
|
||||
function to open it. */
|
||||
dir_pb.dp_open = 0;
|
||||
|
||||
/* while not at the end of the directory, set a pointer
|
||||
to the next entry in the directory */
|
||||
while (dir_entry = get_nde(dir_pb))
|
||||
{
|
||||
if (dir_entry -> de_userno == 0xE5)
|
||||
continue; /* bypass inactive entries */
|
||||
|
||||
for (count = 0; /* start with the first alloc. block */
|
||||
count < dir_pb.dp_nabpde; /* for number of alloc. blks per dir. entry */
|
||||
count++)
|
||||
{
|
||||
if (dir_pb.dp_nabpde == 8) /* assume 8 2-byte numbers */
|
||||
{
|
||||
disk_map[scb.scb_disk][dir_entry -> de_userno]
|
||||
+= (dir_entry -> _dirab.de_long[count] > 0 ? 1 : 0);
|
||||
}
|
||||
else /* assume 16 1-byte numbers */
|
||||
{
|
||||
disk_map[scb.scb_disk][dir_entry -> de_userno]
|
||||
+= (dir_entry -> _dirab.de_short[count] > 0 ? 1 : 0);
|
||||
}
|
||||
} /* all allocation blocks processed */
|
||||
} /* end of directory for this disk */
|
||||
|
||||
|
||||
/* Compute the storage used by multiplying the number of
|
||||
allocation blocks counted by the number of Kbytes in
|
||||
each allocation block. */
|
||||
|
||||
for (user = 0; /* start with user 0 */
|
||||
user < 16; /* end with user 15 */
|
||||
user ++) /* move to next user number */
|
||||
{
|
||||
/* compute size occupied in Kbytes */
|
||||
disk_map[scb.scb_disk][user] *= dir_pb.dp_absize;
|
||||
/* build up sum for this disk */
|
||||
disk_map[scb.scb_disk][USED_COUNT] += disk_map[scb.scb_disk][user];
|
||||
}
|
||||
|
||||
/* free space = (# of alloc. blks * # of kbyte per blk)
|
||||
- used Kbytes
|
||||
- (directory entries * 32) / 1024 ... or divide by 32 */
|
||||
disk_map[scb.scb_disk][FREE_COUNT] = (dir_pb.dp_nab * dir_pb.dp_absize)
|
||||
- disk_map[scb.scb_disk][USED_COUNT]
|
||||
- (dir_pb.dp_nument >> 5); /* same as / 32 */
|
||||
} /* all disks processed */
|
||||
|
||||
|
||||
printf("\n Numbers show space used in kilobytes.");
|
||||
printf("\n --- User Numbers --- Space (Kb)");
|
||||
|
||||
dm_disp(disk_map,scb.scb_adisks); /* display disk map */
|
||||
|
||||
|
||||
bdos(SETDISK,cur_disk); /* reset to current disk */
|
||||
}
|
||||
|
||||
ssetscb(scb,ldisks) /* special version of - set search control block */
|
||||
/* This function sets up a search control block according
|
||||
to just the logical disks specified. The disk are specified as
|
||||
a single string of characters without any separators. An
|
||||
asterisk means "all disks". For example -
|
||||
|
||||
ABGH (disks A:, B:, G: and H: )
|
||||
* (all disks for which SELDSK has tables)
|
||||
|
||||
It sets the bit map according to which disks should be searched.
|
||||
For each selected disk, it checks to see if an error is generated
|
||||
when selecting the disk (i.e. if there are disk tables in the BIOS
|
||||
for the disk).
|
||||
The file name, type and extent number are all set to '?' to match
|
||||
all possible entries in the directory. */
|
||||
|
||||
/* Entry Parameters */
|
||||
struct _scb *scb; /* pointer to search control block */
|
||||
char *ldisks; /* pointer to the logical disks */
|
||||
|
||||
/* Exit Parameters
|
||||
None.
|
||||
*/
|
||||
{
|
||||
int disk; /* disk number currently being checked */
|
||||
unsigned adisks; /* bit map for active disks */
|
||||
|
||||
adisks = 0; /* assume no disks to search */
|
||||
|
||||
if (*ldisks) /* some values specified */
|
||||
{
|
||||
if (*ldisks == '*') /* check if "all disks" */
|
||||
{
|
||||
adisks = 0xFFFF; /* set all bits */
|
||||
}
|
||||
else /* set specific disks */
|
||||
{
|
||||
while(*ldisks) /* until end of disks reached */
|
||||
{
|
||||
/* build the bit map by getting the next disk
|
||||
id. (A - P), converting it to a number
|
||||
in the range 0 - 15, and shifting a 1-bit
|
||||
left that many places and OR-ing it into
|
||||
the current active disks.
|
||||
*/
|
||||
adisks |= 1 << (toupper(*ldisks) - 'A');
|
||||
++ldisks; /* move to next character */
|
||||
}
|
||||
}
|
||||
}
|
||||
else /* use only current default disk */
|
||||
{
|
||||
/* set just the bit corresponding to the current disk */
|
||||
adisks = 1 << bdos(GETDISK);
|
||||
}
|
||||
|
||||
/* set the user number, file name, type and extent to '?'
|
||||
so that all active directory entries will match */
|
||||
/* 0123456789012 */
|
||||
strcpy(&scb -> scb_userno,"?????????????");
|
||||
|
||||
/* Make calls to the BIOS SELDSK routine to make sure that
|
||||
all of the active disk drives indeed do have disk tables
|
||||
for them in the BIOS. If they don't, turn off the corresponding
|
||||
bits in the bit map. */
|
||||
|
||||
|
||||
for (disk = 0; /* start with disk A: */
|
||||
disk < 16; /* until disk P: */
|
||||
disk++) /* use next disk */
|
||||
{
|
||||
if ( !((1 << disk) & adisks) ) /* avoid unnecessary selects */
|
||||
continue;
|
||||
if (biosh(SELDSK,disk) == 0) /* make BIOS SELDSK call */
|
||||
{ /* returns 0 if invalid disk */
|
||||
/* turn OFF corresponding bit in mask
|
||||
by ANDing it with bit mask having
|
||||
all the other bits set = 1. */
|
||||
adisks &= ((1 << disk) ^ 0xFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
scb -> scb_adisks = adisks; /* set bit map in scb */
|
||||
|
||||
} /* end ssetscb */
|
||||
|
||||
|
||||
|
||||
chk_use(argc) /* check usage */
|
||||
/* This function checks that the correct number of
|
||||
parameters has been specified, outputting instructions
|
||||
if not. */
|
||||
|
||||
/* Entry Parameter */
|
||||
int argc; /* Count of the number of arguments on the command line */
|
||||
{
|
||||
|
||||
/* The minimum value of argc is 1 (for the program name itself),
|
||||
so argc is always one greater than the number of parameters
|
||||
on the command line */
|
||||
|
||||
if (argc != 2)
|
||||
{
|
||||
printf("\nUsage :");
|
||||
printf("\n\tSPACE * (All disks)");
|
||||
printf("\n\tSPACE ABCD..OP (Selected Disks)");
|
||||
exit();
|
||||
}
|
||||
} /* end chk_use */
|
||||
|
||||
179
CONTRIBUTIONS/cpm-handbook/cpmsrc/SPEED.C
Normal file
179
CONTRIBUTIONS/cpm-handbook/cpmsrc/SPEED.C
Normal file
@@ -0,0 +1,179 @@
|
||||
#define VN "\nSPEED 1.0 02/17/83"
|
||||
/* This utility sets the baud rate speed for each of the physical
|
||||
devices. */
|
||||
|
||||
#include <LIBRARY.H>
|
||||
|
||||
struct _ct ct_pdev[MAXPDEV + 2]; /* physical device table */
|
||||
|
||||
/* hardware specific items */
|
||||
/* baud rates for serial ports */
|
||||
#define B300 0x35 /* 300 baud */
|
||||
#define B600 0x36 /* 600 baud */
|
||||
#define B1200 0x37 /* 1200 baud */
|
||||
#define B2400 0x3A /* 2400 baud */
|
||||
#define B4800 0x3C /* 4800 baud */
|
||||
#define B9600 0x3E /* 9600 baud */
|
||||
#define B19200 0x3F /* 19200 baud */
|
||||
struct _ct ct_br[10]; /* code table for baud rates (+ spare entries) */
|
||||
|
||||
|
||||
/* parameters on the command line */
|
||||
#define PDEV argv[1] /* physical device */
|
||||
#define BAUD argv[2] /* baud rate */
|
||||
|
||||
|
||||
main(argc,argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
printf(VN); /* display sign on message */
|
||||
setup(); /* setup code tables */
|
||||
chk_use(argc); /* check correct usage */
|
||||
|
||||
/* check if request to show current settings */
|
||||
if (usstrcmp("SHOW",argv[1]))
|
||||
{ /* No, assume setting is required */
|
||||
set_baud(get_pdev(PDEV),get_baud(BAUD)); /* set baud rate */
|
||||
}
|
||||
|
||||
show_baud(); /* display current settings */
|
||||
|
||||
} /* end of program */
|
||||
|
||||
setup() /* setup the code tables for this program */
|
||||
{
|
||||
/* initialize the physical device table */
|
||||
ct_init(ct_pdev[0],T_DEVN,PN_T); /* terminal */
|
||||
ct_init(ct_pdev[1],P_DEVN,PN_P); /* printer */
|
||||
ct_init(ct_pdev[2],M_DEVN,PN_M); /* modem */
|
||||
ct_init(ct_pdev[3],CT_SNF,"*"); /* terminator */
|
||||
|
||||
/* initialize the baud rate table */
|
||||
ct_init(ct_br[0],B300,"300");
|
||||
ct_init(ct_br[1],B600,"600");
|
||||
ct_init(ct_br[2],B1200,"1200");
|
||||
ct_init(ct_br[3],B2400,"2400");
|
||||
ct_init(ct_br[4],B4800,"4800");
|
||||
ct_init(ct_br[5],B9600,"9600");
|
||||
ct_init(ct_br[6],B19200,"19200");
|
||||
ct_init(ct_br[7],CT_SNF,"*"); /* terminator */
|
||||
}
|
||||
|
||||
unsigned
|
||||
get_pdev(ppdev) /* get physical device */
|
||||
/* This function returns the physical device code
|
||||
specified by the user in the command line. */
|
||||
char *ppdev; /* pointer to character string */
|
||||
{
|
||||
unsigned retval; /* return value */
|
||||
|
||||
retval = ct_parc(ct_pdev,ppdev); /* get code for ASCII string */
|
||||
if (retval == CT_SNF) /* if string not found */
|
||||
{
|
||||
printf("\n\007Physical Device '%s' is invalid or ambiguous.",
|
||||
ppdev);
|
||||
printf("\nLegal Physical Devices are : ");
|
||||
ct_disps(ct_pdev); /* display all values */
|
||||
exit();
|
||||
}
|
||||
return retval; /* return code */
|
||||
}
|
||||
|
||||
|
||||
unsigned
|
||||
get_baud(pbaud)
|
||||
/* This function returns the baud rate time constant
|
||||
for baud rate specified by the user in the command line. */
|
||||
char *pbaud; /* pointer to character string */
|
||||
{
|
||||
unsigned retval; /* return value */
|
||||
retval = ct_parc(ct_br,pbaud); /* get code for ASCII string */
|
||||
if (retval == CT_SNF) /* if string not found */
|
||||
{
|
||||
printf("\n\007Baud Rate '%s' is invalid or ambiguous.",
|
||||
pbaud);
|
||||
printf("\nLegal Baud Rates are : ");
|
||||
ct_disps(ct_br); /* display all values */
|
||||
exit();
|
||||
}
|
||||
return retval; /* return code */
|
||||
}
|
||||
|
||||
set_baud(pdevc,baudc) /* set the baud rate of the specified device */
|
||||
int pdevc; /* physical device code */
|
||||
short baudc; /* baud rate code */
|
||||
/* on some systems this may have to be a
|
||||
two-byte (unsigned) value. */
|
||||
{
|
||||
short *baud_rc; /* pointer to the baud rate constant */
|
||||
/* on some systems this may have to be a
|
||||
two-byte (unsigned) value. */
|
||||
/* Note : the respective codes for accessing the baud rate constants
|
||||
via the get_cba (get configuration block address) function are:
|
||||
Device #0 = 19, #1 = 21, #2 = 23. This function uses this
|
||||
mathematical relationship. */
|
||||
|
||||
/* setup pointer to the baud rate constant */
|
||||
baud_rc = get_cba(CB_D0_BRC + (pdevc << 1));
|
||||
|
||||
/* then set the baud rate constant */
|
||||
*baud_rc = baudc;
|
||||
|
||||
/* then call the BIOS initialization routine */
|
||||
bios(CIOINIT,pdevc);
|
||||
}
|
||||
|
||||
|
||||
show_baud() /* show current baud rate */
|
||||
{
|
||||
|
||||
int pdevn; /* physical device number */
|
||||
short baudc; /* baud rate code */
|
||||
/* on some systems this may have to be a
|
||||
two-byte (unsigned) value. */
|
||||
short *baud_rc; /* pointer to the baud rate constant */
|
||||
/* on some systems this may have to be a
|
||||
two-byte (unsigned) value. */
|
||||
/* Note : the respective codes for accessing the baud rate constants
|
||||
via the get_cba (get configuration block address) function are:
|
||||
Device #0 = 19, #1 = 21, #2 = 23. This function uses this
|
||||
mathematical relationship. */
|
||||
|
||||
printf("\nCurrent Baud Rate settings are :");
|
||||
|
||||
|
||||
for (pdevn = 0; pdevn <= MAXPDEV; pdevn ++) /* all physical devices */
|
||||
{
|
||||
/* setup pointer to the baud rate constant -
|
||||
the code for the get_cba function is computed
|
||||
by adding the physical device number *2 to
|
||||
the Baud Rate code for device #0 */
|
||||
|
||||
baud_rc = get_cba(CB_D0_BRC + (pdevn << 1));
|
||||
|
||||
/* then set the baud rate constant */
|
||||
baudc = *baud_rc;
|
||||
|
||||
printf("\n\t%s set to %s baud.",
|
||||
ct_strc(ct_pdev,pdevn), /* get ptr to device name */
|
||||
ct_strc(ct_br,baudc) ); /* get ptr to baud rate */
|
||||
}
|
||||
}
|
||||
|
||||
chk_use(argc) /* check correct usage */
|
||||
int argc; /* argument count */
|
||||
{
|
||||
if (argc == 1)
|
||||
{
|
||||
printf("\nThe SPEED utility sets the baud rate speed for each physical device.");
|
||||
printf("\nUsage is : SPEED physical-device baud-rate, or");
|
||||
printf("\n SPEED SHOW (to show current settings)");
|
||||
printf("\n\nValid physical devices are: ");
|
||||
ct_disps(ct_pdev);
|
||||
printf("\nValid baud rates are: ");
|
||||
ct_disps(ct_br);
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
77
CONTRIBUTIONS/cpm-handbook/cpmsrc/TIME.C
Normal file
77
CONTRIBUTIONS/cpm-handbook/cpmsrc/TIME.C
Normal file
@@ -0,0 +1,77 @@
|
||||
#define VN "\nTIME Vn 1.0 02/18/83"
|
||||
/* This utility accepts the current time from the command tail
|
||||
validates it, and set the internal system time in the BIOS.
|
||||
Alternatively, it can be requested just to display the current
|
||||
system time. */
|
||||
|
||||
#include <LIBRARY.H>
|
||||
|
||||
char *time; /* pointer to the time in the config. block */
|
||||
char *time_set; /* pointer to the time set flag */
|
||||
int hh,mm,ss; /* variables to hold hours, minutes, seconds */
|
||||
int mcount; /* match count of numeric values entered */
|
||||
int count; /* count used to add leading 0's to time */
|
||||
|
||||
main(argc,argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
printf(VN); /* display signon message */
|
||||
time = get_cba(CB_TIMEA); /* set pointer to time */
|
||||
time_flag = get_cba(CB_DTFLAGS); /* set pointer to the time set flag */
|
||||
hh = mm = ss = 0; /* initialize the time in case seconds or
|
||||
minutes are not specified */
|
||||
|
||||
if (argc != 2) /* check if help requested (or needed) */
|
||||
show_use(); /* display correct usage and exit */
|
||||
|
||||
if (usstrcmp("SHOW",argv[1])) /* check if not SHOW option */
|
||||
{
|
||||
/* convert time into hours, minutes, seconds */
|
||||
mcount = sscanf(argv[1],"%d:%d:%d",&hh,&mm,&ss);
|
||||
if (!mcount) /* input not numeric */
|
||||
show_use(); /* display correct usage and exit */
|
||||
|
||||
if (hh > 12) /* check valid hours, minutes, seconds */
|
||||
{
|
||||
printf("\n\007Hours = %d is illegal.",hh);
|
||||
show_use(); /* display correct usage and exit */
|
||||
}
|
||||
if (mm > 59)
|
||||
{
|
||||
printf("\n\007Minutes = %d is illegal.",mm);
|
||||
show_use(); /* display correct usage and exit */
|
||||
}
|
||||
if (ss > 59)
|
||||
{
|
||||
show_use(); /* display correct usage and exit */
|
||||
printf("\n\007Seconds = %d is illegal.",ss);
|
||||
}
|
||||
|
||||
/* convert integers back into formatted string */
|
||||
sprintf(time,"%2d:%2d:%2d",hh,mm,ss);
|
||||
time[8] = 0x0A; /* terminate with line feed */
|
||||
time[9] = '\0'; /* new string terminator */
|
||||
|
||||
/* convert " 1: 2: 3" into "01:02:03" */
|
||||
for (count = 0; count < 7; count+=3)
|
||||
{
|
||||
if (time[count] == ' ')
|
||||
time[count] = '0';
|
||||
}
|
||||
/* turn bit on to indicate that the time has been set */
|
||||
*time_flag |= TIME_SET;
|
||||
}
|
||||
|
||||
printf("\n\tCurrent Time is %s",time);
|
||||
}
|
||||
|
||||
show_use() /* display correct usage and exit */
|
||||
{
|
||||
printf("\nTIME sets the system time. Usage is :");
|
||||
printf("\n\tTIME hh{:mm{:ss}}");
|
||||
printf("\n\tTIME SHOW (to display current time)\n");
|
||||
exit();
|
||||
}
|
||||
|
||||
|
||||
282
CONTRIBUTIONS/cpm-handbook/cpmsrc/UNERASE.C
Normal file
282
CONTRIBUTIONS/cpm-handbook/cpmsrc/UNERASE.C
Normal file
@@ -0,0 +1,282 @@
|
||||
#define VN "1.0 02/12/83"
|
||||
/* UNERASE - This does the inverse of ERASE. It revives the specified files,
|
||||
by changing the first byte of their directory entries from 0xE5
|
||||
back to the specified user number. */
|
||||
|
||||
#include <LIBRARY.H>
|
||||
|
||||
struct _dirpb dir_pb; /* directory management parameter block */
|
||||
struct _dir *dir_entry; /* pointer to directory entry */
|
||||
struct _scb scb; /* search control block */
|
||||
struct _scb scba; /* scb setup to match all files */
|
||||
struct _dpb dpb; /* CP/M's disk parameter block */
|
||||
struct _bv inuse_bv; /* bit vector for blocks in use */
|
||||
struct _bv file_bv; /* bit vector for file to be unerased */
|
||||
struct _bv extents; /* bit vector for those extents unerased */
|
||||
|
||||
char file_name[20]; /* formatted for display : un/d:FILENAME.TYP */
|
||||
|
||||
short cur_disk; /* current logical disk at start of program
|
||||
NZ = show map of number of files */
|
||||
int count; /* used to access the allocation block numbers
|
||||
in each directory entry */
|
||||
int user; /* user in which the file is to be revived */
|
||||
|
||||
|
||||
main(argc,argv)
|
||||
short argc; /* argument count */
|
||||
char *argv[]; /* argument vector (pointer to an array of chars) */
|
||||
{
|
||||
|
||||
printf("\nUNERASE Version %s (Library %s)",VN,LIBVN);
|
||||
chk_use(argc); /* check usage */
|
||||
cur_disk = bdos(GETDISK); /* get current default disk */
|
||||
|
||||
|
||||
/* using a special version of set search control block,
|
||||
set the disk, name, type (no ambiguous names), the user number
|
||||
to match only erased entries, and the length to compare
|
||||
the user, name and type.
|
||||
This special version also returns the disk_id taken from
|
||||
the file name on the command line. */
|
||||
if ((dir_pb.dp_disk = ssetscb(scb,argv[1],0xE5,12)) == 0)
|
||||
{ /* use default disk */
|
||||
dir_pb.dp_disk = cur_disk;
|
||||
}
|
||||
else
|
||||
{ /* make disk A = 0, B = 1 (for SELDSK) */
|
||||
dir_pb.dp_disk--;
|
||||
}
|
||||
printf("\nSearching disk %d.",dir_pb.dp_disk);
|
||||
|
||||
if(strscn(scb,"?")) /* check if ambiguous name */
|
||||
{
|
||||
printf("\nError - UNERASE can only revive a single file at a time.");
|
||||
exit();
|
||||
}
|
||||
|
||||
|
||||
/* set up a special search control block that will match with
|
||||
all existing files. */
|
||||
ssetscb(scba,"*.*",'?',12); /* set file name and initialize scb */
|
||||
|
||||
|
||||
if (argc == 2) /* no user number specified */
|
||||
user = bdos(GETUSER,0xFF); /* get current user number */
|
||||
else
|
||||
{
|
||||
user = atoi(argv[2]); /* get specified number */
|
||||
if (user > 15)
|
||||
{
|
||||
printf("\nUser number can only be between 0 - 15.");
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
/* build a bit vector that shows the allocation blocks
|
||||
currently in use. scba has been set up to match all
|
||||
active directory entries on the disk. */
|
||||
build_bv(inuse_bv,scba);
|
||||
|
||||
/* build a bit vector for the file to be restored showing
|
||||
which allocation blocks will be needed for the file. */
|
||||
if (!build_bv(file_bv,scb))
|
||||
{
|
||||
printf("\nNo directory entries found for file %s.",
|
||||
argv[1]);
|
||||
exit();
|
||||
}
|
||||
/* perform a boolean AND of the two bit vectors. */
|
||||
bv_and(file_bv,inuse_bv,file_bv);
|
||||
|
||||
/* check if the result is non-zero - if so, then one or more
|
||||
of the allocation blocks required by the erased file is
|
||||
already in use for an existing file and the file cannot
|
||||
be restored. */
|
||||
if (bv_nz(file_bv))
|
||||
{
|
||||
printf("\n--- This file cannot be restored as some parts of it");
|
||||
printf("\n have been re-used for other files! ---");
|
||||
exit();
|
||||
}
|
||||
|
||||
/* continue on to restore the file by changing all the entries
|
||||
in the directory to have the specified user number.
|
||||
Note : the problem is complicated by the fact that there
|
||||
may be several entries in the directory that are for the
|
||||
same file name and type, and even have the same extent
|
||||
number. For this reason, a bit map is kept of the extent
|
||||
numbers unerased - duplicate extent numbers will not be
|
||||
unerased. */
|
||||
|
||||
/* set up the bit vector for up to 127 unerased extents */
|
||||
bv_make(extents,16); /* 16 * 8 bits */
|
||||
|
||||
|
||||
/* set the directory to "closed", and force the get_nde
|
||||
function to open it. */
|
||||
dir_pb.dp_open = 0;
|
||||
|
||||
/* while not at the end of the directory, return a pointer to
|
||||
the next entry in the directory. */
|
||||
while(dir_entry = get_nde(dir_pb))
|
||||
{
|
||||
|
||||
/* check if user = 0xE5 and name, type match */
|
||||
if (comp_fname(scb,dir_entry) == NAME_EQ)
|
||||
{
|
||||
/* test if this extent has already been
|
||||
unerased */
|
||||
if (bv_test(extents,dir_entry -> de_extent))
|
||||
{ /* yes it has */
|
||||
printf("\n\t\tExtent #%d of %s ignored.",
|
||||
dir_entry -> de_extent,argv[1]);
|
||||
continue; /* do not unerase this one */
|
||||
}
|
||||
else /* indicate this extent unerased */
|
||||
{
|
||||
bv_set(extents,dir_entry -> de_extent);
|
||||
dir_entry -> de_userno = user; /* unerase entry */
|
||||
dir_pb.dp_write = 1; /* need to write sector back */
|
||||
printf("\n\tExtent #%d of %s unerased.",
|
||||
dir_entry -> de_extent,argv[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n\nFile %s unerased in User Number %d.",
|
||||
argv[1],user);
|
||||
|
||||
bdos(SETDISK,cur_disk); /* reset to current disk */
|
||||
}
|
||||
|
||||
|
||||
build_bv(bv,scb) /* build bit vector (from directory) */
|
||||
/* This function scans the directory of the disk specified in
|
||||
the directory parameter block (declared as a global variable),
|
||||
and builds the specified bit vector showing all the allocation
|
||||
blocks used by files matching the name in the search control
|
||||
block. */
|
||||
|
||||
/* Entry Parameters */
|
||||
struct _bv *bv; /* pointer to the bit vector */
|
||||
struct _scb *scb; /* pointer to search control block */
|
||||
/* also uses : directory parameter block (dir_pb) */
|
||||
|
||||
/* Exit Parameters
|
||||
The specified bit vector will be created, and will have 1-bits
|
||||
set wherever an allocation block is found in a directory
|
||||
entry that matches the search control block.
|
||||
It also returns the number of directory entries matched. */
|
||||
{
|
||||
unsigned abno; /* allocation block number */
|
||||
struct _dpb *dpb; /* pointer to the disk parameter block in the BIOS */
|
||||
int mcount; /* match count of dir. entries matched */
|
||||
|
||||
mcount = 0; /* initialize match count */
|
||||
dpb = get_dpb(dir_pb.dp_disk); /* get disk parameter block address */
|
||||
|
||||
/* make the bit vector with one byte for each 8 allocation
|
||||
blocks + 1 */
|
||||
if (!(bv_make(bv,(dpb -> dpb_maxabn >>3)+1)))
|
||||
{
|
||||
printf("\nError - Insufficient memory to make a bit vector.");
|
||||
exit();
|
||||
}
|
||||
|
||||
|
||||
/* set directory to "closed" to force the get_nde
|
||||
function to open it. */
|
||||
dir_pb.dp_open = 0;
|
||||
|
||||
/* now scan the directory building the bit vector */
|
||||
while(dir_entry = get_nde(dir_pb))
|
||||
{
|
||||
/* compare user number (which can legitimately be
|
||||
0xE5), the file name and the type). */
|
||||
if (comp_fname(scb,dir_entry) == NAME_EQ)
|
||||
{
|
||||
++mcount; /* update match count */
|
||||
for (count = 0; /* start with the first alloc. block */
|
||||
count < dir_pb.dp_nabpde; /* for number of alloc. blks per dir. entry */
|
||||
count++)
|
||||
{
|
||||
/* set the appropriate bit number for
|
||||
each non-zero allocation block number */
|
||||
if (dir_pb.dp_nabpde == 8) /* assume 8 2-byte numbers */
|
||||
{
|
||||
abno = dir_entry -> _dirab.de_long[count];
|
||||
}
|
||||
else /* assume 16 1-byte numbers */
|
||||
{
|
||||
abno = dir_entry -> _dirab.de_short[count];
|
||||
}
|
||||
if (abno) bv_set(bv,abno); /* set the bit */
|
||||
}
|
||||
}
|
||||
}
|
||||
return mcount; /* return number of dir entries matched */
|
||||
}
|
||||
|
||||
|
||||
|
||||
chk_use(argc) /* check usage */
|
||||
/* This function checks that the correct number of
|
||||
parameters has been specified, outputting instructions
|
||||
if not. */
|
||||
|
||||
/* Entry Parameter */
|
||||
int argc; /* Count of the number of arguments on the command line */
|
||||
{
|
||||
|
||||
/* The minimum value of argc is 1 (for the program name itself),
|
||||
so argc is always one greater than the number of parameters
|
||||
on the command line */
|
||||
|
||||
if (argc == 1 || argc > 3)
|
||||
{
|
||||
printf("\nUsage :");
|
||||
printf("\n\tUNERASE {d:}filename.typ {user}");
|
||||
printf("\n\tOnly a single unambiguous file name can be used.)");
|
||||
exit();
|
||||
}
|
||||
} /* end chk_use */
|
||||
|
||||
|
||||
ssetscb(scb,fname,user,length) /* special version of set search control block */
|
||||
/* This function sets up a search control block according
|
||||
to the file name, type, user number and number of bytes to
|
||||
compare.
|
||||
The file name can take the following forms :
|
||||
|
||||
filename
|
||||
filename.typ
|
||||
d:filename.typ
|
||||
|
||||
It sets the bit map according to which disks should be searched.
|
||||
For each selected disk, it checks to see if an error is generated
|
||||
when selecting the disk (i.e. if there are disk tables in the BIOS
|
||||
for the disk). */
|
||||
|
||||
/* Entry Parameters */
|
||||
struct _scb *scb; /* pointer to search control block */
|
||||
char *fname; /* pointer to the file name */
|
||||
short user; /* user number to be matched */
|
||||
int length; /* number of bytes to compare */
|
||||
|
||||
/* Exit Parameters
|
||||
Disk number to be searched. (A = 1, B = 2...)
|
||||
*/
|
||||
{
|
||||
short disk_id; /* disk number to search */
|
||||
|
||||
setfcb(scb,fname); /* set search control block as though it
|
||||
is a file control block. */
|
||||
disk_id = scb -> scb_userno; /* set disk_id before it gets overwritten
|
||||
by the user number */
|
||||
scb -> scb_userno = user; /* set user number */
|
||||
scb -> scb_length = length; /* set number of bytes to compare */
|
||||
return disk_id;
|
||||
} /* end setscb */
|
||||
|
||||
|
||||
786
CONTRIBUTIONS/cpm1.4/bldccp/OS2CCP.ASM
Normal file
786
CONTRIBUTIONS/cpm1.4/bldccp/OS2CCP.ASM
Normal file
@@ -0,0 +1,786 @@
|
||||
title 'console command processor (CCP), ver 2.0'
|
||||
; assembly language version of the CP/M console command processor
|
||||
;
|
||||
; version 1.4
|
||||
;
|
||||
; Copyright (c) 1976, 1977, 1978
|
||||
; Digital Research
|
||||
; Box 579, Pacific Grove,
|
||||
; California, 93950
|
||||
;
|
||||
false equ 0000h
|
||||
true equ not false
|
||||
testing equ false ;true if debugging
|
||||
;
|
||||
;
|
||||
if testing
|
||||
org 3400h
|
||||
bdosl equ $+800h ;bdos location
|
||||
else
|
||||
org 000h
|
||||
bdosl equ $+800h ;bdos location
|
||||
endif
|
||||
tran equ 100h
|
||||
tranm equ $
|
||||
ccploc equ $
|
||||
;
|
||||
; ********************************************************
|
||||
; * Base of CCP contains the following code/data *
|
||||
; * ccp: jmp ccpstart (start with command) *
|
||||
; * jmp ccpclear (start, clear command) *
|
||||
; * ccp+6 127 (max command length) *
|
||||
; * ccp+7 comlen (command length = 00) *
|
||||
; * ccp+8 ' ... ' (16 blanks) *
|
||||
; ********************************************************
|
||||
; * Normal entry is at ccp, where the command line given *
|
||||
; * at ccp+8 is executed automatically (normally a null *
|
||||
; * command with comlen = 00). An initializing program *
|
||||
; * can be automatically loaded by storing the command *
|
||||
; * at ccp+8, with the command length at ccp+7. In this *
|
||||
; * case, the ccp executes the command before prompting *
|
||||
; * the console for input. Note that the command is exe-*
|
||||
; * cuted on both warm and cold starts. When the command*
|
||||
; * line is initialized, a jump to "jmp ccpclear" dis- *
|
||||
; * ables the automatic command execution. *
|
||||
; ********************************************************
|
||||
;
|
||||
jmp ccpstart ;start ccp with possible initial command
|
||||
jmp ccpclear ;clear the command buffer
|
||||
maxlen: db 127 ;max buffer length
|
||||
comlen: db 0 ;command length (filled in by dos)
|
||||
; (command executed initially if comlen non zero)
|
||||
combuf:
|
||||
db ' ' ;8 character fill
|
||||
db ' ' ;8 character fill
|
||||
db 'COPYRIGHT (C) 1978, DIGITAL RESEARCH '; 38
|
||||
ds 128-($-combuf)
|
||||
; total buffer length is 128 characters
|
||||
comaddr:dw combuf ;address of next to char to scan
|
||||
staddr: ds 2 ;starting address of current fillfcb request
|
||||
;
|
||||
diska equ 0004h ;disk address for current disk
|
||||
bdos equ 0005h ;primary bdos entry point
|
||||
buff equ 0080h ;default buffer
|
||||
fcb equ 005ch ;default file control block
|
||||
;
|
||||
rcharf equ 1 ;read character function
|
||||
pcharf equ 2 ;print character function
|
||||
pbuff equ 9 ;print buffer function
|
||||
rbuff equ 10 ;read buffer function
|
||||
breakf equ 11 ;break key function
|
||||
liftf equ 12 ;lift head function (no operation)
|
||||
initf equ 13 ;initialize bdos function
|
||||
self equ 14 ;select disk function
|
||||
openf equ 15 ;open file function
|
||||
closef equ 16 ;close file function
|
||||
searf equ 17 ;search for file function
|
||||
searnf equ 18 ;search for next file function
|
||||
delf equ 19 ;delete file function
|
||||
dreadf equ 20 ;disk read function
|
||||
dwritf equ 21 ;disk write function
|
||||
makef equ 22 ;file make function
|
||||
renf equ 23 ;rename file function
|
||||
logf equ 24 ;return login vector
|
||||
cself equ 25 ;return currently selected drive number
|
||||
dmaf equ 26 ;set dma address
|
||||
;
|
||||
; special fcb flags
|
||||
rofile equ 9 ;read only file
|
||||
sysfile equ 10 ;system file flag
|
||||
;
|
||||
; special characters
|
||||
cr equ 13 ;carriage return
|
||||
lf equ 10 ;line feed
|
||||
la equ 5fh ;left arrow
|
||||
eofile equ 1ah ;end of file
|
||||
;
|
||||
; utility procedures
|
||||
printchar:
|
||||
mov e,a! mvi c,pcharf! jmp bdos
|
||||
;
|
||||
printbc:
|
||||
;print character, but save b,c registers
|
||||
push b! call printchar! pop b! ret
|
||||
;
|
||||
crlf:
|
||||
mvi a,cr! call printchar
|
||||
mvi a,lf! jmp printchar
|
||||
;
|
||||
;
|
||||
print: ;print string starting at b,c until next 00 entry
|
||||
push b! call crlf! pop h ;now print the string
|
||||
prin0: mov a,m! ora a! rz ;stop on 00
|
||||
inx h! push h ;ready for next
|
||||
call printchar! pop h ;character printed
|
||||
jmp prin0 ;for another character
|
||||
;
|
||||
initialize:
|
||||
mvi c,initf! jmp bdos
|
||||
;
|
||||
select:
|
||||
mov e,a! mvi c,self! jmp bdos
|
||||
;
|
||||
;
|
||||
open: ;open the file given by d,e
|
||||
mvi c, openf! call bdos! sta dcnt! inr a! ret
|
||||
;
|
||||
openc: ;open comfcb
|
||||
xra a! sta comrec ;clear next record to read
|
||||
lxi d,comfcb! jmp open
|
||||
;
|
||||
close: ;close the file given by d,e
|
||||
mvi c,closef! call bdos! sta dcnt! inr a! ret
|
||||
;
|
||||
search: ;search for the file given by d,e
|
||||
mvi c,searf! call bdos! sta dcnt! inr a! ret
|
||||
;
|
||||
searchn:
|
||||
;search for the next occurrence of the file given by d,e
|
||||
mvi c,searnf! call bdos! sta dcnt! inr a! ret
|
||||
;
|
||||
searchcom:
|
||||
;search for comfcb file
|
||||
lxi d,comfcb! jmp search
|
||||
;
|
||||
delete: ;delete the file given by d,e
|
||||
mvi c,delf! jmp bdos
|
||||
;
|
||||
;
|
||||
diskread:
|
||||
;read the next record from the file given by d,e
|
||||
mvi c,dreadf! call bdos! ora a! ret
|
||||
;
|
||||
diskreadc:
|
||||
;read the comfcb file
|
||||
lxi d,comfcb! jmp diskread
|
||||
;
|
||||
diskwrite:
|
||||
;write the next record to the file given by d,e
|
||||
mvi c,dwritf! call bdos! ora a! ret
|
||||
;
|
||||
make: ;create the file given by d,e
|
||||
mvi c,makef! call bdos! sta dcnt! ret
|
||||
;
|
||||
renam: ;rename the file given by d,e
|
||||
mvi c,renf! jmp bdos
|
||||
;
|
||||
;
|
||||
translate:
|
||||
;translate character in register A to upper case
|
||||
cpi 61h! rc ;return if below lower case a
|
||||
cpi 7bh! rnc ;return if above lower case z
|
||||
ani 5fh! ret ;translated to upper case
|
||||
;
|
||||
readcom:
|
||||
;read the next command into the command buffer
|
||||
;check for submit file
|
||||
lda submit! ora a! jz nosub
|
||||
;scanning a submit file
|
||||
;change drives to open and read the file
|
||||
lda cdisk! ora a! mvi a,0! cnz select
|
||||
;have to open again in case xsub present
|
||||
lda subrc! dcr a ;read last record(s) first
|
||||
sta subcr ;current record to read
|
||||
lxi d,subfcb! call diskread ;end of file if last record
|
||||
jnz nosub
|
||||
;disk read is ok, transfer to combuf
|
||||
lxi d,comlen! lxi h,buff! mvi b,128! call move0
|
||||
;line is transferred, close the file with a
|
||||
;deleted record
|
||||
lxi h,subrc ; mvi m,0 ;clear fwflag
|
||||
dcr m ;one less record
|
||||
lxi d,subfcb! call close! jz nosub
|
||||
;close went ok, return to original drive
|
||||
lda cdisk! ora a! cnz select
|
||||
;print to the 00
|
||||
lxi h,combuf! call prin0
|
||||
call break$key! jz noread
|
||||
call del$sub! jmp ccp ;break key depressed
|
||||
;
|
||||
nosub: ;no submit file! call del$sub
|
||||
;translate to upper case, store zero at end
|
||||
mvi c,rbuff! lxi d,maxlen! call bdos
|
||||
noread: ;enter here from submit file
|
||||
;set the last character to zero for later scans
|
||||
lxi h,comlen! mov b,m ;length is in b
|
||||
readcom0: inx h! mov a,b! ora a ;end of scan?
|
||||
jz readcom1! mov a,m ;get character and translate
|
||||
call translate! mov m,a! dcr b! jmp readcom0
|
||||
;
|
||||
readcom1: ;end of scan, h,l address end of command
|
||||
mov m,a ;store a zero
|
||||
lxi h,combuf! shld comaddr ;ready to scan to zero
|
||||
ret
|
||||
;
|
||||
break$key:
|
||||
;check for a character ready at the console
|
||||
mvi c,breakf! call bdos
|
||||
ora a! rz
|
||||
mvi c,rcharf! call bdos ;character cleared
|
||||
ora a! ret
|
||||
;
|
||||
clifter:
|
||||
mvi c,liftf! jmp bdos
|
||||
;
|
||||
cselect:
|
||||
;get the currently selected drive number to reg-A
|
||||
mvi c,cself! jmp bdos
|
||||
;
|
||||
cpyblock:
|
||||
ldax d! mov m,a! inx d! inx h
|
||||
dcr c! jnz cpyblock! ret
|
||||
;
|
||||
setdma:
|
||||
;set dma address to d,e
|
||||
mvi c,dmaf! jmp bdos
|
||||
;
|
||||
del$sub:
|
||||
;delete the submit file, and set submit flag to false
|
||||
lxi h,submit! mov a,m! ora a! rz ;return if no sub file
|
||||
mvi m,0 ;submit flag is set to false
|
||||
xra a! call select ;on drive a to erase file
|
||||
lxi d,subfcb! call delete
|
||||
lda cdisk! jmp select ;back to original drive
|
||||
;
|
||||
serialize:
|
||||
;check serialization
|
||||
lxi d,serial! lxi h,bdosl! mvi b,6 ;check six bytes
|
||||
ser0: ldax d! cmp m! jnz badserial
|
||||
inx d! inx h! dcr b! jnz ser0
|
||||
ret ;serial number is ok
|
||||
;
|
||||
comerr:
|
||||
;error in command string starting at position
|
||||
;'staddr' and ending with first delimiter
|
||||
call crlf ;space to next line
|
||||
lhld staddr ;h,l address first to print
|
||||
comerr0: ;print characters until blank or zero
|
||||
mov a,m! cpi ' '! jz comerr1; not blank
|
||||
ora a! jz comerr1; not zero, so print it
|
||||
push h! call printchar! pop h! inx h
|
||||
jmp comerr0; for another character
|
||||
comerr1: ;print question mark,and delete sub file
|
||||
mvi a,'?'! call printchar
|
||||
call crlf! call del$sub
|
||||
jmp ccp ;restart with next command
|
||||
;
|
||||
; fcb scan and fill subroutine (entry is at fillfcb below)
|
||||
;fill the comfcb, indexed by A (0 or 16)
|
||||
;subroutines
|
||||
delim: ;look for a delimiter
|
||||
ldax d! ora a! rz ;not the last element
|
||||
cpi ' '! jc comerr ;non graphic
|
||||
rz ;treat blank as delimiter
|
||||
cpi '='! rz
|
||||
cpi la! rz ;left arrow
|
||||
cpi '.'! rz
|
||||
cpi ':'! rz
|
||||
cpi ';'! rz
|
||||
cpi '<'! rz
|
||||
cpi '>'! rz
|
||||
ret ;delimiter not found
|
||||
;
|
||||
deblank: ;deblank the input line
|
||||
ldax d! ora a! rz ;treat end of line as blank
|
||||
cpi ' '! rnz! inx d! jmp deblank
|
||||
;
|
||||
addh: ;add a to h,l
|
||||
add l! mov l,a! rnc
|
||||
inr h! ret
|
||||
;
|
||||
fillfcb0:
|
||||
;equivalent to fillfcb(0)
|
||||
mvi a,0
|
||||
;
|
||||
fillfcb:
|
||||
lxi h,comfcb! call addh! push h! push h ;fcb rescanned at end
|
||||
xra a! sta sdisk ;clear selected disk (in case A:...)
|
||||
lhld comaddr! xchg ;command address in d,e
|
||||
call deblank ;to first non-blank character
|
||||
xchg! shld staddr ;in case of errors
|
||||
xchg! pop h ;d,e has command, h,l has fcb address
|
||||
;look for preceding file name A: B: ...
|
||||
ldax d! ora a! jz setcur0 ;use current disk if empty command
|
||||
sbi 'A'-1! mov b,a ;disk name held in b if : follows
|
||||
inx d! ldax d! cpi ':'! jz setdsk ;set disk name if :
|
||||
;
|
||||
setcur: ;set current disk
|
||||
dcx d ;back to first character of command
|
||||
setcur0:
|
||||
lda cdisk! mov m,a! jmp setname
|
||||
;
|
||||
setdsk: ;set disk to name in register b
|
||||
mov a,b! sta sdisk ;mark as disk selected
|
||||
mov m,b! inx d ;past the :
|
||||
;
|
||||
setname: ;set the file name field
|
||||
mvi b,8 ;file name length (max)
|
||||
setnam0: call delim! jz padname ;not a delimiter
|
||||
inx h! cpi '*'! jnz setnam1 ;must be ?'s
|
||||
mvi m,'?'! jmp setnam2 ;to dec count
|
||||
;
|
||||
setnam1: mov m,a ;store character to fcb! inx d
|
||||
setnam2: dcr b ;count down length! jnz setnam0
|
||||
;
|
||||
;end of name, truncate remainder
|
||||
trname: call delim! jz setty ;set type field if delimiter
|
||||
inx d! jmp trname
|
||||
;
|
||||
padname: inx h! mvi m,' '! dcr b! jnz padname
|
||||
;
|
||||
setty: ;set the type field
|
||||
mvi b,3! cpi '.'! jnz padty ;skip the type field if no .
|
||||
inx d ;past the ., to the file type field
|
||||
setty0: ;set the field from the command buffer
|
||||
call delim! jz padty! inx h! cpi '*'! jnz setty1
|
||||
mvi m,'?' ;since * specified! jmp setty2
|
||||
;
|
||||
setty1: ;not a *, so copy to type field
|
||||
mov m,a! inx d
|
||||
setty2: ;decrement count and go again
|
||||
dcr b! jnz setty0
|
||||
;
|
||||
;end of type field, truncate
|
||||
trtyp: ;truncate type field
|
||||
call delim! jz efill! inx d! jmp trtyp
|
||||
;
|
||||
padty: ;pad the type field with blanks
|
||||
inx h! mvi m,' '! dcr b! jnz padty
|
||||
;
|
||||
efill: ;end of the filename/filetype fill, save command address
|
||||
;fill the remaining fields for the fcb
|
||||
mvi b,3
|
||||
efill0: inx h! mvi m,0! dcr b! jnz efill0
|
||||
xchg! shld comaddr ;set new starting point
|
||||
;
|
||||
;recover the start address of the fcb and count ?'s
|
||||
pop h! lxi b,11 ;b=0, c=8+3
|
||||
scnq: inx h! mov a,m! cpi '?'! jnz scnq0
|
||||
;? found, count it in b! inr b
|
||||
scnq0: dcr c! jnz scnq
|
||||
;
|
||||
;number of ?'s in c, move to a and return with flags set
|
||||
mov a,b! ora a! ret
|
||||
;
|
||||
intvec:
|
||||
;intrinsic function names (all are four characters)
|
||||
db 'DIR '
|
||||
db 'ERA '
|
||||
db 'TYPE'
|
||||
db 'SAVE'
|
||||
db 'REN '
|
||||
intlen equ ($-intvec)/4 ;intrinsic function length
|
||||
serial: ;db 0,0,0,0,0,0
|
||||
db 14h,0eh,0,0,7h,06dh
|
||||
;
|
||||
;
|
||||
intrinsic:
|
||||
;look for intrinsic functions (comfcb has been filled)
|
||||
lxi h,intvec! mvi c,0 ;c counts intrinsics as scanned
|
||||
intrin0: mov a,c! cpi intlen ;done with scan?! rnc
|
||||
;no, more to scan
|
||||
lxi d,comfcb+1 ;beginning of name
|
||||
mvi b,4 ;length of match is in b
|
||||
intrin1: ldax d! cmp m ;match?
|
||||
jnz intrin2 ;skip if no match
|
||||
inx d! inx h! dcr b
|
||||
jnz intrin1 ;loop while matching
|
||||
;
|
||||
;complete match on name, check for blank in fcb
|
||||
ldax d! cpi ' '! jnz intrin3 ;otherwise matched
|
||||
mov a,c! ret ;with intrinsic number in a
|
||||
;
|
||||
intrin2: ;mismatch, move to end of intrinsic
|
||||
inx h! dcr b! jnz intrin2
|
||||
;
|
||||
intrin3: ;try next intrinsic
|
||||
inr c ;to next intrinsic number
|
||||
jmp intrin0 ;for another round
|
||||
intrin4:
|
||||
ora a! jnz intrin5! lxi d,subfcb! call open
|
||||
jz intrin5
|
||||
mvi a, 0ffh! jmp intrin6
|
||||
intrin5:
|
||||
xra a
|
||||
intrin6:
|
||||
sta submit
|
||||
ret
|
||||
;
|
||||
ccpclear:
|
||||
;clear the command buffer
|
||||
xra a
|
||||
sta comlen
|
||||
;drop through to start ccp
|
||||
ccpstart:
|
||||
;enter here from boot loader
|
||||
lxi sp,stack! push b ;save initial disk number
|
||||
;(high order 4bits=user code, low 4bits=disk#)
|
||||
push b! call initialize! pop b
|
||||
push psw! mov a,c! call select
|
||||
pop psw! pop b
|
||||
inr a! ora c
|
||||
call intrin4 ;proper disk is selected, now check sub files
|
||||
;check for initial command
|
||||
lda comlen! ora a! jnz ccp0 ;assume typed already
|
||||
;
|
||||
ccp:
|
||||
;enter here on each command or error condition
|
||||
lxi sp,stack
|
||||
call crlf ;print d> prompt, where d is disk name
|
||||
call cselect ;get current disk number
|
||||
adi 'A'! call printchar
|
||||
mvi a,'>'! call printchar
|
||||
call readcom ;command buffer filled
|
||||
ccp0: ;(enter here from initialization with command full)
|
||||
lxi d,buff! call setdma ;default dma address at buff
|
||||
call cselect! sta cdisk ;current disk number saved
|
||||
call fillfcb0 ;command fcb filled
|
||||
cnz comerr ;the name cannot be an ambiguous reference
|
||||
lda sdisk! ora a! jnz userfunc
|
||||
;check for an intrinsic function
|
||||
call intrinsic
|
||||
lxi h,jmptab ;index is in the accumulator
|
||||
mov e,a! mvi d,0! dad d! dad d ;index in d,e
|
||||
mov a,m! inx h! mov h,m! mov l,a! pchl
|
||||
;pc changes to the proper intrinsic or user function
|
||||
jmptab:
|
||||
dw direct ;directory search
|
||||
dw erase ;file erase
|
||||
dw type ;type file
|
||||
dw save ;save memory image
|
||||
dw rename ;file rename
|
||||
dw userfunc;user-defined function
|
||||
badserial:
|
||||
lxi h,di or (hlt shl 8)
|
||||
shld ccploc! lxi h,ccploc! pchl
|
||||
;
|
||||
;
|
||||
;utility subroutines for intrinsic handlers
|
||||
readerr:
|
||||
;print the read error message
|
||||
lxi b,rdmsg! jmp print
|
||||
rdmsg: db 'READ ERROR',0
|
||||
;
|
||||
nofile:
|
||||
;print no file message
|
||||
lxi b,nofmsg! jmp print
|
||||
nofmsg: db 'NOT FOUND',0
|
||||
;
|
||||
getnumber: ;read a number from the command line
|
||||
;convert the byte value in comfcb to binary
|
||||
lxi h,comfcb+1! lxi b,11 ;(b=0, c=11)
|
||||
;value accumulated in b, c counts name length to zero
|
||||
conv0: mov a,m! cpi ' '! jz conv1
|
||||
;more to scan, convert char to binary and add
|
||||
inx h! sui '0'! cpi 10! jnc comerr ;valid?
|
||||
mov d,a ;save value! mov a,b ;mult by 10
|
||||
ani 1110$0000b! jnz comerr
|
||||
mov a,b ;recover value
|
||||
rlc! rlc! rlc ;*8
|
||||
add b! jc comerr
|
||||
add b! jc comerr ;*8+*2 = *10
|
||||
add d! jc comerr ;+digit
|
||||
mov b,a! dcr c! jnz conv0 ;for another digit
|
||||
ret
|
||||
conv1: ;end of digits, check for all blanks
|
||||
mov a,m! cpi ' '! jnz comerr ;blanks?
|
||||
inx h! dcr c! jnz conv1
|
||||
mov a,b ;recover value! ret
|
||||
;
|
||||
movename:
|
||||
;move 3 characters from h,l to d,e addresses
|
||||
mvi b,3
|
||||
move0: mov a,m! stax d! inx h! inx d
|
||||
dcr b! jnz move0
|
||||
ret
|
||||
;
|
||||
addhcf: ;buff + a + c to h,l followed by fetch
|
||||
lxi h,buff! add c! call addh! mov a,m! ret
|
||||
;
|
||||
setdisk:
|
||||
;change disks for this command, if requested
|
||||
xra a! sta comfcb ;clear disk name from fcb
|
||||
setdisk1:
|
||||
lda sdisk! ora a! rz ;no action if not specified
|
||||
dcr a! lxi h,cdisk! cmp m! rz ;already selected
|
||||
jmp select
|
||||
;
|
||||
resetdisk:
|
||||
;return to original disk after command
|
||||
lda sdisk! ora a! rz ;no action if not selected
|
||||
dcr a! lxi h,cdisk! cmp m! rz ;same disk
|
||||
lda cdisk! jmp select
|
||||
;
|
||||
;individual intrinsics follow
|
||||
direct:
|
||||
;directory search
|
||||
call fillfcb0 ;comfcb gets file name
|
||||
call setdisk ;change disk drives if requested
|
||||
lxi h,comfcb+1! mov a,m ;may be empty request
|
||||
cpi ' '! jnz dir1 ;skip fill of ??? if not blank
|
||||
;set comfcb to all ??? for current disk
|
||||
mvi b,11 ;length of fill ????????.???
|
||||
dir0: mvi m,'?'! inx h! dcr b! jnz dir0
|
||||
;not a blank request, must be in comfcb
|
||||
dir1:
|
||||
call searchcom ;first one has been found
|
||||
cz nofile ;not found message
|
||||
dir2: jz endir
|
||||
;found, but may be system file
|
||||
call crlf! call cselect
|
||||
;current disk in A
|
||||
adi 'A'! call printchar
|
||||
mvi a,':'! call printchar
|
||||
mvi a,' '! call printchar
|
||||
dirhdr1:
|
||||
lda dcnt! rrc! rrc! rrc! ani 60h! mov c,a
|
||||
;compute position of name in buffer
|
||||
mvi b,1 ;start with first character of name
|
||||
dir3: mov a,b! call addhcf ;buff+a+c fetched
|
||||
cpi ' '! jnz dir4 ;check for blank type
|
||||
mvi a,9! call addhcf ;first char of type
|
||||
mvi a,' '! cmp m! jz dir5
|
||||
dir4:
|
||||
call printbc ;char printed
|
||||
inr b! mov a,b! cpi 12! jnc dir5
|
||||
;check for break between names
|
||||
cpi 9! jnz dir3 ;for another char
|
||||
;print a blank between names
|
||||
mvi a,' '! call printbc! jmp dir3
|
||||
;
|
||||
dir5: ;end of current entry
|
||||
dir6: call break$key ;check for interrupt at keyboard
|
||||
jnz endir ;abort directory search
|
||||
call searchn! jmp dir2 ;for another entry
|
||||
endir: ;end of directory scan
|
||||
jmp retcom
|
||||
;
|
||||
;
|
||||
erase:
|
||||
call fillfcb0 ;cannot be all ???'s
|
||||
cpi 11
|
||||
jnz getout
|
||||
;erasing all of the disk
|
||||
lxi b,ermsg! call print!
|
||||
call readcom
|
||||
lxi h,comlen! dcr m! jnz ccp ;bad input
|
||||
inx h! mov a,m! cpi 'Y'! jnz ccp
|
||||
;ok, erase the entire diskette
|
||||
inx h! shld comaddr ;otherwise error at retcom
|
||||
erasefile:
|
||||
lxi h, comfcb! mvi m,'?'
|
||||
call setdisk1
|
||||
lxi d,comfcb! call delete
|
||||
call initialize! jmp retcom
|
||||
getout:
|
||||
call setdisk
|
||||
lxi d, comfcb! call delete
|
||||
jmp retcom
|
||||
;
|
||||
ermsg: db 'ALL FILES (Y/N)?',0
|
||||
;
|
||||
type:
|
||||
call fillfcb0! jnz comerr ;don't allow ?'s in file name
|
||||
call setdisk! call openc ;open the file
|
||||
jz typerr ;zero flag indicates not found
|
||||
;file opened, read 'til eof
|
||||
call crlf! lxi h,bptr! mvi m,255 ;read first buffer
|
||||
type0: ;loop on bptr
|
||||
lxi h,bptr! mov a,m! cpi 128 ;end buffer
|
||||
jc type1! push h ;carry if 0,1,...,127
|
||||
;read another buffer full
|
||||
call diskreadc! pop h ;recover address of bptr
|
||||
jnz typeof ;hard end of file
|
||||
xra a! mov m,a ;bptr = 0
|
||||
type1: ;read character at bptr and print
|
||||
inr m ;bptr = bptr + 1
|
||||
lxi h,buff! call addh ;h,l addresses char
|
||||
mov a,m! cpi eofile! jz retcom
|
||||
call printchar
|
||||
call break$key! jnz retcom ;abort if break
|
||||
jmp type0 ;for another character
|
||||
;
|
||||
typeof: ;end of file, check for errors
|
||||
dcr a! jz retcom
|
||||
call readerr
|
||||
typerr: call resetdisk! jmp comerr
|
||||
;
|
||||
save:
|
||||
call fillfcb0! lda sdisk! ora a! jnz comerr
|
||||
call getnumber; value to register a
|
||||
push psw ;save it for later
|
||||
;
|
||||
;should be followed by a file to save the memory image
|
||||
call fillfcb0
|
||||
jnz comerr ;cannot be ambiguous
|
||||
call setdisk ;may be a disk change
|
||||
lxi d,comfcb! push d! call delete ;existing file removed
|
||||
pop d! call make ;create a new file on disk
|
||||
call openc! jz save1
|
||||
pop psw ;#pages to write is in a, change to #sectors
|
||||
mov l,a! mvi h,0! dad h!
|
||||
lxi d,tran ;h,l is sector count, d,e is load address
|
||||
save0: ;check for sector count zero
|
||||
mov a,h! ora l! jz save2 ;may be completed
|
||||
dcx h ;sector count = sector count - 1
|
||||
push h ;save it for next time around
|
||||
lxi h,128! dad d! push h ;next dma address saved
|
||||
call setdma ;current dma address set
|
||||
lxi d,comfcb! call diskwrite
|
||||
pop d! pop h ;dma address, sector count
|
||||
jnz save1 ;may be disk full case
|
||||
jmp save0 ;for another sector
|
||||
;
|
||||
save1: ;end of dump, close the file
|
||||
lxi b, fullmsg! call print
|
||||
save2:
|
||||
lxi d,comfcb! call close
|
||||
jnz retsave ;for another command
|
||||
saverr: ;must be full or read only disk
|
||||
lxi b,closemsg! call print
|
||||
retsave:
|
||||
jmp retcom
|
||||
fullmsg: db 'NO SPACE',0
|
||||
;
|
||||
closemsg: db 'CANNOT CLOSE',0
|
||||
;
|
||||
rename:
|
||||
;rename a file on a specific disk
|
||||
call fillfcb0! jnz comerr ;must be unambiguous
|
||||
lda sdisk! push psw ;save for later compare
|
||||
call setdisk ;disk selected
|
||||
call searchcom ;is new name already there?
|
||||
jnz renerr3
|
||||
;file doesn't exist, move to second half of fcb
|
||||
lxi h,comfcb! lxi d,comfcb+16! mvi b,16! call move0
|
||||
;check for = or left arrow
|
||||
lhld comaddr! xchg! call deblank
|
||||
cpi '='! jz ren1 ;ok if =
|
||||
cpi la! jnz renerr2
|
||||
ren1: xchg! inx h! shld comaddr ;past delimiter
|
||||
;proper delimiter found
|
||||
call fillfcb0! jnz renerr2
|
||||
;check for drive conflict
|
||||
pop psw! mov b,a ;previous drive number
|
||||
lxi h,sdisk! mov a,m! ora a! jz ren2
|
||||
;drive name was specified. same one?
|
||||
cmp b! mov m,b! jnz renerr2
|
||||
ren2: mov m,b ;store the name in case drives switched
|
||||
xra a! sta comfcb! call searchcom ;is old file there?
|
||||
jz renerr1
|
||||
;
|
||||
;everything is ok, rename the file
|
||||
lxi d,comfcb! call renam
|
||||
jmp retcom
|
||||
;
|
||||
renerr1:; no file on disk
|
||||
call nofile! jmp retcom
|
||||
renerr2:; ambigous reference/name conflict
|
||||
call resetdisk! jmp comerr
|
||||
renerr3:; file already exists
|
||||
lxi b,renmsg! call print! jmp retcom
|
||||
renmsg: db 'FILE EXISTS',0
|
||||
;
|
||||
;
|
||||
userfunc:
|
||||
call serialize ;check serialization
|
||||
;load user function and set up for execution
|
||||
lda comfcb+1! cpi ' '! jnz user0
|
||||
;no file name, but may be disk switch
|
||||
lda sdisk! ora a! jz endcom ;no disk name if 0
|
||||
dcr a! sta cdisk! ;call setdiska ;set user/disk
|
||||
sta diska
|
||||
call select! jmp endcom
|
||||
user0: ;file name is present
|
||||
lxi d,comfcb+9! ldax d! cpi ' '! jnz comerr ;type ' '
|
||||
push d! call setdisk! pop d! lxi h,comtype ;.com
|
||||
call movename ;file type is set to .com
|
||||
call openc! jz userer
|
||||
;file opened properly, read it into memory
|
||||
lxi h,tran ;transient program base
|
||||
load0: push h ;save dma address
|
||||
xchg! call setdma
|
||||
lxi d,comfcb! call diskread! jnz load1
|
||||
;sector loaded, set new dma address and compare
|
||||
pop h! lxi d,128! dad d
|
||||
lxi d,tranm ;has the load overflowed?
|
||||
mov a,l! sub e! mov a,h! sbb d! jnc loaderr
|
||||
jmp load0 ;for another sector
|
||||
;
|
||||
load1: pop h! dcr a! jnz loaderr ;end file is 1
|
||||
call resetdisk ;back to original disk
|
||||
call fillfcb0! lxi h,sdisk! push h
|
||||
mov a,m! sta comfcb ;drive number set
|
||||
mvi a,16! call fillfcb ;move entire fcb to memory
|
||||
pop h! mov a,m! sta comfcb+16
|
||||
xra a! sta comrec ;record number set to zero
|
||||
lxi d,fcb! lxi h,comfcb! mvi b,33! call move0
|
||||
;move command line to buff
|
||||
lxi h,combuf
|
||||
bmove0: mov a,m! ora a! jz bmove1! cpi ' '! jz bmove1
|
||||
inx h! jmp bmove0 ;for another scan
|
||||
;first blank position found
|
||||
bmove1: mvi b,0! lxi d,buff+1! ;ready for the move
|
||||
bmove2: mov a,m! stax d! ora a! jz bmove3
|
||||
;more to move
|
||||
inr b! inx h! inx d! jmp bmove2
|
||||
bmove3: ;b has character count
|
||||
mov a,b! sta buff
|
||||
call crlf
|
||||
;now go to the loaded program
|
||||
lda cdisk! sta diska! call clifter! lxi d, buff
|
||||
call setdma ;user code saved
|
||||
;low memory diska contains user code
|
||||
call tran ;gone to the loaded program
|
||||
lxi sp,stack ;may come back here
|
||||
lda cdisk! call select
|
||||
jmp ccp
|
||||
;
|
||||
userer: ;arrive here on command error
|
||||
call resetdisk! jmp comerr
|
||||
;
|
||||
loaderr:;cannot load the program
|
||||
lxi b,loadmsg! call print
|
||||
jmp retcom
|
||||
loadmsg: db 'LOAD ERROR',0
|
||||
comtype: db 'COM' ;for com files
|
||||
;
|
||||
;
|
||||
retcom: ;reset disk before end of command check
|
||||
call resetdisk
|
||||
;
|
||||
endcom: ;end of intrinsic command
|
||||
call fillfcb0 ;to check for garbage at end of line
|
||||
lda comfcb+1! sui ' '! lxi h,sdisk! ora m
|
||||
;0 in accumulator if no disk selected, and blank fcb
|
||||
jnz comerr
|
||||
jmp ccp
|
||||
;
|
||||
;
|
||||
;
|
||||
; data areas
|
||||
ds 16 ;8 level stack
|
||||
stack:
|
||||
;
|
||||
; 'submit' file control block
|
||||
submit: db 0 ;00 if no submit file, ff if submitting
|
||||
subfcb: db 0,'$$$ ' ;file name is $$$
|
||||
db 'SUB',0,0 ;file type is sub
|
||||
submod: db 0 ;module number
|
||||
subrc: ds 1 ;record count filed
|
||||
ds 16 ;disk map
|
||||
subcr: ds 1 ;current record to read
|
||||
;
|
||||
; command file control block
|
||||
comfcb: ds 32 ;fields filled in later
|
||||
comrec: ds 1 ;current record to read/write
|
||||
dcnt: ds 1 ;disk directory count (used for error codes)
|
||||
cdisk: ds 1 ;current disk
|
||||
sdisk: ds 1 ;selected disk for current operation
|
||||
;none=0, a=1, b=2 ...
|
||||
bptr: ds 1 ;buffer pointer
|
||||
|
||||
ds 0eh
|
||||
ds 38
|
||||
|
||||
end ccploc
|
||||
BIN
CONTRIBUTIONS/cpm1.4/doc/Reconstruct CPM 1.4.doc
Normal file
BIN
CONTRIBUTIONS/cpm1.4/doc/Reconstruct CPM 1.4.doc
Normal file
Binary file not shown.
1
CONTRIBUTIONS/cpm1.4/readme.md
Normal file
1
CONTRIBUTIONS/cpm1.4/readme.md
Normal file
@@ -0,0 +1 @@
|
||||
Make CPM 1.4 v 0.1: by Ernie Price. Make CPM 1.4 is a howto on reconstucting the CPM Version 1.4 CCP and BDOS from recovered and regenerated sources.
|
||||
5
CONTRIBUTIONS/cpm1.4/tgtbin/dbg.bat
Normal file
5
CONTRIBUTIONS/cpm1.4/tgtbin/dbg.bat
Normal file
@@ -0,0 +1,5 @@
|
||||
rcx
|
||||
800
|
||||
nccp.bin
|
||||
wa00
|
||||
q
|
||||
BIN
CONTRIBUTIONS/cpm1.4/tools/EXTRACT.EXE
Normal file
BIN
CONTRIBUTIONS/cpm1.4/tools/EXTRACT.EXE
Normal file
Binary file not shown.
BIN
CONTRIBUTIONS/cpm1.4/tools/HEXCON.EXE
Normal file
BIN
CONTRIBUTIONS/cpm1.4/tools/HEXCON.EXE
Normal file
Binary file not shown.
253
CONTRIBUTIONS/cpm1.4/tools/extract.c
Normal file
253
CONTRIBUTIONS/cpm1.4/tools/extract.c
Normal file
@@ -0,0 +1,253 @@
|
||||
/* #include <conio.h> */
|
||||
#include <malloc.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct fcb // also directory entry
|
||||
{
|
||||
unsigned char user; // not used in CP/M 1.4
|
||||
unsigned char name[8]; // file name
|
||||
unsigned char type[3]; // file extension
|
||||
unsigned char ext; // extent number
|
||||
unsigned char notused[2];
|
||||
unsigned char rc; // record count in this extent
|
||||
unsigned char dm[16]; // single byte extent numbers
|
||||
};
|
||||
|
||||
#define DIR_ENT_SZ 32 // size of one directory entry
|
||||
#define SECT_SZ 128 // disk sector size
|
||||
#define SPB 8 // sectors per block
|
||||
#define DIR_BLOCKS 2 // 2 blocks reserved for directory
|
||||
#define SPT 26 // sectors per track
|
||||
#define RESERVED_TRACKS 2 // for cold boot, ccp and cpm
|
||||
|
||||
#define DIR_SECTORS (SPB * DIR_BLOCKS) // sectors for directory
|
||||
#define DIR_LOCN (SPT * RESERVED_TRACKS) // offset of directory
|
||||
#define DIR_ENT_PER_SEC (SECT_SZ / DIR_ENT_SZ) // directory entries per sector
|
||||
|
||||
unsigned char buff1[SPT * SECT_SZ]; // for de-interleaving
|
||||
unsigned char buff2[SPT * SECT_SZ]; // "
|
||||
|
||||
unsigned char fsec [SECT_SZ];
|
||||
char fname [20]; // file name for current extent
|
||||
char fname2[20]; // currently open output file name, if any
|
||||
|
||||
FILE *in, // raw image file
|
||||
*out; // extracted CP/M file
|
||||
|
||||
unsigned char exm[1024]; // map of processed blocks
|
||||
|
||||
// sector interleave table
|
||||
unsigned char sectran[] = {
|
||||
"\x01\x07\x0d\x13\x19\x05\x0b\x11"
|
||||
"\x17\x03\x09\x0f\x15\x02\x08\x0e"
|
||||
"\x14\x1a\x06\x0c\x12\x18\x04\x0a"
|
||||
"\x10\x16\x00\x00\x00\x00\x00\x00"};
|
||||
|
||||
char temp[] = "junkimg.jnk"; // name of de-interleaved raw image file
|
||||
|
||||
/**************************************************
|
||||
|
||||
Read the input image file in gulps of 26 sectors, reorder using the
|
||||
interleace table, and save the to the de-interleaved file
|
||||
|
||||
*/
|
||||
void RemoveInterleave
|
||||
(
|
||||
char *fn1, // ram image file name
|
||||
char * fn2, // reordered image file name
|
||||
int flag // not used
|
||||
)
|
||||
{
|
||||
int x;
|
||||
|
||||
in = fopen(fn1, "rb");
|
||||
out = fopen(fn2, "wb");
|
||||
|
||||
while (fread(buff1, 1, sizeof(buff1), in)) // read a 'track'
|
||||
{
|
||||
for (x = 0; x < SPT; x++) // shuffle
|
||||
{
|
||||
memcpy(&buff2[x * SECT_SZ], &buff1[(sectran[x] - 1) * SECT_SZ], SECT_SZ);
|
||||
}
|
||||
fwrite(buff2, 1, sizeof(buff2), out);
|
||||
}
|
||||
fcloseall();
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
|
||||
Copy a file name or extension until a space character is found
|
||||
or limit is reached.
|
||||
|
||||
*/
|
||||
void copyuntil
|
||||
(
|
||||
char *dst, // destination for copy
|
||||
char *src, // source for copy
|
||||
int count // max copy length
|
||||
)
|
||||
{
|
||||
while (*src != ' ' && count--)
|
||||
{
|
||||
*dst++ = *src++;
|
||||
}
|
||||
*dst = 0;
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
|
||||
Convert an 8,3 filename into name.ext format
|
||||
|
||||
*/
|
||||
void MakeFilename
|
||||
(
|
||||
char *fname, // destination for file name
|
||||
struct fcb *tfcb // pointer to fcb (directory entry)
|
||||
)
|
||||
{
|
||||
copyuntil(fname, tfcb->name, 8); // copy name part
|
||||
|
||||
if (tfcb->type[0] != ' ') // if extension is non-blank
|
||||
{
|
||||
strcat(fname, "."); // add a dot
|
||||
copyuntil(fname + strlen(fname), tfcb->type, 3);
|
||||
}
|
||||
}
|
||||
/**************************************************
|
||||
|
||||
Read a logical CP/M sector from the image file. Sector is a logical
|
||||
number based at the directory root. The reserved sectors(tracks)
|
||||
are added.
|
||||
|
||||
*/
|
||||
void ReadSector
|
||||
(
|
||||
unsigned char *where, // destination for read
|
||||
int sectorno // logical sector number
|
||||
)
|
||||
{
|
||||
fseek(in, (long)(DIR_LOCN + sectorno) * (long)SECT_SZ, SEEK_SET);
|
||||
fread(where, 1, SECT_SZ, in);
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
|
||||
Construct the file name and copy all records in the specified extent into the
|
||||
output file. If the file name differs from the previously processed file name
|
||||
close the previous file and open a new one with the current name.
|
||||
Since extents are psorecces in sorted order, including the extent number, this
|
||||
results in recovered files.
|
||||
|
||||
|
||||
*/
|
||||
void CopyExtentToFile
|
||||
(
|
||||
struct fcb *tfcb, // pointer to fcb (directory entry)
|
||||
int deleted // flag indicating a deleted extent
|
||||
)
|
||||
{
|
||||
int x, // general counter
|
||||
thisSect, // computed logical sector number
|
||||
said; // flag for printing
|
||||
static int extent; // logical extent number
|
||||
|
||||
MakeFilename(fname, tfcb); // extract filename
|
||||
if (strcmp(fname2, fname)) // is it different from before?
|
||||
{
|
||||
if (out != NULL)
|
||||
{
|
||||
fclose(out);
|
||||
}
|
||||
out = fopen(fname, "wb"); // create new output file
|
||||
strcpy(fname2, fname);
|
||||
printf("Extracting %sfile %s\n", deleted ? "deleted " : "", fname);
|
||||
extent = -1;
|
||||
}
|
||||
extent++;
|
||||
|
||||
//printf("%15s", fname);
|
||||
for (x = 0; x < tfcb->rc; x++) // fetch record count sectors and save
|
||||
{
|
||||
if (!(x % SPB))
|
||||
{
|
||||
//printf(" %02x", tfcb->dm[x / SPB]);
|
||||
}
|
||||
if ((exm[tfcb->dm[x / SPB]] != 0) && !said)
|
||||
{
|
||||
said = 1;
|
||||
printf(" extent %d has blocks used elsewhere\n");
|
||||
}
|
||||
exm[tfcb->dm[x / SPB]] = 1; // mark in block map
|
||||
|
||||
// convert logical sector to physical
|
||||
thisSect = (tfcb->dm[x / SPB] * SPB) + (x % SPB);
|
||||
|
||||
ReadSector(fsec, thisSect); // load the file sector
|
||||
fwrite(fsec, 1, SECT_SZ, out); // store in new file
|
||||
}
|
||||
//printf("\n");
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
|
||||
Compare routine for qsort of directory
|
||||
|
||||
*/
|
||||
int compare
|
||||
(
|
||||
void *a, // pointer to key field 'a'
|
||||
void *b // pointer to key field 'b'
|
||||
)
|
||||
{
|
||||
return memcmp(a, b, 16); // compare keys
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
*/
|
||||
main
|
||||
(
|
||||
int argc, // count of command line arguments
|
||||
char **argv // pointers to arguments
|
||||
)
|
||||
{
|
||||
int x;
|
||||
struct fcb *tfcb = (struct fcb *)buff1;
|
||||
|
||||
//printf("Dir locn %x\n", DIR_LOCN * SECT_SZ);
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
printf("File name required for compare\n\n");
|
||||
printf("Correct usage is:\n");
|
||||
printf(" extract <filename>\n\n");
|
||||
printf(" where <filename> is a diskette image file\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
RemoveInterleave(argv[1], temp, 0);
|
||||
|
||||
in = fopen(temp, "rb");
|
||||
|
||||
// load the directory into memory
|
||||
for (x = 0; x < DIR_SECTORS; x++)
|
||||
{
|
||||
ReadSector(buff1 + (x * SECT_SZ), x);
|
||||
}
|
||||
|
||||
// sort the directory in [user], name and extent order
|
||||
qsort(buff1, DIR_SECTORS, DIR_ENT_SZ, compare);
|
||||
|
||||
// process the sorted list
|
||||
for (x = 0; x < (DIR_SECTORS * DIR_ENT_PER_SEC); x++)
|
||||
{
|
||||
if ((tfcb->name[0] != 0xe5) && (tfcb->name != 0))
|
||||
{
|
||||
CopyExtentToFile(tfcb, tfcb->user == 0xe5);
|
||||
}
|
||||
tfcb++;
|
||||
}
|
||||
fcloseall();
|
||||
remove(temp);
|
||||
}
|
||||
3
CONTRIBUTIONS/cpm1.4/tools/getbdos.bat
Normal file
3
CONTRIBUTIONS/cpm1.4/tools/getbdos.bat
Normal file
@@ -0,0 +1,3 @@
|
||||
@echo off
|
||||
rem extract the BDOS image from cpm.com
|
||||
call ..\tools\getcpm ..\binaries\cpm.com bdos.bin 1200 d00
|
||||
4
CONTRIBUTIONS/cpm1.4/tools/getccp.bat
Normal file
4
CONTRIBUTIONS/cpm1.4/tools/getccp.bat
Normal file
@@ -0,0 +1,4 @@
|
||||
@echo off
|
||||
rem extract the CCP image from cpm.com
|
||||
call ..\tools\getcpm ..\binaries\cpm.com ccp.bin a00 800
|
||||
|
||||
10
CONTRIBUTIONS/cpm1.4/tools/getcpm.bat
Normal file
10
CONTRIBUTIONS/cpm1.4/tools/getcpm.bat
Normal file
@@ -0,0 +1,10 @@
|
||||
@echo off
|
||||
rem #1 = inputfn, #2 outputfn #3 = addr, #4 = lth
|
||||
rem build a script for debug
|
||||
echo rcx>dbg.bat
|
||||
echo %4>>dbg.bat
|
||||
echo n%2>>dbg.bat
|
||||
echo w%3>>dbg.bat
|
||||
echo q>>dbg.bat
|
||||
call debug %1 <dbg.bat
|
||||
|
||||
176
CONTRIBUTIONS/cpm1.4/tools/hexcon.c
Normal file
176
CONTRIBUTIONS/cpm1.4/tools/hexcon.c
Normal file
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
|
||||
Intel hex to binary converter Converts the specified file to binary
|
||||
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <conio.h>
|
||||
#include <assert.h>
|
||||
|
||||
typedef struct image_t
|
||||
{
|
||||
unsigned lowaddress, highaddress;
|
||||
} image_t;
|
||||
|
||||
//void LoadHexFile(char *fn, unsigned char *where, image_t *im);
|
||||
|
||||
|
||||
#define LINE_SIZE 500 // max size of input hex line
|
||||
#define MAX_IMG_SZ 0x4000
|
||||
|
||||
// Intel hex-file record types
|
||||
#define RT_DATA 0
|
||||
#define RT_EOF 1
|
||||
|
||||
static int hexsum;
|
||||
static unsigned char *lyne;
|
||||
|
||||
/******************************************************************************
|
||||
|
||||
Get a hexadecimal nybble from the input stream. Increment the pointer.
|
||||
|
||||
*/
|
||||
static int getnib(char **bt)
|
||||
{
|
||||
int x = **bt - '0';
|
||||
|
||||
if (x > 9)
|
||||
{
|
||||
x -= 7;
|
||||
}
|
||||
(*bt)++;
|
||||
return x;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
||||
Get a single unsigned byte (2 nibbles) from the input stream. Increment the
|
||||
pointer and add the fetched byte to the line checksum
|
||||
|
||||
*/
|
||||
static unsigned long gethex(char **bt)
|
||||
{
|
||||
int x;
|
||||
|
||||
x = getnib(bt) << 4;
|
||||
x |= getnib(bt);
|
||||
hexsum += x;
|
||||
return x;
|
||||
}
|
||||
/******************************************************************************
|
||||
|
||||
Get an unsigned short from the input stream, The pointer and the line checksum
|
||||
are maintained.
|
||||
|
||||
*/
|
||||
static unsigned long getshort(char **bt)
|
||||
{
|
||||
unsigned short ret;
|
||||
|
||||
ret = gethex(bt) << 8;
|
||||
ret |= gethex(bt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
||||
Load the specified Intel format hex file into memory as a binary
|
||||
image. Returns the file loaded in 'prog' with the base and limit filled in
|
||||
as im->lowaddress and im->highaddress respectively.
|
||||
|
||||
*/
|
||||
void LoadHexFile(char *fn, unsigned char *prog, image_t *im, unsigned limit)
|
||||
{
|
||||
char *p1; // pointer to hex input text
|
||||
FILE *ff = fopen(fn, "rb");
|
||||
int lth; // line length byte
|
||||
unsigned address, // current line address
|
||||
offset; // 0 offset of first byte
|
||||
int rt; // record type
|
||||
unsigned char kh; // fetched byte from hex file
|
||||
|
||||
printf("Converting %s\n", fn);
|
||||
|
||||
lyne = (unsigned char*)malloc(LINE_SIZE);
|
||||
|
||||
im->lowaddress = 0xffff;
|
||||
im->highaddress = 0;
|
||||
|
||||
while (fgets(p1 = lyne, LINE_SIZE, ff))
|
||||
{
|
||||
if (*p1++ != ':') // all good Intel hex file have this
|
||||
{
|
||||
break;
|
||||
}
|
||||
hexsum = 0;
|
||||
lth = gethex(&p1); // fetch length of line
|
||||
address = getshort(&p1); // fetch target address
|
||||
|
||||
if ((rt = gethex(&p1)) == RT_EOF) // fetch record type
|
||||
{
|
||||
break; // end of file
|
||||
}
|
||||
switch(rt)
|
||||
{
|
||||
default:
|
||||
printf("Invalid record type %02x\n", rt);
|
||||
getch();
|
||||
break;
|
||||
|
||||
case RT_DATA: // data bytes
|
||||
if (address < im->lowaddress)
|
||||
{
|
||||
assert(im->highaddress == 0);
|
||||
im->lowaddress = address;
|
||||
offset = address;
|
||||
}
|
||||
|
||||
while (lth--)
|
||||
{
|
||||
kh = (unsigned char)gethex(&p1);
|
||||
if ((address - offset) > limit)
|
||||
{
|
||||
printf("Hex file too large\n");
|
||||
getch();
|
||||
exit(0);
|
||||
}
|
||||
*(prog + address++ - offset) = kh;
|
||||
}
|
||||
if (address > im->highaddress)
|
||||
{
|
||||
im->highaddress = address;
|
||||
}
|
||||
break;
|
||||
}
|
||||
kh = (unsigned char)gethex(&p1);
|
||||
if (hexsum & 0xff)
|
||||
{
|
||||
printf("Hex conversion error\n");
|
||||
getch();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
free(lyne);
|
||||
fclose(ff);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
||||
Convert the specified Intel format hex file <argv[1]> into memory as a binary
|
||||
image. Saves the binary image as <argv[2]>.
|
||||
|
||||
*/
|
||||
void main(int argc, char **argv)
|
||||
{
|
||||
image_t img;
|
||||
FILE *out;
|
||||
|
||||
char *where = (char*)malloc(MAX_IMG_SZ);
|
||||
|
||||
memset(where, 0, MAX_IMG_SZ);
|
||||
LoadHexFile(argv[1], where, &img, MAX_IMG_SZ);
|
||||
out = fopen(argv[2], "wb");
|
||||
fwrite(where, 1, img.highaddress - img.lowaddress, out);
|
||||
fclose(out);
|
||||
}
|
||||
17
CONTRIBUTIONS/cpm1.4/tools/makebdos.bat
Normal file
17
CONTRIBUTIONS/cpm1.4/tools/makebdos.bat
Normal file
@@ -0,0 +1,17 @@
|
||||
set :F0:=..\isis\plm80
|
||||
set :F1:=..\isis\utils
|
||||
set :F2:=.
|
||||
set :F3:=..\isis\asm80
|
||||
..\isis\utils\isis :F0:plm80 :F2:bdos.plm
|
||||
..\isis\utils\isis :F3:asm80 :F2:bdosi.src
|
||||
..\isis\utils\isis :F1:link :F2:bdosi.obj,:F2:bdos.obj,:F1:plm80.lib to :F2:bdos.mod
|
||||
del bdosi.obj
|
||||
del bdos.obj
|
||||
..\isis\utils\isis :F1:locate :F2:bdos.mod code(0800h) stacksize(0)
|
||||
del bdos.mod
|
||||
..\isis\utils\isis :F1:objhex :F2:bdos to :F2:bdos.hex
|
||||
del bdos
|
||||
..\tools\hexcon bdos.hex bdos.abs
|
||||
del bdos.hex
|
||||
|
||||
|
||||
7
CONTRIBUTIONS/cpm1.4/tools/makeccp.bat
Normal file
7
CONTRIBUTIONS/cpm1.4/tools/makeccp.bat
Normal file
@@ -0,0 +1,7 @@
|
||||
@echo off
|
||||
set savepath=%path%
|
||||
set path=..\tools2;%path%
|
||||
rmac os2ccp
|
||||
link os2ccp[l0]
|
||||
set path=%savepath%
|
||||
set savepath=
|
||||
2
CONTRIBUTIONS/exchange-0.1/Makefile
Normal file
2
CONTRIBUTIONS/exchange-0.1/Makefile
Normal file
@@ -0,0 +1,2 @@
|
||||
all:
|
||||
gcc -o exchange -g -fno-builtin -DRLI *c
|
||||
84
CONTRIBUTIONS/exchange-0.1/README
Normal file
84
CONTRIBUTIONS/exchange-0.1/README
Normal file
@@ -0,0 +1,84 @@
|
||||
Greetings!
|
||||
|
||||
This is a utility that allows CP/M disk images to be manipulated under
|
||||
Unix. It supports disk images in either the standard 8" SSSD format or
|
||||
the P112 3.5" format. Disk images can be examined and files imported and
|
||||
exported from them.
|
||||
|
||||
The source is a slightly hacked over copy of CP/M-68K which has
|
||||
been worked over to allow compilation using GCC, to wit:
|
||||
|
||||
- A handful of typecasts have been dropped in.
|
||||
- An assumption that an int is 16 bits has been fixed.
|
||||
- An assumption that chars are signed has been fixed.
|
||||
- The file diverge.h renames all of the globals to ensure they
|
||||
don't collide with operating system globals.
|
||||
- I changed the way the BDOS communicates with the BIOS; see
|
||||
biosdef.h
|
||||
- There are probably a couple of other minor changes I made that
|
||||
I've forgotten (perhaps renaming a routine or two before I
|
||||
decided to make diverge.h).
|
||||
- A BIOS that allows the program to be run under Unix.
|
||||
|
||||
I've also added a couple of built-in commands:
|
||||
|
||||
- EXIT causes CP/M-68K to exit, returning to the host operating
|
||||
system.
|
||||
- IMPORT copies a file from the current directory of the host
|
||||
operating system into the disk image.
|
||||
- EXPORT copies a file from the disk image into the current
|
||||
directory of the host operating system.
|
||||
|
||||
IMPORT and EXPORT do not accept wildcards. This is just a quickie hack
|
||||
that turned out to be useful, not a snazzy disk image manipulation
|
||||
program.
|
||||
|
||||
To build the program, execute make. This results in an executable called
|
||||
exchange. The command-line syntax is:
|
||||
|
||||
exchange [-p112] file.img
|
||||
|
||||
-p112 This option tells the file to use the P112 3.5" disk format
|
||||
for the image. By default, the the standard 8" SSSD format is
|
||||
used.
|
||||
|
||||
file.img is the name of the disk image that should be used.
|
||||
|
||||
In this example, I copy the file BDOS.LST from an 8" SSSD image
|
||||
containing CP/M 1.4 sources (obtained from http://cpm.z80.de/) to user 1
|
||||
of the P112 boot disk image (obtained from
|
||||
http://members.iinet.net.au/~daveb/p112/p112.html):
|
||||
|
||||
> mac> uname -a
|
||||
> Linux mac.no.domain 2.4.22-2f #1 Sun Nov 9 16:49:49 EST 2003 ppc ...
|
||||
> mac> ls
|
||||
> bdosPLM.img bootdisk.img exchange
|
||||
> mac> ./exchange bdosPLM.img
|
||||
>
|
||||
> A>dir
|
||||
> A: BDOSI SRC : BDOS PLM : BDOS OBJ : BDOS LST
|
||||
> A>export BDOS.LST
|
||||
> export BDOS .LST -> BDOS.LST
|
||||
> A>exit
|
||||
> mac> ls
|
||||
> BDOS.LST bdosPLM.img bootdisk.img exchange
|
||||
> mac> ./exchange -p112 bootdisk.img
|
||||
>
|
||||
> A>user 1
|
||||
>
|
||||
> 1A>dir
|
||||
> A: RECEIVE PAS : UUENCODE PAS : UUDECODE PAS : USER MAC : ROM UUE
|
||||
> A: ROM PAS : ROM COM
|
||||
> 1A>import bdos.lst
|
||||
> import BDOS.LST -> BDOS .LST
|
||||
> 1A>dir
|
||||
> A: RECEIVE PAS : UUENCODE PAS : UUDECODE PAS : USER MAC : ROM UUE
|
||||
> A: ROM PAS : ROM COM : BDOS LST
|
||||
> 1A>exit
|
||||
> mac>
|
||||
|
||||
Enjoy!
|
||||
|
||||
Roger Ivie
|
||||
anachronda@hotmail.com
|
||||
|
||||
89
CONTRIBUTIONS/exchange-0.1/README.MARKDOWN
Normal file
89
CONTRIBUTIONS/exchange-0.1/README.MARKDOWN
Normal file
@@ -0,0 +1,89 @@
|
||||
Program by Roger Ivie. Exchange is a utility that allows CP/M disk images to be manipulated under Unix. It supports disk images in either the standard 8" SSSD format or the P112 3.5" format. Disk images can be examined and files imported and exported from them.
|
||||
The source is a slightly hacked over copy of CP/M-68K BDOS and CCP which has been worked over to allow compilation using GCC.
|
||||
|
||||
/README
|
||||
|
||||
Greetings!
|
||||
|
||||
This is a utility that allows CP/M disk images to be manipulated under
|
||||
Unix. It supports disk images in either the standard 8" SSSD format or
|
||||
the P112 3.5" format. Disk images can be examined and files imported and
|
||||
exported from them.
|
||||
|
||||
The source is a slightly hacked over copy of CP/M-68K which has
|
||||
been worked over to allow compilation using GCC, to wit:
|
||||
|
||||
- A handful of typecasts have been dropped in.
|
||||
- An assumption that an int is 16 bits has been fixed.
|
||||
- An assumption that chars are signed has been fixed.
|
||||
- The file diverge.h renames all of the globals to ensure they
|
||||
don't collide with operating system globals.
|
||||
- I changed the way the BDOS communicates with the BIOS; see
|
||||
biosdef.h
|
||||
- There are probably a couple of other minor changes I made that
|
||||
I've forgotten (perhaps renaming a routine or two before I
|
||||
decided to make diverge.h).
|
||||
- A BIOS that allows the program to be run under Unix.
|
||||
|
||||
I've also added a couple of built-in commands:
|
||||
|
||||
- EXIT causes CP/M-68K to exit, returning to the host operating
|
||||
system.
|
||||
- IMPORT copies a file from the current directory of the host
|
||||
operating system into the disk image.
|
||||
- EXPORT copies a file from the disk image into the current
|
||||
directory of the host operating system.
|
||||
|
||||
IMPORT and EXPORT do not accept wildcards. This is just a quickie hack
|
||||
that turned out to be useful, not a snazzy disk image manipulation
|
||||
program.
|
||||
|
||||
To build the program, execute make. This results in an executable called
|
||||
exchange. The command-line syntax is:
|
||||
|
||||
exchange [-p112] file.img
|
||||
|
||||
-p112 This option tells the file to use the P112 3.5" disk format
|
||||
for the image. By default, the the standard 8" SSSD format is
|
||||
used.
|
||||
|
||||
file.img is the name of the disk image that should be used.
|
||||
|
||||
In this example, I copy the file BDOS.LST from an 8" SSSD image
|
||||
containing CP/M 1.4 sources (obtained from http://cpm.z80.de/) to user 1
|
||||
of the P112 boot disk image (obtained from
|
||||
http://members.iinet.net.au/~daveb/p112/p112.html):
|
||||
|
||||
> mac> uname -a
|
||||
> Linux mac.no.domain 2.4.22-2f #1 Sun Nov 9 16:49:49 EST 2003 ppc ...
|
||||
> mac> ls
|
||||
> bdosPLM.img bootdisk.img exchange
|
||||
> mac> ./exchange bdosPLM.img
|
||||
>
|
||||
> A>dir
|
||||
> A: BDOSI SRC : BDOS PLM : BDOS OBJ : BDOS LST
|
||||
> A>export BDOS.LST
|
||||
> export BDOS .LST -> BDOS.LST
|
||||
> A>exit
|
||||
> mac> ls
|
||||
> BDOS.LST bdosPLM.img bootdisk.img exchange
|
||||
> mac> ./exchange -p112 bootdisk.img
|
||||
>
|
||||
> A>user 1
|
||||
>
|
||||
> 1A>dir
|
||||
> A: RECEIVE PAS : UUENCODE PAS : UUDECODE PAS : USER MAC : ROM UUE
|
||||
> A: ROM PAS : ROM COM
|
||||
> 1A>import bdos.lst
|
||||
> import BDOS.LST -> BDOS .LST
|
||||
> 1A>dir
|
||||
> A: RECEIVE PAS : UUENCODE PAS : UUDECODE PAS : USER MAC : ROM UUE
|
||||
> A: ROM PAS : ROM COM : BDOS LST
|
||||
> 1A>exit
|
||||
> mac>
|
||||
|
||||
Enjoy!
|
||||
|
||||
Roger Ivie
|
||||
anachronda@hotmail.com
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user