COMP1521 24T2 F13A tutorial code

Here you'll find all the code I've written in the F13A tutorials, as well as some possibly useful information:

Week #10

hello_from_thread.c

// print "Hello from thread!", from another thread

#include <stdio.h>
#include <pthread.h>

int main(void) {
    
}

add_to_counter.c

#include <stdio.h>
#include <pthread.h>


int global_total = 0;

void *add_50000_to_counter(void *data) {
    for (int i = 0; i < 50000; i++) {
        // sleep for 1 nanosecond
        // nanosleep (&(struct timespec){.tv_nsec = 1}, NULL);

        // doesn't change anything, just encourages the scheduler to do its stuff
        sched_yield();

        global_total++;
    }

    return NULL;
}

int main(void) {
    pthread_t thread1;
    pthread_create(&thread1, NULL, add_50000_to_counter, NULL);

    pthread_t thread2;
    pthread_create(&thread2, NULL, add_50000_to_counter, NULL);

    pthread_join(thread1, NULL);
    pthread_join(thread2, NULL);

    printf("Final total: %d\n", global_total);
}

Week #9

print_diary.c

// Write a C program, print_diary.c, which prints the contents
// of the file $HOME/.diary to stdout

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


int main(void) {
    char *home = getenv("HOME");

    size_t buffer_len = strlen(home) + strlen("/.diary") + 1;
    char *buffer = malloc(buffer_len);
    // char buffer[buffer_len];

    snprintf(buffer, buffer_len, "%s/.diary", home);

    printf("buffer = \"%s\"\n", buffer);

    FILE *stream = fopen(buffer, "r");

    if (stream == NULL) {
        perror(buffer);
        return 1;
    }

    int byte;
    while ((byte = fgetc(stream)) != EOF) {
        putchar(byte);
    }

    fclose(stream);
    free(buffer);

    return 0;
}

Week #8

first_line.c

// Write a C program, first_line.c, which is given one command-line argument,
// the name of a file, and which prints the first line of that file to stdout.
// If given an incorrect number of arguments, or if there was an error opening
// the file, it should print a suitable error message.

#include <stdio.h>
#include <stdlib.h>

// $ ./first_line my_file
// argv[0] = "./first_line"
// argv[1] = "my_file"
// argc = 2

int main(int argc, char *argv[]) {
    if (argc != 2) {
        fprintf(stderr, "Usage: ./first_line <filename>\n");
        exit(1);
    }

    char *path = argv[1];

    FILE *stream = fopen(path, "r");

    if (stream == NULL) {
        perror(path);
        exit(1);
    }

    // to read: fgetc fread fgets fscanf

    int byte;

    while ((byte = fgetc(stream)) != EOF) {
        putchar(byte);
        if (byte == '\n') {
            break;
        }
    }

    fclose(stream);
}

Week #7

Here's the presentation

float_weird.c

#include <stdio.h>

int main(void) {
    float a = 0.1;
    float b = 0.2;
    float sum = a + b;

    printf("a = %.9g, b = %.9g and sum = %.9g\n", a, b, sum);
    printf("And sum == 0.3 is: %d\n", sum == 0.3);
}

get_bit_groups.c

#include <stdint.h>
#include <stdio.h>

typedef struct six_bit_groups {
    uint8_t middle_bits;
    uint8_t lower_bits;
} six_bit_groups_t;


/*
Example:

    01100010   10101101   11001100   10010011
                    ^^^   ^^^          ^^^^^^
                      middle            lower
                       = 46             = 19


       01100010101011011100110010010011
mask = 00000000000000000000000000111111 &
       --------------------------------
       00000000000000000000000000010011 &


value = 01100010101011011100110010010011
 mask = 00000000000001111110000000000000 &
        --------------------------------
        00000000000001011100000000000000

value = 01100010101011011100110010010011
                     0110001010101101110
 mask = 00000000000000000000000000111111 &

*/


six_bit_groups_t get_bit_groups(uint32_t value) {
    uint32_t mask = 0x3F;
    uint32_t mask_2 = 0b111111;
    uint32_t mask_3 = 63;

    six_bit_groups_t result;
    result.lower_bits = mask & value;
    // result.middle_bits = (value & (mask << 13)) >> 13;
    result.middle_bits = (value >> 13) & mask;

    // (a ^ b) ^ b = a
    // (a ^ b) = 0

    return result;
}

