FastSpin

Table of Contents

1 Famous First Words

This is work in progress and will change often and massively without prior notice.

I'm assimilating my FastSpin related snippets, programs, thoughts and whatsoever into this EMACS Orgmode document admittedly with far too few comments and explanations so reading more about FastSpin in Parallax's forum and FastSpin's own source and documentation is a better start than this place.

Still being new to Orgmode, I have to find out a lot of things about how to manage HOWTO like documents containing lots of active code snippets and complete programs.

It sure will take some time until it all settles down.

1.1 Forum Threads

fastspin compiler for P2: Assembly, Spin, BASIC, and C in one compiler
https://forums.parallax.com/discussion/164187

New BASIC compiler for Prop1 and Prop2
https://forums.parallax.com/discussion/168913

FlexGUI 4.0.3: a complete programming system for P2 (and P1)
https://forums.parallax.com/discussion/170730

Testing the new Fastspin Assembly, Spin, BASIC, and C for P1
https://forums.parallax.com/discussion/169141

1.2 Use the Source, Luke!

"Use the Source, Luke!" shall not mean you have to compile everything on your own. Typically you will find compiled bundles and documentation in these locations too and if something does not behave as expected, you should find issue trackers in the sources repositories.

2 Appetiser

2.1 FlexSPIN

This example would compile with other Spin compilers too. A pure FlexSPIN example could look different. See minimal.spin for some hints.

File hello.spin:

con
  _clkmode = xtal1+pll16x
  _clkfreq = 80_000_000

obj
  ser : "spin/FullDuplexSerial"

pub main

  ser.start(31, 30, 0, 115200)

  ser.str(string("Hello, FlexSPIN!",13,10))

  waitcnt(_clkfreq + cnt)
  ser.stop

  cogstop(0)

Compile to hello.spin.binary:

fastspin -O2 hello.spin -o hello.spin.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
hello.spin
|-FullDuplexSerial.spin
hello.spin.pasm
Done.
Program size is 1692 bytes

Run the result in spinsim:

spinsim -b hello.spin.binary
Hello, FlexSPIN!

2.2 FlexBASIC

File hello.bas:

print"Hello, FlexBASIC!"

Compile to hello.bas.binary:

fastspin -O2 hello.bas -o hello.bas.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
hello.bas
fmt.c
strlen.c
hello.bas.pasm
Done.
Program size is 1796 bytes

Run the result in spinsim:

spinsim -b hello.bas.binary
Hello, FlexBASIC!

2.3 FlexC

File hello.c:

#include <stdio.h>

void main( void )
{
    printf("Hello, FlexC!\n");
}

Compile to hello.c.binary:

fastspin -O2 hello.c -o hello.c.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
hello.c
fmt.c
strlen.c
hello.c.pasm
Done.
Program size is 1792 bytes

Run the result in spinsim:

spinsim -b hello.c.binary
Hello, FlexC!

3 FastSpin - The Program

Assuming you have fastspin installed in a directory being mentioned in your PATH variable:

