It provides access to a handful of 64-bit counters that count different things:
- clock cycles
- instructions
- number of IRQ processed
- number of NMIs processed
- nanoseconds since 1-1-1970.
This in not ready yet to be pushed as a merge request into the upstream CC65
repository. What's lacking:
- documentation
- tests
And to be discussed:
- do we agree on this implementation direction and interface in principe?
- can I include inttypes.h for printing a 64-bit unsigned value?
- will clock_gettime() work on a Windows build?
Issue #2539 brings to light a number of issues in the sim65 simulator.
Several issues can be traced back to undesirable side effects of the
use of bare 'unsigned' types for the CPU registers in the 'CPURegs'
type defined in src/sim65/6502.h.
The intention is to tighten the types of the registers defined there
to uint8_t and uint16_t, in accordance with the actual number of bits
that those registers have in the 6502. However, it turns out that a
handful of opcode implementations depend on the fact that the register
types currently have more bits than the actual 6502 registers themselves
for correct operation. This mostly involves operations that involve
the carry bit (ROL, ROR, ADC, SBC).
In preparation of fixing the CPURegs field types, we will first make
sure that those opcode implementations are changed in such a way that
they still work if the underlying register types are tightened to their
actual bit width.
This PR concerns this specific change for the ROL and ROR operations.
The correct functioning of ROL and ROR after this patch has been verified
by testing against the 65x02 test suite.
In sim65, simulator memory access to a 64 KB array is implemented via functions
defined in src/sim65/memory.h and src/sim65/memory.c.
In the old version, the types for both content bytes (8 bits), content words
(16 bits), regular addresses (16 bits), and zero-page addresses (8 bits) were
all given as bare 'unsigned'.
This lead to several cases of address overrun (e.g., when an instruction wraps
around from address 0xffff to 0x0000) when running the simulator against a
stress test (specifically, the 65x02 test suite). To protect from this, and to
more properly express the bit width of the types involved which is a good idea
anyway, we start using the fixed-width types provided by 'stdint.h'.
In the process, we also change the MemReadByte macro to a full function call.
This may impact performance (by a small amount), but it improves memory safety,
as cases where the address is accidentally expressed as a value exceeding 0xffff
are handled by wrap-around (as it is in the actual hardware), rather than causing
access outside of the Mem[] array where the 64 KB of simulated RAM resides.
The reason for this patch is twofold.
(1) It is a partial patch for issue #2539.
Several issues brought to the surface by running the 65x02 testsuite are
eliminated by these changes. In the discussion about this issue, it was
concluded that it is a Good Idea to use the stdint-types, both for the
simulated CPU registers and for the memory. This patch addresses the
memory-part of that change.
(2) It is a precursor patch for issue #2355.
For that issue, we will implement a memory-mapped timer register. This will
make handling of memory access in the simulator a bit more complex.
Having proper functions with the proper types in place will help to make the
timer register patch easier.
The BIT #imm instruction behaves differently from the BIT instruction with other
addressing modes, in that it does /not/ set the N and V flags according to the
value of its operand. It only sets the Z flag, in accordance to the value of
(A & operand).
This is corroborated in two ways:
- The 65x02 test suite;
- Documentation about BIT #imm such as http://www.6502.org/tutorials/65c02opcodes.html
This patch implements the correct behavior for BIT with immediate addressing.
The patched version passes the 65x02 test suite for 65C02 opcode 0x89.
Branch instructions, when taken, take three or four cycles,
depending on whether a page is crossed by the branch.
The proper check to determine whether the extra cycle must be added
is the target address of the branch vs the address immediately
following the branch.
In the former version of the BRANCH instruction handler, the target
address was incorrectly checked vs the address of the branch instruction
itself.
The corrected behavior was verified against a real 6502 (Atari) and
the 65x02 testsuite.
The JMP (ind) bug is present in the 6502 which is emulated by both the "6502" and "6502X"
emulation targets of sim65; specifically, the OPC_6502_6C handler. In the old code, the
bug-exhibiting code was not executed when the target was set to 6502X, which is incorrect.
the patch removes the (CPU == CPU_6502) check, which made no sense.
The JMP (ind) bug was actually fixed in the 65c02. Indeed, the OPC_65C02_6C opcode handler
has code that implements the 'right' behavior.
This PR is mostly a complete rewrite of the emulator for 6502/65c02 opcodes.
It provides an easier to maintain implementation of the instructions, by using few macros rather than having hand-written code for each function.
All undocumented, previously missing opcodes for 6502 are also implemented.
The patch also includes a detailed documentation of those opcodes, for reference to developers.
This PR should fix one of the milestones listed here for the next version of CC65:
https://github.com/cc65/wiki/wiki/Before-the-next-release
MaxCycleCount is accounted by countdown, eliminating the 1-instruction-overhead issue, and removing the need to compare against a growing TotalCycles.
Makes main.c responsible for counting total cycles, instead of 6502.c, so the size of MaxCycleCount etc. is fully determined in one location.
Makes error.c responsible for PrintCycles instead of paravirt.c, so that it can be treated globally instead of
Return value of main() should be SIM65_ERROR because it is unreachable by design.
test/val/constexpr.c relies on close(-1) to return -1 for some reason (comment says "abuse"), but on MSVC close(-1) is treated as a security issue and terminates the program instead of returning -1
simulating this desire for sim65, though constexpr.c may also warrant a review
long is 64-bit on some platforms, making this inconsistent, added range check to catch overflow.
reduced tests requesting 5 billion cycles to 2^32-1 so they can fun on 32-bit long sim65.
The Pop() function was not handling stack pointer wrap around correctly.
Also, change the simulated RTS implementation in ParaVirtHooks() to
explicitly sequence the two Pop() calls in the correct order.
load and run address now configured from header
fix error codes not to conflict with test
fix test/misc/endless.c which is supposed to fail if an endless loop does not occur