diff --git a/two-liners/doc/autumn.png b/two-liners/doc/autumn.png new file mode 100644 index 00000000..9e8979d1 Binary files /dev/null and b/two-liners/doc/autumn.png differ diff --git a/two-liners/doc/circles.png b/two-liners/doc/circles.png new file mode 100644 index 00000000..eee9f87b Binary files /dev/null and b/two-liners/doc/circles.png differ diff --git a/two-liners/doc/dhgr.png b/two-liners/doc/dhgr.png new file mode 100644 index 00000000..0f13d615 Binary files /dev/null and b/two-liners/doc/dhgr.png differ diff --git a/two-liners/doc/flame.png b/two-liners/doc/flame.png new file mode 100644 index 00000000..d2b6b8f5 Binary files /dev/null and b/two-liners/doc/flame.png differ diff --git a/two-liners/doc/index.html b/two-liners/doc/index.html new file mode 100644 index 00000000..08d621a8 --- /dev/null +++ b/two-liners/doc/index.html @@ -0,0 +1,311 @@ + + + + + + +

Flame Demo (64-byte assembly)

+The first attempt was to see if we could get some assembly language going, +so a good thing to try is my 64B Flame Demo. + +
+ +
+ +The first attempt uses the traditional method of entering assembly +language from BASIC via Applesoft: you have data staements holding the +raw 8-bit data for the 6502 Machine Language, you poke them to a free +area of memory (often $300 (which is 768 in decimal)) and then you call +to it.

+Note this code is longer than 256 chars long which means while it is +a valid Applesoft program, you can't type it in on an actual Apple II +as it will overflow the keyboard input buffer. You can however tokenize +it and load from disk, which must be what the Apple II bot does. +

+
+1 FOR X=768TO832:READ A:POKE X,A:NEXT:CALL 768:DATA 44,80,192,44,82,192,32,112,252,169,255,145,42,136,16,251,169,22,133,37,32,34,252,160,39,104,240,5,10,240,4,144,2,73,29,72,48,10,177,40,41,7,170,189,57,3,145,40,136,16,230,198,37,16,221,48,205,0,187,0,170,0,153,0,221
+
+ +This worked, but then 4am got me thinking about more compact ways to try +and fit larger programs. I looked into the way that Sellam Abraham did things +with his "Mesmerizer Exorciser" Kansasfest 2020 Hackfest entry, but it turns +out that is a bit too big to fit in a tweet.

+ +My fist attempt loads a short assembly language program that then decodes +a string. The string is machine code encoded with two values, the first +shifted left by three then xored with the second to get the value. +

+Why not just include raw 8-bit values? For one on twitter we're going +to assume you can only pass in ASCII text, so that limits you to 7-bit values. +In addition you can't send control characters (the first 32 values) and +on Apple II+ you can't send lowercase, further reducing things. In the +end you are sort of limited to around 6-bits (64 values) and have to +construct the machine code from that. +

+Also note that by now I had remembered that Applesoft ignores all spaces +so you can leave them out to get more room. +
+1 FOR X=768TO789:READ A:POKE X,A:NEXT:CALL768:DATA162,0,189,106,8,48,12,10,10,10,93,171,8,157,0,12,232,208,239,76,0,12
+9 "MBPMBPLFW]WZMYJW]JXLLLW\LEVHIVHZHAKANI^MMH]_OIZMYJTPLJSNQH_H]H[HSD@@DB@@@DAGAB@@CAFEE@BD@G@@EB@D@BAE@@BA@AGBEADA@@@FFE@E@E@C@B@A@E"+
+
+ +
+ +

Circles Demo (101-byte assembly)

+ +
+ +
+ +This is an unreleased demo of mine based on part of Hellmood's "Memories" +Demo

+In this case we are using 4+4 bit encoding, so it takes two bytes to represent +each byte. This is a bit wasteful but it's a lot easier to write a 4+4 +decoder than a more efficient 6+2 one. Applesoft in particular makes +this really difficult as it has no shift or bitwise logic functions. +It's not easy to write decoders in assembly either, so multiplication +in Applesoft it is. The A=(A-INT(A)) code is the way to get a +remainder (modulus) in Applesoft. +

