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