This commit is contained in:
Michael Matuzak 2016-10-02 14:54:14 -07:00
parent 345b844107
commit 8a077f9d66
11 changed files with 673 additions and 0 deletions

329
example.s Normal file
View File

@ -0,0 +1,329 @@
.inesprg 1
.ineschr 1
.inesmap 0
.inesmir 1
.bank 0
.org $C000
RESET:
sei
cld
ldx #$40
stx $4017
ldx #$FF
txs
inx
stx $2000
stx $2001
stx $4010
vblankwait1:
bit $2002
bpl vblankwait1
clrmem:
lda #$00
sta $0000, x
sta $0100, x
sta $0200, x
sta $0400, x
sta $0500, x
sta $0600, x
sta $0700, x
lda #$FE
sta $0300, x
inx
bne clrmem
vblankwait2:
bit $2002
bpl vblankwait2
lda $2002
lda #$3F
sta $2006
lda #$00
sta $2006
ldx #$00
LoadPalettesLoop:
lda PaletteData, x
sta $2007
inx
cpx #$20
bne LoadPalettesLoop
LoadSprites:
ldx #$00
LoadSpritesLoop:
lda sprites, x
sta $0200, x
inx
cpx #$10
bne LoadSpritesLoop
LoadBackgrounds:
lda $2002
lda #$20
sta $2006
lda #$00
sta $2006
ldx #$00
LoadBackground1:
lda background1, x
sta $2007
inx
cpx #$00
bne LoadBackground1
LoadBackground2:
lda background2, x
sta $2007
inx
cpx #$00
bne LoadBackground2
LoadBackground3:
lda background3, x
sta $2007
inx
cpx #$00
bne LoadBackground3
LoadBackground4:
lda background4, x
sta $2007
inx
cpx #$00
bne LoadBackground4
LoadAttribute:
lda $2002
lda #$23
sta $2006
lda #$C0
sta $2006
ldx #$00
LoadAttributeLoop:
lda attribute, x
sta $2007
inx
cpx #$40
bne LoadAttributeLoop
lda #%10010000
sta $2000
lda #%00011110
sta $2001
Forever:
jmp Forever
NMI:
lda #$00
sta $2003
lda #$02
sta $4014
lda #$01
sta $4016
lda #$00
sta $4016
ReadA:
lda $4016
and #%00000001
beq ReadADone
ReadADone:
ReadB:
lda $4016
and #%00000001
beq ReadBDone
ReadBDone:
ReadSel:
lda $4016
and #%00000001
beq ReadSelDone
ReadSelDone:
ReadStart:
lda $4016
and #%00000001
beq ReadStartDone
ReadStartDone:
ReadUp:
lda $4016
and #%00000001
beq ReadUpDone
lda $0200
sec
sbc #$01
sta $0200
lda $0204
sec
sbc #$01
sta $0204
lda $0208
sec
sbc #$01
sta $0208
lda $020C
sec
sbc #$01
sta $020C
ReadUpDone:
ReadDown:
lda $4016
and #%00000001
beq ReadDownDone
lda $0200
clc
adc #$01
sta $0200
lda $0204
clc
adc #$01
sta $0204
lda $0208
clc
adc #$01
sta $0208
lda $020C
clc
adc #$01
sta $020C
ReadDownDone:
ReadLeft:
lda $4016
and #%00000001
beq ReadLeftDone
lda $0203
sec
sbc #$01
sta $0203
lda $0207
sec
sbc #$01
sta $0207
lda $020B
sec
sbc #$01
sta $020B
lda $020F
sec
sbc #$01
sta $020F
ReadLeftDone:
ReadRight:
lda $4016
and #%00000001
beq ReadRightDone
lda $0203
clc
adc #$01
sta $0203
lda $0207
clc
adc #$01
sta $0207
lda $020B
clc
adc #$01
sta $020B
lda $020F
clc
adc #$01
sta $020F
ReadRightDone:
lda #%10010000
sta $2000
lda #%00011110
sta $2001
lda #$00
sta $2005
sta $2005
rti
.bank 1
.org $E000
PaletteData:
.db $22,$29,$1A,$0F,$22,$36,$17,$0F,$22,$30,$21,$0F,$22,$27,$17,$0F
.db $0F,$16,$27,$18,$22,$02,$38,$3C,$22,$1C,$15,$14,$22,$02,$38,$3C
sprites:
.db $80, 112, $0, $80
.db $80, 113, $0, $88
.db $88, 114, $0, $80
.db $88, 115, $0, $88
background1:
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$45,$45,$24,$24,$45,$45,$45,$45,$45,$45,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$53,$54,$24,$24
.db $24,$24,$24,$24,$47,$47,$24,$24,$47,$47,$47,$47,$47,$47,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$55,$56,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
background2:
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$45,$45,$24,$24,$45,$45,$45,$45,$45,$45,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$53,$54,$24,$24
.db $24,$24,$24,$24,$47,$47,$24,$24,$47,$47,$47,$47,$47,$47,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$55,$56,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
background3:
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$45,$45,$24,$24,$45,$45,$45,$45,$45,$45,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$53,$54,$24,$24
.db $24,$24,$24,$24,$47,$47,$24,$24,$47,$47,$47,$47,$47,$47,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$55,$56,$24,$24
.db 17,14,21,21,24,36,32,24,27,21,13,36,36,36,36,36
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
background4:
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$45,$45,$24,$24,$45,$45,$45,$45,$45,$45,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$53,$54,$24,$24
.db $24,$24,$24,$24,$47,$47,$24,$24,$47,$47,$47,$47,$47,$47,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$55,$56,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
.db $24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24,$24
attribute:
.db %00010001, %00010001, %01010101, %00010001, %00010001, %00010001, %00010001, %01110111
.db %00010001, %00010001, %01010101, %00010001, %00010001, %00010001, %00010001, %01110111
.db %00010001, %00010001, %01010101, %00010001, %00010001, %00010001, %00010001, %01110111
.db %00010001, %00010001, %01010101, %00010001, %00010001, %00010001, %00010001, %01110111
.db %00010001, %00010001, %01010101, %00010001, %00010001, %00010001, %00010001, %01110111
.db %00010001, %00010001, %01010101, %00010001, %00010001, %00010001, %00010001, %01110111
.db %00010001, %00010001, %01010101, %00010001, %00010001, %00010001, %00010001, %01110111
.db %00010001, %00010001, %01010101, %00010001, %00010001, %00010001, %00010001, %01110111
.org $FFFA
.dw NMI
.dw RESET
.dw 0
.bank 2
.org $0000
.incbin "mario.chr"

