Commit Graph

149 Commits

Author SHA1 Message Date
Colin Leroy-Mira
50cccc2c3a Add lseek to sim6502 paravirt 2025-01-01 14:32:03 +01:00
sidney
511f4478de Fixed style issues. 2024-12-29 22:26:38 +01:00
Sidney Cadot
7980b81ddb sim65: Fix instruction timings for 6502 and 65C02.
This PR fixes all discrepancies of sim65 instruction timings, for both the 6502 and the 65C02 processors.

The timings as implemented in this PR have been verified against actual hardware (Atari 800 XL for 6502; and WDC 65C02 for 65C02).

These timings can also be verified against the 65x02 test suite. However, in this case, a single discrepancy arises; the 65x02 testsuite suggests that the 65C02 opcode 0x5c should take 4 clocks. However, tests on a hardware 65C02 have conclusively shown that this instruction takes 8 clock cycles. The 8 clock cycles duration for the 65C02 0xfc opcode is also confirmed by other sources, e.g. Section 9 of http://www.6502.org/tutorials/65c02opcodes.html.

This test makes sim65 correct both in terms of functionality (all opcodes now do what they do on hardware) and in terms of timing (all instructions take as long as they would on real hardware).

The one discrepancy that remains, is that on a real 6502/65C02, some instructions issue R or W cycles on the bus while the instruction processing is being done. Those spurious bus cycles are not replicated in sim65. Sim65 is thus an instruction-level simulator, rather than a bus-cycle level simulator. In other words, while the clock cycle counts for each instruction are now correct, not all clock cycles are individually simulated.
2024-12-24 09:24:02 +01:00
Sidney Cadot
07b168e062 Merge pull request #2573 from sidneycadot/fix-6502x-illegals
sim65: properly implement 5 'illegal' 6502X opcodes.
2024-12-24 08:29:16 +01:00
Sidney Cadot
fbf3bde97c sim65: properly implement 5 'illegal' 6502X opcodes.
This PR fixes the implementation of 5 illegal opcodes
in the 6502, which the 6502X supports:

* $93   SHA (zp),y
* $9B   TAS abs,y
* $9C   SHY abs,x
* $9E   SHX abs,x
* $9F   SHA abs,y

The common denominator of the previous implementation was that it didn't correctly handle the case when the Y or X indexing induced a page crossing. In those cases, the effective address calculation of the instructions becomes truly messed up (with the high byte of the address equal to the value being written).

The correctness of the implementations in this PR was verified using the 65x02 test suite, and corresponds to a (detailed) reading of the "No More Secrets" document.

Stylistically, there is room for improvement in these implementations, specifically in factoring out common behavior into macros. However, for now the "explicit" coding style will suffice. It is clear enough, and we want to reach a situation soon where the sim65
code is able to pass the full '65x02' testsuite. Once we get to that point, we can refactor this code with a lot more confidence, since we will have the benefit of a working exhaustive test to make sure we don't break stuff.
2024-12-22 19:48:41 +01:00
Sidney Cadot
d064ca424f sim65: implemented missing 65C02 instructions
This PR implements support for 32 65C02-specific instructions
to sim65: BBRx, BBSx, RMBx, SMBx, with x = 0..7.

These instructions are implemented using two macros:

* The "ZP_BITOP" macro implements the RMBx and SMBx isntructions.
* The "ZP_BIT_BRANCH" macro implements the BBRx abd BBSx instructions.

The implementation of these instructions has been verified usingthe 65x02 test suite.
2024-12-22 19:15:20 +01:00
Sidney Cadot
075514c60c Merge pull request #2569 from sidneycadot/fix-cpu-register-types
sim65: tighten 6502 register types
2024-12-22 18:00:16 +01:00
Sidney Cadot
3c5d5aac63 Merge pull request #2568 from sidneycadot/fix-ane-behavior
sim65: changes constant of the unstable "ANE" instruction.
2024-12-22 17:59:57 +01:00
Sidney Cadot
8cb941985d sim65: tighten 6502 register types
After a lot of preparatory work, we are now in position to finally tighten
the types of the 6502 registers defined in the CPURegs struct of sim65.

All registers were previously defined as bare 'unsigned', leading to subtle
bugs where the bits beyond the 8 or 16 "true" bits in the register could
become non-zero. Tightening the types of the registers to uint8_t and
uint16_t as appropriate gets rid of these subtle bugs once and for all,
assisted by the semantics of C when assigning an unsigned value to an
unsigned type with less bits: the high-order bits are simply discarded,
which is precisely what we'd want to happen.

This change cleans up a lot of spurious failures of sim65 against the
65x02 test-set. For the 6502 and 65C02, we're now *functionally*
compliant. For timing (i.e., clock cycle counts for each instruction),
some work remains.
2024-12-19 23:13:20 +01:00
Sidney Cadot
b14f883e73 sim65: changes constant of the unstable "ANE" instruction to comply with 65x02 test suite.
ANE (0x8b) is an unstable illegal opcode that depends on a "constant" value that isn't
really constant. It varies between machines, with temperature, and so on. Original sim65
behavior was to use the constant value 0xEF. To get the behavior in line with the 65x02
testsuite, we now use the value 0xEE instead, which is also a reasonable choice that can
be observed in practice.
2024-12-19 22:58:42 +01:00
Sidney Cadot
bad2f54f75 Fix memory access order of the JSR instruction.
The obvious way to implement JSR for the 6502 is to (a) read the target address,
and then (b) push the return address minus one. Or do (b) first, then (a).

