-
Notifications
You must be signed in to change notification settings - Fork 1
/
os.s
303 lines (272 loc) · 13 KB
/
os.s
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
;------------------------------------------------------------------------------
; Project
; Ted John
; Version 1.4
; 16 April 2013
;
; Operating system
;
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
; Generic constants
;------------------------------------------------------------------------------
FALSE EQU 0
TRUE EQU 1
;------------------------------------------------------------------------------
; Sector division offsets
;------------------------------------------------------------------------------
OFFSET_OS EQU &0 ; start address for the OS (code in supervisor mode)
OFFSET_IRQ EQU &7900 ; start address for interupt code (IRQ mode)
OFFSET_USER EQU &8000 ; start address for the user code (user mode)
OFFSET_ENDRAM EQU &27C00 ; the last available RAM address
;------------------------------------------------------------------------------
; Architecture constants
;------------------------------------------------------------------------------
PSR_CLR_MODE EQU &1F
PSR_USR EQU &10
PSR_FIQ EQU &11
PSR_IRQ EQU &12
PSR_SVC EQU &13
PSR_ABT EQU &17
PSR_UND EQU &1B
PSR_SYS EQU &1F
;------------------------------------------------------------------------------
; I/O constants
;------------------------------------------------------------------------------
port_area EQU &10000000
port_LCD_DATA EQU &0
port_LCD_CTRL EQU &4
port_BUTTONS EQU &4
port_TIMER EQU &8
port_TIMER_CMP EQU &C
port_INT_REQ EQU &18
port_INT_EN EQU &1C
fpga_area EQU &20000000
;------------------------------------------------------------------------------
; BUTTON constants
;------------------------------------------------------------------------------
BTN_1 EQU (1 << 3)
BTN_2 EQU (1 << 7)
BTN_3 EQU (1 << 6)
BTN_MASK EQU (BTN_1 | BTN_2 | BTN_3)
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
; Interrupt constants
;------------------------------------------------------------------------------
INT_TIMER_CMP EQU (1 << 0)
INT_SPARTAN EQU (1 << 1)
INT_VIRTEX EQU (1 << 2)
INT_ETHERNET EQU (1 << 3)
INT_SERIAL_RR EQU (1 << 4)
INT_SERIAL_TR EQU (1 << 5)
INT_BTN_UPPER EQU (1 << 6)
INT_BTN_LOWER EQU (1 << 7)
;------------------------------------------------------------------------------
; Buzzer constants
;------------------------------------------------------------------------------
BUZZER_ENABLE_MASK EQU &8000
;------------------------------------------------------------------------------
ORG 0
;------------------------------------------------------------------------------
; Exception table
;------------------------------------------------------------------------------
os_exception_table
B os_reset ; reset
B os_undefined_instruction ; undefined instruction
B os_svc ; SVC
B os_prefetch_abort ; prefetch abort
B os_data_abort ; data abort
B os_trapper_exception ; -
B os_irq ; IRQ
B os_fiq ; FIQ
;------------------------------------------------------------------------------
; Operating system variables
;------------------------------------------------------------------------------
os_tick_count DEFW 0 ; the number of elapsed ms
;------------------------------------------------------------------------------
; os_undefined_instruction() - trapper
;------------------------------------------------------------------------------
os_undefined_instruction
B os_undefined_instruction
;------------------------------------------------------------------------------
; os_prefetch_abort() - trapper
;------------------------------------------------------------------------------
os_prefetch_abort
B os_prefetch_abort
;------------------------------------------------------------------------------
; os_data_abort() - trapper
;------------------------------------------------------------------------------
os_data_abort
B os_data_abort
;------------------------------------------------------------------------------
; os_trapper_exception() - trapper
;------------------------------------------------------------------------------
os_trapper_exception
B os_trapper_exception
;------------------------------------------------------------------------------
; os_fiq() - trapper
;------------------------------------------------------------------------------
os_fiq
B os_fiq
;------------------------------------------------------------------------------
; SVC CALL TYPES
;------------------------------------------------------------------------------
SVC_EXIT EQU 0
SVC_LCD_LIGHT EQU 1
SVC_LCD_CLEAR EQU 2
SVC_LCD_WRITE EQU 3
SVC_LCD_WRITE_CHAR EQU 4
SVC_LCD_SET_CURSOR EQU 5
SVC_LCD_COMMAND EQU 6
SVC_BUZZ_SET EQU 7
SVC_KEYPAD_SCAN EQU 8
SVC_SVC_COUNT EQU 9
;------------------------------------------------------------------------------
; os_svc() - Runs a supervisor instruction
;
; R14 - mode
;------------------------------------------------------------------------------
os_svc
PUSH {R14} ; push scratch register
LDR R14, [R14, #-4] ; read SVC instruction
BIC R14, R14, #&FF000000 ; mask off opcode
CMP R14, #SVC_SVC_COUNT ; check if SVC instruction exists
BHS os_undefined_instruction
os_svc_jump ; SVC switch
ADD R14, PC, R14, LSL #2
LDR R14, [R14, #(os_svc_jumptable-os_svc_jump-8)]
PUSH {R14}
MOV R14, #os_svc_return
POP {PC}
os_svc_return
POP {PC}^
os_svc_jumptable ; SVC case jump table
DEFW os_exit
DEFW lcd_setlight
DEFW lcd_clear
DEFW lcd_putstring
DEFW lcd_putchar
DEFW lcd_setcursor
DEFW lcd_command
DEFW buzz_set
DEFW keypad_scan
;------------------------------------------------------------------------------
; os_irq() - interrupt handler
;------------------------------------------------------------------------------
os_irq
SUB LR, LR, #4 ; Convert return address to interrupted instruction address
PUSH {R0, R1, R2, LR}
MOV R0, #port_area
LDR R1, [R0, #port_INT_REQ] ; Obtain the interrupt request
TST R1, #INT_TIMER_CMP ; Test if timer compare
BLNE os_update_tick_count
MOV R1, #0 ; Clear the interrupt requests
STR R1, [R0, #port_INT_REQ]
POP {R0, R1, R2, PC}^ ; Return to last code and mode
;------------------------------------------------------------------------------
; os_reset() - reset the operating system
;
; R14 - mode
;------------------------------------------------------------------------------
os_reset
MOV SP, #OFFSET_IRQ ; initialise supervisor stack
MOV R0, #0 ; initialise os variables
MOV R1, #os_tick_count
STR R0, [R1]
MOV R1, #0
MOV R0, #port_area
STRB R1, [R0, #port_LCD_CTRL] ; store port value
MOV R0, #fpga_area
STRH R1, [R0] ; store buzzer output
MSR CPSR_c, #&D2 ; change to IRQ mode
MOV SP, #OFFSET_USER ; initialise interrupt stack
MOV R0, #port_area
MOV R1, #0 ; clear the interrupt requests
STR R1, [R0, #port_INT_REQ]
MOV R1, #INT_TIMER_CMP ; enable the timer compare interrupt
STR R1, [R0, #port_INT_EN]
MOV R1, #1 ; set the timer compare to be 1ms
STR R1, [R0, #port_TIMER_CMP]
MOV R14, #&50 ; user mode, with interrupts
MSR SPSR, R14
MOV LR, #OFFSET_USER ; set main as the user code entry point
ADD LR, LR, #(main-OFFSET_USER)
MOVS PC, LR ; switch to user code
;------------------------------------------------------------------------------
; os_exit() - ends the program and operating system
;------------------------------------------------------------------------------
os_exit
B os_exit
;------------------------------------------------------------------------------
; os_update_tick_count() - increments the tick count and resets the timer
;
; R0 - port area address
; R1 - ticks
; R2 - os tick count variable reference
;------------------------------------------------------------------------------
os_update_tick_count
PUSH {R0, R1, R2, LR}
MOV R2, #os_tick_count
MOV R0, #port_area
MOV R1, #0 ; Clear the timer
STR R1, [R0, #port_TIMER]
LDR R1, [R2] ; Increment the OS tick count
ADD R1, R1, #1
STR R1, [R2]
POP {R0, R1, R2, PC}
;------------------------------------------------------------------------------
; buzz_set() - sets the buzzer to play a certain frequency
;
; I R0 - time period
; I R1 - port
; R2 - general purpose value
;------------------------------------------------------------------------------
buzz_set
PUSH {R2, R3, LR}
MOV R2, #fpga_area ; get port address
ADD R2, R2, R1 LSL #2
MOV R3, R0, LSR #8 ; store high
STRB R3, [R2, #1]
STRB R0, [R2, #0]
POP {R2, R3, PC}
;------------------------------------------------------------------------------
; memset() - sets a number of bytes to a value
; I R0 - address
; I R1 - value
; I R2 - length
;------------------------------------------------------------------------------
memset
PUSH {R0, R2, LR}
memset_loop
CMP R2, #1
STRGEB R1, [R0], #1
SUBGE R2, R2, #1
BGE memset_loop
POP {R0, R2, PC}
;------------------------------------------------------------------------------
; has_elapsed_by()
;
; IO R0 - address of tick save, output true if so otherwise false
; I R1 - number of ticks
;
; R2 - current tick count
; R3 - last tick count / elapsed
;------------------------------------------------------------------------------
has_elapsed_by
PUSH {R2, R3, LR}
MOV R2, #os_tick_count ; get current tick
LDR R2, [R2]
LDR R3, [R0] ; get last tick
SUB R3, R2, R3 ; get elapsed ticks
CMP R3, R1 ; check if elapsed ticks > R1
MOVLT R0, #FALSE
BLT has_elapsed_by_return
STR R2, [R0] ; set last tick
MOV R0, #TRUE
has_elapsed_by_return
POP {R2, R3, PC}
;------------------------------------------------------------------------------
INCLUDE lcd.s
INCLUDE keypad.s
INCLUDE math.s
INCLUDE string.s