Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

leeeetle bit of bug fixing for disasm

  • Loading branch information...
commit a3aaa11ba9985a443e811bc81cba1ac9649fdbe8 1 parent 5f726f5
@robey authored
Showing with 52 additions and 8 deletions.
  1. +23 −7 src/d16bunny/disassembler.coffee
  2. +29 −1 test/test_disassembler.coffee
View
30 src/d16bunny/disassembler.coffee
@@ -8,8 +8,8 @@ class Instruction
# if any of the arguments are labels, use the label name.
resolve: (labels) ->
- if @aArgument? and labels[@aArgument] then @aArgument = labels[@aArgument]
- if @bArgument? and labels[@bArgument] then @bArgument = labels[@bArgument]
+ if @aArgument? and labels[@aArgument]? then @aArgument = labels[@aArgument]
+ if @bArgument? and labels[@bArgument]? then @bArgument = labels[@bArgument]
this
stringify: (x) ->
@@ -93,13 +93,14 @@ class Disassembler
@address = 0
nextWord: ->
- word = @memory[@address]
+ word = @memory[@address] || 0
@address = (@address + 1) % 0x10000
word
nextInstruction: ->
pc = @address
word = @nextWord()
+ if word == 0 then return null
opcode = word & 0x1f
a = (word >> 10) & 0x3f
b = (word >> 5) & 0x1f
@@ -133,14 +134,13 @@ class Disassembler
# first, skip all zeros.
while (@memory[@address] or 0) == 0 and @address < 0x10000 then @address += 1
if @address >= 0x10000 then return []
- if @address > 0
- out.push(".ORG 0x#{@address.toString(16)}")
# also, ignore zeros from the end.
end = 0x10000
while (@memory[end - 1] or 0) == 0 then end -= 1
# now, process all instructions.
while @address < end
- instructions.push(@nextInstruction())
+ x = @nextInstruction()
+ if x? then instructions.push(x)
# build up labels
targets = []
labels = {}
@@ -153,11 +153,27 @@ class Disassembler
# fill in labels
for x in instructions then x.resolve(labels)
# flush
+ start = 0
indent = " "
+ labeled = {}
for x in instructions
- if labels[x.pc]? then out.push(":#{labels[x.pc]}")
+ if x.pc != start
+ if labels[start]?
+ out.push(":#{labels[start]}")
+ labeled[start] = true
+ out.push("")
+ out.push(".ORG 0x#{x.pc.toString(16)}")
+ indent = " "
+ if labels[x.pc]?
+ out.push(":#{labels[x.pc]}")
+ labeled[x.pc] = true
out.push(indent + x.toString(labels))
indent = if x.conditional() then (indent + " ") else " "
+ start = x.pc + x.words
+ # clean up missing labels
+ for address, name of labels
+ if not labeled[address]
+ out.unshift(".DEFINE #{name} 0x#{parseInt(address).toString(16)}")
out
View
30 test/test_disassembler.coffee
@@ -61,7 +61,6 @@ describe "Disassembler", ->
dis1(0x7461).toString().should.eql("SET X, EX")
it "gives up for DAT", ->
- dis1(0).toString().should.eql("DAT 0")
dis1(0xfffd).toString().should.eql("DAT 0xfffd")
describe "finds targets", ->
@@ -109,6 +108,7 @@ describe "Disassembler", ->
it "processes a loop", ->
x = disat(0x200, 0x8862, 0xd476, 0x9383, 0x6381)
x.should.eql([
+ ""
".ORG 0x200"
":t1"
" ADD X, 1"
@@ -130,9 +130,37 @@ describe "Disassembler", ->
it "processes jumps", ->
x = disat(0x2000, 0x7f81, 0x2002, 0x7f81, 0x2000)
x.should.eql([
+ ""
".ORG 0x2000"
":t1"
" SET PC, t2"
":t2"
" SET PC, t1"
])
+
+ it "processes gaps", ->
+ x = disat(0x333, 0xa821, 0xa821, 0, 0, 0xa821, 0)
+ x.should.eql([
+ ""
+ ".ORG 0x333"
+ " SET B, 9"
+ " SET B, 9"
+ ""
+ ".ORG 0x337"
+ " SET B, 9"
+ ])
+
+ it "can handle jumping into the middle of an instruction", ->
+ x = disat(0x3d, 0x3aa9, 0x301, 0x701, 0xb01, 0x413, 0x7c20, 0x3e)
+ x.should.eql([
+ ".DEFINE t1 0x3e"
+ ""
+ ".ORG 0x3d"
+ " MDI [Z + 0x301], [I]"
+ " SET PUSH, B"
+ " SET PUSH, C"
+ " IFN A, B"
+ " JSR t1"
+ ])
+
+
Please sign in to comment.
Something went wrong with that request. Please try again.