wickensonline.co.uk Retrochallenge 2009 Summer Challenge Entry Miller-time |
Retrochallenge 2009
Summer Challenge
Mark Wickens
18-Jul-2009
Miller Time?
This will have to be a short post because bed becons. After the hardware traumas
of yesterday I stuck at what I'm best at and continued the program development.
Actually, the title 'Mandelbrot Generator' is a bit misleading, a more accurate
title would be 'Transcendental Function in the u plane Generator', but we won't
split hairs, eh?
Having done the first run which was setup to generate a data tuple for each of a
1000x1000 real/imaginary grid I was coming to the realisation that this might
take some time when ALLIN1 asked me 'did I really want to copy that file because
disk space was running low' - yes, I'd filled my DATA disk in about 20 minutes.
Note from the MONITOR SYSTEM capture shown below the program was primarly bound
by the IO time required to write the data out in ASCII by capturing SYS$OUTPUT.
I remembered the commands straight off to do this, even thought it must be some
16 years since I last did it:
$ DEFINE SYS$OUTPUT MBRT1.OUT
$ RUN MBRT1
$ DEASSIGN SYS$OUTPUT
Node: ORAC OpenVMS Monitor Utility 18-JUL-2009 21:55:25
Statistic: CURRENT SYSTEM STATISTICS
Process States
+ CPU Busy (62) -+ LEF: 7 LEFO: 0
|**************** | HIB: 30 HIBO: 0
CPU 0 |--------------------------| 100 COM: 1 COMO: 0
|********* | PFW: 0 Other: 2
+--------------------------+ MWAIT: 0
Cur Top: _TNA3: (37) Total: 40
+ Page Fault Rate (0) -+ + Free List Size (65336) +
|| | |************ | 136K
MEMORY 0 |--------------------------| 500 0 |--------------------------|
| | |******** | 13K
+--------------------------+ + Mod List Size (4394) +
Cur Top: (0)
+ Direct I/O Rate (837) -+ + Buffered I/O Rate (2) -+
|**************************| | |
I/O 0 |--------------------------| 500 0 |--------------------------| 500
|**************************| | |
+--------------------------+ +--------------------------+
Cur Top: _TNA3: (837) Cur Top: _TNA3: (2)
So I set my sights slightly lower with a 100x100 grid covering the same portion
of the complex plane, and this only took a couple of minutes. In the meantime
I'd not had a lot of success getting gnuplot[1] to compile under OpenVMS, so I
resorted to copying the data file over to the NetBSD box running the retrobbs.
The contents of the file look like (real imaginary value):
-0.100000E+01 -0.100000E+01 0.100000E+01
-0.100000E+01 -0.990000E+00 0.100000E+01
-0.100000E+01 -0.980000E+00 0.100000E+01
-0.100000E+01 -0.970000E+00 0.100000E+01
My gnuplot file ended up containing:
set terminal jpeg large size 1024, 600
set title "MBRT1 - Chaotic Dusty Curls generator in VAX Macro"
set xrange [-1:1]
set yrange [-1:1]
splot "mbrt1.out" using 1:2:3 '%lf %lf %lf' lt 3 pt 5 ps 0.25 lc palette z
show title
Which produces the following somewhat mysterous output:
This is a grid data plot which is quite pretty but admittedly sucks a bit - I
really need to now persue two immediate directions:
1. Generate output in a format more suitable for gnuplot or persue other
options for output.
2. Investigate how to create the output in binary format which should speed up
the output I/O time and make the process CPU bound.
Apologies for missing the hunt, but hopefully a pretty graph will make up for it
a bit.
Finally, the current code now looks like this:
.TITLE Chaotic Dusty Curls Generation Using VAX Macro
;++
; This program will produce a set of coordinate and value tuples
; for a window on a Mandelbrot set to the standard output.
;
; References:
; VAX Macro and Instruction Set Reference Manual
; VMS Run-Time Library (LIB$) Reference Manual
; VMS System Services Reference Manual
; VMS Run-Time Math Library (MTH$) Reference Manual
; Sara Baase 'VAX Assembler Language Programming'
;
; Author : Mark Wickens
; Date : 11-Jul-2009
;--
; 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;
;--
; Define symbols, constants, etc. used in this module
; Debugging aids
; Debug the inner loop by outputting each value calculated for sqrt(rz**2 + iz**2)
DEBUG_INNER = 0
; Offset in bytes in real/imaginary pair of the real and imaginary value
COMP_REAL = 0
COMP_IMAG = 4
.PSECT MBRT1_RWDATA WRT,NOSHR,NOEXE,PAGE
.ALIGN LONG
; Real and imaginary values for constant 'u'
U: .F_FLOATING 0.74, 0.11
; Convergence test 1, comparison value
CONV1_MAX: .F_FLOATING 4.0
; Real axis dimensions and increment
RRZ_MIN: .F_FLOATING -1.0
RRZ_MAX: .F_FLOATING 1.0
RRZ_INC: .F_FLOATING 0.01
POW2: .LONG 2
; Imaginary axis dimensions and increment
IIZ_MIN: .F_FLOATING -1.0
IIZ_MAX: .F_FLOATING 1.0
IIZ_INC: .F_FLOATING 0.01
TWOF: .F_FLOATING 2.0
; Number of iterations to perform in convergence loop
LOOP_MAX = 100
; Convergence test to use
CONV_TEST_VALUE = 1
; Output buffer maximum size
MAX_SIZE = 132
; Fortran E Format buffer max size
FEF_MAX_SIZE = 16
; Setup a text buffer for use as an output line
OUT_BUFFER: .BLKB MAX_SIZE
OUT_DESC: .WORD MAX_SIZE
.BYTE DSC$K_DTYPE_T
.BYTE DSC$K_CLASS_S
.ADDRESS OUT_BUFFER
FEF_BUFFER: .BLKB FEF_MAX_SIZE
FEF_DESC: .WORD FEF_MAX_SIZE
.BYTE DSC$K_DTYPE_T
.BYTE DSC$K_CLASS_S
.ADDRESS FEF_BUFFER
FEF_VAL: .F_FLOATING 0.0
ASC_SPACE: .ASCII / /
NULL = 00
ASC_NULL: .ASCII <NULL>
; Allocate a longword to store any failure status value we might see
ERROR_CODE: .BLKL 1
; Real axis loop counter
RRZ: .BLKF 1
; Imaginary axis loop counter
IIZ: .BLKF 1
; Z Complex value (real/imaginary pair)
Z: .BLKF 2
; Complex temporary
COMP_TEMP: .BLKF 2
RZ: .BLKF 1
IZ: .BLKF 1
RZPOW2: .BLKF 1
IZPOW2: .BLKF 1
SQRTZ: .BLKF 1
ZPOW2: .BLKF 1
COLOUR: .BLKF 1
; Convergence test
CONV_TEST: .BYTE CONV_TEST_VALUE
.PSECT MBRT1_CODE NOWRT,SHR,EXE,PAGE
.ALIGN PAGE
;*******************************************************************************
; Program Entry Point
;*******************************************************************************
.ENTRY MBRT1,^M<R2,R3,R4,R5,R7>
; Initialize
START:
MOVB #SS$_NORMAL, ERROR_CODE ; error code to normal
MOVB #CONV_TEST_VALUE, CONV_TEST ; convergence test to use
MOVF RRZ_MIN, RRZ ; init real axis value
RRZ_LOOP:
MOVF IIZ_MIN, IIZ ; init imaginary axis value
; Set value of complex variable Z, stored in R2
IIZ_LOOP:
MOVAF Z, R2
MOVF RRZ, COMP_REAL(R2)
MOVF IIZ, COMP_IMAG(R2)
; Initialize inner loop counter, stored in R3
MOVL #1, R3
; Within loop
LOOP:
; z**2
PUSHL POW2
PUSHL COMP_IMAG(R2)
PUSHL COMP_REAL(R2)
CALLS #3, G^OTS$POWCJ
MOVAF COMP_TEMP, R4
MOVF R0, COMP_REAL(R4)
MOVF R1, COMP_IMAG(R4)
;R4 now contains address of z**2, COMP_TEMP
;; z = z**2 + u
MOVAL U, R5
ADDF3 COMP_IMAG(R4), COMP_IMAG(R5), COMP_IMAG(R2)
ADDF3 COMP_REAL(R4), COMP_REAL(R5), COMP_REAL(R2)
; rz = real(z)
MOVF COMP_REAL(R2), RZ
; iz = imag(z)
MOVF COMP_IMAG(R2), IZ
MULF3 RZ, RZ, RZPOW2
MULF3 IZ, IZ, IZPOW2
ADDF3 RZPOW2, IZPOW2, R5
; R5 = rz**2 + iz**2
MOVF R5, ZPOW2
PUSHAF ZPOW2
CALLS #1, G^MTH$SQRT
MOVF R0, SQRTZ
; R0 = SQRT(rz**2 + iz**2)
.IF DEFINED DEBUG_INNER
PUSHAL SQRTZ
CALLS #1, G^FLOAT2STR
.ENDC
CMPF SQRTZ, TWOF
BGTR EXIT_LOOP
CMPL #LOOP_MAX, R3
BEQLU EXIT_LOOP
ADDL #1, R3
JMP LOOP
EXIT_LOOP:
CVTLF R3, COLOUR
JSB CONVERGENCE_TEST
; IIZ = IIZ + IIZ_INC
ADDF3 IIZ, IIZ_INC, IIZ
; IF IIZ < IIZ_MAX THEN GOTO iiz_loop
CMPF IIZ, IIZ_MAX
BGTR EXIT_IIZ_LOOP
JMP IIZ_LOOP
EXIT_IIZ_LOOP:
ADDF3 RRZ, RRZ_INC, RRZ
; if rrz < rrz_max then goto rrz_loop
CMPF RRZ, RRZ_MAX
BGTR EXIT_RRZ_LOOP
JMP RRZ_LOOP
CONVERGENCE_TEST:
CMPF R5, CONV1_MAX
BLEQ CONVERGENCE_TEST_END
JSB PRINTDOT
CALLS #0, PRTSTR
CONVERGENCE_TEST_END:
RSB
EXIT_RRZ_LOOP:
; Normal Exit
MOVL #SS$_NORMAL, ERROR_CODE
BRB COMMON_EXIT
FAILURE_EXIT:
MOVL R0, ERROR_CODE
MOVW #MAX_SIZE, OUT_DESC
PUSHAQ OUT_DESC
PUSHAW OUT_DESC
PUSHAL ERROR_CODE
CALLS #3, G^LIB$SYS_GETMSG
PUSHAQ OUT_DESC
CALLS #1, G^LIB$PUT_OUTPUT
COMMON_EXIT:
$EXIT_S ERROR_CODE
;---------------------------------------------------
PRINTDOT:
PUSHAL RRZ
CALLS #1, FLOAT2STR
; Append string to the output buffer
MOVC3 #FEF_MAX_SIZE, FEF_BUFFER, OUT_BUFFER
MOVC3 #1, ASC_SPACE, OUT_BUFFER+16
PUSHAL IIZ
CALLS #1, FLOAT2STR
MOVC3 #FEF_MAX_SIZE, FEF_BUFFER, OUT_BUFFER+17
MOVC3 #1, ASC_SPACE, OUT_BUFFER+33
PUSHAL COLOUR
CALLS #1, FLOAT2STR
MOVC3 #FEF_MAX_SIZE, FEF_BUFFER, OUT_BUFFER+34
MOVC3 #1, ASC_NULL, OUT_BUFFER+50
; Set the length
MOVW #50, OUT_DESC
RSB
;---------------------------------------------------
; Convert float to string
.ENTRY FLOAT2STR,^M<>
MOVL @4(AP),FEF_VAL
MOVW #FEF_MAX_SIZE, FEF_DESC
PUSHL #6
PUSHAQ FEF_DESC
PUSHAQ FEF_VAL
CALLS #3, G^OTS$CNVOUT
RET
;---------------------------------------------------
; Output string to terminal
.ENTRY PRTSTR,^M<>
PUSHAQ OUT_DESC
CALLS #1, G^LIB$PUT_OUTPUT
RET
.END MBRT1
ENDNOTES
1. gnuplot home page