UNIVERSITY OF ALBERTA

 

DEPT. OF ELECTRICAL AND COMPUTER ENGINEERING

 

CMPE 401 - Computer Interfacing

 

Midterm Examination

 

 

 

Instructor:

B. F. Cockburn  (Section A1)

Exam date:

October 22, 2003

Exam duration:

50 minutes

Aids permitted:

Course notes (hardcopies of the lecture transparencies)

 

Assignments, student assignment solutions, model solutions

 

Electronic calculator

 

MC68000 Programming Reference Card

 

 

Instructions:

1.  Fill out your printed name, signature and I.D. number on this page.

2.  Verify that this booklet contains 6 pages.

3.  Neatly enter your answers in the spaces provided.

4.  Use the reverse sides of the pages for rough work.

 

 

 

 

 

 

 

Student name: ___________________________________

 

 

 

 

Signature: ______________________________________

 

 

 

 

Student I.D.: ____________________________________

 

 

 

Question

Time

Worth

Mark

Subject

1.

20

 40

 

MicroC/OS-II Event Control Block

2.

10

 20

 

Multitasking Concepts

3.

20

 40

 

Enq-ack Flow Control Using the DUART

Total

50 mins

100

 

--


Question #1  (MicroC/OS-II Event Control Block)

 

.OSEventType

 

.OSEventCnt

 

.OSEventPtr

 

.OSEventGrp

 

.OSEventTbl[7-0]

 

.OSEventTbl[15-8]

 

.OSEventTbl[23-16]

 

.OSEventTbl[31-24]

 

.OSEventTbl[39-32]

 

.OSEventTbl[47-40]

 

.OSEventTbl[55-48]

 

.OSEventTbl[63-56]

 

 

The Event Control Block (ECB) in MicroC/OS-II, illustrated above, is a data structure that is used to keep track of data required by various kernel objects, including semaphores and message queues.  These objects all need to keep track of the tasks that are currently blocked on the object.  The various fields in the ECB are: (1) the OSEventType, which is a constant that identifies the type of object; (2) OSEventCnt, which keeps track of the total number of tasks that are currently blocked on the object; (3) OSEventPtr, which is either a null pointer (value 0) or is a pointer to the next ECB in a list; (4) OSEventGrp, whose bits are the logical OR of the bits in each of the remaining 8 bytes in the ECB; and (5) OSEventTbl, which contains 64 bit flags that identify which tasks are currently blocked on the object (1 => task blocked at corresponding priority).  Note that bit #7 (the MSB) of OSEventGrp is the logical OR of OSEventTbl[63, . . . , 56], and bit #0 (the LSB) of OSEventGrp is the logical OR of OSEventTbl[7, . . . , 0].

 

(a)   In the space below, draw a standard 68000-style memory diagram (16 bits wide) that illustrates how the ECB would be stored in Big Endian storage order.  You are to assume that the bytes in the above diagram are in strictly ascending order as you move down the page.  Be sure to label all of the fields, and the 64 bit positions inside the OSEventTbl field.

 

[5 marks]

 

 15                  8 7                   0

+---------------------+---------------------+

|     OSEventType     |      OSEventCnt     |

+---------------------+---------------------+

|     OSEventPtr      |      OSEventGrp     |

+---------------------+---------------------+

|   OSEventTbl[7-0]   |   OSEventTbl[15-8]  |

+---------------------+---------------------+

|   OSEventTbl[23-16] |   OSEventTbl[31-24] |

+---------------------+---------------------+

|   OSEventTbl[39-32] |   OSEventTbl[47-40] |

+---------------------+---------------------+

|   OSEventTbl[55-48] |   OSEventTbl[63-56] |

+---------------------+---------------------+

 


Question #1  (MicroC/OS-II Event Control Block, cont'd)

 

