Christmas Challenge

Programming the 6502 microprocessor and its relatives in assembly and other languages.
User avatar
BigEd
Posts: 11464
Joined: 11 Dec 2008
Location: England
Contact:

Re: Christmas Challenge

Post by BigEd »

(I see the video review of competition entries has begun, as a livestream
https://www.youtube.com/watch?v=uHmVMfQbCqE
)
User avatar
drogon
Posts: 1671
Joined: 14 Feb 2018
Location: Scotland
Contact:

Re: Christmas Challenge

Post by drogon »

barrym95838 wrote:
drogon wrote:
Minor improvements can be made by utilising the 3 unused sweet16 non-register opcodes - e.g. one could be print new line and another could be print Acc - that saves the jump to 6502 land and back again twice, however is that overstepping the mark?
Trade-offs are part of the game. Charlie liked Sweet16 enough to install an optimized (!) version on his PET and added opcodes for EXT, a DTC Forth NEXT, DUP and DROP. I hope he's doing well ... I haven't heard from him in months.
I wrote my version almost from scratch and made it a lot faster than the original using 65c02 opcodes if possible, and will run anywhere with no page boundary dependency. But I've not benchmarked it.. It comes to 643 bytes which is a little more than the original... But where to stop - write a program that accepts as input a single star and nothing else and prints a tree - hey, presto, won the code size prize! ;-)

Cheers,

-Gordon
--
Gordon Henderson.
See my Ruby 6502 and 65816 SBC projects here: https://projects.drogon.net/ruby/
User avatar
Proxy
Posts: 746
Joined: 03 Aug 2018
Location: Germany

Re: Christmas Challenge

Post by Proxy »

I didn't enter because i'm bad at optimizing code and I wouldn't've used a retro machine/language.
though the site says you can use any language you want... so if i did enter, i probably would've submitted this:

Code: Select all

#include <stdint.h>
#include "serial.h"

int main(){
	ftprints("            *\n");
	ftprints("           ***\n");
	ftprints("          *****\n");
	ftprints("         *******\n");
	ftprints("           ***\n");
	ftprints("         *******\n");
	ftprints("       ***********\n");
	ftprints("     ***************\n");
	ftprints("          *****\n");
	ftprints("       ***********\n");
	ftprints("    *****************\n");
	ftprints(" ***********************\n");
	ftprints("           ***\n");
	ftprints("           ***\n");
	return 0;
}
using CC65 to target my own 65C02 SBC, the output is 488 Bytes large. Around 1/3rd of that is just for the strings.
I made a more optimized version that is exactly 100 Bytes smaller:

Code: Select all

#include <stdint.h>
#include "serial.h"

// Array contains the amount of Spaces and Stars for each row
uint8_t tree_array[] = {
    12,  1,     // 0            *
    11,  3,     // 1           ***
    10,  5,     // 2          *****
     9,  7,     // 3         *******
    11,  3,     // 4           ***
     9,  7,     // 5         *******
     7, 11,     // 6       ***********
     5, 15,     // 7     ***************
    10,  5,     // 8          *****
     7, 11,     // 9       ***********
     4, 17,     //10    *****************
     1, 23,     //11 ***********************
    11,  3,     //12           ***
    11,  3      //13           ***
};

int main(){
    
    uint8_t i;
    uint8_t k;
    uint8_t spaces;
    uint8_t stars;
    for (i = 0; i < 28; i = i + 2){     // Go through the Array in steps of 2 (Row by Row)
        spaces = tree_array[i];         // For the current Row save the amount of Spaces,
        stars = tree_array[i + 1];      // And Stars it has
        
        for (k = 0; k < spaces; k++){   // Print the Spaces
            ftprintc(' ');
        }
        for (k = 0; k < stars; k++){    // Print the Stars
            ftprintc('*');
        }
        ftprintc('\n');                 // End the current Line and repeat until the end of the Array
    }
    return 0;
}
for anyone curious here is what the "ftprintc" code looks like:

Code: Select all

; ---------------------------------------------------------------------------
; _ftprintc.s
; ---------------------------------------------------------------------------
;
; FT Print Character
;

.importzp   FT_MASK_TXE
.import     FT_OUT, FT_ST_TXE
.export     _ftprintc

