xref: /plan9/sys/src/9/teg2/coproc.c (revision 3de6a9c0b3d5cf34fc4090d0bf1930d83799a7fd)
1 /*
2  * arm co-processors
3  * mainly to cope with arm hard-wiring register numbers into instructions.
4  *
5  * CP15 (system control) is the one that gets used the most in practice.
6  * these routines must be callable from KZERO space or the 0 segment.
7  */
8 #include "u.h"
9 #include "../port/lib.h"
10 #include "mem.h"
11 #include "dat.h"
12 #include "fns.h"
13 #include "io.h"
14 
15 #include "arm.h"
16 
17 enum {
18 	/* alternates:	0xe12fff1e	BX (R14); last e is R14 */
19 	/*		0xe28ef000	B 0(R14); second e is R14 (ken) */
20 	Retinst	= 0xe1a0f00e,		/* MOV R14, R15 */
21 
22 	Opmask	= MASK(3),
23 	Regmask	= MASK(4),
24 };
25 
26 typedef ulong (*Pufv)(void);
27 typedef void  (*Pvfu)(ulong);
28 
29 static void
setupcpop(ulong instr[2],ulong opcode,int cp,int op1,int crn,int crm,int op2)30 setupcpop(ulong instr[2], ulong opcode, int cp, int op1, int crn, int crm,
31 	int op2)
32 {
33 	ulong instrsz[2];
34 
35 	op1 &= Opmask;
36 	op2 &= Opmask;
37 	crn &= Regmask;
38 	crm &= Regmask;
39 	cp  &= Regmask;
40 	instr[0] = opcode | op1 << 21 | crn << 16 | cp << 8 | op2 << 5 | crm;
41 	instr[1] = Retinst;
42 
43 	cachedwbse(instr, sizeof instrsz);
44 	cacheiinv();
45 }
46 
47 ulong
cprd(int cp,int op1,int crn,int crm,int op2)48 cprd(int cp, int op1, int crn, int crm, int op2)
49 {
50 	int s, r;
51 	volatile ulong instr[2];
52 	Pufv fp;
53 
54 	s = splhi();
55 	/*
56 	 * MRC.  return value will be in R0, which is convenient.
57 	 * Rt will be R0.
58 	 */
59 	setupcpop(instr, 0xee100010, cp, op1, crn, crm, op2);
60 	fp = (Pufv)instr;
61 	r = fp();
62 	splx(s);
63 	return r;
64 }
65 
66 void
cpwr(int cp,int op1,int crn,int crm,int op2,ulong val)67 cpwr(int cp, int op1, int crn, int crm, int op2, ulong val)
68 {
69 	int s;
70 	volatile ulong instr[2];
71 	Pvfu fp;
72 
73 	s = splhi();
74 	setupcpop(instr, 0xee000010, cp, op1, crn, crm, op2); /* MCR, Rt is R0 */
75 	fp = (Pvfu)instr;
76 	fp(val);
77 	coherence();
78 	splx(s);
79 }
80 
81 ulong
cprdsc(int op1,int crn,int crm,int op2)82 cprdsc(int op1, int crn, int crm, int op2)
83 {
84 	return cprd(CpSC, op1, crn, crm, op2);
85 }
86 
87 void
cpwrsc(int op1,int crn,int crm,int op2,ulong val)88 cpwrsc(int op1, int crn, int crm, int op2, ulong val)
89 {
90 	cpwr(CpSC, op1, crn, crm, op2, val);
91 }
92 
93 /* floating point */
94 
95 /* fp coproc control */
96 static void
setupfpctlop(ulong instr[2],int opcode,int fpctlreg)97 setupfpctlop(ulong instr[2], int opcode, int fpctlreg)
98 {
99 	ulong instrsz[2];
100 
101 	fpctlreg &= Nfpctlregs - 1;
102 	instr[0] = opcode | fpctlreg << 16 | 0 << 12 | CpFP << 8;
103 	instr[1] = Retinst;
104 
105 	cachedwbse(instr, sizeof instrsz);
106 	cacheiinv();
107 }
108 
109 ulong
fprd(int fpreg)110 fprd(int fpreg)
111 {
112 	int s, r;
113 	volatile ulong instr[2];
114 	Pufv fp;
115 
116 	if (!m->fpon) {
117 		dumpstack();
118 		panic("fprd: cpu%d fpu off", m->machno);
119 	}
120 	s = splhi();
121 	/*
122 	 * VMRS.  return value will be in R0, which is convenient.
123 	 * Rt will be R0.
124 	 */
125 	setupfpctlop(instr, 0xeef00010, fpreg);
126 	fp = (Pufv)instr;
127 	r = fp();
128 	splx(s);
129 	return r;
130 }
131 
132 void
fpwr(int fpreg,ulong val)133 fpwr(int fpreg, ulong val)
134 {
135 	int s;
136 	volatile ulong instr[2];
137 	Pvfu fp;
138 
139 	/* fpu might be off and this VMSR might enable it */
140 	s = splhi();
141 	setupfpctlop(instr, 0xeee00010, fpreg);		/* VMSR, Rt is R0 */
142 	fp = (Pvfu)instr;
143 	fp(val);
144 	coherence();
145 	splx(s);
146 }
147 
148 /* fp register access; don't bother with single precision */
149 static void
setupfpop(ulong instr[2],int opcode,int fpreg)150 setupfpop(ulong instr[2], int opcode, int fpreg)
151 {
152 	ulong instrsz[2];
153 
154 	instr[0] = opcode | 0 << 16 | (fpreg & (16 - 1)) << 12;
155 	if (fpreg >= 16)
156 		instr[0] |= 1 << 22;		/* high bit of dfp reg # */
157 	instr[1] = Retinst;
158 
159 	cachedwbse(instr, sizeof instrsz);
160 	cacheiinv();
161 }
162 
163 ulong
fpsavereg(int fpreg,uvlong * fpp)164 fpsavereg(int fpreg, uvlong *fpp)
165 {
166 	int s, r;
167 	volatile ulong instr[2];
168 	ulong (*fp)(uvlong *);
169 
170 	if (!m->fpon)
171 		panic("fpsavereg: cpu%d fpu off", m->machno);
172 	s = splhi();
173 	/*
174 	 * VSTR.  pointer will be in R0, which is convenient.
175 	 * Rt will be R0.
176 	 */
177 	setupfpop(instr, 0xed000000 | CpDFP << 8, fpreg);
178 	fp = (ulong (*)(uvlong *))instr;
179 	r = fp(fpp);
180 	splx(s);
181 	coherence();
182 	return r;			/* not too meaningful */
183 }
184 
185 void
fprestreg(int fpreg,uvlong val)186 fprestreg(int fpreg, uvlong val)
187 {
188 	int s;
189 	volatile ulong instr[2];
190 	void (*fp)(uvlong *);
191 
192 	if (!m->fpon)
193 		panic("fprestreg: cpu%d fpu off", m->machno);
194 	s = splhi();
195 	setupfpop(instr, 0xed100000 | CpDFP << 8, fpreg); /* VLDR, Rt is R0 */
196 	fp = (void (*)(uvlong *))instr;
197 	fp(&val);
198 	coherence();
199 	splx(s);
200 }
201