badline 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +40 -0
- data/exe/badline +55 -0
- data/lib/badline/address_bus.rb +206 -0
- data/lib/badline/addressable.rb +61 -0
- data/lib/badline/cartridge/magic_desk.rb +23 -0
- data/lib/badline/cartridge/ocean.rb +33 -0
- data/lib/badline/cartridge/standard.rb +31 -0
- data/lib/badline/cartridge.rb +75 -0
- data/lib/badline/chrout_trap.rb +39 -0
- data/lib/badline/cia/timer.rb +122 -0
- data/lib/badline/cia.rb +189 -0
- data/lib/badline/color_memory.rb +16 -0
- data/lib/badline/computer.rb +100 -0
- data/lib/badline/control_ports.rb +24 -0
- data/lib/badline/cpu.rb +239 -0
- data/lib/badline/cycleable.rb +35 -0
- data/lib/badline/gui/application.rb +94 -0
- data/lib/badline/gui/joy_map.rb +19 -0
- data/lib/badline/gui/key_map.rb +34 -0
- data/lib/badline/gui/palette.rb +35 -0
- data/lib/badline/gui/pane.rb +35 -0
- data/lib/badline/gui/screen_pane.rb +50 -0
- data/lib/badline/gui/window.rb +46 -0
- data/lib/badline/gui.rb +11 -0
- data/lib/badline/instruction.rb +334 -0
- data/lib/badline/instruction_set/arithmetic.rb +119 -0
- data/lib/badline/instruction_set/bitwise.rb +131 -0
- data/lib/badline/instruction_set/branch.rb +78 -0
- data/lib/badline/instruction_set/flag.rb +63 -0
- data/lib/badline/instruction_set/illegal.rb +278 -0
- data/lib/badline/instruction_set/inc_dec.rb +71 -0
- data/lib/badline/instruction_set/stack.rb +104 -0
- data/lib/badline/instruction_set/transfer.rb +137 -0
- data/lib/badline/instruction_set.rb +77 -0
- data/lib/badline/integer_helper.rb +39 -0
- data/lib/badline/joystick.rb +25 -0
- data/lib/badline/kernal_trap/file.rb +54 -0
- data/lib/badline/kernal_trap/load.rb +63 -0
- data/lib/badline/kernal_trap/save.rb +42 -0
- data/lib/badline/kernal_trap.rb +5 -0
- data/lib/badline/keyboard.rb +58 -0
- data/lib/badline/keyboard_buffer.rb +33 -0
- data/lib/badline/media.rb +59 -0
- data/lib/badline/memory.rb +43 -0
- data/lib/badline/rom.rb +23 -0
- data/lib/badline/roms/README +18 -0
- data/lib/badline/roms/basic.rom +0 -0
- data/lib/badline/roms/character.rom +0 -0
- data/lib/badline/roms/kernal.rom +0 -0
- data/lib/badline/sid.rb +25 -0
- data/lib/badline/status.rb +56 -0
- data/lib/badline/storage/crt_file.rb +53 -0
- data/lib/badline/storage/d64_image.rb +21 -0
- data/lib/badline/storage/d71_image.rb +13 -0
- data/lib/badline/storage/d81_image.rb +14 -0
- data/lib/badline/storage/disk_image.rb +71 -0
- data/lib/badline/storage/host_directory.rb +49 -0
- data/lib/badline/storage/p00.rb +24 -0
- data/lib/badline/storage.rb +28 -0
- data/lib/badline/time_of_day.rb +101 -0
- data/lib/badline/traps.rb +15 -0
- data/lib/badline/version.rb +5 -0
- data/lib/badline/vic/bank.rb +65 -0
- data/lib/badline/vic/display_state.rb +78 -0
- data/lib/badline/vic/graphics_mode.rb +139 -0
- data/lib/badline/vic/registers.rb +170 -0
- data/lib/badline/vic/sequencer.rb +237 -0
- data/lib/badline/vic/sprite.rb +121 -0
- data/lib/badline/vic/sprites.rb +112 -0
- data/lib/badline/vic.rb +192 -0
- data/lib/badline.rb +29 -0
- metadata +131 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module InstructionSet
|
|
5
|
+
module Arithmetic
|
|
6
|
+
# Add memory with carry to accumulator.
|
|
7
|
+
#
|
|
8
|
+
# Opcodes:
|
|
9
|
+
# $61 - indirect_x - 6 cycles
|
|
10
|
+
# $65 - zeropage - 3 cycles
|
|
11
|
+
# $69 - immediate - 2 cycles
|
|
12
|
+
# $6D - absolute - 4 cycles
|
|
13
|
+
# $71 - indirect_y - 5+ cycles
|
|
14
|
+
# $75 - zeropage_x - 4 cycles
|
|
15
|
+
# $79 - absolute_y - 4+ cycles
|
|
16
|
+
# $7D - absolute_x - 4+ cycles
|
|
17
|
+
def adc(_addr, value)
|
|
18
|
+
v = resolve(value)
|
|
19
|
+
result = a + v + status.carry
|
|
20
|
+
status.zero = result.nobits?(0xff)
|
|
21
|
+
|
|
22
|
+
if status.decimal?
|
|
23
|
+
result = (a & 0x0f) + (v & 0x0f) + status.carry
|
|
24
|
+
result += 0x06 if result > 0x09
|
|
25
|
+
c = result > 0x0f ? 1 : 0
|
|
26
|
+
result = (a & 0xf0) + (v & 0xf0) + (c << 4) + (result & 0x0f)
|
|
27
|
+
update_calculation_flags(v, result)
|
|
28
|
+
result += 0x60 if result > 0x9f
|
|
29
|
+
else
|
|
30
|
+
update_calculation_flags(v, result)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
status.carry = result > 0xff
|
|
34
|
+
@a = result & 0xff
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Compare memory with accumulator.
|
|
38
|
+
#
|
|
39
|
+
# Opcodes:
|
|
40
|
+
# $C1 - indirect_x - 6 cycles
|
|
41
|
+
# $C5 - zeropage - 3 cycles
|
|
42
|
+
# $C9 - immediate - 2 cycles
|
|
43
|
+
# $CD - absolute - 4 cycles
|
|
44
|
+
# $D1 - indirect_y - 5+ cycles
|
|
45
|
+
# $D5 - zeropage_x - 4 cycles
|
|
46
|
+
# $D9 - absolute_y - 4+ cycles
|
|
47
|
+
# $DD - absolute_x - 4+ cycles
|
|
48
|
+
def cmp(_addr, value)
|
|
49
|
+
v = resolve(value)
|
|
50
|
+
status.carry = (@a >= v)
|
|
51
|
+
update_number_flags(@a - v)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Compare memory with X register.
|
|
55
|
+
#
|
|
56
|
+
# Opcodes:
|
|
57
|
+
# $E0 - immediate - 2 cycles
|
|
58
|
+
# $E4 - zeropage - 3 cycles
|
|
59
|
+
# $EC - absolute - 4 cycles
|
|
60
|
+
def cpx(_addr, value)
|
|
61
|
+
v = resolve(value)
|
|
62
|
+
status.carry = @x >= v
|
|
63
|
+
update_number_flags(@x - v)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Compare memory with Y register.
|
|
67
|
+
#
|
|
68
|
+
# Opcodes:
|
|
69
|
+
# $C0 - immediate - 2 cycles
|
|
70
|
+
# $C4 - zeropage - 3 cycles
|
|
71
|
+
# $CC - absolute - 4 cycles
|
|
72
|
+
def cpy(_addr, value)
|
|
73
|
+
v = resolve(value)
|
|
74
|
+
status.carry = @y >= v
|
|
75
|
+
update_number_flags(@y - v)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Subtract memory from accumulator with borrow.
|
|
79
|
+
#
|
|
80
|
+
# Opcodes:
|
|
81
|
+
# $E1 - indirect_x - 6 cycles
|
|
82
|
+
# $E5 - zeropage - 3 cycles
|
|
83
|
+
# $E9 - immediate - 2 cycles
|
|
84
|
+
# $ED - absolute - 4 cycles
|
|
85
|
+
# $F1 - indirect_y - 5+ cycles
|
|
86
|
+
# $F5 - zeropage_x - 4 cycles
|
|
87
|
+
# $F9 - absolute_y - 4+ cycles
|
|
88
|
+
# $FD - absolute_x - 4+ cycles
|
|
89
|
+
def sbc(_addr, value)
|
|
90
|
+
v = resolve(value)
|
|
91
|
+
v_inv = ~v & 0xff
|
|
92
|
+
carry = status.carry? ? 0 : -1
|
|
93
|
+
|
|
94
|
+
result = a + v_inv + status.carry
|
|
95
|
+
status.zero = result.nobits?(0xff)
|
|
96
|
+
status.carry = result > 0xff
|
|
97
|
+
update_calculation_flags(v_inv, result)
|
|
98
|
+
|
|
99
|
+
if status.decimal?
|
|
100
|
+
al = (a & 0x0f) - (v & 0x0f) + carry
|
|
101
|
+
al = ((al - 0x06) & 0x0F) - 0x10 if al.negative?
|
|
102
|
+
|
|
103
|
+
result = (a & 0xf0) - (v & 0xf0) + al
|
|
104
|
+
result -= 0x60 if result.negative?
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
@a = result & 0xff
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
private
|
|
111
|
+
|
|
112
|
+
def update_calculation_flags(value, result)
|
|
113
|
+
status.negative = result.anybits?(0x80)
|
|
114
|
+
status.overflow = (a ^ value).nobits?(0x80) &&
|
|
115
|
+
(a ^ result).anybits?(0x80)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module InstructionSet
|
|
5
|
+
module Bitwise
|
|
6
|
+
# Performs bitwise AND on accumulator with memory.
|
|
7
|
+
#
|
|
8
|
+
# Opcodes:
|
|
9
|
+
# $21 - indirect_x - 6 cycles
|
|
10
|
+
# $25 - zeropage - 3 cycles
|
|
11
|
+
# $29 - immediate - 2 cycles
|
|
12
|
+
# $2D - absolute - 4 cycles
|
|
13
|
+
# $31 - indirect_y - 5+ cycles
|
|
14
|
+
# $35 - zeropage_x - 4 cycles
|
|
15
|
+
# $39 - absolute_y - 4+ cycles
|
|
16
|
+
# $3D - absolute_x - 4+ cycles
|
|
17
|
+
def and(_addr, value)
|
|
18
|
+
@a &= resolve(value)
|
|
19
|
+
update_number_flags(@a)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Arithmetic shift left. Shifts bits left by one position.
|
|
23
|
+
#
|
|
24
|
+
# Opcodes:
|
|
25
|
+
# $06 - zeropage - 5 cycles
|
|
26
|
+
# $0A - accumulator- 2 cycles
|
|
27
|
+
# $0E - absolute - 6 cycles
|
|
28
|
+
# $16 - zeropage_x - 6 cycles
|
|
29
|
+
# $1E - absolute_x - 7 cycles
|
|
30
|
+
def asl(addr, value)
|
|
31
|
+
v = resolve(value)
|
|
32
|
+
result = (v << 1) & 0xff
|
|
33
|
+
status.carry = v[7]
|
|
34
|
+
write_modified(addr, v, result)
|
|
35
|
+
update_number_flags(result)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Tests bits in memory with accumulator.
|
|
39
|
+
#
|
|
40
|
+
# Opcodes:
|
|
41
|
+
# $24 - zeropage - 3 cycles
|
|
42
|
+
# $2C - absolute - 4 cycles
|
|
43
|
+
def bit(_addr, value)
|
|
44
|
+
v = resolve(value)
|
|
45
|
+
status.value = ((status.value & 0b00111111) +
|
|
46
|
+
(v & 0b11000000)).to_i
|
|
47
|
+
status.zero = (a & v).nobits?(0xff)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Performs bitwise XOR on accumulator with memory.
|
|
51
|
+
#
|
|
52
|
+
# Opcodes:
|
|
53
|
+
# $41 - indirect_x - 6 cycles
|
|
54
|
+
# $45 - zeropage - 3 cycles
|
|
55
|
+
# $49 - immediate - 2 cycles
|
|
56
|
+
# $4D - absolute - 4 cycles
|
|
57
|
+
# $51 - indirect_y - 5+ cycles
|
|
58
|
+
# $55 - zeropage_x - 4 cycles
|
|
59
|
+
# $59 - absolute_y - 4+ cycles
|
|
60
|
+
# $5D - absolute_x - 4+ cycles
|
|
61
|
+
def eor(_addr, value)
|
|
62
|
+
@a = (@a ^ resolve(value)) & 0xff
|
|
63
|
+
update_number_flags(@a)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Logical shift right. Shifts bits right by one position.
|
|
67
|
+
#
|
|
68
|
+
# Opcodes:
|
|
69
|
+
# $46 - zeropage - 5 cycles
|
|
70
|
+
# $4A - accumulator- 2 cycles
|
|
71
|
+
# $4E - absolute - 6 cycles
|
|
72
|
+
# $56 - zeropage_x - 6 cycles
|
|
73
|
+
# $5E - absolute_x - 7 cycles
|
|
74
|
+
def lsr(addr, value)
|
|
75
|
+
v = resolve(value)
|
|
76
|
+
result = (v >> 1) & 0xff
|
|
77
|
+
status.carry = v[0]
|
|
78
|
+
write_modified(addr, v, result)
|
|
79
|
+
update_number_flags(result)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Performs bitwise OR on accumulator with memory.
|
|
83
|
+
#
|
|
84
|
+
# Opcodes:
|
|
85
|
+
# $01 - indirect_x - 6 cycles
|
|
86
|
+
# $05 - zeropage - 3 cycles
|
|
87
|
+
# $09 - immediate - 2 cycles
|
|
88
|
+
# $0D - absolute - 4 cycles
|
|
89
|
+
# $11 - indirect_y - 5+ cycles
|
|
90
|
+
# $15 - zeropage_x - 4 cycles
|
|
91
|
+
# $19 - absolute_y - 4+ cycles
|
|
92
|
+
# $1D - absolute_x - 4+ cycles
|
|
93
|
+
def ora(_addr, value)
|
|
94
|
+
@a |= resolve(value)
|
|
95
|
+
update_number_flags(@a)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Rotate left through carry.
|
|
99
|
+
#
|
|
100
|
+
# Opcodes:
|
|
101
|
+
# $26 - zeropage - 5 cycles
|
|
102
|
+
# $2A - accumulator- 2 cycles
|
|
103
|
+
# $2E - absolute - 6 cycles
|
|
104
|
+
# $36 - zeropage_x - 6 cycles
|
|
105
|
+
# $3E - absolute_x - 7 cycles
|
|
106
|
+
def rol(addr, value)
|
|
107
|
+
v = resolve(value)
|
|
108
|
+
result = ((v << 1) + status.carry) & 0xff
|
|
109
|
+
status.carry = v[7]
|
|
110
|
+
write_modified(addr, v, result)
|
|
111
|
+
update_number_flags(result)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Rotate right through carry.
|
|
115
|
+
#
|
|
116
|
+
# Opcodes:
|
|
117
|
+
# $66 - zeropage - 5 cycles
|
|
118
|
+
# $6A - accumulator- 2 cycles
|
|
119
|
+
# $6E - absolute - 6 cycles
|
|
120
|
+
# $76 - zeropage_x - 6 cycles
|
|
121
|
+
# $7E - absolute_x - 7 cycles
|
|
122
|
+
def ror(addr, value)
|
|
123
|
+
v = resolve(value)
|
|
124
|
+
result = ((v >> 1) + (status.carry? ? 0x80 : 0)) & 0xff
|
|
125
|
+
status.carry = v[0]
|
|
126
|
+
write_modified(addr, v, result)
|
|
127
|
+
update_number_flags(result)
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module InstructionSet
|
|
5
|
+
module Branch
|
|
6
|
+
# Branch if carry clear (C=0).
|
|
7
|
+
#
|
|
8
|
+
# Opcodes:
|
|
9
|
+
# $90 - relative - 2+ cycles
|
|
10
|
+
def bcc(addr, _value)
|
|
11
|
+
branch(addr) unless status.carry?
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Branch if carry set (C=1).
|
|
15
|
+
#
|
|
16
|
+
# Opcodes:
|
|
17
|
+
# $B0 - relative - 2+ cycles
|
|
18
|
+
def bcs(addr, _value)
|
|
19
|
+
branch(addr) if status.carry?
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Branch if equal (Z=1).
|
|
23
|
+
#
|
|
24
|
+
# Opcodes:
|
|
25
|
+
# $F0 - relative - 2+ cycles
|
|
26
|
+
def beq(addr, _value)
|
|
27
|
+
branch(addr) if status.zero?
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Branch if minus (N=1).
|
|
31
|
+
#
|
|
32
|
+
# Opcodes:
|
|
33
|
+
# $30 - relative - 2+ cycles
|
|
34
|
+
def bmi(addr, _value)
|
|
35
|
+
branch(addr) if status.negative?
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Branch if not equal (Z=0).
|
|
39
|
+
#
|
|
40
|
+
# Opcodes:
|
|
41
|
+
# $D0 - relative - 2+ cycles
|
|
42
|
+
def bne(addr, _value)
|
|
43
|
+
branch(addr) unless status.zero?
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Branch if plus (N=0).
|
|
47
|
+
#
|
|
48
|
+
# Opcodes:
|
|
49
|
+
# $10 - relative - 2+ cycles
|
|
50
|
+
def bpl(addr, _value)
|
|
51
|
+
branch(addr) unless status.negative?
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Branch if overflow clear (V=0).
|
|
55
|
+
#
|
|
56
|
+
# Opcodes:
|
|
57
|
+
# $50 - relative - 2+ cycles
|
|
58
|
+
def bvc(addr, _value)
|
|
59
|
+
branch(addr) unless status.overflow?
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Branch if overflow set (V=1).
|
|
63
|
+
#
|
|
64
|
+
# Opcodes:
|
|
65
|
+
# $70 - relative - 2+ cycles
|
|
66
|
+
def bvs(addr, _value)
|
|
67
|
+
branch(addr) if status.overflow?
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
def branch(addr)
|
|
73
|
+
cycle if high_byte(addr) != high_byte(@program_counter)
|
|
74
|
+
cycle { @program_counter = addr }
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module InstructionSet
|
|
5
|
+
module Flag
|
|
6
|
+
# Clear carry flag.
|
|
7
|
+
#
|
|
8
|
+
# Opcodes:
|
|
9
|
+
# $18 - implied - 2 cycles
|
|
10
|
+
def clc(_addr, _value)
|
|
11
|
+
cycle { status.carry = false }
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Clear decimal mode flag.
|
|
15
|
+
#
|
|
16
|
+
# Opcodes:
|
|
17
|
+
# $D8 - implied - 2 cycles
|
|
18
|
+
def cld(_addr, _value)
|
|
19
|
+
cycle { status.decimal = false }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Clear interrupt disable flag.
|
|
23
|
+
#
|
|
24
|
+
# Opcodes:
|
|
25
|
+
# $58 - implied - 2 cycles
|
|
26
|
+
def cli(_addr, _value)
|
|
27
|
+
cycle { status.interrupt = false }
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Clear overflow flag.
|
|
31
|
+
#
|
|
32
|
+
# Opcodes:
|
|
33
|
+
# $B8 - implied - 2 cycles
|
|
34
|
+
def clv(_addr, _value)
|
|
35
|
+
cycle { status.overflow = false }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Set carry flag.
|
|
39
|
+
#
|
|
40
|
+
# Opcodes:
|
|
41
|
+
# $38 - implied - 2 cycles
|
|
42
|
+
def sec(_addr, _value)
|
|
43
|
+
cycle { status.carry = true }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Set decimal mode flag.
|
|
47
|
+
#
|
|
48
|
+
# Opcodes:
|
|
49
|
+
# $F8 - implied - 2 cycles
|
|
50
|
+
def sed(_addr, _value)
|
|
51
|
+
cycle { status.decimal = true }
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Set interrupt disable flag.
|
|
55
|
+
#
|
|
56
|
+
# Opcodes:
|
|
57
|
+
# $78 - implied - 2 cycles
|
|
58
|
+
def sei(_addr, _value)
|
|
59
|
+
cycle { status.interrupt = true }
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Badline
|
|
4
|
+
module InstructionSet
|
|
5
|
+
# Illegal opcodes
|
|
6
|
+
module Illegal
|
|
7
|
+
# Combination of AND and LSR.
|
|
8
|
+
#
|
|
9
|
+
# Opcodes:
|
|
10
|
+
# $4B - immediate - 2 cycles
|
|
11
|
+
def alr(_addr, value)
|
|
12
|
+
@a &= resolve(value)
|
|
13
|
+
status.carry = @a[0]
|
|
14
|
+
@a = (@a >> 1) & 0xff
|
|
15
|
+
update_number_flags(@a)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Combination of AND where carry is set to bit 7 of result.
|
|
19
|
+
#
|
|
20
|
+
# Opcodes:
|
|
21
|
+
# $0B, $2B - immediate - 2 cycles
|
|
22
|
+
def anc(addr, value)
|
|
23
|
+
self.and(addr, value)
|
|
24
|
+
status.carry = status.negative
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Unstable instruction. AND's value with A|magic_const and X.
|
|
28
|
+
# Magic constant varies by CPU.
|
|
29
|
+
#
|
|
30
|
+
# Opcodes:
|
|
31
|
+
# $8B - immediate - 2 cycles
|
|
32
|
+
def ane(_addr, value)
|
|
33
|
+
magic_const = 0xee
|
|
34
|
+
@a = (a | magic_const) & x & resolve(value)
|
|
35
|
+
update_number_flags(@a)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Combination of AND and ROR.
|
|
39
|
+
#
|
|
40
|
+
# Opcodes:
|
|
41
|
+
# $6B - immediate - 2 cycles
|
|
42
|
+
def arr(_addr, value)
|
|
43
|
+
tmp = a & resolve(value)
|
|
44
|
+
result = (tmp >> 1) | (status.carry? ? 0x80 : 0)
|
|
45
|
+
status.zero = result.zero?
|
|
46
|
+
status.negative = status.carry
|
|
47
|
+
|
|
48
|
+
if status.decimal?
|
|
49
|
+
status.overflow = (result ^ tmp).anybits?(0x40)
|
|
50
|
+
|
|
51
|
+
# Low nibble
|
|
52
|
+
result = (result & 0xf0) | ((result + 0x06) & 0x0f) if ((tmp & 0x0f) + (tmp & 0x01)) > 0x05
|
|
53
|
+
|
|
54
|
+
# High nibble + carry
|
|
55
|
+
if ((tmp & 0xf0) + (tmp & 0x10)) > 0x50
|
|
56
|
+
result = (result & 0x0f) | ((result + 0x60) & 0xf0)
|
|
57
|
+
status.carry = true
|
|
58
|
+
else
|
|
59
|
+
status.carry = false
|
|
60
|
+
end
|
|
61
|
+
else
|
|
62
|
+
status.carry = tmp[7] == 1
|
|
63
|
+
status.overflow = tmp[7] ^ tmp[6]
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
@a = result
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Combination of DEC and CMP operations.
|
|
70
|
+
#
|
|
71
|
+
# Opcodes:
|
|
72
|
+
# $C3 - indirect_x - 8 cycles
|
|
73
|
+
# $C7 - zeropage - 5 cycles
|
|
74
|
+
# $CF - absolute - 6 cycles
|
|
75
|
+
# $D3 - indirect_y - 8 cycles
|
|
76
|
+
# $D7 - zeropage_x - 6 cycles
|
|
77
|
+
# $DB - absolute_y - 7 cycles
|
|
78
|
+
# $DF - absolute_x - 7 cycles
|
|
79
|
+
def dcp(addr, value)
|
|
80
|
+
cmp(addr, dec(addr, value))
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Combination of INC and SBC operations.
|
|
84
|
+
#
|
|
85
|
+
# Opcodes:
|
|
86
|
+
# $E3 - indirect_x - 8 cycles
|
|
87
|
+
# $E7 - zeropage - 5 cycles
|
|
88
|
+
# $EF - absolute - 6 cycles
|
|
89
|
+
# $F3 - indirect_y - 8 cycles
|
|
90
|
+
# $F7 - zeropage_x - 6 cycles
|
|
91
|
+
# $FB - absolute_y - 7 cycles
|
|
92
|
+
# $FF - absolute_x - 7 cycles
|
|
93
|
+
def isc(addr, value)
|
|
94
|
+
sbc(addr, inc(addr, value))
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Freezes the CPU by forcing an infinite loop.
|
|
98
|
+
#
|
|
99
|
+
# Opcodes:
|
|
100
|
+
# $02, $12, $22, $32, $42, $52, $62, $72, $92, $B2, $D2, $F2
|
|
101
|
+
def jam(_addr, _value)
|
|
102
|
+
# TODO: Handle jam
|
|
103
|
+
# It is possible to implement with loop { cycle }, but makes
|
|
104
|
+
# testing problematic.
|
|
105
|
+
10.times { cycle }
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Loads A and S with value AND stack pointer.
|
|
109
|
+
#
|
|
110
|
+
# Opcodes:
|
|
111
|
+
# $BB - absolute_y - 4 cycles
|
|
112
|
+
def las(_addr, value)
|
|
113
|
+
@a = @x = @stack_pointer = resolve(value) & stack_pointer
|
|
114
|
+
update_number_flags(@a)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Combination of LDA and LDX with same value.
|
|
118
|
+
#
|
|
119
|
+
# Opcodes:
|
|
120
|
+
# $A3 - indirect_x - 6 cycles
|
|
121
|
+
# $A7 - zeropage - 3 cycles
|
|
122
|
+
# $AF - absolute - 4 cycles
|
|
123
|
+
# $B3 - indirect_y - 5+ cycles
|
|
124
|
+
# $B7 - zeropage_y - 4 cycles
|
|
125
|
+
# $BF - absolute_y - 4+ cycles
|
|
126
|
+
def lax(_addr, value)
|
|
127
|
+
@a = @x = resolve(value)
|
|
128
|
+
|
|
129
|
+
update_number_flags(@a)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Unstable immediate form of LAX. Loads A and X with
|
|
133
|
+
# (A | magic_const) AND value. Magic constant varies by CPU.
|
|
134
|
+
#
|
|
135
|
+
# Opcodes:
|
|
136
|
+
# $AB - immediate - 2 cycles
|
|
137
|
+
def lxa(_addr, value)
|
|
138
|
+
magic_const = 0xee
|
|
139
|
+
@a = @x = (a | magic_const) & resolve(value)
|
|
140
|
+
update_number_flags(@a)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Special no-operation instruction that does not consume a CPU cycle,
|
|
144
|
+
# unlike the standard NOP. Used by some illegal opcodes.
|
|
145
|
+
#
|
|
146
|
+
# Opcodes:
|
|
147
|
+
# $80, $82, $89, $C2, $E2 - immediate - 2 cycles
|
|
148
|
+
def nop_nocycle(_addr, _value); end
|
|
149
|
+
|
|
150
|
+
# Combination of ROL and AND operations.
|
|
151
|
+
#
|
|
152
|
+
# Opcodes:
|
|
153
|
+
# $23 - indirect_x - 8 cycles
|
|
154
|
+
# $27 - zeropage - 5 cycles
|
|
155
|
+
# $2F - absolute - 6 cycles
|
|
156
|
+
# $33 - indirect_y - 8 cycles
|
|
157
|
+
# $37 - zeropage_x - 6 cycles
|
|
158
|
+
# $3B - absolute_y - 7 cycles
|
|
159
|
+
# $3F - absolute_x - 7 cycles
|
|
160
|
+
def rla(addr, value)
|
|
161
|
+
self.and(addr, rol(addr, value))
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# Combination of ROR and ADC operations.
|
|
165
|
+
#
|
|
166
|
+
# Opcodes:
|
|
167
|
+
# $63 - indirect_x - 8 cycles
|
|
168
|
+
# $67 - zeropage - 5 cycles
|
|
169
|
+
# $6F - absolute - 6 cycles
|
|
170
|
+
# $73 - indirect_y - 8 cycles
|
|
171
|
+
# $77 - zeropage_x - 6 cycles
|
|
172
|
+
# $7B - absolute_y - 7 cycles
|
|
173
|
+
# $7F - absolute_x - 7 cycles
|
|
174
|
+
def rra(addr, value)
|
|
175
|
+
adc(addr, ror(addr, value))
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Store A AND X.
|
|
179
|
+
#
|
|
180
|
+
# Opcodes:
|
|
181
|
+
# $83 - indirect_x - 6 cycles
|
|
182
|
+
# $87 - zeropage - 3 cycles
|
|
183
|
+
# $8F - absolute - 4 cycles
|
|
184
|
+
# $97 - zeropage_y - 4 cycles
|
|
185
|
+
def sax(addr, _value)
|
|
186
|
+
write_byte(addr, @a & @x)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# AND X register with accumulator and subtract value.
|
|
190
|
+
#
|
|
191
|
+
# Opcodes:
|
|
192
|
+
# $CB - immediate - 2 cycles
|
|
193
|
+
def sbx(_addr, value)
|
|
194
|
+
v = resolve(value)
|
|
195
|
+
result = (@x & @a) - v
|
|
196
|
+
status.carry = result >= 0
|
|
197
|
+
@x = result & 0xff
|
|
198
|
+
update_number_flags(@x)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
# Stores A AND X AND (high byte of base address + 1) at addr.
|
|
202
|
+
#
|
|
203
|
+
# Opcodes:
|
|
204
|
+
# $93 - indirect_y - 6 cycles
|
|
205
|
+
# $9F - absolute_y - 5 cycles
|
|
206
|
+
def sha(addr, _value)
|
|
207
|
+
store_high_and(a & x, addr)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# Stores X AND (high byte of base address + 1) at addr.
|
|
211
|
+
#
|
|
212
|
+
# Opcodes:
|
|
213
|
+
# $9E - absolute_y - 5 cycles
|
|
214
|
+
def shx(addr, _value)
|
|
215
|
+
store_high_and(x, addr)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# Stores Y AND (high byte of base address + 1) at addr.
|
|
219
|
+
#
|
|
220
|
+
# Opcodes:
|
|
221
|
+
# $9C - absolute_x - 5 cycles
|
|
222
|
+
def shy(addr, _value)
|
|
223
|
+
store_high_and(y, addr)
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
# Combination of ASL and ORA operations.
|
|
227
|
+
#
|
|
228
|
+
# Opcodes:
|
|
229
|
+
# $03 - indirect_x - 8 cycles
|
|
230
|
+
# $07 - zeropage - 5 cycles
|
|
231
|
+
# $0F - absolute - 6 cycles
|
|
232
|
+
# $13 - indirect_y - 8 cycles
|
|
233
|
+
# $17 - zeropage_x - 6 cycles
|
|
234
|
+
# $1B - absolute_y - 7 cycles
|
|
235
|
+
# $1F - absolute_x - 7 cycles
|
|
236
|
+
def slo(addr, value)
|
|
237
|
+
ora(addr, asl(addr, value))
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# Combination of LSR and EOR operations.
|
|
241
|
+
#
|
|
242
|
+
# Opcodes:
|
|
243
|
+
# $43 - indirect_x - 8 cycles
|
|
244
|
+
# $47 - zeropage - 5 cycles
|
|
245
|
+
# $4F - absolute - 6 cycles
|
|
246
|
+
# $53 - indirect_y - 8 cycles
|
|
247
|
+
# $57 - zeropage_x - 6 cycles
|
|
248
|
+
# $5B - absolute_y - 7 cycles
|
|
249
|
+
# $5F - absolute_x - 7 cycles
|
|
250
|
+
def sre(addr, value)
|
|
251
|
+
eor(addr, lsr(addr, value))
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
# Stores A AND X in SP, then stores SP AND (high byte of base + 1) at
|
|
255
|
+
# addr.
|
|
256
|
+
#
|
|
257
|
+
# Opcodes:
|
|
258
|
+
# $9B - absolute_y - 5 cycles
|
|
259
|
+
def tas(addr, _value)
|
|
260
|
+
@stack_pointer = @a & @x
|
|
261
|
+
store_high_and(stack_pointer, addr)
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
private
|
|
265
|
+
|
|
266
|
+
def store_high_and(register, addr)
|
|
267
|
+
base_high = if boundary_crossed
|
|
268
|
+
(high_byte(addr) - 1) & 0xff
|
|
269
|
+
else
|
|
270
|
+
high_byte(addr)
|
|
271
|
+
end
|
|
272
|
+
result = register & ((base_high + 1) & 0xff)
|
|
273
|
+
target = boundary_crossed ? uint16(low_byte(addr), result) : addr
|
|
274
|
+
write_byte(target, result)
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
end
|
|
278
|
+
end
|