diff --git a/CHANGELOG.md b/CHANGELOG.md index cc25f0fc..10354e5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,12 +2,16 @@ ## Current version +* `sizeof` now supports arrays. + * Added `-R` option for specifying extra commandline parameters for emulators. * Added full 16-bit multiplication. * Added preliminary support for EasyFlash. +* Added preliminary support for Commander X16. + * Allowed defining custom output padding byte value. * Allowed passing non-decimal numbers to the `-D` option. diff --git a/docs/api/target-platforms.md b/docs/api/target-platforms.md index 4469ee37..a8f2b668 100644 --- a/docs/api/target-platforms.md +++ b/docs/api/target-platforms.md @@ -99,4 +99,7 @@ The compiler emits COM files. * `dos_com` – a COM file for DOS on IBM PC. (very experimental) +* `x16_experimental` – Commander X16; very experimental, +as both the target configuration *and* the device itself are in their experimental phases. + The primary and most tested platform is Commodore 64. diff --git a/docs/lang/preprocessor.md b/docs/lang/preprocessor.md index dcabc769..1c5e827b 100644 --- a/docs/lang/preprocessor.md +++ b/docs/lang/preprocessor.md @@ -84,7 +84,7 @@ See [the ROM vs RAM guide](../api/rom-vs-ram.md) for more information. * `WIDESCREEN` – 1 if the horizontal screen resolution, ignoring borders, is greater than 256, 0 otherwise -* `CBM` – 1 if the target is an 8-bit Commodore computer, 0 otherwise +* `CBM` – 1 if the target is an 8-bit Commodore computer (or a compatible one), 0 otherwise * `CBM_64_COMPAT` – 1 if the target is an 8-bit Commodore computer compatible with Commodore 64, 0 otherwise diff --git a/examples/README.md b/examples/README.md index 72f194f7..f2992a49 100644 --- a/examples/README.md +++ b/examples/README.md @@ -4,7 +4,7 @@ * [Hello world](crossplatform/hello_world.mfk) (C64/C16/PET/VIC-20/PET/Atari/Apple II/BBC Micro/ZX Spectrum/PC-88/Armstrad CPC/MSX) – simple text output -* [Fizzbuzz](crossplatform/fizzbuzz.mfk) (C64/C16/PET/VIC-20/PET/Atari/Apple II/BBC Micro/ZX Spectrum/PC-88/Armstrad CPC/MSX) – everyone's favourite programming task +* [Fizzbuzz](crossplatform/fizzbuzz.mfk) (C64/C16/PET/VIC-20/PET/Atari/Apple II/BBC Micro/ZX Spectrum/PC-88/Armstrad CPC/MSX/X16) – everyone's favourite programming task * [Fizzbuzz 2](crossplatform/fizzbuzz2.mfk) (C64/C16/PET/VIC-20/PET/Atari/Apple II/BBC Micro/ZX Spectrum/PC-88/Armstrad CPC/MSX) – an alternative, more extensible implemententation of fizzbuzz @@ -61,3 +61,9 @@ how to create a program made of multiple files loaded on demand * [Encoding test](msx/encoding_test.mfk) – text encoding test; displays three lines of text in three different languages, no more one of which will display correctly depending on the default font of your computer. + +# Commander X16 examples + +* [Palette](x16/palette.mfk) – displays the default 256-colour palette. + +* [Balls](x16/palette.mfk) – 16 sprites using 240 colours. diff --git a/examples/x16/balls.mfk b/examples/x16/balls.mfk new file mode 100644 index 00000000..09f5d23a --- /dev/null +++ b/examples/x16/balls.mfk @@ -0,0 +1,92 @@ +// the emulator supports only 16 sprites: +const byte SPRITE_COUNT = 16 +array(vera_sprite_data) sprites[SPRITE_COUNT] +array(sbyte) vx[SPRITE_COUNT] +array(sbyte) vy[SPRITE_COUNT] + +import random + +void main () { + pointer.vera_sprite_data p + + byte i,j + word x,y + init_rand_seed() + // make balls striped + for i,0,parallelto,$1f { + for j,1,parallelto,$f { + sprite_bitmap[nonet(j<<5) + i] *= j + } + } + for i,0,paralleluntil,SPRITE_COUNT { + p = sprites[i].pointer + // bitmap is at $10000: + p->address = $800 + p->x.lo = rand() + p->x.hi = rand() & 1 + p->y = rand() + // no collision, above all layers, no flipping + p->ctrl0 = $c + // 32×32 pixels, different palette offsets + p->ctrl1 = $a0 | (i & $f) + vx[i] = 1 - (rand() & 2) + vy[i] = 1 - (rand() & 2) + } + vera_upload_large($10000, sprite_bitmap.addr, sizeof(sprite_bitmap)) + vera_upload_large($40800, sprites.addr, sizeof(sprites)) + // enable sprites: + vera_poke($40020, 1) + while true { + for i,0,paralleluntil,SPRITE_COUNT { + p = sprites[i].pointer + x = p->x + y = p->y + x += vx[i] + y += vy[i] + p->x = x + p->y = y + if x == 0 { vx[i] = 1 } + if x >= 640-32 { vx[i] = 0-1 } + if y == 0 { vy[i] = 1 } + if y >= 480-32 { vy[i] = 0-1 } + } + vera_upload_large($40800, sprites.addr, sizeof(sprites)) + } +} + + +array sprite_bitmap = [ +$00,$00,$00,$00,$00,$00,$11,$11,$11,$11,$00,$00,$00,$00,$00,$00, +$00,$00,$00,$00,$01,$11,$11,$11,$11,$11,$11,$10,$00,$00,$00,$00, +$00,$00,$00,$01,$11,$11,$11,$11,$11,$11,$11,$11,$10,$00,$00,$00, +$00,$00,$00,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$00,$00,$00, +$00,$00,$01,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$10,$00,$00, +$00,$00,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$00,$00, +$00,$01,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$10,$00, +$00,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$00, +$00,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$00, +$01,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$10, +$01,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$10, +$01,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$10, +$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11, +$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11, +$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11, +$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11, +$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11, +$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11, +$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11, +$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11, +$01,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$10, +$01,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$10, +$01,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$10, +$00,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$00, +$00,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$00, +$00,$01,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$10,$00, +$00,$00,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$00,$00, +$00,$00,$01,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$10,$00,$00, +$00,$00,$00,$11,$11,$11,$11,$11,$11,$11,$11,$11,$11,$00,$00,$00, +$00,$00,$00,$01,$11,$11,$11,$11,$11,$11,$11,$11,$10,$00,$00,$00, +$00,$00,$00,$00,$01,$11,$11,$11,$11,$11,$11,$10,$00,$00,$00,$00, +$00,$00,$00,$00,$00,$00,$11,$11,$11,$11,$00,$00,$00,$00,$00,$00 +] + diff --git a/examples/x16/palette.mfk b/examples/x16/palette.mfk new file mode 100644 index 00000000..0c39ae2d --- /dev/null +++ b/examples/x16/palette.mfk @@ -0,0 +1,24 @@ +void main() { + word i + byte hn, ln + // 256-colour text mode for layer 0 + vera_poke($40000, $21) + // 8×8 tiles, 64×64 tile map + vera_poke($40001, $35) + // 2× zoom in + vera_poke($40041, $40) + vera_poke($40042, $40) + i = 0 + while i < $2000 { + vera_poke(i, $A0) + if i.lo & $7f < 64 { + ln = lo(i>>1) & $1f + hn = lo(i>>2) & $e0 + vera_poke(i+1, hn | ln) + } else { + vera_poke(i+1, 0) + } + i += 2 + } + while true {} +} diff --git a/include/x16_experimental.ini b/include/x16_experimental.ini new file mode 100644 index 00000000..2938502d --- /dev/null +++ b/include/x16_experimental.ini @@ -0,0 +1,40 @@ +; Commander X16 +; VERY EXPERIMENTAL +; The device's haven't been completed yet, so this platform configuration may not run on the final device +; Use only for goofing around plz + +[compilation] +arch=cmos +encoding=petscii +screen_encoding=petscr +modules=loader_0801,c64_kernal,x16_hardware,c64_panic,stdlib + +[allocation] +; list of free zp pointer locations is the same as C64 +zp_pointers=$FB,$FD,$43,$45,$47,$4B,$F7,$F9,$9E,$9B,$3D +segments=default,himem0 +default_code_segment=default +segment_default_start=$80D +segment_default_codeend=$9eff +segment_default_datastart=after_code +segment_default_end=$9eff + +segment_himem0_start=$c000 +segment_himem0_codeend=$dfff +segment_himem0_datastart=after_code +segment_himem0_end=$dfff + +[define] +CBM=1 +WIDESCREEN=1 +KEYBOARD=1 +JOYSTICKS=0 +HAS_BITMAP_MODE=1 + +[output] +style=single +format=startaddr,allocated +extension=prg +labels=vice + + diff --git a/include/x16_hardware.mfk b/include/x16_hardware.mfk new file mode 100644 index 00000000..e1ae8d88 --- /dev/null +++ b/include/x16_hardware.mfk @@ -0,0 +1,103 @@ +// TODO: bankswitching + + +volatile byte vera_addr_hi @ $9f20 +volatile byte vera_addr_mi @ $9f21 +volatile byte vera_addr_lo @ $9f22 +volatile byte vera_data1 @ $9f23 +volatile byte vera_data2 @ $9f24 +volatile byte vera_ctrl @ $9f25 +volatile byte vera_ien @ $9f26 +volatile byte vera_isr @ $9f27 + +struct vera_layer_setup { + byte ctrl0 + byte ctrl1 + word map_base + word tile_base + word hscroll + word vscroll +} + +asm void set_vera_layer_internal(pointer.vera_layer_setup ax, byte y) { + sta __reg + stx __reg+1 + stz vera_ctrl + lda $14 + sta vera_addr_hi + stz vera_addr_mi + sty vera_addr_lo + ldy #0 + __set_layer_internal_loop: + lda (__reg),y + sta vera_data1 + iny + cpy #sizeof(vera_layer_setup) + bne __set_layer_internal_loop + ? rts +} + +asm void set_vera_layer0(pointer.vera_layer_setup ax) { + ? ldy #0 + ? jmp set_vera_layer_internal +} + +asm void set_vera_layer1(pointer.vera_layer_setup ax) { + ? ldy #0 + ? jmp set_vera_layer_internal +} + +inline void vera_poke(int24 address, byte value) { + vera_addr_lo = address.b0 + vera_addr_mi = address.b1 + vera_addr_hi = address.b2 + vera_ctrl = 0 + vera_data1 = value +} + +inline void vera_fill(int24 address, byte value, word size) { + word i + vera_addr_lo = address.b0 + vera_addr_mi = address.b1 + vera_addr_hi = address.b2 | $10 + vera_ctrl = 0 + for i,0,paralleluntil,size { + vera_data1 = value + } +} + +void vera_upload_large(int24 address, pointer source, word size) { + word i + vera_ctrl = 0 + vera_addr_lo = address.b0 + vera_addr_mi = address.b1 + vera_addr_hi = address.b2 | $10 + for i,0,paralleluntil,size { + vera_data1 = source[i] + } +} + +inline void vera_upload(int24 address, pointer source, byte size) { + byte i + vera_ctrl = 0 + vera_addr_lo = address.b0 + vera_addr_mi = address.b1 + vera_addr_hi = address.b2 | $10 + asm { + ? ldy #0 + __vera_upload_loop: + ? lda (__reg),y + ? sta vera_data1 + ? iny + ? cpy size + ? bne __vera_upload_loop + } +} + +struct vera_sprite_data { + word address + word x + word y + byte ctrl0 + byte ctrl1 +} diff --git a/src/main/scala/millfork/env/Environment.scala b/src/main/scala/millfork/env/Environment.scala index 90a13ffd..da4ff232 100644 --- a/src/main/scala/millfork/env/Environment.scala +++ b/src/main/scala/millfork/env/Environment.scala @@ -599,8 +599,8 @@ class Environment(val parent: Option[Environment], val prefix: String, val cpuFa case Some(thing) => thing match { case t: Type => t.size case v: Variable => v.typ.size - case a: InitializedArray => a.elementType.size * a.contents.length - case a: UninitializedArray => a.sizeInBytes + case a: MfArray => a.sizeInBytes + case ConstantThing(_, MemoryAddressConstant(a: MfArray), _) => a.sizeInBytes case x => log.error("Invalid parameter for expr: " + name) 1