;------------------------------------------------------------------; ; SERVNIBB.S, network software for the ZX-Spectrum (Amiga part) ; ; ; ; Attaches a network to the parallel port of an OPUS Discovery ; ; Cable configuration: ; ; D0 - D3 = nibble to handle ; ; D4 = Spectrum togglebit ; ; D5 = own togglebit ; ; D6 = Spectrum errorbit ; ; D7 = Own errorbit ; ; BUSY = halt server-bit ; ; The connectivity should be 100%. ; ; The OPUS needs the optional 2K RAM (or 4K or 8K) to store the ; ; client part into, which patches the OPUS ROM. ; ; This version works with nibbles at network level. ; ; ; ; Copyright (C) 1991 Jeroen J. Kwast ThunderWare Research Center. ; ;------------------------------------------------------------------; ;----------------------------------------------------------- ; >>> DEFINES <<< ;----------------------------------------------------------- Open: = -30 Close: = -36 Read: = -42 Write: = -48 Lock: = -84 Unlock: = -90 Info: = -114 Examine: = -102 ExNext: = -108 Delay: = -198 DeleteFile: = -72 Rename: = -78 Output: = -60 Mode_Read: = 1005 Mode_Write: = 1006 SetTaskPri: = -300 OpenLibrary: = -552 CloseLibrary: = -414 AllocMem: = -198 AllocAbs: = -204 FreeMem: = -210 FindTask: = -294 WaitPort: = -384 GetMsg: = -372 Execbase: = 4 Public: = 1 Chip: = 2 Fast: = 4 Clear: = Chip+$10000 move.l d0,d6 move.l Execbase,a6 suba.l a1,a1 jsr FindTask(a6) move.l d0,a4 clr.b Wb tst.l $ac(a4) ; Cli or workbench ? bne Start lea $5c(a4),a0 ; (Messageport) jsr WaitPort(a6) ; Wait for message lea $5c(a4),a0 jsr GetMsg(a6) ; Get message move.b #1,Wb Start: move.l a4,a1 moveq #0,d0 jsr SetTaskPri(a6) move.l #$10000,d0 move.l #Fast,d1 jsr AllocMem(a6) beq TheEnd move.l d0,Data lea DosName,a1 moveq #0,d0 jsr OpenLibrary(a6) beq NoMem move.l d0,DosBase move.l DosBase,a6 tst.b Wb ; Workbench ? bne.s DoWb ; Yes jsr Output(a6) ; Use stdout for cli beq StopAll move.l d0,ConHandle bra.s DoWb1 DoWb: move.l #CliWindow,d1 ; Open window on worbench move.l #Mode_Write,d2 jsr Open(a6) beq StopAll move.l d0,ConHandle DoWb1: move.b #$af,$bfe301 ; Reset port to read 643210 write 75 ; to signal server on-line and waiting ... move.b #$c0,$bfd200 ; Busy bit on input btst #4,$bfe101 ; Errorbit beq.s Begin move.l ConHandle,d1 move.l #Ton,d2 move.l #Ton1-Ton,d3 jsr Write(a6) move.l #320000,d7 Begin: bclr #5,$bfe101 ; Always clear error bit bset #7,$bfe101 ; and set toggle bit TestErr: move.b $bfec01,d0 ; Do a keyboard scan not.b d0 ror.b #1,d0 cmp.b #$59,d0 ; Test if F10 is pressed beq StopServ btst #4,$bfe101 ; Test zx errorbit bne.s TestErr ; (until reset) btst #6,$bfe101 ; Test zx toggle bit bne.s TestErr ; (until reset) jsr LoadByte ; Get 'action byte' in d0 tst.b d0 ; Format ? beq Format cmp.b #1,d0 ; Save ? beq Save cmp.b #2,d0 ; Load ? beq Load bset #5,$bfe101 ; Signal error: 'action unknown' move.l #TActUn,d2 ; ('Unknown action' message) move.l #TActUn1-TActUn,d3 move.l DosBase,a6 move.l ConHandle,d1 jsr Write(a6) bra Begin ; And retry StopServ: tst.b Wb ; Workbench ? beq.s StopAll ; No, cli move.l DosBase,a6 ; Else close window move.l ConHandle,d1 jsr Close(a6) StopAll: move.l Execbase,a6 move.l DosBase,a1 jsr CloseLibrary(a6) NoMem: move.l Execbase,a6 move.l Data,a1 jsr FreeMem(a6) TheEnd: rts WaitSwitch: ; Needed because else I would ; reprogram the zx port too ; instead of the zx Busy1: btst #2,$bfd000 ; Busy 0 ? bne.s Busy1 Busy2: btst #2,$bfd000 ; Busy 1 ? beq.s Busy2 rts Format: move.l #FCode,a0 jsr LoadByte ; Get format code jsr WaitSwitch ; Wait for zx to switch to read move.l #Init,a0 ; Print initstring on zx Format1: jsr SendByte tst.b -1(a0) ; Terminate char 0 ? bne.s Format1 move.l DosBase,a6 move.l ConHandle,d1 move.l #Ton1,d2 move.l #Ton2-Ton1,d3 jsr Write(a6) bra Begin Load: move.l Data,a0 ; Start of buffer move.w #17,d2 ; Length = 18 moveq #0,d3 ; Parity Load1: jsr LoadByte move.b -1(a0),d0 eor.b d0,d3 ; XOR byte with parity dbf d2,Load1 jsr WaitSwitch ; Wait for zx to switch to read btst #7,FCode ; Network formatted ? beq.s Load1a lea Temp,a0 move.b #1,(a0) ; Signal: error jsr SendByte lea Err6,a5 ; Signal: 'network not formatted' error bra RepError ; Print error Load1a: tst.b d3 ; Test parity beq.s Load2 lea Temp,a0 move.b #1,(a0) ; Signal: error jsr SendByte move.l #Thr,d2 ; 'Header parity error' message move.l #Thr1-Thr,d3 move.l DosBase,a6 move.l ConHandle,d1 jsr Write(a6) lea Err2,a5 ; Signal: header parity error bra RepError ; Print error Load2: move.l Data,a1 ; Load it from disk move.b (a1),d7 ; Save the type prog, code etc. add.l #1,a1 lea Dir1,a0 ; Name to be saved move.w #9,d0 ; 10 chars Load3: move.b (a1)+,(a0)+ ; Transfer name dbf d0,Load3 move.l DosBase,a6 move.l #Dir,d1 move.l #Mode_Read,d2 jsr Open(a6) ; Open file for read tst.l d0 ; Error ? bne Load4 ; No, continue lea Temp,a0 move.b #1,(a0) ; Signal: error jsr SendByte lea Err7,a5 ; Signal: 'File not found' error bra RepError Load4: move.l d0,Handle ; Store the read handle moveq #17,d3 ; The header length move.l Data,d2 ; Start move.l Handle,d1 ; Read handle jsr Read(a6) ; Read header + body move.l Data,a0 cmp.b (a0),d7 ; Types the same ? beq.s Load5 lea Temp,a0 move.b #1,(a0) ; Signal: error jsr SendByte lea Err8,a5 ; Signal: 'Wrong file type' error bra RepError Load5: lea Temp,a0 clr.b (a0) ; Signal: ok jsr SendByte move.l Data,a0 moveq #0,d3 move.b 12(a0),d3 ; High byte of length lsl.w #8,d3 move.b 11(a0),d3 ; Low byte of length move.l Data,d2 ; Start of header add.l #17,d2 ; Get start of body move.l Handle,d1 jsr Read(a6) ; Read body move.l Handle,d1 jsr Close(a6) ; Close file move.l Data,a0 ; Start of buffer move.w #16,d2 ; Length = 17 moveq #0,d3 ; Parity Load6: move.b (a0),d0 eor.b d0,d3 ; XOR byte with parity jsr SendByte dbf d2,Load6 lea Temp,a0 move.b d3,(a0) ; Put parity jsr SendByte ; Send parity jsr WaitSwitch ; Wait for zx to switch to write lea Temp,a0 jsr LoadByte ; Load status jsr WaitSwitch ; Wait for zx to switch to read tst.b Temp ; Test status beq.s Load7 ; Ok lea Err9,a5 ; Signal: 'File size error' cmp.b #1,-1(a0) beq.s Load9 lea ErrA,a5 ; Signal: 'Out of memory' error cmp.b #2,-1(a0) beq.s Load9 lea Err2,a5 ; Signal: 'Parity error' Load9: bra RepError Load7: move.l Data,a0 ; Header pointer moveq #0,d2 move.b 12(a0),d2 ; High byte of length lsl.w #8,d2 move.b 11(a0),d2 ; Low byte of length sub.l #1,d2 ; Subtract 1 for dbf add.l #17,a0 moveq #0,d3 ; Parity Load8: move.b (a0),d0 eor.b d0,d3 ; XOR byte with parity jsr SendByte dbf d2,Load8 lea Temp,a0 move.b d3,(a0) ; Put parity jsr SendByte ; Send parity move.l Data,a0 move.l #Prog,d2 ; Start of text moveq #0,d0 move.b (a0),d0 tst.b d0 beq Loada sub.b #1,d0 Loadb: add.l #9,d2 dbf d0,Loadb Loada: move.l #9,d3 ; Print type move.l DosBase,a6 move.l ConHandle,d1 jsr Write(a6) move.l #Dir1,d2 ; Print name move.l #10,d3 move.l DosBase,a6 move.l ConHandle,d1 jsr Write(a6) move.l #Sen,d2 ; Print 'transmitted' move.l #Sen1-Sen,d3 move.l DosBase,a6 move.l ConHandle,d1 jsr Write(a6) bra Begin Save: move.l Data,a0 ; Start of buffer move.w #17,d2 ; Length = 18 moveq #0,d3 ; Parity Save1: jsr LoadByte move.b -1(a0),d0 eor.b d0,d3 ; XOR byte with parity dbf d2,Save1 jsr WaitSwitch ; Wait for zx to switch to read btst #7,FCode ; Network formatted ? beq.s Save1a lea Temp,a0 move.b #1,(a0) ; Signal: error jsr SendByte lea Err6,a5 ; Signal: 'Network not formatted' error bra RepError ; Print error Save1a: tst.b d3 ; Test parity beq.s Save2 lea Temp,a0 move.b #1,(a0) ; Signal: error jsr SendByte move.l #Thr,d2 ; 'Header parity error' message move.l #Thr1-Thr,d3 move.l DosBase,a6 move.l ConHandle,d1 jsr Write(a6) lea Err2,a5 ; Signal: 'Header parity error' bra RepError ; Print error Save2: clr.b -(a0) ; Signal: ok jsr SendByte suba.l #1,a0 ; Begin after header move.l Data,a1 ; Start of buffer moveq #0,d2 move.b 12(a1),d2 ; High byte of length lsl.w #8,d2 move.b 11(a1),d2 ; Low byte of length + parity moveq #0,d3 ; Parity Save3: jsr LoadByte move.b -1(a0),d0 eor.b d0,d3 ; XOR byte with parity dbf d2,Save3 ; Last byte is parity byte jsr WaitSwitch ; Wait for zx to switch to read tst.b d3 ; Test parity beq.s Save4 lea Temp,a0 move.b #1,(a0) ; Signal: error jsr SendByte move.l #Thr1,d2 ; 'Parity error' message move.l #Thr2-Thr1,d3 move.l DosBase,a6 move.l ConHandle,d1 jsr Write(a6) lea Err3,a5 ; Signal: 'Body parity error' bra RepError ; Print error Save4: clr.b -(a0) ; Signal: ok jsr SendByte move.l Data,a1 ; Save it to disk add.l #1,a1 lea Dir1,a0 ; Name to be saved move.w #9,d0 ; 10 chars Save5: move.b (a1)+,(a0)+ ; Transfer name dbf d0,Save5 move.l DosBase,a6 move.l #Dir,d1 move.l #Mode_Write,d2 jsr Open(a6) ; Open file for write tst.l d0 ; Error ? beq Begin ; Yes, return move.l d0,Handle ; Store the write handle move.l Data,a0 moveq #0,d3 move.b 12(a0),d3 ; High byte of length lsl.w #8,d3 move.b 11(a0),d3 ; Low byte of length add.w #17,d3 ; Add the header move.l Data,d2 ; Start move.l Handle,d1 ; Write handle jsr Write(a6) ; Write header+body move.l Handle,d1 jsr Close(a6) ; Close file move.l Data,a0 move.l #Prog,d2 ; Start of text moveq #0,d0 move.b (a0),d0 tst.b d0 beq Save6 sub.b #1,d0 Save7: add.l #9,d2 dbf d0,Save7 Save6: move.l #9,d3 ; Print type move.l DosBase,a6 move.l ConHandle,d1 jsr Write(a6) move.l #Dir1,d2 ; Print name move.l #10,d3 move.l DosBase,a6 move.l ConHandle,d1 jsr Write(a6) move.l #Rec,d2 ; Print 'received' move.l #Rec1-Rec,d3 move.l DosBase,a6 move.l ConHandle,d1 jsr Write(a6) bra Begin ; Wait for next action ; SendByte : (a0)+ contains the byte to be sent SendByte: move.b #$af,d0 ; Reset port to read 643210 write 75 move.b d0,$bfe301 ; Init parallel port move.l #80000,d1 ; Timeout move.b (a0),d0 lsr.b #4,d0 and.b #$f0,$bfe101 or.b d0,$bfe101 bclr #7,$bfe101 ; Signal: high nibble sent! (0) SendHigh: btst #4,$bfe101 ; Error from zx ? (1 = yes) bne RepError sub.l #1,d1 beq TOutSnd ; Timed out btst #6,$bfe101 ; Received ? (0 = yes) bne SendHigh move.l #80000,d1 ; Timeout move.b (a0)+,d0 and.b #$0f,d0 and.b #$f0,$bfe101 or.b d0,$bfe101 bset #7,$bfe101 ; Signal: low nibble sent! (1) SendLow: btst #4,$bfe101 ; Error from zx ? (1 = yes) bne ZXErrSnd sub.l #1,d1 beq RepError ; Timed out btst #6,$bfe101 ; Received ? (1 = yes) beq SendLow rts ; LoadByte : (a0)+ contains the byte loaded LoadByte: move.b #$a0,d0 ; Reset port to write 64 write 753210 move.b d0,$bfe301 ; Init parallel port move.l #80000,d1 ; Timeout LoadHigh: btst #4,$bfe101 ; Error from zx ? (1 = yes) bne ZXErrRec sub.l #1,d1 beq TOutRec ; Timed out btst #6,$bfe101 ; Ready to send ? (0 = yes) bne LoadHigh moveq #0,d0 ; Clear receive byte move.b $bfe101,d0 ; Get high nibble lsl.b #4,d0 bclr #7,$bfe101 ; Signal: high nibble received! (0) move.l #80000,d1 ; Timeout LoadLow: btst #4,$bfe101 ; Error from zx ? (1 = yes) bne ZXErrRec sub.l #1,d1 beq TOutRec ; Timed out btst #6,$bfe101 ; Ready to send ? (1 = yes) beq LoadLow move.b $bfe101,d1 ; Get low nibble and.b #$0f,d1 ; Mask low nibble or.b d1,d0 ; OR nibble to get byte in d0 move.b d0,(a0)+ bset #7,$bfe101 ; Signal: low nibble received! (1) rts TOutSnd: lea Err1,a5 ; Signal: time-out send bra.s TOut2 TOutRec: lea Err0,a5 ; Signal: time-out receive TOut2: move.l (a7)+,a0 ; Pop last value on stack bset #5,$bfe101 ; Signal: error move.l #160000,d1 ; Timeout TOut3: btst #4,$bfe101 ; Error set ? bne TOut4 ; Yep, set too sub.l #1,d1 bne TOut3 ; Timed out again? bra.s TOutAgn TOut4: bclr #5,$bfe101 ; Clear error btst #4,$bfe101 ; Error reset ? beq RepError ; Yep, clear too sub.l #1,d1 bne TOut3 ; Timed out again? TOutAgn: move.l #TTOut,d2 ; 'Timed out again' message move.l #TTOut1-TTOut,d3 move.l DosBase,a6 move.l ConHandle,d1 jsr Write(a6) bra Begin ; Restart, but leave error bit ; Also entry for outside the loop (stack correct) RepError: jsr WaitSwitch ; Wait for zx to switch to read move.l a5,a0 ; Switch at error RepErr2: jsr SendByte tst.b -1(a0) ; Terminate char 0? bne.s RepErr2 move.l #TTOut1,d2 ; 'Response during time-out' message move.l #TTOut2-TTOut1,d3 move.l DosBase,a6 move.l ConHandle,d1 jsr Write(a6) bra Begin ; Restart and clear error bit ZXErrRec: lea Err4,a5 move.l #TZxErr0,d2 ; Zx error message receive move.l #TZxErr-TZxErr0,d3 bra.s ZXErr2 ZXErrSnd: lea Err5,a5 move.l #TZxErr,d2 ; Zx error message send move.l #TZxErr1-TZxErr,d3 ZXErr2: bset #5,$bfe101 ; Signal: error move.l (a7)+,a0 ; Pop last value on stack move.l DosBase,a6 move.l ConHandle,d1 jsr Write(a6) move.l #80000,d1 ; Timeout ZXErr3: btst #4,$bfe101 ; Error reset ? beq ZXErr4 ; Yep clear too sub.l #1,d1 bne ZXErr3 ; Timed out again? bra Begin ; Restart ZXErr4: bclr #5,$bfe101 ; Reset error bra RepError ; Send the error DosBase: dc.l 0 Handle: dc.l 0 ConHandle: dc.l 0 Data: dc.l 0 Temp: dc.b 0 In: dc.b 0 Out: dc.b 0 FCode: dc.b 128 Wb: dc.b 0 DosName: dc.b "dos.library",0 CliWindow: dc.b "con:0/0/640/100/SlingServerV1.3a",0 Init: dc.b "SlingServer v1.3a ready",0 Err0: dc.b "0 Receive time-out",0 Err1: dc.b "1 Transmit time-out",0 Err2: dc.b "2 Header parity error",0 Err3: dc.b "3 Body parity error",0 Err4: dc.b "4 Receive time-out",0 Err5: dc.b "5 Transmit time-out",0 Err6: dc.b "- Network not formatted",0 Err7: dc.b "6 File not found",0 Err8: dc.b "7 Wrong file type",0 Err9: dc.b "8 File size error",0 ErrA: dc.b "9 Out of memory",0 Ton: dc.b "Spectrum not connected, waiting for connection",13,10 Ton1: dc.b "Format sequence received, all systems clear",13,10 Ton2: Thr: dc.b "Header received with incorrect parity",13,10 Thr1: dc.b "Body received with incorrect parity",13,10 Thr2: TZxErr0: dc.b "Spectrum signalled a receive time-out",13,10 TZxErr: dc.b "Spectrum signalled a transmit time-out",13,10 TZxErr1: TTOut: dc.b "No response after error",13,10 TTOut1: dc.b "Spectrum responded after error",13,10 TTOut2: TActUn: dc.b "Spectrum requested an unknown action",13,10 TActUn1: Prog: dc.b "Program: " dc.b "Number : " dc.b "Char : " dc.b "Code : " Rec: dc.b " received Ok",13,10 Rec1: Sen: dc.b " transmitted Ok",13,10 Sen1: Dir: dc.b "DH0:ZXNet/" Dir1: dc.b " ",0