fastspin
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
usage: fastspin [options] filename.spin | filename.bas
  [ -h ]              display this help
  [ -L or -I <path> ] add a directory to the include path
  [ -o <name> ]      set output filename to <name>
  [ -b ]             output binary file format
  [ -e ]             output eeprom file format
  [ -c ]             output only DAT sections
  [ -l ]             output DAT as a listing file
  [ -f ]             output list of file names
  [ -q ]             quiet mode (suppress banner and non-error text)
  [ -p ]             disable the preprocessor
  [ -D <define> ]    add a define
  [ -u ]             ignore for openspin compatibility (unused method elimination always enabled)
  [ -2# ]             compile for Prop2
          -2a = original silicon
          -2b = rev B silicon
  [ -O# ]            set optimization level:
          -O0 = no optimization
          -O1 = basic optimization
          -O2 = all optimization
  [ -H nnnn ]        set starting hub address
  [ -E ]             skip initial coginit code (usually used with -H)
  [ -w ]             compile for COG with Spin wrappers
  [ -C ]             enable case sensitive mode
  [ -x ]             capture program exit code (for testing)
  [ -z ]             compress code
  [ --code=cog ]     compile for COG mode instead of LMM
  [ --fcache=N ]     set FCACHE size to N (0 to disable)
  [ --fixedreal ]    use 16.16 fixed point in place of floats
  [ --lmm=xxx ]      use alternate LMM implementation for P1
           xxx = orig uses original fastspin LMM
           xxx = slow uses traditional (slow) LMM

4 Unsorted Snippets and Examples

As long as I have no better idea, the examples are sorted by their hopefully meaningful filenames.

4.1 FlexSPIN

4.1.1 conditional-expression-demo1.spin

@@@TODO@@@ Find a nicer example.

FlexSPIN documentation: conditional-expressions(FlexSPIN)

File conditional-expression-demo1.spin:

con
  _clkmode = xtal1+pll16x
  _clkfreq = 80_000_000

obj
  ser : "spin/FullDuplexSerial"

pub main

  ser.start(31, 30, 0, 115200)

  ser.dec( ( 1 < 2 ) ? 1 : 0 ) 
  ser.str(string(13,10))

  ser.dec( ( 1 > 2 ) ? 1 : 0 ) 
  ser.str(string(13,10))

  waitcnt(_clkfreq + cnt)
  ser.stop

  cogstop(0)

Compile to conditional-expression-demo1.spin.binary:

fastspin -O2 conditional-expression-demo1.spin -o conditional-expression-demo1.spin.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
conditional-expression-demo1.spin
|-FullDuplexSerial.spin
conditional-expression-demo1.spin.pasm
Done.
Program size is 2248 bytes

Run it in spinsim:

spinsim -b conditional-expression-demo1.spin.binary
1
0

4.1.2 conditional-expression-demo2.spin

FlexSPIN documentation: conditional-expressions(FlexSPIN)

File conditional-expression-demo2.spin:

con
  _clkmode = xtal1+pll16x
  _clkfreq = 80_000_000

obj
  ser : "spin/FullDuplexSerial"

pub main

  ser.start(31, 30, 0, 115200)

  ser.dec( ( 1 < 2 ) ? a : b )
  ser.str(string(13,10))

  waitcnt(_clkfreq + cnt)
  ser.stop

  cogstop(0)

pri a
  ser.str(string("called a",13,10))
  return 1

pri b
  ser.str(string("called b",13,10))
  return 2

Compile to conditional-expression-demo2.spin.binary:

fastspin -O2 conditional-expression-demo2.spin -o conditional-expression-demo2.spin.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
conditional-expression-demo2.spin
|-FullDuplexSerial.spin
conditional-expression-demo2.spin.pasm
Done.
Program size is 2252 bytes

Run it in spinsim:

spinsim -b conditional-expression-demo2.spin.binary
called a
1

No called b shows up. That's what we want!

4.1.3 Hybrid FlexSPIN/OpenSpin Programs

These examples show using objects compiled by FastSpin in OpenSpin programs.

4.1.3.1 hybrid-tx.spin

FastSpin documentation: spin-wrappers(FastSpin).

File hybrid-tx.spin:

''
'' tx only uart - pin and baud hardcoded
''
CON
  txpin  = 30
  baud   = 115200
  txmask = 1 << txpin

VAR
  long t_fullbit

PUB start
  t_fullbit := clkfreq / baud
  OUTA      |= txmask                   ' line idle = 1
  DIRA      |= txmask                   ' set for output

PUB stop                                ' to complete the start/stop duality

PUB tx(c) | t_next
  c := (c | 256) << 1                   ' 1_dddddddd_0
  t_next := CNT                         ' remember now
  repeat 10
    if c & 1
      OUTA |= txmask
    else
      OUTA &= !txmask
    c >>= 1
    waitcnt(t_next += t_fullbit)       ' until old t_next plus a bit's duration

Compile to hybrid-tx.cog.spin:

fastspin -O2 -w hybrid-tx.spin
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
hybrid-tx.spin

4.1.3.2 hybrid-tx-test.spin

File hybrid-tx-test.spin:

con
  _clkmode = xtal1 + pll16x
  _xinfreq = 5_000_000

obj
  out : "hybrid-tx.cog.spin"

pub main
  out.__cognew
  out.start

  repeat 3
    str(string("Hello Spin!", 13, 10))

  out.__cogstop

pub str(s) | c
  repeat while c := byte[s++]
    out.tx(c)

Compile to hybrid-tx.openspin.binary:

openspin -u hybrid-tx-test.spin -o hybrid-tx-test.openspin.binary
Propeller Spin/PASM Compiler 'OpenSpin' (c)2012-2018 Parallax Inc. DBA Parallax Semiconductor.
Version 1.00.81 Compiled on Oct 15 2019 02:25:19
Compiling...
hybrid-tx-test.spin
|-hybrid-tx.cog.spin
Done.
Unused Method Elimination:
    2 methods removed
    0 objects removed
   28 bytes saved
--------------------------
Program size is 656 bytes

Run it in spinsim:

spinsim -b hybrid-tx-test.openspin.binary
Hello Spin!
Hello Spin!
Hello Spin!

4.1.3.3 hybrid-rx.spin

FastSpin documentation: spin-wrappers(FastSpin).

File hybrid-rx.spin:

Runing this receiver in an own cog just speeds it up. It still is not asynchronous and will receive only when rx is called and so it still can miss input data.

Writing the final and perfect FullDuplexSerial variant was not the focus of this example. ;-)

''
'' rx only uart - pin and baud hardcoded
''
CON
  rxpin  = 31
  baud   = 115200
  rxmask = 1 << rxpin

VAR
  long t_fullbit
  long t_halfbit

PUB start
  t_fullbit := clkfreq / baud           ' duration of a bit in clock cycles
  t_halfbit := t_fullbit >> 1           ' duration of a halfbit in clock cycles
  DIRA      &= !rxmask                  ' set for input

pub stop                                ' to complete the start/stop duality

PUB rx : c | t_next
  waitpeq(0, rxmask, 0)                 ' wait for 0 (start of start bit)
  t_next := CNT + t_halfbit             ' ignore to middle of start bit
  c := 0
  repeat 8
    c >>= 1
    waitcnt(t_next += t_fullbit)        ' wait 1 bit length
    if INA & rxmask                     ' check rx
      c |= $80
  waitcnt(t_next += t_halfbit)          ' wait 2nd halfbit of 8th bit

Compile to hybrid-rx.cog.spin:

fastspin -O2 -w hybrid-rx.spin
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
hybrid-rx.spin

4.1.3.4 hybrid-rx-test.spin

File hybrid-rx-test.spin:

con
  _clkmode = xtal1 + pll16x
  _xinfreq = 5_000_000

obj
  in  : "hybrid-rx.cog.spin"
  out : "hybrid-tx.cog.spin"

pub main | c
  in.__cognew
  in.start
  out.__cognew
  out.start

  repeat
    c := in.rx
    if c == 27
      quit
    if c
      out.tx(c)

  out.__cogstop
  in.__cogstop

Compile to hybrid-tx.openspin.binary:

openspin -u hybrid-rx-test.spin -o hybrid-rx-test.openspin.binary
Propeller Spin/PASM Compiler 'OpenSpin' (c)2012-2018 Parallax Inc. DBA Parallax Semiconductor.
Version 1.00.81 Compiled on Oct 15 2019 02:25:19
Compiling...
hybrid-rx-test.spin
|-hybrid-rx.cog.spin
|-hybrid-tx.cog.spin
Done.
Unused Method Elimination:
    4 methods removed
    0 objects removed
   56 bytes saved
--------------------------
Program size is 1272 bytes

Run it in spinsim:

( for c in S u r p r i s e . . . '\e' ; do
    sleep 0.01
    printf $c
  done
) | spinsim -b hybrid-rx-test.openspin.binary
Surprise...

4.1.4 inline-asm.spin

FlexSPIN documentation: inline-assembly(FlexSPIN)

File inline-asm.spin:

con
  _clkmode = xtal1+pll16x
  _clkfreq = 80_000_000

obj
  ser : "spin/FullDuplexSerial"

pub main
  ser.start(31,30,0,115200)

  ser.str(string("the answer is "))
  ser.dec(answer(14))
  ser.str(string(13,10))

  waitcnt(_clkfreq+cnt)
  ser.stop
  cogstop(0)

pub answer(question)
  asm
	  mov     result, question        ' result as target
	  add     result, result          ' result as source too
	  add     result, question
  endasm

Compile to inline-asm.spin.binary:

fastspin -O2 inline-asm.spin -o inline-asm.spin.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
inline-asm.spin
|-FullDuplexSerial.spin
inline-asm.spin.pasm
Done.
Program size is 2248 bytes

Run it in spinsim:

spinsim -b inline-asm.spin.binary
the answer is 42

4.1.5 inline-asm-loop-unroll.spin

FlexSPIN documentation: inline-assembly(FlexSPIN)

@@@TODO@@@ the PASM loop unrolling is not specific to using Spin as outer envelope. Maybe expamples focussing on PASM and inline PASM better should get an own section…

File inline-asm-loop-unroll.spin:

' see https://forums.parallax.com/discussion/comment/1177581/#Comment_1177581

con
  _clkmode = xtal1+pll16x
  _clkfreq = 80_000_000

obj
  ser : "spin/FullDuplexSerial"

pub main | r,t,d,d1,d2
  ser.start(31,30,0,115200)

  d1:=r?
  d2:=r?

  ser.str(string("d1,d2        ... "))
  ser.dec(d1)
  ser.tx(",")
  ser.dec(d2)
  ser.str(string(13,10))

  t:=cnt
  d:=d1*d2
  t:=cnt-t
  ser.str(string("internal     ... "))
  ser.dec(t)
  ser.str(string(13,10))

  t:=cnt
  d:=mul1(d1,d2)
  t:=cnt-t
  ser.str(string("assembler(1) ... "))
  ser.dec(t)
  ser.str(string(13,10))

  t:=cnt
  d:=mul2(d1,d2)
  t:=cnt-t
  ser.str(string("assembler(2) ... "))
  ser.dec(t)
  ser.str(string(13,10))

  t:=cnt
  d:=mul4(d1,d2)
  t:=cnt-t
  ser.str(string("assembler(4) ... "))
  ser.dec(t)
  ser.str(string(13,10))

  waitcnt(_clkfreq+cnt)
  ser.stop
  cogstop(0)

pub mul1(v1,v2):vres
  asm
	      abs       v1, v1 wc
	if_c  neg       v2, v2
	      abs       v2, v2 wc
	      mov       vRes, v2
	      min       v2, v1
	      max       v1, vRes
	if_c  neg       v2, v2
	      mov       vRes, #0
  :loop       shr       v1, #1 wc, wz
	if_c  add       vRes, v2
	      shl       v2, #1
	if_nz jmp       #:loop
  endasm

pub mul2(v1,v2):vres
  asm
	      abs       v1, v1 wc
	if_c  neg       v2, v2
	      abs       v2, v2 wc
	      mov       vRes, v2
	      min       v2, v1
	      max       v1, vRes
	if_c  neg       v2, v2
	      mov       vRes, #0
  :loop       shr       v1, #1 wc, wz
	if_c  add       vRes, v2
	      shl       v2, #1
	      shr       v1, #1 wc, wz
	if_c  add       vRes, v2
	      shl       v2, #1
	if_nz jmp       #:loop
  endasm

pub mul4(v1,v2):vres
  asm
	      abs       v1, v1 wc
	if_c  neg       v2, v2
	      abs       v2, v2 wc
	      mov       vRes, v2
	      min       v2, v1
	      max       v1, vRes
	if_c  neg       v2, v2
	      mov       vRes, #0
  :loop       shr       v1, #1 wc, wz
	if_c  add       vRes, v2
	      shl       v2, #1
	      shr       v1, #1 wc, wz
	if_c  add       vRes, v2
	      shl       v2, #1
	      shr       v1, #1 wc, wz
	if_c  add       vRes, v2
	      shl       v2, #1
	      shr       v1, #1 wc, wz
	if_c  add       vRes, v2
	      shl       v2, #1
	if_nz jmp       #:loop
  endasm

Compile to inline-asm-loop-unroll.spin.lmm.binary:

fastspin -O2 inline-asm-loop-unroll.spin -o inline-asm-loop-unroll.spin.lmm.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
inline-asm-loop-unroll.spin
|-FullDuplexSerial.spin
inline-asm-loop-unroll.spin.lmm.pasm
Done.
Program size is 3052 bytes

Run it in spinsim:

spinsim -b inline-asm-loop-unroll.spin.lmm.binary
d1,d2        ... 1326,1555658231
internal     ... 608
assembler(1) ... 608
assembler(2) ... 688
assembler(4) ... 864

Compile to inline-asm-loop-unroll.spin.cog.binary:

Depending on the FastSpin version this may need -O1 to fit.

fastspin -O1 inline-asm-loop-unroll.spin --code=cog -o inline-asm-loop-unroll.spin.cog.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
inline-asm-loop-unroll.spin
|-FullDuplexSerial.spin
inline-asm-loop-unroll.spin.cog.pasm
Done.
Program size is 2412 bytes

Run it in spinsim:

spinsim -b inline-asm-loop-unroll.spin.cog.binary
d1,d2        ... -1555657445,1886241206
internal     ... 548
assembler(1) ... 552
assembler(2) ... 504
assembler(4) ... 472

Interesting: In LMM assembler, unrolling the loop slows it down. This needs a closer look.

@@@TODO@@@ Check different unrolling factors against different FCACHE sizes.

4.1.6 mandelbrot-s4p12.spin

File mandelbrot-s4p12.spin:

''
'' mandelbrot-s4p12.spin
''
con
  _clkmode = xtal1+pll16x
  _clkfreq = 80_000_000

  xmin=round(-2.1*float(1<<12))
  xmax=round( 0.7*float(1<<12))

  ymin=round(-1.2*float(1<<12))
  ymax=round( 1.2*float(1<<12))

  maxiter=32

  MPX=79 ' 0..79
  MPY=24 ' 0..24

  dx=(xmax-xmin)/MPX
  dy=(ymax-ymin)/MPY

  c4=4<<12

obj
  ser : "spin/FullDuplexSerial"

pub main | c,cx,cy,x,y,x2,y2,iter,px,py

  ser.start(31,30,0,115200)

  cy:=ymin
  repeat py from 0 to MPY
    cx:=xmin
    repeat px from 0 to MPX
      x:=0
      y:=0
      iter:=0
      repeat while iter=<maxiter
	x2:=(x*x)~>12
	y2:=(y*y)~>12
	if x2+y2>c4
	  quit
	y:=((x*y)~>11)+cy
	x:=x2-y2+cx
	iter+=1
      cx+=dx
      ser.tx(iter+32)
    cy+=dy
    ser.tx(10)

  waitcnt(_clkfreq+cnt)
  ser.stop
  cogstop(0)

Compile to mandelbrot-s4p12.spin.binary:

fastspin -O2 mandelbrot-s4p12.spin -o mandelbrot-s4p12.spin.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
mandelbrot-s4p12.spin
|-FullDuplexSerial.spin
mandelbrot-s4p12.spin.pasm
Done.
Program size is 2052 bytes

Run it in spinsim:

spinsim -b mandelbrot-s4p12.spin.binary
!!!!!!!!!!!!!!!"""""""""""""####################################""""""""""""""""
!!!!!!!!!!!!!"""""""""#######################$$$$$$$%'+)%%%$$$$$######""""""""""
!!!!!!!!!!!"""""""#######################$$$$$$$$%%%&&(+,)++&%$$$$$$######""""""
!!!!!!!!!"""""#######################$$$$$$$$$$%%%%&')*4:/+('&%%$$$$$$#######"""
!!!!!!!!""""#####################$$$$$$$$$$%%%&&&''),AAAAAAA,'&%%%%%$$$$########
!!!!!!!"""####################$$$$$$$$%%%&'())((())*,AAAAAA/+))('&&&&)'%$$######
!!!!!!""###################$$$$$%%%%%%&&&'+.AA=/<AAAAAAAAAAAAAAA/++A..:2%%$#####
!!!!!"################$$$%%%%%%%%%%&&&&'),+1AAAAAAAAAAAAAAAAAAAAAAAAA1('&%$$####
!!!!"##########$$$$$%%&(-(''''''''''''(*,5AAAAAAAAAAAAAAAAAAAAAAAAAAAA+)-&%$$###
!!!!####$$$$$$$$%%%%%&'(*-A1.+.A-4+))**AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4-(&%$$$##
!!!!#$$$$$$$$$%%%%%%'''++.5AAAAAAAAA8/0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3(%%$$$$#
!!!#$$$$$$$%&&&&''().-5.5AAAAAAAAAAAAA>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'&%%$$$$#
!!!(**+-+;732/;0045;AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4+)'&&%%$$$$#
!!!#$$$$$$$%&&&&''().-3.AAAAAAAAAAAAAA?AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'&%%$$$$#
!!!!#$$$$$$$$$%%%%%%'''/,.7AAAAAAAAA;/0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0'%%$$$$#
!!!!####$$$$$$$$%%%%%&'(*-:2.,/>-5+))**<AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4+(&%$$$##
!!!!"##########$$$$$%%&(-(''''(''''''((*,4AAAAAAAAAAAAAAAAAAAAAAAAAAA4+)-&%$$###
!!!!!"################$$$%%%%%%%%%%&&&&')A,4AAAAAAAAAAAAAAAAAAAAAAAAA/('&%%$####
!!!!!!""##################$$$$$$%%%%%%&&&'*.AAA0AAAAAAAAAAAAAAAA1,,A//9)%%$#####
!!!!!!!"""####################$$$$$$$$%%%&(())((()**-AAAAAA/+)))'&&&')'%$$######
!!!!!!!!""""#####################$$$$$$$$$$%%%&&&''(,AAAAAAA+'&&%%%%%$$$########
!!!!!!!!!"""""#######################$$$$$$$$$$%%%%&')*7A0+('&%%%$$$$$#######"""
!!!!!!!!!!!"""""""######################$$$$$$$$$%%%&&(+.)-*&%$$$$$$######""""""
!!!!!!!!!!!!!"""""""""#######################$$$$$$%%'6(%%%$$$$$######""""""""""
!!!!!!!!!!!!!!!""""""""""""#####################################""""""""""""""""

4.1.7 mandelbrot-s8p24.spin

File mandelbrot-s8p24.spin:

' mandelbrot-s8p24.spin

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=79 ' 0..MPX
  MPY=24 ' 0..MPY

  dx=(xmax-xmin)/MPX
  dy=(ymax-ymin)/MPY

  c4=4<<24

obj
  ser : "spin/FullDuplexSerial"

pub main | c,cx,cy,x,y,x2,y2,iter,px,py

  ser.start(31,30,0,115200)

  cy:=ymin
  repeat py from 0 to MPY
    cx:=xmin
    repeat px from 0 to MPX
      x:=0
      y:=0
      iter:=0
      repeat while iter=<maxiter
	x2:=(x**x)<<8 | (x*x)>>24 ' x*x
	y2:=(y**y)<<8 | (y*y)>>24 ' y*y
	if x2+y2>c4
	  quit
	y:=((x**y)<<9 | (x*y)>>23)+cy ' 2*x*y+cy
	x:=x2-y2+cx
	iter+=1
      cx+=dx
      ser.tx(iter+32)
    cy+=dy
    ser.tx(10)

  waitcnt(_clkfreq+cnt)
  ser.stop
  cogstop(0)

Compile to mandelbrot-s8p24.spin.binary:

fastspin -O2 mandelbrot-s8p24.spin -o mandelbrot-s8p24.spin.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
mandelbrot-s8p24.spin
|-FullDuplexSerial.spin
mandelbrot-s8p24.spin.pasm
Done.
Program size is 2136 bytes

Run it in spinsim:

spinsim -b mandelbrot-s8p24.spin.binary
!!!!!!!!!!!!!!!"""""""""""""####################################""""""""""""""""
!!!!!!!!!!!!!"""""""""#######################$$$$$$$%'0(%%%$$$$$#####"""""""""""
!!!!!!!!!!!"""""""#######################$$$$$$$$%%%&&(++)++&$$$$$$$######""""""
!!!!!!!!!"""""#######################$$$$$$$$$$%%%%&')*A;/*('&%%$$$$$$#######"""
!!!!!!!!""""#####################$$$$$$$$$$%%%&&&''),AAAAAA@+'&%%%%%$$$$########
!!!!!!!"""####################$$$$$$$$%%%&'())((())*-AAAAAA.+))('&&&&+&%$$######
!!!!!!""###################$$$$$%%%%%%&&&'+.AAA08AAAAAAAAAAAAAAA/+,A//A)%%$#####
!!!!!"################$$$%%%%%%%%%%&&&&')-+7AAAAAAAAAAAAAAAAAAAAAAAAA4(&&%$$####
!!!!"##########$$$$$%%&(,('''''''''''((*-5AAAAAAAAAAAAAAAAAAAAAAAAAAA3+)4&%$$###
!!!!####$$$$$$$$%%%%%&'(*-A1.+/A-4+))**AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3+'&%$$$##
!!!!#$$$$$$$$$%%%%%%'''++.7AAAAAAAAA9/0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA<6'%%$$$$#
!!!#$$$$$$$%&&&&''().-2.6AAAAAAAAAAAAA>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'&%%$$$$#
!!!378<@AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2+)'&&%%$$$$#
!!!#$$$$$$$%&&&&''().-2.6AAAAAAAAAAAAA>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'&%%$$$$#
!!!!#$$$$$$$$$%%%%%%'''++.7AAAAAAAAA9/0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA<6'%%$$$$#
!!!!####$$$$$$$$%%%%%&'(*-A1.+/A-4+))**AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3+'&%$$$##
!!!!"##########$$$$$%%&(,('''''''''''((*-5AAAAAAAAAAAAAAAAAAAAAAAAAAA3+)4&%$$###
!!!!!"################$$$%%%%%%%%%%&&&&')-+7AAAAAAAAAAAAAAAAAAAAAAAAA4(&&%$$####
!!!!!!""###################$$$$$%%%%%%&&&'+.AAA08AAAAAAAAAAAAAAA/+,A//A)%%$#####
!!!!!!!"""####################$$$$$$$$%%%&'())((())*-AAAAAA.+))('&&&&+&%$$######
!!!!!!!!""""#####################$$$$$$$$$$%%%&&&''),AAAAAA@+'&%%%%%$$$$########
!!!!!!!!!"""""#######################$$$$$$$$$$%%%%&')*A;/*('&%%$$$$$$#######"""
!!!!!!!!!!!"""""""#######################$$$$$$$$%%%&&(++)++&$$$$$$$######""""""
!!!!!!!!!!!!!"""""""""#######################$$$$$$$%'0(%%%$$$$$#####"""""""""""
!!!!!!!!!!!!!!!"""""""""""""####################################""""""""""""""""

4.1.8 minimal.spin

Like FlexBASIC and FlexC, FlexSPIN defaults (on Propeller1) to expecting a 5MHz quartz and will use a 16 times PLL.

@@@TODO@@@ look up Propeller2 defaults.

Also there are some useful library functions available (e.g. _tx, pausems) but more about this will be added later. Maybe… ;-)

File minimal.spin:

pub surprise | s, c
  s := string("Surprised?", 13, 10)
  repeat while c := byte[s++]
    _tx(c)
  pausems(1000)

Compile to minimal.bas.binary:

fastspin minimal.spin -o minimal.spin.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
minimal.spin
minimal.spin.pasm
Done.
Program size is 920 bytes

Run it in spinsim:

spinsim -b minimal.spin.binary
Surprised?

4.1.9 minimal-using-stdio.spin

File minimal-using-stdio.spin:

obj
  stdio : "stdio.h"

pub main
  stdio.puts(string("Hello, Polyglot Propeller Compiler Collection!"))

Compile to minimal-using-stdio.bas.binary:

fastspin -O2 minimal-using-stdio.spin -o minimal-using-stdio.spin.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
minimal-using-stdio.spin
|-stdio.h
fputs.c
ftab.c
minimal-using-stdio.spin.pasm
Done.
Program size is 1324 bytes

Run it in spinsim:

spinsim -b minimal-using-stdio.spin.binary
Hello, Polyglot Propeller Compiler Collection!

4.1.10 pseudorandom-integer.spin

Spin's normal way to generate pseudorandom sure does work with FlexSPIN. And so does rand() imported from FlexC.

N.b.: Using printf() is not cheap.

@@@TODO@@@ some hints about the ranges. For now read rand.c.

File pseudorandom-integer.spin:

obj
  stdio : "stdio.h"
  stdlib: "stdlib.h"

pub main | r
  repeat 5
    stdio.printf(string("%d "),?r)
  stdio.puts("")

  repeat 5
    stdio.printf(string("%d "),stdlib.rand)
  stdio.puts("")

Compile to pseudorandom-integer.spin.binary:

fastspin -O2 pseudorandom-integer.spin -o pseudorandom-integer.spin.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
pseudorandom-integer.spin
|-stdio.h
|-stdlib.h
fprintf.c
fputs.c
rand.c
ftab.c
dofmt.c
fmt.c
strcpy.c
strlen.c
pseudorandom-integer.spin.pasm
Done.
Program size is 12228 bytes

Run it in spinsim:

spinsim -b pseudorandom-integer.spin.binary
-1603072260 1917942482 -255291742 1804755633 570879342 
16807 282475249 1622650073 984943658 1144108930 

4.1.11 spin2-operators.spin

FlexSPIN documentation: spin2-operators(FlexSPIN)

File spin2-operators.spin:

con
  _clkmode = xtal1+pll16x
  _clkfreq = 80_000_000

obj
  ser : "spin/FullDuplexSerial"

pub init
  ser.start( 31, 30, 0, 115200 )
  main
  waitcnt( _clkfreq + cnt )
  ser.stop
  cogstop( 0 )

pub main | a, b, c, d

  ''++
  '' a \ b   uses the value of a, but then sets a to b
  ''
  a := 113
  b := 335

  ser.dec( a \ b )
  ser.str( string( 13, 10 ) )
  ser.dec( a )
  ser.str( string( 13, 10 ) )
  ''--

  ''++
  '' evil mad scientist mode... mwhuaaahaahhaahahaaa...
  ''
  a := 0
  b := 90
  c := 180
  d := 270

  repeat 13
    ser.dec( a \ b \ c \ d \ a )
    ser.tx( 32 )

  ser.str( string( "...", 13, 10 ) )
  ''--

  ''++
  '' x <=> y returns -1, 0, or 1 if x < y, x == y, or x > y
  ''
  '' @@@TODO@@@ add example
  ''--

Compile to spin2-operators.spin.binary:

fastspin spin2-operators.spin -o spin2-operators.spin.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
spin2-operators.spin
|-FullDuplexSerial.spin
spin2-operators.spin.pasm
Done.
Program size is 2500 bytes

Run it in spinsim:

spinsim -b spin2-operators.spin.binary
113
335
0 90 180 270 0 90 180 270 0 90 180 270 0 ...

4.1.12 tuple.spin

FlexSPIN documentation: multiple-return-values-and-assignments(FlexSPIN)

File tuple.spin:

con
  _clkmode = xtal1+pll16x
  _clkfreq = 80_000_000

obj
  ser : "spin/FullDuplexSerial"

pub main | i, s, d

  ser.start(31, 30, 0, 115200)

  s, d := 0, 1                  ' tuple assignment
  repeat i from 1 to 10
    s, d := f(s, d)             ' tuple assignment
    ser.dec(s)
    ser.tx(32)

  ser.str(string(13, 10))
  waitcnt(_clkfreq + cnt)
    ser.stop
  cogstop(0)

pub f(s, d) : ss, dd            ' function returning a tuple
  ss, dd := s + d, s

Compile to tuple.spin.binary:

fastspin -O2 tuple.spin -o tuple.spin.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
tuple.spin
|-FullDuplexSerial.spin
tuple.spin.pasm
Done.
Program size is 2228 bytes

Run it in spinsim:

spinsim -b tuple.spin.binary
1 1 2 3 5 8 13 21 34 55 

4.2 FlexBASIC

4.2.1 anonymous-function1.bas

FlexBASIC documentation: anonymous-functions(FlexBASIC)

File anonymous-function1.bas:

type intfunc as function(x as integer) as integer
dim as intfunc anonfunc

anonfunc = function(n as integer) as integer
	     return n * n
	   end function

print anonfunc(5)

Compile to anonymous-function1.bas.binary:

fastspin -O2 anonymous-function1.bas -o anonymous-function1.bas.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
anonymous-function1.bas
fmt.c
gcptrs.spin
strlen.c
anonymous-function1.bas.pasm
Done.
Program size is 6508 bytes

Run it in spinsim:

spinsim -b anonymous-function1.bas.binary
25

4.2.2 anonymous-function2.bas

FlexBASIC documentation: anonymous-functions(FlexBASIC)

See https://github.com/totalspectrum/spin2cpp/blob/master/doc/basic.md#anonymous-functions.

File anonymous-function2.bas:

type intfunc as function(x as integer) as integer
dim as intfunc anonfunc

anonfunc = (function(n as integer) n * n)

print anonfunc(6)

Compile to anonymous-function2.bas.binary:

fastspin -O2 anonymous-function2.bas -o anonymous-function2.bas.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
anonymous-function2.bas
fmt.c
gcptrs.spin
strlen.c
anonymous-function2.bas.pasm
Done.
Program size is 6508 bytes

Run it in spinsim:

spinsim -b anonymous-function2.bas.binary
36

4.2.3 anonymous-function3.bas

FlexBASIC documentation: anonymous-functions(FlexBASIC)

See https://github.com/totalspectrum/spin2cpp/blob/master/doc/basic.md#anonymous-functions.

File anonymous-function3.bas:

type intfunc as function(x as integer) as integer
dim as intfunc anonfunc

anonfunc = [ n :=> n * n ]

print anonfunc(7)

Compile to anonymous-function3.bas.binary:

fastspin -O2 anonymous-function3.bas -o anonymous-function3.bas.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
anonymous-function3.bas
fmt.c
gcptrs.spin
strlen.c
anonymous-function3.bas.pasm
Done.
Program size is 6508 bytes

Run it in spinsim:

spinsim -b anonymous-function3.bas.binary
49

4.2.4 anonymous-sub1.bas

FlexBASIC documentation: anonymous-subroutines(FlexBASIC)

File anonymous-sub1.bas:

dim as sub() anonsub

anonsub = sub()
  print "Rumpelstiltskin?"
end sub

anonsub
anonsub()

Compile to anonymous-sub1.bas.binary:

fastspin -O2 anonymous-sub1.bas -o anonymous-sub1.bas.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
anonymous-sub1.bas
fmt.c
gcptrs.spin
strlen.c
anonymous-sub1.bas.pasm
Done.
Program size is 5500 bytes

Run it in spinsim:

spinsim -b anonymous-sub1.bas.binary
Rumpelstiltskin?
Rumpelstiltskin?

4.2.5 anonymous-sub2.bas

FlexBASIC documentation: anonymous-subroutines(FlexBASIC)

File anonymous-sub2.bas:

dim as sub() anonsub

anonsub = [: print "Rumpelstiltskin!" ]

anonsub
anonsub()

Compile to anonymous-sub2.bas.binary:

fastspin -O2 anonymous-sub2.bas -o anonymous-sub2.bas.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
anonymous-sub2.bas
fmt.c
gcptrs.spin
strlen.c
anonymous-sub2.bas.pasm
Done.
Program size is 5500 bytes

Run it in spinsim:

spinsim -b anonymous-sub2.bas.binary
Rumpelstiltskin!
Rumpelstiltskin!

4.2.6 cast.bas

FlexBASIC documentation: cast(FlexBASIC)

Version 3.9.27-beta introduces cast.

This example shows overlaying the whole hub RAM (and ROM) with an array using cast. This can be used to replace classic peek and poke or to build their emulation atop of it.

File cast.bas:

''
'' create a "byte pointer" pointing to the hub's start
''
var mem8 = cast(byte ptr,0)

''
'' test it
''
dim as string Question$
Question$ = "Surprise?"

'' check "?" being where expected.
'' just to demonstrate reading mem8()
''
if mem8(cast(byte ptr,Question$) + 8) == asc("?") then
  print Question$
  mem8(cast(byte ptr,Question$) + 8) = asc("!")
  print Question$
else
  print "Strange things are happening!"
end if

Compile to cast.bas.binary:

fastspin cast.bas -o cast.bas.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
cast.bas
fmt.c
strlen.c
cast.bas.pasm
Done.
Program size is 2036 bytes

Run it in spinsim:

spinsim -b cast.bas.binary
Surprise?
Surprise!

4.2.7 cnt-dira-outa.bas

Using the well known register names works and makes BASIC look a bit SPINier. It's nice to have this option!

File cnt-dira-outa.bas:

dira = 0xFFFFFFFF
do
  outa = cnt
loop

Compile to cnt-dira-outa.bas.binary:

fastspin --code=cog -o cnt-dira-outa.bas.binary cnt-dira-outa.bas
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
cnt-dira-outa.bas
cnt-dira-outa.bas.pasm
Done.
Program size is 68 bytes

Run it in gear:

cnt-dira-outa.bas.png

cnt-dira-outa.bas.png

4.2.8 extending-lines.bas

FlexBASIC documentation: extending-lines(FlexBASIC)

An extremely long line can be seen in static-image-vga-512x384x1.bas.

File extending-lines.bas:

print"Hello, "; _
     "World!"

Compile to extending-lines.bas.binary:

fastspin -O2 extending-lines.bas -o extending-lines.bas.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
extending-lines.bas
fmt.c
strlen.c
extending-lines.bas.pasm
Done.
Program size is 1868 bytes

Run it in spinsim:

spinsim -b extending-lines.bas.binary
Hello, World!

4.2.9 hopper-vga-512x384x1.bas

See https://forums.parallax.com/discussion/comment/1453190/#Comment_1453190.

File hopper-vga-512x384x1.bas:

''++ -------------------------------------------------------------------------
'' hopper-vga-512x384x1.bas
''
'' set the VGA pin(group) as needed a few lines below.
''-- -------------------------------------------------------------------------

''++
'' set up VGA and preset the tiles' colors
''
dim vga as class using "VGA_512x384_Bitmap.spin"
''
dim shared as ulong sync
dim shared as ulong bitmap(vga.hp/32*vga.vp)
dim shared as ushort colors(vga.xtiles*vga.ytiles)
''
''        lowest pin of VGA pingroup
''        |
''        V
vga.start(16, @colors, @bitmap, @sync)
''
'' set same colorpair for all tiles
''
wordfill(@colors,&b111111_00_010101_00,192) ' ffffff_00_bbbbbb_00
''--

''++ =========================================================================

const a =   3.0
const b =  -5.0
const c =   7.0

const scale = 10.0

dim as single x,y,xn,yn

x = 0.0
y = 0.0

do
  xn = y-sgn(x)*sqrt(abs(b*x-c))
  yn = a-x
  x  = xn
  y  = yn
  plot 255.5+x*scale,191.5+y*scale
loop

''-- =========================================================================

''++
sub plot(x as integer,y as integer)
#ifdef PRINT
  print x," ",y
#endif
  if 0<=x and x<=511 and 0<=y and y<=383 then
    var index = y<<4 + x>>5 + 1
    bitmap(index) = bitmap(index) or 1<<(x and 31)
  end if
end sub
''--

''++
function sgn(x as single) as single
  if x>0.0 return 1.0
  if x<0.0 return -1.0
  return 0.0
end function
''--

Compile to hopper-vga-512x384x1.bas.binary:

fastspin -O2 hopper-vga-512x384x1.bas -o hopper-vga-512x384x1.bas.binary -L lib
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
hopper-vga-512x384x1.bas
|-VGA_512x384_Bitmap.spin
hopper-vga-512x384x1.bas.pasm
Done.
Program size is 27940 bytes

Run it in gear:

hopper-vga-512x384x1.bas.png

hopper-vga-512x384x1.bas.png

4.2.10 inline-asm.bas

FlexBASIC documentation: asm(FlexBASIC)

File inline-asm.bas:

function answer(question as ulong) as ulong
  dim result as ulong
  asm
	  mov     result, question
	  add     result, result
	  add     result, question
  end asm
  return result
end function

print "the answer is ";answer(14)

Compile to inline-asm.bas.binary:

fastspin -O2 inline-asm.bas -o inline-asm.bas.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
inline-asm.bas
fmt.c
strlen.c
inline-asm.bas.pasm
Done.
Program size is 2744 bytes

Run it in spinsim:

spinsim -b inline-asm.bas.binary
the answer is 42

4.2.11 Libraries

FlexBASIC documentation: Libraries(FlexBASIC)

4.2.11.1 basic-external-class.bas

See 4.2.11.2 for a related example using an include file instead of an external class.

@@@TODO@@@ add example and some lines about what happens to the toplevel of such files (classname.program). See https://forums.parallax.com/discussion/comment/1479370/#Comment_1479370.

File basic-external-class.bas:

function martian_quotient(m as single, n as single) as single
  martian_quotient = n / m
end function

File basic-external-class-test.bas:

dim mars as class using "basic-external-class.bas"

print mars.martian_quotient(113, 355)

Compile to basic-external-class-test.bas.binary:

fastspin basic-external-class-test.bas -o basic-external-class-test.bas.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
basic-external-class-test.bas
|-basic-external-class.bas
fmt.c
strcpy.c
strlen.c
basic-external-class-test.bas.pasm
Done.
Program size is 8332 bytes

Run it in spinsim:

spinsim -b basic-external-class-test.bas.binary
3.1420

4.2.11.2 basic-include.bas

See 4.2.11.1 for a related example using a external class instead of an include file.

The include file could have any extension but for being able to embed test code and compile it on its own the extension needs to be .bas.

File basic-include.bas:

function martian_quotient(m as single, n as single) as single
  martian_quotient = n / m
end function

#ifdef SELFTEST
print martian_quotient(113, 355)
#endif

Compile to basic-include.bas.binary:

fastspin -D SELFTEST basic-include.bas -o basic-include.bas.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
basic-include.bas
fmt.c
strcpy.c
strlen.c
basic-include.bas.pasm
Done.
Program size is 8332 bytes

Run it in spinsim:

spinsim -b basic-include.bas.binary
3.1420

For using this include in a program just remember not to add the compiler option -D SELFTEST.

File basic-include-test.bas:

#include "basic-include.bas"

print "martian_quotient(113, 355) = ";martian_quotient(113, 355)

Compile to basic-include-test.bas.binary:

fastspin basic-include-test.bas -o basic-include-test.bas.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
basic-include-test.bas
fmt.c
strcpy.c
strlen.c
basic-include-test.bas.pasm
Done.
Program size is 8460 bytes

Run it in spinsim:

spinsim -b basic-include-test.bas.binary
martian_quotient(113, 355) = 3.1420

4.2.12 line-numbers.bas

@@@TODO@@@ where are line numbers in the docs?

File line-numbers.bas:

100 for i=0 to 5
110   gosub 900
120 next i
199 goto 999
900 if i < 2 print "book! ";
910 if i mod 2 print "raaadiiiooo! ";
920 if i mod 3 print "yipyip! ";
930 print
940 return
999 print "happy! happy! happy!"

Loosely based upon https://www.youtube.com/watch?v=z_trSIBCgF0. ;-)

Compile to line-numbers.bas.binary:

fastspin -O2 line-numbers.bas -o line-numbers.bas.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
line-numbers.bas
fmt.c
strlen.c
line-numbers.bas.pasm
Done.
Program size is 2216 bytes

Run it in spinsim:

spinsim -b line-numbers.bas.binary
book! 
book! raaadiiiooo! yipyip! 
yipyip! 
raaadiiiooo! 
yipyip! 
raaadiiiooo! yipyip! 
happy! happy! happy!

4.2.13 mandelbrot-s4p12.bas

File mandelbrot-s4p12.bas:

'
' translated to BASIC from mandelbrot16-20180406-fds.spin
'-------------------------------------------------------------------------------

'++
  const xmin = (-21<<12)/10
  const xmax = (  7<<12)/10

  const ymin = (-12<<12)/10
  const ymax = ( 12<<12)/10

  const maxiter = 32

  const MPX = 79 ' 0..79
  const MPY = 24 ' 0..24

  const dx = (xmax-xmin)/MPX
  const dy = (ymax-ymin)/MPY

  const c4 = 4<<12
'--

'++
' was main
'
  dim as integer x,y,x2,y2,cx,cy,iter

  cy = ymin
  for py = 0 to MPY
    cx = xmin
    for px = 0 to MPX
      x = 0
      y = 0
      x2 = 0
      y2 = 0
      iter = 0
      while iter < maxiter and x2+y2 <= c4
	y = ((x*y)>>11)+cy
	x = x2-y2+cx
	iter = iter+1
	x2 = (x*x)>>12
	y2 = (y*y)>>12
      end while
      cx = cx+dx
      print \(iter+32);
    next px
    cy = cy+dy
    print
  next py
'--

Compile to mandelbrot-s4p12.bas.binary:

fastspin -O2 mandelbrot-s4p12.bas -o mandelbrot-s4p12.bas.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
mandelbrot-s4p12.bas
fmt.c
mandelbrot-s4p12.bas.pasm
Done.
Program size is 1628 bytes

Run it in spinsim:

spinsim -b mandelbrot-s4p12.bas.binary
!!!!!!!!!!!!!!!"""""""""""""####################################""""""""""""""""
!!!!!!!!!!!!!"""""""""#######################$$$$$$$%'+)%%%$$$$$#####"""""""""""
!!!!!!!!!!!"""""""#######################$$$$$$$$%%%&&(+,)++&%$$$$$$######""""""
!!!!!!!!!"""""#######################$$$$$$$$$$%%%%&')*5:/+('&%%$$$$$$#######"""
!!!!!!!!""""#####################$$$$$$$$$$%%%&&&''),@@@@@@@,'&%%%%%$$$$########
!!!!!!!"""####################$$$$$$$$%%%&'())((())*,@@@@@@/+))('&&&&)'%$$######
!!!!!!""###################$$$$$%%%%%%&&&'+.@@=/<@@@@@@@@@@@@@@@/++@..93%%$#####
!!!!!"################$$$%%%%%%%%%%&&&&'),+2@@@@@@@@@@@@@@@@@@@@@@@@@1(&&%$$####
!!!!"##########$$$$$%%&(-(''''''''''''(*,5@@@@@@@@@@@@@@@@@@@@@@@@@@@@+)-&%$$###
!!!!####$$$$$$$$%%%%%&'(*-@1.+.@-4+))**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@4-(&%$$$##
!!!!#$$$$$$$$$%%%%%%'''++.6@@@@@@@@@8/0@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@3(%%$$$$#
!!!#$$$$$$$%&&&&''()/-5.5@@@@@@@@@@@@@>@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@?'&%%$$$$#
!!!(**+/+<523/80/46@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@4+)'&&%%$$$$#
!!!#$$$$$$$%&&&&''().-2.@@@@@@@@@@@@@@?@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@'&%%$$$$#
!!!!#$$$$$$$$$%%%%%&'''/,.7@@@@@@@@@;/0@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@0'%%$$$$#
!!!!####$$$$$$$$%%%%%&'(*-:2.,/?-5+))**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@4+(&%$$$##
!!!!"##########$$$$$%%&(-(''''(''''''((*,4@@@@@@@@@@@@@@@@@@@@@@@@@@@4+).&%$$###
!!!!!"################$$$%%%%%%%%%%&&&&')<,4@@@@@@@@@@@@@@@@@@@@@@@@@/('&%%$####
!!!!!!""##################$$$$$$%%%%%%&&&'*.@@@0@@@@@@@@@@@@@@@@1,,@//9)%%$#####
!!!!!!!"""####################$$$$$$$$%%%&(())((()**-@@@@@@/+)))'&&&')'%$$######
!!!!!!!!""""#####################$$$$$$$$$$%%%&&&''(,@@@@@@@+'&&%%%%%$$$########
!!!!!!!!!"""""#######################$$$$$$$$$$%%%%&')*7@0+('&%%%$$$$$#######"""
!!!!!!!!!!!"""""""######################$$$$$$$$$%%%&&(+-).*&%$$$$$$######""""""
!!!!!!!!!!!!!"""""""""#######################$$$$$$%%'3(%%%$$$$$######""""""""""
!!!!!!!!!!!!!!!""""""""""""#####################################""""""""""""""""