23
index.js Normal file
View File

@ -0,0 +1,23 @@
const mona = require('mona')
const directive = require('./parsers/directive')
const instruction = require('./parsers/instruction')
const label = require('./parsers/label')
function assembler (input) {
return mona.parse(
mona.collect(
mona.or(
directive(),
instruction(),
label(),
mona.eol()
)
),
input
)
}
module.exports = assembler
// const result = mona.parse(mona.collect(assembler()), c)
// console.log(result)

33
package.json Normal file
View File

@ -0,0 +1,33 @@
{
"name": "parser-6502",
"version": "1.0.0",
"description": "Parser for 6502 assembler.",
"main": "index.js",
"dependencies": {
"mona": "^0.9.1"
},
"devDependencies": {
"standard": "^8.1.0",
"tap": "^7.1.2"
},
"scripts": {
"test": "tap test/*.js --cov && standard"
},
"repository": {
"type": "git",
"url": "git+https://github.com/emkay/parser-6502.git"
},
"keywords": [
"parser",
"6502",
"nesly",
"nes",
"assembler"
],
"author": "Michael Matuzak",
"license": "MIT",
"bugs": {
"url": "https://github.com/emkay/parser-6502/issues"
},
"homepage": "https://github.com/emkay/parser-6502#readme"
}

36
parsers/directive.js Normal file
View File

@ -0,0 +1,36 @@
const mona = require('mona')
const parameters = require('./parameters')
function directiveName () {
return mona.oneOf([
'.inesprg',
'.ineschr',
'.inesmap',
'.inesmir',
'.bank',
'.org',
'.db',
'.byte',
'.dw',
'.word',
'.incbin',
'.rsset',
'.rs'
])
}
// <directive> ::= <directive-name> [<spaces> <parameter>]*
function directive () {
return mona.sequence((s) => {
const d = s(directiveName())
const args = s(mona.map((a) => (a[0]), parameters()))
// const nl = s(mona.eol())
return mona.value({
directive: d,
args: args
})
})
}
module.exports = directive

37
parsers/instruction.js Normal file
View File

@ -0,0 +1,37 @@
const mona = require('mona')
const parameters = require('./parameters')
const instructions = [
'adc', 'and', 'asl',
'bcc', 'bcs', 'beq', 'bit', 'bmi', 'bne', 'bpl', 'brk', 'bvc', 'bvs',
'clc', 'cld', 'cli', 'clv', 'cmp', 'cpx', 'cpy',
'dec', 'dex', 'dey',
'eor',
'inc', 'inx', 'iny',
'jmp', 'jsr',
'lda', 'ldx', 'ldy', 'lsr',
'nop',
'ora',
'pha', 'php', 'pla', 'plp',
'rol', 'ror', 'rti', 'rts',
'sbc', 'sec', 'sed', 'sei', 'sta', 'stx', 'sty',
'tax', 'tay', 'tsx', 'txa', 'txs', 'tya'
]
function instructionName () {
return mona.oneOf(instructions)
}
function instruction () {
return mona.sequence((s) => {
const i = s(instructionName())
const args = s(mona.map((a) => (a[0]), parameters()))
// const nl = s(mona.eol())
return mona.value({
instruction: i,
args: args
})
})
}
module.exports = instruction

15
parsers/label.js Normal file
View File

