diff options
Diffstat (limited to 'docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/EAD9')
-rw-r--r-- | docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/EAD9 | 1 |
1 files changed, 1 insertions, 0 deletions
diff --git a/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/EAD9 b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/EAD9 new file mode 100644 index 0000000..6682621 --- /dev/null +++ b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/EAD9 @@ -0,0 +1 @@ +OS SERIES 8
GEOFF COX
*************************************************************************
* *
* OSBYTE &F7 (247) INTERCEPT BREAK *
* *
*************************************************************************
EAD9 LDA &0287 ;get BREAK vector code
EADC EOR #&4C ;produces 0 if JMP not in &287
EADE BNE &EAF3 ;if not goto EAF3
EAE0 JMP &0287 ;else jump to user BREAK code
*************************************************************************
* *
* OSBYTE &90 (144) *TV *
* *
*************************************************************************
;X=display delay
;Y=interlace flag
EAE3 LDA &0290 ;VDU vertical adjustment
EAE6 STX &0290 ;store new value
EAE9 TAX ;put old value in X
EAEA TYA ;put interlace flag in A
EAEB AND #&01 ;maximum value =1
EAED LDY &0291 ;get old value into Y
EAF0 STA &0291 ;put new value into A
EAF3 RTS ;and Exit
*************************************************************************
* *
* OSBYTE &93 (147) WRITE TO FRED *
* *
*************************************************************************
;X is offset within page
;Y is byte to write
EAF4 TYA ;
EAF5 STA &FC00,X ;
EAF8 RTS ;
*************************************************************************
* *
* OSBYTE &95 (149) WRITE TO JIM *
* *
*************************************************************************
;X is offset within page
;Y is byte to write
;
EAF9 TYA ;
EAFA STA &FD00,X ;
EAFD RTS ;
*************************************************************************
* *
* OSBYTE &97 (151) WRITE TO SHEILA *
* *
*************************************************************************
;X is offset within page
;Y is byte to write
EAFE TYA ;
EAFF STA &FE00,X ;
EB02 RTS ;
****************** Silence a sound channel *******************************
;X=channel number
EB03 LDA #&04 ;mark end of release phase
EB05 STA &0808,X ;to channel X
EB08 LDA #&C0 ;load code for zero volume
****** if sound not disabled set sound generator volume ******************
EB0A STA &0804,X ;store A to give basic sound level of Zero
EB0D LDY &0262 ;get sound output/enable flag
EB10 BEQ &EB14 ;if sound enabled goto EB14
EB12 LDA #&C0 ;else load zero sound code
EB14 SEC ;set carry
EB15 SBC #&40 ;subtract &40
EB17 LSR ;divide by 8
EB18 LSR ;to get into bits 0 - 3
EB19 LSR ;
EB1A EOR #&0F ;invert bits 0-3
EB1C ORA &EB3C,X ;get channel number into top nybble
EB1F ORA #&10 ;
EB21 PHP ;
EB22 SEI ;disable interrupts
EB23 LDY #&FF ;System VIA port A all outputs
EB25 STY &FE43 ;set
EB28 STA &FE4F ;output A on port A
EB2B INY ;Y=0
EB2C STY &FE40 ;enable sound chip
EB2F LDY #&02 ;set and
EB31 DEY ;execute short delay
EB32 BNE &EB31 ;
EB34 LDY #&08 ;then disable sound chip again
EB36 STY &FE40 ;
EB39 LDY #&04 ;set delay
EB3B DEY ;and loop delay
EB3C BNE &EB3B ;
EB3E PLP ;get back flags
EB3F RTS ;and exit
*******: Sound parameters look up table **********************************
EB40 DB &E0,&C0,&A0,&80
EB44 JMP &EC59 ;just to allow relative branches in early part
;of sound interrupt routine
*************************************************************************
* *
* PROCESS SOUND INTERRUPT *
* *
*************************************************************************
EB47 LDA #&00 ;
EB49 STA &083B ;zero number of channels on hold for sync
EB4C LDA &0838 ;get number of channels required for sync
EB4F BNE &EB57 ;if this <>0 then EB57
EB51 INC &083B ;else number of chanels on hold for sync =1
EB54 DEC &0838 ;number of channels required for sync =255
EB57 LDX #&08 ;set loop counter
EB59 DEX ;loop
EB5A LDA &0800,X ;get value of &800 +offset (sound queue occupancy)
EB5D BEQ &EB44 ;if 0 goto EC59 no sound this channel
EB5F LDA &02CF,X ;else get buffer busy flag
EB62 BMI &EB69 ;if negative (buffer empty) goto EB69
EB64 LDA &0818,X ;else if duration count not zer0
EB67 BNE &EB6C ;goto EB6C
EB69 JSR &EC6B ;check and pick up new sound if required
EB6C LDA &0818,X ;if duration count 0
EB6F BEQ &EB84 ;goto EB84
EB71 CMP #&FF ;else if it is &FF (infinite duration)
EB73 BEQ &EB87 ;go onto EB87
EB75 DEC &081C,X ;decrement 10 mS count
EB78 BNE &EB87 ;and if 0
EB7A LDA #&05 ;reset to 5
EB7C STA &081C,X ;to give 50 mSec delay
EB7F DEC &0818,X ;and decrement main counter
EB82 BNE &EB87 ;if not zero then EB87
EB84 JSR &EC6B ;else check and get nw sound
EB87 LDA &0824,X ;if step progress counter is 0 no envelope involved
EB8A BEQ &EB91 ;so jump to EB91
EB8C DEC &0824,X ;else decrement it
EB8F BNE &EB44 ;and if not zero go on to EC59
EB91 LDY &0820,X ;get envelope data offset from (8C0)
EB94 CPY #&FF ;if 255 no envelope set so
EB96 BEQ &EB44 ;goto EC59
EB98 LDA &08C0,Y ;else get get step length
EB9B AND #&7F ;zero repeat bit
EB9D STA &0824,X ;and store it
EBA0 LDA &0808,X ;get phase counter
EBA3 CMP #&04 ;if release phase completed
EBA5 BEQ &EC07 ;goto EC07
EBA7 LDA &0808,X ;else start new step by getting phase
EBAA CLC ;
EBAB ADC &0820,X ;add it to interval multiplier
EBAE TAY ;transfer to Y
EBAF LDA &08CB,Y ;and get target value base for envelope
EBB2 SEC ;
EBB3 SBC #&3F ;
EBB5 STA &083A ;store modified number as current target amplitude
EBB8 LDA &08C7,Y ;get byte from envelope store
EBBB STA &0839 ;store as current amplitude step
EBBE LDA &0804,X ;get base volumelevel
EBC1 PHA ;save it
EBC2 CLC ;clear carry
EBC3 ADC &0839 ;add to current amplitude step
EBC6 BVC &EBCF ;if no overflow
EBC8 ROL ;double it Carry = bit 7
EBC9 LDA #&3F ;if bit =1 A=&3F
EBCB BCS &EBCF ;into &EBCF
EBCD EOR #&FF ;else toggle bits (A=&C0)
;at this point the BASIC volume commands are converted
; &C0 (0) to &38 (-15) 3 times, In fact last 3 bits
;are ignored so &3F represents -15
EBCF STA &0804,X ;store in current volume
EBD2 ROL ;multiply by 2
EBD3 EOR &0804,X ;if bits 6 and 7 are equal
EBD6 BPL &EBE1 ;goto &EBE1
EBD8 LDA #&3F ;if carry clear A=&3F (maximum)
EBDA BCC &EBDE ;or
EBDC EOR #&FF ;&C0 minimum
EBDE STA &0804,X ;and this is stored in current volume
EBE1 DEC &0839 ;decrement amplitude change per step
EBE4 LDA &0804,X ;get volume again
EBE7 SEC ;set carry
EBE8 SBC &083A ;subtract target value
EBEB EOR &0839 ;negative value undicates correct trend
EBEE BMI &EBF9 ;so jump to next part
EBF0 LDA &083A ;else enter new phase
EBF3 STA &0804,X ;
EBF6 INC &0808,X ;
EBF9 PLA ;get the old volume level
EBFA EOR &0804,X ;and compare with the old
EBFD AND #&F8 ;
EBFF BEQ &EC07 ;if they are the same goto EC07
EC01 LDA &0804,X ;else set new level
EC04 JSR &EB0A ;via EB0A
EC07 LDA &0810,X ;get absolute pitch value
EC0A CMP #&03 ;if it =3
EC0C BEQ &EC59 ;skip rest of loop as all sections are finished
EC0E LDA &0814,X ;else if 814,X is not 0 current section is not
;complete
EC11 BNE &EC3D ;so EC3D
EC13 INC &0810,X ;else implement a section change
EC16 LDA &0810,X ;check if its complete
EC19 CMP #&03 ;if not
EC1B BNE &EC2D ;goto EC2D
EC1D LDY &0820,X ;else set A from
EC20 LDA &08C0,Y ;&820 and &8C0 (first envelope byte)
EC23 BMI &EC59 ;if negative there is no repeat
EC25 LDA #&00 ;else restart section sequence
EC27 STA &0830,X ;
EC2A STA &0810,X ;
EC2D LDA &0810,X ;get number of steps in new section
EC30 CLC ;
EC31 ADC &0820,X ;
EC34 TAY ;
EC35 LDA &08C4,Y ;
EC38 STA &0814,X ;set in 814+X
EC3B BEQ &EC59 ;and if 0 then EC59
EC3D DEC &0814,X ;decrement
EC40 LDA &0820,X ;and pick up rate of pitch change
EC43 CLC ;
EC44 ADC &0810,X ;
EC47 TAY ;
EC48 LDA &08C1,Y ;
EC4B CLC ;
EC4C ADC &0830,X ;add to rate of differential pitch change
EC4F STA &0830,X ;and save it
EC52 CLC ;
EC53 ADC &080C,X ;ad to base pitch
EC56 JSR &ED01 ;and set new pitch
EC59 CPX #&04 ;if X=4 (last channel)
EC5B BEQ &EC6A ;goto EC6A (RTS)
EC5D JMP &EB59 ;else do loop again
EC60 LDX #&08 ;X=7 again
EC62 DEX ;loop
EC63 JSR &ECA2 ;clear channel
EC66 CPX #&04 ;if not 4
EC68 BNE &EC62 ;do it again
EC6A RTS ;and return
;
EC6B LDA &0808,X ;check for last channel
EC6E CMP #&04 ;is it 4 (release complete)
EC70 BEQ &EC77 ;if so EC77
EC72 LDA #&03 ;else mark release in progress
EC74 STA &0808,X ;and store it
EC77 LDA &02CF,X ;is buffer not empty
EC7A BEQ &EC90 ;if so EC90
EC7C LDA #&00 ;else mark buffer not empty
EC7E STA &02CF,X ;an store it
EC81 LDY #&04 ;loop counter
EC83 STA &082B,Y ;zero sync bytes
EC86 DEY ;
EC87 BNE &EC83 ;until Y=0
EC89 STA &0818,X ;zero duration count
EC8C DEY ;and set sync count to
EC8D STY &0838 ;&FF
EC90 LDA &0828,X ;get synchronising flag
EC93 BEQ &ECDB ;if its 0 then ECDB
EC95 LDA &083B ;else get number of channels on hold
EC98 BEQ &ECD0 ;if 0 then ECD0
EC9A LDA #&00 ;else
EC9C STA &0828,X ;zero note length interval
EC9F JMP &ED98 ;and goto ED98
ECA2 JSR &EB03 ;silence the channel
ECA5 TYA ;Y=0 A=Y
ECA6 STA &0818,X ;zero main count
ECA9 STA &02CF,X ;mark buffer not empty
ECAC STA &0800,X ;mark channel dormant
ECAF LDY #&03 ;loop counter
ECB1 STA &082C,Y ;zero sync flags
ECB4 DEY ;
ECB5 BPL &ECB1 ;
ECB7 STY &0838 ;number of channels to &FF
ECBA BMI &ED06 ;jump to ED06 ALWAYS
ECBC PHP ;save flags
ECBD SEI ;and disable interrupts
ECBE LDA &0808,X ;check for end of release
ECC1 CMP #&04 ;
ECC3 BNE &ECCF ;and if not found ECCF
ECC5 JSR &E45B ;elseexamine buffer
ECC8 BCC &ECCF ;if not empty ECCF
ECCA LDA #&00 ;else mark channel dormant
ECCC STA &0800,X ;
ECCF PLP ;get back flags
ECD0 LDY &0820,X ;if no envelope 820=&FF
ECD3 CPY #&FF ;
ECD5 BNE &ECDA ;then terminate sound
ECD7 JSR &EB03 ;via EB03
ECDA RTS ;else return
;
************ Synchronise sound routines **********************************
ECDB JSR &E45B ;examine buffer if empty carry set
ECDE BCS &ECBC ;
ECE0 AND #&03 ;else examine next word if>3 or 0
ECE2 BEQ &EC9F ;goto ED98 (via EC9F)
ECE4 LDA &0838 ;else get synchronising count
ECE7 BEQ &ECFE ;in 0 (complete) goto ECFE
ECE9 INC &0828,X ;else set sync flag
ECEC BIT &0838 ;if 0838 is +ve S has already been set so
ECEF BPL &ECFB ;jump to ECFB
ECF1 JSR &E45B ;else get first byte
ECF4 AND #&03 ;mask bits 0,1
ECF6 STA &0838 ;and store result
ECF9 BPL &ECFE ;Jump to ECFE (ALWAYS!!)
ECFB DEC &0838 ;decrement 0838
ECFE JMP &ECD0 ;and silence the channel if envelope not in use
************ Pitch setting ***********************************************
ED01 CMP &082C,X ;If A=&82C,X then pitch is unchanged
ED04 BEQ &ECDA ;then exit via ECDA
ED06 STA &082C,X ;store new pitch
ED09 CPX #&04 ;if X<>4 then not noise so
ED0B BNE &ED16 ;jump to ED16
*********** Noise setting ************************************************
ED0D AND #&0F ;convert to chip format
ED0F ORA &EB3C,X ;
ED12 PHP ;save flags
ED13 JMP &ED95 ;and pass to chip control routine at EB22 via ED95
ED16 PHA ;
ED17 AND #&03 ;
ED19 STA &083C ;lose eigth tone surplus
ED1C LDA #&00 ;
ED1E STA &083D ;
ED21 PLA ;get back A
ED22 LSR ;divide by 12
ED23 LSR ;
ED24 CMP #&0C ;
ED26 BCC &ED2F ;
ED28 INC &083D ;store result
ED2B SBC #&0C ;with remainder in A
ED2D BNE &ED24 ;
;at this point 83D defines the Octave
;A the semitone within the octave
ED2F TAY ;Y=A
ED30 LDA &083D ;get octave number into A
ED33 PHA ;push it
ED34 LDA &EDFB,Y ;get byte from look up table
ED37 STA &083D ;store it
ED3A LDA &EE07,Y ;get byte from second table
ED3D PHA ;push it
ED3E AND #&03 ;keep two LS bits only
ED40 STA &083E ;save them
ED43 PLA ;pull second table byte
ED44 LSR ;push hi nybble into lo nybble
ED45 LSR ;
ED46 LSR ;
ED47 LSR ;
ED48 STA &083F ;store it
ED4B LDA &083D ;get back octave number
ED4E LDY &083C ;adjust for surplus eighth tones
ED51 BEQ &ED5F ;
ED53 SEC ;
ED54 SBC &083F ;
ED57 BCS &ED5C ;
ED59 DEC &083E ;
ED5C DEY ;
ED5D BNE &ED53 ;
ED5F STA &083D ;
ED62 PLA ;
ED63 TAY ;
ED64 BEQ &ED6F ;
ED66 LSR &083E ;
ED69 ROR &083D ;
ED6C DEY ;
ED6D BNE &ED66 ;
ED6F LDA &083D ;
ED72 CLC ;
ED73 ADC &C43D,X ;
ED76 STA &083D ;
ED79 BCC &ED7E ;
ED7B INC &083E ;
ED7E AND #&0F ;
ED80 ORA &EB3C,X ;
ED83 PHP ;push P
ED84 SEI ;bar interrupts
ED85 JSR &EB21 ;set up chip access 1
ED88 LDA &083D ;
ED8B LSR &083E ;
ED8E ROR ;
ED8F LSR &083E ;
ED92 ROR ;
ED93 LSR ;
ED94 LSR ;
ED95 JMP &EB22 ;set up chip access 2 and return
**************** Pick up and interpret sound buffer data *****************
ED98 PHP ;push flags
ED99 SEI ;disable interrupts
ED9A JSR &E460 ;read a byte from buffer
ED9D PHA ;push A
ED9E AND #&04 ;isolate H bit
EDA0 BEQ &EDB7 ;if 0 then EDB7
EDA2 PLA ;get back A
EDA3 LDY &0820,X ;if &820,X=&FF
EDA6 CPY #&FF ;envelope is not in use
EDA8 BNE &EDAD ;
EDAA JSR &EB03 ;so call EB03 to silence channel
EDAD JSR &E460 ;clear buffer of redundant data
EDB0 JSR &E460 ;and again
EDB3 PLP ;get back flags
EDB4 JMP &EDF7 ;set main duration count using last byte from buffer
EDB7 PLA ;get back A
EDB8 AND #&F8 ;zero bits 0-2
EDBA ASL ;put bit 7 into carry
EDBB BCC &EDC8 ;if zero (envelope) jump to EDC8
EDBD EOR #&FF ;invert A
EDBF LSR ;shift right
EDC0 SEC ;
EDC1 SBC #&40 ;subtract &40
EDC3 JSR &EB0A ;and set volume
EDC6 LDA #&FF ;A=&FF
EDC8 STA &0820,X ;get envelope no.-1 *16 into A
EDCB LDA #&05 ;set duration sub-counter
EDCD STA &081C,X ;
EDD0 LDA #&01 ;set phase counter
EDD2 STA &0824,X ;
EDD5 LDA #&00 ;set step counter
EDD7 STA &0814,X ;
EDDA STA &0808,X ;and envelope phase
EDDD STA &0830,X ;and pitch differential
EDE0 LDA #&FF ;
EDE2 STA &0810,X ;set step count
EDE5 JSR &E460 ;read pitch
EDE8 STA &080C,X ;set it
EDEB JSR &E460 ;read buffer
EDEE PLP ;
EDEF PHA ;save duration
EDF0 LDA &080C,X ;get back pitch value
EDF3 JSR &ED01 ;and set it
EDF6 PLA ;get back duration
EDF7 STA &0818,X ;set it
EDFA RTS ;and return
********************* Pitch look up table 1*****************************
EDFB DB &F0
EDFC DB &B7
EDFD DB &82
EDFE DB &4F
EDFF DB &20
EE00 DB &F3
EE01 DB &C8
EE02 DB &A0
EE03 DB &7B
EE04 DB &57
EE05 DB &35
EE06 DB &16
********************* Pitch look up table 2 *****************************
EE07 DB &E7
EE08 DB &D7
EE09 DB &CB
EE0A DB &C3
EE0B DB &B7
EE0C DB &AA
EE0D DB &A2
EE0E DB &9A
EE0F DB &92
EE10 DB &8A
EE11 DB &82
EE12 DB &7A
*********: set current filing system ROM/PHROM **************************
EE13 LDA #&EF ;get ROM
EE15 STA &F5 ;store it
EE17 RTS ;return
********** Get byte from data ROM ***************************************
EE18 LDX #&0D ;X=13
EE1A INC &F5 ;
EE1C LDY &F5 ;get Rom
EE1E BPL &EE59 ;if +ve it's a sideways ROM else it's a PHROM
EE20 LDX #&00 ;PHROM
EE22 STX &F7 ;set address pointer in PHROM
EE24 INX ;
EE25 STX &F6 ;to 0001
EE27 JSR &EEBB ;pass info to speech processor
EE2A LDX #&03 ;X=3
EE2C JSR &EE62 ;check for speech processor and output until
;it reports, read byte from ROM
EE2F CMP &DF0C,X ;if A<> DF0C+X then EE18 (DF0C = (C))
EE32 BNE &EE18 ;
EE34 DEX ;else decrement X
EE35 BPL &EE2C ;and do it again
EE37 LDA #&3E ;
EE39 STA &F6 ;get noe lo byte address
EE3B JSR &EEBB ;pass info to speech processor
EE3E LDX #&FF ;
EE40 JSR &EE62 ;check for speech proc. etc.
EE43 LDY #&08 ;
EE45 ASL ;
EE46 ROR &F7,X ;
EE48 DEY ;
EE49 BNE &EE45 ;
EE4B INX ;
EE4C BEQ &EE40 ;
EE4E CLC ;
EE4F BCC &EEBB ;
************ ROM SERVICE ************************************************
EE51 LDX #&0E ;
EE53 LDY &F5 ;if Y is negative (PHROM)
EE55 BMI &EE62 ;GOTO EE62
EE57 LDY #&FF ;else Y=255
EE59 PHP ;push flags
EE5A JSR &F168 ;offer paged rom service
EE5D PLP ;pull processor flags
EE5E CMP #&01 ;if A>0 set carry
EE60 TYA ;A=Y
EE61 RTS ;return
********* PHROM SERVICE *************************************************
;
EE62 PHP ;push processor flags
EE63 SEI ;disable interrupts
EE64 LDY #&10 ;Y=16
EE66 JSR &EE7F ;call EE7F (osbyte 159 write to speech processor
EE69 LDY #&00 ;Y=0
EE6B BEQ &EE84 ;Jump to EE84 (ALWAYS!!)
*************************************************************************
* *
* OSBYTE 158 read from speech processor *
* *
*************************************************************************
EE6D LDY #&00 ;Y=0 to set speech proc to read
EE6F BEQ &EE82 ;jump to EE82 always
;write A to speech processor as two nybbles
EE71 PHA ;push A
EE72 JSR &EE7A ;to write to speech processor
EE75 PLA ;get back A
EE76 ROR ;bring upper nybble to lower nybble
EE77 ROR ;by rotate right
EE78 ROR ;4 times
EE79 ROR ;
EE7A AND #&0F ;Y=lo nybble A +&40
EE7C ORA #&40 ;
EE7E TAY ;forming command for speech processor
*************************************************************************
* *
* OSBYTE 159 Write to speech processor *
* *
*************************************************************************
; on entry data or command in Y
EE7F TYA ;transfer command to A
EE80 LDY #&01 ;to set speech proc to write
;if Y=0 read speech processor
;if Y=1 write speech processor
EE82 PHP ;push flags
EE83 SEI ;disable interrupts
EE84 BIT &027B ;test for prescence of speech processor
EE87 BPL &EEAA ;if not there goto EEAA
EE89 PHA ;else push A
EE8A LDA &F075,Y ;
EE8D STA &FE43 ;set DDRA of system VIA to give 8 bit input (Y=0)
;or 8 bit output (Y=1)
EE90 PLA ;get back A
EE91 STA &FE4F ;and send to speech chip
EE94 LDA &F077,Y ;output Prt B of system VIA
EE97 STA &FE40 ;to select read or write (dependent on Y)
EE9A BIT &FE40 ;loop until
EE9D BMI &EE9A ;speech proceessor reports ready (bit 7 Prt B=0)
EE9F LDA &FE4F ;read speech processor data if input selected
EEA2 PHA ;push A
EEA3 LDA &F079,Y ;reset speech
EEA6 STA &FE40 ;processor
EEA9 PLA ;get back A
EEAA PLP ;get back flags
EEAB TAY ;transfer A to Y
EEAC RTS ;and exit routine
;
EEAD LDA &03CB ;set rom displacement pointer
EEB0 STA &F6 ;in &F6
EEB2 LDA &03CC ;
EEB5 STA &F7 ;And &F7
EEB7 LDA &F5 ;if F5 is +ve ROM is selected so
EEB9 BPL &EED9 ;goto EED9
EEBB PHP ;else push processor
EEBC SEI ;disable interrupts
EEBD LDA &F6 ;get lo displacement
EEBF JSR &EE71 ;pass two nyblles to speech proc.
EEC2 LDA &F5 ;&FA=&F5
EEC4 STA &FA ;
EEC6 LDA &F7 ;get hi displacement value
EEC8 ROL ;replace two most significant bits of A
EEC9 ROL ;by 2 LSBs of &FA
EECA LSR &FA ;
EECC ROR ;
EECD LSR &FA ;
EECF ROR ;
EED0 JSR &EE71 ;pass two nybbles to speech processor
EED3 LDA &FA ;FA has now been divided by 4 so pass
EED5 JSR &EE7A ;lower nybble to speech proc.
EED8 PLP ;get back flags
EED9 RTS ;and Return
;
\ No newline at end of file |