picodrive/cpu/fame/fame.html

1128 lines
57 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>FAME Fast and Accurate Morolora 68000 Emulation Library</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>
<body>
<hr size="1">
<div align="center"><font color="#0000FF" size="4"><strong><font color="#0000FF" size="4"><strong><font size="7">F.A.M.E.</font></strong></font><font size="5"><br>
<font size="4">Fast and Accurate Morolora 68000 Emulation Library</font></font></strong></font><font size="4"><br>
<font size="3"><strong>Copyright (c) 2002-2005 Oscar Orallo Pel&aacute;ez / Daniel Lancha Garc&iacute;a. All rights
reserved.</strong></font></font><br>
<strong>March 14th, 2006</strong><br>
<hr size="1">
<div align="left">
<p><font size="5"><strong>Table of Contents</strong></font></p>
</div>
</div>
<blockquote>
<p> <font size="3"><strong><a href="#Introduction">0. Introduction</a><br>
<a href="#TermsofUse">1. Terms of Use</a><br>
<a href="#VersionHistory">2. Version History</a><br>
</strong><a href="#WhatIsEmulated"><strong>3. What is emulated</strong></a><strong><br>
<a href="#UsingFAME">4.&nbsp;Using the emulation library</a> <br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#DataStructure">4.1. Data structure</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#CPUcontext">4.1.1.
CPU context</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="#MemoryMapExample">4.1.2.
Memory map definition example</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#memoryhandling">4.2. Memory handling</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#RunningCPU">4.3. Running the CPU</a><br>
<a href="#Interrupts">5. Interrupts and exceptions<br>
</a>&nbsp;&nbsp;&nbsp;&nbsp;<a href="#InterruptAcknowledge">5.1. Interrupt
acknowledge</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#CustomizingProcessingHLE">5.2. Customizing
processing (HLE)</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#IRQLoweringtype">5.3. IRQ lowering</a><br>
<a href="#FunctionReference">6. Function Reference</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#GeneralPurposeFunctions">6.1. General Purpose
Functions</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#HardwareFunctions">6.2. Hardware interrupt
handling functions</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#CPUContextFunctions">6.3. CPU context handling
functions</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="#TimingFunctions">6.4. Timing functions</a><br>
<a href="#MultiCPU">7. Multi-CPU systems</a><br>
<a href="#HelpfulTips">8. Helpful tips</a><br>
<a href="#Troubleshooting">9. Troubleshooting</a><br>
<a href="#KnownBugs">10. Known bugs</a><br>
<a href="#SpecialThanks">11. Special thanks</a></strong></font></p>
</blockquote>
<hr size="1">
<br>
<table width="100%" border="0" cellspacing="1" cellpadding="1">
<tr>
<td bgcolor="#000000"><font size="4"><a name="Introduction"></a><font color="#FFFFFF" size="5"><strong>
0. Introduction</strong></font></font></td>
</tr>
</table>
<p align="justify">This is the documentation for FAME library, please read it.</p>
<p align="justify">FAME is an extremely fast and accurate <strong>Motorola 68000 Emulation Library</strong>.
It is currently available for Intel x86-based systems (80386 or better processor)
and SH-4 based systems.</p>
<p align="justify">The x86 version was designed to work under any win32 development environment
such as Microsoft Visual Basic, Microsoft Visual C++, Borland Delphi or Borland
C++ Builder.</p>
<p align="justify">The SH-4 version was specially designed for the Dreamcast videogame console
but it can be used in any SH-4 based system.</p>
<p align="justify">This manual tries to be a guide to get the emulation library working in your
development environment. I hope you find it useful. If you use FAME in your
project I would like to hear your opinion about it.</p>
<p align="justify">The package contains one example (C++ program) to show how the library should
be called and used. It was compiled successfully in Microsoft Visual C++ 6.0
SP5, Borland C++ Builder 5/6 and Borland C++ Compiler 5.5.</p>
<p align="justify">If you have any questions about how it works in your favorite compiler send
me an email. I'd like to help you with FAME.<br>
If you find any bug in FAME, it would be nice that you inform me about that via
<a href="mailto:oscar@m68k.com?subject=FAME">email</a>. Any feedback, comments
and suggestions will also be appreciated.</p>
<p>How to contact Oscar Orallo:</p>
<blockquote>
<p>E-mail:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="mailto:oscar@m68k.com?subject=FAME">oscar@m68k.com</a><br>
Web site:&nbsp; <a href="http://www.m68k.com/fame">http://www.m68k.com/fame</a></p>
</blockquote>
<p>FAME Distribution: <a href="http://www.m68k.com/fame/fame.zip">http://www.m68k.com/fame/fame.zip</a>
(latest)<br>
FAME Development Package: <a href="http://www.m68k.com/fame/famedev.zip">http://www.m68k.com/fame/famedev.zip</a> (latest)</p>
<p>Here we go folks, have fun :)</p>
<p>&nbsp;</p>
<table width="100%" border="0" cellspacing="1" cellpadding="1">
<tr>
<td bgcolor="#000000"><font size="4"><a name="TermsofUse" id="TermsofUse"></a><strong><font color="#FFFFFF">&nbsp;<font size="5">1.
Terms of use</font></font></strong></font></td>
</tr>
</table>
<p> FAME is a development package that contains the following files:</p>
<table width="100%" border="0">
<tr bgcolor="#666666">
<th scope="col"><font color="#FFFFFF">File</font></th>
<th scope="col"><font color="#FFFFFF">Description</font></th>
</tr>
<tr bgcolor="#EEEEEE">
<td>/x86/win32/fame.dll</td>
<td>Microsoft win32 dinamic link library</td>
</tr>
<tr bgcolor="#CCCCCC">
<td>/x86/linux/libfame.a</td>
<td>x86 static ELF library</td>
</tr>
<tr bgcolor="#EEEEEE">
<td>/x86/cygwin/libfame.a</td>
<td>x86 static win32 library</td>
</tr>
<tr bgcolor="#CCCCCC">
<td>/sh4/libfame.a</td>
<td>SH-4 static ELF library</td>
</tr>
<tr bgcolor="#EEEEEE">
<td>/delphi/fame.pas</td>
<td>Delphi unit</td>
</tr>
<tr bgcolor="#CCCCCC">
<td>/doc/fame.html</td>
<td>Documentation file</td>
</tr>
<tr bgcolor="#EEEEEE">
<td>/example/main.c</td>
<td>C source code example</td>
</tr>
<tr bgcolor="#CCCCCC">
<td>/example/makefile.cygwin</td>
<td>Cygwin example makefile </td>
</tr>
<tr bgcolor="#EEEEEE">
<td>/example/makefile.dc</td>
<td>Dreamcast example makefile </td>
</tr>
<tr bgcolor="#CCCCCC">
<td>/example/makefile.linux</td>
<td>Linux example makefile </td>
</tr>
<tr bgcolor="#EEEEEE">
<td bgcolor="#EEEEEE">/example/romdisk/bubble.bin</td>
<td>Motorola 68000 binary code file</td>
</tr>
<tr bgcolor="#CCCCCC">
<td>/lib/bc/fame.lib</td>
<td>Borland C++ 32-bit import library</td>
</tr>
<tr bgcolor="#EEEEEE">
<td>/lib/vc/fame.exp</td>
<td>Microsoft Visual C++ 32-bit export file</td>
</tr>
<tr bgcolor="#CCCCCC">
<td>/include/fame.h</td>
<td>C/C++ header file</td>
</tr>
</table>
<p align="justify"><br>
FAME may be distributed freely in unmodified form, as long as this document
file is included.</p>
<p align="justify">Nothing may be charged for this library. If you want to use it in a shareware
or commercial application, contact me.</p>
<p align="justify">The author will not be held liable for damages. FAME comes with absolutely
NO WARRANTY. Anyway i will try to help you with any problem you have using FAME.</p>
<p align="justify">If you do not agree with all of these terms, please remove FAME from your computer.</p>
<p align="justify">You are encouraged to contact the author if you wish to use FAME in a commercial
product (to negotiate licensing).</p>
<p align="justify">Any program which uses FAME must include in its documentation or in the program
itself the following credit text:</p>
<p><em><strong>FAME Motorola 68000 Emulation Library by Oscar Orallo (oscar@m68k.com)</strong></em></p>
<p>&nbsp;</p>
<table width="100%" border="0" cellspacing="1" cellpadding="1">
<tr>
<td bgcolor="#000000"><font size="4"><a name="VersionHistory"></a><strong><font color="#FFFFFF">&nbsp;<font size="5">2.
Version History</font></font></strong></font></td>
</tr>
</table>
<br>
<table width="100%" border="0" cellpadding="3" cellspacing="1">
<tr bgcolor="#666666">
<td width="50%"><div align="center"><strong><font color="#FFFFFF">Intel&reg;
80386 CISC engine</font></strong></div></td>
<td> <div align="center"><strong><font color="#FFFFFF">Super H&reg; SH-4 RISC
engine</font></strong></div></td>
</tr>
<tr>
<td width="50%" valign="top" bgcolor="#EEEEEE"> <p>Version <strong>2.0a</strong> (14th, march, 2006)</p>
<p>- Stupid bug fixed in IRQ management (thanks Martin Kresse). <br>
- Accurate DIV timing implemented (thanks Jorge Cwik).<br>
- Overflow detection fixed in signed DIV instruction.<br>
- Added makefiles for linux and cygwin environments. </p>
<p>Version <strong>2.0</strong> (11th, january, 2006)</p>
<p>- <em>set_irq_type</em> API function removed. IRQs will be automatically lowered once it was attended.<br>
- Many flag calculations fixed.<br>
- Some minor tweaks. </p>
<p>Version <strong>1.23</strong> (5th April,
2005)</p>
<p>- Timing fixed in MOVEM instructions.</p>
<p>Version <strong>1.22</strong> (7th March, 2005)</p>
<p>- Fixed a stupid bug in <em>fetch</em> function.</p>
<p>Version <strong>1.21</strong> (19th February, 2005)</p>
<p>- <em>set_irq_type</em> function changed for flexible use.<br>
- Pointer to data structure parameter removed from memory handlers to
increase throughtput.</p>
<p>Version <strong>1.2</strong> (17th December, 2004)</p>
<p>- Fixed the PC base calculation for fetch memory regions beyond the first
allocated area.<br>
- Fixed a tiny error in the status register masking. Several instructions
could generate an invalid value.<br>
- Fixed JSR instruction when jumping to a fetch bank different to the
current one.<br>
- Tiny error fixed in interrupt acknowledge function parameter.<br>
- Fixed the <em>set_context</em> function when setting status register.<br>
- Fixed the PC restoring in HLE feature.<br>
- Fixed DIVS instruction operation.</p>
<p>Version <strong>1.1</strong> (7th October, 2004)</p>
<p>- New static ELF library available.<br>
- Interrupt acknowledge calling bug fixed.<br>
- Custom exception processing (HLE) feature added.<br>
- Some little changes in CPU context (register ordering).<br>
- Flag N calculation in CHK instruction fixed.<br>
- Some little code tweaks.<br>
- New sections added to this document.<br>
- Some defines added to header file.<br>
- Some return values have been changed.<br>
- Set/get context functions simplified. Some changes have been applied.
</p>
<p>Version <strong>1.0g</strong> (2nd August, 2004) </p>
<p>- Speed emulation increased once more. The fetch/decode/execute loop
has been inlined.<br>
- Some API functions added:<em> add_cycles</em> and <em>release_cycles</em>.<br>
- Memory handling section added to this document (thanks Richard Hollstein
for requesting it).<br>
- Faster memory access (both program code and data). Memory regions must
be 4 KB aligned now. <br>
- Overhead reduced in <em>emulate</em> function calls (entry/exit code
optimized).<br>
- Interrupt acknowledge function added.<br>
- Some code tweaks here and there.<br>
- Static library for Borland C++ compilers added to the package.<br>
- DLL file size reduced: internal compression (<a href="http://upx.sourceforge.net/" target="_blank">UPX</a>).<br>
- Fixed a bug in STOP instruction: the processor started up after an interrupt
request even if its interrupt level was not higher than current PPL.<br>
- Ver little optimization in branch instructions.<br>
</p>
<p> Version <strong>1.0f</strong> (23th February, 2003)</p>
<p>- API functions added: <em>get_register</em> and <em>set_register</em>
to retrieve and set register values.<br>
- Small optimizations for improved speed.<br>
- CPU context modified: execinfo added for more complete CPU state handling
support. <br>
- LIB file added to package to support implicit linking :).<br>
- Changes in documentation.<br>
- C header file (fame.h) and Delphi unit (fame.pas) modified.<br>
</p>
<p>Version <strong>1.0e</strong> (18th February, 2003)</p>
<p>- Emulation core speed increased lightly (faster entry/exit code). Now
the library is pretty fast.<br>
- Some changes in function and variable naming (odometer changed to cycles_counter).<br>
</p>
<p>Version <strong>1.0d</strong> (20th December, 2002)</p>
<p>- Fetch function speed incremented a bit.<br>
- Fixed memory boundary for byte data accesses.<br>
</p>
<p>Version <strong>1.0c</strong> (27th August, 2002)</p>
<p>- Fixed a stupid bug in group 0 exceptions management.<br>
</p>
<p> Version <strong>1.0b</strong> (16th August, 2002)</p>
<p>- Many errors corrected in documentation about memory mapping.<br>
- The function <em>fetch</em> has now capability to access to the data
address space.</p>
<p><br>
Version <strong>1.0a</strong> (24th July, 2002)</p>
<p>- First public release.</p> </td>
<td valign="top" bgcolor="#EEEEEE"> <p>Version <strong>2.0a</strong> (14th, march, 2006)</p>
<p>- Timing fixed for DIV and signed MUL instructions.<br>
- Improved overflow detection in signed DIV instruction.<br>
- Added makefile for Dreamcast system (requires <a href="http://gamedev.allusion.net/softprj/kos/">KOS</a>). </p>
<p>Version <strong>2.0</strong> (11th, january, 2006)</p>
<p>- Tons of bugs fixed (thanks Chui).<br>
- Accurate DIV timing implemented (thanks Jorge Cwik).<br>
- <em>set_irq_type</em> API function removed. IRQs will be automatically lowered once it was attended.<br>
- Great speed improvements.</p>
<p>Version <strong>0.04 </strong>(5th April, 2005)</p>
<p>- Lightweighted entry/exit code.<br>
- Fixed sign/zero flag calculation when moving long data from memory to
memory.<br>
- Privilege violation exception fixed.<br>
- Faster interrupt/exception management.<br>
- Timing fixed in MOVEM instructions.</p>
<p> Version <strong>0.03 </strong>(7th March, 2005)</p>
<p>- Sign flag calculation in inmediate logical instruction fixed.<br>
- Carry flag calculation in NEG instruction fixed.<br>
- Overflow flag in operations with X flag fixed.<br>
- Fixed CPU state stop bit.<br>
- Speed up by about 20%.<br>
- Tiny tweaks here and there and everywhere.</p>
<p>Version <strong>0.02</strong> (19th February, 2005)</p>
<p>- First beta release.<br>
- <em>set_irq_type</em> function changed for flexible use.<br>
- Greatly improved internal memory management.<br>
- Pointer to data structure parameter removed from memory handlers to
increase throughtput.<br>
- DIV/DIVS instructions fixed.<br>
- ABCD/SBCD adjusted result fixed.<br>
- MOVEM (control addressing mode) instruction fixed.<br>
- BTST with memory addressing mode fixed.<br>
- Fixed Z flag calculation in NEGX instruction.<br>
- Fixed TAS instruction.<br>
- Fixed RESET instruction (external handler calling).<br>
- Fixed ILLEGAL instruction (exception generation).<br>
- Quick ADD to address register fixed.<br>
- EXG instruction fixed.<br>
- V flag calculation fixed in ASL instruction.<br>
- Some tiny tweaks &amp; improvements.</p>
<p>Version <strong>0.01b</strong> (17th December, 2004)</p>
<p>- Memory map cache generation fixed.<br>
- Fixed the PC restoring in HLE feature.<br>
- Many opcodes fixed.<br>
- Lots of bugs fixed.</p>
<p>Version <strong>0.01a</strong> (7th October, 2004)</p>
<p>- First public release. Alpha development state!</p></td>
</tr>
</table>
<p>&nbsp;</p>
<table width="100%" border="0" cellspacing="1" cellpadding="1">
<tr>
<td bgcolor="#000000"><font size="4"><a name="WhatIsEmulated"></a><strong><font color="#FFFFFF">&nbsp;<font size="5">3.
What is emulated</font></font></strong></font></td>
</tr>
</table>
<p>This library emulates the Motorola 68000 microprocessor. The main emulation
features are the following:</p>
<ul>
<li>
<div align="justify">&nbsp;Written in <font color="#FF0000"><strong>100% 32-bit assembly language</strong></font>.</div>
</li>
<li>
<div align="justify">&nbsp;Support for all opcodes.</div>
</li>
<li>
<div align="justify">&nbsp;Calculates <font color="#FF0000"><strong>100% of flags correctly</strong></font>,
even undocumented ones.</div>
</li>
<li>
<div align="justify">&nbsp;Excellent accurate timing emulation for all opcodes. All instructions
have perfect timing emulation according to Motorola references. Take a look at Motorola manuals for more information about this
fact.</div>
</li>
<li>
<div align="justify">&nbsp;Complete hardware interrupt support.</div>
</li>
<li>
<div align="justify">&nbsp;Accurate exception support allowing an appropriate emulation of home
computer systems.</div>
</li>
<li>
<div align="justify">&nbsp;Priorities between interrupts and exceptions are fully emulated.</div>
</li>
</ul>
<p>&nbsp;</p><table width="100%" border="0" cellspacing="1" cellpadding="1">
<tr>
<td bgcolor="#000000"><a name="UsingFAME"></a><font color="#FFFFFF" size="4"><strong>&nbsp;4<font size="5">.
Using the emulation library</font></strong></font></td>
</tr>
</table>
<p> <font size="4"><a name="DataStructure"></a>4.1. Data structure</font></p>
<p align="justify">The data structures used in the emulation core is defined in the C file header
fame.h. In this file you will get all the data structures needed to use the
library.<br>
<br>
If you cannot use this file because you are not using a C/C++ compliant compiler
you have to define this structures by yourself in your code.</p>
<p>Here I describe these data structures.</p>
<blockquote>
<p><font size="2" face="Courier New, Courier, mono">struct M68K_PROGRAM<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;unsigned low_addr;<br>
&nbsp;&nbsp;&nbsp;&nbsp;unsigned high_addr;<br>
&nbsp;&nbsp;&nbsp;&nbsp;unsigned offset;<br>
}</font></p>
</blockquote>
<p align="justify">This structure defines the memory regions for 68000 program code. The fields
<em>low_addr</em> and <em>high_addr</em> are 32-bit values used for determine
the low and high address of the memory block in the 68000 memory map.</p>
<p align="justify">The last field is a 32-bit pointer to the data of the memory region. The data
pointed by it must be allocated in native (Motorola) format. If not, the data
will be fetched incorrectly. Make sure of this fact.</p>
<blockquote>
<p> <font size="2" face="Courier New, Courier, mono">struct M68K_DATA<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;unsigned low_addr;<br>
&nbsp;&nbsp;&nbsp;&nbsp;unsigned high_addr;<br>
&nbsp;&nbsp;&nbsp;&nbsp;void *mem_handler;<br>
&nbsp;&nbsp;&nbsp;&nbsp;void *data;<br>
}</font></p>
</blockquote>
<p align="justify">This one is used for 68000 data code. This structure has an appearance very
similar to the last one but has a diference in the way you can give the control
of the memory to FAME. The pointer called <em>mem_handler</em> is a function
pointer. This pointer is used for memory management, so when you want to take
control in the reading/writing of a memory region, you have to set this pointer
to the appropriate value. If you do not want to use this funcionality you have
to set this pointer to NULL and set <em>data</em> pointing to the data itself.
The different ways to perform memory handling will be described with more detail
in <a href="#memoryhandling">memory handling section</a>.</p>
<p><font size="3"><strong><a name="CPUcontext" id="CPUcontext"></a>4.1.1. CPU
context</strong></font></p>
<blockquote>
<p><font size="2" face="Courier New, Courier, mono">struct M68K_CONTEXT<br>
{<br>
&nbsp;&nbsp;&nbsp; struct M68K_PROGRAM *fetch;<br>
&nbsp;&nbsp;&nbsp;&nbsp;struct M68K_DATA *read_byte;<br>
&nbsp;&nbsp;&nbsp;&nbsp;struct M68K_DATA *read_word;<br>
&nbsp;&nbsp;&nbsp;&nbsp;struct M68K_DATA *write_byte;<br>
&nbsp;&nbsp;&nbsp;&nbsp;struct M68K_DATA *write_word;<br>
&nbsp;&nbsp;&nbsp;&nbsp;struct M68K_PROGRAM *sv_fetch;<br>
&nbsp;&nbsp;&nbsp;&nbsp;struct M68K_DATA *sv_read_byte;<br>
&nbsp;&nbsp;&nbsp;&nbsp;struct M68K_DATA *sv_read_word;<br>
&nbsp;&nbsp;&nbsp;&nbsp;struct M68K_DATA *sv_write_byte;<br>
&nbsp;&nbsp;&nbsp;&nbsp;struct M68K_DATA *sv_write_word;<br>
&nbsp;&nbsp;&nbsp;&nbsp;struct M68K_PROGRAM *user_fetch;<br>
&nbsp;&nbsp;&nbsp;&nbsp;struct M68K_DATA *user_read_byte;<br>
&nbsp;&nbsp;&nbsp;&nbsp;struct M68K_DATA *user_read_word;<br>
&nbsp;&nbsp;&nbsp;&nbsp;struct M68K_DATA *user_write_byte;<br>
&nbsp;&nbsp;&nbsp;&nbsp;struct M68K_DATA *user_write_word;<br>
&nbsp;&nbsp;&nbsp;&nbsp;void (*reset_handler)(void);</font><font size="2" face="Courier New, Courier, mono"><br>
&nbsp;&nbsp;&nbsp; void (*iack_handler)(unsigned level);<br>
&nbsp;&nbsp;&nbsp;&nbsp;unsigned *icust_handler;<br>
&nbsp;&nbsp;&nbsp;&nbsp;unsigned dreg[8];<br>
&nbsp;&nbsp;&nbsp;&nbsp;unsigned areg[8];<br>
&nbsp;&nbsp;&nbsp;&nbsp;unsigned asp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;unsigned pc;<br>
&nbsp;&nbsp;&nbsp;&nbsp;unsigned cycles_counter;<br>
&nbsp;&nbsp;&nbsp;&nbsp;unsigned char interrupts[8];<br>
&nbsp;&nbsp;&nbsp;&nbsp;unsigned short sr;<br>
&nbsp;&nbsp;&nbsp;&nbsp;unsigned short execinfo;<br>
}</font></p>
</blockquote>
<p align="justify">This structure defines a CPU context. You have to declare a variable of this
type. It contains all information related with the context of the CPU.</p>
<p align="justify">You have to set pointer values of <font size="2" face="Courier New, Courier, mono"><em>sv*</em></font>
which defines the supervisor memory map. In order to get the CPU into user mode,
set the <font size="2" face="Courier New, Courier, mono"><em>user*</em></font>
pointers.</p>
<p align="justify">The pointer <em>reset_handler</em> is called when the RESET instruction is
executed. In this way, you can reset all external devices in the calling to
this function. If you do not want to use this feature remember to set this pointer
to NULL.</p>
<p align="justify">The pointer <em>iack_handler</em> is called whenever a hardware interrupt is
handled by the CPU. This feature will be covered later in <a href="#Interrupts">Interrupts
and exceptions section</a>.</p>
<p align="justify">The pointer <em>icust_handler</em> is intented to point to an array of function
pointers to handle customized interrupt/exception processing (known as High
Level Emulation or HLE for short). See <a href="#Interrupts">Interrupts and
exceptions section</a> to set up this feature.</p>
<p align="justify">The rest of the structure is managed by FAME so you can read it in execution
time to retrieve information about the CPU.</p>
<p align="justify">Here I describe some interesting fields for the 68000 programmer:</p>
<blockquote>
<p align="justify"> - <font size="2" face="Courier New, Courier, mono"><strong>dreg[8]</strong></font>
holds the eight data registers in order (d0 - d7).<br>
- <font size="2" face="Courier New, Courier, mono"><strong>areg[8]</strong></font>
holds the eight address registers in order (a0 - a7).<br>
- <font size="2" face="Courier New, Courier, mono"><strong>pc</strong></font>
is the current PC address.<br>
- <font size="2" face="Courier New, Courier, mono"><strong>asp</strong></font>
stands for <em>Alternative Stack Pointer</em>. It is used to store the not
currently used stack pointer. In supervisor mode, asp is the user stack pointer,
in user mode it is the supervisor stack pointer.<br>
- <font size="2" face="Courier New, Courier, mono"><strong>cycles_counter</strong></font>
holds the number of cycles executed so far.<br>
- <font size="2" face="Courier New, Courier, mono"><strong>interrupts</strong></font>
is an array that contains information about interrupts.<br>
- <font size="2" face="Courier New, Courier, mono"><strong>sr</strong></font>
is the status register.</p>
</blockquote>
<p><font size="3"><strong><a name="MemoryMapExample"></a>4.1.2 Memory map definition
example</strong></font></p>
<p align="justify"> As an example of an address space definition, consider the following simple
memory map:</p>
<ul>
<li> &nbsp;ROM: 000000-01FFFF</li>
<li>&nbsp;RAM-1: 300000-407FFF</li>
<li>&nbsp;RAM-2: 500000-50FFFF</li>
<li>&nbsp;RAM-3: 600000-601FFF</li>
<li>&nbsp;RAM-4: 800000-80AFFF</li>
</ul>
<p align="justify">This is the structure for the program address space. I will suppose that ROM,
RAM-1 and RAM-2 contains program code.</p>
<blockquote>
<p> <font size="2" face="Courier New, Courier, mono">struct M68K_PROGRAM prg_fetch[]
= {<br>
&nbsp;&nbsp;&nbsp;&nbsp;{0x000000, 0x01FFFF, (unsigned)rom},<br>
&nbsp;&nbsp;&nbsp;&nbsp;{0x300000, 0x407FFF, (unsigned)ram1 - 0x300000},<br>
&nbsp;&nbsp;&nbsp;&nbsp;{0x500000, 0x500FFF, (unsigned)ram2 - 0x500000},<br>
&nbsp;&nbsp;&nbsp;&nbsp;{-1, -1, NULL}<br>
}</font></p>
</blockquote>
<p>Note that the last entry must be <font size="2" face="Courier New, Courier, mono">{-1,
-1, NULL}</font>.</p>
<p align="justify">Now, I will set up the data address space. In this case, I will suppose that
all memory areas will be accesed and that RAM-3 is accessed by the routine <em>mem_access</em>.
To do this, you will have to set up the following:</p>
<p>- One structure for read byte operations:</p>
<blockquote>
<p> <font size="2" face="Courier New, Courier, mono">struct M68K_DATA data_rb[]
= {<br>
&nbsp;&nbsp;&nbsp;&nbsp;{0x000000, 0x01FFFF, NULL, rom},<br>
&nbsp;&nbsp;&nbsp;&nbsp;{0x300000, 0x407FFF, NULL, ram1 - 0x300000},<br>
&nbsp;&nbsp;&nbsp;&nbsp;{0x500000, 0x507FFF, NULL, ram2 - 0x500000},<br>
&nbsp;&nbsp;&nbsp;&nbsp;{0x600000, 0x601FFF, mem_access, NULL},<br>
&nbsp;&nbsp;&nbsp;&nbsp;{0x800000, 0x80AFFF, NULL, ram4 - 0x800000},<br>
&nbsp;&nbsp;&nbsp;&nbsp;{-1, -1, NULL, NULL}<br>
}</font></p>
</blockquote>
<p>- One structure for write byte operations:</p>
<blockquote>
<p> <font size="2" face="Courier New, Courier, mono">struct M68K_DATA data_wb[]
= {<br>
&nbsp;&nbsp;&nbsp;&nbsp;{0x000000, 0x01FFFF, NULL, rom},<br>
&nbsp;&nbsp;&nbsp;&nbsp;{0x300000, 0x407FFF, NULL, ram1 - 0x300000},<br>
&nbsp;&nbsp;&nbsp;&nbsp;{0x500000, 0x507FFF, NULL, ram2 - 0x500000},<br>
&nbsp;&nbsp;&nbsp;&nbsp;{0x600000, 0x601FFF, mem_access, NULL},<br>
&nbsp;&nbsp;&nbsp;&nbsp;{0x800000, 0x80AFFF, NULL, ram4 - 0x800000},<br>
&nbsp;&nbsp;&nbsp;&nbsp;{-1, -1, NULL, NULL}<br>
}</font></p>
</blockquote>
<p>- One structure for read word operations:</p>
<blockquote>
<p> <font size="2" face="Courier New, Courier, mono">struct M68K_DATA data_rw[]
= {<br>
&nbsp;&nbsp;&nbsp;&nbsp;{0x000000, 0x01FFFF, NULL, rom},<br>
&nbsp;&nbsp;&nbsp;&nbsp;{0x300000, 0x407FFF, NULL, ram1 - 0x300000},<br>
&nbsp;&nbsp;&nbsp;&nbsp;{0x500000, 0x507FFF, NULL, ram2 - 0x500000},<br>
&nbsp;&nbsp;&nbsp;&nbsp;{0x600000, 0x601FFF, mem_access, NULL},<br>
&nbsp;&nbsp;&nbsp;&nbsp;{0x800000, 0x80AFFF, NULL, ram4 - 0x800000},<br>
&nbsp;&nbsp;&nbsp;&nbsp;{-1, -1, NULL, NULL}<br>
}</font></p>
</blockquote>
<p>- One structure for write word operations:</p>
<blockquote>
<p> <font size="2" face="Courier New, Courier, mono">struct M68K_DATA data_ww[]
= {<br>
&nbsp;&nbsp;&nbsp;&nbsp;{0x000000, 0x01FFFF, NULL, rom},<br>
&nbsp;&nbsp;&nbsp;&nbsp;{0x300000, 0x407FFF, NULL, ram1 - 0x300000},<br>
&nbsp;&nbsp;&nbsp;&nbsp;{0x500000, 0x507FFF, NULL, ram2 - 0x500000},<br>
&nbsp;&nbsp;&nbsp;&nbsp;{0x600000, 0x601FFF, mem_access, NULL},<br>
&nbsp;&nbsp;&nbsp;&nbsp;{0x800000, 0x80AFFF, NULL, ram4 - 0x800000},<br>
&nbsp;&nbsp;&nbsp;&nbsp;{-1, -1, NULL, NULL}<br>
}</font></p>
</blockquote>
<p align="justify">In the example, the routine used for access to ram3 area is the same in all
the structures defined but it could be different.</p>
<p align="justify">And now the last step is to fill the CPU context with the defined address spaces.
This is accomplished in the following way:</p>
<blockquote>
<p> <font size="2" face="Courier New, Courier, mono">struct M68K_CONTEXT cpu_contxt;</font></p>
<p><font size="2" face="Courier New, Courier, mono">cpu_contxt.sv_fetch = prg_fetch;<br>
cpu_contxt.user_fetch = prg_fetch;</font></p>
<p><font size="2" face="Courier New, Courier, mono"> cpu_contxt.sv_read_byte
= data_rb;<br>
cpu_contxt.user_read_byte = data_rb;<br>
cpu_contxt.sv_read_word = data_rw;<br>
cpu_contxt.user_read_word = data_rw;<br>
cpu_contxt.sv_write_byte = data_wb;<br>
cpu_contxt.user_write_byte = data_wb;<br>
cpu_contxt.sv_write_word = data_ww;<br>
cpu_contxt.user_write_word = data_ww;</font></p>
</blockquote>
<p align="justify">Note that the memory address spaces for supervisor and user are the same. This
is very common but remember they could be different.</p>
<p>And that is all.<br>
</p>
<p><font size="4"><a name="Memoryhandling"></a>4.2. Memory handling</font></p>
<p>The emulation library provides two ways to perform the access to the memory
map: <em>built-in</em> and <em>custom</em>.</p>
<p align="justify">The built-in memory handling is ideal to get the maximun speed to the memory
map but at the cost of less control. To use it you have to set <em>data</em>
pointing to the beginning of the native memory region and set <em>mem_handler</em>
to NULL.</p>
<blockquote>
<p> <font size="2" face="Courier New, Courier, mono"> struct M68K_DATA<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;unsigned low_addr;<br>
&nbsp;&nbsp;&nbsp;&nbsp;unsigned high_addr;<br>
&nbsp;&nbsp;&nbsp;&nbsp;void *mem_handler;<br>
&nbsp;&nbsp;&nbsp;&nbsp;void *data;<br>
}</font></p>
</blockquote>
<p align="justify">The custom memory handling gives you total control over memory accesses but
its use could create a bottleneck in the emulated system if it is used inappropriately.
To use this feature you have to set up <em>mem_handler</em> pointer to the handling
function. That function will be called whenever a memory access is done.<br>
There is a restriction in the definition of a memory region: <u>it must be 4
KB aligned</u>. So it must start on 0XXX000h and end on 0YYYFFFh.</p>
<p align="justify">Memory handling functions have the following structure:</p>
<p align="justify"><font size="2" face="Courier New, Courier, mono">int &nbsp;read_xxxx (int address);<br>
void write_xxxx(int address, int data);</font></p>
<p align="justify">where <em>xxxx</em> stands for byte, word or long depending on data size, <em>
address</em> is the memory address accessed and <em>data</em> is the data itself.</p>
<p align="justify">Using memory handling functions might be a good way to customize emulated memory
space. You have to read/write data in the way FAME expects. This process could
become confusing. To avoid undesired problems in this point, i have written
some simple routines to make your life easier:</p>
<blockquote>
<p><font size="2" face="Courier New, Courier, mono">int readbyte(int address)<br>
{ <br>
&nbsp;&nbsp;&nbsp;&nbsp;return ram[address^1]; <br>
} </font><br>
<br>
<font size="2" face="Courier New, Courier, mono">int readword(int address)<br>
{ <br>
&nbsp;&nbsp;&nbsp;&nbsp;return ((unsigned short *)ram)[address&gt;&gt;1];
<br>
} <br>
</font><br>
<font size="2" face="Courier New, Courier, mono">void writebyte(int address,
int data)<br>
{ <br>
&nbsp;&nbsp;&nbsp;&nbsp;ram[address^1] = data &amp; 0xFF; <br>
} </font><br>
<br>
<font size="2" face="Courier New, Courier, mono">void writeword(int address,
int data)<br>
{ <br>
&nbsp;&nbsp;&nbsp;&nbsp;((unsigned short *)ram)[address&gt;&gt;1] = data &amp;
0xFFFF; <br>
} </font></p>
</blockquote>
<p align="justify">I am considering you have your emulated memory region (pointed by <em>ram</em> here)
in native endian format (this is, big endian for the 68000 processor). Note
the required endianess switch in the byte accesses, since we are reading in
a little endian machine (x86 and SH4 processors).</p>
<p><br>
<a name="RunningCPU"></a><font size="4">4.3. Running the CPU</font></p>
<p>In order to get the 68000 CPU running, you have to do the following steps:</p>
<blockquote>
<p>1. Initialize the emulation library. Call <font size="2" face="Courier New">m68k_init()</font>
to perform this task.<br>
2. Set up the memory map (see <a href="#MemoryMapExample">section 4.1.2</a>).<br>
3. Reset the processor calling the <font size="2" face="Courier New">m68k_reset()</font>
function.<br>
4. Execute code calling <font size="2" face="Courier New">m68k_emulate(n)</font>
function where the parameter n means the number of clock cycles to execute.</p>
</blockquote>
<p><u>Note:</u> See <a href="#FunctionReference">Function Reference section</a>
for more information about how API functions work.</p>
<p>&nbsp;</p>
<table width="100%" border="0" cellspacing="1" cellpadding="1">
<tr>
<td bgcolor="#000000"><font size="4"><a name="Interrupts"></a><strong><font color="#FFFFFF">&nbsp;<font size="5">5.
Interrupts and exceptions</font></font></strong></font></td>
</tr>
</table>
<p align="justify">The library currently emulates the <strong>group 0 exceptions</strong> (address
error and bus error), <strong>group 1 exceptions</strong> (trace mode, external
interrupts, illegal opcode and privilege violation) and <strong>group 2 exceptions</strong>.</p>
<p align="justify">The <strong>reset exception</strong> is not emulated. This is due to performance
facts. If this exception was emulated, the performance of the library would
fall notably. If you need this exception be emulated, contact me.</p>
<p align="justify">Hardware interrupts can be raised at any time, but it will be attended only in the entry code of the emulate function. To manage interrupts, please refer to the section <a href="#FunctionReference">Function Reference</a> bellow.</p>
<p align="justify">If you have any doubt about how these events work, I recommend you to take a look at <a href="http://e-www.motorola.com/brdata/PDFDB/docs/MC68000UM.pdf" target="_blank">M68000 Microprocessors User's Manual</a> (english) or at the book <em>Sistemas Digitales</em> (spanish).</p>
<p><strong><a name="InterruptAcknowledge"></a></strong><font size="4">5.1. Interrupt
acknowledge</font></p>
<p align="justify">Sometimes could be useful to be warned when a hardware interrupt is being attended.
This feature is frequently called <em>interrupt acknowledging</em> and allows
you to take specific actions when an interrupt is handled, signaling a device
to lower the interrupt request, for example.<br>
This function accepts one parameter, the interrupt level, and returns no value.</p>
<blockquote>
<p><font size="2" face="Courier New, Courier, mono">void iackhandler(unsigned
int_level);</font></p>
</blockquote>
<p>Once you have defined your function, set up the CPU context:</p>
<blockquote>
<p><font size="2" face="Courier New, Courier, mono"> struct M68K_CONTEXT cpu_contxt;</font></p>
<p><font size="2" face="Courier New, Courier, mono">cpu_contxt.iack_handler
= iackhandler;<br>
m68k_set_context(&amp;cpu_contxt);</font></p>
</blockquote>
<p>If you do not need this feature, set this pointer to NULL to avoid undesired
results.</p>
<p><strong><a name="CustomizingProcessingHLE"></a></strong><font size="4">5.2.
Customizing processing (HLE)</font></p>
<p align="justify">Sometimes it is needed to trap an exception to perform some native tasks overriding
target system tasks (system BIOS calls, for example).</p>
<p align="justify">To customize interrupt and exception processing use <em>icusthandler</em> table
pointer. This pointer must point to a table of a total of 256 function pointers,
each one handling each vector exception presented in the 68000 system starting
from address $000000. The index of the table is the vector number.</p>
<p>The handling function accepts one parameter, the vector exception number, and
returns no value.</p>
<blockquote>
<p><font size="2" face="Courier New, Courier, mono">void icusthandler(unsigned
vector);</font></p>
</blockquote>
<p>The array of pointers could be used in this fashion:</p>
<blockquote>
<p><font size="2" face="Courier New, Courier, mono">/* Function to customize
CHK exception */<br>
void chk_handler(unsigned vector)<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;. . .<br>
&nbsp;&nbsp;&nbsp;&nbsp;(some actions)<br>
&nbsp;&nbsp;&nbsp;&nbsp;. . .<br>
}</font></p>
<p><font size="2" face="Courier New, Courier, mono">unsigned fpa[256]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*
Function Pointer Array declaration */<br>
struct M68K_CONTEXT</font><font size="2" face="Courier New, Courier, mono">
cpu_context; <br>
<br>
fpa[6] = chk_handler; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*
Customizing CHK exception */<br>
cpu_context.icust_handler = fpa;&nbsp; /* Setting up function pointers */</font></p>
</blockquote>
<p><font size="2" face="Courier New, Courier, mono"> </font>Take in account the
following when you use this feature:</p>
<ul>
<li> &nbsp;Remember to set to NULL those exceptions you do not want to be customized
in the array of function pointers.</li>
<li>
<div align="justify">&nbsp;Group 0 exceptions are a special type of exception. Since they are
raised when something has gone seriously wrong with the system, they can not
be customized.</div>
</li>
</ul>
<p>If you do not need this feature, set this pointer to NULL to avoid undesired
results.</p>
<p><font size="4"><a name="IRQLoweringtype"></a>5.3. IRQ lowering</font></p>
<p>Every IRQ will be automatically lowered once it has been attended. User selectable IRQ lowering type has been removed.</p>
<p>&nbsp;</p>
<table width="100%" border="0" cellspacing="1" cellpadding="1">
<tr>
<td bgcolor="#000000"><font size="4"><a name="FunctionReference"></a><strong><font color="#FFFFFF">&nbsp;<font size="5">6.
Function Reference</font></font></strong></font></td>
</tr>
</table>
<p>This is a brief description of the library functions. </p>
<ul>
<li>&nbsp;For C/C++ programmers:
<p> - They are declared in fame.h to include in your C/C++ application. You
can take a look at the sample program included.</p>
</li>
<li>&nbsp;For Delphi programmers:
<p> - Copy fame.pas and fame.dll into your project's directory. Add fame.pas
to your project.</p>
</li>
</ul>
<p><br>
Remember that this is a brief overview. If you do not find answers to your questions,
contact me.</p>
<p><br>
<font size="4"><a name="GeneralPurposeFunctions"></a>6.1. General Purpose Functions</font><br>
</p>
- <strong>void m68k_init (void)</strong>
<hr size="1" noshade>
<p>This function initialize the emulation library. Must be called before any other
function library.<br>
</p>
- <strong>unsigned m68k_reset (void)</strong>
<hr size="1" noshade>
<p>Resets the CPU. You must set up the memory map before call this function.</p>
<p> Return values:</p>
<blockquote>
<p> <strong>M68K_OK (0)</strong>: Success.<br>
<strong>M68K_RUNNING (1)</strong>: The function failures because the CPU is
running. Stop the CPU first.<br>
<strong>M68K_NO_SUP_ADDR_SPACE (2)</strong>: The CPU could not be resetted
because there is no supervisor memory map for opcode fetching.<br>
</p>
</blockquote>
- <strong>void m68k_emulate (int n)</strong>
<hr size="1" noshade>
<p align="justify">Starts the emulation and executes n clock cycles. This is the function you
have to call to execute 68000's code. The number of elapsed CPU cycles is the
lowest number equal or greater than n.</p>
<p><br>
- <strong>unsigned m68k_get_pc (void)</strong></p>
<hr size="1" noshade>
<p>Returns the current PC address. The value returned by this function does not
have to be equal to the beginning of an instruction.<br>
</p>
- <strong>unsigned m68k_get_cpu_state (void)</strong>
<hr size="1" noshade>
<p>Returns information about the CPU current state. It could be called at any
time to retrieve interesting and useful information about the CPU state.</p>
<p>The data returned has the following format:</p>
<blockquote>
<table width="100%" border="0">
<tr bgcolor="#666666">
<th scope="col"><font color="#FFFFFF">Bits</font></th>
<th bgcolor="#666666" scope="col"><font color="#FFFFFF">Meaning</font></th>
</tr>
<tr bgcolor="#EEEEEE">
<td>0</td>
<td>Internal use. Should be zero.</td>
</tr>
<tr bgcolor="#CCCCCC">
<td>1</td>
<td>Processing a group 0 exception (address error or bus error).</td>
</tr>
<tr bgcolor="#EEEEEE">
<td>2</td>
<td>Double bus fault has happened.</td>
</tr>
<tr bgcolor="#CCCCCC">
<td>3</td>
<td>Trace mode is being processed. </td>
</tr>
<tr bgcolor="#EEEEEE">
<td>4</td>
<td>Processing trace mode exception.</td>
</tr>
<tr bgcolor="#CCCCCC">
<td>5</td>
<td>Processing bus error exception.</td>
</tr>
<tr bgcolor="#EEEEEE">
<td>6</td>
<td>Processing address error exception.</td>
</tr>
<tr bgcolor="#CCCCCC">
<td>7</td>
<td>CPU stopped by the STOP instruction.</td>
</tr>
<tr bgcolor="#EEEEEE">
<td>8-31</td>
<td>Reserved for future use. Should be zero.</td>
</tr>
</table>
</blockquote>
<p>&nbsp;</p>
- <strong>int m68k_fetch(unsigned address, unsigned memory_space)</strong>
<hr size="1" noshade>
<p>Fetches the word pointed by the specified address using the given memory space
from the fetch memory array. The memory space means the following:</p>
<ul>
<li>&nbsp;Supervisor address space (<font size="2" face="Courier New, Courier, mono">M68K_SUP_ADDR_SPACE</font>)</li>
<li>&nbsp;User address space (<font size="2" face="Courier New, Courier, mono">M68K_USER_ADDR_SPACE</font>)</li>
<li>&nbsp;Data address space (<font size="2" face="Courier New, Courier, mono">M68K_DATA_ADDR_SPACE</font>)</li>
<li>&nbsp;Program address space (<font size="2" face="Courier New, Courier, mono">M68K_PROG_ADDR_SPACE</font>)</li>
</ul>
<p>Generally, you will want to fetch a word from a memory map joining two of those
primitives types. For example:</p>
<blockquote>
<p>Supervisor Data Address Space (Supervisor &amp; Data)</p>
</blockquote>
<p>To accomplish this, you have to use a bitwise OR operation: </p>
<blockquote>
<p><font size="2" face="Courier New, Courier, mono">M68K_SUP_ADDR_SPACE | M68K_DATA_ADDR_SPACE</font></p>
</blockquote>
<p> Return value:</p>
<blockquote>
<p> <strong>FFFFFFFFh</strong>: The address specified is out of bounds in the
given <br>
memory space.<br>
<strong>0000xxxxh</strong>: The fetched word.</p>
</blockquote>
<p><br>
<strong><font size="3"><a name="HardwareFunctions"></a></font></strong><font size="3"><font size="4">6.2
Hardware interrupt handling functions</font></font><br>
</p>
- <strong>int m68k_raise_irq (int level, int vector)</strong>
<hr size="1" noshade>
<p align="justify">This function allows you to generate a hardware interrupt. This event is external
to the CPU and generally activated by an external device. The possible values
for the parameter level are between 1 and 7, both inclusive.</p>
<p>For vector the values are the following:</p>
<blockquote>
<p> <strong>M68K_AUTOVECTORED_IRQ (-1)</strong>: Autovectored interrupt.<br>
<strong>M68K_SPURIOUS_IRQ (-2)</strong>: Spurious interrupt.<br>
<strong>0-255</strong>: Vector number.</p>
</blockquote>
<p>Return value:</p>
<blockquote>
<p> <strong>M68K_OK (0)</strong>: Success.<br>
<strong>M68K_INT_LEVEL_ERROR (-1)</strong>: The function failures because
there is another interrupt activated at the given level.<br>
<strong>M68K_INT_INV_PARAMS (-2)</strong>: Invalid parameter values. The vector
value is not valid or the level is equal to zero.</p>
</blockquote>
<p><br>
<strong>int m68k_lower_irq (int level)</strong></p>
<hr size="1" noshade>
<p>This function is used to deactivate an interrupt.</p>
<p>Return value:</p>
<blockquote>
<p> <strong>M68K_OK (0)</strong>: The interrupt has been deactivated successfully.<br>
<strong>M68K_IRQ_LEVEL_ERROR (-1)</strong>: The function failures because
the interrupt is not activated.<br>
<strong>M68K_IRQ_INV_PARAMS (-2)</strong>: Invalid interrupt level value.</p>
</blockquote>
<p><br>
- <strong>int m68k_get_irq_vector (int level)</strong></p>
<hr size="1" noshade>
<p>Calling this function you will get the vector of a generated interrupt at the
given interrupt level.</p>
<p>Return value:</p>
<blockquote>
<p> <strong>&gt; -1</strong>: Requested interrupt vector.<br>
<strong>M68K_IRQ_LEVEL_ERROR (-1)</strong>: The function failures because
the interrupt is not activated.<br>
<strong>M68K_IRQ_INV_PARAMS (-2)</strong>: Invalid interrupt level.<br>
</p>
</blockquote>
- <strong>int m68k_change_irq_vector (int level, int vector)</strong>
<hr size="1" noshade>
<p align="justify">It allows you to change the vector of a generated interrupt. Remember that
the interrupt must be already activated when you call this function.<br>
The possible values for vector are between 0 and 255, both inclusive.</p>
<p>Return value:</p>
<blockquote>
<p> <strong>M68K_OK (0)</strong>: Success.<br>
<strong>M68K_IRQ_LEVEL_ERROR (-1)</strong>: The interrupt at the given vector
was not activated.<br>
<strong>M68K_IRQ_INV_PARAMS (-2)</strong>: Invalid interrupt vector value.</p>
</blockquote>
<p><br>
<strong><font size="3"><a name="CPUContextFunctions"></a></font></strong><font size="3"><font size="4">6.3.
CPU context handling functions</font></font><br>
</p>
<p>These functions are intented for handling the CPU context.<br>
</p>
- <strong>int m68k_get_context_size (void)</strong>
<hr size="1" noshade>
<p>Returns the size in bytes of the CPU context.<br>
</p>
- <strong>void m68k_get_context (void *context)</strong>
<hr size="1" noshade>
<p align="justify">Fills the context pointed by the pointer with the current CPU context. You
must deserve memory space in order to allocate the CPU context.<br>
</p>
- <strong>void m68k_set_context (void *context)</strong>
<hr size="1" noshade>
<p>Allows you to set up the CPU context. The parameter is a pointer to the context
structure.<br>
</p>
- <strong>int m68k_get_register (m68k_register reg)</strong>
<hr size="1" noshade>
<p>Returns the value of the specified register. If the value of the reg parameter
is not valid, the function will return -1.</p>
<p align="justify">Note that the value returned by the function when the register specified is
not valid (-1) is a valid 32-bit register value. This may be cause for concern.<br>
</p>
- <strong>int m68k_set_register (m68k_register reg, unsigned value)</strong>
<hr size="1" noshade>
<p>Sets the value of the specified register.</p>
<p>Return values:</p>
<blockquote>
<p><strong>M68K_OK (0)</strong>: Success.<br>
<strong>M68K_INV_REG (-1)</strong>: The register specified is not valid.</p>
</blockquote>
<p><br>
<strong><a name="TimingFunctions"></a></strong><font size="4">6.4. Timing functions</font></p>
<p align="justify">These functions allows you to control the CPU cycles executed in the emulation.
This way, you can adjust the emulation speed. The <em>cycles_counter</em>
is the variable used in the library to count the CPU cycles. For each calling
to function <em>emulate</em>, the executed CPU cycles are added to <em>cycles_counter</em>.<br>
</p>
<strong>- unsigned m68k_get_cycles_counter (void)</strong>
<hr size="1" noshade>
<p>Returns the current value of the <em>cycles_counter</em>.<br>
</p>
- <strong>unsigned m68k_trip_cycles_counter (void)</strong>
<hr size="1" noshade>
<p>Returns the current value of the <em>cycles_counter</em> variable and resets
it to zero.</p>
<br>
- <strong>unsigned m68k_control_cycles_counter (int n)</strong>
<hr size="1" noshade>
<p>If the parameter <em>n</em> is equal to zero, the function returns the <em>cycles_counter</em>.<br>
Otherwise, it returns the <em>cycles_counter</em> resetting it to zero.<br>
</p>
- <strong>void m68k_release_timeslice (void)</strong>
<hr size="1" noshade>
<p align="justify">Calling this function you will request the CPU to finish its execution as soon
as possible. The premature exit will be reflected in the <em>cycles_counter</em>.<font size="4"><br>
</font></p>
<p>- <strong>void m68k_add_cycles (int cycles)</strong></p>
<hr size="1" noshade>
<p align="justify">Call this function when you want to increase the clock cycles counting (<em>cycles_counter</em>
variable).<br>
This function could be useful when emulating systems equipped with DMA capabilities,
keeping track of how many clock cycles the CPU was frozen by any device doing
a DMA operation.<br>
</p>
<p> - <strong>void m68k_release_cycles (int cycles)</strong></p>
<hr size="1" noshade>
<p>Call this function when you want to decrease the clock cycles counting (<em>cycles_counter</em>
variable).</p>
<p>&nbsp;</p>
<table width="100%" border="0" cellspacing="1" cellpadding="1">
<tr>
<td bgcolor="#000000"><font size="4"><a name="MultiCPU"></a><font color="#FFFFFF"><strong>&nbsp;<font size="5">7.
Multi-CPU systems</font></strong></font></font></td>
</tr>
</table>
<p align="justify">Emulating multiple 68000 processors is fairly simple. If you want to emulate
more than one 68000 processor, you have to set up a CPU context and a memory
map for each one (see <a href="#MemoryMapExample">memory map example</a>).</p>
<p>For example, you would do this:</p>
<blockquote>
<p><font size="2" face="Courier New">struct M68K_CONTEXT my_contexts[NUMBER_OF_PROCESSORS];</font></p>
<p> <font size="2" face="Courier New">for (int i = 0; i &lt; NUMBER_OF_PROCESSORS;
i++)<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;m68k_set_context(&amp;my_contexts[i]);<br>
&nbsp;&nbsp;&nbsp;&nbsp;m68k_emulate(100);<br>
&nbsp;&nbsp;&nbsp;&nbsp;m68k_get_context(&amp;my_contexts[i]);<br>
}</font></p>
</blockquote>
<p>Try to compensate the overhead due to the copying of the contexts emulating
the CPUs in large timeslices.</p>
<p>FAME is non-reentrant so you cannot multi-thread several processors. If you
need FAME running in this way, contact me.</p>
<p>&nbsp;</p>
<table width="100%" border="0" cellspacing="1" cellpadding="1">
<tr>
<td bgcolor="#000000"><font size="4"><a name="HelpfulTips"></a><strong><font color="#FFFFFF">&nbsp;<font size="5">8.
Helpful tips</font></font></strong></font></td>
</tr>
</table>
<p align="justify"> - It is recommended to use built-in memory handlers as much as possible because
they should be much faster than others coded into high level languages.</p>
<p align="justify"> - Use timeslices as large as possible because this way you will reduce the overhead
produced by the entry and exit code of the library.</p>
<p>- Try to avoid context swapping. It will reduce performance notably.</p>
<p align="justify"> - It is a good idea to call the <em>emulate</em> function with a variable
number of cycles instead of a fixed one. Keep track of how many cycles overflowed
from the last call to <em>emulate</em> and subtract them in the next calling:</p>
<blockquote>
<p> <font size="2" face="Courier New">#define CPU_TIMESLICE 100</font></p>
<p><font size="2" face="Courier New"> cpu_context.cycles_counter = 0;<br>
while(!done)<br>
{<br>
&nbsp;&nbsp;&nbsp;&nbsp;if (cpu_context.cycles_counter &lt; CPU_TIMESLICE)<br>
&nbsp;&nbsp;&nbsp;&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m68k_emulate(CPU_TIMESLICE
- cpu_context.cycles_counter);<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;cpu_context.cycles_counter -= CPU_TIMESLICE;<br>
}</font></p>
</blockquote>
<p align="justify">- Library routines were designed with accuracy and speed in mind. Use them
as much as possible in order to reach a fast and accurate emulated system.</p>
<p align="justify">- The object code contains many symbols for program relocation. Strip your executable when you are done. </p>
<p>&nbsp;</p>
<table width="100%" border="0" cellspacing="1" cellpadding="1">
<tr>
<td bgcolor="#000000"><font size="4"><a name="Troubleshooting"></a><strong><font color="#FFFFFF">&nbsp;<font size="5">9.
Troubleshooting</font></font></strong></font></td>
</tr>
</table>
<p align="justify">This section tries to help you to get the library working correctly. I hope
you find this section useful.</p>
<p align="justify"> - Remember to call <em>init</em> function before any other function library.
It initialize the library setting up the emulator.</p>
<p align="justify"> - You must call <em>reset</em> function before starting the emulation in order
to get the library working appropriately.</p>
<p align="justify"> - Set up your memory map before reset the CPU. The reset function look up
the vector table.</p>
<p align="justify"> - Ensure that the CPU context has been set correctly after the calling to
<em>set_context</em>.</p>
<p align="justify"> - Check if memory maps are well-constructed. Every memory region must be 4
KB aligned. This is a common pitfall.</p>
<p align="justify">- Check if your emulated processor is accessing memory correctly specially
when you have to use memory handling functions. Take a look at the <a href="#Memoryhandling">Memory
handling section</a> if you are having problems in this point.</p>
<p align="justify">- Make sure to set <em>reset_handler</em>,<em> iack_handler</em> and <em>icust_handler</em>
to NULL if you are not using these features. It would be a good idea to set
every byte of a new context to zero to avoid any problem.</p>
<p align="justify">- Remember to set every handler not used in the array of function pointers
(<em>icust_handler</em>) to NULL to avoid undesired results.</p>
<p align="justify">- Remember to include <em>fame.h</em> in any C module that use FAME. This header
file is subject to change in future versions.</p>
<p align="justify">- Make sure to instruct your compiler configuration to treat enum types as
32-bit ints when using <font size="2" face="Courier New">m68k_get_register</font>
and <font size="2" face="Courier New">m68k_set_register</font> functions.</p>
<p>&nbsp;</p>
<table width="100%" border="0" cellspacing="1" cellpadding="1">
<tr>
<td bgcolor="#000000"><font size="4"><a name="KnownBugs"></a><strong><font color="#FFFFFF">&nbsp;<font size="5">10.
Known bugs</font></font></strong></font></td>
</tr>
</table>
<p align="justify"> - The bit I/N (specific information about the processor activity) saved on
the supervisor stack when an address or bus error happens is not calculated
and its value is fixed to one (instruction). This tiny detail will be implemented
in future versions if needed.</p>
<p>&nbsp; </p>
<table width="100%" border="0" cellspacing="1" cellpadding="1">
<tr>
<td bgcolor="#000000"><font size="4"><a name="SpecialThanks"></a><strong><font color="#FFFFFF">&nbsp;<font size="5">11.
Special thanks</font></font></strong></font></td>
</tr>
</table>
<p align="justify">Many thanks go out to those who helped me out with this library or contributed
to the project in any form in no special order. </p>
<p align="justify">- <em>Chui</em> for his invaluable work to get this thing up into his NeoGeo
emulator (<a href="http://chui.dcemu.co.uk/neo4all.html">Neo4All</a>) and for helping me to fix loads of errors.<br>
- <em>Bart Trzynadlowski</em> (<a href="mailto:trzynadl@unr.nevada.edu">trzynadl@unr.nevada.edu</a>)
for his notes about 68000 undocumented behavior.<br>
- <em>Julio C&eacute;sar &Aacute;lvarez Acosta</em> (<a href="mailto:julio_a_a@yahoo.es">julio_a_a@yahoo.es</a>)
for his help to build the import library.<br>
- <em>Richard Hollstein</em> for let me know that memory handling functions
were not documented in previous releases.<br>
- <em>Jorge Cwik</em> for figuring out the algorithm to calculate the exact number of cycles in DIV instructions. <br>
- <em>Neill Corlett</em> for his excellent Starscream 680x0 emulation library
which give me a lot of understandings and ideas on CPU emulation.<br>
- <em>St&eacute;phane Dallongeville</em> for Gens (probably the best Genesis/Mega
Drive emulator ever programmed) and for giving me his opinion about several
aspects of 68000 emulation.<br>
- <em>BlackAura</em> and <em>Ian Micheal</em> for telling me about the high
level emulation (HLE) feature.<br>
- <em>Juan Carlos Hern&aacute;ndez Mart&iacute;n</em> (<a href="mailto:jmartin@uax.es">jmartin@uax.es</a>)
for his interest in this project.<br>
- <em>Antonio Garc&iacute;a Guerra</em> for his great book <em>Sistemas Digitales</em>.<br>
- The creators of the 68000 microprocessor, because without their work nothing
of this might be a reality.<br>
<br>
Thank you too! for your interest in the library. If you have any suggestions,
comments or contributions do not hesitate to get in contact with <a href="mailto:oscar@m68k.com?subject=FAME">me</a>.</p>
<p align="justify">Have a nice day!</p>
</body>
</html>