+Note in this case I abandoned using a string. It has some problems, +the worst being that you can't include a quote character (ASCII 34). +Using a REM remark (comment) statement takes slightly more room but +everything after it is ignored. +

+You might ask how we load values from a REM statement. In Applseoft the +whole program is loaded into memory, REM statements and all. Programs +are loaded at $800 in tokenized format, but it's fairly easy to poke +around and find where lines get loaded in memory and then use PEEK to load +the values in. +
+2 GR:FOR X=0TO100:A=(PEEK(2245+X/2)-32)/4:IFJTHENA=(A-INT(A))*4
+3 J=NOTJ:POKE768+X,(PEEK(2144+X)-32)*4+A:NEXT:CALL768:REM+4PY_H&A\RH%A\B&N3 ""?2 29_*'222A^JN8 A,I\B( ^I\( ^I^B( ^I\( ^Y\B$SY\R$P,N)('&&%%$$##""!!!!       5 ="""". ! &.)+)!.*#!'$!( '  . !, ) "."!!+&"""')#)$ $,
+
+ +
+ +

Autumn (117 byte demo)

+ +
+ +
+ +This is a slightly shorter version of my +Seasons demo (without color cycling) that was entered in the Outline +Online 2020 Demo Party. +

+ +This is using 6+2 coding, with the 6 bit values (with 32 added to get the +bits up in visible ASCII) first followed by the packed remaining 2 bits +in chunks of three. Qkumba figured out the crazy use of the exponent +to handle the proper shifting of the 2-bit values. + +

+Because it uses a lot +of multiplies and shifts, this is fairly slow to decode which is why +it has a directive to skip 9 seconds. It should skip more but there +were only 4 free bytes in the tweet so we couldn't delay more. +

+ +
+{B9}
+1REM(V\I\I\B.Y\A\FY\R@:A\9\&B9\A\F9\R@:A\9\9]9]9]9]L'Y^T Y^I\:@A
+\D Y\.J Y\A\J Y\A\I^")^1^A^*!" JI\,HI\*\TG([]I\I\I\(5]3  P")90'6"F)=8KBI.)H%1@&1F1WA6%=:S50@"E,\
+2FORI=0TO116:C=INT((PEEK(2171+I/3)-32)/4^(I-INT(I/3)*3)):POKE768+I,((PEEK(2054+I)-32)*4)+C-INT(C/4)*4:NEXT:CALL768
+
+ +

Spaceship -- Applesoft Shapetable

+ +
+ +
+ +After managing to fit Autumn in, I gave up on assembly language and went +back to coding in Applesoft. One thing Applesoft has going for it is +"Shapetables" which are a software vector drawing library included +in the Applesoft BASIC ROMs. +

+To use shapetables, you map out the vectors. You can only do +draw+move UP/DOWN/LEFT/RIGHT and pen-up move (no-draw) UP/DOWN/LEFT/RIGHT. +Each operating is three bits, you can pack two or sometimes three directives +per byte and there's a header with the number of shapes and the offset +of the shapes. +

+Typically you'd POKE the shapetable into memory via data +statements (there's no easy way to +load them, though oddly there is a dedicated command to loading them from +casette tape). Poking wastes a lot of space, so I thought maybe we +can stick it in a REM statement like before. There's a trick here, you +need to have your shapetable be valid ASCII. To do that you need the second +value in each byte to not be a not-draw instruction, and also you can't +have a third value either. +

+Once you have your shapes, you can DRAW them at a location, or XDRAW +to xor draw (which makes it easier to draw and erase). There is ROT +to rotate and SCALE to scale. +

+This example like 2 tells Applesoft where the shapetable is by POKEing +in the locations to the proper zero page address. The shape table +in the REM depends on being on line 5, because we depend on the +actual layout of the BASIC program. +

