n65 0.5.0 → 1.0.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.
Files changed (64) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data/.github/workflows/ci.yml +28 -0
  4. data/.gitignore +1 -1
  5. data/.rubocop.yml +125 -0
  6. data/Gemfile +3 -1
  7. data/README.md +3 -20
  8. data/Rakefile +15 -1
  9. data/bin/n65 +2 -0
  10. data/data/opcodes.yaml +39 -39
  11. data/everdrive_transfer/everdrive.rb +175 -0
  12. data/examples/pulse_chord.asm +1 -1
  13. data/examples/scales.asm +182 -0
  14. data/lib/n65/directives/ascii.rb +4 -19
  15. data/lib/n65/directives/bytes.rb +20 -35
  16. data/lib/n65/directives/dw.rb +22 -36
  17. data/lib/n65/directives/enter_scope.rb +14 -30
  18. data/lib/n65/directives/exit_scope.rb +7 -17
  19. data/lib/n65/directives/inc.rb +14 -30
  20. data/lib/n65/directives/incbin.rb +6 -24
  21. data/lib/n65/directives/ines_header.rb +66 -27
  22. data/lib/n65/directives/label.rb +8 -21
  23. data/lib/n65/directives/org.rb +9 -19
  24. data/lib/n65/directives/segment.rb +5 -19
  25. data/lib/n65/directives/space.rb +6 -18
  26. data/lib/n65/front_end.rb +36 -39
  27. data/lib/n65/instruction.rb +123 -159
  28. data/lib/n65/instruction_base.rb +6 -18
  29. data/lib/n65/memory_space.rb +51 -71
  30. data/lib/n65/opcodes.rb +3 -5
  31. data/lib/n65/parser.rb +20 -38
  32. data/lib/n65/regexes.rb +20 -21
  33. data/lib/n65/symbol_table.rb +58 -89
  34. data/lib/n65/version.rb +3 -1
  35. data/lib/n65.rb +120 -121
  36. data/n65.gemspec +17 -12
  37. data/nes_lib/nes.sym +2 -2
  38. data/spec/.rubocop.yml +4 -0
  39. data/spec/assembler_spec.rb +84 -0
  40. data/spec/lib/n65/memory_space_spec.rb +147 -0
  41. data/spec/lib/n65/symbol_table_spec.rb +291 -0
  42. data/utils/opcode_table_to_yaml.rb +65 -67
  43. data.tar.gz.sig +0 -0
  44. metadata +84 -41
  45. metadata.gz.sig +0 -0
  46. data/examples/music_driver.asm +0 -202
  47. data/test/test_memory_space.rb +0 -82
  48. data/test/test_symbol_table.rb +0 -238
  49. data/utils/midi/Makefile +0 -3
  50. data/utils/midi/c_scale.mid +0 -0
  51. data/utils/midi/convert +0 -0
  52. data/utils/midi/guitar.mid +0 -0
  53. data/utils/midi/include/event.h +0 -93
  54. data/utils/midi/include/file.h +0 -57
  55. data/utils/midi/include/helpers.h +0 -14
  56. data/utils/midi/include/track.h +0 -45
  57. data/utils/midi/lil_melody.mid +0 -0
  58. data/utils/midi/mi_feabhra.mid +0 -0
  59. data/utils/midi/midi_to_nes.rb +0 -204
  60. data/utils/midi/source/convert.cpp +0 -16
  61. data/utils/midi/source/event.cpp +0 -96
  62. data/utils/midi/source/file.cpp +0 -37
  63. data/utils/midi/source/helpers.cpp +0 -46
  64. data/utils/midi/source/track.cpp +0 -37
