aboutsummaryrefslogtreecommitdiff
path: root/src/shareable_cache.rs
blob: 9e0725a43bb6f2b1d567b6ff0690fd3b201fcf16 (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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
use rustv::isa;
use rustv::memory::{MemoryInterface, Result, SharedMemory};

/// A cache that can be used as two separate caches or one
/// set-associative cache.
pub struct ShareableCache<'a> {
    core_id: usize,
    primary: SharedMemory<'a>,
    secondary: SharedMemory<'a>,
    secondary_enabled: bool,
    use_secondary: bool,
}

impl<'a> ShareableCache<'a> {
    pub fn new(core_id: usize,
               cache1: SharedMemory<'a>, cache2: SharedMemory<'a>)
               -> ShareableCache<'a> {
        ShareableCache {
            core_id: core_id,
            primary: cache1.clone(),
            secondary: cache2.clone(),
            secondary_enabled: false,
            use_secondary: false,
        }
    }

    pub fn enable_secondary(&mut self) {
        self.secondary_enabled = true;
        self.use_secondary = true;
    }

    pub fn disable_secondary(&mut self) {
        self.secondary_enabled = false;
    }

    fn address_accessible(&self, address: isa::Address) -> (bool, bool) {
        // Use scopes to make sure these borrows end before the
        // branches of the if statement begin
        let primary_accessible = {
            self.primary.borrow().is_address_accessible(address)
        };
        let secondary_accessible = {
            self.secondary.borrow().is_address_accessible(address)
        };

        (primary_accessible, secondary_accessible)
    }

    fn snoop(cache: &mut SharedMemory<'a>,
             address: isa::Address, value: isa::Word) {
        // Cache snooping: update all cache lines when a write is made
        if cache.borrow().is_address_accessible(address) {
            // Depends on invariant: write_word completes instantly
            // when the address is accessible (in-cache)
            cache.borrow_mut().write_word(address, value);
        }
    }
}

impl<'a> MemoryInterface for ShareableCache<'a> {
    fn latency(&self) -> u32 {
        self.primary.borrow().latency()
    }

    fn step(&mut self) {
        // We only step the primary cache. The idea is that the
        // secondary cache should be the primary cache of another
        // ShareableCache.
        self.primary.borrow_mut().step();
    }

    fn is_address_accessible(&self, address: isa::Address) -> bool {
        self.primary.borrow().is_address_accessible(address) ||
            (self.secondary_enabled &&
             self.secondary.borrow().is_address_accessible(address))
    }

    fn read_word(&mut self, address: isa::Address) -> Result<isa::Word> {
        if self.secondary_enabled {
            let (primary_accessible, secondary_accessible) =
                self.address_accessible(address);

            if primary_accessible {
                self.primary.borrow_mut().read_word(address)
            }
            else if secondary_accessible {
                self.secondary.borrow_mut().read_word(address)
            }
            else {
                self.use_secondary = !self.use_secondary;
                if self.use_secondary {
                    self.secondary.borrow_mut().read_word(address)
                }
                else {
                    self.primary.borrow_mut().read_word(address)
                }
            }
        }
        else {
            self.primary.borrow_mut().read_word(address)
        }
    }

    fn write_word(&mut self, address: isa::Address, value: isa::Word) -> Result<()> {
        if self.secondary_enabled {
            let (primary_accessible, secondary_accessible) =
                self.address_accessible(address);

            if primary_accessible {
                ShareableCache::snoop(&mut self.secondary, address, value);
                self.primary.borrow_mut().write_word(address, value)
            }
            else if secondary_accessible {
                ShareableCache::snoop(&mut self.primary, address, value);
                self.secondary.borrow_mut().write_word(address, value)
            }
            else {
                self.use_secondary = !self.use_secondary;
                if self.use_secondary {
                    ShareableCache::snoop(&mut self.primary, address, value);
                    self.secondary.borrow_mut().write_word(address, value)
                }
                else {
                    ShareableCache::snoop(&mut self.secondary, address, value);
                    self.primary.borrow_mut().write_word(address, value)
                }
            }
        }
        else {
            ShareableCache::snoop(&mut self.secondary, address, value);
            self.primary.borrow_mut().write_word(address, value)
        }
    }
}