1
0
mirror of https://github.com/KarolS/millfork.git synced 2024-05-31 18:41:30 +00:00

Compare commits

...

266 Commits

Author SHA1 Message Date
Karol Stasiak
d8c11a9c50 Minor optimizations 2023-02-03 14:46:01 +01:00
Karol Stasiak
ee47ccef5a fix z80 indexing in hardwritten assembly (#137) 2023-01-27 18:27:53 +01:00
Karol Stasiak
24de2f7530 enable tests of identity page 2023-01-27 18:19:19 +01:00
Karol Stasiak
1beb695151 more tests 2023-01-27 18:17:41 +01:00
Karol Stasiak
9229092309 random minor stuff 2023-01-27 18:16:25 +01:00
Karol Stasiak
ca7166d1ae oops 2023-01-27 18:16:02 +01:00
Karol Stasiak
1594d63a9a Add a command line flag for identity page 2023-01-27 18:15:40 +01:00
Karol Stasiak
75cc34663c Z80: fix an optimization 2023-01-27 18:15:10 +01:00
Karol Stasiak
f4d2fdd370 6502: use identity page for maths 2023-01-27 18:14:50 +01:00
Karol Stasiak
29c1e3f2a6 6502 and Z80: Optimize optimizations 2023-01-27 18:13:21 +01:00
Karol Stasiak
e9cfec54b5 Various 6502 optimization fixes 2023-01-27 17:34:09 +01:00
Karol Stasiak
1bc1ab3539 Fix some codegen bugs on 6502 2023-01-27 17:00:29 +01:00
Karol Stasiak
6f294d6dec Fix -fbounds-checking 2022-02-12 02:13:30 +01:00
Karol Stasiak
9866c974ad Don't apply Constant index offset propagation in decimal mode 2022-02-12 02:12:55 +01:00
Karol Stasiak
ef2f5b5918 Add test 2022-02-11 21:48:24 +01:00
Karol Stasiak
a70a1c0e6b Consider kernal_interrupt functions as entry points 2022-02-11 21:48:13 +01:00
Karol Stasiak
790c836771 Fix handling of non-top-level return dispatch statements 2022-02-11 21:47:39 +01:00
Karol Stasiak
6af84d1628 Optimize the optimizer 2022-02-08 14:42:30 +01:00
Karol Stasiak
7b205a2754 Allow multiple -D options 2022-02-08 13:21:26 +01:00
Karol Stasiak
d23fe1756e Switch to snapshot versioning 2022-02-08 13:20:15 +01:00
Karol Stasiak
3b3ee1bc55 Version 0.3.30 2021-12-15 16:01:46 +01:00
Karol Stasiak
fb30075ea5 Update CHANGELOG 2021-12-15 15:54:00 +01:00
Karol Stasiak
b5084cd180 More tests 2021-12-15 15:53:49 +01:00
Karol Stasiak
b1a2be5574 6809: Fix constant condition compilation 2021-11-22 01:58:09 +01:00
Karol Stasiak
a260d0a806 CBM BASIC loader should use the actual address of main (fixes #111) 2021-11-12 02:45:53 +01:00
Karol Stasiak
38ad919ed9 Show the positions of unevaluated constants 2021-11-12 02:44:58 +01:00
Karol Stasiak
34ef8b8de9 Better evaluation of the if function in constants 2021-11-12 02:44:20 +01:00
Karol Stasiak
f676e74e38 Macro improvements:
– allow local constants in macros
– allow untyped macro parameters with void
– treat the name of a function as a pointer to it
– add this.function local alias (#118)
2021-11-12 02:10:07 +01:00
Karol Stasiak
c9313e5dbe Add support for ld65 label file format (#128) 2021-11-12 00:47:12 +01:00
Karol Stasiak
73a223b9b6 Add support for Mesen label file format by tracking file-relative positions of segments (#128) 2021-11-03 21:48:45 +01:00
Karol Stasiak
b168818bab Report every hole in the output 4 bytes or larger; count total free bytes in the entire bank 2021-09-21 00:43:29 +02:00
Karol Stasiak
effa723863 Never commit .labels files again 2021-09-21 00:21:21 +02:00
Karol Stasiak
b2ab3dbeab Clean accidentally commited labels file 2021-09-21 00:20:54 +02:00
Karol Stasiak
c9ef5e636b Add raw label file format 2021-09-21 00:09:59 +02:00
Karol Stasiak
fc2f0782c5 Update Notepad++ syntax 2021-09-20 00:56:04 +02:00
Karol Stasiak
f0e22f02a6
Merge pull request #126 from mookiexl/master
Update x16_experimental.ini
2021-09-18 14:23:02 +02:00
Karol Stasiak
b2291d1cb2
Merge pull request #122 from retrac0/master
gb library code updates to current syntax
2021-09-18 13:21:15 +02:00
Karol Stasiak
166acf2b18 R800 support 2021-09-18 00:36:16 +02:00
Karol Stasiak
7530b382a8 Fix array fields in certain contexts 2021-09-17 22:19:39 +02:00
Karol Stasiak
b66435d06b Fix EasyFlash switch_hirom (fixes #121) 2021-09-13 15:10:11 +02:00
Karol Stasiak
0c8951d015 Fix unused variable elimination in for-array statements (fixes #125) 2021-09-13 09:27:34 +02:00
Karol Stasiak
84dde8589c Allow spaces after the array keyword (fixes #120) 2021-09-13 09:26:54 +02:00
Karol Stasiak
3b0aa9a425 Fixes for flag boolean types (fixes #123) 2021-09-13 09:26:27 +02:00
mookiexl
1b8de990a5 Update x16_experimental.ini 2021-08-19 14:37:20 +02:00
mookiexl
b060fc599b Update x16_experimental.ini
$00-$01 are used for bank switching.
Unintentional write to those will crash the machine.
2021-08-16 16:06:28 +02:00
Karol Stasiak
90e5360bfd Related to #119:
– Detection of simple byte overflow cases.
– Optimization of 8×8→16 multiplication on 6809.
– Multiplication optimizations on Z80.
2021-08-06 21:01:03 +02:00
Joel Heikkila
bbf430a1c7 update gb lib code to current syntax for example/ 2021-07-11 18:15:39 -04:00
Karol Stasiak
7f6a0c6b0d Fix documentation of .loword and .hiword 2021-06-29 02:39:23 +02:00
Karol Stasiak
7f0def54bc Improvements for 65CE02 assembly (fixes #116) 2021-06-29 02:29:30 +02:00
Karol Stasiak
faf97cee1f Don't call valid control characters invalid 2021-06-29 02:29:12 +02:00
Karol Stasiak
da862069a7 Fix for volatile fields 2021-06-29 02:28:32 +02:00
Karol Stasiak
431a25d325 Internal support for pointers to volatile objects; add volatile fields (closes #112) 2021-06-21 14:20:24 +02:00
Karol Stasiak
73beafd65e Support for expressions in file() (fixes #114) 2021-06-21 14:18:17 +02:00
Karol Stasiak
307ad90ecf 6809: Improve flow analysis and add few more optimizations 2021-06-21 14:15:40 +02:00
Karol Stasiak
2e592a2331 Correct address for sid_v1_sr (fixing #115) 2021-06-21 14:12:33 +02:00
Karol Stasiak
91c9b42f3d Switch to snapshot versioning 2021-06-21 14:11:56 +02:00
Karol Stasiak
144da70594 Version 0.3.28 2021-05-24 00:17:51 +02:00
Karol Stasiak
4f6eefab79 Officially deprecate old decimal operators 2021-05-23 22:31:11 +02:00
Karol Stasiak
ca35367974 Tease floating-point numbers 2021-05-16 23:32:33 +02:00
Karol Stasiak
2065c3b4ac Fix 6809 under native-image 2021-05-16 23:32:18 +02:00
Karol Stasiak
9028d55a7e Various optimization improvements and fixes, mostly for 6809 2021-05-16 23:31:52 +02:00
Karol Stasiak
21d4d3252f Remove debugging statements 2021-05-16 00:40:12 +02:00
Karol Stasiak
45ad049a51 Update CHANGELOG 2021-05-08 00:46:37 +02:00
Karol Stasiak
0172e29bb2 Underscores in numeric literals. Fix parsing of Intel hex constants starting with 0B. 2021-05-08 00:42:06 +02:00
Karol Stasiak
ffb46c4250 Optimize some bitmask operations 2021-05-05 02:58:57 +02:00
Karol Stasiak
c51c08ad56 6809: Fix and improve optimizations 2021-05-05 02:58:28 +02:00
Karol Stasiak
fcdad413b0 #110 Add a warning for comparisons between bytes and pointers. 2021-05-05 00:59:54 +02:00
Karol Stasiak
63edce28c4 Update CHANGELOG 2021-04-24 01:21:03 +02:00
Karol Stasiak
1f318a2a0e 6502: Optimize sign extension 2021-04-24 01:18:34 +02:00
Karol Stasiak
1bcb6d5010 Fix sign extension when using pointers 2021-04-24 01:18:21 +02:00
Karol Stasiak
510f85960c Fix optimizations of unused labels 2021-04-24 01:18:01 +02:00
Karol Stasiak
8412075175 Fix pointer type compatibility checks 2021-04-24 01:13:59 +02:00
Karol Stasiak
e25df3d1b3 Parser optimizations again 2021-04-19 01:06:51 +02:00
Karol Stasiak
b71d058c6a Parser optimizations 2021-04-18 23:48:23 +02:00
Karol Stasiak
bf273456a3 Fix #107 2021-03-20 01:25:27 +01:00
Karol Stasiak
062483971a Fix #107 (syntax errors in stdlib, overpanicky statement preprocessor) 2021-03-20 01:23:51 +01:00
Karol Stasiak
1e4a193741 Optimization hints 2021-03-15 00:44:14 +01:00
Karol Stasiak
2468d8cca5 Update changelog 2021-03-13 21:42:52 +01:00
Karol Stasiak
58b5b6ff28 Fix #106: the current working directory should be always included in the include path 2021-03-13 21:42:11 +01:00
Karol Stasiak
8aac3bc329 Allow character literals in preprocessor 2021-03-13 21:40:38 +01:00
Karol Stasiak
24eac6708b Fix escape sequences in many encodings 2021-03-13 21:40:18 +01:00
Karol Stasiak
66fc1d3984 Add several more encodings 2021-03-13 21:39:48 +01:00
Karol Stasiak
0bbdc348e7 Switch to snapshot versioning 2021-03-13 02:19:29 +01:00
Karol Stasiak
15a32a4caf Version 0.3.26 2021-03-01 10:25:38 +01:00
Karol Stasiak
e8f5667faa Move apple2_prodos module documentation 2021-02-28 20:53:22 +01:00
Karol Stasiak
03bc5894aa
Merge pull request #103 from retrac0/master
outlined ProDOS API in docs
2021-02-28 20:43:01 +01:00
Karol Stasiak
bd9ff2f66d Unfinished test 2021-02-28 19:38:25 +01:00
Karol Stasiak
a111af384e Unify assembly parameter evaluation 2021-02-27 00:08:31 +01:00
Karol Stasiak
6f2c8cd991 Show unused space in the middle of segments 2021-02-26 23:20:32 +01:00
Karol Stasiak
a0c2eaabcf Struct array fields performance improvements 2021-02-26 23:13:16 +01:00
Karol Stasiak
83393d49f1 Z80: optimization improvements 2021-02-26 23:12:43 +01:00
Karol Stasiak
84d707b932 Cosmetic improvements 2021-02-26 23:10:08 +01:00
Karol Stasiak
f01879e4a3 Use local labels in m6809_math 2021-02-26 23:05:29 +01:00
Joel Heikkila
efb3d3c7c9 outlined ProDOS API in docs 2021-02-25 13:19:37 -05:00
Karol Stasiak
22bd6ac443 Update changelog 2021-02-24 03:05:09 +01:00
Karol Stasiak
ffa0ffb899 Allow enabling/disabling warnings individually 2021-02-24 03:04:53 +01:00
Karol Stasiak
3155d7a571 Improve error message 2021-02-24 02:32:24 +01:00
Karol Stasiak
ba7c5b507c Optimize constant resolution 2021-02-24 02:32:13 +01:00
Karol Stasiak
196ad6542f Allow refering to labels from other functions in assembly (fixes #101) 2021-02-24 02:32:00 +01:00
Karol Stasiak
ff6106a838 Fix module name resolution (#89) 2021-02-24 02:31:20 +01:00
Karol Stasiak
9ebbbdc022 Summarize the compilation 2021-02-24 02:30:28 +01:00
Karol Stasiak
ab9cdf7ad5 Fix deduplication problems with trampolined functions 2021-02-24 02:29:47 +01:00
Karol Stasiak
4ff6120702 Warn about data not being included in the output 2021-02-24 02:28:29 +01:00
Karol Stasiak
521b73d0d3 Array fields for structs and unions (see #87) 2021-02-22 23:23:00 +01:00
Karol Stasiak
478b2eefbd Update changelog 2021-02-18 03:26:24 +01:00
Karol Stasiak
3d57421959
Merge pull request #100 from retrac0/apple2
ProDOS library + some small Apple II terminal fixes
2021-02-18 01:33:47 +01:00
Karol Stasiak
78c29c784d
Merge pull request #102 from agg23/agg23/OverflowErrors
Added position logging to overflow errors
2021-02-18 01:30:09 +01:00
Karol Stasiak
25adb05229 Fix typeof 2021-02-18 01:29:27 +01:00
Karol Stasiak
bb46b1e7e9 Update documentation 2021-02-18 00:51:07 +01:00
Karol Stasiak
7c60a89776 Signed multiplication 2021-02-18 00:39:14 +01:00
Karol Stasiak
02031da61a Correctly optimize variables around macros 2021-02-18 00:38:51 +01:00
Karol Stasiak
d20cc677bb The typeof builtin function 2021-02-18 00:38:30 +01:00
Karol Stasiak
2beabb7bed Improvements to constant folding 2021-02-18 00:36:13 +01:00
Karol Stasiak
fb71f88343 8080: Correctly compile sbytes to BC 2021-02-18 00:35:02 +01:00
Adam Gastineau
7689afb5d6 Added position logging to overflow errors 2021-02-03 11:51:41 -08:00
Karol Stasiak
958c1c09e7 #98: Warning about a missing call to init_rw_memory 2021-02-03 09:58:39 +01:00
Karol Stasiak
919f11af2e #101: Allow using local labels in all assembly instructions and all assembly expressions 2021-02-03 09:50:44 +01:00
Karol Stasiak
9c7e946f4c Allow labels in assembly on the same line (see #101) 2021-02-03 09:49:17 +01:00
Karol Stasiak
32b98750a9 Warn about non-volatile spinlocks (see #95) 2021-02-03 09:46:09 +01:00
Joel Heikkila
ef34f534f9 first attempt at a ProDOS library for the Apple II 2021-02-02 23:33:45 -05:00
Joel Heikkila
3a2e29888d some documentation of what I've tested 2021-01-25 20:29:54 -05:00
Joel Heikkila
d6deb81166 change monitor address to not print prompt 2021-01-25 20:15:18 -05:00
Joel Heikkila
394ac63805 0x80 + 0x0D is a2 newline 2021-01-25 16:13:59 -05:00
Karol Stasiak
42f6efc9bd Switch to snapshot versioning 2021-01-13 19:57:52 +01:00
Karol Stasiak
8b0c026bf7 Update changelog 2021-01-13 19:57:17 +01:00
Karol Stasiak
c1959b356f Make all constants referring to segments match their equivalents from the platform definition (see #87) 2021-01-13 19:55:11 +01:00
Karol Stasiak
499e650752 Define and document more magic suffixes and constants (see #87) 2021-01-13 19:35:11 +01:00
Karol Stasiak
fe4f0dcfd9 6502: Optimize more jumps in place 2021-01-13 19:26:17 +01:00
Karol Stasiak
c6932da6b3 Update changelog 2021-01-13 14:39:32 +01:00
Karol Stasiak
600bfce0c1 Allow new lines after = 2021-01-13 14:38:59 +01:00
Karol Stasiak
9feda54d92 Optimize word shifts by 7–12 bits 2021-01-13 14:31:20 +01:00
Karol Stasiak
91699b64c6 Less useless logging 2021-01-13 14:18:41 +01:00
Karol Stasiak
2a5933e115 6502: Fix sbyte to word promotion in some contexts 2021-01-13 14:18:28 +01:00
Karol Stasiak
bd8078cc47
Merge pull request #90 from agg23/agg23/RemovedOptimizationHintPrint
Removed optimization hint debug println statements
2021-01-02 01:06:31 +01:00
Adam Gastineau
30216d0be6 Removed optimization hint debug println statements 2021-01-01 14:52:37 -08:00
Karol Stasiak
181332e238 Version 0.3.24 2020-12-02 00:54:52 +01:00
Karol Stasiak
90a9538936 Various optimizations 2020-12-01 18:18:56 +01:00
Karol Stasiak
4a529b5ddc Fix typos/grammar 2020-12-01 14:26:47 +01:00
Karol Stasiak
7962a1d083 Point at the end of the line if the error is something missing at the end of the line 2020-12-01 03:21:04 +01:00
Karol Stasiak
52c9da36b8 Fix GraalVM NPE when getting a character name 2020-12-01 03:20:31 +01:00
Karol Stasiak
8dfad735ab Tiny formatting fix 2020-12-01 03:19:47 +01:00
Karol Stasiak
cba145d674 Better error messages for variable definitions in macros (#77) 2020-12-01 03:19:38 +01:00
Karol Stasiak
145f2ed711 Update changelog 2020-11-19 18:56:49 +01:00
Karol Stasiak
f2f53a4b28 Configurable entry point for ZX Spectrum, Z1013, TRS-80 and CoCo (#78) 2020-11-19 18:47:50 +01:00
Karol Stasiak
7e45967b0c Allow emitting addresses of labels in the output (#78) 2020-11-19 18:33:51 +01:00
Karol Stasiak
c8e32a876f Fix endaddr+N output 2020-11-19 18:21:08 +01:00
Karol Stasiak
b2d2c3e005 Don't emit labels that are not necessary; fix the __heap_start symbol. 2020-11-18 23:08:45 +01:00
Karol Stasiak
dc087ed887 Better error messages for arays without sizes 2020-11-18 23:08:09 +01:00
Karol Stasiak
97c7d0ffed Basic groundwork for optimization hint support 2020-11-18 22:37:58 +01:00
Karol Stasiak
385b2fd40b Fix function pointers (fixes #86) 2020-11-18 09:34:02 +01:00
Karol Stasiak
fc7643c416 Interrupt handler pointer types 2020-11-11 00:28:21 +01:00
Karol Stasiak
91409504fb Small inlining fix 2020-11-11 00:27:52 +01:00
Karol Stasiak
cd6b789416 Document explicit bool conversions 2020-11-11 00:27:29 +01:00
Karol Stasiak
f4a3601d6e 8080: Fix word negation 2020-11-11 00:25:39 +01:00
Karol Stasiak
f39810793b Use skipTests instead of includeTests 2020-11-02 13:47:16 +01:00
Karol Stasiak
831be03167
Merge pull request #82 from agg23/SBTIncludeTestFlags
Improved #36: Added compile flags for enabling tests
2020-11-02 13:37:58 +01:00
Adam Gastineau
af565b581a Fixed only some test dependencies being properly emitted 2020-10-30 22:14:37 -07:00
Karol Stasiak
4a7166b9e0
Merge pull request #84 from zbyti/master
A8 fixed example code
2020-10-30 23:22:42 +01:00
zbyti
45b4a5dfe3 A8 fixed code 2020-10-30 16:08:29 +01:00
Adam Gastineau
d483dd1994 Improved #36: Added compile flags for enabling tests 2020-10-27 19:52:12 -07:00
Karol Stasiak
4a09a80db0
Merge pull request #79 from zbyti/master
refactor and MPT player examble
2020-10-25 02:01:47 +01:00
zbyti
2ce1781e91 refator 2020-10-06 00:51:50 +02:00
zbyti
d76ae3ff9e refator 2020-10-06 00:50:50 +02:00
zbyti
758f0945f9 refactor 2020-10-06 00:42:19 +02:00
zbyti
d0154253ea .nfo files added 2020-10-06 00:39:20 +02:00
zbyti
85829102b8 .nfo files added 2020-10-06 00:36:41 +02:00
zbyti
8a4e65b365 A8 CMC Player with sample music 2020-10-05 23:17:35 +02:00
zbyti
838ef0d1eb refactor and MPT player examble 2020-10-05 22:33:22 +02:00
Karol Stasiak
963fae8275 Various documentation updates 2020-10-05 22:20:08 +02:00
Karol Stasiak
e94ccd164f Use POKEY for random seed on Atari 2020-09-30 01:51:36 +02:00
Karol Stasiak
a00e10382d Implement readline and readword for VIC-20 2020-09-30 01:37:00 +02:00
Karol Stasiak
24c0e8a8ee Fix typo 2020-09-30 01:36:13 +02:00
Karol Stasiak
5d09410350 Document TRS-80 and Z1013 library support 2020-09-30 01:07:56 +02:00
Karol Stasiak
70da293fce
Merge pull request #76 from zbyti/master
ANTIC Display List Instruction Set constans & some refactor
2020-09-29 23:02:34 +02:00
Karol Stasiak
c2e9acd3f3 Update CHANGELOG and READMEs 2020-09-29 22:57:48 +02:00
Karol Stasiak
d45fe42d17 Add Robotron Z1013 support 2020-09-29 22:57:27 +02:00
Karol Stasiak
889a4f94be All things mentioned in segment layouts should be considered used. 2020-09-29 22:49:15 +02:00
Karol Stasiak
c7008f4414 New output elements: literal ASCII strings and space-padded program name 2020-09-29 22:48:50 +02:00
zbyti
802424316c ANTIC Display List BASIC fix 2020-09-28 22:54:58 +02:00
zbyti
f9fc001c9a ANTIC Display List BASIC modes forrmating 2020-09-28 22:17:34 +02:00
zbyti
cc1adee4f1 ANTIC Display List BASIC modes 2020-09-28 22:15:39 +02:00
zbyti
362d682c11 ANTIC Display List Instruction Set table typo 2020-09-28 21:54:35 +02:00
zbyti
a4b27f73e7 ANTIC Display List Instruction Set constans 2020-09-28 21:49:44 +02:00
zbyti
1b6b49889b A8 landscape refactor 2020-09-28 19:19:35 +02:00
Karol Stasiak
2d7c365b20 TSR-80 newline is just 0x0D 2020-09-27 18:58:46 +02:00
Karol Stasiak
3af4fcffa9 Z80: Add SLS as an alternate mnemonic for SLL 2020-09-27 18:46:19 +02:00
Karol Stasiak
3a9be16107 Add TRS-80 Model 1 and 3 support 2020-09-26 23:52:49 +02:00
Karol Stasiak
3702002541 Fix header 2020-09-26 19:56:56 +02:00
Karol Stasiak
a15c9088ee
Merge pull request #75 from zbyti/master
A8 examples readme new arrangement
2020-09-26 19:56:10 +02:00
zbyti
6b3f43393e A8 Landscape refactor 2020-09-26 01:14:08 +02:00
zbyti
2823b7fde0 A8 examples readme new arrangement 2020-09-26 01:02:07 +02:00
Karol Stasiak
e0572fa3aa
Merge pull request #74 from zbyti/master
A8 examples
2020-09-26 00:14:17 +02:00
zbyti
3364f8ab10 Quatari Landscape refactor 2020-09-25 11:20:16 +02:00
zbyti
560ed09439 Quatari Landscape refactor 2020-09-25 09:45:48 +02:00
zbyti
dc2def7e72 A8 my last examples 2020-09-25 03:08:33 +02:00
Karol Stasiak
9f1309c119
Merge pull request #71 from zbyti/master
A8 new examples
2020-09-24 01:25:04 +02:00
Karol Stasiak
888f7a0fdb Fix documentation (fixes #72) 2020-09-23 23:21:35 +02:00
zbyti
1d046f26e3 A8 Grand Ttheft Antic refactor 2020-09-23 23:17:01 +02:00
zbyti
a4de573593 A8 Grand Ttheft Antic 2020-09-23 23:09:15 +02:00
zbyti
433066fedd comment fix 2020-09-23 20:18:04 +02:00
zbyti
7182f32032 more life in empty space 2020-09-23 00:04:22 +02:00
zbyti
86ae6de325 A8 horizontal stars done on one missile 2020-09-22 19:34:29 +02:00
Karol Stasiak
9f40fc5066 Add some trivial test case 2020-09-22 17:59:50 +02:00
Karol Stasiak
b87c40fc9c Migration from Nashorn to GraalJS 2020-09-22 17:59:32 +02:00
Karol Stasiak
1decf2f087 65816: Various codegen bugfixes 2020-09-22 17:59:14 +02:00
Karol Stasiak
c9f602b049 65816: Emulator bugfixes 2020-09-22 17:58:34 +02:00
Karol Stasiak
030531161e Update changelog 2020-09-21 09:10:50 +02:00
Karol Stasiak
7de23ddd44 Allow the : operator in const-pure functions 2020-09-21 09:08:49 +02:00
Karol Stasiak
2673a486d6
Merge pull request #68 from zbyti/master
A8 more examples
2020-09-21 00:18:14 +02:00
Karol Stasiak
c0eae29a41 Minor compilation speed optimization 2020-09-21 00:15:16 +02:00
Karol Stasiak
a92f24b280 Better detection of memset loops (fixes #59) 2020-09-20 23:39:30 +02:00
zbyti
e9d4359bc2 A8 Monte Carlo PI refactor (__mul_u16u8u16) 2020-09-20 22:58:20 +02:00
zbyti
07b6adf6bc two more benchmarks 2020-09-19 13:02:55 +02:00
zbyti
269519715b two more benchmarks 2020-09-19 12:59:14 +02:00
zbyti
3234bbd3d9 two more becnhmarks 2020-09-19 12:52:41 +02:00
zbyti
19d9e36fa5 A8 more examples 2020-09-19 01:34:29 +02:00
Karol Stasiak
fe094af912
Merge pull request #66 from zbyti/master
Atari 800 System Off example, some minor refactor and more examples
2020-09-17 16:01:00 +02:00
Karol Stasiak
11d2f1aa77 Switch to snapshot versioning 2020-09-17 15:29:37 +02:00
zbyti
81bf24b355 A8 System Off refactor 2020-09-17 12:18:00 +02:00
zbyti
0010358d08 A8 Chessboard drawing benchmark in GR.0 2020-09-17 11:13:28 +02:00
zbyti
8e550669c1 A8 system off example typo 2020-09-16 17:09:24 +02:00
zbyti
aaaae08c03 A8 system off example typo 2020-09-16 13:44:09 +02:00
zbyti
9ee9712554 A8 system off example typo 2020-09-16 12:50:31 +02:00
zbyti
4758dba89e A8 system off example minor refactor 2020-09-16 12:15:46 +02:00
zbyti
e8a50dc610 A8 system off example and some minor refactor 2020-09-16 12:04:39 +02:00
zbyti
88e74906b6 a8 examples refactor 2020-09-15 22:29:18 +02:00
Karol Stasiak
bed44cd08e Version 0.3.22 2020-09-15 17:16:47 +02:00
Karol Stasiak
0806e719ce Update CHANGELOG 2020-09-15 17:14:20 +02:00
Karol Stasiak
ca5fe5cdb0 6809: various optimizations 2020-09-15 17:08:38 +02:00
Karol Stasiak
947a84833a Make some command line options repeatable 2020-09-15 17:08:22 +02:00
Karol Stasiak
e8b1e9e391
Merge pull request #65 from zbyti/master
Details (A8 platform) for new release
2020-09-11 23:50:17 +02:00
zbyti
adf84c084d more info about a8 example 2020-09-09 02:47:07 +02:00
zbyti
a635449829 new a8 memory mapping helpers 2020-09-09 01:52:11 +02:00
Karol Stasiak
fc0171d5aa Update CHANGELOG 2020-09-09 01:49:00 +02:00
Karol Stasiak
40510dc436
Merge pull request #63 from zbyti/master
new memory mapping helpers
2020-09-09 01:47:05 +02:00
Karol Stasiak
615a0d7dc1 Interrupt functions in assembly should not have prologue (fixes #62) 2020-09-09 01:46:34 +02:00
Karol Stasiak
75c8ac19e1 Fix warning messages 2020-09-09 01:45:53 +02:00
Karol Stasiak
ae311f28ea Document new Atari examples 2020-09-09 01:45:39 +02:00
zbyti
3bbab4a126 new memory mapping helpers 2020-09-09 00:57:12 +02:00
Karol Stasiak
b7cb124706
Merge pull request #60 from zbyti/master
Simple Atari 800XL Memory Map
2020-09-08 23:46:21 +02:00
zbyti
866a9ee9d0 refactor 2020-09-08 00:17:10 +02:00
zbyti
e0b2d28a7d refactor 2020-09-08 00:08:43 +02:00
zbyti
f5fb1a6911 refactor 2020-09-07 23:56:50 +02:00
zbyti
19de4085d7 dli example 2020-09-07 01:29:53 +02:00
zbyti
06e5da4e66 endless scroll with random letters 2020-09-06 22:53:59 +02:00
zbyti
c31a2ee388 Simple Atari 800XL Memory Map 2020-09-05 11:58:02 +02:00
zbyti
4849069d39 Simple Atari 800XL Memory Map 2020-09-05 11:48:49 +02:00
zbyti
9a0176333b Simple Atari 800XL Memory Map 2020-09-05 11:47:24 +02:00
zbyti
6b0effaae6 Simple Atari 800XL Memory Map 2020-09-05 11:43:18 +02:00
zbyti
3582925cb1 Simple Atari 800XL Memory Map 2020-09-05 11:37:04 +02:00
Karol Stasiak
c12541c64d Fix the a8_os module (fixing #58) 2020-09-04 01:18:37 +02:00
Karol Stasiak
5e46e8ade9 Fix alignment of substructures 2020-09-02 00:44:24 +02:00
Karol Stasiak
3ded652a90 Add encodings: BraSCII, DEC MCS, LICS, MacRoman 2020-09-01 22:22:28 +02:00
Karol Stasiak
e09db3d132 Local labels in assembly 2020-09-01 22:00:07 +02:00
Karol Stasiak
539c27f13e Update CHANGELOG 2020-08-14 22:34:34 +02:00
Karol Stasiak
57776f7f93 8080: Optimization improvements 2020-08-14 22:29:19 +02:00
Karol Stasiak
7427231c3d Fix constant simplification 2020-08-14 22:29:06 +02:00
Karol Stasiak
b9cd18c3c8 Improve error message for multiple operators at the same priority 2020-08-14 22:28:50 +02:00
Karol Stasiak
49816d18fe Fix volatile 2020-08-14 22:28:31 +02:00
Karol Stasiak
70256e9d46 Fix evaluation of boolean expressions on all targets (#56) 2020-08-14 22:27:23 +02:00
Karol Stasiak
fccbf7df7d Add dollar syntax for decimal operators, disallow identifiers ending in a dollar sign. 2020-08-14 02:22:13 +02:00
Karol Stasiak
0913c5037c Typecheck division of large constants 2020-08-14 01:27:13 +02:00
Karol Stasiak
b5c51e48be Rename zx80next to z80next, document the typo (fixes #55) 2020-08-13 16:53:38 +02:00
Karol Stasiak
708fdab593
Merge pull request #54 from Kobrasadetin/patch-1
fix the value of vera_dc_hscale_hstop
2020-08-13 16:44:04 +02:00
Karol Stasiak
398d9b9c4e Switch to snapshot versioning 2020-08-13 16:43:34 +02:00
Mikko Karjanmaa
29018729f5
fix the value of vera_dc_hscale_hstop 2020-08-11 18:59:54 +03:00
328 changed files with 11074 additions and 2223 deletions

6
.gitignore vendored
View File

@ -6,6 +6,7 @@ project/project/target/
stuff
releases
src/test/scala/experiments/
src/test/java/experiments/
# doesn't work yet
examples/lunix/
# older copies
@ -30,9 +31,12 @@ issue*.mfk
*.seq
*.asm
*.lbl
*.labels
*.nl
*.fns
*.sym
*.mlb
*.dbg
*.deb
*.xex
*.nes
@ -49,6 +53,8 @@ issue*.mfk
*.rom
*.ssd
*.o
*.cmd
*.z80
HELLO
HELLOCPC
FIZZBUZZ

View File

@ -1,5 +1,195 @@
# Change log
## 0.3.30 (2021-12-15)
* Added volatile structure fields (#112).
* Added `this.function` as the alias for the current function (#118).
* Added support for constant evaluation in `file` expressions (#114).
* Allowed declaring local constants and passing untyped parameters for macros.
* Allowed treating bare function name as a pointer to it.
* Added Mesen, ld65 and "raw" label file formats (#128).
* Commodore: the address used by SYS is now determined automatically instead of hardcoded (#111).
* C64: Fixed address for `sid_v1_sr` (#115).
* EasyFlash: Fixed address for `switch_hirom` (#121).
* GB: Fixed standard library (thanks to @retrac0).
* Commander X16: Updated platform definition file (thanks to @mookiexl).
* 65CE02: Full assembly support.
* R800: Full assembly support.
* Various miscompilation fixes (#123, #125) and parser fixes (e.g. #120).
* 6809: Various optimizations.
* Improvements related to constant evaluation.
## 0.3.28 (2021-05-24)
* Officially deprecated decimal operators with apostrophes.
* Added optimization hints.
* Added `utf32be`, `utf32le`, `cp1253`, `cp1254`, `cp1257`, `geos_de` encodings.
* Allowed for underscores in numeric literals for readability purposes, similar to several other programming languages.
* Added a warning for comparisons between bytes and pointers (#110).
* Fixed escape sequences in many encodings.
* Fixed and documented absolute module imports (#106)
* Fixed and optimized sign extension.
* Fixed optimizations involving unused labels.
* Fixed pointer types to type aliases.
* Fixed parsing of Intel hex literals of the form `0BH`, `0B0H` etc.
* 6809: Fixed flow analysis in optimization.
* Optimization of certain bitmask operations.
* Parsing optimizations.
## 0.3.26 (2021-03-01)
* Array fields in structs.
* Various Apple II-related improvements, including ProDOS support (thanks to @retrac0).
* Segment-related constants now match their equivalents from the platform definition. Missing constants have been defined.
* Constants with heap start and segment start are now generated properly.
* Signed multiplication support for `sbyte` and `signed16`.
* Heavily experimental `typeof` builtin.
* Self-modifying assembly code is now supported (#101).
* Successful compilation now prints result program size.
* Warning about data not being included in the output file.
* Warnings can now be enabled and disabled individually.
* Imported modules are now identified by their full relative path, not just the token used in the `import` statement (#89).
* 6502: Fixed sbyte to word promotions in certain contexts.
* 8080: Fixed compilation of sign extension of `sbyte` values into the BC register pair.
* Fixed negative constant folding.
* Fixed optimizations around macro invocations.
* 6502: Fixed code deduplication in presence of trampolined functions.
* Optimized word shifts for between 7 and 12 bits.
* Allowed new lines after `=`.
* Various optimization improvements.
* Improved some error messages (thanks to @agg23).
* Other fixes and improvements.
## 0.3.24 (2020-12-02)
* Preliminary support for TRS-80 Model 1 and 3 running TRS-DOS.
* Preliminary support for Robotron Z1013.
* Allowed defining entry points other than the start of the segment for Atari, ZX Spectrum, CoCo, Z1013 and TRS-80. (#78)
* Allowed the `:` operator in const-pure functions.
* Added `pointer.interrupt` and `pointer.kernal_interrupt` types.
* Implemented `readline` and `readword` for VIC-20.
* `init_rand_seed` uses the POKEY on Atari.
* Useless labels are no longer emitted into the label file.
* VIC-20: added `readline` and `readword`.
* Atari: use POKEY for randomness source.
* New output format elements: ASCII string, program name.
* Fix: Pointers to functions with parameters (#86)/
* Fix: more instances of memset loops should be detected and optimized (#59).
* Fix: things mentioned in the segment layout should not be deleted even if unused.
* Fix: `endaddr+N` output format.
* 65816: some code generation fixes.
* 8080: word negation now works.
* Various optimization improvements.
* Various other fixes.
* Improved some error messages.
* Even more new Atari examples (thanks to @zbyti).
* Build process slightly changed.
## 0.3.22 (2020-09-15)
* Added local labels in assembly.
* Added alternate decimal operators (with `$` instead of `'`).
* **Potentially breaking change!** Identifiers no longer can end with `$`.
* Added `z80next` as an alternate name for the ZX Spectrum Next's processor (#55).
* Added encodings: `brascii`, `macroman`, `dmcs`, `lics`.
* Improved some error messages.
* Fix: interrupt functions written in assembly no longer have the default prologue (#62).
* Fixed the `a8_os` module (#58).
* Fixed evaluation of division of large constants.
* Fix: Structure alignment is now respected for substructures.
* X16: Fixed the address of `vera_dc_hscale_hstop` register (#54) (thanks to @Kobrasadetin).
* Fixed evaluation of more complex boolean expressions (#56).
* Fixed accesses to volatile variables.
* 8080/Z80: Optimization improvements.
* 6809: Optimization improvements.
* Various Atari improvements (#60, #63, #65) (thanks to @zbyti).
* New Atari examples (thanks to @zbyti).
## 0.3.18 (2020-04-08)
* Support for Motorola 6809 (complete, but still experimental).
@ -448,7 +638,7 @@ can no longer be read before an explicit call to `init_rw_memory`, either add th
* Added enumeration types.
* Added preprocessor.
* Added the preprocessor.
* Added `for` loops over enum types and in-place lists
@ -470,7 +660,7 @@ can no longer be read before an explicit call to `init_rw_memory`, either add th
* Extra `z` at the name of the encoding means that the string is zero-terminated.
* **Potentially breaking change!** No longer allowed to define things with names that are keywords or builtins.
* **Potentially breaking change!** It's no longer allowed to define things with names that are keywords or builtins.
* **Potentially breaking change!** Curly braces in text literals are now used for escape sequences.

View File

@ -21,36 +21,22 @@ Setting up the test suite for Millfork is tricky, so if you don't need the tests
#### Steps
* remove all test dependencies from `build.sbt`:
"org.scalatest" %% "scalatest"
"com.codingrodent.microprocessor" % "Z80Processor"
"NeatMonster" % "Intel8086"
"com.loomcom.symon" % "symon"
"com.grapeshot" % "halfnes"
"eu.rekawek.coffeegb" % "coffee-gb"
"roug.org.osnine" % "osnine-core"
* navigate to the project directory
* run `sbt 'set test in assembly := {}' compile`
* run `sbt -DskipTests compile`
to compile the project
* run `sbt 'set test in assembly := {}' assembly`
* run `sbt -DskipTests assembly`
to build the executable jar file, it should appear in `target/scala-2.12`
* on Windows, use double quotes for the last two commands:
sbt "set test in assembly := {}" compile
sbt "set test in assembly := {}" assembly
### Building with tests
Test suite is useful if you plan on modifying the compiler. Some test dependencies need manual installation.
#### Prerequisites
* JDK 1.8 with Nashorn (tests don't work on newer versions)
* JDK 1.8 or later
* Millfork up to version 0.3.22 used to require exactly JDK 1.8 with Nashorn,
as the tests didn't work on newer versions
* sbt
@ -71,7 +57,7 @@ Test suite is useful if you plan on modifying the compiler. Some test dependenci
* run `sbt compile` to compile the project
* run `sbt assemble` to build the executable jar file, it should appear in `target/scala-2.12`
* run `sbt assembly` to build the executable jar file, it should appear in `target/scala-2.12`
### Building a native executable

View File

@ -13,7 +13,7 @@ If you want to contribute:
* make a pull request, explaining what you implemented if needed.
By making pull request, you agree for your changes to be distributed in perpetuity
under the applicable license (GPL-3 for the compiler, zlib for the stdlib, CC0 for documentation)
under the applicable license (GPL-3 for the compiler, zlib for the stdlib, CC0 for the documentation)
or any other compatible license.
You retain copyright to your contributions, you do not have to assign the copyright to anybody.

View File

@ -5,7 +5,7 @@
A middle-level programming language targeting 6502-based, 8080-based, Z80-based and 6809-based microcomputers.
For binary releases, see: [https://github.com/KarolS/millfork/releases](https://github.com/KarolS/millfork/releases)
(latest: 0.3.18).
(latest: 0.3.30).
For build instructions, see [Build instructions](./COMPILING.md).
## Features
@ -22,7 +22,7 @@ For build instructions, see [Build instructions](./COMPILING.md).
* other 6502-based machines: Famicom/NES, Atari Lynx, Atari 8-bit computers, BBC Micro, Apple II+/IIe/Enhanced IIe, Atari 2600 (experimental), Commander X16 (experimental)
* Z80-based machines: ZX Spectrum 48k, NEC PC-88, Amstrad CPC, MSX
* Z80-based machines: ZX Spectrum 48k, NEC PC-88, Amstrad CPC, MSX, TRS-80 Model 1 and 3, Robotron Z1013
* CP/M

View File

@ -1,7 +1,8 @@
name := "millfork"
version := "0.3.18"
version := "0.3.31-SNAPSHOT"
// keep it at 2.12.11 for GraalVM native image compatibility!
scalaVersion := "2.12.11"
resolvers += Resolver.mavenLocal
@ -12,25 +13,42 @@ libraryDependencies += "org.apache.commons" % "commons-configuration2" % "2.2"
libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.8" % "test"
libraryDependencies += "com.codingrodent.microprocessor" % "Z80Processor" % "2.0.2" % "test"
val testDependencies = Seq(
"com.codingrodent.microprocessor" % "Z80Processor" % "2.0.2" % "test",
// see: https://github.com/NeatMonster/Intel8086
"NeatMonster" % "Intel8086" % "1.0" % "test" from "https://github.com/NeatMonster/Intel8086/raw/master/IBMPC.jar",
// these three are not in Maven Central or any other public repo
// get them from the following links or just build millfork without tests:
// https://github.com/sethm/symon/tree/71905fdb1998ee4f142260879504bc46cf27648f
// https://github.com/andrew-hoffman/halfnes/tree/061
// https://github.com/trekawek/coffee-gb/tree/coffee-gb-1.0.0
// https://github.com/sorenroug/osnine-java/tree/b77349a6c314e1362e69b7158c385ac6f89b7ab8
"com.loomcom.symon" % "symon" % "1.3.0-SNAPSHOT" % "test",
"com.grapeshot" % "halfnes" % "061" % "test",
"eu.rekawek.coffeegb" % "coffee-gb" % "1.0.0" % "test",
"roug.org.osnine" % "osnine-core" % "2.0-SNAPSHOT" % "test",
"org.graalvm.sdk" % "graal-sdk" % "20.2.0" % "test",
"org.graalvm.js" % "js" % "20.2.0" % "test",
"org.graalvm.js" % "js-scriptengine" % "20.2.0" % "test"
)
// see: https://github.com/NeatMonster/Intel8086
libraryDependencies += "NeatMonster" % "Intel8086" % "1.0" % "test" from "https://github.com/NeatMonster/Intel8086/raw/master/IBMPC.jar"
val includesTests = System.getProperty("skipTests") == null
// these three are not in Maven Central or any other public repo
// get them from the following links or just build millfork without tests:
// https://github.com/sethm/symon/tree/71905fdb1998ee4f142260879504bc46cf27648f
// https://github.com/andrew-hoffman/halfnes/tree/061
// https://github.com/trekawek/coffee-gb/tree/coffee-gb-1.0.0
// https://github.com/sorenroug/osnine-java/tree/b77349a6c314e1362e69b7158c385ac6f89b7ab8
libraryDependencies ++=(
if (includesTests) {
println("Including test dependencies")
testDependencies
} else {
Seq[ModuleID]()
}
)
libraryDependencies += "com.loomcom.symon" % "symon" % "1.3.0-SNAPSHOT" % "test"
libraryDependencies += "com.grapeshot" % "halfnes" % "061" % "test"
libraryDependencies += "eu.rekawek.coffeegb" % "coffee-gb" % "1.0.0" % "test"
libraryDependencies += "roug.org.osnine" % "osnine-core" % "2.0-SNAPSHOT" % "test"
(if (!includesTests) {
// Disable assembling tests
sbt.internals.DslEntry.fromSettingsDef(test in assembly := {})
} else {
sbt.internals.DslEntry.fromSettingsDef(Seq[sbt.Def.Setting[_]]())
})
mainClass in Compile := Some("millfork.Main")

View File

@ -29,7 +29,7 @@
* on 65816: callee will preserve the emulation flag
(setting the emulation flag correctly is the responsibility of the initialization code)
* on 65816 in native mode:
* on 65816 in the native mode:
* callee expects the M and X flag to be set and will leave them set
(8-bit accumulator and index registers by default)
@ -45,11 +45,11 @@
* if the function has one parameter of size two bytes, it is passed via the HL register pair
* if the function has one parameter of size three bytes,
its least significant two bytes are passed via the HL register pair
its least significant two bytes are passed via the HL register pair,
and the most significant byte is passed via the E register
* if the function has one parameter of size four bytes,
its least significant word is passed via the HL register pair
its least significant word is passed via the HL register pair,
and the most significant word is passed via the DE register pair
* otherwise, all parameters are passed via static locations
@ -61,11 +61,11 @@ and the most significant word is passed via the DE register pair
* two-byte return values are passed via the HL register pair
* in case of three-byte return values,
its least significant two bytes are passed via the HL register pair
its least significant two bytes are passed via the HL register pair,
and the most significant byte is passed via the E register
* in case of four-byte return values,
its least significant word is passed via the HL register pair
its least significant word is passed via the HL register pair,
and the most significant word is passed via the DE register pair
* otherwise, the return value is passed via a static location
@ -89,11 +89,11 @@ The DI register is not used.
* if the function has one parameter of size two bytes, it is passed via the BX register
* if the function has one parameter of size three bytes,
its least significant two bytes are passed via the BX register
its least significant two bytes are passed via the BX register,
and the most significant byte is passed via the DL register
* if the function has one parameter of size four bytes,
its least significant word is passed via the BX register
its least significant word is passed via the BX register,
and the most significant word is passed via the DX register
* otherwise, all parameters are passed via static locations
@ -105,11 +105,11 @@ and the most significant word is passed via the DX register
* two-byte return values are passed via the BX register
* in case of three-byte return values,
its least significant two bytes are passed via the BX register
its least significant two bytes are passed via the BX register,
and the most significant byte is passed via the DL register
* in case of four-byte return values,
its least significant word is passed via the BX register
its least significant word is passed via the BX register,
and the most significant word is passed via the DX register
* otherwise, the return value is passed via a static location

View File

@ -12,6 +12,10 @@ It implies the following:
* cannot be `inline`, `noinline` or `extern`
* cannot contain variable or array declarations
* but can contain scalar constant declarations; the constants are scoped to the particular macro invocation
* can be `asm` - in this case, they should **not** end with a return instruction
* do not have an address
@ -33,7 +37,13 @@ It implies the following:
* `call` parameters exceptionally can have their type declared as `void`;
such parameters accept expressions of any type, including `void`, however, you cannot assign from those expressions
* macros do not have their own scope (they reuse the scope from their invocations) exceptions: the parameters and the local labels defined in assembly
* macros do not have their own scope (they reuse the scope from their invocations) exceptions:
* the parameters
* the local labels defined in assembly
* the local constants
* control-flow statements (`break`, `continue`, `return`, `goto`, `label`) are run as if places in the caller function
@ -123,7 +133,7 @@ calls with non-constant arguments are subject to the regular rules.
* functions declared with the `noinline` keyword will never be inlined
* the remaining functions may be inlined only if the `-finline` command-line option is enabled
* the remaining functions may be inlined only if the `-finline` command-line option is enabled,
and the compiler decides the function is worth doing
## Automatic subroutine extraction

View File

@ -46,6 +46,8 @@ but the main disadvantages are:
* cannot use them in inline assembly code blocks
* structs and unions containing array fields are not supported
The implementation depends on the target architecture:
* on 6502, the stack pointer is transferred into the X register and used as a base

View File

@ -1,18 +1,30 @@
[< back to index](../doc_index.md)
### A note about Apple II
## Apple II
Apple II variants other than II+/IIe/Enhanced IIe are untested;
this includes the original II, IIc and IIc+, but also later compatible computers (Apple III and IIgs).
They may or may not work.
### Model support
The current platform configuration for the Apple II targets the original Apple II with an NMOS processor.
Simple programs have been tested on the Apple II, II+, IIe and enhanced IIe. The IIc, IIc+ are untested.
The IIgs may work in compatibility mode, but this is untested. The Apple III is untested.
ProDOS support is handled by the [`apple2_prodos` module](../stdlib/apple2.md).
### Running your program
The compiler output is a raw machine code file, which then has to be put on a disk.
You can do it using [CiderPress](http://a2ciderpress.com/),
[AppleCommander](https://applecommander.github.io/),
or some other tool.
The file has to be loaded from $0C00. An example how to put such file onto a disk using AppleCommander:
The file has to be loaded from $0C00. An example how to put such a file onto a disk using AppleCommander:
java -jar AppleCommander.jar -p disk_image.dsk FILENAME B 0xc00 < compiler_output.a2
When you have placed your file on disk, boot the disk and enter this at the BASIC prompt:
] BRUN FILENAME
This has been successfully tested under DOS 3.3 and [ProDOS 2.4](https://prodos8.com/), on an Apple II+ and Apple IIe.
java -jar AppleCommander-1.3.5.jar -p disk_image.dsk FILENAME B 0xc00 < compiler_output.a2
Creating a bootable disk is beyond the scope of this document.

View File

@ -31,7 +31,7 @@ no extension for BBC micro program file,
Default: If compiling one file with `.mfk` extension, the same name as the input file. Otherwise, `a`.
* `-s` Generate also the assembly output. It is not compatible with any assembler, but it serves purely informational purpose. The file has the same nam as the output file and the extension is `.asm`.
* `-s` Generate also the assembly output. It is not compatible with any assembler, but it serves purely informational purpose. The file has the same nam as the output file, and the extension is `.asm`.
* `-g` Generate also the label file. The label file contains labels with their addresses, with duplicates removed.
It can be loaded into the monitor of the emulator for debugging purposes.
@ -47,6 +47,12 @@ The extension and the file format are platform-dependent.
* `-G sym` format used by the WLA DX assembler. The extension is `.sym`.
* `-G fceux` multi-file format used by the FCEUX emulator. The extension is `.nl`.
* `-G mesen` format used by the Mesen emulator. The extension is `.mlb`.
* `-G ld65` a simplified version of the format used by the `ld65` linker (used by CC65 and CA65). The extension is `.dbg`.
* `-G raw` Millfork-specific format. The extension is '.labels'. Each row contains bank number, start address, end address (if known), object type, and Millfork-specific object identifier.
* `-fbreakpoints`, `-fno-breakpoints`
Whether the compiler should use the `breakpoint` macro.
@ -59,7 +65,7 @@ Those directories are searched for modules and platform definitions.
When searching for modules, the directory containing the file currently being compiled is also searched.
When searching for platform definitions, the current working directory is also searched.
If not given, the compiler will try to detect the default include directory.
If given, then the compiler will NOT try to detect the default include directory and you will have to add it to the list yourself.
If given, then the compiler will NOT try to detect the default include directory, and you will have to add it to the list yourself.
* `-i <dir>` Add a directory to the include directories.
Unlike `-I`, this does not replace the default include directory and allows using directories with semicolons in their names.
@ -206,6 +212,10 @@ The compiler doesn't support accessing the stack variables via the S stack point
* `-O9` Optimize code using superoptimizer (experimental). Computationally very expensive, decent results.
* `-fhints`, `-fno-hints`
Whether optimization hints should be used.
Default: yes.
* `-finline`, `-fno-inline` Whether should inline functions automatically.
See the [documentation about inlining](../abi/inlining.md). Computationally easy, can give decent gains.
`.ini` equivalent: `inline`.
@ -278,3 +288,45 @@ By default, the compiler emits only some of the most important warnings.
* `-Wnone` Disable all warnings.
* `-Wfatal` Treat warnings as errors.
You can also enable or disable warnings individually:
* `-Wbuggy`, `-Wno-buggy`
Whether should warn about code that may cause surprising behaviours or even miscompilation.
Default: enabled.
* `-Wdeprecation`, `-Wno-deprecation`
Whether should warn about deprecated aliases.
Default: enabled.
* `-Wcomparisons`, `-Wno-comparisons`
Whether should warn about comparisons between bytes and pointers.
Default: enabled.
* `-Wextra-comparisons`, `-Wno-extra-comparisons`
Whether should warn about simplifiable unsigned integer comparisons.
Default: disabled.
* `-Wfallback`, `-Wno-fallback`
Whether should warn about the use of default values by text codecs, the preprocessor, and array literals.
Default: enabled.
* `-Wmissing-output`, `-Wno-missing-output`
Whether should warn about data that is missing in output files.
Default: enabled.
* `-Woverlapping-call`, `-Wno-overlapping-call`
Whether should warn about calls to functions in a different, yet overlapping segment.
Default: enabled.
* `-Wror`, `-Wno-ror`
Whether should warn about the ROR instruction (6502 only).
Default: disabled.
* `-Wuseless`, `-Wno-useless`
Whether should warn about code that does nothing.
Default: enabled.
* `-Whints`, `-Wno-hints`
Whether should warn about unsupported optimization hints.
Default: enabled.

View File

@ -2,6 +2,11 @@
### A note about Commodore 64
#### Unusual main function location
If you're creating a prg file and your `main` function may be located at address $2710 hex (10000 decimal) or higher,
you might need to define the `DISPLACED_MAIN=1` preprocessor feature.
#### Multifile programs
A multifile program is a program stored on a disk that consists of the main program file that is executed first

View File

@ -8,7 +8,7 @@ You can do it using [CPCDiskXP](http://www.cpcwiki.eu/index.php/CPCDiskXP),
[iDSK](http://www.cpcwiki.eu/index.php/IDSK),
or some other tool.
The file has to be loaded from $0400. An example how to put such file onto a disk using CPCDiskXP:
The file has to be loaded from $0400. An example how to put such a file onto a disk using CPCDiskXP:
CPCDiskXP -File FILENAME -AddAmsdosHeader 0400 -AddToNewDsk disk_image.dsk

View File

@ -37,8 +37,11 @@ if a line ends with a backslash character, the value continues to the next line.
* `z80` (Zilog Z80)
* `strictz80` (Z80 without illegal instructions)
* `r800` (R800)
* `z80next` (Z80 core from ZX Spectrum Next)
* `z80next` (Z80 core from ZX Spectrum Next)
Note: Millfork version 0.3.18 and earlier uses the name `zx80next` for this architecture.
* `i8080` (Intel 8080)
@ -79,6 +82,8 @@ This list cannot contain module template instantiations.
* `emit_x80` whether the compiler should emit instructions present on Sharp LR35902 and Z80, but absent on Intel 8080, default is `true` on compatible processors and `false` elsewhere
* `emit_z80` whether the compiler should emit Zilog Z80 instructions not covered by `emit_x80`, default is `true` on compatible processors and `false` elsewhere
* `emit_r800` whether the compiler should emit R800 instructions, default is `true` on compatible processors and `false` elsewhere
* `prevent_jmp_indirect_bug` whether the compiler should try to avoid the indirect JMP bug,
default is `false` on 65C02-compatible or non-6502 processors and `true` elsewhere
@ -172,7 +177,7 @@ Default: `after_code`.
* `segment_NAME_bank` the bank number the segment belongs to. Default: `0`.
For better debugging on NES, RAM segments should use bank number `$ff`.
* `segment_NAME_fill` the byte value used to fill gaps and other unused space in the bank. Default: `0`.
* `segment_NAME_fill` the byte value used to fill gaps and other unused space in the segment. Default: `0`.
* `segment_NAME_layout` a comma-separated list of object names that defines in what order the objects are laid out in the segment.
One item has to be `*`, it means "all the other objects".
@ -203,9 +208,15 @@ Default: `main,*`
* `endaddr_be` the same, but big-endian
* `startaddr+123`, `startaddr_be+123`, `endaddr+123`, `endaddr_be+123` the same, but incremented by the given number
* `addr:XXXX` little-endian 16-bit address of the symbol XXXX
* `addr_be:XXXX` the same, but big-endian
* `startaddr+123`, `startaddr_be+123`, `endaddr+123`, `endaddr_be+123`, `addr:XXXX+123`, `addr_be:XXXX+123` the same, but incremented by the given number
* `startaddr-123`, `startaddr_be-123`, `endaddr-123`, `endaddr_be-123` the same, but decremented by the given number
* the number can be decimal, hexadecimal, octal, quaternary or binary
* `startaddr-123`, `startaddr_be-123`, `endaddr-123`, `endaddr_be-123`, `addr:XXXX-123`, `addr_be:XXXX-123` the same, but decremented by the given number
* `startpage` the high byte of `startaddr`
@ -216,18 +227,28 @@ Default: `main,*`
* `length+123`, `length_be+123` the same, but incremented by the given number
* `length-123`, `length_be-123` the same, but decremented by the given number
* `programname-123` the name of the program of the given length, uppercase ASCII, padded with spaces
* `allocated` all used bytes
* `pagecount` the number of pages used by all used bytes (including partially filled pages)
* `"<string>"` literal ASCII string; commas, non-ASCII characters and escape sequences are not supported
* `<addr>:<addr>` - inclusive range of bytes
* `<segment>:<addr>:<addr>` - inclusive range of bytes in a given segment
* `d88` - a D88 floppy disk image for PC-88
* `tap` - a tape disk image for ZX Spectrum
* `tap:XXXX` - a tape image for ZX Spectrum; XXXX is the name of the entry point to the program
* `tap` equivalent to `tap:main`
* `trscmd:XXXX` - a chunked loadable executable for TRS-80 Model 1 or 3 running TRS-DOS, also known as the /CMD format; XXXX is the name of the entry point to the program
* `trscmd` - equivalent to `trscmd:main`
* `format_segment_NAME` if using the `per_segment` style, overrides the format for the given segment
@ -246,3 +267,7 @@ Default: `main,*`
* `sym` format used by the WLA/DX assembler. The extension is `.sym`.
* `fceux` multi-file format used by the FCEUX emulator. The extension is `.nl`.
* `mesen` format used by the Mesen emulator. The extension is `.mlb`.
* `ld65` format used by the `ld65` linker. The extension is `.dbg`.

View File

@ -36,7 +36,7 @@ The minimal Famicom program thus looks like this:
To use a mapper of your choice, create a new `.ini` file with the definitions you need.
The most important ones are `[output]format` and `[allocation]segments`.
Currently, its a bit inconvenient to create programs using mappers that change the bank containing the interrupt vectors.
Currently, it's a bit inconvenient to create programs using mappers that change the bank containing the interrupt vectors.
Therefore, it's recommended to stick to mappers that have a fixed bank at the end of the address space.
Mappers that should be fine: NROM (0), CNROM (1), UxROM(2), MMC2 (9), MMC3 (4), MMC4 (10), MMC6 (4).

View File

@ -99,6 +99,12 @@ The compiler emits COM files.
* `cpm_z80` CP/M on Z80
* `z1013` Robotron Z1013. The compiler emits Z80 files.
* `trs80m1cmd` TRS-80 Model 1 running TRS-DOS. The compiler emits CMD files.
* `trs80m3cmd` TRS-80 Model 3 running TRS-DOS. The compiler emits CMD files.
* `coco_rsdos` Tandy Color Computer running RS-DOS. (very experimental)
Read [the Color Computer programming guide](./coco-programming-guide.md) for more info.

View File

@ -26,6 +26,8 @@
* [Predefined constants](lang/predefined_constants.md)
* [List of magic suffixes](lang/suffixes.md)
* [List of text encodings and escape sequences](lang/text.md)
* [Defining custom encodings](lang/custom-encoding.md)
@ -42,6 +44,8 @@
* [Important guidelines regarding reentrancy](lang/reentrancy.md)
* [Optimization hints](lang/hints.md)
* [List of keywords](lang/keywords.md)
## Library reference
@ -69,10 +73,14 @@
* [Definitions available on only some platforms](stdlib/frequent.md)
* [C64-only modules](stdlib/c64.md)
* [VIC-20-only modules](stdlib/vic20.md)
* [PET-only modules](stdlib/cbm_pet.md)
* [`cbm_file` module](stdlib/cbm_file.md)
* [Apple II-only modules](stdlib/apple2.md)
* [NES-only modules](stdlib/nes.md)

View File

@ -33,6 +33,6 @@ Millfork is © by Karol Stasiak, and is released under the GNU Public License ve
Millfork standard include files are © by Karol Stasiak, and are released under the zlib License.
Millfork documentation is realeased under the [CC0 1.0 Universal (CC0 1.0) Public Domain Dedication](https://creativecommons.org/publicdomain/zero/1.0/).
Millfork documentation is released under the [CC0 1.0 Universal (CC0 1.0) Public Domain Dedication](https://creativecommons.org/publicdomain/zero/1.0/).
This means you are allowed to develop Millfork programs, both free and proprietary, open- and closed-source, without any extra obligations or requirements.

View File

@ -39,7 +39,7 @@ Currently, some extra 65CE02/65816 instructions are not supported yet.
Undocumented instructions are supported using various opcodes.
Labels have to be followed by a colon and they can optionally be on a separate line.
Labels have to be followed by a colon, and they can optionally be on a separate line.
Indentation is not important:
first: INC x
@ -48,9 +48,20 @@ Indentation is not important:
INC z
Label names have to start with a letter and can contain digits, underscores and letters.
This means than they cannot start with a period like in many other assemblers.
Similarly, anonymous labels designated with `+` or `-` are also not supported.
Global label names have to start with a letter and can contain digits, underscores and letters.
Local label names (available since Millfork 0.3.22) start with a period and are visible only in the given function.
Anonymous labels designated with `+` or `-` are also not supported.
Referring to a global label with an offset requires wrapping it in `label(…)`:
STA .local_opcode // ok
STA label(.local_opcode) // ok
STA .local_opcode + 1 // ok
STA label(.local_opcode) + 1 // ok
STA global_opcode // ok
STA label(global_opcode) // ok
STA global_opcode + 1 // NOT OK
sta label(global_opcode) + 1 // ok
Assembly can refer to variables and constants defined in Millfork,
but you need to be careful with using absolute vs immediate addressing:
@ -70,7 +81,7 @@ but you need to be careful with using absolute vs immediate addressing:
}
Any assembly opcode can be prefixed with `?`, which allows the optimizer change it or elide it if needed.
Opcodes without that prefix will be always compiled as written.
Opcodes without that prefix will always be compiled as written.
The '!' prefix marks the statement as volatile, which means it will be a subject to certain, but not all optimizations,
in order to preserve its semantics.
@ -113,7 +124,7 @@ the return type can be any valid return type, like for Millfork functions.
If the size of the return type is one byte,
then the result is passed via the accumulator.
If the size of the return type is two bytes,
then the low byte of the result is passed via the accumulator
then the low byte of the result is passed via the accumulator,
and the high byte of the result is passed via the X register.
@ -220,7 +231,7 @@ it should abide to the following rules:
* explicitly use 16-bit immediate operands when appropriate; the assembler doesn't track flags and assumes 8-bit immediates by default (TODO: actually implement the 16-bit inline assembly correctly)
* use far jumps unless you're sure that the called function returns with an `RTS`
* use far jumps unless you are sure the called function returns with an `RTS`
* on 65CE02:

View File

@ -14,7 +14,7 @@ There are two ways to include raw assembly code in your Millfork programs:
Millfork inline assembly uses the same three-letter opcodes as most other 6809 assemblers.
Labels have to be followed by a colon and they can optionally be on a separate line.
Labels have to be followed by a colon, and they can optionally be on a separate line.
Indentation is not important:
first: INC a
@ -23,9 +23,20 @@ Indentation is not important:
INC c
Label names have to start with a letter and can contain digits, underscores and letters.
This means than they cannot start with a period like in many other assemblers.
Similarly, anonymous labels designated with `+` or `-` are also not supported.
Global label names have to start with a letter and can contain digits, underscores and letters.
Local label names (available since Millfork 0.3.22) start with a period and are visible only in the given function.
Anonymous labels designated with `+` or `-` are also not supported.
Referring to a global label with an offset requires wrapping it in `label(…)`:
STA .local_opcode // ok
STA label(.local_opcode) // ok
STA .local_opcode + 1 // ok
STA label(.local_opcode) + 1 // ok
STA global_opcode // ok
STA label(global_opcode) // ok
STA global_opcode + 1 // NOT OK
STA label(global_opcode) + 1 // ok
Assembly can refer to variables and constants defined in Millfork,
but you need to be careful with using absolute vs immediate addressing:
@ -52,7 +63,7 @@ You can use `>` do signify the absolute addressing mode, but it is never necessa
This option exists only for compatibility with other assemblers.
Any assembly opcode can be prefixed with `?`, which allows the optimizer change it or elide it if needed.
Opcodes without that prefix will be always compiled as written.
Opcodes without that prefix will always be compiled as written.
The '!' prefix marks the statement as volatile, which means it will be a subject to certain, but not all optimizations,
in order to preserve its semantics.

View File

@ -32,7 +32,7 @@ It does not support instructions that are unavailable on the Z80 or other undocu
Not all ZX Spectrum Next instructions are supported. `JP (C)`, `BSLA` and similar instructions are not supported.
Labels have to be followed by a colon and they can optionally be on a separate line.
Labels have to be followed by a colon, and they can optionally be on a separate line.
Indentation is not important:
// Zilog syntax
@ -48,9 +48,20 @@ Indentation is not important:
INR c
Label names have to start with a letter and can contain digits, underscores and letters.
This means than they cannot start with a period like in many other assemblers.
Similarly, anonymous labels designated with `+` or `-` are also not supported.
Global label names have to start with a letter and can contain digits, underscores and letters.
Local label names (available since Millfork 0.3.22) start with a period and are visible only in the given function.
Anonymous labels designated with `+` or `-` are also not supported.
Referring to a global label with an offset requires wrapping it in `label(…)`:
LD (.local_opcode),A // ok
LD (label(.local_opcode)),A // ok
LD (.local_opcode + 1),A // ok
LD (label(.local_opcode) + 1),A // ok
LD (global_opcode),A // ok
LD (label(global_opcode)),A // ok
LD (global_opcode + 1),A // NOT OK
LD (label(global_opcode) + 1),A // ok
Assembly can refer to variables and constants defined in Millfork,
but you need to be careful with using absolute vs immediate addressing:
@ -75,7 +86,7 @@ but you need to be careful with using absolute vs immediate addressing:
}
Any assembly opcode can be prefixed with `?`, which allows the optimizer change it or elide it if needed.
Opcodes without that prefix will be always compiled as written.
Opcodes without that prefix will always be compiled as written.
The '!' prefix marks the statement as volatile, which means it will be a subject to certain, but not all optimizations,
in order to preserve its semantics.
@ -263,8 +274,8 @@ Intel syntax | Zilog syntax
**SLAY d** | **SLA IY(d)**
**SRAY d** | **SRA IY(d)**
**SRLY d** | **SRL IY(d)**
**SLLR r** | **SLL r**
**SLLY d** | **SLL IY(d)**
**SLLR r** | **SLL r**, SLS r
**SLLY d** | **SLL IY(d)**, SLS IY(d)
**SPIY** | **LD SP,IY**
**PUSHIY**, PUSH IY | **PUSH IY**
**POPIY**, POP IY | **POP IY**

View File

@ -16,7 +16,7 @@ No other lines are allowed in the file.
* `NAME=<name>` defines the name for this encoding. Required.
* `BUILTIN=<internal name>` defines this encoding to be a UTF-based encoding.
`<internal name>` may be one of `UTF-8`, `UTF-16LE`, `UTF-16BE`.
`<internal name>` may be one of `UTF-8`, `UTF-16LE`, `UTF-16BE`, `UTF-32LE`, `UTF-32BE`.
If this directive is present, the only other allowed directive in the file is the `NAME` directive.
* `EOT=<xx>` where `<xx>` are two hex digits, defines the string terminator byte.

View File

@ -4,17 +4,17 @@
Syntax:
`[segment (<segment>)] [<modifiers>] <return_type> <name> ( <params> ) [align ( <alignment> )] [@ <address>] { <body> }`
`[segment (<segment>)] [<modifiers>] <return_type> <name> ( <params> ) [align ( <alignment> )] [<optimization hints>] [@ <address>] { <body> }`
`[segment (<segment>)] [<modifiers>] <return_type> <name> ( <params> ) [align ( <alignment> )] [@ <address>] = <expression>`
`[segment (<segment>)] [<modifiers>] <return_type> <name> ( <params> ) [align ( <alignment> )] [<optimization hints>] [@ <address>] = <expression>`
`[segment (<segment>)] asm <return_type> <name> ( <params> ) @ <address> extern`
`[segment (<segment>)] asm <return_type> <name> ( <params> ) [<optimization hints>] @ <address> extern`
Examples:
void do_nothing() { }
inline byte two() = 2
extern asm void chkout(byte register(a) char) @ $FFD2
asm void chkout(byte register(a) char) !preserves_x !preserves_y @ $FFD2 extern
segment(prgrom0) void main_loop(word w, byte x) align(fast) { // body omitted
@ -39,7 +39,7 @@ Examples:
You are not allowed to call such functions directly.
The function cannot have parameters and the return type should be `void`.
* `kernal_interrupt` the function is an interrupt handler called from a generic vendor-provider hardware interrupt handler.
* `kernal_interrupt` the function is an interrupt handler called from a generic vendor-provided hardware interrupt handler.
The hardware instruction handler is assumed to have preserved the CPU registers,
so this function only has to preserve the zeropage pseudoregisters.
An example is the Commodore 64 interrupt handler that calls the function at an address read from $314/$315.
@ -68,6 +68,8 @@ For assembly functions, certain parameter names are interpreted as CPU registers
* on 6502, it means that the function will not cross a page boundary if possible
* on Z80, it is ignored
* `<optimization hints>` is a list of [optimization hints](./hints.md), separated by spaces
* `<address>` is a constant expression that defines where in the memory the function is or will be located.
* `extern` is a keyword than marks functions that are not defined in the current program,
@ -78,16 +80,19 @@ Such functions should be marked as written in assembly and should have their par
* `<expression>` is an expression. It is equivalent to a function body of form `{ return <expression> }`.
The address of an non-macro function `f` is a constant `f.addr`.
The address of a non-macro function `f` is a constant `f.addr`.
Non-macro, non-interrupt functions which have max one parameter of size max 2 bytes
and return `void` or a value of size max 2 bytes,
can be accessed via a pointer.
void f() {}
void g(byte x) {}
function.void.to.void p = f.pointer
function.byte.to.void p = g.pointer
call(p)
call(p, 13)
The value of the pointer `f.pointer` may not be the same as the value of the function address `f.addr`.

84
docs/lang/hints.md Normal file
View File

@ -0,0 +1,84 @@
[< back to index](../doc_index.md)
# Optimization hints
Optimization hints are optional annotations for functions and variables
that allow the compiler to make extra assumptions that help with code optimization.
The general idea is that removing or disabling optimization hints will not break the code,
but adding invalid optimization hints may break the code.
Every optimization hint's name starts with an exclamation mark.
Optimization hints marked with **(X)** currently do nothing and are planned to be implemented in the future.
## Hints for functions
* `!preserves_memory` the function does not write to memory
* `!idempotent` calling the function multiple times in succession has no effect
* `!hot` the function is hot and should be optimized for speed at the cost of increased size
* `!cold` **(X)** the function is cold and should be optimized for size at the cost of increased run time
* `!odd` the function returns an odd value
* `!even` the function returns an even value
## Hints for 6502 assembly functions
These hints have only effect when used on an assembly function on a 6502 target:
* `!preserves_a` the function preserves the contents of the A register
* `!preserves_x` the function preserves the contents of the X register
* `!preserves_y` the function preserves the contents of the Y register
* `!preserves_c` the function preserves the contents of the carry flag
## Hints for 8080/Z80/LR35902 assembly functions
These hints have only effect when used on an assembly function on a 8080-like target:
* `!preserves_a` the function preserves the contents of the A register
* `!preserves_bc` the function preserves the contents of the B and C registers
* `!preserves_de` the function preserves the contents of the D and E registers
* `!preserves_hl` the function preserves the contents of the H and L registers
* `!preserves_cf` the function preserves the contents of the carry flag
## Hints for 6809 assembly functions
These hints have only effect when used on an assembly function on a 6809 target:
* `!preserves_a` the function preserves the contents of the A register
* `!preserves_b` the function preserves the contents of the B register
* `!preserves_d` the function preserves the contents of the A and B register
* `!preserves_dp` **(X)** the function preserves the contents of the DP register; exceptionally this can also be used on non-assembly functions
* `!preserves_x` the function preserves the contents of the X register
* `!preserves_y` the function preserves the contents of the Y register
* `!preserves_u` the function preserves the contents of the U register
* `!preserves_c` the function preserves the contents of the carry flag
## Hints for variables
* `!odd` **(X)** the variable can only contain odd values
* `!even` **(X)** the variable can only contain even values

View File

@ -14,7 +14,14 @@ Octal: `0o172`
Hexadecimal: `$D323`, `0x2a2`
When using Intel syntax for inline assembly, another hexadecimal syntax is available: `0D323H`, `2a2h`.
Digits can be separated by underscores for readability. Underscores are also allowed between the radix prefix and the digits:
123_456
0x01_ff
0b_0101_1111__1100_0001
$___________FF
When using Intel syntax for inline assembly, another hexadecimal syntax is available: `0D323H`, `2a2h`, `3e_h`.
It is not allowed in any other places.
The type of a literal is the smallest type of undefined signedness
@ -63,9 +70,9 @@ The byte constant `nullchar` is defined to be equal to the string terminator in
and the byte constant `nullchar_scr` is defined to be equal to the string terminator in the `scr` encoding (`'{nullchar}'scr`).
You can override the values for `nullchar` and `nullchar_scr`
by defining preprocesor features `NULLCHAR` and `NULLCHAR_SCR` respectively.
by defining preprocessor features `NULLCHAR` and `NULLCHAR_SCR` respectively.
Warning: If you define UTF-16 to be you default or screen encoding, you will encounter several problems:
Warning: If you define UTF-16 or UTF-32 to be you default or screen encoding, you will encounter several problems:
* `nullchar` and `nullchar_scr` will still be bytes, equal to zero.
* the `string` module in the Millfork standard library will not work correctly
@ -75,21 +82,26 @@ Warning: If you define UTF-16 to be you default or screen encoding, you will enc
You can also prepend `p` to the name of the encoding to make the string length-prefixed.
The length is measured in bytes and doesn't include the zero terminator, if present.
In all encodings except for UTF-16 the prefix takes one byte,
In all encodings except for UTF-16 and UTF-32 the prefix takes one byte,
which means that length-prefixed strings cannot be longer than 255 bytes.
In case of UTF-16, the length prefix contains the number of code units,
so the number of bytes divided by two,
which allows for strings of practically unlimited length.
The length is stores as two bytes and is always little endian,
The length is stored as two bytes and is always little endian,
even in case of the `utf16be` encoding or a big-endian processor.
In case of UTF-32, the length prefix contains the number of Unicode codepoints,
so the number of bytes divided by four.
The length is stored as four bytes and is always little endian,
even in case of the `utf32be` encoding or a big-endian processor.
"this is a Pascal string" pascii
"this is also a Pascal string"p
"this is a zero-terminated Pascal string"pz
Note: A string that's both length-prefixed and zero-terminated does not count as a normal zero-terminated string!
To pass it to a function that expects a zero-terminated string, add 1 (or, in case of UTF-16, 2):
To pass it to a function that expects a zero-terminated string, add 1 (or, in case of UTF-16, 2, or UTF-32, 4):
pointer p
p = "test"pz

View File

@ -11,7 +11,8 @@ Each module has a name, which is its unique identifier.
A module name is a sequence of slash-separated valid Millfork identifiers.
The name also defines where the module is located:
a module named `a/b` is presumed to exist in `a/b.mfk`
and it's looked up first in the current working directory,
and it's looked up first in the directory that contains the current source file,
then in the current working directory,
and then in the include directories.
A module can import other modules, using the `import` statement.

View File

@ -18,9 +18,9 @@ Millfork has different operator precedence compared to most other languages. Fro
* `->` and `[]`
* `*`, `*'`, `/`, `%%`
* `*`, `$*`, `/`, `%%`
* `+`, `+'`, `-`, `-'`, `|`, `&`, `^`, `>>`, `>>'`, `<<`, `<<'`, `>>>>`
* `+`, `$+`, `-`, `$-`, `|`, `&`, `^`, `>>`, `$>>`, `<<`, `$<<`, `>>>>`
* `:`
@ -34,13 +34,19 @@ Millfork has different operator precedence compared to most other languages. Fro
You cannot use two different operators at the same precedence levels without using parentheses to disambiguate.
It is to prevent confusion about whether `a + b & c << d` means `(a + b) & (c << d)` `((a + b) & c) << d` or something else.
The only exceptions are `+` and `-`, and `+'` and `-'`.
They are interpreted as expected: `5 - 3 + 2 == 4` and `5 -' 3 +' 2 == 4`.
Note that you cannot mix `+'` and `-'` with `+` and `-`.
The only exceptions are `+` and `-`, and `$+` and `$-`.
They are interpreted as expected: `5 - 3 + 2 == 4` and `5 $- 3 $+ 2 == 4`.
Note that you cannot mix `$+` and `$-` with `+` and `-`.
Certain operators (`/`, `%%`, `<<`, `>>`, `<<'`, `>>'`, `>>>>`, `:`, `!=`) cannot have more than 2 parameters,
Certain operators (`/`, `%%`, `<<`, `>>`, `$<<`, `$>>`, `>>>>`, `:`, `!=`) cannot have more than 2 parameters,
i.e. `x / y / z` will not compile.
The decimal operators have two different forms:
* apostrophe form (e.g. `+'`) the original one, deprecated, will be removed in Millfork 0.4
* dollar form (e.g. `$+`) available since Millfork 0.3.22
## Argument types
In the descriptions below, arguments to the operators are explained as follows:
@ -82,14 +88,14 @@ TODO
## Binary arithmetic operators
* `+`, `-`:
* `+`, `-`: addition and subtraction
`byte + byte`
`constant word + constant word`
`constant long + constant long`
`constant word + byte`
`word + word` (zpreg)
* `*`: multiplication; the size of the result is the same as the size of the arguments
* `*`: multiplication (signed or unsigned); the size of the result is the same as the size of the largest of the arguments
`byte * constant byte`
`constant byte * byte`
`constant word * constant word`
@ -129,17 +135,20 @@ These operators work using the decimal arithmetic (packed BCD).
On Ricoh-based targets (e.g. Famicom) they require the zeropage register to have size at least 4
* `+'`, `-'`: decimal addition/subtraction
`byte +' byte`
`constant word +' constant word`
`constant long +' constant long`
`word +' word` (zpreg)
* `$+`, `$-`: decimal addition/subtraction
`+'`, `-'`: (deprecated form)
`byte $+ byte`
`constant word $+ constant word`
`constant long $+ constant long`
`word $+ word` (zpreg)
* `*'`: decimal multiplication
`constant *' constant`
* `$*`: decimal multiplication
`*'`: (deprecated form)
`constant $* constant`
* `<<'`, `>>'`: decimal multiplication/division by power of two
`byte <<' constant byte`
* `$<<`, `$>>`: decimal multiplication/division by power of two
`<<'`, `>>'`: (deprecated form)
`byte $<< constant byte`
## Comparison operators
@ -192,7 +201,8 @@ An expression of form `a[f()] += b` may call `f` an undefined number of times.
`mutable word = word`
`mutable long = long`
* `+=`, `+'=`, `|=`, `^=`, `&=`: modification in place
* `+=`, `$+=`, `|=`, `^=`, `&=`: modification in place
`+'=` (deprecated form)
`mutable byte += byte`
`mutable word += word`
`mutable trivial long += long`
@ -202,12 +212,14 @@ An expression of form `a[f()] += b` may call `f` an undefined number of times.
`mutable word <<= byte`
`mutable trivial long <<= byte`
* `<<'=`, `>>'=`: decimal shift in place
`mutable byte <<'= constant byte`
`mutable word <<'= constant byte`
`mutable trivial long <<'= constant byte`
* `$<<=`, `$>>=`: decimal shift in place
`<<'=`, `>>'=` (deprecated form)
`mutable byte $<<= constant byte`
`mutable word $<<= constant byte`
`mutable trivial long $<<= constant byte`
* `-=`, `-'=`: subtraction in place
* `-=`, `$-=`: subtraction in place
`-'=` (deprecated form)
`mutable byte -= byte`
`mutable word -= simple word`
`mutable trivial long -= simple long`
@ -218,8 +230,9 @@ An expression of form `a[f()] += b` may call `f` an undefined number of times.
`mutable word *= unsigned byte` (zpreg)
`mutable word *= word` (zpreg)
* `*'=`: decimal multiplication in place
`mutable byte *'= constant byte`
* `$*=`: decimal multiplication in place
`*'=` (deprecated form)
`mutable byte $*= constant byte`
* `/=`, `%%=`: unsigned division and modulo in place
`mutable unsigned byte /= unsigned byte` (zpreg)
@ -278,9 +291,9 @@ but you can access its fields or take its pointer:
* `nonet`: expansion of an 8-bit operation to a 9-bit operation
`nonet(byte + byte)`
`nonet(byte +' byte)`
`nonet(byte $+ byte)`
`nonet(byte << constant byte)`
`nonet(byte <<' constant byte)`
`nonet(byte $<< constant byte)`
Other kinds of expressions than the above (even `nonet(byte + byte + byte)`) will not work as expected.
* `hi`, `lo`: most/least significant byte of a word
@ -297,7 +310,16 @@ but not
some enum → `word`
* `sizeof`: size of the argument in bytes; the argument can be an expression or a type,
and the result is a constant of either `byte` or `word` type, depending on the actual value
and the result is a constant of either `byte` or `word` type, depending on the actual value.
In case of aligned types, this returns the aligned size.
* `typeof`: a word constant that identifies the type of the argument; the argument can be an expression or a type.
The argument is never evaluated.
**Warnings:**
* **This is a highly experimental feature.**
* The exact values may change in any future version of the compiler. Only compare one `typeof` to another `typeof`.
* There is no guarantee that different types will have different values of `typeof`. Indeed, it's even easy to see that a Millfork program can have more than 65536 types and values of `typeof` can clash even before that.
* In certain circumstances, pointer types and function pointer types may have different `typeof` values even if they're essentially the same.
* `call`: calls a function via a pointer;
the first argument is the pointer to the function;

View File

@ -2,7 +2,9 @@
# Predefined constants
* `byte nullchar` the null terminator for strings in the default encoding, equivalent to `""z[0]`
* `byte nullchar` the null terminator for strings in the default encoding, equivalent to `""z[0]`, can be overriden by the `NULLCHAR` feature
* `byte nullchar_scr` the null terminator for strings in the screen encoding, equivalent to `""scrz[0]`, can be overriden by the `NULLCHAR_SCR` feature
* `null$ nullptr` the invalid pointer value; the value of the `NULLPTR` feature
@ -10,6 +12,10 @@
* `pointer segment.N.start` the value of `segment_N_start` from the platform definition
* `pointer segment.N.codeend` the value of `segment_N_codeend` from the platform definition
* `pointer segment.N.datastart` the value of `segment_N_datastart` from the platform definition
* `pointer segment.N.end` the value of `segment_N_end` from the platform definition
* `pointer segment.N.heapstart` the address of the first byte in the `N` segment that was not automatically allocated
@ -17,3 +23,7 @@
* `word segment.N.length` the number of byte locations between `segment_N_start` and `segment_N_end`, inclusive
* `byte segment.N.bank` the value of `segment_N_bank` from the platform definition
* `byte segment.N.fill` the value of `segment_N_fill` from the platform definition
* `this.function` the alias of the current function (in macros, it resolves to the actual non-macro function that called the macro)

View File

@ -103,6 +103,8 @@ Some libraries may require that some of these be defined.
* `KEYBOARD` 1 if the target has a keyboard, 0 otherwise
* `DISPLACED_MAIN` set this to 1 if the `main` function is in a very unusual location for the target
* `USE_MOUSE_MBM` set this to 1 if you want to enable middle button support for the mouse.
* `JOYSTICKS` the maximum number of joysticks using standard hardware configurations, may be 0
@ -151,11 +153,40 @@ The `if` function returns its second parameter if the first parameter is defined
// prints 500:
#infoeval if(0, 400, 500)
TODO
`not`, `lo`, `hi`, `min`, `max` `+`, `-`, `*`, `|`, `&`, `^`, `||`, `&&`, `<<`, `>>`,`==`, `!=`, `>`, `>=`, `<`, `<=`
The `min` and `max` functions return the smallest or largest parameter respectively. They support any number of arguments:
// prints 400:
#infoeval min(400, 500, 600)
// prints 500:
#infoeval max(400, 500)
The following Millfork operators and functions are also available in the preprocessor:
`not`, `lo`, `hi`, `+`, `-`, `*`, `|`, `&`, `^`, `||`, `&&`, `<<`, `>>`,`==`, `!=`, `>`, `>=`, `<`, `<=`
The following Millfork operators and functions are not available in the preprocessor:
`+'`, `-'`, `*'`, `<<'`, `>>'`, `:`, `>>>>`, `nonet`, all the assignment operators
`$+`, `$-`, `$*`, `$<<`, `$>>`, `:`, `>>>>`, `nonet`, all the assignment operators
### Character literals
Preprocessor supports character literals. By default, they are interpreted in the default encoding,
but you can suffix them with other encodings.
// usually prints 97:
#infoeval 'a'
// prints 97:
#infoeval 'a'ascii
Exceptionally, you can suffix the character literal with `utf32`.
This gives the literal the value of the Unicode codepoint of the character:
// may print 94, 96, 112, 173, 176, 184, 185, 222, 227, 234, 240, something else, or even fail to compile:
#infoeval 'π'
// prints 960:
#infoeval 'π'utf32
Escape sequences are supported, as per encoding. `utf32` pseudoencoding supports the same escape sequences as `utf8`.
### `#template`

52
docs/lang/suffixes.md Normal file
View File

@ -0,0 +1,52 @@
[< back to index](../doc_index.md)
# Magic suffixes
## Byte-related suffixes
These suffixes can be only applied to arithmetic or pointer variables:
* `.lo` the least significant byte of a two-byte variable (word, pointer) (use `lo(_)` for arbitrary expressions)
* `.hi` the most significant byte of a two-byte variable (word, pointer) (use `hi(_)` for arbitrary expressions)
* `.loword` the least significant word of a three- or four-byte variable
* `.hiword` the most significant word of a three- or four-byte variable
* `.b0`, `.b1` etc. the given byte of the multi-byte arithmetic variable, with `.b0` being the least significant byte
## Pointer-related suffixes:
These suffixes can be applied to variables, arrays, functions or pointable expressions (sometimes called _lvalues_):
* `.addr` returns address of the object (type `pointer`) (constant unless on Lunix)
* `.rawaddr` returns the raw address constant of the object (type `pointer`, the same as `.addr` unless on Lunix, guaranteed to be constant)
* `.pointer` returns the typed pointer to the object
This suffix is available only on expressions that have a type of a typed pointer:
* `.raw` a view of the pointer as a raw pointer
## Segment-related suffixes
These suffixes can be applied to variables, arrays, or functions:
* `.segment.bank` (or `.segment` for short) returns the bank number of the segment the object is in
* `.segment.start` returns the start address of the segment the object is in
* `.segment.codeend` returns the last address of code in the segment the object is in
* `.segment.datastart` returns the start address of data in the segment the object is in
* `.segment.heapstart` returns the start address of uninitialized data in the segment the object is in
* `.segment.end` returns the last address of the segment the object is in
* `.segment.fill` returns the byte value used to fill gaps and other unused space in the segment the object is in
See also [the list of predefined constants](./predefined_constants.md).

View File

@ -13,6 +13,26 @@ Allowed line endings are U+000A, U+000D and U+000D/U+000A.
Outside of text strings and comments, the only allowed characters are U+0009 and U+0020U+007E
(so-called printable ASCII).
## Valid identifiers
Identifiers are used for variable names, function names, array names, segment names.
Identifiers have to start with a letter or an underscore, and they can contain letters, underscores, digits and dollar signs.
An identifier cannot end with a dollar sign, nor can it contain two consecutive dollar signs.
Identifiers using dollar signs are reserved for internal use, do not use them without a good reason.
There is no hard limit on the identifier length.
a // valid
1a // invalid
a1 // valid
_1 // valid
a$1 // valid, but discouraged
a$$a // invalid
a$ // invalid
## Comments
Comments start with `//` and last until the end of line.
@ -30,7 +50,7 @@ or a top level of a function (*local* variables).
Syntax:
`[segment(<segment>)] [volatile] [<storage>] <type> <name> [@<address>] [= <initial_value>]`
`[segment(<segment>)] [volatile] [<storage>] <type> <name> [<optimization hints>] [@<address>] [= <initial_value>]`
Examples:
@ -43,12 +63,14 @@ Examples:
* `volatile` means that the variable is volatile.
The optimizer shouldn't remove or reorder accesses to volatile variables.
Volatile variables (unline non-volatile ones) will not be removed or inlined by the optimizer.
Volatile variables (unlike non-volatile ones) will not be removed or inlined by the optimizer.
Volatile variables cannot be declared as `register` or `stack`.
* `<storage>` can be only specified for local variables. It can be either `stack`, `static`, `register` or nothing.
`register` is only a hint for the optimizer.
See [the description of variable storage](../abi/variable-storage.md).
* `<optimization hints>` is a list of [optimization hints](./hints.md), separated by spaces
* `<address>` is a constant expression that defines where in the memory the variable will be located.
If not specified, it will be located according to the usual allocation rules.
@ -87,6 +109,12 @@ For every variable `x` larger than a byte, extra subvariables are defined:
* constituent bytes, from low to high: `x.b0`, `x.b1`, `x.b2`, etc.
* the lowest word: `x.loword` (=`x.b1:x.b0`)
* if `x` is a typed pointer:
* a view of as a raw pointer: `x.raw`
See also [the list of magic suffixes](./suffixes.md).
### Constant declarations

View File

@ -26,6 +26,8 @@ TODO: document the file format.
* `oldpetscii` or `oldpet` old PETSCII (Commodore PET with newer ROMs)
* `geos_de` text encoding used by the German version of GEOS for C64
* `cbmscr` or `petscr` Commodore screencodes
* `cbmscrjp` or `petscrjp` Commodore screencodes as used on Japanese versions of Commodore 64
@ -38,6 +40,8 @@ TODO: document the file format.
* `apple2gs` Apple IIgs charset
* `macroman` Macintosh Western Latin charset
* `bbc` BBC Micro character set
* `sinclair` ZX Spectrum character set
@ -52,6 +56,10 @@ TODO: document the file format.
* `iso_dk`, `iso_fi` aliases for `iso_no` and `iso_se` respectively
* `dmcs` DEC Multinational Character Set
* `lics` Lotus International Character Set
* `iso8859_1`, `iso8859_2`, `iso8859_3`,
`iso8859_4`, `iso8859_5`, `iso8859_7`,
`iso8859_9`, `iso8859_10`, `iso8859_13`,
@ -74,6 +82,8 @@ ISO 8859-14, ISO 8859-15, ISO 8859-16,
* `iso_15`, `latin9`, `latin0` aliases for `iso8859_15`
* `iso16`, `latin10` aliases for `iso8859_16`
* `brascii` BraSCII
* `cp437`, `cp850`, `cp851`, `cp852`, `cp855`, `cp858`, `cp866`
DOS codepages 437, 850, 851, 852, 855, 858, 866
@ -81,7 +91,7 @@ DOS codepages 437, 850, 851, 852, 855, 858, 866
* `kamenicky` Kamenický encoding
* `cp1250`, `cp1251`, `cp1252` Windows codepages 1250, 1251, 1252
* `cp1250`, `cp1251`, `cp1252`, `cp1253`, `cp1254`, `cp1257` Windows codepages 1250, 1251, 1252, 1253, 1254, 1257
* `msx_intl`, `msx_jp`, `msx_ru`, `msx_br` MSX character encoding, International, Japanese, Russian and Brazilian respectively
@ -108,16 +118,24 @@ English, Japanese, Spanish/Italian and French/German respectively
* `galaksija` text encoding used on Galaksija computers
* `trs80m1` text encoding used on TRS-80 Model 1
* `trs80m3` text encoding used on TRS-80 Model 3
* `coco` text encoding used on Tandy Color Computer
* `cocoscr` Tandy Color Computer screencodes
* `z1013` text encodind used on Robotron Z1013
* `ebcdic` EBCDIC codepage 037 (partial coverage)
* `utf8` UTF-8
* `utf16be`, `utf16le` UTF-16BE and UTF-16LE
* `utf32be`, `utf32le` UTF-32BE and UTF-32LE
When programming for Commodore,
use `petscii` for strings you're printing using standard I/O routines
and `petsciiscr` for strings you're copying to screen memory directly.
@ -149,10 +167,12 @@ The exact value of `{nullchar}` is encoding-dependent:
* in the `zx80` encoding it's `{x01}`,
* in the `zx81` encoding it's `{x0b}`,
* in the `petscr` and `petscrjp` encodings it's `{xe0}`,
* in the `apple2e` encoding it's `{x7f}`,
* in the `atasciiscr` encoding it's `{xdb}`,
* in the `pokemon1*` encodings it's `{x50}`,
* in the `cocoscr` encoding it's exceptionally two bytes: `{xd0}`
* in the `utf16be` and `utf16le` encodings it's exceptionally two bytes: `{x00}{x00}`
* in the `utf32be` and `utf32le` encodings it's exceptionally four bytes: `{x00}{x00}{x00}{x00}`
* in other encodings it's `{x00}` (this may be a subject to change in future versions).
##### Available only in some encodings
@ -197,12 +217,16 @@ Encoding | lowercase letters | backslash | currencies | intl | card suits
`petscr` | yes¹ | no | £ | none | yes¹
`petjp` | no | no | ¥ | katakana³ | yes³
`petscrjp` | no | no | ¥ | katakana³ | yes³
`geos_de` | yes | no | | | no
`sinclair`, `bbc` | yes | yes | £ | none | no
`zx80`, `zx81` | no | no | £ | none | no
`apple2` | no | yes | | none | no
`atascii` | yes | yes | | none | yes
`atasciiscr` | yes | yes | | none | yes
`z1013` | yes | yes | | none | yes
`jis` | yes | no | ¥ | both kana | no
`dmcs`,`lics` | yes | yes | ¢£¥ | Western | no
`brascii`,`macroman`| yes | yes | ¢£¥ | Western | no
`msx_intl`,`msx_br` | yes | yes | ¢£¥ | Western | yes
`msx_jp` | yes | no | ¥ | katakana | yes
`msx_ru` | yes | yes | | Russian⁴ | yes
@ -256,6 +280,7 @@ Encoding | new line | braces | backspace | cursor movement | text colour | rever
`origpet` | yes | no | no | yes | no | yes | no
`oldpet` | yes | no | no | yes | no | yes | no
`petscr`, `petscrjp`| no | no | no | no | no | no | no
`geos_de` | no | no | no | no | no | yes | no
`sinclair` | yes | yes | no | yes | yes | yes | yes
`zx80`,`zx81` | yes | no | yes | yes | no | no | no
`ascii`, `iso_*` | yes | yes | yes | no | no | no | no

View File

@ -69,6 +69,14 @@ or forcing zero extension or sign extension:
x = y // does zero extension and assigns value $0080
x = sbyte(y) // does sign extension and assigns value $FF80
You can also explicitly convert expressions of type `bool` to any numeric type.
`false` is converted to 0 and `true` is converted to 1.
byte a,b,c
a = 5
b = byte(a == 4) // b is now equal to 0
c = byte(a == 5) // c is now equal to 1
## Typed pointers
For every type `T`, there is a pointer type defined called `pointer.T`.
@ -126,11 +134,33 @@ Using `call` on 6502 requires at least 4 bytes of zeropage pseudoregister.
The value of the pointer `f.pointer` may not be the same as the value of the function address `f.addr`.
## Interrupt handler pointers
Functions that are interrupt pointers have their own pointer types:
* `pointer.interrupt` for hardware interrupt handlers
* `pointer.kernal_interrupt` for kernal interrupt handlers
`pointer.kernal_interrupt` is automatically convertible to `function.void.to.void`
interrupt void handler1(){}
kernal_interrupt void handler2(){}
pointer.interrupt p1
p1 = handler1.pointer
pointer.kernal_interrupt p2
p2 = handler2.pointer
function.void.to.void p3
p3 = handler2.pointer
## Boolean types
Boolean types can be used as conditions. They have two possible values, `true` and `false`.
* `bool` a 1-byte boolean value. An uninitialized variable of type `bool` may contain an invalid value.
* `bool` a 1-byte boolean value.
An uninitialized variable of type `bool` may contain an invalid value.
The value `false` is stored as 0, `true` as 1.
* several boolean types based on the CPU flags that may be used only as a return type for a function written in assembly:
@ -146,6 +176,10 @@ Boolean types can be used as conditions. They have two possible values, `true` a
2\. LR35902 does not support these types due to the lack of appropriate flags
You can convert from a boolean type to an arithmetic type by simply casting:
byte c = byte(x >= 0x80)
Examples:
bool f() = true
@ -222,11 +256,24 @@ as there are no checks on values when converting bytes to enumeration values and
## Structs
Struct is a compound type containing multiple fields of various types:
Struct is a compound type containing multiple fields of various types.
A struct is represented in memory as a contiguous area of variables or arrays laid out one after another.
struct <name> [align (alignment)] { <field definitions (type and name), separated by commas or newlines>}
Declaration syntax:
A struct is represented in memory as a contiguous area of variables laid out one after another.
struct <name> [align (alignment)] { <field definitions, separated by commas or newlines>}
where a field definition is either:
* `<type> <name>` and defines a scalar field,
* or `array (<type>) <name> [<size>]`, which defines an array field,
where the array contains items of type `<type>`,
and either contains `<size>` elements
if `<size>` is a constant expression between 0 and 127,
or, if `<size>` is a plain enumeration type, the array is indexed by that type,
and the number of elements is equal to the number of variants in that enumeration.
`(<type>)` can be omitted and defaults to `byte`.
Struct can have a maximum size of 255 bytes. Larger structs are not supported.
@ -256,8 +303,8 @@ All arguments to the constructor must be constant.
Structures declared with an alignment are allocated at appropriate memory addresses.
The alignment has to be a power of two.
If the structs are in an array, they are padded with unused bytes.
If the struct is smaller that its alignment, then arrays of it are faster
If the structs with declared alignment are in an array, they are padded with unused bytes.
If the struct is smaller that its alignment, then arrays of it are faster than if it were not aligned
struct a align(4) { byte x,byte y, byte z }
struct b { byte x,byte y, byte z }
@ -269,12 +316,21 @@ If the struct is smaller that its alignment, then arrays of it are faster
sizeof(a) // equals 16
sizeof(b) // equals 12
return a[i].x // requires XXXX cycles on 6502
return b[i].x // requires XXXX cycles on 6502
return a[i].x // requires 22 or 24 cycles on 6502
return b[i].x // requires 18 cycles on 6502
A struct that contains substructs or subunions with non-trivial alignments has its alignment equal
to the least common multiple of the alignments of the substructs and its own declared alignment.
**Warning:** Limitations of array fields:
* Structs containing arrays cannot be allocated on the stack.
* Struct constructors for structs with array fields are not supported.
## Unions
union <name> [align (alignment)] { <field definitions (type and name), separated by commas or newlines>}
union <name> [align (alignment)] { <field definitions, separated by commas or newlines>}
Unions are pretty similar to structs, with the difference that all fields of the union
start at the same point in memory and therefore overlap each other.
@ -290,3 +346,5 @@ start at the same point in memory and therefore overlap each other.
Offset constants are also available, but they're obviously all zero.
Unions currently do not have an equivalent of struct constructors. This may be improved on in the future.
Unions with array fields have the same limitations as structs with array fields.

91
docs/stdlib/apple2.md Normal file
View File

@ -0,0 +1,91 @@
[< back to index](../doc_index.md)
# Apple II-oriented modules
## apple2_prodos module
This module provides basic support for issuing ProDOS calls.
It assumes ProDOS has been loaded normally before your program has started.
The API closely follows the ProDOS machine language interface.
See the
[ProDOS 8 Technical Reference Manual](http://www.easy68k.com/paulrsm/6502/PDOS8TRM.HTM)
for more details, such as the error code values returned.
The following functions are currently implemented:
#### void prodos_read_block(byte unit, pointer data_buffer, word block_number)
Read the specified block from device `unit` into `data_buffer`.
`data_buffer` must be page-aligned.
#### void prodos_write_block(byte unit, pointer data_buffer, word block_number)
Write the specified block from device `unit` into `data_buffer`.
`data_buffer` must be page-aligned.
#### void prodos_close(byte rnum)
Close file referred to by reference `rnum`.
ProDOS will free the associated buffers and flush all changes to disk if necessary.
#### void prodos_flush(byte rnum)
Flush any changes to disk for file referred to by reference `rnum`.
#### void prodos_get_prefix(pointer filename)
Takes a pointer to a 64-byte buffer.
ProDOS will fill this with the current path prefix as a Pascal-style string.
#### void prodos_set_prefix(pointer filename)
Sets or modifies the ProDOS prefix.
Takes a pointer to a Pascal-style string.
#### void prodos_create(pointer filename, byte filetype)
Create a file.
`filename` is a pointer to a Pascal-style string.
`filetype` is one of the standard ProDOS file types.
See the ProDOS manual for more details.
This *must* be called before a file can be opened or written.
ProDOS does not create files implicitly.
#### void prodos_destroy(pointer filename)
Delete a file.
#### void prodos_rename(pointer filename, pointer new_filename)
Rename a file.
#### byte prodos_open (pointer filename, pointer buffer)
Open a file.
`filename` is a pointer to a Pascal-style string containing the path of file to be opened.
Buffer is a 1024 byte I/O buffer used internally by ProDOS.
The buffer must be page-aligned.
This call returns a byte which is the ProDOS file handle.
This handle is used by other calls.
A minimal example:
byte file_handle
array io_buffer [1024] align (256)
file_handle = prodos_open("myfile"p, io_buffer)
prodos_close(file_handle)
Files must exist to be opened.
Use the `prodos_create` call to create a file first if necessary.
#### void prodos_newline(byte rnum, byte mask, byte newline_char)
Set the ProDOS newline character and mask.
See ProDOS manual for details.
#### void prodos_read(byte rnum, pointer data_buffer, word read_count)
Read the number of bytes specified by `read_count` into `data_buffer` from file handle `rnum`.
#### void prodos_write(byte rnum, pointer data_buffer, word write_count)
Write the number of bytes specified by `write_count` from `data_buffer` to file handle `rnum`.

View File

@ -11,7 +11,7 @@ TODO
## c64_basic module
The `c64_basic` module provides access to Kernal routines, so it requires the Basic ROM to be enabled.
The `c64_basic` module provides access to Basic routines, so it requires the Basic ROM to be enabled.
In particular, this means that it will not work on cartridge targets without extra preparations.
TODO

View File

@ -31,11 +31,11 @@ Executes a CBM DOS command on the given drive.
#### void delete_file(byte device, pointer name)
Deletes given file in the given drive. (`S0:`)
Deletes the given file in the given drive. (`S0:`)
#### void rename_file(byte device, pointer old_name, pointer new_name)
Renames given file in the given drive. (`R0:`)
Renames the given file in the given drive. (`R0:`)
#### void copy_file(byte device, pointer old_name, pointer new_name)

View File

@ -85,7 +85,7 @@ Available only on 6502-based platforms.
#### byte atascii_to_atasciiscr(byte)
Converts a byte from ATASCII to a Atari screencode.
Converts a byte from ATASCII to an Atari screencode.
Control characters <$80 are converted to the graphical characters that share the ATASCII code.
Control characters ≥$80 are not supported.
@ -93,7 +93,7 @@ Available only on 6502-based platforms.
#### byte atasciiscr_to_atascii(byte)
Converts a byte from a Atari screencode to ATASCII.
Converts a byte from an Atari screencode to ATASCII.
Characters that share their ATASCII code with control characters are supported,
but they require to be escaped with $1B to be printed.
Reverse characters are interpreted as non-reverse characters.

View File

@ -49,8 +49,11 @@ ZX Spectrum,
NEC PC-88,
MSX,
Apple II,
Commodore 64 with `c64_basic` module (requires KERNAL and BASIC),
Commodore 16 or Plus/4 with `c264_basic` module (requires KERNAL and BASIC).
Robotron Z1013 (always trims trailing spaces),
TRS-80,
VIC-20 (except for `vic20_a000`),
Commodore 64 with `c64_basic` module (requires KERNAL and BASIC; empty input is treated like a single space),
Commodore 16 or Plus/4 with `c264_basic` module (requires KERNAL and BASIC; empty input is treated like a single space).
#### `word readword()`
@ -61,6 +64,9 @@ ZX Spectrum,
NEC PC-88,
MSX,
Apple II,
Robotron Z1013,
TRS-80,
VIC-20 (except for `vic20_a000`),
Commodore 64 with `c64_basic` module (requires KERNAL and BASIC),
Commodore 16 or Plus/4 with `c264_basic` module (requires KERNAL and BASIC).

View File

@ -28,6 +28,8 @@ Atari,
Amstrad CPC,
ZX Spectrum,
NEC PC-88,
Robotron Z1013,
TRS-80,
Tandy Color Computer.
#### `const byte KEY_ENTER`

View File

@ -47,6 +47,6 @@ or `word` if the screen is more that 256 pixels tall.
## null_mouse_default
This module set the default mouse to null mouse.
The null mouse has no button pressed and the cursos is fixed at coordinates (0,0).
The null mouse has no button pressed and the cursor is fixed at coordinates (0,0).
#### `void read_mouse()`

View File

@ -103,19 +103,19 @@ Provides an interface for reading joypads that is compatible with the [`joy` mod
#### `alias input_a = input_btn`
1 if A button pressed, 0 id not pressed.
1 if A button pressed, 0 if not pressed.
#### `byte input_b`
1 if B button pressed, 0 id not pressed.
1 if B button pressed, 0 if not pressed.
#### `byte input_select`
1 if Select button pressed, 0 id not pressed.
1 if Select button pressed, 0 if not pressed.
#### `byte input_start`
1 if Start button pressed, 0 id not pressed.
1 if Start button pressed, 0 if not pressed.
#### `void read_joy1()`

View File

@ -32,6 +32,8 @@ Current implementation:
* On C64, spends two frames reading noise data from the SID chip.
* On Atari computers, reads the POKEY random register.
* On Z80, reads the refresh register.
* On all other targets, sets the seed to 1.

21
docs/stdlib/vic20.md Normal file
View File

@ -0,0 +1,21 @@
[< back to index](../doc_index.md)
# VIC-20-oriented modules
## vic20_kernal module
The `vic20_kernal` module is imported automatically on the VIC-20 target.
It provides access to Kernal routines.
TODO
## vic20_basic module
The `vic20_basic` module provides access to Basic routines.
It is imported automatically on all PRG VIC-20 targets (`vic20`, `vic20_3k`, `vic20_8k`), but not on cartridge targets (like `vic20_a000`).
TODO
## vic20_hardware
TODO

View File

@ -19,7 +19,7 @@ Raw addresses are acquired using the `.addr` suffix.
The numeric values of the pointer and of the raw address may differ.
* Operator precedence works differently.
Bitwise and bitshift operators have the same precedence as arithmetic operators,
Bitwise and bit-shifting operators have the same precedence as arithmetic operators,
and mixing different operators with the same precedence is usually forbidden.
This prevents most ambiguities in bit-twiddling code, but requires care when porting code from or to C.
@ -34,7 +34,9 @@ This prevents most ambiguities in bit-twiddling code, but requires care when por
* Integer literals starting with zero and containing just digits are decimal, not octal.
For octal literals, use the `0o` prefix.
* String literals are not null-terminated by default. Use the `z` suffix for null-terminated strings.
* String literals are not null-terminated by default. Use the `z` suffix for null-terminated strings.
Note: this is the opposite of what KickC does!
Keep this in mind when migrating KickC code to Millfork or the other way around.
* In `if`, `do/while`, `while` and `for` statements, parentheses are not required, but braces are.
The `else` branch also requires braces, unless the only statement in the `else` block is an `if` statement.
@ -70,7 +72,7 @@ Unlike `#define`, such definitions are not visible within the preprocessor.
This issue applies mostly to the `*` and `<<` operators.
* There is no padding in structs.
* There is no padding in structs, except before fields whose type is a struct or a union with a non-trivial alignment.

View File

@ -10,7 +10,7 @@ mostly game developers, who have little use for advanced features of C, but don'
### What was the inspiration?
The main inspirations was Atalan, but also Quetzalcoatl, Batari BASIC and NESHLA.
Sadly, Atalan has been abandoned and the compiler has been left in a non-working state.
Sadly, Atalan has been abandoned, and the compiler has been left in a non-working state.
The goal of Millfork is to succeed where Atalan failed.
### What platforms are supported?

View File

@ -1,8 +1,16 @@
# Examples
The examples showcased here are designed to compile with a compiler built from newest sources.
The examples showcased here are designed to compile with a compiler built from the newest sources.
If you are using a release version of the compiler, consider browsing the older versions of the examples:
* [for version 0.3.28](https://github.com/KarolS/millfork/tree/v0.3.28/examples)
* [for version 0.3.26](https://github.com/KarolS/millfork/tree/v0.3.26/examples)
* [for version 0.3.24](https://github.com/KarolS/millfork/tree/v0.3.24/examples)
* [for version 0.3.22](https://github.com/KarolS/millfork/tree/v0.3.22/examples)
* [for version 0.3.18](https://github.com/KarolS/millfork/tree/v0.3.18/examples)
* [for version 0.3.16](https://github.com/KarolS/millfork/tree/v0.3.16/examples)
@ -15,25 +23,25 @@ If you are using a release version of the compiler, consider browsing the older
## Cross-platform examples
* [Hello world](crossplatform/hello_world.mfk) (C64/C16/PET/VIC-20/Atari/Apple II/BBC Micro/ZX Spectrum/PC-88/Armstrad CPC/MSX) simple text output
* [Hello world](crossplatform/hello_world.mfk) (C64/C16/PET/VIC-20/Atari/Apple II/BBC Micro/ZX Spectrum/PC-88/Armstrad CPC/MSX/Z1013) simple text output
* [Fizzbuzz](crossplatform/fizzbuzz.mfk) (C64/C16/PET/VIC-20/PET/Atari/Apple II/BBC Micro/ZX Spectrum/PC-88/Armstrad CPC/MSX/X16) everyone's favourite programming task
* [Fizzbuzz 2](crossplatform/fizzbuzz2.mfk) (C64/C16/PET/VIC-20/PET/Atari/Apple II/BBC Micro/ZX Spectrum/PC-88/Armstrad CPC/MSX/CoCo) an alternative, more extensible implemententation of fizzbuzz
* [Fizzbuzz 2](crossplatform/fizzbuzz2.mfk) (C64/C16/PET/VIC-20/PET/Atari/Apple II/BBC Micro/ZX Spectrum/PC-88/Armstrad CPC/MSX/CoCo) an alternative, more extensible implementation of fizzbuzz
* [Fizzbuzz JP](crossplatform/fizzbuzz_jp.mfk) (PC-88/Japanese C64) Fizzbuzz, but in Japanese
* [Text encodings](crossplatform/text_encodings.mfk) (C64/ZX Spectrum) examples of text encoding features
* [Echo](crossplatform/echo.mfk) (C64/C16/Apple II/ZX Spectrum/PC-88/MSX) simple text input and output
* [Echo](crossplatform/echo.mfk) (C64/C16/VIC-20/Apple II/ZX Spectrum/PC-88/MSX) simple text input and output
* [Calculator](crossplatform/calculator.mfk) (C64/C16/Apple II/ZX Spectrum/PC-88/MSX) simple numeric input and output
* [Calculator](crossplatform/calculator.mfk) (C64/C16/VIC-20/Apple II/ZX Spectrum/PC-88/MSX/TRS-80) simple numeric input and output
* [Guessing game](crossplatform/guess.mfk) (C64/C16/Apple II/ZX Spectrum/PC-88/MSX) a guess-a-number game
* [Guessing game](crossplatform/guess.mfk) (C64/C16/VIC-20/Apple II/ZX Spectrum/PC-88/MSX/TRS-80/Z1013) a guess-a-number game
* [Fire effect](crossplatform/fire.mfk) (C64/C16/ZX Spectrum) a simple fire effect
* [`readkey` test](crossplatform/readkeytest.mfk) (C64/C16/PET/VIC-20/Atari/Apple II/Armstrad CPC/ZX Spectrum/PC-88) keyboard reading test
* [`readkey` test](crossplatform/readkeytest.mfk) (C64/C16/PET/VIC-20/Atari/Apple II/Armstrad CPC/ZX Spectrum/PC-88/TRS-80/Z1013) keyboard reading test
* [Screen encoding test](crossplatform/screnctest.mfk) (C64/C16) default-to-screen encoding conversion test
@ -41,7 +49,7 @@ If you are using a release version of the compiler, consider browsing the older
* [Life](crossplatform/life.mfk) (C64/C16/Atari/ZX Spectrum) Conway's game of life
* [Reg dump](crossplatform/regdump.mfk) (C64/C16/ZX Spectrum/CoCo) a program that simply prints the initial values of CPU registers
* [Reg dump](crossplatform/regdump.mfk) (C64/C16/ZX Spectrum/CoCo) a program that simply prints the initial values of CPU registers
* [Test suite](tests) (C64/C16/Atari/Apple II/BBC Micro/Armstrad CPC/ZX Spectrum/PC-88/CoCo) the semi-official test-suite for Millfork
@ -53,14 +61,14 @@ If you are using a release version of the compiler, consider browsing the older
* [Softscrolling](c64/softscroll.mfk) soft-scrolling a single line of text
* [Galencia starfield](c64/galencia.mfk) a port of the starfield effect from the game *Galencia*
* [Galencia starfield](c64/galencia.mfk) a port of the starfield effect from the game *Galencia*
* [Space Poker \[external link\]](https://github.com/KarolS/spacepoker) a game made for the 2018 Reset C64 Craptastic 4KB Game Competition
### Other examples
* Multifile ([source code](c64/multifile.mfk), [platform definition](c64/multifile.ini))
how to create a program made of multiple files loaded on demand
how to create a program made of multiple files loaded on demand
* [Panic](c64/panic_test.mfk) how panic works on C64, showing the address of where it happened
@ -78,8 +86,48 @@ how to create a program made of multiple files loaded on demand
## Atari 8-bit examples
### Hardware specific examples
* [System Off example](a8/systemoff_example.mfk) programming with ROM off
* [DLI example](a8/dli_example.mfk) simple display list and display list interrupt example
* [Horizontal scroll example](a8/endless_scroll.mfk) simple horizontal scroll example
* [Vertical scroll example](a8/vertical_scroll.mfk) simple vertical scroll example
* [Horizontal stars example](a8/horizontal_stars.mfk) horizontal stars done on one missile
### Music
* [CMC Player](a8/cmcplayer.mfk) CMC player with sample music
* [MPT Player](a8/mptplayer.mfk) MPT player with sample music
### Benchmarks
* [Grand Theft Antic](a8/grand_theft_antic.mfk) ANTIC impact on CPU depending on the used graphic mode
* [GR.8 Chessboard Benchmark](a8/gr8_chessboard_benchmark.mfk) chessboard drawing benchmark in GR.8
* [FOR Countdown Benchmark](a8/countdown_for_benchmark.mfk) countdown from 1,999,999 to 0 (FOR loop)
* [WHILE Countdown Benchmark](a8/countdown_while_benchmark.mfk) countdown from 1,999,999 to 0 (WHILE loop)
* [Sieve of Eratosthenes (1899) Benchmark](a8/sieve1899.mfk) sieve of Eratosthenes, 1899 primes algorithm
* [Monte Carlo PI approximation Benchmark](a8/montecarlo_pi_benchmark.mfk) measures the efficiency of multiplication
* [Bubble Sort Benchmark](a8/bubble_sort.mfk) sort 255 elements
### Other examples
* [Test OS module](a8/a8_os_test.mfk) quick test for a8_os.mfk module
* [Rainbow example](a8/rainbow.mfk) simple scrolling rasterbars
* [Quatari Landscape](a8/landscape.mfk) part of Quatari 256B intro
## Game Boy examples
* [GB test example](gb/gbtest.mfk) a partial port of the NES example, with a rudimentary experimental text output implementation
@ -93,7 +141,7 @@ how to create a program made of multiple files loaded on demand
* [Encoding test](msx/encoding_test.mfk) text encoding test; displays three lines of text in three different languages,
no more one of which will display correctly depending on the default font of your computer.
# Commander X16 examples
## Commander X16 examples
* [Palette](x16/palette.mfk) displays the default 256-colour palette.

View File

@ -0,0 +1,62 @@
pointer screen @ $84
byte i @ $80, n1 @ $81, n2 @ $82, t @ $83
array(byte) sorttable align(fast) = [for x,255,downto,1 [x]]
asm void pause() {
lda os_RTCLOK.b2
.rt_check:
cmp os_RTCLOK.b2
beq .rt_check
rts
}
// print in HEX
void printScore(byte val) {
array(byte) tmp[2]
byte iter
tmp[0] = val >> 4
tmp[1] = val & %00001111
for iter:tmp {
if tmp[iter] < 10 {
screen[0] = tmp[iter] + $10
} else {
screen[0] = tmp[iter] + $17
}
screen += 1
}
screen[0] = 0
screen += 1
}
void main(){
screen = os_SAVMSC
for i:sorttable {
printScore(sorttable[i])
}
pause()
os_RTCLOK.b2 = 0
for t,253,downto,0{
for i,0,to,253{
n1 = sorttable[i]
n2 = sorttable[i+1]
if n1>n2 {
sorttable[i] = n2
sorttable[i+1] = n1
}
}
}
t = os_RTCLOK.b2
screen = os_SAVMSC
for i:sorttable {
printScore(sorttable[i])
}
// print jiffies
printScore(t)
while true {}
}

23
examples/a8/cmcplayer.mfk Normal file
View File

@ -0,0 +1,23 @@
const word ADDRMUS = $a000
const word ADDRPLA = $b000
asm void comm(byte register(a) a, byte register(x) x, byte register(y) y) @ ADDRPLA+3 extern
asm void takt() @ ADDRPLA+6 extern
void main(){
comm($70,ADDRMUS.lo,ADDRMUS.hi)
comm(0,0,0)
while os_CH == $ff {
if antic_vcount == $10 {
antic_wsync = $e
gtia_colbk = $e
takt()
gtia_colbk = 0
}
}
comm($40,0,0)
}
const array player @ ADDRPLA = file("data/cmc_player.rep", 6)
// Music by Michal Brzezicki (Caruso) - Echo
const array music @ ADDRMUS = file("data/echo.cmc", 6)

View File

@ -0,0 +1,98 @@
byte RTCLOK @ 0
byte iter0B @ 1
word iter0W @ 2
bool run_counter @ 4
byte zpr_0 @ $24, zpr_1 @ $23, zpr_2 @ $22, zpr_3 @ $21, zpr_4 @ $20
byte zpc_0 @ $47, zpc_1 @ $46, zpc_2 @ $45, zpc_3 @ $44, zpc_4 @ $43, zpc_5 @ $42, zpc_6 @ $41
const array(byte) dl align(16) = [
$70,$70,$70,
$42,$20,0,
$41,@word[dl.addr]
]
void system_off(){
asm { sei }
antic_nmien = 0
pia_portb = $fe
os_NMIVEC = vbi.addr
run_counter = false
antic_nmien = $40
}
asm void pause() {
lda RTCLOK
.rt_check:
cmp RTCLOK
beq .rt_check
rts
}
interrupt void vbi(){
RTCLOK += 1
if run_counter{
zpr_0 += 1
if zpr_0 == 10 {
zpr_1 += 1
zpr_0 = 0
}
if zpr_1 == 10 {
zpr_2 += 1
zpr_1 = 0
}
if zpr_2 == 10 {
zpr_3 += 1
zpr_2 = 0
}
if zpr_3 == 10 {
zpr_4 += 1
zpr_3 = 0
}
}
}
void copy_block(pointer src, pointer dsc, word size){
for iter0W,0,to,size-1{
dsc[iter0W] = src[iter0W]
}
}
void set_block(pointer from, word size, byte val){
for iter0W,0,to,size-1{
from[iter0W] = val
}
}
void main(){
copy_block($e080,$4000,80)
system_off()
set_block($20,40,255)
set_block($20,5,0)
set_block($41,7,0)
pause()
antic_chbase = $40
antic_dlist = dl.addr
run_counter = true
for zpc_6,1,downto,0{
for zpc_5,9,downto,0{
for zpc_4,9,downto,0{
for zpc_3,9,downto,0{
for zpc_2,9,downto,0{
for zpc_1,9,downto,0{
for zpc_0,9,downto,0{
}
}
}
}
}
}
}
run_counter = false
while true {}
}

View File

@ -0,0 +1,119 @@
byte RTCLOK @ 0
byte iter0B @ 1
word iter0W @ 2
bool run_counter @ 4
byte zpr_0 @ $24, zpr_1 @ $23, zpr_2 @ $22, zpr_3 @ $21, zpr_4 @ $20
byte zpc_0 @ $47, zpc_1 @ $46, zpc_2 @ $45, zpc_3 @ $44, zpc_4 @ $43, zpc_5 @ $42, zpc_6 @ $41
const array(byte) dl align(16) = [
$70,$70,$70,
$42,$20,0,
$41,@word[dl.addr]
]
void system_off(){
asm { sei }
antic_nmien = 0
pia_portb = $fe
os_NMIVEC = vbi.addr
run_counter = false
antic_nmien = $40
}
asm void pause() {
lda RTCLOK
.rt_check:
cmp RTCLOK
beq .rt_check
rts
}
interrupt void vbi(){
RTCLOK += 1
if run_counter{
zpr_0 += 1
if zpr_0 == 10 {
zpr_1 += 1
zpr_0 = 0
}
if zpr_1 == 10 {
zpr_2 += 1
zpr_1 = 0
}
if zpr_2 == 10 {
zpr_3 += 1
zpr_2 = 0
}
if zpr_3 == 10 {
zpr_4 += 1
zpr_3 = 0
}
}
}
void copy_block(pointer src, pointer dsc, word size){
for iter0W,0,to,size-1{
dsc[iter0W] = src[iter0W]
}
}
void set_block(pointer from, word size, byte val){
for iter0W,0,to,size-1{
from[iter0W] = val
}
}
void main(){
copy_block($e080,$4000,80)
system_off()
set_block($20,40,255)
set_block($20,5,0)
set_block($41,7,0)
zpc_0 = 9
zpc_1 = 9
zpc_2 = 9
zpc_3 = 9
zpc_4 = 9
zpc_5 = 9
zpc_6 = 1
pause()
antic_chbase = $40
antic_dlist = dl.addr
run_counter = true
while(zpc_6 != $ff){
zpc_5 = 9
while(zpc_5 != $ff){
zpc_4 = 9
while(zpc_4 != $ff){
zpc_3 = 9
while(zpc_3 != $ff){
zpc_2 = 9
while(zpc_2 != $ff){
zpc_1 = 9
while(zpc_1 != $ff){
zpc_0 = 9
while(zpc_0 != $ff){
zpc_0 -= 1
}
zpc_1 -= 1
}
zpc_2 -= 1
}
zpc_3 -= 1
}
zpc_4 -= 1
}
zpc_5 -= 1
}
zpc_6 -= 1
}
run_counter = false
while true {}
}

Binary file not shown.

4
examples/a8/data/cmc.nfo Normal file
View File

@ -0,0 +1,4 @@
Chaos Music Composer http://atariki.krap.pl/index.php/
player modified by Marok; version 2.2 rev01-20
Example tune: Michal Brzezicki (Caruso) - Echo

Binary file not shown.

BIN
examples/a8/data/echo.cmc Normal file

Binary file not shown.

4
examples/a8/data/mpt.nfo Normal file
View File

@ -0,0 +1,4 @@
Music ProTracker http://atariki.krap.pl/index.php/Music_Protracker
player version 2.4
Example tune: Adam Bienias (SoTe): Bitter Reality - Partyland 1

Binary file not shown.

View File

@ -0,0 +1,26 @@
const word dlAddr = $3000
const word dliAddr = $3100
const array(byte) dl @ dlAddr = [
BLANK_8,BLANK_8,BLANK_8,
LMS|MODE_2,$00,$40,
MODE_2,MODE_2,MODE_2,MODE_2,
BLANK_8|DLI,
MODE_2,MODE_2,MODE_2,MODE_2,
JVB,@word[dlAddr]
]
volatile word SDLST @ $230
interrupt void dli() @ dliAddr {
gtia_colpf2 = $de
antic_wsync = 1
}
void main() {
SDLST = dl.addr
os_VDSLST = dli.addr
antic_nmien = $c0
while true {}
}

View File

@ -0,0 +1,68 @@
const word dlAddr = $3000
const word lms1Addr = $4000
const word lms2Addr = $4060
const word lms3Addr = $40c0
array(byte) dl @ dlAddr = [
$70,$70,$70,
$52, @word[lms1Addr],
$52, @word[lms2Addr],
$52, @word[lms3Addr],
$41,lo(dlAddr),hi(dlAddr)
]
noinline asm void wait(byte register(a) f) {
clc
adc os_RTCLOK.b2
.rt_check:
cmp os_RTCLOK.b2
bne .rt_check
rts
}
void main() {
word lms1 @ dlAddr + 4
word lms2 @ dlAddr + 7
word lms3 @ dlAddr + 10
byte hscroli @ $80, a, b, c
pointer screeni @ $82
hscroli = $f
screeni = lms1Addr
wait(1)
os_SDLST = dl.addr
while true {
if hscroli == $b {
a = (pokey_random & 15) + 33
b = (pokey_random & 15) + 33
c = (pokey_random & 15) + 33
screeni[0] = a
screeni[$60] = b
screeni[$c0] = c
screeni[$30] = a
screeni[$30 + $60] = b
screeni[$30 + $c0] = c
lms1 += 1
lms2 += 1
lms3 += 1
screeni += 1
if lms1 == lms1Addr + $30 {
lms1 = lms1Addr
lms2 = lms2Addr
lms3 = lms3Addr
screeni = lms1Addr
}
hscroli = $f
}
antic_hscrol = hscroli
hscroli -= 1
wait(1)
}
}

View File

@ -0,0 +1,109 @@
const word lmsAddr1 = $8400
const word lmsAddr2 = $6010
byte i@$e0, j@$e2, k@$e4, count@$e6
pointer screen@$e8
const array(byte) dl align(256) = [
$70,$70,$70,
$4f,@word[lmsAddr2],
$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,
$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,
$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,
$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,
$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,
$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,
$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,
$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,
$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,
$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,
$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,
$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,
$0f,$0f,$0f,$0f,$0f,
$4f,0,lmsAddr2.hi + $10,
$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,
$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,
$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,
$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,
$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,
$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,
$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,
$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,
$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,
$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,
$0f,$0f,$0f,$0f,$0f,$0f,$0f,$0f,
$0f,
$41,@word[dl.addr]
]
const array(byte) dlPrint align(16) = [
$70,$70,$70,
$42,@word[lmsAddr1],
$41,@word[dlPrint.addr]
]
asm void pause() {
LDA os_RTCLOK.b2
.rt_check:
CMP os_RTCLOK.b2
BEQ .rt_check
RTS
}
//print HEX value
void printScore() {
array(byte) tmp[2]
byte iter
screen = lmsAddr1
os_SDLST = dlPrint.addr
tmp[0] = count >> 4
tmp[1] = count & %00001111
for iter:tmp {
if tmp[iter] < 10 {
screen[iter] = tmp[iter] + $10
} else {
screen[iter] = tmp[iter] + $17
}
}
}
void drawBoard() {
screen = lmsAddr2
os_SDLST = dl.addr
for i,7,downto,0 {
for j,23,downto,0 {
for k,3,downto,0 {
screen[0] = 255
screen[1] = 255
screen[2] = 255
screen += 6
}
screen += 16
}
if (i & 1) != 0 {
screen += 3
} else {
screen -= 3
}
}
}
void main() {
count = 0
pause()
os_RTCLOK.b2 = 0
while os_RTCLOK.b2 < 150 {
drawBoard()
count += 1
}
printScore()
while (true){}
}

View File

@ -0,0 +1,85 @@
byte i @ $b0
pointer screen @ $b2
array(word) scores[17] @ $80
asm void openmode(byte register(a) m) @ $ef9c extern
asm void pause() {
lda os_RTCLOK.b2
.rt_check:
cmp os_RTCLOK.b2
beq .rt_check
rts
}
// print in HEX
void printScore(word val) {
array(byte) tmp[4]
byte iter
tmp[0] = val.hi >> 4
tmp[1] = val.hi & %00001111
tmp[2] = val.lo >> 4
tmp[3] = val.lo & %00001111
for iter:tmp {
if tmp[iter] < 10 {
screen[iter] = tmp[iter] + $10
} else {
screen[iter] = tmp[iter] + $17
}
}
if i < 16 {
screen[4] = 0
screen[5] = 'G' atariscr
screen[6] = 'R' atariscr
screen[7] = '.' atariscr
if i < 10 {
screen[8] = i + $10
} else {
screen[8] = i + $17
}
} else {
screen[4] = 0
screen[5] = 'O' atariscr
screen[6] = 'F' atariscr
screen[7] = 'F' atariscr
}
screen += 40
}
void main(){
for i:scores {
scores[i] = 0
}
for i,0,to,15 {
openmode(i)
pause()
os_RTCLOK.b2 = 0
while os_RTCLOK.b2 < 100 {
scores[i] += 1
}
}
os_SDMCTL = 0
i = 16
pause()
os_RTCLOK.b2 = 0
while os_RTCLOK.b2 < 100 {
scores[i] += 1
}
os_SDMCTL = $22
openmode(0)
screen = os_SAVMSC
for i:scores {
printScore(scores[i])
}
while true {}
}

View File

@ -0,0 +1,23 @@
void main(){
array(byte) stars[256] align(fast)
array(byte) speed[256] align(fast)
byte i
os_PCOLR0 = $e
gtia_grafm = $e
for i:stars {
stars[i] = pokey_random
speed[i] = (pokey_random & 3) + 1
}
while true {
if antic_vcount == 0 {
for i:stars {
antic_wsync = 1
gtia_hposm0 = stars[i]
stars[i] += speed[i]
}
}
}
}

42
examples/a8/landscape.mfk Normal file
View File

@ -0,0 +1,42 @@
// idea @ilmenit
// https://demozoo.org/productions/280623
// for 8bit AtariXL, OS Rev 2
alias prev_x = os_OLDCOL.lo
alias cursor_x = os_COLCRS.lo
alias prev_y = os_OLDROW
alias cursor_y = os_ROWCRS
alias color = os_ATACHR
byte i
array(byte) color_height = [
170,150,144,144,122,122,110,110,94,94,86,86,82,80
]
asm void openmode(byte register(a) m) @ $ef9c extern
asm void drawto() @ $f9c2 extern
void main(){
openmode(9)
os_COLOR4 = $b0
for i,0,to,79 {
cursor_x = i
prev_x = i
prev_y = 1
for color,13,downto,0 {
cursor_y = color_height[color]
if pokey_random < $80 {
color_height[color] -= 1
}
if pokey_random < $80 {
color_height[color] += 1
}
drawto()
}
}
while true {}
}

View File

@ -0,0 +1,64 @@
const word probe = 9999
const word radius = 127 * 127
pointer screen @ $80
asm void pause() {
lda os_RTCLOK.b2
.rt_check:
cmp os_RTCLOK.b2
beq .rt_check
rts
}
// print in HEX
void printScore(word val) {
array(byte) tmp[4]
byte iter
tmp[0] = val.hi >> 4
tmp[1] = val.hi & %00001111
tmp[2] = val.lo >> 4
tmp[3] = val.lo & %00001111
for iter:tmp {
if tmp[iter] < 10 {
screen[iter] = tmp[iter] + $10
} else {
screen[iter] = tmp[iter] + $17
}
}
screen += 40
}
void main() {
word i@$e0, bingo@$e2
word x@$e4, y@$e6, p@$e8, t@$ea
byte n@$82
screen = os_SAVMSC
x = 0
y = 0
bingo = 0
pause()
os_RTCLOK = 0
for i,0,to,probe {
n = pokey_random & 127
x = n * word(n)
n = pokey_random & 127
y = n * word(n)
if ((x + y) <= radius) {
bingo += 1
}
}
p = 4 * bingo
t = os_RTCLOK.b2 + (os_RTCLOK.b1 * 256)
printScore(t)
printScore(p)
while true {}
}

25
examples/a8/mptplayer.mfk Normal file
View File

@ -0,0 +1,25 @@
const word ADDRMUS = $a000
const word ADDRPLA = $b000
byte stop @ ADDRPLA + $62d
asm void comm(byte register(a) a, byte register(x) x, byte register(y) y) @ ADDRPLA extern
asm void takt() @ ADDRPLA+3 extern
void main(){
comm(0,ADDRMUS.hi,ADDRMUS.lo)
comm(4,0,0)
while os_CH == $ff {
if antic_vcount == $10 {
antic_wsync = $e
gtia_colbk = $e
takt()
gtia_colbk = 0
}
}
stop = 0
}
const array player @ ADDRPLA = file("data/mpt_player.obj", 6)
// Music by Adam Bienias (SoTe): Bitter Reality - Partyland 1
const array music @ ADDRMUS = file("data/bitter_reality_4.mpt", 6)

68
examples/a8/sieve1899.mfk Normal file
View File

@ -0,0 +1,68 @@
const word size = 8192
word RTCLOK @ $13, SAVMSC @ $58
word i@$e0, prime@$e2, k@$e4, count@$e6
pointer screen@$e8
asm void pause() {
lda $14
.rt_check:
cmp $14
beq .rt_check
rts
}
// print in HEX
void printScore() {
array(byte) tmp[4]
byte iter
screen = SAVMSC
tmp[0] = RTCLOK.lo >> 4
tmp[1] = RTCLOK.lo & %00001111
tmp[2] = RTCLOK.hi >> 4
tmp[3] = RTCLOK.hi & %00001111
for iter:tmp {
if tmp[iter] < 10 {
screen[iter] = tmp[iter] + $10
} else {
screen[iter] = tmp[iter] + $17
}
}
}
void main() {
array(bool) flags[size] align(1024)
byte iter
pause()
RTCLOK = 0
for iter,9,downto,0 {
count = 0
for i:flags {
flags[i] = true
}
for i:flags {
if flags[i] {
prime = (i * 2) + 3
k = i + prime
while k <= size {
flags[k] = false
k += prime
}
count += 1
}
}
}
printScore()
while true {}
}

View File

@ -0,0 +1,137 @@
// ================================================
//
// antic_nmien = $40
//
// %01000000 $40 VBI
// %10000000 $80 DLI
// %11000000 $c0 VBI + DLI
//
// ================================================
//
// pia_portb = $fe
//
// PORTB_BASIC_OFF + PORTB_SELFTEST_OFF + %01111100
//
// PORTB_SELFTEST_OFF = %10000000; portb bit value to turn Self-Test off
// PORTB_BASIC_OFF = %00000010; portb bit value to turn Basic off
// PORTB_SYSTEM_ON = %00000001; portb bit value to turn System on
//
// ================================================
//
// Now the routine that lets you get to
// the RAM that is under the OS.
// There are actually 2 memory areas
// present:
// 4K at $C000 to $CFFF, 49152 to 53247
// 10K at $D800 to $FFFF, 55296 to 65535
//
// The last 6 bytes of the 10K area are not
// usable, since that is where the interrupt
// routines are located. Therefore do not
// use any RAM above $FFF9 (65529) or you
// will crash the system.
//
// ================================================
byte nmien = $c0
byte rti @ $15 // default routine for VBI & DLI
word vbivec @ $10 // vector for VBI
word vdslst @ $16 // vector for DLI
// simple display list; LMS = $e000
const array(byte) dl align(32) = [
$70,$70,$70,
$42,$00,$e0,2,2,$f0,2,2,2,$f0,2,2,2,
$41,@word[dl.addr]
]
// init procedure
void system_off(){
asm { sei } // turn off IRQ
antic_nmien = 0 // turn off NMI
pia_portb = $fe // turn off ROM
rti = $40 // set RTI opcode
vbivec = rti.addr // set address for VBI routine
vdslst = rti.addr // set address for DLI routine
os_NMIVEC = nmi.addr // set address for custom NMI handler
antic_nmien = nmien
}
// custom NMI handler
asm void nmi(){
bit antic_nmist // test nmist
bpl .vblclock // if 7-bit not set handle VBI
jmp (vdslst) // indirect jump to DLI routine
.vblclock: // RTCLOK maintainer
inc os_RTCLOK.b2
bne .tickend
inc os_RTCLOK.b1
bne .tickend
inc os_RTCLOK.b0
.tickend:
jmp (vbivec) // indirect jump to VBI routine
}
// example dli
interrupt asm void dli_first(){
pha
lda #$2a
sta gtia_colpf2
sta antic_wsync
lda #<dli_second.addr
sta vdslst.lo
lda #>dli_second.addr
sta vdslst.hi
pla
rti
}
// example dli
interrupt void dli_second(){
gtia_colpf2 = $de
antic_wsync = $de
vdslst = dli_first.addr
}
// wait for VBLANK
asm void pause() {
lda os_RTCLOK.b2
.rt_check:
cmp os_RTCLOK.b2
beq .rt_check
rts
}
// wait 0-255 frames
noinline asm void wait(byte register(a) f) {
clc
adc os_RTCLOK.b2
.rt_check:
cmp os_RTCLOK.b2
bne .rt_check
rts
}
// example vbi
interrupt void vbi(){
gtia_colpf2 = os_RTCLOK.b2
}
// main procedure
void main(){
system_off() // turn off OS
wait(100) // waint 2 sec on PAL for fun
antic_dlist = dl.addr // set custom display list
wait(100) // waint 2 sec on PAL for the lulz
vbivec = vbi.addr // set custom VBI
wait(100) // waint 2 sec on PAL because we can
vdslst = dli_first.addr // set custom DLI
while(true){
wait(100)
nmien ^= %10000000 // toggle DLI
antic_nmien = nmien
}
}

View File

@ -0,0 +1,37 @@
const array text align(64) = "...MILLFORK RULEZ..." atariscr
const array(byte) dl align(16) = [
$70,$70,$70,$70,
$67,@word[text.addr],
$41,@word[dl.addr]
]
noinline asm void wait(byte register(a) f) {
clc
adc os_RTCLOK.b2
.rt_check:
cmp os_RTCLOK.b2
bne .rt_check
rts
}
void main(){
byte i0B @ $80
i0B = $f
os_SDLST = dl.addr
while true {
while (i0B != 0){
i0B -= 1
antic_vscrol = i0B
wait(3)
}
wait(50)
while (i0B < $f){
i0B += 1
antic_vscrol = i0B
wait(2)
}
}
}

View File

@ -0,0 +1,37 @@
// simple demonstration of ProDOS library routines that will write
// the Disk II ROM (assuming it is in slot 6) to the file DISKII.ROM
import stdio
import apple2_prodos
void main() {
// ProDOS requires a 1K aligned page for an open file as an IO buffer
array iobuf [1024] align(256)
// you have to explicitly create a file if it doesn't exist yet
// this can fail (so you should check prodos_error
// 06 is general binary type
prodos_create("DISKII.ROM"p, $06)
if prodos_error != 0 {
// prodos error call will be returned in prodos_error so you know
// what went wrong. 0 = no error
putstrz("{n}couldn't create file"z)
panic()
}
// ProDOS file handle
byte fp
fp = prodos_open("DISKII.ROM"p, iobuf)
// should check here again for error, and after all calls
// write the disk controller ROM to the file
prodos_write(fp, $c600, 256)
// closing frees the handle and io buffer
prodos_close(fp)
putstrz("{n}DONE"z)
while true { }
}

View File

@ -4,7 +4,7 @@ import stdio
import c64_basic
#elseif CBM_264
import c264_basic
#elseif ZX_SPECTRUM || NEC_PC_88
#elseif ZX_SPECTRUM || NEC_PC_88 || TRS80 || CBM_VIC
// no imports needed
#else
#error Unsupported platform

View File

@ -3,7 +3,7 @@
import c64_basic
#elseif CBM_264
import c264_basic
#elseif ZX_SPECTRUM || NEC_PC_88
#elseif CBM_VIC || ZX_SPECTRUM || NEC_PC_88
// no imports needed
#else
#error Unsupported platform

View File

@ -10,7 +10,7 @@ import c64_basic
import c264_basic
#endif
#define READKEY = CBM_64 | CBM_264 | ZX_SPECTRUM | NEC_PC_88 | APPLE_2
#define READKEY = CBM_64 | CBM_264 | CBM_VIC | ZX_SPECTRUM | NEC_PC_88 | APPLE_2
#if READKEY
import keyboard

View File

@ -4,8 +4,47 @@
#warn a8_antic module should be used only on Atari computer-compatible targets
#endif
// ANTIC Display List Instruction Set
// THE DISPLAY LIST CANNOT CROSS A 1K BYTE MEMORY BOUNDARY UNLESS A JUMP INSTRUCTION IS USED!
const byte LMS = $40 // Load memory scan 12-bit counter, $0-$fff boundary.
const byte DLI = $80 // Display list interrupt - Interrupt CPU at beginning of last scan line.
const byte HSCROL = $10 // Enable horizontal scrolling.
const byte VSCROL = $20 // Enable vertical scrolling.
const byte JMP = 1 // Jump command - followed by two bytes indicating the new instruction pointer for the display list.
const byte JVB = $41 // Jump and wait for Vertical Blank - suspends the display list until vertical blank and then jumps.
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+ BASIC + colors + resolution + display mode + scan lines per row + screen memory + bytes per line + bits per pixel +
const byte MODE_2 = 2 //+ 0 + 2 + 40x24 + text + 8 + 960 B + 40 + 8 +
const byte MODE_3 = 3 //+ - + 2 + 40x24 + text + 10 + 760 B + 40 + 8 +
const byte MODE_4 = 4 //+ 12 + 5 + 40x24 + text + 8 + 960 B + 40 + 8 +
const byte MODE_5 = 5 //+ 13 + 5 + 40x12 + text + 16 + 480 B + 40 + 8 +
const byte MODE_6 = 6 //+ 1 + 5 + 20x24 + text + 8 + 480 B + 20 + 8 +
const byte MODE_7 = 7 //+ 2 + 5 + 20x12 + text + 16 + 240 B + 20 + 8 +
const byte MODE_8 = 8 //+ 3 + 4 + 40x24 + graphics + 8 + 240 B + 10 + 2 +
const byte MODE_9 = 9 //+ 4 + 2 + 80x48 + graphics + 4 + 480 B + 10 + 1 +
const byte MODE_A = $a //+ 5 + 4 + 80x48 + graphics + 4 + 960 B + 20 + 2 +
const byte MODE_B = $b //+ 6 + 2 + 160x96 + graphics + 2 + 1920 B + 20 + 1 +
const byte MODE_C = $c //+ 14 + 2 + 160x192 + graphics + 1 + 3840 B + 20 + 1 +
const byte MODE_D = $d //+ 7 + 4 + 160x96 + graphics + 2 + 3840 B + 40 + 2 +
const byte MODE_E = $e //+ 15 + 4 + 160x192 + graphics + 1 + 7680 B + 40 + 2 +
const byte MODE_F = $f //+8,9,10,11+ 2 + 320x192 + graphics + 1 + 7680 B + 40 + 1 +
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
const byte BLANK_1 = 0
const byte BLANK_2 = $10
const byte BLANK_3 = $20
const byte BLANK_4 = $30
const byte BLANK_5 = $40
const byte BLANK_6 = $50
const byte BLANK_7 = $60
const byte BLANK_8 = $70
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
volatile byte antic_dmactl @$D400 // direct memory access control
volatile byte antic_chactl @$D401 // character mode control
volatile word antic_dlist @$D402 // display list pointer
volatile byte antic_dlistl @$D402 // display list pointer low-byte
volatile byte antic_dlisth @$D403 // display list pointer high-byte
volatile byte antic_hscrol @$D404 // horizontal scroll enable
@ -19,6 +58,5 @@ volatile byte antic_vcount @$D40B // vertical line counter
volatile byte antic_penh @$D40C // light pen horizontal position
volatile byte antic_penv @$D40D // light pen vertical position
volatile byte antic_nmien @$D40E // non-maskable interrupt enable
// nmi reset status
volatile byte antic_nmires @$D40F
volatile byte antic_nmist @$D40F // (R) NMI status; holds cause for the NMI interrupt, corresponding to the same bits in NMIEN
volatile byte antic_nmires @$D40F // (W) Reset for NMIST; clears the interrupt request register

View File

@ -20,8 +20,8 @@
const byte os_MAXDEV = 33 // offset to last possible entry of HATABS
const byte os_IOCBSZ = 16 // length of IOCB
const byte os_SEIOCB = 0*IOCBSZ // ##rev2## screen editor IOCB index
const byte os_MAXIOC = 8*IOCBSZ // first invalid IOCB index
const byte os_SEIOCB = 0 * os_IOCBSZ // ##rev2## screen editor IOCB index
const byte os_MAXIOC = 8 * os_IOCBSZ // first invalid IOCB index
const byte os_DSCTSZ = 128 // ##rev2## disk sector size
@ -424,6 +424,7 @@ volatile byte os_CDTMF4 @$022C // COUNT DOWN TIMER 4 FLAG
volatile byte os_INTEMP @$022D // IAN'S TEMP
volatile byte os_CDTMF5 @$022E // COUNT DOWN TIMER FLAG 5
volatile byte os_SDMCTL @$022F // SAVE DMACTL REGISTER
volatile word os_SDLST @$0230 // SAVE DISPLAY LIST
volatile byte os_SDLSTL @$0230 // SAVE DISPLAY LIST LOW BYTE
volatile byte os_SDLSTH @$0231 // SAVE DISPLAY LIST HI BYTE
volatile byte os_SSKCTL @$0232 // SKCTL REGISTER RAM
@ -678,50 +679,50 @@ volatile word os_CARTAD @$BFFE // ##rev2## 2-byte cartridge start vector
// Character sets
const byte os_ICSORG = $CC00 // ##rev2## international character set origin
const byte os_DCSORG = $E000 // ##rev2## domestic character set origin
const array os_ICSORG[$400] @$CC00 // ##rev2## international character set origin
const array os_DCSORG[$400] @$E000 // ##rev2## domestic character set origin
// Device Handler Vector Table Address Equates
const byte os_EDITRV = $E400 // editor handler vector table
const byte os_SCRENV = $E410 // screen handler vector table
const byte os_KEYBDV = $E420 // keyboard handler vector table
const byte os_PRINTV = $E430 // printer handler vector table
const byte os_CASETV = $E440 // cassette handler vector table
const array(function.void.to.void) os_EDITRV [8] @$E400 // editor handler vector table
const array(function.void.to.void) os_SCRENV [8] @$E410 // screen handler vector table
const array(function.void.to.void) os_KEYBDV [8] @$E420 // keyboard handler vector table
const array(function.void.to.void) os_PRINTV [8] @$E430 // printer handler vector table
const array(function.void.to.void) os_CASETV [8] @$E440 // cassette handler vector table
// Jump Vector Address Equates
const byte os_DISKIV = $E450 // vector to initialize DIO
const byte os_DSKINV = $E453 // vector to DIO
const byte os_CIOV = $E456 // vector to CIO
const byte os_SIOV = $E459 // vector to SIO
asm void os_DISKIV() @$E450 extern // vector to initialize DIO
asm void os_DSKINV() @$E453 extern // vector to DIO
asm void os_CIOV() @$E456 extern // vector to CIO
asm void os_SIOV() @$E459 extern // vector to SIO
const byte os_SETVBV = $E45C // vector to set VBLANK parameters
const byte os_SYSVBV = $E45F // vector to process immediate VBLANK
const byte os_XITVBV = $E462 // vector to process deferred VBLANK
asm void os_SETVBV() @$E45C extern // vector to set VBLANK parameters
asm void os_SYSVBV() @$E45F extern // vector to process immediate VBLANK
asm void os_XITVBV() @$E462 extern // vector to process deferred VBLANK
const byte os_SIOINV = $E465 // vector to initialize SIO
const byte os_SENDEV = $E468 // vector to enable SEND
const byte os_INTINV = $E46B // vector to initialize interrupt handler
const byte os_CIOINV = $E46E // vector to initialize CIO
asm void os_SIOINV() @$E465 extern // vector to initialize SIO
asm void os_SENDEV() @$E468 extern // vector to enable SEND
asm void os_INTINV() @$E46B extern // vector to initialize interrupt handler
asm void os_CIOINV() @$E46E extern // vector to initialize CIO
const byte os_BLKBDV = $E471 // vector to power-up display
const byte os_WARMSV = $E474 // vector to warmstart
const byte os_COLDSV = $E477 // vector to coldstart
asm void os_BLKBDV() @$E471 extern // vector to power-up display
asm void os_WARMSV() @$E474 extern // vector to warmstart
asm void os_COLDSV() @$E477 extern // vector to coldstart
const byte os_RBLOKV = $E47A // vector to read cassette block
const byte os_CSOPIV = $E47D // vector to open cassette for input
asm void os_RBLOKV() @$E47A extern // vector to read cassette block
asm void os_CSOPIV() @$E47D extern // vector to open cassette for input
const byte os_VCTABL = $E480 // RAM vector initial value table
const byte os_PUPDIV = $E480 // ##rev2## vector to power-up display
const byte os_SLFTSV = $E483 // ##rev2## vector to self-test
const byte os_PHENTV = $E486 // ##rev2## vector to enter peripheral handler
const byte os_PHUNLV = $E489 // ##rev2## vector to unlink peripheral handler
const byte os_PHINIV = $E48C // ##rev2## vector to initialize peripheral handler
const byte os_GPDVV = $E48F // ##rev2## generic parallel device handler vector
asm void os_VCTABL() @$E480 extern // RAM vector initial value table
asm void os_PUPDIV() @$E480 extern // ##rev2## vector to power-up display
asm void os_SLFTSV() @$E483 extern // ##rev2## vector to self-test
asm void os_PHENTV() @$E486 extern // ##rev2## vector to enter peripheral handler
asm void os_PHUNLV() @$E489 extern // ##rev2## vector to unlink peripheral handler
asm void os_PHINIV() @$E48C extern // ##rev2## vector to initialize peripheral handler
asm void os_GPDVV() @$E48F extern // ##rev2## generic parallel device handler vector
// 6502
const byte os_NMIVEC = $FFFA
const byte os_RESVEC = $FFFC
const byte os_IRQVEC = $FFFE
volatile word os_NMIVEC @$FFFA
volatile word os_RESVEC @$FFFC
volatile word os_IRQVEC @$FFFE

View File

@ -11,7 +11,7 @@ asm void bell() @$FBE4 extern
asm void putchar(byte register(a) char) @$FDED extern
asm void new_line() @$FC62 extern
asm pointer readline() {
jsr $FD6A
jsr $FD6F
ldx #$ff
__readline_loop:
inx

273
include/apple2_prodos.mfk Normal file
View File

@ -0,0 +1,273 @@
const byte PRODOS_ALLOC_INTERRUPT = $40
const byte PRODOS_DEALLOC_INTERRUPT = $41
const byte PRODOS_READ_BLOCK = $80
const byte PRODOS_WRITE_BLOCK = $81
const byte PRODOS_GET_TIME = $82
const byte PRODOS_CREATE = $c0
const byte PRODOS_DESTROY = $c1
const byte PRODOS_RENAME = $c2
const byte PRODOS_SET_FILE_INFO = $c3
const byte PRODOS_GET_FILE_INFO = $c4
const byte PRODOS_ON_LINE = $c5
const byte PRODOS_SET_PREFIX = $c6
const byte PRODOS_GET_PREFIX = $c7
const byte PRODOS_OPEN = $c8
const byte PRODOS_NEWLINE = $c9
const byte PRODOS_READ = $ca
const byte PRODOS_WRITE = $cb
const byte PRODOS_CLOSE = $cc
const byte PRODOS_FLUSH = $cd
const byte PRODOS_SET_MARK = $ce
const byte PRODOS_GET_MARK = $cf
const byte PRODOS_SET_EOF = $d0
const byte PRODOS_GET_EOF = $d1
const byte PRODOS_SET_BUF = $d2
const byte PRODOS_GET_BUF = $d3
// ProDOS MLI parameter lists
struct read_block_plist {
byte param_count
byte unit_num
pointer data_buffer
word block_num
}
struct write_block_plist {
byte param_count
byte unit_num
pointer data_buffer
word block_num
}
struct close_plist {
byte param_count
byte ref_num
}
struct flush_plist {
byte param_count
byte ref_num
}
struct create_plist {
byte param_count
pointer pathname
byte access
byte file_type
word aux_type
byte storage_type
word create_time
word create_date
}
struct destroy_plist {
byte param_count
pointer pathname
}
struct open_plist {
byte param_count
pointer pathname
pointer io_buffer
byte ref_num
}
struct newline_plist {
byte param_count
byte ref_num
byte enable_mask
byte newline_char
}
struct read_plist {
byte param_count
byte ref_num
pointer data_buffer
word request_count
word trans_count
}
struct rename_plist {
byte param_count
pointer pathname
pointer new_pathname
}
struct write_plist {
byte param_count
byte ref_num
pointer data_buffer
word request_count
word trans_count
}
struct get_prefix_plist {
byte param_count
pointer data_buffer
}
struct set_prefix_plist {
byte param_count
pointer data_buffer
}
// we'll just reuse the same area for all plists
union prodos_plist {
read_block_plist read_block
write_block_plist write_block
create_plist create
destroy_plist destroy
rename_plist rename
open_plist open
newline_plist newline
read_plist read
write_plist write
close_plist close
flush_plist flush
get_prefix_plist get_prefix
set_prefix_plist set_prefix
}
prodos_plist plist
byte prodos_error
// Millfork doesn't support self-modification in the assembler yet, so this
// code is placed in the following array:
//
// jsr $bf00
// $00
// plist.addr
// rts
//
// We modify mli_trampoline[3] ($00 on the second line) to set the specific
// ProDOS call before we jsr to $bf00
//
// TODO: can we just jmp to bf00 and save the extra rts ?
array mli_trampoline = [ $20, 0, $bf, 0, plist.addr.lo, plist.addr.hi, $60 ]
asm void prodos_mli_call(byte register(a) pdcall) {
sta mli_trampoline+3
jsr mli_trampoline
sta prodos_error
rts
}
void prodos_read_block(byte unum, pointer dbuf, word bnum) {
plist.read_block.param_count = 3
plist.read_block.unit_num = unum
plist.read_block.data_buffer = dbuf
plist.read_block.block_num = bnum
prodos_mli_call(PRODOS_READ_BLOCK)
}
void prodos_write_block(byte unum, pointer dbuf, word bnum) {
plist.write_block.param_count = 3
plist.write_block.unit_num = unum
plist.write_block.data_buffer = dbuf
plist.write_block.block_num = bnum
prodos_mli_call(PRODOS_WRITE_BLOCK)
}
void prodos_close(byte rnum) {
plist.close.param_count = 1
plist.close.ref_num = rnum
prodos_mli_call(PRODOS_CLOSE)
}
void prodos_flush(byte fp) {
plist.flush.param_count = 1
plist.flush.ref_num = fp
prodos_mli_call(PRODOS_FLUSH)
}
void prodos_get_prefix(pointer fnbuf) {
plist.get_prefix.param_count = 1
plist.get_prefix.data_buffer = fnbuf
prodos_mli_call(PRODOS_GET_PREFIX)
}
void prodos_set_prefix(pointer fnbuf) {
plist.set_prefix.param_count = 1
plist.set_prefix.data_buffer = fnbuf
prodos_mli_call(PRODOS_SET_PREFIX)
}
void prodos_create(pointer fn, byte ftype) {
plist.create.param_count = 7
plist.create.pathname = fn
plist.create.access = $c3
plist.create.file_type = ftype
plist.create.aux_type = $0
plist.create.storage_type = 1
plist.create.create_time = 0
plist.create.create_date = 0
prodos_mli_call(PRODOS_CREATE)
}
void prodos_destroy (pointer fn) {
plist.destroy.param_count = 0
plist.destroy.pathname = fn
prodos_mli_call(PRODOS_DESTROY)
}
void prodos_rename(pointer fn, pointer newfn) {
plist.rename.param_count = 2
plist.rename.pathname = fn
plist.rename.new_pathname = newfn
prodos_mli_call(PRODOS_RENAME)
}
// returns file handle if no error
byte prodos_open (pointer fn, pointer b) {
plist.open.param_count = 3
plist.open.pathname = fn
plist.open.io_buffer = b
prodos_mli_call(PRODOS_OPEN)
return plist.open.ref_num
}
void prodos_newline(byte fp, byte mask, byte nlchar) {
plist.newline.param_count = 3
plist.newline.ref_num = fp
plist.newline.enable_mask = mask
plist.newline.newline_char = nlchar
prodos_mli_call(PRODOS_NEWLINE)
}
void prodos_read(byte rnum, pointer dbuf, word rcnt) {
plist.read.param_count = 4
plist.read.ref_num = rnum
plist.read.data_buffer = dbuf
plist.read.request_count = rcnt
prodos_mli_call(PRODOS_READ)
}
void prodos_write(byte rnum, pointer dbuf, word rcnt) {
plist.write.param_count = 4
plist.write.ref_num = rnum
plist.write.data_buffer = dbuf
plist.write.request_count = rcnt
prodos_mli_call(PRODOS_WRITE)
}

View File

@ -6,7 +6,7 @@
// CHROUT. Write byte to default output. (If not screen, must call OPEN and CHKOUT beforehands.)
// Input: A = Byte to write.
asm void chrout(byte register(a) char) @$FFD2 extern
asm void chrout(byte register(a) char) !preserves_a !preserves_x !preserves_y @$FFD2 extern
asm void putchar(byte register(a) char) {
JSR chrout

View File

@ -5,7 +5,7 @@
// CHROUT. Write byte to default output. (If not screen, must call OPEN and CHKOUT beforehands.)
// Input: A = Byte to write.
asm void chrout(byte register(a) char) @$FFD2 extern
asm void chrout(byte register(a) char) !preserves_a !preserves_x !preserves_y @$FFD2 extern
asm void putchar(byte register(a) char) {
JSR chrout

View File

@ -2,7 +2,7 @@ import err
inline asm void switch_hirom(byte register(a) bank) {
? and #$3F
! sta $DE01
! sta $DE00
? rts
}

View File

@ -2,7 +2,7 @@
// CHROUT. Write byte to default output. (If not screen, must call OPEN and CHKOUT beforehands.)
// Input: A = Byte to write.
asm void chrout(byte register(a) char) @$FFD2 extern
asm void chrout(byte register(a) char) !preserves_a !preserves_x !preserves_y @$FFD2 extern
// CHRIN. Read byte from default input (for keyboard, read a line from the screen). (If not keyboard, must call OPEN and CHKIN beforehands.)
// Output: A = Byte read.

View File

@ -10,7 +10,7 @@ word sid_v1_freq @$D400
word sid_v1_pulse @$D402
byte sid_v1_cr @$D404
byte sid_v1_ad @$D405
byte sid_v1_sr @$D409
byte sid_v1_sr @$D406
word sid_v2_freq @$D407
word sid_v2_pulse @$D409

View File

@ -0,0 +1,31 @@
#template $ADDR$
#if not(CBM)
#warn cbm/basic_loader module should be only used on Commodore targets
#endif
const array _basic_loader @ $ADDR$ = [
#if DISPLACED_MAIN
@word_le [
$ADDR$ + 0xB
],
#else
@word_le [
$ADDR$ + if(main.addr >= 10000, 1/0, 0xA) // use -D DISPLACED_MAIN=1 if you get an error here
],
#endif
10,
0,
$9e,
#if DISPLACED_MAIN
$30 + (main.addr/10000)%%10,
#endif
$30 + (main.addr/1000)%%10,
$30 + (main.addr/100)%%10,
$30 + (main.addr/10)%%10,
$30 + (main.addr/1)%%10,
0,
0,
0
]

View File

@ -1,8 +1,2 @@
noinline asm byte readkey() {
clr $6f
jsr [$A000]
beq readkey
tfr a,b
rts
}
asm byte readkey() @ $49 extern

View File

@ -7,7 +7,7 @@ C0-DF=@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
a-z=C1
{q}=02
{apos}=07
{q}=A2
{apos}=A7
{nbsp}=40
{n}=8D

View File

@ -13,3 +13,4 @@ EOT=00
{apos}=27
{lbrace}=7b
{rbrace}=7d
{pound}=5c

View File

@ -7,8 +7,8 @@ EOT=7F
20-3f=@abcdefghijklmnopqrstuvwxyz[\]^_
60-7e=πABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~
{q}=22
{apos}=27
{q}=02
{apos}=07
{lbrace}=7b
{rbrace}=7d
{pi}=60

View File

@ -9,4 +9,4 @@ E0-FE=`abcdefghijklmnopqrstuvwxyz{\}~
{q}=A2
{apos}=A7
{lbrace}=FB
{rbrace}=FC
{rbrace}=FD

View File

@ -0,0 +1,29 @@
NAME=BraSCII
EOT=00
20=U+0020
21-3f=!"#$%&'()*+,-./0123456789:;<=>?
40-5f=@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
60-7e=`abcdefghijklmnopqrstuvwxyz{|}~
a1-ac=¡¢£¤¥¦§¨©ª«¬
ae-af=®¯
b0-bf=°±²³´µ¶·¸¹º»¼½¾¿
c0-cf=ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ
d0-df=ÐÑÒÓÔÕÖŒØÙÚÛÜÝÞß
e0-ef=àáâãäåæçèéêëìíîï
f0-ff=ðñòóôõöœøùúûüýþÿ
{b}=08
{t}=09
{n}=0d0a
{q}=22
{apos}=27
{lbrace}=7b
{rbrace}=7d
{cent}=a2
{pound}=a3
{yen}=a5
{copy}=a9
{ss}=df
{nbsp}=A0
{shy}=AD

View File

@ -26,6 +26,7 @@ f0-ff=đńňóôőö÷řůúűüýţ˙
{apos}=27
{lbrace}=7b
{rbrace}=7d
{euro}=80
{copy}=a9
{ss}=df
{nbsp}=A0

View File

@ -23,6 +23,7 @@ f0-ff=рстуфхцчшщъыьэюя
{apos}=27
{lbrace}=7b
{rbrace}=7d
{euro}=88
{copy}=a9
{nbsp}=A0
{shy}=AD

View File

@ -25,6 +25,7 @@ f0-ff=ðñòóôõö÷øùúûüýþÿ
{apos}=27
{lbrace}=7b
{rbrace}=7d
{euro}=80
{cent}=a2
{pound}=a3
{yen}=a5

View File

@ -0,0 +1,39 @@
NAME=CP1253
EOT=00
20=U+0020
21-3f=!"#$%&'()*+,-./0123456789:;<=>?
40-5f=@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
60-7e=`abcdefghijklmnopqrstuvwxyz{|}~
80=€
82-87=‚ƒ„…†‡
89=‰
8b=
91-97=‘’“”•–—
99=™
9b=
a1-ac=΅Ά£¤¥¦§¨©ͺ«¬
ae-af=®―
b0-bf=°±²³΄µ¶·ΈΉΊ»Ό½ΎΏ
c0-cf=ΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟ
d0-d1=ΠΡ
d3-df=ΣΤΥΦΧΨΩΪΫάέήί
e0-ef=ΰαβγδεζηθικλμνξο
f0-fe=πρςστυφχψωϊϋόύώ
{b}=08
{t}=09
{n}=0d0a
{q}=22
{apos}=27
{lbrace}=7b
{rbrace}=7d
{euro}=80
{pound}=a3
{yen}=a5
{copy}=a9
{pi}=f0
{nbsp}=A0
{shy}=AD

View File

@ -0,0 +1,34 @@
NAME=CP1254
EOT=00
20=U+0020
21-3f=!"#$%&'()*+,-./0123456789:;<=>?
40-5f=@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
60-7e=`abcdefghijklmnopqrstuvwxyz{|}~
80=€
82-8c=‚ƒ„…†‡ˆ‰Š‹Œ
91-9c=‘’“”•–—˜™š›œ
9f=Ÿ
a1-ac=¡¢£¤¥¦§¨©ª«¬
ae-af=®¯
b0-bf=°±²³´µ¶·¸¹º»¼½¾¿
c0-cf=ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ
d0-df=ĞÑÒÓÔÕÖ×ØÙÚÛÜİŞß
e0-ef=àáâãäåæçèéêëìíîï
f0-ff=ğñòóôõö÷øùúûüışÿ
{b}=08
{t}=09
{n}=0d0a
{q}=22
{apos}=27
{lbrace}=7b
{rbrace}=7d
{euro}=80
{cent}=a2
{pound}=a3
{yen}=a5
{copy}=a9
{ss}=df
{nbsp}=A0
{shy}=AD

View File

@ -0,0 +1,36 @@
NAME=CP1257
EOT=00
20=U+0020
21-3f=!"#$%&'()*+,-./0123456789:;<=>?
40-5f=@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
60-7e=`abcdefghijklmnopqrstuvwxyz{|}~
80=€
82-8c=‚ƒ„…†‡ˆ‰Š‹Œ
8d-8f=¨ˇ¸
91-9c=‘’“”•–—˜™š›œ
9e-9f=¯˛
a1-ac=¡¢£¤¥¦§Ø©Ŗ«¬
ae-af=®Æ
b0-bf=°±²³´µ¶·ø¹ŗ»¼½¾æ
c0-cf=ĄĮĀĆÄÅĘĒČÉŹĖĢĶĪĻ
d0-df=ŠŃŅÓŌÕÖ×ŲŁŚŪÜŻŽß
e0-ef=ąįāćäåęēčéźėģķīļ
f0-ff=šńņóōõö÷ųłśūüżž˙
{b}=08
{t}=09
{n}=0d0a
{q}=22
{apos}=27
{lbrace}=7b
{rbrace}=7d
{euro}=80
{cent}=a2
{pound}=a3
{yen}=a5
{copy}=a9
{ss}=df
{nbsp}=A0
{shy}=AD

View File

@ -27,4 +27,5 @@ F0-FE=≡±≥≤⌠⌡÷≈°∙·√ⁿ²■
{pound}=9c
{yen}=9d
{ss}=e1
{pi}=e3
{nbsp}=FF

View File

@ -23,6 +23,7 @@ F1-FE=±‗¾¶§÷¸°¨·¹³²■
{apos}=27
{lbrace}=7b
{rbrace}=7d
{copy}=b8
{cent}=BD
{pound}=9c
{yen}=BE

View File

@ -24,6 +24,7 @@ F1-FE=±υφχ§ψ¸°¨ωϋΰώ■
{apos}=27
{lbrace}=7b
{rbrace}=7d
{pound}=9c
{ss}=D7
{nbsp}=FF
{shy}=F0

View File

@ -25,6 +25,7 @@ F1-FE=±‗¾¶§÷¸°¨·¹³²■
{rbrace}=7d
{cent}=BD
{pound}=9c
{copy}=b8
{yen}=BE
{euro}=D5
{ss}=e1

View File

@ -19,6 +19,9 @@ fe-ff=↕↔
{apos}=27
{lbrace}=7b
{rbrace}=7d
{pound}=a3
{copy}=a4
{pi}=b8
{AE}=5b
{OE}=5c
{AA}=5d

View File

@ -19,3 +19,6 @@ fe-ff=↕↔
{apos}=27
{lbrace}=7b
{rbrace}=7d
{pound}=a3
{copy}=a4
{pi}=b8

View File

@ -19,3 +19,5 @@ fe-ff=↕↔
{apos}=27
{lbrace}=7b
{rbrace}=7d
{copy}=a4
{pi}=b8

Some files were not shown because too many files have changed in this diff Show More