mirror of
https://github.com/RaySollium99/picodrive.git
synced 2025-09-04 23:07:46 -04:00

Source: http://www.emu-france.com/emulateurs/7-processeurs/82-680x0/2311-fame/ Fixes https://github.com/notaz/picodrive/issues/132
1128 lines
57 KiB
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áez / Daniel Lancha Garcí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. Using the emulation library</a> <br>
|
|
<a href="#DataStructure">4.1. Data structure</a><br>
|
|
<a href="#CPUcontext">4.1.1.
|
|
CPU context</a><br>
|
|
<a href="#MemoryMapExample">4.1.2.
|
|
Memory map definition example</a><br>
|
|
<a href="#memoryhandling">4.2. Memory handling</a><br>
|
|
<a href="#RunningCPU">4.3. Running the CPU</a><br>
|
|
<a href="#Interrupts">5. Interrupts and exceptions<br>
|
|
</a> <a href="#InterruptAcknowledge">5.1. Interrupt
|
|
acknowledge</a><br>
|
|
<a href="#CustomizingProcessingHLE">5.2. Customizing
|
|
processing (HLE)</a><br>
|
|
<a href="#IRQLoweringtype">5.3. IRQ lowering</a><br>
|
|
<a href="#FunctionReference">6. Function Reference</a><br>
|
|
<a href="#GeneralPurposeFunctions">6.1. General Purpose
|
|
Functions</a><br>
|
|
<a href="#HardwareFunctions">6.2. Hardware interrupt
|
|
handling functions</a><br>
|
|
<a href="#CPUContextFunctions">6.3. CPU context handling
|
|
functions</a><br>
|
|
<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: <a href="mailto:oscar@m68k.com?subject=FAME">oscar@m68k.com</a><br>
|
|
Web site: <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> </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"> <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> </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"> <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®
|
|
80386 CISC engine</font></strong></div></td>
|
|
<td> <div align="center"><strong><font color="#FFFFFF">Super H® 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 & 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> </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"> <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"> Written in <font color="#FF0000"><strong>100% 32-bit assembly language</strong></font>.</div>
|
|
</li>
|
|
<li>
|
|
<div align="justify"> Support for all opcodes.</div>
|
|
</li>
|
|
<li>
|
|
<div align="justify"> Calculates <font color="#FF0000"><strong>100% of flags correctly</strong></font>,
|
|
even undocumented ones.</div>
|
|
</li>
|
|
<li>
|
|
<div align="justify"> 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"> Complete hardware interrupt support.</div>
|
|
</li>
|
|
<li>
|
|
<div align="justify"> Accurate exception support allowing an appropriate emulation of home
|
|
computer systems.</div>
|
|
</li>
|
|
<li>
|
|
<div align="justify"> Priorities between interrupts and exceptions are fully emulated.</div>
|
|
</li>
|
|
</ul>
|
|
<p> </p><table width="100%" border="0" cellspacing="1" cellpadding="1">
|
|
<tr>
|
|
<td bgcolor="#000000"><a name="UsingFAME"></a><font color="#FFFFFF" size="4"><strong> 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>
|
|
unsigned low_addr;<br>
|
|
unsigned high_addr;<br>
|
|
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>
|
|
unsigned low_addr;<br>
|
|
unsigned high_addr;<br>
|
|
void *mem_handler;<br>
|
|
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>
|
|
struct M68K_PROGRAM *fetch;<br>
|
|
struct M68K_DATA *read_byte;<br>
|
|
struct M68K_DATA *read_word;<br>
|
|
struct M68K_DATA *write_byte;<br>
|
|
struct M68K_DATA *write_word;<br>
|
|
struct M68K_PROGRAM *sv_fetch;<br>
|
|
struct M68K_DATA *sv_read_byte;<br>
|
|
struct M68K_DATA *sv_read_word;<br>
|
|
struct M68K_DATA *sv_write_byte;<br>
|
|
struct M68K_DATA *sv_write_word;<br>
|
|
struct M68K_PROGRAM *user_fetch;<br>
|
|
struct M68K_DATA *user_read_byte;<br>
|
|
struct M68K_DATA *user_read_word;<br>
|
|
struct M68K_DATA *user_write_byte;<br>
|
|
struct M68K_DATA *user_write_word;<br>
|
|
void (*reset_handler)(void);</font><font size="2" face="Courier New, Courier, mono"><br>
|
|
void (*iack_handler)(unsigned level);<br>
|
|
unsigned *icust_handler;<br>
|
|
unsigned dreg[8];<br>
|
|
unsigned areg[8];<br>
|
|
unsigned asp;<br>
|
|
unsigned pc;<br>
|
|
unsigned cycles_counter;<br>
|
|
unsigned char interrupts[8];<br>
|
|
unsigned short sr;<br>
|
|
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> ROM: 000000-01FFFF</li>
|
|
<li> RAM-1: 300000-407FFF</li>
|
|
<li> RAM-2: 500000-50FFFF</li>
|
|
<li> RAM-3: 600000-601FFF</li>
|
|
<li> 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>
|
|
{0x000000, 0x01FFFF, (unsigned)rom},<br>
|
|
{0x300000, 0x407FFF, (unsigned)ram1 - 0x300000},<br>
|
|
{0x500000, 0x500FFF, (unsigned)ram2 - 0x500000},<br>
|
|
{-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>
|
|
{0x000000, 0x01FFFF, NULL, rom},<br>
|
|
{0x300000, 0x407FFF, NULL, ram1 - 0x300000},<br>
|
|
{0x500000, 0x507FFF, NULL, ram2 - 0x500000},<br>
|
|
{0x600000, 0x601FFF, mem_access, NULL},<br>
|
|
{0x800000, 0x80AFFF, NULL, ram4 - 0x800000},<br>
|
|
{-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>
|
|
{0x000000, 0x01FFFF, NULL, rom},<br>
|
|
{0x300000, 0x407FFF, NULL, ram1 - 0x300000},<br>
|
|
{0x500000, 0x507FFF, NULL, ram2 - 0x500000},<br>
|
|
{0x600000, 0x601FFF, mem_access, NULL},<br>
|
|
{0x800000, 0x80AFFF, NULL, ram4 - 0x800000},<br>
|
|
{-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>
|
|
{0x000000, 0x01FFFF, NULL, rom},<br>
|
|
{0x300000, 0x407FFF, NULL, ram1 - 0x300000},<br>
|
|
{0x500000, 0x507FFF, NULL, ram2 - 0x500000},<br>
|
|
{0x600000, 0x601FFF, mem_access, NULL},<br>
|
|
{0x800000, 0x80AFFF, NULL, ram4 - 0x800000},<br>
|
|
{-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>
|
|
{0x000000, 0x01FFFF, NULL, rom},<br>
|
|
{0x300000, 0x407FFF, NULL, ram1 - 0x300000},<br>
|
|
{0x500000, 0x507FFF, NULL, ram2 - 0x500000},<br>
|
|
{0x600000, 0x601FFF, mem_access, NULL},<br>
|
|
{0x800000, 0x80AFFF, NULL, ram4 - 0x800000},<br>
|
|
{-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>
|
|
unsigned low_addr;<br>
|
|
unsigned high_addr;<br>
|
|
void *mem_handler;<br>
|
|
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 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>
|
|
return ram[address^1]; <br>
|
|
} </font><br>
|
|
<br>
|
|
<font size="2" face="Courier New, Courier, mono">int readword(int address)<br>
|
|
{ <br>
|
|
return ((unsigned short *)ram)[address>>1];
|
|
<br>
|
|
} <br>
|
|
</font><br>
|
|
<font size="2" face="Courier New, Courier, mono">void writebyte(int address,
|
|
int data)<br>
|
|
{ <br>
|
|
ram[address^1] = data & 0xFF; <br>
|
|
} </font><br>
|
|
<br>
|
|
<font size="2" face="Courier New, Courier, mono">void writeword(int address,
|
|
int data)<br>
|
|
{ <br>
|
|
((unsigned short *)ram)[address>>1] = data &
|
|
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> </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"> <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(&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>
|
|
. . .<br>
|
|
(some actions)<br>
|
|
. . .<br>
|
|
}</font></p>
|
|
<p><font size="2" face="Courier New, Courier, mono">unsigned fpa[256]; /*
|
|
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; /*
|
|
Customizing CHK exception */<br>
|
|
cpu_context.icust_handler = fpa; /* 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> 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"> 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> </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"> <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> 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> 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> </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> Supervisor address space (<font size="2" face="Courier New, Courier, mono">M68K_SUP_ADDR_SPACE</font>)</li>
|
|
<li> User address space (<font size="2" face="Courier New, Courier, mono">M68K_USER_ADDR_SPACE</font>)</li>
|
|
<li> Data address space (<font size="2" face="Courier New, Courier, mono">M68K_DATA_ADDR_SPACE</font>)</li>
|
|
<li> 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 & 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>> -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> </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> <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 < NUMBER_OF_PROCESSORS;
|
|
i++)<br>
|
|
{<br>
|
|
m68k_set_context(&my_contexts[i]);<br>
|
|
m68k_emulate(100);<br>
|
|
m68k_get_context(&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> </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"> <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>
|
|
if (cpu_context.cycles_counter < CPU_TIMESLICE)<br>
|
|
{<br>
|
|
m68k_emulate(CPU_TIMESLICE
|
|
- cpu_context.cycles_counter);<br>
|
|
}<br>
|
|
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> </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"> <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> </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"> <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> </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"> <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ésar Á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é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ández Martín</em> (<a href="mailto:jmartin@uax.es">jmartin@uax.es</a>)
|
|
for his interest in this project.<br>
|
|
- <em>Antonio Garcí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>
|