@@ -0,0 +1,175 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'libusb'
4
+ require 'date'
5
+
6
+ class EverdriveIO
7
+ class DeviceNotFound < StandardError; end
8
+
9
+ def initialize(vendor, product)
10
+ @device = find_device(vendor, product)
11
+ @input, @output = find_bulk_endpoints(device)
12
+ @handle = device.open
13
+ handle.claim_interface(input.interface)
14
+ end
15
+
16
+ def inspect
17
+ "#<#{self.class.name}: #{device.inspect}>"
18
+ end
19
+
20
+ def close
21
+ handle.close
22
+ end
23
+
24
+ def read(length)
25
+ handle.bulk_transfer(endpoint: input, dataIn: length)
26
+ end
27
+
28
+ def write(data)
29
+ handle.bulk_transfer(endpoint: output, dataOut: data)
30
+ end
31
+
32
+ def read_u8
33
+ read(1).ord
34
+ end
35
+
36
+ def read_u16
37
+ read(2).unpack('S').first
38
+ end
39
+
40
+ def read_u32
41
+ read(4).unpack('L').first
42
+ end
43
+
44
+ def write_u8(u8)
45
+ write(
46
+ (u8 & 0xff).chr
47
+ )
48
+ end
49
+
50
+ def write_u16(u16)
51
+ write(
52
+ [
53
+ (u16 & 0x00ff),
54
+ (u16 & 0xff00) >> 8
55
+ ].pack('cc')
56
+ )
57
+ end
58
+
59
+ def write_u32(u32)
60
+ write(
61
+ [
62
+ (u32 & 0x000000ff),
63
+ (u32 & 0x0000ff00) >> 8,
64
+ (u32 & 0x00ff0000) >> 32,
65
+ (u32 & 0xff000000) >> 24,
66
+ ].pack('cccc')
67
+ )
68
+ end
69
+
70
+ def write_string(string)
71
+ write_u16(string.length)
72
+ write(string)
73
+ end
74
+
75
+ private
76
+
77
+ attr_reader :input, :output, :handle, :device
78
+
79
+ def find_device(vendor, product)
80
+ LIBUSB::Context.new.devices(idVendor: vendor, idProduct: product).first.tap do |device|
81
+ raise(DeviceNotFound) if device.nil?
82
+ end
83
+ end
84
+
85
+ def find_bulk_endpoints(device)
86
+ [
87
+ device.endpoints.find { |ep| ep.transfer_type == :bulk && ep.direction == :in },
88
+ device.endpoints.find { |ep| ep.transfer_type == :bulk && ep.direction == :out }
89
+ ]
90
+ end
91
+ end
92
+
93
+
94
+ class Everdrive
95
+ VENDOR = 0x0483
96
+ PRODUCT = 0x5740
97
+ STATUS_OK = 0xa500
98
+
99
+ FAT_WRITE = 0x02
100
+ FAT_OPEN_ALWAYS = 0x10
101
+
102
+ CMD_F_FCLOSE = 0xCE;
103
+ CMD_F_FOPN = 0xC9
104
+ CMD_F_FWR = 0xCC
105
+ CMD_RTC_GET = 0x14;
106
+ CMD_STATUS = 0x10
107
+
108
+
109
+ def initialize
110
+ @everdrive = EverdriveIO.new(VENDOR, PRODUCT)
111
+ p status_ok?
112
+ end
113
+
114
+ def inspect
115
+ "#<#{self.class.name}: #{@everdrive.inspect}>"
116
+ end
117
+
118
+ def status_ok?
119
+ everdrive.write(make_command(CMD_STATUS))
120
+ everdrive.read_u16 == STATUS_OK
121
+ end
122
+
123
+ def get_realtime_clock
124
+ everdrive.write(make_command(CMD_RTC_GET))
125
+ rtc = everdrive.read(6)
126
+
127
+ ary = rtc.split('').map{|c| ('%x' % c.ord).to_i }
128
+ DateTime.new(ary[0] + 2000, ary[1], ary[2], ary[3], ary[4], ary[5])
129
+ end
130
+
131
+ def test_write_file
132
+ filename = '000-test.nes'
133
+ File.open(filename, 'rb') do |fp|
134
+ contents = fp.read
135
+ p file_open(filename, FAT_OPEN_ALWAYS | FAT_WRITE)
136
+ p file_write(contents, 0, contents.length)
137
+ p file_close
138
+ end
139
+ end
140
+
141
+ private
142
+
143
+ attr_reader :everdrive
144
+
145
+ def file_open(filename, mode)
146
+ puts 'file_open'
147
+ everdrive.write(make_command(CMD_F_FOPN))
148
+ everdrive.write_u8(mode)
149
+ everdrive.write_string('000-test.nes')
150
+ status_ok?
151
+ end
152
+
153
+ def file_write(data, notsure, length)
154
+ puts 'file_write'
155
+ everdrive.write(make_command(CMD_F_FWR))
156
+ everdrive.write_u32(data.length)
157
+ everdrive.write(data)
158
+ # other stuff txdataack instead, pay attention to blocksizes
159
+ status_ok?
160
+ end
161
+
162
+ def file_close
163
+ puts 'file_close'
164
+ everdrive.write(make_command(CMD_F_FCLOSE))
165
+ status_ok?
166
+ end
167
+
168
+ def make_command(command_code)
169
+ data = ['+', '+'.ord ^ 0xff, command_code, command_code ^ 0xff].map { |b| (b.ord & 0xff).chr }.join
170
+ end
171
+ end
172
+
173
+ everdrive = Everdrive.new
174
+ p everdrive.get_realtime_clock
175
+ # p everdrive.test_write_file
@@ -37,7 +37,7 @@
37
37
  sei ; SEt Interrupt (Disables them)
