EE25M
25th April 2002
C24
page IV 6
1. Write code to decrement a 16-bit variable and test the result for zero, branching to Bothzero
if the result is zero. Can this be done using fewer lines of code and/or faster execution than
simply concatenating the two routines shown previously?
The concatenated routines can be made smaller by eliminating the first line from the test for zero.
It is redundant, just after the decrement of countl. They can be made faster by reversing the
order of the final branch so that the non-zero case branches before the non-zero case.
The tutorial group proposed an alternate solution which departed early, for all cases which either
borrowed from the hi-byte or had a non-zero result in the lo-byte without borrowing (see slides IV
for code.) The early departure didn’t save code space, but improved average performance.
2. Why does -7/3 yield a different remainder to 7/-3?
D
V
= Q; R
D =Q×V +R
−7 = (3)(−2) + (−1)
7 = (−3)(−2) + 1
The sign of the remainder depends only on the sign of the dividend.
EE25M
25th April 2002
C25
3. Design an algorithm and implement it in PIC assembly language to perform unsigned division
of a 24-bit number by an 8-bit number and produce a 24-bit quotient and 8-bit remainder.
Repeated subtraction is the simplest method. Two approaches were presented by students at the
tutorial session:
Jan: start from the MSB and subtract the 8 bit divisor from the current divisor byte, and the
remainder of the previous divisor byte. Keep an 8 bit counter for each answer byte.
Sanjay: perform 8 bit subtraction on the last byte, borrowing from the upper bytes as needed.
Use a full 24 bit increment for the answer.
Code for the latter approach follows:
div24by8
clrf
clrf
clrf
ans_lo
ans_mid
ans_hi
next
movf
subwf
btfsc
goto
movlw
subwf
btfsc
goto
subwf
btfsc
goto
divr,W
; subtract from low byte
divd_lo,F
STATUS,C
; check for borrow
inc_ans
1
divd_mid,F
STATUS,C
inc_ans
divd_hi,F
STATUS,C
inc_ans
; we are done here .... undo the last to leave
; remainder in divd_lo
movf
divr,W
addwf
divd_lo,F
goto
good_exit
inc_ans
incfsz
goto
incfsz
goto
incfsz
goto
goto
ans_lo,F
next
ans_mid,F
next
ans_hi,F
next
error_exit; there was a problem here .....
EE25M
25th April 2002
C26
4. Design an algorithm that works more efficiently than repeated subtraction for unsigned 8-bit
by 8-bit division. Implement it in PIC assembly language.
Method: Shift dividend until it is large enough to subtract the divisor. (see Stallings)
loop
chk
movf
movwf
clrf
movlw
movwf
Dividend,W
Q
A
8
cnt
bcf
rlf
rlf
STATUS,C
Q
A
movf
subwf
btfss
goto
movwf
bsf
Divisor,W
A,W
STATUS,C
chk
A
Q,0
decfsz cnt
goto loop
...
; final answer will be in Q
; final remainder will be in A
; if we did not borrow then carry is set
; is clear and we do not want to store A
; is set and we need to store A and change Q_0
; check the count
EE25M
25th April 2002
C27
5. Implement Booth’s algorithm for two signed 8 bit numbers in PIC assembly language. It is
presumed that the result will be 16 bits wide.
The following does not test for invalid cases.
LIST p=16F877
#include <p16F877.inc>
A
Q
M
EQU 0x20
EQU 0x21
EQU 0x22
count
EQU 0x23
Main
; result will appear in A:Q
ORG 0x00
nop
goto Main
; initialization code
movlw
movwf
movlw
movwf
movlw
movwf
clrf
0xB1
Q
0x80
M
0x10
count
A
; load up the numbers
movf
xorwf
M,W
Q,W
bthloop movf
andlw
xorwf
btfss
goto
movlw
Q,W
0x01
STATUS,F
STATUS,C
arshft
M
sub8
btfsc
subwf
Q,0
A,F
add8
btfss
addwf
Q,0
A,F
bcf
btfsc
bsf
rrf
rrf
STATUS,C
A,7
STATUS,C
A,F
Q,F
decfsz
goto
count,F
bthloop
arshft
done
sleep
END
; store the result sign
; check the pair of bits
; if the Q_0 bit is 1 then subtract
; check if we are done
EE25M
25th April 2002
C28
6. Design a Booth’s-like algorithm for the division of a signed 16 bit number by a signed 8 bit
number, and implement it in PIC assembly language. Booth’s like division will fail in the cases
where the divisor is 0: the invalid quotient would be ±1 (sign is opposite that of the dividend) a
remainder equal to the lower byte(s) of the dividend.
LIST p=16F877
#include <p16F877.inc>
M
EQU 0x20
cnt EQU 0x21
A
EQU 0x22
Q_hi
EQU 0x23
Q_lo
EQU 0x24
sgn EQU 0x25
temp
EQU 0x26
ORG 0x00
nop
init
movlw
movwf
M
0xFF
; load the divisor into M
clrf
A
movlw
movwf
movlw
movwf
0x00
Q_hi
0x01
Q_lo
btfsc
comf
Q_hi,7
A,F
movlw
movwf
.16
cnt
; load count with the number of bits in Q
movf
xorwf
movwf
M,W
Q_hi,W
sgn
; store the result sign in bit 7 of variable
; load the dividend into Q (hi,lo)
; sign extend the dividend from 16 to 24 bits in A:Q_hi:Q_lo
; Note: division by 0 will yield an invalid answer!!
loop
bcf
rlf
rlf
rlf
STATUS,C
Q_lo,F
Q_hi,F
A,F
movf
xorwf
andlw
btfss
; shift A,Q left 1 bit
M,W
; put M in W
A,W
0x80
; check if M and A have the same sign (A=A-M) or different signs (A=A+M)
STATUS,Z
EE25M
25th April 2002
goto
diffsgn
movf
subwf
goto
M,W
A,W
chk
diffsgn
movf
addwf
M,W
A,W
chk
; check if W now has same sign as A or (A=0 and Q_hi=0 and Q_lo=0)
; then set Q_0 to 1 and replace A with W
movwf
xorwf
andlw
btfsc
goto
temp
A,W
0x80
STATUS,Z
replace
movf
andlw
iorwf
Q_hi,W
0x80
temp,W
btfss
goto
STATUS,Z
next
replace
movf
temp,W
movwf
A
bsf Q_lo,0
next
C29
decfsz
goto loop
; successful
; also succesful if this is 0 and upper bit of Q is 0.
; unsuccessful but all zeros
cnt,F
; decrement count; if not zero, goto loop
sgnchk btfss
sgn,7
goto
done
comf
comf
Q_hi,F
Q_lo,F
incf
btfsc
incf
Q_lo,F
STATUS,Z
Q_hi,F
done
sleep
END
; correct for sign
EE25M
25th April 2002
C30
7. Presuming a two’s complement 8-bit integer representation, write an algorithm and implement
it in PIC assembly language to count the number of negative integers in a set of twenty
numbers starting at address 30h. [Past Paper 2001, No. 1(c)]
loop
clrf
movlw
movwf
btfsc
incf
incf
movf
sublw
btfsc
goto
...
cnt
0x30
FSR
INDF,7 ;
cnt,F
;
FSR,F
;
FSR,W
;
0x44
STATUS,Z
loop
;
check the sign bit
increment the count if it is set
move up one location
test to see if we are at location 0x44
proceed
EE25M
25th April 2002
C31
8. Write an algorithm and implement it in PIC assembly language to subtract two 24-bit numbers, Q 1 and Q 2, and store the result in R. Ensure that the carry flag reflects the result of
the subtraction. [Past Paper 2001, No. 2]
Note there is a bug in the Handout for 16 bit subtraction. The carry flag will be set incorrectly if
the two hi bytes are equivalent.
hi
movf
subwf
movwf
Q_1_lo,W
Q_2_lo,W
R_lo
; return Q_2 - Q_1
bcf
btfsc
bsf
temp, mbf
STATUS,C
temp, mbf
; use a bit in a temporary variable as my borrow flag
; carry is clear iff a borrow occurred
; remember to borrow from result
movf
subwf
movwf
Q_1_md,W
Q_2_md,W
R_md
btfss
goto
btfsc
bsf
decf
temp, mbf
hi
STATUS,Z
STATUS,C
R_md,F
bcf
btfsc
bsf
temp, mbf
STATUS,C
temp, mbf
movf
subwf
movwf
Q_1_hi,W
Q_2_hi,W
R_hi
btfss
return
temp, mbf
; do the borrow if needed
btfsc
bsf
decf
return
STATUS,Z
STATUS,C
R_hi,F
; if R_hi is zero
; set the carry then
; decrement
; do the borrow if needed
; if R_md is zero
; set the carry then
; do a decrement
; check for borrow from the hi byte
EE25M
25th April 2002
C32
Coursework A
Using PIC assembly, implement Booth’s algorithm for the multiplication of two 16-bit signed integers. Note that Booths algorithm does not work if 0x8000 is in the multiplicand. The following sample
answer corrects this case, and uses two’s complement addition to perform subtraction.
LIST p=16F877
#include <p16F877.inc>
A_hi
A_lo
EQU 0x20
EQU 0x21
Q_hi
Q_lo
EQU 0x22
EQU 0x23
M_hi
M_lo
EQU 0x24
EQU 0x25
nM_hi
nM_lo
EQU 0x26
EQU 0x27
count
EQU 0x28
storage EQU 0x29
ORG 0x00
nop
goto Main
; initialization code
;
; subroutine tc16 replaces the 16 bit number stored
; HI:LO at the location specified by the FSR,
; with its two’s complement.
; returns with carry flag set if there was an overflow
;
tc16
comf
INDF,F
; complement hi byte
incf
FSR ,F
comf
INDF,F
; complement lo byte
tc16inc incf
INDF,F
; now the regular increment of lo byte
btfsc
STATUS,Z
bsf STATUS,C
; set the carry if we overflow
decf
FSR, F
btfss
STATUS,C
; if no overflow then leave
return
incfsz INDF,F
; else increment hi byte
bcf
STATUS,C
; clear flag if there was no overflow
return
; all done
EE25M
Main
25th April 2002
movlw
movwf
movlw
movwf
movlw
movwf
movwf
movlw
movwf
movwf
0xB1
Q_hi
0x00
Q_lo
0x80
M_hi
nM_hi
0x00
M_lo
nM_lo
movlw
movwf
0x10
count
clrf
movlw
movwf
call
STATUS
nM_hi
FSR
tc16
clrf
clrf
clrf
clrf
A_hi
A_lo
storage
STATUS
movf
xorwf
movwf
M_hi,W
Q_hi,W
storage
; store the result sign
bthloop movf
andlw
xorwf
btfss
goto
clrw
btfsc
addlw
addlw
movwf
Q_lo,W
0x01
STATUS,F
STATUS,C
ashft32
; check the pair of bits
Q_lo,0
0x02
M_lo
FSR
; if the Q_lo bit is 1 then subtract
add16
INDF,W
A_lo,F
FSR ,F
INDF,W
STATUS,C
A_hi,F
A_hi,W
; addition of M (or -M) to A
movf
addwf
decf
movf
btfsc
incfsz
addwf
; load up the numbers
; store the negative multiplier
; clear out the flags
; load up FSR with M or -M
C33
EE25M
25th April 2002
movwf
ashft32 bcf
btfsc
bsf
rrf
rrf
rrf
rrf
done
A_hi
STATUS,C
A_hi,7
STATUS,C
A_hi,F
A_lo,F
Q_hi,F
Q_lo,F
; 32 bit arithmetic shift for
; A_hi,A_lo,M_hi,M_lo
decfsz
goto
count,F
bthloop
; check if we are done
; fudge
movf
xorwf
btfss
goto
for the 8000 case -- check if sign is correct.
A_hi,W
storage,F
storage,7
done
movlw
movwf
call
comf
comf
btfss
goto
Q_hi
FSR
tc16
A_lo,F
A_hi,F
STATUS,C
done
incfsz
bcf
btfsc
incfsz
bcf
A_lo,F
STATUS,C
STATUS,C
A_hi,F
STATUS,C
sleep
END
; note carry is not right
; at the end here!!
C34
EE25M
25th April 2002
C35
CourseWork B
Lab Exercise 1 – A/D settling time is 20µs and sampling time is 12 ∗ TAD . For a 4MHz clock and an
A/D sampling frequency of Fosc/8, successive samples will be at least 44µs apart. The lowest prescaler
that can be used with TMR0 is 1:2. For a prescale value of 1:1 assign the prescaler to the Watchdog
timer.
LIST p=16f877
INCLUDE "p16f877.inc"
PotRead EQU
0x20
ORG
nop
goto
0x00
Start
BANKSEL
clrf
clrf
movlw
movwf
PORTD
PORTD
PORTC
B’01000001’ ;
ADCON0
; Fosc/8, A/D enabled, Sample Channel 0
BANKSEL
movlw
movwf
clrf
clrf
movlw
movwf
OPTION_REG
B’10001000’ ; TMR0 w/no prescaler
OPTION_REG
TRISD
TRISC
B’00001110’ ; Left justify, 1 analog channel
ADCON1
; VDD and VSS references
; for ICD
Start
BANKSEL PORTD
Main
movlw
movwf
bcf
.236
; 256-20=236
TMR0
; Timer 0 flag will go off after 20 cycles
INTCON,T0IF
Loop
btfss
goto
INTCON,T0IF
Loop
bsf
ADCON0,GO
Wait
btfss
PIR1,ADIF
goto Wait
movf
movwf
ADRESH,W
PotRead
swapf
movlw
andwf
movf
PotRead,F
0x0F
PotRead,F
PotRead,W
EE25M
25th April 2002
call
movwf
7seg
PORTC
bcf
rrf
call
movwf
STATUS,C
PotRead,W
mbar
PORTD
goto
Loop
; table lists 7 seg pins as
7seg
andlw
0x0F
addwf
PCL,F
retlw
B’00111111’
retlw
B’00000110’
retlw
B’01011011’
retlw
B’01001111’
retlw
B’01100110’
retlw
B’01101101’
retlw
B’01111101’
retlw
B’00000111’
retlw
B’01111111’
retlw
B’01100111’
retlw
B’01011111’
retlw
B’01111100’
retlw
B’01011000’
retlw
B’01011110’
retlw
B’01111011’
retlw
B’01110001’
mbar
andlw
addwf
retlw
retlw
retlw
retlw
retlw
retlw
retlw
retlw
END
0x07
PCL,F
B’00000001’
B’00000011’
B’00000111’
B’00001111’
B’00011111’
B’00111111’
B’01111111’
B’11111111’
dp, g, f, e, d, c, b, a
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
0
1
2
3
4
5
6
7
8
9
a
b
c
d
e
f
;
;
;
;
;
;
;
;
0
1
2
3
4
5
6
7
C36
EE25M
25th April 2002
C37
Lab Exercise II – PWM frequency choice: For convenience with the ADRESH value between 0 and 255,
choose PR2 so that 255 equals 100% duty cycle ( i.e. PR2=254) and move ADRESH directly into CCP1RL
without modification.
CCP1CON<5:4> will be 002 .
With a 4 MHz clock, valid prescaler values for Timer2 include 1:1, 1:4, 1:16, corresponding to PWM
periods (frequencies) of 255µs (3.92kHz), 1020µs (980Hz), 4080µs (245Hz).
When sampling two A/D channels, care must be taken to ensure that the input settles before sampling. With a full Timer 0 overflow (256µs)this should be ok.
LIST p=16f877
INCLUDE "p16f877.inc"
PotRead
Intensity
EQU
EQU
0x20
0x21
w_temp
EQU
status_temp EQU
0x22
0x23
Init
ORG
nop
goto
0x00
Init
ORG
goto
0x04
ISR
bcf
btfsc
goto
INTCON, GIE
INTCON,GIE
Init
BANKSEL
clrf
clrf
movlw
movwf
PORTD
PORTD
PORTC
B’01000001’ ;
ADCON0
; Fosc/8, A/D enabled, Sample Channel 0
; for ICD
BANKSEL PIE1
bsf
PIE1,ADIE
movlw
movwf
bsf
B’10001000’ ; TMR0 w/no prescaler
OPTION_REG
INTCON,T0IE
clrf
bcf
movlw
movwf
TRISD
TRISC,2
; setup pin for PWM output
B’00000100’ ; Left justify, 3 analog channels
ADCON1
; VDD and VSS references
movlw
movwf
.254
PR2
BANKSEL PORTD
; setup PWM frequency
EE25M
Loop
25th April 2002
clrf
clrf
CCP1RL
CCP1CON
movlw
movwf
B’00000100’
T2CON
movlw
movwf
B’00001100’
CCP1CON
clrf
clrf
Intensity
PotRead
bsf
bsf
OPTION_REG, PEIE
OPTION_REG, GIE
movf
movwf
movf
movwf
goto
Intensity,W
CCP1RL
PotRead,W
PORTD
Loop
movwf
movf
movwf
w_temp
STATUS,W
status_temp
btfsc
call
btfsc
call
INTCON,T0IF ; presume we are in Bank 0
AD_Start
PIR1, ADIF
AD_Done
movf
movwf
swapf
swapf
status_temp,W
STATUS
w_temp,F
w_temp,W
ISR
Poll
retfie
AD_Start
bsf
bcf
return
ADCON0,GO
INTCON,T0IF
movf
btfsc
movwf
btfss
movwf
bcf
return
ADRESH,W
ADCON0,CHS0 ; if channel 1 put it in Intensity
Intensity
ADCON0,CHS0 ; if channel 0 put it in PotRead
PotRead
PIR1,ADIF
AD_Done
END
C38
EE25M
25th April 2002
C39
page IV 10
1. Many CPU’s provide logic for performing arithmetic on packed decimal numbers. Although
the rules for decimal arithmetic are similar to those for binary operations, the decimal results
may require some corrections to the individual digits if binary logic is used. Consider the
decimal addition of two unsigned numbers. If each number consists of N digits, then there
are 4N bits in each number. The two numbers are to be added using a binary adder. Suggest
a simple rule for correcting the result.
Add 6 to each nibble of the addition result. If the nibble overflows into the next nibble, then
it was not a valid BCD nibble previously, and it is now correct. The next nibble up should be
incremented. If the nibble did not overflow into the next nibble, then it was valid, and should be
restored.
Perform addition in this fashion on the numbers 1698 and 1786. [Sta00, 9.1]
The decimal numbers 169810 and 178610 are represented as the packed BCD hex numbers: 169816
and 178616 . Standard binary addition will yield the result 2E1E16 . Starting with the least
significant nibble, add 6 to each nibble, test for overflow, and reverse if not. 2E1E 16 + 000616 =
2E2416 – overflow so is ok
2E2416 + 006016 = 2E8416 – no overflow so undo
2E2416 + 060016 = 342416 – overflow so is ok
342416 + 600016 = 942416 – no overflow so undo
Final answer is 342410 .
2. The tens complement of the decimal number X is defined to be 10N − X, where N is the
number of digits in the number. Describe the use of tens complement representation to
perform decimal subtraction.
To perform decimal subtraction, take the ten’s complement of the subtrahend (number below)
and add it to the minuend(number above).
Illustrate the procedure by subtracting (0326)10 from (0736)10 . [Sta00, 9.2]
073610 − 032610 = 073610 + (104 − 032610 ) = 073610 + 9674( 10) = 1041010
Uppermost digit will not fit in the 4 digit result. Remaining digits give the correct answer.
What purpose does ten’s complement arithmetic serve in BCD arithmetic?
BCD represents individual decimal digits separately. BCD subtraction can therefore be done by
using the BCD ten’s complement of the subtrahend and adding it to the BCD minuend using
standard BCD addition.
3. BCD is not the only means of representing decimal numbers. The ASCII character set
defines a representation of characters as 7 bit numbers. The digit characters 0 through 9 are
represented as 011 0000 thru 011 1001. Using this information write routines to correctly
add and subtract two ASCII digits. (Note: The carry flag should be set for overflow, or no
borrow respectively)
Ascii_add
movf
addwf
andlw
iorlw
bcf
btfsc
bsf
bcf
return
A,W
B,W
0x0F
0x30
STATUS,C
STATUS,DC
STATUS,C
STATUS,DC
;
;
;
;
;
;
perform A+B where A and B
are ASCII encoded digits
clear the upper bits
set the upper bits
set the CARRY flag if the
add generated a digit carry
EE25M
25th April 2002
C40
page IV 12
1. Show how the following floating point calculations are performed (where significands are
truncated to 4 decimal digits) [Sta00, 8.25–8.27]
(a) 0.5566 × 103 + 0.7777 × 103
(0.5566 + 0.7777) × 103 = 1.3343 × 103 = 0.1334 × 102
(b) 0.3344 × 102 + 0.8877 × 10−1
(0.3344 + 0.8877 × 10−1−2=−3 ) × 102 = 0.3352 × 102
(c) 0.7744 × 10−2 − 0.6666 × 10−2
(0.7744 − 0.6666) × 10−2 = 0.1078 × 10−2
(d) 0.8844 × 10−2 − 0.2233 × 100
(0.8844 − 0.2233 × 100−(−2)=2 × 10−2 = −21.4467 × 10−2 = −0.2145 × 100
(e) (0.2255 × 102 ) × (0.1234 × 101 )
(0.2255 × 0.1234) × 102+1=3 = 0.02782 × 103 = 0.2782 × 102
(f) (0.8833 × 103 ) ÷ (0.5555 × 105 )
(0.8833 ÷ 0.5555) × 103−5=−2 = 1.5901 × 10−2 = 0.1590 × 10−1
2. Any floating point representation used in a computer can represent only certain real numbers
exactly; all others must be approximated. If A’ is the stored value approximating the real
0
value A then the relative error r is expressed as: r = A−A
A .[Sta00, 8.21–8.24]
(a) Represent the decimal quantity +0.4 in the following floating point format: base = 2;
exponent: biased 4 bits; significand 7 bits.
This is a recurring decimal in base 2: 0.410 = 0.011001100110....2
Truncating we get: 0.110011002 × 21
In floating point format, the sign bit is 0, the significand is 1001100 and the biased exponent
is 1001 (presumed that the bias is 7 for the 4 bit exponent).
What is the relative error?
The stored truncated value is equivalent to 0.398437510 . The relative error is therefore:
0.0039062510 or approximately 0.4%.
(b) If A = 1.427, find the relative error if A is truncated to 1.42 and if it is rounded to 1.43.
For truncation: 0.49% For rounding: -0.21%
(c) Numerical values A and B are stored in the computer as approximations A 0 and B 0 .
Neglecting any further truncation or roundoff errors, show that the relative error of the
product is approximately the sum of the relative errors in the factors.
Rearranging the equation we get: A0 = A(1 − r). Therefore the product A0 B 0 = AB(1 −
rA )(1 − rB ) = AB(1 − (rA + rB − rA rB )) If the relative errors were small (i.e. much less
than 1), the product term is negligible and rAB ≈ rA + rB
(d) One of the most serious errors in computer calculations occurs when two nearly equal
numbers are subtracted. Consider A = 0.22288 and B = 0.2221. The computer truncates all values to four decimal digits. Thus A0 = 0.2228 and B 0 = 0.2221.
i. What are the relative errors for A0 and B 0 ? rA = 0.036%,rB = 0%
ii. What is the relative error for C 0 = A0 − B 0 ? C = 0.00078, C 0 = 0.0007, rC = 10%
EE25M
25th April 2002
C41
3. Typically floating point numbers are represented using a minimum of 32 bits.
The IEEE standard 754 standard defines a ”single” format 32 bit floating point number as a
sign bit followed by an 8 bit biased exponent, followed by a 23 bit significand (representing
the normalised 24 bit binary fraction 0.1xxx xxxx xxxx xxxx xxxx xxxx).
Floating point numbers in the CCS compiler for the PIC16F877, place a biased 8 bit exponent
first, followed by the sign bit and then a 23 bit significand (representing the normalised 24
bit binary fraction 0.1xxx xxxx xxxx xxxx xxxx xxxx).
The difference is in the location of the sign bit. Suggest possible advantages/disadvantages
of placing the sign bit in either position.
If the sign bit is at the beginning, then floating point numbers can easily be tested for relative
magnitude, by considering the front bits for sign and biased exponent as a two’s complement
integer. Sorting by these bits will group numbers of similar value.
If the sign bit is placed after the exponent, then the initial byte, can easily be extracted for use in
exponent manipulation.
page IV 13
1.
(a) For the following data structures, draw the big-endian and little-endian layouts, using the format
of Figure 9.18 (see handout) and comment on the results. [Sta00, 9.17]
i. struct {
double i; // 0x1112131415161718
} s1;
00 01 02 03 04 05 06 07
Big
11 12 13 14 15 16 17 18
Little 18 17 16 15 14 13 12 11
ii. struct {
int i; // 0x11121314
int j; // 0x15161718
} s2;
00 01 02 03 04 05 06 07
Big
11 12 13 14 15 16 17 18
Little 14 13 12 11 18 17 16 15
iii. struct {
short i; // 0x1112
short j; // 0x1314
short k; // 0x1516
short l; // 0x1718
} s3;
00 01 02 03 04 05 06 07
Big
11 12 13 14 15 16 17 18
Little 12 11 14 13 16 15 18 17
In Big-endian layout, all the data structures appear identical, however in the little endian layout
the data order depends on the type of data being stored.
EE25M
25th April 2002
C42
(b) Based on the above, write a small C program which determines the endianness of a machine and
reports the results. [Sta00, 9.19]
#include <stdio.h>
void main()
{
int i;
// i is a 32 bit integer
BYTE *b; // b is a single byte pointer
i=1;
b=&i;
// now test to see which of the four bytes is non-zero,
// and which end of the byte the
// bit is set at ...
if ((b[0]==0x00) && (b[3]!=0x00))
{
if (b[3]==0x01)
printf("Big endian, LSB at bit 0");
else if (b[3]==0x80)
printf("Big endian, LSB at bit 7");
else
printf("Big endian");
}
else if ((b[0]!=0x00) &&(b[3]==0x00))
{
if (b[0]==0x01)
printf("Little endian, LSB at bit 0");
else if (b[0]==0x80)
printf("Little endian, LSB at bit 7");
else
printf("Little endian");
}
else
{
printf("Something went wrong in the test ....");
}
}
EE25M
25th April 2002
C43
page IV 16
1. The notes contain example code for a lookup table using the DT directive, which presumes
that there was no need to switch banks within the table. Write similar code which will operate
correctly even when the table spans a program bank boundary.
The following code is from PIC Microcontroller Pocket Reference by M. Predko. HIGH and LOW
are assembler directives which will return the high and low bytes of the following program address.
The code operates by determining if the value we want to lookup is in this bank, or the next
bank.
Table
movwf
movlw
movwf
movf
addlw
btfsc
incf
movwf
TableEntries
DT
Temp
HIGH
PCLATH
Temp,w
TableEntries
;
;
;
;
return table value of contents of "w"
save the table index
get the current 256 instruction block
store it so that the next jump is correct
LOW
TableEntries
STATUS,C
PCLATH,F
PCL
; if our entry is in the next bank, increment PCLATH
; writes the correct address to the Program counter
"Table",0
; now declare data as normal.
2. Write a program containing a lookup table for multiplication by 7 in the data EEPROM. The
lookup table should be accessed with a subroutine called mul7 which will take the value in
the working register as it’s argument, and return the answer in the working register. Assume
that mul7 is only called with inputs from 0 to 15.
; note that this routine changes bank .. the main code should be careful!!
mul7
addlw
0x60
; find offset from table start
BANKSEL EEADR
movwf
EEADR
BANKSEL EECON1
bcf
EECON1, EEPGD ;Point to Data memory
bsf
EECON1, RD
;Start read operation
BANKSEL EEDATA
movf
EEDATA, W
;W = EEDATA
return
ORG 2160
; Table starts at data EEPROM location 0x60
DE .0,.7,.14,.21,.28,.35,.42,.49,.56,.63,.70,.77,.84,.91,.98,.105
3. (a) It is possible to store a data structure which is either wider or narrower than the data
word size, by simply storing the bits of the data structure consecutively. What are the
implications for retrieving data from memory?
Where a data structure consists of multiple parts which need to be accessed individually,
storing the structure in consecutive bits, may mean that multiple data-words have to be
retrieved, and artificially ”joined” in order to access the part.
EE25M
25th April 2002
C44
(b) Boundary alignment is the practice of starting new blocks of data in a new data-word
block, regardless of the space remaining in the previous data-word block. What possible
advantage does such a scheme offer?
The advantage is that a new part will always start at the beginnning of a dataword and
fetching the part will require a mininal number of datawords.
(c) A particular data structure contains an 10 bit unsigned integer, two 7 bit characters,
and two status flags. Write some sample code for the PIC which retrieves the specified
26-bit data structure from the program memory, and stores it in 5 registers using:
The variables are presumed to be stored in Int hi, Int lo, char a, char b, and Flags a, Flags b.
To retrieve a dataword from the program memory we use the following procedures:
GetPWord
BANKSEL ADDRL
movf ADDRL, W
BANKSEL EEADR
movwf EEADR
BANKSEL ADDRH
movf ADDRH,W
BANKSEL EEADRH
movwf EEADRH
;address to read
BANKSEL EECON1
bsf EECON1, EEPGD
bsf EECON1, RD
nop
nop
;Point to Program memory
;Start read operation
;Required two NOPs
;
BANKSEL
movf
BANKSEL
movwf
BANKSEL
movf
BANKSEL
movwf
EEDATA
EEDATA, W
DATAL
DATAL
EEDATH
EEDATH,W
DATAH
DATAH
;Write the
;address bytes
;for the desired
;DATAL = EEDATA
;DATAH = EEDATH
return
GetNextPWord
; note this does not check for bad increments/addresses
incf
btfsc
incf
call
return
ADDRL,F
STATUS,Z
ADDRH,F
GetPWord
EE25M
25th April 2002
C45
i. packing with boundary alignment (i.e. 2 data words per structure)
In this case, the entire structure has been aligned to the dataword boundary. In this
case we just need two datawords, and we need to extract the relevant bits.
13 12 11 10 9
8
7 6 5
address
4
3
int
Inthi < 1 : 0 >,Intlo < 7 : 0 >
2
1
0
13 12 11 10 9
char
Chara < 6 : 0 >
8
7
6
5
4 3
address+1
char
flag
Charb < 6 : 0 >
F laga < 0 >
2
1
flag
F lagb < 0 >
N/U
; presume that the starting address was already loaded into ADDRL, ADDRH
call
GetPWord
swapf
DATAH,W
andlw
0x0F
movwf
Int_hi
swapf
andlw
movwf
DATAH,W
0xF0
Int_lo
swapf
andlw
iorwf
DATAL,W
0x0F
Int_lo,F
swapf
andlw
movwf
bcf
rrf
DATAL,W
0xF0
Char_a
STATUS,C
Char_a
call
GetNextPWord
movf
movwf
rlf
swapf
andlw
iorwf
DATAH,W
tmp
tmp,F
tmp,W
B’00000111’
Char_a,F
movf
movwf
swapf
andlw
movwf
DATAH,W
tmp
tmp,W
B’01110000’
Char_b
swapf
andlw
iorwf
DATAL,W
0x0F
Char_b,F
clrf
btfsc
bsf
Flag_a
DATAL,3
Flag_a,0
clrf
btfsc
bsf
Flag_b
DATAL,2
Flag_b,0
return
0
EE25M
25th April 2002
C46
ii. packing with no boundary alignment (i.e. overlapping datawords)
In this case because neither the structure nor the data is boundary aligned, then the
data is packed in consecutive bits. We cannot use the same extraction code for each
structure. The structure is 26 bits wide, and the data word size is 14 bits. The spare two
bits will make a complete structure after 13 iterations. Therefore, the pattern will repeat
itself every 14 structures. We could write code to extract a block of 14 structures, or we
could use a buffer and shift data in and out, if we know which bit the structure starts at.
13 12 11 10 9
8
7 6 5
address
4
3
2
1
0
13 12 11 10 9
8
7
6
5
4
address+1
3
2
1
0
int
char
char
flag flag
int(uppermost)
Inthi < 1 : 0 >,Intlo < 7 : 0 >
Chara < 6 : 0 >
Charb < 6 : 0 >
Fa
Fb
Inthi < 1 : 0 >
address+2
address+3
int
char
char
flag flag
int(uppermost)
Intlo < 7 : 0 >
Chara < 6 : 0 >
Charb < 6 : 0 >
Fa
Fb
Inthi < 1 : 0 >,Intlo < 7 : 6 >
address+4
address+5
int
char
char
flag flag
int(uppermost)
Intlo < 5 : 0 >
Chara < 6 : 0 >
Charb < 6 : 0 >
Fa
Fb
Inthi < 1 : 0 >, Intlo < 7 : 4 >
; presume structure starts n bits from the MSB in ADDRH,ADDRL dataword
; with an end of buffer pointer b
call
clrf
clrf
movlw
movwf
Fill_int
call
rlf
rlf
decfsz
goto
clrf
movlw
movwf
Fill_ca
call
rlf
decfsz
goto
clrf
movlw
movwf
Fill_cb
call
rlf
decfsz
goto
InitBuff
; do GetPWord, and shift until data bit n is first
Int_lo
Int_hi
.10
cnt
GetBuffBit
Int_lo,F
Int_hi,F
cnt,F
Fill_int
Char_a
.7
cnt
GetBuffBit
Char_a,F
cnt,F
Fill_ca
Char_b
.7
cnt
GetBuffBit
Char_b,F
cnt,F
Fill_cb
clrf
call
rlf
Flag_a
GetBuffBit
Flag_a,F
clrf
call
Flag_b
GetBuffBit
; shift uppermost bit into the CARRY -- refill using GetNextPWord
EE25M
25th April 2002
rlf
Flag_b,F
return
InitBuff
call
movlw
movwf
call
call
movf
tst btfsc
return
call
decf
goto
GetBuffBit
ShiftBuff
movf
btfsc
call
bcf
rlf
rlf
decf
return
RefillBuff
call
movlw
movlw
call
call
return
GetPWord
.16
b
; initialise end of buffer
ShiftBuff ; get rid of two blanks
ShiftBuff
n,F
STATUS,Z
ShiftBuff
n,F
tst
b,F
STATUS,Z
RefillBuff
STATUS,C
DATAL
DATAH
b,F
GetNextPWord
.16
b
ShiftBuff
ShiftBuff
C47
EE25M
25th April 2002
C48
iii. individual program words for each structure element (i.e. 5 data words per structure)
This is relatively simple, each element is retrieved, one at a time; if necessary, bit masking
could be used to ensure that invalid bits were not set.
call
movf
movwf
movf
movwf
GetPWord
DATAH,W
Int_hi
DATAL,W
Int_lo
call
movf
movwf
GetNextPWord
DATAL,W
Char_a
call
movf
movwf
GetNextPWord
DATAL,W
Char_b
call
movf
movwf
GetNextPWord
DATAL,W
Flag_a
call
movf
movwf
GetNextPWord
DATAL,W
Flag_b
return
From the preceding examples (i)-(iii) we can see that boundary alignment reduces the extraction code, but makes memory usage less efficient. One compromise as in (i) is to align
the structure instead of individual elements.
page V6
1. The MPASM assembler has the BANKSEL preprocessor directive, which switches banks to
the bank of the specified register. Write code to configure PortB for all inputs using the
BANKSEL directive.
BANKSEL TRISB
movlw
.255
movwf
TRISB ; set for all inputs
BANKSEL PORTB
movf
PORTB,W ; now we can read in data
EE25M
25th April 2002
C49
2. Write an assembly language routine which will
• initialize PORTB<5> as an input, and PORTB<4> as an output.
• within a loop: read PORTB<5> and set PORTB<4> to the value read.
BANKSEL TRISB
movlw
B’11101111’
movwf
TRISB
; set for all inputs except <4>
Loop
BANKSEL
btfss
bcf
btfsc
bsf
goto
PORTB
PORTB,5
PORTB,4
PORTB,5
PORTB,4
Loop
; clear <4> if not <5>
; set <4> if <5>
page V12
1. For the example on page V 8, calculate the percentage error caused by the neglected overhead,
and the extra cycle on return for delays of 1 ms, 100 ms and 255 ms.
The overhead on this routine is
Load value into W 1 cycle
Call the subroutine 2 cycles
Store W 1 cycle
Return 1 extra cycle
An error of 5µs is incurred on each call of this routine. The percentage errors will be: 0.5%,
0.005% and 0.002% respectively.
2. For the example on page V11, the code timed 250 cycles, with the prescaler set to 128. For
a 4MHz clock, what is the delay in ms?
Clock tick: 0.25µs
Instruction tick: 1µs
Pre-scaler tick: 128µs
Delay: 250 ∗ 128 = 32000µs = 32ms
EE25M
25th April 2002
C52
page V16
1. In a typical ISR, part of the initialization saves the W and STATUS registers, however this
assumes that the main code that will be interrupted will never be in Bank 1 at the time of
the interrupt. If the ISR ever switches banks then the values of W and STATUS that are
restored would be incorrect27 . In processors where the Bank 0 addresses are different from
the Bank 1 addresses several things can be done to relax this assumption.
(a) Interrupts can be disabled before switching to Bank 1 and re-enabled after switching
back to Bank 0.
(b) Use two addresses, one in each bank, to hold the temporary value of W, i.e. W_TEMP. For
example,
W_TEMP
equ
0x20 W_TEMP_ equ
0xA0
Now when W is stored in W_TEMP using direct addressing at the beginning of the ISR it
will go in either of two locations: 0x20 or 0xA0, depending on which bank is active at
the moment the interrupt occurs.
i. Rewrite the initialization of the ISR that saves W and STATUS in this case, switching to Bank 0 for the duration of the ISR. There would be need only for one location
for STATUS_TEMP defined in Bank 0.
movwf
W_TEMP
movf
STATUS,W
bcf
STATUS,RP0; switch to bank zero
bcf
STATUS,RP1
movwf
STATUS_TEMP
ii. Rewrite the ending of the ISR to restore the STATUS and W.
bcf
STATUS,RP0
bcf
STATUS,RP1; back to bank zero
movf
STATUS_TEMP,W
movwf
STATUS ; back to original bank so w restore ok
swapf
W_TEMP,F
swapf
W_TEMP,W
2. (a) What is the reason of having the interrupt sources in a particular order?
For priority servicing.
(b) When the ISR is entered in response to one specific interrupt, is it possible that a
different source might be serviced first? Discuss your answer.
Yes. If a higher priority interrupt occurs after the ISR has been entered, but before the higher
priority flag has been polled/re-polled, it will be serviced before the original interrupt source.
(c) If while one interrupt source is being serviced, a second interrupt source requests service,
will the second source be serviced before the retfie instruction at the end of the ISR?
Discuss your answer.
Possibly. This depends on the ISR structure. If the ”call” structure is used, the ISR will exit,
and then re-enter to service the later interrupt. If the ”goto” structure is used, the second
source will be service before exit.
27
In the PIC16F8x, Bank 1’s General purpose registers are mapped to Bank 0, so that this argument does not hold
EE25M
25th April 2002
C62
page V 32
1. List features of simulators, and debuggers using MPLAB as an example.
Simulator:
Debugger:
What are some of the disadvantages of using simulators to develop application code?
a) Instruction level simulation, cannot handle events occurring between instructions in the same
way as the hardware would. This may lead to different results on the simulator and hardware.
b) Microprocessor assembly programming is highly dependent on the connected hardware, and the
resultant currents/voltages cannot be simulated, except as binary 1/0’s. This may be inadequate.
(e.g. An output pin is loaded so that it’s voltage drops sufficiently that it cannot trigger the
input Schmidt trigger. The program may be written to ignore this effect, if it is observed prior to
loading on the hardware.)
2. One useful feature of the PIC16F877 microcontroller is the fact that it can report what
condition caused it to re-start: Power-on, Brown-out, Watchdog timer reset or Physical reset
(MCLR pin). Are these features supported in the simulator? Yes.
Can the simulator be used to generate each of these conditions, in order to test any associated
code? Yes.
For details of the actual menu options/buttons, refer to the MPLAB SIM/IDE manual.
EE25M
25th April 2002
C63
page VI9
1. Consider a PIC application that has four interrupt sources, with T1 =10 cycles, T2 =20 cycles,
T3 =40 cycles and, T4 =80 cycles
(a) Using the inequality
T1 + T2 + · · · + Tn + On ≤ worst case time < T1 + T2 + · · · + Tn + 2On ,
(3)
determine the worst-case response of the CPU to any of these interrupts given the polling
scheme where subroutine calls are used for each handler.
On = 12 + 8 = 20 T1 + T2 + t3 + T4 = 150 170 ≤ worst case time < 190
(b) What does this mean for the minimum period between any of these interrupts? If
interrupts arrive more frequently than the period dictated by the worst case execution time,
the priority ordering of the interrupts will not be correct, and a new interrupt may arrive
before the previous one has been serviced.
2. Consider the timing diagrams from Figures (8), (9) and (10) in the notes titled Input/Output.
(a) Why does the worst-case time for source 1 begin at the end of the time labeled P 1 instead
at the time before this when the CPU actually stops execution of the main program?
In the worst case, the interrupt for source 1 arrives just after it has been polled for in an ISR
triggered by another source.
(b) Why does the worst-case time for source 2 begin at the end of the time labeled P 2 instead
at the time before this when the CPU actually stops execution of the main program?
In the worst case, the interrupt for source 2 arrives just after it has been polled for in an ISR
triggered by source 3 and on re-poll source 1 is serviced first.
(c) Why does the worst-case time for source 3, the lowest priority interrupt, begin when the
CPU actually stops execution of the main program rather at the end of P 3 or P1 ?
In the worst case, source 3 triggers the ISR, and then services the other sources first.
3. Using the new polling structure for ISRs i.e. using goto for the handlers instead of call, consider an application with four interrupt sources having times exactly like those in Problem 1
and priority T1 , T2 , T3 , and T4 .
Draw the worst-case timing diagram for the response of the CPU to interrupts from source 1.
Worst case timing is from just after the poll (P1 ) through the execution of the longest other
handler (T4 ) i.e. Tw1 = O4 + (2 × 4 − 1 + T4 ) + (2 × 1 − 1 + T1 ) − P1
Also determine the time TP1 , the minimum time between source 1 interrupts such that the
CPU will assuredly execute source 1’s handler and be ready to handle another source 1
interrupt.
This is the same as the worst case timing except we do not need to exit the routine, so the return
and the remaining polls are removed from the overhead, i.e. TP1 = Tw1 − 6 − (2 × 3)
Repeat this exercise for source 3.
For source 3, worst case is when it is just missed on a source 4, and then sources 1 and 2 are both
serviced. i.e. Tw3 = O4 +(2×4−1+T4 )+(2×3−1)+T1 +T2 +T3 −P3 TP1 = Tw3 −6−(2×1)
EE25M
25th April 2002
C64
4. When an interrupt occurs, the global interrupt enable bit, GIE, is automatically cleared by
the CPU. Sometimes it is necessary to disable interrupts for a short time in the main program
in order to execute a short sequence that can give an incorrect result if interrupted and then
re-enable the interrupt after the sequence.
A problem could arise if the instruction to disable the interrupts is being executed at the
exact moment that an interrupt occurs. Describe the effect if the instruction to disable the
interrupts is indeed executed, but the interrupt is acknowledged and handled by the CPU
before the program instruction is able to take effect.
If the interrupt occurs when the instruction to disable interrupts is being fetched, the interrupt
handler will be activated, just after the GIE bit has been cleared by the instruction. On leaving the
interrupt handler, the system will set the GIE bit (automatic). The main program will therefore
proceed as though the GIE bit had never been cleared.
EE25M
25th April 2002
C65
page VI 15
1. Using the code developed for the Rotary Pulse Generator, modify it to increment a 2-byte
variable, Amplitude if the RPG has been rotated CW and to decrement it if the rotation is
CCW. Do not increment past 65,535 or decrement past zero.
2. Modify the solution to Problem (1) to change the variable Amplitude by one-eighth of its
value or by one count, whichever is larger when fast turning of the RPG is detected.
Using the same interrupt structure, we can simply write the subroutines decrease voltage small
etc...
decrease_voltage_small
movf
Amplitude_lo,F
btfss
STATUS,Z
goto
dvsok
movf
Amplitude_hi,F
btfsc
STATUS,Z
return
decf
Amplitude_hi,F
dvsok
decf
Amplitude_lo,F
return
; check if lo byte is zero
; both bytes zero then leave
increase_voltage_small
incf
Amplitude_lo,F
btfss
STATUS,Z
return
; increment didn’t overflow low byte
incf
Amplitude_hi,F
btfss
STATUS,Z
return
; increment didn’t overflow upper byte
max_out movlw
movwf
movwf
return
0xFF
Amplitude_hi
Amplitude_lo
decrease_voltage_large
call find_eighth
; do 16 bit subtraction -- if overflow set to 0
movf
Temp_lo,W
subwf
Amplitude_lo,F
movf
STATUS,W
movwf
LoSubFlags
movf
Temp_hi,W
subwf
Amplitude_hi,W
btfss
LoSubFlags,C
addlw
0xFF
movwf
Amplitude_hi
btfsc
STATUS,C
return
zero
clrf
Amplitude_hi
clrf
Amplitude_lo
return
EE25M
25th April 2002
increase_voltage_large
call find_eighth
; do 16 bit addition -- if overflow set to max.
movf
Temp_lo,W
addwf
Amplitude_lo,F
movf
Temp_hi,W
btfsc
STATUS,C
incf
Amplitude_hi,F
addwf
Amplitude_hi
btfsc
STATUS,C
goto
max_out
return
find_eighth
; find one-eighth of value and place in the variable Eighth
; minimum value should be 1.
movf
Amplitude_lo,W
movwf
Eighth_lo
movf
Amplitude_hi,W
movwf
Eighth_hi
bcf
STATUS,C
rrf
Eighth_hi
rrf
Eighth_lo
movf
Eighth_lo,F
btfss
STATUS,Z
return
movf
Eighth_hi,F
btfsc
STATUS,Z
incf
Eighth_lo,F
return
C66
EE25M
25th April 2002
C67
page VI 18
1. The code presented should produce a 16-bit estimate for the switching frequency of the signal
connected to Timer0. Comment on the accuracy of this measurement. Hints: Check the
minimum duration change detected on the Timer0 input, and the ISR execution time.
We make the following observations:
• The latency between the external interrupt, and the clearing of TMR0 at the beginning
of measurement is 3-4 cycles (response time) + 10 cycles (counting instructions) + save
overhead.
• The latency between the external interrupt, and the storage of TMR0 is 3-4 cycles (response
time) + 11 cycles (counting instructions) + save overhead.
• In the worst case, if INTF arrives while T0IF is being serviced, there will be an additional 10
cycles while T0IF is serviced.
• If INTF arrives during register restore, the time will be the total overhead plus the ISR return/call overhead.
It follows that the accuracy of the timebase for the frequency estimate will be off by 1
cycle at best, and up to twice 10 (or overhead if larger)+1 cycles at worst.
• The transition count may have overflowed, just prior to the timebase interrrupt, in which
case Ncycles will be unincremented even though the count in TMR0 has rest to a smaller
value. This will lead to an occasional error in the transition count of 255*prescale.
• Transitions must occur with at least 2 T OSC between them. Therefore frequencies more
than 2MHZ cannot be measured.
• In two registers, we can express frequencies up to 131072 (using carry) Hz with a resolution
of 1 Hz.
• When sampling, there is always the problem of starting late in the cycle, and not getting all
transitions for another point. This adds inaccuracy of ±1 transition.
© Copyright 2026 Paperzz