Compare commits

..
2086 Commits
Author SHA1 Message Date
Irmen de Jong b2520db872 add compiler version in assembly file 2026-10-22 19:26:02 +02:00
Irmen de Jong ebe26d0cf9 Fix block alias 2026-10-22 19:08:36 +02:00
Irmen de Jong 63e2a45f09 Require explicit via for linked-list for loops 2026-10-20 01:42:39 +02:00
Irmen de Jong 6076b01f6d Require explicit via for linked-list for loops
Removes the header shorthand, extracts shared validation into
LinkedForLoopChecks.kt, fixes until-validation for pointer sentinels,
and updates docs/examples/tests.
2026-10-20 00:25:27 +02:00
Irmen de Jong d0bf2c3dcb fix doc build for RTD 2026-10-19 23:07:18 +02:00
Irmen de Jong d9bf6f090e antlr4 parser tweaks 2026-10-19 22:57:49 +02:00
Irmen de Jong e08a995067 amiga: get rid of local var address escape warnings 2026-10-19 22:49:03 +02:00
Irmen de Jong da2288db93 improved variable source line position 2026-10-19 22:16:53 +02:00
Irmen de Jong 31b5cddb96 apply new linked list iteration for loop syntax 2026-10-19 22:10:19 +02:00
Irmen de Jong 264b894909 Add linked-list for-loop iteration with via/until syntax 2026-10-19 21:59:56 +02:00
Irmen de Jong 09ae0c6322 Fix 6502 codegen for pointer-to-pointer struct field double-deref 2026-10-19 19:44:44 +02:00
Irmen de Jong 9ca5db3436 fix 6502 pointer deref clobbering bare pointer variable 2026-10-19 04:01:12 +02:00
Irmen de Jong 375214b5e3 Add emudbg library module for amiga500/amiga1200 targets
New Prog8 standard library module for emulator debug output on the Amiga
targets, targeting the Copperline emulator (with partial WinUAE support).
2026-10-19 01:29:04 +02:00
Irmen de Jong 1da37e4119 skill 2026-10-17 23:45:22 +02:00
Irmen de Jong 16f7d588a7 add '-emu2' for amiga targets, -emu now launches the actual 'copperline' emulator, -emu2 still launches vamos. 2026-10-17 14:01:03 +02:00
Irmen de Jong f6c8a3f2ed defer: keep static per-subroutine mask, fix m68k carry bug, document recursion limitation
Roll back the per-activation defer-mask change because its code/RAM cost
outweighed the benefit. The pending-defer state is again a single static
mask variable per subroutine.

Keep the m68k bugfix: the handler now tests each defer bit with
`mask & bit != 0` instead of `mask >>= 1; bcc`, because the `>>=` store
on m68k uses MOVE which clears carry before the branch can read it.

Document that recursive/mutually recursive subroutines containing defer
are not supported on stack-frame targets, and remove the recursion-sound
defer todo item.
2026-10-17 05:00:02 +02:00
Irmen de Jong 5619898113 reduce test memory footprint 2026-10-17 02:43:39 +02:00
Irmen de Jong ae0414631e fix compiler crash on peek/poke/popp used in the wrong statement/expression context
fixes #248
2026-10-17 02:27:51 +02:00
Irmen de Jong e3ca9ae4a8 Fix virtual target typed pop results 2026-10-17 02:12:17 +02:00
Irmen de Jong 38c60a2d75 harden AstWalker detached-subtree skipping and extract shared canSkipExplicitCmpi helper 2026-10-17 01:46:35 +02:00
Irmen de Jong 5e83c44300 fix wrong result for short-circuit boolean and/or on the virtual target 2026-10-17 01:43:08 +02:00
Irmen de Jong 99ff5768c5 fix compiler crash on 'not' combined with or/and in one expression
cherry-picked from v12 maintenance b71787a929
2026-10-17 01:18:09 +02:00
Irmen de Jong fba4bb5272 6502 codegen bug: subtraction with a register-clobbering right operand 2026-10-16 00:58:49 +02:00
Irmen de Jong 17322a08ec 6502 math: convert lerp/lerpw/interpolate/interpolatew to 6502 assembly 2026-10-16 00:07:46 +02:00
Irmen de Jong 06d2f9ebbe when->on..goto: calibrate the jump-table sizeLimit per target 2026-10-15 22:10:52 +02:00
Irmen de Jong 3a5f2c33ab when->on..goto: allow arbitrary choice bodies by generating labels and jump tables 2026-10-15 20:23:02 +02:00
Irmen de Jong d523ecd1e1 when->on..goto: synthesize a gap label so gapped value ranges also use jumpi tables instead of the compare chain 2026-10-15 04:57:02 +02:00
Irmen de Jong 159634a99f Fix m68k frame teardown for intra-subroutine dispatch 2026-10-15 04:29:33 +02:00
Irmen de Jong 55dcb45230 when->on..goto: let the else part be any body, not just a single goto
Only the value choices have to be goto's, since those become entries in the
jump table. The else is taken over verbatim as the on..goto's else part, so a
common `else -> { ... }` body no longer disqualifies the whole when.
2026-10-15 04:05:45 +02:00
Irmen de Jong de75342198 fix when->on..goto rewrite for signed-byte conditions and non-zero-based values. Also made it smarter to allow a nonzero start value index 2026-10-15 03:29:02 +02:00
Irmen de Jong 30d3b76787 LSP: extract more document symbols
SymbolExtractor now also emits symbols for enum members, struct
fields, aliases, subroutine parameters, local variables and labels,
and finds labels/declarations nested in control-flow bodies.
Also refresh the LSP feature list in the introduction docs.
2026-10-15 01:47:45 +02:00
Irmen de Jong 8bbe5bd209 label names hash numbers are now stable 2026-10-14 19:35:49 +02:00
Irmen de Jong da7ea294ef todo cleanup 2026-10-14 01:29:22 +02:00
Irmen de Jong 05d8acc4bb optimized VM initialization and update Mordant library to fix a FFM crash 2026-10-13 22:48:29 +02:00
Irmen de Jong 6cac707fd1 code cleanups 2026-10-13 22:40:19 +02:00
Irmen de Jong dea43c99bb m68k: remove word packed args plan doc 2026-10-13 21:42:57 +02:00
Irmen de Jong 0b902f06b5 m68k: word-packed stack argument slots 2026-10-13 21:37:43 +02:00
Irmen de Jong 733a3fb752 add missing helper routines doc 2026-10-13 17:49:31 +02:00
Irmen de Jong 460adb9e02 Remove Exec-specific for-loop over linked lists, disallow pointer as struct field name 2026-10-13 01:01:24 +02:00
Irmen de Jong 3c22dfc11a fix compiler crash on indexed reads/writes through ^^pointer struct fields 2026-10-13 00:45:21 +02:00
Irmen de Jong dfb3257c04 reserve the 'pointer' datatype name, it can no longer be used as a symbol name 2026-10-13 00:00:26 +02:00
Irmen de Jong 8bcd176746 fix invalid parsing of ^^pointer 2026-10-12 20:45:12 +02:00
Irmen de Jong fd3add76e4 rename amiga_gfx to easygfx 2026-10-11 14:39:37 +02:00
Irmen de Jong 4d0a7ff8bf added amiga/tictactoe example 2026-10-11 06:42:29 +02:00
Irmen de Jong e1f2faabe7 added diskfont.p8 2026-10-11 05:33:47 +02:00
Irmen de Jong 25bd60368a fix undefined symbol error 2026-10-11 03:23:49 +02:00
Irmen de Jong f61c1dc7ef fix mouse click offsets and aspect ratio 2026-10-11 02:41:42 +02:00
Irmen de Jong eda21a6ebf Fix in operator on arrays larger than 255 elements 2026-10-11 02:05:21 +02:00
Irmen de Jong c0267e37b0 added amiga_gfx module and amiga/gfxdemo example 2026-10-11 01:03:59 +02:00
Irmen de Jong 78f9df203c inline math trig routines 2026-10-10 20:46:10 +02:00
Irmen de Jong d3e10b4974 m68k: optimize log2 and gcd routines, added log2l 2026-10-10 19:36:04 +02:00
Irmen de Jong c4679bd8af m68k: optimize lerp/interpolate/CRC routines; add interpolatew 2026-10-10 18:28:12 +02:00
Irmen de Jong e7dfe79919 m68k: add log2, diff, lerp, interpolate, gcd and crc16/32; fix qemu68k word shifts and const-eval of log2/atan2 2026-10-10 17:49:29 +02:00
Irmen de Jong 31dbbc3fe1 m68k: implement bcd library routines 2026-10-10 15:41:32 +02:00
Irmen de Jong 55b7239553 improve skills 2026-10-10 14:19:38 +02:00
Irmen de Jong 5702e5aa2a 14.0-beta2 release 2026-10-10 13:25:11 +02:00
Irmen de Jong 592637856f m68k: cleaner recursive defer errors 2026-10-10 02:02:25 +02:00
Irmen de Jong 233ca21492 m68k: frameable inline asm, word-sized sys.exit, and sys.die alerts 2026-10-10 00:19:22 +02:00
Irmen de Jong 1a84616363 update skills 2026-10-09 20:06:56 +02:00
Irmen de Jong d32b70bb75 m68k: tear down frames on external conditional branches 2026-10-08 20:50:39 +02:00
Irmen de Jong 73241b0261 m68k: tear down frames before absolute jumps 2026-10-08 20:41:35 +02:00
Irmen de Jong e515dee561 m68k: suggest @shared for locals referenced from inline assembly 2026-10-08 19:08:27 +02:00
Irmen de Jong 3d78415088 better vm error for %asm 2026-10-08 04:37:19 +02:00
Irmen de Jong 0189903a63 m68k: pin @shared variables to static storage 2026-10-08 04:17:40 +02:00
Irmen de Jong 9c9552174e m68k: stackful coroutines fixed with per-task stacks, new %option noframe 2026-10-08 01:59:50 +02:00
Irmen de Jong be61d37fd1 update gradle wrapper 2026-10-08 00:30:07 +02:00
Irmen de Jong 70bb199e12 m68k: pop frame on jumps leaving subroutine; reject dispatch to subs with parameters 2026-10-07 23:46:48 +02:00
Irmen de Jong 09737187ad fix %jmptable crashes on expression and unqualified entries 2026-10-07 22:25:23 +02:00
Irmen de Jong de39533fba qemu68k: new recursive maze solver example 2026-10-07 19:06:16 +02:00
Irmen de Jong 8bc2b177a0 m68k: made textelite native recursion 2026-10-07 19:06:16 +02:00
Irmen de Jong 09eba995ae m68k: storing or returning the address of a variable in call stack frame is now an error 2026-10-07 19:06:16 +02:00
Irmen de Jong b739d7b663 m68k: print call arg names in asm comments 2026-10-07 19:06:16 +02:00
Irmen de Jong 5e709fca7e m68k: stack-frame zero-clear coalescing 2026-10-07 19:06:16 +02:00
Irmen de Jong cc8df33418 m68k: plan for optimized stack frame zeroing 2026-10-07 19:06:16 +02:00
Irmen de Jong 125af552ff amiga: added recursive fractal-tree example 2026-10-07 19:06:16 +02:00
Irmen de Jong 29254e892b m68k: no longer print recursion warnings 2026-10-07 19:06:16 +02:00
Irmen de Jong a1a48405b0 m68k: fix a5 frame pointer register clobbering 2026-10-07 19:06:16 +02:00
Irmen de Jong acc8705ea8 bugfix for m68k stack memory model 2026-10-07 19:06:16 +02:00
Irmen de Jong bbff472457 doc cleanup 2026-10-07 19:06:16 +02:00
Irmen de Jong 353b0c84b7 slice 5 for m68k stack memory model
(slice 4 was skipped)
2026-10-07 19:06:16 +02:00
Irmen de Jong 329b3df4a3 slice 3 for m68k stack memory model 2026-10-07 19:06:16 +02:00
Irmen de Jong fe90ca572d slice 2 for m68k stack mememory model 2026-10-07 19:06:16 +02:00
Irmen de Jong 26bbd6c1fe vertical slice prototype for m68k stack mememory model 2026-10-07 19:06:16 +02:00
Irmen de Jong 822cfd4f35 tweak textelite 2026-10-07 02:24:17 +02:00
Irmen de Jong 0807d07ee5 cleanups 2026-10-07 02:00:31 +02:00
Irmen de Jong 2e3aa76a2f m68k: improve subroutine inlining 2026-10-07 01:17:14 +02:00
Irmen de Jong 3beb565c84 m68k targets: add sys.stack_size() function that gives remaining stack size in bytes 2026-10-07 00:39:11 +02:00
Irmen de Jong b1642f4f7a m68k: fix some subtle memset/memclear errors 2026-10-06 22:28:40 +02:00
Irmen de Jong 1f8b42fae5 make user docs and some code comments less convoluted 2026-10-05 20:00:32 +02:00
Irmen de Jong 13828ea932 fix defer stack-save ordering for multi-value returns 2026-10-04 07:55:51 +02:00
Irmen de Jong e550143ed0 amiga: added dos.read_file helper routine to read complete files 2026-10-04 04:46:33 +02:00
Irmen de Jong 47e6066a36 fix sizeof for large structs 2026-10-04 04:44:08 +02:00
Irmen de Jong 266f4ab380 amiga: fixed lowlevel-timer example 2026-10-04 02:53:35 +02:00
Irmen de Jong e5954542dd mention stack alignment rule in m68k skill 2026-10-04 02:31:23 +02:00
Irmen de Jong 8c2bc15b41 Fix IR peephole crash on lsigb.l + ext.b with mismatched register types
regression was introduced in commit 2ce7a63c1e
2026-10-03 14:01:56 +02:00
Irmen de Jong c9a7dc05d9 better error message 2026-10-03 02:08:57 +02:00
Irmen de Jong 9d023c9568 fix .p8ir file system case (in)sensitivity fragility 2026-10-02 23:41:42 +02:00
Irmen de Jong a1ce45e409 doc updates 2026-10-02 23:24:07 +02:00
Irmen de Jong 09d469714b whole enum aliasing (by aliasing each member) 2026-10-02 22:53:25 +02:00
Irmen de Jong 38db571f20 implemented -o / --output to specify specific output file 2026-10-02 22:33:43 +02:00
Irmen de Jong 5f3b587af1 docs
outputfile todo
2026-10-02 21:28:18 +02:00
Irmen de Jong e74c34a5ab fix builtins rejecting a cx16 virtual register as their result register 2026-10-01 02:54:53 +02:00
Irmen de Jong 2b156ec652 amiga: add lowlevel.library timer example 2026-09-30 22:56:29 +02:00
Irmen de Jong e38f71fd2d keep routines referenced from struct instance initializers, so that unusedcoderemover doesn't strip them 2026-09-30 21:33:26 +02:00
Irmen de Jong 6c107379df fix broken struct-array initializer prefixing for address-of arguments
fixes #246
2026-09-30 21:15:32 +02:00
Irmen de Jong 99f29cb9b9 fix broken min/max rewrite when the target aliases an operand.
fixes #247
2026-09-30 21:15:32 +02:00
Irmen de Jong d6ea0782e2 amiga: added lowlevel.library support 2026-09-30 19:23:32 +02:00
Irmen de Jong bdee93dc8f eliminate redundant lea for repeated indexed array access 2026-09-28 21:51:03 +02:00
Irmen de Jong 3d675a460e don't fold signed division by a power of two into a shift 2026-09-28 21:22:01 +02:00
Irmen de Jong bd1747926c slightly optimize long multiplication 2026-09-28 02:29:25 +02:00
Irmen de Jong cff7732189 fix unsound index-reload peephole and extend it to two indexed accesses 2026-09-28 00:48:00 +02:00
Irmen de Jong fa966086e9 corrections 2026-09-28 00:39:57 +02:00
Irmen de Jong ec4b47ac0d support custom m68k targets: select the codegen by CpuType and allow a per-target link.ld 2026-09-27 11:50:33 +02:00
Irmen de Jong 5222562493 move sqr range check into prog8_math.square instead of inlining it at each call site 2026-09-27 11:49:49 +02:00
Irmen de Jong c8cda7947a 6502 optimization for uword * ubyte 2026-09-26 05:15:41 +02:00
Irmen de Jong ffe855f295 x*x correctness fix 2026-09-26 04:57:40 +02:00
Irmen de Jong 8a66dabf6d adjust benchmark weights and bump benchmark version number 2026-09-26 04:49:28 +02:00
Irmen de Jong b8c975704a 6502 byte shift optimization for const multiplications 2026-09-26 03:25:25 +02:00
Irmen de Jong 2ef0ddd42c 6502 word shift optimization for const multiplications 2026-09-26 02:45:57 +02:00
Irmen de Jong 9a83b7455a possible 6502 codegen optimization opportunities 2026-09-25 23:58:59 +02:00
Irmen de Jong 9fce07565c some romable tests, fix romable callfar crash and update stale VM label address test 2026-09-25 22:40:36 +02:00
Irmen de Jong d703d678b4 fix VM label-valued initializers 2026-09-25 02:22:19 +02:00
Irmen de Jong 90a7c41586 fix IR symbol prefixing 2026-09-25 02:04:43 +02:00
Irmen de Jong b1a9ba929d remove ARRAY_POINTER and make pointer arrays target-independent 2026-09-25 01:18:32 +02:00
Irmen de Jong 75ab3ccfbd amiga1200: added ahi library and demo programs 2026-09-25 00:03:50 +02:00
Irmen de Jong c031737da0 fixup docs about amiga targets (missing amiga1200 mostly) 2026-09-24 22:31:03 +02:00
Irmen de Jong 2f905ef6b6 update reg design 2026-09-24 01:23:33 +02:00
Irmen de Jong 4cbf93da85 fix Status flag extraction clobbers a register return value 2026-09-24 01:00:49 +02:00
Irmen de Jong 976b64185d fix struct size truncation to 256 bytes on targets that allow larger structs (m68k) 2026-09-24 00:22:23 +02:00
Irmen de Jong 2050fcb4ee m68k: emit struct field definitions in the asm 2026-09-23 23:55:57 +02:00
Irmen de Jong 69525ae67f 6502 codegen: emit _size symbol for struct and union memory size 2026-09-23 23:14:11 +02:00
Irmen de Jong 4eaba62f1e 6502 codegen: inline clamp() on word/uword when having compile-time constant bounds 2026-09-23 22:54:57 +02:00
Irmen de Jong bf696bcf5e fix multiple status flag returns in new codegens 2026-09-23 03:10:59 +02:00
Irmen de Jong 34bbb46514 fix a few new6502 codegen bugs 2026-09-23 01:27:40 +02:00
Irmen de Jong f086918e6f add union types: structs where every field is at offset 0, thus saving memory 2026-09-23 00:07:44 +02:00
Irmen de Jong 521f7ffbe6 tweak amiga audio 2026-09-22 22:49:09 +02:00
Irmen de Jong 2d070aaec4 Fix 6502 pointer-field augmented assignment clobbering scratch pointer
Fixes #245
2026-09-21 22:51:11 +02:00
Irmen de Jong 044a4a1789 amiga: added trackdisk device support 2026-09-21 00:13:17 +02:00
Irmen de Jong 6de6a81d4b amiga: added asyncio.library support 2026-09-20 05:12:10 +02:00
Irmen de Jong 815f4109a5 cx16/gfx_lores: optimize text() by setting VERA address once per character 2026-09-19 22:06:05 +02:00
Irmen de Jong a49f080ca7 cx16/gfx_hires: optimize text() by hoisting color dispatch and using local tables 2026-09-19 19:04:20 +02:00
Irmen de Jong ac4ae0440f vera64 restructure 2026-09-19 17:50:30 +02:00
Irmen de Jong 773f1f2292 more vera64 code 2026-09-19 16:25:52 +02:00
Irmen de Jong efee8bde68 added preliminary VERA64 support library for the c64 target
vera64 = a board for the c64 containing a VERA graphics adapter
2026-09-19 00:14:11 +02:00
Irmen de Jong ddfdd9097d fix adpcm private symbols 2026-09-18 22:40:59 +02:00
Irmen de Jong ef64e2f9a4 fix typed pointer arithmetic p2-p1 to yield the number of elements. fixes #244 2026-09-18 21:22:07 +02:00
Irmen de Jong 2f6ab002d8 amiga: adpcmbench, m68k adpcm decoder optimized further, fix wavc output byte order format 2026-09-18 03:46:00 +02:00
Irmen de Jong ba76fbfe85 fix code generation for "return <void function call>" 2026-09-17 22:39:53 +02:00
Irmen de Jong 7f3b2e8aa6 m68k asm versions of adpcm decoder routines, now byte at a time instead of nibble 2026-09-17 21:53:13 +02:00
Irmen de Jong f254fc2b62 m68k asm versions of adpcm decoder routines 2026-09-17 02:53:48 +02:00
Irmen de Jong 457d55b392 fix potential endless loop in wavfile library, also made a correct implementation of it for m68k targets (little/big endianness problem resolved) 2026-09-17 00:04:34 +02:00
Irmen de Jong b21a984dbb even more optimized adpcm decoding routine 2026-09-16 19:04:49 +02:00
Irmen de Jong 7427e6ddad changed adpcm decoder by a table driven one, almost twice as fast now 2026-09-16 05:03:13 +02:00
Irmen de Jong 192e0086f9 update plans 2026-09-16 00:52:40 +02:00
Irmen de Jong c8972c9561 add jdk option --enable-native-access=ALL-UNNAMED to manifest and launcher scripts to suppress newer JDK warning about JNI/JNA calling native libraries 2026-09-14 23:10:12 +02:00
Irmen de Jong 7ba2ee9857 added named struct field initializers 2026-09-14 00:56:22 +02:00
Irmen de Jong a025d68291 added %assert expression, "message" 2026-09-13 23:04:56 +02:00
Irmen de Jong 81794aded3 use Mordant library to make some terminal output more sophisticated
this library is already used by the Clikt option parser library so no new dependency
2026-09-13 21:28:32 +02:00
Irmen de Jong 9621552056 add 'arena' allocator library
6502 targets use uword sizes with no alignment overhead; m68k/virtual use
long sizes with even-address alignment. Updated the six pointer examples that used to have their own arena implementation.
2026-09-13 05:43:57 +02:00
Irmen de Jong 5685a1f229 6502: tighter for loop code for word and long loop vars 2026-09-13 04:29:59 +02:00
Irmen de Jong b014c78c94 m68k: better error when trying to use cx16 virtual register, those don't exist anymore 2026-09-13 04:28:25 +02:00
Irmen de Jong ca729d279e update history and syntax files 2026-09-12 23:14:50 +02:00
Irmen de Jong 3b0faa749a Merge branch 'master' into structured-IR
Port end-exclusive for-loop codegen and M4 loop-counter peephole to the
structured operand API (IRInstructions factories, memory?.symbolName,
labelTarget, requireDest/requireSrcA).
2026-09-12 00:48:30 +02:00
Irmen de Jong 22a2f8cbc5 IR: end-exclusive increment+compare for step +-1 for-loops; fix DECM/BSTPOS on VM 2026-09-12 00:07:02 +02:00
Irmen de Jong 468850bc47 structured IR 2026-09-11 20:20:40 +02:00
Irmen de Jong 20374f4059 Merge branch 'v12maintenance'
# Conflicts:
#	compilerAst/src/prog8/ast/antlr/Antlr2KotlinVisitor.kt
#	compilerAst/src/prog8/ast/statements/AstStatements.kt
#	examples/test.p8
2026-09-11 19:37:10 +02:00
Irmen de Jong ceffa4d83d todos 2026-09-11 19:25:43 +02:00
Irmen de Jong af14562e2b allow struct field array sizes to be constant expressions
fixes #240
2026-09-11 01:38:18 +02:00
Irmen de Jong dbba6a94fa Merge branch 'v12maintenance'
# Conflicts:
#	codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt
#	compiler/src/prog8/compiler/astprocessing/AstIdentifiersChecker.kt
#	compiler/test/ast/TestVariousCompilerAst.kt
#	compiler/test/codegeneration/TestExecution6502.kt
#	examples/test.p8
#	gradle.properties
2026-09-10 21:45:47 +02:00
Irmen de Jong 302e4bdf8e m68k targets are experimental not for production code use 2026-09-10 20:41:00 +02:00
Irmen de Jong ccc26a0eb2 Fix alias targets to enum members
Defer alias error reporting when the target is a not-yet-desugared
enum member. Also reject aliases that target an enum itself.

fixes #239
2026-09-10 19:20:02 +02:00
Irmen de Jong e017c541bb proper error message when using a builtin function name as block name. Also for some keywords if the parser allows. Fixes #236 2026-09-10 19:20:02 +02:00
Irmen de Jong 3d5a7795d0 make set of keywords (for name restriction test) dynamic 2026-09-10 19:20:02 +02:00
Irmen de Jong af06fdfffc fix more 6502-only struct pointer-field bugs; add indexed in-place support
fixes #237
2026-09-10 19:20:02 +02:00
Irmen de Jong e811ecdbde fix 6502 struct pointer-field array indexing 2026-09-09 23:47:09 +02:00
Irmen de Jong 4c65049817 proper error message when using a builtin function name as block name 2026-09-09 04:05:31 +02:00
Irmen de Jong a7cbc2c5bf Review fixes: pointer read desugaring and poke->assignment optimizer 2026-09-09 02:31:21 +02:00
Irmen de Jong d51ca62431 Fix poke->assignment optimizer dropping AddressOf index
StatementOptimizer rewrote pokel(&arena[1], x) to arena = x, ignoring
AddressOf.arrayIndex (and dereference), which miscompiled implicit
indexed-base struct field writes such as arena[1].s = X. All four
poke/pokew/pokel/pokef rewrites now require a plain variable address.
2026-09-09 02:05:20 +02:00
Irmen de Jong 9ac60eec40 fix some more pointer syntax related issues 2026-09-09 01:33:43 +02:00
Irmen de Jong c55b16f4cb todo 2026-09-09 01:01:16 +02:00
Irmen de Jong bd0457f262 Allow const expressions for 2D array dimensions (not just numeric literals) 2026-09-08 23:13:54 +02:00
Irmen de Jong ce2b298d6f code cleanups 2026-09-08 22:36:54 +02:00
Irmen de Jong cf7afaf77a update libraries, update to kotlin 2.4.20 2026-09-08 21:41:53 +02:00
Irmen de Jong 54507ad9b3 Merge branch 'v12maintenance'
# Conflicts:
#	gradle.properties
2026-09-07 19:19:52 +02:00
Irmen de Jong 30435b6778 version 12.3.3 2026-09-07 19:18:15 +02:00
Irmen de Jong 619a215a87 fix test size expectation 2026-09-07 19:14:58 +02:00
Irmen de Jong c12e27dacc cx16: added verafx-accelerated line routine, added cobramk3 example that uses it next to the cpu only version 2026-09-06 22:51:12 +02:00
Irmen de Jong db32b81d7a m68k: d0 caching 2026-09-06 20:32:16 +02:00
Irmen de Jong 687d86d36e added amiga1200 target (68020 + FPU) 2026-09-06 18:25:15 +02:00
Irmen de Jong e074fe614f avoid extremely long array data source lines, and redundant label comments 2026-09-06 16:18:31 +02:00
Irmen de Jong bbfb09e467 IR: uniform traversal 2026-09-05 00:06:30 +02:00
Irmen de Jong 1358a535e3 Fix inliner crash when inlining a sub that assigns to its own parameter
Also error on a variable declaration directly followed by another statement on the same line.

fixes #235
2026-09-04 22:13:11 +02:00
Irmen de Jong bc62b2de81 IR: fix CONCAT register direction 2026-09-04 19:42:31 +02:00
Irmen de Jong 58f544fe14 Implement counted-loop IR (IRLoopChunk)
Replace the early lowering of constant repeat/for loops into p8_regfile
counter sequences with a first-class IRLoopChunk that carries the trip
count and body. This removes the fragile REGFILE-DEPENDENT m68k dbra
peephole and gives each backend explicit control.
2026-09-04 00:01:00 +02:00
Irmen de Jong 7dc05688bf Add peephole optimization to fold array[variable+const] index offsets
Adds three new passes to the 6502 assembly optimizer:

- optimizeFoldIndexOffset (byte/bool arrays)
- optimizeFoldIndexOffsetSplitWord (split word arrays)
- optimizeFoldIndexOffsetNonSplitWord (@nosplit word arrays)

fixes github issue #234
2026-09-03 21:36:29 +02:00
Irmen de Jong aac7d409dc split AssignmentAsmGen into 3 helper objects to reduce massive file size 2026-09-03 03:39:29 +02:00
Irmen de Jong 0771105694 fix sorting module on virtual target 2026-09-03 03:39:07 +02:00
Irmen de Jong 9a461628f2 Merge branch 'v12maintenance' 2026-09-02 19:14:57 +02:00
Irmen de Jong c8f309307f fix inlining bug: subroutines with register-mapped parameters cannot be inlined 2026-09-02 19:10:21 +02:00
Irmen de Jong b702ea50da no longer mangle inline asm that uses pipe operator (in other spots that is used as an instruction separator...) 2026-09-02 02:02:53 +02:00
Irmen de Jong b0f1f655c3 codeGenIntermediate: fold struct-array field access to single LOADX/STOREX
Replace arr[idx].field (arr:Struct[Sz], idx variable) from
EXT+MUL #Sz + ADDR + ADD #fieldOff + LOADI/STOREI (5 ops) to
single indexed op: LOADX/STOREX arr+fieldOff,S=Sz and
STOREZX for zero. Reuses existing ,S=N + +off encoding.
2026-09-02 01:35:30 +02:00
Irmen de Jong 59c41ad129 ir: add scaled indexing (S=) to LOADX/STOREX/STOREZX
Remove byte-offset pre-scaling from IR generation and encode
element index + explicit scale in the IR.  Effective address is
base + index*scale + disp (disp = symbolOffset).
2026-09-02 00:34:23 +02:00
Irmen de Jong 60eeaba791 streamline IR optimization proposals 2026-09-01 23:15:03 +02:00
Irmen de Jong 30266c1b92 Merge branch 'v12maintenance'
# Conflicts:
#	gradle.properties
2026-09-01 22:22:39 +02:00
Irmen de Jong 05ba1237dc fix %asm line grouping that tripped the asm optimizer to think stuff was one line where it wasn't 2026-09-01 22:04:33 +02:00
Irmen de Jong 9d537ab3c0 warn when %zpreserve/%zpallowed excludes fixed zeropage scratch locations 2026-09-01 04:21:49 +02:00
Irmen de Jong 1ba08ec6ec make -dumpvars work on all compilation targets 2026-09-01 03:51:13 +02:00
Irmen de Jong 199c3e4efb Merge branch 'new-codegens' 2026-08-30 23:54:10 +02:00
Irmen de Jong a7c035f4d1 attempt to fix github runner OOM 2026-08-30 23:44:05 +02:00
Irmen de Jong 05cbe74a60 attempt to fix github runner OOM 2026-08-30 23:04:47 +02:00
Irmen de Jong d652d7a924 Merge branch 'new-codegens'
# Conflicts:
#	gradle.properties
2026-08-30 22:47:38 +02:00
Irmen de Jong 739fb6dc42 release 12.3.2 2026-08-30 22:39:01 +02:00
Irmen de Jong 9c53791ef4 m68k: optimize small memcopies to inline copy 2026-08-30 21:35:48 +02:00
Irmen de Jong 420a9b7249 m68k: optimize load of constant args into CPU registers for subroutine call 2026-08-30 19:20:12 +02:00
Irmen de Jong 9bf8318b1c Support arrays of struct instances
- Parser: parse `StructType[N] var` via elementToArray() for
  STRUCT_INSTANCE (Prog8ANTLR.g4, Antlr2KotlinVisitor)
- Desugar: struct-instance bases via addressOfStructInstance(),
  whole-struct `a[i]=a[j]` -> sys.memcopy, inferred `[[...]]`
  and explicit `Struct : [...]` (without ^^) for value arrays;
  reject `^^Struct : [...]` in instance arrays
- 6502: computeStructArrayElementAddress() with 16-bit
  index*structSize scaling (AssignmentAsmGen, AsmGen)
- IR/VM/m68k/new6502: STRUCTDEFS round-trip, loaders, gens
- AstChecker/IdentifiersChecker: reject struct fields that are
  arrays of structs; fix isArray guards
- Docs: structpointers.rst/variables.rst, todo.rst, examples/test.p8
- Tests: TestArraysOfStructs (pointer vs value init, IR round-trip,
  16-bit strides)
2026-08-30 18:24:14 +02:00
Irmen de Jong 94822b8662 Add arrays of struct instances (StructType[N] vars)
Parser: accept `Type[N] name` between type and identifier
(Prog8ANTLR.g4, Antlr2KotlinVisitor) via elementToArray()
for STRUCT_INSTANCE; CodeDesugarer: handle struct-instance
bases, addressOfStructInstance(), whole-struct memcopy
(points[a]=points[b]), and fix variable-index 16-bit scaling
in 6502 AssignmentAsmGen.computeStructArrayElementAddress();
IR: preserve STRUCTDEFS round-trip, VM loader support;
m68k/new6502/intermediate backends; docs + todo updated.
Limitations: not as struct fields (AstChecker/
AstIdentifiersChecker error) nor as sub params.
2026-08-30 14:14:49 +02:00
Irmen de Jong b0d50c2a68 preserve block comments in compiler AST and AST output 2026-08-30 02:33:30 +02:00
Irmen de Jong deae2e6422 Unify variable and memory slab relocation with vars address configuration 2026-08-29 01:17:44 +02:00
Irmen de Jong c8d29e6dc9 ir: more IR peephole optimizations 2026-08-29 00:29:50 +02:00
Irmen de Jong a7b14c2931 ir: more optimized inplace array assignments 2026-08-28 23:38:54 +02:00
Irmen de Jong a14a8f4e62 ir: deduplicate index canonicalization and strengthen regression tests 2026-08-28 23:00:51 +02:00
Irmen de Jong cf50372515 ir: canonicalize LOADX/STOREX/STOREZX index width and remove guessed-type workaround 2026-08-28 22:23:55 +02:00
Irmen de Jong da0df8f133 amiga: use defer for resource freeing, change custom.grab_system and restore_system value storage so they are now regular subroutines instead of inline 2026-08-28 21:27:02 +02:00
Irmen de Jong 27070f31e8 Merge branch 'master' into new-codegens
# Conflicts:
#	codeCore/src/prog8/code/core/DataTypes.kt
#	docs/source/todo.rst
2026-08-28 05:23:30 +02:00
Irmen de Jong aa3f8e3038 fix daemon error 2026-08-28 05:14:12 +02:00
Irmen de Jong 277e9c09bb making defer program-wide: also unwinds at program exit()/return from start() 2026-08-28 05:10:09 +02:00
Irmen de Jong 70521ce301 amiga: fix modplay file close 2026-08-27 23:05:13 +02:00
Irmen de Jong 93b5faa038 m68k: revert LSIGB/LSIGW direct p8_regfile loads - caused code growth 2026-08-27 19:49:21 +02:00
Irmen de Jong f33814a594 m68k: fuse LOADX+JUMPI/CALLI in asm peephole and document %jmptable as 6502-only 2026-08-27 04:50:07 +02:00
Irmen de Jong 986ae35821 m68k: optimize LSIGB/LSIGW to direct p8_regfile byte loads 2026-08-27 03:29:56 +02:00
Irmen de Jong 937b520838 core: fix POINTER equalsSize target-aware for 32-bit 2026-08-27 03:15:57 +02:00
Irmen de Jong 250ddda11b ir,m68k: add LOADP_INC/STOREP_INC for pointer post-inc (a0)+ 2026-08-27 02:57:54 +02:00
Irmen de Jong bde52cc134 ir: fix byte->long/pointer extension for 32-bit targets (single-type EXTL) 2026-08-26 23:55:17 +02:00
Irmen de Jong 8e739febf0 ir: m68k status-flag fusion - skip redundant CMPI #0 on ops that set Z 2026-08-26 23:41:36 +02:00
Irmen de Jong 3fcb4b4262 ir: canonicalize LOADX index width, 2026-08-26 23:18:06 +02:00
Irmen de Jong 56643f43df tweak m68k tests and docs 2026-08-26 22:31:05 +02:00
Irmen de Jong a9cad9b51d fix some problems in several examples 2026-08-26 00:49:02 +02:00
Irmen de Jong 8647b136bd 6502: fix constant byte store via pointer+const offset storing garbage
fixes regression from commit 102992911
2026-08-25 23:59:41 +02:00
Irmen de Jong 4179f2c571 disable RMB-menus, doc updates 2026-08-25 03:31:15 +02:00
Irmen de Jong 02a118ec0e deref assignment targets: use target pointer width for address temps and IR casts 2026-08-24 23:38:45 +02:00
Irmen de Jong 561f31329d support pointer assignment targets like (expr as ^^Struct).field = v and func().field = v (grammar + CodeDesugarer poke desugar, IR pointer-cast widening, tests/docs) 2026-08-24 23:00:23 +02:00
Irmen de Jong 2bbbacc46e normal error message instead of crash when typed pointer arrays are used as struct field (currently not supported by the compiler) 2026-08-24 19:21:30 +02:00
Irmen de Jong c3920de251 update to new ksim65 version 2026-08-24 00:25:01 +02:00
Irmen de Jong 14bf07907b amiga: tweak modplay and ptplayer library to be able to supply playback feedback 2026-08-23 23:00:33 +02:00
Irmen de Jong c657935f10 m68k: fix passing 0 in m68k address register codegen 2026-08-23 22:30:50 +02:00
Irmen de Jong c08def79ae Merge branch 'master' into new-codegens 2026-08-23 21:04:23 +02:00
Irmen de Jong 296295011e Fix 6502 indexed pointer array store correctness bugs / missing code gen implementations 2026-08-23 20:54:32 +02:00
Irmen de Jong de20c09790 fix missing array bounds check for struct field arrays 2026-08-23 18:42:57 +02:00
Irmen de Jong 4199ab4200 fix broken unit test dependency on vasm 2026-08-23 16:07:27 +02:00
Irmen de Jong fe6850816c m68k: restore zero-extension for ADDR/SUBR widening and byte array indices
this broke in d978be2f9d
2026-08-23 15:34:17 +02:00
Irmen de Jong eff1a9fc53 m68k: loop dbra optimization 2026-08-23 14:58:44 +02:00
Irmen de Jong 5857382242 add %bssaddress and %slabsaddress directives to directly control the addresses of those segments 2026-08-23 14:16:06 +02:00
Irmen de Jong dfda43e747 more 6502 optimizations 2026-08-23 10:18:05 +02:00
Irmen de Jong 1029929111 6502 optimizations 2026-08-23 04:15:47 +02:00
Irmen de Jong ae55109a18 m68k: peepholes 2026-08-23 03:24:20 +02:00
Irmen de Jong 2ce7a63c1e IR: resolve loadx index-width type conflicts in usedRegisters; add conversion-collapse peephole 2026-08-23 02:41:12 +02:00
Irmen de Jong da6934ea33 m68k: prefer BSR/BRA over JSR/JMP 2026-08-23 01:09:15 +02:00
Irmen de Jong 2c8ccb706e added sfxgen library 2026-08-23 00:39:55 +02:00
Irmen de Jong 0d0d707976 Merge branch 'master' into new-codegens
# Conflicts:
#	simpleAst/src/prog8/code/ast/AstExpressions.kt
2026-08-23 00:25:27 +02:00
Irmen de Jong 4912c96f78 various codegen bug fixes 2026-08-23 00:12:12 +02:00
Irmen de Jong 79dd8d6b92 vm: rnd() is now identical to the xorshift algorithm of the other compilation targets
m68k: implemented clamp IR syscalls
new6502: implement EXTL
2026-08-22 22:29:41 +02:00
Irmen de Jong f750caa833 68k: fix vasm parse issue with .b, .l etc symbols -> now name-mangled 2026-08-22 21:46:16 +02:00
Irmen de Jong d17c978892 Merge branch 'master' into new-codegens
# Conflicts:
#	compiler/test/TestCompilerOnExamples.kt
#	examples/c64/cube3d.p8
#	examples/cube3d-gfx.p8
#	examples/cx16/cobramk3-gfx.p8
#	examples/cx16/cube3d.p8
2026-08-22 19:12:06 +02:00
Irmen de Jong 45cb50ebb1 fix crash on typecast of array element to long as operand of shift/add 2026-08-22 19:05:14 +02:00
Irmen de Jong 2cd2bb0121 optimized the 3d rotation examples 2026-08-22 19:03:14 +02:00
Irmen de Jong 5b890ac5d5 amiga: more strongly typed pointers in the library structs and routines 2026-08-22 18:23:01 +02:00
Irmen de Jong 894a3e90db codegen: fix pointer-typed struct field reads on 32-bit targets to use peekl and long address arithmetic 2026-08-22 12:40:34 +02:00
Irmen de Jong 234468690e resolve aliased/qualified struct types via StructTypeResolver with proper errors, infer for-loop node type in the list declaration's scope so imported module lists work, and fix 6502 codegen crash comparing against &struct.field 2026-08-21 23:00:00 +02:00
Irmen de Jong 5f50b254a2 rename list -> lists 2026-08-21 21:22:17 +02:00
Irmen de Jong c5b17ae880 finalize amiga audio routines 2026-08-21 21:08:28 +02:00
Irmen de Jong 4b320013cf Merge branch 'master' into new-codegens
# Conflicts:
#	codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/PointerAssignmentsGen.kt
#	compiler/test/TestPointers.kt
#	docs/source/todo.rst
#	examples/test.p8
2026-08-21 19:14:29 +02:00
Irmen de Jong f3de26bf6c for-loop support for list/node iteration, and reverse str/array iteration using step -1 2026-08-21 07:28:39 +02:00
Irmen de Jong 65a1300147 cpu6502: implement pointer inplace invert/negate (byte/word/long/float) 2026-08-21 01:33:43 +02:00
Irmen de Jong ba6179a4d3 fix crash and errors on parenthesized/casted struct pointer field access (e.g. (t.next).flag, (t.port as ^^Thing).flag) 2026-08-21 00:48:19 +02:00
Irmen de Jong 6b91a464c0 fix spelling errors 2026-08-20 23:55:26 +02:00
Irmen de Jong 08ac5eff3e amiga: forward sys.memcopy to exec.CopyMem 2026-08-20 23:46:34 +02:00
Irmen de Jong 7de39bbd62 amiga: fix audio.wait_all() 2026-08-20 23:28:19 +02:00
Irmen de Jong 198cf4d722 IR: fix for loop iteration overflow for 256 iters 2026-08-20 23:20:42 +02:00
Irmen de Jong b0b8513cb8 amiga.audio using static allocations 2026-08-20 23:19:08 +02:00
Irmen de Jong 82cc66c0cc fix amiga audio (needs BeginIO) 2026-08-20 20:15:33 +02:00
Irmen de Jong c81d9b25ac Merge branch 'master' into new-codegens
# Conflicts:
#	compiler/test/ast/TestConst.kt
#	docs/source/todo.rst
2026-08-18 23:52:02 +02:00
Irmen de Jong 3aab457a47 fix const evaluation type truncation error for bitwise operations between constants of different types 2026-08-18 23:48:06 +02:00
Irmen de Jong c89f870dd0 amiga: adding audio.p8 for audio.device support
but test program still doesn't produce any audible sound...
2026-08-18 23:42:17 +02:00
Irmen de Jong ffb0a4d603 amiga: custom now includes interrupt vector offset symbols, cpuVBR and isPAL (set in grab_system) 2026-08-18 22:07:13 +02:00
Irmen de Jong df659d285b optimize imports 2026-08-18 01:28:35 +02:00
Irmen de Jong 2c2664c91f Merge branch 'vm32bit' into new-codegens 2026-08-18 00:12:59 +02:00
Irmen de Jong e0147a4a7e fix hardcoded uword pointer-size assumptions for 32-bit targets 2026-08-18 00:09:10 +02:00
Irmen de Jong 859223c98b fix hardcoded uword pointer-size assumptions for 32-bit targets 2026-08-17 23:57:37 +02:00
Irmen de Jong 7bdb9bc853 Merge branch 'new-codegens' into vm32bit 2026-08-17 22:19:46 +02:00
Irmen de Jong 4e87aa6b85 m68k: preserve immediate loads for named call arguments 2026-08-17 22:19:03 +02:00
Irmen de Jong 02667e9916 fix str/long type comparison 2026-08-17 20:36:39 +02:00
Irmen de Jong 9d57cbe263 m68k: fix float sgn instruction format 2026-08-17 20:06:52 +02:00
Irmen de Jong 8b25ff2390 Merge branch 'master' into vm32bit 2026-08-17 04:08:23 +02:00
Irmen de Jong 2cb753caf8 fix floating point issue for IR syscalls and m68k codegen 2026-08-17 04:03:09 +02:00
Irmen de Jong 34f0bea4e8 fix pointer unit tests, consolidate pointer type selection for target 2026-08-17 03:30:17 +02:00
Irmen de Jong 82828606e6 removed some string routines from shared because virtual target versions now need a 32 bit compatible implementation 2026-08-17 01:39:31 +02:00
Irmen de Jong ae751c4af4 Merge branch 'new-codegens' into vm32bit 2026-08-16 23:41:35 +02:00
Irmen de Jong 51b98204e9 fix unit test build issue 2026-08-16 23:39:55 +02:00
Irmen de Jong 12f375e070 Merge branch 'new-codegens' into vm32bit
# Conflicts:
#	examples/test.p8
2026-08-16 23:28:39 +02:00
Irmen de Jong 54a1a0704a allow strings to be used to initialize arrays in struct instances 2026-08-16 23:25:41 +02:00
Irmen de Jong 08b4168311 IR: preserve floating point value precision in struct fields 2026-08-16 21:30:25 +02:00
Irmen de Jong 4fdd12929a vm: switched to m68k like 32 bits registers 2026-08-16 21:14:15 +02:00
Irmen de Jong cc4f27d121 vm: making VM 32 bit
work in progress: see vm32.md there are failing tests still
2026-08-16 19:49:28 +02:00
Irmen de Jong 61041f4502 m68k: now calls IR register type verifier properly 2026-08-16 18:07:42 +02:00
Irmen de Jong 673ed91ee3 pointer and float size moved to memsizer, fix memory size of pass-by-ref to properly be size of pointer 2026-08-16 16:13:42 +02:00
Irmen de Jong 65b6280618 fix string compares on 32 bits targets 2026-08-16 15:55:30 +02:00
Irmen de Jong e50e175522 amiga: fix negative LVO offsets in library calls in p8ir file 2026-08-16 14:34:35 +02:00
Irmen de Jong fa1ceab78f M68K codegen: extend immediate call-argument forwarding and dead-store removal to floating-point registers and `p8_fregfile`. 2026-08-16 08:08:02 +02:00
Irmen de Jong 7eab0278b3 Merge branch 'master' into new-codegens 2026-08-16 07:32:34 +02:00
Irmen de Jong 36b12e9897 fix uword double increment/decrement bug 2026-08-16 07:26:21 +02:00
Irmen de Jong 69eaaf29c4 amiga: added sys.arguments for any CLI argument string 2026-08-16 07:08:22 +02:00
Irmen de Jong 69def73f3f m68k: allow assigning string constant to long/pointer variable (to get its address) 2026-08-16 06:18:33 +02:00
Irmen de Jong 9c2d8541c3 cx16: fix invalid code in sys.restore_irq(). Fixes #233 2026-08-16 03:33:40 +02:00
Irmen de Jong 6c93254758 m68k assembly peephole optimizer 2026-08-16 01:58:17 +02:00
Irmen de Jong a68cdd13a6 IR: added EXTL and EXTLS opcodes to help with pointer math 2026-08-15 22:58:15 +02:00
Irmen de Jong 295dfada61 amiga: add custom.filter_on() and filter_off() 2026-08-15 22:56:42 +02:00
Irmen de Jong d978be2f9d m68k: remove needless 0-extensions 2026-08-15 19:48:30 +02:00
Irmen de Jong 0a4601721a docs 2026-08-15 19:22:37 +02:00
Irmen de Jong d870c39aa4 m68k: use moveq and movea for call argument loading, drop +0 offset
- use moveq for small immediate call args (bytes 128-255 map to signed -128..-1)
- use movea.l for pointer/long args into address registers, dropping +0 suffix
- loadPointerToA0 also emits movea.l without the redundant +0 offset
- update stale C64 multiplexer expected output size
2026-08-15 18:49:28 +02:00
Irmen de Jong 2b93efbb33 m68k: remove redundant 0-extension, optimize and fix MSB/LSB extraction 2026-08-15 18:21:16 +02:00
Irmen de Jong c563562a6f m68k: optimized indirect JSR/JMP on 68020+ 2026-08-15 16:49:54 +02:00
Irmen de Jong 92a0d3cb1b m68k: optimize MUL and DIV instructions 2026-08-15 16:39:01 +02:00
Irmen de Jong 21d45a0a90 m68k: optimize CMP instruction, fix % 2026-08-15 16:00:26 +02:00
Irmen de Jong c87afc03ef m68k: optimize function call arg loading for immediates 2026-08-15 15:31:43 +02:00
Irmen de Jong 8dc9c4d3c2 optimize agent skills 2026-08-14 22:33:20 +02:00
Irmen de Jong e264aff607 added amiga3d example, fixing amiga blitter routines 2026-08-14 19:39:58 +02:00
Irmen de Jong 9591aad814 improving the C64 sprite multiplexer 2026-08-14 02:54:09 +02:00
Irmen de Jong 3208ef1f1a fix custom.set_aga_color 2026-08-14 00:33:50 +02:00
Irmen de Jong 36fcfa6965 implemented unary operations through pointers 2026-08-13 23:45:24 +02:00
Irmen de Jong ba7bf3f4fe cache IRProgram.registersUsed() 2026-08-13 23:25:00 +02:00
Irmen de Jong fcc93b385d IR: implement array in place / and % 2026-08-13 23:13:53 +02:00
Irmen de Jong 4c6d9b8f5f even more IR peephole optimizations 2026-08-13 23:01:41 +02:00
Irmen de Jong 6a3ee52bd5 more IR peephole optimizations 2026-08-13 22:50:50 +02:00
Irmen de Jong 8dec449a1c get rid of Either 2026-08-13 22:40:51 +02:00
Irmen de Jong a09942254d migrate CLI argument parsing from the obsolete kotlinx-cli library to Clikt 2026-08-13 22:33:16 +02:00
Irmen de Jong d702ace09f add support for pointer sizes >2 to configurable targets 2026-08-13 22:23:47 +02:00
Irmen de Jong f011d3f100 new language feature: %option private_symbols, and public keyword - to manage visibility 2026-08-13 22:05:58 +02:00
Irmen de Jong e404530ba4 Merge branch 'master' into new-codegens
# Conflicts:
#	compiler/src/prog8/compiler/Compiler.kt
#	compiler/src/prog8/compiler/CompilerDaemon.kt
#	gradle.properties
2026-08-13 18:32:47 +02:00
Irmen de Jong 48da22866c simplify and fix daemon output messages once more 2026-08-12 23:48:28 +02:00
Irmen de Jong 2e529f8849 amiga: added copper and blitter modules and amigablitcop example 2026-08-12 22:59:42 +02:00
Irmen de Jong 79a5ddcdd8 amiga: fix custom chip register names and offsets 2026-08-12 02:33:24 +02:00
Irmen de Jong 7aecb8d6eb amiga: add floating point support (assumes 68020+ and a FPU to run) 2026-08-11 23:12:49 +02:00
Irmen de Jong 73768e1876 new syntax feature done 2026-08-11 21:45:56 +02:00
Irmen de Jong 3514bd61ab new syntax feature: const type can be omitted (defaults to long for integers now) 2026-08-11 21:27:07 +02:00
Irmen de Jong a7f60a571d m68k: fix byte/word index value type mismatch 2026-08-11 20:58:13 +02:00
Irmen de Jong 3705064157 m68k: moveq improvements 2026-08-11 06:25:25 +02:00
Irmen de Jong 208205faea step 4 to allow for loop 'step' to be variable not only const: various correctness 2026-08-11 06:17:34 +02:00
Irmen de Jong 5af6afef61 step 3 to allow for loop 'step' to be variable not only const: 6502 codegen 2026-08-11 05:29:55 +02:00
Irmen de Jong a5a535806b step 2 to allow for loop 'step' to be variable not only const: step type casting done earlier 2026-08-11 04:20:00 +02:00
Irmen de Jong d582c1edf6 step 1 to allow for loop 'step' to be variable not only const 2026-08-11 04:07:56 +02:00
Irmen de Jong 7275137782 update some amiga stuff 2026-08-11 00:15:13 +02:00
Irmen de Jong f11da0488a fix false recursion message 2026-08-10 21:49:41 +02:00
Irmen de Jong ed1abe7e6b allow (optional) explicit for loop variable type to override the inferred type 2026-08-10 21:20:37 +02:00
Irmen de Jong 4dedc27e5b release 12.3.1 2026-08-10 20:54:26 +02:00
Irmen de Jong e70a1ed403 fix STOREZX.BYTE register type determination on m68k targets
STOREZX uses reg1 as the index register (not the value register),
so it should return indexRegType (WORD on 32-bit targets) regardless
of the instruction type. The code handled this for FLOAT/WORD/LONG
but missed the BYTE type case, causing register type conflicts
when indexing arrays with uword variables on m68k targets.
2026-08-09 23:18:46 +02:00
Irmen de Jong c53e72c5b2 Merge branch 'master' into new-codegens
# Conflicts:
#	compiler/test/TestCompilerOnExamples.kt
2026-08-09 23:05:04 +02:00
Irmen de Jong 5ba494c5e5 fix IR codegen needing explicit CMP instructions because of changed status bits contract (see commit #19238cc36) 2026-08-09 22:36:39 +02:00
Irmen de Jong b353904d30 fix for loop index register type issue in IR on m68k targets 2026-08-09 21:57:22 +02:00
Irmen de Jong a58a643d0d fixing unit test 2026-08-09 19:10:35 +02:00
Irmen de Jong 823ecfac6f add amiga ptplayer module (protracker module player) 2026-08-09 18:28:11 +02:00
Irmen de Jong 22035077af clean up for loop vardecls in examples 2026-08-09 17:05:34 +02:00
Irmen de Jong da8c3eda92 new language feature: implicit for loop variable declaration 2026-08-09 14:49:19 +02:00
Irmen de Jong 41c2b9c039 fix bit shift code for shifts by 16/32 bits or more 2026-08-09 14:26:45 +02:00
Recoordinate 5c16ebe377 Fix typo in comment (#232) 2026-08-09 12:35:32 +02:00
Irmen de Jong c7e25e323a some script fixes and izx0 image format 2026-08-09 12:26:59 +02:00
Irmen de Jong 1e2fc4d6f9 fix unit test on github hopefully 2026-08-09 00:48:43 +02:00
Irmen de Jong b5dfc0cd97 fix debug message and tests 2026-08-09 00:32:58 +02:00
Irmen de Jong 799486eb1b Merge branch 'master' into new-codegens 2026-08-09 00:23:23 +02:00
Irmen de Jong ed67a259de m68k: added compression module with ZX0 decompressor 2026-08-09 00:22:58 +02:00
Irmen de Jong d276fb9ed5 fix the overdraw in filled disc drawing routines 2026-08-09 00:20:22 +02:00
Irmen de Jong e0329e4457 added amiga iff load example 2026-08-08 22:13:53 +02:00
Irmen de Jong a3161fa117 implemented endian-aware msb/lsb handling 2026-08-08 19:34:12 +02:00
Irmen de Jong 9c8e81b566 IR: fix m68k indexing datatype size 2026-08-08 18:14:30 +02:00
Irmen de Jong e2e72a1791 Merge branch 'master' into new-codegens
# Conflicts:
#	compiler/src/prog8/CompilerMain.kt
2026-08-08 16:45:49 +02:00
Irmen de Jong ec9567a669 fix error output text in daemon mode 2026-08-08 16:44:43 +02:00
Irmen de Jong b3b983c7ec fix untyped pointer indexing on 32 bits targets (long vs uword) 2026-08-08 16:01:28 +02:00
Irmen de Jong 14ae579f00 amiga: add iffparse library module 2026-08-08 14:57:07 +02:00
Irmen de Jong 45f48d2e88 amiga: added %option amiga_chipram in blocks to allocate them in CHIP ram (for sound and graphics data) 2026-08-08 02:01:04 +02:00
Irmen de Jong 8d6ed7712d fix ir block cleanup bug 2026-08-08 01:24:09 +02:00
Irmen de Jong eea185bb83 keep label at top of block instead of moving vardecls before it, IR: fix bug that removed labels in blocks without code 2026-08-08 01:06:42 +02:00
Irmen de Jong 99d28ae557 fix typecast error for certain long/word address-of 2026-08-08 00:47:43 +02:00
Irmen de Jong 528762d961 add amiga screen example 2026-08-07 23:49:12 +02:00
Irmen de Jong c6e9a45293 fix m68k floating point code generation (68020 + FPU required) 2026-08-07 22:40:44 +02:00
Irmen de Jong 6880bd2a05 prog8 coder skill 2026-08-07 21:43:08 +02:00
Irmen de Jong 7547fb7747 array and string size limit raised to 32K on m68k targets 2026-08-07 20:47:06 +02:00
Irmen de Jong ff0e922674 dumpsymbols no longer includes compiler daemon info messages 2026-08-07 19:33:05 +02:00
Irmen de Jong 71f66171c4 amiga: fix const types in generated library files 2026-08-07 19:32:33 +02:00
Irmen de Jong c1f76cf073 m68k: prog8 doesn't have to do BSS clearing itself, the exe loaders already do this for us automatically 2026-08-07 19:07:40 +02:00
Irmen de Jong c2d151920d new docs about register allocation 2026-08-07 17:43:46 +02:00
Irmen de Jong c916570abd m68k now has long mul and div on 68000, uses utility.library on amiga if available 2026-08-07 12:32:47 +02:00
Irmen de Jong bdab975d14 fix amiga library pointer params 2026-08-07 11:28:29 +02:00
Irmen de Jong 1693e4ff9c Merge branch 'refs/heads/master' into new-codegens
# Conflicts:
#	examples/test.p8
2026-08-06 23:34:07 +02:00
Irmen de Jong 70d81298c1 fix multi-value initializer error when in nested scope 2026-08-06 23:32:08 +02:00
Irmen de Jong 6bf304b67b amiga500: add arexx library, timer.device manually opened 2026-08-06 23:17:28 +02:00
Irmen de Jong a5978a913b m68k: added coroutines module 2026-08-06 22:08:59 +02:00
Irmen de Jong e528f0ccaa amiga500: update generated library modules 2026-08-06 20:35:55 +02:00
Irmen de Jong e5f488dcfb new6502: fix align and 0-assign into array 2026-08-06 20:13:42 +02:00
Irmen de Jong 1de1c10b41 IR: fix register type error when 0-assigning into an array 2026-08-06 19:44:52 +02:00
Irmen de Jong c47a6bde0e IR: fix register type error when 0-assigning into an array 2026-08-06 19:31:05 +02:00
Irmen de Jong b8d38eccca new6502: fix long comparisons and STZ on 6502 2026-08-06 19:08:09 +02:00
Irmen de Jong 4c2144eb0d m68k: optimized bit shifts 2026-08-05 19:08:30 +02:00
Irmen de Jong 68399e8370 m68k: optimized bit manipulations 2026-08-05 13:50:12 +02:00
Irmen de Jong 7b61b066e6 m68k: optimized branches 2026-08-05 13:31:07 +02:00
Irmen de Jong bd2a47fb54 m68k: added agent skill 2026-08-05 13:20:13 +02:00
Irmen de Jong 2521df21e7 m68k: optimize bitwise not and zero loads 2026-08-05 12:50:34 +02:00
Irmen de Jong ddb6b597d6 m68k: optimize bitwise ops 2026-08-05 12:38:19 +02:00
Irmen de Jong c24fc9e81d emit floats as dc.s 2026-08-05 12:12:49 +02:00
Irmen de Jong 68f0d2285f Merge branch 'master' into new-codegens
# Conflicts:
#	docs/source/_static/symboldumps/skeletons-c128.txt
#	docs/source/_static/symboldumps/skeletons-c64.txt
#	docs/source/_static/symboldumps/skeletons-cx16.txt
#	docs/source/_static/symboldumps/skeletons-pet32.txt
#	docs/source/_static/symboldumps/skeletons-virtual.txt
#	docs/source/compiling.rst
#	gradle.properties
2026-08-05 11:05:02 +02:00
Irmen de Jong 25f883bb85 fix dangling bullet in history list 2026-08-05 11:03:02 +02:00
Irmen de Jong adc6d6626a attempt to fix Windows library file import bug (InvalidPathException) 2026-08-05 10:34:52 +02:00
Irmen de Jong 90ff904b6e add doc about newcodegen 2026-08-05 03:45:14 +02:00
Irmen de Jong ba54601eab release 12.3 2026-08-05 03:25:32 +02:00
Irmen de Jong 9937990618 Merge branch 'master' into new-codegens
# Conflicts:
#	examples/test.p8
2026-08-05 03:20:14 +02:00
Irmen de Jong 1c71f702f4 fix invalid const-folding of certain strings char classification routines such as isupper() 2026-08-05 02:55:36 +02:00
Irmen de Jong 3d3c567ea6 fix memory-byte read sign extension error when the byte was signed 2026-08-05 02:54:59 +02:00
Irmen de Jong 539c75bbf6 fix expression operand swap bug when there are side effects 2026-08-05 02:51:37 +02:00
Irmen de Jong 2683b6388a update history 2026-08-05 02:40:30 +02:00
Irmen de Jong e007d127f0 IR: smarter handling of x<<16 and x>>16 if x is a long 2026-08-05 02:01:21 +02:00
Irmen de Jong e5d9609db1 IR: added new multi-bit shifting opcodes 2026-08-05 01:42:49 +02:00
Irmen de Jong 051f3809cd IR: improved add/sub of small const values 2026-08-05 00:10:09 +02:00
Irmen de Jong b5fd07bb91 IR: added STOREIM instruction for immediate store constant to memory 2026-08-04 23:11:07 +02:00
Irmen de Jong 4097d51514 IR: more efficient code for comparisons against constants 2026-08-04 22:28:59 +02:00
Irmen de Jong 577815a1f4 m68k: cmp -> tst optimization 2026-08-04 22:06:20 +02:00
Irmen de Jong c2a942dd45 fix jump table on m68k 2026-08-04 21:43:39 +02:00
Irmen de Jong 82342268da fix too conservative Inliner gates, and possible endinanness problem. Optimized nested msb/lsb on m68k. 2026-08-04 21:01:29 +02:00
Irmen de Jong 30e576e253 defensive fix for wrong datatype in pointer comparisons 2026-08-04 20:44:05 +02:00
Irmen de Jong a5782c300a fix compiler crash on out of range pointer address values 2026-08-04 20:24:50 +02:00
Irmen de Jong 84f720b63b fix pokew/pokel pointer size mismatch 2026-08-04 19:46:49 +02:00
Irmen de Jong b8cded4373 revert back to fast (but slightly inaccurate) signed bitshifting for division optimization 2026-08-04 19:41:14 +02:00
Irmen de Jong 368dce93d9 new6502 codegen: implement long multiplications and divisions 2026-08-04 19:09:41 +02:00
Irmen de Jong 644226f925 update prog8 coder skill about multiple statements per line 2026-08-04 18:52:58 +02:00
Irmen de Jong 42e8e91034 disable signed div bias-shift method because of code bloat 2026-08-04 18:38:35 +02:00
Irmen de Jong af80ec6502 fix invalid optimization of signed division into a shift (wrong rounding result) - IR codegen 2026-08-04 17:42:12 +02:00
Irmen de Jong cf714d8e0c fix invalid optimization of signed division into a shift (wrong rounding result) - 6502 codegen only 2026-08-04 16:16:38 +02:00
Irmen de Jong 86c2f711ed fix invalid const-folding of certain strings char classification routines such as isupper() 2026-08-04 15:59:08 +02:00
Irmen de Jong 86c01e9d7b remaining m68k optimization issues noted in doc 2026-08-04 15:45:29 +02:00
Irmen de Jong 7138ee024b fix memory-byte read sign extension error when the byte was signed 2026-08-04 15:45:14 +02:00
Irmen de Jong b9f65186cb fix expression operand swap bug when there are side effects 2026-08-04 14:49:01 +02:00
Irmen de Jong 27aeafef0d more ast optimization gatings for m68k 2026-08-04 13:58:03 +02:00
Irmen de Jong 16901212d4 m68k: fix divmod() and lmh() call convention 2026-08-04 13:40:30 +02:00
Irmen de Jong 49f5c30e8c 6502: better error message for missing signed divmod support 2026-08-04 13:09:06 +02:00
Irmen de Jong bef1678c2a IR: divmod no longer uses stack to return the quotient and remainer 2026-08-04 12:46:36 +02:00
Irmen de Jong 3459ffcdb9 m68k: fix wrong divm/mulm code gen 2026-08-04 05:19:53 +02:00
Irmen de Jong 4cfe9b2729 Merge branch 'master' into new-codegens 2026-08-04 04:58:22 +02:00
Irmen de Jong a919ea63e4 remove wrong ast node copy() overrides 2026-08-04 04:54:53 +02:00
Irmen de Jong 97e5a6f7bb amiga500 textio: use dos VPrintf instead of separate conv calls 2026-08-04 04:50:01 +02:00
Irmen de Jong 79c05ae396 m68k: fix divs sign extension bug 2026-08-04 03:05:13 +02:00
Irmen de Jong f25ea95bdf m68k: fix extb.l on 68000, checks for long division/multiplication on 68000 2026-08-04 01:51:14 +02:00
Irmen de Jong 45bf8ba72a m68k: fix long and float variable dc.l/dc.s, fix 68020 long division instruction syntax 2026-08-04 01:00:27 +02:00
Irmen de Jong 07910fc543 IR: fix register type error for power of 2 multiplies as shifts 2026-08-04 00:06:09 +02:00
Irmen de Jong c64fdcffa8 IR: fix register type error for power of 2 multiplies as shifts 2026-08-04 00:05:13 +02:00
Irmen de Jong c0b8cf827d fix m68k eor instruction syntax 2026-08-04 00:04:19 +02:00
Irmen de Jong fc38847af4 fix addq/subq value range to 1-8 2026-08-03 23:33:30 +02:00
Irmen de Jong fea52c6145 uword comparison optimizations not for m68k 2026-08-03 22:45:46 +02:00
Irmen de Jong 4b20440efe another bit shift optimization not for m68k 2026-08-03 22:30:30 +02:00
Irmen de Jong c39410afc2 x/256 ast optimization not for m68k 2026-08-03 22:19:29 +02:00
Irmen de Jong 93b953cf60 implement IR ADDIM and SUBIM in the new codegens 2026-08-03 21:53:54 +02:00
Irmen de Jong 01c82f92eb Merge branch 'refs/heads/master' into new-codegens
# Conflicts:
#	examples/test.p8
#	intermediate/src/prog8/intermediate/IRInstructions.kt
2026-08-03 19:36:25 +02:00
Irmen de Jong 13e032e1a3 add new IR instructions ADDIM and SUBIM 2026-08-03 19:31:57 +02:00
Irmen de Jong 8405e6f2a3 fix endianness issue with msw/lsw on m68k 2026-08-03 15:49:39 +02:00
Irmen de Jong 491b28f6b6 chained expression splitting is only beneficial on the 6502 2026-08-03 15:26:52 +02:00
Irmen de Jong 9286d6b2c8 fix amiga sysinit 2026-08-03 15:21:33 +02:00
Irmen de Jong d144235dc9 Merge branch 'master' into new-codegens 2026-08-03 14:35:47 +02:00
Irmen de Jong c3b5ee3dfd optimize imports 2026-08-03 14:31:42 +02:00
Irmen de Jong b0e0058310 split huge test file 2026-08-03 14:23:21 +02:00
Irmen de Jong 9cbbf85a85 fix chained expression optimization bug 2026-08-03 14:22:46 +02:00
Irmen de Jong 2fa82ff3ad fix ast remainder optimization check 2026-08-03 13:26:11 +02:00
Irmen de Jong 9936a855ab fix ast remainder optimization check 2026-08-03 13:05:26 +02:00
Irmen de Jong 3e03980478 tweaking ast optimizations for m68k 2026-08-03 12:45:48 +02:00
Irmen de Jong e042756453 add timer.device 2026-08-03 08:09:11 +02:00
Irmen de Jong 84d5247b78 fix m68k enum field symbols 2026-08-03 05:30:09 +02:00
Irmen de Jong 4682462c19 added utility.library 2026-08-03 04:16:10 +02:00
Irmen de Jong b6e503a67b fix amiga textio and m68k alignment issues 2026-08-03 02:33:19 +02:00
Irmen de Jong dedae29d72 Merge branch 'master' into new-codegens 2026-08-02 17:42:33 +02:00
Irmen de Jong bb1d1e2007 gradle --non-interactive didn't work 2026-08-02 17:27:39 +02:00
Irmen de Jong 0aa6c130e8 update to kotlin 2.4.10 2026-08-02 17:23:22 +02:00
Irmen de Jong 092116de1d custom grab_system() and return_system() added for demo/game hardware banging programs
added amigarasters example
2026-07-16 23:04:14 +02:00
Irmen de Jong bf0733f8b3 amiga LVOs (extsub library callfars) are now represented by their familiar negative decimal offset number instead of a hex unsigned long.
Actual JSR to the library LVO uses the symbolic name if possible to create code that is easier to debug
2026-07-16 21:42:04 +02:00
Irmen de Jong b0cf649c2d register packer does't work well 2026-07-16 20:33:27 +02:00
Irmen de Jong 3499121f9c better amiga program startup 2026-07-16 00:35:44 +02:00
Irmen de Jong c43cacdc2f added a IR RegisterPacking optimization step that reduces the number of registers through reuse of register slots 2026-07-15 22:39:19 +02:00
Irmen de Jong ead1e5e879 make exit() work on m68k 2026-07-15 00:18:40 +02:00
Irmen de Jong 4c1f193d53 amiga custom chip registers 2026-07-14 22:20:12 +02:00
Irmen de Jong abaaea33d8 more intuition constants 2026-07-14 20:13:03 +02:00
Irmen de Jong 51257e47da structs in symboldumps 2026-07-14 08:05:03 +02:00
Irmen de Jong fe42040d48 structs in symboldumps 2026-07-14 08:04:32 +02:00
Irmen de Jong 67ddd97f3d fix skill to allow fixed-size arrays as struct fields 2026-07-14 07:31:10 +02:00
Irmen de Jong abea7bf329 fix const evaluation type problem in bitwise operations 2026-07-14 07:28:31 +02:00
Irmen de Jong bc3f49dc13 unit test for bitwise long const errors 2026-07-14 07:27:44 +02:00
Irmen de Jong 7565d04cf5 fix missing constants in amiga lib dumps 2026-07-14 07:27:15 +02:00
Irmen de Jong 0d76eea1be unit test for bitwise long const errors 2026-07-14 07:24:01 +02:00
Irmen de Jong 9a2851a9d5 fix const evaluation type problem in bitwise operations 2026-07-14 07:12:52 +02:00
Irmen de Jong 5e1612f204 improved amiga libconvert script (now requires clang to parse the C header files) 2026-07-14 06:49:29 +02:00
Irmen de Jong 316181b971 fix skill to allow fixed-size arrays as struct fields 2026-07-14 06:26:08 +02:00
Irmen de Jong e753eed4d4 amiga lib dumps with structs 2026-07-14 04:52:45 +02:00
Irmen de Jong b52a07c7c4 tweak m68k roxl/roxr semantix (X bit)
work on m68k conv routines
2026-07-14 02:49:19 +02:00
Irmen de Jong f210c8b0db amiga library calls 2026-07-13 22:58:34 +02:00
Irmen de Jong f865a9801f output memory mapped variables on m68k asm 2026-07-12 19:18:17 +02:00
Irmen de Jong 6a165e951b amiga500 target 2026-07-12 19:05:13 +02:00
Irmen de Jong 9322fbb234 better syntax highlighting in docs
added m68k qemubootinfo example
2026-07-12 14:20:31 +02:00
Irmen de Jong 4b7e2dce9d better syntax highlighting in docs 2026-07-12 13:05:05 +02:00
Irmen de Jong 7bda2e987c remove redundant DONTCARE split pointer array conversions on non-6502 targets 2026-07-12 12:55:00 +02:00
Irmen de Jong e645b0abe1 add pokep() and peekp() builtin functions 2026-07-12 12:54:29 +02:00
Irmen de Jong f10a58ee1b fix m68k long/string arrays 2026-07-12 12:09:44 +02:00
Irmen de Jong f498f598bf fix m68k concat 2026-07-12 04:49:13 +02:00
Irmen de Jong 4dfcb59b6f fix daemon 2026-07-12 04:03:10 +02:00
Irmen de Jong 4506a3cb3e pass compilation target to more places to be able to determine correct types 2026-07-12 03:52:57 +02:00
Irmen de Jong 247559858f fix bitwise instructions on m68k 2026-07-11 23:40:46 +02:00
Irmen de Jong 8a8cf3abc7 Merge branch 'master' into new-codegens
# Conflicts:
#	compiler/test/TestCompilerOnExamples.kt
2026-07-11 23:13:04 +02:00
Irmen de Jong cf2a5ae4f9 fix test sizes 2026-07-11 23:06:26 +02:00
Irmen de Jong 0cf488b586 fix some array issues 2026-07-11 23:01:23 +02:00
Irmen de Jong a019f22f47 all arena allocators now return pointer type 2026-07-11 22:26:14 +02:00
Irmen de Jong 9587e1b724 Merge branch 'master' into new-codegens 2026-07-11 22:17:25 +02:00
Irmen de Jong e5865a1446 fix delete root node bug in binarytree.p8 2026-07-11 22:16:51 +02:00
Irmen de Jong 7adbdf39ac specific for 6502 2026-07-11 22:02:08 +02:00
Irmen de Jong 57714efb40 added pushp() and popp() builtin functions 2026-07-11 21:49:22 +02:00
Irmen de Jong dafb0906c3 fix some m68k pointer/uword stuff 2026-07-11 21:13:21 +02:00
Irmen de Jong 96bb64aebb fix some m68k fp and alignment stuff 2026-07-11 20:36:03 +02:00
Irmen de Jong 57254233e4 Merge branch 'master' into new-codegens
# Conflicts:
#	codeCore/src/prog8/code/target/NormalMemSizer.kt
2026-07-11 18:22:11 +02:00
Irmen de Jong 9ec4b35de9 fix m68k memclear 2026-07-11 18:20:41 +02:00
Irmen de Jong 9adbd77ce4 vasm package is borked 2026-07-11 17:28:15 +02:00
Irmen de Jong 8957e8fff7 needs devmode as well 2026-07-11 17:25:16 +02:00
Irmen de Jong 3aa0344c4a needs beta channel 2026-07-11 17:23:14 +02:00
Irmen de Jong 54de2c5fbf attempt to install vasm in github actions 2026-07-11 17:21:12 +02:00
Irmen de Jong 5b5f553d37 improved error message when attempting to alias types,
fix size test
2026-07-11 17:04:52 +02:00
Irmen de Jong 0e978b250b added 'pointer' as type alias for uword or long depending on the compilation target's pointer size 2026-07-11 16:59:24 +02:00
Irmen de Jong 67e6888009 fix ast check for m68k to also consider library files, align code on even addresses, start implementing syscalls 2026-07-11 14:59:46 +02:00
Irmen de Jong b9fe1f2057 fix fibonacci sequence to start from 0 2026-07-11 14:48:52 +02:00
Irmen de Jong debb91965b fix ast check for m68k to also consider library files, align code on even addresses 2026-07-11 13:43:14 +02:00
Irmen de Jong d0b3fefd57 fix peek/poke to take long addresses on m68k 2026-07-11 13:16:16 +02:00
Irmen de Jong 5cc3623a2a m68 adding input routine, fix linkerscript, qemu bootinfo 2026-07-11 12:41:35 +02:00
Irmen de Jong d08f532a10 m68k float support 2026-07-11 02:39:14 +02:00
Irmen de Jong 35b7e4a4de fix reference return types vs pointer 2026-07-11 00:07:36 +02:00
Irmen de Jong 38b77d8817 ir: fix usage of STOREZ on pointers 2026-07-10 23:49:48 +02:00
Irmen de Jong 3078f402bb fix uword literal assignment to pointer on m68k 2026-07-10 22:35:07 +02:00
Irmen de Jong f977daafbb value casting now gets passed the compilation target (needed for correct pointer type casting) 2026-07-10 22:23:33 +02:00
Irmen de Jong aabd99e9eb fix uword to pointer assignment problems 2026-07-10 21:32:59 +02:00
Irmen de Jong e7dbab1822 fix defer on m68k by making mask variable a word so correct memory LSR instruction can be used 2026-07-10 17:40:47 +02:00
Irmen de Jong cf6efd76f0 making sure memory() is long on m68k 2026-07-10 04:51:54 +02:00
Irmen de Jong 8a7922ffcc fix split words arrays on m68k to be not split 2026-07-10 01:47:18 +02:00
Irmen de Jong c7a8e84fd0 fix more pointer type handling on m68k 2026-07-09 03:44:41 +02:00
Irmen de Jong cb57bea862 fix inline asmsub handling, more optimized strings and sys routines 2026-07-09 03:25:30 +02:00
Irmen de Jong b24ce80945 tweaking m68k library 2026-07-09 00:13:20 +02:00
Irmen de Jong eb18397035 Merge branch 'master' into new-codegens 2026-07-08 23:37:48 +02:00
Irmen de Jong cfd1f951f0 should call through 2026-07-08 23:36:48 +02:00
Irmen de Jong b0e55eb25b fix another float to long cast error 2026-07-08 23:27:10 +02:00
Irmen de Jong 37a86f3899 switch back to M68020 CPU so code migth eventually run on a stock Amiga 1200 2026-07-08 23:03:10 +02:00
Irmen de Jong 5700ae446f improve m68k codegen, add integer sqrt 2026-07-08 22:28:00 +02:00
Irmen de Jong cb240f6a4b Merge branch 'master' into new-codegens 2026-07-08 21:02:17 +02:00
Irmen de Jong b405ffb8bd fix missing float to long cast, fix missing inlined floats routines prefix 2026-07-08 20:42:54 +02:00
Irmen de Jong 0fa08310e7 add missing floats.pow() to the docs, optimize the signature of many float functions 2026-07-08 19:28:34 +02:00
Irmen de Jong 968d9819db removed -nostdlib option 2026-07-07 23:31:20 +02:00
Irmen de Jong 54df69a2b3 allow array args for pointer params in m68k 2026-07-07 22:14:38 +02:00
Irmen de Jong 88b3291785 added ELF/RAW output type selection for m68k, fix div garbage register data 2026-07-07 21:49:45 +02:00
Irmen de Jong c9c68f7d8c clean up some pointer type stuff in m68k 2026-07-07 20:36:00 +02:00
Irmen de Jong 2d3f0baa51 add a few m68k math routines
properly output data section in m68k
2026-07-07 20:03:13 +02:00
Irmen de Jong bd4184252f add sys.MAX_LONG and sys.MIN_LONG for m68k 2026-07-07 05:02:47 +02:00
Irmen de Jong f043dba23d Merge branch 'master' into new-codegens 2026-07-07 04:39:09 +02:00
Irmen de Jong f85c59b12c add sys.MAX_LONG and sys.MIN_LONG 2026-07-07 04:37:59 +02:00
Irmen de Jong e6a267bd3f fix 32 bits address-of 2026-07-07 04:27:47 +02:00
Irmen de Jong a532fb411b IR POINTER size tweaks 2026-07-07 02:58:05 +02:00
Irmen de Jong 1f4ffdffc1 fix IR constant prefixing/no prefixing 2026-07-07 01:45:55 +02:00
Irmen de Jong 1053a9a761 Merge branch 'master' into new-codegens 2026-07-07 01:00:13 +02:00
Irmen de Jong 34eedd1fe7 fix missing return values in symboldumps 2026-07-07 00:41:14 +02:00
Andy De George 2c10e2b102 Fix the swap documentation now that it's a statement and no longer a function (#229)
* [docs] Remove swap from built in functions

* Move swap info to programming doc

* Reintroduce swap statement documentation

* Apply suggestion from @Thraka
2026-07-07 00:08:29 +02:00
Irmen de Jong 7f51bbd777 working on encoding support for variable sized pointers in the IR 2026-07-07 00:06:28 +02:00
Irmen de Jong 5c36e21948 working on fixing pointer arithmethic
but see transformWithPointerArithmetic() still unfinished
2026-07-06 02:20:32 +02:00
Irmen de Jong a46443417e disable zeropage usage on non-6502 targets 2026-07-05 20:02:14 +02:00
Irmen de Jong 57055b3b55 map m68k cpu registers to and from slots 2026-07-05 16:25:20 +02:00
Irmen de Jong 559521c6df m68k better BSS 2026-07-05 07:07:19 +02:00
Irmen de Jong 11e3b39486 m68k (incomplete) attempt to fix 32 bits pointers 2026-07-05 06:31:24 +02:00
Irmen de Jong 1c50e397de m68k registers 2026-07-05 03:41:59 +02:00
Irmen de Jong 05bea61a69 builtin functions now have a signature in the symbol dump files 2026-07-05 01:11:40 +02:00
Irmen de Jong 2a8b24074b remove error about memory mapped pointers 2026-07-05 00:53:13 +02:00
Irmen de Jong 99ead2c74c m68k 2026-07-04 23:18:03 +02:00
Irmen de Jong f557d2bee0 Merge branch 'master' into new-codegens 2026-07-04 18:28:14 +02:00
Irmen de Jong 1f184a14ae diskio: document path length limit 2026-07-04 18:24:19 +02:00
Irmen de Jong 8be1cd1090 pet32: added some alternative hopefully unused ZP locations (as long as you're not using tape I/O which is a common assumption for every other cbm target as well) 2026-07-04 18:12:31 +02:00
Irmen de Jong 5278f9a595 new codegen fix floatparse / mul 2026-07-04 18:00:49 +02:00
Irmen de Jong dd1a886b66 Merge branch 'master' into new-codegens 2026-07-04 00:04:50 +02:00
Irmen de Jong c3ec400ee7 pet32: don't use problematic zeropage locations 2026-07-04 00:03:22 +02:00
Irmen de Jong 7f95377ad7 newcodegen: fixing more comparisons and branches 2026-07-04 00:01:53 +02:00
Irmen de Jong 903c553f94 newcodegen: fixing more comparisons and branches 2026-07-03 22:15:39 +02:00
Irmen de Jong 0e7237c64a newcodegen: fixing branches 2026-07-03 21:13:27 +02:00
Irmen de Jong 122af69cdc newcodegen: fixing comparisons 2026-07-03 05:14:07 +02:00
Irmen de Jong 786d742e76 newcodegen: fixing floats 2026-07-03 02:04:43 +02:00
Irmen de Jong c4c46fd282 fix stack byte order in new codegen 2026-07-02 22:49:10 +02:00
Irmen de Jong 5a49c97e5d fix zeropage var inits in new codegen, better 65c02 instruction usage 2026-07-02 22:12:43 +02:00
Irmen de Jong 2cd195b343 fix string encoding in new codegen 2026-07-02 21:03:54 +02:00
Irmen de Jong 36238267d0 reuse AssemblyProgram6502 in newcodegen for 6502 2026-07-02 01:36:25 +02:00
Irmen de Jong 52fe2f2c0d adjust compilation options etc for the newCodegen flag 2026-07-02 01:21:18 +02:00
Irmen de Jong 4bf0eba2f8 Merge branch 'master' into new-codegens
# Conflicts:
#	.idea/compiler.xml
#	codeCore/src/prog8/code/core/CompilationOptions.kt
#	codeGenIntermediate/test/TestVmCodeGen.kt
#	codeGenNew6502/src/prog8/codegen/new6502/New6502CodeGenerator.kt
#	compiler/src/prog8/CompilerMain.kt
#	compiler/src/prog8/compiler/Compiler.kt
#	compiler/src/prog8/compiler/CompilerDaemon.kt
#	compiler/test/TestCompilerOnExamples.kt
#	compiler/test/helpers/compileXyz.kt
#	scripts/clean.sh
#	settings.gradle
2026-07-02 01:14:55 +02:00
Irmen de Jong 5130a74754 removed expericodegen 2026-07-02 01:07:21 +02:00
Irmen de Jong 9d1bcfc0c6 remove codegenExperimental module 2026-07-02 00:54:11 +02:00
Irmen de Jong 15756a8977 rename -expericodegen into -newcodegen that should switch all existing 6502 codegens to using the new one based on IR 2026-07-02 00:51:45 +02:00
Irmen de Jong 0ab36bcbf6 added qemu68k compilation target 2026-07-01 23:47:13 +02:00
Irmen de Jong 36eef51e1c new package structure for new codegens 2026-07-01 23:03:32 +02:00
Irmen de Jong 309c25a993 add new codegens that are based on the IR 2026-07-01 22:22:53 +02:00
Irmen de Jong e61db5ed3f cleanup 2026-07-01 22:16:00 +02:00
Irmen de Jong cc5ef21fd6 don't publish unfinished codegens yet 2026-07-01 21:40:00 +02:00
Irmen de Jong f1f925ecee clarify sqrt() behavior on values <0 2026-07-01 20:51:06 +02:00
Irmen de Jong ab422c0ebc fix wrong codegen and 'empty' library subroutines 2026-07-01 20:25:00 +02:00
Irmen de Jong 05a13463f4 tweak agent skills and helper routine visibilities 2026-07-01 17:55:13 +02:00
Irmen de Jong 19238cc366 IR: introduce strict and broad status flags contract for cpu targets
fix cmpi for words and longs
2026-07-01 01:38:35 +02:00
Irmen de Jong e3d4401d99 fix callfar 2026-07-01 00:02:26 +02:00
Irmen de Jong 5da4efc2a3 shorten long operations by using a Y-loop 2026-06-30 22:47:50 +02:00
Irmen de Jong c0c44156f1 new codegen: implement roxl/roxr longs, float casting, callfar 2026-06-30 22:18:41 +02:00
Irmen de Jong 8645833319 new codegen: float support and CALLI 2026-06-30 20:40:34 +02:00
Irmen de Jong 6a867d98eb new codegen: syscall support started 2026-06-30 05:57:19 +02:00
Irmen de Jong 58363ff4e4 Add required support for inlined asmsub routines in IR and new codegen 2026-06-30 03:17:19 +02:00
Irmen de Jong 2555aa72ca improve codegen argument slot processing (func call arg order) 2026-06-30 02:45:19 +02:00
Irmen de Jong 3b94fd4c4b IR: more consistent BSS handling 2026-06-30 01:14:31 +02:00
Irmen de Jong 95f500c32f fixing codegen 2026-06-29 23:10:55 +02:00
Irmen de Jong 870c2e8827 add name to StExtSubParameter to pass this to the codegen (required for @R0 etc) 2026-06-29 04:43:24 +02:00
Irmen de Jong af2360648f implement codegen mul and div routines, and fix symboloffsets 2026-06-29 04:43:24 +02:00
Irmen de Jong bb95d40d6d asm syntax 2026-06-29 04:43:24 +02:00
Irmen de Jong 55ea599fca Remove hardcoded external KERNAL entry points in codegen 2026-06-29 04:43:24 +02:00
Irmen de Jong fd5fdf3d13 IR codegen: Emit extsub as inline assembly equate for codegen references 2026-06-29 04:43:24 +02:00
Irmen de Jong ca129edce4 adding new 6502 codegen 2026-06-29 04:43:23 +02:00
Irmen de Jong c1694a4b08 add m68k codegen skeleton 2026-06-29 04:43:23 +02:00
Irmen de Jong a348bbbebe adding new 6502 codegen based on IR files 2026-06-29 04:43:23 +02:00
Irmen de Jong e6b0a89d64 asm coder skill 2026-06-29 04:43:09 +02:00
Irmen de Jong 9a4821d1e3 extra asm syntax rule in skill 2026-06-28 22:50:43 +02:00
Irmen de Jong 71583a5b93 Move symbol prefixing logic from 6502 codegen to IR generation. 2026-06-28 21:33:10 +02:00
Irmen de Jong 407ba34c72 IR fix certain setmsb/setlsb and rol/ror crashes on indexed pointers 2026-06-27 14:50:45 +02:00
Irmen de Jong fc4782a35b Support &blockname in IR generation 2026-06-27 12:54:36 +02:00
Irmen de Jong 7a83b7db1b Fix dark mode styling for ..data:: headers in documentation 2026-06-27 10:03:15 +02:00
Irmen de Jong a827f4c4ce Support block-level %align in IR 2026-06-27 09:51:08 +02:00
Irmen de Jong 01c5794799 IR: fixing zeropage array initialization 2026-06-27 02:42:55 +02:00
Irmen de Jong 1c093cca2d fix zeropage array initialization for split word arrays 2026-06-27 01:39:38 +02:00
Irmen de Jong a85b267872 streamline asm generation 2026-06-26 20:33:40 +02:00
Irmen de Jong 5e0c1c9794 Optimize parser by introducing SLL prediction mode with LL fallback for improved performance and error handling. 2026-06-25 03:53:18 +02:00
Irmen de Jong 887df44359 fix IR loadhr/storehr parsing from p8ir 2026-06-25 03:30:10 +02:00
Irmen de Jong a5fc162c71 Optimize block sorting and subroutine reordering logic in AST processing steps. 2026-06-25 02:22:44 +02:00
Irmen de Jong 9d3fc99d71 ignores 2026-06-25 01:58:14 +02:00
Irmen de Jong a871713907 some more explanations 2026-06-23 20:57:06 +02:00
Irmen de Jong 2a19e5682a add cx16 dynamicbanking example 2026-06-23 20:45:34 +02:00
Irmen de Jong 22d4fa73d6 rename bankmanager to bankselector 2026-06-23 19:07:31 +02:00
Irmen de Jong 2ed95c52ef tune JSRFAR bank byte setup 2026-06-23 01:01:35 +02:00
Irmen de Jong 73fb04aaf5 Add support for unique call-site IDs in banked subroutines 2026-06-23 00:28:22 +02:00
Irmen de Jong f97a7f426c improved cmp() documentation 2026-06-22 19:53:45 +02:00
Irmen de Jong c1189617f3 fix 64tass repo link 2026-06-22 00:12:55 +02:00
Irmen de Jong 78d43c3cb6 Merge branch 'refs/heads/bugfix12.2.1'
# Conflicts:
#	examples/test.p8
2026-06-20 19:50:42 +02:00
Irmen de Jong 86f9b6aa69 fixed cmp() sign/flags errors 2026-06-20 19:49:45 +02:00
Irmen de Jong 8df2bb8d2e Merge branch 'bugfix12.2.1' 2026-06-20 15:47:41 +02:00
Irmen de Jong 33f30d925e Update documentation with proper example links 2026-06-20 15:45:01 +02:00
Irmen de Jong c8c51245af Merge branch 'bugfix12.2.1' 2026-06-20 15:18:14 +02:00
Irmen de Jong db227679a8 fix empty/full boundary checks on various datastructions in the buffers module 2026-06-20 15:05:37 +02:00
Irmen de Jong 02110de844 optimized floats minf, maxf, clampf routines 2026-06-20 13:56:17 +02:00
Irmen de Jong 7d77a0eca6 Merge branch 'bugfix12.2.1'
# Conflicts:
#	compiler/test/TestCompilerOnExamples.kt
2026-06-19 23:37:49 +02:00
Irmen de Jong 0f3475128a fix divmod_uw_asm to not clobber R15 anymore 2026-06-19 23:23:53 +02:00
Irmen de Jong e6e4714b02 adjust pet music tempo a little
todo about memory mapping pointers
2026-06-19 19:59:54 +02:00
Irmen de Jong d83ece397d add configurable default launcher types for custom compilation targets 2026-06-19 18:58:05 +02:00
Irmen de Jong a3c768bc6b add floats.mod() 2026-06-19 18:35:09 +02:00
Irmen de Jong a3d14003cb Enhanced inlining: support subroutines with one simple parameter. NOTE: risky optimization, maybe still broken in obscure cases
also improve parent pointer relinking, fix namespace scoping, and refine assembly checks.
2026-06-19 04:57:54 +02:00
Irmen de Jong d451953e40 improve prog8 skill 2026-06-19 02:18:41 +02:00
Irmen de Jong d505c42d15 improve undefined symbol error handling
(cherry picked from commit 8c92663824)
2026-06-19 02:16:11 +02:00
Irmen de Jong 8c92663824 improve undefined symbol error handling 2026-06-19 02:13:03 +02:00
Irmen de Jong 10d86eb4d8 Merge remote-tracking branch 'origin/master' 2026-06-19 00:45:32 +02:00
markjreed ee5e734f23 feat: add symbols for enharmonic flats (#226) 2026-06-19 00:44:50 +02:00
Irmen de Jong 6b233b7da3 pet: add sys.set_irq() and sys.restore_irq() support routines 2026-06-19 00:34:53 +02:00
Irmen de Jong a140519374 fix pet music example to use higher octave to be able to play correct B section end note 2026-06-18 23:57:38 +02:00
Irmen de Jong 2b118f2e42 pet32: add petsnd REST constant for silence, and set_gap() for intra note silence gap 2026-06-18 23:13:13 +02:00
Irmen de Jong be9d9fe377 pet32: added new playback functions to petsnd module to play songs (blocking or non-blocking). New 'music' example added for pet. 2026-06-18 21:02:33 +02:00
Irmen de Jong d1345aafec don't limit callfar/banked call support on fixed set of built in targets
but you have to set supports_banked_calls = true in the custom target config file.
2026-06-18 19:09:10 +02:00
Irmen de Jong d5932a7a57 improved bankin support error message 2026-06-17 23:45:30 +02:00
Irmen de Jong 5751beb72f fix some more LSP tests 2026-06-17 20:52:59 +02:00
Irmen de Jong 02194a735a Add supports_banked_calls property to target configuration files 2026-06-17 20:30:21 +02:00
Irmen de Jong b5fc25b2f4 Merge branch 'v12.2.1'
# Conflicts:
#	compiler/test/TestCompilerOnExamples.kt
#	docs/source/_static/symboldumps/skeletons-cx16.txt
2026-06-17 19:41:34 +02:00
Irmen de Jong 5a593b9ef3 Preserve cx16.r15 register in % for words. Update related code and documentation accordingly. 2026-06-17 19:23:19 +02:00
Irmen de Jong b411914624 Document virtual register clobbering details and update related comments. 2026-06-17 03:00:33 +02:00
Irmen de Jong 0f80b695e7 Fix invalid optimizer edge cases 2026-06-17 01:18:39 +02:00
Irmen de Jong 63c425f247 Merge branch 'refs/heads/v12.2.1' 2026-06-16 23:25:18 +02:00
Irmen de Jong 276627abcb remove broken expression optimization that combined a=x, a*=y into a=x*y 2026-06-16 23:19:42 +02:00
Irmen de Jong 34225d10aa add missing division and modulus code generation support for LONG variables 2026-06-16 23:18:07 +02:00
Irmen de Jong 69261c51b3 IR: Add single-bit manipulation opcodes (BITTST, BITSET, BITCLR, BITTOG) 2026-06-16 21:52:31 +02:00
Irmen de Jong 63d7ef7105 IR: Replace 6502-specific hardware register LOAD/STORE opcodes with generic, parameterized LOADHR/STOREHR opcodes 2026-06-16 20:59:51 +02:00
Irmen de Jong 88a3e5b23f Merge branch 'v12.2.1'
# Conflicts:
#	compiler/test/TestCompilerOnExamples.kt
#	compiler/test/codegeneration/TestArrayThings.kt
#	examples/test.p8
2026-06-16 00:48:35 +02:00
Irmen de Jong 282c3aa00b fix a return split word array codegen issue where it didn't use lsb suffix 2026-06-16 00:39:51 +02:00
Irmen de Jong 19f3b03ac3 remove problematic inlining for subroutines having 1 or more parameters, to avoid an endless loop 2026-06-16 00:02:05 +02:00
Irmen de Jong 1b5efe1e5d fix datatype size comparison for strings vs pointers 2026-06-15 09:03:13 +02:00
Irmen de Jong 2b5a15a178 limit iteration cycles in AST processing steps to prevent endless loops 2026-06-15 03:35:14 +02:00
Irmen de Jong a9f22d9375 handle library path files earlier during import to mark them as library files 2026-06-14 19:29:44 +02:00
Irmen de Jong f9b3514f2a fixes and tests for embedded arrays in structs 2026-06-14 16:18:23 +02:00
Irmen de Jong be12fb507e arrays in structs 2026-06-14 15:35:30 +02:00
Irmen de Jong b2dcd02ee4 prioritize frequently accessed variables for zeropage allocation based on usage scores 2026-06-14 13:41:31 +02:00
Irmen de Jong 5c23471254 Merge branch 'v12.2.1' 2026-06-13 12:16:14 +02:00
Irmen de Jong 6cb6f37871 exclude private symbols from completion suggestions in the LSP 2026-06-13 12:15:11 +02:00
Irmen de Jong 67e284b680 complexity based argument evaluation order in sub calls to optimize register spill handling 2026-06-13 03:22:15 +02:00
Irmen de Jong 1e5ba48fe0 tweak banked call support checks on compilation targets 2026-06-13 02:01:34 +02:00
Irmen de Jong 8e6a27d7c1 @bank now also allows the name of a subroutine for dynamic / overlay banking 2026-06-12 23:47:16 +02:00
Irmen de Jong d0edc0b484 prevent TCO with defer blocks 2026-06-12 03:05:26 +02:00
Irmen de Jong ccd3d94ec0 prevent TCO with defer blocks 2026-06-12 03:02:58 +02:00
Irmen de Jong 98355d3850 avoid shouldContain asserts on large strings in tests to avoid massive log dumps 2026-06-12 02:48:41 +02:00
Irmen de Jong 0e53113b85 Merge branch 'v12.2.1'
# Conflicts:
#	gradle.properties
2026-06-11 23:12:28 +02:00
Irmen de Jong e9a3ed457e fix optimizer problem that removed var inits for pointer vars in certain cases. Fixes #225 2026-06-11 22:37:51 +02:00
Irmen de Jong 6001da30d8 add comments to float library routines about the Z flag wrapper routines
(cherry picked from commit c55f5e4b50)
2026-06-11 21:50:25 +02:00
Irmen de Jong c55f5e4b50 add comments to float library routines about the Z flag wrapper routines 2026-06-11 21:49:51 +02:00
Irmen de Jong e983c0c2b9 fixed the c64 float heisenbug
(cherry picked from commit 532bf13057)
2026-06-11 21:40:42 +02:00
Irmen de Jong 532bf13057 fixed the c64 float heisenbug 2026-06-11 21:29:06 +02:00
Irmen de Jong de706e79de add friendly error for invalid 2D array syntax 2026-06-10 04:14:32 +02:00
Irmen de Jong a19f337ebe update prog8-coder skill 2026-06-10 02:49:48 +02:00
Irmen de Jong 041a904e44 fix serialdownload size test 2026-06-09 19:24:02 +02:00
Irmen de Jong 131134d24b fix daemon output path 2026-06-09 02:06:07 +02:00
Irmen de Jong 97fb5298a8 fix daemon output path 2026-06-09 01:59:06 +02:00
Irmen de Jong b580a177d4 serial module now has configurable baud rate, and some uart tweaks 2026-06-09 01:46:46 +02:00
Irmen de Jong a0b1ca5d9f Merge branch 'next-version-12.3' 2026-06-08 21:35:53 +02:00
Irmen de Jong 3a291c56b4 ci: split build step into compile, test, and package for better granularity 2026-06-08 21:07:25 +02:00
Irmen de Jong ed41d5dbc5 update libs and Kotlin
remove docs and examples imls
2026-06-08 20:58:27 +02:00
Irmen de Jong 628bd41740 update kotest 2026-06-08 20:43:54 +02:00
Irmen de Jong de988f72c6 switch from IDEA iml to Gradle build config, this finally fixes Kotest integration as well 2026-06-08 20:43:54 +02:00
Irmen de Jong 869c5ef544 move -srcdirs directories in front of everything else.
add -traceimports option to trace module imports.
2026-06-08 20:35:39 +02:00
Irmen de Jong 17ee233e8b tweak import path search order and document it 2026-06-08 20:34:17 +02:00
Irmen de Jong f2d1dffbe0 preparing for 12.2 release 2026-06-08 20:15:19 +02:00
Irmen de Jong 4008280a62 fix 64tass output order in daemon 2026-06-07 02:45:52 +02:00
Irmen de Jong 2e7235ec02 fix daemon mode error reporting paths 2026-06-07 02:31:06 +02:00
Irmen de Jong a4330f5048 fix -emu program name problem with -daemon 2026-06-07 00:34:35 +02:00
Irmen de Jong f65aeff231 -emu works again together with -daemon 2026-06-07 00:08:07 +02:00
Irmen de Jong 505243aff7 fix a optimizer crash 2026-06-06 23:29:16 +02:00
Irmen de Jong d0f2fc13ba add dummy rambank() and rombank() support for virtual target 2026-06-06 23:26:47 +02:00
Irmen de Jong 53d51dcd38 improve -libsearch by adding fuzzy search fallback 2026-06-06 19:28:53 +02:00
Irmen de Jong c1aa0e49fe fix a possible vera registers clobbering issue when using psg2 from irq handler 2026-06-06 17:30:08 +02:00
Irmen de Jong e1e72d4317 fix crash when using const ubyte pointer as string argument 2026-06-06 17:12:15 +02:00
Irmen de Jong feec343cbc made -daemon more robust 2026-06-06 12:41:15 +02:00
Irmen de Jong 5cdc4233f3 ideas & update prog8-coder skill 2026-06-04 01:16:41 +02:00
Irmen de Jong 1ae89d18cc prevent string deduplication for struct initializers 2026-06-03 01:43:50 +02:00
Irmen de Jong eb19d00a1e prevent faulty inlining of subs with register-aliased parameters 2026-06-02 23:14:55 +02:00
Irmen de Jong e01ee10ef0 fix output binary path displayed to the user 2026-06-02 21:05:03 +02:00
Irmen de Jong f4b3cb12e1 history 2026-06-01 23:19:31 +02:00
Irmen de Jong 77ced60ad6 fix psg2 release timing to make it linear just as attack.
clarify envelope timing details in docs.
2026-06-01 22:58:42 +02:00
Irmen de Jong 6fad90af6e long for loop warning 2026-05-31 23:42:58 +02:00
Irmen de Jong 3076318d7e implement missing for loops on long rages for 6502 2026-05-31 23:38:35 +02:00
Irmen de Jong 9c99110738 doc 2026-05-31 23:07:16 +02:00
Irmen de Jong 1457d36997 beta3 2026-05-31 17:47:37 +02:00
Irmen de Jong 43fb9296dd clarify serial module docs 2026-05-31 17:46:33 +02:00
Irmen de Jong 8bf744cc4a fix some bitwise expression optimization bugs 2026-05-31 07:35:32 +02:00
Irmen de Jong f1f5f070cf fix invalid asm for some in-place long operations on zp vars 2026-05-31 05:14:33 +02:00
Irmen de Jong 191a240d0d adjust extsub jump table offsets to more closely match reality 2026-05-30 23:42:52 +02:00
Irmen de Jong cafb2e355b implement long loop counter support 2026-05-30 23:36:08 +02:00
Irmen de Jong c99c5751f8 tweak serial 2026-05-30 21:11:19 +02:00
Irmen de Jong 435b7e56fa IR VM refactor to reduce class size 2026-05-29 23:14:44 +02:00
Irmen de Jong 14f13fac53 IR tweaks 2026-05-29 22:17:56 +02:00
Irmen de Jong f8b5037924 spelling corrections 2026-05-29 20:58:06 +02:00
Irmen de Jong d2870cb02e implement hex mode file transfer in serial module
as an attempt to have a working file transfer because the binary mode is still failing right now
2026-05-29 20:04:40 +02:00
Irmen de Jong 8e43fc426c IR: handle extsub with banked addresses properly 2026-05-28 03:25:04 +02:00
Irmen de Jong ba1b6e127a IR: properly consume registers for void targets 2026-05-28 00:57:00 +02:00
Irmen de Jong 4f36a6958c fix a few if-expression typecast issues 2026-05-28 00:55:15 +02:00
Irmen de Jong df8f08b4ab more serial tweaks to attempt to fix binary downloads 2026-05-27 23:42:55 +02:00
Irmen de Jong fd5746d3fc tweak the serial module a bit for more robustness 2026-05-27 02:22:35 +02:00
Irmen de Jong 6ab74fd51d don't erroneously allow taking the address of const values 2026-05-27 00:58:01 +02:00
Irmen de Jong 245082ca1d plain console output in github action builds 2026-05-24 12:40:43 +02:00
Irmen de Jong 845e58ea10 64tass install step 2026-05-24 12:33:47 +02:00
Irmen de Jong 2a5dbc1ef7 update project urls that have been moved from github to codeberg 2026-05-24 12:29:09 +02:00
Irmen de Jong 02a1deb1e0 update github build actions 2026-05-23 00:13:14 +02:00
Irmen de Jong 3ba8e5de10 Add serial download example for CX16 and fix serial module import 2026-05-23 00:05:40 +02:00
Irmen de Jong 819d1b4af7 Add serial library for CX16 with UART and ZiModem support
version 12.2-BETA2
2026-05-22 23:52:58 +02:00
Irmen de Jong cdd3d37376 update asmsub inlining behavior and tests: improve support for parameterized calls 2026-05-22 04:17:43 +02:00
Irmen de Jong d0bc01d618 improve inliner: support slightly more complex return expressions 2026-05-22 03:15:57 +02:00
Irmen de Jong ffab73334a enforce errors for empty enum and struct declarations, add corresponding tests 2026-05-22 02:39:09 +02:00
Irmen de Jong 83aeb8846c add support for private keyword for structs, enums, aliases, variables, and subroutines 2026-05-22 02:27:38 +02:00
Irmen de Jong 3a2087310b background daemon compiler mode via -daemon option 2026-05-21 19:08:29 +02:00
Irmen de Jong 61b616701e fix -watch mode to not use stale cached files on subsequent runs 2026-05-20 22:54:52 +02:00
Irmen de Jong bddf872906 better romable awareness in IR 2026-05-20 19:54:12 +02:00
Irmen de Jong 48214a6fdb more IR peephole optimizations, added some implementation plans to the todo 2026-05-19 00:26:35 +02:00
Irmen de Jong b7340856df fix long expression evaluation bug clobbering R14R15 intermediary results 2026-05-18 20:07:23 +02:00
Irmen de Jong 2685854113 memory("name") with only 1 arg now allowed to refer to the actual memory reservation call elsewhere (with all three name, size, align args). 2026-05-16 23:24:41 +02:00
Irmen de Jong ad92f39469 fix error message for conflicting memory() calls 2026-05-16 23:01:49 +02:00
Irmen de Jong d3fe041e01 update kotlin and ksim65 2026-05-16 15:33:03 +02:00
Irmen de Jong f32bac5004 implement 6502 long division routine 2026-05-16 15:04:09 +02:00
Irmen de Jong 9a8e4ac105 lineclip.inside() at top level to check a single point 2026-05-15 21:53:13 +02:00
Irmen de Jong 78857e5c22 pet32: diskio.list_filenames() now checks buffer size 2026-05-15 19:38:45 +02:00
Irmen de Jong 1bb828875d improved vm waitvsync 2026-05-15 18:05:01 +02:00
Irmen de Jong 82aa67ffda lineclip module added 2026-05-15 17:45:13 +02:00
Irmen de Jong 7c44835772 const folding is always done even when -noopt is used 2026-05-15 12:22:52 +02:00
Irmen de Jong 8b9c63fe90 lineclip 2026-05-15 00:31:27 +02:00
Irmen de Jong e77fcc8c16 fix an unsigned long problem 2026-05-10 21:29:42 +02:00
Irmen de Jong 08c12131d4 tweak the rules for turning pointers into consts 2026-05-10 19:51:06 +02:00
Irmen de Jong 5a3ddf705a threshold 2 on ptr usages before no longer const
version 12.2-BETA
2026-05-10 03:08:54 +02:00
Irmen de Jong 20b29fb9b1 add getStaticAddressLowHigh to simplify address calculations and improve arithmetic code generation 2026-05-10 00:09:10 +02:00
Irmen de Jong fd3d59e159 fix sizeof() on a memory slab reference to return const 2 again
diskio.list_filenames() now checks filenames_buf_size minimum (>20)
2026-05-09 23:43:05 +02:00
Irmen de Jong 6d1dfd2a09 due to internal complexity, only pointers to bytes can be made const 2026-05-09 22:45:44 +02:00
Irmen de Jong 7095b14bcb checks 2026-05-09 22:05:57 +02:00
Irmen de Jong 1fe5ff18b1 memory() turned into 2 new ast nodes (slab reservation and slab ref) - still somewhat broken 2026-05-09 11:16:09 +02:00
Irmen de Jong 793b2a703b first step refactoring memory() calls 2026-05-08 19:32:33 +02:00
Irmen de Jong 53948be68f better skill name 2026-05-08 19:30:00 +02:00
Irmen de Jong 3d0dbb71ce created coding agent skills for prog8 and 6502 asm 2026-05-08 19:17:39 +02:00
Irmen de Jong 3dfa804e52 more optimized image conversion script/library 2026-05-07 21:59:53 +02:00
Irmen de Jong fd93d103f6 fix const value problems related to memory(), and fix a bug in constvalue calculation for ArrayIndexedExpression 2026-05-07 03:07:01 +02:00
Irmen de Jong 28977996e2 non-const pointers now can get optimized to const too. 2026-05-06 19:50:21 +02:00
Irmen de Jong e867cb88a7 fix astprinter crash,
IR: fixed using memory() as initialization value for a const uword or const pointer crashed the compiler
2026-05-06 01:31:40 +02:00
Irmen de Jong 1ba8dfcc8b actually doing some const-folding for most const pointer usages. 2026-05-06 00:31:47 +02:00
Irmen de Jong cd2d30c2c7 const pointer support added (but lacks proper const-folding still) 2026-05-05 23:21:32 +02:00
Irmen de Jong a47d2fa40d hint about efficient buffer iteration and skeleton files 2026-05-05 18:39:40 +02:00
Irmen de Jong 6be70af79f fix Inliner crash when using void in multi-value assignment.
update to gradle 9.4.1, tweak agent instructions.
2026-05-03 21:01:57 +02:00
Irmen de Jong 15a28814d5 optimized peekl() mklong() mklong2() to write directly into target variable if possible 2026-05-03 13:42:13 +02:00
Irmen de Jong 049acf0e98 implement long min() max() clamp() and abs() 2026-05-03 08:31:46 +02:00
Irmen de Jong df0d9e567f fix codegen for min() and max() for signed bytes 2026-05-03 07:11:42 +02:00
Irmen de Jong 78920aa115 script to create disk images 2026-05-03 05:15:19 +02:00
Irmen de Jong 1bb9ad5f46 fix peekw target register assignment crash 2026-05-02 23:38:56 +02:00
Andrew Gillham 1f30a06429 Don't require the BASIC launcher when the target has a custom launcher defined. (#224) 2026-05-02 23:38:47 +02:00
Irmen de Jong 5560c342db Merge branch 'optimizing_ifs' 2026-05-02 18:47:04 +02:00
Irmen de Jong e073c007ad better error when trying to run non-6502 code in the 6502 simulator 2026-05-02 18:37:07 +02:00
Irmen de Jong 9d1fa856d4 added unit tests that use the ksim65 simulator to actually run the compiled code 2026-05-02 06:15:09 +02:00
Irmen de Jong 7a26bb972f fix problem where no efficient code was generated anymore for pointer+index 2026-05-02 03:05:19 +02:00
Irmen de Jong e72a4723f9 Merge branch 'master' into optimizing_ifs 2026-05-02 02:17:23 +02:00
Irmen de Jong 96f0d112d2 fix problem where no efficient code was generated anymore for pointer+index 2026-05-02 02:14:18 +02:00
Irmen de Jong eac1b64f81 fix invalid optimization from commit b175dd0265 2026-05-02 00:39:05 +02:00
Irmen de Jong 0011dd8f4c Merge branch 'master' into optimizing_ifs
# Conflicts:
#	codeGenCpu6502/src/prog8/codegen/cpu6502/IfElseAsmGen.kt
#	compiler/test/TestCompilerOnExamples.kt
2026-05-01 19:54:16 +02:00
Irmen de Jong 5ce463d133 added jitpack.io library repository and ksim65 library for possible future use 2026-05-01 18:59:58 +02:00
Irmen de Jong 5926473281 working on improving operand order swap 2026-04-30 05:44:13 +02:00
Irmen de Jong 0a1d06b7f2 corrected associative -> commutative operators names, simplified maySwapOperandOrder logic 2026-04-30 01:13:50 +02:00
Irmen de Jong f98e7d6ad9 optimizing a=b+c; use 64tass local anonymous labels 2026-04-29 22:20:14 +02:00
Irmen de Jong 37896aeed4 optimizing a=b+c 2026-04-29 19:36:38 +02:00
Irmen de Jong b175dd0265 optimizing if-expressions too: more tweaks 2026-04-28 19:54:29 +02:00
Irmen de Jong 310d17d8bb optimizing if-expressions too: typecast const operand unwrapping 2026-04-28 19:54:29 +02:00
Irmen de Jong 371bd4b120 optimizing if-expressions too: final step 2026-04-28 19:54:29 +02:00
Irmen de Jong 3965d77813 optimizing if-expressions too: optimized word and long comparisons more 2026-04-28 19:54:29 +02:00
Irmen de Jong e0ed761661 optimizing if-expressions too: optimized word and long comparisons 2026-04-28 19:54:29 +02:00
Irmen de Jong 51d5261776 optimizing if-expressions too: pointer deref support 2026-04-28 19:54:29 +02:00
Irmen de Jong b85ac38b3b optimizing if-expressions too 2026-04-28 19:54:29 +02:00
Irmen de Jong 6ff9153d9b attempt to optimize word and long comparisons 2026-04-28 19:54:29 +02:00
Irmen de Jong e0d2e407e4 sort operands on complexity 2026-04-28 19:54:29 +02:00
Irmen de Jong 0117ab410b fix an uninitialized parent issue 2026-04-28 19:52:28 +02:00
Irmen de Jong b78a0cf076 make now auto selects system gradle or gradlew wrapper script 2026-04-28 13:29:51 +02:00
Irmen de Jong 722d52c939 revert status channel read on the C64 because it messes with the open file I/O
culprit was commit 2a9ac45cad
2026-04-27 23:37:17 +02:00
Irmen de Jong 162e5ffe3c agent instruction 2026-04-27 11:32:02 +02:00
Irmen de Jong 7383ffae46 fix UnusedCodeRemover wrongly removing var initializers 2026-04-27 00:19:16 +02:00
Irmen de Jong 1b4635d27e missing file 2026-04-26 00:22:41 +02:00
Irmen de Jong 1c376aa9d1 fix some 6502 code gen regressions 2026-04-26 00:18:28 +02:00
Irmen de Jong 91ff17f666 fix some 6502 code gen regressions 2026-04-25 23:32:30 +02:00
Irmen de Jong 5a81021ddc -out now creates the directory if it does not exist yet 2026-04-25 22:48:24 +02:00
Irmen de Jong 9fdd9254f1 fix missing CMP in IR after conditional expression 2026-04-25 22:23:10 +02:00
Irmen de Jong ae4c4ca160 IR: optimized boolean expression codegen (use status flags directly more often instead of transforming to 1 / 0 values) 2026-04-24 22:26:16 +02:00
Irmen de Jong 7ab4880c4a IR: optimized poke() and pokemon() 2026-04-24 19:38:18 +02:00
Irmen de Jong 5c16a40f33 IR: optimized float and bol comparison code gen 2026-04-24 09:41:45 +02:00
Irmen de Jong 6f9f31cd8a better const folding for multivalue assignments / vardecl inits in StatementReorderer 2026-04-24 07:18:01 +02:00
Irmen de Jong 7cd70acc01 implemented const folding of lmh() and divmod() 2026-04-24 06:02:16 +02:00
Irmen de Jong 2d3c20d347 c128: define golden ram area at $1300-$1BDF 2026-04-24 05:26:25 +02:00
Irmen de Jong b05bc9ac0e add IR peephole optimization for x * negative power of 2 2026-04-24 04:57:28 +02:00
Irmen de Jong 2589f953c3 fix IR peephole optimizer fault that incorrectly optimized 20-x expression 2026-04-24 04:49:09 +02:00
Irmen de Jong a40f9de9e6 fix IR codegen issue with DIVMOD and some other instructions 2026-04-24 04:22:29 +02:00
Irmen de Jong e7491a56ef todo 2026-04-23 02:50:56 +02:00
Irmen de Jong 2bf5d1406d make cx16/starszoom example fill the whole screen, and rotate 2026-04-22 19:52:11 +02:00
Irmen de Jong c32e7ee57b improve docs about operator precedence 2026-04-22 02:46:17 +02:00
Irmen de Jong a633b5a4b5 split Agent Prog8 language instructions 2026-04-21 22:13:03 +02:00
Irmen de Jong a5c078be14 fix inline warning 2026-04-21 06:27:40 +02:00
Irmen de Jong 547d21a42b added more redundant variable initialization removals 2026-04-21 06:13:39 +02:00
Irmen de Jong e2e0992d02 verafx: fix copy() and clear() unrolling 2026-04-21 03:55:28 +02:00
Irmen de Jong 10fd321537 use STZ in certain repeat loops on 65c02
remove unused memcopy16_up
2026-04-21 00:07:29 +02:00
Irmen de Jong fb26a7af3b redundant 2026-04-19 11:06:46 +02:00
Irmen de Jong 8592a3a200 use VarDecl builder instead of constructor 2026-04-19 02:26:50 +02:00
Irmen de Jong 930697dad5 using builder to improve massive lists of constructor params 2026-04-19 01:39:50 +02:00
Irmen de Jong a60ba27bad improve LSP 2026-04-18 23:30:12 +02:00
Irmen de Jong 87480b150a fix monogfx doublebuffer 2026-04-18 20:20:33 +02:00
Irmen de Jong 0cb9d408ff made some internal routines and variables in the library routines private 2026-04-18 19:55:10 +02:00
Irmen de Jong c784fd03fd remove internal_string_copy because strings can no longer be assigned by value that always needs strings.copy() 2026-04-18 19:29:05 +02:00
Irmen de Jong 5dcc11d67e try to avoid crash when importing modules twice (via symlink for instance). 2026-04-18 18:06:41 +02:00
Irmen de Jong e36a589e23 try to avoid crash when importing modules twice (via symlink for instance). 2026-04-18 12:56:30 +02:00
Irmen de Jong fe6a8f63a0 cx16: make gfx_lores actually use the kernal's screen mode 128 (keeps text layer)
also for gfx_hires and monogfx. fixes #220
2026-04-18 12:25:46 +02:00
Irmen de Jong 60e2a38060 fix IR read error on structs with typed pointer fields 2026-04-17 21:01:51 +02:00
Irmen de Jong d808818506 refactor grammar for signatures 2026-04-15 01:51:58 +02:00
Irmen de Jong 0f72bafeae improve code for in-place assignments to indexed pointers 2026-04-14 19:11:13 +02:00
Irmen de Jong c794d2a50b fix invalid IR opcode used for inplace assignments to memory targets 2026-04-14 15:32:12 +02:00
Irmen de Jong db84c375f1 implement a missing long pointer assignment case 2026-04-14 01:55:02 +02:00
Irmen de Jong 03fa6422b3 fix codegen for split array access using some peek/poke patterns 2026-04-13 21:43:39 +02:00
Irmen de Jong ad34633ca9 fix codegen for split array access using pointer + or - offset 2026-04-13 21:18:32 +02:00
Irmen de Jong d5eef79892 implement @nosplit pointer arrays 2026-04-13 20:41:57 +02:00
Irmen de Jong d5a53c5d21 implement missing division operations in VM 2026-04-13 18:48:35 +02:00
Irmen de Jong bd51296a33 implement V flag on comparisons in the virtualmachine 2026-04-12 20:47:56 +02:00
Irmen de Jong c0103f149e more general implementation of struct definition equality check see github #198 2026-04-12 20:43:19 +02:00
Irmen de Jong 86174e49c9 fix invalid ast node lookup in replacements 2026-04-12 16:41:00 +02:00
Irmen de Jong 0be336c8a8 lineclip test code 2026-04-12 16:36:10 +02:00
Irmen de Jong d836f48f38 updated prog8 instructions 2026-04-12 13:00:19 +02:00
Irmen de Jong 952d7b3162 fix faulty float optimization and ptrderef equality check 2026-04-11 23:55:59 +02:00
Irmen de Jong 5638eb1c53 asm optimizations: fix inconsistent line property, float copy optimization bug, Y register modification bug 2026-04-11 19:24:12 +02:00
Irmen de Jong d3f19bb438 fix lacking checks for IO registers in asm optimizer, caused incorrect instruction removals 2026-04-11 18:01:57 +02:00
Irmen de Jong be60021edc fix lacking checks for IO registers in asm optimizer, caused incorrect instruction removals 2026-04-11 04:18:22 +02:00
Irmen de Jong b2ed3b5934 add C128 MMU control registers to 'IO' registers ranges.
remove unused GoldenRam configuration stuff.
2026-04-10 16:52:28 +02:00
Irmen de Jong 59d0f7d49c 2-dimensional array support 2026-04-10 04:22:38 +02:00
Irmen de Jong 47700918cf preparing for improvements in pointer dereference grammar 2026-04-09 19:29:32 +02:00
Irmen de Jong db7edde2aa report multiple parse errors at once.
grammar rules improvements.
2026-04-09 07:06:03 +02:00
Irmen de Jong e2702d3e22 IRFileWriter and IRFileReader improvements 2026-04-09 05:06:39 +02:00
Irmen de Jong 74475d023b improving IR symbolic references 2026-04-09 03:54:51 +02:00
Irmen de Jong 9ae0623ad0 making MemoryAddress an Unsigned Int 2026-04-09 02:40:24 +02:00
Irmen de Jong 33b34b990e making RegisterNum type safe 2026-04-08 02:57:45 +02:00
Irmen de Jong 6dc96bb8f0 making IRInstruction parameters type safe 2026-04-07 20:15:55 +02:00
Irmen de Jong aeca6350da make IR instruction number order more pleasant to read 2026-04-07 14:39:28 +02:00
Irmen de Jong 6a340aa59d refactor void return value handling for multivalue results 2026-04-07 13:41:07 +02:00
Irmen de Jong 207650fbc2 fix multivalue pha/pla regression 2026-04-07 05:52:50 +02:00
Irmen de Jong 4fb3df977e fix correct evaluation of floats in multi-value returns 2026-04-07 05:41:27 +02:00
Irmen de Jong 9f742e1806 6502 codegen: handle floats as part of multi-value result 2026-04-07 04:50:23 +02:00
Irmen de Jong aca6c22098 IR codegen: handle floats as part of multi-value result 2026-04-07 04:31:17 +02:00
Irmen de Jong 4b45dae68a IR codegen: optimized array +/-/* in place 2026-04-07 04:12:44 +02:00
Irmen de Jong 0b68481fda optimized 6502 codegen for split array |=, &=, ^= 2026-04-06 23:27:25 +02:00
Irmen de Jong bba08f55de use compact loop to copy longs instead of 4x lda/sta pairs 2026-04-06 20:47:20 +02:00
Irmen de Jong 9e5df3d2d4 Optimize the IfExpression code generation to be more like regular if-else code (tighter branch code) 2026-04-06 20:25:41 +02:00
Irmen de Jong 5c1aa2307d for loops where the counter variable is unused in the loop body and count is constant -> simple repeat loops 2026-04-05 23:35:58 +02:00
Irmen de Jong 3129f5e071 fix IR return type assignment error 2026-04-05 12:44:06 +02:00
Irmen de Jong 04a8181c05 fix error when assigning str to ^^ubyte in multi-value assign 2026-04-05 12:26:20 +02:00
Irmen de Jong 27bf9c9a4c fix compiler crash when comparing str with number 2026-04-04 02:47:02 +02:00
Irmen de Jong 7658a0ab12 added strings.isxdigit()
fixed size bugs in several virtual string to number conv routines
2026-04-03 23:33:00 +02:00
Irmen de Jong 42d3340fe4 fix an msb() codegen crash when assigning back to word 2026-04-03 22:15:08 +02:00
Irmen de Jong 1100ab0d22 performance tweaks 2026-04-03 19:54:37 +02:00
Irmen de Jong 96eb3f0fb2 ImportFileSystem thread safe, IR performance tweaks 2026-04-03 06:53:08 +02:00
Irmen de Jong 1ed618c474 performance improvements in parser 2026-04-03 04:31:29 +02:00
Irmen de Jong e6c26587d6 improve Position accuracy 2026-04-03 03:42:17 +02:00
Irmen de Jong 4739bd087a IR: avoid redundant CMPI in if-expressions, remove dead stores 2026-04-02 23:41:03 +02:00
Irmen de Jong 92751d9285 document links in the LSP, remove repl/beanshell 2026-04-02 21:55:56 +02:00
Irmen de Jong 0792571b28 parse errors in the LSP 2026-04-02 02:29:38 +02:00
Irmen de Jong 511564dd1e symbol extraction in the LSP 2026-04-02 01:14:36 +02:00
Irmen de Jong 3da3d63eb4 more inlining support
fix invalid character in LSP
2026-04-01 19:04:03 +02:00
Irmen de Jong 3c859512a5 TDD inilining with parameters tests 2026-04-01 00:05:22 +02:00
Irmen de Jong 45c05522d5 fix inliner bug 2026-03-31 21:25:34 +02:00
Irmen de Jong db417ab9ce refactoring AstModification 2026-03-31 19:59:56 +02:00
Irmen de Jong c17a3aff5c refactoring AstModification 2026-03-31 15:37:55 +02:00
Irmen de Jong 6184a5004c wrapping child nodes mutable list away to avoid direct access that might corrupt it 2026-03-31 10:33:54 +02:00
Irmen de Jong 07772bddfd better zeropage tests and symboltable tweaks 2026-03-31 07:21:56 +02:00
Irmen de Jong 15bf4c7692 unit test helpers refactoring 2026-03-31 05:50:30 +02:00
Irmen de Jong f38c701658 some support for inlining multi-value returns (where there are no function parameters to deal with) 2026-03-31 04:42:34 +02:00
Irmen de Jong 10ce992b35 IR example metrics now count instructions not p8ir lines 2026-03-29 22:46:51 +02:00
Irmen de Jong 331e2b8f2b improve ast source position tracking 2026-03-29 19:49:42 +02:00
Irmen de Jong 05093e35c8 refactor inliner 2026-03-29 11:00:26 +02:00
Irmen de Jong 5fd11ca036 more consistent allowance of inline keyword 2026-03-29 10:15:51 +02:00
Irmen de Jong 5330069b53 disallow weird sizeof argument types 2026-03-29 09:50:13 +02:00
Irmen de Jong 5408a3ca68 fix compiler crash on certain pointer type struct fields
added new compiler options for debugging purposes
2026-03-29 08:25:53 +02:00
Irmen de Jong cecf49b8e3 IR: attempt to optimize negative comparisons by using direct status flag branches instead 2026-03-29 01:23:24 +01:00
Irmen de Jong 65c17b920a add txt.iso() to virtual target for source code compatibility and tests 2026-03-29 00:39:04 +01:00
Irmen de Jong 7666b72fea implement missing codegen for returning multivalue result of a subroutine call 2026-03-28 23:38:52 +01:00
Irmen de Jong bcd12a0fc7 improve handling of boolean literals in logical expressions with -noopt 2026-03-28 19:19:14 +01:00
Irmen de Jong dd0828a1fc fix a circular dependency in gfx_lores.p8 between line and plot 2026-03-28 15:35:56 +01:00
Irmen de Jong 770532a039 tweak line drawing routine for better accurracy
better agent instructions about asmsubs
2026-03-28 14:22:21 +01:00
Irmen de Jong 400149d5a3 standardize gradle project configurations across submodules 2026-03-28 10:08:47 +01:00
Irmen de Jong d6ed40af36 SymbolTable improvements 2026-03-28 04:14:26 +01:00
Irmen de Jong 570ea50a3b cleanups 2 2026-03-28 01:22:33 +01:00
Irmen de Jong 04b9f8e749 cleanups 2026-03-28 00:48:29 +01:00
Irmen de Jong 2bd7f3e210 improved SimpleAST optimizer 2026-03-27 01:13:38 +01:00
Irmen de Jong 00bae6e746 comment 2026-03-27 00:20:35 +01:00
Irmen de Jong f6d5e88f31 Fix test cases 2026-03-26 23:32:27 +01:00
Irmen de Jong 8d44a1b226 implemented bitmap text drawing for the virtual target (so monogfx.text() now works there) 2026-03-26 22:47:44 +01:00
Irmen de Jong a47be61812 fix bobs example, add fps counter to cobra example 2026-03-25 19:35:36 +01:00
Irmen de Jong 68226a8fcd Update Kotlin and dependencies to latest versions
- Bump Kotlin to 2.3.20 across all configurations.
- Upgrade `kotlin-result-jvm` to 2.3.1 in all modules.
- Update Gradle wrapper to 9.4.0.
- Add `poweroff_system()` function in virtual target symboldump
2026-03-25 17:51:01 +01:00
Irmen de Jong 2016883f6c compare p8ir line counts instead of file size 2026-03-21 02:44:21 +01:00
Irmen de Jong d4dd2f02e8 new example floatparse routine 2026-03-21 02:06:46 +01:00
Irmen de Jong bc959435ec fix missing const-evaluation for abs() and clamp()
add `poweroff_system()` for virtual target function
clarify CX16 usage and debugging tips
2026-03-20 02:31:17 +01:00
Irmen de Jong e5c6e4b854 add output size verification for compiled examples; include PET target in tests 2026-03-19 20:16:47 +01:00
Irmen de Jong 4294658d71 fix IR symbol lookup for deeply scoped variables 2026-03-18 23:31:39 +01:00
Irmen de Jong 0a7352de99 add disableCache option to SymbolTable to assist debugging and optimize behavior when -noopt is used 2026-03-18 23:12:48 +01:00
Irmen de Jong bb907aa2af fix chained aliasing errors 2026-03-18 21:52:42 +01:00
Irmen de Jong e5d74d55b5 vm memory optimizations 2026-03-18 18:02:13 +01:00
Irmen de Jong c291d7d4a8 const memory() support in struct initializers 2026-03-18 04:16:05 +01:00
Irmen de Jong d2633187a6 more work on making memory() const (6502) 2026-03-18 02:57:59 +01:00
Irmen de Jong ca56cf26c5 more work on making memory() const (virtual target only for now) 2026-03-18 02:20:50 +01:00
Irmen de Jong f72bec3c4a working on making memory() accepted as constant initializer value 2026-03-17 23:14:03 +01:00
Irmen de Jong 06b4ec600a more permanent solution for the struct name prefix bug when merging blocks, fixes #198 2026-03-17 23:09:52 +01:00
Irmen de Jong 410e330889 add --nostdlib compiler option to disable loading built-in standard libraries 2026-03-17 21:46:33 +01:00
Irmen de Jong 11f187bda8 implement signed % remainder operator for virtual target 2026-03-17 03:36:38 +01:00
Irmen de Jong a53e7c7050 fix divmod result when dividing by 0 2026-03-16 03:25:34 +01:00
Irmen de Jong e56ccdbc3a add signed divmod() support for virtual target 2026-03-16 01:19:02 +01:00
Irmen de Jong 51264267ad fix multi variable initialization from builtin function call that returns multiple values (such as divmod) 2026-03-16 00:45:37 +01:00
Irmen de Jong 8be0cd3c19 fix certain value copying through pointer dereferences 2026-03-16 00:10:47 +01:00
Irmen de Jong decfbfc8cc allow float constants even without float option enable 2026-03-15 22:46:35 +01:00
Irmen de Jong 652da4c692 fix some (not all) problems with directly returning multivalue returncalls 2026-03-15 22:33:17 +01:00
Irmen de Jong ce58f0e759 fix virtual target diskio.f_write(), added f_tell() and f_seek()
cx16 diskio.f_seek() and f_seek_w() now return success status
2026-03-15 21:04:06 +01:00
Irmen de Jong 8ba8efbc3e added sys.die() , a bare bones emergency exit function 2026-03-14 22:13:13 +01:00
Irmen de Jong 276121bfb3 updated Kate syntax file to fix string match problem 2026-03-14 19:06:17 +01:00
Irmen de Jong 5c9c6bd023 updated syntax files 2026-03-14 15:37:27 +01:00
Irmen de Jong 86f331aa39 thread locking tweaks 2026-03-14 00:13:56 +01:00
Irmen de Jong e61328b6d6 update Java dependency to 17, update results library version 2026-03-14 00:04:11 +01:00
Irmen de Jong 9502a6f590 fix invalid augmented assignment optimization, and a call to pop() that crashed a symbol prefix test because the call wasn't defined as a builtin 2026-03-13 22:08:36 +01:00
Irmen de Jong 01748517ae most often used long-copies now done with shorter loop instead of unrolled lda/sta 2026-03-13 21:21:38 +01:00
Irmen de Jong 3890191981 implement missing mul_long routine for long-long multiplication support 2026-03-13 20:32:42 +01:00
Irmen de Jong c20e5b788b implement missing square_long routine
improve agents system prompt file
2026-03-13 18:21:47 +01:00
Irmen de Jong fb3a001a99 attempting to optimize redundant variable initializations (STZs) 2026-03-12 21:38:28 +01:00
Irmen de Jong 04910ffbc0 add enum syntax (sugar for list of const decls) 2026-03-10 20:33:43 +01:00
Irmen de Jong caa991e478 IR: remove redundant add when pointer dereferencing 2026-03-08 21:31:31 +01:00
Irmen de Jong f9767a5b1b cx16: added sys.waitirq() that just does a WAI like waitvsync() but it is explicit about its behavior 2026-03-08 18:05:43 +01:00
Irmen de Jong 3b68741208 replace indexed pointer deref expressions with peek(ptr+index) 2026-03-08 12:59:34 +01:00
Irmen de Jong b8ef64139a avoid always including profile support routine in resulting asm 2026-03-08 03:16:17 +01:00
Irmen de Jong 1ad9e0fc46 implement missing struct field array indexing and faulty pointer dereferencing 2026-03-08 02:43:52 +01:00
Irmen de Jong ce244906ef added wavfile and adpcm library modules (adpcm only on X16) 2026-03-07 20:47:23 +01:00
Irmen de Jong 63ab79157f optimize palette module routines slightly to no longer use vaddr()
fix unused symbol warnings in bcd library module
2026-03-05 03:55:08 +01:00
Irmen de Jong 9ac0cfd14c fix palette.fade_step_colors() for color indexes >=128 2026-03-05 03:05:19 +01:00
Irmen de Jong 02c544bb62 fix cx16.getlfs() and add diskio.reuse_last_drive()
update cx16images.py to use improved quantization
2026-03-05 01:11:02 +01:00
Irmen de Jong 998d1ad446 IR: storezi now also takes an immediate offset argument, optimized some code gen to utilize that offset better insteads of doing separate ADDs 2026-03-04 01:12:01 +01:00
Irmen de Jong 89e38c6d42 IR: loadfield/storefield are now just loadi/storei 2026-03-03 21:17:27 +01:00
Irmen de Jong a326c6f079 adding multivalue vardecls and assignments 2026-03-03 00:06:48 +01:00
Irmen de Jong acf70d68ca todo 2026-03-02 02:54:16 +01:00
Irmen de Jong 17850d3bc1 fix certain long initialization type error 2026-03-02 02:14:31 +01:00
Irmen de Jong d03e49a92f implemented 6502 long loops with step >1 2026-03-01 03:13:54 +01:00
Irmen de Jong 62c5b531c5 implemented 6502 long loops with step 1 or -1 2026-03-01 02:06:18 +01:00
Irmen de Jong 8911f58bd2 fix IR long comparisons (used in for loops for instance) 2026-03-01 01:45:07 +01:00
Irmen de Jong da6e47d422 fix IR long comparisons (used in for loops for instance) 2026-03-01 01:17:22 +01:00
Irmen de Jong 10d80d0274 tinyc64 custom config: move SCRATCH_PTR to $04+$05, from $9b+$9c because $9b is used by JiffyDOS. see #217 2026-02-28 23:19:57 +01:00
Irmen de Jong 23b9a2792d C64: move SCRATCH_PTR to $04+$05, from $9b+$9c because $9b is used by JiffyDOS. Fixes #217 2026-02-28 22:55:44 +01:00
Irmen de Jong 0a52cd2cee changed math.crc16() to now also take an initvalue and xorout value, to make it more flexible in calculating various variants of CRC16 checksums 2026-02-28 18:13:00 +01:00
Irmen de Jong fedf342cee fix interned string problem with -profiling 2026-02-28 16:46:27 +01:00
Irmen de Jong 2bafc161d6 attempt to fix doc 2026-02-27 23:03:14 +01:00
Irmen de Jong d0c5e35f0a attempt to fix doc 2026-02-27 22:56:58 +01:00
Irmen de Jong 859a02fb0a adding profiling instrumentation support 2026-02-27 22:41:42 +01:00
Irmen de Jong 2a53dbc1f3 tweaks 2026-02-27 01:56:55 +01:00
Irmen de Jong 63cba4825a doc tweaks 2026-02-26 01:44:36 +01:00
Irmen de Jong 08e3652924 sgn() can look directly at msb if arg is a variable 2026-02-24 22:11:50 +01:00
Irmen de Jong 10796c09c7 cleanup weiord multi-return type handling more 2026-02-24 21:42:44 +01:00
Irmen de Jong a3cbf4c3db fix divmod doc 2026-02-23 22:01:59 +01:00
Irmen de Jong bdbdf6e5cd add lmh(longvalue) builtin function that returns the low, mid, hi (=bank) bytes of a long
symboldumps now also contain the builtin functions
2026-02-23 21:30:39 +01:00
Irmen de Jong 1b5dd980df optimize result register cases for mklong() and mkword() 2026-02-23 02:07:43 +01:00
Irmen de Jong f6b59c6832 optimize some result register cases for peekw() 2026-02-23 00:54:12 +01:00
Irmen de Jong fe8d904792 fixing result register assignment from builtin functions 2026-02-22 19:54:21 +01:00
Irmen de Jong 9736ac19d1 implementing multiple return values for builtin functions 2026-02-22 19:54:21 +01:00
Irmen de Jong 14abc1f0b7 clarify compiler errors output 2026-02-22 03:22:20 +01:00
Irmen de Jong effc7f1b56 optimize and fix diskio.status_code() also for C64 and PET 2026-02-21 11:07:57 +01:00
Irmen de Jong 093be9f2dd sys.push(), sys.pop() etc etc are now builtin functions again push() pop() to avoid storing value in temporary variables
this means that all of the syslib.p8 library files no longer contain all those stack related asmsubs
2026-02-21 02:11:34 +01:00
Irmen de Jong 9aff85f08a optimize diskio.status_code() size 2026-02-20 20:52:49 +01:00
Irmen de Jong f2077cb56f sqrt_long() no longer allocates a bunch of zeropage variables 2026-02-20 01:23:33 +01:00
Irmen de Jong 2a9ac45cad diskio: make f_open, f_open_w, and exists to read the command channel for success status rather than depending on flaky ST 2026-02-18 02:05:47 +01:00
Irmen de Jong e15452b110 doc 2026-02-17 21:49:35 +01:00
Irmen de Jong a64b586a43 Merge branch 'swap-statement' 2026-02-17 21:00:43 +01:00
Irmen de Jong 2613d45cd5 swap() is now a statement instead of a builtin function call 2026-02-17 20:56:21 +01:00
Irmen de Jong c25fbbccfb update kotlin to 2.3.10 2026-02-17 16:33:21 +01:00
Irmen de Jong 77f0cf8e89 defer stack doc and better error message for invalid range syntax 2026-02-16 23:00:50 +01:00
Irmen de Jong 74ca190ce0 long args call convention is to pass via parameter variable not R14R15 2026-02-15 17:36:09 +01:00
Irmen de Jong 6a0b22bb64 implement sqrt(long) 2026-02-15 17:11:31 +01:00
Irmen de Jong 07be7f0154 fix long argument @R0R1 register usage in regular subroutines 2026-02-15 14:54:47 +01:00
Irmen de Jong d1383813d2 version 12.1.1 2026-02-13 22:11:29 +01:00
Irmen de Jong 3bd2064c3a mention empty file issue 2026-02-12 22:10:53 +01:00
Irmen de Jong f95f568319 fix mflpt5 overflow error message 2026-02-12 02:29:10 +01:00
Irmen de Jong 5eb873b722 conv.str2long() added. alias problems detected. 2026-02-12 00:38:42 +01:00
Irmen de Jong 3f181b0ede allow alias to blocks 2026-02-10 22:51:05 +01:00
Irmen de Jong d6c8fc0c61 alias refactorings 2026-02-10 21:08:35 +01:00
Irmen de Jong 709ced1bca alias test program, replace alias chains 2026-02-10 21:08:35 +01:00
Irmen de Jong 3b16d08246 arrays can contain pointers too 2026-02-10 21:03:07 +01:00
Irmen de Jong b9a6deea25 implement ror / rol on ptr expressions 2026-02-08 21:20:13 +01:00
Andy De George 099514a2c0 Fix error output file path: Encode to URI (#214) 2026-02-06 22:09:58 +01:00
Irmen de Jong ed02b84f7d micro optimization for containment checks in compiler 2026-02-06 02:43:12 +01:00
Irmen de Jong 7d6e67e251 fix numeric type error when comparing undefined symbols 2026-02-04 23:55:08 +01:00
Irmen de Jong 4aa364925d todo 2026-02-02 23:02:21 +01:00
Andrew Gillham e5ae9ad4e0 Add PET 80 column support. (#211) 2026-02-02 23:02:01 +01:00
Irmen de Jong 6329388a4e skeleton 2026-01-31 19:39:43 +01:00
Irmen de Jong ac851a35bc implement FREADUY on pet, so that ubyte to float now works 2026-01-31 19:31:26 +01:00
Irmen de Jong bc0d6453ae revert 2026-01-30 23:40:45 +01:00
Irmen de Jong 8c65e0a537 attempt to create index in latex pdf 2026-01-30 23:38:26 +01:00
Irmen de Jong d415cf356f attempt to create index in latex pdf 2026-01-30 23:33:54 +01:00
Andrew Gillham 2bd74b8c44 Add an index and set some non-ASCII fonts to improve the resulting pdf. (#210)
* Add an index and set some non-ASCII fonts to improve the resulting pdf.

* Fix coroutines index interfering with code block

* Add genindex which is needed to get a link to the html index.
2026-01-30 22:03:40 +01:00
Irmen de Jong 88b48f58c9 fix string init error about string multiplication. fixes #209 2026-01-30 17:36:48 +01:00
Irmen de Jong 75accf4059 release 12.1 2026-01-28 23:45:42 +01:00
Irmen de Jong c3f9959891 fixed invalid replacement in optimization of if-statement.
better replacement errors.
fixes #208
2026-01-28 22:58:53 +01:00
Irmen de Jong ee492a1e9a some more optimized swap() code paths 2026-01-28 00:07:10 +01:00
Irmen de Jong 415f0fb071 pet: added bunch more diskio routines like directory(), delete(), rename() and list_filenames() 2026-01-27 01:07:08 +01:00
Irmen de Jong 8e7bf4227b pet: added diskio.save() and save_raw() 2026-01-26 22:32:46 +01:00
Irmen de Jong d2b743c296 pet: added diskio.load() and load_raw() 2026-01-26 02:38:40 +01:00
Irmen de Jong cb44e76626 swap 2026-01-25 19:14:05 +01:00
Irmen de Jong b2983e912d swap longs now uses R14+R15 as temporary storage instead of R0+R1 2026-01-25 17:02:47 +01:00
Irmen de Jong 10ae42ed59 suggest import for undefined block symbols, update github links 2026-01-25 05:45:33 +01:00
Irmen de Jong 5cbd4aafcc strings: added next_token() which mimicks C's strtok() routine 2026-01-25 00:09:52 +01:00
Irmen de Jong 4aa326d5ca diskio: added lf_start_list_having_prefix()
strings: added split()
2026-01-24 22:42:54 +01:00
Irmen de Jong 39b1bbcf58 pet32: added more missing routines in textio like column(), row() 2026-01-24 19:34:33 +01:00
Irmen de Jong 4661d3bada implement simple array element swap() 2026-01-24 18:41:25 +01:00
Irmen de Jong ab98f4a5e2 fix charset encoding error with merge. Fixes #207 2026-01-24 16:13:11 +01:00
Irmen de Jong b99b054a09 cx16: add missing extapi16 call numbers
tweak swap(long,long) and swap(ptr^^, ptr^^)
2026-01-24 11:51:42 +01:00
Irmen de Jong 5d5ad8a70e fix void/nonvoid assign target issue 2026-01-24 01:11:30 +01:00
Irmen de Jong 9a5edeebbc upgrade to kotlin 2.3.0 2026-01-24 00:29:45 +01:00
Irmen de Jong 3fb45a611a make math.gcd() use swap() builtin 2026-01-24 00:14:31 +01:00
Irmen de Jong 2e0db6f211 add swap() builtin for optimized value swaps without the need for a temporary variable 2026-01-23 23:17:10 +01:00
Irmen de Jong 51ac096a31 add a -warnimplicitcasts compiler option 2026-01-23 03:06:53 +01:00
Irmen de Jong dfad83650d add math.gcd() 2026-01-23 00:03:13 +01:00
Irmen de Jong 492cd686a0 avoid invalid pointer arithmetic in joined expresssions. Fixes #206 2026-01-22 22:25:48 +01:00
Irmen de Jong 561e05a764 decent error message for unsupported struct instance expressions. Fixes #205 2026-01-22 02:47:44 +01:00
Irmen de Jong f56037142b added petgfx module for pet32, c64, c128 for petscii block characters drawing (double resolution) 2026-01-22 02:17:04 +01:00
Irmen de Jong a41cb60328 pet: working boingball example, implement floats.GIVUAYFAY
cx16: improved floats.GIVUAYFAY to no longer depend on magic zp locations
2026-01-20 22:58:47 +01:00
Irmen de Jong ca3e4b161b add Amiga boing ball example, plus more pet syslib definitions, and pet diskio beginnings 2026-01-19 22:47:58 +01:00
Irmen de Jong 4971ebd41f pet32: added floats support! 2026-01-18 23:32:19 +01:00
Irmen de Jong e2276f000c fix alias issue when it targeted multi variable declaration 2026-01-18 19:48:37 +01:00
Irmen de Jong 520a12194e cx16: add new X16Edit rom entrypoint x16edit_loadfile_options2() that also takes starting line number 2026-01-18 19:10:06 +01:00
Irmen de Jong 6c61e1e5e8 fix alias target scoping problem 2026-01-17 21:39:39 +01:00
Irmen de Jong a385412e70 smaller floats.internal_long_to_float() 2026-01-17 20:38:30 +01:00
Irmen de Jong 928443469a strings: implement compare_nocase and compare_nocase_iso for 6502 2026-01-17 17:54:29 +01:00
Irmen de Jong 823f1cd6e2 strings: removed ncompare 2026-01-17 17:29:21 +01:00
Irmen de Jong 3009ddaaab strings: adding compare_nocase and compare_nocase_iso 2026-01-17 17:01:34 +01:00
Irmen de Jong bc0aecb1af cx16 diskio: way simpler solution for case insensitive file name listing 2026-01-17 01:02:38 +01:00
Irmen de Jong 573702111e attempt at improving compilation speed by caching scopedName 2026-01-16 22:46:04 +01:00
Irmen de Jong eaab2cfe5f version 12.1 2026-01-16 21:19:05 +01:00
Irmen de Jong 666285a002 add petsnd to symboldumps 2026-01-16 00:38:33 +01:00
Irmen de Jong d477e9b2bd pet32: added VIA registers (in 'pet' namespace) and petsnd module to play sound. 2026-01-16 00:15:04 +01:00
Irmen de Jong d774bad2b4 docs for new case routines 2026-01-15 22:06:05 +01:00
Irmen de Jong e3bb09d2a1 diskio: case insensitive file/dir listings only on CX16 target, and based on ISO encoding 2026-01-14 23:12:12 +01:00
Irmen de Jong 112bce0ac0 cx16: added ISO lowercase and uppercase routines to strings module 2026-01-14 22:07:24 +01:00
Irmen de Jong aac7d68455 fix watch mode to clear file cache every cycle 2026-01-14 20:16:33 +01:00
Irmen de Jong 620793011e way faster long to float conversion routine, fixes #202 2026-01-13 22:55:37 +01:00
Irmen de Jong cb4ffaa028 added case-insensitive pattern matcher strings.pattern_match_nocase()
added various case-insensitive versions of the file and directory listing routines in diskio (the ones that take an optional pattern)
2026-01-13 01:33:46 +01:00
Irmen de Jong 8c4944d703 optimized long and float copying through pointers 2026-01-12 00:19:21 +01:00
Irmen de Jong f5fbb5f930 implement some missing float copy 2026-01-11 22:06:21 +01:00
Irmen de Jong 40ce40db32 irq doc 2026-01-11 19:00:37 +01:00
Irmen de Jong ee556434bc doc 2026-01-11 14:12:16 +01:00
Irmen de Jong 5cd175d54f optimize successive additions/subtractions and multiplications (with const) into just a single add/sub, mul
optimize var = simpleexpression |  var += expression    -->   var = simpleexpression + expression  (for any augmented operator)
2026-01-11 01:30:04 +01:00
Irmen de Jong b51e116b63 optimize expression: uwordvar + 256 and variants to only manipulate msb 2026-01-10 22:50:33 +01:00
Irmen de Jong 5c7ac0efb7 IR: remove broken loadi/storei optimization 2026-01-10 22:23:01 +01:00
Irmen de Jong 34b228cfca fix peek/poke error with const offset 2026-01-10 20:58:16 +01:00
Irmen de Jong 2b26952044 better error 2026-01-10 19:06:59 +01:00
Irmen de Jong db38c27224 optimized peeks with a ubyte variable offset 2026-01-10 00:22:39 +01:00
Irmen de Jong 560013e58b optimized pokes with a ubyte variable offset 2026-01-09 22:36:04 +01:00
Irmen de Jong cdb41f4352 better errors when multiplying string or array with bogus value 2026-01-09 18:43:41 +01:00
Irmen de Jong 13cd68ba96 IR: fix LOADI.f peephole optimization 2026-01-09 03:49:55 +01:00
Irmen de Jong f69b293b7f optimized some more cases of poke and peek 2026-01-09 02:57:12 +01:00
Irmen de Jong d4bf0bf5b7 optimized simple cases of pokel() 2026-01-09 01:21:11 +01:00
Irmen de Jong 8c6a95f5e2 optimized simple cases of v = peekl() 2026-01-08 23:37:06 +01:00
Irmen de Jong 6301a8b040 optimize msb(long<<8/16/24) into single byte accesses (skip the whole shift) 2026-01-08 22:38:07 +01:00
Irmen de Jong daa9b40883 optimize lsb(long>>8/16/24) into single byte accesses (skip the whole shift) 2026-01-08 03:21:57 +01:00
Irmen de Jong aa045bb383 optimized certain word and long shifts to get the lsb/msb 2026-01-08 02:45:09 +01:00
Irmen de Jong 9d7049a659 optimized long>>8, long>>16, long>>24 2026-01-08 00:31:39 +01:00
Irmen de Jong bbfb2eb367 optimized longvar = lptr^^ 2026-01-07 23:30:35 +01:00
Irmen de Jong 447271f3f2 implemented missing byte ptr assignment 2026-01-07 22:42:53 +01:00
Irmen de Jong 78d6d2d59a breaking change: renamed R0R1_32 etc combined register parameters to just R0R1, R2R3, etc etc (_32 suffix is removed to make it more consistent with the other existing register names) 2026-01-07 21:56:16 +01:00
Irmen de Jong c6cd39b4ab slighty improved fix len() error message for pointer types 2026-01-07 21:37:07 +01:00
Irmen de Jong cd34c4eed0 fix len() error message for pointer types 2026-01-07 03:25:52 +01:00
Irmen de Jong 652b585ea4 code style 2026-01-07 00:48:45 +01:00
Irmen de Jong 2913fa47b2 fix pointer assignment TODO 2026-01-07 00:31:06 +01:00
Irmen de Jong d6e4175e21 fix msb(a+b), lsb(a+b) 2026-01-07 00:20:49 +01:00
Irmen de Jong 3a0add60fd optimize msb(lsw(longvar)) into @(&longvar+1) 2026-01-06 22:58:45 +01:00
Irmen de Jong bc4470aeda remove bsb() again - too confusing? 2026-01-06 22:39:04 +01:00
Irmen de Jong 97dade3655 fix setmsb() on long types 2026-01-06 22:11:58 +01:00
Irmen de Jong 54f23387d0 added bsb(long) builtin function that returns the bank byte of the long value (bits 16-23) 2026-01-06 20:56:03 +01:00
Irmen de Jong 77161e0f39 avoid separate definitions for list of simple builtin functions 2026-01-06 18:19:15 +01:00
Irmen de Jong 70d99bebb0 on c64/c128, txt.getclr() now always returns 0-15 (upper 4 bits are cleared). fixes #204 2026-01-05 21:50:38 +01:00
Irmen de Jong 75156f7dbd fix optimized long comparison against 0 2026-01-05 19:08:56 +01:00
Irmen de Jong 9827be0047 optimize sgn(integer) comparisons 2026-01-05 18:33:26 +01:00
Irmen de Jong 495dd526e1 comment correction 2026-01-04 23:04:33 +01:00
Irmen de Jong 3d20bc13b5 Virtual target: fix strings.right() and strings.slice() 2026-01-04 20:55:02 +01:00
Irmen de Jong 6028cc49ab simplify when into if-else, if possible 2026-01-04 19:39:38 +01:00
Irmen de Jong 23d3fb96b9 improved parsing rule of constdecl 2026-01-02 23:36:55 +01:00
Irmen de Jong 51503e054a IR: improve use of loadfield for msb/lsb of struct fields 2026-01-02 22:10:10 +01:00
Irmen de Jong 3f6177cbb8 improved 6502 codegen for lsb/msb of struct field 2026-01-02 21:36:11 +01:00
Irmen de Jong c1c88e0327 improved 6502 codegen for memory byte access into structs 2026-01-02 21:03:13 +01:00
Irmen de Jong 18ba25d6a4 IR: optimize double ADD/SUB 2026-01-02 20:24:35 +01:00
Irmen de Jong e74162671a clarify doc, fix possible poke() ast rewrite error 2026-01-02 19:11:57 +01:00
Irmen de Jong 2290308e06 fix invalid 6502 instructions in math.diff. Fixes #203 2026-01-02 01:08:50 +01:00
Irmen de Jong 82693cc3ee optimized lsb(msb(longvar)) which grabs the bank byte from a long 2026-01-01 21:39:34 +01:00
Irmen de Jong 50b8cae519 sys.save_prog8_internals() now also correctly saves the SCRATCH_PTR temp var. Moved a bunch of common sys routines into separate shared_sys_functions.p8 module file 2025-12-31 12:10:04 +01:00
Irmen de Jong 3a74931a61 c128: added c128.fast() and c128.slow() to enable/disable the CPU's 2 MHz mode.
Also added c128.is80(), set80(), set40() to check and set 40/80 column screen mode
2025-12-30 23:53:58 +01:00
Irmen de Jong c87e920c61 IR: stick all variable elements in <VARS> to improve the xml file structure a bit 2025-12-30 22:17:29 +01:00
Irmen de Jong 2c2de8bfb3 fix IR peephole optimizer index off by 1 error and make SSA blocks configurable (still defaults to yes in this version) 2025-12-30 18:58:42 +01:00
Irmen de Jong d386343fe7 fix romable error check for arrays 2025-12-30 02:26:01 +01:00
Irmen de Jong 5b32cfd172 fix some obscure errors, improve some error messages 2025-12-28 23:02:03 +01:00
Irmen de Jong 46dffcfb96 cx16: sysinit now explicitly makes vera border color also black (0) 2025-12-28 17:18:43 +01:00
Irmen de Jong b156c876f0 fix long expression typecast error 2025-12-28 01:24:54 +01:00
Irmen de Jong 71b66f506d fix asmsub register order crash when using longs + something else 2025-12-28 01:08:10 +01:00
Irmen de Jong 28d087b8b4 psg2 tweaks 2025-12-27 17:47:40 +01:00
Irmen de Jong a57815153d Merge branch 'psg2-module'
# Conflicts:
#	examples/test.p8
2025-12-27 17:12:05 +01:00
Irmen de Jong f910f73f28 added txt.iso2petscii() and txt.iso2petscii_str() 2025-12-26 17:55:07 +01:00
Irmen de Jong 6635515bf0 fix subtracting from str pointer, this fixes strings.endswith() for instance 2025-12-26 15:15:15 +01:00
Irmen de Jong cc0425a2c4 detect circular aliases, also fix error message for aliased function call with wrong number of args 2025-12-26 15:04:55 +01:00
Irmen de Jong c7052a183e fixing wrong error message about wrong arg count with alias 2025-12-25 23:49:03 +01:00
Irmen de Jong d9a0f3cb4a add line numbers to certain error messages 2025-12-25 22:30:05 +01:00
Irmen de Jong 80d6eb232d bool variables were not converted to constants if that was possible 2025-12-25 17:39:54 +01:00
Irmen de Jong d9ffb10eb5 added psg2 module (cx16 only) 2025-12-25 01:22:38 +01:00
Irmen de Jong 463d53345d more helpful min max error message for floats 2025-12-24 17:19:47 +01:00
Irmen de Jong 4b1063530e define cx16.VERA_PSG_BASE, VERA_PALETTE_BASE, VERA_SPRITES_BASE as long consts into Vera VRAM
returning a bool is no longer allowed if the sub return type is byte
2025-12-24 03:20:53 +01:00
Irmen de Jong 9266943e74 fix pointer assign type error with cast to uword 2025-12-24 01:18:23 +01:00
Irmen de Jong 1e3ae2cb1d IR: just use loadhay to get the result from CALLI 2025-12-23 19:07:51 +01:00
Irmen de Jong 55bc242e8b implemented in-place long negation and some missing long to float casts 2025-12-23 15:30:39 +01:00
Irmen de Jong aa3bbbb867 tweaks to wav streaming examples 2025-12-23 05:32:28 +01:00
Irmen de Jong 45ad0911df emudbg.cpu_cycles() now returns a long type instead of 2 separate words 2025-12-23 02:02:34 +01:00
Irmen de Jong 946def4613 IR: fix call() / CALLI return value handling 2025-12-23 00:39:14 +01:00
Irmen de Jong 3000c399bd cx16: add support for VIA timer IRQ in the irq routines 2025-12-22 21:37:09 +01:00
Irmen de Jong 1682400988 fix missing cx16 virtual register symbols in asm file (bool and long variants)
fix actually relocating all of them in the cx16 module
pet32 and c128 targets now also relocate them to ZP if there is space
2025-12-22 17:56:25 +01:00
Irmen de Jong 6ad435df1f mention main block size restriction 2025-12-22 05:28:55 +01:00
Irmen de Jong cd433b2111 c128: disable f-keys macros on startup 2025-12-22 00:23:21 +01:00
Irmen de Jong a50eebb369 fixed the balls example to also work on the monochrome pet32 target 2025-12-21 22:27:54 +01:00
Irmen de Jong 13d4af59c7 c64+c128: improved speed of txt.setchr, txt.getchr, txt.setclr, txt.getclr, txt.setcc 2025-12-21 22:23:17 +01:00
Irmen de Jong b6f4f2adb7 c64+c128: improved speed of txt.setchr and txt.getchr 2025-12-21 22:23:17 +01:00
Irmen de Jong e57d9f59a2 fix long 0 argument to asmsub with 32-bits combined virtual register to pass it in 2025-12-21 22:23:17 +01:00
Irmen de Jong 071d5dc0c5 pet32: improved speed of txt.setchr and txt.getchr 2025-12-21 22:23:16 +01:00
Irmen de Jong 4030a1b9e5 cleanup, animals example removed because it's superseded by the pointers/animalgame example now 2025-12-16 16:48:34 +01:00
Irmen de Jong 0217d05c68 IR: loadfield/storefield now accept offsets up to 65535 2025-12-16 14:56:11 +01:00
Irmen de Jong 8553f3c9f1 IR: loadfield is a better name 2025-12-16 12:57:45 +01:00
Irmen de Jong d157d03ea0 IR: optimize load+add+load into single loadm with offset (also store)
update gradle wrapper to 9.2.0
2025-12-16 12:17:52 +01:00
Irmen de Jong 1799b5f00c updated bundled zsmkit version to 2.8 2025-12-15 18:41:28 +01:00
Irmen de Jong 2ddb5e11b7 updated symboldumps 2025-12-13 02:12:00 +01:00
Irmen de Jong 3aa8b9fd12 turn prefix - numbers into negative numbers asap to avoid type problems later 2025-12-13 01:13:52 +01:00
Irmen de Jong 51300196e8 fix more long comparisons with arrays, fixes #196 2025-12-12 21:01:51 +01:00
Irmen de Jong f7b2f19cba remove restriction about long comparison with expression 2025-12-11 21:43:53 +01:00
Irmen de Jong 014a82a1ee always put all struct types as .struct in asm code to make them all accessible for size and offsets 2025-12-10 21:39:44 +01:00
Irmen de Jong 745cf3d958 IR: removed loadix/storeix instructions 2025-12-09 22:55:53 +01:00
Irmen de Jong c4aa681d58 IR: better name for loadfield/storefield instructions 2025-12-09 00:40:26 +01:00
Irmen de Jong feb0774bbd in benchmark-c routines, use same CIA timer as the original C code did so the program size is better comparable 2025-12-08 01:08:33 +01:00
Irmen de Jong 2ccfb2ac90 fix double evaluation (sign extension) of word to long assignment. Fixes #201 2025-12-07 22:23:59 +01:00
Irmen de Jong 2191c4b7d8 remove redundant expression assignment before multiplying certain words 2025-12-07 14:06:59 +01:00
Irmen de Jong 39c1cf0c3c fix diskio lf_start_list_dirs() and lf_start_list_files() not processing the pattern argument 2025-12-07 05:11:08 +01:00
Irmen de Jong c693be0dd6 fix byte subtract from long
fix IR register check error for %ir segments
2025-12-06 20:40:42 +01:00
Irmen de Jong 0f433055a7 fix pointer dereference division and modulus , fixes #199 2025-12-05 22:19:54 +01:00
Irmen de Jong 76c95ba6fa some more obscure inplace modifications implemented 2025-12-05 21:00:14 +01:00
Irmen de Jong bd272a8567 optimize some specialized cases of long << 2025-12-05 01:08:19 +01:00
Irmen de Jong b38fff76e9 hack to work around struct name prefix inconsistency
see github issue 198
2025-12-03 21:07:08 +01:00
Irmen de Jong 07b7639ff2 better error msg 2025-12-02 22:56:40 +01:00
Irmen de Jong 6871561c09 fix parent node error in sizeof() 2025-12-01 23:21:14 +01:00
Irmen de Jong 77a71138ad fix typo r8r0sl -> r8r9sl 2025-11-30 22:05:57 +01:00
Irmen de Jong 165f94bc93 fix long expression <0 / >0 comparison 2025-11-30 16:57:05 +01:00
Irmen de Jong b75090f928 fix some register clobbering with long operations 2025-11-30 16:44:36 +01:00
Irmen de Jong 62b0c82f93 implement long <=0 and long >=0 comparisons
make sure the adpcm benchmark doesn't use random memory contents
2025-11-30 16:25:58 +01:00
Irmen de Jong b1ef863c7f make $8000000 a valid long integer (-2147483648) 2025-11-26 23:10:59 +01:00
Irmen de Jong e78345410f fix long-- high word wrap bug 2025-11-26 20:13:17 +01:00
Irmen de Jong 8b86f97aaa Implement struct field long and signed word bitshifts. Fixes #194 2025-11-25 22:28:28 +01:00
Irmen de Jong 93135774e6 fix IR signed bitshift right 2025-11-25 22:16:28 +01:00
Irmen de Jong a64f27c6b0 add cx16.r0r1sl, cx16.r2r3sl, ... that memory-map signed longs on the virtual registers 2025-11-25 21:13:03 +01:00
Irmen de Jong 69ef63c96d tweaks 2025-11-24 22:23:40 +01:00
Irmen de Jong df1a2a1611 also optimize BRA+RTS into just BRA
release 12.0
2025-11-23 15:18:05 +01:00
Irmen de Jong d19a3af9ed change some single use float global constants to their asm proc 2025-11-21 21:35:51 +01:00
Irmen de Jong 352c11ad9f optimize float<>0 into sgn(float)<>0 2025-11-21 00:57:43 +01:00
Irmen de Jong 9504711fc7 IR/VM: SGN sets status bits 2025-11-19 21:37:04 +01:00
Irmen de Jong 590feda903 IR: fix sgn(float) register type error 2025-11-19 21:11:31 +01:00
Irmen de Jong 6e7e2922bf moved the float <> long cast routines to float.asm where the other cast routines are too 2025-11-19 18:45:32 +01:00
Irmen de Jong 01df1f0083 way more efficient implementation of internal_cast_as_long now using QINT 2025-11-19 18:32:40 +01:00
Irmen de Jong 397299bd1d implement 6502 codegen for casting float to long (super slow...) 2025-11-19 00:05:18 +01:00
Irmen de Jong c275aacd38 implement 6502 codegen for casting long to float 2025-11-18 23:26:12 +01:00
Irmen de Jong 6a6e18773e C64: key repeat is now enabled at program startup, to fall in line with the default key repeat behavior on the C128 and X16. 2025-11-18 21:09:13 +01:00
Irmen de Jong 99e037489b IR: added float<>long casts, cx16: blink_cursor extapi tested in test.p8 2025-11-17 23:13:56 +01:00
Irmen de Jong fb5290e17b cx16: added diskio.f_fatlba() 2025-11-15 20:17:26 +01:00
Irmen de Jong 818774ab84 added conv.hex2long(), added more new X16 extapi calls (rom 49+) 2025-11-15 17:52:34 +01:00
Irmen de Jong d667312acc Merge branch 'refs/heads/12.1-SNAPSHOT'
# Conflicts:
#	docs/source/todo.rst
#	examples/test.p8
2025-11-15 15:15:06 +01:00
Irmen de Jong 64d0cd87a8 diskio.f_seek() and f_tell() now use longs instead of separate words
also fix bug when returning multiple long values
2025-11-15 15:13:26 +01:00
Irmen de Jong 2fffbdde89 todo 2025-11-14 20:05:46 +01:00
Irmen de Jong dc8ea31c49 fix codegen error for a word array equality test 2025-11-13 21:18:04 +01:00
Irmen de Jong f4ead66e91 fix param name breakage in PET txt.setcc for ignored charcolor parameter 2025-11-12 22:00:30 +01:00
Irmen de Jong 314e7f5691 doc updates 2025-11-10 23:42:29 +01:00
Irmen de Jong da31465b7f added the missing smallstack to buffers module 2025-11-10 00:21:13 +01:00
Irmen de Jong 397a907088 fix handling and errors of using long addresses in memread/memwrite 2025-11-09 18:17:57 +01:00
Irmen de Jong 50c6962e1f fix symbol lookup crash 2025-11-09 15:10:10 +01:00
Irmen de Jong b7d1fb1342 translate address-of into + expression for non-const address ptrs too,
also IR optimization to use immediate arithmetic opcodes if possible
2025-11-09 01:36:34 +01:00
Irmen de Jong afb458a7da fix crash in long address-of 2025-11-08 22:24:37 +01:00
Irmen de Jong da3c7f267f improved identifier const value handling if types differ 2025-11-08 20:34:51 +01:00
Irmen de Jong b7ba7c50b1 handle &ptr[offset] for non-uword ptr 2025-11-08 20:31:28 +01:00
Irmen de Jong bdbfe7048b updated library symboldumps 2025-11-08 00:21:53 +01:00
Irmen de Jong 79039b66d4 beta6 2025-11-07 23:40:03 +01:00
Irmen de Jong 833e463525 String indexing bound check now includes the terminating 0 character. Also fix negative indexes on strings.
fixes #190
2025-11-07 23:20:44 +01:00
Irmen de Jong 6611e4e092 improve error message 2025-11-07 01:22:41 +01:00
Irmen de Jong 1f31cb18e4 IR: fix missing source lines in p8ir file 2025-11-06 00:39:31 +01:00
Irmen de Jong bc8ba252a5 made Position line, col, endcol all 1-based
added a precise (but slow) back face culling routine to the cobra-mk3 example
2025-11-05 00:25:43 +01:00
Irmen de Jong c353dd40bf put on..call jumplist in correct scope, fixes #197 2025-11-03 23:46:49 +01:00
Irmen de Jong 928ef6bbaa fix on..call parse problem, also struct name cannot be a keyword 2025-11-03 21:21:07 +01:00
Irmen de Jong 45dde856c6 upgrade to kotlin 2.2.21 2025-11-02 20:08:59 +01:00
Irmen de Jong e1ccef4e89 sort the library routines better, updated result of crc32 benchmark 2025-11-02 16:58:49 +01:00
Irmen de Jong 4d3f0ec223 sizeof(string) is now defined 2025-11-01 21:19:30 +01:00
Irmen de Jong b73c958c4a ir immediate syntax fixes 2025-11-01 16:55:00 +01:00
Irmen de Jong 2eac457e1c clarify string assignment (or rather, the lack thereof) 2025-11-01 00:40:52 +01:00
Irmen de Jong 815ef7e654 add check for not yet implement long expression comparisons 2025-11-01 00:26:36 +01:00
Irmen de Jong 0cd8c4f87e add strings.ncopy and nappend (length limited) 2025-10-31 21:22:15 +01:00
Irmen de Jong b02a8ed954 strings can no longer be assigned by-value. Use strings.copy() instead. Fixes #189 2025-10-31 19:22:40 +01:00
Irmen de Jong b1e07f3fdb better error when trying to use a const pointer (which is not supported yet) 2025-10-30 20:58:21 +01:00
Irmen de Jong fc8727f81e allow pointer to pointer assignment in cast codegen, fixes #191 2025-10-30 19:35:44 +01:00
Irmen de Jong ec728bad52 fix certain float array assignment, fixes #193 2025-10-30 01:45:25 +01:00
Irmen de Jong a5e827e40f implement some more long array operations 2025-10-30 01:20:59 +01:00
Irmen de Jong 34061c5a63 implement inplace bitwise operations on long struct fields 2025-10-28 23:44:34 +01:00
Irmen de Jong 9c2bcab4a5 fix more ptr/long issues 2025-10-28 23:08:12 +01:00
Irmen de Jong 2f07f41664 detect self-referencing aliases 2025-10-23 21:24:14 +02:00
Irmen de Jong 7027304597 put some upper bounds on more internal compiler loops 2025-10-23 20:37:44 +02:00
Irmen de Jong ee75333891 implement more long assignments through pointers 2025-10-21 22:55:46 +02:00
Irmen de Jong 6a70fb0480 deal with invalid sqrt results (negative argument), allow sqrt of longs (like floats) 2025-10-21 21:01:03 +02:00
Irmen de Jong ebc738b132 'hack' to allow unsigned long constants such as $ffffffff to be assigned to longs without casts 2025-10-20 00:33:40 +02:00
Irmen de Jong e5939be0bd some more long operations implemented 2025-10-19 23:03:17 +02:00
Irmen de Jong 0c0affd1bf cx16 diskio.load_size() now returns full long size. Fixes #184 2025-10-19 21:18:46 +02:00
Irmen de Jong c7158fd968 implement more long operations on struct fields 2025-10-17 01:55:11 +02:00
Irmen de Jong de2f3f0d0d tweak TODO messages for longs 2025-10-16 23:20:34 +02:00
Irmen de Jong c0286e3349 added txt.size() to return text screen width and height in 1 call. Also fixed txt.width/height on the C128 (where SCREEN reports 1 less for them...) 2025-10-16 00:33:14 +02:00
Irmen de Jong 513ee25432 beta5 2025-10-15 18:29:36 +02:00
Irmen de Jong be74290ddc many more TODO messages now log proper source positions 2025-10-15 17:58:40 +02:00
Irmen de Jong a36501a9ed fix long bitwise expressions temp register usage 2025-10-14 02:57:48 +02:00
Irmen de Jong ee5d33a230 fix long if-expressions temp register usage 2025-10-14 02:16:42 +02:00
Irmen de Jong a8fd66cfdb fix long==0 long!=0 register usage 2025-10-14 01:49:42 +02:00
Irmen de Jong f5ce744748 undo the math crc param optimization that now causes the footgun warning when you import math. + doc fix about arithmetic expressions 2025-10-14 00:31:29 +02:00
Irmen de Jong 68066acdec changed (and fixed) msb(long) and lsb(long) 2025-10-13 21:34:03 +02:00
Irmen de Jong 6286035d89 support long +/- number in expressions 2025-10-13 02:50:48 +02:00
Irmen de Jong 9a37eb9146 save A and Y when storing longs 2025-10-13 02:12:07 +02:00
Irmen de Jong 307796f115 fixed some bugs in optimizing long values 2025-10-12 23:15:42 +02:00
Irmen de Jong e962431139 added bcd.addtol()/subfroml() for in-place long calculations
fix long overflow messages, IR register type error
2025-10-12 22:08:10 +02:00
Irmen de Jong b7620abc9a longs: fix msw() and lsw() 2025-10-12 19:49:36 +02:00
Irmen de Jong d2719d23f5 C128: adjust MEMTOP value to $C000 during runtime (41 Kb of available space because Basic ROM is banked out) 2025-10-12 15:02:36 +02:00
Irmen de Jong d69eead6d8 fix abs(long), mklong(), mklong2(), peekl(), pokel() 2025-10-12 14:17:27 +02:00
Irmen de Jong 6db3611d93 fix typecast error when assigning pointer to long 2025-10-12 12:44:28 +02:00
Irmen de Jong a84320c7e2 add sgn(long) support, fix sgn() result type in IR 2025-10-12 12:22:32 +02:00
Irmen de Jong dfc720557c fix some more long hex value comparisons 2025-10-12 04:40:50 +02:00
Irmen de Jong 32149d073a bitwise long exprs now use R12-R13 instead of R2-R3 2025-10-12 03:02:09 +02:00
Irmen de Jong fc38be6376 fix a const long value hex asm mistake, fix conv.str_l(0) empty output 2025-10-12 01:52:35 +02:00
Irmen de Jong 13f6efc1d1 long +/- long now use R12-R15 instead of R0-R3 2025-10-12 01:35:02 +02:00
Irmen de Jong 8296002887 fix combined reg asm name 2025-10-12 01:34:00 +02:00
Irmen de Jong 424b89f357 longs now returned in R14+R15 instead of R0+R1 2025-10-12 00:27:17 +02:00
Irmen de Jong 4f5590fbff doc 2025-10-11 21:37:59 +02:00
Irmen de Jong 598e70c49a allow negative values on poke and pokew without an explicit cast 2025-10-11 16:39:36 +02:00
Irmen de Jong a6d051b496 update syntax files 2025-10-11 16:15:34 +02:00
Irmen de Jong 796d3242e1 optimize word pointer indexing and fix long pointer indexing assignment (pokel) 2025-10-11 15:59:27 +02:00
Irmen de Jong 1e8ff6f82a warning in doc about problems when using long + R0/R1 together 2025-10-11 15:36:57 +02:00
Irmen de Jong 07bb5c36bd avoid fallback JSR peek for common case pointer+offset 2025-10-11 04:45:03 +02:00
Irmen de Jong 7e26ecb0b6 allow 'then' in if-expressions to separate condition and result value 2025-10-10 23:26:53 +02:00
Irmen de Jong 0c59ad70d4 fix aliased pointer deref problem 2025-10-10 22:13:24 +02:00
Irmen de Jong 53ce688cc5 fix pointer type check for R0-R15 subroutine arg 2025-10-10 00:54:52 +02:00
Irmen de Jong bb8b44d9d0 fix missing byte to long assignment, add c-bench-64 comparison 2025-10-10 00:01:54 +02:00
Irmen de Jong 51ae32d23e fix up todo 2025-10-09 21:14:06 +02:00
markjreed c873fac0dc feat: point doc source links to matching version (#179)
* feat: point doc source links to matching version

* fix: formatting, remove debug
2025-10-09 20:03:46 +02:00
Irmen de Jong f0a67fff8a added missing byte to long type assignment 2025-10-09 02:52:33 +02:00
Irmen de Jong f85ccd837d tweak conv.str_l() so that it properly reuses the conv.string_out buffer 2025-10-08 22:33:03 +02:00
Irmen de Jong 396fcbc927 implement missing long typecasts 2025-10-07 17:46:10 +02:00
Irmen de Jong 0f564b301d implement peekl() and pokel() 2025-10-07 00:53:00 +02:00
Irmen de Jong f4f34fc2ed added symboltable into CompilationResult because it might be useful to inspect in tests 2025-10-07 00:26:43 +02:00
Irmen de Jong f7639cb78f implement long comparisons > and <= 2025-10-06 23:42:40 +02:00
Irmen de Jong f5f5aef722 implement long comparisons < and >= 2025-10-06 22:30:17 +02:00
Irmen de Jong d6e30d8468 fix signed word and long cmp() 2025-10-06 22:05:34 +02:00
Irmen de Jong 37afdf5a18 tweak antlr grammar to improve parsing performance 2025-10-06 01:28:33 +02:00
Irmen de Jong 5eb7074172 fix gfx_lores and gfx_hires disc() inaccurracy 2025-10-05 23:21:19 +02:00
Irmen de Jong 9aff280d10 fix monogfx.disc() inaccurracy 2025-10-05 23:03:53 +02:00
Irmen de Jong 44741a8e32 fix c64 graphics.disc() inaccurracy 2025-10-05 22:57:39 +02:00
Irmen de Jong 37535f2913 optimize charfade example, added textspotlight example 2025-10-05 21:18:47 +02:00
Irmen de Jong ec9475c308 use pointer arithmetic instead of raw peeks and pokes 2025-10-05 18:38:01 +02:00
Irmen de Jong b961ce97d6 add -libdump and -libsearch compiler options 2025-10-05 17:07:55 +02:00
Irmen de Jong 4ed92d71a7 remove "@split" tag
The default is to split word arrays. If you need your word array to not be split, use @nosplit on the array.
2025-10-05 17:06:21 +02:00
Irmen de Jong 3e1386a987 remove the -dontsplitarrays compiler option
it was still there for backward compatibility reasons with really old prog8 code. If you need a word array to be not split, just use @nosplit on the array.
2025-10-05 14:44:29 +02:00
Irmen de Jong 4195e3968a remove needless library module imports in unit tests 2025-10-05 13:10:02 +02:00
Irmen de Jong 961095bfec fix output path for shadow jar 2025-10-04 23:31:52 +02:00
Irmen de Jong 3ea8ca59b7 beta 4 now with support for long values 2025-10-04 22:55:18 +02:00
Irmen de Jong 71ffbe2ba7 document the long type 2025-10-04 22:33:43 +02:00
Irmen de Jong e63921009c added math.mul32(), verafx.muls now returns long 2025-10-04 21:54:53 +02:00
Irmen de Jong db1aa3f257 math.crc32() now returns the crc value as a long 2025-10-04 17:40:49 +02:00
Irmen de Jong 8abdb837b2 fix long equality comparisons 2025-10-04 17:21:39 +02:00
Irmen de Jong cdeabd4b66 only * and / 2025-10-04 05:13:18 +02:00
Irmen de Jong efff74c0f1 added sys.pushl() and sys.popl() 2025-10-04 03:05:50 +02:00
Irmen de Jong 0e177cb531 added cbm.RDTIML and cbm.SETTIML wrappers 2025-10-04 02:00:24 +02:00
Irmen de Jong 35b921b062 added bcd module for decimal addition and subtraction using BCD mode 2025-10-03 23:36:17 +02:00
Irmen de Jong a7d98e43b8 cmp(long, long) 2025-10-03 22:41:59 +02:00
Irmen de Jong 845ee2dd83 smaller code for several long operations 2025-10-03 21:25:13 +02:00
Irmen de Jong f9b0bfe31b implement rol() and ror() on longs (also rol2 and ror2 and abs) 2025-10-03 01:22:24 +02:00
Irmen de Jong f303d15628 fix long equality checks 2025-10-03 01:22:24 +02:00
Irmen de Jong 67f7ffa52d multi value returns with longs 2025-10-03 01:22:24 +02:00
Irmen de Jong 88c5d9783a long params and return values 2025-10-03 01:22:24 +02:00
Irmen de Jong e7fc0360ad long bitwise operator expressions 2025-10-03 01:22:24 +02:00
Irmen de Jong cd1862dd9f fix signed long shift right 2025-10-03 01:22:24 +02:00
Irmen de Jong 045c4909a8 long equality comparisons 2025-10-03 01:22:24 +02:00
Irmen de Jong f1bfe619b2 avoiding endless loop in optimizer 2025-10-03 01:22:24 +02:00
Irmen de Jong e0107bacbd implement long << >> expressions 2025-10-03 01:22:24 +02:00
Irmen de Jong b3bd2a6a09 fixed a bunch of long type handling 2025-10-03 01:22:24 +02:00
Irmen de Jong ff1f58e022 implement simple + / - long expressions 2025-10-03 01:22:24 +02:00
Irmen de Jong 557b12668d implement print_ulhex(long, prefix) 2025-10-03 01:22:24 +02:00
Irmen de Jong b058f1c7c2 implement mklong(a,b,c,d) and mklong2(w1,w2) 2025-10-03 01:22:24 +02:00
Irmen de Jong 3e07b6ca70 adding long arrays 2025-10-03 01:22:24 +02:00
Irmen de Jong d66dc664de work on longs 2025-10-03 01:22:24 +02:00
Irmen de Jong a2b9d78cf3 start with introducing LONG datatype (32 bits signed integer) 2025-10-03 01:22:24 +02:00
Irmen de Jong 44f70da113 upgrade to JDK 17 for the build process (required by Gradle 9) 2025-10-03 00:18:55 +02:00
Irmen de Jong c87eaf576d buildfix and update to Gradle 9.1.0 2025-10-03 00:11:52 +02:00
Irmen de Jong c09b1395f6 IR: add a unit test for the SSA basic block change 2025-10-01 22:49:51 +02:00
Irmen de Jong d6a8201291 IR: fix SQRT reg1 type 2025-10-01 20:28:38 +02:00
Irmen de Jong 4187f97f7a IR: rename <CODE> to <CHUNK> , put the code lines in a new sub node <CODE> for improved xml structure 2025-10-01 19:32:05 +02:00
Irmen de Jong 9d3b2f12fd IR code blocks now better SSA basic blocks (ending with single branch instruction) 2025-10-01 19:08:44 +02:00
Irmen de Jong 87c1bbbf40 readme about LSP 2025-10-01 01:15:00 +02:00
Irmen de Jong a7ad6abdb9 Merge branch 'languageServer'
# Conflicts:
#	examples/test.p8
2025-09-30 22:14:03 +02:00
Irmen de Jong a611406020 IR: add compilerversion attribute to p8ir file 2025-09-30 22:07:04 +02:00
Irmen de Jong 75da38224d IR: make LSIG,MSIG,CONCAT instruction set flags to skip cmp #0 afterwards (if msb(x)>0) 2025-09-30 21:48:57 +02:00
Irmen de Jong 8d6f3301c8 conv.any2uword() return values have been changed to be more useful and convenient
now returns both the actual value and the number of characters, and the return values for the virtual target now matches the others.
2025-09-30 20:44:02 +02:00
Irmen de Jong 86b52a1c5e fix endless loop in rewriting type of const long values 2025-09-29 22:28:13 +02:00
Irmen de Jong 2c8b1c2022 moved cx16.cpu_is_65816() to sys.cpu_is_65816(). It know also does proper detection on the C64 and C128 like on the X16, because those two computers can also have this CPU via a SuperCPU expansion. 2025-09-29 21:37:26 +02:00
Irmen de Jong ab1f065752 first setup of LSP languageserver 2025-09-27 15:27:37 +02:00
Irmen de Jong 2c7256a443 support assignment to indexed pointer targets 2025-09-27 14:52:04 +02:00
Irmen de Jong 97420b28e5 preparing to support assignment to indexed pointer targets 2025-09-27 11:03:55 +02:00
Irmen de Jong 1467c7039d fix pointer deref ast printer 2025-09-27 10:42:55 +02:00
Irmen de Jong d319badc6c default 0 for long type 2025-09-25 21:32:23 +02:00
Irmen de Jong 65d6c1c438 fix IR instruction R/W usage counter 2025-09-25 01:50:27 +02:00
Irmen de Jong abeefb5655 improved pointer[0] 2025-09-24 22:26:09 +02:00
Irmen de Jong 50fecbcebe c64 sprite multiplexer WIP 2025-09-24 21:11:08 +02:00
Irmen de Jong 4fe8b72d42 fix broken uword comparison and asm peephole optimization 2025-09-24 02:42:26 +02:00
Irmen de Jong f3b060df51 no longer save Y register when loading value through ZP pointer LDA (zp),Y 2025-09-23 22:59:01 +02:00
Irmen de Jong 09d1cb6925 fix crash when indexing on a label or subroutine name
working on multiplexer
2025-09-23 20:07:52 +02:00
Irmen de Jong 54fa72fa98 added sys.waitrasterline() routine like sys.waitvsync() but wait for a given raster line
optimize uword <= $xx00 into msb(uword)<$xx
2025-09-23 01:09:54 +02:00
Irmen de Jong fd62fe7511 fix crash on invalid type cast added to ptr deref expression ('.' operator) 2025-09-22 23:54:01 +02:00
Irmen de Jong bfb34dff62 fix recursive var decl error in case of some pointer derefs 2025-09-22 23:45:59 +02:00
Irmen de Jong 817b623596 optimize uword >= $xx00 into msb(uword)>=$xx 2025-09-22 22:59:56 +02:00
Irmen de Jong f6dbeb1f63 working on a more complex c64 sprite multiplexer 2025-09-22 21:58:12 +02:00
Irmen de Jong c4b9bdd33f proper pointer array initializer size checking, nicer sprite movement in simplemultiplexer 2025-09-22 20:07:38 +02:00
Irmen de Jong 68e0d5f1b5 add sys.set_rasterline on c64 and c128 targets as well (cx16 already had it) 2025-09-21 01:36:43 +02:00
Irmen de Jong 4939e3df55 add sys.update_rasterirq, more robust sei/cli handling, added simple c64 sprite multiplexer example 2025-09-21 00:28:33 +02:00
Irmen de Jong 19f19f3880 doc and opening borders 2025-09-20 21:44:48 +02:00
Irmen de Jong ad0c767ea8 %breakpoint! introduced to place after an assignment to make it parse correctly 2025-09-20 00:46:15 +02:00
Irmen de Jong ed5f4d5855 fix missing subroutine argument list check 2025-09-19 05:35:03 +02:00
Irmen de Jong c2f5d37486 new cx16/charfade.p8 example 2025-09-19 04:44:08 +02:00
Irmen de Jong 231b50dacb optimize certain word multiplication with bit shifting if it's a power of 2 2025-09-18 20:57:26 +02:00
Irmen de Jong a71895cbe8 optimize pointer.field += 1 into pointer.field INC/DEC 2025-09-18 19:27:36 +02:00
Irmen de Jong a8bede17b2 fix defer() with the arena allocator ("return values are evaluated before the defer is executed") 2025-09-17 23:59:32 +02:00
Irmen de Jong f6c8e693a5 add offsetof() 2025-09-17 23:30:15 +02:00
Irmen de Jong 9461e4088c fixed the hashtable example and workarounds for misbehaving defer in allocators 2025-09-17 22:53:01 +02:00
Irmen de Jong efd73fd10d implement some more in place pointer operators 2025-09-17 18:19:03 +02:00
Irmen de Jong ddf6e84a1a fix type checks for wrong pointer types in pointer array initalizer and assignment 2025-09-16 21:18:29 +02:00
Irmen de Jong 633d6c34e2 add support for struct pointers and short-form initializers in arrays and assignments 2025-09-16 20:37:50 +02:00
Irmen de Jong 6e7fbc6683 fix crash when invalid struct name is used in pointer decl 2025-09-15 20:39:21 +02:00
Irmen de Jong 124ea1230b fix vm to understand struct instances in arrays 2025-09-14 19:04:01 +02:00
Irmen de Jong 8b48a295b6 allow struct initializers to occur in array literals 2025-09-14 18:16:46 +02:00
Irmen de Jong d285d37fdb fix clobbers syntax in symboldumper 2025-09-13 21:47:52 +02:00
Irmen de Jong 8bb927b483 fix compiler crash with on..call statement in nested scope 2025-09-13 06:44:49 +02:00
Irmen de Jong 1af4cd0d63 fix struct initializer error checking 2025-09-12 19:55:12 +02:00
Irmen de Jong db2f28c4cd add struct and pointer benchmark to benchmark program (btree, subscore=654, total 7420)
fix nullpointer in array initalizer
2025-09-12 17:09:44 +02:00
Irmen de Jong 5d9fbd2ccc fix doc build 2025-09-11 22:53:57 +02:00
Irmen de Jong 7efc709538 release 12.0 BETA 1 2025-09-11 22:50:34 +02:00
Irmen de Jong 79419a98d0 add if-expression versions for the conditionals if_cc, if_cs, if_vc etc 2025-09-11 01:57:30 +02:00
Irmen de Jong 1c77d5d5e7 avoid creating inferredtype instances all the time 2025-09-10 20:43:15 +02:00
Irmen de Jong c6854e22a3 fix wrong operand order for in place pointer subtraction 2025-09-10 17:19:03 +02:00
Irmen de Jong 83acc2f285 fix pointer variable overwriting when used in expression 2025-09-10 16:40:45 +02:00
Irmen de Jong 6de95f7a3b new static struct initializer syntax ^^Node : [1,2,3]
avoids confusion with function calls
2025-09-10 13:47:12 +02:00
Irmen de Jong 82839a2d82 fix alias error and byte to word assignment error 2025-09-09 15:05:02 +02:00
Irmen de Jong e5fc9b3132 fix 6502 pointer arithmetic optimization that led to increased code size 2025-09-09 14:06:41 +02:00
Irmen de Jong ced4c5944a fix broken optimization for wordvar - value expressions 2025-09-09 08:05:51 +02:00
Irmen de Jong d4c460072b don't place library and subroutine parameter pointers in ZP automatically, to save ZP space 2025-09-09 06:25:40 +02:00
Irmen de Jong 0b9384b556 fix typecasted byte-to-word pointer assignment, some more asm optimizations 2025-09-09 05:56:55 +02:00
Irmen de Jong 6c3277e3e3 fix more alias bugs 2025-09-09 02:28:05 +02:00
Irmen de Jong d9ff1eb38a fix internal error in on..call 2025-09-08 19:30:32 +02:00
Irmen de Jong e178097735 support more struct instance assignments via memcopy() 2025-09-08 13:18:50 +02:00
Irmen de Jong a1ab8ed208 fixing alias bugs 2025-09-07 22:52:13 +02:00
Irmen de Jong 6ababbf8f4 support more struct instance assignments via memcopy() 2025-09-07 00:29:18 +02:00
Irmen de Jong 79629befc1 fix pointer arithmetic error in struct instance assignments (that get turned into a memcopy call) 2025-09-06 00:28:59 +02:00
Irmen de Jong 8022c0772a oops 2025-09-05 20:37:19 +02:00
Irmen de Jong 8ad2b4638b fix and optimize nodes[i].field (it could clobber the actual temporary pointer value in a scratch register) 2025-09-05 20:02:37 +02:00
Irmen de Jong 3a0392df8a there's a problem with the struct initializer syntax 2025-09-05 00:18:42 +02:00
Irmen de Jong beb28b061d fix non-struct pointer deref code bug
fix gradle 9 compatibility issue (fixes #175)
2025-09-04 21:30:20 +02:00
Irmen de Jong c39acc5031 fix mistakes 2025-09-04 00:30:00 +02:00
Irmen de Jong f54a29c415 small 6502 pointer arithmetic expression rewrite that produces smaller code 2025-09-03 23:54:10 +02:00
Irmen de Jong 783b111059 pointer to uword casts should not be removed
optimized addUnsignedByteOrWordToAY a tiny bit (but needs more)
2025-09-03 23:09:11 +02:00
Irmen de Jong fb286f8b54 optimize operatorDereference() to not always use a zp scratch pointer 2025-09-03 20:30:10 +02:00
Irmen de Jong 5999110e3f avoid using temporary pointer to access struct fields if a simple Y indexed cpu instruction can be used 2025-09-03 18:37:56 +02:00
Irmen de Jong 52a757ea78 todo 2025-09-02 00:42:46 +02:00
Irmen de Jong 28df08eea8 introduce P8ZP_SCRATCH_PTR temporary zp pointer to avoid clobbering W1,W2 2025-09-01 23:56:31 +02:00
Irmen de Jong 79505308ba optimize indexed pointer code a bit more 2025-09-01 22:18:17 +02:00
Irmen de Jong a7e9d8e14b fix struct field offset calculations 2025-09-01 18:57:02 +02:00
Irmen de Jong 08f3abe5bf prefer to put pointer variables into zeropage (add implicit @zp) 2025-08-31 17:06:14 +02:00
Irmen de Jong 3ef09d7d9a use LOADFIELD instruction more instead of an extra explicit ADD
add implicit @zp to pointer variables if they don't have a preference
2025-08-31 15:53:44 +02:00
Irmen de Jong a9142b9ce5 slightly optimize certain pointer indexing calculation, fix invalid deref optimization 2025-08-31 13:40:28 +02:00
Irmen de Jong 13e6f64d3b implement missing struct pointer indexing codegen 2025-08-31 12:20:38 +02:00
Irmen de Jong 4a1256c772 optimizing some pointer codegen for indexed derefs 2025-08-30 21:20:14 +02:00
Irmen de Jong ff9bec90ec fix struct pointer array indexing field dereferencing
the pointers/sorting example now actually works on the 6502 too
2025-08-30 12:24:30 +02:00
Irmen de Jong a6fee1e510 fixing deref() 2025-08-30 07:04:01 +02:00
Irmen de Jong 80538f101e Merge branch 'master' into structs6502 2025-08-29 21:42:03 +02:00
Irmen de Jong aee53b14c7 avoid costly multiplications to get indexed pointer address 2025-08-29 20:18:26 +02:00
Irmen de Jong 5eb2fc8d86 fix a bad pointer arithmetic optimization 2025-08-29 19:36:57 +02:00
Irmen de Jong 98f91bbf88 another attempt to get correct docs chapters 2025-08-29 02:50:09 +02:00
Irmen de Jong b48b36ef18 another attempt to get correct docs chapters 2025-08-29 00:52:29 +02:00
Irmen de Jong 221a093e5f optimize some pointer arithmetic, fix pointer arithmetic for ptr-value 2025-08-28 23:08:06 +02:00
Irmen de Jong 2ca1820d4e Merge branch 'master' into structs6502 2025-08-28 21:55:46 +02:00
Irmen de Jong d58737d5be use RST chapter notation to attempt to fix PDF chapters 2025-08-28 21:46:09 +02:00
Irmen de Jong b52cee3154 use RST chapter notation to attempt to fix PDF chapters 2025-08-28 21:19:16 +02:00
Irmen de Jong 9a76941e10 fix invalid optimization for ptr-value 2025-08-28 20:13:02 +02:00
Irmen de Jong 0285a4cce1 avoid needless pointer arithmetic multiplication by struct size 1 2025-08-27 21:50:09 +02:00
Irmen de Jong 5a3aa1bd25 optimized IR to return a constant value: use RETURNI 2025-08-26 22:54:11 +02:00
Irmen de Jong 0f79351de9 support word size indexing on typed pointers 2025-08-25 22:58:48 +02:00
Irmen de Jong 3cdb25ce8e fix invalid string comparisons being generated for regular pointer value comparison 2025-08-24 16:19:42 +02:00
Irmen de Jong b7193bd0c6 update examples to use typed pointers where appropriate
(found 2 regressions that still need to be handled)
2025-08-24 15:17:47 +02:00
Irmen de Jong 10ff6a0095 Merge branch 'master' into structs6502 2025-08-24 14:34:15 +02:00
Irmen de Jong d30f58004e converting untyped to typed pointers in custom target libraries 2025-08-24 14:27:25 +02:00
Irmen de Jong 17bdb22e4f converting untyped to typed pointers in c64,c128,pet32 libraries 2025-08-24 14:21:51 +02:00
Irmen de Jong a68209be37 converting untyped to typed pointers in cx16 libraries 2025-08-24 14:13:02 +02:00
Irmen de Jong 7b40eade44 added txt.rvs_on() and txt.rvs_off(), added txt.color() support for virtual target 2025-08-24 13:29:29 +02:00
Irmen de Jong 8a717c74b9 sorting lib symboldumps 2025-08-24 13:07:10 +02:00
Irmen de Jong aa72ded21e add sorting module to symboldump, moved shared cbm textio routines to shared module 2025-08-24 13:05:38 +02:00
Irmen de Jong 8e53c83844 optimize certain ptr+value expression on 6502 2025-08-24 05:46:49 +02:00
Irmen de Jong e2a2db1256 converting untyped to typed pointers in libraries 2025-08-22 22:47:19 +02:00
markjreed 2afd2d4dae Make PET PLOT routine more efficient (#174)
* feat: take advantage of KERNAL vars to implement PLOT

* fix: tabs

* fix: update TBLX too, so cursor change sticks after output

* fix: formatting
2025-08-22 21:28:21 +02:00
Irmen de Jong fad17cc094 support a few other simple cases of struct instance assignment 2025-08-21 00:04:30 +02:00
Irmen de Jong f93d957999 proper warning for struct instance assignment (not yet supported) 2025-08-20 20:35:29 +02:00
Irmen de Jong 8db0344cee Merge branch 'master' into structs6502
# Conflicts:
#	codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt
2025-08-19 23:10:15 +02:00
Irmen de Jong 32e531f951 test 2025-08-19 23:09:33 +02:00
Irmen de Jong a4769702f9 todo 2025-08-19 23:06:04 +02:00
Irmen de Jong cf19fb8df1 fix 6502 struct type and field name prefixing and datatype references to stale structs from stale Symboltable 2025-08-19 20:47:37 +02:00
Irmen de Jong 79b8bb5c9f Merge branch 'master' into structs6502 2025-08-19 01:12:50 +02:00
Irmen de Jong fc5889ec0b kotlin 2.2.10, kotest 2025-08-19 01:04:24 +02:00
Irmen de Jong 369303c46d fix register clobbering in pointer deref 2025-08-18 23:36:35 +02:00
Irmen de Jong d65670cc7b fix 6502 address-of for array-indexed pointers (pointer arithmetic) 2025-08-18 20:24:39 +02:00
Irmen de Jong f74eeaee0f fix IR address-of for array-indexed pointers (pointer arithmetic) 2025-08-18 03:24:32 +02:00
Irmen de Jong 826fb3e9c2 implemented assign indexed ptr byte 2025-08-17 13:21:31 +02:00
Irmen de Jong a3d7b8a899 fix detection of string comparisons (make it aware of new pointer types equivalent to STR) 2025-08-16 17:04:59 +02:00
Irmen de Jong 0cc36ed6e4 pointer TODO's all as stub methods in the PointerAssignmentsGen class 2025-08-16 16:21:06 +02:00
Irmen de Jong 976bd52972 docs dark mode 2025-08-16 11:32:24 +02:00
Irmen de Jong 4a8d5def84 code cleanups, pointer TODOs, docs dark mode 2025-08-16 11:25:18 +02:00
Irmen de Jong 2f60716082 6502 struct allocation to asm file, struct name and field prefixing (maybe unneeded...) 2025-08-16 01:49:22 +02:00
Irmen de Jong 729efb04e1 fix code size regressions 2025-08-14 23:59:59 +02:00
Irmen de Jong 4ea8b4d445 fix unknown field test and redundant errors 2025-08-14 21:01:25 +02:00
Irmen de Jong e800c165f9 fix 6502 inplace pointer variable assignment 2025-08-14 20:38:18 +02:00
Irmen de Jong fd9bd23449 6502 statementreorderer: str -> ^^ubyte 2025-08-13 18:45:29 +02:00
Irmen de Jong 8880ed1393 fix address-of struct fields 2025-08-08 23:08:47 +02:00
Irmen de Jong f7fde070ca fix boolean pointer condition in if expression 2025-08-08 22:15:58 +02:00
Irmen de Jong 5ada80779d Merge branch 'refs/heads/master' into structs6502
# Conflicts:
#	examples/test.p8
2025-08-07 21:25:07 +02:00
Irmen de Jong 8972235a0e fix missing peekbool() and pokebool() code gen 2025-08-07 21:22:48 +02:00
Irmen de Jong e56f533e38 more basic pointer inplace operations 2025-08-07 00:36:47 +02:00
Irmen de Jong 324fb7dbf7 more basic pointer inplace operations (float)
basic pointers unit test now passes
2025-08-06 22:26:23 +02:00
Irmen de Jong 44285b9b5d more basic pointer inplace operations 2025-08-06 00:32:15 +02:00
Irmen de Jong a68f477d61 Merge branch 'master' into structs6502
# Conflicts:
#	docs/source/todo.rst
#	examples/test.p8
2025-08-05 23:29:58 +02:00
Irmen de Jong ae9f99448e fix pointer subtract arithmetic 2025-08-05 23:23:29 +02:00
Irmen de Jong 7c0fb10197 fix bug: VM MULR float error, another pointer dependency checker error 2025-08-05 22:00:05 +02:00
Irmen de Jong 9e85571a7b fix pointer variable usage detection in other block 2025-08-05 17:39:22 +02:00
Irmen de Jong 9e10c15e2e working on 6502 pointer inplace assignments 2025-08-04 23:32:17 +02:00
Irmen de Jong 6bd7752bac working on 6502 pointer dereferencing 2025-08-04 20:22:13 +02:00
Irmen de Jong 83ec437e8a testpointers unit test now also for 6502 targets
implementing first simple pointer operations
pointer vars also allocated in ZP for dontcare
2025-08-03 22:12:03 +02:00
Irmen de Jong 4a1d05dd46 first 6502 codegen results 2025-08-03 16:10:00 +02:00
Irmen de Jong aa324e355a remove 6502 pointer check, TODOs for pointer assignments 2025-08-03 13:28:39 +02:00
Irmen de Jong 5cb8bcead7 todo 2025-08-03 00:54:43 +02:00
Irmen de Jong bbd06c0c99 implement peekbool/pokebool on 6502, fix float assignment register error 2025-08-02 21:38:29 +02:00
Irmen de Jong 651830ea82 update syntax files 2025-08-02 21:00:16 +02:00
Irmen de Jong c70146f1dc Merge branch 'master' into structs
# Conflicts:
#	docs/source/todo.rst
2025-08-02 19:26:54 +02:00
Irmen de Jong d4e83b28bb error messages and trying to improve support for struct allocs in arrays
added sorting example
2025-08-02 19:22:58 +02:00
Irmen de Jong bc58a25765 allow sizeof(^^type) to return the size of a pointer 2025-08-02 11:33:15 +02:00
Irmen de Jong 38645022c9 actually disallow ^^str 2025-08-02 05:49:12 +02:00
Irmen de Jong 647cd0fbe1 fix pointer[i].field compiler crash 2025-08-02 05:29:16 +02:00
Irmen de Jong ea8935a346 doc 2025-08-02 00:02:29 +02:00
Irmen de Jong 7ea80babfc todo 2025-08-01 23:38:49 +02:00
Irmen de Jong dee761a99e fix compiler crash on certain pointer assignments 2025-08-01 22:22:43 +02:00
Irmen de Jong 88ee7a8187 fix expected outcome of function call arg type pointer test 2025-08-01 00:23:10 +02:00
Irmen de Jong eb8b408b82 fix countries[2]^^ = 0 compiler crash 2025-07-31 02:03:18 +02:00
Irmen de Jong 3d10882f57 fix ast printing 2025-07-30 23:42:45 +02:00
Irmen de Jong 1988496512 correct commit hash 2025-07-30 01:08:22 +02:00
Irmen de Jong 88b074c208 pointer types should just be uwords in IR 2025-07-30 01:07:37 +02:00
Irmen de Jong c4c5636a81 fixing array indexing on pointers 2025-07-29 23:41:38 +02:00
Irmen de Jong c39d570b72 make more use of ISubType interface itself rather than casting it to StructDecl all the time 2025-07-29 22:59:31 +02:00
Irmen de Jong 4ccd7f9f3a improve docs about recursion 2025-07-29 22:49:24 +02:00
Irmen de Jong 1c9c5aeef7 todos 2025-07-28 23:29:18 +02:00
Irmen de Jong 23ad540aa5 fix IR codegen type error on array pointer dereference 2025-07-28 20:25:56 +02:00
Irmen de Jong 08810c2749 proper error message for unsupported &&subroutine 2025-07-27 23:44:24 +02:00
Irmen de Jong a52966f327 rollback implicit casts to boolean in struct initializers and function call arguments 2025-07-27 03:27:26 +02:00
Irmen de Jong 624220e9a3 fix boolean struct field as if conditional 2025-07-27 01:58:18 +02:00
Irmen de Jong 842b11ed9e struct docs 2025-07-27 00:00:40 +02:00
Irmen de Jong 82267b3f56 Merge branch 'master' into structs
# Conflicts:
#	compiler/test/codegeneration/TestVariables.kt
#	docs/source/_static/symboldumps/skeletons-c128.txt
#	docs/source/_static/symboldumps/skeletons-c64.txt
#	docs/source/_static/symboldumps/skeletons-cx16.txt
#	docs/source/_static/symboldumps/skeletons-pet32.txt
#	docs/source/_static/symboldumps/skeletons-virtual.txt
#	docs/source/todo.rst
#	examples/test.p8
2025-07-26 12:43:13 +02:00
Irmen de Jong 67fb45a55b don't produce invalid boolean initalization error. Fixes #173 2025-07-26 12:35:23 +02:00
Irmen de Jong 11186f1dbe make sure that the virtual target -emu (vm) only runs the actual .p8ir file (fixes #172)
added emudbg.console_nl()
2025-07-26 11:19:01 +02:00
Irmen de Jong 0116fac201 release 11.4.1 2025-07-24 23:00:10 +02:00
Irmen de Jong 817f4f8e7c Merge branch 'master' into structs
# Conflicts:
#	compiler/src/prog8/compiler/Compiler.kt
#	compiler/src/prog8/compiler/astprocessing/AstExtensions.kt
#	compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt
#	docs/source/todo.rst
#	examples/test.p8
2025-07-24 22:27:29 +02:00
Irmen de Jong 866313209b fixed zp vars 0 initialization 2025-07-24 00:17:31 +02:00
Irmen de Jong 28e351daab new library routine skeletons 2025-07-22 18:18:15 +02:00
Irmen de Jong 893e16d814 replace str or ubyte[] param and returnvalue type into ^^ubyte rather than uword 2025-07-21 22:59:14 +02:00
Irmen de Jong 33470c47fc last changes to virtual diskio to make untyped pointers typed 2025-07-21 22:13:36 +02:00
Irmen de Jong 63f7b87572 Merge branch 'master' into structs 2025-07-21 22:11:34 +02:00
Irmen de Jong e2901cca1b fix virtual diskio save_raw() 2025-07-21 22:10:50 +02:00
Irmen de Jong ce8006992a changing virtual diskio to use typed pointers 2025-07-21 22:10:04 +02:00
Irmen de Jong 0b5413ad83 Merge branch 'master' into structs
# Conflicts:
#	docs/source/todo.rst
#	examples/test.p8
2025-07-21 20:53:06 +02:00
Irmen de Jong dd7adde387 fix virtual diskio.f_write 2025-07-21 20:52:11 +02:00
Irmen de Jong 23058b51a1 started changing libs to typed pointers 2025-07-21 20:50:33 +02:00
Irmen de Jong 2f90c53ad0 started changing libs to typed pointers 2025-07-20 23:59:59 +02:00
Irmen de Jong c3be7ab4b3 fix if expression type problems with pointers 2025-07-18 23:44:55 +02:00
Irmen de Jong a9b8fbc6c6 Merge branch 'master' into structs
# Conflicts:
#	examples/test.p8
2025-07-18 22:37:36 +02:00
Irmen de Jong 720988ae72 proper warnings for using pure builtin functions as a statement (discarding the result)
swallow a defer warning for a very common use case
2025-07-18 22:37:07 +02:00
Irmen de Jong b0981a5fae pointers no longer implicitly converted to boolean in expressions, to be consistent with how integers are handled in conditionals
adding particles fountain examples
2025-07-18 01:43:35 +02:00
Irmen de Jong ea5deeefbd new links to Codebase64 website 2025-07-17 23:06:39 +02:00
Irmen de Jong 054c98da7c add link to extra prog8 compilation targets 2025-07-15 00:17:04 +02:00
Irmen de Jong dc434d034a fix address-of identifier alias replacement stripping array index away 2025-07-14 23:54:26 +02:00
Irmen de Jong a4a1b563aa sdks 2025-07-14 21:54:56 +02:00
Irmen de Jong 3f34b83e0d sdks 2025-07-14 21:54:40 +02:00
Irmen de Jong 9c63ef39c7 fix pointer test 2025-07-07 23:09:45 +02:00
Irmen de Jong 9f6106452e revert & to untyped pointer, added && for typed pointer address-of 2025-07-07 16:17:07 +02:00
Irmen de Jong f9fbfe30e3 fix &x +/- offset pointer arithmetic expression 2025-07-07 13:11:57 +02:00
Irmen de Jong 9a9bf170c6 Merge branch 'master' into structs 2025-07-06 23:17:00 +02:00
Irmen de Jong 7dd64b4f13 fix 'cpa' instruction generated in certain boolean assignment, must be 'cmp' 2025-07-06 22:43:19 +02:00
Irmen de Jong b6c0bac96f identified problems with pointer array as parameter 2025-07-06 20:33:20 +02:00
Irmen de Jong 8ede098154 fix pointer array initialization 2025-07-06 19:42:54 +02:00
Irmen de Jong 2a4a3b786e cleanup error message for currently unsupported deref'd pointer assignments 2025-07-06 14:59:42 +02:00
Irmen de Jong b4e0a2019e fixed assignment to a[i]^^ 2025-07-06 13:38:22 +02:00
Irmen de Jong e14c3f8b59 code cleanups 2025-07-06 00:52:37 +02:00
Irmen de Jong c81f76226d Merge branch 'master' into structs 2025-07-06 00:37:58 +02:00
Irmen de Jong edc353cc24 more kotlin 2.2 settings 2025-07-06 00:37:15 +02:00
Irmen de Jong dcce519c69 Merge branch 'master' into structs
# Conflicts:
#	.idea/libraries/KotlinJavaRuntime.xml
#	build.gradle.kts
#	gradle.properties
2025-07-06 00:07:16 +02:00
Irmen de Jong 0a16dcafc0 update kotlin and gradle wrapper 2025-07-06 00:01:24 +02:00
Irmen de Jong 54d41b7f6f fixed a[i]^^ 2025-07-05 23:54:08 +02:00
Irmen de Jong 0541b84d09 Merge branch 'master' into structs 2025-06-29 16:34:32 +02:00
gillham 1b420f7fe7 Add a preliminary external custom target for the Foenix F256 family of modern retro computers. (#171) 2025-06-29 11:14:34 +02:00
Irmen de Jong 6a9a82ff9d doc 2025-06-27 18:14:36 +02:00
markjreed aa36e6b19f flesh out C128-specific KERNAL calls (#170)
* flesh out C128-specific KERNAL calls

* fix: typo in comment

* fix: typo in comment

* fix: include return values of INDCMP

* fix: rearrange return values of INDCMP
2025-06-27 18:13:26 +02:00
Irmen de Jong 51cb6aad50 add c128.PRIMM() 2025-06-27 17:39:31 +02:00
Irmen de Jong b5ce409592 clarify booleans 2025-06-26 20:06:36 +02:00
Irmen de Jong 2119817e4a Merge branch 'master' into structs 2025-06-24 21:14:53 +02:00
Irmen de Jong 1efdfe8ea1 much nicer colors in the bubbleuniverse example 2025-06-23 21:25:05 +02:00
Irmen de Jong 67d4180825 lib 2025-06-20 22:01:29 +02:00
Irmen de Jong be31e190d2 shuffle arguments of 64tass command so the additional assembler options from custom targets actually work 2025-06-19 22:33:50 +02:00
Irmen de Jong a68cf3c812 fix animalgame node reuse 2025-06-18 23:34:47 +02:00
Irmen de Jong c2bf9024f8 start writing docs about structs and pointers, update syntax files with ^^ 2025-06-18 19:00:18 +02:00
Irmen de Jong bd72eaad4c Merge branch 'refs/heads/master' into structs
# Conflicts:
#	examples/test.p8
2025-06-18 17:53:20 +02:00
Irmen de Jong b5d1575823 added boolean typed versions of the cx16.r0-r15 virtual registers 2025-06-18 00:05:10 +02:00
Irmen de Jong 1d306e5cdc moved new animalgame 2025-06-17 23:21:54 +02:00
Irmen de Jong b137164fe6 allow str assigned to ^^ubyte without an explicit cast 2025-06-17 18:29:48 +02:00
Irmen de Jong 67d4ad50e1 add new animals example (that uses a pointer tree) 2025-06-17 01:08:36 +02:00
Irmen de Jong c71066af4c fixing name lookup issue 2025-06-16 22:15:51 +02:00
Irmen de Jong 6f0a0981bd fixing name lookup issue 2025-06-16 00:21:54 +02:00
Irmen de Jong 49a4d9ba37 allow str as struct field type (^^ubyte) and strings in struct initializers 2025-06-15 00:29:59 +02:00
Irmen de Jong fcdfa741b9 Merge branch 'master' into structs
# Conflicts:
#	compiler/src/prog8/compiler/astprocessing/AstPreprocessor.kt
2025-06-14 21:07:23 +02:00
Irmen de Jong e3e395836d fix splitting of array decl and initializer for non numeric types 2025-06-13 23:31:56 +02:00
Irmen de Jong 3bab177d50 working on pointers/binarytree example 2025-06-13 23:20:15 +02:00
Irmen de Jong 12abafb917 Merge branch 'master' into structs
# Conflicts:
#	docs/source/todo.rst
#	examples/test.p8
#	gradle.properties
2025-06-12 00:11:58 +02:00
Irmen de Jong 8dc2e47507 fix partial unused code removal in vm target 2025-06-11 23:31:29 +02:00
Irmen de Jong 0be90dedf2 check for split word array as argument 2025-06-11 21:35:36 +02:00
Irmen de Jong daf7c3357c better detection of missing return statement
preparing 11.4
2025-06-09 16:01:56 +02:00
Irmen de Jong e6bab3ceeb IR: adding LOADFIELD and STOREFIELD instructions 2025-06-09 01:41:45 +02:00
Irmen de Jong 59387b2ae8 Merge branch 'master' into structs
# Conflicts:
#	docs/source/todo.rst
#	examples/test.p8
2025-06-07 20:28:23 +02:00
Irmen de Jong e8795859c5 added sorting library for target virtual
added sorting routines that sort a values array together with the keys array
optimized gnomesort a little
2025-06-07 19:42:40 +02:00
Irmen de Jong bebe60b687 fix compiler crash on for x in wordvar, add sys.get_as_returnaddress() 2025-06-05 16:10:40 +02:00
Irmen de Jong ddceec364e optimized coroutines library 2025-06-04 21:34:32 +02:00
Irmen de Jong f8f20440d3 allow pointer to be treated as uword value in augmented assignments 2025-06-03 21:33:35 +02:00
Irmen de Jong f8722faa4e Merge branch 'master' into structs
# Conflicts:
#	examples/test.p8
2025-06-03 21:15:19 +02:00
Irmen de Jong d067fa4b73 added strings.find_eol() 2025-06-03 21:09:44 +02:00
Irmen de Jong 26fbbf48a4 adapt new antlr visitor to the pointer/struct additions 2025-06-03 01:28:58 +02:00
Irmen de Jong d5cc414221 Merge branch 'master' into structs
# Conflicts:
#	codeOptimizers/src/prog8/optimizer/StatementOptimizer.kt
#	compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt
#	compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt
#	examples/test.p8
2025-06-02 20:52:50 +02:00
Irmen de Jong b5e51ab937 cleaner timings output 2025-06-02 19:30:25 +02:00
Irmen de Jong 552e55c29f fix missing cmp #0 when asmsub call is part of a boolean expression 2025-06-02 19:22:00 +02:00
Irmen de Jong a228908c1a fix wrong address calculation for &wordarray[i] where i is a variable 2025-06-02 03:13:23 +02:00
Irmen de Jong 15fc3b6c04 replace old antlr2kotlin code with the new visitor-based translator 2025-06-02 01:56:07 +02:00
Irmen de Jong 0456badd02 creating on a new visitor-based antlr to kotlin translator 2025-06-02 01:18:07 +02:00
Irmen de Jong d28f154f1c Merge branch 'master' into structs
# Conflicts:
#	examples/test.p8
#	parser/src/main/antlr/Prog8ANTLR.g4
2025-06-01 17:53:41 +02:00
Irmen de Jong 399cf5118d we will get a 11.4 version first before structs will land 2025-06-01 17:47:06 +02:00
Irmen de Jong a87f2640d3 fixed signed byte comparisons in case of overflowing values 2025-06-01 14:01:25 +02:00
Irmen de Jong a90ef274d7 fix word*128 codegen.
added cx16/landscape.p8 example that draws procedurally generated landscapes.
found bug in signed byte comparisons with overflow.
2025-05-31 05:27:19 +02:00
Irmen de Jong 1c02179c5c refactor loadIndexReg() 2025-05-30 21:39:17 +02:00
Irmen de Jong 77584493fd support a.b.ptr[i]^^.value as expression (RHS) 2025-05-30 20:28:10 +02:00
Irmen de Jong a36709e638 Merge branch 'master' into structs
# Conflicts:
#	compiler/src/prog8/compiler/Compiler.kt
2025-05-30 12:39:23 +02:00
Irmen de Jong 341778ba67 added -timings flag 2025-05-30 12:38:16 +02:00
Irmen de Jong 8d63cce749 working on deref after array indexing 2025-05-30 11:30:49 +02:00
Irmen de Jong ec50b5a007 homebrew info 2025-05-30 03:43:03 +02:00
Irmen de Jong 8e7bbcdbe0 clear syntax error for yet unsupported deref after array indexing 2025-05-29 21:14:38 +02:00
Irmen de Jong 37ecdc47b3 allow ptr1^^ = ptr^^ (replaces it with memcopy) 2025-05-29 16:34:47 +02:00
Irmen de Jong 112ca3cc53 allow sizeof(&thing), add sys.SIZEOF_POINTER 2025-05-29 15:58:29 +02:00
Irmen de Jong 33b3a1664c replace sizeof(list^^) with sizeof(List) to allow it to compile. Same with simple pointers. 2025-05-29 14:13:42 +02:00
Irmen de Jong 8a0c02e264 Merge branch 'refs/heads/master' into structs
# Conflicts:
#	codeCore/src/prog8/code/target/NormalMemSizer.kt
#	codeCore/src/prog8/code/target/VMTarget.kt
#	compiler/src/prog8/compiler/BuiltinFunctions.kt
#	compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt
#	examples/test.p8
2025-05-29 13:42:16 +02:00
Irmen de Jong 31d84c8921 doc 2025-05-29 13:35:20 +02:00
Irmen de Jong 34bedbeef1 optimize byte modulus (%) routine with repeated subtraction instead of using full division 2025-05-29 13:26:04 +02:00
Irmen de Jong 3b1b0985c1 make sizeof(float) work, so you don't have to use sys.SIZEOF_FLOAT anymore etc.
define sys.SIZEOF_FLOAT in terms of sizeof(float)
2025-05-29 12:38:03 +02:00
Irmen de Jong e40ace9dea todo 2025-05-29 01:35:53 +02:00
Irmen de Jong 4c0e6e2640 fix split/nosplit pointer arrays, replace ubyteptr^^ with @(ubyteptr), fix double dereference 2025-05-29 00:36:55 +02:00
Irmen de Jong 08b314c37d IR: fix various register type mismatches 2025-05-28 22:15:07 +02:00
Irmen de Jong 86da9d3c7e assigning to plain pointer with array indexing 2025-05-28 18:08:53 +02:00
Irmen de Jong 4e61e25c02 Merge branch 'master' into structs
# Conflicts:
#	compiler/test/TestTypecasts.kt
2025-05-27 23:52:59 +02:00
Irmen de Jong 5097d52d99 IR codegen for pointer indexing expressions, -assignment 2025-05-27 23:41:08 +02:00
Irmen de Jong 368387e1a7 allow floats to be (explicitly) cast to integers 2025-05-26 21:39:48 +02:00
Irmen de Jong 09d2185bb1 PtArrayIndexer variable is now nullable (because it could be a ptr deref instead) 2025-05-25 23:04:32 +02:00
Irmen de Jong 5c02e2bd71 fix a ptr indexing case, fix address-of fields 2025-05-25 21:32:31 +02:00
Irmen de Jong fb01389b3d cleaning up pointer deref 2025-05-25 18:33:37 +02:00
Irmen de Jong aaa81210ce cleaning up pointer indexing 2025-05-25 02:56:32 +02:00
Irmen de Jong 51269257ea fix a.b.c.d desugaring into pointer deref chain 2025-05-24 14:48:02 +02:00
Irmen de Jong 23a853db1e Merge branch 'master' into structs
# Conflicts:
#	compiler/src/prog8/compiler/astprocessing/AstChecker.kt
#	examples/test.p8
2025-05-23 19:00:59 +02:00
Irmen de Jong 9da430ffeb vm: more complete V-flag handling. somd doc and todo updates. 2025-05-23 18:58:14 +02:00
Irmen de Jong cc063124cf add joystick control to cx16 fileselector.
fix fileselector Basic exasmple.
fixed too aggressive asm peephole optimization that destroyed %jumptable in libraries for example.
2025-05-23 17:50:11 +02:00
Irmen de Jong 3b37b89951 added cx16.joysticks_detect() and cx16.joysticks_getall() 2025-05-23 02:26:21 +02:00
Irmen de Jong 844b537d1e cobramk3 example now draws with new monogfx doublebuffering 2025-05-22 23:29:49 +02:00
Irmen de Jong caf1d4a22a fix monogfx INVERT draw mode 2025-05-22 21:29:23 +02:00
Irmen de Jong d8e244df99 fix monogfx example 2025-05-22 00:37:20 +02:00
Irmen de Jong 548e421e27 added doublebuffering to monogfx (in both lores and hires mode) 2025-05-22 00:10:03 +02:00
Irmen de Jong 322fa7ea69 slightly optimize monogfx plot() 2025-05-21 01:16:43 +02:00
Irmen de Jong db6c887795 Merge branch 'master' into structs
# Conflicts:
#	compiler/test/ast/TestVariousCompilerAst.kt
2025-05-21 00:27:45 +02:00
Irmen de Jong cf7bea0985 cleanup RTS insertion and ast postprocessing before assembly generation 2025-05-21 00:19:50 +02:00
Irmen de Jong 61fe55168a Merge branch 'master' into structs
# Conflicts:
#	codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt
#	codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt
#	examples/test.p8
2025-05-20 22:35:04 +02:00
Irmen de Jong 25d7f8808f IR: added signed multiplication opcodes 2025-05-20 21:36:05 +02:00
Irmen de Jong 1c4999ec87 adding ptr unit tests 2025-05-20 20:57:05 +02:00
Irmen de Jong c726d3f937 fix ptr errors 2025-05-19 22:49:07 +02:00
Irmen de Jong f70341df1b fix ptr errors 2025-05-19 20:06:31 +02:00
Irmen de Jong f0b791452e fix many ptr deref errors 2025-05-19 01:33:57 +02:00
Irmen de Jong adf5600a9b simplify 2025-05-18 18:37:19 +02:00
Irmen de Jong 6d4ccc5feb fix pointer variable not getting marked as used in some cases 2025-05-18 13:23:56 +02:00
Irmen de Jong 5f3829d5cc partly fix weird errors for ptr indexed expressions 2025-05-17 22:56:41 +02:00
Irmen de Jong 770ebdcd4a party fix weird errors for ptr indexed assignment 2025-05-17 20:54:02 +02:00
Irmen de Jong 96f690e749 fix a ptr indexing error 2025-05-17 20:27:38 +02:00
Irmen de Jong eabdd3a8f3 fix the ptr.uword[index] assignment target error 2025-05-17 14:57:24 +02:00
Irmen de Jong 50650b966b repeat countervars again in zeropage if possible, fix pointer arithmetic error 2025-05-17 14:18:56 +02:00
Irmen de Jong 65e34d4989 stricter types for & operator (address-of), and fix invalid recursive subroutine flagging related to struct definition 2025-05-17 11:32:54 +02:00
Irmen de Jong 05dad5ab5f cleanup 6502 pointer usage checks 2025-05-16 21:44:28 +02:00
Irmen de Jong 1a69a2f1bc fix some ptr vs uword type checks 2025-05-16 20:31:15 +02:00
Irmen de Jong 435faafaad fix split-word storage (lsb/msb) of arrays of pointers 2025-05-16 17:53:15 +02:00
Irmen de Jong 686b32dc29 replace ^^str by ^^ubyte and allow returning ubyte/uword when pointer is expected 2025-05-16 17:53:15 +02:00
Irmen de Jong 0e64a22910 tweak address-of types 2025-05-16 17:53:15 +02:00
Irmen de Jong 4f0839f27e rewrite pointer[0] into @(pointer) if its ^^ubyte 2025-05-16 17:53:15 +02:00
Irmen de Jong bb1953267d Merge branch 'master' into structs
# Conflicts:
#	examples/test.p8
2025-05-15 23:09:30 +02:00
Irmen de Jong acc630972a make keyboardhandler example restartable 2025-05-15 23:07:54 +02:00
Irmen de Jong 6a33be3fd8 IR: allow returning boolean in Pc/Pv cpu status register (Pz and Pn are not yet possible) 2025-05-15 22:56:45 +02:00
Irmen de Jong cd8aae4681 allow @(..) to take a ^^ubyte address pointer, not only uwords. 2025-05-15 22:12:42 +02:00
Irmen de Jong 11456496bd Merge branch 'master' into structs
# Conflicts:
#	compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt
#	parser/src/main/antlr/Prog8ANTLR.g4
2025-05-15 21:35:31 +02:00
Irmen de Jong f5fc4e345c fix build error on case-insensitive filesystems 2025-05-15 21:11:34 +02:00
Irmen de Jong 86eef7039f @(..) now also accepts pointer to ubyte address 2025-05-15 20:07:02 +02:00
Irmen de Jong f4b2264fcf fix struct type checks for subroutine call arguments 2025-05-14 23:33:55 +02:00
Irmen de Jong 9b36ae2277 implement inplace boolean short-circuit operators on pointer dereferenced booleans 2025-05-14 21:29:50 +02:00
Irmen de Jong 913ab03963 get rid of invalid ARRAY_STRUCT data type (arrays of struct instance are not yet supported) 2025-05-14 20:43:00 +02:00
Irmen de Jong 38448e471c Merge branch 'master' into structs
# Conflicts:
#	codeGenCpu6502/src/prog8/codegen/cpu6502/ForLoopsAsmGen.kt
#	codeGenIntermediate/src/prog8/codegen/intermediate/IRCodeGen.kt
#	examples/test.p8
2025-05-13 23:42:13 +02:00
Irmen de Jong 67231af623 fix forloop codegen over non-split word arrays of length >= 64 elements 2025-05-13 23:32:26 +02:00
Irmen de Jong e31ef6f06f IR: fix temp register type in for x in array 2025-05-13 22:23:04 +02:00
Irmen de Jong 09d188106a different temp var mechanism for certain array expression, remove old tmpvar mechanism. 2025-05-13 21:12:10 +02:00
Irmen de Jong d8e2116481 different temp var mechanism for for loops, and pokef() 2025-05-13 21:06:33 +02:00
Irmen de Jong 435dfbb932 optimize: rewrite suitable when into on..goto 2025-05-13 01:12:58 +02:00
Irmen de Jong ba93966474 optimize codegen: shortcut redundant jumps in when statement 2025-05-13 00:35:22 +02:00
Irmen de Jong ea8d17cdb2 optimized the cx16 multi-irq dispatcher used in cx16.enable_irq_handlers() 2025-05-12 23:26:54 +02:00
Irmen de Jong 082265fb25 todo 2025-05-12 00:24:57 +02:00
Irmen de Jong d138a7a567 add struct and pointers to IDEA syntax 2025-05-11 23:35:53 +02:00
Irmen de Jong ea27d732ab Merge branch 'refs/heads/master' into structs 2025-05-11 23:35:13 +02:00
Irmen de Jong 9e557ce8ac add keyword 'on' to IDEA syntax 2025-05-11 23:32:54 +02:00
Irmen de Jong 924e28e9b3 Merge branch 'master' into structs
# Conflicts:
#	codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt
#	compiler/src/prog8/compiler/astprocessing/CodeDesugarer.kt
#	compiler/src/prog8/compiler/astprocessing/SimplifiedAstMaker.kt
#	compilerAst/src/prog8/ast/AstToSourceTextConverter.kt
#	compilerAst/src/prog8/ast/antlr/Antlr2Kotlin.kt
#	compilerAst/src/prog8/ast/walk/AstWalker.kt
#	compilerAst/src/prog8/ast/walk/IAstVisitor.kt
#	docs/source/todo.rst
#	examples/test.p8
#	parser/src/main/antlr/Prog8ANTLR.g4
2025-05-11 23:23:06 +02:00
Irmen de Jong e5d9af75de remove double bra/jmp 2025-05-11 23:01:13 +02:00
Irmen de Jong 31c1bf8bc5 added on..goto/call statement 2025-05-11 21:37:44 +02:00
Irmen de Jong 37d4055036 translate newline '\n' to char code 13 in various encodings such as ISO (used to be 10)
This means that when printed, such newlines will now properly go to the next line in these encodings too (ISO variants, KATAKANA).
2025-05-11 19:45:24 +02:00
Irmen de Jong 78b1076110 some more software links 2025-05-11 19:39:20 +02:00
Irmen de Jong 0a3c748e41 fix code gen bug for certain goto array[idx] 2025-05-11 17:18:20 +02:00
Irmen de Jong ebf79ef9e2 release 11.3.2 2025-05-11 12:30:36 +02:00
Irmen de Jong 60a73248cd todo 2025-05-11 03:16:48 +02:00
Irmen de Jong abbb7d7ba3 fix struct pointers in subroutine parameters and return values 2025-05-11 02:08:59 +02:00
Irmen de Jong 59c378089e fix some struct type and symbol lookup errors 2025-05-11 00:52:35 +02:00
Irmen de Jong 0b789b5f0b added most inplace operators for pointer deref 2025-05-10 20:58:01 +02:00
Irmen de Jong 4382b96a9a tweaking pointer deref in IR 2025-05-10 19:52:06 +02:00
Irmen de Jong 246e4f35a6 Merge branch 'master' into structs
# Conflicts:
#	codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt
#	codeGenIntermediate/src/prog8/codegen/intermediate/ExpressionGen.kt
#	compiler/test/ast/TestConst.kt
#	docs/source/todo.rst
#	examples/test.p8
2025-05-10 16:36:16 +02:00
Irmen de Jong 99b9370178 fix various bugs around word-indexing combined with address-of: &buffer[2000] 2025-05-10 16:22:05 +02:00
Irmen de Jong 506062c6b6 start implementing ptr deref augmented assigns 2025-05-09 23:05:27 +02:00
Irmen de Jong d634061cd9 Merge pull request #169 from Frosty-J/crc
Specify X16 CRC type
2025-05-08 23:47:17 +02:00
Irmen de Jong 8353c689ca start making '&' (address-of) return a typed pointer, fixes some errors 2025-05-08 23:40:41 +02:00
Frosty-J d59d8ff1fe Specify X16 CRC type 2025-05-08 05:57:30 +01:00
Irmen de Jong e98e6f70ac Merge branch 'master' into structs
# Conflicts:
#	compiler/src/prog8/compiler/astprocessing/AstChecker.kt
#	compiler/test/TestTypecasts.kt
#	docs/source/todo.rst
#	examples/test.p8
#	gradle.properties
2025-05-07 23:26:21 +02:00
Irmen de Jong 53e442d509 fix regression in 11.3.1: allow bitwise operation between different types as long as they're the same size. 2025-05-07 23:06:45 +02:00
Irmen de Jong 134352ed7c Merge branch 'master' into structs
# Conflicts:
#	compiler/test/TestTypecasts.kt
#	docs/source/todo.rst
#	examples/test.p8
#	virtualmachine/src/prog8/vm/VmProgramLoader.kt
2025-05-07 22:32:41 +02:00
Irmen de Jong f7cbfdff06 skip this test for now 2025-05-07 21:14:52 +02:00
Irmen de Jong b28ee0819f revert behavior change of @dirty variables, instead document the initialization behavior correctly in the docs
they get zeroed at program startup (like other uninitialized BSS variables), just not on entry in the subroutine.
2025-05-07 21:07:12 +02:00
Irmen de Jong 5de626aab8 support comparison operators on pointers 2025-05-06 22:26:27 +02:00
Irmen de Jong 7aad5d486e Merge pull request #168 from adiee5/master
Update `nano` syntax highlighting
2025-05-06 18:17:58 +02:00
Irmen de Jong 701f155951 Merge branch 'master' into structs
# Conflicts:
#	codeGenCpu6502/src/prog8/codegen/cpu6502/ProgramAndVarsGen.kt
#	compiler/test/TestSymbolTable.kt
#	docs/source/todo.rst
#	examples/test.p8
#	intermediate/src/prog8/intermediate/IRFileReader.kt
#	intermediate/src/prog8/intermediate/IRFileWriter.kt
#	intermediate/src/prog8/intermediate/IRSymbolTable.kt
#	simpleAst/src/prog8/code/SymbolTable.kt
#	simpleAst/src/prog8/code/SymbolTableMaker.kt
#	virtualmachine/src/prog8/vm/VmProgramLoader.kt
2025-05-06 17:59:36 +02:00
Irmen de Jong 8c324d7514 tweak error 2025-05-06 17:50:53 +02:00
Irmen de Jong 522958e0e9 @dirty variables now actually end up in the uninitialized BSS_NOCLEAR section 2025-05-06 01:41:34 +02:00
adiee5 97390db5f5 Update prog8.nanorc 2025-05-05 21:06:56 +02:00
Irmen de Jong af920d1427 pointer arithmetic for '-', fixed '+' 2025-05-05 21:06:49 +02:00
Irmen de Jong 779ebc0537 pointer arithmetic for '+' 2025-05-05 18:09:19 +02:00
Irmen de Jong 38949b82c3 type check tuning 2025-05-05 15:41:32 +02:00
Irmen de Jong d11386ef26 type check tuning 2025-05-04 23:23:21 +02:00
Irmen de Jong 0e0377d1f0 IR/VM implemented struct allocations and initialization 2025-05-04 14:04:44 +02:00
Irmen de Jong 55e0dbab27 preparing for statically allocating struct instances 2025-05-03 23:44:29 +02:00
Irmen de Jong 4dc82f2c83 preparing for statically allocating struct instances 2025-05-03 19:00:27 +02:00
Irmen de Jong 1ba5587404 allow syntax for declaring variables with struct instance type 2025-05-03 16:14:22 +02:00
Irmen de Jong 835c4b6da3 allow multi-field declarations in structs, get rid of . -> ^^ rewrite 2025-05-03 12:32:29 +02:00
Irmen de Jong dbd955b61e tweak typecheck and better code for constant indexes in pointer derefs 2025-05-02 23:44:26 +02:00
Irmen de Jong d20e2fd88c structs will be a new major version of the compiler 2025-05-02 22:25:26 +02:00
Irmen de Jong e0dea89477 added support for ptr[x].field 2025-05-02 22:16:20 +02:00
Irmen de Jong ccc6b56e35 added link to prog8reu library 2025-05-02 19:38:59 +02:00
Irmen de Jong 6fc2902895 fixing ptr traversal typecheck issues 2025-05-02 00:41:42 +02:00
Irmen de Jong c96e4b40d4 building syntax support for ptr[x].field
attempting to do this by making '.' an expression operator
2025-05-02 00:41:42 +02:00
Irmen de Jong 37da3e2170 parser 2025-05-02 00:41:42 +02:00
Irmen de Jong 2661d3c489 allow array syntax on pointers 2025-05-02 00:41:42 +02:00
Irmen de Jong b89bbb9281 allow pointers in subroutines params and return values 2025-05-02 00:41:42 +02:00
Irmen de Jong 696bf636ed better parsing of directive names results in better error messages when an invalid one is found 2025-05-02 00:41:42 +02:00
Irmen de Jong 40952a788a PtSub: params and returns now as children (in PtSignature node) for easier Ast walking
PtPointerDeref: same but for its start identifier
2025-05-02 00:41:42 +02:00
Irmen de Jong 0162e7a0c1 fix the scoping problems on subtypes 2025-05-02 00:41:42 +02:00
Irmen de Jong 6ce099f176 IR: fix ptr type checks and struct field assignment errors 2025-05-02 00:41:42 +02:00
Irmen de Jong 476a4bac8e IR: LOADI allows r1 and r2 to be the same for pointer chain dereference optimalization 2025-05-02 00:41:42 +02:00
Irmen de Jong 63a410a6df implicit cast to bool for numeric or pointers as condition arguments (to if, while, until) 2025-05-02 00:41:42 +02:00
Irmen de Jong cca27faa3b fix pointer value assignment (not dereferencing the actual pointer) 2025-05-02 00:41:42 +02:00
Irmen de Jong 803e6bd81a fix uword vs pointer type errors and casts 2025-05-02 00:41:42 +02:00
Irmen de Jong 88269628a2 had to turn ^type syntax into ^^type to avoid confusion with the eor operator once again 2025-05-02 00:41:42 +02:00
Irmen de Jong b920d553a0 make address-of dereference work 2025-05-02 00:41:42 +02:00
Irmen de Jong 5e2d0d0dfc fix param order of AssignTarget 2025-05-02 00:41:42 +02:00
Irmen de Jong 2ae3bd68eb more pointer dereferencing for chains 2025-05-02 00:41:42 +02:00
Irmen de Jong 9c183f27eb pointer dereferencing for chains 2025-05-02 00:41:42 +02:00
Irmen de Jong 8046023e82 pointer dereferencing for simple types (read and write) 2025-05-02 00:41:42 +02:00
Irmen de Jong e328520588 initial struct and typed pointer support 2025-05-02 00:41:40 +02:00
Irmen de Jong 7eb079050c fix strings.hash() on 6502 CPU's. NOTE: now takes string pointer in AY instead of R0 on all platforms 2025-05-01 22:47:43 +02:00
Irmen de Jong 2fdd5543b2 release 11.3.1 2025-04-30 22:40:54 +02:00
Irmen de Jong d04164c0a6 fix const evaluation of bitwise logical expressions (&, |, ^, <<, >>) of signed operands 2025-04-30 22:27:31 +02:00
Irmen de Jong b047731f82 removed some redundant arguments 2025-04-25 23:27:06 +02:00
Irmen de Jong 4d91f92a2e clearer error message 2025-04-25 19:38:45 +02:00
Irmen de Jong 98505d27b1 IR: fix invalid removal of label chunks and include asmsubs when looking for labels 2025-04-24 23:30:51 +02:00
Irmen de Jong cd63a58ad9 IR: get rid of problematic PREPARECALL pseudo instruction 2025-04-24 22:32:40 +02:00
Irmen de Jong 170f8dd092 IR: new CALLFAR instructions to support callfar into another bank 2025-04-24 21:17:48 +02:00
Irmen de Jong 619dcb6a84 fix error in IR register typing 2025-04-24 20:50:19 +02:00
Irmen de Jong 99ae8ea52e code cleanup 2025-04-24 18:51:03 +02:00
Irmen de Jong dc031c30eb add -version option to just print the compiler version and then exit 2025-04-24 18:13:35 +02:00
Irmen de Jong 1e702439b7 avoid JDK 21+/Kotlin method conflict of removeLast()/removeFirst()
background: see https://www.reddit.com/r/androiddev/comments/1gspjrs/dont_use_kotlins_removefirst_and_removelast_when/
https://youtrack.jetbrains.com/issue/KT-71375/Prevent-Kotlins-removeFirst-and-removeLast-from-causing-crashes-on-Android-14-and-below-after-upgrading-to-Android-API-Level-35

it's about Android but the problem also occurs on desktop JDKs for example when running a Java21 compiled prog8 with Java17
2025-04-24 18:11:42 +02:00
Irmen de Jong 8debc42381 slightly stricter assignment type compatibility checking 2025-04-24 15:05:35 +02:00
Irmen de Jong 532d719089 more optimal math.randrange() routines 2025-04-24 04:04:14 +02:00
Irmen de Jong b40860aca4 get rid of RTS after JMP 2025-04-23 17:08:16 +02:00
Irmen de Jong 2cbe6b5f7f info message when more optimal goto array[idx] is possible 2025-04-23 16:59:18 +02:00
Irmen de Jong d2cc7ccdfa remove redundant variable=0 initializations (BSS clear takes care of them) 2025-04-23 14:45:38 +02:00
Irmen de Jong 2cb183c6d8 fix regression for goto array[idx] on 6502 cpu which doesn't have jmp (ptr,x) 2025-04-23 02:56:10 +02:00
Irmen de Jong 84026b105f smaller code for goto nosplitptrarray[index] 2025-04-22 20:01:16 +02:00
Irmen de Jong a4d0589f10 fix errors like parse error still printed in color when -plaintext is set 2025-04-22 19:26:11 +02:00
Irmen de Jong e375f6afce fix diskio.f_read() returning 1 less than the actual size read.
fix diskio.f_read_all() more robust error status end of loop checking.
2025-04-21 05:02:16 +02:00
Irmen de Jong 5a7bc04816 update docs about library jump table 2025-04-19 13:49:03 +02:00
Irmen de Jong bd1894580e allow floating point value as part of a multi-value return 2025-04-18 22:45:05 +02:00
Irmen de Jong 9e694c0337 doc 2025-04-18 21:11:27 +02:00
Irmen de Jong c82586db28 print copyright message better 2025-04-17 23:09:28 +02:00
Irmen de Jong dd2d466350 code cleanups 2025-04-17 22:58:02 +02:00
Irmen de Jong 830da8de0a memorymapped vars in ZP are now treated as ZP-variables by prog8 itself too 2025-04-17 22:19:01 +02:00
Irmen de Jong 4e5ee333c8 preparing release 11.3 2025-04-17 21:16:52 +02:00
Irmen de Jong 9df899eb63 document romable option and that strings+initialized arrays become read-only 2025-04-17 21:05:46 +02:00
Irmen de Jong ca7491a702 cx16: sys.enable_irq_handlers() and associated functions are now romable 2025-04-17 00:25:25 +02:00
Irmen de Jong 1a07129865 c64: graphics.horizontal_line() is romable 2025-04-17 00:02:17 +02:00
Irmen de Jong 4fbd67ff99 txt.setcc() is romable 2025-04-16 23:44:50 +02:00
Irmen de Jong 5bc6c50f42 txt.setclr() and getclr() are romable 2025-04-16 23:38:16 +02:00
Irmen de Jong 063de3801d txt.getchr() is romable 2025-04-16 23:32:18 +02:00
Irmen de Jong ae65266a4a txt.setchr() is romable 2025-04-16 23:27:23 +02:00
Irmen de Jong 8ed2401e0b cx16: txt.scroll_left(), right, up and down are now romable 2025-04-16 23:11:27 +02:00
Irmen de Jong d2e8ee8269 cx16: txt.fill_screen, txt.clear_screenchars, clear_screencolors are now romable 2025-04-16 22:59:36 +02:00
Irmen de Jong 1f996e3b8b sorting.gnomesort_ub(), compression.decode_rle() and decode_rle_srcfunc() are now romable 2025-04-16 22:47:34 +02:00
Irmen de Jong 7108b74105 string.rfind() is now romable and now works correctly on empty strings.
added some comments to strings.pattern_match
2025-04-16 21:55:55 +02:00
Irmen de Jong 801fe1b604 c64: callfar() is now romable 2025-04-16 21:13:59 +02:00
Irmen de Jong fb44c87597 make diskio.f_read() ROM-compatible 2025-04-15 00:23:23 +02:00
Irmen de Jong 6b9cdbd482 remove unused arraycopy routines 2025-04-14 22:10:54 +02:00
Irmen de Jong 0ab98033b5 add rom-compatible random number routines 2025-04-14 22:04:11 +02:00
Irmen de Jong 14a2b96609 scanned libraries for self-modifying code/inline vars (romable problem) 2025-04-14 21:15:32 +02:00
Irmen de Jong f829b689db update zsmkit example to zsmkit release 2.6 2025-04-14 19:28:12 +02:00
Irmen de Jong dfda8b7ed5 remove problematic rewriting of X=value-X 2025-04-14 02:35:37 +02:00
Irmen de Jong 4388466451 romable comments 2025-04-10 22:21:27 +02:00
Irmen de Jong 5c2f509a52 also hide emulator process output when using -quiet 2025-04-10 21:26:48 +02:00
Irmen de Jong 59582f5210 added -quiet flag to suppres all compiler and assembler messages 2025-04-10 21:16:26 +02:00
Irmen de Jong e2a8bdbdfb romable comments 2025-04-09 22:35:23 +02:00
Irmen de Jong 0916b943da sys.exit(), exit2(), exit3() now romable 2025-04-09 22:13:52 +02:00
Irmen de Jong 9c7ebc883c fixed: memsetw() invalid asm, c128: sys.restore_irq() 2025-04-09 21:29:48 +02:00
Irmen de Jong 0ee42b9aa0 output_type is now part of custom target config and atari again defaults to .xex 2025-04-09 20:43:44 +02:00
Irmen de Jong 37b3868ca3 symboldump now also includes aliased symbols (like palette.set_default) 2025-04-08 21:40:28 +02:00
Irmen de Jong a6835ce3f0 fix signed word value range check error, fix rol2() on array element 2025-04-08 21:05:50 +02:00
Irmen de Jong 69c96ad99b cx16: added cx16.push_rambank/rombank and cx16.pop_rambank/rombank for easy temporary bank switching 2025-04-06 15:33:35 +02:00
Irmen de Jong b72877d59d cx16: added routines to get and set the default palette (new rom 49+ extapi) 2025-04-06 15:14:04 +02:00
Irmen de Jong 05eb15d4f7 add cx16.memory_decompress_from_func() 2025-04-06 13:48:08 +02:00
Irmen de Jong f1fec37c79 rename examples/vm to examples/virtual 2025-04-04 20:02:45 +02:00
Irmen de Jong 73f6880ff8 fix irq related crash by no longer zeroing out stored vector 2025-04-02 22:22:21 +02:00
Irmen de Jong 8a53742f31 fix notreached error 2025-04-01 23:12:08 +02:00
adiee5 9be40e85ff Improve romability of low-level libs (#160)
* Improve romability of low-level libs

* Improve ROMability of targeted syslibs

Previous commit just did that for multitarget libs, now it's also syslibs of built-in targets that get this treatment too.
2025-04-01 23:00:14 +02:00
Irmen de Jong 61079c1eb7 errormessage for assignment to str/arrays in ROM 2025-03-31 23:57:04 +02:00
Irmen de Jong 1075ee8fc3 errormessage for non romable extsub bank declaration 2025-03-31 23:05:58 +02:00
Irmen de Jong a28b265197 fix diskio merge issue on c64 and c128. Fixes #167 2025-03-31 22:06:49 +02:00
Irmen de Jong 20e534c468 fix memtop limit when using -varshigh option 2025-03-27 23:31:05 +01:00
Irmen de Jong da7aa5dc49 forloop temp index variables no longer inline when romable 2025-03-26 22:38:50 +01:00
Irmen de Jong 8f2a43ca0a temp vars for for loops indices in romable mode, are no longer allocated from the precious Zeropage 2025-03-26 22:12:22 +01:00
Irmen de Jong d0909d7810 added diskio.loadlib() convenience function to load library blobs 2025-03-24 22:35:34 +01:00
Irmen de Jong 1641999d20 upgrade to kotlin 2.1.20 2025-03-22 23:06:44 +01:00
Irmen de Jong e16452037c no more self modifying code for loops over non-const word range 2025-03-22 22:51:30 +01:00
Irmen de Jong 344d79684a get rid of more modifying code in forloops (byte ranges with step 1/-1)
fix invalid stack corrupting loops
2025-03-22 20:45:28 +01:00
Irmen de Jong 573a1d9b7b refactor for loop over byte ranges 2025-03-22 16:07:46 +01:00
Irmen de Jong 25ab57580c for loop over string no longer requires self-modifying code 2025-03-22 13:38:49 +01:00
Irmen de Jong a332e0e3d1 remove self-modifying code from @(ptr)++ and @(ptr)--
romable errors for string and array variables turned into read-only warnings

remove self-modifying code from @(ptr)++ and @(ptr)--
2025-03-21 23:54:19 +01:00
Irmen de Jong 376f1cb139 remove self-modifying code from rol(ptr) and ror(ptr) 2025-03-21 23:16:40 +01:00
Irmen de Jong 90f80558d7 add more 'modified' comments to self-modifying code lines 2025-03-21 17:59:49 +01:00
Irmen de Jong e281994898 intellij syntax def file works for all jetbrains ides 2025-03-21 01:32:24 +01:00
markjreed 29fac122e1 fix: ignore EOF when looking for error status after reading first byte of newly-opened file (#166)
* fix: ignore EOF when looking for error status after reading first byte of newly-opened file

* fix: replace hard-coded $40 and $BF with STATUS_EOF and ~STATUS_EOF
2025-03-19 23:00:55 +01:00
Irmen de Jong 1dc412eb90 simplify 2025-03-18 23:50:51 +01:00
Irmen de Jong 3770a4fe0c easier datatype notation by just using the type objects directly 2025-03-18 23:33:04 +01:00
Irmen de Jong 79cda544c8 allow integer range as when choice value 2025-03-17 22:26:27 +01:00
Irmen de Jong f04b97d890 support symlinks in paths (triggered by symlinked tmp on mac os) 2025-03-15 14:33:33 +01:00
Irmen de Jong 3e9b4ccc45 getting rid of needless absolute pathings 2025-03-14 20:39:18 +01:00
Irmen de Jong 2c3d838dd8 get rid of deprecated usage of thread id to create temporary test output file names 2025-03-14 01:23:01 +01:00
Irmen de Jong 7668a3c660 use kotest tempdir instead of hardcoded output directory 2025-03-14 01:18:33 +01:00
Irmen de Jong 5dd45b714a psg module: the envelope handler no longer writes to vera PSG voices that haven't been enabled 2025-03-12 23:07:13 +01:00
Irmen de Jong 8b08895d0f also add strings.ncompare() to virtual lib 2025-03-09 14:33:31 +01:00
Irmen de Jong 8f8d99e3ed updated symboldumps 2025-03-07 23:58:06 +01:00
Irmen de Jong 23474360ec fix ncompare calls 2025-03-07 23:56:13 +01:00
gillham 81c255c450 Add strings.ncompare (and backing strncmp_mem) to compare up to n characters of a string. (#164)
* Add strings.ncompare (and backing strncmp_mem) to compare up to n characters of a string.

* Document strings.ncompare.
2025-03-07 23:53:56 +01:00
Irmen de Jong ef23d52ed7 better error if module name clash occurs caused by case-insensitive names 2025-03-07 21:35:35 +01:00
Irmen de Jong 220ab773aa fix asmgen error when assigning address of split word array without explicit adressof syntax 2025-03-06 23:20:42 +01:00
Irmen de Jong e3e5bff7bb add missing sprites benchmark module 2025-03-06 19:39:55 +01:00
Irmen de Jong 7b9a841b2a fix C64 graphics.plot() it was broken since 10.5 2025-03-06 00:42:17 +01:00
Irmen de Jong 40423911ef added footgun warning when calling labels as subroutine 2025-03-04 22:14:21 +01:00
Irmen de Jong 582a70b046 fix calling label as subroutine (JSR label) 2025-03-04 21:53:53 +01:00
Irmen de Jong 5b63590ebf fix symbol prefixing bug triggered by certain usage of %option no_symbol_prefixing 2025-03-03 22:26:19 +01:00
Irmen de Jong 2b6510dc19 improve error message for non-numeric when choice values 2025-03-03 19:48:45 +01:00
Irmen de Jong 9d49589d73 fix codegen for @(ptr-offset)=value writing bogus values 2025-03-02 23:40:14 +01:00
Irmen de Jong 125b66c929 fix crash in asmgen for boolean comparison with false, when not using optimizations 2025-03-01 23:57:55 +01:00
Irmen de Jong 5255f1c052 print offending source position in more of the TODO errors to help diagnosing 2025-03-01 23:16:34 +01:00
Irmen de Jong a6ba05d60c compile time evaluation of constant rangecheck 2025-03-01 13:45:11 +01:00
Irmen de Jong 41e963b04b memory() name argument should be string literal, nice error message 2025-03-01 12:38:42 +01:00
Irmen de Jong 6ff75bef29 fix verafx register address typo VERA_FX_POLY_FILL_H 2025-02-27 21:59:04 +01:00
Irmen de Jong 72c16d0d32 avoid doing useless jsr for reboot/poweroff calls 2025-02-26 20:42:38 +01:00
Irmen de Jong 94653e5c8c possible workaround for SMC issue that could make sys.reset_system() and sys.poweroff_system() not work properly 2025-02-24 23:07:51 +01:00
Irmen de Jong 3e2b2a698d Separate simple Ast and Symboltable from codeCore into new simpleAst module. VirtualMachine and Intermediate do not need them, just codeCore. 2025-02-24 22:06:52 +01:00
Irmen de Jong ae04f5aee8 %option romable now disables floating point support
because if it's your code that is running in the rom bank you can't have the floating point routines available there
2025-02-23 10:21:55 +01:00
Irmen de Jong 5c56267662 Also romable warning for inline variables. Added TODO: Romable in library files where applicable 2025-02-21 21:58:31 +01:00
Irmen de Jong e55ce5504e added %option romable to enable romable mode, but only generate a bunch of warnings for problematic codegeneration atm 2025-02-20 23:40:44 +01:00
Irmen de Jong fb1e89d9ef update docs about call convention for multi-value results (first is in A or AY, then R15...R0)
added sprites+coroutines+defer part to benchmark program
2025-02-19 22:10:12 +01:00
Irmen de Jong bc550a4549 fix optimized multi-value call result assignment 2025-02-19 20:19:20 +01:00
Irmen de Jong ebdea9cf76 optimized call convention for multi-value return and assign on regular asmsubs (6502) 2025-02-19 20:19:20 +01:00
Irmen de Jong 09ec508f82 avoid unnecessary word extension when assigning a register byte to a byte target 2025-02-19 20:19:20 +01:00
Irmen de Jong d06e9ea7f6 allow comparisons against constant values with different type 2025-02-19 20:19:20 +01:00
Mia McMahill a36bdc54fd Add Notepad++ syntax highlighting file for dark mode (#161) 2025-02-19 18:33:31 +01:00
Irmen de Jong 0814ea9711 symboldumps 2025-02-13 13:10:07 +01:00
Irmen de Jong daefe839d8 version 11.1 2025-02-13 12:31:12 +01:00
Irmen de Jong e6088dd315 optimize byte comparisons against small word constants 2025-02-13 12:02:11 +01:00
Irmen de Jong fc03d6f332 changed -sourcelines option to -nosourcelines (default is now to include them) 2025-02-12 21:27:46 +01:00
Irmen de Jong 2aeb7a838e finalize extracting neo and atari compiler targets into configuration files instead 2025-02-12 14:01:04 +01:00
Irmen de Jong 99ff5dd078 extracting neo and atari compiler targets into configuration files instead 2025-02-12 13:58:34 +01:00
Irmen de Jong 49982b49b6 extracting neo and atari compiler targets into configuration files instead 2025-02-12 13:58:34 +01:00
Irmen de Jong fd39c22616 Update FUNDING.yml
added paypal sponsor link
2025-02-12 13:48:49 +01:00
Irmen de Jong 9e79722a7f fix rangeexpression value type casting 2025-02-11 22:23:07 +01:00
Irmen de Jong 17334a1c58 fix 6502 codegen error for mixed case register params and normal params 2025-02-10 22:06:11 +01:00
Irmen de Jong c7f0ff11ac fix crash when initializing string variable with a non-string value 2025-02-10 02:54:53 +01:00
Irmen de Jong cd2cc89e6a fix type errors in Range containment check 2025-02-10 02:27:34 +01:00
Irmen de Jong 069143092d fix Golden ram issues 2025-02-09 15:57:14 +01:00
Irmen de Jong efd41260f2 added %jmptable 2025-02-09 15:02:59 +01:00
Irmen de Jong 8d2410622c make 64tass less strict about implied register addressing modes on instructions like "asl" 2025-02-05 22:33:50 +01:00
Irmen de Jong 60554389b3 for fileselector library save/restore the prog8 temporary ZP locations 2025-02-04 00:17:55 +01:00
Irmen de Jong a940dc7d43 improve dumpvars output for zeropage variables 2025-02-03 22:36:58 +01:00
Irmen de Jong 06ca68a625 add drivenumber to fileselector config 2025-02-02 23:09:27 +01:00
Irmen de Jong 5b58e5b158 fix unit tests 2025-02-02 21:52:33 +01:00
Irmen de Jong 74dd8fe80b %output library header generation depends on compiler target
fileselector example tweaks
2025-02-02 20:51:45 +01:00
Irmen de Jong 75ddcda5f3 simplify DirectiveArg 2025-02-02 04:35:20 +01:00
Irmen de Jong 216825b98a cx16: made fileselector example into a loadable library 2025-02-02 04:13:03 +01:00
Irmen de Jong a96defab86 diskio: added several diskio routines to list only the files or dir entries on the disk
uses CBM DOS filtering $:*=c and $:*=p
2025-02-02 02:44:23 +01:00
Irmen de Jong 0864b0a1b7 cx16: added several diskio routines to list only the files or dir entries on the disk
uses CBM DOS filtering $:*=d and $:*=p
2025-02-01 22:41:34 +01:00
Irmen de Jong 8b158d9240 fix 64tass ascii encoding option for atari and neo6502 2025-02-01 21:47:01 +01:00
Irmen de Jong f335251c2b added ability to specify additional assembler options in custom target configurations 2025-02-01 16:09:43 +01:00
Tymoteusz Moryto 67bc0b6931 Added txt.cls() to prog8_builtins.vim (#159) 2025-02-01 14:21:40 +01:00
gillham e646dd1ed1 Add an encoding for the C64 OS custom character set. Use c64os: (#158) 2025-01-31 23:41:55 +01:00
Irmen de Jong 2b7947f9b0 fix address check issue when using custom launcher 2025-01-31 23:34:12 +01:00
Irmen de Jong ec0cfb4b3f doc fix 2025-01-30 23:55:14 +01:00
Irmen de Jong 9cdf53019c some tweaks to the configurable targets 2025-01-30 23:52:44 +01:00
Irmen de Jong 1a04a3eb3a added ability to configure custom ASM launcher code in target configuration file 2025-01-30 22:10:42 +01:00
Irmen de Jong 105d3995e0 some docs about the configurable targets, update kotlin to 2.1.10 2025-01-29 21:14:40 +01:00
Irmen de Jong 8ce3204f93 program start label is back for library outputs 2025-01-28 19:28:34 +01:00
Irmen de Jong d0f15f1285 missing pic 2025-01-27 23:40:32 +01:00
Irmen de Jong 66d6f67120 usage 2025-01-27 23:36:39 +01:00
Irmen de Jong a106c88054 unit test for %output library, and docs. 2025-01-27 23:26:21 +01:00
Irmen de Jong ee784e1ccc fix indication for when imported modules are library modules or not.
This fixes a bug where syslib and such gets optimized away when it is loaded from an alternative library location using the configurable target library path property setting.
2025-01-26 21:19:29 +01:00
Irmen de Jong bb75be0b44 library now includes the 2 byte PRG header
fixed some assorted things
2025-01-26 19:48:44 +01:00
Irmen de Jong 2478aea316 add %output library 2025-01-24 23:25:57 +01:00
Irmen de Jong 1e17df5296 optimize word+byte*2 expression to word+byte+byte (more efficient in 6502 codegen) 2025-01-24 21:30:02 +01:00
Irmen de Jong 8583a96519 optimized gnomesorts 2025-01-24 00:40:11 +01:00
Irmen de Jong d0c184c7de remove needless 0 initializations of multi decl's
fix outdated text
2025-01-23 22:42:58 +01:00
Irmen de Jong 0191acb2b3 fix IR codegen for the RETURN 4,5,6,7
added cx16.EXTAPI_memory_decompress_from_func for cx16
2025-01-22 23:31:51 +01:00
Irmen de Jong 277a1a32b2 fix crash when declaring a string array with wrong variable type str vs str[] 2025-01-21 03:12:12 +01:00
Irmen de Jong 7a13f57ab0 enforce variable init values are only strings or arrays 2025-01-20 01:25:17 +01:00
Irmen de Jong 0c882836d9 support multi-value variable initialization: ubyte a,b,c = multi() 2025-01-18 22:08:31 +01:00
Irmen de Jong 228be5cd04 callgraph no longer forgets some identifier occurrences 2025-01-18 21:18:08 +01:00
Irmen de Jong 08cd2fd6e8 fix check for assigning to a constant, for multi-value assigns. 2025-01-18 20:38:02 +01:00
Irmen de Jong bc7b086f0f fix a configurable compilation target, add working example 2025-01-17 22:58:51 +01:00
Irmen de Jong e8f3af6981 adding a configurable compilation target 2025-01-17 00:56:44 +01:00
Irmen de Jong f9c7c7dab7 fix subroutine calling convention for @Rx parameters: don't pass them via cpu registers 2025-01-14 23:02:17 +01:00
Irmen de Jong 09a17743ad merge IMachineDefinition into ICompilationTarget 2025-01-13 21:45:38 +01:00
Irmen de Jong 4f096a7511 added sprites.getxy()
fix compiler crash on return xxx,yyy  when symbol is not defined
2025-01-10 22:26:38 +01:00
Irmen de Jong 2ab2130000 renamed "intermediate AST" to "simplified AST" 2025-01-10 20:33:44 +01:00
Irmen de Jong 66558f7638 IR support for multi-value returns in normal subroutines, documentation. 2025-01-09 22:39:08 +01:00
Irmen de Jong a6f9ed07e7 6502 codegen for multi-assigns 2025-01-09 00:38:47 +01:00
Irmen de Jong 7268a8736f working on 6502 codegen for multi-assigns 2025-01-07 22:13:13 +01:00
Irmen de Jong 8f6b5676d7 working on codegen for multi-value returns 2025-01-07 20:35:49 +01:00
Irmen de Jong ca9422bbe9 be able to parse multiple return values (sub + return) 2025-01-07 01:51:54 +01:00
Irmen de Jong 35d9412559 better error message 2025-01-07 00:53:48 +01:00
Irmen de Jong f071c07dd9 IR: only put align on lsb array of split word array. tag split word arrays with split. (but this isn't actually used yet) 2025-01-06 02:50:54 +01:00
Irmen de Jong e5ff3c1ff3 fix compiler crash when using strings in if-expression. Remove harmless info message. 2025-01-06 01:34:42 +01:00
Irmen de Jong f0e8ff0326 get rid of some empty lines in the generated asm 2025-01-05 19:34:05 +01:00
Irmen de Jong 3b5cda85ff fix register clobber on @() 2025-01-05 16:34:51 +01:00
Irmen de Jong 420793f9e2 mkword() avoids unneeded push/pop for simple arguments 2025-01-05 13:41:40 +01:00
Irmen de Jong cf1dbaf0d8 no longer clear msb on asmsub argument byte @R0
avoid unneeded push/pop for 2 byte arguments to a functioncall
2025-01-05 13:06:39 +01:00
Irmen de Jong d187cef6b7 optimize x=min(x,100) and some other simple min() and max() cases 2025-01-05 11:59:00 +01:00
Irmen de Jong 3b3616afda optimized pointer access @(pointer - constantoffset) 2025-01-05 06:31:34 +01:00
Irmen de Jong 0ffebc25d0 tweak pointer access, fix and optimize reading memory from a label as pointer 2025-01-05 05:44:51 +01:00
Irmen de Jong 478e2b4ebd abs() return type changed to ubyte/uword 2025-01-04 23:16:51 +01:00
Irmen de Jong a56ae7539a optimized codegen for word*128 (word << 7): no longer do 7 shifts 2025-01-04 23:08:21 +01:00
Irmen de Jong 407773bda2 IR: don't lose inline asm chunks, fix carry behavior for multi-shifts 2025-01-04 22:12:54 +01:00
Irmen de Jong 823eaa8918 when using @requirezp in a subroutine that is unused (and is pruned), don't give an error there when using %zeropage dontuse
give warning when a pointer var is declared as @nozp  (very inefficient)
2025-01-04 16:39:09 +01:00
Irmen de Jong a2be42c5ca txt.get_cursor() now returns the column and row as 2 values, no longer requires 2 pointer arguments 2025-01-04 04:06:27 +01:00
Irmen de Jong a76b8d66ff cx16: added syslib.get_charset()
updated fileselector
2025-01-04 01:02:43 +01:00
Irmen de Jong b7f47d354f IR: implemented << and >> for split word arrays 2025-01-03 22:18:02 +01:00
Irmen de Jong 5d33c93af9 IR: implemented rol(), rol2(), ror(), ror2() for split word arrays 2025-01-03 20:01:50 +01:00
Irmen de Jong 4db6859f3f IR: strict register pool type assignment, 1 unique type per register + verification during IR writing 2025-01-03 04:18:16 +01:00
Irmen de Jong 45fe1bb16e reduce error clutter for undefined symbols 2025-01-03 01:55:44 +01:00
Irmen de Jong b014facbd3 cx16 fileselector improvements 2025-01-03 01:35:20 +01:00
Irmen de Jong 3b4b37f16b optimize codegen for x += array[index] (and others) 2025-01-02 01:11:25 +01:00
Irmen de Jong 68d5983a14 optimize monogfx.plot() to use a *40 lookup table in lores mode. Speeds up a lot of other routines too (line etc) 2025-01-01 20:25:58 +01:00
Irmen de Jong f2cfcfdf31 cx16: monogfx can fill with stipple mode again.
cx16: charset switching enabled again on program exit.
cx16: fileselector example: can now also show directories
2025-01-01 18:27:25 +01:00
Irmen de Jong 10b9162dc5 improving fileselector 2024-12-30 21:34:03 +01:00
Irmen de Jong c84cc8f8c9 word arrays for sorting should be @nosplit 2024-12-30 00:00:31 +01:00
Irmen de Jong 78c71bbf0e adding file selector example 2024-12-30 00:00:31 +01:00
Irmen de Jong 37c2c1bf0b support &, &< and &> on array elements from split word arrays, not just on the array as a whole 2024-12-30 00:00:31 +01:00
Irmen de Jong c8996418da ir: tweak register pool, prepare to register the types there uniquely 2024-12-30 00:00:31 +01:00
Irmen de Jong 76b29aa629 fixed register reuse and types on syscall interface 2024-12-30 00:00:31 +01:00
Irmen de Jong ee521793f8 ir: enforce single reg type 2024-12-30 00:00:31 +01:00
Irmen de Jong f42e12bc13 ir: fix more register typing errors 2024-12-30 00:00:31 +01:00
Irmen de Jong 427451a23f ir: remove remaining SL* opcodes 2024-12-30 00:00:31 +01:00
Irmen de Jong af7930d494 ir: remove SL* opcodes 2024-12-30 00:00:31 +01:00
Irmen de Jong e2882d37bf ir: remove a bunch of strange in-place assignment operators, and problematic opcodes 2024-12-30 00:00:31 +01:00
Irmen de Jong 942d3ee640 ir: improve register type detection 2024-12-30 00:00:31 +01:00
Irmen de Jong 7b4a82b91a IR: report register usage and types in code blocks 2024-12-30 00:00:31 +01:00
Irmen de Jong 056c0a24d9 better way of doing BIT instructions 2024-12-30 00:00:31 +01:00
Irmen de Jong 827df04b32 IR: BIT instruction added 2024-12-30 00:00:31 +01:00
Irmen de Jong e174b31344 IR: fix up missing indirect goto codegen 2024-12-30 00:00:31 +01:00
Irmen de Jong 49959af752 IR: support %align in code chunks, and load/store FAC0/FAC1 2024-12-30 00:00:31 +01:00
Irmen de Jong c86c0912f8 latest symboldumps 2024-12-29 20:07:45 +01:00
Irmen de Jong 268b0c9365 fix memory top boundary address on c64 and c128 2024-12-29 17:01:22 +01:00
Irmen de Jong 099fe280ba improved diskio.diskname() error detection 2024-12-29 10:29:31 +01:00
Irmen de Jong f786f60e9c cmb.PLOT: fixed order of return registers (Y then X, column then row) - same as argument order 2024-12-29 07:42:13 +01:00
Irmen de Jong f40e1eb1f2 fixed clipping sample 2024-12-29 00:56:12 +01:00
Irmen de Jong 8b9da65357 Added supervisor to coroutines.run(). update symboldumps for 11.0.1. 2024-12-28 04:44:45 +01:00
Irmen de Jong 2cbbe0d48a remove syscall from docs, it doesn't exist anymore 2024-12-27 22:35:56 +01:00
Irmen de Jong b6e1fb3ba8 emphasize that str[] is also split by default 2024-12-27 17:00:39 +01:00
Irmen de Jong bdccffbb8e stricter type checking in multivalue assigns, avoids possible invalid output due to missing type cast 2024-12-26 22:20:08 +01:00
Irmen de Jong 5a85474712 pet32: fixed txt.plot() mixing up row and column 2024-12-26 19:37:39 +01:00
Irmen de Jong f50899c6fa coroutines: make yield() return a configured uword so that a task subroutine can get reused for multiple different things 2024-12-26 18:55:32 +01:00
Irmen de Jong 4daa909f32 fix path normalization problems,
allow ~ in srcdirs compiler flag
2024-12-26 17:42:20 +01:00
Irmen de Jong 4555edf369 update zsmkit to fix zsm_clearisr routine 2024-12-26 13:06:41 +01:00
Irmen de Jong 529ea5bf58 added coroutines library and multitasking example. Added sys.push_returnaddress(). 2024-12-26 00:57:39 +01:00
Irmen de Jong fe011de934 fix the missing cases in certain expressions that need the address of a split word array 2024-12-25 16:55:07 +01:00
Irmen de Jong 0653d430a7 fix compiler crash related to uword array parameters type checking 2024-12-25 12:12:20 +01:00
Irmen de Jong a587f6e9a0 make imported module cache case-insensitive
this avoids crashes when using case-insensitive filesystems and mistyping the exact path case
2024-12-25 11:51:24 +01:00
Irmen de Jong 3850e1dbb5 Merge branch 'better-ir' 2024-12-24 21:23:57 +01:00
Irmen de Jong 91cde072e0 added txt.t256c() on the cx16 to turn 256 color tile mode on or off 2024-12-24 12:10:02 +01:00
Irmen de Jong 2ca4aed566 IR: prefix immediate values with '#' for human readability reasons (no technical reason) 2024-12-24 09:35:10 +01:00
Irmen de Jong 5071da6784 retain constants in IR
some IR related cleanups
2024-12-24 00:30:08 +01:00
Irmen de Jong 4c1e2f3110 refactor package nesting of ast exception classes 2024-12-23 18:14:46 +01:00
Irmen de Jong 2727a4dcb3 tweak DataType class and memsizer related to subtypes/elementtypes 2024-12-23 17:28:25 +01:00
Irmen de Jong 126d4c69e6 fix cx16images.py script for new pillow library version 2024-12-23 16:31:15 +01:00
Irmen de Jong 7657edcb7d latest symboldumps 2024-12-22 09:24:45 +01:00
Irmen de Jong 580e786952 change math.crc32 to the same algorithm as pkzip/zlib uses (ISO-HDLC). Add math.crc32_end_result(). Fix a parse error in profiler.py script. 2024-12-22 09:19:54 +01:00
Irmen de Jong c0ae35b3a3 tweaks, bump version 11.0 2024-12-22 06:34:17 +01:00
Irmen de Jong c3dc74788a added diskio.get_loadaddress()
added compression.decode_tscrunch_inplace()
2024-12-22 03:17:16 +01:00
Irmen de Jong 379d241a0d various library modules now also use regular asm symbol prefixing rules: buffers, compression, cx16logo, test_stack. 2024-12-21 06:34:55 +01:00
Irmen de Jong 1f49e8fe75 in diskio.f_readline make sure AY result isn't clobbered 2024-12-21 06:25:56 +01:00
Irmen de Jong d70cfbb661 added sorting module and sortingbench example 2024-12-21 06:18:35 +01:00
Irmen de Jong 5482ac0302 simplify grammar of @tags, also improving their error message 2024-12-21 01:44:58 +01:00
Irmen de Jong 131d5ceb4f avoid re-reading all source files when sourcelines are requested in the asm 2024-12-21 00:06:18 +01:00
Irmen de Jong 512ddd1694 cleanups 2024-12-20 22:59:20 +01:00
Irmen de Jong 14a213bff9 compression module: added decode_zx0 and decode_tscrunch
two very fast decompressors while still having pretty good compression ratio
2024-12-20 20:44:57 +01:00
Irmen de Jong d586846bc5 use simpler set_screen_mode() 2024-12-19 22:17:09 +01:00
Irmen de Jong ef4efcb112 cleanup 2024-12-19 21:06:51 +01:00
Irmen de Jong b01555d75e cx16.set_screen_mode() no longer returns anything.
tweak when codegen slightly.
allow trailing comma in array literals.

set_screen_mode failure status is really uncommon and still returned by the real kernal routine screen_mode().
2024-12-19 20:56:07 +01:00
Irmen de Jong 3804fba0f1 moved jdk version config back to main gradle build file, version consistency 2024-12-19 13:39:27 +01:00
Irmen de Jong f93b7e3303 changed IR JUMPI instruction to support more indirect jump cases 2024-12-19 04:29:16 +01:00
Irmen de Jong 73baaeff1f avoid compiler crash when using char literal in str initialization
fix compiler crash when using str var in an expression without &
2024-12-18 15:08:45 +01:00
Irmen de Jong 7c79cdbd2f fix symbol prefixing on goto with expression
added coroutines example
2024-12-17 16:16:38 +01:00
Irmen de Jong 8ea032ed66 fix compiler crash on certain split array values 2024-12-17 12:31:47 +01:00
Irmen de Jong e7a0cb636c add $< and $> operators to get the lsb and msb addresses of a @split array respectively.
document the new split array things.
2024-12-16 17:45:54 +01:00
Irmen de Jong 02f3f5d0f5 @split is back to force splitting of word arrays 2024-12-16 14:51:32 +01:00
Irmen de Jong 1e9bbd662b add palette.set_rgb_nosplit() and set_rbg_be_nosplit()
fix stream-wav missing rts which corrupted playback
fix showbmx example palette and image centering
2024-12-16 02:00:51 +01:00
Irmen de Jong 8644a4ae91 more split array fixes 2024-12-15 22:54:06 +01:00
Irmen de Jong 1e85f7812f removed anyall library module altogether. The routines weren't very optimized and didn't work on split word arrays. 2024-12-15 17:45:31 +01:00
Irmen de Jong 80d88b3c61 fix many split array issues 2024-12-15 17:08:07 +01:00
Irmen de Jong d2827a7431 fix ast printer for arrays containing label addresses 2024-12-15 13:53:24 +01:00
Irmen de Jong 28c721fa7d add a split-array version for word containment check 2024-12-15 13:45:47 +01:00
Irmen de Jong 8f799567cf make word arrays split by default (w.i.p.) 2024-12-15 08:12:34 +01:00
Irmen de Jong 9e8cc8b54d goto can now accept any expression as address (instead of just a constant), and ofcourse a label name still. 2024-12-15 05:22:37 +01:00
Irmen de Jong cc59069876 allow goto to take any expression, not only an integer or an identifier (part 1) 2024-12-14 01:01:32 +01:00
Irmen de Jong 697d54e10a fix asmgen for call $3000 2024-12-13 22:33:26 +01:00
Irmen de Jong 1679ca79b4 can now use boolean params mapped to Rx register 2024-12-13 20:47:23 +01:00
Irmen de Jong 124ec77b58 update zsmkit to version 2.4, including the new on_deck routines 2024-12-13 20:15:36 +01:00
Irmen de Jong 3675d7961b boolean variables can now also be memory-mapped (including boolean arrays) 2024-12-11 18:25:27 +01:00
Irmen de Jong f8aaa2d13c explicit integer type check for @R0-R15 parameters
avoids weird type inconsistency for boolean parameters that would get aliased as unsigned byte instead invisibly
2024-12-10 23:19:41 +01:00
Irmen de Jong b7afda781a Optimize 6502 bitwise operations on word values where only the msb or lsb is touched 2024-12-10 21:42:42 +01:00
Irmen de Jong 535ec13072 improved codegen for testing for single bits: x & mask == mask 2024-12-09 04:05:00 +01:00
Irmen de Jong 26d0a174db optimize codegen for while loops with empty body 2024-12-09 03:21:20 +01:00
Irmen de Jong b2e821755c optimized palette module
removed palette.set_monochrome(), added start color index to several color set functions
removed mcf example
update gradle wrapper
2024-12-08 15:30:42 +01:00
Irmen de Jong 2e303041c1 fix crash when using undefined variable in for loop 2024-12-06 21:50:22 +01:00
Irmen de Jong 96bed8f57f tweaks 2024-12-06 00:37:16 +01:00
Irmen de Jong 86d4a4309f cleanups 2024-12-05 21:56:00 +01:00
Irmen de Jong 1a1ab0dac6 changed the data type system to composite types 2024-12-05 21:48:51 +01:00
Irmen de Jong ba8c3d14f7 diskio docs, remove super harmless warning message 2024-12-05 20:51:44 +01:00
Irmen de Jong 617ea15c3a fix failing optimization of 'not' in if statements 2024-12-04 19:03:24 +01:00
Irmen de Jong ef192a5778 easier notation for builtin function signatures by using varargs 2024-12-04 01:57:02 +01:00
Irmen de Jong 565973c520 diskio read & write routines now always reset the io channels back to the defaults before returning
This means you don't have to call CLRCHN yourself anymore inbetween if you want to do screen output or keyboard input while a file is open
2024-12-03 23:46:07 +01:00
Irmen de Jong 25b1043572 c64 diskio: Always call CLRCHN before CHKIN/CHKOUT calls
this seems to work around a Vice emulator issue when using host filesystem disk emulation.
Fixes #156
2024-12-03 19:15:44 +01:00
Irmen de Jong 1ebfff7c7b add -plaintext and -ignorefootguns options 2024-12-03 19:12:30 +01:00
Irmen de Jong 8341f9c066 diskio.status(): remove unreliable device not present error detection 2024-12-02 23:33:33 +01:00
Irmen de Jong 28cac291de diskio.f_open_w() now also resets io channels back to defaults, like f_open() already did 2024-12-02 22:25:32 +01:00
Irmen de Jong 8fa14a10e2 Optimize diskio.f_read for size=1, also improve ST check 2024-12-02 21:25:38 +01:00
Irmen de Jong 55dbd095ed fix IR codegen missing a CMPI after if not condition
fix IR codegen for containmentcheck
2024-12-02 03:06:06 +01:00
Irmen de Jong 31ad8bdd8d remove bankof(), documented msw() and lsw() 2024-12-01 21:24:26 +01:00
Irmen de Jong 181f3e9eb1 remove the unary/prefix operators ^ and << again 2024-12-01 20:50:33 +01:00
Irmen de Jong 50c3d809dc fix type casting issues and unary ^ operator
signed numbers are no longer implicitly converted to unsigned
proper range check on bankof()
2024-12-01 17:43:53 +01:00
Irmen de Jong 58f696d00a document the @R0 - @R15 register support for normal subroutine parameters 2024-11-30 20:46:31 +01:00
Irmen de Jong f603c543d3 restructure documentation to get rid of redundant syntax chapter 2024-11-30 20:26:06 +01:00
Irmen de Jong 6aaa0f928e IR: fix invalid asm name matching that resulted in not removing subs with a name matching an IR asm instruction 2024-11-30 00:10:57 +01:00
Irmen de Jong feb8aa435e monogfx, gfx_lores, gfx_hires now all uses 8kb stack from buffers module; no more broken flood fills. fill() has an extra byte parameter now where you need to pass in the ram bank to use for the stack. (not on virtual target) 2024-11-29 21:28:34 +01:00
Irmen de Jong 310e8f15cd update to latest zsmkit lib v2.2 2024-11-29 18:37:06 +01:00
Irmen de Jong da03941582 fix build 2024-11-29 01:01:59 +01:00
Irmen de Jong dcbb36a3bd update gradle wrapper version 2024-11-29 00:54:21 +01:00
Irmen de Jong 53558f5c1d add zmskit example for zsmkit v2 2024-11-29 00:04:57 +01:00
Irmen de Jong 189399d5f8 update to kotlin 2.1.0 2024-11-28 03:49:07 +01:00
Irmen de Jong 5406a992f5 improved buffers library, added to docs 2024-11-28 03:30:32 +01:00
Irmen de Jong bc9683cc54 add compression.decode_rle_vram() to decompress RLE data directly to X16's VRAM.
Document the compression library.
2024-11-26 02:06:35 +01:00
Irmen de Jong 2eed75f602 call convention for @Rx parameters, also use cpu registers if possible, like normal parameters 2024-11-25 22:22:24 +01:00
Irmen de Jong d58f9f56c4 tests for register args for normal subs
some warnings demoted into infos
2024-11-24 19:21:45 +01:00
Irmen de Jong 2e35f3c3a3 code check cleanups 2024-11-24 16:14:22 +01:00
Irmen de Jong 5c6bd9c091 register params support for normal subroutines 2024-11-24 15:56:54 +01:00
Irmen de Jong 857d2eefca added floats.interpolate(), math.interpolate(), and LERP example 2024-11-24 10:00:21 +01:00
Irmen de Jong 90f1e7fd6a ast printing fixes, added alias to syntax files 2024-11-24 07:28:33 +01:00
Irmen de Jong 18e37accf9 improve detection of register re-use in parameters 2024-11-24 05:27:43 +01:00
Irmen de Jong cc53d698bf added msw() and lsw() builtin functions (experimental) 2024-11-24 03:53:37 +01:00
Irmen de Jong cb86206698 added unary ^ and << operators (experimental) (gets bank and address of a long integer) 2024-11-24 03:07:18 +01:00
Irmen de Jong d77b1944fb rename bnk() to bankof() 2024-11-24 00:53:09 +01:00
Irmen de Jong a58cb43c4a fixed weird error messages when attempting to create variable with type long 2024-11-23 21:35:57 +01:00
Irmen de Jong 88574c87c4 convert vtui and zsmkit to new extsub address expression capability 2024-11-23 21:21:52 +01:00
Irmen de Jong 3a7a7091c0 update some docs 2024-11-23 21:01:18 +01:00
Irmen de Jong 906b137a7c renamed 'string' module to 'strings' for consistency 2024-11-23 15:51:38 +01:00
Irmen de Jong 42e2c5f605 fix some deprecated code in tests
silence redundant error about unused txt block
2024-11-23 15:48:18 +01:00
Irmen de Jong cc13a51493 fix import order problem related to %option merge 2024-11-23 12:15:15 +01:00
Irmen de Jong f569ce6141 setting a byte >=128 or word >=32768 now results in an out-of-range error, instead of an invalid casted value 2024-11-22 21:24:04 +01:00
Irmen de Jong 4958463e75 moved floats.MIN/MAX to sys.MIN_FLOAT/MAX_FLOAT
added txt.print_f as alias to floats.print
2024-11-22 00:46:23 +01:00
Irmen de Jong 2360625927 added min/max values for the various integer types as sys.MAX_XXX and sys.MIN_XXX
renamed sys.sizeof_xxx into sys.SIZEOF_XXX to be consistent with the uppercasing of the other constants
2024-11-21 23:25:02 +01:00
Irmen de Jong 8badc40883 added several float limits contants such as floats.EPSILON, E, MIN, MAX
fix VM float min max limits
2024-11-21 23:25:02 +01:00
Irmen de Jong 844c97930f fix Antlr grammar build and convert final build.gradle to build.gradle.kts (kotlin DSL) 2024-11-20 23:23:26 +01:00
Irmen de Jong 5c09dc10ae convert build.gradle to build.gradle.kts (kotlin DSL) 2024-11-20 23:23:26 +01:00
Irmen de Jong 9fd9e9ab5f change block sort order so that blocks with address are now sorted last 2024-11-20 23:23:26 +01:00
Irmen de Jong 35c477b5a6 Make extsub address a (constant) expression instead of a numeric literal
this makes it easier to define API jump tables
2024-11-20 23:23:26 +01:00
Irmen de Jong ae0cadb383 added bnk() builtin function 2024-11-20 23:23:21 +01:00
Irmen de Jong 984230e8fa removed txt.VERA_TEXTMATRIX_BANK/VERA_TEXTMATRIX_ADDR it's now just txt.VERA_TEXTMATRIX (long const) 2024-11-20 23:22:56 +01:00
Irmen de Jong a874aec6a1 implementing const long 2024-11-20 23:22:56 +01:00
Irmen de Jong ea1daa97d3 remove the 'addmissingrts' compiler option 2024-11-20 23:22:56 +01:00
Irmen de Jong fb0d9b46b0 remove 'romsub' as a recognised alternative for 'extsub' 2024-11-20 23:22:56 +01:00
Irmen de Jong 9da70bdf05 simplify ReturnConvention a little 2024-11-20 23:22:56 +01:00
Irmen de Jong d640cfbe13 removed BuiltinFunctionCallStatement redundant ast node type 2024-11-20 23:22:56 +01:00
Irmen de Jong 51a05ec4b7 removed BuiltinFunctionCall redundant ast node type 2024-11-20 23:22:56 +01:00
987 changed files with 206674 additions and 47307 deletions

No files matched your search

+5
View File
@@ -0,0 +1,5 @@
---
description: Startup workflow to load project context
---
1. Read the file `AGENTS.md` in the project root as initial system prompt to build context and instructions about the project structure, module descriptions, and development commands.
+204
View File
@@ -0,0 +1,204 @@
---
name: asm6502-coder
description: Writing or understanding 6502/65C02 assembly in 64tass syntax, standalone or embedded in Prog8
---
# 6502 Assembly Coder
Use 64tass syntax, not ca65 or another assembler. Keep answers concise and
practical. This applies to standalone `.asm` files and Prog8 `%asm {{ }}` or
`asmsub` blocks.
Reference documentation for the assembler is available locally in
`~/Documents/prog8-dev-resources` (the 64tass manual, `64tass.md`). Search this
folder first before looking online.
## Syntax
- Labels begin in column 1. Instructions are indented at least four spaces.
- Use lowercase opcodes and operands, two spaces between opcode and operand,
and two spaces before end-of-line comments.
- Hex is `$1234`, binary is `%1010`, decimal is `123`.
- Use `.byte`, `.word`, `.dword`, `.fill`, `.text`, and equates such as
`name = value`.
- Sections use `.section name` and `.send name`.
- Procedures use `.proc` and `.pend`; labels beginning with `_` are local to a
procedure.
- Conditional assembly uses `.if`, `.elsif`, `.else`, and `.endif`.
## Anonymous Labels
Anonymous label definitions are always a single `+` or `-` in column 1.
References use repeated signs:
- `+` is the next upcoming `+` definition, `++` the second, `+++` the third.
- `-` is the most recent `-` definition, `--` the preceding one, and so on.
- Passing a `+` definition resets the forward-reference count.
```asm
- dex
bne - ; most recent '-' above
ldx #5
+ dex ; first upcoming '+'
bne + ; this '+'
sta $400
+ lda #0 ; second '+' definition
bne ++ ; next '+' after this one
rts
+ inc $d020 ; third '+' definition
```
## CPU Differences
- `cx16` is the only Prog8 target that supports 65C02 instructions such as
`stz`, `phx`, `plx`, `phy`, `ply`, `bra`, `trb`, `tsb`, `wai`, `stp`, and
`bit #imm`. C64, C128, and PET32 use the original 6502.
- Rockwell instructions (`rmb`, `smb`, `bbr`, `bbs`) are not available.
- Use an explicit `a` for accumulator forms such as `rol a`, `lsr a`, `inc a`,
and `dec a`.
- Branches are relative. Prog8's assembler invocation enables `--long-branch`
for out-of-range branches.
- `lda`, `ldx`, and `ldy` do not affect carry. `cmp` sets carry for
`register >= operand`.
- On NMOS 6502, `jmp ($xxff)` wraps the high-byte fetch within the page.
- `BRK` skips the byte after its opcode. The byte is commonly a handler
signature.
- `bit` memory forms set N and V from the operand and Z from `A AND operand`.
65C02 `bit #imm` sets only Z.
- Decimal mode can persist into NMOS IRQ handlers. Use `cld` at handler entry
and explicitly control D before `adc` or `sbc`.
## Prog8 Integration
`asmsub` parameter names are documentation only. Use the actual registers or
define assembly aliases, and list every modified register in `clobbers`.
```prog8
asmsub increment(uword value @R0) clobbers (A, X) {
%asm {{
lda cx16.r0L
clc
adc #1
sta cx16.r0L
}}
}
```
Annotations include `@A`, `@X`, `@Y`, `@AX`, `@AY`, `@R0`-`@R15`, `@FAC1`,
`@FAC2`, `@Pc` (carry), and `@Pz` (zero). Unmapped parameters are accessed as
`p8v_name`.
Prog8 symbols use these prefixes: `p8v_` variables and parameters, `p8s_`
subroutines, `p8b_` blocks, `p8c_` constants, `p8l_` labels, and `p8t_` struct
types. Fully qualified names may look like
`p8b_main.p8s_helper.p8v_local`. `%option no_symbol_prefixing` disables the
prefixes. Split word arrays use `_lsb` and `_msb` symbols.
## Zeropage and Memory
- Never hardcode zeropage addresses. Use `P8ZP_SCRATCH_B1`,
`P8ZP_SCRATCH_REG`, `P8ZP_SCRATCH_W1`, `P8ZP_SCRATCH_W2`, and
`P8ZP_SCRATCH_PTR`, or the appropriate `cx16.r0`-`cx16.r15` symbols.
- Scratch variables are not necessarily consecutive. CX16 virtual registers
are consecutive and have `L` and `H` byte names.
- Allocate additional temporary storage in BSS.
- The hardware stack occupies `$0100-$01ff` and is limited. Do not overflow
it.
- Prog8 words are little-endian: load the low byte first, then the high byte.
```asm
clc
lda word1
adc word2
sta result
lda word1+1
adc word2+1
sta result+1
```
## Common Patterns
```asm
ldy #index
lda (ptr),y
jsr p8s_main.p8s_helper
```
Avoid self-modifying code unless it is explicitly required. It cannot run
from ROM and complicates debugging and tooling. Prefer lookup tables, RAM
vectors, or alternative algorithms.
## Reference
### Primary: 6502 Family CPU Reference
<https://www.pagetable.com/c64ref/6502/?cpu=65c02&tab=2> is the reference to reach for.
It covers the whole 6502 family and lets you **select the CPU variant**, which matters
because the parts genuinely differ. The variants are `6502`, `6502rorbug`, `65dtv02`,
`65c02`, `r65c02` (Rockwell), `65c02s`, `65ce02` and `65c816`. Change the `cpu=` query
parameter to switch; for Prog8, use `cpu=65c02` when working on cx16 and `cpu=6502` for
c64, c128 and pet32.
Per instruction it gives the operation, the opcodes, the byte length, the cycle count
and which status flags are affected, with tabs for opcodes, instructions, addressing
modes and a full opcode table (switchable between 4-4 and 3-3-2 layout). It can also
show the NMOS undocumented opcodes, and each part lists what it is based on, so a
variant's inherited instructions are visible.
Cycle counts use a compact notation worth knowing: a trailing `t` means +1 if a branch
is taken, `p` means +1 if a page is crossed, and `d` means +1 when the D (decimal) flag
is set. So `d0 2+t+p` for `bne` is 2 cycles, 3 if taken, 4 if taken across a page.
Consult it whenever an exact figure is needed rather than recalled: the byte length or
cycle cost of an instruction, which flags it clobbers, whether an addressing mode exists
on the target CPU, or whether an instruction belongs to a different part at all. Typical
reasons are costing a peephole or code-size tradeoff, checking a hand-written routine,
and confirming a mnemonic is valid before using it.
Do not assume a timing from memory or from another part. Cycle counts are exactly the
kind of detail that is misremembered, and the difference matters when it is the basis of
an optimization claim. Read the number off the reference for the specific CPU being
targeted.
### Secondary: WDC 65C02 reference
<https://cx16.dk/65c02/reference.html> is a 65C02-only reference. It is worth having
because it states each instruction's effect in a single formula (for example
`ADC: A,Z,C,N = A+M+C`), which makes the flag behaviour quick to check, and it lists
every status bit per instruction including the ones not affected. Use it for flag
semantics; use the primary reference for timings and for anything CPU-specific, since
it covers the 65C02 only and will not answer a question about the NMOS 6502.
### Neither reference covers the assembler
Both document the CPU, not 64tass. For whether 64tass accepts a mnemonic or a given
syntax, assemble it: an instruction outside the selected CPU set fails with
`error: general syntax` rather than being silently ignored. Note also that 64tass has
no `w65c02s`; its CPU selection is `--m65xx` (default), `--m65c02` and `--m65ce02`, and
Prog8 emits `.cpu 'w65c02'`.
## Tools
Prog8 invokes 64tass with `--ascii --case-sensitive --long-branch -Wall` plus
the target output option such as `--cbm-prg`. For manual assembly:
```bash
64tass --ascii --case-sensitive --long-branch -Wall --cbm-prg \
-o myprogram.prg myprogram.asm
```
For debugging, add `--vice-labels --labels=labels.txt` and/or
`--list=listing.txt`.
To check an instruction's encoding or size, assemble it in isolation and read the
output bytes. The 2-byte load address comes first, so `stx $7b` / `ldy $7b` below
shows as `86 7b a4 7b` - two instructions, four bytes:
```bash
printf '.cpu %s\n* = $0801\nlbl\tstx\t$7b\n\tldy\t$7b\n' "'w65c02'" > sz.asm
64tass --ascii --case-sensitive --cbm-prg -o sz.prg sz.asm && xxd sz.prg
```
Note that a 64tass label takes no trailing colon; `lbl:` is a syntax error reported as
`error: label required`.
+197
View File
@@ -0,0 +1,197 @@
---
name: m68k-coder
description: Writing or understanding Motorola 68000/68020 assembly in vasm mot syntax, standalone or embedded in Prog8
---
# M68K Assembly Coder
Use Motorola syntax for `vasm`, not Devpac or other assemblers. Keep answers
concise and practical.
Reference documentation for the assembler and linker is available locally in
`~/Documents/prog8-dev-resources` (the vasm and vlink manuals). Search this
folder first before looking online.
## Syntax
- Labels begin in column 1. Instructions are indented at least four spaces.
- Use lowercase opcodes and operands, two spaces between opcode and operand,
and two spaces before end-of-line comments.
- Use `.b`, `.w`, and `.l` for byte, word, and long operations. Do not rely on
default sizes.
- Hex is `$1234`, binary is `%1010`, decimal is `123`, and characters use
`#'A'`.
- Local labels start with `.`. Equates use `name = value`.
- Data directives are `dc.b`, `dc.w`, `dc.l`; allocation directives are
`ds.b`, `ds.w`, `ds.l`.
- Sections use forms such as `SECTION .text,code` and `SECTION .bss,bss`.
```asm
moveq #0,d0
move.w value,d0
add.l d1,d0
.loop
dbra d0,.loop
```
## FPU Size Suffixes
FPU instructions that access memory **must** include a size suffix: `.s`
(single, 4 bytes), `.d` (double, 8 bytes), or `.x` (extended, 12 bytes).
Without a suffix, vasm defaults to `.x`, reading 12 bytes and corrupting
results when the operand is smaller.
**Use `.s` with memory operands:**
```asm
fmove.s value(pc),fp0 ; load float from memory
fcmp.s other(pc),fp0 ; compare float in memory
ftst.s value(pc) ; test float in memory
```
**Omit the suffix for register-to-register operations:**
```asm
fadd fp1,fp0 ; fp0 = fp0 + fp1
fcmp fp1,fp0 ; compare fp0 vs fp1
ftst fp0 ; test fp0
fintrz fp0,fp0 ; truncate fp0
```
The FPU registers are always 80-bit internally, so no size suffix is needed
when both operands are registers.
## Architecture
- Registers `D0-D7` and `A0-A7` are 32-bit; `A7` is the stack pointer.
- Pointers are 32-bit and must normally be accessed with `.l`.
- Memory is big-endian: `$1234` is stored as `$12,$34` and a long's low byte
is at offset `+3`.
- Word and long accesses must be even-aligned on 68000. 68020 permits
misalignment but it is slower.
- **Byte `A7` auto-update steps by 2, not 1.** If A7 (== SP, the stack pointer) is the address
register and the operand length for post-increment or post-decrement is one byte, A7 is
decremented/incremented by 2 instead of 1, to maintain a word-aligned stack. This is the
specified behaviour of all the 680x0, not a 68000 quirk, so it is identical everywhere and
safe to rely on. Word and long operands step by 2 and 4.
```asm
move.b d0,-(sp) ; A7 steps by 2, so SP stays word-aligned
...
addq.l #2, sp ; and the matching pop is #2, not #1
```
Do not "fix" this to an explicit `subq.l #1,sp`: that leaves SP odd and cause crash.
- The 68000 (`amiga500`) has only word multiply/divide and no scaled indexing,
bit-field, or 32-bit multiply/divide instructions. The 68020 (`qemu68k`)
adds those features and `extb.l`.
- On 68000, sign-extend a byte with `ext.w` followed by `ext.l`.
- `move.b` and `move.w` to a data register do not clear its upper bits. Like
`move.w` only writes the lower 16 bits, `move.b` only writes the lower 8 bits;
both leave all other bits of the register untouched. So zero-extending a byte
to long requires `moveq #0,d0` first, then `move.b src,d0`, then `move.l d0,dst`
(or mask with `and.l #$ff` / `and.l #$ffff`). Relying on `move.b` to clear the
upper bits is a common bug that corrupts values.
- `movea` does not set condition codes; `move` does. Keep the stack word
aligned and push words or longs, never bytes.
## Registers and Calls
- Return values use `D0` (primary), `D1` and `D2` (additional), or `A0` for a
pointer.
- `D0-D1` and `A0-A1` are scratch registers. Preserve registers required by
the surrounding calling convention, especially `D2-D7` and `A2-A6`.
- Never clobber `A5`: on every M68K target it is the Prog8 stack frame pointer
(locals at negative offsets, parameters at positive offsets). Overwriting it
corrupts the frame of the running subroutine and breaks unwinding.
- Never clobber `A6` on the Amiga targets (`amiga500`, `amiga1200`): it holds
the AmigaOS library base pointer that library calls depend on. Prog8 itself
leaves `A6` free for that reason.
- `move.l d0,-(sp)` pushes and `move.l (sp)+,d0` pops.
### Prog8 M68K stack ABI
- Normal framed subroutines use `link a5,#-N` and `unlk a5`; locals are at
negative `A5` offsets and incoming parameters are at positive offsets.
- Arguments use word-packed slots of natural width: byte, bool, word and uword
arguments take a 2-byte slot; long, pointer and float arguments take a 4-byte
slot. The caller pushes arguments left-to-right (a byte sits at the base byte
of its 2-byte slot, the second byte is garbage; word values fill their slot)
and removes the complete argument area after the call. The area
size is always even, so the stack stays word-aligned; slot bases accumulate from
the rightmost argument at `8(a5)` according to each argument's width.
- A normal call preserves the caller's frame. A `goto` or conditional branch
leaving the current subroutine must execute `unlk a5` on the taken path before
transferring control.
- The built-in Prog8 `call(address)` is a zero-argument indirect call. It does
not marshal stack arguments. `asmsub` and `extsub` keep their explicit
register-annotated ABI, separate from normal framed calls.
- Push narrow arguments into their own 2-byte slots, each with one instruction: a
byte uses `move.b ..., -(sp)` (A7 byte predecrement steps by 2, reserving the
slot; the byte lands at the slot's base byte), a word uses a plain
`move.w ..., -(sp)`. Never push a narrow value where the callee expects a
wide (4-byte) argument: the slot sizes must line up exactly.
Wide arguments (`move.l ..., -(sp)` / `fmove.s fp0,-(sp)`) push in one step.
Use `lea N(sp),sp` for the cleanup when the call returns a status flag
(`addq` clobbers CCR).
## Prog8 Integration
Assembly can appear in `%asm {{ }}` blocks or `asmsub` routines. `asmsub`
parameter names are documentation only: use the actual annotated registers.
Declare every modified register in `clobbers`.
```prog8
asmsub add100(uword value @D0) -> uword @D0 clobbers (D0) {
%asm {{
add.w #100,d0
}}
}
```
Do not use `%option no_sysinit` on `amiga500` or `qemu68k` targets when the goal
is to create normal runnable programs. It skips critical startup logic including
library initialization and CLI argument handling, causing programs to crash on
start.
Supported annotations include `@D0`-`@D7`, `@A0`-`@A6`, virtual `@R0`-`@R15`,
floating-point `@FP0`-`@FP7`, and flags `@Pc` and `@Pz`.
Prog8 assembly symbols are prefixed:
| Prefix | Symbol |
| --- | --- |
| `p8v_` | variable or parameter |
| `p8s_` | subroutine |
| `p8b_` | block |
| `p8c_` | constant or enum member |
| `p8l_` | label |
| `p8t_` | struct type |
Use fully qualified names when needed, such as
`p8b_main.p8v_value`. `%option no_symbol_prefixing` disables prefixes.
```asm
move.l p8v_pointer,a0
move.w p8v_word,d0
jsr p8s_main.p8s_helper
```
## Useful Patterns
```asm
lea source,a0
lea dest,a1
.copy
move.b (a0)+,(a1)+
bne.s .copy
```
Use `moveq` for small constants, `addq`/`subq` for constants 1 through 8, and
`lea` for address arithmetic. Check divisors for zero and division overflow.
## Tools
For QEMU 68k, Prog8 invokes `vasmm68k_mot` with `-m68020 -m68881 -Felf
-opt-speed -warnunaligned -ldots -spaces`, then links with `vlink`. For raw
binary output use `-Fbin` and `-join=0x<addr>`. Add `-L listing.txt` when a
listing is needed.
Prog8 runs `amiga500` programs with `vamos --cpu 68000` and `qemu68k` programs
with `qemu-system-m68k -M virt -cpu m68020 -m 1M -kernel program.elf -nographic`.
+168
View File
@@ -0,0 +1,168 @@
---
name: prog8-coder
description: Writing or understanding Prog8 programs and Prog8 IR
---
# Prog8 Coder
You are an expert Prog8 assistant. Keep answers concise and practical. This
skill covers `.p8` source and `.p8ir` intermediate representation for the
6502, M68000, and virtual targets.
Various reference documentation is available locally in
`~/Documents/prog8-dev-resources`:
Prog8 reference documentation, emulator manuals such as VICE and the X16
emulator, the 64tass/vasm/vlink assembler and linker docs, X16 hardware and register specs,
the Amiga NDK (docs and includes), and other resources.
Search in this folder first before looking online!
## Essentials
- A program normally has a `main` block with a parameterless `start` entry
subroutine. Other blocks and subroutines may be added.
- `%import modulename` imports a module without aliases. Use its defined prefix,
such as `%import textio` followed by `txt.print(...)`.
- `sys` is always available and needs no import.
- `.p8ir` is target-independent IR and can be run with
`prog8c -vm program.p8ir`.
- Use `%zeropage basicsafe` in test programs when a clean return is needed.
- Find library routines with `prog8c -libsearch <regex>` or extract them with
`prog8c -libdump <dir>`.
- Options accept single-dash or double-dash (`-target` == `--target`). Use
`-out <dir>` to place output in a directory, or `-o <file>` to name the exact
final program artifact (all other output files then land beside it).
For CX16 emulator programs, use `%encoding iso`, call `txt.iso()` in `start`,
and finish with `sys.poweroff_system()`. CBM targets use PETSCII by default;
avoid uppercase in test output unless intentional graphics. The virtual target
uses ISO when configured with `%encoding iso` and `txt.iso()`.
On any CBM machine with PETSCII (this includes the Commander X16), files
on disk must only consist of 'safe' characters (`a-z`, `0-9`, `.-+!%`).
Do NOT mix casing in filenames; in Prog8 source code, filenames should
usually be written in *lowercase* letters. Other characters (such as
`_` or uppercase mixed with lowercase) can make kernal file operations
fail, depending on the drive/host layer.
Do not use `%option no_sysinit` on `amiga500`, `amiga1200`, or `qemu68k` targets when the goal
is to create normal runnable programs. It skips critical startup logic including
library initialization (DOS, graphics, intuition, timer) and CLI argument
handling, causing programs to crash on start. It is appropriate for library
modules, IRQ handlers, boot stubs, or code that deliberately avoids those
libraries.
## Types and Memory
- Primitive types include `bool`, `byte`, `ubyte`, `word`, `uword`, `long`,
`float`, `str`, and `pointer`.
- `pointer` is target-sized: 16-bit on 6502 targets, 32-bit on `amiga500`,
`qemu68k`, and `virtual`. Use it for portable addresses, not `uword` or
`long` chosen by assumption.
- M68000 targets are big-endian and use 32-bit pointers. Load the `m68k-coder`
skill for assembly details.
- `float` requires `%import floats`.
- On 6502 and virtual targets, variables are statically allocated and
zero-initialized. There is no normal call stack for locals, so recursion
overwrites locals unless an explicit hardware or software stack is used.
Iterative rewrites are preferred. Arrays are cleared once at startup here,
not on every subroutine entry.
- On the M68000 targets (`amiga500`, `amiga1200`, `qemu68k`) ordinary subroutine
locals and parameters live in an activation record on the CPU stack, so true
recursion and re-entrancy work. `link a5,#-N` / `unlk a5`, frame pointer `A5`,
locals at negative offsets, parameters at positive offsets. Block-level
variables, globals, `@shared`, memory slabs, and objects needing a permanent
external address stay static. Clean locals are zeroed on every call
including arrays, so the compiler warns for framed arrays over 8 bytes; use
`@dirty` when you assign first, otherwise you read stack garbage.
- Normal M68K calls use word-packed argument slots: byte/bool/word/uword arguments
take a 2-byte slot, long/pointer/float take 4 bytes. The caller pushes arguments
left-to-right and removes the complete argument area after the call. Slot bases
accumulate right-to-left starting at positive `A5` offset 8, so a parameter's
offset depends on the widths of the parameters to its right; locals use negative
offsets. See `docs/source/technical.rst` for the full convention and static
fallback rules.
- `memory(name, size)` reserves static memory and returns a `pointer`.
- `str` and arrays have compile-time byte budgets. On 6502 targets the usual
limit is 256 bytes; M68000 targets allow up to 32768 bytes. Use `memory()`
for larger data.
- Word arrays are split into LSB/MSB arrays by default. Use `@nosplit` when
contiguous storage is required.
- Variable tags follow the type and array dimensions, before the name:
```prog8
ubyte[8] @shared vera_storage
uword @requirezp address
```
Use `@shared` for values accessed externally by assembly. Use `@zp` and
`@requirezp` sparingly because zeropage is limited. Never assume virtual
registers survive calls. Long operations may clobber `R12-R15`.
## Syntax Pitfalls
- Hex uses `$FF`, binary uses `%1010`, and casts use `expression as type`.
- There is no automatic type widening in expression results: `byte * byte`
remains a byte. Cast explicitly when a wider result is needed. Assignments,
call arguments, and mixed-type expressions do widen implicitly
(`ubyte`/`byte` to `word`/`uword` to `long`); only same-width signedness
reinterpretation (`uword` to `word` and back) needs an explicit `as` cast.
- `&` is an untyped address and `&&` is a typed pointer. Complex pointer field
assignments may require `ptr^^.field`.
- `and`, `or`, `xor`, and `not` are logical operators. Use `&`, `|`, `^`, and
`~` for bitwise operations.
- `and` and `or` short-circuit, so the right operand may not be evaluated.
- There is no `elif`, bare block, or semicolon statement separator. Semicolon
starts a comment. Prefer one statement per line and four-space indentation.
- `defer` executes registered statements in reverse registration order.
- Array indexing starts at zero. Use `len(array)` rather than hardcoded sizes.
- There is no function overloading. Call type-specific library routines such as
`txt.print_ub` or `txt.print_w`.
## Control Flow
Prog8 supports `if`/`else`, `when`, `for`, `while`, `do`/`until`, `repeat`,
`unroll`, `break`, `continue`, `goto`, and labels. `unroll` duplicates a
constant-count body at compile time and does not support `break` or `continue`.
`repeat` is usually more efficient than `for` when no loop variable is needed.
Replace a `for` loop with a `repeat` loop when the loop variable is not used in the loop body.
Use `if_cs`, `if_cc`, `if_z`, and `if_nz` for direct CPU-flag branches.
## Subroutines and Assembly
- Subroutines can return zero, one, or multiple values:
`a, b = routine()` or `void routine()`.
- On M68K, ordinary calls preserve the caller's active frame. A `goto` or branch
that leaves the current subroutine must tear that frame down before transferring
control. The built-in `call(address)` is a zero-argument indirect call; it does
not marshal stack arguments.
- Avoid `private` unless requested. Prog8 symbols are public by default.
- `asmsub` bodies contain only one `%asm {{ ... }}` node. Parameters are type
checked and documented, but assembly must use the mapped registers. Declare
every modified hardware register in `clobbers`.
- On M68K targets never clobber `A5`, the stack frame pointer. On the Amiga
targets never clobber `A6` either, it holds the AmigaOS library base.
- `extsub` maps a signature to a fixed external address and has no body. Use
it for ROM, kernel, drivers, or binary-library routines.
- For inline assembly, load `asm6502-coder` for 64tass syntax, target-specific
instructions, zero-page rules, and symbol references. Load `m68k-coder` for
M68000 assembly.
## Interrupts and Hardware
- Keep IRQ handlers short. Set a flag and do substantial work in the main loop.
- Virtual registers `R0-R15` are not preserved across IRQ handlers. Avoid them
or save and restore them with the library routines.
- CX16 IRQ handlers that touch VERA registers must save and restore VERA
context.
- Use only symbolic scratch names such as `P8ZP_SCRATCH_W1` and
`cx16.r0`; never hardcode zeropage addresses.
## Verification
- Use the `virtual` target for behavioral tests when possible:
`prog8c -target virtual -emu program.p8`.
- Use `-check` for syntax and semantic checks without output generation.
- Use `-noopt` to determine whether a failure is optimizer-related.
- For IR execution, use `-vmtrace` when control flow needs inspection.
+20
View File
@@ -0,0 +1,20 @@
# An .aiignore file follows the same syntax as a .gitignore file.
# .gitignore documentation: https://git-scm.com/docs/gitignore
# you can ignore files
.DS_Store
*.log
*.tmp
*.bin
*.prg
# or folders
dist/
build/
out/
output/
gradle/
Libs/
.gradle/
.kotlin/
.git/
+45
View File
@@ -0,0 +1,45 @@
# EditorConfig for Prog8 projects
# Ensures consistent formatting across editors and team members
# See https://editorconfig.org
root = true
# All files
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
# Prog8 source files (.p8)
[*.p8]
indent_style = space
indent_size = 4
# Assembly files (.asm) - 64tass syntax
[*.asm]
indent_style = space
indent_size = 4
# Kotlin compiler source files
[*.kt]
indent_style = space
indent_size = 4
trim_trailing_whitespace = false
# Documentation files
[*.md]
trim_trailing_whitespace = false
[*.rst]
trim_trailing_whitespace = false
# Gradle build files
[*.gradle.kts]
indent_style = space
indent_size = 4
# Git ignore files
[.gitignore]
indent_style = space
indent_size = 2
+2 -1
View File
@@ -2,7 +2,7 @@
#github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
#patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
#open_collective: # Replace with a single Open Collective username
ko_fi: irmen
#tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
#community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
@@ -11,3 +11,4 @@ ko_fi: irmen
#otechie: # Replace with a single Otechie username
#lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
#custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
custom: ['https://paypal.me/irmendejong']
+27 -14
View File
@@ -10,32 +10,45 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: build and install recent 64tass
- name: install 64tass
run: |
sudo apt-get install -y make build-essential
git clone --depth=1 https://github.com/irmen/64tass
cd 64tass
make -j4
sudo make install
sudo apt update
sudo apt install 64tass
64tass --version
- name: Set up JDK 11
uses: actions/setup-java@v4
- name: Set up JDK 17
uses: actions/setup-java@v5
with:
java-version: 11
java-version: 17
distribution: temurin
- name: Build and test with Gradle
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v6
- name: Compile
run: ./gradlew compileKotlin compileTestKotlin --console=plain
- name: Test
run: ./gradlew test --continue --max-workers=3 -PtestConcurrency=2 -PtestMaxHeap=8g --console=plain
- name: Package
run: |
./gradlew build shadowJar --no-daemon
./gradlew shadowJar --console=plain
sha256sum -b compiler/build/libs/*-all.jar > compiler/build/libs/hash.txt
- name: Create compiler shadowJar artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
name: prog8-compiler-jar-zipped
path: |
compiler/build/libs/*-all.jar
compiler/build/libs/hash.txt
- name: Upload test results
if: always()
uses: actions/upload-artifact@v6
with:
name: test-results
path: compiler/build/test-results/test/
+14 -2
View File
@@ -3,14 +3,23 @@
.idea/developer-tools.xml
.idea/usage.statistics.xml
.idea/shelf/
.junie/
.junie/memory/
.serena
build/
dist/
output/
out/
out-new/
out-old/
.*cache/
*.directory
*.prg
*.elf
*.o
*.bin
*.p8ir
*.bankedcalls
*.labels.txt
*.vm.txt
*.vice-mon-list
@@ -19,6 +28,7 @@ parser/**/*.interp
parser/**/*.tokens
parser/**/*.java
compiler/src/prog8/buildversion/*
languageServer/src/prog8/buildversion/*
*.py[cod]
*.egg
*.egg-info
@@ -32,8 +42,10 @@ parsetab.py
.pytest_cache/
.attach_pid*
compiler/lib/
.gradle
sd*.img
*.d64
AsyncIO/
AsyncIO.info
m68k-amigaos-ahi/
Libs/
+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JunieProjectTechnologies">
<option name="explicitlyEnabledTechs">
<set>
<option value="junie.python" />
</set>
</option>
</component>
</project>
+12 -2
View File
@@ -2,6 +2,16 @@
<project version="4">
<component name="CompilerConfiguration">
<option name="BUILD_PROCESS_HEAP_SIZE" value="3000" />
<bytecodeTargetLevel target="11" />
<bytecodeTargetLevel target="11">
<module name="prog8.codeGenExperimental" target="17" />
<module name="prog8.codeGenExperimental.main" target="17" />
<module name="prog8.codeGenExperimental.test" target="17" />
<module name="prog8.codeGenM68k" target="17" />
<module name="prog8.codeGenM68k.main" target="17" />
<module name="prog8.codeGenM68k.test" target="17" />
<module name="prog8.codeGenNew6502" target="17" />
<module name="prog8.codeGenNew6502.main" target="17" />
<module name="prog8.codeGenNew6502.test" target="17" />
</bytecodeTargetLevel>
</component>
</project>
</project>
+30
View File
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/codeCore" />
<option value="$PROJECT_DIR$/codeGenCpu6502" />
<option value="$PROJECT_DIR$/codeGenIntermediate" />
<option value="$PROJECT_DIR$/codeGenM68k" />
<option value="$PROJECT_DIR$/codeGenNew6502" />
<option value="$PROJECT_DIR$/codeOptimizers" />
<option value="$PROJECT_DIR$/compiler" />
<option value="$PROJECT_DIR$/compilerAst" />
<option value="$PROJECT_DIR$/intermediate" />
<option value="$PROJECT_DIR$/languageServer" />
<option value="$PROJECT_DIR$/parser" />
<option value="$PROJECT_DIR$/simpleAst" />
<option value="$PROJECT_DIR$/virtualmachine" />
</set>
</option>
<option name="myGradleHome" value="/usr/share/java/gradle" />
</GradleProjectSettings>
</option>
</component>
</project>
File diff suppressed because it is too large. Load diff
+15
View File
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="80ae155e-b222-4ca0-92cf-6041a298e78a" />
<option name="name" value="80ae155e-b222-4ca0-92cf-6041a298e78a" />
<option name="url" value="https://jitpack.io" />
</remote-repository>
</component>
</project>
+12 -1
View File
@@ -1,9 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Kotlin2JsCompilerArguments">
<option name="moduleKind" value="plain" />
</component>
<component name="Kotlin2JvmCompilerArguments">
<option name="jvmTarget" value="11" />
</component>
<component name="KotlinCommonCompilerArguments">
<option name="apiVersion" value="2.4" />
<option name="languageVersion" value="2.4" />
</component>
<component name="KotlinCompilerSettings">
<option name="additionalArguments" value="-jvm-default=no-compatibility" />
</component>
<component name="KotlinJpsPluginSettings">
<option name="version" value="2.0.21" />
<option name="externalSystemId" value="Gradle" />
<option name="version" value="2.4.21" />
</component>
</project>
-23
View File
@@ -1,23 +0,0 @@
<component name="libraryTable">
<library name="KotlinJavaRuntime" type="repository">
<properties maven-id="org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.21" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/2.0.21/kotlin-stdlib-jdk8-2.0.21.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.0.21/kotlin-stdlib-2.0.21.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/2.0.21/kotlin-stdlib-jdk7-2.0.21.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/2.0.21/kotlin-stdlib-jdk8-2.0.21-javadoc.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.0.21/kotlin-stdlib-2.0.21-javadoc.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0-javadoc.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/2.0.21/kotlin-stdlib-jdk7-2.0.21-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/2.0.21/kotlin-stdlib-jdk8-2.0.21-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.0.21/kotlin-stdlib-2.0.21-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/2.0.21/kotlin-stdlib-jdk7-2.0.21-sources.jar!/" />
</SOURCES>
</library>
</component>
-18
View File
@@ -1,18 +0,0 @@
<component name="libraryTable">
<library name="antlr.antlr4" type="repository">
<properties maven-id="org.antlr:antlr4:4.13.2">
<exclude>
<dependency maven-id="com.ibm.icu:icu4j" />
</exclude>
</properties>
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/antlr/antlr4/4.13.2/antlr4-4.13.2.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/antlr/antlr4-runtime/4.13.2/antlr4-runtime-4.13.2.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/antlr/antlr-runtime/3.5.3/antlr-runtime-3.5.3.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/antlr/ST4/4.3.4/ST4-4.3.4.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/abego/treelayout/org.abego.treelayout.core/1.0.3/org.abego.treelayout.core-1.0.3.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>
-13
View File
@@ -1,13 +0,0 @@
<component name="libraryTable">
<library name="eclipse.lsp4j" type="repository">
<properties maven-id="org.eclipse.lsp4j:org.eclipse.lsp4j:0.23.1" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/eclipse/lsp4j/org.eclipse.lsp4j/0.23.1/org.eclipse.lsp4j-0.23.1.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/eclipse/lsp4j/org.eclipse.lsp4j.jsonrpc/0.23.1/org.eclipse.lsp4j.jsonrpc-0.23.1.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/com/google/code/gson/gson/2.11.0/gson-2.11.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/com/google/errorprone/error_prone_annotations/2.27.0/error_prone_annotations-2.27.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>
-20
View File
@@ -1,20 +0,0 @@
<component name="libraryTable">
<library name="io.kotest.assertions.core.jvm" type="repository">
<properties maven-id="io.kotest:kotest-assertions-core-jvm:5.9.1" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-core-jvm/5.9.1/kotest-assertions-core-jvm-5.9.1.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-shared-jvm/5.9.1/kotest-assertions-shared-jvm-5.9.1.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/github/java-diff-utils/java-diff-utils/4.12/java-diff-utils-4.12.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/opentest4j/opentest4j/1.3.0/opentest4j-1.3.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.9.23/kotlin-stdlib-1.9.23.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-jdk8/1.8.0/kotlinx-coroutines-jdk8-1.8.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-reflect/1.9.23/kotlin-reflect-1.9.23.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-common-jvm/5.9.1/kotest-common-jvm-5.9.1.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-api-jvm/5.9.1/kotest-assertions-api-jvm-5.9.1.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-core-jvm/1.8.0/kotlinx-coroutines-core-jvm-1.8.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>
-23
View File
@@ -1,23 +0,0 @@
<component name="libraryTable">
<library name="io.kotest.framework.datatest" type="repository">
<properties maven-id="io.kotest:kotest-framework-datatest:5.9.1" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-framework-datatest/5.9.1/kotest-framework-datatest-5.9.1.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-framework-datatest-jvm/5.9.1/kotest-framework-datatest-jvm-5.9.1.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.9.23/kotlin-stdlib-1.9.23.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-core-jvm/1.8.0/kotlinx-coroutines-core-jvm-1.8.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-common-jvm/5.9.1/kotest-common-jvm-5.9.1.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-reflect/1.9.23/kotlin-reflect-1.9.23.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-framework-api-jvm/5.9.1/kotest-framework-api-jvm-5.9.1.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-shared-jvm/5.9.1/kotest-assertions-shared-jvm-5.9.1.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-api-jvm/5.9.1/kotest-assertions-api-jvm-5.9.1.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-jdk8/1.8.0/kotlinx-coroutines-jdk8-1.8.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/github/java-diff-utils/java-diff-utils/4.12/java-diff-utils-4.12.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/opentest4j/opentest4j/1.3.0/opentest4j-1.3.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-test-jvm/1.8.0/kotlinx-coroutines-test-jvm-1.8.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>
-41
View File
@@ -1,41 +0,0 @@
<component name="libraryTable">
<library name="io.kotest.runner.junit5.jvm" type="repository">
<properties maven-id="io.kotest:kotest-runner-junit5-jvm:5.9.1" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-runner-junit5-jvm/5.9.1/kotest-runner-junit5-jvm-5.9.1.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-framework-api-jvm/5.9.1/kotest-framework-api-jvm-5.9.1.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-shared-jvm/5.9.1/kotest-assertions-shared-jvm-5.9.1.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/github/java-diff-utils/java-diff-utils/4.12/java-diff-utils-4.12.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-test-jvm/1.8.0/kotlinx-coroutines-test-jvm-1.8.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-common-jvm/5.9.1/kotest-common-jvm-5.9.1.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-framework-engine-jvm/5.9.1/kotest-framework-engine-jvm-5.9.1.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/github/classgraph/classgraph/4.8.172/classgraph-4.8.172.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/com/github/ajalt/mordant/1.2.1/mordant-1.2.1.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/com/github/ajalt/colormath/1.2.0/colormath-1.2.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/opentest4j/opentest4j/1.3.0/opentest4j-1.3.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-debug/1.8.0/kotlinx-coroutines-debug-1.8.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/net/java/dev/jna/jna/5.9.0/jna-5.9.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/net/java/dev/jna/jna-platform/5.9.0/jna-platform-5.9.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/net/bytebuddy/byte-buddy/1.10.9/byte-buddy-1.10.9.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/net/bytebuddy/byte-buddy-agent/1.10.9/byte-buddy-agent-1.10.9.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-framework-discovery-jvm/5.9.1/kotest-framework-discovery-jvm-5.9.1.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-core-jvm/5.9.1/kotest-assertions-core-jvm-5.9.1.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-jdk8/1.8.0/kotlinx-coroutines-jdk8-1.8.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-api-jvm/5.9.1/kotest-assertions-api-jvm-5.9.1.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-extensions-jvm/5.9.1/kotest-extensions-jvm-5.9.1.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-framework-concurrency-jvm/5.9.1/kotest-framework-concurrency-jvm-5.9.1.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-core-jvm/1.8.0/kotlinx-coroutines-core-jvm-1.8.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/23.0.0/annotations-23.0.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-engine/1.8.2/junit-platform-engine-1.8.2.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-commons/1.8.2/junit-platform-commons-1.8.2.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/apiguardian/apiguardian-api/1.1.2/apiguardian-api-1.1.2.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-suite-api/1.8.2/junit-platform-suite-api-1.8.2.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/junit/platform/junit-platform-launcher/1.8.2/junit-platform-launcher-1.8.2.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter-api/5.8.2/junit-jupiter-api-5.8.2.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.9.23/kotlin-stdlib-1.9.23.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-reflect/1.9.23/kotlin-reflect-1.9.23.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>
-10
View File
@@ -1,10 +0,0 @@
<component name="libraryTable">
<library name="jetbrains.kotlinx.cli.jvm" type="repository">
<properties include-transitive-deps="false" maven-id="org.jetbrains.kotlinx:kotlinx-cli-jvm:0.3.6" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-cli-jvm/0.3.6/kotlinx-cli-jvm-0.3.6.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>
-20
View File
@@ -1,20 +0,0 @@
<component name="libraryTable">
<library name="michael.bull.kotlin.result.jvm" type="repository">
<properties maven-id="com.michael-bull.kotlin-result:kotlin-result-jvm:2.0.0" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/com/michael-bull/kotlin-result/kotlin-result-jvm/2.0.0/kotlin-result-jvm-2.0.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.9.22/kotlin-stdlib-1.9.22.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/com/michael-bull/kotlin-result/kotlin-result-jvm/2.0.0/kotlin-result-jvm-2.0.0-javadoc.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.9.22/kotlin-stdlib-1.9.22-javadoc.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/com/michael-bull/kotlin-result/kotlin-result-jvm/2.0.0/kotlin-result-jvm-2.0.0-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.9.22/kotlin-stdlib-1.9.22-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0-sources.jar!/" />
</SOURCES>
</library>
</component>
+8 -3
View File
@@ -4,14 +4,15 @@
<option name="perGrammarGenerationSettings">
<list>
<PerGrammarGenerationSettings>
<option name="fileName" value="$PROJECT_DIR$/parser/antlr/Prog8ANTLR.g4" />
<option name="fileName" value="$PROJECT_DIR$/parser/src/main/antlr/Prog8ANTLR.g4" />
<option name="autoGen" value="true" />
<option name="outputDir" value="$PROJECT_DIR$/parser/src/prog8/parser" />
<option name="libDir" value="" />
<option name="encoding" value="" />
<option name="pkg" value="" />
<option name="language" value="" />
<option name="language" value="Java" />
<option name="generateListener" value="false" />
<option name="generateVisitor" value="true" />
</PerGrammarGenerationSettings>
</list>
</option>
@@ -19,10 +20,14 @@
<component name="Black">
<option name="sdkName" value="Python 3.11" />
</component>
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="FrameworkDetectionExcludesConfiguration">
<type id="Python" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="openjdk-17" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="openjdk-21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
<component name="PythonCompatibilityInspectionAdvertiser">
<option name="version" value="3" />
</component>
</project>
-13
View File
@@ -2,22 +2,9 @@
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/beanshell/beanshell.iml" filepath="$PROJECT_DIR$/beanshell/beanshell.iml" />
<module fileurl="file://$PROJECT_DIR$/benchmark-program/benchmark-program.iml" filepath="$PROJECT_DIR$/benchmark-program/benchmark-program.iml" />
<module fileurl="file://$PROJECT_DIR$/codeCore/codeCore.iml" filepath="$PROJECT_DIR$/codeCore/codeCore.iml" />
<module fileurl="file://$PROJECT_DIR$/codeGenCpu6502/codeGenCpu6502.iml" filepath="$PROJECT_DIR$/codeGenCpu6502/codeGenCpu6502.iml" />
<module fileurl="file://$PROJECT_DIR$/codeGenExperimental/codeGenExperimental.iml" filepath="$PROJECT_DIR$/codeGenExperimental/codeGenExperimental.iml" />
<module fileurl="file://$PROJECT_DIR$/codeGenIntermediate/codeGenIntermediate.iml" filepath="$PROJECT_DIR$/codeGenIntermediate/codeGenIntermediate.iml" />
<module fileurl="file://$PROJECT_DIR$/codeGenVirtual/codeGenVirtual.iml" filepath="$PROJECT_DIR$/codeGenVirtual/codeGenVirtual.iml" />
<module fileurl="file://$PROJECT_DIR$/codeOptimizers/codeOptimizers.iml" filepath="$PROJECT_DIR$/codeOptimizers/codeOptimizers.iml" />
<module fileurl="file://$PROJECT_DIR$/compiler/compiler.iml" filepath="$PROJECT_DIR$/compiler/compiler.iml" />
<module fileurl="file://$PROJECT_DIR$/compilerAst/compilerAst.iml" filepath="$PROJECT_DIR$/compilerAst/compilerAst.iml" />
<module fileurl="file://$PROJECT_DIR$/docs/docs.iml" filepath="$PROJECT_DIR$/docs/docs.iml" />
<module fileurl="file://$PROJECT_DIR$/examples/examples.iml" filepath="$PROJECT_DIR$/examples/examples.iml" />
<module fileurl="file://$PROJECT_DIR$/intermediate/intermediate.iml" filepath="$PROJECT_DIR$/intermediate/intermediate.iml" />
<module fileurl="file://$PROJECT_DIR$/parser/parser.iml" filepath="$PROJECT_DIR$/parser/parser.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/prog8.iml" filepath="$PROJECT_DIR$/.idea/modules/prog8.iml" />
<module fileurl="file://$PROJECT_DIR$/virtualmachine/virtualmachine.iml" filepath="$PROJECT_DIR$/virtualmachine/virtualmachine.iml" />
</modules>
</component>
</project>
Generated
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
<mapping directory="" vcs="Git" />
</component>
</project>
+5
View File
@@ -0,0 +1,5 @@
---
description: Startup workflow to load project context
---
1. Read the file `AGENTS.md` in the project root as initial system prompt to build context and instructions about the project structure, module descriptions, and development commands.
+5
View File
@@ -0,0 +1,5 @@
# Agent Instructions
- The file `AGENTS.md` MUST be loaded as the very first step of every session, if it isn't already loaded by the system.
- Follow all project-specific guidelines and information provided in `AGENTS.md`.
- Ensure all automated tasks and code generations adhere to the language rules and architectural decisions described in `AGENTS.md`.
+405
View File
@@ -0,0 +1,405 @@
# CRITICAL RULES - MUST FOLLOW
## RESPONSES
- Keep responses concise and to the point - unless the user asks otherwise
## PLANNING MODE
- Always ask clarifying questions
- Never assume design, tech stack or features
- Use deep-dive sub-agents to assist with research
- Use deep-dive sub-agents to review the different aspects of your plan before presenting to the user
## CHANGE / EDIT MODE
- Use a subagent for larger chunks of work
- Identify changes from the plan that can be implemented in parallel, and use sub-agents to implement the features efficiently
- When using sub-agents to implement features, act as a coordinator only
- Use the best model for the task - premium models for complex tasks (like coding) and mid-tier models for simpler tasks, like documentation
- After completing features (large or small), run the relevant quality commands (lint, type check, build) to check code quality.
Only compiler/standard-library changes require a build: that means Kotlin sources (`.kt`), the grammar (`.g4`), or embedded
standard library files (`compiler/res/prog8lib/**/*.p8` and `**/*.asm`). For changes limited to `examples/**`, `docs/**`, or
other non-compiler files, verify with the target compiler directly instead (for example `prog8c -target <target> <file>`), and
skip the build entirely
(exception: if the change is only whitespace or code comments, a build or test run is not necessary)
- `gradle build` already runs the full test suite; don't run a separate full `gradle test` before it, to avoid lengthy double test runs (targeted `--tests` filters to find failing tests are fine)
## Project Overview
- This project is a compiler for the Prog8 programming language.
- Prog8 is a programming language primarily targeting 8-bit retro systems with the 6502 CPU, such as the Commodore 64, Commodore 128, and Commander X16.
- The compiler has a 6502 code generator backend, and an IR code generator.
- The IR code is used by machine-specific code generator backends, including 6502 and M68K.
- The compiler includes a simple 'virtual machine' that can execute the IR code directly via interpretation.
- Prog8 source files have .p8 extension – these are *not* LUA or PICO-8 source files in this case!
- Prog8 source files are a "module" that can contain one or more "blocks". They can also import other modules, from internal library files or from source files on the filesystem.
- The prog8 compiler is written mostly in Kotlin, those files have the .kt extension.
- The standard library is mostly written in Prog8 and assembly code, and can be found in the "compiler" module, in the 'res/prog8lib' directory.
- **Library Reference**: For a quick overview of all available modules, routines, and their signatures, **consult the skeleton files (symboldumps)** in `docs/source/_static/symboldumps/`. They are named `skeletons-<target>.txt`.
- Kotlin version 2.4 is used for the compiler implementation.
- Java 17 is used as Java runtime version.
- ANTLR4 version 4.13 is used for the parser implementation.
- Dependent library versions can be found in 'build.gradle.kts' and in the IntelliJ IDEA configuration files in .idea/libraries
- The compiler main entrypoint is in the "compiler" module, in src/prog8/CompilerMain.kt
- **Codebase knowledge graph**: For a structured overview of modules, their dependencies, key entities, the end-to-end compilation pipeline, the standard library layout, and the test structure, consult `docs/CODEBASE-KNOWLEDGE-GRAPH.md`. Read it when you need to understand how the compiler fits together before diving into specific files.
## Compilation Flow (High-Level)
```
Source → parseMainModule() → processAst() → optimizeAst() → postprocessAst()
→ Simple AST → Code Generator → Assembly → .prg
```
**Key phases in `compiler/src/prog8/compiler/Compiler.kt`:**
- `parseMainModule()` - Import modules, parse to Compiler AST
- `processAst()` - Semantic analysis, constant folding, type casting, validation
- `optimizeAst()` - Dead code elimination, inlining, statement optimization
- `postprocessAst()` - Memory layout, final transformations
- Code generation – Simple AST → IR or 6502 assembly
**Understanding this order is important:** For example, `ConstantIdentifierReplacer` runs during `processAst()`, so by the time `AstChecker` runs at the end of that phase, identifier references have already been replaced with their actual values.
### Target Differences
- **CPU instruction set differences**: Only the CommanderX16 target (cx16) can use 65C02 instructions such as STZ. The other targets (C64, C128, PET32) can only use original 6502 instructions.
- When writing or understanding 6502/65C02 assembly code, load the `asm6502-coder` skill for 64tass syntax and conventions.
- When writing or understanding M68K assembly code (amiga500, amiga1200, qemu68k targets), load the `m68k-coder` skill for vasm mot syntax and conventions.
- M68K ordinary subroutine locals and parameters use `A5`-based stack frames. Normal calls pass word-packed argument slots on the stack (2-byte slots for byte/word args, 4-byte for wide args, byte values at the slot base), and the caller cleans up; see `docs/source/technical.rst` for the complete convention and frame eligibility rules.
## DEBUGGING TIP: Use `-noopt` to isolate problems
When investigating a possible code generation problem (both IR and 6502), **FIRST try compiling the program with the `-noopt` switch** to disable most of the compiler optimizations.
- **Problem gone with `-noopt`**: Issue is in **optimization phases** (`optimizeAst()`, `UnusedCodeRemover`, `Inliner`, etc.)
- **Problem persists with `-noopt`**: Issue is in **parsing, semantic analysis, symboltable, or the regular code generation path**.
This way you can determine if the problem is caused by a faulty optimization step, or just occurs in the regular code generation path.
## DEBUGGING TIP: Use `-compareir` to see what changed
When investigating optimization-related issues or tracking regressions:
```bash
# Compile without optimizations (baseline)
prog8c -target virtual -noopt -out dir program.p8
# Compile with optimizations and compare
prog8c -target virtual -compareir dir/program_noopt.p8ir program.p8
```
**Output shows:**
- Instruction/chunk/register count changes with percentages
- First 10 actual instruction differences
- Helps identify which optimization transformed the code
## DEBUGGING TIP: Use `-vmtrace` to trace execution
When debugging VM execution or control flow issues:
```bash
prog8c -target virtual -vm program.p8ir -vmtrace
prog8c -target virtual -emu -vmtrace program.p8
```
**Output format:** `[chunkName:instructionIndex] instruction`
- Shows each executed IR instruction with location
- Useful for understanding control flow and finding where execution diverges
- **Only works on virtual target**
## Typical debugging workflow:
1. **Quick check:** `-check` for syntax errors
2. **Isolate:** `-noopt` to determine if problem is optimizer-related
3. **Compare:** `-compareir` to see what instructions changed
4. **Trace:** `-vmtrace` to watch actual execution flow
5. **Deep dive:** `-printast1` / `-printast2` for compiler internals
## IMPORTANT: SymbolTable cachedFlat cache
The `SymbolTable` class has a **cached `flat` property** for fast symbol lookups.
**CRITICAL:** If you modify the AST **after** SymbolTable construction, you **MUST** call `symbolTable.resetCachedFlat()` or lookups will fail!
## IMPORTANT: Virtual Target (IR Codegen) Issues
For problems that **ONLY occur with the 'virtual' target**, **ONLY modify these modules**:
- `codeGenIntermediate` - IR code generator
- `intermediate` - IR representation and file I/O
- `virtualmachine` - VM that executes IR code
**DO NOT modify** `compilerAst`, `simpleAst`, `codeGenCpu6502`, etc. The IR codegen has its own separate handling for symbol tables, AST transformations, and unused code removal.
## IMPORTANT: Compiler Crashes Must Be Fixed in the Compiler
A Kotlin/Java crash in the compiler itself (as opposed to a compilation error in the user's program) indicates a bug in the compiler code. **Such crashes should NEVER be worked around by modifying the Prog8 source file that triggered them.**
Instead, always fix the bug in the compiler's Kotlin code. The user's program is correct - the compiler needs to handle it properly.
Steps when encountering a compiler crash:
1. Create a minimal reproduction case of the Prog8 source that triggers the crash
2. Debug the compiler to find the root cause in the Kotlin code
3. Fix the compiler bug, not the user program
## CRITICAL: NO FORMATTING
- DO NOT change indentation and formatting of lines that are not being modified. NEVER run formatters (black, ruff, prettier, etc.) after edits,
- .editorconfig handles basic formatting (indentation, line endings, whitespace)
- Make ONLY the requested changes, touch nothing else
- **NO EMOJI in user documentation**. Do not use emoji or decorative unicode symbols in documentation files. Functional unicode symbols are acceptable when they serve a clear purpose (e.g., → for arrows, ± for plus-minus, × for multiplication, ° for degrees). Avoid decorative emoji like ❌ ✅ ⚠️ 🎉 etc.
### Code Style Guidelines
**Code comments**: Comments are the exception, not the norm. A comment earns its place only by recording
something the code itself cannot say: the reason for a non-obvious choice, or a constraint that
a well-meaning future edit would otherwise violate.
- Inline comment inside a function body: 1 line, never more.
- KDoc on a declaration: 3 lines, unless a genuine non-obvious contract cannot be stated shorter.
- Never restate the identifier, the type, or what the following line does.
- Prefer a good name or a well-named function over a comment that explains it.
Before keeping any comment, delete it mentally and ask what the reader loses. If nothing, it goes.
Keep existing comments as they are; do not expand, reword, or reformat them while editing
nearby lines - unless that would cause inconsistency.
**Kotlin string `$` handling**: The `$` character is special in Kotlin string literals (string interpolation). If you need a literal `$` character, use Kotlin's `$$"..."` interpolation prefix instead of backslash escaping (`\$`) or `${'$'}`. The `$$"..."` syntax is a fairly recent Kotlin feature that avoids nasty escaping. For example:
```kotlin
val bill = $$"The value is $3.99"
```
## Prog8 language information
When the task involves writing or understanding `.p8` (Prog8 source) or `.p8ir` (Prog8 intermediate representation) files, **load the `prog8-coder` skill** — it contains the full language reference, syntax rules, and standard library guidance.
## Project Module Descriptions
- `compiler` - Main compiler entrypoint (src/prog8/CompilerMain.kt)
- `compilerAst` - Complex AST where most optimizations run
- `simpleAst` - Simplified AST used by code generator backends
- `parser` - ANTLR4 parser implementation
- `codeCore` - Core code generation utilities
- `codeGenCpu6502` - 6502 assembly code generator backend
- `codeGenIntermediate` - Intermediate representation (IR) code generator
- `codeGenVirtual` - Virtual machine code generator backend
- `codeOptimizers` - Optimization passes
- `intermediate` - IR components
- `virtualmachine` - VM that executes IR code
- `languageServer` - Language Server Protocol implementation
- `docs` - Documentation files
- `examples` - Example Prog8 programs
## Key Information
- never read the files and directories that are ignored via the .aiignore and .gitignore files (EXCEPT when it is a folder for agent config such as .junie, .opencode, .qwen or .agent)
- never perform any git source control write/update/add/commit/branch operations. Read and status operations are allowed.
- **git log/history queries can be useful** for understanding when/why a feature was added or tracking down when a bug was introduced, but for locating code use grep_search or glob instead.
- Architecture decisions: separation of frontend/parser, IR intermediate representation, multiple backends
# Dev environment tips
## Development Workflows
**1. Testing your own Prog8 programs** (no compiler changes):
- No rebuild needed - just run `prog8c` directly
- Edit your `.p8` file → compile/run → check stdout output
- Example: `prog8c -target virtual -emu myprogram.p8`
**2. Testing compiler or standard library changes**:
- Rebuild required after every change to `.kt`, `.p8`, or `.asm` files in the compiler project
- Workflow: edit source → `gradle installdist installshadowdist` → test with `prog8c`
- Example: fix bug in `CodeGen6502.kt` → rebuild → `prog8c -target cx16 test.p8`
## Building and Installing the Compiler
- use the system installed gradle command instead of the gradle wrapper.
### Quick compile check (NO tests)
- **After changing compiler Kotlin source (.kt files)**: Use `gradle :compiler:compileKotlin --console=plain` to quickly check for syntax/compile errors
- This compiles the compiler but **skips running tests**, this is much faster than `gradle build`
- **Note:** This does NOT install the compiler - use `gradle installdist installshadowdist --console=plain` after to actually use your changes
### When you MUST rebuild AND reinstall the compiler
**After ANY change to:**
1. **Kotlin compiler source code** (`.kt` files in any module, or the `.g4` grammar file)
2. **Standard library Prog8 files** (`compiler/res/prog8lib/**/*.p8`)
3. **Standard library assembly files** (`compiler/res/prog8lib/**/*.asm`)
**Run:** `gradle installdist installshadowdist --console=plain`
**Why:** The standard library files (.p8 and .asm) are embedded into the compiler JAR during the build. Changes to these files are NOT picked up by simply running `prog8c` - you MUST rebuild and reinstall for your changes to take effect.
**Without this step, your changes will NOT be reflected when running `prog8c`!**
- This compiles AND installs, but still skips running tests (faster than `gradle build`)
### When to run full build with tests
- **Before final verification**: Run `gradle build` to ensure all tests pass - but only if the change actually touched the
compiler or standard library (`.kt`, `.g4`, or `compiler/res/prog8lib/**`). For `examples/**` or `docs/**`-only changes,
verify with `prog8c` directly instead and skip the build
- **After major refactoring**: Run `gradle build` to catch regressions
- **When debugging test failures**: Use `gradle test --tests "*TestName*"` for specific tests
- **When working on a standalone code gen module** (one that reads `.p8ir` files): Run `gradle :<module>:test --console=plain` instead of full `gradle build`. Compiler unit tests are irrelevant for IR-level changes. Do run full `gradle build` before final verification if the change touched compiler sources.
### Build command summary
| Command | When to use | Time |
|---------|-------------|------|
| `gradle :compiler:compileKotlin --console=plain` | Quick syntax check (no tests) | ~10-20s |
| `gradle installdist installshadowdist --console=plain` | After compiler changes (to use them) | ~10-20s |
| `gradle build --console=plain` | Before commits, after major changes | ~45-60s |
| `gradle test --tests "*Name*" --console=plain` | Run specific tests | ~5-30s |
**Note:** Use system `gradle` command, not wrapper. Run `gradle clean` if you suspect stale artifacts.
## Using the Compiler (prog8c)
- the prog8c compiler executable can be found in the compiler/build/install/prog8c/bin folder (this is already added to the shell's path)
- **the `-check` switch performs a quick syntax/semantic check only; it will NOT produce any output files (no .prg, .asm, etc.)**. Use it only for fast error checking during development.
- **the `-noopt` switch DISABLES all optimizations** - useful for debugging to determine if a problem is caused by the optimizer. **Optimizations are ENABLED by default** (no flag needed).
- **prog8c options accept single-dash or double-dash** (e.g., `-target` and `--target` are equivalent).
- **the `-printast1` switch prints out the internal Compiler AST** after parsing and semantic analysis.
- **the `-printast2` switch prints out the optimized Simple AST** just before it goes to the code generator. This is useful for debugging optimizer issues.
- **the `-out outdir` switch sets an alternative output directory** for compiled files (.prg, .asm, .list, etc.). **By default, output files are written to the current working directory**.
- **the `-o <file>` switch names the exact final program artifact** (also spelled `--output`); all other output files go in the same directory with the same stem. Cannot be combined with `-out` or with multiple source files.
- **Other useful flags**: `-quiet` (suppress messages), `-warnimplicitcasts` (warn on implicit type widening), `-daemon` (keep a background compiler process alive — must be passed on every invocation)
### Compilation Output Files
Names follow the source file name, or the stem of the `-o` file when that option is used.
- `*.prg` - The final compiled program file for the target system (e.g., Commander X16)
- `*.asm` - Generated assembly code from the Prog8 source
- `*.list` - Generated full assembly listing file from the Prog8 source
- `*.p8ir` - Intermediate representation file, can be executed in the Virtual Machine
- `*.vice-mon-list` - Vice emulator monitor list file for debugging
### Execution Examples
- `prog8c -target targetname input.p8` - Compile a Prog8 source file "input.p8" for the given target (cx16, c64, pet32, c128, virtual)
- `prog8c -target targetname -emu input.p8` - Compile and execute a prog8 file in the emulator for the given target (cx16, c64, pet32, c128, virtual)
- `prog8c -vm input.p8ir` - Execute an existing prog8 program, compiled in IR form, in the Virtual Machine
### Library Tools
- **Library search**: `prog8c -libsearch <regex>` — search for a regex pattern in the embedded stdlib files. Extremely useful to quickly find library routines, variables, or signatures (e.g., `prog8c -libsearch "txt\."` lists all textio routines)
- **Library dump**: `prog8c -libdump <dir>` — extract all embedded library source files into a directory for direct inspection
## Testing and Verification
- Never assume your changes simply work, always test!
- If the project does not have any testing tools, scripts, MCP tools, skills, etc. available for testing, ask the user whether testing should be skipped.
- in prog8 code being tested, use '@shared' variables to avoid const-folding
### Automated Tests (gradle)
Always use the `--console=plain` flag with these commands to avoid messing up the agent's text interface.
- `ionice -c 3 nice gradle build --console=plain` - Full build including all tests (about 50s)
- `ionice -c 3 nice gradle :compiler:test --console=plain` - Run only compiler tests (faster)
- `ionice -c 3 nice gradle :compiler:test --tests "prog8tests.compiler.TestOptimization" --console=plain` - Run specific test class
Note: By default, Gradle only shows failed tests. Passed and skipped tests are silent.
On Unix-like systems, prefix **every** gradle invocation with `nice` to lower its CPU priority,
because gradle is CPU-heavy. This applies to all gradle commands (build, compile, test, install), not
just `gradle build`. Use the same prefix for the quick compile checks and install commands in
"Building and Installing the Compiler" above.
On **Linux** additionally put `ionice -c 3` in front (idle-class I/O scheduling), so the build doesn't
compete for disk with whatever else is running: `ionice -c 3 nice gradle ...`. `ionice` is
Linux-only (util-linux); on macOS/BSD just use `nice`.
**⚠️ CRITICAL: Test Filtering Patterns - Read This First!**
Gradle's `--tests` filter has **strict rules** that are easy to get wrong:
| Pattern | Example | Works? |
|---------|---------|---------------|
| **Full class name** | `--tests "prog8tests.compiler.TestOptimization"` | **USE THIS** |
| Wildcard at END | `--tests "prog8tests.compiler.Test*"` | Yes |
| Wildcard on package | `--tests "prog8tests.compiler.*"` | Yes |
| **Wildcard at START** | `--tests "*TestOptimization"` | FAILS |
| Test description | `--tests "*Optimization*inline*"` | FAILS |
**Why the restrictions?** Gradle's `--tests` filter matches **fully qualified class names only**. Wildcards work as **suffixes** (e.g., `Test*`) but NOT as prefixes (e.g., `*Test`). KoTest test names like `"inline multi-value void"` are _descriptions_, not method names, so you cannot filter by them.
**To find failing tests after a run:**
```bash
# Check XML results (reliable)
grep "<failure" compiler/build/test-results/test/*.xml
# Or check HTML report (most reliable)
cat compiler/build/reports/tests/test/index.html
# For test compilation errors
gradle :compiler:compileTestKotlin --info 2>&1 | grep "^e:"
```
**Additional notes:**
- Unit tests use KoTest (FunSpec style)
- Tests are in the "compiler" module's `test` directory (and some other modules)
- Test config is in root `build.gradle.kts`; tests run in parallel
- **When writing test programs**, add at the top: `%zeropage basicsafe` and `%option no_sysinit` - the latter ONLY when NOT writing for the amiga500 or qemu68k targets
- When a test fails, the output shows "There were failing tests. See the report at:" - **read that HTML report**
### TestCompilerOnExamples expected sizes
`TestCompilerOnExamples` asserts exact output sizes per example. A code-generator change shifts them,
so expect a handful of `expected:<N> but was:<M>` failures with no stack trace pointing at the cause.
Attribute each one before editing: rebuild with the change reverted and compare the two generated
`.asm` files, so the size delta is demonstrably yours and not a side effect. Then update the expected
size. A delta of a few bytes from removed `ldy`/`lda` instructions is normal; a large or erratic delta
means something else changed and needs investigating.
### Compiler Unit Test Snippets
Prog8 code snippets embedded in the compiler's own Kotlin unit tests (e.g., in `TestAstChecks.kt`, `TestOptimization.kt`) follow different rules from standalone programs:
- **Keep self-contained** — avoid `%import` directives (test setup may not have library search path configured)
- **Use `cx16` target** (not `virtual`, unless specifically testing the VM)
- **Set `writeAssembly=false`** if the test only checks generated AST (much faster)
- **Set `optimize=false`** by default for these snippets
- **Do NOT use** the `%encoding iso` / `txt.iso()` / `sys.poweroff_system()` pattern — that's only for real CX16 emulator runs
- **Do NOT** write compiler tests that depend on the `vasm` assembler: it is not always installed
(CI only installs `64tass`). For m68k codegen tests (`amiga500`, `qemu68k` targets) pass
`writeAssembly = true, assemble = false` to the `compileText`/`compileFile` helpers. This still
generates the codegen AST to assert on but skips assembling, so no vasm is needed. If a test's
assertions cannot be made from the AST alone, drop the test.
### Testing Assembly Output
When testing generated assembly in Kotlin tests:
- **NEVER dump raw assembly in string assertions** (e.g., `asm shouldContain "jsr label"`). On failure, this dumps the ENTIRE assembly listing into test logs.
- **Instead, parse into lines and check specific properties:**
```kotlin
val lines = asm.lines().map { it.trim() }
lines.any { it == "lda #42" } shouldBe true
lines.count { it.startsWith("jsr") } shouldBe 0
```
- Prefer `lines.any { ... }` for existence checks and `lines.count { ... } shouldBe 0` for absence checks.
### Manual Verification & Emulators
**Testing tip**: When writing and testing Prog8 programs, **use the `virtual` target** (e.g., `prog8c -target virtual -emu input.p8` or `prog8c -vm input.p8ir`). This is the preferred way to test because the virtual target can easily write output to stdout, making it simple to verify program behavior and check results.
For the amiga targets, `-emu` launches FS-UAE (GUI) while `-emu2` launches Vamos (headless CLI). For automated/non-interactive testing, prefer `-emu2` (vamos) to avoid opening a GUI window.
**CX16 output verification**: Use `x16emu -echo iso -run -prg input.prg` to echo screen output to stdout **and auto-start the program**. The `-run` flag is **critical**: without it, the program loads but doesn't execute, so you'll see no output. Pipe through `strings` or `grep` to filter: `x16emu -echo iso -run -prg input.prg 2>&1 | grep -E "(PASS|FAIL)"`.
**IMPORTANT**: Always add `%encoding iso` at the top of your source file and call `txt.iso()` in `start()`. This prevents PETSCII→ISO charset translation errors that garble uppercase/special characters and make output unreadable:
```prog8
%encoding iso
%import textio
main { sub start() { txt.iso(); txt.print("PASS\n") } }
```
**IMPORTANT: Always use `sys.poweroff_system()` to exit the CX16 emulator cleanly!** Add `sys.poweroff_system()` at the end of your main program block - this exits x16emu automatically in most cases.
**Note:** The `sys` module is always available, there is no need to import it ever.
**Commodore 64 (x64sc)**: `x64sc input.prg` - run an existing compiled program in the Commodore-64 emulator. Ignore any errors and warnings, because the emulator doesn't produce any output on STDOUT.
### actual 6502 CPU simulation tests
For high-fidelity functional verification of generated 6502 code without a full emulator, you can use the `ksim65` simulator in your unit tests. This allows executing the compiled machine code and asserting on memory or register states.
- Use the `simulate()` extension function on a `CompilationResult`.
- See `prog8tests.codegeneration.TestExecution6502` for examples.
- Both 6502 and 65C02 CPUs can be simulated.
- The simulator supports capturing serial output and handling hardware reset/poweroff signals.
- There are various assertion helper methods to test on the state of CPU registers, memory contents, etc.
- Using the simulator is much faster and way more controllable than using a full emulator to run the code.
- The simulator DOES NOT represent an actual real world machine and has VERY LIMITED hardware devices so it can generally not be used to run full example prorams on.
## Git Operations for File Moves/Deletes
**When renaming or moving git-tracked files, ALWAYS use `git mv`:**
```bash
# CORRECT - preserves git history
git mv old/path/File.kt new/path/File.kt
# WRONG - git sees this as delete + add (loses history)
mv old/path/File.kt new/path/File.kt
```
**When deleting git-tracked files, ALWAYS use `git rm`:**
```bash
# CORRECT - properly stages the deletion
git rm path/to/File.kt
# WRONG - git sees this as unstaged deletion
rm path/to/File.kt
```
**Why this matters:** `git mv` and `git rm` properly stage the changes and preserve file history. Plain `mv`/`rm` requires git to detect renames heuristically, which may not always work correctly.
## TODO Items
The file `docs/source/todo.rst` contains a comprehensive list of things that still have to be fixed, implemented, or optimized. **Use this to understand what features are NOT yet available** in the compiler or Prog8 language: if a user asks for something that's on the TODO list, you'll know it's not implemented yet and can explain the limitation.
+13 -5
View File
@@ -1,12 +1,20 @@
# super simple Makefile to lauch the main gradle targets to build and/or test the prog8 compiler
# super simple Makefile to launch the main gradle targets to build and/or test the prog8 compiler
.PHONY: all test
# Use system gradle if available, otherwise fall back to gradlew wrapper
# Windows uses 'where' and gradlew.bat, Unix uses 'command -v' and ./gradlew
ifeq ($(OS),Windows_NT)
GRADLE = $(shell where gradle >nul 2>&1 && echo gradle || echo gradlew.bat)
else
GRADLE = $(shell command -v gradle >/dev/null 2>&1 && echo gradle || echo ./gradlew)
endif
all:
gradle installdist installshadowdist
@echo "compiler launch script can be found here: compiler/build/install/compiler-shadow/bin/prog8c"
$(GRADLE) installdist installshadowdist
@echo "compiler launch script can be found here: compiler/build/install/prog8c-shadow/bin/prog8c"
test:
gradle build
@echo "compiler launch script can be found here: compiler/build/install/compiler-shadow/bin/prog8c"
$(GRADLE) build
@echo "compiler launch script can be found here: compiler/build/install/prog8c-shadow/bin/prog8c"
+55 -17
View File
@@ -1,21 +1,27 @@
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/H2H6S0FFF)
PayPal: [![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://paypal.me/irmendejong)
[![Documentation](https://readthedocs.org/projects/prog8/badge/?version=latest)](https://prog8.readthedocs.io/)
Prog8 - Structured Programming Language for 8-bit 6502/65c02 microprocessors
============================================================================
Prog8 - Structured Programming Language for 6502/65c02 (8-bit) and 68000 (32-bit) microprocessors
=================================================================================================
*Written by Irmen de Jong (irmen@razorvine.net)*
This is a structured programming language for the 8-bit 6502/6510/65c02 microprocessor from the late 1970's and 1980's
as used in many home computers from that era. It is a medium to low level programming language,
as used in many home computers from that era. It also supports the 32-bit Motorola 68000 CPU, for which the
Commodore Amiga is the intended machine. It is a medium to low level programming language,
which aims to provide many conveniences over raw assembly code (even when using a macro assembler).
**Want to buy me a coffee or a pizza perhaps?**
This project was created over the last couple of years by dedicating thousands of hours of my free time to it, to make it the best I possibly can.
This project was created over the last couple of years by dedicating a huge amount of my free time to it, to make it the best I possibly can.
If you like Prog8, and think it's worth a nice cup of hot coffee or a delicious pizza,
you can help me out a little bit over at [ko-fi.com/irmen](https://ko-fi.com/irmen).
you can help me out a little bit over at [ko-fi.com/irmen](https://ko-fi.com/irmen) or [PayPal](https://paypal.me/irmendejong)
[![JetBrains logo.](https://resources.jetbrains.com/storage/products/company/brand/logos/jetbrains.svg)](https://jb.gg/OpenSource)
I am using JetBrains products to develop the Prog8 compiler.
Documentation
-------------
@@ -31,8 +37,11 @@ How to get it/build it
- you can also compile it yourself from source. [Instructions here](https://prog8.readthedocs.io/en/latest/compiling.html).
Note that if you are not using *gradle* to build it, you might have to perform some manual
tasks once to make it compile fully. These are explained in the linked instructions.
- Alternatively, you can also install the compiler as a package on some linux distros:
- Alternatively, you can also install the compiler as a package on some linux distros (which will take care of dependencies automatically):
- Arch (via AUR): [`prog8`](https://aur.archlinux.org/packages/prog8)
- Finally there's a Homebrew recipe for Mac OS (but also for Linux, and WSL2 on Windows, this also takes care of dependencies automatically):
``brew install prog8``
Community
---------
@@ -55,50 +64,63 @@ What does Prog8 provide?
- all advantages of a higher level language over having to write assembly code manually
- programs run very fast because it's compiled to native machine code
- code often is smaller and faster than equivalent C code compiled with CC65 or even LLVM-MOS
- compiled code is very small; much smaller than equivalent C code compiled with CC65, and usually runs faster as well
- modularity, symbol scoping, subroutines. No need for forward declarations.
- various data types other than just bytes (16-bit words, floats, strings)
- Can make vars and routines private, as a simple way to restrict access and hide implementation details
- various data types other than just bytes (16-bit words, long integers, floats, strings)
- Structs and typed pointers
- 2D arrays (`matrix[row][col]` syntax)
- floating point math is supported on certain targets
- access to most Kernal ROM routines as external subroutine definitions you can call normally
- tight control over Zeropage usage
- programs can be run multiple times without reloading because of automatic variable (re)initializations.
- programs can be configured to execute in ROM
- strings can contain escaped characters but also many symbols directly if they have a petscii equivalent, such as "♠♥♣♦π▚●○╳". Characters like ^, _, \, {, } and | are also accepted and converted to the closest petscii equivalents.
- automatic static variable allocations, automatic string and array variables and string sharing
- high-level program optimizations
- programs can be run multiple times without reloading because of automatic variable (re)initializations.
- conditional branches that map 1:1 to cpu status flags
- ``when`` statement to provide a concise jump table alternative to if/elseif chains
- ``on .. goto`` statement for fast jump tables
- ``in`` expression for concise and efficient multi-value/containment check
- ``defer`` statement to help write concise and robust subroutine cleanup logic
- several specialized built-in functions such as ``lsb``, ``msb``, ``min``, ``max``, ``rol``, ``ror``
- various powerful built-in libraries to do I/O, number conversions, graphics and more
- subroutines can return more than one result value
- inline assembly allows you to have full control when every cycle or byte matters
- supports the sixteen 'virtual' 16-bit registers R0 - R15 from the Commander X16 (also available on other targets)
- encode strings and characters into petscii or screencodes or even other encodings
- Automatic ROM/RAM bank switching on certain compiler targets when calling routines in other banks
- 50 Kb of available program RAM size on the C64 by default; because Basic ROM is banked out altogether
- 50 Kb of available program RAM size on the C64 by default (41 Kb on the C128) because Basic ROM is banked out by default
*Rapid edit-compile-run-debug cycle:*
- use a modern PC to do the work on, use nice editors and enjoy quick compilation times
- can automatically run the program in the Vice emulator after succesful compilation
- can automatically run the program in the Vice emulator after successful compilation
- breakpoints, that let the Vice emulator drop into the monitor if execution hits them
- source code labels automatically loaded in Vice emulator so it can show them in disassembly
*Multiple supported compiler targets* (contributions to improve these or to add support for other machines are welcome!):
- "cx16": [CommanderX16](https://www.commanderx16.com) (65c02 CPU)
- "c64": Commodore-64 (6502 like CPU)
- "c128": Commodore-128 (6502 like CPU - the Z80 cpu mode is not supported)
- "cx16": [CommanderX16](https://www.commanderx16.com) (65c02 CPU)
- "pet32": Commodore PET (experimental)
- "atari": Atari 8 bit such as 800XL (experimental)
- "pet32": Commodore PET (limited support)
- "amiga500": Commodore Amiga 500 (16/32-bit 68000 CPU; experimental)
- "amiga1200": Commodore Amiga 1200 (32-bit 68020 CPU with optional FPU; experimental)
- "qemu68k": Qemu M68k simulator (experimental)
- via external configurable targets: Atari 800 XL, Neo6502, NES, C64 OS, Foenix F256, ...
- If you only use standard kernal and prog8 library routines, it is possible to compile the *exact same program* for different machines (just change the compiler target flag)
The m68k targets (amiga500, amiga1200, qemu68k) and the optional `-newcodegen` 6502 code generator are experimental and not yet suitable for production code.
Additional required tools
-------------------------
[64tass](https://sourceforge.net/projects/tass64/) - cross assembler. Install this on your shell path.
A recent .exe version of this tool for Windows can be obtained from my [clone](https://github.com/irmen/64tass/releases) of this project.
For other platforms it is very easy to compile it yourself (make ; make install).
If you're on Windows, download a recent .exe from the official repository's file section <https://sourceforge.net/projects/tass64/files/binaries/>.
For other systems (Mac, Linux) it is very easy to get it via your package manager or to compile it yourself.
A **Java runtime (jre or jdk), version 11 or newer** is required to run a prepackaged version of the compiler.
If you want to build it from source, you'll need a Java SDK + Kotlin 1.3.x SDK (or for instance,
@@ -163,7 +185,7 @@ This code calculates prime numbers using the Sieve of Eratosthenes algorithm::
}
}
when compiled an ran on a C-64 you'll get:
when compiled and ran on a C-64 you'll get:
![c64 screen](docs/source/_static/primes_example.png)
@@ -184,3 +206,19 @@ For instance here's a well known space ship animated in 3D with hidden line remo
in the CommanderX16 emulator:
![cobra3d](docs/source/_static/cobra3d.png)
Performance comparison with various C compilers
-----------------------------------------------
Here is a performance comparison with various C compilers for the 6502/C64 so you can get
an idea of how Prog8 stacks up.
[comparison](benchmark-c/benchmark.md)
Agent context instructions
--------------------------
[Agent context instructions](AGENTS.md)
-24
View File
@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/build" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="KotlinJavaRuntime" level="project" />
<orderEntry type="library" name="jetbrains.kotlinx.cli.jvm" level="project" />
<orderEntry type="library" name="michael.bull.kotlin.result.jvm" level="project" />
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$MODULE_DIR$/lib/bsh-3.0.0-SNAPSHOT.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
</component>
</module>
-91
View File
@@ -1,91 +0,0 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
kotlin("jvm")
id("application")
}
val serverMainClassName = "prog8lsp.MainKt"
val applicationName = "prog8-beanshell"
val javaVersion: String by project
application {
mainClass.set(serverMainClassName)
description = "Code completions, diagnostics and more for Prog8"
// applicationDefaultJvmArgs = listOf("-DkotlinLanguageServer.version=$version")
applicationDistribution.into("bin") {
filePermissions {
user {
read=true
execute=true
write=true
}
other.execute = true
group.execute = true
}
}
}
repositories {
mavenCentral()
}
dependencies {
implementation(files("lib/bsh-3.0.0-SNAPSHOT.jar"))
}
configurations.forEach { config ->
config.resolutionStrategy {
preferProjectModules()
}
}
sourceSets.main {
java.srcDir("src")
resources.srcDir("resources")
}
sourceSets.test {
java.srcDir("src")
resources.srcDir("resources")
}
tasks.startScripts {
applicationName = "prog8-beanshell"
}
tasks.register<Exec>("fixFilePermissions") {
// When running on macOS or Linux the start script
// needs executable permissions to run.
onlyIf { !System.getProperty("os.name").lowercase().contains("windows") }
commandLine("chmod", "+x", "${tasks.installDist.get().destinationDir}/bin/prog8-beanshell")
}
tasks.withType<Test>() {
testLogging {
events("failed")
exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
}
}
tasks.installDist {
finalizedBy("fixFilePermissions")
}
tasks.build {
finalizedBy("installDist")
}
java {
targetCompatibility = JavaVersion.VERSION_11
sourceCompatibility = JavaVersion.VERSION_11
}
kotlin {
compilerOptions.jvmTarget = JvmTarget.JVM_11
// jvmToolchain {
// languageVersion = JavaLanguageVersion.of(javaVersion.toInt())
// }
}
Binary file not shown.
@@ -1,48 +0,0 @@
package prog8beanshell
import java.io.FilterReader
import java.io.Reader
class CommandLineReader(val input: Reader): FilterReader(input) {
private val normal = 0
private val lastCharNL = 1
private val sentSemi = 2
private var state = lastCharNL
override fun read(): Int {
if (state == sentSemi) {
this.state = lastCharNL
return 10
} else {
var b = input.read()
while(b==13) b = input.read()
if (b == 10) {
if (this.state == lastCharNL) {
b = 59
this.state = sentSemi
} else {
this.state = lastCharNL
}
} else {
this.state = normal
}
return b
}
}
override fun read(buff: CharArray, off: Int, len: Int): Int {
val b = read()
if (b == -1) {
return -1
} else {
buff[off] = b.toChar()
return 1
}
}
}
-23
View File
@@ -1,23 +0,0 @@
package prog8beanshell
import bsh.FileReader
import bsh.Interpreter
class BeanshellInterpreter {
fun run(symbols: Map<String, Any>) {
val interpreter = Interpreter(CommandLineReader(FileReader(System.`in`)), System.out, System.err, true)
interpreter.setExitOnEOF(false)
symbols.forEach { (name, value) -> interpreter.set(name, value) }
interpreter.run()
}
}
fun main(args: Array<String>) {
val i = BeanshellInterpreter()
i.run(mapOf(
"env" to System.getenv(),
"args" to args
))
}
+39
View File
@@ -0,0 +1,39 @@
# C-Bench-64 comparison
Several benchmarks of https://thred.github.io/c-bench-64/
have been ported to equivalent Prog8 code and the benchmark results have been penciled in in the graphs below.
Because they use the CIA timer for measuring the duration of the runs, the code only works on a C64.
Maybe one day I'll try to integrate the prog8 data properly but their benchmark site is comparing C compilers, which Prog8 clearly is not.
However conclusions so far (note: these are micro benchmarks so interpret the results as you will!)
* Prog8 program size is consistently one of the smallest.
* Prog8 execution speed places it more or less in the middle of the stack.
Measured with Prog8 V12.0 .
Benchmarks ran on a PAL C64 emulated through VICE.
textual results:
| benchmark | size | time |
|-----------|------|----------|
| crc8 | 1568 | 2.0 sec |
| crc16 | 1608 | 2.5 sec |
| crc32 | 1812 | 4.2 sec |
| pow | 2152 | 11.7 sec |
| sieve | 1772 | 22.1 sec |
| sieve_bit | 1918 | 40.1 sec |
![crc8](result-crc8.png)
![crc16](result-crc16.png)
![crc32](result-crc32.png)
![pow](result-pow.png)
![sieve](result-sieve.png)
![sieve-bit](result-sieve-bit.png)
+98
View File
@@ -0,0 +1,98 @@
%import textio
cia {
ubyte freq
const ubyte CNT = 200
sub calibrate() {
txt.print("calibrating frequency: ")
tod_init(0)
txt.print_ub(tod_freq())
txt.print(" hz\n")
tod_reset()
}
sub print_time() {
uword t = tod_get10()
txt.print("(cia) time: ")
txt.print_uw(t / 10)
txt.chrout('.')
txt.print_uw(t % 10)
txt.print(" sec.\n")
}
sub tod_reset() {
; set the tod to 0
c64.CIA2TODHR = 0
c64.CIA2TODMIN = 0
c64.CIA2TODSEC = 0
c64.CIA2TOD10 = 0
}
sub tod_get10() -> uword {
ubyte h, m, s, t
uword time
h = c64.CIA2TODHR
m = c64.CIA2TODMIN
s = c64.CIA2TODSEC
t = c64.CIA2TOD10
time = t
time += (s & $0f) * (10 as uword)
time += (s >> 4) * (100 as uword)
time += (m & $0f) * 600
time += (m >> 4) * 6000
return time
}
sub tod_init(ubyte f) {
if (f == 0)
freq = tod_detect_freq()
else
freq = f
if (freq == 50)
c64.CIA2CRA |= $80
else
c64.CIA2CRA &= $7f
}
sub tod_freq() -> ubyte {
return freq
}
sub tod_detect_freq() -> ubyte {
uword cbl
c64.CIA2CRB = $40 ; stop timer
c64.CIA2CRA = $80 ; stop timer
; set ta to overflow every 10000 count (~= 10ms)
c64.CIA2TAL = $10
c64.CIA2TAH = $27
c64.CIA2TBL = CNT
c64.CIA2TBH = 0
tod_reset()
c64.CIA2CRB = $41 ; input from tim1 overflow, continuous, start timer
c64.CIA2CRA = $81 ; start timer, continuous tod 50HZ
while c64.CIA2TODSEC == 0 {
; wait for tod to count 1s
}
; cal=CIA2.ta_lo;
; cah=CIA2.ta_hi;
cbl = c64.CIA2TBL
; cbh=CIA2.tb_hi;
; printf("count2 = %d %d %d %d\n",cah, cal, cbh, cbl);
; printf("elapsed ~= %d0ms\n",CNT-cbl);
if CNT - cbl > 90
return 50
else
return 60
}
}
+71
View File
@@ -0,0 +1,71 @@
%import textio
%import ciatimer
; note: Prog8 has a complete CRC16 routine in its library: math.crc16
main {
sub start() {
txt.lowercase()
cia.calibrate()
test.benchmark_name()
test.benchmark()
void test.benchmark_check()
cia.print_time()
repeat {}
}
}
test {
const uword EXPECTED = $ffd0
uword crc_result
sub benchmark_name()
{
txt.print("crc16.p8\n")
txt.print("Calculates the CRC16 of the C64 Kernal\n")
}
sub benchmark()
{
crc_result = CRC16($e000, $2000)
}
sub benchmark_check() -> bool
{
txt.print("CRC=")
txt.print_uwhex(crc_result, true)
if crc_result == EXPECTED
{
txt.print(" [OK]\n")
return false
}
txt.print(" [FAIL] - expected ")
txt.print_uwhex(EXPECTED, true)
txt.nl()
return true
}
sub CRC16(^^ubyte data, uword length) -> uword {
; CRC-16/XMODEM
uword crc
repeat length
{
crc ^= mkword(@(data),0) ; currently there's no easy way to affect only the MSB of the variable
repeat 8
{
crc <<=1
if_cs
crc ^= $1021
}
data++
}
return crc
}
}
+72
View File
@@ -0,0 +1,72 @@
%import textio
%import ciatimer
; note: Prog8 has a complete CRC32 routine in its library: math.crc32
main {
sub start() {
txt.lowercase()
cia.calibrate()
test.benchmark_name()
test.benchmark()
void test.benchmark_check()
cia.print_time()
repeat {}
}
}
test {
const long EXPECTED = $e1fa84c6
long crc_result
sub benchmark_name()
{
txt.print("crc32.p8\n")
txt.print("Calculates the CRC32 of the C64 Kernal\n")
}
sub benchmark()
{
crc_result = CRC32($e000, $2000)
}
sub benchmark_check() -> bool
{
txt.print("CRC=")
txt.print_ulhex(crc_result, true)
if crc_result == EXPECTED
{
txt.print(" [OK]\n")
return false
}
txt.print(" [FAIL] - expected ")
txt.print_ulhex(EXPECTED, true)
txt.nl()
return true
}
sub CRC32(^^ubyte data, uword length) -> long {
; CRC-32/CKSUM
long crc
repeat length
{
crc ^= (@(data) as long)<<24 ; currently there's no easy way to affect only the MSB of the variable
repeat 8
{
crc <<=1
if_cs
crc ^= $04c11db7
}
data++
}
crc ^= $ffffffff
return crc
}
}
+72
View File
@@ -0,0 +1,72 @@
%import textio
%import ciatimer
main {
sub start() {
txt.lowercase()
cia.calibrate()
test.benchmark_name()
test.benchmark()
void test.benchmark_check()
cia.print_time()
repeat {}
}
}
test {
sub benchmark_name()
{
txt.print("crc8.p8\n")
txt.print("Calculates the CRC8 of the C64 Kernal\n")
}
sub benchmark()
{
crc_result = CRC8($e000, $2000)
}
sub benchmark_check() -> bool
{
txt.print("CRC=")
txt.print_ubhex(crc_result, true)
if crc_result == EXPECTED
{
txt.print(" [OK]\n")
return false
}
txt.print(" [FAIL] - expected ")
txt.print_ubhex(EXPECTED, true)
txt.nl()
return true
}
const ubyte EXPECTED = $a2
ubyte crc_result
sub CRC8(^^ubyte data, uword length) -> ubyte
{
; CRC-8/GSM-A
ubyte crc
repeat length
{
crc ^= @(data)
repeat 8
{
if (crc & $80) != 0
crc = (crc << 1) ^ $1d
else
crc <<= 1
}
data++
}
return crc
}
}
+93
View File
@@ -0,0 +1,93 @@
%import textio
%import floats
%import ciatimer
main {
sub start() {
txt.lowercase()
cia.calibrate()
test.benchmark_name()
test.benchmark()
void test.benchmark_check()
cia.print_time()
repeat {}
}
}
test {
const ubyte N_ITER = 10
const ubyte SIZE = 32
float[SIZE] array
const float expected = 3614007361536.000000
const float epsilon = 10000000
float res
sub benchmark_name()
{
txt.print("pow.p8\n")
txt.print("Calculates floating point exponential (")
txt.print_uw(N_ITER)
txt.print(" iterations)\n")
}
sub benchmark()
{
ubyte i,j
res = 0
for j in 0 to SIZE-1 {
array[j]=0
}
for i in 0 to N_ITER-1 {
for j in 0 to SIZE-1 {
array[j] += testpow(2.5 / ((i + 1) as float), j)
}
}
for j in 0 to SIZE-1 {
res += array[j]
}
}
sub testpow(float x, ubyte y) -> float
{
float tmp = x
if y == 0
return 1
repeat y-1
tmp *= x
return tmp
}
sub benchmark_check() -> bool
{
txt.print("res = ")
txt.print_f(res)
float diff = expected - res;
txt.print("\nexpected = ")
txt.print_f(expected)
txt.print("\nepsilon = ")
txt.print_f(epsilon)
txt.print("\ndiff = ")
txt.print_f(diff)
if (diff < epsilon and diff > -epsilon)
{
txt.print(" [OK]\n")
return false
}
txt.print("[FAIL]\n")
return true
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

+85
View File
@@ -0,0 +1,85 @@
%import textio
%import ciatimer
main {
sub start() {
txt.lowercase()
cia.calibrate()
test.benchmark_name()
test.benchmark()
void test.benchmark_check()
cia.print_time()
repeat {}
}
}
test {
const ubyte N_ITER = 10
const uword SIZE = 8191
const uword EXPECTED = 1900
uword prime_count
^^bool @zp flags = memory("flags", SIZE, 0)
sub benchmark_name()
{
txt.print("sieve.c\n")
txt.print("Calculates the primes from 1 to ")
txt.print_uw(SIZE * 2 + 2)
txt.print(" (")
txt.print_ub(N_ITER)
txt.print(" iterations)\n")
}
sub benchmark()
{
repeat N_ITER
prime_count = sieve(SIZE)
}
sub benchmark_check() -> bool
{
txt.print("count=")
txt.print_uw(prime_count)
if prime_count == EXPECTED
{
txt.print(" [OK]\n")
return false
}
txt.print(" [FAIL] - expected ")
txt.print_uw(EXPECTED)
txt.nl()
return true
}
sub sieve(uword size) -> uword
{
uword i, prime, k
uword count = 1
for i in 0 to size-1
flags[i] = true
for i in 0 to size-1
{
if flags[i]
{
prime = i + i + 3
k = i + prime
while k < size
{
flags[k] = false
k += prime
}
count++
}
}
return count
}
}
+107
View File
@@ -0,0 +1,107 @@
%import textio
%import ciatimer
main {
sub start() {
txt.lowercase()
cia.calibrate()
test.benchmark_name()
test.benchmark()
void test.benchmark_check()
cia.print_time()
repeat {}
}
}
test {
const ubyte N_ITER = 4
const uword SIZE = 16000
const uword EXPECTED = 3432
uword prime_count
^^ubyte @zp flags = memory("flags", SIZE/8+1, 0)
sub benchmark_name()
{
txt.print("sieve_bit.p8\n")
txt.print("Calculates the primes from 1 to ")
txt.print_uw(SIZE * 2 + 2)
txt.print(" (")
txt.print_ub(N_ITER)
txt.print(" iterations)\n")
}
sub benchmark()
{
repeat N_ITER
prime_count = sieve(SIZE)
}
sub benchmark_check() -> bool
{
txt.print("count=")
txt.print_uw(prime_count)
if prime_count == EXPECTED
{
txt.print(" [OK]\n")
return false
}
txt.print(" [FAIL] - expected ")
txt.print_uw(EXPECTED)
txt.nl()
return true
}
ubyte[] bitv = [
$01,
$02,
$04,
$08,
$10,
$20,
$40,
$80
]
sub check_flag(uword idx) -> bool
{
return flags[idx / 8] & bitv[lsb(idx) & 7] != 0
}
sub clear_flag(uword idx)
{
flags[idx / 8] &= ~(bitv[lsb(idx) & 7])
}
sub sieve(uword size) -> uword
{
uword i, prime, k
uword count=1
for i in 0 to (size / 8)
flags[i] = $ff
for i in 0 to size-1
{
if check_flag(i)
{
prime = i + i + 3
k = i + prime;
while k < size
{
clear_flag(k)
k += prime
}
count++
}
}
return count
}
}
+19 -18
View File
@@ -41,7 +41,7 @@ rotate3d {
for i in 0 to len(matrix_math.xcoor)-1 {
rz = matrix_math.rotatedz[i]
if rz >= 10 {
persp = 600 + rz/64
persp = 600 + (rz>>5)
sx = matrix_math.rotatedx[i] / persp as byte + WIDTH/2
sy = matrix_math.rotatedy[i] / persp as byte + HEIGHT/2
;; txt.setcc(sx as ubyte, sy as ubyte, 46, 7)
@@ -51,7 +51,7 @@ rotate3d {
for i in 0 to len(matrix_math.xcoor)-1 {
rz = matrix_math.rotatedz[i]
if rz < 10 {
persp = 600 + rz/64
persp = 600 + (rz>>5)
sx = matrix_math.rotatedx[i] / persp as byte + WIDTH/2
sy = matrix_math.rotatedy[i] / persp as byte + HEIGHT/2
;; txt.setcc(sx as ubyte, sy as ubyte, 81, 7)
@@ -64,14 +64,14 @@ rotate3d {
matrix_math {
; vertices
word[] @split xcoor = [ -40, -40, -40, -40, 40, 40, 40, 40 ]
word[] @split ycoor = [ -40, -40, 40, 40, -40, -40, 40, 40 ]
word[] @split zcoor = [ -40, 40, -40, 40, -40, 40, -40, 40 ]
word[] xcoor = [ -40, -40, -40, -40, 40, 40, 40, 40 ]
word[] ycoor = [ -40, -40, 40, 40, -40, -40, 40, 40 ]
word[] zcoor = [ -40, 40, -40, 40, -40, 40, -40, 40 ]
; storage for rotated coordinates
word[len(xcoor)] @split rotatedx
word[len(ycoor)] @split rotatedy
word[len(zcoor)] @split rotatedz
word[len(xcoor)] rotatedx
word[len(ycoor)] rotatedy
word[len(zcoor)] rotatedz
sub rotate_vertices(ubyte ax, ubyte ay, ubyte az) {
; rotate around origin (0,0,0)
@@ -84,18 +84,19 @@ matrix_math {
word wcosc = math.cos8(az)
word wsinc = math.sin8(az)
word wcosa_sinb = wcosa*wsinb / 128
word wsina_sinb = wsina*wsinb / 128
; instead of (slow) /128, we simply shift 7 bits (and take the roundoff error)
word wcosa_sinb = wcosa*wsinb >> 7
word wsina_sinb = wsina*wsinb >> 7
word Axx = wcosa*wcosb / 128
word Axy = (wcosa_sinb*wsinc - wsina*wcosc) / 128
word Axz = (wcosa_sinb*wcosc + wsina*wsinc) / 128
word Ayx = wsina*wcosb / 128
word Ayy = (wsina_sinb*wsinc + wcosa*wcosc) / 128
word Ayz = (wsina_sinb*wcosc - wcosa*wsinc) / 128
word Axx = wcosa*wcosb >> 7
word Axy = (wcosa_sinb*wsinc - wsina*wcosc) >> 7
word Axz = (wcosa_sinb*wcosc + wsina*wsinc) >> 7
word Ayx = wsina*wcosb >> 7
word Ayy = (wsina_sinb*wsinc + wcosa*wcosc) >> 7
word Ayz = (wsina_sinb*wcosc - wcosa*wsinc) >> 7
word Azx = -wsinb
word Azy = wcosb*wsinc / 128
word Azz = wcosb*wcosc / 128
word Azy = wcosb*wsinc >> 7
word Azz = wcosb*wcosc >> 7
ubyte @zp i
for i in 0 to len(xcoor)-1 {
+4 -4
View File
@@ -7,7 +7,7 @@ adpcm {
while cbm.RDTIM16()<max_time {
adpcm.init(0,0)
uword @requirezp nibbles_ptr = $a000 ; for benchmark purposes, the exact nibbles don't really matter, so we just take the basic ROM as input
uword @requirezp nibbles_ptr = $0800 ; for benchmark purposes, the exact nibbles don't really matter, so we just take this benchmark program itself as input
repeat 252/2 {
unroll 2 {
ubyte @zp nibble = @(nibbles_ptr)
@@ -25,8 +25,8 @@ adpcm {
; IMA ADPCM decoder. Supports mono and stereo streams.
ubyte[] t_index = [ -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8]
uword[] @split t_step = [
byte[] t_index = [ -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8]
uword[] t_step = [
7, 8, 9, 10, 11, 12, 13, 14,
16, 17, 19, 21, 23, 25, 28, 31,
34, 37, 41, 45, 50, 55, 60, 66,
@@ -79,7 +79,7 @@ adpcm {
; elif predicted < -32767:
; predicted = - 32767
index += t_index[nibble]
index += t_index[nibble] as ubyte
if_neg
index = 0
else if index >= len(t_step)-1
+234
View File
@@ -0,0 +1,234 @@
; Binary Search Tree.
; It's a simple implementation for test/demonstration purposes of the pointer support;
; no balancing is done and memory is not freed when elements are removed.
%import textio
btree {
sub benchmark(uword max_time) -> uword {
txt.nl()
cbm.SETTIM(0,0,0)
uword score
while cbm.RDTIM16() < max_time {
bench_operations()
txt.chrout('.')
score++
}
txt.nl()
return score
}
sub bench_operations() {
arena.freeall()
btree.root = 0
for cx16.r0 in [321, 719, 194, 550, 187, 203, 520, 562, 221, 676, 97, 852, 273, 326, 589, 606, 275, 794, 63, 716]
btree.add(cx16.r0)
cx16.r0L = btree.size()
btree.process_tree_inorder()
btree.process_tree_preorder()
void btree.contains(203)
void btree.contains(204)
void btree.contains(605)
void btree.contains(606)
btree.remove(9999)
btree.remove(97)
btree.remove(187)
btree.remove(203)
btree.remove(275)
btree.remove(321)
btree.remove(520)
btree.remove(562)
btree.remove(606)
btree.remove(719)
btree.remove(794)
cx16.r0L = btree.size()
btree.process_tree_inorder()
btree.process_tree_preorder()
}
struct Node {
^^Node left
^^Node right
uword value
}
^^Node root = 0
sub add(uword value) {
^^Node node = arena.alloc(sizeof(Node))
node.value = value
node.left = node.right = 0
if root==0
root=node
else {
^^Node parent = root
repeat {
if parent.value >= value {
if parent.left!=0
parent = parent.left
else {
parent.left = node
return
}
} else {
if parent.right!=0
parent = parent.right
else {
parent.right = node
return
}
}
}
}
}
sub contains(uword value) -> bool {
^^Node r = root
while r!=0 {
if r.value==value
return true
if r.value>value
r = r.left
else
r = r.right
}
return false
}
sub size() -> ubyte {
ubyte count
if root!=0
count_node(root)
return count
sub count_node(^^Node r) {
count++
if r.left!=0 {
pushw(r)
count_node(r.left)
r = popw()
}
if r.right!=0 {
pushw(r)
count_node(r.right)
r = popw()
}
}
}
sub remove(uword value) {
; note: we don't deallocate the memory from the node, for simplicity sake
^^Node n = root
^^Node parent = 0
while n!=0 {
if n.value==value {
if n.left==0
replacechild(parent, n, n.right)
else if n.right==0
replacechild(parent, n, n.left)
else {
; Both left & right subtrees are present.
; N = node to delete.
; Find N's successor S. (N's right subtree's minimum element)
; Attach N's left subtree to S.left (S doesn't have a left child)
; Attach N's right subtree to Parent in place of N.
^^Node successor = find_successor(n)
successor.left = n.left
replacechild(parent, n, n.right)
}
return
}
parent = n
if n.value>value
n = n.left
else
n = n.right
}
sub find_successor(^^Node p) -> ^^Node {
^^Node succ = p
p = p.right
while p!=0 {
succ = p
p = p.left
}
return succ
}
sub replacechild(^^Node p, ^^Node child, ^^Node newchild) {
if p.left==child
p.left = newchild
else
p.right = newchild
}
}
sub process_tree_inorder() {
if root!=0
process_tree(root)
sub process_tree(^^Node r) {
if r.left!=0 {
pushw(r)
process_tree(r.left)
r = popw()
}
cx16.r0 = r.value
if r.right!=0 {
pushw(r)
process_tree(r.right)
r = popw()
}
}
}
sub process_tree_preorder() {
if root!=0
process_tree(root,0)
sub process_tree(^^Node r, ubyte depth) {
cx16.r0 = r.value
if r.left!=0 {
pushw(r)
push(depth)
process_tree(r.left, depth+1)
depth = pop()
r = popw()
}
if r.right!=0 {
pushw(r)
push(depth)
process_tree(r.right, depth+1)
depth = pop()
r = popw()
}
}
}
}
arena {
; extremely trivial arena allocator (that never frees)
pointer buffer = memory("arena", 2000, 0)
pointer next = buffer
sub alloc(ubyte size) -> pointer {
defer next += size
return next
}
sub freeall() {
next = buffer
}
}
+4 -4
View File
@@ -4,15 +4,15 @@
circles {
const ubyte MAX_NUM_CIRCLES = 80
const ubyte GROWTH_RATE = 4
uword[MAX_NUM_CIRCLES] @split circle_x
uword[MAX_NUM_CIRCLES] @split circle_y
uword[MAX_NUM_CIRCLES] circle_x
uword[MAX_NUM_CIRCLES] circle_y
ubyte[MAX_NUM_CIRCLES] circle_radius
ubyte color
uword total_num_circles
sub draw(bool use_kernal, uword max_time) -> uword {
if use_kernal
void cx16.set_screen_mode(128)
cx16.set_screen_mode(128)
else
gfx_lores.graphics_mode()
@@ -33,7 +33,7 @@ circles {
}
if use_kernal
void cx16.set_screen_mode(3)
cx16.set_screen_mode(3)
else {
gfx_lores.text_mode()
}
+1 -2
View File
@@ -61,8 +61,7 @@ life {
math.rndseed(12345,9999)
uword offset = STRIDE+1
ubyte x
ubyte y
for y in 0 to HEIGHT-1 {
repeat HEIGHT {
for x in 0 to WIDTH-1 {
active_world[offset+x] = math.rnd() & 1
}
+4 -4
View File
@@ -35,12 +35,12 @@ queens {
if could_place(row, col) {
board[row] = col
; we need to save the local variables row and col.
sys.push(row)
sys.push(col)
push(row)
push(col)
continue_running = place_queen(row + 1)
; restore the local variables after the recursive call.
col = sys.pop()
row = sys.pop()
col = pop()
row = pop()
board[row] = 0
if not continue_running
+69
View File
@@ -0,0 +1,69 @@
%import sprites
%import coroutines
%import math
animsprites {
uword num_iterations
ubyte[64] sx
ubyte[64] sy
ubyte[64] sc
ubyte[64] dx
ubyte[64] dy
uword maximum_duration
sub benchmark(uword max_duration) -> uword {
maximum_duration = max_duration
math.rndseed(1122,9876)
cx16.set_screen_mode(3)
cx16.mouse_config2(1)
sprites.set_mousepointer_hand()
repeat 64
void coroutines.add(animsprite, 0)
cx16.mouse_config2(0)
cbm.SETTIM(0,0,0)
coroutines.run(supervisor)
sprites.reset(0, 64)
return num_iterations
}
sub supervisor() -> bool {
if cbm.RDTIM16() >= maximum_duration {
coroutines.killall()
return false
}
return true
}
sub animsprite() {
num_iterations++
; set up the sprite
ubyte sprnum = coroutines.current()
cx16.r6L, cx16.r7 = sprites.get_data_ptr(0)
sprites.init(sprnum, cx16.r6L, cx16.r7, sprites.SIZE_16, sprites.SIZE_16, sprites.COLORS_256, 0)
sx[sprnum] = math.rnd()
sy[sprnum] = math.rnd()
sc[sprnum] = math.rnd()
dx[sprnum] = if math.rnd()&1 == 1 1 else 255
dy[sprnum] = if math.rnd()&1 == 1 1 else 255
; move the sprite around
while sc[sprnum]!=0 {
animate(sprnum)
void coroutines.yield()
sprnum = coroutines.current()
}
sub animate(ubyte spr) {
defer sc[spr]--
sprites.pos(spr, sx[spr], sy[spr])
sx[spr] += dx[spr]
sy[spr] += dy[spr]
}
; end the task but replace it with a fresh animated sprite task
void coroutines.add(animsprite, 0)
}
}
+48 -49
View File
@@ -1,7 +1,6 @@
%import textio
%import conv
%import string
%import string
%import strings
textelite {
@@ -172,7 +171,7 @@ textelite {
sub next_input(str buffer) -> ubyte {
input_index++
return string.copy(inputs[input_index], buffer)
return strings.copy(inputs[input_index], buffer)
}
}
@@ -473,7 +472,7 @@ elite_galaxy {
generate_next_planet()
textelite.num_commands++
}
elite_planet.name = make_current_planet_name()
void strings.copy(make_current_planet_name(), elite_planet.name)
init_market_for_planet()
}
@@ -495,7 +494,7 @@ elite_galaxy {
ubyte pi
for pi in 0 to 255 {
generate_next_planet()
elite_planet.name = make_current_planet_name()
void strings.copy(make_current_planet_name(), elite_planet.name)
if elite_util.prefix_matches(nameptr, elite_planet.name) {
ubyte distance = elite_planet.distance(x, y)
if distance < current_distance {
@@ -533,7 +532,7 @@ elite_galaxy {
; else
; txt.chrout('-')
; txt.spc()
elite_planet.name = make_current_planet_name()
void strings.copy(make_current_planet_name(), elite_planet.name)
elite_planet.display(true, distance)
}
pn++
@@ -549,7 +548,7 @@ elite_galaxy {
str current_name = " " ; 8 max
ubyte pn = 0
current_name = elite_planet.name
void strings.copy(elite_planet.name, current_name)
init(number)
; txt.clear_screen()
; txt.print("Galaxy #")
@@ -570,8 +569,8 @@ elite_galaxy {
generate_next_planet()
ubyte distance = elite_planet.distance(px, py)
if distance <= max_distance {
elite_planet.name = make_current_planet_name()
elite_planet.name[0] = string.upperchar(elite_planet.name[0])
void strings.copy(make_current_planet_name(), elite_planet.name)
elite_planet.name[0] = strings.upperchar(elite_planet.name[0])
uword tx = elite_planet.x
uword ty = elite_planet.y
if local {
@@ -743,42 +742,42 @@ elite_galaxy {
}
elite_planet {
str[] words81 = ["fabled", "notable", "well known", "famous", "noted"]
str[] words82 = ["very", "mildly", "most", "reasonably", ""]
str[] words83 = ["ancient", "\x95", "great", "vast", "pink"]
str[] words84 = ["\x9E \x9D plantations", "mountains", "\x9C", "\x94 forests", "oceans"]
str[] words85 = ["shyness", "silliness", "mating traditions", "loathing of \x86", "love for \x86"]
str[] words86 = ["food blenders", "tourists", "poetry", "discos", "\x8E"]
str[] words87 = ["talking tree", "crab", "bat", "lobst", "\xB2"]
str[] words88 = ["beset", "plagued", "ravaged", "cursed", "scourged"]
str[] words89 = ["\x96 civil war", "\x9B \x98 \x99s", "a \x9B disease", "\x96 earthquakes", "\x96 solar activity"]
str[] words8A = ["its \x83 \x84", "the \xB1 \x98 \x99", "its inhabitants' \x9A \x85", "\xA1", "its \x8D \x8E"]
str[] words8B = ["juice", "brandy", "water", "brew", "gargle blasters"]
str[] words8C = ["\xB2", "\xB1 \x99", "\xB1 \xB2", "\xB1 \x9B", "\x9B \xB2"]
str[] words8D = ["fabulous", "exotic", "hoopy", "unusual", "exciting"]
str[] words8E = ["cuisine", "night life", "casinos", "sit coms", " \xA1 "]
str[] words8F = ["\xB0", "The planet \xB0", "The world \xB0", "This planet", "This world"]
str[] words90 = ["n unremarkable", " boring", " dull", " tedious", " revolting"]
str[] words91 = ["planet", "world", "place", "little planet", "dump"]
str[] words92 = ["wasp", "moth", "grub", "ant", "\xB2"]
str[] words93 = ["poet", "arts graduate", "yak", "snail", "slug"]
str[] words94 = ["tropical", "dense", "rain", "impenetrable", "exuberant"]
str[] words95 = ["funny", "wierd", "unusual", "strange", "peculiar"]
str[] words96 = ["frequent", "occasional", "unpredictable", "dreadful", "deadly"]
str[] words97 = ["\x82 \x81 for \x8A", "\x82 \x81 for \x8A and \x8A", "\x88 by \x89", "\x82 \x81 for \x8A but \x88 by \x89", "a\x90 \x91"]
str[] words98 = ["\x9B", "mountain", "edible", "tree", "spotted"]
str[] words99 = ["\x9F", "\xA0", "\x87oid", "\x93", "\x92"]
str[] words9A = ["ancient", "exceptional", "eccentric", "ingrained", "\x95"]
str[] words9B = ["killer", "deadly", "evil", "lethal", "vicious"]
str[] words9C = ["parking meters", "dust clouds", "ice bergs", "rock formations", "volcanoes"]
str[] words9D = ["plant", "tulip", "banana", "corn", "\xB2weed"]
str[] words9E = ["\xB2", "\xB1 \xB2", "\xB1 \x9B", "inhabitant", "\xB1 \xB2"]
str[] words9F = ["shrew", "beast", "bison", "snake", "wolf"]
str[] wordsA0 = ["leopard", "cat", "monkey", "goat", "fish"]
str[] wordsA1 = ["\x8C \x8B", "\xB1 \x9F \xA2", "its \x8D \xA0 \xA2", "\xA3 \xA4", "\x8C \x8B"]
str[] wordsA2 = ["meat", "cutlet", "steak", "burgers", "soup"]
str[] wordsA3 = ["ice", "mud", "Zero-G", "vacuum", "\xB1 ultra"]
str[] wordsA4 = ["hockey", "cricket", "karate", "polo", "tennis"]
str[] @nosplit words81 = ["fabled", "notable", "well known", "famous", "noted"]
str[] @nosplit words82 = ["very", "mildly", "most", "reasonably", ""]
str[] @nosplit words83 = ["ancient", "\x95", "great", "vast", "pink"]
str[] @nosplit words84 = ["\x9E \x9D plantations", "mountains", "\x9C", "\x94 forests", "oceans"]
str[] @nosplit words85 = ["shyness", "silliness", "mating traditions", "loathing of \x86", "love for \x86"]
str[] @nosplit words86 = ["food blenders", "tourists", "poetry", "discos", "\x8E"]
str[] @nosplit words87 = ["talking tree", "crab", "bat", "lobst", "\xB2"]
str[] @nosplit words88 = ["beset", "plagued", "ravaged", "cursed", "scourged"]
str[] @nosplit words89 = ["\x96 civil war", "\x9B \x98 \x99s", "a \x9B disease", "\x96 earthquakes", "\x96 solar activity"]
str[] @nosplit words8A = ["its \x83 \x84", "the \xB1 \x98 \x99", "its inhabitants' \x9A \x85", "\xA1", "its \x8D \x8E"]
str[] @nosplit words8B = ["juice", "brandy", "water", "brew", "gargle blasters"]
str[] @nosplit words8C = ["\xB2", "\xB1 \x99", "\xB1 \xB2", "\xB1 \x9B", "\x9B \xB2"]
str[] @nosplit words8D = ["fabulous", "exotic", "hoopy", "unusual", "exciting"]
str[] @nosplit words8E = ["cuisine", "night life", "casinos", "sit coms", " \xA1 "]
str[] @nosplit words8F = ["\xB0", "The planet \xB0", "The world \xB0", "This planet", "This world"]
str[] @nosplit words90 = ["n unremarkable", " boring", " dull", " tedious", " revolting"]
str[] @nosplit words91 = ["planet", "world", "place", "little planet", "dump"]
str[] @nosplit words92 = ["wasp", "moth", "grub", "ant", "\xB2"]
str[] @nosplit words93 = ["poet", "arts graduate", "yak", "snail", "slug"]
str[] @nosplit words94 = ["tropical", "dense", "rain", "impenetrable", "exuberant"]
str[] @nosplit words95 = ["funny", "wierd", "unusual", "strange", "peculiar"]
str[] @nosplit words96 = ["frequent", "occasional", "unpredictable", "dreadful", "deadly"]
str[] @nosplit words97 = ["\x82 \x81 for \x8A", "\x82 \x81 for \x8A and \x8A", "\x88 by \x89", "\x82 \x81 for \x8A but \x88 by \x89", "a\x90 \x91"]
str[] @nosplit words98 = ["\x9B", "mountain", "edible", "tree", "spotted"]
str[] @nosplit words99 = ["\x9F", "\xA0", "\x87oid", "\x93", "\x92"]
str[] @nosplit words9A = ["ancient", "exceptional", "eccentric", "ingrained", "\x95"]
str[] @nosplit words9B = ["killer", "deadly", "evil", "lethal", "vicious"]
str[] @nosplit words9C = ["parking meters", "dust clouds", "ice bergs", "rock formations", "volcanoes"]
str[] @nosplit words9D = ["plant", "tulip", "banana", "corn", "\xB2weed"]
str[] @nosplit words9E = ["\xB2", "\xB1 \xB2", "\xB1 \x9B", "inhabitant", "\xB1 \xB2"]
str[] @nosplit words9F = ["shrew", "beast", "bison", "snake", "wolf"]
str[] @nosplit wordsA0 = ["leopard", "cat", "monkey", "goat", "fish"]
str[] @nosplit wordsA1 = ["\x8C \x8B", "\xB1 \x9F \xA2", "its \x8D \xA0 \xA2", "\xA3 \xA4", "\x8C \x8B"]
str[] @nosplit wordsA2 = ["meat", "cutlet", "steak", "burgers", "soup"]
str[] @nosplit wordsA3 = ["ice", "mud", "Zero-G", "vacuum", "\xB1 ultra"]
str[] @nosplit wordsA4 = ["hockey", "cricket", "karate", "polo", "tennis"]
uword[] @shared wordlists = [
words81, words82, words83, words84, words85, words86, words87, words88,
@@ -840,7 +839,7 @@ elite_planet {
}
}
randname[nx] = 0
randname[0] = string.upperchar(randname[0])
randname[0] = strings.upperchar(randname[0])
return randname
}
@@ -912,12 +911,12 @@ elite_planet {
source_ptr = source_stack[stack_ptr]
} else {
if c == $b0 {
@(result_ptr) = string.upperchar(name[0])
@(result_ptr) = strings.upperchar(name[0])
result_ptr++
concat_string(&name + 1)
}
else if c == $b1 {
@(result_ptr) = string.upperchar(name[0])
@(result_ptr) = strings.upperchar(name[0])
result_ptr++
ubyte ni
for ni in 1 to len(name) {
@@ -981,7 +980,7 @@ elite_util {
if pc == 0
return true
; to lowercase for case insensitive compare:
if string.lowerchar(pc)!=string.lowerchar(sc)
if strings.lowerchar(pc)!=strings.lowerchar(sc)
return false
prefixptr++
stringptr++
+46 -17
View File
@@ -4,6 +4,12 @@
;
; As the X16 computer is a more or less fixed system, it's not very useful
; to benchmark the computer itself with.
;
; The individual scores are iteration counts, and they differ by more than an
; order of magnitude between benchmarks (maze does ~3000, game of life ~180).
; Summing the raw counts therefore let one or two benchmarks dominate the total
; and hide regressions in all the others, so the total is a weighted sum - see
; benchmark_weight below.
%import textio
@@ -15,6 +21,8 @@
%import b_queens
%import b_textelite
%import b_maze
%import b_sprites
%import b_btree
%zeropage basicsafe
%option no_sysinit
@@ -24,17 +32,28 @@ main {
str[20] benchmark_names
uword[20] benchmark_score
; Weight per benchmark, in the same order as the benchmarks are run below. The total is the
; weighted sum of the raw iteration counts.
; The raw counts differ by more than an order of magnitude (maze ~3064, game of life ~180), so
; in an unweighted sum the two heaviest - maze solver and text-elite - were 57% of the total
; while game of life was 2%. A regression in a small benchmark was therefore nearly invisible.
; Their weights are scaled down so that every benchmark contributes roughly comparably; the
; other eight are left at 256 (i.e. unweighted).
uword[10] benchmark_weight = [ 64, 256, 256, 256, 256, 256, 256, 64, 256, 256 ]
str version = "14.0"
sub start() {
ubyte benchmark_number
void cx16.set_screen_mode(3)
cx16.set_screen_mode(3)
txt.color2(1, 6)
txt.clear_screen()
txt.print("\n\n\n prog8 compiler benchmark tests.\n")
sys.wait(60)
txt.print("\n\n\n prog8 compiler benchmark tests.\n\n benchmark version ")
txt.print(version)
txt.print("\n\n")
sys.wait(120)
benchmark_number = 0
@@ -63,43 +82,53 @@ main {
benchmark_number++
announce_benchmark("circles with gfx_lores")
benchmark_score[benchmark_number] = circles.draw(false, 300)
benchmark_score[benchmark_number] = circles.draw(false, 400)
benchmark_number++
; announce_benchmark("circles with kernal")
; benchmark_score[benchmark_number] = circles.draw(true, 300)
; benchmark_number++
announce_benchmark("text-elite")
benchmark_score[benchmark_number] = textelite.bench(120)
benchmark_number++
announce_benchmark("sprites-coroutines-defer")
benchmark_score[benchmark_number] = animsprites.benchmark(300)
benchmark_number++
announce_benchmark("btree-struct-pointers")
benchmark_score[benchmark_number] = btree.benchmark(200)
benchmark_number++
benchmark_names[benchmark_number] = 0
benchmark_score[benchmark_number] = 0
void cx16.set_screen_mode(3)
cx16.set_screen_mode(3)
txt.uppercase()
txt.color2(1, 6)
uword final_score
uword total_score
benchmark_number = 0
txt.print("\nscore benchmark\n\n")
txt.print("\nscore benchmark (")
txt.print(version)
txt.print(")\n\n")
do {
; Weighted contribution. Done in long arithmetic on purpose: score*weight overflows a
; uword (3064*256 is 784384, which wraps to 63488 and would corrupt the total).
uword weighted = ((benchmark_score[benchmark_number] as long) * benchmark_weight[benchmark_number] / 256) as uword
txt.spc()
txt.print_uw(benchmark_score[benchmark_number])
txt.print_uw(weighted)
txt.column(6)
txt.print(benchmark_names[benchmark_number])
final_score += benchmark_score[benchmark_number]
total_score += weighted
txt.nl()
benchmark_number++
} until benchmark_names[benchmark_number]==0
txt.print("\n\nfinal score : ")
txt.print_uw(final_score)
txt.nl()
txt.print("\n\ntotal score : ")
txt.print_uw(total_score)
txt.print(" (higher=better)\n")
sub announce_benchmark(str name) {
benchmark_names[benchmark_number] = name
void cx16.set_screen_mode(3)
cx16.set_screen_mode(3)
txt.uppercase()
txt.color2(1, 6)
txt.clear_screen()
-10
View File
@@ -1,10 +0,0 @@
plugins {
id "org.jetbrains.kotlin.jvm" version "$kotlinVersion" apply false
}
allprojects {
repositories {
mavenLocal()
mavenCentral()
}
}
+111
View File
@@ -0,0 +1,111 @@
import org.jetbrains.kotlin.gradle.dsl.JvmDefaultMode
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
kotlin("jvm") version "2.4.21"
}
allprojects {
apply(plugin="kotlin")
repositories {
mavenLocal()
mavenCentral()
maven { url = uri("https://jitpack.io") }
}
kotlin {
compilerOptions {
freeCompilerArgs = listOf()
jvmTarget = JvmTarget.JVM_17
jvmDefault = JvmDefaultMode.NO_COMPATIBILITY
// languageVersion.set(KotlinVersion.KOTLIN_2_3)
}
sourceSets.all {
languageSettings {
// enable language features like so:
// enableLanguageFeature(LanguageFeature.WhenGuards.name)
}
}
}
java {
targetCompatibility = JavaVersion.VERSION_17
sourceCompatibility = JavaVersion.VERSION_17
}
}
// ============================================================================
// Common Configuration for All Subprojects
// ============================================================================
// This avoids duplication in each module's build.gradle.kts
// ============================================================================
subprojects {
// Common dependency exclusions for all subprojects
// Note: antlr4 exclusion is done per-module since parser module needs it
configurations.all {
exclude(group = "com.ibm.icu", module = "icu4j")
}
// Common test dependencies via Kotest BOM (Bill of Materials)
// This manages all Kotest module versions centrally
dependencies {
testImplementation(platform("io.kotest:kotest-bom:6.2.4"))
// implementation("org.codeberg.irmen:ksim65:v2.2")
}
// Common sourceSets configuration
sourceSets {
main {
java.srcDir("${project.projectDir}/src")
resources.srcDir("${project.projectDir}/res")
}
test {
java.srcDir("${project.projectDir}/test")
}
}
// Common test configuration
tasks.withType<Test>().configureEach {
// Enable JUnit 5 (required for Kotest)
useJUnitPlatform()
// Forked test JVMs each reserve up to -PtestMaxHeap, so keep the fork count
// bounded even on many-core machines to avoid swapping during parallel builds.
val testConcurrency = (project.findProperty("testConcurrency")?.toString()?.toIntOrNull()
?: (Runtime.getRuntime().availableProcessors() / 2)).coerceIn(1, 4)
project.findProperty("testMaxHeap")?.toString()?.let { maxHeapSize = it }
// Enable concurrent test execution for Kotest
// Allow CI to override parallelism for memory-constrained runners
jvmArgs("-Dkotest.framework.parallelism=$testConcurrency")
// Disable Kotest autoscan warning
jvmArgs("-Dkotest.framework.classpath.scanning.autoscan.disable=true")
// Enable Gradle's parallel test execution (runs multiple test classes concurrently)
// Use 50% of available processors to avoid over-subscription
maxParallelForks = testConcurrency
// Allow filtering tests via -PtestFilter="*TestName*" from command line
// Example: gradle test -PtestFilter="*TestLookup*"
val testFilter = project.findProperty("testFilter")?.toString()
if(testFilter != null) {
filter {
includeTestsMatching(testFilter)
}
}
// Show test results - only show failures to reduce noise
testLogging {
events("failed")
// Show full exception details for failures
exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
showExceptions = true
showCauses = true
showStackTraces = true
}
}
}
-42
View File
@@ -1,42 +0,0 @@
plugins {
id 'java'
id 'application'
id "org.jetbrains.kotlin.jvm"
}
java {
targetCompatibility = JavaLanguageVersion.of(javaVersion)
sourceCompatibility = JavaLanguageVersion.of(javaVersion)
}
compileKotlin {
kotlinOptions {
jvmTarget = javaVersion
}
}
compileTestKotlin {
kotlinOptions {
jvmTarget = javaVersion
}
}
dependencies {
// should have no dependencies to other modules
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
implementation "com.michael-bull.kotlin-result:kotlin-result-jvm:2.0.0"
}
sourceSets {
main {
java {
srcDir "${project.projectDir}/src"
}
resources {
srcDir "${project.projectDir}/res"
}
}
}
// note: there are no unit tests in this module!
+11
View File
@@ -0,0 +1,11 @@
plugins {
kotlin("jvm")
`java-test-fixtures`
}
dependencies {
// should have no dependencies to other modules
implementation("com.michael-bull.kotlin-result:kotlin-result-jvm:2.3.1")
testImplementation("io.kotest:kotest-runner-junit5")
}
-14
View File
@@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/build" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="KotlinJavaRuntime" level="project" />
<orderEntry type="library" name="michael.bull.kotlin.result.jvm" level="project" />
</component>
</module>
-24
View File
@@ -1,24 +0,0 @@
package prog8.code
/**
* By convention, the right side of an `Either` is used to hold successful values.
*/
sealed class Either<out L, out R> {
data class Left<out L>(val value: L) : Either<L, Nothing>()
data class Right<out R>(val value: R) : Either<Nothing, R>()
fun isRight() = this is Right<R>
fun isLeft() = this is Left<L>
inline fun <C> fold(ifLeft: (L) -> C, ifRight: (R) -> C): C = when (this) {
is Right -> ifRight(value)
is Left -> ifLeft(value)
}
}
fun <L> left(a: L) = Either.Left(a)
fun <R> right(b: R) = Either.Right(b)
+49
View File
@@ -0,0 +1,49 @@
package prog8.code
import java.io.IOException
import java.nio.file.Path
import kotlin.io.path.absolute
const val INTERNED_STRINGS_MODULENAME = "prog8_interned_strings"
val PROG8_CONTAINER_MODULES = arrayOf(INTERNED_STRINGS_MODULENAME) // option to add more if needed one day
// all automatically generated labels everywhere need to have the same label name prefix:
const val GENERATED_LABEL_PREFIX = "p8_label_gen_"
/**
* Returns the absolute path of the given path,
* where links are replaced by the actual directories,
* and containing no redundant path elements.
* If the path doesn't refer to an existing directory or file on the file system,
* it is returned unchanged.
*/
fun Path.sanitize(): Path {
return try {
this.toRealPath().normalize()
} catch (_: java.nio.file.NoSuchFileException) {
this.absolute().normalize()
//throw NoSuchFileException(this.toFile(), null, nx.reason).also { it.initCause(nx) }
} catch (iox: IOException) {
throw FileSystemException(this.toFile()).also { it.initCause(iox) }
}
}
object SymbolNames {
/**
* Strips Prog8 symbol prefixes (p8b_, p8t_, p8s_, p8v_, p8l_, p8c_) from a scoped name.
* Example: "p8b_plane.p8t_Point" -> "plane.Point"
* Used to compare names across different contexts where prefixes may or may not be applied.
* See https://github.com/irmen/prog8/issues/198
*/
fun stripPrefixes(scopedName: String): String {
return scopedName.split('.').joinToString(".") { part ->
if (part.length > 4 && part.startsWith("p8") && part[2].isLetter() && part[3] == '_')
part.drop(4)
else part
}
}
}
-280
View File
@@ -1,280 +0,0 @@
package prog8.code
import prog8.code.ast.PtAsmSub
import prog8.code.ast.PtNode
import prog8.code.ast.PtProgram
import prog8.code.core.*
/**
* Tree structure containing all symbol definitions in the program
* (blocks, subroutines, variables (all types), memoryslabs, and labels).
*/
class SymbolTable(astProgram: PtProgram) : StNode(astProgram.name, StNodeType.GLOBAL, astProgram) {
/**
* The table as a flat mapping of scoped names to the StNode.
* This gives the fastest lookup possible (no need to traverse tree nodes)
*/
private var cachedFlat: Map<String, StNode>? = null
val flat: Map<String, StNode> get() {
if(cachedFlat!=null)
return cachedFlat!!
val result = mutableMapOf<String, StNode>()
fun collect(node: StNode) {
for(child in node.children) {
result[child.value.scopedName] = child.value
collect(child.value)
}
}
collect(this)
cachedFlat = result
return result
}
fun resetCachedFlat() {
cachedFlat = null
}
val allVariables: Collection<StStaticVariable> by lazy {
val vars = mutableListOf<StStaticVariable>()
fun collect(node: StNode) {
for(child in node.children) {
if(child.value.type== StNodeType.STATICVAR)
vars.add(child.value as StStaticVariable)
else
collect(child.value)
}
}
collect(this)
vars
}
val allMemMappedVariables: Collection<StMemVar> by lazy {
val vars = mutableListOf<StMemVar>()
fun collect(node: StNode) {
for(child in node.children) {
if(child.value.type== StNodeType.MEMVAR)
vars.add(child.value as StMemVar)
else
collect(child.value)
}
}
collect(this)
vars
}
val allMemorySlabs: Collection<StMemorySlab> by lazy {
val vars = mutableListOf<StMemorySlab>()
fun collect(node: StNode) {
for(child in node.children) {
if(child.value.type== StNodeType.MEMORYSLAB)
vars.add(child.value as StMemorySlab)
else
collect(child.value)
}
}
collect(this)
vars
}
override fun lookup(scopedName: String) = flat[scopedName]
fun getLength(name: String): Int? {
return when(val node = flat[name]) {
is StMemVar -> node.length
is StMemorySlab -> node.size.toInt()
is StStaticVariable -> node.length
else -> null
}
}
}
enum class StNodeType {
GLOBAL,
// MODULE, // not used with current scoping rules
BLOCK,
SUBROUTINE,
EXTSUB,
LABEL,
STATICVAR,
MEMVAR,
CONSTANT,
BUILTINFUNC,
MEMORYSLAB
}
open class StNode(val name: String,
val type: StNodeType,
val astNode: PtNode,
val children: MutableMap<String, StNode> = mutableMapOf()
) {
lateinit var parent: StNode
val scopedName: String by lazy { scopedNameList.joinToString(".") }
open fun lookup(scopedName: String) =
lookup(scopedName.split('.'))
fun lookupUnscopedOrElse(name: String, default: () -> StNode) =
lookupUnscoped(name) ?: default()
fun lookupOrElse(scopedName: String, default: () -> StNode): StNode =
lookup(scopedName.split('.')) ?: default()
fun lookupUnscoped(name: String): StNode? {
// first consider the builtin functions
var globalscope = this
while(globalscope.type!= StNodeType.GLOBAL)
globalscope = globalscope.parent
val globalNode = globalscope.children[name]
if(globalNode!=null && globalNode.type== StNodeType.BUILTINFUNC)
return globalNode
// search for the unqualified name in the current scope or its parent scopes
var scope=this
while(true) {
val node = scope.children[name]
if(node!=null)
return node
if(scope.type== StNodeType.GLOBAL)
return null
else
scope = scope.parent
}
}
fun add(child: StNode) {
children[child.name] = child
child.parent = this
}
private val scopedNameList: List<String> by lazy {
if(type==StNodeType.GLOBAL)
emptyList()
else
parent.scopedNameList + name
}
private fun lookup(scopedName: List<String>): StNode? {
// a scoped name refers to a name in another namespace, and always stars from the root.
var node = this
while(node.type!=StNodeType.GLOBAL)
node = node.parent
for(name in scopedName) {
if(name in node.children)
node = node.children.getValue(name)
else
return null
}
return node
}
}
class StStaticVariable(name: String,
val dt: DataType,
val initializationStringValue: StString?,
val initializationArrayValue: StArray?,
val length: Int?, // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte
val zpwish: ZeropageWish, // used in the variable allocator
val align: Int,
astNode: PtNode) : StNode(name, StNodeType.STATICVAR, astNode) {
var initializationNumericValue: Double? = null
private set
fun setOnetimeInitNumeric(number: Double) {
// In certain cases the init value of an existing var should be updated,
// so we can't ask this as a constructor parameter.
// This has to do with the way Prog8 does the (re)initialization of such variables: via code assignment statements.
// Certain codegens might want to put them back into the variable directly.
// For strings and arrays this doesn't occur - these are always already specced at creation time.
initializationNumericValue = number
}
val uninitialized: Boolean
get() = initializationArrayValue==null && initializationStringValue==null && initializationNumericValue==null
init {
if(length!=null) {
require(initializationNumericValue == null)
if(initializationArrayValue!=null)
require(initializationArrayValue.isEmpty() ||initializationArrayValue.size==length)
}
if(initializationNumericValue!=null) {
require(dt in NumericDatatypes || dt==DataType.BOOL)
}
if(initializationArrayValue!=null) {
require(dt in ArrayDatatypes)
require(length==initializationArrayValue.size)
}
if(initializationStringValue!=null) {
require(dt == DataType.STR)
require(length == initializationStringValue.first.length+1)
}
if(align > 0) {
require(dt == DataType.STR || dt in ArrayDatatypes)
require(zpwish != ZeropageWish.REQUIRE_ZEROPAGE && zpwish != ZeropageWish.PREFER_ZEROPAGE)
}
}
}
class StConstant(name: String, val dt: DataType, val value: Double, astNode: PtNode) :
StNode(name, StNodeType.CONSTANT, astNode)
class StMemVar(name: String,
val dt: DataType,
val address: UInt,
val length: Int?, // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte
astNode: PtNode) :
StNode(name, StNodeType.MEMVAR, astNode) {
init{
require(dt!=DataType.BOOL && dt!=DataType.ARRAY_BOOL)
if(dt in ArrayDatatypes || dt == DataType.STR)
requireNotNull(length)
}
}
class StMemorySlab(
name: String,
val size: UInt,
val align: UInt,
astNode: PtNode
):
StNode(name, StNodeType.MEMORYSLAB, astNode)
class StSub(name: String, val parameters: List<StSubroutineParameter>, val returnType: DataType?, astNode: PtNode) :
StNode(name, StNodeType.SUBROUTINE, astNode)
class StExtSub(name: String,
val address: PtAsmSub.Address?, // null in case of asmsub, specified in case of extsub.
val parameters: List<StExtSubParameter>,
val returns: List<StExtSubParameter>,
astNode: PtNode) :
StNode(name, StNodeType.EXTSUB, astNode)
class StSubroutineParameter(val name: String, val type: DataType)
class StExtSubParameter(val register: RegisterOrStatusflag, val type: DataType)
class StArrayElement(val number: Double?, val addressOfSymbol: String?, val boolean: Boolean?) {
init {
if(number!=null) require(addressOfSymbol==null && boolean==null)
if(addressOfSymbol!=null) require(number==null && boolean==null)
if(boolean!=null) require(addressOfSymbol==null && number==null)
}
}
typealias StString = Pair<String, Encoding>
typealias StArray = List<StArrayElement>
-212
View File
@@ -1,212 +0,0 @@
package prog8.code
import prog8.code.ast.*
import prog8.code.core.*
import prog8.code.target.VMTarget
class SymbolTableMaker(private val program: PtProgram, private val options: CompilationOptions) {
fun make(): SymbolTable {
val st = SymbolTable(program)
BuiltinFunctions.forEach {
st.add(StNode(it.key, StNodeType.BUILTINFUNC, PtIdentifier(it.key, it.value.returnType ?: DataType.UNDEFINED, Position.DUMMY)))
}
val scopestack = ArrayDeque<StNode>()
scopestack.add(st)
program.children.forEach {
addToSt(it, scopestack)
}
require(scopestack.size==1)
if(options.compTarget.name != VMTarget.NAME) {
listOf(
PtMemMapped("P8ZP_SCRATCH_B1", DataType.UBYTE, options.compTarget.machine.zeropage.SCRATCH_B1, null, Position.DUMMY),
PtMemMapped("P8ZP_SCRATCH_REG", DataType.UBYTE, options.compTarget.machine.zeropage.SCRATCH_REG, null, Position.DUMMY),
PtMemMapped("P8ZP_SCRATCH_W1", DataType.UWORD, options.compTarget.machine.zeropage.SCRATCH_W1, null, Position.DUMMY),
PtMemMapped("P8ZP_SCRATCH_W2", DataType.UWORD, options.compTarget.machine.zeropage.SCRATCH_W2, null, Position.DUMMY),
).forEach {
it.parent = program
st.add(StMemVar(it.name, it.type, it.address, it.arraySize?.toInt(), it))
}
}
return st
}
private fun addToSt(node: PtNode, scope: ArrayDeque<StNode>) {
val stNode = when(node) {
is PtAsmSub -> {
val parameters = node.parameters.map { StExtSubParameter(it.first, it.second.type) }
val returns = node.returns.map { StExtSubParameter(it.first, it.second) }
StExtSub(node.name, node.address, parameters, returns, node)
}
is PtBlock -> {
StNode(node.name, StNodeType.BLOCK, node)
}
is PtConstant -> {
StConstant(node.name, node.type, node.value, node)
}
is PtLabel -> {
StNode(node.name, StNodeType.LABEL, node)
}
is PtMemMapped -> {
StMemVar(node.name, node.type, node.address, node.arraySize?.toInt(), node)
}
is PtSub -> {
val params = node.parameters.map {StSubroutineParameter(it.name, it.type) }
StSub(node.name, params, node.returntype, node)
}
is PtVariable -> {
val initialNumeric: Double?
val initialString: StString?
val initialArray: StArray?
val numElements: Int?
val value = node.value
if(value!=null) {
when (value) {
is PtString -> {
initialString = StString(value.value, value.encoding)
initialArray = null
initialNumeric = null
numElements = value.value.length + 1 // include the terminating 0-byte
}
is PtArray -> {
initialArray = makeInitialArray(value)
initialString = null
initialNumeric = null
numElements = initialArray.size
require(node.arraySize?.toInt()==numElements)
}
else -> {
require(value is PtNumber)
initialString = null
initialArray = null
val number = value.number
initialNumeric = number
numElements = node.arraySize?.toInt()
}
}
} else {
initialNumeric = null
initialArray = null
initialString = null
numElements = node.arraySize?.toInt()
}
// if(node.type in SplitWordArrayTypes) {
// ... split array also add _lsb and _msb to symboltable?
// }
val stVar = StStaticVariable(node.name, node.type, initialString, initialArray, numElements, node.zeropage, node.align.toInt(), node)
if(initialNumeric!=null)
stVar.setOnetimeInitNumeric(initialNumeric)
stVar
}
is PtBuiltinFunctionCall -> {
if(node.name=="memory") {
// memory slab allocations are a builtin functioncall in the program, but end up named as well in the symboltable
require(node.name.all { it.isLetterOrDigit() || it=='_' }) {"memory name should be a valid symbol name"}
val slabname = (node.args[0] as PtString).value
val size = (node.args[1] as PtNumber).number.toUInt()
val align = (node.args[2] as PtNumber).number.toUInt()
// don't add memory slabs in nested scope, just put them in the top level of the ST
scope.first().add(StMemorySlab("prog8_memoryslab_$slabname", size, align, node))
}
null
}
else -> null // node is not present in the ST
}
if(stNode!=null) {
scope.last().add(stNode)
scope.add(stNode)
}
node.children.forEach {
addToSt(it, scope)
}
if(stNode!=null)
scope.removeLast()
}
private fun makeInitialArray(value: PtArray): List<StArrayElement> {
return value.children.map {
when(it) {
is PtAddressOf -> {
if(it.isFromArrayElement)
TODO("address-of array element $it in initial array value")
StArrayElement(null, it.identifier.name, null)
}
is PtNumber -> StArrayElement(it.number, null, null)
is PtBool -> StArrayElement(null, null, it.value)
else -> throw AssemblyError("invalid array element $it")
}
}
}
}
// override fun visit(decl: VarDecl) {
// val node =
// when(decl.type) {
// VarDeclType.VAR -> {
// var initialNumeric = (decl.value as? NumericLiteral)?.number
// if(initialNumeric==0.0)
// initialNumeric=null // variable will go into BSS and this will be set to 0
// val initialStringLit = decl.value as? StringLiteral
// val initialString = if(initialStringLit==null) null else Pair(initialStringLit.value, initialStringLit.encoding)
// val initialArrayLit = decl.value as? ArrayLiteral
// val initialArray = makeInitialArray(initialArrayLit)
// if(decl.isArray && decl.datatype !in ArrayDatatypes)
// throw FatalAstException("array vardecl has mismatched dt ${decl.datatype}")
// val numElements =
// if(decl.isArray)
// decl.arraysize!!.constIndex()
// else if(initialStringLit!=null)
// initialStringLit.value.length+1 // include the terminating 0-byte
// else
// null
// val bss = if(decl.datatype==DataType.STR)
// false
// else if(decl.isArray)
// initialArray.isNullOrEmpty()
// else
// initialNumeric == null
// val astNode = PtVariable(decl.name, decl.datatype, null, null, decl.position)
// StStaticVariable(decl.name, decl.datatype, bss, initialNumeric, initialString, initialArray, numElements, decl.zeropage, astNode, decl.position)
// }
// VarDeclType.CONST -> {
// val astNode = PtVariable(decl.name, decl.datatype, null, null, decl.position)
// StConstant(decl.name, decl.datatype, (decl.value as NumericLiteral).number, astNode, decl.position)
// }
// VarDeclType.MEMORY -> {
// val numElements =
// if(decl.isArray)
// decl.arraysize!!.constIndex()
// else null
// val astNode = PtVariable(decl.name, decl.datatype, null, null, decl.position)
// StMemVar(decl.name, decl.datatype, (decl.value as NumericLiteral).number.toUInt(), numElements, astNode, decl.position)
// }
// }
// scopestack.peek().add(node)
// // st.origAstLinks[decl] = node
// }
//
// private fun makeInitialArray(arrayLit: ArrayLiteral?): StArray? {
// if(arrayLit==null)
// return null
// return arrayLit.value.map {
// when(it){
// is AddressOf -> {
// val scopedName = it.identifier.targetNameAndType(program).first
// StArrayElement(null, scopedName)
// }
// is IdentifierReference -> {
// val scopedName = it.targetNameAndType(program).first
// StArrayElement(null, scopedName)
// }
// is NumericLiteral -> StArrayElement(it.number, null)
// else -> throw FatalAstException("weird element dt in array literal")
// }
// }.toList()
// }
//
@@ -0,0 +1,187 @@
package prog8.code.assembly
import prog8.code.GENERATED_LABEL_PREFIX
import prog8.code.core.*
import prog8.code.target.C128Target
import prog8.code.target.C64Target
import prog8.code.target.PETTarget
import java.nio.file.Path
class AssemblyProgram6502(
override val name: String,
private val options: CompilationOptions,
private val compTarget: ICompilationTarget) : IAssemblyProgram {
override val irInstructionCount: Int = 0
override val irChunkCount: Int = 0
override val irRegisterCount: Int = 0
override fun assemble(options: CompilationOptions, errors: IErrorReporter): Boolean {
val assemblerCommand: List<String>
val outs = OutputFiles.of(options, name)
fun addRemainingOptions(command: MutableList<String>, program: Path, assembly: Path): List<String> {
// keep additionalAssemblerOptions BEFORE --output: a target config may contain its own --output
if(options.compTarget.additionalAssemblerOptions.isNotEmpty())
command.addAll(options.compTarget.additionalAssemblerOptions)
command.addAll(listOf("--output", program.toString(), assembly.toString()))
return command
}
when(options.output) {
OutputType.PRG -> {
// CBM machines .prg generation.
val command = mutableListOf("64tass", "--cbm-prg", "--ascii", "--case-sensitive", "--long-branch",
"-Wall", "-Wno-implied-reg", "--no-monitor", "--dump-labels", "--vice-labels", "--labels=${outs.viceMonList()}")
if(options.warnSymbolShadowing)
command.add("-Wshadow")
else
command.add("-Wno-shadow")
if(options.asmQuiet)
command.add("--quiet")
if(options.asmListfile) {
command.add("--list=${outs.list()}")
}
assemblerCommand = addRemainingOptions(command, outs.programFile, outs.asm())
if(!options.quiet)
println("\nCreating prg for target ${compTarget.name}.")
}
OutputType.XEX -> {
// Atari800XL .xex generation.
val command = mutableListOf("64tass", "--atari-xex", "--case-sensitive", "--long-branch",
"-Wall", "-Wno-implied-reg", "--no-monitor", "--dump-labels", "--vice-labels", "--labels=${outs.viceMonList()}")
if(options.warnSymbolShadowing)
command.add("-Wshadow")
else
command.add("-Wno-shadow")
if(options.asmQuiet)
command.add("--quiet")
if(options.asmListfile)
command.add("--list=${outs.list()}")
assemblerCommand = addRemainingOptions(command, outs.programFile, outs.asm())
if(!options.quiet)
println("\nCreating xex for target ${compTarget.name}.")
}
OutputType.RAW -> {
// Neo6502/headerless raw program generation.
val command = mutableListOf("64tass", "--nostart", "--case-sensitive", "--long-branch",
"-Wall", "-Wno-implied-reg", "--no-monitor", "--dump-labels", "--vice-labels", "--labels=${outs.viceMonList()}")
if(options.warnSymbolShadowing)
command.add("-Wshadow")
else
command.add("-Wno-shadow")
if(options.asmQuiet)
command.add("--quiet")
if(options.asmListfile)
command.add("--list=${outs.list()}")
assemblerCommand = addRemainingOptions(command, outs.programFile, outs.asm())
if(!options.quiet)
println("\nCreating raw binary for target ${compTarget.name}.")
}
OutputType.LIBRARY -> {
// CBM machines library (.bin) generation (with or without 2 byte load address header depending on the compilation target machine)
val command = mutableListOf("64tass", "--ascii", "--case-sensitive", "--long-branch",
"-Wall", "-Wno-implied-reg", "--no-monitor", "--dump-labels", "--vice-labels", "--labels=${outs.viceMonList()}")
if(options.warnSymbolShadowing)
command.add("-Wshadow")
else
command.add("-Wno-shadow")
if(options.asmQuiet)
command.add("--quiet")
if(options.asmListfile)
command.add("--list=${outs.list()}")
if(compTarget.name in listOf(C64Target.NAME, C128Target.NAME, PETTarget.NAME)) {
if(!options.quiet)
println("\nCreating binary library file with header for target ${compTarget.name}.")
command.add("--cbm-prg")
} else {
if(!options.quiet)
println("\nCreating binary library file without header for target ${compTarget.name}.")
command.add("--nostart") // should be headerless bin, because basic has problems doing a normal LOAD"lib",8,1 - need to use BLOAD
}
assemblerCommand = addRemainingOptions(command, outs.programFile, outs.asm())
}
else -> error("Unsupported output type: ${compTarget.defaultOutputType}")
}
val proc = ProcessBuilder(assemblerCommand)
.redirectErrorStream(true)
if (options.quiet) {
proc.redirectOutput(ProcessBuilder.Redirect.DISCARD)
}
val process = try {
proc.start()
} catch (e: Exception) {
System.err.println("daemon: assembler failed to start: ${e.message}")
return false
}
if (!options.quiet) {
process.inputStream.bufferedReader().use { reader ->
reader.forEachLine {
println(it)
}
}
}
val result = process.waitFor()
if (result == 0) {
removeGeneratedLabelsFromMonlist(outs)
generateBreakpointList(outs)
}
return result==0
}
private fun removeGeneratedLabelsFromMonlist(outs: OutputFiles) {
val pattern = Regex("""al (\w+) \S+$GENERATED_LABEL_PREFIX.+?""")
val lines = outs.viceMonList().toFile().readLines()
outs.viceMonList().toFile().outputStream().bufferedWriter().use {
for (line in lines) {
if(pattern.matchEntire(line)==null)
it.write(line+"\n")
}
}
}
private fun generateBreakpointList(outs: OutputFiles) {
// builds list of breakpoints, appends to monitor list file
val breakpoints = mutableListOf<String>()
val pattern = Regex("""al (\w+) \S+_prog8_breakpoint_\d+.?""") // gather breakpoints by the source label that's generated for them
for (line in outs.viceMonList().toFile().readLines()) {
val match = pattern.matchEntire(line)
if (match != null)
breakpoints.add("break $" + match.groupValues[1])
}
val num = breakpoints.size
breakpoints.add(0, "; breakpoint list now follows")
breakpoints.add(1, "; $num breakpoints have been defined")
breakpoints.add(2, "del")
outs.viceMonList().toFile().appendText(breakpoints.joinToString("\n") + "\n")
}
}
@@ -0,0 +1,12 @@
package prog8.code.assembly
import prog8.code.core.CompilationOptions
import prog8.code.core.IErrorReporter
interface IAssemblyProgram {
val name: String
val irInstructionCount: Int
val irChunkCount: Int
val irRegisterCount: Int
fun assemble(options: CompilationOptions, errors: IErrorReporter): Boolean
}
-129
View File
@@ -1,129 +0,0 @@
package prog8.code.ast
import prog8.code.core.IMemSizer
import prog8.code.core.IStringEncoding
import prog8.code.core.Position
import prog8.code.core.SourceCode
import java.nio.file.Path
// New simplified AST for the code generator.
sealed class PtNode(val position: Position) {
val children = mutableListOf<PtNode>()
lateinit var parent: PtNode
fun add(child: PtNode) {
children.add(child)
child.parent = this
}
fun add(index: Int, child: PtNode) {
children.add(index, child)
child.parent = this
}
fun definingBlock() = findParentNode<PtBlock>(this)
fun definingSub() = findParentNode<PtSub>(this)
fun definingAsmSub() = findParentNode<PtAsmSub>(this)
fun definingISub() = findParentNode<IPtSubroutine>(this)
}
sealed interface IPtStatementContainer
class PtNodeGroup : PtNode(Position.DUMMY), IPtStatementContainer
sealed class PtNamedNode(var name: String, position: Position): PtNode(position) {
// Note that as an exception, the 'name' is not read-only
// but a var. This is to allow for cheap node renames.
val scopedName: String
get() {
var namedParent: PtNode = this.parent
return if(namedParent is PtProgram)
name
else {
while (namedParent !is PtNamedNode)
namedParent = namedParent.parent
namedParent.scopedName + "." + name
}
}
}
class PtProgram(
val name: String,
val memsizer: IMemSizer,
val encoding: IStringEncoding
) : PtNode(Position.DUMMY) {
// fun allModuleDirectives(): Sequence<PtDirective> =
// children.asSequence().flatMap { it.children }.filterIsInstance<PtDirective>().distinct()
fun allBlocks(): Sequence<PtBlock> =
children.asSequence().filterIsInstance<PtBlock>()
fun entrypoint(): PtSub? =
// returns the main.start subroutine if it exists
allBlocks().firstOrNull { it.name == "main" || it.name=="p8b_main" }
?.children
?.firstOrNull { it is PtSub && (it.name == "start" || it.name=="main.start" || it.name=="p8s_start" || it.name=="p8b_main.p8s_start") } as PtSub?
}
class PtBlock(name: String,
val library: Boolean,
val source: SourceCode, // taken from the module the block is defined in.
val options: Options,
position: Position
) : PtNamedNode(name, position), IPtStatementContainer {
class Options(val address: UInt? = null,
val forceOutput: Boolean = false,
val noSymbolPrefixing: Boolean = false,
val veraFxMuls: Boolean = false,
val ignoreUnused: Boolean = false)
}
class PtInlineAssembly(val assembly: String, val isIR: Boolean, position: Position) : PtNode(position) {
init {
require(!assembly.startsWith('\n') && !assembly.startsWith('\r')) { "inline assembly should be trimmed" }
require(!assembly.endsWith('\n') && !assembly.endsWith('\r')) { "inline assembly should be trimmed" }
}
}
class PtLabel(name: String, position: Position) : PtNamedNode(name, position) {
companion object {
// all automatically generated labels everywhere need to have the same label name prefix:
const val GeneratedLabelPrefix = "p8_label_gen_"
}
}
class PtBreakpoint(position: Position): PtNode(position)
class PtAlign(val align: UInt, position: Position): PtNode(position)
class PtIncludeBinary(val file: Path, val offset: UInt?, val length: UInt?, position: Position) : PtNode(position)
class PtNop(position: Position): PtNode(position)
// find the parent node of a specific type or interface
// (useful to figure out in what namespace/block something is defined, etc.)
inline fun <reified T> findParentNode(node: PtNode): T? {
var candidate = node.parent
while(candidate !is T && candidate !is PtProgram)
candidate = candidate.parent
return if(candidate is PtProgram)
null
else
candidate as T
}
@@ -1,380 +0,0 @@
package prog8.code.ast
import prog8.code.core.*
import java.util.Objects
import kotlin.math.abs
import kotlin.math.truncate
sealed class PtExpression(val type: DataType, position: Position) : PtNode(position) {
init {
if(type==DataType.UNDEFINED) {
@Suppress("LeakingThis")
when(this) {
is PtBuiltinFunctionCall -> { /* void function call */ }
is PtFunctionCall -> { /* void function call */ }
is PtIdentifier -> { /* non-variable identifier */ }
else -> throw IllegalArgumentException("type should be known @$position")
}
}
}
infix fun isSameAs(other: PtExpression): Boolean {
return when(this) {
is PtAddressOf -> {
if(other !is PtAddressOf)
return false
if (other.type!==type || !(other.identifier isSameAs identifier))
return false
if(other.children.size!=children.size)
return false
if(children.size==1)
return true
return arrayIndexExpr!! isSameAs other.arrayIndexExpr!!
}
is PtArrayIndexer -> other is PtArrayIndexer && other.type==type && other.variable isSameAs variable && other.index isSameAs index && other.splitWords==splitWords
is PtBinaryExpression -> {
if(other !is PtBinaryExpression || other.operator!=operator)
false
else if(operator in AssociativeOperators)
(other.left isSameAs left && other.right isSameAs right) || (other.left isSameAs right && other.right isSameAs left)
else
other.left isSameAs left && other.right isSameAs right
}
is PtContainmentCheck -> {
if(other !is PtContainmentCheck || other.type != type || !(other.needle isSameAs needle))
false
else {
if(haystackHeapVar!=null)
other.haystackHeapVar!=null && other.haystackHeapVar!! isSameAs haystackHeapVar!!
else if(haystackValues!=null)
other.haystackValues!=null && other.haystackValues!! isSameAs haystackValues!!
else
false
}
}
is PtIdentifier -> other is PtIdentifier && other.type==type && other.name==name
is PtIrRegister -> other is PtIrRegister && other.type==type && other.register==register
is PtMemoryByte -> other is PtMemoryByte && other.address isSameAs address
is PtNumber -> other is PtNumber && other.type==type && other.number==number
is PtBool -> other is PtBool && other.value==value
is PtPrefix -> other is PtPrefix && other.type==type && other.operator==operator && other.value isSameAs value
is PtRange -> other is PtRange && other.type==type && other.from==from && other.to==to && other.step==step
is PtTypeCast -> other is PtTypeCast && other.type==type && other.value isSameAs value
else -> false
}
}
infix fun isSameAs(target: PtAssignTarget): Boolean {
return when {
target.memory != null && this is PtMemoryByte-> {
target.memory!!.address isSameAs this.address
}
target.identifier != null && this is PtIdentifier -> {
this.name == target.identifier!!.name
}
target.array != null && this is PtArrayIndexer -> {
this.variable.name == target.array!!.variable.name && this.index isSameAs target.array!!.index && this.splitWords==target.array!!.splitWords
}
else -> false
}
}
fun asConstInteger(): Int? = (this as? PtNumber)?.number?.toInt() ?: (this as? PtBool)?.asInt()
fun asConstValue(): Double? = (this as? PtNumber)?.number ?: (this as? PtBool)?.asInt()?.toDouble()
fun isSimple(): Boolean {
return when(this) {
is PtAddressOf -> this.arrayIndexExpr==null || this.arrayIndexExpr?.isSimple()==true
is PtArray -> true
is PtArrayIndexer -> index is PtNumber || index is PtIdentifier
is PtBinaryExpression -> false
is PtBuiltinFunctionCall -> {
when (name) {
in arrayOf("msb", "lsb", "mkword", "set_carry", "set_irqd", "clear_carry", "clear_irqd") -> this.args.all { it.isSimple() }
else -> false
}
}
is PtContainmentCheck -> false
is PtFunctionCall -> false
is PtIdentifier -> true
is PtIrRegister -> true
is PtMemoryByte -> address is PtNumber || address is PtIdentifier
is PtBool -> true
is PtNumber -> true
is PtPrefix -> value.isSimple()
is PtRange -> true
is PtString -> true
is PtTypeCast -> value.isSimple()
is PtIfExpression -> condition.isSimple() && truevalue.isSimple() && falsevalue.isSimple()
}
}
/*
fun clone(): PtExpression {
fun withClonedChildrenFrom(orig: PtExpression, clone: PtExpression): PtExpression {
orig.children.forEach { clone.add((it as PtExpression).clone()) }
return clone
}
when(this) {
is PtAddressOf -> return withClonedChildrenFrom(this, PtAddressOf(position))
is PtArray -> return withClonedChildrenFrom(this, PtArray(type, position))
is PtArrayIndexer -> return withClonedChildrenFrom(this, PtArrayIndexer(type, position))
is PtBinaryExpression -> return withClonedChildrenFrom(this, PtBinaryExpression(operator, type, position))
is PtBuiltinFunctionCall -> return withClonedChildrenFrom(this, PtBuiltinFunctionCall(name, void, hasNoSideEffects, type, position))
is PtContainmentCheck -> return withClonedChildrenFrom(this, PtContainmentCheck(position))
is PtFunctionCall -> return withClonedChildrenFrom(this, PtFunctionCall(name, void, type, position))
is PtIdentifier -> return withClonedChildrenFrom(this, PtIdentifier(name, type, position))
is PtMachineRegister -> return withClonedChildrenFrom(this, PtMachineRegister(register, type, position))
is PtMemoryByte -> return withClonedChildrenFrom(this, PtMemoryByte(position))
is PtNumber -> return withClonedChildrenFrom(this, PtNumber(type, number, position))
is PtBool -> return withClonedChildrenFrom(this, PtBool(value, position))
is PtPrefix -> return withClonedChildrenFrom(this, PtPrefix(operator, type, position))
is PtRange -> return withClonedChildrenFrom(this, PtRange(type, position))
is PtString -> return withClonedChildrenFrom(this, PtString(value, encoding, position))
is PtTypeCast -> return withClonedChildrenFrom(this, PtTypeCast(type, position))
}
}
*/
}
class PtAddressOf(position: Position) : PtExpression(DataType.UWORD, position) {
val identifier: PtIdentifier
get() = children[0] as PtIdentifier
val arrayIndexExpr: PtExpression?
get() = if(children.size==2) children[1] as PtExpression else null
val isFromArrayElement: Boolean
get() = children.size==2
}
class PtArrayIndexer(elementType: DataType, position: Position): PtExpression(elementType, position) {
val variable: PtIdentifier
get() = children[0] as PtIdentifier
val index: PtExpression
get() = children[1] as PtExpression
val splitWords: Boolean
get() = variable.type in SplitWordArrayTypes
init {
require(elementType in NumericDatatypesWithBoolean)
}
}
class PtArray(type: DataType, position: Position): PtExpression(type, position) {
// children are always one of 3 types: PtBool, PtNumber or PtAddressOf.
override fun hashCode(): Int = Objects.hash(children, type)
override fun equals(other: Any?): Boolean {
if(other==null || other !is PtArray)
return false
return type==other.type && children == other.children
}
val size: Int
get() = children.size
}
class PtBuiltinFunctionCall(val name: String,
val void: Boolean,
val hasNoSideEffects: Boolean,
type: DataType,
position: Position) : PtExpression(type, position) {
init {
if(!void)
require(type!=DataType.UNDEFINED)
}
val args: List<PtExpression>
get() = children.map { it as PtExpression }
}
class PtBinaryExpression(val operator: String, type: DataType, position: Position): PtExpression(type, position) {
val left: PtExpression
get() = children[0] as PtExpression
val right: PtExpression
get() = children[1] as PtExpression
init {
if(operator in ComparisonOperators + LogicalOperators)
require(type==DataType.BOOL)
else
require(type!=DataType.BOOL) { "no bool allowed for this operator $operator"}
}
}
class PtIfExpression(type: DataType, position: Position): PtExpression(type, position) {
val condition: PtExpression
get() = children[0] as PtExpression
val truevalue: PtExpression
get() = children[1] as PtExpression
val falsevalue: PtExpression
get() = children[2] as PtExpression
}
class PtContainmentCheck(position: Position): PtExpression(DataType.BOOL, position) {
val needle: PtExpression
get() = children[0] as PtExpression
val haystackHeapVar: PtIdentifier?
get() = children[1] as? PtIdentifier
val haystackValues: PtArray?
get() = children[1] as? PtArray
companion object {
val MAX_SIZE_FOR_INLINE_CHECKS_BYTE = 5
val MAX_SIZE_FOR_INLINE_CHECKS_WORD = 4
}
}
class PtFunctionCall(val name: String,
val void: Boolean,
type: DataType,
position: Position) : PtExpression(type, position) {
val args: List<PtExpression>
get() = children.map { it as PtExpression }
init {
if(void) require(type==DataType.UNDEFINED) {
"void fcall should have undefined datatype"
}
// note: non-void calls can have UNDEFINED type: is if they return more than 1 value
}
}
class PtIdentifier(val name: String, type: DataType, position: Position) : PtExpression(type, position) {
override fun toString(): String {
return "[PtIdentifier:$name $type $position]"
}
fun copy() = PtIdentifier(name, type, position)
}
class PtMemoryByte(position: Position) : PtExpression(DataType.UBYTE, position) {
val address: PtExpression
get() = children.single() as PtExpression
}
class PtBool(val value: Boolean, position: Position) : PtExpression(DataType.BOOL, position) {
override fun hashCode(): Int = Objects.hash(type, value)
override fun equals(other: Any?): Boolean {
if(other==null || other !is PtBool)
return false
return value==other.value
}
override fun toString() = "PtBool:$value"
fun asInt(): Int = if(value) 1 else 0
}
class PtNumber(type: DataType, val number: Double, position: Position) : PtExpression(type, position) {
companion object {
fun fromBoolean(bool: Boolean, position: Position): PtNumber =
PtNumber(DataType.UBYTE, if(bool) 1.0 else 0.0, position)
}
init {
if(type==DataType.BOOL)
throw IllegalArgumentException("use PtBool instead")
if(type!=DataType.FLOAT) {
val trunc = truncate(number)
if (trunc != number)
throw IllegalArgumentException("refused truncating of float to avoid loss of precision @$position")
}
}
override fun hashCode(): Int = Objects.hash(type, number)
override fun equals(other: Any?): Boolean {
return if(other==null || other !is PtNumber)
false
else if(type!=DataType.BOOL && other.type!=DataType.BOOL)
number==other.number
else
type==other.type && number==other.number
}
operator fun compareTo(other: PtNumber): Int = number.compareTo(other.number)
override fun toString() = "PtNumber:$type:$number"
}
class PtPrefix(val operator: String, type: DataType, position: Position): PtExpression(type, position) {
val value: PtExpression
get() = children.single() as PtExpression
init {
require(operator in setOf("+", "-", "~", "not")) { "invalid prefix operator: $operator" }
}
}
class PtRange(type: DataType, position: Position) : PtExpression(type, position) {
val from: PtExpression
get() = children[0] as PtExpression
val to: PtExpression
get() = children[1] as PtExpression
val step: PtNumber
get() = children[2] as PtNumber
fun toConstantIntegerRange(): IntProgression? {
fun makeRange(fromVal: Int, toVal: Int, stepVal: Int): IntProgression {
return when {
fromVal == toVal -> fromVal .. toVal
fromVal <= toVal -> when {
stepVal <= 0 -> IntRange.EMPTY
stepVal == 1 -> fromVal..toVal
else -> fromVal..toVal step stepVal
}
else -> when {
stepVal >= 0 -> IntRange.EMPTY
stepVal == -1 -> fromVal downTo toVal
else -> fromVal downTo toVal step abs(stepVal)
}
}
}
val fromLv = from as? PtNumber
val toLv = to as? PtNumber
if(fromLv==null || toLv==null)
return null
val fromVal = fromLv.number.toInt()
val toVal = toLv.number.toInt()
val stepVal = step.number.toInt()
return makeRange(fromVal, toVal, stepVal)
}
}
class PtString(val value: String, val encoding: Encoding, position: Position) : PtExpression(DataType.STR, position) {
override fun hashCode(): Int = Objects.hash(value, encoding)
override fun equals(other: Any?): Boolean {
if(other==null || other !is PtString)
return false
return value==other.value && encoding == other.encoding
}
}
class PtTypeCast(type: DataType, position: Position) : PtExpression(type, position) {
val value: PtExpression
get() = children.single() as PtExpression
}
// special node that isn't created from compiling user code, but used internally in the Intermediate Code
class PtIrRegister(val register: Int, type: DataType, position: Position) : PtExpression(type, position)
@@ -1,196 +0,0 @@
package prog8.code.ast
import prog8.code.core.*
sealed interface IPtSubroutine {
val name: String
val scopedName: String
}
class PtAsmSub(
name: String,
val address: Address?,
val clobbers: Set<CpuRegister>,
val parameters: List<Pair<RegisterOrStatusflag, PtSubroutineParameter>>,
val returns: List<Pair<RegisterOrStatusflag, DataType>>,
val inline: Boolean,
position: Position
) : PtNamedNode(name, position), IPtSubroutine {
class Address(val constbank: UByte?, var varbank: PtIdentifier?, val address: UInt)
}
class PtSub(
name: String,
val parameters: List<PtSubroutineParameter>,
val returntype: DataType?,
position: Position
) : PtNamedNode(name, position), IPtSubroutine, IPtStatementContainer {
init {
// params and return value should not be str
if(parameters.any{ it.type !in NumericDatatypes && it.type!=DataType.BOOL })
throw AssemblyError("non-numeric/non-bool parameter")
if(returntype!=null && returntype !in NumericDatatypes && returntype!=DataType.BOOL)
throw AssemblyError("non-numeric/non-bool returntype $returntype")
parameters.forEach { it.parent=this }
}
}
class PtSubroutineParameter(name: String, val type: DataType, position: Position): PtNamedNode(name, position)
sealed interface IPtAssignment {
val children: MutableList<PtNode>
val target: PtAssignTarget
get() {
if(children.size==2)
return children[0] as PtAssignTarget
else if(children.size<2)
throw AssemblyError("incomplete node")
else
throw AssemblyError("no singular target")
}
val value: PtExpression
get() = children.last() as PtExpression
val multiTarget: Boolean
get() = children.size>2
}
class PtAssignment(position: Position) : PtNode(position), IPtAssignment
class PtAugmentedAssign(val operator: String, position: Position) : PtNode(position), IPtAssignment
class PtAssignTarget(val void: Boolean, position: Position) : PtNode(position) {
val identifier: PtIdentifier?
get() = children.single() as? PtIdentifier
val array: PtArrayIndexer?
get() = children.single() as? PtArrayIndexer
val memory: PtMemoryByte?
get() = children.single() as? PtMemoryByte
val type: DataType
get() {
return when(val tgt = children.single()) {
is PtIdentifier -> tgt.type
is PtArrayIndexer -> tgt.type
is PtMemoryByte -> tgt.type
else -> throw AssemblyError("weird target $tgt")
}
}
infix fun isSameAs(expression: PtExpression): Boolean = !void && expression.isSameAs(this)
}
class PtConditionalBranch(val condition: BranchCondition, position: Position) : PtNode(position) {
val trueScope: PtNodeGroup
get() = children[0] as PtNodeGroup
val falseScope: PtNodeGroup
get() = children[1] as PtNodeGroup
}
class PtForLoop(position: Position) : PtNode(position) {
val variable: PtIdentifier
get() = children[0] as PtIdentifier
val iterable: PtExpression
get() = children[1] as PtExpression
val statements: PtNodeGroup
get() = children[2] as PtNodeGroup
}
class PtIfElse(position: Position) : PtNode(position) {
val condition: PtExpression
get() = children[0] as PtExpression
val ifScope: PtNodeGroup
get() = children[1] as PtNodeGroup
val elseScope: PtNodeGroup
get() = children[2] as PtNodeGroup
fun hasElse(): Boolean = children.size==3 && elseScope.children.isNotEmpty()
}
class PtJump(val identifier: PtIdentifier?, // note: even ad-hoc labels are wrapped as an Identifier to simplify code. Just use dummy type and position.
val address: UInt?,
position: Position) : PtNode(position) {
init {
identifier?.let {it.parent = this }
}
}
class PtRepeatLoop(position: Position) : PtNode(position) {
val count: PtExpression
get() = children[0] as PtExpression
val statements: PtNodeGroup
get() = children[1] as PtNodeGroup
}
class PtReturn(position: Position) : PtNode(position) {
val hasValue: Boolean
get() = children.any()
val value: PtExpression?
get() {
return if(children.any())
children.single() as PtExpression
else
null
}
}
sealed interface IPtVariable {
val name: String
val type: DataType
}
class PtVariable(
name: String,
override val type: DataType,
val zeropage: ZeropageWish,
val align: UInt,
val value: PtExpression?,
val arraySize: UInt?,
position: Position
) : PtNamedNode(name, position), IPtVariable {
init {
value?.let {it.parent=this}
}
}
class PtConstant(name: String, override val type: DataType, val value: Double, position: Position) : PtNamedNode(name, position), IPtVariable
class PtMemMapped(name: String, override val type: DataType, val address: UInt, val arraySize: UInt?, position: Position) : PtNamedNode(name, position), IPtVariable {
init {
require(type!=DataType.BOOL && type!=DataType.ARRAY_BOOL)
}
}
class PtWhen(position: Position) : PtNode(position) {
val value: PtExpression
get() = children[0] as PtExpression
val choices: PtNodeGroup
get() = children[1] as PtNodeGroup
}
class PtWhenChoice(val isElse: Boolean, position: Position) : PtNode(position) {
val values: PtNodeGroup
get() = children[0] as PtNodeGroup
val statements: PtNodeGroup
get() = children[1] as PtNodeGroup
}
class PtDefer(position: Position): PtNode(position), IPtStatementContainer
-16
View File
@@ -1,16 +0,0 @@
package prog8.code.ast
import prog8.code.SymbolTable
import prog8.code.core.*
fun verifyFinalAstBeforeAsmGen(program: PtProgram, options: CompilationOptions, st: SymbolTable, errors: IErrorReporter) {
/*
walkAst(program) { node, _ ->
if(node is PtVariable) {
if(node.value!=null) {
// require(node.type in ArrayDatatypes || node.type==DataType.STR) { "final check before asmgen: only string and array variables can still have an init value ${node.name} ${node.type} ${node.position}"}
}
}
}
*/
}
+151 -90
View File
@@ -1,7 +1,7 @@
package prog8.code.core
class ReturnConvention(val dt: DataType?, val reg: RegisterOrPair?, val floatFac1: Boolean)
class ParamConvention(val dt: DataType, val reg: RegisterOrPair?, val variable: Boolean)
class ReturnConvention(val dt: BaseDataType?, val reg: RegisterOrPair?)
class ParamConvention(val dt: BaseDataType, val reg: RegisterOrPair?, val variable: Boolean)
class CallConvention(val params: List<ParamConvention>, val returns: ReturnConvention) {
override fun toString(): String {
val paramConvs = params.mapIndexed { index, it ->
@@ -13,55 +13,80 @@ class CallConvention(val params: List<ParamConvention>, val returns: ReturnConve
}
val returnConv =
when {
returns.reg!=null -> returns.reg.toString()
returns.floatFac1 -> "floatFAC1"
returns.reg == RegisterOrPair.FAC1 -> "floatFAC1"
returns.reg != null -> returns.reg.toString()
else -> "<no returnvalue>"
}
return "CallConvention[" + paramConvs.joinToString() + " ; returns: $returnConv]"
}
}
class FParam(val name: String, val possibleDatatypes: Array<DataType>)
class FParam(val name: String, vararg val possibleDatatypes: BaseDataType)
private val IterableDatatypes = arrayOf(BaseDataType.STR, BaseDataType.ARRAY, BaseDataType.ARRAY_SPLITW)
private val IntegerDatatypes = arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)
private val NumericDatatypes = arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG, BaseDataType.FLOAT)
class FSignature(val pure: Boolean, // does it have side effects?
val parameters: List<FParam>,
val returnType: DataType?) {
val returnTypes: Array<BaseDataType>,
vararg val parameters: FParam) {
fun callConvention(actualParamTypes: List<DataType>): CallConvention {
val returns: ReturnConvention = when (returnType) {
DataType.UBYTE, DataType.BYTE -> ReturnConvention(returnType, RegisterOrPair.A, false)
DataType.UWORD, DataType.WORD -> ReturnConvention(returnType, RegisterOrPair.AY, false)
DataType.FLOAT -> ReturnConvention(returnType, null, true)
in PassByReferenceDatatypes -> ReturnConvention(returnType!!, RegisterOrPair.AY, false)
null -> ReturnConvention(null, null, false)
else -> {
// return type depends on arg type
when (val paramType = actualParamTypes.first()) {
DataType.UBYTE, DataType.BYTE -> ReturnConvention(paramType, RegisterOrPair.A, false)
DataType.UWORD, DataType.WORD -> ReturnConvention(paramType, RegisterOrPair.AY, false)
DataType.FLOAT -> ReturnConvention(paramType, null, true)
in PassByReferenceDatatypes -> ReturnConvention(paramType, RegisterOrPair.AY, false)
else -> ReturnConvention(paramType, null, false)
fun callConventionFor6502(actualParamTypes: List<BaseDataType>): CallConvention {
val returns: ReturnConvention
if(returnTypes.isEmpty())
returns = ReturnConvention(null, null)
else if(returnTypes.size==1) {
val returnType = returnTypes[0]
returns = when (returnType) {
BaseDataType.UBYTE, BaseDataType.BYTE -> ReturnConvention(returnType, RegisterOrPair.A)
BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.POINTER -> ReturnConvention(returnType, RegisterOrPair.AY)
BaseDataType.LONG -> ReturnConvention(returnType, RegisterOrPair.R14R15)
BaseDataType.FLOAT -> ReturnConvention(returnType, RegisterOrPair.FAC1)
in IterableDatatypes -> ReturnConvention(returnType, RegisterOrPair.AY)
else -> {
// return type depends on arg type
when (val paramType = actualParamTypes.first()) {
BaseDataType.UBYTE, BaseDataType.BYTE -> ReturnConvention(paramType, RegisterOrPair.A)
BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.POINTER -> ReturnConvention(paramType, RegisterOrPair.AY)
BaseDataType.LONG -> ReturnConvention(returnType, RegisterOrPair.R14R15)
BaseDataType.FLOAT -> ReturnConvention(paramType, RegisterOrPair.FAC1)
in IterableDatatypes -> ReturnConvention(paramType, RegisterOrPair.AY)
else -> ReturnConvention(paramType, null)
}
}
}
} else {
// note: this path is currently never hit because the builtin functions with multiple return values have been handled in specialized optimized codegens already earlier.
TODO("multiple return types from builtin function")
}
return when {
actualParamTypes.isEmpty() -> CallConvention(emptyList(), returns)
actualParamTypes.size==1 -> {
// One parameter goes via register/registerpair.
// One parameter goes via register/registerpair (except longs)
// this avoids repeated code for every caller to store the value in the subroutine's argument variable.
// (that store is still done, but only coded once at the start at the subroutine itself rather than at every call site).
// TODO can we start using the X register as well for a third byte or word+byte combo
val paramConv = when(val paramType = actualParamTypes[0]) {
DataType.UBYTE, DataType.BYTE -> ParamConvention(paramType, RegisterOrPair.A, false)
DataType.UWORD, DataType.WORD -> ParamConvention(paramType, RegisterOrPair.AY, false)
DataType.FLOAT -> ParamConvention(paramType, RegisterOrPair.AY, false) // TODO is this correct? shouldn't it be FAC1?
in PassByReferenceDatatypes -> ParamConvention(paramType, RegisterOrPair.AY, false)
BaseDataType.UBYTE, BaseDataType.BYTE -> ParamConvention(paramType, RegisterOrPair.A, false)
BaseDataType.UWORD, BaseDataType.WORD -> ParamConvention(paramType, RegisterOrPair.AY, false)
BaseDataType.LONG -> ParamConvention(paramType, null, true)
BaseDataType.FLOAT -> ParamConvention(paramType, RegisterOrPair.AY, false) // NOTE: for builtin functions, floating point arguments are passed by reference (so you get a pointer in AY)
in IterableDatatypes -> ParamConvention(paramType, RegisterOrPair.AY, false)
else -> ParamConvention(paramType, null, false)
}
CallConvention(listOf(paramConv), returns)
}
actualParamTypes.size==2 && (actualParamTypes[0].isByte && actualParamTypes[1].isWord) -> {
TODO("opportunity to pass word+byte arguments in A,Y and X registers but not implemented yet")
}
actualParamTypes.size==2 && (actualParamTypes[0].isWord && actualParamTypes[1].isByte) -> {
TODO("opportunity to pass word+byte arguments in A,Y and X registers but not implemented yet")
}
actualParamTypes.size==3 && actualParamTypes.all { it.isByte } -> {
TODO("opportunity to pass 3 byte arguments in A,Y and X registers but not implemented yet")
}
else -> {
// multiple parameters go via variables
val paramConvs = actualParamTypes.map { ParamConvention(it, null, true) }
@@ -72,70 +97,106 @@ class FSignature(val pure: Boolean, // does it have side effects?
}
val BuiltinFunctions: Map<String, FSignature> = mapOf(
// this set of function have no return value and operate in-place:
"setlsb" to FSignature(false, listOf(FParam("variable", arrayOf(DataType.WORD, DataType.UWORD)), FParam("value", arrayOf(DataType.BYTE, DataType.UBYTE))), null),
"setmsb" to FSignature(false, listOf(FParam("variable", arrayOf(DataType.WORD, DataType.UWORD)), FParam("value", arrayOf(DataType.BYTE, DataType.UBYTE))), null),
"rol" to FSignature(false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), null),
"ror" to FSignature(false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), null),
"rol2" to FSignature(false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), null),
"ror2" to FSignature(false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), null),
// cmp returns a status in the carry flag, but not a proper return value
"cmp" to FSignature(false, listOf(FParam("value1", IntegerDatatypes), FParam("value2", NumericDatatypes)), null),
"prog8_lib_stringcompare" to FSignature(true, listOf(FParam("str1", arrayOf(DataType.STR)), FParam("str2", arrayOf(DataType.STR))), DataType.BYTE),
"prog8_lib_square_byte" to FSignature(true, listOf(FParam("value", arrayOf(DataType.BYTE, DataType.UBYTE))), DataType.UBYTE),
"prog8_lib_square_word" to FSignature(true, listOf(FParam("value", arrayOf(DataType.WORD, DataType.UWORD))), DataType.UWORD),
"prog8_ifelse_bittest_set" to FSignature(true, listOf(FParam("variable", ByteDatatypes), FParam("bitnumber", arrayOf(DataType.UBYTE))), DataType.BOOL),
"prog8_ifelse_bittest_notset" to FSignature(true, listOf(FParam("variable", ByteDatatypes), FParam("bitnumber", arrayOf(DataType.UBYTE))), DataType.BOOL),
"abs" to FSignature(true, listOf(FParam("value", NumericDatatypes)), null),
"abs__byte" to FSignature(true, listOf(FParam("value", arrayOf(DataType.BYTE))), DataType.BYTE),
"abs__word" to FSignature(true, listOf(FParam("value", arrayOf(DataType.WORD))), DataType.WORD),
"abs__float" to FSignature(true, listOf(FParam("value", arrayOf(DataType.FLOAT))), DataType.FLOAT),
"len" to FSignature(true, listOf(FParam("values", IterableDatatypes)), DataType.UWORD),
// normal functions follow:
"sizeof" to FSignature(true, listOf(FParam("object", DataType.entries.toTypedArray())), DataType.UBYTE),
"sgn" to FSignature(true, listOf(FParam("value", NumericDatatypes)), DataType.BYTE),
"sqrt" to FSignature(true, listOf(FParam("value", NumericDatatypes)), null),
"sqrt__ubyte" to FSignature(true, listOf(FParam("value", arrayOf(DataType.UBYTE))), DataType.UBYTE),
"sqrt__uword" to FSignature(true, listOf(FParam("value", arrayOf(DataType.UWORD))), DataType.UBYTE),
"sqrt__float" to FSignature(true, listOf(FParam("value", arrayOf(DataType.FLOAT))), DataType.FLOAT),
"divmod" to FSignature(false, listOf(FParam("dividend", arrayOf(DataType.UBYTE, DataType.UWORD)), FParam("divisor", arrayOf(DataType.UBYTE, DataType.UWORD)), FParam("quotient", arrayOf(DataType.UBYTE, DataType.UWORD)), FParam("remainder", arrayOf(DataType.UBYTE, DataType.UWORD))), null),
"divmod__ubyte" to FSignature(false, listOf(FParam("dividend", arrayOf(DataType.UBYTE)), FParam("divisor", arrayOf(DataType.UBYTE)), FParam("quotient", arrayOf(DataType.UBYTE)), FParam("remainder", arrayOf(DataType.UBYTE))), null),
"divmod__uword" to FSignature(false, listOf(FParam("dividend", arrayOf(DataType.UWORD)), FParam("divisor", arrayOf(DataType.UWORD)), FParam("quotient", arrayOf(DataType.UWORD)), FParam("remainder", arrayOf(DataType.UWORD))), null),
"lsb" to FSignature(true, listOf(FParam("value", arrayOf(DataType.UWORD, DataType.WORD))), DataType.UBYTE),
"msb" to FSignature(true, listOf(FParam("value", arrayOf(DataType.UWORD, DataType.WORD))), DataType.UBYTE),
"mkword" to FSignature(true, listOf(FParam("msb", arrayOf(DataType.UBYTE)), FParam("lsb", arrayOf(DataType.UBYTE))), DataType.UWORD),
"clamp" to FSignature(true, listOf(FParam("value", arrayOf(DataType.BYTE)), FParam("minimum", arrayOf(DataType.BYTE)), FParam("maximum", arrayOf(DataType.BYTE))), null),
"clamp__byte" to FSignature(true, listOf(FParam("value", arrayOf(DataType.BYTE)), FParam("minimum", arrayOf(DataType.BYTE)), FParam("maximum", arrayOf(DataType.BYTE))), DataType.BYTE),
"clamp__ubyte" to FSignature(true, listOf(FParam("value", arrayOf(DataType.UBYTE)), FParam("minimum", arrayOf(DataType.UBYTE)), FParam("maximum", arrayOf(DataType.UBYTE))), DataType.UBYTE),
"clamp__word" to FSignature(true, listOf(FParam("value", arrayOf(DataType.WORD)), FParam("minimum", arrayOf(DataType.WORD)), FParam("maximum", arrayOf(DataType.WORD))), DataType.WORD),
"clamp__uword" to FSignature(true, listOf(FParam("value", arrayOf(DataType.UWORD)), FParam("minimum", arrayOf(DataType.UWORD)), FParam("maximum", arrayOf(DataType.UWORD))), DataType.UWORD),
"min" to FSignature(true, listOf(FParam("val1", arrayOf(DataType.BYTE)), FParam("val2", arrayOf(DataType.BYTE))), null),
"min__byte" to FSignature(true, listOf(FParam("val1", arrayOf(DataType.BYTE)), FParam("val2", arrayOf(DataType.BYTE))), DataType.BYTE),
"min__ubyte" to FSignature(true, listOf(FParam("val1", arrayOf(DataType.UBYTE)), FParam("val2", arrayOf(DataType.UBYTE))), DataType.UBYTE),
"min__word" to FSignature(true, listOf(FParam("val1", arrayOf(DataType.WORD)), FParam("val2", arrayOf(DataType.WORD))), DataType.WORD),
"min__uword" to FSignature(true, listOf(FParam("val1", arrayOf(DataType.UWORD)), FParam("val2", arrayOf(DataType.UWORD))), DataType.UWORD),
"max" to FSignature(true, listOf(FParam("val1", arrayOf(DataType.BYTE)), FParam("val2", arrayOf(DataType.BYTE))), null),
"max__byte" to FSignature(true, listOf(FParam("val1", arrayOf(DataType.BYTE)), FParam("val2", arrayOf(DataType.BYTE))), DataType.BYTE),
"max__ubyte" to FSignature(true, listOf(FParam("val1", arrayOf(DataType.UBYTE)), FParam("val2", arrayOf(DataType.UBYTE))), DataType.UBYTE),
"max__word" to FSignature(true, listOf(FParam("val1", arrayOf(DataType.WORD)), FParam("val2", arrayOf(DataType.WORD))), DataType.WORD),
"max__uword" to FSignature(true, listOf(FParam("val1", arrayOf(DataType.UWORD)), FParam("val2", arrayOf(DataType.UWORD))), DataType.UWORD),
"peek" to FSignature(true, listOf(FParam("address", arrayOf(DataType.UWORD))), DataType.UBYTE),
"peekw" to FSignature(true, listOf(FParam("address", arrayOf(DataType.UWORD))), DataType.UWORD),
"peekf" to FSignature(true, listOf(FParam("address", arrayOf(DataType.UWORD))), DataType.FLOAT),
"poke" to FSignature(false, listOf(FParam("address", arrayOf(DataType.UWORD)), FParam("value", arrayOf(DataType.UBYTE))), null),
"pokew" to FSignature(false, listOf(FParam("address", arrayOf(DataType.UWORD)), FParam("value", arrayOf(DataType.UWORD))), null),
"pokef" to FSignature(false, listOf(FParam("address", arrayOf(DataType.UWORD)), FParam("value", arrayOf(DataType.FLOAT))), null),
"pokemon" to FSignature(false, listOf(FParam("address", arrayOf(DataType.UWORD)), FParam("value", arrayOf(DataType.UBYTE))), DataType.UBYTE),
"rsave" to FSignature(false, emptyList(), null),
"rrestore" to FSignature(false, emptyList(), null),
"memory" to FSignature(true, listOf(FParam("name", arrayOf(DataType.STR)), FParam("size", arrayOf(DataType.UWORD)), FParam("alignment", arrayOf(DataType.UWORD))), DataType.UWORD),
"callfar" to FSignature(false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("arg", arrayOf(DataType.UWORD))), DataType.UWORD),
"callfar2" to FSignature(false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("argA", arrayOf(DataType.UBYTE)), FParam("argX", arrayOf(DataType.UBYTE)), FParam("argY", arrayOf(DataType.UBYTE)), FParam("argC", arrayOf(DataType.BOOL))), DataType.UWORD),
"call" to FSignature(false, listOf(FParam("address", arrayOf(DataType.UWORD))), DataType.UWORD),
"setlsb" to FSignature(false, emptyArray(), FParam("variable", BaseDataType.WORD, BaseDataType.UWORD, BaseDataType.LONG), FParam("value", BaseDataType.BYTE, BaseDataType.UBYTE)),
"setmsb" to FSignature(false, emptyArray(), FParam("variable", BaseDataType.WORD, BaseDataType.UWORD, BaseDataType.LONG), FParam("value", BaseDataType.BYTE, BaseDataType.UBYTE)),
"rol" to FSignature(false, emptyArray(), FParam("item", BaseDataType.UBYTE, BaseDataType.UWORD, BaseDataType.LONG)),
"ror" to FSignature(false, emptyArray(), FParam("item", BaseDataType.UBYTE, BaseDataType.UWORD, BaseDataType.LONG)),
"rol2" to FSignature(false, emptyArray(), FParam("item", BaseDataType.UBYTE, BaseDataType.UWORD, BaseDataType.LONG)),
"ror2" to FSignature(false, emptyArray(), FParam("item", BaseDataType.UBYTE, BaseDataType.UWORD, BaseDataType.LONG)),
"cmp" to FSignature(false, emptyArray(), FParam("value1", *IntegerDatatypes), FParam("value2", *NumericDatatypes)), // cmp returns result in the cpu status flags, but not asa proper return value
"prog8_lib_stringcompare" to FSignature(true, arrayOf(BaseDataType.BYTE), FParam("str1", BaseDataType.STR), FParam("str2", BaseDataType.STR)),
"prog8_lib_square_byte" to FSignature(true, arrayOf(BaseDataType.UBYTE), FParam("value", BaseDataType.BYTE, BaseDataType.UBYTE)),
"prog8_lib_square_word" to FSignature(true, arrayOf(BaseDataType.UWORD), FParam("value", BaseDataType.WORD, BaseDataType.UWORD)),
"prog8_lib_square_long" to FSignature(true, arrayOf(BaseDataType.LONG), FParam("value", BaseDataType.LONG)),
"prog8_lib_structalloc" to FSignature(true, arrayOf(BaseDataType.UWORD)),
"prog8_lib_copylong" to FSignature(false, emptyArray(), FParam("pointer1", BaseDataType.POINTER, BaseDataType.UWORD, BaseDataType.LONG), FParam("pointer2", BaseDataType.POINTER, BaseDataType.UWORD, BaseDataType.LONG)),
"prog8_lib_copyfloat" to FSignature(false, emptyArray(), FParam("pointer1", BaseDataType.POINTER, BaseDataType.UWORD, BaseDataType.LONG), FParam("pointer2", BaseDataType.POINTER, BaseDataType.UWORD, BaseDataType.LONG)),
"abs" to FSignature(true, arrayOf(BaseDataType.UNDEFINED), FParam("value", *NumericDatatypes)),
"abs__byte" to FSignature(true, arrayOf(BaseDataType.UBYTE), FParam("value", BaseDataType.BYTE)),
"abs__word" to FSignature(true, arrayOf(BaseDataType.UWORD), FParam("value", BaseDataType.WORD)),
"abs__long" to FSignature(true, arrayOf(BaseDataType.LONG), FParam("value", BaseDataType.LONG)),
"abs__float" to FSignature(true, arrayOf(BaseDataType.FLOAT), FParam("value", BaseDataType.FLOAT)),
"len" to FSignature(true, arrayOf(BaseDataType.UWORD), FParam("values", *IterableDatatypes)),
"sizeof" to FSignature(true, arrayOf(BaseDataType.UBYTE), FParam("object", *(BaseDataType.entries - BaseDataType.STRUCT_INSTANCE).toTypedArray())),
"offsetof" to FSignature(true, arrayOf(BaseDataType.UBYTE), FParam("field", BaseDataType.UBYTE)),
"sgn" to FSignature(true, arrayOf(BaseDataType.BYTE), FParam("value", *NumericDatatypes)),
"sqrt" to FSignature(true, arrayOf(BaseDataType.UNDEFINED), FParam("value", *NumericDatatypes)),
"sqrt__ubyte" to FSignature(true, arrayOf(BaseDataType.UBYTE), FParam("value", BaseDataType.UBYTE)),
"sqrt__uword" to FSignature(true, arrayOf(BaseDataType.UBYTE), FParam("value", BaseDataType.UWORD)),
"sqrt__long" to FSignature(true, arrayOf(BaseDataType.UWORD), FParam("value", BaseDataType.LONG)),
"sqrt__float" to FSignature(true, arrayOf(BaseDataType.FLOAT), FParam("value", BaseDataType.FLOAT)),
"divmod" to FSignature(false, arrayOf(BaseDataType.UNDEFINED, BaseDataType.UNDEFINED), FParam("dividend", BaseDataType.UBYTE, BaseDataType.UWORD), FParam("divisor", BaseDataType.UBYTE, BaseDataType.UWORD)),
"divmod__ubyte" to FSignature(false, arrayOf(BaseDataType.UBYTE, BaseDataType.UBYTE), FParam("dividend", BaseDataType.UBYTE), FParam("divisor", BaseDataType.UBYTE)),
"divmod__uword" to FSignature(false, arrayOf(BaseDataType.UWORD, BaseDataType.UWORD), FParam("dividend", BaseDataType.UWORD), FParam("divisor", BaseDataType.UWORD)),
"divmod__byte" to FSignature(false, arrayOf(BaseDataType.BYTE, BaseDataType.BYTE), FParam("dividend", BaseDataType.BYTE), FParam("divisor", BaseDataType.BYTE)),
"divmod__word" to FSignature(false, arrayOf(BaseDataType.WORD, BaseDataType.WORD), FParam("dividend", BaseDataType.WORD), FParam("divisor", BaseDataType.WORD)),
"lmh" to FSignature(true, arrayOf(BaseDataType.UBYTE, BaseDataType.UBYTE, BaseDataType.UBYTE), FParam("value", BaseDataType.LONG)),
"lsb" to FSignature(true, arrayOf(BaseDataType.UBYTE), FParam("value", BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)),
"lsb__long" to FSignature(true, arrayOf(BaseDataType.UBYTE), FParam("value", BaseDataType.LONG)),
"msb" to FSignature(true, arrayOf(BaseDataType.UBYTE), FParam("value", BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)),
"msb__long" to FSignature(true, arrayOf(BaseDataType.UBYTE), FParam("value", BaseDataType.LONG)),
"lsw" to FSignature(true, arrayOf(BaseDataType.UWORD), FParam("value", BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)),
"msw" to FSignature(true, arrayOf(BaseDataType.UWORD), FParam("value", BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)),
"mkword" to FSignature(true, arrayOf(BaseDataType.UWORD), FParam("msb", BaseDataType.UBYTE), FParam("lsb", BaseDataType.UBYTE)),
"mklong" to FSignature(true, arrayOf(BaseDataType.LONG), FParam("msb", BaseDataType.UBYTE), FParam("b2", BaseDataType.UBYTE), FParam("b1", BaseDataType.UBYTE), FParam("lsb", BaseDataType.UBYTE)),
"mklong2" to FSignature(true, arrayOf(BaseDataType.LONG), FParam("msw", BaseDataType.UWORD), FParam("lsw", BaseDataType.UWORD)),
"clamp" to FSignature(true, arrayOf(BaseDataType.UNDEFINED), FParam("value", BaseDataType.BYTE), FParam("minimum", BaseDataType.BYTE), FParam("maximum", BaseDataType.BYTE)),
"clamp__byte" to FSignature(true, arrayOf(BaseDataType.BYTE), FParam("value", BaseDataType.BYTE), FParam("minimum", BaseDataType.BYTE), FParam("maximum", BaseDataType.BYTE)),
"clamp__ubyte" to FSignature(true, arrayOf(BaseDataType.UBYTE), FParam("value", BaseDataType.UBYTE), FParam("minimum", BaseDataType.UBYTE), FParam("maximum", BaseDataType.UBYTE)),
"clamp__word" to FSignature(true, arrayOf(BaseDataType.WORD), FParam("value", BaseDataType.WORD), FParam("minimum", BaseDataType.WORD), FParam("maximum", BaseDataType.WORD)),
"clamp__uword" to FSignature(true, arrayOf(BaseDataType.UWORD), FParam("value", BaseDataType.UWORD), FParam("minimum", BaseDataType.UWORD), FParam("maximum", BaseDataType.UWORD)),
"clamp__long" to FSignature(true, arrayOf(BaseDataType.LONG), FParam("value", BaseDataType.LONG), FParam("minimum", BaseDataType.LONG), FParam("maximum", BaseDataType.LONG)),
"min" to FSignature(true, arrayOf(BaseDataType.UNDEFINED), FParam("val1", BaseDataType.BYTE), FParam("val2", BaseDataType.BYTE)),
"min__byte" to FSignature(true, arrayOf(BaseDataType.BYTE), FParam("val1", BaseDataType.BYTE), FParam("val2", BaseDataType.BYTE)),
"min__ubyte" to FSignature(true, arrayOf(BaseDataType.UBYTE), FParam("val1", BaseDataType.UBYTE), FParam("val2", BaseDataType.UBYTE)),
"min__word" to FSignature(true, arrayOf(BaseDataType.WORD), FParam("val1", BaseDataType.WORD), FParam("val2", BaseDataType.WORD)),
"min__uword" to FSignature(true, arrayOf(BaseDataType.UWORD), FParam("val1", BaseDataType.UWORD), FParam("val2", BaseDataType.UWORD)),
"min__long" to FSignature(true, arrayOf(BaseDataType.LONG), FParam("val1", BaseDataType.LONG), FParam("val2", BaseDataType.LONG)),
"max" to FSignature(true, arrayOf(BaseDataType.UNDEFINED), FParam("val1", BaseDataType.BYTE), FParam("val2", BaseDataType.BYTE)),
"max__byte" to FSignature(true, arrayOf(BaseDataType.BYTE), FParam("val1", BaseDataType.BYTE), FParam("val2", BaseDataType.BYTE)),
"max__ubyte" to FSignature(true, arrayOf(BaseDataType.UBYTE), FParam("val1", BaseDataType.UBYTE), FParam("val2", BaseDataType.UBYTE)),
"max__word" to FSignature(true, arrayOf(BaseDataType.WORD), FParam("val1", BaseDataType.WORD), FParam("val2", BaseDataType.WORD)),
"max__uword" to FSignature(true, arrayOf(BaseDataType.UWORD), FParam("val1", BaseDataType.UWORD), FParam("val2", BaseDataType.UWORD)),
"max__long" to FSignature(true, arrayOf(BaseDataType.LONG), FParam("val1", BaseDataType.LONG), FParam("val2", BaseDataType.LONG)),
"peek" to FSignature(true, arrayOf(BaseDataType.UBYTE), FParam("address", BaseDataType.UWORD, BaseDataType.LONG, BaseDataType.POINTER)),
"peekbool" to FSignature(true, arrayOf(BaseDataType.BOOL), FParam("address", BaseDataType.UWORD, BaseDataType.LONG, BaseDataType.POINTER)),
"peekw" to FSignature(true, arrayOf(BaseDataType.UWORD), FParam("address", BaseDataType.UWORD, BaseDataType.LONG, BaseDataType.POINTER)),
"peekl" to FSignature(true, arrayOf(BaseDataType.LONG), FParam("address", BaseDataType.UWORD, BaseDataType.LONG, BaseDataType.POINTER)),
"peekf" to FSignature(true, arrayOf(BaseDataType.FLOAT), FParam("address", BaseDataType.UWORD, BaseDataType.LONG, BaseDataType.POINTER)),
"peekp" to FSignature(true, arrayOf(BaseDataType.POINTER), FParam("address", BaseDataType.POINTER, BaseDataType.UWORD, BaseDataType.LONG)),
"poke" to FSignature(false, emptyArray(), FParam("address", BaseDataType.UWORD, BaseDataType.LONG, BaseDataType.POINTER), FParam("value", BaseDataType.UBYTE, BaseDataType.BYTE)),
"pokebool" to FSignature(false, emptyArray(), FParam("address", BaseDataType.UWORD, BaseDataType.LONG, BaseDataType.POINTER), FParam("value", BaseDataType.BOOL)),
"pokebowl" to FSignature(false, emptyArray(), FParam("address", BaseDataType.UWORD, BaseDataType.LONG, BaseDataType.POINTER), FParam("value", BaseDataType.BOOL)),
"pokew" to FSignature(false, emptyArray(), FParam("address", BaseDataType.UWORD, BaseDataType.LONG, BaseDataType.POINTER), FParam("value", BaseDataType.UWORD, BaseDataType.WORD)),
"pokel" to FSignature(false, emptyArray(), FParam("address", BaseDataType.UWORD, BaseDataType.LONG, BaseDataType.POINTER), FParam("value", BaseDataType.LONG)),
"pokef" to FSignature(false, emptyArray(), FParam("address", BaseDataType.UWORD, BaseDataType.LONG, BaseDataType.POINTER), FParam("value", BaseDataType.FLOAT)),
"pokep" to FSignature(false, emptyArray(), FParam("address", BaseDataType.POINTER, BaseDataType.UWORD, BaseDataType.LONG), FParam("value", BaseDataType.POINTER)),
"pokemon" to FSignature(false, arrayOf(BaseDataType.UBYTE), FParam("address", BaseDataType.UWORD, BaseDataType.LONG, BaseDataType.POINTER), FParam("value", BaseDataType.UBYTE)),
"rsave" to FSignature(false, emptyArray()),
"rrestore" to FSignature(false, emptyArray()),
"memory" to FSignature(true, arrayOf(BaseDataType.POINTER), FParam("name", BaseDataType.STR), FParam("size", BaseDataType.UWORD), FParam("alignment", BaseDataType.UWORD)),
"memory__ref" to FSignature(true, arrayOf(BaseDataType.POINTER), FParam("name", BaseDataType.STR)),
"callfar" to FSignature(false, arrayOf(BaseDataType.UWORD), FParam("bank", BaseDataType.UBYTE), FParam("address", BaseDataType.POINTER), FParam("arg", BaseDataType.UWORD)),
"callfar2" to FSignature(false, arrayOf(BaseDataType.UWORD), FParam("bank", BaseDataType.UBYTE), FParam("address", BaseDataType.POINTER), FParam("argA", BaseDataType.UBYTE), FParam("argX", BaseDataType.UBYTE), FParam("argY", BaseDataType.UBYTE), FParam("argC", BaseDataType.BOOL)),
"call" to FSignature(false, arrayOf(BaseDataType.UWORD), FParam("address", BaseDataType.POINTER)),
"push" to FSignature(false, emptyArray(), FParam("value", BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.BOOL)),
"pushw" to FSignature(false, emptyArray(), FParam("value", BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.POINTER)),
"pushl" to FSignature(false, emptyArray(), FParam("value", BaseDataType.LONG)),
"pushf" to FSignature(false, emptyArray(), FParam("value", BaseDataType.FLOAT)),
"pushp" to FSignature(false, emptyArray(), FParam("value", BaseDataType.POINTER)),
"pop" to FSignature(false, arrayOf(BaseDataType.UBYTE)),
"popw" to FSignature(false, arrayOf(BaseDataType.UWORD)),
"popl" to FSignature(false, arrayOf(BaseDataType.LONG)),
"popf" to FSignature(false, arrayOf(BaseDataType.FLOAT)),
"popp" to FSignature(false, arrayOf(BaseDataType.POINTER)),
)
val InplaceModifyingBuiltinFunctions = setOf(
"setlsb", "setmsb",
"rol", "ror", "rol2", "ror2",
"divmod", "divmod__ubyte", "divmod__uword"
"rol", "ror", "rol2", "ror2"
)
val SimpleBuiltinFunctions = setOf(
"msb", "lsb", "msw", "lsw",
"mkword", "mklong", "mklong2",
"set_carry", "set_irqd", "clear_carry", "clear_irqd")
@@ -4,6 +4,7 @@ import java.nio.file.Path
import kotlin.io.path.Path
@Suppress("unused")
class CompilationOptions(val output: OutputType,
val launcher: CbmPrgLauncherType,
val zeropage: ZeropageType,
@@ -11,33 +12,114 @@ class CompilationOptions(val output: OutputType,
val zpAllowed: List<UIntRange>,
val floats: Boolean,
val noSysInit: Boolean,
val romable: Boolean,
val compTarget: ICompilationTarget,
val compilerVersion: String,
// these are set later, based on command line arguments or options in the source code:
var loadAddress: UInt,
var memtopAddress: UInt,
var varsAddress: UInt? = null,
var warnSymbolShadowing: Boolean = false,
var warnImplicitTypeCast: Boolean = false,
var optimize: Boolean = false,
var asmQuiet: Boolean = false,
var asmListfile: Boolean = false,
var includeSourcelines: Boolean = false,
var dumpVariables: Boolean = false,
var dumpSymbols: Boolean = false,
var experimentalCodegen: Boolean = false,
var newCodegen: Boolean = false,
var varsHighBank: Int? = null,
var varsGolden: Boolean = false,
var slabsHighBank: Int? = null,
var slabsGolden: Boolean = false,
var splitWordArrays: Boolean = false,
var addMissingRts: Boolean = false, // deprecated, will likely go way in future version
var breakpointCpuInstruction: String? = null,
var ignoreFootguns: Boolean = false,
var outputDir: Path = Path(""),
var symbolDefs: Map<String, String> = emptyMap()
var quiet: Boolean = false,
var profilingInstrumentation: Boolean = false,
var symbolDefs: Map<String, String> = emptyMap(),
var privateSymbols: Boolean = false,
var outputFile: Path? = null
) {
init {
compTarget.machine.initializeMemoryAreas(this)
compTarget.initializeMemoryAreas(this)
}
companion object {
val AllZeropageAllowed: List<UIntRange> = listOf(0u..255u)
fun builder(compTarget: ICompilationTarget) = Builder(compTarget)
class Builder(private val compTarget: ICompilationTarget) {
private var output: OutputType = compTarget.defaultOutputType
private var launcher: CbmPrgLauncherType = CbmPrgLauncherType.NONE
private var zeropage: ZeropageType = ZeropageType.DONTUSE
private var zpReserved: List<UIntRange> = emptyList()
private var zpAllowed: List<UIntRange> = AllZeropageAllowed
private var floats: Boolean = false
private var noSysInit: Boolean = false
private var romable: Boolean = false
private var compilerVersion: String = "unknown"
private var loadAddress: UInt = compTarget.PROGRAM_LOAD_ADDRESS
private var memtopAddress: UInt = compTarget.PROGRAM_MEMTOP_ADDRESS
private var varsAddress: UInt? = null
private var warnSymbolShadowing: Boolean = false
private var warnImplicitTypeCast: Boolean = false
private var optimize: Boolean = false
private var asmQuiet: Boolean = false
private var asmListfile: Boolean = false
private var includeSourcelines: Boolean = false
private var dumpVariables: Boolean = false
private var dumpSymbols: Boolean = false
private var varsHighBank: Int? = null
private var varsGolden: Boolean = false
private var breakpointCpuInstruction: String? = null
private var ignoreFootguns: Boolean = false
private var outputDir: Path = Path("")
private var quiet: Boolean = false
private var profilingInstrumentation: Boolean = false
private var newCodegen: Boolean = false
private var symbolDefs: Map<String, String> = emptyMap()
private var outputFile: Path? = null
fun output(output: OutputType) = apply { this.output = output }
fun launcher(launcher: CbmPrgLauncherType) = apply { this.launcher = launcher }
fun zeropage(zeropage: ZeropageType) = apply { this.zeropage = zeropage }
fun zpReserved(zpReserved: List<UIntRange>) = apply { this.zpReserved = zpReserved }
fun zpAllowed(zpAllowed: List<UIntRange>) = apply { this.zpAllowed = zpAllowed }
fun floats(floats: Boolean) = apply { this.floats = floats }
fun noSysInit(noSysInit: Boolean) = apply { this.noSysInit = noSysInit }
fun romable(romable: Boolean) = apply { this.romable = romable }
fun compilerVersion(compilerVersion: String) = apply { this.compilerVersion = compilerVersion }
fun loadAddress(loadAddress: UInt) = apply { this.loadAddress = loadAddress }
fun memtopAddress(memtopAddress: UInt) = apply { this.memtopAddress = memtopAddress }
fun varsAddress(varsAddress: UInt?) = apply { this.varsAddress = varsAddress }
fun warnSymbolShadowing(warnSymbolShadowing: Boolean) = apply { this.warnSymbolShadowing = warnSymbolShadowing }
fun warnImplicitTypeCast(warnImplicitTypeCast: Boolean) = apply { this.warnImplicitTypeCast = warnImplicitTypeCast }
fun optimize(optimize: Boolean) = apply { this.optimize = optimize }
fun asmQuiet(asmQuiet: Boolean) = apply { this.asmQuiet = asmQuiet }
fun asmListfile(asmListfile: Boolean) = apply { this.asmListfile = asmListfile }
fun includeSourcelines(includeSourcelines: Boolean) = apply { this.includeSourcelines = includeSourcelines }
fun dumpVariables(dumpVariables: Boolean) = apply { this.dumpVariables = dumpVariables }
fun dumpSymbols(dumpSymbols: Boolean) = apply { this.dumpSymbols = dumpSymbols }
fun varsHighBank(varsHighBank: Int?) = apply { this.varsHighBank = varsHighBank }
fun varsGolden(varsGolden: Boolean) = apply { this.varsGolden = varsGolden }
fun breakpointCpuInstruction(breakpointCpuInstruction: String?) = apply { this.breakpointCpuInstruction = breakpointCpuInstruction }
fun ignoreFootguns(ignoreFootguns: Boolean) = apply { this.ignoreFootguns = ignoreFootguns }
fun outputDir(outputDir: Path) = apply { this.outputDir = outputDir }
fun quiet(quiet: Boolean) = apply { this.quiet = quiet }
fun profilingInstrumentation(profilingInstrumentation: Boolean) = apply { this.profilingInstrumentation = profilingInstrumentation }
fun symbolDefs(symbolDefs: Map<String, String>) = apply { this.symbolDefs = symbolDefs }
fun newCodegen(newCodegen: Boolean) = apply { this.newCodegen = newCodegen }
fun outputFile(outputFile: Path?) = apply { this.outputFile = outputFile }
fun build(): CompilationOptions {
return CompilationOptions(
output, launcher, zeropage, zpReserved, zpAllowed, floats, noSysInit, romable, compTarget, compilerVersion,
loadAddress, memtopAddress, varsAddress, warnSymbolShadowing, warnImplicitTypeCast, optimize, asmQuiet, asmListfile,
includeSourcelines, dumpVariables, dumpSymbols, newCodegen, varsHighBank, varsGolden,
breakpointCpuInstruction, ignoreFootguns, outputDir, quiet,
profilingInstrumentation, symbolDefs
).apply { this.outputFile = this@Builder.outputFile }
}
}
}
}
+30 -4
View File
@@ -11,15 +11,19 @@ fun Number.toHex(): String {
// 0..15 -> "0".."15"
// 16..255 -> "$10".."$ff"
// 256..65536 -> "$0100".."$ffff"
// larger -> "$12345678"
// negative values are prefixed with '-'.
val integer = this.toInt()
if(integer<0)
val integer = this.toLong()
if(integer<0) {
if(integer==-2147483648L)
return "$80000000" // the exception to the rule, because -$80000000 is not a valid hex number
return '-' + abs(integer).toHex()
}
return when (integer) {
in 0 until 16 -> integer.toString()
in 0 until 0x100 -> "$"+integer.toString(16).padStart(2,'0')
in 0 until 0x10000 -> "$"+integer.toString(16).padStart(4,'0')
else -> throw IllegalArgumentException("number too large for 16 bits $this")
else -> "$"+integer.toString(16).padStart(8,'0')
}
}
@@ -27,11 +31,12 @@ fun UInt.toHex(): String {
// 0..15 -> "0".."15"
// 16..255 -> "$10".."$ff"
// 256..65536 -> "$0100".."$ffff"
// larger -> "$12345678"
return when (this) {
in 0u until 16u -> this.toString()
in 0u until 0x100u -> "$"+this.toString(16).padStart(2,'0')
in 0u until 0x10000u -> "$"+this.toString(16).padStart(4,'0')
else -> throw IllegalArgumentException("number too large for 16 bits $this")
else -> "$"+this.toString(16).padStart(8,'0')
}
}
@@ -93,3 +98,24 @@ fun String.unescape(): String {
}
return result.joinToString("")
}
// === Symbol name prefixing ===
// These are used by code generators to add p8b_/p8s_/p8v_/etc. prefixes to symbol names.
// The prefix character depends on the symbol type (block='b', sub='s', variable='v', etc.)
// Scoped names (containing dots) have each part prefixed according to its role.
fun prefixScopedName(name: String, type: Char): String {
val generatedPrefix = "p8_label_gen_"
if('.' !in name) {
if(name.startsWith(generatedPrefix))
return name
return "p8${type}_$name"
}
val parts = name.split('.')
val firstPrefixed = "p8b_${parts[0]}"
val lastPart = parts.last()
val lastPrefixed = if(lastPart.startsWith(generatedPrefix)) lastPart else "p8${type}_$lastPart"
val inbetweenPrefixed = parts.drop(1).dropLast(1).map{ "p8s_$it" }
val prefixed = listOf(firstPrefixed) + inbetweenPrefixed + listOf(lastPrefixed)
return prefixed.joinToString(".")
}
+534
View File
@@ -0,0 +1,534 @@
package prog8.code.core
import java.util.Objects
/**
* Base data types supported by the Prog8 compiler.
* These represent the fundamental types that can be used in Prog8 programs.
*/
enum class BaseDataType {
UBYTE, // pass by value 8 bits unsigned
BYTE, // pass by value 8 bits signed
UWORD, // pass by value 16 bits unsigned
WORD, // pass by value 16 bits signed
LONG, // pass by value 32 bits signed
FLOAT, // pass by value machine dependent
BOOL, // pass by value bit 0 of an 8-bit byte
STR, // pass by reference
ARRAY, // pass by reference, subtype is the element type
ARRAY_SPLITW, // pass by reference, split word layout, subtype is the element type (restricted to word types)
POINTER, // typed pointer, subtype is whatever type is pointed to
STRUCT_INSTANCE, // the actual instance of a struct (not directly supported in the language yet, but we need its type)
UNDEFINED;
fun largerSizeThan(other: BaseDataType) =
when {
this == other -> false
this.isByteOrBool -> false
this.isWord -> other.isByteOrBool
this == LONG -> other.isByteOrBool || other.isWord
this == STR && (other == UWORD || other == LONG) || this == UWORD && other == STR -> false
this.isArray && other.isArray -> false
this.isArray -> other.isByteOrBool
this == STR -> other.isByteOrBool
this.isPointer -> other.isByteOrBool
else -> true
}
fun equalsSize(other: BaseDataType): Boolean = equalsSize(other, null)
fun equalsSize(other: BaseDataType, memsizer: IMemSizer?): Boolean =
when {
this == other -> true
this.isArray && other.isArray -> true
this.isByteOrBool -> other.isByteOrBool
this.isWord -> other.isWord || (other.isPointer && (memsizer == null || memsizer.POINTER_MEM_SIZE == 2u))
this.isLong -> other.isLong || (other.isPointer && memsizer?.POINTER_MEM_SIZE != null && memsizer.POINTER_MEM_SIZE != 2u)
this.isPointer -> when(memsizer?.POINTER_MEM_SIZE) {
null -> other.isWord || other.isPointer
2u -> other.isWord || other.isPointer
else -> other.isLong || other.isPointer
}
this == STR && (other == UWORD || other == LONG) || (this == UWORD || this == LONG) && other == STR -> true
this == STR && other.isArray -> true
this.isArray && other == STR -> true
else -> false
}
}
// ============================================================================
// BaseDataType Extension Properties
// ============================================================================
val BaseDataType.isByte get() = this in arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE)
val BaseDataType.isUnsignedByte get() = this == BaseDataType.UBYTE
val BaseDataType.isSignedByte get() = this == BaseDataType.BYTE
val BaseDataType.isBool get() = this == BaseDataType.BOOL
val BaseDataType.isByteOrBool get() = this in arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.BOOL)
val BaseDataType.isWord get() = this in arrayOf(BaseDataType.UWORD, BaseDataType.WORD)
val BaseDataType.isUnsignedWord get() = this == BaseDataType.UWORD
val BaseDataType.isSignedWord get() = this == BaseDataType.WORD
val BaseDataType.isLong get() = this == BaseDataType.LONG
val BaseDataType.isFloat get() = this == BaseDataType.FLOAT
val BaseDataType.isInteger get() = this in setOf(BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)
val BaseDataType.maxUnsignedValue: Double
get() = when (this) {
BaseDataType.UBYTE -> 255.0
BaseDataType.BYTE -> 127.0
BaseDataType.UWORD -> 65535.0
BaseDataType.WORD -> 32767.0
BaseDataType.LONG -> 2147483647.0
else -> Double.MAX_VALUE
}
val BaseDataType.isIntegerOrBool get() = this in setOf(BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG, BaseDataType.BOOL)
val BaseDataType.isWordOrByteOrBool get() = this in setOf(BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.BOOL)
val BaseDataType.isNumeric get() = this == BaseDataType.FLOAT || this.isInteger
val BaseDataType.isNumericOrBool get() = this == BaseDataType.BOOL || this.isNumeric
val BaseDataType.isSigned get() = this in setOf(BaseDataType.BYTE, BaseDataType.WORD, BaseDataType.LONG, BaseDataType.FLOAT)
val BaseDataType.isUnsigned get() = !this.isSigned
val BaseDataType.isSignedInteger get() = this.isSigned && this.isInteger
val BaseDataType.isUnsignedInteger get() = this.isUnsigned && this.isInteger
val BaseDataType.isArray get() = this == BaseDataType.ARRAY || this == BaseDataType.ARRAY_SPLITW
val BaseDataType.isPointer get() = this == BaseDataType.POINTER
val BaseDataType.isStructInstance get() = this == BaseDataType.STRUCT_INSTANCE
val BaseDataType.isIterable get() = this in setOf(BaseDataType.STR, BaseDataType.ARRAY, BaseDataType.ARRAY_SPLITW)
val BaseDataType.isPassByRef get() = this.isIterable && !this.isPointer
val BaseDataType.isPassByValue get() = !this.isIterable || this.isPointer
/**
* Interface for types that can be used as subtypes in DataType.
* Primarily used for struct types.
*/
interface ISubType {
val scopedNameString: String
fun memsize(sizer: IMemSizer): Int
fun sameas(other: ISubType): Boolean
fun getFieldType(name: String): DataType?
}
/**
* Represents a complete data type in Prog8, including base type and optional subtype.
*
* DataType is immutable after construction. Use the companion object factory methods
* to create instances.
*
* @property base The base data type (e.g., UBYTE, WORD, ARRAY, POINTER)
* @property sub The subtype for arrays and strings (e.g., UBYTE for byte arrays)
* @property subType The structured subtype for pointers and struct instances
* @property subTypeFromAntlr Deferred subtype resolution from parser
*/
class DataType private constructor(
val base: BaseDataType,
val sub: BaseDataType?,
val pointeeSub: BaseDataType?,
var subType: ISubType?,
var subTypeFromAntlr: List<String>? = null
) {
init {
when {
base.isArray && sub == BaseDataType.POINTER -> {
require(pointeeSub != null || subType != null || subTypeFromAntlr != null)
}
base.isArray -> {
require(sub != null)
// subType and subTypeFromAntlr allowed for arrays with struct element types
// (from parser creating ARRAY(LONG) directly for 32-bit targets, or from VariousCleanups conversion)
if(base == BaseDataType.ARRAY_SPLITW)
require(sub == BaseDataType.UWORD || sub == BaseDataType.WORD)
}
base==BaseDataType.STR -> require(sub==BaseDataType.UBYTE) { "string subtype should be ubyte" }
base!=BaseDataType.POINTER -> require(sub == null) { "only string, array and pointer base types can have a subtype"}
else -> {
require(sub == null || (subType == null && subTypeFromAntlr == null)) {
"sub and subtype can't both be set"
}
}
}
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is DataType) return false
if (base != other.base || sub != other.sub || pointeeSub != other.pointeeSub) return false
val st1 = subType
val st2 = other.subType
if (st1 == st2) return true
if (st1 == null || st2 == null) return false
return st1.sameas(st2)
}
override fun hashCode(): Int = Objects.hash(base, sub, pointeeSub, subType)
fun setActualSubType(actualSubType: ISubType) {
subType = actualSubType
subTypeFromAntlr = null
}
// ============================================================================
// Companion Object - Factory Methods
// ============================================================================
companion object {
val UBYTE = DataType(BaseDataType.UBYTE, null, null, null)
val BYTE = DataType(BaseDataType.BYTE, null, null, null)
val UWORD = DataType(BaseDataType.UWORD, null, null, null)
val WORD = DataType(BaseDataType.WORD, null, null, null)
val LONG = DataType(BaseDataType.LONG, null, null, null)
val FLOAT = DataType(BaseDataType.FLOAT, null, null, null)
val BOOL = DataType(BaseDataType.BOOL, null, null, null)
val STR = DataType(BaseDataType.STR, BaseDataType.UBYTE, null, null)
val UNDEFINED = DataType(BaseDataType.UNDEFINED, null, null, null)
private val simpletypes = mapOf(
BaseDataType.UBYTE to DataType(BaseDataType.UBYTE, null, null, null),
BaseDataType.BYTE to DataType(BaseDataType.BYTE, null, null, null),
BaseDataType.UWORD to DataType(BaseDataType.UWORD, null, null, null),
BaseDataType.WORD to DataType(BaseDataType.WORD, null, null, null),
BaseDataType.LONG to DataType(BaseDataType.LONG, null, null, null),
BaseDataType.FLOAT to DataType(BaseDataType.FLOAT, null, null, null),
BaseDataType.BOOL to DataType(BaseDataType.BOOL, null, null, null),
BaseDataType.STR to DataType(BaseDataType.STR, BaseDataType.UBYTE, null, null),
BaseDataType.POINTER to DataType(BaseDataType.POINTER, null, null, null),
BaseDataType.UNDEFINED to DataType(BaseDataType.UNDEFINED, null, null, null)
)
fun forDt(dt: BaseDataType): DataType {
if(dt.isStructInstance)
return DataType(BaseDataType.STRUCT_INSTANCE, null, null, null)
return simpletypes.getValue(dt)
}
fun arrayFor(elementDt: BaseDataType, memsizer: IMemSizer): DataType {
require(elementDt != BaseDataType.POINTER) { "use arrayOfPointersTo for arrays of pointers" }
val actualElementDt = if(elementDt==BaseDataType.STR) {
memsizer.pointerBaseType
} else elementDt
if(actualElementDt.isNumericOrBool)
return DataType(BaseDataType.ARRAY, actualElementDt, null, null)
else
throw NoSuchElementException("invalid basic element dt $elementDt")
}
fun splitWordArrayFor(elementDt: BaseDataType): DataType {
require(elementDt.isWord) { "split word array element type must be word" }
return DataType(BaseDataType.ARRAY_SPLITW, elementDt, null, null)
}
fun arrayOfPointersTo(sub: BaseDataType): DataType =
DataType(BaseDataType.ARRAY, BaseDataType.POINTER, sub, null)
fun arrayOfPointersTo(structType: ISubType?): DataType =
DataType(BaseDataType.ARRAY, BaseDataType.POINTER, BaseDataType.STRUCT_INSTANCE, structType)
fun arrayOfPointersFromAntlrTo(sub: BaseDataType?, identifier: List<String>?): DataType =
DataType(BaseDataType.ARRAY, BaseDataType.POINTER, sub ?: BaseDataType.STRUCT_INSTANCE, null, identifier)
// array of struct instances: sub is STRUCT_INSTANCE, subType carries the resolved struct
fun arrayOfStructs(structType: ISubType): DataType = DataType(BaseDataType.ARRAY, BaseDataType.STRUCT_INSTANCE, null, structType)
fun arrayOfStructsFromAntlr(struct: List<String>): DataType =
DataType(BaseDataType.ARRAY, BaseDataType.STRUCT_INSTANCE, null, null, subTypeFromAntlr = struct)
fun pointer(base: BaseDataType): DataType = DataType(BaseDataType.POINTER, base, null, null)
fun pointer(dt: DataType): DataType = if(dt.isBasic)
DataType(BaseDataType.POINTER, dt.base, null, null)
else
DataType(BaseDataType.POINTER, null, null, dt.subType, dt.subTypeFromAntlr)
fun pointer(structType: ISubType): DataType = DataType(BaseDataType.POINTER, null, null, structType)
fun pointerFromAntlr(identifier: List<String>): DataType = DataType(BaseDataType.POINTER, null, null, null, identifier)
fun structInstance(type: ISubType?): DataType = DataType(BaseDataType.STRUCT_INSTANCE, sub=null, pointeeSub=null, type)
fun structInstanceFromAntlr(struct: List<String>): DataType = DataType(BaseDataType.STRUCT_INSTANCE, null, null, null, subTypeFromAntlr = struct)
}
// ============================================================================
// DataType Methods
// ============================================================================
fun elementToArray(target: ICompilationTarget, splitwords: Boolean = true): DataType {
fun pointerArray(): DataType =
if (subType != null)
arrayOfPointersTo(subType)
else if (subTypeFromAntlr != null)
arrayOfPointersFromAntlrTo(sub, subTypeFromAntlr)
else
arrayOfPointersTo(sub!!)
if(base == BaseDataType.STRUCT_INSTANCE) {
val st = subType
return if(st != null)
arrayOfStructs(st)
else
arrayOfStructsFromAntlr(subTypeFromAntlr!!)
}
if(base.isPointer)
return pointerArray()
if(!target.cpu.is6502)
return arrayFor(base, target)
return if (splitwords && (base == BaseDataType.UWORD || base == BaseDataType.WORD || base == BaseDataType.STR))
splitWordArrayFor(base)
else
arrayFor(base, target)
}
fun elementType(): DataType =
when {
isPointerArray -> {
if (subType != null) DataType(BaseDataType.POINTER, null, null, subType)
else if (subTypeFromAntlr != null) DataType(BaseDataType.POINTER, null, null, null, subTypeFromAntlr)
else DataType(BaseDataType.POINTER, pointeeSub!!, null, null)
}
base.isArray || base==BaseDataType.STR -> {
if (sub == BaseDataType.STRUCT_INSTANCE && subType != null)
return DataType(BaseDataType.STRUCT_INSTANCE, null, null, subType)
val dt = forDt(sub!!)
if (subType != null) DataType(BaseDataType.POINTER, null, null, subType) else dt
}
else -> throw IllegalArgumentException("not an array")
}
fun typeForUntypedAddressOf(msb: Boolean, mem: IMemSizer): DataType {
val untypedPointerType = if(mem.memorySize(BaseDataType.POINTER)>2) LONG else UWORD
if (isUndefined)
return if(msb) pointer(BaseDataType.UBYTE) else untypedPointerType
else {
if (isBasic)
return pointer(base)
if (isString)
return pointer(BaseDataType.UBYTE)
if (isPointer)
return untypedPointerType
if (isArray) {
val isSplit = base == BaseDataType.ARRAY_SPLITW ||
(isPointerArray && mem.memorySize(BaseDataType.POINTER) <= 2)
if (msb || isSplit)
return pointer(BaseDataType.UBYTE)
val elementDt = elementType()
if (elementDt.isBasic)
return pointer(elementDt)
return untypedPointerType
}
if (subType != null)
return pointer(this)
return untypedPointerType
}
}
fun dereference(): DataType {
require(isPointer || isUnsignedWord) { "cannot dereference non-pointer type $this"}
return when {
isUnsignedWord -> forDt(BaseDataType.UBYTE)
sub!=null -> forDt(sub)
subType!=null -> DataType(BaseDataType.STRUCT_INSTANCE, null, null, subType)
subTypeFromAntlr!=null -> DataType(BaseDataType.STRUCT_INSTANCE, null, null, null, subTypeFromAntlr)
else -> throw IllegalArgumentException("cannot dereference this pointer type")
}
}
override fun toString(): String = when(base) {
BaseDataType.ARRAY -> {
when(sub) {
BaseDataType.BOOL -> "bool[]"
BaseDataType.FLOAT -> "float[]"
BaseDataType.BYTE -> "byte[]"
BaseDataType.WORD -> "word[]"
BaseDataType.UBYTE -> "ubyte[]"
BaseDataType.UWORD -> "uword[]"
BaseDataType.LONG -> "long[]"
BaseDataType.POINTER -> {
val pointee = if (subType != null) subType!!.scopedNameString
else if (subTypeFromAntlr != null) "$subTypeFromAntlr"
else pointeeSub!!.name.lowercase()
"^^$pointee[]"
}
BaseDataType.STRUCT_INSTANCE -> if (subType != null) "${subType!!.scopedNameString}[]" else "$subTypeFromAntlr[]"
else -> throw IllegalArgumentException("invalid sub type")
}
}
BaseDataType.ARRAY_SPLITW -> {
when(sub) {
BaseDataType.WORD -> "word[] (split)"
BaseDataType.UWORD -> "uword[] (split)"
else -> throw IllegalArgumentException("invalid sub type")
}
}
BaseDataType.POINTER -> {
if(sub!=null) "^^${sub.name.lowercase()}" else if(subType!=null) "^^${subType!!.scopedNameString}" else "^^${subTypeFromAntlr}"
}
BaseDataType.STRUCT_INSTANCE -> {
sub?.name?.lowercase() ?: if (subType!=null) subType!!.scopedNameString else "$subTypeFromAntlr"
}
else -> base.name.lowercase()
}
fun sourceString(): String = when (base) {
BaseDataType.BOOL -> "bool"
BaseDataType.UBYTE -> "ubyte"
BaseDataType.BYTE -> "byte"
BaseDataType.UWORD -> "uword"
BaseDataType.WORD -> "word"
BaseDataType.LONG -> "long"
BaseDataType.FLOAT -> "float"
BaseDataType.STR -> "str"
BaseDataType.POINTER -> {
when {
sub!=null -> "^^${sub.name.lowercase()}"
subType!=null -> "^^${subType!!.scopedNameString}"
subTypeFromAntlr!=null -> "^^${subTypeFromAntlr!!.joinToString(".")}"
else -> "?????"
}
}
BaseDataType.STRUCT_INSTANCE -> {
when {
sub!=null -> sub.name.lowercase()
subType!=null -> subType!!.scopedNameString
subTypeFromAntlr!=null -> subTypeFromAntlr!!.joinToString(".")
else -> "?????"
}
}
BaseDataType.ARRAY -> {
when(sub) {
BaseDataType.UBYTE -> "ubyte["
BaseDataType.UWORD -> "@nosplit uword["
BaseDataType.BOOL -> "bool["
BaseDataType.BYTE -> "byte["
BaseDataType.WORD -> "@nosplit word["
BaseDataType.LONG -> "long["
BaseDataType.FLOAT -> "float["
BaseDataType.POINTER -> {
val pointee = if (subType != null) "^^${subType!!.scopedNameString}["
else if (subTypeFromAntlr != null) "^^${subTypeFromAntlr!!.joinToString(".")}["
else "^^${pointeeSub!!.name.lowercase()}["
pointee
}
BaseDataType.STRUCT_INSTANCE -> if (subType != null) "${subType!!.scopedNameString}[" else "$subTypeFromAntlr["
else -> throw IllegalArgumentException("invalid sub type")
}
}
BaseDataType.ARRAY_SPLITW -> {
when(sub) {
BaseDataType.UWORD -> "uword["
BaseDataType.WORD -> "word["
else -> throw IllegalArgumentException("invalid sub type")
}
}
BaseDataType.UNDEFINED -> throw IllegalArgumentException("wrong dt")
}
/**
* Check if this type is assignable to the given target type (perhaps via a typecast)
* without loss of precision.
*/
infix fun isAssignableTo(targetType: DataType) =
when(base) {
BaseDataType.BOOL -> targetType.base == BaseDataType.BOOL
BaseDataType.UBYTE -> targetType.base in setOf(BaseDataType.UBYTE, BaseDataType.WORD, BaseDataType.UWORD, BaseDataType.LONG, BaseDataType.FLOAT)
BaseDataType.BYTE -> targetType.base in setOf(BaseDataType.BYTE, BaseDataType.WORD, BaseDataType.LONG, BaseDataType.FLOAT)
BaseDataType.UWORD -> targetType.base in setOf(BaseDataType.UWORD, BaseDataType.LONG, BaseDataType.FLOAT, BaseDataType.POINTER) || targetType.isPointerArray
BaseDataType.WORD -> targetType.base in setOf(BaseDataType.WORD, BaseDataType.LONG, BaseDataType.FLOAT)
BaseDataType.LONG -> targetType.base in setOf(BaseDataType.LONG, BaseDataType.FLOAT, BaseDataType.POINTER) || targetType.isPointerArray
BaseDataType.FLOAT -> targetType.base in arrayOf(BaseDataType.FLOAT)
BaseDataType.STR -> targetType.base in setOf(BaseDataType.STR, BaseDataType.UWORD, BaseDataType.LONG) || (targetType.isPointer && targetType.sub==BaseDataType.UBYTE)
BaseDataType.ARRAY, BaseDataType.ARRAY_SPLITW -> {
if (isPointerArray) {
targetType.isPointerArray && if (subType != null && targetType.subType != null) subType!!.sameas(targetType.subType!!)
else if (subType == null && targetType.subType == null) pointeeSub == targetType.pointeeSub
else false
} else {
targetType.base in setOf(BaseDataType.ARRAY, BaseDataType.ARRAY_SPLITW) && targetType.sub == sub
}
}
BaseDataType.POINTER -> {
when {
targetType.base == BaseDataType.UWORD || targetType.base == BaseDataType.LONG -> true
targetType.isPointer -> this.isUnsignedWord || this == targetType
else -> false
}
}
BaseDataType.STRUCT_INSTANCE -> false // we cannot deal with actual struct instances yet in any shape or form (only getting fields from it)
BaseDataType.UNDEFINED -> false
}
fun largerSizeThan(other: DataType): Boolean = base.largerSizeThan(other.base)
fun equalsSize(other: DataType): Boolean = base.equalsSize(other.base)
fun equalsSize(other: DataType, memsizer: IMemSizer): Boolean = base.equalsSize(other.base, memsizer)
/**
* Returns the memory size in bytes.
* Note: for pointer types, size() doesn't return the size of the pointer itself
* but the size of the thing it points to.
*/
fun size(memsizer: IMemSizer): Int = when {
base == BaseDataType.ARRAY && sub == BaseDataType.POINTER -> memsizer.memorySize(BaseDataType.POINTER)
sub!=null -> memsizer.memorySize(sub)
subType!=null -> subType!!.memsize(memsizer)
else -> memsizer.memorySize(base)
}
// ============================================================================
// DataType Properties
// ============================================================================
val isBasic = sub==null && subType==null && subTypeFromAntlr==null
val isUndefined = base == BaseDataType.UNDEFINED
val isByte = base.isByte
val isUnsignedByte = base == BaseDataType.UBYTE
val isSignedByte = base == BaseDataType.BYTE
val isByteOrBool = base.isByteOrBool
val isWord = base.isWord
val isUnsignedWord = base == BaseDataType.UWORD
val isSignedWord = base == BaseDataType.WORD
val isInteger = base.isInteger
val isWordOrByteOrBool = base.isWordOrByteOrBool
val isIntegerOrBool = base.isIntegerOrBool
val isNumeric = base.isNumeric
val isNumericOrBool = base.isNumericOrBool
val isSigned = base.isSigned
val isUnsigned = !base.isSigned
val isSignedInteger = isSigned && isInteger
val isUnsignedInteger = isUnsigned && isInteger
val isArray = base.isArray
val isPointer = base.isPointer
val isPointerToByte = base.isPointer && sub?.isByteOrBool==true
val isPointerToWord = base.isPointer && sub?.isWord==true
val isStructInstance = base.isStructInstance
val isPointerArray = base == BaseDataType.ARRAY && sub == BaseDataType.POINTER
val isBoolArray = base == BaseDataType.ARRAY && sub == BaseDataType.BOOL
val isByteArray = base == BaseDataType.ARRAY && (sub == BaseDataType.UBYTE || sub == BaseDataType.BYTE)
val isUnsignedByteArray = base == BaseDataType.ARRAY && sub == BaseDataType.UBYTE
val isSignedByteArray = base == BaseDataType.ARRAY && sub == BaseDataType.BYTE
val isWordArray = (base == BaseDataType.ARRAY || base == BaseDataType.ARRAY_SPLITW) && (sub == BaseDataType.UWORD || sub == BaseDataType.WORD)
val isUnsignedWordArray = (base == BaseDataType.ARRAY || base == BaseDataType.ARRAY_SPLITW) && sub == BaseDataType.UWORD
val isSignedWordArray = (base == BaseDataType.ARRAY || base == BaseDataType.ARRAY_SPLITW) && sub == BaseDataType.WORD
val isLongArray = base == BaseDataType.ARRAY && sub == BaseDataType.LONG
val isFloatArray = base == BaseDataType.ARRAY && sub == BaseDataType.FLOAT
val isString = base == BaseDataType.STR
val isBool = base == BaseDataType.BOOL
val isFloat = base == BaseDataType.FLOAT
val isLong = base == BaseDataType.LONG
fun isStringly(memsizer: IMemSizer): Boolean =
base == BaseDataType.STR ||
(memsizer.POINTER_MEM_SIZE == 2u && base == BaseDataType.UWORD) ||
(memsizer.POINTER_MEM_SIZE > 2u && base == BaseDataType.LONG) ||
(base == BaseDataType.ARRAY && (sub == BaseDataType.UBYTE || sub == BaseDataType.BYTE))
fun isSplitWordArray(memsizer: IMemSizer): Boolean {
return when (base) {
BaseDataType.ARRAY_SPLITW -> true
BaseDataType.ARRAY if sub == BaseDataType.POINTER -> memsizer.POINTER_MEM_SIZE <= 2u
else -> false
}
}
val isSplitUnsignedWordArray = base == BaseDataType.ARRAY_SPLITW && sub == BaseDataType.UWORD
val isSplitSignedWordArray = base == BaseDataType.ARRAY_SPLITW && sub == BaseDataType.WORD
val isIterable = base.isIterable
val isPassByRef = base.isPassByRef
val isPassByValue = base.isPassByValue
}
+100 -105
View File
@@ -1,67 +1,14 @@
package prog8.code.core
enum class DataType {
UBYTE, // pass by value 8 bits unsigned
BYTE, // pass by value 8 bits signed
UWORD, // pass by value 16 bits unsigned
WORD, // pass by value 16 bits signed
LONG, // pass by value 32 bits signed
FLOAT, // pass by value machine dependent
BOOL, // pass by value bit 0 of a 8 bit byte
STR, // pass by reference
ARRAY_UB, // pass by reference
ARRAY_B, // pass by reference
ARRAY_UW, // pass by reference
ARRAY_UW_SPLIT, // pass by reference, lo/hi byte split
ARRAY_W, // pass by reference
ARRAY_W_SPLIT, // pass by reference, lo/hi byte split
ARRAY_F, // pass by reference
ARRAY_BOOL, // pass by reference
UNDEFINED;
/**
* is the type assignable to the given other type (perhaps via a typecast) without loss of precision?
*/
infix fun isAssignableTo(targetType: DataType) =
when(this) {
BOOL -> targetType == BOOL
UBYTE -> targetType.oneOf(UBYTE, WORD, UWORD, LONG, FLOAT)
BYTE -> targetType.oneOf(BYTE, WORD, LONG, FLOAT)
UWORD -> targetType.oneOf(UWORD, LONG, FLOAT)
WORD -> targetType.oneOf(WORD, LONG, FLOAT)
LONG -> targetType.oneOf(LONG, FLOAT)
FLOAT -> targetType.oneOf(FLOAT)
STR -> targetType.oneOf(STR, UWORD)
in ArrayDatatypes -> targetType == this
else -> false
}
fun oneOf(vararg types: DataType) = this in types
infix fun largerThan(other: DataType) =
when {
this == other -> false
this in ByteDatatypesWithBoolean -> false
this in WordDatatypes -> other in ByteDatatypesWithBoolean
this == LONG -> other in ByteDatatypesWithBoolean+WordDatatypes
this == STR && other == UWORD || this == UWORD && other == STR -> false
else -> true
}
infix fun equalsSize(other: DataType) =
when {
this == other -> true
this in ByteDatatypesWithBoolean -> other in ByteDatatypesWithBoolean
this in WordDatatypes -> other in WordDatatypes
this== STR && other== UWORD || this== UWORD && other== STR -> true
else -> false
}
}
enum class CpuRegister {
A,
X,
Y
Y,
// m68k:
D0, D1, D2, D3, D4, D5, D6, D7,
A0, A1, A2, A3, A4, A5, A6,
FP0, FP1, FP2, FP3, FP4, FP5, FP6, FP7
}
enum class RegisterOrPair {
@@ -75,19 +22,65 @@ enum class RegisterOrPair {
FAC2,
// cx16 virtual registers:
R0, R1, R2, R3, R4, R5, R6, R7,
R8, R9, R10, R11, R12, R13, R14, R15;
R8, R9, R10, R11, R12, R13, R14, R15,
// combined virtual registers to store 32 bits longs:
R0R1, R2R3, R4R5, R6R7, R8R9, R10R11, R12R13, R14R15,
// m68k data & address registers:
D0, D1, D2, D3, D4, D5, D6, D7,
A0, A1, A2, A3, A4, A5, A6,
// m68k FPU registers:
FP0, FP1, FP2, FP3, FP4, FP5, FP6, FP7;
companion object {
val names by lazy { entries.map { it.toString()} }
val names: Set<String> = entries.map { it.toString() }.toSet()
fun fromCpuRegister(cpu: CpuRegister): RegisterOrPair {
return when(cpu) {
CpuRegister.A -> A
CpuRegister.X -> X
CpuRegister.Y -> Y
CpuRegister.D0 -> D0
CpuRegister.D1 -> D1
CpuRegister.D2 -> D2
CpuRegister.D3 -> D3
CpuRegister.D4 -> D4
CpuRegister.D5 -> D5
CpuRegister.D6 -> D6
CpuRegister.D7 -> D7
CpuRegister.A0 -> A0
CpuRegister.A1 -> A1
CpuRegister.A2 -> A2
CpuRegister.A3 -> A3
CpuRegister.A4 -> A4
CpuRegister.A5 -> A5
CpuRegister.A6 -> A6
CpuRegister.FP0 -> FP0
CpuRegister.FP1 -> FP1
CpuRegister.FP2 -> FP2
CpuRegister.FP3 -> FP3
CpuRegister.FP4 -> FP4
CpuRegister.FP5 -> FP5
CpuRegister.FP6 -> FP6
CpuRegister.FP7 -> FP7
}
}
}
/**
* Returns the starting virtual register name for the current 32-bit combined virtual register
* @return The starting register name as a string, WITHOUT THE cx16 block scope prefix!
*/
fun startregname() = when(this) {
R0R1 -> "r0"
R2R3 -> "r2"
R4R5 -> "r4"
R6R7 -> "r6"
R8R9 -> "r8"
R10R11 -> "r10"
R12R13 -> "r12"
R14R15 -> "r14"
else -> throw IllegalArgumentException("must be a combined virtual register $this")
}
fun asCpuRegister(): CpuRegister = when(this) {
A -> CpuRegister.A
X -> CpuRegister.X
@@ -95,6 +88,22 @@ enum class RegisterOrPair {
else -> throw IllegalArgumentException("no cpu hardware register for $this")
}
fun asScopedNameVirtualReg(type: DataType?): List<String> {
require(this in Cx16VirtualRegisters || this in CombinedLongRegisters)
val suffix = when(type?.base) {
BaseDataType.UBYTE, BaseDataType.BOOL -> "L"
BaseDataType.BYTE -> "sL"
BaseDataType.WORD -> "s"
BaseDataType.UWORD, BaseDataType.POINTER, null -> ""
BaseDataType.LONG -> "sl"
else -> throw IllegalArgumentException("invalid register param type for cx16 virtual reg")
}
return listOf("cx16", name.lowercase()+suffix)
}
fun isWord() = this==AX || this == AY || this==XY || this in Cx16VirtualRegisters
fun isLong() = this in CombinedLongRegisters
} // only used in parameter and return value specs in asm subroutines
enum class Statusflag {
@@ -104,7 +113,7 @@ enum class Statusflag {
Pn; // don't use
companion object {
val names by lazy { entries.map { it.toString()} }
val names: Set<String> = entries.map { it.toString() }.toSet()
}
}
@@ -123,55 +132,33 @@ enum class BranchCondition {
VC
}
val ByteDatatypes = arrayOf(DataType.UBYTE, DataType.BYTE)
val ByteDatatypesWithBoolean = ByteDatatypes + DataType.BOOL
val WordDatatypes = arrayOf(DataType.UWORD, DataType.WORD)
val IntegerDatatypes = arrayOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.LONG)
val IntegerDatatypesWithBoolean = IntegerDatatypes + DataType.BOOL
val NumericDatatypes = arrayOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.LONG, DataType.FLOAT)
val NumericDatatypesWithBoolean = NumericDatatypes + DataType.BOOL
val SignedDatatypes = arrayOf(DataType.BYTE, DataType.WORD, DataType.LONG, DataType.FLOAT)
val ArrayDatatypes = arrayOf(DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_UW_SPLIT, DataType.ARRAY_W, DataType.ARRAY_W_SPLIT, DataType.ARRAY_F, DataType.ARRAY_BOOL)
val StringlyDatatypes = arrayOf(DataType.STR, DataType.ARRAY_UB, DataType.ARRAY_B, DataType.UWORD)
val SplitWordArrayTypes = arrayOf(DataType.ARRAY_UW_SPLIT, DataType.ARRAY_W_SPLIT)
val IterableDatatypes = arrayOf(
DataType.STR,
DataType.ARRAY_UB, DataType.ARRAY_B,
DataType.ARRAY_UW, DataType.ARRAY_W,
DataType.ARRAY_UW_SPLIT, DataType.ARRAY_W_SPLIT,
DataType.ARRAY_F, DataType.ARRAY_BOOL
)
val PassByValueDatatypes = NumericDatatypesWithBoolean
val PassByReferenceDatatypes = IterableDatatypes
val ArrayToElementTypes = mapOf(
DataType.STR to DataType.UBYTE,
DataType.ARRAY_B to DataType.BYTE,
DataType.ARRAY_UB to DataType.UBYTE,
DataType.ARRAY_W to DataType.WORD,
DataType.ARRAY_UW to DataType.UWORD,
DataType.ARRAY_W_SPLIT to DataType.WORD,
DataType.ARRAY_UW_SPLIT to DataType.UWORD,
DataType.ARRAY_F to DataType.FLOAT,
DataType.ARRAY_BOOL to DataType.BOOL
)
val ElementToArrayTypes = mapOf(
DataType.BYTE to DataType.ARRAY_B,
DataType.UBYTE to DataType.ARRAY_UB,
DataType.WORD to DataType.ARRAY_W,
DataType.UWORD to DataType.ARRAY_UW,
DataType.FLOAT to DataType.ARRAY_F,
DataType.BOOL to DataType.ARRAY_BOOL,
DataType.STR to DataType.ARRAY_UW // array of str is just an array of pointers
)
val Cx16VirtualRegisters = arrayOf(
val Cx16VirtualRegisters = setOf(
RegisterOrPair.R0, RegisterOrPair.R1, RegisterOrPair.R2, RegisterOrPair.R3,
RegisterOrPair.R4, RegisterOrPair.R5, RegisterOrPair.R6, RegisterOrPair.R7,
RegisterOrPair.R8, RegisterOrPair.R9, RegisterOrPair.R10, RegisterOrPair.R11,
RegisterOrPair.R12, RegisterOrPair.R13, RegisterOrPair.R14, RegisterOrPair.R15
)
val CombinedLongRegisters = setOf(
RegisterOrPair.R0R1,
RegisterOrPair.R2R3,
RegisterOrPair.R4R5,
RegisterOrPair.R6R7,
RegisterOrPair.R8R9,
RegisterOrPair.R10R11,
RegisterOrPair.R12R13,
RegisterOrPair.R14R15
)
val M68kRegisters = setOf(
RegisterOrPair.D0, RegisterOrPair.D1, RegisterOrPair.D2, RegisterOrPair.D3,
RegisterOrPair.D4, RegisterOrPair.D5, RegisterOrPair.D6, RegisterOrPair.D7,
RegisterOrPair.A0, RegisterOrPair.A1, RegisterOrPair.A2, RegisterOrPair.A3,
RegisterOrPair.A4, RegisterOrPair.A5, RegisterOrPair.A6,
RegisterOrPair.FP0, RegisterOrPair.FP1, RegisterOrPair.FP2, RegisterOrPair.FP3,
RegisterOrPair.FP4, RegisterOrPair.FP5, RegisterOrPair.FP6, RegisterOrPair.FP7
)
val CpuRegisters = setOf(
RegisterOrPair.A, RegisterOrPair.X, RegisterOrPair.Y,
RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY
@@ -181,7 +168,10 @@ val CpuRegisters = setOf(
enum class OutputType {
RAW,
PRG,
XEX
XEX,
ELF,
AMIGAHUNK,
LIBRARY
}
enum class CbmPrgLauncherType {
@@ -203,3 +193,8 @@ enum class ZeropageWish {
DONTCARE,
NOT_IN_ZEROPAGE
}
enum class SplitWish {
DONTCARE,
NOSPLIT
}
@@ -1,17 +0,0 @@
package prog8.code.core
import prog8.code.SymbolTable
import prog8.code.ast.PtProgram
interface ICodeGeneratorBackend {
fun generate(program: PtProgram,
symbolTable: SymbolTable,
options: CompilationOptions,
errors: IErrorReporter): IAssemblyProgram?
}
interface IAssemblyProgram {
val name: String
fun assemble(options: CompilationOptions, errors: IErrorReporter): Boolean
}
@@ -1,8 +1,112 @@
package prog8.code.core
import java.nio.file.Path
/**
* Identifies the target CPU type and its key characteristics that affect IR semantics.
*
* The most important property is [statusBitsOnMultiByteOps], which controls the IR
* status-bit contract (see IRInstructions.kt for the full spec):
*
* - When `true`, the IR generator is allowed to skip emitting explicit CMP/CMPI before
* branches that depend on the result of a previous "status-setting" instruction
* (LOAD, INC, DEC, AND, OR, XOR, etc.). The contract is: "this instruction sets
* Z and N based on the full multi-byte value." Backends for these targets must
* honor this contract (e.g., M68000's `move.w #imm,d0` naturally sets Z based on
* the 16-bit value, so the IR can rely on it).
*
* - When `false`, multi-byte operations on this target do NOT set status bits
* correctly for the full value (e.g., 6502's `dec lo` only sets Z based on the
* low byte of a 16-bit decrement). The IR generator must therefore always emit
* an explicit CMP/CMPI before any branch that depends on the result. Backends
* for these targets should NOT add `ora` postambles to set Z; instead they
* rely on the explicit CMP/CMPI emitted by the IR generator.
*
* For 8-bit CPUs (6502, 65C02) the natural status flags from a multi-byte
* cascade are misleading: Z is set based on the LAST byte operated on, not
* the full value. So we treat the contract as "no instruction sets status
* bits except CMP/CMPI/SEC/CLC/SGN/BITTST" and have the IR generator emit
* explicit compares. This avoids the trap of "this works for BYTE but
* silently breaks for WORD/LONG".
*/
enum class CpuType(val statusBitsOnMultiByteOps: Boolean) {
/** 8-bit NMOS 6502. Multi-byte ops don't set Z based on full value. */
CPU6502(false),
/** 8-bit CMOS 65C02. Same status-bit issue as plain 6502. */
CPU65C02(false),
/** 16/32 bit Motorola 68000. has single instructions that set status bits when dealing with multi byte operands */
M68000(true),
/** 32 bit Motorola 68020. has single instructions that set status bits when dealing with multi byte operands */
M68020(true),
/**
* Virtual machine target. We use `false` here so the IR generator always
* emits explicit CMP/CMPI; the VM's setResultReg then does NOT set Z/N
* flags (only CMP/CMPI/SEC/CLC/SGN/BITTST do). This matches the VM's
* existing documentation (VirtualMachine.kt top comment) and keeps the
* behavior consistent across all current targets.
*/
VIRTUAL(false)
;
/** True for the 6502-family targets (plain 6502 and 65C02). */
val is6502: Boolean
get() = this == CPU6502 || this == CPU65C02
val is68k: Boolean
get() = this == M68000 || this == M68020
/** True for targets that use the m68k-style hardware-register calling convention (D0-D7, A0-A6, FP0-FP7). */
val usesM68kConvention: Boolean
get() = is68k || this == VIRTUAL
/** True for big-endian targets. The 6502 family and the VM are little-endian. */
val isBigEndian: Boolean
get() = this == M68000 || this == M68020
}
interface ICompilationTarget: IStringEncoding, IMemSizer {
val name: String
val machine: IMachineDefinition
val FLOAT_MAX_NEGATIVE: Double
val FLOAT_MAX_POSITIVE: Double
val ARRAY_SIZE_LIMIT: UInt
val PROGRAM_LOAD_ADDRESS : UInt
val PROGRAM_MEMTOP_ADDRESS: UInt
val BSSHIGHRAM_START: UInt
val BSSHIGHRAM_END: UInt
val BSSGOLDENRAM_START: UInt
val BSSGOLDENRAM_END: UInt
val cpu: CpuType
var zeropage: Zeropage
val libraryPath: Path?
val customLauncher: List<String>
val additionalAssemblerOptions: List<String>
val defaultOutputType: OutputType
val defaultLauncherType: CbmPrgLauncherType
val supportsBankedCalls: Boolean
/**
* True when the code generator allocates subroutine locals and per-activation intermediate values
* in a stack frame instead of static memory, so a subroutine on a call-graph cycle can have more
* than one live activation. False means two live activations would share the same storage.
*/
val supportsStackFrames: Boolean
fun initializeMemoryAreas(compilerOptions: CompilationOptions)
fun getFloatAsmBytes(num: Number): String
fun convertFloatToBytes(num: Double): List<UByte>
fun convertBytesToFloat(bytes: List<UByte>): Double
/**
* Launches an emulator to run the compiled program artifact.
* [programFile] is the exact artifact path including its extension; launchers must use it
* verbatim, without stripping or appending one.
*/
fun launchEmulator(selectedEmulator: Int, programFile: Path, quiet: Boolean)
fun isIOAddress(address: UInt): Boolean
override fun encodeString(str: String, encoding: Encoding): List<UByte>
override fun decodeString(bytes: Iterable<UByte>, encoding: Encoding): String
@@ -4,7 +4,7 @@ interface IErrorReporter {
fun err(msg: String, position: Position)
fun warn(msg: String, position: Position)
fun info(msg: String, position: Position)
fun undefined(symbol: List<String>, position: Position)
fun undefined(symbol: List<String>, suggestImport: Boolean=false, position: Position)
fun noErrors(): Boolean
fun report()
fun finalizeNumErrors(numErrors: Int, numWarnings: Int, numInfos: Int) {
@@ -13,4 +13,6 @@ interface IErrorReporter {
}
fun noErrorForLine(position: Position): Boolean
fun printSingleError(errormessage: String)
}
@@ -1,36 +0,0 @@
package prog8.code.core
import java.nio.file.Path
enum class CpuType {
CPU6502,
CPU65c02,
VIRTUAL
}
interface IMachineDefinition {
val FLOAT_MAX_NEGATIVE: Double
val FLOAT_MAX_POSITIVE: Double
val FLOAT_MEM_SIZE: Int
val STARTUP_CODE_RESERVED_SIZE: UInt // this is here, so that certain compiler targets are able to tune this
val PROGRAM_LOAD_ADDRESS : UInt
val PROGRAM_MEMTOP_ADDRESS: UInt
val BSSHIGHRAM_START: UInt
val BSSHIGHRAM_END: UInt
val BSSGOLDENRAM_START: UInt
val BSSGOLDENRAM_END: UInt
val cpu: CpuType
var zeropage: Zeropage
var golden: GoldenRam
fun initializeMemoryAreas(compilerOptions: CompilationOptions)
fun getFloatAsmBytes(num: Number): String
fun convertFloatToBytes(num: Double): List<UByte>
fun convertBytesToFloat(bytes: List<UByte>): Double
fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path)
fun isIOAddress(address: UInt): Boolean
}
+24 -2
View File
@@ -1,6 +1,28 @@
package prog8.code.core
interface IMemSizer {
fun memorySize(dt: DataType): Int
fun memorySize(arrayDt: DataType, numElements: Int): Int
val FLOAT_MEM_SIZE: UInt
val POINTER_MEM_SIZE: UInt
val pointerType: DataType
get() = if(POINTER_MEM_SIZE > 2u) DataType.LONG else DataType.UWORD
val pointerBaseType: BaseDataType
get() = if(POINTER_MEM_SIZE > 2u) BaseDataType.LONG else BaseDataType.UWORD
fun memorySize(dt: DataType, numElements: Int?): Int
fun memorySize(dt: BaseDataType): Int {
if(dt.isPassByRef)
return POINTER_MEM_SIZE.toInt()
try {
return memorySize(DataType.forDt(dt), null)
} catch (x: NoSuchElementException) {
throw IllegalArgumentException(x.message)
}
}
fun isSplitWordArray(dt: DataType): Boolean {
return dt.isSplitWordArray(this)
}
}
@@ -9,7 +9,8 @@ enum class Encoding(val prefix: String) {
ISO5("iso5"), // cx16 (iso-8859-5, cyrillic)
ISO16("iso16"), // cx16 (iso-8859-16, eastern european)
CP437("cp437"), // cx16 (ibm pc, codepage 437)
KATAKANA("kata") // cx16 (katakana)
KATAKANA("kata"), // cx16 (katakana)
C64OS("c64os") // c64 (C64 OS)
}
interface IStringEncoding {
+57 -78
View File
@@ -22,40 +22,53 @@ abstract class MemoryAllocator(protected val options: CompilationOptions) {
abstract class Zeropage(options: CompilationOptions): MemoryAllocator(options) {
abstract val SCRATCH_B1 : UInt // temp storage for a single byte
abstract val SCRATCH_REG : UInt // temp storage for a register, must be B1+1
abstract val SCRATCH_W1 : UInt // temp storage 1 for a word $fb+$fc
abstract val SCRATCH_W2 : UInt // temp storage 2 for a word $fb+$fc
abstract val SCRATCH_REG : UInt // temp storage for a register byte, must be B1+1
abstract val SCRATCH_W1 : UInt // temp storage 1 for a word
abstract val SCRATCH_W2 : UInt // temp storage 2 for a word
abstract val SCRATCH_PTR : UInt // temp storage for a pointer
// the variables allocated into Zeropage.
// Collections for zeropage allocation (single-threaded usage)
// name (scoped) ==> pair of address to (Datatype + bytesize)
val allocatedVariables = mutableMapOf<String, VarAllocation>()
val free = mutableSetOf<UInt>() // subclasses must set this to the appropriate free locations.
val free = mutableListOf<UInt>() // subclasses must set this to the appropriate free locations.
/**
* Report a warning for every scratch byte that is excluded from allocation by a %zpreserved
* or %zpallowed directive. The compiler's code generators always use these fixed scratch
* locations internally (P8ZP_SCRATCH_*), so a %zpreserved/%zpallowed range that excludes one
* of them would let the compiler overwrite memory the user explicitly wants to protect.
*/
fun checkScratchConflicts(errors: IErrorReporter) {
if(options.zeropage== ZeropageType.DONTUSE)
return
val scratchBytes = listOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_W1, SCRATCH_W1 + 1u, SCRATCH_W2, SCRATCH_W2 + 1u, SCRATCH_PTR, SCRATCH_PTR + 1u)
for(byte in scratchBytes) {
val preserved = options.zpReserved.any { byte in it }
val allowed = options.zpAllowed.any { byte in it }
if(preserved || !allowed)
errors.warn("zero-page address $${byte.toString(16)} is a fixed scratch location used by the compiler (P8ZP_SCRATCH_*), but it is excluded by a %zpreserved or %zpallowed directive", Position.DUMMY)
}
}
fun removeReservedFromFreePool() {
synchronized(this) {
for (reserved in options.zpReserved)
reserve(reserved)
for (reserved in options.zpReserved)
reserve(reserved)
free.removeAll(setOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_W1, SCRATCH_W1 + 1u, SCRATCH_W2, SCRATCH_W2 + 1u))
}
free.removeAll(setOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_W1, SCRATCH_W1 + 1u, SCRATCH_W2, SCRATCH_W2 + 1u, SCRATCH_PTR, SCRATCH_PTR+1u))
}
fun retainAllowed() {
synchronized(this) {
for(allowed in options.zpAllowed)
free.retainAll { it in allowed }
}
for(allowed in options.zpAllowed)
free.retainAll { it in allowed }
}
fun availableBytes() = if(options.zeropage== ZeropageType.DONTUSE) 0 else free.size
fun hasByteAvailable() = if(options.zeropage== ZeropageType.DONTUSE) false else free.isNotEmpty()
fun hasByteAvailable() = options.zeropage != ZeropageType.DONTUSE && free.isNotEmpty()
fun hasWordAvailable(): Boolean {
if(options.zeropage== ZeropageType.DONTUSE)
return false
return free.windowed(2).any { it[0] == it[1] - 1u }
return options.zeropage != ZeropageType.DONTUSE && free.windowed(2).any { it[0] == it[1] - 1u }
}
override fun allocate(name: String,
@@ -64,15 +77,16 @@ abstract class Zeropage(options: CompilationOptions): MemoryAllocator(options) {
position: Position?,
errors: IErrorReporter): Result<VarAllocation, MemAllocationError> {
require(name.isEmpty() || name !in allocatedVariables) {"name can't be allocated twice"}
require(name.isEmpty() || !allocatedVariables.containsKey(name)) {"name can't be allocated twice"}
if(options.zeropage== ZeropageType.DONTUSE)
return Err(MemAllocationError("zero page usage has been disabled"))
val size: Int =
when (datatype) {
in IntegerDatatypesWithBoolean -> options.compTarget.memorySize(datatype)
DataType.STR, in ArrayDatatypes -> {
when {
datatype.isIntegerOrBool -> options.compTarget.memorySize(datatype, null)
datatype.isPointer -> options.compTarget.memorySize(datatype, null)
datatype.isString || datatype.isArray -> {
val memsize = options.compTarget.memorySize(datatype, numElements!!)
if(position!=null)
errors.warn("allocating a large value in zeropage; str/array $memsize bytes", position)
@@ -80,9 +94,9 @@ abstract class Zeropage(options: CompilationOptions): MemoryAllocator(options) {
errors.warn("$name: allocating a large value in zeropage; str/array $memsize bytes", Position.DUMMY)
memsize
}
DataType.FLOAT -> {
datatype.isFloat -> {
if (options.floats) {
val memsize = options.compTarget.memorySize(DataType.FLOAT)
val memsize = options.compTarget.memorySize(DataType.FLOAT, null)
if(position!=null)
errors.warn("allocating a large value in zeropage; float $memsize bytes", position)
else
@@ -93,19 +107,17 @@ abstract class Zeropage(options: CompilationOptions): MemoryAllocator(options) {
else -> throw MemAllocationError("weird dt")
}
synchronized(this) {
if(free.size > 0) {
if(size==1) {
for(candidate in free.minOrNull()!! .. free.maxOrNull()!!+1u) {
if(oneSeparateByteFree(candidate))
return Ok(VarAllocation(makeAllocation(candidate, 1, datatype, name), datatype,1))
}
return Ok(VarAllocation(makeAllocation(free[0], 1, datatype, name), datatype,1))
}
if(free.isNotEmpty()) {
if(size==1) {
for(candidate in free.minOrNull()!! .. free.maxOrNull()!!+1u) {
if (sequentialFree(candidate, size))
return Ok(VarAllocation(makeAllocation(candidate, size, datatype, name), datatype, size))
if(oneSeparateByteFree(candidate))
return Ok(VarAllocation(makeAllocation(candidate, 1, datatype, name), datatype,1))
}
return Ok(VarAllocation(makeAllocation(free.first(), 1, datatype, name), datatype,1))
}
for(candidate in free.minOrNull()!! .. free.maxOrNull()!!+1u) {
if (sequentialFree(candidate, size))
return Ok(VarAllocation(makeAllocation(candidate, size, datatype, name), datatype, size))
}
}
@@ -118,56 +130,23 @@ abstract class Zeropage(options: CompilationOptions): MemoryAllocator(options) {
require(size>=0)
free.removeAll(address until address+size.toUInt())
if(name.isNotEmpty()) {
allocatedVariables[name] = when(datatype) {
in NumericDatatypes, DataType.BOOL -> VarAllocation(address, datatype, size) // numerical variables in zeropage never have an initial value here because they are set in separate initializer assignments
DataType.STR -> VarAllocation(address, datatype, size)
in ArrayDatatypes -> VarAllocation(address, datatype, size)
allocatedVariables[name] = when {
datatype.isNumericOrBool -> VarAllocation(address, datatype, size) // numerical variables in zeropage never have an initial value here because they are set in separate initializer assignments
datatype.isString -> VarAllocation(address, datatype, size)
datatype.isArray -> VarAllocation(address, datatype, size)
datatype.isPointer -> VarAllocation(address, datatype, size)
else -> throw AssemblyError("invalid dt")
}
}
return address
}
private fun oneSeparateByteFree(address: UInt) = address in free && address-1u !in free && address+1u !in free
private fun oneSeparateByteFree(address: UInt) =
address in free &&
(address == 0u || address-1u !in free) &&
address+1u !in free
private fun sequentialFree(address: UInt, size: Int): Boolean {
require(size>0)
return free.containsAll((address until address+size.toUInt()).toList())
}
abstract fun allocateCx16VirtualRegisters()
}
// TODO: this class is not yet used
class GoldenRam(options: CompilationOptions, val region: UIntRange): MemoryAllocator(options) {
private var nextLocation: UInt = region.first
override fun allocate(
name: String,
datatype: DataType,
numElements: Int?,
position: Position?,
errors: IErrorReporter): Result<VarAllocation, MemAllocationError> {
val size: Int =
when (datatype) {
in IntegerDatatypesWithBoolean -> options.compTarget.memorySize(datatype)
DataType.STR, in ArrayDatatypes -> {
options.compTarget.memorySize(datatype, numElements!!)
}
DataType.FLOAT -> {
if (options.floats) {
options.compTarget.memorySize(DataType.FLOAT)
} else return Err(MemAllocationError("floating point option not enabled"))
}
else -> throw MemAllocationError("weird dt")
}
return if(nextLocation<=region.last && (region.last + 1u - nextLocation) >= size.toUInt()) {
val result = Ok(VarAllocation(nextLocation, datatype, size))
nextLocation += size.toUInt()
result
} else
Err(MemAllocationError("no more free space in Golden RAM to allocate $size sequential bytes"))
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
package prog8.code.core
val AssociativeOperators = setOf("+", "*", "&", "|", "^", "==", "!=", "xor") // note: and,or are no longer associative because of Shortcircuit/McCarthy evaluation
val CommutativeOperators = setOf("+", "*", "&", "|", "^", "==", "!=", "xor") // note: and,or are not commutative because of Shortcircuit/McCarthy evaluation
val ComparisonOperators = setOf("==", "!=", "<", ">", "<=", ">=")
val LogicalOperators = setOf("and", "or", "xor", "not", "in")
val BitwiseOperators = setOf("&", "|", "^", "~")
@@ -0,0 +1,80 @@
package prog8.code.core
import prog8.code.target.VMTarget
import java.nio.file.Path
import kotlin.io.path.extension
import kotlin.io.path.name
/** VICE/box16 monitor (symbol) list file name for an artifact stem. */
fun viceMonListName(stem: String) = "$stem.vice-mon-list"
/**
* Artifact stem of a user-supplied `-o` output file name.
* A dot at index 0 is not an extension separator: ".pgz" keeps its whole name.
* Only applied to `-o`; the legacy program stem (source name without extension) is used verbatim.
*/
fun outputStemOf(name: Path): String {
val filename = name.name
val dotIndex = filename.lastIndexOf('.')
return if (dotIndex <= 0) filename else filename.substring(0, dotIndex)
}
/**
* The final program artifact path: [CompilationOptions.outputFile] verbatim when set,
* otherwise [defaultName] plus the extension for [CompilationOptions.output], in [CompilationOptions.outputDir].
* RAW and LIBRARY both use ".bin"; AMIGAHUNK has no extension.
* On the virtual target the artifact is the IR file, so ".p8ir" is always enforced on -o.
*/
fun CompilationOptions.programFile(defaultName: String): Path {
// VMTarget's defaultOutputType = PRG is misleading: its artifact is the .p8ir file, never PRG.
// The VM identifies the IR by its extension, so -o is not verbatim here: ".p8ir" is enforced.
// Only the exact lowercase extension is recognized (same rule as -vm in CompilerMain).
if(compTarget is VMTarget) {
val ir = outputFile ?: return outputDir.resolve("$defaultName.p8ir")
return if (ir.extension=="p8ir") ir else ir.resolveSibling("${ir.name}.p8ir")
}
outputFile?.let { return it }
val filename = when(output) {
OutputType.PRG -> "$defaultName.prg"
OutputType.XEX -> "$defaultName.xex"
OutputType.RAW -> "$defaultName.bin"
OutputType.LIBRARY -> "$defaultName.bin"
OutputType.ELF -> "$defaultName.elf"
OutputType.AMIGAHUNK -> defaultName
}
return outputDir.resolve(filename)
}
/**
* Output artifact naming.
* Invariant: [asm] must resolve into the same directory as `CompilationOptions.outputDir`,
* because 64tass resolves `.binary` includes relative to the generated `.asm`.
*/
class OutputFiles(val programFile: Path, val stem: String, val dir: Path) {
fun asm() = dir.resolve("$stem.asm")
fun list() = dir.resolve("$stem.list")
fun viceMonList() = dir.resolve(viceMonListName(stem))
fun binFile() = dir.resolve("$stem.bin")
fun ir() = dir.resolve("$stem.p8ir")
fun bankedCalls() = dir.resolve("$stem.bankedcalls")
fun obj() = dir.resolve("$stem.o")
fun linkScript() = dir.resolve("$stem.link.ld")
companion object {
/**
* Builds the output file set. Without `-o` the stem is [defaultName] verbatim
* (outputStemOf is only applied to the `-o` name). With `-o` the stem is derived
* from the resolved artifact name, so it also covers the virtual target appending
* ".p8ir". [dir] is the program file's parent, or [CompilationOptions.outputDir]
* for a bare -o filename.
*/
fun of(options: CompilationOptions, defaultName: String): OutputFiles {
val programFile = options.programFile(defaultName)
val stem = options.outputFile?.let { outputStemOf(programFile) } ?: defaultName
val dir = programFile.parent ?: options.outputDir
return OutputFiles(programFile, stem, dir)
}
}
}
+20 -9
View File
@@ -1,21 +1,32 @@
package prog8.code.core
import prog8.code.core.SourceCode.Companion.LIBRARYFILEPREFIX
import prog8.code.sanitize
import prog8.code.source.SourceCode
import java.nio.file.InvalidPathException
import kotlin.io.path.Path
import kotlin.io.path.absolute
data class Position(val file: String, val line: Int, val startCol: Int, val endCol: Int) {
override fun toString(): String = "[$file: line $line col ${startCol+1}-${endCol+1}]"
/**
* Source code position.
*/
data class Position(
val file: String,
val line: Int, // line number (1-based)
val startCol: Int, // start column (1-based, tab-expanded)
val endCol: Int // end column (1-based, tab-expanded)
) {
override fun toString(): String {
return "[$file: line $line col ${startCol}-${endCol}]"
}
fun toClickableStr(): String {
if(this===DUMMY)
return ""
if(file.startsWith(LIBRARYFILEPREFIX))
if(SourceCode.isLibraryResource(file))
return "$file:$line:$startCol:"
return try {
val path = Path(file).absolute().normalize().toString()
"file://$path:$line:$startCol:"
} catch(x: InvalidPathException) {
val path = Path(file).sanitize().toUri().toString()
"$path:$line:$startCol:"
} catch(_: InvalidPathException) {
// this can occur on Windows when the source origin contains "invalid" characters such as ':'
"file://$file:$line:$startCol:"
}
@@ -24,4 +35,4 @@ data class Position(val file: String, val line: Int, val startCol: Int, val endC
companion object {
val DUMMY = Position("~dummy~", 0, 0, 0)
}
}
}
@@ -0,0 +1,80 @@
package prog8.code.cpu6502
// Horner ("shift-add") expansion of a multiply by a small compile-time constant, for the 6502 and
// 65C02 backends. The runtime routines prog8_math.multiply_words / multiply_bytes cost the same
// whatever the constant is (~442 and ~130 cycles), while this expansion costs O(bit length), so
// for a small constant inlining wins. It generalises the hand-written prog8_math.mul_word_N /
// mul_byte_N routines, which are themselves unrolled Horner chains (mul_word_3 is "AY = AY*2 + AY",
// one Horner step for 11).
//
// The sequences live here rather than in either backend because the register bookkeeping is easy to
// get subtly wrong and the two backends must not drift apart.
//
// The gate is on generated size, not on the constant's magnitude: cycles alone would argue for
// expanding nearly every multiply and bloating every program. Budgets are the max instruction count
// the expansion may take; the call sequence each replaces is 6 instructions.
private const val WORD_BUDGET = 32
private const val BYTE_BUDGET = 24
// --- byte ---
// Contract: A holds the multiplicand. Result in A. Only A and one scratch byte are live, so there
// is no second register to keep in sync (unlike the word case, where a bare doubling leaves the
// high byte stale in Y).
fun byteShiftAddExpansion(value: Int): List<String>? {
if (value !in 3..255)
return null
val bitlen = 31 - Integer.numberOfLeadingZeros(value)
val popcount = Integer.bitCount(value)
if (1 + (bitlen-1) + 2*(popcount-1) > BYTE_BUDGET)
return null
val result = ArrayList<String>(1 + 3*bitlen)
result.add("sta P8ZP_SCRATCH_REG") // keep x for the conditional adds
for (bit in (bitlen-1) downTo 0) {
result.add("asl a") // r = r*2
if (value and (1 shl bit) != 0) { // r += x
result.add("clc")
result.add("adc P8ZP_SCRATCH_REG")
}
}
return result
}
// --- word ---
// Contract on entry: A = r.lo, Y = r.hi, P8ZP_SCRATCH_W1 = r, P8ZP_SCRATCH_W2 = x (all 16-bit,
// little-endian: byte 0 is the low byte). On exit: A = result.lo, Y = result.hi.
//
// Two things this sequence must get right, both learned the hard way:
// * the add step must store the new high byte back to W1+1 as well as to Y. Writing it only to Y
// leaves W1+1 stale, and the next step's 'rol P8ZP_SCRATCH_W1+1' would then double the wrong
// high byte.
// * a trailing bare doubling (any even constant) updates A and W1+1 but not Y, so Y needs an
// explicit reload at the end. It cannot be 'tay', because at that point A holds the low byte.
fun wordShiftAddExpansion(value: Int): List<String>? {
if (value < 3)
return null
val bitlen = 31 - Integer.numberOfLeadingZeros(value)
val popcount = Integer.bitCount(value)
if (1 + 2*(bitlen-1) + 7*(popcount-1) > WORD_BUDGET)
return null
val result = ArrayList<String>(2 + 9*bitlen)
for (bit in (bitlen-1) downTo 0) {
result.add("asl a") // r = r*2
result.add("rol P8ZP_SCRATCH_W1+1")
if (value and (1 shl bit) != 0) { // r += x
result.add("clc")
result.add("adc P8ZP_SCRATCH_W2")
result.add("sta P8ZP_SCRATCH_W1")
result.add("lda P8ZP_SCRATCH_W1+1")
result.add("adc P8ZP_SCRATCH_W2+1")
result.add("sta P8ZP_SCRATCH_W1+1")
result.add("tay")
result.add("lda P8ZP_SCRATCH_W1")
}
}
if (value and 1 == 0)
result.add("ldy P8ZP_SCRATCH_W1+1")
return result
}
@@ -1,180 +0,0 @@
package prog8.code.optimize
import prog8.code.StExtSub
import prog8.code.SymbolTable
import prog8.code.ast.*
import prog8.code.core.*
fun optimizeIntermediateAst(program: PtProgram, options: CompilationOptions, st: SymbolTable, errors: IErrorReporter) {
if (!options.optimize)
return
while (errors.noErrors() &&
(optimizeBitTest(program, options)
+ optimizeAssignTargets(program, st, errors)) > 0
) {
// keep rolling
}
}
private fun walkAst(root: PtNode, act: (node: PtNode, depth: Int) -> Boolean) {
fun recurse(node: PtNode, depth: Int) {
if(act(node, depth))
node.children.forEach { recurse(it, depth+1) }
}
recurse(root, 0)
}
private fun optimizeAssignTargets(program: PtProgram, st: SymbolTable, errors: IErrorReporter): Int {
var changes = 0
walkAst(program) { node: PtNode, depth: Int ->
if(node is PtAssignment) {
val value = node.value
val functionName = when(value) {
is PtBuiltinFunctionCall -> value.name
is PtFunctionCall -> value.name
else -> null
}
if(functionName!=null) {
val stNode = st.lookup(functionName)
if (stNode is StExtSub) {
require(node.children.size==stNode.returns.size+1) {
"number of targets must match return values"
}
node.children.zip(stNode.returns).withIndex().forEach { (index, xx) ->
val target = xx.first as PtAssignTarget
val returnedRegister = xx.second.register.registerOrPair
if(returnedRegister!=null && !target.void && target.identifier!=null) {
if(isSame(target.identifier!!, xx.second.type, returnedRegister)) {
// output register is already identical to target register, so it can become void
val voidTarget = PtAssignTarget(true, target.position)
node.children[index] = voidTarget
voidTarget.parent = node
changes++
}
}
}
}
if(node.children.dropLast(1).all { (it as PtAssignTarget).void }) {
// all targets are now void, the whole assignment can be discarded and replaced by just a (void) call to the subroutine
val index = node.parent.children.indexOf(node)
val voidCall = PtFunctionCall(functionName, true, DataType.UNDEFINED, value.position)
value.children.forEach { voidCall.add(it) }
node.parent.children[index] = voidCall
voidCall.parent = node.parent
changes++
}
}
}
true
}
return changes
}
private fun optimizeBitTest(program: PtProgram, options: CompilationOptions): Int {
if(options.compTarget.machine.cpu == CpuType.VIRTUAL)
return 0 // the special bittest optimization is not yet valid for the IR
fun makeBittestCall(condition: PtBinaryExpression, and: PtBinaryExpression, variable: PtIdentifier, bitmask: Int): PtBuiltinFunctionCall {
require(bitmask==128 || bitmask==64)
val setOrNot = if(condition.operator=="!=") "set" else "notset"
val bittestCall = PtBuiltinFunctionCall("prog8_ifelse_bittest_$setOrNot", false, true, DataType.BOOL, condition.position)
bittestCall.add(variable)
if(bitmask==128)
bittestCall.add(PtNumber(DataType.UBYTE, 7.0, and.right.position))
else
bittestCall.add(PtNumber(DataType.UBYTE, 6.0, and.right.position))
return bittestCall
}
fun isAndByteCondition(condition: PtBinaryExpression?): Triple<PtBinaryExpression, PtIdentifier, Int>? {
if(condition!=null && (condition.operator=="==" || condition.operator=="!=")) {
if (condition.right.asConstInteger() == 0) {
val and = condition.left as? PtBinaryExpression
if (and != null && and.operator == "&" && and.type == DataType.UBYTE) {
val bitmask = and.right.asConstInteger()
if(bitmask==128 || bitmask==64) {
val variable = and.left as? PtIdentifier
if (variable != null && variable.type in ByteDatatypes) {
return Triple(and, variable, bitmask)
}
val typecast = and.left as? PtTypeCast
if (typecast != null && typecast.type == DataType.UBYTE) {
val castedVariable = typecast.value as? PtIdentifier
if(castedVariable!=null && castedVariable.type in ByteDatatypes)
return Triple(and, castedVariable, bitmask)
}
}
}
}
}
return null
}
var changes = 0
var recurse = true
walkAst(program) { node: PtNode, depth: Int ->
if(node is PtIfElse) {
val condition = node.condition as? PtBinaryExpression
val check = isAndByteCondition(condition)
if(check!=null) {
val (and, variable, bitmask) = check
val bittestCall = makeBittestCall(condition!!, and, variable, bitmask)
val ifElse = PtIfElse(node.position)
ifElse.add(bittestCall)
ifElse.add(node.ifScope)
if (node.hasElse())
ifElse.add(node.elseScope)
val index = node.parent.children.indexOf(node)
node.parent.children[index] = ifElse
ifElse.parent = node.parent
changes++
recurse = false
}
}
if (node is PtIfExpression) {
val condition = node.condition as? PtBinaryExpression
val check = isAndByteCondition(condition)
if(check!=null) {
val (and, variable, bitmask) = check
val bittestCall = makeBittestCall(condition!!, and, variable, bitmask)
node.children[0] = bittestCall
bittestCall.parent = node
changes++
recurse = false
}
}
recurse
}
return changes
}
internal fun isSame(identifier: PtIdentifier, type: DataType, returnedRegister: RegisterOrPair): Boolean {
if(returnedRegister in Cx16VirtualRegisters) {
val regname = returnedRegister.name.lowercase()
val identifierRegName = identifier.name.substringAfterLast('.')
/*
cx16.r? UWORD
cx16.r?s WORD
cx16.r?L UBYTE
cx16.r?H UBYTE
cx16.r?sL BYTE
cx16.r?sH BYTE
*/
if(identifier.type in ByteDatatypes && type in ByteDatatypes) {
if(identifier.name.startsWith("cx16.$regname") && identifierRegName.startsWith(regname)) {
return identifierRegName.substring(2) in arrayOf("", "L", "sL") // note: not the -H (msb) variants!
}
}
else if(identifier.type in WordDatatypes && type in WordDatatypes) {
if(identifier.name.startsWith("cx16.$regname") && identifierRegName.startsWith(regname)) {
return identifierRegName.substring(2) in arrayOf("", "s")
}
}
}
return false // there are no identifiers directly corresponding to cpu registers
}
@@ -0,0 +1,76 @@
package prog8.code.source
import prog8.code.core.Position
import prog8.code.sanitize
import java.nio.file.Path
import java.util.concurrent.ConcurrentHashMap
import kotlin.io.path.Path
// Resource caching "filesystem".
// Note that it leaves the decision to load a resource or an actual disk file to the caller.
// Thread-safe: uses ConcurrentHashMap for all caches.
object ImportFileSystem {
val userHome: Path get() = Path.of(System.getProperty("user.home"))
fun expandTilde(path: String): String = if (path.startsWith("~")) {
userHome.toString() + path.drop(1)
} else {
path
}
fun expandTilde(path: Path): Path = Path(expandTilde(path.toString()))
fun getFile(path: Path, isLibrary: Boolean=false): SourceCode {
val normalized = path.sanitize()
return cache.computeIfAbsent(normalized.toString().lowercase()) {
SourceCode.File(normalized, isLibrary)
}
}
fun getResource(name: String): SourceCode {
return cache.computeIfAbsent(name.lowercase()) {
SourceCode.Resource(name)
}
}
fun clearCaches() {
cache.clear()
lineSpanCache.clear()
}
fun retrieveSourceLine(position: Position): String {
if(SourceCode.isLibraryResource(position.file)) {
val key = SourceCode.withoutPrefix(position.file)
val cached = cache[key.lowercase()]
?: runCatching { getResource(key) }.getOrNull()
if(cached != null)
return getLine(cached, position.line)
}
val cached = cache[position.file.lowercase()]
if(cached != null)
return getLine(cached, position.line)
val path = Path(position.file).sanitize()
val cached2 = cache[path.toString().lowercase()]
if(cached2 != null)
return getLine(cached2, position.line)
throw NoSuchElementException("cannot get source line $position, with path $path")
}
private fun getLine(code: SourceCode, lineIndex: Int): String {
val spans = lineSpanCache.computeIfAbsent(code) {
val lineSpans = Regex("^", RegexOption.MULTILINE).findAll(code.text).map { it.range.first }
val ends = lineSpans.drop(1) + code.text.length
lineSpans.zip(ends).map { (start, end) -> LineSpan(start, end) }.toList().toTypedArray()
}
val span = spans[lineIndex - 1]
return code.text.substring(span.start, span.end).trim()
}
private class LineSpan(val start: Int, val end: Int)
private val cache = ConcurrentHashMap<String, SourceCode>()
private val lineSpanCache = ConcurrentHashMap<SourceCode, Array<LineSpan>>()
}
@@ -1,16 +1,13 @@
package prog8.code.core
package prog8.code.source
import java.io.File
import prog8.code.sanitize
import java.io.IOException
import java.nio.file.Path
import java.text.Normalizer
import kotlin.io.path.Path
import kotlin.io.path.absolute
import kotlin.io.path.readText
const val internedStringsModuleName = "prog8_interned_strings"
/**
* Encapsulates - and ties together - actual source code (=text) and its [origin].
*/
@@ -26,6 +23,11 @@ sealed class SourceCode {
*/
abstract val isFromFilesystem: Boolean
/**
* Whether this [SourceCode] instance was created from a library module file
*/
abstract val isFromLibrary: Boolean
/**
* The logical name of the source code unit. Usually the module's name.
*/
@@ -55,14 +57,21 @@ sealed class SourceCode {
/**
* filename prefix to designate library files that will be retreived from internal resources rather than disk
*/
const val LIBRARYFILEPREFIX = "library:"
const val STRINGSOURCEPREFIX = "string:"
val curdir: Path = Path(".").toAbsolutePath()
fun relative(path: Path): Path = curdir.relativize(path.toAbsolutePath())
fun isRegularFilesystemPath(pathString: String) =
!(pathString.startsWith(LIBRARYFILEPREFIX) || pathString.startsWith(STRINGSOURCEPREFIX))
private const val LIBRARYFILEPREFIX = "library:"
private const val STRINGSOURCEPREFIX = "string:"
val curdir: Path = Path(".").absolute()
fun relative(path: Path): Path = curdir.relativize(path.sanitize())
fun isRegularFilesystemPath(pathString: String) = !isLibraryResource(pathString) && !isStringResource(pathString)
fun isLibraryResource(path: String) = path.startsWith(LIBRARYFILEPREFIX)
fun isStringResource(path: String) = path.startsWith(STRINGSOURCEPREFIX)
fun withoutPrefix(path: String): String {
return if(isLibraryResource(path))
path.removePrefix(LIBRARYFILEPREFIX)
else if(isStringResource(path))
path.removePrefix(STRINGSOURCEPREFIX)
else
path
}
}
/**
@@ -73,6 +82,7 @@ sealed class SourceCode {
override val text = origText.replace("\\R".toRegex(), "\n") // normalize line endings
override val isFromResources = false
override val isFromFilesystem = false
override val isFromLibrary = false
override val origin = "$STRINGSOURCEPREFIX${System.identityHashCode(text).toString(16)}"
override val name = "<unnamed-text>"
}
@@ -80,12 +90,13 @@ sealed class SourceCode {
/**
* Get [SourceCode] from the file represented by the specified Path.
* This immediately reads the file fully into memory.
* You can only get an instance of this via the ImportFileSystem object.
*
* [origin] will be the given path in absolute and normalized form.
* @throws NoSuchFileException if the file does not exist
* @throws FileSystemException if the file cannot be read
*/
class File(path: Path): SourceCode() {
internal class File(path: Path, override val isFromLibrary: Boolean): SourceCode() {
override val text: String
override val origin: String
override val name: String
@@ -109,12 +120,14 @@ sealed class SourceCode {
/**
* [origin]: `library:/x/y/z.p8` for a given `pathString` of "x/y/z.p8"
* You can only get an instance of this via the ImportFileSystem object.
*/
class Resource(pathString: String): SourceCode() {
internal class Resource(pathString: String): SourceCode() {
private val normalized = "/" + Path(pathString).normalize().toMutableList().joinToString("/")
override val isFromResources = true
override val isFromFilesystem = false
override val isFromLibrary = true
override val origin = "$LIBRARYFILEPREFIX$normalized"
override val text: String
override val name: String
@@ -124,7 +137,7 @@ sealed class SourceCode {
if (rscURL == null) {
val rscRoot = object {}.javaClass.getResource("/")
throw NoSuchFileException(
File(normalized),
java.io.File(normalized),
reason = "looked in resources rooted at $rscRoot"
)
}
@@ -141,37 +154,8 @@ sealed class SourceCode {
class Generated(override val name: String) : SourceCode() {
override val isFromResources: Boolean = false
override val isFromFilesystem: Boolean = false
override val isFromLibrary: Boolean = false
override val origin: String = name
override val text: String = "<generated code node, no text representation>"
}
}
object SourceLineCache {
private val cache = mutableMapOf<String, List<String>>()
private fun getCachedFile(file: String): List<String> {
val existing = cache[file]
if(existing!=null)
return existing
if (SourceCode.isRegularFilesystemPath(file)) {
val source = SourceCode.File(Path(file))
cache[file] = source.text.split('\n', '\r').map { it.trim() }
return cache.getValue(file)
} else if(file.startsWith(SourceCode.LIBRARYFILEPREFIX)) {
val source = SourceCode.Resource(file.drop(SourceCode.LIBRARYFILEPREFIX.length))
cache[file] = source.text.split('\n', '\r').map { it.trim()}
return cache.getValue(file)
}
return emptyList()
}
fun retrieveLine(position: Position): String? {
if (position.line>0) {
val lines = getCachedFile(position.file)
if(lines.isNotEmpty())
return lines[position.line-1]
}
return null
}
}
@@ -0,0 +1,86 @@
package prog8.code.target
import prog8.code.core.*
import prog8.code.target.encodings.Encoder
import prog8.code.target.zp.M68kZeropage
import java.nio.file.Path
class Amiga1200Target: ICompilationTarget,
IStringEncoding by Encoder(false),
IMemSizer by NormalMemSizer(4u, 4u) {
override val name = NAME
override val supportsBankedCalls = true
override val supportsStackFrames = true
override val defaultEncoding = Encoding.ISO
override val libraryPath = null
override val customLauncher = emptyList<String>()
override val additionalAssemblerOptions = emptyList<String>()
override val defaultOutputType = OutputType.AMIGAHUNK
override val defaultLauncherType = CbmPrgLauncherType.NONE
companion object {
const val NAME = "amiga1200"
/** needed to map bank numbers to libraries in extsub/CALLFAR library calls */
val LibraryNumbers = Amiga500Target.LibraryNumbers
}
override val cpu = CpuType.M68020
override val FLOAT_MAX_POSITIVE = Float.MAX_VALUE.toDouble()
override val FLOAT_MAX_NEGATIVE = -Float.MAX_VALUE.toDouble()
override val FLOAT_MEM_SIZE = 4u
override val POINTER_MEM_SIZE = 4u
override val ARRAY_SIZE_LIMIT = 32768u
override val PROGRAM_LOAD_ADDRESS = 0u // amiga executables are relocatable
override val PROGRAM_MEMTOP_ADDRESS = 0xfffffffeu // not actually used
override val BSSHIGHRAM_START = 0u // not used
override val BSSHIGHRAM_END = 0u // not used
override val BSSGOLDENRAM_START = 0u // not used
override val BSSGOLDENRAM_END = 0u // not used
override lateinit var zeropage: Zeropage
override fun getFloatAsmBytes(num: Number): String {
TODO("float asm bytes")
}
override fun convertFloatToBytes(num: Double): List<UByte> {
TODO("convert float to bytes")
}
override fun convertBytesToFloat(bytes: List<UByte>): Double {
require(bytes.size==4) { "need 4 bytes" }
TODO("convert bytes to float")
}
override fun launchEmulator(selectedEmulator: Int, programFile: Path, quiet: Boolean) {
if (selectedEmulator == 1) {
CopperlineEmulator.launch(programFile, quiet, "A1200", "68020", listOf("--fast", "2M", "--fpu"))
return
}
if (selectedEmulator != 2) {
System.err.println("The amiga1200 target supports FS-UAE (-emu) and Amitools's vamos (-emu2).")
return
}
val cpuStr = when (this.cpu) {
CpuType.M68000 -> "68000"
CpuType.M68020 -> "68020"
else -> error("invalid cpu type")
}
VamosEmulator.launch(programFile, quiet, cpuStr)
return
}
override fun isIOAddress(address: UInt): Boolean =
address in 0xbfd000u..0xbfdfffu || // CIA-B
address in 0xbfe000u..0xbfefffu || // CIA-A
address in 0xdff000u..0xdff1ffu || // Custom chipset (Paula, Alice, Lisa, Denise)
address in 0xe80000u..0xefffffu // Zorro II autoconfig space
override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {
zeropage = M68kZeropage(compilerOptions)
}
}
@@ -0,0 +1,126 @@
package prog8.code.target
import prog8.code.core.*
import prog8.code.target.encodings.Encoder
import prog8.code.target.zp.M68kZeropage
import java.nio.file.Path
class Amiga500Target: ICompilationTarget,
IStringEncoding by Encoder(false),
IMemSizer by NormalMemSizer(4u, 4u) {
override val name = NAME
override val supportsBankedCalls = true
override val supportsStackFrames = true
override val defaultEncoding = Encoding.ISO
override val libraryPath = null
override val customLauncher = emptyList<String>()
override val additionalAssemblerOptions = emptyList<String>()
override val defaultOutputType = OutputType.AMIGAHUNK
override val defaultLauncherType = CbmPrgLauncherType.NONE
companion object {
const val NAME = "amiga500"
/** needed to map bank numbers to libraries in extsub/CALLFAR library calls */
val LibraryNumbers = mapOf(
1 to "Sys", // exec
2 to "DOS",
3 to "Gfx",
4 to "Intuition",
5 to "GadTools",
6 to "Layers",
7 to "Asl",
8 to "ConsoleDevice",
9 to "Utility",
10 to "Expansion",
11 to "Icon",
12 to "Workbench",
13 to "Diskfont",
14 to "IFFParse",
15 to "Input",
16 to "Keymap",
17 to "Locale",
18 to "Timer",
19 to "LowLevel",
20 to "Math",
21 to "MathIeeeSingBas",
22 to "MathIeeeSingTrans",
23 to "MathIeeeDoubBas",
24 to "MathIeeeDoubTrans",
25 to "MathTrans",
26 to "NV",
27 to "RealTime",
28 to "Translator",
29 to "RexxSys",
30 to "Cx",
31 to "DataTypes",
32 to "Disk",
33 to "AmigaGuide",
34 to "ARexx",
35 to "BattClock",
36 to "BattMem",
// from here, non-standard libraries are listed
100 to "AsyncIO",
101 to "AHI", // ahi.device base (amiga1200 target only, 68020+, used by the low-level ahi.* LVOs)
)
}
override val cpu = CpuType.M68000
override val FLOAT_MAX_POSITIVE = Float.MAX_VALUE.toDouble()
override val FLOAT_MAX_NEGATIVE = -Float.MAX_VALUE.toDouble()
override val FLOAT_MEM_SIZE = 4u
override val POINTER_MEM_SIZE = 4u
override val ARRAY_SIZE_LIMIT = 32768u
override val PROGRAM_LOAD_ADDRESS = 0u // amiga executables are relocatable
override val PROGRAM_MEMTOP_ADDRESS = 0xfffffffeu // not actually used
override val BSSHIGHRAM_START = 0u // not used
override val BSSHIGHRAM_END = 0u // not used
override val BSSGOLDENRAM_START = 0u // not used
override val BSSGOLDENRAM_END = 0u // not used
override lateinit var zeropage: Zeropage
override fun getFloatAsmBytes(num: Number): String {
TODO("float asm bytes")
}
override fun convertFloatToBytes(num: Double): List<UByte> {
TODO("convert float to bytes")
}
override fun convertBytesToFloat(bytes: List<UByte>): Double {
require(bytes.size==4) { "need 4 bytes" }
TODO("convert bytes to float")
}
override fun launchEmulator(selectedEmulator: Int, programFile: Path, quiet: Boolean) {
if (selectedEmulator == 1) {
CopperlineEmulator.launch(programFile, quiet, "A500", "68000", listOf("--slow", "512K"))
return
}
if (selectedEmulator != 2) {
System.err.println("The amiga500 target supports FS-UAE (-emu) and Amitools's vamos (-emu2).")
return
}
val cpuStr = when (this.cpu) {
CpuType.M68000 -> "68000"
CpuType.M68020 -> "68020"
else -> error("invalid cpu type")
}
VamosEmulator.launch(programFile, quiet, cpuStr)
return
}
override fun isIOAddress(address: UInt): Boolean =
address in 0xbfd000u..0xbfdfffu || // CIA-B
address in 0xbfe000u..0xbfefffu || // CIA-A
address in 0xdff000u..0xdff1ffu || // Custom chipset (Paula, Alice, Lisa, Denise)
address in 0xe80000u..0xefffffu // Zorro II autoconfig space
override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {
zeropage = M68kZeropage(compilerOptions)
}
}
@@ -1,31 +0,0 @@
package prog8.code.target
import prog8.code.core.*
import prog8.code.target.atari.AtariMachineDefinition
class AtariTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer {
override val name = NAME
override val machine = AtariMachineDefinition()
override val defaultEncoding = Encoding.ATASCII
companion object {
const val NAME = "atari"
}
override fun memorySize(dt: DataType): Int {
return when(dt) {
in ByteDatatypesWithBoolean -> 1
in WordDatatypes, in PassByReferenceDatatypes -> 2
DataType.FLOAT -> machine.FLOAT_MEM_SIZE
else -> throw IllegalArgumentException("invalid datatype")
}
}
override fun memorySize(arrayDt: DataType, numElements: Int) =
if(arrayDt==DataType.UWORD)
numElements // pointer to bytes.
else
memorySize(ArrayToElementTypes.getValue(arrayDt)) * numElements
}
+72 -8
View File
@@ -1,19 +1,83 @@
package prog8.code.target
import prog8.code.core.Encoding
import prog8.code.core.ICompilationTarget
import prog8.code.core.IMemSizer
import prog8.code.core.IStringEncoding
import prog8.code.target.c128.C128MachineDefinition
import prog8.code.target.cbm.CbmMemorySizer
import prog8.code.core.*
import prog8.code.target.encodings.Encoder
import prog8.code.target.zp.C128Zeropage
import java.nio.file.Path
class C128Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by CbmMemorySizer {
class C128Target: ICompilationTarget,
IStringEncoding by Encoder(true),
IMemSizer by NormalMemSizer(Mflpt5.FLOAT_MEM_SIZE, 2u) {
override val name = NAME
override val machine = C128MachineDefinition()
override val supportsBankedCalls = true
override val supportsStackFrames = false
override val defaultEncoding = Encoding.PETSCII
override val libraryPath = null
override val customLauncher = emptyList<String>()
override val additionalAssemblerOptions = emptyList<String>()
override val defaultOutputType = OutputType.PRG
override val defaultLauncherType = CbmPrgLauncherType.BASIC
companion object {
const val NAME = "c128"
}
override val cpu = CpuType.CPU6502
override val FLOAT_MAX_POSITIVE = Mflpt5.FLOAT_MAX_POSITIVE
override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE
override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE
override val POINTER_MEM_SIZE = 2u
override val ARRAY_SIZE_LIMIT = 256u
override val PROGRAM_LOAD_ADDRESS = 0x1c01u
override val PROGRAM_MEMTOP_ADDRESS = 0xc000u
override val BSSHIGHRAM_START = 0u // no high ram
override val BSSHIGHRAM_END = 0u // no high ram
override val BSSGOLDENRAM_START = 0x1300u
override val BSSGOLDENRAM_END = 0x1bdfu // note: $1be0 - $1bff contains the 16 virtual registers
override lateinit var zeropage: Zeropage
override fun getFloatAsmBytes(num: Number) = Mflpt5.fromNumber(num).makeFloatFillAsm()
override fun convertFloatToBytes(num: Double): List<UByte> {
val m5 = Mflpt5.fromNumber(num)
return listOf(m5.b0, m5.b1, m5.b2, m5.b3, m5.b4)
}
override fun convertBytesToFloat(bytes: List<UByte>): Double {
require(bytes.size==5) { "need 5 bytes" }
val m5 = Mflpt5(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4])
return m5.toDouble()
}
override fun launchEmulator(selectedEmulator: Int, programFile: Path, quiet: Boolean) {
if(selectedEmulator!=1) {
System.err.println("The c128 target only supports the main emulator (Vice).")
return
}
if(!quiet)
println("\nStarting C-128 emulator x128...")
val viceMonlist = programFile.resolveSibling(viceMonListName(outputStemOf(programFile)))
val cmdline = listOf("x128", "-silent", "-moncommands", viceMonlist.toString(),
"-autostartprgmode", "1", "-autostart-warp", "-autostart", programFile.toString())
val processb = ProcessBuilder(cmdline)
if(!quiet)
processb.inheritIO()
val process: Process = processb.start()
process.waitFor()
}
override fun isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0xd000u..0xdfffu || address in 0xff00u..0xff04u
override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {
zeropage = C128Zeropage(compilerOptions)
}
}
+88 -14
View File
@@ -1,23 +1,95 @@
package prog8.code.target
import prog8.code.core.Encoding
import prog8.code.core.ICompilationTarget
import prog8.code.core.IMemSizer
import prog8.code.core.IStringEncoding
import prog8.code.target.c64.C64MachineDefinition
import prog8.code.target.cbm.CbmMemorySizer
import prog8.code.core.*
import prog8.code.target.encodings.Encoder
import prog8.code.target.zp.C64Zeropage
import java.io.IOException
import java.nio.file.Path
class C64Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by CbmMemorySizer {
class C64Target: ICompilationTarget,
IStringEncoding by Encoder(true),
IMemSizer by NormalMemSizer(Mflpt5.FLOAT_MEM_SIZE, 2u) {
override val name = NAME
override val machine = C64MachineDefinition()
override val supportsBankedCalls = true
override val supportsStackFrames = false
override val defaultEncoding = Encoding.PETSCII
override val libraryPath = null
override val customLauncher = emptyList<String>()
override val additionalAssemblerOptions = emptyList<String>()
override val defaultOutputType = OutputType.PRG
override val defaultLauncherType = CbmPrgLauncherType.BASIC
companion object {
const val NAME = "c64"
fun viceMonListName(baseFilename: String) = "$baseFilename.vice-mon-list"
}
override val cpu = CpuType.CPU6502
override val FLOAT_MAX_POSITIVE = Mflpt5.FLOAT_MAX_POSITIVE
override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE
override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE
override val POINTER_MEM_SIZE = 2u
override val ARRAY_SIZE_LIMIT = 256u
override val PROGRAM_LOAD_ADDRESS = 0x0801u
override val PROGRAM_MEMTOP_ADDRESS = 0xcfe0u // $a000 if floats are used
// note that at $cfe0-$cfff are the 16 'virtual registers' R0-R15
override val BSSHIGHRAM_START = 0xc000u
override val BSSHIGHRAM_END = 0xcfdfu
override val BSSGOLDENRAM_START = 0u // no golden ram on C64
override val BSSGOLDENRAM_END = 0u
override lateinit var zeropage: Zeropage
override fun getFloatAsmBytes(num: Number) = Mflpt5.fromNumber(num).makeFloatFillAsm()
override fun convertFloatToBytes(num: Double): List<UByte> {
val m5 = Mflpt5.fromNumber(num)
return listOf(m5.b0, m5.b1, m5.b2, m5.b3, m5.b4)
}
override fun convertBytesToFloat(bytes: List<UByte>): Double {
require(bytes.size==5) { "need 5 bytes" }
val m5 = Mflpt5(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4])
return m5.toDouble()
}
override fun launchEmulator(selectedEmulator: Int, programFile: Path, quiet: Boolean) {
if(selectedEmulator!=1) {
System.err.println("The c64 target only supports the main emulator (Vice).")
return
}
for(emulator in listOf("x64sc", "x64")) {
if(!quiet)
println("\nStarting C-64 emulator $emulator...")
val viceMonlist = programFile.resolveSibling(viceMonListName(outputStemOf(programFile)))
val cmdline = listOf(emulator, "-silent", "-moncommands", viceMonlist.toString(),
"-autostartprgmode", "1", "-autostart-warp", "-autostart", programFile.toString())
val processb = ProcessBuilder(cmdline)
if(!quiet)
processb.inheritIO()
val process: Process
try {
process=processb.start()
} catch(_: IOException) {
continue // try the next emulator executable
}
process.waitFor()
break
}
}
override fun isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0xd000u..0xdfffu
override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {
zeropage = C64Zeropage(compilerOptions)
}
}
@@ -26,8 +98,9 @@ val CompilationTargets = listOf(
C128Target.NAME,
Cx16Target.NAME,
PETTarget.NAME,
AtariTarget.NAME,
Neo6502Target.NAME,
Qemu68kTarget.NAME,
Amiga500Target.NAME,
Amiga1200Target.NAME,
VMTarget.NAME
)
@@ -36,8 +109,9 @@ fun getCompilationTargetByName(name: String) = when(name.lowercase()) {
C128Target.NAME -> C128Target()
Cx16Target.NAME -> Cx16Target()
PETTarget.NAME -> PETTarget()
AtariTarget.NAME -> AtariTarget()
Qemu68kTarget.NAME -> Qemu68kTarget()
Amiga500Target.NAME -> Amiga500Target()
Amiga1200Target.NAME -> Amiga1200Target()
VMTarget.NAME -> VMTarget()
Neo6502Target.NAME -> Neo6502Target()
else -> throw IllegalArgumentException("invalid compilation target")
}
@@ -0,0 +1,204 @@
package prog8.code.target
import prog8.code.core.*
import prog8.code.source.ImportFileSystem.expandTilde
import prog8.code.target.encodings.Encoder
import prog8.code.target.zp.ConfigurableZeropage
import prog8.code.target.zp.M68kZeropage
import java.io.IOException
import java.nio.file.Path
import java.util.*
import kotlin.io.path.Path
import kotlin.io.path.inputStream
import kotlin.io.path.isDirectory
import kotlin.io.path.nameWithoutExtension
class ConfigFileTarget(
override val name: String,
override val supportsBankedCalls: Boolean,
override val defaultEncoding: Encoding,
override val cpu: CpuType,
override val supportsStackFrames: Boolean,
override val PROGRAM_LOAD_ADDRESS: UInt,
override val PROGRAM_MEMTOP_ADDRESS: UInt,
override val BSSHIGHRAM_START: UInt,
override val BSSHIGHRAM_END: UInt,
override val BSSGOLDENRAM_START: UInt,
override val BSSGOLDENRAM_END: UInt,
override val defaultOutputType: OutputType,
override val defaultLauncherType: CbmPrgLauncherType,
override val libraryPath: Path,
override val customLauncher: List<String>,
override val additionalAssemblerOptions: List<String>,
val varsAddress: UInt? = null,
val ioAddresses: List<UIntRange>,
val zpScratchB1: UInt,
val zpScratchReg: UInt,
val zpScratchW1: UInt,
val zpScratchW2: UInt,
val zpScratchPtr: UInt,
val virtualregistersStart: UInt,
val zpFullsafe: List<UIntRange>,
val zpKernalsafe: List<UIntRange>,
val zpBasicsafe: List<UIntRange>,
val pointerSize: Int = 2
): ICompilationTarget, IStringEncoding by Encoder(true), IMemSizer by NormalMemSizer(8u, pointerSize.toUInt()) {
init {
require(pointerSize == 2 || pointerSize == 4) { "unsupported pointer size: $pointerSize" }
}
companion object {
private fun Properties.getString(property: String): String {
val value = this.getProperty(property, null)
if(value!=null)
return value
throw NoSuchElementException("string property '$property' not found in config file")
}
private fun Properties.getInteger(property: String): UInt {
val value = this.getProperty(property, null)
if(value!=null) return parseInt(value)
throw NoSuchElementException("integer property '$property' not found in config file")
}
private fun parseInt(value: String): UInt {
if(value.startsWith("0x"))
return value.drop(2).toUInt(16)
if(value.startsWith("$"))
return value.drop(1).toUInt(16)
if(value.startsWith("%"))
return value.drop(1).toUInt(2)
return value.toUInt()
}
private fun parsePointerSize(props: Properties): Int {
val pointerSize = parseInt(props.getProperty("pointer_size", "2")).toInt()
require(pointerSize == 2 || pointerSize == 4) { "unsupported pointer size: $pointerSize" }
return pointerSize
}
private fun parseAddressRanges(key: String, props: Properties): List<UIntRange> {
val rangesStr = props.getString(key)
if(rangesStr.isBlank())
return emptyList()
val result = mutableListOf<UIntRange>()
val ranges = rangesStr.split(",").map { it.trim() }
for(r in ranges) {
if ('-' in r) {
val (fromStr, toStr) = r.split("-")
val from = parseInt(fromStr.trim())
val to = parseInt(toStr.trim())
result.add(from..to)
} else {
val address = parseInt(r)
result.add(address..address)
}
}
return result
}
fun fromConfigFile(configfile: Path): ConfigFileTarget {
val props = Properties()
props.load(configfile.inputStream())
val cpuString = props.getString("cpu").uppercase()
val cpuType = try {
CpuType.valueOf(cpuString)
} catch (_: IllegalArgumentException) {
CpuType.valueOf("CPU$cpuString")
}
val ioAddresses = parseAddressRanges("io_regions", props)
// The m68k has no zero page, so the zeropage settings below don't apply to an m68k
// target and are not required in its config file.
fun zpSetting(name: String) = if(cpuType.is68k) 0u else props.getInteger(name)
val zpFullsafe = if(cpuType.is68k) emptyList() else parseAddressRanges("zp_fullsafe", props)
val zpKernalsafe = if(cpuType.is68k) emptyList() else parseAddressRanges("zp_kernalsafe", props)
val zpBasicsafe = if(cpuType.is68k) emptyList() else parseAddressRanges("zp_basicsafe", props)
val libraryPath = expandTilde(Path(props.getString("library")))
if(!libraryPath.isDirectory())
throw IOException("invalid library path: $libraryPath")
val customLauncherStr = props.getProperty("custom_launcher_code", null)
val customLauncher =
if(customLauncherStr?.isNotBlank()==true)
(customLauncherStr+"\n").lines().map { it.trimEnd() }
else emptyList()
val assemblerOptionsStr = props.getProperty("assembler_options", "").trim()
val pointerSize = parsePointerSize(props)
val outputTypeString = props.getProperty("output_type", "PRG")
val defaultOutputType = OutputType.valueOf(outputTypeString.uppercase())
val launcherString = props.getProperty("launcher", "BASIC")
val defaultLauncherType = try {
CbmPrgLauncherType.valueOf(launcherString.uppercase())
} catch (_: IllegalArgumentException) {
CbmPrgLauncherType.BASIC
}
val varsAddress = props.getProperty("vars_address")?.let { parseInt(it) }
return ConfigFileTarget(
configfile.nameWithoutExtension,
props.getProperty("supports_banked_calls", "false").toBoolean(),
Encoding.entries.first { it.prefix==props.getString("encoding") },
cpuType,
props.getProperty("supports_stack_frames", cpuType.is68k.toString()).toBoolean(),
props.getInteger("load_address"),
props.getInteger("memtop"),
props.getInteger("bss_highram_start"),
props.getInteger("bss_highram_end"),
props.getInteger("bss_goldenram_start"),
props.getInteger("bss_goldenram_end"),
defaultOutputType,
defaultLauncherType,
libraryPath,
customLauncher,
if(assemblerOptionsStr=="") emptyList() else assemblerOptionsStr.split(" "),
varsAddress,
ioAddresses,
zpSetting("zp_scratch_b1"),
zpSetting("zp_scratch_reg"),
zpSetting("zp_scratch_w1"),
zpSetting("zp_scratch_w2"),
zpSetting("zp_scratch_ptr"),
zpSetting("virtual_registers"),
zpFullsafe,
zpKernalsafe,
zpBasicsafe,
pointerSize,
)
}
}
// TODO floats are not yet supported here, just enter some values
override val FLOAT_MAX_POSITIVE = 9.999999999e97
override val FLOAT_MAX_NEGATIVE = -9.999999999e97
override val FLOAT_MEM_SIZE = 8u
override val POINTER_MEM_SIZE = pointerSize.toUInt()
override val ARRAY_SIZE_LIMIT = 256u
override lateinit var zeropage: Zeropage
override fun getFloatAsmBytes(num: Number) = TODO("floats")
override fun convertFloatToBytes(num: Double): List<UByte> = TODO("floats")
override fun convertBytesToFloat(bytes: List<UByte>): Double = TODO("floats")
override fun launchEmulator(selectedEmulator: Int, programFile: Path, quiet: Boolean) {
throw IllegalArgumentException("Custom compiler target cannot automatically launch an emulator. Do this manually.")
}
override fun isIOAddress(address: UInt): Boolean = ioAddresses.any { address in it }
override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {
// the m68k has no zero page, so the zp scratch addresses in the config file don't apply there
zeropage = if(cpu.is68k) M68kZeropage(compilerOptions) else ConfigurableZeropage(
zpScratchB1, zpScratchReg, zpScratchW1, zpScratchW2, zpScratchPtr,
virtualregistersStart,
zpBasicsafe,
zpKernalsafe,
zpFullsafe,
compilerOptions
)
}
}
@@ -0,0 +1,71 @@
package prog8.code.target
import java.io.File
import java.nio.file.Path
import java.nio.file.Paths
import kotlin.io.path.copyTo
import kotlin.io.path.createDirectories
object CopperlineEmulator {
fun launch(programFile: Path, quiet: Boolean, model: String, cpu: String, memoryArgs: List<String>) {
val home = System.getProperty("user.home")
val sourceHdName = if (model == "A500") "Harddisk500" else "Harddisk1200"
val cmdDir = if (model == "A500") "c" else "C"
val libsDir = if (model == "A500") "libs" else "Libs"
val libs = listOf("diskfont.library", "iffparse.library", "lowlevel.library", "rexxsyslib.library", "asyncio.library", "icon.library")
val tempDir = Paths.get(System.getProperty("java.io.tmpdir"), "prog8-copperline-$model")
tempDir.createDirectories()
val progName = programFile.fileName.toString()
val stagedProg = tempDir.resolve(progName)
programFile.copyTo(stagedProg, overwrite = true)
val srcHd = File("$home/Documents/FS-UAE/Hard Drives/$sourceHdName")
if (!srcHd.isDirectory) System.err.println("Warning: source hard disk folder not found: ${srcHd}; skipping file staging.")
for (lib in libs) {
val src = File(srcHd, "$libsDir/$lib")
if (src.exists()) src.toPath().copyTo(tempDir.resolve(lib), overwrite = true)
}
val commands = if (model == "A500") listOf("Dir","List","Makedir","Assign","SetPatch","Mount","CPU","Echo","Avail") else listOf("Dir","List","MakeDir","Assign","SetPatch","Mount","CPU","Echo","Avail")
for (cmd in commands) {
val src = File(srcHd, "$cmdDir/$cmd")
if (src.exists()) src.toPath().copyTo(tempDir.resolve(cmd), overwrite = true)
}
val ramHandlerSrc = File(srcHd, "l/Ram-Handler")
if (model == "A500" && ramHandlerSrc.exists()) ramHandlerSrc.toPath().copyTo(tempDir.resolve("Ram-Handler"), overwrite = true)
val sysCfgSrc = File(srcHd, "Devs/system-configuration")
if (sysCfgSrc.exists()) sysCfgSrc.toPath().copyTo(tempDir.resolve("system-configuration"), overwrite = true)
val ksDirs = listOf(
File("${System.getProperty("user.home")}/Documents/FS-UAE/Kickstarts"),
File("${System.getProperty("user.home")}/Documents/Kickstarts")
)
val ksDir = ksDirs.firstOrNull { it.isDirectory } ?: ksDirs.first()
val candidates = ksDirs.filter { it.isDirectory }.flatMap { d -> d.listFiles()?.filter { it.name.endsWith(".rom", ignoreCase = true) && it.name.contains(model, ignoreCase = true) } ?: emptyList() }
val preferredVersion = if (model == "A500") "v1.3" else "v3.1"
val rom = candidates.firstOrNull { it.name.contains(preferredVersion, ignoreCase = true) && it.name.contains("[!", ignoreCase = true) }
?: candidates.firstOrNull { it.name.contains(preferredVersion, ignoreCase = true) && !it.name.contains("[b", ignoreCase = true) && !it.name.contains("[h", ignoreCase = true) }
?: candidates.firstOrNull { it.name.contains(preferredVersion, ignoreCase = true) }
if (rom == null) {
System.err.println("Warning: no Kickstart ROM for $model found in ${ksDir}; using bundled AROS.")
}
val cmd = mutableListOf(
"copperline",
"--factory",
"--model", model,
"--cpu", cpu
)
cmd.addAll(memoryArgs)
if (rom != null) cmd.add(rom.absolutePath)
cmd.addAll(listOf(
"--run", stagedProg.toString()
))
if (!quiet) println("Launching Copperline...")
val pb = ProcessBuilder(cmd).inheritIO()
try {
pb.start().waitFor()
} catch (_: Exception) {
System.err.println("Cannot find 'copperline'. Install it from https://copperline.dev/")
}
}
}
Loaded 100 of 987 files, more files were not shown because too many files have changed in this diff. Show more