10
20
30
40
50
60
70 :
80 DIM mcode% &3000
90 OSCLI"LOAD NFSROM "+STR$~mcode%
100 rom2%=&9FB5:OSBYTE=&FFF4
110 :
120 EcoTx%=mcode%!&1631 AND &FFFF
130 EcoInit%=mcode%!&1634 AND &FFFF
140 EcoNMIRelease%=mcode%!&1637 AND &FFFF
150 EcoNMIClaim%=mcode%!&163A AND &FFFF
160 :
170 TxStatus=&FC08:TxRDY=1:TxData=&FC09
180 RxStatus=&FC08:RxRDY=2:RxData=&FC09
190 :
200 esc=&9B
210
220
230
240
250
260
270
280
290
300
310
320
330
340 :
350 DEFFNorg(A%):P%=A%:O%=P%-&8000+mcode%:=P*3+4
360 FOR P=0 TO 1
370 [OPT FNorg(&8009)
380 EQUS "SER" :\ Title="SER,NET"
390 :
400 OPT FNorg(&9630) :\ Low level networking entry points
410 JMP SerNetTx :\ Transmit block
420 JMP SerNetInit :\ Initialise, put receive handlers in place
430 JMP EcoNMIRelease% :\ I must release NMIs
440 JMP EcoNMIClaim% :\ I can take over NMIs
450 :
460 OPT FNorg(&9643)
470 JMP SerNetIRQ :\ IRQ occured
480 :
490 OPT FNorg(rom2%)
500 \ Service routine
510 \ ===============
520 RTS
530 :
540 :
550 \ Initialise network drivers
560 \ ==========================
570 .SerNetInit
580 JSR EcoInit% :\ Initialise Econet drivers
590 LDA #7:LDX #7:JSR OSBYTE
600 LDA #8:LDX #7:JSR OSBYTE :\ Set serial port speed to 9600
610 LDA #0:STA &190+232 :\ Serial IRQs come to me
620 RTS
630 :
640 :
650 \ Transmit a block of data
660 \ ========================
670 .SerNetTx
680 \ On entry,
690 \ X is important
700 \ A,Y unimportant
710 \ &A0/1=>workspace+&6F
720 \ (&A0),0 = control byte
730 \ 1 = port
740 \ 2 = station
750 \ 3 = net
760 \ 4-7 =>buffer start
770 \ 8-11 =>buffer end
780 \ 12-15= Remote Address
790 \
800 \ On exit,
810 \ (&A0),0 = result, read by OSBYTE &32
820 \ A,Y = unimportant
830 \ X = preserved
840 \
850 LDY #3:LDA (&A0),Y :\ Get network number
860 CMP #&FF:BEQ SerTxBroadcast
870 AND #&F0:CMP #&70
880 BEQ SerTx:JMP EcoTx% :\ Not net &7x, pass to Econet driver
890 :
900 .SerTxBroadcast
910 JSR EcoTx% :\ Send broadcast to Econet
920 .SerTx
930 :
940 \ Transmit a block of data via serial port
950 \ Sends <header> <wait-ack> <data> <wait-ack>
960 \
970 \ Should wait for 'Background reception not in progress'
980 :
990 TXA:PHA:LDA &A9:PHA:LDA &A8:PHA :\ Save X and some workspace
1000 LDX #0:JSR SerTxScoutStart :\ Frame start
1010 LDY #2:LDA (&A0),Y:JSR SerTxByte :\ dest stn
1020 INY:LDA (&A0),Y:JSR SerTxByte :\ dest net
1030 LDA &D22:JSR SerTxByte :\ src stn
1040 LDA &D8F:AND #15
1050 ORA #&70:JSR SerTxByte :\ src net
1060 LDY #0:LDA (&A0),Y:JSR SerTxByte :\ Ctrl
1070 INY:LDA (&A0),Y:JSR SerTxByte :\ Port
1080 BNE SerTxNotImmediate:LDY #12
1090 .SerTxRAddr
1100 LDA (&A0),Y:JSR SerTxByte :\ Send RemoteAddress
1110 INY:CPY #16:BNE SerTxRAddr
1120 .SerTxNotImmediate
1130 LDY #2:LDA (&A0),Y:CMP #&FF:PHP :\ Dest=???.255 ?
1140 \\\
1150 \\\ Should check for Tube address
1160 \\\
1170 INY:LDA (&A0),Y:STA &A8
1180 INY:LDA (&A0),Y:STA &A9 :\ &A8/9=address
1190 PLP:BNE SerTxNotBroadcast
1200 .SerTxBroadcast
1210 LDA (&A8),Y:JSR SerTxByte
1220 INY:CPY #8:BNE SerTxBroadcast :\ Send exactly 8 bytes
1230 .SerTxNotBroadcast
1240 PHP:JSR SerTxScoutEnd:PLP :\ End of scout frame
1250 BEQ SerTxDone :\ Broadcast has no ACK
1260 JSR SerWaitAck:BNE SerTxDone :\ Not ACK'd, don't send data
1270 JSR SerTxDataStart :\ Start of data frame
1280 .SerTxDataLp
1290 LDY #0:LDA (&A8),Y:JSR SerTxByte :\ Send a byte of data
1300 INC &A8:BNE P%+4:INC &A9 :\ Increment address
1310 LDY #8:LDA (&A0),Y :\ Compare with end address
1320 CMP &A8:BNE SerTxDataLp :\ More to do
1330 INY:LDA (&A0),Y
1340 CMP &A9:BNE SerTxDataLp :\ More to do
1350 JSR SerTxDataEnd :\ End of data frame
1360 JSR SerWaitAck :\ Get ack/nak
1370 .SerTxDone
1380 TXA:LDY #0:STA (&A0),Y :\ Store result
1390 PLA:STA &A8:PLA:STA &A9:PLA:TAX :\ Restore workspace and X
1400 RTS
1410 :
1420 \ Transmission subroutines
1430 \ ------------------------
1440 .SerTxScoutStart:LDA #&A0:BNE SerTxCommand
1450 .SerTxScoutEnd :LDA #&A2:BNE SerTxCommand
1460 .SerTxDataStart :LDA #&A4:BNE SerTxCommand
1470 .SerTxDataEnd :LDA #&A6:BNE SerTxCommand
1480 .SerTxScoutACK :LDA #&A8:BNE SerTxCommand
1490 .SerTxScoutNAK :LDA #&AA:BNE SerTxCommand
1500 .SerTxDataACK :LDA #&AC:BNE SerTxCommand
1510 .SerTxDataNAK :LDA #&AE:BNE SerTxCommand
1520 :
1530 .SerTxCommand
1540 PHA:LDA #esc:JSR SerTxRaw :\ Send esc to prefix command
1550 PLA:BNE SerTxRaw :\ Send command byte
1560 :
1570 .SerTxByte
1580 CMP #esc:BNE SerTxRaw :\ esc has to be esc'ed
1590 JSR SerTxRaw
1600 .SerTxRaw
1610 PHA
1620 .SerTxByteWait
1630 LDA TxStatus:AND #TxRDY :\ Wait until Tx empty
1640 BEQ SerTxByteWait
1650 PLA:STA TxData :\ Send byte
1660 RTS
1670 :
1680 .SerWaitAck
1690 LDA &D8F:AND #&30:BEQ SerWaitAck :\ Wait for ACK/NAK response
1700 AND #&20:BEQ P%+4:LDA #&42 :\ Convert to NetStatus value
1710 TAX:LDA &8DF:AND #&CF:STA &8DF
1720 TXA:RTS :\ EQ=ACK, NE=NAK
1730 :
1740 :
1750 :
1760 :
1770 \ IRQ occured
1780 \ ===========
1790 \ &A8/&A9 stacked, usable as workspace
1800 \ &A8=Y=Service Y parameter
1810 \ &A9=service number, returned A value
1820 \ X=?&BB
1830 \ On exit, ?&A9 passed to A
1840 \ Y returned to caller
1850 \ X ignored, restored from &F4
1860 \
1870 \ &D80-&D8B - Incoming scout
1880 \ &D80 dest stn
1890 \ &D81 dest net
1900 \ &D82 src stn
1910 \ &D83 src net
1920 \ &D84 ctrl
1930 \ &D85 port
1940 \ &D86-9 RemoteAddress, TransferAddress
1950 \ &D8A-D TransferAddressEnd
1960 \ &D86-D Broadcast data
1970 \ &D8E b7=0 - index into incoming scout
1980 \ b7=1 - waiting for incoming data
1990 \ &D8F b7 - waiting for escaped byte
2000 \ b6 - transfering to Tube
2010 \ b5-b4 - received ACK/NAK flag
2020 \ b3-b0 - my network number
2030 \ &D90-&D91 - Incoming receive block address
2040 \
2050 .SerNetIRQ
2060 LDA RxStatus:BMI SerNetIRQYes
2070 LDA #5:RTS :\ Not from serial, exit
2080 .SerNetIRQYes
2090 TYA:PHA:LDA &A9:PHA :\ Save Y and ?&A9
2100 LDA RxData :\ Get byte from serial port
2110 BIT &D8F:BMI SerRxEsc2nd :\ Waiting for escaped byte
2120 CMP #esc:BEQ SerRxEsc1st :\ Start of escape sequence
2130 LDY &D8E:BMI SerRxData :\ Waiting for data frame
2140 CPY #12:BCS SerRxExit :\ Scout overrun, ignore extra bytes
2150 STA &D80,Y:INY:STY &D8E :\ Store byte of scout
2160 BNE SerRxExit :\ Exit
2170 :
2180 .SerRxEsc1st
2190 LDA #&80:ORA &D8F:STA &D8F :\ Set b7, waiting for escaped byte
2200 BNE SerRxExit
2210 :
2220 .SerRxEsc2nd
2230 CMP #esc:BNE SerRxEscCmd :\ esc,<>esc -> escaped command
2240 \ esc,esc -> esc
2250 :
2260 .SerRxData
2270 BIT &D8F:BVC SerRxIO :\ b6=0, read to I/O memory
2280 STA &FEE5:BVS SerRxUpdate :\ Read to Tube memory
2290 .SerRxIO
2300 TAY
2310 LDA &D86:STA &A8
2320 LDA &D87:STA &A9
2330 TYA:LDY #0:STA (&A8),Y :\ Store received byte
2340 .SerRxUpdate
2350 INC &D86:BNE SerRxUpdEnd :\ Update transfer address
2360 INC &D87:BNE SerRxUpdEnd
2370 INC &D88:BNE SerRxUpdEnd
2380 INC &D89
2390 .SerRxUpdEnd
2400 \ Should check for data overrun
2410 .SerRxExit
2420 PLA:STA &A9:PLA:TAY :\ Restore workspace and Y
2430 LDA #0:RTS
2440 :
2450 \ Escaped command
2460 \ ---------------
2470 \ &esc,&Ax - %10100xxx - incoming
2480 \ &esc,&Ax - %10101xxx - replies
2490 \
2500 \ %1010000x - ScoutStart
2510 \ %1010001x - ScoutEnd
2520 \ %1010010x - DataStart
2530 \ %1010011x - DataEnd
2540 \
2550 \ %1010100x - ScoutACK
2560 \ %1010101x - ScoutNAK
2570 \ %1010110x - DataACK
2580 \ %1010111x - DataNAK
2590 \
2600 .SerRxEscCmd
2610 TAY:AND #&F0
2620 CMP #&A0:BNE SerRxExit :\ Not %1010xxxx, ignore
2630 TYA:AND #7:LSR A
2640 BNE SerRxScoutEnd
2650 :
2660 \ ScoutStart
2670 STA &D8E:BEQ SerRxExit :\ Set count index to zero
2680 :
2690 .SerRxScoutEnd
2700 CMP #2:BCS SerRxDataStart
2710 LDA &D85:BEQ SerRxImmediate:\ Port=0, immediate command
2720 \
2730 \ Look through open receive block
2740 \ See if anything's listening for this incoming scout
2750 \ This is where gateway action could be performed
2760 \ If deststn<>mystn OR destnet<>0, pass out onto Econet
2770 \ Would need complemntary EcoRx->SerTx code
2780 \
2790 JSR FindReceiveBlock :\ Returns X=ScoutACK/ScoutNAK
2800 JSR SerTxCommand :\ Send ACK/NAK
2810 JMP SerRxExit
2820 :
2830 .SerRxDataStart
2840 BNE SerRxDataEnd
2850 LDA #&80:STA &D8E :\ Waiting for data
2860 BNE SerRxExit
2870 :
2880 .SerRxDataEnd
2890 CMP #4:BCS SerRxACK :\ ACK/NAK received
2900 JSR SerTxDataACK :\ Send ACK
2910 LDA &D90:STA &A8 :\ Get Rx block address
2920 LDA &D91:STA &A9
2930 LDY #11
2940 .SerRxEndAddr
2950 LDA &D7E,Y:STA (&A8),Y :\ Update end address with final data address
2960 DEY:CPY #8:BNE SerRxEndAddr
2970 LDY #3:LDA &D83:STA (&A8),Y:\ Actual Net received from
2980 DEY:LDA &D82:STA (&A8),Y :\ Actual Stn received from
2990 DEY:LDA &D85:STA (&A8),Y :\ Actual port received
3000 DEY:LDA &D84:STA (&A8),Y :\ Received control byte, closes receive block
3010 LDA #0:STA &D8E :\ Reset back to waiting for scout
3020 BIT &D8F:BVC SerRxExit :\ I/O transfer
3030 LDA #&C0+&3E:JSR &406 :\ Release Tube
3040 STA &D8F:AND #15:STA &D8F :\ Clear Tube flag
3050 JMP SerRxExit
3060 :
3070 .SerRxACK
3080 TYA:AND #3:ORA #1 :\ A=01 11 01 11 for ACK/NAK/ACK/NAK
3090 ASL A:ASL A:ASL A:ASL A :\ A=&1x=ACK, &3x=NAK
3100 ORA &D8F:STA &D8F :\ Put ACK/NAK into flag byte
3110 JMP SerRxExit
3120 :
3130 \ Immediate Operations
3140 \ --------------------
3150 \ If &D80<>mystat, not for me
3160 \ If &D81<>mynet, not for me
3170 .SerRxImmediate
3180 LDA &D84:CMP #&88 :\ Only MachType supported
3190 BEQ P%+5:JMP SerRxExit :\ Ignore all others
3200 :
3210 \\\ Need to send a long scout in reply
3220 \\\ dstn,dnet,sstn,snet,b1,b2,b3,b4
3230 \\\
3240 \\\ Need to wait until foreground not transmitting
3250 \\\
3260 JMP SerRxExit
3270 :
3280 :
3290 \ Look for a matching open receive block
3300 \ ======================================
3310 \ Receive blocks are in private Econet workspace at (&9E),Y
3320 \ If &D64.b7=1, listening receive block at &00C0 for FSOp
3330 \ 0 - 0=end blocks, &7F=open receive block, &80+x=receive control byte
3340 \ 1 - port
3350 \ 2 - stn
3360 \ 3 - net
3370 \ 4-7 - buffer start
3380 \ 8-11 - buffer end
3390 \
3400 .FindReceiveBlock
3410 LDA &9F:STA &A9:LDA #0:STA &A8 :\ &A8/9=>Econet workspace
3420 BIT &D64:BPL FindRxLp
3430 STA &A9:LDA #&C0:STA &A8 :\ &A8/9=>&00C0 FSOp receive block
3440 .FindRxLp
3450 LDY #0
3460 LDA (&A8),Y:BEQ FindRxNone :\ End of blocks, no match
3470 CMP #&7F:BNE FindRxNext :\ Not an open block, try next
3480 INY:LDA (&A8),Y:BEQ FindRxPort :\ Listen on any port
3490 CMP &D85:BNE FindRxNext :\ Port doesn't match, try next
3500 .FindRxPort
3510 INY:LDA (&A8),Y:BEQ FindRxFound:\ Listen to any station
3520 CMP &0D80:BNE FindRxNext :\ Station doesn't match, try next
3530 INY:LDA (&A8),Y:BEQ FindRxFound:\ Listen to any network
3540 CMP &0D81:BEQ FindRxFound :\ Nets match, jump to process
3550 :
3560 .FindRxNext :\ This block doesn't match, step to next
3570 LDA &A9:BEQ FindRxNone :\ FSOp receive block
3580 LDA &A8:CLC:ADC #12 :\ Step to next receive block
3590 STA &A8:BCC FindRxLp :\ Loop back to check this one
3600 .FindRxNone
3610 SEC:LDX #&AA:RTS :\ X=ScoutEndNAK - no receive block found
3620 :
3630 \ Receive block matches
3640 \ ---------------------
3650 .FindRxFound
3660 LDA &A8:STA &D90
3670 LDA &A9:STA &D91 :\ Point to this receive block
3680 \\\
3690 \\\ If broadcast, eat the data now
3700 \\\
3710 LDY #4
3720 .FindRxAddrLp
3730 LDA (&A8),Y:STA &D82,Y :\ Copy AddrStart and AddrEnd to workspace
3740 INY:CPY #12:BNE FindRxAddrLp
3750 LDA &D89:CMP #&FF:BNE FindRxIO :\ I/O memory, return
3760 .FindRxTube
3770 LDA #&80+&3E:JSR &406 :\ Claim Tube
3780 BCC FindRxTube
3790 LDA #1:JSR &406 :\ Transfer bytes to CoPro
3800 LDA &D8F:ORA #&40:STA &D8F :\ Flag 'Tube transfer'
3810 .FindRxIO
3820 CLC:LDX #&A8:RTS :\ X=ScoutEndACK
3830 :
3840 ]
3850 NEXT
3860 PRINT"*SAVE SerNet/rom ";~mcode%;" ";~O%;" 0 FFFBBC00"