1 /* 2 * QEMU AVR CPU helpers 3 * 4 * Copyright (c) 2016-2020 Michael Rolnik 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, see 18 * <http://www.gnu.org/licenses/lgpl-2.1.html> 19 */ 20 21 #include "qemu/osdep.h" 22 #include "qemu/log.h" 23 #include "cpu.h" 24 #include "hw/core/tcg-cpu-ops.h" 25 #include "exec/exec-all.h" 26 #include "exec/address-spaces.h" 27 #include "exec/helper-proto.h" 28 29 bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request) 30 { 31 bool ret = false; 32 AVRCPU *cpu = AVR_CPU(cs); 33 CPUAVRState *env = &cpu->env; 34 35 if (interrupt_request & CPU_INTERRUPT_RESET) { 36 if (cpu_interrupts_enabled(env)) { 37 cs->exception_index = EXCP_RESET; 38 avr_cpu_do_interrupt(cs); 39 40 cs->interrupt_request &= ~CPU_INTERRUPT_RESET; 41 42 ret = true; 43 } 44 } 45 if (interrupt_request & CPU_INTERRUPT_HARD) { 46 if (cpu_interrupts_enabled(env) && env->intsrc != 0) { 47 int index = ctz32(env->intsrc); 48 cs->exception_index = EXCP_INT(index); 49 avr_cpu_do_interrupt(cs); 50 51 env->intsrc &= env->intsrc - 1; /* clear the interrupt */ 52 if (!env->intsrc) { 53 cs->interrupt_request &= ~CPU_INTERRUPT_HARD; 54 } 55 56 ret = true; 57 } 58 } 59 return ret; 60 } 61 62 void avr_cpu_do_interrupt(CPUState *cs) 63 { 64 AVRCPU *cpu = AVR_CPU(cs); 65 CPUAVRState *env = &cpu->env; 66 67 uint32_t ret = env->pc_w; 68 int vector = 0; 69 int size = avr_feature(env, AVR_FEATURE_JMP_CALL) ? 2 : 1; 70 int base = 0; 71 72 if (cs->exception_index == EXCP_RESET) { 73 vector = 0; 74 } else if (env->intsrc != 0) { 75 vector = ctz32(env->intsrc) + 1; 76 } 77 78 if (avr_feature(env, AVR_FEATURE_3_BYTE_PC)) { 79 cpu_stb_data(env, env->sp--, (ret & 0x0000ff)); 80 cpu_stb_data(env, env->sp--, (ret & 0x00ff00) >> 8); 81 cpu_stb_data(env, env->sp--, (ret & 0xff0000) >> 16); 82 } else if (avr_feature(env, AVR_FEATURE_2_BYTE_PC)) { 83 cpu_stb_data(env, env->sp--, (ret & 0x0000ff)); 84 cpu_stb_data(env, env->sp--, (ret & 0x00ff00) >> 8); 85 } else { 86 cpu_stb_data(env, env->sp--, (ret & 0x0000ff)); 87 } 88 89 env->pc_w = base + vector * size; 90 env->sregI = 0; /* clear Global Interrupt Flag */ 91 92 cs->exception_index = -1; 93 } 94 95 hwaddr avr_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) 96 { 97 return addr; /* I assume 1:1 address correspondence */ 98 } 99 100 bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size, 101 MMUAccessType access_type, int mmu_idx, 102 bool probe, uintptr_t retaddr) 103 { 104 int prot, page_size = TARGET_PAGE_SIZE; 105 uint32_t paddr; 106 107 address &= TARGET_PAGE_MASK; 108 109 if (mmu_idx == MMU_CODE_IDX) { 110 /* Access to code in flash. */ 111 paddr = OFFSET_CODE + address; 112 prot = PAGE_READ | PAGE_EXEC; 113 if (paddr >= OFFSET_DATA) { 114 /* 115 * This should not be possible via any architectural operations. 116 * There is certainly not an exception that we can deliver. 117 * Accept probing that might come from generic code. 118 */ 119 if (probe) { 120 return false; 121 } 122 error_report("execution left flash memory"); 123 abort(); 124 } 125 } else { 126 /* Access to memory. */ 127 paddr = OFFSET_DATA + address; 128 prot = PAGE_READ | PAGE_WRITE; 129 if (address < NUMBER_OF_CPU_REGISTERS + NUMBER_OF_IO_REGISTERS) { 130 /* 131 * Access to CPU registers, exit and rebuilt this TB to use 132 * full access in case it touches specially handled registers 133 * like SREG or SP. For probing, set page_size = 1, in order 134 * to force tlb_fill to be called for the next access. 135 */ 136 if (probe) { 137 page_size = 1; 138 } else { 139 AVRCPU *cpu = AVR_CPU(cs); 140 CPUAVRState *env = &cpu->env; 141 env->fullacc = 1; 142 cpu_loop_exit_restore(cs, retaddr); 143 } 144 } 145 } 146 147 tlb_set_page(cs, address, paddr, prot, mmu_idx, page_size); 148 return true; 149 } 150 151 /* 152 * helpers 153 */ 154 155 void helper_sleep(CPUAVRState *env) 156 { 157 CPUState *cs = env_cpu(env); 158 159 cs->exception_index = EXCP_HLT; 160 cpu_loop_exit(cs); 161 } 162 163 void helper_unsupported(CPUAVRState *env) 164 { 165 CPUState *cs = env_cpu(env); 166 167 /* 168 * I count not find what happens on the real platform, so 169 * it's EXCP_DEBUG for meanwhile 170 */ 171 cs->exception_index = EXCP_DEBUG; 172 if (qemu_loglevel_mask(LOG_UNIMP)) { 173 qemu_log("UNSUPPORTED\n"); 174 cpu_dump_state(cs, stderr, 0); 175 } 176 cpu_loop_exit(cs); 177 } 178 179 void helper_debug(CPUAVRState *env) 180 { 181 CPUState *cs = env_cpu(env); 182 183 cs->exception_index = EXCP_DEBUG; 184 cpu_loop_exit(cs); 185 } 186 187 void helper_break(CPUAVRState *env) 188 { 189 CPUState *cs = env_cpu(env); 190 191 cs->exception_index = EXCP_DEBUG; 192 cpu_loop_exit(cs); 193 } 194 195 void helper_wdr(CPUAVRState *env) 196 { 197 qemu_log_mask(LOG_UNIMP, "WDG reset (not implemented)\n"); 198 } 199 200 /* 201 * This function implements IN instruction 202 * 203 * It does the following 204 * a. if an IO register belongs to CPU, its value is read and returned 205 * b. otherwise io address is translated to mem address and physical memory 206 * is read. 207 * c. it caches the value for sake of SBI, SBIC, SBIS & CBI implementation 208 * 209 */ 210 target_ulong helper_inb(CPUAVRState *env, uint32_t port) 211 { 212 target_ulong data = 0; 213 214 switch (port) { 215 case 0x38: /* RAMPD */ 216 data = 0xff & (env->rampD >> 16); 217 break; 218 case 0x39: /* RAMPX */ 219 data = 0xff & (env->rampX >> 16); 220 break; 221 case 0x3a: /* RAMPY */ 222 data = 0xff & (env->rampY >> 16); 223 break; 224 case 0x3b: /* RAMPZ */ 225 data = 0xff & (env->rampZ >> 16); 226 break; 227 case 0x3c: /* EIND */ 228 data = 0xff & (env->eind >> 16); 229 break; 230 case 0x3d: /* SPL */ 231 data = env->sp & 0x00ff; 232 break; 233 case 0x3e: /* SPH */ 234 data = env->sp >> 8; 235 break; 236 case 0x3f: /* SREG */ 237 data = cpu_get_sreg(env); 238 break; 239 default: 240 /* not a special register, pass to normal memory access */ 241 data = address_space_ldub(&address_space_memory, 242 OFFSET_IO_REGISTERS + port, 243 MEMTXATTRS_UNSPECIFIED, NULL); 244 } 245 246 return data; 247 } 248 249 /* 250 * This function implements OUT instruction 251 * 252 * It does the following 253 * a. if an IO register belongs to CPU, its value is written into the register 254 * b. otherwise io address is translated to mem address and physical memory 255 * is written. 256 * c. it caches the value for sake of SBI, SBIC, SBIS & CBI implementation 257 * 258 */ 259 void helper_outb(CPUAVRState *env, uint32_t port, uint32_t data) 260 { 261 data &= 0x000000ff; 262 263 switch (port) { 264 case 0x38: /* RAMPD */ 265 if (avr_feature(env, AVR_FEATURE_RAMPD)) { 266 env->rampD = (data & 0xff) << 16; 267 } 268 break; 269 case 0x39: /* RAMPX */ 270 if (avr_feature(env, AVR_FEATURE_RAMPX)) { 271 env->rampX = (data & 0xff) << 16; 272 } 273 break; 274 case 0x3a: /* RAMPY */ 275 if (avr_feature(env, AVR_FEATURE_RAMPY)) { 276 env->rampY = (data & 0xff) << 16; 277 } 278 break; 279 case 0x3b: /* RAMPZ */ 280 if (avr_feature(env, AVR_FEATURE_RAMPZ)) { 281 env->rampZ = (data & 0xff) << 16; 282 } 283 break; 284 case 0x3c: /* EIDN */ 285 env->eind = (data & 0xff) << 16; 286 break; 287 case 0x3d: /* SPL */ 288 env->sp = (env->sp & 0xff00) | (data); 289 break; 290 case 0x3e: /* SPH */ 291 if (avr_feature(env, AVR_FEATURE_2_BYTE_SP)) { 292 env->sp = (env->sp & 0x00ff) | (data << 8); 293 } 294 break; 295 case 0x3f: /* SREG */ 296 cpu_set_sreg(env, data); 297 break; 298 default: 299 /* not a special register, pass to normal memory access */ 300 address_space_stb(&address_space_memory, OFFSET_IO_REGISTERS + port, 301 data, MEMTXATTRS_UNSPECIFIED, NULL); 302 } 303 } 304 305 /* 306 * this function implements LD instruction when there is a possibility to read 307 * from a CPU register 308 */ 309 target_ulong helper_fullrd(CPUAVRState *env, uint32_t addr) 310 { 311 uint8_t data; 312 313 env->fullacc = false; 314 315 if (addr < NUMBER_OF_CPU_REGISTERS) { 316 /* CPU registers */ 317 data = env->r[addr]; 318 } else if (addr < NUMBER_OF_CPU_REGISTERS + NUMBER_OF_IO_REGISTERS) { 319 /* IO registers */ 320 data = helper_inb(env, addr - NUMBER_OF_CPU_REGISTERS); 321 } else { 322 /* memory */ 323 data = address_space_ldub(&address_space_memory, OFFSET_DATA + addr, 324 MEMTXATTRS_UNSPECIFIED, NULL); 325 } 326 return data; 327 } 328 329 /* 330 * this function implements ST instruction when there is a possibility to write 331 * into a CPU register 332 */ 333 void helper_fullwr(CPUAVRState *env, uint32_t data, uint32_t addr) 334 { 335 env->fullacc = false; 336 337 /* Following logic assumes this: */ 338 assert(OFFSET_CPU_REGISTERS == OFFSET_DATA); 339 assert(OFFSET_IO_REGISTERS == OFFSET_CPU_REGISTERS + 340 NUMBER_OF_CPU_REGISTERS); 341 342 if (addr < NUMBER_OF_CPU_REGISTERS) { 343 /* CPU registers */ 344 env->r[addr] = data; 345 } else if (addr < NUMBER_OF_CPU_REGISTERS + NUMBER_OF_IO_REGISTERS) { 346 /* IO registers */ 347 helper_outb(env, addr - NUMBER_OF_CPU_REGISTERS, data); 348 } else { 349 /* memory */ 350 address_space_stb(&address_space_memory, OFFSET_DATA + addr, data, 351 MEMTXATTRS_UNSPECIFIED, NULL); 352 } 353 } 354