BPRUN: Broadcast Parallel RUN for NadaNet
Michael J. Mahon - May 31, 2008
Revised - February 5, 2009
BPRUN is an Applesoft program that runs on a ProDOS master machine. Its purpose is to boot any AppleCrate machines needing network booting, start a Message Server if needed, and then run a user-selected Applesoft BASIC program on all remaining AppleCrate machines. It capitalizes on the fact that all slaves receive the same program by using a broadcast protocol to send it to all of them simultaneously. BPRUN can be found on the ProDOS boot disk.
The Applesoft BASIC program, BPRUN, is presented below, with liberal comments:
Two address constants are defined: the start address of CR.BPRUNNER and the address of the copy of the master's IDTBL that is loaded into each slave machine.
100 REM Broadcast Parallel RUN BASIC program 110 REM MJM - 02/05/09 120 : 200 REM Addresses in slave machines 210 BPRN = 2 * 256: REM CR.BPRUNNER at $200 220 SITBL = BPRN + 8 * 16: REM IDTBL at $280 230 :
After finding out whether a Message server should be started, we initialize NadaNet. This initialization presumes that NadaNet, with the AmperNada extensions, has already been installed below the OS, HIMEM has been adjusted, and an initializing call has been made. (These actions are usually taken by the STARTUP program at the time the master machine is booted from disk.) The following GOSUB merely verifies that NadaNet is installed and sets up some pointer variables for application use. Next, we take a "census" of all machines from 1 up to MX (defined by the initialization code at 60070) to determine which ones are serving and, if so, what type of machine they are. AppleCrate slave machines are marked "2" in IDTBL. If the Message Server (ID=2) is running, then that is noted. If the Message Server is running and is not needed, that machine is forced to re-boot NADA.CRATE. The disk prefix for M/L code loads and an abbreviation for D$"bload" are defined for convenience.
240 INPUT "Is Message Server needed? (y/N)";A$ 250 NEEDMS = A$ = "Y" OR A$ = "y" 260 : 270 GOSUB 60000: REM Initialize AmperNada 280 GOSUB 61000: REM Take census 290 MSRV = PEEK (ITBL + 2) = 3: REM Save pre-boot Msg Server status 300 IF NOT NEEDMS AND MSRV THEN POKE 512,0: & POKE (2,1012,1,512): & CALL (2,64098,0): POKE ITBL + 2,0: REM Force re-boot of Message Server 310 PFX$ = "/ap/merlin/work/nadanet/" 320 DB$ = CHR$ (4) + "bload" 330 :
The next lines define a general purpose buffer, send the boot code to boot any network-bootable machines needing boot service, then call &SERVE(10) to enter the master's service loop with a count such that it will stay in the service loop for about 200ms. (since, if nothing is requested, each RCVPKT call times out in about 20ms, and this specifies 10 iterations).
The purpose of this &SERVE call is to process the GETID requests of any just-booted AppleCrate slave machines, causing them to be assigned unique IDs. When we return from SERVE, all slave machines will have their IDs and will be running their service loops.
340 REM Boot unbooted slaves 350 PBUF = 2 * 4096: REM Program buffer 360 PRINT DB$PFX$"nada.crate,A"PBUF 370 PSRT = PEEK (PBUF + 2) * 256: REM Prog start 380 PLNG = PEEK (48840) + 256 * PEEK (48841): REM Prog length 390 & BOOT(PSRT,PLNG,PBUF) 400 & SERVE(10): REM Handle AppleCrate II GETIDs 410 PRINT "Boot of slaves completed." 420 :
Now that booting is completed, we retake a census to determine how many slaves are present. If the Message Server is not already running and is needed, we require that machine #2 be available, then &BRUN NADA.MSERVE on it. IDTBL is updated to reflect that machine #2 is now the Message Server and not a normal slave.
430 GOSUB 61000: REM Re-take census 440 IF MSRV OR NOT NEEDMS GOTO 550: REM Already running or not needed 450 : 460 REM Load Message Server 470 IF NOT PEEK (ITBL + 2) THEN PRINT "No Msg Server (2)": STOP 480 PRINT DB$PFX$"nada.mserve,A"PBUF 490 PSRT = PEEK (PBUF + 2) * 256: REM Prog start 500 PLNG = PEEK (48840) + 256 * PEEK (48841): REM Prog length 510 & B RUN (2,PSRT,PLNG,PBUF): REM BRUN Message Server 520 PRINT "Message Server now running on 2" 530 MSRV = 1: POKE ITBL + 2,3: REM Mark Msg Server 540 :
In preparation for initializing the slave machines, we now pre-load the CR.BPRUNNER code that will run on page 2 to receive the broadcast Applesoft program. The master's IDTBL is poked into that image at what will be $280 so that each slave machine can determine the environment in which it is running.
We then get the name of the Applesoft program to be RUN and pre-load it as well. Note that the program must have been SAVEd from the default Applesoft start address of $801, and will be LOADed and RUN at that location in the slave machines.
550 REM Broadcast RUN Applesoft program 560 : 570 PRINT DB$PFX$"cr.bprunner,a"PBUF 580 ASTAG = 14 * 4096: REM Applesoft program BCAST tag ($E000) 590 : 600 FOR D = 0 TO PEEK (ITBL): REM Copy IDTBL to slave's $280 610 POKE PBUF + 128 + D, PEEK (ITBL + D) 620 NEXT 630 : 640 PRINT "Run what program? ";: INPUT "";P$ 650 IF P$ = "" THEN PRINT CHR$ (4)"catalog,tbas": GOTO 640 660 PRINT DB$P$",a"PBUF + 256",tbas" 670 PLNG = PEEK (48840) + 256 * PEEK (48841): REM Prog Length 680 PSRT = (8 * 256 + 1): REM Prog start = $0801 690 :
The CR.BPRUNNER program is then &BRUN on each serving AppleCrate slave machine (IDTBL type = 2), and each machine is counted and reported as ready for the broadcast of the BASIC program.
700 REM Start BPRUNNER program on slaves 710 PRINT "Machines "; 720 C$ = "": REM no initial comma 730 FOR D = 2 TO MX 740 IF PEEK (ITBL + D) < > 2 GOTO 800: REM Only AppleCrate machines 750 & B RUN #(D,512,256,PBUF): REM BRUN the 1-page BPRUNNER at $200 760 IF PEEK (1) GOTO 800: REM Skip if not serving 770 NS = NS + 1: REM Count machines 780 PRINT C$D; 790 C$ = ", ": REM Commas after first 800 NEXT D 810 PRINT 820 IF NS = 0 THEN PRINT "not available.": STOP 830 PRINT "awaiting BASIC program." 840 :
Now we clear the master's SITBL area ($280) in preparation to receive status from the running slaves, then broadcast the Applesoft program by executing a &BCAST command. What each slave does with the data depends entirely on the code of CR.BPRUNNER.
CR.BPRUNNER waits for a broadcast BCASTREQ packet with a "tag" high byte of $E0 (ASTAG), then receives the subsequent data into the fixed address $801. Following the load of the Applesoft program, it coldstarts BASIC, sets up the program pointers, and jumps to the Applesoft "RUN" entry point to start the program.
850 FOR D = 2 TO MX: POKE SITBL + D,0: NEXT : REM Clear status 860 & BCAST(ASTAG,PLNG,PBUF + 256): REM Broadcast BASIC program
At this point, the Applesoft program should be RUNning in each slave machine, and the purpose of the following code is to verify that status.
The master machine &SERVEs requests from the slave machines. Each slave, by convention, &POKEs a non-zero status byte into the master's SITBL area corresponding to its ID. The master then scans the SITBL area to verify that all slaves are running the desired program, or to report if they are not.
The work of BPRUN is now finished as the slave machines continue the requested computation.
870 FOR I = 1 TO MX: & SERVE#(5): NEXT : REM Serve &PEEKs from BASIC progs 880 FOR D = 2 TO MX 890 IF PEEK (ITBL + D) < > 2 GOTO 920 900 ST = PEEK (SITBL + D): REM Get slave program status 910 IF NOT ST THEN PRINT "Machine "D" ("ST") not running program.":NR = 1 920 NEXT 930 IF NOT NR THEN PRINT "All machines running program." 940 : 950 END 960 :
This is the standard "suffix" for NadaNet applications, added by EXECing the text file NADADEFS. The subroutine at 60000 verifies that NadaNet is initialized and sets up a few variables. The subroutine at 61000 performs a "census" of serving machines on the net and saves the results in a table at ITBL. (Note that because the census loop is probing machines that may not be serving (or even exist), it temporarily sets the &TIMEOUT value down to 2 * 60ms. so that unresponsive machines do not stall the &PEEK for very long. The default timeout is restored when the census is completed.)
Note that as of NadaNet 3.0, the initialization subroutine (60000) no longer defines BUF, and that the census subroutine (61000) has been modified to create a multi-column report to better accommodate a larger number of machines (MX). NadaNet 3.0 supports machine IDs up to 31, so MX can be adjusted to suit the expected NadaNet environment.
60000 REM NadaNet Definitions for Applesoft 60010 REM MJM - 01/13/09 60020 : 60030 MX = 20: REM Max machine ID 60040 IF PEEK (973) < > 76 THEN PRINT "NadaNet not loaded.": STOP 60050 SELF = PEEK (972) 60060 & IDTBL(ITBL): REM ID table 60070 RETURN 60080 : 61000 REM Take census of serving machines 61010 & TIMEOUT(2): REM Set short timeout 61020 QC = INT ( PEEK (33) / 13): REM Number of columns 61030 QL = INT ((MX + QC - 1) / QC): REM Number of lines 61040 FOR I = 1 TO QL 61050 FOR D = I TO MX STEP QL 61060 IF D = SELF THEN J = PEEK (975): GOTO 61110 61070 A$ = " " 61080 & PEEK #(D,975,1,512): REM Machine type 61090 IF PEEK (1) THEN K = 0: GOTO 61150 61100 J = PEEK (512) 61110 IF J = 184 THEN A$ = "CRATE ":K = 2 61120 IF J = 008 THEN A$ = "MSERVER ":K = 3 61130 IF J = 145 THEN A$ = "PRODOS ":K = 4 61140 IF J = 141 THEN A$ = "DOS ":K = 5 61150 POKE ITBL + D,K: REM Save type in IDTBL 61160 IF D = SELF THEN A$ = "==SELF==" 61170 IF D < 10 THEN PRINT " "; 61180 PRINT D":"A$" "; 61190 NEXT D 61200 PRINT 61210 NEXT I 61220 & TIMEOUT(): REM Reset retrys 61230 RETURN