Category : Assembly Language Source Code
Archive   : SIG8051.ZIP
Filename : SAMPLES.ASM

 
Output of file : SAMPLES.ASM contained in archive : SIG8051.ZIP
; support.asm - support routines
; (c) e. hegar - sytronincs, inc. 8/89
;
; name type descriptive info
; ========================= ==== ========================================

; alarm f
; bell f ....sound effects...put a piezo on the pwm
; n_beeps f .....output(s) to hear these...(will need
; ( a driver transistor)


; a2d_subsystem i a standalone interrupt driven a to d isr

; diagnostics_out i a standalone interrupt driven rs-232 isr (output)

; delay f
; real_time_clock i sample timekeeping functions..
; elapsed_t f

; 32_bit math module p a 32-bit integer math module

; clamp f how to keep a variable within bounds....

; watchdog f operation of the watchdog timer...t3
; (t3 must be hardware enable, see jumper C..
;


; type key - f=function no register mods allowed
; p=procedure register mods allowed
; i=isr standalone operation w/ diff. register set



; constants

warble_freq equ 21h ; warble period (.01 second increments) (3hz)
alarm_h_freq equ 0ah ; 500 hz
alarm_l_freq equ 2ah ; 2000 hz
bell_freq equ 0dh ; 1500 hz
bell_1_freq equ 15h ; 1000 hz

; 11,059,200 / (2*(1+xx)*255) = freq...500 hz= 42.39 = 2a
; 1500 hz= 13.4 = 0d
; 2000 hz= 9.84 = 0a


;---------==========----------==========---------=========---------
; alarm
;---------==========----------==========---------=========---------
; sounds warbling alarm 500 hz- 2000 hz, 1-8hz warble
;
; note - alarm and bell routines adjust freq of pwm outputs...
; routine leaves pwm freq at 1500 hz default...
;
; warble freq is a constant ( number of times per second to change)
; alarm_l_freq is a constant (low frequency desired)
; alarm_h_freq is a constant (high frequency desired)
; beeper_output is the pwm direct address desired for the beeper



alarm: equ $

mov pwm_freq,#alarm_l_freq ; set prescaler register to lo freq
mov beeper_output,#7fh ; 50% d.c.
mov a,#warble_freq ; warble period
call delay

mov pwm_freq,#alarm_h_freq ; set prescaler register to hi freq
mov a,#warble_freq ; warble period (in .01 sec steps)
call delay

mov beeper_output,#0ffh ; 0% d.c. - turn off alarm
mov pwm_freq,#bell_freq ; default freq for pwm ops..
ret


;---------==========----------==========---------=========---------
; bell
;---------==========----------==========---------=========---------
; sounds 1500hz tone
;
bell: equ $
mov beeper_output,#7fh ; turn on bell outputs..50% d.c.

mov a,#10
call delay ; delay for .1 sec

bell_end: mov beeper_output,#0ffh ; turn off bell outputs. 0% d.c.
ret



;---------==========----------==========---------=========---------
; n_beeps
;---------==========----------==========---------=========---------
; sounds n beeps...acc=n

n_beep: equ $

xch a,r0 ; save contents of r0
push acc

n_beep1: mov pwm_freq,#bell_1_freq ; set prescaler register to ~1khz
mov a,#0ah ; .1 second, more or less
mov beeper_output,#7fh ; 50% d.c.
call delay
mov beeper_output,#0ffh ; 0% d.c. - turn off alarm
mov a,#0ah
call delay
djnz r0,n_beep1


mov pwm_freq,#bell_freq ; default freq for pwm ops..
pop acc
mov r0,acc ; restore former contents of r0

ret

;---------==========----------==========---------=========---------
; delay
;---------==========----------==========---------=========---------
; acc= # .01 second clock ticks to count for delay.....
; max delay =.01 sec x 255 = 2.55 sec
;
old_msecs equ 60h ; a direct variable to save former time....
; may be located anywhere in direct ram...


delay: equ $
xch a,r3 ; free up a counter register, r3
push acc

delay0: mov old_msecs,msecs

delay1: mov a,msecs
cjne a,old_msecs,delay2 ; if they're different, clock has clicked

call watchdog ; if a watchdog timer is in use, call it.

sjmp delay1 ; else, wait for change


delay2: djnz r3,delay0 ; count down and repeat

pop acc ; restore r3 and exit
mov r3,a

ret

;-----=====-----=====-----=====-----=====-----======-----=====-----=====
; calculate elapsed time...
;-----=====-----=====-----=====-----=====-----======-----=====-----=====
;purpose: module accomodates rollover of minutes, seconds, hours...
; note : assumes same interval is being passed in both regs
;
; all intervals treated as if they are modulo 60 !!
;
;entry: a=current time b=time of event
;exit : a=elapsed time period, modulo 60
;
elapsed_t: equ $
clr c
push acc

subb a,b ; if current t > event time, all ok
jnc et_end

clr c ; if current t< event time, swap positions
mov a,b
add a,#3ch ; then, add 60 to a
pop b

subb a,b
ret

et_end: mov b,a ; get rid of pushed acc
pop acc
mov a,b
ret



;---------==========----------==========---------=========---------
; analog to digital subsystem.....isr
;---------==========----------==========---------=========---------
; the following code section implements an interrupt driven a2d subsystem.
; in this example, conversions are started elsewhere, most commonly in
; the real time clock routine upon exit. This ISR is then invoked upon
; the completion of the conversion.... A ram variable, analog_ch, keeps
; track of which channel was converted, and is also used to point to a
; ram variable which has been set aside for the storage of the result for
; each channel...The routine constantly updates the ram locations with the
; most recent conversion on each channel.
;
;
;
; An interrupt vector to the a2d_subsystem should be placed at ROM address
; 0053h and should appear in the source code as follows:
;
;
; org 0053h ; adc completion 0053h
; jmp a2d_subsystem
;
; the following code should be placed in the user's setup routine, or in
; an appropriate other location in the source code...
;
;
;
;
;
; MOV ANALOG_CH,#07H ; POINT TO CHANNEL 7
; MOV D_ADCON,ANALOG_CH ; SET MUX
; ORL D_IEN0,#40H ; ENABLE A/D INTERRUPT
;
;
; conversions are started with the following code statement
;
; orl d_adcon,#00001000b ; start a2d every click...
;
;
;
; the following is a sample data structure..
;
; name channel port pin scaling and units
; ============== = ====== === ==================
; analog_input1 equ 0 ; d_p5.0 1 0..40 a
; analog_input2 equ 1 ; d_p5.1 68 0..1 a
; analog_input3 equ 2 ; d_p5.2 67 0..50 deg c
; analog_input4 equ 3 ; d_p5.3 66 0..50 deg c
; analog_input5 equ 4 ; d_p5.4 65 0..150 vac
; analog_input6 equ 5 ; d_p5.5 64 0..30 vdc
; analog_input7 equ 6 ; d_p5.6 63 0..30 vdc
; analog_input8 equ 7 ; d_p5.7 62 0..30 vdc
;
;
; variable ram
; name loc channel name ch num address pin range units
; ===== ==== ============== ====== ========= === ===== =====
;

i_load equ 30h ; load_current 0 d_p5.0 1 0..40 a
i_charger equ 31h ; charge_current 1 d_p5.1 68 0..1 a
t_ambient equ 32h ; ambient_temp 2 d_p5.2 67 0..50 deg c
t_battery equ 33h ; battery_temp 3 d_p5.3 66 0..50 deg c
v_ac equ 34h ; ac_volts 4 d_p5.4 65 0..150 vac
v_battery equ 35h ; battery_volts 5 d_p5.5 64 0..30 vdc
half_ref equ 36h ; 1/2 rev voltage 6 d_p5.6 63 (2.5v) 7f..
tilt_switchequ 37h ; tilt switch inputs 7 d_p5.7 62 7f=ok, <40,>a0=tilt

;
;
;

analog_ch equ 4fh ; memory pointer used to point to current channel
; may be located anywhere desired...

d_adch: equ 0c6h ; direct address for a2d reading SFR

d_adcon: equ 0c5h ; direct address for a2d control SFR
; d_adcon.5 adex enable external start of adc (always to be 0)
; d_adcon.4 adci interrupt flag....1=conversion done
; d_adcon.3 acds start and status 0=done, 0=not started...1=busy
; d_adcon.2 addr2
; d_adcon.1 " 1 three bit mux address 0..7
; d_adcon.0 " 0
;
; n o t e : > > > > > > conversions are started in real_time_clock routine
; once per clock tick... (10 msecs)
a2d_subsystem: equ $

push psw ; preserve current registers...
push acc ; and accumulator
mov a,r0
push acc

mov r0,#i_load ; point to first 8 bit analog value in ram
mov a,analog_ch ; get current channel upon which conversion done
add a,r0
mov r0,a

mov @r0,d_adch ; read ad channel just converted and put in var

dec analog_ch ; point to next channel and limit from 7..0
anl analog_ch,#07h ; mask analog_ch ^ 00000111
anl d_adcon,#0c7h ; reset ad control bits...11000111
mov d_adcon,analog_ch ; set new mux address

pop acc ; restore environment
mov r0,a ; and exit
pop acc
pop psw

reti




;---------==========----------==========---------=========---------
; real time clock isr
;---------==========----------==========---------=========---------
t0_ovflo1: equ $
rtc: equ $

push psw ; save current registers
push acc
mov a,r0
push acc

clr tr0 ; stop timer and reload
mov th0,#high -t0period
mov tl0,#low -t0period
clr tf0
setb tr0 ; re-enable timer

inc msecs ; bump milliseconds. (10 ms clicks)

mov a,msecs
cjne a,#0ah,rtc_end ; 100 milliseconds passed?
inc centisecs ; yes, increment centisecs
mov msecs,#00h ; reinit msecs

t0_1: mov a,centisecs ; 100 centisecs passed?
cjne a,#0ah,rtc_end
mov centisecs,#00h ; yes, increment seconds, reinit centisecs
inc seconds

t0_2: mov a,seconds
cjne a,#3ch,rtc_end ; 60 seconds passed? no..exit
mov seconds,#00h ; else, increment minutes, reinit seconds
inc minutes

t0_3: mov a,minutes
cjne a,#3ch,rtc_end ; 60 minutes passed? no..exit
mov minutes,#00h ; else, increment hours, reinit minutes
inc hours

rtc_end:

orl d_adcon,#00001000b ; start a2d every click...

pop acc ; restore environment and exit
mov r0,a
pop acc
pop psw

reti

;---------==========----------==========---------=========---------
; diagnostics out isr
;---------==========----------==========---------=========---------
; a series of bytes is output to the RS-232 on an interrupt-driven
; basis via a pointer which rotates through a table of byte
; addresses defined within this routine....if enabled, at
; each interrupt the procesor will output the next nibble of byte
; info, spaces and crlf combinations as required.
;
; the following constants are used for the formatting of data going out
;
cr equ 0dh ; carriage return
lf equ 0ah ; line feed
spc equ 20h ; space
;
; this module uses three bit variables:
;
diagnostic_output equ 00h ; send out diagnostic data on/off
diag_space equ 01h ; send out a space during diagnostics
diag_high equ 02h ; send out high nibble or low?
;
; this module requires a single table pointer variable, diag_count,
; to keep track of where in the table we are.....
;
diag_count equ 030h ; a pointer to the table entry...
;
;
; the following interrupt vector should be placed in ROM:
;
; org 0023h ; serial io (uart) 0023h
; jmp diag_out ; diagnostic output isr...
;
;
; the following setup tasks are required in the user's setup routine...
;
;
; CLR EA ; disable all interrupts generally
; CLR ES ; clear serial int. specifically
; CLR RI ; if there are pending rs232 rec or xmits,
; CLR TI ; cancel and ignore
;
;--- SET TIMER 1 AS BIT RATE GENERATOR (9600 baud....)
;
; MOV TCON,#00H ; SHUT DOWN TIMERS, IF RUNNING
; MOV TMOD,#00100000B ; T1 IN MODE 2
; MOV TH1,#LOW -BITRATE ; SERIAL PORT BIT RATE
; MOV TL1,#LOW -BITRATE ; ... SET UP FIRST CYCLE!
;
;--- SET SERIAL PORT TO USE TIMER1 FOR BIT RATE, 8 DATA BIT MODE
;
; MOV SCON,#01000000B ; MODE 1, CLEAR "READY" FLAGS
;
; SETB TR1 ;---- ACTIVATE UART TIMER
; SETB EA ;---- ENABLE ALL INTERRUPTS
; SETB REN ;----- ENABLE THE SERIAL receive INTERRUPT
; SETB ES ;------enable serial interrupts
;
; INITIALIZE THE DIAGNOSTIC OUTPUT POINTER "DIAG_COUNT =00H "
; INITI " " DIAGNOSTIC SPACE INDICATOR " SETB DIAG_SPC
; must set diagnostics in motion by calling routine once or by
; putting a byte out. E.G., CR to sbuf OR BY HITTING ANY KEY ON
; A TEMINAL....HITTING A KEY IS THE CHOSEN METHOD...
;
; MOV DIAG_COUNT,#00H ; POINT TO FIRST DIAGNOSTIC ADDRESS IN TBL
; SETB DIAG_SPACE ; FIRST CHARACTER OUT WILL BE A SPACE..
; SETB DIAGNOSTIC_OUTPUT ; ENABLE DIAGNOSTICS, AS DESIRED....
;
; MOV SBUF,#CR ; SET DIAGNOSTIC OPERATIONS IN PROCESS
;
;
;
;
;
;
; - the following code is the actual interrupt service routine...finally
;
;


tbl_size: equ 11 ; size of the byte table... ( <= 27 decimal ) or

;tbl_size equ #diag_table_end-diag_table ; size of the byte table...

diag_out: equ $

clr es ; disable serial int's

push acc ; save acc, r0, and dptr
mov a,r0
push acc
push dph
push dpl

ti_int: clr ti
clr ri

jb diag_space,space_out ; check if this is 3rd time thru

mov a,diag_count ; which byte to output now?
mov dptr,#diag_table ; point to beginning of diag tbl..
movc a,@a+dptr ; get the address of the byte to send out

mov r0,a ; put into r0
mov a,@r0 ; get the internal ram byte @ r0

jnb diag_high,low_out ; send out the low nibble ?

high_out: swap a ; put high nibble in low spot
clr diag_high ; send out low, next time
clr diag_space ; and make sure you don't send out a space
sjmp nibble_out ; jump around next instructions

low_out: setb diag_space ; send out a space next time
clr diag_high

nibble_out: call h_2_a ; convert it to ascii
mov sbuf,a ; send out the rs232 without waiting
sjmp diag_end

space_out: mov sbuf,#spc
clr diag_space
setb diag_high ; send out high nibble next time

inc diag_count ; point to the next byte to send out
mov a,diag_count ; and perform a limit check on the number
cjne a,#tbl_size,diag_end

mov diag_count,#00h ; reinitialize pointer into diag_table

mov sbuf,#cr ; send cr
jnb ti,$ ; wait till done
clr ti

mov sbuf,#lf ; send lf and don't wait....

diag_end: equ $

pop dpl
pop dph
pop acc ; restore world
mov r0,a
pop acc
setb es ; renable serial int's

reti


; the following table should contain the addresses of the bytes which
; the user wishes to see coming out of the rs-232 and should appear in the
; order desired....
;
; most assemblers allow the format which appears below, but it may be
; necessary to supply the actual addresses literally, depending on the
; assembler being used...
;
;



diag_table: equ $

db half_ref ; analog inputs
db v_battery ;
db v_ac ;
db t_battery ;
db t_ambient ;
db i_charger ;
db i_load ;

db error_code0 ; current error code

db bitvar1 ; equ 20h ; bit variables
db bitvar2 ; equ 21h
db bitvar3 ; equ 22h

diag_table_end: equ $





;---------------------------------------------------------------
; hex to ascii routine
;---------------------------------------------------------------
; acc contains hex and returns ascii value (upper case)..of low nibble
h_2_a: equ $
anl a,#0fh ; mask out high bits
clr c ; clear carry for following tests
subb a,#0ah ; is it less than a?
jc ha_1 ; yes, then just add 3ah
add a,#07h ; otherwise, add 3a and 7 (41h)
ha_1: add a,#3ah
ret




;---------==========----------==========---------=========---------
; fake return from interrupt
;---------==========----------==========---------=========---------

reti_fake: equ $
reti


;=========-------========--------=========--------=========--------=====
; bcd conversion
;=========-------========--------=========--------=========--------=====
; the following code originates from ucontroller applications handbook
; by intel.
;
; entry - a = lower 8 bits of number to convert
; b = upper 8 bits
; r0 = pointer to packed bcd output string
;
; trashes r1,r2,r3,r4,r5
;
bcd_cnv: xch a,r0
mov r1,a
xch a,r0
mov r4,#digpr
bcd00a: mov @r1,#00h
inc r1
djnz r4,bcd00a
mov r3,#16
bcd00b: clr c
rlc a
xch a,b
rlc a
xch a,b
xch a,r0
mov r1,a
xch a,r0
mov r4,#digpr
mov r5,a
bcd00c: mov a,@r1
addc a,@r1
da a
mov @r1,a
inc r1
djnz r4,bcd00c
mov a,r5
jc bcd00d
djnz r3,bcd00b
clr c
bcd00d: ret


;---------==========----------==========---------=========---------
; 32 bit math routines for the 80c552
;---------==========----------==========---------=========---------
;
; these routines use a pseudo 32-bit accumulator set up in ram
; a 32-bit temp register, and an operand register which is 32 or 16 bits
; depending on what is needed.....
;
; the routines are started by placing the 16 or 32 bit operand into
; the appropriate register and calling the desired operation.
; on completion, the result will be in the 32bit accumulator.
;
; r6 and r7 are used to access high, middle and low portions of the
; results from the accumulator, via calls to low, mid and high_16
;
; r6:r7 = msb:lsb
;
; requires 12 direct ram locations and a few hundred bytes of code space

;buffer_32bit equ __

;load_32byte equ buffer_32bit
;load_16byte equ load_32byte+2
;
;mul_16byte equ load_16byte
;div_16byte equ load_16byte
;add_16byte equ load_16byte
;sub_16byte equ load_16byte
;add_32byte equ load_32byte
;sub_32byte equ load_32byte
;
;acc32_3 equ buffer_32bit+4
;acc32_2 equ acc32_3+1
;acc32_1 equ acc32_3+2
;acc32_0 equ acc32_3+3
;
;tmp_3 equ buffer_32bit+8
;tmp_2 equ tmp_3+1
;tmp_1 equ tmp_3+2
;tmp_0 equ tmp_3+3

clr_acc32:
; clear the pseudo 32-bit acc
mov acc32_3,#0
mov acc32_2,#0
mov acc32_1,#0
mov acc32_0,#0
ret




clr_32:
; clear the 32 and/or 16 bit operand register
mov load_32byte,#0
mov load_32byte+1,#0
clr_16: mov load_32byte+2,#0
mov load_32byte+3,#0
ret


load_16:
;load the lower 16 bits of the op registers with the value supplied
mov acc32_3,#0
mov acc32_2,#0
mov acc32_1,load_16byte
mov acc32_0,load_16byte + 1
ret

load_32:
;load all the op registers with the value supplied
mov acc32_3,load_32byte
mov acc32_2,load_32byte + 1
mov acc32_1,load_32byte + 2
mov acc32_0,load_32byte + 3
ret

swap_32:
; exchange op32 and acc32 registers
mov tmp_3,acc32_3 ; move acc32 to temp
mov tmp_2,acc32_2
mov tmp_1,acc32_1
mov tmp_0,acc32_0
mov acc32_3,load_32byte ; move op_32 to acc_32
mov acc32_2,load_32byte+1
mov acc32_1,load_32byte+2
mov acc32_0,load_32byte+3
mov load_32byte,tmp_3 ; move temp to op_32
mov load_32byte+1,tmp_2
mov load_32byte+2,tmp_1
mov load_32byte+3,tmp_0
ret


low_16:
;return the lower 16 bits of the op registers
mov r6,acc32_1
mov r7,acc32_0
ret

mid_16:
;return the middle 16 bits of the op registers
mov r6,acc32_2
mov r7,acc32_1
ret

high_16:
;return the high 16 bits of the op registers
mov r6,acc32_3
mov r7,acc32_2
ret

add_16:
;add the 16 bits supplied by the caller to the op registers
clr c
mov a,acc32_0
addc a,add_16byte + 1 ;low byte first
mov acc32_0,a
mov a,acc32_1
addc a,add_16byte ;high byte + carry
mov acc32_1,a
mov a,acc32_2
addc a,#0 ;propagate carry only
mov acc32_2,a
mov a,acc32_3
addc a,#0 ;propagate carry only
mov acc32_3,a
ret


add_32:
;add the 32 bits supplied by the caller to the op registers
clr c
mov a,acc32_0
addc a,add_32byte + 3 ;lowest byte first
mov acc32_0,a
mov a,acc32_1
addc a,add_32byte + 2 ;mid-lowest byte + carry
mov acc32_1,a
mov a,acc32_2
addc a,add_32byte + 1 ;mid-highest byte + carry
mov acc32_2,a
mov a,acc32_3
addc a,add_32byte ;highest byte + carry
mov acc32_3,a
ret

sub_16:
;subtract the 16 bits supplied by the caller from the op registers
clr c
mov a,acc32_0
subb a,sub_16byte + 1 ;low byte first
mov acc32_0,a
mov a,acc32_1
subb a,sub_16byte ;high byte + carry
mov acc32_1,a
mov a,acc32_2
subb a,#0 ;propagate carry only
mov acc32_2,a
mov a,acc32_3
subb a,#0 ;propagate carry only
mov acc32_3,a
ret


sub_32:
;subtract the 32 bits supplied by the caller from the op registers
clr c
mov a,acc32_0
subb a,sub_32byte + 3 ;lowest byte first
mov acc32_0,a
mov a,acc32_1
subb a,sub_32byte + 2 ;mid-lowest byte + carry
mov acc32_1,a
mov a,acc32_2
subb a,sub_32byte + 1 ;mid-highest byte + carry
mov acc32_2,a
mov a,acc32_3
subb a,sub_32byte ;highest byte + carry
mov acc32_3,a
ret

mul_16:
;multiply the 32 bit op with the 16 value supplied
mov tmp_3,#0 ;clear out upper 16 bits
mov tmp_2,#0
;generate the lowest byte of the result
mov b,acc32_0
mov a,mul_16byte+1
mul ab
mov tmp_0,a ;low-order result
mov tmp_1,b ;high_order result
;now generate the next higher order byte
mov b,acc32_1
mov a,mul_16byte+1
mul ab
add a,tmp_1 ;low-order result
mov tmp_1,a ; save
mov a,b ; get high-order result
addc a,tmp_2 ; include carry from previous operation
mov tmp_2,a ; save
jnc mul_loop1
inc tmp_3 ; propagate carry into tmp_3
mul_loop1:
mov b,acc32_0
mov a,mul_16byte
mul ab
add a,tmp_1 ;low-order result
mov tmp_1,a ; save
mov a,b ; get high-order result
addc a,tmp_2 ; include carry from previous operation
mov tmp_2,a ; save
jnc mul_loop2
inc tmp_3 ; propagate carry into tmp_3
mul_loop2:
; now start working on the 3rd byte
mov b,acc32_2
mov a,mul_16byte+1
mul ab
add a,tmp_2 ;low-order result
mov tmp_2,a ; save
mov a,b ; get high-order result
addc a,tmp_3 ; include carry from previous operation
mov tmp_3,a ; save
; now the other half
mov b,acc32_1
mov a,mul_16byte
mul ab
add a,tmp_2 ;low-order result
mov tmp_2,a ; save
mov a,b ; get high-order result
addc a,tmp_3 ; include carry from previous operation
mov tmp_3,a ; save
; now finish off the highest order byte
mov b,acc32_3
mov a,mul_16byte+1
mul ab
add a,tmp_3 ;low-order result
mov tmp_3,a ; save
; forget about the high-order result, this is only 32 bit math!
mov b,acc32_2
mov a,mul_16byte
mul ab
add a,tmp_3 ;low-order result
mov tmp_3,a ; save
; now we are all done, move the tmp values back into op
mov acc32_0,tmp_0
mov acc32_1,tmp_1
mov acc32_2,tmp_2
mov acc32_3,tmp_3
ret

div_16:
;this divides the 32 bit op register by the value supplied
mov r7,#0
mov r6,#0 ;zero out partial remainder
mov tmp_0,#0
mov tmp_1,#0
mov tmp_2,#0
mov tmp_3,#0
mov r1,div_16byte ;load divisor
mov r0,div_16byte+1
mov r5,#32 ;loop count
;this begins the loop
div_loop:
call shift_d ;shift the dividend and return msb in c
mov a,r6 ;shift carry into lsb of partial remainder
rlc a
mov r6,a
mov a,r7
rlc a
mov r7,a
;now test to see if r7:r6 >= r1:r0
clr c
mov a,r7 ;subtract r1 from r7 to see if r1 < r7
subb a,r1 ; a = r7 - r1, carry set if r7 < r1
jc cant_sub
;at this point r7>r1 or r7=r1
jnz can_sub ;jump if r7>r1
;if r7 = r1, test for r6>=r0
clr c
mov a,r6
subb a,r0 ; a = r6 - r0, carry set if r6 < r0
jc cant_sub
can_sub:
;subtract the divisor from the partial remainder
clr c
mov a,r6
subb a,r0 ; a = r6 - r0
mov r6,a
mov a,r7
subb a,r1 ; a = r7 - r1 - borrow
mov r7,a
setb c ; shift a 1 into the quotient
jmp quot
cant_sub:
;shift a 0 into the quotient
clr c
quot:
;shift the carry bit into the quotient
call shift_q
; test for competion
djnz r5,div_loop
; now we are all done, move the tmp values back into op
mov acc32_0,tmp_0
mov acc32_1,tmp_1
mov acc32_2,tmp_2
mov acc32_3,tmp_3
ret

shift_d:
;shift the dividend one bit to the left and return the msb in c
clr c
mov a,acc32_0
rlc a
mov acc32_0,a
mov a,acc32_1
rlc a
mov acc32_1,a
mov a,acc32_2
rlc a
mov acc32_2,a
mov a,acc32_3
rlc a
mov acc32_3,a
ret

shift_q:
;shift the quotent one bit to the left and shift the c into lsb
mov a,tmp_0
rlc a
mov tmp_0,a
mov a,tmp_1
rlc a
mov tmp_1,a
mov a,tmp_2
rlc a
mov tmp_2,a
mov a,tmp_3
rlc a
mov tmp_3,a
ret


;---------==========----------==========---------=========---------
; clamp subroutine
;---------==========----------==========---------=========---------
; checks value in accumulator against low_limit and high_limit
; and returns a value bewteen then two in acc
;
; routine requires the use of two variables in IRAM, high_limit and
; low_limit.
;
;
high_limit equ 030h
low_limit equ 031h
;
;
; entry - high_limit contains highest permissible 8-bit value
; low_limit contains lowest permissible 8-bit value
; acc contains value in question
;
; exit - acc is unchanged, at high_limit or at low_limit
;
;

clamp: equ $

push acc ; save two copies of the value passed in acc
push acc

lo_check: equ $
clr c ; make sure that carry is cleared
subb a,low_limit ; if a < low_limit, then a carry will happen
jnc hi_check
mov a,low_limit ; a is less than low, so set it to low_limit
dec sp ; clean up stack to remove excess two copies
dec sp ; .........
ret ; ...and return to caller

hi_check: equ $
pop acc ; get a copy of a, which was destroyed above..
clr c ; make sure that carry is cleared
subb a,high_limit ; if a>high limit, then no carry will result
jc clamp_end

mov a,high_limit ; a is > high, so set a=high_limit
dec sp ; remove excess copy of acc
ret ; ...and return to caller

clamp_end: equ $
; low_limit <= a <= high_limit, so exit..
pop acc ; get original copy of acc, which was ok
ret ; ... and return to caller

;-----=====-----=====-----=====-----=====-----======-----=====-----=====
; watchdog timer tickler
;-----=====-----=====-----=====-----=====-----======-----=====-----=====
;
; if the watchdog timer, t3, is being used, then this is the code to tickle it.
;
; call often enough to keep your program from resetting.....( < 500 msec or so)
;
;
watchdog:

orl pcon,#10h ; enable resetting of t3..
mov d_t3,#0 ; reset software watchdog...

ret





  3 Responses to “Category : Assembly Language Source Code
Archive   : SIG8051.ZIP
Filename : SAMPLES.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/