+This points to address $814. If you look there in memory you find the values +
29 08 05 00 B2 37 ...
+The 29 08 (little endian) is actually part of the linked list of the BASIC +program in memory pointing to the next line. The 05 00 is the line number. +And B2 is the token for REM followed by the data. By pointing at the +29 we say we have 29 shapes, but that doesn't matter as we only use +1. The next value is ignored. The next is the offset to +the first shape (from the beginning). Since this is 5 it skips the REM +and goes to the data. +

+The rest is just regular Applesoft BASIC, it draws some random stars, +moves the spaceship, and draws some flames and then repeats. +

+ +
+2POKE232,20:POKE233,8
+5REM7:'%%,5..>'<29'
+6HGR2:FOR X=1 TO 100:HCOLOR=7:HPLOT RND(1)*280,RND(1)*192:NEXT
+7SCALE=5:FORR=0TO16:ROT=R:GOSUB9:GOSUB9:NEXT:FOR X=100TO270:GOSUB9
+8HCOLOR=5:HPLOTX-30,86+RND(1)*16TOX-10,91:X1=X+SQR(X/25):GOSUB9:X=X1:NEXT:GOTO6
+9XDRAW1ATX,91:RETURN
+
+ +

Nyan Cat -- Shape Tables and Page Flipping

+ +
+ +
+ +I wanted to do something wiht page-flipping and shape tables, possibly +the only two graphics features the Apple II can do better than other +8-bit computers. I was thinking something like my +Shapetable Party demo.

+ +In the end trying to make complex ASCII shape tables was too much. +But then oddly I had a dream where I made a HGR version of Nyan Cat. +So here it is, a program that brought a lot of joy.

+ +Not much exciting about it, the poptart-cat shapetable is done more or +less like in the previous example. It uses HGR:HGR2 to clear both +graphics pages and leaves things on PAGE2. The rainbow and cat are +first drawn on PAGE2 (the routine at line 8 draws them). Then +they are drawn again at a slightly different offset on PAGE1. +The POKE 230,32 tells the Applesoft routines to draw to PAGE1 +($2000) instead of PAGE2 ($4000). Ideally we'd switch back to page1 +so we could see both being drawn, in fact when watching it there's +an annoying pause while PAGE1 is drawn and you can't see it. However +I was out of characters to do that. +

+As some have pointed out, I used tail-call optimization here, where instead +of GOSUB9 one lsat time in line 8 I fall through to line 9 and let the +return from there return from the GOSUB to line 8. This is something +I do a lot in 6502 assembly and it's fun to do it in BASIC too. +

+The actual program is like 7 which just flips pages rapidly. +The V=0 call was added to slow the animation a bit, it roughly is as slow +as the GOTO7. I tried putting slower things (like SQR() square root) +to slow it even more, but you have to put things twice or the animation +is unbalanced and there wasn't enough room for two. +

+It was a bit more of a pain than you think to get the HGR colors to +plot in rainbow order. Also in size coding like this you run into issues +where it takes less characters to have things to the upper left part +of the screen as the coordinates can be less than 3 digits. +

+ +
+2POKE232,20:POKE233,8
+5REM$,.,6>???$$--5
+6ROT=0:SCALE=5:P=49236:HGR:HGR2:GOSUB8:Q=1:POKE230,32:GOSUB8
+7POKEP+1,0:V=0:POKEP,0:GOTO7
+8C=5:Y=80:XDRAW1AT134,102+Q*2:GOSUB9:C=1:GOSUB9:C=6:GOSUB9:C=2
+9HCOLOR=C:FORZ=YTOY+5:FORX=0TO13:Q=NOTQ:HPLOTX*8,Z+QTOX*8+7,Z+Q:NEXTX,Z:Y=Z:RETURN
+
+ +

Double Hires Pattern

+ +
+ +
+ +I was interested in seeing if I could get some better colors going. +I have done demos that do +Vapor Lock and +mid-screen race-the beam mode switching +but I was pretty sure the Linux-based emulator used by the Apple II bot +can't do that type of cycle-counted effects.

