/[gxemul]/upstream/0.4.5/src/cpus/cpu_mips_instr_unaligned.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /upstream/0.4.5/src/cpus/cpu_mips_instr_unaligned.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 39 - (show annotations)
Mon Oct 8 16:22:02 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 5182 byte(s)
0.4.5
1 /*
2 * Copyright (C) 2006-2007 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. 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 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: cpu_mips_instr_unaligned.c,v 1.4 2006/12/30 13:30:54 debug Exp $
29 *
30 * MIPS unaligned load/store instructions; the following args are used:
31 *
32 * arg[0] = pointer to the register to load to or store from
33 * arg[1] = pointer to the base register
34 * arg[2] = offset (as an int32_t)
35 *
36 * NOTE/TODO: This is a very slow generic implementation, from the
37 * pre-Dyntrans emulation mode. It should be rewritten.
38 */
39
40 #include "cop0.h"
41 #include "cpu.h"
42 #include "memory.h"
43 #include "misc.h"
44
45
46 void mips_unaligned_loadstore(struct cpu *cpu, struct mips_instr_call *ic,
47 int is_left, int wlen, int store)
48 {
49 /* For L (Left): address is the most significant byte */
50 /* For R (Right): address is the least significant byte */
51 uint64_t addr = *((uint64_t *)ic->arg[1]) + (int32_t)ic->arg[2];
52 int i, dir, reg_dir, reg_ofs, ok;
53 uint64_t result_value, tmpaddr;
54 uint64_t aligned_addr = addr & ~(wlen-1);
55 unsigned char aligned_word[8], databyte;
56
57 int low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page)
58 / sizeof(struct mips_instr_call);
59 cpu->pc &= ~((MIPS_IC_ENTRIES_PER_PAGE-1)
60 << MIPS_INSTR_ALIGNMENT_SHIFT);
61 cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT);
62
63 dir = 1; /* big endian, Left */
64 reg_dir = -1;
65 reg_ofs = wlen - 1; /* byte offset in the register */
66 if (!is_left) {
67 dir = -dir;
68 reg_ofs = 0;
69 reg_dir = 1;
70 }
71
72 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
73 dir = -dir;
74
75 result_value = *((uint64_t *)ic->arg[0]);
76
77 if (cpu->is_32bit) {
78 result_value = (int32_t)result_value;
79 aligned_addr = (int32_t)aligned_addr;
80 addr = (int32_t)addr;
81 }
82
83 if (store) {
84 /* Store: */
85 uint64_t oldpc = cpu->pc;
86
87 /*
88 * NOTE (this is ugly): The memory_rw()
89 * call generates a TLBL exception, if there
90 * is a tlb refill exception. However, since
91 * this is a Store, the exception is converted
92 * to a TLBS:
93 */
94 ok = cpu->memory_rw(cpu, cpu->mem, aligned_addr,
95 &aligned_word[0], wlen, MEM_READ, CACHE_DATA);
96 if (!ok) {
97 if (cpu->pc != oldpc) {
98 cpu->cd.mips.coproc[0]->reg[COP0_CAUSE] &=
99 ~CAUSE_EXCCODE_MASK;
100 cpu->cd.mips.coproc[0]->reg[COP0_CAUSE] |=
101 (EXCEPTION_TLBS << CAUSE_EXCCODE_SHIFT);
102 }
103 return;
104 }
105
106 for (i=0; i<wlen; i++) {
107 tmpaddr = addr + i*dir;
108 /* Have we moved into another word/dword? Then stop: */
109 if ( (tmpaddr & ~(wlen-1)) != (addr & ~(wlen-1)) )
110 break;
111
112 /* debug("unaligned byte at %016"PRIx64",
113 reg_ofs=%i reg=0x%016"PRIx64"\n",
114 tmpaddr, reg_ofs, (long long)result_value); */
115
116 /* Store one byte: */
117 aligned_word[tmpaddr & (wlen-1)] =
118 (result_value >> (reg_ofs * 8)) & 255;
119
120 reg_ofs += reg_dir;
121 }
122
123 ok = cpu->memory_rw(cpu, cpu->mem,
124 aligned_addr, &aligned_word[0], wlen,
125 MEM_WRITE, CACHE_DATA);
126
127 return;
128 }
129
130 /* Load: */
131 ok = cpu->memory_rw(cpu, cpu->mem, aligned_addr, &aligned_word[0], wlen,
132 MEM_READ, CACHE_DATA);
133 if (!ok)
134 return;
135
136 for (i=0; i<wlen; i++) {
137 tmpaddr = addr + i*dir;
138 /* Have we moved into another word/dword? Then stop: */
139 if ( (tmpaddr & ~(wlen-1)) != (addr & ~(wlen-1)) )
140 break;
141
142 /* debug("unaligned byte at %016"PRIx64", reg_ofs=%i reg="
143 "0x%016"PRIx64"\n", (uint64_t) tmpaddr,
144 reg_ofs, (uint64_t)result_value); */
145
146 /* Load one byte: */
147 databyte = aligned_word[tmpaddr & (wlen-1)];
148 result_value &= ~((uint64_t)0xff << (reg_ofs * 8));
149 result_value |= (uint64_t)databyte << (reg_ofs * 8);
150
151 reg_ofs += reg_dir;
152 }
153
154 /* Sign extend for 32-bit load lefts: */
155 if (!store && wlen == sizeof(uint32_t))
156 result_value = (int32_t)result_value;
157
158 (*(uint64_t *)ic->arg[0]) = result_value;
159 }
160

  ViewVC Help
Powered by ViewVC 1.1.26