fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
1/*****************************************************************************
2 * pce *
3 *****************************************************************************/
4
5/*****************************************************************************
6 * File name: src/cpu/arm/copr14.c *
7 * Created: 2007-02-16 by Hampa Hug <hampa@hampa.ch> *
8 * Copyright: (C) 2007-2011 Hampa Hug <hampa@hampa.ch> *
9 *****************************************************************************/
10
11/*****************************************************************************
12 * This program is free software. You can redistribute it and / or modify it *
13 * under the terms of the GNU General Public License version 2 as published *
14 * by the Free Software Foundation. *
15 * *
16 * This program is distributed in the hope that it will be useful, but *
17 * WITHOUT ANY WARRANTY, without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
19 * Public License for more details. *
20 *****************************************************************************/
21
22
23#include "arm.h"
24#include "internal.h"
25
26
27static int cp14_reset (arm_t *c, arm_copr_t *p);
28static int cp14_exec (arm_t *c, arm_copr_t *p);
29
30
31void cp14_init (arm_copr14_t *c)
32{
33 arm_copr_init (&c->copr);
34
35 c->copr.ext = c;
36 c->copr.reset = cp14_reset;
37 c->copr.exec = cp14_exec;
38
39 c->cclkcfg = 0;
40 c->pwrmode = 0;
41}
42
43arm_copr_t *cp14_new (void)
44{
45 arm_copr14_t *c;
46
47 c = malloc (sizeof (arm_copr14_t));
48 if (c == NULL) {
49 return (NULL);
50 }
51
52 cp14_init (c);
53
54 return (&c->copr);
55}
56
57void cp14_free (arm_copr14_t *p)
58{
59}
60
61void cp14_del (arm_copr14_t *p)
62{
63 if (p != NULL) {
64 cp14_free (p);
65 }
66
67 free (p);
68}
69
70static
71int cp14_op_mrc (arm_t *c, arm_copr_t *p)
72{
73 arm_copr14_t *p14;
74 unsigned rn, rm;
75 uint32_t val;
76
77 p14 = p->ext;
78
79 rn = arm_ir_rn (c->ir);
80 rm = arm_ir_rm (c->ir);
81 /* op2 = arm_get_bits (c->ir, 5, 3); */
82
83 switch ((rm << 4) | rn) {
84 case 0x00: /* xsc1 performance monitor control register */
85 val = 0;
86 break;
87
88 case 0x06: /* CCLKCFG */
89 val = p14->cclkcfg;
90 break;
91
92 case 0x07: /* PWRMODE */
93 val = p14->pwrmode;
94 break;
95
96 default:
97 return (1);
98 }
99
100 if (arm_rd_is_pc (c->ir)) {
101 arm_set_cpsr (c, (arm_get_cpsr (c) & ~ARM_PSR_CC) | (val & ARM_PSR_CC));
102 }
103 else {
104 arm_set_rd (c, c->ir, val & 0xffffffff);
105 }
106
107 return (0);
108}
109
110static
111int cp14_op_mcr (arm_t *c, arm_copr_t *p)
112{
113 arm_copr14_t *p14;
114 unsigned rn, rm;
115 uint32_t val;
116
117 p14 = p->ext;
118
119 rn = arm_ir_rn (c->ir);
120 rm = arm_ir_rm (c->ir);
121 /* op2 = arm_get_bits (c->ir, 5, 3); */
122
123 val = arm_get_rd (c, c->ir);
124
125 switch ((rm << 4) | rn) {
126 case 0x00: /* xsc1 performance monitor control register */
127 break;
128
129 case 0x06: /* CCLKCFG */
130 p14->cclkcfg = val & 0x0000000f;
131 break;
132
133 case 0x07: /* PWRMODE */
134 p14->pwrmode = val & 0x0000000f;
135 break;
136
137 default:
138 return (1);
139 }
140
141 return (0);
142}
143
144int cp14_reset (arm_t *c, arm_copr_t *p)
145{
146 arm_copr14_t *p14;
147
148 p14 = p->ext;
149
150 p14->cclkcfg = 0;
151 p14->pwrmode = 0;
152
153 return (0);
154}
155
156static
157int cp14_exec (arm_t *c, arm_copr_t *p)
158{
159 int r;
160 unsigned long pc;
161 char *op;
162
163 pc = arm_get_pc (c);
164
165 if (arm_is_privileged (c) == 0) {
166 return (1);
167 }
168
169 op = "?";
170
171 switch (c->ir & 0x00f00010) {
172 case 0x00000010: /* mcr */
173 op = "W";
174 r = cp14_op_mcr (c, p);
175 break;
176
177 case 0x00100010: /* mrc */
178 op = "R";
179 r = cp14_op_mrc (c, p);
180 break;
181
182 default:
183 r = 1;
184 break;
185 }
186
187 if (r == 0) {
188 arm_set_clk (c, 4, 1);
189 }
190
191 if (r) {
192 fprintf (stderr, "%08lX C14: %s Rd=%u Rn=%u Rm=%u op2=%u\n",
193 pc, op,
194 (unsigned) arm_ir_rd (c->ir),
195 (unsigned) arm_ir_rn (c->ir),
196 (unsigned) arm_ir_rm (c->ir),
197 (unsigned) arm_get_bits (c->ir, 5, 3)
198 ); fflush (stderr);
199 }
200
201 return (r);
202}