.segment "CODE"

.PC02       ; Force 65C02 assembly mode

; ---------------------------------------------------------------------------
; void __fastcall__ _ftprintc(char value);
; Writes "value" to SERIAL

.proc _ftprintc: near
    PHA                     ; Save A onto the Stack
    LDA #FT_MASK_TXE        ; Load the "TXE" (Sending) bit Mask
    @WAIT:
        BIT FT_ST_TXE       ; Check the "TXE" Status bit
    BNE @WAIT               ; If it's not 0, Data cannot be written to SERIAL, so jump back
    PLA                     ; If it is, pull A from the Stack
    STA FT_OUT          ; And Throw it at SERIAL
RTS
.endproc
and yes it does actually run, though it's not centered as the width of the Terminal window is variable.
ttermpro_BqIuXcJvV6.png
Hope i didn't pollute this thread by posting some C Code!
Anyways, Merry Christmas to everyone reading this! :D
User avatar
drogon
Posts: 1671
Joined: 14 Feb 2018
Location: Scotland
Contact:

Re: Christmas Challenge

Post by drogon »

Proxy wrote:
Hope i didn't pollute this thread by posting some C Code!
Anyways, Merry Christmas to everyone reading this! :D
Interesting!

I tried it with my cc65 setup - used cputs() to print the strings and it comes out to 573 bytes in total. I think my runtime overhead is larger as it includes the communications to the host for both filesystem and console IO, as well as a program header that my RubyOS likes.

Using your optimised code with cputc() it comes to 469 bytes.

My cputs() and cputc() are coded in asm but just calls the RubyOS system calls.

Code: Select all

        .export _cputc

        .include        "osVectors.h"

        .code

_cputc:
        cmp     #10
        bne     :+
        pha
        lda     #13
        jsr     osWrch
        pla
:       jmp     osWrch
Maybe what to do is compile a minimal C program ie. just return 0; to get the base, then add in the rest to see the real code size...

so I get 284 bytes, so the simple print version is then 573 - 284 = 325 bytes and and the optimised one 185 bytes. That still feels like a lot of code but maybe that's the price...

-Gordon

Ps. Yes, it works! :)

Code: Select all

* load treec 8000
* go
Starting program at $8000 (Emulation)
            *
           ***
          *****
         *******
           ***
         *******
       ***********
     ***************
          *****
       ***********
    *****************
 ***********************
           ***
           ***
--
Gordon Henderson.
See my Ruby 6502 and 65816 SBC projects here: https://projects.drogon.net/ruby/
User avatar
BigEd
Posts: 11464
Joined: 11 Dec 2008
Location: England
Contact:

Re: Christmas Challenge

Post by BigEd »

Here's a notably short entry, from Geir Straume. (I think the shorter 6502 entries use the LAX undocumented opcode. Which is of course standard on a C64's 6510.)
Screenshot 2021-12-23 17.57.21.png
laubzega
Posts: 6
Joined: 07 Oct 2020

Re: Christmas Challenge

Post by laubzega »

This is the 44 byte C64 entry that assembles to 46 byte executable:

Code: Select all

line = 2

        * = $304 - (end - next_line)
next_line:
        lda #'*'
        ldx line
        ldy tab_c,x
finish: bmi finish
        ldx #12
next_char:
        sta $400+24*40+19,y
        sta $400+24*40+19-12,x
        dex
        dey
        bpl next_char

        jsr $e8ec

        inc line
        jmp next_line
end:

tab_c:  .byte 0,1,2,3,1,3,5,7,2,5,8,11,1,1,$ff
plasmo
Posts: 1273
Joined: 21 Dec 2018
Location: Albuquerque NM USA

Re: Christmas Challenge

Post by plasmo »

This is 4 days late and 1 LED short, but I did it by bit-banging 65816's MX output to drive 16x16 panel of WS2812B RGB LEDs. The program itself is 52 bytes, but the data table is 224 bytes. Should be possible to pack the table to reduce its size by a factor of 8.

I showed it to my wife of 39 years, and she said "Wow!". Now that's a success! :shock: :lol:
Bill

Code: Select all

