mirror of
https://github.com/safiire/n65.git
synced 2024-12-12 00:29:03 +00:00
Ported NES101 tutor to this assembler, fixed the PROG and CHR positioning in the ROM, added more directives .ascii etc.
This commit is contained in:
parent
f5866fa2e3
commit
427b676502
@ -21,14 +21,9 @@
|
||||
## on FCEUX, got it to make some sounds, etc.
|
||||
##
|
||||
## Some Todos:
|
||||
## - I need to add the .byte operator to add data bytes.
|
||||
## - I need to add the #<$800 and #>$800 style operators to select the
|
||||
## MSB and LSB of immediate values during assembly.
|
||||
## - I need to make the text/code/data sections easier to configure, it is
|
||||
## currently set to 0x8000 like NES Prog ROM
|
||||
## - I need to add commandline options through the OptionParser library
|
||||
## - I may make this into a Rubygem
|
||||
## - I need to split the project up into one class per file like usual.
|
||||
## - Maybe I can put some better error messages.
|
||||
## - I should just make a 6502 CPU emulator probably now too.
|
||||
|
||||
@ -62,7 +57,7 @@ module Assembler6502
|
||||
def run
|
||||
options = {:out_file => nil}
|
||||
parser = OptionParser.new do |opts|
|
||||
opts.banner = "Usage: #{$0} [options]"
|
||||
opts.banner = "Usage: #{$0} [options] <input_file.asm>"
|
||||
|
||||
opts.on('-o', '--outfile filename', 'outfile') do |out_file|
|
||||
options[:out_file] = out_file;
|
||||
@ -105,13 +100,3 @@ module Assembler6502
|
||||
end
|
||||
|
||||
Assembler6502.run
|
||||
|
||||
#p Assembler6502::Directive.parse(' .ines {"prog": 1, "char": 0, "mapper": 0, "mirror": 1} ')
|
||||
#p Assembler6502::Directive.parse(' .org $423C ')
|
||||
#p Assembler6502::Directive.parse(' .incbin "mario.chr" ')
|
||||
#p Assembler6502::Directive.parse(' .dw $2FFF ')
|
||||
#p Assembler6502::Directive.parse(' .bytes $2F, $FF, $2 ')
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -42,6 +42,10 @@ module Assembler6502
|
||||
## The Main Assembler
|
||||
class Assembler
|
||||
|
||||
## Custom exceptions
|
||||
class INESHeaderNotFound < StandardError; end
|
||||
|
||||
|
||||
####
|
||||
## Assemble from a file to a file
|
||||
def self.from_file(infile, outfile)
|
||||
@ -79,8 +83,8 @@ module Assembler6502
|
||||
when INESHeader
|
||||
fail(SyntaxError, "Already got ines header") unless @ines_header.nil?
|
||||
@ines_header = parsed_line
|
||||
puts "\tWriting iNES Header"
|
||||
memory.write(0x0, parsed_line.emit_bytes)
|
||||
puts "\tGot iNES Header"
|
||||
#memory.write(0x0, parsed_line.emit_bytes)
|
||||
|
||||
when Org
|
||||
address = parsed_line.address
|
||||
@ -102,7 +106,8 @@ module Assembler6502
|
||||
puts "\tAdvanced address to %X" % address
|
||||
|
||||
when IncBin
|
||||
puts "\tI Don't support .incbin yet"
|
||||
fail("\tI Don't support .incbin yet")
|
||||
|
||||
|
||||
when DW
|
||||
if parsed_line.unresolved_symbols?
|
||||
@ -116,9 +121,16 @@ module Assembler6502
|
||||
|
||||
when Bytes
|
||||
bytes = parsed_line.emit_bytes
|
||||
puts "\tWriting raw bytes to memory #{bytes.inspect}"
|
||||
puts "\tWriting raw #{bytes.size} bytes to #{sprintf("$%X", address)}"
|
||||
memory.write(address, bytes)
|
||||
address += bytes.size
|
||||
|
||||
when ASCII
|
||||
bytes = parsed_line.emit_bytes
|
||||
puts "\tWriting ascii string to memory \"#{bytes.pack('C*')}\""
|
||||
memory.write(address, bytes)
|
||||
address += bytes.size
|
||||
|
||||
else
|
||||
fail(SyntaxError, sprintf("%.4X: Failed to parse: #{parsed_line}", address))
|
||||
end
|
||||
@ -145,11 +157,37 @@ module Assembler6502
|
||||
## beginning at 0xC000, this should reach right up to the interrupt vectors
|
||||
def assemble
|
||||
virtual_memory = assemble_in_virtual_memory
|
||||
rom_size = 16 + (0xffff - 0xc000)
|
||||
nes_rom = MemorySpace.new(rom_size)
|
||||
nes_rom.write(0x0, virtual_memory.read(0x0, 0x10))
|
||||
nes_rom.write(0x10, virtual_memory.read(0xC000, 0x4000))
|
||||
|
||||
## First we need to be sure we have an iNES header
|
||||
fail(INESHeaderNotFound) if @ines_header.nil?
|
||||
|
||||
## Create memory to hold the ROM
|
||||
nes_rom = MemorySpace.new(0x10 + 0x4000)
|
||||
|
||||
## First write the iNES header itself
|
||||
nes_rom.write(0x0, @ines_header.emit_bytes)
|
||||
|
||||
## Write only one PROG section from 0xC000
|
||||
start_address = 0xC000
|
||||
length = 0x4000
|
||||
prog_rom = virtual_memory.read(start_address, length)
|
||||
write_start = 0x10
|
||||
nes_rom.write(write_start, prog_rom)
|
||||
|
||||
## Now try writing one CHR-ROM section from 0x0000
|
||||
start_address = 0x0000
|
||||
length = 0x4000
|
||||
char_rom = virtual_memory.read(start_address, length)
|
||||
write_start = 0x10 + 0x4000
|
||||
nes_rom.write(write_start, char_rom)
|
||||
|
||||
nes_rom.emit_bytes
|
||||
|
||||
#rom_size = 16 + (0xffff - 0xc000)
|
||||
#nes_rom = MemorySpace.new(rom_size)
|
||||
#nes_rom.write(0x0, virtual_memory.read(0x0, 0x10))
|
||||
#nes_rom.write(0x10, virtual_memory.read(0xC000, 0x4000))
|
||||
#nes_rom.emit_bytes
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -5,6 +5,7 @@ module Assembler6502
|
||||
####
|
||||
## This class can setup an iNES Header
|
||||
class INESHeader
|
||||
attr_reader :prog, :char, :mapper, :mirror
|
||||
|
||||
####
|
||||
## Construct with the right values
|
||||
@ -12,6 +13,17 @@ module Assembler6502
|
||||
@prog, @char, @mapper, @mirror = prog, char, mapper, mirror
|
||||
end
|
||||
|
||||
|
||||
####
|
||||
## What will the size of the ROM binary be?
|
||||
def rom_size
|
||||
size = 0x10 # Always have a 16 byte header
|
||||
size += 0x4000 * @prog # 16KB per PROG-ROM
|
||||
size += 0x2000 * @char # 8KB per CHR_ROM
|
||||
size
|
||||
end
|
||||
|
||||
|
||||
####
|
||||
## Emit the header bytes, this is not exactly right, but it works for now.
|
||||
def emit_bytes
|
||||
@ -108,6 +120,19 @@ module Assembler6502
|
||||
def emit_bytes
|
||||
@bytes
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
####
|
||||
## This inserts ASCII text straight into the ROM
|
||||
class ASCII
|
||||
def initialize(string)
|
||||
@string = string
|
||||
end
|
||||
|
||||
def emit_bytes
|
||||
@string.bytes
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@ -138,6 +163,9 @@ module Assembler6502
|
||||
when /^\.dw\s+([A-Za-z_][A-Za-z0-9_]+)/
|
||||
DW.new($1.to_sym, address)
|
||||
|
||||
when /^\.ascii\s+"([^"]+)"$/
|
||||
ASCII.new($1)
|
||||
|
||||
when /^\.bytes\s+(.+)$/
|
||||
Bytes.new($1)
|
||||
when /^\./
|
||||
|
@ -16,21 +16,22 @@ module Assembler6502
|
||||
Hex8 = '\$([A-Z0-9]{2})'
|
||||
Hex16 = '\$([A-Z0-9]{4})'
|
||||
Immediate = '\#\$([0-9A-F]{2})'
|
||||
Sym = '([A-Za-z_][A-Za-z0-9_]+)'
|
||||
Sym = '([a-zZ-Z_][a-zA-Z0-9_]+)'
|
||||
Branches = '(BPL|BMI|BVC|BVS|BCC|BCS|BNE|BEQ)'
|
||||
|
||||
AddressingModes = {
|
||||
:relative => {
|
||||
:example => 'B** my_label',
|
||||
:display => '%s $%.4X',
|
||||
:regex => /$^/, # Will never match this one
|
||||
:regex => /$^/i, # Will never match this one
|
||||
:regex_label => /^#{Branches}\s+#{Sym}$/
|
||||
},
|
||||
|
||||
:immediate => {
|
||||
:example => 'AAA #$FF',
|
||||
:display => '%s #$%.2X',
|
||||
:regex => /^#{Mnemonic}\s+#{Immediate}$/
|
||||
:regex => /^#{Mnemonic}\s+#{Immediate}$/,
|
||||
:regex_label => /^#{Mnemonic}\s+#(<|>)#{Sym}$/
|
||||
},
|
||||
|
||||
:implied => {
|
||||
@ -93,7 +94,7 @@ module Assembler6502
|
||||
},
|
||||
|
||||
:indirect_y => {
|
||||
:example => 'AAA ($FF, X)',
|
||||
:example => 'AAA ($FF), Y)',
|
||||
:display => '%s ($%.2X), Y',
|
||||
:regex => /^#{Mnemonic}\s+\(#{Hex8}\)\s?,\s?Y$/,
|
||||
:regex_label => /^#{Mnemonic}\s+\(#{Sym}\)\s?,\s?Y$/
|
||||
@ -116,7 +117,6 @@ module Assembler6502
|
||||
directive = Directive.parse(sanitized, address)
|
||||
return directive unless directive.nil?
|
||||
|
||||
|
||||
## Let's see if this line is a label, and try
|
||||
## to create a label for the current address
|
||||
label = Label.parse_label(sanitized, address)
|
||||
@ -143,10 +143,22 @@ module Assembler6502
|
||||
|
||||
unless match_data.nil?
|
||||
## Yep, the arg is a label, we can resolve that to an address later
|
||||
## Buf for now we will create an Instruction where the label is a
|
||||
## But for now we will create an Instruction where the label is a
|
||||
## symbol reference to the label we found, ie. arg.to_sym
|
||||
_, op, arg = match_data.to_a
|
||||
return Instruction.new(op, arg.to_sym, mode, address)
|
||||
match_array = match_data.to_a
|
||||
|
||||
## If we have a 4 element array, this means we matched something
|
||||
## like LDA #<label, which is a legal immediate one byte value
|
||||
## by taking the msb. We need to make that distinction in the
|
||||
## Instruction, by passing an extra argument
|
||||
if match_array.size == 4
|
||||
_, op, byte_selector, arg = match_array
|
||||
return Instruction.new(op, arg.to_sym, mode, address, byte_selector.to_sym)
|
||||
puts "I found one with #{byte_selector} #{arg}"
|
||||
else
|
||||
_, op, arg = match_array
|
||||
return Instruction.new(op, arg.to_sym, mode, address)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -161,9 +173,11 @@ module Assembler6502
|
||||
## Create an instruction. Having the instruction op a downcased symbol is nice
|
||||
## because that can later be used to index into our opcodes hash in OpCodes
|
||||
## OpCodes contains the definitions of each OpCode
|
||||
def initialize(op, arg, mode, address)
|
||||
def initialize(op, arg, mode, address, byte_selector = nil)
|
||||
|
||||
## Lookup the definition of this opcode, otherwise it is an invalid instruction
|
||||
@byte_selector = byte_selector.nil? ? nil : byte_selector.to_sym
|
||||
fail(InvalidInstruction, "Bad Byte selector: #{byte_selector}") unless [:>, :<, nil].include?(@byte_selector)
|
||||
@op = op.downcase.to_sym
|
||||
definition = OpCodes[@op]
|
||||
fail(InvalidInstruction, op) if definition.nil?
|
||||
@ -215,6 +229,19 @@ module Assembler6502
|
||||
fail(SyntaxError, "Unknown symbol #{@arg.inspect}")
|
||||
end
|
||||
|
||||
## It is possible to resolve a symbol to a 16-bit address and then
|
||||
## use byte_selector to select the msb or lsb
|
||||
unless @byte_selector.nil?
|
||||
arg_16 = symbols[@arg].address
|
||||
@arg = case @byte_selector
|
||||
when :>
|
||||
(arg_16 & 0xFF00) >> 8
|
||||
when :<
|
||||
arg_16 & 0xFF
|
||||
end
|
||||
return @arg
|
||||
end
|
||||
|
||||
## Based on this instructions length, we should resolve the address
|
||||
## to either an absolute one, or a relative one. The only relative addresses
|
||||
## are the branching ones, which are 2 bytes in size, hence the extra 2 byte difference
|
||||
@ -266,6 +293,7 @@ module Assembler6502
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
####
|
||||
## Break an integer into two 8-bit parts
|
||||
|
@ -7,7 +7,7 @@ module Assembler6502
|
||||
|
||||
def self.parse_label(asm_line, address)
|
||||
sanitized = Assembler6502.sanitize_line(asm_line)
|
||||
match_data = sanitized.match(/([A-za-z][A-Za-z0-9]+):/)
|
||||
match_data = sanitized.match(/#{Instruction::Sym}:/)
|
||||
|
||||
unless match_data.nil?
|
||||
_, label = match_data.to_a
|
||||
|
444
scroll.asm
Normal file
444
scroll.asm
Normal file
@ -0,0 +1,444 @@
|
||||
;------------------------------------------------------------------------------
|
||||
; This is a direct port of Michael Martin's tutorial project for NES101
|
||||
;
|
||||
; I believe that tutorial can be found here:
|
||||
; http://hackipedia.org/Platform/Nintendo/NES/tutorial,%20NES%20programming%20101/NES101.html
|
||||
;
|
||||
; I just rewrote it to have something interesting to test my assembler on.
|
||||
; Saf 2015
|
||||
;
|
||||
; Create an iNES header
|
||||
.ines {"prog": 1, "char": 1, "mapper": 0, "mirror": 0}
|
||||
|
||||
; SRAM
|
||||
; I have no way to do this right now, but I need to add
|
||||
; the ability to simply name parts of memory with a sort
|
||||
; of alias, specifically in the zero page where memory
|
||||
; access is quick.
|
||||
; For now, let's just remember that in the zero page:
|
||||
; *dx = $00 ; The speed delta x of the sprite
|
||||
; *a = $01 ; Whether the A button is down
|
||||
; *scroll = $02 ; The scroll amount
|
||||
;
|
||||
; *sprite = $200 ; Some sprite memory
|
||||
; Actually I can probably do this with a .org and label pair
|
||||
|
||||
.org $0200
|
||||
sprite:
|
||||
|
||||
; Main Code Segment
|
||||
.org $C000
|
||||
|
||||
reset:
|
||||
SEI
|
||||
CLD
|
||||
|
||||
; Wait two VBLANKs.
|
||||
wait_vb1:
|
||||
LDA $2002
|
||||
BPL wait_vb1
|
||||
|
||||
wait_vb2:
|
||||
LDA $2002
|
||||
BPL wait_vb2
|
||||
|
||||
|
||||
; Clear out RAM.
|
||||
LDA #$00
|
||||
LDX #$00
|
||||
clear_segments:
|
||||
STA $00, X
|
||||
STA $0100, X
|
||||
STA $0200, X
|
||||
STA $0300, X
|
||||
STA $0400, X
|
||||
STA $0500, X
|
||||
STA $0600, X
|
||||
STA $0700, X
|
||||
INX
|
||||
BNE clear_segments
|
||||
|
||||
|
||||
; Reset the stack pointer.
|
||||
LDX #$FF
|
||||
TXS
|
||||
|
||||
; Disable all graphics.
|
||||
LDA #$00
|
||||
STA $2000
|
||||
STA $2001
|
||||
|
||||
JSR init_graphics
|
||||
JSR init_input
|
||||
JSR init_sound
|
||||
|
||||
; Set basic PPU registers. Load background from $0000,
|
||||
; sprites from $1000, and the name table from $2000.
|
||||
LDA #$88
|
||||
STA $2000
|
||||
LDA #$1E
|
||||
STA $2001
|
||||
CLI
|
||||
|
||||
|
||||
; Transfer control to the VBLANK routines.
|
||||
forever:
|
||||
JMP forever
|
||||
|
||||
init_graphics:
|
||||
JSR init_sprites
|
||||
JSR load_palette
|
||||
JSR load_name_tables
|
||||
JSR init_scrolling
|
||||
RTS
|
||||
|
||||
init_input:
|
||||
; The A button starts out not-pressed.
|
||||
LDA #$00
|
||||
STA $01 ; $01 = A button
|
||||
RTS
|
||||
|
||||
init_sound:
|
||||
; initialize sound hardware
|
||||
LDA #$01
|
||||
STA $4015
|
||||
LDA #$00
|
||||
STA $4001
|
||||
LDA #$40
|
||||
STA $4017
|
||||
RTS
|
||||
|
||||
|
||||
init_sprites:
|
||||
|
||||
; Clear page #2, which we'll use to hold sprite data
|
||||
LDA #$00
|
||||
LDX #$00
|
||||
sprite_clear1:
|
||||
STA $0200, X ; $0200 = sprite
|
||||
INX
|
||||
BNE sprite_clear1
|
||||
|
||||
; initialize Sprite 0
|
||||
LDA #$70
|
||||
STA $0200 ; sprite Y coordinate
|
||||
LDA #$01
|
||||
STA $0201 ; sprite + 1Pattern number
|
||||
STA $0203 ; sprite+3 X coordinate
|
||||
; sprite+2, color, stays 0.
|
||||
|
||||
; Set initial value of dx
|
||||
LDA #$01
|
||||
STA $00 ; dx = $00
|
||||
RTS
|
||||
|
||||
; Load palette into $3F00
|
||||
load_palette:
|
||||
LDA #$3F
|
||||
LDX #$00
|
||||
STA $2006
|
||||
STX $2006
|
||||
loady_loop:
|
||||
LDA palette, X
|
||||
STA $2007
|
||||
INX
|
||||
CPX #$20
|
||||
BNE loady_loop
|
||||
RTS
|
||||
|
||||
; Jam some text into the first name table (at $2400, thanks to mirroring)
|
||||
load_name_tables:
|
||||
LDY #$00
|
||||
LDX #$04
|
||||
LDA #<bg
|
||||
STA $10
|
||||
LDA #>bg
|
||||
STA $11
|
||||
LDA #$24
|
||||
STA $2006
|
||||
LDA #$00
|
||||
STA $2006
|
||||
go_back:
|
||||
LDA ($10), Y
|
||||
STA $2007
|
||||
INY
|
||||
BNE go_back
|
||||
INC $11
|
||||
DEX
|
||||
BNE go_back
|
||||
RTS
|
||||
|
||||
; Clear out the Name Table at $2800 (where we already are. Yay.)
|
||||
LDY #$00
|
||||
LDX #$04
|
||||
LDA #$00
|
||||
back:
|
||||
STA $2007
|
||||
INY
|
||||
BNE back
|
||||
DEX
|
||||
BNE back
|
||||
RTS
|
||||
|
||||
init_scrolling:
|
||||
LDA #$F0
|
||||
STA $02 ; scroll
|
||||
RTS
|
||||
|
||||
update_sprite:
|
||||
LDA #>sprite
|
||||
STA $4014 ; Jam page $200-$2FF into SPR-RAM
|
||||
|
||||
LDA $05 ; sprite+3 Is this right???
|
||||
BEQ hit_left
|
||||
CMP #$F7
|
||||
BNE edge_done
|
||||
; Hit right
|
||||
LDX #$FF
|
||||
STX $00 ; dx
|
||||
JSR high_c
|
||||
JMP edge_done
|
||||
|
||||
|
||||
hit_left:
|
||||
LDX #$01
|
||||
STX $00 ; dx
|
||||
JSR high_c
|
||||
|
||||
edge_done: ; update X and store it.
|
||||
CLC
|
||||
ADC $00 ; dx
|
||||
STA $05 ; sprite+3 Is this right?
|
||||
RTS
|
||||
|
||||
react_to_input:
|
||||
LDA #$01 ; strobe joypad
|
||||
STA $4016
|
||||
LDA #$00
|
||||
STA $4016
|
||||
|
||||
LDA $4016 ; Is the A button down?
|
||||
AND #$01
|
||||
BEQ not_a
|
||||
LDX $01 ; a
|
||||
BNE a_done ; Only react if the A button wasn't down last time.
|
||||
STA $01 ; Store the 1 in local variable 'a' so that we this is
|
||||
JSR reverse_dx ; only called once per press.
|
||||
JMP a_done
|
||||
not_a:
|
||||
STA $01 ; A has been released, so put that zero into 'a'.
|
||||
a_done:
|
||||
LDA $4016 ; B does nothing
|
||||
LDA $4016 ; Select does nothing
|
||||
LDA $4016 ; Start does nothing
|
||||
LDA $4016 ; Up
|
||||
AND #$01
|
||||
BEQ not_up
|
||||
LDX sprite ; Load Y value
|
||||
CPX #$07
|
||||
BEQ not_up ; No going past the top of the screen
|
||||
DEX
|
||||
STX sprite
|
||||
|
||||
not_up: lda $4016 ; Down
|
||||
AND #$01
|
||||
BEQ not_dn
|
||||
LDX sprite
|
||||
CPX #$DF ; No going past the bottom of the screen.
|
||||
BEQ not_dn
|
||||
INX
|
||||
STX sprite
|
||||
not_dn:
|
||||
RTS ; Ignore left and right, we don't use 'em
|
||||
|
||||
reverse_dx:
|
||||
LDA #$FF
|
||||
EOR $00 ; dx
|
||||
CLC
|
||||
ADC #$01
|
||||
STA $00 ; dx
|
||||
JSR low_c
|
||||
RTS
|
||||
|
||||
scroll_screen:
|
||||
LDX #$00 ; Reset VRAM
|
||||
STX $2006
|
||||
STX $2006
|
||||
|
||||
LDX $02 ; scroll ; Do we need to scroll at all?
|
||||
BEQ no_scroll
|
||||
DEX
|
||||
STX $02 ; scroll
|
||||
LDA #$00
|
||||
STA $2005 ; Write 0 for Horiz. Scroll value
|
||||
STX $2005 ; Write the value of 'scroll' for Vert. Scroll value
|
||||
|
||||
no_scroll:
|
||||
RTS
|
||||
|
||||
low_c:
|
||||
PHA
|
||||
LDA #$84
|
||||
STA $4000
|
||||
LDA #$AA
|
||||
STA $4002
|
||||
LDA #$09
|
||||
STA $4003
|
||||
PLA
|
||||
RTS
|
||||
|
||||
high_c:
|
||||
PHA
|
||||
LDA #$86
|
||||
STA $4000
|
||||
LDA #$69
|
||||
STA $4002
|
||||
LDA #$08
|
||||
STA $4003
|
||||
PLA
|
||||
RTS
|
||||
|
||||
|
||||
vblank:
|
||||
JSR scroll_screen
|
||||
JSR update_sprite
|
||||
JSR react_to_input
|
||||
|
||||
irq:
|
||||
RTI
|
||||
|
||||
; palette data
|
||||
palette:
|
||||
.bytes $0E,$00,$0E,$19,$00,$00,$00,$00,$00,$00,$00,$00,$01,$00,$01,$21
|
||||
.bytes $0E,$20,$22,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
|
||||
|
||||
|
||||
; Background data
|
||||
bg:
|
||||
.ascii " "
|
||||
.ascii " "
|
||||
.ascii " SAF'S 6502 NES ASSEMBLER "
|
||||
.ascii " "
|
||||
.ascii " "
|
||||
.ascii " "
|
||||
.ascii " VSS RES "
|
||||
.ascii " RDY PHI2 "
|
||||
.ascii " PH1 S0 "
|
||||
.ascii " IRQ 6 PHI0 "
|
||||
.ascii " NC NC "
|
||||
.ascii " NMI NC "
|
||||
.ascii " SYNC 5 R/W "
|
||||
.ascii " VCC D0 "
|
||||
.ascii " A0 D1 "
|
||||
.ascii " A1 0 D2 "
|
||||
.ascii " A2 D3 "
|
||||
.ascii " A3 D4 "
|
||||
.ascii " A4 2 D5 "
|
||||
.ascii " A5 D6 "
|
||||
.ascii " A6 D7 "
|
||||
.ascii " A7 A15 "
|
||||
.ascii " A8 A14 "
|
||||
.ascii " A9 A13 "
|
||||
.ascii " A10 A12 "
|
||||
.ascii " A11 VSS "
|
||||
.ascii " "
|
||||
.ascii " "
|
||||
.ascii " "
|
||||
.ascii " "
|
||||
|
||||
; Attribute table
|
||||
.bytes $00,$00,$00,$00,$00,$00,$00,$00,
|
||||
.bytes $00,$00,$FF,$FF,$FF,$00,$00,$00,
|
||||
.bytes $00,$00,$FF,$FF,$FF,$00,$00,$00,
|
||||
.bytes $00,$00,$FF,$FF,$FF,$00,$00,$00,
|
||||
.bytes $00,$00,$FF,$FF,$FF,$00,$00,$00,
|
||||
.bytes $00,$00,$FF,$FF,$FF,$00,$00,$00,
|
||||
.bytes $00,$00,$FF,$FF,$FF,$00,$00,$00,
|
||||
.bytes $00,$00,$00,$00,$00,$00,$00,$00,
|
||||
|
||||
|
||||
; Setup the interrupt vectors
|
||||
.org $FFFA ;first of the three vectors starts here
|
||||
.dw vblank ;when an NMI happens (once per frame if enabled) the processor will jump to the label NMI:
|
||||
.dw reset ;when the processor first turns on or is reset, it will jump to the label RESET:
|
||||
.dw irq ;external interrupt IRQ is not used in this tutorial
|
||||
|
||||
|
||||
|
||||
; This is CHR-ROM page 1, which starts at 0x0000, but I'm skipping the first bit
|
||||
; So this is where tile memory is going to go, this is the commodore 64's character ROM
|
||||
; mapped to ASCII for tile numbers. We are only using 4KB of this 8KB page.
|
||||
.org $0200
|
||||
|
||||
.bytes $00,$00,$00,$00,$00,$00,$00,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 32
|
||||
.bytes $18,$18,$18,$18,$00,$00,$18,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 33
|
||||
.bytes $66,$66,$66,$00,$00,$00,$00,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 34
|
||||
.bytes $66,$66,$FF,$66,$FF,$66,$66,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 35
|
||||
.bytes $18,$3E,$60,$3C,$06,$7C,$18,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 36
|
||||
.bytes $62,$66,$0C,$18,$30,$66,$46,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 37
|
||||
.bytes $3C,$66,$3C,$38,$67,$66,$3F,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 38
|
||||
.bytes $06,$0C,$18,$00,$00,$00,$00,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 39
|
||||
.bytes $0C,$18,$30,$30,$30,$18,$0C,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 40
|
||||
.bytes $30,$18,$0C,$0C,$0C,$18,$30,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 41
|
||||
.bytes $00,$66,$3C,$FF,$3C,$66,$00,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 42
|
||||
.bytes $00,$18,$18,$7E,$18,$18,$00,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 43
|
||||
.bytes $00,$00,$00,$00,$00,$18,$18,$30,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 44
|
||||
.bytes $00,$00,$00,$7E,$00,$00,$00,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 45
|
||||
.bytes $00,$00,$00,$00,$00,$18,$18,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 46
|
||||
.bytes $00,$03,$06,$0C,$18,$30,$60,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 47
|
||||
.bytes $3C,$66,$6E,$76,$66,$66,$3C,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 48
|
||||
.bytes $18,$18,$38,$18,$18,$18,$7E,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 49
|
||||
.bytes $3C,$66,$06,$0C,$30,$60,$7E,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 50
|
||||
.bytes $3C,$66,$06,$1C,$06,$66,$3C,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 51
|
||||
.bytes $06,$0E,$1E,$66,$7F,$06,$06,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 52
|
||||
.bytes $7E,$60,$7C,$06,$06,$66,$3C,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 53
|
||||
.bytes $3C,$66,$60,$7C,$66,$66,$3C,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 54
|
||||
.bytes $7E,$66,$0C,$18,$18,$18,$18,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 55
|
||||
.bytes $3C,$66,$66,$3C,$66,$66,$3C,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 56
|
||||
.bytes $3C,$66,$66,$3E,$06,$66,$3C,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 57
|
||||
.bytes $00,$00,$18,$00,$00,$18,$00,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 58
|
||||
.bytes $00,$00,$18,$00,$00,$18,$18,$30,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 59
|
||||
.bytes $0E,$18,$30,$60,$30,$18,$0E,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 60
|
||||
.bytes $00,$00,$7E,$00,$7E,$00,$00,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 61
|
||||
.bytes $70,$18,$0C,$06,$0C,$18,$70,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 62
|
||||
.bytes $3C,$66,$06,$0C,$18,$00,$18,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 63
|
||||
.bytes $3C,$66,$6E,$6E,$60,$62,$3C,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 64
|
||||
.bytes $18,$3C,$66,$7E,$66,$66,$66,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 65
|
||||
.bytes $7C,$66,$66,$7C,$66,$66,$7C,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 66
|
||||
.bytes $3C,$66,$60,$60,$60,$66,$3C,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 67
|
||||
.bytes $78,$6C,$66,$66,$66,$6C,$78,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 68
|
||||
.bytes $7E,$60,$60,$78,$60,$60,$7E,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 69
|
||||
.bytes $7E,$60,$60,$78,$60,$60,$60,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 70
|
||||
.bytes $3C,$66,$60,$6E,$66,$66,$3C,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 71
|
||||
.bytes $66,$66,$66,$7E,$66,$66,$66,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 72
|
||||
.bytes $3C,$18,$18,$18,$18,$18,$3C,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 73
|
||||
.bytes $1E,$0C,$0C,$0C,$0C,$6C,$38,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 74
|
||||
.bytes $66,$6C,$78,$70,$78,$6C,$66,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 75
|
||||
.bytes $60,$60,$60,$60,$60,$60,$7E,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 76
|
||||
.bytes $63,$77,$7F,$6B,$63,$63,$63,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 77
|
||||
.bytes $66,$76,$7E,$7E,$6E,$66,$66,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 78
|
||||
.bytes $3C,$66,$66,$66,$66,$66,$3C,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 79
|
||||
.bytes $7C,$66,$66,$7C,$60,$60,$60,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 80
|
||||
.bytes $3C,$66,$66,$66,$66,$3C,$0E,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 81
|
||||
.bytes $7C,$66,$66,$7C,$78,$6C,$66,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 82
|
||||
.bytes $3C,$66,$60,$3C,$06,$66,$3C,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 83
|
||||
.bytes $7E,$18,$18,$18,$18,$18,$18,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 84
|
||||
.bytes $66,$66,$66,$66,$66,$66,$3C,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 85
|
||||
.bytes $66,$66,$66,$66,$66,$3C,$18,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 86
|
||||
.bytes $63,$63,$63,$6B,$7F,$77,$63,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 87
|
||||
.bytes $66,$66,$3C,$18,$3C,$66,$66,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 88
|
||||
.bytes $66,$66,$66,$3C,$18,$18,$18,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 89
|
||||
.bytes $7E,$06,$0C,$18,$30,$60,$7E,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 90
|
||||
.bytes $3C,$30,$30,$30,$30,$30,$3C,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 91
|
||||
.bytes $0C,$12,$30,$7C,$30,$62,$FC,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 92
|
||||
.bytes $3C,$0C,$0C,$0C,$0C,$0C,$3C,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 93
|
||||
.bytes $00,$18,$3C,$7E,$18,$18,$18,$18,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 94
|
||||
.bytes $00,$10,$30,$7F,$7F,$30,$10,$00,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF ; Character 95
|
||||
|
||||
|
||||
; This is CHR-ROM page 2, which starts at 0x2000, and we put the sprite data here.
|
||||
.org $1000
|
||||
|
||||
.bytes $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ; Character 0: Blank
|
||||
.bytes $18,$24,$66,$99,$99,$66,$24,$18,$00,$18,$18,$66,$66,$18,$18,$00 ; Character 1: Diamond sprite
|
||||
|
Loading…
Reference in New Issue
Block a user