38
38
  cld ; CLear Decimal Mode
39
39
 
40
- ldx #$ff
40
+ ldx #$ff
41
41
  txs ; Set the stack pointer
42
42
 
43
43
  ldx #$00
@@ -0,0 +1,182 @@
1
+ .ines {"prog": 1, "char": 0, "mapper": 0, "mirror": 0}
2
+ .inc <nes.sym>
3
+
4
+ .segment prog 0
5
+
6
+ ;; SRAM Variables
7
+ .org $0000
8
+ .scope audio
9
+ .space timer 1
10
+ .space next_note 1
11
+ .space note_frequency 2
12
+ .
13
+
14
+ ;; Interrupt vectors
15
+ .org $FFFA
16
+ .dw vblank
17
+ .dw main
18
+ .dw irq
19
+
20
+
21
+ .org $C000
22
+ .scope main
23
+ sei
24
+ cld
25
+
26
+ ;; Setup the stack
27
+ ldx #$ff
28
+ txs
29
+
30
+ ;; Disable rendering, reset APU
31
+ ldx #$00
32
+ stx nes.ppu.control
33
+ stx nes.ppu.mask
34
+ jsr zero_apu
35
+
36
+ .scope
37
+ wait_vblank:
38
+ bit nes.ppu.status
39
+ bpl wait_vblank
40
+ .
41
+
42
+ clear_ram:
43
+ lda #$00
44
+ sta $00, x
45
+ sta $100, x
46
+ sta $300, x
47
+ sta $400, x
48
+ sta $500, x
49
+ sta $600, x
50
+ sta $700, x
51
+ lda #$ff
52
+ sta $200, x
53
+ inx
54
+ bne clear_ram
55
+
56
+ .scope
57
+ wait_vblank:
58
+ bit nes.ppu.status
59
+ bpl wait_vblank
60
+ .
61
+
62
+ jsr initialize
63
+
64
+ forever:
65
+ jmp forever
66
+ rti
67
+ .
68
+
69
+
70
+ ;; Zero the APU
71
+ .scope zero_apu
72
+ lda #$00
73
+ ldx #$00
74
+ loop:
75
+ sta $4000, x
76
+ inx
77
+ cpx $18
78
+ bne loop
79
+ rts
80
+ .
81
+
82
+
83
+ ;; Initialize PPU and APU
84
+ .scope initialize
85
+ lda #%00000011
86
+ sta nes.apu.channel_enable
87
+
88
+ ; Reenable interrupts, Turn Vblank back on
89
+ lda #%10000000
90
+ sta nes.ppu.control
91
+
92
+ ; Initialize the audio structure
93
+ lda #$00
94
+ sta audio.timer zp
95
+ lda #$30
96
+ sta audio.next_note zp
97
+
98
+ cli
99
+ rts
100
+ .
101
+
102
+
103
+ ;; Keep time via 60fps vblank
104
+ .scope vblank
105
+ ; Update the audio timer so it resets every 64 frames
106
+ ldx audio.timer zp
107
+ inx
108
+ txa
109
+ and #%00000011
110
+ sta audio.timer zp
111
+ bne return
112
+
113
+ ; Play the next note on reset
114
+ lda audio.next_note zp
115
+ cmp #$80
116
+ bmi continue
117
+ lda #$30
118
+
119
+ continue:
120
+ jsr play_note
121
+ sta audio.next_note zp
122
+ inc audio.next_note zp
123
+
124
+ return:
125
+ rti
126
+ .
127
+
128
+
129
+ ;; Hi and lo byte tables for note frequencies
130
+ .scope midi_notes
131
+ .scope hi
132
+ .bytes $35, $32, $2f, $2c, $2a, $28, $25, $23, $21, $1f, $1d, $1c, $1a, $19, $17, $16
133
+ .bytes $15, $14, $12, $11, $10, $0f, $0e, $0e, $0d, $0c, $0b, $0b, $0a, $0a, $09, $08
134
+ .bytes $08, $07, $07, $07, $06, $06, $05, $05, $05, $05, $04, $04, $04, $03, $03, $03
135
+ .bytes $03, $03, $02, $02, $02, $02, $02, $02, $02, $01, $01, $01, $01, $01, $01, $01
136
+ .bytes $01, $01, $01, $01, $01, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
137
+ .bytes $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
138
+ .bytes $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
139
+ .bytes $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
140
+ .
141
+ .scope lo
142
+ .bytes $71, $71, $9c, $f0, $6a, $09, $ca, $ab, $aa, $c6, $fe, $4f, $b8, $38, $ce, $78
143
+ .bytes $35, $04, $e4, $d5, $d5, $e3, $fe, $27, $5b, $9c, $e6, $3b, $9a, $01, $72, $ea
144
+ .bytes $6a, $f1, $7f, $13, $ad, $4d, $f3, $9d, $4c, $00, $b8, $74, $34, $f8, $bf, $89
145
+ .bytes $56, $26, $f9, $ce, $a6, $80, $5c, $3a, $1a, $fb, $df, $c4, $ab, $93, $7c, $67
146
+ .bytes $52, $3f, $2d, $1c, $0c, $fd, $ef, $e1, $d5, $c9, $bd, $b3, $a9, $9f, $96, $8e
147
+ .bytes $86, $7e, $77, $70, $6a, $64, $5e, $59, $54, $4f, $4b, $46, $42, $3f, $3b, $38
148
+ .bytes $34, $31, $2f, $2c, $29, $27, $25, $23, $21, $1f, $1d, $1b, $1a, $18, $17, $15
149
+ .bytes $14, $13, $12, $11, $10, $0f, $0e, $0d, $0c, $0c, $0b, $0a, $0a, $09, $08, $08
150
+ .
151
+ .
152
+
153
+
154
+ ;; Play midi note held in A
155
+ .scope play_note
156
+ pha
157
+ tax
158
+ lda #%10011111
159
+ sta nes.apu.pulse1.control
160
+
161
+ ; Get the low byte of the timer
162
+ ldy midi_notes.lo, x
163
+ sty nes.apu.pulse1.ft
164
+ sty audio.note_frequency+1 zp
165
+
166
+ ; Get the high 3 bits of the timer
167
+ ldy midi_notes.hi, x
168
+ tya
169
+ and #%00000111
170
+ ora #%11111000
171
+ sta nes.apu.pulse1.ct
172
+ sta audio.note_frequency zp
173
+
174
+ pla
175
+ rts
176
+ .
177
+
178
+
179
+ ;; IRQ, we are not using
180
+ .scope irq
181
+ rti
182
+ .
@@ -1,42 +1,27 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative '../instruction_base'
2
4
 
