OXYGENHUB
# ea9efff4e540 x16-emulator / src / coverage.c
2.4 KiB · C · last changed chore(): initial commit 15 days ago source blame history raw
1
// Commander X16 Emulator
2
// Execution coverage: which addresses the CPU fetched an instruction from.
3
// See coverage.h for the file it writes.
4
5
#include <signal.h>
6
#include <stdio.h>
7
#include <stdlib.h>
8
#include <string.h>
9
#include "memory.h"
10
#include "coverage.h"
11
12
bool coverage_enabled = false;
13
volatile bool coverage_stop = false;
14
15
static const char *coverage_path;   // argv's, which lives as long as the program
16
static uint8_t *low;      // $0000-$9FFF
17
static uint8_t *ram;      // 256 banks of $A000-$BFFF
18
static uint8_t *rom;      // 256 banks of $C000-$FFFF
19
20
#define LOW_SIZE  0xa000
21
#define RAM_SIZE  0x2000
22
#define ROM_SIZE  0x4000
23
24
// SIGTERM ends the CPU loop rather than the process, so main's shutdown runs
25
// and the marks are written; a second SIGTERM, or SIGKILL, still ends it.
26
static void
27
coverage_sigterm(int sig)
28
{
29
	(void)sig;
30
	coverage_stop = true;
31
	signal(SIGTERM, SIG_DFL);
32
}
33
34
bool
35
coverage_init(const char *path)
36
{
37
	low = calloc(LOW_SIZE, 1);
38
	ram = calloc(256 * RAM_SIZE, 1);
39
	rom = calloc(256 * ROM_SIZE, 1);
40
	coverage_path = path;
41
	if (!low || !ram || !rom) {
42
		return false;
43
	}
44
	coverage_enabled = true;
45
	signal(SIGTERM, coverage_sigterm);
46
	return true;
47
}
48
49
void
50
coverage_mark(uint16_t pc)
51
{
52
	if (pc < 0xa000) {
53
		low[pc] = 1;
54
	} else if (pc < 0xc000) {
55
		ram[(memory_get_ram_bank() << 13) + (pc - 0xa000)] = 1;
56
	} else {
57
		rom[(memory_get_rom_bank() << 14) + (pc - 0xc000)] = 1;
58
	}
59
}
60
61
// One line per run of marked addresses in [0, size), named from base.
62
static void
63
write_runs(FILE *f, char kind, int bank, const uint8_t *marks, int size, int base)
64
{
65
	for (int i = 0; i < size; i++) {
66
		if (!marks[i]) {
67
			continue;
68
		}
69
		int start = i;
70
		while (i + 1 < size && marks[i + 1]) {
71
			i++;
72
		}
73
		if (bank < 0) {
74
			fprintf(f, "%c %04x-%04x\n", kind, base + start, base + i);
75
		} else {
76
			fprintf(f, "%c %02x:%04x-%04x\n", kind, bank, base + start, base + i);
77
		}
78
	}
79
}
80
81
void
82
coverage_write(void)
83
{
84
	if (!coverage_enabled) {
85
		return;
86
	}
87
	FILE *f = fopen(coverage_path, "w");
88
	if (!f) {
89
		fprintf(stderr, "Cannot write coverage to %s!\n", coverage_path);
90
		return;
91
	}
92
	fprintf(f, "x16emu-coverage 1\n");
93
	write_runs(f, 'm', -1, low, LOW_SIZE, 0);
94
	for (int bank = 0; bank < 256; bank++) {
95
		write_runs(f, 'r', bank, ram + (bank << 13), RAM_SIZE, 0xa000);
96
	}
97
	for (int bank = 0; bank < 256; bank++) {
98
		write_runs(f, 'k', bank, rom + (bank << 14), ROM_SIZE, 0xc000);
99
	}
100
	fclose(f);
101
}