000000r 1               ;Use MX output to bit-bang WS2912B 16x16 matrix
000000r 1               ;CPU clock is 14.7MHz
000000r 1               
000000r 1               	.p816
000000r 1               	.ORG $1000
001000  1               
001000  1  18           	CLC
001001  1  FB           	XCE		;switch to native mode
001002  1               WSstart:
001002  1  C2 30        	REP #$30	;drive MX low to reset WS2812
001004  1               	.i16
001004  1               	.a16
001004  1  A2 00 01     	LDX #$100	;drive low for 50uS to reset WS2812
001007  1               WSrst:
001007  1  CA           	DEX
001008  1  D0 FD        	BNE WSrst
00100A  1               WSshow:
00100A  1  BD 33 10     	LDA Grn-1,x	;lookup table for green
00100D  1  20 18 10     	JSR showWS
001010  1  E8           	INX
001011  1  E0 E0 00     	CPX #$e0
001014  1  D0 F4        	BNE WSshow
001016  1  80 FE        	BRA *		;stop here
001018  1               
001018  1               showWS:
001018  1               ;shorter version
001018  1               ;Send a byte of color data to WS2812
001018  1               ;1 is 12 clock high, 6 clock low
001018  1               ;0 is 6 clock high, 12 clock low
001018  1               ;reg Y and A are modified
001018  1               	.i16
001018  1               	.a16
001018  1  A0 18 00     	LDY #24		;each LED needs 8 bits of green, red, blue
00101B  1  29 00 FF     	AND #$ff00	; only show green, red and blue are zero
00101E  1               showWSnew1:
00101E  1  0A           	ASL A		;msb first
00101F  1  E2 30        	SEP #$30	;first 6 clocks is always high
001021  1  90 09        	BCC bitLo
001023  1  80 00        	BRA *+2		;3 clock to execute
001025  1  EA           	NOP
001026  1  88           	DEY		;problem?: Y reg is 8-bit at this point
001027  1  C2 30        	REP #$30
001029  1  D0 F3        	BNE showWSnew1
00102B  1  60           	RTS
00102C  1               bitLo:
00102C  1  C2 30        	REP #$30
00102E  1  EA           	NOP
00102F  1  EA           	NOP
001030  1  88           	DEY		;problem?: Y reg is 16-bit here
001031  1  D0 EB        	BNE showWSnew1
001033  1  60           	RTS
001034  1               Grn:
001034  1               ; Green color table
001034  1  00 00 00 00  	.byte 0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0
001038  1  00 00 00 01  
00103C  1  01 01 00 00  
001044  1  00 00 00 00  	.byte 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0
001048  1  00 00 01 01  
00104C  1  01 00 00 00  
001054  1  01 01 01 01  	.byte 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
001058  1  01 01 01 01  
00105C  1  01 01 01 01  
001064  1  00 01 01 01  	.byte 0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0
001068  1  01 01 01 01  
00106C  1  01 01 01 01  
001074  1  00 00 00 00  	.byte 0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0
001078  1  01 01 01 01  
00107C  1  01 01 01 01  
001084  1  00 00 00 00  	.byte 0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0
001088  1  00 01 01 01  
00108C  1  01 01 00 00  
001094  1  00 01 01 01  	.byte 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
001098  1  01 01 01 01  
00109C  1  01 01 01 01  
0010A4  1  00 00 01 01  	.byte 0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0
0010A8  1  01 01 01 01  
0010AC  1  01 01 01 01  
0010B4  1  00 00 00 00  	.byte 0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0
0010B8  1  00 01 01 01  
0010BC  1  01 01 01 01  
0010C4  1  00 00 00 00  	.byte 0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0
0010C8  1  00 00 01 01  
0010CC  1  01 00 00 00  
0010D4  1  00 00 00 00  	.byte 0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0
0010D8  1  00 01 01 01  
0010DC  1  01 01 01 01  
0010E4  1  00 00 00 00  	.byte 0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0
0010E8  1  00 01 01 01  
0010EC  1  01 01 00 00  
0010F4  1  00 00 00 00  	.byte 0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0
0010F8  1  00 00 00 01  
0010FC  1  01 01 00 00  
001104  1  00 00 00 00  	.byte 0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0
001108  1  00 00 00 01  
00110C  1  00 00 00 00  
Attachments
DSC_67131229.jpg
Post Reply