From bc656052eeafec60807131d1e9a5172eff0d08b3 Mon Sep 17 00:00:00 2001 From: Hans Spaans Date: Sun, 3 Dec 2023 11:09:00 +0000 Subject: [PATCH 01/11] Add 6502 Basic Architecture and The Registers documentation --- wiki/{6502 Basic Architecture.md => 6502-Basic-Architecture.md} | 0 wiki/{The Registers.md => The-Registers.md} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename wiki/{6502 Basic Architecture.md => 6502-Basic-Architecture.md} (100%) rename wiki/{The Registers.md => The-Registers.md} (100%) diff --git a/wiki/6502 Basic Architecture.md b/wiki/6502-Basic-Architecture.md similarity index 100% rename from wiki/6502 Basic Architecture.md rename to wiki/6502-Basic-Architecture.md diff --git a/wiki/The Registers.md b/wiki/The-Registers.md similarity index 100% rename from wiki/The Registers.md rename to wiki/The-Registers.md From fa0fc23dc2eee9afb159317e1e5b7676d02219f8 Mon Sep 17 00:00:00 2001 From: Hans Spaans Date: Sun, 3 Dec 2023 11:29:33 +0000 Subject: [PATCH 02/11] Add wiki pages for addressing modes, coding algorithms, instruction reference, introduction, and the instruction set --- wiki/Addressing-Modes.md | 28 ++++++++++++++++++++++++++++ wiki/Coding-Algorithms.md | 19 +++++++++++++++++++ wiki/Instruction-Reference.md | 1 + wiki/Introduction.md | 2 ++ wiki/The-Instruction-Set.md | 23 +++++++++++++++++++++++ wiki/The-Registers.md | 13 +++++++++++++ wiki/_Sidebar.md | 16 +++++++++------- 7 files changed, 95 insertions(+), 7 deletions(-) create mode 100644 wiki/Addressing-Modes.md create mode 100644 wiki/Coding-Algorithms.md create mode 100644 wiki/Instruction-Reference.md create mode 100644 wiki/Introduction.md create mode 100644 wiki/The-Instruction-Set.md diff --git a/wiki/Addressing-Modes.md b/wiki/Addressing-Modes.md new file mode 100644 index 0000000..1c6851a --- /dev/null +++ b/wiki/Addressing-Modes.md @@ -0,0 +1,28 @@ +# Addressing Modes + +## Implicit + +## Accumulator + +## Immediate + +## Zero Page + +## Zero Page, X + +## Zero Page, Y + +## Relative + +## Absolute + +## Absolute, X + +## Absolute, Y + +## Indirect + +## Indexed Indirect + +## Indirect Indexed + diff --git a/wiki/Coding-Algorithms.md b/wiki/Coding-Algorithms.md new file mode 100644 index 0000000..bb3ec36 --- /dev/null +++ b/wiki/Coding-Algorithms.md @@ -0,0 +1,19 @@ +# Coding Algorithms + +## Standard Conventions + +## Simple Memory Operations + +## Logical Operations + +## Shifts and Rotates + +## Addition and Subtraction + +## Negation + +## Decimal Arithmetic + +## Increments and Decrements + +## Complex Memory Operations diff --git a/wiki/Instruction-Reference.md b/wiki/Instruction-Reference.md new file mode 100644 index 0000000..37a11a2 --- /dev/null +++ b/wiki/Instruction-Reference.md @@ -0,0 +1 @@ +# Instruction Reference diff --git a/wiki/Introduction.md b/wiki/Introduction.md new file mode 100644 index 0000000..3d07efe --- /dev/null +++ b/wiki/Introduction.md @@ -0,0 +1,2 @@ +# Introduction + diff --git a/wiki/The-Instruction-Set.md b/wiki/The-Instruction-Set.md new file mode 100644 index 0000000..d90323e --- /dev/null +++ b/wiki/The-Instruction-Set.md @@ -0,0 +1,23 @@ +# The Instruction Set + +## Load and Store Instructions + +## Register Transfers + +## Stack Operations + +## Logical + +## Arithmetic + +## Increment and Decrement + +## Shifts + +## Jumps and Calls + +## Branches + +## Status Flag Changes + +## System Functions diff --git a/wiki/The-Registers.md b/wiki/The-Registers.md index e69de29..fefacab 100644 --- a/wiki/The-Registers.md +++ b/wiki/The-Registers.md @@ -0,0 +1,13 @@ +# The Registers + +## Program Counter (PC) + +## Stack Pointer (SP) + +## Accumulator (A) + +## Index Register X + +## Index Register Y + +## Processor Status (P) diff --git a/wiki/_Sidebar.md b/wiki/_Sidebar.md index c89049d..e058b9a 100644 --- a/wiki/_Sidebar.md +++ b/wiki/_Sidebar.md @@ -1,7 +1,9 @@ -- [Introduction](https://github.com/hspaans/python-6502-emulator/wiki/Home) -- [6502 Basic Architecture](https://github.com/hspaans/python-6502-emulator/wiki/6502_Basic_Architecture) -- [The Registers](https://github.com/hspaans/python-6502-emulator/wiki/The_Registers) -- [The Instruction Set]() -- [Addressing Modes]() -- [Coding Algorithms]() -- [Instruction Reference]() +# 6502 Instruction Set Guide + +- [Introduction](https://github.com/hspaans/python-6502-emulator/wiki/Introduction) +- [6502 Basic Architecture](https://github.com/hspaans/python-6502-emulator/wiki/6502-Basic-Architecture) +- [The Registers](https://github.com/hspaans/python-6502-emulator/wiki/The-Registers) +- [The Instruction Set](https://github.com/hspaans/python-6502-emulator/wiki/The-Instruction-Set) +- [Addressing Modes](https://github.com/hspaans/python-6502-emulator/wiki/Addressing-Modes) +- [Coding Algorithms](https://github.com/hspaans/python-6502-emulator/wiki/Coding-Algorithms) +- [Instruction Reference](https://github.com/hspaans/python-6502-emulator/wiki/Instruction-Reference) From 2ce5ed932d52a40023dcb80283f3a446b9e6b4dc Mon Sep 17 00:00:00 2001 From: Hans Spaans Date: Sun, 3 Dec 2023 12:26:55 +0000 Subject: [PATCH 03/11] Update opcode for DEY instruction --- tests/test_cpu_ins_dey.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_cpu_ins_dey.py b/tests/test_cpu_ins_dey.py index 95f2f82..ecf7b71 100644 --- a/tests/test_cpu_ins_dey.py +++ b/tests/test_cpu_ins_dey.py @@ -26,7 +26,7 @@ +-----------------+--------+-------+--------+ | Addressing Mode | Opcode | Bytes | Cycles | +=================+========+=======+========+ -| Implied | 0xC8 | 1 | 2 | +| Implied | 0x88 | 1 | 2 | +-----------------+--------+-------+--------+ See also: DEC, DEX From e2de6b124748d50d1b0e799542d291430f90bdb7 Mon Sep 17 00:00:00 2001 From: Hans Spaans Date: Sun, 3 Dec 2023 12:27:05 +0000 Subject: [PATCH 04/11] Add instruction reference for CLC, CLD, CLI, CLV, DEC, DEX, DEY, and EOR --- wiki/Instruction-Reference.md | 195 ++++++++++++++++++++++++++++++++++ 1 file changed, 195 insertions(+) diff --git a/wiki/Instruction-Reference.md b/wiki/Instruction-Reference.md index 37a11a2..4cf852e 100644 --- a/wiki/Instruction-Reference.md +++ b/wiki/Instruction-Reference.md @@ -1 +1,196 @@ # Instruction Reference + +## ADC - Add with Carry + +## AND - Logical AND + +## ASL - Arithmetic Shift Left + +## BCC - Branch if Carry Clear + +## BCS - Branch if Carry Set + +## BEQ - Branch if Equal + +## BIT - Bit Test + +## BMI - Branch if Minus + +## BNE - Branch if Not Equal + +## BPL - Branch if Positive + +## BRK - Force Interrupt + +## BVC - Branch if Overflow Clear + +## BVS - Branch if Overflow Set + +## CLC - Clear Carry Flag + +C = 0 + +Set the carry flag to zero. + +Processor status after use: + +| Flag | Description | State | +| ---- | ----------------- | ------------ | +| C | Carry Flag | Set to 0 | +| Z | Zero Flag | Not affected | +| I | Interrupt Disable | Not affected | +| D | Decimal Mode Flag | Not affected | +| B | Break Command | Not affected | +| V | Overflow Flag | Not affected | +| N | Negative Flag | Not affected | + +| Addressing Mode | Opcode | Bytes | Cycles | +| --------------- | ------ | ----- | ------ | +| Implied | 0x18 | 1 | 2 | + +See also: SEC + +## CLD - Clear Decimal Mode + +D = 0 + +Sets the decimal mode flag to zero. + +| Flag | Description | State | +| ---- | ----------------- | ------------ | +| C | Carry Flag | Not affected | +| Z | Zero Flag | Not affected | +| I | Interrupt Disable | Not affected | +| D | Decimal Mode Flag | Set to 0 | +| B | Break Command | Not affected | +| V | Overflow Flag | Not affected | +| N | Negative Flag | Not affected | + +| Addressing Mode | Opcode | Bytes | Cycles | +| --------------- | ------ | ----- | ------ | +| Implied | 0xD8 | 1 | 2 | + +NB: +The state of the decimal flag is uncertain when the CPU is powered up and it is not reset when an interrupt is generated. In both cases you should include an explicit CLD to ensure that the flag is cleared before performing addition or subtraction. + +See also: SED + +## CLI - Clear Interrupt Disable + +I = 0 + +Clears the interrupt disable flag allowing normal interrupt requests to be serviced. + +| Flag | Description | State | +| ---- | ----------------- | ------------ | +| C | Carry Flag | Not affected | +| Z | Zero Flag | Not affected | +| I | Interrupt Disable | Set to 0 | +| D | Decimal Mode Flag | Not affected | +| B | Break Command | Not affected | +| V | Overflow Flag | Not affected | +| N | Negative Flag | Not affected | + +| Addressing Mode | Opcode | Bytes | Cycles | +| --------------- | ------ | ----- | ------ | +| Implied | 0x58 | 1 | 2 | + +See also: SEI + +## CLV - Clear Overflow Flag + +V = 0 + +Clears the overflow flag. + +| Flag | Description | State | +| ---- | ----------------- | ------------ | +| C | Carry Flag | Not affected | +| Z | Zero Flag | Not affected | +| I | Interrupt Disable | Not affected | +| D | Decimal Mode Flag | Not affected | +| B | Break Command | Not affected | +| V | Overflow Flag | Set to 0 | +| N | Negative Flag | Not affected | + +| Addressing Mode | Opcode | Bytes | Cycles | +| --------------- | ------ | ----- | ------ | +| Implied | 0xB8 | 1 | 2 | + +## CMP - Compare + +## CPX - Compare X Register + +## CPY - Compare Y Register + +## DEC - Decrement Memory + +M,Z,N = M-1 + +Subtracts one from the value held at a specified memory location setting the +zero and negative flags as appropriate. + +| Flag | Description | State | +| ---- | ----------------- | ----------------------------- | +| C | Carry Flag | Not affected | +| Z | Zero Flag | Set if result is zero | +| I | Interrupt Disable | Not affected | +| D | Decimal Mode Flag | Not affected | +| B | Break Command | Not affected | +| V | Overflow Flag | Not affected | +| N | Negative Flag | Set if bit 7 of result is set | + +| Addressing Mode | Opcode | Bytes | Cycles | +| --------------- | ------ | ----- | ------ | +| Zero Page | 0xC6 | 2 | 5 | +| Zero Page, X | 0xD6 | 2 | 6 | +| Absolute | 0xCE | 3 | 6 | +| Absolute, X | 0xDE | 3 | 7 | + +See also: DEX, DEY + +## DEX - Decrement X Register + +X,Z,N = X-1 + +Subtracts one from the X register setting the zero and negative flags as appropriate. + +| Flag | Description | State | +| ---- | ----------------- | ------------------------ | +| C | Carry Flag | Not affected | +| Z | Zero Flag | Set if X is zero | +| I | Interrupt Disable | Not affected | +| D | Decimal Mode Flag | Not affected | +| B | Break Command | Not affected | +| V | Overflow Flag | Not affected | +| N | Negative Flag | Set if bit 7 of X is set | + +| Addressing Mode | Opcode | Bytes | Cycles | +| --------------- | ------ | ----- | ------ | +| Implied | 0xCA | 1 | 2 | + +See also: DEC, DEY + +## DEY - Decrement Y Register + +Y,Z,N = Y-1 + +Subtracts one from the Y register setting the zero and negative flags as appropriate. + +| Flag | Description | State | +| ---- | ----------------- | ------------------------ | +| C | Carry Flag | Not affected | +| Z | Zero Flag | Set if Y is zero | +| I | Interrupt Disable | Not affected | +| D | Decimal Mode Flag | Not affected | +| B | Break Command | Not affected | +| V | Overflow Flag | Not affected | +| N | Negative Flag | Set if bit 7 of Y is set | + +| Addressing Mode | Opcode | Bytes | Cycles | +| --------------- | ------ | ----- | ------ | +| Implied | 0x88 | 1 | 2 | + +See also: DEC, DEX + +## EOR - Exclusive OR From 67394146f3cc57666fbcdf6d157432d28a602fdb Mon Sep 17 00:00:00 2001 From: Hans Spaans Date: Sat, 9 Dec 2023 17:23:40 +0100 Subject: [PATCH 05/11] Add new test files and update existing files --- README.md | 274 -------------- m6502/memory.py | 6 +- m6502/processor.py | 649 ++++++++++++++++++++++++++++---- setup.cfg | 31 +- tests/test_cpu.py | 38 +- tests/test_cpu_in_.rts | 0 tests/test_cpu_ins_adc.py | 91 +++++ tests/test_cpu_ins_and.py | 84 +++++ tests/test_cpu_ins_asl.py | 101 +++++ tests/test_cpu_ins_bcc.py | 39 ++ tests/test_cpu_ins_bcs.py | 39 ++ tests/test_cpu_ins_beq.py | 39 ++ tests/test_cpu_ins_bit.py | 46 +++ tests/test_cpu_ins_bmi.py | 39 ++ tests/test_cpu_ins_bne.py | 39 ++ tests/test_cpu_ins_bpl.py | 39 ++ tests/test_cpu_ins_brk.py | 41 ++ tests/test_cpu_ins_bvc.py | 39 ++ tests/test_cpu_ins_bvs.py | 39 ++ tests/test_cpu_ins_clc.py | 6 +- tests/test_cpu_ins_cld.py | 6 +- tests/test_cpu_ins_cli.py | 6 +- tests/test_cpu_ins_clv.py | 6 +- tests/test_cpu_ins_cmp.py | 82 ++++ tests/test_cpu_ins_cpx.py | 52 +++ tests/test_cpu_ins_cpy.py | 52 +++ tests/test_cpu_ins_dec.py | 18 +- tests/test_cpu_ins_dex.py | 6 +- tests/test_cpu_ins_dey.py | 6 +- tests/test_cpu_ins_eor.py | 0 tests/test_cpu_ins_inc.py | 18 +- tests/test_cpu_ins_inx.py | 6 +- tests/test_cpu_ins_iny.py | 6 +- tests/test_cpu_ins_jmp.py | 0 tests/test_cpu_ins_jsr.py | 0 tests/test_cpu_ins_lda.py | 34 +- tests/test_cpu_ins_ldx.py | 22 +- tests/test_cpu_ins_ldy.py | 22 +- tests/test_cpu_ins_lsr.py | 0 tests/test_cpu_ins_nop.py | 6 +- tests/test_cpu_ins_ora.py | 0 tests/test_cpu_ins_pha.py | 6 +- tests/test_cpu_ins_php.py | 6 +- tests/test_cpu_ins_pla.py | 6 +- tests/test_cpu_ins_plp.py | 6 +- tests/test_cpu_ins_rol.py | 0 tests/test_cpu_ins_ror.py | 0 tests/test_cpu_ins_rti.py | 0 tests/test_cpu_ins_sbc.py | 0 tests/test_cpu_ins_sec.py | 6 +- tests/test_cpu_ins_sed.py | 6 +- tests/test_cpu_ins_sei.py | 6 +- tests/test_cpu_ins_sta.py | 30 +- tests/test_cpu_ins_stx.py | 14 +- tests/test_cpu_ins_sty.py | 14 +- tests/test_cpu_ins_tax.py | 6 +- tests/test_cpu_ins_tay.py | 6 +- tests/test_cpu_ins_tsx.py | 6 +- tests/test_cpu_ins_txa.py | 6 +- tests/test_cpu_ins_txs.py | 6 +- tests/test_cpu_ins_tya.py | 6 +- tests/test_memory.py | 12 +- wiki/6502-Basic-Architecture.md | 7 +- wiki/Addressing-Modes.md | 3 +- wiki/Home.md | 22 +- wiki/Instruction-Reference.md | 418 +++++++++++++++++++- wiki/Introduction.md | 1 - 67 files changed, 2082 insertions(+), 544 deletions(-) create mode 100644 tests/test_cpu_in_.rts create mode 100644 tests/test_cpu_ins_adc.py create mode 100644 tests/test_cpu_ins_and.py create mode 100644 tests/test_cpu_ins_asl.py create mode 100644 tests/test_cpu_ins_bcc.py create mode 100644 tests/test_cpu_ins_bcs.py create mode 100644 tests/test_cpu_ins_beq.py create mode 100644 tests/test_cpu_ins_bit.py create mode 100644 tests/test_cpu_ins_bmi.py create mode 100644 tests/test_cpu_ins_bne.py create mode 100644 tests/test_cpu_ins_bpl.py create mode 100644 tests/test_cpu_ins_brk.py create mode 100644 tests/test_cpu_ins_bvc.py create mode 100644 tests/test_cpu_ins_bvs.py create mode 100644 tests/test_cpu_ins_cmp.py create mode 100644 tests/test_cpu_ins_cpx.py create mode 100644 tests/test_cpu_ins_cpy.py create mode 100644 tests/test_cpu_ins_eor.py create mode 100644 tests/test_cpu_ins_jmp.py create mode 100644 tests/test_cpu_ins_jsr.py create mode 100644 tests/test_cpu_ins_lsr.py create mode 100644 tests/test_cpu_ins_ora.py create mode 100644 tests/test_cpu_ins_rol.py create mode 100644 tests/test_cpu_ins_ror.py create mode 100644 tests/test_cpu_ins_rti.py create mode 100644 tests/test_cpu_ins_sbc.py diff --git a/README.md b/README.md index a311932..ee41501 100644 --- a/README.md +++ b/README.md @@ -1,277 +1,3 @@ # CS: Writing a 6502 emulator in Python -[Python] is a great language to learn because it is easy to learn and safe to write in. It is also available for Windows, Linux and Mac, and it is free. It is also available on [Raspberry Pi][Raspberry Pi] which is targetted for education and testing purposes. This makes computer science easy accessible to everyone. Also for writing a basic emulator to learn how computers work and what they do. The [6502][6502] processor has a very simple design and a small instruction set that makes it easy to learn. - -Learning how processors work also gives the possibility to understand why certain applications are so slow and how to optimize them, but also how to start doing security research by writing a fuzzer to find vulnerabilities. Lets start with the basics and write a simple 6502 emulator before we start with the assembly language. - -The [Introduction](#introduction) chapter is mainly based on the **6502 Instruction Set Guide** by [Andrew John Jacobs aka BitWise](https://github.com/andrew-jacobs) and full credit goes to him. Sadly he passed away in 2021 and I copied his work as a reference as his website is no longer available. - ## Introduction - -### The 6502 basic processor? - -### The Registers - -#### Program Counter - -#### Stack Pointer - -#### Accumulator - -#### Index registers X and Y - -#### Processor Status - -As instructions are executed a set of processor flags are set or clear to record the results of the operation. This flags and some additional control flags are held in a special status register. Each flag has a single bit within the register. - -Instructions exist to test the values of the various bits, to set or clear some of them and to push or pull the entire set to or from the stack. - -* Carry Flag - - The carry flag is set if the last operation caused an overflow from bit 7 of the result or an underflow from bit 0. This condition is set during arithmetic, comparison and during logical shifts. It can be explicitly set using the ['Set Carry Flag' (SEC)](#set-carry-flag) instruction and cleared with ['Clear Carry Flag' (CLC)](#clear-carry-flag). - -* Zero Flag - - The zero flag is set of the result of the last operation as was zero. - -* Interrupt Disable - - The interrupt disable flag is set if the program has executed a ['Set Interrupt Disable' (SEI)](#sei---set-interrupt-disable) instruction. While this flag is set the processor will not respond to interrupts from devices until it is cleared by a ['Clear Interrupt Disable' (CLI)](#cli---clear-interrupt-disable) instruction. - -* Decimal Mode - - While the decimal mode flag is set the processor will obey the rules of Binary Coded Decimal (BCD) arithmetic during addition and subtraction. The flag can be explicitly set using ['Set Decimal Mode' (SED)](#sed---set-decimal-mode) and cleared with ['Clear Decimal Mode' (CLD)](#cld---clear-decimal-mode). - > Note that only two instructions are affected by the D flag: ['Add with Carry' (ADC)](#adc---add-with-carry) and ['Subtract with Carry' (SBC)](#sbc---subtract-with-carry). - -* Break Command - - The break command bit is set when a [BRK](#brk) instruction has been executed and an interrupt has been generated to process it. - -* Overflow Flag - - The overflow flag is set during arithmetic operations if the result has yielded an ivalid 2's complement result (e.g. adding to positive numbers an dending up with a negative result: 64 + 64 => -128) It is determined by looking at the carry between bits 6 and 7 and between bit 7 and the carry flag. - -* Negative Flag - - The negative flag is set if the result of the last operation has bit 7 set to a one. - -### The Instruction Set - -#### Load/Store Operations - -#### Register Transfer Operations - -#### Stack Operations - -#### Logical Operations - -#### Arithmetic Operations - -#### Increment/Decrement Operations - -#### Bitwise Operations - -#### Jump/Call Operations - -#### Branch Operations - -#### Status Flag Changes - -##### CLC - Clear Carry Flag - -Set the carry flag to zero. - -| Flag | Description | State | -| :---: | ----------------- | ------------ | -| C | Carry Flag | Set to 0 | -| Z | Zero Flag | Not affected | -| I | Interrupt Disable | Not affected | -| D | Decimal Mode Flag | Not affected | -| B | Break Command | Not affected | -| V | Overflow Flag | Not affected | -| N | Negative Flag | Not affected | - -| Addressing Mode | Opcode | Bytes | Cycles | -| --------------- | :----: | :---: | :----: | -| Implied | 0x18 | 1 | 2 | - -See also [SEC](#sec---set-carry-flag). - -##### CLD - Clear Decimal Mode - -Sets the decimal mode flag to zero. - -| Flag | Description | State | -| :---: | ----------------- | ------------ | -| C | Carry Flag | Not affected | -| Z | Zero Flag | Not affected | -| I | Interrupt Disable | Not affected | -| D | Decimal Mode Flag | Set to 0 | -| B | Break Command | Not affected | -| V | Overflow Flag | Not affected | -| N | Negative Flag | Not affected | - -| Addressing Mode | Opcode | Bytes | Cycles | -| --------------- | :----: | :---: | :----: | -| Implied | 0xD8 | 1 | 2 | - -> The state of the decimal flag is uncertain when the CPU is powered up and it -> is not reset when an interrupt is generated. In both cases you should include -> an explicit CLD to ensure that the flag is cleared before performing addition -> or subtraction. - -See also [SED](#sed---set-decimal-mode). - -##### CLI - Clear Interrupt Disable - -Clears the interrupt disable flag allowing normal interrupt requests to be -serviced. - -| Flag | Description | State | -| :---: | ----------------- | ------------ | -| C | Carry Flag | Not affected | -| Z | Zero Flag | Not affected | -| I | Interrupt Disable | Set to 0 | -| D | Decimal Mode Flag | Not affected | -| B | Break Command | Not affected | -| V | Overflow Flag | Not affected | -| N | Negative Flag | Not affected | - -| Addressing Mode | Opcode | Bytes | Cycles | -| --------------- | :----: | :---: | :----: | -| Implied | 0x58 | 1 | 2 | - -See also [SEI](#sei---set-interrupt-disable). - -##### CLV - Clear Overflow Flag - -Clears the overflow flag. - -| Flag | Description | State | -| :---: | ----------------- | ------------ | -| C | Carry Flag | Not affected | -| Z | Zero Flag | Not affected | -| I | Interrupt Disable | Not affected | -| D | Decimal Mode Flag | Not affected | -| B | Break Command | Not affected | -| V | Overflow Flag | Set to 0 | -| N | Negative Flag | Not affected | - -| Addressing Mode | Opcode | Bytes | Cycles | -| --------------- | :----: | :---: | :----: | -| Implied | 0xB8 | 1 | 2 | - -##### SEC - Set Carry Flag - -Set the carry flag to one. - -| Flag | Description | State | -| :---: | ----------------- | ------------ | -| C | Carry Flag | Set to 1 | -| Z | Zero Flag | Not affected | -| I | Interrupt Disable | Not affected | -| D | Decimal Mode Flag | Not affected | -| B | Break Command | Not affected | -| V | Overflow Flag | Not affected | -| N | Negative Flag | Not affected | - -| Addressing Mode | Opcode | Bytes | Cycles | -| --------------- | :----: | :---: | :----: | -| Implied | 0x38 | 1 | 2 | - -See also [CLC](#clc---clear-carry-flag). - -##### SED - Set Decimal Mode - -Sets the decimal mode flag to one. - -| Flag | Description | State | -| :---: | ----------------- | ------------ | -| C | Carry Flag | Not affected | -| Z | Zero Flag | Not affected | -| I | Interrupt Disable | Not affected | -| D | Decimal Mode Flag | Set to 1 | -| B | Break Command | Not affected | -| V | Overflow Flag | Not affected | -| N | Negative Flag | Not affected | - -| Addressing Mode | Opcode | Bytes | Cycles | -| --------------- | :----: | :---: | :----: | -| Implied | 0xF8 | 1 | 2 | - -See also [CLD](#cld---clear-decimal-mode). - -##### SEI - Set Interrupt Disable - -Sets the interrupt disable flag to zero. - -| Flag | Description | State | -| :---: | ----------------- | ------------ | -| C | Carry Flag | Not affected | -| Z | Zero Flag | Not affected | -| I | Interrupt Disable | Set to 1 | -| D | Decimal Mode Flag | Not affected | -| B | Break Command | Not affected | -| V | Overflow Flag | Not affected | -| N | Negative Flag | Not affected | - -| Addressing Mode | Opcode | Bytes | Cycles | -| --------------- | :----: | :---: | :----: | -| Implied | 0x78 | 1 | 2 | - -See also [CLI](#cli---clear-interrupt-disable). - -#### System Functions - -##### NOP - No Operation - -The NOP instruction causes no changes to the processor other than the normal -incrementing of the program counter to the next instruction. - -Processor Status after use: - -| Flag | Description | State | -| :---: | ----------------- | ------------ | -| C | Carry Flag | Not affected | -| Z | Zero Flag | Not affected | -| I | Interrupt Disable | Not affected | -| D | Decimal Mode Flag | Not affected | -| B | Break Command | Not affected | -| V | Overflow Flag | Not affected | -| N | Negative Flag | Not affected | - -| Addressing Mode | Opcode | Bytes | Cycles | -| --------------- | :----: | :---: | :----: | -| Implied | 0xEA | 1 | 2 | - -### Addressing Modes - -#### Implicit Addressing Mode - -#### Accumulator Addressing Mode - -#### Immediate Addressing Mode - -#### Zero Page Addressing Mode - -#### Zero Page,X or Zero Page,Y Addressing Mode - -#### Relative Addressing Mode - -#### Absolute Addressing Mode - -#### Absolute,X or Absolute,Y Addressing Mode - -#### Indirect Addressing Mode - -#### Indirect Indexed Addressing Mode - -### The memory model - -## The basic structure of a 6502 processor - -## Implementing the Set and Clear instructions - -[6502]: https://en.m.wikipedia.org/wiki/6502 -[Python]: https://www.python.org/ -[Raspberry Pi]: https://www.raspberrypi.org/ diff --git a/m6502/memory.py b/m6502/memory.py index a5f6e6c..ca6b47d 100644 --- a/m6502/memory.py +++ b/m6502/memory.py @@ -4,7 +4,7 @@ class Memory: """Memory bank for MOT-6502 systems.""" - def __init__(self: object, size: int = None) -> None: + def __init__(self, size: int = 0xFFFF) -> None: """ Initialize the memory. @@ -20,7 +20,7 @@ def __init__(self: object, size: int = None) -> None: self.size = size self.memory = [0] * self.size - def __getitem__(self: object, address: int) -> int: + def __getitem__(self, address: int) -> int: """ Get the value at the specified address. @@ -31,7 +31,7 @@ def __getitem__(self: object, address: int) -> int: raise ValueError("Memory address is not valid") return self.memory[address] - def __setitem__(self: object, address: int, value: int) -> int: + def __setitem__(self, address: int, value: int) -> int: """ Set the value at the specified address. diff --git a/m6502/processor.py b/m6502/processor.py index 7402536..ed9efa7 100644 --- a/m6502/processor.py +++ b/m6502/processor.py @@ -1,7 +1,7 @@ """Emulation of the MOT-6502 Processor.""" import sys -import m6502 +from m6502 import Memory class Processor: @@ -47,7 +47,7 @@ class Processor: "beq", "sbc", "nop", "isb", "nop", "sbc", "inc", "isb", "sed", "sbc", "nop", "isb", "nop", "sbc", "inc", "isb", # F ] - def __init__(self: object, memory: m6502.memory) -> None: + def __init__(self, memory: Memory) -> None: """ Initialize the processor. @@ -71,7 +71,7 @@ def __init__(self: object, memory: m6502.memory) -> None: self.flag_v = True # Status flag - Overflow Flag self.flag_n = True # Status flag - Negative Flag - def reset(self: object) -> None: + def reset(self) -> None: """ Reset processor to initial state. @@ -85,7 +85,7 @@ def reset(self: object) -> None: self.flag_d = False self.flag_b = True - def fetch_byte(self: object) -> int: + def fetch_byte(self) -> int: """ Fetch a byte from memory. @@ -96,7 +96,7 @@ def fetch_byte(self: object) -> int: self.program_counter += 1 return data - def fetch_word(self: object) -> int: + def fetch_word(self) -> int: """ Fetch a word from memory. @@ -107,7 +107,7 @@ def fetch_word(self: object) -> int: self.program_counter += 2 return data - def read_byte(self: object, address: int) -> int: + def read_byte(self, address: int) -> int: """ Read a byte from memory. @@ -118,7 +118,7 @@ def read_byte(self: object, address: int) -> int: self.cycles += 1 return data - def read_word(self: object, address: int) -> int: + def read_word(self, address: int) -> int: """ Read a word from memory. @@ -131,7 +131,7 @@ def read_word(self: object, address: int) -> int: data = (self.read_byte(address) << 8) | self.read_byte(address + 1) return data - def write_byte(self: object, address: int, value: int) -> None: + def write_byte(self, address: int, value: int) -> None: """ Write a byte to memory. @@ -142,7 +142,7 @@ def write_byte(self: object, address: int, value: int) -> None: self.memory[address] = value self.cycles += 1 - def write_word(self: object, address: int, value: int) -> None: + def write_word(self, address: int, value: int) -> None: """ Split a word to two bytes and write to memory. @@ -157,7 +157,7 @@ def write_word(self: object, address: int, value: int) -> None: self.write_byte(address, (value >> 8) & 0xFF) self.write_byte(address + 1, value & 0xFF) - def read_register_a(self: object) -> int: + def read_register_a(self) -> int: """ Read the A register. @@ -166,7 +166,7 @@ def read_register_a(self: object) -> int: self.cycles += 1 return self.reg_a - def read_register_x(self: object) -> int: + def read_register_x(self) -> int: """ Read the X register. @@ -175,7 +175,7 @@ def read_register_x(self: object) -> int: self.cycles += 1 return self.reg_x - def read_register_y(self: object) -> int: + def read_register_y(self) -> int: """ Read the Y register. @@ -184,7 +184,7 @@ def read_register_y(self: object) -> int: self.cycles += 1 return self.reg_y - def push(self: object, data: int) -> None: + def push(self, data: int) -> None: """ Push data to stack. @@ -194,7 +194,7 @@ def push(self: object, data: int) -> None: self.stack_pointer -= 1 self.cycles += 1 - def pop(self: object) -> int: + def pop(self) -> int: """ Pop data from stack. @@ -204,7 +204,7 @@ def pop(self: object) -> int: self.cycles += 1 return self.memory[self.stack_pointer - 1] - def evaluate_flag_n(self: object, data: int) -> None: + def evaluate_flag_n(self, data: int) -> None: """ Evaluate negative flag. @@ -213,7 +213,7 @@ def evaluate_flag_n(self: object, data: int) -> None: """ self.flag_n = (data & 0x80) != 0 - def evaluate_flag_z(self: object, data: int) -> None: + def evaluate_flag_z(self, data: int) -> None: """ Evaluate the Zero Flag. @@ -225,7 +225,7 @@ def evaluate_flag_z(self: object, data: int) -> None: else: self.flag_z = False - def execute(self: object, cycles: int = 0) -> None: + def execute(self, cycles: int = 0) -> None: """ Execute code for X amount of cycles. Or until a breakpoint is reached. @@ -236,7 +236,7 @@ def execute(self: object, cycles: int = 0) -> None: opcode = self.fetch_byte() eval("self.ins_" + self.OPCODES[opcode] + "_" + self.ADDRESSING[opcode] + "()") # noqa: PLW0123 - def ins_nop_imp(self: object) -> None: + def ins_nop_imp(self) -> None: """ NOP - No Operation. @@ -244,7 +244,360 @@ def ins_nop_imp(self: object) -> None: """ self.cycles += 1 - def ins_clc_imp(self: object) -> None: + def ins_adc_imm(self) -> None: + """ + ADC - Add with Carry, Immediate. + + :return: None + """ + self.reg_a = self.read_register_a() + self.fetch_byte() + self.evaluate_flag_n(self.reg_a) + self.evaluate_flag_z(self.reg_a) + self.cycles += 1 + + def ins_adc_zp(self) -> None: + """ + ADC - Add with Carry, Zero Page. + + :return: None + """ + self.reg_a = self.read_register_a() + self.read_byte(self.fetch_byte()) + self.evaluate_flag_n(self.reg_a) + self.evaluate_flag_z(self.reg_a) + self.cycles += 1 + + def ins_adc_zpx(self) -> None: + """ + ADC - Add with Carry, Zero Page, X. + + :return: None + """ + self.reg_a = self.read_register_a() + self.read_byte((self.fetch_byte() + self.read_register_x()) & 0xFF) + self.evaluate_flag_n(self.reg_a) + self.evaluate_flag_z(self.reg_a) + self.cycles += 1 + + def ins_adc_abs(self) -> None: + """ + ADC - Add with Carry, Absolute. + + :return: None + """ + self.reg_a = self.read_register_a() + self.read_byte(self.fetch_word()) + self.evaluate_flag_n(self.reg_a) + self.evaluate_flag_z(self.reg_a) + self.cycles += 1 + + def ins_adc_abx(self) -> None: + """ + ADC - Add with Carry, Absolute, X. + + :return: None + """ + self.reg_a = self.read_register_a() + self.read_byte(self.fetch_word() + self.read_register_x()) + self.evaluate_flag_n(self.reg_a) + self.evaluate_flag_z(self.reg_a) + self.cycles += 1 + + def ins_adc_aby(self) -> None: + """ + ADC - Add with Carry, Absolute, Y. + + :return: None + """ + self.reg_a = self.read_register_a() + self.read_byte(self.fetch_word() + self.read_register_y()) + self.evaluate_flag_n(self.reg_a) + self.evaluate_flag_z(self.reg_a) + self.cycles += 1 + + def ins_adc_inx(self) -> None: + """ + ADC - Add with Carry, Indexed Indirect. + + :return: None + """ + self.reg_a = self.read_register_a() + self.read_byte(self.fetch_byte() + self.read_register_x()) + self.evaluate_flag_n(self.reg_a) + self.evaluate_flag_z(self.reg_a) + self.cycles += 1 + + def ins_adc_iny(self) -> None: + """ + ADC - Add with Carry, Indirect Indexed. + + :return: None + """ + self.reg_a = self.read_register_a() + self.read_byte(self.fetch_byte()) + self.read_register_y() + self.evaluate_flag_n(self.reg_a) + self.evaluate_flag_z(self.reg_a) + self.cycles += 1 + + def ins_and_imm(self) -> None: + """ + AND - Logical AND, Immediate. + + :return: None + """ + self.reg_a = self.read_register_a() & self.fetch_byte() + self.evaluate_flag_n(self.reg_a) + self.evaluate_flag_z(self.reg_a) + self.cycles += 1 + + def ins_and_zp(self) -> None: + """ + AND - Logical AND, Zero Page. + + :return: None + """ + self.reg_a = self.read_register_a() & self.read_byte(self.fetch_byte()) + self.evaluate_flag_n(self.reg_a) + self.evaluate_flag_z(self.reg_a) + self.cycles += 1 + + def ins_and_zpx(self) -> None: + """ + AND - Logical AND, Zero Page, X. + + :return: None + """ + self.reg_a = self.read_register_a() & self.read_byte((self.fetch_byte() + self.read_register_x()) & 0xFF) + self.evaluate_flag_n(self.reg_a) + self.evaluate_flag_z(self.reg_a) + self.cycles += 1 + + def ins_and_abs(self) -> None: + """ + AND - Logical AND, Absolute. + + :return: None + """ + self.reg_a = self.read_register_a() & self.read_byte(self.fetch_word()) + self.evaluate_flag_n(self.reg_a) + self.evaluate_flag_z(self.reg_a) + self.cycles += 1 + + def ins_and_abx(self) -> None: + """ + AND - Logical AND, Absolute, X. + + :return: None + """ + self.reg_a = self.read_register_a() & self.read_byte(self.fetch_word() + self.read_register_x()) + self.evaluate_flag_n(self.reg_a) + self.evaluate_flag_z(self.reg_a) + self.cycles += 1 + + def ins_and_aby(self) -> None: + """ + AND - Logical AND, Absolute, Y. + + :return: None + """ + self.reg_a = self.read_register_a() & self.read_byte(self.fetch_word() + self.read_register_y()) + self.evaluate_flag_n(self.reg_a) + self.evaluate_flag_z(self.reg_a) + self.cycles += 1 + + def ins_and_inx(self) -> None: + """ + AND - Logical AND, Indexed Indirect. + + :return: None + """ + self.reg_a = self.read_register_a() & self.read_byte(self.fetch_byte() + self.read_register_x()) + self.evaluate_flag_n(self.reg_a) + self.evaluate_flag_z(self.reg_a) + self.cycles += 1 + + def ins_and_iny(self) -> None: + """ + AND - Logical AND, Indirect Indexed. + + :return: None + """ + self.reg_a = self.read_register_a() & self.read_byte(self.fetch_byte()) + self.read_register_y() + self.evaluate_flag_n(self.reg_a) + self.evaluate_flag_z(self.reg_a) + self.cycles += 1 + + def ins_asl_acc(self) -> None: + """ + ASL - Arithmetic Shift Left, Accumulator. + + :return: None + """ + self.reg_a = self.read_register_a() << 1 + self.evaluate_flag_n(self.reg_a) + self.evaluate_flag_z(self.reg_a) + self.cycles += 1 + + def ins_asl_zp(self) -> None: + """ + ASL - Arithmetic Shift Left, Zero Page. + + :return: None + """ + address = self.fetch_byte() + self.write_byte(address, self.read_byte(address) << 1) + self.evaluate_flag_n(self.memory[address]) + self.evaluate_flag_z(self.memory[address]) + self.cycles += 1 + + def ins_asl_zpx(self) -> None: + """ + ASL - Arithmetic Shift Left, Zero Page, X. + + :return: None + """ + address = (self.fetch_byte() + self.read_register_x()) & 0xFF + self.write_byte(address, self.read_byte(address) << 1) + self.evaluate_flag_n(self.memory[address]) + self.evaluate_flag_z(self.memory[address]) + self.cycles += 1 + + def ins_asl_abs(self) -> None: + """ + ASL - Arithmetic Shift Left, Absolute. + + :return: None + """ + address = self.fetch_word() + self.write_byte(address, self.read_byte(address) << 1) + self.evaluate_flag_n(self.memory[address]) + self.evaluate_flag_z(self.memory[address]) + self.cycles += 1 + + def ins_asl_abx(self) -> None: + """ + ASL - Arithmetic Shift Left, Absolute, X. + + :return: None + """ + address = self.fetch_word() + self.read_register_x() + self.write_byte(address, self.read_byte(address) << 1) + self.evaluate_flag_n(self.memory[address]) + self.evaluate_flag_z(self.memory[address]) + self.cycles += 1 + + def ins_bcc_rel(self) -> None: + """ + BCC - Branch if Carry Clear. + + :return: None + """ + if not self.flag_c: + self.program_counter += self.fetch_byte() + self.cycles += 1 + + def ins_bcs_rel(self) -> None: + """ + BCS - Branch if Carry Set. + + :return: None + """ + if self.flag_c: + self.program_counter += self.fetch_byte() + self.cycles += 1 + + def ins_beq_rel(self) -> None: + """ + BEQ - Branch if Equal. + + :return: None + """ + if self.flag_z: + self.program_counter += self.fetch_byte() + self.cycles += 1 + + def ins_bit_zp(self) -> None: + """ + BIT - Bit Test, Zero Page. + + :return: None + """ + self.reg_a = self.read_register_a() & self.read_byte(self.fetch_byte()) + self.evaluate_flag_n(self.reg_a) + self.evaluate_flag_z(self.reg_a) + self.flag_v = (self.read_byte(self.fetch_byte()) & 0x40) != 0 + self.cycles += 1 + + def ins_bit_abs(self) -> None: + """ + BIT - Bit Test, Absolute. + + :return: None + """ + self.reg_a = self.read_register_a() & self.read_byte(self.fetch_word()) + self.evaluate_flag_n(self.reg_a) + self.evaluate_flag_z(self.reg_a) + self.flag_v = (self.read_byte(self.fetch_word()) & 0x40) != 0 + self.cycles += 1 + + def ins_bmi_rel(self) -> None: + """ + BMI - Branch if Minus. + + :return: None + """ + if self.flag_n: + self.program_counter += self.fetch_byte() + self.cycles += 1 + + def ins_bne_rel(self) -> None: + """ + BNE - Branch if Not Equal. + + :return: None + """ + if not self.flag_z: + self.program_counter += self.fetch_byte() + self.cycles += 1 + + def ins_bpl_rel(self) -> None: + """ + BPL - Branch if Positive. + + :return: None + """ + if not self.flag_n: + self.program_counter += self.fetch_byte() + self.cycles += 1 + + def ins_brk_imp(self) -> None: + """ + BRK - Force Interrupt. + + :return: None + """ + self.flag_b = True + self.push((self.program_counter >> 8) & 0xFF) + self.push(self.program_counter & 0xFF) + self.push(self.flag_c) + self.flag_i = True + self.program_counter = self.read_word(0xFFFE) + self.cycles += 1 + + def ins_bvc_rel(self) -> None: + """ + BVC - Branch if Overflow Clear. + + :return: None + """ + if not self.flag_v: + self.program_counter += self.fetch_byte() + self.cycles += 1 + + def ins_bvs_rel(self) -> None: + """ + BVS - Branch if Overflow Set. + + :return: None + """ + if self.flag_v: + self.program_counter += self.fetch_byte() + self.cycles += 1 + + def ins_clc_imp(self) -> None: """ CLC - Clear Carry Flag. @@ -253,7 +606,7 @@ def ins_clc_imp(self: object) -> None: self.flag_c = False self.cycles += 1 - def ins_cld_imp(self: object) -> None: + def ins_cld_imp(self) -> None: """ CLD - Clear Decimal Mode. @@ -262,7 +615,7 @@ def ins_cld_imp(self: object) -> None: self.flag_d = False self.cycles += 1 - def ins_cli_imp(self: object) -> None: + def ins_cli_imp(self) -> None: """ CLI - Clear Interrupt Disable. @@ -271,7 +624,7 @@ def ins_cli_imp(self: object) -> None: self.flag_i = False self.cycles += 1 - def ins_clv_imp(self: object) -> None: + def ins_clv_imp(self) -> None: """ CLV - Clear Overflow Flag. @@ -280,7 +633,147 @@ def ins_clv_imp(self: object) -> None: self.flag_v = False self.cycles += 1 - def ins_dec_zp(self: object) -> None: + def ins_cmp_imm(self) -> None: + """ + CMP - Compare, Immediate. + + :return: None + """ + self.evaluate_flag_n(self.read_register_a() - self.fetch_byte()) + self.evaluate_flag_z(self.read_register_a() - self.fetch_byte()) + self.cycles += 1 + + def ins_cmp_zp(self) -> None: + """ + CMP - Compare, Zero Page. + + :return: None + """ + self.evaluate_flag_n(self.read_register_a() - self.read_byte(self.fetch_byte())) + self.evaluate_flag_z(self.read_register_a() - self.read_byte(self.fetch_byte())) + self.cycles += 1 + + def ins_cmp_zpx(self) -> None: + """ + CMP - Compare, Zero Page, X. + + :return: None + """ + self.evaluate_flag_n(self.read_register_a() - self.read_byte((self.fetch_byte() + self.read_register_x()) & 0xFF)) + self.evaluate_flag_z(self.read_register_a() - self.read_byte((self.fetch_byte() + self.read_register_x()) & 0xFF)) + self.cycles += 1 + + def ins_cmp_abs(self) -> None: + """ + CMP - Compare, Absolute. + + :return: None + """ + self.evaluate_flag_n(self.read_register_a() - self.read_byte(self.fetch_word())) + self.evaluate_flag_z(self.read_register_a() - self.read_byte(self.fetch_word())) + self.cycles += 1 + + def ins_cmp_abx(self) -> None: + """ + CMP - Compare, Absolute, X. + + :return: None + """ + self.evaluate_flag_n(self.read_register_a() - self.read_byte(self.fetch_word() + self.read_register_x())) + self.evaluate_flag_z(self.read_register_a() - self.read_byte(self.fetch_word() + self.read_register_x())) + self.cycles += 1 + + def ins_cmp_aby(self) -> None: + """ + CMP - Compare, Absolute, Y. + + :return: None + """ + self.evaluate_flag_n(self.read_register_a() - self.read_byte(self.fetch_word() + self.read_register_y())) + self.evaluate_flag_z(self.read_register_a() - self.read_byte(self.fetch_word() + self.read_register_y())) + self.cycles += 1 + + def ins_cmp_inx(self) -> None: + """ + CMP - Compare, Indexed Indirect. + + :return: None + """ + self.evaluate_flag_n(self.read_register_a() - self.read_byte(self.fetch_byte() + self.read_register_x())) + self.evaluate_flag_z(self.read_register_a() - self.read_byte(self.fetch_byte() + self.read_register_x())) + self.cycles += 1 + + def ins_cmp_iny(self) -> None: + """ + CMP - Compare, Indirect Indexed. + + :return: None + """ + self.evaluate_flag_n(self.read_register_a() - self.read_byte(self.fetch_byte()) + self.read_register_y()) + self.evaluate_flag_z(self.read_register_a() - self.read_byte(self.fetch_byte()) + self.read_register_y()) + self.cycles += 1 + + def ins_cpx_imm(self) -> None: + """ + CPX - Compare X Register, Immediate. + + :return: None + """ + self.evaluate_flag_n(self.read_register_x() - self.fetch_byte()) + self.evaluate_flag_z(self.read_register_x() - self.fetch_byte()) + self.cycles += 1 + + def ins_cpx_zp(self) -> None: + """ + CPX - Compare X Register, Zero Page. + + :return: None + """ + self.evaluate_flag_n(self.read_register_x() - self.read_byte(self.fetch_byte())) + self.evaluate_flag_z(self.read_register_x() - self.read_byte(self.fetch_byte())) + self.cycles += 1 + + def ins_cpx_abs(self) -> None: + """ + CPX - Compare X Register, Absolute. + + :return: None + """ + self.evaluate_flag_n(self.read_register_x() - self.read_byte(self.fetch_word())) + self.evaluate_flag_z(self.read_register_x() - self.read_byte(self.fetch_word())) + self.cycles += 1 + + def ins_cpy_imm(self) -> None: + """ + CPY - Compare Y Register, Immediate. + + :return: None + """ + self.evaluate_flag_n(self.read_register_y() - self.fetch_byte()) + self.evaluate_flag_z(self.read_register_y() - self.fetch_byte()) + self.cycles += 1 + + def ins_cpy_zp(self) -> None: + """ + CPY - Compare Y Register, Zero Page. + + :return: None + """ + self.evaluate_flag_n(self.read_register_y() - self.read_byte(self.fetch_byte())) + self.evaluate_flag_z(self.read_register_y() - self.read_byte(self.fetch_byte())) + self.cycles += 1 + + def ins_cpy_abs(self) -> None: + """ + CPY - Compare Y Register, Absolute. + + :return: None + """ + self.evaluate_flag_n(self.read_register_y() - self.read_byte(self.fetch_word())) + self.evaluate_flag_z(self.read_register_y() - self.read_byte(self.fetch_word())) + self.cycles += 1 + + def ins_dec_zp(self) -> None: """ DEC - Decrement Memory, Zero Page. @@ -292,7 +785,7 @@ def ins_dec_zp(self: object) -> None: self.evaluate_flag_z(self.memory[address]) self.cycles += 1 - def ins_dec_zpx(self: object) -> None: + def ins_dec_zpx(self) -> None: """ DEC - Decrement Memory, Zero Page, X. @@ -304,7 +797,7 @@ def ins_dec_zpx(self: object) -> None: self.evaluate_flag_z(self.memory[address]) self.cycles += 1 - def ins_dec_abs(self: object) -> None: + def ins_dec_abs(self) -> None: """ DEC - Decrement Memory, Absolute. @@ -316,7 +809,7 @@ def ins_dec_abs(self: object) -> None: self.evaluate_flag_z(self.memory[address]) self.cycles += 1 - def ins_dec_abx(self: object) -> None: + def ins_dec_abx(self) -> None: """ DEC - Decrement Memory, Absolute, X. @@ -328,7 +821,7 @@ def ins_dec_abx(self: object) -> None: self.evaluate_flag_z(self.memory[address]) self.cycles += 1 - def ins_dex_imp(self: object) -> None: + def ins_dex_imp(self) -> None: """ DEX - Decrement X Register. @@ -338,7 +831,7 @@ def ins_dex_imp(self: object) -> None: self.evaluate_flag_z(self.reg_x) self.evaluate_flag_n(self.reg_x) - def ins_dey_imp(self: object) -> None: + def ins_dey_imp(self) -> None: """ DEY - Decrement Y Register. @@ -348,7 +841,7 @@ def ins_dey_imp(self: object) -> None: self.evaluate_flag_z(self.reg_y) self.evaluate_flag_n(self.reg_y) - def ins_inc_zp(self: object) -> None: + def ins_inc_zp(self) -> None: """ INC - Increment Memory, Zero Page. @@ -360,7 +853,7 @@ def ins_inc_zp(self: object) -> None: self.evaluate_flag_z(self.memory[address]) self.cycles += 1 - def ins_inc_zpx(self: object) -> None: + def ins_inc_zpx(self) -> None: """ INC - Increment Memory, Zero Page, X. @@ -372,7 +865,7 @@ def ins_inc_zpx(self: object) -> None: self.evaluate_flag_z(self.memory[address]) self.cycles += 1 - def ins_inc_abs(self: object) -> None: + def ins_inc_abs(self) -> None: """ INC - Increment Memory, Absolute. @@ -384,7 +877,7 @@ def ins_inc_abs(self: object) -> None: self.evaluate_flag_z(self.memory[address]) self.cycles += 1 - def ins_inc_abx(self: object) -> None: + def ins_inc_abx(self) -> None: """ INC - Increment Memory, Absolute, X. @@ -396,7 +889,7 @@ def ins_inc_abx(self: object) -> None: self.evaluate_flag_z(self.memory[address]) self.cycles += 1 - def ins_inx_imp(self: object) -> None: + def ins_inx_imp(self) -> None: """ INX - Increment X Register. @@ -406,7 +899,7 @@ def ins_inx_imp(self: object) -> None: self.evaluate_flag_z(self.reg_x) self.evaluate_flag_n(self.reg_x) - def ins_iny_imp(self: object) -> None: + def ins_iny_imp(self) -> None: """ INY - Increment Y Register. @@ -416,7 +909,7 @@ def ins_iny_imp(self: object) -> None: self.evaluate_flag_z(self.reg_y) self.evaluate_flag_n(self.reg_y) - def ins_lda_imm(self: object) -> None: + def ins_lda_imm(self) -> None: """ LDA - Load Accumulator, Immediate. @@ -426,7 +919,7 @@ def ins_lda_imm(self: object) -> None: self.evaluate_flag_z(self.reg_a) self.evaluate_flag_n(self.reg_a) - def ins_lda_zp(self: object) -> None: + def ins_lda_zp(self) -> None: """ LDA - Load Accumulator, Zero Page. @@ -438,7 +931,7 @@ def ins_lda_zp(self: object) -> None: self.evaluate_flag_z(self.reg_a) self.evaluate_flag_n(self.reg_a) - def ins_lda_zpx(self: object) -> None: + def ins_lda_zpx(self) -> None: """ LDA - Load Accumulator, Zero Page, X. @@ -450,7 +943,7 @@ def ins_lda_zpx(self: object) -> None: self.evaluate_flag_z(self.reg_a) self.evaluate_flag_n(self.reg_a) - def ins_lda_abs(self: object) -> None: + def ins_lda_abs(self) -> None: """ LDA - Load Accumulator, Absolute. @@ -462,7 +955,7 @@ def ins_lda_abs(self: object) -> None: self.evaluate_flag_z(self.reg_a) self.evaluate_flag_n(self.reg_a) - def ins_lda_abx(self: object) -> None: + def ins_lda_abx(self) -> None: """ LDA - Load Accumulator, Absolute, X. @@ -476,7 +969,7 @@ def ins_lda_abx(self: object) -> None: self.evaluate_flag_z(self.reg_a) self.evaluate_flag_n(self.reg_a) - def ins_lda_aby(self: object) -> None: + def ins_lda_aby(self) -> None: """ LDA - Load Accumulator, Absolute, Y. @@ -490,7 +983,7 @@ def ins_lda_aby(self: object) -> None: self.evaluate_flag_z(self.reg_a) self.evaluate_flag_n(self.reg_a) - def ins_lda_inx(self: object) -> None: + def ins_lda_inx(self) -> None: """ LDA - Load Accumulator, Indexed Indirect. @@ -505,7 +998,7 @@ def ins_lda_inx(self: object) -> None: self.evaluate_flag_n(self.reg_a) self.cycles += 1 - def ins_lda_iny(self: object) -> None: + def ins_lda_iny(self) -> None: """ LDA - Load Accumulator, Indirect Indexed. @@ -519,7 +1012,7 @@ def ins_lda_iny(self: object) -> None: self.evaluate_flag_z(self.reg_a) self.evaluate_flag_n(self.reg_a) - def ins_ldx_imm(self: object) -> None: + def ins_ldx_imm(self) -> None: """ LDA - Load X Register, Immediate. @@ -529,7 +1022,7 @@ def ins_ldx_imm(self: object) -> None: self.evaluate_flag_z(self.reg_x) self.evaluate_flag_n(self.reg_x) - def ins_ldx_zp(self: object) -> None: + def ins_ldx_zp(self) -> None: """ LDA - Load X Register, Zero Page. @@ -539,7 +1032,7 @@ def ins_ldx_zp(self: object) -> None: self.evaluate_flag_z(self.reg_x) self.evaluate_flag_n(self.reg_x) - def ins_ldx_zpy(self: object) -> None: + def ins_ldx_zpy(self) -> None: """ LDA - Load X Register, Zero Page, Y. @@ -551,7 +1044,7 @@ def ins_ldx_zpy(self: object) -> None: self.evaluate_flag_z(self.reg_x) self.evaluate_flag_n(self.reg_x) - def ins_ldx_abs(self: object) -> None: + def ins_ldx_abs(self) -> None: """ LDA - Load X Register, Absolute. @@ -563,7 +1056,7 @@ def ins_ldx_abs(self: object) -> None: self.evaluate_flag_z(self.reg_x) self.evaluate_flag_n(self.reg_x) - def ins_ldx_aby(self: object) -> None: + def ins_ldx_aby(self) -> None: """ LDA - Load X Register, Absolute, Y. @@ -577,7 +1070,7 @@ def ins_ldx_aby(self: object) -> None: self.evaluate_flag_z(self.reg_x) self.evaluate_flag_n(self.reg_x) - def ins_ldy_imm(self: object) -> None: + def ins_ldy_imm(self) -> None: """ LDA - Load Y Register, Immediate. @@ -587,7 +1080,7 @@ def ins_ldy_imm(self: object) -> None: self.evaluate_flag_z(self.reg_y) self.evaluate_flag_n(self.reg_y) - def ins_ldy_zp(self: object) -> None: + def ins_ldy_zp(self) -> None: """ LDA - Load Y Register, Zero Page. @@ -599,7 +1092,7 @@ def ins_ldy_zp(self: object) -> None: self.evaluate_flag_z(self.reg_y) self.evaluate_flag_n(self.reg_y) - def ins_ldy_zpx(self: object) -> None: + def ins_ldy_zpx(self) -> None: """ LDA - Load Y Register, Zero Page, X. @@ -611,7 +1104,7 @@ def ins_ldy_zpx(self: object) -> None: self.evaluate_flag_z(self.reg_y) self.evaluate_flag_n(self.reg_y) - def ins_ldy_abs(self: object) -> None: + def ins_ldy_abs(self) -> None: """ LDA - Load Y Register, Absolute. @@ -623,7 +1116,7 @@ def ins_ldy_abs(self: object) -> None: self.evaluate_flag_z(self.reg_y) self.evaluate_flag_n(self.reg_y) - def ins_ldy_abx(self: object) -> None: + def ins_ldy_abx(self) -> None: """ LDA - Load Y Register, Absolute, X. @@ -637,7 +1130,7 @@ def ins_ldy_abx(self: object) -> None: self.evaluate_flag_z(self.reg_y) self.evaluate_flag_n(self.reg_y) - def ins_sec_imp(self: object) -> None: + def ins_sec_imp(self) -> None: """ SEC - Set Carry Flag. @@ -646,7 +1139,7 @@ def ins_sec_imp(self: object) -> None: self.flag_c = True self.cycles += 1 - def ins_sed_imp(self: object) -> None: + def ins_sed_imp(self) -> None: """ SED - Set Decimal Mode. @@ -655,7 +1148,7 @@ def ins_sed_imp(self: object) -> None: self.flag_d = True self.cycles += 1 - def ins_sei_imp(self: object) -> None: + def ins_sei_imp(self) -> None: """ SEI - Set Interrupt Disable. @@ -664,7 +1157,7 @@ def ins_sei_imp(self: object) -> None: self.flag_i = True self.cycles += 1 - def ins_sta_zp(self: object) -> None: + def ins_sta_zp(self) -> None: """ STA - Store Accumulator, Zero Page. @@ -675,7 +1168,7 @@ def ins_sta_zp(self: object) -> None: self.reg_a ) - def ins_sta_zpx(self: object) -> None: + def ins_sta_zpx(self) -> None: """ STA - Store Accumulator, Zero Page, X. @@ -686,7 +1179,7 @@ def ins_sta_zpx(self: object) -> None: self.reg_a ) - def ins_sta_abs(self: object) -> None: + def ins_sta_abs(self) -> None: """ STA - Store Accumulator, Absolute. @@ -697,7 +1190,7 @@ def ins_sta_abs(self: object) -> None: self.reg_a ) - def ins_sta_abx(self: object) -> None: + def ins_sta_abx(self) -> None: """ STA - Store Accumulator, Absolute, X. @@ -712,7 +1205,7 @@ def ins_sta_abx(self: object) -> None: self.reg_a ) - def ins_sta_aby(self: object) -> None: + def ins_sta_aby(self) -> None: """ STA - Store Accumulator, Absolute, Y. @@ -727,7 +1220,7 @@ def ins_sta_aby(self: object) -> None: self.reg_a ) - def ins_sta_inx(self: object) -> None: + def ins_sta_inx(self) -> None: """ STA - Store Accumulator, Indexed Indirect. @@ -742,7 +1235,7 @@ def ins_sta_inx(self: object) -> None: self.reg_a ) - def ins_sta_iny(self: object) -> None: + def ins_sta_iny(self) -> None: """ LDA - Store Accumulator, Indirect Indexed. @@ -757,7 +1250,7 @@ def ins_sta_iny(self: object) -> None: self.reg_a ) - def ins_stx_zp(self: object) -> None: + def ins_stx_zp(self) -> None: """ STA - Store X Register, Zero Page. @@ -768,7 +1261,7 @@ def ins_stx_zp(self: object) -> None: self.reg_x ) - def ins_stx_zpy(self: object) -> None: + def ins_stx_zpy(self) -> None: """ STA - Store Y Register, Zero Page, X. @@ -779,7 +1272,7 @@ def ins_stx_zpy(self: object) -> None: self.reg_x ) - def ins_stx_abs(self: object) -> None: + def ins_stx_abs(self) -> None: """ STA - Store X Register, Absolute. @@ -790,7 +1283,7 @@ def ins_stx_abs(self: object) -> None: self.reg_x ) - def ins_sty_zp(self: object) -> None: + def ins_sty_zp(self) -> None: """ STA - Store Y Register, Zero Page. @@ -801,7 +1294,7 @@ def ins_sty_zp(self: object) -> None: self.reg_y ) - def ins_sty_zpx(self: object) -> None: + def ins_sty_zpx(self) -> None: """ STA - Store Y Register, Zero Page, X. @@ -812,7 +1305,7 @@ def ins_sty_zpx(self: object) -> None: self.reg_y ) - def ins_sty_abs(self: object) -> None: + def ins_sty_abs(self) -> None: """ STA - Store Y Register, Absolute. @@ -823,7 +1316,7 @@ def ins_sty_abs(self: object) -> None: self.reg_y ) - def ins_tax_imp(self: object) -> None: + def ins_tax_imp(self) -> None: """ TAX - Transfer Accumulator to X. @@ -833,7 +1326,7 @@ def ins_tax_imp(self: object) -> None: self.evaluate_flag_z(self.reg_x) self.evaluate_flag_n(self.reg_x) - def ins_tay_imp(self: object) -> None: + def ins_tay_imp(self) -> None: """ TAY - Transfer Accumulator to Y. @@ -843,7 +1336,7 @@ def ins_tay_imp(self: object) -> None: self.evaluate_flag_z(self.reg_y) self.evaluate_flag_n(self.reg_y) - def ins_tsx_imp(self: object) -> None: + def ins_tsx_imp(self) -> None: """ TSX - Transfer Stack Pointer to X. @@ -853,7 +1346,7 @@ def ins_tsx_imp(self: object) -> None: self.evaluate_flag_z(self.reg_x) self.evaluate_flag_n(self.reg_x) - def ins_txa_imp(self: object) -> None: + def ins_txa_imp(self) -> None: """ TXA - Transfer Register X to Accumulator. @@ -863,7 +1356,7 @@ def ins_txa_imp(self: object) -> None: self.evaluate_flag_z(self.reg_a) self.evaluate_flag_n(self.reg_a) - def ins_txs_imp(self: object) -> None: + def ins_txs_imp(self) -> None: """ TXS - Transfer Register X to Stack Pointer. @@ -871,7 +1364,7 @@ def ins_txs_imp(self: object) -> None: """ self.push(self.reg_x) - def ins_tya_imp(self: object) -> None: + def ins_tya_imp(self) -> None: """ TYA - Transfer Register Y to Accumulator. @@ -881,7 +1374,7 @@ def ins_tya_imp(self: object) -> None: self.evaluate_flag_z(self.reg_a) self.evaluate_flag_n(self.reg_a) - def ins_pha_imp(self: object) -> None: + def ins_pha_imp(self) -> None: """ PHA - Push Accumulator. @@ -893,7 +1386,7 @@ def ins_pha_imp(self: object) -> None: self.stack_pointer -= 1 self.cycles += 1 - def ins_pla_imp(self: object) -> None: + def ins_pla_imp(self) -> None: """ PLA - Pull Accumulator. @@ -907,7 +1400,7 @@ def ins_pla_imp(self: object) -> None: self.evaluate_flag_z(self.reg_a) self.evaluate_flag_n(self.reg_a) - def ins_php_imp(self: object) -> None: + def ins_php_imp(self) -> None: """ Push Processor Statys, Implied. @@ -931,7 +1424,7 @@ def ins_php_imp(self: object) -> None: self.push(flags) self.cycles += 1 - def ins_plp_imp(self: object) -> None: + def ins_plp_imp(self) -> None: """ Pull Processor Status. diff --git a/setup.cfg b/setup.cfg index 76f8954..94d2b28 100644 --- a/setup.cfg +++ b/setup.cfg @@ -15,19 +15,21 @@ min_version = 4.0 no_package = true skipsdist = true env_list = + clean py38 py39 py310 py311 py312 flake8 + pymarkdownlnt yamllint [testenv] deps = flake8 - flake8-annotations - flake8-annotations-complexity + ; flake8-annotations + ; flake8-annotations-complexity flake8-bugbear flake8-deprecated flake8-docstrings>=1.3.1 @@ -40,9 +42,26 @@ deps = flake8-builtins flake8-pytest-style pep8-naming + pymarkdownlnt pytest>=7,<8 + pytest-cov yamllint -commands = pytest tests +commands = pytest --cov=m6502 --cov-report=term-missing tests +depends = + {py38,py39,py310,py311,py312}: clean + report: py38,py39,py310,py311,py312 + +[testenv:clean] +deps = coverage +skip_install = true +commands = coverage erase + +[testenv:report] +deps = coverage +skip_install = true +commands = + coverage report + coverage html [testenv:flake8] basepython = python3.12 @@ -50,6 +69,12 @@ skip_install = true commands = flake8 --doctests tests/ m6502/ +[testenv:pymarkdownlnt] +basepython = python3.12 +skip_install = true +commands = + pymarkdownlnt scan . wiki + [testenv:yamllint] basepython = python3.12 skip_install = true diff --git a/tests/test_cpu.py b/tests/test_cpu.py index 2e5b253..27e0c05 100644 --- a/tests/test_cpu.py +++ b/tests/test_cpu.py @@ -1,5 +1,5 @@ """Verifies that the processor class works as expected.""" -import m6502 +from m6502 import Memory, Processor def test_cpu_reset() -> None: @@ -8,8 +8,8 @@ def test_cpu_reset() -> None: :return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() assert ( cpu.program_counter, @@ -30,8 +30,8 @@ def test_cpu_read_byte() -> None: :return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() memory[0x0001] = 0xA5 value = cpu.read_byte(0x0001) @@ -55,8 +55,8 @@ def test_cpu_read_word() -> None: :return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() memory[0x0001] = 0xA5 memory[0x0002] = 0x5A @@ -81,8 +81,8 @@ def test_cpu_write_byte() -> None: :return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.write_byte(0x0001, 0xA5) assert ( @@ -105,8 +105,8 @@ def test_cpu_write_word() -> None: :return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.write_word(0x0001, 0x5AA5) assert ( @@ -130,8 +130,8 @@ def test_cpu_read_write_byte() -> None: :return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.write_byte(0x0001, 0xA5) value = cpu.read_byte(0x0001) @@ -155,8 +155,8 @@ def test_cpu_read_write_word() -> None: :return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.write_word(0x0001, 0x5AA5) value = cpu.read_word(0x0001) @@ -180,8 +180,8 @@ def test_cpu_fetch_byte() -> None: :return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() memory[0xFCE2] = 0xA5 value = cpu.fetch_byte() @@ -205,8 +205,8 @@ def test_cpu_fetch_word() -> None: :return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() memory[0xFCE2] = 0xA5 memory[0xFCE3] = 0x5A diff --git a/tests/test_cpu_in_.rts b/tests/test_cpu_in_.rts new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_cpu_ins_adc.py b/tests/test_cpu_ins_adc.py new file mode 100644 index 0000000..ab72507 --- /dev/null +++ b/tests/test_cpu_ins_adc.py @@ -0,0 +1,91 @@ +""" +ADC - Add with Carry. + +A,Z,C,N = A+M+C + +This instruction adds the contents of a memory location to the accumulator +together with the carry bit. If overflow occurs the carry bit is set, this +enables multiple byte addition to be performed. + +Processor Status after use: + ++------+-------------------+------------------------------+ +| Flag | Description | State | ++======+===================+==============================+ +| C | Carry Flag | Set if overflow in bit 7 | ++------+-------------------+------------------------------+ +| Z | Zero Flag | Set if A = 0 | ++------+-------------------+------------------------------+ +| I | Interrupt Disable | Not affected | ++------+-------------------+------------------------------+ +| D | Decimal Mode Flag | Not affected | ++------+-------------------+------------------------------+ +| B | Break Command | Not affected | ++------+-------------------+------------------------------+ +| V | Overflow Flag | Set if sign bit is incorrect | ++------+-------------------+------------------------------+ +| N | Negative Flag | Set if bit 7 set | ++------+-------------------+------------------------------+ + ++-----------------+--------+-------+--------------------------+ +| Addressing Mode | Opcode | Bytes | Cycles | ++=================+========+=======+==========================+ +| Immediate | 0x69 | 2 | 2 | ++-----------------+--------+-------+--------------------------+ +| Zero Page | 0x65 | 2 | 3 | ++-----------------+--------+-------+--------------------------+ +| Zero Page,X | 0x75 | 2 | 4 | ++-----------------+--------+-------+--------------------------+ +| Absolute | 0x6D | 3 | 4 | ++-----------------+-------+-------+--------------------------+ +| Absolute,X | 0x7D | 3 | 4 (+1 if page crossed) | ++-----------------+--------+-------+--------------------------+ +| Absolute,Y | 0x79 | 3 | 4 (+1 if page crossed) | ++-----------------+--------+-------+--------------------------+ +| (Indirect,X) | 0x61 | 2 | 6 | ++-----------------+--------+-------+--------------------------+ +| (Indirect),Y | 0x71 | 2 | 5 (+1 if page crossed) | ++-----------------+--------+-------+--------------------------+ + +See also: SBC +""" +import pytest + +from m6502 import Memory, Processor + + +@pytest.mark.parametrize( + ("value_a", "value_mem", "result"), + [ + (0x0F, 0xF0, False), + (0xF0, 0x0F, False), + (0x0F, 0x0F, True), + (0xF0, 0xF0, True), + ] +) +def test_cpu_ins_adc_imm(value_a: int, value_mem: int, result: bool) -> None: + assert False # TODO: implement test + + +def test_cpu_ins_adc_zp() -> None: + assert False # TODO: implement test + + +def test_cpu_ins_adc_zpx() -> None: + assert False # TODO: implement test + + +def test_cpu_ins_adc_abs() -> None: + assert False # TODO: implement test + + +def test_cpu_ins_adc_absx() -> None: + assert False # TODO: implement test + + +def test_cpu_ins_adc_absy() -> None: + assert False # TODO: implement test + + +def test_cpu_ins_adc_indx() -> None: + assert False # TODO: implement test diff --git a/tests/test_cpu_ins_and.py b/tests/test_cpu_ins_and.py new file mode 100644 index 0000000..e1065d6 --- /dev/null +++ b/tests/test_cpu_ins_and.py @@ -0,0 +1,84 @@ +""" +AND - Logical AND. + +A,Z,N = A&M + +A logical AND is performed, bit by bit, on the accumulator contents using +the contents of a byte of memory + +Processor Status after use: + ++------+-------------------+------------------+ +| Flag | Description | State | ++======+===================+==================+ +| C | Carry Flag | Not affected | ++------+-------------------+------------------+ +| Z | Zero Flag | Set if A = 0 | ++------+-------------------+------------------+ +| I | Interrupt Disable | Not affected | ++------+-------------------+------------------+ +| D | Decimal Mode Flag | Not affected | ++------+-------------------+------------------+ +| B | Break Command | Not affected | ++------+-------------------+------------------+ +| V | Overflow Flag | Not affected | ++------+-------------------+------------------+ +| N | Negative Flag | Set if bit 7 set | ++------+-------------------+------------------+ + ++-----------------+--------+-------+--------------------------+ +| Addressing Mode | Opcode | Bytes | Cycles | ++=================+========+=======+==========================+ +| Immediate | 0x29 | 2 | 2 | ++-----------------+--------+-------+--------------------------+ +| Zero Page | 0x25 | 2 | 3 | ++-----------------+--------+-------+--------------------------+ +| Zero Page,X | 0x35 | 2 | 4 | ++-----------------+--------+-------+--------------------------+ +| Absolute | 0x2D | 3 | 4 | ++-----------------+--------+-------+--------------------------+ +| Absolute,X | 0x3D | 3 | 4 (+1 if page crossed) | ++-----------------+--------+-------+--------------------------+ +| Absolute,Y | 0x39 | 3 | 4 (+1 if page crossed) | ++-----------------+--------+-------+--------------------------+ +| (Indirect,X) | 0x21 | 2 | 6 | ++-----------------+--------+-------+--------------------------+ +| (Indirect),Y | 0x31 | 2 | 5 (+1 if page crossed) | ++-----------------+--------+-------+--------------------------+ + +See also: EOR, ORA +""" +import pytest + +from m6502 import Memory, Processor + +testdata = [ + (0x0F, 0xF0, False), + (0xF0, 0x0F, False), + (0x0F, 0x0F, True), + (0xF0, 0xF0, True), +] + + +@pytest.mark.parametrize( + ("value_a", "value_mem", "result"), + testdata +) +def test_cpu_ins_and_imm(value_a: int, value_mem: int, result: bool) -> None: + assert False # TODO: implement test + + +@pytest.mark.parametrize( + ("value_a", "value_mem", "result"), + testdata +) +def test_cpu_ins_and_zp(value_a: int, value_mem: int, result: bool) -> None: + assert False # TODO: implement test + + +@pytest.mark.parametrize( + ("value_a", "value_mem", "result"), + testdata +) +def test_cpu_ins_and_zpx(value_a: int, value_mem: int, result: bool) -> None: + assert False # TODO: implement test diff --git a/tests/test_cpu_ins_asl.py b/tests/test_cpu_ins_asl.py new file mode 100644 index 0000000..19ab5c7 --- /dev/null +++ b/tests/test_cpu_ins_asl.py @@ -0,0 +1,101 @@ +""" +ASL - Arithmetic Shift Left. + +A,Z,C,N = A*2 or M,Z,C,N = M*2 + +This instruction adds the contents of a memory location to the accumulator +together with the carry bit. If overflow occurs the carry bit is set, this +enables multiple byte addition to be performed. + +Processor Status after use: + ++------+-------------------+-----------------------------------+ +| Flag | Description | State | ++======+===================+===================================+ +| C | Carry Flag | Set to contents of old bit 7 | ++------+-------------------+-----------------------------------+ +| Z | Zero Flag | Set if A = 0 | ++------+-------------------+-----------------------------------+ +| I | Interrupt Disable | Not affected | ++------+-------------------+-----------------------------------+ +| D | Decimal Mode Flag | Not affected | ++------+-------------------+-----------------------------------+ +| B | Break Command | Not affected | ++------+-------------------+-----------------------------------+ +| V | Overflow Flag | Not affected | ++------+-------------------+-----------------------------------+ +| N | Negative Flag | Set if bit 7 of the result is set | ++------+-------------------+-----------------------------------+ + ++-----------------+--------+-------+--------+ +| Addressing Mode | Opcode | Bytes | Cycles | ++=================+========+=======+========+ +| Accumulator | 0x0A | 1 | 2 | ++-----------------+--------+-------+--------+ +| Zero Page | 0x06 | 2 | 5 | ++-----------------+--------+-------+--------+ +| Zero Page,X | 0x16 | 2 | 6 | ++-----------------+--------+-------+--------+ +| Absolute | 0x0E | 3 | 6 | ++-----------------+-------+-------+---------+ +| Absolute,X | 0x1E | 3 | 7 | ++-----------------+--------+-------+--------+ + +See also: LSR, ROL, ROR +""" +import pytest + +from m6502 import Memory, Processor + + +testdata = [ + (0b00000000, 0b00000001, False, False, False), + (0b00000001, 0b00000010, False, False, False), + (0b00000010, 0b00000100, False, False, False), + (0b00000100, 0b00001000, False, False, False), + (0b00001000, 0b00010000, False, False, False), + (0b00010000, 0b00100000, False, False, False), + (0b00100000, 0b01000000, False, False, False), + (0b01000000, 0b10000000, False, False, False), + (0b10000000, 0b00000000, True, False, True), +] + + +@pytest.mark.parametrize( + ("value_a", "result", "carry", "zero", "negative"), + testdata +) +def test_asl_acc(value_a: int, result: int, carry: bool, zero: bool, negative: bool) -> None: + assert False # TODO: implement test + + +@pytest.mark.parametrize( + ("value_a", "result", "carry", "zero", "negative"), + testdata +) +def test_asl_zp(value_a: int, result: int, carry: bool, zero: bool, negative: bool) -> None: + assert False # TODO: implement test + + +@pytest.mark.parametrize( + ("value_a", "result", "carry", "zero", "negative"), + testdata +) +def test_asl_zpx(value_a: int, result: int, carry: bool, zero: bool, negative: bool) -> None: + assert False # TODO: implement test + + +@pytest.mark.parametrize( + ("value_a", "result", "carry", "zero", "negative"), + testdata +) +def test_asl_abs(value_a: int, result: int, carry: bool, zero: bool, negative: bool) -> None: + assert False # TODO: implement test + + +@pytest.mark.parametrize( + ("value_a", "result", "carry", "zero", "negative"), + testdata +) +def test_asl_absx(value_a: int, result: int, carry: bool, zero: bool, negative: bool) -> None: + assert False # TODO: implement test diff --git a/tests/test_cpu_ins_bcc.py b/tests/test_cpu_ins_bcc.py new file mode 100644 index 0000000..cbc1e07 --- /dev/null +++ b/tests/test_cpu_ins_bcc.py @@ -0,0 +1,39 @@ +""" +BCC - Branch if Carry Clear. + +If the carry flag is clear then add the relative displacement to the program +to cause a branch to a new location. + +Processor Status after use: + ++------+-------------------+-----------------------------------+ +| Flag | Description | State | ++======+===================+===================================+ +| C | Carry Flag | Not affected | ++------+-------------------+-----------------------------------+ +| Z | Zero Flag | Not affected | ++------+-------------------+-----------------------------------+ +| I | Interrupt Disable | Not affected | ++------+-------------------+-----------------------------------+ +| D | Decimal Mode Flag | Not affected | ++------+-------------------+-----------------------------------+ +| B | Break Command | Not affected | ++------+-------------------+-----------------------------------+ +| V | Overflow Flag | Not affected | ++------+-------------------+-----------------------------------+ +| N | Negative Flag | Not affected | ++------+-------------------+-----------------------------------+ + ++-----------------+--------+-------+---------------------------+ +| Addressing Mode | Opcode | Bytes | Cycles | ++=================+========+=======+===========================+ +| Relative | 0x90 | 2 | 2 (+1 if branch succeeds | +| | | | +2 if to a new page) | ++-----------------+--------+-------+---------------------------+ + +See also: BCS +""" + + +def test_cpu_ins_bcc_rel() -> None: + assert False # TODO: implement test diff --git a/tests/test_cpu_ins_bcs.py b/tests/test_cpu_ins_bcs.py new file mode 100644 index 0000000..162eadc --- /dev/null +++ b/tests/test_cpu_ins_bcs.py @@ -0,0 +1,39 @@ +""" +BCS - Branch if Carry Set. + +If the carry flag is set then add the relative displacement to the program +to cause a branch to a new location. + +Processor Status after use: + ++------+-------------------+-----------------------------------+ +| Flag | Description | State | ++======+===================+===================================+ +| C | Carry Flag | Not affected | ++------+-------------------+-----------------------------------+ +| Z | Zero Flag | Not affected | ++------+-------------------+-----------------------------------+ +| I | Interrupt Disable | Not affected | ++------+-------------------+-----------------------------------+ +| D | Decimal Mode Flag | Not affected | ++------+-------------------+-----------------------------------+ +| B | Break Command | Not affected | ++------+-------------------+-----------------------------------+ +| V | Overflow Flag | Not affected | ++------+-------------------+-----------------------------------+ +| N | Negative Flag | Not affected | ++------+-------------------+-----------------------------------+ + ++-----------------+--------+-------+---------------------------+ +| Addressing Mode | Opcode | Bytes | Cycles | ++=================+========+=======+===========================+ +| Relative | 0xB0 | 2 | 2 (+1 if branch succeeds | +| | | | +2 if to a new page) | ++-----------------+--------+-------+---------------------------+ + +See also: BCC +""" + + +def test_cpu_ins_bcs_rel() -> None: + assert False # TODO: implement test diff --git a/tests/test_cpu_ins_beq.py b/tests/test_cpu_ins_beq.py new file mode 100644 index 0000000..6ae5e7d --- /dev/null +++ b/tests/test_cpu_ins_beq.py @@ -0,0 +1,39 @@ +""" +BEQ - Branch if Equal. + +If the zero flag is set then add the relative displacement to the program +to cause a branch to a new location. + +Processor Status after use: + ++------+-------------------+-----------------------------------+ +| Flag | Description | State | ++======+===================+===================================+ +| C | Carry Flag | Not affected | ++------+-------------------+-----------------------------------+ +| Z | Zero Flag | Not affected | ++------+-------------------+-----------------------------------+ +| I | Interrupt Disable | Not affected | ++------+-------------------+-----------------------------------+ +| D | Decimal Mode Flag | Not affected | ++------+-------------------+-----------------------------------+ +| B | Break Command | Not affected | ++------+-------------------+-----------------------------------+ +| V | Overflow Flag | Not affected | ++------+-------------------+-----------------------------------+ +| N | Negative Flag | Not affected | ++------+-------------------+-----------------------------------+ + ++-----------------+--------+-------+---------------------------+ +| Addressing Mode | Opcode | Bytes | Cycles | ++=================+========+=======+===========================+ +| Relative | 0xF0 | 2 | 2 (+1 if branch succeeds | +| | | | +2 if to a new page) | ++-----------------+--------+-------+---------------------------+ + +See also: BNE +""" + + +def test_cpu_ins_beq_rel() -> None: + assert False # TODO: implement test diff --git a/tests/test_cpu_ins_bit.py b/tests/test_cpu_ins_bit.py new file mode 100644 index 0000000..cf2ee0f --- /dev/null +++ b/tests/test_cpu_ins_bit.py @@ -0,0 +1,46 @@ +""" +BIT - Bit Test. + +A & M, N = M7, V = M6 + +This instructions is used to test if one or more bits are set in a target +memory location. The mask pattern in A is ANDed with the value in memory to +set or clear the zero flag, but the result is not kept. Bits 7 and 6 of the +value from memory are copied into the N and V flags. + +Processor Status after use: + ++------+-------------------+-----------------------------------+ +| Flag | Description | State | ++======+===================+===================================+ +| C | Carry Flag | Not affected | ++------+-------------------+-----------------------------------+ +| Z | Zero Flag | Not affected | ++------+-------------------+-----------------------------------+ +| I | Interrupt Disable | Not affected | ++------+-------------------+-----------------------------------+ +| D | Decimal Mode Flag | Not affected | ++------+-------------------+-----------------------------------+ +| B | Break Command | Not affected | ++------+-------------------+-----------------------------------+ +| V | Overflow Flag | Not affected | ++------+-------------------+-----------------------------------+ +| N | Negative Flag | Not affected | ++------+-------------------+-----------------------------------+ + ++-----------------+--------+-------+---------------------------+ +| Addressing Mode | Opcode | Bytes | Cycles | ++=================+========+=======+===========================+ +| Zero Page | 0x24 | 2 | 3 | ++-----------------+--------+-------+---------------------------+ +| Absolute | 0x2C | 3 | 4 | ++-----------------+--------+-------+---------------------------+ +""" + + +def test_cpu_ins_bit_zp() -> None: + assert False # TODO: implement test + + +def test_cpu_ins_bit_abs() -> None: + assert False # TODO: implement test diff --git a/tests/test_cpu_ins_bmi.py b/tests/test_cpu_ins_bmi.py new file mode 100644 index 0000000..430e1ce --- /dev/null +++ b/tests/test_cpu_ins_bmi.py @@ -0,0 +1,39 @@ +""" +BMI - Branch if Minus. + +If the negative flag is set then add the relative displacement to the program +to cause a branch to a new location. + +Processor Status after use: + ++------+-------------------+-----------------------------------+ +| Flag | Description | State | ++======+===================+===================================+ +| C | Carry Flag | Not affected | ++------+-------------------+-----------------------------------+ +| Z | Zero Flag | Not affected | ++------+-------------------+-----------------------------------+ +| I | Interrupt Disable | Not affected | ++------+-------------------+-----------------------------------+ +| D | Decimal Mode Flag | Not affected | ++------+-------------------+-----------------------------------+ +| B | Break Command | Not affected | ++------+-------------------+-----------------------------------+ +| V | Overflow Flag | Not affected | ++------+-------------------+-----------------------------------+ +| N | Negative Flag | Not affected | ++------+-------------------+-----------------------------------+ + ++-----------------+--------+-------+---------------------------+ +| Addressing Mode | Opcode | Bytes | Cycles | ++=================+========+=======+===========================+ +| Relative | 0x30 | 2 | 2 (+1 if branch succeeds | +| | | | +2 if to a new page) | ++-----------------+--------+-------+---------------------------+ + +See also: BPL +""" + + +def test_cpu_ins_bmi_rel() -> None: + assert False # TODO: implement test diff --git a/tests/test_cpu_ins_bne.py b/tests/test_cpu_ins_bne.py new file mode 100644 index 0000000..5c7189a --- /dev/null +++ b/tests/test_cpu_ins_bne.py @@ -0,0 +1,39 @@ +""" +BNE - Branch if Not Equal. + +If the zero flag is clear then add the relative displacement to the program +to cause a branch to a new location. + +Processor Status after use: + ++------+-------------------+-----------------------------------+ +| Flag | Description | State | ++======+===================+===================================+ +| C | Carry Flag | Not affected | ++------+-------------------+-----------------------------------+ +| Z | Zero Flag | Not affected | ++------+-------------------+-----------------------------------+ +| I | Interrupt Disable | Not affected | ++------+-------------------+-----------------------------------+ +| D | Decimal Mode Flag | Not affected | ++------+-------------------+-----------------------------------+ +| B | Break Command | Not affected | ++------+-------------------+-----------------------------------+ +| V | Overflow Flag | Not affected | ++------+-------------------+-----------------------------------+ +| N | Negative Flag | Not affected | ++------+-------------------+-----------------------------------+ + ++-----------------+--------+-------+---------------------------+ +| Addressing Mode | Opcode | Bytes | Cycles | ++=================+========+=======+===========================+ +| Relative | 0xD0 | 2 | 2 (+1 if branch succeeds | +| | | | +2 if to a new page) | ++-----------------+--------+-------+---------------------------+ + +See also: BEQ +""" + + +def test_cpu_ins_bne_rel() -> None: + assert False # TODO: implement test diff --git a/tests/test_cpu_ins_bpl.py b/tests/test_cpu_ins_bpl.py new file mode 100644 index 0000000..ab123fa --- /dev/null +++ b/tests/test_cpu_ins_bpl.py @@ -0,0 +1,39 @@ +""" +BPL - Branch if Positive. + +If the negative flag is clear then add the relative displacement to the program +to cause a branch to a new location. + +Processor Status after use: + ++------+-------------------+-----------------------------------+ +| Flag | Description | State | ++======+===================+===================================+ +| C | Carry Flag | Not affected | ++------+-------------------+-----------------------------------+ +| Z | Zero Flag | Not affected | ++------+-------------------+-----------------------------------+ +| I | Interrupt Disable | Not affected | ++------+-------------------+-----------------------------------+ +| D | Decimal Mode Flag | Not affected | ++------+-------------------+-----------------------------------+ +| B | Break Command | Not affected | ++------+-------------------+-----------------------------------+ +| V | Overflow Flag | Not affected | ++------+-------------------+-----------------------------------+ +| N | Negative Flag | Not affected | ++------+-------------------+-----------------------------------+ + ++-----------------+--------+-------+---------------------------+ +| Addressing Mode | Opcode | Bytes | Cycles | ++=================+========+=======+===========================+ +| Relative | 0x10 | 2 | 2 (+1 if branch succeeds | +| | | | +2 if to a new page) | ++-----------------+--------+-------+---------------------------+ + +See also: BMI +""" + + +def test_cpu_ins_bpl_rel() -> None: + assert False # TODO: implement test diff --git a/tests/test_cpu_ins_brk.py b/tests/test_cpu_ins_brk.py new file mode 100644 index 0000000..d55d08d --- /dev/null +++ b/tests/test_cpu_ins_brk.py @@ -0,0 +1,41 @@ +""" +BRK - Force Interrupt. + +The BRK instruction forces the generation of an interrupt request. The program +counter and processor status are pushed on the stack then the IRQ interrupt at +vector $FFFE/F is loaded into the PC and the break flag in the status set to +one. + ++------+-------------------+-----------------------------------+ +| Flag | Description | State | ++======+===================+===================================+ +| C | Carry Flag | Not affected | ++------+-------------------+-----------------------------------+ +| Z | Zero Flag | Not affected | ++------+-------------------+-----------------------------------+ +| I | Interrupt Disable | Not affected | ++------+-------------------+-----------------------------------+ +| D | Decimal Mode Flag | Not affected | ++------+-------------------+-----------------------------------+ +| B | Break Command | Set to 1 | ++------+-------------------+-----------------------------------+ +| V | Overflow Flag | Not affected | ++------+-------------------+-----------------------------------+ +| N | Negative Flag | Not affected | ++------+-------------------+-----------------------------------+ + ++-----------------+--------+-------+---------------------------+ +| Addressing Mode | Opcode | Bytes | Cycles | ++=================+========+=======+===========================+ +| Implied | 0x00 | 1 | 7 | ++-----------------+--------+-------+---------------------------+ + +The interpretation of a BRK depends pn the operating system. On the BBC +Microcomputer it is used by language ROMs to signal run time errors but it +could be used for other purposes (e.g. calling operating system functions, +etc.). +""" + + +def test_cpu_ins_brk_rel() -> None: + assert False # TODO: implement test diff --git a/tests/test_cpu_ins_bvc.py b/tests/test_cpu_ins_bvc.py new file mode 100644 index 0000000..72252c7 --- /dev/null +++ b/tests/test_cpu_ins_bvc.py @@ -0,0 +1,39 @@ +""" +BVC - Branch if Overflow Clear. + +If the overflow flag is clear then add the relative displacement to the program +counter to cause a branch to a new location. + +Processor Status after use: + ++------+-------------------+-----------------------------------+ +| Flag | Description | State | ++======+===================+===================================+ +| C | Carry Flag | Not affected | ++------+-------------------+-----------------------------------+ +| Z | Zero Flag | Not affected | ++------+-------------------+-----------------------------------+ +| I | Interrupt Disable | Not affected | ++------+-------------------+-----------------------------------+ +| D | Decimal Mode Flag | Not affected | ++------+-------------------+-----------------------------------+ +| B | Break Command | Not affected | ++------+-------------------+-----------------------------------+ +| V | Overflow Flag | Not affected | ++------+-------------------+-----------------------------------+ +| N | Negative Flag | Not affected | ++------+-------------------+-----------------------------------+ + ++-----------------+--------+-------+---------------------------+ +| Addressing Mode | Opcode | Bytes | Cycles | ++=================+========+=======+===========================+ +| Relative | 0x50 | 2 | 2 (+1 if branch succeeds | +| | | | +2 if to a new page) | ++-----------------+--------+-------+---------------------------+ + +See also: BVS +""" + + +def test_cpu_ins_bvc_rel() -> None: + assert False # TODO: implement test diff --git a/tests/test_cpu_ins_bvs.py b/tests/test_cpu_ins_bvs.py new file mode 100644 index 0000000..de008e4 --- /dev/null +++ b/tests/test_cpu_ins_bvs.py @@ -0,0 +1,39 @@ +""" +BVS - Branch if Overflow Set. + +If the overflow flag is set then add the relative displacement to the program +counter to cause a branch to a new location. + +Processor Status after use: + ++------+-------------------+-----------------------------------+ +| Flag | Description | State | ++======+===================+===================================+ +| C | Carry Flag | Not affected | ++------+-------------------+-----------------------------------+ +| Z | Zero Flag | Not affected | ++------+-------------------+-----------------------------------+ +| I | Interrupt Disable | Not affected | ++------+-------------------+-----------------------------------+ +| D | Decimal Mode Flag | Not affected | ++------+-------------------+-----------------------------------+ +| B | Break Command | Not affected | ++------+-------------------+-----------------------------------+ +| V | Overflow Flag | Not affected | ++------+-------------------+-----------------------------------+ +| N | Negative Flag | Not affected | ++------+-------------------+-----------------------------------+ + ++-----------------+--------+-------+---------------------------+ +| Addressing Mode | Opcode | Bytes | Cycles | ++=================+========+=======+===========================+ +| Relative | 0x70 | 2 | 2 (+1 if branch succeeds | +| | | | +2 if to a new page) | ++-----------------+--------+-------+---------------------------+ + +See also: BVC +""" + + +def test_cpu_ins_bvs_rel() -> None: + assert False # TODO: implement test diff --git a/tests/test_cpu_ins_clc.py b/tests/test_cpu_ins_clc.py index b70be17..92c709f 100644 --- a/tests/test_cpu_ins_clc.py +++ b/tests/test_cpu_ins_clc.py @@ -31,7 +31,7 @@ See also: SEC """ -import m6502 +from m6502 import Memory, Processor def test_cpu_ins_clc_imp() -> None: @@ -40,8 +40,8 @@ def test_cpu_ins_clc_imp() -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.flag_c = True memory[0xFCE2] = 0x18 diff --git a/tests/test_cpu_ins_cld.py b/tests/test_cpu_ins_cld.py index d11ea85..1915b8f 100644 --- a/tests/test_cpu_ins_cld.py +++ b/tests/test_cpu_ins_cld.py @@ -37,7 +37,7 @@ See also: SED """ -import m6502 +from m6502 import Memory, Processor def test_cpu_ins_cld_imp() -> None: @@ -46,8 +46,8 @@ def test_cpu_ins_cld_imp() -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.flag_d = True memory[0xFCE2] = 0xD8 diff --git a/tests/test_cpu_ins_cli.py b/tests/test_cpu_ins_cli.py index 31c4396..0f20c20 100644 --- a/tests/test_cpu_ins_cli.py +++ b/tests/test_cpu_ins_cli.py @@ -32,7 +32,7 @@ See also: SEI """ -import m6502 +from m6502 import Memory, Processor def test_cpu_ins_cld_imp() -> None: @@ -41,8 +41,8 @@ def test_cpu_ins_cld_imp() -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.flag_i = True memory[0xFCE2] = 0x58 diff --git a/tests/test_cpu_ins_clv.py b/tests/test_cpu_ins_clv.py index 5d7df01..398227b 100644 --- a/tests/test_cpu_ins_clv.py +++ b/tests/test_cpu_ins_clv.py @@ -29,7 +29,7 @@ | Implied | 0xB8 | 1 | 2 | +-----------------+--------+-------+--------+ """ -import m6502 +from m6502 import Memory, Processor def test_cpu_ins_cld_imp() -> None: @@ -38,8 +38,8 @@ def test_cpu_ins_cld_imp() -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.flag_v = True memory[0xFCE2] = 0xB8 diff --git a/tests/test_cpu_ins_cmp.py b/tests/test_cpu_ins_cmp.py new file mode 100644 index 0000000..061cce1 --- /dev/null +++ b/tests/test_cpu_ins_cmp.py @@ -0,0 +1,82 @@ +""" +CMP - Compare. + +Z,C,N = A-M + +This instruction compares the contents of the accumulator with another memory +held value and sets the zero and carry flags as appropriate. + +Processor Status after use: + ++------+-------------------+-----------------------------------+ +| Flag | Description | State | ++======+===================+===================================+ +| C | Carry Flag | Set if A >= M | ++------+-------------------+-----------------------------------+ +| Z | Zero Flag | Set if A = M | ++------+-------------------+-----------------------------------+ +| I | Interrupt Disable | Not affected | ++------+-------------------+-----------------------------------+ +| D | Decimal Mode Flag | Not affected | ++------+-------------------+-----------------------------------+ +| B | Break Command | Not affected | ++------+-------------------+-----------------------------------+ +| V | Overflow Flag | Not affected | ++------+-------------------+-----------------------------------+ +| N | Negative Flag | Set if bit 7 of the result is set | ++------+-------------------+-----------------------------------+ + ++-----------------+--------+-------+--------------------------+ +| Addressing Mode | Opcode | Bytes | Cycles | ++=================+========+=======+==========================+ +| Immediate | 0xC9 | 2 | 2 | ++-----------------+--------+-------+--------------------------+ +| Zero Page | 0xC5 | 2 | 3 | ++-----------------+--------+-------+--------------------------+ +| Zero Page,X | 0xD5 | 2 | 4 | ++-----------------+--------+-------+--------------------------+ +| Absolute | 0xCD | 3 | 4 | ++-----------------+-------+-------+--------------------------+ +| Absolute,X | 0xDD | 3 | 4 (+1 if page crossed) | ++-----------------+--------+-------+--------------------------+ +| Absolute,Y | 0xD9 | 3 | 4 (+1 if page crossed) | ++-----------------+--------+-------+--------------------------+ +| (Indirect,X) | 0xC1 | 2 | 6 | ++-----------------+--------+-------+--------------------------+ +| (Indirect),Y | 0xD1 | 2 | 5 (+1 if page crossed) | ++-----------------+--------+-------+--------------------------+ + +See also: CPX, CPY +""" + + +def test_cpu_ins_cmp_imm() -> None: + assert False # TODO: implement test + + +def test_cpu_ins_cmp_zp() -> None: + assert False # TODO: implement test + + +def test_cpu_ins_cmp_zpx() -> None: + assert False # TODO: implement test + + +def test_cpu_ins_cmp_abs() -> None: + assert False # TODO: implement test + + +def test_cpu_ins_cmp_absx() -> None: + assert False # TODO: implement test + + +def test_cpu_ins_cmp_absy() -> None: + assert False # TODO: implement test + + +def test_cpu_ins_cmp_indx() -> None: + assert False # TODO: implement test + + +def test_cpu_ins_cmp_indy() -> None: + assert False # TODO: implement test diff --git a/tests/test_cpu_ins_cpx.py b/tests/test_cpu_ins_cpx.py new file mode 100644 index 0000000..aca5db8 --- /dev/null +++ b/tests/test_cpu_ins_cpx.py @@ -0,0 +1,52 @@ +""" +CPX - Compare X Register. + +Z,C,N = X-M + +This instruction compares the contents of the X register with another memory +held value and sets the zero and carry flags as appropriate. + +Processor Status after use: + ++------+-------------------+-----------------------------------+ +| Flag | Description | State | ++======+===================+===================================+ +| C | Carry Flag | Set if X >= M | ++------+-------------------+-----------------------------------+ +| Z | Zero Flag | Set if X = M | ++------+-------------------+-----------------------------------+ +| I | Interrupt Disable | Not affected | ++------+-------------------+-----------------------------------+ +| D | Decimal Mode Flag | Not affected | ++------+-------------------+-----------------------------------+ +| B | Break Command | Not affected | ++------+-------------------+-----------------------------------+ +| V | Overflow Flag | Not affected | ++------+-------------------+-----------------------------------+ +| N | Negative Flag | Set if bit 7 of the result is set | ++------+-------------------+-----------------------------------+ + ++-----------------+--------+-------+--------------------------+ +| Addressing Mode | Opcode | Bytes | Cycles | ++=================+========+=======+==========================+ +| Immediate | 0xE0 | 2 | 2 | ++-----------------+--------+-------+--------------------------+ +| Zero Page | 0xE4 | 2 | 3 | ++-----------------+--------+-------+--------------------------+ +| Absolute | 0xEC | 3 | 4 | ++-----------------+--------+-------+--------------------------+ + +See also: CMP, CPY +""" + + +def test_cpu_ins_cpx_imm() -> None: + assert False # TODO: implement test + + +def test_cpu_ins_cpx_zp() -> None: + assert False # TODO: implement test + + +def test_cpu_ins_cpx_abs() -> None: + assert False # TODO: implement test diff --git a/tests/test_cpu_ins_cpy.py b/tests/test_cpu_ins_cpy.py new file mode 100644 index 0000000..ad8b868 --- /dev/null +++ b/tests/test_cpu_ins_cpy.py @@ -0,0 +1,52 @@ +""" +CPY - Compare Y Register. + +Z,C,N = Y-M + +This instruction compares the contents of the Y register with another memory +held value and sets the zero and carry flags as appropriate. + +Processor Status after use: + ++------+-------------------+-----------------------------------+ +| Flag | Description | State | ++======+===================+===================================+ +| C | Carry Flag | Set if Y >= M | ++------+-------------------+-----------------------------------+ +| Z | Zero Flag | Set if Y = M | ++------+-------------------+-----------------------------------+ +| I | Interrupt Disable | Not affected | ++------+-------------------+-----------------------------------+ +| D | Decimal Mode Flag | Not affected | ++------+-------------------+-----------------------------------+ +| B | Break Command | Not affected | ++------+-------------------+-----------------------------------+ +| V | Overflow Flag | Not affected | ++------+-------------------+-----------------------------------+ +| N | Negative Flag | Set if bit 7 of the result is set | ++------+-------------------+-----------------------------------+ + ++-----------------+--------+-------+--------------------------+ +| Addressing Mode | Opcode | Bytes | Cycles | ++=================+========+=======+==========================+ +| Immediate | 0xC0 | 2 | 2 | ++-----------------+--------+-------+--------------------------+ +| Zero Page | 0xC4 | 2 | 3 | ++-----------------+--------+-------+--------------------------+ +| Absolute | 0xCC | 3 | 4 | ++-----------------+--------+-------+--------------------------+ + +See also: CMP, CPX +""" + + +def test_cpu_ins_cpy_imm() -> None: + assert False # TODO: implement test + + +def test_cpu_ins_cpy_zp() -> None: + assert False # TODO: implement test + + +def test_cpu_ins_cpy_abs() -> None: + assert False # TODO: implement test diff --git a/tests/test_cpu_ins_dec.py b/tests/test_cpu_ins_dec.py index 328b68d..1299aa3 100644 --- a/tests/test_cpu_ins_dec.py +++ b/tests/test_cpu_ins_dec.py @@ -41,7 +41,7 @@ """ import pytest -import m6502 +from m6502 import Memory, Processor @pytest.mark.parametrize( @@ -57,8 +57,8 @@ def test_cpu_ins_dec_zp(value: int, expected: int, flag_z: bool, flag_n: bool) - return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() memory[0xFCE2] = 0xC6 memory[0xFCE3] = 0xFC @@ -96,8 +96,8 @@ def test_cpu_ins_dec_zpx(value: int, expected: int, flag_z: bool, flag_n: bool, return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_x = reg_x memory[0xFCE2] = 0xD6 @@ -127,8 +127,8 @@ def test_cpu_ins_dec_abs(value: int, expected: int, flag_z: bool, flag_n: bool) return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() memory[0xFCE2] = 0xCE memory[0xFCE3] = 0xFC @@ -158,8 +158,8 @@ def test_cpu_ins_dec_abx(value: int, expected: int, flag_z: bool, flag_n: bool) return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_x = 1 memory[0xFCE2] = 0xDE diff --git a/tests/test_cpu_ins_dex.py b/tests/test_cpu_ins_dex.py index 272780e..c161a49 100644 --- a/tests/test_cpu_ins_dex.py +++ b/tests/test_cpu_ins_dex.py @@ -34,7 +34,7 @@ """ import pytest -import m6502 +from m6502 import Memory, Processor @pytest.mark.parametrize( @@ -50,8 +50,8 @@ def test_cpu_ins_dex_imp(value: int, expected: int, flag_z: bool, flag_n: bool) return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_x = value memory[0xFCE2] = 0xCA diff --git a/tests/test_cpu_ins_dey.py b/tests/test_cpu_ins_dey.py index ecf7b71..2911acd 100644 --- a/tests/test_cpu_ins_dey.py +++ b/tests/test_cpu_ins_dey.py @@ -34,7 +34,7 @@ """ import pytest -import m6502 +from m6502 import Memory, Processor @pytest.mark.parametrize( @@ -50,8 +50,8 @@ def test_cpu_ins_dey_imp(value: int, expected: int, flag_z: bool, flag_n: bool) return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_y = value memory[0xFCE2] = 0x88 diff --git a/tests/test_cpu_ins_eor.py b/tests/test_cpu_ins_eor.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_cpu_ins_inc.py b/tests/test_cpu_ins_inc.py index 9ef983d..c39357d 100644 --- a/tests/test_cpu_ins_inc.py +++ b/tests/test_cpu_ins_inc.py @@ -41,7 +41,7 @@ """ import pytest -import m6502 +from m6502 import Memory, Processor @pytest.mark.parametrize( @@ -57,8 +57,8 @@ def test_cpu_ins_inc_zp(value: int, expected: int, flag_z: bool, flag_n: bool) - return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() memory[0xFCE2] = 0xE6 memory[0xFCE3] = 0xFC @@ -96,8 +96,8 @@ def test_cpu_ins_inc_zpx(value: int, expected: int, flag_z: bool, flag_n: bool, return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_x = reg_x memory[0xFCE2] = 0xF6 @@ -127,8 +127,8 @@ def test_cpu_ins_inc_abs(value: int, expected: int, flag_z: bool, flag_n: bool) return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() memory[0xFCE2] = 0xEE memory[0xFCE3] = 0xFC @@ -158,8 +158,8 @@ def test_cpu_ins_inc_abx(value: int, expected: int, flag_z: bool, flag_n: bool) return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_x = 1 memory[0xFCE2] = 0xFE diff --git a/tests/test_cpu_ins_inx.py b/tests/test_cpu_ins_inx.py index 058c771..fddd093 100644 --- a/tests/test_cpu_ins_inx.py +++ b/tests/test_cpu_ins_inx.py @@ -34,7 +34,7 @@ """ import pytest -import m6502 +from m6502 import Memory, Processor @pytest.mark.parametrize( @@ -50,8 +50,8 @@ def test_cpu_ins_inx_imp(value: int, expected: int, flag_z: bool, flag_n: bool) return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_x = value memory[0xFCE2] = 0xE8 diff --git a/tests/test_cpu_ins_iny.py b/tests/test_cpu_ins_iny.py index ecf8ca1..4a0ba6c 100644 --- a/tests/test_cpu_ins_iny.py +++ b/tests/test_cpu_ins_iny.py @@ -34,7 +34,7 @@ """ import pytest -import m6502 +from m6502 import Memory, Processor @pytest.mark.parametrize( @@ -50,8 +50,8 @@ def test_cpu_ins_iny_imp(value: int, expected: int, flag_z: bool, flag_n: bool) return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_y = value memory[0xFCE2] = 0xC8 diff --git a/tests/test_cpu_ins_jmp.py b/tests/test_cpu_ins_jmp.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_cpu_ins_jsr.py b/tests/test_cpu_ins_jsr.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_cpu_ins_lda.py b/tests/test_cpu_ins_lda.py index 65a255b..5e2d4c3 100644 --- a/tests/test_cpu_ins_lda.py +++ b/tests/test_cpu_ins_lda.py @@ -48,7 +48,7 @@ """ import pytest -import m6502 +from m6502 import Memory, Processor def test_cpu_ins_lda_imm() -> None: @@ -57,8 +57,8 @@ def test_cpu_ins_lda_imm() -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_a = 0x00 memory[0xFCE2] = 0xA9 @@ -78,8 +78,8 @@ def test_cpu_ins_lda_zp() -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_a = 0x00 memory[0xFCE2] = 0xA5 @@ -110,8 +110,8 @@ def test_cpu_ins_lda_zpx(reg_x: int, memory_location: int) -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_a = 0x00 cpu.reg_x = reg_x @@ -133,8 +133,8 @@ def test_cpu_ins_lda_abs() -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_a = 0x00 memory[0xFCE2] = 0xAD @@ -158,8 +158,8 @@ def test_cpu_ins_lda_abx() -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_a = 0x00 cpu.reg_x = 0x01 @@ -184,8 +184,8 @@ def test_cpu_ins_lda_aby() -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_a = 0x00 cpu.reg_y = 1 @@ -213,8 +213,8 @@ def test_cpu_ins_lda_inx(reg_x: int, mem_low: int, mem_high: int) -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_a = 0x00 cpu.reg_x = reg_x @@ -240,8 +240,8 @@ def test_cpu_ins_lda_iny() -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_a = 0x00 cpu.reg_y = 0x10 diff --git a/tests/test_cpu_ins_ldx.py b/tests/test_cpu_ins_ldx.py index 108fb37..e375e50 100644 --- a/tests/test_cpu_ins_ldx.py +++ b/tests/test_cpu_ins_ldx.py @@ -42,7 +42,7 @@ """ import pytest -import m6502 +from m6502 import Memory, Processor def test_cpu_ins_ldx_imm() -> None: @@ -51,8 +51,8 @@ def test_cpu_ins_ldx_imm() -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_x = 0x00 memory[0xFCE2] = 0xA2 @@ -72,8 +72,8 @@ def test_cpu_ins_ldx_zp() -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_x = 0x00 memory[0xFCE2] = 0xA6 @@ -104,8 +104,8 @@ def test_cpu_ins_ldx_zpy(reg_y: int, memory_location: int) -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_x = 0x00 cpu.reg_y = reg_y @@ -127,8 +127,8 @@ def test_cpu_ins_ldx_abs() -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_x = 0x00 memory[0xFCE2] = 0xAE @@ -152,8 +152,8 @@ def test_cpu_ins_ldx_aby() -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_x = 0x00 cpu.reg_y = 1 diff --git a/tests/test_cpu_ins_ldy.py b/tests/test_cpu_ins_ldy.py index f359dfa..454ec31 100644 --- a/tests/test_cpu_ins_ldy.py +++ b/tests/test_cpu_ins_ldy.py @@ -42,7 +42,7 @@ """ import pytest -import m6502 +from m6502 import Memory, Processor def test_cpu_ins_ldy_imm() -> None: @@ -51,8 +51,8 @@ def test_cpu_ins_ldy_imm() -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_y = 0x00 memory[0xFCE2] = 0xA0 @@ -72,8 +72,8 @@ def test_cpu_ins_ldy_zp() -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_y = 0x00 memory[0xFCE2] = 0xA4 @@ -104,8 +104,8 @@ def test_cpu_ins_ldy_zpx(reg_x: int, memory_location: int) -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_y = 0x00 cpu.reg_x = reg_x @@ -127,8 +127,8 @@ def test_cpu_ins_ldy_abs() -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_y = 0x00 memory[0xFCE2] = 0xAC @@ -152,8 +152,8 @@ def test_cpu_ins_ldy_abx() -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_y = 0x00 cpu.reg_x = 1 diff --git a/tests/test_cpu_ins_lsr.py b/tests/test_cpu_ins_lsr.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_cpu_ins_nop.py b/tests/test_cpu_ins_nop.py index 1bf5583..6fff7cd 100644 --- a/tests/test_cpu_ins_nop.py +++ b/tests/test_cpu_ins_nop.py @@ -30,7 +30,7 @@ | Implied | 0xEA | 1 | 2 | +-----------------+--------+-------+--------+ """ -import m6502 +from m6502 import Memory, Processor def test_cpu_ins_nop() -> None: @@ -39,8 +39,8 @@ def test_cpu_ins_nop() -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() memory[0xFCE2] = 0xEA cpu.execute(2) diff --git a/tests/test_cpu_ins_ora.py b/tests/test_cpu_ins_ora.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_cpu_ins_pha.py b/tests/test_cpu_ins_pha.py index ef16e98..6f17b2e 100644 --- a/tests/test_cpu_ins_pha.py +++ b/tests/test_cpu_ins_pha.py @@ -31,7 +31,7 @@ See also: PLA """ -import m6502 +from m6502 import Memory, Processor def test_cpu_ins_pha_imp() -> None: @@ -42,8 +42,8 @@ def test_cpu_ins_pha_imp() -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_a = 0xF0 memory[0xFCE2] = 0x48 diff --git a/tests/test_cpu_ins_php.py b/tests/test_cpu_ins_php.py index 97baabd..fe5cba2 100644 --- a/tests/test_cpu_ins_php.py +++ b/tests/test_cpu_ins_php.py @@ -33,7 +33,7 @@ """ import pytest -import m6502 +from m6502 import Memory, Processor @pytest.mark.parametrize( @@ -48,8 +48,8 @@ def test_cpu_ins_php_imp(value: int, flag_n: bool, flag_z: bool) -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() memory[0xFCE2] = 0x08 cpu.flag_z = flag_z diff --git a/tests/test_cpu_ins_pla.py b/tests/test_cpu_ins_pla.py index f9b3dcd..f402be6 100644 --- a/tests/test_cpu_ins_pla.py +++ b/tests/test_cpu_ins_pla.py @@ -32,7 +32,7 @@ See also: PHA """ -import m6502 +from m6502 import Memory, Processor def test_cpu_ins_pla_imp() -> None: @@ -43,8 +43,8 @@ def test_cpu_ins_pla_imp() -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_a = 0x00 cpu.stack_pointer = 0x01FB diff --git a/tests/test_cpu_ins_plp.py b/tests/test_cpu_ins_plp.py index 09e7647..12773a8 100644 --- a/tests/test_cpu_ins_plp.py +++ b/tests/test_cpu_ins_plp.py @@ -34,7 +34,7 @@ """ import pytest -import m6502 +from m6502 import Memory, Processor @pytest.mark.parametrize( @@ -49,8 +49,8 @@ def test_cpu_ins_plp_imp(value: int, flag_n: bool, flag_z: bool) -> None: :return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.memory[0xFCE2] = 0x28 cpu.memory[cpu.stack_pointer] = value diff --git a/tests/test_cpu_ins_rol.py b/tests/test_cpu_ins_rol.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_cpu_ins_ror.py b/tests/test_cpu_ins_ror.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_cpu_ins_rti.py b/tests/test_cpu_ins_rti.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_cpu_ins_sbc.py b/tests/test_cpu_ins_sbc.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_cpu_ins_sec.py b/tests/test_cpu_ins_sec.py index 640cb9d..1dde301 100644 --- a/tests/test_cpu_ins_sec.py +++ b/tests/test_cpu_ins_sec.py @@ -31,7 +31,7 @@ See also: CLC """ -import m6502 +from m6502 import Memory, Processor def test_cpu_ins_sec_imp() -> None: @@ -40,8 +40,8 @@ def test_cpu_ins_sec_imp() -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.flag_c = False memory[0xFCE2] = 0x38 diff --git a/tests/test_cpu_ins_sed.py b/tests/test_cpu_ins_sed.py index 8e05928..8e789e2 100644 --- a/tests/test_cpu_ins_sed.py +++ b/tests/test_cpu_ins_sed.py @@ -31,7 +31,7 @@ See also: CLD """ -import m6502 +from m6502 import Memory, Processor def test_cpu_ins_sed_imp() -> None: @@ -40,8 +40,8 @@ def test_cpu_ins_sed_imp() -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.flag_d = False memory[0xFCE2] = 0xF8 diff --git a/tests/test_cpu_ins_sei.py b/tests/test_cpu_ins_sei.py index d3548f2..b29c871 100644 --- a/tests/test_cpu_ins_sei.py +++ b/tests/test_cpu_ins_sei.py @@ -31,7 +31,7 @@ See also: CLI """ -import m6502 +from m6502 import Memory, Processor def test_cpu_ins_sei_imp() -> None: @@ -40,8 +40,8 @@ def test_cpu_ins_sei_imp() -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.flag_i = False memory[0xFCE2] = 0x78 diff --git a/tests/test_cpu_ins_sta.py b/tests/test_cpu_ins_sta.py index 7c8c985..9f4ad13 100644 --- a/tests/test_cpu_ins_sta.py +++ b/tests/test_cpu_ins_sta.py @@ -45,7 +45,7 @@ """ import pytest -import m6502 +from m6502 import Memory, Processor def test_cpu_ins_sta_zp() -> None: @@ -54,8 +54,8 @@ def test_cpu_ins_sta_zp() -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_a = 0xF0 memory[0xFCE2] = 0x85 @@ -81,8 +81,8 @@ def test_cpu_ins_sta_zpx(reg_x: int, memory_location: int) -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_a = 0xF0 cpu.reg_x = reg_x @@ -104,8 +104,8 @@ def test_cpu_ins_sta_abs() -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_a = 0xF0 memory[0xFCE2] = 0x8D @@ -127,8 +127,8 @@ def test_cpu_ins_sta_abx() -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_a = 0xF0 cpu.reg_x = 0x01 @@ -151,8 +151,8 @@ def test_cpu_ins_sta_aby() -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_a = 0xF0 cpu.reg_y = 0x01 @@ -180,8 +180,8 @@ def test_cpu_ins_sta_inx(reg_x: int, mem_low: int, mem_high: int) -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_a = 0xF0 cpu.reg_x = reg_x @@ -207,8 +207,8 @@ def test_cpu_ins_sta_iny() -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_a = 0xF0 cpu.reg_y = 0x10 diff --git a/tests/test_cpu_ins_stx.py b/tests/test_cpu_ins_stx.py index 763f999..d96b113 100644 --- a/tests/test_cpu_ins_stx.py +++ b/tests/test_cpu_ins_stx.py @@ -37,7 +37,7 @@ """ import pytest -import m6502 +from m6502 import Memory, Processor def test_cpu_ins_stx_zp() -> None: @@ -46,8 +46,8 @@ def test_cpu_ins_stx_zp() -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_x = 0xF0 memory[0xFCE2] = 0x86 @@ -78,8 +78,8 @@ def test_cpu_ins_stx_zpy(reg_y: int, memory_location: int) -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_x = 0xF0 cpu.reg_y = reg_y @@ -101,8 +101,8 @@ def test_cpu_ins_stx_abs() -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_x = 0xF0 memory[0xFCE2] = 0x8E diff --git a/tests/test_cpu_ins_sty.py b/tests/test_cpu_ins_sty.py index 65a709f..6e9d93b 100644 --- a/tests/test_cpu_ins_sty.py +++ b/tests/test_cpu_ins_sty.py @@ -37,7 +37,7 @@ """ import pytest -import m6502 +from m6502 import Memory, Processor def test_cpu_ins_sty_zp() -> None: @@ -46,8 +46,8 @@ def test_cpu_ins_sty_zp() -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_y = 0xF0 memory[0xFCE2] = 0x84 @@ -73,8 +73,8 @@ def test_cpu_ins_sty_zpx(reg_x: int, memory_location: int) -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_y = 0xF0 cpu.reg_x = reg_x @@ -96,8 +96,8 @@ def test_cpu_ins_sty_abs() -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_y = 0xF0 memory[0xFCE2] = 0x8C diff --git a/tests/test_cpu_ins_tax.py b/tests/test_cpu_ins_tax.py index 5e863d5..79150db 100644 --- a/tests/test_cpu_ins_tax.py +++ b/tests/test_cpu_ins_tax.py @@ -36,7 +36,7 @@ """ import pytest -import m6502 +from m6502 import Memory, Processor @pytest.mark.parametrize( @@ -51,8 +51,8 @@ def test_cpu_ins_tax_imm(value: int, flag_n: bool, flag_z: bool) -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_a = value cpu.reg_x = 0x00 diff --git a/tests/test_cpu_ins_tay.py b/tests/test_cpu_ins_tay.py index e8fb155..32f1be9 100644 --- a/tests/test_cpu_ins_tay.py +++ b/tests/test_cpu_ins_tay.py @@ -36,7 +36,7 @@ """ import pytest -import m6502 +from m6502 import Memory, Processor @pytest.mark.parametrize( @@ -51,8 +51,8 @@ def test_cpu_ins_tay_imm(value: int, flag_n: bool, flag_z: bool) -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_a = value cpu.reg_y = 0x00 diff --git a/tests/test_cpu_ins_tsx.py b/tests/test_cpu_ins_tsx.py index 9988857..57d5645 100644 --- a/tests/test_cpu_ins_tsx.py +++ b/tests/test_cpu_ins_tsx.py @@ -36,7 +36,7 @@ """ import pytest -import m6502 +from m6502 import Memory, Processor @pytest.mark.parametrize( @@ -51,8 +51,8 @@ def test_cpu_ins_tsx_imm(value: int, flag_n: bool, flag_z: bool) -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_x = 0x00 memory[0xFCE2] = 0xBA diff --git a/tests/test_cpu_ins_txa.py b/tests/test_cpu_ins_txa.py index f84d0fd..849ebef 100644 --- a/tests/test_cpu_ins_txa.py +++ b/tests/test_cpu_ins_txa.py @@ -36,7 +36,7 @@ """ import pytest -import m6502 +from m6502 import Memory, Processor @pytest.mark.parametrize( @@ -51,8 +51,8 @@ def test_cpu_ins_txa_imm(value: int, flag_n: bool, flag_z: bool) -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_a = 0x00 cpu.reg_x = value diff --git a/tests/test_cpu_ins_txs.py b/tests/test_cpu_ins_txs.py index 395930b..882ed23 100644 --- a/tests/test_cpu_ins_txs.py +++ b/tests/test_cpu_ins_txs.py @@ -35,7 +35,7 @@ """ import pytest -import m6502 +from m6502 import Memory, Processor @pytest.mark.parametrize( @@ -50,8 +50,8 @@ def test_cpu_ins_txs_imm(value: int) -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_x = value memory[0xFCE2] = 0x9A diff --git a/tests/test_cpu_ins_tya.py b/tests/test_cpu_ins_tya.py index ddaa9d7..a391e53 100644 --- a/tests/test_cpu_ins_tya.py +++ b/tests/test_cpu_ins_tya.py @@ -36,7 +36,7 @@ """ import pytest -import m6502 +from m6502 import Memory, Processor @pytest.mark.parametrize( @@ -51,8 +51,8 @@ def test_cpu_ins_tya_imm(value: int, flag_n: bool, flag_z: bool) -> None: return: None """ - memory = m6502.Memory() - cpu = m6502.Processor(memory) + memory = Memory() + cpu = Processor(memory) cpu.reset() cpu.reg_a = 0x00 cpu.reg_y = value diff --git a/tests/test_memory.py b/tests/test_memory.py index 4247ddc..aa470bc 100644 --- a/tests/test_memory.py +++ b/tests/test_memory.py @@ -1,7 +1,7 @@ """Verifies that the memory class works as expected.""" import pytest -import m6502 +from m6502 import Memory, Processor @pytest.mark.parametrize( @@ -18,7 +18,7 @@ def test_init_memory_size(size: int) -> None: :param size: The size of the memory :return: None """ - memory = m6502.Memory(size) # noqa: E302 F841 PLW0612 + memory = Memory(size) # noqa: E302 F841 PLW0612 assert len(memory.memory) == size @@ -37,7 +37,7 @@ def test_init_memory_valueerror(size: int) -> None: :return: None """ with pytest.raises(ValueError, match="Memory size is not valid"): - memory = m6502.Memory(size) # noqa: E302 F841 PLW0612 + memory = Memory(size) # noqa: E302 F841 PLW0612 @pytest.mark.parametrize( @@ -51,7 +51,7 @@ def test_write_zero_page(i: int) -> None: :param i: The address to write to :return: None """ - memory = m6502.Memory() + memory = Memory() memory[i] = 0xA5 assert memory[i] == 0xA5 @@ -67,7 +67,7 @@ def test_write_stack(i: int) -> None: :param i: The address to write to :return: None """ - memory = m6502.Memory() + memory = Memory() memory[i] = 0xA5 assert memory[i] == 0xA5 @@ -84,6 +84,6 @@ def test_write_vector(i: int) -> None: :param i: The address to write to :return: None """ - memory = m6502.Memory() + memory = Memory() memory[i] = 0xA5 assert memory[i] == 0xA5 diff --git a/wiki/6502-Basic-Architecture.md b/wiki/6502-Basic-Architecture.md index 4878b70..18b7680 100644 --- a/wiki/6502-Basic-Architecture.md +++ b/wiki/6502-Basic-Architecture.md @@ -1 +1,6 @@ -The 6502 microprocessor is a relative simple 8-bit CPU with only a few internal registers capable of addressing at most 64Kb of memory via its 16-bit address bus. The processor is little endian and expects addresses to be stored in memory least significant byte first. \ No newline at end of file +# 6502 Basic Architecture + +The 6502 microprocessor is a relative simple 8-bit CPU with only a few internal +registers capable of addressing at most 64Kb of memory via its 16-bit address +bus. The processor is little endian and expects addresses to be stored in +memory least significant byte first. diff --git a/wiki/Addressing-Modes.md b/wiki/Addressing-Modes.md index 1c6851a..76f105e 100644 --- a/wiki/Addressing-Modes.md +++ b/wiki/Addressing-Modes.md @@ -1,6 +1,6 @@ # Addressing Modes -## Implicit +## Implicit ## Accumulator @@ -25,4 +25,3 @@ ## Indexed Indirect ## Indirect Indexed - diff --git a/wiki/Home.md b/wiki/Home.md index ec91104..ea6b60f 100644 --- a/wiki/Home.md +++ b/wiki/Home.md @@ -1,7 +1,21 @@ -Welcome to the python-6502-emulator wiki! +# Welcome to the python-6502-emulator wiki -[Python](https://www.python.org/) is a great language to learn because it is easy to learn and safe to write in. It is also available for Windows, Linux and Mac, and it is free. It is also available on [Raspberry Pi](https://www.raspberrypi.org/) which is targeted for education and testing purposes. This makes computer science easy accessible to everyone. Also for writing a basic emulator to learn how computers work and what they do. The [6502](https://en.m.wikipedia.org/wiki/6502) processor has a very simple design and a small instruction set that makes it easy to learn. +[Python](https://www.python.org/) is a great language to learn because it is +easy to learn and safe to write in. It is also available for Windows, Linux and +Mac, and it is free. It is also available on [Raspberry Pi](https://www.raspberrypi.org/) +which is targeted for education and testing purposes. This makes computer +science easy accessible to everyone. Also for writing a basic emulator to learn +how computers work and what they do. The [6502](https://en.m.wikipedia.org/wiki/6502) +processor has a very simple design and a small instruction set that makes it +easy to learn. -Learning how processors work also gives the possibility to understand why certain applications are so slow and how to optimize them, but also how to start doing security research by writing a fuzzer to find vulnerabilities. Let's start with the basics and write a simple 6502 emulator before we start with the assembly language. +Learning how processors work also gives the possibility to understand why +certain applications are so slow and how to optimize them, but also how to +start doing security research by writing a fuzzer to find vulnerabilities. +Let's start with the basics and write a simple 6502 emulator before we start +with the assembly language. -The [Introduction](#introduction) chapter is mainly based on the **6502 Instruction Set Guide** by [Andrew John Jacobs aka BitWise](https://github.com/andrew-jacobs) and full credit goes to him. Sadly he passed away in 2021 and I copied his work as a reference as his website is no longer available. \ No newline at end of file +The [Introduction](#introduction) chapter is mainly based on the **6502 +Instruction Set Guide** by [Andrew John Jacobs aka BitWise](https://github.com/andrew-jacobs) +and full credit goes to him. Sadly he passed away in 2021 and I copied his work +as a reference as his website is no longer available. diff --git a/wiki/Instruction-Reference.md b/wiki/Instruction-Reference.md index 4cf852e..9b61728 100644 --- a/wiki/Instruction-Reference.md +++ b/wiki/Instruction-Reference.md @@ -2,30 +2,357 @@ ## ADC - Add with Carry +A,Z,C,N = A+M+C + +This instruction adds the contents of a memory location to the accumulator +together with the carry bit. If overflow occurs the carry bit is set, this +enables multiple byte addition to be performed. + +Processor Status after use: + +| Flag | Description | State | +| ---- | ----------------- | ---------------------------- | +| C | Carry Flag | Set if overflow in bit 7 | +| Z | Zero Flag | Set if A = 0 | +| I | Interrupt Disable | Not affected | +| D | Decimal Mode Flag | Not affected | +| B | Break Command | Not affected | +| V | Overflow Flag | Set if sign bit is incorrect | +| N | Negative Flag | Set if bit 7 set | + +| Addressing Mode | Opcode | Bytes | Cycles | +| --------------- | ------ | ----- | ------------------------ | +| Immediate | 0x69 | 2 | 2 | +| Zero Page | 0x65 | 2 | 3 | +| Zero Page,X | 0x75 | 2 | 4 | +| Absolute | 0x6D | 3 | 4 | +| Absolute,X | 0x7D | 3 | 4 (+1 if page crossed) | +| Absolute,Y | 0x79 | 3 | 4 (+1 if page crossed) | +| (Indirect,X) | 0x61 | 2 | 6 | +| (Indirect),Y | 0x71 | 2 | 5 (+1 if page crossed) | + +See also: SBC + ## AND - Logical AND +A,Z,N = A&M + +A logical AND is performed, bit by bit, on the accumulator contents using +the contents of a byte of memory + +Processor Status after use: + +| Flag | Description | State | +| ---- | ----------------- | ---------------- | +| C | Carry Flag | Not affected | +| Z | Zero Flag | Set if A = 0 | +| I | Interrupt Disable | Not affected | +| D | Decimal Mode Flag | Not affected | +| B | Break Command | Not affected | +| V | Overflow Flag | Not affected | +| N | Negative Flag | Set if bit 7 set | + +| Addressing Mode | Opcode | Bytes | Cycles | +| --------------- | ------ | ----- | ------------------------ | +| Immediate | 0x29 | 2 | 2 | +| Zero Page | 0x25 | 2 | 3 | +| Zero Page,X | 0x35 | 2 | 4 | +| Absolute | 0x2D | 3 | 4 | +| Absolute,X | 0x3D | 3 | 4 (+1 if page crossed) | +| Absolute,Y | 0x39 | 3 | 4 (+1 if page crossed) | +| (Indirect,X) | 0x21 | 2 | 6 | +| (Indirect),Y | 0x31 | 2 | 5 (+1 if page crossed) | + +See also: EOR, ORA + ## ASL - Arithmetic Shift Left +ASL - Arithmetic Shift Left. + +A,Z,C,N = A*2 or M,Z,C,N = M*2 + +This instruction adds the contents of a memory location to the accumulator +together with the carry bit. If overflow occurs the carry bit is set, this +enables multiple byte addition to be performed. + +Processor Status after use: + +| Flag | Description | State | +| ---- | ----------------- | --------------------------------- | +| C | Carry Flag | Set to contents of old bit 7 | +| Z | Zero Flag | Set if A = 0 | +| I | Interrupt Disable | Not affected | +| D | Decimal Mode Flag | Not affected | +| B | Break Command | Not affected | +| V | Overflow Flag | Not affected | +| N | Negative Flag | Set if bit 7 of the result is set | + +| Addressing Mode | Opcode | Bytes | Cycles | +| --------------- | ------ | ----- | ------ | +| Accumulator | 0x0A | 1 | 2 | +| Zero Page | 0x06 | 2 | 5 | +| Zero Page,X | 0x16 | 2 | 6 | +| Absolute | 0x0E | 3 | 6 | +| Absolute,X | 0x1E | 3 | 7 | + +See also: LSR, ROL, ROR + ## BCC - Branch if Carry Clear +BCS - Branch if Carry Set. + +If the carry flag is clear then add the relative displacement to the program +to cause a branch to a new location. + +Processor Status after use: + +| Flag | Description | State | +| ---- | ----------------- | --------------------------------- | +| C | Carry Flag | Not affected | +| Z | Zero Flag | Not affected | +| I | Interrupt Disable | Not affected | +| D | Decimal Mode Flag | Not affected | +| B | Break Command | Not affected | +| V | Overflow Flag | Not affected | +| N | Negative Flag | Not affected | + +| Addressing Mode | Opcode | Bytes | Cycles | +| --------------- | ------ | ----- | --------------------------------------------- | +| Relative | 0x90 | 2 | 2 (+1 if branch succeeds +2 if to a new page) | + +See also: BCS + ## BCS - Branch if Carry Set +BCS - Branch if Carry Set. + +If the carry flag is set then add the relative displacement to the program +to cause a branch to a new location. + +Processor Status after use: + +| Flag | Description | State | +| ---- | ----------------- | --------------------------------- | +| C | Carry Flag | Not affected | +| Z | Zero Flag | Not affected | +| I | Interrupt Disable | Not affected | +| D | Decimal Mode Flag | Not affected | +| B | Break Command | Not affected | +| V | Overflow Flag | Not affected | +| N | Negative Flag | Not affected | + +| Addressing Mode | Opcode | Bytes | Cycles | +| --------------- | ------ | ----- | --------------------------------------------- | +| Relative | 0xB0 | 2 | 2 (+1 if branch succeeds +2 if to a new page) | + +See also: BCC + ## BEQ - Branch if Equal +BEQ - Branch if Equal. + +If the zero flag is set then add the relative displacement to the program +to cause a branch to a new location. + +Processor Status after use: + +| Flag | Description | State | +| ---- | ----------------- | --------------------------------- | +| C | Carry Flag | Not affected | +| Z | Zero Flag | Not affected | +| I | Interrupt Disable | Not affected | +| D | Decimal Mode Flag | Not affected | +| B | Break Command | Not affected | +| V | Overflow Flag | Not affected | +| N | Negative Flag | Not affected | + +| Addressing Mode | Opcode | Bytes | Cycles | +| --------------- | ------ | ----- | --------------------------------------------- | +| Relative | 0xF0 | 2 | 2 (+1 if branch succeeds +2 if to a new page) | + +See also: BNE + ## BIT - Bit Test +BIT - Bit Test. + +A & M, N = M7, V = M6 + +This instructions is used to test if one or more bits are set in a target +memory location. The mask pattern in A is ANDed with the value in memory to +set or clear the zero flag, but the result is not kept. Bits 7 and 6 of the +value from memory are copied into the N and V flags. + +Processor Status after use: + +| Flag | Description | State | +| ---- | ----------------- | --------------------------------- | +| C | Carry Flag | Not affected | +| Z | Zero Flag | Not affected | +| I | Interrupt Disable | Not affected | +| D | Decimal Mode Flag | Not affected | +| B | Break Command | Not affected | +| V | Overflow Flag | Not affected | +| N | Negative Flag | Not affected | + +| Addressing Mode | Opcode | Bytes | Cycles | +| --------------- | ------ | ----- | ------------------------- | +| Zero Page | 0x24 | 2 | 3 | +| Absolute | 0x2C | 3 | 4 | + ## BMI - Branch if Minus +BMI - Branch if Minus. + +If the negative flag is set then add the relative displacement to the program +to cause a branch to a new location. + +Processor Status after use: + +| Flag | Description | State | +| ---- | ----------------- | --------------------------------- | +| C | Carry Flag | Not affected | +| Z | Zero Flag | Not affected | +| I | Interrupt Disable | Not affected | +| D | Decimal Mode Flag | Not affected | +| B | Break Command | Not affected | +| V | Overflow Flag | Not affected | +| N | Negative Flag | Not affected | + +| Addressing Mode | Opcode | Bytes | Cycles | +| --------------- | ------ | ----- | --------------------------------------------- | +| Relative | 0x30 | 2 | 2 (+1 if branch succeeds +2 if to a new page) | + +See also: BPL + ## BNE - Branch if Not Equal +BNE - Branch if Not Equal. + +If the zero flag is clear then add the relative displacement to the program +to cause a branch to a new location. + +Processor Status after use: + +| Flag | Description | State | +| ---- | ----------------- | --------------------------------- | +| C | Carry Flag | Not affected | +| Z | Zero Flag | Not affected | +| I | Interrupt Disable | Not affected | +| D | Decimal Mode Flag | Not affected | +| B | Break Command | Not affected | +| V | Overflow Flag | Not affected | +| N | Negative Flag | Not affected | + +| Addressing Mode | Opcode | Bytes | Cycles | +| --------------- | ------ | ----- | --------------------------------------------- | +| Relative | 0xD0 | 2 | 2 (+1 if branch succeeds +2 if to a new page) | + +See also: BEQ + ## BPL - Branch if Positive +BPL - Branch if Positive. + +If the negative flag is clear then add the relative displacement to the program +to cause a branch to a new location. + +Processor Status after use: + +| Flag | Description | State | +| ---- | ----------------- | --------------------------------- | +| C | Carry Flag | Not affected | +| Z | Zero Flag | Not affected | +| I | Interrupt Disable | Not affected | +| D | Decimal Mode Flag | Not affected | +| B | Break Command | Not affected | +| V | Overflow Flag | Not affected | +| N | Negative Flag | Not affected | + +| Addressing Mode | Opcode | Bytes | Cycles | +| --------------- | ------ | ----- | --------------------------------------------- | +| Relative | 0x10 | 2 | 2 (+1 if branch succeeds +2 if to a new page) | + +See also: BMI + ## BRK - Force Interrupt +BRK - Force Interrupt. + +The BRK instruction forces the generation of an interrupt request. The program +counter and processor status are pushed on the stack then the IRQ interrupt at +vector $FFFE/F is loaded into the PC and the break flag in the status set to +one. + +| Flag | Description | State | +| ---- | ----------------- | --------------------------------- | +| C | Carry Flag | Not affected | +| Z | Zero Flag | Not affected | +| I | Interrupt Disable | Not affected | +| D | Decimal Mode Flag | Not affected | +| B | Break Command | Set to 1 | +| V | Overflow Flag | Not affected | +| N | Negative Flag | Not affected | + +| Addressing Mode | Opcode | Bytes | Cycles | +| --------------- | ------ | ----- | ------------------------- | +| Implied | 0x00 | 1 | 7 | + +The interpretation of a BRK depends pn the operating system. On the BBC +Microcomputer it is used by language ROMs to signal run time errors but it +could be used for other purposes (e.g. calling operating system functions, +etc.). + ## BVC - Branch if Overflow Clear +BVC - Branch if Overflow Clear. + +If the overflow flag is clear then add the relative displacement to the program +counter to cause a branch to a new location. + +Processor Status after use: + +| Flag | Description | State | +| ---- | ----------------- | --------------------------------- | +| C | Carry Flag | Not affected | +| Z | Zero Flag | Not affected | +| I | Interrupt Disable | Not affected | +| D | Decimal Mode Flag | Not affected | +| B | Break Command | Not affected | +| V | Overflow Flag | Not affected | +| N | Negative Flag | Not affected | + +| Addressing Mode | Opcode | Bytes | Cycles | +| --------------- | ------ | ----- | --------------------------------------------- | +| Relative | 0x50 | 2 | 2 (+1 if branch succeeds +2 if to a new page) | + +See also: BVS + ## BVS - Branch if Overflow Set +BVS - Branch if Overflow Set. + +If the overflow flag is clear then add the relative displacement to the program +counter to cause a branch to a new location. + +Processor Status after use: + +| Flag | Description | State | +| ---- | ----------------- | --------------------------------- | +| C | Carry Flag | Not affected | +| Z | Zero Flag | Not affected | +| I | Interrupt Disable | Not affected | +| D | Decimal Mode Flag | Not affected | +| B | Break Command | Not affected | +| V | Overflow Flag | Not affected | +| N | Negative Flag | Not affected | + +| Addressing Mode | Opcode | Bytes | Cycles | +| --------------- | ------ | ----- | --------------------------------------------- | +| Relative | 0x70 | 2 | 2 (+1 if branch succeeds +2 if to a new page) | + +See also: BVC + ## CLC - Clear Carry Flag C = 0 @@ -71,7 +398,10 @@ Sets the decimal mode flag to zero. | Implied | 0xD8 | 1 | 2 | NB: -The state of the decimal flag is uncertain when the CPU is powered up and it is not reset when an interrupt is generated. In both cases you should include an explicit CLD to ensure that the flag is cleared before performing addition or subtraction. +The state of the decimal flag is uncertain when the CPU is powered up and it is +not reset when an interrupt is generated. In both cases you should include an +explicit CLD to ensure that the flag is cleared before performing addition or +subtraction. See also: SED @@ -119,10 +449,96 @@ Clears the overflow flag. ## CMP - Compare +CMP - Compare. + +Z,C,N = A-M + +This instruction compares the contents of the accumulator with another memory +held value and sets the zero and carry flags as appropriate. + +Processor Status after use: + +| Flag | Description | State | +| ---- | ----------------- | --------------------------------- | +| C | Carry Flag | Set if A >= M | +| Z | Zero Flag | Set if A = M | +| I | Interrupt Disable | Not affected | +| D | Decimal Mode Flag | Not affected | +| B | Break Command | Not affected | +| V | Overflow Flag | Not affected | +| N | Negative Flag | Set if bit 7 of the result is set | + +| Addressing Mode | Opcode | Bytes | Cycles | +| --------------- | ------ | ----- | ------------------------ | +| Immediate | 0xC9 | 2 | 2 | +| Zero Page | 0xC5 | 2 | 3 | +| Zero Page,X | 0xD5 | 2 | 4 | +| Absolute | 0xCD | 3 | 4 | +| Absolute,X | 0xDD | 3 | 4 (+1 if page crossed) | +| Absolute,Y | 0xD9 | 3 | 4 (+1 if page crossed) | +| (Indirect,X) | 0xC1 | 2 | 6 | +| (Indirect),Y | 0xD1 | 2 | 5 (+1 if page crossed) | + +See also: CPX, CPY + ## CPX - Compare X Register +CPX - Compare X Register. + +Z,C,N = X-M + +This instruction compares the contents of the X register with another memory +held value and sets the zero and carry flags as appropriate. + +Processor Status after use: + +| Flag | Description | State | +| ---- | ----------------- | --------------------------------- | +| C | Carry Flag | Set if X >= M | +| Z | Zero Flag | Set if X = M | +| I | Interrupt Disable | Not affected | +| D | Decimal Mode Flag | Not affected | +| B | Break Command | Not affected | +| V | Overflow Flag | Not affected | +| N | Negative Flag | Set if bit 7 of the result is set | + +| Addressing Mode | Opcode | Bytes | Cycles | +| --------------- | ------ | ----- | ------------------------ | +| Immediate | 0xE0 | 2 | 2 | +| Zero Page | 0xE4 | 2 | 3 | +| Absolute | 0xEC | 3 | 4 | + +See also: CMP, CPY + ## CPY - Compare Y Register +CPY - Compare Y Register. + +Z,C,N = Y-M + +This instruction compares the contents of the Y register with another memory +held value and sets the zero and carry flags as appropriate. + +Processor Status after use: + +| Flag | Description | State | +| ---- | ----------------- | --------------------------------- | +| C | Carry Flag | Set if Y >= M | +| Z | Zero Flag | Set if Y = M | +| I | Interrupt Disable | Not affected | +| D | Decimal Mode Flag | Not affected | +| B | Break Command | Not affected | +| V | Overflow Flag | Not affected | +| N | Negative Flag | Set if bit 7 of the result is set | + +| Addressing Mode | Opcode | Bytes | Cycles | +| --------------- | ------ | ----- | ------------------------ | +| Immediate | 0xC0 | 2 | 2 | +| Zero Page | 0xC4 | 2 | 3 | +| Absolute | 0xCC | 3 | 4 | + +See also: CMP, CPX + ## DEC - Decrement Memory M,Z,N = M-1 diff --git a/wiki/Introduction.md b/wiki/Introduction.md index 3d07efe..e10b99d 100644 --- a/wiki/Introduction.md +++ b/wiki/Introduction.md @@ -1,2 +1 @@ # Introduction - From c219a34e01e1eec0ceeff9d07c884e5e809bc4db Mon Sep 17 00:00:00 2001 From: Hans Spaans Date: Wed, 20 Dec 2023 00:40:37 +0100 Subject: [PATCH 06/11] Update setup.cfg to include pytest-github-actions-annotate-failures --- setup.cfg | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.cfg b/setup.cfg index 94d2b28..9bcf2f9 100644 --- a/setup.cfg +++ b/setup.cfg @@ -45,6 +45,7 @@ deps = pymarkdownlnt pytest>=7,<8 pytest-cov + pytest-github-actions-annotate-failures yamllint commands = pytest --cov=m6502 --cov-report=term-missing tests depends = From bce37f91089874e2a147f8733c1a2f0de05e78c0 Mon Sep 17 00:00:00 2001 From: Hans Spaans Date: Thu, 22 Feb 2024 00:01:47 +0000 Subject: [PATCH 07/11] Update devcontainer image and features --- .devcontainer/devcontainer.json | 29 +++++++---------------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index f7a465a..c9aed54 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,27 +1,12 @@ { - "image": "mcr.microsoft.com/devcontainers/base:debian", + "image": "mcr.microsoft.com/devcontainers/python:1-3.12-bullseye", "features": { - "ghcr.io/devcontainers/features/python:1": { - "installTools": true, - "version": "3.12" - }, - "ghcr.io/devcontainers/features/github-cli:1": { - "installDirectlyFromGitHubRelease": true, - "version": "latest" - }, - "ghcr.io/devcontainers-contrib/features/flake8:2": { - "version": "latest", - "plugins": "flake8-annotations flake8-annotations-complexity flake8-bugbear flake8-deprecated flake8-docstrings flake8-isort flake8-print flake8-pylint flake8-builtins flake8-pytest-style flake8-todo" - }, - "ghcr.io/devcontainers-contrib/features/yamllint:2": { - "version": "latest" - }, - "ghcr.io/devcontainers-contrib/features/tox:2": { - "version": "latest" - }, - "ghcr.io/hspaans/devcontainer-features/pytest:1": { - "version": "latest" - } + "ghcr.io/devcontainers/features/github-cli:1": {}, + "ghcr.io/devcontainers-contrib/features/flake8:2": {}, + "ghcr.io/devcontainers-contrib/features/yamllint:2": {}, + "ghcr.io/devcontainers-contrib/features/tox:2": {}, + "ghcr.io/hspaans/devcontainer-features/pytest:1": {}, + "ghcr.io/hspaans/devcontainer-features/pyupgrade:1": {} }, "customizations": { "vscode": { From da9b5908c867957de8d4830601d464b8d5365a40 Mon Sep 17 00:00:00 2001 From: Hans Spaans Date: Thu, 22 Feb 2024 00:03:37 +0000 Subject: [PATCH 08/11] Rewriting some code with pyupgrade --- m6502/processor.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/m6502/processor.py b/m6502/processor.py index ed9efa7..d5e7627 100644 --- a/m6502/processor.py +++ b/m6502/processor.py @@ -991,7 +991,7 @@ def ins_lda_inx(self) -> None: """ self.reg_a = self.read_byte( self.read_word( - ((self.fetch_byte() + self.reg_x) & 0xFF) + (self.fetch_byte() + self.reg_x) & 0xFF ) ) self.evaluate_flag_z(self.reg_a) @@ -1229,7 +1229,7 @@ def ins_sta_inx(self) -> None: self.write_byte( self.read_byte( self.read_word( - ((self.fetch_byte() + self.reg_x) & 0xFF) + (self.fetch_byte() + self.reg_x) & 0xFF ) ), self.reg_a From e2a4a610df1d2b50f6a9dc295b399179cfd222cd Mon Sep 17 00:00:00 2001 From: Hans Spaans Date: Thu, 22 Feb 2024 00:14:46 +0000 Subject: [PATCH 09/11] Delete test_cpu_in_.rts file --- tests/test_cpu_in_.rts | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tests/test_cpu_in_.rts diff --git a/tests/test_cpu_in_.rts b/tests/test_cpu_in_.rts deleted file mode 100644 index e69de29..0000000 From 713cd45966d80dfed6e7e8d06e3546443aa3d4c0 Mon Sep 17 00:00:00 2001 From: Hans Spaans Date: Thu, 22 Feb 2024 00:34:57 +0000 Subject: [PATCH 10/11] Remove pytest and add postCreateCommand to install pytest --- .devcontainer/devcontainer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index c9aed54..87cae54 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -5,7 +5,6 @@ "ghcr.io/devcontainers-contrib/features/flake8:2": {}, "ghcr.io/devcontainers-contrib/features/yamllint:2": {}, "ghcr.io/devcontainers-contrib/features/tox:2": {}, - "ghcr.io/hspaans/devcontainer-features/pytest:1": {}, "ghcr.io/hspaans/devcontainer-features/pyupgrade:1": {} }, "customizations": { @@ -32,5 +31,6 @@ "python.analysis.inlayHints.pytestParameters": true } } - } + }, + "postCreateCommand": "python -m pip install pytest" } \ No newline at end of file From 9717e6de076fba3b28e1808b703972ab3addf2a3 Mon Sep 17 00:00:00 2001 From: Hans Spaans Date: Sat, 24 Feb 2024 00:06:59 +0000 Subject: [PATCH 11/11] Update devcontainer configuration and editorconfig --- .devcontainer/devcontainer.json | 69 +++++++++++++++++---------------- .editorconfig | 4 -- 2 files changed, 35 insertions(+), 38 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 87cae54..56b8c50 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,36 +1,37 @@ { - "image": "mcr.microsoft.com/devcontainers/python:1-3.12-bullseye", - "features": { - "ghcr.io/devcontainers/features/github-cli:1": {}, - "ghcr.io/devcontainers-contrib/features/flake8:2": {}, - "ghcr.io/devcontainers-contrib/features/yamllint:2": {}, - "ghcr.io/devcontainers-contrib/features/tox:2": {}, - "ghcr.io/hspaans/devcontainer-features/pyupgrade:1": {} - }, - "customizations": { - "vscode": { - "extensions": [ - "EditorConfig.EditorConfig", - "github.vscode-github-actions", - "ms-python.autopep8", - "ms-python.flake8", - "ms-python.vscode-pylance", - "ms-python.python" - ], - "[python]": { - "editor.defaultFormatter": "ms-python.autopep8", - "editor.formatOnSave": true - }, - "settings": { - "python.formatting.provider": "flake8", - "python.testing.pytestArgs": [ - "tests" - ], - "python.testing.unittestEnabled": false, - "python.testing.pytestEnabled": true, - "python.analysis.inlayHints.pytestParameters": true - } - } - }, - "postCreateCommand": "python -m pip install pytest" + "name": "Python", + "image": "mcr.microsoft.com/devcontainers/python:1-3.12-bullseye", + "features": { + "ghcr.io/devcontainers/features/github-cli:1": {}, + "ghcr.io/devcontainers-contrib/features/flake8:2": {}, + "ghcr.io/devcontainers-contrib/features/yamllint:2": {}, + "ghcr.io/devcontainers-contrib/features/tox:2": {}, + "ghcr.io/hspaans/devcontainer-features/pyupgrade:1": {} + }, + "customizations": { + "vscode": { + "extensions": [ + "EditorConfig.EditorConfig", + "github.vscode-github-actions", + "ms-python.vscode-pylance", + "ms-python.python", + "ms-python.autopep8", + "ms-python.flake8" + ], + "[python]": { + "editor.defaultFormatter": "ms-python.autopep8", + "editor.formatOnSave": true + }, + "settings": { + "python.formatting.provider": "flake8", + "python.testing.pytestArgs": [ + "tests" + ], + "python.testing.unittestEnabled": false, + "python.testing.pytestEnabled": true, + "python.analysis.inlayHints.pytestParameters": true + } + } + }, + "postCreateCommand": "python -m pip install pytest" } \ No newline at end of file diff --git a/.editorconfig b/.editorconfig index 1571cd4..f39f0a1 100644 --- a/.editorconfig +++ b/.editorconfig @@ -23,10 +23,6 @@ indent_size = 2 indent_size = 2 insert_final_newline = true -# The JSON files contain newlines inconsistently -[*.json] -indent_size = 2 - # Makefiles always use tabs for indentation [Makefile] indent_style = tab