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, 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), 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 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.
|0x80000000||read||bits 17-0: SW[17:0]||binary input|
|0x80000001||write||bits 17-0: LED_RED[17:0]||binary output|
|0x80000002||write||bits 7-0: LED_GREEN[7:0]||binary output|
|0x80000003||write||bits 15-0: HEX3-HEX0||hexadecimal output|
|0x80000004||write||bits 15-0: HEX7-HEX4||hexadecimal output|
|0x80000005||read||bits 31-0: real-time clock||measure time|
|0x80000010||write||bit 0: lcd_command||LCD display|
|0x80000011||read||bit 0: lcd_response|
|0x80000012||write||bits 3-0: lcd_x[3:0]|
|0x80000013||write||bit 0: lcd_y|
|0x80000014||write||bits 7-0: lcd_ascii[7:0]|
|0x80000020||write||bit 0: ps2_command||PS/2 keyboard|
|0x80000021||read||bit 0: ps2_response|
|0x80000022||read||bit 0: ps2_pressed|
|0x80000023||read||bits 7-0: ps2_ascii[7:0]|
|0x80000030||write||bit 0: sdram_command||SDRAM memory|
|0x80000031||read||bit 0: sdram_response|
|0x80000032||write||bit 0: sdram_write|
|0x80000033||write||bits 24-0: sdram_address[24:0]|
|0x80000034||write||bits 31-0: sdram_data_write|
|0x80000035||read||bits 31-0: sdram_data_read|
|0x80000040||write||bit 0: speaker_command||speaker|
|0x80000041||read||bit 0: speaker_response|
|0x80000042||write||bits 31-0: speaker_sample|
|0x80000050||write||bit 0: microphone_command||microphone|
|0x80000051||read||bit 0: microphone_response|
|0x80000052||read||bits 31-0: microphone_sample|
|0x80000060||write||bit 0: vga_command||VGA monitor|
|0x80000061||read||bit 0: vga_response|
|0x80000062||write||bit 0: vga_write|
|0x80000063||write||bits 9-0: vga_x1[9:0]|
|0x80000064||write||bits 9-0: vga_y1[9:0]|
|0x80000065||write||bits 9-0: vga_x2[9:0]|
|0x80000066||write||bits 9-0: vga_y2[9:0]|
|0x80000067||write||bits 14-0: vga_color_write[14:0]|
|0x80000068||read||bits 14-0: vga_color_read[14:0]|
|0x80000070||write||bit 0: mouse_command||USB mouse/touchscreen|
|0x80000071||read||bit 0: mouse_response|
|0x80000072||read||bits 31-0: mouse_deltax|
|0x80000073||read||bits 31-0: mouse_deltay|
|0x80000074||read||bit 0: mouse_button1|
|0x80000075||read||bit 0: mouse_button2|
|0x80000076||read||bit 0: mouse_button3|
|0x80000080||write||bit 0: sd_command||SD card|
|0x80000081||read||bit 0: sd_response|
|0x80000082||write||bits 0: sd_write|
|0x80000083||write||bits 29-0: sd_address[29:0]|
|0x80000084||write||bits 31-0: sd_data_write|
|0x80000085||read||bits 31-0: sd_data_read|
|0x80000090||write||bit 0: serial_receive_command||
(wired and wireless)
|0x80000091||read||bit 0: serial_receive_response|
|0x80000092||read||bits 7-0: serial_receive_data[7:0]|
|0x800000a0||write||bit 0: serial_send_command|
|0x800000a1||read||bit 0: serial_send_response|
|0x800000a2||write||bits 7-0: serial_send_data[7:0]|
|0x800000b0||write||bit 0: camera_command||camera|
|0x800000b1||read||bit 0: camera_response|
|0x800000b2||write||bits 9-0: camera_x[9:0]|
|0x800000b3||write||bits 9-0: camera_y[9:0]|
|0x800000b4||write||bits 1-0: camera_scale[1:0]|
|0x800000b5||write||bit 0: camera_mirror|
|0x800000c0||write||bit 0: fft_send_command||Fast Fourier Transform|
|0x800000c1||read||bit 0: fft_send_response|
|0x800000c2||write||bits 31-0: fft_send_real|
|0x800000c3||write||bits 31-0: fft_send_imaginary|
|0x800000c4||write||bits 0: fft_send_inverse|
|0x800000c5||write||bit 0: fft_send_end|
|0x800000d0||write||bit 0: fft_receive_command|
|0x800000d1||read||bit 0: fft_receive_response|
|0x800000d2||read||bits 31-0: fft_receive_real|
|0x800000d3||read||bits 31-0: fft_receive_imaginary|
|0x800000e0||write||bit 0: touch_command||Touch|
|0x800000e1||read||bit 0: touch_response|
|0x800000e2||read||bits 9-0: touch_x|
|0x800000e3||read||bits 8-0: touch_y|
|0x800000e4||read||bit 0: touch_pressed|
|0x800000f0||write||bit 0: spi_command||SPI|
|0x800000f1||read||bit 0: spi_response|
|0x800000f2||write||bits 7-0: spi_send_data|
|0x800000f3||read||bits 7-0: spi_receive_data|
|0x80000100||write||bit 0: pwm_command||PWM|
|0x80000101||read||bit 0: pwm_response|
|0x80000102||write||bits 31-0: pwm_period|
|0x80000103||write||bits 31-0: pwm_compare|
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:
|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.|
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:
You should be using a Github repository to store, submit, and share your files among your team. So to get started fill out the line below with your Github username and team number and execute it to clone the repository. If you have problems adding, commiting, and pushing your files to the repository see Lab 5.
$ git clone https://[USERNAME]@github.com/ENGR100-W15/team[team#]-LAB7.git
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.
Demonstrate your test program and device driver on the DE2-115 to a lab instructor. After you've demonstrated your program, make sure that the final version of your test program and device driver have been pushed to your team's git repo.