Skip to content

Commit 3fade7f

Browse files
skmpinolen
authored andcommitted
initial mmu support for sq remaps
1 parent e06f450 commit 3fade7f

13 files changed

+312
-22
lines changed

CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ set(RELIB_SOURCES
210210
src/guest/sh4/sh4_dbg.c
211211
src/guest/sh4/sh4_dmac.c
212212
src/guest/sh4/sh4_intc.c
213+
src/guest/sh4/sh4_mmu.c
213214
src/guest/sh4/sh4_tmu.c
214215
src/guest/debugger.c
215216
src/guest/dreamcast.c

src/guest/sh4/sh4.c

+28-2
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ static int sh4_init(struct device *dev) {
165165
sh4->guest->mem = as_translate(sh4->memory_if->space, 0x0);
166166
sh4->guest->space = sh4->memory_if->space;
167167
sh4->guest->invalid_instr = &sh4_invalid_instr;
168+
sh4->guest->load_tlb = &sh4_mmu_load_tlb;
168169
sh4->guest->sq_prefetch = &sh4_ccn_sq_prefetch;
169170
sh4->guest->sleep = &sh4_sleep;
170171
sh4->guest->sr_updated = &sh4_sr_updated;
@@ -212,6 +213,10 @@ void sh4_reset(struct sh4 *sh4, uint32_t pc) {
212213
#include "guest/sh4/sh4_regs.inc"
213214
#undef SH4_REG
214215

216+
/* reset tlb */
217+
memset(sh4->utlb_sq_map, 0, sizeof(sh4->utlb_sq_map));
218+
memset(sh4->utlb, 0, sizeof(sh4->utlb));
219+
215220
/* reset interrupts */
216221
sh4_intc_reprioritize(sh4);
217222

@@ -351,16 +356,37 @@ AM_BEGIN(struct sh4, sh4_data_map)
351356
AM_RANGE(0x80000000, 0x9fffffff) AM_MIRROR(0x00000000) /* p1 */
352357
AM_RANGE(0xa0000000, 0xbfffffff) AM_MIRROR(0x00000000) /* p2 */
353358
AM_RANGE(0xc0000000, 0xdfffffff) AM_MIRROR(0x00000000) /* p3 */
354-
AM_RANGE(0xe0000000, 0xffffffff) AM_MIRROR(0x00000000) /* p4 */
355359

356-
/* internal cache and sq only accessible through p4 */
360+
/* internal cache is only accessible through p0, not any of the mirrors */
357361
AM_RANGE(0x7c000000, 0x7fffffff) AM_HANDLE("sh4 cache",
358362
(mmio_read_cb)&sh4_ccn_cache_read,
359363
(mmio_write_cb)&sh4_ccn_cache_write,
360364
NULL, NULL)
365+
366+
/* p4 area */
361367
AM_RANGE(0xe0000000, 0xe3ffffff) AM_HANDLE("sh4 sq",
362368
(mmio_read_cb)&sh4_ccn_sq_read,
363369
(mmio_write_cb)&sh4_ccn_sq_write,
364370
NULL, NULL)
371+
AM_RANGE(0xf0000000, 0xf1ffffff) AM_HANDLE("sh4 icache",
372+
(mmio_read_cb)&sh4_ccn_icache_read,
373+
(mmio_write_cb)&sh4_ccn_icache_write,
374+
NULL, NULL)
375+
AM_RANGE(0xf2000000, 0xf3ffffff) AM_HANDLE("sh4 itlb",
376+
(mmio_read_cb)&sh4_mmu_itlb_read,
377+
(mmio_write_cb)&sh4_mmu_itlb_write,
378+
NULL, NULL)
379+
AM_RANGE(0xf4000000, 0xf5ffffff) AM_HANDLE("sh4 ocache",
380+
(mmio_read_cb)&sh4_ccn_ocache_read,
381+
(mmio_write_cb)&sh4_ccn_ocache_write,
382+
NULL, NULL)
383+
AM_RANGE(0xf6000000, 0xf7ffffff) AM_HANDLE("sh4 utlb",
384+
(mmio_read_cb)&sh4_mmu_utlb_read,
385+
(mmio_write_cb)&sh4_mmu_utlb_write,
386+
NULL, NULL)
387+
AM_RANGE(0xfc000000, 0xffffffff) AM_HANDLE("sh4 reg",
388+
(mmio_read_cb)&sh4_reg_read,
389+
(mmio_write_cb)&sh4_reg_write,
390+
NULL, NULL)
365391
AM_END();
366392
/* clang-format on */

src/guest/sh4/sh4.h

+30-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ struct sh4_dtr {
3636
int size;
3737
};
3838

39+
struct sh4_tlb_entry {
40+
union pteh hi;
41+
union ptel lo;
42+
};
43+
3944
struct sh4 {
4045
struct device;
4146

@@ -61,6 +66,10 @@ struct sh4 {
6166
uint64_t requested_interrupts;
6267
/* pending interrupts moved to context for fast jit access */
6368

69+
/* mmu */
70+
uint32_t utlb_sq_map[64];
71+
struct sh4_tlb_entry utlb[64];
72+
6473
/* tmu */
6574
struct timer *tmu_timers[3];
6675
};
@@ -71,14 +80,24 @@ DECLARE_COUNTER(sh4_instrs);
7180

7281
AM_DECLARE(sh4_data_map);
7382

83+
/* ccn */
7484
void sh4_ccn_sq_prefetch(void *data, uint32_t addr);
7585
uint32_t sh4_ccn_cache_read(struct sh4 *sh4, uint32_t addr, uint32_t data_mask);
7686
void sh4_ccn_cache_write(struct sh4 *sh4, uint32_t addr, uint32_t data,
7787
uint32_t data_mask);
7888
uint32_t sh4_ccn_sq_read(struct sh4 *sh4, uint32_t addr, uint32_t data_mask);
7989
void sh4_ccn_sq_write(struct sh4 *sh4, uint32_t addr, uint32_t data,
8090
uint32_t data_mask);
81-
91+
uint32_t sh4_ccn_icache_read(struct sh4 *sh4, uint32_t addr,
92+
uint32_t data_mask);
93+
void sh4_ccn_icache_write(struct sh4 *sh4, uint32_t addr, uint32_t data,
94+
uint32_t data_mask);
95+
uint32_t sh4_ccn_ocache_read(struct sh4 *sh4, uint32_t addr,
96+
uint32_t data_mask);
97+
void sh4_ccn_ocache_write(struct sh4 *sh4, uint32_t addr, uint32_t data,
98+
uint32_t data_mask);
99+
100+
/* dbg */
82101
int sh4_dbg_num_registers(struct device *dev);
83102
void sh4_dbg_step(struct device *dev);
84103
void sh4_dbg_add_breakpoint(struct device *dev, int type, uint32_t addr);
@@ -91,10 +110,20 @@ int sh4_dbg_invalid_instr(struct sh4 *sh4);
91110

92111
void sh4_dmac_ddt(struct sh4 *sh, struct sh4_dtr *dtr);
93112

113+
/* intc */
94114
void sh4_intc_update_pending(struct sh4 *sh4);
95115
void sh4_intc_check_pending(void *data);
96116
void sh4_intc_reprioritize(struct sh4 *sh4);
97117

118+
/* mmu */
119+
void sh4_mmu_load_tlb(void *data);
120+
uint32_t sh4_mmu_itlb_read(struct sh4 *sh4, uint32_t addr, uint32_t data_mask);
121+
uint32_t sh4_mmu_utlb_read(struct sh4 *sh4, uint32_t addr, uint32_t data_mask);
122+
void sh4_mmu_itlb_write(struct sh4 *sh4, uint32_t addr, uint32_t data,
123+
uint32_t data_mask);
124+
void sh4_mmu_utlb_write(struct sh4 *sh4, uint32_t addr, uint32_t data,
125+
uint32_t data_mask);
126+
98127
struct sh4 *sh4_create(struct dreamcast *dc);
99128
void sh4_destroy(struct sh4 *sh4);
100129
void sh4_debug_menu(struct sh4 *sh4);

src/guest/sh4/sh4_ccn.c

+60-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
#include "guest/sh4/sh4.h"
22
#include "jit/jit.h"
33

4+
#if 0
5+
#define LOG_CCN LOG_INFO
6+
#else
7+
#define LOG_CCN(...)
8+
#endif
9+
410
/* with OIX, bit 25, rather than bit 13, determines which 4kb bank to use */
511
#define CACHE_OFFSET(addr, OIX) \
612
((OIX ? ((addr & 0x2000000) >> 13) : ((addr & 0x2000) >> 1)) | (addr & 0xfff))
@@ -29,12 +35,27 @@ void sh4_ccn_sq_prefetch(void *data, uint32_t addr) {
2935
DCHECK(addr >= 0xe0000000 && addr <= 0xe3ffffff);
3036

3137
struct sh4 *sh4 = data;
32-
uint32_t dst = addr & 0x03ffffe0;
38+
39+
uint32_t dst = 0x0;
3340
uint32_t sqi = (addr & 0x20) >> 5;
34-
if (sqi) {
35-
dst |= (*sh4->QACR1 & 0x1c) << 24;
41+
42+
if (sh4->MMUCR->AT) {
43+
/* get upper 12 bits from UTLB */
44+
uint32_t vpn = addr >> 20;
45+
dst = sh4->utlb_sq_map[vpn & 0x3f];
46+
47+
/* get lower 20 bits from original address */
48+
dst |= addr & 0xfffe0;
3649
} else {
37-
dst |= (*sh4->QACR0 & 0x1c) << 24;
50+
/* get upper 6 bits from QACR* registers */
51+
if (sqi) {
52+
dst = (*sh4->QACR1 & 0x1c) << 24;
53+
} else {
54+
dst = (*sh4->QACR0 & 0x1c) << 24;
55+
}
56+
57+
/* get lower 26 bits from original address */
58+
dst |= addr & 0x3ffffe0;
3859
}
3960

4061
as_memcpy_to_guest(sh4->memory_if->space, dst, sh4->ctx.sq[sqi], 32);
@@ -69,10 +90,43 @@ void sh4_ccn_sq_write(struct sh4 *sh4, uint32_t addr, uint32_t data,
6990
sh4->ctx.sq[sqi][idx] = data;
7091
}
7192

93+
uint32_t sh4_ccn_icache_read(struct sh4 *sh4, uint32_t addr,
94+
uint32_t data_mask) {
95+
LOG_CCN("sh4_ccn_icache_read 0x%08x", addr);
96+
97+
/* return an invalid entry */
98+
return 0;
99+
}
100+
101+
void sh4_ccn_icache_write(struct sh4 *sh4, uint32_t addr, uint32_t data,
102+
uint32_t data_mask) {
103+
LOG_CCN("sh4_ccn_icache_write 0x%08x", addr);
104+
105+
/* ignore */
106+
}
107+
108+
uint32_t sh4_ccn_ocache_read(struct sh4 *sh4, uint32_t addr,
109+
uint32_t data_mask) {
110+
LOG_CCN("sh4_ccn_ocache_read 0x%08x", addr);
111+
112+
/* return an invalid entry */
113+
return 0;
114+
}
115+
116+
void sh4_ccn_ocache_write(struct sh4 *sh4, uint32_t addr, uint32_t data,
117+
uint32_t data_mask) {
118+
LOG_CCN("sh4_ccn_ocache_write 0x%08x", addr);
119+
120+
/* ignore */
121+
}
122+
72123
REG_W32(sh4_cb, MMUCR) {
73124
struct sh4 *sh4 = dc->sh4;
74-
if (value) {
75-
LOG_FATAL("MMU not currently supported");
125+
126+
sh4->MMUCR->full = value;
127+
128+
if (sh4->MMUCR->AT) {
129+
LOG_WARNING("MMU not fully supported");
76130
}
77131
}
78132

src/guest/sh4/sh4_mmu.c

+123
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
#include "guest/sh4/sh4.h"
2+
3+
#if 0
4+
#define LOG_MMU LOG_INFO
5+
#else
6+
#define LOG_MMU(...)
7+
#endif
8+
9+
#define TLB_INDEX(addr) (((addr) >> 8) & 0x3f)
10+
11+
#define PAGE_SIZE(entry) (((entry)->lo.SZ1 << 1) | (entry)->lo.SZ0)
12+
13+
enum {
14+
PAGE_SIZE_1KB,
15+
PAGE_SIZE_4KB,
16+
PAGE_SIZE_64KB,
17+
PAGE_SIZE_1MB,
18+
};
19+
20+
static void sh4_mmu_utlb_sync(struct sh4 *sh4, struct sh4_tlb_entry *entry) {
21+
int n = entry - sh4->utlb;
22+
23+
/* check if entry maps to sq region [0xe0000000, 0xe3ffffff] */
24+
if ((entry->hi.VPN & (0xfc000000 >> 10)) == (0xe0000000 >> 10)) {
25+
/* assume page size is 1MB
26+
FIXME support all page sizes */
27+
uint32_t vpn = entry->hi.VPN >> 10;
28+
uint32_t ppn = entry->lo.PPN << 10;
29+
30+
sh4->utlb_sq_map[vpn & 0x3f] = ppn;
31+
32+
LOG_INFO("sh4_mmu_utlb_sync sq map (%d) 0x%x -> 0x%x", n, vpn, ppn);
33+
} else {
34+
LOG_FATAL("sh4_mmu_utlb_sync memory mapping not supported");
35+
}
36+
}
37+
38+
static void sh4_mmu_translate(struct sh4 *sh4, uint32_t addr) {}
39+
40+
void sh4_mmu_load_tlb(void *data) {
41+
struct sh4 *sh4 = data;
42+
43+
uint32_t n = sh4->MMUCR->URC;
44+
struct sh4_tlb_entry *entry = &sh4->utlb[n];
45+
entry->lo = *sh4->PTEL;
46+
entry->hi = *sh4->PTEH;
47+
48+
sh4_mmu_utlb_sync(sh4, entry);
49+
}
50+
51+
uint32_t sh4_mmu_itlb_read(struct sh4 *sh4, uint32_t addr, uint32_t data_mask) {
52+
if (addr < 0x01000000) {
53+
LOG_MMU("sh4_mmu_itlb_read address array %08x", addr);
54+
} else {
55+
LOG_MMU("sh4_mmu_itlb_read data array %08x", addr);
56+
}
57+
58+
/* return an invalid entry */
59+
return 0;
60+
}
61+
62+
uint32_t sh4_mmu_utlb_read(struct sh4 *sh4, uint32_t addr, uint32_t data_mask) {
63+
if (addr < 0x01000000) {
64+
LOG_MMU("sh4_mmu_utlb_read address array %08x", addr);
65+
66+
struct sh4_tlb_entry *entry = &sh4->utlb[TLB_INDEX(addr)];
67+
uint32_t data = entry->hi.full;
68+
data |= entry->lo.D << 9;
69+
data |= entry->lo.V << 8;
70+
return data;
71+
} else {
72+
if (addr & 0x800000) {
73+
LOG_FATAL("sh4_mmu_utlb_read data array 2 %08x", addr);
74+
} else {
75+
LOG_MMU("sh4_mmu_utlb_read data array 1 %08x", addr);
76+
77+
struct sh4_tlb_entry *entry = &sh4->utlb[TLB_INDEX(addr)];
78+
uint32_t data = entry->lo.full;
79+
return data;
80+
}
81+
}
82+
}
83+
84+
void sh4_mmu_itlb_write(struct sh4 *sh4, uint32_t addr, uint32_t data,
85+
uint32_t data_mask) {
86+
if (addr < 0x01000000) {
87+
LOG_MMU("sh4_mmu_itlb_write address array %08x %08x", addr, data);
88+
} else {
89+
LOG_MMU("sh4_mmu_itlb_write data array %08x %08x", addr, data);
90+
}
91+
92+
/* ignore */
93+
}
94+
95+
void sh4_mmu_utlb_write(struct sh4 *sh4, uint32_t addr, uint32_t data,
96+
uint32_t data_mask) {
97+
if (addr < 0x01000000) {
98+
if (addr & 0x80) {
99+
LOG_FATAL("sh4_mmu_utlb_write address array (associative) %08x %08x",
100+
addr, data);
101+
} else {
102+
LOG_MMU("sh4_mmu_utlb_write address array %08x %08x", addr, data);
103+
104+
struct sh4_tlb_entry *entry = &sh4->utlb[TLB_INDEX(addr)];
105+
entry->hi.full = data & 0xfffffcff;
106+
entry->lo.D = (data >> 9) & 1;
107+
entry->lo.V = (data >> 8) & 1;
108+
109+
sh4_mmu_utlb_sync(sh4, entry);
110+
}
111+
} else {
112+
if (addr & 0x800000) {
113+
LOG_FATAL("sh4_mmu_utlb_write data array 2 %08x %08x", addr, data);
114+
} else {
115+
LOG_MMU("sh4_mmu_utlb_write data array 1 %08x %08x", addr, data);
116+
117+
struct sh4_tlb_entry *entry = &sh4->utlb[TLB_INDEX(addr)];
118+
entry->lo.full = data;
119+
120+
sh4_mmu_utlb_sync(sh4, entry);
121+
}
122+
}
123+
}

src/guest/sh4/sh4_regs.inc

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
/* ADDR NAME DEFAULT TYPE */
2-
SH4_REG(0xff000000, PTEH, 0x00000000, uint32_t)
3-
SH4_REG(0xff000004, PTEL, 0x00000000, uint32_t)
2+
SH4_REG(0xff000000, PTEH, 0x00000000, union pteh)
3+
SH4_REG(0xff000004, PTEL, 0x00000000, union ptel)
44
SH4_REG(0xff000008, TTB, 0x00000000, uint32_t)
55
SH4_REG(0xff00000c, TEA, 0x00000000, uint32_t)
6-
SH4_REG(0xff000010, MMUCR, 0x00000000, uint32_t)
6+
SH4_REG(0xff000010, MMUCR, 0x00000000, union mmucr)
77
SH4_REG(0xff000014, BASRA, 0x00000000, uint32_t)
88
SH4_REG(0xff000018, BASRB, 0x00000000, uint32_t)
99
SH4_REG(0xff00001c, CCR, 0x00000000, union ccr)

0 commit comments

Comments
 (0)