prog8/docs/source/targetsystem.rst

178 lines
8.1 KiB
ReStructuredText
Raw Normal View History

2018-08-06 01:35:43 +00:00
***************************
Target system specification
***************************
2018-09-15 14:21:05 +00:00
Prog8 targets the following hardware:
2018-08-06 01:35:43 +00:00
2020-08-27 16:18:29 +00:00
- 8 bit MOS 6502/65c02/6510 CPU
2018-08-06 01:35:43 +00:00
- 64 Kb addressable memory (RAM or ROM)
2020-08-27 16:18:29 +00:00
- optional use of memory mapped I/O registers
- optional use of system ROM routines
2018-08-06 01:35:43 +00:00
Currently these machines can be selected as a compilation target (via the ``-target`` compiler argument):
2020-08-27 16:18:29 +00:00
- 'c64': the Commodore 64
- 'cx16': the `Commander X16 <https://www.commanderx16.com/>`_
- 'c128': the Commodore 128 (*limited support*)
- 'atari': the Atari 800 XL (*experimental support*)
2022-09-20 02:04:47 +00:00
- 'virtual': a builtin virtual machine
2020-08-30 16:32:16 +00:00
2021-12-30 17:33:26 +00:00
This chapter explains some relevant system details of the c64 and cx16 machines.
2018-08-06 01:35:43 +00:00
2020-10-17 18:35:36 +00:00
.. hint::
2022-10-29 12:10:11 +00:00
If you only use standard Kernal and prog8 library routines,
2022-09-20 02:04:47 +00:00
it is often possible to compile the *exact same program* for
different machines (just change the compilation target flag)!
2020-09-21 22:47:02 +00:00
2018-08-06 01:35:43 +00:00
Memory Model
============
Physical address space layout
-----------------------------
The 6502 CPU can address 64 kilobyte of memory.
2018-09-15 14:21:05 +00:00
Most of the 64 kilobyte address space can be used by Prog8 programs.
2018-08-06 01:35:43 +00:00
This is a hard limit: there is no built-in support for RAM expansions or bank switching.
====================== ================== ========
memory area type note
====================== ================== ========
2022-10-29 12:12:10 +00:00
``$00``--``$ff`` zeropage contains many sensitive system variables
2018-08-06 01:35:43 +00:00
``$100``--``$1ff`` Hardware stack used by the CPU, normally not accessed directly
``$0200``--``$ffff`` Free RAM or ROM free to use memory area, often a mix of RAM and ROM
====================== ================== ========
A few of these memory addresses are reserved and cannot be used for arbitrary data.
They have a special hardware function, or are reserved for internal use in the
code generated by the compiler:
================== =======================
reserved address in use for
================== =======================
``$00`` data direction (CPU hw)
``$01`` bank select (CPU hw)
2018-09-15 14:21:05 +00:00
``$02`` internal scratch variable
``$03`` internal scratch variable
``$fb - $fc`` internal scratch variable
``$fd - $fe`` internal scratch variable
2018-08-06 01:35:43 +00:00
``$fffa - $fffb`` NMI vector (CPU hw)
``$fffc - $fffd`` RESET vector (CPU hw)
``$fffe - $ffff`` IRQ vector (CPU hw)
================== =======================
The actual machine will often have many other special addresses as well,
2022-10-28 21:45:09 +00:00
For example, the Commodore 64 has:
2018-08-06 01:35:43 +00:00
2022-10-29 12:10:11 +00:00
- ROMs installed in the machine: BASIC, Kernal and character roms. Occupying ``$a000``--``$bfff`` and ``$e000``--``$ffff``.
2018-08-06 01:35:43 +00:00
- memory-mapped I/O registers, for the video and sound chips, and the CIA's. Occupying ``$d000``--``$dfff``.
- RAM areas that are used for screen graphics and sprite data: usually at ``$0400``--``$07ff``.
2018-09-15 14:21:05 +00:00
Prog8 programs can access all of those special memory locations but it will have a special meaning.
2018-08-06 01:35:43 +00:00
.. _zeropage:
2022-10-29 12:12:10 +00:00
Zeropage ("ZP")
2018-08-06 01:35:43 +00:00
---------------
2022-10-29 12:12:10 +00:00
The zeropage memory block ``$02``--``$ff`` can be regarded as 254 CPU 'registers', because
2018-08-06 01:35:43 +00:00
they take less clock cycles to access and need fewer instruction bytes than accessing other memory locations outside of the ZP.
2022-10-28 21:39:15 +00:00
Theoretically they can all be used in a program, with the following limitations:
2018-08-06 01:35:43 +00:00
- several addresses (``$02``, ``$03``, ``$fb - $fc``, ``$fd - $fe``) are reserved for internal use
2022-10-29 12:10:11 +00:00
- most other addresses will already be in use by the machine's operating system or Kernal,
2018-08-06 01:35:43 +00:00
and overwriting them will probably crash the machine. It is possible to use all of these
2022-10-29 12:10:11 +00:00
yourself, but only if the program takes over the entire system (and seizes control from the regular Kernal).
This means it can no longer use (most) BASIC and Kernal routines from ROM.
2018-09-15 14:21:05 +00:00
- it's more convenient and safe to let the compiler allocate these addresses for you and just
2018-08-06 01:35:43 +00:00
use symbolic names in the program code.
2018-09-15 14:21:05 +00:00
Prog8 knows what addresses are safe to use in the various ZP handling configurations.
It will use the free ZP addresses to place its ZP variables in,
2018-08-06 01:35:43 +00:00
until they're all used up. If instructed to output a program that takes over the entire
machine, (almost) all of the ZP addresses are suddenly available and will be used.
2022-10-29 12:12:10 +00:00
**zeropage handling is configurable:**
There's a global program directive to specify the way the compiler
treats the ZP for the program. The default is to be reasonably restrictive to use the
2022-10-29 12:10:11 +00:00
part of the ZP that is not used by the C64's Kernal routines.
It's possible to claim the whole ZP as well (by disabling the operating system or Kernal).
2022-10-28 21:39:15 +00:00
If you want, it's also possible to be more restrictive and stay clear of the addresses used by BASIC routines too.
This allows the program to exit cleanly back to a BASIC ready prompt - something that is not possible in the other modes.
2018-08-06 01:35:43 +00:00
2022-10-29 12:12:10 +00:00
IRQs and the zeropage
2018-08-06 01:35:43 +00:00
^^^^^^^^^^^^^^^^^^^^^
2022-10-29 12:12:10 +00:00
The normal IRQ routine in the C64's Kernal will read and write several addresses in the ZP
2018-08-06 01:35:43 +00:00
(such as the system's software jiffy clock which sits in ``$a0 - $a2``):
``$a0 - $a2``; ``$91``; ``$c0``; ``$c5``; ``$cb``; ``$f5 - $f6``
These addresses will *never* be used by the compiler for ZP variables, so variables will
2018-08-06 01:35:43 +00:00
not interfere with the IRQ routine and vice versa. This is true for the normal ZP mode but also
for the mode where the whole system and ZP have been taken over.
So the normal IRQ vector can still run and will be when the program is started!
CPU
===
Directly Usable Registers
-------------------------
The hardware CPU registers are not directly accessible from regular Prog8 code.
If you need to mess with them, you'll have to use inline assembly.
Be extra wary of the ``X`` register because it is used as an evaluation stack pointer and
changing its value you will destroy the evaluation stack and likely crash the program.
2018-08-06 01:35:43 +00:00
The status register (P) carry flag and interrupt disable flag can be written via a couple of special
builtin functions (``set_carry()``, ``clear_carry()``, ``set_irqd()``, ``clear_irqd()``),
and read via the ``read_flags()`` function.
2019-01-24 01:43:25 +00:00
2020-12-22 12:29:16 +00:00
The 16 'virtual' 16-bit registers that are defined on the Commander X16 machine are not real hardware
registers and are just 16 memory-mapped word values that you *can* access directly.
2019-03-06 21:11:16 +00:00
IRQ Handling
============
Normally, the system's default IRQ handling is not interfered with.
You can however install your own IRQ handler (for clean separation, it is advised to define it inside its own block).
2022-10-29 12:12:10 +00:00
There are a few library routines available to make setting up C64 60hz IRQs and Raster IRQs a lot easier (no assembly code required).
2019-03-06 21:11:16 +00:00
2020-08-27 16:18:29 +00:00
For the C64 these routines are::
2019-03-06 21:11:16 +00:00
c64.set_irq(uword handler_address, boolean useKernal)
c64.set_rasterirq(uword handler_address, uword rasterline, boolean useKernal)
c64.restore_irq() ; set everything back to the systems default irq handler
2021-11-27 18:58:08 +00:00
And for the Commander X16::
2021-02-21 22:41:50 +00:00
cx16.set_irq(uword handler_address, boolean useKernal) ; vsync irq
2022-10-29 12:10:11 +00:00
cx16.set_rasterirq(uword handler_address, uword rasterline) ; note: disables Kernal irq handler! sys.wait() won't work anymore
2021-02-21 22:41:50 +00:00
cx16.restore_irq() ; set everything back to the systems default irq handler
2022-04-03 15:33:50 +00:00
2023-01-25 23:37:30 +00:00
The Commander X16 syslib provides two additional routines that should be used *in your IRQ handler routine* if it uses the Vera registers.
They take care of saving and restoring the Vera state of the interrupted main program, otherwise the IRQ handler's manipulation
will corrupt any Vera operations that were going on in the main program. The routines are::
cx16.push_vera_context()
; ... do your work that uses vera here...
2022-10-28 21:39:15 +00:00
cx16.pop_vera_context()
.. caution::
It is advised to not use floating point calculations inside IRQ handler routines.
Beside them being very slow, there are intricate requirements such as having the
correct ROM bank enabled to be able to successfully call them (and making sure the correct
ROM bank is reset at the end of the handler), and the possibility
of corrupting variables and floating point calculations that are being executed
in the interrupted main program. These memory locations should be backed up
and restored at the end of the handler, further increasing its execution time...