CMPE 401 - Computer Interfacing

Assignment #2 Solutions

Due: In the CMPE 401 assignment box at 15:45 on Wednesday, Oct. 20, 2004


  1. The Motorola 68000 processors provide 14 different addressing modes. Three of those modes (immediate data, program counter relative with displacement, and program counter relative with displacement and index) cannot be used to specify a destination operand. Briefly explain how each of these addressing modes is used, and explain why this restriction against destination operands is present in each mode.

    [10 marks]
    Immediate data: It does not make sense to move a source value to a destination that is an immediate value, and is thus a constant value. Constants can't be made to change.

    Program counter relative with displacement: This addressing mode was forbidden to make it more difficult to create a self-modifying program, which is a program that modifies its own instructions by explicit write operations. This mode specifies a location that is at a displacement relative to the currently executing program instruction. Restricting this mode to source operands allows data values that have a fixed address displacement with respect to program code to be read, but not written.

    Program counter relative with displacement and index: This addressing mode was forbidden for the same reason that program counter relative with displacement was forbidden.

  2. The vast majority of modern computer systems use memory-mapped input/output interfaces. What do we mean by "memory-mapped" in this context? What do you think are the major advantages of memory-mapping? Can you think of any disadvantages of memory-mapping? (An alternative to memory mapping is to use a separate I/O bus that comes directly off of the CPU.)

    [10 marks]
    A memory-mapped input/output interface is one in which the interface device has been allocated a set of addresses in the memory address space of the microcomputer. The interface is controlled by reading and writing device registers, which are accessed just like memory locations.

    The main advantages of memory mapping include: (1) No special busses or instructions are required: the regular system bus and ordinary data manipulation instructions can be used. (2) There is great flexibility in how the memory mapping is implemented. Input/output devices can be shifted around in the memory map as desired.

    Disadvantages of memory-mapping include: (1) Memory accesses and input/output data transfers must share the same system bus. (2) Input/output devices will occupy some of the available memory addresses (but this should really be a very minor problem since the address space is so large in modern CPUs).

  3. Go to the website of Freescale Semiconductor (the new name of Motorola Semiconductor) and determine what peripheral functions are provided in the MC68331 and MC68340 microcontrollers in addition to the embedded CPU32 microprocessor. Do not just give the acronym abbeviations of the peripheral subsystems: spell out the subsystem names and give a brief description of each.

    [10 marks]
    The 68340 microcontroller contains a CPU32 microprocessor, an embedded DUART-compatible serial interface, two timer subsystems, and a two-channel direct memory access (DMA) subsystem. Along with the other 683xx microcontrollers, the 68340 has programmable input/output pins such as chip select outputs and interrupt request inputs. Each DMA channel can be used to control the transfer of a block of data over the system bus between two buffer regions of memory, or between an input/output interface and a buffer region in memory. The one (or two) DMA transfers can be programmed to share the system bus with the CPU during the transfer.

    The 68331 microcontroller contains a CPU32 microprocessor, a system integration module (SIM), a queued serial module (QSM), and a general-purpose timer (GPT). It is thus very similar to the 68332 that we are using in the lab, with the GPT replacing the 2048-byte RAM and the time processing unit (TPU). As in the 68332, the SIM in the 68331 allows the system bus to be extended to connect to external peripheral chips; it also can be used to configure the interrupt priority encoder settings and other interface-related features (e.g. chip select outputs). The QSM in the 68331 provides an industry-standard synchronous serial peripheral interface (SPI) for connecting to other SPI-compatible devices; it also has as an RS232-compatible asynchronous serial port.

  4. Consult the on-line documentation or the course textbook, and then briefly explain how the MOVEP instruction works. Why was such an instruction included in the 68000 instruction set? Illustrate your answer with a short example in assembly language.

    [10 marks]
    The MOVEP (move peripheral data) instruction is used to move byte, word or long-word data between a data register and a sequence of 1, 2 or 4 odd-address-aligned or even-address-aligned byte-wide memory locations. One of the operands must be in a data register (.B, .W or .L sizes); the other operand is specified by indicating the byte location in memory with the smallest address value. The address register indirect with displacement addressing mode must be used to specify the first memory byte in the sequence.

    The MOVEP instruction was included in the 68000-family instruction set to make it easier for the new 16/32-bit microprocessors to access the 8-bit-wide registers of the older 8-bit peripheral chips (and the then new, but still 8-bit-wide, DUART chip). It is normal practice to put 8-bit-wide parts only on even-numbered addresses or odd-numbered addresses because address bit A0 is treated differently from the other address lines in the original 68000 microprocessor. In the 68000 the A0 signal was decoded into an upper data strobe (for even-addressed bytes) and a lower data strobe (for odd-addressed bytes). The simplest way of driving the register select signals on 8-bit parts is thus to use address lines A1, A2, etc., and to leave out the two data strobes (which together encode A0).

    Here are a few examples of the MOVEP instruction:

    MOVEP.L D1,5(A0)
    MOVEP.W 6(A2),D3
    MOVEP.B 0(A6),D3

  5. Consult the on-line documentation or the course textbook, and then briefly explain how the CHK and CHK2 instructions work. Illustrate your answer with a short example in assembly language. You do not have to provide the exception handling routines.

    [10 marks]
    The CHK instruction (16 or 32 bit values) is used to determine whether the integer value stored in the data register given as the second operand lies between 0 and the two's complement value (inclusive) specified by the effective address in the first operand. If the data register value is outside of this range, then a CHK exception occurs and corresponding exception handling routine (pointed to by vector number 6) is executed. Examples of this instruction are:

    CHK.B UPPER_LIM,D7 /* memory location UPPER_LIM contains the limit */
    CHK.W D3,D4 /* D3 contains the limit */
    CHK.B (A3),D5 /* A3 points to the memory location containing the limit */

    The CHK2 instruction (8, 16 or 32 bit values) is used to determine whether the integer value stored in the data or address register given as the second operand lies inclusively between the packed lower and upper limits specified by the effective address in the first operand. If the register is an address register and the data size is either 8 or 16 bits, then the bounds are sign-extended to 32 bits and then compared to the full 32 bits in the address register. If the register value is outside of range, then a CHK exception (also vector 6) occurs and corresponding exception handling routine is executed. An example of this instruction is:

    CHK2.B TWO_LIMITS,D7 /* TWO_LIMITS contains lower & upper limits */
    CHK2.W D3,A4 /* the full 32 bits of A4 are used */
    CHK2.L (A3),D5

  6. Small microcomputers can usually get by with autovectored interrupts and do not require user interrupts. Briefly explain the difference between autovectored and user interrupts. What would be the advantage of using only autovectored interrupts in a small microcomputer? How is autovectoring forced in the lab microcomputer?

    [15 marks]
    In autovectored interrupts, there is hardware provided in the microcomputer to group the various possible hardware interrupt signals into a relatively small number (e.g. 7 in the 68000-family CPUs) of interrupt priority levels. A priority encoder circuit passes only the highest priority interrupt signal on to the CPU. The CPU then uses the interrupt priority level to select the one interrupt autovector (e.g. the starting address of the interrupt service routine) for that level. After loading this autovector into its program counter, the CPU starts to fetch and execute the instructions of the interrupt service routine.

    In user interrupts the interrupting device is queried by the CPU to get an exception vector number, which is then used by the CPU to locate the interrupt vector (e.g. the starting address of the interrupt service routine). In the CPU32, the exception vector number is multiplied by 4 (shifted left by two bit positions) to give a binary offset into the exception vector table. The long-word table entry at that offset is the appropriate user interrupt vector. After loading this interrupt vector into its program counter, the CPU starts to fetch and execute the instructions of the interrupt service routine.

    It might be desirable for small systems to use autovectored interrupts since the interrupt acknowledgement cycle (e.g. the process by which the CPU determines the interrupt vector) is simpler than what it would be for user interrupts. As well, the peripheral chips that just use autovectored interrupts tend to be simpler than those that provide user interrupts (e.g. an interrupt vector register is not required and an IACK control input signal is not required). The total number of interrupts in a small system is likely to be 7 or less, so it might be possible to have one interrupt priority level for each potentially interrupting device.

    In the 68332-based lab microcomputer, autovectoring is forced by setting a dip switch that forces the active low AVEC input signal to 0 volts.

  7. Briefly describe how the two (A and B side) quadruple receiver buffers work in the MC68681 DUART. What happens when a single character is received when the receiver buffers start out empty? Be sure to specify how the status register bits change in this case. Assume that error status is in character (not block) mode. Assume that all interrupt modes have been disabled in the DUART. What happens when four characters are received in a quick burst (too fast for the CPU to respond) into an empty receiver? What happens if the quick burst contains five rather than four characters?

    [20 marks]
    The quadruple receiver buffer allows up to four characters to be received by the DUART (starting from a completely empty quadruple buffer) without the danger of data loss due to overrun. Overrun is the situation when a newly arrived character overwrites an earlier character that was received, but not yet read out of the DUART by the CPU. The first buffer in the quadruple buffer is a shift register that converts the serially received bits into a character that can be handled in parallel. Once a new character is fully received, it is normally transferred (in a single parallel operation) directly to the corresponding receiver data register (A or B). From that register, the character can be addressed and read by the CPU. However, if the receiver data register contains another character that has not yet been read by the CPU, then the new character is deposited into a second buffer "behind" the data receiver register. If the second buffer also contains a character that has not yet been read by the CPU, then the new character is loaded into a third buffer. If the data register and both the second and third buffers hold characters that have not been read, then the new character must remain in the shift register (where it is vulnerable to being overwritten by any further received characters). As soon as a character is read from the receiver data register, then the next received data character (if any) is transferred from either the second buffer or the receiver shift register into the receiver data register. If the third buffer holds an unread character, then this character is transferred into the second buffer, and if the shift register holds a full character then that character is loaded into the third buffer.

    Consider the situation on the A side (the B side is similar). After a DUART reset or after a reset command, and the channel A transmitter is disabled, then the channel A status register will contain 8 zeros. If the channel A transmitter is enabled, then bit 3 (channel A transmitter empty) and bit 2 (channel A transmitter ready) will both be set. As soon as a character is completely received by the channel A receiver, then bit 0 (channel A receiver ready) is set to let the CPU know that the new character can be read. If the new character fills up the third and last buffer in the receiver circuit, then bit 1 (channel A FIFO full) is also set to warn the CPU that there is the imminent danger of overrun error if two more characters are received.

    The four other bits in the channel A status register are updated to indicate unusual situations that require the CPU's special attention. Bit 7 (channel A received break) is set when an-zero signal that exceeded one normal character time (start bit to first stop bit) corresponds to the character position in the receiver data register. Bit 6 (channel A framing error) is set if the received character in the receiver data register was not all-zero, but the first stop bit failed to arrive (the signal stayed zero when the first stop bit was expected). Bit 5 (channel A parity error) is set when a parity error was detected when the character in the receiver data register was received. Bit 4 (channel A overrun error) is set when at least one received character was lost because a new character started shifting into the shift register when the shift register was alreading holding an unread character.

    When four characters are received in quick succession, then the status register changes from $00 (or $0C if the transmitter is enabled) to $03 (or $0F). When five characters are received in quick succession, then the status register changes from $00 (or $0C if the transmitter is enabled) to $13 (or $1F).

  8. Write an assembly language program that initializes a DUART for normal duplex serial communications as follows: The A port is to use busy waiting, so interrupts are to be disabled for that side. The characters are to contain 7 data bits, odd parity, and one stop bit. The baud rate is to be 4800 in both directions. Receiver error status is to apply to all characters in the receiver FIFO. The CTS handshake input is to automatically disable/enable the A side transmitter. The RTS handshake output is to go inactive automatically when the receiver FIFO is full.
    The B port is to use interrupts in both the transmit and receiver directions. Receiver interrupts are to be caused whenever one character is received. The characters are to contain 8 data bits, no parity, and two stop bits. The baud rate is to be 9600 in both directions. Receiver error status is to apply to character that was just received. The RTS handshake output to be controlled by software, not controlled automatically by the DUART hardware. The CTS input is to have no automatic effect on the transmitter.
    Be sure to reset the receiver and transmitter circuits on both sides by issuing the appropriate commands to the command registers.

    [15 marks]
    .equ   DUART, 0xFF0000               /* DUART base address */
    .equ   MR1A,  0x00                   /* offsets to DUART registers */
    .equ   MR2A,  MR1A
    .equ   SRA,   0x02
    .equ   CSRA,  0x02
    .equ   CRA,   0x04
    .equ   RBA,   0x06
    .equ   TBA,   0x06
    .equ   ACR,   0x08
    .equ   ISR,   0x0A
    .equ   IMR,   0x0A
    .equ   MR1B,  0x10
    .equ   MR2B,  MR1B
    .equ   SRB,   0x12
    .equ   CSRB,  0x12
    .equ   CRB,   0x14
    .equ   RBB,   0x16
    .equ   TBB,   0x16
    
    Duart_Init:
           MOVEM.L A0,-(SP)              /* save scratchpad registers */
           LEA     DUART,A0              /* point to DUART base address */
    
    /* Ensure that the MR pointers are to MR1A and MR1B */
           MOVE.B  #0b00010000,CRA(A0)   /* bits 6-4: reset pointer to MR1A */
           MOVE.B  #0b00010000,CRB(A0)   /* bits 6-4: reset pointer to MR1B */
           CLR.B   CRA(A0)               /* no command to A */
           CLR.B   CRB(A0)               /* no command to B */
    
    /* Initialize MR1A and MR1B */
           MOVE.B  #0b10100110,MR1A(A0)  /* bit 7: RTS on when FIFO full */
                                         /* bit 6: IRQs per char */
    				     /* bit 5: block-mode error status */
    				     /* bits 4-2: odd parity */
    				     /* bits 1-0: 7-bit data */
    
           MOVE.B  #0b00010011,MR1B(A0)  /* bit 7: RTS controlled by software */
                                         /* bit 6: IRQs per char */
    				     /* bit 5: char-mode error status */ 
    				     /* bits 4-2: no parity */
    				     /* bits 1-0: 8 data */
    
    /* Initialize MR2A and MR2B */
           MOVE.B  #0b00110111,MR2A(A0)  /* auto RTS output on */
                                         /* auto CTS TxA inhibit on */
                                         /* 1.0 stop bit */
    
           MOVE.B  #0b00001111,MR2B(A0)  /* auto RTS output off */
                                         /* auto CTS TxB inhibit off */
    				     /* 2.0 stop bits */
    
    /* Select the baud rates */
           MOVE.B  #0b00000000,ACR(A0)   /* use baud rate set 1 */
           MOVE.B  #0b10011001,CSRA(A0)  /* 4800 used by channel A */
           MOVE.B  #0b10111011,CSRB(A0)  /* 9600 used by channel B */
    
    /* Enable the desired interrupts */
           MOVE.B  #0b00110000,IMR_COPY  /* enable RxRDYB and TxRDYB IRQs */
           MOVE.B  IMR_COPY,IMR(A0)
    
    /* Issue reset commands to channels A and B */
           MOVE.B  #0b00100000,CRA(A0)   /* bits 6-4: reset receiver A */
           MOVE.B  #0b00110000,CRA(A0)   /* bits 6-4: reset transmitter A */
           MOVE.B  #0b01000000,CRA(A0)   /* bits 6-4: reset error status A */
           MOVE.B  #0b01010000,CRA(A0)   /* bits 6-4: reset break interrupt A */
           CLR.B   CRA(A0)               /* no command to A */
           MOVE.B  #0b00100000,CRB(A0)   /* bits 6-4: reset receiver B */
           MOVE.B  #0b00110000,CRB(A0)   /* bits 6-4: reset transmitter B */
           MOVE.B  #0b01000000,CRB(A0)   /* bits 6-4: reset error status B */
           MOVE.B  #0b01010000,CRB(A0)   /* bits 6-4: reset break interrupt B */
           CLR.B   CRB(A0)               /* no command to B */
    
    /* Install the DUART interrupt vector */
           MOVE.L  #DuartISR,DUART_VEC_ADDR
    
    /* Enable channels A and B */
           MOVE.B  #0b00000101,CRA(A0)   /* bits 3-2: enable TxA */
                                         /* bits 1-0: enable RxA */
           CLR.B   CRA(A0)               /* no command to A */
           MOVE.B  #0b00000101,CRB(A0)   /* bits 3-2: enable TxB */
                                         /* bits 1-0: enable RxB */
           CLR.B   CRB(A0)               /* no command to B */
    
           MOVEM.L (SP)+,A0              /* restore scratchpad registers */
           RTS