| 1 | /* Simulator for Analog Devices Blackfin processors. |
| 2 | |
| 3 | Copyright (C) 2005-2014 Free Software Foundation, Inc. |
| 4 | Contributed by Analog Devices, Inc. |
| 5 | |
| 6 | This file is part of simulators. |
| 7 | |
| 8 | This program is free software; you can redistribute it and/or modify |
| 9 | it under the terms of the GNU General Public License as published by |
| 10 | the Free Software Foundation; either version 3 of the License, or |
| 11 | (at your option) any later version. |
| 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, see <http://www.gnu.org/licenses/>. */ |
| 20 | |
| 21 | #ifndef _BFIN_SIM_H_ |
| 22 | #define _BFIN_SIM_H_ |
| 23 | |
| 24 | #include <stdbool.h> |
| 25 | #include <stdint.h> |
| 26 | |
| 27 | typedef uint8_t bu8; |
| 28 | typedef uint16_t bu16; |
| 29 | typedef uint32_t bu32; |
| 30 | typedef uint64_t bu40; |
| 31 | typedef uint64_t bu64; |
| 32 | typedef int8_t bs8; |
| 33 | typedef int16_t bs16; |
| 34 | typedef int32_t bs32; |
| 35 | typedef int64_t bs40; |
| 36 | typedef int64_t bs64; |
| 37 | |
| 38 | /* For dealing with parallel instructions, we must avoid changing our register |
| 39 | file until all parallel insns have been simulated. This queue of stores |
| 40 | can be used to delay a modification. |
| 41 | XXX: Should go and convert all 32 bit insns to use this. */ |
| 42 | struct store { |
| 43 | bu32 *addr; |
| 44 | bu32 val; |
| 45 | }; |
| 46 | |
| 47 | enum bfin_parallel_group { |
| 48 | BFIN_PARALLEL_NONE, |
| 49 | BFIN_PARALLEL_GROUP0, /* 32bit slot. */ |
| 50 | BFIN_PARALLEL_GROUP1, /* 16bit group1. */ |
| 51 | BFIN_PARALLEL_GROUP2, /* 16bit group2. */ |
| 52 | }; |
| 53 | |
| 54 | /* The KSP/USP handling wrt SP may not follow the hardware exactly (the hw |
| 55 | looks at current mode and uses either SP or USP based on that. We instead |
| 56 | always operate on SP and mirror things in KSP and USP. During a CEC |
| 57 | transition, we take care of syncing the values. This lowers the simulation |
| 58 | complexity and speeds things up a bit. */ |
| 59 | struct bfin_cpu_state |
| 60 | { |
| 61 | bu32 dpregs[16], iregs[4], mregs[4], bregs[4], lregs[4], cycles[3]; |
| 62 | bu32 ax[2], aw[2]; |
| 63 | bu32 lt[2], lc[2], lb[2]; |
| 64 | bu32 ksp, usp, seqstat, syscfg, rets, reti, retx, retn, rete; |
| 65 | bu32 pc, emudat[2]; |
| 66 | /* These ASTAT flags need not be bu32, but it makes pointers easier. */ |
| 67 | bu32 ac0, ac0_copy, ac1, an, aq; |
| 68 | union { struct { bu32 av0; bu32 av1; }; bu32 av [2]; }; |
| 69 | union { struct { bu32 av0s; bu32 av1s; }; bu32 avs[2]; }; |
| 70 | bu32 az, cc, v, v_copy, vs; |
| 71 | bu32 rnd_mod; |
| 72 | bu32 v_internal; |
| 73 | bu32 astat_reserved; |
| 74 | |
| 75 | /* Set by an instruction emulation function if we performed a jump. We |
| 76 | cannot compare oldpc to newpc as this ignores the "jump 0;" case. */ |
| 77 | bool did_jump; |
| 78 | |
| 79 | /* Used by the CEC to figure out where to return to. */ |
| 80 | bu32 insn_len; |
| 81 | |
| 82 | /* How many cycles did this insn take to complete ? */ |
| 83 | bu32 cycle_delay; |
| 84 | |
| 85 | /* The pc currently being interpreted in parallel insns. */ |
| 86 | bu32 multi_pc; |
| 87 | |
| 88 | /* Some insns are valid in group1, and others in group2, so we |
| 89 | need to keep track of the exact slot we're processing. */ |
| 90 | enum bfin_parallel_group group; |
| 91 | |
| 92 | /* Needed for supporting the DISALGNEXCPT instruction */ |
| 93 | int dis_algn_expt; |
| 94 | |
| 95 | /* See notes above for struct store. */ |
| 96 | struct store stores[20]; |
| 97 | int n_stores; |
| 98 | |
| 99 | #if (WITH_HW) |
| 100 | /* Cache heavily used CPU-specific device pointers. */ |
| 101 | void *cec_cache; |
| 102 | void *evt_cache; |
| 103 | void *mmu_cache; |
| 104 | void *trace_cache; |
| 105 | #endif |
| 106 | }; |
| 107 | |
| 108 | #define REG_H_L(h, l) (((h) & 0xffff0000) | ((l) & 0x0000ffff)) |
| 109 | |
| 110 | #define DREG(x) (BFIN_CPU_STATE.dpregs[x]) |
| 111 | #define PREG(x) (BFIN_CPU_STATE.dpregs[x + 8]) |
| 112 | #define SPREG PREG (6) |
| 113 | #define FPREG PREG (7) |
| 114 | #define IREG(x) (BFIN_CPU_STATE.iregs[x]) |
| 115 | #define MREG(x) (BFIN_CPU_STATE.mregs[x]) |
| 116 | #define BREG(x) (BFIN_CPU_STATE.bregs[x]) |
| 117 | #define LREG(x) (BFIN_CPU_STATE.lregs[x]) |
| 118 | #define AXREG(x) (BFIN_CPU_STATE.ax[x]) |
| 119 | #define AWREG(x) (BFIN_CPU_STATE.aw[x]) |
| 120 | #define CCREG (BFIN_CPU_STATE.cc) |
| 121 | #define LCREG(x) (BFIN_CPU_STATE.lc[x]) |
| 122 | #define LTREG(x) (BFIN_CPU_STATE.lt[x]) |
| 123 | #define LBREG(x) (BFIN_CPU_STATE.lb[x]) |
| 124 | #define CYCLESREG (BFIN_CPU_STATE.cycles[0]) |
| 125 | #define CYCLES2REG (BFIN_CPU_STATE.cycles[1]) |
| 126 | #define CYCLES2SHDREG (BFIN_CPU_STATE.cycles[2]) |
| 127 | #define KSPREG (BFIN_CPU_STATE.ksp) |
| 128 | #define USPREG (BFIN_CPU_STATE.usp) |
| 129 | #define SEQSTATREG (BFIN_CPU_STATE.seqstat) |
| 130 | #define SYSCFGREG (BFIN_CPU_STATE.syscfg) |
| 131 | #define RETSREG (BFIN_CPU_STATE.rets) |
| 132 | #define RETIREG (BFIN_CPU_STATE.reti) |
| 133 | #define RETXREG (BFIN_CPU_STATE.retx) |
| 134 | #define RETNREG (BFIN_CPU_STATE.retn) |
| 135 | #define RETEREG (BFIN_CPU_STATE.rete) |
| 136 | #define PCREG (BFIN_CPU_STATE.pc) |
| 137 | #define EMUDAT_INREG (BFIN_CPU_STATE.emudat[0]) |
| 138 | #define EMUDAT_OUTREG (BFIN_CPU_STATE.emudat[1]) |
| 139 | #define INSN_LEN (BFIN_CPU_STATE.insn_len) |
| 140 | #define PARALLEL_GROUP (BFIN_CPU_STATE.group) |
| 141 | #define CYCLE_DELAY (BFIN_CPU_STATE.cycle_delay) |
| 142 | #define DIS_ALGN_EXPT (BFIN_CPU_STATE.dis_algn_expt) |
| 143 | |
| 144 | #define EXCAUSE_SHIFT 0 |
| 145 | #define EXCAUSE_MASK (0x3f << EXCAUSE_SHIFT) |
| 146 | #define EXCAUSE ((SEQSTATREG & EXCAUSE_MASK) >> EXCAUSE_SHIFT) |
| 147 | #define HWERRCAUSE_SHIFT 14 |
| 148 | #define HWERRCAUSE_MASK (0x1f << HWERRCAUSE_SHIFT) |
| 149 | #define HWERRCAUSE ((SEQSTATREG & HWERRCAUSE_MASK) >> HWERRCAUSE_SHIFT) |
| 150 | |
| 151 | #define _SET_CORE32REG_IDX(reg, p, x, val) \ |
| 152 | do { \ |
| 153 | bu32 __v = (val); \ |
| 154 | TRACE_REGISTER (cpu, "wrote "#p"%i = %#x", x, __v); \ |
| 155 | reg = __v; \ |
| 156 | } while (0) |
| 157 | #define SET_DREG(x, val) _SET_CORE32REG_IDX (DREG (x), R, x, val) |
| 158 | #define SET_PREG(x, val) _SET_CORE32REG_IDX (PREG (x), P, x, val) |
| 159 | #define SET_IREG(x, val) _SET_CORE32REG_IDX (IREG (x), I, x, val) |
| 160 | #define SET_MREG(x, val) _SET_CORE32REG_IDX (MREG (x), M, x, val) |
| 161 | #define SET_BREG(x, val) _SET_CORE32REG_IDX (BREG (x), B, x, val) |
| 162 | #define SET_LREG(x, val) _SET_CORE32REG_IDX (LREG (x), L, x, val) |
| 163 | #define SET_LCREG(x, val) _SET_CORE32REG_IDX (LCREG (x), LC, x, val) |
| 164 | #define SET_LTREG(x, val) _SET_CORE32REG_IDX (LTREG (x), LT, x, val) |
| 165 | #define SET_LBREG(x, val) _SET_CORE32REG_IDX (LBREG (x), LB, x, val) |
| 166 | |
| 167 | #define SET_DREG_L_H(x, l, h) SET_DREG (x, REG_H_L (h, l)) |
| 168 | #define SET_DREG_L(x, l) SET_DREG (x, REG_H_L (DREG (x), l)) |
| 169 | #define SET_DREG_H(x, h) SET_DREG (x, REG_H_L (h, DREG (x))) |
| 170 | |
| 171 | #define _SET_CORE32REG_ALU(reg, p, x, val) \ |
| 172 | do { \ |
| 173 | bu32 __v = (val); \ |
| 174 | TRACE_REGISTER (cpu, "wrote A%i"#p" = %#x", x, __v); \ |
| 175 | reg = __v; \ |
| 176 | } while (0) |
| 177 | #define SET_AXREG(x, val) _SET_CORE32REG_ALU (AXREG (x), X, x, val) |
| 178 | #define SET_AWREG(x, val) _SET_CORE32REG_ALU (AWREG (x), W, x, val) |
| 179 | |
| 180 | #define SET_AREG(x, val) \ |
| 181 | do { \ |
| 182 | bu40 __a = (val); \ |
| 183 | SET_AXREG (x, (__a >> 32) & 0xff); \ |
| 184 | SET_AWREG (x, __a); \ |
| 185 | } while (0) |
| 186 | #define SET_AREG32(x, val) \ |
| 187 | do { \ |
| 188 | SET_AWREG (x, val); \ |
| 189 | SET_AXREG (x, -(AWREG (x) >> 31)); \ |
| 190 | } while (0) |
| 191 | |
| 192 | #define _SET_CORE32REG(reg, val) \ |
| 193 | do { \ |
| 194 | bu32 __v = (val); \ |
| 195 | TRACE_REGISTER (cpu, "wrote "#reg" = %#x", __v); \ |
| 196 | reg##REG = __v; \ |
| 197 | } while (0) |
| 198 | #define SET_FPREG(val) _SET_CORE32REG (FP, val) |
| 199 | #define SET_SPREG(val) _SET_CORE32REG (SP, val) |
| 200 | #define SET_CYCLESREG(val) _SET_CORE32REG (CYCLES, val) |
| 201 | #define SET_CYCLES2REG(val) _SET_CORE32REG (CYCLES2, val) |
| 202 | #define SET_CYCLES2SHDREG(val) _SET_CORE32REG (CYCLES2SHD, val) |
| 203 | #define SET_KSPREG(val) _SET_CORE32REG (KSP, val) |
| 204 | #define SET_USPREG(val) _SET_CORE32REG (USP, val) |
| 205 | #define SET_SYSCFGREG(val) _SET_CORE32REG (SYSCFG, val) |
| 206 | #define SET_RETSREG(val) _SET_CORE32REG (RETS, val) |
| 207 | #define SET_RETIREG(val) _SET_CORE32REG (RETI, val) |
| 208 | #define SET_RETXREG(val) _SET_CORE32REG (RETX, val) |
| 209 | #define SET_RETNREG(val) _SET_CORE32REG (RETN, val) |
| 210 | #define SET_RETEREG(val) _SET_CORE32REG (RETE, val) |
| 211 | #define SET_PCREG(val) _SET_CORE32REG (PC, val) |
| 212 | |
| 213 | #define _SET_CORE32REGFIELD(reg, field, val, mask, shift) \ |
| 214 | do { \ |
| 215 | bu32 __f = (val); \ |
| 216 | bu32 __v = ((reg##REG) & ~(mask)) | (__f << (shift)); \ |
| 217 | TRACE_REGISTER (cpu, "wrote "#field" = %#x ("#reg" = %#x)", __f, __v); \ |
| 218 | reg##REG = __v; \ |
| 219 | } while (0) |
| 220 | #define SET_SEQSTATREG(val) _SET_CORE32REG (SEQSTAT, val) |
| 221 | #define SET_EXCAUSE(excp) _SET_CORE32REGFIELD (SEQSTAT, EXCAUSE, excp, EXCAUSE_MASK, EXCAUSE_SHIFT) |
| 222 | #define SET_HWERRCAUSE(hwerr) _SET_CORE32REGFIELD (SEQSTAT, HWERRCAUSE, hwerr, HWERRCAUSE_MASK, HWERRCAUSE_SHIFT) |
| 223 | |
| 224 | #define AZ_BIT 0 |
| 225 | #define AN_BIT 1 |
| 226 | #define AC0_COPY_BIT 2 |
| 227 | #define V_COPY_BIT 3 |
| 228 | #define CC_BIT 5 |
| 229 | #define AQ_BIT 6 |
| 230 | #define RND_MOD_BIT 8 |
| 231 | #define AC0_BIT 12 |
| 232 | #define AC1_BIT 13 |
| 233 | #define AV0_BIT 16 |
| 234 | #define AV0S_BIT 17 |
| 235 | #define AV1_BIT 18 |
| 236 | #define AV1S_BIT 19 |
| 237 | #define V_BIT 24 |
| 238 | #define VS_BIT 25 |
| 239 | #define ASTAT_DEFINED_BITS \ |
| 240 | ((1 << AZ_BIT) | (1 << AN_BIT) | (1 << AC0_COPY_BIT) | (1 << V_COPY_BIT) \ |
| 241 | |(1 << CC_BIT) | (1 << AQ_BIT) \ |
| 242 | |(1 << RND_MOD_BIT) \ |
| 243 | |(1 << AC0_BIT) | (1 << AC1_BIT) \ |
| 244 | |(1 << AV0_BIT) | (1 << AV0S_BIT) | (1 << AV1_BIT) | (1 << AV1S_BIT) \ |
| 245 | |(1 << V_BIT) | (1 << VS_BIT)) |
| 246 | |
| 247 | #define ASTATREG(field) (BFIN_CPU_STATE.field) |
| 248 | #define ASTAT_DEPOSIT(field, bit) (ASTATREG(field) << (bit)) |
| 249 | #define ASTAT \ |
| 250 | (ASTAT_DEPOSIT(az, AZ_BIT) \ |
| 251 | |ASTAT_DEPOSIT(an, AN_BIT) \ |
| 252 | |ASTAT_DEPOSIT(ac0_copy, AC0_COPY_BIT) \ |
| 253 | |ASTAT_DEPOSIT(v_copy, V_COPY_BIT) \ |
| 254 | |ASTAT_DEPOSIT(cc, CC_BIT) \ |
| 255 | |ASTAT_DEPOSIT(aq, AQ_BIT) \ |
| 256 | |ASTAT_DEPOSIT(rnd_mod, RND_MOD_BIT) \ |
| 257 | |ASTAT_DEPOSIT(ac0, AC0_BIT) \ |
| 258 | |ASTAT_DEPOSIT(ac1, AC1_BIT) \ |
| 259 | |ASTAT_DEPOSIT(av0, AV0_BIT) \ |
| 260 | |ASTAT_DEPOSIT(av0s, AV0S_BIT) \ |
| 261 | |ASTAT_DEPOSIT(av1, AV1_BIT) \ |
| 262 | |ASTAT_DEPOSIT(av1s, AV1S_BIT) \ |
| 263 | |ASTAT_DEPOSIT(v, V_BIT) \ |
| 264 | |ASTAT_DEPOSIT(vs, VS_BIT) \ |
| 265 | |ASTATREG(astat_reserved)) |
| 266 | |
| 267 | #define ASTAT_EXTRACT(a, bit) (((a) >> bit) & 1) |
| 268 | #define _SET_ASTAT(a, field, bit) (ASTATREG(field) = ASTAT_EXTRACT(a, bit)) |
| 269 | #define SET_ASTAT(a) \ |
| 270 | do { \ |
| 271 | TRACE_REGISTER (cpu, "wrote ASTAT = %#x", a); \ |
| 272 | _SET_ASTAT(a, az, AZ_BIT); \ |
| 273 | _SET_ASTAT(a, an, AN_BIT); \ |
| 274 | _SET_ASTAT(a, ac0_copy, AC0_COPY_BIT); \ |
| 275 | _SET_ASTAT(a, v_copy, V_COPY_BIT); \ |
| 276 | _SET_ASTAT(a, cc, CC_BIT); \ |
| 277 | _SET_ASTAT(a, aq, AQ_BIT); \ |
| 278 | _SET_ASTAT(a, rnd_mod, RND_MOD_BIT); \ |
| 279 | _SET_ASTAT(a, ac0, AC0_BIT); \ |
| 280 | _SET_ASTAT(a, ac1, AC1_BIT); \ |
| 281 | _SET_ASTAT(a, av0, AV0_BIT); \ |
| 282 | _SET_ASTAT(a, av0s, AV0S_BIT); \ |
| 283 | _SET_ASTAT(a, av1, AV1_BIT); \ |
| 284 | _SET_ASTAT(a, av1s, AV1S_BIT); \ |
| 285 | _SET_ASTAT(a, v, V_BIT); \ |
| 286 | _SET_ASTAT(a, vs, VS_BIT); \ |
| 287 | ASTATREG(astat_reserved) = (a) & ~ASTAT_DEFINED_BITS; \ |
| 288 | } while (0) |
| 289 | #define SET_ASTATREG(field, val) \ |
| 290 | do { \ |
| 291 | int __v = !!(val); \ |
| 292 | TRACE_REGISTER (cpu, "wrote ASTAT["#field"] = %i", __v); \ |
| 293 | ASTATREG (field) = __v; \ |
| 294 | if (&ASTATREG (field) == &ASTATREG (ac0)) \ |
| 295 | { \ |
| 296 | TRACE_REGISTER (cpu, "wrote ASTAT["#field"_copy] = %i", __v); \ |
| 297 | ASTATREG (ac0_copy) = __v; \ |
| 298 | } \ |
| 299 | else if (&ASTATREG (field) == &ASTATREG (v)) \ |
| 300 | { \ |
| 301 | TRACE_REGISTER (cpu, "wrote ASTAT["#field"_copy] = %i", __v); \ |
| 302 | ASTATREG (v_copy) = __v; \ |
| 303 | } \ |
| 304 | } while (0) |
| 305 | #define SET_CCREG(val) SET_ASTATREG (cc, val) |
| 306 | |
| 307 | #define SYSCFG_SSSTEP (1 << 0) |
| 308 | #define SYSCFG_CCEN (1 << 1) |
| 309 | #define SYSCFG_SNEN (1 << 2) |
| 310 | |
| 311 | #define __PUT_MEM(taddr, v, size) \ |
| 312 | do { \ |
| 313 | bu##size __v = (v); \ |
| 314 | bu32 __taddr = (taddr); \ |
| 315 | int __cnt, __bytes = size / 8; \ |
| 316 | mmu_check_addr (cpu, __taddr, true, false, __bytes); \ |
| 317 | __cnt = sim_core_write_buffer (CPU_STATE(cpu), cpu, write_map, \ |
| 318 | (void *)&__v, __taddr, __bytes); \ |
| 319 | if (__cnt != __bytes) \ |
| 320 | mmu_process_fault (cpu, __taddr, true, false, false, true); \ |
| 321 | TRACE_CORE (cpu, __taddr, __bytes, write_map, __v); \ |
| 322 | } while (0) |
| 323 | #define PUT_BYTE(taddr, v) __PUT_MEM(taddr, v, 8) |
| 324 | #define PUT_WORD(taddr, v) __PUT_MEM(taddr, v, 16) |
| 325 | #define PUT_LONG(taddr, v) __PUT_MEM(taddr, v, 32) |
| 326 | |
| 327 | #define __GET_MEM(taddr, size, inst, map) \ |
| 328 | ({ \ |
| 329 | bu##size __ret; \ |
| 330 | bu32 __taddr = (taddr); \ |
| 331 | int __cnt, __bytes = size / 8; \ |
| 332 | mmu_check_addr (cpu, __taddr, false, inst, __bytes); \ |
| 333 | __cnt = sim_core_read_buffer (CPU_STATE(cpu), cpu, map, \ |
| 334 | (void *)&__ret, __taddr, __bytes); \ |
| 335 | if (__cnt != __bytes) \ |
| 336 | mmu_process_fault (cpu, __taddr, false, inst, false, true); \ |
| 337 | TRACE_CORE (cpu, __taddr, __bytes, map, __ret); \ |
| 338 | __ret; \ |
| 339 | }) |
| 340 | #define _GET_MEM(taddr, size) __GET_MEM(taddr, size, false, read_map) |
| 341 | #define GET_BYTE(taddr) _GET_MEM(taddr, 8) |
| 342 | #define GET_WORD(taddr) _GET_MEM(taddr, 16) |
| 343 | #define GET_LONG(taddr) _GET_MEM(taddr, 32) |
| 344 | |
| 345 | #define IFETCH(taddr) __GET_MEM(taddr, 16, true, exec_map) |
| 346 | #define IFETCH_CHECK(taddr) mmu_check_addr (cpu, taddr, false, true, 2) |
| 347 | |
| 348 | extern void bfin_syscall (SIM_CPU *); |
| 349 | extern bu32 interp_insn_bfin (SIM_CPU *, bu32); |
| 350 | extern bu32 hwloop_get_next_pc (SIM_CPU *, bu32, bu32); |
| 351 | |
| 352 | /* Defines for Blackfin memory layouts. */ |
| 353 | #define BFIN_ASYNC_BASE 0x20000000 |
| 354 | #define BFIN_SYSTEM_MMR_BASE 0xFFC00000 |
| 355 | #define BFIN_CORE_MMR_BASE 0xFFE00000 |
| 356 | #define BFIN_L1_SRAM_SCRATCH 0xFFB00000 |
| 357 | #define BFIN_L1_SRAM_SCRATCH_SIZE 0x1000 |
| 358 | #define BFIN_L1_SRAM_SCRATCH_END (BFIN_L1_SRAM_SCRATCH + BFIN_L1_SRAM_SCRATCH_SIZE) |
| 359 | |
| 360 | #define BFIN_L1_CACHE_BYTES 32 |
| 361 | |
| 362 | #endif |