' mandelbrot-20170604

con
  _clkmode = xtal1+pll16x
  _clkfreq = 80_000_000

  xmin=round(-2.1*float(1<<24))
  xmax=round( 0.7*float(1<<24))

  ymin=round(-1.2*float(1<<24))
  ymax=round( 1.2*float(1<<24))

  maxiter=32

  MPX=256 ' 0..MPX
  MPY=192 ' 0..MPY

  c4=4<<24

  MAX_PARALLEL = 2
  COGSTACKLENGTH = 100


obj
  ios: "reg-ios"

dat
' SHM - shared memory


  lkBus       long      -1      ' Semaphore fuer Buszugriffe
  lkShm       long      -1      ' Semaphore fuer Zugriffe auf den gemeinsamen Speicher

  dx          long      0       ' Delta-Z, x-Anteil
  dy          long      0       ' Delta-Z, y-Anteil

  px          long      0       ' zu berechnendes Pixel, x-Anteil
  py          long      0       ' zu berechnendes Pixel, y-Anteil, -1 bedeutet Ende

  strParallel byte      "parallel "
  numParallel byte      "9", 0
  strParallelEnd

  '''DEBUG
  strEnde byte      "Ende", 0
  strEndeEnd

var
  long  stack[MAX_PARALLEL * COGSTACKLENGTH]

pub apfel
  ios.start
  ios.g0_load
  !outa[ios#HBEAT]
  waitcnt(cnt+clkfreq*3)
  screenset1                                            'farben und tiles setzen
  ios.g0_static

  ios.g0_clear
  ios.g0_width(0)

  dx := (xmax - xmin) / MPX
  dy := (ymax - ymin) / MPY

  lkBus := locknew
  lkShm := locknew
  if lkShm > -1
    start_parallel
    lockret(lkShm)

  if lkBus > -1
    lockret(lkBus)

  pr_ende '''DEBUG

  repeat 100
    ' 100 ms warten
    !outa[ios#HBEAT]
    waitcnt(_clkfreq / 10 + cnt)
'    if ios.keystat > 0
'      quit

  ios.stop

pri getNextPixel (addr_p)
  repeat while lockset(lkShm)
  if (py > -1 and ++px => MPX)
    px := 0
'    !outa[ios#HBEAT]  '''DEBUG
    if (++py => MPY)
      py := -1
  long[addr_p] := px
  long[addr_p][1] := py
  lockclr(lkShm)

pri drawPixel(x, y, c, is_slave)
  repeat while lockset(lkBus)
  ifnot is_slave  '''DEBUG
    ' 23.7.2017: Es nützt nichts, dira nach dem Buszugriff auf 0 zu setzen:
    '  Sobald ein Slave den Bus benutzt, bleibt das Programm stehen oder
    '  produziert Mist auf dem Bildschirm. :-(
    ios.g0_color(c)
    ios.g0_plot(x, y)
  dira := 0 'ios#db_in
  lockclr(lkBus)

pri julia(ix, iy): color | cx, cy, x, y, xn, rsq, iter
  ' Pixel -> Z
  cx := xmin + ix * dx
  cy := ymin + iy * dy

  ' Berechnung
  x := y := rsq := 0
  iter := maxiter
  repeat while iter and rsq =< c4
    xn := ((fpm(x, x) - fpm(y, y))) + cx
    y := 2 * fpm(x, y) + cy
    x := xn
    rsq := fpm(x, x) + fpm(y, y)
    iter--

  ' Farbauswahl
  if iter > 24
    color := 3
  elseif iter > 16
    color := 2
  elseif iter > 8
    color := 1
  else
    color := 0

pri worker(is_slave) | lpx, lpy, color
  if is_slave
    dira := 0
  repeat
    getNextPixel(@lpx)
    if lpy == -1
      if is_slave
        cogstop(cogid)
      else
        return
    color := julia(lpx, lpy)
    drawPixel(lpx, lpy, color, is_slave)


pri pr_parallel_degree(deg)
  repeat while lockset(lkBus)
  ios.g0_color(1)
  ios.g0_textmode(1, 1, 6, 0)
  byte[@numParallel] := deg + "0"
  ios.g0_datblk(@strParallel, 0, @strParallelEnd - @strParallel)
  ios.g0_text(10, 175, 0)
  lockclr(lkBus)

'''DEBUG
pri pr_ende
  ios.g0_color(1)
  ios.g0_textmode(1, 1, 6, 0)
  ios.g0_datblk(@strEnde, 0, @strEndeEnd - @strEnde)
  ios.g0_text(10, 10, 0)

pri start_parallel | i, lpx, lpy, color
  if MAX_PARALLEL > 1
    repeat i from 0 to MAX_PARALLEL - 2
      ifnot cognew(worker(TRUE), @stack[i * COGSTACKLENGTH]) + 1
        quit

  pr_parallel_degree(i + 1)

  ' letzter Worker
'  worker(FALSE)
  repeat until py == -1  '''DEBUG, wenn letzter Worker auskommentiert wird


con

'
'           AAAAAAAAaaaaaaaaaaaaaaaaaaaaaaaa
' *         BBBBBBBBbbbbbbbbbbbbbbbbbbbbbbbb
'           ================================
' = CCCCCCCCCCCCCCCCcccccccccccccccccccccccccccccccccccccccccccccccc
'   \______________  ______________/\______________  ______________/
'                  \/                              \/
'              SChi:=SA**SB                    SClo:=SA*SB
'
pri fpm(SA,SB) | SClo
  SClo:=(SA*SB)
  return (SA**SB)<<8 | SClo.byte[0]


con

disp_base     = $5000

var
  'achtung, folgende reihenfolge darf nicht verändert werden!
  word              screen[ios#g0_xtiles * ios#g0_ytiles]         'tilemap
  long              colortab[64]                      'farbregister

PUB screenset1|i,tx,ty

  'tilescreen setzen
  repeat tx from 0 to ios#g0_xtiles - 1
    repeat ty from 0 to ios#g0_ytiles - 1
      screen[ty * ios#g0_xtiles + tx] := disp_base >> 6 + ty + tx * ios#g0_ytiles + ((ty & $3F) << 10)

  'farbtabelle füllen
  repeat i from 0 to 63
    colortab[i] := $0D060802

  ios.g0_colortab(@colortab)
  ios.g0_screen(@screen)