3
5
  module N65
4
-
5
-
6
- ####
7
- ## This directive to include bytes
6
+ # This directive to include bytes
8
7
  class ASCII < InstructionBase
9
-
10
-
11
- ####
12
- ## Try to parse an incbin directive
13
8
  def self.parse(line)
14
9
  match_data = line.match(/^\.ascii\s+"([^"]+)"$/)
15
10
  return nil if match_data.nil?
11
+
16
12
  ASCII.new(match_data[1])
17
13
  end
18
14
 
19
-
20
- ####
21
- ## Initialize with filename
22
15
  def initialize(string)
23
16
  @string = string
24
17
  end
25
18
 
26
-
27
- ####
28
- ## Execute on the assembler
29
19
  def exec(assembler)
30
20
  assembler.write_memory(@string.bytes)
31
21
  end
32
22
 
33
-
34
- ####
35
- ## Display
36
23
  def to_s
37
24
  ".ascii \"#{@string}\""
38
25
  end
39
-
40
26
  end
41
-
42
27
  end
@@ -1,27 +1,21 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative '../instruction_base'
2
- require_relative '../regexes.rb'
4
+ require_relative '../regexes'
3
5
 
4
6
  module N65
5
-
6
-
7
- ####
8
- ## This directive to include bytes
7
+ # This directive to include bytes
9
8
  class Bytes < InstructionBase