However, there is a non-obvious case where this conflicts with the actual order
of operations that the 6502 does, which is:

(a) Load the LSB of the target address.
(b) Push the MSB of the return address, minus one.
(c) Push the LSB of the return address, minus one.
(d) Load the MSB of the target address.

This can make a difference in a pretty esoteric case, if the JSR target is located,
wholly or in part, inside the stack page (!). This won't happen in normal code
but it can happen in specifically constructed examples.

To deal with this, we load the LSB and MSB of the target address separately, with
the pushing of the return address sandwiched in between, to mimic the order of the
bus operations on a real 6502.
2024-12-19 22:35:15 +01:00
Bob Andrews
c52d7b27e6 Merge pull request #2564 from sidneycadot/fix-cpuregs-linkage
sim65: simulated CPU registers can be accessed from outside 6502.c.
2024-12-19 21:09:37 +01:00
Sidney Cadot
86ccf25e81 CPU registers can be accessed from outside 6502.c.
The linkage of the 'Regs' variable in 6502.c was changed from static
to extern. This makes the Regs type visible (and even alterable) from
the outside.

This change helps tools to inspect the CPU state. In particular, it
was implemented to facilitate a tool that verifies opcode
functionality using the '65x02' testsuite. But the change is also
potentially useful for e.g. an online debugger that wants to inspect
the CPU state while the 6502 is neing simulated.
2024-12-16 17:12:07 +01:00
Sidney Cadot
fb6745573e Fixed whitespace. 2024-12-16 16:55:26 +01:00
Sidney Cadot
dfc88d5796 Merge branch 'cc65:master' into fix-adc-sbc 2024-12-16 16:46:26 +01:00
Sidney Cadot
eda8774e08 Fixed ADC/SBC for the 65C02.
The current (before-this-patch) version of sim65.c does not correctly implement
the ADC and SBC instructions in 65C02 mode. This PR fixes that.

The 6502 and 65C02 behave identically in binary mode; in decimal behavior
however they diverge, both in the handling of inputs that are not BCD values,
and in the handling of processor flags.

This fix restructures the original "ADC" and "SBC" macros in versions that
are specific for the 6502 and the 65C02, and updates the opcode tables to
ensure that they point to the correct implementations.

Considering the ADC instruction for a moment, the original "ADC" macro was
changed to two macros ADC_6502 and ADC_65C02. These check the D (decimal
mode) bit, and defer their implementation to any of three macros ADC_BINARY_MODE,
ADC_DECIMAL_MODE_6502, and ADC_DECIMAL_MODE_65C02. This is a bit verbose but it
makes it very clear what's going on.

(For the SBC changes, the analogous changes were made.)

The correctness of the changes made is ensured as follows:

First, an in-depth study was made how ADC and SBC work, both in the original
6502 and the later 65C02 processor. The actual behavior of both processors
was captured on hardware (an Atari 800 XL with a 6502 and a Neo6502 equipped
with a WDC 65C02 processor), and was analyzed. The results were cross-referenced
with internet sources, leading to a C implementation that reproduces the exact
result of the hardware processors. See:

https://github.com/sidneycadot/6502-test/blob/main/functional_test/adc_sbc/c_and_python_implementations/6502_adc_sbc.c

Next, these C implementations of ADC and SBC were fitted into sim65's macro-
based implementation scheme, replacing the existing 6502-only implementation.

Finally, the new sim65 implementation was tested against the 65x02 testsuite,
showing that (1) the 6502 implementation was still correct; and (2) that
the 65C02 implementation is now also correct.

As an added bonus, this new implementation of ADC/SBC no longer relies on a
dirty implementation detail in sim65: the previous implementation relied on
the fact that currently, the A register in the simulator is implemented as
an "unsigned", with more bits than the actual A register (8 bits). In the
future we want to change the register width to 8 bits, and this updated
ADC/SBC is a necessary precursor to that change.
2024-12-16 16:36:23 +01:00
Bob Andrews
11699a4124 Merge pull request #2557 from sidneycadot/fix-sim65-rol-ror-ops
sim65 : improve implementation of ROL and ROR operations
2024-12-15 22:59:39 +01:00
Sidney Cadot
05b3825683 sim65 : improve implementation of ROL and ROR operations
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.
2024-12-03 23:33:57 +01:00
Sidney Cadot
fbd8961be1 sim65: changing memory access types to uint8_t and uint16_t.
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.
2024-12-03 21:21:49 +01:00
Sidney Cadot
84c4ea062d Sim65: removed ZR register from CPURegs type. 2024-12-03 01:17:44 +01:00
Bob Andrews
c0a4942b5d Merge pull request #2550 from sidneycadot/fix-bit-imm
Fixed behavior of the 65C02 "BIT #imm" instruction in sim65.
2024-12-02 00:28:07 +01:00
Bob Andrews
918c39cbeb Merge pull request #2548 from sidneycadot/fix-branch-timings
Fixed clock-cycle timing of branch (Bxx) instructions.
2024-12-02 00:25:54 +01:00
Bob Andrews
3895caae90 Style fix 2024-12-02 00:25:24 +01:00
Bob Andrews
79e26c1bc5 Merge pull request #2547 from sidneycadot/fix-jmp-ind
Fixed the behavior of JMP (ind) in sim65 when it runs with the 6502X CPU type.
2024-12-02 00:21:31 +01:00
Sidney Cadot
e26c17fd50 Fixed wrong clearing of D-flag on interrupts for sim65 with 6502X CPU type.
The 65C02 clears the D flag on interrupts while the 6502 does not.