4.2.14 mandelbrot-s4p12-vga-320x240x2.bas

Everyone loves a fresh almond bread (Mandelbrot).
Right?

This program uses [Kwabena W. Agyeman]'s "VGA64 Bitmap Engine" to display a 320x240x2 image. Its initialisation is slightly different than in the monochrome examples and its drawing routine and named constants for the colours are used from BASIC.

The Mandelbrot algorithm is run in 16 bit rational arithmetic with 12 bit accuracy (1/4096) for the broken part. That's enough for some simple pictures but for deeper zooms you'd need 32 bit rationals or floating point. The main focus of the example is how to interface this VGA engine, so using the faster and a bit less accurate arithmetic is ok here.

@@@TODO@@@ link to VGA64_BMPDemo.zip in OBEX: http://obex.parallax.com/object/96

File mandelbrot-s4p12-vga-320x240x2.bas:

''++ -------------------------------------------------------------------------
'' mandelbrot-s4p12-vga-320x240x2.bas
''
''                     translated to BASIC from mandelbrot16-20180406-fds.spin
''
'' set the VGA pin(group) as needed a few lines below.
''-- -------------------------------------------------------------------------

dim vga as class using "VGA64_BMPEngine.spin"

const pingroup = 2
const bpp = 2 ' bits per pixel

const xsize = 320
const ysize = 240

dim as ulong bitmap(((xsize*ysize)/32)*bpp)

vga.bmpenginestart(pingroup,bpp,xsize,ysize,@bitmap) ' check rc

vga.displaycolor(0,vga.black)
vga.displaycolor(1,vga.light_red)
vga.displaycolor(2,vga.light_green)
vga.displaycolor(3,vga.light_blue)

''++ ===========================================================================

const xmin = (-14<<12)/10 ' (-21<<12)/10
const xmax =            0 ' (  7<<12)/10

const ymin = (-12<<12)/10 ' (-12<<12)/10
const ymax =            0 ' ( 12<<12)/10

const maxiter = 32

const MPX = xsize-1
const MPY = ysize-1

const dx = (xmax-xmin)/MPX
const dy = (ymax-ymin)/MPY

const c4 = 4<<12

dim as integer x,y,x2,y2,cx,cy,iter

cy = ymin
for py = 0 to MPY
  cx = xmin
  for px = 0 to MPX
    x = 0
    y = 0
    x2 = 0
    y2 = 0
    iter = 0
    while iter < maxiter and x2+y2 <= c4
      y = ((x*y)>>11)+cy
      x = x2-y2+cx
      iter = iter+1
      x2 = (x*x)>>12
      y2 = (y*y)>>12
    end while
    cx = cx+dx
    vga.plotpixel(iter and 3,px,py,@bitmap)
  next px
  cy = cy+dy
next py

''-- ===========================================================================

''++
do
loop
''--

Compile to mandelbrot-s4p12-vga-320x240x2.bas.binary:

fastspin mandelbrot-s4p12-vga-320x240x2.bas -o mandelbrot-s4p12-vga-320x240x2.bas.binary -L lib
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
mandelbrot-s4p12-vga-320x240x2.bas
|-VGA64_BMPEngine.spin
mandelbrot-s4p12-vga-320x240x2.bas.pasm
Done.
Program size is 21964 bytes

Run it in gear:

mandelbrot-s4p12-vga-320x240x2.bas.png

mandelbrot-s4p12-vga-320x240x2.bas.png

4.2.15 mandelbrot-s8p24.bas

File mandelbrot-s8p24.bas:

'
' translated from mandelbrot32-20180317-b.spin
'-------------------------------------------------------------------------------

'++
  const xmin = (-21<<24)/10
  const xmax = (  7<<24)/10

  const ymin = (-12<<24)/10
  const ymax = ( 12<<24)/10

  const maxiter = 32

  const MPX = 79 ' 0..79
  const MPY = 24 ' 0..24

  const dx = (xmax-xmin)/MPX
  const dy = (ymax-ymin)/MPY

  const c4 = 4<<24
'--

'++
' was main
'
dim as integer x,y,x2,y2,cx,cy,iter

  cy = ymin
  for py = 0 to MPY
    cx = xmin
    for px = 0 to MPX
      x = 0
      y = 0
      x2 = 0
      y2 = 0
      iter = 0
      while iter < maxiter and x2+y2 <= c4
	y = hack.multimes2(x,y)+cy
	x = x2-y2+cx
	iter = iter+1
	x2 = hack.mul(x,x)
	y2 = hack.mul(y,y)
      end while
      cx = cx+dx
      print \(iter+32);
    next px
    cy = cy+dy
    print
  next py

#ifdef MagicExit
  print \255;\0;\0;
#endif
'--

'++
class hacks using "mandelbrot-s8p24.hacks.spin"
dim hack as hacks
' hack.mul(x,y) does s8p24 fp multiplication
' hack.multimes2(x,y) does mul(x,y)*2
'--

File mandelbrot-s8p24.hacks.spin:

pub mul(x,y)
  return (x**y)<<8 | (x*y)>>24

pub multimes2(x,y)
  return (x**y)<<9 | (x*y)>>23

Compile to mandelbrot-s8p24.bas.binary:

fastspin -O2 mandelbrot-s8p24.bas -o mandelbrot-s8p24.bas.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
mandelbrot-s8p24.bas
|-mandelbrot-s8p24.hacks.spin
fmt.c
mandelbrot-s8p24.bas.pasm
Done.
Program size is 1704 bytes

Run it in spinsim:

