Program notes

LASTC.UB  (The console program)

5 'DOS Beowulf V 2.0 October 7, 2002, Bill Weller
10 cls:console 0,*:color 3
20 Id=16 'sets this machine as console
The ID determines the name of the machine for calling (polling) purposes. 17 through 31 are set aside for nodes, but anything could be used. If more nodes are needed, a two byte scheme could be used.
30 '
40 'initialize port
50 Base%=956 'base% address for lpt1 on a Thinkpad  Most machines use 888 for LPT1. Use FINDPORT.EXE in the ZIP package to determine the address on your machine.
60 out Base%+2,4
70 out Base%,0 'clear port
80 goto 370
90 '
100 '
110 beep 1:for T=1 to 100000:next:beep 0:return  I though it would be nice to have each node beep as it was polled, but it messed up the timing. I left it in so you can have a BEEP when the machine has finished your app.
120 '
130 '
140 *Newbyte UBASIC looks for the *. For speed, make sure your GOTOs and GOSUBs point to a line with "*" rather than the line below it.
150 Nflag=0
160 gosub 240
170 B=Inbyte%
180 gosub 240
190 if Inbyte%<>B then 160 'make sure it is stable Allows time for the inverted bits to switch and slow machines to be mixed with fast ones.
200 if Inbyte%<>Outbyte then Newbyte%=Inbyte%:Nflag%=1
210 if Newbyte%>127 then Newbyte%=Newbyte%-128
220 return
230 '
240 *Inbyte
250 if inkey<>"" then out Base%,0:end Eliminating this line will speed things greatly, but you need CONTROL / BREAK to exit. I left it in to help when troubleshooting.
260 Inbyte%=bitor(bitand(inp(Base%+1),240),bitand(inp(Base%+2),15)) Takes care of those darn inverted bits.
270 Inbyte%=bitxor(Inbyte%,139)
280 return
Lines 140 through 280 are the heart of the communications. By turning bit 8 on and off, the console and nodes know when a new byte has arrived. I experimented for weeks with different schemes, and found this to be the simplest and most reliable, but not the fastest. The biggest problem is the four inverted bits in the parallel port. They don't switch at the same time, and it varies from machine to machine. Lines 170-190 takes care of this, but the penalty is speed. If somebody would write a machine code version I would be happy to post it.
290 '
300 *Outbyte
310 Lastbyte%=Outbyte%+Flag%
320 out Base%,Lastbyte%
330 if Flag%=0 then Flag%=128:return  This is where bit 8 is turned on and off.
340 if Flag%=128 then Flag%=0
350 return
360 '
370 *Ringtest
380 cls:N=0
390 print " Testing ring";
400 for I=1 to 6:N=2^I  Tests each line individually, looking for wiring errors.
410 clr time
420 Outbyte%=N:gosub 300
430 gosub 140:print ".";
440 if time1000<15 then 430  Time is necessary, in case you skipped a node when you numbered them. It does not, however check to see if a node number was used twice. A number greater than 15 might be needed if there are a lot of nodes. Nodes on the ring do not have to be in any sequence.
450 if Inbyte%<>Lastbyte% then Test=1
460 if Test=1 and I=1 then goto 520
470 next I
480 if Test=1 then color 4:print " FAIL Check wiring.":color 3:end
490 print:print " Ring continuity and wiring bit test OK.":out Base%,0
500 print:print " Press any key to continue."
510 if inkey="" then 510 else goto 550
520 color 4:print:print " FAIL.. make sure nodes are on.":color 3:end
530 '
540 '
550 *RollCall  Checks to see which node numbers are used, and makes sure they are all running.
560 cls
570 Nn=0:print
580 print " Roll call.":print:color 2
590 for Node=17 to 20
600 Outbyte%=Node:gosub 300
610 for T=1 to 15000:next Allow plenty of time to look for slow nodes.
620 gosub 140
630 if Inbyte%=Lastbyte% then 680
640 if Inbyte%<>6 then 620
650 print " Node";Node-16;" is online":inc Nn
660 out Base%,4 Four is End Of Transmission (EOT)
670 for T=1 to 10000:next
680 next
690 Outbyte%=4:gosub 300
700 if Nn=0 then color 4 else color 3
710 print:print " There are";Nn;" nodes online."
720 if Nn=0 then then color 3:end
730 print:print " Press any key to process.":print
740 if inkey<>"" then out Base%,3:goto 890 else 740  Commands the nodes to run you application.
750 '
760 *Get_String  This is the heart of the data transmission. All data communication is ASCII bytes, 32 to 127. This way there is no confusion over what is data, and which are command bytes.
770 In$="":Lastbyte%=0
780 gosub 140
790 if B=3 then 780 In the nodes, a "3" tells it to run you application. This line tells the console to ignore it.
800 if B=Lastbyte% then 780
810 Lastbyte%=B:out Base%,Inbyte%
820 if B>127 then B=B-128
830 In$=In$+chr(B)
840 for T=1 to 100:next
850 if B<>4 then 780
860 In=val(mid(In$,3,len(In$))) It seems that UBASIC does not like null strings, and inserts a few non-ASCII bytes.
870 return
880 '
890 *StartOfYourProgram
900 X=2+2
910 print " From console: 2+2=";X
920 for T=1 to 10000:next May not be needed on your cluster.
930 out Base%,17 ' poll node 1 Tells node to start sending data
940 gosub 760  Get the string. The computational results from the node are contained in IN$ as ASCII.
950 print " From node 1: ";val(In$) At this point something would be done with the data, added to what was calculated in the console, sent to floppy, forwarded to another node, etc. before getting more data.
960 '
970 for T=1 to 10000:next
980 out Base%,18 'poll node 2
990 for T=1 to 10000:next  Wait for the "18" to get to the node, and allow time for it to set up transmitting before looking for the first byte..
1000 gosub 760
1010 print " From node 2: ";val(In$)
1020 gosub 110
1030 '
1040 *EndOfYourProgram
1050 'out base%,0:end

This is the absolute bare program. Much could be added, such as multiple apps, chaining, shared data, transfer or modification of formulas. I need more feedback from users before I can make this more sophisticated.