10
-
11
- #### Custom Exceptions
12
9
  class InvalidByteValue < StandardError; end
13
10
 
14
-
15
- ####
16
- ## Try to parse an incbin directive
11
+ # Try to parse an incbin directive
17
12
  def self.parse(line)
18
13
  match_data = line.match(/^\.bytes\s+(.+)$/)
19
14
  return nil if match_data.nil?
20
15
 
21
16
  bytes_array = match_data[1].split(',').map do |byte_string|
22
-
23
- ## Does byte_string represent a numeric literal, or is it a symbol?
24
- ## In numeric captures $2 is always binary, $1 is always hex
17
+ # Does byte_string represent a numeric literal, or is it a symbol?
18
+ # In numeric captures $2 is always binary, $1 is always hex
25
19
 
26
20
  case byte_string.strip
27
21
  when Regexp.new("^#{Regexes::Num8}$")
@@ -30,41 +24,36 @@ module N65
30
24
  when Regexp.new("^#{Regexes::Num16}$")
31
25
  value = $2.nil? ? $1.to_i(16) : $2.to_i(2)
32
26
 
33
- ## Break value up into two bytes
27
+ # Break value up into two bytes
34
28
  high = (0xff00 & value) >> 8
35
29
  low = (0x00ff & value)
36
30
  [low, high]
37
31
  when Regexp.new("^#{Regexes::Sym}$")
38
32
  $1
39
33
  else
40
- fail(InvalidByteValue, byte_string)
34
+ raise(InvalidByteValue, byte_string)
41
35
  end
42
36
  end.flatten
43
37
 
44
38
  Bytes.new(bytes_array)
45
39
  end
46
40
 
47
-
48
- ####
49
- ## Initialize with filename
41
+ # Initialize with a byte array
50
42
  def initialize(bytes_array)
51
43
  @bytes_array = bytes_array
52
44
  end
53
45
 
54
-
55
- ####
56
- ## Execute on the assembler
46
+ # Execute on the assembler
57
47
  def exec(assembler)
