physical.cc (2665:a124942bacb8) physical.cc (2738:5d7a31c7fa29)
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 * Authors: Ron Dreslinski
29 */
30
31#include <sys/types.h>
32#include <sys/mman.h>
33#include <errno.h>
34#include <fcntl.h>
35#include <unistd.h>
36#include <zlib.h>
37
38#include <iostream>
39#include <string>
40
41
42#include "base/misc.hh"
43#include "config/full_system.hh"
44#include "mem/packet_impl.hh"
45#include "mem/physical.hh"
46#include "sim/host.hh"
47#include "sim/builder.hh"
48#include "sim/eventq.hh"
49#include "arch/isa_traits.hh"
50
51
52using namespace std;
53using namespace TheISA;
54
55PhysicalMemory::MemResponseEvent::MemResponseEvent(Packet *pkt, MemoryPort* _m)
56 : Event(&mainEventQueue, CPU_Tick_Pri), pkt(pkt), memoryPort(_m)
57{
58
59 this->setFlags(AutoDelete);
60}
61
62void
63PhysicalMemory::MemResponseEvent::process()
64{
65 memoryPort->sendTiming(pkt);
66}
67
68const char *
69PhysicalMemory::MemResponseEvent::description()
70{
71 return "Physical Memory Timing Access respnse event";
72}
73
74PhysicalMemory::PhysicalMemory(const string &n, Tick latency)
75 : MemObject(n),base_addr(0), pmem_addr(NULL), port(NULL), lat(latency)
76{
77 // Hardcoded to 128 MB for now.
78 pmem_size = 1 << 27;
79
80 if (pmem_size % TheISA::PageBytes != 0)
81 panic("Memory Size not divisible by page size\n");
82
83 int map_flags = MAP_ANON | MAP_PRIVATE;
84 pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
85 map_flags, -1, 0);
86
87 if (pmem_addr == (void *)MAP_FAILED) {
88 perror("mmap");
89 fatal("Could not mmap!\n");
90 }
91
92 page_ptr = 0;
93}
94
95void
96PhysicalMemory::init()
97{
98 if (!port)
99 panic("PhysicalMemory not connected to anything!");
100 port->sendStatusChange(Port::RangeChange);
101}
102
103PhysicalMemory::~PhysicalMemory()
104{
105 if (pmem_addr)
106 munmap(pmem_addr, pmem_size);
107 //Remove memPorts?
108}
109
110Addr
111PhysicalMemory::new_page()
112{
113 Addr return_addr = page_ptr << LogVMPageSize;
114 return_addr += base_addr;
115
116 ++page_ptr;
117 return return_addr;
118}
119
120int
121PhysicalMemory::deviceBlockSize()
122{
123 //Can accept anysize request
124 return 0;
125}
126
127bool
128PhysicalMemory::doTimingAccess (Packet *pkt, MemoryPort* memoryPort)
129{
130 doFunctionalAccess(pkt);
131
132 // turn packet around to go back to requester
133 pkt->makeTimingResponse();
134 MemResponseEvent* response = new MemResponseEvent(pkt, memoryPort);
135 response->schedule(curTick + lat);
136
137 return true;
138}
139
140Tick
141PhysicalMemory::doAtomicAccess(Packet *pkt)
142{
143 doFunctionalAccess(pkt);
144 return lat;
145}
146
147void
148PhysicalMemory::doFunctionalAccess(Packet *pkt)
149{
150 assert(pkt->getAddr() + pkt->getSize() < pmem_size);
151
152 switch (pkt->cmd) {
153 case Packet::ReadReq:
154 memcpy(pkt->getPtr<uint8_t>(),
155 pmem_addr + pkt->getAddr() - base_addr,
156 pkt->getSize());
157 break;
158 case Packet::WriteReq:
159 memcpy(pmem_addr + pkt->getAddr() - base_addr,
160 pkt->getPtr<uint8_t>(),
161 pkt->getSize());
162 // temporary hack: will need to add real LL/SC implementation
163 // for cacheless systems later.
164 if (pkt->req->getFlags() & LOCKED) {
165 pkt->req->setScResult(1);
166 }
167 break;
168 default:
169 panic("unimplemented");
170 }
171
172 pkt->result = Packet::Success;
173}
174
175Port *
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 * Authors: Ron Dreslinski
29 */
30
31#include <sys/types.h>
32#include <sys/mman.h>
33#include <errno.h>
34#include <fcntl.h>
35#include <unistd.h>
36#include <zlib.h>
37
38#include <iostream>
39#include <string>
40
41
42#include "base/misc.hh"
43#include "config/full_system.hh"
44#include "mem/packet_impl.hh"
45#include "mem/physical.hh"
46#include "sim/host.hh"
47#include "sim/builder.hh"
48#include "sim/eventq.hh"
49#include "arch/isa_traits.hh"
50
51
52using namespace std;
53using namespace TheISA;
54
55PhysicalMemory::MemResponseEvent::MemResponseEvent(Packet *pkt, MemoryPort* _m)
56 : Event(&mainEventQueue, CPU_Tick_Pri), pkt(pkt), memoryPort(_m)
57{
58
59 this->setFlags(AutoDelete);
60}
61
62void
63PhysicalMemory::MemResponseEvent::process()
64{
65 memoryPort->sendTiming(pkt);
66}
67
68const char *
69PhysicalMemory::MemResponseEvent::description()
70{
71 return "Physical Memory Timing Access respnse event";
72}
73
74PhysicalMemory::PhysicalMemory(const string &n, Tick latency)
75 : MemObject(n),base_addr(0), pmem_addr(NULL), port(NULL), lat(latency)
76{
77 // Hardcoded to 128 MB for now.
78 pmem_size = 1 << 27;
79
80 if (pmem_size % TheISA::PageBytes != 0)
81 panic("Memory Size not divisible by page size\n");
82
83 int map_flags = MAP_ANON | MAP_PRIVATE;
84 pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
85 map_flags, -1, 0);
86
87 if (pmem_addr == (void *)MAP_FAILED) {
88 perror("mmap");
89 fatal("Could not mmap!\n");
90 }
91
92 page_ptr = 0;
93}
94
95void
96PhysicalMemory::init()
97{
98 if (!port)
99 panic("PhysicalMemory not connected to anything!");
100 port->sendStatusChange(Port::RangeChange);
101}
102
103PhysicalMemory::~PhysicalMemory()
104{
105 if (pmem_addr)
106 munmap(pmem_addr, pmem_size);
107 //Remove memPorts?
108}
109
110Addr
111PhysicalMemory::new_page()
112{
113 Addr return_addr = page_ptr << LogVMPageSize;
114 return_addr += base_addr;
115
116 ++page_ptr;
117 return return_addr;
118}
119
120int
121PhysicalMemory::deviceBlockSize()
122{
123 //Can accept anysize request
124 return 0;
125}
126
127bool
128PhysicalMemory::doTimingAccess (Packet *pkt, MemoryPort* memoryPort)
129{
130 doFunctionalAccess(pkt);
131
132 // turn packet around to go back to requester
133 pkt->makeTimingResponse();
134 MemResponseEvent* response = new MemResponseEvent(pkt, memoryPort);
135 response->schedule(curTick + lat);
136
137 return true;
138}
139
140Tick
141PhysicalMemory::doAtomicAccess(Packet *pkt)
142{
143 doFunctionalAccess(pkt);
144 return lat;
145}
146
147void
148PhysicalMemory::doFunctionalAccess(Packet *pkt)
149{
150 assert(pkt->getAddr() + pkt->getSize() < pmem_size);
151
152 switch (pkt->cmd) {
153 case Packet::ReadReq:
154 memcpy(pkt->getPtr<uint8_t>(),
155 pmem_addr + pkt->getAddr() - base_addr,
156 pkt->getSize());
157 break;
158 case Packet::WriteReq:
159 memcpy(pmem_addr + pkt->getAddr() - base_addr,
160 pkt->getPtr<uint8_t>(),
161 pkt->getSize());
162 // temporary hack: will need to add real LL/SC implementation
163 // for cacheless systems later.
164 if (pkt->req->getFlags() & LOCKED) {
165 pkt->req->setScResult(1);
166 }
167 break;
168 default:
169 panic("unimplemented");
170 }
171
172 pkt->result = Packet::Success;
173}
174
175Port *
176PhysicalMemory::getPort(const std::string &if_name)
176PhysicalMemory::getPort(const std::string &if_name, int idx)
177{
177{
178 if (if_name == "") {
178 if (if_name == "port" && idx == -1) {
179 if (port != NULL)
180 panic("PhysicalMemory::getPort: additional port requested to memory!");
181 port = new MemoryPort(name() + "-port", this);
182 return port;
183 } else if (if_name == "functional") {
184 /* special port for functional writes at startup. */
185 return new MemoryPort(name() + "-funcport", this);
186 } else {
187 panic("PhysicalMemory::getPort: unknown port %s requested", if_name);
188 }
189}
190
191void
192PhysicalMemory::recvStatusChange(Port::Status status)
193{
194}
195
196PhysicalMemory::MemoryPort::MemoryPort(const std::string &_name,
197 PhysicalMemory *_memory)
198 : Port(_name), memory(_memory)
199{ }
200
201void
202PhysicalMemory::MemoryPort::recvStatusChange(Port::Status status)
203{
204 memory->recvStatusChange(status);
205}
206
207void
208PhysicalMemory::MemoryPort::getDeviceAddressRanges(AddrRangeList &resp,
209 AddrRangeList &snoop)
210{
211 memory->getAddressRanges(resp, snoop);
212}
213
214void
215PhysicalMemory::getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
216{
217 snoop.clear();
218 resp.clear();
219 resp.push_back(RangeSize(base_addr, pmem_size));
220}
221
222int
223PhysicalMemory::MemoryPort::deviceBlockSize()
224{
225 return memory->deviceBlockSize();
226}
227
228bool
229PhysicalMemory::MemoryPort::recvTiming(Packet *pkt)
230{
231 return memory->doTimingAccess(pkt, this);
232}
233
234Tick
235PhysicalMemory::MemoryPort::recvAtomic(Packet *pkt)
236{
237 return memory->doAtomicAccess(pkt);
238}
239
240void
241PhysicalMemory::MemoryPort::recvFunctional(Packet *pkt)
242{
243 memory->doFunctionalAccess(pkt);
244}
245
246
247
248void
249PhysicalMemory::serialize(ostream &os)
250{
251 gzFile compressedMem;
252 string filename = name() + ".physmem";
253
254 SERIALIZE_SCALAR(pmem_size);
255 SERIALIZE_SCALAR(filename);
256
257 // write memory file
258 string thefile = Checkpoint::dir() + "/" + filename.c_str();
259 int fd = creat(thefile.c_str(), 0664);
260 if (fd < 0) {
261 perror("creat");
262 fatal("Can't open physical memory checkpoint file '%s'\n", filename);
263 }
264
265 compressedMem = gzdopen(fd, "wb");
266 if (compressedMem == NULL)
267 fatal("Insufficient memory to allocate compression state for %s\n",
268 filename);
269
270 if (gzwrite(compressedMem, pmem_addr, pmem_size) != pmem_size) {
271 fatal("Write failed on physical memory checkpoint file '%s'\n",
272 filename);
273 }
274
275 if (gzclose(compressedMem))
276 fatal("Close failed on physical memory checkpoint file '%s'\n",
277 filename);
278}
279
280void
281PhysicalMemory::unserialize(Checkpoint *cp, const string &section)
282{
283 gzFile compressedMem;
284 long *tempPage;
285 long *pmem_current;
286 uint64_t curSize;
287 uint32_t bytesRead;
288 const int chunkSize = 16384;
289
290
291 // unmap file that was mmaped in the constructor
292 munmap(pmem_addr, pmem_size);
293
294 string filename;
295
296 UNSERIALIZE_SCALAR(pmem_size);
297 UNSERIALIZE_SCALAR(filename);
298
299 filename = cp->cptDir + "/" + filename;
300
301 // mmap memoryfile
302 int fd = open(filename.c_str(), O_RDONLY);
303 if (fd < 0) {
304 perror("open");
305 fatal("Can't open physical memory checkpoint file '%s'", filename);
306 }
307
308 compressedMem = gzdopen(fd, "rb");
309 if (compressedMem == NULL)
310 fatal("Insufficient memory to allocate compression state for %s\n",
311 filename);
312
313
314 pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
315 MAP_ANON | MAP_PRIVATE, -1, 0);
316
317 if (pmem_addr == (void *)MAP_FAILED) {
318 perror("mmap");
319 fatal("Could not mmap physical memory!\n");
320 }
321
322 curSize = 0;
323 tempPage = (long*)malloc(chunkSize);
324 if (tempPage == NULL)
325 fatal("Unable to malloc memory to read file %s\n", filename);
326
327 /* Only copy bytes that are non-zero, so we don't give the VM system hell */
328 while (curSize < pmem_size) {
329 bytesRead = gzread(compressedMem, tempPage, chunkSize);
330 if (bytesRead != chunkSize && bytesRead != pmem_size - curSize)
331 fatal("Read failed on physical memory checkpoint file '%s'"
332 " got %d bytes, expected %d or %d bytes\n",
333 filename, bytesRead, chunkSize, pmem_size-curSize);
334
335 assert(bytesRead % sizeof(long) == 0);
336
337 for (int x = 0; x < bytesRead/sizeof(long); x++)
338 {
339 if (*(tempPage+x) != 0) {
340 pmem_current = (long*)(pmem_addr + curSize + x * sizeof(long));
341 *pmem_current = *(tempPage+x);
342 }
343 }
344 curSize += bytesRead;
345 }
346
347 free(tempPage);
348
349 if (gzclose(compressedMem))
350 fatal("Close failed on physical memory checkpoint file '%s'\n",
351 filename);
352
353}
354
355
356BEGIN_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
357
358 Param<string> file;
359 Param<Range<Addr> > range;
360 Param<Tick> latency;
361
362END_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
363
364BEGIN_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
365
366 INIT_PARAM_DFLT(file, "memory mapped file", ""),
367 INIT_PARAM(range, "Device Address Range"),
368 INIT_PARAM(latency, "Memory access latency")
369
370END_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
371
372CREATE_SIM_OBJECT(PhysicalMemory)
373{
374
375 return new PhysicalMemory(getInstanceName(), latency);
376}
377
378REGISTER_SIM_OBJECT("PhysicalMemory", PhysicalMemory)
179 if (port != NULL)
180 panic("PhysicalMemory::getPort: additional port requested to memory!");
181 port = new MemoryPort(name() + "-port", this);
182 return port;
183 } else if (if_name == "functional") {
184 /* special port for functional writes at startup. */
185 return new MemoryPort(name() + "-funcport", this);
186 } else {
187 panic("PhysicalMemory::getPort: unknown port %s requested", if_name);
188 }
189}
190
191void
192PhysicalMemory::recvStatusChange(Port::Status status)
193{
194}
195
196PhysicalMemory::MemoryPort::MemoryPort(const std::string &_name,
197 PhysicalMemory *_memory)
198 : Port(_name), memory(_memory)
199{ }
200
201void
202PhysicalMemory::MemoryPort::recvStatusChange(Port::Status status)
203{
204 memory->recvStatusChange(status);
205}
206
207void
208PhysicalMemory::MemoryPort::getDeviceAddressRanges(AddrRangeList &resp,
209 AddrRangeList &snoop)
210{
211 memory->getAddressRanges(resp, snoop);
212}
213
214void
215PhysicalMemory::getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
216{
217 snoop.clear();
218 resp.clear();
219 resp.push_back(RangeSize(base_addr, pmem_size));
220}
221
222int
223PhysicalMemory::MemoryPort::deviceBlockSize()
224{
225 return memory->deviceBlockSize();
226}
227
228bool
229PhysicalMemory::MemoryPort::recvTiming(Packet *pkt)
230{
231 return memory->doTimingAccess(pkt, this);
232}
233
234Tick
235PhysicalMemory::MemoryPort::recvAtomic(Packet *pkt)
236{
237 return memory->doAtomicAccess(pkt);
238}
239
240void
241PhysicalMemory::MemoryPort::recvFunctional(Packet *pkt)
242{
243 memory->doFunctionalAccess(pkt);
244}
245
246
247
248void
249PhysicalMemory::serialize(ostream &os)
250{
251 gzFile compressedMem;
252 string filename = name() + ".physmem";
253
254 SERIALIZE_SCALAR(pmem_size);
255 SERIALIZE_SCALAR(filename);
256
257 // write memory file
258 string thefile = Checkpoint::dir() + "/" + filename.c_str();
259 int fd = creat(thefile.c_str(), 0664);
260 if (fd < 0) {
261 perror("creat");
262 fatal("Can't open physical memory checkpoint file '%s'\n", filename);
263 }
264
265 compressedMem = gzdopen(fd, "wb");
266 if (compressedMem == NULL)
267 fatal("Insufficient memory to allocate compression state for %s\n",
268 filename);
269
270 if (gzwrite(compressedMem, pmem_addr, pmem_size) != pmem_size) {
271 fatal("Write failed on physical memory checkpoint file '%s'\n",
272 filename);
273 }
274
275 if (gzclose(compressedMem))
276 fatal("Close failed on physical memory checkpoint file '%s'\n",
277 filename);
278}
279
280void
281PhysicalMemory::unserialize(Checkpoint *cp, const string &section)
282{
283 gzFile compressedMem;
284 long *tempPage;
285 long *pmem_current;
286 uint64_t curSize;
287 uint32_t bytesRead;
288 const int chunkSize = 16384;
289
290
291 // unmap file that was mmaped in the constructor
292 munmap(pmem_addr, pmem_size);
293
294 string filename;
295
296 UNSERIALIZE_SCALAR(pmem_size);
297 UNSERIALIZE_SCALAR(filename);
298
299 filename = cp->cptDir + "/" + filename;
300
301 // mmap memoryfile
302 int fd = open(filename.c_str(), O_RDONLY);
303 if (fd < 0) {
304 perror("open");
305 fatal("Can't open physical memory checkpoint file '%s'", filename);
306 }
307
308 compressedMem = gzdopen(fd, "rb");
309 if (compressedMem == NULL)
310 fatal("Insufficient memory to allocate compression state for %s\n",
311 filename);
312
313
314 pmem_addr = (uint8_t *)mmap(NULL, pmem_size, PROT_READ | PROT_WRITE,
315 MAP_ANON | MAP_PRIVATE, -1, 0);
316
317 if (pmem_addr == (void *)MAP_FAILED) {
318 perror("mmap");
319 fatal("Could not mmap physical memory!\n");
320 }
321
322 curSize = 0;
323 tempPage = (long*)malloc(chunkSize);
324 if (tempPage == NULL)
325 fatal("Unable to malloc memory to read file %s\n", filename);
326
327 /* Only copy bytes that are non-zero, so we don't give the VM system hell */
328 while (curSize < pmem_size) {
329 bytesRead = gzread(compressedMem, tempPage, chunkSize);
330 if (bytesRead != chunkSize && bytesRead != pmem_size - curSize)
331 fatal("Read failed on physical memory checkpoint file '%s'"
332 " got %d bytes, expected %d or %d bytes\n",
333 filename, bytesRead, chunkSize, pmem_size-curSize);
334
335 assert(bytesRead % sizeof(long) == 0);
336
337 for (int x = 0; x < bytesRead/sizeof(long); x++)
338 {
339 if (*(tempPage+x) != 0) {
340 pmem_current = (long*)(pmem_addr + curSize + x * sizeof(long));
341 *pmem_current = *(tempPage+x);
342 }
343 }
344 curSize += bytesRead;
345 }
346
347 free(tempPage);
348
349 if (gzclose(compressedMem))
350 fatal("Close failed on physical memory checkpoint file '%s'\n",
351 filename);
352
353}
354
355
356BEGIN_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
357
358 Param<string> file;
359 Param<Range<Addr> > range;
360 Param<Tick> latency;
361
362END_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
363
364BEGIN_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
365
366 INIT_PARAM_DFLT(file, "memory mapped file", ""),
367 INIT_PARAM(range, "Device Address Range"),
368 INIT_PARAM(latency, "Memory access latency")
369
370END_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
371
372CREATE_SIM_OBJECT(PhysicalMemory)
373{
374
375 return new PhysicalMemory(getInstanceName(), latency);
376}
377
378REGISTER_SIM_OBJECT("PhysicalMemory", PhysicalMemory)