@ -0,0 +1,15 @@
const mona = require('mona')
function label () {
return mona.sequence((s) => {
const label = s(mona.text(mona.alphanum()))
const end = s(mona.string(':'))
const nl = s(mona.eol())
return mona.value({
label: `${label}${end}`
})
})
}
module.exports = label

59
parsers/parameters.js Normal file
View File

@ -0,0 +1,59 @@
const mona = require('mona')
function quotedChar () {
return mona.or(mona.noneOf('"'),
mona.and(mona.string('""'),
mona.value('"')))
}
// pulled out, because in the future, this might be more detailed!
// <parameter> ::= <alphanum>+
function parameter () {
const param = () => {
return mona.or(
mona.join(
mona.string('$'),
mona.alphanum()
),
mona.join(
mona.string('#'),
mona.string('$'),
mona.alphanum()
),
mona.join(
mona.string('#'),
mona.string('%'),
mona.alphanum()
),
mona.join(
mona.string('%'),
mona.alphanum()
),
mona.between(
mona.string('"'),
mona.string('"'),
mona.text(quotedChar())
),
mona.alphanum()
)
}
return mona.text(param(), {min: 1})
}
function parameters () {
return mona.collect(
mona.and(
mona.spaces(),
mona.split(
parameter(),
mona.or(
mona.and(mona.string(','), mona.spaces()),
mona.string(',')
)
)
)
)
}
module.exports = parameters

18
test/assembler.js Normal file
View File

@ -0,0 +1,18 @@
const tap = require('tap')
const parser = require('..')
tap.test('should parse the basics', (t) => {
t.plan(1)
const input = '.org $C000\nRESET:\n'
t.deepEqual(parser(input), [
{
directive: '.org',
args: [
'$,C000'
]
},
{
label: 'RESET:'
}
])
})

86
test/directive.js Normal file
View File

@ -0,0 +1,86 @@
const tap = require('tap')
const mona = require('mona')
const directiveParser = require('../parsers/directive')
tap.test('will parse a directive', (t) => {
t.plan(1)
t.deepEqual(mona.parse(directiveParser(), '.inesprg 1'), {
args: [
'1'
],
directive: '.inesprg'
})
})
tap.test('will parse a directive with direct address', (t) => {
t.plan(1)
t.deepEqual(mona.parse(directiveParser(), '.inesprg $0000'), {
args: [
'$,0000'
],
directive: '.inesprg'
})
})
tap.test('will parse a directive with hex arg', (t) => {
t.plan(1)
t.deepEqual(mona.parse(directiveParser(), '.inesprg #$FE'), {
args: [
'#,$,FE'
],
directive: '.inesprg'
})
})
tap.test('will parse a directive with binary arg', (t) => {
t.plan(2)
t.deepEqual(mona.parse(directiveParser(), '.db %00010001'), {
args: [
'%,00010001'
],
directive: '.db'
})
t.deepEqual(mona.parse(directiveParser(), '.db #%00010001'), {
args: [
'#,%,00010001'
],
directive: '.db'
})
})
tap.test('will parse a directive with multiple args', (t) => {
t.plan(1)
t.deepEqual(mona.parse(directiveParser(), '.db %00010001,%00010001,%00010001,%00010001'), {
args: [
'%,00010001',
'%,00010001',
'%,00010001',
'%,00010001'
],
directive: '.db'
})
})
tap.test('will parse a directive with multiple args with spaces between them', (t) => {
t.plan(1)
t.deepEqual(mona.parse(directiveParser(), '.db %00010001, %00010001, %00010001, %00010001'), {
args: [
'%,00010001',
'%,00010001',
'%,00010001',
'%,00010001'
],
directive: '.db'
})
})
tap.test('will parse a directive with string arg', (t) => {
t.plan(1)
t.deepEqual(mona.parse(directiveParser(), '.incbin "mario.chr"'), {
args: [
'mario.chr'
],
directive: '.incbin'
})
})

27
test/instruction.js Normal file
View File

@ -0,0 +1,27 @@
const tap = require('tap')
const mona = require('mona')
const instructionParser = require('../parsers/instruction')
tap.test('will parse an instruction', (t) => {
t.plan(1)
t.deepEqual(mona.parse(instructionParser(), 'sei'), {
args: null,
instruction: 'sei'
})
})
tap.test('will parse an instruction with args', (t) => {
t.plan(1)
t.deepEqual(mona.parse(instructionParser(), 'stx $2000'), {
args: ['$,2000'],
instruction: 'stx'
})
})
tap.test('will parse an instruction with multiple args', (t) => {
t.plan(1)
t.deepEqual(mona.parse(instructionParser(), 'lda background3, x'), {
args: ['background3', 'x'],
instruction: 'lda'
})
})

10
test/label.js Normal file
View File

@ -0,0 +1,10 @@
const tap = require('tap')
const mona = require('mona')
const labelParser = require('../parsers/label')
tap.test('should parse a label', (t) => {
t.plan(2)
t.deepEqual(mona.parse(labelParser(), 'SOMETHING:'), {
label: 'SOMETHING:'
})
})