首页 > > 详细

讲解留学生C语言、辅导留学生 Piazza Discussion 、辅导留学生Binary Clock

For this assignment you will build a BCD (Binary Coded Decimal) clock simulator. BCD is a way to represent
decimal digits (0-9) in 4 bits (0000-1001). You will use an array of 4 unsigned chars to store the tens and ones
values of the clock's hours, minutes, seconds and a char ‘A’ or ‘P’ to indicate AM or PM. The tens digit will be
stored in the upper 4 bits (nibble) of each byte. The ones digit will be stored in the lower 4 bits of each byte.
The binary clock display will be similar to the BCD clock I have in my office.

The purpose of this programming assignment is to gain more experience with ARM assembly bit-wise
operations, memory loads and stores (ldr/str), allocating local variables on the runtime stack and accessing
them relative to the frame. pointer (fp). You will use Standard C Library routines and varied techniques to
communicate C Preprocessor-derived values to your assembly routines (accessing global variables set in a C
function and calling C functions from assembly).

IMPORTANT NOTE for Assembly routines:
1. Make sure you do not use registers other than r0-r3 as scratch registers in your assembly functions.
Allocate local variables on the stack instead.
2. Only fp, lr are pushed to the stack.
3. Note that values in r0-r3 will not be preserved after function calls.


Grading

● README: 10 points - See README Requirements here and questions below
http://cseweb.ucsd.edu/~ricko/CSE30READMEGuidelines.pdf
● Compiling: 5 points - Using our Makefile; no warnings. If what you turn in does not compile with the
given Makefile, you will receive 0 points for this assignment. NO EXCEPTIONS!
● Style. 20 points - See Style. Requirements here
http://cseweb.ucsd.edu/~ricko/CSE30StyleGuidelines.pdf
● Correctness: 65 points
○ Milestone (15 points) - To be distributed across the Milestone functions (see below)
○ Make sure you have all files tracked in Git.
● Extra Credit: 5 points - View Extra Credit section for more information.
● Wrong Language: You will lose 10 points for each module in the wrong language, C vs. Assembly or
vice versa.
NOTE: If what you turn in does not compile with given Makefile, you will receive 0 points for this assignment.

Back to Top
Getting Started

Follow these steps to acquire the starter files and prepare your Git repository.

Gathering Starter Files:
The first step is to gather all the appropriate files for this assignment. Connect to pi-cluster via ssh.
$ ssh

Create and enter the pa2 working directory.
$ mkdir ~/pa2
$ cd ~/pa2

