mirror of
https://github.com/KarolS/millfork.git
synced 2024-05-31 18:41:30 +00:00
Compare commits
266 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 |
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -6,6 +6,7 @@ project/project/target/
|
|||
stuff
|
||||
releases
|
||||
src/test/scala/experiments/
|
||||
src/test/java/experiments/
|
||||
# doesn't work yet
|
||||
examples/lunix/
|
||||
# older copies
|
||||
|
@ -30,9 +31,12 @@ issue*.mfk
|
|||
*.seq
|
||||
*.asm
|
||||
*.lbl
|
||||
*.labels
|
||||
*.nl
|
||||
*.fns
|
||||
*.sym
|
||||
*.mlb
|
||||
*.dbg
|
||||
*.deb
|
||||
*.xex
|
||||
*.nes
|
||||
|
@ -49,6 +53,8 @@ issue*.mfk
|
|||
*.rom
|
||||
*.ssd
|
||||
*.o
|
||||
*.cmd
|
||||
*.z80
|
||||
HELLO
|
||||
HELLOCPC
|
||||
FIZZBUZZ
|
||||
|
|
194
CHANGELOG.md
194
CHANGELOG.md
|
@ -1,5 +1,195 @@
|
|||
# Change log
|
||||
|
||||
## 0.3.30 (2021-12-15)
|
||||
|
||||
* Added volatile structure fields (#112).
|
||||
|
||||
* Added `this.function` as the alias for the current function (#118).
|
||||
|
||||
* Added support for constant evaluation in `file` expressions (#114).
|
||||
|
||||
* Allowed declaring local constants and passing untyped parameters for macros.
|
||||
|
||||
* Allowed treating bare function name as a pointer to it.
|
||||
|
||||
* Added Mesen, ld65 and "raw" label file formats (#128).
|
||||
|
||||
* Commodore: the address used by SYS is now determined automatically instead of hardcoded (#111).
|
||||
|
||||
* C64: Fixed address for `sid_v1_sr` (#115).
|
||||
|
||||
* EasyFlash: Fixed address for `switch_hirom` (#121).
|
||||
|
||||
* GB: Fixed standard library (thanks to @retrac0).
|
||||
|
||||
* Commander X16: Updated platform definition file (thanks to @mookiexl).
|
||||
|
||||
* 65CE02: Full assembly support.
|
||||
|
||||
* R800: Full assembly support.
|
||||
|
||||
* Various miscompilation fixes (#123, #125) and parser fixes (e.g. #120).
|
||||
|
||||
* 6809: Various optimizations.
|
||||
|
||||
* Improvements related to constant evaluation.
|
||||
|
||||
## 0.3.28 (2021-05-24)
|
||||
|
||||
* Officially deprecated decimal operators with apostrophes.
|
||||
|
||||
* Added optimization hints.
|
||||
|
||||
* Added `utf32be`, `utf32le`, `cp1253`, `cp1254`, `cp1257`, `geos_de` encodings.
|
||||
|
||||
* Allowed for underscores in numeric literals for readability purposes, similar to several other programming languages.
|
||||
|
||||
* Added a warning for comparisons between bytes and pointers (#110).
|
||||
|
||||
* Fixed escape sequences in many encodings.
|
||||
|
||||
* Fixed and documented absolute module imports (#106)
|
||||
|
||||
* Fixed and optimized sign extension.
|
||||
|
||||
* Fixed optimizations involving unused labels.
|
||||
|
||||
* Fixed pointer types to type aliases.
|
||||
|
||||
* Fixed parsing of Intel hex literals of the form `0BH`, `0B0H` etc.
|
||||
|
||||
* 6809: Fixed flow analysis in optimization.
|
||||
|
||||
* Optimization of certain bitmask operations.
|
||||
|
||||
* Parsing optimizations.
|
||||
|
||||
## 0.3.26 (2021-03-01)
|
||||
|
||||
* Array fields in structs.
|
||||
|
||||
* Various Apple II-related improvements, including ProDOS support (thanks to @retrac0).
|
||||
|
||||
* Segment-related constants now match their equivalents from the platform definition. Missing constants have been defined.
|
||||
|
||||
* Constants with heap start and segment start are now generated properly.
|
||||
|
||||
* Signed multiplication support for `sbyte` and `signed16`.
|
||||
|
||||
* Heavily experimental `typeof` builtin.
|
||||
|
||||
* Self-modifying assembly code is now supported (#101).
|
||||
|
||||
* Successful compilation now prints result program size.
|
||||
|
||||
* Warning about data not being included in the output file.
|
||||
|
||||
* Warnings can now be enabled and disabled individually.
|
||||
|
||||
* Imported modules are now identified by their full relative path, not just the token used in the `import` statement (#89).
|
||||
|
||||
* 6502: Fixed sbyte to word promotions in certain contexts.
|
||||
|
||||
* 8080: Fixed compilation of sign extension of `sbyte` values into the BC register pair.
|
||||
|
||||
* Fixed negative constant folding.
|
||||
|
||||
* Fixed optimizations around macro invocations.
|
||||
|
||||
* 6502: Fixed code deduplication in presence of trampolined functions.
|
||||
|
||||
* Optimized word shifts for between 7 and 12 bits.
|
||||
|
||||
* Allowed new lines after `=`.
|
||||
|
||||
* Various optimization improvements.
|
||||
|
||||
* Improved some error messages (thanks to @agg23).
|
||||
|
||||
* Other fixes and improvements.
|
||||
|
||||
## 0.3.24 (2020-12-02)
|
||||
|
||||
* Preliminary support for TRS-80 Model 1 and 3 running TRS-DOS.
|
||||
|
||||
* Preliminary support for Robotron Z1013.
|
||||
|
||||
* Allowed defining entry points other than the start of the segment for Atari, ZX Spectrum, CoCo, Z1013 and TRS-80. (#78)
|
||||
|
||||
* Allowed the `:` operator in const-pure functions.
|
||||
|
||||
* Added `pointer.interrupt` and `pointer.kernal_interrupt` types.
|
||||
|
||||
* Implemented `readline` and `readword` for VIC-20.
|
||||
|
||||
* `init_rand_seed` uses the POKEY on Atari.
|
||||
|
||||
* Useless labels are no longer emitted into the label file.
|
||||
|
||||
* VIC-20: added `readline` and `readword`.
|
||||
|
||||
* Atari: use POKEY for randomness source.
|
||||
|
||||
* New output format elements: ASCII string, program name.
|
||||
|
||||
* Fix: Pointers to functions with parameters (#86)/
|
||||
|
||||
* Fix: more instances of memset loops should be detected and optimized (#59).
|
||||
|
||||
* Fix: things mentioned in the segment layout should not be deleted even if unused.
|
||||
|
||||
* Fix: `endaddr+N` output format.
|
||||
|
||||
* 65816: some code generation fixes.
|
||||
|
||||
* 8080: word negation now works.
|
||||
|
||||
* Various optimization improvements.
|
||||
|
||||
* Various other fixes.
|
||||
|
||||
* Improved some error messages.
|
||||
|
||||
* Even more new Atari examples (thanks to @zbyti).
|
||||
|
||||
* Build process slightly changed.
|
||||
|
||||
## 0.3.22 (2020-09-15)
|
||||
|
||||
* Added local labels in assembly.
|
||||
|
||||
* Added alternate decimal operators (with `$` instead of `'`).
|
||||
|
||||
* **Potentially breaking change!** Identifiers no longer can end with `$`.
|
||||
|
||||
* Added `z80next` as an alternate name for the ZX Spectrum Next's processor (#55).
|
||||
|
||||
* Added encodings: `brascii`, `macroman`, `dmcs`, `lics`.
|
||||
|
||||
* Improved some error messages.
|
||||
|
||||
* Fix: interrupt functions written in assembly no longer have the default prologue (#62).
|
||||
|
||||
* Fixed the `a8_os` module (#58).
|
||||
|
||||
* Fixed evaluation of division of large constants.
|
||||
|
||||
* Fix: Structure alignment is now respected for substructures.
|
||||
|
||||
* X16: Fixed the address of `vera_dc_hscale_hstop` register (#54) (thanks to @Kobrasadetin).
|
||||
|
||||
* Fixed evaluation of more complex boolean expressions (#56).
|
||||
|
||||
* Fixed accesses to volatile variables.
|
||||
|
||||
* 8080/Z80: Optimization improvements.
|
||||
|
||||
* 6809: Optimization improvements.
|
||||
|
||||
* Various Atari improvements (#60, #63, #65) (thanks to @zbyti).
|
||||
|
||||
* New Atari examples (thanks to @zbyti).
|
||||
|
||||
## 0.3.18 (2020-04-08)
|
||||
|
||||
* Support for Motorola 6809 (complete, but still experimental).
|
||||
|
@ -448,7 +638,7 @@ can no longer be read before an explicit call to `init_rw_memory`, either add th
|
|||
|
||||
* Added enumeration types.
|
||||
|
||||
* Added preprocessor.
|
||||
* Added the preprocessor.
|
||||
|
||||
* Added `for` loops over enum types and in-place lists
|
||||
|
||||
|
@ -470,7 +660,7 @@ can no longer be read before an explicit call to `init_rw_memory`, either add th
|
|||
|
||||
* Extra `z` at the name of the encoding means that the string is zero-terminated.
|
||||
|
||||
* **Potentially breaking change!** No longer allowed to define things with names that are keywords or builtins.
|
||||
* **Potentially breaking change!** It's no longer allowed to define things with names that are keywords or builtins.
|
||||
|
||||
* **Potentially breaking change!** Curly braces in text literals are now used for escape sequences.
|
||||
|
||||
|
|
28
COMPILING.md
28
COMPILING.md
|
@ -21,36 +21,22 @@ Setting up the test suite for Millfork is tricky, so if you don't need the tests
|
|||
|
||||
#### Steps
|
||||
|
||||
* remove all test dependencies from `build.sbt`:
|
||||
|
||||
"org.scalatest" %% "scalatest"
|
||||
"com.codingrodent.microprocessor" % "Z80Processor"
|
||||
"NeatMonster" % "Intel8086"
|
||||
"com.loomcom.symon" % "symon"
|
||||
"com.grapeshot" % "halfnes"
|
||||
"eu.rekawek.coffeegb" % "coffee-gb"
|
||||
"roug.org.osnine" % "osnine-core"
|
||||
|
||||
* navigate to the project directory
|
||||
|
||||
* run `sbt 'set test in assembly := {}' compile`
|
||||
* run `sbt -DskipTests compile`
|
||||
to compile the project
|
||||
|
||||
* run `sbt 'set test in assembly := {}' assembly`
|
||||
* run `sbt -DskipTests assembly`
|
||||
to build the executable jar file, it should appear in `target/scala-2.12`
|
||||
|
||||
* on Windows, use double quotes for the last two commands:
|
||||
|
||||
sbt "set test in assembly := {}" compile
|
||||
sbt "set test in assembly := {}" assembly
|
||||
|
||||
### Building with tests
|
||||
|
||||
Test suite is useful if you plan on modifying the compiler. Some test dependencies need manual installation.
|
||||
|
||||
#### Prerequisites
|
||||
|
||||
* JDK 1.8 with Nashorn (tests don't work on newer versions)
|
||||
* JDK 1.8 or later
|
||||
|
||||
* Millfork up to version 0.3.22 used to require exactly JDK 1.8 with Nashorn,
|
||||
as the tests didn't work on newer versions
|
||||
|
||||
* sbt
|
||||
|
||||
|
@ -71,7 +57,7 @@ Test suite is useful if you plan on modifying the compiler. Some test dependenci
|
|||
|
||||
* run `sbt compile` to compile the project
|
||||
|
||||
* run `sbt assemble` to build the executable jar file, it should appear in `target/scala-2.12`
|
||||
* run `sbt assembly` to build the executable jar file, it should appear in `target/scala-2.12`
|
||||
|
||||
### Building a native executable
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
A middle-level programming language targeting 6502-based, 8080-based, Z80-based and 6809-based microcomputers.
|
||||
|
||||
For binary releases, see: [https://github.com/KarolS/millfork/releases](https://github.com/KarolS/millfork/releases)
|
||||
(latest: 0.3.18).
|
||||
(latest: 0.3.30).
|
||||
For build instructions, see [Build instructions](./COMPILING.md).
|
||||
|
||||
## Features
|
||||
|
@ -22,7 +22,7 @@ For build instructions, see [Build instructions](./COMPILING.md).
|
|||
|
||||
* other 6502-based machines: Famicom/NES, Atari Lynx, Atari 8-bit computers, BBC Micro, Apple II+/IIe/Enhanced IIe, Atari 2600 (experimental), Commander X16 (experimental)
|
||||
|
||||
* Z80-based machines: ZX Spectrum 48k, NEC PC-88, Amstrad CPC, MSX
|
||||
* Z80-based machines: ZX Spectrum 48k, NEC PC-88, Amstrad CPC, MSX, TRS-80 Model 1 and 3, Robotron Z1013
|
||||
|
||||
* CP/M
|
||||
|
||||
|
|
52
build.sbt
52
build.sbt
|
@ -1,7 +1,8 @@
|
|||
name := "millfork"
|
||||
|
||||
version := "0.3.18"
|
||||
version := "0.3.31-SNAPSHOT"
|
||||
|
||||
// keep it at 2.12.11 for GraalVM native image compatibility!
|
||||
scalaVersion := "2.12.11"
|
||||
|
||||
resolvers += Resolver.mavenLocal
|
||||
|
@ -12,25 +13,42 @@ libraryDependencies += "org.apache.commons" % "commons-configuration2" % "2.2"
|
|||
|
||||
libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.8" % "test"
|
||||
|
||||
libraryDependencies += "com.codingrodent.microprocessor" % "Z80Processor" % "2.0.2" % "test"
|
||||
val testDependencies = Seq(
|
||||
"com.codingrodent.microprocessor" % "Z80Processor" % "2.0.2" % "test",
|
||||
// see: https://github.com/NeatMonster/Intel8086
|
||||
"NeatMonster" % "Intel8086" % "1.0" % "test" from "https://github.com/NeatMonster/Intel8086/raw/master/IBMPC.jar",
|
||||
// these three are not in Maven Central or any other public repo
|
||||
// get them from the following links or just build millfork without tests:
|
||||
// https://github.com/sethm/symon/tree/71905fdb1998ee4f142260879504bc46cf27648f
|
||||
// https://github.com/andrew-hoffman/halfnes/tree/061
|
||||
// https://github.com/trekawek/coffee-gb/tree/coffee-gb-1.0.0
|
||||
// https://github.com/sorenroug/osnine-java/tree/b77349a6c314e1362e69b7158c385ac6f89b7ab8
|
||||
"com.loomcom.symon" % "symon" % "1.3.0-SNAPSHOT" % "test",
|
||||
"com.grapeshot" % "halfnes" % "061" % "test",
|
||||
"eu.rekawek.coffeegb" % "coffee-gb" % "1.0.0" % "test",
|
||||
"roug.org.osnine" % "osnine-core" % "2.0-SNAPSHOT" % "test",
|
||||
"org.graalvm.sdk" % "graal-sdk" % "20.2.0" % "test",
|
||||
"org.graalvm.js" % "js" % "20.2.0" % "test",
|
||||
"org.graalvm.js" % "js-scriptengine" % "20.2.0" % "test"
|
||||
)
|
||||
|
||||
// see: https://github.com/NeatMonster/Intel8086
|
||||
libraryDependencies += "NeatMonster" % "Intel8086" % "1.0" % "test" from "https://github.com/NeatMonster/Intel8086/raw/master/IBMPC.jar"
|
||||
val includesTests = System.getProperty("skipTests") == null
|
||||
|
||||
// these three are not in Maven Central or any other public repo
|
||||
// get them from the following links or just build millfork without tests:
|
||||
// https://github.com/sethm/symon/tree/71905fdb1998ee4f142260879504bc46cf27648f
|
||||
// https://github.com/andrew-hoffman/halfnes/tree/061
|
||||
// https://github.com/trekawek/coffee-gb/tree/coffee-gb-1.0.0
|
||||
// https://github.com/sorenroug/osnine-java/tree/b77349a6c314e1362e69b7158c385ac6f89b7ab8
|
||||
libraryDependencies ++=(
|
||||
if (includesTests) {
|
||||
println("Including test dependencies")
|
||||
testDependencies
|
||||
} else {
|
||||
Seq[ModuleID]()
|
||||
}
|
||||
)
|
||||
|
||||
libraryDependencies += "com.loomcom.symon" % "symon" % "1.3.0-SNAPSHOT" % "test"
|
||||
|
||||
libraryDependencies += "com.grapeshot" % "halfnes" % "061" % "test"
|
||||
|
||||
libraryDependencies += "eu.rekawek.coffeegb" % "coffee-gb" % "1.0.0" % "test"
|
||||
|
||||
libraryDependencies += "roug.org.osnine" % "osnine-core" % "2.0-SNAPSHOT" % "test"
|
||||
(if (!includesTests) {
|
||||
// Disable assembling tests
|
||||
sbt.internals.DslEntry.fromSettingsDef(test in assembly := {})
|
||||
} else {
|
||||
sbt.internals.DslEntry.fromSettingsDef(Seq[sbt.Def.Setting[_]]())
|
||||
})
|
||||
|
||||
mainClass in Compile := Some("millfork.Main")
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -12,6 +12,10 @@ It implies the following:
|
|||
|
||||
* cannot be `inline`, `noinline` or `extern`
|
||||
|
||||
* cannot contain variable or array declarations
|
||||
|
||||
* but can contain scalar constant declarations; the constants are scoped to the particular macro invocation
|
||||
|
||||
* can be `asm` - in this case, they should **not** end with a return instruction
|
||||
|
||||
* do not have an address
|
||||
|
@ -33,7 +37,13 @@ It implies the following:
|
|||
* `call` parameters exceptionally can have their type declared as `void`;
|
||||
such parameters accept expressions of any type, including `void`, however, you cannot assign from those expressions
|
||||
|
||||
* macros do not have their own scope (they reuse the scope from their invocations) – exceptions: the parameters and the local labels defined in assembly
|
||||
* macros do not have their own scope (they reuse the scope from their invocations) – exceptions:
|
||||
|
||||
* the parameters
|
||||
|
||||
* the local labels defined in assembly
|
||||
|
||||
* the local constants
|
||||
|
||||
* control-flow statements (`break`, `continue`, `return`, `goto`, `label`) are run as if places in the caller function
|
||||
|
||||
|
@ -123,7 +133,7 @@ calls with non-constant arguments are subject to the regular rules.
|
|||
|
||||
* functions declared with the `noinline` keyword will never be inlined
|
||||
|
||||
* the remaining functions may be inlined only if the `-finline` command-line option is enabled
|
||||
* the remaining functions may be inlined only if the `-finline` command-line option is enabled,
|
||||
and the compiler decides the function is worth doing
|
||||
|
||||
## Automatic subroutine extraction
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -31,7 +31,7 @@ no extension for BBC micro program file,
|
|||
Default: If compiling one file with `.mfk` extension, the same name as the input file. Otherwise, `a`.
|
||||
|
||||
|
||||
* `-s` – Generate also the assembly output. It is not compatible with any assembler, but it serves purely informational purpose. The file has the same nam as the output file and the extension is `.asm`.
|
||||
* `-s` – Generate also the assembly output. It is not compatible with any assembler, but it serves purely informational purpose. The file has the same nam as the output file, and the extension is `.asm`.
|
||||
|
||||
* `-g` – Generate also the label file. The label file contains labels with their addresses, with duplicates removed.
|
||||
It can be loaded into the monitor of the emulator for debugging purposes.
|
||||
|
@ -47,6 +47,12 @@ The extension and the file format are platform-dependent.
|
|||
* `-G sym` – format used by the WLA DX assembler. The extension is `.sym`.
|
||||
|
||||
* `-G fceux` – multi-file format used by the FCEUX emulator. The extension is `.nl`.
|
||||
|
||||
* `-G mesen` – format used by the Mesen emulator. The extension is `.mlb`.
|
||||
|
||||
* `-G ld65` – a simplified version of the format used by the `ld65` linker (used by CC65 and CA65). The extension is `.dbg`.
|
||||
|
||||
* `-G raw` – Millfork-specific format. The extension is '.labels'. Each row contains bank number, start address, end address (if known), object type, and Millfork-specific object identifier.
|
||||
|
||||
* `-fbreakpoints`, `-fno-breakpoints` –
|
||||
Whether the compiler should use the `breakpoint` macro.
|
||||
|
@ -59,7 +65,7 @@ Those directories are searched for modules and platform definitions.
|
|||
When searching for modules, the directory containing the file currently being compiled is also searched.
|
||||
When searching for platform definitions, the current working directory is also searched.
|
||||
If not given, the compiler will try to detect the default include directory.
|
||||
If given, then the compiler will NOT try to detect the default include directory and you will have to add it to the list yourself.
|
||||
If given, then the compiler will NOT try to detect the default include directory, and you will have to add it to the list yourself.
|
||||
|
||||
* `-i <dir>` – Add a directory to the include directories.
|
||||
Unlike `-I`, this does not replace the default include directory and allows using directories with semicolons in their names.
|
||||
|
@ -206,6 +212,10 @@ The compiler doesn't support accessing the stack variables via the S stack point
|
|||
|
||||
* `-O9` – Optimize code using superoptimizer (experimental). Computationally very expensive, decent results.
|
||||
|
||||
* `-fhints`, `-fno-hints` –
|
||||
Whether optimization hints should be used.
|
||||
Default: yes.
|
||||
|
||||
* `-finline`, `-fno-inline` – Whether should inline functions automatically.
|
||||
See the [documentation about inlining](../abi/inlining.md). Computationally easy, can give decent gains.
|
||||
`.ini` equivalent: `inline`.
|
||||
|
@ -278,3 +288,45 @@ By default, the compiler emits only some of the most important warnings.
|
|||
* `-Wnone` – Disable all warnings.
|
||||
|
||||
* `-Wfatal` – Treat warnings as errors.
|
||||
|
||||
You can also enable or disable warnings individually:
|
||||
|
||||
* `-Wbuggy`, `-Wno-buggy` –
|
||||
Whether should warn about code that may cause surprising behaviours or even miscompilation.
|
||||
Default: enabled.
|
||||
|
||||
* `-Wdeprecation`, `-Wno-deprecation` –
|
||||
Whether should warn about deprecated aliases.
|
||||
Default: enabled.
|
||||
|
||||
* `-Wcomparisons`, `-Wno-comparisons` –
|
||||
Whether should warn about comparisons between bytes and pointers.
|
||||
Default: enabled.
|
||||
|
||||
* `-Wextra-comparisons`, `-Wno-extra-comparisons` –
|
||||
Whether should warn about simplifiable unsigned integer comparisons.
|
||||
Default: disabled.
|
||||
|
||||
* `-Wfallback`, `-Wno-fallback` –
|
||||
Whether should warn about the use of default values by text codecs, the preprocessor, and array literals.
|
||||
Default: enabled.
|
||||
|
||||
* `-Wmissing-output`, `-Wno-missing-output` –
|
||||
Whether should warn about data that is missing in output files.
|
||||
Default: enabled.
|
||||
|
||||
* `-Woverlapping-call`, `-Wno-overlapping-call` –
|
||||
Whether should warn about calls to functions in a different, yet overlapping segment.
|
||||
Default: enabled.
|
||||
|
||||
* `-Wror`, `-Wno-ror` –
|
||||
Whether should warn about the ROR instruction (6502 only).
|
||||
Default: disabled.
|
||||
|
||||
* `-Wuseless`, `-Wno-useless` –
|
||||
Whether should warn about code that does nothing.
|
||||
Default: enabled.
|
||||
|
||||
* `-Whints`, `-Wno-hints` –
|
||||
Whether should warn about unsupported optimization hints.
|
||||
Default: enabled.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -37,8 +37,11 @@ if a line ends with a backslash character, the value continues to the next line.
|
|||
* `z80` (Zilog Z80)
|
||||
|
||||
* `strictz80` (Z80 without illegal instructions)
|
||||
|
||||
* `r800` (R800)
|
||||
|
||||
* `z80next` (Z80 core from ZX Spectrum Next)
|
||||
* `z80next` (Z80 core from ZX Spectrum Next)
|
||||
Note: Millfork version 0.3.18 and earlier uses the name `zx80next` for this architecture.
|
||||
|
||||
* `i8080` (Intel 8080)
|
||||
|
||||
|
@ -79,6 +82,8 @@ This list cannot contain module template instantiations.
|
|||
* `emit_x80` – whether the compiler should emit instructions present on Sharp LR35902 and Z80, but absent on Intel 8080, default is `true` on compatible processors and `false` elsewhere
|
||||
|
||||
* `emit_z80` – whether the compiler should emit Zilog Z80 instructions not covered by `emit_x80`, default is `true` on compatible processors and `false` elsewhere
|
||||
|
||||
* `emit_r800` – whether the compiler should emit R800 instructions, default is `true` on compatible processors and `false` elsewhere
|
||||
|
||||
* `prevent_jmp_indirect_bug` – whether the compiler should try to avoid the indirect JMP bug,
|
||||
default is `false` on 65C02-compatible or non-6502 processors and `true` elsewhere
|
||||
|
@ -172,7 +177,7 @@ Default: `after_code`.
|
|||
* `segment_NAME_bank` – the bank number the segment belongs to. Default: `0`.
|
||||
For better debugging on NES, RAM segments should use bank number `$ff`.
|
||||
|
||||
* `segment_NAME_fill` – the byte value used to fill gaps and other unused space in the bank. Default: `0`.
|
||||
* `segment_NAME_fill` – the byte value used to fill gaps and other unused space in the segment. Default: `0`.
|
||||
|
||||
* `segment_NAME_layout` – a comma-separated list of object names that defines in what order the objects are laid out in the segment.
|
||||
One item has to be `*`, it means "all the other objects".
|
||||
|
@ -203,9 +208,15 @@ Default: `main,*`
|
|||
|
||||
* `endaddr_be` – the same, but big-endian
|
||||
|
||||
* `startaddr+123`, `startaddr_be+123`, `endaddr+123`, `endaddr_be+123` – the same, but incremented by the given number
|
||||
* `addr:XXXX` – little-endian 16-bit address of the symbol XXXX
|
||||
|
||||
* `addr_be:XXXX` – the same, but big-endian
|
||||
|
||||
* `startaddr+123`, `startaddr_be+123`, `endaddr+123`, `endaddr_be+123`, `addr:XXXX+123`, `addr_be:XXXX+123` – the same, but incremented by the given number
|
||||
|
||||
* `startaddr-123`, `startaddr_be-123`, `endaddr-123`, `endaddr_be-123` – the same, but decremented by the given number
|
||||
* the number can be decimal, hexadecimal, octal, quaternary or binary
|
||||
|
||||
* `startaddr-123`, `startaddr_be-123`, `endaddr-123`, `endaddr_be-123`, `addr:XXXX-123`, `addr_be:XXXX-123`– the same, but decremented by the given number
|
||||
|
||||
* `startpage` – the high byte of `startaddr`
|
||||
|
||||
|
@ -216,18 +227,28 @@ Default: `main,*`
|
|||
* `length+123`, `length_be+123` – the same, but incremented by the given number
|
||||
|
||||
* `length-123`, `length_be-123` – the same, but decremented by the given number
|
||||
|
||||
* `programname-123` – the name of the program of the given length, uppercase ASCII, padded with spaces
|
||||
|
||||
* `allocated` – all used bytes
|
||||
|
||||
* `pagecount` – the number of pages used by all used bytes (including partially filled pages)
|
||||
|
||||
* `"<string>"` – literal ASCII string; commas, non-ASCII characters and escape sequences are not supported
|
||||
|
||||
* `<addr>:<addr>` - inclusive range of bytes
|
||||
|
||||
* `<segment>:<addr>:<addr>` - inclusive range of bytes in a given segment
|
||||
|
||||
* `d88` - a D88 floppy disk image for PC-88
|
||||
|
||||
* `tap` - a tape disk image for ZX Spectrum
|
||||
* `tap:XXXX` - a tape image for ZX Spectrum; XXXX is the name of the entry point to the program
|
||||
|
||||
* `tap` – equivalent to `tap:main`
|
||||
|
||||
* `trscmd:XXXX` - a chunked loadable executable for TRS-80 Model 1 or 3 running TRS-DOS, also known as the /CMD format; XXXX is the name of the entry point to the program
|
||||
|
||||
* `trscmd` - equivalent to `trscmd:main`
|
||||
|
||||
* `format_segment_NAME` – if using the `per_segment` style, overrides the format for the given segment
|
||||
|
||||
|
@ -246,3 +267,7 @@ Default: `main,*`
|
|||
* `sym` – format used by the WLA/DX assembler. The extension is `.sym`.
|
||||
|
||||
* `fceux` – multi-file format used by the FCEUX emulator. The extension is `.nl`.
|
||||
|
||||
* `mesen` – format used by the Mesen emulator. The extension is `.mlb`.
|
||||
|
||||
* `ld65` – format used by the `ld65` linker. The extension is `.dbg`.
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -99,6 +99,12 @@ The compiler emits COM files.
|
|||
|
||||
* `cpm_z80` – CP/M on Z80
|
||||
|
||||
* `z1013` – Robotron Z1013. The compiler emits Z80 files.
|
||||
|
||||
* `trs80m1cmd` – TRS-80 Model 1 running TRS-DOS. The compiler emits CMD files.
|
||||
|
||||
* `trs80m3cmd` – TRS-80 Model 3 running TRS-DOS. The compiler emits CMD files.
|
||||
|
||||
* `coco_rsdos` – Tandy Color Computer running RS-DOS. (very experimental)
|
||||
Read [the Color Computer programming guide](./coco-programming-guide.md) for more info.
|
||||
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
|
||||
* [Predefined constants](lang/predefined_constants.md)
|
||||
|
||||
* [List of magic suffixes](lang/suffixes.md)
|
||||
|
||||
* [List of text encodings and escape sequences](lang/text.md)
|
||||
|
||||
* [Defining custom encodings](lang/custom-encoding.md)
|
||||
|
@ -42,6 +44,8 @@
|
|||
|
||||
* [Important guidelines regarding reentrancy](lang/reentrancy.md)
|
||||
|
||||
* [Optimization hints](lang/hints.md)
|
||||
|
||||
* [List of keywords](lang/keywords.md)
|
||||
|
||||
## Library reference
|
||||
|
@ -69,10 +73,14 @@
|
|||
* [Definitions available on only some platforms](stdlib/frequent.md)
|
||||
|
||||
* [C64-only modules](stdlib/c64.md)
|
||||
|
||||
* [VIC-20-only modules](stdlib/vic20.md)
|
||||
|
||||
* [PET-only modules](stdlib/cbm_pet.md)
|
||||
|
||||
* [`cbm_file` module](stdlib/cbm_file.md)
|
||||
|
||||
* [Apple II-only modules](stdlib/apple2.md)
|
||||
|
||||
* [NES-only modules](stdlib/nes.md)
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -39,7 +39,7 @@ Currently, some extra 65CE02/65816 instructions are not supported yet.
|
|||
|
||||
Undocumented instructions are supported using various opcodes.
|
||||
|
||||
Labels have to be followed by a colon and they can optionally be on a separate line.
|
||||
Labels have to be followed by a colon, and they can optionally be on a separate line.
|
||||
Indentation is not important:
|
||||
|
||||
first: INC x
|
||||
|
@ -48,9 +48,20 @@ Indentation is not important:
|
|||
INC z
|
||||
|
||||
|
||||
Label names have to start with a letter and can contain digits, underscores and letters.
|
||||
This means than they cannot start with a period like in many other assemblers.
|
||||
Similarly, anonymous labels designated with `+` or `-` are also not supported.
|
||||
Global label names have to start with a letter and can contain digits, underscores and letters.
|
||||
Local label names (available since Millfork 0.3.22) start with a period and are visible only in the given function.
|
||||
Anonymous labels designated with `+` or `-` are also not supported.
|
||||
|
||||
Referring to a global label with an offset requires wrapping it in `label(…)`:
|
||||
|
||||
STA .local_opcode // ok
|
||||
STA label(.local_opcode) // ok
|
||||
STA .local_opcode + 1 // ok
|
||||
STA label(.local_opcode) + 1 // ok
|
||||
STA global_opcode // ok
|
||||
STA label(global_opcode) // ok
|
||||
STA global_opcode + 1 // NOT OK
|
||||
sta label(global_opcode) + 1 // ok
|
||||
|
||||
Assembly can refer to variables and constants defined in Millfork,
|
||||
but you need to be careful with using absolute vs immediate addressing:
|
||||
|
@ -70,7 +81,7 @@ but you need to be careful with using absolute vs immediate addressing:
|
|||
}
|
||||
|
||||
Any assembly opcode can be prefixed with `?`, which allows the optimizer change it or elide it if needed.
|
||||
Opcodes without that prefix will be always compiled as written.
|
||||
Opcodes without that prefix will always be compiled as written.
|
||||
|
||||
The '!' prefix marks the statement as volatile, which means it will be a subject to certain, but not all optimizations,
|
||||
in order to preserve its semantics.
|
||||
|
@ -113,7 +124,7 @@ the return type can be any valid return type, like for Millfork functions.
|
|||
If the size of the return type is one byte,
|
||||
then the result is passed via the accumulator.
|
||||
If the size of the return type is two bytes,
|
||||
then the low byte of the result is passed via the accumulator
|
||||
then the low byte of the result is passed via the accumulator,
|
||||
and the high byte of the result is passed via the X register.
|
||||
|
||||
|
||||
|
@ -220,7 +231,7 @@ it should abide to the following rules:
|
|||
|
||||
* explicitly use 16-bit immediate operands when appropriate; the assembler doesn't track flags and assumes 8-bit immediates by default (TODO: actually implement the 16-bit inline assembly correctly)
|
||||
|
||||
* use far jumps unless you're sure that the called function returns with an `RTS`
|
||||
* use far jumps unless you are sure the called function returns with an `RTS`
|
||||
|
||||
* on 65CE02:
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ There are two ways to include raw assembly code in your Millfork programs:
|
|||
|
||||
Millfork inline assembly uses the same three-letter opcodes as most other 6809 assemblers.
|
||||
|
||||
Labels have to be followed by a colon and they can optionally be on a separate line.
|
||||
Labels have to be followed by a colon, and they can optionally be on a separate line.
|
||||
Indentation is not important:
|
||||
|
||||
first: INC a
|
||||
|
@ -23,9 +23,20 @@ Indentation is not important:
|
|||
INC c
|
||||
|
||||
|
||||
Label names have to start with a letter and can contain digits, underscores and letters.
|
||||
This means than they cannot start with a period like in many other assemblers.
|
||||
Similarly, anonymous labels designated with `+` or `-` are also not supported.
|
||||
Global label names have to start with a letter and can contain digits, underscores and letters.
|
||||
Local label names (available since Millfork 0.3.22) start with a period and are visible only in the given function.
|
||||
Anonymous labels designated with `+` or `-` are also not supported.
|
||||
|
||||
Referring to a global label with an offset requires wrapping it in `label(…)`:
|
||||
|
||||
STA .local_opcode // ok
|
||||
STA label(.local_opcode) // ok
|
||||
STA .local_opcode + 1 // ok
|
||||
STA label(.local_opcode) + 1 // ok
|
||||
STA global_opcode // ok
|
||||
STA label(global_opcode) // ok
|
||||
STA global_opcode + 1 // NOT OK
|
||||
STA label(global_opcode) + 1 // ok
|
||||
|
||||
Assembly can refer to variables and constants defined in Millfork,
|
||||
but you need to be careful with using absolute vs immediate addressing:
|
||||
|
@ -52,7 +63,7 @@ You can use `>` do signify the absolute addressing mode, but it is never necessa
|
|||
This option exists only for compatibility with other assemblers.
|
||||
|
||||
Any assembly opcode can be prefixed with `?`, which allows the optimizer change it or elide it if needed.
|
||||
Opcodes without that prefix will be always compiled as written.
|
||||
Opcodes without that prefix will always be compiled as written.
|
||||
|
||||
The '!' prefix marks the statement as volatile, which means it will be a subject to certain, but not all optimizations,
|
||||
in order to preserve its semantics.
|
||||
|
|
|
@ -32,7 +32,7 @@ It does not support instructions that are unavailable on the Z80 or other undocu
|
|||
|
||||
Not all ZX Spectrum Next instructions are supported. `JP (C)`, `BSLA` and similar instructions are not supported.
|
||||
|
||||
Labels have to be followed by a colon and they can optionally be on a separate line.
|
||||
Labels have to be followed by a colon, and they can optionally be on a separate line.
|
||||
Indentation is not important:
|
||||
|
||||
// Zilog syntax
|
||||
|
@ -48,9 +48,20 @@ Indentation is not important:
|
|||
INR c
|
||||
|
||||
|
||||
Label names have to start with a letter and can contain digits, underscores and letters.
|
||||
This means than they cannot start with a period like in many other assemblers.
|
||||
Similarly, anonymous labels designated with `+` or `-` are also not supported.
|
||||
Global label names have to start with a letter and can contain digits, underscores and letters.
|
||||
Local label names (available since Millfork 0.3.22) start with a period and are visible only in the given function.
|
||||
Anonymous labels designated with `+` or `-` are also not supported.
|
||||
|
||||
Referring to a global label with an offset requires wrapping it in `label(…)`:
|
||||
|
||||
LD (.local_opcode),A // ok
|
||||
LD (label(.local_opcode)),A // ok
|
||||
LD (.local_opcode + 1),A // ok
|
||||
LD (label(.local_opcode) + 1),A // ok
|
||||
LD (global_opcode),A // ok
|
||||
LD (label(global_opcode)),A // ok
|
||||
LD (global_opcode + 1),A // NOT OK
|
||||
LD (label(global_opcode) + 1),A // ok
|
||||
|
||||
Assembly can refer to variables and constants defined in Millfork,
|
||||
but you need to be careful with using absolute vs immediate addressing:
|
||||
|
@ -75,7 +86,7 @@ but you need to be careful with using absolute vs immediate addressing:
|
|||
}
|
||||
|
||||
Any assembly opcode can be prefixed with `?`, which allows the optimizer change it or elide it if needed.
|
||||
Opcodes without that prefix will be always compiled as written.
|
||||
Opcodes without that prefix will always be compiled as written.
|
||||
|
||||
The '!' prefix marks the statement as volatile, which means it will be a subject to certain, but not all optimizations,
|
||||
in order to preserve its semantics.
|
||||
|
@ -263,8 +274,8 @@ Intel syntax | Zilog syntax
|
|||
**SLAY d** | **SLA IY(d)**
|
||||
**SRAY d** | **SRA IY(d)**
|
||||
**SRLY d** | **SRL IY(d)**
|
||||
**SLLR r** | **SLL r**
|
||||
**SLLY d** | **SLL IY(d)**
|
||||
**SLLR r** | **SLL r**, SLS r
|
||||
**SLLY d** | **SLL IY(d)**, SLS IY(d)
|
||||
**SPIY** | **LD SP,IY**
|
||||
**PUSHIY**, PUSH IY | **PUSH IY**
|
||||
**POPIY**, POP IY | **POP IY**
|
||||
|
|
|
@ -16,7 +16,7 @@ No other lines are allowed in the file.
|
|||
* `NAME=<name>` defines the name for this encoding. Required.
|
||||
|
||||
* `BUILTIN=<internal name>` defines this encoding to be a UTF-based encoding.
|
||||
`<internal name>` may be one of `UTF-8`, `UTF-16LE`, `UTF-16BE`.
|
||||
`<internal name>` may be one of `UTF-8`, `UTF-16LE`, `UTF-16BE`, `UTF-32LE`, `UTF-32BE`.
|
||||
If this directive is present, the only other allowed directive in the file is the `NAME` directive.
|
||||
|
||||
* `EOT=<xx>` where `<xx>` are two hex digits, defines the string terminator byte.
|
||||
|
|
|
@ -4,17 +4,17 @@
|
|||
|
||||
Syntax:
|
||||
|
||||
`[segment (<segment>)] [<modifiers>] <return_type> <name> ( <params> ) [align ( <alignment> )] [@ <address>] { <body> }`
|
||||
`[segment (<segment>)] [<modifiers>] <return_type> <name> ( <params> ) [align ( <alignment> )] [<optimization hints>] [@ <address>] { <body> }`
|
||||
|
||||
`[segment (<segment>)] [<modifiers>] <return_type> <name> ( <params> ) [align ( <alignment> )] [@ <address>] = <expression>`
|
||||
`[segment (<segment>)] [<modifiers>] <return_type> <name> ( <params> ) [align ( <alignment> )] [<optimization hints>] [@ <address>] = <expression>`
|
||||
|
||||
`[segment (<segment>)] asm <return_type> <name> ( <params> ) @ <address> extern`
|
||||
`[segment (<segment>)] asm <return_type> <name> ( <params> ) [<optimization hints>] @ <address> extern`
|
||||
|
||||
Examples:
|
||||
|
||||
void do_nothing() { }
|
||||
inline byte two() = 2
|
||||
extern asm void chkout(byte register(a) char) @ $FFD2
|
||||
asm void chkout(byte register(a) char) !preserves_x !preserves_y @ $FFD2 extern
|
||||
segment(prgrom0) void main_loop(word w, byte x) align(fast) { // body omitted
|
||||
|
||||
|
||||
|
@ -39,7 +39,7 @@ Examples:
|
|||
You are not allowed to call such functions directly.
|
||||
The function cannot have parameters and the return type should be `void`.
|
||||
|
||||
* `kernal_interrupt` – the function is an interrupt handler called from a generic vendor-provider hardware interrupt handler.
|
||||
* `kernal_interrupt` – the function is an interrupt handler called from a generic vendor-provided hardware interrupt handler.
|
||||
The hardware instruction handler is assumed to have preserved the CPU registers,
|
||||
so this function only has to preserve the zeropage pseudoregisters.
|
||||
An example is the Commodore 64 interrupt handler that calls the function at an address read from $314/$315.
|
||||
|
@ -68,6 +68,8 @@ For assembly functions, certain parameter names are interpreted as CPU registers
|
|||
* on 6502, it means that the function will not cross a page boundary if possible
|
||||
* on Z80, it is ignored
|
||||
|
||||
* `<optimization hints>` is a list of [optimization hints](./hints.md), separated by spaces
|
||||
|
||||
* `<address>` is a constant expression that defines where in the memory the function is or will be located.
|
||||
|
||||
* `extern` is a keyword than marks functions that are not defined in the current program,
|
||||
|
@ -78,16 +80,19 @@ Such functions should be marked as written in assembly and should have their par
|
|||
|
||||
* `<expression>` is an expression. It is equivalent to a function body of form `{ return <expression> }`.
|
||||
|
||||
The address of an non-macro function `f` is a constant `f.addr`.
|
||||
The address of a non-macro function `f` is a constant `f.addr`.
|
||||
|
||||
Non-macro, non-interrupt functions which have max one parameter of size max 2 bytes
|
||||
and return `void` or a value of size max 2 bytes,
|
||||
can be accessed via a pointer.
|
||||
|
||||
void f() {}
|
||||
void g(byte x) {}
|
||||
|
||||
function.void.to.void p = f.pointer
|
||||
function.byte.to.void p = g.pointer
|
||||
|
||||
call(p)
|
||||
call(p, 13)
|
||||
|
||||
The value of the pointer `f.pointer` may not be the same as the value of the function address `f.addr`.
|
||||
|
|
84
docs/lang/hints.md
Normal file
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
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -14,7 +14,14 @@ Octal: `0o172`
|
|||
|
||||
Hexadecimal: `$D323`, `0x2a2`
|
||||
|
||||
When using Intel syntax for inline assembly, another hexadecimal syntax is available: `0D323H`, `2a2h`.
|
||||
Digits can be separated by underscores for readability. Underscores are also allowed between the radix prefix and the digits:
|
||||
|
||||
123_456
|
||||
0x01_ff
|
||||
0b_0101_1111__1100_0001
|
||||
$___________FF
|
||||
|
||||
When using Intel syntax for inline assembly, another hexadecimal syntax is available: `0D323H`, `2a2h`, `3e_h`.
|
||||
It is not allowed in any other places.
|
||||
|
||||
The type of a literal is the smallest type of undefined signedness
|
||||
|
@ -63,9 +70,9 @@ The byte constant `nullchar` is defined to be equal to the string terminator in
|
|||
and the byte constant `nullchar_scr` is defined to be equal to the string terminator in the `scr` encoding (`'{nullchar}'scr`).
|
||||
|
||||
You can override the values for `nullchar` and `nullchar_scr`
|
||||
by defining preprocesor features `NULLCHAR` and `NULLCHAR_SCR` respectively.
|
||||
by defining preprocessor features `NULLCHAR` and `NULLCHAR_SCR` respectively.
|
||||
|
||||
Warning: If you define UTF-16 to be you default or screen encoding, you will encounter several problems:
|
||||
Warning: If you define UTF-16 or UTF-32 to be you default or screen encoding, you will encounter several problems:
|
||||
|
||||
* `nullchar` and `nullchar_scr` will still be bytes, equal to zero.
|
||||
* the `string` module in the Millfork standard library will not work correctly
|
||||
|
@ -75,21 +82,26 @@ Warning: If you define UTF-16 to be you default or screen encoding, you will enc
|
|||
You can also prepend `p` to the name of the encoding to make the string length-prefixed.
|
||||
|
||||
The length is measured in bytes and doesn't include the zero terminator, if present.
|
||||
In all encodings except for UTF-16 the prefix takes one byte,
|
||||
In all encodings except for UTF-16 and UTF-32 the prefix takes one byte,
|
||||
which means that length-prefixed strings cannot be longer than 255 bytes.
|
||||
|
||||
In case of UTF-16, the length prefix contains the number of code units,
|
||||
so the number of bytes divided by two,
|
||||
which allows for strings of practically unlimited length.
|
||||
The length is stores as two bytes and is always little endian,
|
||||
The length is stored as two bytes and is always little endian,
|
||||
even in case of the `utf16be` encoding or a big-endian processor.
|
||||
|
||||
In case of UTF-32, the length prefix contains the number of Unicode codepoints,
|
||||
so the number of bytes divided by four.
|
||||
The length is stored as four bytes and is always little endian,
|
||||
even in case of the `utf32be` encoding or a big-endian processor.
|
||||
|
||||
"this is a Pascal string" pascii
|
||||
"this is also a Pascal string"p
|
||||
"this is a zero-terminated Pascal string"pz
|
||||
|
||||
Note: A string that's both length-prefixed and zero-terminated does not count as a normal zero-terminated string!
|
||||
To pass it to a function that expects a zero-terminated string, add 1 (or, in case of UTF-16, 2):
|
||||
To pass it to a function that expects a zero-terminated string, add 1 (or, in case of UTF-16, 2, or UTF-32, 4):
|
||||
|
||||
pointer p
|
||||
p = "test"pz
|
||||
|
|
|
@ -11,7 +11,8 @@ Each module has a name, which is its unique identifier.
|
|||
A module name is a sequence of slash-separated valid Millfork identifiers.
|
||||
The name also defines where the module is located:
|
||||
a module named `a/b` is presumed to exist in `a/b.mfk`
|
||||
and it's looked up first in the current working directory,
|
||||
and it's looked up first in the directory that contains the current source file,
|
||||
then in the current working directory,
|
||||
and then in the include directories.
|
||||
|
||||
A module can import other modules, using the `import` statement.
|
||||
|
|
|
@ -18,9 +18,9 @@ Millfork has different operator precedence compared to most other languages. Fro
|
|||
|
||||
* `->` and `[]`
|
||||
|
||||
* `*`, `*'`, `/`, `%%`
|
||||
* `*`, `$*`, `/`, `%%`
|
||||
|
||||
* `+`, `+'`, `-`, `-'`, `|`, `&`, `^`, `>>`, `>>'`, `<<`, `<<'`, `>>>>`
|
||||
* `+`, `$+`, `-`, `$-`, `|`, `&`, `^`, `>>`, `$>>`, `<<`, `$<<`, `>>>>`
|
||||
|
||||
* `:`
|
||||
|
||||
|
@ -34,13 +34,19 @@ Millfork has different operator precedence compared to most other languages. Fro
|
|||
|
||||
You cannot use two different operators at the same precedence levels without using parentheses to disambiguate.
|
||||
It is to prevent confusion about whether `a + b & c << d` means `(a + b) & (c << d)` `((a + b) & c) << d` or something else.
|
||||
The only exceptions are `+` and `-`, and `+'` and `-'`.
|
||||
They are interpreted as expected: `5 - 3 + 2 == 4` and `5 -' 3 +' 2 == 4`.
|
||||
Note that you cannot mix `+'` and `-'` with `+` and `-`.
|
||||
The only exceptions are `+` and `-`, and `$+` and `$-`.
|
||||
They are interpreted as expected: `5 - 3 + 2 == 4` and `5 $- 3 $+ 2 == 4`.
|
||||
Note that you cannot mix `$+` and `$-` with `+` and `-`.
|
||||
|
||||
Certain operators (`/`, `%%`, `<<`, `>>`, `<<'`, `>>'`, `>>>>`, `:`, `!=`) cannot have more than 2 parameters,
|
||||
Certain operators (`/`, `%%`, `<<`, `>>`, `$<<`, `$>>`, `>>>>`, `:`, `!=`) cannot have more than 2 parameters,
|
||||
i.e. `x / y / z` will not compile.
|
||||
|
||||
The decimal operators have two different forms:
|
||||
|
||||
* apostrophe form (e.g. `+'`) – the original one, deprecated, will be removed in Millfork 0.4
|
||||
|
||||
* dollar form (e.g. `$+`) – available since Millfork 0.3.22
|
||||
|
||||
## Argument types
|
||||
|
||||
In the descriptions below, arguments to the operators are explained as follows:
|
||||
|
@ -82,14 +88,14 @@ TODO
|
|||
|
||||
## Binary arithmetic operators
|
||||
|
||||
* `+`, `-`:
|
||||
* `+`, `-`: addition and subtraction
|
||||
`byte + byte`
|
||||
`constant word + constant word`
|
||||
`constant long + constant long`
|
||||
`constant word + byte`
|
||||
`word + word` (zpreg)
|
||||
|
||||
* `*`: multiplication; the size of the result is the same as the size of the arguments
|
||||
* `*`: multiplication (signed or unsigned); the size of the result is the same as the size of the largest of the arguments
|
||||
`byte * constant byte`
|
||||
`constant byte * byte`
|
||||
`constant word * constant word`
|
||||
|
@ -129,17 +135,20 @@ These operators work using the decimal arithmetic (packed BCD).
|
|||
|
||||
On Ricoh-based targets (e.g. Famicom) they require the zeropage register to have size at least 4
|
||||
|
||||
* `+'`, `-'`: decimal addition/subtraction
|
||||
`byte +' byte`
|
||||
`constant word +' constant word`
|
||||
`constant long +' constant long`
|
||||
`word +' word` (zpreg)
|
||||
* `$+`, `$-`: decimal addition/subtraction
|
||||
`+'`, `-'`: (deprecated form)
|
||||
`byte $+ byte`
|
||||
`constant word $+ constant word`
|
||||
`constant long $+ constant long`
|
||||
`word $+ word` (zpreg)
|
||||
|
||||
* `*'`: decimal multiplication
|
||||
`constant *' constant`
|
||||
* `$*`: decimal multiplication
|
||||
`*'`: (deprecated form)
|
||||
`constant $* constant`
|
||||
|
||||
* `<<'`, `>>'`: decimal multiplication/division by power of two
|
||||
`byte <<' constant byte`
|
||||
* `$<<`, `$>>`: decimal multiplication/division by power of two
|
||||
`<<'`, `>>'`: (deprecated form)
|
||||
`byte $<< constant byte`
|
||||
|
||||
## Comparison operators
|
||||
|
||||
|
@ -192,7 +201,8 @@ An expression of form `a[f()] += b` may call `f` an undefined number of times.
|
|||
`mutable word = word`
|
||||
`mutable long = long`
|
||||
|
||||
* `+=`, `+'=`, `|=`, `^=`, `&=`: modification in place
|
||||
* `+=`, `$+=`, `|=`, `^=`, `&=`: modification in place
|
||||
`+'=` (deprecated form)
|
||||
`mutable byte += byte`
|
||||
`mutable word += word`
|
||||
`mutable trivial long += long`
|
||||
|
@ -202,12 +212,14 @@ An expression of form `a[f()] += b` may call `f` an undefined number of times.
|
|||
`mutable word <<= byte`
|
||||
`mutable trivial long <<= byte`
|
||||
|
||||
* `<<'=`, `>>'=`: decimal shift in place
|
||||
`mutable byte <<'= constant byte`
|
||||
`mutable word <<'= constant byte`
|
||||
`mutable trivial long <<'= constant byte`
|
||||
* `$<<=`, `$>>=`: decimal shift in place
|
||||
`<<'=`, `>>'=` (deprecated form)
|
||||
`mutable byte $<<= constant byte`
|
||||
`mutable word $<<= constant byte`
|
||||
`mutable trivial long $<<= constant byte`
|
||||
|
||||
* `-=`, `-'=`: subtraction in place
|
||||
* `-=`, `$-=`: subtraction in place
|
||||
`-'=` (deprecated form)
|
||||
`mutable byte -= byte`
|
||||
`mutable word -= simple word`
|
||||
`mutable trivial long -= simple long`
|
||||
|
@ -218,8 +230,9 @@ An expression of form `a[f()] += b` may call `f` an undefined number of times.
|
|||
`mutable word *= unsigned byte` (zpreg)
|
||||
`mutable word *= word` (zpreg)
|
||||
|
||||
* `*'=`: decimal multiplication in place
|
||||
`mutable byte *'= constant byte`
|
||||
* `$*=`: decimal multiplication in place
|
||||
`*'=` (deprecated form)
|
||||
`mutable byte $*= constant byte`
|
||||
|
||||
* `/=`, `%%=`: unsigned division and modulo in place
|
||||
`mutable unsigned byte /= unsigned byte` (zpreg)
|
||||
|
@ -278,9 +291,9 @@ but you can access its fields or take its pointer:
|
|||
|
||||
* `nonet`: expansion of an 8-bit operation to a 9-bit operation
|
||||
`nonet(byte + byte)`
|
||||
`nonet(byte +' byte)`
|
||||
`nonet(byte $+ byte)`
|
||||
`nonet(byte << constant byte)`
|
||||
`nonet(byte <<' constant byte)`
|
||||
`nonet(byte $<< constant byte)`
|
||||
Other kinds of expressions than the above (even `nonet(byte + byte + byte)`) will not work as expected.
|
||||
|
||||
* `hi`, `lo`: most/least significant byte of a word
|
||||
|
@ -297,7 +310,16 @@ but not
|
|||
some enum → `word`
|
||||
|
||||
* `sizeof`: size of the argument in bytes; the argument can be an expression or a type,
|
||||
and the result is a constant of either `byte` or `word` type, depending on the actual value
|
||||
and the result is a constant of either `byte` or `word` type, depending on the actual value.
|
||||
In case of aligned types, this returns the aligned size.
|
||||
|
||||
* `typeof`: a word constant that identifies the type of the argument; the argument can be an expression or a type.
|
||||
The argument is never evaluated.
|
||||
**Warnings:**
|
||||
* **This is a highly experimental feature.**
|
||||
* The exact values may change in any future version of the compiler. Only compare one `typeof` to another `typeof`.
|
||||
* There is no guarantee that different types will have different values of `typeof`. Indeed, it's even easy to see that a Millfork program can have more than 65536 types – and values of `typeof` can clash even before that.
|
||||
* In certain circumstances, pointer types and function pointer types may have different `typeof` values even if they're essentially the same.
|
||||
|
||||
* `call`: calls a function via a pointer;
|
||||
the first argument is the pointer to the function;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -103,6 +103,8 @@ Some libraries may require that some of these be defined.
|
|||
|
||||
* `KEYBOARD` – 1 if the target has a keyboard, 0 otherwise
|
||||
|
||||
* `DISPLACED_MAIN` – set this to 1 if the `main` function is in a very unusual location for the target
|
||||
|
||||
* `USE_MOUSE_MBM` – set this to 1 if you want to enable middle button support for the mouse.
|
||||
|
||||
* `JOYSTICKS` – the maximum number of joysticks using standard hardware configurations, may be 0
|
||||
|
@ -151,11 +153,40 @@ The `if` function returns its second parameter if the first parameter is defined
|
|||
// prints 500:
|
||||
#infoeval if(0, 400, 500)
|
||||
|
||||
TODO
|
||||
`not`, `lo`, `hi`, `min`, `max` `+`, `-`, `*`, `|`, `&`, `^`, `||`, `&&`, `<<`, `>>`,`==`, `!=`, `>`, `>=`, `<`, `<=`
|
||||
The `min` and `max` functions return the smallest or largest parameter respectively. They support any number of arguments:
|
||||
|
||||
// prints 400:
|
||||
#infoeval min(400, 500, 600)
|
||||
// prints 500:
|
||||
#infoeval max(400, 500)
|
||||
|
||||
The following Millfork operators and functions are also available in the preprocessor:
|
||||
`not`, `lo`, `hi`, `+`, `-`, `*`, `|`, `&`, `^`, `||`, `&&`, `<<`, `>>`,`==`, `!=`, `>`, `>=`, `<`, `<=`
|
||||
|
||||
The following Millfork operators and functions are not available in the preprocessor:
|
||||
`+'`, `-'`, `*'`, `<<'`, `>>'`, `:`, `>>>>`, `nonet`, all the assignment operators
|
||||
`$+`, `$-`, `$*`, `$<<`, `$>>`, `:`, `>>>>`, `nonet`, all the assignment operators
|
||||
|
||||
|
||||
### Character literals
|
||||
|
||||
Preprocessor supports character literals. By default, they are interpreted in the default encoding,
|
||||
but you can suffix them with other encodings.
|
||||
|
||||
// usually prints 97:
|
||||
#infoeval 'a'
|
||||
// prints 97:
|
||||
#infoeval 'a'ascii
|
||||
|
||||
Exceptionally, you can suffix the character literal with `utf32`.
|
||||
This gives the literal the value of the Unicode codepoint of the character:
|
||||
|
||||
// may print 94, 96, 112, 173, 176, 184, 185, 222, 227, 234, 240, something else, or even fail to compile:
|
||||
#infoeval 'π'
|
||||
// prints 960:
|
||||
#infoeval 'π'utf32
|
||||
|
||||
Escape sequences are supported, as per encoding. `utf32` pseudoencoding supports the same escape sequences as `utf8`.
|
||||
|
||||
|
||||
### `#template`
|
||||
|
||||
|
|
52
docs/lang/suffixes.md
Normal file
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,12 +63,14 @@ Examples:
|
|||
|
||||
* `volatile` means that the variable is volatile.
|
||||
The optimizer shouldn't remove or reorder accesses to volatile variables.
|
||||
Volatile variables (unline non-volatile ones) will not be removed or inlined by the optimizer.
|
||||
Volatile variables (unlike non-volatile ones) will not be removed or inlined by the optimizer.
|
||||
Volatile variables cannot be declared as `register` or `stack`.
|
||||
|
||||
* `<storage>` can be only specified for local variables. It can be either `stack`, `static`, `register` or nothing.
|
||||
`register` is only a hint for the optimizer.
|
||||
See [the description of variable storage](../abi/variable-storage.md).
|
||||
|
||||
* `<optimization hints>` is a list of [optimization hints](./hints.md), separated by spaces
|
||||
|
||||
* `<address>` is a constant expression that defines where in the memory the variable will be located.
|
||||
If not specified, it will be located according to the usual allocation rules.
|
||||
|
@ -87,6 +109,12 @@ For every variable `x` larger than a byte, extra subvariables are defined:
|
|||
* constituent bytes, from low to high: `x.b0`, `x.b1`, `x.b2`, etc.
|
||||
|
||||
* the lowest word: `x.loword` (=`x.b1:x.b0`)
|
||||
|
||||
* if `x` is a typed pointer:
|
||||
|
||||
* a view of as a raw pointer: `x.raw`
|
||||
|
||||
See also [the list of magic suffixes](./suffixes.md).
|
||||
|
||||
### Constant declarations
|
||||
|
||||
|
|
|
@ -26,6 +26,8 @@ TODO: document the file format.
|
|||
|
||||
* `oldpetscii` or `oldpet` – old PETSCII (Commodore PET with newer ROMs)
|
||||
|
||||
* `geos_de` – text encoding used by the German version of GEOS for C64
|
||||
|
||||
* `cbmscr` or `petscr` – Commodore screencodes
|
||||
|
||||
* `cbmscrjp` or `petscrjp` – Commodore screencodes as used on Japanese versions of Commodore 64
|
||||
|
@ -38,6 +40,8 @@ TODO: document the file format.
|
|||
|
||||
* `apple2gs` – Apple IIgs charset
|
||||
|
||||
* `macroman` – Macintosh Western Latin charset
|
||||
|
||||
* `bbc` – BBC Micro character set
|
||||
|
||||
* `sinclair` – ZX Spectrum character set
|
||||
|
@ -52,6 +56,10 @@ TODO: document the file format.
|
|||
|
||||
* `iso_dk`, `iso_fi` – aliases for `iso_no` and `iso_se` respectively
|
||||
|
||||
* `dmcs` – DEC Multinational Character Set
|
||||
|
||||
* `lics` – Lotus International Character Set
|
||||
|
||||
* `iso8859_1`, `iso8859_2`, `iso8859_3`,
|
||||
`iso8859_4`, `iso8859_5`, `iso8859_7`,
|
||||
`iso8859_9`, `iso8859_10`, `iso8859_13`,
|
||||
|
@ -74,6 +82,8 @@ ISO 8859-14, ISO 8859-15, ISO 8859-16,
|
|||
* `iso_15`, `latin9`, `latin0` – aliases for `iso8859_15`
|
||||
* `iso16`, `latin10` – aliases for `iso8859_16`
|
||||
|
||||
* `brascii` – BraSCII
|
||||
|
||||
* `cp437`, `cp850`, `cp851`, `cp852`, `cp855`, `cp858`, `cp866` –
|
||||
DOS codepages 437, 850, 851, 852, 855, 858, 866
|
||||
|
||||
|
@ -81,7 +91,7 @@ DOS codepages 437, 850, 851, 852, 855, 858, 866
|
|||
|
||||
* `kamenicky` – Kamenický encoding
|
||||
|
||||
* `cp1250`, `cp1251`, `cp1252` – Windows codepages 1250, 1251, 1252
|
||||
* `cp1250`, `cp1251`, `cp1252`, `cp1253`, `cp1254`, `cp1257` – Windows codepages 1250, 1251, 1252, 1253, 1254, 1257
|
||||
|
||||
* `msx_intl`, `msx_jp`, `msx_ru`, `msx_br` – MSX character encoding, International, Japanese, Russian and Brazilian respectively
|
||||
|
||||
|
@ -108,16 +118,24 @@ English, Japanese, Spanish/Italian and French/German respectively
|
|||
|
||||
* `galaksija` – text encoding used on Galaksija computers
|
||||
|
||||
* `trs80m1` – text encoding used on TRS-80 Model 1
|
||||
|
||||
* `trs80m3` – text encoding used on TRS-80 Model 3
|
||||
|
||||
* `coco` – text encoding used on Tandy Color Computer
|
||||
|
||||
* `cocoscr` – Tandy Color Computer screencodes
|
||||
|
||||
* `z1013` – text encodind used on Robotron Z1013
|
||||
|
||||
* `ebcdic` – EBCDIC codepage 037 (partial coverage)
|
||||
|
||||
* `utf8` – UTF-8
|
||||
|
||||
* `utf16be`, `utf16le` – UTF-16BE and UTF-16LE
|
||||
|
||||
* `utf32be`, `utf32le` – UTF-32BE and UTF-32LE
|
||||
|
||||
When programming for Commodore,
|
||||
use `petscii` for strings you're printing using standard I/O routines
|
||||
and `petsciiscr` for strings you're copying to screen memory directly.
|
||||
|
@ -149,10 +167,12 @@ The exact value of `{nullchar}` is encoding-dependent:
|
|||
* in the `zx80` encoding it's `{x01}`,
|
||||
* in the `zx81` encoding it's `{x0b}`,
|
||||
* in the `petscr` and `petscrjp` encodings it's `{xe0}`,
|
||||
* in the `apple2e` encoding it's `{x7f}`,
|
||||
* in the `atasciiscr` encoding it's `{xdb}`,
|
||||
* in the `pokemon1*` encodings it's `{x50}`,
|
||||
* in the `cocoscr` encoding it's exceptionally two bytes: `{xd0}`
|
||||
* in the `utf16be` and `utf16le` encodings it's exceptionally two bytes: `{x00}{x00}`
|
||||
* in the `utf32be` and `utf32le` encodings it's exceptionally four bytes: `{x00}{x00}{x00}{x00}`
|
||||
* in other encodings it's `{x00}` (this may be a subject to change in future versions).
|
||||
|
||||
##### Available only in some encodings
|
||||
|
@ -197,12 +217,16 @@ Encoding | lowercase letters | backslash | currencies | intl | card suits
|
|||
`petscr` | yes¹ | no | £ | none | yes¹
|
||||
`petjp` | no | no | ¥ | katakana³ | yes³
|
||||
`petscrjp` | no | no | ¥ | katakana³ | yes³
|
||||
`geos_de` | yes | no | | | no
|
||||
`sinclair`, `bbc` | yes | yes | £ | none | no
|
||||
`zx80`, `zx81` | no | no | £ | none | no
|
||||
`apple2` | no | yes | | none | no
|
||||
`atascii` | yes | yes | | none | yes
|
||||
`atasciiscr` | yes | yes | | none | yes
|
||||
`z1013` | yes | yes | | none | yes
|
||||
`jis` | yes | no | ¥ | both kana | no
|
||||
`dmcs`,`lics` | yes | yes | ¢£¥ | Western | no
|
||||
`brascii`,`macroman`| yes | yes | ¢£¥ | Western | no
|
||||
`msx_intl`,`msx_br` | yes | yes | ¢£¥ | Western | yes
|
||||
`msx_jp` | yes | no | ¥ | katakana | yes
|
||||
`msx_ru` | yes | yes | | Russian⁴ | yes
|
||||
|
@ -256,6 +280,7 @@ Encoding | new line | braces | backspace | cursor movement | text colour | rever
|
|||
`origpet` | yes | no | no | yes | no | yes | no
|
||||
`oldpet` | yes | no | no | yes | no | yes | no
|
||||
`petscr`, `petscrjp`| no | no | no | no | no | no | no
|
||||
`geos_de` | no | no | no | no | no | yes | no
|
||||
`sinclair` | yes | yes | no | yes | yes | yes | yes
|
||||
`zx80`,`zx81` | yes | no | yes | yes | no | no | no
|
||||
`ascii`, `iso_*` | yes | yes | yes | no | no | no | no
|
||||
|
|
|
@ -69,6 +69,14 @@ or forcing zero extension or sign extension:
|
|||
x = y // does zero extension and assigns value $0080
|
||||
x = sbyte(y) // does sign extension and assigns value $FF80
|
||||
|
||||
You can also explicitly convert expressions of type `bool` to any numeric type.
|
||||
`false` is converted to 0 and `true` is converted to 1.
|
||||
|
||||
byte a,b,c
|
||||
a = 5
|
||||
b = byte(a == 4) // b is now equal to 0
|
||||
c = byte(a == 5) // c is now equal to 1
|
||||
|
||||
## Typed pointers
|
||||
|
||||
For every type `T`, there is a pointer type defined called `pointer.T`.
|
||||
|
@ -126,11 +134,33 @@ Using `call` on 6502 requires at least 4 bytes of zeropage pseudoregister.
|
|||
|
||||
The value of the pointer `f.pointer` may not be the same as the value of the function address `f.addr`.
|
||||
|
||||
## Interrupt handler pointers
|
||||
|
||||
Functions that are interrupt pointers have their own pointer types:
|
||||
|
||||
* `pointer.interrupt` for hardware interrupt handlers
|
||||
|
||||
* `pointer.kernal_interrupt` for kernal interrupt handlers
|
||||
|
||||
`pointer.kernal_interrupt` is automatically convertible to `function.void.to.void`
|
||||
|
||||
interrupt void handler1(){}
|
||||
kernal_interrupt void handler2(){}
|
||||
|
||||
pointer.interrupt p1
|
||||
p1 = handler1.pointer
|
||||
pointer.kernal_interrupt p2
|
||||
p2 = handler2.pointer
|
||||
function.void.to.void p3
|
||||
p3 = handler2.pointer
|
||||
|
||||
## Boolean types
|
||||
|
||||
Boolean types can be used as conditions. They have two possible values, `true` and `false`.
|
||||
|
||||
* `bool` – a 1-byte boolean value. An uninitialized variable of type `bool` may contain an invalid value.
|
||||
* `bool` – a 1-byte boolean value.
|
||||
An uninitialized variable of type `bool` may contain an invalid value.
|
||||
The value `false` is stored as 0, `true` as 1.
|
||||
|
||||
* several boolean types based on the CPU flags that may be used only as a return type for a function written in assembly:
|
||||
|
||||
|
@ -146,6 +176,10 @@ Boolean types can be used as conditions. They have two possible values, `true` a
|
|||
|
||||
2\. LR35902 does not support these types due to the lack of appropriate flags
|
||||
|
||||
You can convert from a boolean type to an arithmetic type by simply casting:
|
||||
|
||||
byte c = byte(x >= 0x80)
|
||||
|
||||
Examples:
|
||||
|
||||
bool f() = true
|
||||
|
@ -222,11 +256,24 @@ as there are no checks on values when converting bytes to enumeration values and
|
|||
|
||||
## Structs
|
||||
|
||||
Struct is a compound type containing multiple fields of various types:
|
||||
Struct is a compound type containing multiple fields of various types.
|
||||
A struct is represented in memory as a contiguous area of variables or arrays laid out one after another.
|
||||
|
||||
struct <name> [align (alignment)] { <field definitions (type and name), separated by commas or newlines>}
|
||||
Declaration syntax:
|
||||
|
||||
A struct is represented in memory as a contiguous area of variables laid out one after another.
|
||||
struct <name> [align (alignment)] { <field definitions, separated by commas or newlines>}
|
||||
|
||||
where a field definition is either:
|
||||
|
||||
* `<type> <name>` and defines a scalar field,
|
||||
|
||||
* or `array (<type>) <name> [<size>]`, which defines an array field,
|
||||
where the array contains items of type `<type>`,
|
||||
and either contains `<size>` elements
|
||||
if `<size>` is a constant expression between 0 and 127,
|
||||
or, if `<size>` is a plain enumeration type, the array is indexed by that type,
|
||||
and the number of elements is equal to the number of variants in that enumeration.
|
||||
`(<type>)` can be omitted and defaults to `byte`.
|
||||
|
||||
Struct can have a maximum size of 255 bytes. Larger structs are not supported.
|
||||
|
||||
|
@ -256,8 +303,8 @@ All arguments to the constructor must be constant.
|
|||
|
||||
Structures declared with an alignment are allocated at appropriate memory addresses.
|
||||
The alignment has to be a power of two.
|
||||
If the structs are in an array, they are padded with unused bytes.
|
||||
If the struct is smaller that its alignment, then arrays of it are faster
|
||||
If the structs with declared alignment are in an array, they are padded with unused bytes.
|
||||
If the struct is smaller that its alignment, then arrays of it are faster than if it were not aligned
|
||||
|
||||
struct a align(4) { byte x,byte y, byte z }
|
||||
struct b { byte x,byte y, byte z }
|
||||
|
@ -269,12 +316,21 @@ If the struct is smaller that its alignment, then arrays of it are faster
|
|||
sizeof(a) // equals 16
|
||||
sizeof(b) // equals 12
|
||||
|
||||
return a[i].x // requires XXXX cycles on 6502
|
||||
return b[i].x // requires XXXX cycles on 6502
|
||||
return a[i].x // requires 22 or 24 cycles on 6502
|
||||
return b[i].x // requires 18 cycles on 6502
|
||||
|
||||
A struct that contains substructs or subunions with non-trivial alignments has its alignment equal
|
||||
to the least common multiple of the alignments of the substructs and its own declared alignment.
|
||||
|
||||
**Warning:** Limitations of array fields:
|
||||
|
||||
* Structs containing arrays cannot be allocated on the stack.
|
||||
|
||||
* Struct constructors for structs with array fields are not supported.
|
||||
|
||||
## Unions
|
||||
|
||||
union <name> [align (alignment)] { <field definitions (type and name), separated by commas or newlines>}
|
||||
union <name> [align (alignment)] { <field definitions, separated by commas or newlines>}
|
||||
|
||||
Unions are pretty similar to structs, with the difference that all fields of the union
|
||||
start at the same point in memory and therefore overlap each other.
|
||||
|
@ -290,3 +346,5 @@ start at the same point in memory and therefore overlap each other.
|
|||
Offset constants are also available, but they're obviously all zero.
|
||||
|
||||
Unions currently do not have an equivalent of struct constructors. This may be improved on in the future.
|
||||
|
||||
Unions with array fields have the same limitations as structs with array fields.
|
||||
|
|
91
docs/stdlib/apple2.md
Normal file
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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ Available only on 6502-based platforms.
|
|||
|
||||
#### byte atascii_to_atasciiscr(byte)
|
||||
|
||||
Converts a byte from ATASCII to a Atari screencode.
|
||||
Converts a byte from ATASCII to an Atari screencode.
|
||||
Control characters <$80 are converted to the graphical characters that share the ATASCII code.
|
||||
Control characters ≥$80 are not supported.
|
||||
|
||||
|
@ -93,7 +93,7 @@ Available only on 6502-based platforms.
|
|||
|
||||
#### byte atasciiscr_to_atascii(byte)
|
||||
|
||||
Converts a byte from a Atari screencode to ATASCII.
|
||||
Converts a byte from an Atari screencode to ATASCII.
|
||||
Characters that share their ATASCII code with control characters are supported,
|
||||
but they require to be escaped with $1B to be printed.
|
||||
Reverse characters are interpreted as non-reverse characters.
|
||||
|
|
|
@ -49,8 +49,11 @@ ZX Spectrum,
|
|||
NEC PC-88,
|
||||
MSX,
|
||||
Apple II,
|
||||
Commodore 64 with `c64_basic` module (requires KERNAL and BASIC),
|
||||
Commodore 16 or Plus/4 with `c264_basic` module (requires KERNAL and BASIC).
|
||||
Robotron Z1013 (always trims trailing spaces),
|
||||
TRS-80,
|
||||
VIC-20 (except for `vic20_a000`),
|
||||
Commodore 64 with `c64_basic` module (requires KERNAL and BASIC; empty input is treated like a single space),
|
||||
Commodore 16 or Plus/4 with `c264_basic` module (requires KERNAL and BASIC; empty input is treated like a single space).
|
||||
|
||||
#### `word readword()`
|
||||
|
||||
|
@ -61,6 +64,9 @@ ZX Spectrum,
|
|||
NEC PC-88,
|
||||
MSX,
|
||||
Apple II,
|
||||
Robotron Z1013,
|
||||
TRS-80,
|
||||
VIC-20 (except for `vic20_a000`),
|
||||
Commodore 64 with `c64_basic` module (requires KERNAL and BASIC),
|
||||
Commodore 16 or Plus/4 with `c264_basic` module (requires KERNAL and BASIC).
|
||||
|
||||
|
|
|
@ -28,6 +28,8 @@ Atari,
|
|||
Amstrad CPC,
|
||||
ZX Spectrum,
|
||||
NEC PC-88,
|
||||
Robotron Z1013,
|
||||
TRS-80,
|
||||
Tandy Color Computer.
|
||||
|
||||
#### `const byte KEY_ENTER`
|
||||
|
|
|
@ -47,6 +47,6 @@ or `word` if the screen is more that 256 pixels tall.
|
|||
## null_mouse_default
|
||||
|
||||
This module set the default mouse to null mouse.
|
||||
The null mouse has no button pressed and the cursos is fixed at coordinates (0,0).
|
||||
The null mouse has no button pressed and the cursor is fixed at coordinates (0,0).
|
||||
|
||||
#### `void read_mouse()`
|
||||
|
|
|
@ -103,19 +103,19 @@ Provides an interface for reading joypads that is compatible with the [`joy` mod
|
|||
|
||||
#### `alias input_a = input_btn`
|
||||
|
||||
1 if A button pressed, 0 id not pressed.
|
||||
1 if A button pressed, 0 if not pressed.
|
||||
|
||||
#### `byte input_b`
|
||||
|
||||
1 if B button pressed, 0 id not pressed.
|
||||
1 if B button pressed, 0 if not pressed.
|
||||
|
||||
#### `byte input_select`
|
||||
|
||||
1 if Select button pressed, 0 id not pressed.
|
||||
1 if Select button pressed, 0 if not pressed.
|
||||
|
||||
#### `byte input_start`
|
||||
|
||||
1 if Start button pressed, 0 id not pressed.
|
||||
1 if Start button pressed, 0 if not pressed.
|
||||
|
||||
#### `void read_joy1()`
|
||||
|
||||
|
|
|
@ -32,6 +32,8 @@ Current implementation:
|
|||
|
||||
* On C64, spends two frames reading noise data from the SID chip.
|
||||
|
||||
* On Atari computers, reads the POKEY random register.
|
||||
|
||||
* On Z80, reads the refresh register.
|
||||
|
||||
* On all other targets, sets the seed to 1.
|
||||
|
|
21
docs/stdlib/vic20.md
Normal file
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
|
|
@ -19,7 +19,7 @@ Raw addresses are acquired using the `.addr` suffix.
|
|||
The numeric values of the pointer and of the raw address may differ.
|
||||
|
||||
* Operator precedence works differently.
|
||||
Bitwise and bitshift operators have the same precedence as arithmetic operators,
|
||||
Bitwise and bit-shifting operators have the same precedence as arithmetic operators,
|
||||
and mixing different operators with the same precedence is usually forbidden.
|
||||
This prevents most ambiguities in bit-twiddling code, but requires care when porting code from or to C.
|
||||
|
||||
|
@ -34,7 +34,9 @@ This prevents most ambiguities in bit-twiddling code, but requires care when por
|
|||
* Integer literals starting with zero and containing just digits are decimal, not octal.
|
||||
For octal literals, use the `0o` prefix.
|
||||
|
||||
* String literals are not null-terminated by default. Use the `z` suffix for null-terminated strings.
|
||||
* String literals are not null-terminated by default. Use the `z` suffix for null-terminated strings.
|
||||
Note: this is the opposite of what KickC does!
|
||||
Keep this in mind when migrating KickC code to Millfork or the other way around.
|
||||
|
||||
* In `if`, `do/while`, `while` and `for` statements, parentheses are not required, but braces are.
|
||||
The `else` branch also requires braces, unless the only statement in the `else` block is an `if` statement.
|
||||
|
@ -70,7 +72,7 @@ Unlike `#define`, such definitions are not visible within the preprocessor.
|
|||
|
||||
This issue applies mostly to the `*` and `<<` operators.
|
||||
|
||||
* There is no padding in structs.
|
||||
* There is no padding in structs, except before fields whose type is a struct or a union with a non-trivial alignment.
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -1,8 +1,16 @@
|
|||
# Examples
|
||||
|
||||
The examples showcased here are designed to compile with a compiler built from newest sources.
|
||||
The examples showcased here are designed to compile with a compiler built from the newest sources.
|
||||
If you are using a release version of the compiler, consider browsing the older versions of the examples:
|
||||
|
||||
* [for version 0.3.28](https://github.com/KarolS/millfork/tree/v0.3.28/examples)
|
||||
|
||||
* [for version 0.3.26](https://github.com/KarolS/millfork/tree/v0.3.26/examples)
|
||||
|
||||
* [for version 0.3.24](https://github.com/KarolS/millfork/tree/v0.3.24/examples)
|
||||
|
||||
* [for version 0.3.22](https://github.com/KarolS/millfork/tree/v0.3.22/examples)
|
||||
|
||||
* [for version 0.3.18](https://github.com/KarolS/millfork/tree/v0.3.18/examples)
|
||||
|
||||
* [for version 0.3.16](https://github.com/KarolS/millfork/tree/v0.3.16/examples)
|
||||
|
@ -15,25 +23,25 @@ If you are using a release version of the compiler, consider browsing the older
|
|||
|
||||
## Cross-platform examples
|
||||
|
||||
* [Hello world](crossplatform/hello_world.mfk) (C64/C16/PET/VIC-20/Atari/Apple II/BBC Micro/ZX Spectrum/PC-88/Armstrad CPC/MSX) – simple text output
|
||||
* [Hello world](crossplatform/hello_world.mfk) (C64/C16/PET/VIC-20/Atari/Apple II/BBC Micro/ZX Spectrum/PC-88/Armstrad CPC/MSX/Z1013) – simple text output
|
||||
|
||||
* [Fizzbuzz](crossplatform/fizzbuzz.mfk) (C64/C16/PET/VIC-20/PET/Atari/Apple II/BBC Micro/ZX Spectrum/PC-88/Armstrad CPC/MSX/X16) – everyone's favourite programming task
|
||||
|
||||
* [Fizzbuzz 2](crossplatform/fizzbuzz2.mfk) (C64/C16/PET/VIC-20/PET/Atari/Apple II/BBC Micro/ZX Spectrum/PC-88/Armstrad CPC/MSX/CoCo) – an alternative, more extensible implemententation of fizzbuzz
|
||||
* [Fizzbuzz 2](crossplatform/fizzbuzz2.mfk) (C64/C16/PET/VIC-20/PET/Atari/Apple II/BBC Micro/ZX Spectrum/PC-88/Armstrad CPC/MSX/CoCo) – an alternative, more extensible implementation of fizzbuzz
|
||||
|
||||
* [Fizzbuzz JP](crossplatform/fizzbuzz_jp.mfk) (PC-88/Japanese C64) – Fizzbuzz, but in Japanese
|
||||
|
||||
* [Text encodings](crossplatform/text_encodings.mfk) (C64/ZX Spectrum) – examples of text encoding features
|
||||
|
||||
* [Echo](crossplatform/echo.mfk) (C64/C16/Apple II/ZX Spectrum/PC-88/MSX)– simple text input and output
|
||||
* [Echo](crossplatform/echo.mfk) (C64/C16/VIC-20/Apple II/ZX Spectrum/PC-88/MSX)– simple text input and output
|
||||
|
||||
* [Calculator](crossplatform/calculator.mfk) (C64/C16/Apple II/ZX Spectrum/PC-88/MSX) – simple numeric input and output
|
||||
* [Calculator](crossplatform/calculator.mfk) (C64/C16/VIC-20/Apple II/ZX Spectrum/PC-88/MSX/TRS-80) – simple numeric input and output
|
||||
|
||||
* [Guessing game](crossplatform/guess.mfk) (C64/C16/Apple II/ZX Spectrum/PC-88/MSX) – a guess-a-number game
|
||||
* [Guessing game](crossplatform/guess.mfk) (C64/C16/VIC-20/Apple II/ZX Spectrum/PC-88/MSX/TRS-80/Z1013) – a guess-a-number game
|
||||
|
||||
* [Fire effect](crossplatform/fire.mfk) (C64/C16/ZX Spectrum) – a simple fire effect
|
||||
|
||||
* [`readkey` test](crossplatform/readkeytest.mfk) (C64/C16/PET/VIC-20/Atari/Apple II/Armstrad CPC/ZX Spectrum/PC-88) – keyboard reading test
|
||||
* [`readkey` test](crossplatform/readkeytest.mfk) (C64/C16/PET/VIC-20/Atari/Apple II/Armstrad CPC/ZX Spectrum/PC-88/TRS-80/Z1013) – keyboard reading test
|
||||
|
||||
* [Screen encoding test](crossplatform/screnctest.mfk) (C64/C16) – default-to-screen encoding conversion test
|
||||
|
||||
|
@ -41,7 +49,7 @@ If you are using a release version of the compiler, consider browsing the older
|
|||
|
||||
* [Life](crossplatform/life.mfk) (C64/C16/Atari/ZX Spectrum) – Conway's game of life
|
||||
|
||||
* [Reg dump](crossplatform/regdump.mfk) (C64/C16/ZX Spectrum/CoCo) – a program that simply prints the initial values of CPU registers
|
||||
* [Reg dump](crossplatform/regdump.mfk) (C64/C16/ZX Spectrum/CoCo) – a program that simply prints the initial values of CPU registers
|
||||
|
||||
* [Test suite](tests) (C64/C16/Atari/Apple II/BBC Micro/Armstrad CPC/ZX Spectrum/PC-88/CoCo) – the semi-official test-suite for Millfork
|
||||
|
||||
|
@ -53,14 +61,14 @@ If you are using a release version of the compiler, consider browsing the older
|
|||
|
||||
* [Softscrolling](c64/softscroll.mfk) – soft-scrolling a single line of text
|
||||
|
||||
* [Galencia starfield](c64/galencia.mfk) – a port of the starfield effect from the game *Galencia*
|
||||
* [Galencia starfield](c64/galencia.mfk) – a port of the starfield effect from the game *Galencia*
|
||||
|
||||
* [Space Poker \[external link\]](https://github.com/KarolS/spacepoker) – a game made for the 2018 Reset C64 Craptastic 4KB Game Competition
|
||||
|
||||
### Other examples
|
||||
|
||||
* Multifile ([source code](c64/multifile.mfk), [platform definition](c64/multifile.ini)) –
|
||||
how to create a program made of multiple files loaded on demand
|
||||
how to create a program made of multiple files loaded on demand
|
||||
|
||||
* [Panic](c64/panic_test.mfk) – how panic works on C64, showing the address of where it happened
|
||||
|
||||
|
@ -78,8 +86,48 @@ how to create a program made of multiple files loaded on demand
|
|||
|
||||
## Atari 8-bit examples
|
||||
|
||||
### Hardware specific examples
|
||||
|
||||
* [System Off example](a8/systemoff_example.mfk) – programming with ROM off
|
||||
|
||||
* [DLI example](a8/dli_example.mfk) – simple display list and display list interrupt example
|
||||
|
||||
* [Horizontal scroll example](a8/endless_scroll.mfk) – simple horizontal scroll example
|
||||
|
||||
* [Vertical scroll example](a8/vertical_scroll.mfk) – simple vertical scroll example
|
||||
|
||||
* [Horizontal stars example](a8/horizontal_stars.mfk) – horizontal stars done on one missile
|
||||
|
||||
### Music
|
||||
|
||||
* [CMC Player](a8/cmcplayer.mfk) – CMC player with sample music
|
||||
|
||||
* [MPT Player](a8/mptplayer.mfk) – MPT player with sample music
|
||||
|
||||
### Benchmarks
|
||||
|
||||
* [Grand Theft Antic](a8/grand_theft_antic.mfk) – ANTIC impact on CPU depending on the used graphic mode
|
||||
|
||||
* [GR.8 Chessboard Benchmark](a8/gr8_chessboard_benchmark.mfk) – chessboard drawing benchmark in GR.8
|
||||
|
||||
* [FOR Countdown Benchmark](a8/countdown_for_benchmark.mfk) – countdown from 1,999,999 to 0 (FOR loop)
|
||||
|
||||
* [WHILE Countdown Benchmark](a8/countdown_while_benchmark.mfk) – countdown from 1,999,999 to 0 (WHILE loop)
|
||||
|
||||
* [Sieve of Eratosthenes (1899) Benchmark](a8/sieve1899.mfk) – sieve of Eratosthenes, 1899 primes algorithm
|
||||
|
||||
* [Monte Carlo PI approximation Benchmark](a8/montecarlo_pi_benchmark.mfk) – measures the efficiency of multiplication
|
||||
|
||||
* [Bubble Sort Benchmark](a8/bubble_sort.mfk) – sort 255 elements
|
||||
|
||||
### Other examples
|
||||
|
||||
* [Test OS module](a8/a8_os_test.mfk) – quick test for a8_os.mfk module
|
||||
|
||||
* [Rainbow example](a8/rainbow.mfk) – simple scrolling rasterbars
|
||||
|
||||
* [Quatari Landscape](a8/landscape.mfk) – part of Quatari 256B intro
|
||||
|
||||
## Game Boy examples
|
||||
|
||||
* [GB test example](gb/gbtest.mfk) – a partial port of the NES example, with a rudimentary experimental text output implementation
|
||||
|
@ -93,7 +141,7 @@ how to create a program made of multiple files loaded on demand
|
|||
* [Encoding test](msx/encoding_test.mfk) – text encoding test; displays three lines of text in three different languages,
|
||||
no more one of which will display correctly depending on the default font of your computer.
|
||||
|
||||
# Commander X16 examples
|
||||
## Commander X16 examples
|
||||
|
||||
* [Palette](x16/palette.mfk) – displays the default 256-colour palette.
|
||||
|
||||
|
|
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 { }
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -10,7 +10,7 @@ import c64_basic
|
|||
import c264_basic
|
||||
#endif
|
||||
|
||||
#define READKEY = CBM_64 | CBM_264 | ZX_SPECTRUM | NEC_PC_88 | APPLE_2
|
||||
#define READKEY = CBM_64 | CBM_264 | CBM_VIC | ZX_SPECTRUM | NEC_PC_88 | APPLE_2
|
||||
|
||||
#if READKEY
|
||||
import keyboard
|
||||
|
|
|
@ -4,8 +4,47 @@
|
|||
#warn a8_antic module should be used only on Atari computer-compatible targets
|
||||
#endif
|
||||
|
||||
// ANTIC Display List Instruction Set
|
||||
// THE DISPLAY LIST CANNOT CROSS A 1K BYTE MEMORY BOUNDARY UNLESS A JUMP INSTRUCTION IS USED!
|
||||
const byte LMS = $40 // Load memory scan 12-bit counter, $0-$fff boundary.
|
||||
const byte DLI = $80 // Display list interrupt - Interrupt CPU at beginning of last scan line.
|
||||
const byte HSCROL = $10 // Enable horizontal scrolling.
|
||||
const byte VSCROL = $20 // Enable vertical scrolling.
|
||||
const byte JMP = 1 // Jump command - followed by two bytes indicating the new instruction pointer for the display list.
|
||||
const byte JVB = $41 // Jump and wait for Vertical Blank - suspends the display list until vertical blank and then jumps.
|
||||
|
||||
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
//+ BASIC + colors + resolution + display mode + scan lines per row + screen memory + bytes per line + bits per pixel +
|
||||
const byte MODE_2 = 2 //+ 0 + 2 + 40x24 + text + 8 + 960 B + 40 + 8 +
|
||||
const byte MODE_3 = 3 //+ - + 2 + 40x24 + text + 10 + 760 B + 40 + 8 +
|
||||
const byte MODE_4 = 4 //+ 12 + 5 + 40x24 + text + 8 + 960 B + 40 + 8 +
|
||||
const byte MODE_5 = 5 //+ 13 + 5 + 40x12 + text + 16 + 480 B + 40 + 8 +
|
||||
const byte MODE_6 = 6 //+ 1 + 5 + 20x24 + text + 8 + 480 B + 20 + 8 +
|
||||
const byte MODE_7 = 7 //+ 2 + 5 + 20x12 + text + 16 + 240 B + 20 + 8 +
|
||||
const byte MODE_8 = 8 //+ 3 + 4 + 40x24 + graphics + 8 + 240 B + 10 + 2 +
|
||||
const byte MODE_9 = 9 //+ 4 + 2 + 80x48 + graphics + 4 + 480 B + 10 + 1 +
|
||||
const byte MODE_A = $a //+ 5 + 4 + 80x48 + graphics + 4 + 960 B + 20 + 2 +
|
||||
const byte MODE_B = $b //+ 6 + 2 + 160x96 + graphics + 2 + 1920 B + 20 + 1 +
|
||||
const byte MODE_C = $c //+ 14 + 2 + 160x192 + graphics + 1 + 3840 B + 20 + 1 +
|
||||
const byte MODE_D = $d //+ 7 + 4 + 160x96 + graphics + 2 + 3840 B + 40 + 2 +
|
||||
const byte MODE_E = $e //+ 15 + 4 + 160x192 + graphics + 1 + 7680 B + 40 + 2 +
|
||||
const byte MODE_F = $f //+8,9,10,11+ 2 + 320x192 + graphics + 1 + 7680 B + 40 + 1 +
|
||||
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
const byte BLANK_1 = 0
|
||||
const byte BLANK_2 = $10
|
||||
const byte BLANK_3 = $20
|
||||
const byte BLANK_4 = $30
|
||||
const byte BLANK_5 = $40
|
||||
const byte BLANK_6 = $50
|
||||
const byte BLANK_7 = $60
|
||||
const byte BLANK_8 = $70
|
||||
|
||||
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
volatile byte antic_dmactl @$D400 // direct memory access control
|
||||
volatile byte antic_chactl @$D401 // character mode control
|
||||
volatile word antic_dlist @$D402 // display list pointer
|
||||
volatile byte antic_dlistl @$D402 // display list pointer low-byte
|
||||
volatile byte antic_dlisth @$D403 // display list pointer high-byte
|
||||
volatile byte antic_hscrol @$D404 // horizontal scroll enable
|
||||
|
@ -19,6 +58,5 @@ volatile byte antic_vcount @$D40B // vertical line counter
|
|||
volatile byte antic_penh @$D40C // light pen horizontal position
|
||||
volatile byte antic_penv @$D40D // light pen vertical position
|
||||
volatile byte antic_nmien @$D40E // non-maskable interrupt enable
|
||||
|
||||
// nmi reset status
|
||||
volatile byte antic_nmires @$D40F
|
||||
volatile byte antic_nmist @$D40F // (R) NMI status; holds cause for the NMI interrupt, corresponding to the same bits in NMIEN
|
||||
volatile byte antic_nmires @$D40F // (W) Reset for NMIST; clears the interrupt request register
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
const byte os_MAXDEV = 33 // offset to last possible entry of HATABS
|
||||
const byte os_IOCBSZ = 16 // length of IOCB
|
||||
|
||||
const byte os_SEIOCB = 0*IOCBSZ // ##rev2## screen editor IOCB index
|
||||
const byte os_MAXIOC = 8*IOCBSZ // first invalid IOCB index
|
||||
const byte os_SEIOCB = 0 * os_IOCBSZ // ##rev2## screen editor IOCB index
|
||||
const byte os_MAXIOC = 8 * os_IOCBSZ // first invalid IOCB index
|
||||
|
||||
const byte os_DSCTSZ = 128 // ##rev2## disk sector size
|
||||
|
||||
|
@ -424,6 +424,7 @@ volatile byte os_CDTMF4 @$022C // COUNT DOWN TIMER 4 FLAG
|
|||
volatile byte os_INTEMP @$022D // IAN'S TEMP
|
||||
volatile byte os_CDTMF5 @$022E // COUNT DOWN TIMER FLAG 5
|
||||
volatile byte os_SDMCTL @$022F // SAVE DMACTL REGISTER
|
||||
volatile word os_SDLST @$0230 // SAVE DISPLAY LIST
|
||||
volatile byte os_SDLSTL @$0230 // SAVE DISPLAY LIST LOW BYTE
|
||||
volatile byte os_SDLSTH @$0231 // SAVE DISPLAY LIST HI BYTE
|
||||
volatile byte os_SSKCTL @$0232 // SKCTL REGISTER RAM
|
||||
|
@ -678,50 +679,50 @@ volatile word os_CARTAD @$BFFE // ##rev2## 2-byte cartridge start vector
|
|||
|
||||
// Character sets
|
||||
|
||||
const byte os_ICSORG = $CC00 // ##rev2## international character set origin
|
||||
const byte os_DCSORG = $E000 // ##rev2## domestic character set origin
|
||||
const array os_ICSORG[$400] @$CC00 // ##rev2## international character set origin
|
||||
const array os_DCSORG[$400] @$E000 // ##rev2## domestic character set origin
|
||||
|
||||
// Device Handler Vector Table Address Equates
|
||||
|
||||
const byte os_EDITRV = $E400 // editor handler vector table
|
||||
const byte os_SCRENV = $E410 // screen handler vector table
|
||||
const byte os_KEYBDV = $E420 // keyboard handler vector table
|
||||
const byte os_PRINTV = $E430 // printer handler vector table
|
||||
const byte os_CASETV = $E440 // cassette handler vector table
|
||||
const array(function.void.to.void) os_EDITRV [8] @$E400 // editor handler vector table
|
||||
const array(function.void.to.void) os_SCRENV [8] @$E410 // screen handler vector table
|
||||
const array(function.void.to.void) os_KEYBDV [8] @$E420 // keyboard handler vector table
|
||||
const array(function.void.to.void) os_PRINTV [8] @$E430 // printer handler vector table
|
||||
const array(function.void.to.void) os_CASETV [8] @$E440 // cassette handler vector table
|
||||
|
||||
// Jump Vector Address Equates
|
||||
|
||||
const byte os_DISKIV = $E450 // vector to initialize DIO
|
||||
const byte os_DSKINV = $E453 // vector to DIO
|
||||
const byte os_CIOV = $E456 // vector to CIO
|
||||
const byte os_SIOV = $E459 // vector to SIO
|
||||
asm void os_DISKIV() @$E450 extern // vector to initialize DIO
|
||||
asm void os_DSKINV() @$E453 extern // vector to DIO
|
||||
asm void os_CIOV() @$E456 extern // vector to CIO
|
||||
asm void os_SIOV() @$E459 extern // vector to SIO
|
||||
|
||||
const byte os_SETVBV = $E45C // vector to set VBLANK parameters
|
||||
const byte os_SYSVBV = $E45F // vector to process immediate VBLANK
|
||||
const byte os_XITVBV = $E462 // vector to process deferred VBLANK
|
||||
asm void os_SETVBV() @$E45C extern // vector to set VBLANK parameters
|
||||
asm void os_SYSVBV() @$E45F extern // vector to process immediate VBLANK
|
||||
asm void os_XITVBV() @$E462 extern // vector to process deferred VBLANK
|
||||
|
||||
const byte os_SIOINV = $E465 // vector to initialize SIO
|
||||
const byte os_SENDEV = $E468 // vector to enable SEND
|
||||
const byte os_INTINV = $E46B // vector to initialize interrupt handler
|
||||
const byte os_CIOINV = $E46E // vector to initialize CIO
|
||||
asm void os_SIOINV() @$E465 extern // vector to initialize SIO
|
||||
asm void os_SENDEV() @$E468 extern // vector to enable SEND
|
||||
asm void os_INTINV() @$E46B extern // vector to initialize interrupt handler
|
||||
asm void os_CIOINV() @$E46E extern // vector to initialize CIO
|
||||
|
||||
const byte os_BLKBDV = $E471 // vector to power-up display
|
||||
const byte os_WARMSV = $E474 // vector to warmstart
|
||||
const byte os_COLDSV = $E477 // vector to coldstart
|
||||
asm void os_BLKBDV() @$E471 extern // vector to power-up display
|
||||
asm void os_WARMSV() @$E474 extern // vector to warmstart
|
||||
asm void os_COLDSV() @$E477 extern // vector to coldstart
|
||||
|
||||
const byte os_RBLOKV = $E47A // vector to read cassette block
|
||||
const byte os_CSOPIV = $E47D // vector to open cassette for input
|
||||
asm void os_RBLOKV() @$E47A extern // vector to read cassette block
|
||||
asm void os_CSOPIV() @$E47D extern // vector to open cassette for input
|
||||
|
||||
const byte os_VCTABL = $E480 // RAM vector initial value table
|
||||
const byte os_PUPDIV = $E480 // ##rev2## vector to power-up display
|
||||
const byte os_SLFTSV = $E483 // ##rev2## vector to self-test
|
||||
const byte os_PHENTV = $E486 // ##rev2## vector to enter peripheral handler
|
||||
const byte os_PHUNLV = $E489 // ##rev2## vector to unlink peripheral handler
|
||||
const byte os_PHINIV = $E48C // ##rev2## vector to initialize peripheral handler
|
||||
const byte os_GPDVV = $E48F // ##rev2## generic parallel device handler vector
|
||||
asm void os_VCTABL() @$E480 extern // RAM vector initial value table
|
||||
asm void os_PUPDIV() @$E480 extern // ##rev2## vector to power-up display
|
||||
asm void os_SLFTSV() @$E483 extern // ##rev2## vector to self-test
|
||||
asm void os_PHENTV() @$E486 extern // ##rev2## vector to enter peripheral handler
|
||||
asm void os_PHUNLV() @$E489 extern // ##rev2## vector to unlink peripheral handler
|
||||
asm void os_PHINIV() @$E48C extern // ##rev2## vector to initialize peripheral handler
|
||||
asm void os_GPDVV() @$E48F extern // ##rev2## generic parallel device handler vector
|
||||
|
||||
// 6502
|
||||
|
||||
const byte os_NMIVEC = $FFFA
|
||||
const byte os_RESVEC = $FFFC
|
||||
const byte os_IRQVEC = $FFFE
|
||||
volatile word os_NMIVEC @$FFFA
|
||||
volatile word os_RESVEC @$FFFC
|
||||
volatile word os_IRQVEC @$FFFE
|
||||
|
|
|
@ -11,7 +11,7 @@ asm void bell() @$FBE4 extern
|
|||
asm void putchar(byte register(a) char) @$FDED extern
|
||||
asm void new_line() @$FC62 extern
|
||||
asm pointer readline() {
|
||||
jsr $FD6A
|
||||
jsr $FD6F
|
||||
ldx #$ff
|
||||
__readline_loop:
|
||||
inx
|
||||
|
|
273
include/apple2_prodos.mfk
Normal file
273
include/apple2_prodos.mfk
Normal file
|
@ -0,0 +1,273 @@
|
|||
|
||||
const byte PRODOS_ALLOC_INTERRUPT = $40
|
||||
const byte PRODOS_DEALLOC_INTERRUPT = $41
|
||||
const byte PRODOS_READ_BLOCK = $80
|
||||
const byte PRODOS_WRITE_BLOCK = $81
|
||||
const byte PRODOS_GET_TIME = $82
|
||||
const byte PRODOS_CREATE = $c0
|
||||
const byte PRODOS_DESTROY = $c1
|
||||
const byte PRODOS_RENAME = $c2
|
||||
const byte PRODOS_SET_FILE_INFO = $c3
|
||||
const byte PRODOS_GET_FILE_INFO = $c4
|
||||
const byte PRODOS_ON_LINE = $c5
|
||||
const byte PRODOS_SET_PREFIX = $c6
|
||||
const byte PRODOS_GET_PREFIX = $c7
|
||||
const byte PRODOS_OPEN = $c8
|
||||
const byte PRODOS_NEWLINE = $c9
|
||||
const byte PRODOS_READ = $ca
|
||||
const byte PRODOS_WRITE = $cb
|
||||
const byte PRODOS_CLOSE = $cc
|
||||
const byte PRODOS_FLUSH = $cd
|
||||
const byte PRODOS_SET_MARK = $ce
|
||||
const byte PRODOS_GET_MARK = $cf
|
||||
const byte PRODOS_SET_EOF = $d0
|
||||
const byte PRODOS_GET_EOF = $d1
|
||||
const byte PRODOS_SET_BUF = $d2
|
||||
const byte PRODOS_GET_BUF = $d3
|
||||
|
||||
|
||||
// ProDOS MLI parameter lists
|
||||
|
||||
struct read_block_plist {
|
||||
byte param_count
|
||||
byte unit_num
|
||||
pointer data_buffer
|
||||
word block_num
|
||||
}
|
||||
|
||||
struct write_block_plist {
|
||||
byte param_count
|
||||
byte unit_num
|
||||
pointer data_buffer
|
||||
word block_num
|
||||
}
|
||||
|
||||
struct close_plist {
|
||||
byte param_count
|
||||
byte ref_num
|
||||
}
|
||||
|
||||
struct flush_plist {
|
||||
byte param_count
|
||||
byte ref_num
|
||||
}
|
||||
|
||||
struct create_plist {
|
||||
byte param_count
|
||||
pointer pathname
|
||||
byte access
|
||||
byte file_type
|
||||
word aux_type
|
||||
byte storage_type
|
||||
word create_time
|
||||
word create_date
|
||||
}
|
||||
|
||||
struct destroy_plist {
|
||||
byte param_count
|
||||
pointer pathname
|
||||
}
|
||||
|
||||
struct open_plist {
|
||||
byte param_count
|
||||
pointer pathname
|
||||
pointer io_buffer
|
||||
byte ref_num
|
||||
}
|
||||
|
||||
struct newline_plist {
|
||||
byte param_count
|
||||
byte ref_num
|
||||
byte enable_mask
|
||||
byte newline_char
|
||||
}
|
||||
|
||||
struct read_plist {
|
||||
byte param_count
|
||||
byte ref_num
|
||||
pointer data_buffer
|
||||
word request_count
|
||||
word trans_count
|
||||
}
|
||||
|
||||
struct rename_plist {
|
||||
byte param_count
|
||||
pointer pathname
|
||||
pointer new_pathname
|
||||
}
|
||||
|
||||
struct write_plist {
|
||||
byte param_count
|
||||
byte ref_num
|
||||
pointer data_buffer
|
||||
word request_count
|
||||
word trans_count
|
||||
}
|
||||
|
||||
struct get_prefix_plist {
|
||||
byte param_count
|
||||
pointer data_buffer
|
||||
}
|
||||
|
||||
struct set_prefix_plist {
|
||||
byte param_count
|
||||
pointer data_buffer
|
||||
}
|
||||
|
||||
// we'll just reuse the same area for all plists
|
||||
|
||||
union prodos_plist {
|
||||
read_block_plist read_block
|
||||
write_block_plist write_block
|
||||
create_plist create
|
||||
destroy_plist destroy
|
||||
rename_plist rename
|
||||
open_plist open
|
||||
newline_plist newline
|
||||
read_plist read
|
||||
|
||||
write_plist write
|
||||
close_plist close
|
||||
flush_plist flush
|
||||
|
||||
get_prefix_plist get_prefix
|
||||
set_prefix_plist set_prefix
|
||||
|
||||
}
|
||||
|
||||
prodos_plist plist
|
||||
|
||||
byte prodos_error
|
||||
|
||||
// Millfork doesn't support self-modification in the assembler yet, so this
|
||||
// code is placed in the following array:
|
||||
//
|
||||
// jsr $bf00
|
||||
// $00
|
||||
// plist.addr
|
||||
// rts
|
||||
//
|
||||
// We modify mli_trampoline[3] ($00 on the second line) to set the specific
|
||||
// ProDOS call before we jsr to $bf00
|
||||
//
|
||||
// TODO: can we just jmp to bf00 and save the extra rts ?
|
||||
|
||||
array mli_trampoline = [ $20, 0, $bf, 0, plist.addr.lo, plist.addr.hi, $60 ]
|
||||
|
||||
asm void prodos_mli_call(byte register(a) pdcall) {
|
||||
sta mli_trampoline+3
|
||||
jsr mli_trampoline
|
||||
sta prodos_error
|
||||
rts
|
||||
}
|
||||
|
||||
void prodos_read_block(byte unum, pointer dbuf, word bnum) {
|
||||
plist.read_block.param_count = 3
|
||||
plist.read_block.unit_num = unum
|
||||
plist.read_block.data_buffer = dbuf
|
||||
plist.read_block.block_num = bnum
|
||||
|
||||
prodos_mli_call(PRODOS_READ_BLOCK)
|
||||
}
|
||||
|
||||
void prodos_write_block(byte unum, pointer dbuf, word bnum) {
|
||||
plist.write_block.param_count = 3
|
||||
plist.write_block.unit_num = unum
|
||||
plist.write_block.data_buffer = dbuf
|
||||
plist.write_block.block_num = bnum
|
||||
|
||||
prodos_mli_call(PRODOS_WRITE_BLOCK)
|
||||
}
|
||||
|
||||
void prodos_close(byte rnum) {
|
||||
plist.close.param_count = 1
|
||||
plist.close.ref_num = rnum
|
||||
|
||||
prodos_mli_call(PRODOS_CLOSE)
|
||||
}
|
||||
|
||||
void prodos_flush(byte fp) {
|
||||
plist.flush.param_count = 1
|
||||
plist.flush.ref_num = fp
|
||||
|
||||
prodos_mli_call(PRODOS_FLUSH)
|
||||
}
|
||||
|
||||
void prodos_get_prefix(pointer fnbuf) {
|
||||
plist.get_prefix.param_count = 1
|
||||
plist.get_prefix.data_buffer = fnbuf
|
||||
|
||||
prodos_mli_call(PRODOS_GET_PREFIX)
|
||||
}
|
||||
|
||||
void prodos_set_prefix(pointer fnbuf) {
|
||||
plist.set_prefix.param_count = 1
|
||||
plist.set_prefix.data_buffer = fnbuf
|
||||
|
||||
prodos_mli_call(PRODOS_SET_PREFIX)
|
||||
}
|
||||
|
||||
void prodos_create(pointer fn, byte ftype) {
|
||||
plist.create.param_count = 7
|
||||
plist.create.pathname = fn
|
||||
plist.create.access = $c3
|
||||
plist.create.file_type = ftype
|
||||
plist.create.aux_type = $0
|
||||
plist.create.storage_type = 1
|
||||
plist.create.create_time = 0
|
||||
plist.create.create_date = 0
|
||||
|
||||
prodos_mli_call(PRODOS_CREATE)
|
||||
}
|
||||
|
||||
void prodos_destroy (pointer fn) {
|
||||
plist.destroy.param_count = 0
|
||||
plist.destroy.pathname = fn
|
||||
prodos_mli_call(PRODOS_DESTROY)
|
||||
}
|
||||
|
||||
void prodos_rename(pointer fn, pointer newfn) {
|
||||
plist.rename.param_count = 2
|
||||
plist.rename.pathname = fn
|
||||
plist.rename.new_pathname = newfn
|
||||
|
||||
prodos_mli_call(PRODOS_RENAME)
|
||||
}
|
||||
|
||||
// returns file handle if no error
|
||||
byte prodos_open (pointer fn, pointer b) {
|
||||
plist.open.param_count = 3
|
||||
plist.open.pathname = fn
|
||||
plist.open.io_buffer = b
|
||||
|
||||
prodos_mli_call(PRODOS_OPEN)
|
||||
|
||||
return plist.open.ref_num
|
||||
}
|
||||
|
||||
void prodos_newline(byte fp, byte mask, byte nlchar) {
|
||||
plist.newline.param_count = 3
|
||||
plist.newline.ref_num = fp
|
||||
plist.newline.enable_mask = mask
|
||||
plist.newline.newline_char = nlchar
|
||||
|
||||
prodos_mli_call(PRODOS_NEWLINE)
|
||||
}
|
||||
|
||||
void prodos_read(byte rnum, pointer dbuf, word rcnt) {
|
||||
plist.read.param_count = 4
|
||||
plist.read.ref_num = rnum
|
||||
plist.read.data_buffer = dbuf
|
||||
plist.read.request_count = rcnt
|
||||
|
||||
prodos_mli_call(PRODOS_READ)
|
||||
}
|
||||
|
||||
void prodos_write(byte rnum, pointer dbuf, word rcnt) {
|
||||
plist.write.param_count = 4
|
||||
plist.write.ref_num = rnum
|
||||
plist.write.data_buffer = dbuf
|
||||
plist.write.request_count = rcnt
|
||||
|
||||
prodos_mli_call(PRODOS_WRITE)
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
// CHROUT. Write byte to default output. (If not screen, must call OPEN and CHKOUT beforehands.)
|
||||
// Input: A = Byte to write.
|
||||
asm void chrout(byte register(a) char) @$FFD2 extern
|
||||
asm void chrout(byte register(a) char) !preserves_a !preserves_x !preserves_y @$FFD2 extern
|
||||
|
||||
asm void putchar(byte register(a) char) {
|
||||
JSR chrout
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
// CHROUT. Write byte to default output. (If not screen, must call OPEN and CHKOUT beforehands.)
|
||||
// Input: A = Byte to write.
|
||||
asm void chrout(byte register(a) char) @$FFD2 extern
|
||||
asm void chrout(byte register(a) char) !preserves_a !preserves_x !preserves_y @$FFD2 extern
|
||||
|
||||
asm void putchar(byte register(a) char) {
|
||||
JSR chrout
|
||||
|
|
|
@ -2,7 +2,7 @@ import err
|
|||
|
||||
inline asm void switch_hirom(byte register(a) bank) {
|
||||
? and #$3F
|
||||
! sta $DE01
|
||||
! sta $DE00
|
||||
? rts
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
// CHROUT. Write byte to default output. (If not screen, must call OPEN and CHKOUT beforehands.)
|
||||
// Input: A = Byte to write.
|
||||
asm void chrout(byte register(a) char) @$FFD2 extern
|
||||
asm void chrout(byte register(a) char) !preserves_a !preserves_x !preserves_y @$FFD2 extern
|
||||
|
||||
// CHRIN. Read byte from default input (for keyboard, read a line from the screen). (If not keyboard, must call OPEN and CHKIN beforehands.)
|
||||
// Output: A = Byte read.
|
||||
|
|
|
@ -10,7 +10,7 @@ word sid_v1_freq @$D400
|
|||
word sid_v1_pulse @$D402
|
||||
byte sid_v1_cr @$D404
|
||||
byte sid_v1_ad @$D405
|
||||
byte sid_v1_sr @$D409
|
||||
byte sid_v1_sr @$D406
|
||||
|
||||
word sid_v2_freq @$D407
|
||||
word sid_v2_pulse @$D409
|
||||
|
|
31
include/cbm/basic_loader.mfk
Normal file
31
include/cbm/basic_loader.mfk
Normal file
|
@ -0,0 +1,31 @@
|
|||
#template $ADDR$
|
||||
|
||||
#if not(CBM)
|
||||
#warn cbm/basic_loader module should be only used on Commodore targets
|
||||
#endif
|
||||
|
||||
const array _basic_loader @ $ADDR$ = [
|
||||
#if DISPLACED_MAIN
|
||||
@word_le [
|
||||
$ADDR$ + 0xB
|
||||
],
|
||||
#else
|
||||
@word_le [
|
||||
$ADDR$ + if(main.addr >= 10000, 1/0, 0xA) // use -D DISPLACED_MAIN=1 if you get an error here
|
||||
],
|
||||
#endif
|
||||
10,
|
||||
0,
|
||||
$9e,
|
||||
#if DISPLACED_MAIN
|
||||
$30 + (main.addr/10000)%%10,
|
||||
#endif
|
||||
$30 + (main.addr/1000)%%10,
|
||||
$30 + (main.addr/100)%%10,
|
||||
$30 + (main.addr/10)%%10,
|
||||
$30 + (main.addr/1)%%10,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
]
|
||||
|
|
@ -1,8 +1,2 @@
|
|||
|
||||
noinline asm byte readkey() {
|
||||
clr $6f
|
||||
jsr [$A000]
|
||||
beq readkey
|
||||
tfr a,b
|
||||
rts
|
||||
}
|
||||
asm byte readkey() @ $49 extern
|
||||
|
|
|
@ -7,7 +7,7 @@ C0-DF=@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
|
|||
|
||||
a-z=C1
|
||||
|
||||
{q}=02
|
||||
{apos}=07
|
||||
{q}=A2
|
||||
{apos}=A7
|
||||
{nbsp}=40
|
||||
|
||||
{n}=8D
|
||||
|
|
|
@ -13,3 +13,4 @@ EOT=00
|
|||
{apos}=27
|
||||
{lbrace}=7b
|
||||
{rbrace}=7d
|
||||
{pound}=5c
|
||||
|
|
|
@ -7,8 +7,8 @@ EOT=7F
|
|||
20-3f=@abcdefghijklmnopqrstuvwxyz[\]^_
|
||||
60-7e=πABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~
|
||||
|
||||
{q}=22
|
||||
{apos}=27
|
||||
{q}=02
|
||||
{apos}=07
|
||||
{lbrace}=7b
|
||||
{rbrace}=7d
|
||||
{pi}=60
|
||||
|
|
|
@ -9,4 +9,4 @@ E0-FE=`abcdefghijklmnopqrstuvwxyz{\}~
|
|||
{q}=A2
|
||||
{apos}=A7
|
||||
{lbrace}=FB
|
||||
{rbrace}=FC
|
||||
{rbrace}=FD
|
||||
|
|
29
include/encoding/brascii.tbl
Normal file
29
include/encoding/brascii.tbl
Normal file
|
@ -0,0 +1,29 @@
|
|||
NAME=BraSCII
|
||||
EOT=00
|
||||
|
||||
20=U+0020
|
||||
21-3f=!"#$%&'()*+,-./0123456789:;<=>?
|
||||
40-5f=@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
|
||||
60-7e=`abcdefghijklmnopqrstuvwxyz{|}~
|
||||
a1-ac=¡¢£¤¥¦§¨©ª«¬
|
||||
ae-af=®¯
|
||||
b0-bf=°±²³´µ¶·¸¹º»¼½¾¿
|
||||
c0-cf=ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ
|
||||
d0-df=ÐÑÒÓÔÕÖŒØÙÚÛÜÝÞß
|
||||
e0-ef=àáâãäåæçèéêëìíîï
|
||||
f0-ff=ðñòóôõöœøùúûüýþÿ
|
||||
|
||||
{b}=08
|
||||
{t}=09
|
||||
{n}=0d0a
|
||||
{q}=22
|
||||
{apos}=27
|
||||
{lbrace}=7b
|
||||
{rbrace}=7d
|
||||
{cent}=a2
|
||||
{pound}=a3
|
||||
{yen}=a5
|
||||
{copy}=a9
|
||||
{ss}=df
|
||||
{nbsp}=A0
|
||||
{shy}=AD
|
|
@ -26,6 +26,7 @@ f0-ff=đńňóôőö÷řůúűüýţ˙
|
|||
{apos}=27
|
||||
{lbrace}=7b
|
||||
{rbrace}=7d
|
||||
{euro}=80
|
||||
{copy}=a9
|
||||
{ss}=df
|
||||
{nbsp}=A0
|
||||
|
|
|
@ -23,6 +23,7 @@ f0-ff=рстуфхцчшщъыьэюя
|
|||
{apos}=27
|
||||
{lbrace}=7b
|
||||
{rbrace}=7d
|
||||
{euro}=88
|
||||
{copy}=a9
|
||||
{nbsp}=A0
|
||||
{shy}=AD
|
||||
|
|
|
@ -25,6 +25,7 @@ f0-ff=ðñòóôõö÷øùúûüýþÿ
|
|||
{apos}=27
|
||||
{lbrace}=7b
|
||||
{rbrace}=7d
|
||||
{euro}=80
|
||||
{cent}=a2
|
||||
{pound}=a3
|
||||
{yen}=a5
|
||||
|
|
39
include/encoding/cp1253.tbl
Normal file
39
include/encoding/cp1253.tbl
Normal file
|
@ -0,0 +1,39 @@
|
|||
NAME=CP1253
|
||||
EOT=00
|
||||
|
||||
20=U+0020
|
||||
21-3f=!"#$%&'()*+,-./0123456789:;<=>?
|
||||
40-5f=@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
|
||||
60-7e=`abcdefghijklmnopqrstuvwxyz{|}~
|
||||
80=€
|
||||
82-87=‚ƒ„…†‡
|
||||
89=‰
|
||||
8b=‹
|
||||
91-97=‘’“”•–—
|
||||
99=™
|
||||
9b=›
|
||||
a1-ac=΅Ά£¤¥¦§¨©ͺ«¬
|
||||
ae-af=®―
|
||||
b0-bf=°±²³΄µ¶·ΈΉΊ»Ό½ΎΏ
|
||||
c0-cf=ΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟ
|
||||
d0-d1=ΠΡ
|
||||
d3-df=ΣΤΥΦΧΨΩΪΫάέήί
|
||||
e0-ef=ΰαβγδεζηθικλμνξο
|
||||
f0-fe=πρςστυφχψωϊϋόύώ
|
||||
|
||||
|
||||
|
||||
{b}=08
|
||||
{t}=09
|
||||
{n}=0d0a
|
||||
{q}=22
|
||||
{apos}=27
|
||||
{lbrace}=7b
|
||||
{rbrace}=7d
|
||||
{euro}=80
|
||||
{pound}=a3
|
||||
{yen}=a5
|
||||
{copy}=a9
|
||||
{pi}=f0
|
||||
{nbsp}=A0
|
||||
{shy}=AD
|
34
include/encoding/cp1254.tbl
Normal file
34
include/encoding/cp1254.tbl
Normal file
|
@ -0,0 +1,34 @@
|
|||
NAME=CP1254
|
||||
EOT=00
|
||||
|
||||
20=U+0020
|
||||
21-3f=!"#$%&'()*+,-./0123456789:;<=>?
|
||||
40-5f=@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
|
||||
60-7e=`abcdefghijklmnopqrstuvwxyz{|}~
|
||||
80=€
|
||||
82-8c=‚ƒ„…†‡ˆ‰Š‹Œ
|
||||
91-9c=‘’“”•–—˜™š›œ
|
||||
9f=Ÿ
|
||||
a1-ac=¡¢£¤¥¦§¨©ª«¬
|
||||
ae-af=®¯
|
||||
b0-bf=°±²³´µ¶·¸¹º»¼½¾¿
|
||||
c0-cf=ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ
|
||||
d0-df=ĞÑÒÓÔÕÖ×ØÙÚÛÜİŞß
|
||||
e0-ef=àáâãäåæçèéêëìíîï
|
||||
f0-ff=ğñòóôõö÷øùúûüışÿ
|
||||
|
||||
{b}=08
|
||||
{t}=09
|
||||
{n}=0d0a
|
||||
{q}=22
|
||||
{apos}=27
|
||||
{lbrace}=7b
|
||||
{rbrace}=7d
|
||||
{euro}=80
|
||||
{cent}=a2
|
||||
{pound}=a3
|
||||
{yen}=a5
|
||||
{copy}=a9
|
||||
{ss}=df
|
||||
{nbsp}=A0
|
||||
{shy}=AD
|
36
include/encoding/cp1257.tbl
Normal file
36
include/encoding/cp1257.tbl
Normal file
|
@ -0,0 +1,36 @@
|
|||
NAME=CP1257
|
||||
EOT=00
|
||||
|
||||
20=U+0020
|
||||
21-3f=!"#$%&'()*+,-./0123456789:;<=>?
|
||||
40-5f=@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
|
||||
60-7e=`abcdefghijklmnopqrstuvwxyz{|}~
|
||||
80=€
|
||||
82-8c=‚ƒ„…†‡ˆ‰Š‹Œ
|
||||
8d-8f=¨ˇ¸
|
||||
91-9c=‘’“”•–—˜™š›œ
|
||||
9e-9f=¯˛
|
||||
a1-ac=¡¢£¤¥¦§Ø©Ŗ«¬
|
||||
ae-af=®Æ
|
||||
b0-bf=°±²³´µ¶·ø¹ŗ»¼½¾æ
|
||||
c0-cf=ĄĮĀĆÄÅĘĒČÉŹĖĢĶĪĻ
|
||||
d0-df=ŠŃŅÓŌÕÖ×ŲŁŚŪÜŻŽß
|
||||
e0-ef=ąįāćäåęēčéźėģķīļ
|
||||
f0-ff=šńņóōõö÷ųłśūüżž˙
|
||||
|
||||
|
||||
{b}=08
|
||||
{t}=09
|
||||
{n}=0d0a
|
||||
{q}=22
|
||||
{apos}=27
|
||||
{lbrace}=7b
|
||||
{rbrace}=7d
|
||||
{euro}=80
|
||||
{cent}=a2
|
||||
{pound}=a3
|
||||
{yen}=a5
|
||||
{copy}=a9
|
||||
{ss}=df
|
||||
{nbsp}=A0
|
||||
{shy}=AD
|
|
@ -27,4 +27,5 @@ F0-FE=≡±≥≤⌠⌡÷≈°∙·√ⁿ²■
|
|||
{pound}=9c
|
||||
{yen}=9d
|
||||
{ss}=e1
|
||||
{pi}=e3
|
||||
{nbsp}=FF
|
||||
|
|
|
@ -23,6 +23,7 @@ F1-FE=±‗¾¶§÷¸°¨·¹³²■
|
|||
{apos}=27
|
||||
{lbrace}=7b
|
||||
{rbrace}=7d
|
||||
{copy}=b8
|
||||
{cent}=BD
|
||||
{pound}=9c
|
||||
{yen}=BE
|
||||
|
|
|
@ -24,6 +24,7 @@ F1-FE=±υφχ§ψ¸°¨ωϋΰώ■
|
|||
{apos}=27
|
||||
{lbrace}=7b
|
||||
{rbrace}=7d
|
||||
{pound}=9c
|
||||
{ss}=D7
|
||||
{nbsp}=FF
|
||||
{shy}=F0
|
||||
|
|
|
@ -25,6 +25,7 @@ F1-FE=±‗¾¶§÷¸°¨·¹³²■
|
|||
{rbrace}=7d
|
||||
{cent}=BD
|
||||
{pound}=9c
|
||||
{copy}=b8
|
||||
{yen}=BE
|
||||
{euro}=D5
|
||||
{ss}=e1
|
||||
|
|
|
@ -19,6 +19,9 @@ fe-ff=↕↔
|
|||
{apos}=27
|
||||
{lbrace}=7b
|
||||
{rbrace}=7d
|
||||
{pound}=a3
|
||||
{copy}=a4
|
||||
{pi}=b8
|
||||
{AE}=5b
|
||||
{OE}=5c
|
||||
{AA}=5d
|
||||
|
|
|
@ -19,3 +19,6 @@ fe-ff=↕↔
|
|||
{apos}=27
|
||||
{lbrace}=7b
|
||||
{rbrace}=7d
|
||||
{pound}=a3
|
||||
{copy}=a4
|
||||
{pi}=b8
|
||||
|
|
|
@ -19,3 +19,5 @@ fe-ff=↕↔
|
|||
{apos}=27
|
||||
{lbrace}=7b
|
||||
{rbrace}=7d
|
||||
{copy}=a4
|
||||
{pi}=b8
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user