wickensonline.co.uk Retrochallenge 2009 Summer Challenge Entry Research |
Retrochallenge 2009
Summer Challenge
Mark Wickens
9-Jul-2009
Research
It appears that my usually verbose presence has been missed by those who
witnessed the veritable stream of posts in my winter challenge! I can only
apologise and say in my defence that it hasn't been for the lack of trying. I
did do some research the other night which didn't make it onto the VAX until
now, so here goes.
In preparation for this challenge I had taken the following algorithm and coded
it up in Java to educate me as to what I needed to achieve in VAX Macro. The
algorithm is from the Clifford Pickover book:
ALGORITHM: Calculation of chaotic dusty curls
Variables: rz, iz = real, imaginary component of complex number
i = iteration counter
u, z = complex numbers
Note: Choose one of the three different tests for divergence.
u = -.74 + .11 i;
DO rrz = -1 to 1 by 0.001;
DO iiz = -1 to 1 by 0.001;
z = cplx(rrz, iiz);
InnerLoop: DO i = 1 to 100;
z = z**2 + u;
rz = real(z); iz = imag(z);
if sqrt(rz**2) + iz**2) > 2 then leave InnerLoop;
END;
color = i;
if convergence_test = 1 then
if rz**2 + iz**2 > 4 then PRINTDOT(rrz,iiz,color);
if convergence_test = 2 then
if ((abs(rz)<2) & (abs(iz)<2)) then PRINTDOT(rrz,iiz,color);
if convergence_test = 3 then
if rz**2+iz**2>4 & mod(i,2) = 0 then PRINTDOT(rrz,iiz,color);
END;
END;
My first thought, when thinking about this algorithm in terms of VAX Macro was
how to implement complex numbers. I had a quick look in my set of OpenVMS
manuals and found the OpenVMS VAX RTL Mathematics(MTH$) Manual[1]. This manual
defines a number of routines that may be helpful in developing my code to
process complex numbers, aswell as pointing the reader to the OpenVMS RTL
General Purpose (OTS$) Manual aswell[2].
System utilities that might be of interest are:
OTS$DIVCx Perform complex division
OTS$MULCx Perform complex multiplication
OTS$CNVOUT Convert a D-, G- or H-float value to a character string
OTS$POWCxCx Raise a complex base to a complex floating-point exponent
OTS$CNVOUT_G G-float to character string (Fortran E-format)
Argument 1: address of a G-floating point number
Argument 2: address of a fixed length resultant string, as a descriptor
Returns: unsigned longword condition
SS$_NORMAL
SS$_ROPRAND
OTS$_OUTCONNERR
MTH$GABS Absolute value of G-float
MTH$GDIM Positive difference of two G-floating parameters
MTH$GMIN1 G-floating minimum of n G-floating parameters
Where possible I'd like to use these utilities instead of inventing the wheel.
Originally my challenge idea involved generating the mandelbrot to a terminal
and I am undecided whether this will be an easier proposition than interfacing
with my next choice, which is the venerable gnuplot[3]. This fantastic program
takes a script, datafile or combination of both and given one of any number of
possible targets (such as terminal, x-window, postcript printer, jpeg file,
etc.) produces a beautifully rendered graph.
I used gnuplot extensively whilst doing my PhD back in the mid 1990's, and
recently called on its' services again when writing a utility to track my ADSL
uptime. Anyone who is uses the BBS knows that I was having a hard time having
changed over to Demon Internet with outages. Things seemed to have calmed down,
but I figured that a picture is worth a thousand words.
I run a couple of scripts from a cronjob on the NetBSD box running the
retrochallenge BBS:
$ crontab -l
SHELL=/bin/sh
MAILTO=msw
@hourly /home/msw/router/getstats
5,10,15,20,25,30,35,40,45,50,55 * * * * /home/msw/router/ping-internet.sh
5,10,15,20,25,30,35,40,45,50,55 * * * * /home/msw/router/plot-stats.sh
0,15,30,45 * * * * /home/msw/router/upload-stats.sh
Every five minutes the ping-internet.sh script attempts to ping one of the demon
nameservers using its' IP address:
#!/usr/pkg/bin/bash
LOGFILE=/home/msw/router/ping-stats.txt
TIME="`date +%C%y%m%d%H%M`"
/sbin/ping -c 1 158.152.1.58 > /dev/null 2>&1
if [ "$?" == "0" ]
then
STATUS=1
else
STATUS=0
fi
echo "$TIME $STATUS" >> $LOGFILE
This generates a line in the LOGFILE which looks like this:
200907091945 1
200907091950 1
200907091955 1
200907092005 1
200907092010 1
200907092015 1
200907092020 1
200907092025 1
200907092030 1
200907092035 1
where the first number is the date and time and the second number is a '1' if
the ping was successful, or a '0' if it was not.
The plot-stats.sh script turns these numbers into a nice graph with the help of
GnuPlot then puts the resulting jpeg onto the local apache webserver:
#!/usr/pkg/bin/bash
sleep 30
export PATH=/bin:/sbin:/usr/pkg/bin
export RS=/home/msw/router
export HTDOCS=/usr/pkg/share/httpd/htdocs
export STATS_FILE=$RS/ping-stats.txt
export JPG_FILE=ping-stats.jpg
export SHARE_DIR=/usr/local/archive
export HTTPD_DIR=/usr/pkg/share/httpd/htdocs
cp $STATS_FILE $RS/ping-stats-copy.txt
gnuplot $RS/plot-stats.gnuplot > $SHARE_DIR/$JPG_FILE
cp $SHARE_DIR/$JPG_FILE $HTTPD_DIR
The gnuplot script plot-stats.gnuplot that works the magic:
set terminal jpeg large size 1024, 600
#set terminal dumb
set title "Demon Internet HomeOffice 8000, hostname: waldo"
set lmargin 10
set rmargin 10
set tmargin 5
set bmargin 8
set xdata time
set format x "%d/%m"
set xlabel "Date, 2009" offset 0,-2
set ylabel "ADSL Status"
set yrange [-1:2]
set ytics 0,1,1 ("Off" 0, "On" 1)
set mxtics 6
set timefmt "%Y%m%d%H%M%S"
plot "/home/msw/router/ping-stats-copy.txt" using 1:2 with lines title
"Status at `date`"
#set title "ADSL status" offset 0,-10
# - generated on %Y%m%d %H%M"
show title
Then once every 1/4 hour the upload-stats.sh script pushes the stats up to my
remote web host (assuming the connection is up of course!)
#!/usr/pkg/bin/bash
cp /usr/local/archive/ping-stats.jpg /tmp
cd /tmp
ftp ftp://username:password@ftp.wickensonline.co.uk <<-END_OF_INPUT
bin
cd public_html
put ping-stats.jpg
dir
bye
END_OF_INPUT
The end result being this lovely image:
VAX MACRO Yeah!
What, another digression, surely not! So, without further ado, some VAX Macro:
TITLE: .ASCIZ /Computation of 6*(ALPHA)+(BETA)/<LF>
ALPHA: .LONG 3
BETA: .LONG 450
RESULT: .BLKL 1
BEGIN EXAMPLE
PRINTCHRS TITLE
DUMPLONG ALPHA,BETA
MULL3 #6,ALPHA,R5
ADDL3 R5,BETA,RESULT
DUMPLONG RESULT
EXIT
.END EXAMPLE
A sample, example 5.8[4] to be precise, from the Baase Assembly Language book.
The bits in bold are decidedly non-standard. They are macros, which must be
linked with the code. I don't like this way of doing such things - I understand
that it makes the examples easy to code and provides macros to do terminal input
and output, but it hides some of the nitty gritty which you're going to have to
come across sonner or later.
The build script[5] for this example assembles the example together with a macro
library:
$ library/create/macro iomac.mlb iomac.mar
$ macro/debug iomod+iomac/lib
$ macro/list/debug example5_8.mar+iomac/lib
$ link/debug example5_8,iomod
The macros themselves are in the IOMAC.MAR[6] file:
.MACRO BEGIN NAME
.ENTRY NAME,^M<IV>
;
$OPEN FAB=INFAB
$CONNECT RAB=INRAB
$CREATE FAB=OUTFAB
$CONNECT RAB=OUTRAB
$OPEN FAB=DISKFAB
$CONNECT RAB=DISKRAB
.ENDM BEGIN
.MACRO READLINE WHERETO
PUSHAB WHERETO
CALLS #1,RDLINE
.ENDM READLINE
.MACRO READRCRD WHERETO,?LBL
PUSHAB WHERETO
CALLS #1,RDRCRD
BNEQ LBL
BRW EOF
LBL: .ENDM READRCRD
.MACRO PRINTCHRS STRING,LENGTH=#85
CVTWL LENGTH,-(SP)
PUSHAB STRING
CALLS #2,PTCHRS
.ENDM PRINTCHRS
.MACRO DUMPLONG ARG1,ARG2,ARG3,ARG4,ARG5,ARG6-
ARG7,ARG8,ARG9,ARG10,ARG11,ARG12
CALLS #0,STARTDUMP
.IRP ARG,<ARG1,ARG2,ARG3,ARG4,ARG5,ARG6-
ARG7,ARG8,ARG9,ARG10,ARG11,ARG12>
.IF NOT_BLANK ARG
MOVQ #^A/%EXTRACT(0,8,ARG)/,-(SP)
PUSHL SP
PUSHL ARG
CALLS #2,CVTPRT
ADDL2 #8,SP
.ENDC
.ENDR
CALLS #0,ENDDUMP
.ENDM DUMPLONG
.MACRO EXIT
$CLOSE FAB=INFAB
$CLOSE FAB=OUTFAB
$CLOSE FAB=DISKFAB
$EXIT_S
.ENDM EXIT
.END
Finally, the code behind the macros in IOMOD.MAR[7]:
.PSECT IO_DATA,LONG,WRT,NOEXE
LF = 10
CR = 13
BLANK = ^A/ /
INFAB:: $FAB FNM=<SYS$INPUT>
OUTFAB:: $FAB FNM=<SYS$OUTPUT>,MRS=85
DISKFAB:: $FAB FNM=<DATA.DAT>
INRAB:: $RAB FAB=INFAB,USZ=80,-
ROP=PMT,PBF=PROMPT,PSZ=5
OUTRAB:: $RAB FAB=OUTFAB
DISKRAB:: $RAB FAB=DISKFAB,USZ=80
PROMPT: .ASCII <LF><CR>/?? /
; PROCEDURE RDLINE(WHERETO)
.PSECT IO_PROCS,NOWRT
.ENTRY RDLINE,0
MOVL 4(AP),INRAB+RAB$L_UBF
$GET RAB=INRAB
CVTWL INRAB+RAB$W_RSZ,R0
RET
; PROCEDURE RDRCRD(WHERETO)
.ENTRY RDRCRD,0
MOVL 4(AP),DISKRAB+RAB$L_UBF
$GET RAB=DISKRAB
CMPL DISKRAB+RAB$L_STS,#RMS$_EOF
BEQL EOF
CVTWL DISKRAB+RAB$W_RSZ,R0
RET
EOF: BISB2 #^X04,4(FP)
RET
; PROCEDURE PTCHRS(STRING,MAX_LEN)
CR_LF: .BYTE 13,10
.ENTRY PTCHRS,0
MOVAW CR_LF,OUTRAB+RAB$L_RBF
MOVW #2,OUTRAB+RAB$W_RSZ
$PUT RAB=OUTRAB
MOVL 4(AP),OUTRAB+RAB$L_RBF
LOCC #0,8(AP),@4(AP)
SUBL2 4(AP),R1
MOVW R1,OUTRAB+RAB$W_RSZ
$PUT RAB=OUTRAB
RET
; PROCEDURE DUMP_MSGS
HDR: .ASCIZ /** DUMPLONG OUTPUT **/
STARS: .ASCIZ /** END DUMPLOG **/
.ENTRY STARTDUMP,0
PRINTCHRS HDR
RET
.ENTRY ENDDUMP,0
PRINTCHRS STARS
RET
; PROCEDURE CVTPRT (LONG,NAME)
.PSECT IO_DATA
LONG: .BLKL 1
DUMP: .BLKB 18
.PSECT IO_PROCS
DESC: .LONG ^X010E0008
.ADDRESS DUMP+10
ARGS: .LONG 3
.ADDRESS LONG,DESC
.LONG 8
.ENTRY CVTPRT,^M<R2,R3,R4,R5>
MOVC5 #0,0,#BLANK,#10,DUMP
LOCC #0,#8,@8(AP)
SUBL3 R0,#8,R2
MOVC3 R2,@8(AP),DUMP
MOVL 4(AP),LONG
CALLG ARGS,G^OTS$CVT_L_TZ
PRINTCHRS DUMP,#18
RET
.END
OK, so that's me done for the evening. Hopefully, my DECserver(s) will arrive
shortly and I can be submerged in VT terminal heaven for the coding proper!
ENDNOTES
1.VAX RTL Mathematics Manual
2.VAX RTL General Purpose Manual
3.Gnuplot Home Page
4.EXAMPLE5_8.MAR
5.build.com
6.IOMAC.MAR
7.IOMOD.MAR