xa_asm: fixed parsing of symbols used with DS directive in BSEG (pass 2&3).
[fw/sdcc] / as / xa51 / mt.xa
1
2 ;$include xa-g3.equ     ;will implement included later on
3
4
5 ; Include file for XA-G3 SFR Definitions
6 ; Philips Semiconductors. Revision 1.8, 1/21/97
7 ; $nolist               ;will implement this later on
8
9 ; Register equates.
10
11 acc     reg     R4L          ; for translated 80C51 code
12 dpl     reg     R6L          ; for translated 80C51 code
13 dph     reg     R6H          ; for translated 80C51 code
14 sp      reg     R7           ; for translated 80C51 code
15
16
17 ; SFR byte and bit definitions.
18
19 bcr     sfr     46ah
20 btrh    sfr     469h
21 btrl    sfr     468h
22 cs      sfr     443h
23 ds      sfr     441h
24 es      sfr     442h
25
26 ieh     sfr     427h
27 eri0    bit     ieh.0
28 eti0    bit     ieh.1
29 eri1    bit     ieh.2
30 eti1    bit     ieh.3
31
32 iel     sfr     426h
33 ex0     bit     iel.0
34 et0     bit     iel.1
35 ex1     bit     iel.2
36 et1     bit     iel.3
37 et2     bit     iel.4
38 ea      bit     iel.7
39
40 ipa0    sfr     4a0h
41 ipa1    sfr     4a1h
42 ipa2    sfr     4a2h
43 ipa4    sfr     4a4h
44 ipa5    sfr     4a5h
45
46 p0      sfr     430h
47 p1      sfr     431h
48 p2      sfr     432h
49 p3      sfr     433h
50 p0cfga  sfr     470h
51 p1cfga  sfr     471h
52 p2cfga  sfr     472h
53 p3cfga  sfr     473h
54 p0cfgb  sfr     4f0h
55 p1cfgb  sfr     4f1h
56 p2cfgb  sfr     4f2h
57 p3cfgb  sfr     4f3h
58
59 pcon    sfr     404h
60 idl     bit     pcon.0
61 pd      bit     pcon.1
62
63 pswh    sfr     401h
64 im0     bit     pswh.0
65 im1     bit     pswh.1
66 im2     bit     pswh.2
67 im3     bit     pswh.3
68 rs0     bit     pswh.4
69 rs1     bit     pswh.5
70 tm      bit     pswh.6
71 sm      bit     pswh.7
72
73 pswl    sfr     400h
74 z       bit     pswl.0
75 n       bit     pswl.1
76 v       bit     pswl.2
77 ac      bit     pswl.6
78 cy      bit     pswl.7
79
80 psw51   sfr     402h
81
82 rth0    sfr     455h
83 rth1    sfr     457h
84 rtl0    sfr     454h
85 rtl1    sfr     456h
86
87 s0con   sfr     420h
88 ri_0    bit     s0con.0
89 ti_0    bit     s0con.1
90 rb8_0   bit     s0con.2
91 tb8_0   bit     s0con.3
92 ren_0   bit     s0con.4
93 sm2_0   bit     s0con.5
94 sm1_0   bit     s0con.6
95 sm0_0   bit     s0con.7
96 scon    sfr     420h         ; duplicate label for translated 80C51 code.
97 ri      bit     scon.0       ; duplicate label for translated 80C51 code.
98 ti      bit     scon.1       ; duplicate label for translated 80C51 code.
99 rb8     bit     s0con.2      ; duplicate label for translated 80C51 code.
100 tb8     bit     s0con.3      ; duplicate label for translated 80C51 code.
101 ren     bit     s0con.4      ; duplicate label for translated 80C51 code.
102 sm2     bit     s0con.5      ; duplicate label for translated 80C51 code.
103 sm1     bit     s0con.6      ; duplicate label for translated 80C51 code.
104 sm0     bit     s0con.7      ; duplicate label for translated 80C51 code.
105
106 s0stat  sfr     421h
107 stint0  bit     s0stat.0
108 oe0     bit     s0stat.1
109 br0     bit     s0stat.2
110 fe0     bit     s0stat.3
111
112 s0buf   sfr     460h
113 sbuf    sfr     460h         ; duplicate label for translated 80C51 code.
114 s0addr  sfr     461h
115 s0aden  sfr     462h
116
117 s1con   sfr     424h
118 ri_1    bit     s1con.0
119 ti_1    bit     s1con.1
120 rb8_1   bit     s1con.2
121 tb8_1   bit     s1con.3
122 ren_1   bit     s1con.4
123 sm2_1   bit     s1con.5
124 sm1_1   bit     s1con.6
125 sm0_1   bit     s1con.7
126
127 s1stat  sfr     425h
128 stint1  bit     s1stat.0
129 oe1     bit     s1stat.1
130 br1     bit     s1stat.2
131 fe1     bit     s1stat.3
132
133 s1buf   sfr     464h
134 s1addr  sfr     465h
135 s1aden  sfr     466h
136
137 scr     sfr     440h
138
139 ssel    sfr     403h
140 r0seg   bit     ssel.0
141 r1seg   bit     ssel.1
142 r2seg   bit     ssel.2
143 r3seg   bit     ssel.3
144 r4seg   bit     ssel.4
145 r5seg   bit     ssel.5
146 r6seg   bit     ssel.6
147 eswen   bit     ssel.7
148
149 swe     sfr     47ah
150 swr     sfr     42ah
151 swr1    bit     swr.0
152 swr2    bit     swr.1
153 swr3    bit     swr.2
154 swr4    bit     swr.3
155 swr5    bit     swr.4
156 swr6    bit     swr.5
157 swr7    bit     swr.6
158
159 swe1    equ     00000001q    ; bit masks for software interrupt enables.
160 swe2    equ     00000010q
161 swe3    equ     00000100q
162 swe4    equ     00001000q
163 swe5    equ     00010000q
164 swe6    equ     00100000q
165 swe7    equ     01000000q
166
167 t2con   sfr     418h
168 cprl2   bit     t2con.0
169 ct2     bit     t2con.1
170 tr2     bit     t2con.2
171 exen2   bit     t2con.3
172 tclk0   bit     t2con.4
173 rclk0   bit     t2con.5
174 tclk    bit     t2con.4      ; duplicate label for translated 80C51 code.
175 rclk    bit     t2con.5      ; duplicate label for translated 80C51 code.
176 exf2    bit     t2con.6
177 tf2     bit     t2con.7
178
179 t2mod   sfr     419h
180 dcen    bit     t2mod.0
181 t2oe    bit     t2mod.1
182 t2rd    bit     t2mod.2
183 tclk1   bit     t2mod.4
184 rclk1   bit     t2mod.5
185
186 th2     sfr     459h
187 tl2     sfr     458h
188 t2caph  sfr     45bh
189 t2capl  sfr     45ah
190
191 tcon    sfr     410h
192 it0     bit     tcon.0
193 ie0     bit     tcon.1
194 it1     bit     tcon.2
195 ie1     bit     tcon.3
196 tr0     bit     tcon.4
197 tf0     bit     tcon.5
198 tr1     bit     tcon.6
199 tf1     bit     tcon.7
200
201 th0     sfr     451h
202 th1     sfr     453h
203 tl0     sfr     450h
204 tl1     sfr     452h
205 tmod    sfr     45ch
206 tstat   sfr     411h
207 t0oe    bit     tstat.0
208 t0rd    bit     tstat.1
209 t1oe    bit     tstat.2
210 t1rd    bit     tstat.3
211
212 wdcon   sfr     41fh
213 wdtof   bit     wdcon.1
214 wdrun   bit     wdcon.2
215 pre0    bit     wdcon.5
216 pre1    bit     wdcon.6
217 pre2    bit     wdcon.7
218
219 wdl     sfr     45fh
220 wfeed1  sfr     45dh
221 wfeed2  sfr     45eh
222
223
224 ; Port pin name definitions.
225
226 a4d0    bit     P0.0
227 a5d1    bit     P0.1
228 a6d2    bit     P0.2
229 a7d3    bit     P0.3
230 a8d4    bit     P0.4
231 a9d5    bit     P0.5
232 a10d6   bit     P0.6
233 a11d7   bit     P0.7
234
235 a0      bit     P1.0
236 wrh     bit     P1.0
237 a1      bit     P1.1
238 a2      bit     P1.2
239 a3      bit     P1.3
240 rxd1    bit     P1.4
241 txd1    bit     P1.5
242 t2      bit     P1.6
243 t2ex    bit     P1.7
244
245 a12d8   bit     P2.0
246 a13d9   bit     P2.1
247 a14d10  bit     P2.2
248 a15d11  bit     P2.3
249 a16d12  bit     P2.4
250 a17d13  bit     P2.5
251 a18d14  bit     P2.6
252 a19d15  bit     P2.7
253
254 rxd0    bit     P3.0
255 txd0    bit     P3.1
256 int0    bit     P3.2
257 int1    bit     P3.3
258 t0      bit     P3.4
259 t1      bit     P3.5
260 busw    bit     P3.5
261 wrl     bit     P3.6
262 rd      bit     P3.7
263
264 ; End of XA-G3 SFR definitions.
265 ;$list          ;handle this later on
266
267
268
269
270 trap_delay              equ             0
271 trap_cout               equ             1
272
273         org             $8040           ;paulmon2 will jump here on trap #0
274         jmp             syscall_sleep
275         org             $8044           ;paulmon2 will jump here on trap #1
276         jmp             syscall_cout
277
278         org             $8084           ;paulmon2 will jump here on timer0 interrupt
279         jmp             timer0
280
281         org             $80A0           ;paulmon2 will jump here on uart0 rx interrupt
282         jmp             uart0_recv
283         org             $80A4           ;paulmon2 will jump here on uart0 tx interrupt
284         jmp             uart0_xmit
285         org             $80A8           ;paulmon2 will jump here on uart1 rx interrupt
286         jmp             uart1_recv
287         org             $80AC           ;paulmon2 will jump here on uart1 tx interrupt
288         jmp             uart1_xmit
289
290         org             $8100           ;paulmon2 will jump here on software int1
291         jmp             context_switch
292         org             $8104           ;paulmon2 will jump here on software int2
293         jmp             do_events
294
295         org             $8120
296         jmp             poweron
297
298 request_do_events                       bit             swr2
299 request_context_switch          bit             swr1
300
301 max_num_ticks   equ             7               ;max time a process can run if other
302                                                                 ;processes are waiting in the run queue
303
304
305 ;this memory allocation should be done with "ds" directives to
306 ;save space, but for now it's done with "equ" with lots of gaps,
307 ;so that things will stay put and aligned on 16 byte boundries
308 ;where they can be easily viewed with the paulmon2 hex dump.  When
309 ;the kernel code is more mature this will have to be changed.
310
311 sys_stack               equ             $FB00
312
313 rx0_buf_head    equ             $FB00           ;2 bytes
314 rx0_buf_tail    equ             $FB02           ;2 bytes
315 rx0_buf_size    equ             $20
316 rx0_buf                 equ             $FB10           ;rx0_buf_size bytes
317
318 rx1_buf_head    equ             $FB40           ;2 bytes
319 rx1_buf_tail    equ             $FB42           ;2 bytes
320 rx1_buf_size    equ             $20
321 rx1_buf                 equ             $FB50           ;rx1_buf_size bytes
322
323 tx0_buf_head    equ             $FB80           ;2 bytes
324 tx0_buf_tail    equ             $FB82           ;2 bytes
325 tx0_buf_size    equ             $20
326 tx0_buf_threshold       equ     9
327 tx0_buf                 equ             $FB90           ;tx0_buf_size bytes
328
329 tx1_buf_head    equ             $FBC0           ;2 bytes
330 tx1_buf_tail    equ             $FBC2           ;2 bytes
331 tx1_buf_size    equ             $20
332 tx1_buf_threshold       equ     9
333 tx1_buf                 equ             $FBD0           ;tx1_buf_size bytes
334
335
336 current_proc    equ             $FEF0   ;2 bytes, ptr to proc_table entry of
337                                                                 ;currently running process, 0 if none
338 run_queue               equ             $FEF2   ;2 bytes, pointer to a linked list
339                                                                 ;of processes waiting to run
340 sleep_queue             equ             $FEF4   ;2 bytes, pointer to a linked list
341                                                                 ;of sleeping processes
342 time_running    equ             $FEF6   ;1 byte, number of ticks that the
343                                                                 ;current process has run.
344 event_queue             equ             $FCF0   ;2 bytes, pointer to a linked list
345                                                                 ;of pending events (event_table)
346
347 max_num_proc    equ             14
348 proc_table              equ             $FE00   ;(max_num_proc*pt_entry_size) bytes
349 pt_entry_size   equ             16              ;16 bytes per table entry
350 pt_usp                  equ             0               ;2 bytes, User Stack Pointer
351 pt_q_next               equ             2               ;2 bytes, ptr to next in queue
352 pt_q_prev               equ             4               ;2 bytes, ptr to prev in queue (+pt_q_next)
353 pt_wait                 equ             6               ;2 bytes, what are we waiting for?
354 pt_wakeup               equ             8               ;2 bytes, where do we go on wakeup?
355 pt_prog_addr    equ             10              ;2 bytes, location of program header
356 pt_prog_cs              equ             12              ;1 byte, code segment of program header
357 pt_priority             equ             13              ;1 byte, execution priority
358 pt_pid                  equ             14              ;1 byte, id num for this process
359
360         ;need to define a program header, which will include various
361         ;info about the program, including the req'd stack space, max
362         ;expect memory to malloc, range of directly addressed memory
363         ;(which must be saved during a context switch), max number of
364         ;open file descriptors reqd, etc.
365
366 max_num_event   equ             15              ;(max_num_proc*2)
367 event_table             equ             $FC00   ;(max_num_event*evt_entry_size)
368 evt_entry_size  equ             16              ;8 bytes per event entry
369 evt_ticks               equ             0               ;# of ticks until event (delta from prev)
370 evt_next                equ             2               ;pointer to next event in list
371 evt_function    equ             4               ;place to call (0 if evt slot unused)
372 evt_arg1                equ             6               ;optional argument
373
374 ;the file descriptors will be allocated before the stack in the
375 ;block of memory which is allocated when the process is created.
376 ;each individual process can specify the max number of file
377 ;descriptors that it will require
378
379 file_desc_table equ             $FE80   ;128 bytes
380 fd_entry_size   equ             7               ;7 bytes per table entry
381 fd_offset               equ             0               ;4 bytes, offset in file
382 fd_flags                equ             4               ;1 byte, read/write/append
383 fd_routines             equ             5               ;2 bytes, ptr to i/o routines
384
385
386 ;single character debug symbols:
387 ;  space        context switcher is idle
388 ;    *      contect switcher entered
389 ;    #          timer interrupt (normal)
390 ;    %          timer interrupt requested context switch
391 ;    !      timer interrupt requested event service
392 ;        @              entered event service interrupt routine
393 ;    ^          event service function called
394 ;        ~      leaving event service interrupt routine
395
396 ;this timer interrupt routine is responsible for monitoring the
397 ;time that the current process has been running and adjusting the
398 ;process priorities accordingly.  It also checks if any events
399 ;in the event queue need to be processed.  This code runs at a
400 ;high cpu priority and it runs often, so it should get done as
401 ;quickly as possible... if anything lengthy might need to be done,
402 ;a software interrupt (low priority) should be set, so it can be
403 ;done later on without blocking other important interrupts, such
404 ;as low-level i/o.
405
406 timer0:
407         push    r0, r1, r2, r3, r4, r5, r6
408         ;other stuff can be added here, such as maintaining a
409         ;system clock...
410           ;mov  r4l, #'#'
411 check_events:
412         mov             r0, #event_queue
413         clr             ea
414         mov             r1, [r0]
415         beq             ckevt_end               ;no events if queue is empty
416         mov             r2, [r1+evt_ticks]
417         beq             ckevt_do_em
418         ;if we get here, there are events pending but it's not
419         ;time to do any of them yet, so we'll just decrement the
420         ;ticks of the first one, which will decrement the effective
421         ;time for all of them since they use a delta-time between
422         ;each entry in the linked list
423         adds.w  [r1+evt_ticks], #-1
424         br              ckevt_end
425 ckevt_do_em:
426         ;if we get here, there is at least one event which needs
427         ;to be serviced... but we won't do that here, just set the
428         ;software interrupt so it can be handled by "do_event"
429         ;setb   request_do_events
430           ;mov  r4l, #'!'
431           ;call cout
432         ;call   do_events               ;not nice, but sw int priority not working
433         setb    request_do_events
434 ckevt_end:
435         setb    ea
436         nop
437 schedule:
438         mov             r0, #current_proc
439         clr             ea
440         mov             r1, [r0]
441         beq             sch_end                 ;don't bother if no process is running
442         sub.b   [r1+pt_priority], #1    ;decrease priority by one
443         bcc     sch_priority_ok
444         movs.b  [r1+pt_priority], #0    ;but don't go less than zero
445 sch_priority_ok:
446         mov             r0, #time_running
447         mov             r3l, [r0]
448         adds    r3l, #1                         ;increment time_running
449         mov             [r0], r3l
450         cmp             r3l, #max_num_ticks
451         bl              sch_end
452         ;if we get here, the currently running process is has been
453         ;using the cpu for at least the max number ticks, so it's
454         ;time to force it to take a rest and let someone else have
455         ;a chance.
456         mov             r0, #run_queue
457         mov             r1, [r0]
458         beq             sch_end         ;don't preempt if nothing in run queue
459           ;mov  r4l, #'%'
460         setb    request_context_switch          ;make something else run
461 sch_end:
462         setb    ea
463           ;cmp  r4l, #'!'
464           ;beq  t0_skip_print
465           ;call cout
466         nop
467 t0_skip_print:
468         pop             r0, r1, r2, r3, r4, r5, r6
469         reti
470
471
472         ;this routine actually calls the event handlers for all
473         ;events which are supposed to happen NOW.  The main timer
474         ;routine must decrement the time of the events and arrange
475         ;for this code to be run when any events are supposed to
476         ;happen.  The event handler gets the address of the event
477         ;in r1.
478 do_events:
479         push    r0, r1, r2, r3, r4, r5, r6
480 do_events_begin:
481           ;mov  r4l, #'@'
482           ;call cout
483 doevt_loop:
484         mov             r0, #event_queue
485         mov             r1, [r0]
486         beq             doevt_end               ;no events to do if queue is empty
487         mov             r2, [r1+evt_ticks]
488         bne             doevt_end               ;done if event is in the future
489         mov             r2, [r1+evt_next]
490         mov             [r0], r2                ;remove event from queue
491         mov             r2, [r1+evt_function]
492         movs.w  [r1+evt_function], #0
493           ;mov  r4l, #'^'
494           ;call cout
495         call    [r2]                    ;call the event handler specified
496         br              doevt_loop
497 doevt_end:
498           ;mov  r4l, #'~'
499           ;call cout
500         clr             request_do_events
501         pop             r0, r1, r2, r3, r4, r5, r6
502         reti
503
504
505
506 ;interrupt receive routine for uart #0
507 uart0_recv:
508         push    r0, r1, r2, r5, r6
509         clr             ri_0
510         mov             r5l, s0buf
511         mov             r2, #rx0_buf
512         mov             r0, #rx0_buf_head
513         mov             r6, #rx0_buf_tail
514         mov             r1, [r0]
515         adds    r1, #1
516         cjne    r1, #rx0_buf+rx0_buf_size, uart_recv_check2
517         mov             r1, #rx0_buf
518         br              uart_recv_check2
519 ;interrupt receive routine for uart #1
520 uart1_recv:
521         push    r0, r1, r2, r5, r6
522         clr             ri_1
523         mov             r5l, s1buf
524         mov             r2, #rx1_buf
525         mov             r0, #rx1_buf_head
526         mov             r6, #rx1_buf_tail
527         mov             r1, [r0]
528         adds    r1, #1
529         cjne    r1, #rx1_buf+rx1_buf_size, uart_recv_check2
530         mov             r1, #rx1_buf
531 ;this remaining code is shared by both uart receive routines
532 uart_recv_check2:
533         cmp             r1, [r6]
534         bne             uart_recv_ok
535         ;if we get here, the buffer is full, discard data
536         call    wakeup_intr_io
537         pop             r0, r1, r2, r5, r6
538         reti
539 uart_recv_ok:
540         mov.b   [r1], r5l               ;store byte into buffer
541         mov             [r0], r1                ;update buffer pointer
542         ;perhaps there should be a way for us to know how much data a
543         ;sleeping process wants to extract from the buffer, so we can
544         ;avoid waking it up until there is at least that much data.
545         call    wakeup_intr_io
546         pop             r0, r1, r2, r5, r6
547         reti
548
549 ;interrupt transmit routine for uart #0
550 uart0_xmit:
551         push    r0, r1, r2, r5, r6
552         clr             ti_0
553         mov             r0, #tx0_buf_tail
554         mov             r2, #tx0_buf_head
555         mov             r1, [r0]
556         cmp             r1, [r2]
557         beq             uart_no_xmit
558         adds    r1, #1
559         cjne    r1, #tx0_buf+tx0_buf_size, uart0_xmit2
560         mov             r1, #tx0_buf
561 uart0_xmit2:
562         mov.b   s0buf, [r1]
563         mov             [r0], r1
564         ;now figure out if we want to wake up processes which are
565         ;waiting to put more data into this buffer
566         mov             r1, [r2]
567         sub             r1, [r0]
568         bcc             uart0_xmit3
569         add             r1, #tx0_buf_size
570 uart0_xmit3:
571         cmp             r1, #(tx0_buf_threshold)
572         bcc             uart0_xmit_end          ;don't wake proc unless over threshold
573         mov             r2, #tx0_buf
574         call    wakeup_intr_io
575 uart0_xmit_end:
576         pop             r0, r1, r2, r5, r6
577         reti
578 ;interrupt transmit routine for uart #1
579 uart1_xmit:
580         push    r0, r1, r2, r5, r6
581         clr             ti_1
582         mov             r0, #tx1_buf_tail
583         mov             r2, #tx1_buf_head
584         mov             r1, [r0]
585         cmp             r1, [r2]
586         beq             uart_no_xmit
587         adds    r1, #1
588         cjne    r1, #tx1_buf+tx1_buf_size, uart1_xmit2
589         mov             r1, #tx1_buf
590 uart1_xmit2:
591         mov.b   s1buf, [r1]
592         mov             [r0], r1
593         ;now figure out if we want to wake up processes which are
594         ;waiting to put more data into this buffer
595         mov             r1, [r2]
596         sub             r1, [r0]
597         bcc             uart1_xmit3
598         add             r1, #tx1_buf_size
599 uart1_xmit3:
600         cmp             r1, #tx1_buf_threshold
601         bcc             uart1_xmit_end          ;don't wake proc unless over threshold
602         mov             r2, #tx1_buf
603         call    wakeup_intr_io
604 uart1_xmit_end:
605         pop             r0, r1, r2, r5, r6
606         reti
607
608 ;this is shared by both transmit interrupt routines
609 uart_no_xmit:
610         ;if we got here, there is no data waiting to transmit
611         ;load the _head pointer with 0, so a routine which loads
612         ;data into the buffer will know to set the ti bit.
613         movs.w  [r2], #0
614         pop             r0, r1, r2, r5, r6
615         reti
616
617
618 ;This routine wakes up any sleeping processes that are waiting
619 ;for i/o in the buffer pointed to by r2.  Interrupt routines
620 ;should call here after doing i/o one their buffers, so that
621 ;any processes which are waiting for that i/o will be awakened.
622
623 wakeup_intr_io:
624         mov             r0, #sleep_queue
625         mov             r1, [r0]
626         beq             wkintio_empty   ;sleep_queue is empty
627         clr             ea                      ;disable interrupts while we look at the queue
628 wkintio_loop:
629         cmp             [r1+pt_wait], r2
630         beq             wkintio_wakeup  ;wake proc if waiting for i/o on this buffer
631         mov             r1, [r1+pt_q_next]
632         bne             wkintio_loop
633         setb    ea                              ;ok for other interrupts now
634 wkintio_empty:
635         ret
636 wkintio_wakeup:
637         ;if we get here, this sleeping processes was waiting for
638         ;i/o on the buffer pointed to by r2, so let's wake it up.
639         ;d_que_proc: (remove from sleep queue)
640         mov             r6, [r1+pt_q_next]
641         push    r6                                              ;save ptr to next in sleep queue
642         mov             r5, [r1+pt_q_prev]
643         mov             [r5], r6
644         mov             [r6+pt_q_prev], r5
645         ;en_que_proc: (add to run queue)
646         mov             r0, #run_queue
647         mov             [r1+pt_q_prev], r0
648         mov             r5, [r0]
649         mov             [r1+pt_q_next], r5
650         lea             r6, r1+pt_q_next
651         mov             [r5+pt_q_prev], r6
652         mov             [r0], r1
653         adds.b  [r1+pt_priority], #5    ;give it a bit of priority boost...
654         ;need to check here for overrange on user priority
655         setb    request_context_switch  ;get it running asap.
656         ;continue looking for processes waiting on this i/o buffer,
657         ;because there may be more than one, and we need to get them
658         ;all into the run queue so that the context switcher can choose
659         ;the one with the highest priority.
660         pop             r1
661         cmp             r1, #0
662         bne             wkintio_loop
663         setb    ea
664         ret
665
666
667
668
669
670
671
672 ;**************************************************************
673
674
675
676
677
678
679 ;The context switcher is responsible for figuring out which process
680 ;is supposed to run next (looks at pt_priority) and if a context
681 ;change is required this is where it will happen.  If any
682 ;interrupt driven part of the kernel wants to make a particular
683 ;process run, it must change the priority for that process and
684 ;then set the software interrupt to run the context switcher later.
685
686 ;For system calls that want to make their calling process sleep,
687 ;they should jump to the ksleep routine, which will jump to
688 ;"ctsw_begin" to allow something else to run.
689
690 ;Note: the context switcher doesn't enforce preemptive multitasking...
691 ;a timer routine must count how long the currently running process
692 ;has be running since a context switch ("time_running" variable)
693 ;and if it's being a hog the timer routine that detects it must
694 ;lower the priority and set the software interrupt to cause this
695 ;context switcher to make a different process run.  The context
696 ;switcher also depends on interrupt routines to change the
697 ;"pt_priority" field of each process table entry, all the context
698 ;switcher does is pick the process with highest priority.  The
699 ;currently running process is always switched out if there is
700 ;something in the run queue, even if the item in the run queue
701 ;has a lower priority.
702
703
704 context_switch:
705         pushu   r0, r1, r2, r3, r4, r5, r6              ;save registers
706         pop             r2, r3, r4                                              ;get pc and psw
707         pushu   r2, r3, r4                                              ;save them on user stack
708         pushu.b ds
709         pushu.b es
710         pushu.b ssel
711
712
713 ctsw_begin:
714           ;mov  r4l, #'*'
715           ;call cout
716 ctsw_retry:
717         ;find the process on the run queue with highest priority
718         mov             r0, #run_queue
719         mov             r1, [r0]
720         beq             ctsw_queue_empty        ;run_queue is empty
721         movs    r2, #0                  ;r2 is proc w/ highest priority
722         mov             r3l, #0                 ;r3l is highest priority we've seen
723         clr             ea                      ;disable interrupts while we look at the
724                                                 ;run queue, since interrupt routines will be
725                                                 ;changing priorities to influence which process
726                                                 ;should be run next
727 ctsw_loop:
728         cmp             [r1+pt_priority], r3l
729         bcs             ctsw_skip
730         ;if we get here, this process is the highest
731         ;priority so far, so forget about any other
732         mov             r3l, [r1+pt_priority]
733         mov             r2, r1
734 ctsw_skip:
735         mov             r1, [r1+pt_q_next]
736         bne             ctsw_loop
737         ;now r2 points to the process which should be running...
738         ;check to see if "current_proc" is valid... if it is zero then
739         ;nothing was running (a sys call probably put the process to
740         ;sleep).  If "current_proc" has a valid process pointer, then we
741         ;need to save that process's context (apart from the pushed regs)
742         ;and put that process back into the run queue
743         mov             r0, #current_proc
744         mov             r1, [r0]
745         beq             ctsw_switch
746         call    save_context
747         movs.w  [r1+pt_wakeup], #0              ;wants to go back to user mode
748         mov             r0, #run_queue
749         call    en_que_proc                             ;put back into run queue
750 ctsw_switch:
751         ;now it's time to switch to the new process that is about
752         ;to start running.
753         mov             r1, r2
754         call    d_que_proc                      ;remove new proc from run queue
755         call    restore_context
756         mov             r0, #time_running
757         movs.b  [r0], #0                        ;reset "time_running"
758         mov             r0, #current_proc
759         mov             [r0], r1                        ;set "current_proc" to new process
760         ;we may need to return to executing the process in user mode,
761         ;or we may need to jump to a location in the kernel (to continue
762         ;a system call).  If pt_wakup for this process is not zero, then
763         ;some kernel routine caused this process to sleep or be preempted
764         ;and wants to do more work before finally returning to the user
765         ;mode and running the program again.  Usually this is due to a
766         ;system call which needed to put the process to sleep while
767         ;waiting for I/O.
768         mov             r6, [r1+pt_wakeup]
769         setb    ea
770         beq             ctsw_return
771         movs.w  [r1+pt_wakeup], #0      ;don't do this again unless set again
772         jmp             [r6]
773 ctsw_return:
774         clr             request_context_switch
775         popu.b  ssel
776         popu.b  es
777         popu.b  ds
778         popu    r2, r3, r4
779     push        r2, r3, r4
780         popu    r0, r1, r2, r3, r4, r5, r6
781         reti
782
783 ctsw_queue_empty:
784         ;if we get here, there was no process waiting in the run
785         ;queue.  However, the currently running process isn't
786         ;normally in the run queue, so check if there was a process
787         ;running... if so reset its time slice and let it continue
788         mov             r0, #current_proc
789         mov             r1, [r0]
790         beq             ctsw_idle               ;idle if nothing was running
791         mov             r0, #time_running
792         movs.b  [r0], #0
793         jmp             ctsw_return
794         ;if we get here, the run queue is empty and there in no
795         ;process running now, so we just keep looping inside the
796         ;context switcher until something appears in the run queue
797 ctsw_idle:
798         ;need to make a special user-mode idle process... someday
799         ;that could put the processor into idle-mode to save power
800           ;mov  r4l, #' '
801           ;call cout
802         jmp             ctsw_retry
803
804
805
806
807 ;This "ksleep" routine causes the current process to sleep, afterwhich
808 ;it jumps to the context switcher, which tries to pick something else to
809 ;run, if anything is ready.  This code should only be called from
810 ;within the service code of system calls, which often times need to
811 ;make their calling process sleep.  R3 should have a value to stuff
812 ;into "pt_wait" for the process.  ksleep should be CALLed, because
813 ;it will arrange for the scheduler to return back to the kernel code
814 ;which called ksleep.  The call to ksleep should be followed by a
815 ;single NOP, for jump alignment.  Note, before calling ksleep some mechanism
816 ;to wake the sleeping process back up again must be in place... there
817 ;is nothing within ksleep which arranges for the process to become
818 ;awake again, though in the case of i/o the value in r3 should cause it
819 ;to wake up of the i/o interrupt routine checks for that value.
820
821 ksleep:
822         clr             ea
823         mov             r0, #current_proc
824         mov             r1, [r0]                                ;get pointer to process
825           ;cmp  r1, #$FE10
826           ;beq  ksleep_die
827         movs.w  [r0], #0                                ;no current process anymore
828         nop
829 ksleep_any:
830         clr             ea
831         mov             [r1+pt_wait], r3                ;record what we're waiting for
832         pop             r5, r6                                  ;get return address
833         adds    r6, #1                                  ;make sure return addr is word addr
834         and             r6, #$FFFE
835         mov             [r1+pt_wakeup], r6              ;set return addr when it wakes up
836         adds.b  [r1+pt_priority], #3    ;increase priority a bit
837         ;need to check here for overrange on user priority
838         mov             r0, #sleep_queue
839         call    en_que_proc                     ;add it to the sleep queue
840         setb    ea
841         call    save_context
842           ;cmp  r1, #$FE10
843           ;beq  ksleep_die
844         jmp             ctsw_begin                              ;scheduler will pick a new
845                                                                         ;process to run (or run idle loop)
846
847 ksleep_die:
848         jmp             die
849
850
851 syscall_sleep:
852         ;all system calls should run at the same priority as the
853         ;context switcher (level #1), but the code in paulmon2
854         ;sets the trap priority to #8... need to change that.
855         mov.b           pswh, #10000001q
856         pushu   r0, r1, r2, r3, r4, r5, r6              ;save registers
857         pop             r4, r5, r6                                              ;get pc and psw
858         pushu   r4, r5, r6                                              ;save them on user stack
859         pushu.b ds
860         pushu.b es
861         pushu.b ssel
862         ;r0 is number of ticks to sleep, from caller
863         mov             r4, #wake_process
864         mov             r2, #current_proc
865         mov             r5, [r2]        ;"wake_process" will need to know which proc
866         call    add_event
867         mov             r3, #0          ;no other routines will need to know it's sleeping
868         call    ksleep
869         nop
870         popu.b  ssel
871         popu.b  es
872         popu.b  ds
873         popu    r2, r3, r4
874     push        r2, r3, r4
875         popu    r0, r1, r2, r3, r4, r5, r6
876         reti
877
878         ;do_events is supposed to call here when the process is supposed
879         ;to wake up again... all we have to do it remove the process
880         ;from the sleep queue, add it to the run queue, and set the
881         ;software interrupt for the context switcher so it will select
882         ;a new process to run, and it will likely be this one since we
883         ;gave the priority a boost when it was put to sleep.
884         nop
885 wake_process:
886           ;mov  r4l, #'$'
887           ;call cout
888         ;r1 should point to event table entry created earlier
889         clr             ea
890         mov             r1, [r1+evt_arg1]       ;now r1 points to process entry
891         call    d_que_proc                      ;remove it from the sleep queue
892         mov             r0, #run_queue
893         call    en_que_proc                     ;add it to the run queue
894         setb    ea
895         ;should really test the priority of this waking process and
896         ;the priority of the currently running one, and only do the
897         ;context switch if the waking one has a higher priority
898         setb    request_context_switch
899         ret
900
901
902
903
904         ;transmit the character in r4l
905 syscall_cout:
906         mov.b           pswh, #10000001q
907         pushu   r0, r1, r2, r3, r4, r5, r6              ;save registers
908         pop             r3, r5, r6                                              ;get pc and psw
909         pushu   r3, r5, r6                                              ;save them on user stack
910         pushu.b ds
911         pushu.b es
912         pushu.b ssel
913 sc_cout_begin:
914         mov             r0, #tx0_buf_head
915         mov             r2, #tx0_buf_tail
916         clr             ea
917         mov             r1, [r0]
918         bne             sc_cout2
919         ;if we get here, the transmit buffer is empty and the interrupt
920         ;routine cleared the ti bit so no more interrupts are expected
921         setb    ti_0                    ;give the transmitter a kick-start
922         mov             r1, #tx0_buf
923         mov             [r0], r1                ;restore buffer pointers to useful values
924         mov             [r2], r1
925 sc_cout2:
926         adds    r1, #1
927         cjne    r1, #tx0_buf+tx0_buf_size, sc_cout3
928         mov             r1, #tx0_buf
929 sc_cout3:
930         cmp             r1, [r2]
931         bne             sc_cout4
932         ;if we get here, the buffer is full, so let's just wait
933         ;in a loop... eventually this routine will be replaced
934         ;with "write" which will put the process to sleep and set
935         ;the pt_wait so the context switcher will return here when
936         ;there is space available.  How do we save the variables
937         ;associated with the system call??  Push them onto the
938         ;user's stack for this process?
939         setb    ea
940         mov             r3, #tx0_buf
941         pushu   r4
942         call    ksleep
943         nop
944         popu    r4
945         br              sc_cout_begin   ;try again now that the intr i/o woke us up
946 sc_cout4:
947         mov.b   [r1], r4l               ;put data into buffer
948         mov             [r0], r1                ;update pointer
949         setb    ea
950         popu.b  ssel
951         popu.b  es
952         popu.b  ds
953         popu    r2, r3, r4
954     push        r2, r3, r4
955         popu    r0, r1, r2, r3, r4, r5, r6
956         reti
957
958
959
960
961
962
963
964
965         ;this function adds an event to the event queue.  These
966         ;parameters are required:
967         ;       r0      number of ticks until the event should occur
968         ;       r4      function to call when event happens (not zero!!)
969         ;       r5      optional argument
970         ;the event list uses delta time between each entry, so that
971         ;the timer interrupt will only have to deal with the front
972         ;of the queue... but it makes adding an entry here much more
973         ;difficult, but we only have to do this once whereas the
974         ;timer will have to look at the queue however many times the
975         ;evt_ticks value specifies.
976 add_event:
977         ;the first thing to do is find a empty place in the table
978         ;to store this event
979         mov             r1, #event_table
980         mov             r2, #max_num_event
981         clr             ea
982 aevt_find_slot:
983         mov             r3, [r1+evt_function]
984         beq             aevt_found_slot
985         add             r1, #evt_entry_size
986         djnz    r2, aevt_find_slot
987         ;if we get here there were no slots available, which is a
988         ;very bad thing...
989         jmp             kernel_panic
990 aevt_found_slot:
991         ;now that we've located the slot we'll use, let's dump the
992         ;data into it before making a mistake and reusing one of the
993         ;registers that are holding the input parameters
994         mov             [r1+evt_ticks], r0              ;store time value
995         mov             [r1+evt_function], r4   ;store function to be called
996         mov             [r1+evt_arg1], r5               ;store argument
997         ;now we've got to add this event into the linked list in
998         ;the correct time sequence position, and also subtract the
999         ;sum of all the previous evt_ticks values from this one.
1000         mov             r6, #event_queue
1001         mov             r2, [r6]
1002         bne             aevt_check_first
1003         ;if we get here, it's easy because the list is empty...
1004         mov             [r6], r1
1005         movs.w  [r1+evt_next], #0
1006         setb    ea
1007         ret
1008 aevt_check_first:
1009         ;it may be the case that our new event is supposed to happen
1010         ;before the events that are already on the queue
1011         cmp             r0, [r2+evt_ticks]
1012         bcc             aevt_search
1013         mov             [r6], r1
1014         mov             [r1+evt_next], r2
1015 aevt_adjust:
1016         ;now that we've added an entry (at r1), we need to adjust the
1017         ;evt_ticks values stored in the entry that comes after it.
1018         mov             r3, [r1+evt_next]               ;r3 points to next event after ours
1019         mov             r4, [r1+evt_ticks]
1020         sub             [r3+evt_ticks], r4
1021         setb    ea
1022         ret
1023 aevt_search:
1024         ;r4 is the adjusted value of ticks for our event as we progress
1025         ;through the linked list
1026         mov             r4, [r1+evt_ticks]
1027 aevt_search_loop:
1028     sub         r4, [r2+evt_ticks]
1029         mov             r3, [r2+evt_next]
1030         beq             aevt_add
1031         cmp             r4, [r3+evt_ticks]
1032         bcs             aevt_add
1033         mov             r2, r3
1034         jmp             aevt_search_loop
1035 aevt_add:
1036         ;r2 points to the event before the place where we will add
1037         ;and r3 points to the place after it in the list
1038         mov             [r2+evt_next], r1
1039         mov             [r1+evt_next], r3
1040         mov             [r1+evt_ticks], r4
1041         bne             aevt_adjust                             ;adjust rest of list if it exists
1042         setb    ea
1043         ret
1044
1045
1046
1047
1048 save_context:           ;process pointer in r1
1049         mov             r0, usp
1050         mov             [r1+pt_usp], r0                 ;save user stack pointer
1051         ;save any directly addressed memory range
1052         ;assigned to this process
1053         ret
1054
1055 restore_context:                ;process pointer in r1
1056         mov             r0, [r1+pt_usp]
1057         mov             usp, r0                         ;restore usp to value for new process
1058         ;copy contents of directly addresses memory
1059         ;back if necessary
1060         ret
1061
1062
1063
1064
1065 ;This routine removes a process (at r1) from a process queue
1066 ;(run/sleep).  This might be better as an assembler macro, but
1067 ;it's in a subroutine because of the difficulty of figuring out
1068 ;how to correctly manipulate the pointers of a doubly-linked list
1069 d_que_proc:
1070         mov             r6, [r1+pt_q_next]              ;<-- should be macro (begin)
1071         mov             r5, [r1+pt_q_prev]
1072         mov             [r5], r6
1073         mov             [r6+pt_q_prev], r5              ;<--- should be macro (end)
1074         ret
1075
1076 ;this routine takes a process (at r1) and adds it to a queue, where
1077 ;the location of the head of the queue is in r0.  This is more or
1078 ;less the opposite of "d_que_proc" except that the new process is
1079 ;always added to the head of the list.
1080 en_que_proc:
1081         mov             [r1+pt_q_prev], r0              ;<-- should be macro (begin)
1082         mov             r5, [r0]
1083         mov             [r1+pt_q_next], r5
1084         lea             r6, r1+pt_q_next
1085         mov             [r5+pt_q_prev], r6
1086         mov             [r0], r1                                ;<--- should be macro (end)
1087         ret
1088
1089 ;pt_usp                 equ             0               ;2 bytes, User Stack Pointer
1090 ;pt_q_next              equ             2               ;2 bytes, ptr to next in queue
1091 ;pt_q_prev              equ             4               ;2 bytes, ptr to prev in queue (+pt_q_next)
1092
1093
1094 ;this routine creates a new process, and returns a pointer to it
1095 ;in r1.  If the process can't be created, r1 is zero.  Data about
1096 ;the new process is required:
1097 ;       r4 = location of executable program
1098 ;       r5 = location for user stack (eventually malloc will do this)
1099
1100
1101 create_process:
1102         mov             r1, #proc_table
1103         mov             r2, #max_num_proc
1104 cproc_find_slot:
1105         mov             r0, [r1+pt_usp]
1106         beq             cproc_found_slot                ;ok to use this process entry
1107         add             r1, #pt_entry_size
1108         djnz    r2, cproc_find_slot
1109         ;if we get here, there is no more room in the process
1110         ;table so we can't create a new process.
1111         movs    r1, #0
1112         ret
1113 cproc_found_slot:
1114         push    r4, r5
1115         ;first initialize the various kernel data required
1116         mov             r0, #run_queue
1117         clr             ea
1118         call    en_que_proc                                     ;add it to the run queue
1119         mov.b   [r1+pt_priority], #100          ;start at priority 100
1120         movs.w  [r1+pt_wait], #0
1121         movs.w  [r1+pt_wakeup], #0
1122         ;next we need to set up the process's context
1123         pop             r4, r5
1124         sub             r5, #26                         ;advance r5 to context storage area
1125         mov             [r1+pt_usp], r5
1126         movs.w  [r5+], #0                       ;segment select is 0
1127         movs.w  [r5+], #0                       ;es is 0
1128         movs.w  [r5+], #0                       ;ds is 0
1129         movs.w  [r5+], #0                       ;psw is zero (user mode)
1130         movs.w  [r5+], #0                       ;run is page zero only (for now)
1131         mov             [r5+], r4                       ;set return addr to beginning
1132         ;could create initial values for the registers here...
1133         setb    ea
1134         ret
1135
1136 ;user stack while in kernel mode:
1137 ; byte
1138 ; offset   Variable
1139 ;       -2              r6
1140 ;       -4              r5
1141 ;       -6              r4
1142 ;       -8              r3
1143 ;       -10             r2
1144 ;       -12             r1
1145 ;       -14             r0
1146 ;       -16             program counter (lsw)
1147 ;       -18             program counter (msb)
1148 ;       -20             program status word
1149 ;       -22             ds
1150 ;       -24             es
1151 ;       -26             ssel            <-- usp points here
1152
1153
1154 poweron:
1155         mov             r6, #$F000
1156 clear_memory_loop:
1157         movs.w  [r6+], #0
1158         cjne    r6, #0, clear_memory_loop
1159           setb  p1.6
1160           setb  p1.7
1161
1162         mov             r7, #sys_stack                          ;set sys stack pointer
1163         clr             ea
1164         ;initialize serial port buffers
1165         mov             r0, #rx0_buf_head
1166         mov.w   [r0], #rx0_buf
1167         mov             r0, #rx0_buf_tail
1168         mov.w   [r0], #rx0_buf
1169         mov             r0, #tx0_buf_head
1170         movs.w  [r0], #0
1171         mov             r0, #tx0_buf_tail
1172         movs.w  [r0], #0
1173         mov             r0, #rx1_buf_head
1174         mov.w   [r0], #rx1_buf
1175         mov             r0, #rx1_buf_tail
1176         mov.w   [r0], #rx1_buf
1177         mov             r0, #tx1_buf_head
1178         movs.w  [r0], #0
1179         mov             r0, #tx1_buf_tail
1180         movs.w  [r0], #0
1181         ;clear serial port flags
1182         clr             ri_0
1183         clr             ti_0
1184         clr             ri_1
1185         clr             ti_1
1186         ;initialize interrupts
1187         mov.b   swe, #255                               ;allow all software interrupts
1188     mov.b   ipa0, #10010000q            ;priority #9: timer0 interrupt
1189         mov.b   ipa4, #10011001q                ;priority #9: uart0 rx and tx interrupts
1190         mov.b   ipa5, #10011001q                ;priority #9: uart1 rx and tx interrupts
1191         mov.b   ieh, #00001111q                 ;enable uart interrupts
1192         ;set up timer 0 to 16-bit auto reload (10 ms)
1193         clr             et0                                             ;no timer 0 interrupt yet
1194         clr             tr0                                             ;stop timer 0
1195         clr             tf0
1196         mov.b   rtl0, #low 37798                ;set 10 ms rate
1197         mov.b   rth0, #high 37798
1198         movs.b  tl0, #0                                 ;zero timer
1199         movs.b  th0, #0
1200         and.b   tmod, #11110000q                ;set for 16 bit auto reload
1201
1202
1203     ;now set up the variables so we're in idle mode
1204         mov             r0, #current_proc
1205         movs.w  [r0], #0                                        ;set no process running
1206         mov             r0, #run_queue
1207         movs.b  [r0], #0                                        ;all queues empty
1208         mov             r0, #sleep_queue
1209         movs.b  [r0], #0
1210         mov             r0, #time_running
1211         movs.b  [r0], #0
1212         ;initialize pt_usp of all processes to zero, so that
1213         ;there won't appear to be any processes
1214
1215         nop
1216 clr_proc_tbl:
1217         mov             r1, #proc_table
1218         mov             r2, #max_num_proc
1219 clr_proc_tbl_loop:
1220         movs.w  [r1+pt_usp], #0
1221         add             r1, #pt_entry_size
1222         djnz    r2, clr_proc_tbl_loop
1223 clr_events:
1224         mov             r1, #event_table
1225         mov             r2, #max_num_event
1226 clr_events_loop:
1227         movs.w  [r1+evt_function], #0
1228         add             r1, #evt_entry_size
1229         djnz    r2, clr_events_loop
1230
1231 ;now create process table entries for the test programs
1232         mov             r4, #program1
1233         mov             r5, #$F000
1234         call    create_process          ;create process for program1
1235         mov             r4, #program2
1236         mov             r5, #$EC00
1237         call    create_process          ;create process for program2
1238         mov             r4, #program3
1239         mov             r5, #$E800
1240         ;call   create_process          ;create process for program3
1241
1242
1243
1244         ;now how can we get into user mode for the first time???
1245         ;normally the kernel is entered by an interrupt (hardware
1246         ;or software) or a trap (sys call), so we get back to a
1247         ;user program with reti... but the first time has to be
1248         ;handled a bit differently
1249         mov             r1, #proc_table
1250         call    d_que_proc                      ;remove new proc to run from run queue
1251         call    restore_context
1252         mov             r0, #time_running
1253         movs.b  [r0], #0                        ;reset "time_running"
1254         mov             r0, #current_proc
1255         mov             [r0], r1                        ;set "current_proc" to new process
1256         popu.b  ssel
1257         popu.b  es
1258         popu.b  ds
1259         popu    r0, r1, r2                      ;r0=psw, r1=pc_high, r2=pc_low
1260         popu    r3, r4, r5                      ;extract r0/r2 reg from stack
1261         popu    r3, r4, r5, r6          ;extract r3/r6 reg from stack
1262         mov             cs, r1l                         ;set code segment
1263         clr             tf0                                     ;clear timer0 flag
1264         setb    tr0                                     ;start timer0
1265         setb    et0                                     ;enable timer0 interrupt
1266         setb    ea
1267         mov             pswl, r0l
1268         mov             pswh, r0h                       ;this makes the switch to user mode
1269                                                                 ;and lower priority to 0 (from max)
1270         jmp             [r2]                            ;jump to the user program
1271
1272
1273
1274
1275 kernel_panic:
1276 die:
1277         clr             ea
1278         clr             ri_0
1279 die_loop:
1280         jnb             ri_0, die_loop
1281         clr             ri_0
1282         jmp             $120            ;reboot!
1283
1284
1285
1286 ;unix system calls: (which ones to try first??)
1287 ;process mgt: fork, exec/execve, exit, wait/wait4
1288 ;file i/o: open, read, write, select, ioclt, lseek, close, fcntl
1289 ;signals: kill, signal, alarm, pause
1290 ;pipes: pipe, dup/dup2
1291 ;network/ipc: socket, bind, connect/listen/accept, sendto, recvfrom
1292 ;network/ipc: socketpair, getsockname/getpeername, setsockopt/getsockopt
1293 ;filesystems: chroot/chdir, link, unlink, mkdir, rmdir,
1294 ;filesystems: chown/chmod, stat, rename, truncate
1295
1296
1297
1298
1299 ;**************************************************************
1300 ;**                                                          **
1301 ;**                     User Programs                        **
1302 ;**                                                          **
1303 ;**************************************************************
1304
1305
1306
1307 cout:
1308         trap    #trap_cout
1309         ret
1310
1311 newline:
1312         push    r4l
1313         mov             r4l, #13
1314         call    cout
1315         mov             r4l, #10
1316         call    cout
1317         pop             r4l
1318         ret
1319
1320 pstr:      PUSH    r4
1321 pstr1:     MOVC    r4l,[r6+]
1322            beq     pstr2
1323            AND     R4L,#0x7F
1324            CALL    cout
1325            BR      pstr1
1326 pstr2:     POP     r4
1327            RET
1328
1329 phex:
1330 phex8:
1331            PUSH.B  acc
1332            RL.B R4L,#4
1333            AND.B   R4L,#15
1334            ADD.B   R4L,#246
1335            BCC     phex_b
1336            ADD.B   R4L,#7
1337 phex_b:    ADD.B   R4L,#58
1338            CALL    cout
1339            POP.B   acc
1340 phex1:     PUSH.B  acc
1341            AND.B   R4L,#15
1342            ADD.B   R4L,#246
1343            BCC     phex_c
1344            ADD.B   R4L,#7
1345 phex_c:    ADD.B   R4L,#58
1346            CALL    cout
1347            POP.B   acc
1348            RET
1349
1350 phex16:
1351            PUSH.B  acc
1352            MOV.B   R4L,dph
1353            CALL    phex
1354            MOV.B   R4L,dpl
1355            CALL    phex
1356            POP.B   acc
1357            RET
1358
1359
1360
1361
1362
1363         ;program #1 prints "Paul" to serial port #0, with a
1364         ;fairly long delay between each printing
1365 program1:
1366         mov             r6, #str_paul
1367         call    pstr
1368         mov             r0, #130
1369         trap    #trap_delay
1370         jmp             program1
1371
1372 str_paul: db "Paul",0
1373
1374 pgm2_speed              equ             10              ;number of ticks between led blinks
1375
1376         nop
1377         ;program #2 blinks the LEDs and prints a "." to the
1378         ;serial port #0 after every sequence of blinks.
1379 program2:
1380         or.b    p1cfga, #$C0                    ;p1.6 and p1.7 outputs
1381         or.b    p1cfgb, #$C0
1382 pg2_loop:
1383         ;br             pg2_skip_blink
1384         setb    p1.6
1385         setb    p1.7
1386         mov             r0, #pgm2_speed
1387         trap    #trap_delay
1388         clr             p1.6
1389         setb    p1.7
1390         mov             r0, #pgm2_speed
1391         trap    #trap_delay
1392         setb    p1.6
1393         setb    p1.7
1394         mov             r0, #pgm2_speed
1395         trap    #trap_delay
1396         setb    p1.6
1397         clr             p1.7
1398         mov             r0, #pgm2_speed
1399         trap    #trap_delay
1400         setb    p1.6
1401         setb    p1.7
1402
1403 pg2_skip_blink:
1404         mov             r4l, #'.'
1405         call    cout
1406         br              pg2_loop
1407
1408 program3:
1409         mov             r4l, #'3'
1410         call    cout
1411         ;mov            r6, #test_str
1412         ;call   pstr
1413         jmp             program3
1414
1415
1416 test_str: db "This_is_a_test", 0
1417
1418
1419
1420
1421
1422
1423
1424
1425