asm6502 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b930f2636eba5307b21d5b2c4ae91da53900323ba7014b79e654ca788d16983c
4
+ data.tar.gz: c51fe89160ee92824ad11da37bc79abeeb0bb03a6edcae861a004a07780b89aa
5
+ SHA512:
6
+ metadata.gz: aacc404e4bb1eead3d9388f4b25db223e44276c1abd8f1cd2beb7b10e684025617c2c64085c52ca7b6c0114f617d45fa26a5455c1b3b46a29cf609bba2f05a6e
7
+ data.tar.gz: cdef1cfea165a0c96b07ea4ca8f337d0b81ed459cb38a5a8f87ed0c20517093dda8241c044348cd24c9f0bf6456be3fd688c8c40cce02ed3ed81b60983fec13e
@@ -0,0 +1,7 @@
1
+ *.bin
2
+ *.asm
3
+ *.h
4
+ \#*\#
5
+ build.sh
6
+ main.rb
7
+ *.gem
@@ -0,0 +1,176 @@
1
+ # asm6502
2
+
3
+ Write 6502 assembly with Ruby code.
4
+
5
+ This gem was specifically built to write Atari2600 games and comes packages with some the Ruby equivalent of the `vcs.h` and `macro.h` files. It is also in a very early stage of development and should be considered as a proof of concept. I also tried to make it less than 100 lines of code.
6
+
7
+ ## Installation
8
+
9
+ ```
10
+ gem install asm6502
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ Ruby is quite a powerful language when it comes to building DSL like configuration files... or 6502 assembly. Let's take an example from https://8bitworkshop.com:
16
+
17
+ ```
18
+ ; https://8bitworkshop.com/v3.7.0/?file=examples%2Fplayfield.a&platform=vcs
19
+
20
+ processor 6502
21
+ include "vcs.h"
22
+ include "macro.h"
23
+
24
+ org $f000
25
+
26
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
27
+ ;
28
+ ; We're going to mess with the playfield registers, PF0, PF1 and PF2.
29
+ ; Between them, they represent 20 bits of bitmap information
30
+ ; which are replicated over 40 wide pixels for each scanline.
31
+ ; By changing the registers before each scanline, we can draw bitmaps.
32
+ ;
33
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
34
+
35
+ Counter equ $81
36
+
37
+ Start CLEAN_START
38
+
39
+ NextFrame
40
+ ; This macro efficiently gives us 1 + 3 lines of VSYNC
41
+ VERTICAL_SYNC
42
+
43
+ ; 36 lines of VBLANK
44
+ ldx #36
45
+ LVBlank sta WSYNC
46
+ dex
47
+ bne LVBlank
48
+ ; Disable VBLANK
49
+ stx VBLANK
50
+ ; Set foreground color
51
+ lda #$82
52
+ sta COLUPF
53
+ ; Draw the 192 scanlines
54
+ ldx #192
55
+ lda #0 ; changes every scanline
56
+ ;lda Counter ; uncomment to scroll!
57
+ ScanLoop
58
+ sta WSYNC ; wait for next scanline
59
+ sta PF0 ; set the PF1 playfield pattern register
60
+ sta PF1 ; set the PF1 playfield pattern register
61
+ sta PF2 ; set the PF2 playfield pattern register
62
+ stx COLUBK ; set the background color
63
+ adc #1 ; increment A
64
+ dex
65
+ bne ScanLoop
66
+
67
+ ; Reenable VBLANK for bottom (and top of next frame)
68
+ lda #2
69
+ sta VBLANK
70
+ ; 30 lines of overscan
71
+ ldx #30
72
+ LVOver sta WSYNC
73
+ dex
74
+ bne LVOver
75
+
76
+ ; Go back and do another frame
77
+ inc Counter
78
+ jmp NextFrame
79
+
80
+ org $fffc
81
+ .word Start
82
+ .word Start
83
+ ```
84
+
85
+ The same code written using asm6502 will be something like:
86
+
87
+ ```ruby
88
+ require "asm6502"
89
+ include Asm6502
90
+
91
+ require 'asm6502/vcs'
92
+
93
+ # We're going to mess with the playfield registers, PF0, PF1 and PF2.
94
+ # Between them, they represent 20 bits of bitmap information
95
+ # which are replicated over 40 wide pixels for each scanline.
96
+ # By changing the registers before each scanline, we can draw bitmaps.
97
+
98
+ Org[0x0080]
99
+ Label[:counter, 1]
100
+
101
+ Output[ARGV[0]] do
102
+ Org[0xf000]
103
+ Label[:reset]
104
+
105
+ clean_start
106
+
107
+ Label[:next_frame]
108
+ # This macro efficiently gives us 1 + 3 lines of VSYNC
109
+ vertical_sync
110
+
111
+ # 36 lines of VBLANK
112
+ ldx 36
113
+
114
+ Label[:lv_blank]
115
+
116
+ sta :WSYNC
117
+ dex
118
+ bne :lv_blank
119
+
120
+ # Disable VBLANK
121
+ stx :VBLANK
122
+
123
+ # Set foreground color
124
+ lda 0x82
125
+ sta :COLUPF
126
+
127
+ # Draw the 192 scanline
128
+ ldx 192
129
+ lda 0 # changes every scanline
130
+
131
+ Label[:scan_loop]
132
+
133
+ sta :WSYNC # wait for next scanline
134
+ sta :PF0 # set the PF0 playfield pattern register
135
+ sta :PF1 # set the PF1 playfield pattern register
136
+ sta :PF2 # set the PF1 playfield pattern register
137
+ stx :COLUBK # set the background color
138
+ adc 1 # increment A
139
+ dex
140
+ bne :scan_loop
141
+
142
+ # Reenable VBLANK for bottom (and top of next fram
143
+ lda 2
144
+ sta :VBLANK
145
+
146
+ # 30 lines of overscan
147
+ ldx 30
148
+
149
+ Label[:lv_over]
150
+ sta :WSYNC
151
+ dex
152
+ bne :lv_over
153
+
154
+ # Go back and do another frame
155
+ inc :counter
156
+ jmp :next_frame
157
+
158
+ Org[0xfffa]
159
+
160
+ Mem[2] = :reset
161
+ Mem[2] = :reset
162
+ Mem[2] = :reset
163
+ end
164
+ ```
165
+
166
+ As you can see, even though it looks like assembly, it it actually Ruby code: each operator is a Ruby fonction and there's also a few control stuff:
167
+
168
+ * `Org[addr]`: set the current memory index.
169
+ * `Label[name, size = 0]`: Give a name to the current memory index and increase it by `size`.
170
+ * `Output[path] { actual code to output }`: Everything in the block will be written in the final file `path`.
171
+ * `Mem[size] = value`: set the memory at the current memory index to value and increases it by `size`.
172
+
173
+ ## Disclaimer
174
+
175
+ This is just a proof and concept, I'm not sure everything works properly, I'm not sure about the way it works and I'm pretty certain it doesn't handle every use case. I'll try later to build an actual game from scratch with it.
176
+
@@ -0,0 +1,9 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "asm6502"
3
+ s.version = "0.1.1"
4
+ s.author = "Gallimimus"
5
+ s.date = %q{2020-12-31}
6
+ s.summary = %q{Write 6502 assembly from Ruby code}
7
+ s.files = `git ls-files -z`.split("\x0")
8
+ s.require_paths = ["lib"]
9
+ end
@@ -0,0 +1,97 @@
1
+ module Asm6502
2
+ X, Y = [ 'x', 'y' ]
3
+ @@org = 0
4
+ @@labels = {}
5
+ @@mem = []
6
+
7
+ class Label
8
+ def self.[](value, size = 0)
9
+ @@labels[value] = @@org
10
+ @@org += size
11
+ end
12
+ end
13
+
14
+ class Org
15
+ def self.[](value) @@org = value; end
16
+ end
17
+
18
+ class Output
19
+ def self.[](path, &block)
20
+ File.open(path, 'w+') do |f|
21
+ @@mem = []
22
+ block.call
23
+ f.write(@@mem.drop_while(&:nil?).reverse.drop_while(&:nil?).reverse.map(&:to_i).pack("c*"))
24
+ end
25
+ end
26
+ end
27
+
28
+ class Mem < Struct.new(:length, :value)
29
+ def self.[]=(length, value)
30
+ value = value.kind_of?(Symbol) ? @@labels[value] : value
31
+ sprintf("%0#{value.size * 8 + 2}b", value)[2..-1].scan(/.{8}/).last(length).map { |i| i.to_i(2) }.reverse.each_with_index do |digit, index|
32
+ @@mem[@@org + index] = digit
33
+ end
34
+ @@org += length
35
+ end
36
+ end
37
+
38
+ {
39
+ adc: { im: 0x69, zp: 0x65, zx: 0x75, ab: 0x6d, ax: 0x7d, ay: 0x79, ix: 0x61, iy: 0x71 },
40
+ and: { im: 0x29, zp: 0x25, zx: 0x35, ab: 0x2d, ax: 0x3d, ay: 0x39, ix: 0x21, iy: 0x31 },
41
+ sbc: { im: 0xe9, zp: 0xe5, zx: 0xf5, ab: 0xed, ax: 0xfd, ay: 0xf9, ix: 0xe1, iy: 0xf1 },
42
+ asl: { ac: 0x0a, zp: 0x06, zx: 0x16, ab: 0x0e, ax: 0x1e }, bit: { zp: 0x24, ab: 0x2c },
43
+ cmp: { im: 0xc9, zp: 0xc5, zx: 0xd5, ab: 0xcd, ax: 0xdd, ay: 0xd9, ix: 0xc1, iy: 0xd1 },
44
+ cpx: { im: 0xe0, zp: 0xe4, ab: 0xec }, cpy: { im: 0xc0, zp: 0xc4, ab: 0xcc },
45
+ dec: { zp: 0xc6, zx: 0xd6, ab: 0xce, ax: 0xde },
46
+ ldx: { im: 0xa2, zp: 0xa6, zy: 0xb6, ab: 0xae, ay: 0xbe },
47
+ ldy: { im: 0xa0, zp: 0xa4, zx: 0xb4, ab: 0xac, ax: 0xbc },
48
+ eor: { im: 0x49, zp: 0x45, zx: 0x55, ab: 0x4d, ax: 0x5d, ay: 0x59, ix: 0x41, iy: 0x51 },
49
+ inc: { zp: 0xe6, zx: 0xf6, ab: 0xee, ax: 0xfe },
50
+ jmp: { ab: 0x4c, in: 0x6c }, sr: { ab: 0x20 }, lsr: { ac: 0x4a, zx: 0x46, ab: 0x4e, ax: 0x5e },
51
+ lda: { im: 0xa9, zp: 0xa5, zx: 0xb5, ab: 0xad, ax: 0xbd, ay: 0xb9, ix: 0xa1, iy: 0xb1 },
52
+ ora: { im: 0x09, zp: 0x05, zx: 0x15, ab: 0x0d, ax: 0x1d, ay: 0x19, ix: 0x01, iy: 0x11 },
53
+ rol: { ac: 0x2a, zp: 0x26, zx: 0x36, ab: 0x2e, ax: 0x3e },
54
+ ror: { ac: 0x6a, zp: 0x66, zx: 0x76, ab: 0x6e, ax: 0x7e },
55
+ sty: { zp: 0x84, zx: 0x94, ab: 0x8c }, stx: { zp: 0x86, zy: 0x96, ab: 0x8e },
56
+ sta: { zp: 0x85, zx: 0x95, ab: 0x8d, ax: 0x9d, ay: 0x99, ix: 0x81, iy: 0x91 },
57
+ bpl: { rl: 0x10 }, bmi: { rl: 0x30 }, bvc: { rl: 0x50 }, bne: { rl: 0xd0 },
58
+ bvs: { rl: 0x70 }, bcc: { rl: 0x90 }, bcs: { rl: 0xb0 }, beq: { rl: 0xf0 },
59
+ brk: 0x00, nop: 0xea, rti: 0x40, clc: 0x18, sec: 0x38, cli: 0x58, sei: 0x78, clv: 0xb8,
60
+ cld: 0xd8, sed: 0xf8, txs: 0x9a, tsx: 0xba, pha: 0x48, rts: 0x60, pla: 0x68, php: 0x08,
61
+ plp: 0x28, tax: 0xaa, txa: 0x8a, dex: 0xca, inx: 0xe8, tay: 0xa8, tya: 0x98, dey: 0x88, iny: 0xc8
62
+ }.each do |opcode, modes|
63
+ define_method(opcode) do |*args|
64
+ if args[0].nil? && modes.kind_of?(Integer)
65
+ [ modes ]
66
+ elsif modes[:ac] && args[0].nil?
67
+ [ modes[:ac] ]
68
+ elsif modes[:rl] && args[0].kind_of?(Symbol)
69
+ [ modes[:rl], @@labels[args[0]] - @@org - 2 ]
70
+ elsif modes[:im] && args[0].kind_of?(Integer) && args[0] < 0xff
71
+ [ modes[:im], args[0] ]
72
+ elsif modes[:zp] && args[0].kind_of?(Symbol) && @@labels[args[0]] < 0xff && args[1].nil?
73
+ [ modes[:zp], @@labels[args[0]] ]
74
+ elsif modes[:zx] && args[0].kind_of?(Symbol) && @@labels[args[0]] < 0xff && args[1].eql?(X)
75
+ [ modes[:zx], @@labels[args[0]] ]
76
+ elsif modes[:ab] && args[0].kind_of?(Symbol) && args[1].nil?
77
+ [ modes[:ab], @@labels[args[0]] & 0xff, @@labels[args[0]] >> 8 & 0xff ]
78
+ elsif modes[:ax] && args[0].kind_of?(Symbol) && args[1].eql?(X)
79
+ [ modes[:ax], @@labels[args[0]] & 0xff, @@labels[args[0]] >> 8 & 0xff ]
80
+ elsif modes[:ay] && args[0].kind_of?(Symbol) && args[1].eql?(Y)
81
+ [ modes[:ay], @@labels[args[0]] & 0xff, @@labels[args[0]] >> 8 & 0xff ]
82
+ elsif modes[:ix] && args[0].kind_of?(Array) && args[0].length == 2 && args[0][0].kind_of?(Symbol) && args[0][1].eql?(X) && args[1].nil?
83
+ [ modes[:ix], @@labels[args[0][0]] & 0xff ]
84
+ elsif modes[:iy] && args[0].kind_of?(Array) && args[0].length == 1 && args[0][0].kind_of?(Symbol) && args[1].eql?(Y)
85
+ [ modes[:iy], @@labels[args[0][0]] & 0xff ]
86
+ elsif modes[:in] && args[0].kind_of?(Array) && args[0].length == 1 && args[0][0].kind_of?(Symbol)
87
+ [ modes[:in], @@labels[args[0][0]] & 0xff, @@labels[args[0][0]] >> 8 & 0xff ]
88
+ else
89
+ raise ArgumentError.new("No suitable mode found for '#{opcode} #{args.join(" ")}'")
90
+ end.each do |opi|
91
+ Mem[1] = opi
92
+ end
93
+ rescue => error
94
+ raise ArgumentError.new("Unexpected error on '#{opcode} #{args.join(" ")}': #{error}")
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,2 @@
1
+ require 'asm6502/vcs/vcs'
2
+ require 'asm6502/vcs/macro'
@@ -0,0 +1,157 @@
1
+ # MACRO.H
2
+ # Version 1.06, 3/SEPTEMBER/2004
3
+
4
+ VERSION_MACRO = 106
5
+
6
+ #
7
+ # THIS FILE IS EXPLICITLY SUPPORTED AS A DASM-PREFERRED COMPANION FILE
8
+ # PLEASE DO *NOT* REDISTRIBUTE MODIFIED VERSIONS OF THIS FILE!
9
+ #
10
+ # This file defines DASM macros useful for development for the Atari 2600.
11
+ # It is distributed as a companion machine-specific support package
12
+ # for the DASM compiler. Updates to this file, DASM, and associated tools are
13
+ # available at at http://www.atari2600.org/dasm
14
+ #
15
+ # Many thanks to the people who have contributed. If you take issue with the
16
+ # contents, or would like to add something, please write to me
17
+ # (atari2600@taswegian.com) with your contribution.
18
+ #
19
+ # Latest Revisions...
20
+ #
21
+ # 1.06 03/SEP/2004 - nice revision of VERTICAL_BLANK (Edwin Blink)
22
+ # 1.05 14/NOV/2003 - Added VERSION_MACRO equate (which will reflect 100x version #)
23
+ # This will allow conditional code to verify MACRO.H being
24
+ # used for code assembly.
25
+ # 1.04 13/NOV/2003 - SET_POINTER macro added (16-bit address load)
26
+ #
27
+ # 1.03 23/JUN/2003 - CLEAN_START macro added - clears TIA, RAM, registers
28
+ #
29
+ # 1.02 14/JUN/2003 - VERTICAL_SYNC macro added
30
+ # (standardised macro for vertical synch code)
31
+ # 1.01 22/MAR/2003 - SLEEP macro added.
32
+ # - NO_ILLEGAL_OPCODES switch implemented
33
+ # 1.0 22/MAR/2003 Initial release
34
+
35
+ # Note: These macros use illegal opcodes. To disable illegal opcode usage,
36
+ # define the symbol NO_ILLEGAL_OPCODES (-DNO_ILLEGAL_OPCODES=1 on command-line).
37
+ # If you do not allow illegal opcode usage, you must include this file
38
+ # *after* including VCS.H (as the non-illegal opcodes access hardware
39
+ # registers and require them to be defined first).
40
+
41
+ # Available macros...
42
+ # SLEEP n - sleep for n cycles
43
+ # VERTICAL_SYNC - correct 3 scanline vertical synch code
44
+ # CLEAN_START - set machine to known state on startup
45
+ # SET_POINTER - load a 16-bit absolute to a 16-bit variable
46
+
47
+ #-------------------------------------------------------------------------------
48
+ # SLEEP duration
49
+ # Original author: Thomas Jentzsch
50
+ # Inserts code which takes the specified number of cycles to execute. This is
51
+ # useful for code where precise timing is required.
52
+ # ILLEGAL-OPCODE VERSION DOES NOT AFFECT FLAGS OR REGISTERS.
53
+ # LEGAL OPCODE VERSION MAY AFFECT FLAGS
54
+ # Uses illegal opcode (DASM 2.20.01 onwards).
55
+
56
+ def sleep(cycles) #usage: sleep n (n>1)
57
+ if cycles < 2
58
+ puts "MACRO ERROR: 'SLEEP': Duration must be > 1"
59
+ exit 1
60
+ end
61
+
62
+ if cycles & 1
63
+ bit :VSYNC
64
+ end
65
+
66
+ cycles -= 3
67
+
68
+ (cycles / 2).times do
69
+ nop
70
+ end
71
+ end
72
+
73
+ #-------------------------------------------------------------------------------
74
+ # VERTICAL_SYNC
75
+ # revised version by Edwin Blink -- saves bytes!
76
+ # Inserts the code required for a proper 3 scanline vertical sync sequence
77
+ # Note: Alters the accumulator
78
+
79
+ # OUT: A = 0
80
+
81
+ def vertical_sync
82
+ lda 0b1110 #%1110 # each '1' bits generate a VSYNC ON line (bits 1..3)
83
+ Label[:VSLP1]
84
+ sta :WSYNC # 1st '0' bit resets Vsync, 2nd '0' bit exit loop
85
+ sta :VSYNC
86
+ lsr
87
+ bne :VSLP1 # branch until VYSNC has been reset
88
+
89
+ end
90
+
91
+ #-------------------------------------------------------------------------------
92
+ # CLEAN_START
93
+ # Original author: Andrew Davie
94
+ # Standardised start-up code, clears stack, all TIA registers and RAM to 0
95
+ # Sets stack pointer to $FF, and all registers to 0
96
+ # Sets decimal mode off, sets interrupt flag (kind of un-necessary)
97
+ # Use as very first section of code on boot (ie: at reset)
98
+ # Code written to minimise total ROM usage - uses weird 6502 knowledge :)
99
+
100
+ def clean_start
101
+ sei
102
+ cld
103
+
104
+ ldx 0
105
+ txa
106
+ tay
107
+ Label[:CLEAR_STACK]
108
+ dex
109
+ txs
110
+ pha
111
+ bne :CLEAR_STACK # SP=$FF, X = A = Y = 0
112
+
113
+ end
114
+
115
+ #-------------------------------------------------------
116
+ # SET_POINTER
117
+ # Original author: Manuel Rotschkar
118
+ #
119
+ # Sets a 2 byte RAM pointer to an absolute address.
120
+ #
121
+ # Usage: SET_POINTER pointer, address
122
+ # Example: SET_POINTER SpritePTR, SpriteData
123
+ #
124
+ # Note: Alters the accumulator, NZ flags
125
+ # IN 1: 2 byte RAM location reserved for pointer
126
+ # IN 2: absolute address
127
+
128
+ def set_pointer(pointer, address)
129
+ LDA #<.ADDRESS # Get Lowbyte of Address
130
+ STA .POINTER # Store in pointer
131
+ LDA #>.ADDRESS # Get Hibyte of Address
132
+ STA .POINTER+1 # Store in pointer+1
133
+ end
134
+
135
+ #-------------------------------------------------------
136
+ # BOUNDARY byte#
137
+ # Original author: Denis Debro (borrowed from Bob Smith / Thomas)
138
+ #
139
+ # Push data to a certain position inside a page and keep count of how
140
+ # many free bytes the programmer will have.
141
+ #
142
+ # eg: BOUNDARY 5 # position at byte #5 in page
143
+
144
+ # .FREE_BYTES SET 0
145
+ # MAC BOUNDARY
146
+ # REPEAT 256
147
+ # IF <. % {1} = 0
148
+ # MEXIT
149
+ # ELSE
150
+ # .FREE_BYTES SET .FREE_BYTES + 1
151
+ # .byte $00
152
+ # ENDIF
153
+ # REPEND
154
+ # ENDM
155
+
156
+
157
+ # EOF
@@ -0,0 +1,91 @@
1
+ require "asm6502"
2
+ include Asm6502
3
+
4
+ TIA_BASE_ADDRESS = 0
5
+ TIA_BASE_READ_ADDRESS = TIA_BASE_ADDRESS
6
+ TIA_BASE_WRITE_ADDRESS = TIA_BASE_ADDRESS
7
+
8
+ Org[TIA_BASE_WRITE_ADDRESS]
9
+
10
+ Label[:VSYNC, 1] # $00 0000 00x0 Vertical Sync Set-Clear
11
+ Label[:VBLANK, 1] # $01 xx00 00x0 Vertical Blank Set-Clear
12
+ Label[:WSYNC, 1] # $02 ---- ---- Wait for Horizontal Blank
13
+ Label[:RSYNC, 1] # $03 ---- ---- Reset Horizontal Sync Counter
14
+ Label[:NUSIZ0, 1] # $04 00xx 0xxx Number-Size player/missle 0
15
+ Label[:NUSIZ1, 1] # $05 00xx 0xxx Number-Size player/missle 1
16
+ Label[:COLUP0, 1] # $06 xxxx xxx0 Color-Luminance Player 0
17
+ Label[:COLUP1, 1] # $07 xxxx xxx0 Color-Luminance Player 1
18
+ Label[:COLUPF, 1] # $08 xxxx xxx0 Color-Luminance Playfield
19
+ Label[:COLUBK, 1] # $09 xxxx xxx0 Color-Luminance Background
20
+ Label[:CTRLPF, 1] # $0A 00xx 0xxx Control Playfield, Ball, Collisions
21
+ Label[:REFP0, 1] # $0B 0000 x000 Reflection Player 0
22
+ Label[:REFP1, 1] # $0C 0000 x000 Reflection Player 1
23
+ Label[:PF0, 1] # $0D xxxx 0000 Playfield Register Byte 0
24
+ Label[:PF1, 1] # $0E xxxx xxxx Playfield Register Byte 1
25
+ Label[:PF2, 1] # $0F xxxx xxxx Playfield Register Byte 2
26
+ Label[:RESP0, 1] # $10 ---- ---- Reset Player 0
27
+ Label[:RESP1, 1] # $11 ---- ---- Reset Player 1
28
+ Label[:RESM0, 1] # $12 ---- ---- Reset Missle 0
29
+ Label[:RESM1, 1] # $13 ---- ---- Reset Missle 1
30
+ Label[:RESBL, 1] # $14 ---- ---- Reset Ball
31
+ Label[:AUDC0, 1] # $15 0000 xxxx Audio Control 0
32
+ Label[:AUDC1, 1] # $16 0000 xxxx Audio Control 1
33
+ Label[:AUDF0, 1] # $17 000x xxxx Audio Frequency 0
34
+ Label[:AUDF1, 1] # $18 000x xxxx Audio Frequency 1
35
+ Label[:AUDV0, 1] # $19 0000 xxxx Audio Volume 0
36
+ Label[:AUDV1, 1] # $1A 0000 xxxx Audio Volume 1
37
+ Label[:GRP0, 1] # $1B xxxx xxxx Graphics Register Player 0
38
+ Label[:GRP1, 1] # $1C xxxx xxxx Graphics Register Player 1
39
+ Label[:ENAM0, 1] # $1D 0000 00x0 Graphics Enable Missle 0
40
+ Label[:ENAM1, 1] # $1E 0000 00x0 Graphics Enable Missle 1
41
+ Label[:ENABL, 1] # $1F 0000 00x0 Graphics Enable Ball
42
+ Label[:HMP0, 1] # $20 xxxx 0000 Horizontal Motion Player 0
43
+ Label[:HMP1, 1] # $21 xxxx 0000 Horizontal Motion Player 1
44
+ Label[:HMM0, 1] # $22 xxxx 0000 Horizontal Motion Missle 0
45
+ Label[:HMM1, 1] # $23 xxxx 0000 Horizontal Motion Missle 1
46
+ Label[:HMBL, 1] # $24 xxxx 0000 Horizontal Motion Ball
47
+ Label[:VDELP0, 1] # $25 0000 000x Vertical Delay Player 0
48
+ Label[:VDELP1, 1] # $26 0000 000x Vertical Delay Player 1
49
+ Label[:VDELBL, 1] # $27 0000 000x Vertical Delay Ball
50
+ Label[:RESMP0, 1] # $28 0000 00x0 Reset Missle 0 to Player 0
51
+ Label[:RESMP1, 1] # $29 0000 00x0 Reset Missle 1 to Player 1
52
+ Label[:HMOVE, 1] # $2A ---- ---- Apply Horizontal Motion
53
+ Label[:HMCLR, 1] # $2B ---- ---- Clear Horizontal Move Registers
54
+ Label[:CXCLR, 1] # $2C ---- ---- Clear Collision Latches
55
+
56
+ Org[TIA_BASE_READ_ADDRESS]
57
+
58
+ Label[:CXM0P, 1] # $00 xx00 0000 Read Collision M0-P1 M0-P0
59
+ Label[:CXM1P, 1] # $01 xx00 0000 M1-P0 M1-P1
60
+ Label[:CXP0FB, 1] # $02 xx00 0000 P0-PF P0-BL
61
+ Label[:CXP1FB, 1] # $03 xx00 0000 P1-PF P1-BL
62
+ Label[:CXM0FB, 1] # $04 xx00 0000 M0-PF M0-BL
63
+ Label[:CXM1FB, 1] # $05 xx00 0000 M1-PF M1-BL
64
+ Label[:CXBLPF, 1] # $06 x000 0000 BL-PF -----
65
+ Label[:CXPPMM, 1] # $07 xx00 0000 P0-P1 M0-M1
66
+ Label[:INPT0, 1] # $08 x000 0000 Read Pot Port 0
67
+ Label[:INPT1, 1] # $09 x000 0000 Read Pot Port 1
68
+ Label[:INPT2, 1] # $0A x000 0000 Read Pot Port 2
69
+ Label[:INPT3, 1] # $0B x000 0000 Read Pot Port 3
70
+ Label[:INPT4, 1] # $0C x000 0000 Read Input (Trigger) 0
71
+ Label[:INPT5, 1] # $0D x000 0000 Read Input (Trigger) 1
72
+
73
+ Org[0x280]
74
+
75
+ Label[:SWCHA, 1] # $280 Port A data register for joysticks:
76
+ # Bits 4-7 for player 1. Bits 0-3 for player 2.
77
+
78
+ Label[:SWACNT, 1] # $281 Port A data direction register (DDR)
79
+ Label[:SWCHB, 1] # $282 Port B data (console switches)
80
+ Label[:SWBCNT, 1] # $283 Port B DDR
81
+ Label[:INTIM, 1] # $284 Timer output
82
+
83
+ Label[:TIMINT, 1] # $285
84
+
85
+ # Unused/undefined registers ($285-$294)
86
+ Label[nil, 14]
87
+
88
+ Label[:TIM1T, 1] # $294 set 1 clock interval
89
+ Label[:TIM8T, 1] # $295 set 8 clock interval
90
+ Label[:TIM64T, 1] # $296 set 64 clock interval
91
+ Label[:T1024T, 1] # $297 set 1024 clock interval
metadata ADDED
@@ -0,0 +1,48 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: asm6502
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Gallimimus
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-12-31 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email:
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - ".gitignore"
20
+ - README.md
21
+ - asm6502.gemspec
22
+ - lib/asm6502.rb
23
+ - lib/asm6502/vcs.rb
24
+ - lib/asm6502/vcs/macro.rb
25
+ - lib/asm6502/vcs/vcs.rb
26
+ homepage:
27
+ licenses: []
28
+ metadata: {}
29
+ post_install_message:
30
+ rdoc_options: []
31
+ require_paths:
32
+ - lib
33
+ required_ruby_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ required_rubygems_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ requirements: []
44
+ rubygems_version: 3.0.3
45
+ signing_key:
46
+ specification_version: 4
47
+ summary: Write 6502 assembly from Ruby code
48
+ test_files: []