documentation

This commit is contained in:
Michael Specht 2018-02-19 23:35:31 +01:00
parent 1cec19787c
commit 7f0529db03
5 changed files with 45 additions and 16 deletions

View File

@ -192,6 +192,29 @@ To disable a watch, add a `;` right behind the `@`:
ADC FOO ; @;Au(post)
```
### Error reporting
Should your program run into an error, champ shows you where in the source code the error occured and an execution log of the previous 20 CPU steps (you can increase the size of the log with `--error-log-size`).
Look at this example ([example05.yaml](example05.yaml) / [example05.s](example05.s)):
```
DSK test
MX %11
ORG $6000
LDX #$ff
COUNT PHA
PHA
DEX
BNE COUNT
```
This is a program which repeatedly pushes the A register onto the stack until the stack is full. Stack overflow, mission accomplished! Champ will generate the following output:
![Error report](doc/example05_1.gif?raw=true)
On the left hand side you can see that the error occured in example05.s, line 7, while attempting a `PHA` operation when `SP` is already down to zero from previous `PHA` operations (as can be seen on the right).
## Did you know?
By the way, there's a full-fledged, incremental, standalone, no-dependencies GIF encoder in [pgif.c](pgif.c) that writes animated GIFs and uses some optimizations to further minimize space. It's stream-friendly and as you feed pixels in via `stdin`, it dutifully writes GIF data to `stdout` until `stdin` gets closed.

View File

@ -853,7 +853,7 @@ class Champ
def parse_merlin_output(path)
input_file = File.basename(@source_path)
@source_for_file[input_file] = File.read(@source_path).split("\n").map { |x| x.gsub("\t", ' ' * 4) }
@max_source_width_for_file[input_file] = @source_for_file[input_file].map { |x| x.size }.max
@max_source_width_for_file[input_file] = [@source_for_file[input_file].map { |x| x.size }.max, 40].max
@source_line = -3
File.open(path, 'r') do |f|

BIN
doc/example05_1.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@ -2,16 +2,8 @@
MX %11
ORG $6000
LDX #$20
JSR COUNT
LDX #$30
JSR COUNT
LDX #$40
JSR COUNT
BRK
COUNT DEX ; @Xu(post) @cycles
LDX #$ff
COUNT PHA
PHA
DEX
BNE COUNT
BRK
RTS

View File

@ -31,6 +31,7 @@ uint64_t frame_count = 0;
uint16_t start_pc = 0x6000;
uint16_t start_frame_pc = 0xffff;
uint16_t old_pc = 0;
uint16_t yoffset[192] = {
0x0000, 0x0400, 0x0800, 0x0c00, 0x1000, 0x1400, 0x1800, 0x1c00,
@ -98,6 +99,7 @@ typedef struct {
} r_watch;
r_watch *watches = 0;
uint8_t watches_allocated = 0;
size_t watch_count = 0;
int32_t watch_offset_for_pc_and_post[0x20000];
@ -150,6 +152,9 @@ void push(uint8_t value)
{
if (cpu.sp == 0)
{
printf("error %04x Stack overflow\n", old_pc);
fflush(stdout);
fprintf(stderr, "Stack overflow!\n");
exit(1);
}
@ -161,6 +166,8 @@ uint8_t pop()
{
if (cpu.sp == 0xff)
{
printf("error %04x Stack underrun\n", old_pc);
fflush(stdout);
fprintf(stderr, "Stack underrun!\n");
exit(1);
}
@ -564,7 +571,7 @@ void branch(uint8_t condition, int8_t offset, uint8_t* cycles)
void handle_next_opcode()
{
uint16_t old_pc = cpu.pc;
old_pc = cpu.pc;
// fetch opcode, addressing mode and cycles for next instruction
uint8_t read_opcode = 0;
@ -575,6 +582,9 @@ void handle_next_opcode()
if (opcode == NO_OPCODE || addressing_mode == NO_ADDRESSING_MODE)
{
printf("error %04x Unhandled opcode: %02x\n", old_pc, read_opcode);
fflush(stdout);
fprintf(stderr, "Unhandled opcode at %04x: %02x\n", old_pc, read_opcode);
exit(1);
}
@ -1067,10 +1077,14 @@ int main(int argc, char** argv)
int watch_index = 0;
while (fgets(s, 1024, stdin))
{
if (!watches)
if (s[0] == '\n')
break;
if (!watches_allocated)
{
watch_count = parse_int(s, 0);
watches = malloc(sizeof(r_watch) * watch_count);
if (watch_count > 0)
watches = malloc(sizeof(r_watch) * watch_count);
watches_allocated = 1;
}
else
{