58
-
59
48
  promise = assembler.with_saved_state do |saved_assembler|
60
49
  @bytes_array.map! do |byte|
61
50
  case byte
62
- when Fixnum
51
+ when Integer
63
52
  byte
64
53
  when String
65
- value = saved_assembler.symbol_table.resolve_symbol(byte)
54
+ saved_assembler.symbol_table.resolve_symbol(byte)
66
55
  else
67
- fail(InvalidByteValue, byte)
56
+ raise(InvalidByteValue, byte)
68
57
  end
69
58
  end
70
59
  saved_assembler.write_memory(@bytes_array)
@@ -73,30 +62,26 @@ module N65
73
62
  begin
74
63
  promise.call
75
64
  rescue SymbolTable::UndefinedSymbol
76
- ## Write the bytes but assume a zero page address for all symbols
77
- ## And just write 0xDE for a placeholder
65
+ # Write the bytes but assume a zero page address for all symbols
66
+ # And just write 0xDE for a placeholder
78
67
  placeholder_bytes = @bytes_array.map do |byte|
79
68
  case bytes
80
- when Fixnum
69
+ when Integer
81
70
  byte
82
71
  when String
83
72
  0xDE
84
73
  else
85
- fail(InvalidByteValue, byte)
74
+ raise(InvalidByteValue, byte)
86
75
  end
87
76
  end
88
77
  assembler.write_memory(placeholder_bytes)
89
- return promise
78
+ promise
90
79
  end
91
80
  end
92
81
 
93
-
94
- ####
95
- ## Display, I don't want to write all these out
82
+ # Display, I don't want to write all these out
96
83
  def to_s
97
84
  ".bytes (#{@bytes_array.length})"
98
85
  end
99
-
100
86
  end
101
-
102
87
  end
@@ -1,25 +1,21 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative '../instruction_base'
2
4
 
3
5
  module N65
4
-
5
-
6
- ####
7
- ## This directive instruction can include a binary file
6
+ # This directive instruction can include a binary file
8
7
  class DW < InstructionBase
9
-
10
- ####
11
- ## Try to parse a dw directive
8
+ # Try to parse a dw directive
12
9
  def self.parse(line)
13
-
14
- ## Maybe it is a straight up bit of hex
10
+ # Maybe it is a straight up bit of hex
15
11
  match_data = line.match(/^\.dw\s+\$([0-9A-F]{1,4})$/)
16
12
  unless match_data.nil?
17
13
  word = match_data[1].to_i(16)
18
14
  return DW.new(word)
19
15
  end
20
16
 
21
- ## Or maybe it points to a symbol
22
- match_data = line.match(/^\.dw\s+([A-Za-z_][A-Za-z0-9_\.]+)/)
17
+ # Or maybe it points to a symbol
18
+ match_data = line.match(/^\.dw\s+([A-Za-z_][A-Za-z0-9_.]+)/)
23
19
  unless match_data.nil?
24
20
  symbol = match_data[1]
25
21
  return DW.new(symbol)
@@ -27,60 +23,50 @@ module N65
27
23
  nil
28
24
  end
29
25
 
30
-
31
- ####
32
- ## Initialize with filename
26
+ # Initialize with filename
33
27
  def initialize(value)
34
28
  @value = value
35
29
  end
36
30
 
37
-
38
- ####
39
- ## Execute on the assembler, now in this case value may
40
- ## be a symbol that needs to be resolved, if so we return
41
- ## a lambda which can be executed later, with the promise
42
- ## that that symbol will have then be defined
43
- ## This is a little complicated, I admit.
31
+ # Execute on the assembler, now in this case value may
32
+ # be a symbol that needs to be resolved, if so we return
33
+ # a lambda which can be executed later, with the promise
34
+ # that that symbol will have then be defined
35
+ # This is a little complicated, I admit.
44
36
  def exec(assembler)
45
-
46
37
  promise = assembler.with_saved_state do |saved_assembler|
