\documentstyle[epsf,6.111-lab,12pt]{article}

\name{Marc Horowitz}
\labnum{4 -- Music Box}
\recitation{John Piscitello \\ Tuesday 2pm}

\begin{abstract}
A complex circuit is constructed which reads hexadecimally encoded
music from a serial transmitter and plays it on a speaker.  The main
part of the circuit is a microcontroller unit (MCU) based around a
29c10 sequencer.  This MCU controls the UART to receive the data, a
conversion unit which decodes the hex data into binary, an SRAM unit
which stores the data, and an output block, which contains a DAC to
convert the music to into analog output for the speaker.
\end{abstract}

\begin{document}

\coverpage

\tableofcontents

\listoftables

\newpage

\section{Overview}

This project reads and decodes sequences of notes and durations from a
serial input.  These notes are stored in an SRAM, and if the block ID
number matches that in the switches, the song is played.  This is done
by sending sampled sine wave outputs (precomputed and stored on an
EPROM), to a DAC, and running a speaker from the outputs.

\section{Description}
\subsection{Input Block}

The input block reads the hex-encoded input one byte at time from the
serial line.  This data is converted into binary, and driven onto the
bus, so that it can be stored into the SRAM.  In addition, an
adder\slash accumulator stores the sum of all the values in the line, and
asserts an output if the sum of all bytes received so far is zero.
Since the checksum byte immediately follows the data, this can be used
to make sure there have been no transmission errors.

\subsection{SRAM Block}

The SRAM block is used to store the decoded input before it is played.
It consists of static RAM and address hardware.  The address registers
can be loaded off the bus, in order to set the address which is
encoded in the input from the serial line.  It also asserts a signal
when the output of the SRAM is {\tt 0xff}.  This is used by the MCU to
determine if the song is over.

\subsection{Output Block}

The output block plays back the notes.  A ROM is encoded with a sine
wave, and a counter\slash adder system steps through the values in the ROM,
sound, sending them to a Digital-Analog converter, for output on an
external speaker.

\subsection{MCU}

The MCU implements a microcode system.  This system consists of a
microcode program, which drives twelve assertions, and uses a
sequencer capable of jumps, subroutines, and loops, while making
decisions based on one of eight input status bits.  The basic program
inplemented by the MCU is as follows

\begin{enumerate}
\item Read a block of serial data.  Reset if the checksum fails.
\item If the block number does not match the switches, read the next
block.
\item Loop, playing each note.  Delays between notes are implemented
by loops in empty subroutines.
\item Halt at the end of the song.
\end{enumerate}

\section{Implementation Details}

\subsection{Input Block}

The input block consists of three major parts.  The UART takes the
serial data which is input to the circuit and converts it into bytes
of parallel data.  The UART is a single chip, so the implementation is
trivial.

The input data consists of lines of Intel hex-encoded format data.
The second part of the input block is responsible for converting two
ASCII hex characters data into one byte of binary data.  This is
implemented in a single 22v10.  This PAL also has an output which is
asserted if the character is a colon, signifying the beginning of a
line.  The PAL's tri-state drivers drive directly onto the bus when
the /OE/ control signal is asserted.


The third part of the input block is an adder\slash accumulator which keeps
track of the checksum of each line in order to check it against the
transmitted checksum.  This is implemented as an 8-bit full adder and
an 8 bit register, in two 22v10's.  When CKADD is asserted, the inputs
(which are taken from the bus) are added into the value contained in
the register.  This is done when a new byte of data has been received,
and has been converted from ASCII to binary.  The sum outputs of the
adder are compared against zero to yield a signal which is asserted
only when the sum of all the bytes since CKCLR was last asserted is
zero.

\subsection{SRAM block}

The SRAM block stores the data as it is read from the serial input,
before it is played.  It consists of a memory address register (MAR),
a static RAM (SRAM), a NAND to determine if the output is 0xff, and a
comparator to determine if the SRAM is outputting the same value as
contained in the switches.

The MAR is implemented by three '163 counters which can be loaded from
the bus as a high byte (/MARHILOAD/) and a low byte (/MARLOLOAD/).
The MAR can also be incremented (MARCNT) and cleared (/MARCLR/).  The
MAR outputs drive the address lines of the SRAM.  The SRAM outputs
read or drive the bus, depending on the value of the /SRAMCS/ and
/SRAMWE/ control signals.

