diff --git a/examples/atari_lynx/atari_lynx_demo.mfk b/examples/atari_lynx/atari_lynx_demo.mfk new file mode 100644 index 00000000..fb1d2dad --- /dev/null +++ b/examples/atari_lynx/atari_lynx_demo.mfk @@ -0,0 +1,243 @@ + +import joy +import atari_lynx_hardware + +// BUILD with millfork demo.mfk -t atari_lynx -o lynx +// the lynx.o file will have the correct header to load into Handy Emulator + +// highly recommended to use compressed atari bitmap formats for art via +// https://github.com/Wookie/sprpck +// sprpck.exe -a080014 -v logo.pcx logo + +// from CC64 suzy.h +// this is the suzy sprite format +// this is the largest type supported +// see atari lynx hardware documents found here +// https://atarilynxdeveloper.wordpress.com/documentation/ + +struct SCB_REHVST_PAL { + byte spctrl0 + byte spctrl1 + byte spcollision + word next + word image + word xpos + word ypos + word width + word height + word stretch + word tilt + byte remap01 + byte remap23 + byte remap45 + byte remap67 + byte remap89 + byte remapAB + byte remapCD + byte remapEF +} +SCB_REHVST_PAL demosp @$5000 + +void initDemoSprite() { + + // set Bits per pixel and type of sprite SEE atari_lynx.mfk for options + demosp.spctrl0 = BPP_4 | TYPE_BACKNONCOLL + // set the sprite format, here we use the most complex one. + demosp.spctrl1 = REHVST + demosp.spcollision = 0 + // set location + demosp.xpos = 80 + demosp.ypos = 51 + // atari sprites are a chain so to draw more you add them to the prior sprite's next + demosp.next = 0 + // width is defined as 8:8 fixed point , where $100 = 1.00,$200 = 2.0,$80=0.5 etc + demosp.width = $100 + demosp.height = $100 + + demosp.tilt = 0 + demosp.stretch = 0 + + // image to use + demosp.image = background_sprite.addr + + // you can remap any pen per sprite if you wish + // more useful for BPP_1-BPP_3 + demosp.remap01 = $01 + demosp.remap23 = $23 + demosp.remap45 = $45 + demosp.remap67 = $67 + demosp.remap89 = $89 + demosp.remapAB = $ab + demosp.remapCD = $cd + demosp.remapEF = $ef +} + +void main() { +byte i +byte t +pointer dest +pointer source + + // see atari_lynx_hardware.mfk + // we set suzy to $dc00 for display address + // 60hz display as recommended + + lynx_init() + initDemoSprite() + + // copy the palette + i = 0 + for t,0,until,16 { + palette_ram_green[t]=palette[i] + palette_ram_blue_red[t]=palette[i+1] + i+=2 + } + + while true { + // wait for the "raster" to hit 60 + // while we wait set the blue + red to the current raster pos + while RASTER!=60 { + palette_ram_blue_red[0]=RASTER + } + read_joy1() + + // tell suzy to process our commands + VIDBASE = $dc00 + SPRGO = 1 + SCBNEXT=demosp.addr + SUZYDONEACK = 1 + + // wait until finished + lynx_wait_suzy() + SUZYDONEACK = 0 + + + if input_btn!=0 { + if input_dx==$ff { + demosp.width-=1 + } + if input_dx==$01 { + demosp.width+=1 + } + if input_dy==$ff { + demosp.height-=1 + } + if input_dy==$01 { + demosp.height+=1 + } + } + else { + if input_dy==$ff { + demosp.ypos+=1 + } + if input_dy==$01 { + demosp.ypos-=1 + } + if input_dx==$ff { + demosp.xpos-=1 + } + if input_dx==$01 { + demosp.xpos+=1 + } + } + } +} + +// image encoded with sprpack + +array background_sprite=[ + $18, $15, $10, $23, $BC, $7A, $80, $8C, $0B, $49, $08, $8C, + $8B, $89, $52, $91, $01, $88, $74, $20, $98, $80, $A0, $00, + $1A, $15, $14, $24, $35, $C4, $A9, $75, $68, $80, $B4, $B0, + $9E, $CD, $71, $68, $5B, $0E, $15, $46, $44, $20, $88, $80, + $9C, $00, $15, $15, $1C, $23, $BC, $7A, $88, $81, $69, $A1, + $11, $90, $D4, $38, $75, $0E, $3D, $43, $5E, $01, $00, $12, + $15, $24, $03, $C5, $A8, $F4, $96, $9E, $10, $10, $D4, $39, + $74, $1E, $78, $40, $00, $12, $15, $24, $20, $21, $E2, $D4, + $38, $B4, $F0, $08, $40, $43, $CC, $A8, $F6, $B8, $00, $11, + $15, $2C, $21, $A1, $E5, $53, $80, $42, $10, $86, $B6, $A1, + $C1, $A8, $0A, $C0, $12, $15, $30, $22, $3A, $AA, $58, $40, + $4B, $10, $10, $84, $35, $B5, $3E, $AD, $14, $80, $13, $15, + $38, $24, $35, $C7, $A4, $04, $05, $70, $20, $86, $87, $97, + $41, $E8, $C8, $98, $00, $12, $15, $3C, $24, $13, $C6, $A2, + $84, $05, $B0, $50, $86, $87, $97, $41, $E8, $69, $40, $11, + $15, $3C, $02, $10, $D3, $51, $01, $B0, $80, $80, $87, $99, + $41, $E8, $08, $C0, $0E, $78, $38, $20, $2D, $88, $0A, $C2, + $5B, $D4, $DE, $86, $88, $00, $07, $78, $3C, $1E, $0F, $07, + $80, $07, $78, $3C, $1E, $0F, $07, $80, $07, $78, $3C, $1E, + $0F, $07, $80, $01, $17, $85, $07, $84, $10, $10, $F1, $28, + $3D, $0D, $28, $16, $90, $10, $D3, $54, $64, $42, $05, $80, + $8A, $61, $60, $13, $97, $50, $84, $21, $A1, $E2, $54, $BA, + $84, $C0, $5A, $78, $08, $20, $2F, $88, $43, $40, $11, $86, + $88, $23, $3C, $4A, $0F, $43, $50, $05, $A7, $84, $01, $F0, + $18, $78, $00, $11, $08, $40, $43, $C5, $A8, $F4, $A4, $0B, + $4E, $08, $0B, $E2, $30, $2F, $08, $00, $14, $84, $87, $89, + $52, $EA, $15, $81, $69, $61, $01, $7C, $46, $04, $21, $01, + $0F, $40, $5A, $00, $10, $3D, $43, $5A, $05, $A5, $03, $E0, + $30, $10, $8E, $D1, $3A, $12, $B0, $00, $12, $35, $42, $5C, + $05, $A4, $03, $E0, $30, $10, $86, $8B, $89, $41, $E8, $C8, + $A0, $00, $13, $1D, $07, $A1, $AF, $02, $D1, $81, $F0, $18, + $20, $47, $68, $3C, $5A, $0F, $46, $B4, $C0, $14, $15, $07, + $A0, $2F, $08, $01, $68, $81, $01, $7C, $46, $04, $E1, $0D, + $0F, $26, $A1, $24, $00, $0E, $16, $BC, $06, $05, $D1, $84, + $05, $D1, $01, $60, $38, $42, $00, $07, $78, $3C, $1E, $0F, + $07, $80, $07, $78, $3C, $1E, $0F, $07, $80, $07, $78, $3C, + $1E, $0F, $07, $80, $07, $78, $3C, $1E, $0F, $07, $80, $01, + $16, $35, $47, $B5, $A1, $0D, $0F, $1A, $A1, $22, $00, $F1, + $6A, $3D, $AF, $00, $84, $25, $35, $0E, $10, $00, $15, $35, + $47, $B5, $81, $19, $E3, $54, $78, $44, $11, $AE, $3D, $47, + $B5, $E1, $10, $94, $D4, $38, $40, $16, $0F, $12, $A3, $DA, + $B0, $8D, $71, $AA, $3D, $A2, $08, $8F, $2E, $A0, $2E, $08, + $4A, $6A, $1C, $20, $00, $14, $88, $F1, $2A, $3D, $A9, $08, + $09, $E8, $3C, $50, $88, $F2, $E9, $C1, $09, $4D, $43, $84, + $00, $18, $10, $47, $78, $35, $1E, $D3, $84, $24, $3C, $6A, + $80, $A4, $23, $BC, $9A, $8F, $53, $02, $12, $9A, $87, $08, + $00, $19, $86, $88, $28, $3D, $5D, $A5, $08, $8F, $1A, $83, + $D0, $D5, $84, $77, $93, $41, $E8, $0A, $82, $12, $9A, $87, + $08, $00, $19, $97, $50, $84, $26, $35, $DA, $40, $80, $87, + $8B, $52, $EA, $16, $84, $35, $54, $1E, $86, $A4, $21, $29, + $A8, $70, $80, $17, $15, $43, $44, $11, $D1, $18, $43, $4D, + $41, $E8, $6B, $C2, $40, $3C, $AA, $87, $24, $21, $29, $A8, + $70, $80, $17, $0D, $07, $A1, $25, $09, $0D, $71, $AA, $3C, + $2F, $01, $04, $77, $97, $50, $13, $84, $25, $35, $0E, $10, + $00, $0F, $2E, $C0, $44, $09, $D7, $81, $C2, $02, $CD, $30, + $40, $55, $A2, $00, $07, $78, $3C, $1E, $0F, $07, $80, $07, + $78, $3C, $1E, $0F, $07, $80, $07, $78, $3C, $1E, $0F, $07, + $80, $07, $78, $3C, $1E, $0F, $07, $80, $01, $14, $35, $47, + $B5, $E1, $01, $45, $4E, $44, $34, $75, $2E, $A1, $78, $08, + $21, $29, $A8, $70, $80, $16, $35, $47, $B5, $E1, $30, $1A, + $E2, $D0, $7A, $62, $03, $21, $A8, $C8, $BC, $06, $10, $94, + $D4, $38, $40, $13, $35, $47, $B5, $E0, $10, $90, $EF, $1E, + $A1, $A1, $00, $EB, $C0, $A0, $9A, $0F, $08, $00, $11, $35, + $47, $B5, $E0, $40, $8D, $71, $EA, $1A, $F0, $38, $42, $53, + $50, $E1, $00, $0E, $35, $47, $B5, $E0, $40, $8E, $F1, $EA, + $1C, $F0, $78, $18, $00, $0F, $35, $47, $B5, $E0, $40, $8E, + $F1, $EA, $1C, $60, $78, $B0, $44, $00, $11, $35, $47, $B5, + $E0, $40, $8E, $F1, $EA, $1C, $50, $86, $BE, $97, $50, $E1, + $00, $12, $35, $47, $B5, $E0, $40, $8E, $F1, $EA, $1C, $50, + $8E, $F3, $E9, $55, $0E, $10, $00, $11, $35, $47, $B5, $E0, + $40, $8E, $F2, $28, $A1, $1D, $E7, $D2, $AA, $1C, $20, $00, + $10, $35, $47, $B5, $E0, $40, $86, $A6, $8A, $11, $DE, $7D, + $2A, $A1, $C2, $00, $07, $78, $3C, $1E, $0F, $07, $80, $07, + $78, $3C, $1E, $0F, $07, $80, $07, $78, $3C, $1E, $0F, $07, + $80, $07, $78, $3C, $1E, $0F, $07, $80, $00 + ] +// colors are 0000GGGG,BBBBRRRR +array palette = [ + $00,$10, + $02,$33, + $04,$65, + $03,$77, + $08,$A8, + $0C,$C7, + $08,$93, + $04,$41, + $03,$39, + $06,$49, + $09,$3E, + $06,$7D, + $09,$7D, + $07,$36, + $0C,$4C, + $0E,$BF + ] \ No newline at end of file diff --git a/include/atari_lynx.ini b/include/atari_lynx.ini new file mode 100644 index 00000000..f2d7aa53 --- /dev/null +++ b/include/atari_lynx.ini @@ -0,0 +1,27 @@ +[compilation] +arch=cmos +modules= +encoding=atascii +screen_encoding=atasciiscr + +[allocation] +zp_bytes=$2-$ff +segment_default_start=$300 +segment_default_end=$dc00 + +[define] +ATARI_LYNX=1 +WIDESCREEN=1 +KEYBOARD=0 +JOYSTICKS=1 +HAS_BITMAP_MODE=1 + +[output] +;TODO +style=single +format=$80,$08,$3,$00,length_be,$42,$53,$39,$33,allocated +extension=o + + + + diff --git a/include/atari_lynx_hardware.mfk b/include/atari_lynx_hardware.mfk new file mode 100644 index 00000000..035f62f6 --- /dev/null +++ b/include/atari_lynx_hardware.mfk @@ -0,0 +1,182 @@ +#if not(ATARI_LYNX) +#warn atari lynx module should be only used on atari lynx +#endif + +word TMPADRL @$fc00 +word TILTACUM @$fc02 +word HOFF @$fc04 +word VOFF @$fc06 +word VIDBASE @$fc08 +word COLLBASE @$fc0a +word VIDADRL @$fc0c +word COLLADRL @$fc0e +word SCBNEXT @$fc10 +word SPRDLINE @$fc12 +word HPOSSTRT @$fc14 +word VPOSSTRT @$fc16 +word SPRHSIZ @$fc18 +word SPRVSIZ @$fc1a +word STRETCH @$fc1c +word TILT @$fc1e +word SPRDOFF @$fc20 +word SPRVPOS @$fc22 +word COLLOFF @$fc24 +word VSIZACUM @$fc26 +word HSIZOFF @$fc28 +word VSIZOFF @$fc2a +word SCBADR @$fc2c +word PROCADR @$fc2e +byte SPRCTRL0 @$fc80 +byte SPRCTRL1 @$fc81 +byte SPRCOLL @$fc82 +byte SPRINT @$fc83 + +byte SUZYBUSEN @$fc90 +byte SPRGO @$fc91 +byte SPRSYS @$fc92 + +byte JOYSTICK @$fcb0 +byte SWITCHES @$fcb1 + +word DISPADR @$fd94 +byte SUZYDONEACK @$fd90 +byte CPUSLEEP @$fd91 +byte DISPCTRL @$fd92 +byte PBKUP @$fd93 + +byte INTSET @$fd81 + +byte TIMER0_reload @$fd00 +byte TIMER0_ctrl @$fd01 +byte TIMER0_count @$fd02 +byte TIMER0_ctrl2 @$fd03 + +byte TIMER1_reload @$fd04 +byte TIMER1_ctrl @$fd05 +byte TIMER1_count @$fd06 +byte TIMER1_ctrl2 @$fd07 + +// video vertical position +byte TIMER2_reload @$fd08 +byte TIMER2_ctrl @$fd09 +byte TIMER2_count @$fd0a +byte TIMER2_ctrl2 @$fd0b + +byte RASTER @$fd0a + +byte TIMER3_reload @$fd0c +byte TIMER3_ctrl @$fd0d +byte TIMER3_count @$fd0e +byte TIMER3_ctrl2 @$fd0f + +byte TIMER4_reload @$fd10 +byte TIMER4_ctrl @$fd11 +byte TIMER4_count @$fd12 +byte TIMER4_ctrl2 @$fd13 + +byte TIMER5_reload @$fd14 +byte TIMER5_ctrl @$fd15 +byte TIMER5_count @$fd16 +byte TIMER5_ctrl2 @$fd17 + +byte TIMER6_reload @$fd18 +byte TIMER6_ctrl @$fd19 +byte TIMER6_count @$fd1a +byte TIMER6_ctrl2 @$fd1b + +byte TIMER7_reload @$fd1c +byte TIMER7_ctrl @$fd1d +byte TIMER7_count @$fd1e +byte TIMER7_ctrl2 @$fd1f + +const byte DISPLAY_COLOR=%1000 +const byte DISPLAY_4bpp=%0100 +const byte DISPLAY_FLIPPED=%0010 +const byte DISPLAY_ENABLE=%0001 + +// suzy sprite type +const byte TYPE_BACKGROUND =00 +const byte TYPE_BACKNONCOLL =01 +const byte TYPE_BSHADOW =02 +const byte TYPE_BOUNDARY =03 +const byte TYPE_NORMAL =04 +const byte TYPE_NONCOLL =05 +const byte TYPE_XOR =06 +const byte TYPE_SHADOW =07 + +// suzy drawing flags +const byte LITERAL =$80 +const byte PACKED =$00 +const byte ALGO3 =$40 +const byte RENONE =$00 +const byte REHV =$10 +const byte REHVS =$20 +const byte REHVST =$30 +const byte REUSEPAL =$08 +const byte SKIP =$04 +const byte DRAWUP =$02 +const byte DRAWLEFT =$01 + +const byte BPP_1 = %00000000 +const byte BPP_2 = %01000000 +const byte BPP_3 = %10000000 +const byte BPP_4 = %11000000 +const byte HFLIP = $20 +const byte VFLIP = $10 + +array(byte) palette_ram_green[16] @$FDA0 +array(byte) palette_ram_blue_red[16] @$FDb0 + +//joystick + +const byte BTN_A= %00000001 +const byte BTN_B= %00000010 +const byte BTN_R= %00010000 +const byte BTN_L= %00100000 +const byte BTN_D= %01000000 +const byte BTN_U= %10000000 + +inline void read_joy1() { + reset_joy() + if JOYSTICK & BTN_U != 0 { input_dy += 1 } + if JOYSTICK & BTN_D != 0 { input_dy -= 1 } + if JOYSTICK & BTN_R != 0 { input_dx += 1 } + if JOYSTICK & BTN_L != 0 { input_dx -= 1 } + + if JOYSTICK & BTN_A != 0 { input_btn |= 1 } + if JOYSTICK & BTN_B != 0 { input_btn |= 2 } +} + +void lynx_init() { + // vid memory to the furthest point from code + // right at the top of ram + DISPADR=$dc00 + VIDBASE=$dc00 + COLLBASE=$bc00 + // reset Horizontal and Vertical offset regs + HOFF = 0 + VOFF = 0 + // suzy and display + SPRSYS = 0 + SPRINT = $f3 + DISPCTRL = DISPLAY_COLOR | DISPLAY_4bpp | DISPLAY_ENABLE + SUZYBUSEN = 1 + // set 60hz display + TIMER0_reload=$9e + TIMER0_ctrl=$18 + TIMER2_reload=$68 + TIMER2_ctrl=$1f +// TIMER2_ctrl = %11011000 + PBKUP=$29 +} + +// wait for suzy to finish rendering +void lynx_wait_suzy() { + asm { +waitsuzy: + stz CPUSLEEP + lda SPRSYS + lsr + bcs waitsuzy + } +}