Week #5

reverse_bits.c

#include <assert.h>
#include <stdio.h>
#include <stdint.h>


// Reverse a 32 bit value
uint32_t reverse_bits(uint32_t value) {
    uint32_t result = 0;
    for (int i = 0; i < 32; i++) {
        // Check if the i'th bit in `value` is a 1?
        uint32_t mask = ((uint32_t) 1) << i;

        if ((mask & value) != 0) {
            //  ==> If it is... set the 'opposite' bit in result
            //      to a 1
            mask = ((uint32_t) 1) << (31 - i);
            result = result | mask;
        }

    }

    return result;
}

int main(void) {
    assert(reverse_bits(0xFFFFFFFF) == 0xFFFFFFFF);
    assert(reverse_bits(0x00000000) == 0x00000000);
    assert(reverse_bits(0x1) == 0x80000000);
    assert(reverse_bits(0x2) == 0x40000000);
    assert(reverse_bits(0x01234567) == 0xE6A2C480);
    printf("All tests passed!\n");
    return 0;
}

examples.txt

  uint16_t a = 0x5566, b = 0xAAAA, c = 0x0001;

   a) a | b  == 0xFFEE
   b) a & b  == 0x0022
   c) a ^ b  == 0xFFCC
   d) a & ~b
   e) c << 6
   f) a >> 4
   g) a & (b << 1)
   h) b | c
   i) a & ~c

Week #4

Here's the spreadsheet I used

topography.c

// A topographic map!
// This helpful tool will tell explorers how much they need to climb to
// reach various points of interest.
// Given an array of points, `my_points`, it can look up individual cells
// in the 2D map and print their height.

#include <stdio.h>

#define NUM_ROWS 5
#define NUM_COLS 5
#define N_POINTS 4

// 2D representation of a point, stored as a single struct
struct point2D {
    int row;
    int col;
} typedef point2D_t;

// 2D grid representing the height data for an area.
int topography_grid[NUM_ROWS][NUM_COLS] = {
    { 0, 1, 1, 2, 3 },
    { 1, 1, 2, 3, 4 },
    { 1, 2, 3, 5, 7 },
    { 3, 3, 4, 5, 6 },
    { 3, 4, 5, 6, 7 },
};

// Points of interest to print heights for, as a 1D array.
point2D_t my_points[N_POINTS] = {
    { 1, 2 },
    { 2, 3 },
    { 0, 0 },
    { 4, 4 },
};

int main(void) {
    for (int i = 0; i < N_POINTS; i++) {
        int row = my_points[i].row;
        int col = my_points[i].col;
        int height = topography_grid[row][col];

        printf("Height at %d,%d=%d\n", row, col, height);
    }

    return 0;
}

topography.s

# A topographic map!

# Constants
NUM_ROWS = 5
NUM_COLS = 5
N_POINTS = 4

SIZEOF_INT = 4
SIZEOF_POINT2D = 8
POINT2D_ROW_OFFSET = 0
POINT2D_COL_OFFSET = 4

	.data
# 2D grid representing the height data for an area.
topography_grid:
	.word	0, 1, 1, 2, 3
	.word	1, 1, 2, 3, 4
	.word	1, 2, 3, 5, 7
	.word	3, 3, 4, 5, 6
	.word	3, 4, 5, 6, 7

# Points of interest to print heights for, as a 1D array of point2D_t structs.
# Note the memory layout of this array: each element requires 8 bytes, not 4.
my_points:
	.word	1, 2
	.word	2, 3
	.word	0, 0
	.word	4, 4

height_str:
	.asciiz "Height at "


	.text
main:
	# Registers:
	#   - $t0: int i, the loop counter
	#   - $t1: row of the current point
	#   - $t2: col of the current point
	#   - $t3: height of the current point
	#   - $t4: temporary result for array indexing
	#   - $t5: temporary result for array indexing

					# Loop over all elements, and print their data
points_loop_init:			# for (int i = 0; i < N_POINTS; i++) {
	li	$t0, 0			# $t0 = 0

