class Zemu::InteractiveInstance
An interactive instance of a Zemu
emulator. Wraps a Zemu::Instance
to allow for user input and debugging.
Public Class Methods
new(instance)
click to toggle source
Constructor.
Create a new interactive wrapper for the given instance.
# File lib/zemu/interactive.rb, line 8 def initialize(instance) @instance = instance @master, @slave = PTY.open log "Opened PTY at #{@slave.path}" end
Public Instance Methods
add_breakpoint(addr_str)
click to toggle source
Add a breakpoint at the address given by the string.
# File lib/zemu/interactive.rb, line 162 def add_breakpoint(addr_str) @instance.break(addr_str.to_i(16), :program) end
close()
click to toggle source
Close the interactive wrapper
# File lib/zemu/interactive.rb, line 21 def close @master.close @slave.close @instance.quit end
continue(cycles=-1)
click to toggle source
Continue for *up to* the given number of cycles. Fewer cycles may be executed, depending on the behaviour of the processor.
# File lib/zemu/interactive.rb, line 106 def continue(cycles=-1) if cycles == 0 log "Invalid value: #{cycles}" return end # Continue executing instruction-by-instruction. # Process IO in-between. cycles_left = cycles actual_cycles = 0 serial_count = @instance.serial_delay while ((cycles == -1) || (cycles_left > 0)) # Get time before execution. start = Time.now old_pc = r16("PC") if (serial_count >= @instance.serial_delay) process_serial serial_count = 0 end cycles_done = @instance.continue(1) cycles_left -= cycles_done actual_cycles += cycles_done # Get time after execution. ending = Time.now # Get elapsed time and calculate padding time to match clock speed. if @instance.clock_speed > 0 elapsed = ending - start execution_time = cycles_done * (1.0/@instance.clock_speed) serial_count += execution_time padding = execution_time - elapsed sleep(padding) unless padding < 0 end # Have we hit a breakpoint or HALT instruction? if @instance.break? log "Hit breakpoint at #{r16("PC")}." break elsif @instance.halted? log "Executed HALT instruction at #{old_pc}." break end end log "Executed for #{actual_cycles} cycles." end
log(message)
click to toggle source
Logs a message to the user output.
# File lib/zemu/interactive.rb, line 16 def log(message) STDOUT.puts " " + message end
memory(address, size="1")
click to toggle source
Dump an amount of memory.
# File lib/zemu/interactive.rb, line 167 def memory(address, size="1") if address.nil? log "Expected an address, got #{address}." return end if (address.to_i(16) < 1 || address.to_i(16) > 0xffff) log "Invalid address: 0x%04x" % address.to_i(16) return end (address.to_i(16)...address.to_i(16) + size.to_i(16)).each do |a| m = @instance.memory(a) if (m < 32 || m > 126) log "%04x: %02x ." % [a, m] else log ("%04x: %02x " % [a, m]) + m.chr("UTF-8") end end end
process_serial()
click to toggle source
Process serial input/output via the TTY.
# File lib/zemu/interactive.rb, line 189 def process_serial # Read/write serial. # Get the strings to be input/output. input = "" ready = IO.select([@master], [], [], 0) unless ready.nil? || ready.empty? input = @master.read(1) end output = @instance.serial_gets(1) unless input.empty? @instance.serial_puts input log "Serial in: #{input}" end unless output.empty? @master.write output log "Serial out: #{output}" end end
r(reg)
click to toggle source
Returns a particular 8-bit register value.
# File lib/zemu/interactive.rb, line 95 def r(reg) return "0x%02x" % @instance.registers[reg] end
r16(reg)
click to toggle source
Returns a particular 16-bit register value.
# File lib/zemu/interactive.rb, line 100 def r16(reg) return "0x%04x" % @instance.registers[reg] end
registers()
click to toggle source
Outputs a table giving the current values of the instance's registers.
# File lib/zemu/interactive.rb, line 82 def registers log "A: #{r("A")} F: #{r("F")}" log "B: #{r("B")} C: #{r("C")}" log "D: #{r("D")} E: #{r("E")}" log "H: #{r("H")} L: #{r("L")}" log "" log "IX: #{r16("IX")}" log "IY: #{r16("IY")}" log "SP: #{r16("SP")}" log "PC: #{r16("PC")}" end
run()
click to toggle source
Run the interactive emulator until the user exits.
# File lib/zemu/interactive.rb, line 28 def run quit = false until quit print "ZEMU> " # Get a command from the user. cmd = STDIN.gets.split if cmd[0] == "quit" quit = true elsif cmd[0] == "continue" if cmd[1].nil? continue else continue(cmd[1].to_i) end elsif cmd[0] == "step" continue(1) elsif cmd[0] == "registers" registers elsif cmd[0] == "break" add_breakpoint(cmd[1]) elsif cmd[0] == "memory" if cmd[2].nil? memory(cmd[1]) else memory(cmd[1], cmd[2]) end elsif cmd[0] == "help" log "Available commands:" log " continue [<n>] - Continue execution for <n> cycles" log " step - Step over a single instruction" log " registers - View register contents" log " memory <a> [<n>] - View <n> bytes of memory, starting at address <a>." log " <n> defaults to 1 if omitted." log " break <a> - Set a breakpoint at the given address <a>." log " quit - End this emulator instance." else log "Invalid command. Type 'help' for available commands." end end close end