256: A (not enough) Space Odyssey

by P_Malin / Bitshifters

A 256 byte BBC BASIC / 6502 effect
For the BBC Micro (Model B)

Released at LoveByte 2024

---------------------------


This effect is mainly implemented in golfed BBC BASIC with some embedded 6502 assembly code.
The size of the production is the file size of the tokenised BASIC program on disk.

There is no loader, just load and run the basic program.

BBC BASIC is a great high level language and part of what I wanted to explore was looking at making an intro with it. I'd made a number of golfed colour cycling BASIC programs for BBC Micro Bot https://www.bbcmicrobot.com/ on Mastodon, https://mastodon.me.uk/@bbcmicrobot which you tag in a Toot containing a BASIC program and it will run the program and reply with a screenshot or video.

The difference with colour cycling effects on the bot is that there it runs for 30 seconds (or 3 hours if you include an emoji) before it captures output.

I wondered about hooking some simple colour cycling on a vsync interrupt in assembler, then allowing the BASIC program to run at its own slower pace to build up the effect so this intro is based on that idea.

The BASIC program is something like:

1REMxƭĄĂƅqƭąĂƅrƩĜƍĄĂƩęƍąĂX`ƥǼHƊHƭMǾ)ĂǰęǦpƢąƊĘep)ďǰĊĊĊĊĊĝIęƍ!ǾǊĐǫhƪhƅǼlqĀćăāĀĄĆ
2MODE2:PRINT"ąĝƀĂĀĂ":Z=1:Y=.1:CALLPAGE:REPEATC=C+1:IFZ<9X=.5-RND(1):S=C/512:Y=-Y:Z=99
3W=6E4/Z:PLOT5+(Z=99),X*W,Y*W:GCOL0,1+C MOD15:Z=Z-S-1:IF7ANDC ELSESOUND(1ANDC/13)*(3ANDS),-9,4+(3ANDC/8)+S,1
4?(PAGE+43)=3+S/2:UNTILFALSE

The BASIC commands get tokenised to byte values when the file is stored on disk so it's not really relevant but BBC BASIC does have the option of abbreviating keywords so even this listing can be golfed further. E.g. PRINT can become P.

1REMxƭĄĂƅqƭąĂƅrƩĜƍĄĂƩęƍąĂX`ƥǼHƊHƭMǾ)ĂǰęǦpƢąƊĘep)ďǰĊĊĊĊĊĝIęƍ!ǾǊĐǫhƪhƅǼlqĀćăāĀĄĆ
2MO.2:P."ąĝƀĂĀĂ":Z=1:Y=.1:CA.PA.:REP.C=C+1:IFZ<9X=.5-RND(1):S=C/512:Y=-Y:Z=99
3W=6E4/Z:PL.5+(Z=99),X*W,Y*W:GC.0,1+C MOD15:Z=Z-S-1:IF7A.C EL.SO.(1A.C/13)*(3A.S),-9,4+(3A.C/8)+S,1
4?(PA.+43)=3+S/2:U.0


The characters after the REM statement in the first line are the assembly code to do the palette cycling. The assembly code for this is in Cycle.asm. 

The special characters here are just a way of embedding particular binary values into the program. I edited a lot of the BASIC code in Owlet https://bbcmic.ro/#. 
Owlet makes a disk image (with the tokenised basic program as a file on it) in order to run the program you edit in the emulator and also has a feature to export that disk image to run in another emulator (or on real hardware).
The unicode values of the special characters are written by Owlet into the program modulo 256 so they do end up just as single bytes in the tokenised basic program.

Note, if you try to press escape and LIST the program, some of the unprintable characters in the REM statement cause this to fail. You can list the rest of the program (everything after Line 2) on a BBC or in the emulator with L.2,

It's also fun when you press escape as the interrupt is still running so the prompt will colour cycling.

Here is a link to Owlet with the program encoded in the URL:

https://bbcmic.ro/#%7B%22v%22%3A1%2C%22program%22%3A%221REMx%C6%AD%C4%84%C4%82%C6%85q%C6%AD%C4%85%C4%82%C6%85r%C6%A9%C4%9C%C6%8D%C4%84%C4%82%C6%A9%C4%99%C6%8D%C4%85%C4%82X%60%C6%A5%C7%BCH%C6%8AH%C6%ADM%C7%BE%29%C4%82%C7%B0%C4%99%C7%A6p%C6%A2%C4%85%C6%8A%C4%98ep%29%C4%8F%C7%B0%C4%8A%C4%8A%C4%8A%C4%8A%C4%8A%C4%9DI%C4%99%C6%8D!%C7%BE%C7%8A%C4%90%C7%ABh%C6%AAh%C6%85%C7%BClq%C4%80%C4%87%C4%83%C4%81%C4%80%C4%84%C4%86%5Cn2%3F%28PAGE%2B22%29%3DPAGE%2F256%3A%3F%28PAGE%2B58%29%3DPAGE%2F256%3AMODE2%3APRINT%5C%22%C4%85%C4%9D%C6%80%C4%82%C4%80%C4%82%5C%22%3AZ%3D1%3AY%3D.1%3ACALLPAGE%3AREPEATC%3DC%2B1%3AIFZ%3C9X%3D.5-RND%281%29%3AS%3DC%2F512%3AY%3D-Y%3AZ%3D99%5Cn3W%3D6E4%2FZ%3APLOT5%2B%28Z%3D99%29%2CX*W%2CY*W%3AGCOL0%2C1%2BC%20MOD15%3AZ%3DZ-S-1%3AIF7ANDC%20ELSESOUND%281ANDC%2F13%29*%283ANDS%29%2C-9%2C4%2B%283ANDC%2F8%29%2BS%2C1%5Cn4%3F%28PAGE%2B43%29%3D3%2BS%2F2%3AUNTILFALSE%22%7D