points_loop_cond:
	bge	$t0, N_POINTS, points_loop_end	# if (i >= N_POINTS)

	# We have i in $t0
	# We want row in $t1
	# We want col in $t2
	# We want height in $t3


	# int row = my_points[i].row;
	la	$t4, my_points			# my_points
	mul	$t5, SIZEOF_POINT2D, $t0	# i * SIZEOF_POINT2D
	add	$t4, $t4, $t5			# i * SIZEOF_POINT2D + my_points
	addi	$t4, $t4, POINT2D_ROW_OFFSET	# i * SIZEOF_POINT2D + my_points + POINT2D_ROW_OFFSET
	# then we do the load (lw)		#   = &my_points[i].row
	lw	$t1, ($t4)			# row = my_points[i].row

        # int col = my_points[i].col;
	la	$t4, my_points			# my_points
	mul	$t5, SIZEOF_POINT2D, $t0	# i * SIZEOF_POINT2D
	add	$t4, $t4, $t5			# i * SIZEOF_POINT2D + my_points
	addi	$t4, $t4, POINT2D_COL_OFFSET	# i * SIZEOF_POINT2D + my_points + POINT2D_COL_OFFSET
	# then we do the load (lw)		#   = &my_points[i].col
	lw	$t2, ($t4)			# col = my_points[i].col


        # int height = topography_grid[row][col];
	# &topography_grid[row][col] = &topography_grid + (row * NUM_COLS + col) * sizeof(element)
	mul	$t4, $t1, NUM_COLS
	add	$t4, $t4, $t2
	mul	$t4, $t4, SIZEOF_INT
	addi	$t4, $t4, topography_grid
	lw	$t3, ($t4)

					# printf("Height at %d,%d=%d\n", row, col, height);

	li	$v0, 4			# $v0 = 4 (print string)
	la	$a0, height_str		# load address of height_str into $a0
	syscall				# print height_str

	li	$v0, 1			# $v0 = 1 (print int)
	move	$a0, $t1		# $a0 = row
	syscall				# print row

	li	$v0, 11			# $v0 = 11 (print ASCII character)
	li	$a0, ','		# $a0 = ','
	syscall				# print ','

	li	$v0, 1			# $v0 = 1 (print int)
	move	$a0, $t2		# $a0 = col
	syscall				# print col

	li	$v0, 11			# $v0 = 11 (print ASCII character)
	li	$a0, '='		# $a0 = '='
	syscall				# print '='

	li	$v0, 1			# $v0 = 1 (print int)
	move	$a0, $t3		# $a0 = height
	syscall				# print height

	li	$v0, 11			# $v0 = 11 (print ASCII character)
	li	$a0, '\n'		# $a0 = '\n'
	syscall				# print '\n'

points_loop_iter:
	addi	$t0, $t0, 1		# i++
	b	points_loop_cond	# branch to points_loop_cond

points_loop_end:

	jr	$ra			# return 0;

rec_max.c

#include <stdio.h>

// C function to find the largest element in an array, recursively.
// Returns the value of the largest element in the array.
//
// array:  Array to search
// length: Number of elements in the array
int rec_max(int array[], int length) {
    int first_element = array[0];
    if (length == 1) {
        // Handle the base-case of the recursion, at the end of the array.
        return first_element;
    } else {
        // Recurse on the rest of the array.
        // Finds the largest element after first_element in the array.
        int max_so_far = rec_max(&array[1], length - 1);

        // Compare this element with the largest element after it in the array.
        if (first_element > max_so_far) {
            max_so_far = first_element;
        }
        return max_so_far;
    }
}

int main(void) {
    int data[10] = {2, -3, 5, 4, 42, 2, 8, 4, 1, 9};

    printf("%d\n", rec_max(data, 10));

    return 0;
}

rec_max.s

########################################################################
# COMP1521 24T2 -- ...
#
#
# !!! IMPORTANT !!!
# Before starting work on the assignment, make sure you set your tab-width to 8!
# It is also suggested to indent with tabs only.
# Instructions to configure your text editor can be found here:
#   https://cgi.cse.unsw.edu.au/~cs1521/23T2/resources/mips-editors.html
# !!! IMPORTANT !!!
#
#
# This program was written by YOUR-NAME-HERE (z5555555)
# on INSERT-DATE-HERE. INSERT-SIMPLE-PROGRAM-DESCRIPTION-HERE
#
# Version 1.0 (12-06-2023): Team COMP1521 <cs1521@cse.unsw.edu.au>
#
########################################################################

	.text
