Previous Next Contents Index
The network routines

THE '"N" CHANNEL INPUT' ROUTINE
This routine handles the input of a single byte. When 'EOF' occurs, an error is given,
in case of an other error retries will be made.

3808 N_INPUT    PUSH BC                  Save registers before getting a byte.
3809            PUSH DE
380A            PUSH HL
380B NCI_RETRY  CALL #3819,NCHAN_IN
380E            JR   C,#3815,NCI_ACCEPT  Jump if byte acceptable.
3810            JR   Z,#380B,NCI_RETRY   Try again if no byte has been read.
3812            JP   #2956,REP_27        Give error if end of file.

3815 NCI_ACCEPT POP  HL                  Restore registers and exit.
3816            POP  DE
3817            POP  BC
3818            RET

THE '"N" CHANNEL INPUT' ROUTINE
The actual "n" input involves the reading of the byte from the network buffer. If no
other bytes are found in the buffer, a further data block is to be received (provided
that the 'current' block is not the 'EOF' one) before reading the byte.

3819 NCHAN_IN   LD   IX,#1E3D            Fetch start of "n" channel.
381D            LD   A,(IX+16)
3820            AND  A
3821            JP   NZ,#2944,REP_18     Jump if it isn't a "read" file.
3824 TEST_BUFF  LD   A,(IX+20)           Fetch number of bytes in input buffer.
3827            AND  A
3828            JR   Z,#383E,TEST_N_EOF  Jump if buffer is empty.
382A            LD   E,(IX+19)           Otherwise fetch the current position.
382D            DEC  A                   Decrease number of bytes to be read.
382E            SUB  E
382F            JR   C,#383E,TEST_N_EOF  Jump if all bytes have been read.
3831            LD   D,0                 Clear D.
3833            INC  E
3834            LD   (IX+19),E           Update byte position.
3837            ADD  IX,DE               Point to 'byte to be read - 20'.
3839            LD   A,(IX+20)           Read the byte.
383C            SCF                      Signal 'acceptable byte'.
383D            RET

If no data is found in the buffer, consider whether this is the last data block.

