aboutsummaryrefslogtreecommitdiff
path: root/debug_rom/debug_rom.S
blob: 74a934b201a94a31be63b24dd7c68a1149dcdecc (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
# This code should be functional. Doesn't have to be optimal.
# I'm writing it to prove that it can be done.

#include "riscv/encoding.h"

# TODO: Update these constants once they're finalized in the doc.

#define DEBUG_RAM               0x400
#ifndef DEBUG_RAM_SIZE
# define DEBUG_RAM_SIZE          64
#endif

#define CLEARDEBINT             0x100
#define SETHALTNOT              0x10c

#if (defined(RV32) + defined(RV64) + defined(RV128)) > 1
# define MULTI_XLEN
#elif (defined(RV32) + defined(RV64) + defined(RV128)) == 0
# error define one or more of RV32, RV64, RV128
#endif

        .global entry
        .global resume
        .global exception

        # Automatically called when Debug Mode is first entered.
entry:  j       _entry
        # Should be called by Debug RAM code that has finished execution and
        # wants to return to Debug Mode.
resume:
        j       _resume
exception:
        # Set the last word of Debug RAM to all ones, to indicate that we hit
        # an exception.
        li      s0, ~0
        j       _resume2

_resume:
        li      s0, 0
_resume2:
        fence

        # Restore s1.
#ifdef MULTI_XLEN
        csrr    s1, CSR_MISA
#endif

#ifdef RV32
# ifdef MULTI_XLEN
        bltz    s1, restore_not_32
# endif

restore_32:
        lw      s1, (DEBUG_RAM + DEBUG_RAM_SIZE - 4)(zero)
# if defined(RV64) || defined(RV128)
        j       finish_restore
# endif
#endif

restore_not_32:
#if defined(RV64) && defined(RV128)
        slli    s1, s1, 1
        bltz    s1, restore_128
#endif

#ifdef RV64
restore_64:
        ld      s1, (DEBUG_RAM + DEBUG_RAM_SIZE - 8)(zero)
#endif
#if defined(RV64) && defined(RV128)
        j       finish_restore
#endif
#ifdef RV128
restore_128:
        lq      s1, (DEBUG_RAM + DEBUG_RAM_SIZE - 16)(zero)
#endif

finish_restore:
        # s0 contains ~0 if we got here through an exception, and 0 otherwise.
        # Store this to the last word in Debug RAM so the debugger can tell if
        # an exception occurred.
        sw      s0, (DEBUG_RAM + DEBUG_RAM_SIZE - 4)(zero)

        # Clear debug interrupt.
        csrr    s0, CSR_MHARTID
        sw      s0, CLEARDEBINT(zero)

check_halt:
        csrr    s0, CSR_DCSR
        andi    s0, s0, DCSR_HALT
        bnez    s0, wait_for_interrupt

exit:
        # Restore s0.
        csrr    s0, CSR_DSCRATCH
        dret

_entry:
        # Save s0 in DSCRATCH
        csrw    CSR_DSCRATCH, s0

        # Check why we're here
        csrr    s0, CSR_DCSR
        # cause is in bits 8:6 of dcsr
        andi    s0, s0, DCSR_CAUSE
        addi    s0, s0, -(DCSR_CAUSE_DEBUGINT<<6)
        bnez    s0, spontaneous_halt

jdebugram:
        # Save s1 so that the debug program can use two registers.
#ifdef MULTI_XLEN
        csrr    s0, CSR_MISA
#endif

#ifdef RV32
# ifdef MULTI_XLEN
        bltz    s0, save_not_32
# endif
save_32:
        sw      s1, (DEBUG_RAM + DEBUG_RAM_SIZE - 4)(zero)
        jr      zero, DEBUG_RAM
#endif

save_not_32:
#if defined(RV64) && defined(RV128)
        slli    s0, s0, 1
        bltz    s0, save_128
#endif

#ifdef RV64
save_64:
        sd      s1, (DEBUG_RAM + DEBUG_RAM_SIZE - 8)(zero)
        jr      zero, DEBUG_RAM
#endif

#ifdef RV128
save_128:
        sq      s1, (DEBUG_RAM + DEBUG_RAM_SIZE - 16)(zero)
        jr      zero, DEBUG_RAM
#endif

spontaneous_halt:
        csrr    s0, CSR_MHARTID
        sw      s0, SETHALTNOT(zero)
        csrsi   CSR_DCSR, DCSR_HALT

wait_for_interrupt:
        csrr    s0, CSR_DCSR
        andi    s0, s0, DCSR_DEBUGINT
        beqz    s0, wait_for_interrupt

        j       jdebugram