1st step to Hacker's Guide
--------------------------

0) Content
----------
1) Types
2) Interaction with memory
3) Exceptions
4) HW emulation
5) Emulated opcode
6) Native features
7) Sources
8) debuggers
9) Checking memory boundary
10) Threads and interrupts



1) Types
--------

  In "sysdeps.h" there are declared platform independent integer types:

int8     - signed 8 bit
uint8    - unsigned 8 bit
int16    - signed 16 bit
uint16   - unsigned 16 bit
int32    - signed 32 bit
uint32   - unsigned 32 bit
int64    - signed 64 bit
uint64   - unsigned 64 bit

uintptr  - unsigned type with size of (void *)
intptr   - signed type with size of (void *)

memptr   - this type represents Atari's pointer

  For compatibility between ARAnyM and UAE CPU there are declared also these
types:

uae_s8   ~ int8
uae_u8   ~ uint8
uae_s16  ~ int16
uae_u16  ~ uint16
uae_s32  ~ int32
uae_u32  ~ uint32
uae_s64  ~ int64
uae_u64  ~ uint64

uaecptr  - this type represents Atari's pointer

  These types are only for interaction with CPU core. It is better to use
uintXX/intXX types than uae_XXX types.

  For compatibility between ARAnyM and Bochs IDE emulation there are declared
also these types:

Bit8u   ~ uint8
Bit16u  ~ uint16
Bit32u  ~ uint32

  These types are only for internal IDE emulation, not for ARAnyM.

2) Interaction with memory
--------------------------

  For interaction with memory there are six functions declared in
"cpu_emulation.h", three for reading, three for writing:

uint32 ReadAtariInt32(uint32 addr)
uint16 ReadAtariInt16(uint32 addr)
uint8 ReadAtariInt8(uint32 addr)

void WriteAtariInt32(uint32 addr, uint32 l)
void WriteAtariInt16(uint32 addr, uint16 w)
void WriteAtariInt8(uint32 addr, uint8 b)

  These functions have direct access to memory space. They ignore all settings
of CPU (inclusive of MMU). All functions for an emulation of HW (DMA) in
ARAnyM must become only physical addresses, not logical.
  For all emulations of SW, there are another six functions declared in the
same place:

uint32 ReadInt32(uint32 addr)
uint16 ReadInt16(uint32 addr)
uint8 ReadInt8(uint32 addr)

void WriteInt32(uint32 addr, uint32 l)
void WriteInt16(uint32 addr, uint16 w)
void WriteInt8(uint32 addr, uint8 b)

  If you want to use underlying memory (memory allocated in HW I/O address
space), you can use special, quick functions (they don't make any checking):

uint32 ReadHWMemInt32(uint32 addr)
uint16 ReadHWMemInt16(uint32 addr)
uint8 ReadHWMemInt8(uint32 addr)

void WriteHWMemInt32(uint32 addr, uint32 l)
void WriteHWMemInt16(uint32 addr, uint16 w)
void WriteHWMemInt8(uint32 addr, uint8 b)

  If you want make some large operations in ST-RAM or FastRAM, you can use two
functions for address validation:

The 1st is for non-MMU access:

bool ValidAtariAddr(uint32 addr, bool write, uint32 len)

  You can use ReadHWMemIntXX and WriteHWMemIntXX after this function for
ST-RAM and FastRAM with no problems. It doesn't check HW registers!

The 2nd is for MMU access:

bool ValidAddr(uint32 addr, bool write, uint32 len) 
  
  This function is secure only for len = 1, 2 or 4!


3) Exceptions
-------------

  If you want to generate some Exception, it can be done with this sample code:

regs.mmu_fault_addr = addr;
THROW(No. of Exception);

  If you need to generate bus error, use macro BUS_ERROR(fault_address)
defined in cpu_emulation.h


4) HW emulation
---------------

  In ARAnyM there are two possibilities how to emulate HW - old, classic,
Motorola's - to use HW address space mapped to RAM address space and the
second, which needs special drivers - to use emulated opcode. For the second
possibility look at sections 5th and 6th of these guide.
  If you want to write new emulated "HW" from original Atari computers for
ARAnyM you must use older (but better) access for it - mapped address space.
For inspiration look at "hardware.cpp" and e.g. "mmu.cpp".


5) Emulated opcode
------------------

  For implementation of ARAnyM's specific HW, which cannot be supported by any
emulator of Atari computer, you can use one opcode from 0x71XX. Look at
"emul_op.cpp".


6) Native features
------------------
  HW (or better functions) which are "emulator-independent" can use Native
features. In progress.


7) Sources
--------------
CPU:

