mirror of https://github.com/safiire/n65.git
Updates to the assembler's output concerning the sizes of banks, how much are used, a --quiet option was added, and a -s option to produce a symbol map.
This commit is contained in:
parent
6b387e20df
commit
eca1831e35
|
@ -0,0 +1,182 @@
|
||||||
|
.ines {"prog": 1, "char": 0, "mapper": 0, "mirror": 0}
|
||||||
|
.inc <nes.sym>
|
||||||
|
|
||||||
|
.segment prog 0
|
||||||
|
|
||||||
|
;; SRAM Variables
|
||||||
|
.org $0000
|
||||||
|
.scope audio
|
||||||
|
.space timer 1
|
||||||
|
.space next_note 1
|
||||||
|
.space note_frequency 2
|
||||||
|
.
|
||||||
|
|
||||||
|
;; Interrupt vectors
|
||||||
|
.org $FFFA
|
||||||
|
.dw vblank
|
||||||
|
.dw main
|
||||||
|
.dw irq
|
||||||
|
|
||||||
|
|
||||||
|
.org $C000
|
||||||
|
.scope main
|
||||||
|
sei
|
||||||
|
cld
|
||||||
|
|
||||||
|
;; Setup the stack
|
||||||
|
ldx #$ff
|
||||||
|
txs
|
||||||
|
|
||||||
|
;; Disable rendering, reset APU
|
||||||
|
ldx #$00
|
||||||
|
stx nes.ppu.control
|
||||||
|
stx nes.ppu.mask
|
||||||
|
jsr zero_apu
|
||||||
|
|
||||||
|
.scope
|
||||||
|
wait_vblank:
|
||||||
|
bit nes.ppu.status
|
||||||
|
bpl wait_vblank
|
||||||
|
.
|
||||||
|
|
||||||
|
clear_ram:
|
||||||
|
lda #$00
|
||||||
|
sta $00, x
|
||||||
|
sta $100, x
|
||||||
|
sta $300, x
|
||||||
|
sta $400, x
|
||||||
|
sta $500, x
|
||||||
|
sta $600, x
|
||||||
|
sta $700, x
|
||||||
|
lda #$ff
|
||||||
|
sta $200, x
|
||||||
|
inx
|
||||||
|
bne clear_ram
|
||||||
|
|
||||||
|
.scope
|
||||||
|
wait_vblank:
|
||||||
|
bit nes.ppu.status
|
||||||
|
bpl wait_vblank
|
||||||
|
.
|
||||||
|
|
||||||
|
jsr initialize
|
||||||
|
|
||||||
|
forever:
|
||||||
|
jmp forever
|
||||||
|
rti
|
||||||
|
.
|
||||||
|
|
||||||
|
|
||||||
|
;; Zero the APU
|
||||||
|
.scope zero_apu
|
||||||
|
lda #$00
|
||||||
|
ldx #$00
|
||||||
|
loop:
|
||||||
|
sta $4000, x
|
||||||
|
inx
|
||||||
|
cpx $18
|
||||||
|
bne loop
|
||||||
|
rts
|
||||||
|
.
|
||||||
|
|
||||||
|
|
||||||
|
;; Initialize PPU and APU
|
||||||
|
.scope initialize
|
||||||
|
lda #%00000011
|
||||||
|
sta nes.apu.channel_enable
|
||||||
|
|
||||||
|
; Reenable interrupts, Turn Vblank back on
|
||||||
|
lda #%10000000
|
||||||
|
sta nes.ppu.control
|
||||||
|
|
||||||
|
; Initialize the audio structure
|
||||||
|
lda #$00
|
||||||
|
sta audio.timer zp
|
||||||
|
lda #$30
|
||||||
|
sta audio.next_note zp
|
||||||
|
|
||||||
|
cli
|
||||||
|
rts
|
||||||
|
.
|
||||||
|
|
||||||
|
|
||||||
|
;; Keep time via 60fps vblank
|
||||||
|
.scope vblank
|
||||||
|
; Update the audio timer so it resets every 64 frames
|
||||||
|
ldx audio.timer zp
|
||||||
|
inx
|
||||||
|
txa
|
||||||
|
and #%00000011
|
||||||
|
sta audio.timer zp
|
||||||
|
bne return
|
||||||
|
|
||||||
|
; Play the next note on reset
|
||||||
|
lda audio.next_note zp
|
||||||
|
cmp #$80
|
||||||
|
bmi continue
|
||||||
|
lda #$30
|
||||||
|
|
||||||
|
continue:
|
||||||
|
jsr play_note
|
||||||
|
sta audio.next_note zp
|
||||||
|
inc audio.next_note zp
|
||||||
|
|
||||||
|
return:
|
||||||
|
rti
|
||||||
|
.
|
||||||
|
|
||||||
|
|
||||||
|
;; Hi and lo byte tables for note frequencies
|
||||||
|
.scope midi_notes
|
||||||
|
.scope hi
|
||||||
|
.bytes $35, $32, $2f, $2c, $2a, $28, $25, $23, $21, $1f, $1d, $1c, $1a, $19, $17, $16
|
||||||
|
.bytes $15, $14, $12, $11, $10, $0f, $0e, $0e, $0d, $0c, $0b, $0b, $0a, $0a, $09, $08
|
||||||
|
.bytes $08, $07, $07, $07, $06, $06, $05, $05, $05, $05, $04, $04, $04, $03, $03, $03
|
||||||
|
.bytes $03, $03, $02, $02, $02, $02, $02, $02, $02, $01, $01, $01, $01, $01, $01, $01
|
||||||
|
.bytes $01, $01, $01, $01, $01, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
|
||||||
|
.bytes $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
|
||||||
|
.bytes $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
|
||||||
|
.bytes $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
|
||||||
|
.
|
||||||
|
.scope lo
|
||||||
|
.bytes $71, $71, $9c, $f0, $6a, $09, $ca, $ab, $aa, $c6, $fe, $4f, $b8, $38, $ce, $78
|
||||||
|
.bytes $35, $04, $e4, $d5, $d5, $e3, $fe, $27, $5b, $9c, $e6, $3b, $9a, $01, $72, $ea
|
||||||
|
.bytes $6a, $f1, $7f, $13, $ad, $4d, $f3, $9d, $4c, $00, $b8, $74, $34, $f8, $bf, $89
|
||||||
|
.bytes $56, $26, $f9, $ce, $a6, $80, $5c, $3a, $1a, $fb, $df, $c4, $ab, $93, $7c, $67
|
||||||
|
.bytes $52, $3f, $2d, $1c, $0c, $fd, $ef, $e1, $d5, $c9, $bd, $b3, $a9, $9f, $96, $8e
|
||||||
|
.bytes $86, $7e, $77, $70, $6a, $64, $5e, $59, $54, $4f, $4b, $46, $42, $3f, $3b, $38
|
||||||
|
.bytes $34, $31, $2f, $2c, $29, $27, $25, $23, $21, $1f, $1d, $1b, $1a, $18, $17, $15
|
||||||
|
.bytes $14, $13, $12, $11, $10, $0f, $0e, $0d, $0c, $0c, $0b, $0a, $0a, $09, $08, $08
|
||||||
|
.
|
||||||
|
.
|
||||||
|
|
||||||
|
|
||||||
|
;; Play midi note held in A
|
||||||
|
.scope play_note
|
||||||
|
pha
|
||||||
|
tax
|
||||||
|
lda #%10011111
|
||||||
|
sta nes.apu.pulse1.control
|
||||||
|
|
||||||
|
; Get the low byte of the timer
|
||||||
|
ldy midi_notes.lo, x
|
||||||
|
sty nes.apu.pulse1.ft
|
||||||
|
sty audio.note_frequency+1 zp
|
||||||
|
|
||||||
|
; Get the high 3 bits of the timer
|
||||||
|
ldy midi_notes.hi, x
|
||||||
|
tya
|
||||||
|
and #%00000111
|
||||||
|
ora #%11111000
|
||||||
|
sta nes.apu.pulse1.ct
|
||||||
|
sta audio.note_frequency zp
|
||||||
|
|
||||||
|
pla
|
||||||
|
rts
|
||||||
|
.
|
||||||
|
|
||||||
|
|
||||||
|
;; IRQ, we are not using
|
||||||
|
.scope irq
|
||||||
|
rti
|
||||||
|
.
|
62
lib/n65.rb
62
lib/n65.rb
|
@ -18,13 +18,14 @@ module N65
|
||||||
|
|
||||||
####
|
####
|
||||||
## Assemble from an asm file to a nes ROM
|
## Assemble from an asm file to a nes ROM
|
||||||
def self.from_file(infile, outfile)
|
def self.from_file(infile, options)
|
||||||
fail(FileNotFound, infile) unless File.exists?(infile)
|
fail(FileNotFound, infile) unless File.exists?(infile)
|
||||||
|
|
||||||
assembler = self.new
|
assembler = self.new
|
||||||
program = File.read(infile)
|
program = File.read(infile)
|
||||||
|
output_file = options[:output_file]
|
||||||
|
|
||||||
puts "Building #{infile}"
|
puts "Building #{infile}" unless options[:quiet]
|
||||||
## Process each line in the file
|
## Process each line in the file
|
||||||
program.split(/\n/).each_with_index do |line, line_number|
|
program.split(/\n/).each_with_index do |line, line_number|
|
||||||
begin
|
begin
|
||||||
|
@ -33,28 +34,35 @@ module N65
|
||||||
STDERR.puts("\n\n#{e.class}\n#{line}\n#{e}\nOn line #{line_number}")
|
STDERR.puts("\n\n#{e.class}\n#{line}\n#{e}\nOn line #{line_number}")
|
||||||
exit(1)
|
exit(1)
|
||||||
end
|
end
|
||||||
print '.'
|
print '.' unless options[:quiet]
|
||||||
end
|
end
|
||||||
puts
|
puts unless options[:quiet]
|
||||||
|
|
||||||
## Second pass to resolve any missing symbols.
|
## Second pass to resolve any missing symbols.
|
||||||
print "Second pass, resolving symbols..."
|
print "Second pass, resolving symbols..." unless options[:quiet]
|
||||||
assembler.fulfill_promises
|
assembler.fulfill_promises
|
||||||
puts " Done."
|
puts " Done." unless options[:quiet]
|
||||||
|
|
||||||
## Let's not export the symbol table to a file anymore
|
if options[:write_symbol_table]
|
||||||
## Will add an option for this later.
|
print "Writing symbol table to #{output_file}.yaml..." unless options[:quiet]
|
||||||
#print "Writing symbol table to #{outfile}.yaml..."
|
File.open("#{output_file}.yaml", 'w') do |fp|
|
||||||
#File.open("#{outfile}.yaml", 'w') do |fp|
|
fp.write(assembler.symbol_table.export_to_yaml)
|
||||||
#fp.write(assembler.symbol_table.export_to_yaml)
|
end
|
||||||
#end
|
puts "Done." unless options[:quiet]
|
||||||
#puts "Done."
|
end
|
||||||
|
|
||||||
## Emit the complete binary ROM
|
## Emit the complete binary ROM
|
||||||
File.open(outfile, 'w') do |fp|
|
rom = assembler.emit_binary_rom
|
||||||
fp.write(assembler.emit_binary_rom)
|
File.open(output_file, 'w') do |fp|
|
||||||
|
fp.write(rom)
|
||||||
|
end
|
||||||
|
|
||||||
|
unless options[:quiet]
|
||||||
|
rom_size = rom.size
|
||||||
|
rom_size_hex = "%x" % rom_size
|
||||||
|
assembler.print_bank_usage
|
||||||
|
puts "Total size: $#{rom_size_hex}, #{rom_size} bytes"
|
||||||
end
|
end
|
||||||
puts "All Done :)"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -190,15 +198,11 @@ module N65
|
||||||
def emit_binary_rom
|
def emit_binary_rom
|
||||||
progs = @virtual_memory[:prog]
|
progs = @virtual_memory[:prog]
|
||||||
chars = @virtual_memory[:char]
|
chars = @virtual_memory[:char]
|
||||||
puts "iNES Header"
|
|
||||||
puts "+ #{progs.size} PROG ROM bank#{progs.size != 1 ? 's' : ''}"
|
|
||||||
puts "+ #{chars.size} CHAR ROM bank#{chars.size != 1 ? 's' : ''}"
|
|
||||||
|
|
||||||
rom_size = 0x10
|
rom_size = 0x10
|
||||||
rom_size += MemorySpace::BankSizes[:prog] * progs.size
|
rom_size += MemorySpace::BankSizes[:prog] * progs.size
|
||||||
rom_size += MemorySpace::BankSizes[:char] * chars.size
|
rom_size += MemorySpace::BankSizes[:char] * chars.size
|
||||||
|
|
||||||
puts "= Output ROM will be #{rom_size} bytes"
|
|
||||||
rom = MemorySpace.new(rom_size, :rom)
|
rom = MemorySpace.new(rom_size, :rom)
|
||||||
|
|
||||||
offset = 0x0
|
offset = 0x0
|
||||||
|
@ -215,6 +219,24 @@ module N65
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
####
|
||||||
|
## Display information about the bank sizes and total usage
|
||||||
|
def print_bank_usage
|
||||||
|
puts
|
||||||
|
puts "ROM Structure {"
|
||||||
|
puts " iNES 1.0 Header: $10 bytes"
|
||||||
|
|
||||||
|
@virtual_memory[:prog].each_with_index do |prog_rom, bank_number|
|
||||||
|
puts " PROG ROM bank #{bank_number}: #{prog_rom.usage_info}"
|
||||||
|
end
|
||||||
|
|
||||||
|
@virtual_memory[:char].each_with_index do |char_rom, bank_number|
|
||||||
|
puts " CHAR ROM bank #{bank_number}: #{char_rom.usage_info}"
|
||||||
|
end
|
||||||
|
puts "}"
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ module N65
|
||||||
####
|
####
|
||||||
## Initialize with ARGV commandline
|
## Initialize with ARGV commandline
|
||||||
def initialize(argv)
|
def initialize(argv)
|
||||||
@options = {:output_file => nil}
|
@options = {output_file: nil, write_symbol_table: false, quiet: false}
|
||||||
@argv = argv.dup
|
@argv = argv.dup
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ module N65
|
||||||
|
|
||||||
## Only can assemble one file at once for now
|
## Only can assemble one file at once for now
|
||||||
if @argv.size != 1
|
if @argv.size != 1
|
||||||
STDERR.puts "Can only assemble one input file at once :("
|
STDERR.puts "Can only assemble one input file at once, but you can use .inc and .incbin directives"
|
||||||
exit(1)
|
exit(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ module N65
|
||||||
exit(1)
|
exit(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
N65::Assembler.from_file(input_file, @options[:output_file])
|
N65::Assembler.from_file(input_file, @options)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -69,12 +69,19 @@ module N65
|
||||||
@options[:output_file] = output_file;
|
@options[:output_file] = output_file;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
opts.on('-s', '--symbols', 'Outputs a symbol map') do
|
||||||
|
@options[:write_symbol_table] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
opts.on('-q', '--quiet', 'No output on success') do
|
||||||
|
@options[:quiet] = true
|
||||||
|
end
|
||||||
|
|
||||||
opts.on('-v', '--version', 'Displays Version') do
|
opts.on('-v', '--version', 'Displays Version') do
|
||||||
puts "N65 Assembler Version #{N65::VERSION}"
|
puts "N65 Assembler Version #{N65::VERSION}"
|
||||||
exit
|
exit
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
opts.on('-h', '--help', 'Displays Help') do
|
opts.on('-h', '--help', 'Displays Help') do
|
||||||
puts opts
|
puts opts
|
||||||
exit
|
exit
|
||||||
|
|
|
@ -48,6 +48,7 @@ module N65
|
||||||
def initialize(size, type)
|
def initialize(size, type)
|
||||||
@type = type
|
@type = type
|
||||||
@memory = Array.new(size, 0x0)
|
@memory = Array.new(size, 0x0)
|
||||||
|
@bytes_written = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -71,6 +72,7 @@ module N65
|
||||||
|
|
||||||
bytes.each_with_index do |byte, index|
|
bytes.each_with_index do |byte, index|
|
||||||
@memory[from_normalized + index] = byte
|
@memory[from_normalized + index] = byte
|
||||||
|
@bytes_written += 1
|
||||||
end
|
end
|
||||||
bytes.size
|
bytes.size
|
||||||
end
|
end
|
||||||
|
@ -83,6 +85,17 @@ module N65
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
####
|
||||||
|
## Bank Usage information
|
||||||
|
def usage_info
|
||||||
|
percent_used = @bytes_written / @memory.size.to_f * 100
|
||||||
|
percent_string = "%0.2f" % percent_used
|
||||||
|
bytes_written_hex = "$%04x" % @bytes_written
|
||||||
|
memory_size_hex = "$%04x" % @memory.size
|
||||||
|
"(#{bytes_written_hex} / #{memory_size_hex}) #{percent_string}%"
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
####
|
####
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
module N65
|
module N65
|
||||||
VERSION ||= "1.5.0"
|
VERSION ||= "1.5.2"
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue