aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips
diff options
context:
space:
mode:
authorSteven J. Hill <sjhill@mips.com>2013-02-05 17:52:02 -0500
committerSteven J. Hill <Steven.Hill@imgtec.com>2013-05-01 17:32:46 -0400
commita6a4834cdbef23a7db16e7598c8c6e427ac82531 (patch)
tree9a2a89d17ef06eb672dc03bddce61f3aea889558 /arch/mips
parentabc597fe623cfd7d3b18d5235c54f3d567d2c3d3 (diff)
MIPS: microMIPS: uasm: Add microMIPS micro assembler support.
Add new file 'uasm-micromips.c' that allows the micro assembler to generate microMIPS ISA code. It can be included in the kernel alongside the classic ISA as long as the platform supports the microMIPS ISA. Signed-off-by: Steven J. Hill <sjhill@mips.com> Cc: linux-mips@linux-mips.org Cc: cernekee@gmail.com Cc: kevink@paralogos.com Cc: ddaney.cavm@gmail.com Patchwork: https://patchwork.linux-mips.org/patch/4923/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org> (cherry picked from commit 5f011a866afbd03a5379f67f4e70e5efbdfc16e9)
Diffstat (limited to 'arch/mips')
-rw-r--r--arch/mips/Kconfig4
-rw-r--r--arch/mips/include/asm/uasm.h4
-rw-r--r--arch/mips/mm/Makefile2
-rw-r--r--arch/mips/mm/uasm-micromips.c220
4 files changed, 230 insertions, 0 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 51244bf97271..03de102b7a09 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -354,6 +354,7 @@ config MIPS_SEAD3
354 select SYS_SUPPORTS_BIG_ENDIAN 354 select SYS_SUPPORTS_BIG_ENDIAN
355 select SYS_SUPPORTS_LITTLE_ENDIAN 355 select SYS_SUPPORTS_LITTLE_ENDIAN
356 select SYS_SUPPORTS_SMARTMIPS 356 select SYS_SUPPORTS_SMARTMIPS
357 select SYS_SUPPORTS_MICROMIPS
357 select USB_ARCH_HAS_EHCI 358 select USB_ARCH_HAS_EHCI
358 select USB_EHCI_BIG_ENDIAN_DESC 359 select USB_EHCI_BIG_ENDIAN_DESC
359 select USB_EHCI_BIG_ENDIAN_MMIO 360 select USB_EHCI_BIG_ENDIAN_MMIO
@@ -2102,6 +2103,9 @@ config SYS_SUPPORTS_HIGHMEM
2102config SYS_SUPPORTS_SMARTMIPS 2103config SYS_SUPPORTS_SMARTMIPS
2103 bool 2104 bool
2104 2105
2106config SYS_SUPPORTS_MICROMIPS
2107 bool
2108
2105config ARCH_FLATMEM_ENABLE 2109config ARCH_FLATMEM_ENABLE
2106 def_bool y 2110 def_bool y
2107 depends on !NUMA && !CPU_LOONGSON2 2111 depends on !NUMA && !CPU_LOONGSON2
diff --git a/arch/mips/include/asm/uasm.h b/arch/mips/include/asm/uasm.h
index f7d8f1509c4d..f924b87b5308 100644
--- a/arch/mips/include/asm/uasm.h
+++ b/arch/mips/include/asm/uasm.h
@@ -23,6 +23,7 @@
23#endif 23#endif
24 24
25#define _UASM_ISA_CLASSIC 0 25#define _UASM_ISA_CLASSIC 0
26#define _UASM_ISA_MICROMIPS 1
26 27
27#ifndef UASM_ISA 28#ifndef UASM_ISA
28#define UASM_ISA _UASM_ISA_CLASSIC 29#define UASM_ISA _UASM_ISA_CLASSIC
@@ -31,6 +32,9 @@
31#if (UASM_ISA == _UASM_ISA_CLASSIC) 32#if (UASM_ISA == _UASM_ISA_CLASSIC)
32#define ISAOPC(op) uasm_i##op 33#define ISAOPC(op) uasm_i##op
33#define ISAFUNC(x) x 34#define ISAFUNC(x) x
35#elif (UASM_ISA == _UASM_ISA_MICROMIPS)
36#define ISAOPC(op) MM_uasm_i##op
37#define ISAFUNC(x) MM_##x
34#else 38#else
35#error Unsupported micro-assembler ISA!!! 39#error Unsupported micro-assembler ISA!!!
36#endif 40#endif
diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile
index 9e90c2182aa5..e87aae1f2e80 100644
--- a/arch/mips/mm/Makefile
+++ b/arch/mips/mm/Makefile
@@ -22,3 +22,5 @@ obj-$(CONFIG_IP22_CPU_SCACHE) += sc-ip22.o
22obj-$(CONFIG_R5000_CPU_SCACHE) += sc-r5k.o 22obj-$(CONFIG_R5000_CPU_SCACHE) += sc-r5k.o
23obj-$(CONFIG_RM7000_CPU_SCACHE) += sc-rm7k.o 23obj-$(CONFIG_RM7000_CPU_SCACHE) += sc-rm7k.o
24obj-$(CONFIG_MIPS_CPU_SCACHE) += sc-mips.o 24obj-$(CONFIG_MIPS_CPU_SCACHE) += sc-mips.o
25
26obj-$(CONFIG_SYS_SUPPORTS_MICROMIPS) += uasm-micromips.o
diff --git a/arch/mips/mm/uasm-micromips.c b/arch/mips/mm/uasm-micromips.c
new file mode 100644
index 000000000000..476d50c5fac1
--- /dev/null
+++ b/arch/mips/mm/uasm-micromips.c
@@ -0,0 +1,220 @@
1/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * A small micro-assembler. It is intentionally kept simple, does only
7 * support a subset of instructions, and does not try to hide pipeline
8 * effects like branch delay slots.
9 *
10 * Copyright (C) 2004, 2005, 2006, 2008 Thiemo Seufer
11 * Copyright (C) 2005, 2007 Maciej W. Rozycki
12 * Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org)
13 * Copyright (C) 2012, 2013 MIPS Technologies, Inc. All rights reserved.
14 */
15
16#include <linux/kernel.h>
17#include <linux/types.h>
18#include <linux/init.h>
19
20#include <asm/inst.h>
21#include <asm/elf.h>
22#include <asm/bugs.h>
23#define UASM_ISA _UASM_ISA_MICROMIPS
24#include <asm/uasm.h>
25
26#define RS_MASK 0x1f
27#define RS_SH 16
28#define RT_MASK 0x1f
29#define RT_SH 21
30#define SCIMM_MASK 0x3ff
31#define SCIMM_SH 16
32
33/* This macro sets the non-variable bits of an instruction. */
34#define M(a, b, c, d, e, f) \
35 ((a) << OP_SH \
36 | (b) << RT_SH \
37 | (c) << RS_SH \
38 | (d) << RD_SH \
39 | (e) << RE_SH \
40 | (f) << FUNC_SH)
41
42/* Define these when we are not the ISA the kernel is being compiled with. */
43#ifndef CONFIG_CPU_MICROMIPS
44#define MM_uasm_i_b(buf, off) ISAOPC(_beq)(buf, 0, 0, off)
45#define MM_uasm_i_beqz(buf, rs, off) ISAOPC(_beq)(buf, rs, 0, off)
46#define MM_uasm_i_beqzl(buf, rs, off) ISAOPC(_beql)(buf, rs, 0, off)
47#define MM_uasm_i_bnez(buf, rs, off) ISAOPC(_bne)(buf, rs, 0, off)
48#endif
49
50#include "uasm.c"
51
52static struct insn insn_table_MM[] __uasminitdata = {
53 { insn_addu, M(mm_pool32a_op, 0, 0, 0, 0, mm_addu32_op), RT | RS | RD },
54 { insn_addiu, M(mm_addiu32_op, 0, 0, 0, 0, 0), RT | RS | SIMM },
55 { insn_and, M(mm_pool32a_op, 0, 0, 0, 0, mm_and_op), RT | RS | RD },
56 { insn_andi, M(mm_andi32_op, 0, 0, 0, 0, 0), RT | RS | UIMM },
57 { insn_beq, M(mm_beq32_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
58 { insn_beql, 0, 0 },
59 { insn_bgez, M(mm_pool32i_op, mm_bgez_op, 0, 0, 0, 0), RS | BIMM },
60 { insn_bgezl, 0, 0 },
61 { insn_bltz, M(mm_pool32i_op, mm_bltz_op, 0, 0, 0, 0), RS | BIMM },
62 { insn_bltzl, 0, 0 },
63 { insn_bne, M(mm_bne32_op, 0, 0, 0, 0, 0), RT | RS | BIMM },
64 { insn_cache, M(mm_pool32b_op, 0, 0, mm_cache_func, 0, 0), RT | RS | SIMM },
65 { insn_daddu, 0, 0 },
66 { insn_daddiu, 0, 0 },
67 { insn_dmfc0, 0, 0 },
68 { insn_dmtc0, 0, 0 },
69 { insn_dsll, 0, 0 },
70 { insn_dsll32, 0, 0 },
71 { insn_dsra, 0, 0 },
72 { insn_dsrl, 0, 0 },
73 { insn_dsrl32, 0, 0 },
74 { insn_drotr, 0, 0 },
75 { insn_drotr32, 0, 0 },
76 { insn_dsubu, 0, 0 },
77 { insn_eret, M(mm_pool32a_op, 0, 0, 0, mm_eret_op, mm_pool32axf_op), 0 },
78 { insn_ins, M(mm_pool32a_op, 0, 0, 0, 0, mm_ins_op), RT | RS | RD | RE },
79 { insn_ext, M(mm_pool32a_op, 0, 0, 0, 0, mm_ext_op), RT | RS | RD | RE },
80 { insn_j, M(mm_j32_op, 0, 0, 0, 0, 0), JIMM },
81 { insn_jal, M(mm_jal32_op, 0, 0, 0, 0, 0), JIMM },
82 { insn_jr, M(mm_pool32a_op, 0, 0, 0, mm_jalr_op, mm_pool32axf_op), RS },
83 { insn_ld, 0, 0 },
84 { insn_ll, M(mm_pool32c_op, 0, 0, (mm_ll_func << 1), 0, 0), RS | RT | SIMM },
85 { insn_lld, 0, 0 },
86 { insn_lui, M(mm_pool32i_op, mm_lui_op, 0, 0, 0, 0), RS | SIMM },
87 { insn_lw, M(mm_lw32_op, 0, 0, 0, 0, 0), RT | RS | SIMM },
88 { insn_mfc0, M(mm_pool32a_op, 0, 0, 0, mm_mfc0_op, mm_pool32axf_op), RT | RS | RD },
89 { insn_mtc0, M(mm_pool32a_op, 0, 0, 0, mm_mtc0_op, mm_pool32axf_op), RT | RS | RD },
90 { insn_or, M(mm_pool32a_op, 0, 0, 0, 0, mm_or32_op), RT | RS | RD },
91 { insn_ori, M(mm_ori32_op, 0, 0, 0, 0, 0), RT | RS | UIMM },
92 { insn_pref, M(mm_pool32c_op, 0, 0, (mm_pref_func << 1), 0, 0), RT | RS | SIMM },
93 { insn_rfe, 0, 0 },
94 { insn_sc, M(mm_pool32c_op, 0, 0, (mm_sc_func << 1), 0, 0), RT | RS | SIMM },
95 { insn_scd, 0, 0 },
96 { insn_sd, 0, 0 },
97 { insn_sll, M(mm_pool32a_op, 0, 0, 0, 0, mm_sll32_op), RT | RS | RD },
98 { insn_sra, M(mm_pool32a_op, 0, 0, 0, 0, mm_sra_op), RT | RS | RD },
99 { insn_srl, M(mm_pool32a_op, 0, 0, 0, 0, mm_srl32_op), RT | RS | RD },
100 { insn_rotr, M(mm_pool32a_op, 0, 0, 0, 0, mm_rotr_op), RT | RS | RD },
101 { insn_subu, M(mm_pool32a_op, 0, 0, 0, 0, mm_subu32_op), RT | RS | RD },
102 { insn_sw, M(mm_sw32_op, 0, 0, 0, 0, 0), RT | RS | SIMM },
103 { insn_tlbp, M(mm_pool32a_op, 0, 0, 0, mm_tlbp_op, mm_pool32axf_op), 0 },
104 { insn_tlbr, M(mm_pool32a_op, 0, 0, 0, mm_tlbr_op, mm_pool32axf_op), 0 },
105 { insn_tlbwi, M(mm_pool32a_op, 0, 0, 0, mm_tlbwi_op, mm_pool32axf_op), 0 },
106 { insn_tlbwr, M(mm_pool32a_op, 0, 0, 0, mm_tlbwr_op, mm_pool32axf_op), 0 },
107 { insn_xor, M(mm_pool32a_op, 0, 0, 0, 0, mm_xor32_op), RT | RS | RD },
108 { insn_xori, M(mm_xori32_op, 0, 0, 0, 0, 0), RT | RS | UIMM },
109 { insn_dins, 0, 0 },
110 { insn_dinsm, 0, 0 },
111 { insn_syscall, M(mm_pool32a_op, 0, 0, 0, mm_syscall_op, mm_pool32axf_op), SCIMM},
112 { insn_bbit0, 0, 0 },
113 { insn_bbit1, 0, 0 },
114 { insn_lwx, 0, 0 },
115 { insn_ldx, 0, 0 },
116 { insn_invalid, 0, 0 }
117};
118
119#undef M
120
121static inline __uasminit u32 build_bimm(s32 arg)
122{
123 WARN(arg > 0xffff || arg < -0x10000,
124 KERN_WARNING "Micro-assembler field overflow\n");
125
126 WARN(arg & 0x3, KERN_WARNING "Invalid micro-assembler branch target\n");
127
128 return ((arg < 0) ? (1 << 15) : 0) | ((arg >> 1) & 0x7fff);
129}
130
131static inline __uasminit u32 build_jimm(u32 arg)
132{
133 WARN(arg & ~(JIMM_MASK << 2),
134 KERN_WARNING "Micro-assembler field overflow\n");
135
136 return (arg >> 1) & JIMM_MASK;
137}
138
139/*
140 * The order of opcode arguments is implicitly left to right,
141 * starting with RS and ending with FUNC or IMM.
142 */
143static void __uasminit build_insn(u32 **buf, enum opcode opc, ...)
144{
145 struct insn *ip = NULL;
146 unsigned int i;
147 va_list ap;
148 u32 op;
149
150 for (i = 0; insn_table_MM[i].opcode != insn_invalid; i++)
151 if (insn_table_MM[i].opcode == opc) {
152 ip = &insn_table_MM[i];
153 break;
154 }
155
156 if (!ip || (opc == insn_daddiu && r4k_daddiu_bug()))
157 panic("Unsupported Micro-assembler instruction %d", opc);
158
159 op = ip->match;
160 va_start(ap, opc);
161 if (ip->fields & RS) {
162 if (opc == insn_mfc0 || opc == insn_mtc0)
163 op |= build_rt(va_arg(ap, u32));
164 else
165 op |= build_rs(va_arg(ap, u32));
166 }
167 if (ip->fields & RT) {
168 if (opc == insn_mfc0 || opc == insn_mtc0)
169 op |= build_rs(va_arg(ap, u32));
170 else
171 op |= build_rt(va_arg(ap, u32));
172 }
173 if (ip->fields & RD)
174 op |= build_rd(va_arg(ap, u32));
175 if (ip->fields & RE)
176 op |= build_re(va_arg(ap, u32));
177 if (ip->fields & SIMM)
178 op |= build_simm(va_arg(ap, s32));
179 if (ip->fields & UIMM)
180 op |= build_uimm(va_arg(ap, u32));
181 if (ip->fields & BIMM)
182 op |= build_bimm(va_arg(ap, s32));
183 if (ip->fields & JIMM)
184 op |= build_jimm(va_arg(ap, u32));
185 if (ip->fields & FUNC)
186 op |= build_func(va_arg(ap, u32));
187 if (ip->fields & SET)
188 op |= build_set(va_arg(ap, u32));
189 if (ip->fields & SCIMM)
190 op |= build_scimm(va_arg(ap, u32));
191 va_end(ap);
192
193#ifdef CONFIG_CPU_LITTLE_ENDIAN
194 **buf = ((op & 0xffff) << 16) | (op >> 16);
195#else
196 **buf = op;
197#endif
198 (*buf)++;
199}
200
201static inline void __uasminit
202__resolve_relocs(struct uasm_reloc *rel, struct uasm_label *lab)
203{
204 long laddr = (long)lab->addr;
205 long raddr = (long)rel->addr;
206
207 switch (rel->type) {
208 case R_MIPS_PC16:
209#ifdef CONFIG_CPU_LITTLE_ENDIAN
210 *rel->addr |= (build_bimm(laddr - (raddr + 4)) << 16);
211#else
212 *rel->addr |= build_bimm(laddr - (raddr + 4));
213#endif
214 break;
215
216 default:
217 panic("Unsupported Micro-assembler relocation %d",
218 rel->type);
219 }
220}