Permalink
Browse files

Improve bin/rcpu:

* Can now run binaries
* Can now compile to binaries
  • Loading branch information...
1 parent 47049f8 commit 0e841d182a35c347d7ad83a8d0765fadff671d7b @judofyr committed Apr 9, 2012
Showing with 849 additions and 96 deletions.
  1. +35 −12 bin/rcpu
  2. +0 −55 bin/rcpu-as
  3. +0 −20 bin/rcpu-bin
  4. BIN examples/hello
  5. +2 −0 lib/rcpu.rb
  6. +9 −6 lib/rcpu/assembler.rb
  7. +19 −3 lib/rcpu/debugger.rb
  8. +2 −0 lib/rcpu/emulator.rb
  9. +782 −0 lib/rcpu/trollop.rb
View
@@ -1,23 +1,46 @@
#!/usr/bin/env ruby
$LOAD_PATH.unshift(File.expand_path("../../lib", __FILE__))
-if ARGV.empty?
- puts "usage: rcpu examples/from_spec.rpcu"
- exit 1
+require 'rcpu'
+require 'rcpu/trollop'
+T = RCPU::Trollop
+
+p = T::Parser.new do
+ version "RCPU #{RCPU::VERSION}"
+ banner <<-EOS
+DCPU-16 assembler, emulator, debugger
+
+Usage:
+ bin/rcpu examples/hello.rcpu
+ bin/rcpu examples/hello.bin
+ bin/rcpu -f bin examples/hello
+
+Available options:
+EOS
+ opt :format, "File format (bin or rcpu). Guessed from filename if not present.",
+ :type => String
end
-require 'rcpu'
+formats = %w[bin rcpu]
-begin
- require 'pry'
-rescue LoadError
+opts = nil
+T.with_standard_exception_handling(p) do
+ opts = p.parse(ARGV)
+ raise T::HelpNeeded unless opts[:filename] = ARGV.shift
+ opts[:format] ||= File.extname(opts[:filename]).sub('.','')
+ p.die :format, "can only be 'bin' or 'rcpu'" unless formats.include?(opts[:format])
end
linker = RCPU::Linker.new
-lib = linker.find(ARGV[0], Dir.pwd)
-linker.compile(lib)
-emu = RCPU::Emulator.new(linker.finalize)
-emu.memory.add_extensions(linker.extensions)
-RCPU::Debugger.new(emu, linker).start
+case opts[:format]
+when 'rpcu'
+ lib = linker.find(opts[:filename], Dir.pwd)
+ linker.compile_library(lib)
+when 'bin'
+ linker.extensions << [0x8000, RCPU::ScreenExtension, []]
+ linker.compile_binary(File.binread(opts[:filename]))
+end
+
+linker.debugger.start
View
@@ -1,55 +0,0 @@
-#!/usr/bin/env ruby
-$LOAD_PATH.unshift(File.expand_path("../../lib", __FILE__))
-require 'trollop'
-require 'rcpu'
-
-EXTENSIONS = {
- 'binary' => 'bin',
- 'hex' => 'hex',
-}
-
-opts = Trollop.options do
- banner <<-EOS
-rcpu-as - a DCPU-16 assembler
-
-Usage:
- rcpu-as [options] [file]
-
-where [options] are:
-EOS
-
- opt :output, "Output filename", :short => 'o', :type => :string
- opt :format, "Output format (#{EXTENSIONS.keys*'|'})", :short => 'O', :default => 'binary'
- opt :help, "Show this message", :short => 'h'
-
- text <<-EOS
-
-If no output filename is given the output will be written to filename.(#{EXTENSIONS.values*'|'}).
- EOS
-end
-
-Trollop.die "invalid output format #{opts[:format].inspect}" unless EXTENSIONS.member?(opts[:format])
-
-input_filename = ARGV[0]
-
-if opts[:output]
- output_io = File.open(opts[:output], 'w')
-else
- filename = File.join(File.dirname(input_filename),
- File.basename(input_filename, '.rcpu') + '.' + EXTENSIONS[opts[:format]])
- output_io = File.open(filename, 'w')
-end
-
-linker = RCPU::Linker.new
-lib = linker.find(input_filename, Dir.pwd)
-linker.compile(lib)
-data = linker.finalize
-
-case opts.format
-when 'binary'
- output_io.write data.pack('v*')
-when 'hex'
- data.each do |x|
- printf "%04x\n", x
- end
-end
View
@@ -1,20 +0,0 @@
-#!/usr/bin/env ruby
-$LOAD_PATH.unshift(File.expand_path("../../lib", __FILE__))
-
-if ARGV.empty?
- puts "usage: rcpu-bin file.bin"
- exit 1
-end
-
-require 'rcpu'
-
-data = File.open(ARGV.shift, 'rb') { |f| f.read }.unpack('v*')
-emu = RCPU::Emulator.new(data)
-emu.memory.add_extensions([[0x8000, RCPU::ScreenExtension, [], nil]])
-emu.start
-at_exit do
- emu.stop
- emu.dump
-end
-emu.run
-
View
Binary file not shown.
View
@@ -1,4 +1,6 @@
module RCPU
+ VERSION = "0.1.0"
+
class AssemblerError < StandardError; end
class BasicInstruction < Struct.new(:name, :a, :b)
View
@@ -168,7 +168,11 @@ def load_file(file)
@libraries[file] = l
end
- def compile(library, name = :main)
+ def compile_binary(str)
+ @memory.concat(str.unpack('v*'))
+ end
+
+ def compile_library(library, name = :main)
gather(library)
block = @blocks[name] or raise AssemblerError, "no block: #{name}"
compile_block(name, block)
@@ -220,11 +224,10 @@ def finalize
end
end
- def dump
- finalize.each_slice(8).each_with_index do |r, i|
- print "#{(i*8).to_s(16).rjust(4, '0')}: "
- puts r.map { |x| x.to_s(16).rjust(4, '0') }.join(" ")
- end
+ def debugger
+ emu = Emulator.new(finalize)
+ emu.memory.add_extensions(extensions)
+ Debugger.new(emu, self)
end
end
end
View
@@ -1,3 +1,8 @@
+begin
+ require 'pry'
+rescue LoadError
+end
+
module RCPU
class Debugger
def initialize(emulator, linker = Linker.new)
@@ -14,9 +19,10 @@ def pry?
def help
puts "(^C) stop execution"
puts "(b) add breakpoint"
- puts "(d) dump state"
+ puts "(c) compile to binary"
+ puts "(d) dump memory and registrers"
puts "(e) evaluate ruby"
- puts "(h) help"
+ puts "(h) help (this message)"
puts "(p) ruby shell" if pry?
puts "(r) run"
puts "(s) step"
@@ -35,8 +41,11 @@ def start
@running = false
end
- puts "Welcome to RCPU:"
+ puts "Welcome to RCPU #{VERSION}:"
help
+ puts
+ puts "You probably want to type 'r' for run or 'c' for compile"
+ puts
while true
begin
@@ -55,6 +64,13 @@ def start
bp = @linker.symbols[input] || Integer(input)
@breakpoints << bp
puts "Added breakpoint #{@breakpoints.size} at 0x#{bp.to_s(16)}"
+ when "c"
+ print "Enter filename: "
+ filename = gets.strip
+ File.open(filename, 'w') do |f|
+ f << @emulator.memory.to_s
+ end
+ puts ">> Saved as #{filename}"
when "d"
@emulator.dump
when "e"
View
@@ -16,6 +16,8 @@ def initialize(source)
@extensions = []
end
+ def to_s; @array.pack('v*') end
+
def add_extensions(list)
list.each do |(location, klass, args, blk)|
ext = klass.new(@array, location, *args, &blk)
Oops, something went wrong.

2 comments on commit 0e841d1

Collaborator

rlane replied Apr 10, 2012

Please don't remove the standalone assembler. It's very useful for automation, such as in a Makefile.

Owner

judofyr replied Apr 10, 2012

Revived in 60e375e.

Please sign in to comment.