Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
621 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
#!/usr/bin/env ruby | ||
|
||
begin | ||
require 'dcpu16' | ||
rescue LoadError | ||
$LOAD_PATH.unshift(File.expand_path("../../lib", __FILE__)) | ||
require 'dcpu16' | ||
end | ||
|
||
if ARGV.length == 1 | ||
filename = ARGV[0] | ||
if filename.end_with?(".o") | ||
dump = File.open(filename, "rb").read.unpack("S>*") | ||
else | ||
require 'tempfile' | ||
file = File.open(filename) | ||
assembler = DCPU16::Assembler.new(file.read) | ||
tmp_file = Tempfile.new("obj") | ||
assembler.write(tmp_file.path) | ||
dump = tmp_file.read.unpack("S>*") | ||
end | ||
debugger = DCPU16::Debugger.new(dump) | ||
debugger.run | ||
elsif ARGV.length == 2 | ||
file = File.open(ARGV[0]) | ||
assembler = DCPU16::Assembler.new(file.read) | ||
assembler.write(ARGV[1]) | ||
else | ||
puts "Usage: dcpu16 <input> <output>" | ||
exit | ||
end | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
[0x7c21, 0x0030, 0x8011, 0x0911, 0x8000, 0x8412, 0x05fe, 0x0300, 0x7dc1, 0x0003, 0x8422, 0x09fe, 0x007b, 0x7dc1, 0x0002,0000] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
; Patrick Helm, deradon87@gmail.com | ||
; | ||
; Flash Screen with chars (Benchmark) | ||
; | ||
; Output: | ||
; * Cycle: 519002 (Cycle needed to finish) | ||
; * Clock: 100000 (Clock-Speed of CPU [defined]) | ||
; * HZ: 99999.02 (Clock-Speed of CPU [real]) | ||
|
||
SET C, 0x30 ; Init OuterLoop | ||
:outer_loop SET B, 0 ; Init InnerLoop | ||
:inner_loop SET [0x8000+B], C ;draw | ||
ADD B, 1 | ||
IFG 0x0300, B | ||
SET PC, inner_loop ;jmp inner_loop | ||
|
||
ADD C,1 | ||
IFG 0x7B, C | ||
SET PC, outer_loop ;jmp outer_loop | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,33 +1,275 @@ | ||
# WIP | ||
# Taken from: https://github.com/dcpu16/dcpu16-rb/blob/master/asm.rb | ||
module DCPU16 | ||
class Assembler | ||
class Instruction | ||
attr_accessor :inst, :a, :b | ||
attr_reader :num, :line | ||
|
||
def initialize(num, line) | ||
@num, @line = num, line | ||
@inst, @a, @b = 0, 0, 0 | ||
@extensions = [] | ||
@references = [] | ||
end | ||
|
||
def extend(value) | ||
# Check value against max int | ||
@extensions << value | ||
end | ||
|
||
def reference(label) | ||
@references[@extensions.size] = label | ||
@extensions << 0 # Placeholder | ||
end | ||
|
||
def resolve(labels) | ||
@references.each_with_index do |label, i| | ||
next unless label | ||
location = labels[label] | ||
error("Cannot find label #{label} in #{labels.keys.join(", ")}") unless location | ||
@extensions[i] = location | ||
end | ||
end | ||
|
||
def word | ||
@inst + (@a << 4) + (@b << 10) | ||
end | ||
|
||
def words | ||
[word] + @extensions.dup | ||
end | ||
|
||
def bytes | ||
words.map{|w| [w].pack('n') }.join("") | ||
end | ||
|
||
def size | ||
@extensions.size + 1 | ||
end | ||
|
||
def hex(w) | ||
"%04x" % w | ||
end | ||
|
||
def to_s | ||
"#{@num}: #{words.map{|w| hex(w)}.join(" ")}" # ; #{line}" | ||
end | ||
|
||
def error(message) | ||
raise Exception.new("Line #{num}: #{message}\n#{line}") | ||
end | ||
end | ||
|
||
|
||
|
||
def self.declare(map, start, string) | ||
count = start | ||
string.split(" ").each do |token| | ||
map[token] = count | ||
count += 1 | ||
end | ||
end | ||
|
||
HEX_RE = /^0x[0-9a-fA-F]+$/ | ||
INT_RE = /^\d+$/ | ||
REG_RE = /^[A-Z]+$/ | ||
LABEL_RE = /^[a-z_]+$/ | ||
INDIRECT_RE = /^\[.+\]/ | ||
INDIRECT_OFFSET_RE = /^[^+]+\+[^+]+$/ | ||
|
||
EXT_PREFIX = 0 | ||
|
||
INDIRECT = 0x08 | ||
INDIRECT_OFFSET = 0x10 | ||
INDIRECT_NEXT = 0x1e | ||
NEXT = 0x1f | ||
LITERAL = 0x20 | ||
|
||
INSTRUCTIONS = {} | ||
EXTENDED_INSTRUCTIONS = {} | ||
VALUES = {} | ||
|
||
declare(INSTRUCTIONS, 1, "SET ADD SUB MUL DIV MOD SHL SHR AND BOR XOR IFE IFN IFG IFB") | ||
declare(EXTENDED_INSTRUCTIONS, 1, "JSR") | ||
declare(VALUES, 0, "A B C X Y Z I J") | ||
declare(VALUES, 0x18, "POP PEEK PUSH SP PC O") | ||
|
||
attr_reader :input | ||
def initialize(text) | ||
@input = text | ||
def initialize(input) | ||
@body = [] | ||
@label_these = [] | ||
@input = input | ||
self.assemble | ||
end | ||
|
||
def clean(line) | ||
line.gsub(/;.*/, "").gsub(/,/, " ").gsub(/\s+/, " ").strip | ||
end | ||
|
||
def dehex(token) | ||
return token.hex.to_s if HEX_RE === token | ||
token | ||
end | ||
|
||
def parse_value(token, op) | ||
token = dehex(token) | ||
|
||
case token | ||
when INT_RE | ||
value = token.to_i | ||
return LITERAL + value if value <= 31 | ||
op.extend value | ||
return NEXT | ||
|
||
when REG_RE | ||
return VALUES[token] | ||
|
||
when LABEL_RE | ||
op.reference(token) | ||
return NEXT | ||
|
||
when INDIRECT_RE | ||
inner = dehex(token[1..-2]) | ||
case inner | ||
when INT_RE | ||
value = inner.to_i | ||
op.extend value | ||
return INDIRECT_NEXT | ||
|
||
when REG_RE | ||
reg = VALUES[inner] | ||
op.error("Can't use indirect addressing on non-basic reg #{reg}") unless reg <= VALUES["J"] | ||
return INDIRECT + reg | ||
|
||
when LABEL_RE | ||
op.reference(inner) | ||
return INDIRECT_NEXT | ||
|
||
when INDIRECT_OFFSET_RE | ||
offset, reg = inner.split("+").map{|x| x.strip } | ||
offset = dehex(offset) | ||
|
||
op.error("Malformed indirect offset value #{inner}") unless INT_RE === offset && REG_RE === reg | ||
value = offset.to_i# + VALUES[reg] | ||
op.extend value | ||
|
||
return INDIRECT_OFFSET + VALUES[reg] | ||
end | ||
else | ||
op.error("Unrecognized value #{token}") | ||
end | ||
end | ||
|
||
def dump | ||
raise "TODO #{caller.first}" | ||
lines = [] | ||
@input.each_line do |line| | ||
empty = (line =~ /^\s*$/) | ||
comment = (line =~ /^\s*;+.*$/) | ||
def parse_op(op, tokens) | ||
inst_name = tokens.shift | ||
|
||
inst_code = INSTRUCTIONS[inst_name] | ||
if inst_code | ||
op.inst = inst_code | ||
op.a = parse_value(tokens.shift, op) | ||
op.b = parse_value(tokens.shift, op) | ||
return | ||
end | ||
|
||
inst_code = EXTENDED_INSTRUCTIONS[inst_name] | ||
if inst_code | ||
op.inst = EXT_PREFIX | ||
op.a = inst_code | ||
op.b = parse_value(tokens.shift, op) | ||
end | ||
|
||
raise Exception.new("No such instruction: #{inst_name}") unless inst_code | ||
end | ||
|
||
def assemble#(text) | ||
text = @input | ||
labels = {} | ||
|
||
num = 0 | ||
location = 0 | ||
text.each_line do |line| | ||
num += 1 | ||
op = Instruction.new(num, line) | ||
|
||
cleaned = clean(line) | ||
next if cleaned.empty? | ||
|
||
tokens = cleaned.split(/\s/) | ||
op.error("Wrong number of tokens - #{tokens}") unless (2..4) === tokens.size | ||
|
||
labels[tokens.shift[1..-1]] = location if tokens[0].start_with?(":") | ||
parse_op(op, tokens) | ||
|
||
@body << op | ||
location += op.size | ||
end | ||
|
||
@body.each {|op| op.resolve(labels) } | ||
|
||
#display | ||
end | ||
|
||
next if empty || comment | ||
def display | ||
@body.each { |op| puts op } | ||
end | ||
|
||
line.gsub!(/^\s*([^;]*).*$/) { $1 } # Strip some spaces | ||
|
||
regex = /^(:\w*)?\s*(\w*)\s*([^,\s]*),?\s?([^\s]*).*$/ | ||
match = line.match(regex) | ||
def dump#(filename) | ||
@body | ||
# File.open(filename, "w") do |file| | ||
# @body.each {|inst| file.write(inst.bytes) } | ||
# end | ||
end | ||
|
||
line = { :label => match[1], | ||
:op => match[2], | ||
:a => match[3], | ||
:b => match[4] } | ||
puts line | ||
lines << line | ||
def write(filename) | ||
File.open(filename, "w") do |file| | ||
@body.each {|inst| file.write(inst.bytes) } | ||
end | ||
end | ||
end | ||
end | ||
|
||
|
||
#if __FILE__ == $PROGRAM_NAME | ||
# asm = Assembler.new | ||
# filename = "#{ARGV.first || "out.s"}.o" | ||
# asm.assemble ARGF | ||
# asm.dump filename | ||
#end | ||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
#attr_reader :input | ||
#def initialize(text) | ||
# @input = text | ||
#end | ||
|
||
#def dump | ||
# lines = [] | ||
# @input.each_line do |line| | ||
# empty = (line =~ /^\s*$/) | ||
# comment = (line =~ /^\s*;+.*$/) | ||
|
||
# next if empty || comment | ||
|
||
# line.gsub!(/^\s*([^;]*).*$/) { $1 } # Strip some spaces | ||
|
||
# regex = /^(:\w*)?\s*(\w*)\s*([^,\s]*),?\s?([^\s]*).*$/ | ||
# match = line.match(regex) | ||
|
||
# line = { :label => match[1], | ||
# :op => match[2], | ||
# :a => match[3], | ||
# :b => match[4] } | ||
# puts line | ||
# lines << line | ||
# end | ||
#end | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.