You are on page 1of 5

Course project - AGra

Course: Microprocessors and Assembly Languages

Objectives
● Apply all the skills learned in the course to develop software library in Assembly
language
● Learn about a test bench
● Learn about graphics primitives
● Optimize the code for speed, avoiding costly instructions

Description
Develop agra - a graphics library of functions in Assembly that could be called from C. The
functions implement drawing operations on a graphics buffer in memory. The graphics
primitives to be drawn are:

● A point (a pixel)
● A line
● A circle, not filled
● A triangle, filled

You should also develop a C program that tests the library by calling its functions to draw a
picture.

You must create the following files with these exact names:
● Makefile - the makefile used to compile and test your program
● agra_main.c - the main C program for testing the library
● agra.s - the Assembly program, implementing the graphics primitive drawing
functions
● agra.h - the header file with the prototypes of the Assembly functions, in C
● framebuffer.c - the implementation of buffer access functions, in C
● framebuffer.h - optional
● report.pdf - the report about the accomplishments of the project

All the files must be in the directory named agra under your home directory on the course
server.
Data Types
The data types and the prototypes of the functions to be implemented in Assembly are
declared in the file agra.h, and should be as follows:

// Color type for a pixel (a 32 bit number):


// r,g,b are red, green and blue components.
// Each color component is 10 bits long
// op is the operation that must be performed
// with the background color for this pixel.
// 0 - means overwrite.
typedef struct {
unsigned int r : 10;
unsigned int g : 10;
unsigned int b : 10;
unsigned int op: 2;
} pixcolor_t;

// Operations for a pixel with the background


// Used in the pixcolor_t structure field "op".
typedef enum {
PIXEL_COPY = 0,
PIXEL_AND = 1,
PIXEL_OR = 2,
PIXEL_XOR = 3
} pixop_t;

// Function: set the current color and operation


void setPixColor( pixcolor_t * color_op);

// Function: draw one pixel


void pixel(int x, int y, pixcolor_t * colorop);

// Function: draw a line between two points


// using the current color
void line(int x1, int y1, int x2, int y2);

// Function: draw a filled triangle


// using the current color
void triangleFill(int x1, int y1, int x2, int y2, int x3,
int y3);

// Function: draw a circle using the current color


void circle(int x1, int y1, int radius);

Suggestion: start the development by ignoring the operation op field, assuming that the
operation is always to replace - “paint over” the contents of the frame buffer. Once you have
this functionality up and running, see to the implementation of the various operations as
defined in the “pixop_t”.
Frame Buffer Access Functions
Your library functions must use the following FrameBuffer functions to access the frame
buffer and to determine its properties.

// Frame buffer start address


pixcolor_t * FrameBufferGetAddress();

// Frame width, in pixels


int FrameBufferGetWidth();

// Frame height, in pixels


int FrameBufferGetHeight();

// Frame output to a “screen”


int FrameShow();

FrameShow() should assume that the (0,0) coordinate is at the top left corner of the frame.

In all cases when the return value type is int but it is not described, 0 means success, and 1
means failure.

Color coding
In a general case the framebuffer would stream the contents of the buffer to a real graphical
display, such as LCD or OLED screens. However, for testing purposes in this project, the
frame buffer contents will be represented using characters when printed. Each pixel is
represented by one character.

Use the following encoding for the pixels, when printing them:
● The black color is a space ' ' (black)
● The white color is a star '*' (white)
● Use the corresponding characters if the dominating color
is as follows:
○ 'R' (red)
○ 'G' (green)
○ 'B' (blue)
○ 'C' (cyan)
○ 'M' (magenta)
○ 'Y' (yellow)

A color is considered dominating if this color has the most intensity. This could be observed
with a help of a color cube, where each of the RGB components is a coordinate on one axis
of the cube. One might ask, how do we determine the dominating color if each component
has 10 bits? A possible solution is to divide the RGB cube with three planes so that you end
up with 8 smaller cubes. Then assign one dominating color for each of the small cubes. A
crude approximation would be normalizing each of the RGB components to a single bit (e.g.
taking the most significant bit). Then RGB will represent a 3-bit combination that determines
which of the 8 colors is dominating.

Test bench in C
The Assembly program should be wrapped in a main program written in C. The main
program will parse the arguments and prepare the memory buffers as needed. It will also
print the results.

For this task, the main program will act as a test bench - the environment for testing your
library. It will create a graphics buffer in memory that will be passed to the library function
calls. Then it will call the library functions in succession to draw a picture on the memory
buffer. Finally it will print the buffer contents to verify the result of the function calls.

The test sequence must include the following:


1. Define a buffer of the size 40 x 20 (using your framebuffer.c code)
2. Clear the buffer, fill every pixel with 0x00000000
3. Draw a white pixel at (25,2)
4. Draw a line from (0,0) to (39,19), blue, using intensity 0x03ff
5. Draw a filled triangle: (20,13), (28,19), (38,6), green, using intensity 0x03ff
6. Draw a circle centered at (20,10) and with radius 7, red, using intensity 0x03ff
7. Call function FrameShow()
Note, that the output of the FrameShow() is done by printing characters representing the
contents of the buffer. This is to simplify the testing procedure.

Error handling
The following situations may happen and should be handled accordingly:
● If a pixel for any primitive is drawn outside the buffer dimensions, the pixel should be
ignored (not drawn). Thus, you may have a primitive that is just partially visible on the
buffer.
● If a function is called with incorrect parameters, it should do nothing and just return.

Testing
The programs should be compiled, linked, and tested with the qemu-arm emulator.

When testing, the arguments should be passed on the command line, as in the example:

$ qemu-arm … agra > outfile.txt

In the example above outfile.txt is a file where the result should be written.
The Report
You should write a report about your project and save it to a file in PDF format.
The report should contain the following:
● What functionality has been implemented? How is it implemented?
● What is not implemented, and why?
● What was the biggest challenge in the project?
● What would you do differently next time?
● Other comments.

Submission and Grading


Your submission will be collected from the specified directory on the course server exactly
on the due date and time. The grade will be reported to your grade book. There will also be
the test log file log-grading.txt copied to the submission directory with the test results and
scores.
The scores will be assigned based on the implemented functionality, each primitive will be
evaluated. Also, the testing code and the report will contribute to the final score. Remember
that comments in the code are just as important as getting it to do what you want.

Even though the report should be submitted in a written form, you should also be ready to
discuss your solution with the instructor during the exam.

You might also like