aboutsummaryrefslogtreecommitdiff
path: root/qtmips_machine/cache.cpp
blob: 0f8bd1aa51ae777f22d98cf9c4cf722137af6824 (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
83
84
85
86
87
88
89
90
91
92
93
94
#include "cache.h"

using namespace machine;

Cache::Cache(Memory *m, MachineConfigCache *cc) : cnf(cc) {
    mem = m;
    // Allocate cache data structure
    dt = new struct cache_data*[cc->associativity()];
    for (unsigned i = 0; i < cc->associativity(); i++) {
        dt[i] = new cache_data[cc->sets()];
        for (unsigned y = 0; y < cc->sets(); y++) {
            dt[i][y].valid = false;
            dt[i][y].data = new std::uint32_t[cc->blocks()];
        }
    }
    // Zero hit and miss rate
    hitc = 0;
    missc = 0;
}

void Cache::wword(std::uint32_t address, std::uint32_t value) {
    std::uint32_t *data;
    access(address, &data, false);
    *data = value;

    if (cnf.write_policy() == MachineConfigCache::WP_TROUGH)
        mem->wword(address, value);
}

std::uint32_t Cache::rword(std::uint32_t address) const {
    std::uint32_t *data;
    access(address, &data, true);
    return *data;
}

void Cache::flush() {
    for (unsigned as = 0; as < cnf.associativity(); as++) {
        for (unsigned st = 0; st < cnf.sets(); st++) {
            struct cache_data &cd = dt[as][st];
            if (cnf.write_policy() == MachineConfigCache::WP_BACK && cd.valid && cd.dirty) {
                std::uint32_t base_address = cd.tag * cnf.blocks() * cnf.sets();
                for (unsigned i = 0; i < cnf.blocks(); i++)
                    mem->wword(base_address + (4*i), cd.data[i]);
            }
            cd.dirty = false;
            cd.valid = false;
        }
    }
}

unsigned Cache::hit() {
    return hitc;
}

unsigned Cache::miss() {
    return missc;
}

void Cache::access(std::uint32_t address, std::uint32_t **data, bool read) const {
    // TODO associativity
    address = address >> 2;
    unsigned ssize = cnf.blocks() * cnf.sets();
    std::uint32_t tag = address / ssize;
    std::uint32_t base_address = ((address / cnf.blocks()) * cnf.blocks()) << 2;
    std::uint32_t index = address % ssize;
    std::uint32_t row = index / cnf.blocks();
    std::uint32_t col = index % cnf.blocks();

    struct cache_data &cd = dt[0][row];

    // Verify if we are not replacing
    if (cd.tag != tag && cd.valid) {
        if (cd.dirty && cnf.write_policy() == MachineConfigCache::WP_BACK)
            for (unsigned i = 0; i < cnf.blocks(); i++)
                mem->wword(base_address + (4*i), cd.data[i]);
        cd.valid = false;
        cd.dirty = false;
    }

    if (cd.valid) {
        hitc++;
    } else {
        missc++;
        if (read) { // If this is read and we don't have valid content then read it from memory
            for (unsigned i = 0; i < cnf.blocks(); i++)
                cd.data[i] = mem->rword(base_address + (4*i));
        }
    }

    cd.valid = true; // We either write to it or we read from memory. Either way it's valid when we leave Cache class
    cd.dirty = cd.dirty || !read;
    cd.tag = tag;
    *data = &cd.data[col];
}