Laboratory 7 (individual) -- I/O devices

Due March 1, 2019
35 points


In this lab, you will gain experience writing assembly-language programs and interacting with I/O devices. This assignment is to be done individually.

Each person will write a device driver and test program for one of the following I/O devices: speaker, microphone, PS/2 keyboard, USB mouse, touchscreen, LCD display, VGA monitor, SD card, camera, serial send, serial receive. Each member of your team should choose a different I/O device. I recommend one member write the device driver for the serial send controller, because you can use this as console to help debug future programs.

This handout also provides information about other I/O devices (SDRAM, real-time clock, Fast Fourier Transform co-processor, PWM, SPI), but these should not be chosen for this lab.

You should develop and debug your device driver and program initially on ase100. You should then run your device driver and program on a hardware E100 processor, which you will create by adding I/O controllers to your E100 processor.

E100 I/O devices

E100 programs communicate with I/O devices by reading and writing to variables provided by those devices. These variables are called device registers. Each device register is assigned a memory address, and E100 programs read and write a device register via normal instructions (e.g., cp, bne) to its assigned address. This method for accessing I/O device registers is called memory-mapped device registers.

Some device registers can be read to determine their current value; for example, cp switch 0x80000000 reads the current value of SW[17:0]. Other device registers may be written to change their value; for example, cp 0x80000001 tmp writes the value of tmp to LED_RED[17:0].

The following table lists the I/O devices available for the E100, along with the addresses (in hexadecimal) assigned to each device registers and whether the register can be read or written. The links in the right column of the table provide detailed information about the behavior of each device and the test program that you should write for that device.
Address Allowed access Definition Use
0x80000000read bits 17-0: SW[17:0] binary input
0x80000001write bits 17-0: LED_RED[17:0] binary output
0x80000002write bits 7-0: LED_GREEN[7:0] binary output
0x80000003write bits 15-0: HEX3-HEX0 hexadecimal output
0x80000004write bits 15-0: HEX7-HEX4 hexadecimal output
0x80000005read bits 31-0: real-time clock measure time
0x80000010write bit 0: lcd_command LCD display
0x80000011read bit 0: lcd_response
0x80000012write bits 3-0: lcd_x[3:0]
0x80000013write bit 0: lcd_y
0x80000014write bits 7-0: lcd_ascii[7:0]
0x80000020write bit 0: ps2_command PS/2 keyboard
0x80000021read bit 0: ps2_response
0x80000022read bit 0: ps2_pressed
0x80000023read bits 7-0: ps2_ascii[7:0]
0x80000030write bit 0: sdram_command SDRAM memory
0x80000031read bit 0: sdram_response
0x80000032write bit 0: sdram_write
0x80000033write bits 24-0: sdram_address[24:0]
0x80000034write bits 31-0: sdram_data_write
0x80000035read bits 31-0: sdram_data_read
0x80000040write bit 0: speaker_command speaker
0x80000041read bit 0: speaker_response
0x80000042write bits 31-0: speaker_sample
0x80000050write bit 0: microphone_command microphone
0x80000051read bit 0: microphone_response
0x80000052read bits 31-0: microphone_sample
0x80000060write bit 0: vga_command VGA monitor
0x80000061read bit 0: vga_response
0x80000062write bit 0: vga_write
0x80000063write bits 9-0: vga_x1[9:0]
0x80000064write bits 9-0: vga_y1[9:0]
0x80000065write bits 9-0: vga_x2[9:0]
0x80000066write bits 9-0: vga_y2[9:0]
0x80000067write bits 23-0: vga_color_write[23:0]
0x80000068read bits 23-0: vga_color_read[23:0]
0x80000070write bit 0: mouse_command USB mouse
0x80000071read bit 0: mouse_response
0x80000072read bits 31-0: mouse_deltax
0x80000073read bits 31-0: mouse_deltay
0x80000074read bit 0: mouse_button1
0x80000075read bit 0: mouse_button2
0x80000076read bit 0: mouse_button3
0x80000080write bit 0: sd_command SD card
0x80000081read bit 0: sd_response
0x80000082write bits 0: sd_write
0x80000083write bits 29-0: sd_address[29:0]
0x80000084write bits 31-0: sd_data_write
0x80000085read bits 31-0: sd_data_read
0x80000090write bit 0: serial_receive_command serial communication
(wired and wireless)
0x80000091read bit 0: serial_receive_response
0x80000092read bits 7-0: serial_receive_data[7:0]
0x800000a0write bit 0: serial_send_command
0x800000a1read bit 0: serial_send_response
0x800000a2write bits 7-0: serial_send_data[7:0]
0x800000b0write bit 0: camera_command camera
0x800000b1read bit 0: camera_response
0x800000b2write bits 9-0: camera_x[9:0]
0x800000b3write bits 9-0: camera_y[9:0]
0x800000b4write bits 1-0: camera_scale[1:0]
0x800000b5write bit 0: camera_mirror
0x800000c0write bit 0: fft_send_command Fast Fourier Transform
0x800000c1read bit 0: fft_send_response
0x800000c2write bits 31-0: fft_send_real
0x800000c3write bits 31-0: fft_send_imaginary
0x800000c4write bits 0: fft_send_inverse
0x800000c5write bit 0: fft_send_end
0x800000d0write bit 0: fft_receive_command
0x800000d1read bit 0: fft_receive_response
0x800000d2read bits 31-0: fft_receive_real
0x800000d3read bits 31-0: fft_receive_imaginary
0x800000e0write bit 0: touch_command touchscreen
0x800000e1read bit 0: touch_response
0x800000e2read bits 9-0: touch_x
0x800000e3read bits 8-0: touch_y
0x800000e4read bit 0: touch_pressed
0x800000f0write bit 0: pwm_command PWM
0x800000f1read bit 0: pwm_response
0x800000f2write bits 31-0: pwm_period
0x800000f3write bits 31-0: pwm_high
0x80000100write bit 0: spi_command SPI
0x80000101read bit 0: spi_response
0x80000102write bits 7-0: spi_send_data
0x80000103read bits 7-0: spi_receive_data