The old code cleared the D flag also for the 6502X CPU type, which
was incorrect.
2024-12-01 09:59:10 +01:00
Sidney Cadot
1d9d056da5 Fixed behavior of the 65C02 "BIT #imm" instruction.
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.
2024-11-30 23:46:19 +01:00
Sidney Cadot
709d71ef70 Fixed clock-cycle timing of branch (Bxx) instructions.
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.
2024-11-30 19:56:31 +01:00
Sidney Cadot
2abd66ea0c Fixed the behavior of the JMP (ind) instruction in sim65 when it runs with the "6502X" CPU type.
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.
2024-11-30 12:36:35 +01:00
Bob Andrews
a372ead4de Merge pull request #2334 from carlo-bramini/fix-sim65-1
[SIM65] Support undocumented opcodes for 6502
2024-03-10 00:37:18 +01:00
Carlo Bramini
b04d79b1da [SIM65] Support undocumented opcodes for 6502
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
2024-02-08 12:13:17 +01:00
Colin Leroy-Mira
0dd7b0c3a5 Implement __sysremove for sim65
This will allow using unlink()/remove() in sim65 programs
Use it to unlink fgets' test output file
2024-01-28 13:58:57 +01:00
bbbradsmith
f15e9c4159 Linux build rejects %llu in ErrorCode 2023-05-07 17:41:54 -04:00
bbbradsmith
2cb457b85f sim65 use error codes outside the simulated program's range for non-sim errors 2023-05-07 16:51:12 -04:00
bbbradsmith
0081fe548c sim64 universal 64-bit cycle count support:
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.
2023-05-07 16:26:42 -04:00
bbbradsmith
84f0ab322d sim65: cycles does not increment 1 at a time, so some small overhead is needed in range check 2023-05-06 13:54:28 -04:00
bbbradsmith
c03d00bc80 sim65 suppress uninitialized variable warning
the EOF check was protecting uninitialized Val2 but the compiler can't figure that out
2023-05-05 21:46:42 -04:00
bbbradsmith
773716c32a sim65 close(-1) crash fix
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
2023-05-05 21:46:11 -04:00
bbbradsmith
f2e7609046 sim65 cycles 32-bit range fix
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.
2023-05-05 21:45:57 -04:00
bbbradsmith
4d30333099 sim65 path length safety for PVOpen 2023-02-19 05:31:46 -05:00
Lauri Kasanen
b052e64089 Speed up sim65 by 10% 2022-10-17 13:32:38 +03:00
mrdudz
3c1bb85b8e remove dangling spaces 2022-04-17 16:07:09 +02:00
Matthew D. Steele
22a3d55e40 Add space after function names 2022-01-08 16:39:30 -05:00
Matthew D. Steele
1f6bc6240f Move local variable declaration to top of block 2022-01-08 16:29:42 -05:00
Matthew D. Steele
92bfbeb8ab Adjust Pop() sequencing in paravirt.c 2022-01-08 16:24:40 -05:00
Matthew D. Steele
cf1bc4fad4 Fix Pop() implementation in src/sim65/paravirt.c (fixes #1625)
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.
2022-01-07 09:56:46 -05:00
Oliver Schmidt
5d84a4ba13 Removed non-ASCII chars. 2021-04-19 16:06:10 +02:00
Greg King
fb0d09a277 Changed sim65's internal error codes from 9-bit values to 7-bit values.
Some shells truncate process return codes to 8 bits.  And, the eigth bit often is used to show that a signal stopped the process.
2019-12-06 14:47:47 -05:00
bbbradsmith
5269552346 sim65 common define for paravirt hooks base location
allows the loaded binary to take up as much space as possible
restored some documentation of the hooks but without reference to specific location
2019-05-31 10:40:04 +02:00
Oliver Schmidt
6efb71bea7 Rearranged paravirt function vector.
- exit right below 6502 vectors.
- keep exit addr stable as it may be called from asm.
2019-05-30 00:10:17 +02:00
bbbradsmith
7e4c4ee53e sim65/main.c spaces were requested 2019-05-29 22:56:51 +02:00