< Previous  |  Contents  |  Next >

E: Tube Host Code Source    

Tube Host Code

No listings or specifications were available for any of the code examples shown here, therefore they were saved from a live 512 system and disassembled. This has two implications. Firstly, they should be accurate, and secondly there is unfortunately no way to determine the precise purpose of some areas of data storage or some parts of the code in detail for all circumstances.

In the original disassembly there were short sections of code in page 6, now omitted, which were not called from any of the tube routines here or elsewhere. Direct calls to ROM addresses within the code tend to suggest that they were incidental to tube operation. If they have any relevant function it is possible that these portions of code are used only during initial machine power-up and are subsequently overwritten. More probable however, is that they are downloaded simply because they just happen to occupy the last few bytes of that page, the bulk of which is relevant and remains.

The code shown below, which in essence and function is common to all BBC micro second processor support, consists of two parts. The first resides in page zero and is called at &16 on execution of a BRK instraction and is used to inform the co-processor of host software errors. During tube initialisation, when a hard break has been issued, if the tube is found to be active the break vector at &202 is therefore re-directed to point to &16 in zero page.

The second portion of the code is located in pages 4,5 and 6, normally reserved for the host's current language, which of course is irrelevant when running a co-processor. Page 7, normally the input stream buffer, is used as a 256-byte data buffer for various transfers and calls. This code calls the zero page code at both location &32 and &36. In turn it is itself called by the zero page code. The entry addresses for this depend on the function called for by the co-processor. This is indicated by a single hex digit, detected within the idle loop at &36.

This is where the 6502 'waits' in the host code for co-processor dialogue when there is no current activity. The code entry points for the various function calls are located in a table of twelve addresses at &500 in both examples.

The two sections of the code are downloaded from the filing system ROM, provided that it includes support for the tube. The original DFS 0.9 did not, but all Acorn disc filing systens since DNFS 1.2, including the 1770 DFS and all versions of ADFS have, as have the alternatives from Solidisk and more recent versions from Watford Electronics. No Watford code has been checked, but like the STL version which has, it is likely to be identical byte for byte with the Acorn code, and the entry points, functions and returned values must be.

Note that the ADFS in the Master's 'Mega-ROM' is different to that in the stand-alone ADFS ROMs used by model B or B+ machines. The Master version of this code is therefore shown in the second example of the host code. The major differences are a slight 'shuffling' of the order of several of the routines and the saving of a few bytes of memory by using a 2-byte 65C02 relative branch instruction (BRA) instead of a three byte absolute JMP.

These differences are not in the interests of efficiency, as in places this technique is clearly less efficient. It is rather a by-product of the fact that Acorn's ADFS code is produced by a macro assembler rather than being hand-coded, with the result that some of the generated code is highly stylised. As the entry points in the code must remain fixed (ie 6502.SYS does not configure itself to suit the host type or its MOS) any bytes saved are wasted, as shown at &47h. Also, for example at &65F, there are no less than 2 relative branches followed by an absolute jump where only an absolute JMP would normally be used.

For both examples of this code shown here the functions are substantially similar, therefore to aid comparison the same labels have been used where direct equivalents of operations exist. The latest incarnation of the Master's 'Mega-ROM', released in November 1989 (since these disassemblies were produced and too late for inclusion) is largely similar to the Master version shown and 'hackers' should have little trouble in dis-assembling and understanding the new code. For all versions of the code the entry points, the functions, temporary workspace and zero page code are the same.

For a 512, regardless of host type, additional functions are required over and above those of a 6502 co-processor. In the case of the 512 therefore, extra code is loaded from the DOS boot disc. Initially this is transferred across the tube to the 512 from the DOS file called 6502.SYS, contained in the boot disc. Before system initialisation this file is transferred back across the tube and located at &2800, after shadow RAM has been turned off by an OSBYTE 114. The 6502.SYS code is then initialised, which results in the redirection of three more of the host's vectors. The user-vector at &200 is re-directed to &2803, the interrupt request 1 vector at &204 is redirected to &2834 and the event vector at &220 is re-directed to &2831.

