Last active
June 18, 2017 16:25
-
-
Save shirriff/323b71e0dd24e58f3b0993ba67009515 to your computer and use it in GitHub Desktop.
Mandelbrot set code for the Xerox Alto, written in BCPL.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
get "streams.d" | |
external | |
[ | |
Ws; | |
Wns; | |
MulFull; | |
DoubleAdd; | |
keys; | |
Gets; | |
] | |
let Main() be | |
[ | |
let v = vec 30705 // Pixel buffer | |
v = (v + 1) & -2 // Data needs to be 32-bit aligned | |
let dcb = vec 5 // Display control block: defines display region | |
dcb = (dcb + 1) & -2 | |
dcb!0 = 0 // End of display list | |
dcb!1 = 38 // 38 words per line | |
dcb!2 = v // Data pointer | |
dcb!3 = 404 // # lines / 2 | |
let lvdas = #420 // Address holds pointer to display control block | |
lvdas!0 = dcb | |
for i = 0 to 30703 do v!i = 0 // Clear display | |
// Values are represented as fixed point with 12 bits to right of decimal point. | |
let x0 = (-2) lshift 12 // Left boundary: x = -2 | |
let x1 = 1 lshift 12 // Right boundary: x = 1 | |
let y0 = (-1) lshift 12 // Top boundary: y = -1 | |
let y1 = 1 lshift 12 // Bottom boundary: y = 1 | |
let xstep = (x1 - x0) / 600 // Render 600 pixels horizontally | |
let ystep = (y1 - y0) / 400 // Render 400 pixels vertically | |
let x2 = vec 2 // double word to hold x^2 | |
let y2 = vec 2 // double word to hold y^2 | |
let xy = vec 2 // double word to hold x * y | |
let cy = y0 // Constant value, y part. I.e. the z value for this pixel | |
for ypos = 0 to 400 do // line count. Note "for" limits are inclusive. | |
[ | |
let cx = x0 // Constant value, x part. | |
for h = 0 to 37 do // horizontal word count | |
[ | |
for b = 0 to 15 do // horizontal bit count | |
[ | |
let x = cx // The complex z value is represented as x + i*y | |
let y = cy | |
for n = 0 to 999 do // Will bail out long before 999 | |
[ | |
MulFull(y, y, y2) // y2 = y*y. Integer multiplication, y2 is double word. | |
MulFull(x, x, x2) // x2 = x*x | |
if x2!0 + y2!0 ge 1024 then break // Quit if x^2 + y^2 > 4 | |
if n eq 20 then // Last iteration. Still inside set, so set pixel. | |
[ | |
let adr = (200 + ypos) * 38 + h // 200 blank pixels at top, 38 words per line | |
v!adr = v!adr % (1 lshift (15-b)) | |
break | |
] | |
// Convert to single precision by dropping 12 bits. | |
// rshift 12 = lshift top word 4 | |
let x2sp = (x2!0 lshift 4) % (x2!1 rshift 12) // x2sp = x^2, single precision | |
let y2sp = (y2!0 lshift 4) % (y2!1 rshift 12) // y2sp = y^2, single precision | |
MulFull(x, y, xy) // xy = x*y | |
let xysp = (xy!0 lshift 4) % (xy!1 rshift 12) // xysp = x*y, single precision | |
// z = z^2 + c (complex arithmetic, z = x+iy) | |
// i.e. y = 2xy + cy | |
// x = x^2 - y2 + cx | |
y = xysp + xysp + cy | |
x = x2sp - y2sp + cx | |
] | |
cx = cx + xstep // Move to next cx value | |
] | |
] | |
cy = cy + ystep // Move to next cy value | |
] | |
Gets(keys) // Get a key, i.e. wait for a keypress | |
] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment