mirror of
https://github.com/KarolS/millfork.git
synced 2024-05-31 18:41:30 +00:00
Compare commits
463 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
d8c11a9c50 | ||
|
ee47ccef5a | ||
|
24de2f7530 | ||
|
1beb695151 | ||
|
9229092309 | ||
|
ca7166d1ae | ||
|
1594d63a9a | ||
|
75cc34663c | ||
|
f4d2fdd370 | ||
|
29c1e3f2a6 | ||
|
e9cfec54b5 | ||
|
1bc1ab3539 | ||
|
6f294d6dec | ||
|
9866c974ad | ||
|
ef2f5b5918 | ||
|
a70a1c0e6b | ||
|
790c836771 | ||
|
6af84d1628 | ||
|
7b205a2754 | ||
|
d23fe1756e | ||
|
3b3ee1bc55 | ||
|
fb30075ea5 | ||
|
b5084cd180 | ||
|
b1a2be5574 | ||
|
a260d0a806 | ||
|
38ad919ed9 | ||
|
34ef8b8de9 | ||
|
f676e74e38 | ||
|
c9313e5dbe | ||
|
73a223b9b6 | ||
|
b168818bab | ||
|
effa723863 | ||
|
b2ab3dbeab | ||
|
c9ef5e636b | ||
|
fc2f0782c5 | ||
|
f0e22f02a6 | ||
|
b2291d1cb2 | ||
|
166acf2b18 | ||
|
7530b382a8 | ||
|
b66435d06b | ||
|
0c8951d015 | ||
|
84dde8589c | ||
|
3b0aa9a425 | ||
|
1b8de990a5 | ||
|
b060fc599b | ||
|
90e5360bfd | ||
|
bbf430a1c7 | ||
|
7f6a0c6b0d | ||
|
7f0def54bc | ||
|
faf97cee1f | ||
|
da862069a7 | ||
|
431a25d325 | ||
|
73beafd65e | ||
|
307ad90ecf | ||
|
2e592a2331 | ||
|
91c9b42f3d | ||
|
144da70594 | ||
|
4f6eefab79 | ||
|
ca35367974 | ||
|
2065c3b4ac | ||
|
9028d55a7e | ||
|
21d4d3252f | ||
|
45ad049a51 | ||
|
0172e29bb2 | ||
|
ffb46c4250 | ||
|
c51c08ad56 | ||
|
fcdad413b0 | ||
|
63edce28c4 | ||
|
1f318a2a0e | ||
|
1bcb6d5010 | ||
|
510f85960c | ||
|
8412075175 | ||
|
e25df3d1b3 | ||
|
b71d058c6a | ||
|
bf273456a3 | ||
|
062483971a | ||
|
1e4a193741 | ||
|
2468d8cca5 | ||
|
58b5b6ff28 | ||
|
8aac3bc329 | ||
|
24eac6708b | ||
|
66fc1d3984 | ||
|
0bbdc348e7 | ||
|
15a32a4caf | ||
|
e8f5667faa | ||
|
03bc5894aa | ||
|
bd9ff2f66d | ||
|
a111af384e | ||
|
6f2c8cd991 | ||
|
a0c2eaabcf | ||
|
83393d49f1 | ||
|
84d707b932 | ||
|
f01879e4a3 | ||
|
efb3d3c7c9 | ||
|
22bd6ac443 | ||
|
ffa0ffb899 | ||
|
3155d7a571 | ||
|
ba7c5b507c | ||
|
196ad6542f | ||
|
ff6106a838 | ||
|
9ebbbdc022 | ||
|
ab9cdf7ad5 | ||
|
4ff6120702 | ||
|
521b73d0d3 | ||
|
478b2eefbd | ||
|
3d57421959 | ||
|
78c29c784d | ||
|
25adb05229 | ||
|
bb46b1e7e9 | ||
|
7c60a89776 | ||
|
02031da61a | ||
|
d20cc677bb | ||
|
2beabb7bed | ||
|
fb71f88343 | ||
|
7689afb5d6 | ||
|
958c1c09e7 | ||
|
919f11af2e | ||
|
9c7e946f4c | ||
|
32b98750a9 | ||
|
ef34f534f9 | ||
|
3a2e29888d | ||
|
d6deb81166 | ||
|
394ac63805 | ||
|
42f6efc9bd | ||
|
8b0c026bf7 | ||
|
c1959b356f | ||
|
499e650752 | ||
|
fe4f0dcfd9 | ||
|
c6932da6b3 | ||
|
600bfce0c1 | ||
|
9feda54d92 | ||
|
91699b64c6 | ||
|
2a5933e115 | ||
|
bd8078cc47 | ||
|
30216d0be6 | ||
|
181332e238 | ||
|
90a9538936 | ||
|
4a529b5ddc | ||
|
7962a1d083 | ||
|
52c9da36b8 | ||
|
8dfad735ab | ||
|
cba145d674 | ||
|
145f2ed711 | ||
|
f2f53a4b28 | ||
|
7e45967b0c | ||
|
c8e32a876f | ||
|
b2d2c3e005 | ||
|
dc087ed887 | ||
|
97c7d0ffed | ||
|
385b2fd40b | ||
|
fc7643c416 | ||
|
91409504fb | ||
|
cd6b789416 | ||
|
f4a3601d6e | ||
|
f39810793b | ||
|
831be03167 | ||
|
af565b581a | ||
|
4a7166b9e0 | ||
|
45b4a5dfe3 | ||
|
d483dd1994 | ||
|
4a09a80db0 | ||
|
2ce1781e91 | ||
|
d76ae3ff9e | ||
|
758f0945f9 | ||
|
d0154253ea | ||
|
85829102b8 | ||
|
8a4e65b365 | ||
|
838ef0d1eb | ||
|
963fae8275 | ||
|
e94ccd164f | ||
|
a00e10382d | ||
|
24c0e8a8ee | ||
|
5d09410350 | ||
|
70da293fce | ||
|
c2e9acd3f3 | ||
|
d45fe42d17 | ||
|
889a4f94be | ||
|
c7008f4414 | ||
|
802424316c | ||
|
f9fc001c9a | ||
|
cc1adee4f1 | ||
|
362d682c11 | ||
|
a4b27f73e7 | ||
|
1b6b49889b | ||
|
2d7c365b20 | ||
|
3af4fcffa9 | ||
|
3a9be16107 | ||
|
3702002541 | ||
|
a15c9088ee | ||
|
6b3f43393e | ||
|
2823b7fde0 | ||
|
e0572fa3aa | ||
|
3364f8ab10 | ||
|
560ed09439 | ||
|
dc2def7e72 | ||
|
9f1309c119 | ||
|
888f7a0fdb | ||
|
1d046f26e3 | ||
|
a4de573593 | ||
|
433066fedd | ||
|
7182f32032 | ||
|
86ae6de325 | ||
|
9f40fc5066 | ||
|
b87c40fc9c | ||
|
1decf2f087 | ||
|
c9f602b049 | ||
|
030531161e | ||
|
7de23ddd44 | ||
|
2673a486d6 | ||
|
c0eae29a41 | ||
|
a92f24b280 | ||
|
e9d4359bc2 | ||
|
07b6adf6bc | ||
|
269519715b | ||
|
3234bbd3d9 | ||
|
19d9e36fa5 | ||
|
fe094af912 | ||
|
11d2f1aa77 | ||
|
81bf24b355 | ||
|
0010358d08 | ||
|
8e550669c1 | ||
|
aaaae08c03 | ||
|
9ee9712554 | ||
|
4758dba89e | ||
|
e8a50dc610 | ||
|
88e74906b6 | ||
|
bed44cd08e | ||
|
0806e719ce | ||
|
ca5fe5cdb0 | ||
|
947a84833a | ||
|
e8b1e9e391 | ||
|
adf84c084d | ||
|
a635449829 | ||
|
fc0171d5aa | ||
|
40510dc436 | ||
|
615a0d7dc1 | ||
|
75c8ac19e1 | ||
|
ae311f28ea | ||
|
3bbab4a126 | ||
|
b7cb124706 | ||
|
866a9ee9d0 | ||
|
e0b2d28a7d | ||
|
f5fb1a6911 | ||
|
19de4085d7 | ||
|
06e5da4e66 | ||
|
c31a2ee388 | ||
|
4849069d39 | ||
|
9a0176333b | ||
|
6b0effaae6 | ||
|
3582925cb1 | ||
|
c12541c64d | ||
|
5e46e8ade9 | ||
|
3ded652a90 | ||
|
e09db3d132 | ||
|
539c27f13e | ||
|
57776f7f93 | ||
|
7427231c3d | ||
|
b9cd18c3c8 | ||
|
49816d18fe | ||
|
70256e9d46 | ||
|
fccbf7df7d | ||
|
0913c5037c | ||
|
b5c51e48be | ||
|
708fdab593 | ||
|
398d9b9c4e | ||
|
29018729f5 | ||
|
c8c1657521 | ||
|
8331d6a575 | ||
|
c20b144823 | ||
|
a9aac4fca3 | ||
|
ea04b1f6c0 | ||
|
c1224f0795 | ||
|
925cc29172 | ||
|
d1c0ad6b22 | ||
|
89ff89bc48 | ||
|
87d9884597 | ||
|
cf707cc31f | ||
|
7c4fb50808 | ||
|
2382f95b5c | ||
|
4e1958d831 | ||
|
d77ecba518 | ||
|
2c9a3f7cbd | ||
|
2905e99521 | ||
|
03a57138f0 | ||
|
72dcf2342e | ||
|
bce48e8e4a | ||
|
ed55e2f081 | ||
|
33d67ec932 | ||
|
cad6f27185 | ||
|
8ec82ef520 | ||
|
f0b083abea | ||
|
d7f2b0688f | ||
|
0b7183daf2 | ||
|
42426808f5 | ||
|
2ee2de62cd | ||
|
9a67ac553d | ||
|
ff03b50668 | ||
|
778fc41187 | ||
|
84483830ce | ||
|
c6c021cf85 | ||
|
d5367cc1fe | ||
|
9a47c66539 | ||
|
b24ac32932 | ||
|
616873bbec | ||
|
53973f081a | ||
|
000aede8db | ||
|
27645e93ad | ||
|
8a0c552762 | ||
|
09ff184172 | ||
|
5fe4a4e3ac | ||
|
63aab64204 | ||
|
d0bf683657 | ||
|
a2c49a1f89 | ||
|
31a8504195 | ||
|
9881bc0284 | ||
|
d346800590 | ||
|
fff27c59ea | ||
|
0b948f801d | ||
|
632bb0c994 | ||
|
b9736f924c | ||
|
350c5d2d5d | ||
|
a22571f60b | ||
|
b9bf433308 | ||
|
b7a34457fb | ||
|
e77811c67c | ||
|
b387ece71d | ||
|
88b2bbd434 | ||
|
2b0090714c | ||
|
78a680c0d6 | ||
|
2d19537ed3 | ||
|
a947946313 | ||
|
bfe90193fa | ||
|
dd78b14c5e | ||
|
4e19b1ba34 | ||
|
b0577270d5 | ||
|
7ba01f83e3 | ||
|
b91f259971 | ||
|
718245c56a | ||
|
b5134dfbd1 | ||
|
4b5d290d6c | ||
|
655edc35ff | ||
|
3e33660c2e | ||
|
7f9bd18bdd | ||
|
a0aa9d418d | ||
|
e82f51668c | ||
|
78fe0e37bb | ||
|
c8492173ee | ||
|
c3b3548956 | ||
|
5909c37166 | ||
|
cd5e9decac | ||
|
29335d376a | ||
|
fac5a54376 | ||
|
b3fe0e9b06 | ||
|
dcf8fb2900 | ||
|
c53656aee2 | ||
|
4c39d5e6af | ||
|
0cba2dec04 | ||
|
eba91e26e5 | ||
|
49c916fea1 | ||
|
5b3e812bb1 | ||
|
f04f5ec111 | ||
|
4ea8658d5b | ||
|
16b83c42f3 | ||
|
78346af2ef | ||
|
b21b04efeb | ||
|
320b84edb9 | ||
|
4485c9479e | ||
|
017019ef5a | ||
|
078b22869a | ||
|
064a9d7022 | ||
|
5df695f2c2 | ||
|
7ce088514f | ||
|
d08f7ee77c | ||
|
ff942333bd | ||
|
9ffd303583 | ||
|
80018a55b4 | ||
|
353923d3bc | ||
|
1f626b0666 | ||
|
ceef57ed18 | ||
|
542474e920 | ||
|
ffb9de6889 | ||
|
742fc50ccc | ||
|
be21c34dc4 | ||
|
63ff28e94e | ||
|
5cdc599b1d | ||
|
5dd3e91c2d | ||
|
dfe33c9b7a | ||
|
78070c115f | ||
|
59882cf765 | ||
|
2a3c9f04be | ||
|
5215400cb2 | ||
|
9bc4bb949e | ||
|
842393106e | ||
|
8b39c59830 | ||
|
0f235e6135 | ||
|
3187ed155e | ||
|
b8e5e71c19 | ||
|
e3d5ce4e81 | ||
|
475496c137 | ||
|
2a566af3da | ||
|
d478f3504f | ||
|
5acf92d4e8 | ||
|
769f31717d | ||
|
85030d3147 | ||
|
9cd1e47a37 | ||
|
17e660a2f6 | ||
|
2eb8ef53ca | ||
|
7939b0f2c1 | ||
|
128dabba3f | ||
|
a527eea0fc | ||
|
748aa0cf19 | ||
|
46a523a763 | ||
|
ec8f2e6a1c | ||
|
83b85ef0fc | ||
|
3cc9996531 | ||
|
f57ecc9800 | ||
|
9f128d3c35 | ||
|
24870ae62e | ||
|
ab597e2dbe | ||
|
21ffbfc466 | ||
|
6e65cd1902 | ||
|
259d871786 | ||
|
5380eb39c7 | ||
|
63d4bf2317 | ||
|
fb1ad18868 | ||
|
8b6e89f9a4 | ||
|
5cb4717de6 | ||
|
b41c76c10e | ||
|
de4c261987 | ||
|
08acfed907 | ||
|
5c40d581c0 | ||
|
d6fd1e8b77 | ||
|
f247516187 | ||
|
6774c283ae | ||
|
7672ba008d | ||
|
09359235c7 | ||
|
b3fba658dd | ||
|
921a59bdad | ||
|
63866fffe3 | ||
|
ee425a0325 | ||
|
49bf0d2777 | ||
|
298e94e3bc | ||
|
6f68d9e668 | ||
|
0333b339ca | ||
|
17e02b9b13 | ||
|
d49e5cf022 | ||
|
3dab3aad6b | ||
|
43b64aac21 | ||
|
df1d5421be | ||
|
6e36166af2 | ||
|
b9cdd0ffff | ||
|
5c96b7e463 | ||
|
b421dbba4f | ||
|
e69b7084bc | ||
|
237985117e | ||
|
69c82d90a8 | ||
|
709d3d0fcd | ||
|
b2dd4eadd4 | ||
|
b1a76cad86 | ||
|
2c8b628da9 | ||
|
f8fc001971 | ||
|
f39fd67a89 | ||
|
6cd639a23a |
16
.gitignore
vendored
16
.gitignore
vendored
|
@ -6,22 +6,24 @@ project/project/target/
|
|||
stuff
|
||||
releases
|
||||
src/test/scala/experiments/
|
||||
src/test/java/experiments/
|
||||
# doesn't work yet
|
||||
examples/lunix/
|
||||
|
||||
# may become a feature in the future
|
||||
*.tbl
|
||||
# older copies
|
||||
include-*/
|
||||
|
||||
# hidden files
|
||||
*.~
|
||||
|
||||
#tools
|
||||
*.bat
|
||||
issue*.mfk
|
||||
|
||||
# compiled Scala files
|
||||
*.jar
|
||||
*.class
|
||||
*.zip
|
||||
*.exe
|
||||
|
||||
# compiled Millfork files
|
||||
*.prg
|
||||
|
@ -29,9 +31,12 @@ examples/lunix/
|
|||
*.seq
|
||||
*.asm
|
||||
*.lbl
|
||||
*.labels
|
||||
*.nl
|
||||
*.fns
|
||||
*.sym
|
||||
*.mlb
|
||||
*.dbg
|
||||
*.deb
|
||||
*.xex
|
||||
*.nes
|
||||
|
@ -46,12 +51,17 @@ examples/lunix/
|
|||
*.com
|
||||
*.gb
|
||||
*.rom
|
||||
*.ssd
|
||||
*.o
|
||||
*.cmd
|
||||
*.z80
|
||||
HELLO
|
||||
HELLOCPC
|
||||
FIZZBUZZ
|
||||
__hw_bbcmicro
|
||||
__hw_cpc464
|
||||
tests-cpc-*
|
||||
BBC-*
|
||||
|
||||
#heap dumps
|
||||
java_pid*
|
||||
|
|
377
CHANGELOG.md
377
CHANGELOG.md
|
@ -1,6 +1,355 @@
|
|||
# Change log
|
||||
|
||||
## 0.3.14
|
||||
## 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).
|
||||
|
||||
* Preliminary support for Tandy Color Computer running RS-DOS.
|
||||
|
||||
* Preliminary support for 16K cartridges for Tandy Color Computer.
|
||||
|
||||
* Added support for modifying large variables via pointers.
|
||||
|
||||
* Added the ability to declare structure alignment.
|
||||
|
||||
* `for` loops over arrays.
|
||||
|
||||
* Allowed defining custom text encodings.
|
||||
**Potentially breaking change!**
|
||||
There are no built-in encodings now, the include path needs to contain the necessary encodings.
|
||||
|
||||
* Fixed encodings:
|
||||
`apple2`, `atasciiscr`, `iso_de`, `iso_no`, `iso_se`,
|
||||
`koi7n2`, `msx_jp`,
|
||||
`oldpet`, `origpet`, `petscii`, `petsciijp`, `petscr`, `petscrjp`,
|
||||
`zx80`.
|
||||
|
||||
* Added encodings:
|
||||
`apple2c`, `apple2e`, `apple2gs`,
|
||||
`coco`, `cocoscr`,
|
||||
`cpc_da`, `cpc_en`, `cpc_es`, `cpc_fr`,
|
||||
`cp437`, `cp850`, `cp851`, `cp852`, `cp855`, `cp858`, `cp866`,
|
||||
`cp1250`, `cp1251`, `cp1252`,
|
||||
`ebcdic`,
|
||||
`galaksija`,
|
||||
`iso8859_1`, `iso8859_2`, `iso8859_3`, `iso8859_4`, `iso8859_5`,
|
||||
`iso8859_7`, `iso8859_9`, `iso8859_10`, `iso8859_13`, `iso8859_14`, `iso8859_16`,
|
||||
`kamenicky`,
|
||||
`koi8e`, `koi8f`, `koi8r`, `koi8ru`, `koi8t`, `koi8u`,
|
||||
`mazovia`, `pcw`,
|
||||
`pokemon1en`, `pokemon1es`, `pokemon1fr`, `pokemon1jp`.
|
||||
|
||||
* Added `ENCODING_NOLOWER` preprocessor feature.
|
||||
|
||||
* Fixed raw views of typed pointers.
|
||||
|
||||
* Fixed dead code elimination (#51).
|
||||
|
||||
* **Potentially breaking change!** Changed default encoding for CPC to `cpc_en`.
|
||||
|
||||
* **Potentially breaking change!** Changed the type of `mouse_lbm` and `mouse_rbm` to `bool`. Added `mouse_mbm`
|
||||
|
||||
* **Potentially breaking change!** Renamed the `x_coord` module to `coord`. Added the `y_coord` type and `TALLSCREEN` preprocessor feature.
|
||||
|
||||
* Added `pscrstr2word` function.
|
||||
|
||||
* Labels with fixed addresses are now exported to the label file (#49).
|
||||
|
||||
* Fixed address of the VIC 20 volume register (#52) (thanks to @nippur72).
|
||||
|
||||
* Fixed and improved stdlib optimizations.
|
||||
|
||||
* Allow importing modules from subdirectories.
|
||||
|
||||
* Allow placing platform definitions in a dedicated subdirectory.
|
||||
|
||||
* Allow using Batch files with the `-r` option.
|
||||
|
||||
* Improved error reporting for constants used before their definitions.
|
||||
|
||||
* Improved typo hints.
|
||||
|
||||
* Typo hints for non-ASCII characters.
|
||||
|
||||
* Z80: Intel syntax for all Z80 instructions, based on Digital Research's Z80.LIB.
|
||||
|
||||
* Commander X16: Updated to support VERA 0.9 and the new joystick API. Added mouse support.
|
||||
|
||||
* 6502: Optimization improvements:
|
||||
|
||||
* Fixed index register optimization regressions.
|
||||
|
||||
* Small array optimizations are now available for more operations.
|
||||
|
||||
* Index calculations for arrays of structs with sizes divisible by an even power of two are now sometimes optimized.
|
||||
|
||||
* Redundant index calculations are now removed.
|
||||
|
||||
## 0.3.16 (2020-04-08)
|
||||
|
||||
* Language improvements:
|
||||
|
||||
* Added compile-time evaluation for user-defined functions.
|
||||
|
||||
* Added `breakpoint` macro (#44).
|
||||
|
||||
* **Potentially breaking change!** Added `min`, `max` and `if` compile-time functions.
|
||||
|
||||
* Added experimental `signed16` and `unsigned16` types.
|
||||
|
||||
* Added length-prefixed strings (Pascal strings).
|
||||
|
||||
* Improved operator support for word-sized arguments (#24, #25).
|
||||
|
||||
* **Potentially breaking change!** Various macros improvements, including the requirement of parameter types matching exactly (#23, #39, #40).
|
||||
|
||||
* Compiler improvements:
|
||||
|
||||
* 6809 improvements (no full support yet).
|
||||
|
||||
* Added warnings for calling from one segment to another overlapping one.
|
||||
|
||||
* 6502: Fixed undocumented mnemonics.
|
||||
|
||||
* Create output directories when needed (#21).
|
||||
|
||||
* Allow defining different output formats for different segments when outputting one file per segment.
|
||||
|
||||
* Fixed multiple optimization bugs (#32, #38, #41, #46 and others) – thanks to @agg23 for detailed bug reports!
|
||||
|
||||
* 6502: Fix boolean arrays and pointers (#28).
|
||||
|
||||
* Fixed and improved memset-like loops (#47).
|
||||
|
||||
* Minor improvements to inline assembly.
|
||||
|
||||
* Improvements to constant evaluation, including more arithmetic operators.
|
||||
|
||||
* **Potentially breaking change!** Detect overflowing constants, like `const byte x = 256`.
|
||||
|
||||
* Optimization improvements.
|
||||
|
||||
* 6502: Memory allocation improvements for pointers.
|
||||
|
||||
* Support for MkImg (tool for creating BBC Micro disk images) and multiple output files on BBC Micro.
|
||||
|
||||
* Other minor fixes.
|
||||
|
||||
* Library improvements:
|
||||
|
||||
* Added `putsigned16` function.
|
||||
|
||||
* Added `pstring` module and `putpstr` function.
|
||||
|
||||
* Various improvements to the C64 libraries (thanks to @bsutherland).
|
||||
|
||||
* Added detection for various PET variants and implemented `readkey` for PET.
|
||||
|
||||
* Implemented `readkey` and `readline` for Apple II.
|
||||
|
||||
* Changed the default load address for BBC Micro.
|
||||
|
||||
* Multiple fixes to the `string`, `scrstring` and `encconv` modules.
|
||||
|
||||
* Other minor fixes.
|
||||
|
||||
* Other changes:
|
||||
|
||||
* Created a pure-Millfork test suite.
|
||||
|
||||
* Updated to Scala 2.12.11.
|
||||
|
||||
## 0.3.14 (2019-12-03)
|
||||
|
||||
* Full assembly support for HuC6280.
|
||||
|
||||
|
@ -16,7 +365,7 @@
|
|||
|
||||
* Other bug fixes.
|
||||
|
||||
## 0.3.12
|
||||
## 0.3.12 (2019-11-06)
|
||||
|
||||
* **Breaking change!**
|
||||
The `petscr`, `petscrjp` and `atasciiscr` encodings now use $E0, $E0 and $DB respectively as their string terminator.
|
||||
|
@ -40,7 +389,7 @@ Changed the identifiers for various subtypes of the 65C02 processors.
|
|||
|
||||
* Other bugfixes
|
||||
|
||||
## 0.3.10
|
||||
## 0.3.10 (2019-10-24)
|
||||
|
||||
* Preliminary support for the CPU from ZX Spectrum Next.
|
||||
|
||||
|
@ -80,7 +429,7 @@ Changed the identifiers for various subtypes of the 65C02 processors.
|
|||
|
||||
* Added another NES example (thanks to @Garydos).
|
||||
|
||||
## 0.3.8
|
||||
## 0.3.8 (2019-06-21)
|
||||
|
||||
* `sizeof` now supports arrays.
|
||||
|
||||
|
@ -116,7 +465,7 @@ Changed the identifiers for various subtypes of the 65C02 processors.
|
|||
|
||||
* 6502: Inlining improvements.
|
||||
|
||||
## 0.3.6
|
||||
## 0.3.6 (2019-08-05)
|
||||
|
||||
* **Breaking change!**
|
||||
The `petscii` encoding now uses the $C0-$DE range for uppercase characters instead of $60-$7E.
|
||||
|
@ -178,7 +527,7 @@ This matches both the CC65 behaviour and the return values from `readkey()`.
|
|||
|
||||
* Other fixes and improvements.
|
||||
|
||||
## 0.3.4
|
||||
## 0.3.4 (2019-07-01)
|
||||
|
||||
* Preliminary experimental Game Boy support.
|
||||
|
||||
|
@ -275,7 +624,7 @@ can no longer be read before an explicit call to `init_rw_memory`, either add th
|
|||
|
||||
* Optimization improvements.
|
||||
|
||||
## 0.3.2
|
||||
## 0.3.2 (2018-12-28)
|
||||
|
||||
* Almost complete support for the Zilog Z80, Intel 8080 and Sharp LR35902 microprocessors.
|
||||
|
||||
|
@ -289,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
|
||||
|
||||
|
@ -311,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.
|
||||
|
||||
|
@ -348,7 +697,7 @@ Code that uses a custom platform definitions will cause extra warnings until fix
|
|||
|
||||
* Other improvements.
|
||||
|
||||
## 0.3.0
|
||||
## 0.3.0 (2018-06-25)
|
||||
|
||||
* Finally faster than C.
|
||||
|
||||
|
@ -380,7 +729,7 @@ Code that uses a custom platform definitions will cause extra warnings until fix
|
|||
|
||||
* Other improvements.
|
||||
|
||||
## 0.2.2
|
||||
## 0.2.2 (2018-03-19)
|
||||
|
||||
* Allowed adding constant words to variable bytes without the zeropage pseudoregister.
|
||||
|
||||
|
@ -392,7 +741,7 @@ Code that uses a custom platform definitions will cause extra warnings until fix
|
|||
|
||||
* Other improvements.
|
||||
|
||||
## 0.2
|
||||
## 0.2 (2018-03-17)
|
||||
|
||||
* **Breaking change!** Renamed `inline` to `macro`.
|
||||
|
||||
|
@ -441,6 +790,6 @@ Detailed flow analysis was slow, broken, hard to maintain, and didn't even help
|
|||
|
||||
* Other improvements.
|
||||
|
||||
## 0.1
|
||||
## 0.1 (2018-01-24)
|
||||
|
||||
* Initial numbered version.
|
||||
* Initial numbered version.
|
||||
|
|
29
COMPILING.md
29
COMPILING.md
|
@ -21,23 +21,11 @@ Setting up the test suite for Millfork is tricky, so if you don't need the tests
|
|||
|
||||
#### Steps
|
||||
|
||||
* delete the `src/test` directory
|
||||
* run `sbt -DskipTests compile`
|
||||
to compile the project
|
||||
|
||||
* 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 compile` to compile the project
|
||||
|
||||
* run `sbt assembly` to build the executable jar file, it should appear in `target/scala-2.12`
|
||||
* run `sbt -DskipTests assembly`
|
||||
to build the executable jar file, it should appear in `target/scala-2.12`
|
||||
|
||||
### Building with tests
|
||||
|
||||
|
@ -45,7 +33,10 @@ Test suite is useful if you plan on modifying the compiler. Some test dependenci
|
|||
|
||||
#### 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
|
||||
|
||||
|
@ -58,7 +49,7 @@ Test suite is useful if you plan on modifying the compiler. Some test dependenci
|
|||
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/1b4e059c5886fe01e8901c70684f7eedefe65010
|
||||
https://github.com/sorenroug/osnine-java/tree/b77349a6c314e1362e69b7158c385ac6f89b7ab8
|
||||
|
||||
* for each of them, run `maven package` and `maven install`
|
||||
|
||||
|
@ -66,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
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
10
README.md
10
README.md
|
@ -2,10 +2,10 @@
|
|||
|
||||
# Millfork
|
||||
|
||||
A middle-level programming language targeting 6502-based, 8080-based and Z80-based microcomputers.
|
||||
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.14).
|
||||
(latest: 0.3.30).
|
||||
For build instructions, see [Build instructions](./COMPILING.md).
|
||||
|
||||
## Features
|
||||
|
@ -22,19 +22,21 @@ 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
|
||||
|
||||
* Game Boy (experimental)
|
||||
|
||||
* Tandy Color Computer (experimental)
|
||||
|
||||
* MS-DOS (very experimental, via 8080-to-8086 translation)
|
||||
|
||||
* multiple supported target processors:
|
||||
|
||||
* well supported: MOS 6502, Ricoh 2A03/2A07, WDC 65C02, Intel 8080, Intel 8085, Zilog Z80
|
||||
|
||||
* reasonably well supported: Sharp LR35902, CSG 65CE02
|
||||
* reasonably well supported: Sharp LR35902, CSG 65CE02, Motorola 6809
|
||||
|
||||
* partially supported: Hudson Soft HuC6280, WDC 65816, Intel 8086
|
||||
|
||||
|
|
54
build.sbt
54
build.sbt
|
@ -1,8 +1,9 @@
|
|||
name := "millfork"
|
||||
|
||||
version := "0.3.14"
|
||||
version := "0.3.31-SNAPSHOT"
|
||||
|
||||
scalaVersion := "2.12.10"
|
||||
// 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/1b4e059c5886fe01e8901c70684f7eedefe65010
|
||||
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" % "1.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")
|
||||
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
* [Preprocessor](lang/preprocessor.md)
|
||||
|
||||
* [Modules](lang/modules.md)
|
||||
|
||||
* [Syntax](lang/syntax.md)
|
||||
|
||||
* [Types](lang/types.md)
|
||||
|
@ -34,6 +36,8 @@
|
|||
|
||||
* [Inline 8080/LR35902/Z80 assembly syntax](lang/assemblyz80.md)
|
||||
|
||||
* [Inline 6809 assembly syntax](lang/assembly6809.md)
|
||||
|
||||
* [Important guidelines regarding reentrancy](lang/reentrancy.md)
|
||||
|
||||
* [List of keywords](lang/keywords.md)
|
||||
|
@ -42,27 +46,47 @@
|
|||
|
||||
* [`stdlib` module](stdlib/stdlib.md)
|
||||
|
||||
* [`string` and `scrstring` modules](stdlib/string.md)
|
||||
* [`string`, `scrstring` and `pstring` modules](stdlib/string.md)
|
||||
|
||||
* [`stdio` module](stdlib/stdio.md)
|
||||
|
||||
* [Modules for reading input devices](stdlib/input.md)
|
||||
* Reading input devices:
|
||||
|
||||
* [`joy` module](stdlib/joy.md)
|
||||
|
||||
* [`keyboard` module](stdlib/keyboard.md)
|
||||
|
||||
* [`mouse` module](stdlib/mouse.md)
|
||||
|
||||
* [`encconv` module](stdlib/encconv.md)
|
||||
|
||||
* [Other cross-platform modules (`keyboard`, `err`, `random`)](stdlib/other.md)
|
||||
* [Other cross-platform modules (`err`, `random`)](stdlib/other.md)
|
||||
|
||||
* [Definitions available on only some platforms](stdlib/frequent.md)
|
||||
* Platform-specific modules:
|
||||
|
||||
* [C64-only modules](stdlib/c64.md)
|
||||
* [Definitions available on only some platforms](stdlib/frequent.md)
|
||||
|
||||
* [`cbm_file` module](stdlib/cbm_file.md)
|
||||
* [C64-only modules](stdlib/c64.md)
|
||||
|
||||
* [PET-only modules](stdlib/cbm_pet.md)
|
||||
|
||||
* [`cbm_file` module](stdlib/cbm_file.md)
|
||||
|
||||
* [NES-only modules](stdlib/nes.md)
|
||||
|
||||
* [Atari Lynx-only modules](stdlib/lynx.md)
|
||||
|
||||
* [Game Boy–only modules](stdlib/gb.md)
|
||||
|
||||
* [X16–only modules](stdlib/x16.md)
|
||||
|
||||
## Guides
|
||||
|
||||
* [NES-only modules](stdlib/nes.md)
|
||||
* [Differences from C](various/cdiff.md)
|
||||
|
||||
* [Game Boy–only modules](stdlib/gb.md)
|
||||
* [Differences from other assemblers](various/asmdiff.md)
|
||||
|
||||
* [X16–only modules](stdlib/x16.md)
|
||||
* [Optimization guide](various/optimization.md)
|
||||
|
||||
## Implementation details
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -4,17 +4,136 @@
|
|||
|
||||
## Macros
|
||||
|
||||
`macro` keyword
|
||||
Functions defined with the `macro` keyword are not actual functions, but they are used as syntax replacements.
|
||||
|
||||
It implies the following:
|
||||
|
||||
* macros must return `void`
|
||||
|
||||
* 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
|
||||
|
||||
* their invocations cannot be used as expressions
|
||||
|
||||
* in case of `asm` macros, the parameters:
|
||||
|
||||
* must be defined as either `const` (compile-time constants), `ref` (variables) or `register(XX)` (registers, where XX is the register you want to use)
|
||||
|
||||
* at most one parameter can be defined as a register
|
||||
|
||||
* in case of non-`asm` macros, the parameters
|
||||
|
||||
* must be defined as either `ref` (variables; default, may be omitted) `const` (compile-time constants), or `call` (expressions, which are evaluated every time they are used)
|
||||
|
||||
* `ref` parameters exceptionally can have their type declared as `void`; such parameters accept variables of any type
|
||||
|
||||
* `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
|
||||
|
||||
* 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
|
||||
|
||||
When invoking a macro, you need to pass variables as arguments to parameters annotated with `ref` and constants as arguments annotated with `const`.
|
||||
|
||||
Invoking a non-`asm` macro requires the types of variables via `ref` parameters to match precisely.
|
||||
No type conversions are performed.
|
||||
Exception: parameters of type `void` can accept a variable of any type.
|
||||
|
||||
For parameters defined as `const`, `register(XX)` or `call`, the usual type conversions are performed.
|
||||
|
||||
You can invoke a macro from assembly, by preceding the invocation with `+`
|
||||
|
||||
Examples:
|
||||
|
||||
macro void inc_x() {
|
||||
x += 1
|
||||
}
|
||||
byte add_two_1(byte x) {
|
||||
inc_x()
|
||||
inc_x()
|
||||
return x
|
||||
}
|
||||
|
||||
macro void inc(byte b) {
|
||||
b += 1
|
||||
}
|
||||
byte add_two_2(byte x) {
|
||||
inc(x)
|
||||
inc(x)
|
||||
return x
|
||||
}
|
||||
macro void perform_twice(void call f) {
|
||||
f
|
||||
f
|
||||
}
|
||||
byte add_two_3(byte x) {
|
||||
perform_twice(inc(x))
|
||||
return x
|
||||
}
|
||||
|
||||
macro void add(byte b, byte v) {
|
||||
b += v
|
||||
}
|
||||
macro void retu(byte result) {
|
||||
return result
|
||||
}
|
||||
byte add_two_4(byte x) {
|
||||
add(x, 2)
|
||||
retu(x)
|
||||
}
|
||||
|
||||
macro asm byte add_asm(byte ref b, byte const v) {
|
||||
LDA b
|
||||
CLC
|
||||
ADC #v
|
||||
STA b
|
||||
// no RTS!
|
||||
}
|
||||
byte add_two_5(byte x) {
|
||||
add_asm(x, 2)
|
||||
return x
|
||||
}
|
||||
|
||||
macro asm byte add_asm_2(byte ref b, byte register(x) v) {
|
||||
TXA
|
||||
CLC
|
||||
ADC b
|
||||
STA b
|
||||
// no RTS!
|
||||
}
|
||||
byte add_two_6(byte x) {
|
||||
add_asm_2(x, 2)
|
||||
return x
|
||||
}
|
||||
|
||||
|
||||
## Automatic inlining
|
||||
|
||||
You can control inlining behavior in several ways:
|
||||
|
||||
* functions declared with the `const` keyword called with constant arguments will always be inlined,
|
||||
with the whole invocation being converted into a single constant, regardless of `inline` and `noinline` keywords;
|
||||
calls with non-constant arguments are subject to the regular rules.
|
||||
|
||||
* functions declared with the `inline` keyword will be inlined if possible
|
||||
|
||||
* 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
|
||||
|
|
|
@ -24,6 +24,8 @@ Millfork supports multiple mnemonics per opcode. The default one is given first:
|
|||
|
||||
* **ISC**, INS
|
||||
|
||||
* **KIL**
|
||||
|
||||
* **LAS**
|
||||
|
||||
* **LAX**
|
||||
|
@ -67,8 +69,11 @@ AHX, LAS, LXA, SHX, SHY, TAS, XAA.
|
|||
## Z80
|
||||
|
||||
Original Z80 processors accidentally supported a bunch of extra undocumented instructions.
|
||||
Millfork will not emit them.
|
||||
The only exception is SLL, which will be emitted if it occurs in a handwritten assembly block.
|
||||
Millfork will emit some of them if used in an assembly block:
|
||||
|
||||
* `SLL` – supported
|
||||
* instructions using the IXH, IXL, IYH, IYL registers – supported (can only be used in Zilog syntax)
|
||||
* instructions of the form `RLC IX(1),B` – not supported
|
||||
|
||||
## 8085
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
Variables in Millfork can belong to one of the following storage classes:
|
||||
|
||||
* static: all global variables; local variables declared with `static`
|
||||
* static: all global variables; local variables declared with `static` or `volatile`
|
||||
|
||||
* stack: local variables declared with `stack`
|
||||
|
||||
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -6,7 +6,9 @@ The default configuration file puts the start address for the program at $0E00.
|
|||
|
||||
The compiler outputs two files: a raw machine code file without an extension and a `.inf` file with file metadata.
|
||||
To use the file, you need to put it on a disk or a disk image.
|
||||
You can for example use tools like BBC Disk Explorer.
|
||||
You can for example use tools like BBC Disk Explorer (GUI) or MkImg (command line):
|
||||
|
||||
MkImg disk_image.ssd output_directory
|
||||
|
||||
After putting it on a disk, the file can be run with:
|
||||
|
||||
|
|
26
docs/api/coco-programming-guide.md
Normal file
26
docs/api/coco-programming-guide.md
Normal file
|
@ -0,0 +1,26 @@
|
|||
[< back to index](../doc_index.md)
|
||||
|
||||
### A note about Color Computer
|
||||
|
||||
#### `coco_rsdos` target
|
||||
|
||||
The `coco_rsdos` target creates binary files that can run on Tandy Color Computer running RS-DOS.
|
||||
|
||||
The compiler output is a raw machine code file with the `.bin` extension, which then has to be put on a disk.
|
||||
You can do it using `imgtool` from the [MAME project](https://www.mamedev.org/):
|
||||
|
||||
imgtool create coco_jvc_rsdos disk_image.dsk
|
||||
imgtool put coco_jvc_rsdos disk_image.dsk compiler_output.bin CO.BIN
|
||||
|
||||
The resulting file can then be loaded and ran using the following commands:
|
||||
|
||||
LOADM"CO":EXEC
|
||||
|
||||
#### `coco_crt` target
|
||||
|
||||
The `coco_crt` target creates 16k cartridge images that can run on Tandy Color Computer or Dragon.
|
||||
|
||||
The program is run directly from ROM;
|
||||
typical ROM programming guidelines apply, see [the ROM vs RAM guide](./rom-vs-ram.md).
|
||||
|
||||
The `main` function is not allowed to return.
|
|
@ -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,20 +47,35 @@ 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.
|
||||
When enabled, breakpoints become memory barriers and the label file will contain the breakpoints if the format supports them.
|
||||
Currently, the only formats that supports breakpoints are `vice` and `sym`.
|
||||
`.ini` equivalent: `breakpoints`. Default: yes.
|
||||
|
||||
* `-I <dir>;<dir>` – The include directories.
|
||||
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.
|
||||
|
||||
* `-t <platform>` – Target platform. It is loaded from an `.ini` file found in any of the include directories. See also [this document](target-platforms.md).
|
||||
|
||||
* `-r <program>` – Run given program after successful compilation. Useful for automatically launching emulators without any external scripting.
|
||||
* `-r <program>` – Run given program after successful compilation.
|
||||
Useful for automatically launching emulators without any external scripting.
|
||||
The program is run with the working directory set to its own directory,
|
||||
and it's passed the full path to the output file as its argument.
|
||||
|
||||
* `-R <param>` – Adds a parameter to the command line of the program run with `-r`. All `-R` options are added in order, before the output file name.
|
||||
|
||||
|
@ -181,6 +196,14 @@ Allow using the IY register for other purposes.
|
|||
Compiling to 8086 is based on translating from a mix of 8085 and Z80 instructions to 8086.
|
||||
See [the 8086 support disclaimer](./../lang/x86disclaimer.md).
|
||||
|
||||
#### 6809-related
|
||||
|
||||
* `-fuse-u-for-stack`, `-fuse-y-for-stack`
|
||||
Which of Z80 index registers should be used as the base pointer for accessing stack variables, if any.
|
||||
`.ini` equivalent: `u_stack` and `y_stack`. Default: none.
|
||||
**Warning: Currently, picking one of those two options is required!**
|
||||
The compiler doesn't support accessing the stack variables via the S stack pointer register yet.
|
||||
|
||||
## Optimization options
|
||||
|
||||
* `-O0` – Disable all optimizations except unused global symbol removal.
|
||||
|
@ -189,6 +212,10 @@ See [the 8086 support disclaimer](./../lang/x86disclaimer.md).
|
|||
|
||||
* `-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`.
|
||||
|
@ -204,7 +231,7 @@ Default: yes.
|
|||
|
||||
* `-foptimize-stdlib`, `-fno-optimize-stdlib` –
|
||||
Whether should replace some standard library calls with constant parameters with more efficient variants.
|
||||
Currently affects `putstrz` and `strzlen`, but may affect more functions in the future.
|
||||
Currently affects `putstrz`, `putpstr`, `strzlen`, `scrstrlen` and `pstrlen`, but may affect more functions in the future.
|
||||
`.ini` equivalent: `optimize_stdlib`.
|
||||
Default: no.
|
||||
|
||||
|
@ -254,6 +281,52 @@ command line options `--inline`, `--dangerous-optimizations` `--fipo` and `--fno
|
|||
|
||||
## Warning options
|
||||
|
||||
By default, the compiler emits only some of the most important warnings.
|
||||
|
||||
* `-Wall` – Enable extra 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.
|
||||
|
|
|
@ -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
|
||||
|
@ -63,7 +68,7 @@ The default segment will be in `OUTPUT.prg`, the segment called `extra` in `OUTP
|
|||
The Millfork compiler does not create Commodore disk images.
|
||||
|
||||
You can use a variety of tools to perform that task,
|
||||
for example the `c1531` tool shipped with [the VICE emulator](http://vice-emu.sourceforge.net/).
|
||||
for example the `c1541` tool shipped with [the VICE emulator](http://vice-emu.sourceforge.net/).
|
||||
|
||||
To create a new disk image for the last example, use:
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
## Adding a custom platform
|
||||
|
||||
Every platform is defined in an `.ini` file with an appropriate name.
|
||||
The file is looked up in the directories on the include path, first directly, then in the `platform` subdirectory.
|
||||
|
||||
As an extension, multiline entries are supported:
|
||||
if a line ends with a backslash character, the value continues to the next line.
|
||||
|
@ -36,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)
|
||||
|
||||
|
@ -59,7 +63,8 @@ See [the list of available encodings](../lang/text.md).
|
|||
* `screen_encoding` – default encoding for screencodes (literals with encoding specified as `scr`).
|
||||
Default: the same as `encoding`.
|
||||
|
||||
* `modules` – comma-separated list of modules that will be automatically imported
|
||||
* `modules` – comma-separated list of modules that will be automatically imported.
|
||||
This list cannot contain module template instantiations.
|
||||
|
||||
* other compilation options (they can be overridden using commandline options):
|
||||
|
||||
|
@ -77,6 +82,8 @@ Default: the same as `encoding`.
|
|||
* `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
|
||||
|
@ -112,6 +119,13 @@ Default: the same as `encoding`.
|
|||
|
||||
* `iy_scratch` – allow using the IY register for other purposes, default is `false`
|
||||
|
||||
* `u_stack` – use the U register to access stack variables, default is `false`. Applicable only to 6809-based targets.
|
||||
|
||||
* `y_stack` – use the Y register to access stack variables, default is `false`. Applicable only to 6809-based targets.
|
||||
**Warning: Currently, picking either `u_stack` or `y_stack` is required,
|
||||
unless you want to always specify this option in the compiler's command line!**
|
||||
The compiler doesn't support accessing the stack variables via the S stack pointer register yet.
|
||||
|
||||
* `software_stack` – use software stack for stack variables, default is `false`. Applicable only to 6502-based targets.
|
||||
|
||||
* `output_intel_syntax` – use Intel syntax instead of Zilog syntax, default is `true` for Intel 8080/8085 and `false` otherwise
|
||||
|
@ -163,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".
|
||||
|
@ -194,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`
|
||||
|
||||
|
@ -207,18 +227,30 @@ 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
|
||||
|
||||
* `extension` – target file extension, with or without the dot
|
||||
|
||||
|
@ -235,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`.
|
||||
|
|
|
@ -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).
|
||||
|
@ -60,7 +60,7 @@ just specify them correctly in the `[output]format` tag.
|
|||
|
||||
The `[output]format` tag should contain a valid iNES or NES 2.0 header of the mapper of your choice
|
||||
and then all the segments in proper order (first PRGROM, then CHRROM).
|
||||
See [the MMC4 example](../../include/nes_mmc4.ini) to see how it can be done.
|
||||
See [the MMC4 example](https://github.com/KarolS/millfork/blob/master/include/nes_mmc4.ini) to see how it can be done.
|
||||
|
||||
See [the NesDev wiki](https://wiki.nesdev.com/w/index.php/NES_2.0) for more info about the NES 2.0 file format.
|
||||
|
||||
|
|
|
@ -99,6 +99,18 @@ 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.
|
||||
|
||||
* `coco_crt` – 16K cartridge for Tandy Color Computer. (very experimental)
|
||||
Read [the Color Computer programming guide](./coco-programming-guide.md) for more info.
|
||||
|
||||
* `dos_com` – a COM file for DOS on IBM PC. (very experimental)
|
||||
|
||||
* `x16_experimental` – Commander X16; very experimental,
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
* [Preprocessor](lang/preprocessor.md)
|
||||
|
||||
* [Modules](lang/modules.md)
|
||||
|
||||
* [Syntax](lang/syntax.md)
|
||||
|
||||
* [Types](lang/types.md)
|
||||
|
@ -24,8 +26,12 @@
|
|||
|
||||
* [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)
|
||||
|
||||
* [Operators reference](lang/operators.md)
|
||||
|
||||
* [Functions](lang/functions.md)
|
||||
|
@ -38,35 +44,59 @@
|
|||
|
||||
* [Important guidelines regarding reentrancy](lang/reentrancy.md)
|
||||
|
||||
* [Optimization hints](lang/hints.md)
|
||||
|
||||
* [List of keywords](lang/keywords.md)
|
||||
|
||||
## Library reference
|
||||
|
||||
* [`stdlib` module](stdlib/stdlib.md)
|
||||
|
||||
* [`string` and `scrstring` modules](stdlib/string.md)
|
||||
* [`string`, `scrstring` and `pstring` modules](stdlib/string.md)
|
||||
|
||||
* [`stdio` module](stdlib/stdio.md)
|
||||
|
||||
* [Modules for reading input devices](stdlib/input.md)
|
||||
* Reading input devices:
|
||||
|
||||
* [`joy` module](stdlib/joy.md)
|
||||
|
||||
* [`keyboard` module](stdlib/keyboard.md)
|
||||
|
||||
* [`mouse` module](stdlib/mouse.md)
|
||||
|
||||
* [`encconv` module](stdlib/encconv.md)
|
||||
|
||||
* [Other cross-platform modules (`keyboard`, `err`, `random`)](stdlib/other.md)
|
||||
* [Other cross-platform modules (`err`, `random`)](stdlib/other.md)
|
||||
|
||||
* [Definitions available on only some platforms](stdlib/frequent.md)
|
||||
* Platform-specific modules:
|
||||
|
||||
* [C64-only modules](stdlib/c64.md)
|
||||
* [Definitions available on only some platforms](stdlib/frequent.md)
|
||||
|
||||
* [`cbm_file` module](stdlib/cbm_file.md)
|
||||
* [C64-only modules](stdlib/c64.md)
|
||||
|
||||
* [NES-only modules](stdlib/nes.md)
|
||||
* [VIC-20-only modules](stdlib/vic20.md)
|
||||
|
||||
* [PET-only modules](stdlib/cbm_pet.md)
|
||||
|
||||
* [`cbm_file` module](stdlib/cbm_file.md)
|
||||
|
||||
* [Atari Lynx-only modules](stdlib/lynx.md)
|
||||
* [Apple II-only modules](stdlib/apple2.md)
|
||||
|
||||
* [NES-only modules](stdlib/nes.md)
|
||||
|
||||
* [Atari Lynx-only modules](stdlib/lynx.md)
|
||||
|
||||
* [Game Boy–only modules](stdlib/gb.md)
|
||||
|
||||
* [X16–only modules](stdlib/x16.md)
|
||||
|
||||
## Guides
|
||||
|
||||
* [Game Boy–only modules](stdlib/gb.md)
|
||||
* [Differences from C](various/cdiff.md)
|
||||
|
||||
* [X16–only modules](stdlib/x16.md)
|
||||
* [Differences from other assemblers](various/asmdiff.md)
|
||||
|
||||
* [Optimization guide](various/optimization.md)
|
||||
|
||||
## Implementation details
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -13,6 +13,9 @@ 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 6502 assemblers.
|
||||
Indexing syntax is also the same. Only instructions available on the current CPU architecture are available.
|
||||
|
||||
The short branching instructions and the `BRK` instruction support the immediate addressing mode,
|
||||
for more control over code generation.
|
||||
|
||||
The `BBRn/BBSn/SMBn/RMBn` instructions cannot parameterize the tested bit. The syntax is as follows:
|
||||
|
||||
BBR1 $10,label
|
||||
|
@ -36,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
|
||||
|
@ -45,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:
|
||||
|
@ -67,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.
|
||||
|
@ -110,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.
|
||||
|
||||
|
||||
|
@ -148,9 +162,11 @@ Non-macro functions can only have their parameters passed via registers:
|
|||
* `word xa`, `word ax`, `word ay`, `word ya`, `word xy`, `word yx`: a 2-byte word byte passed via given two CPU registers,
|
||||
with the high byte passed through the first register and the low byte passed through the second register; any 2-byte type can be used
|
||||
|
||||
* the above, but written more explicitly: `byte register(a) paramname`, `byte register(x) paramname`, `word register(ax) paramname` etc.
|
||||
|
||||
For example, this piece of code:
|
||||
|
||||
asm void f(word ax) @F_ADDR extern
|
||||
asm void f(word register(ax) value) @F_ADDR extern
|
||||
|
||||
f(5)
|
||||
|
||||
|
@ -176,7 +192,7 @@ Macro assembly functions can have maximum one parameter passed via a register.
|
|||
An external function should be declared with a defined memory address
|
||||
and the `extern` keyword instead of the body:
|
||||
|
||||
asm void putchar(byte a) @$FFD2 extern
|
||||
asm void putchar(byte register(a) char) @$FFD2 extern
|
||||
|
||||
## Safe assembly
|
||||
|
||||
|
@ -215,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:
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
@ -42,9 +53,17 @@ but you need to be careful with using absolute vs immediate addressing:
|
|||
}
|
||||
return result
|
||||
}
|
||||
|
||||
To use the direct addressing mode, prepend the argument with `<`:
|
||||
|
||||
CLR <$6f // clears the byte $6f in the direct page
|
||||
CLR $6f // clears the byte $006f (absolute address!)
|
||||
|
||||
You can use `>` do signify the absolute addressing mode, but it is never necessary.
|
||||
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.
|
||||
|
@ -120,6 +139,8 @@ Non-macro functions can only have their parameters passed via registers:
|
|||
|
||||
* `word d`, `word x`, `word y`: a 2-byte word byte passed via given 16-bit register; any 2-byte type can be used
|
||||
|
||||
* the above, but written more explicitly: `byte register(a) paramname`, `byte register(b) paramname`, `word register(x) paramname` etc.
|
||||
|
||||
Parameters passed via other registers (`U`, `S` etc.) or combinations of registers do not work yet.
|
||||
|
||||
**Work in progress**:
|
||||
|
|
|
@ -22,12 +22,17 @@ LR35902 instructions that load/store the accumulator indirectly via HL and then
|
|||
LR35902 instructions for faster access to the $FFxx addresses use the `LDH` mnemonic: `LDH A,(4)`, `LDH (C),A` etc.
|
||||
|
||||
Only instructions available on the current CPU architecture are available.
|
||||
Intel syntax does not support instructions that are unavailable on the 8080.
|
||||
Undocumented Z80 instructions are not supported, except for `SLL`.
|
||||
Undocumented Z80 instructions are partially supported:
|
||||
* `SLL` – supported
|
||||
* instructions using the IXH, IXL, IYH, IYL registers – supported (can only be used in Zilog syntax)
|
||||
* instructions of the form `RLC IX(1),B` – not supported
|
||||
|
||||
Not all ZX Spectrum Next are supported. `JP (C)`, `BSLA` and similar instructions are not supported.
|
||||
Intel syntax supports the 8080 instructions, the documented Z80 instructions and `SLL`.
|
||||
It does not support instructions that are unavailable on the Z80 or other undocumented Z80 instructions.
|
||||
|
||||
Labels have to be followed by a colon and they can optionally be on a separate line.
|
||||
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.
|
||||
Indentation is not important:
|
||||
|
||||
// Zilog syntax
|
||||
|
@ -43,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:
|
||||
|
@ -70,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.
|
||||
|
@ -160,6 +176,8 @@ Non-macro functions can only have their parameters passed via registers:
|
|||
|
||||
* `word hl`, `word bc`, `word de`: a 2-byte word byte passed via given 16-bit register; any 2-byte type can be used
|
||||
|
||||
* the above, but written more explicitly: `byte register(a) paramname`, `byte register(b) paramname`, `word register(hl) paramname` etc.
|
||||
|
||||
Parameters passed via other registers (`I`, `IX`, `IY`, `IXH` etc.) or combinations of registers do not work yet.
|
||||
|
||||
**Work in progress**:
|
||||
|
@ -198,3 +216,108 @@ it should abide to the following rules:
|
|||
* end non-inline assembly functions with `RET`, `JP`, `RETI` or `RETN` (Zilog) / `RET` or `JMP` (Intel) as appropriate
|
||||
|
||||
The above list is not exhaustive.
|
||||
|
||||
## Z80 instructions in the Intel syntax
|
||||
|
||||
Millfork uses the same extensions for Intel syntax as Z80.LIB from Digital Research.
|
||||
Some mnemonics from the TDL Z80 Relocating/Linking Assembler are also supported.
|
||||
|
||||
In the list below, `c` is a flag, `r` is a register, and `n` and `d` are parameters.
|
||||
For instructions using the index registers, only the IY variant is given;
|
||||
the IX variant has the same mnemonic, but with `Y` replaced with `X`.
|
||||
|
||||
Intel syntax | Zilog syntax
|
||||
----|----
|
||||
**EXAF** | **EX AF,AF'**
|
||||
**JR n**, JMPR n | **JR n**
|
||||
**JRc n** | **JR c,n**
|
||||
**INP r** | **IN r,(C)**
|
||||
**OUTP r** | **OUT r,(C)**
|
||||
**CCI** | **CPI**
|
||||
**CCIR** | **CPIR**
|
||||
**CCD** | **CPD**
|
||||
**CCDR** | **CPDR**
|
||||
**OUTIR** | **OTIR**, OUTIR
|
||||
**OUTDR** | **OTDR**, OUTDR
|
||||
**IM0** | **IM 0**
|
||||
**IM1** | **IM 1**
|
||||
**IM2** | **IM 2**
|
||||
**DSBC r** | **SBC HL,rr**
|
||||
**DADC r** | **ADC HL,rr**
|
||||
**DADY r** | **ADD IY,rr**
|
||||
**INXIY**, INX IY | **INC IY**
|
||||
**DCXIY**, DCX IY | **DEC IY**
|
||||
**SBCD nn** | **LD (nn),BC**
|
||||
**SDED nn** | **LD (nn),DE**
|
||||
**SSPD nn** | **LD (nn),SP**
|
||||
**SIYD nn** | **LD (nn),IY**
|
||||
**LBCD nn** | **LD BC,(nn)**
|
||||
**LDED nn** | **LD DE,(nn)**
|
||||
**LSPD nn** | **LD SP,(nn)**
|
||||
**LIYD nn** | **LD IY,(nn)**
|
||||
**SETB n,r**, SET n,r | **SET n,r**
|
||||
**BITY n,d** | **BIT n,IY(d)**
|
||||
**SETY n,d** | **SET n,IY(d)**
|
||||
**RESY n,d** | **RES n,IY(d)**
|
||||
**PCIY** | **JP IY**
|
||||
**RLCR r** | **RLC r**
|
||||
**RALR r** | **RL r**
|
||||
**RRCR r** | **RRC r**
|
||||
**RARR r** | **RR r**
|
||||
**SLAR r** | **SLA r**
|
||||
**SRAR r** | **SRA r**
|
||||
**SRLR r** | **SRL r**
|
||||
**RLCX r** | **RLC r**
|
||||
**RALY d** | **RL IY(d)**
|
||||
**RRCY d** | **RRC IY(d)**
|
||||
**RARY d** | **RR IY(d)**
|
||||
**SLAY d** | **SLA IY(d)**
|
||||
**SRAY d** | **SRA IY(d)**
|
||||
**SRLY d** | **SRL 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**
|
||||
**XTIY** | **EX (SP),IY**
|
||||
**LDAI** | **LD A,I**
|
||||
**LDAR** | **LD A,R**
|
||||
**STAI** | **LD I,A**
|
||||
**STAR** | **LD R,A**
|
||||
**LXIY nn**, LXI IY,nn | **LD IY,nn**
|
||||
**ADDY d** | **ADD A,IY(d)**
|
||||
**ADCY d** | **ADC A,IY(d)**
|
||||
**SUBY d** | **SUB IY(d)**
|
||||
**SBCY d** | **SBC A,IY(d)**
|
||||
**ANDY d** | **AND IY(d)**
|
||||
**XORY d** | **XOR IY(d)**
|
||||
**ORY d** | **OR IY(d)**
|
||||
**CMPY d** | **CMP IY(d)**
|
||||
**INRY d** | **INC IY(d)**
|
||||
**DCRY d** | **DEC IY(d)**
|
||||
**MVIY n,d** | **LD IY(d),n**
|
||||
**LDY r,d** | **LD r,IY(d)**
|
||||
**STY r,d** | **LD IY(d),r**
|
||||
|
||||
|
||||
Instructions that are the same in both syntaxes:
|
||||
|
||||
**BIT n,r**,
|
||||
**RES n,r**,
|
||||
**DJNZ n**,
|
||||
**EXX**,
|
||||
**NEG**,
|
||||
**RETI**,
|
||||
**RETN**,
|
||||
**RLD**,
|
||||
**RRD**,
|
||||
**LDI**,
|
||||
**LDIR**,
|
||||
**LDD**,
|
||||
**LDDR**,
|
||||
**INI**,
|
||||
**INIR**,
|
||||
**IND**,
|
||||
**INDR**,
|
||||
**OUTI**,
|
||||
**OUTD**
|
||||
|
|
52
docs/lang/custom-encoding.md
Normal file
52
docs/lang/custom-encoding.md
Normal file
|
@ -0,0 +1,52 @@
|
|||
[< back to index](../doc_index.md)
|
||||
|
||||
### Defining custom encodings
|
||||
|
||||
Every encoding is defined in an `.tbl` file with an appropriate name.
|
||||
The file is looked up in the directories on the include path, first directly, then in the `encoding` subdirectory.
|
||||
|
||||
The file is a UTF-8 text file, with each line having a specific meaning.
|
||||
In the specifications below, `<>` are not to be meant literally:
|
||||
|
||||
* lines starting with `#`, `;` or `//` are comments.
|
||||
|
||||
* `ALIAS=<another encoding name>` defines this encoding to be an alias for another encoding.
|
||||
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`, `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.
|
||||
Required, unless `BUILTIN` is present.
|
||||
There have to be two digits, `EOT=0` is invalid.
|
||||
|
||||
* lines like `<xx>=<c>` where `<xx>` are two hex digits
|
||||
and `<c>` is either a **non-whitespace** character or a **BMP** Unicode codepoint written as `U+xxxx`,
|
||||
define the byte `<xx>` to correspond to character `<c>`.
|
||||
There have to be two digits, `0=@` is invalid.
|
||||
|
||||
* lines like `<xx>-<xx>=<c><c><c><c>` where `<c>` is repeated an appropriate number of times
|
||||
define characters for multiple byte values.
|
||||
In this kind of lines, characters cannot be represented as Unicode codepoints.
|
||||
|
||||
* lines like `<c>=<xx>`, `<c>=<xx><xx>` etc.
|
||||
define secondary or alternate characters that are going to be represented as one or more bytes.
|
||||
There have to be two digits, `@=0` is invalid.
|
||||
Problematic characters (space, `=`, `#`, `;`) can be written as Unicode codepoints `U+xxxx`.
|
||||
|
||||
* a line like `a-z=<xx>` is equivalent to lines `a=<xx>`, `b=<xx+$01>` all the way to `z=<xx+$19>`.
|
||||
|
||||
* a line like `KATAKANA=>DECOMPOSE` means that katakana characters with dakuten or handakuten
|
||||
should be split into the base character and the standalone dakuten/handakuten.
|
||||
|
||||
* similarly with `HIRAGANA=>DECOMPOSE`.
|
||||
|
||||
* lines like `{<escape code>}=<xx>`, `{<escape code>}=<xx><xx>` etc.
|
||||
define escape codes. It's a good practice to define these when possible:
|
||||
`{q}`, `{apos}`, `{n}`, `{lbrace}`, `{rbrace}`,
|
||||
`{yen}`, `{pound}`, `{cent}`, `{euro}`, `{copy}`, `{pi}`,
|
||||
`{nbsp}`, `{shy}`.
|
||||
|
|
@ -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 a) @ $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,13 +39,23 @@ 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.
|
||||
Unlike hardware handlers with `interrupt`, you can treat functions with `kernal_interrupt` like normal functions.
|
||||
On non-6502-based targets, functions marked as `kernal_interrupt` don't differ from normal functions.
|
||||
|
||||
* `const` – the function is pure and can be used in constant expressions. `const` functions are not allowed to:
|
||||
|
||||
* use constants that have been declared after them
|
||||
|
||||
* have local variables
|
||||
|
||||
* call non-const functions
|
||||
|
||||
* contain any other statements other than return statements and conditional statements
|
||||
|
||||
* `<return_type>` is a valid return type, see [Types](./types.md)
|
||||
|
||||
* `<params>` is a comma-separated list of parameters, in form `type name`. Allowed types are the same as for local variables.
|
||||
|
@ -58,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,
|
||||
|
@ -68,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
84
docs/lang/hints.md
Normal 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
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -7,10 +7,10 @@
|
|||
To call an external function, you need to declare it as `asm extern`. For example:
|
||||
|
||||
```
|
||||
asm void putchar(byte a) @$FFD2 extern
|
||||
asm void putchar(byte register(a) char) @$FFD2 extern
|
||||
```
|
||||
|
||||
The function parameter will be passed via the accumulator,
|
||||
In this example, the function parameter will be passed via the accumulator,
|
||||
the function itself is located in ROM at $FFD2. A call like this:
|
||||
|
||||
```
|
||||
|
@ -36,7 +36,7 @@ To call a function that has its address calculated dynamically,
|
|||
you just need to do the same as what you would do in assembly; 6502 example:
|
||||
|
||||
```
|
||||
asm void call_function(byte a) {
|
||||
asm void call_function(byte register(a) param) {
|
||||
JMP (function_address)
|
||||
}
|
||||
```
|
||||
|
|
|
@ -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,13 +70,44 @@ 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
|
||||
|
||||
## Length-prefixed strings (Pascal strings)
|
||||
|
||||
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 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 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, or UTF-32, 4):
|
||||
|
||||
pointer p
|
||||
p = "test"pz
|
||||
// putstrz(p) // won't work correctly
|
||||
putstrz(p + 1) // ok
|
||||
|
||||
## Escape sequences and miscellaneous compatibility issues
|
||||
|
||||
Most characters between the quotes are interpreted literally.
|
||||
|
@ -175,6 +213,7 @@ An array is initialized with either:
|
|||
array b = "----" scr
|
||||
array c = ["hello world!" ascii, 13]
|
||||
array d = file("d.bin")
|
||||
array d1 = file("d.bin", 128)
|
||||
array e = file("d.bin", 128, 256)
|
||||
array f = for x,0,until,8 [x * 3 + 5] // equivalent to [5, 8, 11, 14, 17, 20, 23, 26]
|
||||
array(point) g = [point(2,3), point(5,6)]
|
||||
|
@ -182,8 +221,19 @@ An array is initialized with either:
|
|||
|
||||
Trailing commas (`[1, 2,]`) are not allowed.
|
||||
|
||||
String literals are laid out in the arrays as-is, flat.
|
||||
To have an array of pointers to strings, wrap each string in `pointer(...)`:
|
||||
|
||||
// a.length = 12; identical to [$48, $45, $4C, $4C, $4F, 0, $57, $4F, $52, $4C, $44, 0]
|
||||
array a = [ "hello"z, "world"z ]
|
||||
// b.length = 2
|
||||
array(pointer) b = [ pointer("hello"z), pointer("world"z) ]
|
||||
|
||||
The parameters for `file` are: file path, optional start offset, optional length
|
||||
(start offset and length have to be either both present or both absent).
|
||||
(if only two parameters are present, then the second one is assumed to be the start offset).
|
||||
The `file` expression is expanded at the compile time to an array of bytes equal to the bytes contained in the file.
|
||||
If the start offset is present, then that many bytes at the start of the file are skipped.
|
||||
If the length is present, then only that many bytes are taken, otherwise, all bytes until the end of the file are taken.
|
||||
|
||||
The `for`-style expression has a variable, a starting index, a direction, a final index,
|
||||
and a parameterizable array initializer.
|
||||
|
@ -195,7 +245,7 @@ Fields of arithmetic, pointer and enum types are declared using normal expressio
|
|||
Fields of struct types are declared using struct constructors.
|
||||
Fields of union types cannot be declared.
|
||||
|
||||
What might be useful is the fact that the compiler allows for built-in trigonometric functions
|
||||
What might be useful is the fact that the compiler allows for certain built-in functions
|
||||
in constant expressions only:
|
||||
|
||||
* `sin(x, n)` – returns _n_·**sin**(*x*π/128)
|
||||
|
@ -204,3 +254,7 @@ in constant expressions only:
|
|||
|
||||
* `tan(x, n)` – returns _n_·**tan**(*x*π/128)
|
||||
|
||||
* `min(x,...)` – returns the smallest argument
|
||||
|
||||
* `max(x,...)` – returns the largest argument
|
||||
|
||||
|
|
98
docs/lang/modules.md
Normal file
98
docs/lang/modules.md
Normal file
|
@ -0,0 +1,98 @@
|
|||
[< back to index](../doc_index.md)
|
||||
|
||||
# Program structure
|
||||
|
||||
A Millfork program is build from one or more modules.
|
||||
|
||||
Each module is stored in a single file.
|
||||
All source filenames passed to the compiler are considered to be modules of that program, called _root modules_.
|
||||
|
||||
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 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.
|
||||
Importing the same module multiple times merely marks it as imported by multiple modules,
|
||||
but the program will still contain only one copy of it.
|
||||
Examples:
|
||||
|
||||
import string
|
||||
import cbm_file
|
||||
|
||||
Usually, the imported module will undergo the first phase of compilation first.
|
||||
This means that the constants in the imported module will be resolved first, allowing you to use them in the importing module.
|
||||
|
||||
|
||||
The only exception to this rule is when the importing graph has a cycle, in which case the order of modules within the cycle is unspecified.
|
||||
|
||||
A platform may define starting modules using the `modules=` directive of the `[compilation]` section.
|
||||
All starting modules are considered to be imported by all source files explicitly mentioned on the command line.
|
||||
|
||||
### Module templates
|
||||
|
||||
If the first line of a source file starts with the `#template` directive,
|
||||
then the source is considered to be a _module template_.
|
||||
Module templates are a tool for generating repetitive code, similar to COBOL copybooks or Go Generate.
|
||||
|
||||
The template directive contains a comma-separated list of parameters.
|
||||
It's recommended that the names of parameters begin and end with non-alphanumeric characters:
|
||||
|
||||
#template $P1$, $P2$
|
||||
|
||||
A module template cannot be imported as-is.
|
||||
When importing a module template, you import a concrete instantiation of it.
|
||||
|
||||
For example, if the file `temp.mfk` contains the `#template` from above,
|
||||
you can import it by providing a list of numeric literals or identifiers:
|
||||
|
||||
import temp<1, 2>
|
||||
|
||||
This instantiates a new module named `temp<1,2>` (if it hasn't been instantiated anywhere else).
|
||||
The code in that module is generated by replacing every instance of the parameter names with the actual argument content.
|
||||
Parameters that are numeric literals are normalized to their decimal representations.
|
||||
|
||||
Your program may contain multiple modules created from the same template with different parameters. For example,
|
||||
|
||||
import temp<3, 4>
|
||||
import temp<5, 6>
|
||||
import temp<$5, $6>
|
||||
|
||||
instantiates and imports two similar, yet different modules: `temp<3,4>` and `temp<5,6>`.
|
||||
The third import imports a module that has already been instantiated and imported, so it's redundant.
|
||||
|
||||
The instantiation works through simple text replacement. For example, if `temp.mfk` contains:
|
||||
|
||||
#template $P1$, $P2$
|
||||
const byte a$P1$ = $P2$
|
||||
|
||||
then the `temp<1,2>` module will contain
|
||||
|
||||
const byte a1 = 2
|
||||
|
||||
This substitution is performed before preprocessing, so those substitutions are available for the preprocessor directives.
|
||||
It applies to identifiers, string literals, keywords, preprocesor directives etc.
|
||||
|
||||
**Warning:** This mechanism provides no direct way for preventing duplicates of code
|
||||
that does not depend on the template parameters, or depends on only some template parameters.
|
||||
In such situations, it might be advisable to put the non-dependent definitions in another module that is not a template,
|
||||
or in a module template with fewer parameters. For example, instead of writing:
|
||||
|
||||
#template $N$
|
||||
const byte X = 50
|
||||
array a$N$ [X]
|
||||
|
||||
(which would define duplicate `X`s if imported multiple times), consider writing two files:
|
||||
|
||||
#template $N$
|
||||
import define_X
|
||||
array a$N$ [X]
|
||||
>
|
||||
|
||||
//define_X.mfk:
|
||||
const byte X = 50
|
||||
|
||||
|
|
@ -18,9 +18,9 @@ Millfork has different operator precedence compared to most other languages. Fro
|
|||
|
||||
* `->` and `[]`
|
||||
|
||||
* `*`, `*'`
|
||||
* `*`, `$*`, `/`, `%%`
|
||||
|
||||
* `+`, `+'`, `-`, `-'`, `|`, `&`, `^`, `>>`, `>>'`, `<<`, `<<'`, `>>>>`
|
||||
* `+`, `$+`, `-`, `$-`, `|`, `&`, `^`, `>>`, `$>>`, `<<`, `$<<`, `>>>>`
|
||||
|
||||
* `:`
|
||||
|
||||
|
@ -34,9 +34,18 @@ 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,
|
||||
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
|
||||
|
||||
|
@ -54,6 +63,8 @@ In the descriptions below, arguments to the operators are explained as follows:
|
|||
|
||||
* `constant` means a compile-time constant
|
||||
|
||||
* `trivial` means either a constant or a non-stack variable
|
||||
|
||||
* `simple` means either: a constant, a non-stack variable,
|
||||
a pointer indexed with a constant, a pointer indexed with a non-stack variable,
|
||||
an array indexed with a constant, an array indexed with a non-stack variable,
|
||||
|
@ -77,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`
|
||||
|
@ -124,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
|
||||
|
||||
|
@ -187,25 +201,28 @@ 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 long += long`
|
||||
`mutable trivial long += long`
|
||||
|
||||
* `<<=`, `>>=`: shift in place
|
||||
`mutable byte <<= byte`
|
||||
`mutable word <<= byte`
|
||||
`mutable long <<= byte`
|
||||
`mutable trivial long <<= byte`
|
||||
|
||||
* `<<'=`, `>>'=`: decimal shift in place
|
||||
`mutable byte <<'= constant byte`
|
||||
`mutable word <<'= constant byte`
|
||||
`mutable 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 long -= simple long`
|
||||
`mutable trivial long -= simple long`
|
||||
|
||||
* `*=`: multiplication in place
|
||||
`mutable byte *= constant byte`
|
||||
|
@ -213,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)
|
||||
|
@ -273,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
|
||||
|
@ -292,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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -54,10 +54,14 @@ The following features are defined based on the chosen CPU and compilation optio
|
|||
`CPUFEATURE_8080`, `CPUFEATURE_8085`, `CPUFEATURE_GAMEBOY`, `CPUFEATURE_Z80`,
|
||||
`CPUFEATURE_6502_ILLEGALS`, `CPUFEATURE_8085_ILLEGALS`, `CPUFEATURE_Z80_ILLEGALS`, `CPUFEATURE_Z80_NEXT` – 1 if given instruction subset is enabled, 0 otherwise
|
||||
|
||||
* `ENCCONV_SUPPORTED` - 1 if the module `encconv` supports the function `to_screencode` and other related funtions, 0 otherwise.
|
||||
* `ENCCONV_SUPPORTED` - 1 if the module `encconv` supports the function `to_screencode` and other related functions, 0 otherwise.
|
||||
|
||||
* `ENCODING_SAME` - 1 if the encodings `default` and `src` are the same, 0 otherwise.
|
||||
|
||||
* `ENCODING_NOLOWER` – 1 if the `default` encoding does not support lowercase ASCII letters.
|
||||
|
||||
* `DECIMALS_SAME` - 1 if the encodings `default` and `src` have the same string terminator and decimal digits `'0'`-`'9'`, 0 otherwise.
|
||||
|
||||
* `NULLCHAR_SAME` - 1 if the encodings `default` and `src` have the same string terminator, 0 otherwise.
|
||||
|
||||
* `NULLCHAR` – the value of the `nullchar` constant
|
||||
|
@ -90,40 +94,55 @@ See [the ROM vs RAM guide](../api/rom-vs-ram.md) for more information.
|
|||
|
||||
### Commonly used features
|
||||
|
||||
These features are frequently defined in the platform definition file.
|
||||
Some libraries may require that some of these be defined.
|
||||
|
||||
* `WIDESCREEN` – 1 if the horizontal screen resolution, ignoring borders, is greater than 256, 0 otherwise
|
||||
|
||||
* `CBM` – 1 if the target is an 8-bit Commodore computer (or a compatible one), 0 otherwise
|
||||
|
||||
* `CBM_64_COMPAT` – 1 if the target is an 8-bit Commodore computer compatible with Commodore 64, 0 otherwise
|
||||
|
||||
* `CBM_64_CRT` – 1 if the target is a cartridge for Commodore 64, 0 otherwise
|
||||
|
||||
* `CBM_264` – 1 if the target is an 8-bit Commodore computer from the 264 line, 0 otherwise
|
||||
* `TALLSCREEN` – 1 if the vertical screen resolution, ignoring borders, is greater than 256, 0 otherwise
|
||||
|
||||
* `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
|
||||
|
||||
* `HAS_BITMAP_MODE` – 1 if the target has a display mode with every pixel addressable, 0 otherwise
|
||||
|
||||
* `MOS_6510` – 1 if the target uses a MOS 6510-compatible processor (with an I/O port at $0000/$0001)
|
||||
|
||||
* `CPM` – 1 if the target is CP/M, 0 otherwise
|
||||
|
||||
* `IBM_PC` – 1 if the target is IBM PC, 0 otherwise
|
||||
|
||||
* `MSX` – 1 if the target is MSX, 0 otherwise
|
||||
|
||||
* `NTSC` – 1 if the target is NTSC, 0 otherwise
|
||||
|
||||
* `PAL` – 1 if the target is PAL, 0 otherwise
|
||||
|
||||
* `NULLPTR` – physical value of `nullptr`, default 0
|
||||
|
||||
* `VERA_VERSION` – on Commander X16, the version of the VERA chip: `7` for 0.7, `8` for 0.8
|
||||
### Target-specific features
|
||||
|
||||
These features are used to identify the target machine in multiplatform programs and libraries:
|
||||
|
||||
* `CBM` – 1 if the target is an 8-bit Commodore computer (or a compatible one), 0 otherwise
|
||||
(for more Commodore-related preprocessor options, see [Preprocessor options for Commodore computer targets](./preprocessor_cbm.md))
|
||||
|
||||
* `AMSTRAD_CPC`, `ATARI_2600`, `ATARI_8`, `ATARI_LYNX`, `APPLE_2`, `BBC_MICRO`,
|
||||
`COMMANDER_X16`, `CPM`, `GAMEBOY`, `IBM_PC`, `MSX`, `NEC_PC_88`, `NES`, `ZX_SPECTRUM`
|
||||
– 1 if the target is the machine in question, 0 otherwise
|
||||
|
||||
* `VERA_VERSION` – on Commander X16, the version of the VERA chip: `7` for 0.7, `8` for 0.8, `9` for 0.9
|
||||
|
||||
|
||||
### Built-in preprocessor functions and operators
|
||||
|
||||
The `same` function returns 1 if given identical identifiers and 0 otherwise.
|
||||
It is the only function that does not support any other kind of parameters, and it's only useful in module templates.
|
||||
|
||||
// prints 1:
|
||||
#infoeval same(a,a)
|
||||
// prints 0:
|
||||
#infoeval same(a,b)
|
||||
// fails to compile
|
||||
#infoeval same(a,1)
|
||||
|
||||
The `defined` function returns 1 if the feature is defined, 0 otherwise.
|
||||
All the other functions and operators treat undefined features as if they were defined as 0.
|
||||
|
||||
|
@ -134,11 +153,45 @@ The `if` function returns its second parameter if the first parameter is defined
|
|||
// prints 500:
|
||||
#infoeval if(0, 400, 500)
|
||||
|
||||
TODO
|
||||
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`
|
||||
|
||||
Defines the source to be a module template. See [Modules](./modules.md) for more information.
|
||||
|
||||
|
||||
### `#if/#elseif/#else/#endif`
|
||||
|
||||
|
|
38
docs/lang/preprocessor_cbm.md
Normal file
38
docs/lang/preprocessor_cbm.md
Normal file
|
@ -0,0 +1,38 @@
|
|||
[< back to index](../doc_index.md)
|
||||
|
||||
# Preprocessor options for Commodore computer targets
|
||||
|
||||
All Commodore targets define the `CBM` feature as 1.
|
||||
|
||||
### Target detection
|
||||
|
||||
* `CBM_PET` – 1 if the target is PET, 0 otherwise
|
||||
|
||||
* `CBM_VIC` – 1 if the target is VIC-20, 0 otherwise
|
||||
|
||||
* `CBM_264` – 1 if the target is an 8-bit Commodore computer from the 264 line, 0 otherwise
|
||||
|
||||
* `MOS_6510` – 1 if the target uses a MOS 6510-compatible processor (with an I/O port at $0000/$0001)
|
||||
|
||||
* `CBM_64` – 1 if the target is Commodore 64, 0 otherwise
|
||||
|
||||
* `CBM_64_CRT` – 1 if the target is a cartridge for Commodore 64, 0 otherwise
|
||||
|
||||
* `LUNIX` – 1 if the target is Commodore 64 running LUnix, 0 otherwise
|
||||
|
||||
* `CBM_128` – 1 if the target is Commodore 128, 0 otherwise
|
||||
|
||||
* `CBM_64_COMPAT` – 1 if the target is an 8-bit Commodore computer compatible with Commodore 64
|
||||
(for example, C128, C65, Mega 65), but not Commodore 64 itself, 0 otherwise
|
||||
|
||||
### Feature enabling
|
||||
|
||||
Due to incompatibilities between different versions of Commodore PET,
|
||||
certain libraries can be configured to support only some ROM revisions.
|
||||
By default, all of these are enabled:
|
||||
|
||||
* `PET2000_SUPPORT` – set this to 1 to enable support for PET 2001 with the original ROMs (BASIC 1.0), set it to 0 to disable it
|
||||
|
||||
* `PET3000_SUPPORT` – set this to 1 to enable support for PET 3000 series with the upgraded ROMs (BASIC 2.0), set it to 0 to disable it
|
||||
|
||||
* `PET4000_SUPPORT` – set this to 1 to enable support for PET 4000 with the 4.0 ROMs (BASIC 4.0), set it to 0 to disable it
|
52
docs/lang/suffixes.md
Normal file
52
docs/lang/suffixes.md
Normal 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).
|
||||
|
|
@ -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+0020–U+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,11 +63,14 @@ Examples:
|
|||
|
||||
* `volatile` means that the variable is volatile.
|
||||
The optimizer shouldn't remove or reorder accesses to volatile variables.
|
||||
Volatile variables cannot be declared as `register` or `stack.
|
||||
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.
|
||||
|
@ -86,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
|
||||
|
||||
|
@ -217,7 +246,11 @@ is equivalent to:
|
|||
|
||||
import <module>
|
||||
|
||||
Adds a module to the program.
|
||||
Adds a module to the program. The module name can be a valid identifier
|
||||
or a sequence of identifiers separated by forward slashes:
|
||||
|
||||
import module1
|
||||
import library1/module2
|
||||
|
||||
The module is looked up first in the current working directory, and then in the include directories.
|
||||
|
||||
|
@ -366,12 +399,18 @@ for <variable> , <start> , <direction> , <end> {
|
|||
}
|
||||
for <variable> : <enum type> {
|
||||
}
|
||||
for <variable> : <array> {
|
||||
}
|
||||
for <variable> , <variable2> : <array> {
|
||||
}
|
||||
for <variable> : [ <comma separated expressions> ] {
|
||||
}
|
||||
```
|
||||
|
||||
* `<variable>` – an already defined numeric variable
|
||||
|
||||
* `<variable2>` – an already defined numeric variable
|
||||
|
||||
* `<direction>` – the type of range to traverse:
|
||||
|
||||
* `to` – from `<start>` inclusive to `<end>` inclusive, in ascending order
|
||||
|
@ -406,11 +445,34 @@ for <variable> : [ <comma separated expressions> ] {
|
|||
|
||||
* `<enum type>` – traverse enum constants of given type, in arbitrary order
|
||||
|
||||
* `<array>` – traverse given array, in arbitrary order,
|
||||
assigning the index to `<variable>` and either the element or the pointer to the element to `<variable2>`
|
||||
|
||||
* `<comma separated expressions>` – traverse every value in the list, in the given order.
|
||||
Values do not have to be constant.
|
||||
If a value is not a constant and its value changes while executing the loop, the behaviour is undefined.
|
||||
Jumps using `goto` across the scope of this kind of loop are disallowed.
|
||||
|
||||
Examples:
|
||||
|
||||
struct S { ... }
|
||||
pointer.S p
|
||||
S s
|
||||
byte i
|
||||
array(str) arr [8]
|
||||
enum E { E_1, E_2, E_3 }
|
||||
E e
|
||||
|
||||
for i,0,until,8 { ... } // executes the body with i=0, i=1, ... i=7
|
||||
for i,0,to,7 { ... } // executes the body with i=0, i=1, ... i=7
|
||||
for i,0,paralleluntil,8 { ... } // executes the body with i=0, i=1, ... i=7 (in arbitrary order)
|
||||
for i,0,parallelto,8 { ... } // executes the body with i=0, i=1, ... i=7 (in arbitrary order)
|
||||
for i,7,downto,0 { ... } // executes the body with i=7, i=6, ... i=0
|
||||
for i:arr { ... } // executes the body with i=0, i=1, ... i=7 (in arbitrary order)
|
||||
for i,s:arr { ... } // executes the body with i=0, s=arr[0]; i=1, s=arr[1]; ... i=7, s=arr[7] (in arbitrary order)
|
||||
for i,p:arr { ... } // executes the body with i=0, p=arr[0].pointer; ... i=7, p=arr[7].pointer (in arbitrary order)
|
||||
for e:E { ... } // executes the body with e=E_1, e=E_2, e=E_3 (in arbitrary order)
|
||||
|
||||
### `break` and `continue` statements
|
||||
|
||||
Syntax:
|
||||
|
@ -433,6 +495,7 @@ Labelless `break` and `continue` apply to the innermost `for`, `while` or `do-wh
|
|||
`break for`, `continue do` etc. apply to the innermost loop of the given type.
|
||||
|
||||
`break i` and `continue i` apply to the innermost `for` loop that uses the `i` variable.
|
||||
`for` loops of the form `for i,j:array` can be broken from using `break i` only, not `break j`.
|
||||
|
||||
### `goto` and `label`
|
||||
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
[< back to index](../doc_index.md)
|
||||
|
||||
# Text encodings ans escape sequences
|
||||
# Text encodings and escape sequences
|
||||
|
||||
### Defining custom encodings
|
||||
|
||||
Every platform is defined in an `.tbl` file with an appropriate name.
|
||||
The file is looked up in the directories on the include path, first directly, then in the `encoding` subdirectory.
|
||||
|
||||
TODO: document the file format.
|
||||
|
||||
### Text encoding list
|
||||
|
||||
|
@ -11,19 +18,29 @@
|
|||
|
||||
* `ascii` – standard ASCII
|
||||
|
||||
* `pet` or `petscii` – PETSCII (ASCII-like character set used by Commodore machines from VIC-20 onward)
|
||||
* `petscii` or `pet` – PETSCII (ASCII-like character set used by Commodore machines from VIC-20 onward)
|
||||
|
||||
* `petjp` or `petsciijp` – PETSCII as used on Japanese versions of Commodore 64
|
||||
* `petsciijp` or `petjp` – PETSCII as used on Japanese versions of Commodore 64
|
||||
|
||||
* `origpet` or `origpetscii` – old PETSCII (Commodore PET with original ROMs)
|
||||
* `origpetscii` or `origpet` – old PETSCII (Commodore PET with original ROMs)
|
||||
|
||||
* `oldpet` or `oldpetscii` – old PETSCII (Commodore PET with newer ROMs)
|
||||
* `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
|
||||
|
||||
* `apple2` – Apple II charset ($A0–$DF)
|
||||
* `apple2` – original Apple II charset ($A0–$DF)
|
||||
|
||||
* `apple2e` – Apple IIe charset
|
||||
|
||||
* `apple2c` – alternative Apple IIc charset
|
||||
|
||||
* `apple2gs` – Apple IIgs charset
|
||||
|
||||
* `macroman` – Macintosh Western Latin charset
|
||||
|
||||
* `bbc` – BBC Micro character set
|
||||
|
||||
|
@ -37,15 +54,57 @@
|
|||
|
||||
* `iso_de`, `iso_no`, `iso_se`, `iso_yu` – various variants of ISO/IEC-646
|
||||
|
||||
* `iso_dk`, `iso_fi` – aliases for `iso_no` and `iso_se` respectively
|
||||
* `iso_dk`, `iso_fi` – aliases for `iso_no` and `iso_se` respectively
|
||||
|
||||
* `iso15` – ISO 8859-15
|
||||
* `dmcs` – DEC Multinational Character Set
|
||||
|
||||
* `latin0`, `latin9`, `iso8859_15` – aliases for `iso15`
|
||||
* `lics` – Lotus International Character Set
|
||||
|
||||
* `iso8859_1`, `iso8859_2`, `iso8859_3`,
|
||||
`iso8859_4`, `iso8859_5`, `iso8859_7`,
|
||||
`iso8859_9`, `iso8859_10`, `iso8859_13`,
|
||||
`iso8859_14`, `iso8859_15`, `iso8859_13` –
|
||||
ISO 8859-1, ISO 8859-2, ISO 8859-3,
|
||||
ISO 8859-4, ISO 8859-5, ISO 8859-7,
|
||||
ISO 8859-9, ISO 8859-10, ISO 8859-13,
|
||||
ISO 8859-14, ISO 8859-15, ISO 8859-16,
|
||||
|
||||
* `iso1`, `latin1` – aliases for `iso8859_1`
|
||||
* `iso2`, `latin2` – aliases for `iso8859_2`
|
||||
* `iso3`, `latin3` – aliases for `iso8859_3`
|
||||
* `iso4`, `latin4` – aliases for `iso8859_4`
|
||||
* `iso5` – alias for `iso8859_5`
|
||||
* `iso7` – alias for `iso8859_7`
|
||||
* `iso9`, `latin5`, – aliases for `iso8859_9`
|
||||
* `iso10`, `latin6` – aliases for `iso8859_10`
|
||||
* `iso13`, `latin7` – aliases for `iso8859_13`
|
||||
* `iso14`, `latin8` – aliases for `iso8859_14`
|
||||
* `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
|
||||
|
||||
* `mazovia` – Mazovia encoding
|
||||
|
||||
* `kamenicky` – Kamenický encoding
|
||||
|
||||
* `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
|
||||
|
||||
* `msx_us`, `msx_uk`, `msx_fr`, `msx_de` – aliases for `msx_intl`
|
||||
* `msx_us`, `msx_uk`, `msx_fr`, `msx_de` – aliases for `msx_intl`
|
||||
|
||||
* `cpc_en`, `cpc_fr`, `cpc_es`, `cpc_da` – Amstrad CPC character encoding, English, French, Spanish and Danish respectively
|
||||
|
||||
* `pcw` or `amstrad_cpm` – Amstrad CP/M encoding, the US variant (language 0), as used on PCW machines
|
||||
|
||||
* `pokemon1en`, `pokemon1jp`, `pokemon1es`, `pokemon1fr` – text encodings used in 1st generation Pokémon games,
|
||||
English, Japanese, Spanish/Italian and French/German respectively
|
||||
|
||||
* `pokemon1it`, `pokemon1de` – aliases for `pokemon1es` and `pokemon1fr` respectively
|
||||
|
||||
* `atascii` or `atari` – ATASCII as seen on Atari 8-bit computers
|
||||
|
||||
|
@ -53,15 +112,37 @@
|
|||
|
||||
* `koi7n2` or `short_koi` – KOI-7 N2
|
||||
|
||||
* `koi8r`, `koi8u`, `koi8ru`, `koi8e`, `koi8f`, `koi8t` – various variants of KOI-8
|
||||
|
||||
* `vectrex` – built-in Vectrex font
|
||||
|
||||
* `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 `pet` for strings you're printing using standard I/O routines
|
||||
and `petscr` for strings you're copying to screen memory directly.
|
||||
use `petscii` for strings you're printing using standard I/O routines
|
||||
and `petsciiscr` for strings you're copying to screen memory directly.
|
||||
|
||||
When programming for Atari,
|
||||
use `atascii` for strings you're printing using standard I/O routines
|
||||
and `atasciiscr` for strings you're copying to screen memory directly.
|
||||
|
||||
### Escape sequences
|
||||
|
||||
|
@ -71,8 +152,6 @@ Some escape sequences may expand to multiple characters. For example, in several
|
|||
|
||||
##### Available everywhere
|
||||
|
||||
* `{q}` – double quote symbol
|
||||
|
||||
* `{x00}`–`{xff}` – a character of the given hexadecimal value
|
||||
|
||||
* `{copyright_year}` – this expands to the current year in digits
|
||||
|
@ -88,13 +167,19 @@ 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
|
||||
|
||||
* `{apos}` – apostrophe/single quote (available everywhere except for `zx80` and `zx81`)
|
||||
* `{apos}` – apostrophe/single quote (available everywhere except for `zx80`, `zx81` and `galaksija`)
|
||||
|
||||
* `{q}` – double quote symbol (available everywhere except for `pokemon1*` encodings)
|
||||
|
||||
* `{n}` – new line
|
||||
|
||||
|
@ -105,19 +190,25 @@ The exact value of `{nullchar}` is encoding-dependent:
|
|||
* `{up}`, `{down}`, `{left}`, `{right}` – control codes for moving the cursor
|
||||
|
||||
* `{white}`, `{black}`, `{red}`, `{green}`, `{blue}`, `{cyan}`, `{yellow}`, `{purple}` –
|
||||
control codes for changing the text color
|
||||
control codes for changing the text color (`petscii`, `petsciijp`, `sinclair` only)
|
||||
|
||||
* `{bgwhite}`, `{bgblack}`, `{bgred}`, `{bggreen}`, `{bgblue}`, `{bgcyan}`, `{bgyellow}`, `{bgpurple}` –
|
||||
control codes for changing the text background color
|
||||
control codes for changing the text background color (`sinclair` only)
|
||||
|
||||
* `{reverse}`, `{reverseoff}` – inverted mode on/off
|
||||
|
||||
* `{yen}`, `{pound}`, `{cent}`, `{euro}`, `{copy}` – yen symbol, pound symbol, cent symbol, euro symbol, copyright symbol
|
||||
|
||||
* `{nbsp}`, `{shy}` – non-breaking space, soft hyphen
|
||||
|
||||
* `{pi}` – letter π
|
||||
|
||||
* `{u0000}`–`{u1fffff}` – Unicode codepoint (available in UTF encodings only)
|
||||
|
||||
##### Character availability
|
||||
|
||||
For ISO/DOS/Windows/UTF encodings, consult external sources.
|
||||
|
||||
Encoding | lowercase letters | backslash | currencies | intl | card suits
|
||||
---------|-------------------|-----------|------------|------|-----------
|
||||
`pet`, | yes¹ | no | £ | none | yes¹
|
||||
|
@ -126,20 +217,32 @@ 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
|
||||
`iso15` | yes | yes | €¢£¥ | Western | 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
|
||||
`koi7n2` | no | yes | | Russian⁵ | no
|
||||
`koi8*` | yes | yes | | Russian | no
|
||||
`cpc_en` | yes | yes | £ | none | yes
|
||||
`cpc_es` | yes | yes | | Spanish⁶ | yes
|
||||
`cpc_fr` | yes | no | £ | French⁷ | yes
|
||||
`cpc_da` | yes | no | £ | Nor/Dan. | yes
|
||||
`vectrex` | no | yes | | none | no
|
||||
`utf*` | yes | yes | all | all | yes
|
||||
all the rest | yes | yes | | none | no
|
||||
`coco`,`cocoscr` | no | yes | | none | no
|
||||
`pokemon1jp` | no | no | | both kana | no
|
||||
`pokemon1en` | yes | no | | none | no
|
||||
`pokemon1fr` | yes | no | | Ger/Fre. | no
|
||||
`pokemon1es` | yes | no | | Spa/Ita. | no
|
||||
`galaksija` | no | no | | Yugoslav⁸ | no
|
||||
|
||||
1. `pet`, `origpet` and `petscr` cannot display card suit symbols and lowercase letters at the same time.
|
||||
Card suit symbols are only available in graphics mode,
|
||||
|
@ -155,6 +258,12 @@ Card suit symbols are only available in graphics mode, in which katakana is disp
|
|||
|
||||
5. Only uppercase. Letters **Ё** and **Ъ** are not available.
|
||||
|
||||
6. No accented vowels.
|
||||
|
||||
7. Some accented vowels are not available.
|
||||
|
||||
8. Letter **Đ** is not available.
|
||||
|
||||
If the encoding does not support lowercase letters (e.g. `apple2`, `petjp`, `petscrjp`, `koi7n2`, `vectrex`),
|
||||
then text and character literals containing lowercase letters are automatically converted to uppercase.
|
||||
Only unaccented Latin and Cyrillic letters will be converted as such.
|
||||
|
@ -163,21 +272,30 @@ To detect if your default encoding does not support lowercase letters, test `'A'
|
|||
|
||||
##### Escape sequence availability
|
||||
|
||||
The table below may be incomplete.
|
||||
|
||||
Encoding | new line | braces | backspace | cursor movement | text colour | reverse | background colour
|
||||
---------|----------|--------|-----------|-----------------|-------------|---------|------------------
|
||||
`pet`,`petjp` | yes | no | no | yes | yes | yes | no
|
||||
`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
|
||||
`iso15` | yes | yes | yes | no | no | no | no
|
||||
`iso8869_*`, `cp*` | yes | yes | yes | no | no | no | no
|
||||
`apple2` | no | yes | no | no | no | no | no
|
||||
`apple2` | no | no | no | no | no | no | no
|
||||
`apple2e` | no | yes | no | no | no | no | no
|
||||
`apple2gs` | no | yes | no | no | no | no | no
|
||||
`atascii` | yes | no | yes | yes | no | no | no
|
||||
`atasciiscr` | no | no | no | no | no | no | no
|
||||
`msx_*` | yes | yes | yes | yes | no | no | no
|
||||
`koi7n2` | yes | no | yes | no | no | no | no
|
||||
`koi8*` | yes | yes | yes | no | no | no | no
|
||||
`vectrex` | no | no | no | no | no | no | no
|
||||
`coco` | yes | no | yes | no | no | no | no
|
||||
`cocoscr` | no | no | no | no | no | no | no
|
||||
`utf*` | yes | yes | yes | no | no | no | no
|
||||
all the rest | yes | yes | no | no | no | no | no
|
||||
|
|
|
@ -20,11 +20,15 @@ Millfork puts extra limitations on which types can be used in which contexts.
|
|||
* `long` – 4-byte value of undefined signedness, defaulting to unsigned
|
||||
(alias: `int32`)
|
||||
|
||||
* `int40`, `int48`,... `int128` – even larger unsigned types
|
||||
* `int40`, `int48`,... `int128` – even larger types of undefined signedness, defaulting to unsigned
|
||||
|
||||
* `sbyte` – signed 1-byte value
|
||||
* `sbyte` – signed 1-byte value (alias: `signed8`)
|
||||
|
||||
* `ubyte` – unsigned 1-byte value
|
||||
* `ubyte` – unsigned 1-byte value (alias: `unsigned8`)
|
||||
|
||||
* `signed16` – signed 2-byte value (experimental)
|
||||
|
||||
* `unsigned16` – unsigned 2-byte value (experimental)
|
||||
|
||||
* `pointer` – raw pointers; the same as `word`, but variables of this type default to be zero-page-allocated
|
||||
and you can index `pointer`-typed expressions.
|
||||
|
@ -65,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`.
|
||||
|
@ -78,6 +90,8 @@ You can create pointer values by suffixing `.pointer` to the name of a variable,
|
|||
|
||||
You can replace C-style pointer arithmetic by combining indexing and `.pointer`: C `p+5`, Millfork `p[5].pointer`.
|
||||
|
||||
You can use the typed pointer as a raw pointer by suffixing `.raw`.
|
||||
|
||||
Examples:
|
||||
|
||||
pointer.t p
|
||||
|
@ -89,6 +103,7 @@ Examples:
|
|||
p[i] // accessing the ith element; if 'sizeof(t) == 1', then equivalent to 't(p.raw[i])'
|
||||
p->x // valid only if the type 't' has a field called 'x', accesses the field 'x' of the pointed element
|
||||
p->x.y[0]->z[0][6] // you can stack it
|
||||
p.raw += sizeof(t) // if p points to an element of an array, then advances it to the next element
|
||||
|
||||
## `nullptr`
|
||||
|
||||
|
@ -119,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:
|
||||
|
||||
|
@ -139,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
|
||||
|
@ -215,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> { <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.
|
||||
|
||||
|
@ -247,9 +301,36 @@ You can create constant expressions of struct types using so-called struct const
|
|||
|
||||
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 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 }
|
||||
array(a) as [4] @ $C000
|
||||
array(b) bs [4] @ $C800
|
||||
|
||||
a[1].addr - a[0].addr // equals 4
|
||||
b[1].addr - b[0].addr // equals 3
|
||||
sizeof(a) // equals 16
|
||||
sizeof(b) // equals 12
|
||||
|
||||
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> { <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.
|
||||
|
@ -265,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
91
docs/stdlib/apple2.md
Normal 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`.
|
|
@ -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
|
||||
|
@ -22,7 +22,7 @@ TODO
|
|||
|
||||
## c1531
|
||||
|
||||
The `c1531` module implements a Commodore 1531 proportional mouse driver compatible with the `mouse` module.
|
||||
The `c1531` module implements a Commodore 1531 proportional mouse driver compatible with the [`mouse` module](./mouse.md).
|
||||
|
||||
#### `void c1531_mouse()`
|
||||
|
||||
|
@ -36,7 +36,7 @@ Defines the `c1531` module as the default module for reading mouse input.
|
|||
|
||||
## c64_joy
|
||||
|
||||
The `c64_joy` module implements a joystick driver compatible with the `joy` module.
|
||||
The `c64_joy` module implements a joystick driver compatible with the [`joy` module](./joy.md).
|
||||
|
||||
#### `void read_joy2()`
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
26
docs/stdlib/cbm_pet.md
Normal file
26
docs/stdlib/cbm_pet.md
Normal file
|
@ -0,0 +1,26 @@
|
|||
[< back to index](../doc_index.md)
|
||||
|
||||
# Commodore PET-oriented modules
|
||||
|
||||
## pet_kernal module
|
||||
|
||||
The `pet_kernal` module is imported automatically on the PET target.
|
||||
It provides access to Kernal routines.
|
||||
|
||||
TODO
|
||||
|
||||
|
||||
#### asm set_zero is_pet2000()
|
||||
|
||||
Returns true if the current machine has the original ROM (usually, the PET 2000 series).
|
||||
When calling from assembly, the result is stored in the Z flag.
|
||||
|
||||
#### asm set_zero is_pet3000()
|
||||
|
||||
Returns true if the current machine has the upgraded ROM (usually, the PET 3000 series).
|
||||
When calling from assembly, the result is stored in the Z flag.
|
||||
|
||||
#### asm set_zero is_pet4000()
|
||||
|
||||
Returns true if the current machine has the 4.0 ROM (usually, the PET 4000 series).
|
||||
When calling from assembly, the result is stored in the Z flag.
|
|
@ -31,6 +31,8 @@ Available only if one of the following is true:
|
|||
|
||||
* the default encoding is `atascii`, the screen encoding is `atasciiscr`, and the platform is 6502-based
|
||||
|
||||
* the default encoding is `coco`, the screen encoding is `cococsr`, and the platform is 6809-based
|
||||
|
||||
You can test for the availability of this function using the `ENCCONV_SUPPORTED` preprocessor feature.
|
||||
|
||||
#### byte from_screencode(byte)
|
||||
|
@ -53,6 +55,18 @@ Destructively converts a null-terminated string from the `scr` encoding into the
|
|||
|
||||
Available only if `from_screencode` is available.
|
||||
|
||||
#### void pstr_to_screencode(pointer)
|
||||
|
||||
Destructively converts a length-prefixed string from the `default` encoding into the `scr` encoding.
|
||||
|
||||
Available only if `to_screencode` is available.
|
||||
|
||||
#### void pstr_from_screencode(pointer)
|
||||
|
||||
Destructively converts a length-prefixed string from the `scr` encoding into the `default` encoding.
|
||||
|
||||
Available only if `from_screencode` is available.
|
||||
|
||||
#### byte petscii_to_petscr(byte)
|
||||
|
||||
Converts a byte from PETSCII to a CBM screencode.
|
||||
|
@ -71,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.
|
||||
|
||||
|
@ -79,10 +93,24 @@ 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.
|
||||
|
||||
Available only on 6502-based platforms.
|
||||
|
||||
#### byte coco_to_cocoscr(byte)
|
||||
|
||||
Converts a byte from Color Computer pseudo-ASCII to a Color Computer screencode.
|
||||
Control characters <$20 are converted inverted punctuation.
|
||||
|
||||
Available only on 6809-based platforms.
|
||||
|
||||
#### byte cocoscr_to_coco(byte)
|
||||
|
||||
Converts a byte from a Color Computer screencode to Color Computer pseudo-ASCII.
|
||||
Inverted punctuation is converted to control characters.
|
||||
|
||||
Available only on 6809-based platforms.
|
||||
|
||||
|
|
|
@ -48,8 +48,12 @@ Available for:
|
|||
ZX Spectrum,
|
||||
NEC PC-88,
|
||||
MSX,
|
||||
Commodore 64 with `c64_basic` module (requires KERNAL and BASIC),
|
||||
Commodore 16 or Plus/4 with `c264_basic` module (requires KERNAL and BASIC).
|
||||
Apple II,
|
||||
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()`
|
||||
|
||||
|
@ -59,6 +63,10 @@ Available for:
|
|||
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).
|
||||
|
||||
|
@ -87,11 +95,6 @@ Various colour constants.
|
|||
|
||||
Available for: VIC-20, C64, C128, C264 series, ZX Spectrum.
|
||||
|
||||
#### `macro void memory_barrier()`
|
||||
|
||||
Informs the optimizer that at this point arbitrary memory has been accessed and either read or written by an external device.
|
||||
The optimizer should not optimize any memory accesses across that macro.
|
||||
|
||||
Available for: all targets.
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ It contains the default header for 32K Game Boy programs.
|
|||
|
||||
## gb_joy
|
||||
|
||||
Provides an interface for reading joypads that is compatible with the `joy` module.
|
||||
Provides an interface for reading joypads that is compatible with the [`joy` module](./joy.md).
|
||||
|
||||
#### `alias input_a = input_btn`
|
||||
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
[< back to index](../doc_index.md)
|
||||
|
||||
## joy
|
||||
|
||||
The module contains global variables representing the state of the one-button joystick.
|
||||
If the program is not using any joystick driver, the state of these variables is undefined.
|
||||
|
||||
To actually use this module, an appropriate joystick module must be used, such as `c64_joy`, `nes_joy` or `gb_joy`.
|
||||
|
||||
#### `sbyte input_dx`
|
||||
|
||||
Horizontal joystick movement. 1 if right, -1 if left, 0 if neither.
|
||||
|
||||
#### `sbyte input_dy`
|
||||
|
||||
Vertical joystick movement. 1 if down, -1 if up, 0 if neither.
|
||||
|
||||
#### `byte input_btn`
|
||||
|
||||
1 if main button pressed, 0 if not pressed.
|
||||
|
||||
#### `void reset_joy()`
|
||||
|
||||
Resets the state variables.
|
||||
The default implementation resets only the main button.
|
||||
May be overridden by a strong alias on some platforms that have more buttons.
|
||||
|
||||
## null_joy_default
|
||||
|
||||
This module set the default joystick to no joystick.
|
||||
|
||||
#### `alias read_joy`
|
||||
|
||||
A reserved name for reading the default joystick.
|
||||
|
||||
## mouse
|
||||
|
||||
The `mouse` module automatically imports the `x_coord` module.
|
||||
|
||||
The module contains global variables representing the state of the mouse.
|
||||
If the program is not using any mouse driver, the state of these variables is undefined.
|
||||
|
||||
To actually use this module, an appropriate mouse module must be used, such as `c1531`.
|
||||
|
||||
#### `x_coord mouse_x`
|
||||
|
||||
Mouse X position.
|
||||
|
||||
#### `byte mouse_y`
|
||||
|
||||
Mouse Y position.
|
||||
|
||||
#### `byte mouse_lbm`
|
||||
|
||||
1 if the left mouse button is being pressed, 0 otherwise
|
||||
|
||||
#### `byte mouse_rbm`
|
||||
|
||||
1 if the right mouse button is being pressed, 0 otherwise
|
||||
|
||||
## `x_coord` module
|
||||
|
||||
#### `alias x_coord`
|
||||
|
||||
The type for representing horizontal screen coordinates.
|
||||
It's `byte` if the screen is 256 pixels wide or less,
|
||||
or `word` if the screen is more that 256 pixels wide.
|
||||
|
||||
## null_mouse_default
|
||||
|
||||
This module set the default mouse to no mouse.
|
||||
|
||||
#### `void read_mouse()`
|
35
docs/stdlib/joy.md
Normal file
35
docs/stdlib/joy.md
Normal file
|
@ -0,0 +1,35 @@
|
|||
[< back to index](../doc_index.md)
|
||||
|
||||
## joy
|
||||
|
||||
The module contains global variables representing the state of the one-button joystick.
|
||||
If the program is not using any joystick driver, the state of these variables is undefined.
|
||||
|
||||
To actually use this module, an appropriate joystick module must be used,
|
||||
such as [`c64_joy`](./c64.md), [`nes_joy`](./nes.md), [`gb_joy`](./gb.md) or [`x16_joy`](./x16.md).
|
||||
|
||||
#### `sbyte input_dx`
|
||||
|
||||
Horizontal joystick movement. 1 if right, -1 if left, 0 if neither.
|
||||
|
||||
#### `sbyte input_dy`
|
||||
|
||||
Vertical joystick movement. 1 if down, -1 if up, 0 if neither.
|
||||
|
||||
#### `byte input_btn`
|
||||
|
||||
1 if main button pressed, 0 if not pressed.
|
||||
|
||||
#### `void reset_joy()`
|
||||
|
||||
Resets the state variables.
|
||||
The default implementation resets only the main button.
|
||||
May be overridden by a strong alias on some platforms that have more buttons.
|
||||
|
||||
## null_joy_default
|
||||
|
||||
This module set the default joystick to no joystick.
|
||||
|
||||
#### `alias read_joy`
|
||||
|
||||
A reserved name for reading the default joystick.
|
37
docs/stdlib/keyboard.md
Normal file
37
docs/stdlib/keyboard.md
Normal file
|
@ -0,0 +1,37 @@
|
|||
[< back to index](../doc_index.md)
|
||||
|
||||
## keyboard
|
||||
|
||||
The `keyboard` module provides support for reading keypresses from the keyboard.
|
||||
Not supported on all targets.
|
||||
|
||||
For reading entire lines of text from the keyboard, see the `readline` and `readword` functions
|
||||
in [the frequently provided definitions](./frequent.md).
|
||||
|
||||
#### `byte readkey()`
|
||||
|
||||
Waits for and reads a single keypress.
|
||||
|
||||
The returning values may vary between platforms:
|
||||
|
||||
* letters may be uppercase or lowercase
|
||||
|
||||
* modifier keys may be applied or ignored
|
||||
|
||||
Available for:
|
||||
Commodore 64 (requires KERNAL),
|
||||
Commodore 16 or Plus/4 (requires KERNAL),
|
||||
Commodore 128 (requires KERNAL),
|
||||
Commodore PET (requires KERNAL),
|
||||
VIC 20 (requires KERNAL),
|
||||
Atari,
|
||||
Amstrad CPC,
|
||||
ZX Spectrum,
|
||||
NEC PC-88,
|
||||
Robotron Z1013,
|
||||
TRS-80,
|
||||
Tandy Color Computer.
|
||||
|
||||
#### `const byte KEY_ENTER`
|
||||
|
||||
Key code for the Enter/Return key. Usually 13, but not always.
|
|
@ -4,9 +4,9 @@
|
|||
|
||||
## atari_lynx_hardware
|
||||
|
||||
The `atari_lynx_hardware` module is imported automatically on NES targets.
|
||||
The `atari_lynx_hardware` module is imported automatically on Atari Lynx targets.
|
||||
|
||||
It also implements a joystick API compatible with the `joy` module.
|
||||
It also implements a joystick API compatible with the [`joy` module](./joy.md).
|
||||
|
||||
TODO
|
||||
|
||||
|
|
52
docs/stdlib/mouse.md
Normal file
52
docs/stdlib/mouse.md
Normal file
|
@ -0,0 +1,52 @@
|
|||
[< back to index](../doc_index.md)
|
||||
|
||||
## mouse
|
||||
|
||||
The `mouse` module automatically imports the `coord` module.
|
||||
|
||||
The module contains global variables representing the state of the mouse.
|
||||
If the program is not using any mouse driver, the state of these variables is undefined.
|
||||
|
||||
To actually use this module, an appropriate mouse module must be used, such as [`c1531`](./c64.md).
|
||||
|
||||
#### `x_coord mouse_x`
|
||||
|
||||
Mouse X position.
|
||||
|
||||
#### `y_coord mouse_y`
|
||||
|
||||
Mouse Y position.
|
||||
|
||||
#### `bool mouse_lbm`
|
||||
|
||||
`true` if the left mouse button is being pressed, `false` otherwise
|
||||
|
||||
#### `byte mouse_mbm`
|
||||
|
||||
`true` if the middle mouse button is being pressed, `false` otherwise.
|
||||
Available only if `USE_MOUSE_MBM` is set and non-zero.
|
||||
|
||||
#### `byte mouse_rbm`
|
||||
|
||||
`true` if the right mouse button is being pressed, `false` otherwise
|
||||
|
||||
## coord
|
||||
|
||||
#### `alias x_coord`
|
||||
|
||||
The type for representing horizontal screen coordinates.
|
||||
It's `byte` if the screen is 256 pixels wide or less,
|
||||
or `word` if the screen is more that 256 pixels wide.
|
||||
|
||||
#### `alias y_coord`
|
||||
|
||||
The type for representing vertical screen coordinates.
|
||||
It's `byte` if the screen is 256 pixels tall or less,
|
||||
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 cursor is fixed at coordinates (0,0).
|
||||
|
||||
#### `void read_mouse()`
|
|
@ -26,7 +26,7 @@ Available variables:
|
|||
|
||||
#### `byte strobe_joypad()`
|
||||
|
||||
Updates joypad1 by querying for new button states.
|
||||
Strobes joypads in preparation for reading new joypad states.
|
||||
|
||||
#### `byte read_joypad1()`
|
||||
|
||||
|
@ -41,7 +41,7 @@ Get joypad2's state as a byte.
|
|||
Simulates a hardware reset by jumping to the reset vector,
|
||||
which then calls main().
|
||||
|
||||
#### `void ppu_set_addr(word ax)`
|
||||
#### `void ppu_set_addr(word register(ax) address)`
|
||||
|
||||
Sets the PPU to point at the VRAM address at ax, usually in preparation
|
||||
for a write via ppu_write_data().
|
||||
|
@ -50,18 +50,18 @@ for a write via ppu_write_data().
|
|||
|
||||
Gets the PPU status byte.
|
||||
|
||||
#### `void ppu_set_scroll(byte a, byte x)`
|
||||
#### `void ppu_set_scroll(byte register(a) xscroll, byte register(x) yscroll)`
|
||||
|
||||
Sets the PPU scroll register. Parameter a defines the horizontal
|
||||
(X-axis) scroll value, and parameter x defines the vertical (Y-axis)
|
||||
scroll value.
|
||||
|
||||
#### `void ppu_write_data(byte a)`
|
||||
#### `void ppu_write_data(byte register(a) data)`
|
||||
|
||||
Writes a byte to the PPU's VRAM at the address the PPU
|
||||
is currently pointing to. Usually used after a call to ppu_set_addr().
|
||||
|
||||
#### `void ppu_oam_dma_write(byte a)`
|
||||
#### `void ppu_oam_dma_write(byte register(a) page)`
|
||||
|
||||
Initiates a DMA transfer of 256 bytes from CPU memory address $xx00-$xxFF
|
||||
to PPU OAM memory, where xx is the hexadecimal representation of parameter a.
|
||||
|
@ -71,18 +71,18 @@ to PPU OAM memory, where xx is the hexadecimal representation of parameter a.
|
|||
The `nes_mmc4` module is imported automatically on the NES MMC4 target
|
||||
and contains routines related to MMC4 bankswitching.
|
||||
|
||||
#### `void set_prg_bank(byte a)`
|
||||
#### `void set_prg_bank(byte register(a) bank)`
|
||||
|
||||
Changes the $8000-$BFFF PRG bank.
|
||||
|
||||
#### `void set_chr_bank0(byte a)`
|
||||
#### `void set_chr_bank0(byte register(a) bank)`
|
||||
|
||||
Changes the CHR bank 0 ($0000-$0fff in the PPU memory space).
|
||||
|
||||
The high nibble (0 or 1) selects between `chrrom0` and `chrrom1` segments.
|
||||
The low nibble L (0-$F) selects a 4K-aligned address in the segment ($L000).
|
||||
|
||||
#### `void set_chr_bank1(byte a)`
|
||||
#### `void set_chr_bank1(byte register(a) bank)`
|
||||
|
||||
Changes the CHR bank 1 ($1000-$1fff in the PPU memory space).
|
||||
|
||||
|
@ -99,23 +99,23 @@ Switches nametable mirroring to horizontal.
|
|||
|
||||
## nes_joy
|
||||
|
||||
Provides an interface for reading joypads that is compatible with the `joy` module.
|
||||
Provides an interface for reading joypads that is compatible with the [`joy` module](./joy.md).
|
||||
|
||||
#### `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()`
|
||||
|
||||
|
|
|
@ -1,34 +1,5 @@
|
|||
[< back to index](../doc_index.md)
|
||||
|
||||
## keyboard
|
||||
|
||||
The `keyboard` module provides support for reading keypresses from the keyboard.
|
||||
Not supported on all targets.
|
||||
|
||||
#### `byte readkey()`
|
||||
|
||||
Waits for and reads a single keypress.
|
||||
|
||||
The returning values may vary between platforms:
|
||||
|
||||
* letters may be uppercase or lowercase
|
||||
|
||||
* modifier keys may be applied or ignored
|
||||
|
||||
Available for:
|
||||
Commodore 64 (requires KERNAL),
|
||||
Commodore 16 or Plus/4 (requires KERNAL),
|
||||
Commodore 128 (requires KERNAL),
|
||||
VIC 20 (requires KERNAL),
|
||||
Atari,
|
||||
Amstrad CPC,
|
||||
ZX Spectrum,
|
||||
NEC PC-88.
|
||||
|
||||
#### `const byte KEY_ENTER`
|
||||
|
||||
Key code for the Enter/Return key. Usually 13, but not always.
|
||||
|
||||
## err
|
||||
|
||||
#### `enum error_number`
|
||||
|
@ -61,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.
|
||||
|
|
|
@ -3,9 +3,12 @@
|
|||
## stdio
|
||||
|
||||
The `stdio` module automatically imports the `string` and `err` modules.
|
||||
It requires an implementation of `void putchar(byte a)` and therefore works only on targets with console output.
|
||||
It requires an implementation of `void putchar(byte a)` and therefore works only on targets with console output
|
||||
(see [the frequently provided definitions](./frequent.md) for details).
|
||||
On targets with idiosyncratic behaviour of `putchar`, functions in this module inherit that behaviour.
|
||||
|
||||
All strings are assumed to be in the default encoding.
|
||||
|
||||
#### `void putstr(pointer str, byte len)`
|
||||
|
||||
Prints a string of length `len` located at address `str`.
|
||||
|
@ -15,11 +18,20 @@ Prints a string of length `len` located at address `str`.
|
|||
Prints a null-terminated string located at address `str`.
|
||||
If the string is longer than 255 bytes, then the behaviour is undefined (might even crash).
|
||||
|
||||
#### `void putpstr(pointer pstr)`
|
||||
|
||||
Prints a length-prefixed string located at address `str`.
|
||||
|
||||
#### `void putword(word w)`
|
||||
|
||||
Prints the decimal representation of the 16-bit unsigned integer `w`.
|
||||
|
||||
#### `void putsigned16(signed16 x)`
|
||||
|
||||
Prints the decimal representation of the 16-bit signed integer `x`.
|
||||
|
||||
#### `void ensure_mixedcase()`
|
||||
|
||||
On targets that have separate all-caps and mixed-case modes (like most Commodore machines), switches to the mixed-case mode.
|
||||
On targets that have separate all-caps and mixed-case modes (like most Commodore machines), switches to the mixed-case mode.
|
||||
On the remaining platforms, does nothing.
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
The `stdlib` module is automatically imported on most targets.
|
||||
|
||||
#### `macro asm void poke(word const addr, byte a)`
|
||||
#### `macro asm void poke(word const addr, byte register(a) value)`
|
||||
|
||||
Stores a byte at given constant address. Will not be optimized away by the optimizer.
|
||||
|
||||
|
@ -20,14 +20,32 @@ Disables interrupts.
|
|||
|
||||
Enables interrupts.
|
||||
|
||||
#### `byte hi_nibble_to_hex(byte a)`
|
||||
#### `byte hi_nibble_to_hex(byte register(a) value)`
|
||||
|
||||
Returns an ASCII representation of the upper nibble of the given byte.
|
||||
|
||||
#### `byte lo_nibble_to_hex(byte a)`
|
||||
#### `byte lo_nibble_to_hex(byte register(a) value)`
|
||||
|
||||
Returns an ASCII representation of the lower nibble of the given byte.
|
||||
|
||||
#### `macro asm void panic()`
|
||||
|
||||
Crashes the program.
|
||||
|
||||
## Standard macros available without any import
|
||||
|
||||
#### `macro void memory_barrier()`
|
||||
|
||||
Informs the optimizer that at this point arbitrary memory has been accessed and either read or written by an external device.
|
||||
The optimizer should not optimize any memory accesses across that macro.
|
||||
|
||||
Available for: all targets.
|
||||
|
||||
#### `macro void breakpoint()`
|
||||
|
||||
If the `-fbreakpoints` option is selected (default), then it emits a memory barrier,
|
||||
and also outputs a breakpoint to the label file (if the format of the label file allows it).
|
||||
|
||||
If the `-fno-breakpoints` option is selected, then it does nothing.
|
||||
|
||||
Available for: all targets.
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
## string
|
||||
|
||||
The `string` module automatically imports the `err` module.
|
||||
The `string` module automatically imports the [`err` module](./other.md).
|
||||
|
||||
All the functions are designed to work for the strings in the default encoding.
|
||||
If passed a string in an encoding that has a different null terminator,
|
||||
|
@ -40,7 +40,7 @@ Modifies the given null-terminated buffer by appending a null-terminated string
|
|||
|
||||
## scrstring
|
||||
|
||||
The `scrstring` module automatically imports the `string` and `err` modules.
|
||||
The `scrstring` module automatically imports the `string` and [`err`](./other.md) modules.
|
||||
|
||||
It contains functions for handling strings in the screen encoding with the same semantics as the functions from the string module.
|
||||
|
||||
|
@ -51,3 +51,25 @@ It contains functions for handling strings in the screen encoding with the same
|
|||
#### `word scrstrz2word(pointer str)`
|
||||
#### `void scrstrzappend(pointer buffer, pointer str)`
|
||||
#### `void scrstrzappendchar(pointer buffer, byte char)`
|
||||
|
||||
## pstring
|
||||
|
||||
The `pstring` module automatically imports the [`err` module](./other.md).
|
||||
|
||||
It contains functions for handling length-prefixed strings in any 8-bit encoding.
|
||||
|
||||
#### `byte pstrlen(pointer str)`
|
||||
#### `sbyte pstrcmp(pointer str1, pointer str2)`
|
||||
#### `void pstrcopy(pointer dest, pointer src)`
|
||||
#### `void pstrpaste(pointer dest, pointer src)`
|
||||
#### `void pstrappend(pointer buffer, pointer str)`
|
||||
#### `void pstrappendchar(pointer buffer, byte char)`
|
||||
#### `word pstr2word(pointer str)`
|
||||
|
||||
Converts a length-prefixed string to a number. Uses the default encoding.
|
||||
Sets `errno`.
|
||||
|
||||
#### `word pscrstr2word(pointer str)`
|
||||
|
||||
Converts a length-prefixed string to a number. Uses the screen encoding.
|
||||
Sets `errno`.
|
||||
|
|
21
docs/stdlib/vic20.md
Normal file
21
docs/stdlib/vic20.md
Normal 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
|
|
@ -3,15 +3,22 @@
|
|||
# Commander X16-oriented modules
|
||||
|
||||
**WARNING!** Commander X16 is not yet a finalised design.
|
||||
Therefore, both the device itself and the modules for its support may change at any moment.
|
||||
Therefore, both the device itself and the modules for its support may change at any moment.
|
||||
The X16-oriented modules may be out of date and not support the current design of the device.
|
||||
|
||||
## x16_kernal module
|
||||
## x16_kernal
|
||||
|
||||
The `x16_kernal` module is imported automatically on the X16 target.
|
||||
|
||||
Currently, it automatically imports the [`c64_kernal` module](./c64.md).
|
||||
|
||||
## `x16_hardware` module
|
||||
#### `void mouse_config(byte register(a) enable, byte register(x) scale)`
|
||||
|
||||
Configures the mouse pointer.
|
||||
`enable` should be `1` to enable, `0` to disable and `$ff` to enable without reconfiguration.
|
||||
`scale` should be `1` on 640×480 screens, `2` on 320×240 screens, and `0` to keep the current scale.
|
||||
|
||||
## x16_hardware
|
||||
|
||||
The `x16_hardware` module is imported automatically on the X16 target.
|
||||
|
||||
|
@ -42,7 +49,7 @@ Copies `size` bytes from the RAM at address `source` into the VERA memory space
|
|||
|
||||
#### `struct vera_layer_setup`
|
||||
|
||||
Hardware register values for a video layer:
|
||||
Hardware register values for a video layer. For VERA 0.7 and 0.8:
|
||||
|
||||
byte ctrl0
|
||||
byte ctrl1
|
||||
|
@ -50,14 +57,32 @@ Hardware register values for a video layer:
|
|||
word tile_base
|
||||
word hscroll
|
||||
word vscroll
|
||||
|
||||
For VERA 0.9:
|
||||
|
||||
byte config
|
||||
byte map_base
|
||||
byte tile_base
|
||||
word hscroll
|
||||
word vscroll
|
||||
|
||||
#### `void set_vera_layer1(pointer.vera_layer_setup)`
|
||||
|
||||
Sets up the layer 1.
|
||||
Sets up the layer 1. VERA 0.7 and 0.8 only.
|
||||
On VERA 0.9, use `vera_layer0` directly.
|
||||
|
||||
#### `void set_vera_layer2(pointer.vera_layer_setup)`
|
||||
|
||||
Sets up the layer 2.
|
||||
Sets up the layer 2. VERA 0.7 and 0.8 only.
|
||||
On VERA 0.9, use `vera_layer1` directly.
|
||||
|
||||
#### `vera_layer_setup vera_layer0`
|
||||
|
||||
Direct access to registers for the layer 0. VERA 0.9 only.
|
||||
|
||||
#### `vera_layer_setup vera_layer1`
|
||||
|
||||
Direct access to registers for the layer 1. VERA 0.9 only.
|
||||
|
||||
#### `struct vera_sprite_data`
|
||||
|
||||
|
@ -69,16 +94,35 @@ Hardware register values for a sprite:
|
|||
byte ctrl0
|
||||
byte ctrl1
|
||||
|
||||
#### `const int24 VERA_COMPOSER_CTRL`
|
||||
#### `void vera_upload_sprite(byte sprite_id, pointer.vera_sprite_data source)`
|
||||
|
||||
Uploads sprite data for given sprite id.
|
||||
|
||||
#### `const int24 VERA_PALETTE`
|
||||
#### `const int24 VERA_LAYER_1`
|
||||
#### `const int24 VERA_LAYER_2`
|
||||
#### `const int24 VERA_SPRITE_CTRL`
|
||||
#### `const int24 VERA_SPRITES`
|
||||
|
||||
Various addresses in the VERA memory space.
|
||||
|
||||
## `x16_joy` module
|
||||
#### `const int24 VERA_COMPOSER_CTRL`
|
||||
#### `const int24 VERA_LAYER_1`
|
||||
#### `const int24 VERA_LAYER_2`
|
||||
#### `const int24 VERA_SPRITE_CTRL`
|
||||
|
||||
Various addresses in the VERA memory space. VERA 0.7 and 0.8 only.
|
||||
|
||||
#### `void vera_reset()`
|
||||
|
||||
Resets the VERA.
|
||||
|
||||
#### `void vera_set_sprites_enable(bool enabled)`
|
||||
|
||||
Enables/disables sprites.
|
||||
|
||||
#### `void set_border(byte color)`
|
||||
|
||||
Changes the color of the border.
|
||||
|
||||
## x16_joy
|
||||
|
||||
The `x16_joy` module implements a joystick driver compatible with the `joy` module.
|
||||
|
||||
|
@ -117,6 +161,10 @@ Variable | SNES controller | NES controller | Keyboard (joy 1 only)
|
|||
|
||||
|
||||
`input_b` is an alias for `input_btn`. Single-button games should use `input_btn` for compatibility.
|
||||
|
||||
#### `x16_joy_type joy_type`
|
||||
|
||||
The type of the last read joystick. One of `joy_none`, `joy_nes`, `joy_snes`, `joy_keyboard`.
|
||||
|
||||
## x16_joy1_default module
|
||||
|
||||
|
@ -124,3 +172,12 @@ Defines the joystick in port 1 as the default joystick.
|
|||
|
||||
#### `alias read_joy = read_joy1`
|
||||
|
||||
## x16_mouse
|
||||
|
||||
The `x16_mouse` module implements a mouse driver compatible with the `mouse` module.
|
||||
|
||||
Before using this, you may want to call `mouse_config` from the `x16_kernal` module.
|
||||
|
||||
#### `void read_mouse()`
|
||||
|
||||
Reads the state of the mouse.
|
||||
|
|
36
docs/various/asmdiff.md
Normal file
36
docs/various/asmdiff.md
Normal file
|
@ -0,0 +1,36 @@
|
|||
[< back to index](../doc_index.md)
|
||||
|
||||
# Differences in assembly
|
||||
|
||||
## Syntax
|
||||
|
||||
* High and low bytes of an 16-bit value are acquired using the `hi` and `lo` functions, not the `>` and `<` operators.
|
||||
|
||||
* Anonymous labels and local labels are not supported.
|
||||
All labels defined in assembly are global.
|
||||
Colons are required in label declarations.
|
||||
|
||||
* Macros are inserted using the `+` operator.
|
||||
|
||||
* Raw bytes are inserted using the Millfork array syntax, not with any pseudoopcode (like `!byte`, `db` or `fcb`)
|
||||
|
||||
* Assembly blocks cannot contain definitions of constants or variables.
|
||||
|
||||
* 6502: To enforce zero-page addressing, wrap the argument in the `lo` function: `lo(arg)`
|
||||
|
||||
* 6502: To enforce absolute addressing, add a 16-bit zero to the argument: `0000 + arg`
|
||||
|
||||
* GameBoy: The $FF page loads/stores are written `LDH (C),A`, not `LD ($FF00+C),A`.
|
||||
|
||||
* GameBoy: The loads/stores that postincrement/postdecrement HL write the HL register as `HLI` or `HLD`, not `HL+` or `HL-`
|
||||
|
||||
* Z80: Indexing using the index register uses the `IX(1)` syntax, not `(IX+1)` or `1(IX)`.
|
||||
|
||||
* Z80: Most undocumented instructions are not supported. The only one supported is `SLL`.
|
||||
|
||||
* 6809: `0,X` is assembled the same as `,X`.
|
||||
|
||||
* 6502: To enforce direct-page addressing, prepend the argument with `<`: `<arg`.
|
||||
|
||||
|
||||
|
80
docs/various/cdiff.md
Normal file
80
docs/various/cdiff.md
Normal file
|
@ -0,0 +1,80 @@
|
|||
[< back to index](../doc_index.md)
|
||||
|
||||
# Differences from C
|
||||
|
||||
## Syntax
|
||||
|
||||
* Block comments `/* */` are not supported, use line comments `//`.
|
||||
|
||||
* You cannot put multiple statements on one line.
|
||||
Semicolons are allowed at the end of the line, but no code can follow them.
|
||||
|
||||
* There are no `++` or `--` operators. Use `+= 1` and `-= 1`.
|
||||
|
||||
* Pointer types are declared using the `pointer.` prefix, not `*` suffix. To dereference them, use `p[0]` instead of `*p`.
|
||||
|
||||
* There is no unary `&` operator.
|
||||
Pointers to an object are acquired using the `.pointer` suffix.
|
||||
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 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.
|
||||
|
||||
* There is no `!` operator. The negation is expressed as the `not` function.
|
||||
|
||||
* The modulo operator is written `%%`. As with `/`, it's only defined for unsigned division.
|
||||
|
||||
* The `for` loops are range-based. Arbitrary, C-like `for` loops are not supported.
|
||||
|
||||
* Variable declaration and initialization have to be separate.
|
||||
|
||||
* 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.
|
||||
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.
|
||||
|
||||
* There has to be a space between many operators and character literals,
|
||||
as the parser may treat the apostrophe as a part of the operator.
|
||||
|
||||
## Preprocessor
|
||||
|
||||
* The preprocessor cannot expand symbols to something more complex than an identifier or a literal.
|
||||
|
||||
* The preprocessor cannot define symbols for use in other files.
|
||||
|
||||
* The closest to C's `#define` is `#use`.
|
||||
Unlike `#define`, such definitions are not visible within the preprocessor.
|
||||
|
||||
* Directives like `#use` and `#pragma` affect the entire file, not just the code after the directive.
|
||||
|
||||
* The preprocessor cannot include files.
|
||||
|
||||
## Semantics
|
||||
|
||||
* There is no automatic integer promotion. An operation of two bytes will yield a byte. For example:
|
||||
|
||||
byte a
|
||||
byte b
|
||||
word w
|
||||
w = a * b
|
||||
|
||||
may yield unexpected results. To prevent this, cast at least one argument:
|
||||
|
||||
w = word(a) * b
|
||||
|
||||
This issue applies mostly to the `*` and `<<` operators.
|
||||
|
||||
* There is no padding in structs, except before fields whose type is a struct or a union with a non-trivial alignment.
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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?
|
||||
|
@ -83,6 +83,10 @@ or generate a static binary and link it manually using the `file` directive.
|
|||
|
||||
Since the compiler is a work-in-progress, some of the mentioned issues might be improved upon in the future.
|
||||
|
||||
### I have experience with C and/or assembly. What should I keep in mind?
|
||||
|
||||
See the [differences from C](./cdiff.md) and the [differences from assembly](./asmdiff.md).
|
||||
|
||||
### Why is it called Millfork?
|
||||
|
||||
It stands for **MI**ddle **L**evel **L**anguage **FOR** **K**ommodore computers.
|
||||
|
|
107
docs/various/optimization.md
Normal file
107
docs/various/optimization.md
Normal file
|
@ -0,0 +1,107 @@
|
|||
[< back to index](../doc_index.md)
|
||||
|
||||
# Optimization guidelines
|
||||
|
||||
## Command-line options
|
||||
|
||||
* The default options provide literally no optimizations.
|
||||
Consider using at least `-O1` for quick compilation and `-O4` for release builds.
|
||||
|
||||
* Inlining can drastically improve performance. Add `-finline` to the command line.
|
||||
|
||||
* If you're not using self-modifying code or code generation,
|
||||
enabling interprocedural optimizations (`-fipo`) and stdlib optimizations (`-foptimize-stdlib`) can also help.
|
||||
|
||||
* For convenience, all options useful for debug builds can be enabled with `-Xd`,
|
||||
and for release builds with `-Xr`.
|
||||
|
||||
* 6502 only: If you are sure the target will have a CPU that supports so-called illegal/undocumented 6502 instructions,
|
||||
consider adding the `-fillegals` option. Good examples of such targets are NES and C64.
|
||||
|
||||
## Alignment
|
||||
|
||||
* Consider adding `align(fast)` or even `align(256)` to arrays which you want to access quickly.
|
||||
|
||||
* 6502 only: Consider adding `align(fast)` to the hottest functions.
|
||||
|
||||
* If you have an array of structs, consider adding `align(X)` to the definition of the struct,
|
||||
where `X` is a power of two. Even if this makes the struct 12 bytes instead of 11, it can still improve performance.
|
||||
|
||||
## Variables
|
||||
|
||||
* Use the smallest type you need. Note that Millfork supports integers of any size from 1 to 16 bytes.
|
||||
|
||||
* Consider using multiple arrays instead of arrays of structs.
|
||||
|
||||
* Avoid reusing temporary variables.
|
||||
It makes it easier for the optimizer to eliminate the variable entirely.
|
||||
|
||||
* Mark the most frequently used local variables as `register`.
|
||||
It will increase chances that those variables, and not the ones less frequently used,
|
||||
are inlined into registers or put in the zeropage.
|
||||
|
||||
## Functions
|
||||
|
||||
* Write many functions with no parameters and use `-finline`.
|
||||
This will simplify the job for the optimizer and increase the chances of certain powerful optimizations to apply.
|
||||
|
||||
* Avoid passing many parameters to functions.
|
||||
Try to minimize the number of bytes passed as parameters and returned as return values.
|
||||
|
||||
## Loops
|
||||
|
||||
* For `for` loops that use a byte-sized variable and whose body does not involve function calls or further loops,
|
||||
use a unique iteration variable. Such variable will have a bigger chance of being stored in a CPU register.
|
||||
For example:
|
||||
|
||||
byte i
|
||||
byte j
|
||||
for i,0,until,30 { .... }
|
||||
for j,0,until,40 { .... }
|
||||
|
||||
is usually better than:
|
||||
|
||||
byte i
|
||||
for i,0,until,30 { .... }
|
||||
for i,0,until,40 { .... }
|
||||
|
||||
* 8080/Z80 only: The previous tip applies also for loops using word-sized variables.
|
||||
|
||||
* When the iteration order is not important, use `paralleluntil` or `parallelto`.
|
||||
The compiler will try to choose the optimal iteration order.
|
||||
|
||||
* Since 0.3.18: When the iteration order is not important,
|
||||
use `for ix,ptr:array` to iterate over arrays of structs.
|
||||
|
||||
* 6502 only: When iterating over an array larger than 256 bytes, whose element count is a composite number,
|
||||
consider splitting it into less-than-256-byte sized slices and use them within the same iteration.
|
||||
For example, instead of:
|
||||
|
||||
word i
|
||||
for i,0,paralleluntil,1000 {
|
||||
screen[i] = ' 'scr
|
||||
}
|
||||
|
||||
consider:
|
||||
|
||||
byte i
|
||||
for i,0,paralleluntil,250 {
|
||||
screen[i+000] = ' 'scr
|
||||
screen[i+250] = ' 'scr
|
||||
screen[i+500] = ' 'scr
|
||||
screen[i+750] = ' 'scr
|
||||
}
|
||||
|
||||
Note that the compiler might do this optimization automatically
|
||||
for simpler loops with certain iteration ranges, but it is not guaranteed.
|
||||
|
||||
# Arithmetic
|
||||
|
||||
* Avoid 16-bit arithmetic. Try to keep calculations 8-bit for as long as you can.
|
||||
If you can calculate the upper and lower byte of a 16-bit value separately, it's usually better to do so.
|
||||
|
||||
* Avoid arithmetic larger than 16-bit.
|
||||
|
||||
* Use `nonet` if you are sure that the result of shifting will fit into 9 bits.
|
||||
Use `nonet` when doing byte addition that you want to promote to a word.
|
||||
|
|
@ -1,31 +1,58 @@
|
|||
# Examples
|
||||
|
||||
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)
|
||||
|
||||
* [for version 0.3.14](https://github.com/KarolS/millfork/tree/v0.3.14/examples)
|
||||
|
||||
* [for version 0.3.12](https://github.com/KarolS/millfork/tree/v0.3.12/examples)
|
||||
|
||||
* [for version 0.3.10](https://github.com/KarolS/millfork/tree/v0.3.10/examples)
|
||||
|
||||
## Cross-platform examples
|
||||
|
||||
* [Hello world](crossplatform/hello_world.mfk) (C64/C16/PET/VIC-20/PET/Atari/Apple II/BBC Micro/ZX Spectrum/PC-88/Armstrad CPC/MSX) – simple text output
|
||||
* [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) – 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/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/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/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/TRS-80/Z1013) – keyboard reading test
|
||||
|
||||
* [Screen encoding test](crossplatform/screnctest.mfk) (C64/C16) – default-to-screen encoding conversion test
|
||||
|
||||
* [Bell](crossplatform/bell.mfk) (Apple II/ZX Spectrum) – a program that goes \*ding!\*
|
||||
|
||||
* [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
|
||||
|
||||
* [Test suite](tests) (C64/C16/Atari/Apple II/BBC Micro/Armstrad CPC/ZX Spectrum/PC-88/CoCo) – the semi-official test-suite for Millfork
|
||||
|
||||
## Commodore 64 examples
|
||||
|
||||
### Graphical examples
|
||||
|
@ -34,14 +61,14 @@
|
|||
|
||||
* [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
|
||||
|
||||
|
@ -59,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
|
||||
|
@ -74,8 +141,10 @@ 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.
|
||||
|
||||
* [Balls](x16/balls.mfk) – 16 sprites using 240 colours.
|
||||
|
||||
* [Joy demo](x16/joydemo.mfk) – simple joystick demo.
|
||||
|
|
62
examples/a8/bubble_sort.mfk
Normal file
62
examples/a8/bubble_sort.mfk
Normal 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
23
examples/a8/cmcplayer.mfk
Normal 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)
|
98
examples/a8/countdown_for_benchmark.mfk
Normal file
98
examples/a8/countdown_for_benchmark.mfk
Normal 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 {}
|
||||
}
|
119
examples/a8/countdown_while_benchmark.mfk
Normal file
119
examples/a8/countdown_while_benchmark.mfk
Normal 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 {}
|
||||
}
|
BIN
examples/a8/data/bitter_reality_4.mpt
Normal file
BIN
examples/a8/data/bitter_reality_4.mpt
Normal file
Binary file not shown.
4
examples/a8/data/cmc.nfo
Normal file
4
examples/a8/data/cmc.nfo
Normal 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
|
BIN
examples/a8/data/cmc_player.rep
Normal file
BIN
examples/a8/data/cmc_player.rep
Normal file
Binary file not shown.
BIN
examples/a8/data/echo.cmc
Normal file
BIN
examples/a8/data/echo.cmc
Normal file
Binary file not shown.
4
examples/a8/data/mpt.nfo
Normal file
4
examples/a8/data/mpt.nfo
Normal 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
|
BIN
examples/a8/data/mpt_player.obj
Normal file
BIN
examples/a8/data/mpt_player.obj
Normal file
Binary file not shown.
26
examples/a8/dli_example.mfk
Normal file
26
examples/a8/dli_example.mfk
Normal 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 {}
|
||||
}
|
68
examples/a8/endless_scroll.mfk
Normal file
68
examples/a8/endless_scroll.mfk
Normal 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)
|
||||
}
|
||||
}
|
109
examples/a8/gr8_chessboard_benchmark.mfk
Normal file
109
examples/a8/gr8_chessboard_benchmark.mfk
Normal 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){}
|
||||
}
|
85
examples/a8/grand_theft_antic.mfk
Normal file
85
examples/a8/grand_theft_antic.mfk
Normal 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 {}
|
||||
}
|
23
examples/a8/horizontal_stars.mfk
Normal file
23
examples/a8/horizontal_stars.mfk
Normal 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
42
examples/a8/landscape.mfk
Normal 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 {}
|
||||
}
|
64
examples/a8/montecarlo_pi_benchmark.mfk
Normal file
64
examples/a8/montecarlo_pi_benchmark.mfk
Normal 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
25
examples/a8/mptplayer.mfk
Normal 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
68
examples/a8/sieve1899.mfk
Normal 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 {}
|
||||
}
|
137
examples/a8/systemoff_example.mfk
Normal file
137
examples/a8/systemoff_example.mfk
Normal 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
|
||||
}
|
||||
}
|
37
examples/a8/vertical_scroll.mfk
Normal file
37
examples/a8/vertical_scroll.mfk
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
37
examples/apple2/diskrom_dump.mfk
Normal file
37
examples/apple2/diskrom_dump.mfk
Normal 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 { }
|
||||
}
|
|
@ -37,6 +37,7 @@ HAS_BITMAP_MODE=1
|
|||
; every segment should land in its own file:
|
||||
style=per_segment
|
||||
format=startaddr,allocated
|
||||
format_segment_extra=startaddr,allocated,$ea,$ea,$ea,$ea,$ea,$ea,$ea,$ea,$ea,$ea,$ea
|
||||
extension=prg
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
@ -15,8 +15,9 @@ void main() {
|
|||
pointer line
|
||||
while true {
|
||||
line = readline()
|
||||
// empty line is read as a single space
|
||||
// empty line is read as a single space on C64
|
||||
if line[0] == 32 && line[1] == 0 { return }
|
||||
if line[0] == 0 { return }
|
||||
putstrz(line)
|
||||
new_line()
|
||||
}
|
||||
|
|
|
@ -9,10 +9,17 @@ struct stage {
|
|||
pointer text
|
||||
}
|
||||
|
||||
#if ENCODING_NOLOWER
|
||||
array(stage) stages = [
|
||||
stage(divisible3.pointer, "FIZZ"z),
|
||||
stage(divisible5.pointer, "BUZZ"z)
|
||||
]
|
||||
#else
|
||||
array(stage) stages = [
|
||||
stage(divisible3.pointer, "fizz"z),
|
||||
stage(divisible5.pointer, "buzz"z)
|
||||
]
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
byte i, s
|
||||
|
|
|
@ -10,7 +10,7 @@ import c64_basic
|
|||
import c264_basic
|
||||
#endif
|
||||
|
||||
#define READKEY = CBM_64 | CBM_264 | ZX_SPECTRUM | NEC_PC_88
|
||||
#define READKEY = CBM_64 | CBM_264 | CBM_VIC | ZX_SPECTRUM | NEC_PC_88 | APPLE_2
|
||||
|
||||
#if READKEY
|
||||
import keyboard
|
||||
|
|
|
@ -9,7 +9,7 @@ void main() {
|
|||
ensure_mixedcase()
|
||||
|
||||
#if CBM_64 || CBM_264
|
||||
set_bg_color(green)
|
||||
set_bg_color(white)
|
||||
#endif
|
||||
#if CBM_64 || CBM_264 || ZX_SPECTRUM
|
||||
set_border(red)
|
||||
|
|
13
examples/crossplatform/readkeytest.mfk
Normal file
13
examples/crossplatform/readkeytest.mfk
Normal file
|
@ -0,0 +1,13 @@
|
|||
import stdio
|
||||
import keyboard
|
||||
void main() {
|
||||
byte c
|
||||
ensure_mixedcase()
|
||||
while true {
|
||||
c = readkey()
|
||||
putchar(c)
|
||||
putchar(hi_nibble_to_hex(c))
|
||||
putchar(lo_nibble_to_hex(c))
|
||||
putchar(' ')
|
||||
}
|
||||
}
|
136
examples/crossplatform/regdump.mfk
Normal file
136
examples/crossplatform/regdump.mfk
Normal file
|
@ -0,0 +1,136 @@
|
|||
import stdio
|
||||
|
||||
struct reg {
|
||||
pointer name
|
||||
byte size
|
||||
}
|
||||
|
||||
#if ARCH_6502
|
||||
|
||||
const array(reg) reg_defs = [reg("A"z, 1),reg("X"z, 1),reg("Y"z, 1),reg("S"z, 1),reg("P"z, 1),reg("PC"z, 2)]
|
||||
|
||||
macro asm void save_regs() {
|
||||
JSR save_regs_inner
|
||||
save_regs_inner:
|
||||
STA reg_values
|
||||
STX reg_values + 2
|
||||
STY reg_values + 4
|
||||
PHP
|
||||
PLA
|
||||
STA reg_values + 8
|
||||
TSX
|
||||
STX reg_values + 6
|
||||
PLA
|
||||
TAY
|
||||
PLA
|
||||
TAX
|
||||
CPY #2
|
||||
BCS save_regs_pcl_large
|
||||
DEX
|
||||
save_regs_pcl_large:
|
||||
DEY
|
||||
DEY
|
||||
STY reg_values + 10
|
||||
STX reg_values + 11
|
||||
}
|
||||
|
||||
#elseif ARCH_6809
|
||||
|
||||
const array(reg) reg_defs = [reg("D"z, 2),reg("X"z, 2),reg("Y"z, 2),reg("U"z, 2),reg("S"z, 2),reg("CC"z, 1),reg("DP"z, 1),reg("PC"z, 2)]
|
||||
|
||||
macro asm void save_regs() {
|
||||
PSHS PC
|
||||
STD reg_values
|
||||
TFR CC,B
|
||||
STB reg_values+10
|
||||
STB reg_values+11
|
||||
STX reg_values+2
|
||||
STY reg_values+4
|
||||
STU reg_values+6
|
||||
PULS D
|
||||
SUBD #2
|
||||
STD reg_values+14
|
||||
STS reg_values+8
|
||||
TFR DP,B
|
||||
STB reg_values+12
|
||||
STB reg_values+13
|
||||
}
|
||||
|
||||
#elseif CPUFEATURE_Z80
|
||||
|
||||
#pragma zilog_syntax
|
||||
const array(reg) reg_defs = [reg("AF"z, 2),reg("BC"z, 2),reg("DE"z, 2),reg("HL"z, 2),reg("SP"z, 2),reg("IX"z, 2),reg("IY"z, 2),reg("PC"z, 2)]
|
||||
|
||||
macro asm void save_regs() {
|
||||
CALL save_regs_inner
|
||||
save_regs_inner:
|
||||
LD (reg_values+6),HL
|
||||
PUSH AF
|
||||
POP HL
|
||||
LD (reg_values+0),HL
|
||||
LD (reg_values+2),BC
|
||||
LD (reg_values+3),DE
|
||||
POP HL
|
||||
LD B, $ff
|
||||
LD C, $fd
|
||||
ADD HL,BC
|
||||
LD (reg_values+14),HL
|
||||
LD (reg_values+10),IX
|
||||
LD (reg_values+12),IY
|
||||
}
|
||||
|
||||
#elseif ARCH_I80
|
||||
|
||||
#pragma intel_syntax
|
||||
const array(reg) reg_defs = [reg("AF"z, 2),reg("BC"z, 2),reg("DE"z, 2),reg("HL"z, 2),reg("SP"z, 2),reg("PC"z, 2)]
|
||||
|
||||
macro asm void save_regs() {
|
||||
CALL save_regs_inner
|
||||
save_regs_inner:
|
||||
LD (reg_values+6),HL
|
||||
PUSH AF
|
||||
POP HL
|
||||
LD (reg_values+0),HL
|
||||
LD H,B
|
||||
LD L,C
|
||||
LD (reg_values+2),HL
|
||||
EX HL,DE
|
||||
LD (reg_values+3),HL
|
||||
POP HL
|
||||
LD B, $ff
|
||||
LD C, $fd
|
||||
ADD HL,BC
|
||||
LD (reg_values+10),HL
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#error unsupported architecture
|
||||
|
||||
#endif
|
||||
|
||||
array(word) reg_values[reg_defs.length]
|
||||
|
||||
void main() {
|
||||
word w
|
||||
byte i
|
||||
pointer.reg r
|
||||
save_regs()
|
||||
ensure_mixedcase()
|
||||
for i,r:reg_defs {
|
||||
putstrz(r->name)
|
||||
putchar('=')
|
||||
w = reg_values[i]
|
||||
if r->size == 1 {
|
||||
putchar(hi_nibble_to_hex(w.lo))
|
||||
putchar(lo_nibble_to_hex(w.lo))
|
||||
} else {
|
||||
putchar(hi_nibble_to_hex(w.hi))
|
||||
putchar(lo_nibble_to_hex(w.hi))
|
||||
putchar(hi_nibble_to_hex(w.lo))
|
||||
putchar(lo_nibble_to_hex(w.lo))
|
||||
}
|
||||
new_line()
|
||||
}
|
||||
while true {}
|
||||
}
|
|
@ -627,4 +627,4 @@ const array attribute = [
|
|||
|
||||
|
||||
// *CHARACTER ROM (GRAPHICS)*
|
||||
segment(chrrom) const array graphics @ $0000 = file("tiles.chr")
|
||||
segment(chrrom) const array graphics @ $0000 = file("tiles.chr", 0)
|
||||
|
|
45
examples/tests/README.md
Normal file
45
examples/tests/README.md
Normal file
|
@ -0,0 +1,45 @@
|
|||
# The test suite
|
||||
|
||||
This is the semi-official test suite for Millfork standard libraries.
|
||||
|
||||
## Compiling
|
||||
|
||||
Compile the `main.mfk` file and run the resulting program.
|
||||
You are advised to try various different optimization options.
|
||||
|
||||
millfork -t <platform> main.mfk
|
||||
|
||||
Supported platforms:
|
||||
|
||||
* Commodore 64, 128 and Plus/4, loadable program (`c64`, `c128`, `plus4`)
|
||||
|
||||
* Commodore PET, VIC-20, C16, loadable program (`pet`, `vic20`, `c16`) –
|
||||
note that support for these targets may end when the suite grows beyond their memory capacity
|
||||
|
||||
* ZX Spectrum (`zxspectrum`)
|
||||
|
||||
* NEC PC-88, bootable floppy (`pc88`)
|
||||
|
||||
* MSX, cartridge (`msx_crt`)
|
||||
|
||||
* Atari computers, loadable programs (`a8`)
|
||||
|
||||
* Amstrad CPC, loadable programs (`cpc464`)
|
||||
|
||||
* BBC Micro, loadable programs (`bbcmicro`)
|
||||
|
||||
* Apple II, loadable programs (`apple2`)
|
||||
|
||||
Compiling with the `-D PRINT_SUCCESSES` will cause the suite to print all tests, including successful ones.
|
||||
Otherwise, only failed tests will be printed.
|
||||
|
||||
On each failed the following message will be printed:
|
||||
|
||||
[FAIL] <suite name> #<assertion number>
|
||||
|
||||
To continue, press any key (on MSX, press RETURN).
|
||||
|
||||
At the end of a successful run, the test suite should print
|
||||
|
||||
Total failures: 0
|
||||
|
74
examples/tests/framework.mfk
Normal file
74
examples/tests/framework.mfk
Normal file
|
@ -0,0 +1,74 @@
|
|||
import stdio
|
||||
|
||||
pointer current_suite_name
|
||||
byte current_test_number
|
||||
word failure_count = 0
|
||||
|
||||
#if ZX_SPECTRUM || CBM || NEC_PC88 || ATARI_8 || AMSTRAD_CPC || APPLE_2 || COCO
|
||||
|
||||
import keyboard
|
||||
alias wait_after_failure = readkey
|
||||
|
||||
#elseif MSX
|
||||
|
||||
alias wait_after_failure = readline
|
||||
|
||||
#else
|
||||
|
||||
macro void wait_after_failure() { while true {} }
|
||||
|
||||
#endif
|
||||
|
||||
void start_suite(pointer suite_name) {
|
||||
putstrz("Running "z)
|
||||
putstrz(suite_name)
|
||||
new_line()
|
||||
current_suite_name = suite_name
|
||||
current_test_number = 0
|
||||
}
|
||||
|
||||
void print_failure() {
|
||||
putstrz("[FAIL]: "z)
|
||||
putstrz(current_suite_name)
|
||||
putstrz(" #"z)
|
||||
putword(current_test_number)
|
||||
new_line()
|
||||
failure_count += 1
|
||||
}
|
||||
|
||||
void print_success() {
|
||||
putstrz("[ OK ]: "z)
|
||||
putstrz(current_suite_name)
|
||||
putstrz(" #"z)
|
||||
putword(current_test_number)
|
||||
new_line()
|
||||
}
|
||||
|
||||
void assert_equal(word expected, word actual) {
|
||||
current_test_number += 1
|
||||
if actual != expected {
|
||||
print_failure()
|
||||
putstrz("Expected: "z)
|
||||
putword(expected)
|
||||
putstrz(" Actual: "z)
|
||||
putword(actual)
|
||||
new_line()
|
||||
wait_after_failure()
|
||||
#if PRINT_SUCCESSES
|
||||
} else {
|
||||
print_success()
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void assert_true(bool result) {
|
||||
current_test_number += 1
|
||||
if not(result) {
|
||||
print_failure()
|
||||
readkey()
|
||||
#if PRINT_SUCCESSES
|
||||
} else {
|
||||
print_success()
|
||||
#endif
|
||||
}
|
||||
}
|
28
examples/tests/main.mfk
Normal file
28
examples/tests/main.mfk
Normal file
|
@ -0,0 +1,28 @@
|
|||
import test_fibonacci
|
||||
import test_pstring
|
||||
import test_string
|
||||
#if ENCCONV_SUPPORTED
|
||||
import test_encconv
|
||||
#endif
|
||||
#if MILLFORK_VERSION >= 000317
|
||||
import test_template<ignored1, 1>
|
||||
import test_template<ignored1, 1>
|
||||
import test_template<ignored2, 2>
|
||||
#endif
|
||||
|
||||
void main() {
|
||||
ensure_mixedcase()
|
||||
|
||||
// readkey()
|
||||
test_fibonacci()
|
||||
test_string()
|
||||
test_pstring()
|
||||
#if ENCCONV_SUPPORTED
|
||||
test_encconv()
|
||||
#endif
|
||||
|
||||
new_line()
|
||||
putstrz("Total failures: "z)
|
||||
putword(failure_count)
|
||||
while true {} // don't exit
|
||||
}
|
15
examples/tests/test_encconv.mfk
Normal file
15
examples/tests/test_encconv.mfk
Normal file
|
@ -0,0 +1,15 @@
|
|||
import framework
|
||||
import encconv
|
||||
import scrstring
|
||||
import string
|
||||
|
||||
void test_encconv() {
|
||||
array buffer[16]
|
||||
start_suite("encconv"z)
|
||||
|
||||
strzcopy(buffer, "test 132"z)
|
||||
strz_to_screencode(buffer)
|
||||
assert_equal(0, scrstrzcmp("test 132"scrz, buffer))
|
||||
strz_from_screencode(buffer)
|
||||
assert_equal(0, strzcmp("test 132"z, buffer))
|
||||
}
|
18
examples/tests/test_fibonacci.mfk
Normal file
18
examples/tests/test_fibonacci.mfk
Normal file
|
@ -0,0 +1,18 @@
|
|||
import framework
|
||||
|
||||
word fib(byte n) {
|
||||
stack byte i
|
||||
i = n
|
||||
if i < 2 { return 1 }
|
||||
return fib(i-1) + fib(i-2)
|
||||
}
|
||||
|
||||
void test_fibonacci() {
|
||||
start_suite("Fibonacci"z)
|
||||
|
||||
assert_equal(1, fib(0))
|
||||
assert_equal(1, fib(1))
|
||||
assert_equal(2, fib(2))
|
||||
assert_equal(3, fib(3))
|
||||
assert_equal(5, fib(4))
|
||||
}
|
29
examples/tests/test_pstring.mfk
Normal file
29
examples/tests/test_pstring.mfk
Normal file
|
@ -0,0 +1,29 @@
|
|||
import pstring
|
||||
import framework
|
||||
|
||||
void test_pstring() {
|
||||
array buffer[256]
|
||||
|
||||
// #1-5
|
||||
start_suite("pstring"z)
|
||||
assert_equal(0, pstrcmp("a"p, "a"p))
|
||||
assert_equal(-1, pstrcmp("a"p, "b"p))
|
||||
assert_equal(-1, pstrcmp("a"p, "ab"p))
|
||||
assert_equal(1, pstrcmp("b"p, "a"p))
|
||||
assert_equal(1, pstrcmp("ab"p, "a"p))
|
||||
|
||||
// #6-10
|
||||
pstrcopy(buffer, "test"p)
|
||||
assert_equal(4, pstrlen(buffer))
|
||||
assert_equal(0, pstrcmp("test"p, buffer))
|
||||
pstrappend(buffer, "hello"p)
|
||||
assert_equal(9, pstrlen(buffer))
|
||||
assert_equal(0, pstrcmp("testhello"p, buffer))
|
||||
assert_equal(1234, pstr2word("1234"p))
|
||||
|
||||
// #11
|
||||
pstrcopy(buffer, "test****test"p)
|
||||
pstrpaste(buffer+5, "test"p)
|
||||
assert_equal(0, pstrcmp("testtesttest"p, buffer))
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user