This is slightly different to the listings above as there is extra code "?(PAGE+22)=PAGE/256:?(PAGE+58)=PAGE/256:" that is not in the compo version which makes the program more portable. Owlet has an emulator ROM configuration that means the program loads to a different address then a vanilla BBC Model B so this code is needed to patch some of the absolute addresses in the assembly code.

The other special characters PRINT"ąĝƀĂĀĂ" is a string that contains special control codes to set graphics options.

The special characters are the equivalent of the following:
VDU 5  REM (write text at graphics cursor - this is also a shortcut to turn the flashing cursor off)
VDU 29,640;512;   REM   VDU 29 means "set the graphics origin - in this case to the centre of the screen" it is followed by two 16 bit values (VDU codes are treated as 16 bit if followed by a ; rather than interpreted as a byte if on their own or followed by a , )

The PRINT string with funky characters for Owlet can be made from these using the following utility:

https://8bitkick.github.io/vdu/

I also used a modified version of this page to encode the assembly.

The rest of the program is more or less standard BASIC stuff with some BBC BASIC extras. CALL PAGE runs the assembly routine. PAGE is where the BASIC program is loaded so it also executes assembly instructions for the first line number and the token of the REM statement but those evaluate to fairly harmless 6502 instructions. The actual assembly code starts at PAGE + 5. 6E4 is a shorter notation for numbers e.g. 60000 in this case.
PLOT is a general purpose drawing command on the BBC Micro (unlike other basic dialects where it tends to mean draw a single pixel). The value immediately after the PLOT command is the PLOT code. In this case we are abusing the fact that a logic expression that evaluates to true is -1 and one that evaluates to false is 0. The plot code 4 is the equivalent of moving the graphics cursor to a location without drawing anything and the plot code 5 draws a line from the previous graphics cursor location to the specified co-ordinate so PLOT5+(Z=99),X*W,Y*W is effectively just moving the cursor and not drawing a line when Z = 99.
The ? command is the BBC BASIC equivalent of PEEK and POKE. ?12345=123 is will write 123 to the byte at address 12345. Similarly X=?12345 will read the byte at address 12345 and put the result in X.

The sound command takes a number of parameters, the first is the channel to use. Channel 0 is special and can be used to make noise effects so we use that for percussion like sounds. The second parameter is the volume which is ranged 0 to -15, I set -9 as its only one digit. The third parameter is the pitch and the last parameter the time to play the sound for.


Bonus:

A link to run in VirtualBeeb (pressing the "3D" button in Owlet also does this)

https://virtual.bbcmic.ro/?embedBasic=1REMx%C6%AD%C4%84%C4%82%C6%85q%C6%AD%C4%85%C4%82%C6%85r%C6%A9%C4%9C%C6%8D%C4%84%C4%82%C6%A9%C4%99%C6%8D%C4%85%C4%82X%60%C6%A5%C7%BCH%C6%8AH%C6%ADM%C7%BE)%C4%82%C7%B0%C4%99%C7%A6p%C6%A2%C4%85%C6%8A%C4%98ep)%C4%8F%C7%B0%C4%8A%C4%8A%C4%8A%C4%8A%C4%8A%C4%9DI%C4%99%C6%8D!%C7%BE%C7%8A%C4%90%C7%ABh%C6%AAh%C6%85%C7%BClq%C4%80%C4%87%C4%83%C4%81%C4%80%C4%84%C4%86%0A2%3F(PAGE%2B22)%3DPAGE%2F256%3A%3F(PAGE%2B58)%3DPAGE%2F256%3AMODE2%3APRINT%22%C4%85%C4%9D%C6%80%C4%82%C4%80%C4%82%22%3AZ%3D1%3AY%3D.1%3ACALLPAGE%3AREPEATC%3DC%2B1%3AIFZ%3C9X%3D.5-RND(1)%3AS%3DC%2F512%3AY%3D-Y%3AZ%3D99%0A3W%3D6E4%2FZ%3APLOT5%2B(Z%3D99)%2CX*W%2CY*W%3AGCOL0%2C1%2BC%20MOD15%3AZ%3DZ-S-1%3AIF7ANDC%20ELSESOUND(1ANDC%2F13)*(3ANDS)%2C-9%2C4%2B(3ANDC%2F8)%2BS%2C1%0A4%3F(PAGE%2B43)%3D3%2BS%2F2%3AUNTILFALSE

