CMPE 401 - Computer Interfacing

Assignment #2 Solutions

Due: In the CMPE 401 assignment box at 15:45 on Friday, Oct. 17, 2008


  1. Design an assembly language subroutine that scans through a packed array of longwords and computes the following two numbers: (1) the number of 1's present in all bytes at odd-numbered byte addresses, and (2) the number of 0's present in all bytes at even-numbered byte addresses. The subroutine is to be called BIT_COUNT. The 32-bit addresses of the first and last longwords in the array are to be pushed onto the stack immediately before BIT_COUNT is called. The number of 1's and the number of 0's are to be returned in D1.W and D0.W, respectively. No other CPU register bits are to be altered by the time that execution has returned from BIT_COUNT to the calling routine.

    [25 marks]
      BIT_COUNT:  MOVEM.L  A0-A1/D2-D3,-(SP)   // save CPU regs
                  MOVE.L   D0,-(SP)            // save D0 to known place on stack
                  MOVE.L   D1,-(SP)            // likewise, save D1 to stack
    
                  MOVE.L   32(SP),A0           // get first longword address
                  MOVE.L   28(SP),A1           // get last longword address
                  ADDA.L   #3,A1               // create last byte address
                  CLR.L    D0                  // clear count (1) of 0's
                  CLR.L    D1                  // clear count (2) of 1's
    
      LOOP1:      MOVE.B   (A0)+,D2            // get next even-addressed byte
                  CLR.L    D3                  // initialize bit counter for byte
    
      LOOP2:      BTST.B   D3,D2               // is the next bit a 0?
                  BNE      SKIP1               // skip increment if 1
                  ADDQ.L   #1,D0               // increment count of 0's
      SKIP1:      ADDQ.L   #1,D3               // increment bit ptr
                  CMPI.L   #8,D3               // finished present byte?
                  BLT      LOOP2               // if not, go back to next bit
    
                  MOVE.B   (A0)+,D2            // get next odd-addressed byte
                  CLR.L    D3                  // initialize bit counter for byte
    
      LOOP3:      BTST.B   D3,D2               // is the next bit a 1?
                  BEQ      SKIP2               // skip increment if 0
                  ADDQ.L   #1,D1               // increment count of 1's
      SKIP2:      ADDQ.L   #1,D3               // increment bit ptr
                  CMPI.L   #8,D3               // finished present byte?
                  BLT      LOOP3               // if not, go back to next bit
    
                  CMPA     A1,A0               // check if done last byte
                  BLT      LOOP1               // loop back if A0 < A1
    
                  MOVE.W   D1,2(SP)            // write count (1) to saved D1.W
                  MOVE.W   D0,6(SP)            // write count (2) to saved D0.W
    
                  MOVE.L   (SP)+,D1            // restore D1 with count (1)
                  MOVE.L   (SP)+,D0            // restore D0 with count (2)
                  MOVEM.L  (SP)+,A0-A1/D2-D3   // restore CPU regs
                  RTS
      

  1. Slide 3-11 in the course notes illustrates the scheduling behaviour of a simple multitasking system with two tasks, Task A and Task B, that are scheduled to execute regularly at two different frequencies. Task B is scheduled to execute its software states at exactly twice the rate of Task A. In your own words describe a design, using the MicroC/OS pre-emptive multitasking environment, that implements the behaviour in Slide 3-11. Assume that Task B is scheduled to run every 20 milliseconds. Further assume that the hardware timer produces 200 ticks per second. Use C code to describe your task designs. However, you do not have to produce a compileable MicroC/OS system, with full initialization code. Hint: It might be useful to introduce a new task and two semaphores.

    [25 marks]
    General strategy: According to slide 3-11, there is a single sequence of timer interrupts that enables Tasks A and B. Task A only executes for alternating timer interrupts, and when it does execute, it has priority over Task B. There are several workable solutions in a MicroC/OS system. Following the hint, one could introduce a new timer Task T that controls two semaphores: one that enables Task A and one that enables Task B. This approach would be modular, separating out the problem of sequencing task execution from the code inside Tasks A and B. Task A would block on semaphore A and Task B would block on semaphore B. Here is how the code would look for Task A, Task B, the timing Task T, and the UserMain task.
       extern "C" {
          void UserMain( void *Pd );
       }
    
       DWORD TaskTStack[ USER_TASK_STK_SIZE ] __attribute__( ( aligned(4) ) );
       DWORD TaskAStack[ USER_TASK_STK_SIZE ] __attribute__( ( aligned(4) ) );
       DWORD TaskBStack[ USER_TASK_STK_SIZE ] __attribute__( ( aligned(4) ) );
    
       OS_SEM SemaphoreA, SemaphoreB;
      
       void TaskA( void *pd )
       {
          current_state = reset_state_for_A;
          while (1) {
             OSSemPend( &SemaphoreA );
             // Execute code in current_state
             // update next_state according to inputs and the current state
             current_state = next_state;
          } // end while (1)
       }
      
       void TaskB( void *pd )
       {
          current_state = reset_state_for_B;
          while (1) {
             OSSemPend( &SemaphoreB );
             // Execute code in current_state
             // update next_state according to inputs and the current state
             current_state = next_state;
          } // end while (1)
       }
      
       void TaskT( void *pd )
       {
          while (1) {
             OSTimeDly( TICS_PER_SECOND * 0.040 );
             OSSemPost( &SemaphoreA );
             OSSemPost( &SemaphoreB );
             OSTimeDly( TICS_PER_SECOND * 0.040 );
             OSSemPost( &SemaphoreB );
          } // end while (1)
       }
      
       // Task UserMain
       void UserMain( void *pd ) {
          OSChangePrio( MAIN_PRIO );
          OSSemInit( &SemaphoreA, 0 );
          OSSemInit( &SemaphoreB, 0 );
    
          OSTaskCreate( TaskT, (void *) 0,
             &TaskTStack[USER_TASK_STK_SIZE],
             TaskTStack, MAIN_PRIO-3 );
    
          OSTaskCreate( TaskA, (void *) 0,
             &TaskAStack[USER_TASK_STK_SIZE],
             TaskAStack, MAIN_PRIO-2 );
    
          OSTaskCreate( TaskB, (void *) 0,
             &TaskBStack[USER_TASK_STK_SIZE],
             TaskBStack, MAIN_PRIO-1 );
    
          while (1) {
             OSTimeDly( TICKS_PER_SECOND * 5 );
          } // end while
       }
      
      
      

  1. Briefly define what is meant by a "noise margin" in the case of digital logic. What is the main purpose of having nonzero noise margins at a digital interface.

    [10 marks]
    A noise margin is the additional noise voltage that can be tolerated when superimposed onto a digital signal without causing a driven 0 to be interpreted in error as a 1 (or vice versa). The upper and lower noise margins are computed as the absolute value of (1) the difference between a minimum input high and a minimum output high, and (2) the difference between a maximum input low and a maximum input high.

    The noise margin provides a degree of immunity against noise that might get introduced onto a digital signal. The source of the noise could be electromagnetically coupled noise, ground voltage noise, offsets in the power supply voltage of the transmitting and receiving sides, etc.

  1. Consult Chapter 26 in the MCF5235 Reference Manual (MCF5235.pdf) and then briefly explain the events that are associated with bits #7, 2, 1 and 0 of the UART Interrupt Status and Mask Registers (UISR and UIMR).

    [10 marks]
    The contents of the UISR and UIMR are bitwise ANDed together and if the result is nonzero, a hardware interrupt will be active from the UART; if the result is zero then the hardware interrupt will not be active.

    Bit #7 in the UISR is the "Change Of State" (COS) bit. It is used to detect the next 0-to-1 or 1-to-0 transition in the UnCTS (Clear To Send) line provided this feature has been enabled in the UACRn register.

    Bit #2 in the UISR is the "Delta break" bit. It is used to detect a a break signal (i.e. a low voltage "space" signal that lasts longer than the time for one character frame).

    Bit #1 in the UISR is the "FIFO Full/Receiver Ready" (FFULL/RxRDY) bit. The operation of this bit depends on the bit value that is stored in the FFULL/RxRDY bit in register UMR1. If this other bit is 1, then bit #1 in the UISR has value 1 if the receiver First In First Out (FIFO) buffer is full; otherwise, bit #1 has value 0. If the FFULL/RxRDY bit in register UMR1 is 0, then bit #1 in the UISR is a Receiver Ready (RxRDY) bit that has value 1 if the receiver is "ready" (has a new character for the CPU to read) and has value 0 if the receiver has no new characters to read.

    Bit #0 in the UISR is the Transmitter Ready (TxRDY) bit. It has value 1 if the transmitter can accept another character to transmit and the transmitter is currently enabled to transmit; otherwise, bit #0 has value 0.

  1. Briefly explain the general functionality provided by an Ethernet PHY chip, such as the the Micrel KS8721BT. Why has it been important for the industry to standardize the interface between the PHY and the MAC device?

    [10 marks]
    An Ethernet PHY is responsible for both (1) driving digital signals out onto a transmission medium, and (2) recovering digital signals from the analogue signals that are received from a transmission medium. A PHY, such as the Micrel KS8721BT, may have several different operating modes (e.g. 10 Mbps and 100 Mbps) to make the device more versatile and useful to potential customers. Control modes may be provided to select between the various available options provided for in the communications standard (e.g. full duplex vs. half duplex). Test modes (e.g. a software-controlled loopback path from the transmitter output directly back to the receiver input) might also be provided. Devices that interface on the digital side of the PHY are shielded by the PHY from the complexities of the transmission medium (e.g. different voltage, shaped analog waveforms, interference cancellation techniques, etc). >P> It has been important to standardize the interface between the PHY and the MAC (the digital device immediately connected above the PHY in the protocol stack) to promote interchangeability among different PHYs and MACs. Standards generally promote the development of lower-cost devices since they provide some assurance to manufacturers that their devices (PHY or MAC implementatiuons) will be more easily sold.

  1. Consult Chapter 19 in the MCF5235 Reference Manual (MCF5235.pdf) and then briefly explain how software running on the ColdFire CPU can write and read values to the registers in the PHY over the MII/MDIO interface using the MII Management Frame Register (MMFR). Note: A "MII Management Frame" is a 32-bit long formatted data packet that is shifted serially onto the MDIO line by the rising edges of the MDC clock signal. Usually, the MAC drives the MDIO line and the PHY latches the arriving bits into the specified internal PHY register. In the case of MII Management Frames that request a PHY register read, however, the data direction on the MDIO line is reversed for the last 16 bit times in the frame, when the PHY drives the 16 bits that are shifted out from the one addressed internal PHY register. The detailed operation of the MDIO and MDC lines is controlled automatically by the FEC/MAC block, with no intervention by the CPU. How can the CPU be notified, using an FEC interrupt, that the current MII Management Frame has been successfully transmitted to the desired PHY?

    [10 marks]
    The MMFR is a CPU-readable and writeable register in the FEC. If the various fields of the MMFR are written with the correct values, then the FEC hardware will automatically generate an MII frame at the MDIO serial data output. If the MII operation is a write, then 32 bits will be shifted serially out of the MDIO pin and into the addressed register of an attached PHY device. If the MII operation is a read, then the first 16 bits will be shifted out of the MDIO pin and into the PHY, and the last 16 bits will be driven in the opposite direction by the PHY into the MDIO pin.

    Bit #23 of the Ethernet Interrupt Event Register (EIR) will be set after a 32-bit shifting sequence from the MMFR has been completed. This is a useful feature since the MDC clock runs more slowly than the CPU clock. The CPU can do other useful work wile the MII frame is being shifted, and only when that operation is completed will the CPU be alerted by means of the MII interrupt. For the MII interrupt to be enabled through to the CPU as a hardware signal, the MII bit in the Ethernet Interrupt Mask Register (EIMR) must hold a 1.

  1. Briefly describe how the W and L bits are used in the FEC transmit buffer descriptors. Also explain how the transmit buffer descriptors are used together in the transmit buffer descriptor ring.

    [10 marks]
    The W bit in the transmit buffer descriptor (BD) is used to indicate the last buffer in the transmit BD ring. Only the last DB has W=1; the other BDs have W=0. In a similar way, the L bit in the BD is used to indicate the last BD in a frame. The BD that points to the last transmit buffer of a fram has L=1; the other BDs corresponding to the same transmit frame all have L-0.

    The transmit BDs are used by the transmitter to locate the various buffers that contain the bits in a transmitted frame. It is convenient to split up such a frame into pieces so that software can more easily access different kinds of information. For example, separate transmit buffers might be used to store the Ethernet header, the IP header, the TCP header, the application payload, and the Ethernet trailer.