summaryrefslogtreecommitdiff
path: root/demo/cache.c
blob: c9e56f0bb789f15fadd6d1fc469a027e98f3e1b4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include "demo.h"

#define CACHE_DEBUG_BASE(n)    (0x30100000 | (0x10000 * (n)))
#define CACHE_DEBUG_WORD(n, i) (*(volatile unsigned *)(CACHE_DEBUG_BASE(n) + 16 + 4 * (i)))

#define CACHE_STATUS(n)          (*(volatile unsigned *)CACHE_DEBUG_BASE(n))
#define CACHE_STATUS_CACHED      (1 << 1)
#define CACHE_STATUS_STATE_MASK  0x0000000c
#define CACHE_STATUS_STATE_SHIFT 2
#define CACHE_STATUS_INDEX_MASK  0x0000fff0
#define CACHE_STATUS_INDEX_SHIFT 4
#define CACHE_STATUS_INDEX_BITS  12
#define CACHE_STATUS_TAG_MASK    0x1fff0000
#define CACHE_STATUS_TAG_SHIFT   16
#define CACHE_STATUS_TAG_BITS    13
#define CACHE_STATUS_STATE_I     0b00
#define CACHE_STATUS_STATE_S     0b01
#define CACHE_STATUS_STATE_E     0b10
#define CACHE_STATUS_STATE_M     0b11

void cache_debug(unsigned cpu, void *ptr)
{
	unsigned ptr_val = (unsigned)ptr;

	CACHE_STATUS(cpu) = (unsigned)ptr;
	unsigned status = CACHE_STATUS(cpu);

	int cached = status & CACHE_STATUS_CACHED;

	print("req_addr:     %p", ptr);
	print("cacheability: %s", cached ? "write-back" : "uncached (I/O)");

	if (!cached)
		return;

	unsigned index = (status & CACHE_STATUS_INDEX_MASK) >> CACHE_STATUS_INDEX_SHIFT;
	unsigned addr_tag = (ptr_val & CACHE_STATUS_TAG_MASK) >> CACHE_STATUS_TAG_SHIFT;
	unsigned cache_tag = (status & CACHE_STATUS_TAG_MASK) >> CACHE_STATUS_TAG_SHIFT;
	unsigned line_addr = status & (CACHE_STATUS_TAG_MASK | CACHE_STATUS_INDEX_MASK);

	print("index:        %r", index, CACHE_STATUS_INDEX_BITS);
	print("req_tag:      %r", addr_tag, CACHE_STATUS_TAG_BITS);
	print("cache_tag:    %r", cache_tag, CACHE_STATUS_TAG_BITS);
	print("req_line:     %p", ptr_val & (CACHE_STATUS_TAG_MASK | CACHE_STATUS_INDEX_MASK));
	print("cache_line:   %p", line_addr);

	int valid, dirty;
	const char *state;

	switch ((status & CACHE_STATUS_STATE_MASK) >> CACHE_STATUS_STATE_SHIFT) {
		case CACHE_STATUS_STATE_I:
			valid = 0;
			dirty = 0;
			state = "INVALID";
			break;

		case CACHE_STATUS_STATE_S:
			valid = 1;
			dirty = 0;
			state = "SHARED";
			break;

		case CACHE_STATUS_STATE_E:
			valid = 1;
			dirty = 0;
			state = "EXCLUSIVE";
			break;

		case CACHE_STATUS_STATE_M:
			valid = 1;
			dirty = 1;
			state = "MODIFIED";
			break;
	}

	print("valid=%d dirty=%d state=%s", valid, dirty, state);
	print("access is a %s on cpu%u", valid && addr_tag == cache_tag ? "hit" : "miss", cpu);

	for (unsigned i = 0; i < 4; ++i) {
		print("%p: %x", line_addr | i << CACHE_STATUS_STATE_SHIFT, CACHE_DEBUG_WORD(cpu, i));
	}
}