diff --git a/Source/Apps/Build.cmd b/Source/Apps/Build.cmd index 48a858ae..87038f2e 100644 --- a/Source/Apps/Build.cmd +++ b/Source/Apps/Build.cmd @@ -35,6 +35,7 @@ pushd Tune && call Build || exit /b & popd pushd FAT && call Build || exit /b & popd pushd I2C && call Build || exit /b & popd pushd ramtest && call Build || exit /b & popd +pushd zmodem && call Build || exit /b & popd copy *.com %APPBIN%\ || exit /b diff --git a/Source/Apps/ZMODEM/Build.cmd b/Source/Apps/ZMODEM/Build.cmd new file mode 100644 index 00000000..7063e7f3 --- /dev/null +++ b/Source/Apps/ZMODEM/Build.cmd @@ -0,0 +1,18 @@ +@echo off +setlocal + +set TOOLS=..\..\..\Tools + +set PATH=%TOOLS%\zx;%PATH% + +set ZXBINDIR=%TOOLS%\cpm\bin\ +set ZXLIBDIR=%TOOLS%\cpm\lib\ +set ZXINCDIR=%TOOLS%\cpm\include\ + +zx Z80ASM -ZMO-RW01/H || exit /b +zx MLOAD25 -ZMP.COM=ZMPX.COM,ZMO-RW01 || exit /b + +copy /Y zmp.com ..\..\..\Binary\Apps\ || exit /b +copy /Y *.ovr ..\..\..\Binary\Apps\ || exit /b +copy /Y *.hlp ..\..\..\Binary\Apps\ || exit /b +copy /Y zmp.doc ..\..\..\Doc\ || exit /b \ No newline at end of file diff --git a/Source/Apps/ZMODEM/Clean.cmd b/Source/Apps/ZMODEM/Clean.cmd new file mode 100644 index 00000000..161b365c --- /dev/null +++ b/Source/Apps/ZMODEM/Clean.cmd @@ -0,0 +1,7 @@ +@echo off +setlocal + +if exist zmp.com del zmp.com +if exist *.hex del *.hex +if exist *.lst del *.lst +if exist *.zip del *.zip diff --git a/Source/Apps/ZMODEM/zmconfig.ovr b/Source/Apps/ZMODEM/zmconfig.ovr new file mode 100644 index 00000000..556170c1 Binary files /dev/null and b/Source/Apps/ZMODEM/zmconfig.ovr differ diff --git a/Source/Apps/ZMODEM/zminit.ovr b/Source/Apps/ZMODEM/zminit.ovr new file mode 100644 index 00000000..c522157a Binary files /dev/null and b/Source/Apps/ZMODEM/zminit.ovr differ diff --git a/Source/Apps/ZMODEM/zmo-rw01.z80 b/Source/Apps/ZMODEM/zmo-rw01.z80 new file mode 100644 index 00000000..b2b8af4b --- /dev/null +++ b/Source/Apps/ZMODEM/zmo-rw01.z80 @@ -0,0 +1,862 @@ +;----------------------------------------------------------------------------- +; +; Overlay for ZMP (Z-Modem Program) +; +; Name ZMO-RW01.Z80 +; +; Dated Sep 14, 1988 +; +; Written by - +; Ron Murray, c/o Z-Node 62, 061-9-450-0200, Perth, Western Australia. +; +; Modified to ZMP v1.2 standard rjm 15/9/88 +; Modified to ZMP v1.3 standard rjm 11/10/88 +; Modified to ZMP v1.4 standard rjm 20/11/88 +; Modified to ZMP v1.5 standard rjm 25/3/89 +; +; ZMO-RW01.Z80 ROMWBW version using HBIOS and https://github.com/mecparts/zmp version of zmodem +; Databits, stop bit, parity setting not supported. +; All i/o is through the hbios. +; Timing delay calcuations based on hbios reported cpu speed. +; Console is assumed to be current hbios CIO console +; Only 1 port is supported by this version of zmp. +; Port setting supports 2 port, port A is CIO 1, port B is CIO 2 +; This overlay is compatible with Ron Murray's original ZMP15 which support two ports. +; Teraterm users may need to change the ZmodemWinSize value to 1024 in teraterm.ini file. +; +;----------------------------------------------------------------------------- +; +; +; System-dependent code overlay for ZMODEM +; +; +; +; Insert your own code as necessary in this file. Code contained herein +; has been written in Z80 code for use with M80 or SLR. Assemble as follows: +; +; SLR ZMO-xx01/h +; MLOAD ZMP.COM=ZMODEM.COM,ZMO-xx01.HEX +; or +; M80 =ZMO-xx01.Z80 +; RELHEX ZMO-xx01 +; MLOAD ZMP.COM=ZMODEM.COM,ZMO-xx01.HEX +; +; +; (Don't use L80 without changing the source for assembly as a +; cseg file.) +; +;----------------------------------------------------------------------------- +; +; +; Notes on modifying this file: +; +; C requires that functions do not change either index register (IX or IY). +; If your overlay requires either of these to be changed, ensure they are +; restored to the original values on return. +; Since collecting parameters from C functions can be tricky, only change +; the parts marked 'Insert your own code here'. Do NOT modify the jump +; table at the start. Do NOT modify the entry/exit sections of each +; function. Do NOT pass 'GO'. Do NOT collect $200. +; Apart from defining modem functions, this file also defines terminal +; characteristics. Examples provided are for ADM-3A (with a few of my own +; additions). Modify to suit your own terminal. An inline print routine +; is provided for printing strings in the usual way: usage is +; +; call print +; db 'required string',0 +; +;----------------------------------------------------------------------------- +; +; +; Don't forget to set your clock speed at the clkspd variable. +; +; +; If you find your overlay exceeds the maximum size (currently 0400h), +; you will have to contact me for another version. If too many people need +; to do it, we haven't allowed enough room. +; +; Ron Murray 15/8/88 +; +; +; +;--------------------------------------------------------------------------- + +false equ 0 +true equ not false + +;------------------------------------------------------------------------------ + +; User-set variables: + +;clkspd equ 10 ; Processor clock speed in MHz +debug equ false ; to allow debugging of overlay with Z8E etc. + +;Set the following two equates to the drive and user area which will contain +; ZMP's .OVR files, .CFG file, .FON file and .HLP file. Set both to zero +; (null) to locate them on the drive from which ZMP was invoked. + +overdrive equ 0 ; Drive to find overlay files on ('A'-'P') +overuser equ 0 ; User area to find files +; +; Initial ROMWBW CIO device +; +initdev equ 1 ; Second CIO device on system +; +; Initial baud rate code +; +initbr equ 10 ; Refer to "baudtbl" table below - brate column +; +;------------------------------------------------------------------------------ + + +; NOT user-set variables + +userdef equ 0145h ; origin of this overlay + ; This address should not change with + ; subsequent revisions. +mspeed equ 03ch ; location of current baud rate. +ovsize equ 0400h ; max size of this overlay + + .z80 ; use z80 code + aseg ; absolute + + if debug + org 100h ; so you can debug it with cebug, zsid, etc + else + org userdef + endif + + +esc equ 1bh +ctrlq equ 11h +cr equ 0dh +lf equ 0ah +bdos equ 5 + + +codebgn equ $ + +;Jump table for the overlay: do NOT change this +jump_tab: + jp scrnpr ; screen print + jp mrd ; modem read with timeout + jp mchin ; get a character from modem + jp mchout ; send a character to the modem + jp mordy ; test for tx buffer empty + jp mirdy ; test for character received + jp sndbrk ; send break + jp cursadd ; cursor addressing + jp cls ; clear screen + jp invon ; inverse video on + jp invoff ; inverse video off + jp hide ; hide cursor + jp show ; show cursor + jp savecu ; save cursor position + jp rescu ; restore cursor position + jp mint ; service modem interrupt + jp invec ; initialise interrupt vectors + jp dinvec ; de-initialise interrupt vectors + jp mdmerr ; test uart flags for error + jp dtron ; turn DTR on + jp dtroff ; turn DTR OFF + jp init ; initialise uart + jp wait ; wait seconds + jp mswait ; wait milliseconds + jp userin ; user-defined entry routine + jp userout ; user-defined exit routine + jp getvars ; get system variables + jp setport ; set port (0 or 1) + +; Spare jumps for compatibility with future versions + jp spare ; spare for later use + jp spare ; spare for later use + jp spare ; spare for later use + jp spare ; spare for later use + jp spare ; spare for later use + jp spare ; spare for later use + +; +; Main code starts here +; +;Screen print function +scrnpr: + ; <== Insert your own code here + call print + db 'This function not supported.',cr,lf,0 + ; <== End of your own code +spare: + ret + +; User-defined entry routine: leave empty if not needed +; +; Get the cpu speed reported by romwbw hbios and calculate +; the three required loop counter values for timing. +; +; outerva (outv) +; innerval (inv) +; millisv (msv) + +userin: + ld a,-1 ; force re-init + ld (mspeed),a + + push bc + ld bc,0f8f0h ; get clock speed in l + rst 08 +; +; outerval equ (clkspd / 10) + 1 +; + push hl ; save clock speed + ld h,0 + ld c,10 + call div_hl_c ; result in hl + ld a,l + inc a + ld (outv),a +; +; innerval equ (6667 / outerval) * clkspd +; + ld c,a + ld hl,6667 + call div_hl_c ; result in hl +; + ex de,hl + pop hl ; recall clock + ld a,l ; save + push af ; clock speed + + call mult_a_de + ld (inv),hl + +; +; ld de,39 * clkspd +; + pop af ; recall clock speed + ld de,39 + call mult_a_de + ld (msv),hl +; + pop bc + ret + +outv: ds 1 ; outer value +inv: ds 2 ; inner value +msv: ds 2 ; millisec value +; +; maths helpers +; +mult_a_de: ; https://wikiti.brandonw.net/index.php?title=Z80_Routines:Math:Multiplication + ld c, 0 + ld h, c + ld l, h + add a, a ; optimised 1st iteration + jr nc,$+4 + ld h,d + ld l,e + ld b,7 +_loop2: + add hl,hl + rla + jr nc,$+4 + add hl,de + adc a,c + djnz _loop2 ; result in ahl + ret +; +div_hl_c: ; https://wikiti.brandonw.net/index.php?title=Z80_Routines:Math:Division + xor a + ld b,16 +_loop1: + add hl, hl + rla + jr c,$+5 + cp c + jr c,$+4 + sub c + inc l + djnz _loop1 ; result in hl + ret + +; User-defined exit routine: leave empty if not needed +userout: + + ret + + +;Get a character from the modem: return in HL +mchin: + push bc + ; <== Insert your own code here + push de + ld b,00h + ld hl,port + ld c,(hl) + rst 08 + + ld a,e + pop de + ; <== End of your own code + + ld l,a ; put in HL +; ld h,0 +; or a ; set/clear Z + pop bc + ret + +;Send a character to the modem +mchout: + ld hl,2 ; get the character + add hl,sp + ld a,(hl) + ; <== Insert your own code here + ld e,a + ld b,01h + ld hl,port + ld c,(hl) + rst 08 + ; <== End of your own code + ret ; done + +;Test for output ready: return TRUE (1) in HL if ok +mordy: + ; <== Insert your own code here + ld b,03h + ld hl,port + ld c,(hl) + rst 08 + ld h,0 + or a + jr z,modrdy1 + ld a,1 +modrdy1: + ld l,a + ; <== End of your own code + + ld a,l ; set/clear Z + or a + ret + +;Test for character at modem: return TRUE (1) in HL if so +mirdy: + ; <== Insert your own code here + push bc + ld b,02h + ld hl,port + ld c,(hl) + rst 08 + or a + jr z,mirdy1 + ld a,1 +mirdy1: + ld l,a + ld h,0 + pop bc + + ; <== End of your own code +; ld a,l ; set/clear Z +; or a + ret + +;Send a break to the modem: leave empty if your system can't do it +sndbrk: + ; <== Insert your own code here + + ld hl,300 ; wait 300 mS + call waithlms + + ; <== End of your own code + ret +; +;Test UART flags for error: return TRUE (1) in HL if error. +mdmerr: + ; <== Insert your own code here + ld hl,0 + + ; <== End of your own code + ld a,l ; set/clear Z + or a + ret + + + +;Turn DTR ON +dtron: + ; <== Insert your own code here + + ; <== End of your own code + ret + + + +;Turn DTR OFF +dtroff: + ; <== Insert your own code here + + + ; <== End of your own code + ret + + + +;Initialise the uart + +init: + ld hl,2 ; get parameters + add hl,sp + ex de,hl + call getparm ; in HL + ld (brate),hl ; baud rate + call getparm + ld (parity),hl ; parity + call getparm + ld (data),hl ; data bits (BINARY 7 or 8) + call getparm + ld (stop),hl ; stop bits (BINARY 1 or 2) + + + ; <== Insert your own code here + ; using values below + call print + db cr,lf,cr,lf,'Initializing CIO device ...',cr,lf,0 + + ld a,(port) ; get device type + ld c,a + ld b,06h + rst 08 + or a ; check if valid + jr nz,initerr + + ld a,(brate) ; get baud rate to set + ld c,a + ld b,0 + ld hl,baudtbl + add hl,bc + ld a,(hl) ; convert to encoded hbios + cp a,-1 + jr z,initerr + + push af + ld a,(port) ; get line characteristics + ld c,a + ld b,05h + rst 08 + ld a,d ; mask out exisitng + and 11100000b ; replace with rate + ld d,a + pop af + or d + ld d,a + + ld b,04h ; set new + ld a,(port) ; speed + ld c,a + rst 08 + or a + jr nz,initerr + + call print + db 'CIO device initialized: ',0 + ld a,(port) + add a,'0'-1 + call cout + call print + db cr,lf,0 + + ld a,(brate) + ld (mspeed),a ; don't forget to load mspeed with the + ; current brate value if the new rate is + ; valid. See table of values below. + ; <== End of your own code + ret +initerr: + call print + db 'Unable to initialize CIO device: ',0 + ld a,(port) + add a,'0'-1 + call cout + call print + db cr,lf,0 + + ret + +;-------------------------------------------------------------------------- +stop: dw 1 ; stop bits +parity: dw 'N' ; parity +data: dw 8 ; data bits +brate: dw initbr ; baud rate: +;-------------------------------------------------------------------------- +;Values of brate for each baud rate +; +; hb encode baud rate brate +; +baudtbl: + db -1 ; 110 0 not supported + db 2 ; 300 1 + db 17 ; 450 2 + db 3 ; 600 3 + db -1 ; 710 4 not supported + db 4 ; 1200 5 + db 5 ; 2400 6 + db 6 ; 4800 7 + db 7 ; 9600 8 + db 8 ; 19200 9 + db 9 ; 38400 10 + db 24 ; 57600 11 + db 10 ; 76800 12 + +; +; Set the port. ZMP supplies either 0 or 1 as a parameter. You're on your +; own here -- your system is bound to be different from any other! You may +; implement a software switch on all the modem-dependent routines, or perhaps +; you can have one or two centralised routines for accessing the UARTs and +; modify the code from this routine to select one or the other. (Who said +; there was anything wrong with self-modifying code?). If you have only one +; UART port, or if you don't want to go through all the hassles, just have +; this routine returning with no changes made. Note that ZMP calls this +; routine with both values for the port on initialisation. +; +setport: + ld hl,2 ; get port number + add hl,sp + ex de,hl + call getparm ; in HL (values are 0 and 1) + + ; <== Insert your own code here + + inc l ; l = cio 1 or cio 2 + push hl + ld b,06h ; test if a valid cio + ld c,l + rst 08 + pop hl + or a + ld a,l + ld (port),a + jr nz,seterr + push hl + call print + db 'Setting CIO device: ',0 + pop hl + + ld a,l + add a,'0'-1 + call cout + call print + db cr,lf,0 + ret +seterr: + push hl + call print + db 'Unable to set CIO device: ',0 + pop hl + ld a,l + add a,'0'-1 + call cout + call print + db cr,lf,0 + ; <== End of your own code + ret + +port: db initdev ; zmp port 0 = cio 1, zmp port 1 = cio 2 + +;**************************************************************************** +;Video terminal sequences: these are for VT-100: Modify as you wish +;Cursor addressing: +cursadd: + ld hl,2 ; get parameters + add hl,sp + ex de,hl + call getparm ; in HL + inc hl + ld (row),hl ; row + call getparm + inc hl + ld (col),hl ; column + ; <== Insert your own code here + ; using values in row and col + call print + db esc,'[',0 + ld a,(row) ; row first + call cursconv + ld a,';' + call cout + ld a,(col) ; same for column + call cursconv + ld a,'H' + call cout + ; <== end of your own code + ret + +cursconv: + ld b,a + xor a +ca1: + add a,1 + daa + djnz ca1 + ld (num),a + and 0f0h + jr z,ca2 + srl a + srl a + srl a + srl a + or '0' + call cout +ca2: + ld a,(num) + and 0fh + or '0' + call cout + ret + +row: ds 2 ; row +col: ds 2 ; column +num: ds 1 + +;Clear screen: +cls: + call print + db esc,"[H",esc,"[2J",0 + ret + +;Inverse video on: +invon: + call print + db esc,"[7m",0 + ret + +;Inverse video off: +invoff: + call print + db esc,"[m",0 + ret + +;Turn off cursor: +hide: + call print + db esc,'[?25l',0 + ret + +;Turn on cursor: +show: + call print + db esc,'.3',0 + ret + +;Save cursor position: +savecu: + call print + db esc,'[7',0 + ret + +;Restore cursor position: +rescu: + call print + db esc,'[8',0 + ret + +;**************************************************************************** + +;Service modem interrupt: +mint: + ret ; my system doesn't need this + +;Initialise interrupt vectors: +invec: + ret ; ditto + +;De-initialise interrupt vectors: +dinvec: + ret ; ditto +; Display A in hex +prthexbyte: + push af + push de + call hexascii + ld a,d + call cout + ld a,e + call cout + pop de + pop af + ret + +hexascii: + ld d,a + call hexconv + ld e,a + ld a,d + rlca + rlca + rlca + rlca + call hexconv + ld d,a + ret + +hexconv: + and 0fh + add a,90h + daa + adc a,40h + daa + ret + +;****************** End of user-defined code ******************************** +; Do not change anything below here. + +;Modem character test for 100 ms +mrd: + push bc ; save bc + ld bc,100 ; set limit +mrd1: + call mirdy ; char at modem? + jr nz,mrd2 ; yes, exit + ld hl,1 ; else wait 1ms + call waithlms + dec bc ; loop till done + ld a,b + or c + jr nz,mrd1 + ld hl,0 ; none there, result=0 + xor a +mrd2: + pop bc + ret + +; Inline print routine: destroys A and HL + +print: + ex (sp),hl ; get address of string +ploop: + ld a,(hl) ; get next + inc hl ; bump pointer + or a ; done if zero + jr z,pdone + call cout ; else print + jr ploop ; and loop +pdone: + ex (sp),hl ; restore return address + ret ; and quit + +; +;Output a character in A to the console +; +cout: + push bc ; save regs + push de + push hl +; ld e,a ; character to E +; ld c,2 +; call bdos ; print it + ld b,01h + ld c,80h + ld e,a + rst 08 + pop hl + pop de + pop bc + ret + +;Wait(seconds) +wait: + ld hl,2 + add hl,sp + ex de,hl ; get delay size + call getparm + ; fall thru to.. +;Wait seconds in HL +waithls: + push bc ; save bc + push de ; de + push ix ; and ix + ld ix,0 ; then point ix to 0 + ; so we don't upset memory-mapped i/o + +;Calculate values for loop constants. Need to have two loops to avoid +; 16-bit overflow with clock speeds above 9 MHz. + +;outerval equ (clkspd / 10) + 1 +;innerval equ (6667 / outerval) * clkspd + +wait10: + ld a,(outv) ; was ld b,outerval + ld b,a +wait11: + ld de,(inv) ; was ld de,innerval + +wait12: + bit 0,(ix) ; time-wasters + bit 0,(ix) + bit 0,(ix) ; 20 T-states each + bit 0,(ix) + bit 0,(ix) + bit 0,(ix) + dec de + ld a,e + ld a,d + or e + jr nz,wait12 ; 150 T-states per inner loop + djnz wait11 ; decrement outer loop + dec hl ; ok, decrement count in hl + ld a,h + or l + jr nz,wait10 + pop ix ; done -- restore ix + pop de ; de + pop bc ; and bc + ret + +;Wait milliseconds +mswait: + ld hl,2 + add hl,sp + ex de,hl ; get delay size + call getparm + ; fall thru to.. +;Wait milliseconds in HL +waithlms: + push de +w1ms0: + ld de,(msv) ; was ld de,39 * clkspd + +w1ms1: + dec de + ld a,d + or e + jr nz,w1ms1 + dec hl + ld a,h + or l + jr nz,w1ms0 + pop de + ret + +;Get next parameter from (de) into hl +getparm: + ex de,hl ; get address into hl + ld e,(hl) ; get lo + inc hl + ld d,(hl) ; then hi + inc hl ; bump for next + ex de,hl ; result in hl, address still in de + ret + +;Get address of user-defined variables + +getvars: + ld hl,uservars + ret + +uservars: + dw overdrive ; .OVR etc. drive/user + dw overuser + + + if ($ - codebgn) gt ovsize +toobig: jp errval ; Overlay too large! + endif + + end + \ No newline at end of file diff --git a/Source/Apps/ZMODEM/zmp-blnk.z80 b/Source/Apps/ZMODEM/zmp-blnk.z80 new file mode 100644 index 00000000..9cd1ba0b --- /dev/null +++ b/Source/Apps/ZMODEM/zmp-blnk.z80 @@ -0,0 +1,573 @@ +;----------------------------------------------------------------------------- +; +; Sample Overlay for ZMP (Z-Modem Program) +; +; Name ZMO-BLNK.Z80 +; +; Dated Sep 14, 1988 +; +; Written by - +; Ron Murray, c/o Z-Node 62, 061-9-450-0200, Perth, Western Australia. +; +; Modified to ZMP v1.2 standard rjm 15/9/88 +; Modified to ZMP v1.3 standard rjm 11/10/88 +; Modified to ZMP v1.4 standard rjm 20/11/88 +; Modified to ZMP v1.5 standard rjm 25/3/89 +; +; +;----------------------------------------------------------------------------- +; +; +; System-dependent code overlay for ZMODEM +; +; +; +; Insert your own code as necessary in this file. Code contained herein +; has been written in Z80 code for use with M80 or SLR. Assemble as follows: +; +; SLR ZMO-xx01/h +; MLOAD ZMP.COM=ZMODEM.COM,ZMO-xx01.HEX +; or +; M80 =ZMO-xx01.Z80 +; RELHEX ZMO-xx01 +; MLOAD ZMP.COM=ZMODEM.COM,ZMO-xx01.HEX +; +; +; (Don't use L80 without changing the source for assembly as a +; cseg file.) +; +;----------------------------------------------------------------------------- +; +; +; Notes on modifying this file: +; +; C requires that functions do not change either index register (IX or IY). +; If your overlay requires either of these to be changed, ensure they are +; restored to the original values on return. +; Since collecting parameters from C functions can be tricky, only change +; the parts marked 'Insert your own code here'. Do NOT modify the jump +; table at the start. Do NOT modify the entry/exit sections of each +; function. Do NOT pass 'GO'. Do NOT collect $200. +; Apart from defining modem functions, this file also defines terminal +; characteristics. Examples provided are for ADM-3A (with a few of my own +; additions). Modify to suit your own terminal. An inline print routine +; is provided for printing strings in the usual way: usage is +; +; call print +; db 'required string',0 +; +;----------------------------------------------------------------------------- +; +; +; Don't forget to set your clock speed at the clkspd variable. +; +; +; If you find your overlay exceeds the maximum size (currently 0400h), +; you will have to contact me for another version. If too many people need +; to do it, we haven't allowed enough room. +; +; Ron Murray 15/8/88 +; +; +; +;--------------------------------------------------------------------------- + +false equ 0 +true equ not false + +;------------------------------------------------------------------------------ + +; User-set variables: + +clkspd equ 4 ; Processor clock speed in MHz +debug equ false ; to allow debugging of overlay with Z8E etc. + +;Set the following two equates to the drive and user area which will contain +; ZMP's .OVR files, .CFG file, .FON file and .HLP file. Set both to zero +; (null) to locate them on the drive from which ZMP was invoked. + +overdrive equ 'A' ; Drive to find overlay files on ('A'-'P') +overuser equ 0 ; User area to find files + +;------------------------------------------------------------------------------ + + +; NOT user-set variables + +userdef equ 0145h ; origin of this overlay + ; This address should not change with + ; subsequent revisions. +mspeed equ 03ch ; location of current baud rate. +ovsize equ 0400h ; max size of this overlay + + .z80 ; use z80 code + aseg ; absolute + + if debug + org 100h ; so you can debug it with cebug, zsid, etc + else + org userdef + endif + + +esc equ 1bh +ctrlq equ 11h +cr equ 0dh +lf equ 0ah +bdos equ 5 + + +codebgn equ $ + +;Jump table for the overlay: do NOT change this +jump_tab: + jp scrnpr ; screen print + jp mrd ; modem read with timeout + jp mchin ; get a character from modem + jp mchout ; send a character to the modem + jp mordy ; test for tx buffer empty + jp mirdy ; test for character received + jp sndbrk ; send break + jp cursadd ; cursor addressing + jp cls ; clear screen + jp invon ; inverse video on + jp invoff ; inverse video off + jp hide ; hide cursor + jp show ; show cursor + jp savecu ; save cursor position + jp rescu ; restore cursor position + jp mint ; service modem interrupt + jp invec ; initialise interrupt vectors + jp dinvec ; de-initialise interrupt vectors + jp mdmerr ; test uart flags for error + jp dtron ; turn DTR on + jp dtroff ; turn DTR OFF + jp init ; initialise uart + jp wait ; wait seconds + jp mswait ; wait milliseconds + jp userin ; user-defined entry routine + jp userout ; user-defined exit routine + jp getvars ; get system variables + jp setport ; set port (0 or 1) + +; Spare jumps for compatibility with future versions + jp spare ; spare for later use + jp spare ; spare for later use + jp spare ; spare for later use + jp spare ; spare for later use + jp spare ; spare for later use + jp spare ; spare for later use + +; +; Main code starts here +; +;Screen print function +scrnpr: + ; <== Insert your own code here + call print + db 'This function not supported.',cr,lf,0 + ; <== End of your own code +spare: + ret + +; User-defined entry routine: leave empty if not needed +userin: + ret + +; User-defined exit routine: leave empty if not needed +userout: + ret + + +;Get a character from the modem: return in HL +mchin: + push bc + ; <== Insert your own code here + + + ; <== End of your own code + + ld l,a ; put in HL + ld h,0 + or a ; set/clear Z + pop bc + ret + +;Send a character to the modem +mchout: + ld hl,2 ; get the character + add hl,sp + ld a,(hl) + ; <== Insert your own code here + + + ; <== End of your own code + ret ; done + +;Test for output ready: return TRUE (1) in HL if ok +mordy: + ; <== Insert your own code here + + ; <== End of your own code + + ld a,l ; set/clear Z + or a + ret + +;Test for character at modem: return TRUE (1) in HL if so +mirdy: + ; <== Insert your own code here + + + ; <== End of your own code + ld a,l ; set/clear Z + or a + ret + +;Send a break to the modem: leave empty if your system can't do it +sndbrk: + ; <== Insert your own code here + + ld hl,300 ; wait 300 mS + call waithlms + + ; <== End of your own code + ret +; +;Test UART flags for error: return TRUE (1) in HL if error. +mdmerr: + ; <== Insert your own code here + + ; <== End of your own code + ld a,l ; set/clear Z + or a + ret + + + +;Turn DTR ON +dtron: + ; <== Insert your own code here + + ; <== End of your own code + ret + + + +;Turn DTR OFF +dtroff: + ; <== Insert your own code here + + + ; <== End of your own code + ret + + + +;Initialise the uart + +init: + + ld hl,2 ; get parameters + add hl,sp + ex de,hl + call getparm ; in HL + ld (brate),hl ; baud rate + call getparm + ld (parity),hl ; parity + call getparm + ld (data),hl ; data bits (BINARY 7 or 8) + call getparm + ld (stop),hl ; stop bits (BINARY 1 or 2) + + + ; <== Insert your own code here + ; using values below + ld (mspeed),a ; don't forget to load mspeed with the + ; current brate value if the new rate is + ; valid. See table of values below. + ; <== End of your own code + ret +;-------------------------------------------------------------------------- + +stop: dw 1 ; stop bits +parity: dw 'N' ; parity +data: dw 8 ; data bits +brate: dw 7 ; baud rate: + +;-------------------------------------------------------------------------- +;Values of brate for each baud rate +; +; baud rate brate +; +; 110 0 +; 300 1 +; 450 2 +; 600 3 +; 710 4 +; 1200 5 +; 2400 6 +; 4800 7 +; 9600 8 +; 19200 9 +; 38400 10 +; 57600 11 +; 76800 12 + +; +; Set the port. ZMP supplies either 0 or 1 as a parameter. You're on your +; own here -- your system is bound to be different from any other! You may +; implement a software switch on all the modem-dependent routines, or perhaps +; you can have one or two centralised routines for accessing the UARTs and +; modify the code from this routine to select one or the other. (Who said +; there was anything wrong with self-modifying code?). If you have only one +; UART port, or if you don't want to go through all the hassles, just have +; this routine returning with no changes made. Note that ZMP calls this +; routine with both values for the port on initialisation. +; +setport: + ld hl,2 ; get port number + add hl,sp + ex de,hl + call getparm ; in HL (values are 0 and 1) + + ; <== Insert your own code here + + ; <== End of your own code + ret + +port: ds 1 + + +;**************************************************************************** +;Video terminal sequences: these are for ADM-3A: Modify as you wish +;Cursor addressing: +cursadd: + ld hl,2 ; get parameters + add hl,sp + ex de,hl + call getparm ; in HL + ld (row),hl ; row + call getparm + ld (col),hl ; column + ; <== Insert your own code here + ; using values in row and col + call print + db esc,'=',0 ; ADM-3A leadin + ld a,(row) ; row first + add a,' ' ; add offset + call cout + ld a,(col) ; sane for column + add a,' ' + call cout + ; <== end of your own code + ret + +row: ds 2 ; row +col: ds 2 ; column + + +;Clear screen: +cls: + call print + db 1ah,0 + ret + +;Inverse video on: +invon: + call print + db esc,'G4',0 + ret + +;Inverse video off: +invoff: + call print + db esc,'G0',0 + ret + +;Turn off cursor: +hide: + call print + db esc,'.1',0 + ret + +;Turn on cursor: +show: + call print + db esc,'.3',0 + ret + +;Save cursor position: +savecu: + ret + +;Restore cursor position: +rescu: + ret + +;**************************************************************************** + +;Service modem interrupt: +mint: + ret ; my system doesn't need this + +;Initialise interrupt vectors: +invec: + ret ; ditto + +;De-initialise interrupt vectors: +dinvec: + ret ; ditto + +;****************** End of user-defined code ******************************** +; Do not change anything below here. + +;Modem character test for 100 ms +mrd: + push bc ; save bc + ld bc,100 ; set limit +mrd1: + call mirdy ; char at modem? + jr nz,mrd2 ; yes, exit + ld hl,1 ; else wait 1ms + call waithlms + dec bc ; loop till done + ld a,b + or c + jr nz,mrd1 + ld hl,0 ; none there, result=0 + xor a +mrd2: + pop bc + ret + +; Inline print routine: destroys A and HL + +print: + ex (sp),hl ; get address of string +ploop: + ld a,(hl) ; get next + inc hl ; bump pointer + or a ; done if zero + jr z,pdone + call cout ; else print + jr ploop ; and loop +pdone: + ex (sp),hl ; restore return address + ret ; and quit + +; +;Output a character in A to the console +; +cout: + push bc ; save regs + push de + push hl + ld e,a ; character to E + ld c,2 + call bdos ; print it + pop hl + pop de + pop bc + ret + +;Wait(seconds) +wait: + ld hl,2 + add hl,sp + ex de,hl ; get delay size + call getparm + ; fall thru to.. +;Wait seconds in HL +waithls: + push bc ; save bc + push de ; de + push ix ; and ix + ld ix,0 ; then point ix to 0 + ; so we don't upset memory-mapped i/o + +;Calculate values for loop constants. Need to have two loops to avoid +; 16-bit overflow with clock speeds above 9 MHz. + +outerval equ (clkspd / 10) + 1 +innerval equ (6667 / outerval) * clkspd + +wait10: + ld b,outerval + +wait11: + ld de,innerval + +wait12: + bit 0,(ix) ; time-wasters + bit 0,(ix) + bit 0,(ix) ; 20 T-states each + bit 0,(ix) + bit 0,(ix) + bit 0,(ix) + dec de + ld a,e + ld a,d + or e + jr nz,wait12 ; 150 T-states per inner loop + djnz wait11 ; decrement outer loop + dec hl ; ok, decrement count in hl + ld a,h + or l + jr nz,wait10 + pop ix ; done -- restore ix + pop de ; de + pop bc ; and bc + ret + +;Wait milliseconds +mswait: + ld hl,2 + add hl,sp + ex de,hl ; get delay size + call getparm + ; fall thru to.. +;Wait milliseconds in HL +waithlms: + push de +w1ms0: + ld de,39 * clkspd +w1ms1: + dec de + ld a,d + or e + jr nz,w1ms1 + dec hl + ld a,h + or l + jr nz,w1ms0 + pop de + ret + +;Get next parameter from (de) into hl +getparm: + ex de,hl ; get address into hl + ld e,(hl) ; get lo + inc hl + ld d,(hl) ; then hi + inc hl ; bump for next + ex de,hl ; result in hl, address still in de + ret + +;Get address of user-defined variables + +getvars: + ld hl,uservars + ret + +uservars: + dw overdrive ; .OVR etc. drive/user + dw overuser + + + if ($ - codebgn) gt ovsize +toobig: jp errval ; Overlay too large! + endif + + end + \ No newline at end of file diff --git a/Source/Apps/ZMODEM/zmp-ovl.upd b/Source/Apps/ZMODEM/zmp-ovl.upd new file mode 100644 index 00000000..b2da16ec --- /dev/null +++ b/Source/Apps/ZMODEM/zmp-ovl.upd @@ -0,0 +1,256 @@ + ZMP Overlay Update Information + + This file contains information on updating ZMP overlays designed for +previous versions to the current version. Newer versions appear first in +this file. + +Updates to ZMP14 Overlays for use with ZMP15. +--------------------------------------------- + + The changes required here are associated with ZMP15's ability to access +either of two UART ports, if available on the specific machine. One entry +needs to be added to the jump table, and an extra routine needs to be added +to set which port is in use. Lines which must be added to the overlay have +an asterisk at the beginning. + +1. Add an entry to the jump table. + + Add the following instruction at the end of the jump table, after the +'jp getvars' instruction and before the spare jumps: + +* jp setport ; Set the modem port being used + +2. Add the setport routine. + + The following routine should be added into the code. A good place is +immediately following the UART init code. + +*; +*; Set the port. ZMP supplies either 0 or 1 as a parameter. You're on your +*; own here -- your system is bound to be different from any other! You may +*; implement a software switch on all the modem-dependent routines, or perhaps +*; you can have one or two centralised routines for accessing the UARTs and +*; modify the code from this routine to select one or the other. (Who said +*; there was anything wrong with self-modifying code?). If you have only one +*; UART port, or if you don't want to go through all the hassles, just have +*; this routine returning with no changes made. Note that ZMP calls this +*; routine twice -- once for each port value -- on initialisation. +*; +*setport: +* ld hl,2 ; get port number +* add hl,sp +* ex de,hl +* call getparm ; in HL (values are 0 and 1) +* +* ; <== Insert your own code here +* +* ; <== End of your own code +* ret +* +*port: ds 1 +* + +End of changes ZMP14 --> ZMP15. + + -- Ron Murray + 25/3/89 + +=============================================================================== + +Updates to ZMP13 Overlays for use with ZMP14. +--------------------------------------------- + + Some changes need to be made to accommodate the user-specification +of drive/user area for the .OVR files. Changes need to be made in three +places in your overlay (asterisks at the start of lines indicate which lines +should be added): + +1. Specify the required drive/user area. + + Add the following section after the mspeed equate: + +*;Set the following two equates to the drive and user area which will contain +*; ZMP's .OVR files, .CFG file, .FON file and .HLP file. Set both to zero +*; (null) to locate them on the drive from which ZMP was invoked. +* +*overdrive equ 'A' ; Drive to find overlay files on ('A'-'P') +*overuser equ 0 ; User area to find files + +2. Add to the jump table + + Add the following instruction at the end of the jump table, after the +'jp userout' instruction and before the spare jumps: + +* jp getvars ; get system variables + + +3. Add code at the end to get the system variables: + + Add the following code just in front of the overlay size test: + +*;Get address of user-defined variables +* +*getvars: +* ld hl,uservars +* ret +* +*uservars: +* dw overdrive ; .OVR etc. drive/user +* dw overuser +* + +End of ZMP14 overlay modifications. + + -- Ron Murray, 20/11/88 + +=============================================================================== + +Updates to ZMP12 Overlays for use with ZMP13. +--------------------------------------------- + + There have been very few changes made to the overlay structure in ZMP13. +Some shuffling of module orders has allowed the origin to be set at 0145 hex, +and here it should stay (unless I fiddle with the startup code -- MOST +unlikely!). So, set your 'userdef' equate to 0145h and you should be able to +leave it there. + There is also a bug fix which should be installed in all overlays. + +1. Fix a bug in the wait routines + + Two routines in the user overlays are misnamed. You would expect wait1s +to pause for one second, and wait1ms to pause for one millisecond, wouldn't +you? Well they don't. Blame it on a lack of sleep on my part. They actually +pause for a number of seconds (milliseconds) in hl. I suggest renaming them +to waithls amd waithlms. The main consequence of this has been the pause in +the middle of the 'send break' routine: there was originally a ld hl, 1 before +the call to wait1s, but it got lost somewhere along the way. In any case, one +second is probably too long for this, and I suggest you change it to + + ld hl, 300 ; wait 300 mS + call waithlms + + There are two faults in the waithls (formerly wait1s) routine. The first +is a misplaced jr instruction that caused waits of more than 1 second to be +much longer than intended. The other concerns z80 machines with a clock speed +greater than 9 MHz: these will cause 16-bit overflow in the ld de,6667 +instruction. (It had never occurred to me that anyone would have a z80 running +at this speed!). Both these faults can be solved by replacing the whole +waithls routine with the following: + +;Wait seconds in HL +waithls: + push bc ; save bc + push de ; de + push ix ; and ix + ld ix,0 ; then point ix to 0 + ; so we don't upset memory-mapped i/o + +;Calculate values for loop constants. Need to have two loops to avoid +; 16-bit overflow with clock speeds above 9 MHz. + +outerval equ (clkspd / 10) + 1 +innerval equ (6667 / outerval) * clkspd + +wait10: + ld b,outerval + +wait11: + ld de,innerval + +wait12: + bit 0,(ix) ; time-wasters + bit 0,(ix) + bit 0,(ix) ; 20 T-states each + bit 0,(ix) + bit 0,(ix) + bit 0,(ix) + dec de + ld a,e + ld a,d + or e + jr nz,wait12 ; 150 T-states per inner loop + djnz wait11 ; decrement outer loop + dec hl ; ok, decrement count in hl + ld a,h + or l + jr nz,wait10 + pop ix ; done -- restore ix + pop de ; de + pop bc ; and bc + ret + +; End of changes to waithls routine + + The remaining changes concern baud rates. Firstly, ZMP13 will reject a +selected baud rate if the machine is not capable of it. It does this by +determining if the value in mspeed (location 3c hex) has changed. Thus if +you modify your overlay to only change 003ch (mspeed) if the new baud rate +is valid, then incorrect baud rates cannot be selected. No code is given for +this as all overlays are different. Note that the only penalty for not making +this change is that all baud rates are accepted, whether valid or not. Older +overlays always set mspeed to the new value. + In response to numerous requests (well, actually, two), ZMP13 will accept +speeds of 38400, 57600 and 76800 baud. This means that it accepts the numbers +for these -- mspeed values are 10, 11 and 12 respectively. If you think that +you can get your machine to actually work at these speeds, then go ahead. But +don't blame me if it doesn't work. (Personally, I doubt if successful +transfers in both directions with a 4 MHz machine can be done at much over +4800 baud. But don't let me stop you.) + + -- Ron Murray + 11/10/88 + + +End of changes ZMP12 --> ZMP13 +=============================================================================== + +Updates to ZMP11 Overlays for ZMP12. +------------------------------------ + + Some additions to the jump table have been made to allow for user-defined +routines to be executed on entry/exit from ZMP. Modify your overlay as +follows: + +1. Adding to the jump table + + Add the following code to the end of the jump table after the line: + + jp mswait ; wait milliseconds (Last entry of old table) + +==> Insert this stuff + jp userin ; user-defined entry routine + jp userout ; user-defined exit routine + +;Spare jumps for compatibility with future versions + jp spare ; spares for later use + jp spare ; spares for later use + jp spare ; spares for later use + jp spare ; spares for later use + jp spare ; spares for later use +==> End of inserted jump codes + +2. Adding the 'spare' code + + The following code can be added anywhere. A good idea is to put the +'spare:' label in front of an existing ret instruction. + +spare: + ret + +3. Adding the user routines + + Add the following code to your overlay. Anywhere will do. The code +you put in here depends on what you want to do. + +;User-defined entry routine: leave empty if not used +userin: + ret + +;User-defined exit routine: leave empty if not used +userout: + ret + +End of changes ZMP11 --> ZMP12 +=============================================================================== + + \ No newline at end of file diff --git a/Source/Apps/ZMODEM/zmp.cfg b/Source/Apps/ZMODEM/zmp.cfg new file mode 100644 index 00000000..1f2b0ffb --- /dev/null +++ b/Source/Apps/ZMODEM/zmp.cfg @@ -0,0 +1,24 @@ +1 1 0 0 0 360 + + + + + + + + + + +AT! +ATV1Q0DT +! +CONNECT +BUSY +NO CARRIER +NO ANSWER +ERROR +~+++~~ATH! +15 30 +5 N 8 1 +1400 512 F 5 50 + diff --git a/Source/Apps/ZMODEM/zmp.doc b/Source/Apps/ZMODEM/zmp.doc new file mode 100644 index 00000000..aeb5383e --- /dev/null +++ b/Source/Apps/ZMODEM/zmp.doc @@ -0,0 +1,389 @@ + ** ZMP Documentation ** + +1. Introduction. + + ZMP is a communications/file transfer program for CP/M which +performs Xmodem, Xmodem-1k (often erroneously called Ymodem), +true Ymodem and Zmodem file transfer protocols. Although tested +with Z80DOS, ZRDOS and CP/M 2.2, there seems to be no reason why +it shouldn't work with CP/M 3 as well. The only requirements are +a Z80 processor (sorry about that!), a computer running CP/M in +one of its various guises, with at least 45k of TPA (but the more +the better!), and a modem. + When you try to pack this many features into one program, +you end up with a pretty large file. The big problem occurs when +file transfers are attempted: unless you have at least 4-8k of +buffer size, you might as well use xmodem protocol. The approach +taken in ZMP is to use overlays for various functions, accepting +the time taken to load these from disk. Thus performance will +vary depending on your disk setup: if you have a hard disk and a +fast processor you will likely not notice the difference. If, on +the other hand, you are running a Commodore 128 with CP/M on a +1571 drive, there is no physical reason why ZMP won't work, but +you might consider investing in a book to read while the overlays +load. (A suitable book to read might be a computer catalogue!). + The curious amongst you may notice that the beginning of the +ZMPX.COM file has the magic 'Z3ENV' string, but don't let this +fool you into thinking that you don't need to add terminal +characteristics into the overlay if you have a ZCPR3 system. It +has proved possible to persuade this particular C compiler to +access ZCPR3's environment descriptor, but not for ZMP. Yet. +Perhaps later. In the meantime, the startup code is there for it. + In order to produce a program which would work with most +CP/M systems, the Zmodem protocol performed by ZMP is fairly +simple. The transmit section uses 'Full Streaming with Reverse +Interrupt', as Chuck Forsberg calls it in his description of the +Zmodem protocol. The receive section uses 'Segmented Streaming'. +This means that, if your system can do serial I/O and disk I/O at +the same time, ZMP does not take advantage of the faster transfer +rate which this capability provides. Since, however, I can't +write and listen at the same time, and neither can my computer, +and neither can the vast majority of CP/M computers, it seemed +the best approach to take. Segmented Streaming means that the +receive program tells the transmit program how big its buffer is. +The transmit program then sends just that much data, then waits +for an acknowledge from the receiver. We have encountered some +Zmodem programs which send too much data in this case: errors +will appear if this happens, but the protocol should recover and +the file will be received intact (we hope!). + The string which ZMP passes to the receiving program to +interrupt in case of errors is likewise simple. Basically it +causes the receiving program to send a control-C character and +then wait for one second. The receiver will then send its ZRPOS +string, by which time ZMP, as the transmitter, should be ready to +receive it. + + +2. Customisation. + + ZMP must be customised to suit your system. This involves +overlaying the un-installed copy of ZMP.COM (contained in this +library as ZMPX.COM) with a user-written installation overlay. +Some hints on writing this are given below; there is a blank +overlay file in this library, or you may be able to obtain one +for your computer from the same place you got this library. +This value is set at 0145 hex, and should stay there permanently. +See the notes in this document, and also the ZMP-OVL.UPD file, +for more details on how to set up your overlay. + Once the installation overlay is written, assemble it with +M80 (or SLR or whatever), use RELHEX to create a .HEX file, and +use MLOAD to overlay it over the ZMPX.COM file to produce your +very own ZMP.COM. + +3. Operation. + + The following files must be on the same disk and user area, +which must be specified in your customisation overlay: + + ZMCONFIG.OVR -- the configuration overlay + ZMINIT.OVR -- the initialisation overlay + ZMTERM.OVR -- the terminal overlay + ZMXFER.OVR -- the file transfer overlay + ZMP.HLP -- the help file (recommended). + + Start the program with ZMP. The screen should clear, then a +title message is printed, then ZMP enters terminal mode. You may +type escape-H for help at this point. When you first run the +program, the first thing you need to do is to enter the +configuration overlay (type escape-C) and set all the defaults +and others to suit your system as required. If you don't know +whether to change something or not, it's probably better to leave +it alone. When you exit the configuration program, answer 'Y' to +the 'Make changes permanent' question. ZMP.FON and ZMP.CFG will +be produced on your disk, in the same drive/user area as the +above files. + + Operation of the program is controlled by escape sequences +entered in terminal mode. Escape-H gives you a list of options. +Most of these are self-explanatory, but they will be summarized +here. + +B - Send Break to modem. + If your overlay has been set up to send a break command + to your UART, this command will perform this function. (Some + remote systems may require a break sent to them to interrupt + Zmodem transfers). + +C - Configure system. + This function is designed to set system defaults, save + phone numbers etc. Changing baud rates etc. for a particular + call are better handled with the escape-L option. If you + answer Y or y to the 'make changes permanent?' question, the + new configuration will be saved in a ZMP.CFG file, and the + phone numbers in a ZMP.FON file for later use. The .CFG file + is read, if it exists, when ZMP is first started. + +D - Get disk Directory. + Gets a directory of the current drive and user area. + Change to another with the escape-F command, described + below. The directory will be sorted and will include + filesizes unless you have so many files on the current + drive/user area that there is insufficient memory available + to sort them. In this case an unsorted directory, without + file sizes, will be printed. + +F - Disk/File operations. + This command is used to change the current drive/user + area, to reset a disk in the current drive, and to view, + erase, print or rename files. There are also options to give + a directory of the current drive/user area, and to supply a + new filename for the capture file. This filename may specify + a different drive/user area than the current one. If capture + mode is on, the status line printed when terminal mode is + entered will state the capture file name. + +H - Get Help. + Prints the ZMP.HLP file. You may then either type CR to + return to terminal mode, or enter the required function key. + +I - Initiate phone call. + Reads the ZMP.FON file, if any, and prints it. You have + four seconds after typing ESC I, during which you may enter + the letter corresponding to the required number, in which + case ZMP will dial it without printing a list. Otherwise the + full phone list will be printed, and you will be asked which + number you want. Enter the identifying letter of the number + you wish to call. You can also enter numbers not in the + list. Multiple numbers can be called by entering them separ- + ated with commas. Dialling will then commence, and will + continue until one of the numbers answers, or until you + abort the process with the escape key. Note that the baud + rate used for the call is that in the .FON file for that + number, or the current one if a new number is entered. This + function works best if the strings in the .CFG file have + been set up for your modem, and the initialisation string + sent to the modem sets it into verbose mode for status + messages (ATV1). + +K - Display Keyboard macros. + The configuration option allows up to ten macro keys to + be defined, and these are recalled by typing escape followed + by the numbers 0 to 9. This function prints the current + assignments. + +L - Change Line settings. + This function allows temporary changes of baud rate, + stop bits, and data bits. There is also an option to operate + terminal mode in full duplex (locally typed characters are + sent but not displayed on the screen), half duplex (locally + typed characters are sent and also displayed on the screen), + or echo mode (as for half duplex, but received characters + are echoed to the remote system as well as being displayed). + Don't have two computers talking to each other in echo mode + unless you're bored. There are also options to allow/dis- + allow control characters above CR to be displayed in term- + inal mode, to strip the parity bit in terminal mode, and to + re-initialise the currently selected UART and modem at the + current baud rate. + Like IMP, ZMP uses location 003C hex to store a value + corresponding to the present baud rate. Then, if you leave + ZMP and later re-enter, it checks location 003C. If it + contains a legal value, then that baud rate is set for you, + otherwise it sets the default baud rate as selected in the + .CFG file. + +M - Toggle capture mode in Memory. + Received characters will be saved in a buffer and saved + in a file named 'ZMP.LOG' when the buffer fills or when the + command is entered again. A control-S/control-Q sequence is + sent to the remote computer while the buffer is being saved + in an attempt to stop it sending more data. + +P - Toggle Printer. + This is similar to the 'M' command, except incoming + characters are sent to the printer. This functions best if + your system performs the BIOS 'List Status' function + correctly. + +Q - Quit the program. + Obvious. You will be asked if this is really what you + want. Any entry other than N or n will exit to CP/M. + +R - Receive a file. + You will be asked which protocol you wish to use. The + default is ZMODEM. The modem option will allow either + 128-byte blocks (standard XMODEM) or 1k blocks (XMODEM-1k), + since this is decided by the transmit end. If an attempt is + made to receive a file which has the same name as a file on + the current drive/user area, the current one will be renamed + to .BAK and the new one will then be received normally. + (However, see below for the transfer resumption feature in + ZMP v1.5 and above). + Note that the byte count on the screen is not kept up- + to-date on Zmodem receive. This is because the data arrives + non-stop and there is simply no time available with non- + interrupt driven computers to update the screen. An update + is performed if errors occur, and when the computer pauses + to write to the disk. + Starting with version 1.4, Zmodem file receive will + commence automatically upon receipt of the sender's ZRQINIT + string. Thus all you need to do is have the sender initiate + the transfer, select the drive and user area you wish + the file(s) to be received on, and wait.. + ZMP v1.5 adds the ability to resume an interrupted + Zmodem transfer. If a Zmodem receive attempt fails (either + because of manual cancellation or massive errors), you will + be asked if you wish to save the portion of the file already + received. If not, it will be erased. If so, and a subsequent + Zmodem receive attempt would result in a file of the same + name, you are asked if you wish to resume the transfer. If + you do, transfer will start at the end of the file. + Otherwise the old file will be renamed to .BAK as before. + Since this feature is a function of the receiver, it should + work with any Zmodem implementation which conforms + reasonably closely to Chuck Forsberg's standard. It has been + tested with ZMP and RZMP, and I would like to hear of any + programs with which it doesn't work. No attempt is made to + determine if the files are the same up to the commencement + point: the Zmodem protocol provides two ways in which this + may be determined (file date and CRC), but neither has yet + been implemented in ZMP. + +S - Send a file. + Operation is similar to the receive function. + Additional options available are ASCII send and the + capability of distinguishing between normal Xmodem and + Xmodem-1k. In Ymodem and Zmodem modes, wildcard filenames + and multiple filenames are allowed. Multiple filenames + should be entered separated by spaces. In all cases, files + on different drives/user areas may be specified by supplying + a zcpr3-style du: prefix (e.g. C7:NEATPROG.WOW). + Byte count information is displayed in Zmodem mode on + transmit. This causes noticeable breaks between packets, but + it is felt that this is outweighed by the usefulness of the + information. ZMP's Zmodem mode is capable of CRC-32 opera- + tion, although CRC-16 mode is used if the receiver is incap- + able of CRC-32. Some other terminal programs, however, do + strange things when faced with a receiving program which + claims it can do CRC-32 (we have encountered one for the + Amiga which exhibits this problem). If this happens, the + esc-L menu and the configuration overlay have an option to + disable CRC-32. + +X - Hangup. + This function causes the modem to disconnect from the + phone line, by momentarily dropping DTR. + +Y - Print screen. + Allows the current screen to be dumped to printer. Note + that this must be supported in the overlay: most terminals + are incapable of this function. The standard overlay prints + 'This function not supported.'. If you can make it work on + your system, good luck! + +Z - Clear screen. + Allows the screen to be cleared. Useful if it fills + with rubbish. + + +4. Other information. + +a) ZMP at higher baud rates. + When I first produced ZMP, I was more interested in + producing a universal Zmodem program than anything else. + Originally (several C compilers ago!) I had difficulty get- + ting it to work even at 300 baud, and so little thought was + given to accommodate higher transmission speeds. In partic- + ular, there is a "designed-in" bug/feature which would prob- + ably preclude ZMP working at much over 4800 baud. The prob- + lem is in the user overlay, in the mrd: routine. The requ- + irement here is to have a routine which returns either when + a character is available at the modem (in which case we + return TRUE), or 100 mS has elapsed (in which case we return + FALSE). The catch is that I used 100 x 1 mS waits, between + which we test for a character. A little calculation will + show that a 9600 baud character will take a little over 1 mS + to transfer, and 19200 baud characters take half this time. + Thus we are practically guaranteed to miss characters at + 19200 baud, and even 9600 baud characters leave little + processing timeto spare. Two possible ways to overcome this + are: + + i) Make the wait time shorter. Thus we could wait 1000 x + 100 uS periods instead. This, however, makes the actual + wait time more unpredictable, since subroutine + call/return times are comparable to the wait time. It + also just puts off the evil day. + + ii) Use a hardware timer to determine whether 100 mS has + elapsed. This is the preferred approach. Thus the mrd: + routine would loop continuously, exiting when either + there was a character at the modem or when the hardware + timer expired. An embryo CP/M-68K version of ZMP using + this approach has proved capable of reliable transfers + at 19,200 baud (although one must admit that it IS + running a 68010 at 10 MHz!). + + I would like to hear from anyone who has had any + success with either of these two approaches. + +5. Acknowledgements. + + ZMP was developed from Hal Maney's Heath-specific HMODEM II. +I would like to thank Hal for writing HMODEM: CP/M users have +been without ZMODEM capability for far too long. As requested in +the source file, acknowledgement is given to him therein. +Appreciations also go to the authors of the Hi-Tech C compiler, +which proved to be capable of producing fast and compact code for +Z80 machines. + ZMP in its various incarnations is refined by suggestions +from you, the user. In particular, I would like to thank Mike +Allen, Richard Kopplin and Fred Haines for their invaluable +suggestions. I may sometimes be a little slow at implementation, +but I usually get there eventually! Fred Haines has also kindly +offered to be the U.S. collection point for bug reports, +suggestions etc. His address appears at the bottom of this +document, and he'll forward them to me via what he calls 'U.S. +Snail'. I will try and respond using what I call 'Australia +Pest'. + I would also like to thank Lindsay Allen, sysop of Z-Node +62. His name was removed from the original zmp11 title screen at +his own request, since I had done most of the work in modifying +Hmodem to work on other machines. Without Lindsay's encouragement +at difficult times, suggestions as to how to go about +recalcitrant procedures, and experience in file transfers, ZMP +would not have been produced. Thank you. + + +6. Finally... + The files contained in this library are placed in the public +domain. Just don't sell it, claim you wrote it, or do anything +similar that might annoy me. Above all, don't bother trying to +sue me if it doesn't work, or you tripped over the disk, or +anything similar. I haven't distributed the source files partly +due to the size of them, partly due to the fact that compilation +is messy (several modifications were needed to "standard" library +functions!), and partly due to the fact that there's still work +to do on them. Besides, I feel a certain fatherly feeling towards +ZMP, having spent most of my spare time for the last four months +working on it. So here's the deal: I will continue to support ZMP +(and RZMP) until I get sick of it. This could take an unknown +amount of time! At that point, I will release the sources into +the RCP/M community, and you may make of them what you will. + ZMP has a remote system relative, called RZMP. This allows +Zmodem transfers to and from remote systems. It should be +available from the same place from which you obtained ZMP. + I have also produced an extremely cut-down version of ZMP +which runs under CP/M-68K, currently running quite well as a +single .68K file (no overlays!) on a system with 128k bytes of +memory. If there is enough interest from CP/M-68k users (are +there any??), I could be persuaded to upgrade this version to the +point where it could be released. + Comments and suggestions are welcome. Bug reports are not so +welcome, but we'd like them anyway! Send either to: + + Z-Node 62 + Perth, Western Australia + (061+) 09-450-0200 + (Soon to be on FidoNet) + + U.S. users may send reports/comments to: + + Fred Haines, + 733 North King's Road, Apt. 356 + Los Angeles, California 90069 + + -- Ron Murray + 26th March, 1989 +te systems. It should be +available from the same place fr diff --git a/Source/Apps/ZMODEM/zmp.fon b/Source/Apps/ZMODEM/zmp.fon new file mode 100644 index 00000000..3266618f --- /dev/null +++ b/Source/Apps/ZMODEM/zmp.fon @@ -0,0 +1,21 @@ +Virtual Altair altair 8 N 8 1 0 +_________________ _________________ 9 N 8 1 0 +_________________ _________________ 9 N 8 1 0 +_________________ _________________ 9 N 8 1 0 +_________________ _________________ 9 N 8 1 0 +_________________ _________________ 9 N 8 1 0 +_________________ _________________ 9 N 8 1 0 +heatwave heatwave 8 N 8 1 0 +_________________ _________________ 9 N 8 1 0 +_________________ _________________ 9 N 8 1 0 +_________________ _________________ 9 N 8 1 0 +Level 29 bbs.fozztexx.com 8 N 8 1 0 +_________________ _________________ 9 N 8 1 0 +_________________ _________________ 9 N 8 1 0 +_________________ _________________ 9 N 8 1 0 +Particles BBS particles 8 N 8 1 0 +_________________ _________________ 9 N 8 1 0 +_________________ _________________ 9 N 8 1 0 +_________________ _________________ 9 N 8 1 0 +_________________ _________________ 9 N 8 1 0 + diff --git a/Source/Apps/ZMODEM/zmp.for b/Source/Apps/ZMODEM/zmp.for new file mode 100644 index 00000000..18f92615 --- /dev/null +++ b/Source/Apps/ZMODEM/zmp.for @@ -0,0 +1,13 @@ + ZMP is a communications/file transfer program for CP/M which +performs Xmodem, Xmodem-1k (often erroneously called Ymodem), +true Ymodem and Zmodem file transfer protocols. + + This library contains an un-installed ZMP.COM (called +ZMPX.COM) and five .OVR files. There is also a file called +ZMP-OVL.UPD which describes the changes which need to be made to +the user-written overlay to allow it to operate with this version +of ZMP. YOU need to read this one!! + + Details of changes made to this version are in the ZMPxx.NEW +file. + \ No newline at end of file diff --git a/Source/Apps/ZMODEM/zmp.hlp b/Source/Apps/ZMODEM/zmp.hlp new file mode 100644 index 00000000..641ab610 --- /dev/null +++ b/Source/Apps/ZMODEM/zmp.hlp @@ -0,0 +1,20 @@ +Commands: Precede with ESC: + +B Send break to modem +C Configure system +D Get disk directory +F File operations, change/reset disk +H Get instructions +I Initiate phone call (dial) +K Display keyboard macros +L Change line parameters (baud rate, full/half duplex/echo, UART settings) +M Toggle memory capture mode +P Toggle printer +Q Quit +R Receive a file +S Send a file +X Hangup +Y Print screen +Z Clear local screen + + \ No newline at end of file diff --git a/Source/Apps/ZMODEM/zmp15+-.new b/Source/Apps/ZMODEM/zmp15+-.new new file mode 100644 index 00000000..0e027d6b --- /dev/null +++ b/Source/Apps/ZMODEM/zmp15+-.new @@ -0,0 +1,29 @@ + Version 1.5+/- of ZMP now compiles and links with v3.09 of +Hi Tech C and fixes a few things that had niggled at me for +awhile (some, a few decades): + +* Datestamps transferred in Y/Zmodem transfers. +* Fixed long filename conversions on Y/Zmodem transfers. +* Fixed issues displaying baud rate and send times when the + baud rate is > 19.2K. +* Removed superfluous CR sent to the remote end when a + connection was established, which was a pita when connecting to + a Linux box. +* In keyboard macros, ! translates to a CR now, not CR/LF. +* \ escapes ! and ~ so those literal characters can be used in + keyboard macros. +* Long distance access code has been removed. +* Quick dialing letters limited to A-T. + + This version, based on the version of the source code in +ZMP-SRC.LBR, is missing a few things that made it into the later +version in ZMP15.LBR. So, to quote the original author, + +"As always, ensure that you erase your .CFG file and make a +new one with the config option. There have again been changes to +the format of this file." + +June 7, 2021 + +This ROMWBW version is an extract of https://github.com/mecparts/zmp/bin +as at Aug 23rd, 2021. diff --git a/Source/Apps/ZMODEM/zmterm.ovr b/Source/Apps/ZMODEM/zmterm.ovr new file mode 100644 index 00000000..ef5b3324 Binary files /dev/null and b/Source/Apps/ZMODEM/zmterm.ovr differ diff --git a/Source/Apps/ZMODEM/zmxfer.ovr b/Source/Apps/ZMODEM/zmxfer.ovr new file mode 100644 index 00000000..ff488465 Binary files /dev/null and b/Source/Apps/ZMODEM/zmxfer.ovr differ diff --git a/Source/HBIOS/uf.asm b/Source/HBIOS/uf.asm index b67c15ab..c0f04c63 100644 --- a/Source/HBIOS/uf.asm +++ b/Source/HBIOS/uf.asm @@ -90,13 +90,13 @@ UF_OUT: XOR A ; SIGNAL SUCCESS RET ; -; INPUT STATUS - CAN WE SEND A CHARACTER +; INPUT STATUS - CAN WE RECEIVE A CHARACTER ; UF_IST: IN A,(FIFO_STATUS) ; IS THE QUEUE EMPTY? - RLCA - CPL - AND 00000001B + RLCA ; SET BIT 1 : 0 = DATA AVAIL. 1 = NO DATA AVAIL + CPL ; INVERT BIT 1 : 1 = DATA AVAIL. 0 = NO DATA AVAIL + AND 00000001B ; SET BYTE PENDING, 0 OR 1 AND STATUS RET ; ; OUTPUT STATUS - CAN WE OUTPUT A CHARACTER @@ -137,6 +137,7 @@ UF_FLUSH: UFBUFEMPTY: LD (IY+0),E ; SAVE LOW WORD LD (IY+1),D ; SAVE HI WORD + XOR A RET ; NZ STATUS HERE INDICATES FAIL. ; ; USB-FIFO WILL APPEAR AS A SERIAL DEVICE AT DEFAULT SERIAL MODE