diff --git a/.gitignore b/.gitignore index e1e3951d5..7ccf0345c 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,6 @@ __pycache__/ parser.out parsetab.py !/il65/lib/* +.pytest_cache/ +docs/build + diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 000000000..2a83c4b00 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SPHINXPROJ = IL65 +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 000000000..098185353 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,36 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build +set SPHINXPROJ=IL65 + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% + +:end +popd diff --git a/docs/programming.md b/docs/programming.md deleted file mode 100644 index b786df6d2..000000000 --- a/docs/programming.md +++ /dev/null @@ -1,552 +0,0 @@ -What is a Program? ------------------- - -A "complete program" is a compiled, assembled, and linked together single unit. -It contains all of the program's code and data and has a certain file format that -allows it to be loaded directly on the target system. - -Most programs will need a tiny BASIC launcher that does a SYS into the generated machine code, -but it is also possible to output just binary programs that can be loaded into memory elsewhere. - -Compiling a program -------------------- - -Compilation of a program is done by compiling just the main source code module file. -Other modules that the code needs can be imported from within the file. -The compiler will eventually link them together into one output program. - -Program code structure ----------------------- - -A program is created by compiling and linking *one or more module source code files*. - -### Module file - -This is a file with the ``.ill`` suffix, without spaces in its name, containing: -- source code comments -- global program options -- imports of other modules -- one or more *code blocks* - -The filename doesn't really matter as long as it doesn't contain spaces. -The full name of the symbols defined in the file is not impacted by the filename. - -#### Source code comments - - A=5 ; set the initial value to 5 - ; next is the code that... - -In any file, everything after a semicolon '``;``' is considered a comment and is ignored by the compiler. -If all of the line is just a comment, it will be copied into the resulting assembly source code. -This makes it easier to understand and relate the generated code. - - -#### Things global to the program - -The global program options that can be put at the top of a module file, -determine the settings for the entire output program. -They're all optional (defaults will be chosen as mentioned below). -If specified though, they can only occur once in the entire program: - - %output prg - %address $0801 - %launcher none - %zp compatible - - -##### ``%output`` : select output format of the program -- ``raw`` : no header at all, just the raw machine code data -- ``prg`` : C64 program (with load address header) - -The default is ``prg``. - - -##### ``%address`` : specify start address of the code - -- default for ``raw`` output is $c000 -- default for ``prg`` output is $0801 -- cannot be changed if you select ``prg`` with a ``basic`` launcher; - then it is always $081d (immediately after the BASIC program), and the BASIC program itself is always at $0801. - This is because the C64 expects BASIC programs to start at this address. - - -##### ``%launcher`` : specify launcher type - -Only relevant when using the ``prg`` output type. Defaults to ``basic``. -- ``basic`` : add a tiny C64 BASIC program, whith a SYS statement calling into the machine code -- ``none`` : no launcher logic is added at all - - -##### ``%zp`` : select ZeroPage behavior - -- ``compatible`` : only use a few free locations in the ZP -- ``full`` : use the whole ZP for variables, makes the program faster but can't use BASIC or KERNAL routines anymore, and cannot exit cleanly -- ``full-restore`` : like ``full``, but makes a backup copy of the original values at program start. - These are restored when exiting the program back to the BASIC prompt - -Defaults to ``compatible``. -The exact meaning of these options can be found in the paragraph -about the ZeroPage in the system documentation. - - -##### Program Start and Entry Point - -Your program must have a single entry point where code execution begins. -The compiler expects a ``start`` subroutine in the ``main`` block for this, -taking no parameters and having no return value. -As any subroutine, it has to end with a ``return`` statement (or a ``goto`` call). - - ~ main { - sub start () -> () { - ; program entrypoint code here - return - } - } - -The ``main`` module is always relocated to the start of your programs -address space, and the ``start`` subroutine (the entrypoint) will be on the -first address. This will also be the address that the BASIC loader program (if generated) -calls with the SYS statement. - -Blocks and subroutines are explained below. - - -#### Using other modules via import - -Immediately following the global program options at the top of the module file, -the imports of other modules are placed: - -``%import filename`` - -This reads and compiles the named module source file as part of your current program. -Symbols from the imported module become available in your code, -without a module or filename prefix. -You can import modules one at a time, and importing a module more than once has no effect. - - -#### Blocks, Scopes, and accessing Symbols - -Blocks are the separate pieces of code and data of your program. They are combined -into a single output program. No code or data can occur outside a block. - - ~ blockname [address] { - [directives...] - [variables...] - [subroutines...] - } - -Block names must be unique in your entire program. -It's possible to omit the blockname, but then you can only refer to the contents of the block via its absolute address, -which is required in this case. If you omit *both* name and address, the block is *ignored* by the compiler (and a warning is displayed). -This is a way to quickly "comment out" a piece of code that is unfinshed or may contain errors that you -want to work on later, because the contents of the ignored block are not fully parsed either. - -The address can be used to place a block at a specific location in memory. -Otherwise the compiler will automatically choose the location (usually immediately after -the previous block in memory). -The address must be >= $0200 (because $00-$fff is the ZP and $100-$200 is the cpu stack). - -A block is also a *scope* in your program so the symbols in the block don't clash with -symbols of the same name defined elsewhere in the same file or in another file. -You can refer to the symbols in a particular block by using a *dotted name*: ``blockname.symbolname``. -Labels inside a subroutine are appended again to that; ``blockname.subroutinename.label``. - -Every symbol is 'public' and can be accessed from elsewhere given its dotted name. - - -**The special "ZP" ZeroPage block** - -Blocks named "ZP" are treated a bit differently: they refer to the ZeroPage. -The contents of every block with that name (this one may occur multiple times) are merged into one. -Its start address is always set to $04, because $00/$01 are used by the hardware -and $02/$03 are reserved as general purpose scratch registers. - - -Code elements -------------- - -### Data types for Variables and Values - -IL65 supports the following data types: - -| type | storage size | type identifier | example | -|-------------------------|-------------------|-----------------|---------------------------------------------------| -| unsigned byte | 1 byte = 8 bits | ``.byte`` | ``$8f`` | -| unsigned word | 2 bytes = 16 bits | ``.word`` | ``$8fee`` | -| floating-point | 5 bytes = 40 bits | ``.float`` | ``1.2345`` (stored in 5-byte cbm MFLPT format) | -| byte array | varies | ``.array`` | @todo | -| word array | varies | ``.wordarray`` | @todo | -| matrix (of bytes) | varies | ``.matrix`` | @todo | -| string (petscii) | varies | ``.str`` | ``"hello."`` (implicitly terminated by a 0-byte) | -| pascal-string (petscii) | varies | ``.strp`` | ``"hello."`` (implicit first byte = length, no 0-byte | -| string (screencodes) | varies | ``.strs`` | ``"hello."`` (implicitly terminated by a 0-byte) | -| pascal-string (scr) | varies | ``.strps`` | ``"hello."`` (implicit first byte = length, no 0-byte | - - -You can use the literals ``true`` and ``false`` as 'boolean' values, they are aliases for the -byte value 1 and 0 respectively. - - -Strings in your code will be encoded in either CBM PETSCII or C-64 screencode variants, -this encoding is done by the compiler. PETSCII is the default, if you need screencodes you -have to use the ``s`` variants of the string type identifier. -A string with just one character in it is considered to be a BYTE instead with -that character's PETSCII value. So if you really need a string of length 1 you must declare -the variable explicitly of type ``.str``. - -Floating point numbers are stored in the 5-byte 'MFLPT' format that is used on CBM machines, -but most float operations are specific to the Commodore-64 even because -routines in the C-64 BASIC and KERNAL ROMs are used. -So floating point operations will only work if the C-64 BASIC ROM (and KERNAL ROM) are banked in, and your code imports the ``c654lib.ill``. -The largest 5-byte MFLPT float that can be stored is: 1.7014118345e+38 (negative: -1.7014118345e+38) - -The initial values of your variables will be restored automatically when the program is (re)started, -*except for string variables*. It is assumed these are left unchanged by the program. -If you do modify them in-place, you should take care yourself that they work as -expected when the program is restarted. - - -@todo pointers/addresses? (as opposed to normal WORDs) -@todo signed integers (byte and word)? - - -### Indirect addressing and address-of - -**Address-of:** -The ``#`` prefix is used to take the address of something. This is sometimes useful, -for instance when you want to manipulate the *address* of a memory mapped variable rather than -the value it represents. You could take the address of a string as well, but that is redundant: -the compiler already treats those as a value that you manipulate via its address. -For most other types this prefix is not supported and will result in a compile error. -The resulting value is simply a 16 bit word. - -**Indirect addressing:** The ``[address]`` syntax means: the contents of the memory at address, or "indirect addressing". -By default, if not otherwise known, a single byte is assumed. You can add the ``.byte`` or ``.word`` or ``.float`` -type identifier, inside the bracket, to make it clear what data type the address points to. -For instance: ``[address .word]`` (notice the space, to distinguish this from a dotted symbol name). -For an indirect goto call, the 6502 CPU has a special instruction -(``jmp`` indirect) and an indirect subroutine call (``jsr`` indirect) is emitted -using a couple of instructions. - - -### Conditional Execution - -Conditional execution means that the flow of execution changes based on certiain conditions, -rather than having fixed gotos or subroutine calls. IL65 has a *conditional goto* statement for this, -that is translated into a comparison (if needed) and then a conditional branch instruction: - - if[_XX] [] goto