physical.cc (2640:266b80dd5eca) physical.cc (2641:6d9d837e2032)
1/*
2 * Copyright (c) 2001-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <sys/types.h>
30#include <sys/mman.h>
31#include <errno.h>
32#include <fcntl.h>
33#include <unistd.h>
34#include <zlib.h>
35
36#include <iostream>
37#include <string>
38
39
40#include "base/misc.hh"
41#include "config/full_system.hh"
42#include "mem/packet_impl.hh"
43#include "mem/physical.hh"
44#include "sim/host.hh"
45#include "sim/builder.hh"
46#include "sim/eventq.hh"
47#include "arch/isa_traits.hh"
48
49
50using namespace std;
51using namespace TheISA;
52
53PhysicalMemory::MemResponseEvent::MemResponseEvent(Packet *pkt, MemoryPort* _m)
54 : Event(&mainEventQueue, CPU_Tick_Pri), pkt(pkt), memoryPort(_m)
55{
56
57 this->setFlags(AutoDelete);
58}
59
60void
61PhysicalMemory::MemResponseEvent::process()
62{
63 memoryPort->sendTiming(pkt);
64}
65
66const char *
67PhysicalMemory::MemResponseEvent::description()
68{
69 return "Physical Memory Timing Access respnse event";
70}
71
72PhysicalMemory::PhysicalMemory(const string &n, Tick latency)
73 : MemObject(n),base_addr(0), pmem_addr(NULL), port(NULL), lat(latency)
74{
75 // Hardcoded to 128 MB for now.
76 pmem_size = 1 << 27;
77
78 if (pmem_size % TheISA::PageBytes != 0)
79 panic("Memory Size not divisible by page size\n");
80
81 int map_flags = MAP_ANON | MAP_PRIVATE;
82 pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
83 map_flags, -1, 0);
84
85 if (pmem_addr == (void *)MAP_FAILED) {
86 perror("mmap");
87 fatal("Could not mmap!\n");
88 }
89
90 page_ptr = 0;
91}
92
93void
94PhysicalMemory::init()
95{
96 if (!port)
97 panic("PhysicalMemory not connected to anything!");
98 port->sendStatusChange(Port::RangeChange);
99}
100
101PhysicalMemory::~PhysicalMemory()
102{
103 if (pmem_addr)
104 munmap(pmem_addr, pmem_size);
105 //Remove memPorts?
106}
107
108Addr
109PhysicalMemory::new_page()
110{
111 Addr return_addr = page_ptr << LogVMPageSize;
112 return_addr += base_addr;
113
114 ++page_ptr;
115 return return_addr;
116}
117
118int
119PhysicalMemory::deviceBlockSize()
120{
121 //Can accept anysize request
122 return 0;
123}
124
125bool
126PhysicalMemory::doTimingAccess (Packet *pkt, MemoryPort* memoryPort)
127{
128 doFunctionalAccess(pkt);
129
130 // turn packet around to go back to requester
1/*
2 * Copyright (c) 2001-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <sys/types.h>
30#include <sys/mman.h>
31#include <errno.h>
32#include <fcntl.h>
33#include <unistd.h>
34#include <zlib.h>
35
36#include <iostream>
37#include <string>
38
39
40#include "base/misc.hh"
41#include "config/full_system.hh"
42#include "mem/packet_impl.hh"
43#include "mem/physical.hh"
44#include "sim/host.hh"
45#include "sim/builder.hh"
46#include "sim/eventq.hh"
47#include "arch/isa_traits.hh"
48
49
50using namespace std;
51using namespace TheISA;
52
53PhysicalMemory::MemResponseEvent::MemResponseEvent(Packet *pkt, MemoryPort* _m)
54 : Event(&mainEventQueue, CPU_Tick_Pri), pkt(pkt), memoryPort(_m)
55{
56
57 this->setFlags(AutoDelete);
58}
59
60void
61PhysicalMemory::MemResponseEvent::process()
62{
63 memoryPort->sendTiming(pkt);
64}
65
66const char *
67PhysicalMemory::MemResponseEvent::description()
68{
69 return "Physical Memory Timing Access respnse event";
70}
71
72PhysicalMemory::PhysicalMemory(const string &n, Tick latency)
73 : MemObject(n),base_addr(0), pmem_addr(NULL), port(NULL), lat(latency)
74{
75 // Hardcoded to 128 MB for now.
76 pmem_size = 1 << 27;
77
78 if (pmem_size % TheISA::PageBytes != 0)
79 panic("Memory Size not divisible by page size\n");
80
81 int map_flags = MAP_ANON | MAP_PRIVATE;
82 pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
83 map_flags, -1, 0);
84
85 if (pmem_addr == (void *)MAP_FAILED) {
86 perror("mmap");
87 fatal("Could not mmap!\n");
88 }
89
90 page_ptr = 0;
91}
92
93void
94PhysicalMemory::init()
95{
96 if (!port)
97 panic("PhysicalMemory not connected to anything!");
98 port->sendStatusChange(Port::RangeChange);
99}
100
101PhysicalMemory::~PhysicalMemory()
102{
103 if (pmem_addr)
104 munmap(pmem_addr, pmem_size);
105 //Remove memPorts?
106}
107
108Addr
109PhysicalMemory::new_page()
110{
111 Addr return_addr = page_ptr << LogVMPageSize;
112 return_addr += base_addr;
113
114 ++page_ptr;
115 return return_addr;
116}
117
118int
119PhysicalMemory::deviceBlockSize()
120{
121 //Can accept anysize request
122 return 0;
123}
124
125bool
126PhysicalMemory::doTimingAccess (Packet *pkt, MemoryPort* memoryPort)
127{
128 doFunctionalAccess(pkt);
129
130 // turn packet around to go back to requester
131 pkt->dest = pkt->src;
131 pkt->makeTimingResponse();
132 MemResponseEvent* response = new MemResponseEvent(pkt, memoryPort);
133 response->schedule(curTick + lat);
134
135 return true;
136}
137
138Tick
139PhysicalMemory::doAtomicAccess(Packet *pkt)
140{
141 doFunctionalAccess(pkt);
142 pkt->time = curTick + lat;
143 return curTick + lat;
144}
145
146void
147PhysicalMemory::doFunctionalAccess(Packet *pkt)
148{
132 MemResponseEvent* response = new MemResponseEvent(pkt, memoryPort);
133 response->schedule(curTick + lat);
134
135 return true;
136}
137
138Tick
139PhysicalMemory::doAtomicAccess(Packet *pkt)
140{
141 doFunctionalAccess(pkt);
142 pkt->time = curTick + lat;
143 return curTick + lat;
144}
145
146void
147PhysicalMemory::doFunctionalAccess(Packet *pkt)
148{
149 assert(pkt->addr + pkt->size < pmem_size);
149 assert(pkt->getAddr() + pkt->getSize() < pmem_size);
150
151 switch (pkt->cmd) {
150
151 switch (pkt->cmd) {
152 case Read:
153 memcpy(pkt->getPtr<uint8_t>(), pmem_addr + pkt->addr - base_addr,
154 pkt->size);
152 case Packet::ReadReq:
153 memcpy(pkt->getPtr(),
154 pmem_addr + pkt->getAddr() - base_addr,
155 pkt->getSize());
155 break;
156 break;
156 case Write:
157 memcpy(pmem_addr + pkt->addr - base_addr, pkt->getPtr<uint8_t>(),
158 pkt->size);
157 case Packet::WriteReq:
158 memcpy(pmem_addr + pkt->getAddr() - base_addr,
159 pkt->getPtr<uint8_t>(),
160 pkt->getSize());
159 // temporary hack: will need to add real LL/SC implementation
160 // for cacheless systems later.
161 if (pkt->req->getFlags() & LOCKED) {
162 pkt->req->setScResult(1);
163 }
164 break;
165 default:
166 panic("unimplemented");
167 }
168
161 // temporary hack: will need to add real LL/SC implementation
162 // for cacheless systems later.
163 if (pkt->req->getFlags() & LOCKED) {
164 pkt->req->setScResult(1);
165 }
166 break;
167 default:
168 panic("unimplemented");
169 }
170
169 pkt->result = Success;
171 pkt->result = Packet::Success;
170}
171
172Port *
173PhysicalMemory::getPort(const std::string &if_name)
174{
175 if (if_name == "") {
176 if (port != NULL)
177 panic("PhysicalMemory::getPort: additional port requested to memory!");
178 port = new MemoryPort(name() + "-port", this);
179 return port;
180 } else if (if_name == "functional") {
181 /* special port for functional writes at startup. */
182 return new MemoryPort(name() + "-funcport", this);
183 } else {
184 panic("PhysicalMemory::getPort: unknown port %s requested", if_name);
185 }
186}
187
188void
189PhysicalMemory::recvStatusChange(Port::Status status)
190{
191}
192
193PhysicalMemory::MemoryPort::MemoryPort(const std::string &_name,
194 PhysicalMemory *_memory)
195 : Port(_name), memory(_memory)
196{ }
197
198void
199PhysicalMemory::MemoryPort::recvStatusChange(Port::Status status)
200{
201 memory->recvStatusChange(status);
202}
203
204void
205PhysicalMemory::MemoryPort::getDeviceAddressRanges(AddrRangeList &resp,
206 AddrRangeList &snoop)
207{
208 memory->getAddressRanges(resp, snoop);
209}
210
211void
212PhysicalMemory::getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
213{
214 snoop.clear();
215 resp.clear();
216 resp.push_back(RangeSize(base_addr, pmem_size));
217}
218
219int
220PhysicalMemory::MemoryPort::deviceBlockSize()
221{
222 return memory->deviceBlockSize();
223}
224
225bool
226PhysicalMemory::MemoryPort::recvTiming(Packet *pkt)
227{
228 return memory->doTimingAccess(pkt, this);
229}
230
231Tick
232PhysicalMemory::MemoryPort::recvAtomic(Packet *pkt)
233{
234 return memory->doAtomicAccess(pkt);
235}
236
237void
238PhysicalMemory::MemoryPort::recvFunctional(Packet *pkt)
239{
240 memory->doFunctionalAccess(pkt);
241}
242
243
244
245void
246PhysicalMemory::serialize(ostream &os)
247{
248 gzFile compressedMem;
249 string filename = name() + ".physmem";
250
251 SERIALIZE_SCALAR(pmem_size);
252 SERIALIZE_SCALAR(filename);
253
254 // write memory file
255 string thefile = Checkpoint::dir() + "/" + filename.c_str();
256 int fd = creat(thefile.c_str(), 0664);
257 if (fd < 0) {
258 perror("creat");
259 fatal("Can't open physical memory checkpoint file '%s'\n", filename);
260 }
261
262 compressedMem = gzdopen(fd, "wb");
263 if (compressedMem == NULL)
264 fatal("Insufficient memory to allocate compression state for %s\n",
265 filename);
266
267 if (gzwrite(compressedMem, pmem_addr, pmem_size) != pmem_size) {
268 fatal("Write failed on physical memory checkpoint file '%s'\n",
269 filename);
270 }
271
272 if (gzclose(compressedMem))
273 fatal("Close failed on physical memory checkpoint file '%s'\n",
274 filename);
275}
276
277void
278PhysicalMemory::unserialize(Checkpoint *cp, const string &section)
279{
280 gzFile compressedMem;
281 long *tempPage;
282 long *pmem_current;
283 uint64_t curSize;
284 uint32_t bytesRead;
285 const int chunkSize = 16384;
286
287
288 // unmap file that was mmaped in the constructor
289 munmap(pmem_addr, pmem_size);
290
291 string filename;
292
293 UNSERIALIZE_SCALAR(pmem_size);
294 UNSERIALIZE_SCALAR(filename);
295
296 filename = cp->cptDir + "/" + filename;
297
298 // mmap memoryfile
299 int fd = open(filename.c_str(), O_RDONLY);
300 if (fd < 0) {
301 perror("open");
302 fatal("Can't open physical memory checkpoint file '%s'", filename);
303 }
304
305 compressedMem = gzdopen(fd, "rb");
306 if (compressedMem == NULL)
307 fatal("Insufficient memory to allocate compression state for %s\n",
308 filename);
309
310
311 pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
312 MAP_ANON | MAP_PRIVATE, -1, 0);
313
314 if (pmem_addr == (void *)MAP_FAILED) {
315 perror("mmap");
316 fatal("Could not mmap physical memory!\n");
317 }
318
319 curSize = 0;
320 tempPage = (long*)malloc(chunkSize);
321 if (tempPage == NULL)
322 fatal("Unable to malloc memory to read file %s\n", filename);
323
324 /* Only copy bytes that are non-zero, so we don't give the VM system hell */
325 while (curSize < pmem_size) {
326 bytesRead = gzread(compressedMem, tempPage, chunkSize);
327 if (bytesRead != chunkSize && bytesRead != pmem_size - curSize)
328 fatal("Read failed on physical memory checkpoint file '%s'"
329 " got %d bytes, expected %d or %d bytes\n",
330 filename, bytesRead, chunkSize, pmem_size-curSize);
331
332 assert(bytesRead % sizeof(long) == 0);
333
334 for (int x = 0; x < bytesRead/sizeof(long); x++)
335 {
336 if (*(tempPage+x) != 0) {
337 pmem_current = (long*)(pmem_addr + curSize + x * sizeof(long));
338 *pmem_current = *(tempPage+x);
339 }
340 }
341 curSize += bytesRead;
342 }
343
344 free(tempPage);
345
346 if (gzclose(compressedMem))
347 fatal("Close failed on physical memory checkpoint file '%s'\n",
348 filename);
349
350}
351
352
353BEGIN_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
354
355 Param<string> file;
356 Param<Range<Addr> > range;
357 Param<Tick> latency;
358
359END_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
360
361BEGIN_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
362
363 INIT_PARAM_DFLT(file, "memory mapped file", ""),
364 INIT_PARAM(range, "Device Address Range"),
365 INIT_PARAM(latency, "Memory access latency")
366
367END_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
368
369CREATE_SIM_OBJECT(PhysicalMemory)
370{
371
372 return new PhysicalMemory(getInstanceName(), latency);
373}
374
375REGISTER_SIM_OBJECT("PhysicalMemory", PhysicalMemory)
172}
173
174Port *
175PhysicalMemory::getPort(const std::string &if_name)
176{
177 if (if_name == "") {
178 if (port != NULL)
179 panic("PhysicalMemory::getPort: additional port requested to memory!");
180 port = new MemoryPort(name() + "-port", this);
181 return port;
182 } else if (if_name == "functional") {
183 /* special port for functional writes at startup. */
184 return new MemoryPort(name() + "-funcport", this);
185 } else {
186 panic("PhysicalMemory::getPort: unknown port %s requested", if_name);
187 }
188}
189
190void
191PhysicalMemory::recvStatusChange(Port::Status status)
192{
193}
194
195PhysicalMemory::MemoryPort::MemoryPort(const std::string &_name,
196 PhysicalMemory *_memory)
197 : Port(_name), memory(_memory)
198{ }
199
200void
201PhysicalMemory::MemoryPort::recvStatusChange(Port::Status status)
202{
203 memory->recvStatusChange(status);
204}
205
206void
207PhysicalMemory::MemoryPort::getDeviceAddressRanges(AddrRangeList &resp,
208 AddrRangeList &snoop)
209{
210 memory->getAddressRanges(resp, snoop);
211}
212
213void
214PhysicalMemory::getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
215{
216 snoop.clear();
217 resp.clear();
218 resp.push_back(RangeSize(base_addr, pmem_size));
219}
220
221int
222PhysicalMemory::MemoryPort::deviceBlockSize()
223{
224 return memory->deviceBlockSize();
225}
226
227bool
228PhysicalMemory::MemoryPort::recvTiming(Packet *pkt)
229{
230 return memory->doTimingAccess(pkt, this);
231}
232
233Tick
234PhysicalMemory::MemoryPort::recvAtomic(Packet *pkt)
235{
236 return memory->doAtomicAccess(pkt);
237}
238
239void
240PhysicalMemory::MemoryPort::recvFunctional(Packet *pkt)
241{
242 memory->doFunctionalAccess(pkt);
243}
244
245
246
247void
248PhysicalMemory::serialize(ostream &os)
249{
250 gzFile compressedMem;
251 string filename = name() + ".physmem";
252
253 SERIALIZE_SCALAR(pmem_size);
254 SERIALIZE_SCALAR(filename);
255
256 // write memory file
257 string thefile = Checkpoint::dir() + "/" + filename.c_str();
258 int fd = creat(thefile.c_str(), 0664);
259 if (fd < 0) {
260 perror("creat");
261 fatal("Can't open physical memory checkpoint file '%s'\n", filename);
262 }
263
264 compressedMem = gzdopen(fd, "wb");
265 if (compressedMem == NULL)
266 fatal("Insufficient memory to allocate compression state for %s\n",
267 filename);
268
269 if (gzwrite(compressedMem, pmem_addr, pmem_size) != pmem_size) {
270 fatal("Write failed on physical memory checkpoint file '%s'\n",
271 filename);
272 }
273
274 if (gzclose(compressedMem))
275 fatal("Close failed on physical memory checkpoint file '%s'\n",
276 filename);
277}
278
279void
280PhysicalMemory::unserialize(Checkpoint *cp, const string &section)
281{
282 gzFile compressedMem;
283 long *tempPage;
284 long *pmem_current;
285 uint64_t curSize;
286 uint32_t bytesRead;
287 const int chunkSize = 16384;
288
289
290 // unmap file that was mmaped in the constructor
291 munmap(pmem_addr, pmem_size);
292
293 string filename;
294
295 UNSERIALIZE_SCALAR(pmem_size);
296 UNSERIALIZE_SCALAR(filename);
297
298 filename = cp->cptDir + "/" + filename;
299
300 // mmap memoryfile
301 int fd = open(filename.c_str(), O_RDONLY);
302 if (fd < 0) {
303 perror("open");
304 fatal("Can't open physical memory checkpoint file '%s'", filename);
305 }
306
307 compressedMem = gzdopen(fd, "rb");
308 if (compressedMem == NULL)
309 fatal("Insufficient memory to allocate compression state for %s\n",
310 filename);
311
312
313 pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
314 MAP_ANON | MAP_PRIVATE, -1, 0);
315
316 if (pmem_addr == (void *)MAP_FAILED) {
317 perror("mmap");
318 fatal("Could not mmap physical memory!\n");
319 }
320
321 curSize = 0;
322 tempPage = (long*)malloc(chunkSize);
323 if (tempPage == NULL)
324 fatal("Unable to malloc memory to read file %s\n", filename);
325
326 /* Only copy bytes that are non-zero, so we don't give the VM system hell */
327 while (curSize < pmem_size) {
328 bytesRead = gzread(compressedMem, tempPage, chunkSize);
329 if (bytesRead != chunkSize && bytesRead != pmem_size - curSize)
330 fatal("Read failed on physical memory checkpoint file '%s'"
331 " got %d bytes, expected %d or %d bytes\n",
332 filename, bytesRead, chunkSize, pmem_size-curSize);
333
334 assert(bytesRead % sizeof(long) == 0);
335
336 for (int x = 0; x < bytesRead/sizeof(long); x++)
337 {
338 if (*(tempPage+x) != 0) {
339 pmem_current = (long*)(pmem_addr + curSize + x * sizeof(long));
340 *pmem_current = *(tempPage+x);
341 }
342 }
343 curSize += bytesRead;
344 }
345
346 free(tempPage);
347
348 if (gzclose(compressedMem))
349 fatal("Close failed on physical memory checkpoint file '%s'\n",
350 filename);
351
352}
353
354
355BEGIN_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
356
357 Param<string> file;
358 Param<Range<Addr> > range;
359 Param<Tick> latency;
360
361END_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
362
363BEGIN_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
364
365 INIT_PARAM_DFLT(file, "memory mapped file", ""),
366 INIT_PARAM(range, "Device Address Range"),
367 INIT_PARAM(latency, "Memory access latency")
368
369END_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
370
371CREATE_SIM_OBJECT(PhysicalMemory)
372{
373
374 return new PhysicalMemory(getInstanceName(), latency);
375}
376
377REGISTER_SIM_OBJECT("PhysicalMemory", PhysicalMemory)