383E TEST_N_EOF LD   A,(IX+15)           Fetch packet type.
3841            AND  A                   Jump if it is a normal  packet  (packet
3842            JR   Z,#3845,GET_N_BUF   type of EOF = 1).
3844            RET                      Otherwise return with both Zero and
                                         Carry flags reset to signal 'EOF'.

A further data block is to be received if the current data block is not the 'EOF' one.

3845 GET_N_BUF  CALL #3AF1,NET_BORD      Set border colour, store IFF and DI.
3848 TRY_AGAIN  CALL #3A09,WT_SCOUT      Wait for a 'scout' leader.
384B            JR   NC,#3861,TIME_OUT   Jump if 'time out' occurs.
384D            CALL #391E,GET_NBLK      Get header and data block.
3850            JR   NZ,#3861,TIME_OUT   Jump with any error.
3852            CALL #3B02,REST_BORD     Restore border and interrupt status.
3855            LD   (IX+19),#00         Reset byte position.
3859            LD   A,(#1DF9)
385C            LD   (IX+15),A           Store packet type.
385F            JR   #3824,TEST_BUFF     Now try to fetch the byte.

Something went wrong, ignore it when broadcasting.

3861 TIME_OUT   LD   A,(IX+11)           Fetch destination station number.
3864            AND  A                   Jump if broadcasting, then there is no
3865            JR   Z,#3848,TRY_AGAIN   'time out'.
3867            CALL #3B02,REST_BORD     Restore border and interrupt status.
386A            AND  0                   Return with Zero flag set and Carry
386C            RET                      reset, to signal 'no data read'.

THE '"N" CHANNEL OUTPUT' ROUTINE
This routine handles the output of a single byte.

386D N_OUTPUT   PUSH BC                  Save registers before outputting the
386E            PUSH DE                  byte.
386F            PUSH HL
3870            CALL #3877,NCHAN_OUT
3873            POP  HL                  Restore registers and exit.
3874            POP  DE
3875            POP  BC
3876            RET

THE '"N" CHANNEL OUTPUT' ROUTINE
The routine that handles the "n" channel output is quite straightforward. It involves
the storing of the byte held in the A register into the 255-byte buffer; whenever this
is filled, the subroutine 'S_PACK_1' is called, so the data block is sent over the
network.

3877 NCHAN_OUT  LD   IX,#1E3D            Point to start of channel.
387B            LD   B,A
387C            LD   A,(IX+20)
387F            AND  A
3880            LD   A,B
3881            JP   NZ,#2946,REP_19     Give error if it is a 'read' channel.
3884            LD   E,(IX+16)           Fetch position of previous byte.
3887            INC  E                   Include current byte.
3888            JR   NZ,#3892,ST_BUF_POS Jump if the buffer isn't full.
388A            PUSH AF
388B            XOR  A                   Signal normal packet type.
388C            CALL #38B5,S_PACK_1      Send the packet.
388F            POP  AF
3890            LD   E,1                 Only 1 byte in buffer now.
3892 ST_BUF_POS LD   (IX+16),E           Store byte position.
3895            LD   D,0
3897            ADD  IX,DE               Point to 'first free byte - 20'.
3899            LD   (IX+20),A           Store the byte.
389C            RET

THE 'OUT_BLK_N' SUBROUTINE
This subroutine calls the 'OUTPAK' subroutine to send over the network the block of
bytes starting from (HL), and whose length is held in the E register. Then a 'response
byte' is to be received (provided there isn't broadcasted). The Zero flag is returned
reset if no response byte has been received. This subroutine is called from 'SEND_PACK'
below to send the header and then the data block over the network.

389D OUT_BLK_N  CALL #3ABC,OUTPAK        Send the block.
38A0            LD   A,(IX+11)
38A3            AND  A
38A4            RET  Z                   Return if broadcasting.
38A5            LD   HL,#1DF4            Address of store for network response
38A8            LD   (HL),0              code.
38AA            LD   E,1                 A single byte is to be received.
38AC            CALL #3A87,INPAK         Get response byte.
38AF            RET  NZ                  Return if the network was inactive.
38B0            LD   A,(#1DF4)
38B3            DEC  A                   The response byte must be 1.
38B4            RET                      Return with NZ if it wasn't.

THE 'S_PACK_1' SUBROUTINE
This subroutine simply calls 'SEND_PACK' below. If broadcasting, a certain delay is to
be inserted after having sent the packet.

38B5 S_PACK_1   CALL #38BC,SEND_PACK     Send the packet.
38B8            RET  NZ                  Return if not broadcasting.
38B9            JP   #3915,BR_DELAY      Otherwise return via the delay routine.

THE 'SEND_PACK' SUBROUTINE
This subroutine sends over the network a SCOUT leader, followed by the header and the
data block for the "n" channel. On entry, the A register may hold 1 or 0 depending on
whether the block is the 'end of file' one or not. The block number (IX+13,14) is
incremented before returning. The Zero flag is returned set if 'broadcasting' is being
used.

38BC SEND_PACK  LD   (IX+15),A           Store packet type, i.e. #00 for normal,
                                         #01 for end of file.
38BF            LD   B,(IX+16)           Fetch block length.
38C2            CALL #3AF1,NET_BORD      Set border, store IFF and DI.
38C5            PUSH IX                  Make DE point to the start of the
38C7            POP  DE                  "n" channel.
38C8            LD   HL,21               Offset to the 255 byte buffer.
38CB            ADD  HL,DE

Now the checksum of the data block is calculated.

38CC            XOR  A                   Clear checksum.
38CD CHKS1      ADD  A,(HL)              Add this byte.
38CE            INC  HL                  Next byte.
38CF            DJNZ #38CD,CHKS1         Repeat for all bytes in the block.
38D1            LD   (IX+17),A           Store the obtained checksum.
38D4            LD   HL,11               Now point to the location where the
38D7            ADD  HL,DE               destination station number is held.
38D8            PUSH HL

The checksum of the header is calculated.

38D9            LD   B,7                 Checksum is for 7 bytes.
38DB            XOR  A                   Clear checksum.
38DC CHKS2      ADD  A,(HL)              Add this byte.
38DD            INC  HL                  Next byte.
38DE            DJNZ #38DC,CHKS2         Repeat for all header bytes.
38E0            LD   (HL),A              Store the checksum.
38E1 SENDSCOUT  CALL #3A4A,SEND_SC       Send the SCOUT i.e. a leader followed
                                         by the station number.
38E4            POP  HL                  Restore  pointer  to  start  of  header
38E5            PUSH HL                  block.
38E6            LD   E,8                 The header consists of '8' bytes.
38E8            CALL #389D,OUT_BLK_N     The header is sent, and the response
                                         code received.
38EB            JR   NZ,#38E1,SENDSCOUT  Repeat until successfull.
38ED            PUSH IX                  Make HL point to the start of the
38EF            POP  HL                  "n" channel.
38F0            LD   DE,21
38F3            ADD  HL,DE               Point to the start of the data block.
38F4            LD   E,(IX+16)           Get block length.
38F7            LD   A,E
38F8            AND  A                   If the buffer is empty; no data needs
38F9            JR   Z,#3904,INC_BLKN    to be sent.
38FB            LD   B,32                Wait 418 T cycles before proceeding.
38FD SP_DL_1    DJNZ #38FD,SP_DL_1

Now the data block is sent and the block number incremented.

38FF            CALL #389D,OUT_BLK_N     Send the data block, receive response.
3902            JR   NZ,#38E1,SENDSCOUT  Repeat until successfull.
3904 INC_BLKN   INC  (IX+13)             Increment low byte of block number.
3907            JR   NZ,#390C,SP_N_END   The high byte of block number is only
3909            INC  (IX+14)             incremented when necessary.
390C SP_N_END   POP  HL                  Restore pointer to start of header.
390D            CALL #3B02,REST_BORD     Restore border and interrupt status.
3910            LD   A,(IX+11)           Get destination station number.
3913            AND  A
3914            RET                      Return with Zero set if broadcasting.

THE 'BR_DELAY' SUBROUTINE
This short subroutine inserts a delay of about 40 msec. when it is called. Its task
is that of separating outputs during broadcast transmissions.

3915 BR_DELAY   LD   DE,5376             This costs 139791 T states including
3918 DL_LOOP    DEC  DE                  the RET instruction. The 3.5 MHz Z80 in
3919            LD   A,E                 the Spectrum takes 39.94 msec to
391A            OR   D                   complete this subroutine.
391B            JR   NZ,#3918,DL_LOOP
391D            RET

THE 'GET A HEADER & DATA BLOCK' ROUTINES
The following two subroutines are used to get from the network an 8-byte header and a
data block respectively. Both require that the IX register points to the start of the
"n" channel. The Zero flag is returned reset with any error.

391E GET_NBLK   LD   HL,#1DF5            Point to the first byte of the header.
3921            LD   E,8                 A header is 8 bytes long.
3923            CALL #3A87,INPAK         Receive the header.
3926            RET  NZ                  Return when no header received.
3927            LD   HL,#1DF5            Restore pointer.

Now the header checksum is calculated, and compared with the received checksum.

392A            XOR  A                   First clear the checksum.
392B            LD   B,7                 Length of header (without checksum).
392D CHKS3      ADD  A,(HL)              Add this byte.
392E            INC  HL                  Next byte.
392F            DJNZ #392D,CHKS3         Repeat for all bytes.
3931            CP   (HL)                Compare with received checksum.
3932            RET  NZ                  Return if they don't match.

Now some tests are being made: Is the block for this Spectrum, is it from the right
Spectrum and is it the right block?

3933            LD   A,(#1DF5)           Fetch destination station number.
3936            AND  A
3937            JR   Z,#3946,BRCAST      Jump if broadcasting.
3939            CP   (IX+12)             Otherwise compare with own station
393C            RET  NZ                  number, return if for another Spectrum.
393D            LD   A,(#1DF6)           Source station number.
3940            CP   (IX+11)             Return if the transmitting Spectrum is
3943            RET  NZ                  not the required one.
3944            JR   #394B,TEST_BLKN

3946 BRCAST     LD   A,(IX+11)
3949            OR   A                   Return if this station is not waiting
394A            RET  NZ                  for a broadcast.
394B TEST_BLKN  LD   HL,(#1DF7)          Fetch number of block being
394E            LD   E,(IX+13)           transmitted, fetch number of expected
3951            LD   D,(IX+14)           block.
3954            AND  A
3955            SBC  HL,DE               Jump if the block being transmitted is
3957            JR   Z,#396B,GET_NBUFF   the expected one.
3959            DEC  HL                  Accept also the previous block (already
395A            LD   A,H                 received, but 'response' has not
395B            OR   L                   reached transmitter).
395C            RET  NZ                  But refuse other blocks.
395D            CALL #396B,GET_NBUFF     Receive the block.
3960            DEC  (IX+13)             Decrease block number, i.e. 'ignore'
3963            JR   NC,#3968,GETNB_END  this block.
3965            DEC  (IX+14)
3968 GETNB_END  OR   1                   Return with Zero flag reset, so that
396A            RET                      the procedure is repeated.

Now follows the second routine, used to get the data block from the network.

396B GET_NBUFF  LD   A,(#1DF5)
396E            AND  A                   Send the 'response' code for the header
396F            CALL NZ,#3AB5,SEND_RESP  unless broadcasting.
3972            LD   A,(#1DFA)           Fetch data block length.
3975            AND  A
3976            JR   Z,#3999,STORE_LEN   Jump if the data block is empty.
3978            PUSH IX                  Make HL point to the start of the
397A            POP  HL                  channel.
397B            LD   DE,21
397E            ADD  HL,DE               Point to the start of the data buffer.
397F            PUSH HL
3980            LD   E,A                 E is holds the length.
3981            CALL #3A87,INPAK         Receive the data block.
3984            POP  HL
3985            RET  NZ                  Return if the network was inactive.
3986            LD   A,(#1DFA)           Load the loop variable with the length
3989            LD   B,A                 of the received block.
398A            LD   A,(#1DFB)           Fetch checksum of received block.
398D CHKS4      SUB  (HL)                Subtract current byte.
398E            INC  HL                  Point to next byte.
398F            DJNZ #398D,CHKS4         repeat for all bytes in the block.
3991            RET  NZ                  Return if the checksum is wrong.
3992            LD   A,(#1DF5)
3995            AND  A                   Send the 'response' code for  the  data
3996            CALL NZ,#3AB5,SEND_RESP  block, unless broadcasting.
3999 STORE_LEN  LD   A,(#1DFA)           Fetch data block length.
399C            LD   (IX+20),A           Store number of bytes in input buffer.
399F            INC  (IX+13)             Increment block number.
39A2            JR   NZ,#39A7,GETBF_END
39A4            INC  (IX+14)
39A7 GETBF_END  CP   A                   Return with Zero flag set to signal
39A8            RET                      'block successfully received'.

THE 'OPEN "N" CHANNEL' ROUTINE
The DISCiPLE doesn't support "n" channel use from BASIC. This routine creates a "n"
channel in the DISCiPLE's own RAM. The channel is used for network serving purposes.

39A9 OPEN_N     LD   A,(#1DDA)           Clear network bit of current control
39AC            AND  #7F                 port state.
39AE            LD   (#1DDA),A
39B1            LD   DE,#1E3D            Start of the channel area.
39B4            LD   HL,#39D4,N_CH_DATA  Start of "n" channel data.
39B7            LD   BC,11               Copy the 11 bytes channel data to the
39BA            LDIR                     channel area.
39BC            LD   A,(#1E01)           Fetch destination station number.
39BF            LD   (DE),A
39C0            INC  DE
39C1            LD   A,(#029C)           Fetch own station number from NSTAT.
39C4            LD   (DE),A
39C5            INC  DE
39C6            XOR  A
39C7            LD   (DE),A              Clear the remaining 262 bytes.
39C8            LD   H,D
39C9            LD   L,E
39CA            INC  DE
39CB            LD   BC,262
39CE            LDIR
39D0            LD   DE,#1E3D            Point to the start of the channel.
39D3            RET

THE '"N" CHANNEL DATA' TABLE
The '11' bytes that compose the initial part of a "N" channel are as follows:

39D4 N_CH_DATA  DEFW #0008               Main ROM 'output' routine.
39D6            DEFW #0008               Main ROM 'input' routine.
39D8            DEFB "N"                 Channel specifier.
39D9            DEFW #3877               DISCiPLE ROM 'output' routine.
39DB            DEFW #3819               DISCiPLE ROM 'input' routine.
39DD            DEFW 276                 Length of channel.

THE 'SEND EOF BLOCK' SUBROUTINE
This subroutine is used whenever the remaining buffer contents of the "n" channel have
to be sent as the "end of file" block.

39DF SEND_NEOF  LD   IX,#1E3D            Start of channel.
39E3            LD   A,(IX+16)           Fetch data block length.
39E6            AND  A
39E7            RET  Z                   Return if this is a 'read' channel.
39E8            LD   A,#01               Signal 'EOF packet'.
39EA            JP   #38B5,S_PACK_1      Send packet and exit.

THE 'NETWORK STATE' SUBROUTINE
This subroutine returns when the network is considered to be 'resting', i.e. when the
network line is inactive for 3-4 ms. The exact time is 'randomised' to prevent
Spectrums from claiming the network at the same time over and over again.

39ED NET_STATE  LD   A,R                 Get a 'random' value.
39EF            OR   #C0                 Allow only the range 192..255.
39F1            LD   B,A                 Pass it to the loop count variable.
39F2            CALL #39F8,CHK_REST      Check network state.
39F5            JR   C,#39ED,NET_STATE   Repeat until the network is resting, or
                                         SPACE is pressed.
39F7            RET                      Return when 'ready to claim'.

THE 'CHECK_RESTING' SUBROUTINE
This subroutine checks the state of the network and returns with carry reset if it is
inactive for a 'sufficient' time determined by the value passed in the B register
((B * 54) - 22) T cycles).

39F8 CHK_REST   LD   A,#7F               First check SPACE key.
39FA            IN   A,(254)
39FC            RRCA
39FD            JR   NC,#3A39,NET_BREAK  Give an error if it is pressed.
39FF MAKESURE   PUSH BC                  Wait 21 T cycles.
3A00            POP  BC
3A01            IN   A,(31)              Check network state.
3A03            CPL                      Invert the bits.
3A04            RLCA                     Only bit 7. Return if the network is
3A05            RET  C                   already claimed by another Spectrum.
3A06            DJNZ #39FF,MAKESURE      Repeat the test.
3A08            RET                      Return with Carry reset when network is
                                         resting.

THE 'WAIT_SCOUT' SUBROUTINE
This subroutine is used to identify a SCOUT leader from the network. This is done by
checking the network line for about 7000 T cycles, to prove whether it is resting.
After this, the network is examined until it is active. At this point, the SCOUT is
identified. The subroutine returns with the Carry flag reset if 'time-out' has
occurred and no SCOUT has been identified. Remember that there are no 'time-outs' when
broadcasting.

3A09 WT_SCOUT   LD   HL,450              Set a counter.
3A0C CLAIMED    LD   B,128               This constant allows the network to be
                                         tested for 6890 T cycles.
3A0E            CALL #39F8,CHK_REST      Check network state.
3A11            JR   NC,#3A20,WT_SYNC    Jump for waiting the SCOUT.
3A13            DEC  HL                  Loop again if the network is active,
3A14            DEC  HL                  until the counter reaches zero.
3A15            LD   A,H
3A16            OR   L
3A17            JR   NZ,#3A0C,CLAIMED
3A19            LD   A,(IX+11)           There is no 'time-out' when
3A1C            AND  A                   broadcasting.
3A1D            JR   Z,#3A0C,CLAIMED
3A1F            RET                      Carry set signals 'time-out'.

Now the SCOUT pulse is waited for.

3A20 WT_SYNC    IN   A,(31)              Read the network line.
3A22            CPL                      Invert the bits.
3A23            RLCA                     Only bit 7.
3A24            JR   C,#3A3F,SCOUT_END   Jump if the SCOUT is identified.
3A26            LD   A,#7F               Check the SPACE key.
3A28            IN   A,(254)
3A2A            RRCA
3A2B            JR   NC,#3A39,NET_BREAK  Give an error if it is pressed.
3A2D            DEC  HL                  Decrease counter.
3A2E            LD   A,H
3A2F            OR   L
3A30            JR   NZ,#3A20,WT_SYNC    Repeat until it reaches zero.
3A32            LD   A,(IX+11)
3A35            AND  A                   Again there is no 'time-out' when
3A36            JR   Z,#3A20,WT_SYNC     broadcasting.
3A38            RET                      Carry reset signals 'time-out'.

THE 'NETWORK BREAK' ROUTINE
Whenever the SPACE key is pressed during a network operation, the 'BREAK requested'
error is given.

3A39 NET_BREAK  CALL #3B02,REST_BORD     Restore border colour.
3A3C            JP   #2926,REP_3         Give the error.

THE 'WAIT SCOUT' SUBROUTINE CONTINUED
When a SCOUT has been identified, the routine waits until it is finished.

3A3F SCOUT_END  LD   L,9                 Set a counter.
3A41 LP_SCOUT   DEC  L                   Decrease it.
3A42            SCF                      Return with Carry set (to signal
3A43            RET  Z                   'SCOUT identified') when the counter
3A44            LD   B,14                reaches zero.
3A46 DELAY_SC   DJNZ #3A46,DELAY_SC      Wait a while.
3A48            JR   #3A41,LP_SCOUT      Go back into the loop.

THE 'SEND_SCOUT' SUBROUTINE
This is the opposite of the preceding routine; the SCOUT leader followed by an 8-bit
station number, is sent over the network. After having sent every bit, a test is made
to see if the network has the expected state from the current bit value; if any error
is found, then the whole procedure is repeated.

3A4A SEND_SC    CALL #39ED,NET_STATE     Wait until the network is resting.
3A4D            LD   C,31                Control port.
3A4F            LD   A,(#1DDA)           Fetch current state of control port.
3A52            OR   #80                 Set network bit.
3A54            LD   H,A                 H holds port 31 value.
3A55            LD   L,9                 Bit counter.
3A57            LD   A,(#029C)           Fetch own station number from NSTAT.
3A5A            CPL                      Invert the bits.
3A5B            LD   E,A
3A5C            IN   A,(31)
3A5E            RLCA                     Start again if some data is found on
3A5F            JR   NC,#3A4A,SEND_SC    the network line.
3A61 ALL_BITS   OUT  (C),H               Send a bit.
3A63            LD   D,0
3A65            RL   H                   Save the bit in D.
3A67            RR   D
3A69            RLC  E                   Rotate 'station number' left.
3A6B            RR   H                   Bit 7 of station number goes into bit 7
                                         of H.
3A6D            LD   B,7                 Wait 93 T cycles.
3A6F S_SC_DEL   DJNZ #3A6F,S_SC_DEL
3A71            IN   A,(31)              Read the network.
3A73            AND  #80                 Only bit 7.
3A75            CP   D                   Repeat again the procedure if the
3A76            JR   Z,#3A4A,SEND_SC     network does not have the right state
                                         from the current bit value.
3A78            DEC  L                   Decrease bit counter.
3A79            JR   NZ,#3A61,ALL_BITS   Send all bits.
3A7B            LD   A,(#1DDA)           Make network inactive.
3A7E            OUT  (31),A
3A80            LD   A,1
3A82            LD   B,13                Wait 171 T cycles before returning.
3A84 END_S_DEL  DJNZ #3A84,END_S_DEL
3A86            RET

THE 'INPAK' SUBROUTINE
This basic subroutine is used to receive from the network a block of bytes. On entry,
HL must hold the address from which the bytes will be loaded, while E must hold the
length of the block. The subroutine returns with the Zero flag reset if the network is
found inactive and no data has been read. The bits are read every 40 T cycles.

3A87 INPAK      LD   B,255               Set a counter.
3A89 N_ACTIVE   IN   A,(31)              Read the network.
3A8B            RLA                      Only bit 7.
3A8C            JR   NC,#3A92,INPAK_2    Jump if found active.
3A8E            DJNZ #3A89,N_ACTIVE      Otherwise try again.
3A90            INC  B                   Return with Zero flag reset to indicate
3A91            RET                      'network inactive'.

Now the block is received.

3A92 INPAK_2    LD   B,E                 B holds the length of the block.
3A93            LD   A,0                 Balance the CPL instruction below.
3A95 INPAK_L    LD   E,#80               Set a marker into bit 7.
3A97            OUT  (59),A              Set NET-WAIT line. (WAIT if NET=1)
3A99            NOP                      Wait 48 T cycles at the start of each
3A9A            NOP                      byte.
3A9B            INC  IX
3A9D            DEC  IX
3A9F            INC  IX
3AA1            DEC  IX
3AA3 UNTIL_MK   LD   A,0                 Wait 7 T cycles.
3AA5            IN   A,(31)              Get a bit into the
3AA7            RLA                      Carry flag.
3AA8            RR   E                   Shift the bit into E.
3AAA            JP   NC,#3AA3,UNTIL_MK   Repeat for 8 bits.
3AAD            LD   A,E                 Because of the inverting port in the
3AAE            CPL                      DISCiPLE the byte has to be inverted.
3AAF            LD   (HL),A              Store the received byte.
3AB0            INC  HL                  Next location.
3AB1            DJNZ #3A95,INPAK_L       Get next byte.
3AB3            CP   A                   Return with Zero flag set to signal
3AB4            RET                      'successfully read'.

THE 'SEND RESPONSE BYTE' SUBROUTINE
A 'response byte' is simply a byte 1 that is sent over the network to confirm that
some data has been successfully received.

3AB5 SEND_RESP  LD   A,1                 This is the response byte.
3AB7            LD   HL,#1DF4            Store it.
3ABA            LD   (HL),A
3ABB            LD   E,A                 A 'single byte' is to be sent.

The subroutine continues into 'OUTPAK' below.

THE 'OUTPAK' SUBROUTINE
This is the opposite to the 'INPAK' subroutine and thus, is used to send over the
network a block of bytes. Again, on entry HL must hold the address from which the
block is stored, and E must hold its length. Initially a leader (length 98 T cycles)
is sent, followed by each byte, with an initial 'start' period, and then the 8 bits
(each 40 T cycles).

3ABC OUTPAK     LD   A,(#1DDA)           Reset network line of current state of
3ABF            AND  #7F                 control port.
3AC1            LD   (#1DDA),A
3AC4            OR   #80                 Begin with a 'start' leader.
3AC6            OUT  (31),A
3AC8            LD   B,3                 Insert the required delay.
3ACA DEL_O_1    DJNZ #3ACA,DEL_O_1
3ACC OUTPAK_L   LD   C,(HL)              C holds the byte to be sent.
3ACD            INC  HL                  Next location.
3ACE            AND  #7F                 The start bit is low (high on net).
3AD0            LD   B,9                 '9' bits to be sent (start, data).
3AD2            JR   #3AD8,UNT_MARK_2    Send start bit.

Now a byte is send over the network.

3AD4 UNT_MARK_1 RLA                      Rotate bit into A while keeping the
3AD5            SRL  C                   other control bits intact.
3AD7            RRA
3AD8 UNT_MARK_2 OUT  (31),A              Send the bit.
3ADA            DJNZ #3AD4,UNT_MARK_1    Loop for all bits.
3ADC            RLA
3ADD            SCF                      The stop bit is high (low on net).
3ADE            RET  NC                  Wait 5 T cycles
3ADF            RR   A                   Extra 4 T cycles (RRA is 4, RR A is 8).
3AE1            OUT  (31),A              Send the stop bit.
3AE3            PUSH HL                  Wait 44 T cycles.
3AE4            POP  HL
3AE5            PUSH HL
3AE6            POP  HL
3AE7            DEC  E                   Decrease block length.
3AE8            JP   NZ,#3ACC,OUTPAK_L   Loop until all bytes have been sent.
3AEB            LD   A,(#1DDA)
3AEE            OUT  (31),A              Make the network inactive before
3AF0            RET                      returning.

THE 'NET_BORDER' SUBROUTINE
This subroutine sets the border colour at "station MOD 8" and stores the state of
the IFF at address #1ACC. It returns with the interrupts disabled.

3AF1 NET_BORD   LD   A,(#029C)           Fetch own station number from NSTAT.
3AF4            AND  #07                 Keep only bits 0-2.
3AF6            OUT  (254),A             Set border colour.
3AF8            LD   A,I                 Obtain interrupt status.
3AFA            PUSH AF
3AFB            EX   (SP),HL             Move it to HL and
3AFC            LD   (#1ACC),HL          store it into IFF.
3AFF            POP  HL                  Restore HL.
3B00            DI                       Exit with interrupts disabled.
3B01            RET

THE 'RESTORE BORDER COLOUR' SUBROUTINE
This is the opposite to the 'NET_BORD' subroutine and thus, is used to restore the
BORDER colour and the state of the IFF. Note that because of a bug in the Z80 itself
the interrupts can be disabled although they were enabled when the "LD A,I" above was
executed. (See NOTE before #3ECE.)

3B02 REST_BORD  LD   A,(23624)           Get BORDCR (lower screen attribute).
3B05            AND  #38                 Only the BORDER bits.
3B07            RRCA                     Rotate colour into bits 0-2.
3B08            RRCA
3B09            RRCA
3B0A            OUT  (254),A             Restore colour.
3B0C            PUSH HL
3B0D            LD   HL,(#1ACC)          Fetch previous state of the IFF.
3B10            EX   (SP),HL
3B11            POP  AF
3B12            JP   PO,#3B16,R_B_EXIT   Jump if interrupts were disabled.
3B15            EI                       Otherwise enable interrupts.
3B16 R_B_EXIT   RET                      Exit.
Previous Next Contents Index