mos6502 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.gitmodules +3 -0
- data/.rubocop.yml +71 -0
- data/.rubocop_todo.yml +19 -0
- data/.travis.yml +28 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +5 -0
- data/LICENCE +26 -0
- data/README.md +119 -0
- data/Rakefile +19 -0
- data/bin/console +8 -0
- data/bin/setup +6 -0
- data/lib/mos6502.rb +8 -0
- data/lib/mos6502/cpu.rb +143 -0
- data/lib/mos6502/cpu_flags.rb +106 -0
- data/lib/mos6502/cpu_instructions.rb +861 -0
- data/lib/mos6502/cpu_ops.rb +130 -0
- data/lib/mos6502/memory.rb +41 -0
- data/lib/mos6502/version.rb +9 -0
- data/mos6502.gemspec +34 -0
- metadata +132 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e0f60d69f4e61e6400589a302cab4ab6a5c8f3052a302a789b1be82504cd0229
|
4
|
+
data.tar.gz: 022bfe7359508151fc2c0bb3264f0ae3b7b92983480c6ba1bb663975ddd9b14a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5509c6b51da8016c38a3bbadd87763b6532d6e9c4cf6283b78392e6fb08c6c876533a793a3af923ad084e179f0936cfa03b88879947e0abfc9e16a71c231a57c
|
7
|
+
data.tar.gz: e684259a02e6826bafb12e994176dd10feee2f1ea9e2d5f9cf05e07c9ea0ddbfad13c6fa3427cc341103c4609e4ff3c847c16bbb2ee9f246f456adf8da802faf
|
data/.gitignore
ADDED
data/.gitmodules
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require: rubocop-performance
|
2
|
+
inherit_from: .rubocop_todo.yml
|
3
|
+
|
4
|
+
AllCops:
|
5
|
+
TargetRubyVersion: 2.4
|
6
|
+
NewCops: enable
|
7
|
+
|
8
|
+
# Set a slightly bigger default, and ignore ABC failures in the tests.
|
9
|
+
# Also ignore in the CPU instructions files, which are unavoidably big.
|
10
|
+
Metrics/AbcSize:
|
11
|
+
Max: 25
|
12
|
+
Exclude:
|
13
|
+
- 'lib/mos6502/cpu_instructions.rb'
|
14
|
+
- 'lib/mos6502/cpu_ops.rb'
|
15
|
+
- 'test/**/*.rb'
|
16
|
+
|
17
|
+
# Ignore block length failures in the tests.
|
18
|
+
Metrics/BlockLength:
|
19
|
+
Exclude:
|
20
|
+
- 'test/**/*.rb'
|
21
|
+
|
22
|
+
# Ignore class length failures in the tests.
|
23
|
+
# Also ignore in the CPU instructions files, which are unavoidably big.
|
24
|
+
Metrics/ClassLength:
|
25
|
+
Exclude:
|
26
|
+
- 'lib/mos6502/cpu_instructions.rb'
|
27
|
+
- 'lib/mos6502/cpu_ops.rb'
|
28
|
+
- 'test/**/*.rb'
|
29
|
+
|
30
|
+
# Set a slightly higher default for this.
|
31
|
+
# Also ignore the CPU instructions file, which looks complex to this sort
|
32
|
+
# of tool, but isn't really.
|
33
|
+
Metrics/CyclomaticComplexity:
|
34
|
+
Max: 10
|
35
|
+
Exclude:
|
36
|
+
- 'lib/mos6502/cpu_instructions.rb'
|
37
|
+
|
38
|
+
# Ignore method length failures in the tests.
|
39
|
+
# Also ignore in the CPU instructions files, which are unavoidably big.
|
40
|
+
Metrics/MethodLength:
|
41
|
+
Exclude:
|
42
|
+
- 'lib/mos6502/cpu_instructions.rb'
|
43
|
+
- 'lib/mos6502/cpu_ops.rb'
|
44
|
+
- 'test/**/*.rb'
|
45
|
+
|
46
|
+
# Ignore module length failures in the tests.
|
47
|
+
Metrics/ModuleLength:
|
48
|
+
Exclude:
|
49
|
+
- 'test/**/*.rb'
|
50
|
+
|
51
|
+
# Ignore parameter list lengths in the tests.
|
52
|
+
Metrics/ParameterLists:
|
53
|
+
Exclude:
|
54
|
+
- 'test/**/*.rb'
|
55
|
+
|
56
|
+
# Set a slightly higher default for this.
|
57
|
+
# Also ignore the CPU instructions file, which looks complex to this sort
|
58
|
+
# of tool, but isn't really.
|
59
|
+
Metrics/PerceivedComplexity:
|
60
|
+
Max: 10
|
61
|
+
Exclude:
|
62
|
+
- 'lib/mos6502/cpu_instructions.rb'
|
63
|
+
|
64
|
+
# Allow compact child definitions in the tests for brevity.
|
65
|
+
Style/ClassAndModuleChildren:
|
66
|
+
Exclude:
|
67
|
+
- test/**/*.rb
|
68
|
+
|
69
|
+
# Just allow simple formatting rules. We're not doing anything complex.
|
70
|
+
Style/FormatStringToken:
|
71
|
+
EnforcedStyle: unannotated
|
data/.rubocop_todo.yml
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# This configuration was generated by
|
2
|
+
# `rubocop --auto-gen-config`
|
3
|
+
# on 2020-10-08 16:36:35 UTC using RuboCop version 0.93.0.
|
4
|
+
# The point is for the user to remove these configuration records
|
5
|
+
# one by one as the offenses are removed from the code base.
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
8
|
+
|
9
|
+
# Offense count: 1
|
10
|
+
# Cop supports --auto-correct.
|
11
|
+
# Configuration parameters: AllowForAlignment, EnforcedStyleForExponentOperator.
|
12
|
+
# SupportedStylesForExponentOperator: space, no_space
|
13
|
+
Layout/SpaceAroundOperators:
|
14
|
+
Exclude:
|
15
|
+
- 'mos6502.gemspec'
|
16
|
+
|
17
|
+
# Sort this out later :-s.
|
18
|
+
Style/Documentation:
|
19
|
+
Enabled: false
|
data/.travis.yml
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
---
|
2
|
+
dist: bionic
|
3
|
+
language: ruby
|
4
|
+
|
5
|
+
cache: bundler
|
6
|
+
|
7
|
+
before_install: gem install bundler -v 2.1.2
|
8
|
+
|
9
|
+
rvm:
|
10
|
+
- 2.4
|
11
|
+
- 2.5
|
12
|
+
- 2.6
|
13
|
+
- 2.7
|
14
|
+
- ruby-head
|
15
|
+
|
16
|
+
env:
|
17
|
+
- MOS6502_KLAUS2M5=on
|
18
|
+
|
19
|
+
matrix:
|
20
|
+
fast_finish: true
|
21
|
+
include:
|
22
|
+
- name: Rubocop
|
23
|
+
rvm: 2.4
|
24
|
+
script:
|
25
|
+
- bundle info rubocop
|
26
|
+
- bundle exec rubocop
|
27
|
+
allow_failures:
|
28
|
+
- rvm: ruby-head
|
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
2
|
+
|
3
|
+
## Our Pledge
|
4
|
+
|
5
|
+
In the interest of fostering an open and welcoming environment, we as
|
6
|
+
contributors and maintainers pledge to making participation in our project and
|
7
|
+
our community a harassment-free experience for everyone, regardless of age, body
|
8
|
+
size, disability, ethnicity, gender identity and expression, level of experience,
|
9
|
+
nationality, personal appearance, race, religion, or sexual identity and
|
10
|
+
orientation.
|
11
|
+
|
12
|
+
## Our Standards
|
13
|
+
|
14
|
+
Examples of behavior that contributes to creating a positive environment
|
15
|
+
include:
|
16
|
+
|
17
|
+
* Using welcoming and inclusive language
|
18
|
+
* Being respectful of differing viewpoints and experiences
|
19
|
+
* Gracefully accepting constructive criticism
|
20
|
+
* Focusing on what is best for the community
|
21
|
+
* Showing empathy towards other community members
|
22
|
+
|
23
|
+
Examples of unacceptable behavior by participants include:
|
24
|
+
|
25
|
+
* The use of sexualized language or imagery and unwelcome sexual attention or
|
26
|
+
advances
|
27
|
+
* Trolling, insulting/derogatory comments, and personal or political attacks
|
28
|
+
* Public or private harassment
|
29
|
+
* Publishing others' private information, such as a physical or electronic
|
30
|
+
address, without explicit permission
|
31
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
32
|
+
professional setting
|
33
|
+
|
34
|
+
## Our Responsibilities
|
35
|
+
|
36
|
+
Project maintainers are responsible for clarifying the standards of acceptable
|
37
|
+
behavior and are expected to take appropriate and fair corrective action in
|
38
|
+
response to any instances of unacceptable behavior.
|
39
|
+
|
40
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
41
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
42
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
43
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
44
|
+
threatening, offensive, or harmful.
|
45
|
+
|
46
|
+
## Scope
|
47
|
+
|
48
|
+
This Code of Conduct applies both within project spaces and in public spaces
|
49
|
+
when an individual is representing the project or its community. Examples of
|
50
|
+
representing a project or community include using an official project e-mail
|
51
|
+
address, posting via an official social media account, or acting as an appointed
|
52
|
+
representative at an online or offline event. Representation of a project may be
|
53
|
+
further defined and clarified by project maintainers.
|
54
|
+
|
55
|
+
## Enforcement
|
56
|
+
|
57
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
58
|
+
reported by contacting the project team at rhaines@manchester.ac.uk. All
|
59
|
+
complaints will be reviewed and investigated and will result in a response that
|
60
|
+
is deemed necessary and appropriate to the circumstances. The project team is
|
61
|
+
obligated to maintain confidentiality with regard to the reporter of an incident.
|
62
|
+
Further details of specific enforcement policies may be posted separately.
|
63
|
+
|
64
|
+
Project maintainers who do not follow or enforce the Code of Conduct in good
|
65
|
+
faith may face temporary or permanent repercussions as determined by other
|
66
|
+
members of the project's leadership.
|
67
|
+
|
68
|
+
## Attribution
|
69
|
+
|
70
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
71
|
+
available at [https://contributor-covenant.org/version/1/4][version]
|
72
|
+
|
73
|
+
[homepage]: https://contributor-covenant.org
|
74
|
+
[version]: https://contributor-covenant.org/version/1/4/
|
data/Gemfile
ADDED
data/LICENCE
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
MOS 6502 is released under the BSD licence.
|
2
|
+
|
3
|
+
Copyright (c) 2020, Robert Haines
|
4
|
+
All rights reserved.
|
5
|
+
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
8
|
+
* Redistributions of source code must retain the above copyright
|
9
|
+
notice, this list of conditions and the following disclaimer.
|
10
|
+
* Redistributions in binary form must reproduce the above copyright
|
11
|
+
notice, this list of conditions and the following disclaimer in the
|
12
|
+
documentation and/or other materials provided with the distribution.
|
13
|
+
* Neither the name of the OpenMPT project nor the
|
14
|
+
names of its contributors may be used to endorse or promote products
|
15
|
+
derived from this software without specific prior written permission.
|
16
|
+
|
17
|
+
THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY
|
18
|
+
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
19
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
20
|
+
DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
21
|
+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
22
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
23
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
24
|
+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
25
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
26
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
# Ruby MOS 6502
|
2
|
+
|
3
|
+
A ruby implementation of the [MOS Technology 6502 microprocessor][wp-6502].
|
4
|
+
|
5
|
+
![Image of a MOS Technology 6502 microprocessor (from Wikipedia)](https://upload.wikimedia.org/wikipedia/commons/4/49/MOS_6502AD_4585_top.jpg)
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'mos6502'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle install
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install mos6502
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
The entry point to this library is `Mos6502::Cpu`. You can create a new `Cpu` with the program counter (PC) set to a specific memory address as follows:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
cpu = Mos6502::Cpu.new(initial_pc: 0x400)
|
29
|
+
```
|
30
|
+
|
31
|
+
You can load a snippet of code like this:
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
cpu.load!([0xa9, 0x33, 0x69, 0x55])
|
35
|
+
```
|
36
|
+
|
37
|
+
`Cpu#load!` also resets the CPU; all memory is cleared first, then the registers are set to zero, the PC is returned to its initial value, the stack pointer (SP) is reset to `0xff` and the status bits are set to their defaults.
|
38
|
+
|
39
|
+
There is no assembler (yet?). The above code is:
|
40
|
+
|
41
|
+
```
|
42
|
+
LDA #$33 ; load immediate
|
43
|
+
ADC #$55 ; add with carry
|
44
|
+
```
|
45
|
+
|
46
|
+
It will load the hex value `0x33` (51) into the accumulator and add the hex value `0x55` (85) to it and store the result back in the accumulator.
|
47
|
+
|
48
|
+
To run the next instruction, call `Cpu#step`. The PC will be advanced to point to the next instruction. To run the above code, which is just two instructions, use:
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
cpu.step
|
52
|
+
cpu.step
|
53
|
+
```
|
54
|
+
|
55
|
+
You can then inspect the current state of the CPU with:
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
puts cpu.inspect
|
59
|
+
|
60
|
+
# a: 0x88, x: 0x00, y: 0x00, sp: 0xff, pc: 0x0404, op: 0x00, status: 0b11110000
|
61
|
+
```
|
62
|
+
|
63
|
+
You can see here that the accumulator (`a`) holds the result of `0x33` + `0x55` = `0x88` and that the PC has moved on 4 places to `0x404`. You can also see from the status bits that the result is negative in two's complement (bit 7) and that overflow has occurred (bit 6).
|
64
|
+
|
65
|
+
For more complex code, you will need to load in an assembled image:
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
image = File.read(IMAGE_PATH)
|
69
|
+
cpu.load_image!(image, 0x400)
|
70
|
+
```
|
71
|
+
|
72
|
+
You will need to know the entry point, and set the initial PC when initializing the `Cpu` upfront. The above example loads the image at memory location 1024. `Cpu#load_image!` will reset the CPU in the same way as `Cpu#load!` above. If you need to load an image in parts (e.g. assembled code and data) you can use `Cpu#load_image`, which is non-destructive.
|
73
|
+
|
74
|
+
There is loads more information on the 6502, and how to program it here:
|
75
|
+
|
76
|
+
* [Obelisk][obelisk]
|
77
|
+
* [6502.org][6502org]
|
78
|
+
* [Visual 6502][vis6502]
|
79
|
+
|
80
|
+
## Development
|
81
|
+
|
82
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
83
|
+
|
84
|
+
### 6502 test suites
|
85
|
+
|
86
|
+
This repository includes external test suites to more comprehensively test all the features of the 6502 microprocessor. They are not run by default because they can take a few minutes to complete, but can be turned on with environment variables passed into `rake`. Once this code supports all of a test suite's features it will be run by default in CI.
|
87
|
+
|
88
|
+
#### Klaus Dormann's test suite
|
89
|
+
|
90
|
+
This is included as a submodule. Once you've initialized it you can run it as part of the normal test suite with:
|
91
|
+
|
92
|
+
```shell
|
93
|
+
MOS6502_KLAUS2M5=on rake
|
94
|
+
```
|
95
|
+
|
96
|
+
If you want to see a full debug stream of it running, use `MOS6502_KLAUS2M5=debug` instead.
|
97
|
+
|
98
|
+
## Contributing
|
99
|
+
|
100
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/hainesr/mos6502.
|
101
|
+
|
102
|
+
|
103
|
+
## Code of Conduct
|
104
|
+
|
105
|
+
This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct][coc].
|
106
|
+
|
107
|
+
Everyone interacting in the MOS 6502 project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.
|
108
|
+
|
109
|
+
## Licence
|
110
|
+
|
111
|
+
Copyright (c) 2020, Robert Haines.
|
112
|
+
|
113
|
+
Released under the BSD Licence. See LICENCE for details.
|
114
|
+
|
115
|
+
[wp-6502]: https://en.wikipedia.org/wiki/MOS_Technology_6502
|
116
|
+
[coc]: https://github.com/hainesr/mos6502/blob/master/CODE_OF_CONDUCT.md
|
117
|
+
[obelisk]: http://www.obelisk.me.uk/6502/
|
118
|
+
[6502org]: http://www.6502.org/
|
119
|
+
[vis6502]: http://www.visual6502.org/
|
data/Rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2020, Robert Haines.
|
4
|
+
#
|
5
|
+
# Licensed under the BSD License. See LICENCE for details.
|
6
|
+
|
7
|
+
require 'bundler/gem_tasks'
|
8
|
+
require 'rake/testtask'
|
9
|
+
require 'rubocop/rake_task'
|
10
|
+
|
11
|
+
task default: :test
|
12
|
+
|
13
|
+
Rake::TestTask.new(:test) do |t|
|
14
|
+
t.libs << 'test'
|
15
|
+
t.libs << 'lib'
|
16
|
+
t.test_files = FileList['test/**/*_test.rb']
|
17
|
+
end
|
18
|
+
|
19
|
+
RuboCop::RakeTask.new
|
data/bin/console
ADDED
data/bin/setup
ADDED
data/lib/mos6502.rb
ADDED
data/lib/mos6502/cpu.rb
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (c) 2020, Robert Haines.
|
4
|
+
#
|
5
|
+
# Licensed under the BSD License. See LICENCE for details.
|
6
|
+
|
7
|
+
require 'forwardable'
|
8
|
+
|
9
|
+
require_relative 'cpu_flags'
|
10
|
+
require_relative 'cpu_instructions'
|
11
|
+
require_relative 'memory'
|
12
|
+
|
13
|
+
module Mos6502
|
14
|
+
class Cpu
|
15
|
+
extend Forwardable
|
16
|
+
|
17
|
+
attr_reader :a, :pc, :sp, :x, :y
|
18
|
+
|
19
|
+
def_delegators :@status, :break?, :carry?, :decimal_mode?,
|
20
|
+
:interupt_disable?, :negative?, :overflow?, :zero?
|
21
|
+
|
22
|
+
def initialize(initial_pc: 0x600, code: nil)
|
23
|
+
@initial_pc = initial_pc
|
24
|
+
@status = CpuFlags.new
|
25
|
+
load!(code)
|
26
|
+
@instructions = instructions
|
27
|
+
end
|
28
|
+
|
29
|
+
def step
|
30
|
+
inst = next_byte
|
31
|
+
@instructions[inst].call
|
32
|
+
end
|
33
|
+
|
34
|
+
def load!(code = nil)
|
35
|
+
reset!
|
36
|
+
return if code.nil?
|
37
|
+
|
38
|
+
loc = @pc
|
39
|
+
code = code.bytes if code.respond_to?(:bytes)
|
40
|
+
code.each do |b|
|
41
|
+
@memory.set(loc, b)
|
42
|
+
loc += 1
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def load_image(image = nil, start = 0)
|
47
|
+
return if image.nil?
|
48
|
+
|
49
|
+
@memory.load(image, start)
|
50
|
+
end
|
51
|
+
|
52
|
+
def load_image!(image = nil, start = 0)
|
53
|
+
reset!
|
54
|
+
load_image(image, start)
|
55
|
+
end
|
56
|
+
|
57
|
+
def dump_memory(start, length)
|
58
|
+
@memory.dump(start, length)
|
59
|
+
end
|
60
|
+
|
61
|
+
def inspect
|
62
|
+
format(
|
63
|
+
'a: 0x%02x, x: 0x%02x, y: 0x%02x, sp: 0x%02x, ' \
|
64
|
+
'pc: 0x%04x, op: 0x%02x, status: 0b%08b',
|
65
|
+
@a, @x, @y, @sp, @pc, @memory.get(@pc), @status.encode
|
66
|
+
)
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
# Stack access.
|
72
|
+
def stack_push(value)
|
73
|
+
@memory.set((@sp & 0xff) + 0x0100, value)
|
74
|
+
|
75
|
+
# Decrement the stack pointer, and wrap it if it goes below 0.
|
76
|
+
@sp -= 1
|
77
|
+
@sp = @sp &= 0xff if @sp < 0 # rubocop:disable Style/NumericPredicate
|
78
|
+
end
|
79
|
+
|
80
|
+
def stack_pop
|
81
|
+
# Increment the stack pointer, and wrap it if it goes above 255.
|
82
|
+
@sp += 1
|
83
|
+
@sp = @sp &= 0xff if @sp > 0xff
|
84
|
+
|
85
|
+
@memory.get((@sp & 0xff) + 0x0100)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Program access.
|
89
|
+
def next_byte
|
90
|
+
pc = @pc
|
91
|
+
@pc += 1
|
92
|
+
@memory.get(pc)
|
93
|
+
end
|
94
|
+
|
95
|
+
def next_word
|
96
|
+
pc = @pc
|
97
|
+
@pc += 2
|
98
|
+
@memory.get_word(pc)
|
99
|
+
end
|
100
|
+
|
101
|
+
# Memory access.
|
102
|
+
def zero_page(register = 0)
|
103
|
+
(next_byte + register) & 0xff
|
104
|
+
end
|
105
|
+
|
106
|
+
def absolute(register = 0)
|
107
|
+
(next_word + register)
|
108
|
+
end
|
109
|
+
|
110
|
+
def indirect
|
111
|
+
@memory.get_word(next_word)
|
112
|
+
end
|
113
|
+
|
114
|
+
def indexed_indirect
|
115
|
+
@memory.get_word(zero_page(@x))
|
116
|
+
end
|
117
|
+
|
118
|
+
def indirect_indexed
|
119
|
+
@memory.get_word(next_byte) + @y
|
120
|
+
end
|
121
|
+
|
122
|
+
# Status access.
|
123
|
+
def set_nz_flags(value) # rubocop:disable Naming/AccessorMethodName
|
124
|
+
@status.zero = value.zero?
|
125
|
+
@status.negative = value & 0x80
|
126
|
+
end
|
127
|
+
|
128
|
+
def set_carry(value, bit)
|
129
|
+
@status.carry = (value >> bit) & 1
|
130
|
+
end
|
131
|
+
|
132
|
+
# Reset!
|
133
|
+
def reset!
|
134
|
+
@memory = Memory.new
|
135
|
+
@pc = @initial_pc
|
136
|
+
@sp = 0xff
|
137
|
+
@a = 0x00
|
138
|
+
@x = 0x00
|
139
|
+
@y = 0x00
|
140
|
+
@status.reset!
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|