BasiliskII (CVS 28.1.2006)
AmigaXL (Amithlon, AmigaOSXL) (14.9.2002)
hatari (CVS 2.2.2002)
UAE 0.8.22
MMU patch 2 against 0.8.20 


IDE:

Bochs (CVS 29.4.2005)


8) debuggers
------------
ARAnyM has four different debuggers:

a) uae     - based on UAE's debugger, most portable
b) ndebug
c) mon     - based on BasiliskII's monitor, it isn't included in ARAnyM's
             sources, you could download it from CVS

                 anoncvs@down.physik.uni-mainz.de:/cvs

You can select a debugger with ./configure script.
There are some functions and macros defined in debug.h for debugger output.


9) Checking memory boundary
---------------------------

  There are many possibilities in ARAnyM how it checks memory boundary. You can
choose one before a compilation process (configure script, parameter
--enable-addr-check). The most stupid solution is no check memory boundary. It
removes all checks of memory boundary, also ROM space can be rewritten.
  The second possibility is full checking. Before every access to Atari memory
it is used an inlined function check_ram_boundary() (uae_cpu/memory.h). This
function checks if desired address and operation (R/W) is correct. If not then
Bus error is generated.
  The third, default, is page check. It is inspired (I think, Johan?) ATC
(Motorola's TLB). If desired address is in the same memory page as previous
used one then check_ram_boundary() isn't needed and the operation is correct.
There are three page buffers - for PC, read and write operation.
  The fourth can be used only on some platforms (today x86 Linux only).
check_ram_boundary() is removed and host's segmentation fault signal is used
for checking memory boundary. On some processor it can be quicker than
the previous possibility.
  The fifth is combination of the third and the fourth possibility.
  The sixth is special possibility, there is sigsegv handler used also
for handling access to HW pace. It isn't completely committed today. It is
used for JIT compiler mainly.


10) Threads and interrupts
--------------------------

I tried several different models of threading in ARAnyM. Although they
always worked OK in Linux there often were problems in non-Linux operating
systems so the current (0.6.2+?) ARAnyM internals are based on the following
model:

- CPU MC68040 emulation runs in the main thread. The main() function
  first calls main.cpp:InitAll(), then Start680x0() (which starts the CPU
  emulation loop) and when the CPU emulation ends it calls
  main.cpp:ExitAll() and quits. So not only MC68040 emulation runs
  in the main thread but also all the EmulOp and Native Features,
  hardware emulation and VIDEL/fVDI screen output.

- Then there is a SDL timer thread that runs with 10 ms resolution (wish it
  was 5 ms but unfortunately SDL is internally locked to 10 ms resolution).
  It calls the main.cpp:my_callback_function() that in turn calls
  TriggerInternalIRQ().
  This Trigger does one simple and quick thing: it sets SPCFLAG_INTERNAL_IRQ
  for the CPU. That's all it does and the timer function then ends.
  It's a very short function (takes only a few CPU cycles) and so it could
  be called from a real timer interrupt (is there such available?),
  preferably running at 200 Hz.

- There is also a SDL_GUI thread but this one is running only if the GUI
  is active. The SDL_GUI thread ensures that the active GUI does not
  stop the emulation - ARAnyM continues running in background! This is 
  an unusual behaviour and was implemented because I wanted to keep
  the Atari time in sync. We basically don't have a Hibernate option
  for the Atari so I had to let the CPU running (including all interrupts
  and stuff). If I didn't do that the Atari time would be delayed.
  This allows for very cool effects (imagine Lines.app running in TOS
  and the GUI dialog above it). If we went for GUI translucence it
  would be astonishing :-)

All the user interactivity and interrupt emulation now relies on the CPU:
When the SPCFLAG_INTERNAL_IRQ is set we have to wait until CPU emulation
calls SERVE_INTERNAL_IRQ() (which normally happens in m68k_do_specialties()
after processing each instruction). This function calls external function
main.cpp:invoke200HzInterrupt() (as you see from the name I wish it was
called 200 times per second).

The invoke200HzInterrupt() then does a whole bunch of things including:
- emulates 200 Hz MFP TimerC interrupt (calls mfp.IRQ(5))
- emulates VBL (calls TriggerVBL())
- updates screen (VIDEL emulation) (calls videl.renderScreen())
- process user input: keyboard and mouse events (calls check_event())
- shows visual activity indicator (calls heartBeat())

As you see from the model once the heart beat stops you can no longer
expect ARAnyM to follow your keyboard or mouse commands. It also means
it's essential to have the CPU emulation correct, not falling into any
neverending loops or traps. Luckily we have just implemented solutions
for the double bus fault as well as bus error loops so we should be
on the safe side now.

