]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/bcm/coproc.c
audiohda: fix syntax error
[plan9front.git] / sys / src / 9 / bcm / coproc.c
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  *
7  * these routines must be callable from KZERO.
8  *
9  * on a multiprocessor, process switching to another cpu is assumed
10  * to be inhibited by the caller as these registers are local to the cpu.
11  */
12 #include "u.h"
13 #include "../port/lib.h"
14 #include "mem.h"
15 #include "dat.h"
16 #include "fns.h"
17 #include "io.h"
18
19 #include "arm.h"
20
21 enum {
22         /* alternates:  0xe12fff1e      BX (R14); last e is R14 */
23         /*              0xe28ef000      B 0(R14); second e is R14 (ken) */
24         Retinst = 0xe1a0f00e,           /* MOV R14, R15 */
25
26         Opmask  = MASK(3),
27         Regmask = MASK(4),
28 };
29
30 static void*
31 mkinstr(ulong wd)
32 {
33         static ulong ib[256], *ep[MAXMACH+1];
34         static Lock lk;
35         ulong *ip, *ie;
36
37         ie = ep[m->machno];
38         for(ip = ib; ip < ie; ip += 2)
39                 if(*ip == wd)
40                         return ip;
41
42         ilock(&lk);
43         ie = ep[MAXMACH];
44         for(; ip < ie; ip += 2)
45                 if(*ip == wd)
46                         goto Found;
47         if(ip >= &ib[nelem(ib)])
48                 panic("mkinstr: out of instrucuction buffer");
49         ip[0] = wd;
50         ip[1] = Retinst;
51         ep[MAXMACH] = ie = ip + 2;
52         cachedwbse(ip, 2*sizeof(*ip));
53 Found:
54         iunlock(&lk);
55         cacheiinv();
56         ep[m->machno] = ie;
57         return ip;
58 }
59
60
61 static void*
62 setupcpop(ulong opcode, int cp, int op1, int crn, int crm,
63         int op2)
64 {
65         op1 &= Opmask;
66         op2 &= Opmask;
67         crn &= Regmask;
68         crm &= Regmask;
69         cp  &= Regmask;
70         return mkinstr(opcode | op1 << 21 | crn << 16 | cp << 8 | op2 << 5 | crm);
71 }
72
73 ulong
74 cprd(int cp, int op1, int crn, int crm, int op2)
75 {
76         /*
77          * MRC.  return value will be in R0, which is convenient.
78          * Rt will be R0.
79          */
80         ulong (*fp)(void) = setupcpop(0xee100010, cp, op1, crn, crm, op2);
81         return fp();
82 }
83
84 void
85 cpwr(int cp, int op1, int crn, int crm, int op2, ulong val)
86 {
87         /* MCR, Rt is R0 */
88         void (*fp)(ulong) = setupcpop(0xee000010, cp, op1, crn, crm, op2);
89         fp(val);
90 }
91
92 ulong
93 cprdsc(int op1, int crn, int crm, int op2)
94 {
95         return cprd(CpSC, op1, crn, crm, op2);
96 }
97
98 void
99 cpwrsc(int op1, int crn, int crm, int op2, ulong val)
100 {
101         cpwr(CpSC, op1, crn, crm, op2, val);
102 }
103
104 /* floating point */
105
106 /* fp coproc control */
107 static void*
108 setupfpctlop(int opcode, int fpctlreg)
109 {
110         fpctlreg &= Nfpctlregs - 1;
111         return mkinstr(opcode | fpctlreg << 16 | 0 << 12 | CpFP << 8);
112 }
113
114 ulong
115 fprd(int fpreg)
116 {
117         /*
118          * VMRS.  return value will be in R0, which is convenient.
119          * Rt will be R0.
120          */
121         ulong (*fp)(void) = setupfpctlop(0xeef00010, fpreg);
122         return fp();
123 }
124
125 void
126 fpwr(int fpreg, ulong val)
127 {
128         /*
129          * fpu might be off and this VMSR might enable it
130          * VMSR, Rt is R0
131          */
132         void (*fp)(ulong) = setupfpctlop(0xeee00010, fpreg);
133         fp(val);
134 }
135
136 /* fp register access; don't bother with single precision */
137 static void*
138 setupfpop(int opcode, int fpreg)
139 {
140         ulong wd = opcode | 0 << 16 | (fpreg & (16 - 1)) << 12;
141         if (fpreg >= 16)
142                 wd |= 1 << 22;          /* high bit of dfp reg # */
143         return mkinstr(wd);
144 }
145
146 ulong
147 fpsavereg(int fpreg, uvlong *fpp)
148 {
149         /*
150          * VSTR.  pointer will be in R0, which is convenient.
151          * Rt will be R0.
152          */
153         ulong (*fp)(uvlong *) = setupfpop(0xed000000 | CpDFP << 8, fpreg);
154         return fp(fpp);
155 }
156
157 void
158 fprestreg(int fpreg, uvlong val)
159 {
160         /* VLDR, Rt is R0 */
161         void (*fp)(uvlong *) = setupfpop(0xed100000 | CpDFP << 8, fpreg);
162         fp(&val);
163 }