I/O device protocol

At first glance, it seems easy to send data to/from an I/O device. For example, one could send a sample to the speaker simply by copying data to the speaker_sample device register. However, this is not quite enough to send a sequence of values. One problem is that the speaker controller doesn't know when the program has sent the next value to the speaker_sample device register. Another problem is that the program doesn't know when the speaker controller has read the last sample and is ready to receive the next sample. These problems are addressed by an I/O device protocol.

A protocol is used to guide the interaction between two parties. In the context of I/O devices, an I/O protocol is used to guide the interaction between an E100 program and an I/O device. A protocol defines the steps involved in the interaction and includes how each party knows when the current step is complete. We will use a protocol to send commands to an I/O device and receive the response from that device.

The part of an E100 program that implements the E100's side of an I/O protocol is called a device driver.

The I/O protocol uses four types of signals to allow an E100 program to send commands to a device and receive the response from that device.

The steps involved in sending data to an output device are:
command response Description
0 0 System is idle.
1 0 E100 program sets the command parameters to describe the desired command, then sets command to 1 to ask the device to execute the command. After setting command to 1, the E100 program waits for device to execute the command.
1 1 After the device executes the command, it sets the response parameters for the command, then sets response to 1 to tell the E100 program that it has executed the command and is sending back the response. After setting response to 1, the device waits for the E100 program to set command to 0.
0 1 E100 program sets command to 0 to tell the device that the program has seen the device's response. After this state, the device sets response back to 0, and the system returns to the Idle state.

Pre-lab assignment

Your pre-lab assignment is to write, test, and debug your device driver and test program. These tasks can be done by running the E100 assembler and simulator, ase100. Debugging on ase100 is much easier than debugging on the DE2-115 because you can control the execution of your program and view its state as it executes.

Your test program and device drivers should be in separate files. Include the device driver file in your test program by adding a line at the end of your test program, such as:

#include driver.e

Most of your testing and debugging should occur before your lab section. The lab section is meant for running final tests on the DE2-115 board and for demonstrating your program to a lab instructor.

Incremental development

One of the surest ways to waste a lot of time when programming is to try to write and test the entire program all at once. This is especially true when you are trying a new task, language, or unfamiliar environment (such as this lab!).

A better way to program is to write and test a little at a time. The less familiar you are with the material, the smaller the piece you should write and test. For example, since you are new to assembly-language programming, you might write a program consisting of a single instruction (plus halt), then run that program and verify that it changed memory and the IAR as you expected.

For this lab, I strongly recommend you first write and test your device driver before you write your full test program. To test your device driver, write a trivial test program that initializes the input parameters (if any), calls the device driver, displays the output parameters (if any) to the hex digits, then halts. After this works, write a second test program that calls your device driver twice (this verifies that the first call to your device driver left things in the right state).

After you verify that your device driver is correct, then write your test program. Again, do this a little at a time. For example, if your test program requires a loop, test one iteration of the loop before running multiple iterations.

In-lab demonstration

Demonstrate your test program and device driver on the DE2-115 to a lab instructor. After you've demonstrated your program, submit the final version of your test program and device driver here.