mirror of
https://github.com/specht/champ.git
synced 2024-11-24 17:33:23 +00:00
added error handling
This commit is contained in:
parent
044f7be667
commit
d1687f534d
95
champ.rb
95
champ.rb
@ -48,6 +48,7 @@ class Champ
|
||||
STDERR.puts 'Usage: ./champ.rb [options] <config.yaml>'
|
||||
STDERR.puts 'Options:'
|
||||
STDERR.puts ' --max-frames <n>'
|
||||
STDERR.puts ' --error-log-size <n> (default: 20)'
|
||||
STDERR.puts ' --no-animation'
|
||||
exit(1)
|
||||
end
|
||||
@ -58,11 +59,17 @@ class Champ
|
||||
@max_frames = nil
|
||||
@record_frames = true
|
||||
@cycles_per_function = {}
|
||||
@execution_log = []
|
||||
@execution_log_size = 20
|
||||
@code_for_pc = {}
|
||||
@source_for_file = {}
|
||||
args = ARGV.dup
|
||||
while args.size > 1
|
||||
item = args.shift
|
||||
if item == '--max-frames'
|
||||
@max_frames = args.shift.to_i
|
||||
elsif item == '--error-log-size'
|
||||
@execution_log_size = args.shift.to_i
|
||||
elsif item == '--no-animation'
|
||||
@record_frames = false
|
||||
else
|
||||
@ -189,7 +196,7 @@ class Champ
|
||||
@max_cycle_count = 0
|
||||
call_stack = []
|
||||
last_call_stack_cycles = 0
|
||||
Open3.popen2("./p65c02 #{@record_frames ? '' : '--no-screen'} --hide-log --start-pc #{start_pc} #{File.join(temp_dir, 'disk_image')}") do |stdin, stdout, thread|
|
||||
Open3.popen2("./p65c02 #{@record_frames ? '' : '--no-screen'} --start-pc #{start_pc} #{File.join(temp_dir, 'disk_image')}") do |stdin, stdout, thread|
|
||||
stdin.puts watch_input.split("\n").size
|
||||
stdin.puts watch_input
|
||||
stdin.close
|
||||
@ -205,7 +212,19 @@ class Champ
|
||||
stdout.each_line do |line|
|
||||
# puts "> #{line}"
|
||||
parts = line.split(' ')
|
||||
if parts.first == 'jsr'
|
||||
if parts.first == 'error'
|
||||
parts.shift
|
||||
pc = parts.shift.to_i(16)
|
||||
message = parts.join(' ')
|
||||
@error = {:pc => pc, :message => message}
|
||||
elsif parts.first == 'log'
|
||||
parts.shift
|
||||
log = parts.map { |x| x.to_i(16) }
|
||||
@execution_log << log
|
||||
while @execution_log.size > @execution_log_size
|
||||
@execution_log.shift
|
||||
end
|
||||
elsif parts.first == 'jsr'
|
||||
pc = parts[1].to_i(16)
|
||||
cycles = parts[2].to_i
|
||||
@max_cycle_count = cycles
|
||||
@ -725,9 +744,9 @@ class Champ
|
||||
io.puts "overlap = false;"
|
||||
io.puts "rankdir = LR;"
|
||||
io.puts "splines = true;"
|
||||
io.puts "graph [fontname = sans, fontsize = 8, size = \"14, 11\", nodesep = 0.2, ranksep = 0.3, ordering = out];"
|
||||
io.puts "node [fontname = sans, fontsize = 8, shape = rect, style = filled, fillcolor = \"#fce94f\" color = \"#c4a000\"];"
|
||||
io.puts "edge [fontname = sans, fontsize = 8, color = \"#444444\"];"
|
||||
io.puts "graph [fontname = Arial, fontsize = 8, size = \"14, 11\", nodesep = 0.2, ranksep = 0.3, ordering = out];"
|
||||
io.puts "node [fontname = Arial, fontsize = 8, shape = rect, style = filled, fillcolor = \"#fce94f\" color = \"#c4a000\"];"
|
||||
io.puts "edge [fontname = Arial, fontsize = 8, color = \"#444444\"];"
|
||||
all_nodes.each do |node|
|
||||
label = @label_for_pc[node] || sprintf('0x%04x', node)
|
||||
label = "<B>#{label}</B>"
|
||||
@ -766,6 +785,43 @@ class Champ
|
||||
report.sub!('#{call_graph}', '<em>(GraphViz not installed)</em>')
|
||||
end
|
||||
|
||||
# write error dump
|
||||
if @error
|
||||
io = StringIO.new
|
||||
io.puts "<div>"
|
||||
io.puts "<h2>Error log</h2>"
|
||||
|
||||
io.puts "<code><pre>"
|
||||
source_code = @code_for_pc[@error[:pc]]
|
||||
STDERR.puts source_code.to_yaml
|
||||
offset = source_code[:line] - 1
|
||||
this_filename = source_code[:file]
|
||||
io.puts "<span class='heading'>#{sprintf('%-83s', this_filename)}</span>"
|
||||
((offset - 16)..(offset + 16)).each do |i|
|
||||
next if i < 0 || i >= @source_for_file[this_filename].size
|
||||
io.print "<span class='#{(i == offset) ? 'error' : 'code'}'>"
|
||||
io.print sprintf('%5d | %-75s', i + 1, @source_for_file[this_filename][i])
|
||||
io.print "</span>" if i == offset
|
||||
io.puts
|
||||
end
|
||||
io.puts "</pre></code>"
|
||||
|
||||
io.puts "<h3>Debug log</h3>"
|
||||
io.puts "<code><pre>"
|
||||
io.puts sprintf("<span class='heading'> PC | A X Y PC SP Flags </span>")
|
||||
@execution_log.each do |item|
|
||||
io.puts sprintf("<span class='code'> 0x%04x | 0x%02x 0x%02x 0x%02x 0x%04x 0x%02x 0x%02x </span>", *item)
|
||||
end
|
||||
io.puts sprintf("<span class='error'> 0x%04x | %-37s </span>", @error[:pc], @error[:message])
|
||||
io.puts "</pre></code>"
|
||||
|
||||
io.puts "</div>"
|
||||
|
||||
report.sub!('#{error}', io.string)
|
||||
else
|
||||
report.sub!('#{error}', '')
|
||||
end
|
||||
|
||||
f.puts report
|
||||
end
|
||||
puts ' done.'
|
||||
@ -782,6 +838,8 @@ class Champ
|
||||
end
|
||||
|
||||
def parse_merlin_output(path)
|
||||
input_file = File.basename(@source_path)
|
||||
@source_for_file[input_file] = File.read(@source_path).split("\n")
|
||||
@source_line = -3
|
||||
File.open(path, 'r') do |f|
|
||||
f.each_line do |line|
|
||||
@ -795,8 +853,18 @@ class Champ
|
||||
pc = parts[6].split(' ').first.split('/').last.to_i(16)
|
||||
code = parts[7].strip
|
||||
code_parts = code.split(/\s+/)
|
||||
next if code_parts.empty?
|
||||
|
||||
line_number = parts[1].split(' ').map { |x| x.strip }.reject { |x| x.empty? }.last.to_i
|
||||
# unless (@pc_code_lines.last || 0) == pc
|
||||
STDERR.puts line_number
|
||||
@code_for_pc[pc] = {
|
||||
:file => input_file,
|
||||
:line => line_number,
|
||||
}
|
||||
# @pc_code_lines << pc
|
||||
# end
|
||||
|
||||
next if code_parts.empty?
|
||||
label = nil
|
||||
|
||||
champ_directives = []
|
||||
@ -834,7 +902,6 @@ class Champ
|
||||
elsif line_type == 'Code'
|
||||
@watches[pc] ||= []
|
||||
champ_directives.each do |directive|
|
||||
line_number = parts[1].split(' ').map { |x| x.strip }.reject { |x| x.empty? }.last.to_i
|
||||
watch = parse_champ_directive(directive, false)
|
||||
watch[:line_number] = line_number
|
||||
watch[:pc] = pc
|
||||
@ -949,9 +1016,23 @@ __END__
|
||||
text-align: left;
|
||||
padding: 0 0.5em;
|
||||
}
|
||||
.heading {
|
||||
color: #2e3436;
|
||||
background-color: #babdb6;
|
||||
font-weight: bold;
|
||||
}
|
||||
.code {
|
||||
color: #555753;
|
||||
background-color: #edeeec;
|
||||
}
|
||||
.error {
|
||||
color: #cc0000;
|
||||
background-color: #f2bfbf;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
#{error}
|
||||
<div style='float: left; padding-right: 10px;'>
|
||||
<h2>Frames</h2>
|
||||
#{screenshots}
|
||||
|
17
examples/example05.s
Normal file
17
examples/example05.s
Normal file
@ -0,0 +1,17 @@
|
||||
DSK test
|
||||
MX %11
|
||||
ORG $6000
|
||||
|
||||
LDX #$20
|
||||
JSR COUNT
|
||||
LDX #$30
|
||||
JSR COUNT
|
||||
LDX #$40
|
||||
JSR COUNT
|
||||
|
||||
BRK
|
||||
|
||||
COUNT DEX ; @Xu(post) @cycles
|
||||
BNE COUNT
|
||||
BRK
|
||||
RTS
|
3
examples/example05.yaml
Normal file
3
examples/example05.yaml
Normal file
@ -0,0 +1,3 @@
|
||||
load:
|
||||
0x6000: example05.s
|
||||
entry: 0x6000
|
26
p65c02.c
26
p65c02.c
@ -633,13 +633,6 @@ void handle_next_opcode()
|
||||
break;
|
||||
}
|
||||
|
||||
if (show_log)
|
||||
{
|
||||
fprintf(stderr, "# %04x | %d | %02x | %s %-18s | ", old_pc, cycles, read_opcode, OPCODE_STRINGS[opcode],
|
||||
ADDRESSING_MODE_STRINGS[addressing_mode]
|
||||
);
|
||||
}
|
||||
|
||||
int unhandled_opcode = 0;
|
||||
uint8_t t8 = 0;
|
||||
uint16_t t16 = 0;
|
||||
@ -948,7 +941,10 @@ void handle_next_opcode()
|
||||
};
|
||||
if (unhandled_opcode)
|
||||
{
|
||||
fprintf(stderr, "Opcode %s not implemented yet at PC 0x%04x\n",
|
||||
printf("error %04x Opcode %s not implemented yet.\n",
|
||||
old_pc, OPCODE_STRINGS[opcode]);
|
||||
fflush(stdout);
|
||||
fprintf(stderr, "Opcode %s not implemented yet at PC 0x%04x.\n",
|
||||
OPCODE_STRINGS[opcode], cpu.pc);
|
||||
exit(1);
|
||||
}
|
||||
@ -957,17 +953,9 @@ void handle_next_opcode()
|
||||
cycles_per_function[trace_stack_function[trace_stack_pointer + 1]] += cycles;
|
||||
if (show_log)
|
||||
{
|
||||
char flags_str[6];
|
||||
flags_str[0] = test_flag(CARRY) ? 'C' : 'c';
|
||||
flags_str[1] = test_flag(ZERO) ? 'Z' : 'z';
|
||||
flags_str[2] = test_flag(DECIMAL_MODE) ? 'D' : 'd';
|
||||
flags_str[3] = test_flag(OVERFLOW) ? 'V' : 'v';
|
||||
flags_str[4] = test_flag(NEGATIVE) ? 'N' : 'n';
|
||||
flags_str[5] = 0;
|
||||
|
||||
fprintf(stderr, "A: %02x, X: %02x, Y: %02x, PC: %04x, SP: %02x, FLAGS: %02x %s | %10ld |",
|
||||
cpu.a, cpu.x, cpu.y, cpu.pc, cpu.sp, cpu.flags, flags_str, cpu.total_cycles);
|
||||
fprintf(stderr, "\n");
|
||||
printf("log %04x %02x %02x %02x %04x %02x %02x\n",
|
||||
old_pc, cpu.a, cpu.x, cpu.y, cpu.pc, cpu.sp, cpu.flags);
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user