rec_max:
	# Args:
	#    - $a0: int array[]
	#    - $a1: int length
	#
	# Returns:
	#    - $v0: const char *
	#
	# Frame:    [$ra, $s0]
	# Uses:     [$s0, $t0, $t1, $t2, $v0, $a0, $a1]
	# Clobbers: [$t0, $t1, $t2, $v0, $a0, $a1]
	#
	# Locals:
	#   - int array: $t0
	#   - int blah: $t0
	#   - $t0: int array, int blah
	#   - $t0: int array
	#   - $t0: int blah
	#   - int length: $t1
	#   - int max_so_far: $t2
	#   - int first_element: $s0
	#   - array address calculations: $t3
	#
	# Structure:
	#   current_player_str
	#   -> [prologue]
	#       -> body
	#       -> length_ne_1
	#       -> ret_max_so_far
	#   -> [epilogue]

	# int rec_max(int array[], int length) {

rec_max__prologue:
	# TODO
	begin
	push	$ra
	push	$s0

rec_max__body:
	move	$t0, $a0
	move	$t1, $a1

	# int first_element = array[0];
	lw	$s0, ($t0)

	bne	$t1, 1, rec_max__length_ne_1				# if (length == 1) {

	# return first_element;
	move	$v0, $s0
	b	rec_max__epilogue

rec_max__length_ne_1:							# } else {

	# int max_so_far = rec_max(&array[1], length - 1);
	addi	$a0, $t0, 4
	sub	$a1, $t1, 1
	jal	rec_max
	move	$t2, $v0

	ble	$s0, $t2, rec_max__ret_max_so_far	#   if (first_element > max_so_far) {

	# max_so_far = first_element;
	move	$t2, $s0

rec_max__ret_max_so_far:						#   }
	# return max_so_far;
	move	$v0, $t2

rec_max__epilogue:							# }
	# TODO
	pop	$s0
	pop	$ra
	end

	jr	$ra



main:
main__prologue:
	push	$ra

main__body:
	la	$a0, test_data
	li	$a1, 10
	jal	rec_max				# result = rec_max(test_data, 10)

	move	$a0, $v0
	li	$v0, 1				# syscall 1: print_int
	syscall					# printf("%d", result);

	li	$v0, 11				# syscall 11: print_char
	li	$a0, '\n'
	syscall					# printf("%c", '\n');

	li	$v0, 0
main__epilogue:
	pop	$ra
	jr	$ra				# return 0;

	.data
test_data:
	.word 2, -3, 5, 4, 42, 2, 8, 4, 1, 9

Week #3

Here's the spreadsheet I used

print_array.c

// A simple program that will print 10 numbers from an array

#define N_SIZE 10

#include <stdio.h>

int numbers[N_SIZE] = { 3, 1, 4, 1, 5, 9, 2, 6, 5, 3 };

int main(void) {
    int i;

    i = 0;
    while (i < N_SIZE) {
        int num = numbers[i];
        printf("%d\n", num);
        i++;
    }
}

print_array.s

	N_SIZE = 10

	.text
main:
	# i: $t0
	# num: $t1
	# &numbers[i]: $t2

i_loop_init:
	li	$t0, 0				# i = 0;

i_loop_cond:
	bge	$t0, N_SIZE, i_loop_end		# while (i < N_SIZE)

i_loop_body:
	# int num = numbers[i]; // we want to load
	# numbers[i] = 7;       // we want to store

	# int num = numbers[i];

	# we have to figure out what &numbers[i]
	# &numbers[i] = &numbers + i * sizeof(int)
	la	$t2, numbers		# &numbers
	mul	$t3, $t0, 4		# i * sizeof(int)
	add	$t2, $t2, $t3		# &numbers + i * sizeof(int)
					#  = &numbers[i]

	# now we do a memory load!
	lw	$t1, ($t2)			#   num = numbers[i];

	li	$v0, 1
	move	$a0, $t1
	syscall					#   printf("%d", num);

	li	$v0, 11
	li	$a0, '\n'
	syscall					#   putchar('\n');

