cpu_mips_instr_unaligned.cc Source File

Back to the index.

cpu_mips_instr_unaligned.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-2009 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  * MIPS unaligned load/store instructions; the following args are used:
29  *
30  * arg[0] = pointer to the register to load to or store from
31  * arg[1] = pointer to the base register
32  * arg[2] = offset (as an int32_t)
33  *
34  * NOTE/TODO: This is a very slow generic implementation, from the
35  * pre-Dyntrans emulation mode. It should be rewritten.
36  */
37 
38 #include "cop0.h"
39 #include "cpu.h"
40 #include "memory.h"
41 #include "misc.h"
42 
43 
44 void mips_unaligned_loadstore(struct cpu *cpu, struct mips_instr_call *ic,
45  int is_left, int wlen, int store)
46 {
47  /* For L (Left): address is the most significant byte */
48  /* For R (Right): address is the least significant byte */
49  uint64_t addr = *((uint64_t *)ic->arg[1]) + (int32_t)ic->arg[2];
50  int i, dir, reg_dir, reg_ofs, ok;
51  uint64_t result_value, tmpaddr;
52  uint64_t aligned_addr = addr & ~(wlen-1);
53  unsigned char aligned_word[8], databyte;
54 
55  int low_pc = ((size_t)ic - (size_t)cpu->cd.mips.cur_ic_page)
56  / sizeof(struct mips_instr_call);
59  cpu->pc += (low_pc << MIPS_INSTR_ALIGNMENT_SHIFT);
60 
61  dir = 1; /* big endian, Left */
62  reg_dir = -1;
63  reg_ofs = wlen - 1; /* byte offset in the register */
64  if (!is_left) {
65  dir = -dir;
66  reg_ofs = 0;
67  reg_dir = 1;
68  }
69 
71  dir = -dir;
72 
73  result_value = *((uint64_t *)ic->arg[0]);
74 
75  if (cpu->is_32bit) {
76  result_value = (int32_t)result_value;
77  aligned_addr = (int32_t)aligned_addr;
78  addr = (int32_t)addr;
79  }
80 
81  if (store) {
82  /* Store: */
83  uint64_t oldpc = cpu->pc;
84 
85  /*
86  * NOTE (this is ugly): The memory_rw()
87  * call generates a TLBL exception, if there
88  * is a tlb refill exception. However, since
89  * this is a Store, the exception is converted
90  * to a TLBS:
91  */
92  ok = cpu->memory_rw(cpu, cpu->mem, aligned_addr,
93  &aligned_word[0], wlen, MEM_READ, CACHE_DATA);
94  if (!ok) {
95  if (cpu->pc != oldpc) {
96  cpu->cd.mips.coproc[0]->reg[COP0_CAUSE] &=
98  cpu->cd.mips.coproc[0]->reg[COP0_CAUSE] |=
100  }
101  return;
102  }
103 
104  for (i=0; i<wlen; i++) {
105  tmpaddr = addr + i*dir;
106  /* Have we moved into another word/dword? Then stop: */
107  if ( (tmpaddr & ~(wlen-1)) != (addr & ~(wlen-1)) )
108  break;
109 
110  /* debug("unaligned byte at %016"PRIx64",
111  reg_ofs=%i reg=0x%016"PRIx64"\n",
112  tmpaddr, reg_ofs, (long long)result_value); */
113 
114  /* Store one byte: */
115  aligned_word[tmpaddr & (wlen-1)] =
116  (result_value >> (reg_ofs * 8)) & 255;
117 
118  reg_ofs += reg_dir;
119  }
120 
121  ok = cpu->memory_rw(cpu, cpu->mem,
122  aligned_addr, &aligned_word[0], wlen,
124 
125  return;
126  }
127 
128  /* Load: */
129  ok = cpu->memory_rw(cpu, cpu->mem, aligned_addr, &aligned_word[0], wlen,
131  if (!ok)
132  return;
133 
134  for (i=0; i<wlen; i++) {
135  tmpaddr = addr + i*dir;
136  /* Have we moved into another word/dword? Then stop: */
137  if ( (tmpaddr & ~(wlen-1)) != (addr & ~(wlen-1)) )
138  break;
139 
140  /* debug("unaligned byte at %016"PRIx64", reg_ofs=%i reg="
141  "0x%016"PRIx64"\n", (uint64_t) tmpaddr,
142  reg_ofs, (uint64_t)result_value); */
143 
144  /* Load one byte: */
145  databyte = aligned_word[tmpaddr & (wlen-1)];
146  result_value &= ~((uint64_t)0xff << (reg_ofs * 8));
147  result_value |= (uint64_t)databyte << (reg_ofs * 8);
148 
149  reg_ofs += reg_dir;
150  }
151 
152  /* Sign extend for 32-bit load lefts: */
153  if (!store && wlen == sizeof(uint32_t))
154  result_value = (int32_t)result_value;
155 
156  (*(uint64_t *)ic->arg[0]) = result_value;
157 }
158 
mips_coproc::reg
uint64_t reg[N_MIPS_COPROC_REGS]
Definition: cpu_mips.h:102
mips_cpu::coproc
struct mips_coproc * coproc[N_MIPS_COPROCS]
Definition: cpu_mips.h:219
mips_unaligned_loadstore
void mips_unaligned_loadstore(struct cpu *cpu, struct mips_instr_call *ic, int is_left, int wlen, int store)
Definition: cpu_mips_instr_unaligned.cc:44
cop0.h
EXCEPTION_TLBS
#define EXCEPTION_TLBS
Definition: cop0.h:186
CAUSE_EXCCODE_SHIFT
#define CAUSE_EXCCODE_SHIFT
Definition: cop0.h:139
CAUSE_EXCCODE_MASK
#define CAUSE_EXCCODE_MASK
Definition: cop0.h:137
MEM_READ
#define MEM_READ
Definition: memory.h:116
cpu::byte_order
uint8_t byte_order
Definition: cpu.h:347
COP0_CAUSE
#define COP0_CAUSE
Definition: cop0.h:129
addr
uint32_t addr
Definition: tmp_arm_multi.cc:52
cpu::mips
struct mips_cpu mips
Definition: cpu.h:446
MEM_WRITE
#define MEM_WRITE
Definition: memory.h:117
misc.h
cpu::cd
union cpu::@1 cd
ic
struct arm_instr_call * ic
Definition: tmp_arm_multi.cc:50
CACHE_DATA
#define CACHE_DATA
Definition: memory.h:121
cpu::is_32bit
uint8_t is_32bit
Definition: cpu.h:350
cpu.h
cpu::mem
struct memory * mem
Definition: cpu.h:362
EMUL_LITTLE_ENDIAN
#define EMUL_LITTLE_ENDIAN
Definition: misc.h:164
MIPS_INSTR_ALIGNMENT_SHIFT
#define MIPS_INSTR_ALIGNMENT_SHIFT
Definition: cpu_mips.h:189
MIPS_IC_ENTRIES_PER_PAGE
#define MIPS_IC_ENTRIES_PER_PAGE
Definition: cpu_mips.h:190
cpu
Definition: cpu.h:326
cpu::memory_rw
int(* memory_rw)(struct cpu *cpu, struct memory *mem, uint64_t vaddr, unsigned char *data, size_t len, int writeflag, int cache_flags)
Definition: cpu.h:368
cpu::pc
uint64_t pc
Definition: cpu.h:386
memory.h

Generated on Tue Aug 25 2020 19:25:06 for GXemul by doxygen 1.8.18