spinsim -b mandelbrot-s8p24.bas.binary
!!!!!!!!!!!!!!!"""""""""""""####################################""""""""""""""""
!!!!!!!!!!!!!"""""""""#######################$$$$$$$%'0(%%%$$$$$#####"""""""""""
!!!!!!!!!!!"""""""#######################$$$$$$$$%%%&&(++)++&$$$$$$$######""""""
!!!!!!!!!"""""#######################$$$$$$$$$$%%%%&')*@;/*('&%%$$$$$$#######"""
!!!!!!!!""""#####################$$$$$$$$$$%%%&&&''),@@@@@@@+'&%%%%%$$$$########
!!!!!!!"""####################$$$$$$$$%%%&'())((())*-@@@@@@.+))('&&&&+&%$$######
!!!!!!""###################$$$$$%%%%%%&&&'+.@@@08@@@@@@@@@@@@@@@/+,@//@)%%$#####
!!!!!"################$$$%%%%%%%%%%&&&&')-+7@@@@@@@@@@@@@@@@@@@@@@@@@4(&&%$$####
!!!!"##########$$$$$%%&(,('''''''''''((*-5@@@@@@@@@@@@@@@@@@@@@@@@@@@3+)4&%$$###
!!!!####$$$$$$$$%%%%%&'(*-@1.+/@-4+))**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@3+'&%$$$##
!!!!#$$$$$$$$$%%%%%%'''++.7@@@@@@@@@9/0@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@<6'%%$$$$#
!!!#$$$$$$$%&&&&''().-2.6@@@@@@@@@@@@@>@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@'&%%$$$$#
!!!379<@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@2+)'&&%%$$$$#
!!!#$$$$$$$%&&&&''().-2.6@@@@@@@@@@@@@>@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@'&%%$$$$#
!!!!#$$$$$$$$$%%%%%%'''++.7@@@@@@@@@9/0@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@<6'%%$$$$#
!!!!####$$$$$$$$%%%%%&'(*-@1.+/@-4+))**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@3+'&%$$$##
!!!!"##########$$$$$%%&(,('''''''''''((*-5@@@@@@@@@@@@@@@@@@@@@@@@@@@3+)4&%$$###
!!!!!"################$$$%%%%%%%%%%&&&&')-+7@@@@@@@@@@@@@@@@@@@@@@@@@4(&&%$$####
!!!!!!""###################$$$$$%%%%%%&&&'+.@@@08@@@@@@@@@@@@@@@/+,@//@)%%$#####
!!!!!!!"""####################$$$$$$$$%%%&'())((())*-@@@@@@.+))('&&&&+&%$$######
!!!!!!!!""""#####################$$$$$$$$$$%%%&&&''),@@@@@@@+'&%%%%%$$$$########
!!!!!!!!!"""""#######################$$$$$$$$$$%%%%&')*@;/*('&%%$$$$$$#######"""
!!!!!!!!!!!"""""""#######################$$$$$$$$%%%&&(++)++&$$$$$$$######""""""
!!!!!!!!!!!!!"""""""""#######################$$$$$$$%'0(%%%$$$$$#####"""""""""""
!!!!!!!!!!!!!!!"""""""""""""####################################""""""""""""""""

4.2.16 mandelbrot-single.bas

File mandelbrot-single.bas:

'
' translated to BASIC from mandelbrot16-20180406-fds.spin
'-------------------------------------------------------------------------------

'++
  const xmin = -2.1
  const xmax =  0.7

  const ymin = -1.2
  const ymax =  1.2

  const maxiter = 32

  const MPX = 79 ' 0..79
  const MPY = 24 ' 0..24

  const dx = (xmax-xmin)/MPX
  const dy = (ymax-ymin)/MPY

  const c4 = 4.0 ' square of escape radius
'--

'++
' was main
'
  dim as single x,y,x2,y2,cx,cy
  dim as integer iter

  cy = ymin
  for py = 0 to MPY
    cx = xmin
    for px = 0 to MPX
      x = 0.0
      y = 0.0
      x2 = 0.0
      y2 = 0.0
      iter = 0
      while iter < maxiter and x2+y2 <= c4
	y = 2.0*x*y+cy
	x = x2-y2+cx
	iter = iter+1
	x2 = x*x
	y2 = y*y
      end while
      cx = cx+dx
      print \(iter+32);
    next px
    cy = cy+dy
    print
  next py

#ifdef MagicExit
  print \255;\0;\0;
#endif
'--

Compile to mandelbrot-single.bas.binary:

fastspin -O2 mandelbrot-single.bas -o mandelbrot-single.bas.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
mandelbrot-single.bas
fmt.c
mandelbrot-single.bas.pasm
Done.
Program size is 2516 bytes

Run it in spinsim:

spinsim -b mandelbrot-single.bas.binary
!!!!!!!!!!!!!!!"""""""""""""####################################""""""""""""""""
!!!!!!!!!!!!!"""""""""#######################$$$$$$$%'0(%%%$$$$$#####"""""""""""
!!!!!!!!!!!"""""""#######################$$$$$$$$%%%&&(++)++&$$$$$$$######""""""
!!!!!!!!!"""""#######################$$$$$$$$$$%%%%&')*@;/*('&%%$$$$$$#######"""
!!!!!!!!""""#####################$$$$$$$$$$%%%&&&''),@@@@@@@+'&%%%%%$$$$########
!!!!!!!"""####################$$$$$$$$%%%&'())((())*-@@@@@@.+))('&&&&+&%$$######
!!!!!!""###################$$$$$%%%%%%&&&'+.@@@08@@@@@@@@@@@@@@@/+,@//@)%%$#####
!!!!!"################$$$%%%%%%%%%%&&&&')-+7@@@@@@@@@@@@@@@@@@@@@@@@@4(&&%$$####
!!!!"##########$$$$$%%&(,('''''''''''((*-5@@@@@@@@@@@@@@@@@@@@@@@@@@@3+)4&%$$###
!!!!####$$$$$$$$%%%%%&'(*-@1.+/@-4+))**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@3+'&%$$$##
!!!!#$$$$$$$$$%%%%%%'''++.7@@@@@@@@@9/0@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@<6'%%$$$$#
!!!#$$$$$$$%&&&&''().-2.6@@@@@@@@@@@@@>@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@'&%%$$$$#
!!!7:=?@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@2+)'&&%%$$$$#
!!!#$$$$$$$%&&&&''().-2.6@@@@@@@@@@@@@>@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@'&%%$$$$#
!!!!#$$$$$$$$$%%%%%%'''++.7@@@@@@@@@9/0@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@<6'%%$$$$#
!!!!####$$$$$$$$%%%%%&'(*-@1.+/@-4+))**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@3+'&%$$$##
!!!!"##########$$$$$%%&(,('''''''''''((*-5@@@@@@@@@@@@@@@@@@@@@@@@@@@3+)4&%$$###
!!!!!"################$$$%%%%%%%%%%&&&&')-+7@@@@@@@@@@@@@@@@@@@@@@@@@4(&&%$$####
!!!!!!""###################$$$$$%%%%%%&&&'+.@@@08@@@@@@@@@@@@@@@/+,@//@)%%$#####
!!!!!!!"""####################$$$$$$$$%%%&'())((())*-@@@@@@.+))('&&&&+&%$$######
!!!!!!!!""""#####################$$$$$$$$$$%%%&&&''),@@@@@@@+'&%%%%%$$$$########
!!!!!!!!!"""""#######################$$$$$$$$$$%%%%&')*@;/*('&%%$$$$$$#######"""
!!!!!!!!!!!"""""""#######################$$$$$$$$%%%&&(++)++&$$$$$$$######""""""
!!!!!!!!!!!!!"""""""""#######################$$$$$$$%'0(%%%$$$$$#####"""""""""""
!!!!!!!!!!!!!!!"""""""""""""####################################""""""""""""""""

4.2.17 mandelbrot-single-pgm-800x800.bas

File mandelbrot-single-pgm-800x800.bas:

'
' translated from mandelbrot32-20180317-b.spin
'-------------------------------------------------------------------------------

'++
' constants

  const xmin = -2.1 ' -0.79568
  const xmax =  2.1 ' -0.79068

  const ymin = -2.1 ' -0.16337
  const ymax =  2.1 ' -0.15837

  const maxiter = 31

  const MPX = 799 ' 0..800
  const MPY = 799 ' 0..800

  const dx = (xmax-xmin)/MPX
  const dy = (ymax-ymin)/MPY

  const c4 = 4.0
'--

'++
' was main
'
  dim as single x,y,x2,y2,cx,cy
  dim as integer iter

  ' portable greymap header
  print"P2 ";MPX+1;" ";MPY+1;" ";maxiter

  cy = ymin
  for py = 0 to MPY
    cx = xmin
    for px = 0 to MPX
      x = 0.0
      y = 0.0
      x2 = 0.0
      y2 = 0.0
      iter = 0
      while iter < maxiter and  x2+y2 <= c4
	y = 2.0*x*y+cy
	x = x2-y2+cx
	iter = iter+1
	x2 = x*x
	y2 = y*y
      end while
      cx = cx+dx
      print iter
    next px
    cy = cy+dy
  next py
'--

Compile to mandelbrot-single-pgm-800x800.bas.binary:

fastspin -O2 mandelbrot-single-pgm-800x800.bas -o mandelbrot-single-pgm-800x800.bas.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
mandelbrot-single-pgm-800x800.bas
fmt.c
strlen.c
mandelbrot-single-pgm-800x800.bas.pasm
Done.
Program size is 4368 bytes

Run it in spinsim:

spinsim -b mandelbrot-single-pgm-800x800.bas.binary > mandelbrot-single-pgm-800x800.bas.pgm

mandelbrot-single-pgm-800x800.bas.pgm

pnmtopng < mandelbrot-single-pgm-800x800.bas.pgm > mandelbrot-single-pgm-800x800.bas.pgm.png
pnmtopng: 31 colors found

mandelbrot-single-pgm-800x800.bas.pgm.png

mandelbrot-single-pgm-800x800.bas.pgm.png

4.2.18 multiple-statements-per-line.bas

FlexBASIC documentation: multiple-statements-per-line(FlexBASIC)

File multiple-statements-per-line.bas:

print"Hello, "; : print "World!"

Compile to multiple-statements-per-line.bas.binary:

fastspin -O2 multiple-statements-per-line.bas -o multiple-statements-per-line.bas.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
multiple-statements-per-line.bas
fmt.c
strlen.c
multiple-statements-per-line.bas.pasm
Done.
Program size is 1868 bytes

Run it in spinsim:

spinsim -b multiple-statements-per-line.bas.binary
Hello, World!

4.2.19 option-base.bas

FlexBASIC documentation: option-base(FlexBASIC)

File option-base.bas:

option base 1

dim a(2)
dim b(3)

''
'' set
''
for i=1 to 2
  a(i) = 1000+i
next i

for i=0 to 2
  b(i) = 2000+i
next i

''
'' get
''
for i=1 to 2
  print "a(";i;") = ";a(i)
next i

for i=0 to 2
  print "b(";i;") = ";b(i)
next i

Compile to option-base.bas.binary:

fastspin -O2 option-base.bas -o option-base.bas.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
option-base.bas
fmt.c
strlen.c
option-base.bas.pasm
Done.
Program size is 3212 bytes

Run it in spinsim:

spinsim -b option-base.bas.binary
a(1) = 1001
a(2) = 2000
b(0) = 2000
b(1) = 2001
b(2) = 2002

option base 1 did not prevent using the wrong array indices but at least it documents what the coder had in mind and so may give a hint in which direction the code should be corrected.

That's why I think defining arrays without prior option base n settings should be illegal. There should not be a default because being forced to use option base n adds a bit of documentation that may help to find such errors faster.

4.2.20 peekpoke.bas

@@@TODO@@@ chisel a better example using FlexBASIC's cast. (cast.bas)

See https://forums.parallax.com/discussion/comment/1470253/#Comment_1470253 and its answers, especially https://forums.parallax.com/discussion/comment/1470314/#Comment_1470314.

File peekpoke.bas.bas:

function peek(adr as any) as ubyte
  dim p as ubyte pointer
  p = adr
  return p(0)
end function

sub poke(adr as any, val as ubyte)
  dim p as ubyte pointer
  p = adr
  p(0) = val
end sub

''++ ===========================================================================
'' cast to any
'' is there a better way?
''
'' edit @ 20190510:
'' yes, now there is.
'' see https://github.com/totalspectrum/spin2cpp/blob/master/doc/basic.md#cast
''
function toany(adr as any) as any
  toany = adr
end function
''-- ===========================================================================

dim as string Question$
Question$ = "Surprise?"

'' check "?" being where expected.
'' just to demonstrate peek()
''
if peek(toany(Question$) + 8) == asc("?") then
  print Question$
  poke toany(Question$) + 8, 33
  print Question$
else
  print "Strange things are happening!"
end if

Compile to peekpoke.bas.binary:

fastspin -O2 peekpoke.bas -o peekpoke.bas.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
peekpoke.bas
peekpoke.bas:32: warning: parameter passing discards const attribute from pointer
peekpoke.bas:34: warning: parameter passing discards const attribute from pointer
fmt.c
strlen.c
peekpoke.bas.pasm
Done.
Program size is 2032 bytes

Run it in spinsim:

spinsim -b peekpoke.bas.binary
Surprise?
Surprise!

4.2.21 preprocessor-directive-define.bas

FlexBASIC documentation: define(FlexBASIC)

File preprocessor-directive-define.bas:

#define camouflage "/\/\oo!"
print camouflage

Compile to preprocessor-directive-define.bas.binary:

fastspin -O2 preprocessor-directive-define.bas -o preprocessor-directive-define.bas.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
preprocessor-directive-define.bas
fmt.c
strlen.c
preprocessor-directive-define.bas.pasm
Done.
Program size is 1784 bytes

Run it in spinsim:

spinsim -b preprocessor-directive-define.bas.binary
/\/\oo!

4.2.22 preprocessor-predefined-symbols

@@@TODO@@@ check for new defines. Checked/version: 20190907/3.9.30

FlexBASIC documentation: predefined-symbols(FlexBASIC)

File preprocessor-predefined-symbols.bas:

print "__propeller__  -> ";_
#ifdef __propeller__
  __propeller__
#else
  "*undefined*"
#endif

print "__propeller2__ -> ";_
#ifdef __propeller2__
  __propeller2__
#else
  "*undefined*"
#endif

print "__P2__         -> ";_
#ifdef __P2__
  __P2__
#else
  "*undefined*"
#endif

print "__FLEXBASIC__  -> ";_
#ifdef __FLEXBASIC__
  __FLEXBASIC__
#else
  "*undefined*"
#endif

print "__FASTSPIN__   -> ";_
#ifdef __FASTSPIN__
  __FASTSPIN__
#else
  "*undefined*"
#endif

print "__SPINCVT__    -> ";_
#ifdef __SPINCVT__
  __SPINCVT__
#else
  "*undefined*"
#endif

print "__SPIN2PASM__  -> ";_
#ifdef __SPIN2PASM__
  __SPIN2PASM__
#else
  "*undefined*"
#endif

print "__SPIN2CPP__   -> ";_
#ifdef __SPIN2CPP__
  __SPIN2CPP__
#else
  "*undefined*"
#endif

print "__cplusplus    -> ";_
#ifdef __cplusplus
  __cplusplus
#else
  "*undefined*"
#endif

Compile to preprocessor-predefined-symbols.bas.binary:

fastspin -O2 preprocessor-predefined-symbols.bas -o preprocessor-predefined-symbols.bas.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
preprocessor-predefined-symbols.bas
fmt.c
strlen.c
preprocessor-predefined-symbols.bas.pasm
Done.
Program size is 3588 bytes

Run it in spinsim:

spinsim -b preprocessor-predefined-symbols.bas.binary
__propeller__  -> 1
__propeller2__ -> *undefined*
__P2__         -> *undefined*
__FLEXBASIC__  -> 4
__FASTSPIN__   -> 4
__SPINCVT__    -> 4
__SPIN2PASM__  -> 1
__SPIN2CPP__   -> *undefined*
__cplusplus    -> *undefined*

4.2.23 pseudorandom-float.bas

FlexBASIC documentation: rnd(FlexBASIC)

@@@TODO@@@ find out how to use C's integer pseudorandom rand() in FlexBASIC.

File pseudorandom-float.bas:

for i=1 to 5
  print rnd(1)
next

Compile to pseudorandom-float.bas.binary:

fastspin -O2 pseudorandom-float.bas -o pseudorandom-float.bas.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
pseudorandom-float.bas
random.c
fmt.c
strcpy.c
strlen.c
pseudorandom-float.bas.pasm
Done.
Program size is 8524 bytes

Run it in spinsim:

spinsim -b pseudorandom-float.bas.binary
0.9866
0.5245
0.6519
0.6485
0.8297

4.2.24 pseudorandom-integer.bas

@@@TODO@@@ is this "the best way" to get integer pseudorandom in FlexBASIC? @@@TODO@@@ maybe add an axample using FlexSPIN's integer pseudorandom too?

File pseudorandom-integer.bas:

dim stdlib as class using "stdlib.h"

for i=1 to 3
  print stdlib.rand()
next i

Compile to pseudorandom-integer.bas.binary:

fastspin -O2 pseudorandom-integer.bas -o pseudorandom-integer.bas.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
pseudorandom-integer.bas
|-stdlib.h
rand.c
fmt.c
strlen.c
pseudorandom-integer.bas.pasm
Done.
Program size is 2932 bytes

Run it in spinsim:

spinsim -b pseudorandom-integer.bas.binary
16807
282475249
1622650073

4.2.25 screen-bitmap-as-2d-array.bas

The ability to define two dimensional arrays loke bitmap(y,x) directly did not exist in earlier versions of FlexBASIC. An older variant of this example defining the screen as array of scanlines addressed as bitmap(y)(x) can be found as screen-bitmap-as-array-of-arrays.bas.

File screen-bitmap-as-2d-array.bas:

option base 0

dim vga as class using "VGA_512x384_Bitmap.spin"

dim shared as ulong sync
dim shared as ubyte bitmap(vga.vp - 1, vga.hp / 8 - 1)

dim shared as ushort colors(vga.xtiles * vga.ytiles - 1)
''
''        lowest pin of VGA pin group
''        |
''        V
vga.start(16, @colors, @bitmap, @sync)
''
'' set set same colorpair for all tiles
''
wordfill(@colors, &b111111_00_010101_00, vga.xtiles * vga.ytiles)

bytefill(@bitmap, 0, vga.vp * vga.hp / 8 )

var xmax = vga.hp - 1
var ymax = vga.vp - 1

for x = 0 to xmax : plot x, 0 : plot x, ymax : next
for y = 0 to ymax : plot 0, y : plot xmax, y : next

for x = 0 to ymax
  plot        x,        x
  plot xmax - x,        x
  plot        x, ymax - x
  plot xmax - x, ymax - x
next

do
loop

sub plot x,y
  bitmap(y, x >> 3) = bitmap(y, x >> 3) or (1 << (x and 7))
end sub

Compile to screen-bitmap-as-2d-array.bas.binary:

fastspin -O2 screen-bitmap-as-2d-array.bas -o screen-bitmap-as-2d-array.bas.binary -L lib
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
screen-bitmap-as-2d-array.bas
|-VGA_512x384_Bitmap.spin
screen-bitmap-as-2d-array.bas.pasm
Done.
Program size is 26568 bytes

Run it in gear:

screen-bitmap-as-2d-array.bas.png

screen-bitmap-as-2d-array.bas.png

4.2.26 screen-bitmap-as-array-of-arrays.bas

This demonstrates a way to define multidimensional arrays a(y)(x) as alternative to the more common form a(y,x) which was not possible in earlier versions of FlexBASIC. The example screen-bitmap-as-2d-array.bas demonstrates the newer a(y,x) way.

This example using an array of arrays may still be useful in some contexts:

File screen-bitmap-as-array-of-arrays.bas:

option base 0

dim vga as class using "VGA_512x384_Bitmap.spin"

type scanline as ubyte(vga.hp / 8 - 1)
type screen as scanline(vga.vp - 1)

dim shared as ulong sync
dim shared as screen bitmap

dim shared as ushort colors(vga.xtiles * vga.ytiles - 1)
''
''        lowest pin of VGA pin group
''        |
''        V
vga.start(16, @colors, @bitmap, @sync)
''
'' set set same colorpair for all tiles
''
wordfill(@colors, &b111111_00_000000_00, 192)

bytefill(@bitmap, 0, vga.vp * vga.hp / 8 )

var xmax = vga.hp - 1
var ymax = vga.vp - 1

for x = 0 to xmax : plot x, 0 : plot x, ymax : next
for y = 0 to ymax : plot 0, y : plot xmax, y : next

for x = 0 to ymax
  plot        x,        x
  plot xmax - x,        x
  plot        x, ymax - x
  plot xmax - x, ymax - x
next

do
loop

sub plot x,y
  var byt = x >> 3
  bitmap(y)(byt) = bitmap(y)(byt) or (1 << (x and 7))
end sub

Compile to screen-bitmap-as-array-of-arrays.bas.binary:

fastspin -O2 screen-bitmap-as-array-of-arrays.bas -o screen-bitmap-as-array-of-arrays.bas.binary -L lib
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
screen-bitmap-as-array-of-arrays.bas
|-VGA_512x384_Bitmap.spin
screen-bitmap-as-array-of-arrays.bas.pasm
Done.
Program size is 26568 bytes

Run it in gear:

screen-bitmap-as-array-of-arrays.bas.png

screen-bitmap-as-array-of-arrays.bas.png

4.2.27 sendrecvdevice-demo.bas

FlexBASIC documentation: sendrecvdevice(FlexBASIC)

File sendrecvdevice-demo.bas:

dim ser2 as class using "spin/FullDuplexSerial.spin"

ser2.start(31, 30, 0, 115200)

open SendRecvDevice( @ser2.tx, @ser2.rx, @ser2.stop ) as #2

print #2,"Hi! (printed via FullDuplexSerial.spin)"

pausems 1000

close #2

Compile to sendrecvdevice-demo.bas.binary:

fastspin -O2 sendrecvdevice-demo.bas -o sendrecvdevice-demo.bas.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
sendrecvdevice-demo.bas
|-FullDuplexSerial.spin
fmt.c
gcptrs.spin
strlen.c
sendrecvdevice-demo.bas.pasm
Done.
Program size is 7212 bytes

Run it in spinsim:

spinsim -b sendrecvdevice-demo.bas.binary
Hi! (printed via FullDuplexSerial.spin)

4.2.28 static-image-vga-512x384x1.bas

An extreme example for a really long line as array initialisation. ;-)

A moderate example can be found in extending-lines.bas.

See https://forums.parallax.com/discussion/comment/1453190/#Comment_1453190.

File static-image-vga-512x384x1.bas.
(Too long to be displayed inline.)

Compile to static-image-vga-512x384x1.bas.binary:

fastspin -O2 static-image-vga-512x384x1.bas -o static-image-vga-512x384x1.bas.binary -L lib
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
static-image-vga-512x384x1.bas
|-VGA_512x384_Bitmap.spin
static-image-vga-512x384x1.bas.pasm
Done.
Program size is 26216 bytes

Run it in gear:

static-image-vga-512x384x1.bas.png

static-image-vga-512x384x1.bas.png

4.2.29 xor.bas

FlexBASIC documentation: XOR(FlexBASIC).

File xor.bas:

var x = 13
var y = 42
print x, y

x = x xor y
y = y xor x
x = x xor y
print x, y

Compile to xor.bas.binary:

fastspin xor.bas -o xor.bas.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
xor.bas
fmt.c
strlen.c
xor.bas.pasm
Done.
Program size is 2928 bytes

Run it in spinsim:

spinsim -b xor.bas.binary
13	42
42	13

4.3 FlexC

4.3.1 Importing Stuff in C

4.3.1.1 (OLD) Importing LMM-C in LMM-C - io-funcs.c

See https://github.com/totalspectrum/spin2cpp/blob/master/doc/c.md#external-classes-eg-spin-objects. File io-funcs.c:

int puts( const char *s ) {
  int n = 0;

  while( *s ) {
    _tx( *(s++) );
    ++n;
  }
  return n;
}

File io-funcs-demo.c:

struct __using("io-funcs.c") io;

void main( void ) {
  io.puts("Hello, FlexC!\r\n");
}

Compile to io-funcs-demo.c.binary:

fastspin -O2 io-funcs-demo.c -o io-funcs-demo.c.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
io-funcs-demo.c
|-io-funcs.c
io-funcs-demo.c.pasm
Done.
Program size is 584 bytes

Run it in spinsim:

spinsim -b io-funcs-demo.c.binary
Hello, FlexC!

4.3.1.2 (NEW) Importing LMM-C and Cog-C in LMM-C - SimpleSerial.c

This is a quick and dirty partial translation of SimpleSerial.spin to C. It will be used to demonstrate including of external objects running in LMM or COG mode.

See https://github.com/totalspectrum/spin2cpp/blob/master/Lib/SimpleSerial.spin.

File SimpleSerial.c:

//
// SimpleSerial.c
//
// ...a crude, quick and dirty partial translation of spin2cpp's
// Lib/SimpleSerial.spin (commit 5c67857f0523280874ee654e6139a8d23c7b21c9)
//

#include <stdint.h>

uint8_t txpin, rxpin;
uint32_t baud, txmask, rxmask, bitcycles;

#ifdef PC
// we will be using stdio
#include <stdio.h>
#include <stdlib.h>
//
#else
//
#include <propeller.h>
#ifdef __P2__
#define DIRR DIRB   
#define OUTR OUTB
#define INR  INB
#else
#define DIRR DIRA
#define OUTR OUTA
#define INR  INA
#endif
//
#endif

//
// code: largely taken from FullDuplexSerial.spin
//

uint32_t start(uint32_t rx_pin, uint32_t tx_pin, uint32_t mode, uint32_t baudrate)
{
#ifndef PC
  baud = baudrate;
  bitcycles = CLKFREQ / baudrate;
  txpin = tx_pin;
  txmask = 1<<txpin;
  rxpin = rx_pin;
  rxmask = 1<<rxpin;
#endif
  return 1;
}

void tx(uint8_t c)
{
  uint32_t val, waitcycles;
#ifdef PC
  putchar(c);
#else
  OUTR |= txmask;
  DIRR |= txmask;
  val = ((uint16_t)c | 256) << 1; // c needs the cast or a bigger type above
  waitcycles = CNT + bitcycles;
  for( int8_t i = 0 ; i<10 ; i++ ) {
     waitcnt( waitcycles += bitcycles );
     if (val & 1)
       OUTR |= txmask;
     else
       OUTR &= !txmask;
     val >>= 1;
  }
#endif
}

uint8_t rx(void) // does NOT return errorcodes outside of the 8 bit range
{
  uint32_t waitcycles, mask, val, x;
#ifdef PC
  val = getchar();
#else
  mask = rxmask;
  DIRR &= !mask; // set for input
  // wait for start bit
  do{
    x = INR;
  }while( x & mask );
  val = 0;
  waitcycles = CNT + (bitcycles >> 1);  // sync for one half bit
  for( int i=0 ; i<8 ; i++ ) {
      val = val >> 1;
      waitcnt(waitcycles += bitcycles);
      x = INR;
      if ( x & mask )
	val |= 0x80;
  }
  // wait for stop bit?
  // skip it for now
  // waitpeq(mask, mask, 0)
#endif
  return val;
}

int32_t stop(void)
{
  waitcnt(CLKFREQ + cnt);
  return 1;
}
4.3.1.2.1 Include SimpleSerial.c

This simply includes SimpleSerial.c while compiling the main program. It is like including Spin objects in Spin programs and indeed FlexC's way of doing this works with code from FlexSPIN and FlexBASIC too.

File SimpleSerialDemo1.c:

struct __using("SimpleSerial.c") sio;

void str(const char *s)
{
  char c;
  while( c = *s++ )
    sio.tx(c);
}

void main(void)
{
  sio.start(31, 30, 0, 115200);

  str("Yayyyy FastSpin!.\r\n");

  // @@@TODO@@@ make a better batchable sio.rx() test.
  for(;;) {
    char c = sio.rx();
    if( c == 27 )
      break;
    else
      sio.tx( c );
  }

  sio.stop();
}

Compile to SimpleSerialDemo1.c.binary:

fastspin -O2 SimpleSerialDemo1.c -o SimpleSerialDemo1.c.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
SimpleSerialDemo1.c
|-SimpleSerial.c
SimpleSerialDemo1.c.pasm
Done.
Program size is 1320 bytes

Run it in spinsim:

( sleep 1 ; \
  printf "Absolutely!\r\n\e" \
) | spinsim -b SimpleSerialDemo1.c.binary
Yayyyy FastSpin!.
Absolutely!

4.3.1.2.2 Include SimpleSerial.c compiled to COG-PASM

For information about compiling for running in an own cog, see https://github.com/totalspectrum/spin2cpp/blob/master/Fastspin.md#spin-wrappers.

Compile the same SimpleSerial.c from above to SimpleSerial.c.cog.spin:

fastspin -O2 -w SimpleSerial.c -o SimpleSerial.c.cog.spin
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
SimpleSerial.c

File SimpleSerialDemo2.c:

struct __using("SimpleSerial.c.cog.spin") sio;

void str(const char *s)
{
  char c;
  while( c = *s++ )
    sio.tx(c);
}

void main(void)
{
  sio.__cognew();
  sio.start(31, 30, 0, 115200);

  str("Yayyyy FastSpin!.\r\n");

  // @@@TODO@@@ make a better batchable sio.rx() test.
  for(;;) {
    char c = sio.rx();
    if( c == 27 )
      break;
    else
      sio.tx( c );
  }

  sio.stop();
  sio.__cogstop();
}

Compile to sio-funcs-demo.c.binary:

fastspin -O2 SimpleSerialDemo2.c -o SimpleSerialDemo2.c.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
SimpleSerialDemo2.c
|-SimpleSerial.c.cog.spin
SimpleSerialDemo2.c.pasm
Done.
Program size is 2292 bytes

Run it in spinsim:

( sleep 1 ; \
  printf "Absolutely!\r\n\e" \
) | spinsim -b SimpleSerialDemo2.c.binary
Yayyyy FastSpin!.
Absolutely!

4.3.2 inline-asm.c

FlexC documentation: inline-assembly(FlexC)

File inline-asm.c:

#include <stdio.h>

int answer(int question) {
   int result;
   __asm {
       mov result, question
       add result, result
       add result, question
   };
   return result;
}

void main( void ) {
  printf( "the answer is %d\n", answer(14) );
}

Compile to inline-asm.c.binary:

fastspin -O2 inline-asm.c -o inline-asm.c.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
inline-asm.c
fmt.c
strlen.c
inline-asm.c.pasm
Done.
Program size is 2836 bytes

Run it in spinsim:

spinsim -b inline-asm.c.binary
the answer is 42

4.3.3 mandelbrot-float.c

File mandelbrot-float.c:

#include <stdio.h>
#include <stdint.h>

#define XMIN (-2.1)
#define XMAX (0.7)
#define YMIN (-1.2)
#define YMAX (1.2)

#define MAXI (32)

#define DX   ((XMAX-XMIN)/79)
#define DY   ((YMAX-YMIN)/24)

int main(){
  float cx, cy, x, y, x2, y2;
  uint32_t iter;

  for( cy=YMIN; cy<=YMAX; cy+=DY ) {
    for( cx=XMIN; cx<=XMAX; cx+=DX ) {
      x = y = x2 = y2 = 0.0;
      for( iter=0; iter<MAXI && x2+y2<=4.0; iter++ ) {
	y = 2*x*y+cy;
	x = x2-y2+cx;
	x2 = x*x;
	y2 = y*y;
      }
      putchar(32+iter);
    }
    putchar(10);
  }
}

Compile to mandelbrot-float.c.binary:

fastspin -O2 mandelbrot-float.c -o mandelbrot-float.c.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
mandelbrot-float.c
ftab.c
mandelbrot-float.c.pasm
Done.
Program size is 2660 bytes

Run it in spinsim:

spinsim -b mandelbrot-float.c.binary
!!!!!!!!!!!!!!!"""""""""""""####################################"""""""""""""""
!!!!!!!!!!!!!"""""""""#######################$$$$$$$%'0(%%%$$$$$#####""""""""""
!!!!!!!!!!!"""""""#######################$$$$$$$$%%%&&(++)++&$$$$$$$######"""""
!!!!!!!!!"""""#######################$$$$$$$$$$%%%%&')*@;/*('&%%$$$$$$#######""
!!!!!!!!""""#####################$$$$$$$$$$%%%&&&''),@@@@@@@+'&%%%%%$$$$#######
!!!!!!!"""####################$$$$$$$$%%%&'())((())*-@@@@@@.+))('&&&&+&%$$#####
!!!!!!""###################$$$$$%%%%%%&&&'+.@@@08@@@@@@@@@@@@@@@/+,@//@)%%$####
!!!!!"################$$$%%%%%%%%%%&&&&')-+7@@@@@@@@@@@@@@@@@@@@@@@@@4(&&%$$###
!!!!"##########$$$$$%%&(,('''''''''''((*-5@@@@@@@@@@@@@@@@@@@@@@@@@@@3+)4&%$$##
!!!!####$$$$$$$$%%%%%&'(*-@1.+/@-4+))**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@3+'&%$$$#
!!!!#$$$$$$$$$%%%%%%'''++.7@@@@@@@@@9/0@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@<6'%%$$$$
!!!#$$$$$$$%&&&&''().-2.6@@@@@@@@@@@@@>@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@'&%%$$$$
!!!7:=?@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@2+)'&&%%$$$$
!!!#$$$$$$$%&&&&''().-2.6@@@@@@@@@@@@@>@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@'&%%$$$$
!!!!#$$$$$$$$$%%%%%%'''++.7@@@@@@@@@9/0@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@<6'%%$$$$
!!!!####$$$$$$$$%%%%%&'(*-@1.+/@-4+))**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@3+'&%$$$#
!!!!"##########$$$$$%%&(,('''''''''''((*-5@@@@@@@@@@@@@@@@@@@@@@@@@@@3+)4&%$$##
!!!!!"################$$$%%%%%%%%%%&&&&')-+7@@@@@@@@@@@@@@@@@@@@@@@@@4(&&%$$###
!!!!!!""###################$$$$$%%%%%%&&&'+.@@@08@@@@@@@@@@@@@@@/+,@//@)%%$####
!!!!!!!"""####################$$$$$$$$%%%&'())((())*-@@@@@@.+))('&&&&+&%$$#####
!!!!!!!!""""#####################$$$$$$$$$$%%%&&&''),@@@@@@@+'&%%%%%$$$$#######
!!!!!!!!!"""""#######################$$$$$$$$$$%%%%&')*@;/*('&%%$$$$$$#######""
!!!!!!!!!!!"""""""#######################$$$$$$$$%%%&&(++)++&$$$$$$$######"""""
!!!!!!!!!!!!!"""""""""#######################$$$$$$$%'0(%%%$$$$$#####""""""""""

4.3.4 mandelbrot-s4p12.c

File mandelbrot-s4p12.c:

// fixpoint arithmetic mandelbrot program
// using 16 bits: viiiffffffffffff
//                ||  |_ broken part
//                ||____ integer part
//                |_____ sign bit
//
// so fixedpoint(x) = x * 4096
//                  = x << 12
// and fixedpoint(x*y) = (x*y)>>12

