[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.
[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).
[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.
[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:
[10 marks]
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:
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:
[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.
[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).
[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