mirror of
https://github.com/cc65/cc65.git
synced 2025-03-21 05:31:08 +00:00
356 lines
12 KiB
Plaintext
356 lines
12 KiB
Plaintext
<!doctype linuxdoc system> <!-- -*- text-mode -*- -->
|
|
|
|
<article>
|
|
|
|
<title>sim65 Users Guide
|
|
<author><url url="mailto:polluks@sdf.lonestar.org" name="Stefan A. Haubenthal">,<newline>
|
|
<url url="mailto:bbbradsmith@users.noreply.github.com" name="Brad Smith">
|
|
|
|
|
|
<abstract>
|
|
sim65 is a simulator for 6502 and 65C02 CPUs. It allows to test target
|
|
independent code.
|
|
</abstract>
|
|
|
|
<!-- Table of contents -->
|
|
<toc>
|
|
|
|
<!-- Begin the document -->
|
|
|
|
<sect>Overview<p>
|
|
|
|
|
|
sim65 is used as part of the toolchain to test 6502 or 65C02 code.
|
|
The binary to test should be compiled with <tt/--target sim6502/ or <tt/--target sim65c02/.
|
|
|
|
|
|
<sect>Usage<p>
|
|
|
|
The simulator is called as follows:
|
|
|
|
<tscreen><verb>
|
|
Usage: sim65 [options] file [arguments]
|
|
Short options:
|
|
-h Help (this text)
|
|
-c Print amount of executed CPU cycles
|
|
-v Increase verbosity
|
|
-V Print the simulator version number
|
|
-x <num> Exit simulator after <num> cycles
|
|
|
|
Long options:
|
|
--help Help (this text)
|
|
--cycles Print amount of executed CPU cycles
|
|
--verbose Increase verbosity
|
|
--version Print the simulator version number
|
|
</verb></tscreen>
|
|
|
|
sim65 will exit with the error code of the simulated program,
|
|
which is limited to an 8-bit result 0-255.
|
|
|
|
An error in sim65, like bad arguments or an internal problem will exit with <tt/1/.
|
|
|
|
A timeout from <tt/-x/ will exit with <tt/2/.
|
|
|
|
|
|
<sect1>Command line options in detail<p>
|
|
|
|
Here is a description of all the command line options:
|
|
|
|
<descrip>
|
|
|
|
<tag><tt>-h, --help</tt></tag>
|
|
|
|
Print the short option summary shown above.
|
|
|
|
|
|
<tag><tt>-c, --cycles</tt></tag>
|
|
|
|
Print the number of executed CPU cycles when the program terminates.
|
|
The cycles for the final "<tt>jmp exit</tt>" are not included in this
|
|
count.
|
|
|
|
|
|
<tag><tt>-v, --verbose</tt></tag>
|
|
|
|
Increase the simulator verbosity.
|
|
|
|
|
|
<tag><tt>-V, --version</tt></tag>
|
|
|
|
Print the version number of the utility. When submitting a bug report,
|
|
please include the operating system you're using, and the compiler
|
|
version.
|
|
|
|
|
|
<tag><tt>-x num</tt></tag>
|
|
|
|
Exit simulator after num cycles.
|
|
</descrip>
|
|
|
|
|
|
<sect>Input and output<p>
|
|
|
|
The simulator will read one binary file per invocation and can log the
|
|
program loading and paravirtualization calls to stderr.
|
|
|
|
Example output for the command
|
|
<tscreen><verb>
|
|
sim65 --verbose --verbose samples/gunzip65
|
|
</verb></tscreen>
|
|
<tscreen><verb>
|
|
Loaded 'samples/gunzip65' at $0200-$151F
|
|
PVWrite ($0001, $13C9, $000F)
|
|
GZIP file name:PVWrite ($0001, $151F, $0001)
|
|
|
|
PVRead ($0000, $FFD7, $0001)
|
|
PVOpen ("", $0001)
|
|
PVRead ($0003, $1520, $6590)
|
|
PVClose ($0003)
|
|
PVWrite ($0001, $13D9, $000F)
|
|
Not GZIP formatPVWrite ($0001, $151F, $0001)
|
|
|
|
PVExit ($01)
|
|
</verb></tscreen>
|
|
|
|
|
|
<sect>Creating a Test in C<p>
|
|
|
|
For a C test linked with <tt/--target sim6502/ and the <tt/sim6502.lib/ library,
|
|
command line arguments to <tt/sim65/ will be passed to <tt/main/,
|
|
and the return value from <tt/main/ will become sim65's exit code.
|
|
The <tt/stdlib.h/ <tt/exit/ function may also be used to terminate with an exit code.
|
|
|
|
Exit codes are limited to an unsigned 8 bit value. (E.g. returning -1 will give an exit code of 255.)
|
|
|
|
The standard C library high level file input and output is functional.
|
|
A sim65 application can be written like a command line application,
|
|
providing command line arguments to <tt/main/ and using the <tt/stdio.h/ interfaces
|
|
to interact with the console or access files.
|
|
|
|
Internally, file input and output is provided at a lower level by
|
|
a set of built-in paravirtualization functions (see <ref id="paravirt-internal" name="below">).
|
|
|
|
Example:
|
|
|
|
<tscreen><verb>
|
|
#include <stdio.h>
|
|
int main()
|
|
{
|
|
printf("Hello!\n");
|
|
return 5;
|
|
}
|
|
|
|
// Build and run:
|
|
// cl65 -t sim6502 -o example.prg example.c
|
|
// sim65 example.prg
|
|
|
|
// Build and run, separate steps:
|
|
// cc65 -t sim6502 -o example.s example.c
|
|
// ca65 -t sim6502 -o example.o example.s
|
|
// ld65 -t sim6502 -o example.prg example.o sim6502.lib
|
|
// sim65 example.prg
|
|
</verb></tscreen>
|
|
|
|
<sect>Creating a Test in Assembly<p>
|
|
|
|
Though a C test may also link with assembly code,
|
|
a pure assembly test can also be created.
|
|
|
|
Link with <tt/--target sim6502/ or <tt/--target sim65c02/ and the corresponding library,
|
|
define and export <tt/_main/ as an entry point,
|
|
and the sim65 library provides two ways to return an 8-bit exit code:
|
|
|
|
<itemize>
|
|
|
|
<item>Return from <tt/_main/ with the exit code in <tt/A/.
|
|
|
|
<item><tt/jmp exit/ with the code in <tt/A/. (<tt/.import exit/ from the sim65 library.)
|
|
|
|
</itemize>
|
|
|
|
Example:
|
|
|
|
<tscreen><verb>
|
|
.export _main
|
|
_main:
|
|
lda #5
|
|
rts
|
|
|
|
; Build and run:
|
|
; cl65 -t sim6502 -o example.prg example.s
|
|
; sim65 example.prg
|
|
|
|
; Build and run, separate steps:
|
|
; ca65 -t sim6502 -o example.o example.s
|
|
; ld65 -t sim6502 -o example.prg example.o sim6502.lib
|
|
; sim65 example.prg
|
|
</verb></tscreen>
|
|
|
|
Internally, the binary program file has a 12 byte header provided by the library:
|
|
|
|
<itemize>
|
|
|
|
<item>5 byte <bf/signature/: <tt/$73, $69, $6D, $36, $35/ or <tt/'sim65'/
|
|
|
|
<item>1 byte <bf/version/: <tt/2/
|
|
|
|
<item>1 byte <bf/CPU type/: <tt/0/ = 6502, <tt/1/ = 65C02
|
|
|
|
<item>1 byte <bf/sp address/: the zero page address of the C parameter stack pointer <tt/sp/ used by the paravirtualization functions
|
|
|
|
<item>1 word <bf/load address/: where to load the data from the file into memory (default: <tt/$0200/)
|
|
|
|
<item>1 word <bf/reset address/: specifies where to begin execution after loading (default: <tt/$0200/)
|
|
|
|
</itemize>
|
|
|
|
Other internal details:
|
|
|
|
<itemize>
|
|
|
|
<item>The entire 64 kilobyte address space is writeable RAM.
|
|
Aside from the loaded binary, the reset vector at <tt/$FFFC/ will be
|
|
pre-loaded with the given <bf/reset address/.
|
|
|
|
<item>The <tt/exit/ address is <tt/$FFF9/.
|
|
Jumping to this address will terminate execution with the A register value as an exit code.
|
|
|
|
<label id="paravirt-internal">
|
|
<item>Several bytes immediately below the vector table are reserved for paravirtualization functions.
|
|
Except for <tt/exit/, a <tt/JSR/ to one of these addresses will return immediately after performing a special function.
|
|
These use cc65 calling conventions, and are intended for use with the sim65 target C library.
|
|
|
|
<item><tt/IRQ/ and <tt/NMI/ events will not be generated, though <tt/BRK/
|
|
can be used if the IRQ vector at <tt/$FFFE/ is manually prepared by the test code.
|
|
|
|
<item>The <tt/sim6502/ or <tt/sim65c02/ targets provide a default configuration,
|
|
but if customization is needed <tt/sim6502.cfg/ or <tt/sim65c02.cfg/ might be used as a template.
|
|
|
|
</itemize>
|
|
|
|
<sect>Counter peripheral
|
|
|
|
<p>The sim65 simulator supports a memory-mapped counter peripheral that manages
|
|
a number of 64-bit counters that are continuously updated as the simulator is
|
|
running. For each counter, it also provides a 64 bit "latching" register.
|
|
|
|
<p>The functionality of the counter peripheral is accessible through 3 registers:
|
|
|
|
<itemize>
|
|
<item><tt>PERIPHERALS_COUNTER_LATCH</tt> ($FFC0, write-only)
|
|
<item><tt>PERIPHERALS_COUNTER_SELECT</tt> ($FFC1, read/write)
|
|
<item><tt>PERIPHERALS_COUNTER_VALUE</tt> ($FFC2..$FFC9, read-only)
|
|
</itemize>
|
|
|
|
<p>These three registers are used as follows.
|
|
|
|
<p>When a program explicitly requests a "counter latch" operation by writing any value
|
|
to the <tt>PERIPHERALS_COUNTER_LATCH</tt> address ($FFC0), all live registers are simultaneously
|
|
copied to the latch registers. They will keep the newly latched value until another latch
|
|
operation is requested.
|
|
|
|
<p>The <tt>PERIPHERALS_COUNTER_SELECT</tt> address ($FFC1) register holds an 8-bit value that
|
|
specifies which 64-bit latch register is currently readable through the <tt>PERIPHERALS_COUNTER_VALUE</tt>
|
|
address range. Six values are currently defined:
|
|
|
|
<itemize>
|
|
<item>$00: latched clock cycle counter selected.
|
|
<item>$01: latched CPU instruction counter selected.
|
|
<item>$02: latched IRQ interrupt counter selected.
|
|
<item>$03: latched NMI interrupt counter selected.
|
|
<item>$80: latched wallclock time (nanoseconds) selected.
|
|
<item>$81: latched wallclock time (split s/ns) selected.
|
|
</itemize>
|
|
|
|
<p>Values $00 to $03 provide access to the latched (frozen) value of their respective live
|
|
counters at the time of the last write to <tt>PERIPHERALS_COUNTER_LATCH</tt>.
|
|
|
|
<p>When <tt>PERIPHERALS_COUNTER_LATCH</tt> equals $80, the <tt>PERIPHERALS_COUNTER_VALUE</tt>
|
|
will be a 64-bit value corresponding to the number of nanoseconds elapsed since Midnight, Jan 1st,
|
|
1970 UTC, at the time of the last latch operation.
|
|
|
|
<p>When <tt>PERIPHERALS_COUNTER_LATCH</tt> equals $81, the high 32 bits of <tt>PERIPHERALS_COUNTER_VALUE</tt>
|
|
will be a 32-bit value corresponding to the number of seconds elapsed since Midnight,
|
|
Jan 1st, 1970 UTC, at the time of the last latch operation. The low 32 bits of
|
|
<tt>PERIPHERALS_COUNTER_VALUE</tt> will hold the nanoseconds since the start of that second.
|
|
|
|
<p>The two different wallclock-time latch registers will always refer to precisely the same time instant.
|
|
For some applications, the single 64-bit value measured in nanoseconds will be more convenient, while
|
|
for other applications, the split 32/32 bits representations with separate second and nanosecond
|
|
values will be more convenient.
|
|
|
|
<p>Note that the definition above, with time elapsed measured since Midnight, Jan 1st, 1970 UTC, is
|
|
an approximation, as the implementation depends on the way POSIX definition time, and POSIX does
|
|
not account for leap seconds; it falsely assumes that all days are precisely 86400 seconds long.
|
|
|
|
<p>On reset, <tt>PERIPHERALS_COUNTER_SELECT</tt> is initialized to zero. If the <tt>PERIPHERALS_COUNTER_SELECT</tt>
|
|
register holds a value other than one of the six values described above, all <tt>PERIPHERALS_COUNTER_VALUE</tt>
|
|
bytes will read as zero.
|
|
|
|
<p>The <tt>PERIPHERALS_COUNTER_VALUE</tt> addresses ($FFC2..$FFC9) are used to read to currently
|
|
selected 64-bit latch register value. Address $FFC2 holds the least significant byte (LSB),
|
|
while address $FFC9 holds the most significant byte (MSB).
|
|
|
|
<p>On reset, all latch registers are reset to zero. Reading any of the <tt>PERIPHERALS_COUNTER_VALUE</tt>
|
|
bytes before the first write to <tt>PERIPHERALS_COUNTER_LATCH</tt> will yield zero.
|
|
|
|
Example:
|
|
|
|
<tscreen><verb>
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
|
|
volatile uint8_t * CounterLatch = (uint8_t *)0xffc0;
|
|
volatile uint8_t * CounterSelect = (uint8_t *)0xffc1;
|
|
volatile uint32_t * CounterValue = (uint32_t *)0xffc1;
|
|
|
|
static void print_current_counters(void)
|
|
{
|
|
*CounterLatch = 0; /* latch values */
|
|
|
|
*CounterSelect = 0x00;
|
|
printf("clock cycles ............... : %08lx %08lx\n", CounterValue[1], CounterValue[0]);
|
|
*CounterSelect = 0x01;
|
|
printf("instructions ............... : %08lx %08lx\n", CounterValue[1], CounterValue[0]);
|
|
*CounterSelect = 0x80;
|
|
printf("wallclock time ............. : %08lx %08lx\n", CounterValue[1], CounterValue[0]);
|
|
*CounterSelect = 0x81;
|
|
printf("wallclock time, split ...... : %08lx %08lx\n", CounterValue[1], CounterValue[0]);
|
|
printf("\n");
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
print_current_counters();
|
|
print_current_counters();
|
|
return 0;
|
|
}
|
|
</verb></tscreen>
|
|
|
|
<sect>Copyright<p>
|
|
|
|
sim65 (and all cc65 binutils) are (C) Copyright 1998-2000 Ullrich von
|
|
Bassewitz. For usage of the binaries and/or sources the following conditions
|
|
do apply:
|
|
|
|
This software is provided 'as-is', without any expressed or implied
|
|
warranty. In no event will the authors be held liable for any damages
|
|
arising from the use of this software.
|
|
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
including commercial applications, and to alter it and redistribute it
|
|
freely, subject to the following restrictions:
|
|
|
|
<enum>
|
|
<item> The origin of this software must not be misrepresented; you must not
|
|
claim that you wrote the original software. If you use this software
|
|
in a product, an acknowledgment in the product documentation would be
|
|
appreciated but is not required.
|
|
<item> Altered source versions must be plainly marked as such, and must not
|
|
be misrepresented as being the original software.
|
|
<item> This notice may not be removed or altered from any source
|
|
distribution.
|
|
</enum>
|
|
|
|
</article>
|