;AMSTRAD OVERLAY FOR ZMP13 ; System-dependent code overlay for ZMODEM ; false equ 0 true equ not false ; User-set variables: *********** clkspd equ 4 ; Processor clock speed in MHz debug equ false userdef equ 0145h ; origin of this overlay ; This address may change with subsequent ; revisions. PORT EQU 0FADCH ;amstrads serial output port MDCTL1 EQU PORT+1 ;modem control port MDDATP EQU PORT ;modem data port MDMRCV EQU 01H ;your bit to test for receive MDMSND EQU 04H ;your bit to test for send MDTXE EQU 04H ;your value when send ready CTCTX EQU 0FBDCH ;8253 counter 0 (ch a tx.) CTCRX EQU CTCTX+1 ;8253 counter 1 (ch a rx.) CTCMODE EQU CTCTX+3 ;8253 write mode word ; NOT user-set variables mspeed equ 05ch ; location of current baud rate. ovsize equ 0400h ; max size of this overlay org userdef 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 ; 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 LD BC,MDDATP IN A,(C) 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) PUSH BC LD BC,MDDATP OUT (C),A POP BC ret ; done ;Test for output ready: return TRUE (1) in HL if ok mordy: call mstat ;modem status and MDMSND 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 call mstat and MDMRCV ; <== End of your own code ld a,l ; set/clear Z or a ret ;get status of uart mstat: PUSH BC LD A,10H ;reset interupts LD BC,MDCTL1 OUT (C),A IN A,(C) POP BC RET ; sndbrk: call dtroff LD A,5 LD BC,MDCTL1 OUT (C),A LD A,0F8H ;send a break tone ld hl,300 ; wait 300 mS call waithlms call dtron ; <== 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: push bc ld bc,MDCTL1 push af ;save all registers used ld a,5 ;say register 5 out (c),a ;select write register 5 ld a,(wrreg5) ;a copy of write reg 5 set 7,a ;set DTR bit ld (wrreg5),a ;update copy out (C),a ;to modem control port pop af ;restore registers pop bc ret ;Turn DTR OFF dtroff: push bc ld bc,MDCTL1 push af ;save all registers used ld a,5 out (c),a ;select write register 5 ld a,(wrreg5) ;old contents of wr reg5 res 7,a ;reset DTR bit ld (wrreg5),a ;update copy out (c),a pop af ;restore registers pop bc ret ; wrreg5: db 0EAH ;saved copy of write only reg (set at initmod) ; ;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 ld a,(brate) ; 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 ;Amstrad initialization -- sets sio for 8 bits, 1 stop, no parity etc. ; INITMOD: LD BC,MDCTL1 LD A,00H ;select reg. OUT (C),A LD A,18H ;throw out of mode OUT (C),A LD A,04H ;select reg. OUT (C),A LD A,44H ;set ascii parameters OUT (C),A LD A,03H ;select reg. OUT (C),A LD A,0C1H ;enable receive OUT (C),A LD A,05H ;select reg. OUT (C),A LD A,0EAH ;enable send, dtr, rts OUT (C),A ;Initialise 8253 for reqd baud rate LD A,(MSPEED) ;get the selected value CP 1 ;300 bps? NEWBD arrives here JP Z,OK300 CP 5 ;1200 bps? NOW 75/1200 bps JP Z,OK1200 CP 6 ;2400 bps? JP Z,OK2400 CP 8 ;9600 bps? JP Z,OK9600 jp init ;no valid rate ; ITMOD1: LD A,036H ;select counter 0 (a tx) LD BC,CTCMODE OUT (C),A ;send to 8253 timer ;first do tx chan. ; ITMOD2: LD A,068H ;default to 1200 LD BC,CTCTX OUT (C),A ;send to 8253 timer ; ITMOD3: LD A,00H ;1200 baud, msb portion OUT (C),A ;to timer ;now do rx chan. ; ITMOD4: LD A,076H ;select counter 1 (a rx) LD BC,CTCMODE OUT (C),A ; ITMOD5: LD A,068H ;load 1200, msb LD BC,CTCRX OUT (C),A ; ITMOD6: LD A,00H OUT (C),A RET ;..... ; Sets the modem speed via the set command. ; OK300: LD A,1 LD HL,(BD300) LD DE,(BD300) JP LOADBD ; OK1200: LD A,5 LD HL,(BD1200) LD DE,(BD1200) JP LOADBD ; OK2400: LD A,6 LD HL,(BD2400) LD DE,(BD2400) JP LOADBD ; OK9600: LD A,8 LD DE,(BD9600) LD HL,(BD9600) ; LOADBD: LD (MSPEED),A ;change time-to-send to match baudrate LD A,L ;get baudrate byte LD (ITMOD2+1),A ;send to 8253 ch a tx for new baudrate LD A,E LD (ITMOD5+1),A ;now rx LD A,H ;2nd 1/2 of baudrate LD (ITMOD3+1),A ;do tx first LD A,D LD (ITMOD6+1),A ;then rx JP ITMOD1 ;reinitialize to new baudrate, then done ; ; Table of baudrate parameters ; BD300: DEFW 01A0H BD1200: DEFW 0068H BD2400: DEFW 0034H BD9600: DEFW 000DH ; BAUDBUF:DEFB 10,0 DEFS 10 ret ;-------------------------------------------------------------------------- stop: dw 1 ; stop bits parity: dw 'N' ; parity data: dw 8 ; data bits brate: dw 6 ; 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 ; ;**************************************************************************** ;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,'Y',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,'p',0 ret ;Inverse video off: invoff: call print db esc,'q',0 ret ;Turn off cursor: hide: call print db esc,'f',0 ret ;Turn on cursor: show: call print db esc,'e',0 ret ;Save cursor position: savecu: call print db esc,'j',0 ret ;Restore cursor position: rescu: call print db esc,'k',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 ;****************** 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 if ($ - codebgn) gt ovsize toobig: jp errval ; Overlay too large! endif end  in hl, address still in de ret if ($ - codebgn) gt ovs