xa51, work in progress
[fw/sdcc] / as / xa51 / mt.xa
diff --git a/as/xa51/mt.xa b/as/xa51/mt.xa
deleted file mode 100644 (file)
index dfa5ae9..0000000
+++ /dev/null
@@ -1,1425 +0,0 @@
-
-;$include xa-g3.equ    ;will implement included later on
-
-
-; Include file for XA-G3 SFR Definitions
-; Philips Semiconductors. Revision 1.8, 1/21/97
-; $nolist              ;will implement this later on
-
-; Register equates.
-
-acc     reg     R4L          ; for translated 80C51 code
-dpl     reg     R6L          ; for translated 80C51 code
-dph     reg     R6H          ; for translated 80C51 code
-sp      reg     R7           ; for translated 80C51 code
-
-
-; SFR byte and bit definitions.
-
-bcr     sfr     46ah
-btrh    sfr     469h
-btrl    sfr     468h
-cs      sfr     443h
-ds      sfr     441h
-es      sfr     442h
-
-ieh     sfr     427h
-eri0    bit     ieh.0
-eti0    bit     ieh.1
-eri1    bit     ieh.2
-eti1    bit     ieh.3
-
-iel     sfr     426h
-ex0     bit     iel.0
-et0     bit     iel.1
-ex1     bit     iel.2
-et1     bit     iel.3
-et2     bit     iel.4
-ea      bit     iel.7
-
-ipa0    sfr     4a0h
-ipa1    sfr     4a1h
-ipa2    sfr     4a2h
-ipa4    sfr     4a4h
-ipa5    sfr     4a5h
-
-p0      sfr     430h
-p1      sfr     431h
-p2      sfr     432h
-p3      sfr     433h
-p0cfga  sfr     470h
-p1cfga  sfr     471h
-p2cfga  sfr     472h
-p3cfga  sfr     473h
-p0cfgb  sfr     4f0h
-p1cfgb  sfr     4f1h
-p2cfgb  sfr     4f2h
-p3cfgb  sfr     4f3h
-
-pcon    sfr     404h
-idl     bit     pcon.0
-pd      bit     pcon.1
-
-pswh    sfr     401h
-im0     bit     pswh.0
-im1     bit     pswh.1
-im2     bit     pswh.2
-im3     bit     pswh.3
-rs0     bit     pswh.4
-rs1     bit     pswh.5
-tm      bit     pswh.6
-sm      bit     pswh.7
-
-pswl    sfr     400h
-z       bit     pswl.0
-n       bit     pswl.1
-v       bit     pswl.2
-ac      bit     pswl.6
-cy      bit     pswl.7
-
-psw51   sfr     402h
-
-rth0    sfr     455h
-rth1    sfr     457h
-rtl0    sfr     454h
-rtl1    sfr     456h
-
-s0con   sfr     420h
-ri_0    bit     s0con.0
-ti_0    bit     s0con.1
-rb8_0   bit     s0con.2
-tb8_0   bit     s0con.3
-ren_0   bit     s0con.4
-sm2_0   bit     s0con.5
-sm1_0   bit     s0con.6
-sm0_0   bit     s0con.7
-scon    sfr     420h         ; duplicate label for translated 80C51 code.
-ri      bit     scon.0       ; duplicate label for translated 80C51 code.
-ti      bit     scon.1       ; duplicate label for translated 80C51 code.
-rb8     bit     s0con.2      ; duplicate label for translated 80C51 code.
-tb8     bit     s0con.3      ; duplicate label for translated 80C51 code.
-ren     bit     s0con.4      ; duplicate label for translated 80C51 code.
-sm2     bit     s0con.5      ; duplicate label for translated 80C51 code.
-sm1     bit     s0con.6      ; duplicate label for translated 80C51 code.
-sm0     bit     s0con.7      ; duplicate label for translated 80C51 code.
-
-s0stat  sfr     421h
-stint0  bit     s0stat.0
-oe0     bit     s0stat.1
-br0     bit     s0stat.2
-fe0     bit     s0stat.3
-
-s0buf   sfr     460h
-sbuf    sfr     460h         ; duplicate label for translated 80C51 code.
-s0addr  sfr     461h
-s0aden  sfr     462h
-
-s1con   sfr     424h
-ri_1    bit     s1con.0
-ti_1    bit     s1con.1
-rb8_1   bit     s1con.2
-tb8_1   bit     s1con.3
-ren_1   bit     s1con.4
-sm2_1   bit     s1con.5
-sm1_1   bit     s1con.6
-sm0_1   bit     s1con.7
-
-s1stat  sfr     425h
-stint1  bit     s1stat.0
-oe1     bit     s1stat.1
-br1     bit     s1stat.2
-fe1     bit     s1stat.3
-
-s1buf   sfr     464h
-s1addr  sfr     465h
-s1aden  sfr     466h
-
-scr     sfr     440h
-
-ssel    sfr     403h
-r0seg   bit     ssel.0
-r1seg   bit     ssel.1
-r2seg   bit     ssel.2
-r3seg   bit     ssel.3
-r4seg   bit     ssel.4
-r5seg   bit     ssel.5
-r6seg   bit     ssel.6
-eswen   bit     ssel.7
-
-swe     sfr     47ah
-swr     sfr     42ah
-swr1    bit     swr.0
-swr2    bit     swr.1
-swr3    bit     swr.2
-swr4    bit     swr.3
-swr5    bit     swr.4
-swr6    bit     swr.5
-swr7    bit     swr.6
-
-swe1    equ     00000001q    ; bit masks for software interrupt enables.
-swe2    equ     00000010q
-swe3    equ     00000100q
-swe4    equ     00001000q
-swe5    equ     00010000q
-swe6    equ     00100000q
-swe7    equ     01000000q
-
-t2con   sfr     418h
-cprl2   bit     t2con.0
-ct2     bit     t2con.1
-tr2     bit     t2con.2
-exen2   bit     t2con.3
-tclk0   bit     t2con.4
-rclk0   bit     t2con.5
-tclk    bit     t2con.4      ; duplicate label for translated 80C51 code.
-rclk    bit     t2con.5      ; duplicate label for translated 80C51 code.
-exf2    bit     t2con.6
-tf2     bit     t2con.7
-
-t2mod   sfr     419h
-dcen    bit     t2mod.0
-t2oe    bit     t2mod.1
-t2rd    bit     t2mod.2
-tclk1   bit     t2mod.4
-rclk1   bit     t2mod.5
-
-th2     sfr     459h
-tl2     sfr     458h
-t2caph  sfr     45bh
-t2capl  sfr     45ah
-
-tcon    sfr     410h
-it0     bit     tcon.0
-ie0     bit     tcon.1
-it1     bit     tcon.2
-ie1     bit     tcon.3
-tr0     bit     tcon.4
-tf0     bit     tcon.5
-tr1     bit     tcon.6
-tf1     bit     tcon.7
-
-th0     sfr     451h
-th1     sfr     453h
-tl0     sfr     450h
-tl1     sfr     452h
-tmod    sfr     45ch
-tstat   sfr     411h
-t0oe    bit     tstat.0
-t0rd    bit     tstat.1
-t1oe    bit     tstat.2
-t1rd    bit     tstat.3
-
-wdcon   sfr     41fh
-wdtof   bit     wdcon.1
-wdrun   bit     wdcon.2
-pre0    bit     wdcon.5
-pre1    bit     wdcon.6
-pre2    bit     wdcon.7
-
-wdl     sfr     45fh
-wfeed1  sfr     45dh
-wfeed2  sfr     45eh
-
-
-; Port pin name definitions.
-
-a4d0    bit     P0.0
-a5d1    bit     P0.1
-a6d2    bit     P0.2
-a7d3    bit     P0.3
-a8d4    bit     P0.4
-a9d5    bit     P0.5
-a10d6   bit     P0.6
-a11d7   bit     P0.7
-
-a0      bit     P1.0
-wrh     bit     P1.0
-a1      bit     P1.1
-a2      bit     P1.2
-a3      bit     P1.3
-rxd1    bit     P1.4
-txd1    bit     P1.5
-t2      bit     P1.6
-t2ex    bit     P1.7
-
-a12d8   bit     P2.0
-a13d9   bit     P2.1
-a14d10  bit     P2.2
-a15d11  bit     P2.3
-a16d12  bit     P2.4
-a17d13  bit     P2.5
-a18d14  bit     P2.6
-a19d15  bit     P2.7
-
-rxd0    bit     P3.0
-txd0    bit     P3.1
-int0    bit     P3.2
-int1    bit     P3.3
-t0      bit     P3.4
-t1      bit     P3.5
-busw    bit     P3.5
-wrl     bit     P3.6
-rd      bit     P3.7
-
-; End of XA-G3 SFR definitions.
-;$list         ;handle this later on
-
-
-
-
-trap_delay             equ             0
-trap_cout              equ             1
-
-       org             $8040           ;paulmon2 will jump here on trap #0
-       jmp             syscall_sleep
-       org             $8044           ;paulmon2 will jump here on trap #1
-       jmp             syscall_cout
-
-       org             $8084           ;paulmon2 will jump here on timer0 interrupt
-       jmp             timer0
-
-       org             $80A0           ;paulmon2 will jump here on uart0 rx interrupt
-       jmp             uart0_recv
-       org             $80A4           ;paulmon2 will jump here on uart0 tx interrupt
-       jmp             uart0_xmit
-       org             $80A8           ;paulmon2 will jump here on uart1 rx interrupt
-       jmp             uart1_recv
-       org             $80AC           ;paulmon2 will jump here on uart1 tx interrupt
-       jmp             uart1_xmit
-
-       org             $8100           ;paulmon2 will jump here on software int1
-       jmp             context_switch
-       org             $8104           ;paulmon2 will jump here on software int2
-       jmp             do_events
-
-       org             $8120
-       jmp             poweron
-
-request_do_events                      bit             swr2
-request_context_switch         bit             swr1
-
-max_num_ticks  equ             7               ;max time a process can run if other
-                                                               ;processes are waiting in the run queue
-
-
-;this memory allocation should be done with "ds" directives to
-;save space, but for now it's done with "equ" with lots of gaps,
-;so that things will stay put and aligned on 16 byte boundries
-;where they can be easily viewed with the paulmon2 hex dump.  When
-;the kernel code is more mature this will have to be changed.
-
-sys_stack              equ             $FB00
-
-rx0_buf_head   equ             $FB00           ;2 bytes
-rx0_buf_tail   equ             $FB02           ;2 bytes
-rx0_buf_size   equ             $20
-rx0_buf                        equ             $FB10           ;rx0_buf_size bytes
-
-rx1_buf_head   equ             $FB40           ;2 bytes
-rx1_buf_tail   equ             $FB42           ;2 bytes
-rx1_buf_size   equ             $20
-rx1_buf                        equ             $FB50           ;rx1_buf_size bytes
-
-tx0_buf_head   equ             $FB80           ;2 bytes
-tx0_buf_tail   equ             $FB82           ;2 bytes
-tx0_buf_size   equ             $20
-tx0_buf_threshold      equ     9
-tx0_buf                        equ             $FB90           ;tx0_buf_size bytes
-
-tx1_buf_head   equ             $FBC0           ;2 bytes
-tx1_buf_tail   equ             $FBC2           ;2 bytes
-tx1_buf_size   equ             $20
-tx1_buf_threshold      equ     9
-tx1_buf                        equ             $FBD0           ;tx1_buf_size bytes
-
-
-current_proc   equ             $FEF0   ;2 bytes, ptr to proc_table entry of
-                                                               ;currently running process, 0 if none
-run_queue              equ             $FEF2   ;2 bytes, pointer to a linked list
-                                                               ;of processes waiting to run
-sleep_queue            equ             $FEF4   ;2 bytes, pointer to a linked list
-                                                               ;of sleeping processes
-time_running   equ             $FEF6   ;1 byte, number of ticks that the
-                                                               ;current process has run.
-event_queue            equ             $FCF0   ;2 bytes, pointer to a linked list
-                                                               ;of pending events (event_table)
-
-max_num_proc   equ             14
-proc_table             equ             $FE00   ;(max_num_proc*pt_entry_size) bytes
-pt_entry_size  equ             16              ;16 bytes per table entry
-pt_usp                 equ             0               ;2 bytes, User Stack Pointer
-pt_q_next              equ             2               ;2 bytes, ptr to next in queue
-pt_q_prev              equ             4               ;2 bytes, ptr to prev in queue (+pt_q_next)
-pt_wait                        equ             6               ;2 bytes, what are we waiting for?
-pt_wakeup              equ             8               ;2 bytes, where do we go on wakeup?
-pt_prog_addr   equ             10              ;2 bytes, location of program header
-pt_prog_cs             equ             12              ;1 byte, code segment of program header
-pt_priority            equ             13              ;1 byte, execution priority
-pt_pid                 equ             14              ;1 byte, id num for this process
-
-       ;need to define a program header, which will include various
-       ;info about the program, including the req'd stack space, max
-       ;expect memory to malloc, range of directly addressed memory
-       ;(which must be saved during a context switch), max number of
-       ;open file descriptors reqd, etc.
-
-max_num_event  equ             15              ;(max_num_proc*2)
-event_table            equ             $FC00   ;(max_num_event*evt_entry_size)
-evt_entry_size equ             16              ;8 bytes per event entry
-evt_ticks              equ             0               ;# of ticks until event (delta from prev)
-evt_next               equ             2               ;pointer to next event in list
-evt_function   equ             4               ;place to call (0 if evt slot unused)
-evt_arg1               equ             6               ;optional argument
-
-;the file descriptors will be allocated before the stack in the
-;block of memory which is allocated when the process is created.
-;each individual process can specify the max number of file
-;descriptors that it will require
-
-file_desc_table        equ             $FE80   ;128 bytes
-fd_entry_size  equ             7               ;7 bytes per table entry
-fd_offset              equ             0               ;4 bytes, offset in file
-fd_flags               equ             4               ;1 byte, read/write/append
-fd_routines            equ             5               ;2 bytes, ptr to i/o routines
-
-
-;single character debug symbols:
-;  space       context switcher is idle
-;    *      contect switcher entered
-;    #         timer interrupt (normal)
-;    %         timer interrupt requested context switch
-;    !      timer interrupt requested event service
-;       @              entered event service interrupt routine
-;    ^         event service function called
-;       ~      leaving event service interrupt routine
-
-;this timer interrupt routine is responsible for monitoring the
-;time that the current process has been running and adjusting the
-;process priorities accordingly.  It also checks if any events
-;in the event queue need to be processed.  This code runs at a
-;high cpu priority and it runs often, so it should get done as
-;quickly as possible... if anything lengthy might need to be done,
-;a software interrupt (low priority) should be set, so it can be
-;done later on without blocking other important interrupts, such
-;as low-level i/o.
-
-timer0:
-       push    r0, r1, r2, r3, r4, r5, r6
-       ;other stuff can be added here, such as maintaining a
-       ;system clock...
-         ;mov  r4l, #'#'
-check_events:
-       mov             r0, #event_queue
-       clr             ea
-       mov             r1, [r0]
-       beq             ckevt_end               ;no events if queue is empty
-       mov             r2, [r1+evt_ticks]
-       beq             ckevt_do_em
-       ;if we get here, there are events pending but it's not
-       ;time to do any of them yet, so we'll just decrement the
-       ;ticks of the first one, which will decrement the effective
-       ;time for all of them since they use a delta-time between
-       ;each entry in the linked list
-       adds.w  [r1+evt_ticks], #-1
-       br              ckevt_end
-ckevt_do_em:
-       ;if we get here, there is at least one event which needs
-       ;to be serviced... but we won't do that here, just set the
-       ;software interrupt so it can be handled by "do_event"
-       ;setb   request_do_events
-         ;mov  r4l, #'!'
-         ;call cout
-       ;call   do_events               ;not nice, but sw int priority not working
-       setb    request_do_events
-ckevt_end:
-       setb    ea
-       nop
-schedule:
-       mov             r0, #current_proc
-       clr             ea
-       mov             r1, [r0]
-       beq             sch_end                 ;don't bother if no process is running
-       sub.b   [r1+pt_priority], #1    ;decrease priority by one
-       bcc     sch_priority_ok
-       movs.b  [r1+pt_priority], #0    ;but don't go less than zero
-sch_priority_ok:
-       mov             r0, #time_running
-       mov             r3l, [r0]
-       adds    r3l, #1                         ;increment time_running
-       mov             [r0], r3l
-       cmp             r3l, #max_num_ticks
-       bl              sch_end
-       ;if we get here, the currently running process is has been
-       ;using the cpu for at least the max number ticks, so it's
-       ;time to force it to take a rest and let someone else have
-       ;a chance.
-       mov             r0, #run_queue
-       mov             r1, [r0]
-       beq             sch_end         ;don't preempt if nothing in run queue
-         ;mov  r4l, #'%'
-       setb    request_context_switch          ;make something else run
-sch_end:
-       setb    ea
-         ;cmp  r4l, #'!'
-         ;beq  t0_skip_print
-         ;call cout
-       nop
-t0_skip_print:
-       pop             r0, r1, r2, r3, r4, r5, r6
-       reti
-
-
-       ;this routine actually calls the event handlers for all
-       ;events which are supposed to happen NOW.  The main timer
-       ;routine must decrement the time of the events and arrange
-       ;for this code to be run when any events are supposed to
-       ;happen.  The event handler gets the address of the event
-       ;in r1.
-do_events:
-       push    r0, r1, r2, r3, r4, r5, r6
-do_events_begin:
-         ;mov  r4l, #'@'
-         ;call cout
-doevt_loop:
-       mov             r0, #event_queue
-       mov             r1, [r0]
-       beq             doevt_end               ;no events to do if queue is empty
-       mov             r2, [r1+evt_ticks]
-       bne             doevt_end               ;done if event is in the future
-       mov             r2, [r1+evt_next]
-       mov             [r0], r2                ;remove event from queue
-       mov             r2, [r1+evt_function]
-       movs.w  [r1+evt_function], #0
-         ;mov  r4l, #'^'
-         ;call cout
-       call    [r2]                    ;call the event handler specified
-       br              doevt_loop
-doevt_end:
-         ;mov  r4l, #'~'
-         ;call cout
-       clr             request_do_events
-       pop             r0, r1, r2, r3, r4, r5, r6
-       reti
-
-
-
-;interrupt receive routine for uart #0
-uart0_recv:
-       push    r0, r1, r2, r5, r6
-       clr             ri_0
-       mov             r5l, s0buf
-       mov             r2, #rx0_buf
-       mov             r0, #rx0_buf_head
-       mov             r6, #rx0_buf_tail
-       mov             r1, [r0]
-       adds    r1, #1
-       cjne    r1, #rx0_buf+rx0_buf_size, uart_recv_check2
-       mov             r1, #rx0_buf
-       br              uart_recv_check2
-;interrupt receive routine for uart #1
-uart1_recv:
-       push    r0, r1, r2, r5, r6
-       clr             ri_1
-       mov             r5l, s1buf
-       mov             r2, #rx1_buf
-       mov             r0, #rx1_buf_head
-       mov             r6, #rx1_buf_tail
-       mov             r1, [r0]
-       adds    r1, #1
-       cjne    r1, #rx1_buf+rx1_buf_size, uart_recv_check2
-       mov             r1, #rx1_buf
-;this remaining code is shared by both uart receive routines
-uart_recv_check2:
-       cmp             r1, [r6]
-       bne             uart_recv_ok
-       ;if we get here, the buffer is full, discard data
-       call    wakeup_intr_io
-       pop             r0, r1, r2, r5, r6
-       reti
-uart_recv_ok:
-       mov.b   [r1], r5l               ;store byte into buffer
-       mov             [r0], r1                ;update buffer pointer
-       ;perhaps there should be a way for us to know how much data a
-       ;sleeping process wants to extract from the buffer, so we can
-       ;avoid waking it up until there is at least that much data.
-       call    wakeup_intr_io
-       pop             r0, r1, r2, r5, r6
-       reti
-
-;interrupt transmit routine for uart #0
-uart0_xmit:
-       push    r0, r1, r2, r5, r6
-       clr             ti_0
-       mov             r0, #tx0_buf_tail
-       mov             r2, #tx0_buf_head
-       mov             r1, [r0]
-       cmp             r1, [r2]
-       beq             uart_no_xmit
-       adds    r1, #1
-       cjne    r1, #tx0_buf+tx0_buf_size, uart0_xmit2
-       mov             r1, #tx0_buf
-uart0_xmit2:
-       mov.b   s0buf, [r1]
-       mov             [r0], r1
-       ;now figure out if we want to wake up processes which are
-       ;waiting to put more data into this buffer
-       mov             r1, [r2]
-       sub             r1, [r0]
-       bcc             uart0_xmit3
-       add             r1, #tx0_buf_size
-uart0_xmit3:
-       cmp             r1, #(tx0_buf_threshold)
-       bcc             uart0_xmit_end          ;don't wake proc unless over threshold
-       mov             r2, #tx0_buf
-       call    wakeup_intr_io
-uart0_xmit_end:
-       pop             r0, r1, r2, r5, r6
-       reti
-;interrupt transmit routine for uart #1
-uart1_xmit:
-       push    r0, r1, r2, r5, r6
-       clr             ti_1
-       mov             r0, #tx1_buf_tail
-       mov             r2, #tx1_buf_head
-       mov             r1, [r0]
-       cmp             r1, [r2]
-       beq             uart_no_xmit
-       adds    r1, #1
-       cjne    r1, #tx1_buf+tx1_buf_size, uart1_xmit2
-       mov             r1, #tx1_buf
-uart1_xmit2:
-       mov.b   s1buf, [r1]
-       mov             [r0], r1
-       ;now figure out if we want to wake up processes which are
-       ;waiting to put more data into this buffer
-       mov             r1, [r2]
-       sub             r1, [r0]
-       bcc             uart1_xmit3
-       add             r1, #tx1_buf_size
-uart1_xmit3:
-       cmp             r1, #tx1_buf_threshold
-       bcc             uart1_xmit_end          ;don't wake proc unless over threshold
-       mov             r2, #tx1_buf
-       call    wakeup_intr_io
-uart1_xmit_end:
-       pop             r0, r1, r2, r5, r6
-       reti
-
-;this is shared by both transmit interrupt routines
-uart_no_xmit:
-       ;if we got here, there is no data waiting to transmit
-       ;load the _head pointer with 0, so a routine which loads
-       ;data into the buffer will know to set the ti bit.
-       movs.w  [r2], #0
-       pop             r0, r1, r2, r5, r6
-       reti
-
-
-;This routine wakes up any sleeping processes that are waiting
-;for i/o in the buffer pointed to by r2.  Interrupt routines
-;should call here after doing i/o one their buffers, so that
-;any processes which are waiting for that i/o will be awakened.
-
-wakeup_intr_io:
-       mov             r0, #sleep_queue
-       mov             r1, [r0]
-       beq             wkintio_empty   ;sleep_queue is empty
-       clr             ea                      ;disable interrupts while we look at the queue
-wkintio_loop:
-       cmp             [r1+pt_wait], r2
-       beq             wkintio_wakeup  ;wake proc if waiting for i/o on this buffer
-       mov             r1, [r1+pt_q_next]
-       bne             wkintio_loop
-       setb    ea                              ;ok for other interrupts now
-wkintio_empty:
-       ret
-wkintio_wakeup:
-       ;if we get here, this sleeping processes was waiting for
-       ;i/o on the buffer pointed to by r2, so let's wake it up.
-       ;d_que_proc: (remove from sleep queue)
-       mov             r6, [r1+pt_q_next]
-       push    r6                                              ;save ptr to next in sleep queue
-       mov             r5, [r1+pt_q_prev]
-       mov             [r5], r6
-       mov             [r6+pt_q_prev], r5
-       ;en_que_proc: (add to run queue)
-       mov             r0, #run_queue
-       mov             [r1+pt_q_prev], r0
-       mov             r5, [r0]
-       mov             [r1+pt_q_next], r5
-       lea             r6, r1+pt_q_next
-       mov             [r5+pt_q_prev], r6
-       mov             [r0], r1
-       adds.b  [r1+pt_priority], #5    ;give it a bit of priority boost...
-       ;need to check here for overrange on user priority
-       setb    request_context_switch  ;get it running asap.
-       ;continue looking for processes waiting on this i/o buffer,
-       ;because there may be more than one, and we need to get them
-       ;all into the run queue so that the context switcher can choose
-       ;the one with the highest priority.
-       pop             r1
-       cmp             r1, #0
-       bne             wkintio_loop
-       setb    ea
-       ret
-
-
-
-
-
-
-
-;**************************************************************
-
-
-
-
-
-
-;The context switcher is responsible for figuring out which process
-;is supposed to run next (looks at pt_priority) and if a context
-;change is required this is where it will happen.  If any
-;interrupt driven part of the kernel wants to make a particular
-;process run, it must change the priority for that process and
-;then set the software interrupt to run the context switcher later.
-
-;For system calls that want to make their calling process sleep,
-;they should jump to the ksleep routine, which will jump to
-;"ctsw_begin" to allow something else to run.
-
-;Note: the context switcher doesn't enforce preemptive multitasking...
-;a timer routine must count how long the currently running process
-;has be running since a context switch ("time_running" variable)
-;and if it's being a hog the timer routine that detects it must
-;lower the priority and set the software interrupt to cause this
-;context switcher to make a different process run.  The context
-;switcher also depends on interrupt routines to change the
-;"pt_priority" field of each process table entry, all the context
-;switcher does is pick the process with highest priority.  The
-;currently running process is always switched out if there is
-;something in the run queue, even if the item in the run queue
-;has a lower priority.
-
-
-context_switch:
-       pushu   r0, r1, r2, r3, r4, r5, r6              ;save registers
-       pop             r2, r3, r4                                              ;get pc and psw
-       pushu   r2, r3, r4                                              ;save them on user stack
-       pushu.b ds
-       pushu.b es
-       pushu.b ssel
-
-
-ctsw_begin:
-         ;mov  r4l, #'*'
-         ;call cout
-ctsw_retry:
-       ;find the process on the run queue with highest priority
-       mov             r0, #run_queue
-       mov             r1, [r0]
-       beq             ctsw_queue_empty        ;run_queue is empty
-       movs    r2, #0                  ;r2 is proc w/ highest priority
-       mov             r3l, #0                 ;r3l is highest priority we've seen
-       clr             ea                      ;disable interrupts while we look at the
-                                               ;run queue, since interrupt routines will be
-                                               ;changing priorities to influence which process
-                                               ;should be run next
-ctsw_loop:
-       cmp             [r1+pt_priority], r3l
-       bcs             ctsw_skip
-       ;if we get here, this process is the highest
-       ;priority so far, so forget about any other
-       mov             r3l, [r1+pt_priority]
-       mov             r2, r1
-ctsw_skip:
-       mov             r1, [r1+pt_q_next]
-       bne             ctsw_loop
-       ;now r2 points to the process which should be running...
-       ;check to see if "current_proc" is valid... if it is zero then
-       ;nothing was running (a sys call probably put the process to
-       ;sleep).  If "current_proc" has a valid process pointer, then we
-       ;need to save that process's context (apart from the pushed regs)
-       ;and put that process back into the run queue
-       mov             r0, #current_proc
-       mov             r1, [r0]
-       beq             ctsw_switch
-       call    save_context
-       movs.w  [r1+pt_wakeup], #0              ;wants to go back to user mode
-       mov             r0, #run_queue
-       call    en_que_proc                             ;put back into run queue
-ctsw_switch:
-       ;now it's time to switch to the new process that is about
-       ;to start running.
-       mov             r1, r2
-       call    d_que_proc                      ;remove new proc from run queue
-       call    restore_context
-       mov             r0, #time_running
-       movs.b  [r0], #0                        ;reset "time_running"
-       mov             r0, #current_proc
-       mov             [r0], r1                        ;set "current_proc" to new process
-       ;we may need to return to executing the process in user mode,
-       ;or we may need to jump to a location in the kernel (to continue
-       ;a system call).  If pt_wakup for this process is not zero, then
-       ;some kernel routine caused this process to sleep or be preempted
-       ;and wants to do more work before finally returning to the user
-       ;mode and running the program again.  Usually this is due to a
-       ;system call which needed to put the process to sleep while
-       ;waiting for I/O.
-       mov             r6, [r1+pt_wakeup]
-       setb    ea
-       beq             ctsw_return
-       movs.w  [r1+pt_wakeup], #0      ;don't do this again unless set again
-       jmp             [r6]
-ctsw_return:
-       clr             request_context_switch
-       popu.b  ssel
-       popu.b  es
-       popu.b  ds
-       popu    r2, r3, r4
-    push       r2, r3, r4
-       popu    r0, r1, r2, r3, r4, r5, r6
-       reti
-
-ctsw_queue_empty:
-       ;if we get here, there was no process waiting in the run
-       ;queue.  However, the currently running process isn't
-       ;normally in the run queue, so check if there was a process
-       ;running... if so reset its time slice and let it continue
-       mov             r0, #current_proc
-       mov             r1, [r0]
-       beq             ctsw_idle               ;idle if nothing was running
-       mov             r0, #time_running
-       movs.b  [r0], #0
-       jmp             ctsw_return
-       ;if we get here, the run queue is empty and there in no
-       ;process running now, so we just keep looping inside the
-       ;context switcher until something appears in the run queue
-ctsw_idle:
-       ;need to make a special user-mode idle process... someday
-       ;that could put the processor into idle-mode to save power
-         ;mov  r4l, #' '
-         ;call cout
-       jmp             ctsw_retry
-
-
-
-
-;This "ksleep" routine causes the current process to sleep, afterwhich
-;it jumps to the context switcher, which tries to pick something else to
-;run, if anything is ready.  This code should only be called from
-;within the service code of system calls, which often times need to
-;make their calling process sleep.  R3 should have a value to stuff
-;into "pt_wait" for the process.  ksleep should be CALLed, because
-;it will arrange for the scheduler to return back to the kernel code
-;which called ksleep.  The call to ksleep should be followed by a
-;single NOP, for jump alignment.  Note, before calling ksleep some mechanism
-;to wake the sleeping process back up again must be in place... there
-;is nothing within ksleep which arranges for the process to become
-;awake again, though in the case of i/o the value in r3 should cause it
-;to wake up of the i/o interrupt routine checks for that value.
-
-ksleep:
-       clr             ea
-       mov             r0, #current_proc
-       mov             r1, [r0]                                ;get pointer to process
-         ;cmp  r1, #$FE10
-         ;beq  ksleep_die
-       movs.w  [r0], #0                                ;no current process anymore
-       nop
-ksleep_any:
-       clr             ea
-       mov             [r1+pt_wait], r3                ;record what we're waiting for
-       pop             r5, r6                                  ;get return address
-       adds    r6, #1                                  ;make sure return addr is word addr
-       and             r6, #$FFFE
-       mov             [r1+pt_wakeup], r6              ;set return addr when it wakes up
-       adds.b  [r1+pt_priority], #3    ;increase priority a bit
-       ;need to check here for overrange on user priority
-       mov             r0, #sleep_queue
-       call    en_que_proc                     ;add it to the sleep queue
-       setb    ea
-       call    save_context
-         ;cmp  r1, #$FE10
-         ;beq  ksleep_die
-       jmp             ctsw_begin                              ;scheduler will pick a new
-                                                                       ;process to run (or run idle loop)
-
-ksleep_die:
-       jmp             die
-
-
-syscall_sleep:
-       ;all system calls should run at the same priority as the
-       ;context switcher (level #1), but the code in paulmon2
-       ;sets the trap priority to #8... need to change that.
-       mov.b           pswh, #10000001q
-       pushu   r0, r1, r2, r3, r4, r5, r6              ;save registers
-       pop             r4, r5, r6                                              ;get pc and psw
-       pushu   r4, r5, r6                                              ;save them on user stack
-       pushu.b ds
-       pushu.b es
-       pushu.b ssel
-       ;r0 is number of ticks to sleep, from caller
-       mov             r4, #wake_process
-       mov             r2, #current_proc
-       mov             r5, [r2]        ;"wake_process" will need to know which proc
-       call    add_event
-       mov             r3, #0          ;no other routines will need to know it's sleeping
-       call    ksleep
-       nop
-       popu.b  ssel
-       popu.b  es
-       popu.b  ds
-       popu    r2, r3, r4
-    push       r2, r3, r4
-       popu    r0, r1, r2, r3, r4, r5, r6
-       reti
-
-       ;do_events is supposed to call here when the process is supposed
-       ;to wake up again... all we have to do it remove the process
-       ;from the sleep queue, add it to the run queue, and set the
-       ;software interrupt for the context switcher so it will select
-       ;a new process to run, and it will likely be this one since we
-       ;gave the priority a boost when it was put to sleep.
-       nop
-wake_process:
-         ;mov  r4l, #'$'
-         ;call cout
-       ;r1 should point to event table entry created earlier
-       clr             ea
-       mov             r1, [r1+evt_arg1]       ;now r1 points to process entry
-       call    d_que_proc                      ;remove it from the sleep queue
-       mov             r0, #run_queue
-       call    en_que_proc                     ;add it to the run queue
-       setb    ea
-       ;should really test the priority of this waking process and
-       ;the priority of the currently running one, and only do the
-       ;context switch if the waking one has a higher priority
-       setb    request_context_switch
-       ret
-
-
-
-
-       ;transmit the character in r4l
-syscall_cout:
-       mov.b           pswh, #10000001q
-       pushu   r0, r1, r2, r3, r4, r5, r6              ;save registers
-       pop             r3, r5, r6                                              ;get pc and psw
-       pushu   r3, r5, r6                                              ;save them on user stack
-       pushu.b ds
-       pushu.b es
-       pushu.b ssel
-sc_cout_begin:
-       mov             r0, #tx0_buf_head
-       mov             r2, #tx0_buf_tail
-       clr             ea
-       mov             r1, [r0]
-       bne             sc_cout2
-       ;if we get here, the transmit buffer is empty and the interrupt
-       ;routine cleared the ti bit so no more interrupts are expected
-       setb    ti_0                    ;give the transmitter a kick-start
-       mov             r1, #tx0_buf
-       mov             [r0], r1                ;restore buffer pointers to useful values
-       mov             [r2], r1
-sc_cout2:
-       adds    r1, #1
-       cjne    r1, #tx0_buf+tx0_buf_size, sc_cout3
-       mov             r1, #tx0_buf
-sc_cout3:
-       cmp             r1, [r2]
-       bne             sc_cout4
-       ;if we get here, the buffer is full, so let's just wait
-       ;in a loop... eventually this routine will be replaced
-       ;with "write" which will put the process to sleep and set
-       ;the pt_wait so the context switcher will return here when
-       ;there is space available.  How do we save the variables
-       ;associated with the system call??  Push them onto the
-       ;user's stack for this process?
-       setb    ea
-       mov             r3, #tx0_buf
-       pushu   r4
-       call    ksleep
-       nop
-       popu    r4
-       br              sc_cout_begin   ;try again now that the intr i/o woke us up
-sc_cout4:
-       mov.b   [r1], r4l               ;put data into buffer
-       mov             [r0], r1                ;update pointer
-       setb    ea
-       popu.b  ssel
-       popu.b  es
-       popu.b  ds
-       popu    r2, r3, r4
-    push       r2, r3, r4
-       popu    r0, r1, r2, r3, r4, r5, r6
-       reti
-
-
-
-
-
-
-
-
-       ;this function adds an event to the event queue.  These
-       ;parameters are required:
-       ;       r0      number of ticks until the event should occur
-       ;       r4      function to call when event happens (not zero!!)
-       ;       r5      optional argument
-       ;the event list uses delta time between each entry, so that
-       ;the timer interrupt will only have to deal with the front
-       ;of the queue... but it makes adding an entry here much more
-       ;difficult, but we only have to do this once whereas the
-       ;timer will have to look at the queue however many times the
-       ;evt_ticks value specifies.
-add_event:
-       ;the first thing to do is find a empty place in the table
-       ;to store this event
-       mov             r1, #event_table
-       mov             r2, #max_num_event
-       clr             ea
-aevt_find_slot:
-       mov             r3, [r1+evt_function]
-       beq             aevt_found_slot
-       add             r1, #evt_entry_size
-       djnz    r2, aevt_find_slot
-       ;if we get here there were no slots available, which is a
-       ;very bad thing...
-       jmp             kernel_panic
-aevt_found_slot:
-       ;now that we've located the slot we'll use, let's dump the
-       ;data into it before making a mistake and reusing one of the
-       ;registers that are holding the input parameters
-       mov             [r1+evt_ticks], r0              ;store time value
-       mov             [r1+evt_function], r4   ;store function to be called
-       mov             [r1+evt_arg1], r5               ;store argument
-       ;now we've got to add this event into the linked list in
-       ;the correct time sequence position, and also subtract the
-       ;sum of all the previous evt_ticks values from this one.
-       mov             r6, #event_queue
-       mov             r2, [r6]
-       bne             aevt_check_first
-       ;if we get here, it's easy because the list is empty...
-       mov             [r6], r1
-       movs.w  [r1+evt_next], #0
-       setb    ea
-       ret
-aevt_check_first:
-       ;it may be the case that our new event is supposed to happen
-       ;before the events that are already on the queue
-       cmp             r0, [r2+evt_ticks]
-       bcc             aevt_search
-       mov             [r6], r1
-       mov             [r1+evt_next], r2
-aevt_adjust:
-       ;now that we've added an entry (at r1), we need to adjust the
-       ;evt_ticks values stored in the entry that comes after it.
-       mov             r3, [r1+evt_next]               ;r3 points to next event after ours
-       mov             r4, [r1+evt_ticks]
-       sub             [r3+evt_ticks], r4
-       setb    ea
-       ret
-aevt_search:
-       ;r4 is the adjusted value of ticks for our event as we progress
-       ;through the linked list
-       mov             r4, [r1+evt_ticks]
-aevt_search_loop:
-    sub                r4, [r2+evt_ticks]
-       mov             r3, [r2+evt_next]
-       beq             aevt_add
-       cmp             r4, [r3+evt_ticks]
-       bcs             aevt_add
-       mov             r2, r3
-       jmp             aevt_search_loop
-aevt_add:
-       ;r2 points to the event before the place where we will add
-       ;and r3 points to the place after it in the list
-       mov             [r2+evt_next], r1
-       mov             [r1+evt_next], r3
-       mov             [r1+evt_ticks], r4
-       bne             aevt_adjust                             ;adjust rest of list if it exists
-       setb    ea
-       ret
-
-
-
-
-save_context:          ;process pointer in r1
-       mov             r0, usp
-       mov             [r1+pt_usp], r0                 ;save user stack pointer
-       ;save any directly addressed memory range
-       ;assigned to this process
-       ret
-
-restore_context:               ;process pointer in r1
-       mov             r0, [r1+pt_usp]
-       mov             usp, r0                         ;restore usp to value for new process
-       ;copy contents of directly addresses memory
-       ;back if necessary
-       ret
-
-
-
-
-;This routine removes a process (at r1) from a process queue
-;(run/sleep).  This might be better as an assembler macro, but
-;it's in a subroutine because of the difficulty of figuring out
-;how to correctly manipulate the pointers of a doubly-linked list
-d_que_proc:
-       mov             r6, [r1+pt_q_next]              ;<-- should be macro (begin)
-       mov             r5, [r1+pt_q_prev]
-       mov             [r5], r6
-       mov             [r6+pt_q_prev], r5              ;<--- should be macro (end)
-       ret
-
-;this routine takes a process (at r1) and adds it to a queue, where
-;the location of the head of the queue is in r0.  This is more or
-;less the opposite of "d_que_proc" except that the new process is
-;always added to the head of the list.
-en_que_proc:
-       mov             [r1+pt_q_prev], r0              ;<-- should be macro (begin)
-       mov             r5, [r0]
-       mov             [r1+pt_q_next], r5
-       lea             r6, r1+pt_q_next
-       mov             [r5+pt_q_prev], r6
-       mov             [r0], r1                                ;<--- should be macro (end)
-       ret
-
-;pt_usp                        equ             0               ;2 bytes, User Stack Pointer
-;pt_q_next             equ             2               ;2 bytes, ptr to next in queue
-;pt_q_prev             equ             4               ;2 bytes, ptr to prev in queue (+pt_q_next)
-
-
-;this routine creates a new process, and returns a pointer to it
-;in r1.  If the process can't be created, r1 is zero.  Data about
-;the new process is required:
-;      r4 = location of executable program
-;      r5 = location for user stack (eventually malloc will do this)
-
-
-create_process:
-       mov             r1, #proc_table
-       mov             r2, #max_num_proc
-cproc_find_slot:
-       mov             r0, [r1+pt_usp]
-       beq             cproc_found_slot                ;ok to use this process entry
-       add             r1, #pt_entry_size
-       djnz    r2, cproc_find_slot
-       ;if we get here, there is no more room in the process
-       ;table so we can't create a new process.
-       movs    r1, #0
-       ret
-cproc_found_slot:
-       push    r4, r5
-       ;first initialize the various kernel data required
-       mov             r0, #run_queue
-       clr             ea
-       call    en_que_proc                                     ;add it to the run queue
-       mov.b   [r1+pt_priority], #100          ;start at priority 100
-       movs.w  [r1+pt_wait], #0
-       movs.w  [r1+pt_wakeup], #0
-       ;next we need to set up the process's context
-       pop             r4, r5
-       sub             r5, #26                         ;advance r5 to context storage area
-       mov             [r1+pt_usp], r5
-       movs.w  [r5+], #0                       ;segment select is 0
-       movs.w  [r5+], #0                       ;es is 0
-       movs.w  [r5+], #0                       ;ds is 0
-       movs.w  [r5+], #0                       ;psw is zero (user mode)
-       movs.w  [r5+], #0                       ;run is page zero only (for now)
-       mov             [r5+], r4                       ;set return addr to beginning
-       ;could create initial values for the registers here...
-       setb    ea
-       ret
-
-;user stack while in kernel mode:
-; byte
-; offset   Variable
-;      -2              r6
-;      -4              r5
-;      -6              r4
-;      -8              r3
-;      -10             r2
-;      -12             r1
-;      -14             r0
-;      -16             program counter (lsw)
-;      -18             program counter (msb)
-;      -20             program status word
-;      -22             ds
-;      -24             es
-;      -26             ssel            <-- usp points here
-
-
-poweron:
-       mov             r6, #$F000
-clear_memory_loop:
-       movs.w  [r6+], #0
-       cjne    r6, #0, clear_memory_loop
-         setb  p1.6
-         setb  p1.7
-
-       mov             r7, #sys_stack                          ;set sys stack pointer
-       clr             ea
-       ;initialize serial port buffers
-       mov             r0, #rx0_buf_head
-       mov.w   [r0], #rx0_buf
-       mov             r0, #rx0_buf_tail
-       mov.w   [r0], #rx0_buf
-       mov             r0, #tx0_buf_head
-       movs.w  [r0], #0
-       mov             r0, #tx0_buf_tail
-       movs.w  [r0], #0
-       mov             r0, #rx1_buf_head
-       mov.w   [r0], #rx1_buf
-       mov             r0, #rx1_buf_tail
-       mov.w   [r0], #rx1_buf
-       mov             r0, #tx1_buf_head
-       movs.w  [r0], #0
-       mov             r0, #tx1_buf_tail
-       movs.w  [r0], #0
-       ;clear serial port flags
-       clr             ri_0
-       clr             ti_0
-       clr             ri_1
-       clr             ti_1
-       ;initialize interrupts
-       mov.b   swe, #255                               ;allow all software interrupts
-    mov.b   ipa0, #10010000q           ;priority #9: timer0 interrupt
-       mov.b   ipa4, #10011001q                ;priority #9: uart0 rx and tx interrupts
-       mov.b   ipa5, #10011001q                ;priority #9: uart1 rx and tx interrupts
-       mov.b   ieh, #00001111q                 ;enable uart interrupts
-       ;set up timer 0 to 16-bit auto reload (10 ms)
-       clr             et0                                             ;no timer 0 interrupt yet
-       clr             tr0                                             ;stop timer 0
-       clr             tf0
-       mov.b   rtl0, #low 37798                ;set 10 ms rate
-       mov.b   rth0, #high 37798
-       movs.b  tl0, #0                                 ;zero timer
-       movs.b  th0, #0
-       and.b   tmod, #11110000q                ;set for 16 bit auto reload
-
-
-    ;now set up the variables so we're in idle mode
-       mov             r0, #current_proc
-       movs.w  [r0], #0                                        ;set no process running
-       mov             r0, #run_queue
-       movs.b  [r0], #0                                        ;all queues empty
-       mov             r0, #sleep_queue
-       movs.b  [r0], #0
-       mov             r0, #time_running
-       movs.b  [r0], #0
-       ;initialize pt_usp of all processes to zero, so that
-       ;there won't appear to be any processes
-
-       nop
-clr_proc_tbl:
-       mov             r1, #proc_table
-       mov             r2, #max_num_proc
-clr_proc_tbl_loop:
-       movs.w  [r1+pt_usp], #0
-       add             r1, #pt_entry_size
-       djnz    r2, clr_proc_tbl_loop
-clr_events:
-       mov             r1, #event_table
-       mov             r2, #max_num_event
-clr_events_loop:
-       movs.w  [r1+evt_function], #0
-       add             r1, #evt_entry_size
-       djnz    r2, clr_events_loop
-
-;now create process table entries for the test programs
-       mov             r4, #program1
-       mov             r5, #$F000
-       call    create_process          ;create process for program1
-       mov             r4, #program2
-       mov             r5, #$EC00
-       call    create_process          ;create process for program2
-       mov             r4, #program3
-       mov             r5, #$E800
-       ;call   create_process          ;create process for program3
-
-
-
-       ;now how can we get into user mode for the first time???
-       ;normally the kernel is entered by an interrupt (hardware
-       ;or software) or a trap (sys call), so we get back to a
-       ;user program with reti... but the first time has to be
-       ;handled a bit differently
-       mov             r1, #proc_table
-       call    d_que_proc                      ;remove new proc to run from run queue
-       call    restore_context
-       mov             r0, #time_running
-       movs.b  [r0], #0                        ;reset "time_running"
-       mov             r0, #current_proc
-       mov             [r0], r1                        ;set "current_proc" to new process
-       popu.b  ssel
-       popu.b  es
-       popu.b  ds
-       popu    r0, r1, r2                      ;r0=psw, r1=pc_high, r2=pc_low
-       popu    r3, r4, r5                      ;extract r0/r2 reg from stack
-       popu    r3, r4, r5, r6          ;extract r3/r6 reg from stack
-       mov             cs, r1l                         ;set code segment
-       clr             tf0                                     ;clear timer0 flag
-       setb    tr0                                     ;start timer0
-       setb    et0                                     ;enable timer0 interrupt
-       setb    ea
-       mov             pswl, r0l
-       mov             pswh, r0h                       ;this makes the switch to user mode
-                                                               ;and lower priority to 0 (from max)
-       jmp             [r2]                            ;jump to the user program
-
-
-
-
-kernel_panic:
-die:
-       clr             ea
-       clr             ri_0
-die_loop:
-       jnb             ri_0, die_loop
-       clr             ri_0
-       jmp             $120            ;reboot!
-
-
-
-;unix system calls: (which ones to try first??)
-;process mgt: fork, exec/execve, exit, wait/wait4
-;file i/o: open, read, write, select, ioclt, lseek, close, fcntl
-;signals: kill, signal, alarm, pause
-;pipes: pipe, dup/dup2
-;network/ipc: socket, bind, connect/listen/accept, sendto, recvfrom
-;network/ipc: socketpair, getsockname/getpeername, setsockopt/getsockopt
-;filesystems: chroot/chdir, link, unlink, mkdir, rmdir,
-;filesystems: chown/chmod, stat, rename, truncate
-
-
-
-
-;**************************************************************
-;**                                                          **
-;**                     User Programs                        **
-;**                                                          **
-;**************************************************************
-
-
-
-cout:
-       trap    #trap_cout
-       ret
-
-newline:
-       push    r4l
-       mov             r4l, #13
-       call    cout
-       mov             r4l, #10
-       call    cout
-       pop             r4l
-       ret
-
-pstr:      PUSH    r4
-pstr1:     MOVC    r4l,[r6+]
-           beq     pstr2
-           AND     R4L,#0x7F
-           CALL    cout
-           BR      pstr1
-pstr2:     POP     r4
-           RET
-
-phex:
-phex8:
-           PUSH.B  acc
-           RL.B R4L,#4
-           AND.B   R4L,#15
-           ADD.B   R4L,#246
-           BCC     phex_b
-           ADD.B   R4L,#7
-phex_b:    ADD.B   R4L,#58
-           CALL    cout
-           POP.B   acc
-phex1:     PUSH.B  acc
-           AND.B   R4L,#15
-           ADD.B   R4L,#246
-           BCC     phex_c
-           ADD.B   R4L,#7
-phex_c:    ADD.B   R4L,#58
-           CALL    cout
-           POP.B   acc
-           RET
-
-phex16:
-           PUSH.B  acc
-           MOV.B   R4L,dph
-           CALL    phex
-           MOV.B   R4L,dpl
-           CALL    phex
-           POP.B   acc
-           RET
-
-
-
-
-
-       ;program #1 prints "Paul" to serial port #0, with a
-       ;fairly long delay between each printing
-program1:
-       mov             r6, #str_paul
-       call    pstr
-       mov             r0, #130
-       trap    #trap_delay
-       jmp             program1
-
-str_paul: db "Paul",0
-
-pgm2_speed             equ             10              ;number of ticks between led blinks
-
-       nop
-       ;program #2 blinks the LEDs and prints a "." to the
-       ;serial port #0 after every sequence of blinks.
-program2:
-       or.b    p1cfga, #$C0                    ;p1.6 and p1.7 outputs
-       or.b    p1cfgb, #$C0
-pg2_loop:
-       ;br             pg2_skip_blink
-       setb    p1.6
-       setb    p1.7
-       mov             r0, #pgm2_speed
-       trap    #trap_delay
-       clr             p1.6
-       setb    p1.7
-       mov             r0, #pgm2_speed
-       trap    #trap_delay
-       setb    p1.6
-       setb    p1.7
-       mov             r0, #pgm2_speed
-       trap    #trap_delay
-       setb    p1.6
-       clr             p1.7
-       mov             r0, #pgm2_speed
-       trap    #trap_delay
-       setb    p1.6
-       setb    p1.7
-
-pg2_skip_blink:
-       mov             r4l, #'.'
-       call    cout
-       br              pg2_loop
-
-program3:
-       mov             r4l, #'3'
-       call    cout
-       ;mov            r6, #test_str
-       ;call   pstr
-       jmp             program3
-
-
-test_str: db "This_is_a_test", 0
-
-
-
-
-
-
-
-
-