The NAND compares the value on the bus (driven by the SRAM) for
equality with 0xff and asserts /SRAMEQFF/ if it is.  This is necessary
for the control firmware, described below.  The comparator describes
the value on the bus for equality with the switches, in which case
SRAMEQSWT is asserted.

\subsection{Output Block}

The output block consists of a register (74LS377) which stores the
note currently being played, a 10-bit adder\slash accumulator which is very
similar to the checksum accumulator in the input block, a ROM (2716)
which contains an encoding of a sine wave, and a DAC, which drives an
external speaker.

The contents of the ROM are designed such that if the values in the
ROM are converted by the DAC at 5120 values per second, then a 5 Hz
tone will be played.  So, if every other number is driven, a 10 Hz
tone will be played, every third a 15 Hz tone, etc.

To play a note, the register is loaded with the note value (which
comes across the bus from the SRAM) and the adder\slash accumulator value is
cleared.  The adder\slash accumulator outputs are used as an address into
the sine ROM, which drives the DAC.  The adder increments by the note
value at a rate of 5.12 kHz, which results in a (register*5) kHz tone
being played.

\subsection{Microcontroller Unit (MCU)}

The MCU contains the firmware which controls the entire circuit.  It
consists of a 29c10 sequencer, two 2716's containing the firmware
program, a pair of registers driving two 20v8 PALs which decode the
assertion signals, a '151 mux which drives the /CC/ input of the
sequencer, and a buffer to allow the contents of the low ROM to drive
the bus.

The MCU runs the program encoded in the ROMs.  The basic algorithm is
as follows: Read characters until a colon is read.  Read a byte, and
load it into the sequencer count register.  Read the two address
bytes, and load them into the MAR address registers.  Read the next
byte.  If it is odd, this is the last line.  Next, read all the data
into the SRAM, accumulating a checksum along the way.  When the last
byte is read, make sure the checksum is zero.  If it is not, reset.
If this is not the last line, go back to wait for a colon.  If this
was the last line, compare the switches against SRAM location zero.
If they do not match, reset.  If they do match, enter the play loop.
Read the first note into the note register and the duration into the
sequencer count register.  For each iteration through the loop, drive
the DAC, wait 180 cycles, and increment the sine ROM address by the
note register.  Repeat this seven more times.  Then decrement the
sequencer count and iterate.  Continue until the duration is zero.
Repeat for all notes.  When note {\tt 0xff} is reached, halt.

\begin{table}
\begin{description}
\item[/DAV/] the UART does not have a byte of data available for
reading
\item[UARTERR] the UART indicates an error condition
\item[COLON] the value most recenty read from the UART was a colon
\item[/ZEROSUM/] the checksum does not equal zero
\item[/SRAMEQFF/] the SRAM output equals 0xff.
\item[SRAMEQSWT] the SRAM output matches the value in the switches
\end{description}
\caption{Multiplexer Condition Codes}
\label{cc}
\end{table}

\begin{table}
\begin{description}
\item[/RDAV/] reset the DAV ouput from the UART
\item[CKADD] add the value on the bus to the checksum
\item[CKCLR] clear the checksum value
\item[CVTCHAR] convert the next ASCII value into binary
\item[MARCNT] increment the MAR
\item[MARHILOAD] load the high byte (MSB) of the MAR
\item[MARLOLOAD] load the low byte (LSB) of the MAR
\item[/MARCLR/] clear the contents of the MAR
\item[/BINDRV/] drive the output of the hextobin converter onto the bus
\item[/SRAMCS/] set the tri-states of the SRAM to read\slash write the bus
\item[/SRAMWE/] set the SRAM to the value on the bus
\item[/NOTELOAD/] load the note register with the value on the bus
\item[MCUVAL] drive the output of the low byte of the MCU ROM onto the
bus
\end{description}
\caption{MCU Assertion Outputs}
\label{assertions}
\end{table}

\newpage
\epsfbox{uart.ps}
\newpage
\epsfbox{cksum.ps}
\newpage
\epsfbox{dbs.ps}
\newpage
\epsfbox{output.ps}
\newpage

\end{document}