Copy the starter files from the public directory.
$ cp ~/../public/pa2StarterFiles/* ~/pa2/

Copy files needed from your pa1 directory.
$ cp ~/pa1/isInRange.s ~/pa2/
$ cp ~/pa1/isEven.s ~/pa2/
$ cp ~/pa1/myRemainder.s ~/pa2/
$ cp ~/pa1/printChar.s ~/pa2/

Starter files provided:
pa2.h
test.h
timeRightNow.c
pa2Strings.h
testsetClock.c
pa2Globals.c
Makefile

Preparing Git Repository:
You are required to use Git with this and all future programming assignments. Refer to the PA0 writeup for how
to set up your local git repository.

Example Input

A sample stripped executable provided for you to try and compare your output against is available in the public
directory. Note that you cannot copy it to your own directory; you can only run it using the following command
(where you will also pass in the command line arguments):
$ ~/../public/pa2test

NOTE:
1. The output of your program MUST match exactly as it appears in the pa2test output. You need to
pay attention to everything in the output, from the order of the error messages to the small things
like extra newlines at the end (or beginning, or middle, or everywhere)!
2. We are not giving you any sample outputs, instead you are provided some example inputs.
You are responsible for trying out all functionality of the program; the list of example inputs is
not exhaustive or complete. It is important that you fully understand how the program works
and you test your final solution thoroughly against the executable.

 

Back to Top
Example input that has error output:
cs30xyz@pi-cluster-001:pa2$ ./pa2 2 25:0:0 too_many
cs30xyz@pi-cluster-001:pa2$ ./pa2 a 10:00:00
cs30xyz@pi-cluster-001:pa2$ ./pa2 2 10:00:00
cs30xyz@pi-cluster-001:pa2$ ./pa2 62 10:00:00A
cs30xyz@pi-cluster-001:pa2$ ./pa2 -2 10:00:00A
cs30xyz@pi-cluster-001:pa2$ ./pa2 99999999999999999999999 10:00:00A
cs30xyz@pi-cluster-001:pa2$ ./pa2 2 13:00:00A
cs30xyz@pi-cluster-001:pa2$ ./pa2 2 10:60:00A
cs30xyz@pi-cluster-001:pa2$ ./pa2 2 10:00:60A
cs30xyz@pi-cluster-001:pa2$ ./pa2 2 10:00:00B

Example input that has normal output:
cs30xyz@pi-cluster-001:pa2$ ./pa2
cs30xyz@pi-cluster-001:pa2$ ./pa2 5
cs30xyz@pi-cluster-001:pa2$ ./pa2 5 10:00:00a

Detailed Overview

The function prototypes for the various C and Assembly functions are as follows.

C routines:
int main( int argc, char * argv[] );
unsigned long interpretTime( struct tInfo * tmPtr, const char * time );
void printClock( const unsigned char clock[] );
void tickClock( unsigned char clock[] );
int timeRightNow( struct timeval * tp, void * p );

Assembly routines:
void setClock( unsigned char clock[], const struct tInfo * tmPtr );
void convertTime( struct tInfo * ourTime, const struct tm * tmPtr );
unsigned char incrementClockValue( unsigned char BCDbits,
const unsigned int maxValue );
long isInRange( long num, long min, long max );
long isEven( long value );
void printChar( char c );
long myRemainder( long dividend, long divisor );

For the Milestone, you will need to complete:
setClock.s incrementClockValue.s interpretTime.c tickClock.c

Process Overview:
The following is an explanation of the main tasks of the assignment, and how the individual functions work
together to form. the whole program.

This program takes in 2 optional command line arguments to specify how the clock will be displayed and an
optional flag to display a help message.
$ ./pa2 [numTicks [startTime]] | [--help]

Back to Top
Explanation of Command Line Arguments:
● numTicks - [optional] the number of seconds to tick the clock.
● startTime - [optional] starting time of the clock entered as HH:MM:SS (A|a|P|p). *If specifying start
time, numTicks must also be specified as well. If startTime is not specified the start time will be the
current time.
● --help - [optional] the help flag for displaying usage message intentionally


Printing out the clock consists of the following steps:
1. Parse command line arguments in main(), where isInRange() and errno will help with error
checking.
a. If there are errors, print appropriate error messages and usage message to stderr, then return
EXIT_FAILURE.
b. If there are no errors, proceed to print the clock.
2. If user inputs a start time, use interpretTime() to parse the specified time information into a struct.
3. If user did not input a start time, use timeRightNow()to get the current system time and
convertTime() to populate our time struct with information from the system time struct.
4. After parsing the start time of the clock, use setClock()to set up the clock array to represent the
specified value.
5. In a loop print the clock using printClock() and tick the clock using tickClock()which uses
incrementClockValue() to add one second at a time to the clock.
6. After printing and ticking the clock (alternating) for user specified number of times or the default number
of times, and exit the program by returning EXIT_SUCCESS.

Back to Top
Milestone Functions to be Written

Listed below are the modules to be written for the milestone.

setClock.s
void setClock( unsigned char clock[], const struct tInfo * tmPtr );

This function will set the time in the clock array using the hours, minutes, and seconds in tmPtr. tmPtr is a
struct tInfo that has the following members: tm_sec, tm_min, tm_hour, am_pm. (You can check pa2.h
for the declaration). Use the offsets defined in pa2Globals.c to access these members.

You will need to set each digit in clock separately (make sure you understand BCD notation). This means for
each byte in the clock, you’ll need to set the tens digit of that time value in the upper nibble, and the ones
digit of that time value in the lower nibble. You will need to use bit operations to do this.

For example: If the time is 10:38:52 (HH:MM:SS) AM, the following bit patterns should be stored in clock.

clock[0] clock[1] clock[2] clock[3]
Decimal 1 0 3 8 5 2 65 ('A')
Binary 0001 0000 0011 1000 0101 0010 01000001

Hint: You will need to use multiple loads and stores to access members in tmPtr and modify clock. Allocate
space for local variables and parameters on the stack if you need to.

incrementClockValue.s
unsigned char incrementClockValue( unsigned char BCDbits,
const unsigned int maxValue );

This function will increment the 4 BCD bits (nibble) passed in as BCDbits. If the incremented value is larger
than the maxValue, return 0 to indicate that the next nibble should be incremented. Otherwise, return the
incremented value.

For example:
BCDbits maxValue return
7 9 8
5 5 0

Return Value: Return 0 if incremented BCDbits > maxValue. Otherwise, return incremented BCDbits.

interpretTime.c
unsigned long interpretTime( struct tInfo * tInfoPtr, const char * time );

This function will parse the time string and populate the tm_sec, tm_min, tm_hour and am_pm members of
the struct tInfo pointed to by tInfoPtr. If there are no errors in this process, you should return 0.

Back to Top
Otherwise, the appropriate error flags/bits should be set in the unsigned long bitmap to be returned (see
pa2.h for the error flags). You should not print any error messages in this function.

In order to parse the time string, you will need to:
● Copy the contents of time into a local char array (see man -s3 strncpy).
● Count the number of time separators (':') in the string. If the string contains the wrong number of
separators (see pa2.h), set the ERR_TIME_FORMAT bit in the error bitmap and return.
● Convert each unit of time (hours, minutes, seconds) to an integer value (you should be using
strtol()). From this point forward if we encounter any errors, do not return immediately, just set the
appropriate error flag and continue (bit operations are required for this).
○ Remember that strtol() will not necessarily function the way you expect it to if the string you
give is not null terminated (your endptr value will be different than the normal use case). A
useful function here could be strchr() (man -s3 strchr). Think about how you can use
this function to ensure each string you pass into strtol() is null terminated. There are other
ways to accomplish this as well (see the discussion slides for a more detailed description).
○ After each call to strtol() you will need to check errno and endptr, setting the appropriate
error bits if any errors occurred.
○ Note: If the hour value in the input string is 0, it should be interpreted as 12.
● If strtol() did not encounter any errors, you also need to ensure that each time unit is within the
appropriate range (use isInRange() with the constants defined in pa2.h). If a time unit is outside its
range, set the appropriate error flag.
● After parsing the hour, min and sec values, start parsing the am/pm char following the sec value.
○ If the character is any non numeric char other than a/A/p/P, interpret as ERR_TIME_FORMAT.
○ If there are no more characters after HH:MM:SS, interpret as ERR_TIME_FORMAT.
○ If the string has the format of HH:MM:SS(a|A|p|P) followed by other chars, such as
"12:15:10A3string" also interpret as ERR_TIME_FORMAT.

Examples of errors:

time flags set in the error bitmap
03:05:aA ERR_TIME_FORMAT
1z0:16y20 ERR_TIME_FORMAT
13:03:05p ERR_TIME_RANGE
12:03:05b ERR_TIME_FORMAT
12:03:05a9 ERR_TIME_FORMAT
12:03:05 ERR_TIME_FORMAT
1g2:03:05 ERR_TIME_NUM, ERR_TIME_FORMAT
12a:66:05 ERR_TIME_NUM, ERR_TIME_RANGE, ERR_TIME_FORMAT

Reasons for error:
● time did not contain the correct number of colon separators.
● Error parsing the hours, minutes, or seconds from a string to a long (remember to set errno to 0 right
before each call to strtol() so you can accurately identify when an error occurs).
● Hours, minutes, or seconds are outside their respective range.
● time did not have a valid am_pm char (a/A/p/P) immediately following a valid second value


Back to Top
Return Value: Return an unsigned long bitmap where each bit indicates whether or not that specific error
occurred, according to the error flags defined in pa2.h. If no errors occurred, this bitmap will
just be 0.

tickClock.c
void tickClock( unsigned char clock[] );

This function will increment the clock by one second using incrementClockValue(). You should start by
incrementing the ones position in seconds, then check if you need to increment the tens position in seconds,
continuing this all the way to the tens position in hours. Note that you may need to change the char of ‘A’ or ‘P’
to indicate AM or PM.

incrementClockValue() only takes in 4 bits (one nibble--which corresponds to one decimal digit of clock)
at a time. This means you will need to do some bit operations to extract the ones and tens place separately for
each unit of time (see constants defined in pa2.h). Make sure you update clock after each call to
incrementClockValue().

For example:

original clock updated clock
10:20:30A 10:20:31A
05:19:59P 05:20:00P
09:59:59A 10:00:00A
11:59:59P 12:00:00A


Post-Milestone Functions to be Written

Listed below are the modules to be written after the milestone functions are complete.

convertTime.s
void convertTime( struct tInfo * ourTime, const struct tm * tmPtr );

This function will use hours, minutes, and seconds in tmPtr to populate the tm_sec, tm_min, tm_hour and
am_pm members of the struct tInfo pointed to by ourTime. tmPtr is a pointer to a struct tm that has
the following members: tm_sec, tm_min, tm_hour (see man -s3 ctime for more information). Use the
offsets defined in pa2Globals.c to access these members. Note that struct tm uses 0-23 to store hours.
You will need to calculate tm_hour (range specified in pa2.h) and am_pm members of the struct tInfo
properly.

printClock.c
void printClock( const unsigned char clock[] );

This function displays the BCD clock based on the passed-in clock array. For each entry that represents a
number in the array (hours, minutes, seconds), the upper nibble (4 bits) represents the tens place, and the

Back to Top
lower nibble represents the ones place of that value. To display the BCD clock, represent each bit in these
nibbles by 'O' or '.' :
● If the current bit is set (1): output a capital 'O' to indicate a lit LED
● If the current bit is not set (0): output a dot '.' to indicate a unlit LED

Note that the character for a lit LED is a capital O (as in “Oh my goodness, what a cool clock”), and not a 0 (as
in “There is zero parking on campus”).

You will print out a border made up of AM/PM (indicated by the last entry in the array), as shown in the
example below (isEven() may be helpful here):

For example: BCD clock that displays time 08:56:37A with input clock = {0x08, 0x56, 0x37, 0x65}:
 

联系我们
  • QQ:99515681
  • 邮箱:99515681@qq.com
  • 工作时间:8:00-21:00
  • 微信:codinghelp
热点标签

联系我们 - QQ: 99515681 微信:codinghelp
程序辅导网!