-
Notifications
You must be signed in to change notification settings - Fork 5
/
data_memory.cc
162 lines (145 loc) · 5.37 KB
/
data_memory.cc
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#include <cstring>
#include <fstream>
#include <iostream>
#include "defs.h"
#include "data_cache.h"
#include "data_memory.h"
using namespace std;
data_memory_t::data_memory_t(uint64_t *m_ticks, uint64_t m_memory_size,
uint64_t m_code_segment_size, uint64_t m_latency) :
cache(0),
ticks(m_ticks),
memory(0),
accessed(0),
memory_size(m_memory_size),
code_segment_size(m_code_segment_size),
num_dwords(m_memory_size>>3),
latency(m_latency),
resp_ticks(0),
req_block(0) {
// Check if the memory size is a multiple of doubleword.
if(memory_size & 0b111) {
cerr << "Error: memory size must be a multiple of doubleword" << endl;
exit(1);
}
if(memory_size < min_memory_size) {
cerr << "Error: memory size has to be at least 2KB" << endl;
exit(1);
}
// Allocate a memory space in unit of doublewords.
memory = new int64_t[num_dwords];
accessed = new bool[num_dwords];
// Zero the memory space.
memset(memory, 0, num_dwords * sizeof(int64_t));
memset(accessed, 0, num_dwords * sizeof(bool));
// Load initial memory state.
load_mem_state();
}
data_memory_t::~data_memory_t() {
// Deallocate the memory space.
delete [] memory;
delete [] accessed;
}
// Connect to the upper-level cache.
void data_memory_t::connect(data_cache_t *m_cache) { cache = m_cache; }
// Run the data memory.
void data_memory_t::run() {
if(req_block && (*ticks >= resp_ticks)) {
// Invoke the upper-level cache to handle a returned response.
cache->handle_response(req_block);
// Clear the requested block.
req_block = 0;
}
}
// Load a memory block.
void data_memory_t::load_block(uint64_t m_addr, uint64_t m_block_size) {
// Check the doubleword alignment of memory address.
if(m_addr & 0b111) {
cerr << "Error: invalid alignment of memory address " << m_addr << endl;
exit(1);
}
// Check if the requested block size is within memory space.
if((m_addr+m_block_size) > memory_size) {
cerr << "Error: memory address " << m_addr << " is out of bounds" << endl;
exit(1);
}
else if(m_addr < code_segment_size) {
cerr << "Error: memory address " << m_addr << " is in the code segment" << endl;
exit(1);
}
// Mark all doublewords in the requested block are accessed.
for(uint64_t i = 0; i < m_block_size>>3; i++) { accessed[(m_addr>>3)+i] = true; }
// Set pointer to a requested block.
req_block = &memory[m_addr>>3];
// Set time ticks to respond to the cache later.
resp_ticks = *ticks + latency;
}
// Load initial memory state.
void data_memory_t::load_mem_state() {
// Open a memory state file.
fstream file_stream;
file_stream.open("mem_state", fstream::in);
if(!file_stream.is_open()) {
cerr << "Error: failed to open mem_state" << endl;
exit(1);
}
string line;
size_t line_num = 0;
while(getline(file_stream, line)) {
line_num++;
// Crop everything after a comment symbol.
if(line.find_first_of("#") != string::npos) { line.erase(line.find_first_of("#")); }
// Erase all spaces.
line.erase(remove(line.begin(), line.end(), ' '), line.end());
// Skip blank lines.
if(!line.size()) { continue; }
// Store memory state.
size_t l = line.find_first_of("=");
string addr_str = line.substr(0, l);
// Trim the line.
line.erase(0, l+1);
string data_str = line;
// Check if the memory address and data are valid.
if(!is_num_str(addr_str) || !is_num_str(data_str) ||
!addr_str.length() || !data_str.length()) {
cerr << "Error: invalid memory address and/or data " << addr_str
<< " = " << data_str << " at line #" << line_num
<< " of mem_state" << endl;
exit(1);
}
// Convert the memory address and data string to numbers.
uint64_t memory_addr = get_imm(addr_str);
int64_t memory_data = get_imm(data_str);
// Check the alignment of memory address.
if(memory_addr & 0b111) {
cerr << "Error: invalid alignment of memory address " << memory_addr
<< " at line #" << line_num << " of mem_state" << endl;
exit(1);
}
// The memory address goes out of bounds.
if((memory_addr+8) > memory_size) {
cerr << "Error: memory address " << memory_addr << " is out of bounds"
<< " at line #" << line_num << " of mem_state" << endl;
exit(1);
}
// Check if multiple different values are defined at the same memory address.
int64_t &dword = memory[memory_addr>>3];
if(dword && (dword != memory_data)) {
cerr << "Error: memory address " << memory_addr
<< " has multiple values defined at line # " << line_num
<< " of mem_state" << endl;
exit(1);
}
// Store the memory data.
dword = memory_data;
}
// Close the memory state file.
file_stream.close();
}
// Print memory state.
void data_memory_t::print_state() const {
cout << endl << "Memory state (only accessed addresses):" << endl;
for(uint64_t i = 0; i < num_dwords; i++) {
if(accessed[i]) { cout << "(" << (i<<3) << ") = " << memory[i] << endl; }
}
}