AAAAAAAAAAAA
M .O .. .. M
A .. OO .O A
M .. .O OO M
A .. O. OO A
M 08 56 37 M
AAAAAAAAAAAA
clock[0]
Upper nibble: 0 → 00002 → . . . .
Lower nibble: 8 → 10002 → O . . .
clock[1]
Upper nibble: 5 → 01012 → . O . O
Lower nibble: 6 → 01102 → . O O .
clock[2]
Upper nibble: 3 → 00112 → . . O O
Lower nibble: 7 → 01112 → . O O O
BCD clock that displays time 10:59:59P with input clock = {0x10, 0x59, 0x59, 0x80}:
PPPPPPPPPPP
M .. .O .O M
P .. O. O. P
M .. .. .. M
P O. OO OO P
M 10 59 59 M
PPPPPPPPPPPP
clock[0]
Upper nibble: 1 → 00012 → . . . O
Lower nibble: 0 → 00002 → . . . .
clock[1]
Upper nibble: 5 → 01012 → . O . O
Lower nibble: 9 → 10012 → O . . O
clock[2]
Upper nibble: 5 → 01012 → . O . O
Lower nibble: 9 → 10012 → O . . O
Note that the layout for each entry (hours, minutes, seconds) is displayed vertically, but you can only print out
LEDs in each line from left to right (horizontally). There are many ways to implement this function. One way
Back to Top
would be to use bit masks to extract bits from each nibble of the clock array and print out the corresponding
characters to indicate lit or unlit LEDs.
All the characters you will need to print are defined as constants in pa2.h.
main.c
int main( int argc, char *argv[] );
The main function will drive the rest of the program. It will create the BCD clock array, perform. input checking
by parsing the command-line arguments, and display the BCD clock for a specified (or default) number of ticks
if no errors were encountered.
First, create a zero-filled array of unsigned char of size CLOCK_ARR_SIZE on the stack. This array contains
the hours, minutes, seconds, and AM/PM values of the BCD clock that we will be displaying and updating
throughout the program.
Our first error check will be to ensure that the user didn’t enter more than the maximum number of command
line arguments allowed (use the MAX_ARGS constant from pa2.h). If they did, print the usage and return
EXIT_FAILURE right away.
Now we can parse the command line arguments:
1. If the first command line argument is STR_HELP ("--help"), print usage and return EXIT_SUCCESS
right away.
2. numTicks:
a. If numTicks was not entered as the first command line argument, initialize it with DEF_TICK.
b. If numTicks was specified as the first argument: convert numTicks from a string to a long using
strtol() (see man -s3 strtol). Remember to set the global variable errno to 0 right
before each call to strtol() to accurately identify when errors occur (see man -s2 intro).
If numTicks was successfully converted, make sure it is within the ranges defined in
pa2.h.
3. startTime:
a. If startTime was not entered as the second command line argument, populate the struct tm
with the default time. To set the default startTime into a struct tm, we must use
timeRightNow() (provided with the starter files) and localtime() (see man -s3 ctime)
to get the current time and then use convertTime()to get the system’s local time. (Hint: look
up struct timeval and struct tm, and how you need to make use of these structures in
function calls). Look at the function description for timeRightNow() below for more info.
b. If startTime was specified as the second command line argument, populate the struct tm by
calling interpretTime(). Check the return value of interpretTime()for errors in the order
they appear below:
Back to Top
If return value contains How to Handle
ERR_TIME_FORMAT Print error message using STR_TIME_FORMAT_ERR
ERR_TIME_NUM Print error message using STR_TIME_PARSE_ERR
ERR_TIME_RANGE Print error message using STR_TIME_RANGE_ERR
If any errors occurred during the argument parsing, print usage and return EXIT_FAILURE (after parsing all
the arguments).
If no errors were encountered:
● If the startTime is not specified by the user, print out current time (using the struct tm pointer that
points to the populated struct tm structure) before displaying any BCD clock. Hint: use asctime()
to format the current time before printing.
● Set the BCD Clock using the struct tm pointer (that points to the populated struct tm structure)
and your setClock() function.
● For each tick in numTicks, display the BCD clock and then update the clock after each tick. (Note that if
numTicks is 7, we will print the clock a total of 8 times because we want to print the clock with the initial
startTime before we begin the ticks--see public executable, and make sure your output matches
exactly).
Reasons for error:
● Incorrect number of arguments
● Error parsing numTicks or numTicks wasn’t within range.
● startTime was not formatted correctly
● Error parsing values of startTime or values of startTime were not within range.
Return Value: EXIT_SUCCESS on success; EXIT_FAILURE if any errors were encountered.
timeRightNow.c
int timeRightNow( struct timeval * tp, void * p );
This function is provided for you. Do not make any changes to this file.
This routine calls the function gettimeofday() which will populate the struct timeval passed in. See
man -s3 gettimeofday for information on how to use this function. Because gettimeofday() ignores
the void * p passed in, just pass in a null pointer when you call this function from main().
Return Value: 0 to indicate success, and -1 to indicate an error (you do not need to check for errors from this
function when calling it from main()).
isInRange.s
long isInRange( long num, long min, long max );
This is just your isInRange() from PA1 (copy it over from your ~/pa1 directory).
Reasons for error:
● minRange is greater than or equal to maxRange → return -1
Return Value: -1 if an error occurred. Otherwise, return 1 if value is in range and 0 if not in range.
Back to Top
isEven.s
long isEven( long value );
This is just your isEven() from PA1 (copy it over from your ~/pa1 directory).
Return Value: 0 if value is odd; 1 if value is even.
myRemainder.s
long myRemainder( long dividend, long divisor );
This is just your myRemainder() from PA1 (copy it over from your ~/pa1 directory).
Return Value: The remainder as a 32-bit signed integer.
printChar.s
void printChar( char c );
This is just your printChar() from PA1 (copy it over from your ~/pa1 directory).
Return Value: None.
Unit Testing
You are provided with only one basic unit test file for the Milestone function, testsetClock.c. This file only
has minimal test cases and is only meant to give you an idea of how to write your own unit test files. You must
write unit test files for each of the Milestone functions, as well as add several of your own thorough
test cases to all of the unit test files. You need to add as many unit tests as necessary to cover all
possible use cases of each function. You will lose points if you don’t do this! You are responsible for
making sure you thoroughly test your functions. Make sure you think about boundary cases, special cases,
general cases, extreme limits, error cases, etc. as appropriate for each function. The Makefile includes the
rules for compiling these tests. Keep in mind that your unit tests will not build until all required files for that
specific unit test have been written. These test files will be collected with the Milestone, so they must be
complete before you submit your Milestone.
Unit tests you need to complete:
testsetClock.c
testincrementClockValue.c
testinterpretTime.c
testtickClock.c
To compile:
$ make testsetClock
To run:
$ ./testsetClock
(Replace “testsetClock” with the appropriate file names to
compile and run the other unit tests)
Back to Top
README Questions
1. How do you maintain your integrity even when you're stressed, pressured, or tired?
2. Assume in some C code you have the following array:
int arr[] = {10, 20, 30, 40};
And you want to get the value of the second element (int second = ?). How would you do this
without using the array brackets []? (Hint: think about pointer manipulation)
3. [Vim] What is the command to search and replace all occurrences of ‘foo’ with ‘bar’ ? What is the
command to search and replace all occurrences of ‘foo’ with ‘bar’ but ask for confirmation first, and
what option should you type to confirm substitution of this match?
4. [Vim] What is the command to open another file called file.txt (in the same directory) in the current
vim session by splitting the window into top and down? How about splitting into left and right? How do
you move between files when in split mode?
5. [Vim] What is the command to quit without saving after you made some edits?
6. [Vim] What is the command to show tabs and what is the command to turn it off?
7. [Vim] What is the command to show line numbers?
8. [Unix] What is the command to show lines that contain “errno” in the file main.c? What is the
command to show five lines above and below each line that contains “errno” in the file main.c?
9. [Unix] What is the command to change the permissions of the file file.txt such that no one can
read, write or execute the file? What is the command to check for the file permissions of file.txt?
10. [Unix] What is the command to open a file file.txt in vim and go to a certain line number x? (This is
a single command) [Vim] What is the command to go to a certain line number x in vim?
Extra Credit
There are 5 points total for extra credit on this assignment.
● [1.5 Points ] chime.c -- print out Ding! Dong! at every hour boundary for hour number of times
● [1.5 Points ] interpretTimeEC.c -- allows the user to enter the start time in 24 hour format
● [ 2 Points ] max7.s and maxmain.s -- find the max of seven numbers and print it out
There are three components to this extra credit. Two parts (chime.c and interpretTimeEC.c) build upon
your non-extra credit pa2 assignment, so do not begin this extra credit until you are completely certain that
your pa2 assignment works perfectly.
First, copy your non-extra credit files to extra credit files using the following commands. Note: do not modify
your non-extra credit files.
cs30xyz@pi-cluster-001:~/pa2$ cp main.c mainEC.c
cs30xyz@pi-cluster-001:~/pa2$ cp interpretTime.c interpretTimeEC.c
You will be making two additions to this program. First, adding in the chime ability, described in the function
description below. A small change/addition will need to be made to mainEC.c to accommodate for this
feature. The second is to allow users to input the start time in 24 hour format. interpretTimeEC.c will adapt
for this, converting that time into 12 hour time as stored in our struct tInfo.
The last component is a translation exercise from C to ARM assembly as described below.
Back to Top
Compiling:
You can compile the BCD Clock extra credit using the following command.
cs30xyz@pi-cluster-001:~/pa2$ make pa2EC
Sample Executable:
cs30xyz@pi-cluster-001:~/pa2$ ~/../public/pa2ECtest
chime.c
void chime( const unsigned char clock[] );
This function will make the clock “chime” on the hour by printing out the appropriate “chime” when the time
stored in clock is on an hour boundary (meaning the time is exactly 1 o’clock, 2 o’clock, 3 o’clock, etc.). If the
time stored in clock is not on an hour boundary, don’t print anything and simply return.
Otherwise, depending on the hour, print out an alternating pattern of “Ding!” and “Dong!” hour number of times
(always starting with “Ding!”).
For example:
clock output
04:20:30
03:00:00
Ding!
Dong!
Ding!
02:00:00 Ding! Dong!
interpretTimeEC.c
unsigned long interpretTime( struct tInfo * tInfoPtr, const char * time );
This function retains much of the same functionality as the non-extra credit version, but allows for time to be
entered in 24 hour format.
When parsing the hour, you should change the max value to be 23 (as defined in pa2.h). After checking to
see if the hour is in range, you need to convert it to 12 hour time. So, if the user enters hour 13, you should set
the hour to be 1 and am_pm to denote pm. Note that the user is no longer able to enter time in 12 hour format,
so the conditions to check for 'a' or 'p' after seconds should be removed. See the extra credit usage statement
for more information on the time format.
For example:
User input 12 hour time
0:25:32 12:25:32 AM
13:20:56 1:20:56 PM
12:15:20 12:15:20 PM
Return Value: Same as non extra credit version.
Back to Top
Max7 Extra Credit
This extra credit will give you some practice with allocating local variables on the stack and calling functions
with more than four arguments in ARM. Your task is to translate the two provided C functions into assembly.
This program does not take user input and only has one output as shown below; your program must match this
output exactly.
cs30xyz@pi-cluster-001:~/pa2$ ./pa2max7
Max of 1 2 3 4 5 6 7 is 7
cs30xyz@pi-cluster-001:~/pa2$
You will have to write ARM functions to replicate the two C files (maxmain.c and max7.c) that are provided
below. You will write one file maxmain.s to replicate the functionality of the main function and another file
max7.s to replicate the functionality of the max7 function.
You must also allocate space and pass additional arguments beyond the first 4 (r0-r3) on the stack, with arg5
at a lower address than arg6 which is at a lower address than arg7. You will access these additional formal
parameters via positive offsets from the fp in the called function. Deallocate these additional args after the
function call returns.
No magic numbers!
main() is responsible for setting up the local variables, calling max7(), then setting up and executing the call
to printf() to output the max number. max7() needs to take its seven parameters and return the max of
the numbers.
Back to Top
maxmain.c
1 #include
2
3 int main( void ) {
4
5 int a = 1;
6 int b = 2;
7 int c = 3;
8 int d = 4;
9 int e = 5;
10 int f = 6;
11 int g = 7;
12
13 int max;
14
15 max = max7( a, b, c, d, e, f, g );
16
17 printf( "Max of %d %d %d %d %d %d %d is %d\n", a, b, c, d, e, f, g, max );
18
19 return 0;
20
21 }
max7.c
1 int max7( int a, int b, int c, int d, int e, int f, int g ) {
2 int max = a;
3
4 if(b > max) max = b;
5 if(c > max) max = c;
6 if(d > max) max = d;
7 if(e > max) max = e;
8 if(f > max) max = f;
9 if(g > max) max = g;
10
11 return max;
12 }
Compilation:
To compile, use this command:
gcc -g -o pa2max7 maxmain.s max7.s
This command compiles our code using gcc, the GNU Compiler collection. The -g option tells gcc to produce
debug information for our program that allows us to debug it using gdb. The -o option is used to specify what
we want our compiled executable file to be called. In this case, by using “-o pa2max7” we are telling gcc to
call the executable pa2max7. We are supplying maxmain.s and max7.s to gcc as source files to be
compiled. In order for compilation to succeed, one of our sources must contain a main function. In this case,
that file is maxmain.s.
Back to Top
Turnin Summary
See the turnin instructions here. Your file names must match the below *exactly* otherwise our Makefile will
not find your files.
Milestone Turnin:
Due: Wednesday night, May 2 @ 11:59 pm
Files required for the Milestone:
setClock.s
testsetClock.c
incrementClockValue.s
testincrementClockValue.c
interpretTime.c
testinterpretTime.c
tickClock.c
testtickClock.c
Final Turnin:
Due: Wednesday night, May 9 @ 11:59 pm
Files required for the Final Turn-in:
setClock.s
incrementClockValue.s
convertTime.s
isInRange.s
isEven.s
myRemainder.s
printChar.s
interpretTime.c
printClock.c
tickClock.c
timeRightNow.c
main.c
testsetClock.c
testincrementClockValue.c
testinterpretTime.c
testtickClock.c
pa2.h
pa2Strings.h
pa2Globals.c
test.h
Makefile
README
Extra Credit Files:
chime.c
interpretTimeEC.c
mainEC.c
maxmain.s
max7.
If there is anything in these procedures which needs clarifying, please feel free to ask any tutor, the instructor,
or post on the Piazza Discussion Board.