; CPMSYS.MAC ; 10 APRIL 1996 RLEE H. PETERS ; ;THIS IS A HACKED VERSION OF MOVCPM.COM FOR THE PURPOSE OF ;ACTING AS A CPM LOADER SIMILAR TO CPM3 ; ;THIS IS FILE IS FOR THE M80 COMPILER ; ; MOVCPM.COM NOTES 10 APRIL 1996 RHP ; ;THE ORIGINAL MOVCPM PROGRAM WAS ORIGINALLY COPYRIGHTED BY ;DIGITAL RESEARCH AND IS NOW THE PROPERTY OF NOVELLE. ; ;THIS FILE WAS DISASSEMBLED FROM THE MOVCPM.COM THAT WAS ;DISTRIBUTED BY MORROW WITH THEIR REV 5.3E4 CP/M BIOS WITH ;THE GRATEFUL HELP OF RON JACOBS NOTES. ; ;ANYONE PLANNING TO USE THIS PROGRAM FOR COMMERCIAL ;PURPOSES IS NOTIFIED THAT PRIOR TO SUCH USE, YOU MUST ;MAKE YOUR PEACE WITH: ; ; DAVID AJ. McGLONE ; LAMBDA SOFTWARE PUBLISHING ; 149 WEST HILLIARD LANE ; EUGENE OR 97404-3057 ; D.MCGLONE@GENIE.GEIS.COM ; ;AS MR McGLONE HOLDS THE FRANCHISE FROM NOVELLE TO DISTRIBUTE ;THESE CP/M PRODUCTS. ; ; ;MOVCPM53 IS BEING MODIFIED TO ALLOW EASY MODIFICATION AND ;BOOTING OF EXPERIMENTAL VERSIONS OF CP/M VARIETIES IN A ;FASHION SIMILAR TO CP/M3. MY NORMAL BOOT DISKS AUTOLOAD ;THE CP/M3 CPMLDR.COM FILE. IF THIS FILE IS NOT ON DISK ;OR HAS BEEN RENAMED, THEN THE CP/M2.2 SYSTEM IS LEFT AS ;THE OPERATING SYSTEM. THIS VERSION OF MOVCPM IS CALLED ;CPMSYS TO BE COMPATIBLE. ; ; ; COMMAND USAGE: CPMSYS X1 X2 ; ; IF ENTRIES X1 AND X2 ARE MISSING, THEN MAX MEMORY IS TESTED ; FOR AND USED TO GENERATE A SYSTEM WHICH IS THEN MOVED INTO ; POSITION AND THEN EXECUTED. ; ; IF X1 IS A * THEN A MAX MEMORY SYSTEM IS GENERATED. ; IF X1 IS A NUMBER BETWEEN 20 AND 64 THEN THAT SIZE ; SYSTEM IS GENERATED, ELSE AN ERROR MSG IS PRINTED. ; ; IF X2 IS MISSING, THE SYSTEM IS EXECUTED. ; IF X2 IS A *, THEN 'READY FOR SYSGEN' IS PRINTED. ; ;CHANGES FROM MOVCPM TO CPMSYS ; ;REMOVED THE 'SYNCHRONIZATION ERROR' CODE ** ;REMOVED THE REFERENCES TO THE 'BOOT' CODE ** ;REMOVED THE 'MOVE DOWN 80HEX' CODE ** ;REMOVED THE 'CCP' CODE AFTER CONVERTING CCP TO A COM FILE ; AND REWRITING THE BIOS TO CALL CCP.COM ** ;CHANGED CCP.COM TO COMMAND.COM AND IN THE BIOS ** ;REWROTE THE COLD BOOT AND WARM BOOT PARTS OF THE BIOS ** ;MOVED THE SPR HEADER DOWN TO WASTE LESS CORE ** ;ADDED PUBLIC AND EXTERNAL CALLS TO PROGRAM AND BIOS ; TO CUT DOWN ON SEARCHING FOR CODE IN THE BIOS ** ; ; ASEG ORG 00100H ; ; EQUATES ; .Z80 ; REBOOT EQU 00000H ;WARM BOOT VECTOR BDOSE EQU 00005H ;BDOS JUMP ENTRY POINT BDOSAD EQU BDOSE+1 ;ADDRESS OF BOTTOM OF BDOS TAIL EQU 0005DH ;START OF FILE NAME TAIL TAIL2 EQU 0006DH ;START OF COMMAND TAIL TESTST EQU 00700H ;START OF MEMORY TO TEST HEADER EQU 00800H ;START OF RELOCATABLE CODE HEADER CODELG EQU 00801H ;CODE LENGTH IN SPR HEADER IMAGE EQU 00900H ;START OF CPM CODE IMAGE (BOOT) CCPLOC EQU 00B00H ;START OF CCP IN THE IMAGE IMSER EQU 01300H ;LOCATION OF SER# IN THE CCP IMAGE ICOLD EQU 01600H ;COLD BOOT ENTRY IN IMAGE PBIOS EQU 008F7H ;POINTER INTO BIOS FOR 'K' SEARCH PRSTRG EQU 009H ;BDOS PRINT STRING CODE ; ALF EQU 00AH ;LINE FEED ACR EQU 00DH ;CARRIAGE RETURN ; ; ;PROGRAM START ; JP START ; LBIOS: DB 10H ;LENGTH OF BIOS ; ; COPYRIGHT NOTICE ; DB 'Copyright (C) Digital Research' DB ', 1980' ; DB 'COPYRIGHT (C) RLEE H. PETERS, 1996' ; ; PROGRAM STARTS HERE ; START: LD SP,HEADER ;SET STACK BELOW THE SPR HEADER LD DE,TAIL ;1ST CHAR IN COMMAND TAIL LD A,(DE) ;A=1ST CHAR CP ' ' ;IF BLANK, MAKE BIG CPM JP Z,RAMCHK ;CHECK FOR MAX RAM CP '?' ;IF '?', MAKE BIG CPM JP Z,RAMCHK ;CHECK FOR MAX RAM ; ; CHECK FOR 2 ASCII NUMBERS AND CONVERT TO HEX ; TO GET SYSTEM SIZE IN K ; LD HL,0000H ASCHEX: LD A,(DE) ;1ST COMMAND TAIL CHAR INC DE ;NEXT CHAR CP ' ' ;IF A SPACE, JP Z,RNGCHK ;DO MEM SIZE RANGE CHECK OR A ;IS IT A NULL? JP Z,RNGCHK ;DO MEM SIZE RANGE CHECK SUB '0' ;ASCII > HEX CP 10 ;IF > 9 THEN NOT A DIGIT JP NC,PERR1 ;PRINT MEM RANGE ERROR MSG ; ; MULTIPLY BY 10 ON SECOND PASS ; ADD HL,HL ;MULTIPLY X2 PUSH HL ;SAVE X2 ADD HL,HL ;X4 ADD HL,HL ;X8 POP BC ;RECOVER X2 VALUE ADD HL,BC ;NOW X10 LD C,A ;PUT X10 VALUE IN C LD B,0 ;CLEAR B ADD HL,BC ;HL=TARGET SIZE IN K(HEX) JP ASCHEX ;LOOP TIL DONE ; ; CHECK MEMORY SIZE FOR VALID RANGE ; RNGCHK: LD A,H ;HIGH BYTE OF MEMORY SIZE OR A ;IF >0 THEN TOO LARGE, >64K JP NZ,PERR1 ;PRINT MEM RANGE ERROR MSG LD A,L ;LOW BYTE OF MEMORY SIZE CP 16 ;IF LESS TAHN 16K THEN TOO SMALL JP C,PERR1 ;PRINT MEM RANGE ERROR MSG LD L,0 LD H,A ;HL = TARGET SIZE IN K ADD HL,HL ;X2 ADD HL,HL ;X4 = TARGET SIZE IN PAGES JP SAVSIZ ;SAVE THE MEMORY SIZE ; ; PRINT INVALID MEMORY RANGE MESSAGE ; PERR1: LD DE,INVMEM CALL PRTMSG JP REBOOT ; ; TEST THE RAM FOR MAX CONTIGUOUS SIZE ; IF MEMORY SIZE IS NOT SPECIFIED ; RAMCHK: LD HL,TESTST ;START TO TEST MEMORY HERE RAMLP: INC H ;NEXT BYTE JP Z,XLOOP ;ALL FFFF TESTED? LD A,(HL) ;GET THE CONTENTS OF RAM CPL ;COMPLEMENT IT LD (HL),A ;PUT IT BACK CP (HL) ;IS IT THE SAME? CPL ;COMPLEMENT IT AGAIN LD (HL),A ;PUT IT BACK THE WAY IT WAS JP Z,RAMLP ;OK THN LOOP TIL DIFFERENT XLOOP: LD A,H ;GET MEM SIZE AND 252 ;ROUND OFF PAGE SIZE LD H,A ;RESTORE MEMORY SIZE IN PAGES ; ; SAVE THE MEMORY SIZE FROM EITHER METHOD ; SAVSIZ: PUSH HL ;SAVE THE MEMORY SIZE ON THE STACK LD HL,(BDOSAD) ;POINT TO OPERATING SYSTEM BDOS LD (BDOSST),HL ;STORE IT FOR LATER POP HL ;RECOVER TARGET SIZE IN PAGES PUSH HL ;SAVE IT AGAIN FOR LATER LD A,H ;CHANGE TO SIZE IN K DEC A RRCA RRCA AND 03FH ;MASK OFF TWO HIGH BITS INC A LD C,A ;C=TARGET SIZE IN HEX LD HL,CSIZE ;LOAD SIZE IN 'CONSTRUCTING' MSG CALL H2ASC ;CONVERT TO 2 ASCII DIGITS LD DE,CONSTR ;POINT TO 'CONSTRUCTING' MSG CALL PRTMSG ;PRINT IT ; ; NOW LOOK IN THE IMAGE BIOS FOR THE 'K CP/M 2.2' STRING ; AND PATCH IN THE NEW TARGET SIZE ; LD HL,(CODELG) ;POINT TO IMAGE LENGTH IN SPR HEADER ; ; THE SPR HEADER INDICATES THE LENGTH OF THE TOTAL RELOCATABLE IMAGE ; BOOT+CCP+BDOS+BIOS AND THUS THE LOCATION OF THE START OF THE BIT MAP ; LD B,H ;RELATIVE BIT MAP POINTER TO BC LD C,L PUSH BC ;SAVE IT LD HL,PBIOS ;LOAD OFFSET TO POINT IN BIOS ADD HL,BC ;MAKE POINTER ABSOLUTE KLOOP: LD A,B ;HIGH ADDRESS OR C ;LOW ADDRESS JP Z,GOGOGO ;IF ZERO THEN STRING NOT FOUND DEC BC ;DECREMEMT BIT MAP POINTER DEC HL ;DECREMENT POINTER LD A,(CHR_K) ;LOOK FOR 'K' IN 'K CP/M 2.2' CP (HL) ;THIS THE ONE? JP NZ,KLOOP ;NOPE, TRY AGAIN PUSH BC ;SAVE THE FOUND LOCATION LD C,10 ;STRING LENGTH COUNT PUSH HL ;SAVE HL LD DE,CHR_K ;POINT TO OUR 'K CP/M 2.2' STRING ; ; COMPARE THE STRINGS IN THE MOVER AND THE IMAGE ; CLOOP: LD A,(DE) ;GET A CHARACTER CP (HL) ;COMPARE WITH THE IMAGE JP NZ,NOMAT ;NO MATCH INC DE ;NEXT CHARACTER PAIR INC HL DEC C JP Z,MATCH ;MATCH FOUND JP CLOOP ;KEEP LOOKING ; ;HERE RESIDES THE NORTORIOUS 'SYNCHRONIZATION ERROR' CODE ;THIS CODE COMPARES THE SER NO. IN THE RUNNING SYSTEM AND ;THE CODE IN MOVCPM. IF NO MATCH, THEN THE CODE IS CHANGED ;TO MAKE A 'HERE: JMP HERE' HANG LOOP REQUIRING REBOOT. ; DB 001H ;DUMMY BYTE SDELY: XOR A ;MODIFIED TO JUMP IF BAD SER# ;BECOMES A HANG JMP HANG LOOP DELUP: DEC A ;SMALL DELAY HERE JP NZ,DELUP LD HL,076F3H ;LOAD BDOSST WITH F376H LD (BDOSST),HL ;HIDE POINTERS TO SER # LD HL,CHCALL ;CHANGE JMP INSTRUCTION TO CALL LD (HL),0CDH ;CD = CALL LD DE,CHR_K ;NOW POINTS TO FAKE MSG LD HL,0FFD7H ;OFFSET FOR REAL MSG ADD HL,DE ;POINT TO SYNCH ERROR MSG EX DE,HL ;PUT MSG PTR IN DE CALL PRTMSG ;PRINT SYNCH ERROR MSG NOMAT: POP HL POP BC JP KLOOP MATCH: POP HL ;RECOVER LOCATION OF K POP BC ; DEC HL ;HL POINTS TO 1'SDIGIT EX DE,HL ;NOW DE POINTS TO 1'S DIGIT LD HL,(CSIZE) ;GET SIZE, H=1'S, L=10'S EX DE,HL ;NOW PUT THEM IN DE LD (HL),D ;PUT 1'S IN THE IMAGE DEC HL ;GET 10'S LD (HL),E ;PUT 10'S IN THE IMAGE ; ; ADD OFFSET TO BOOT AND CP/M IMAGE ; GOGOGO: LD BC,BDOSST ;GET BDOS ENTRY ADDRESS LD A,(BC) ;GET THE FIRST DIGIT CP 6 ;SHOULD BE A 6 LD A,0 ;CHANGE IT TO 0 LD (BC),A ;CHANGE ADDR TO POINT TO SERIAL # LD A,(LBIOS) ;GET THE # OF PAGES OF THE BIOS ADD A,22 ;ADD # PAGES IN CCP AND BDOS LD B,A ;B = CP/M LENGTH IN PAGES POP HL ;RECOVER IMAGE LENGTH EX (SP),HL ;HL = TOP OF CP/M + 1 LD A,H ;LAST PAGE + 1 OF CP/M TO RELOCATE SUB B ;A = NEW PAGE FOR CCP LD H,A ;HL = ADDRESS OF NEW CCP LD (OFFSET),HL ;STORE CP/M OFFSET TO BE ADDED POP BC ;RECOVER IMAGE LENGTH PUSH BC ;SAVE IT FOR LATER LD HL,IMAGE ;POINT TO START OF IMAGE PUSH HL ;SAVE IMAGE START ADD HL,BC ;POINT TO BIT MAP EX (SP),HL ;PUSH BIT MAP ADDR, POP IMAGE ADDR EX DE,HL ;DE=IMAGE ADDR, HL=ASCII LENGTH LD HL,(OFFSET) ;GET OFFSET UPDATE: LD A,B ;HIGH BYTE OF IMAGE ADDRESS OR C ;IS C 0 YET? JP Z,MDONE ;DONE IF C = 0 DEC BC ;DECREMENT IMAGE LENGTH LD A,E ;LOW BYTE OF IMAGE ADDR AND 7 ;MASK BIT MAP FOR CURRENT BIT SET JP NZ,NXTBYT ;DONE WITH BYTE FROM BIT MAP? EX (SP),HL ;GET NEXT BYTE FROM BIT MAP LD A,(HL) ;A = BIT MAP BYTE INC HL ;POINT TO NEXT BIT MAP BYTE EX (SP),HL ;PUSH BIT MAP POINTTER, POP IMAGE ADDR LD L,A ;L = BYTE FROM BIT MAP NXTBYT: LD A,L ;A = ROTATED BIT MAP BYTE RLA ;ROTATE THE BIT MAP BYTE LD L,A ;L = ROTATED BYTE JP NC,NOFSET ;IS THIS AN OFFSET BIT/BYTE? LD A,(DE) ;GET THE BYTE FROM THE IMAGE ADD A,H ;ADD OFFSET LD (DE),A ;STORE IT IN THE IMAGE NOFSET: INC DE ;NEXT IMAGE BYTE JP UPDATE ;LOOP TIL ALL ADDRESSES UPDATED ; ; HERE IS THE SERIAL NUMBER CHECK IMAGE VS OPERATING CP/M ; MDONE: POP DE ;CLEAN UP STACK LD DE,IMSER ;SERIAL # LOCATION IN THE IMAGE LD HL,(BDOSST) ;POINT TO SER # IN OPERATING BDOS LD C,6 ;6 BYTES TO CHECK SLOOP:LD A,(DE) ;POINT TO IMAGE SER # BYTE CP (HL) ;ARE THEY THE SAME? ; JP NZ,BADMAT ;NO MATCH - HANG DB 00H,00H,00H ;NOP OUT THE JUMP INC HL ;NEXT SYSTEM SER # INC DE ;NEXT IMAGE SER # DEC C ;LESS ONE COUNT JP NZ,SLOOP ;LOOP IF NOT ALL CHECKED ; ; HERE FOR VALID SER #, NOW CHECK FOR ADITIONAL INSTRUCTIONS ; LD A,(TAIL2) ;CHECK TAIL FOR SYSGEN OR RUN CP ' ' ;SPACE IS MORE INSTRUCTIONS JP Z,RELRUN ;IF NO 2ND * THEN RUN ; ; IF THE FIRST 128 BYTES IN THE IMAGE ARE 0'S ; THEN MOVE THE IMAGE DOWN 80H BYTES ; LD B,128 ;LOAD 80HEX LD HL,IMAGE ;POINT TO IMAGE ZLOOP: LD A,(HL) ;GET THE FIRST BYTE OF 128 OR A ;IS IT A ZERO? JP NZ,MEMFIN ;FOUND A NON ZERO BYTE INC HL ;NEXT BYTE DEC B ;ONE LESS COUNT JP NZ,ZLOOP ;LOOP TILL 128 BYTES CHECKED EX DE,HL ;DE = 980H LD HL,(CODELG) ;HL = IMAGE LENGTH LD BC,0FF80H ;FF80 = FFFF - 80 ADD HL,BC ;SUBTRACT 80 FROM IMAGE LENGTH LD B,H ;BC = NEW IMAGE LENGTH LD C,L LD HL,IMAGE ;POINT TO START OF IMAGE MLOOP: LD A,B ;CHECK FOR ALL BYTES MOVED YET OR C JP Z,MEMFIN ;DONE - ALL MOVED DEC BC ;COUNT MINUS 1 LD A,(DE) ;GET BYTE TO BE MOVED LD (HL),A ;LAY IT DOWN 80H LOWER INC DE ;NEXT BYTE TO MOVE INC HL ;NEXT ADDRESS TO MOVE TO JP MLOOP ;LOOP TIL ALL MOVED ; ; NO MATCH TO SERIAL #, PATCH JUMP ADDRESS TO HANG HERE ; DB 001H ;DUMMY BYTE FOR CONFUSION HANG: JP HANG ; MEMFIN: LD DE,HEADER ;POINT TO HEADER POP HL ;RECOVER IMAGE LENGTH ADD HL,DE ;SIZE OF MOVCPM TO SAVE LD C,H ;C = SIZE OF FILE TO SAVE IN HEX LD HL,SAVEL ;STORE IN 'SAVE' STRING CALL H2ASC ;CONVERT TO 2 ASCII DIGITS LD HL,(CSIZE) ;GET CP/M SIZE FROM 'CONSTRUCTING' MSG LD (SSIZE),HL ;LOAD IT INTO 'SYSGEN' MSG LD DE,SYSGEN ;POINT TO 'SYSGEN OR SAVE' MSG CALL PRTMSG ;PRINT IT JP REBOOT ;QUIT ; ; CONVERT A HEX NUMBER IN C TO TWO ASCII DIGITS ; H2ASC: LD (HL),'0' ;STUFF STRING POINTED BY HL WITH 0 INC HL ;NEXT STRING LOCATION LD (HL),'0' ;AGAIN INC C ;BUMP FOR NEXT LOOP ENTRY HLOOP: DEC C ;DECREMENT HEX NUMBER RET Z ;WHEW - GET OUT OF HERE INC (HL) ;INCREMENT 1'S DIGIT LD A,(HL) ;GET THE DIGIT CP 3AH ;IS IT A '9' OR LESS? JP C,HLOOP ;LOOP TIL 1'S IS <= '9' DEC HL ;POINT TO THE 10'S DIGIT INC (HL) ;INCREMENT 10'S DIGIT INC HL ;POINT TO THE 1'S DIGIT LD (HL),'0' ;LOAD 1'S DIGIT WITH '0' JP HLOOP ;WORK OFF THE CARRY ; ; ON A BAD SER# MATCH, PATCHES SDELAY TO BE A NEW ADDRESS ; TO FORM A HANG JMP HANG LOOP ; BADMAT: LD HL,SDELY ;POINT TO ADDR TO CHANG LD (HANG+1),HL ;NEW ADDRESS BYTE JP HANG ; ; RELOCATE CP/M TO ITS OPERATING LOCATION AND RUN IT ; A REGULAR CP/M SYSTEM MAY BE UNSTABLE ; RELRUN: POP BC ;RECOVER IMAGE LENGTH LD A,B ;GET LOW DIGIT SUB 2 ;SUBTRACT LENGTH OF BOOT LD B,A ;UPDATE THE IMAGE LENGTH LD DE,CCPLOC ;POINT TO START OF THE CCP IMAGE LD HL,(OFFSET) ;POINT TO MEMORY LOC FOR CP/M START RLOOP: LD A,(DE) ;GET BYTE TO RELOCATE LD (HL),A ;STORE IT INC DE ;NEXT BYTE INC HL ;NEXT DESTINATION DEC BC ;ONE LESS TO GO LD A,B ;CHECK FOR ZERO YET OR C JP NZ,RLOOP ;NOT DONE, THEN LOOP LD DE,ICOLD ;COLD BOOT ENTRY IN THE IMAGE LD HL,(OFFSET) ;HERE IS THE OFFSET ADD HL,DE ;GET THE RELOCATED ADDRESS JP (HL) ;JUMP TO THE RELOCATED COLD BOOT ; ; PRINT THE MESSAGE POINTED TO BY DE ; PRTMSG: LD C,PRSTRG ;PRINT COMMAND CHCALL: JP BDOSE ;TO BDOS TO DO IT ;;;; JP BDOSE ;TO BDOS TO DO IT ; ; SYSTEM STORAGE ; BDOSST: DW 0000H ;OPERATING SYSTEM BDOS ADDRESS ; OFFSET: DW 0000H ;STORE OFFSET FOR NEW SYSTEM ; ; SYSTEM MESSAGES ; INVMEM: DB ACR,ALF DB 'Invalid memory size$' ; SYNERR: DB ACR,ALF DB 'Synchronization error$' ; CONSTR: DB ACR,ALF DB 'Constructing ' CSIZE: DB '00' CHR_K: DB 'K CP/M 2.2$' ; SYSGEN: DB ACR,ALF DB 'Ready for "sysgen" or' DB ACR,ALF DB '"save ' SAVEL: DB '00 cpm' SSIZE: DB '00.com"' DB ACR,ALF,'$' ; ALDONE: DS HEADER - ALDONE ;FILL TO THE HEADER WITH ZEROS ; ; START OF SPR HEADER, 1ST BYTE 0, 2ND,3RD BYTES IMAGE LENGTH ; ; ORG 0800H ; ; DB 0 DB 0,0 ;IMAGE LENGTH FILHDR: DS IMAGE - FILHDR ; ; ; ; START OF IMAGE ; ; 0900H ; ; NORMAL IMAGE HAS BOOT, CCP, BDOS, AND BIOS ; ; ; IMAGE IS FOLLOWED BY THE BIT MAP ; LENGTH DETERMINED BY THE IMAGE = 1 BIT PER BYTE ; DB 0 END