47
38
  value = saved_assembler.symbol_table.resolve_symbol(@value)
48
39
  bytes = [value & 0xFFFF].pack('S').bytes
49
40
  saved_assembler.write_memory(bytes)
50
41
  end
51
42
 
52
-
53
- ## Try to execute it now, or setup the promise to return
43
+ # Try to execute it now, or setup the promise to return
54
44
  case @value
55
- when Fixnum
45
+ when Integer
56
46
  bytes = [@value & 0xFFFF].pack('S').bytes
57
47
  assembler.write_memory(bytes)
58
48
  when String
59
49
  begin
60
50
  promise.call
61
51
  rescue SymbolTable::UndefinedSymbol
62
- ## Must still advance PC before returning promise, so we'll write
63
- ## a place holder value of 0xDEAD
52
+ # Must still advance PC before returning promise, so we'll write
53
+ # a place holder value of 0xDEAD
64
54
  assembler.write_memory([0xDE, 0xAD])
65
- return promise
55
+ promise
66
56
  end
67
57
  else
68
- fail("Uknown argument in .dw directive")
58
+ raise('Uknown argument in .dw directive')
69
59
  end
70
60
  end
71
61
 
72
-
73
- ####
74
- ## Display
62
+ # Display
75
63
  def to_s
76
64
  case @value
77
65
  when String
78
66
  ".dw #{@value}"
79
- when Fixnum
80
- ".dw $%4.X" % @value
67
+ when Integer
68
+ '.dw $%4.X' % @value
81
69
  end
82
70
  end
83
-
84
71
  end
85
-
86
72
  end
@@ -1,55 +1,39 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative '../instruction_base'
2
4
 
3
5
  module N65
4
-
5
-
6
- ####
7
- ## This directive to include bytes
6
+ # This directive to include bytes
8
7
  class EnterScope < InstructionBase
9
-
10
- ####
11
- ## Try to parse an incbin directive
12
8
  def self.parse(line)
13
- ## Anonymous scope
9
+ # Anonymous scope
14
10
  match_data = line.match(/^\.scope$/)
15
- unless match_data.nil?
16
- return EnterScope.new
17
- end
11
+ return EnterScope.new unless match_data.nil?
18
12
 
19
- ## Named scope
13
+ # Named scope
20
14
  match_data = line.match(/^\.scope\s+([a-zA-Z][a-zA-Z0-9_]+)$/)
21
15
  return nil if match_data.nil?
16
+
22
17
  EnterScope.new(match_data[1])
23
18
  end
24
19
 
25
-
26
- ####
27
- ## Initialize with filename
20
+ # Initialize with filename
28
21
  def initialize(name = nil)
29
22
  @name = name
30
23
  end
31
24
 
32
-
33
- ####
34
- ## Execute on the assembler, also create a symbol referring to
35
- ## the current pc which contains a hyphen, and is impossible for
36
- ## the user to create. This makes a scope simultaneously act as
37
- ## a label to the current PC. If someone tries to use a scope
38
- ## name as a label, it can return the address when the scope opened.
25
+ # Execute on the assembler, also create a symbol referring to
26
+ # the current pc which contains a hyphen, and is impossible for
27
+ # the user to create. This makes a scope simultaneously act as
28
+ # a label to the current PC. If someone tries to use a scope
29
+ # name as a label, it can return the address when the scope opened.
39
30
  def exec(assembler)
40
31
  assembler.symbol_table.enter_scope(@name)
41
- unless @name.nil?
42
- assembler.symbol_table.define_symbol("-#{@name}", assembler.program_counter)
43
- end
32
+ assembler.symbol_table.define_symbol("-#{@name}", assembler.program_counter) unless @name.nil?
44
33
  end
45
34
 
46
-
47
- ####
48
- ## Display
49
35
  def to_s
50
36
  ".scope #{@name}"
51
37
  end
52
-
53
38
  end
54
-
55
39
  end