#include <stdio.h>
#include <stdint.h>

#define XMIN (-8601)
#define XMAX ( 2867)
#define YMIN (-4915)
#define YMAX ( 4915)

#define MAXI (32)

#define DX   ((XMAX-XMIN)/79)
#define DY   ((YMAX-YMIN)/24)

int main() {
  int32_t cx,cy,x,y,x2,y2;
  uint32_t iter;

  for( cy=YMIN; cy<=YMAX; cy+=DY ) {
    for( cx=XMIN; cx<=XMAX; cx+=DX ) {
      x = y = x2 = y2 = 0;
      for( iter=0; iter<MAXI && x2+y2<=16384; iter++ ) {
	y = ((x*y)>>11)+cy;
	x = x2-y2+cx;
	x2 = (x*x)>>12;
	y2 = (y*y)>>12;
      }
      putchar(32+iter);
    }
    putchar(10);
  }
}

Compile to mandelbrot-s4p12.c.binary:

fastspin -O2 mandelbrot-s4p12.c -o mandelbrot-s4p12.c.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
mandelbrot-s4p12.c
ftab.c
mandelbrot-s4p12.c.pasm
Done.
Program size is 1516 bytes

Run it in spinsim:

spinsim -b mandelbrot-s4p12.c.binary
!!!!!!!!!!!!!!!"""""""""""""####################################""""""""""""""""
!!!!!!!!!!!!!"""""""""#######################$$$$$$$%'+)%%%$$$$$#####"""""""""""
!!!!!!!!!!!"""""""#######################$$$$$$$$%%%&&(+,)++&%$$$$$$######""""""
!!!!!!!!!"""""#######################$$$$$$$$$$%%%%&')*5:/+('&%%$$$$$$#######"""
!!!!!!!!""""#####################$$$$$$$$$$%%%&&&''),@@@@@@@,'&%%%%%$$$$########
!!!!!!!"""####################$$$$$$$$%%%&'())((())*,@@@@@@/+))('&&&&)'%$$######
!!!!!!""###################$$$$$%%%%%%&&&'+.@@=/<@@@@@@@@@@@@@@@/++@..93%%$#####
!!!!!"################$$$%%%%%%%%%%&&&&'),+2@@@@@@@@@@@@@@@@@@@@@@@@@1(&&%$$####
!!!!"##########$$$$$%%&(-(''''''''''''(*,5@@@@@@@@@@@@@@@@@@@@@@@@@@@@+)-&%$$###
!!!!####$$$$$$$$%%%%%&'(*-@1.+.@-4+))**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@4-(&%$$$##
!!!!#$$$$$$$$$%%%%%%'''++.6@@@@@@@@@8/0@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@3(%%$$$$#
!!!#$$$$$$$%&&&&''()/-5.5@@@@@@@@@@@@@>@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@?'&%%$$$$#
!!!(**+/+<523/80/46@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@4+)'&&%%$$$$#
!!!#$$$$$$$%&&&&''().-2.@@@@@@@@@@@@@@?@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@'&%%$$$$#
!!!!#$$$$$$$$$%%%%%&'''/,.7@@@@@@@@@;/0@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@0'%%$$$$#
!!!!####$$$$$$$$%%%%%&'(*-:2.,/?-5+))**@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@4+(&%$$$##
!!!!"##########$$$$$%%&(-(''''(''''''((*,4@@@@@@@@@@@@@@@@@@@@@@@@@@@4+).&%$$###
!!!!!"################$$$%%%%%%%%%%&&&&')<,4@@@@@@@@@@@@@@@@@@@@@@@@@/('&%%$####
!!!!!!""##################$$$$$$%%%%%%&&&'*.@@@0@@@@@@@@@@@@@@@@1,,@//9)%%$#####
!!!!!!!"""####################$$$$$$$$%%%&(())((()**-@@@@@@/+)))'&&&')'%$$######
!!!!!!!!""""#####################$$$$$$$$$$%%%&&&''(,@@@@@@@+'&&%%%%%$$$########
!!!!!!!!!"""""#######################$$$$$$$$$$%%%%&')*7@0+('&%%%$$$$$#######"""
!!!!!!!!!!!"""""""######################$$$$$$$$$%%%&&(+-).*&%$$$$$$######""""""
!!!!!!!!!!!!!"""""""""#######################$$$$$$%%'3(%%%$$$$$######""""""""""
!!!!!!!!!!!!!!!""""""""""""#####################################""""""""""""""""

4.3.5 monochrome-vga.c

This example is focussing on how to include and initialise the monocrome VGA bitmap "driver".

File monochrome-vga.c:

#include <stdint.h>

struct __using("VGA_512x384_Bitmap.spin") vga;

uint32_t bitmap[vga.hp/32*vga.vp];
uint16_t colors[vga.xtiles*vga.ytiles];
uint32_t sync;

void main(void)
{
  //
  //        lowest pin of VGA pingroup
  //        |
  //        V
  vga.start(16,colors,bitmap,sync);
  //
  // set same colorpair for all tiles
  //
  wordfill(colors,0b110011_00_001100_00,vga.xtiles*vga.ytiles);
  //               magenta on green

  longfill(bitmap,0xf0f0f0f0,vga.hp/32*vga.vp);

  for(;;); // for(ever)
}

Compile to monochrome-vga.c.binary:

fastspin -O2 monochrome-vga.c -o monochrome-vga.c.binary -L lib
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
monochrome-vga.c
|-VGA_512x384_Bitmap.spin
monochrome-vga.c.pasm
Done.
Program size is 26288 bytes

Run it in gear:

monochrome-vga.c.png

monochrome-vga.c.png

4.3.6 pseudorandom-integer.c

File pseudorandom-integer.c:

#include <stdio.h>
#include <stdlib.h> // rand() lives here

void main(void) {
  for( int i=1 ; i<=3 ; i++ )
    printf("%d\n",rand());
}

Compile to pseudorandom-integer.c.binary:

fastspin -O2 pseudorandom-integer.c -o pseudorandom-integer.c.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
pseudorandom-integer.c
rand.c
fmt.c
strlen.c
pseudorandom-integer.c.pasm
Done.
Program size is 2940 bytes

Run it in spinsim:

spinsim -b pseudorandom-integer.c.binary
16807
282475249
1622650073

4.3.7 truchet-tiles-16x16-vga-512x384x1.c

File truchet-tiles-16x16-vga-512x384x1.c:

#include <propeller.h>
#include <stdint.h>
#include <stdlib.h>

struct __using("VGA_512x384_Bitmap.spin") vga;
uint16_t wordmap[vga.vp][vga.hp>>4];
uint16_t colors[vga.xtiles*vga.ytiles];
uint32_t sync;

uint16_t cg[16][2] = {
  { 0b0_0_0_1_1_0_0_0_0_0_0_1_1_0_0_0, 0b0_0_0_1_1_0_0_0_0_0_0_1_1_0_0_0 },
  { 0b0_0_0_0_1_1_0_0_0_0_1_1_0_0_0_0, 0b0_0_0_1_1_0_0_0_0_0_0_1_1_0_0_0 },
  { 0b0_0_0_0_0_1_1_0_0_1_1_0_0_0_0_0, 0b0_0_1_1_0_0_0_0_0_0_0_0_1_1_0_0 },
  { 0b1_0_0_0_0_0_1_1_1_1_0_0_0_0_0_1, 0b1_1_1_0_0_0_0_0_0_0_0_0_0_1_1_1 },
  { 0b1_1_0_0_0_0_0_1_1_0_0_0_0_0_1_1, 0b1_1_0_0_0_0_0_0_0_0_0_0_0_0_1_1 },
  { 0b0_1_1_0_0_0_0_0_0_0_0_0_0_1_1_0, 0b0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 },
  { 0b0_0_1_1_0_0_0_0_0_0_0_0_1_1_0_0, 0b0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 },
  { 0b0_0_0_1_1_0_0_0_0_0_0_1_1_0_0_0, 0b0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 },
  { 0b0_0_0_1_1_0_0_0_0_0_0_1_1_0_0_0, 0b0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 },
  { 0b0_0_1_1_0_0_0_0_0_0_0_0_1_1_0_0, 0b0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 },
  { 0b0_1_1_0_0_0_0_0_0_0_0_0_0_1_1_0, 0b0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0 },
  { 0b1_1_0_0_0_0_0_1_1_0_0_0_0_0_1_1, 0b1_1_0_0_0_0_0_0_0_0_0_0_0_0_1_1 },
  { 0b1_0_0_0_0_0_1_1_1_1_0_0_0_0_0_1, 0b1_1_1_0_0_0_0_0_0_0_0_0_0_1_1_1 },
  { 0b0_0_0_0_0_1_1_0_0_1_1_0_0_0_0_0, 0b0_0_1_1_0_0_0_0_0_0_0_0_1_1_0_0 },
  { 0b0_0_0_0_1_1_0_0_0_0_1_1_0_0_0_0, 0b0_0_0_1_1_0_0_0_0_0_0_1_1_0_0_0 },
  { 0b0_0_0_1_1_0_0_0_0_0_0_1_1_0_0_0, 0b0_0_0_1_1_0_0_0_0_0_0_1_1_0_0_0 }
};

void randtile(uint8_t x, uint16_t y, uint8_t r) {
  y<<=4;
  for( uint8_t s=0 ; s<16 ; )
    wordmap[y++][x]=cg[s++][r];
}

void main(void) {
  vga.start(16,colors,wordmap,sync);
  wordfill(colors,0b001100_00_010101_00,vga.xtiles*vga.ytiles);
  //
  // fill the whole screen once
  //
  for( uint8_t y=0 ; y<(vga.vp>>4) ; y++ )
    for( uint8_t x=0 ; x<(vga.hp>>4) ; x++ )
      randtile(x,y,rand()&1);
  //
  // then change random tiles to random values
  //
  for( uint32_t t=CNT ;; waitcnt(t+=CLKFREQ) )
    randtile(rand()%(vga.hp>>4),rand()%(vga.vp>>4),rand()&1);
}

Compile to truchet-tiles-16x16-vga-512x384x1.c.binary:

fastspin -O2 truchet-tiles-16x16-vga-512x384x1.c -o truchet-tiles-16x16-vga-512x384x1.c.binary -L lib
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
truchet-tiles-16x16-vga-512x384x1.c
|-VGA_512x384_Bitmap.spin
rand.c
truchet-tiles-16x16-vga-512x384x1.c.pasm
Done.
Program size is 26912 bytes

Run it in gear:

truchet-tiles-16x16-vga-512x384x1.c.png

truchet-tiles-16x16-vga-512x384x1.c.png

4.3.8 truchet-tiles-8x8-vga-512x384x1.c

File truchet-tiles-8x8-vga-512x384x1.c:

#include <propeller.h>
#include <stdint.h>
#include <stdlib.h>

struct __using("VGA_512x384_Bitmap.spin") vga;
uint8_t bytemap[vga.vp][vga.hp>>3];
uint16_t colors[vga.xtiles*vga.ytiles];
uint32_t sync;

uint16_t cg[8][2] = {
  { 0b0_0_1_0_0_1_0_0, 0b0_0_1_0_0_1_0_0 },
  { 0b0_0_1_0_0_1_0_0, 0b0_0_0_1_1_0_0_0 },
  { 0b1_1_1_0_0_1_1_1, 0b1_0_0_0_0_0_0_1 },
  { 0b0_0_0_0_0_0_0_0, 0b0_1_0_0_0_0_1_0 },
  { 0b0_0_0_0_0_0_0_0, 0b0_1_0_0_0_0_1_0 },
  { 0b1_1_1_0_0_1_1_1, 0b1_0_0_0_0_0_0_1 },
  { 0b0_0_1_0_0_1_0_0, 0b0_0_0_1_1_0_0_0 },
  { 0b0_0_1_0_0_1_0_0, 0b0_0_1_0_0_1_0_0 }
};

void randtile(uint8_t x, uint16_t y, uint8_t r) {
  y<<=3;
  for( uint8_t s=0 ; s<8 ; )
    bytemap[y++][x]=cg[s++][r];
}

void main(void) {
  vga.start(16,colors,bytemap,sync);
  wordfill(colors,0b001100_00_010101_00,vga.xtiles*vga.ytiles);
  //
  // fill the whole screen once
  //
  for( uint8_t y=0 ; y<(vga.vp>>3) ; y++ )
    for( uint8_t x=0 ; x<(vga.hp>>3) ; x++ )
      randtile(x,y,rand()&1);
  //
  // then change random tiles to random values
  //
  for( uint32_t t=CNT ;; waitcnt(t+=CLKFREQ) )
    randtile(rand()%(vga.hp>>3),rand()%(vga.vp>>3),rand()&1);
}

Compile to truchet-tiles-8x8-vga-512x384x1.c.binary:

fastspin -O2 truchet-tiles-8x8-vga-512x384x1.c -o truchet-tiles-8x8-vga-512x384x1.c.binary -L lib
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
truchet-tiles-8x8-vga-512x384x1.c
|-VGA_512x384_Bitmap.spin
rand.c
truchet-tiles-8x8-vga-512x384x1.c.pasm
Done.
Program size is 26876 bytes

Run it in gear:

truchet-tiles-8x8-vga-512x384x1.c.png

truchet-tiles-8x8-vga-512x384x1.c.png

6 Labour Ward

6.1 FlexSpin

6.1.1 TODO conditional-expression-demo0.spin

FlexSPIN documentation: conditional-expressions(FlexSPIN)

@@@TODO@@@ example for the r := if a then b else c variant.

6.1.2 TODO hopper-vga-512x384x1.spin

@@@TODO@@@

6.1.3 TODO spinlibdemo.spin

See https://github.com/totalspectrum/spin2cpp/blob/master/doc/spin.md#pub-file-and-pri-file.

File spinlibdemo.spinlib:

pub strcpy(s, d) : r
  r := d
  repeat while byte[d++] := byte[s++]

pub strlen(s) : r
  r := s
  repeat while byte[r]
    r++
  r -= s

File spinlibdemo.spinh:

pub file "spinlibdemo.spinlib" strcpy(s, d)
pub file "spinlibdemo.spinlib" strlen(s)

File spinlibdemo.spin:

con
  _clkmode = xtal1+pll16x
  _clkfreq = 80_000_000

obj
  ser : "spin/FullDuplexSerial"

var
  byte str32[32]

pub main
  ser.start(31, 30, 0, 115200)

  strcpy(string("Hello, World!", 13, 10), str32)
  ser.str(str32)

  ser.dec(strlen(str32))
  ser.str(string(" bytes including CR/LF", 13, 10))

  waitcnt(_clkfreq + cnt)
    ser.stop
  cogstop(0)

''
'' this is the thing to be demonstrated:
''
#include "spinlibdemo.spinh"

Compile to spinlibdemo.spin.binary:

fastspin -O2 spinlibdemo.spin -o spinlibdemo.spin.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
spinlibdemo.spin
|-FullDuplexSerial.spin
spinlibdemo.spinlib
spinlibdemo.spin.pasm
Done.
Program size is 2372 bytes

Run it in spinsim:

spinsim -b spinlibdemo.spin.binary
Hello, World!
15 bytes including CR/LF

6.1.4 TODO truchet-tiles-16x16-vga-512x384x1.spin

FlexSPIN documentation: spin2-operators(FlexSPIN)

@@@TODO@@@ slow down random tiles at random position loop.

File truchet-tiles-16x16-vga-512x384x1.spin:

dat
  cg
    word %0_0_0_1_1_0_0_0_0_0_0_1_1_0_0_0, %0_0_0_1_1_0_0_0_0_0_0_1_1_0_0_0
    word %0_0_0_0_1_1_0_0_0_0_1_1_0_0_0_0, %0_0_0_1_1_0_0_0_0_0_0_1_1_0_0_0
    word %0_0_0_0_0_1_1_0_0_1_1_0_0_0_0_0, %0_0_0_1_1_0_0_0_0_0_0_1_1_0_0_0
    word %1_0_0_0_0_0_1_1_1_1_0_0_0_0_0_1, %1_1_1_1_1_0_0_0_0_0_0_1_1_1_1_1
    word %1_1_0_0_0_0_0_1_1_0_0_0_0_0_1_1, %1_1_1_1_1_0_0_0_0_0_0_1_1_1_1_1
    word %0_1_1_0_0_0_0_0_0_0_0_0_0_1_1_0, %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0
    word %0_0_1_1_0_0_0_0_0_0_0_0_1_1_0_0, %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0
    word %0_0_0_1_1_0_0_0_0_0_0_1_1_0_0_0, %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0
    word %0_0_0_1_1_0_0_0_0_0_0_1_1_0_0_0, %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0
    word %0_0_1_1_0_0_0_0_0_0_0_0_1_1_0_0, %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0
    word %0_1_1_0_0_0_0_0_0_0_0_0_0_1_1_0, %0_0_0_0_0_0_0_0_0_0_0_0_0_0_0_0
    word %1_1_0_0_0_0_0_1_1_0_0_0_0_0_1_1, %1_1_1_1_1_0_0_0_0_0_0_1_1_1_1_1
    word %1_0_0_0_0_0_1_1_1_1_0_0_0_0_0_1, %1_1_1_1_1_0_0_0_0_0_0_1_1_1_1_1
    word %0_0_0_0_0_1_1_0_0_1_1_0_0_0_0_0, %0_0_0_1_1_0_0_0_0_0_0_1_1_0_0_0
    word %0_0_0_0_1_1_0_0_0_0_1_1_0_0_0_0, %0_0_0_1_1_0_0_0_0_0_0_1_1_0_0_0
    word %0_0_0_1_1_0_0_0_0_0_0_1_1_0_0_0, %0_0_0_1_1_0_0_0_0_0_0_1_1_0_0_0

con
  tiles = vga#xtiles * vga#ytiles

obj
  vga : "VGA_512x384_Bitmap.spin"
  lib : "stdlib.h"

