;*****************************************************************************
; INTERFACE WhiteSmith to MCX-16
; ------------------------------
; Platform : Motorola 68HC16 running MCX16 Multitasking Executive
; Compiler : Whitesmith C
;
; (c) M. Lutfi Shahab (13389011)
; Instrumentation and Control Labs.
; Department of Engineering Physics
; Institut Teknologi Bandung (ITB)
;
; Created : 13 Apr 1995
; Updated : 5 May 1995
;
;Interface Spec.
;---------------
; In WSC:
; - The default memory model is the COMPACT model, in which all of
; the code and data must share the same 64K area.
; - Type SHORT INT are stored as two bytes, MSB first
; - Type LONG INTEGER are stored as four bytes, in descending order of
; significance.
; - Type FLOAT are represented in specific format adapted to the M68HC16
; processor, is a 4 bytes of data; the first two bytes contain a signed
; mantissa coding real values in the interval [-1.0,1.0]. The other 2
; bytes contain signed exponent. If the first word is zero, the entire
; number will be understood 0.0. The value of the number is the fraction
; multiplied by 2 raised to the exponent. The mantissa is then compatible
; with the internal DSP processor format.
; - Type DOUBLE are represented as for the proposed IEEE-754 floating point
; standard; 8 bytes stored in descending order of byte significance:
; * MSB bit is one of four negative numbers, and zero otherwise.
; * next 8 bits are the characteristic, biased such that the binary
; exponent of the number is the characteristic minus 1002.
; * the remaining bits are the fraction, starting with the weighted bit.
; - Arguments are moved onto the stack from right to left. The first
; argument is stored in the D register if its size is less than or equal
; to the size of an int, or in the register pair E, D if it is a long
; or float, and in the function doesn't return a struct or a double.
; - By default, character data is sign extended to short, and floats are
; extended to doubles.
; - The function is called via jsr _func or jbsr _func.
; - The arguments to the function are popped off the stack.
; - A data space address is move onto stack if a struct or double return
; area is required.
; - The return value is in D register (if length less than 2 bytes), or
; is in the registers E,D (the D register holds the low order bits).
; The addresses of double and struct data are added on stack at call time.
; - Each C function maintains its own stack frame, using IX as frame pointer.
; - You must save an restore the K register if want to call an assembly
; language routine that modifies the EK, XK, YK, or ZK registers.
; - BSR does these microcode sequences:
; 1. put PC to stack
; 2. SP = SP-2
; 3. put CCR to stack
; 4. SP = SP-2
; so SP (now) = SP (before bsr) + 4
;
; - XK, YK, ZK and SK can be modified by using the transfer index register
; to stack pointer and transfer stack pointer to index register instructions.
; When SP is transfered to (TSX, TSY, and TSZ) or from (TXS, TSY, TSZ) an
; index register, the corresponding address extension fields is also
; transfered. Before the extension field is transfered, it is incremented
; or decremented if bank overflow occured as a result of the instruction.
;
; NOTE
; > Be aware of invoking these routines. Make sure you have
; set extension register (K) to a proper value, otherwise the system
; will crash.
;*****************************************************************************/
.PROCESSOR M68HC16
.TITLE "Thesis Project : WSC -> MCX calling translation"
.INCLUDE "mcx16.mac"
.psect _text
.even
.LIST + .MACRO
;* below are calling codes to MCX-16 *
;-----------------------------------
; __mcx_nop
;
; cycles=14
; code = 4 bytes
;----------------------------------
.PUBLIC __mcx_nop
__mcx_nop:
MCX_CALL MCX_NOP_
rts
;------------------------------------------------------
;* Force a semaphore to PENDing state*
; Narrative:
; WSC:
; void _mcx_pend(int sema)
; sema passed to D (ACCB = lo(sema), ACCA = hi(sema))
;
; MCX:
; parameters:
; ACCA = code for _mcx_pend = 3
; ACCB = semaphore number
; return:
; none
;
; cycles = 14
; code = 6 bytes
;------------------------------------------------------
.even
.PUBLIC __mcx_pend
__mcx_pend:
MCX_CALL MCX_PEND_
rts
;--------------------------------------------------
; * Signal the occurence of an event.
; Narrative:
; WSC:
; void _mcx_signal(int sema)
; ACCD = sema
;
; MCX:
; parameters:
; ACCA = code for mcx_signal = 1
; ACCB = semaphore number
; return:
; none
;
; cycles = 14
; code = 6 bytes
;--------------------------------------------------
.even
.PUBLIC __mcx_signal
__mcx_signal:
MCX_CALL MCX_SIGNAL_ ;* Signal semaphore *
rts
;------------------------------------------------------
; * Make a task wait for the occurence of a specified
; event
; Narrative:
; WSC:
; int _mcx_wait(int sema)
; on call, sema in D register
;
; MCX:
; parameters:
; ACCA = code for _mcx_wait = 2
; ACCB = semaphore number
; return:
; ACCA, 0 = success, 1 = fail
;
; cycles = 16
; code = 8 bytes
;------------------------------------------------------
.even
.PUBLIC __mcx_wait
__mcx_wait:
MCX_CALL MCX_WAIT_ ;* Wait on event *
clrb
rts
;------------------------------------------------------
;* Signal completion of message processing*
; Narrative:
; WSC:
; void _mcx_msg_done(void *msg)
; msg passed to D
;
; MCX:
; parameters:
; ACCA = code for _mcx_msg_done = 18
; IX = message address
; return:
; none
;
; cycles = 28
; code = 12 bytes
;------------------------------------------------------
.even
.PUBLIC __mcx_msg_done
__mcx_msg_done:
pshm x ; save stack frame
xgdx ; IX = msg
MCX_CALL MCX_MSG_DONE_
pulm x ; restore old IX (stack frame)
rts
;------------------------------------------------------
;* Fetch message from a mailbox
; Narrative:
; WSC:
; void *_mcx_receive(int mbx)
; mbx passed to D
; return:
; D = address of the received message
;
; MCX:
; parameters:
; ACCA = code for _mcx_receive = 16
; ACCB = mailbox number
; return:
; IX = address of received message
;
; cycles = 28
; code = 12 bytes
;------------------------------------------------------
.even
.PUBLIC __mcx_receive
__mcx_receive:
pshm x ; save stack frame
MCX_CALL MCX_RECEIVE_
xgdx ; D contain address of msg
pulm x ; restore stack frame
rts
;------------------------------------------------------
;* Fetch message from a mailbox with wait directive
;
; Narrative:
; WSC:
; void *_mcx_receive_w(int mbx)
; mbx passed to D
; return:
; ACCD = address of the received message
;
; MCX:
; parameters:
; ACCA = code for _mcx_receive_w = 17
; ACCB = mailbox number
; return:
; IX = address of the received message
;
; cycles = 28
; code = 12 bytes
;------------------------------------------------------
.even
.PUBLIC __mcx_receive_w
__mcx_receive_w:
pshm x ; save stack frame
MCX_CALL MCX_RECEIVE_W_
xgdx ; D = address of received msg
pulm x ; restore stack frame
rts
;-------------------------------------------------------
;* send message MSG into target MAILBOX
; with SEMA semaphore
; Narrative:
; WSC:
; void _mcx_send_mbx(int mbx, void *msg, int sema)
; mbx in D
; msg in [SP+6]
; sema in [SP+8]
;
; MCX:
; parameters:
; ACCA = code for _mcx_send_mbx = 14
; ACCB = message semaphore number (sema)
; ACCE = mailbox number to receive message (mbx)
; IX = message address
; return:
; none
;
; cycles = 14
; code = 18 bytes
;-------------------------------------------------------
.even
.PUBLIC __mcx_send_mbx
__mcx_send_mbx:
pshm x ; save old stack frame because IX used by MCX
tsz ; Z = SP + 2
xgde ; E = mbx
ldd 8,z ; D = sema
ldx 6,z ; IX = msg
mcx_call MCX_SENDMBX_
; accb = sema, acca = 14
pulm x
rts
;-------------------------------------------------------
;* send message MSG into target MAILBOX
; with SEMA semaphore and wait directive
; Narrative:
; WSC:
; void _mcx_send_mbx_w(int mbx, void *msg, int sema)
; mbx in D
; msg in [SP+6]
; sema in [SP+8]
;
; MCX:
; parameters:
; ACCA = code for _mcx_send_mbx_w = 15
; ACCB = message semaphore number
; ACCE = mailbox number to receive message
; IX = message address
; return:
; none
;
; cycles =
; code = 18 bytes
;-------------------------------------------------------
.even
.PUBLIC __mcx_send_mbx_w
__mcx_send_mbx_w:
pshm x ; save old stack frame because IX used by MCX
tsz ; Z = SP + 2
xgde ; E = mbx
ldd 8,z ; D = sema
ldx 6,z ; IX = msg
MCX_CALL MCX_SENDMBX_W_
; accb = sema, acca = 15
pulm x
rts
;-------------------------------------------------------
;* Get the oldest entry from a FIFO queue
; Narrative:
; int _mcx_dequeue(int queue, void *ptr)
; queue in D
; ptr in [SP+6]
; return: ACCD
;
; parameters to mcx:
; ACCA = code for mcx_dequeue = 12
; ACCB = queue number
; IX = destination address of entry
; return:
; ACCA = 0, if queue was empty
; 1, if entry dequeued successfully other
;
; cycles =
; code = 16 bytes
;-------------------------------------------------------
.even
.PUBLIC __mcx_dequeue
__mcx_dequeue:
pshm x
tsz ;
ldx 6,z ; IX = ptr
; ACCD hold queue number, so we just set ACCA
MCX_CALL MCX_DEQUEUE_
pulm x
clrb
rts
;-------------------------------------------------------
;* Get the oldest entry from a FIFO queue. If queue
; empty, wait until queue not empty
; Narrative:
; int _mcx_dequeue_w(int queue, void *ptr)
; queue in ACCD
; ptr in [SP+6]
;
; parameters to mcx:
; ACCA = code for mcx_dequeue_w = 13
; ACCB = queue number
; IX = destination address of entry
; return:
; ACCA = 0, if queue was empty
; = 1, if dequeue was successful
;
; cyles =
; code = 16 bytes
;-------------------------------------------------------
.even
.PUBLIC __mcx_dequeue_w
__mcx_dequeue_w:
pshm x
tsz
ldx 6,z ; IX = ptr
; ACCD hold queue number, so we just set ACCA
MCX_CALL MCX_DEQUEUE_W_
pulm x
clrb ; ACCD = return value of mcx_dequeue_w
rts
;-------------------------------------------------------
;* Put an entry to a FIFO queue.
;
; Narrative:
; int _mcx_enqueue(int queue, void *ptr)
; queue in D
; ptr in [SP+6]
; return: ACCD
;
; parameters to mcx:
; ACCA = code for mcx_dequeue_w = 10
; ACCB = queue number
; IX = destination address of entry
; return:
; ACCA = 0, if queue was empty
; = 1, if dequeue was successful
;
; cycles =
; code = 16 bytes
;-------------------------------------------------------
.even
.PUBLIC __mcx_enqueue
__mcx_enqueue:
pshm x
tsz ; Z = SP + 2
ldx 6,z ; IX = ptr
; ACCD hold queue number, so we just set ACCA
MCX_CALL MCX_ENQUEUE_
pulm x
clrb
rts
;-------------------------------------------------------
;* Put an entry to a FIFO queue and wait if empty.
; Narrative:
; int _mcx_enqueue_w(int queue, void *ptr)
; queue in ACCD
; ptr in [SP+6]
; return: ACCD
;
; parameters to mcx:
; ACCA = code for mcx_dequeue_w = 11
; ACCB = queue number
; IX = source address of entry
; return:
; ACCA = 0, if queue successful
; = 1, if empty
;
; cycles =
; code = 16 bytes
;-------------------------------------------------------
.even
.PUBLIC __mcx_enqueue_w
__mcx_enqueue_w:
pshm x
tsz ; Z = SP + 2
ldx 6,z ; IX = ptr
; ACCD hold queue number, so we just set ACCA
MCX_CALL MCX_ENQUEUE_W_
pulm x
clrb
rts
;-------------------------------------------------------
;* Change the priority of a task *
; Narrative:
; void _mcx_change_pri(int task, priority)
; ACCD = task number
; [SP+6] = priority
;
; parameters:
; ACCA = code for _mcx_execute = 9
; ACCB = task number
; ACCE = task priority
;
; return:
; none
;
; cycles =
; code = 12 bytes
;-------------------------------------------------------
.even
.PUBLIC __mcx_change_pri
__mcx_change_pri:
tsz ; Z = SP + 2
lde 6,z ; E = priority
; ACCD hold task address, so we just set ACCA
MCX_CALL MCX_CHANGE_PRI_
rts
;-------------------------------------------------------
;* Excecute a task *
; Narrative:
; void _mcx_execute(int tsk_num, priority, (void *)(task)(),
; void *stack_ptr, void *reg_init_ptr)
; tsk_num = ACCD
; reg_init_ptr = [SP +12]
; stack_ptr = [SP +10]
; task address = [SP + 8]
; priority = [SP + 6]
;
; parameters:
; ACCA = code for _mcx_execute = 4
; ACCB = task number
; ACCE = task priority
; IX = starting address of task
; IY = base address of task's stack
; IZ = address of register initialization packet
; (IZ=0 means no packet)
; return:
; none
;
; cycles =
; code = 22 bytes
;-------------------------------------------------------
.even
.PUBLIC __mcx_execute
__mcx_execute:
pshm x
tsz ; Z = SP + 2
; ACCD = task number
lde 6,z ; ACCE = task priority
ldx 8,z ; IX = task
ldy 10,z ; IY = stack
ldz 12,z ; IZ = reg_init_pkt
MCX_CALL MCX_EXECUTE_
;* Execute a task *
pulm x
rts
;-------------------------------------------------------
;* Clears the suspend state of task
;
; Narrative:
; WSC:
; void _mcx_resume(int task_num)
; ACCD = task_num
;
; MCX:
; parameters:
; ACCA = code for _mcx_resume = 7
; ACCB = task number
;
; return:
; none
;
; cycles =
; code = 6 bytes
;-------------------------------------------------------
.even
.PUBLIC __mcx_resume
__mcx_resume:
; ACCB = task number
MCX_CALL MCX_RESUME_
rts
;-------------------------------------------------------
;* Blocks the specified task with a SUSPEND condition
; Narrative:
; WSC:
; void _mcx_suspend(int task_num)
; ACCD = task_num
;
; MCX:
; parameters:
; ACCA = code for _mcx_suspend = 6
; ACCB = task number (0= SELF)
; return:
; none
;
; cycles =
; code = 6 bytes
;-------------------------------------------------------
.even
.PUBLIC __mcx_suspend
__mcx_suspend:
; ACCB = task number
MCX_CALL MCX_SUSPEND_
rts
;-------------------------------------------------------
;* Terminate a task's operation
;
; Narrative:
; WSC:
; void _mcx_terminate(int task_num)
; ACCD = task_num
;
; MCX:
; parameters:
; ACCA = code for _mcx_resume = 5
; ACCB = task number
;
; return:
; none
;
; cycles =
; code = 6 bytes
;-------------------------------------------------------
.even
.PUBLIC __mcx_terminate
__mcx_terminate:
; ACCB = task number
MCX_CALL MCX_TERMINATE_
rts
;-------------------------------------------------------
;* Blocks specified task with a DELAYED state for the
; period
; Narrative:
; WSC:
; void _mcx_delay(int task_num, int tick)
; ACCD = task_num
; [SP+6] = tick
;
; MCX:
; parameters:
; ACCA = code for _mcx_delay = 8
; ACCB = task number (0= SELF)
; ACCE = number of clock ticks to delay
; return:
; none
;
; cycles =
; code = 16 bytes
;-------------------------------------------------------
.even
.PUBLIC __mcx_delay
__mcx_delay:
; ACCB = task number
tsz
lde 6,z ; ACCE = tick
MCX_CALL MCX_DELAY_
rts
;-------------------------------------------------------
;* Stop a timer whose handle is specified by ptr
; Narrative:
; WSC:
; void _mcx_kill_timer(void *tick_handler)
; ACCD = tick_handler
;
; MCX:
; parameters:
; ACCA = code for _mcx_kill_timer = 20
; ACCE = Handle of timer to be killed
; return:
; none
;
; cycles =
; code = 10 bytes
;-------------------------------------------------------
.even
.PUBLIC __mcx_kill_timer
__mcx_kill_timer:
tsz
xgde ; ACCE = tick handler
MCX_CALL MCX_KILL_TIMER_
rts
;-------------------------------------------------------
;* Stop a active timer and reset its duration to a new
; value
; Narrative:
; WSC:
; void _mcx_reset_t(void *hndr, int tick)
; ACCD = hndlr
; [SP+6] = tick
;
; MCX:
; parameters:
; ACCA = code for _mcx_delay = 21
; ACCE = Handle of timer to be reset
; IX = duration of timer's initial period
; return:
; none
;
; cycles =
; code = 16 bytes
;-------------------------------------------------------
.even
.PUBLIC __mcx_reset_t
__mcx_reset_t:
; ACCB = task number
pshm x
tsz
xgde ; ACCE = tick handler
ldx 6,z ; tick
MCX_CALL MCX_RESET_T_
pulm x
rts
;-------------------------------------------------------
;* Stop a active timer and reset its duration to a new
; value
; Narrative:
; WSC:
; void *_mcx_timer(int init_t, int recyle_t, int sema)
; ACCD = init_t
; [SP+6] = recyle_t
; [SP+8] = sema
; return: ACCD
;
; MCX:
; parameters:
; ACCA = code for _mcx_timer = 19
; ACCB = semaphore number
; ACCE = Duration of initial period
; IX = duration of recycle time
; return:
; ADDE = handle of timer if it was established
; = 0, if there were no timer blocks available
; in the pool of free timers.
;
; cycles =
; code = 20 bytes
;-------------------------------------------------------
.even
.PUBLIC __mcx_timer
__mcx_timer:
pshm x
tsz ; z = SP
xgde ; ACCE = init_t
ldd 8,z ; ACCD = sema = [SP+8]
ldx 6,z ; IX = recycle_t = [SP+6]
MCX_CALL MCX_TIMER_
pulm x
ted ; ACCD = handle of timer
rts
.END
Thursday, December 17, 2009
SLIP driver
;----------------------------------------------------------------------------
; SLIP COMMUNICATION HANDLER
; Intel 386-based
; Receiver and Transmitter ISR
;
; * Thesis Project *
; M. Lutfi Shahab 13389011
; Department of Engineering Physics
; Institut Teknologi Bandung
; (c) Bandung, 1995
;
; First made: March 1995
; Last upated: 4-Jan 1996
;----------------------------------------------------------------------------
;
;
; 26/7/95 I found a bug on ISR. ISR should push flags to stack, but
; in older version, this didn't!
; I observed this bug affected keyboard flag checking
; 11 Nov 1995 In next version I plan to use extended USART controller,
; like Intel 82510 and 16550
; Detecting these chips done with writting appropriate setting
; code to FCR (FIFO control register) and detects their presences
; in extended fields of IIR (Interrupt Control Register).
; 8 Jan 1995 16 bit Cyclic Redundancy Check added.
;
;-----------------------------------------------------------------------------
;IFDEF TASM
PAGE 60, 120
;ENDIF
MODEL large, C
MASM
DEBUG EQU 0 ; debug
INCLUDE PIC.ASH
INCLUDE SLIP.ASH
.DATA
EXTRN base :WORD
EXTRN queue :tQUEUE
EXTRN baudrate :DWORD
EXTRN int_no :BYTE
EXTRN thr :WORD
EXTRN rdr :WORD ; base
EXTRN ier :WORD ; = base+1
EXTRN iir :WORD ; = base+2
EXTRN lcr :WORD ; = base+3
EXTRN mcr :WORD ; = base+4
EXTRN lsr :WORD ;
EXTRN msr :WORD ; = base+6
EXTRN scp :WORD ; scratch pad = base + 7
EXTRN installed :WORD ; initialization flag
EXTRN imr :WORD
EXTRN rcv :tCOMBUF
packet_sem DW 0
xmit_time DW 200 ;timeout
rcv_time DW 200
timeout DW 200
recv_pkt_ready DW 0
IF DEBUG EQ 1
isr_msg DB 'Ini di dalam recv_isr', 10, 13, '$'
isr_in_sema db 'Semaphore > 0', 10,13,'$'
ENDIF
.CODE
; This variable must be put in CODE SEGMENT
in_recv_isr DW 0
IF DEBUG EQ 1
;-------------------------
; al = charactrer to print
;-------------------------
print PROC NEAR
PUSH ax bx cx dx ds es si di bp ; Turbo Assembler's macro
mov bh, 0
mov bl, 07h
mov ah, 0eh
int 10H
POP bp di si es ds dx cx bx ax
RETN
print ENDP
;---------------------
; dx => offset string
;---------------------
print_msg PROC
PUSH ax bx cx dx ds es si di bp
ASSUME ds:@data
mov ax, @data
mov ds, ax
mov ah, 9h
int 10H
POP bp di si es ds dx cx bx ax
RET
print_msg ENDP
ENDIF
xmit PROC NEAR
retn
xmit ENDP
;--------------------
send_char PROC NEAR
PUSH ds dx cx
xchg ah,al ; put data char into ah
push ax
ASSUME ds:@data
mov ax,@data ; resetting ds to DGROUP
mov ds, ax
pop ax
xor cx,cx ; 64K retry counter
sendch1:
mov dx, [lsr]
in al, dx
jmp $+2 ; use time, prevent overdriving UART
jmp $+2
test al, LSR_THRE ; Transmitter (THRE) ready?
jnz sendch2 ; nz = yes
loop sendch1
stc ; carry set for failure
jmp short sendch3 ; timeout
sendch2:
xchg al, ah ; now send it
mov dx, [thr]
out dx, al ; send the byte
jmp $+2 ; use a little time
clc ; status of success
sendch3:
POP cx dx ds
RETN
send_char ENDP
; ------------------------------------------
; int _Send_SLIP_Packet(tSLIP_Pkt *pkt)
; ------------------------------------------
PUBLIC C _Send_SLIP_Packet
_Send_SLIP_Packet PROC C pkt:DWORD
;--------- Turbo Assembler automatically set stack frame
PUSH ds si
sti ; enable interrupts
lds si, pkt
;-------- MODIFIED because CRC16 addition ($LTF$, 8/JAN/95)
;mov cl, ds:[si].datalen
;xor ch, ch
;cmp cx, DATASIZE
;jle LESS_OR_EQU
;mov cx, DATASIZE ; align to DATASIZE
mov cx, PKTSIZE
LESS_OR_EQU:
;---add cx, 4 ; total packet length =
; sizeof(pktlen)+sizeof(datatype)+sizeof(crc)
; = 1 + 1 + 2 = 4 bytes
cld
mov al, FR_END ; Flush out any line garbage
call send_char
jc send_pkt_end ; c = failure to send
; Copy input to output, escaping special characters
send_pkt_1:
lodsb
cmp al, FR_ESC ;escape FR_ESC with FR_ESC and T_FR_ESC
jne send_pkt_2
mov al, FR_ESC
call send_char
jc send_pkt_end
mov al, T_FR_ESC
jmp short send_pkt_3
send_pkt_2:
cmp al, FR_END ;escape FR_END with FR_ESC and T_FR_END
jne send_pkt_3
mov al, FR_ESC
call send_char
jc send_pkt_end
mov al, T_FR_END
send_pkt_3:
call send_char
jc send_pkt_end
loop send_pkt_1 ; do cx user characters
mov al, FR_END ; terminate it with a FR_END
call send_char
jc send_pkt_end
mov ax, 1 ; success
jmp short keluar
send_pkt_end:
xor ax, ax ; error occured
keluar:
POP si ds
RET
_Send_SLIP_Packet ENDP
;------------------------------------
; static void near asyrxint(void)
; return:
; - packet_sem
; - recv_pkt_ready
;------------------------------------
asyrxint PROC NEAR
push ds ; save ds register
ASSUME ds:@data
mov ax, @data ; ds points to DGROUP !
mov ds, ax
mov ax, WORD PTR [rcv.buf_end+2] ; just check !!
xor bx, bx
cmp WORD PTR [baudrate+2], 0
jb short asyrxint_a
jbe check_again
jmp short asyrxint_a
check_again:
cmp WORD PTR [baudrate], 9600 ;below 9600 we're strictly
jb asyrxint_a ;interrupt driven
mov bx, rcv_time
asyrxint_a:
les di, DWORD PTR [rcv.head]
xor bp, bp ; set flag to indicate 1st char processed
mov si, packet_sem ; optimization
mov ah, LSR_DR
asyrxint_again:
xor cx, cx ; initialize counter
mov dx, [lsr]
asyrxint_in:
in al, dx ; check for data ready
test al, LSR_DR
jnz asyrxint_gotit ; yes - break out of loop
inc cx ; no - increase loop counter
cmp cx, bx ; timeout?
jae asyrxint_exit ; yes - leave
jmp asyrxint_in ; no - keep looping
asyrxint_gotit:
mov dx, [rdr]
in al, dx
; Process incoming data;
; If buffer is full, we have no choice but to drop the character
;
; segment of rcv.head and rcv.tail is same !!
; so just compare their offsets
cmp di, WORD PTR [rcv.tail]; is it buffer collision ?
jne asyrxint_ok ; none - continue
or si, si ; maybe - if there are packets
jnz asyrxint_exit ; yes exit
asyrxint_ok:
stosb
cmp di, WORD PTR [rcv.buf_end] ; did we hit the end of the buffer?
jne asyrxint_3 ; no.
mov di, WORD PTR [rcv.buf] ; yes - wrap around.
asyrxint_3:
cmp al,FR_END ; might this be the end of a frame?
jne asyrxint_reset ; no - reset flag and loop
inc si ; yes - indicate packet ready
cmp si, 1 ; determine if semaphore is <> 1
jne asyrxint_chk_flg ; yes - recv_frame must be active
inc recv_pkt_ready ; no - set flag to start recv_frame
IF DEBUG EQ 1
mov al, 'O'
call print
ENDIF
asyrxint_chk_flg:
cmp bp, 0 ; was this the first char?
jne asyrxint_1 ; no - exit handler
asyrxint_reset:
inc bp ; set 1st character flag
jmp asyrxint_again ; get another character
asyrxint_exit:
asyrxint_1:
mov WORD PTR [rcv.head], di ; set offset pointed by rcv.head
mov [packet_sem], si
exit:
pop ds
RETN
asyrxint ENDP
;--------------------
; registers used:
; ax, ds
;
;--------------------
recv PROC NEAR
recv_2:
push ds
mov ax, @data
mov ds, ax
mov dx, [iir]
pop ds
in al, dx ;any interrupts at all?
test al, IIR_IP
jne recv_1 ;no.
and al,IIR_ID
cmp al,IIR_RDA ;Receiver interrupt
jne recv_3
call asyrxint
jmp recv_2
recv_3:
recv_5:
; process IIR_MSTAT here.
; If CTS and packet ready then
; enable the transmit buffer empty interrupt
; else
; disable the transmit buffer empty interrupt
;
cmp al, IIR_MSTAT
jne recv_1
push ds
mov ax, @data
mov ds, ax
mov dx, [msr]
pop ds
in al, dx
test al, MSR_CTS ; is CTS bit set
jz recv_5_1 ; no - disable xmit buffer empty int
jmp recv_2
recv_5_1:
jmp recv_2
;process IIR_RLS here
recv_1:
RETN
recv ENDP
;-------------------------------------------
; recv_char
; si = receive buffer = FP_OFF(rcv.tail)
; bx = receive count
; ds = data segment
; return:
; al = next char
; bx = pointer rcv.head
; zero flag:
; nz (0) : character received
; zr (1) : no more chars in this frame
;-----------------------------------------
recv_char PROC NEAR
push ds ; we assume that data segment has been set
mov ax, WORD PTR [rcv.tail+2]
mov ds, ax
lodsb
pop ds
cmp si, WORD PTR [rcv.buf_end]
jne recv_char_1
mov si, WORD PTR [rcv.buf]
recv_char_1:
mov bx, WORD PTR [rcv.head]
cmp si, bx ; if ((rcv.tail==rcv.head)|| //buffer collision
je recv_char_2 ; (_AL==FR_END))
cmp al, FR_END ; return (1);
; else return (0);
recv_char_2:
RETN
recv_char ENDP
;------------------------------
; recv_copy
; on entry:
; ds:si = packet_buffer
; cx = packet length
; do copy packet_to queue.write
;------------------------------
recv_copy PROC NEAR
les di, DWORD PTR [queue.write]
mov ax, es
or ax, di
jz fail
ulang:
rep movsb
mov WORD PTR [queue.write], di ; points to next entry list
fail:
RETN
recv_copy ENDP
;---------------------------------------
; INTERRUPT SERVICE ROUTINE
; almost all registers used, so
; we must save all of those.
; use register variables as possible
; because accesses to memory variable
; consuming much more time
;----------------------------------------
.CODE
PUBLIC C dummy_isr
dummy_isr PROC FAR
PUSH ax bx cx dx ds es si di bp
pushf
ASSUME ds:@data
mov ax, @data
mov ds, ax
mov al, [int_no] ;get hardware int #
add al, TMREOI ; make specific EOI dismissal
out BASE8259, al
popf
POP bp di si es ds dx cx bx ax
iret
ENDP
PUBLIC C recv_isr
recv_isr PROC FAR
;jmp short start
;in_recv_isr DW 0
start:
cmp cs:[in_recv_isr], 0
je no_re_enter
iret
no_re_enter:
PUSH ax bx cx dx ds es si di bp
pushf
mov cs:in_recv_isr, 1
ASSUME ds:@data
mov ax, @data
mov ds, ax
mov al, int_no ; Disable further specific device interrupt
call maskint
COMMENT *
I realize this re-entrancy trap is not perfect, you could be re-entered
anytime before the above instruction. However since the stacks have not
been swapped re-entrancy here will only appear to be a spurious interrupt.
*
;----------------------- CALL TRANSMITTER -----------------------
call xmit
;----------------------------------------------------------------
COMMENT *
; The following comment is wrong in that we now do a specific EOI command,
; and because we don't enable interrupts (even though we should).
;
; Chips & Technologies 8259 clone chip seems to be very broken. If you
; send it a Non Specific EOI command, it clears all In Service Register
; bits instead of just the one with the highest priority (as the Intel
; chip does and clones should do). This bug causes our interrupt
; routine to be reentered if:
; 1. we reenable processor interrupts;
; 2. we reenable device interrupts;
; 3. a timer or other higher priority device interrupt now comes in;
; 4. the new interrupting device uses a Non Specific EOI;
; 5. our device interrupts again.
; Because of this bug, we now completely mask our interrupts around
; the call to "recv", the real device interrupt handler. This allows us
; to send an EOI instruction to the 8259 early, before we actually
; reenable device interrupts. Since the interrupt is masked, we
; are still guaranteed not to get another interrupt from our device
; until the interrupt handler returns. This has another benefit:
; we now no longer prevent other devices from interrupting while our
; interrupt handler is running. This is especially useful if we have
; other (multiple) packet drivers trying to do low-latency transmits.
;
; The following is from Bill Rust, <wjr@ftp.com>
; this code dismisses the interrupt at the 8259. if the interrupt number
; is > 8 then it requires fondling two PICs instead of just one.
*
mov al, [int_no] ;get hardware int #
cmp al, BASEVEC ; see if its on secondary PIC
jg recv_isr_4
add al, TMREOI ; make specific EOI dismissal
out BASE8259, al
jmp short recv_isr_3 ; all done
recv_isr_4:
add al, 060H - BASEVEC ; make specific EOI (# between 9 & 15).
out 0a0H, al ; Secondary 8259 (PC/AT only)
mov al, 062H ; Acknowledge on primary 8259.
out BASE8259, al
recv_isr_3:
;-------- save packet data to buffer
call recv
cmp [recv_pkt_ready], 1 ; is a packet ready?
je ready ; yes, start read
jmp recv_exit ; no - skip to end
ready:
mov [recv_pkt_ready], 0 ; reset flag
sti
;===================== BEGIN DEPACKETIZE DATA HERE ======================
recv_frame:
cmp [packet_sem], 0 ; should we do this?
jne sema ; yes - process it
jmp next_sema ; no (packet_sem==0) => exit
sema:
mov bx, WORD PTR [queue.last]
cmp WORD PTR [queue.write], bx
jne not_full
;-------
; if queue.write reach queue.last, we have no choice thus just return
;-------
recv_frame_full:
mov [queue.status], QFULL
next_pkt:
mov [recv_pkt_ready], 1
jmp recv_exit
not_full:
mov si, WORD PTR [rcv.tail] ; get tail pointer
xor cx, cx ; count up the size here.
;---------- debug only, not needed int final linking
IF DEBUG EQ 1
mov bx, ds
mov dx, WORD PTR [rcv.tail+2]
mov ds, dx
mov ax, ds:[si]
mov ds, bx
mov al, 'A'
call print
ENDIF
;--------
;---- find how long message in the packet is
recv_frame_1:
call recv_char ; get a char.
je recv_frame_2 ; go if no more chars (al==FR_END)
cmp al,FR_ESC ; an escape?
je recv_frame_1 ; yes - don't count this char.
inc cx ; no - count this one.
jmp recv_frame_1
;--- now cx contains message length
recv_frame_2:
jcxz recv_frame_3 ;no data in packet? yes - free the frame
les di, DWORD PTR [queue.write]
mov ax, es
or ax, di
jnz trail_recv
xor cx, cx ; if (queue.write==NULL)
jmp recv_frame_3 ; queue.write[0] = 0 //force packet length to zero
; cx reset to avoid putting a non-packet message
; into queue
trail_recv:
mov bp, di ;remember first entry of queue line
cmp di, WORD PTR [queue.lastline]
jg recv_frame_full
; es:di -> packet buffer to be filled in
; cx = packet length
cmp cx, Q_WIDTH ;if (cx > Q_WIDTH)
jle recv_frame_ok ;
mov cx, Q_WIDTH ;align packet to proper width, 1 byte for size
;so will truncate char beyond the bound
recv_frame_ok:
mov si, WORD PTR [rcv.tail] ;resetting pointer to rcv.tail.
;----mov ax, cx
;----stosb ;queue.write[0] = cx
mov dx, 0 ;count
recv_frame_4:
cmp di, WORD PTR [queue.last] ; is it reach the end of queue ?
jne recv_frame_ready
recv_too_big:
mov [queue.status], QTOOBIG
;--- We don't need to store frame width anymore to simplify queue.
;---- The packet now contains data length to inform other task
;---- that frame has.
;----- (LUTFI, 16 Aug-95)
;-----mov BYTE PTR es:[bp], Q_WIDTH ;truncate packet
IF DEBUG EQ 1
mov al, 'M'
call print
ENDIF
;jmp next_sema
jmp next_pkt
recv_frame_ready:
call recv_char ; if ((recv.tail==recv.buf_end)||(al==FR_END))
je recv_frame_6 ; we're all done.
cmp al,FR_ESC ;an escape?
jne recv_frame_5 ;no - just store it.
call recv_char ;get the next character.
je recv_frame_6
cmp al,T_FR_ESC
mov al,FR_ESC ;assume T_FR_ESC
je recv_frame_5 ;yup, that's it - store FR_ESC
mov al,FR_END ;nope, store FR_END
recv_frame_5:
cmp dx, cx
jge recv_frame_6 ; beyond queue width, so break loop
stosb ;store the byte.
inc dx ;bytes stored
jmp recv_frame_4
recv_frame_6:
mov WORD PTR [rcv.tail], si ;we're skipped to the end
mov [queue.status], QOK ;sign queue status to OK state
jmp recv_frame_end
recv_frame_3:
mov WORD PTR [rcv.tail], si ;set to new location
recv_frame_end:
jcxz next_sema ; if no message, just skipped out
kecil:
add bp, Q_WIDTH
mov WORD PTR queue.write, bp ;next line of queue.
next_sema:
dec [packet_sem]
cmp [packet_sem], 0 ; are there more packets ready?
ja any_packet ; if (semaphore > 0)
jmp short recv_exit
any_packet:
jmp recv_frame ; yes - execute again
recv_exit:
; DDP - This is a BIG mistake. This routine SHOULD NOT enable interrupts.
; doing so can cause interrupt recursion and blow your stack.
; Processor interrupts SHOULD NOT be enabled after enabling device
; interrupts until after the "IRET". You will lose atleast 12 bytes
; on the stack for each recursion.
cli
mov al,[int_no] ; Now reenable device interrupts
call unmaskint
popf
POP bp di si es ds dx cx bx ax
sti
mov cs:in_recv_isr, 0 ; clear the re-entrancy flag
iret
recv_isr ENDP
;--------------------
; parameter:
; al : IRQ number
; register used:
; ax, cx, dx
;--------------------
maskint PROC NEAR
or al, al ;are they using a hardware interrupt?
je maskint_1 ;no, don't mask off the timer!
mov dx, MASKPORT ;assume the master 8259.
cmp al, BASEVEC ;using the slave 8259 on an AT?
jb mask_not_irq2
mov dx, MASKSLAVEPORT ;go disable it on slave 8259
sub al, BASEVEC
mask_not_irq2:
mov cl,al
in al,dx ;disable them on the correct 8259.
mov ah,1 ;set the bit.
shl ah,cl
or al,ah
;
;500ns Stall required here, per INTEL documentation for eisa machines
;
push ax
;in al, KBEOI ; 1.5 - 3 uS should be plenty
;in al, KBEOI
in al, KBEOI
out KBEOI,al
pop ax
out dx,al ; mask IRQ
maskint_1:
RETN
maskint ENDP
;--------------------
; parameter:
; al : IRQ number
; register used:
; ax, cx, dx
;--------------------
unmaskint PROC NEAR
mov dx, MASKPORT ;assume the master 8259.
mov cl, al
cmp cl, BASEVEC ;using the slave 8259 on an AT?
jb unmask_not_irq2 ;no
in al, dx ;get master mask
and al, NOT (1 shl 2) ; and clear slave cascade bit in mask
out dx, al ;set new master mask (enable slave int)
;
;500ns Stall required here, per INTEL documentation for eisa machines
;
push ax
in al, KBEOI ; 1.5 - 3 uS should be plenty
;********in al, KBEOI
;********in al, KBEOI
out KBEOI,al ; refresh keyboard stroke (LUTFI, 7/10/95)
pop ax
mov dx, MASKSLAVEPORT ;go enable interrupt on slave 8259
sub cl, BASEVEC
unmask_not_irq2:
in al,dx ;enable interrupts on the correct 8259.
mov ah,1 ;clear the bit.
shl ah,cl
not ah
and al,ah
; 500ns Stall required here, per INTEL documentation for eisa machines
; --- not needed, caused a problem with kbhit(). (lutfi, april 1995)
push ax
in al, KBEOI ; 1.5 - 3 uS should be plenty
mov ah, al ; save keyboard stroke (LUTFI, 11/12/95)
out KBEOI, al ; refresh keyboard stroke (LUTFI, 7/10/95)
pop ax
out dx,al ; un-mask IRQ
RETN
unmaskint ENDP
ENDS
END
;============================ END OF PROGRAM ===============================
; SLIP COMMUNICATION HANDLER
; Intel 386-based
; Receiver and Transmitter ISR
;
; * Thesis Project *
; M. Lutfi Shahab 13389011
; Department of Engineering Physics
; Institut Teknologi Bandung
; (c) Bandung, 1995
;
; First made: March 1995
; Last upated: 4-Jan 1996
;----------------------------------------------------------------------------
;
;
; 26/7/95 I found a bug on ISR. ISR should push flags to stack, but
; in older version, this didn't!
; I observed this bug affected keyboard flag checking
; 11 Nov 1995 In next version I plan to use extended USART controller,
; like Intel 82510 and 16550
; Detecting these chips done with writting appropriate setting
; code to FCR (FIFO control register) and detects their presences
; in extended fields of IIR (Interrupt Control Register).
; 8 Jan 1995 16 bit Cyclic Redundancy Check added.
;
;-----------------------------------------------------------------------------
;IFDEF TASM
PAGE 60, 120
;ENDIF
MODEL large, C
MASM
DEBUG EQU 0 ; debug
INCLUDE PIC.ASH
INCLUDE SLIP.ASH
.DATA
EXTRN base :WORD
EXTRN queue :tQUEUE
EXTRN baudrate :DWORD
EXTRN int_no :BYTE
EXTRN thr :WORD
EXTRN rdr :WORD ; base
EXTRN ier :WORD ; = base+1
EXTRN iir :WORD ; = base+2
EXTRN lcr :WORD ; = base+3
EXTRN mcr :WORD ; = base+4
EXTRN lsr :WORD ;
EXTRN msr :WORD ; = base+6
EXTRN scp :WORD ; scratch pad = base + 7
EXTRN installed :WORD ; initialization flag
EXTRN imr :WORD
EXTRN rcv :tCOMBUF
packet_sem DW 0
xmit_time DW 200 ;timeout
rcv_time DW 200
timeout DW 200
recv_pkt_ready DW 0
IF DEBUG EQ 1
isr_msg DB 'Ini di dalam recv_isr', 10, 13, '$'
isr_in_sema db 'Semaphore > 0', 10,13,'$'
ENDIF
.CODE
; This variable must be put in CODE SEGMENT
in_recv_isr DW 0
IF DEBUG EQ 1
;-------------------------
; al = charactrer to print
;-------------------------
print PROC NEAR
PUSH ax bx cx dx ds es si di bp ; Turbo Assembler's macro
mov bh, 0
mov bl, 07h
mov ah, 0eh
int 10H
POP bp di si es ds dx cx bx ax
RETN
print ENDP
;---------------------
; dx => offset string
;---------------------
print_msg PROC
PUSH ax bx cx dx ds es si di bp
ASSUME ds:@data
mov ax, @data
mov ds, ax
mov ah, 9h
int 10H
POP bp di si es ds dx cx bx ax
RET
print_msg ENDP
ENDIF
xmit PROC NEAR
retn
xmit ENDP
;--------------------
send_char PROC NEAR
PUSH ds dx cx
xchg ah,al ; put data char into ah
push ax
ASSUME ds:@data
mov ax,@data ; resetting ds to DGROUP
mov ds, ax
pop ax
xor cx,cx ; 64K retry counter
sendch1:
mov dx, [lsr]
in al, dx
jmp $+2 ; use time, prevent overdriving UART
jmp $+2
test al, LSR_THRE ; Transmitter (THRE) ready?
jnz sendch2 ; nz = yes
loop sendch1
stc ; carry set for failure
jmp short sendch3 ; timeout
sendch2:
xchg al, ah ; now send it
mov dx, [thr]
out dx, al ; send the byte
jmp $+2 ; use a little time
clc ; status of success
sendch3:
POP cx dx ds
RETN
send_char ENDP
; ------------------------------------------
; int _Send_SLIP_Packet(tSLIP_Pkt *pkt)
; ------------------------------------------
PUBLIC C _Send_SLIP_Packet
_Send_SLIP_Packet PROC C pkt:DWORD
;--------- Turbo Assembler automatically set stack frame
PUSH ds si
sti ; enable interrupts
lds si, pkt
;-------- MODIFIED because CRC16 addition ($LTF$, 8/JAN/95)
;mov cl, ds:[si].datalen
;xor ch, ch
;cmp cx, DATASIZE
;jle LESS_OR_EQU
;mov cx, DATASIZE ; align to DATASIZE
mov cx, PKTSIZE
LESS_OR_EQU:
;---add cx, 4 ; total packet length =
; sizeof(pktlen)+sizeof(datatype)+sizeof(crc)
; = 1 + 1 + 2 = 4 bytes
cld
mov al, FR_END ; Flush out any line garbage
call send_char
jc send_pkt_end ; c = failure to send
; Copy input to output, escaping special characters
send_pkt_1:
lodsb
cmp al, FR_ESC ;escape FR_ESC with FR_ESC and T_FR_ESC
jne send_pkt_2
mov al, FR_ESC
call send_char
jc send_pkt_end
mov al, T_FR_ESC
jmp short send_pkt_3
send_pkt_2:
cmp al, FR_END ;escape FR_END with FR_ESC and T_FR_END
jne send_pkt_3
mov al, FR_ESC
call send_char
jc send_pkt_end
mov al, T_FR_END
send_pkt_3:
call send_char
jc send_pkt_end
loop send_pkt_1 ; do cx user characters
mov al, FR_END ; terminate it with a FR_END
call send_char
jc send_pkt_end
mov ax, 1 ; success
jmp short keluar
send_pkt_end:
xor ax, ax ; error occured
keluar:
POP si ds
RET
_Send_SLIP_Packet ENDP
;------------------------------------
; static void near asyrxint(void)
; return:
; - packet_sem
; - recv_pkt_ready
;------------------------------------
asyrxint PROC NEAR
push ds ; save ds register
ASSUME ds:@data
mov ax, @data ; ds points to DGROUP !
mov ds, ax
mov ax, WORD PTR [rcv.buf_end+2] ; just check !!
xor bx, bx
cmp WORD PTR [baudrate+2], 0
jb short asyrxint_a
jbe check_again
jmp short asyrxint_a
check_again:
cmp WORD PTR [baudrate], 9600 ;below 9600 we're strictly
jb asyrxint_a ;interrupt driven
mov bx, rcv_time
asyrxint_a:
les di, DWORD PTR [rcv.head]
xor bp, bp ; set flag to indicate 1st char processed
mov si, packet_sem ; optimization
mov ah, LSR_DR
asyrxint_again:
xor cx, cx ; initialize counter
mov dx, [lsr]
asyrxint_in:
in al, dx ; check for data ready
test al, LSR_DR
jnz asyrxint_gotit ; yes - break out of loop
inc cx ; no - increase loop counter
cmp cx, bx ; timeout?
jae asyrxint_exit ; yes - leave
jmp asyrxint_in ; no - keep looping
asyrxint_gotit:
mov dx, [rdr]
in al, dx
; Process incoming data;
; If buffer is full, we have no choice but to drop the character
;
; segment of rcv.head and rcv.tail is same !!
; so just compare their offsets
cmp di, WORD PTR [rcv.tail]; is it buffer collision ?
jne asyrxint_ok ; none - continue
or si, si ; maybe - if there are packets
jnz asyrxint_exit ; yes exit
asyrxint_ok:
stosb
cmp di, WORD PTR [rcv.buf_end] ; did we hit the end of the buffer?
jne asyrxint_3 ; no.
mov di, WORD PTR [rcv.buf] ; yes - wrap around.
asyrxint_3:
cmp al,FR_END ; might this be the end of a frame?
jne asyrxint_reset ; no - reset flag and loop
inc si ; yes - indicate packet ready
cmp si, 1 ; determine if semaphore is <> 1
jne asyrxint_chk_flg ; yes - recv_frame must be active
inc recv_pkt_ready ; no - set flag to start recv_frame
IF DEBUG EQ 1
mov al, 'O'
call print
ENDIF
asyrxint_chk_flg:
cmp bp, 0 ; was this the first char?
jne asyrxint_1 ; no - exit handler
asyrxint_reset:
inc bp ; set 1st character flag
jmp asyrxint_again ; get another character
asyrxint_exit:
asyrxint_1:
mov WORD PTR [rcv.head], di ; set offset pointed by rcv.head
mov [packet_sem], si
exit:
pop ds
RETN
asyrxint ENDP
;--------------------
; registers used:
; ax, ds
;
;--------------------
recv PROC NEAR
recv_2:
push ds
mov ax, @data
mov ds, ax
mov dx, [iir]
pop ds
in al, dx ;any interrupts at all?
test al, IIR_IP
jne recv_1 ;no.
and al,IIR_ID
cmp al,IIR_RDA ;Receiver interrupt
jne recv_3
call asyrxint
jmp recv_2
recv_3:
recv_5:
; process IIR_MSTAT here.
; If CTS and packet ready then
; enable the transmit buffer empty interrupt
; else
; disable the transmit buffer empty interrupt
;
cmp al, IIR_MSTAT
jne recv_1
push ds
mov ax, @data
mov ds, ax
mov dx, [msr]
pop ds
in al, dx
test al, MSR_CTS ; is CTS bit set
jz recv_5_1 ; no - disable xmit buffer empty int
jmp recv_2
recv_5_1:
jmp recv_2
;process IIR_RLS here
recv_1:
RETN
recv ENDP
;-------------------------------------------
; recv_char
; si = receive buffer = FP_OFF(rcv.tail)
; bx = receive count
; ds = data segment
; return:
; al = next char
; bx = pointer rcv.head
; zero flag:
; nz (0) : character received
; zr (1) : no more chars in this frame
;-----------------------------------------
recv_char PROC NEAR
push ds ; we assume that data segment has been set
mov ax, WORD PTR [rcv.tail+2]
mov ds, ax
lodsb
pop ds
cmp si, WORD PTR [rcv.buf_end]
jne recv_char_1
mov si, WORD PTR [rcv.buf]
recv_char_1:
mov bx, WORD PTR [rcv.head]
cmp si, bx ; if ((rcv.tail==rcv.head)|| //buffer collision
je recv_char_2 ; (_AL==FR_END))
cmp al, FR_END ; return (1);
; else return (0);
recv_char_2:
RETN
recv_char ENDP
;------------------------------
; recv_copy
; on entry:
; ds:si = packet_buffer
; cx = packet length
; do copy packet_to queue.write
;------------------------------
recv_copy PROC NEAR
les di, DWORD PTR [queue.write]
mov ax, es
or ax, di
jz fail
ulang:
rep movsb
mov WORD PTR [queue.write], di ; points to next entry list
fail:
RETN
recv_copy ENDP
;---------------------------------------
; INTERRUPT SERVICE ROUTINE
; almost all registers used, so
; we must save all of those.
; use register variables as possible
; because accesses to memory variable
; consuming much more time
;----------------------------------------
.CODE
PUBLIC C dummy_isr
dummy_isr PROC FAR
PUSH ax bx cx dx ds es si di bp
pushf
ASSUME ds:@data
mov ax, @data
mov ds, ax
mov al, [int_no] ;get hardware int #
add al, TMREOI ; make specific EOI dismissal
out BASE8259, al
popf
POP bp di si es ds dx cx bx ax
iret
ENDP
PUBLIC C recv_isr
recv_isr PROC FAR
;jmp short start
;in_recv_isr DW 0
start:
cmp cs:[in_recv_isr], 0
je no_re_enter
iret
no_re_enter:
PUSH ax bx cx dx ds es si di bp
pushf
mov cs:in_recv_isr, 1
ASSUME ds:@data
mov ax, @data
mov ds, ax
mov al, int_no ; Disable further specific device interrupt
call maskint
COMMENT *
I realize this re-entrancy trap is not perfect, you could be re-entered
anytime before the above instruction. However since the stacks have not
been swapped re-entrancy here will only appear to be a spurious interrupt.
*
;----------------------- CALL TRANSMITTER -----------------------
call xmit
;----------------------------------------------------------------
COMMENT *
; The following comment is wrong in that we now do a specific EOI command,
; and because we don't enable interrupts (even though we should).
;
; Chips & Technologies 8259 clone chip seems to be very broken. If you
; send it a Non Specific EOI command, it clears all In Service Register
; bits instead of just the one with the highest priority (as the Intel
; chip does and clones should do). This bug causes our interrupt
; routine to be reentered if:
; 1. we reenable processor interrupts;
; 2. we reenable device interrupts;
; 3. a timer or other higher priority device interrupt now comes in;
; 4. the new interrupting device uses a Non Specific EOI;
; 5. our device interrupts again.
; Because of this bug, we now completely mask our interrupts around
; the call to "recv", the real device interrupt handler. This allows us
; to send an EOI instruction to the 8259 early, before we actually
; reenable device interrupts. Since the interrupt is masked, we
; are still guaranteed not to get another interrupt from our device
; until the interrupt handler returns. This has another benefit:
; we now no longer prevent other devices from interrupting while our
; interrupt handler is running. This is especially useful if we have
; other (multiple) packet drivers trying to do low-latency transmits.
;
; The following is from Bill Rust, <wjr@ftp.com>
; this code dismisses the interrupt at the 8259. if the interrupt number
; is > 8 then it requires fondling two PICs instead of just one.
*
mov al, [int_no] ;get hardware int #
cmp al, BASEVEC ; see if its on secondary PIC
jg recv_isr_4
add al, TMREOI ; make specific EOI dismissal
out BASE8259, al
jmp short recv_isr_3 ; all done
recv_isr_4:
add al, 060H - BASEVEC ; make specific EOI (# between 9 & 15).
out 0a0H, al ; Secondary 8259 (PC/AT only)
mov al, 062H ; Acknowledge on primary 8259.
out BASE8259, al
recv_isr_3:
;-------- save packet data to buffer
call recv
cmp [recv_pkt_ready], 1 ; is a packet ready?
je ready ; yes, start read
jmp recv_exit ; no - skip to end
ready:
mov [recv_pkt_ready], 0 ; reset flag
sti
;===================== BEGIN DEPACKETIZE DATA HERE ======================
recv_frame:
cmp [packet_sem], 0 ; should we do this?
jne sema ; yes - process it
jmp next_sema ; no (packet_sem==0) => exit
sema:
mov bx, WORD PTR [queue.last]
cmp WORD PTR [queue.write], bx
jne not_full
;-------
; if queue.write reach queue.last, we have no choice thus just return
;-------
recv_frame_full:
mov [queue.status], QFULL
next_pkt:
mov [recv_pkt_ready], 1
jmp recv_exit
not_full:
mov si, WORD PTR [rcv.tail] ; get tail pointer
xor cx, cx ; count up the size here.
;---------- debug only, not needed int final linking
IF DEBUG EQ 1
mov bx, ds
mov dx, WORD PTR [rcv.tail+2]
mov ds, dx
mov ax, ds:[si]
mov ds, bx
mov al, 'A'
call print
ENDIF
;--------
;---- find how long message in the packet is
recv_frame_1:
call recv_char ; get a char.
je recv_frame_2 ; go if no more chars (al==FR_END)
cmp al,FR_ESC ; an escape?
je recv_frame_1 ; yes - don't count this char.
inc cx ; no - count this one.
jmp recv_frame_1
;--- now cx contains message length
recv_frame_2:
jcxz recv_frame_3 ;no data in packet? yes - free the frame
les di, DWORD PTR [queue.write]
mov ax, es
or ax, di
jnz trail_recv
xor cx, cx ; if (queue.write==NULL)
jmp recv_frame_3 ; queue.write[0] = 0 //force packet length to zero
; cx reset to avoid putting a non-packet message
; into queue
trail_recv:
mov bp, di ;remember first entry of queue line
cmp di, WORD PTR [queue.lastline]
jg recv_frame_full
; es:di -> packet buffer to be filled in
; cx = packet length
cmp cx, Q_WIDTH ;if (cx > Q_WIDTH)
jle recv_frame_ok ;
mov cx, Q_WIDTH ;align packet to proper width, 1 byte for size
;so will truncate char beyond the bound
recv_frame_ok:
mov si, WORD PTR [rcv.tail] ;resetting pointer to rcv.tail.
;----mov ax, cx
;----stosb ;queue.write[0] = cx
mov dx, 0 ;count
recv_frame_4:
cmp di, WORD PTR [queue.last] ; is it reach the end of queue ?
jne recv_frame_ready
recv_too_big:
mov [queue.status], QTOOBIG
;--- We don't need to store frame width anymore to simplify queue.
;---- The packet now contains data length to inform other task
;---- that frame has.
;----- (LUTFI, 16 Aug-95)
;-----mov BYTE PTR es:[bp], Q_WIDTH ;truncate packet
IF DEBUG EQ 1
mov al, 'M'
call print
ENDIF
;jmp next_sema
jmp next_pkt
recv_frame_ready:
call recv_char ; if ((recv.tail==recv.buf_end)||(al==FR_END))
je recv_frame_6 ; we're all done.
cmp al,FR_ESC ;an escape?
jne recv_frame_5 ;no - just store it.
call recv_char ;get the next character.
je recv_frame_6
cmp al,T_FR_ESC
mov al,FR_ESC ;assume T_FR_ESC
je recv_frame_5 ;yup, that's it - store FR_ESC
mov al,FR_END ;nope, store FR_END
recv_frame_5:
cmp dx, cx
jge recv_frame_6 ; beyond queue width, so break loop
stosb ;store the byte.
inc dx ;bytes stored
jmp recv_frame_4
recv_frame_6:
mov WORD PTR [rcv.tail], si ;we're skipped to the end
mov [queue.status], QOK ;sign queue status to OK state
jmp recv_frame_end
recv_frame_3:
mov WORD PTR [rcv.tail], si ;set to new location
recv_frame_end:
jcxz next_sema ; if no message, just skipped out
kecil:
add bp, Q_WIDTH
mov WORD PTR queue.write, bp ;next line of queue.
next_sema:
dec [packet_sem]
cmp [packet_sem], 0 ; are there more packets ready?
ja any_packet ; if (semaphore > 0)
jmp short recv_exit
any_packet:
jmp recv_frame ; yes - execute again
recv_exit:
; DDP - This is a BIG mistake. This routine SHOULD NOT enable interrupts.
; doing so can cause interrupt recursion and blow your stack.
; Processor interrupts SHOULD NOT be enabled after enabling device
; interrupts until after the "IRET". You will lose atleast 12 bytes
; on the stack for each recursion.
cli
mov al,[int_no] ; Now reenable device interrupts
call unmaskint
popf
POP bp di si es ds dx cx bx ax
sti
mov cs:in_recv_isr, 0 ; clear the re-entrancy flag
iret
recv_isr ENDP
;--------------------
; parameter:
; al : IRQ number
; register used:
; ax, cx, dx
;--------------------
maskint PROC NEAR
or al, al ;are they using a hardware interrupt?
je maskint_1 ;no, don't mask off the timer!
mov dx, MASKPORT ;assume the master 8259.
cmp al, BASEVEC ;using the slave 8259 on an AT?
jb mask_not_irq2
mov dx, MASKSLAVEPORT ;go disable it on slave 8259
sub al, BASEVEC
mask_not_irq2:
mov cl,al
in al,dx ;disable them on the correct 8259.
mov ah,1 ;set the bit.
shl ah,cl
or al,ah
;
;500ns Stall required here, per INTEL documentation for eisa machines
;
push ax
;in al, KBEOI ; 1.5 - 3 uS should be plenty
;in al, KBEOI
in al, KBEOI
out KBEOI,al
pop ax
out dx,al ; mask IRQ
maskint_1:
RETN
maskint ENDP
;--------------------
; parameter:
; al : IRQ number
; register used:
; ax, cx, dx
;--------------------
unmaskint PROC NEAR
mov dx, MASKPORT ;assume the master 8259.
mov cl, al
cmp cl, BASEVEC ;using the slave 8259 on an AT?
jb unmask_not_irq2 ;no
in al, dx ;get master mask
and al, NOT (1 shl 2) ; and clear slave cascade bit in mask
out dx, al ;set new master mask (enable slave int)
;
;500ns Stall required here, per INTEL documentation for eisa machines
;
push ax
in al, KBEOI ; 1.5 - 3 uS should be plenty
;********in al, KBEOI
;********in al, KBEOI
out KBEOI,al ; refresh keyboard stroke (LUTFI, 7/10/95)
pop ax
mov dx, MASKSLAVEPORT ;go enable interrupt on slave 8259
sub cl, BASEVEC
unmask_not_irq2:
in al,dx ;enable interrupts on the correct 8259.
mov ah,1 ;clear the bit.
shl ah,cl
not ah
and al,ah
; 500ns Stall required here, per INTEL documentation for eisa machines
; --- not needed, caused a problem with kbhit(). (lutfi, april 1995)
push ax
in al, KBEOI ; 1.5 - 3 uS should be plenty
mov ah, al ; save keyboard stroke (LUTFI, 11/12/95)
out KBEOI, al ; refresh keyboard stroke (LUTFI, 7/10/95)
pop ax
out dx,al ; un-mask IRQ
RETN
unmaskint ENDP
ENDS
END
;============================ END OF PROGRAM ===============================
Wednesday, December 16, 2009
iptables rules for Anti Social-Net on Linux
List of IP addresses used by most popular social-networking sites:
69.63.181.11, fb1
69.63.181.12, fb2
69.63.181.15, fb3
69.63.181.16, fb4
69.63.187.17, fb5
69.63.187.19, fb6
69.63.184.142, fb7
69.63.186.30, fb8
69.63.184.31, fb9
69.63.184.28, fb10
69.63.184.30, fb11
69.63.184.31, fb12
216.86.150.58, plurk
168.143.162.36, twitter
69.63.181.11, fb1
69.63.181.12, fb2
69.63.181.15, fb3
69.63.181.16, fb4
69.63.187.17, fb5
69.63.187.19, fb6
69.63.184.142, fb7
69.63.186.30, fb8
69.63.184.31, fb9
69.63.184.28, fb10
69.63.184.30, fb11
69.63.184.31, fb12
216.86.150.58, plurk
168.143.162.36, twitter
Pseudo code:
<foreach ip above> do {
sudo iptables -A OUTBOUND -d <ip>/32 -j DROP
}
For firestarter, DROP is replaced with LSO
The above steps will create outbound firewall.
Subscribe to:
Posts (Atom)