aboutsummaryrefslogtreecommitdiff
path: root/src/ARMJIT.h
blob: 0fc1c385ed38ef1b7f1d8f30d44da0d43131b0b9 (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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#ifndef ARMJIT_H
#define ARMJIT_H

#include "types.h"

#include "ARM.h"
#include "ARM_InstrInfo.h"

namespace ARMJIT
{

typedef u32 (*CompiledBlock)();

struct FetchedInstr
{
    u32 A_Reg(int pos) const
    {
        return (Instr >> pos) & 0xF;
    }

    u32 T_Reg(int pos) const
    {
        return (Instr >> pos) & 0x7;
    }

    u32 Cond() const
    {
        return Instr >> 28;
    }

    u32 Instr;
    u32 NextInstr[2];

    u8 CodeCycles;

    ARMInstrInfo::Info Info;
};

/* 
	Copied from DeSmuME
	Some names where changed to match the nomenclature of melonDS

	Since it's nowhere explained and atleast I needed some time to get behind it,
	here's a summary on how it works:
		more or less all memory locations from which code can be executed are
		represented by an array of function pointers, which point to null or
		a function which executes a block instructions starting from there.

		The most significant 4 bits of each address is ignored. This 28 bit space is
		divided into 0x2000 32 KB for ARM9 and 0x4000 16 KB for ARM7, each of which 
		a pointer to the relevant place inside the afore mentioned arrays. 32 and 16 KB
		are the sizes of the smallest contigous memory region mapped to the respective CPU.
		Because ARM addresses are always aligned to 4 bytes and Thumb to a 2 byte boundary,
		we only need every second half word to be adressable.

		In case a memory write hits mapped memory, the function block at this
		address is set to null, so it's recompiled the next time it's executed.

		This method has disadvantages, namely that only writing to the
		first instruction of a block marks it as invalid and that memory remapping
        (SWRAM and VRAM) isn't taken into account.
*/

struct BlockCache
{
    CompiledBlock* AddrMapping9[0x2000] = {0};
    CompiledBlock* AddrMapping7[0x4000] = {0};

    CompiledBlock MainRAM[4*1024*1024/2];
	CompiledBlock SWRAM[0x8000/2]; // Shared working RAM
	CompiledBlock ARM9_ITCM[0x8000/2];
	CompiledBlock ARM9_LCDC[0xA4000/2];
	CompiledBlock ARM9_BIOS[0x8000/2];
	CompiledBlock ARM7_BIOS[0x4000/2];
	CompiledBlock ARM7_WRAM[0x10000/2]; // dedicated ARM7 WRAM
	CompiledBlock ARM7_WVRAM[0x40000/2]; // VRAM allocated as Working RAM
};

extern BlockCache cache;

template <u32 num>
inline bool IsMapped(u32 addr)
{
	if (num == 0)
		return cache.AddrMapping9[(addr & 0xFFFFFFF) >> 15];
	else
		return cache.AddrMapping7[(addr & 0xFFFFFFF) >> 14];
}

template <u32 num>
inline CompiledBlock LookUpBlock(u32 addr)
{
	if (num == 0)
		return cache.AddrMapping9[(addr & 0xFFFFFFF) >> 15][(addr & 0x7FFF) >> 1];
	else
		return cache.AddrMapping7[(addr & 0xFFFFFFF) >> 14][(addr & 0x3FFF) >> 1];
}

template <u32 num>
inline void Invalidate16(u32 addr)
{
	if (IsMapped<num>(addr))
	{
		if (num == 0)
			cache.AddrMapping9[(addr & 0xFFFFFFF) >> 15][(addr & 0x7FFF) >> 1] = NULL;
		else
			cache.AddrMapping7[(addr & 0xFFFFFFF) >> 14][(addr & 0x3FFF) >> 1] = NULL;
	}
}

template <u32 num>
inline void Invalidate32(u32 addr)
{
	if (IsMapped<num>(addr))
	{
		if (num == 0)
		{
			CompiledBlock* page = cache.AddrMapping9[(addr & 0xFFFFFFF) >> 15];
			page[(addr & 0x7FFF) >> 1] = NULL;
			page[((addr + 2) & 0x7FFF) >> 1] = NULL;
		}
		else
		{
			CompiledBlock* page = cache.AddrMapping7[(addr & 0xFFFFFFF) >> 14];
			page[(addr & 0x3FFF) >> 1] = NULL;
			page[((addr + 2) & 0x3FFF) >> 1] = NULL;
		}
	}
}

template <u32 num>
inline void InsertBlock(u32 addr, CompiledBlock func)
{
	if (num == 0)
		cache.AddrMapping9[(addr & 0xFFFFFFF) >> 15][(addr & 0x7FFF) >> 1] = func;
	else
		cache.AddrMapping7[(addr & 0xFFFFFFF) >> 14][(addr & 0x3FFF) >> 1] = func;
}

void Init();
void DeInit();

CompiledBlock CompileBlock(ARM* cpu);

void InvalidateBlockCache();

}

#endif