6502.SYS performs many functions not provided by the standard host code. These include very fast screen updates (by direct pokes, which is why the host's shadow is not active), direct programming of the 6845 CRTC chip for the various IBM screen formats, special actions for keyboard activity scanning and reading mouse or tracker ball movement via the user-port.

6502.SYS must also perform some direct floppy disc control as CP/M formats, PC formats, as well as the 512's 800K format are not supported by ADFS, although they are by the WD1770 or 1772 if it is programmed directly. It will be found by reference to the 6502.SYS disassembly that, unlike 6502 second processors, the host code is called by the 512 via 6502.SYS only when standard MOS or ADFS filing system calls are required, though for speed 6502.SYS also issues several MOS calls directly itself. The host code is therefore of secondary irnportance to the 512, for which the majority of functions are provided by its own specialised code.

<Note: A few corrections or notes have been made to these listings where they were obviouly incorrect or misleading. These are all noted likes this – YP>

; **********************************
; 6 5 0 2  T U B E - H O S T C O D E
; **********************************

; *******************************
; Tube register data declarations
; *******************************


; *************
; Host OS calls
; *************
; Filing System
; *************


; *******
; General
; *******


; *******************
; Zero Page work area
; *******************

; The first two bytes are used for indirect loading 'from' when
; relocating a language across the tube in 6502 co-processors.
; In the 512 system the first 16 bytes are used as the parameter
; block for various OSWORD or filing system operations

00 EQUD 0000
04 EQUD 0000
08 EQUD 0000
0C EQUD 0000

10 EQUW 00

; Bytes &12 and &13 are used for the hi-lo-byte pair for
; block transfers of memory across the tube

12 EQUW 00

14 EQUB 0                   \Tube status - &80 = free/zero = busy
15 EQUB 0                   \Current owner ID - &80 = nobody

; Status bits are as follows
; Bit 0 = &01 is the Interlock for FDC and IRQ in use
; Bit 1 = &02 is the Bad FSmap flag
; Bit 2 = &04 is the MON flaq
; Bit 3 = &08 is the *compact flag (ie 'Do not disturb') Not used by DOS
; Bit 4 - &10 is set during an atomic series of operations for the MFM
; Bit 5 - &20 is set it there's a Winchester controller
; Bit 6 - &40 is set when tube is in use
; Bit 7 - &80 is set if tube is present

; ************************
; The following is the BRK
; handling code located at
; byte &16 in zero page.
; ************************

.brk handler
016 LDA #&FF                \Load A with 255
018 JSR write_R4_data       \Write A to tube data register 4
01B LDA r2_data             \Load A from tube data register 2
01E LDA #0                  \Load A with zero
020 JSR write_R2_data       \Write A to tube data register 2
023 TAY                     \Set Y to zero
024 LDA (&FD),Y             \Load A with first error byte
026 JSR write_R2_data       \Write to tube data register 2
029 INY                     \Increment Y
02A LDA (&FD),Y             \Load second and subsequent error bytes
02C JSR write_R2_data       \Write to tube data register 2
02F TAX                     \Transfer A to X
030 BNE &29                 \Was byte zero (termination)?- No repeat

032 LDX &FF                 \Load X with 255
034 TXS                     \Transfer to stack pointer (reset stack)
035 CLI                     \Clear interrupt disable flag

; ******************************************************
; This is the tube-idle loop which keeps the 6502 amused
; when there is no current I/O activity or tube transfer
; in progress. It continually checks register 1 status
; and if nothing is required checks register 2 - until
; either requires attention this is repeated endlessly.

; Register 1 is reserved for the current output channel
; (screen, printer, RS232) hence an immediate OSWRCH is
; executed if R1 is pending - thus if an output delay is
; caused by the host or peripherals the co-pro is also
; forced to wait. It is the entry for all other activity
; therefore, even if R2 is pending. R1 is serviced first

; The R2 entry causes an indirect jump to various code
; entry points in page 5 to give access to the required
; facilities.
; ******************************************************
036 BIT r1_stat             \Test tube register 1 status
039 BPL &41                 \Not ready - try reqister 2
03B LDA r1_data             \Read tube data register 1
03E JSR oswrch              \Write to current output stream
041 BIT r2_stat             \Test tube register 2 status
044 BPL &36                 \Not ready - try register 1 again
046 BIT r1_stat             \Register 2 ready - recheck register 1
049 BMI &3B                 \Register 1 now ready - do that first
04B LDX r2_data             \Read function code from data register 2
04E STX &51                 \Store at jumpvar, modifying jump address
050 JMP (jumpvar)           \Jump to modified address (&500+X - dirty!)
051 EOUB 0                  \Variable lo-byte of jump point in page 5
052 EQUB &05                \Fixed hi-byte of jump point (page 5)

; ************************************
; This is the 4 byte address used for
; language re-location across the tube

.reloc_data                 \Used for 4 byte memory addressing -
053 EQUB 0                  \Lo-byte of low order of 4 byte address
054 EQUB 0                  \Hi-byte of low order of 4 byte address
o55 EQUB 0                  \These bytes contain &FFFF for the host
056 EQUB 0                  \and &0000 upwards for the co-processor

Model B/B+ source listing

; **************************************************************
; **************************************************************
; Tube host code for model B, B+ machines using stand-alone ADFS
; **************************************************************

; ************************************************************
; This is the start of the code which occupies pages 4 through
; 6. Page 7 is also used as a buffer for 256 byte transfers.
; ************************************************************

400 JMP 6484                \Entry to copy language across tube
403 JMP &6A7                \Entry to copy ESCAPE flag across tube

; *****************************************
; This is the only entry point from 6502SYS
; *****************************************

.tube_entry                 \A=129 for tube release, 193 for claim
406 CMP #680                \Entry for 6502SYS - Tube claim or release?
408 BCC &435                \It's neither - must be data transfer\and also store in X
40A CMP #&CO                \Is it a tube claim?
40C BCS &428                \Yes - branch to claim tube
40E ORA #&40                \No it's a release - Set bit 7 on
410 CMP &15                 \Are we the tube owner?
412 BNE &434                \If not branch return - do nothing
414 PHP                     \Save processor status on stack
415 SEI                     \Set interrupt disable flag
416 LDA #5                  \Load A with 5
418 JSR write_R4_data       \Write A to tube R4
41B LDA &15                 \Load A with tube owner
41D JSR write_R4_data       \Write A to tube R4
420 PLP                     \Restore processor status from stack
421 LDA #&80                \Load A with 128
423 STA &15                 \Store in tube owner (&15)
425 STA &14                 \and in tube status (&14)
427 RTS                     \Return

.claim tube
428 ASL &14                 \Shift left tube status
42A BCS &432                \Tube was free - now it's ours - store_owner
42C CMP &15                 \Tube busy, is it us in &15?
42E BEQ &434                \Yes it's already ours - exit
430 CLC                     \Clear carry - claim failed
431 RTS                     \Return

432 STA &15                 \Store A in zero page byte &15
434 RTS                     \Return

435 PHP                     \Save processor status on stack
436 SEI                     \Disable interrupts (time critical transfer)
437 STY &13                 \Store Y (lo-address byte) in &13
439 STX &12                 \Store X (hi-address byte) in &12
43B JSR write_R4_data       \Write A to tube data register 4
43E TAX                     \and also store in X
43F LDY #3                  \Load Y for 4 byte transfer
441 LDA &15                 \Load A from zero page tube-owner
443 JSR write_R4_data       \Write A to tube data register 4
446 LDA (&12),Y             \Load A from indexed zero page address
448 JSR write_R4_data       \Write byte to tube data register 4
44B DEY                     \Decrement count
44C BPL &446                \Complete? No - loop back and repeat
44E LDY #&18                \Load Y 24
450 STY r1_stat             \Write to tube register 1 status
453 LDA &518,X              \Load from temporary_data
456 STA r1_stat             \Write register 1 status
459 LSR A                   \Divide value by 2
45A LSR A                   \and again (= Divide value by 4)
45B BCC &463                \Branch if old bit 1 was 0
45D BIT r3_data             \Waste a bit of time? These two
460 BIT r3_data             \instructions set P but do not affect A <But see here ‑ YP>
463 JSR write R4 data       \which is written to tube data register 4
466 BIT r4_stat             \Test register 4 status
469 BVC &466                \Not ready _ loop until it is
46B BCS &47A                \Status says terminate operation
46D CPX #4                  \Was original A = 4
46F BNE &482                \No - branch to return

471 JSR &414                \Inform co-pro of tube release
474 JSR write_R2_data       \Write A to tube data register 2
477 JMP &32                 \Jump to reset_stack

47A LSR A                   \Clear top bit
47B BCC 6482                \Branch if bottom bit was also clear
47D LDY #&88                \Confirm action terminated
47F STY r1_stat             \Write Y to tube register 1 status
482 PLP                     \Restore processor status reg from stack
483 RTS                     \Return

484 CLI                     \Enable interrupts
485 BCS &498                \If carry branch to claim tube
487 BNE &48C                \If not zero we've not finished - branch
489 JMP &59C                \Jump to termination at send_completion_byte
48C LDX #0                  \Load X Zero
48E LDY #&FF                \Load Y 255
490 LDA #&FD                \Load A 253
492 JSR osbyte              \Read/write last break
495 TXA                     \Last break type in X, transfer to A
496 BEQ &471                \0 = soft break - branch to soft_break
498 LDA #&FF                \Load A 255 (all bits on)
49A JSR &406                \Exec tube claim code (hard break = startup)
49D BCC &498                \If not successful repeat until it is
49F JSR &4D2                \Check current ROM, set up reloc. If language
4A2 LDA #7                  \Load A with 7 for call to tube_entry
4A4 JSR &4CB                \Jump to tube entry (with return)
4A7 LDY #0                  \Set Y counter to zero
4A9 STY 0                   \Store in romadd (lo-byte of transfer addr)
4AB LDA (0),Y               \Load byte to be transferred
4AD STA r3_data             \Write A to tube data register 3
4B0 NOP                     \These NOPs are included simply to cause a
4B1 NOP                     \delay, as the R3 transfer is 'slow'
4B2 NOP                     \(This extra NOP needed for 6502 and Z80)
4B3 INY                     \Increment Y - Finished current page?
4B4 BNE &4AB                \No - repeat until 256 bytes transferred
4B6 INC &54                 \Increment hi-byte,low order of co_pro addr
4B8 BNE &4C0                \64K transferred? No-branch update-host-page
4BA INC 655                 \Next 64K in co-pro. Inc. lo-byte high order
4BC BNE &4C0                \16Mb complete? No,branch update-host-page
4BE INC &56                 \Inc co-pro hi-byte high order (next 16Mb!!)

4C0 INC 1                   \Increment ROM address hi-byte
4C2 BIT 1                   \Test > 6 bits in &01 (2^14 = 16K addressed)
4C4 BVC &4A2                \If 16K complete branch for tube data Xfer
4C6 JSR &4D2                \Check current ROM and set up reloc. If lang
4C9 LDA #4                  \Load A with 4 for tube transfer type
4CB LDY #0                  \Load Y (lo-byte) for tube data transfer
4CD LDX #653                \Load X (hi_byte) for tube data transfer
4CF JMP &406                \Jump to tube_entry

4D2 LDA #&80                \Load A 128
4D4 STA &54                 \Set co-pro relocation address to &00008000
4D6 STA 1                   \And set host 'Xfer from' address to &8000
4D8 LDA #&20                \Set bit 6 on, all others off
4DA AND &8006               \AND current ROM type byte - is it a lang
4DD TAY                     \Put result in Y in case its not
4DE STY &53                 \Put result in &53 in case its not
4E0 BEQ &4FB                \0 means ROM is NOT lang - branch no_reloc
4E2 LDX &8007               \Load X with ROM copyright pointer offset

4E5 INX                     \Inc X to point to first ( of '(C)' string
4E6 LDA &8000,X             \Load A with copyright bytes until byte = 0
4E9 BNE &4E5                \Until 0 it's the c'right notice
4EB LDA &8001,X             \Load 1st byte of co_processor reloc address
4EE STA &53                 \Store in zero page byte &53
4F0 LDA &8002,X             \Load 2nd byte of relocation address
4F3 STA &54                 \Store in zero page byte &54
4F5 LDY &8003,X             \Load Y with 3rd byte of relocation address
4F8 LDA &8004,X             \Load A with 4th byte of relocation address

4FB STA &56                 \Store accumlator in zero page byte &56
4FD STY 655                 \Store Y in zero page byte &55
4FF RTS                     \Return

; ******************************************************
; These are indirect jumps taken from the tube idle loop
; code at &036 to &050. The address in &051 is poked to
; 'index' one of the following indirect jump addresses.
; *****************************************************

<Note: In the following table all the addresses are printed incorrectly with lo-byte and hi-byte reversed. Here they have been corrected>
500 EQUW &0537              \R2 was 0 - jump osrdch_call
502 EQUW &0596              \R2 was 2 - jump oscli_call
504 EQUW &05F2              \R2 was 4 _ jump short_osbyte
506 EQUW &0607              \R2 was 6 - jump long-osbyte
508 EQUW &0627              \R2 was 8 _ jump osword_call
50A EQUW &0668              \R2 was A _ jump osword0-call
50C EQUW &055E              \R2 was C _ jump osargs_call
50E EQUW &052D              \R2 was E - jump osbget_call
510 EQUW &0520              \R2 was 10 _ jump osbput_call
512 EQUW &0542              \R2 was 12 _ jump osfind_call_1
514 EQUW &05A9              \R2 was 14 - jump osfile_call
516 EQUW &05D1              \R2 was 16 - jump osgbpb_call

.temporary_data             \ <This is wrong. See here - YP>
518 EQUW 00
51A EQUW 00
51C EQUW 00
51E EQUB 00

520 JSR read_R2_data        \Load A with file handle from register 2
523 TAY                     \File handle must be in Y
524 JSR read_R2_data        \Load A with tube data register 2
527 JSR osbput              \Put a single byte to file
52A JMP &59C                \Jump to send completion byte

52D JSR read_R2_data        \Load A with file handle from register 2
530 TAY                     \File handle must be in Y
531 JSR osbget              \Get one byte from file
534 JMP &53A                \Jump to transfer_one byte

537 JSR osrdch

53A ROR A                   \Shift right one bit
53B JSR write_R2_data       \Write A to tube data register 2
53E ROL A                   \Shift left one bit
53F JMP &59E                \Jump to send unshifted byte

542 JSR read_R2_data        \Load A with tube data register 2
545 BEQ osfind_call_2       \Zero byte means close a file
547 PHA                     \Store A on stack temporarily
548 JSR block_transfer      \Transfer file-name from co-pro
54B PLA                     \Restore A (Contents = access mode)
54C JSR osfind              \Open the named file
54F JMP &59E                \Jump to return file handle

552 JSR read_R2_data        \Load A with tube data register 2
555 TAY                     \File handle must be in Y
556 LDA #0                  \Load A with zero
558 JSR osfind              \Close file
55B JMP &59C                \Jump to send completion byte

55E JSR read_R2_data        \Load A from tube data register 2
561 TAY                     \Put file handle in Y
562 LDX #4                  \Set up loop count
564 JSR read_R2_data        \Load A from tube data register 2
567 STA &FF,X               \Store at bottom of zero page
569 DEX                     \Decrement count
56A BNE &564                \complete? No _ loop back and repeat
56C JSR read_R2_data        \Load A with osargs call type
56F JSR osargs              \Read/write file attributes
572 JSR write_R2_data       \Write A to tube data register 2
575 LDX #3                  \Set up loop count for 4 bytes
577 LDA 0,X                 \Load A with returned attributes
579 JSR write_R2_data       \Write A to tube data register 2
57C DEX                     \Decrement count
57D BPL &577                \Complete? No - loop back and repeat
57F JMP &36                 \Jump to tube idle polling loop

582 LDX #0                  \Zero X
584 LDY #0                  \and Y
586 JSR read_R2_data        \Load A from tube data register 2
589 STA data,Y              \Store in 256 byte buffer at &700
58C INY                     \Increment Y
58D BEQ end_block           \Finished 256 bytes? - Yes
58F CMP #&D                 \No - was byte CR (end of transfer)
591 BNE &586                \No - Loop back for next byte

593 LDY #7                  \Finished! - Load Y with 7
595 RTS                     \Return

596 JSR block_transfer      \Get cli string
599 JSR oscli               \Call MOS command line interpreter

59C LDA #&7F                \Load A with 127 (Completion byte)
59E BIT r2_stat             \Test tube register 2 status
5A1 BVC &59E                \Not ready - repeat
5A3 STA r2_data             \Write A to tube data register 2
5A6 JMP &36                 \Jump to tube idle polling loop

5A9 LDX #&10                \Set up for 16 byte transfer in X
5AB JSR read_R2_data        \Load A from tube data register 2
5AE STA &1,X                \Store at romadd+1,X
580 DEX                     \Decrement count
5B1 BNE &5AB                \Complete? - No loop back and repeat
5B3 JSR block_transfer      \transfer bytes
5B6 STX 0                   \Reset filename hi-byte to zero
5B8 STY 1                   \Set filename pointer lo_byte to Y
5BA LDY #0                  \Set X-Y to point to 16 byte parameter block
5BC JSR read_R2_data        \Load A from tube data register 2
5BF JSR osfile              \Call osfile - A defines required action
5C2 JSR write_R2_data       \Write result code to tube data register 2
5C5 LDX #&10                \Set up for 16 byte transfer out
5C7 LDA 1,X                 \Load from romadd+1,X
5C9 JSR write_R2_data       \Write A to tube data register 2
5CC DEX                     \Decrement count
5CD BNE &5C7                \Complete? - No loop back and repeat
5CF BEQ &5A6                \2 stage jump back to tube_idle_loop

5D1 LDX #&D                 \Load X counter with length of param. block
5D3 JSR read_R2_data        \Load A from tube data register 2
5D6 STA &FF,X               \Store at bottom of page zero (1 to &D)
5D8 DEX                     \Decrement count
5D9 BNE &5D3                \Complete? - No loop back and repeat
5DB JSR read_R2_data        \Load A from tube data register 2
5DE LDY #0                  \Set Y to lo-byte of params
5E0 JSR osgbpb              \Call osgetbyte/putbyte
5E3 PHA                     \Preserve A on stack
5E4 LDX #&C                 \Set loop count
5E6 LDA 0,X                 \Load returned file information
5E8 JSR write_R2_data       \Write A to tube data register 2
5EB DEX                     \Decrement count
5EC BPL &5E6                \Complete? No - Loop back and repeat
5EE PLA                     \Restore A from stack
5EF JMP &53A                \Jump to transfer_one_byte

5F2 JSR read_R2_data        \Load A from tube data register 2
5F5 TAX                     \Set X paramter
5F6 JSR read_R2_data        \Load osbyte number from tube data reg
5F9 JSR osbyte              \Call osbyte
5FC BIT r2_stat             \Test register 2 status
5FF BVC &5FC                \Not ready - loop back until it is
601 STX r2_data             \Write returned X value to tube data reg 2
604 JMP &36                 \Jump to tube idle polling loop

607 JSR read_R2_data        \Load A from tube data register 2
60A TAX                     \Set osbyte X paramter
608 JSR read_R2_data        \Load A from tube data register 2
60E TAY                     \Set osbyte Y parameter
60F JSR read_R2_data        \Load A from tube data register 2
612 JSR osbyte              \Call osbyte
615 EOR #&9D                \Was it osbyte 157 (fast tube BPUT)?
617 BEQ &604                \Yes - Branch to idle poll jump
619 ROR A                   \Not 157 - Shift right one bit
61A JSR write_R2_data       \Write A to tube data register 2
61D BIT r2_stat             \Test tube register 2 status
620 BVC &61D                \Not ready - loop back until it is
622 STY r2_data             \Write Y to tube data register 2
625 BVS &5FC                \Branch to write X value to register 2

627 JSR read_R2_data        \Load A from tube data register 2
62A TAY                     \Save read/write action in Y
62B BIT r2_stat             \Test tube register 2 status
62E BPL &62B                \Not ready - loop until it is
630 LDX r2_data             \Load X with number of parameters <correction: original had "param. block offset">
633 DEX                     \Decrement X - If it is zero no parameters
634 BMI &645                \X now &FF? - Yes branch to osword setup
636 BIT r2_stat             \Test tube register 2 status
639 BPL &636                \Not ready - loop back until it is
63B LDA r2_data             \Read tube data register 2
63E STA &128,X              \Store in paramter block at offset X
641 DEX                     \Decrement count
642 BPL &636                \Complete? no - loop back and repeat
644 TYA                     \Restore read/write action from Y

645 LDX #&28                \Load X with param. block address low byte
647 LDY #1                  \Load Y with param. block address high byte
649 JSR osword              \Execute osword using param. block at &128
64C BIT r2_stat             \Test tube register 2 status
64F BPL &64C                \Not ready - loop back until it is
651 LDX r2_data             \Load X from tube data register 2 <ie number of parameters to return>
654 DEX                     \Decrement X
655 BMI &665                \Complete? Yes -
657 LDY &128,X              \Else read parameter into Y
65A BIT r2_stat             \Test tube register 2 status
65D BVC &65A                \Not ready - loop back until it is
65F STY r2_data             \Write Y to tube data register 2
662 DEX                     \Decrement count
663 BPL &657                \Complete? No - loop back and repeat
665 JMP &36                 \Jump to tube idle polling loop

668 LDX #4                  \Set loop count to 4 in X
66A JSR read_R2_data        \Load A from tube data register 2
66D STA 0,X                 \Store at romadd+X
66F DEX                     \Decrement count until X = &FF
670 BPL &66A                \5 bytes Xferred? - No loop back and repeat
672 INX                     \Increment X (back to zero)
673 LDY #0                  \Set Y to zero
675 TXA                     \Set A to zero
676 JSR osword              \Get characters from current input stream
679 BCC &680                \Return pressed? - Yes - branch to write
67B LDA #&FF                \Escape pressed! - load A with 255 and
67D JMP &59E                \Jump to write register 2

.read string
680 LDX #0                  \Zero loop counter
682 LDA #&7F                \Load A with start string byte
684 JSR write_R2_data       \Write A to tube data register 2
687 LDA data,X              \Load from 256 byte block at &700
68A JSR write_R2_data       \Write A to tube data register 2
68D INX                     \Increment count
68E CMP #&D                 \End of input marked by CHR$13?
690 BNE &687                \No - loop back for next byte
692 JMP &36                 \Indirect jump to tube idle polling loop

695 BIT r2_stat             \Test R2 status
698 BVC write_R2_data       \Not ready - loop until it is
69A STA r2_data             \Write A to tube data register 2
69D RTS                     \Return

69E BIT r4_stat             \Test R4 status
6A1 BVC write_R4_data       \Not ready - loop until it is
6A3 STA r4_data             \Write A to tube data register 4
6A6 RTS                     \Return

6A7 LDA &FF                 \Load Accumulator with 255
6A9 SEC                     \Set carry flag
6AA ROR A                   \Rotate right Accumulator bits
6AB BMI write_R1_data       \Branch on -ve flag (bit 7, prey carry)
6AD PHA                     \Preserve A on stack
6AE LDA #0                  \Load A with zero
6B0 JSR write_R1_data       \Write A to tube data register 1
6B3 TYA                     \Transfer contents of Y to A
6B4 JSR write_R1_data       \Write A to tube data register 1
6B7 TXA                     \Transfer contents of X to A
6B8 JSR write_R1_data       \Write A to tube data register 1
6BB PLA                     \Restore A from stack

6BC BIT r1_stat             \Test R1 status
6BF BVC write_R1_data       \Repeat - R1 not ready (bit 6 clear)
6C1 STA r1_data             \Write R1 data from A
6C4 RTS                     \Return

.read R2_data
6C5 BIT r2_stat             \Test R2 status
6C8 BPL read_R2_data        \Repeat - R2 not ready (bit 7 clear)
6CA LDA r2_data             \Read register 2 data into A
6CD RTS                     \Return

700 .data                   \Data buffer for (up to) 256 bytes

Master 128 source listing

; ************************************************************
; ************************************************************
; Tube host code for Master 128 machines using 'Mega-ROM' ADFS
; ************************************************************
; ************************************************************

; This is the start of the code which occupies pages 4 through
; 6. Page 7 is also used, as a buffer for 256 byte transfers.
; ************************************************************

400 JMP &4C2                \Entry to copy language across tube
403 JMP &675                \Entry to copy ESCAPE flag across tube

.tube_entry                 \On entry A=129 for tube rel, 193 for claim
406 CMP #&80                \Entry for 6502SYS - Is it tube claim or rel?
408 BCC &433                \It's neither - must be data transfer
40A CMP #&C0                \Is it a tube claim?
40C BCS &426                \Yes - branch to claim tube
40E ORA #&40                \No its a release - Set bit 7 on
410 CMP &15                 \Are we the tube owner?
412 BNE &432                \If not branch return - do nothing
414 PHP                     \Save processor status on stack
415 SEI                     \Set interrupt disable flag
416 LDA #5                  \Load A with 5
418 JSR write_R4_data       \Write A to tube R4
41B JSR write_R4_tube_owner \Load A with tube owner and write to R4
41E PLP                     \Restore processor status from stack
41F LDA #&80                \Load A with 128
421 STA &15                 \Store in tube owner (&15)
423 STA &14                 \and in tube status (&14)
425 RTS                     \Return

.claim tube
426 ASL &14                 \Shift left tube status
428 BCS &430                \Tube was free - now its ours - store_owner
42A CMP &15                 \Tube busy, is it us in &15?
42C BEQ &432                \Yes its already ours - exit
42E CLC                     \Clear carry - claim failed
42F RTS                     \Return

430 STA &15                 \Store A in zero page byte &15
432 RTS                     \Return

433 PHP                     \Save processor status on stack
434 SEI                     \Disable interrupts (time critical transfer)
435 STY &13                 \Store Y (lo-address byte) in &13
437 STX &12                 \Store X (hi-address byte) in &12
439 JSR write_R4_data       \Write A to tube data register 4
43C TAX                     \and also store in X
43D LDY #3                  \Load Y for 4 byte transfer
43F JSR write_R4_tube_owner \Load tube owner and write to R4
442 LDA (&12),Y             \Load A from indexed zero page address
444 JSR write_R4_data       \Write byte to tube data register 4
447 DEY                     \Decrement count
448 BPL &442                \Complete? No - loop back and repeat
44A LDY #&18                \Load Y 24
44C STY r1_stat             \Write to tube register 1 status
44F LDA &518,X              \Load from temporary_data
452 STA r1_stat             \Write register 1 status
455 LSR A                   \Divide value by 2
456 LSR A                   \and again (= Divide value by 4)
457 BCC &45F                \Branch if old bit 1 was 0
459 BIT r3_data             \Waste a bit of time? These two
45C BIT r3_data             \instructions set P but do not affect A <But see here ‑ YP>

45F JSR write_R4_data       \which is written to tube data register 4
462 BIT r4_stat             \Test register 4 status
465 BVC &462                \Not ready - loop until it is
467 BCS &476                \Status says terminate operation
469 CPX #4                  \Was original A = 4
46B BNE &47E                \No - branch to return
46D JSR &414                \Inform co-pro of tube release
470 JSR &661                \Write A to tube data register 2
473 JMP &32                 \Jump to reset_stack

476 LSR A                   \Clear top bit
477 BCC &47E                \Branch if bottom bit was also clear
479 LDY #&88                \Confirm action terminated
47B STY r1_stat             \Write Y to tube register 1 status
47E PLP                     \Restore processor status reg from stack
47F RTS                     \Return
480 LDX &28D                \X = MOS copy of last BREAK type byte
483 BEQ &46D                \0=soft - branch inform 512, reset stack
485 LDA #&FF                \Load A 255 (all bits on)
487 JSR &406                \Ex tube claim code (hard break = startup)
48A BCC &485                \If not successful repeat until it is
48C JSR &4C9                \Check current ROM, set up reloc.if lang
48F PHP                     \Save processor status
490 SEI                     \Disable interrupts
491 LDA #7                  \Load A with 7 for call to tube_entry
493 JSR &4BB                \Jump to tube entry (with return)
496 LDY #0                  \Store in romadd (lo-byte of Xfer address)
498 STZ 0                   \Store in romadd (lo-byte of Xfer address)
49A LDA (0),Y               \Load byte to be transferred
49C STA r3_data             \Write A to tube data register 3
49F NOP                     \These NOPs are included simply to cause a
4A0 NOP                     \delay, as the R3 transfer is 'slow'
4A1 NOP                     \(Extra NOP needed for the 6502 and Z80)
4A2 INY                     \Increment Y - Finished current page?
4A3 BNE 649A                \No - repeat until 256 bytes transferred
4A5 PLP                     \Restore processor flags
4A6 INC &54                 \Inc hi-byte, low order of co-pro address
4A8 BNE &4B0                \64K Xferred? No - branch update-host-page
4AA INC &55                 \Next 64K in co-pro. Inc. lo-byte high order
4AC BNE &480                \16Mb complete? No-br. update-host-page
                            \Increment ROM address hi-byte
4AE INC &56                 \Inc co-pro hi-byte high order(next 16Mb!!)

4B0 INC &1                  \Increment ROM address hi-byte
4B2 BIT &1                  \Test > 6 bits in &01 (2^14 = 16K addressed)
4B4 BVC &48F                \If 16K complete branch for tube data Xfer
4B6 JSR &4C9                \Check current ROM and set up reloc.if lang
4B9 LDA #4                  \Load A with 4 for tube transfer type
4BB LDY #0                  \Load Y (lo-byte) for tube data transfer
4BD LDX #&53                \Load X (hi-byte) for tube data transfer
4BF JMP &406                \Jump to tube_entry

4C2 CLI                     \Enable interrupts
4C3 BCS &485                \If carry branch to claim tube
4C5 BNE &480                \If not zero we've not finished - branch
4C7 BRA &52A                \B to termination at send completion_byte

.check_rom_ type
4C9 LDA #680                \Load A 128
4CB STA &54                 \Set co-pro relocation address to &00008000
4CD STA 1                   \And set host 'Xfer from' address to &8000
4CF LDA #&20                \Set bit 6 on, all others off
4D1 AND &8006               \AND current ROM type byte - is it a lang?
4D4 TAY                     \Put result in Y in case it's not
4D5 STY &53                 \Put result in &53 in case it's not
4D7 BEQ &4F2                \0 - ROM is NOT a language - branch no_reloc
4D9 LDX &8007               \Load X with ROM copyright pointer offset

.read _C
4DC INX                     \Inc X to first ( of '(C)' string
4DD LDA &8000,X             \Load A with copyright bytes until byte = 0
4E0 BNE &4DC                \Until it's the (C) notice - branch read_C
4E2 LDA &8001,X             \Load 1st byte of co-pro reloc address
4E5 STA &53                 \Store in zero page byte &53
4E7 LDA 8002,X              \Load 2nd byte of relocation address
4EA STA &54                 \Store in zero page byte &54
4EC LDY &8003,X             \Load Y with 3rd byte of relocation address
4EF LDA &8004,X             \Load A with 4th byte of relocation address

4F2 STA &56                 \Store accumulator in zero page byte &56
4F4 STY &55                 \Store Y in zero page byte &55
4F6 RTS                     \Return

4F7                         \These addresses are undefined. They are
4F9                         \unused because the code was re-written
4FA                         \for the master so as to use less memory,
4FC                         \but the addresses at &500 cannot be moved
4FE                         \therefore these bytes are redundant.

; ******************************************************
; These are indirect jumps taken from the tube idle loop
; code at &036 to &050. The address in &051 is poked to
; 'index' one of the following indirect jump addresses.
; *****************************************************

<Note: In the following table all the addresses are printed incorrectly with lo-byte and hi-byte reversed. Here they have been corrected>
500 EQUW &0535              \R2 was 0  - jump osrdch_call
502 EQUW &0588              \R2 was 2  - jump oscli_call
504 EQUW &05DA              \R2 was 4  - jump short_osbyte
506 EQUW &05EB              \R2 was 6  - jump long -osbyte
508 EQUW &0607              \R2 was 8  - jump osword_call
50A EQUW &0636              \R2 was A  - jump osword0_call
50C EQUW &0559              \R2 was C  - jump osargs_call
50E EQUW &052C              \R2 was E  - jump osbget_call
510 EQUW &0520              \R2 was 10 - jump osbput_call
512 EQUW &053F              \R2 was 12 - jump osfind_call_1
514 EQUW &05B2              \R2 was 14 - jump osfile_call
516 EQUW &059A              \R2 was 16 - jump osgbpb_call

.temporary data             \ <This is wrong. See here - YP>
518 EQUW 00
51A EQUW 00
51C EQUW 00
51E EQUW 00

520 JSR read_R2_data        \Load A with file handle from register 2
523 TAY                     \File handle must be in Y
524 JSR read_R2_data        \Load A with tube data register 2
527 JSR osbput              \Put a single byte to file
52A BRA &58E                \Branch to send completion byte

52C JSR read_R2_data        \Load A with file handle from register 2
52F TAY                     \File handle must be in Y
530 JSR osbget              \Get one byte from file
533 BRA &538                \Branch to transfer_one_byte

535 JSR osrdch

538 ROR A                   \Shift right one bit
539 JSR &661                \Write A to tube data register 2
53C ROL A                   \Shift left one bit
53D BRA &590                \Branch to send unshifted byte

53F JSR read R2_data        \Load A with tube data register 2
542 BEQ &54E                \Zero byte means close a file
544 PHA                     \Store A on stack temporarily
545 JSR block_transfer      \Transfer file-name from co-pro
548 PLA                     \Restore A (Contents = access mode)
549 JSR osfind              \Open the named file
54C BRA &590                \Branch to return file handle

54E JSR read_R2_data        \Load A with tube data register 2
551 TAY                     \File handle must be in Y
552 LDA #0                  \Load A with zero
554 JSR osfind              \Close file
557 BRA &58E                \Jump to send completion byte

559 JSR read_R2_data        \Load A from tube data register 2
55C TAY                     \Put file handle in Y
55D LDX #4                  \Set up loop count
55F JSR read_params         \Read parameters into zero page
562 JSR osargs              \Read/write file attributes
565 JSR write_R2_data       \Write returned A value to data register 2
568 LDX #3                  \Set up loop count for 4 bytes
56A LDA 0,X                 \Load A with returned attributes
56C JSR write_R2_data       \Write A to tube data register 2
56F DEX                     \Decrement count
570 BPL &56A                \Complete? No - loop back and repeat
572 BRA &598                \Indirect branch to tube idle polling loop

574 LDX #0                  \Zero X
576 LDY #0                  \and Y
578 JSR read_R2_data        \Load A from tube data register 2
57B STA data,Y              \Store in 256 byte buffer at &700
57E INY                     \Increment Y
57F BEQ end_block           \Finished 256 bytes? - Yes
581 CMP #&D                 \No - was byte CR (end of transfer)
583 BNE &578                \No - Loop back for next byte

585 LDY #7                  \Finished! - Load Y with 7
587 RTS                     \Return

588 JSR block_transfer      \Get cli string
58B JSR oscli               \Call MOS command line interpreter

58E LDA #&7F                \Load A with 127 (Completion byte)
590 BIT r2_stat             \Test tube register 2 status
593 BVC &590                \Not ready - repeat
595 STA r2_data             \Write A to tube data register 2
598 BRA &5E8                \Indirect branch to tube idle polling loop

59A LDX #&0                 \Load X counter with length of param. block
59C JSR read_params         \Read zero page params from tube register 2
59F LDY #0                  \Set Y to lo-byte of params
5A1 JSR osgbpb              \Call osgetbyte/putbyte
5A4 PHA                     \Preserve A on stack
5A5 LDX #&C                 \Set loop count
5A7 LDA 0,X                 \Load returned file information
5A9 JSR write_R2_data       \Write A to tube data register 2
5AC DEX                     \Decrement count
5AD BPL &5A7                \Complete? No - Loop back and repeat
5AF PLA                     \Restore A from stack
5B0 BRA &538                \Branch to transfer_one_byte

5B2 LDX #&10                \Set up for 16 byte transfer in
5B4 JSR read_R2_data        \Load A from tube data register 2
5B7 STA 1,X                 \Store at romadd+1,X
5B9 DEX                     \Decrement count
5BA BNE &5B4                \Complete? - No loop back and repeat
5BC JSR block_transfer      \Transfer bytes
5BF STX 0                   \Reset filename hi-byte to zero
5C1 STY 1                   \Set filename pointer lo-byte to Y
5C3 LDY #0                  \Set X-Y to point to 16 byte parameter block
5C5 JSR read_R2_data        \Load A from tube data register 2
5C8 JSR osfile              \Call osfile - A defines required action
5CB JSR write_R2_data       \Write result code to tube data register 2
5CE LDX #&10                \Set up for 16 byte transfer out
5D0 LDA 1,X                 \Load from romadd+1,X
5D2 JSR write_R2_data       \Write A to tube data register 2
5D5 DEX                     \Decrement count
5D6 BNE &5D0                \Complete? - No loop back and repeat
5D8 BRA &5E8                \2 stage jump back to tube_idle_loop

5DA JSR read_X_and_A        \Read X and A params for short osbyte
5DD JSR osbyte              \Call osbyte
5E0 BIT r2_stat             \Test register 2 status
5E3 BVC &5E0                \Not ready - loop back until it is
5E5 STX r2_data             \Write returned X value to tube data reg 2
5E8 JMP &36                 \Jump to tube idle polling loop

5EB JSR read_X_and_A        \Read X and A params for osbyte
5EE TAY                     \Move A parameter to Y
5EF JSR read_R2_data        \Load A from tube data register 2
5F2 JSR osbyte              \Call osbyte
5F5 EOR #&90                \Was it osbyte 157 (fast tube BPUT)?
5F7 BEQ &5E8                \Yes - Branch to idle poll jump
5F9 ROR A                   \Not 157 - Shift right one bit
5FA JSR write_R2_data       \Write A to tube data register 2
5FD BIT r2_stat             \Test tube register 2 status
600 BVC &5FD                \Not ready - loop back until it is
602 STY r2_data             \Write Y to tube data register 2
605 BRA &5E0                \Branch to write X value to register 2

607 JSR read_R2_data        \Load A from tube data register 2
60A TAY                     \Save read/write action in Y
60B JSR read_X_R2_data      \Read X from tube data register 2 <Sets X to number of parameters to receive-1>
60E BMI &61A                \X now &FF? - Yes branch to osword_setup
610 JSR read_R2_data        \Read parameters from tube data register 2
613 STA &128,X              \Store in paramter block at offset X
616 DEX                     \Decrement count
617 BPL &610                \Complete? no - loop back and repeat
619 TYA                     \Restore read/write action from Y

61A LDX #&28                \Load X with param. block address low byte
61C LDY #1                  \Load Y with param. block address high byte
61E JSR osword              \Execute osword using param block at 5128
621 JSR read_X_R2_data      \Read X from tube data register 2 <X now = number of parameters to return -1>
624 BMI &5E8                \Complete? Yes -
626 LDY &128,X              \Else read parameter into Y
629 BIT r2_stat             \Test tube register 2 status
62C BVC &629                \Not ready - loop back until it is
62E STY r2_data             \Write Y to tube data register 2
631 DEX                     \Decrement count
632 BPL &626                \Complete? No - loop back and repeat
634 BRA &5E8                \Indirect branch to tube idle polling loop

636 LDX 44                  \Set loop count to 4 in X
638 JSR read_R2_data        \Load A from tube data register 2
63B STA 0,X                 \Store at romadd+X
63D DEX                     \Decrement count until X = &FF
63E BPL &638                \5 bytes Xferred? - No loop back and repeat
640 INX                     \Increment X (back to zero)
641 TXA                     \Set A to zero
642 TAY                     \Set Y to zero
643 JSR osword              \Get characters from current input stream
646 BCC &64D                \Return pressed? - Yes - branch to write
648 LDA #&FF                \Escape pressed! - load A with 255 and
64A JMP &590                \Jump to write register 2

64D LDX #0                  \Zero loop counter
64F LDA #&7F                \Load A with start string byte
651 JSR write_R2_data       \Write A to tube data register 2
654 LDA data,X              \Load from 256 byte block at &700
657 JSR write R2 data       \Write A to tube data register 2
65A INX                     \Increment count
65B CMP #&D                 \End of input marked by CHR$13?
65D BNE &654                \No - loop back for next byte
65F BRA &634                \Indirect jump to tube idle polling loop

661 BIT r2_stat             \Test R2 status
664 BVC write_R2_data       \Not ready - loop until it is
666 STA r2_data             \Write A to tube data register 2
669 RTS                     \Return

66A LDA &15                 \Load current tube owner

66C BIT r4_stat             \Test R4 status
66F BVC write_R4_data       \Not ready - loop until it is
671 STA r4_data             \Write A to tube data register 4
674 RTS                     \Return

675 LDA &FF                 \Load Acumulator with 255
677 SEC                     \Set carry flag
678 ROR A                   \Rotate right Acumulator bits
679 BRA write_R1_data       \Branch on negative flag (bit 7, prey carry)
67B PHA                     \Preserve A on stack
67C LDA #0                  \Load A with zero
67E JSR write_R1_data       \Write A to tube data register 1
681 TYA                     \Transfer contents of Y to A
682 JSR write_R1_data       \Write A to tube data register 1
685 TXA                     \Transfer contents of X to A
686 JSR write_R1_data       \Write A to tube data register 1
689 PLA                     \Restore A from stack

68A BIT r1_stat             \Test R1 status
68D BVC write_R1_data       \Repeat - R1 not ready (bit 6 clear)
68F STA r1_data             \Write R1 data from A
692 RTS                     \Return

693 JSR read_R2_data        \Load A from tube data register 2
696 STA &FF,X               \Store at bottom of zero page
698 DEX                     \Decrement count
699 BNE read_params         \complete? No - loop back and repeat
69B BRA read_R2_data        \Branch read Accumulator from R2

69D JSR read_R2_data        \Read data register 2 into A and transfer
6A0 TAX                     \the value to X, then fall through to..

6A1 BIT r2_stat             \Test R2 status
6A4 BPL read_R2_data        \Repeat - R2 not ready (bit 7 clear)
6A6 LDA r2_data             \Read register 2 data into A
6A9 RTS                     \Return

6AA BIT r2_stat             \Test R2 status
6AD BPL read_X_R2_data      \Repeat - R2 not ready (bit 7 clear)
6AF LDX r2_data             \Read register 2 data into X
6B2 DEX                     \Decrement the value
6B3 RTS                     \Return

700 .data                   \Data buffer for (up to) 256 bytes

< Previous  |  Contents  |  Next >

About the Master 512 | Bibliography