summaryrefslogtreecommitdiff
path: root/runtime/riscv.S
blob: 48e690e44c5c11e5ce7d723fc834982ee56879be (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
/**************************************************************************/
/*                                                                        */
/*                                 OCaml                                  */
/*                                                                        */
/*                Nicolas Ojeda Bar <n.oje.bar@gmail.com>                 */
/*                                                                        */
/*   Copyright 2016 Institut National de Recherche en Informatique et     */
/*     en Automatique.                                                    */
/*                                                                        */
/*   All rights reserved.  This file is distributed under the terms of    */
/*   the GNU Lesser General Public License version 2.1, with the          */
/*   special exception on linking described in the file LICENSE.          */
/*                                                                        */
/**************************************************************************/

/* Asm part of the runtime system, RISC-V processor, 64-bit mode */
/* Must be preprocessed by cpp */

#define ARG_DOMAIN_STATE_PTR t0
#define DOMAIN_STATE_PTR s0
#define TRAP_PTR s1
#define ALLOC_PTR s10
#define ALLOC_LIMIT s11
#define TMP t1
#define ARG t2

#define STORE sd
#define LOAD ld

        .set    domain_curr_field, 0
#define DOMAIN_STATE(c_type, name) \
        .equ    domain_field_caml_##name, domain_curr_field ; \
        .set    domain_curr_field, domain_curr_field + 1
#include "../runtime/caml/domain_state.tbl"
#undef DOMAIN_STATE

#define Caml_state(var) (8*domain_field_caml_##var)(s0)

#define FUNCTION(name) \
        .align 2; \
        .globl name; \
        .type name, @function; \
name:

#if defined(__PIC__)
        .option pic
#define PLT(r) r@plt
#else
        .option nopic
#define PLT(r) r
#endif

        .section        .text
/* Invoke the garbage collector. */

        .globl  caml_system__code_begin
caml_system__code_begin:

FUNCTION(caml_call_gc)
.Lcaml_call_gc:
        /* Record return address */
        STORE   ra, Caml_state(last_return_address)
        /* Record lowest stack address */
        STORE   sp, Caml_state(bottom_of_stack)
        /* Set up stack space, saving return address */
        /* (1 reg for RA, 1 reg for FP, 21 allocatable int regs,
            20 caller-save float regs) * 8 */
        /* + 1 for alignment */
        addi    sp, sp, -0x160
        STORE   ra, 0x8(sp)
        STORE   s0, 0x0(sp)
        /* Save allocatable integer registers on the stack,
           in the order given in proc.ml */
        STORE   a0, 0x10(sp)
        STORE   a1, 0x18(sp)
        STORE   a2, 0x20(sp)
        STORE   a3, 0x28(sp)
        STORE   a4, 0x30(sp)
        STORE   a5, 0x38(sp)
        STORE   a6, 0x40(sp)
        STORE   a7, 0x48(sp)
        STORE   s2, 0x50(sp)
        STORE   s3, 0x58(sp)
        STORE   s4, 0x60(sp)
        STORE   s5, 0x68(sp)
        STORE   s6, 0x70(sp)
        STORE   s7, 0x78(sp)
        STORE   s8, 0x80(sp)
        STORE   s9, 0x88(sp)
        STORE   t2, 0x90(sp)
        STORE   t3, 0x98(sp)
        STORE   t4, 0xa0(sp)
        STORE   t5, 0xa8(sp)
        STORE   t6, 0xb0(sp)
        /* Save caller-save floating-point registers on the stack
           (callee-saves are preserved by caml_garbage_collection) */
        fsd     ft0, 0xb8(sp)
        fsd     ft1, 0xc0(sp)
        fsd     ft2, 0xc8(sp)
        fsd     ft3, 0xd0(sp)
        fsd     ft4, 0xd8(sp)
        fsd     ft5, 0xe0(sp)
        fsd     ft6, 0xe8(sp)
        fsd     ft7, 0xf0(sp)
        fsd     fa0, 0xf8(sp)
        fsd     fa1, 0x100(sp)
        fsd     fa2, 0x108(sp)
        fsd     fa3, 0x110(sp)
        fsd     fa4, 0x118(sp)
        fsd     fa5, 0x120(sp)
        fsd     fa6, 0x128(sp)
        fsd     fa7, 0x130(sp)
        fsd     ft8, 0x138(sp)
        fsd     ft9, 0x140(sp)
        fsd     ft9, 0x148(sp)
        fsd     ft10, 0x150(sp)
        fsd     ft11, 0x158(sp)
        /* Store pointer to saved integer registers in caml_gc_regs */
        addi    TMP, sp, 0x10
        STORE   TMP, Caml_state(gc_regs)
        /* Save current allocation pointer for debugging purposes */
        STORE   ALLOC_PTR, Caml_state(young_ptr)
        /* Save trap pointer in case an exception is raised during GC */
        STORE   TRAP_PTR, Caml_state(exception_pointer)
        /* Call the garbage collector */
        call    PLT(caml_garbage_collection)
        /* Restore registers */
        LOAD    a0, 0x10(sp)
        LOAD    a1, 0x18(sp)
        LOAD    a2, 0x20(sp)
        LOAD    a3, 0x28(sp)
        LOAD    a4, 0x30(sp)
        LOAD    a5, 0x38(sp)
        LOAD    a6, 0x40(sp)
        LOAD    a7, 0x48(sp)
        LOAD    s2, 0x50(sp)
        LOAD    s3, 0x58(sp)
        LOAD    s4, 0x60(sp)
        LOAD    s5, 0x68(sp)
        LOAD    s6, 0x70(sp)
        LOAD    s7, 0x78(sp)
        LOAD    s8, 0x80(sp)
        LOAD    s9, 0x88(sp)
        LOAD    t2, 0x90(sp)
        LOAD    t3, 0x98(sp)
        LOAD    t4, 0xa0(sp)
        LOAD    t5, 0xa8(sp)
        LOAD    t6, 0xb0(sp)
        fld     ft0, 0xb8(sp)
        fld     ft1, 0xc0(sp)
        fld     ft2, 0xc8(sp)
        fld     ft3, 0xd0(sp)
        fld     ft4, 0xd8(sp)
        fld     ft5, 0xe0(sp)
        fld     ft6, 0xe8(sp)
        fld     ft7, 0xf0(sp)
        fld     fa0, 0xf8(sp)
        fld     fa1, 0x100(sp)
        fld     fa2, 0x108(sp)
        fld     fa3, 0x110(sp)
        fld     fa4, 0x118(sp)
        fld     fa5, 0x120(sp)
        fld     fa6, 0x128(sp)
        fld     fa7, 0x130(sp)
        fld     ft8, 0x138(sp)
        fld     ft9, 0x140(sp)
        fld     ft9, 0x148(sp)
        fld     ft10, 0x150(sp)
        fld     ft11, 0x158(sp)
        /* Reload new allocation pointer and allocation limit */
        LOAD    ALLOC_PTR, Caml_state(young_ptr)
        LOAD    ALLOC_LIMIT, Caml_state(young_limit)
        /* Free stack space and return to caller */
        LOAD    ra, 0x8(sp)
        LOAD    s0, 0x0(sp)
        addi    sp, sp, 0x160
        ret
        .size   caml_call_gc, .-caml_call_gc

/* Call a C function from OCaml */
/* Function to call is in ARG */

FUNCTION(caml_c_call)
        /* Preserve return address in callee-save register s2 */
        mv      s2, ra
        /* Record lowest stack address and return address */
        STORE   ra, Caml_state(last_return_address)
        STORE   sp, Caml_state(bottom_of_stack)
        /* Make the exception handler alloc ptr available to the C code */
        STORE   ALLOC_PTR, Caml_state(young_ptr)
        STORE   TRAP_PTR, Caml_state(exception_pointer)
        /* Call the function */
        jalr    ARG
        /* Reload alloc ptr and alloc limit */
        LOAD    ALLOC_PTR, Caml_state(young_ptr)
        LOAD    ALLOC_LIMIT, Caml_state(young_limit)
        /* Return */
        jr      s2
        .size   caml_c_call, .-caml_c_call

/* Raise an exception from OCaml */
FUNCTION(caml_raise_exn)
        /* Test if backtrace is active */
        LOAD    TMP, Caml_state(backtrace_active)
        bnez    TMP, 2f
1:      /* Cut stack at current trap handler */
        mv      sp, TRAP_PTR
        /* Pop previous handler and jump to it */
        LOAD    TMP, 8(sp)
        LOAD    TRAP_PTR, 0(sp)
        addi    sp, sp, 16
        jr      TMP
2:      /* Preserve exception bucket in callee-save register s2 */
        mv      s2, a0
        /* Stash the backtrace */
        mv      a1, ra
        mv      a2, sp
        mv      a3, TRAP_PTR
        call    PLT(caml_stash_backtrace)
        /* Restore exception bucket and raise */
        mv      a0, s2
        j       1b
        .size   caml_raise_exn, .-caml_raise_exn

        .globl  caml_reraise_exn
        .type   caml_reraise_exn, @function

/* Raise an exception from C */

FUNCTION(caml_raise_exception)
        mv      DOMAIN_STATE_PTR, a0
        mv      a0, a1
        LOAD    TRAP_PTR, Caml_state(exception_pointer)
        LOAD    ALLOC_PTR, Caml_state(young_ptr)
        LOAD    ALLOC_LIMIT, Caml_state(young_limit)
        LOAD    TMP, Caml_state(backtrace_active)
        bnez    TMP, 2f
1:      /* Cut stack at current trap handler */
        mv      sp, TRAP_PTR
        LOAD    TMP, 8(sp)
        LOAD    TRAP_PTR, 0(sp)
        addi    sp, sp, 16
        jr      TMP
2:      /* Preserve exception bucket in callee-save register s2 */
        mv      s2, a0
        LOAD    a1, Caml_state(last_return_address)
        LOAD    a2, Caml_state(bottom_of_stack)
        mv      a3, TRAP_PTR
        call    PLT(caml_stash_backtrace)
        mv      a0, s2
        j       1b
        .size   caml_raise_exception, .-caml_raise_exception

/* Start the OCaml program */

FUNCTION(caml_start_program)
        mv      ARG_DOMAIN_STATE_PTR, a0
        la      ARG, caml_program
        /* Code shared with caml_callback* */
        /* Address of OCaml code to call is in ARG */
        /* Arguments to the OCaml code are in a0 ... a7 */
.Ljump_to_caml:
        /* Set up stack frame and save callee-save registers */
        addi    sp, sp, -0xd0
        STORE   ra, 0xc0(sp)
        STORE   s0, 0x0(sp)
        STORE   s1, 0x8(sp)
        STORE   s2, 0x10(sp)
        STORE   s3, 0x18(sp)
        STORE   s4, 0x20(sp)
        STORE   s5, 0x28(sp)
        STORE   s6, 0x30(sp)
        STORE   s7, 0x38(sp)
        STORE   s8, 0x40(sp)
        STORE   s9, 0x48(sp)
        STORE   s10, 0x50(sp)
        STORE   s11, 0x58(sp)
        fsd     fs0, 0x60(sp)
        fsd     fs1, 0x68(sp)
        fsd     fs2, 0x70(sp)
        fsd     fs3, 0x78(sp)
        fsd     fs4, 0x80(sp)
        fsd     fs5, 0x88(sp)
        fsd     fs6, 0x90(sp)
        fsd     fs7, 0x98(sp)
        fsd     fs8, 0xa0(sp)
        fsd     fs9, 0xa8(sp)
        fsd     fs10, 0xb0(sp)
        fsd     fs11, 0xb8(sp)
        addi    sp, sp, -32
        /* Load domain state pointer from argument */
        mv      DOMAIN_STATE_PTR, ARG_DOMAIN_STATE_PTR
        /* Setup a callback link on the stack */
        LOAD    TMP, Caml_state(bottom_of_stack)
        STORE   TMP, 0(sp)
        LOAD    TMP, Caml_state(last_return_address)
        STORE   TMP, 8(sp)
        LOAD    TMP, Caml_state(gc_regs)
        STORE   TMP, 16(sp)
        /* set up a trap frame */
        addi    sp, sp, -16
        LOAD    TMP, Caml_state(exception_pointer)
        STORE   TMP, 0(sp)
        lla     TMP, .Ltrap_handler
        STORE   TMP, 8(sp)
        mv      TRAP_PTR, sp
        LOAD    ALLOC_PTR, Caml_state(young_ptr)
        LOAD    ALLOC_LIMIT, Caml_state(young_limit)
        STORE   x0, Caml_state(last_return_address)
        jalr    ARG
.Lcaml_retaddr:         /* pop trap frame, restoring caml_exception_pointer */
        LOAD    TMP, 0(sp)
        STORE   TMP, Caml_state(exception_pointer)
        addi    sp, sp, 16
.Lreturn_result:        /* pop callback link, restoring global variables */
        LOAD    TMP, 0(sp)
        STORE   TMP, Caml_state(bottom_of_stack)
        LOAD    TMP, 8(sp)
        STORE   TMP, Caml_state(last_return_address)
        LOAD    TMP, 16(sp)
        STORE   TMP, Caml_state(gc_regs)
        addi    sp, sp, 32
        /* Update allocation pointer */
        STORE   ALLOC_PTR, Caml_state(young_ptr)
        /* reload callee-save registers and return */
        LOAD    ra, 0xc0(sp)
        LOAD    s0, 0x0(sp)
        LOAD    s1, 0x8(sp)
        LOAD    s2, 0x10(sp)
        LOAD    s3, 0x18(sp)
        LOAD    s4, 0x20(sp)
        LOAD    s5, 0x28(sp)
        LOAD    s6, 0x30(sp)
        LOAD    s7, 0x38(sp)
        LOAD    s8, 0x40(sp)
        LOAD    s9, 0x48(sp)
        LOAD    s10, 0x50(sp)
        LOAD    s11, 0x58(sp)
        fld     fs0, 0x60(sp)
        fld     fs1, 0x68(sp)
        fld     fs2, 0x70(sp)
        fld     fs3, 0x78(sp)
        fld     fs4, 0x80(sp)
        fld     fs5, 0x88(sp)
        fld     fs6, 0x90(sp)
        fld     fs7, 0x98(sp)
        fld     fs8, 0xa0(sp)
        fld     fs9, 0xa8(sp)
        fld     fs10, 0xb0(sp)
        fld     fs11, 0xb8(sp)
        addi    sp, sp, 0xd0
        ret
        .type   .Lcaml_retaddr, @function
        .size   .Lcaml_retaddr, .-.Lcaml_retaddr
        .size   caml_start_program, .-caml_start_program

        .align  2
.Ltrap_handler:
        STORE   TRAP_PTR, Caml_state(exception_pointer)
        ori     a0, a0, 2
        j       .Lreturn_result
        .type   .Ltrap_handler, @function
        .size   .Ltrap_handler, .-.Ltrap_handler

/* Callback from C to OCaml */

FUNCTION(caml_callback_asm)
        /* Initial shuffling of arguments */
        /* a0 = Caml_state, a1 = closure, (a2) = args */
        mv      ARG_DOMAIN_STATE_PTR, a0
        LOAD    a0, 0(a2)   /* a0 = first arg */
                            /* a1 = closure environment */
        LOAD    ARG, 0(a1)  /* code pointer */
        j       .Ljump_to_caml
        .size   caml_callback_asm, .-caml_callback_asm

FUNCTION(caml_callback2_asm)
        /* Initial shuffling of arguments */
        /* a0 = Caml_state, a1 = closure, (a2) = args */
        mv      ARG_DOMAIN_STATE_PTR, a0
        mv      TMP, a1
        LOAD    a0, 0(a2)
        LOAD    a1, 8(a2)
        mv      a2, TMP
        la      ARG, caml_apply2
        j       .Ljump_to_caml
        .size   caml_callback2_asm, .-caml_callback2_asm

FUNCTION(caml_callback3_asm)
        /* Initial shuffling of arguments */
        /* a0 = Caml_state, a1 = closure, (a2) = args */
        mv      ARG_DOMAIN_STATE_PTR, a0
        mv      a3, a1
        LOAD    a0, 0(a2)
        LOAD    a1, 8(a2)
        LOAD    a2, 16(a2)
        la      ARG, caml_apply3
        j       .Ljump_to_caml
        .size   caml_callback3_asm, .-caml_callback3_asm

FUNCTION(caml_ml_array_bound_error)
        /* Load address of [caml_array_bound_error] in ARG */
        la      ARG, caml_array_bound_error
        /* Call that function */
        tail    caml_c_call
        .size   caml_ml_array_bound_error, .-caml_ml_array_bound_error

        .globl  caml_system__code_end
caml_system__code_end:

/* GC roots for callback */

        .section .data
        .align  3
        .globl  caml_system__frametable
        .type   caml_system__frametable, @object
caml_system__frametable:
        .quad   1               /* one descriptor */
        .quad   .Lcaml_retaddr  /* return address into callback */
        .short  -1              /* negative frame size => use callback link */
        .short  0               /* no roots */
        .align  3
        .size   caml_system__frametable, .-caml_system__frametable