/[pearpc]/src/cpu/cpu_generic/ppc_mmu.cc
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /src/cpu/cpu_generic/ppc_mmu.cc

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (hide annotations)
Wed Sep 5 17:11:21 2007 UTC (16 years, 7 months ago) by dpavlin
File size: 49031 byte(s)
import upstream CVS
1 dpavlin 1 /*
2     * PearPC
3     * ppc_mmu.cc
4     *
5     * Copyright (C) 2003, 2004 Sebastian Biallas (sb@biallas.net)
6     * Portions Copyright (C) 2004 Daniel Foesch (dfoesch@cs.nmsu.edu)
7     * Portions Copyright (C) 2004 Apple Computer, Inc.
8     *
9     * This program is free software; you can redistribute it and/or modify
10     * it under the terms of the GNU General Public License version 2 as
11     * published by the Free Software Foundation.
12     *
13     * This program is distributed in the hope that it will be useful,
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16     * GNU General Public License for more details.
17     *
18     * You should have received a copy of the GNU General Public License
19     * along with this program; if not, write to the Free Software
20     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21     */
22    
23     /* Pages marked: v.???
24     * From: IBM PowerPC MicroProcessor Family: Altivec(tm) Technology...
25     * Programming Environments Manual
26     */
27    
28     #include <cstdlib>
29     #include <cstring>
30     #include "system/arch/sysendian.h"
31     #include "tools/snprintf.h"
32     #include "debug/tracers.h"
33     #include "io/prom/prom.h"
34     #include "io/io.h"
35     #include "ppc_cpu.h"
36     #include "ppc_fpu.h"
37     #include "ppc_vec.h"
38     #include "ppc_mmu.h"
39     #include "ppc_exc.h"
40     #include "ppc_tools.h"
41    
42     byte *gMemory = NULL;
43     uint32 gMemorySize;
44    
45     #undef TLB
46    
47     static int ppc_pte_protection[] = {
48     // read(0)/write(1) key pp
49    
50     // read
51     1, // r/w
52     1, // r/w
53     1, // r/w
54     1, // r
55     0, // -
56     1, // r
57     1, // r/w
58     1, // r
59    
60     // write
61     1, // r/w
62     1, // r/w
63     1, // r/w
64     0, // r
65     0, // -
66     0, // r
67     1, // r/w
68     0, // r
69     };
70    
71     inline int FASTCALL ppc_effective_to_physical(uint32 addr, int flags, uint32 &result)
72     {
73     if (flags & PPC_MMU_CODE) {
74     if (!(gCPU.msr & MSR_IR)) {
75     result = addr;
76     return PPC_MMU_OK;
77     }
78     /*
79     * BAT translation .329
80     */
81    
82     uint32 batu = (gCPU.msr & MSR_PR ? BATU_Vp : BATU_Vs);
83    
84     for (int i=0; i<4; i++) {
85     uint32 bl17 = gCPU.ibat_bl17[i];
86     uint32 addr2 = addr & (bl17 | 0xf001ffff);
87     if (BATU_BEPI(addr2) == BATU_BEPI(gCPU.ibatu[i])) {
88     // bat applies to this address
89     if (gCPU.ibatu[i] & batu) {
90     // bat entry valid
91     uint32 offset = BAT_EA_OFFSET(addr);
92     uint32 page = BAT_EA_11(addr);
93     page &= ~bl17;
94     page |= BATL_BRPN(gCPU.ibatl[i]);
95     // fixme: check access rights
96     result = page | offset;
97     return PPC_MMU_OK;
98     }
99     }
100     }
101     } else {
102     if (!(gCPU.msr & MSR_DR)) {
103     result = addr;
104     return PPC_MMU_OK;
105     }
106     /*
107     * BAT translation .329
108     */
109    
110     uint32 batu = (gCPU.msr & MSR_PR ? BATU_Vp : BATU_Vs);
111    
112     for (int i=0; i<4; i++) {
113     uint32 bl17 = gCPU.dbat_bl17[i];
114     uint32 addr2 = addr & (bl17 | 0xf001ffff);
115     if (BATU_BEPI(addr2) == BATU_BEPI(gCPU.dbatu[i])) {
116     // bat applies to this address
117     if (gCPU.dbatu[i] & batu) {
118     // bat entry valid
119     uint32 offset = BAT_EA_OFFSET(addr);
120     uint32 page = BAT_EA_11(addr);
121     page &= ~bl17;
122     page |= BATL_BRPN(gCPU.dbatl[i]);
123     // fixme: check access rights
124     result = page | offset;
125     return PPC_MMU_OK;
126     }
127     }
128     }
129     }
130    
131     /*
132     * Address translation with segment register
133     */
134     uint32 sr = gCPU.sr[EA_SR(addr)];
135    
136     if (sr & SR_T) {
137     // woea
138     // FIXME: implement me
139     PPC_MMU_ERR("sr & T\n");
140     } else {
141     #ifdef TLB
142     for (int i=0; i<4; i++) {
143     if ((addr & ~0xfff) == (gCPU.tlb_va[i])) {
144     gCPU.tlb_last = i;
145     // ht_printf("TLB: %d: %08x -> %08x\n", i, addr, gCPU.tlb_pa[i] | (addr & 0xfff));
146     result = gCPU.tlb_pa[i] | (addr & 0xfff);
147     return PPC_MMU_OK;
148     }
149     }
150     #endif
151     // page address translation
152     if ((flags & PPC_MMU_CODE) && (sr & SR_N)) {
153     // segment isnt executable
154     if (!(flags & PPC_MMU_NO_EXC)) {
155     ppc_exception(PPC_EXC_ISI, PPC_EXC_SRR1_GUARD);
156     return PPC_MMU_EXC;
157     }
158     return PPC_MMU_FATAL;
159     }
160     uint32 offset = EA_Offset(addr); // 12 bit
161     uint32 page_index = EA_PageIndex(addr); // 16 bit
162     uint32 VSID = SR_VSID(sr); // 24 bit
163     uint32 api = EA_API(addr); // 6 bit (part of page_index)
164     // VSID.page_index = Virtual Page Number (VPN)
165    
166     // Hashfunction no 1 "xor" .360
167     uint32 hash1 = (VSID ^ page_index);
168     uint32 pteg_addr = ((hash1 & gCPU.pagetable_hashmask)<<6) | gCPU.pagetable_base;
169     int key;
170     if (gCPU.msr & MSR_PR) {
171     key = (sr & SR_Kp) ? 4 : 0;
172     } else {
173     key = (sr & SR_Ks) ? 4 : 0;
174     }
175    
176     uint32 pte_protection_offset = ((flags&PPC_MMU_WRITE) ? 8:0) + key;
177    
178     for (int i=0; i<8; i++) {
179     uint32 pte;
180     if (ppc_read_physical_word(pteg_addr, pte)) {
181     if (!(flags & PPC_MMU_NO_EXC)) {
182     PPC_MMU_ERR("read physical in address translate failed\n");
183     return PPC_MMU_EXC;
184     }
185     return PPC_MMU_FATAL;
186     }
187     if ((pte & PTE1_V) && (!(pte & PTE1_H))) {
188     if (VSID == PTE1_VSID(pte) && (api == PTE1_API(pte))) {
189     // page found
190     if (ppc_read_physical_word(pteg_addr+4, pte)) {
191     if (!(flags & PPC_MMU_NO_EXC)) {
192     PPC_MMU_ERR("read physical in address translate failed\n");
193     return PPC_MMU_EXC;
194     }
195     return PPC_MMU_FATAL;
196     }
197     // check accessmode .346
198     if (!ppc_pte_protection[pte_protection_offset + PTE2_PP(pte)]) {
199     if (!(flags & PPC_MMU_NO_EXC)) {
200     if (flags & PPC_MMU_CODE) {
201     PPC_MMU_WARN("correct impl? code + read protection\n");
202     ppc_exception(PPC_EXC_ISI, PPC_EXC_SRR1_PROT, addr);
203     return PPC_MMU_EXC;
204     } else {
205     if (flags & PPC_MMU_WRITE) {
206     ppc_exception(PPC_EXC_DSI, PPC_EXC_DSISR_PROT | PPC_EXC_DSISR_STORE, addr);
207     } else {
208     ppc_exception(PPC_EXC_DSI, PPC_EXC_DSISR_PROT, addr);
209     }
210     return PPC_MMU_EXC;
211     }
212     }
213     return PPC_MMU_FATAL;
214     }
215     // ok..
216     uint32 pap = PTE2_RPN(pte);
217     result = pap | offset;
218     #ifdef TLB
219     gCPU.tlb_last++;
220     gCPU.tlb_last &= 3;
221     gCPU.tlb_pa[gCPU.tlb_last] = pap;
222     gCPU.tlb_va[gCPU.tlb_last] = addr & ~0xfff;
223     // ht_printf("TLB: STORE %d: %08x -> %08x\n", gCPU.tlb_last, addr, pap);
224     #endif
225     // update access bits
226     if (flags & PPC_MMU_WRITE) {
227     pte |= PTE2_C | PTE2_R;
228     } else {
229     pte |= PTE2_R;
230     }
231     ppc_write_physical_word(pteg_addr+4, pte);
232     return PPC_MMU_OK;
233     }
234     }
235     pteg_addr+=8;
236     }
237    
238     // Hashfunction no 2 "not" .360
239     hash1 = ~hash1;
240     pteg_addr = ((hash1 & gCPU.pagetable_hashmask)<<6) | gCPU.pagetable_base;
241     for (int i=0; i<8; i++) {
242     uint32 pte;
243     if (ppc_read_physical_word(pteg_addr, pte)) {
244     if (!(flags & PPC_MMU_NO_EXC)) {
245     PPC_MMU_ERR("read physical in address translate failed\n");
246     return PPC_MMU_EXC;
247     }
248     return PPC_MMU_FATAL;
249     }
250     if ((pte & PTE1_V) && (pte & PTE1_H)) {
251     if (VSID == PTE1_VSID(pte) && (api == PTE1_API(pte))) {
252     // page found
253     if (ppc_read_physical_word(pteg_addr+4, pte)) {
254     if (!(flags & PPC_MMU_NO_EXC)) {
255     PPC_MMU_ERR("read physical in address translate failed\n");
256     return PPC_MMU_EXC;
257     }
258     return PPC_MMU_FATAL;
259     }
260     // check accessmode
261     int key;
262     if (gCPU.msr & MSR_PR) {
263     key = (sr & SR_Kp) ? 4 : 0;
264     } else {
265     key = (sr & SR_Ks) ? 4 : 0;
266     }
267     if (!ppc_pte_protection[((flags&PPC_MMU_WRITE)?8:0) + key + PTE2_PP(pte)]) {
268     if (!(flags & PPC_MMU_NO_EXC)) {
269     if (flags & PPC_MMU_CODE) {
270     PPC_MMU_WARN("correct impl? code + read protection\n");
271     ppc_exception(PPC_EXC_ISI, PPC_EXC_SRR1_PROT, addr);
272     return PPC_MMU_EXC;
273     } else {
274     if (flags & PPC_MMU_WRITE) {
275     ppc_exception(PPC_EXC_DSI, PPC_EXC_DSISR_PROT | PPC_EXC_DSISR_STORE, addr);
276     } else {
277     ppc_exception(PPC_EXC_DSI, PPC_EXC_DSISR_PROT, addr);
278     }
279     return PPC_MMU_EXC;
280     }
281     }
282     return PPC_MMU_FATAL;
283     }
284     // ok..
285     result = PTE2_RPN(pte) | offset;
286    
287     // update access bits
288     if (flags & PPC_MMU_WRITE) {
289     pte |= PTE2_C | PTE2_R;
290     } else {
291     pte |= PTE2_R;
292     }
293     ppc_write_physical_word(pteg_addr+4, pte);
294     // PPC_MMU_WARN("hash function 2 used!\n");
295     // gSinglestep = true;
296     return PPC_MMU_OK;
297     }
298     }
299     pteg_addr+=8;
300     }
301     }
302     // page fault
303     if (!(flags & PPC_MMU_NO_EXC)) {
304     if (flags & PPC_MMU_CODE) {
305     ppc_exception(PPC_EXC_ISI, PPC_EXC_SRR1_PAGE);
306     } else {
307     if (flags & PPC_MMU_WRITE) {
308     ppc_exception(PPC_EXC_DSI, PPC_EXC_DSISR_PAGE | PPC_EXC_DSISR_STORE, addr);
309     } else {
310     ppc_exception(PPC_EXC_DSI, PPC_EXC_DSISR_PAGE, addr);
311     }
312     }
313     return PPC_MMU_EXC;
314     }
315     return PPC_MMU_FATAL;
316     }
317    
318     void ppc_mmu_tlb_invalidate()
319     {
320     gCPU.effective_code_page = 0xffffffff;
321     }
322    
323     /*
324     pagetable:
325     min. 2^10 (64k) PTEGs
326     PTEG = 64byte
327     The page table can be any size 2^n where 16 <= n <= 25.
328    
329     A PTEG contains eight
330     PTEs of eight bytes each; therefore, each PTEG is 64 bytes long.
331     */
332    
333     bool FASTCALL ppc_mmu_set_sdr1(uint32 newval, bool quiesce)
334     {
335     /* if (newval == gCPU.sdr1)*/ quiesce = false;
336     PPC_MMU_TRACE("new pagetable: sdr1 = 0x%08x\n", newval);
337     uint32 htabmask = SDR1_HTABMASK(newval);
338     uint32 x = 1;
339     uint32 xx = 0;
340     int n = 0;
341     while ((htabmask & x) && (n < 9)) {
342     n++;
343     xx|=x;
344     x<<=1;
345     }
346     if (htabmask & ~xx) {
347     PPC_MMU_TRACE("new pagetable: broken htabmask (%05x)\n", htabmask);
348     return false;
349     }
350     uint32 htaborg = SDR1_HTABORG(newval);
351     if (htaborg & xx) {
352     PPC_MMU_TRACE("new pagetable: broken htaborg (%05x)\n", htaborg);
353     return false;
354     }
355     gCPU.pagetable_base = htaborg<<16;
356     gCPU.sdr1 = newval;
357     gCPU.pagetable_hashmask = ((xx<<10)|0x3ff);
358     PPC_MMU_TRACE("new pagetable: sdr1 accepted\n");
359     PPC_MMU_TRACE("number of pages: 2^%d pagetable_start: 0x%08x size: 2^%d\n", n+13, gCPU.pagetable_base, n+16);
360     if (quiesce) {
361     prom_quiesce();
362     }
363     return true;
364     }
365    
366     bool FASTCALL ppc_mmu_page_create(uint32 ea, uint32 pa)
367     {
368     uint32 sr = gCPU.sr[EA_SR(ea)];
369     uint32 page_index = EA_PageIndex(ea); // 16 bit
370     uint32 VSID = SR_VSID(sr); // 24 bit
371     uint32 api = EA_API(ea); // 6 bit (part of page_index)
372     uint32 hash1 = (VSID ^ page_index);
373     uint32 pte, pte2;
374     uint32 h = 0;
375     for (int j=0; j<2; j++) {
376     uint32 pteg_addr = ((hash1 & gCPU.pagetable_hashmask)<<6) | gCPU.pagetable_base;
377     for (int i=0; i<8; i++) {
378     if (ppc_read_physical_word(pteg_addr, pte)) {
379     PPC_MMU_ERR("read physical in address translate failed\n");
380     return false;
381     }
382     if (!(pte & PTE1_V)) {
383     // free pagetable entry found
384     pte = PTE1_V | (VSID << 7) | h | api;
385     pte2 = (PA_RPN(pa) << 12) | 0;
386     if (ppc_write_physical_word(pteg_addr, pte)
387     || ppc_write_physical_word(pteg_addr+4, pte2)) {
388     return false;
389     } else {
390     // ok
391     return true;
392     }
393     }
394     pteg_addr+=8;
395     }
396     hash1 = ~hash1;
397     h = PTE1_H;
398     }
399     return false;
400     }
401    
402     inline bool FASTCALL ppc_mmu_page_free(uint32 ea)
403     {
404     return true;
405     }
406    
407     inline int FASTCALL ppc_direct_physical_memory_handle(uint32 addr, byte *&ptr)
408     {
409     if (addr < gMemorySize) {
410     ptr = &gMemory[addr];
411     return PPC_MMU_OK;
412     }
413     return PPC_MMU_FATAL;
414     }
415    
416     int FASTCALL ppc_direct_effective_memory_handle(uint32 addr, byte *&ptr)
417     {
418     uint32 ea;
419     int r;
420     if (!((r = ppc_effective_to_physical(addr, PPC_MMU_READ, ea)))) {
421     return ppc_direct_physical_memory_handle(ea, ptr);
422     }
423     return r;
424     }
425    
426     int FASTCALL ppc_direct_effective_memory_handle_code(uint32 addr, byte *&ptr)
427     {
428     uint32 ea;
429     int r;
430     if (!((r = ppc_effective_to_physical(addr, PPC_MMU_READ | PPC_MMU_CODE, ea)))) {
431     return ppc_direct_physical_memory_handle(ea, ptr);
432     }
433     return r;
434     }
435    
436     inline int FASTCALL ppc_read_physical_qword(uint32 addr, Vector_t &result)
437     {
438     if (addr < gMemorySize) {
439     // big endian
440     VECT_D(result,0) = ppc_dword_from_BE(*((uint64*)(gMemory+addr)));
441     VECT_D(result,1) = ppc_dword_from_BE(*((uint64*)(gMemory+addr+8)));
442     return PPC_MMU_OK;
443     }
444     return io_mem_read128(addr, (uint128 *)&result);
445     }
446    
447     inline int FASTCALL ppc_read_physical_dword(uint32 addr, uint64 &result)
448     {
449     if (addr < gMemorySize) {
450     // big endian
451     result = ppc_dword_from_BE(*((uint64*)(gMemory+addr)));
452     return PPC_MMU_OK;
453     }
454     int ret = io_mem_read64(addr, result);
455     result = ppc_bswap_dword(result);
456     return ret;
457     }
458    
459     inline int FASTCALL ppc_read_physical_word(uint32 addr, uint32 &result)
460     {
461     if (addr < gMemorySize) {
462     // big endian
463     result = ppc_word_from_BE(*((uint32*)(gMemory+addr)));
464     return PPC_MMU_OK;
465     }
466     int ret = io_mem_read(addr, result, 4);
467     result = ppc_bswap_word(result);
468     return ret;
469     }
470    
471     inline int FASTCALL ppc_read_physical_half(uint32 addr, uint16 &result)
472     {
473     if (addr < gMemorySize) {
474     // big endian
475     result = ppc_half_from_BE(*((uint16*)(gMemory+addr)));
476     return PPC_MMU_OK;
477     }
478     uint32 r;
479     int ret = io_mem_read(addr, r, 2);
480     result = ppc_bswap_half(r);
481     return ret;
482     }
483    
484     inline int FASTCALL ppc_read_physical_byte(uint32 addr, uint8 &result)
485     {
486     if (addr < gMemorySize) {
487     // big endian
488     result = gMemory[addr];
489     return PPC_MMU_OK;
490     }
491     uint32 r;
492     int ret = io_mem_read(addr, r, 1);
493     result = r;
494     return ret;
495     }
496    
497     inline int FASTCALL ppc_read_effective_code(uint32 addr, uint32 &result)
498     {
499     if (addr & 3) {
500     // EXC..bla
501     return PPC_MMU_FATAL;
502     }
503     uint32 p;
504     int r;
505     if (!((r=ppc_effective_to_physical(addr, PPC_MMU_READ | PPC_MMU_CODE, p)))) {
506     return ppc_read_physical_word(p, result);
507     }
508     return r;
509     }
510    
511     inline int FASTCALL ppc_read_effective_qword(uint32 addr, Vector_t &result)
512     {
513     uint32 p;
514     int r;
515    
516     addr &= ~0x0f;
517    
518     if (!(r = ppc_effective_to_physical(addr, PPC_MMU_READ, p))) {
519     return ppc_read_physical_qword(p, result);
520     }
521    
522     return r;
523     }
524    
525     inline int FASTCALL ppc_read_effective_dword(uint32 addr, uint64 &result)
526     {
527     uint32 p;
528     int r;
529     if (!(r = ppc_effective_to_physical(addr, PPC_MMU_READ, p))) {
530     if (EA_Offset(addr) > 4088) {
531     // read overlaps two pages.. tricky
532     byte *r1, *r2;
533     byte b[14];
534     ppc_effective_to_physical((addr & ~0xfff)+4089, PPC_MMU_READ, p);
535     if ((r = ppc_direct_physical_memory_handle(p, r1))) return r;
536     if ((r = ppc_effective_to_physical((addr & ~0xfff)+4096, PPC_MMU_READ, p))) return r;
537     if ((r = ppc_direct_physical_memory_handle(p, r2))) return r;
538     memmove(&b[0], r1, 7);
539     memmove(&b[7], r2, 7);
540     memmove(&result, &b[EA_Offset(addr)-4089], 8);
541     result = ppc_dword_from_BE(result);
542     return PPC_MMU_OK;
543     } else {
544     return ppc_read_physical_dword(p, result);
545     }
546     }
547     return r;
548     }
549    
550     inline int FASTCALL ppc_read_effective_word(uint32 addr, uint32 &result)
551     {
552     uint32 p;
553     int r;
554     if (!(r = ppc_effective_to_physical(addr, PPC_MMU_READ, p))) {
555     if (EA_Offset(addr) > 4092) {
556     // read overlaps two pages.. tricky
557     byte *r1, *r2;
558     byte b[6];
559     ppc_effective_to_physical((addr & ~0xfff)+4093, PPC_MMU_READ, p);
560     if ((r = ppc_direct_physical_memory_handle(p, r1))) return r;
561     if ((r = ppc_effective_to_physical((addr & ~0xfff)+4096, PPC_MMU_READ, p))) return r;
562     if ((r = ppc_direct_physical_memory_handle(p, r2))) return r;
563     memmove(&b[0], r1, 3);
564     memmove(&b[3], r2, 3);
565     memmove(&result, &b[EA_Offset(addr)-4093], 4);
566     result = ppc_word_from_BE(result);
567     return PPC_MMU_OK;
568     } else {
569     return ppc_read_physical_word(p, result);
570     }
571     }
572     return r;
573     }
574    
575     inline int FASTCALL ppc_read_effective_half(uint32 addr, uint16 &result)
576     {
577     uint32 p;
578     int r;
579     if (!((r = ppc_effective_to_physical(addr, PPC_MMU_READ, p)))) {
580     if (EA_Offset(addr) > 4094) {
581     // read overlaps two pages.. tricky
582     byte b1, b2;
583     ppc_effective_to_physical((addr & ~0xfff)+4095, PPC_MMU_READ, p);
584     if ((r = ppc_read_physical_byte(p, b1))) return r;
585     if ((r = ppc_effective_to_physical((addr & ~0xfff)+4096, PPC_MMU_READ, p))) return r;
586     if ((r = ppc_read_physical_byte(p, b2))) return r;
587     result = (b1<<8)|b2;
588     return PPC_MMU_OK;
589     } else {
590     return ppc_read_physical_half(p, result);
591     }
592     }
593     return r;
594     }
595    
596     inline int FASTCALL ppc_read_effective_byte(uint32 addr, uint8 &result)
597     {
598     uint32 p;
599     int r;
600     if (!((r = ppc_effective_to_physical(addr, PPC_MMU_READ, p)))) {
601     return ppc_read_physical_byte(p, result);
602     }
603     return r;
604     }
605    
606     inline int FASTCALL ppc_write_physical_qword(uint32 addr, Vector_t data)
607     {
608     if (addr < gMemorySize) {
609     // big endian
610     *((uint64*)(gMemory+addr)) = ppc_dword_to_BE(VECT_D(data,0));
611     *((uint64*)(gMemory+addr+8)) = ppc_dword_to_BE(VECT_D(data,1));
612     return PPC_MMU_OK;
613     }
614     if (io_mem_write128(addr, (uint128 *)&data) == IO_MEM_ACCESS_OK) {
615     return PPC_MMU_OK;
616     } else {
617     return PPC_MMU_FATAL;
618     }
619     }
620    
621     inline int FASTCALL ppc_write_physical_dword(uint32 addr, uint64 data)
622     {
623     if (addr < gMemorySize) {
624     // big endian
625     *((uint64*)(gMemory+addr)) = ppc_dword_to_BE(data);
626     return PPC_MMU_OK;
627     }
628     if (io_mem_write64(addr, ppc_bswap_dword(data)) == IO_MEM_ACCESS_OK) {
629     return PPC_MMU_OK;
630     } else {
631     return PPC_MMU_FATAL;
632     }
633     }
634    
635     inline int FASTCALL ppc_write_physical_word(uint32 addr, uint32 data)
636     {
637     if (addr < gMemorySize) {
638     // big endian
639     *((uint32*)(gMemory+addr)) = ppc_word_to_BE(data);
640     return PPC_MMU_OK;
641     }
642     return io_mem_write(addr, ppc_bswap_word(data), 4);
643     }
644    
645     inline int FASTCALL ppc_write_physical_half(uint32 addr, uint16 data)
646     {
647     if (addr < gMemorySize) {
648     // big endian
649     *((uint16*)(gMemory+addr)) = ppc_half_to_BE(data);
650     return PPC_MMU_OK;
651     }
652     return io_mem_write(addr, ppc_bswap_half(data), 2);
653     }
654    
655     inline int FASTCALL ppc_write_physical_byte(uint32 addr, uint8 data)
656     {
657     if (addr < gMemorySize) {
658     // big endian
659     gMemory[addr] = data;
660     return PPC_MMU_OK;
661     }
662     return io_mem_write(addr, data, 1);
663     }
664    
665     inline int FASTCALL ppc_write_effective_qword(uint32 addr, Vector_t data)
666     {
667     uint32 p;
668     int r;
669    
670     addr &= ~0x0f;
671    
672     if (!((r=ppc_effective_to_physical(addr, PPC_MMU_WRITE, p)))) {
673     return ppc_write_physical_qword(p, data);
674     }
675     return r;
676     }
677    
678     inline int FASTCALL ppc_write_effective_dword(uint32 addr, uint64 data)
679     {
680     uint32 p;
681     int r;
682     if (!((r=ppc_effective_to_physical(addr, PPC_MMU_WRITE, p)))) {
683     if (EA_Offset(addr) > 4088) {
684     // write overlaps two pages.. tricky
685     byte *r1, *r2;
686     byte b[14];
687     ppc_effective_to_physical((addr & ~0xfff)+4089, PPC_MMU_WRITE, p);
688     if ((r = ppc_direct_physical_memory_handle(p, r1))) return r;
689     if ((r = ppc_effective_to_physical((addr & ~0xfff)+4096, PPC_MMU_WRITE, p))) return r;
690     if ((r = ppc_direct_physical_memory_handle(p, r2))) return r;
691     data = ppc_dword_to_BE(data);
692     memmove(&b[0], r1, 7);
693     memmove(&b[7], r2, 7);
694     memmove(&b[EA_Offset(addr)-4089], &data, 8);
695     memmove(r1, &b[0], 7);
696     memmove(r2, &b[7], 7);
697     return PPC_MMU_OK;
698     } else {
699     return ppc_write_physical_dword(p, data);
700     }
701     }
702     return r;
703     }
704    
705     inline int FASTCALL ppc_write_effective_word(uint32 addr, uint32 data)
706     {
707     uint32 p;
708     int r;
709     if (!((r=ppc_effective_to_physical(addr, PPC_MMU_WRITE, p)))) {
710     if (EA_Offset(addr) > 4092) {
711     // write overlaps two pages.. tricky
712     byte *r1, *r2;
713     byte b[6];
714     ppc_effective_to_physical((addr & ~0xfff)+4093, PPC_MMU_WRITE, p);
715     if ((r = ppc_direct_physical_memory_handle(p, r1))) return r;
716     if ((r = ppc_effective_to_physical((addr & ~0xfff)+4096, PPC_MMU_WRITE, p))) return r;
717     if ((r = ppc_direct_physical_memory_handle(p, r2))) return r;
718     data = ppc_word_to_BE(data);
719     memmove(&b[0], r1, 3);
720     memmove(&b[3], r2, 3);
721     memmove(&b[EA_Offset(addr)-4093], &data, 4);
722     memmove(r1, &b[0], 3);
723     memmove(r2, &b[3], 3);
724     return PPC_MMU_OK;
725     } else {
726     return ppc_write_physical_word(p, data);
727     }
728     }
729     return r;
730     }
731    
732     inline int FASTCALL ppc_write_effective_half(uint32 addr, uint16 data)
733     {
734     uint32 p;
735     int r;
736     if (!((r=ppc_effective_to_physical(addr, PPC_MMU_WRITE, p)))) {
737     if (EA_Offset(addr) > 4094) {
738     // write overlaps two pages.. tricky
739     ppc_effective_to_physical((addr & ~0xfff)+4095, PPC_MMU_WRITE, p);
740     if ((r = ppc_write_physical_byte(p, data>>8))) return r;
741     if ((r = ppc_effective_to_physical((addr & ~0xfff)+4096, PPC_MMU_WRITE, p))) return r;
742     if ((r = ppc_write_physical_byte(p, data))) return r;
743     return PPC_MMU_OK;
744     } else {
745     return ppc_write_physical_half(p, data);
746     }
747     }
748     return r;
749     }
750    
751     inline int FASTCALL ppc_write_effective_byte(uint32 addr, uint8 data)
752     {
753     uint32 p;
754     int r;
755     if (!((r=ppc_effective_to_physical(addr, PPC_MMU_WRITE, p)))) {
756     return ppc_write_physical_byte(p, data);
757     }
758     return r;
759     }
760    
761     bool FASTCALL ppc_init_physical_memory(uint size)
762     {
763     if (size < 64*1024*1024) {
764     PPC_MMU_ERR("Main memory size must >= 64MB!\n");
765     }
766     gMemory = (byte*)malloc(size);
767     gMemorySize = size;
768     return gMemory != NULL;
769     }
770    
771     uint32 ppc_get_memory_size()
772     {
773     return gMemorySize;
774     }
775    
776     /***************************************************************************
777     * DMA Interface
778     */
779    
780     bool ppc_dma_write(uint32 dest, const void *src, uint32 size)
781     {
782     if (dest > gMemorySize || (dest+size) > gMemorySize) return false;
783    
784     byte *ptr;
785     ppc_direct_physical_memory_handle(dest, ptr);
786    
787     memcpy(ptr, src, size);
788     return true;
789     }
790    
791     bool ppc_dma_read(void *dest, uint32 src, uint32 size)
792     {
793     if (src > gMemorySize || (src+size) > gMemorySize) return false;
794    
795     byte *ptr;
796     ppc_direct_physical_memory_handle(src, ptr);
797    
798     memcpy(dest, ptr, size);
799     return true;
800     }
801    
802     bool ppc_dma_set(uint32 dest, int c, uint32 size)
803     {
804     if (dest > gMemorySize || (dest+size) > gMemorySize) return false;
805    
806     byte *ptr;
807     ppc_direct_physical_memory_handle(dest, ptr);
808    
809     memset(ptr, c, size);
810     return true;
811     }
812    
813    
814     /***************************************************************************
815     * DEPRECATED prom interface
816     */
817     bool ppc_prom_set_sdr1(uint32 newval, bool quiesce)
818     {
819     return ppc_mmu_set_sdr1(newval, quiesce);
820     }
821    
822     bool ppc_prom_effective_to_physical(uint32 &result, uint32 ea)
823     {
824     return ppc_effective_to_physical(ea, PPC_MMU_READ|PPC_MMU_SV|PPC_MMU_NO_EXC, result) == PPC_MMU_OK;
825     }
826    
827     bool ppc_prom_page_create(uint32 ea, uint32 pa)
828     {
829     uint32 sr = gCPU.sr[EA_SR(ea)];
830     uint32 page_index = EA_PageIndex(ea); // 16 bit
831     uint32 VSID = SR_VSID(sr); // 24 bit
832     uint32 api = EA_API(ea); // 6 bit (part of page_index)
833     uint32 hash1 = (VSID ^ page_index);
834     uint32 pte, pte2;
835     uint32 h = 0;
836     for (int j=0; j<2; j++) {
837     uint32 pteg_addr = ((hash1 & gCPU.pagetable_hashmask)<<6) | gCPU.pagetable_base;
838     for (int i=0; i<8; i++) {
839     if (ppc_read_physical_word(pteg_addr, pte)) {
840     PPC_MMU_ERR("read physical in address translate failed\n");
841     return false;
842     }
843     if (!(pte & PTE1_V)) {
844     // free pagetable entry found
845     pte = PTE1_V | (VSID << 7) | h | api;
846     pte2 = (PA_RPN(pa) << 12) | 0;
847     if (ppc_write_physical_word(pteg_addr, pte)
848     || ppc_write_physical_word(pteg_addr+4, pte2)) {
849     return false;
850     } else {
851     // ok
852     return true;
853     }
854     }
855     pteg_addr+=8;
856     }
857     hash1 = ~hash1;
858     h = PTE1_H;
859     }
860     return false;
861     }
862    
863     bool ppc_prom_page_free(uint32 ea)
864     {
865     return true;
866     }
867    
868     /***************************************************************************
869     * MMU Opcodes
870     */
871    
872     #include "ppc_dec.h"
873    
874     /*
875     * dcbz Data Cache Clear to Zero
876     * .464
877     */
878     void ppc_opc_dcbz()
879     {
880     //PPC_L1_CACHE_LINE_SIZE
881     int rA, rD, rB;
882     PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, rB);
883     // assert rD=0
884     uint32 a = (rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB];
885     // BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
886     ppc_write_effective_dword(a, 0)
887     || ppc_write_effective_dword(a+8, 0)
888     || ppc_write_effective_dword(a+16, 0)
889     || ppc_write_effective_dword(a+24, 0);
890     }
891    
892     /*
893     * lbz Load Byte and Zero
894     * .521
895     */
896     void ppc_opc_lbz()
897     {
898     int rA, rD;
899     uint32 imm;
900     PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rD, rA, imm);
901     uint8 r;
902     int ret = ppc_read_effective_byte((rA?gCPU.gpr[rA]:0)+imm, r);
903     if (ret == PPC_MMU_OK) {
904     gCPU.gpr[rD] = r;
905     }
906     }
907     /*
908     * lbzu Load Byte and Zero with Update
909     * .522
910     */
911     void ppc_opc_lbzu()
912     {
913     int rA, rD;
914     uint32 imm;
915     PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rD, rA, imm);
916     // FIXME: check rA!=0 && rA!=rD
917     uint8 r;
918     int ret = ppc_read_effective_byte(gCPU.gpr[rA]+imm, r);
919     if (ret == PPC_MMU_OK) {
920     gCPU.gpr[rA] += imm;
921     gCPU.gpr[rD] = r;
922     }
923     }
924     /*
925     * lbzux Load Byte and Zero with Update Indexed
926     * .523
927     */
928     void ppc_opc_lbzux()
929     {
930     int rA, rD, rB;
931     PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, rB);
932     // FIXME: check rA!=0 && rA!=rD
933     uint8 r;
934     int ret = ppc_read_effective_byte(gCPU.gpr[rA]+gCPU.gpr[rB], r);
935     if (ret == PPC_MMU_OK) {
936     gCPU.gpr[rA] += gCPU.gpr[rB];
937     gCPU.gpr[rD] = r;
938     }
939     }
940     /*
941     * lbzx Load Byte and Zero Indexed
942     * .524
943     */
944     void ppc_opc_lbzx()
945     {
946     int rA, rD, rB;
947     PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, rB);
948     uint8 r;
949     int ret = ppc_read_effective_byte((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], r);
950     if (ret == PPC_MMU_OK) {
951     gCPU.gpr[rD] = r;
952     }
953     }
954     /*
955     * lfd Load Floating-Point Double
956     * .530
957     */
958     void ppc_opc_lfd()
959     {
960     if ((gCPU.msr & MSR_FP) == 0) {
961     ppc_exception(PPC_EXC_NO_FPU);
962     return;
963     }
964     int rA, frD;
965     uint32 imm;
966     PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, frD, rA, imm);
967     uint64 r;
968     int ret = ppc_read_effective_dword((rA?gCPU.gpr[rA]:0)+imm, r);
969     if (ret == PPC_MMU_OK) {
970     gCPU.fpr[frD] = r;
971     }
972     }
973     /*
974     * lfdu Load Floating-Point Double with Update
975     * .531
976     */
977     void ppc_opc_lfdu()
978     {
979     if ((gCPU.msr & MSR_FP) == 0) {
980     ppc_exception(PPC_EXC_NO_FPU);
981     return;
982     }
983     int rA, frD;
984     uint32 imm;
985     PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, frD, rA, imm);
986     // FIXME: check rA!=0
987     uint64 r;
988     int ret = ppc_read_effective_dword(gCPU.gpr[rA]+imm, r);
989     if (ret == PPC_MMU_OK) {
990     gCPU.fpr[frD] = r;
991     gCPU.gpr[rA] += imm;
992     }
993     }
994     /*
995     * lfdux Load Floating-Point Double with Update Indexed
996     * .532
997     */
998     void ppc_opc_lfdux()
999     {
1000     if ((gCPU.msr & MSR_FP) == 0) {
1001     ppc_exception(PPC_EXC_NO_FPU);
1002     return;
1003     }
1004     int rA, frD, rB;
1005     PPC_OPC_TEMPL_X(gCPU.current_opc, frD, rA, rB);
1006     // FIXME: check rA!=0
1007     uint64 r;
1008     int ret = ppc_read_effective_dword(gCPU.gpr[rA]+gCPU.gpr[rB], r);
1009     if (ret == PPC_MMU_OK) {
1010     gCPU.gpr[rA] += gCPU.gpr[rB];
1011     gCPU.fpr[frD] = r;
1012     }
1013     }
1014     /*
1015     * lfdx Load Floating-Point Double Indexed
1016     * .533
1017     */
1018     void ppc_opc_lfdx()
1019     {
1020     if ((gCPU.msr & MSR_FP) == 0) {
1021     ppc_exception(PPC_EXC_NO_FPU);
1022     return;
1023     }
1024     int rA, frD, rB;
1025     PPC_OPC_TEMPL_X(gCPU.current_opc, frD, rA, rB);
1026     uint64 r;
1027     int ret = ppc_read_effective_dword((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], r);
1028     if (ret == PPC_MMU_OK) {
1029     gCPU.fpr[frD] = r;
1030     }
1031     }
1032     /*
1033     * lfs Load Floating-Point Single
1034     * .534
1035     */
1036     void ppc_opc_lfs()
1037     {
1038     if ((gCPU.msr & MSR_FP) == 0) {
1039     ppc_exception(PPC_EXC_NO_FPU);
1040     return;
1041     }
1042     int rA, frD;
1043     uint32 imm;
1044     PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, frD, rA, imm);
1045     uint32 r;
1046     int ret = ppc_read_effective_word((rA?gCPU.gpr[rA]:0)+imm, r);
1047     if (ret == PPC_MMU_OK) {
1048     ppc_single s;
1049     ppc_double d;
1050     ppc_fpu_unpack_single(s, r);
1051     ppc_fpu_single_to_double(s, d);
1052     ppc_fpu_pack_double(d, gCPU.fpr[frD]);
1053     }
1054     }
1055     /*
1056     * lfsu Load Floating-Point Single with Update
1057     * .535
1058     */
1059     void ppc_opc_lfsu()
1060     {
1061     if ((gCPU.msr & MSR_FP) == 0) {
1062     ppc_exception(PPC_EXC_NO_FPU);
1063     return;
1064     }
1065     int rA, frD;
1066     uint32 imm;
1067     PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, frD, rA, imm);
1068     // FIXME: check rA!=0
1069     uint32 r;
1070     int ret = ppc_read_effective_word(gCPU.gpr[rA]+imm, r);
1071     if (ret == PPC_MMU_OK) {
1072     ppc_single s;
1073     ppc_double d;
1074     ppc_fpu_unpack_single(s, r);
1075     ppc_fpu_single_to_double(s, d);
1076     ppc_fpu_pack_double(d, gCPU.fpr[frD]);
1077     gCPU.gpr[rA] += imm;
1078     }
1079     }
1080     /*
1081     * lfsux Load Floating-Point Single with Update Indexed
1082     * .536
1083     */
1084     void ppc_opc_lfsux()
1085     {
1086     if ((gCPU.msr & MSR_FP) == 0) {
1087     ppc_exception(PPC_EXC_NO_FPU);
1088     return;
1089     }
1090     int rA, frD, rB;
1091     PPC_OPC_TEMPL_X(gCPU.current_opc, frD, rA, rB);
1092     // FIXME: check rA!=0
1093     uint32 r;
1094     int ret = ppc_read_effective_word(gCPU.gpr[rA]+gCPU.gpr[rB], r);
1095     if (ret == PPC_MMU_OK) {
1096     gCPU.gpr[rA] += gCPU.gpr[rB];
1097     ppc_single s;
1098     ppc_double d;
1099     ppc_fpu_unpack_single(s, r);
1100     ppc_fpu_single_to_double(s, d);
1101     ppc_fpu_pack_double(d, gCPU.fpr[frD]);
1102     }
1103     }
1104     /*
1105     * lfsx Load Floating-Point Single Indexed
1106     * .537
1107     */
1108     void ppc_opc_lfsx()
1109     {
1110     if ((gCPU.msr & MSR_FP) == 0) {
1111     ppc_exception(PPC_EXC_NO_FPU);
1112     return;
1113     }
1114     int rA, frD, rB;
1115     PPC_OPC_TEMPL_X(gCPU.current_opc, frD, rA, rB);
1116     uint32 r;
1117     int ret = ppc_read_effective_word((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], r);
1118     if (ret == PPC_MMU_OK) {
1119     ppc_single s;
1120     ppc_double d;
1121     ppc_fpu_unpack_single(s, r);
1122     ppc_fpu_single_to_double(s, d);
1123     ppc_fpu_pack_double(d, gCPU.fpr[frD]);
1124     }
1125     }
1126     /*
1127     * lha Load Half Word Algebraic
1128     * .538
1129     */
1130     void ppc_opc_lha()
1131     {
1132     int rA, rD;
1133     uint32 imm;
1134     PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rD, rA, imm);
1135     uint16 r;
1136     int ret = ppc_read_effective_half((rA?gCPU.gpr[rA]:0)+imm, r);
1137     if (ret == PPC_MMU_OK) {
1138     gCPU.gpr[rD] = (r&0x8000)?(r|0xffff0000):r;
1139     }
1140     }
1141     /*
1142     * lhau Load Half Word Algebraic with Update
1143     * .539
1144     */
1145     void ppc_opc_lhau()
1146     {
1147     int rA, rD;
1148     uint32 imm;
1149     PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rD, rA, imm);
1150     uint16 r;
1151     // FIXME: rA != 0
1152     int ret = ppc_read_effective_half(gCPU.gpr[rA]+imm, r);
1153     if (ret == PPC_MMU_OK) {
1154     gCPU.gpr[rA] += imm;
1155     gCPU.gpr[rD] = (r&0x8000)?(r|0xffff0000):r;
1156     }
1157     }
1158     /*
1159     * lhaux Load Half Word Algebraic with Update Indexed
1160     * .540
1161     */
1162     void ppc_opc_lhaux()
1163     {
1164     int rA, rD, rB;
1165     PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, rB);
1166     uint16 r;
1167     // FIXME: rA != 0
1168     int ret = ppc_read_effective_half(gCPU.gpr[rA]+gCPU.gpr[rB], r);
1169     if (ret == PPC_MMU_OK) {
1170     gCPU.gpr[rA] += gCPU.gpr[rB];
1171     gCPU.gpr[rD] = (r&0x8000)?(r|0xffff0000):r;
1172     }
1173     }
1174     /*
1175     * lhax Load Half Word Algebraic Indexed
1176     * .541
1177     */
1178     void ppc_opc_lhax()
1179     {
1180     int rA, rD, rB;
1181     PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, rB);
1182     uint16 r;
1183     // FIXME: rA != 0
1184     int ret = ppc_read_effective_half((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], r);
1185     if (ret == PPC_MMU_OK) {
1186     gCPU.gpr[rD] = (r&0x8000) ? (r|0xffff0000):r;
1187     }
1188     }
1189     /*
1190     * lhbrx Load Half Word Byte-Reverse Indexed
1191     * .542
1192     */
1193     void ppc_opc_lhbrx()
1194     {
1195     int rA, rD, rB;
1196     PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, rB);
1197     uint16 r;
1198     int ret = ppc_read_effective_half((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], r);
1199     if (ret == PPC_MMU_OK) {
1200     gCPU.gpr[rD] = ppc_bswap_half(r);
1201     }
1202     }
1203     /*
1204     * lhz Load Half Word and Zero
1205     * .543
1206     */
1207     void ppc_opc_lhz()
1208     {
1209     int rA, rD;
1210     uint32 imm;
1211     PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rD, rA, imm);
1212     uint16 r;
1213     int ret = ppc_read_effective_half((rA?gCPU.gpr[rA]:0)+imm, r);
1214     if (ret == PPC_MMU_OK) {
1215     gCPU.gpr[rD] = r;
1216     }
1217     }
1218     /*
1219     * lhzu Load Half Word and Zero with Update
1220     * .544
1221     */
1222     void ppc_opc_lhzu()
1223     {
1224     int rA, rD;
1225     uint32 imm;
1226     PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rD, rA, imm);
1227     uint16 r;
1228     // FIXME: rA!=0
1229     int ret = ppc_read_effective_half(gCPU.gpr[rA]+imm, r);
1230     if (ret == PPC_MMU_OK) {
1231     gCPU.gpr[rD] = r;
1232     gCPU.gpr[rA] += imm;
1233     }
1234     }
1235     /*
1236     * lhzux Load Half Word and Zero with Update Indexed
1237     * .545
1238     */
1239     void ppc_opc_lhzux()
1240     {
1241     int rA, rD, rB;
1242     PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, rB);
1243     uint16 r;
1244     // FIXME: rA != 0
1245     int ret = ppc_read_effective_half(gCPU.gpr[rA]+gCPU.gpr[rB], r);
1246     if (ret == PPC_MMU_OK) {
1247     gCPU.gpr[rA] += gCPU.gpr[rB];
1248     gCPU.gpr[rD] = r;
1249     }
1250     }
1251     /*
1252     * lhzx Load Half Word and Zero Indexed
1253     * .546
1254     */
1255     void ppc_opc_lhzx()
1256     {
1257     int rA, rD, rB;
1258     PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, rB);
1259     uint16 r;
1260     int ret = ppc_read_effective_half((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], r);
1261     if (ret == PPC_MMU_OK) {
1262     gCPU.gpr[rD] = r;
1263     }
1264     }
1265     /*
1266     * lmw Load Multiple Word
1267     * .547
1268     */
1269     void ppc_opc_lmw()
1270     {
1271     int rD, rA;
1272     uint32 imm;
1273     PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rD, rA, imm);
1274     uint32 ea = (rA ? gCPU.gpr[rA] : 0) + imm;
1275     while (rD <= 31) {
1276     if (ppc_read_effective_word(ea, gCPU.gpr[rD])) {
1277     return;
1278     }
1279     rD++;
1280     ea += 4;
1281     }
1282     }
1283     /*
1284     * lswi Load String Word Immediate
1285     * .548
1286     */
1287     void ppc_opc_lswi()
1288     {
1289     int rA, rD, NB;
1290     PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, NB);
1291     if (NB==0) NB=32;
1292     uint32 ea = rA ? gCPU.gpr[rA] : 0;
1293     uint32 r = 0;
1294     int i = 4;
1295     uint8 v;
1296     while (NB > 0) {
1297     if (!i) {
1298     i = 4;
1299     gCPU.gpr[rD] = r;
1300     rD++;
1301     rD%=32;
1302     r = 0;
1303     }
1304     if (ppc_read_effective_byte(ea, v)) {
1305     return;
1306     }
1307     r<<=8;
1308     r|=v;
1309     ea++;
1310     i--;
1311     NB--;
1312     }
1313     while (i) { r<<=8; i--; }
1314     gCPU.gpr[rD] = r;
1315     }
1316     /*
1317     * lswx Load String Word Indexed
1318     * .550
1319     */
1320     void ppc_opc_lswx()
1321     {
1322     int rA, rD, rB;
1323     PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, rB);
1324     int NB = XER_n(gCPU.xer);
1325     uint32 ea = gCPU.gpr[rB] + (rA ? gCPU.gpr[rA] : 0);
1326    
1327     uint32 r = 0;
1328     int i = 4;
1329     uint8 v;
1330     while (NB > 0) {
1331     if (!i) {
1332     i = 4;
1333     gCPU.gpr[rD] = r;
1334     rD++;
1335     rD%=32;
1336     r = 0;
1337     }
1338     if (ppc_read_effective_byte(ea, v)) {
1339     return;
1340     }
1341     r<<=8;
1342     r|=v;
1343     ea++;
1344     i--;
1345     NB--;
1346     }
1347     while (i) { r<<=8; i--; }
1348     gCPU.gpr[rD] = r;
1349     }
1350     /*
1351     * lwarx Load Word and Reserve Indexed
1352     * .553
1353     */
1354     void ppc_opc_lwarx()
1355     {
1356     int rA, rD, rB;
1357     PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, rB);
1358     uint32 r;
1359     int ret = ppc_read_effective_word((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], r);
1360     if (ret == PPC_MMU_OK) {
1361     gCPU.gpr[rD] = r;
1362     gCPU.reserve = r;
1363     gCPU.have_reservation = 1;
1364     }
1365     }
1366     /*
1367     * lwbrx Load Word Byte-Reverse Indexed
1368     * .556
1369     */
1370     void ppc_opc_lwbrx()
1371     {
1372     int rA, rD, rB;
1373     PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, rB);
1374     uint32 r;
1375     int ret = ppc_read_effective_word((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], r);
1376     if (ret == PPC_MMU_OK) {
1377     gCPU.gpr[rD] = ppc_bswap_word(r);
1378     }
1379     }
1380     /*
1381     * lwz Load Word and Zero
1382     * .557
1383     */
1384     void ppc_opc_lwz()
1385     {
1386     int rA, rD;
1387     uint32 imm;
1388     PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rD, rA, imm);
1389     uint32 r;
1390     int ret = ppc_read_effective_word((rA?gCPU.gpr[rA]:0)+imm, r);
1391     if (ret == PPC_MMU_OK) {
1392     gCPU.gpr[rD] = r;
1393     }
1394     }
1395     /*
1396     * lbzu Load Word and Zero with Update
1397     * .558
1398     */
1399     void ppc_opc_lwzu()
1400     {
1401     int rA, rD;
1402     uint32 imm;
1403     PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rD, rA, imm);
1404     // FIXME: check rA!=0 && rA!=rD
1405     uint32 r;
1406     int ret = ppc_read_effective_word(gCPU.gpr[rA]+imm, r);
1407     if (ret == PPC_MMU_OK) {
1408     gCPU.gpr[rA] += imm;
1409     gCPU.gpr[rD] = r;
1410     }
1411     }
1412     /*
1413     * lwzux Load Word and Zero with Update Indexed
1414     * .559
1415     */
1416     void ppc_opc_lwzux()
1417     {
1418     int rA, rD, rB;
1419     PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, rB);
1420     // FIXME: check rA!=0 && rA!=rD
1421     uint32 r;
1422     int ret = ppc_read_effective_word(gCPU.gpr[rA]+gCPU.gpr[rB], r);
1423     if (ret == PPC_MMU_OK) {
1424     gCPU.gpr[rA] += gCPU.gpr[rB];
1425     gCPU.gpr[rD] = r;
1426     }
1427     }
1428     /*
1429     * lwzx Load Word and Zero Indexed
1430     * .560
1431     */
1432     void ppc_opc_lwzx()
1433     {
1434     int rA, rD, rB;
1435     PPC_OPC_TEMPL_X(gCPU.current_opc, rD, rA, rB);
1436     uint32 r;
1437     int ret = ppc_read_effective_word((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], r);
1438     if (ret == PPC_MMU_OK) {
1439     gCPU.gpr[rD] = r;
1440     }
1441     }
1442    
1443     /* lvx Load Vector Indexed
1444     * v.127
1445     */
1446     void ppc_opc_lvx()
1447     {
1448     #ifndef __VEC_EXC_OFF__
1449     if ((gCPU.msr & MSR_VEC) == 0) {
1450     ppc_exception(PPC_EXC_NO_VEC);
1451     return;
1452     }
1453     #endif
1454     VECTOR_DEBUG;
1455     int rA, vrD, rB;
1456     PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, rA, rB);
1457     Vector_t r;
1458    
1459     int ea = ((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB]);
1460    
1461     int ret = ppc_read_effective_qword(ea, r);
1462     if (ret == PPC_MMU_OK) {
1463     gCPU.vr[vrD] = r;
1464     }
1465     }
1466    
1467     /* lvxl Load Vector Index LRU
1468     * v.128
1469     */
1470     void ppc_opc_lvxl()
1471     {
1472     ppc_opc_lvx();
1473     /* This instruction should hint to the cache that the value won't be
1474     * needed again in memory anytime soon. We don't emulate the cache,
1475     * so this is effectively exactly the same as lvx.
1476     */
1477     }
1478    
1479     /* lvebx Load Vector Element Byte Indexed
1480     * v.119
1481     */
1482     void ppc_opc_lvebx()
1483     {
1484     #ifndef __VEC_EXC_OFF__
1485     if ((gCPU.msr & MSR_VEC) == 0) {
1486     ppc_exception(PPC_EXC_NO_VEC);
1487     return;
1488     }
1489     #endif
1490     VECTOR_DEBUG;
1491     int rA, vrD, rB;
1492     PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, rA, rB);
1493     uint32 ea;
1494     uint8 r;
1495     ea = (rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB];
1496     int ret = ppc_read_effective_byte(ea, r);
1497     if (ret == PPC_MMU_OK) {
1498     VECT_B(gCPU.vr[vrD], ea & 0xf) = r;
1499     }
1500     }
1501    
1502     /* lvehx Load Vector Element Half Word Indexed
1503     * v.121
1504     */
1505     void ppc_opc_lvehx()
1506     {
1507     #ifndef __VEC_EXC_OFF__
1508     if ((gCPU.msr & MSR_VEC) == 0) {
1509     ppc_exception(PPC_EXC_NO_VEC);
1510     return;
1511     }
1512     #endif
1513     VECTOR_DEBUG;
1514     int rA, vrD, rB;
1515     PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, rA, rB);
1516     uint32 ea;
1517     uint16 r;
1518     ea = ((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB]) & ~1;
1519     int ret = ppc_read_effective_half(ea, r);
1520     if (ret == PPC_MMU_OK) {
1521     VECT_H(gCPU.vr[vrD], (ea & 0xf) >> 1) = r;
1522     }
1523     }
1524    
1525     /* lvewx Load Vector Element Word Indexed
1526     * v.122
1527     */
1528     void ppc_opc_lvewx()
1529     {
1530     #ifndef __VEC_EXC_OFF__
1531     if ((gCPU.msr & MSR_VEC) == 0) {
1532     ppc_exception(PPC_EXC_NO_VEC);
1533     return;
1534     }
1535     #endif
1536     VECTOR_DEBUG;
1537     int rA, vrD, rB;
1538     PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, rA, rB);
1539     uint32 ea;
1540     uint32 r;
1541     ea = ((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB]) & ~3;
1542     int ret = ppc_read_effective_word(ea, r);
1543     if (ret == PPC_MMU_OK) {
1544     VECT_W(gCPU.vr[vrD], (ea & 0xf) >> 2) = r;
1545     }
1546     }
1547    
1548     #if HOST_ENDIANESS == HOST_ENDIANESS_LE
1549     static byte lvsl_helper[] = {
1550     0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18,
1551     0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
1552     0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08,
1553     0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00
1554     };
1555     #elif HOST_ENDIANESS == HOST_ENDIANESS_BE
1556     static byte lvsl_helper[] = {
1557     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1558     0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
1559     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
1560     0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
1561     };
1562     #else
1563     #error Endianess not supported!
1564     #endif
1565    
1566     /*
1567     * lvsl Load Vector for Shift Left
1568     * v.123
1569     */
1570     void ppc_opc_lvsl()
1571     {
1572     #ifndef __VEC_EXC_OFF__
1573     if ((gCPU.msr & MSR_VEC) == 0) {
1574     ppc_exception(PPC_EXC_NO_VEC);
1575     return;
1576     }
1577     #endif
1578     VECTOR_DEBUG;
1579     int rA, vrD, rB;
1580     PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, rA, rB);
1581     uint32 ea;
1582     ea = ((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB]);
1583     #if HOST_ENDIANESS == HOST_ENDIANESS_LE
1584     memmove(&gCPU.vr[vrD], lvsl_helper+0x10-(ea & 0xf), 16);
1585     #elif HOST_ENDIANESS == HOST_ENDIANESS_BE
1586     memmove(&gCPU.vr[vrD], lvsl_helper+(ea & 0xf), 16);
1587     #else
1588     #error Endianess not supported!
1589     #endif
1590     }
1591    
1592     /*
1593     * lvsr Load Vector for Shift Right
1594     * v.125
1595     */
1596     void ppc_opc_lvsr()
1597     {
1598     #ifndef __VEC_EXC_OFF__
1599     if ((gCPU.msr & MSR_VEC) == 0) {
1600     ppc_exception(PPC_EXC_NO_VEC);
1601     return;
1602     }
1603     #endif
1604     VECTOR_DEBUG;
1605     int rA, vrD, rB;
1606     PPC_OPC_TEMPL_X(gCPU.current_opc, vrD, rA, rB);
1607     uint32 ea;
1608     ea = ((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB]);
1609     #if HOST_ENDIANESS == HOST_ENDIANESS_LE
1610     memmove(&gCPU.vr[vrD], lvsl_helper+(ea & 0xf), 16);
1611     #elif HOST_ENDIANESS == HOST_ENDIANESS_BE
1612     memmove(&gCPU.vr[vrD], lvsl_helper+0x10-(ea & 0xf), 16);
1613     #else
1614     #error Endianess not supported!
1615     #endif
1616     }
1617    
1618     /*
1619     * dst Data Stream Touch
1620     * v.115
1621     */
1622     void ppc_opc_dst()
1623     {
1624     VECTOR_DEBUG;
1625     /* Since we are not emulating the cache, this is a nop */
1626     }
1627    
1628     /*
1629     * stb Store Byte
1630     * .632
1631     */
1632     void ppc_opc_stb()
1633     {
1634     int rA, rS;
1635     uint32 imm;
1636     PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rS, rA, imm);
1637     ppc_write_effective_byte((rA?gCPU.gpr[rA]:0)+imm, (uint8)gCPU.gpr[rS]) != PPC_MMU_FATAL;
1638     }
1639     /*
1640     * stbu Store Byte with Update
1641     * .633
1642     */
1643     void ppc_opc_stbu()
1644     {
1645     int rA, rS;
1646     uint32 imm;
1647     PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rS, rA, imm);
1648     // FIXME: check rA!=0
1649     int ret = ppc_write_effective_byte(gCPU.gpr[rA]+imm, (uint8)gCPU.gpr[rS]);
1650     if (ret == PPC_MMU_OK) {
1651     gCPU.gpr[rA] += imm;
1652     }
1653     }
1654     /*
1655     * stbux Store Byte with Update Indexed
1656     * .634
1657     */
1658     void ppc_opc_stbux()
1659     {
1660     int rA, rS, rB;
1661     PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
1662     // FIXME: check rA!=0
1663     int ret = ppc_write_effective_byte(gCPU.gpr[rA]+gCPU.gpr[rB], (uint8)gCPU.gpr[rS]);
1664     if (ret == PPC_MMU_OK) {
1665     gCPU.gpr[rA] += gCPU.gpr[rB];
1666     }
1667     }
1668     /*
1669     * stbx Store Byte Indexed
1670     * .635
1671     */
1672     void ppc_opc_stbx()
1673     {
1674     int rA, rS, rB;
1675     PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
1676     ppc_write_effective_byte((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], (uint8)gCPU.gpr[rS]) != PPC_MMU_FATAL;
1677     }
1678     /*
1679     * stfd Store Floating-Point Double
1680     * .642
1681     */
1682     void ppc_opc_stfd()
1683     {
1684     if ((gCPU.msr & MSR_FP) == 0) {
1685     ppc_exception(PPC_EXC_NO_FPU);
1686     return;
1687     }
1688     int rA, frS;
1689     uint32 imm;
1690     PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, frS, rA, imm);
1691     ppc_write_effective_dword((rA?gCPU.gpr[rA]:0)+imm, gCPU.fpr[frS]) != PPC_MMU_FATAL;
1692     }
1693     /*
1694     * stfdu Store Floating-Point Double with Update
1695     * .643
1696     */
1697     void ppc_opc_stfdu()
1698     {
1699     if ((gCPU.msr & MSR_FP) == 0) {
1700     ppc_exception(PPC_EXC_NO_FPU);
1701     return;
1702     }
1703     int rA, frS;
1704     uint32 imm;
1705     PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, frS, rA, imm);
1706     // FIXME: check rA!=0
1707     int ret = ppc_write_effective_dword(gCPU.gpr[rA]+imm, gCPU.fpr[frS]);
1708     if (ret == PPC_MMU_OK) {
1709     gCPU.gpr[rA] += imm;
1710     }
1711     }
1712     /*
1713     * stfd Store Floating-Point Double with Update Indexed
1714     * .644
1715     */
1716     void ppc_opc_stfdux()
1717     {
1718     if ((gCPU.msr & MSR_FP) == 0) {
1719     ppc_exception(PPC_EXC_NO_FPU);
1720     return;
1721     }
1722     int rA, frS, rB;
1723     PPC_OPC_TEMPL_X(gCPU.current_opc, frS, rA, rB);
1724     // FIXME: check rA!=0
1725     int ret = ppc_write_effective_dword(gCPU.gpr[rA]+gCPU.gpr[rB], gCPU.fpr[frS]);
1726     if (ret == PPC_MMU_OK) {
1727     gCPU.gpr[rA] += gCPU.gpr[rB];
1728     }
1729     }
1730     /*
1731     * stfdx Store Floating-Point Double Indexed
1732     * .645
1733     */
1734     void ppc_opc_stfdx()
1735     {
1736     if ((gCPU.msr & MSR_FP) == 0) {
1737     ppc_exception(PPC_EXC_NO_FPU);
1738     return;
1739     }
1740     int rA, frS, rB;
1741     PPC_OPC_TEMPL_X(gCPU.current_opc, frS, rA, rB);
1742     ppc_write_effective_dword((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], gCPU.fpr[frS]) != PPC_MMU_FATAL;
1743     }
1744     /*
1745     * stfiwx Store Floating-Point as Integer Word Indexed
1746     * .646
1747     */
1748     void ppc_opc_stfiwx()
1749     {
1750     if ((gCPU.msr & MSR_FP) == 0) {
1751     ppc_exception(PPC_EXC_NO_FPU);
1752     return;
1753     }
1754     int rA, frS, rB;
1755     PPC_OPC_TEMPL_X(gCPU.current_opc, frS, rA, rB);
1756     ppc_write_effective_word((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], (uint32)gCPU.fpr[frS]) != PPC_MMU_FATAL;
1757     }
1758     /*
1759     * stfs Store Floating-Point Single
1760     * .647
1761     */
1762     void ppc_opc_stfs()
1763     {
1764     if ((gCPU.msr & MSR_FP) == 0) {
1765     ppc_exception(PPC_EXC_NO_FPU);
1766     return;
1767     }
1768     int rA, frS;
1769     uint32 imm;
1770     PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, frS, rA, imm);
1771     uint32 s;
1772     ppc_double d;
1773     ppc_fpu_unpack_double(d, gCPU.fpr[frS]);
1774     ppc_fpu_pack_single(d, s);
1775     ppc_write_effective_word((rA?gCPU.gpr[rA]:0)+imm, s) != PPC_MMU_FATAL;
1776     }
1777     /*
1778     * stfsu Store Floating-Point Single with Update
1779     * .648
1780     */
1781     void ppc_opc_stfsu()
1782     {
1783     if ((gCPU.msr & MSR_FP) == 0) {
1784     ppc_exception(PPC_EXC_NO_FPU);
1785     return;
1786     }
1787     int rA, frS;
1788     uint32 imm;
1789     PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, frS, rA, imm);
1790     // FIXME: check rA!=0
1791     uint32 s;
1792     ppc_double d;
1793     ppc_fpu_unpack_double(d, gCPU.fpr[frS]);
1794     ppc_fpu_pack_single(d, s);
1795     int ret = ppc_write_effective_word(gCPU.gpr[rA]+imm, s);
1796     if (ret == PPC_MMU_OK) {
1797     gCPU.gpr[rA] += imm;
1798     }
1799     }
1800     /*
1801     * stfsux Store Floating-Point Single with Update Indexed
1802     * .649
1803     */
1804     void ppc_opc_stfsux()
1805     {
1806     if ((gCPU.msr & MSR_FP) == 0) {
1807     ppc_exception(PPC_EXC_NO_FPU);
1808     return;
1809     }
1810     int rA, frS, rB;
1811     PPC_OPC_TEMPL_X(gCPU.current_opc, frS, rA, rB);
1812     // FIXME: check rA!=0
1813     uint32 s;
1814     ppc_double d;
1815     ppc_fpu_unpack_double(d, gCPU.fpr[frS]);
1816     ppc_fpu_pack_single(d, s);
1817     int ret = ppc_write_effective_word(gCPU.gpr[rA]+gCPU.gpr[rB], s);
1818     if (ret == PPC_MMU_OK) {
1819     gCPU.gpr[rA] += gCPU.gpr[rB];
1820     }
1821     }
1822     /*
1823     * stfsx Store Floating-Point Single Indexed
1824     * .650
1825     */
1826     void ppc_opc_stfsx()
1827     {
1828     if ((gCPU.msr & MSR_FP) == 0) {
1829     ppc_exception(PPC_EXC_NO_FPU);
1830     return;
1831     }
1832     int rA, frS, rB;
1833     PPC_OPC_TEMPL_X(gCPU.current_opc, frS, rA, rB);
1834     uint32 s;
1835     ppc_double d;
1836     ppc_fpu_unpack_double(d, gCPU.fpr[frS]);
1837     ppc_fpu_pack_single(d, s);
1838     ppc_write_effective_word((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], s) != PPC_MMU_FATAL;
1839     }
1840     /*
1841     * sth Store Half Word
1842     * .651
1843     */
1844     void ppc_opc_sth()
1845     {
1846     int rA, rS;
1847     uint32 imm;
1848     PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rS, rA, imm);
1849     ppc_write_effective_half((rA?gCPU.gpr[rA]:0)+imm, (uint16)gCPU.gpr[rS]) != PPC_MMU_FATAL;
1850     }
1851     /*
1852     * sthbrx Store Half Word Byte-Reverse Indexed
1853     * .652
1854     */
1855     void ppc_opc_sthbrx()
1856     {
1857     int rA, rS, rB;
1858     PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
1859     ppc_write_effective_half((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], ppc_bswap_half(gCPU.gpr[rS])) != PPC_MMU_FATAL;
1860     }
1861     /*
1862     * sthu Store Half Word with Update
1863     * .653
1864     */
1865     void ppc_opc_sthu()
1866     {
1867     int rA, rS;
1868     uint32 imm;
1869     PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rS, rA, imm);
1870     // FIXME: check rA!=0
1871     int ret = ppc_write_effective_half(gCPU.gpr[rA]+imm, (uint16)gCPU.gpr[rS]);
1872     if (ret == PPC_MMU_OK) {
1873     gCPU.gpr[rA] += imm;
1874     }
1875     }
1876     /*
1877     * sthux Store Half Word with Update Indexed
1878     * .654
1879     */
1880     void ppc_opc_sthux()
1881     {
1882     int rA, rS, rB;
1883     PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
1884     // FIXME: check rA!=0
1885     int ret = ppc_write_effective_half(gCPU.gpr[rA]+gCPU.gpr[rB], (uint16)gCPU.gpr[rS]);
1886     if (ret == PPC_MMU_OK) {
1887     gCPU.gpr[rA] += gCPU.gpr[rB];
1888     }
1889     }
1890     /*
1891     * sthx Store Half Word Indexed
1892     * .655
1893     */
1894     void ppc_opc_sthx()
1895     {
1896     int rA, rS, rB;
1897     PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
1898     ppc_write_effective_half((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], (uint16)gCPU.gpr[rS]) != PPC_MMU_FATAL;
1899     }
1900     /*
1901     * stmw Store Multiple Word
1902     * .656
1903     */
1904     void ppc_opc_stmw()
1905     {
1906     int rS, rA;
1907     uint32 imm;
1908     PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rS, rA, imm);
1909     uint32 ea = (rA ? gCPU.gpr[rA] : 0) + imm;
1910     while (rS <= 31) {
1911     if (ppc_write_effective_word(ea, gCPU.gpr[rS])) {
1912     return;
1913     }
1914     rS++;
1915     ea += 4;
1916     }
1917     }
1918     /*
1919     * stswi Store String Word Immediate
1920     * .657
1921     */
1922     void ppc_opc_stswi()
1923     {
1924     int rA, rS, NB;
1925     PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, NB);
1926     if (NB==0) NB=32;
1927     uint32 ea = rA ? gCPU.gpr[rA] : 0;
1928     uint32 r = 0;
1929     int i = 0;
1930    
1931     while (NB > 0) {
1932     if (!i) {
1933     r = gCPU.gpr[rS];
1934     rS++;
1935     rS%=32;
1936     i = 4;
1937     }
1938     if (ppc_write_effective_byte(ea, (r>>24))) {
1939     return;
1940     }
1941     r<<=8;
1942     ea++;
1943     i--;
1944     NB--;
1945     }
1946     }
1947     /*
1948     * stswx Store String Word Indexed
1949     * .658
1950     */
1951     void ppc_opc_stswx()
1952     {
1953     int rA, rS, rB;
1954     PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
1955     int NB = XER_n(gCPU.xer);
1956     uint32 ea = gCPU.gpr[rB] + (rA ? gCPU.gpr[rA] : 0);
1957     uint32 r = 0;
1958     int i = 0;
1959    
1960     while (NB > 0) {
1961     if (!i) {
1962     r = gCPU.gpr[rS];
1963     rS++;
1964     rS%=32;
1965     i = 4;
1966     }
1967     if (ppc_write_effective_byte(ea, (r>>24))) {
1968     return;
1969     }
1970     r<<=8;
1971     ea++;
1972     i--;
1973     NB--;
1974     }
1975     }
1976     /*
1977     * stw Store Word
1978     * .659
1979     */
1980     void ppc_opc_stw()
1981     {
1982     int rA, rS;
1983     uint32 imm;
1984     PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rS, rA, imm);
1985     ppc_write_effective_word((rA?gCPU.gpr[rA]:0)+imm, gCPU.gpr[rS]) != PPC_MMU_FATAL;
1986     }
1987     /*
1988     * stwbrx Store Word Byte-Reverse Indexed
1989     * .660
1990     */
1991     void ppc_opc_stwbrx()
1992     {
1993     int rA, rS, rB;
1994     PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
1995     // FIXME: doppelt gemoppelt
1996     ppc_write_effective_word((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], ppc_bswap_word(gCPU.gpr[rS])) != PPC_MMU_FATAL;
1997     }
1998     /*
1999     * stwcx. Store Word Conditional Indexed
2000     * .661
2001     */
2002     void ppc_opc_stwcx_()
2003     {
2004     int rA, rS, rB;
2005     PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
2006     gCPU.cr &= 0x0fffffff;
2007     if (gCPU.have_reservation) {
2008     gCPU.have_reservation = false;
2009     uint32 v;
2010     if (ppc_read_effective_word((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], v)) {
2011     return;
2012     }
2013     if (v==gCPU.reserve) {
2014     if (ppc_write_effective_word((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], gCPU.gpr[rS])) {
2015     return;
2016     }
2017     gCPU.cr |= CR_CR0_EQ;
2018     }
2019     if (gCPU.xer & XER_SO) {
2020     gCPU.cr |= CR_CR0_SO;
2021     }
2022     }
2023     }
2024     /*
2025     * stwu Store Word with Update
2026     * .663
2027     */
2028     void ppc_opc_stwu()
2029     {
2030     int rA, rS;
2031     uint32 imm;
2032     PPC_OPC_TEMPL_D_SImm(gCPU.current_opc, rS, rA, imm);
2033     // FIXME: check rA!=0
2034     int ret = ppc_write_effective_word(gCPU.gpr[rA]+imm, gCPU.gpr[rS]);
2035     if (ret == PPC_MMU_OK) {
2036     gCPU.gpr[rA] += imm;
2037     }
2038     }
2039     /*
2040     * stwux Store Word with Update Indexed
2041     * .664
2042     */
2043     void ppc_opc_stwux()
2044     {
2045     int rA, rS, rB;
2046     PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
2047     // FIXME: check rA!=0
2048     int ret = ppc_write_effective_word(gCPU.gpr[rA]+gCPU.gpr[rB], gCPU.gpr[rS]);
2049     if (ret == PPC_MMU_OK) {
2050     gCPU.gpr[rA] += gCPU.gpr[rB];
2051     }
2052     }
2053     /*
2054     * stwx Store Word Indexed
2055     * .665
2056     */
2057     void ppc_opc_stwx()
2058     {
2059     int rA, rS, rB;
2060     PPC_OPC_TEMPL_X(gCPU.current_opc, rS, rA, rB);
2061     ppc_write_effective_word((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB], gCPU.gpr[rS]) != PPC_MMU_FATAL;
2062     }
2063    
2064     /* stvx Store Vector Indexed
2065     * v.134
2066     */
2067     void ppc_opc_stvx()
2068     {
2069     #ifndef __VEC_EXC_OFF__
2070     if ((gCPU.msr & MSR_VEC) == 0) {
2071     ppc_exception(PPC_EXC_NO_VEC);
2072     return;
2073     }
2074     #endif
2075     VECTOR_DEBUG;
2076     int rA, vrS, rB;
2077     PPC_OPC_TEMPL_X(gCPU.current_opc, vrS, rA, rB);
2078    
2079     int ea = ((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB]);
2080    
2081     ppc_write_effective_qword(ea, gCPU.vr[vrS]) != PPC_MMU_FATAL;
2082     }
2083    
2084     /* stvxl Store Vector Indexed LRU
2085     * v.135
2086     */
2087     void ppc_opc_stvxl()
2088     {
2089     ppc_opc_stvx();
2090     /* This instruction should hint to the cache that the value won't be
2091     * needed again in memory anytime soon. We don't emulate the cache,
2092     * so this is effectively exactly the same as lvx.
2093     */
2094     }
2095    
2096     /* stvebx Store Vector Element Byte Indexed
2097     * v.131
2098     */
2099     void ppc_opc_stvebx()
2100     {
2101     #ifndef __VEC_EXC_OFF__
2102     if ((gCPU.msr & MSR_VEC) == 0) {
2103     ppc_exception(PPC_EXC_NO_VEC);
2104     return;
2105     }
2106     #endif
2107     VECTOR_DEBUG;
2108     int rA, vrS, rB;
2109     PPC_OPC_TEMPL_X(gCPU.current_opc, vrS, rA, rB);
2110     uint32 ea;
2111     ea = (rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB];
2112     ppc_write_effective_byte(ea, VECT_B(gCPU.vr[vrS], ea & 0xf));
2113     }
2114    
2115     /* stvehx Store Vector Element Half Word Indexed
2116     * v.132
2117     */
2118     void ppc_opc_stvehx()
2119     {
2120     #ifndef __VEC_EXC_OFF__
2121     if ((gCPU.msr & MSR_VEC) == 0) {
2122     ppc_exception(PPC_EXC_NO_VEC);
2123     return;
2124     }
2125     #endif
2126     VECTOR_DEBUG;
2127     int rA, vrS, rB;
2128     PPC_OPC_TEMPL_X(gCPU.current_opc, vrS, rA, rB);
2129     uint32 ea;
2130     ea = ((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB]) & ~1;
2131     ppc_write_effective_half(ea, VECT_H(gCPU.vr[vrS], (ea & 0xf) >> 1));
2132     }
2133    
2134     /* stvewx Store Vector Element Word Indexed
2135     * v.133
2136     */
2137     void ppc_opc_stvewx()
2138     {
2139     #ifndef __VEC_EXC_OFF__
2140     if ((gCPU.msr & MSR_VEC) == 0) {
2141     ppc_exception(PPC_EXC_NO_VEC);
2142     return;
2143     }
2144     #endif
2145     VECTOR_DEBUG;
2146     int rA, vrS, rB;
2147     PPC_OPC_TEMPL_X(gCPU.current_opc, vrS, rA, rB);
2148     uint32 ea;
2149     ea = ((rA?gCPU.gpr[rA]:0)+gCPU.gpr[rB]) & ~3;
2150     ppc_write_effective_word(ea, VECT_W(gCPU.vr[vrS], (ea & 0xf) >> 2));
2151     }
2152    
2153     /* dstst Data Stream Touch for Store
2154     * v.117
2155     */
2156     void ppc_opc_dstst()
2157     {
2158     VECTOR_DEBUG;
2159     /* Since we are not emulating the cache, this is a nop */
2160     }
2161    
2162     /* dss Data Stream Stop
2163     * v.114
2164     */
2165     void ppc_opc_dss()
2166     {
2167     VECTOR_DEBUG;
2168     /* Since we are not emulating the cache, this is a nop */
2169     }

  ViewVC Help
Powered by ViewVC 1.1.26