1 | /* |
2 | * QEMU Nios II CPU |
3 | * |
4 | * Copyright (c) 2012 Chris Wulff <crwulff@gmail.com> |
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/module.h" |
23 | #include "qapi/error.h" |
24 | #include "cpu.h" |
25 | #include "exec/log.h" |
26 | #include "exec/gdbstub.h" |
27 | #include "hw/qdev-properties.h" |
28 | |
29 | static void nios2_cpu_set_pc(CPUState *cs, vaddr value) |
30 | { |
31 | Nios2CPU *cpu = NIOS2_CPU(cs); |
32 | CPUNios2State *env = &cpu->env; |
33 | |
34 | env->regs[R_PC] = value; |
35 | } |
36 | |
37 | static bool nios2_cpu_has_work(CPUState *cs) |
38 | { |
39 | return cs->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI); |
40 | } |
41 | |
42 | /* CPUClass::reset() */ |
43 | static void nios2_cpu_reset(CPUState *cs) |
44 | { |
45 | Nios2CPU *cpu = NIOS2_CPU(cs); |
46 | Nios2CPUClass *ncc = NIOS2_CPU_GET_CLASS(cpu); |
47 | CPUNios2State *env = &cpu->env; |
48 | |
49 | if (qemu_loglevel_mask(CPU_LOG_RESET)) { |
50 | qemu_log("CPU Reset (CPU %d)\n" , cs->cpu_index); |
51 | log_cpu_state(cs, 0); |
52 | } |
53 | |
54 | ncc->parent_reset(cs); |
55 | |
56 | memset(env->regs, 0, sizeof(uint32_t) * NUM_CORE_REGS); |
57 | env->regs[R_PC] = cpu->reset_addr; |
58 | |
59 | #if defined(CONFIG_USER_ONLY) |
60 | /* Start in user mode with interrupts enabled. */ |
61 | env->regs[CR_STATUS] = CR_STATUS_U | CR_STATUS_PIE; |
62 | #else |
63 | env->regs[CR_STATUS] = 0; |
64 | #endif |
65 | } |
66 | |
67 | static void nios2_cpu_initfn(Object *obj) |
68 | { |
69 | Nios2CPU *cpu = NIOS2_CPU(obj); |
70 | |
71 | cpu_set_cpustate_pointers(cpu); |
72 | |
73 | #if !defined(CONFIG_USER_ONLY) |
74 | mmu_init(&cpu->env); |
75 | #endif |
76 | } |
77 | |
78 | static ObjectClass *nios2_cpu_class_by_name(const char *cpu_model) |
79 | { |
80 | return object_class_by_name(TYPE_NIOS2_CPU); |
81 | } |
82 | |
83 | static void nios2_cpu_realizefn(DeviceState *dev, Error **errp) |
84 | { |
85 | CPUState *cs = CPU(dev); |
86 | Nios2CPUClass *ncc = NIOS2_CPU_GET_CLASS(dev); |
87 | Error *local_err = NULL; |
88 | |
89 | cpu_exec_realizefn(cs, &local_err); |
90 | if (local_err != NULL) { |
91 | error_propagate(errp, local_err); |
92 | return; |
93 | } |
94 | |
95 | qemu_init_vcpu(cs); |
96 | cpu_reset(cs); |
97 | |
98 | ncc->parent_realize(dev, errp); |
99 | } |
100 | |
101 | static bool nios2_cpu_exec_interrupt(CPUState *cs, int interrupt_request) |
102 | { |
103 | Nios2CPU *cpu = NIOS2_CPU(cs); |
104 | CPUNios2State *env = &cpu->env; |
105 | |
106 | if ((interrupt_request & CPU_INTERRUPT_HARD) && |
107 | (env->regs[CR_STATUS] & CR_STATUS_PIE)) { |
108 | cs->exception_index = EXCP_IRQ; |
109 | nios2_cpu_do_interrupt(cs); |
110 | return true; |
111 | } |
112 | return false; |
113 | } |
114 | |
115 | |
116 | static void nios2_cpu_disas_set_info(CPUState *cpu, disassemble_info *info) |
117 | { |
118 | /* NOTE: NiosII R2 is not supported yet. */ |
119 | info->mach = bfd_arch_nios2; |
120 | #ifdef TARGET_WORDS_BIGENDIAN |
121 | info->print_insn = print_insn_big_nios2; |
122 | #else |
123 | info->print_insn = print_insn_little_nios2; |
124 | #endif |
125 | } |
126 | |
127 | static int nios2_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) |
128 | { |
129 | Nios2CPU *cpu = NIOS2_CPU(cs); |
130 | CPUClass *cc = CPU_GET_CLASS(cs); |
131 | CPUNios2State *env = &cpu->env; |
132 | |
133 | if (n > cc->gdb_num_core_regs) { |
134 | return 0; |
135 | } |
136 | |
137 | if (n < 32) { /* GP regs */ |
138 | return gdb_get_reg32(mem_buf, env->regs[n]); |
139 | } else if (n == 32) { /* PC */ |
140 | return gdb_get_reg32(mem_buf, env->regs[R_PC]); |
141 | } else if (n < 49) { /* Status regs */ |
142 | return gdb_get_reg32(mem_buf, env->regs[n - 1]); |
143 | } |
144 | |
145 | /* Invalid regs */ |
146 | return 0; |
147 | } |
148 | |
149 | static int nios2_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) |
150 | { |
151 | Nios2CPU *cpu = NIOS2_CPU(cs); |
152 | CPUClass *cc = CPU_GET_CLASS(cs); |
153 | CPUNios2State *env = &cpu->env; |
154 | |
155 | if (n > cc->gdb_num_core_regs) { |
156 | return 0; |
157 | } |
158 | |
159 | if (n < 32) { /* GP regs */ |
160 | env->regs[n] = ldl_p(mem_buf); |
161 | } else if (n == 32) { /* PC */ |
162 | env->regs[R_PC] = ldl_p(mem_buf); |
163 | } else if (n < 49) { /* Status regs */ |
164 | env->regs[n - 1] = ldl_p(mem_buf); |
165 | } |
166 | |
167 | return 4; |
168 | } |
169 | |
170 | static Property nios2_properties[] = { |
171 | DEFINE_PROP_BOOL("mmu_present" , Nios2CPU, mmu_present, true), |
172 | /* ALTR,pid-num-bits */ |
173 | DEFINE_PROP_UINT32("mmu_pid_num_bits" , Nios2CPU, pid_num_bits, 8), |
174 | /* ALTR,tlb-num-ways */ |
175 | DEFINE_PROP_UINT32("mmu_tlb_num_ways" , Nios2CPU, tlb_num_ways, 16), |
176 | /* ALTR,tlb-num-entries */ |
177 | DEFINE_PROP_UINT32("mmu_pid_num_entries" , Nios2CPU, tlb_num_entries, 256), |
178 | DEFINE_PROP_END_OF_LIST(), |
179 | }; |
180 | |
181 | |
182 | static void nios2_cpu_class_init(ObjectClass *oc, void *data) |
183 | { |
184 | DeviceClass *dc = DEVICE_CLASS(oc); |
185 | CPUClass *cc = CPU_CLASS(oc); |
186 | Nios2CPUClass *ncc = NIOS2_CPU_CLASS(oc); |
187 | |
188 | device_class_set_parent_realize(dc, nios2_cpu_realizefn, |
189 | &ncc->parent_realize); |
190 | dc->props = nios2_properties; |
191 | ncc->parent_reset = cc->reset; |
192 | cc->reset = nios2_cpu_reset; |
193 | |
194 | cc->class_by_name = nios2_cpu_class_by_name; |
195 | cc->has_work = nios2_cpu_has_work; |
196 | cc->do_interrupt = nios2_cpu_do_interrupt; |
197 | cc->cpu_exec_interrupt = nios2_cpu_exec_interrupt; |
198 | cc->dump_state = nios2_cpu_dump_state; |
199 | cc->set_pc = nios2_cpu_set_pc; |
200 | cc->disas_set_info = nios2_cpu_disas_set_info; |
201 | cc->tlb_fill = nios2_cpu_tlb_fill; |
202 | #ifndef CONFIG_USER_ONLY |
203 | cc->do_unaligned_access = nios2_cpu_do_unaligned_access; |
204 | cc->get_phys_page_debug = nios2_cpu_get_phys_page_debug; |
205 | #endif |
206 | cc->gdb_read_register = nios2_cpu_gdb_read_register; |
207 | cc->gdb_write_register = nios2_cpu_gdb_write_register; |
208 | cc->gdb_num_core_regs = 49; |
209 | cc->tcg_initialize = nios2_tcg_init; |
210 | } |
211 | |
212 | static const TypeInfo nios2_cpu_type_info = { |
213 | .name = TYPE_NIOS2_CPU, |
214 | .parent = TYPE_CPU, |
215 | .instance_size = sizeof(Nios2CPU), |
216 | .instance_init = nios2_cpu_initfn, |
217 | .class_size = sizeof(Nios2CPUClass), |
218 | .class_init = nios2_cpu_class_init, |
219 | }; |
220 | |
221 | static void nios2_cpu_register_types(void) |
222 | { |
223 | type_register_static(&nios2_cpu_type_info); |
224 | } |
225 | |
226 | type_init(nios2_cpu_register_types) |
227 | |