i_loop_step:
	addi	$t0, $t0, 1			#   i++;
	b	i_loop_cond			# }

i_loop_end:

	li	$v0, 0
	jr	$ra				# return 0;



	.data
numbers:	# int numbers[N_SIZE] = { 3, 1, 4, 1, 5, 9, 2, 6, 5, 3 };
	.word	3, 1, 4, 1, 5, 9, 2, 6, 5, 3

my_string:
	.asciiz	"aiowjdoiawjd"

Week #2

hello.s

# Write a MIPS assembly program that prints out "Hello, world!"
.text

main:
	li	$v0, 4			# $v0 = 4
	la	$a0, hello_world_str	# $a0 = "Hello, world!"
	syscall

	li	$v0, 11
	li	$a0, '\n'
	syscall

	li	$v0, 0
	jr	$ra			# return 0;

.data
hello_world_str:
	.asciiz	"Hello, world!"

square.c

// Prints the square of a number

#include <stdio.h>

int main(void) {
    int x; // $t0

    printf("Enter a number: ");
    scanf("%d", &x);

    int y = x * x; // $t2
    printf("%d", y);
    putchar('\n');

    return 0;
}

square.s

main:
	li	$v0, 4
	la	$a0, enter_a_number_str
	syscall					# printf("Enter a number: ");

	li	$v0, 5
	syscall
	move	$t0, $v0			# scanf("%d", &x);

	mul	$t2, $t0, $t0			# y = x * x;

	li	$v0, 1
	move	$a0, $t2
	syscall

	li	$v0, 11
	li	$a0, '\n'
	syscall

	li	$v0, 0
	jr	$ra


.data
enter_a_number_str:
	.asciiz	"Enter a number: "

bounded_square.c

// Squares a number, unless its square is too big for a 32-bit integer.
// If it is too big, prints an error message instead.

#include <stdio.h>

#define SQUARE_MAX 46340

int main(void) {
    int x, y;

    printf("Enter a number: ");
    scanf("%d", &x);

    if (x > SQUARE_MAX) {
        printf("square too big for 32 bits\n");
    } else {
        y = x * x;
        printf("%d\n", y);
    }

    return 0;
}

bounded_square.s

	SQUARE_MAX = 46340

main:
	li	$v0, 4
	la	$a0, enter_a_number_str
	syscall					# printf("Enter a number: ");

	li	$v0, 5
	syscall
	move	$t0, $v0			# scanf("%d", &x);

	ble	$t0, SQUARE_MAX, square_small_enough

	li	$v0, 4
	la	$a0, square_too_big
	syscall					# printf("Enter a number: ");

	b	epilogue

square_small_enough:
	mul	$t2, $t0, $t0			# y = x * x;

	li	$v0, 1
	move	$a0, $t2
	syscall

	li	$v0, 11
	li	$a0, '\n'
	syscall

epilogue:
	li	$v0, 0
	jr	$ra


.data
enter_a_number_str:
	.asciiz	"Enter a number: "
square_too_big:
	.asciiz	"square too big for 32 bits\n"

Week #1

factorial.c

// Write a program which calculates n!, where
//     n! = n * (n - 1) * (n - 2) * ... * 3 * 2 * 1
// e.g.
//     1! = 1 = 1
//     2! = 2 * 1 = 2
//     3! = 3 * 2 * 1 = 6
//     4! = 4 * 3 * 2 * 1 = 24
//     5! = 5 * 4 * 3 * 2 * 1 = 120

//     5! = 5 * (4 * 3 * 2 * 1) = 5 * 4!
//     n! = n * (n - 1)!

#include <stdio.h>
#include <stdlib.h>

int factorial(int n) {
    // n! = n * (n - 1)!
    //
    if (n != 0) {
        return n * factorial(n - 1);
    } else {
        return 1;
    }
}

int main(int argc, char *argv[]) {
    int n = atoi(argv[1]);
    // if (scanf("%d", &n) != 1) {
    //     printf("only number are accepted!\n");
    //     return 1;
    // }

    int total = factorial(n);

    // for (/* initialiser */ int i = n; /* condition */ i > 0; /* step */ i--) {
    //     total = total * i; // total *= i;
    // }

    printf("%d! = %d\n", n, total);
}