1 // See LICENSE for license details.
10 #include "processor.h"
11 #include "memtracer.h"
15 // virtual memory configuration
17 const reg_t PGSIZE
= 1 << PGSHIFT
;
25 struct icache_entry_t
{
31 // this class implements a processor's port into the virtual memory system.
32 // an MMU and instruction cache are maintained for simulator performance.
36 mmu_t(char* _mem
, size_t _memsz
);
39 // template for functions that load an aligned value from memory
40 #define load_func(type) \
41 type##_t load_##type(reg_t addr) __attribute__((always_inline)) { \
42 void* paddr = translate(addr, sizeof(type##_t), false, false); \
43 return *(type##_t*)paddr; \
46 // load value from memory at aligned address; zero extend to register width
52 // load value from memory at aligned address; sign extend to register width
58 // template for functions that store an aligned value to memory
59 #define store_func(type) \
60 void store_##type(reg_t addr, type##_t val) { \
61 void* paddr = translate(addr, sizeof(type##_t), true, false); \
62 *(type##_t*)paddr = val; \
65 // store value to memory at aligned address
71 static const reg_t ICACHE_ENTRIES
= 1024;
73 inline size_t icache_index(reg_t addr
)
75 return (addr
/ PC_ALIGN
) % ICACHE_ENTRIES
;
78 inline icache_entry_t
* refill_icache(reg_t addr
, icache_entry_t
* entry
)
80 char* iaddr
= (char*)translate(addr
, 1, false, true);
81 insn_bits_t insn
= *(uint16_t*)iaddr
;
82 int length
= insn_length(insn
);
84 if (likely(length
== 4)) {
85 if (likely(addr
% PGSIZE
< PGSIZE
-2))
86 insn
|= (insn_bits_t
)*(int16_t*)(iaddr
+ 2) << 16;
88 insn
|= (insn_bits_t
)*(int16_t*)translate(addr
+ 2, 1, false, true) << 16;
89 } else if (length
== 2) {
91 } else if (length
== 6) {
92 insn
|= (insn_bits_t
)*(int16_t*)translate(addr
+ 4, 1, false, true) << 32;
93 insn
|= (insn_bits_t
)*(uint16_t*)translate(addr
+ 2, 1, false, true) << 16;
95 static_assert(sizeof(insn_bits_t
) == 8, "insn_bits_t must be uint64_t");
96 insn
|= (insn_bits_t
)*(int16_t*)translate(addr
+ 6, 1, false, true) << 48;
97 insn
|= (insn_bits_t
)*(uint16_t*)translate(addr
+ 4, 1, false, true) << 32;
98 insn
|= (insn_bits_t
)*(uint16_t*)translate(addr
+ 2, 1, false, true) << 16;
101 insn_fetch_t fetch
= {proc
->decode_insn(insn
), insn
};
105 reg_t paddr
= iaddr
- mem
;
106 if (tracer
.interested_in_range(paddr
, paddr
+ 1, false, true)) {
108 tracer
.trace(paddr
, length
, false, true);
113 inline icache_entry_t
* access_icache(reg_t addr
)
115 icache_entry_t
* entry
= &icache
[icache_index(addr
)];
116 if (likely(entry
->tag
== addr
))
118 return refill_icache(addr
, entry
);
121 inline insn_fetch_t
load_insn(reg_t addr
)
123 return access_icache(addr
)->data
;
126 void set_processor(processor_t
* p
) { proc
= p
; flush_tlb(); }
131 void register_memtracer(memtracer_t
*);
137 memtracer_list_t tracer
;
139 // implement an instruction cache for simulator performance
140 icache_entry_t icache
[ICACHE_ENTRIES
];
142 // implement a TLB for simulator performance
143 static const reg_t TLB_ENTRIES
= 256;
144 char* tlb_data
[TLB_ENTRIES
];
145 reg_t tlb_insn_tag
[TLB_ENTRIES
];
146 reg_t tlb_load_tag
[TLB_ENTRIES
];
147 reg_t tlb_store_tag
[TLB_ENTRIES
];
149 // finish translation on a TLB miss and upate the TLB
150 void* refill_tlb(reg_t addr
, reg_t bytes
, bool store
, bool fetch
);
152 // perform a page table walk for a given VA; set referenced/dirty bits
153 reg_t
walk(reg_t addr
, bool supervisor
, bool store
, bool fetch
);
155 // translate a virtual address to a physical address
156 void* translate(reg_t addr
, reg_t bytes
, bool store
, bool fetch
)
157 __attribute__((always_inline
))
159 reg_t idx
= (addr
>> PGSHIFT
) % TLB_ENTRIES
;
160 reg_t expected_tag
= addr
>> PGSHIFT
;
161 reg_t
* tags
= fetch
? tlb_insn_tag
: store
? tlb_store_tag
:tlb_load_tag
;
162 reg_t tag
= tags
[idx
];
163 void* data
= tlb_data
[idx
] + addr
;
165 if (unlikely(addr
& (bytes
-1)))
166 store
? throw trap_store_address_misaligned(addr
) :
167 fetch
? throw trap_instruction_address_misaligned(addr
) :
168 throw trap_load_address_misaligned(addr
);
170 if (likely(tag
== expected_tag
))
173 return refill_tlb(addr
, bytes
, store
, fetch
);
176 friend class processor_t
;