(b)  In the space below, enter an assembly language program, called ADD_TASK, that adds a task to the queue of a given ECB.  The ECB is to be passed as a long word pointer parameter on the stack; the priority (from 0 to 63) of the task is to be passed in D0.B.  Your program is to correctly update the OSEventCnt field (number of tasks waiting on the object), the OSEventTbl (a bit map that identifies which of the 64 tasks are waiting on the object), and the OSEventGrp (the logical ORs of the bytes in the OSEventTbl.  Be sure to provide a return code in D7.B to indicate any unusual conditions, if any, that were encountered.

 

[35 marks]

 

ADD_TASK: LINK     A6,#0     /* create stack frame */

          MOVEM.L  A0/D1,-(SP)   /* save regs */

 

          MOVEA.L  8(SP),A0  /* retrieve ECB ptr from stack */

          CLR.L    D1

          MOVE.B   D0,D1     /* get task priority */

          LSR.W    #3,D1     /* form priority group in 0..7 */

          BSET.B   D0,0(A0,D1.W) /* set the OSEventTbl bit */

          BEQ      BIT_CHANGED   /* bit was zero before? */

          MOVE.B   #1,D7     /* no, return error code and exit */

          BRA      EXIT_ADD_TASK

BIT_CHANGED:                 /* yes, task is newly added */

          CLR.B    D7        /* clear error code */

          ADDQ.B   #1,1(A0)  /* increment OSEventCnt */

          BSET.B   D1,3(A0)  /* set bit in OSEventGrp */

EXIT_ADD_TASK:

          MOVEM.L  (SP)+,A0/D1   /* restore regs */

          UNLK     A6        /* remove stack frame */

          RTS


Question #2  (Multitasking Concepts)

 

(a)   In your own words, briefly describe the difference between preemptive multitasking and cooperative multitasking.  What would be some of the advantages and disadvantages of cooperative multitasking versus preemptive multitasking.

 

[10 marks]

 

In preemptive multitasking, a priority level is associated with each task.  The highest priority ready-to-run task should always be running on the CPU.  If a task was not running previously for some reason becomes highest priority, then the currently running task is preempted to allow the highest priority task to start running.

 

In cooperative multitasking, the running task cannot be preempted; it continues to run until it decides to give up the CPU to allow the next task in the queue of tasks to run.

 

Some advantages of cooperative multitasking vs. preemptive multitasking:

(1)        No need for the software that would perform preemption.  The kernel is much simpler as a result.

(2)        No CPU time is wasted doing preemptions.

 

Some disadvantages of cooperative multitasking:

(1)        The system is vulnerable to greedy tasks that hold on to the CPU longer than they perhaps show.

(2)        The tasks are not as loosely interacting as they would be if they were strictly prioritized.  This makes the system design problem trickier and more difficult to debug and to tune.

(3)        The system is less likely to have strictly deterministic behaviour since it is difficult to ensure that high-priority tasks will always get to run promptly.

 

 

(b)  MicroC/OS-II uses preemptive multitasking, with at most one task for each of the 64 possible priorities.  Briefly explain how MicroC/OS-II ensures that the highest priority task is always the task that runs on the CPU.  In your answer, be sure to mention what happens when interrupts are serviced.

 

[10 marks]

 

MicroC/OS-II ensures that the highest priority task always runs by monitoring all of the events, including hardware interrupts, that could potentially unblock or unsuspend a higher priority task.  After each such event has occurred, MicroC/OS-II does a quick check to see if the currently running task should be preempted by another, higher-priority task.

 

The same is true for interrupts.  After a hardware interrupt has been serviced, the interrupt service routine calls the kernel function OSIntExit68K(), which checks for higher priority tasks and performs the possible task context switch.

 


Question #3  (Enq-ack Flow Control Using the DUART)

 

In the next two pages below enter your design for an assembly language subroutine that controls the DUART and implements a simple ENQ-ACK flow control protocol.  The subroutine, called POLL_DUART, is to implement the following behaviour:

 

1.     POLL_DUART is to receive a pointer in register A0.L.  This pointer gives the starting address of a null-terminated (i.e. ending in $00) string that is to be transmitted out of the DUART on channel A.  The subroutine is to return an output parameter in register D7.B. If the entire string was transmitted successfully, then the output parameter is to have value $00; otherwise, it is to have value $01.

 

2.     POLL_DUART is to begin the transmission attempt by sending the ASCII "enq" character ($05).  It is then to call an assembly language function called DELAY100, which produces a delay of 100 milliseconds.  (You do not have to write DELAY100.  You can assume that it is provided to you.)  POLL_DUART is to then check the channel A receiver once to determine if an ASCII "ack" ($06) character has been received from the destination system.  If not, then POLL_DUART is to send a second "enq" character, and then call DELAY100 a second time.  If an "ack" does not arrive at the end of the second delay, then POLL_DUART is to return with the $01 return code.

 

3.     If an "ack" is received for either of the two attempts, then POLL_DUART is to begin transmitting all of the characters in the string.  Busy waiting is to be used to ensure that each character is loaded properly into the channel B transmitter.  Once all of the characters have been transmitted, POLL_DUART is to return with the $00 return code.

 

[40 marks]

 

.equ  ENQ,   0x05

.equ  ACK,   0x06

.equ  PD_OK,     0x00

.equ  TIME_OUT,  0x01

 

POLL_DUART:  MOVEM.L  A1/D0,-(SP)     /* save regs */

             LEA.L    DUART_BASE,A1   /* load DUART base ptr */

TxBusy:      MOVE.B   SRA(A1),D0      /* check chan A status */

             ANDI.B   #TxRDYA,D0      /* is TxA idle? */

             BEQ      TxBusy          /* busy wait if not idle */

             MOVE.B   #ENQ,TBA(A1)    /* transmit the 1st ENQ */

             JSR      DELAY100        /* wait 100 ms */

             MOVE.B   SRA(A1),D0

             ANDI.B   #RxRDYA,D0      /* character received? */

             BEQ      ENQ_AGAIN       /* if no, send ENQ again */

             MOVE.B   RBA(A1),D0      /* yes, read out char */

             CMPI.B   #ACK,D0         /* was an ACK received? */

             BEQ      GOT_AN_ACK      /* yes, send string */

ENQ_AGAIN:   MOVE.B   #ENQ,TBA(A1)    /* no, transmit a 2nd ACK */

             JSR      DELAY100        /* wait 100 ms */

             MOVE.B   SRA(A1),D0

             ANDI.B   #RxRDYA,D0      /* character received? */

             BEQ      TIMED_OUT       /* no, timed out */

             MOVE.B   RBA(A1),D0

             CMPI.B   #ACK,D0         /* was an ACK received? */

             BEQ      GOT_AN_ACK      /* yes, send string */

TIMED_OUT:   MOVE.B   #TIME_OUT,D7    /* no, return time out code */

             BRA      EXIT_POLL_DUART

GOT_AN_ACK:  MOVE.B   SRA(A1),D0      /* verify that TxA is idle */

             ANDI.B   #TxRDYA,D0

             BEQ      GOT_AN_ACK      /* busy wait if not idle */

             MOVE.B   (A0)+,TBA(A0)   /* transmit next char */

             BNE      GOT_AN_ACK      /* send next char if not NUL */

             MOVE.B   #PD_OK,D7       /* NUL sent, return code OK */

EXIT_POLL_DUART:

             MOVEM.L  (SP)+,A1/D0     /* restore regs */

             RTS