+ +The emulator did seem to be emulating Apple IIe, which opened things +up for double hi-res graphics. Those are tricky to do and you can't +easily program them from Applesoft. I actually tried at first but had +some issues fitting in a reasonable amount of room, so assembly language +it is.

+ +This was just a first test but it made a neat pattern. I had a lot of trouble +just getting horizontal lines drawn. To do that in double-hires you +have to draw an increasingly rotated-by-one bit version of the color +across 4 bytes on two different bank-switched graphics pages, a huge pain. +

+
+{B10}
+1REM(X\(V\C7PC#PC PJ(AYJ A_J(Y_I_(* Y_I_RPT[3$ H H ($]H)C5P(1 C5P(1 B$\8I_D)R@)_8 XP)%%1&9Z)OF!S+ !7 ' #1GA#
+2FORI=0TO77:C=INT((PEEK(2132+I/3)-32)/4^(I-INT(I/3)*3)):POKE768+I,((PEEK(2054+I)-32)*4)+C-INT(C/4)*4:NEXT:CALL768
+
+ +

Double Hi-res Rasterbars (126 byte assembly)

+ +
+ +
+ +My goal was to get two colors of double hi-res rasterbars going. +It turns out this is much harder than it sounds. I did get one +rasterbar moving fairly easily, but getting a second independent bar +was trouble. Even then it was 136 bytes which was too big for the loader. +

+So I size optimized the code like crazy, including using the "BIT" trick +to avoid a jump and various other things and got it down to 126 bytes. +The pattern ended up being a bit nonsensical, as I had to use an EOR (xor) +to calculate the location of the second bar, but there is more than one +color. +

+Then I optimized down the BASIC loader. It's still qkumba's 6+2 loader +but I found some parenthesis I could remove, did some algebra and orders-of-operation +changes to remove some more parenthesis, and did some tricks with +integer variables. Applesoft does everything in floating point, but +you can specify 16-bit integer values which will truncate, which removes +the need for an INT (though qkumba later noticed that might not be +necessary). +

+
+1REM(X\(V\C7PC#PC P1YJ (+ J!(+ F,!R0L"HR+HBC* RTYA_F2$JJ!A_I_R!D 2 * &9_JO= A_F2Y_H H ($]H)C5P(; C5P(; B$\:JQ_$R8I_D)R@)_8 $(, W[_XP)%%:0'TP!((Z !!=5!V-AY-4"0P%T!T0@QT9X0.Y
+2FORI=768TO894:C%=(PEEK(1924+I/3)-32)/4^(I-INT(I/3)*3):POKEI,C%+4*(PEEK(1286+I)-32-INT(C%/4)):NEXT:CALL768
+
+ +

The Future

+ +So am I done for now?

+ +There are still a few tricks remaining. There is some deep magic you can +do if you call into the Applesoft interpreter direct from assembly language. +Lots of articles on this from the 1980s.

+ +Applesoft supports calls like USR and & besides CALL to call into +assembly language. The most useful is & which just does a plain +jump to $3F5. If you load your assembly properly you can use this to +save another few characters by getting rid of the CALL768. (Also if +you load your code at $3F5 you can watch it being decoded as it writes +to the $400 text page). +

+ +So maybe I will come back to this again, but for now there's other +projects I really need to finish. It's been fun! + +
+ +Back to Apple II Demos + + + diff --git a/two-liners/doc/nyan.png b/two-liners/doc/nyan.png new file mode 100644 index 00000000..89de0600 Binary files /dev/null and b/two-liners/doc/nyan.png differ diff --git a/two-liners/doc/rasterbars.png b/two-liners/doc/rasterbars.png new file mode 100644 index 00000000..4de700f2 Binary files /dev/null and b/two-liners/doc/rasterbars.png differ diff --git a/two-liners/doc/ship.png b/two-liners/doc/ship.png new file mode 100644 index 00000000..664b74d1 Binary files /dev/null and b/two-liners/doc/ship.png differ