var
  long sync
  word wordmap[vga#vp * vga#hp >> 4]
  word colors[tiles]

pub main | x, y
  vga.start(16, @colors, @wordmap, @sync)
  wordfill(@colors,%001100_00_010101_00,tiles)

  repeat y from 0 to 23
    repeat x from 0 to 31
      randtile(x, y)

  repeat
    randtile(lib.rand // 32, lib.rand // 24)

pri randtile(x, y) | c, p
  p := y << 9 + x
  c := @cg + (lib.rand & 2)
  repeat 16
    wordmap[p \ p + 32] := word[c \ c + 4]

Compile to truchet-tiles-16x16-vga-512x384x1.spin.binary:

fastspin -O2 truchet-tiles-16x16-vga-512x384x1.spin -o truchet-tiles-16x16-vga-512x384x1.spin.binary -L lib
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
truchet-tiles-16x16-vga-512x384x1.spin
|-VGA_512x384_Bitmap.spin
|-stdlib.h
rand.c
truchet-tiles-16x16-vga-512x384x1.spin.pasm
Done.
Program size is 1804 bytes

Run it in gear:

truchet-tiles-16x16-vga-512x384x1.spin.png

truchet-tiles-16x16-vga-512x384x1.spin.png

6.1.5 TODO truchet-tiles-8x8-vga-512x384x1.spin

FlexSPIN documentation: spin2-operators(FlexSPIN)

@@@TODO@@@ I saw temporarily graphical glitches (see below) which vanished without my interaction which may or may not be a gear problem.

@@@TODO@@@ slow down random tiles at random position loop.

File truchet-tiles-8x8-vga-512x384x1.spin:

dat
  cg
    byte %0_0_0_1_1_0_0_0, %0_0_0_1_1_0_0_0
    byte %0_0_0_1_1_0_0_0, %0_0_0_1_1_0_0_0
    byte %0_0_1_1_0_0_0_0, %0_0_0_0_1_1_0_0
    byte %1_1_1_0_0_0_1_1, %1_1_0_0_0_1_1_1
    byte %1_1_0_0_0_1_1_1, %1_1_1_0_0_0_1_1
    byte %0_0_0_0_1_1_0_0, %0_0_1_1_0_0_0_0
    byte %0_0_0_1_1_0_0_0, %0_0_0_1_1_0_0_0
    byte %0_0_0_1_1_0_0_0, %0_0_0_1_1_0_0_0

con
  tiles = vga#xtiles * vga#ytiles

obj
  vga : "VGA_512x384_Bitmap.spin"
  lib : "stdlib.h"

var
  long sync
  byte bytemap[vga#vp * vga#hp >> 3]
  word colors[tiles]

pub main | x, y
  vga.start(16, @colors, @bytemap, @sync)
  wordfill(@colors,%001100_00_010101_00,tiles)

  repeat y from 0 to 47
    repeat x from 0 to 63
      randtile(x, y)

  repeat
    randtile(lib.rand // 64, lib.rand // 48)

pri randtile(x, y) | c, p
  p := y << 9 + x
  c := @cg + (lib.rand & 1)
  repeat 8
    bytemap[p \ p + 64] := byte[c \ c + 2]

Compile to truchet-tiles-8x8-vga-512x384x1.spin.binary:

fastspin -O2 truchet-tiles-8x8-vga-512x384x1.spin -o truchet-tiles-8x8-vga-512x384x1.spin.binary -L lib
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 19 2019
truchet-tiles-8x8-vga-512x384x1.spin
|-VGA_512x384_Bitmap.spin
|-stdlib.h
rand.c
truchet-tiles-8x8-vga-512x384x1.spin.pasm
Done.
Program size is 1744 bytes

Run it in gear:

truchet-tiles-8x8-vga-512x384x1.spin.png

truchet-tiles-8x8-vga-512x384x1.spin.png

A glitch:

truchet-tiles-8x8-vga-512x384x1-glitch.spin.png

truchet-tiles-8x8-vga-512x384x1-glitch.spin.png

6.1.6 variable-initialisation.spin

con
  _clkmode = xtal1 + pll16x
  _clkfreq = 80_000_000

obj
  ser : "FullDuplexSerial.spin"

pub main | s
  ser.start(31, 30, 0, 115200)

  ser.dec(s)
  ser.str(string(13,10))

  waitcnt(_clkfreq + cnt)
  ser.stop
  cogstop(0)

Except for FlexSpin, the other tested compilers initialise the variable s to 0. This may have impact on existing code which assumes the behaviour of the other compilers.

6.1.6.1 BST/BSTC
bstc -Oa -b -L lib -o variable-initialisation.bstc variable-initialisation.spin
Brads Spin Tool Compiler v0.15.3 - Copyright 2008,2009 All rights reserved
Compiled for i386 Linux at 08:17:46 on 2009/07/20
Loading Object variable-initialisation
Loading Object FullDuplexSerial.spin
Program size is 640 longs
Compiled 184 Lines of Code in 0.009 Seconds

spinsim -b variable-initialisation.bstc.binary
0

6.1.6.2 FastSpin/FlexSpin
fastspin -O2 variable-initialisation.spin -o variable-initialisation.flexspin.binary -L lib
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
variable-initialisation.spin
|-FullDuplexSerial.spin
variable-initialisation.flexspin.pasm
Done.
Program size is 1952 bytes

spinsim -b variable-initialisation.flexspin.binary
-1593999360

6.1.6.3 HomeSpun
homespun variable-initialisation.spin -b -o variable-initialisation.homespun -L lib/
Homespun Spin Compiler 0.32p1 - Batang Build
parsing variable-initialisation.spin
parsing lib/FullDuplexSerial.spin
compiling variable-initialisation.spin
compiling FullDuplexSerial.spin
writing 760 bytes to variable-initialisation.homespun.binary

spinsim -b variable-initialisation.homespun.binary
0

6.1.6.4 OpenSpin
openspin -u variable-initialisation.spin -o variable-initialisation.openspin.binary -L lib
Propeller Spin/PASM Compiler 'OpenSpin' (c)2012-2018 Parallax Inc. DBA Parallax Semiconductor.
Version 1.00.81 Compiled on Oct 15 2019 02:25:19
Compiling...
variable-initialisation.spin
|-FullDuplexSerial.spin
Done.
Unused Method Elimination:
    4 methods removed
    0 objects removed
  116 bytes saved
--------------------------
Program size is 644 bytes
spinsim -b variable-initialisation.openspin.binary
0

6.2 FlexBASIC

6.2.1 The Mystery Of Array Initialising

See http://forums.parallax.com/discussion/comment/1457704/#Comment_1457704 and FlexBASIC documentation: global-member-and-local-variables(FlexBASIC).

File array-initialiser-1.bas:

dim as integer a(5) = { _
1, 2, 3, _
4, 5 _
}

print a(2)

Compile to array-initialiser-1.bas:

fastspin -O2 array-initialiser-1.bas -o array-initialiser-1.bas.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
array-initialiser-1.bas
array-initialiser-1.bas:4: error: initialization is not supported for member variable a

Retry:

File array-initialiser-2.bas:

dim shared as integer a(5) = { _
1, 2, 3, _
4, 5 _
}

print a(2)

Compile to array-initialiser-2.bas.binary:

fastspin -O2 array-initialiser-2.bas -o array-initialiser-2.bas.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 23 2019
array-initialiser-2.bas
fmt.c
strlen.c
array-initialiser-2.bas.pasm
Done.
Program size is 2800 bytes

Run it in spinsim:

spinsim -b array-initialiser-2.bas.binary
3

Eric explains this behaviour in https://forums.parallax.com/discussion/comment/1457711/#Comment_1457711:

The reason is a little obscure: an ordinary "dim" declares a member variable, which will be different in each instance of a class (even the top level program is really embedded in a class). These cannot be initialized because they're not in a fixed place in memory and there are many copies. "shared" variables though can be initialized because there is only one copy.

6.2.2 TODO closure.bas

FlexBASIC documentation: closures(FlexBASIC)

6.2.3 TODO compressed-lmm.bas

@@@TODO@@@ rename to compressed-lmm-1.

@@@TODO@@@ It works with 3.9.26, 3.9.27 but not with 3.9.28 to 3.9.30 and this needs investigation.

Starting with version 3.9.26 Spin2CPP/FastSpin supports compressed LMM code generation.

For now just a short reminder.

File compressed-lmm.bas:

_setbaud(33600)
print"Don't forget to switch to a slower baud rate when using compressed LMM."

Compile to compressed-lmm.bas.binary:

fastspin-3.9.27 -z -O2 compressed-lmm.bas -o compressed-lmm.bas.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 3.9.27 Compiled on: Sep  4 2019
compressed-lmm.bas
compressed-lmm.bas.pasm
Done.
Program size is 1916 bytes

Run it in spinsim:

spinsim -b33600 compressed-lmm.bas.binary
Don't forget to switch to a slower baud rate when using compressed LMM.

6.2.4 TODO compressed-lmm-2.bas

@@@TODO@@@ With 3.9.28 to 3.9.30 print fails but a simpler example still works.

_setbaud(9600)
var s$="This time the magic word is uvwwv!"
for i=1 to len(s$)
  _tx asc(mid$(s$,i,1))
next
waitcnt cnt+clkfreq

Compile to compressed-lmm-2.bas.binary:

fastspin -z -O2 compressed-lmm-2.bas -o compressed-lmm-2.bas.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 19 2019
compressed-lmm-2.bas
compressed-lmm-2.bas:6: error: Expected integer type for parameter of operator

Run it in spinsim:

spinsim -b9600 compressed-lmm-2.bas.binary
This time the magic word is uvwwv!

6.2.5 TODO cpu / rtc.bas

@@@TODO@@@ chisel cpu(...) examples and mention FlexGUI example: rtc.bas.

6.2.6 TODO nil.bas

FlexBASIC documentation: nil(FlexBASIC)

6.2.7 TODO option-explicit.bas

FlexBASIC documentation: option-explicit(FlexBASIC)

6.2.8 TODO option-implicit.bas

FlexBASIC documentation: option-implicit(FlexBASIC)

6.2.9 TODO pausems.bas

FlexBASIC documentation: pausems(FlexBASIC)

Note to $SELF: waitcnt cnt+clkfreq is soooooo 1980! ;-)
Note to $SELF: pausems can be used in SPIN and C too!

6.2.10 TODO TV examples

6.2.11 TODO strange.bas

This feels like being in an alternate reality… ;-)

File strange.bas:

dim as integer s$
s$ = 1330
print s$+7

Compile to strange.bas.binary:

fastspin strange.bas -o strange.bas.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 19 2019
strange.bas
fmt.c
strlen.c
strange.bas.pasm
Done.
Program size is 2804 bytes

Run it in spinsim:

spinsim -b strange.bas.binary
1337

6.3 FlexC

6.3.1 TODO classes.c

FlexC documentation: classes(FlexC)

6.3.2 TODO CLKFREQ

@@@TODO@@@ note to $SELF: use CLKFREQ from propeller.h

6.3.3 TODO hopper-vga-512x384x1.c

@@@TODO@@@

6.3.4 TODO monochrome-bytearray-vga-512x384x1.c

This example is addressing the VGA as two dimensional array of scanlines of unsigned bytes and shows piyel set and clear functions.

The choice of unsigned bytes as the underlying data type makes stamping 8 pixels wide character patterns into the VGA buffer easier.

@@@TODO@@@ show something with characters.

File monochrome-bytearray-vga-512x384x1.c:

#include <stdint.h>

struct __using("VGA_512x384_Bitmap.spin") vga;

uint8_t bitmap[vga.vp][vga.hp/8];
//             \_  _/  \__  __/
//               \/       \/
//        scanlines       (scanline pixels) / (bits of uint8_t)
//
uint16_t colors[vga.xtiles*vga.ytiles];
uint32_t sync;

void plot(int32_t x, int32_t y)         // use smaller (unsigned?) type?
{
  if(0<=x && x<vga.hp && 0<=y && y<vga.vp)
    bitmap[y][x>>3] |= 1<<(x&7);
}

void unplot(int32_t x, int32_t y)       // use smaller (unsigned?) type?
{
  if(0<=x && x<vga.hp && 0<=y && y<vga.vp)
    bitmap[y][x>>3] &= !(1<<(x&7));
}

void main(void)
{
  //
  //        lowest pin of VGA pingroup
  //        |
  //        V
  vga.start(16,colors,bitmap,sync);
  //
  // set same colorpair for all tiles
  //
  wordfill(colors,0b001100_00_010101_00,vga.xtiles*vga.ytiles);
  //                 green on grey

  for( int32_t x=0 ; x<vga.hp; x++ ) { plot(x,0); plot(x,vga.vp-1); }
  for( int32_t y=0 ; y<vga.vp; y++ ) { plot(0,y); plot(vga.hp-1,y); }

  // @@@TODO@@@ show/test unplot()
  // @@@TODO@@@ show/test manipulating tile colorpairs

  for(;;); // for(ever)
}

Compile to monochrome-bytearray-vga-512x384x1.c.binary:

fastspin -O2 monochrome-bytearray-vga-512x384x1.c -o monochrome-bytearray-vga-512x384x1.c.binary -L lib
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 19 2019
monochrome-bytearray-vga-512x384x1.c
|-VGA_512x384_Bitmap.spin
monochrome-bytearray-vga-512x384x1.c.pasm
Done.
Program size is 26488 bytes

Run it in gear:

monochrome-bytearray-vga-512x384x1.c.png

monochrome-bytearray-vga-512x384x1.c.png

6.3.5 TODO pseudorandom.c

6.4 General

6.4.1 TODO Truchet Tiles In All Languages

6.4.1.1 TODO On Bitmap-VGA-512x384x1

Different tile sizes show different bitmap organisations as bytes, words, …

6.4.1.2 TODO On Character Displays

Implementing the tiles as characters would save a lot of space (no full graphics bitmap) and gain a lot of speed.

6.4.2 TODO Generate Directories for Examples Using Org On The Fly

@@@TODO@@@ test putting examples in own directories.

@@@TODO@@@ find way to make these direcories as needed by org.

6.4.3 TODO Need Catchall Category Name

@@@TODO@@@ find name for examples fitting no other category.

7 Sick Bay

7.1 FlexSPIN

7.2 FlexBASIC

7.2.1 TODO integer only val()

7.2.2 DONE problem-division-uinteger.bas

Fixed by https://github.com/totalspectrum/spin2cpp/commit/811d1ff952ed38bebbc9fc7d071f9ef42d9ad4b3.

mod has a problem with uinteger.

File problem-division-uinteger.bas:

dim as uinteger ui

ui=0xffffffff
print ui,ui/2

Compile to problem-division-uinteger.bas.binary:

fastspin problem-division-uinteger.bas -o problem-division-uinteger.bas.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 19 2019
problem-division-uinteger.bas
fmt.c
strlen.c
problem-division-uinteger.bas.pasm
Done.
Program size is 2924 bytes

Run it in spinsim:

spinsim -b problem-division-uinteger.bas.binary
4294967295	2147483647

7.2.3 DONE problem-mod-uinteger.bas

Fixed by https://github.com/totalspectrum/spin2cpp/commit/811d1ff952ed38bebbc9fc7d071f9ef42d9ad4b3.

mod has a problem with uinteger.

File problem-mod-uinteger.bas:

dim as uinteger ui
dim as ushort us
dim as ubyte ub

ui = 1<<31
us = 1<<15
ub = 1<<7

print using "\      \ ########### ###########";"uinteger",ui,ui mod 10
print using "\      \ ########### ###########";"ushort",us,us mod 10
print using "\      \ ########### ###########";"ubyte",ub,ub mod 10

Compile to problem-mod-uinteger.bas.binary:

fastspin problem-mod-uinteger.bas -o problem-mod-uinteger.bas.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 19 2019
problem-mod-uinteger.bas
fmt.c
strlen.c
problem-mod-uinteger.bas.pasm
Done.
Program size is 3468 bytes

Run it in spinsim:

spinsim -b problem-mod-uinteger.bas.binary
uinteger  2147483648           8
ushort         32768           8
ubyte            128           8

7.2.4 DONE str$ and out of memory

7.2.5 DONE constants-of-objects-problem.bas

Solved by:

commit 7d815c514d1c53bd77b048c9ea5bb319c01e8bce Author: Eric Smith <ersmith@totalspectrum.ca> Date: Fri Sep 27 08:22:16 2019 -0300

fixed some cases of using method constants in const declarations

The included VGA object defines several constants I'd like to use to define derived constants.

File constants-of-objects-problem.bas:

dim vga as class using "VGA_512x384_Bitmap.spin"

const tiles = vga.xtiles*vga.ytiles

dim shared as ulong sync
dim shared as ubyte bitmap(vga.vp,vga.hp>>3)
dim shared as ushort colors(tiles)

vga.start(16, @colors, @bitmap, @sync) 

Compile to constants-of-objects-problem.bas.binary:

Up to v3.9.33:

fastspin-3.9.33 constants-of-objects-problem.bas -o constants-of-objects-problem.bas.binary -L lib
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 3.9.33 Compiled on: Sep 28 2019
constants-of-objects-problem.bas
|-VGA_512x384_Bitmap.spin
constants-of-objects-problem.bas:3: error: request for member xtiles in something not an object
constants-of-objects-problem.bas:3: error: request for member ytiles in something not an object
constants-of-objects-problem.bas:3: error: request for member xtiles in something not an object
constants-of-objects-problem.bas:3: error: request for member ytiles in something not an object

Fixed now:

fastspin constants-of-objects-problem.bas -o constants-of-objects-problem.bas.binary -L lib
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 19 2019
constants-of-objects-problem.bas
|-VGA_512x384_Bitmap.spin
constants-of-objects-problem.bas.pasm
Done.
Program size is 26700 bytes

7.3 FlexC

7.3.1 DONE Block Local Variables

SOLVED by https://github.com/totalspectrum/spin2cpp/commit/dda156962019d1bc38dc1f802bf13bd22f334283. \o/

#include <stdio.h>

void main( void ) {
  for( int s=0 ; s<8 ; s++ ) printf("%d ",s);
  for( int s=7 ; s>-1 ; s-- ) printf("%d ",s);
$ make -B bnmmn
cc     bnmmn.c   -o bnmmn
$ ./bnmmn 
0 1 2 3 4 5 6 7 7 6 5 4 3 2 1 0 
$ fastspin bnmmn.c 
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 3.9.32-beta-5ade57ef Compiled on: Sep 15 2019
bnmmn.c
/tmp/mc-yeti/bnmmn.c:5: error: duplicate definition for s

Shouldn't "int s" be forgotten after each "for"?

Fixed in 3.9.32-beta-dda15696:

$ fastspin bnmmn.c 
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 3.9.32-beta-dda15696 Compiled on: Sep 17 2019
bnmmn.c
fmt.c
strlen.c
bnmmn.pasm
Done.
Program size is 2812 bytes
$ spinsim -b bnmmn.binary 
0 1 2 3 4 5 6 7 7 6 5 4 3 2 1 0 

7.3.2 DONE stdio.h - printf

The CR/LF/CRLF question remains and currently printf seems to count CRLF as one char: https://github.com/totalspectrum/spin2cpp/commit/956d085f6c504d4d873c60b2e5138bb4c4616ea7#diff-58e63038daee6b5044ac9a77b2c525cfR101-R104

@@@TODO@@@ This touches 7.4.2 too.

#include <stdio.h>

void main(void)
{
  int i = printf("%s\n","Test.");
  printf("printf returned %d\n",i);
}

Compile to printftest.c.binary:

fastspin -O2 printftest.c -o printftest.c.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.0 Compiled on: Oct 19 2019
printftest.c
fmt.c
strlen.c
printftest.c.pasm
Done.
Program size is 2956 bytes

Run it in spinsim:

spinsim -b printftest.c.binary
Test.
printf returned 6

Unix does not need/want CR but if it is there, it should count. I prefer not to see a CR on Unix.

With gcc:

gcc printftest.c -o printftest && ./printftest
Test.
printf returned 6

7.3.3 TODO longlong.c

FlexC documentation: missing-features(FlexC)

File longlong.c:

#include <stdio.h>

void main(void) {
   long long a, a1, a2;

   printf("sizeof(long long) = %d\n", sizeof(a));

   a1 = 0xffffffff;
   a2 = 0x10101010;
   a  = a1 * a2;
}

Compile to longlong.c.binary:

fastspin -O2 longlong.c -o longlong.c.binary
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 3.9.34-beta-7d815c51 Compiled on: Sep 28 2019
longlong.c
fmt.c
strlen.c
/home/yeti/wrk/orgy/fastspin/longlong.c:8: error: Cannot handle expression yet
/home/yeti/wrk/orgy/fastspin/longlong.c:9: error: Cannot handle expression yet
/home/yeti/wrk/orgy/fastspin/longlong.c:10: error: Cannot handle expression yet

7.4 General

7.4.1 TODO forced echo of input

_rx in spin2cpp/sys/p1_code.spin echoes the input. This has to change!

7.4.2 TODO The CRLF question needs to be discussed!

LF is all *nixish OSes want and an extra CR sometimes can cause trouble.

8 Build FastSpin

git clone https://github.com/totalspectrum/spin2cpp.git
Cloning into 'spin2cpp'...

cd spin2cpp
make
rm -rf ./build/testlex ./build/spin2cpp ./build/fastspin ./build/* *.zip
mkdir -p ./build
bison -p spinyy -t -b ./build/spin -d frontends/spin/spin.y
bison -p basicyy -t -b ./build/basic -d frontends/basic/basic.y
bison -p cgramyy -t -b ./build/cgram -d frontends/c/cgram.y
gcc -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/lexer.o -c frontends/lexer.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/symbol.o -c symbol.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/ast.o -c ast.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/expr.o -c expr.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/dofmt.o -c util/dofmt.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/flexbuf.o -c util/flexbuf.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/lltoa_prec.o -c util/lltoa_prec.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/strupr.o -c util/strupr.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/strrev.o -c util/strrev.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/strdupcat.o -c util/strdupcat.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/to_utf8.o -c util/to_utf8.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/from_utf8.o -c util/from_utf8.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/preprocess.o -c preprocess.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/cppexpr.o -c backends/cpp/cppexpr.c
gcc -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/testlex testlex.c build/lexer.o build/symbol.o build/ast.o build/expr.o build/dofmt.o build/flexbuf.o build/lltoa_prec.o build/strupr.o build/strrev.o build/strdupcat.o build/to_utf8.o build/from_utf8.o build/preprocess.o build/cppexpr.o -lm
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/common.o -c frontends/common.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/case.o -c frontends/case.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/spinc.o -c spinc.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/functions.o -c functions.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/cse.o -c cse.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/loops.o -c loops.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/pasm.o -c pasm.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/outdat.o -c backends/dat/outdat.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/outlst.o -c backends/dat/outlst.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/spinlang.o -c frontends/spin/spinlang.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/basiclang.o -c frontends/basic/basiclang.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/clang.o -c frontends/c/clang.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/outasm.o -c backends/asm/outasm.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/assemble_ir.o -c backends/asm/assemble_ir.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/optimize_ir.o -c backends/asm/optimize_ir.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/inlineasm.o -c backends/asm/inlineasm.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/compress_ir.o -c backends/asm/compress_ir.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/outcpp.o -c backends/cpp/outcpp.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/cppfunc.o -c backends/cpp/cppfunc.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/outgas.o -c backends/cpp/outgas.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/directive.o -c mcpp/directive.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/expand.o -c mcpp/expand.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/mbchar.o -c mcpp/mbchar.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/mcpp_eval.o -c mcpp/mcpp_eval.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/mcpp_main.o -c mcpp/mcpp_main.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/mcpp_system.o -c mcpp/mcpp_system.c
gcc -MMD -MP -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/mcpp_support.o -c mcpp/mcpp_support.c
gcc -g -Wall -I. -I./build -DFLEXSPIN_BUILD -DGITREV=27cc259b -o build/version.o -c version.c
gcc -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/spin.tab.o -c build/spin.tab.c
gcc -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/basic.tab.o -c build/basic.tab.c
gcc -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/cgram.tab.o -c build/cgram.tab.c
gcc -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/spin2cpp spin2cpp.c build/common.o build/case.o build/spinc.o build/lexer.o build/symbol.o build/ast.o build/expr.o build/dofmt.o build/flexbuf.o build/lltoa_prec.o build/strupr.o build/strrev.o build/strdupcat.o build/to_utf8.o build/from_utf8.o build/preprocess.o build/cppexpr.o build/functions.o build/cse.o build/loops.o build/pasm.o build/outdat.o build/outlst.o build/spinlang.o build/basiclang.o build/clang.o build/outasm.o build/assemble_ir.o build/optimize_ir.o build/inlineasm.o build/compress_ir.o build/outcpp.o build/cppfunc.o build/outgas.o build/directive.o build/expand.o build/mbchar.o build/mcpp_eval.o build/mcpp_main.o build/mcpp_system.o build/mcpp_support.o build/version.o build/spin.tab.o build/basic.tab.o build/cgram.tab.o -lm
gcc -g -Wall -I. -I./build -DFLEXSPIN_BUILD -o build/fastspin fastspin.c build/common.o build/case.o build/spinc.o build/lexer.o build/symbol.o build/ast.o build/expr.o build/dofmt.o build/flexbuf.o build/lltoa_prec.o build/strupr.o build/strrev.o build/strdupcat.o build/to_utf8.o build/from_utf8.o build/preprocess.o build/cppexpr.o build/functions.o build/cse.o build/loops.o build/pasm.o build/outdat.o build/outlst.o build/spinlang.o build/basiclang.o build/clang.o build/outasm.o build/assemble_ir.o build/optimize_ir.o build/inlineasm.o build/compress_ir.o build/outcpp.o build/cppfunc.o build/outgas.o build/directive.o build/expand.o build/mbchar.o build/mcpp_eval.o build/mcpp_main.o build/mcpp_system.o build/mcpp_support.o build/version.o build/spin.tab.o build/basic.tab.o build/cgram.tab.o -lm
ls -l build/fastspin build/spin2cpp
-rwxr-xr-x 1 yeti yeti 1574808 Oct 25 21:08 build/fastspin
-rwxr-xr-x 1 yeti yeti 1574560 Oct 25 21:08 build/spin2cpp

build/fastspin
Propeller Spin/PASM Compiler 'FastSpin' (c) 2011-2019 Total Spectrum Software Inc.
Version 4.0.1 Compiled on: Oct 25 2019
usage: build/fastspin [options] filename.spin | filename.bas
  [ -h ]              display this help
  [ -L or -I <path> ] add a directory to the include path
  [ -o <name> ]      set output filename to <name>
  [ -b ]             output binary file format
  [ -e ]             output eeprom file format
  [ -c ]             output only DAT sections
  [ -l ]             output DAT as a listing file
  [ -f ]             output list of file names
  [ -q ]             quiet mode (suppress banner and non-error text)
  [ -p ]             disable the preprocessor
  [ -D <define> ]    add a define
  [ -u ]             ignore for openspin compatibility (unused method elimination always enabled)
  [ -2# ]             compile for Prop2
          -2a = original silicon
          -2b = rev B silicon
  [ -O# ]            set optimization level:
          -O0 = no optimization
          -O1 = basic optimization
          -O2 = all optimization
  [ -H nnnn ]        set starting hub address
  [ -E ]             skip initial coginit code (usually used with -H)
  [ -w ]             compile for COG with Spin wrappers
  [ -C ]             enable case sensitive mode
  [ -x ]             capture program exit code (for testing)
  [ -z ]             compress code
  [ --code=cog ]     compile for COG mode instead of LMM
  [ --fcache=N ]     set FCACHE size to N (0 to disable)
  [ --fixedreal ]    use 16.16 fixed point in place of floats
  [ --lmm=xxx ]      use alternate LMM implementation for P1
           xxx = orig uses original fastspin LMM
           xxx = slow uses traditional (slow) LMM
build/spin2cpp
Spin to C++ converter version 4.0.1
Usage: build/spin2cpp [options] file.spin
Options:
  --asm:     output (user readable) PASM code
  --binary:  create binary file for download
  --cogspin: create PASM based Spin object (translate Spin to PASM)
  --ccode:   output C code instead of C++
  --cse:     perform common subexpression optimizations on C code
  --cc=CC:   use CC as the C++ compiler instead of PropGCC
  --code=x : PASM output only: control placement of code
             x can be cog (default) or hub (for LMM)
  --ctypes : use inferred pointer (and other) types in generated C/C++ code
  --data=x : PASM output only: control placement of data
             x can be cog or hub (default is hub)
  --dat:     output binary blob of DAT section only
  --eeprom:  create EEPROM binary file for download
  --elf:     create executable ELF file with propgcc
  --files:   print list of .cpp files to stdout
  --fixed:   use 16.16 fixed point in place of float
  --fcache=N: set size of FCACHE area
  --gas:     create inline assembly out of DAT area;
             with --dat, create gas .S file from DAT area
  --list:    produce a listing file
  --main:    include C++ main() function
  --noheader: skip the normal comment about spin2cpp version
  --nocse:   disable common subexpression optimizations on PASM code
  --noopt:   turn off all optimization in PASM output
  --nopre:   do not run preprocessor on the .spin file
  --nofcache: disable FCACHE (same as --fcache=0)
  --normalize: normalize case of all identifiers
  --p2:       use Propeller 2 instructions (experimental)
  --require:  require a specific version (or later) of spin2cpp
  --side:     create a SimpleIDE file for the C/C++ outputs
  -Dname=val: define a preprocessor symbol
  -g:         add debug info to output (original source for PASM output)
  -I dir:     add dir to the object search path
  -L dir:     same as -I
  -o file:    place final output in file
  -y:         debug parser
  --version:  print version and exit
rm -rf spin2cpp

9 Library

9.1 MIT-License–80-Columns.txt

This will be automagically included into some other files…

File: lib/MIT-License–80-Columns.txt

┌──────────────────────────────────────────────────────────────────────────────┐
│                          TERMS OF USE:  MIT License                          │
├──────────────────────────────────────────────────────────────────────────────┤
│ Permission is hereby granted, free of charge, to any person obtaining a copy │
│ of this software and associated documentation files (the "Software"), to     │
│ deal in the Software without restriction, including without limitation the   │
│ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or  │
│ sell copies of the Software, and to permit persons to whom the Software is   │
│ furnished to do so, subject to the following conditions:                     │
│                                                                              │
│ The above copyright notice and this permission notice shall be included in   │
│ all copies or substantial portions of the Software.                          │
│                                                                              │
│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR   │
│ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,     │
│ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE  │
│ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER       │
│ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      │
│ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS │
│ IN THE SOFTWARE.                                                             │
└──────────────────────────────────────────────────────────────────────────────┘

9.2 FullDuplexSerial.spin

@@@TODO@@@ 80-column-ify

File: lib/FullDuplexSerial.spin

{{
Object file:    FullDuplexSerial.spin
Version:        1.2.1
Date:           2006 - 2011
Author:         Chip Gracey, Jeff Martin, Daniel Harris
Company:        Parallax Semiconductor
Email:          dharris@parallaxsemiconductor.com
Licensing:      MIT License - see end of file for terms of use.

Description:
This driver, once started, implements a serial port in one cog.

Revision History:
v1.2.1y1 - switched to 80 columns wide MIT license. 20191018/yeti
v1.2.1 - 5/1/2011 Added extra comments and demonstration code to bring up
		   to gold standard.
v1.2 - 5/7/2009 Fixed bug in dec method causing largest negative value
		(-2,147,483,648) to be output as -0.
v1.1 - 3/1/2006 First official release.


=============================================
	Connection Diagram
=============================================

	┌─────────┐   
	│         │         
	│    rxPin├─── TTL level RX line
	│    txPin├─── TTL level TX line
	│         │   
	└─────────┘           
	 Propeller
	    MCU
	  (P8X32A)

Components:
N/A

=============================================                  
}}


VAR

  'Global variable declarations

  long  cog           'cog flag/id

  '9 longs, MUST be contiguous
  long  rx_head                 
  long  rx_tail
  long  tx_head
  long  tx_tail
  long  rx_pin
  long  tx_pin
  long  rxtx_mode
  long  bit_ticks
  long  buffer_ptr

  byte  rx_buffer[16]           'transmit and receive buffers
  byte  tx_buffer[16]           '16 bytes each


PUB Start(rxPin, txPin, mode, baudrate) : okay
{{
   Start serial driver - starts a cog


   Parameters: rxPin    = Propeller pin to set up as RX-ing pin.  Range = 0 - 31
	       txPin    = Propeller pin to set up as TX-ing pin.  Range = 0 - 31
	       mode     = bitwise mode configuration variable, see mode bit description below.
	       baudrate = baud rate to transmit bits at.

   mode bit 0 = invert rx
   mode bit 1 = invert tx
   mode bit 2 = open-drain/source tx
   mode bit 3 = ignore tx echo on rx

   return: Numeric value of the cog(1-8) that was started, false(0) if no cog is available.

   example usage: serial.start(31, 30, %0000, 9_600)

   expected outcome of example usage call: Starts a serial port on Propller pins 30 and 31.
					   The serial port does not invert the RX and TX data,
					   no open-drain/source on the TX pin, does not ignore
					   data echoed on RX pin, at 9,600 baud.
}}

  Stop                                                  'make sure the driver isnt already running
  longfill(@rx_head, 0, 4)                              'zero out the buffer pointers
  longmove(@rx_pin, @rxpin, 3)                          'copy the start parameters to this objects pin variables
  bit_ticks := clkfreq / baudrate                       'number of clock ticks per bit for the desired baudrate
  buffer_ptr := @rx_buffer                              'save the address of the receive buffer
  okay := cog := cognew(@entry, @rx_head) + 1           'start the new cog now, assembly cog at "entry" label.


PUB Stop
{{
   Stop serial driver if it has already been started - frees the cog

   Parameters: none
   return:     none

   example usage: serial.stop

   expected outcome of example usage call: Stops an already started serial port.
}}

  if cog
    cogstop(cog~ - 1)                                   'if the driver is already running, stop the cog
  longfill(@rx_head, 0, 9)                              'zero out configuration variables


PUB RxFlush
{{
   Continuously pops the head of the receive buffer until no bytes remain.

   Parameters: none
   return:     none

   example usage: serial.RxFlush

   expected outcome of example usage call: Receive bffer will be cleared.
}}

  repeat while RxCheck => 0                             'Call RxCheck until buffer is empty


PUB RxCheck : rxByte
{{
   Check if a byte is waiting in the receive buffer and return the byte if one is there,
   does NOT block (never waits).

   Parameters: none
   return:     If no byte, then return(-1).  If byte, then return(byte).

   example usage: serial.RxCheck

   expected outcome of example usage call: Return a byte if one is available, but dont wait
					   for a byte to come in.
}}


  rxByte--                                              'make rxbyte = -1
  if rx_tail <> rx_head                                 'if a byte is in the buffer, then
    rxByte := rx_buffer[rx_tail]                        '  grab it and store in rxByte
    rx_tail := (rx_tail + 1) & $F                       '  advance the buffer pointer


PUB RxTime(ms) : rxByte | t
{{
   Wait ms milliseconds for a byte to be received 

   Parameters: ms = number of milliseconds to wait for a byte to be received.
   return:     If no byte, then return(-1).  If byte, then return(byte).

   example usage: serial.RxTime(500)

   expected outcome of example usage call: Wait half a second (500 ms) for a byte to be received.
}}

  t := cnt                                              'take note of the current time
  repeat until (rxByte := RxCheck) => 0 or (cnt - t) / (clkfreq / 1000) > ms


PUB Rx : rxByte
{{
   Receive byte (may wait for byte)
   returns $00..$FF

   Parameters: none
   return:     received byte

   example usage: serial.Rx

   expected outcome of example usage call: Wait until a byte has been received, then return that byte.
}}

  repeat while (rxByte := RxCheck) < 0                  'return the byte, wait while the buffer is empty


PUB Tx(txByte)
{{
   Places a byte into the transmit buffer for transmission (may wait for room in buffer).

   Parameters: txByte = the byte to be transmitted
   return:     none

   example usage: serial.Tx($0D)

   expected outcome of example usage call: Transmits the byte $0D serially on the txPin
}}

  repeat until (tx_tail <> (tx_head + 1) & $F)          'wait until the buffer has room                        
  tx_buffer[tx_head] := txByte                          'place the byte into the buffer
  tx_head := (tx_head + 1) & $F                         'advance the buffer's pointer

  if rxtx_mode & %1000                                  'if ignoring rx echo
    Rx                                                  '   receive the echoed byte and discard


PUB Str(stringPtr)
{{
   Transmit a string of bytes

   Parameters: stringPtr = the pointer address of the null-terminated string to be sent
   return:     none

   example usage: serial.Str(@test_string)

   expected outcome of example usage call: Transmits each byte of a string at the address some_string.
}}

  repeat strsize(stringPtr)
    Tx(byte[stringPtr++])                                                       'Transmit each byte in the string


PUB Dec(value) | i, x
{{
   Transmit the ASCII string equivalent of a decimal value

   Parameters: dec = the numeric value to be transmitted
   return:     none

   example usage: serial.Dec(-1_234_567_890)

   expected outcome of example usage call: Will print the string "-1234567890" to a listening terminal.
}}

  x := value == NEGX                                    'Check for max negative
  if value < 0
    value := ||(value+x)                                'If negative, make positive; adjust for max negative
    Tx("-")                                             'and output sign

  i := 1_000_000_000                                    'Initialize divisor

  repeat 10                                             'Loop for 10 digits
    if value => i                                                               
      Tx(value / i + "0" + x*(i == 1))                  'If non-zero digit, output digit; adjust for max negative
      value //= i                                       'and digit from value
      result~~                                          'flag non-zero found
    elseif result or i == 1
      Tx("0")                                           'If zero digit (or only digit) output it
    i /= 10                                             'Update divisor


PUB Hex(value, digits)
{{
   Transmit the ASCII string equivalent of a hexadecimal number

   Parameters: value = the numeric hex value to be transmitted
	       digits = the number of hex digits to print                 
   return:     none

   example usage: serial.Hex($AA_FF_43_21, 8)

   expected outcome of example usage call: Will print the string "AAFF4321" to a listening terminal.
}}

  value <<= (8 - digits) << 2
  repeat digits                                         'do it for the number of hex digits being transmitted
    Tx(lookupz((value <-= 4) & $F : "0".."9", "A".."F"))'  Transmit the ASCII value of the hex characters


PUB Bin(value, digits)
{{
   Transmit the ASCII string equivalent of a binary number

   Parameters: value = the numeric binary value to be transmitted
	       digits = the number of binary digits to print                 
   return:     none

   example usage: serial.Bin(%1110_0011_0000_1100_1111_1010_0101_1111, 32)

   expected outcome of example usage call: Will print the string "11100011000011001111101001011111" to a listening terminal.
}}

  value <<= 32 - digits
  repeat digits
    Tx((value <-= 1) & 1 + "0")                         'Transmit the ASCII value of each binary digit


DAT

'***********************************
'* Assembly language serial driver *
'***********************************

			org
'
'
' Entry
'
entry                   mov     t1,par                'get structure address
			add     t1,#4 << 2            'skip past heads and tails

			rdlong  t2,t1                 'get rx_pin
			mov     rxmask,#1
			shl     rxmask,t2

			add     t1,#4                 'get tx_pin
			rdlong  t2,t1
			mov     txmask,#1
			shl     txmask,t2

			add     t1,#4                 'get rxtx_mode
			rdlong  rxtxmode,t1

			add     t1,#4                 'get bit_ticks
			rdlong  bitticks,t1

			add     t1,#4                 'get buffer_ptr
			rdlong  rxbuff,t1
			mov     txbuff,rxbuff
			add     txbuff,#16

			test    rxtxmode,#%100  wz    'init tx pin according to mode
			test    rxtxmode,#%010  wc
	if_z_ne_c       or      outa,txmask
	if_z            or      dira,txmask

			mov     txcode,#transmit      'initialize ping-pong multitasking
'
'
' Receive
'
receive                 jmpret  rxcode,txcode         'run a chunk of transmit code, then return

			test    rxtxmode,#%001  wz    'wait for start bit on rx pin
			test    rxmask,ina      wc
	if_z_eq_c       jmp     #receive

			mov     rxbits,#9             'ready to receive byte
			mov     rxcnt,bitticks
			shr     rxcnt,#1
			add     rxcnt,cnt                          

:bit                    add     rxcnt,bitticks        'ready next bit period

:wait                   jmpret  rxcode,txcode         'run a chuck of transmit code, then return

			mov     t1,rxcnt              'check if bit receive period done
			sub     t1,cnt
			cmps    t1,#0           wc
	if_nc           jmp     #:wait

			test    rxmask,ina      wc    'receive bit on rx pin
			rcr     rxdata,#1
			djnz    rxbits,#:bit

			shr     rxdata,#32-9          'justify and trim received byte
			and     rxdata,#$FF
			test    rxtxmode,#%001  wz    'if rx inverted, invert byte
	if_nz           xor     rxdata,#$FF

			rdlong  t2,par                'save received byte and inc head
			add     t2,rxbuff
			wrbyte  rxdata,t2
			sub     t2,rxbuff
			add     t2,#1
			and     t2,#$0F
			wrlong  t2,par

			jmp     #receive              'byte done, receive next byte
'
'
' Transmit
'
transmit                jmpret  txcode,rxcode         'run a chunk of receive code, then return

			mov     t1,par                'check for head <> tail
			add     t1,#2 << 2
			rdlong  t2,t1
			add     t1,#1 << 2
			rdlong  t3,t1
			cmp     t2,t3           wz
	if_z            jmp     #transmit

			add     t3,txbuff             'get byte and inc tail
			rdbyte  txdata,t3
			sub     t3,txbuff
			add     t3,#1
			and     t3,#$0F
			wrlong  t3,t1

			or      txdata,#$100          'ready byte to transmit
			shl     txdata,#2
			or      txdata,#1
			mov     txbits,#11
			mov     txcnt,cnt

:bit                    test    rxtxmode,#%100  wz    'output bit on tx pin according to mode
			test    rxtxmode,#%010  wc
	if_z_and_c      xor     txdata,#1
			shr     txdata,#1       wc
	if_z            muxc    outa,txmask        
	if_nz           muxnc   dira,txmask
			add     txcnt,bitticks        'ready next cnt

:wait                   jmpret  txcode,rxcode         'run a chunk of receive code, then return

			mov     t1,txcnt              'check if bit transmit period done
			sub     t1,cnt
			cmps    t1,#0           wc
	if_nc           jmp     #:wait

			djnz    txbits,#:bit          'another bit to transmit?

			jmp     #transmit             'byte done, transmit next byte
'
'
' Uninitialized data
'
t1                      res     1
t2                      res     1
t3                      res     1

rxtxmode                res     1
bitticks                res     1

rxmask                  res     1
rxbuff                  res     1
rxdata                  res     1
rxbits                  res     1
rxcnt                   res     1
rxcode                  res     1

txmask                  res     1
txbuff                  res     1
txdata                  res     1
txbits                  res     1
txcnt                   res     1
txcode                  res     1


DAT
{{
┌──────────────────────────────────────────────────────────────────────────────┐
│                          TERMS OF USE:  MIT License                          │
├──────────────────────────────────────────────────────────────────────────────┤
│ Permission is hereby granted, free of charge, to any person obtaining a copy │
│ of this software and associated documentation files (the "Software"), to     │
│ deal in the Software without restriction, including without limitation the   │
│ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or  │
│ sell copies of the Software, and to permit persons to whom the Software is   │
│ furnished to do so, subject to the following conditions:                     │
│                                                                              │
│ The above copyright notice and this permission notice shall be included in   │
│ all copies or substantial portions of the Software.                          │
│                                                                              │
│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR   │
│ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,     │
│ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE  │
│ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER       │
│ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      │
│ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS │
│ IN THE SOFTWARE.                                                             │
└──────────────────────────────────────────────────────────────────────────────┘
}}

9.3 VGA_512x384_Bitmap.spin

File: lib/VGA_512x384_Bitmap.spin

''******************************************************************************
''*  VGA 512x384 2-Color Bitmap Driver v1.0  *  Reformatted for 80 chars per   *
''*  Author: Chip Gracey                     *  line. no functional changes.   *
''*  Copyright (c) 2006 Parallax, Inc.       *                                 *
''*  See end of file for terms of use.       *                2019-10-03/yeti  *
''******************************************************************************
''
'' This object generates a 512x384 pixel bitmap, signaled as 1024x768 VGA.
'' Each pixel is one bit, so the entire bitmap requires 512 x 384 / 32 longs,
'' or 6,144 longs (24KB). Color words comprised of two byte fields provide
'' unique colors for every 32x32 pixel group. These color words require 512/32
'' * 384/32 words, or 192 words. Pixel memory and color memory are arranged
'' left-to-right then top-to-bottom.
''
'' A sync indicator signals each time the screen is drawn (you may ignore).
''
'' You must provide buffers for the colors, pixels, and sync. Once started,
'' all interfacing is done via memory. To this object, all buffers are read-
'' only, with the exception of the sync indicator which gets written with a
'' non-0 value. You may freely write all buffers to affect screen appearance.
''

CON

' 512x384 settings - signals as 1024 x 768 @ 67Hz

  hp = 512      'horizontal pixels
  vp = 384      'vertical pixels
  hf = 8        'horizontal front porch pixels
  hs = 48       'horizontal sync pixels
  hb = 88       'horizontal back porch pixels
  vf = 1        'vertical front porch lines
  vs = 3        'vertical sync lines
  vb = 28       'vertical back porch lines
  hn = 1        'horizontal normal sync state (0|1)
  vn = 1        'vertical normal sync state (0|1)
  pr = 35       'pixel rate in MHz at 80MHz system clock (5MHz granularity)

' Tiles

  xtiles = hp / 32
  ytiles = vp / 32

' H/V inactive states

  hv_inactive = (hn << 1 + vn) * $0101


VAR long cog

PUB start(BasePin, ColorPtr, PixelPtr, SyncPtr) : okay | i, j

'' Start VGA driver - starts a COG
'' returns false if no COG available
''
''     BasePin = VGA starting pin (0, 8, 16, 24, etc.)
''
''    ColorPtr = Pointer to 192 words which define the "0" and "1" colors for
''               each 32x32 pixel group. The lower byte of each word contains
''               the "0" bit RGB data while the upper byte of each word contains
''               the "1" bit RGB data for the associated group. The RGB
''               data in each byte is arranged as %RRGGBB00 (4 levels each).
''
''               color word example: %%0020_3300 = "0" = gold, "1" = blue
''
''    PixelPtr = Pointer to 6,144 longs containing pixels that make up the 512 x
''               384 pixel bitmap. Longs' LSBs appear left on the screen, while
''               MSBs appear right. The longs are arranged in sequence from
''               left-to-right, then top-to-bottom.
''
''     SyncPtr = Pointer to long which gets written with non-0 upon each screen
''               refresh. May be used to time writes/scrolls, so that chopiness
''               can be avoided. You must clear it each time if you want to see
''               it re-trigger.

  'if driver is already running, stop it
  stop

  'implant pin settings and pointers, then launch COG
  reg_vcfg := $200000FF + (BasePin & %111000) << 6
  i := $FF << (BasePin & %011000)
  j := BasePin & %100000 == 0
  reg_dira := i & j
  reg_dirb := i & !j
  longmove(@color_base, @ColorPtr, 2)
  if (cog := cognew(@init, SyncPtr) + 1)
    return true


PUB stop | i

'' Stop VGA driver - frees a COG

  if cog
    cogstop(cog~ - 1)


DAT

'*******************************************************************************
'* Assembly language VGA 2-color bitmap driver                                 *
'*******************************************************************************

	    org                           'set origin to $000 for start of
					  'program
' Initialization code - init I/O

init        mov     dira,reg_dira         'set pin directions
	    mov     dirb,reg_dirb

	    movi    ctra,#%00001_101      'enable PLL in ctra (VCO runs at 4x)
	    movi    frqa,#(pr / 5) << 3   'set pixel rate

	    mov     vcfg,reg_vcfg         'set video configuration

' Main loop, display field and do invisible sync lines

field       mov     color_ptr,color_base  'reset color pointer
	    mov     pixel_ptr,pixel_base  'reset pixel pointer
	    mov     y,#ytiles             'set y tiles
:ytile      mov     yl,#32                'set y lines per tile
:yline      mov     yx,#2                 'set y expansion
:yexpand    mov     x,#xtiles             'set x tiles
	    mov     vscl,vscl_pixel       'set pixel vscl

:xtile      rdword  color,color_ptr       'get color word
	    and     color,colormask       'clear h/v bits
	    or      color,hv              'set h/v inactive states
	    rdlong  pixel,pixel_ptr       'get pixel long
	    waitvid color,pixel           'pass colors and pixels to video
	    add     color_ptr,#2          'point to next color word
	    add     pixel_ptr,#4          'point to next pixel long
	    djnz    x,#:xtile             'another x tile?

	    sub     color_ptr,#xtiles * 2 'repoint to first colors in same line
	    sub     pixel_ptr,#xtiles * 4 'repoint to first pixels in same line

	    mov     x,#1                  'do horizontal sync
	    call    #hsync

	    djnz    yx,#:yexpand          'y expand?

	    add     pixel_ptr,#xtiles * 4 'point to first pixels in next line
	    djnz    yl,#:yline            'another y line in same tile?

	    add     color_ptr,#xtiles * 2 'point to first colors in next tile 
	    djnz    y,#:ytile             'another y tile?


	    wrlong   colormask,par        'visible done, write non-0 to sync

	    mov     x,#vf                 'do vertical front porch lines
	    call    #blank
	    mov     x,#vs                 'do vertical sync lines
	    call    #vsync
	    mov     x,#vb                 'do vertical back porch lines
	    call    #vsync

	    jmp     #field                'field done, loop


' Subroutine - do blank lines

vsync       xor     hvsync,#$101          'flip vertical sync bits

blank       mov     vscl,hvis             'do blank pixels
	    waitvid hvsync,#0
hsync       mov     vscl,#hf              'do horizontal front porch pixels
	    waitvid hvsync,#0
	    mov     vscl,#hs              'do horizontal sync pixels
	    waitvid hvsync,#1
	    mov     vscl,#hb              'do horizontal back porch pixels
	    waitvid hvsync,#0
	    djnz    x,#blank              'another line?
hsync_ret
blank_ret
vsync_ret   ret


' Data

reg_dira    long    0                     'set at runtime
reg_dirb    long    0                     'set at runtime
reg_vcfg    long    0                     'set at runtime

color_base  long    0                     'set at runtime (2 contiguous longs)
pixel_base  long    0                     'set at runtime

vscl_pixel  long    1 << 12 + 32          '1 pixel per clock and 32 pixels per
					  'set
colormask   long    $FCFC                 'mask to isolate R,G,B bits from H,V
hvis        long    hp                    'visible pixels per scan line
hv          long    hv_inactive           '-H,-V states
hvsync      long    hv_inactive ^ $200    '+/-H,-V states


' Uninitialized data

color_ptr   res     1
pixel_ptr   res     1
color       res     1
pixel       res     1
x           res     1
y           res     1
yl          res     1
yx          res     1

{{
┌──────────────────────────────────────────────────────────────────────────────┐
│                          TERMS OF USE:  MIT License                          │
├──────────────────────────────────────────────────────────────────────────────┤
│ Permission is hereby granted, free of charge, to any person obtaining a copy │
│ of this software and associated documentation files (the "Software"), to     │
│ deal in the Software without restriction, including without limitation the   │
│ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or  │
│ sell copies of the Software, and to permit persons to whom the Software is   │
│ furnished to do so, subject to the following conditions:                     │
│                                                                              │
│ The above copyright notice and this permission notice shall be included in   │
│ all copies or substantial portions of the Software.                          │
│                                                                              │
│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR   │
│ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,     │
│ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE  │
│ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER       │
│ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      │
│ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS │
│ IN THE SOFTWARE.                                                             │
└──────────────────────────────────────────────────────────────────────────────┘
}}

9.4 VGA64_BMPEngine.spin

File: lib/VGA64_BMPEngine.spin

{{
////////////////////////////////////////////////////////////////////////////////
// VGA64 Bitmap Engine
//
// Author: Kwabena W. Agyeman
// Updated: 7/15/2010
// Designed For: P8X32A
// Version: 1.1
//
// Copyright (c) 2010 Kwabena W. Agyeman
// See end of file for terms of use.
//
// Update History:
//
// v1.0 - Original release - 9/28/2009.
// v1.1 - Merged and rewrote code and added more features - 7/15/2010.
// v1.1y - reformatted for 80 CpL. no functional changes - 2019-10-03/yeti
//
// For each included copy of this object only one spin interpreter should access
// it at a time.
//
// Nyamekye,
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Video Circuit:
//
//     0   1   2   3 Pin Group
//
//                     240OHM
// Pin 0,  8, 16, 24 ----R-------- Vertical Sync
//
//                     240OHM
// Pin 1,  9, 17, 25 ----R-------- Horizontal Sync
//
//                     470OHM
// Pin 2, 10, 18, 26 ----R-------- Blue Video
//                            |
//                     240OHM |
// Pin 3, 11, 19, 27 ----R-----
//
//                     470OHM
// Pin 4, 12, 20, 28 ----R-------- Green Video
//                            |
//                     240OHM |
// Pin 5, 13, 21, 29 ----R-----
//
//                     470OHM
// Pin 6, 14, 22, 30 ----R-------- Red Video
//                            |
//                     240OHM |
// Pin 7, 15, 23, 31 ----R-----
//
//                            5V
//                            |
//                            --- 5V
//
//                            --- Vertical Sync Ground
//                            |
//                           GND
//
//                            --- Hoirzontal Sync Ground
//                            |
//                           GND
//
//                            --- Blue Return
//                            |
//                           GND
//
//                            --- Green Return
//                            |
//                           GND
//
//                            --- Red Return
//                            |
//                           GND
////////////////////////////////////////////////////////////////////////////////
}}

CON

  #$FC, Light_Grey, #$A8, Grey, #$54, Dark_Grey
  #$C0, Light_Red, #$80, Red, #$40, Dark_Red
  #$30, Light_Green, #$20, Green, #$10, Dark_Green
  #$0C, Light_Blue, #$08, Blue, #$04, Dark_Blue
  #$F0, Light_Orange, #$A0, Orange, #$50, Dark_Orange
  #$CC, Light_Purple, #$88, Purple, #$44, Dark_Purple
  #$3C, Light_Teal, #$28, Teal, #$14, Dark_Teal
  #$FF, White, #$00, Black

PUB plotCharacter(characterValue, xPixel, yPixel, displayBase) '' 7 Stack Longs

'' /////////////////////////////////////////////////////////////////////////////
'' // Plots a 16x32 pixel character on screen.
'' //
'' // CharacterValue - The ASCII character to plot on screen from the internal
'' //                  character ROM. BG = %%0. FG = %%1
'' // XPixel - The X cartesian pixel coordinate, will be forced to be multiple
'' //          of 16. Y will be forced to be a multiple of 32.
'' // YPixel - The Y cartesian pixel coordinate. Note that this axis is inverted
'' //          like on all other graphics drivers.
'' // DisplayBase - The address of the display buffer to draw to.
'' /////////////////////////////////////////////////////////////////////////////

  displayBase += ( ((((xPixel <# (horizontalPixels - 1)) #> 0) >> 4) <<        {
		 } (bitsPerPixel + 1)) + (((((yPixel <# (verticalPixels - 1))  {
		 } #> 0) >> 5) * horizontalLongs) << 7) )

  characterValue := (characterValue // 256)
  xPixel := (characterValue & 1)
  characterValue := (((characterValue >> 1) << 7) + $80_00)

  repeat result from 0 to 31
    yPixel := (long[characterValue][result] >> xPixel)

    ifnot(bitsPerPixel)
      yPixel := (yPixel & $11_11_11_11) | ((yPixel & $44_44_44_44) >> 1)
      yPixel := (yPixel & $03_03_03_03) | ((yPixel & $30_30_30_30) >> 2)
      yPixel := (yPixel & $00_0F_00_0F) | ((yPixel & $0F_00_0F_00) >> 4)
      word[displayBase] := (yPixel & $00_00_00_FF) | ((yPixel & $00_FF_00_00)  {
			   } >> 8)
    else
      long[displayBase] := (yPixel & $55_55_55_55)

    displayBase += (horizontalLongs << 2)
    if(displayBase => (((horizontalLongs * verticalPixels) << 2)               {
		      } + screenPointer))
      quit

PUB plotPixel(pixelValue, xPixel, yPixel, displayBase) '' 7 Stack Longs

'' /////////////////////////////////////////////////////////////////////////////
'' // Plots a 1x1 pixel on screen.
'' //
'' // PixelValue - The pixel to plot on screen. Between %%0 and %%1 or between
'' //              %%0, %%1, %%2, and %%3 depending on color mode.
'' // XPixel - The X cartesian pixel coordinate, will be forced to be multiple
'' //          of 1. Y will be forced to be a multiple of 1.
'' // YPixel - The Y cartesian pixel coordinate. Note that this axis is inverted
'' //          like on all other graphics drivers.
'' // DisplayBase - The address of the display buffer to draw to.
'' /////////////////////////////////////////////////////////////////////////////

  xPixel := ((xPixel <# (horizontalPixels - 1)) #> 0)
  displayBase += (((horizontalLongs * ((yPixel <# (verticalPixels - 1)) #> 0)) {
		 } + (xPixel >> (5 - bitsPerPixel))) << 2)

  xPixel := ((xPixel & ($1F >> bitsPerPixel)) << bitsPerPixel)
  yPixel := (!((1 + (bitsPerPixel << 1)) << xPixel))

  long[displayBase] := ((long[displayBase] & yPixel) | (((pixelValue <# (1     {
		       } + (bitsPerPixel << 1))) #> 0) << xPixel))

PUB displayState(state) '' 4 Stack Longs

'' /////////////////////////////////////////////////////////////////////////////
'' // Enables or disables the BMP Driver's video output - turning the monitor
'' // off or putting it into standby mode.
'' //
'' // State - True for active and false for inactive.
'' /////////////////////////////////////////////////////////////////////////////

  displayIndicator := state

PUB displayRate(rate) '' 4 Stack Longs

'' /////////////////////////////////////////////////////////////////////////////
'' // Returns true or false depending on the time elasped according to a
'' // specified rate.
'' //
'' // Rate - A display rate to return at. 0=0.234375Hz, 1=0.46875Hz, 2=0.9375Hz,
'' // 3=1.875Hz, 4=3.75Hz, 5=7.5Hz, 6=15Hz, 7=30Hz.
'' /////////////////////////////////////////////////////////////////////////////

  result or= (($80 >> ((rate <# 7) #> 0)) & syncIndicator)

PUB displayWait(frames) '' 4 Stack Longs

'' /////////////////////////////////////////////////////////////////////////////
'' // Waits for the display vertical refresh.
'' //
'' // The best time to draw on screen for flicker free operation is right after
'' // this function returns.
'' //
'' // Frames - Number of vertical refresh frames to wait for.
'' /////////////////////////////////////////////////////////////////////////////

  repeat (frames #> 0)
    result := syncIndicator
    repeat until(result <> syncIndicator)

PUB displayPointer(newDisplayPointer) '' 4 Stack Longs

'' /////////////////////////////////////////////////////////////////////////////
'' // Changes the display pointer for the whole screen.
'' //
'' // In 1 bit per pixel mode each pixel can have a value of 0 or 1 which map to
'' // the 0 and 1 colors for the whole screen.
'' // In 2 bits per pixel mode each pixel can have a value of 0 to 3 which map
'' // to the 0-3 colors for the whole screen.
'' //
'' // In 1 bit per pixel mode the display buffer must be of size
'' // ((horizontalPixels * verticalPixels) / 32) in longs.
'' // In 2 bits per pixel mode the display buffer must be of size
'' // ((horizontalPixels * verticalPixels) / 16) in longs.
'' //
'' // In 1 bit per pixel mode each long holds 32 pixels.
'' // In 2 bits per pixel mode each long holds 16 pixels.
'' //
'' // The LSB/LBSs of every long is/are the left most pixel while the MSB/MSBs
'' // of every long is/are the right most pixel.
'' //
'' // NewDisplayPointer - The address of the new display buffer to be displayed
'' // after the vertical refresh.
'' /////////////////////////////////////////////////////////////////////////////

  screenPointer := newDisplayPointer

PUB displayColor(pixelNumber, newColor) '' 5 Stack Longs

'' /////////////////////////////////////////////////////////////////////////////
'' // Changes a pixel color for the whole screen.
'' //
'' // PixelNumber - The pixel number to change for the whole screen. Between 0
'' //               and 1 or 0 to 3.
'' // NewColor - A color byte (%RR_GG_BB_xx) describing the pixel's new color
'' //            for the whole screen.
'' /////////////////////////////////////////////////////////////////////////////

  pixelColors.byte[(pixelNumber <# (1 + (bitsPerPixel << 1))) #> 0] := newColor

PUB displayClear(patternValue, displayBase) '' 5 Stack Longs

'' /////////////////////////////////////////////////////////////////////////////
'' // Clears the whole screen.
'' //
'' // PatternValue - The pattern to plot on screen.
'' // DisplayBase - The address of the display buffer to draw to.
'' /////////////////////////////////////////////////////////////////////////////

  longfill(displayBase, patternValue, (horizontalLongs * verticalPixels))

PUB BMPEngineStart(pinGroup, colorMode, horizontalResolution,                  {
		  } verticalResolution, newDisplayPointer) '' 11 Stack Longs

'' /////////////////////////////////////////////////////////////////////////////
'' // Starts up the BMP driver running on a cog.
'' //
'' // Returns true on success and false on failure.
'' //
'' // PinGroup - Pin group to use to drive the video circuit. Between 0 and 3.
'' // ColorMode - Color mode to use for the whole screen. Between 1 bit per
'' //             pixel or 2 bits per pixel.
'' // HorizontalResolution - The driver will force this value to be a factor of
'' //                        640 and divisible by 16 or 32. 16/32 to 640.
'' // VerticalResolution - The driver will force this value to be a factor of
'' //                      480. 1 to 480.
'' // NewDisplayPointer - The address of the new display buffer to be displayed
'' //                     after the vertical refresh.
'' /////////////////////////////////////////////////////////////////////////////

  BMPEngineStop
  if(chipver == 1)

    pinGroup := ((pinGroup <# 3) #> 0)
    bitsPerPixel := ((colorMode <# 2) #> 1)

    directionState := ($FF << (8 * pinGroup))
    videoState := ($20_00_00_FF | (pinGroup << 9) | ((--bitsPerPixel) << 28))

    pinGroup := constant((25_175_000 + 1_600) / 4)
    frequencyState := 1

    repeat 32
      pinGroup <<= 1
      frequencyState <-= 1
      if(pinGroup => clkfreq)
	pinGroup -= clkfreq
	frequencyState += 1

    horizontalResolution := ((horizontalResolution <# 640) #>                  {
			    } (32 >> bitsPerPixel))
    repeat while((640 // horizontalResolution) or ((horizontalResolution--)    {
		 } // (32 >> bitsPerPixel)))
    horizontalScaling := (640 / (++horizontalResolution))

    verticalResolution := ((verticalResolution <# 480) #> 1)
    repeat while(480 // verticalResolution--)
    verticalScaling := (480 / (++verticalResolution))

    horizontalPixels := (640 / horizontalScaling)
    verticalPixels := (480 / verticalScaling)

    visibleScale := ((horizontalScaling << 12) + ((constant(640 * 32)          {
		    } >> bitsPerPixel) / horizontalPixels))
    invisibleScale := (((8 << bitsPerPixel) << 12) + 160)

    horizontalLongs := (horizontalPixels / (32 >> bitsPerPixel))
    horizontalLoops := (horizontalLongs * 4)

    screenPointer := newDisplayPointer
    pixelColorsAddress := @pixelColors
    displayIndicatorAddress := @displayIndicator
    syncIndicatorAddress := @syncIndicator

    cogNumber := cognew(@initialization, @screenPointer)
    result or= ++cogNumber

PUB BMPEngineStop '' 3 Stack Longs

'' /////////////////////////////////////////////////////////////////////////////
'' // Shuts down the BMP driver running on a cog.
'' /////////////////////////////////////////////////////////////////////////////

  if(cogNumber)
    cogstop(-1 + cogNumber~)

DAT

' //////////////////////////////////////////////////////////////////////////////
'                       BMP Driver
' //////////////////////////////////////////////////////////////////////////////

	org     0

' //////////////////////Initialization//////////////////////////////////////////

initialization
	mov     vcfg,         videoState        ' Setup video hardware.
	mov     frqa,         frequencyState    '
	movi    ctra,         #%0_00001_101     '

' //////////////////////////////////////////////////////////////////////////////
'                       Active Video
' //////////////////////////////////////////////////////////////////////////////

loop    rdlong  buffer, par                     ' Set/Reset tiles fill counter.
	mov     tilesCounter, verticalPixels    '

tilesDisplay
	mov     tileCounter, verticalScaling    ' Set/Reset tile fill counter.

tileDisplay
	mov     vscl, visibleScale              ' Set/Reset the video scale.
	mov     counter,horizontalLongs         '

' //////////////////////Visible Video///////////////////////////////////////////

videoLoop
	rdlong  screenPixels, buffer            ' Download new pixels.
	add     buffer, #4                      '

	waitvid screenColors, screenPixels      ' Update display scanline.

	djnz    counter, #videoLoop             ' Repeat.

' //////////////////////Invisible Video/////////////////////////////////////////

	mov     vscl, invisibleScale            ' Set/Reset the video scale.

	waitvid HSyncColors, syncPixels         ' Horizontal Sync.

' //////////////////////Repeat//////////////////////////////////////////////////

	sub     buffer, horizontalLoops         ' Repeat.
	djnz    tileCounter, #tileDisplay       '

	add     buffer, horizontalLoops         ' Repeat.
	djnz    tilesCounter, #tilesDisplay     '

' //////////////////////////////////////////////////////////////////////////////
'                       Inactive Video
' //////////////////////////////////////////////////////////////////////////////

	rdlong  screenColors, pixelColorsAddress ' Get new screen colors.
	or      screenColors, HVSyncColors       '

' //////////////////////Update Indicator////////////////////////////////////////

	add     refreshCounter, #1                   ' Update sync indicator.
	wrbyte  refreshCounter, syncIndicatorAddress '

' //////////////////////Front Porch/////////////////////////////////////////////

	mov     counter, #11                    ' Set loop counter.

frontPorch
	mov     vscl, blankPixels               ' Invisible lines.
	waitvid HSyncColors, #0                 '

	mov     vscl, invisibleScale            ' Horizontal Sync.
	waitvid HSyncColors, syncPixels         '

	djnz    counter, #frontPorch            ' Repeat # times.

' //////////////////////Vertical Sync///////////////////////////////////////////

	mov     counter, #(2 + 2)               ' Set loop counter.

verticalSync
	mov     vscl, blankPixels               ' Invisible lines.
	waitvid VSyncColors, #0                 '

	mov     vscl, invisibleScale            ' Vertical Sync.
	waitvid VSyncColors, syncPixels         '

	djnz    counter, #verticalSync          ' Repeat # times.

' //////////////////////Back Porch//////////////////////////////////////////////

	mov     counter, #31                    ' Set loop counter.

backPorch
	mov     vscl, blankPixels               ' Invisible lines.
	waitvid HSyncColors, #0                 '

	mov     vscl, invisibleScale            ' Horizontal Sync.
	waitvid HSyncColors, syncPixels         '

	djnz    counter, #backPorch             ' Repeat # times.

' //////////////////////Update Display Settings/////////////////////////////////

	rdbyte  buffer, displayIndicatorAddress wz ' Update display settings.
	muxnz   dira, directionState               '

' //////////////////////Loop////////////////////////////////////////////////////

	jmp     #loop                           ' Loop.

' //////////////////////////////////////////////////////////////////////////////
'                       Data
' //////////////////////////////////////////////////////////////////////////////

blankPixels
	long    640                     ' Blank scanline pixel length.
syncPixels
	long    $00_00_3F_FC            ' F-porch, h-sync, and b-porch.
HSyncColors
	long    $01_03_01_03            ' Horizontal sync color mask.
VSyncColors
	long    $00_02_00_02            ' Vertical sync color mask.
HVSyncColors
	long    $03_03_03_03            ' Horizontal and vertical sync colors.

' //////////////////////Configuration Settings//////////////////////////////////

directionState
	long    0
videoState
	long    0
frequencyState
	long    0
horizontalScaling
	long    0
verticalScaling
	long    0
horizontalPixels
	long    0
verticalPixels
	long    0
visibleScale
	long    0
invisibleScale
	long    0
horizontalLongs
	long    0
horizontalLoops
	long    0

' //////////////////////Addresses///////////////////////////////////////////////

pixelColorsAddress
	long    0
displayIndicatorAddress
	long    0
syncIndicatorAddress
	long    0

' //////////////////////Run Time Variables//////////////////////////////////////

counter res     1
buffer  res     1

tileCounter
	res     1
tilesCounter
	res     1

screenPixels
	res     1
screenColors
	res     1

refreshCounter
	res     1
displayCounter
	res     1

' //////////////////////////////////////////////////////////////////////////////

	fit     496

DAT

' //////////////////////Variable Arrary/////////////////////////////////////////

screenPointer
	long    0                               ' Screen pointer.
pixelColors
	long    0                               ' Screen colors.
displayIndicator
	byte    1                               ' Video output control.
syncIndicator
	byte    0                               ' Video update control.
cogNumber
	byte    0                               ' Cog ID.
bitsPerPixel
	byte    0                               ' Bits ID.

' //////////////////////////////////////////////////////////////////////////////

{{
┌──────────────────────────────────────────────────────────────────────────────┐
│                          TERMS OF USE:  MIT License                          │
├──────────────────────────────────────────────────────────────────────────────┤
│ Permission is hereby granted, free of charge, to any person obtaining a copy │
│ of this software and associated documentation files (the "Software"), to     │
│ deal in the Software without restriction, including without limitation the   │
│ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or  │
│ sell copies of the Software, and to permit persons to whom the Software is   │
│ furnished to do so, subject to the following conditions:                     │
│                                                                              │
│ The above copyright notice and this permission notice shall be included in   │
│ all copies or substantial portions of the Software.                          │
│                                                                              │
│ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR   │
│ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,     │
│ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE  │
│ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER       │
│ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      │
│ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS │
│ IN THE SOFTWARE.                                                             │
└──────────────────────────────────────────────────────────────────────────────┘
}}

10 Famous Last Words


                                           .-----+-----.
                         .----+----.       |  The END  |
                         | Repent! |       | is neigh! |
                         ·----+----·       ·-----+-----·
                              |  _    _       _  |
                              |\°v°  °v°     ò.ó/|
                                |_|\/|_|)   /|_|
--------------------------------^-^--^-^-----^-^--------------------------------

11 The End

Author: yeti

Created: 2019-11-09 Sat 19:33