At the time of this project, I had only a casual interest in brainfuck. By now you're probably thinking I have a somewhat unhealthy obsession with it.
So I won't talk too much about the logic of the program, but here are the interesting bits:
A tiny javascript program analysed the image and spit out the binary data we needed.
From here the drawing rountine is just a series of shifts and conditional delays. The register used to pass the X coordinate is not really trashed. Conveniently, it's used directly as the counter for the X column, so at the end of the routine it's left in the correct horizontal position for drawing the next character. So in a loop where we're drawing text, we can set the X coordinate once and call the drawChar routine repeatedly.
A convenient part of having a screen resolution of 256 by 256 is that things wrap automatically. On my 'to-do' list was to make the text wrap automatically at word-breaks, which wouldn't be too hard but I guess it's not important for anything apart from the brainfuck pseudo-terminal output.
Scrolling is implemented by having all the terminal characters in SRAM. Each frame (I set it to every 256 BF instructions) these characters are drawn to the display. When we output some text to the display, it adds to this block of SRAM, and if it reaches the end of the line, or a line-feed character is detected, it repeatedly copies each line into the block of memory before it. See the pushCharSRAM function below, there should be enough comments to make it clear.
That's all I have to say about this one, so take a gander below or head onwards to page 6
### brainfuck.asm ### .org 0 Init: ;///////////////// ; Initialize pointers and memory ;//////////////// ; Set the end-of-terminal-text markers ldi r25, HIGH($0100 +(42*24)) ; Display is 42 by 24 characters ldi r24, LOW($0100 +(42*24)) ; Set cursor to the start of the last line ldi YH, HIGH($0100 +(42*23)) ldi YL, LOW($0100 +(42*23)) ; Set the program pointer ldi ZH, HIGH(BFprog*2) ldi ZL, LOW(BFprog*2) tempReset: ; Pre-fill the ram with zeros ldi XH, HIGH(RAMEND) ldi XL, LOW(RAMEND) ldi r16,0 ramFill: sbiw X, 1 st X, r16 cp XL,r24 cpc XH,r25 ; Stop when we get to the text buffer brne ramFill ; Empty the console of text ldi r16,24 ; 24 lines ldi r18,10 ; Newline character textFill: rcall pushCharSRAM dec r16 brne textFill rjmp Main ;///////////////////// ; To make them within range of the relative branch, some ; of the routines have been placed before the main loop ;////////////////////// BFendOfProgram: push ZH push ZL ldi ZL, LOW(MessEndOfProg*2) ldi ZH, HIGH(MessEndOfProg*2) rcall pushPMtextSRAM pop ZL pop ZH ;rcall readController ;sbrc r11,ctrlStart rjmp tempReset ;sbiw Z,1 rjmp nextInstruction BFplus: ld r17, X ; Increment current cell inc r17 st X, r17 rjmp nextInstruction BFminus: ld r17, X ; Decrement current cell dec r17 st X, r17 rjmp nextInstruction BFdot: ld r18, X ; Output current cell to terminal rcall pushCharSRAM rjmp nextInstruction BFless: sbiw X, 1 ; Decrement cell pointer cp XL,r24 ; Check if we hit the bottom cpc XH,r25 brcs MemOverflow ; If so, show error rjmp nextInstruction BFgreater: adiw X, 1 ; Increment cell pointer in r14,SPL ; Check for collision with Stack in r15,SPH cp XL,r14 cpc XH,r15 breq MemOverflow rjmp nextInstruction ; Error message MemOverflow: ldi ZL, LOW(MessOutOfMem*2) ; Display error message ldi ZH, HIGH(MessOutOfMem*2) rcall pushPMtextSRAM ldi r16, $FF ; Stop execution of BF rjmp nextInstruction ; But we still want the screen to refresh ;/////////////////////////// ; Main Loop ;///////////////////////// Main: ; Y pointer is to terminal text in SRAM ; Z pointer is to program memory for reading commands ; X pointer is used as BF cell pointer ; r25:r24 is the end of the terminal display .def depthL=r20 ; Depth is used to count the number of nested loops. .def depthH=r21 ; We'll make it a word just in case ldi r23, 255 ; Loop this many times each frame runInterpreter: cpi r16, $FF ; If program has ended, skip to draw routine breq drawScreen ; (r16 is initialized as zero) lpm r16, Z+ ; There are only 8 instructions, so it's easiest to just compare each one cpi r16, '[' breq BFopen cpi r16, ']' breq BFclose cpi r16, '+' breq BFplus cpi r16, '-' breq BFminus cpi r16, '.' breq BFdot cpi r16, ',' breq BFcomma cpi r16, '<' breq BFless cpi r16, '>' breq BFgreater cpi r16, $FF breq BFendOfProgram nextInstruction: dec r23 brne runInterpreter drawScreen: rcall displayTerminal rjmp Main ;///////////// ; Wait for user input: Select a character via the controller ;///////////// BFcomma: push r16 push r17 ldi r18, 32 ; Make space on the screen by pushing a space rcall pushCharSRAM sbiw Y, 1 ; Rewind cursor so we'll overwrite that space ldi r18, 65 ; Start off at a printable character rjmp BFcommaLoop ; Continues below (to avoid relative branch range issues) ;///////////////// ; Start a conditional loop ;///////////////// BFopen: ld r17, X cpi r17, 0 brne nextInstruction ldi depthL, 1 ldi depthH, 0 BFopenLoop: ; Cell is zero, so move ahead to closing bracket lpm r17, Z+ cpi r17, '[' breq BFopenIncDepth ; Every open bracket, increase the depth cpi r17, ']' breq BFopenDecDepth rjmp BFopenLoop ; Keep going until final closing bracket BFopenIncDepth: subi depthL, -1; Add 1 to depthH:depthL sbci depthH, -1; Non-intuitive but correct rjmp BFopenLoop BFopenDecDepth: subi depthL,1 sbci depthH,0 brne BFopenLoop ; If a closing bracket and depth=0, we can rjmp nextInstruction ; go back to the main program ;///////////////// ; End a conditional loop ;///////////////// BFclose: ld r17, X cpi r17, 0 breq nextInstruction ; If zero, move along... ldi depthL, 1 ; Else we need to rewind to the opening bracket ldi depthH, 0 sbiw Z, 1 ; Undo the postincrement of the last LPM BFcloseLoop: sbiw Z, 1 ; Rewind and load (there is no lpm -Z instruction) lpm r17, Z cpi r17, ']' breq BFcloseIncDepth ; Every close bracket, increase the depth cpi r17, '[' breq BFcloseDecDepth rjmp BFcloseLoop BFcloseIncDepth: subi depthL, -1; Add 1 to depthH:depthL sbci depthH, -1; Non-intuitive but correct rjmp BFcloseLoop BFcloseDecDepth: subi depthL, 1 sbci depthH, 0 brne BFcloseLoop ; If it's an opening bracket and depth=0, adiw Z, 1 ; increment and go to the next instruction rjmp nextInstruction ;////////////// ; Wait for user input (continued) ;///////////// BFcommaLoop: rcall readController sbrc r12, 3 ; Pressed UP inc r18 sbrc r12, 2 ; Pressed DOWN dec r18 sbrc r12, 4 ; Pressed START rjmp BFcommaLF ; Insert a linefeed character rcall displayTerminal ; We want to display the currently selected character ; First calculate the X/Y coordinates of the cursor mov r16, YL mov r17, YH subi r16, LOW($0100 +(42*23)) ; Subtracting this gives us the sbci r17, HIGH($0100 +(42*23)) ; horizontal cursor position ; r16 should now contain a number between 0 and 42 ldi r17, 6 ; Characters are 6 pixels wide mul r16, r17 ; result is in r1:r0 ldi r16, 252 ; Now subtract that value from the starting X value sub r16, r0 ldi r17, 239 ; Finally set the Y position push r16 ; Now draw it to the screen push r17 push r18 rcall drawChar ; Twice, so that it's extra bright pop r18 pop r17 pop r16 push r18 rcall drawChar pop r18 sbrs r12, 7 ; Pressed A? - store the char and return rjmp BFcommaLoop BFcommaEnd: st X, r18 ; Store into the cell rcall pushCharSRAM ; Display on the screen pop r17 pop r16 rjmp nextInstruction BFcommaLF: ldi r18, 10 rjmp BFcommaEnd ; Draw text from our area of SRAM buffer to screen. displayTerminal: push YH push YL ldi YH, HIGH($0100) ldi YL, LOW($0100) rcall drawTextSRAM pop YL pop YH ret ; Function readController ; r11 is buttons held down. r12 is buttons only just pressed. ; A,B,select,start,up,down,left,right readController: sbis SPSR,SPIF ; Wait for previous reception to complete rjmp readController in r11,SPDR ; Read received data com r11 ; Invert (logic low is button down) ; Work out what buttons have just been pressed. ; r13 is the button states from the previous reading mov r12,r11 ; Copy into r12 eor r12,r13 ; XOR gives us the buttons which have changed and r12,r11 ; AND it with the the buttons currently held down mov r13, r11 ; Save button states into r13 for next time push r16 ldi r16,0b00000000 ; Initiate the next reading out SPDR,r16 pop r16 ret ; Delay functions delayPixel: cpi r16,252 breq delCountBegin nop nop ret delCountBegin: push r16 ldi r16,15 delCount: dec r16 brne delCount pop r16 ret /* Function pushCharSRAM(char, [Y pointer]) * Pushes a character onto the terminal, and linefeeds if needed */ pushCharSRAM: cpi r18, 10 ; Is this a carriage return? brne pushCharSRAMnext ldi r18, 32 ; fill the rest of the line with spaces pushCharSRAMfill: rcall pushCharSRAMnext ; Call repeatedly until it returns 10 cpi r18, 10 brne pushCharSRAMfill ret pushCharSRAMnext: st Y+, r18 cp YL,r24 ; Have we reached the end? cpc YH,r25 brne pushCharSRAMend ; scroll text sbiw r25:r24, 42 ; Temporarily rewind the "end" registers by one line ldi YH, HIGH($0100) ; Fully rewind the cursor ldi YL, LOW($0100) scrollTextLoop: ldd r18, Y+42 ; Load the character directly underneath st Y+, r18 ; Store here and advance cursor cp YL,r24 ; Have we reached the final line? cpc YH,r25 brne scrollTextLoop ; Fill the final line with spaces adiw r25:r24, 42 ; reset the line-end registers to the actual end ldi r18, 32 ; Fill with spaces scrollTextLastLine: st Y+, r18 cp YL,r24 ; Have we reached the real end of it? cpc YH,r25 brne scrollTextLastLine ; Finally set cursor to the start of the last line sbiw YH:YL, 42 ldi r18, 10 ; Return value that the line has ended pushCharSRAMend: ret /* Function pushPMtextSRAM(z pointer) * Pushes a string from prog mem onto the terminal. */ pushPMtextSRAM: lpm r18,Z+ cpi r18,0 ; null terminated string breq pushPMtextEnd rcall pushCharSRAM ; Just keep pushing characters until we hit 0 rjmp pushPMtextSRAM pushPMtextEnd: ret /* Function drawChar(x0,y0,char) * */ drawChar: .def x0=r16 .def y0=r17 .def char=r18 push r19 push ZH push ZL ; Each character is a 5 byte bitmap ldi ZL, LOW(bitmapFontTable*2) ldi ZH, HIGH(bitmapFontTable*2) subi char,33 ; Font starts at ascii 33 brsh drawCharMain ; if printable, draw it subi x0,5 ; Otherwise, just move the rjmp drawCharCheckEOL ; cursor 5 pixels and continue drawCharMain: ldi r19,5 mul char,r19 ; Multiply char by 5 movw char,r0 ; Result is in R1:R0 add ZL, char ; Add this to Z pointer adc ZH, r19 ldi r19,5 drawCharLoopByte: lpm char, Z+ push y0 drawCharLoopBit: sbrs char,0 rjmp drawCharNextBit out PORTC,y0 out PORTA,x0 rcall delayPixel drawCharNextBit: dec y0 lsr char brne drawCharLoopBit dec x0 pop y0 dec r19 brne drawCharLoopByte drawCharCheckEOL: dec x0 ; Move cursor ready to draw next character brne drawCharEnd ; end of line? ldi x0, 252 ; wrap subi y0, -10 ; out PORTC,y0 ; try and give it a little more time to stabilize? ; out PORTA,x0 drawCharEnd: pop ZL pop ZH pop r19 ret /* Function drawTextSRAM * draws a message from data space, starting at YH:YL and ending at r25:r24 */ drawTextSRAM: push r16 push r17 push r18 ldi x0,252 ldi y0,9 out PORTC,y0 ; move the beam in advance to reduce artifacts out PORTA,x0 drawTextSRAMLoop: cp YL,r24 cpc YH,r25 ; Have we reached the end? breq drawTextSRAMend ld r18,Y+ ; Load next character rcall drawChar ; x and y are passed straight through to drawChar rjmp drawTextSRAMLoop drawTextSRAMend: pop r18 pop r17 pop r16 ret bitmapFontTable: .db $00,$00,$FA,$00,$00,$00,$E0,$00,$E0,$00,$28,$FE,$28,$FE,$28,$24,$54,$FE,$54,$48,$C4,$C8,$10,$26,$46,$6C,$92,$6A,$04,$0A,$00,$00,$E0,$00,$00,$38,$44,$82,$00,$00,$00,$00,$82,$44,$38,$44,$28,$FE,$28,$44,$10,$10,$7C,$10,$10,$00,$02,$0C,$00,$00,$10,$10,$10,$10,$10,$00,$00,$02,$00,$00,$04,$08,$10,$20,$40,$7C,$8A,$92,$A2,$7C,$00,$42,$FE,$02,$00,$46,$8A,$92,$92,$62,$84,$82,$92,$B2,$CC,$18,$28,$48,$FE,$08,$E4,$A2,$A2,$A2,$9C,$3C,$52,$92,$92,$8C,$80,$8E,$90,$A0,$C0,$6C,$92,$92,$92,$6C,$62,$92,$92,$94,$78,$00,$00,$28,$00,$00,$00,$02,$2C,$00,$00,$10,$28,$44,$82,$00,$28,$28,$28,$28,$28,$00,$82,$44,$28,$10,$40,$80,$9A,$A0,$40,$7C,$82,$BA,$9A,$72,$3E,$48,$88,$48,$3E,$FE,$92,$92,$92,$6C,$7C,$82,$82,$82,$44,$FE,$82,$82,$82,$7C,$FE,$92,$92,$92,$82,$FE,$90,$90,$90,$80,$7C,$82,$82,$8A,$8E,$FE,$10,$10,$10,$FE,$00,$82,$FE,$82,$00,$04,$02,$02,$02,$FC,$FE,$10,$28,$44,$82,$FE,$02,$02,$02,$02,$FE,$40,$30,$40,$FE,$FE,$20,$10,$08,$FE,$7C,$82,$82,$82,$7C,$FE,$90,$90,$90,$60,$7C,$82,$8A,$84,$7A,$FE,$90,$98,$94,$62,$64,$92,$92,$92,$4C,$80,$80,$FE,$80,$80,$FC,$02,$02,$02,$FC,$F8,$04,$02,$04,$F8,$FE,$04,$18,$04,$FE,$C6,$28,$10,$28,$C6,$C0,$20,$1E,$20,$C0,$86,$8A,$92,$A2,$C2,$00,$FE,$82,$82,$00,$40,$20,$10,$08,$04,$00,$82,$82,$FE,$00,$20,$40,$80,$40,$20,$01,$01,$01,$01,$01,$00,$80,$40,$20,$00,$04,$2A,$2A,$2A,$1E,$FE,$22,$22,$22,$1C,$1C,$22,$22,$22,$22,$1C,$22,$22,$22,$FE,$1C,$2A,$2A,$2A,$1A,$10,$7E,$90,$90,$40,$18,$25,$25,$25,$1E,$FE,$20,$20,$20,$1E,$00,$22,$BE,$02,$00,$02,$01,$21,$BE,$00,$FE,$08,$08,$14,$22,$00,$82,$FE,$02,$00,$3E,$20,$1C,$20,$3E,$3E,$20,$20,$20,$1E,$1C,$22,$22,$22,$1C,$3F,$24,$24,$24,$18,$18,$24,$24,$24,$3F,$3E,$10,$20,$20,$20,$12,$2A,$2A,$2A,$24,$20,$FC,$22,$22,$04,$3C,$02,$02,$04,$3E,$38,$04,$02,$04,$38,$3E,$02,$0C,$02,$3E,$22,$14,$08,$14,$22,$38,$05,$05,$05,$3E,$22,$26,$2A,$32,$22,$10,$6C,$82,$82,$00,$00,$00,$FF,$00,$00,$00,$82,$82,$6C,$10,$40,$80,$C0,$40,$80,$54,$28,$54,$28,$54,$00,$00,$00,$00,$00,0 MessOutOfMem: .db "OUT OF MEMORY",10,0 MessEndOfProg: .db 10,"END OF PROGRAM",10,0 BFprog: ; HelloWorld x10 ;.db " >>>>>>>++++++++++ [<<<<<<< >++++++++[<+++++++++>-]<.>>+>+>++>[-]+<[>[->+<<++++>]<<]>.+++++++..+++.>>+++++++.<<<[[-]<[-]>]<+++++++++++++++.>>.+++.------.--------.>>+.>++++. <<<<<[-]>[-]>[-]>[-]>[-]>[-]>[-]>-] ",$FF ; HelloWorld ;.db ">++++++++[<+++++++++>-]<.>>+>+>++>[-]+<[>[->+<<++++>]<<]>.+++++++..+++.>>+++++++.<<<[[-]<[-]>]<+++++++++++++++.>>.+++.------.--------.>>+.>++++.",$FF ; Primes .db ">>>>>>>>> >++++++++[<++++++++>-]<++++++++++++++++.[-]>++++++++++[<++++++++++>-]<++++++++++++++.[-]>++++++++++[<++++++++++>-]<+++++.[-]>++++++++++[<++++++++++>-]<+++++++++.[-]>++++++++++[<++++++++++>-]<+.[-]>++++++++++[<++++++++++>-]<+++++++++++++++.[-]>+++++[<+++++>-]<+++++++.[-]>++++++++++[<++++++++++>-]<+++++++++++++++++.[-]>++++++++++[<++++++++++>-]<++++++++++++.[-]>+++++[<+++++>-]<+++++++.[-]>++++++++++[<++++++++++>-]<++++++++++++++++.[-]>++++++++++[<++++++++++>-]<+++++++++++.[-]>+++++++[<+++++++>-]<+++++++++.[-]>+++++[<+++++>-]<+++++++.[-]+[->,----------[<+>-------------------------------------->[>+>+<<-]>>[<<+>>-]<>>>+++++++++[<<<[>+>+<<-]>>[<<+>>-]<[<<+>>-]>>-]<<<[-]<<[>+<-]]<]>>[<<+>>-]<<>+<-[>+[>+>+<<-]>>[<<+>>-]<>+<-->>>>>>>>+<<<<<<<<[>+<-<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<<<>[>>+>+<<<-]>>>[<<<+>>>-]<<<<>>>[>+>+<<-]>>[<<+>>-]<<<[>>>>>+<<<[>+>+<<-]>>[<<+>>-]<[>>[-]<<-]>>[<<<<[>+>+<<-]>>[<<+>>-]<>>>-]<<<-<<-]+>>[<<[-]>>-]<<>[-]<[>>>>>>[-]<<<<<<-]<<>>[-]>[-]<<<]>>>>>>>>[-<<<<<<<[-]<<[>>+>+<<<-]>>>[<<<+>>>-]<<<>>[>+<-]>[[>+>+<<-]>>[<<+>>-]<>+++++++++<[>>>+<<[>+>[-]<<-]>[<+>-]>[<<++++++++++>>-]<<-<-]+++++++++>[<->-]<[>+<-]<[>+<-]<[>+<-]>>>[<<<+>>>-]<>+++++++++<[>>>+<<[>+>[-]<<-]>[<+>-]>[<<++++++++++>>>+<-]<<-<-]>>>>[<<<<+>>>>-]<<<<>[-]<<+>]<[[>+<-]+++++++[<+++++++>-]<-><.[-]>>[<<+>>-]<<-]>++++[<++++++++>-]<.[-]>>>>>>>]<<<<<<<<>[-]<[-]<<-]++++++++++.[-]",$FF ;Fibonacci ;.db "+++++++++++>+>>>>++++++++++++++++++++++++++++++++++++++++++++>++++++++++++++++++++++++++++++++<<<<<<[>[>>>>>>+>+<<<<<<<-]>>>>>>>[<<<<<<<+>>>>>>>-]<[>++++++++++[-<-[>>+>+<<<-]>>>[<<<+>>>-]+<[>[-]<[-]]>[<<[>>>+<<<-]>>[-]]<<]>>>[>>+>+<<<-]>>>[<<<+>>>-]+<[>[-]<[-]]>[<<+>>[-]]<<<<<<<]>>>>>[++++++++++++++++++++++++++++++++++++++++++++++++.[-]]++++++++++<[->-<]>++++++++++++++++++++++++++++++++++++++++++++++++.[-]<<<<<<<<<<<<[>>>+>+<<<<-]>>>>[<<<<+>>>>-]<-[>>.>.<<<[-]]<<[>>+>+<<<-]>>>[<<<+>>>-]<<[<+>-]>[<+>-]<<<-]",$FF ;99 Bottles .db ">+++++++++[<+++++++++++>-]<[>[-]>[-]<<[>+>+<<-]>>[<<+>>-]>>>[-]<<<+++++++++<[>>>+<<[>+>[-]<<-]>[<+>-]>[<<++++++++++>>>+<-]<<-<-]+++++++++>[<->-]>>+>[<[-]<<+>>>-]>[-]+<<[>+>-<<-]<<<[>>+>+<<<-]>>>[<<<+>>>-]>[<+>-]<<-[>[-]<[-]]>>+<[>[-]<-]<++++++++[<++++++<++++++>>-]>>>[>+>+<<-]>>[<<+>>-]<[<<<<<.>>>>>-]<<<<<<.>>[-]>[-]++++[<++++++++>-]<.>++++[<++++++++>-]<++.>+++++[<+++++++++>-]<.><+++++..--------.-------.>>[>>+>+<<<-]>>>[<<<+>>>-]<[<<<<++++++++++++++.>>>>-]<<<<[-]>++++[<++++++++>-]<.>+++++++++[<+++++++++>-]<--.---------.>+++++++[<---------->-]<.>++++++[<+++++++++++>-]<.+++..+++++++++++++.>++++++++[<---------->-]<--.>+++++++++[<+++++++++>-]<--.-.>++++++++[<---------->-]<++.>++++++++[<++++++++++>-]<++++.------------.---.>+++++++[<---------->-]<+.>++++++++[<+++++++++++>-]<-.>++[<----------->-]<.+++++++++++..>+++++++++[<---------->-]<-----.---.>>>[>+>+<<-]>>[<<+>>-]<[<<<<<.>>>>>-]<<<<<<.>>>++++[<++++++>-]<--.>++++[<++++++++>-]<++.>+++++[<+++++++++>-]<.><+++++..--------.-------.>>[>>+>+<<<-]>>>[<<<+>>>-]<[<<<<++++++++++++++.>>>>-]<<<<[-]>++++[<++++++++>-]<.>+++++++++[<+++++++++>-]<--.---------.>+++++++[<---------->-]<.>++++++[<+++++++++++>-]<.+++..+++++++++++++.>++++++++++[<---------->-]<-.---.>+++++++[<++++++++++>-]<++++.+++++++++++++.++++++++++.------.>+++++++[<---------->-]<+.>" .db "++++++++[<++++++++++>-]<-.-.---------.>+++++++[<---------->-]<+.>+++++++[<++++++++++>-]<--.+++++++++++.++++++++.---------.>++++++++[<---------->-]<++.>+++++[<+++++++++++++>-]<.+++++++++++++.----------.>+++++++[<---------->-]<++.>++++++++[<++++++++++>-]<.>+++[<----->-]<.>+++[<++++++>-]<..>+++++++++[<--------->-]<--.>+++++++[<++++++++++>-]<+++.+++++++++++.>++++++++[<----------->-]<++++.>+++++[<+++++++++++++>-]<.>+++[<++++++>-]<-.---.++++++.-------.----------.>++++++++[<----------->-]<+.---.[-]<<<->[-]>[-]<<[>+>+<<-]>>[<<+>>-]>>>[-]<<<+++++++++<[>>>+<<[>+>[-]<<-]>[<+>-]>[<<++++++++++>>>+<-]<<-<-]+++++++++>[<->-]>>+>[<[-]<<+>>>-]>[-]+<<[>+>-<<-]<<<[>>+>+<<<-]>>>[<<<+>>>-]<>>[<+>-]<<-[>[-]<[-]]>>+<[>[-]<-]<++++++++[<++++++<++++++>>-]>>>[>+>+<<-]>>[<<+>>-]<[<<<<<.>>>>>-]<<<<<<.>>[-]>[-]++++[<++++++++>-]<.>++++[<++++++++>-]<++.>+++++[<+++++++++>-]<.><+++++..--------.-------.>>[>>+>+<<<-]>>>[<<<+>>>-]<[<<<<++++++++++++++.>>>>-]<<<<[-]>++++[<++++++++>-]<.>+++++++++[<+++++++++>-]<--.---------.>+++++++[<---------->-]<.>++++++[<+++++++++++>-]<.+++..+++++++++++++.>++++++++[<---------->-]<--.>+++++++++[<+++++++++>-]<--.-.>++++++++[<---------->-]<++.>++++++++[<++++++++++>-]<++++.------------.---.>+++++++[<---------->-]<+.>++++++++[<+++++++++++>-]<-.>++[<----------->-]<.+++++++++++..>+++++++++[<---------->-]<-----.---.+++.---.[-]<<<]",$FF .include "Bootloader.asm"
Next up, Anaconda, audio and some maths.