xref: /plan9-contrib/sys/src/9/kw/coproc.c (revision 84860c5d80372cab6c5e871d17f5695a8d0192c9)
13d4c7aa0SDavid du Colombier /*
23d4c7aa0SDavid du Colombier  * arm co-processors
33d4c7aa0SDavid du Colombier  * CP15 (system control) is the one that gets used the most in practice.
43d4c7aa0SDavid du Colombier  */
53d4c7aa0SDavid du Colombier #include "u.h"
63d4c7aa0SDavid du Colombier #include "../port/lib.h"
73d4c7aa0SDavid du Colombier #include "mem.h"
83d4c7aa0SDavid du Colombier #include "dat.h"
93d4c7aa0SDavid du Colombier #include "fns.h"
103d4c7aa0SDavid du Colombier #include "io.h"
113d4c7aa0SDavid du Colombier 
123d4c7aa0SDavid du Colombier #include "arm.h"
133d4c7aa0SDavid du Colombier 
143d4c7aa0SDavid du Colombier #define MAP2PCSPACE(va, pc) ((uintptr)(va) & ~KSEGM | (pc) & KSEGM)
153d4c7aa0SDavid du Colombier 
163d4c7aa0SDavid du Colombier enum {
173d4c7aa0SDavid du Colombier 	/* alternates:	0xe12fff1e	BX (R14); last e is R14 */
183d4c7aa0SDavid du Colombier 	/*		0xe28ef000	B 0(R14); second e is R14 (ken) */
19*84860c5dSDavid du Colombier 	Retinst	= 0xe1a0f00e,		/* MOVW R14, R15 */
20*84860c5dSDavid du Colombier 
21*84860c5dSDavid du Colombier 	Fpproc	= 10,			/* for vfp 3+; also 11 for doubles */
223d4c7aa0SDavid du Colombier };
233d4c7aa0SDavid du Colombier 
243d4c7aa0SDavid du Colombier void
cpwr(int cp,int op1,int crn,int crm,int op2,ulong val)253d4c7aa0SDavid du Colombier cpwr(int cp, int op1, int crn, int crm, int op2, ulong val)
263d4c7aa0SDavid du Colombier {
273d4c7aa0SDavid du Colombier 	int s;
283d4c7aa0SDavid du Colombier 	volatile ulong instr[2];
293d4c7aa0SDavid du Colombier 	void *pcaddr;
303d4c7aa0SDavid du Colombier 	void (*fp)(ulong);
313d4c7aa0SDavid du Colombier 
323d4c7aa0SDavid du Colombier 	s = splhi();
333d4c7aa0SDavid du Colombier 	op1 &= 7;
343d4c7aa0SDavid du Colombier 	op2 &= 7;
353d4c7aa0SDavid du Colombier 	crn &= 017;
363d4c7aa0SDavid du Colombier 	crm &= 017;
373d4c7aa0SDavid du Colombier 	cp &= 017;
383d4c7aa0SDavid du Colombier 	/* MCR.  Rt will be R0. */
393d4c7aa0SDavid du Colombier 	instr[0] = 0xee000010 |
403d4c7aa0SDavid du Colombier 		op1 << 21 | crn << 16 | cp << 8 | op2 << 5 | crm;
413d4c7aa0SDavid du Colombier 	instr[1] = Retinst;
423d4c7aa0SDavid du Colombier 	coherence();
433d4c7aa0SDavid du Colombier 
443d4c7aa0SDavid du Colombier 	pcaddr = (void *)MAP2PCSPACE(instr, getcallerpc(&cp));
453d4c7aa0SDavid du Colombier 	cachedwbse(pcaddr, sizeof instr);
463d4c7aa0SDavid du Colombier 	cacheiinv();
473d4c7aa0SDavid du Colombier 
483d4c7aa0SDavid du Colombier 	fp = (void (*)(ulong))pcaddr;
493d4c7aa0SDavid du Colombier 	(*fp)(val);
503d4c7aa0SDavid du Colombier 	coherence();
513d4c7aa0SDavid du Colombier 	splx(s);
523d4c7aa0SDavid du Colombier }
533d4c7aa0SDavid du Colombier 
543d4c7aa0SDavid du Colombier void
cpwrsc(int op1,int crn,int crm,int op2,ulong val)553d4c7aa0SDavid du Colombier cpwrsc(int op1, int crn, int crm, int op2, ulong val)
563d4c7aa0SDavid du Colombier {
573d4c7aa0SDavid du Colombier 	cpwr(CpSC, op1, crn, crm, op2, val);
583d4c7aa0SDavid du Colombier }
593d4c7aa0SDavid du Colombier 
603d4c7aa0SDavid du Colombier ulong
cprd(int cp,int op1,int crn,int crm,int op2)613d4c7aa0SDavid du Colombier cprd(int cp, int op1, int crn, int crm, int op2)
623d4c7aa0SDavid du Colombier {
633d4c7aa0SDavid du Colombier 	int s;
643d4c7aa0SDavid du Colombier 	ulong res;
653d4c7aa0SDavid du Colombier 	volatile ulong instr[2];
663d4c7aa0SDavid du Colombier 	void *pcaddr;
673d4c7aa0SDavid du Colombier 	ulong (*fp)(void);
683d4c7aa0SDavid du Colombier 
693d4c7aa0SDavid du Colombier 	s = splhi();
703d4c7aa0SDavid du Colombier 	op1 &= 7;
713d4c7aa0SDavid du Colombier 	op2 &= 7;
723d4c7aa0SDavid du Colombier 	crn &= 017;
733d4c7aa0SDavid du Colombier 	crm &= 017;
743d4c7aa0SDavid du Colombier 	/*
753d4c7aa0SDavid du Colombier 	 * MRC.  return value will be in R0, which is convenient.
763d4c7aa0SDavid du Colombier 	 * Rt will be R0.
773d4c7aa0SDavid du Colombier 	 */
783d4c7aa0SDavid du Colombier 	instr[0] = 0xee100010 |
793d4c7aa0SDavid du Colombier 		op1 << 21 | crn << 16 | cp << 8 | op2 << 5 | crm;
803d4c7aa0SDavid du Colombier 	instr[1] = Retinst;
813d4c7aa0SDavid du Colombier 	coherence();
823d4c7aa0SDavid du Colombier 
833d4c7aa0SDavid du Colombier 	pcaddr = (void *)MAP2PCSPACE(instr, getcallerpc(&cp));
843d4c7aa0SDavid du Colombier 	cachedwbse(pcaddr, sizeof instr);
853d4c7aa0SDavid du Colombier 	cacheiinv();
863d4c7aa0SDavid du Colombier 
873d4c7aa0SDavid du Colombier 	fp = (ulong (*)(void))pcaddr;
883d4c7aa0SDavid du Colombier 	res = (*fp)();
893d4c7aa0SDavid du Colombier 	splx(s);
903d4c7aa0SDavid du Colombier 	return res;
913d4c7aa0SDavid du Colombier }
923d4c7aa0SDavid du Colombier 
933d4c7aa0SDavid du Colombier ulong
cprdsc(int op1,int crn,int crm,int op2)943d4c7aa0SDavid du Colombier cprdsc(int op1, int crn, int crm, int op2)
953d4c7aa0SDavid du Colombier {
963d4c7aa0SDavid du Colombier 	return cprd(CpSC, op1, crn, crm, op2);
973d4c7aa0SDavid du Colombier }
983d4c7aa0SDavid du Colombier 
993d4c7aa0SDavid du Colombier /* floating point */
1003d4c7aa0SDavid du Colombier 
1013d4c7aa0SDavid du Colombier ulong
fprd(int fpreg)1023d4c7aa0SDavid du Colombier fprd(int fpreg)
1033d4c7aa0SDavid du Colombier {
1043d4c7aa0SDavid du Colombier 	int s;
1053d4c7aa0SDavid du Colombier 	ulong res;
1063d4c7aa0SDavid du Colombier 	volatile ulong instr[2];
1073d4c7aa0SDavid du Colombier 	void *pcaddr;
1083d4c7aa0SDavid du Colombier 	ulong (*fp)(void);
1093d4c7aa0SDavid du Colombier 
1103d4c7aa0SDavid du Colombier 	s = splhi();
1113d4c7aa0SDavid du Colombier 	fpreg &= 017;
1123d4c7aa0SDavid du Colombier 	/*
1133d4c7aa0SDavid du Colombier 	 * VMRS.  return value will be in R0, which is convenient.
1143d4c7aa0SDavid du Colombier 	 * Rt will be R0.
1153d4c7aa0SDavid du Colombier 	 */
116*84860c5dSDavid du Colombier 	instr[0] = 0xeef00010 | fpreg << 16 | 0 << 12 | Fpproc << 8;
1173d4c7aa0SDavid du Colombier 	instr[1] = Retinst;
1183d4c7aa0SDavid du Colombier 	coherence();
1193d4c7aa0SDavid du Colombier 
1203d4c7aa0SDavid du Colombier 	pcaddr = (void *)MAP2PCSPACE(instr, getcallerpc(&fpreg));
1213d4c7aa0SDavid du Colombier 	cachedwbse(pcaddr, sizeof instr);
1223d4c7aa0SDavid du Colombier 	cacheiinv();
1233d4c7aa0SDavid du Colombier 
1243d4c7aa0SDavid du Colombier 	fp = (ulong (*)(void))pcaddr;
1253d4c7aa0SDavid du Colombier 	res = (*fp)();
1263d4c7aa0SDavid du Colombier 	splx(s);
1273d4c7aa0SDavid du Colombier 	return res;
1283d4c7aa0SDavid du Colombier }
1293d4c7aa0SDavid du Colombier 
1303d4c7aa0SDavid du Colombier void
fpwr(int fpreg,ulong val)1313d4c7aa0SDavid du Colombier fpwr(int fpreg, ulong val)
1323d4c7aa0SDavid du Colombier {
1333d4c7aa0SDavid du Colombier 	int s;
1343d4c7aa0SDavid du Colombier 	volatile ulong instr[2];
1353d4c7aa0SDavid du Colombier 	void *pcaddr;
1363d4c7aa0SDavid du Colombier 	void (*fp)(ulong);
1373d4c7aa0SDavid du Colombier 
1383d4c7aa0SDavid du Colombier 	s = splhi();
1393d4c7aa0SDavid du Colombier 	fpreg &= 017;
1403d4c7aa0SDavid du Colombier 	/* VMSR.  Rt will be R0. */
141*84860c5dSDavid du Colombier 	instr[0] = 0xeee00010 | fpreg << 16 | 0 << 12 | Fpproc << 8;
1423d4c7aa0SDavid du Colombier 	instr[1] = Retinst;
1433d4c7aa0SDavid du Colombier 	coherence();
1443d4c7aa0SDavid du Colombier 
1453d4c7aa0SDavid du Colombier 	pcaddr = (void *)MAP2PCSPACE(instr, getcallerpc(&fpreg));
1463d4c7aa0SDavid du Colombier 	cachedwbse(pcaddr, sizeof instr);
1473d4c7aa0SDavid du Colombier 	cacheiinv();
1483d4c7aa0SDavid du Colombier 
1493d4c7aa0SDavid du Colombier 	fp = (void (*)(ulong))pcaddr;
1503d4c7aa0SDavid du Colombier 	(*fp)(val);
1513d4c7aa0SDavid du Colombier 	coherence();
1523d4c7aa0SDavid du Colombier 	splx(s);
1533d4c7aa0SDavid du Colombier }
154