diff --git a/.gitignore b/.gitignore
index cda2256..afcc3bf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -32,6 +32,7 @@ manual/*.toc
*.crf
*.d
*.plg
+*.xml
# *.sct
*.tra
*.lnp
diff --git a/README.md b/README.md
index d1c4a02..6e8965a 100644
--- a/README.md
+++ b/README.md
@@ -17,3 +17,12 @@ This directory contains starter code of each lab.
### `submission`
This directory contains template files for project submissions.
+
+Within manual_code:
+
+#### `template`
+This directory contains the code the group edited for this project.
+
+The directory kernel contains the code used for memory management.
+
+The directory app contains the file ae_mem.c which contains our testing code.
diff --git a/manual_code/lab1/template/.cproject b/manual_code/lab1/template/.cproject
new file mode 100644
index 0000000..fac20cf
--- /dev/null
+++ b/manual_code/lab1/template/.cproject
@@ -0,0 +1,268 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/manual_code/lab1/template/.project b/manual_code/lab1/template/.project
new file mode 100644
index 0000000..86da93a
--- /dev/null
+++ b/manual_code/lab1/template/.project
@@ -0,0 +1,27 @@
+
+
+ SVC
+
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.genmakebuilder
+ clean,full,incremental,
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder
+ full,incremental,
+
+
+
+
+
+ com.arm.debug.ds.nature
+ org.eclipse.cdt.core.cnature
+ org.eclipse.cdt.managedbuilder.core.managedBuildNature
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
+
+
diff --git a/manual_code/lab1/template/SVC.launch b/manual_code/lab1/template/SVC.launch
new file mode 100644
index 0000000..c7417f7
--- /dev/null
+++ b/manual_code/lab1/template/SVC.launch
@@ -0,0 +1,204 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/manual_code/lab1/template/src/.project b/manual_code/lab1/template/src/.project
new file mode 100644
index 0000000..f7d6de6
--- /dev/null
+++ b/manual_code/lab1/template/src/.project
@@ -0,0 +1,11 @@
+
+
+ src
+
+
+
+
+
+
+
+
diff --git a/manual_code/lab1/template/src/app/ae_mem.c b/manual_code/lab1/template/src/app/ae_mem.c
index 0db6243..6447fcd 100644
--- a/manual_code/lab1/template/src/app/ae_mem.c
+++ b/manual_code/lab1/template/src/app/ae_mem.c
@@ -24,37 +24,348 @@
#include "Serial.h"
#include "printf.h"
-int test_mem(void) {
- void *p[4];
- int n;
+int test_coales(void) {
+ U32 result = 0;
+ if (countNodes()==1){
+ result |= BIT(0);
+ }
- U32 result = 0;
+ void *p[4];
- p[0] = mem_alloc(8);
+ p[0] = mem_alloc(12);
+ p[1] = mem_alloc(24);
+ p[2] = mem_alloc(48);
- if (p[0] != NULL) {
- result |= BIT(0);
+ if (countNodes()==4){
+ result |= BIT(1);
}
- p[1] = mem_alloc(8);
+ mem_dealloc(p[1]);
+ if (countNodes()==4){
+ result |= BIT(2);
+ }
+
+ mem_dealloc(p[0]);
+ if (countNodes()==3){
+ result |= BIT(3);
+ }
+
+ mem_dealloc(p[2]);
+ if (countNodes()==1){
+ result |= BIT(4);
+ }
- if (p[1] != NULL && p[1] != p[0]) {
- result |= BIT(1);
+ return result == 31;
+}
+
+int test_reuse_freed(void) {
+ void *p[4];
+ U32 result = 0;
+ if (countNodes()==1){
+ result |= BIT(0);
+ }
+
+ p[0] = mem_alloc(12);
+ p[1] = mem_alloc(24);
+ p[2] = mem_alloc(48);
+
+ if (countNodes()==4){
+ result |= BIT(1);
}
mem_dealloc(p[0]);
- n = mem_count_extfrag(128);
- if (n == 1) {
- result |= BIT(2);
+ if (countNodes()==4){
+ result |= BIT(2);
+ }
+
+ p[3] = mem_alloc(12);
+ if (countNodes()==4){
+ result |= BIT(3);
+ }
+
+ mem_dealloc(p[1]);
+ mem_dealloc(p[2]);
+ mem_dealloc(p[3]);
+ if (countNodes()==1){
+ result |= BIT(4);
+ }
+
+ if(memLeakCheck()==1){
+ result |= BIT(5);
+ }
+
+ return result == 63;
+}
+
+int test_reuse_freed_2(void) {
+ void *p[4];
+ U32 result = 0;
+ if (countNodes()==1){
+ result |= BIT(0);
+ }
+
+ p[0] = mem_alloc(12);
+ p[1] = mem_alloc(24);
+ p[2] = mem_alloc(48);
+
+ if (countNodes()==4){
+ result |= BIT(1);
}
mem_dealloc(p[1]);
- n = mem_count_extfrag(128);
- if (n == 0) {
- result |= BIT(3);
+ if (countNodes()==4){
+ result |= BIT(2);
+ }
+
+ p[3] = mem_alloc(20);
+ if (countNodes()==4){
+ result |= BIT(3);
+ }
+
+ mem_dealloc(p[0]);
+ mem_dealloc(p[2]);
+ mem_dealloc(p[3]);
+ if (countNodes()==1){
+ result |= BIT(4);
+ }
+
+ if(memLeakCheck()==1){
+ result |= BIT(5);
+ }
+
+ return result == 63;
+}
+
+int test_malloc_new_node(void) {
+ void *p[4];
+ U32 result = 0;
+ if (countNodes()==1){
+ result |= BIT(0);
+ }
+
+ p[0] = mem_alloc(12);
+ p[1] = mem_alloc(60);
+ p[2] = mem_alloc(48);
+
+ if (countNodes()==4){
+ result |= BIT(1);
}
- return result;
+
+ mem_dealloc(p[1]);
+ if (countNodes()==4){
+ result |= BIT(2);
+ }
+
+ p[3] = mem_alloc(12);
+ if (countNodes()==5){
+ result |= BIT(3);
+ }
+
+ mem_dealloc(p[3]);
+ if (countNodes()==4){
+ result |= BIT(4);
+ }
+
+ mem_dealloc(p[0]);
+ mem_dealloc(p[2]);
+ if (countNodes()==1){
+ result |= BIT(5);
+ }
+
+ if(memLeakCheck()==1){
+ result |= BIT(6);
+ }
+
+ return result == 127;
}
+
+int test_mem_leak(){
+ void *p[4];
+ U32 result = 0;
+ if(memLeakCheck()==1){
+ result |= BIT(0);
+ }
+
+ p[0] = mem_alloc(12);
+
+ if(memLeakCheck()==1){
+ result |= BIT(1);
+ }
+
+ mem_dealloc(p[0]);
+
+ if(memLeakCheck()==1){
+ result |= BIT(2);
+ }
+
+ return result == 7;
+}
+
+int test_extfrag(void){
+ U32 result = 0;
+ if (countNodes() == 1){
+ result |= BIT(0);
+ }
+
+ void *p[10];
+
+ p[0] = mem_alloc(12);
+ p[1] = mem_alloc(12);
+ p[2] = mem_alloc(12);
+ p[3] = mem_alloc(12);
+ p[4] = mem_alloc(16);
+ p[5] = mem_alloc(12);
+ p[6] = mem_alloc(18);
+
+ if (countNodes() == 8){
+ result |= BIT(1);
+ }
+
+ mem_dealloc(p[2]);
+ p[7] = mem_alloc(15);
+
+ if (countNodes() == 9){
+ result |= BIT(2);
+ }
+
+ mem_dealloc(p[4]);
+ p[8] = mem_alloc(18);
+
+ if (countNodes() == 10){
+ result |= BIT(3);
+ }
+
+ if (mem_count_extfrag(12+12) == 0){
+ result |= BIT(4);
+ }
+
+ if (mem_count_extfrag(13+12) == 1){
+ result |= BIT(5);
+ }
+
+ if (mem_count_extfrag(17+12) == 2){
+ result |= BIT(6);
+ }
+
+ mem_dealloc(p[0]);
+ mem_dealloc(p[1]);
+
+ mem_dealloc(p[3]);
+
+ mem_dealloc(p[5]);
+ mem_dealloc(p[6]);
+ mem_dealloc(p[7]);
+ mem_dealloc(p[8]);
+
+ return result == 127;
+}
+
+int test_utilization(void) {
+ unsigned int totalUsed = 0;
+ unsigned int counter = 0;
+ unsigned int regionSize = 1048576;
+ unsigned int magicSize = 1070585247;
+
+ while(1){
+ if (mem_alloc(regionSize) == NULL) {
+ break;
+ }
+ totalUsed += regionSize;
+ counter++;
+ if(totalUsed > magicSize){
+ return -1;
+ }
+ }
+
+ unsigned int numAllocs = counter;
+ return 0;
+}
+
+int test_throughput(void){
+ for(int i = 0; i < 200; i++){
+ test_reuse_freed_2();
+ }
+ return 1;
+}
+
+int test4mock(){
+ void *p[15];
+ p[0] = mem_alloc(8);
+ p[1] = mem_alloc(8);
+ p[2] = mem_alloc(8);
+ p[3] = mem_alloc(8);
+ p[4] = mem_alloc(8);
+ p[5] = mem_alloc(8);
+ p[6] = mem_alloc(8);
+ p[7] = mem_alloc(8);
+ p[8] = mem_alloc(8);
+ p[9] = mem_alloc(8);
+
+ mem_dealloc(p[0]);
+ mem_dealloc(p[2]);
+ mem_dealloc(p[4]);
+ mem_dealloc(p[6]);
+ mem_dealloc(p[8]);
+
+ printf("Extfrag Regions: %d\r\n", mem_count_extfrag(8+12+1));
+ printf("Extfrag Regions: %d\r\n", mem_count_extfrag(8+12));
+
+ p[10] = mem_alloc(8);
+ p[11] = mem_alloc(8);
+ p[12] = mem_alloc(8);
+ p[13] = mem_alloc(8);
+ p[14] = mem_alloc(8);
+
+ printf("Extfrag Regions: %d\r\n", mem_count_extfrag(8+12+1));
+ printf("Extfrag Regions: %d\r\n", mem_count_extfrag(8+12));
+
+ return 1;
+}
+
+int test_mem(void) {
+// Function Tests:
+// U32 result = 0;
+//
+// if(test_mem_leak()){
+// result |= BIT(0);
+// }
+// if(test_coales()){
+// result |= BIT(1);
+// }
+// if(test_reuse_freed()){
+// result |= BIT(2);
+// }
+// if(test_reuse_freed_2()){
+// result |= BIT(3);
+// }
+// if(test_malloc_new_node()){
+// result |= BIT(4);
+// }
+// if(test_extfrag()){
+// result |= BIT(5);
+// }
+//
+// return result == 63;
+
+// Failing Testcase:
+ U32 result = 0;
+ if(test4Mock()){
+ result |= BIT(0);
+ }
+ return 1;
+
+// Throughput Test: (function needs to be updated
+// test_throughput();
+// return 1;
+
+// Utilization Test: Maxes out memory
+ int utilResult = test_utilization();
+ return 1;
+
+
+}
+
+
/*
*===========================================================================
* END OF FILE
diff --git a/manual_code/lab1/template/src/kernel/k_mem.c b/manual_code/lab1/template/src/kernel/k_mem.c
index 1357dc7..23e96f8 100644
--- a/manual_code/lab1/template/src/kernel/k_mem.c
+++ b/manual_code/lab1/template/src/kernel/k_mem.c
@@ -33,6 +33,19 @@
#include "printf.h"
#endif /* DEBUG_0 */
+
+/*
+ *==========================================================================
+ * STRUCTS
+ *==========================================================================
+ */
+
+typedef struct Node {
+ unsigned int size;
+ int isFree;
+ struct Node *next;
+} Node;
+
/*
*==========================================================================
* GLOBAL VARIABLES
@@ -43,6 +56,7 @@ const U32 g_k_stack_size = KERN_STACK_SIZE;
// task kernel stacks
U32 g_k_stacks[MAX_TASKS][KERN_STACK_SIZE >> 2] __attribute__((aligned(8)));
+Node* HEAD = NULL;
/*
*===========================================================================
@@ -50,34 +64,191 @@ U32 g_k_stacks[MAX_TASKS][KERN_STACK_SIZE >> 2] __attribute__((aligned(8)));
*===========================================================================
*/
+void print_list() {
+ Node* curr = HEAD;
+ while (curr) {
+ printf("location: 0x%x, size: %x, free: %x\r\n", (U32)curr, (U32)curr->size, curr->isFree);
+ curr = curr->next;
+ }
+}
+
int k_mem_init(void) {
unsigned int end_addr = (unsigned int) &Image$$ZI_DATA$$ZI$$Limit;
-#ifdef DEBUG_0
- printf("k_mem_init: image ends at 0x%x\r\n", end_addr);
- printf("k_mem_init: RAM ends at 0x%x\r\n", RAM_END);
-#endif /* DEBUG_0 */
+//#ifdef DEBUG_0
+// printf("k_mem_init: image ends at 0x%x\r\n", end_addr);
+// printf("k_mem_init: RAM ends at 0x%x\r\n", RAM_END);
+//#endif /* DEBUG_0 */
+
+ //check if end addr is valid
+ unsigned int totalSize = 0xBFFFFFFF - end_addr;
+ if(totalSize <= 0) {
+ return RTX_ERR;
+ }
+
+ // round end_addr to nearest 4
+ if (end_addr % 4 != 0) {
+ end_addr = ((unsigned int)(end_addr / 4)) * 4 + 4;
+ }
+
+ // cast end_addr to pointer given in end_addr
+ HEAD = (Node*) end_addr;
+
+ // setup head
+ HEAD->size = totalSize - sizeof(Node);
+ HEAD->isFree = 1;
+ HEAD->next = NULL;
+
return RTX_OK;
}
void* k_mem_alloc(size_t size) {
-#ifdef DEBUG_0
- printf("k_mem_alloc: requested memory size = %d\r\n", size);
-#endif /* DEBUG_0 */
- return NULL;
+//#ifdef DEBUG_0
+// printf("k_mem_alloc: requested memory size = %d\r\n", size);
+//#endif /* DEBUG_0 */
+
+ if (size == 0) {
+ return NULL;
+ }
+
+ // 4 byte align
+ if (size % 4 != 0) {
+ size = ((unsigned int)(size / 4)) * 4 + 4;
+ }
+
+ Node* curr = HEAD;
+
+ while(curr != NULL) {
+ if (size <= curr->size && curr->isFree) {
+ break;
+ }
+ curr = curr->next;
+ }
+
+ // couldn't allocate since no free space
+ if (curr == NULL) {
+ return NULL;
+ }
+
+ if (size == curr->size){
+ curr->isFree=0;
+ return (void*)((U32)curr + sizeof(Node));
+ } else if (size < curr->size && (curr->size < (size + sizeof(Node)))) {
+ curr->isFree=0;
+ return (void*)((U32)curr + sizeof(Node));
+ } else {
+ //make a new node
+ // might need to use an unsigned depending on how types work
+ Node* newNode = (Node*)((unsigned int)curr + sizeof(Node) + size);
+ newNode->isFree = 1;
+ newNode->size = curr->size - size - sizeof(Node);
+ newNode->next = curr->next;
+
+ curr->isFree=0;
+ curr->size = size;
+ curr->next = newNode;
+ // Cast curr to U32 to ensure pointer arithmetic works
+ // Pointer addition works by adding by increment of sizeof the pointer
+ // argument. If curr is of type Node* and we add sizeof(Node), we add
+ // sizeof(Node)^2 amount of bytes.
+ return (void*)((U32)curr + sizeof(Node));
+ }
+}
+
+Node* mergeNode(Node* first, Node* second) {
+ if (first > second) {
+ return NULL;
+ }
+
+ Node* result = first;
+ result->size = first->size + second->size + sizeof(Node);
+ result->next = second->next;
+
+ return result;
}
int k_mem_dealloc(void *ptr) {
-#ifdef DEBUG_0
- printf("k_mem_dealloc: freeing 0x%x\r\n", (U32) ptr);
-#endif /* DEBUG_0 */
+//#ifdef DEBUG_0
+// printf("k_mem_dealloc: freeing 0x%x\r\n", (U32) ptr);
+//#endif /* DEBUG_0 */
+
+ Node* curr = HEAD;
+ Node* prev = NULL;
+
+ while (ptr != (char*)curr + sizeof(Node)) {
+ if (curr->next == NULL) {
+ return RTX_ERR;
+ }
+
+ prev = curr;
+ curr = curr->next;
+// printf("0x%x\n", (U32)((char*)curr + sizeof(Node) + curr->size));
+ }
+
+ // Double free
+ if (curr->isFree > 0) {
+ return RTX_ERR;
+ }
+
+ curr->isFree = 1;
+
+ // Merge neighboring nodes
+ if (prev && prev->isFree > 0) {
+ curr = mergeNode(prev, curr);
+ }
+
+ if (curr->next && curr->next->isFree > 0) {
+ curr = mergeNode(curr, curr->next);
+ }
+
+// print_list();
+
return RTX_OK;
}
int k_mem_count_extfrag(size_t size) {
-#ifdef DEBUG_0
- printf("k_mem_extfrag: size = %d\r\n", size);
-#endif /* DEBUG_0 */
- return RTX_OK;
+//#ifdef DEBUG_0
+// printf("k_mem_extfrag: size = %d\r\n", size);
+//#endif /* DEBUG_0 */
+ // return RTX_OK;
+
+ unsigned int memRegionSize;
+ int regionCount = 0;
+
+ Node* curNode = HEAD; // HEAD is global var
+
+ while(curNode != NULL){
+ memRegionSize = curNode->size + sizeof(Node);
+ if(curNode->isFree){
+ if(memRegionSize < size){
+ regionCount++;
+ }
+ }
+ curNode = curNode->next; // idk if this is the right way to goto next node
+ }
+
+ return regionCount;
+}
+
+int countNodes(){
+ Node* n = HEAD;
+ int ret = 0;
+ while(n != NULL) {
+ ret += 1;
+ n = n->next;
+ }
+ return ret;
+}
+
+int memLeakCheck(){
+ unsigned int howMuchMem = 0;
+ Node* curNode = HEAD;
+ while(curNode != NULL){
+ howMuchMem += curNode->size + sizeof(Node);
+ curNode = curNode->next;
+ }
+ unsigned int end_addr = (unsigned int) &Image$$ZI_DATA$$ZI$$Limit;
+ unsigned int totalSize = 0xBFFFFFFF - end_addr;
+ return howMuchMem == totalSize;
}
/*
diff --git a/manual_code/lab1/template/src/kernel/k_mem.h b/manual_code/lab1/template/src/kernel/k_mem.h
index ff3c3ce..fc6f02a 100644
--- a/manual_code/lab1/template/src/kernel/k_mem.h
+++ b/manual_code/lab1/template/src/kernel/k_mem.h
@@ -36,6 +36,8 @@ int k_mem_init (void);
void *k_mem_alloc (size_t size);
int k_mem_dealloc (void *ptr);
int k_mem_count_extfrag (size_t size);
+int countNodes (void);
+int memLeakCheck (void);
#endif // ! K_MEM_H_
/*
diff --git a/manual_code/lab2/TM/.cproject b/manual_code/lab2/TM/.cproject
index d13abe4..43168ad 100644
--- a/manual_code/lab2/TM/.cproject
+++ b/manual_code/lab2/TM/.cproject
@@ -105,7 +105,7 @@
-
+
@@ -114,6 +114,12 @@
+
+
+
+
+
+
diff --git a/manual_code/lab2/TM/.settings/language.settings.xml b/manual_code/lab2/TM/.settings/language.settings.xml
deleted file mode 100644
index 7cb60c0..0000000
--- a/manual_code/lab2/TM/.settings/language.settings.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/manual_code/lab2/TM/TM1.launch b/manual_code/lab2/TM/TM1.launch
index 691e2b3..785ccea 100644
--- a/manual_code/lab2/TM/TM1.launch
+++ b/manual_code/lab2/TM/TM1.launch
@@ -1,26 +1,36 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -30,9 +40,9 @@
-
+
-
+
@@ -40,9 +50,11 @@
-
+
+
+
-
+
@@ -50,9 +62,11 @@
-
+
+
+
-
+
@@ -95,7 +109,13 @@
-
+
+
+
+
+
+
+
@@ -105,6 +125,10 @@
+
+
+
+
diff --git a/manual_code/lab2/TM/TMHardware.launch b/manual_code/lab2/TM/TMHardware.launch
new file mode 100644
index 0000000..90afd6c
--- /dev/null
+++ b/manual_code/lab2/TM/TMHardware.launch
@@ -0,0 +1,200 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/manual_code/lab2/TM/src/app/ae.c b/manual_code/lab2/TM/src/app/ae.c
index 5286b3b..2b2f6dc 100644
--- a/manual_code/lab2/TM/src/app/ae.c
+++ b/manual_code/lab2/TM/src/app/ae.c
@@ -110,8 +110,11 @@ void ae_set_task_info(RTX_TASK_INFO *tasks, int num_tasks) {
tasks[i].prio = HIGH;
tasks[i].priv = 1;
}
- tasks[0].ptask = &priv_task1;
- tasks[1].ptask = &priv_task2;
+
+// tasks[0].ptask = &priv_tasks_scheduling;
+// tasks[0].ptask = &priv_task_check_sp;
+// tasks[0].ptask = &priv_check_usp;
+ tasks[0].ptask = &priv_task_entry;
return;
}
diff --git a/manual_code/lab2/TM/src/app/ae_mem.c b/manual_code/lab2/TM/src/app/ae_mem.c
index 24b90c6..d4a927b 100644
--- a/manual_code/lab2/TM/src/app/ae_mem.c
+++ b/manual_code/lab2/TM/src/app/ae_mem.c
@@ -40,7 +40,269 @@
#include "Serial.h"
#include "printf.h"
-int test_mem(void) {
+//TODO test out allocating and de-allocating the same task or a diff task
+
+// test 1
+// create tcb
+// malloc
+//dealloc
+// assert pass
+
+// test 2
+// create tcb 1
+// create tcb 2
+// malloc as tcb 1
+// switch to tcb 2
+// dealloc as tcb 2
+// assert rtx error
+
+// test 2
+// create tcb 1
+// create tcb 2 with privilidge
+// malloc as tcb 1
+// switch to tcb 2
+// dealloc as tcb 2
+// assert pass
+
+
+int test_coales(void) {
+ U32 result = 0;
+ if (countNodes()==1){
+ result |= BIT(0);
+ }
+
+ void *p[4];
+
+ p[0] = mem_alloc(12);
+ p[1] = mem_alloc(24);
+ p[2] = mem_alloc(48);
+
+ if (countNodes()==4){
+ result |= BIT(1);
+ }
+
+ mem_dealloc(p[1]);
+ if (countNodes()==4){
+ result |= BIT(2);
+ }
+
+ mem_dealloc(p[0]);
+ if (countNodes()==3){
+ result |= BIT(3);
+ }
+
+ mem_dealloc(p[2]);
+ if (countNodes()==1){
+ result |= BIT(4);
+ }
+
+ return result == 31;
+}
+
+int test_reuse_freed(void) {
+ void *p[4];
+ U32 result = 0;
+ if (countNodes()==1){
+ result |= BIT(0);
+ }
+
+ p[0] = mem_alloc(12);
+ p[1] = mem_alloc(24);
+ p[2] = mem_alloc(48);
+
+ if (countNodes()==4){
+ result |= BIT(1);
+ }
+
+ mem_dealloc(p[0]);
+ if (countNodes()==4){
+ result |= BIT(2);
+ }
+
+ p[3] = mem_alloc(12);
+ if (countNodes()==4){
+ result |= BIT(3);
+ }
+
+ mem_dealloc(p[1]);
+ mem_dealloc(p[2]);
+ mem_dealloc(p[3]);
+ if (countNodes()==1){
+ result |= BIT(4);
+ }
+
+ if(memLeakCheck()==1){
+ result |= BIT(5);
+ }
+
+ return result == 63;
+}
+
+int test_reuse_freed_2(void) {
+ void *p[4];
+ U32 result = 0;
+ if (countNodes()==1){
+ result |= BIT(0);
+ }
+
+ p[0] = mem_alloc(12);
+ p[1] = mem_alloc(24);
+ p[2] = mem_alloc(48);
+
+ if (countNodes()==4){
+ result |= BIT(1);
+ }
+
+ mem_dealloc(p[1]);
+ if (countNodes()==4){
+ result |= BIT(2);
+ }
+
+ p[3] = mem_alloc(20);
+ if (countNodes()==4){
+ result |= BIT(3);
+ }
+
+ mem_dealloc(p[0]);
+ mem_dealloc(p[2]);
+ mem_dealloc(p[3]);
+ if (countNodes()==1){
+ result |= BIT(4);
+ }
+
+ if(memLeakCheck()==1){
+ result |= BIT(5);
+ }
+
+ return result == 63;
+}
+
+int test_malloc_new_node(void) {
+ void *p[4];
+ U32 result = 0;
+ if (countNodes()==1){
+ result |= BIT(0);
+ }
+
+ p[0] = mem_alloc(12);
+ p[1] = mem_alloc(60);
+ p[2] = mem_alloc(48);
+
+ if (countNodes()==4){
+ result |= BIT(1);
+ }
+
+ mem_dealloc(p[1]);
+ if (countNodes()==4){
+ result |= BIT(2);
+ }
+
+ p[3] = mem_alloc(12);
+ if (countNodes()==5){
+ result |= BIT(3);
+ }
+
+ mem_dealloc(p[3]);
+ if (countNodes()==4){
+ result |= BIT(4);
+ }
+
+ mem_dealloc(p[0]);
+ mem_dealloc(p[2]);
+ if (countNodes()==1){
+ result |= BIT(5);
+ }
+
+ if(memLeakCheck()==1){
+ result |= BIT(6);
+ }
+
+ return result == 127;
+}
+
+int test_mem_leak(){
+ void *p[4];
+ U32 result = 0;
+ if(memLeakCheck()==1){
+ result |= BIT(0);
+ }
+
+ p[0] = mem_alloc(12);
+
+ if(memLeakCheck()==1){
+ result |= BIT(1);
+ }
+
+ mem_dealloc(p[0]);
+
+ if(memLeakCheck()==1){
+ result |= BIT(2);
+ }
+
+ return result == 7;
+}
+
+int test_extfrag(void){
+ U32 result = 0;
+ if (countNodes() == 1){
+ result |= BIT(0);
+ }
+
+ void *p[10];
+
+ p[0] = mem_alloc(12);
+ p[1] = mem_alloc(12);
+ p[2] = mem_alloc(12);
+ p[3] = mem_alloc(12);
+ p[4] = mem_alloc(16);
+ p[5] = mem_alloc(12);
+ p[6] = mem_alloc(18);
+
+ if (countNodes() == 8){
+ result |= BIT(1);
+ }
+
+ mem_dealloc(p[2]);
+ p[7] = mem_alloc(15);
+
+ if (countNodes() == 9){
+ result |= BIT(2);
+ }
+
+ mem_dealloc(p[4]);
+ p[8] = mem_alloc(18);
+
+ if (countNodes() == 10){
+ result |= BIT(3);
+ }
+
+ if (mem_count_extfrag(12+12) == 0){
+ result |= BIT(4);
+ }
+
+ if (mem_count_extfrag(13+12) == 1){
+ result |= BIT(5);
+ }
+
+ if (mem_count_extfrag(17+12) == 2){
+ result |= BIT(6);
+ }
+
+ mem_dealloc(p[0]);
+ mem_dealloc(p[1]);
+
+ mem_dealloc(p[3]);
+
+ mem_dealloc(p[5]);
+ mem_dealloc(p[6]);
+ mem_dealloc(p[7]);
+ mem_dealloc(p[8]);
+
+ return result == 127;
+}
+
+//Default test mem
+int test_mem_default(void){
void *p[4];
int n;
@@ -71,6 +333,38 @@ int test_mem(void) {
}
return result;
}
+
+int test_utilization(void) {
+ unsigned int totalUsed = 0;
+ unsigned int counter = 0;
+ unsigned int regionSize = 1048576;
+ unsigned int magicSize = 1070585247;
+
+ while(1){
+ if (mem_alloc(regionSize) == NULL) {
+ break;
+ }
+ totalUsed += regionSize;
+ counter++;
+ if(totalUsed > magicSize){
+ return -1;
+ }
+ }
+
+ unsigned int numAllocs = counter;
+ return 0;
+}
+
+int test_throughput(void){
+ for(int i = 0; i < 200; i++){
+ test_reuse_freed_2();
+ }
+ return 1;
+}
+
+int test_mem(void) {
+ test_mem_default();
+}
/*
*===========================================================================
* END OF FILE
diff --git a/manual_code/lab2/TM/src/app/ae_priv_tasks.c b/manual_code/lab2/TM/src/app/ae_priv_tasks.c
index c64738d..9521013 100644
--- a/manual_code/lab2/TM/src/app/ae_priv_tasks.c
+++ b/manual_code/lab2/TM/src/app/ae_priv_tasks.c
@@ -43,6 +43,369 @@
#include "Serial.h"
#include "printf.h"
+// We should print TCB array inside every function for testing?
+
+//------KERNEL TASKS------//
+// k_tsk_create
+// k_tsk_get
+
+// k_tsk_create until max_tasks (same priority)
+// k_tsk_get for all TIDs
+// k_tsk create > max_tasks should fail
+// k_tsk_exit
+// k_tsk_create should reuse TID
+
+// k_tsk_create
+// tsk_create
+// k_tsk_get
+// k_tsk_set_prio for kernel task
+// k_tsk_set_prio for user task
+// k_tsk_get
+// k_tsk_set_prio PRIO_NULL should fail
+// k_tsk_set_prio invalid TID should fail
+// k_tsk_set_prio dormant task should fail
+
+U32 result = 1;
+U32 numtests = 0;
+
+void printResult(int passFail){
+ numtests++;
+ if(passFail == 1){
+ SER_PutStr ("--- Success ---\n\r");
+ result << 1;
+ result += 1;
+ } else {
+ SER_PutStr ("--- !!! FAILURE !!! ---\n\r");
+ result << 1;
+ }
+}
+
+void priv_check_usp(void){
+
+ RTX_TASK_INFO task_info;
+ task_t tid;
+
+ // k_tsk_get(gp_current_task->tid, &task_info);
+ k_tsk_create(&tid, &dumdum, HIGH, 0x400);
+ k_tsk_yield();
+ //k_tsk_get(gp_current_task->tid, &task_info);
+ k_tsk_exit();
+}
+
+void priv_task_check_sp(void){
+ task_t tid1;
+ RTX_TASK_INFO task_info1;
+ RTX_TASK_INFO task_info2;
+
+ // 1. create new user task with high priority
+ // 2. yield to new user task
+ // 3. k_tsk_get() before new task has chance to SVC
+ // 3. user task
+ k_tsk_create(&tid1, &checkSP, HIGH, 0x400);
+ k_tsk_get(tid1, &task_info1);
+ k_tsk_yield();
+ k_tsk_get(tid1, &task_info2);
+ k_tsk_get(gp_current_task->tid, &task_info2);
+
+ while(1);
+}
+
+void testDataOwnership(void){
+ task_t owner;
+ task_t thief;
+
+ SER_PutStr ("Start of testDataOwnership\n\r");
+
+ k_tsk_create(&owner, &dataOwner, HIGH, 0x200);
+ k_tsk_create(&thief, &dataThief, HIGH, 0x200);
+
+ k_tsk_set_prio(1, MEDIUM);
+
+ k_tsk_yield();
+
+ SER_PutStr ("Melvin Capital Bad\n\r");
+
+ while(1);
+}
+
+void priv_task_entry(void){
+
+ RTX_TASK_INFO task_info;
+ task_t tid;
+
+ SER_PutStr (">>>>>>>>>>>>>>>>>>>>> 1. tsk_create Failure Test:\n\r");
+ SER_PutStr ("Stack Size Too Small:\n\r");
+ printResult(k_tsk_create(&tid, &dumdum, LOW, 0x100) == RTX_ERR);
+ SER_PutStr ("Stack Size Not 8b Aligned:\n\r");
+ printResult(k_tsk_create(&tid, &dumdum, LOW, 0x401) == RTX_ERR);
+ // SER_PutStr ("Stack Size Too Big:\n\r");
+ // printResult(k_tsk_create(&tid, &dumdum, LOW, 0xFFFFFF00) == RTX_ERR); // U16 stack_size
+ SER_PutStr ("Prio Invalid:\n\r");
+ printResult(k_tsk_create(&tid, &dumdum, 99, 0x400) == RTX_ERR);
+ SER_PutStr ("Prio Null:\n\r");
+ printResult(k_tsk_create(&tid, &dumdum, PRIO_NULL, 0x400) == RTX_ERR);
+ SER_PutStr ("Null tid:\n\r");
+ printResult(k_tsk_create(NULL, &dumdum, LOW, 0x400) == RTX_ERR);
+ SER_PutStr ("Null task:\n\r");
+ printResult(k_tsk_create(&tid, NULL, LOW, 0x400) == RTX_ERR);
+
+ if (result == 7){
+ printf(">>>>>>>>>> TESTS PASSED <<<<<<<<<<<< \n\r");
+ }else{
+ printf(">>>>>>>>>> TESTS FAILED: %d <<<<<<<<<<<< \n\r", 7 - result);
+ }
+
+ result = 1;
+
+ SER_PutStr (">>>>>>>>>>>>>>>>>>>>> 2. tsk_create and tsk_get Function Test:\n\r");
+ k_tsk_create(&tid, &dumdum, LOW, 0x400);
+ SER_PutStr ("Did we get tid 2:\n\r");
+ printResult(tid == 2); // 0 = NULL_TASK, 1 = Priv Task, 2 = dumdum
+ k_tsk_get(tid, &task_info);
+
+ SER_PutStr ("Compare kStack Size:\n\r");
+ printResult(task_info.k_stack_size == KERN_STACK_SIZE); // 0x200
+ SER_PutStr ("Compare uStack Size:\n\r");
+ printResult(task_info.u_stack_size == 0x400);
+ SER_PutStr ("Compare Task ID:\n\r");
+ printResult(task_info.tid == tid);
+ SER_PutStr ("Compare Priority:\n\r");
+ printResult(task_info.prio == LOW);
+ SER_PutStr ("Compare State:\n\r");
+ printResult(task_info.state == READY);
+ SER_PutStr ("Compare Privilege:\n\r");
+ printResult(task_info.priv == 0);
+ SER_PutStr ("Compare k stack pointer to k stack hi:\n\r");
+ printResult(task_info.k_sp == task_info.k_stack_hi);
+ SER_PutStr ("Compare u stack pointer to u stack hi:\n\r");
+ printResult(task_info.u_sp == task_info.u_stack_hi);
+
+ if (result == 10){
+ printf(">>>>>>>>>> TESTS PASSED <<<<<<<<<<<< \n\r");
+ }else{
+ printf(">>>>>>>>>> TESTS FAILED: %d <<<<<<<<<<<< \n\r", 10 - result);
+ }
+
+ result = 1;
+
+ SER_PutStr (">>>>>>>>>>>>>>>>>>>>> 3. tsk_get Failure Test:\n\r");
+ SER_PutStr ("Task ID 0:\n\r");
+ printResult(k_tsk_get(0, &task_info) == RTX_ERR);
+ SER_PutStr ("Null Buffer Task Info:\n\r");
+ printResult(k_tsk_get(tid, NULL) == RTX_ERR);
+ SER_PutStr ("Max Task ID:\n\r");
+ printResult(k_tsk_get(MAX_TASKS, &task_info) == RTX_ERR);
+ SER_PutStr ("Dormant Task 3:\n\r");
+ printResult(k_tsk_get(3, &task_info) == RTX_ERR);
+ SER_PutStr ("Dormant Task Mid:\n\r");
+ printResult(k_tsk_get(MAX_TASKS/2, &task_info) == RTX_ERR);
+
+ if (result == 6){
+ printf(">>>>>>>>>> TESTS PASSED <<<<<<<<<<<< \n\r");
+ }else{
+ printf(">>>>>>>>>> TESTS FAILED: %d <<<<<<<<<<<< \n\r", 6 - result);
+ }
+
+ result = 1;
+
+ SER_PutStr (">>>>>>>>>>>>>>>>>>>>> 4. set_prio Function Test:\n\r");
+ SER_PutStr ("Set user prio:\n\r");
+ k_tsk_set_prio(tid, LOWEST);
+ k_tsk_get(tid, &task_info);
+ printResult(task_info.prio == LOWEST);
+ SER_PutStr ("Set own prio:\n\r"); // Should be setting prio from med to hi
+ k_tsk_set_prio(1, HIGH);
+ k_tsk_get(1, &task_info);
+ printResult(task_info.prio == HIGH);
+
+ if (result == 3){
+ printf(">>>>>>>>>> TESTS PASSED <<<<<<<<<<<< \n\r");
+ }else{
+ printf(">>>>>>>>>> TESTS FAILED: %d <<<<<<<<<<<< \n\r", 3 - result);
+ }
+
+ result = 1;
+
+ SER_PutStr (">>>>>>>>>>>>>>>>>>>>> 5. set_prio Failure Test:\n\r");
+ SER_PutStr ("Task ID 0:\n\r");
+ printResult(k_tsk_set_prio(0, HIGH) == RTX_ERR);
+ SER_PutStr ("Null_Task Prio:\n\r");
+ printResult(k_tsk_set_prio(tid, PRIO_NULL) == RTX_ERR);
+ SER_PutStr ("Max Task ID:\n\r");
+ printResult(k_tsk_set_prio(MAX_TASKS, HIGH) == RTX_ERR);
+ SER_PutStr ("Dormant Task 3:\n\r");
+ printResult(k_tsk_set_prio(3, HIGH) == RTX_ERR);
+ SER_PutStr ("Dormant Task Mid:\n\r");
+ printResult(k_tsk_set_prio(MAX_TASKS/2, HIGH) == RTX_ERR);
+ SER_PutStr ("Undefined Priority:\n\r");
+ printResult(k_tsk_set_prio(tid, 99) == RTX_ERR);
+ // SER_PutStr ("Privilege Check:\n\r"); // THIS IS WILL PASS FOR KERNEL TASK
+ // printResult(k_tsk_set_prio(1, HIGH) == RTX_ERR);
+
+ if (result == 7){
+ printf(">>>>>>>>>> TESTS PASSED <<<<<<<<<<<< \n\r");
+ }else{
+ printf(">>>>>>>>>> TESTS FAILED: %d <<<<<<<<<<<< \n\r", 7 - result);
+ }
+
+ result = 1;
+
+ SER_PutStr (">>>>>>>>>>>>>>>>>>>>> 6. tsk_create Stress Test:\n\r");
+
+ // Testing max_tasks
+ for(int i = 3; i < MAX_TASKS; i++){ // 0 is Null Task, 1 is this kernel task
+ k_tsk_create(&tid, &dumdum, LOW, 0x200);
+ }
+
+ SER_PutStr ("Creating Another Task Fails:\n\r");
+ printResult(k_tsk_create(&tid, &dumdum, LOW, 0x400) == RTX_ERR);
+
+ // Testing max_tasks
+ for(int i = 3; i < MAX_TASKS; i++){ // 0 is Null Task, 1 is this kernel task
+ k_tsk_create(&tid, &dumdum, LOW, 0x200);
+ }
+
+ SER_PutStr ("Creating Another Task Fails:\n\r");
+ printResult(k_tsk_create(&tid, &dumdum, LOW, 0x400) == RTX_ERR);
+
+ if (result == 2){
+ printf(">>>>>>>>>> TESTS PASSED <<<<<<<<<<<< \n\r");
+ }else{
+ printf(">>>>>>>>>> TESTS FAILED: %d <<<<<<<<<<<< \n\r", 2 - result);
+ }
+
+ k_tsk_set_prio(gp_current_task->tid, LOWEST);
+ k_tsk_yield();
+
+ SER_PutStr (">>>>>>>>>>>>>>>>>>>>> 7. TCB Reuse Test:\n\r");
+
+ // Testing reusability
+ k_tsk_create(&tid, &dumdum, LOW, 0x400);
+ SER_PutStr ("Task id after full yield is 1\n\r");
+ printResult(tid == 2);
+ k_tsk_yield();
+ k_tsk_create(&tid, &dumdum, LOW, 0x400);
+ SER_PutStr ("Task id after full yield is 1\n\r");
+ printResult(tid == 2);
+
+ k_tsk_exit();
+}
+
+void reset_scheduling() {
+ for (int i = 0; i < 255; i++) {
+ s_buffer[i] = 0;
+ }
+}
+
+// Function to implement strcmp function
+int strcmp(const char *X, const char *Y)
+{
+ while(*X)
+ {
+ // if characters differ or end of second string is reached
+ if (*X != *Y)
+ break;
+
+ // move to next pair of characters
+ X++;
+ Y++;
+ }
+
+ // return the ASCII difference after converting char* to unsigned char*
+ return *(const unsigned char*)X - *(const unsigned char*)Y;
+}
+
+void priv_tasks_scheduling(void) {
+ /* Test 1:
+ * Create:
+ * 3 tasks with high priority,
+ * 3 tasks with medium priority,
+ * 3 tasks with low priority,
+ * 3 tasks with lowest priority
+ * Expect High 1 high 2 high 3 med 1 med 2 med 3 etc.
+ *
+ * Then:
+ * Create in order of h1, m1, l1, lw1 etc.
+ *
+ * Then:
+ * Create in order of lw1, l1, m1, h1 etc.
+ *
+ * Then:
+ * Create in order of lw3, m2, l1, h3, etc.
+ *
+ */
+
+ task_t tid[10];
+
+ reset_scheduling();
+
+ k_tsk_create(&tid[0], &stask0, HIGH, 10000);
+ k_tsk_create(&tid[1], &stask1, HIGH, 10000);
+ k_tsk_create(&tid[2], &stask2, HIGH, 10000);
+ k_tsk_create(&tid[3], &stask3, MEDIUM, 10000);
+ k_tsk_create(&tid[4], &stask4, MEDIUM, 10000);
+ k_tsk_create(&tid[5], &stask5, MEDIUM, 10000);
+ k_tsk_create(&tid[6], &stask6, LOW, 10000);
+ k_tsk_create(&tid[7], &stask7, LOW, 10000);
+ k_tsk_create(&tid[8], &stask8, LOWEST, 10000);
+ k_tsk_create(& tid[9], &stask9, LOWEST, 10000);
+
+ k_tsk_set_prio(gp_current_task->tid, LOWEST);
+
+ k_tsk_yield();
+
+ SER_PutStr("Scheduler output after yielding cpu.\n\r");
+ printResult(strcmp(s_buffer, "0123456789") == 0);
+
+ reset_scheduling();
+
+ k_tsk_create(&tid[0], &stask7, HIGH, 10000);
+ k_tsk_create(&tid[3], &stask2, MEDIUM, 10000);
+ k_tsk_create(&tid[6], &stask9, LOW, 10000);
+ k_tsk_create(&tid[7], &stask1, LOW, 10000);
+ k_tsk_create(&tid[8], &stask0, LOWEST, 10000);
+ k_tsk_create(&tid[4], &stask4, MEDIUM, 10000);
+ k_tsk_create(&tid[5], &stask5, MEDIUM, 10000);
+ k_tsk_create(&tid[1], &stask3, HIGH, 10000);
+ k_tsk_create(&tid[2], &stask6, HIGH, 10000);
+ k_tsk_create(&tid[8], &stask8, LOWEST, 10000);
+
+ k_tsk_set_prio(gp_current_task->tid, LOWEST);
+
+ k_tsk_yield();
+
+ SER_PutStr("Scheduler output after yielding cpu.\n\r");
+ printResult(strcmp(s_buffer, "7362459108") == 0);
+
+ reset_scheduling();
+
+ k_tsk_create(&tid[0], &stask0, HIGH, 10000);
+ k_tsk_create(&tid[1], &stask1, HIGH, 10000);
+ k_tsk_create(&tid[2], &stask2, HIGH, 10000);
+ k_tsk_create(&tid[3], &stask3, MEDIUM, 10000);
+ k_tsk_create(&tid[4], &stask4, MEDIUM, 10000);
+ k_tsk_create(&tid[5], &stask5, MEDIUM, 10000);
+ k_tsk_create(&tid[6], &stask6, LOW, 10000);
+ k_tsk_create(&tid[7], &stask7, LOW, 10000);
+ k_tsk_create(&tid[8], &stask8, LOWEST, 10000);
+ k_tsk_create(& tid[9], &stask9, LOWEST, 10000);
+
+ k_tsk_set_prio(tid[0], LOWEST);
+ k_tsk_set_prio(tid[1], LOWEST);
+ k_tsk_set_prio(tid[2], LOWEST);
+ k_tsk_set_prio(tid[1], MEDIUM);
+
+
+ k_tsk_yield();
+
+ SER_PutStr("Scheduler output after yielding cpu.\n\r");
+ printResult(strcmp(s_buffer, "3451678902") == 0);
+
+ while(1);
+
+ k_tsk_exit();
+}
+
/**************************************************************************//**
* @brief a task that prints AAAAA, BBBBB, CCCCC,...., ZZZZZ on each line.
* It yields the cpu every 6 lines are printed.
diff --git a/manual_code/lab2/TM/src/app/ae_priv_tasks.h b/manual_code/lab2/TM/src/app/ae_priv_tasks.h
index 76492e5..aeb7e4e 100644
--- a/manual_code/lab2/TM/src/app/ae_priv_tasks.h
+++ b/manual_code/lab2/TM/src/app/ae_priv_tasks.h
@@ -59,6 +59,11 @@ extern void task1(void);
void priv_task1 (void);
void priv_task2 (void);
+void priv_task_entry(void);
+void priv_tasks_scheduling(void);
+void priv_task_check_sp(void);
+void testDataOwnership(void);
+
#endif // ! PRIV_TASKS_H_
/*
*===========================================================================
diff --git a/manual_code/lab2/TM/src/app/ae_usr_tasks.c b/manual_code/lab2/TM/src/app/ae_usr_tasks.c
index e57bd33..d3d258d 100644
--- a/manual_code/lab2/TM/src/app/ae_usr_tasks.c
+++ b/manual_code/lab2/TM/src/app/ae_usr_tasks.c
@@ -40,6 +40,96 @@
#include "Serial.h"
#include "printf.h"
+//----USER TASKS------// (implement in ae_usr_tasks.c)
+// tsk_create
+// tsk_get
+
+// tsk_create until max_tasks (same priority)
+// tsk_get for all TIDs
+// tsk create > max_tasks should fail
+// tsk_exit
+// tsk_create should reuse TID
+
+// tsk_create
+// tsk_get
+// tsk_set_prio
+// tsk_get
+// tsk_set_prio PRIO_NULL should fail
+// tsk_set_prio invalid TID should fail
+// tsk_set_prio dormant task should fail
+// tsk_set_prio for kernal task should fail
+// tsk_set_prio for user task
+// tsk_get
+
+char s_buffer[255];
+
+U32 * gmeStonks;
+U32 * bitCoinWallet;
+
+int powerOf(int a, int b){
+ int result = 1;
+ for(int i = 0; i < b; i++){
+ result = result * a;
+ }
+ return result;
+}
+
+void dumdum(void){
+ SER_PutStr ("I have brain damage\n\r");
+ int a = 2;
+ int b = a + 8;
+ int c = powerOf(a, b);
+ int d = 4 + c;
+ int e = powerOf(a, d);
+ tsk_exit();
+}
+
+void dumdum2(void){
+ SER_PutStr ("I have brain damage\n\r");
+ int a = 2;
+ int b = a + 8;
+ int c = powerOf(a, b);
+ int d = 4 + c;
+ int e = powerOf(a, d);
+
+ RTX_TASK_INFO task_info;
+
+ tsk_get(2, &task_info);
+ tsk_exit();
+}
+
+void dataOwner(void){
+ SER_PutStr(":diamond: :hand:\n\r");
+ gmeStonks = mem_alloc(420);
+ if(tsk_set_prio(1, HIGH) == RTX_ERR){
+ SER_PutStr("Could not set prio of kernel task\n\r");
+ }
+ int a = 2;
+ int b = a + 8;
+ int c = powerOf(a, b);
+
+ tsk_exit();
+}
+
+void dataThief(void){
+ SER_PutStr(":brrrrrrrr:\n\r");
+ bitCoinWallet = mem_alloc(0x400);
+ int a = 2;
+ int b = a + 8;
+ int c = powerOf(a, b);
+ if(mem_dealloc(gmeStonks) == RTX_ERR){
+ SER_PutStr("Test Passed\n\r");
+ }
+ mem_dealloc(bitCoinWallet);
+ tsk_set_prio(3, MEDIUM);
+ tsk_exit();
+}
+
+void checkSP(void){
+ SER_PutStr ("checkSP: I will yield\n\r");
+ tsk_yield();
+ tsk_exit();
+}
/**
* @brief: a dummy task1
@@ -68,6 +158,87 @@ void task2(void)
/* terminating */
tsk_exit();
}
+
+// Function to implement strncat() function in C
+char* strncat(char* destination, const char* source, size_t num)
+{
+ // make ptr point to the end of destination string
+ char* ptr = destination + strlen(destination);
+
+ // Appends characters of source to the destination string
+ while (*source != '\0' && num--)
+ *ptr++ = *source++;
+
+ // null terminate destination string
+ *ptr = '\0';
+
+ // destination string is returned by standard strncat()
+ return destination;
+}
+
+
+void stask0(void)
+{
+ strncat(s_buffer, "0", 1);
+ tsk_exit();
+}
+
+void stask1(void)
+{
+ strncat(s_buffer, "1", 1);
+ tsk_exit();
+}
+
+void stask2(void)
+{
+ strncat(s_buffer, "2", 1);
+ tsk_exit();
+}
+
+void stask3(void)
+{
+ strncat(s_buffer, "3", 1);
+ tsk_exit();
+}
+
+void stask4(void)
+{
+ strncat(s_buffer, "4", 1);
+ tsk_exit();
+}
+
+void stask5(void)
+{
+ strncat(s_buffer, "5", 1);
+ tsk_exit();
+}
+
+void stask6(void)
+{
+ strncat(s_buffer, "6", 1);
+ tsk_exit();
+}
+
+void stask7(void)
+{
+ strncat(s_buffer, "7", 1);
+ tsk_exit();
+}
+
+void stask8(void)
+{
+ strncat(s_buffer, "8", 1);
+ tsk_exit();
+}
+
+void stask9(void)
+{
+ strncat(s_buffer, "9", 1);
+ tsk_exit();
+}
+
+
+
/*
*===========================================================================
* END OF FILE
diff --git a/manual_code/lab2/TM/src/app/ae_usr_tasks.h b/manual_code/lab2/TM/src/app/ae_usr_tasks.h
index 3eb8afc..52afaca 100644
--- a/manual_code/lab2/TM/src/app/ae_usr_tasks.h
+++ b/manual_code/lab2/TM/src/app/ae_usr_tasks.h
@@ -40,9 +40,30 @@
#ifndef USR_TASK_H_
#define USR_TASK_H_
+extern char s_buffer[255];
+
void task1(void);
void task2(void);
+void dumdum(void);
+void dumdum2(void);
+
+void dataOwner(void);
+void dataThief(void);
+
+void checkSP(void);
+
+void stask0(void);
+void stask1(void);
+void stask2(void);
+void stask3(void);
+void stask4(void);
+void stask5(void);
+void stask6(void);
+void stask7(void);
+void stask8(void);
+void stask9(void);
+
#endif // ! USR_TASK_H_
/*
diff --git a/manual_code/lab2/TM/src/kernel/k_inc.h b/manual_code/lab2/TM/src/kernel/k_inc.h
index 777f24b..441d8e2 100644
--- a/manual_code/lab2/TM/src/kernel/k_inc.h
+++ b/manual_code/lab2/TM/src/kernel/k_inc.h
@@ -67,8 +67,12 @@ typedef struct tcb {
U32 *msp; /**> msp of the task, TCB_MSP_OFFSET = 4 */
U8 tid; /**> task id */
U8 prio; /**> Execution priority */
+ U32 task_count; /**> Update counter used for FIFO scheduling */
U8 state; /**> task state */
U8 priv; /**> = 0 unprivileged, =1 privileged */
+ U32 u_stack_hi; // user-space stack start
+ U16 u_stack_size; // user-space stack size
+ void (*ptask)(); // task entry address
} TCB;
/*
diff --git a/manual_code/lab2/TM/src/kernel/k_mem.c b/manual_code/lab2/TM/src/kernel/k_mem.c
index db8a842..90fa3d7 100644
--- a/manual_code/lab2/TM/src/kernel/k_mem.c
+++ b/manual_code/lab2/TM/src/kernel/k_mem.c
@@ -65,6 +65,22 @@ U32 g_k_stacks[MAX_TASKS][KERN_STACK_SIZE >> 2] __attribute__((aligned(8)));
//process stack for tasks in SYS mode
U32 g_p_stacks[MAX_TASKS][PROC_STACK_SIZE >> 2] __attribute__((aligned(8)));
+/*
+ *==========================================================================
+ * STRUCTS
+ *==========================================================================
+ */
+
+typedef struct Node {
+ unsigned int size;
+ U8 isFree;
+ task_t owner;
+ struct Node *next;
+} Node;
+
+// Global head
+Node* HEAD = NULL;
+
/*
*===========================================================================
* FUNCTIONS
@@ -76,39 +92,204 @@ U32* k_alloc_k_stack(task_t tid)
return g_k_stacks[tid+1];
}
-U32* k_alloc_p_stack(task_t tid)
-{
- return g_p_stacks[tid+1];
+U32* k_alloc_p_stack(task_t tid) {
+ void* mem = k_mem_alloc(g_tcbs[tid].u_stack_size);
+ Node* node = (Node*)mem - 1;
+ node->owner = 0;
+// return mem;
+ return (U32*) ((char*)mem + g_tcbs[tid].u_stack_size);
+// return g_p_stacks[tid+1];
}
int k_mem_init(void) {
unsigned int end_addr = (unsigned int) &Image$$ZI_DATA$$ZI$$Limit;
#ifdef DEBUG_0
- printf("k_mem_init: image ends at 0x%x\r\n", end_addr);
- printf("k_mem_init: RAM ends at 0x%x\r\n", RAM_END);
+ printf("k_mem_init: image ends at 0x%x\r\n", end_addr);
+ printf("k_mem_init: RAM ends at 0x%x\r\n", RAM_END);
#endif /* DEBUG_0 */
+
+ //check if end addr is valid
+ unsigned int totalSize = RAM_END - end_addr;
+ if(totalSize <= 0) {
+ return RTX_ERR;
+ }
+
+ // round end_addr to nearest 8
+ if (end_addr % 8 != 0) {
+ end_addr = ((unsigned int)(end_addr / 8)) * 8 + 8;
+
+ }
+
+ // cast end_addr to pointer given in end_addr
+ HEAD = (Node*) end_addr;
+
+ // setup head
+ HEAD->size = totalSize - sizeof(Node);
+ HEAD->isFree = 1;
+ HEAD->next = NULL;
+
return RTX_OK;
}
void* k_mem_alloc(size_t size) {
-#ifdef DEBUG_0
- printf("k_mem_alloc: requested memory size = %d\r\n", size);
-#endif /* DEBUG_0 */
- return NULL;
+//#ifdef DEBUG_0
+// printf("k_mem_alloc: requested memory size = %d\r\n", size);
+//#endif /* DEBUG_0 */
+
+ if (size == 0) {
+ return NULL;
+ }
+
+ // 8 byte align
+ if (size % 8 != 0) {
+ size = ((U32)(size / 8)) * 8 + 8;
+ }
+
+ Node* curr = HEAD;
+
+ while(curr != NULL) {
+ if (size <= curr->size && curr->isFree) {
+ break;
+ }
+ curr = curr->next;
+ }
+
+ // couldn't allocate since no free space
+ if (curr == NULL) {
+ return NULL;
+ }
+
+ //TODO: assign TID ownership
+
+ if (size == curr->size){
+ curr->owner = gp_current_task->tid;
+ curr->isFree=0;
+ return (void*)((U32)curr + sizeof(Node));
+ } else if (size < curr->size && (curr->size < (size + sizeof(Node)))) {
+ curr->owner = gp_current_task->tid;
+ curr->isFree=0;
+ return (void*)((U32)curr + sizeof(Node));
+ } else {
+ //make a new node
+ // might need to use an unsigned depending on how types work
+ Node* newNode = (Node*)((unsigned int)curr + sizeof(Node) + size);
+ newNode->isFree = 1;
+ newNode->size = curr->size - size - sizeof(Node);
+ newNode->next = curr->next;
+
+ curr->isFree=0;
+ curr->size = size;
+ curr->next = newNode;
+ curr->owner = gp_current_task->tid;
+ // Cast curr to U32 to ensure pointer arithmetic works
+ // Pointer addition works by adding by increment of sizeof the pointer
+ // argument. If curr is of type Node* and we add sizeof(Node), we add
+ // sizeof(Node)^2 amount of bytes.
+ return (void*)((U32)curr + sizeof(Node));
+ }
+}
+
+Node* mergeNode(Node* first, Node* second) {
+ if (first > second) {
+ return NULL;
+ }
+
+ Node* result = first;
+ result->size = first->size + second->size + sizeof(Node);
+ result->next = second->next;
+
+ return result;
}
int k_mem_dealloc(void *ptr) {
-#ifdef DEBUG_0
- printf("k_mem_dealloc: freeing 0x%x\r\n", (U32) ptr);
-#endif /* DEBUG_0 */
+//#ifdef DEBUG_0
+// printf("k_mem_dealloc: freeing 0x%x\r\n", (U32) ptr);
+//#endif /* DEBUG_0 */
+
+ Node* curr = HEAD;
+ Node* prev = NULL;
+
+ while (ptr != (char*)curr + sizeof(Node)) {
+ if (curr->next == NULL || curr->next == curr) {
+ return RTX_ERR;
+ }
+
+ prev = curr;
+ curr = curr->next;
+// printf("0x%x\n", (U32)((char*)curr + sizeof(Node) + curr->size));
+ }
+
+ // Double free
+ if (curr->isFree > 0) {
+ return RTX_ERR;
+ }
+
+ if (!gp_current_task->priv) {
+ if (gp_current_task->tid != curr->owner){
+ return RTX_ERR;
+ }
+ }
+
+ curr->isFree = 1;
+
+ // Merge neighboring nodes
+ if (prev && prev->isFree > 0) {
+ curr = mergeNode(prev, curr);
+ }
+
+ if (curr->next && curr->next->isFree > 0) {
+ curr = mergeNode(curr, curr->next);
+ }
+
+// print_list();
+
return RTX_OK;
}
int k_mem_count_extfrag(size_t size) {
#ifdef DEBUG_0
- printf("k_mem_extfrag: size = %d\r\n", size);
+ printf("k_mem_extfrag: size = %d\r\n", size);
#endif /* DEBUG_0 */
- return RTX_OK;
+
+ unsigned int memRegionSize;
+ int regionCount = 0;
+
+ Node* curNode = HEAD; // HEAD is global var
+
+ while(curNode != NULL){
+ memRegionSize = curNode->size + sizeof(Node);
+ if(curNode->isFree){
+ if(memRegionSize < size){
+ regionCount++;
+ }
+ }
+ curNode = curNode->next; // idk if this is the right way to goto next node
+ }
+
+
+ return regionCount;
+}
+
+int countNodes(){
+ Node* n = HEAD;
+ int ret = 0;
+ while(n != NULL) {
+ ret += 1;
+ n = n->next;
+ }
+ return ret;
+}
+
+int memLeakCheck(){
+ unsigned int howMuchMem = 0;
+ Node* curNode = HEAD;
+ while(curNode != NULL){
+ howMuchMem += curNode->size + sizeof(Node);
+ curNode = curNode->next;
+ }
+ unsigned int end_addr = (unsigned int) &Image$$ZI_DATA$$ZI$$Limit;
+ unsigned int totalSize = 0xBFFFFFFF - end_addr;
+ return howMuchMem == totalSize;
}
/*
diff --git a/manual_code/lab2/TM/src/kernel/k_mem.h b/manual_code/lab2/TM/src/kernel/k_mem.h
index d6e004a..ce2dada 100644
--- a/manual_code/lab2/TM/src/kernel/k_mem.h
+++ b/manual_code/lab2/TM/src/kernel/k_mem.h
@@ -54,6 +54,8 @@ int k_mem_dealloc (void *ptr);
int k_mem_count_extfrag (size_t size);
U32 *k_alloc_k_stack (task_t tid);
U32 *k_alloc_p_stack (task_t tid);
+int countNodes (void);
+int memLeakCheck (void);
#endif // ! K_MEM_H_
/*
diff --git a/manual_code/lab2/TM/src/kernel/k_task.c b/manual_code/lab2/TM/src/kernel/k_task.c
index f21ed5f..4615aef 100644
--- a/manual_code/lab2/TM/src/kernel/k_task.c
+++ b/manual_code/lab2/TM/src/kernel/k_task.c
@@ -122,6 +122,148 @@ The memory map of the OS image may look like the following:
---------------------------------------------------------------------------*/
+/*
+ *==========================================================================
+ * SCHEDULER VARIABLES
+ *==========================================================================
+ */
+
+static const int h_array_size = MAX_TASKS;
+static TCB* heap[h_array_size];
+static U32 current_size = 0;
+static U32 g_task_count = 0;
+
+/*
+ *===========================================================================
+ * SCHEDULER FUNCTIONS
+ *===========================================================================
+ */
+
+int compare(TCB *t1, TCB* t2) {
+ int result = (*t1).prio < (*t2).prio || ((*t1).prio == (*t2).prio && (*t1).task_count <= (*t2).task_count);
+ // printf("V1: %d, %d, %d - V2: %d, %d, %d - Result: %d\r\n", t1->tid, t1->prio, t1->task_count, t2->tid, t2->prio, t2->task_count, result);
+ return result;
+}
+
+void swap(TCB** t1, TCB** t2) {
+ TCB* t;
+ t = *t1;
+ *t1 = *t2;
+ *t2 = t;
+}
+
+int parent(int i) {
+ return (i > 0 && i < h_array_size) ? (i - 1) / 2 : -1;
+}
+
+int left_child(int i) {
+ return (2*i + 1 < current_size && i >= 0) ? 2*i + 1: -1;
+}
+
+int right_child(int i) {
+ return (2*i + 2 < current_size && i >= 0) ? 2*i + 2 : -1;
+}
+
+void increase_key(TCB* heap[], int i) {
+ while(i >= 0 && parent(i) >= 0 && !compare(heap[parent(i)], heap[i])) {
+ swap(&heap[i], &heap[parent(i)]);
+ i = parent(i);
+ }
+}
+
+void decrease_key(TCB* heap[], int i) {
+ int max_index = i;
+
+ int l = left_child(i);
+
+ if (l > 0 && compare(heap[l], heap[max_index])) {
+ max_index = l;
+ }
+
+ int r = right_child(i);
+
+ if (r > 0 && compare(heap[r], heap[max_index])) {
+ max_index = r;
+ }
+
+ if (i != max_index) {
+ swap(&heap[i], &heap[max_index]);
+ decrease_key(heap, max_index);
+ }
+}
+
+int insert(TCB* heap[], TCB* value) {
+ if (current_size + 1== h_array_size) {
+ return -1;
+ }
+
+ g_task_count += 1;
+ (*value).task_count = g_task_count;
+ heap[current_size] = value;
+ increase_key(heap, current_size);
+ current_size ++;
+ return 0;
+}
+
+int16_t maximum(TCB* heap[]) {
+ return current_size == 0 ? -1 : heap[0]->tid;
+}
+
+int16_t extract_max(TCB* heap[]) {
+ if (current_size == 0) { return 0; }
+
+ int16_t max_value = maximum(heap);
+
+ current_size --;
+ heap[0] = heap[current_size];
+ decrease_key(heap, 0);
+
+ return max_value;
+}
+
+int find_value(TCB* heap[], U8 tid) {
+ int i;
+ for (i = 0; i < current_size; i++) {
+ if (heap[i]->tid == tid) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+void reset_priority(TCB* heap[], U8 tid, U8 priority) {
+ int index = find_value(heap, tid);
+ if (index < 0) { return; }
+
+ TCB v = *heap[index];
+
+ g_task_count += 1;
+ heap[index]->prio = priority;
+ heap[index]->task_count = g_task_count;
+
+ if (compare(heap[index], &v)) {
+ increase_key(heap, index);
+ } else {
+ decrease_key(heap, index);
+ }
+}
+
+void remove_id(TCB* heap[], U8 tid) {
+ if (current_size == 0) { return; }
+
+ int i = find_value(heap, tid);
+
+ if (i < 0) { return; }
+
+ //printf("found id: %d\n", i);
+ heap[i] = heap[0];
+ heap[i]->task_count += 1;
+ increase_key(heap, i);
+ //print_heap(heap, current_size);
+ extract_max(heap);
+}
+
/*
*===========================================================================
* FUNCTIONS
@@ -136,14 +278,32 @@ The memory map of the OS image may look like the following:
*
*****************************************************************************/
+int currently_running() {
+ return gp_current_task && gp_current_task->state == RUNNING;
+}
+
TCB *scheduler(void)
{
- task_t tid = gp_current_task->tid;
- return &g_tcbs[(++tid)%g_num_active_tasks];
+ int16_t tid = maximum(heap);
+ //int16_t tid = extract_max(heap);
+ if (tid < 0) { return gp_current_task; }
-}
+ TCB* current_tcb = gp_current_task;
+ TCB* max_ready_tcb = &g_tcbs[(U8)tid];
+
+ // current task has higher priority
+ if (gp_current_task->state != DORMANT && current_tcb->prio < max_ready_tcb->prio) {
+ return gp_current_task;
+ }
+ gp_current_task = max_ready_tcb;
+ extract_max(heap);
+ insert(heap, current_tcb);
+
+ return gp_current_task;
+
+}
/**************************************************************************//**
* @brief initialize all boot-time tasks in the system,
@@ -178,6 +338,12 @@ int k_tsk_init(RTX_TASK_INFO *task_info, int num_tasks)
g_num_active_tasks++;
gp_current_task = p_tcb;
+ // initialize all TCB task ids and states to DORMANT
+ for(int i = 1; i < MAX_TASKS; i++){
+ g_tcbs[i].state = DORMANT;
+ g_tcbs[i].tid = i;
+ }
+
// create the rest of the tasks
p_taskinfo = task_info;
for ( int i = 0; i < num_tasks; i++ ) {
@@ -218,7 +384,7 @@ int k_tsk_create_new(RTX_TASK_INFO *p_taskinfo, TCB *p_tcb, task_t tid)
return RTX_ERR;
}
- p_tcb ->tid = tid;
+ p_tcb->tid = tid;
p_tcb->state = READY;
/*---------------------------------------------------------------
@@ -258,8 +424,12 @@ int k_tsk_create_new(RTX_TASK_INFO *p_taskinfo, TCB *p_tcb, task_t tid)
//********************************************************************//
//*** allocate user stack from the user space, not implemented yet ***//
//********************************************************************//
+ p_tcb->u_stack_size = p_taskinfo->u_stack_size;
*(--sp) = (U32) k_alloc_p_stack(tid);
+ // store user stack hi pointer in TCB
+ p_tcb->u_stack_hi = *sp; // user stack hi grows downwards
+
// uR12, uR11, ..., uR0
for ( int j = 0; j < 13; j++ ) {
*(--sp) = 0x0;
@@ -279,6 +449,8 @@ int k_tsk_create_new(RTX_TASK_INFO *p_taskinfo, TCB *p_tcb, task_t tid)
} else {
// kernel thread LR: return to the entry point of the task
*(--sp) = (U32) (p_taskinfo->ptask);
+ p_tcb->u_stack_hi = p_taskinfo->u_stack_size; // user stack hi grows downwards
+ p_tcb->u_stack_size = p_taskinfo->u_stack_size;
}
// kernel stack R0 - R12, 13 registers
@@ -286,7 +458,12 @@ int k_tsk_create_new(RTX_TASK_INFO *p_taskinfo, TCB *p_tcb, task_t tid)
*(--sp) = 0x0;
}
- p_tcb->msp = sp;
+ p_tcb->msp = sp; // store msp in TCB
+ p_tcb->ptask = p_taskinfo->ptask; // store task entry in TCB
+ p_tcb->prio = p_taskinfo->prio; // store priority in TCB
+ p_tcb->priv = p_taskinfo->priv; // store privilege in
+
+ insert(heap, p_tcb);
return RTX_OK;
}
@@ -348,8 +525,10 @@ int k_tsk_run_new(void)
// at this point, gp_current_task != NULL and p_tcb_old != NULL
if (gp_current_task != p_tcb_old) {
- gp_current_task->state = RUNNING; // change state of the to-be-switched-in tcb
- p_tcb_old->state = READY; // change state of the to-be-switched-out tcb
+ gp_current_task->state = RUNNING; // change state of the to-be-switched-in tcb
+ if(p_tcb_old->state != DORMANT){
+ p_tcb_old->state = READY; // change state of the to-be-switched-out tcb
+ }
k_tsk_switch(p_tcb_old); // switch stacks
}
@@ -367,6 +546,8 @@ int k_tsk_run_new(void)
*****************************************************************************/
int k_tsk_yield(void)
{
+ g_task_count++;
+ gp_current_task->task_count = g_task_count;
return k_tsk_run_new();
}
@@ -383,15 +564,117 @@ int k_tsk_create(task_t *task, void (*task_entry)(void), U8 prio, U16 stack_size
printf("k_tsk_create: entering...\n\r");
printf("task = 0x%x, task_entry = 0x%x, prio=%d, stack_size = %d\n\r", task, task_entry, prio, stack_size);
#endif /* DEBUG_0 */
- return RTX_OK;
+ // TODO: `k_tsk_create` is non-blocking, but can be preempted by `scheduler`
+ // TODO: check pointers
+ // TODO: error checking additional conditions
+
+ // TID pointer NULL
+ if (task == NULL){
+ return RTX_ERR;
+ }
+
+ // Task entry pointer NULL
+ if (task_entry == NULL){
+ return RTX_ERR;
+ }
+
+ // Maximum number of tasks reached
+ if (g_num_active_tasks == MAX_TASKS){
+ return RTX_ERR;
+ }
+
+ // stack size too small
+ if (stack_size < PROC_STACK_SIZE){
+ return RTX_ERR;
+ }
+
+ // stack size too big
+ size_t ALL_HEAP = 0xFFFFFFFF;
+ size_t suitable_regions = k_mem_count_extfrag(ALL_HEAP) - k_mem_count_extfrag(stack_size);
+ if (!suitable_regions){
+ return RTX_ERR;
+ }
+
+ // stack_size not 8 bytes aligned
+ if (stack_size % 8 != 0){
+ return RTX_ERR;
+ }
+
+ // prio invalid
+ if (prio != HIGH && prio != MEDIUM && prio != LOW && prio != LOWEST){
+ return RTX_ERR;
+ }
+
+ RTX_TASK_INFO task_info;
+ TCB * tcb = NULL;
+
+ // linear traverse to find free TID in g_tcbs;
+ for (int i=0; i < MAX_TASKS; i++){
+ // get dormant TCB
+ if(g_tcbs[i].state == DORMANT){
+ tcb = &g_tcbs[i];
+ break;
+ }
+ }
+
+ // get TID and store in buffer
+ *task = tcb->tid;
+
+ // fill in task_info
+ task_info.prio = prio;
+ task_info.priv = 0;
+ task_info.u_stack_size = stack_size;
+ task_info.ptask = task_entry;
+
+ // call k_tsk_create_new
+ if (k_tsk_create_new(&task_info, tcb, *task) == RTX_ERR){
+ return RTX_ERR;
+ }
+
+ g_num_active_tasks++;
+ //scheduler(); do we need to call?
+
+// if (currently_running()) {
+// k_tsk_yield();
+// } else {
+// return RTX_ERR;
+// }
+
+
+ return RTX_OK;
}
void k_tsk_exit(void)
{
+
#ifdef DEBUG_0
printf("k_tsk_exit: entering...\n\r");
#endif /* DEBUG_0 */
+
+ gp_current_task->state = DORMANT;
+
+ TCB* p_tcb_old = gp_current_task;
+ gp_current_task = scheduler();
+
+ if(p_tcb_old->priv == 0){
+ k_mem_dealloc((void *) ((U32)p_tcb_old->u_stack_hi - p_tcb_old->u_stack_size));
+ }
+
+ g_num_active_tasks--;
+ remove_id(heap, p_tcb_old->tid);
+
+ if ( gp_current_task == NULL ) {
+ gp_current_task = p_tcb_old; // revert back to the old task
+ return;
+ }
+
+ // at this point, gp_current_task != NULL and p_tcb_old != NULL
+ if (gp_current_task != p_tcb_old) {
+ gp_current_task->state = RUNNING; // change state of the to-be-switched-in tcb
+ k_tsk_switch(p_tcb_old); // switch stacks
+ }
+
return;
}
@@ -401,7 +684,48 @@ int k_tsk_set_prio(task_t task_id, U8 prio)
printf("k_tsk_set_prio: entering...\n\r");
printf("task_id = %d, prio = %d.\n\r", task_id, prio);
#endif /* DEBUG_0 */
- return RTX_OK;
+
+ // TODO: This function never blocks, but can be preempted. what does this mean?
+ // TODO: if try to set null task to prio PRIO_NULL, do I let it or error?
+
+ // prio invalid or PRIO_NULL
+ if (prio != HIGH && prio != MEDIUM && prio != LOW && prio != LOWEST){
+ return RTX_ERR;
+ }
+
+ // dormant TCB
+ if (g_tcbs[task_id].state == DORMANT){
+ return RTX_ERR;
+ }
+
+ if (prio == g_tcbs[task_id].prio) {
+ return RTX_OK;
+ }
+
+ // valid TID
+ if (task_id > 0 && task_id < MAX_TASKS){
+ // user-mode task can change prio of any user-mode task
+ // user-mode task cannot change prio of kernel task
+ // kernel task can change prio of any user-mode or kernel task
+
+ if(gp_current_task->priv == 1){
+ g_tcbs[task_id].prio = prio;
+ } else {
+ if(g_tcbs[task_id].priv == 1){
+ return RTX_ERR;
+ } else {
+ g_tcbs[task_id].prio = prio;
+ }
+ }
+
+ reset_priority(heap, task_id, prio);
+
+ k_tsk_yield();
+
+ return RTX_OK;
+ }else{
+ return RTX_ERR;
+ }
}
int k_tsk_get(task_t task_id, RTX_TASK_INFO *buffer)
@@ -410,22 +734,41 @@ int k_tsk_get(task_t task_id, RTX_TASK_INFO *buffer)
printf("k_tsk_get: entering...\n\r");
printf("task_id = %d, buffer = 0x%x.\n\r", task_id, buffer);
#endif /* DEBUG_0 */
+
+ // error checking
if (buffer == NULL) {
return RTX_ERR;
}
- /* The code fills the buffer with some fake task information.
- You should fill the buffer with correct information */
- buffer->tid = task_id;
- buffer->prio = 99;
- buffer->state = MEDIUM;
- buffer->priv = 0;
- buffer->ptask = 0x0;
- buffer->k_sp = 0xBEEFDEAD;
- buffer->k_stack_size = KERN_STACK_SIZE;
- buffer->u_sp = 0xDEADBEEF;
- buffer->u_stack_size = 0x200;
-
- return RTX_OK;
+ // Dormant TCB
+ if (g_tcbs[task_id].state == DORMANT){
+ return RTX_ERR;
+ }
+
+ // valid TID excluding 0
+ if (task_id > 0 && task_id < MAX_TASKS){
+ buffer->tid = task_id;
+ buffer->prio = g_tcbs[task_id].prio;
+ buffer->state = g_tcbs[task_id].state;
+ buffer->priv = g_tcbs[task_id].priv;
+ buffer->ptask = g_tcbs[task_id].ptask;
+ buffer->k_stack_hi = (U32) (&g_k_stacks[task_id+1]); // kernel stack hi grows downwards
+ buffer->k_stack_size = KERN_STACK_SIZE;
+ buffer->u_stack_hi = g_tcbs[task_id].u_stack_hi;
+ buffer->u_stack_size = g_tcbs[task_id].u_stack_size;
+
+ buffer->u_sp = * (U32*)((U32) g_tcbs[task_id].msp + 108);
+
+ if (task_id == gp_current_task->tid){
+ int regVal = __current_sp(); // store value of SP register in regVal
+ buffer->k_sp = regVal;
+ }else{
+ buffer->k_sp = (U32) g_tcbs[task_id].msp;
+ }
+ return RTX_OK;
+
+ }else{
+ return RTX_ERR;
+ }
}
int k_tsk_ls(task_t *buf, int count){
diff --git a/manual_code/lab2/TM/src/kernel/main_svc_cw.c b/manual_code/lab2/TM/src/kernel/main_svc_cw.c
index 08d852e..a65ab52 100644
--- a/manual_code/lab2/TM/src/kernel/main_svc_cw.c
+++ b/manual_code/lab2/TM/src/kernel/main_svc_cw.c
@@ -49,7 +49,6 @@
#include "k_inc.h"
#include "k_rtx.h"
-
extern void __ch_MODE (U32 mode);
extern void __atomic_on(void);
extern void __atomic_off(void);
@@ -67,10 +66,14 @@ void task_null (void)
}
}
+#define num_tasks 1
+
int main()
{
+
static RTX_SYS_INFO sys_info;
- static RTX_TASK_INFO task_info[2];
+ static RTX_TASK_INFO task_info[num_tasks];
+
char mode = 0;
// CMSIS system initialization
@@ -84,8 +87,10 @@ int main()
mode = __get_mode();
printf("mode = 0x%x\r\n", mode);
+
+
// System and Task set up by auto testing software
- if (ae_init(&sys_info, task_info, 2) != RTX_OK) {
+ if (ae_init(&sys_info, task_info, num_tasks) != RTX_OK) {
printf("RTX INIT FAILED\r\n");
return RTX_ERR;
}
@@ -93,7 +98,7 @@ int main()
// start the RTX and built-in tasks
if (mode == MODE_SVC) {
gp_current_task = NULL;
- k_rtx_init(task_info, 2);
+ k_rtx_init(task_info, num_tasks);
}
task_null();
diff --git a/manual_code/lab3/.project b/manual_code/lab3/.project
new file mode 100644
index 0000000..a555529
--- /dev/null
+++ b/manual_code/lab3/.project
@@ -0,0 +1,11 @@
+
+
+ lab3
+
+
+
+
+
+
+
+
diff --git a/manual_code/lab3/IPC/.settings/language.settings.xml b/manual_code/lab3/IPC/.settings/language.settings.xml
deleted file mode 100644
index 330084e..0000000
--- a/manual_code/lab3/IPC/.settings/language.settings.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/manual_code/lab3/IPC/DE1.launch b/manual_code/lab3/IPC/DE1.launch
index b980f7d..01e974d 100644
--- a/manual_code/lab3/IPC/DE1.launch
+++ b/manual_code/lab3/IPC/DE1.launch
@@ -1,31 +1,49 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -35,29 +53,43 @@
-
+
-
+
-
-
+
+
+
+
+
+
+
-
+
-
+
+
+
-
-
+
+
+
+
+
+
+
-
+
-
+
+
+
@@ -100,13 +132,42 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -117,14 +178,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/manual_code/lab3/IPC/TM1.launch b/manual_code/lab3/IPC/TM1.launch
index 691e2b3..7572c84 100644
--- a/manual_code/lab3/IPC/TM1.launch
+++ b/manual_code/lab3/IPC/TM1.launch
@@ -1,26 +1,26 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -30,29 +30,39 @@
-
+
-
+
-
+
+
+
+
-
+
-
+
-
+
+
+
-
+
+
+
+
-
+
-
+
-
+
+
+
@@ -63,7 +73,7 @@
-
+
diff --git a/manual_code/lab3/IPC/src/INC/common_ext.h b/manual_code/lab3/IPC/src/INC/common_ext.h
index 88eb0d6..3e859c6 100644
--- a/manual_code/lab3/IPC/src/INC/common_ext.h
+++ b/manual_code/lab3/IPC/src/INC/common_ext.h
@@ -46,6 +46,7 @@
*
*****************************************************************************/
+#include "common.h"
/*
*===========================================================================
* MACROS
@@ -58,14 +59,16 @@
*===========================================================================
*/
+typedef struct rtx_msg_char {
+ RTX_MSG_HDR hdr;
+ char data; /**> Sender tid */
+} RTX_MSG_CHAR;
/*
*===========================================================================
* STRUCTURES
*===========================================================================
*/
-
-
/*
*===========================================================================
diff --git a/manual_code/lab3/IPC/src/app/ae.c b/manual_code/lab3/IPC/src/app/ae.c
index a955622..b805dd3 100644
--- a/manual_code/lab3/IPC/src/app/ae.c
+++ b/manual_code/lab3/IPC/src/app/ae.c
@@ -105,15 +105,32 @@ void ae_set_task_info(RTX_TASK_INFO *tasks, int num_tasks) {
return;
}
- for (int i = 0; i < num_tasks; i++ ) {
- tasks[i].u_stack_size = 0x0;
- tasks[i].prio = HIGH;
- tasks[i].priv = 1;
- }
- tasks[0].ptask = &priv_task1;
- tasks[1].ptask = &priv_task2;
- tasks[2].ptask = &task2;
+ // for (int i = 0; i < num_tasks; i++ ) {
+ // tasks[i].u_stack_size = 0x0;
+ // tasks[i].prio = HIGH;
+ // tasks[i].priv = 1;
+ // }
+
+ tasks[0].u_stack_size = 0x200;
+ tasks[0].ptask = &kcd_task;
+ tasks[0].prio = MEDIUM;
+ tasks[0].priv = 0;
+
+ tasks[1].u_stack_size = 0x200;
+ tasks[1].ptask = &kcd_waiting;
+ tasks[1].prio = LOW;
+ tasks[1].priv = 0;
+
+ tasks[2].u_stack_size = 0x200;
+ tasks[2].ptask = &kcd_reg_and_exit;
+ tasks[2].prio = HIGH;
tasks[2].priv = 0;
+
+ tasks[3].u_stack_size = 0x200;
+ tasks[3].ptask = &kcd_receive_and_print;
+ tasks[3].prio = MEDIUM;
+ tasks[3].priv = 0;
+
return;
}
diff --git a/manual_code/lab3/IPC/src/app/ae_priv_tasks.c b/manual_code/lab3/IPC/src/app/ae_priv_tasks.c
index 5ef4960..4a4e2f5 100644
--- a/manual_code/lab3/IPC/src/app/ae_priv_tasks.c
+++ b/manual_code/lab3/IPC/src/app/ae_priv_tasks.c
@@ -56,21 +56,21 @@ void priv_task1(void)
int ret_val = 10;
while (1) {
- char out_char = 'A' + i%26;
- for (j = 0; j < 5; j++ ) {
- SER_PutChar(0,out_char);
- }
- SER_PutStr(0,"\n\r");
-
- for ( x = 0; x < DELAY; x++); // some artificial delay
+// char out_char = 'A' + i%26;
+// for (j = 0; j < 5; j++ ) {
+// SER_PutChar(0,out_char);
+// }
+// SER_PutStr(0,"\n\r");
+//
+// for ( x = 0; x < DELAY; x++); // some artificial delay
if ( (++i)%6 == 0 ) {
- SER_PutStr(0,"priv_task1 before yielding cpu.\n\r");
+// SER_PutStr(0,"priv_task1 before yielding cpu.\n\r");
ret_val = k_tsk_yield();
- SER_PutStr(0,"priv_task1 after yielding cpu.\n\r");
- printf("priv_task1: ret_val=%d\n\r", ret_val);
-#ifdef DEBUG_0
- printf("priv_task1: ret_val=%d\n\r", ret_val);
-#endif /* DEBUG_0 */
+// SER_PutStr(0,"priv_task1 after yielding cpu.\n\r");
+// printf("priv_task1: ret_val=%d\n\r", ret_val);
+//#ifdef DEBUG_0
+// printf("priv_task1: ret_val=%d\n\r", ret_val);
+//#endif /* DEBUG_0 */
}
}
}
@@ -92,27 +92,27 @@ void priv_task2(void)
RTX_TASK_INFO task_info;
task_t tid;
- k_tsk_create(&tid, &task1, LOW, 0x200); /*create a user task */
+ k_tsk_create(&tid, &task2, LOW, 0x200); /*create a user task */
k_tsk_get(tid, &task_info);
k_tsk_set_prio(tid, LOWEST);
for (i = 1;;i++) {
- char out_char = '0' + i%10;
- for (j = 0; j < 5; j++ ) {
- SER_PutChar(0,out_char);
- }
- SER_PutStr(0,"\n\r");
-
- for ( x = 0; x < DELAY; x++); // some artifical delay
+// char out_char = '0' + i%10;
+// for (j = 0; j < 5; j++ ) {
+// SER_PutChar(0,out_char);
+// }
+// SER_PutStr(0,"\n\r");
+//
+// for ( x = 0; x < DELAY; x++); // some artifical delay
if ( i%6 == 0 ) {
- SER_PutStr(0,"priv_task2 before yielding cpu.\n\r");
+// SER_PutStr(0,"priv_task2 before yielding cpu.\n\r");
ret_val = k_tsk_yield();
- SER_PutStr(0,"priv_task2 after yielding cpu.\n\r");
- printf("priv_task2: ret_val=%d\n\r", ret_val);
-#ifdef DEBUG_0
- //printf("priv_task2: ret_val=%d\n\r", ret_val);
-#endif /* DEBUG_0 */
+// SER_PutStr(0,"priv_task2 after yielding cpu.\n\r");
+// printf("priv_task2: ret_val=%d\n\r", ret_val);
+//#ifdef DEBUG_0
+// //printf("priv_task2: ret_val=%d\n\r", ret_val);
+//#endif /* DEBUG_0 */
}
}
}
diff --git a/manual_code/lab3/IPC/src/app/ae_usr_tasks.c b/manual_code/lab3/IPC/src/app/ae_usr_tasks.c
index e5ca139..27e6052 100644
--- a/manual_code/lab3/IPC/src/app/ae_usr_tasks.c
+++ b/manual_code/lab3/IPC/src/app/ae_usr_tasks.c
@@ -40,22 +40,41 @@
#include "Serial.h"
#include "printf.h"
+/**
+ * C++ version 0.4 char* style "itoa":
+ * Written by Luk�s Chmela
+ * Released under GPLv3.
+ */
+char* itoa(int value, char* result, int base) {
+ // check that the base if valid
+ if (base < 2 || base > 36) { *result = '\0'; return result; }
+
+ char* ptr = result, *ptr1 = result, tmp_char;
+ int tmp_value;
+
+ do {
+ tmp_value = value;
+ value /= base;
+ *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)];
+ } while ( value );
+
+ // Apply negative sign
+ if (tmp_value < 0) *ptr++ = '-';
+ *ptr-- = '\0';
+ while(ptr1 < ptr) {
+ tmp_char = *ptr;
+ *ptr--= *ptr1;
+ *ptr1++ = tmp_char;
+ }
+ return result;
+}
/**
* @brief: a dummy task1
*/
void task1(void)
{
- task_t tid;
- RTX_TASK_INFO task_info;
-
- SER_PutStr (0,"task1: entering \n\r");
- /* do something */
- tsk_create(&tid, &task2, LOW, 0x200); /*create a user task */
- tsk_get(tid, &task_info);
- tsk_set_prio(tid, LOWEST);
- /* terminating */
- tsk_exit();
+ tsk_exit();
}
/**
@@ -63,30 +82,128 @@ void task1(void)
*/
void task2(void)
{
- SER_PutStr (0,"task2: entering \n\r");
- /* do something */
- long int x = 0;
- int ret_val = 10;
- int i = 0;
- int j = 0;
- for (i = 1;;i++) {
- char out_char = 'a' + i%10;
- for (j = 0; j < 5; j++ ) {
- SER_PutChar(0,out_char);
- }
- SER_PutStr(0,"\n\r");
-
- for ( x = 0; x < 5000000; x++); // some artifical delay
- if ( i%6 == 0 ) {
- SER_PutStr(0,"usr_task2 before yielding cpu.\n\r");
- ret_val = tsk_yield();
- SER_PutStr(0,"usr_task2 after yielding cpu.\n\r");
- printf("usr_task2: ret_val=%d\n\r", ret_val);
- }
+ mbx_create(KCD_MBX_SIZE);
+ U32 counter = 0;
+ while(1) {
+ void* msg = mem_alloc(200);
+ RTX_MSG_HDR* hdr = msg;
+ char count_str[5];
+ char* count_str_s = itoa(counter, count_str, 10);
+ char hello_world[19] = "hello world \0\0\0\0\n\r\0";
+ int i = 12;
+ while (*(count_str_s+i-12) != '\0' && i < 16) {
+ hello_world[i] = *(count_str_s + i - 12);
+ i++;
+ }
+
+ hello_world[i] = '\n';
+ hello_world[i + 1] = '\r';
+ hello_world[i + 2] = '\0';
+ hdr->length = sizeof(RTX_MSG_HDR) + i + 3;
+
+ for (int i = 0; i < 19; i++) {
+ *((char*)msg + sizeof(RTX_MSG_HDR) + i) = hello_world[i];
+ }
+
+ send_msg(TID_KCD, msg);
+ mem_dealloc(msg);
+ counter++;
+ if (counter == 39) {
+ int j = 0;
+ int kk = j;
+ }
+ }
+}
+
+void kcd_reg_and_exit(void){
+ mbx_create(KCD_MBX_SIZE);
+ RTX_MSG_CHAR msg;
+ msg.hdr.length = sizeof(RTX_MSG_HDR) + 1;
+ msg.hdr.type = KCD_REG;
+ msg.data = 'q';
+ if(send_msg(TID_KCD, &msg) == RTX_OK){
+ SER_PutStr(0, "Sent Reg Msg");
+ }
+ tsk_exit();
+}
+
+void kcd_receive_and_print(void){
+ mbx_create(KCD_MBX_SIZE);
+ task_t sender_tid;
+ char* recv_buf = mem_alloc(KCD_MBX_SIZE);
+
+ RTX_MSG_CHAR msg;
+ msg.hdr.length = sizeof(RTX_MSG_HDR) + 1;
+ msg.hdr.type = KCD_REG;
+ msg.data = 'w';
+ send_msg(TID_KCD, &msg);
+
+ U8 flag = 0;
+
+ while(1){
+ int ret_val = recv_msg(&sender_tid, recv_buf, KCD_MBX_SIZE);
+ SER_PutStr(0, "kcd_receive_and_print: ");
+
+ if(ret_val != RTX_OK){
+ SER_PutStr(0, "Sike\r\n");
+ continue;
+ }
+
+ RTX_MSG_HDR* msg_hdr = (RTX_MSG_HDR*)(recv_buf);
+
+ if (msg_hdr->type != KCD_CMD){
+ // ignore message if data more than 1 char
+ SER_PutStr(0, " Not a CMD message\r\n");
+ continue;
}
- /* terminating */
- //tsk_exit();
+
+ *(recv_buf + ((RTX_MSG_HDR*)recv_buf)->length) = '\0';
+ SER_PutStr(0, recv_buf + sizeof(RTX_MSG_HDR));
+ SER_PutStr(0, "\r\n");
+
+ if (flag == 0) {
+ flag = 1;
+ msg.hdr.length = sizeof(RTX_MSG_HDR) + 1;
+ msg.hdr.type = KCD_REG;
+ msg.data = 'q';
+ send_msg(TID_KCD, &msg);
+ } else if (flag == 1) {
+ flag = 2;
+ msg.hdr.length = sizeof(RTX_MSG_HDR) + 1;
+ msg.hdr.type = KCD_REG;
+ msg.data = '!';
+ send_msg(TID_KCD, &msg);
+ } else if (flag == 2) {
+ flag = 3;
+ msg.hdr.length = sizeof(RTX_MSG_HDR) + 2;
+ msg.hdr.type = KCD_REG;
+ msg.data = '!';
+ send_msg(TID_KCD, &msg);
+ }
+
+ }
}
+
+void kcd_waiting(void){
+ mbx_create(KCD_MBX_SIZE);
+
+ RTX_MSG_CHAR msg;
+ msg.hdr.length = sizeof(RTX_MSG_HDR) + 1;
+ msg.hdr.type = KCD_REG;
+ msg.data = 'e';
+
+ send_msg(TID_KCD, &msg);
+
+ while(1){
+ U32 counter = 0;
+ for(U32 timer = 0xFFFFFF; timer != 0; timer--){
+ counter++;
+ }
+ SER_PutStr(0, "Uno Cycle\r\n");
+ tsk_yield();
+ }
+}
+
/*
*===========================================================================
* END OF FILE
diff --git a/manual_code/lab3/IPC/src/app/ae_usr_tasks.h b/manual_code/lab3/IPC/src/app/ae_usr_tasks.h
index 3eb8afc..ee58257 100644
--- a/manual_code/lab3/IPC/src/app/ae_usr_tasks.h
+++ b/manual_code/lab3/IPC/src/app/ae_usr_tasks.h
@@ -43,6 +43,10 @@
void task1(void);
void task2(void);
+void kcd_waiting(void);
+void kcd_reg_and_exit(void);
+void kcd_receive_and_print(void);
+
#endif // ! USR_TASK_H_
/*
diff --git a/manual_code/lab3/IPC/src/app/kcd_task.c b/manual_code/lab3/IPC/src/app/kcd_task.c
index f50b577..e0eef40 100644
--- a/manual_code/lab3/IPC/src/app/kcd_task.c
+++ b/manual_code/lab3/IPC/src/app/kcd_task.c
@@ -1,6 +1,207 @@
+#include "rtx.h"
+#include "Serial.h"
+#include "printf.h"
+extern void kcd_task(void);
+
/* The KCD Task Template File */
+U8 charIsValid(U8 character){
+ if (character > 47 && character < 58){
+ return 1;
+ } else if (character > 64 && character < 91){
+ return 1;
+ } else if (character > 96 && character < 123){
+ return 1;
+ } else if (character == 13 || character == 37){
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+U8 charIsAlphaNum(U8 character){
+ if (character > 47 && character < 58){
+ // 0-9 = 48-57
+ return 1;
+ }else if (character > 64 && character < 91){
+ // A-Z = 65-90
+ return 1;
+ }else if (character > 96 && character < 123){
+ // a-z = 97-122
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+U8 charToIndex(U8 character){
+ if (character > 47 && character < 58){
+ // 0-9 = 48-57
+ return character - 48;
+ }else if (character > 64 && character < 91){
+ // A-Z = 65-90
+ return character - 55;
+ }else if (character > 96 && character < 123){
+ // a-z = 97-122
+ return character - 61;
+ } else {
+ return 255;
+ }
+}
+
void kcd_task(void)
{
- /* not implemented yet */
+ mbx_create(KCD_MBX_SIZE);
+ task_t sender_tid;
+ char* recv_buf = mem_alloc(KCD_MBX_SIZE);
+
+ // 62 valid option commands for registration
+ U8 cmd_reg[62];
+ for (int i=0; i<62; i++){
+ cmd_reg[i] = 0;
+ }
+
+ // KEY_IN queue
+ U8 cmd_queue[64];
+ for (int i=0; i<64; i++){
+ cmd_queue[i] = 0;
+ }
+
+ U8 cmd_queue_counter = 0;
+ U8 cmd_len = 0;
+ U8 cmd_invalid = 0;
+
+ while(1) {
+ int ret_val = recv_msg(&sender_tid, recv_buf, KCD_MBX_SIZE);
+
+ if(ret_val != RTX_OK){
+ continue;
+ }
+
+ RTX_MSG_HDR* msg_hdr = (RTX_MSG_HDR*)(recv_buf);
+
+ if (msg_hdr->length != sizeof(RTX_MSG_HDR) + 1){
+ // ignore message if data more than 1 char
+ // SER_PutStr(0, "KCD_IN: Unexpected message length\r\n");
+ continue;
+ }
+
+ // process KCD_REG or KEY_IN type messages
+ if (msg_hdr->type == KCD_REG){
+ // command registration
+
+ RTX_MSG_CHAR * msg = (RTX_MSG_CHAR*) recv_buf;
+
+ // get command identifier
+ U8 cmd_id = msg->data;
+
+ if (charIsAlphaNum(cmd_id) == 0){
+ // invalid cmd_id
+ // SER_PutStr(0, "Reg: Invalid Command ID\r\n");
+ continue;
+ }
+
+ // convert cmd_id to ascii and offset
+ U8 index = charToIndex(cmd_id);
+
+ // store it in cmd_reg
+ cmd_reg[index] = sender_tid;
+ // SER_PutStr(0, "Reg: Successfully registered something\r\n");
+
+ } else if (msg_hdr->type == KEY_IN){
+ // Keyboard Input
+
+ // get command char
+ RTX_MSG_CHAR * msg = (RTX_MSG_CHAR*) recv_buf;
+ U8 cmd_char = msg->data;
+ cmd_len++;
+
+ // first character should be %
+ if ( (cmd_len == 1 && cmd_char != 37) || (cmd_len != 1 && cmd_char == 37) ){
+ cmd_invalid = 1;
+ // SER_PutStr(0, "Key In: Percent not in the right place\r\n");
+ }
+
+ // command length (including % and enter) larger than 64 bytes
+ if (cmd_len > 64){
+ cmd_invalid = 1;
+ // SER_PutStr(0, "Key In: Command Length too long\r\n");
+ }
+
+ // TODO: write charIsValid(), figure out what is a valid char?
+ if (!charIsValid(cmd_char)){
+ cmd_invalid = 1;
+ // SER_PutStr(0, "Key In: Invalid Character Detected\r\n");
+ }
+
+ if (cmd_invalid == 0){
+ // valid command
+ // if enter: dequeue and create string
+ if (cmd_char == 13){
+ // populate command message buffer
+
+ void* msg = mem_alloc(sizeof(RTX_MSG_HDR) + cmd_len - 2);
+ RTX_MSG_HDR* hdr = msg;
+
+ //RTX_MSG_HDR *cmd_msg;
+ hdr->type = KCD_CMD;
+ hdr->length = sizeof(RTX_MSG_HDR) + cmd_len - 2; // exclude % and enter
+
+ // TODO: verify if string create works
+ for(int i=0; i MAX_TASKS){
+ SER_PutStr(0, "Command cannot be processed\r\n");
+ // SER_PutStr(0, "Key In: Unregistered cmd_id OR invalid TID\r\n");
+ }else{
+
+ // send message to registered task id
+ int msg_sent = send_msg(recv_tid, msg);
+
+ if (msg_sent == RTX_ERR){
+ SER_PutStr(0, "Command cannot be processed\r\n");
+ // SER_PutStr(0, "Key In: Message failed to send\r\n");
+ }
+ }
+
+ // reset
+ for(int i=0; i<64; i++){
+ cmd_queue[i] = 0;
+ }
+ cmd_queue_counter = 0;
+ cmd_len = 0;
+ cmd_invalid = 0;
+
+ }else{
+ // enqueue KEY_IN msg data
+ cmd_queue[cmd_queue_counter] = cmd_char;
+ cmd_queue_counter++;
+ }
+ }else{
+ // invalid command
+ // if enter: dequeue and output failure message
+ if (cmd_char == 13){
+ SER_PutStr(0, "Invalid Command\r\n");
+
+ // reset
+ for(int i=0; i<64; i++){
+ cmd_queue[i] = 0;
+ }
+ cmd_queue_counter = 0;
+ cmd_len = 0;
+ cmd_invalid = 0;
+ }
+ }
+ }
+ }
}
diff --git a/manual_code/lab3/IPC/src/kernel/HAL_CA.c b/manual_code/lab3/IPC/src/kernel/HAL_CA.c
index e55c5ac..0c87397 100644
--- a/manual_code/lab3/IPC/src/kernel/HAL_CA.c
+++ b/manual_code/lab3/IPC/src/kernel/HAL_CA.c
@@ -37,13 +37,14 @@
* The code borrowed ideas from ARM RTX source code
*
*****************************************************************************/
-
-#include "common.h"
+
+#include "common_ext.h"
#include "k_inc.h"
#include "k_HAL_CA.h"
#include "interrupt.h"
#include "Serial.h"
#include "k_task.h"
+#include "k_msg.h"
#pragma push
#pragma arm
@@ -236,8 +237,20 @@ void SER_Interrupt(void)
{
while(Rx_Data_Ready()) // read while Data Ready is valid
{
- char c = Rx_Read_Data(); // would also clear the interrupt if last character is read
- SER_PutChar(1, c); // display back
+ char c = Rx_Read_Data(); // would also clear the interrupt if last character is read
+ if( (U8) c == 13){
+ SER_PutStr(1, "\r\n");
+ } else {
+ SER_PutChar(1, c); // display back
+ }
+
+ RTX_MSG_CHAR msg;
+ msg.hdr.length = sizeof(RTX_MSG_HDR) + 1;
+ msg.hdr.type = KEY_IN;
+ msg.data = c;
+
+ k_send_msg(TID_KCD, &msg);
+
}
}
else{ // unexpected interrupt type
diff --git a/manual_code/lab3/IPC/src/kernel/k_inc.h b/manual_code/lab3/IPC/src/kernel/k_inc.h
index 777f24b..a349a47 100644
--- a/manual_code/lab3/IPC/src/kernel/k_inc.h
+++ b/manual_code/lab3/IPC/src/kernel/k_inc.h
@@ -67,8 +67,13 @@ typedef struct tcb {
U32 *msp; /**> msp of the task, TCB_MSP_OFFSET = 4 */
U8 tid; /**> task id */
U8 prio; /**> Execution priority */
+ U32 task_count; /**> Update counter used for FIFO scheduling */
U8 state; /**> task state */
U8 priv; /**> = 0 unprivileged, =1 privileged */
+ U32 u_stack_hi; // user-space stack start
+ U16 u_stack_size; // user-space stack size
+ void (*ptask)(); // task entry address
+ U32 mailbox; // pointer to mailbox
} TCB;
/*
diff --git a/manual_code/lab3/IPC/src/kernel/k_mem.c b/manual_code/lab3/IPC/src/kernel/k_mem.c
index db8a842..bf86946 100644
--- a/manual_code/lab3/IPC/src/kernel/k_mem.c
+++ b/manual_code/lab3/IPC/src/kernel/k_mem.c
@@ -65,50 +65,238 @@ U32 g_k_stacks[MAX_TASKS][KERN_STACK_SIZE >> 2] __attribute__((aligned(8)));
//process stack for tasks in SYS mode
U32 g_p_stacks[MAX_TASKS][PROC_STACK_SIZE >> 2] __attribute__((aligned(8)));
+/*
+ *==========================================================================
+ * STRUCTS
+ *==========================================================================
+ */
+
+typedef struct Node {
+ unsigned int size;
+ U8 isFree;
+ task_t owner;
+ struct Node *next;
+} __attribute__((aligned(8)))Node;
+
+// Global head
+Node* HEAD = NULL;
+
/*
*===========================================================================
* FUNCTIONS
*===========================================================================
*/
+int glob = 0;
+
U32* k_alloc_k_stack(task_t tid)
{
return g_k_stacks[tid+1];
}
-U32* k_alloc_p_stack(task_t tid)
-{
- return g_p_stacks[tid+1];
+U32* k_alloc_p_stack(task_t tid) {
+ void* mem = k_mem_alloc(g_tcbs[tid].u_stack_size);
+ Node* node = (Node*)mem - 1;
+ node->owner = 0;
+// return mem;
+ return (U32*) ((char*)mem + g_tcbs[tid].u_stack_size);
+// return g_p_stacks[tid+1];
}
int k_mem_init(void) {
unsigned int end_addr = (unsigned int) &Image$$ZI_DATA$$ZI$$Limit;
#ifdef DEBUG_0
- printf("k_mem_init: image ends at 0x%x\r\n", end_addr);
- printf("k_mem_init: RAM ends at 0x%x\r\n", RAM_END);
+ printf("k_mem_init: image ends at 0x%x\r\n", end_addr);
+ printf("k_mem_init: RAM ends at 0x%x\r\n", RAM_END);
#endif /* DEBUG_0 */
+
+ //check if end addr is valid
+ unsigned int totalSize = RAM_END - end_addr;
+ if(totalSize <= 0) {
+ return RTX_ERR;
+ }
+
+ // round end_addr to nearest 8
+ if (end_addr % 8 != 0) {
+ end_addr = ((unsigned int)(end_addr / 8)) * 8 + 8;
+
+ }
+
+ // cast end_addr to pointer given in end_addr
+ HEAD = (Node*) end_addr;
+
+ // setup head
+ HEAD->size = totalSize - sizeof(Node);
+ HEAD->isFree = 1;
+ HEAD->next = NULL;
+
return RTX_OK;
}
void* k_mem_alloc(size_t size) {
-#ifdef DEBUG_0
- printf("k_mem_alloc: requested memory size = %d\r\n", size);
-#endif /* DEBUG_0 */
- return NULL;
+//#ifdef DEBUG_0
+// printf("k_mem_alloc: requested memory size = %d\r\n", size);
+//#endif /* DEBUG_0 */
+
+ if (size == 0) {
+ return NULL;
+ }
+
+ // 8 byte align
+ if (size % 8 != 0) {
+ size = ((U32)(size / 8)) * 8 + 8;
+ }
+
+ Node* curr = HEAD;
+
+ while(curr != NULL) {
+ if (size <= curr->size && curr->isFree) {
+ break;
+ }
+ curr = curr->next;
+ }
+
+ // couldn't allocate since no free space
+ if (curr == NULL) {
+ return NULL;
+ }
+
+ //TODO: assign TID ownership
+
+ if (size == curr->size){
+ curr->owner = gp_current_task->tid;
+ curr->isFree=0;
+ return (void*)((U32)curr + sizeof(Node));
+ } else if (size < curr->size && (curr->size < (size + sizeof(Node)))) {
+ curr->owner = gp_current_task->tid;
+ curr->isFree=0;
+ return (void*)((U32)curr + sizeof(Node));
+ } else {
+ //make a new node
+ // might need to use an unsigned depending on how types work
+ Node* newNode = (Node*)((unsigned int)curr + sizeof(Node) + size);
+ newNode->isFree = 1;
+ newNode->size = curr->size - size - sizeof(Node);
+ newNode->next = curr->next;
+
+ curr->isFree=0;
+ curr->size = size;
+ curr->next = newNode;
+ curr->owner = gp_current_task->tid;
+ // Cast curr to U32 to ensure pointer arithmetic works
+ // Pointer addition works by adding by increment of sizeof the pointer
+ // argument. If curr is of type Node* and we add sizeof(Node), we add
+ // sizeof(Node)^2 amount of bytes.
+ return (void*)((U32)curr + sizeof(Node));
+ }
+}
+
+Node* mergeNode(Node* first, Node* second) {
+ if (first > second) {
+ return NULL;
+ }
+
+ Node* result = first;
+ result->size = first->size + second->size + sizeof(Node);
+ result->next = second->next;
+
+ if ((U32)result % 8 != 0 || (U32)result->next % 8 != 0) {
+ int j = 0;
+ int i = j;
+ }
+
+ return result;
}
int k_mem_dealloc(void *ptr) {
-#ifdef DEBUG_0
- printf("k_mem_dealloc: freeing 0x%x\r\n", (U32) ptr);
-#endif /* DEBUG_0 */
+//#ifdef DEBUG_0
+// printf("k_mem_dealloc: freeing 0x%x\r\n", (U32) ptr);
+//#endif /* DEBUG_0 */
+
+ Node* curr = HEAD;
+ Node* prev = NULL;
+
+ while (ptr != (char*)curr + sizeof(Node)) {
+ if (curr->next == NULL || curr->next == curr) {
+ return RTX_ERR;
+ }
+
+ prev = curr;
+ curr = curr->next;
+// printf("0x%x\n", (U32)((char*)curr + sizeof(Node) + curr->size));
+ }
+
+ // Double free
+ if (curr->isFree > 0) {
+ return RTX_ERR;
+ }
+
+ if (!gp_current_task->priv) {
+ if (gp_current_task->tid != curr->owner){
+ return RTX_ERR;
+ }
+ }
+
+ curr->isFree = 1;
+
+ // Merge neighboring nodes
+ if (prev && prev->isFree > 0) {
+ curr = mergeNode(prev, curr);
+ }
+
+ if (curr->next && curr->next->isFree > 0) {
+ curr = mergeNode(curr, curr->next);
+ }
+
+// print_list();
+
return RTX_OK;
}
int k_mem_count_extfrag(size_t size) {
#ifdef DEBUG_0
- printf("k_mem_extfrag: size = %d\r\n", size);
+ printf("k_mem_extfrag: size = %d\r\n", size);
#endif /* DEBUG_0 */
- return RTX_OK;
+
+ unsigned int memRegionSize;
+ int regionCount = 0;
+
+ Node* curNode = HEAD; // HEAD is global var
+
+ while(curNode != NULL){
+ memRegionSize = curNode->size + sizeof(Node);
+ if(curNode->isFree){
+ if(memRegionSize < size){
+ regionCount++;
+ }
+ }
+ curNode = curNode->next; // idk if this is the right way to goto next node
+ }
+
+
+ return regionCount;
+}
+
+int countNodes(){
+ Node* n = HEAD;
+ int ret = 0;
+ while(n != NULL) {
+ ret += 1;
+ n = n->next;
+ }
+ return ret;
+}
+
+int memLeakCheck(){
+ unsigned int howMuchMem = 0;
+ Node* curNode = HEAD;
+ while(curNode != NULL){
+ howMuchMem += curNode->size + sizeof(Node);
+ curNode = curNode->next;
+ }
+ unsigned int end_addr = (unsigned int) &Image$$ZI_DATA$$ZI$$Limit;
+ unsigned int totalSize = 0xBFFFFFFF - end_addr;
+ return howMuchMem == totalSize;
}
/*
diff --git a/manual_code/lab3/IPC/src/kernel/k_mem.h b/manual_code/lab3/IPC/src/kernel/k_mem.h
index d6e004a..80b5718 100644
--- a/manual_code/lab3/IPC/src/kernel/k_mem.h
+++ b/manual_code/lab3/IPC/src/kernel/k_mem.h
@@ -54,6 +54,8 @@ int k_mem_dealloc (void *ptr);
int k_mem_count_extfrag (size_t size);
U32 *k_alloc_k_stack (task_t tid);
U32 *k_alloc_p_stack (task_t tid);
+int countNodes (void);
+int memLeakCheck (void);
#endif // ! K_MEM_H_
/*
@@ -61,4 +63,3 @@ U32 *k_alloc_p_stack (task_t tid);
* END OF FILE
*===========================================================================
*/
-
diff --git a/manual_code/lab3/IPC/src/kernel/k_msg.c b/manual_code/lab3/IPC/src/kernel/k_msg.c
index b0b2ba4..6569fb7 100644
--- a/manual_code/lab3/IPC/src/kernel/k_msg.c
+++ b/manual_code/lab3/IPC/src/kernel/k_msg.c
@@ -6,15 +6,144 @@
*/
#include "k_msg.h"
+#include "common_ext.h"
#ifdef DEBUG_0
#include "printf.h"
+#include "Serial.h"
#endif /* ! DEBUG_0 */
+// data_end can be less than data_start. Then the data wraps from
+// start_data through buffer_end, back to buffer_start, to data_end.
+typedef struct circular_buffer {
+ U32 buffer_start; // Start of buffer in memory
+ U32 buffer_end; // End of buffer in memory
+ U32 data_start; // Start of "valid data" in memory
+ U32 data_end; // End of "valid data" in memory.
+} __attribute__((aligned(8)))C_BUFFER;
+
+typedef struct c_metadata {
+ task_t sender_tid;
+} __attribute__((aligned(8)))C_METADATA;
+
+void mem_cpy(void* source, void* dest, size_t len) {
+ for (int i = 0; i < len; i++) {
+ *((char*)dest+i) = *((char*)source+i);
+ }
+}
+
+// Prereq: addr is aligned
+U32 align_increment(U32 addr, U32 increment, U32 alignment) {
+ if ((addr + increment) % alignment == 0) {
+ return addr + increment;
+ }
+
+ return addr + increment + (alignment - increment % alignment);
+}
+
+
+// TODO: Do not wrap the header because I need the
+// struct intact to read the length properly
+// E.g., just wrap if buffer_end - data_start < RTX_MSG_HDR
+int c_insert(C_BUFFER* mailbox, void* buf) {
+
+ RTX_MSG_HDR* hdr = buf;
+ C_METADATA meta = {gp_current_task->tid};
+
+ U32 mailbox_len = mailbox->buffer_end - mailbox->buffer_start;
+ U32 length = hdr->length + sizeof(C_METADATA);
+ if (mailbox_len < length) {
+ return RTX_ERR;
+ }
+
+ // If data_end < data_start, data_end + header->length
+ // must not exceed data_start
+ if (mailbox->data_end < mailbox->data_start) {
+ if (mailbox->data_end + length >= mailbox->data_start) {
+ return RTX_ERR;
+ }
+
+ mem_cpy(&meta, (void*)mailbox->data_end, sizeof(C_METADATA));
+ mem_cpy(buf,
+ (void*)(mailbox->data_end + sizeof(C_METADATA)),
+ length - sizeof(C_METADATA));
+ mailbox->data_end = align_increment(mailbox->data_end, length, 8);
+
+ if (mailbox->data_end >= mailbox->buffer_end - (sizeof(C_METADATA) + sizeof(RTX_MSG_HDR))) {
+ mailbox->data_end = mailbox->buffer_start;
+ }
+
+ return RTX_OK;
+ }
+
+ if (mailbox->data_end + length <= mailbox->buffer_end) {
+ mem_cpy(&meta, (void*)mailbox->data_end, sizeof(C_METADATA));
+ mem_cpy(buf,
+ (void*)(mailbox->data_end + sizeof(C_METADATA)),
+ length - sizeof(C_METADATA));
+ mailbox->data_end = align_increment(mailbox->data_end, length, 8);
+
+ if (mailbox->data_end >= mailbox->buffer_end - (sizeof(C_METADATA) + sizeof(RTX_MSG_HDR))) {
+ mailbox->data_end = mailbox->buffer_start;
+ }
+
+ return RTX_OK;
+ }
+
+ //
+ U32 first_copy_length = mailbox->buffer_end - mailbox->data_end;
+
+
+ mem_cpy(&meta, (void*)mailbox->data_end, sizeof(C_METADATA));
+ mailbox->data_end = align_increment(mailbox->data_end, sizeof(C_METADATA), 8);
+
+ mem_cpy(buf, (void*)mailbox->data_end, sizeof(RTX_MSG_HDR));
+ mailbox->data_end = align_increment(mailbox->data_end, sizeof(RTX_MSG_HDR), 8);
+
+ mem_cpy((char*)buf + sizeof(RTX_MSG_HDR),
+ (void*)mailbox->data_end
+ , first_copy_length - sizeof(C_METADATA) - sizeof(RTX_MSG_HDR));
+ mailbox->data_end = mailbox->buffer_start;
+
+ mem_cpy((char*)buf + first_copy_length - sizeof(C_METADATA),
+ (void*)mailbox->data_end
+ , length - first_copy_length);
+
+ mailbox->data_end = align_increment(mailbox->data_end, length - first_copy_length, 8);
+
+ if (mailbox->data_end >= mailbox->buffer_end - (sizeof(C_METADATA) + sizeof(RTX_MSG_HDR))) {
+ mailbox->data_end = mailbox->buffer_start;
+ }
+
+ return RTX_OK;
+}
+
int k_mbx_create(size_t size) {
#ifdef DEBUG_0
printf("k_mbx_create: size = %d\r\n", size);
#endif /* DEBUG_0 */
+
+ if (gp_current_task->mailbox || size < MIN_MBX_SIZE) {
+ return RTX_ERR;
+ }
+
+ // Memory layout: Buffer_data | Buffer size
+ size_t total_size = size + sizeof(C_BUFFER);
+ void *mem = k_mem_alloc(total_size);
+ if (!mem) {
+ return RTX_ERR;
+ }
+
+
+ // Init of C_BUFFER struct
+ C_BUFFER *buffer = mem;
+ buffer->buffer_start = (U32)buffer + sizeof(C_BUFFER);
+ buffer->buffer_end = (U32)buffer + total_size;
+ buffer->data_start = buffer->buffer_start;
+ buffer->data_end = buffer->data_start;
+
+ gp_current_task->mailbox = (U32)buffer;
+
return 0;
}
@@ -22,14 +151,87 @@ int k_send_msg(task_t receiver_tid, const void *buf) {
#ifdef DEBUG_0
printf("k_send_msg: receiver_tid = %d, buf=0x%x\r\n", receiver_tid, buf);
#endif /* DEBUG_0 */
- return 0;
+ if (receiver_tid >= MAX_TASKS || !buf) {
+ return RTX_ERR;
+ }
+
+ TCB* tcb = &g_tcbs[receiver_tid];
+ // TODO: Verify that a receiver having no mailbox is an error
+ if (tcb->state == DORMANT || !tcb->mailbox) {
+ return RTX_ERR;
+ }
+
+ RTX_MSG_HDR* header = (RTX_MSG_HDR*)buf;
+ if (header->length < MIN_MSG_SIZE) {
+ return RTX_ERR;
+ }
+
+ C_BUFFER* mailbox = (C_BUFFER*)tcb->mailbox;
+ int ret_val = c_insert(mailbox, header);
+
+ if (ret_val == RTX_ERR) {
+ return ret_val;
+ }
+
+ // unblocking procedure
+ if (tcb->state == BLK_MSG) {
+ k_tsk_unblock(tcb);
+ }
+
+ return RTX_OK;
}
int k_recv_msg(task_t *sender_tid, void *buf, size_t len) {
#ifdef DEBUG_0
printf("k_recv_msg: sender_tid = 0x%x, buf=0x%x, len=%d\r\n", sender_tid, buf, len);
#endif /* DEBUG_0 */
- return 0;
+
+ TCB tcb = *gp_current_task;
+ if (!buf || !tcb.mailbox) {
+ return RTX_ERR;
+ }
+
+ C_BUFFER* mailbox = (C_BUFFER*)tcb.mailbox;
+
+ // Prevents the header itself wrapping
+ if (mailbox->data_start >= mailbox->buffer_end - (sizeof(C_METADATA) + sizeof(RTX_MSG_HDR))) {
+ mailbox->data_start = mailbox->buffer_start;
+ }
+
+ // No messages to receive
+ while (mailbox->data_start == mailbox->data_end) {
+ k_tsk_block();
+ }
+
+ C_METADATA * meta = (C_METADATA*) mailbox->data_start;
+ RTX_MSG_HDR* msg = (RTX_MSG_HDR*)(meta + 1);
+ if (len < msg->length) {
+ return RTX_ERR;
+ }
+
+ // Process one message
+ *sender_tid = meta->sender_tid;
+ mailbox->data_start += sizeof(C_METADATA);
+ if (msg->length + mailbox->data_start <= mailbox->buffer_end) {
+ mem_cpy((void*)(mailbox->data_start),
+ buf,
+ msg->length);
+ mailbox->data_start = align_increment(mailbox->data_start, msg->length, 8);
+ } else {
+
+ U32 free_space = mailbox->buffer_end - mailbox->data_start;
+
+ mem_cpy((void*)((U32)mailbox->data_start),
+ buf,
+ free_space);
+ mem_cpy((void*)mailbox->buffer_start,
+ (char*)buf + free_space,
+ msg->length - free_space);
+
+ mailbox->data_start = align_increment(mailbox->buffer_start, msg->length - free_space, 8);
+ }
+
+ return RTX_OK;
}
int k_mbx_ls(task_t *buf, int count) {
diff --git a/manual_code/lab3/IPC/src/kernel/k_task.c b/manual_code/lab3/IPC/src/kernel/k_task.c
index f21ed5f..37475cc 100644
--- a/manual_code/lab3/IPC/src/kernel/k_task.c
+++ b/manual_code/lab3/IPC/src/kernel/k_task.c
@@ -122,6 +122,148 @@ The memory map of the OS image may look like the following:
---------------------------------------------------------------------------*/
+/*
+ *==========================================================================
+ * SCHEDULER VARIABLES
+ *==========================================================================
+ */
+
+static const int h_array_size = MAX_TASKS;
+static TCB* heap[h_array_size];
+static U32 current_size = 0;
+static U32 g_task_count = 0;
+
+/*
+ *===========================================================================
+ * SCHEDULER FUNCTIONS
+ *===========================================================================
+ */
+
+int compare(TCB *t1, TCB* t2) {
+ int result = (*t1).prio < (*t2).prio || ((*t1).prio == (*t2).prio && (*t1).task_count <= (*t2).task_count);
+ // printf("V1: %d, %d, %d - V2: %d, %d, %d - Result: %d\r\n", t1->tid, t1->prio, t1->task_count, t2->tid, t2->prio, t2->task_count, result);
+ return result;
+}
+
+void swap(TCB** t1, TCB** t2) {
+ TCB* t;
+ t = *t1;
+ *t1 = *t2;
+ *t2 = t;
+}
+
+int parent(int i) {
+ return (i > 0 && i < h_array_size) ? (i - 1) / 2 : -1;
+}
+
+int left_child(int i) {
+ return (2*i + 1 < current_size && i >= 0) ? 2*i + 1: -1;
+}
+
+int right_child(int i) {
+ return (2*i + 2 < current_size && i >= 0) ? 2*i + 2 : -1;
+}
+
+void increase_key(TCB* heap[], int i) {
+ while(i >= 0 && parent(i) >= 0 && !compare(heap[parent(i)], heap[i])) {
+ swap(&heap[i], &heap[parent(i)]);
+ i = parent(i);
+ }
+}
+
+void decrease_key(TCB* heap[], int i) {
+ int max_index = i;
+
+ int l = left_child(i);
+
+ if (l > 0 && compare(heap[l], heap[max_index])) {
+ max_index = l;
+ }
+
+ int r = right_child(i);
+
+ if (r > 0 && compare(heap[r], heap[max_index])) {
+ max_index = r;
+ }
+
+ if (i != max_index) {
+ swap(&heap[i], &heap[max_index]);
+ decrease_key(heap, max_index);
+ }
+}
+
+int insert(TCB* heap[], TCB* value) {
+ if (current_size + 1== h_array_size) {
+ return -1;
+ }
+
+ g_task_count += 1;
+ (*value).task_count = g_task_count;
+ heap[current_size] = value;
+ increase_key(heap, current_size);
+ current_size ++;
+ return 0;
+}
+
+int16_t maximum(TCB* heap[]) {
+ return current_size == 0 ? -1 : heap[0]->tid;
+}
+
+int16_t extract_max(TCB* heap[]) {
+ if (current_size == 0) { return 0; }
+
+ int16_t max_value = maximum(heap);
+
+ current_size --;
+ heap[0] = heap[current_size];
+ decrease_key(heap, 0);
+
+ return max_value;
+}
+
+int find_value(TCB* heap[], U8 tid) {
+ int i;
+ for (i = 0; i < current_size; i++) {
+ if (heap[i]->tid == tid) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+void reset_priority(TCB* heap[], U8 tid, U8 priority) {
+ int index = find_value(heap, tid);
+ if (index < 0) { return; }
+
+ TCB v = *heap[index];
+
+ g_task_count += 1;
+ heap[index]->prio = priority;
+ heap[index]->task_count = g_task_count;
+
+ if (compare(heap[index], &v)) {
+ increase_key(heap, index);
+ } else {
+ decrease_key(heap, index);
+ }
+}
+
+void remove_id(TCB* heap[], U8 tid) {
+ if (current_size == 0) { return; }
+
+ int i = find_value(heap, tid);
+
+ if (i < 0) { return; }
+
+ //printf("found id: %d\n", i);
+ heap[i] = heap[0];
+ heap[i]->task_count += 1;
+ increase_key(heap, i);
+ //print_heap(heap, current_size);
+ extract_max(heap);
+}
+
/*
*===========================================================================
* FUNCTIONS
@@ -136,14 +278,37 @@ The memory map of the OS image may look like the following:
*
*****************************************************************************/
+int currently_running() {
+ return gp_current_task && gp_current_task->state == RUNNING;
+}
+
TCB *scheduler(void)
{
- task_t tid = gp_current_task->tid;
- return &g_tcbs[(++tid)%g_num_active_tasks];
+ int16_t tid = maximum(heap);
+ //int16_t tid = extract_max(heap);
+ if (tid < 0) { return gp_current_task; }
-}
+ TCB* current_tcb = gp_current_task;
+ TCB* max_ready_tcb = &g_tcbs[(U8)tid];
+
+ // current task has higher priority
+ if (gp_current_task->state != DORMANT &&
+ gp_current_task->state != BLK_MSG &&
+ current_tcb->prio < max_ready_tcb->prio) {
+
+ return gp_current_task;
+ }
+ gp_current_task = max_ready_tcb;
+ extract_max(heap);
+ if (current_tcb->state != BLK_MSG) {
+ insert(heap, current_tcb);
+ }
+
+ return gp_current_task;
+
+}
/**************************************************************************//**
* @brief initialize all boot-time tasks in the system,
@@ -165,7 +330,7 @@ int k_tsk_init(RTX_TASK_INFO *task_info, int num_tasks)
RTX_TASK_INFO *p_taskinfo = &g_null_task_info;
g_num_active_tasks = 0;
- if (num_tasks > MAX_TASKS) {
+ if (num_tasks > MAX_TASKS - 1) { // num_tasks + null task <= MAX_TASKS
return RTX_ERR;
}
@@ -178,15 +343,33 @@ int k_tsk_init(RTX_TASK_INFO *task_info, int num_tasks)
g_num_active_tasks++;
gp_current_task = p_tcb;
+ // initialize all TCB task ids and states to DORMANT
+ for(int i = 1; i < MAX_TASKS; i++){
+ g_tcbs[i].state = DORMANT;
+ g_tcbs[i].tid = i;
+ }
+
// create the rest of the tasks
- p_taskinfo = task_info;
- for ( int i = 0; i < num_tasks; i++ ) {
- TCB *p_tcb = &g_tcbs[i+1];
- if (k_tsk_create_new(p_taskinfo, p_tcb, i+1) == RTX_OK) {
- g_num_active_tasks++;
+ p_taskinfo = task_info;
+ int numCreated = 0;
+ int tcb_index = 1;
+ while(numCreated != num_tasks){
+ if(p_taskinfo->ptask == kcd_task){ // TODO: Check the Extern for KCD_TASK use function.
+ TCB *p_tcb = &g_tcbs[TID_KCD];
+ if (k_tsk_create_new(p_taskinfo, p_tcb, TID_KCD) == RTX_OK) {
+ g_num_active_tasks++;
+ }
+ } else {
+ TCB *p_tcb = &g_tcbs[tcb_index];
+ if (k_tsk_create_new(p_taskinfo, p_tcb, tcb_index) == RTX_OK) {
+ g_num_active_tasks++;
+ }
+ tcb_index++;
}
p_taskinfo++;
+ numCreated++;
}
+
return RTX_OK;
}
/**************************************************************************//**
@@ -218,7 +401,7 @@ int k_tsk_create_new(RTX_TASK_INFO *p_taskinfo, TCB *p_tcb, task_t tid)
return RTX_ERR;
}
- p_tcb ->tid = tid;
+ p_tcb->tid = tid;
p_tcb->state = READY;
/*---------------------------------------------------------------
@@ -258,8 +441,12 @@ int k_tsk_create_new(RTX_TASK_INFO *p_taskinfo, TCB *p_tcb, task_t tid)
//********************************************************************//
//*** allocate user stack from the user space, not implemented yet ***//
//********************************************************************//
+ p_tcb->u_stack_size = p_taskinfo->u_stack_size;
*(--sp) = (U32) k_alloc_p_stack(tid);
+ // store user stack hi pointer in TCB
+ p_tcb->u_stack_hi = *sp; // user stack hi grows downwards
+
// uR12, uR11, ..., uR0
for ( int j = 0; j < 13; j++ ) {
*(--sp) = 0x0;
@@ -279,6 +466,8 @@ int k_tsk_create_new(RTX_TASK_INFO *p_taskinfo, TCB *p_tcb, task_t tid)
} else {
// kernel thread LR: return to the entry point of the task
*(--sp) = (U32) (p_taskinfo->ptask);
+ p_tcb->u_stack_hi = p_taskinfo->u_stack_size; // user stack hi grows downwards
+ p_tcb->u_stack_size = p_taskinfo->u_stack_size;
}
// kernel stack R0 - R12, 13 registers
@@ -286,7 +475,13 @@ int k_tsk_create_new(RTX_TASK_INFO *p_taskinfo, TCB *p_tcb, task_t tid)
*(--sp) = 0x0;
}
- p_tcb->msp = sp;
+ p_tcb->msp = sp; // store msp in TCB
+ p_tcb->ptask = p_taskinfo->ptask; // store task entry in TCB
+ p_tcb->prio = p_taskinfo->prio; // store priority in TCB
+ p_tcb->priv = p_taskinfo->priv; // store privilege in
+ p_tcb->mailbox = 0;
+
+ insert(heap, p_tcb);
return RTX_OK;
}
@@ -348,8 +543,10 @@ int k_tsk_run_new(void)
// at this point, gp_current_task != NULL and p_tcb_old != NULL
if (gp_current_task != p_tcb_old) {
- gp_current_task->state = RUNNING; // change state of the to-be-switched-in tcb
- p_tcb_old->state = READY; // change state of the to-be-switched-out tcb
+ gp_current_task->state = RUNNING; // change state of the to-be-switched-in tcb
+ if(p_tcb_old->state != DORMANT && p_tcb_old->state != BLK_MSG){
+ p_tcb_old->state = READY; // change state of the to-be-switched-out tcb
+ }
k_tsk_switch(p_tcb_old); // switch stacks
}
@@ -367,6 +564,8 @@ int k_tsk_run_new(void)
*****************************************************************************/
int k_tsk_yield(void)
{
+ g_task_count++;
+ gp_current_task->task_count = g_task_count;
return k_tsk_run_new();
}
@@ -383,15 +582,121 @@ int k_tsk_create(task_t *task, void (*task_entry)(void), U8 prio, U16 stack_size
printf("k_tsk_create: entering...\n\r");
printf("task = 0x%x, task_entry = 0x%x, prio=%d, stack_size = %d\n\r", task, task_entry, prio, stack_size);
#endif /* DEBUG_0 */
- return RTX_OK;
+ // TODO: `k_tsk_create` is non-blocking, but can be preempted by `scheduler`
+ // TODO: check pointers
+ // TODO: error checking additional conditions
+
+ // TID pointer NULL
+ if (task == NULL){
+ return RTX_ERR;
+ }
+
+ // Task entry pointer NULL
+ if (task_entry == NULL){
+ return RTX_ERR;
+ }
+
+ // Maximum number of tasks reached
+ if (g_num_active_tasks == MAX_TASKS){
+ return RTX_ERR;
+ }
+
+ // stack size too small
+ if (stack_size < PROC_STACK_SIZE){
+ return RTX_ERR;
+ }
+
+ // stack size too big
+ size_t ALL_HEAP = 0xFFFFFFFF;
+ size_t suitable_regions = k_mem_count_extfrag(ALL_HEAP) - k_mem_count_extfrag(stack_size);
+ if (!suitable_regions){
+ return RTX_ERR;
+ }
+
+ // stack_size not 8 bytes aligned
+ if (stack_size % 8 != 0){
+ return RTX_ERR;
+ }
+
+ // prio invalid
+ if (prio != HIGH && prio != MEDIUM && prio != LOW && prio != LOWEST){
+ return RTX_ERR;
+ }
+
+ RTX_TASK_INFO task_info;
+ TCB * tcb = NULL;
+
+ // linear traverse to find free TID in g_tcbs;
+ for (int i=0; i < MAX_TASKS; i++){
+ // get dormant TCB
+ if(g_tcbs[i].state == DORMANT){
+ tcb = &g_tcbs[i];
+ break;
+ }
+ }
+
+ // get TID and store in buffer
+ *task = tcb->tid;
+
+ // fill in task_info
+ task_info.prio = prio;
+ task_info.priv = 0;
+ task_info.u_stack_size = stack_size;
+ task_info.ptask = task_entry;
+
+ // call k_tsk_create_new
+ if (k_tsk_create_new(&task_info, tcb, *task) == RTX_ERR){
+ return RTX_ERR;
+ }
+
+ g_num_active_tasks++;
+ //scheduler(); do we need to call?
+
+// if (currently_running()) {
+// k_tsk_yield();
+// } else {
+// return RTX_ERR;
+// }
+
+
+ return RTX_OK;
}
void k_tsk_exit(void)
{
+
#ifdef DEBUG_0
printf("k_tsk_exit: entering...\n\r");
#endif /* DEBUG_0 */
+
+ gp_current_task->state = DORMANT;
+
+ TCB* p_tcb_old = gp_current_task;
+ gp_current_task = scheduler();
+
+ if(p_tcb_old->priv == 0){
+ k_mem_dealloc((void *) ((U32)p_tcb_old->u_stack_hi - p_tcb_old->u_stack_size));
+ }
+
+ if (p_tcb_old->mailbox) {
+ k_mem_dealloc((void*)p_tcb_old->mailbox);
+ }
+
+ g_num_active_tasks--;
+ remove_id(heap, p_tcb_old->tid);
+
+ if ( gp_current_task == NULL ) {
+ gp_current_task = p_tcb_old; // revert back to the old task
+ return;
+ }
+
+ // at this point, gp_current_task != NULL and p_tcb_old != NULL
+ if (gp_current_task != p_tcb_old) {
+ gp_current_task->state = RUNNING; // change state of the to-be-switched-in tcb
+ k_tsk_switch(p_tcb_old); // switch stacks
+ }
+
return;
}
@@ -401,7 +706,48 @@ int k_tsk_set_prio(task_t task_id, U8 prio)
printf("k_tsk_set_prio: entering...\n\r");
printf("task_id = %d, prio = %d.\n\r", task_id, prio);
#endif /* DEBUG_0 */
- return RTX_OK;
+
+ // TODO: This function never blocks, but can be preempted. what does this mean?
+ // TODO: if try to set null task to prio PRIO_NULL, do I let it or error?
+
+ // prio invalid or PRIO_NULL
+ if (prio != HIGH && prio != MEDIUM && prio != LOW && prio != LOWEST){
+ return RTX_ERR;
+ }
+
+ // dormant TCB
+ if (g_tcbs[task_id].state == DORMANT){
+ return RTX_ERR;
+ }
+
+ if (prio == g_tcbs[task_id].prio) {
+ return RTX_OK;
+ }
+
+ // valid TID
+ if (task_id > 0 && task_id < MAX_TASKS){
+ // user-mode task can change prio of any user-mode task
+ // user-mode task cannot change prio of kernel task
+ // kernel task can change prio of any user-mode or kernel task
+
+ if(gp_current_task->priv == 1){
+ g_tcbs[task_id].prio = prio;
+ } else {
+ if(g_tcbs[task_id].priv == 1){
+ return RTX_ERR;
+ } else {
+ g_tcbs[task_id].prio = prio;
+ }
+ }
+
+ reset_priority(heap, task_id, prio);
+
+ k_tsk_yield();
+
+ return RTX_OK;
+ }else{
+ return RTX_ERR;
+ }
}
int k_tsk_get(task_t task_id, RTX_TASK_INFO *buffer)
@@ -410,22 +756,41 @@ int k_tsk_get(task_t task_id, RTX_TASK_INFO *buffer)
printf("k_tsk_get: entering...\n\r");
printf("task_id = %d, buffer = 0x%x.\n\r", task_id, buffer);
#endif /* DEBUG_0 */
+
+ // error checking
if (buffer == NULL) {
return RTX_ERR;
}
- /* The code fills the buffer with some fake task information.
- You should fill the buffer with correct information */
- buffer->tid = task_id;
- buffer->prio = 99;
- buffer->state = MEDIUM;
- buffer->priv = 0;
- buffer->ptask = 0x0;
- buffer->k_sp = 0xBEEFDEAD;
- buffer->k_stack_size = KERN_STACK_SIZE;
- buffer->u_sp = 0xDEADBEEF;
- buffer->u_stack_size = 0x200;
-
- return RTX_OK;
+ // Dormant TCB
+ if (g_tcbs[task_id].state == DORMANT){
+ return RTX_ERR;
+ }
+
+ // valid TID excluding 0
+ if (task_id > 0 && task_id < MAX_TASKS){
+ buffer->tid = task_id;
+ buffer->prio = g_tcbs[task_id].prio;
+ buffer->state = g_tcbs[task_id].state;
+ buffer->priv = g_tcbs[task_id].priv;
+ buffer->ptask = g_tcbs[task_id].ptask;
+ buffer->k_stack_hi = (U32) (&g_k_stacks[task_id+1]); // kernel stack hi grows downwards
+ buffer->k_stack_size = KERN_STACK_SIZE;
+ buffer->u_stack_hi = g_tcbs[task_id].u_stack_hi;
+ buffer->u_stack_size = g_tcbs[task_id].u_stack_size;
+
+ buffer->u_sp = * (U32*)((U32) g_tcbs[task_id].msp + 108);
+
+ if (task_id == gp_current_task->tid){
+ int regVal = __current_sp(); // store value of SP register in regVal
+ buffer->k_sp = regVal;
+ }else{
+ buffer->k_sp = (U32) g_tcbs[task_id].msp;
+ }
+ return RTX_OK;
+
+ }else{
+ return RTX_ERR;
+ }
}
int k_tsk_ls(task_t *buf, int count){
@@ -435,6 +800,55 @@ int k_tsk_ls(task_t *buf, int count){
return 0;
}
+void k_tsk_block(void) {
+ if (gp_current_task->state != RUNNING) {
+ return;
+ }
+
+ gp_current_task->state = BLK_MSG;
+ k_tsk_run_new();
+}
+
+void k_tsk_unblock (TCB *task) {
+ if (!task) { return; }
+
+ if (task->state != BLK_MSG) {
+ return;
+ }
+
+ task->state = READY;
+
+ // Unblocked task has higher priority
+ if (compare(task, gp_current_task)) {
+ // Preempt current task
+
+ TCB *p_tcb_old = NULL;
+
+ p_tcb_old = gp_current_task;
+ gp_current_task = task;
+
+ // We move this preempted task to the front of the ready queue
+ // We do not change the fifo counter of the preempted task
+ // So it should remain at the front
+ insert(heap, p_tcb_old);
+
+ // at this point, gp_current_task != NULL and p_tcb_old != NULL
+ if (gp_current_task != p_tcb_old) {
+ gp_current_task->state = RUNNING; // change state of the to-be-switched-in tcb
+ p_tcb_old->state = READY; // change state of the to-be-switched-out tcb
+ k_tsk_switch(p_tcb_old); // switch stacks
+ }
+ } else {
+ // Add unblocked lower priority task to the back of the ready queue
+ // We increment fifo counter so it explicitly goes to the back
+ g_task_count++;
+ task->task_count = g_task_count;
+ insert(heap, task);
+ }
+
+ return;
+}
+
/*
*===========================================================================
* TO BE IMPLEMETED IN LAB4
diff --git a/manual_code/lab3/IPC/src/kernel/k_task.h b/manual_code/lab3/IPC/src/kernel/k_task.h
index 27d83ad..2b50c85 100644
--- a/manual_code/lab3/IPC/src/kernel/k_task.h
+++ b/manual_code/lab3/IPC/src/kernel/k_task.h
@@ -60,7 +60,7 @@ extern TCB *gp_current_task;
*/
extern void task_null (void);
-
+extern void kcd_task (void);
// Implemented by Starter Code
@@ -81,5 +81,7 @@ int k_tsk_get (task_t task_id, RTX_TASK_INFO *buffer);
int k_tsk_create_rt (task_t *tid, TASK_RT *task, RTX_MSG_HDR *msg_hdr, U32 num_msgs);
void k_tsk_done_rt (void);
void k_tsk_suspend (struct timeval_rt *tv);
+void k_tsk_block (void);
+void k_tsk_unblock (TCB* task);
#endif // ! K_TASK_H_
diff --git a/manual_code/lab3/IPC/src/kernel/main_svc_cw.c b/manual_code/lab3/IPC/src/kernel/main_svc_cw.c
index 99caeae..eb946b9 100644
--- a/manual_code/lab3/IPC/src/kernel/main_svc_cw.c
+++ b/manual_code/lab3/IPC/src/kernel/main_svc_cw.c
@@ -54,6 +54,7 @@ extern void __ch_MODE (U32 mode);
extern void __atomic_on(void);
extern void __atomic_off(void);
+
void task_null (void)
{
while (1) {
@@ -66,10 +67,14 @@ void task_null (void)
}
}
+#define num_tasks 4
+
int main()
{
+
static RTX_SYS_INFO sys_info;
- static RTX_TASK_INFO task_info[3];
+ static RTX_TASK_INFO task_info[num_tasks];
+
char mode = 0;
// CMSIS system initialization
@@ -84,7 +89,7 @@ int main()
printf("mode = 0x%x\r\n", mode);
// System and Task set up by auto testing software
- if (ae_init(&sys_info, task_info, 3) != RTX_OK) {
+ if (ae_init(&sys_info, task_info, num_tasks) != RTX_OK) {
printf("RTX INIT FAILED\r\n");
return RTX_ERR;
}
@@ -92,10 +97,9 @@ int main()
// start the RTX and built-in tasks
if (mode == MODE_SVC) {
gp_current_task = NULL;
- k_rtx_init(task_info, 3);
+ k_rtx_init(task_info, num_tasks);
}
-
interrupt_init();
task_null();
diff --git a/manual_code/lab4/.project b/manual_code/lab4/.project
new file mode 100644
index 0000000..49bfa4c
--- /dev/null
+++ b/manual_code/lab4/.project
@@ -0,0 +1,11 @@
+
+
+ lab4
+
+
+
+
+
+
+
+
diff --git a/manual_code/lab4/RT/.settings/language.settings.xml b/manual_code/lab4/RT/.settings/language.settings.xml
index 13f32ba..f702a90 100644
--- a/manual_code/lab4/RT/.settings/language.settings.xml
+++ b/manual_code/lab4/RT/.settings/language.settings.xml
@@ -11,7 +11,7 @@
-
+
@@ -33,7 +33,7 @@
-
+
diff --git a/manual_code/lab4/RT/DE1-lab4.launch b/manual_code/lab4/RT/DE1-lab4.launch
index fc0154f..4c0ab9b 100644
--- a/manual_code/lab4/RT/DE1-lab4.launch
+++ b/manual_code/lab4/RT/DE1-lab4.launch
@@ -60,11 +60,11 @@
-
+
-
+
@@ -74,11 +74,11 @@
-
+
-
+
diff --git a/manual_code/lab4/RT/TM1.launch b/manual_code/lab4/RT/TM1.launch
index 691e2b3..a4209e4 100644
--- a/manual_code/lab4/RT/TM1.launch
+++ b/manual_code/lab4/RT/TM1.launch
@@ -30,9 +30,9 @@
-
+
-
+
@@ -63,7 +63,7 @@
-
+
diff --git a/manual_code/lab4/RT/src/INC/common_ext.h b/manual_code/lab4/RT/src/INC/common_ext.h
index 88eb0d6..0e7f8fc 100644
--- a/manual_code/lab4/RT/src/INC/common_ext.h
+++ b/manual_code/lab4/RT/src/INC/common_ext.h
@@ -58,6 +58,10 @@
*===========================================================================
*/
+typedef struct rtx_msg_char {
+ RTX_MSG_HDR hdr;
+ char data; /**> Sender tid */
+} RTX_MSG_CHAR;
/*
*===========================================================================
diff --git a/manual_code/lab4/RT/src/app/ae.c b/manual_code/lab4/RT/src/app/ae.c
index 8b36843..89f3239 100644
--- a/manual_code/lab4/RT/src/app/ae.c
+++ b/manual_code/lab4/RT/src/app/ae.c
@@ -101,22 +101,57 @@ int ae_set_sys_info(RTX_SYS_INFO *sys_info) {
void ae_set_task_info(RTX_TASK_INFO *tasks, int num_tasks) {
- if (tasks == NULL) {
- return;
- }
-
- for (int i = 0; i < num_tasks; i++) {
- tasks[i].u_stack_size = 0x200;
- tasks[i].prio = 100;
- tasks[i].priv = 0;
- }
- tasks[0].priv = 1;
- tasks[0].ptask = &ktask1;
- tasks[1].ptask = &utask1;
- tasks[2].ptask = &utask2;
- return;
+ if (tasks == NULL) {
+ return;
+ }
+
+ // for (int i = 0; i < num_tasks; i++ ) {
+ // tasks[i].u_stack_size = 0x0;
+ // tasks[i].prio = HIGH;
+ // tasks[i].priv = 1;
+ // }
+
+ tasks[0].u_stack_size = 0x200;
+ tasks[0].ptask = &kcd_task;
+ tasks[0].prio = MEDIUM;
+ tasks[0].priv = 0;
+
+ tasks[1].u_stack_size = 0x200;
+ tasks[1].ptask = &kcd_waiting;
+ tasks[1].prio = LOW;
+ tasks[1].priv = 0;
+
+ tasks[2].u_stack_size = 0x200;
+ tasks[2].ptask = &kcd_reg_and_exit;
+ tasks[2].prio = HIGH;
+ tasks[2].priv = 0;
+
+ tasks[3].u_stack_size = 0x200;
+ tasks[3].ptask = &kcd_receive_and_print;
+ tasks[3].prio = MEDIUM;
+ tasks[3].priv = 0;
+
+ return;
}
+//void ae_set_task_info(RTX_TASK_INFO *tasks, int num_tasks) {
+//
+// if (tasks == NULL) {
+// return;
+// }
+//
+// for (int i = 0; i < num_tasks; i++) {
+// tasks[i].u_stack_size = 0x200;
+// tasks[i].prio = 100;
+// tasks[i].priv = 0;
+// }
+// tasks[0].priv = 1;
+// tasks[0].ptask = &ktask1;
+// tasks[1].ptask = &utask1;
+// tasks[2].ptask = &utask2;
+// return;
+//}
+
/* only used in LAB1 */
#ifdef AE_LAB1
int ae_start(void) {
diff --git a/manual_code/lab4/RT/src/app/ae_usr_tasks.c b/manual_code/lab4/RT/src/app/ae_usr_tasks.c
index f6a8d42..32dbf65 100644
--- a/manual_code/lab4/RT/src/app/ae_usr_tasks.c
+++ b/manual_code/lab4/RT/src/app/ae_usr_tasks.c
@@ -41,6 +41,35 @@
#include "printf.h"
+/**
+ * C++ version 0.4 char* style "itoa":
+ * Written by Luk�s Chmela
+ * Released under GPLv3.
+ */
+char* itoa(int value, char* result, int base) {
+ // check that the base if valid
+ if (base < 2 || base > 36) { *result = '\0'; return result; }
+
+ char* ptr = result, *ptr1 = result, tmp_char;
+ int tmp_value;
+
+ do {
+ tmp_value = value;
+ value /= base;
+ *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)];
+ } while ( value );
+
+ // Apply negative sign
+ if (tmp_value < 0) *ptr++ = '-';
+ *ptr-- = '\0';
+ while(ptr1 < ptr) {
+ tmp_char = *ptr;
+ *ptr--= *ptr1;
+ *ptr1++ = tmp_char;
+ }
+ return result;
+}
+
/**
* @brief: a dummy task1
*/
@@ -90,6 +119,95 @@ void utask2(void)
// tsk_exit();
}
+void kcd_reg_and_exit(void){
+ mbx_create(KCD_MBX_SIZE);
+ RTX_MSG_CHAR msg;
+ msg.hdr.length = sizeof(RTX_MSG_HDR) + 1;
+ msg.hdr.type = KCD_REG;
+ msg.data = 'q';
+ if(send_msg(TID_KCD, &msg) == RTX_OK){
+ SER_PutStr(0, "Sent Reg Msg");
+ }
+ tsk_exit();
+}
+
+void kcd_receive_and_print(void){
+ mbx_create(KCD_MBX_SIZE);
+ task_t sender_tid;
+ char* recv_buf = mem_alloc(KCD_MBX_SIZE);
+
+ RTX_MSG_CHAR msg;
+ msg.hdr.length = sizeof(RTX_MSG_HDR) + 1;
+ msg.hdr.type = KCD_REG;
+ msg.data = 'w';
+ send_msg(TID_KCD, &msg);
+
+ U8 flag = 0;
+
+ while(1){
+ int ret_val = recv_msg(&sender_tid, recv_buf, KCD_MBX_SIZE);
+ SER_PutStr(0, "kcd_receive_and_print: ");
+
+ if(ret_val != RTX_OK){
+ SER_PutStr(0, "Sike\r\n");
+ continue;
+ }
+
+ RTX_MSG_HDR* msg_hdr = (RTX_MSG_HDR*)(recv_buf);
+
+ if (msg_hdr->type != KCD_CMD){
+ // ignore message if data more than 1 char
+ SER_PutStr(0, " Not a CMD message\r\n");
+ continue;
+ }
+
+ *(recv_buf + ((RTX_MSG_HDR*)recv_buf)->length) = '\0';
+ SER_PutStr(0, recv_buf + sizeof(RTX_MSG_HDR));
+ SER_PutStr(0, "\r\n");
+
+ if (flag == 0) {
+ flag = 1;
+ msg.hdr.length = sizeof(RTX_MSG_HDR) + 1;
+ msg.hdr.type = KCD_REG;
+ msg.data = 'q';
+ send_msg(TID_KCD, &msg);
+ } else if (flag == 1) {
+ flag = 2;
+ msg.hdr.length = sizeof(RTX_MSG_HDR) + 1;
+ msg.hdr.type = KCD_REG;
+ msg.data = '!';
+ send_msg(TID_KCD, &msg);
+ } else if (flag == 2) {
+ flag = 3;
+ msg.hdr.length = sizeof(RTX_MSG_HDR) + 2;
+ msg.hdr.type = KCD_REG;
+ msg.data = '!';
+ send_msg(TID_KCD, &msg);
+ }
+
+ }
+}
+
+void kcd_waiting(void){
+ mbx_create(KCD_MBX_SIZE);
+
+ RTX_MSG_CHAR msg;
+ msg.hdr.length = sizeof(RTX_MSG_HDR) + 1;
+ msg.hdr.type = KCD_REG;
+ msg.data = 'e';
+
+ send_msg(TID_KCD, &msg);
+
+ while(1){
+ U32 counter = 0;
+ for(U32 timer = 0xFFFFFF; timer != 0; timer--){
+ counter++;
+ }
+ SER_PutStr(0, "Uno Cycle\r\n");
+ tsk_yield();
+ }
+}
+
/*
*===========================================================================
* END OF FILE
diff --git a/manual_code/lab4/RT/src/app/ae_usr_tasks.h b/manual_code/lab4/RT/src/app/ae_usr_tasks.h
index 0643a10..f270f65 100644
--- a/manual_code/lab4/RT/src/app/ae_usr_tasks.h
+++ b/manual_code/lab4/RT/src/app/ae_usr_tasks.h
@@ -42,6 +42,10 @@
void utask1(void);
void utask2(void);
+void kcd_waiting(void);
+void kcd_reg_and_exit(void);
+void kcd_receive_and_print(void);
+
#endif // ! USR_TASK_H_
/*
diff --git a/manual_code/lab4/RT/src/app/kcd_task.c b/manual_code/lab4/RT/src/app/kcd_task.c
index f50b577..e562537 100644
--- a/manual_code/lab4/RT/src/app/kcd_task.c
+++ b/manual_code/lab4/RT/src/app/kcd_task.c
@@ -1,6 +1,207 @@
+#include "rtx.h"
+#include "Serial.h"
+#include "printf.h"
+extern void kcd_task(void);
+
/* The KCD Task Template File */
+U8 charIsValid(U8 character){
+ if (character > 47 && character < 58){
+ return 1;
+ } else if (character > 64 && character < 91){
+ return 1;
+ } else if (character > 96 && character < 123){
+ return 1;
+ } else if (character == 13 || character == 37){
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+U8 charIsAlphaNum(U8 character){
+ if (character > 47 && character < 58){
+ // 0-9 = 48-57
+ return 1;
+ }else if (character > 64 && character < 91){
+ // A-Z = 65-90
+ return 1;
+ }else if (character > 96 && character < 123){
+ // a-z = 97-122
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+U8 charToIndex(U8 character){
+ if (character > 47 && character < 58){
+ // 0-9 = 48-57
+ return character - 48;
+ }else if (character > 64 && character < 91){
+ // A-Z = 65-90
+ return character - 55;
+ }else if (character > 96 && character < 123){
+ // a-z = 97-122
+ return character - 61;
+ } else {
+ return 255;
+ }
+}
+
void kcd_task(void)
{
- /* not implemented yet */
+ mbx_create(KCD_MBX_SIZE);
+ task_t sender_tid;
+ char* recv_buf = mem_alloc(KCD_MBX_SIZE);
+
+ // 62 valid option commands for registration
+ U8 cmd_reg[62];
+ for (int i=0; i<62; i++){
+ cmd_reg[i] = 0;
+ }
+
+ // KEY_IN queue
+ U8 cmd_queue[64];
+ for (int i=0; i<64; i++){
+ cmd_queue[i] = 0;
+ }
+
+ U8 cmd_queue_counter = 0;
+ U8 cmd_len = 0;
+ U8 cmd_invalid = 0;
+
+ while(1) {
+ int ret_val = recv_msg(&sender_tid, recv_buf, KCD_MBX_SIZE);
+
+ if(ret_val != RTX_OK){
+ continue;
+ }
+
+ RTX_MSG_HDR* msg_hdr = (RTX_MSG_HDR*)(recv_buf);
+
+ if (msg_hdr->length != sizeof(RTX_MSG_HDR) + 1){
+ // ignore message if data more than 1 char
+ // SER_PutStr(0, "KCD_IN: Unexpected message length\r\n");
+ continue;
+ }
+
+ // process KCD_REG or KEY_IN type messages
+ if (msg_hdr->type == KCD_REG){
+ // command registration
+
+ RTX_MSG_CHAR * msg = (RTX_MSG_CHAR*) recv_buf;
+
+ // get command identifier
+ U8 cmd_id = msg->data;
+
+ if (charIsAlphaNum(cmd_id) == 0){
+ // invalid cmd_id
+ // SER_PutStr(0, "Reg: Invalid Command ID\r\n");
+ continue;
+ }
+
+ // convert cmd_id to ascii and offset
+ U8 index = charToIndex(cmd_id);
+
+ // store it in cmd_reg
+ cmd_reg[index] = sender_tid;
+ // SER_PutStr(0, "Reg: Successfully registered something\r\n");
+
+ } else if (msg_hdr->type == KEY_IN){
+ // Keyboard Input
+
+ // get command char
+ RTX_MSG_CHAR * msg = (RTX_MSG_CHAR*) recv_buf;
+ U8 cmd_char = msg->data;
+ cmd_len++;
+
+ // first character should be %
+ if ( (cmd_len == 1 && cmd_char != 37) || (cmd_len != 1 && cmd_char == 37) ){
+ cmd_invalid = 1;
+ // SER_PutStr(0, "Key In: Percent not in the right place\r\n");
+ }
+
+ // command length (including % and enter) larger than 64 bytes
+ if (cmd_len > 64){
+ cmd_invalid = 1;
+ // SER_PutStr(0, "Key In: Command Length too long\r\n");
+ }
+
+ // TODO: write charIsValid(), figure out what is a valid char?
+ if (!charIsValid(cmd_char)){
+ cmd_invalid = 1;
+ // SER_PutStr(0, "Key In: Invalid Character Detected\r\n");
+ }
+
+ if (cmd_invalid == 0){
+ // valid command
+ // if enter: dequeue and create string
+ if (cmd_char == 13){
+ // populate command message buffer
+
+ void* msg = mem_alloc(sizeof(RTX_MSG_HDR) + cmd_len - 2);
+ RTX_MSG_HDR* hdr = msg;
+
+ //RTX_MSG_HDR *cmd_msg;
+ hdr->type = KCD_CMD;
+ hdr->length = sizeof(RTX_MSG_HDR) + cmd_len - 2; // exclude % and enter
+
+ // TODO: verify if string create works
+ for(int i=0; i MAX_TASKS){
+ SER_PutStr(0, "Command cannot be processed\r\n");
+ // SER_PutStr(0, "Key In: Unregistered cmd_id OR invalid TID\r\n");
+ }else{
+
+ // send message to registered task id
+ int msg_sent = send_msg(recv_tid, msg);
+
+ if (msg_sent == RTX_ERR){
+ SER_PutStr(0, "Command cannot be processed\r\n");
+ // SER_PutStr(0, "Key In: Message failed to send\r\n");
+ }
+ }
+
+ // reset
+ for(int i=0; i<64; i++){
+ cmd_queue[i] = 0;
+ }
+ cmd_queue_counter = 0;
+ cmd_len = 0;
+ cmd_invalid = 0;
+
+ }else{
+ // enqueue KEY_IN msg data
+ cmd_queue[cmd_queue_counter] = cmd_char;
+ cmd_queue_counter++;
+ }
+ }else{
+ // invalid command
+ // if enter: dequeue and output failure message
+ if (cmd_char == 13){
+ SER_PutStr(0, "Invalid Command\r\n");
+
+ // reset
+ for(int i=0; i<64; i++){
+ cmd_queue[i] = 0;
+ }
+ cmd_queue_counter = 0;
+ cmd_len = 0;
+ cmd_invalid = 0;
+ }
+ }
+ }
+ }
}
diff --git a/manual_code/lab4/RT/src/kernel/HAL_CA.c b/manual_code/lab4/RT/src/kernel/HAL_CA.c
index 39f4c02..e54d473 100644
--- a/manual_code/lab4/RT/src/kernel/HAL_CA.c
+++ b/manual_code/lab4/RT/src/kernel/HAL_CA.c
@@ -39,6 +39,7 @@
*****************************************************************************/
#include "common.h"
+#include "common_ext.h"
#include "k_inc.h"
#include "k_HAL_CA.h"
#include "interrupt.h"
@@ -46,6 +47,7 @@
#include "k_task.h"
#include "timer.h"
#include "printf.h"
+#include "k_msg.h"
#pragma push
#pragma arm
@@ -240,7 +242,18 @@ void c_IRQ_Handler(void)
while(UART0_GetRxDataStatus()) // read while Data Ready is valid
{
char c = UART0_GetRxData(); // would also clear the interrupt if last character is read
- SER_PutChar(1, c); // display back
+ if( (U8) c == 13){
+ SER_PutStr(1, "\r\n");
+ } else {
+ SER_PutChar(1, c); // display back
+ }
+
+ RTX_MSG_CHAR msg;
+ msg.hdr.length = sizeof(RTX_MSG_HDR) + 1;
+ msg.hdr.type = KEY_IN;
+ msg.data = c;
+
+ k_send_msg(TID_KCD, &msg);
}
switch_flag = 1;
}
diff --git a/manual_code/lab4/RT/src/kernel/k_inc.h b/manual_code/lab4/RT/src/kernel/k_inc.h
index 777f24b..a349a47 100644
--- a/manual_code/lab4/RT/src/kernel/k_inc.h
+++ b/manual_code/lab4/RT/src/kernel/k_inc.h
@@ -67,8 +67,13 @@ typedef struct tcb {
U32 *msp; /**> msp of the task, TCB_MSP_OFFSET = 4 */
U8 tid; /**> task id */
U8 prio; /**> Execution priority */
+ U32 task_count; /**> Update counter used for FIFO scheduling */
U8 state; /**> task state */
U8 priv; /**> = 0 unprivileged, =1 privileged */
+ U32 u_stack_hi; // user-space stack start
+ U16 u_stack_size; // user-space stack size
+ void (*ptask)(); // task entry address
+ U32 mailbox; // pointer to mailbox
} TCB;
/*
diff --git a/manual_code/lab4/RT/src/kernel/k_msg.c b/manual_code/lab4/RT/src/kernel/k_msg.c
index 2416a3e..0725e2d 100644
--- a/manual_code/lab4/RT/src/kernel/k_msg.c
+++ b/manual_code/lab4/RT/src/kernel/k_msg.c
@@ -6,15 +6,144 @@
*/
#include "k_msg.h"
+#include "common_ext.h"
#ifdef DEBUG_0
#include "printf.h"
+#include "Serial.h"
#endif /* ! DEBUG_0 */
+// data_end can be less than data_start. Then the data wraps from
+// start_data through buffer_end, back to buffer_start, to data_end.
+typedef struct circular_buffer {
+ U32 buffer_start; // Start of buffer in memory
+ U32 buffer_end; // End of buffer in memory
+ U32 data_start; // Start of "valid data" in memory
+ U32 data_end; // End of "valid data" in memory.
+} __attribute__((aligned(8)))C_BUFFER;
+
+typedef struct c_metadata {
+ task_t sender_tid;
+} __attribute__((aligned(8)))C_METADATA;
+
+void mem_cpy(void* source, void* dest, size_t len) {
+ for (int i = 0; i < len; i++) {
+ *((char*)dest+i) = *((char*)source+i);
+ }
+}
+
+// Prereq: addr is aligned
+U32 align_increment(U32 addr, U32 increment, U32 alignment) {
+ if ((addr + increment) % alignment == 0) {
+ return addr + increment;
+ }
+
+ return addr + increment + (alignment - increment % alignment);
+}
+
+
+// TODO: Do not wrap the header because I need the
+// struct intact to read the length properly
+// E.g., just wrap if buffer_end - data_start < RTX_MSG_HDR
+int c_insert(C_BUFFER* mailbox, void* buf) {
+
+ RTX_MSG_HDR* hdr = buf;
+ C_METADATA meta = {gp_current_task->tid};
+
+ U32 mailbox_len = mailbox->buffer_end - mailbox->buffer_start;
+ U32 length = hdr->length + sizeof(C_METADATA);
+ if (mailbox_len < length) {
+ return RTX_ERR;
+ }
+
+ // If data_end < data_start, data_end + header->length
+ // must not exceed data_start
+ if (mailbox->data_end < mailbox->data_start) {
+ if (mailbox->data_end + length >= mailbox->data_start) {
+ return RTX_ERR;
+ }
+
+ mem_cpy(&meta, (void*)mailbox->data_end, sizeof(C_METADATA));
+ mem_cpy(buf,
+ (void*)(mailbox->data_end + sizeof(C_METADATA)),
+ length - sizeof(C_METADATA));
+ mailbox->data_end = align_increment(mailbox->data_end, length, 8);
+
+ if (mailbox->data_end >= mailbox->buffer_end - (sizeof(C_METADATA) + sizeof(RTX_MSG_HDR))) {
+ mailbox->data_end = mailbox->buffer_start;
+ }
+
+ return RTX_OK;
+ }
+
+ if (mailbox->data_end + length <= mailbox->buffer_end) {
+ mem_cpy(&meta, (void*)mailbox->data_end, sizeof(C_METADATA));
+ mem_cpy(buf,
+ (void*)(mailbox->data_end + sizeof(C_METADATA)),
+ length - sizeof(C_METADATA));
+ mailbox->data_end = align_increment(mailbox->data_end, length, 8);
+
+ if (mailbox->data_end >= mailbox->buffer_end - (sizeof(C_METADATA) + sizeof(RTX_MSG_HDR))) {
+ mailbox->data_end = mailbox->buffer_start;
+ }
+
+ return RTX_OK;
+ }
+
+ //
+ U32 first_copy_length = mailbox->buffer_end - mailbox->data_end;
+
+
+ mem_cpy(&meta, (void*)mailbox->data_end, sizeof(C_METADATA));
+ mailbox->data_end = align_increment(mailbox->data_end, sizeof(C_METADATA), 8);
+
+ mem_cpy(buf, (void*)mailbox->data_end, sizeof(RTX_MSG_HDR));
+ mailbox->data_end = align_increment(mailbox->data_end, sizeof(RTX_MSG_HDR), 8);
+
+ mem_cpy((char*)buf + sizeof(RTX_MSG_HDR),
+ (void*)mailbox->data_end
+ , first_copy_length - sizeof(C_METADATA) - sizeof(RTX_MSG_HDR));
+ mailbox->data_end = mailbox->buffer_start;
+
+ mem_cpy((char*)buf + first_copy_length - sizeof(C_METADATA),
+ (void*)mailbox->data_end
+ , length - first_copy_length);
+
+ mailbox->data_end = align_increment(mailbox->data_end, length - first_copy_length, 8);
+
+ if (mailbox->data_end >= mailbox->buffer_end - (sizeof(C_METADATA) + sizeof(RTX_MSG_HDR))) {
+ mailbox->data_end = mailbox->buffer_start;
+ }
+
+ return RTX_OK;
+}
+
int k_mbx_create(size_t size) {
#ifdef DEBUG_0
printf("k_mbx_create: size = %d\r\n", size);
#endif /* DEBUG_0 */
+
+ if (gp_current_task->mailbox || size < MIN_MBX_SIZE) {
+ return RTX_ERR;
+ }
+
+ // Memory layout: Buffer_data | Buffer size
+ size_t total_size = size + sizeof(C_BUFFER);
+ void *mem = k_mem_alloc(total_size);
+ if (!mem) {
+ return RTX_ERR;
+ }
+
+
+ // Init of C_BUFFER struct
+ C_BUFFER *buffer = mem;
+ buffer->buffer_start = (U32)buffer + sizeof(C_BUFFER);
+ buffer->buffer_end = (U32)buffer + total_size;
+ buffer->data_start = buffer->buffer_start;
+ buffer->data_end = buffer->data_start;
+
+ gp_current_task->mailbox = (U32)buffer;
+
return 0;
}
@@ -22,26 +151,101 @@ int k_send_msg(task_t receiver_tid, const void *buf) {
#ifdef DEBUG_0
printf("k_send_msg: receiver_tid = %d, buf=0x%x\r\n", receiver_tid, buf);
#endif /* DEBUG_0 */
- return 0;
+ if (receiver_tid >= MAX_TASKS || !buf) {
+ return RTX_ERR;
+ }
+
+ TCB* tcb = &g_tcbs[receiver_tid];
+ // TODO: Verify that a receiver having no mailbox is an error
+ if (tcb->state == DORMANT || !tcb->mailbox) {
+ return RTX_ERR;
+ }
+
+ RTX_MSG_HDR* header = (RTX_MSG_HDR*)buf;
+ if (header->length < MIN_MSG_SIZE) {
+ return RTX_ERR;
+ }
+
+ C_BUFFER* mailbox = (C_BUFFER*)tcb->mailbox;
+ int ret_val = c_insert(mailbox, header);
+
+ if (ret_val == RTX_ERR) {
+ return ret_val;
+ }
+
+ // unblocking procedure
+ if (tcb->state == BLK_MSG) {
+ k_tsk_unblock(tcb);
+ }
+
+ return RTX_OK;
}
int k_recv_msg(task_t *sender_tid, void *buf, size_t len) {
#ifdef DEBUG_0
printf("k_recv_msg: sender_tid = 0x%x, buf=0x%x, len=%d\r\n", sender_tid, buf, len);
#endif /* DEBUG_0 */
- return 0;
+
+ TCB tcb = *gp_current_task;
+ if (!buf || !tcb.mailbox) {
+ return RTX_ERR;
+ }
+
+ C_BUFFER* mailbox = (C_BUFFER*)tcb.mailbox;
+
+ // Prevents the header itself wrapping
+ if (mailbox->data_start >= mailbox->buffer_end - (sizeof(C_METADATA) + sizeof(RTX_MSG_HDR))) {
+ mailbox->data_start = mailbox->buffer_start;
+ }
+
+ // No messages to receive
+ while (mailbox->data_start == mailbox->data_end) {
+ k_tsk_block();
+ }
+
+ C_METADATA * meta = (C_METADATA*) mailbox->data_start;
+ RTX_MSG_HDR* msg = (RTX_MSG_HDR*)(meta + 1);
+ if (len < msg->length) {
+ return RTX_ERR;
+ }
+
+ // Process one message
+ *sender_tid = meta->sender_tid;
+ mailbox->data_start += sizeof(C_METADATA);
+ if (msg->length + mailbox->data_start <= mailbox->buffer_end) {
+ mem_cpy((void*)(mailbox->data_start),
+ buf,
+ msg->length);
+ mailbox->data_start = align_increment(mailbox->data_start, msg->length, 8);
+ } else {
+
+ U32 free_space = mailbox->buffer_end - mailbox->data_start;
+
+ mem_cpy((void*)((U32)mailbox->data_start),
+ buf,
+ free_space);
+ mem_cpy((void*)mailbox->buffer_start,
+ (char*)buf + free_space,
+ msg->length - free_space);
+
+ mailbox->data_start = align_increment(mailbox->buffer_start, msg->length - free_space, 8);
+ }
+
+ return RTX_OK;
}
-int k_recv_msg_nb(task_t *sender_tid, void *buf, size_t len) {
+int k_mbx_ls(task_t *buf, int count) {
#ifdef DEBUG_0
- printf("k_recv_msg_nb: sender_tid = 0x%x, buf=0x%x, len=%d\r\n", sender_tid, buf, len);
+ printf("k_mbx_ls: buf=0x%x, count=%d\r\n", buf, count);
#endif /* DEBUG_0 */
return 0;
}
-int k_mbx_ls(task_t *buf, int count) {
+
+int k_recv_msg_nb(task_t *sender_tid, void *buf, size_t len) {
#ifdef DEBUG_0
- printf("k_mbx_ls: buf=0x%x, count=%d\r\n", buf, count);
+ printf("k_recv_msg_nb: sender_tid = 0x%x, buf=0x%x, len=%d\r\n", sender_tid, buf, len);
#endif /* DEBUG_0 */
return 0;
}
+
diff --git a/manual_code/lab4/RT/src/kernel/k_task.c b/manual_code/lab4/RT/src/kernel/k_task.c
index 35503cc..6fe214d 100644
--- a/manual_code/lab4/RT/src/kernel/k_task.c
+++ b/manual_code/lab4/RT/src/kernel/k_task.c
@@ -122,6 +122,255 @@ The memory map of the OS image may look like the following:
---------------------------------------------------------------------------*/
+
+/*
+ *==========================================================================
+ * UTILITY
+ *==========================================================================
+ */
+
+// returns 1 if t1 is earlier than t2
+int compare_timeval(TIMEVAL t1, TIMEVAL t2) {
+ return t1.sec < t2.sec || (t1.sec == t2.sec && t1.usec < t2.usec);
+}
+
+/*
+ *==========================================================================
+ * EDF VARIABLES
+ *==========================================================================
+ */
+
+typedef struct edf_task_rt {
+ TASK_RT info;
+ TIMEVAL deadline;
+ int flag; // if flag is -1, not in use.
+} EDF_TASK_RT;
+
+static EDF_TASK_RT edf_array[MAX_TASKS];
+
+/*
+ *===========================================================================
+ * EDF FUNCTIONS
+ *===========================================================================
+ */
+
+void edf_insert(task_t tid, TASK_RT info) {
+ if (edf_array[tid].flag > 0) {
+ // this is really bad
+ }
+
+ edf_array[tid].info = info;
+
+ // TODO: fix this to use the timers
+ edf_array[tid].deadline.sec = 0;
+ edf_array[tid].deadline.usec = 0;
+
+ edf_array[tid].flag = 0;
+}
+
+void edf_remove(task_t tid) {
+ if (edf_array[tid].flag < 0) {
+ // this is really bad
+ }
+
+ edf_array[tid].flag = -1;
+}
+
+/*
+ *==========================================================================
+ * SCHEDULER VARIABLES
+ *==========================================================================
+ */
+
+static const int h_array_size = MAX_TASKS;
+static TCB* heap[h_array_size];
+static U32 current_size = 0;
+static U32 g_task_count = 0;
+
+/*
+ *===========================================================================
+ * SCHEDULER FUNCTIONS
+ *===========================================================================
+ */
+
+extern int compare(TCB *t1, TCB* t2);
+
+int compare_rt(TCB *t1, TCB* t2) {
+ if (t1->prio != PRIO_RT || t2->prio != PRIO_RT) {
+ return compare(t1, t2);
+ }
+
+ EDF_TASK_RT rt1 = edf_array[t1->tid];
+ EDF_TASK_RT rt2 = edf_array[t2->tid];
+
+ // TODO: compare rt1 and rt2 using info + last_run
+ return compare_timeval(rt1.deadline, rt2.deadline);
+}
+
+int compare(TCB *t1, TCB* t2) {
+ if (t1->prio == PRIO_RT && t2->prio == PRIO_RT) {
+ return compare_rt(t1, t2);
+ }
+
+ int result = (*t1).prio < (*t2).prio || ((*t1).prio == (*t2).prio && (*t1).task_count <= (*t2).task_count);
+ // printf("V1: %d, %d, %d - V2: %d, %d, %d - Result: %d\r\n", t1->tid, t1->prio, t1->task_count, t2->tid, t2->prio, t2->task_count, result);
+ return result;
+}
+
+void swap(TCB** t1, TCB** t2) {
+ TCB* t;
+ t = *t1;
+ *t1 = *t2;
+ *t2 = t;
+}
+
+int parent(int i) {
+ return (i > 0 && i < h_array_size) ? (i - 1) / 2 : -1;
+}
+
+int left_child(int i) {
+ return (2*i + 1 < current_size && i >= 0) ? 2*i + 1: -1;
+}
+
+int right_child(int i) {
+ return (2*i + 2 < current_size && i >= 0) ? 2*i + 2 : -1;
+}
+
+void increase_key(TCB* heap[], int i) {
+ while(i >= 0 && parent(i) >= 0 && !compare(heap[parent(i)], heap[i])) {
+ swap(&heap[i], &heap[parent(i)]);
+ i = parent(i);
+ }
+}
+
+void decrease_key(TCB* heap[], int i) {
+ int max_index = i;
+
+ int l = left_child(i);
+
+ if (l > 0 && compare(heap[l], heap[max_index])) {
+ max_index = l;
+ }
+
+ int r = right_child(i);
+
+ if (r > 0 && compare(heap[r], heap[max_index])) {
+ max_index = r;
+ }
+
+ if (i != max_index) {
+ swap(&heap[i], &heap[max_index]);
+ decrease_key(heap, max_index);
+ }
+}
+
+int insert(TCB* heap[], TCB* value) {
+ if (current_size + 1== h_array_size) {
+ return -1;
+ }
+
+ g_task_count += 1;
+ (*value).task_count = g_task_count;
+ heap[current_size] = value;
+ increase_key(heap, current_size);
+ current_size ++;
+
+ return 0;
+}
+
+int16_t maximum(TCB* heap[]) {
+ return current_size == 0 ? -1 : heap[0]->tid;
+}
+
+int16_t extract_max(TCB* heap[]) {
+ if (current_size == 0) { return 0; }
+
+ int16_t max_value = maximum(heap);
+
+ current_size --;
+ heap[0] = heap[current_size];
+ decrease_key(heap, 0);
+
+ return max_value;
+}
+
+int find_value(TCB* heap[], U8 tid) {
+ int i;
+ for (i = 0; i < current_size; i++) {
+ if (heap[i]->tid == tid) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+void reset_priority(TCB* heap[], U8 tid, U8 priority) {
+ int index = find_value(heap, tid);
+ if (index < 0) { return; }
+
+ TCB v = *heap[index];
+
+ g_task_count += 1;
+ heap[index]->prio = priority;
+ heap[index]->task_count = g_task_count;
+
+ if (compare(heap[index], &v)) {
+ increase_key(heap, index);
+ } else {
+ decrease_key(heap, index);
+ }
+}
+
+void remove_id(TCB* heap[], U8 tid) {
+ if (current_size == 0) { return; }
+
+ int i = find_value(heap, tid);
+
+ if (i < 0) { return; }
+
+ //printf("found id: %d\n", i);
+ heap[i] = heap[0];
+ heap[i]->task_count += 1;
+ increase_key(heap, i);
+ //print_heap(heap, current_size);
+ extract_max(heap);
+}
+
+/*
+ *===========================================================================
+ * SUSPENDED FUNCTIONS
+ *===========================================================================
+ */
+
+typedef struct suspended_task_info {
+ TIMEVAL wake_up_time;
+ int valid_flag; // if flag is -1, not in use
+} SUSPENDED_TASK_INFO;
+
+static SUSPENDED_TASK_INFO sus_array[MAX_TASKS];
+
+void suspend(task_t tid, TIMEVAL wake_up_time) {
+ sus_array[tid].wake_up_time = wake_up_time;
+ sus_array[tid].valid_flag = 0;
+}
+
+void wake_up(TIMEVAL curr_time) {
+ for (int i = 0; i < MAX_TASKS; i++) {
+ if (sus_array[i].valid_flag < 0) { continue; }
+
+ TIMEVAL wake_up_time = sus_array[i].wake_up_time;
+
+ if (compare_timeval(wake_up_time, curr_time)) {
+ TCB* tcb = &g_tcbs[i];
+ tcb->state = READY;
+ insert(heap, tcb);
+ EDF_TASK_RT info = edf_array[i];
+ // Maybe update deadline??
+ }
+ }
+}
+
/*
*===========================================================================
* FUNCTIONS
@@ -136,14 +385,38 @@ The memory map of the OS image may look like the following:
*
*****************************************************************************/
+int currently_running() {
+ return gp_current_task && gp_current_task->state == RUNNING;
+}
+
TCB *scheduler(void)
{
- task_t tid = gp_current_task->tid;
- return &g_tcbs[(++tid)%g_num_active_tasks];
+ int16_t tid = maximum(heap);
+ //int16_t tid = extract_max(heap);
+ if (tid < 0) { return gp_current_task; }
-}
+ TCB* current_tcb = gp_current_task;
+ TCB* max_ready_tcb = &g_tcbs[(U8)tid];
+
+ // current task has higher priority
+ if (gp_current_task->state != DORMANT &&
+ gp_current_task->state != BLK_MSG &&
+ gp_current_task->state != SUSPENDED &&
+ current_tcb->prio < max_ready_tcb->prio) {
+ return gp_current_task;
+ }
+ gp_current_task = max_ready_tcb;
+ extract_max(heap);
+
+ if (current_tcb->state != BLK_MSG && current_tcb->state != SUSPENDED) {
+ insert(heap, current_tcb);
+ }
+
+ return gp_current_task;
+
+}
/**************************************************************************//**
* @brief initialize all boot-time tasks in the system,
@@ -165,7 +438,7 @@ int k_tsk_init(RTX_TASK_INFO *task_info, int num_tasks)
RTX_TASK_INFO *p_taskinfo = &g_null_task_info;
g_num_active_tasks = 0;
- if (num_tasks > MAX_TASKS) {
+ if (num_tasks > MAX_TASKS - 1) { // num_tasks + null task <= MAX_TASKS
return RTX_ERR;
}
@@ -178,15 +451,54 @@ int k_tsk_init(RTX_TASK_INFO *task_info, int num_tasks)
g_num_active_tasks++;
gp_current_task = p_tcb;
+ // initialize all TCB task ids and states to DORMANT
+ for(int i = 1; i < MAX_TASKS; i++){
+ g_tcbs[i].state = DORMANT;
+ g_tcbs[i].tid = i;
+ }
+
// create the rest of the tasks
p_taskinfo = task_info;
- for ( int i = 0; i < num_tasks; i++ ) {
- TCB *p_tcb = &g_tcbs[i+1];
- if (k_tsk_create_new(p_taskinfo, p_tcb, i+1) == RTX_OK) {
- g_num_active_tasks++;
+ int numCreated = 0;
+ int tcb_index = 1;
+ while(numCreated != num_tasks){
+ if(p_taskinfo->ptask == kcd_task){ // TODO: Check the Extern for KCD_TASK use function.
+ TCB *p_tcb = &g_tcbs[TID_KCD];
+ if (k_tsk_create_new(p_taskinfo, p_tcb, TID_KCD) == RTX_OK) {
+ g_num_active_tasks++;
+ }
+ } else {
+ TCB *p_tcb = &g_tcbs[tcb_index];
+ if (k_tsk_create_new(p_taskinfo, p_tcb, tcb_index) == RTX_OK) {
+ g_num_active_tasks++;
+ }
+ tcb_index++;
}
p_taskinfo++;
+ numCreated++;
+ }
+
+ return RTX_OK;
+}
+
+int validate_stack_size(int stack_size) {
+ // stack size too small
+ if (stack_size < PROC_STACK_SIZE){
+ return RTX_ERR;
+ }
+
+ // stack size too big
+ size_t ALL_HEAP = 0xFFFFFFFF;
+ size_t suitable_regions = k_mem_count_extfrag(ALL_HEAP) - k_mem_count_extfrag(stack_size);
+ if (!suitable_regions){
+ return RTX_ERR;
}
+
+ // stack_size not 8 bytes aligned
+ if (stack_size % 8 != 0){
+ return RTX_ERR;
+ }
+
return RTX_OK;
}
/**************************************************************************//**
@@ -218,7 +530,7 @@ int k_tsk_create_new(RTX_TASK_INFO *p_taskinfo, TCB *p_tcb, task_t tid)
return RTX_ERR;
}
- p_tcb ->tid = tid;
+ p_tcb->tid = tid;
p_tcb->state = READY;
/*---------------------------------------------------------------
@@ -258,7 +570,11 @@ int k_tsk_create_new(RTX_TASK_INFO *p_taskinfo, TCB *p_tcb, task_t tid)
//********************************************************************//
//*** allocate user stack from the user space, not implemented yet ***//
//********************************************************************//
- *(--sp) = (U32) k_alloc_p_stack(tid);
+ p_tcb->u_stack_size = p_taskinfo->u_stack_size;
+ *(--sp) = (U32)k_alloc_p_stack(tid);
+
+ // store user stack hi pointer in TCB
+ p_tcb->u_stack_hi = *sp; // user stack hi grows downwards
// uR12, uR11, ..., uR0
for ( int j = 0; j < 13; j++ ) {
@@ -279,6 +595,8 @@ int k_tsk_create_new(RTX_TASK_INFO *p_taskinfo, TCB *p_tcb, task_t tid)
} else {
// kernel thread LR: return to the entry point of the task
*(--sp) = (U32) (p_taskinfo->ptask);
+ p_tcb->u_stack_hi = p_taskinfo->u_stack_size; // user stack hi grows downwards
+ p_tcb->u_stack_size = p_taskinfo->u_stack_size;
}
// kernel stack R0 - R12, 13 registers
@@ -286,7 +604,13 @@ int k_tsk_create_new(RTX_TASK_INFO *p_taskinfo, TCB *p_tcb, task_t tid)
*(--sp) = 0x0;
}
- p_tcb->msp = sp;
+ p_tcb->msp = sp; // store msp in TCB
+ p_tcb->ptask = p_taskinfo->ptask; // store task entry in TCB
+ p_tcb->prio = p_taskinfo->prio; // store priority in TCB
+ p_tcb->priv = p_taskinfo->priv; // store privilege in
+ p_tcb->mailbox = 0;
+
+ insert(heap, p_tcb);
return RTX_OK;
}
@@ -348,8 +672,12 @@ int k_tsk_run_new(void)
// at this point, gp_current_task != NULL and p_tcb_old != NULL
if (gp_current_task != p_tcb_old) {
- gp_current_task->state = RUNNING; // change state of the to-be-switched-in tcb
- p_tcb_old->state = READY; // change state of the to-be-switched-out tcb
+ gp_current_task->state = RUNNING; // change state of the to-be-switched-in tcb
+ if(p_tcb_old->state != DORMANT &&
+ p_tcb_old->state != BLK_MSG &&
+ p_tcb_old->state != SUSPENDED){
+ p_tcb_old->state = READY; // change state of the to-be-switched-out tcb
+ }
k_tsk_switch(p_tcb_old); // switch stacks
}
@@ -367,6 +695,8 @@ int k_tsk_run_new(void)
*****************************************************************************/
int k_tsk_yield(void)
{
+ g_task_count++;
+ gp_current_task->task_count = g_task_count;
return k_tsk_run_new();
}
@@ -383,15 +713,113 @@ int k_tsk_create(task_t *task, void (*task_entry)(void), U8 prio, U16 stack_size
printf("k_tsk_create: entering...\n\r");
printf("task = 0x%x, task_entry = 0x%x, prio=%d, stack_size = %d\n\r", task, task_entry, prio, stack_size);
#endif /* DEBUG_0 */
- return RTX_OK;
+ // TODO: `k_tsk_create` is non-blocking, but can be preempted by `scheduler`
+ // TODO: check pointers
+ // TODO: error checking additional conditions
+
+ // TID pointer NULL
+ if (task == NULL){
+ return RTX_ERR;
+ }
+
+ // Task entry pointer NULL
+ if (task_entry == NULL){
+ return RTX_ERR;
+ }
+
+ // Maximum number of tasks reached
+ if (g_num_active_tasks == MAX_TASKS){
+ return RTX_ERR;
+ }
+
+ if (validate_stack_size(stack_size) == RTX_ERR) {
+ return RTX_ERR;
+ }
+
+ // prio invalid
+ if (prio != HIGH && prio != MEDIUM && prio != LOW && prio != LOWEST){
+ return RTX_ERR;
+ }
+
+ RTX_TASK_INFO task_info;
+ TCB * tcb = NULL;
+
+ // linear traverse to find free TID in g_tcbs;
+ for (int i=0; i < MAX_TASKS; i++){
+ // get dormant TCB
+ if(g_tcbs[i].state == DORMANT){
+ tcb = &g_tcbs[i];
+ break;
+ }
+ }
+
+ // get TID and store in buffer
+ *task = tcb->tid;
+
+ // fill in task_info
+ task_info.prio = prio;
+ task_info.priv = 0;
+ task_info.u_stack_size = stack_size;
+ task_info.ptask = task_entry;
+
+ // call k_tsk_create_new
+ if (k_tsk_create_new(&task_info, tcb, *task) == RTX_ERR){
+ return RTX_ERR;
+ }
+
+ g_num_active_tasks++;
+ //scheduler(); do we need to call?
+
+// if (currently_running()) {
+// k_tsk_yield();
+// } else {
+// return RTX_ERR;
+// }
+
+
+ return RTX_OK;
}
void k_tsk_exit(void)
{
+
#ifdef DEBUG_0
printf("k_tsk_exit: entering...\n\r");
#endif /* DEBUG_0 */
+
+ gp_current_task->state = DORMANT;
+
+ TCB* p_tcb_old = gp_current_task;
+ gp_current_task = scheduler();
+
+ if(p_tcb_old->priv == 0){
+ k_mem_dealloc((void *) ((U32)p_tcb_old->u_stack_hi - p_tcb_old->u_stack_size));
+ }
+
+ if (p_tcb_old->mailbox) {
+ k_mem_dealloc((void*)p_tcb_old->mailbox);
+ }
+
+ if (p_tcb_old->prio == PRIO_RT) {
+ edf_remove(p_tcb_old->tid);
+ // TODO: Check deadline against timer!
+ }
+
+ g_num_active_tasks--;
+ remove_id(heap, p_tcb_old->tid);
+
+ if ( gp_current_task == NULL ) {
+ gp_current_task = p_tcb_old; // revert back to the old task
+ return;
+ }
+
+ // at this point, gp_current_task != NULL and p_tcb_old != NULL
+ if (gp_current_task != p_tcb_old) {
+ gp_current_task->state = RUNNING; // change state of the to-be-switched-in tcb
+ k_tsk_switch(p_tcb_old); // switch stacks
+ }
+
return;
}
@@ -401,7 +829,48 @@ int k_tsk_set_prio(task_t task_id, U8 prio)
printf("k_tsk_set_prio: entering...\n\r");
printf("task_id = %d, prio = %d.\n\r", task_id, prio);
#endif /* DEBUG_0 */
- return RTX_OK;
+
+ // TODO: This function never blocks, but can be preempted. what does this mean?
+ // TODO: if try to set null task to prio PRIO_NULL, do I let it or error?
+
+ // prio invalid or PRIO_NULL
+ if (prio != HIGH && prio != MEDIUM && prio != LOW && prio != LOWEST){
+ return RTX_ERR;
+ }
+
+ // dormant TCB
+ if (g_tcbs[task_id].state == DORMANT){
+ return RTX_ERR;
+ }
+
+ if (prio == g_tcbs[task_id].prio) {
+ return RTX_OK;
+ }
+
+ // valid TID
+ if (task_id > 0 && task_id < MAX_TASKS){
+ // user-mode task can change prio of any user-mode task
+ // user-mode task cannot change prio of kernel task
+ // kernel task can change prio of any user-mode or kernel task
+
+ if(gp_current_task->priv == 1){
+ g_tcbs[task_id].prio = prio;
+ } else {
+ if(g_tcbs[task_id].priv == 1){
+ return RTX_ERR;
+ } else {
+ g_tcbs[task_id].prio = prio;
+ }
+ }
+
+ reset_priority(heap, task_id, prio);
+
+ k_tsk_yield();
+
+ return RTX_OK;
+ }else{
+ return RTX_ERR;
+ }
}
int k_tsk_get(task_t task_id, RTX_TASK_INFO *buffer)
@@ -410,22 +879,41 @@ int k_tsk_get(task_t task_id, RTX_TASK_INFO *buffer)
printf("k_tsk_get: entering...\n\r");
printf("task_id = %d, buffer = 0x%x.\n\r", task_id, buffer);
#endif /* DEBUG_0 */
+
+ // error checking
if (buffer == NULL) {
return RTX_ERR;
}
- /* The code fills the buffer with some fake task information.
- You should fill the buffer with correct information */
- buffer->tid = task_id;
- buffer->prio = 99;
- buffer->state = 101;
- buffer->priv = 0;
- buffer->ptask = 0x0;
- buffer->k_sp = 0xBEEFDEAD;
- buffer->k_stack_size = KERN_STACK_SIZE;
- buffer->u_sp = 0xDEADBEEF;
- buffer->u_stack_size = 0x200;
+ // Dormant TCB
+ if (g_tcbs[task_id].state == DORMANT){
+ return RTX_ERR;
+ }
+
+ // valid TID excluding 0
+ if (task_id > 0 && task_id < MAX_TASKS){
+ buffer->tid = task_id;
+ buffer->prio = g_tcbs[task_id].prio;
+ buffer->state = g_tcbs[task_id].state;
+ buffer->priv = g_tcbs[task_id].priv;
+ buffer->ptask = g_tcbs[task_id].ptask;
+ buffer->k_stack_hi = (U32) (&g_k_stacks[task_id+1]); // kernel stack hi grows downwards
+ buffer->k_stack_size = KERN_STACK_SIZE;
+ buffer->u_stack_hi = g_tcbs[task_id].u_stack_hi;
+ buffer->u_stack_size = g_tcbs[task_id].u_stack_size;
- return RTX_OK;
+ buffer->u_sp = * (U32*)((U32) g_tcbs[task_id].msp + 108);
+
+ if (task_id == gp_current_task->tid){
+ int regVal = __current_sp(); // store value of SP register in regVal
+ buffer->k_sp = regVal;
+ }else{
+ buffer->k_sp = (U32) g_tcbs[task_id].msp;
+ }
+ return RTX_OK;
+
+ }else{
+ return RTX_ERR;
+ }
}
int k_tsk_ls(task_t *buf, int count){
@@ -435,6 +923,55 @@ int k_tsk_ls(task_t *buf, int count){
return 0;
}
+void k_tsk_block(void) {
+ if (gp_current_task->state != RUNNING) {
+ return;
+ }
+
+ gp_current_task->state = BLK_MSG;
+ k_tsk_run_new();
+}
+
+void k_tsk_unblock (TCB *task) {
+ if (!task) { return; }
+
+ if (task->state != BLK_MSG) {
+ return;
+ }
+
+ task->state = READY;
+
+ // Unblocked task has higher priority
+ if (compare(task, gp_current_task)) {
+ // Preempt current task
+
+ TCB *p_tcb_old = NULL;
+
+ p_tcb_old = gp_current_task;
+ gp_current_task = task;
+
+ // We move this preempted task to the front of the ready queue
+ // We do not change the fifo counter of the preempted task
+ // So it should remain at the front
+ insert(heap, p_tcb_old);
+
+ // at this point, gp_current_task != NULL and p_tcb_old != NULL
+ if (gp_current_task != p_tcb_old) {
+ gp_current_task->state = RUNNING; // change state of the to-be-switched-in tcb
+ p_tcb_old->state = READY; // change state of the to-be-switched-out tcb
+ k_tsk_switch(p_tcb_old); // switch stacks
+ }
+ } else {
+ // Add unblocked lower priority task to the back of the ready queue
+ // We increment fifo counter so it explicitly goes to the back
+ g_task_count++;
+ task->task_count = g_task_count;
+ insert(heap, task);
+ }
+
+ return;
+}
+
/*
*===========================================================================
* TO BE IMPLEMETED IN LAB4
@@ -443,21 +980,99 @@ int k_tsk_ls(task_t *buf, int count){
int k_tsk_create_rt(task_t *tid, TASK_RT *task)
{
- return 0;
+ if (task->p_n.usec % 500 != 0 ||
+ !task->task_entry ||
+ task->rt_mbx_size < MIN_MBX_SIZE ||
+ g_num_active_tasks == MAX_TASKS ||
+ validate_stack_size(task->u_stack_size) == RTX_ERR) {
+ return RTX_ERR;
+ }
+
+ if (g_num_active_tasks == MAX_TASKS) {
+ return RTX_ERR;
+ }
+
+ RTX_TASK_INFO task_info;
+ TCB * tcb = NULL;
+
+ for (int i = 0; i < MAX_TASKS; i++) {
+ if (g_tcbs[i].state == DORMANT) {
+ tcb = &g_tcbs[i];
+ break;
+ }
+ }
+
+ *tid = tcb->tid;
+ task_info.prio = PRIO_RT;
+ task_info.priv = 0;
+ task_info.u_stack_size = task->u_stack_size;
+ task_info.ptask = task->task_entry;
+
+ edf_insert(tcb->tid, *task);
+
+ if (k_tsk_create_new(&task_info, tcb, *tid) == RTX_ERR) {
+ return RTX_ERR;
+ }
+
+ g_num_active_tasks ++;
+
+ return RTX_OK;
}
void k_tsk_done_rt(void) {
#ifdef DEBUG_0
printf("k_tsk_done: Entering\r\n");
#endif /* DEBUG_0 */
+
+ EDF_TASK_RT rt_info = edf_array[gp_current_task->tid];
+ RTX_TASK_INFO info;
+ k_tsk_get(gp_current_task->tid, &info);
+
+ // TODO: logic for suspended
+ gp_current_task->state = SUSPENDED;
+ suspend(gp_current_task->tid, rt_info.deadline);
+
+ U32* sp = (U32*)info.k_stack_hi;;
+
+ if (gp_current_task->priv == 0) {
+ // Walk through sp to reset values
+ --sp;
+ *(--sp) = (U32)info.ptask;
+ *(--sp) = info.u_stack_hi;
+
+ for ( int j = 0; j < 13; j++ ) {
+ *(--sp) = 0x0;
+ }
+
+ --sp;
+ } else {
+ *(--sp) = (U32) info.ptask;
+ }
+
+ // kernel stack R0 - R12, 13 registers
+ for ( int j = 0; j < 13; j++) {
+ *(--sp) = 0x0;
+ }
+
+ gp_current_task->msp = sp;
+
+ k_tsk_run_new();
+
return;
}
-void k_tsk_suspend(TIMEVAL *tv)
+void k_tsk_suspend(struct timeval_rt *tv)
{
#ifdef DEBUG_0
printf("k_tsk_suspend: Entering\r\n");
#endif /* DEBUG_0 */
+ if ((tv->sec == 0 && tv->usec == 0) || tv->usec % 500 != 0) { return; }
+
+ gp_current_task->state = SUSPENDED;
+ suspend(gp_current_task->tid, *tv);
+
+ k_tsk_run_new();
+
return;
}
diff --git a/manual_code/lab4/RT/src/kernel/k_task.h b/manual_code/lab4/RT/src/kernel/k_task.h
index 797af67..971c33c 100644
--- a/manual_code/lab4/RT/src/kernel/k_task.h
+++ b/manual_code/lab4/RT/src/kernel/k_task.h
@@ -60,7 +60,7 @@ extern TCB *gp_current_task;
*/
extern void task_null (void);
-
+extern void kcd_task (void);
// Implemented by Starter Code
@@ -82,4 +82,6 @@ int k_tsk_create_rt(task_t *tid, TASK_RT *task);
void k_tsk_done_rt (void);
void k_tsk_suspend (struct timeval_rt *tv);
+void wake_up(TIMEVAL curr_time);
+
#endif // ! K_TASK_H_
diff --git a/submission/lab1/README.md b/submission/lab1/README.md
new file mode 100644
index 0000000..19ab0da
--- /dev/null
+++ b/submission/lab1/README.md
@@ -0,0 +1,19 @@
+## ECE 350 RTX Project Repository
+
+Group 51
+
+## File structures
+
+### `code`
+This directory contains the ARM DS project files.
+
+Testing:
+The integration test cases in the src/app/ae_mem.c file have been commented out.
+The utilization performance benchmarking test cases have not been commented out.
+
+In order to run our integration test cases, please comment out the `test_utilization()` function and uncomment the integration tests.
+
+The `test_utilization()` function will test both throughput and heap utilization.
+
+### Lab report
+The lab report p1_report.pdf can be found under the current lab1 directory.
diff --git a/submission/lab1/code/.cproject b/submission/lab1/code/.cproject
new file mode 100644
index 0000000..fac20cf
--- /dev/null
+++ b/submission/lab1/code/.cproject
@@ -0,0 +1,268 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/submission/lab1/code/.project b/submission/lab1/code/.project
new file mode 100644
index 0000000..86da93a
--- /dev/null
+++ b/submission/lab1/code/.project
@@ -0,0 +1,27 @@
+
+
+ SVC
+
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.genmakebuilder
+ clean,full,incremental,
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder
+ full,incremental,
+
+
+
+
+
+ com.arm.debug.ds.nature
+ org.eclipse.cdt.core.cnature
+ org.eclipse.cdt.managedbuilder.core.managedBuildNature
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
+
+
diff --git a/submission/lab1/code/SVC.launch b/submission/lab1/code/SVC.launch
new file mode 100644
index 0000000..c7417f7
--- /dev/null
+++ b/submission/lab1/code/SVC.launch
@@ -0,0 +1,204 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/submission/lab1/code/scatter1.sct b/submission/lab1/code/scatter1.sct
new file mode 100644
index 0000000..0fdaef9
--- /dev/null
+++ b/submission/lab1/code/scatter1.sct
@@ -0,0 +1,29 @@
+;**************************************************
+; Copyright (c) 2013 ARM Ltd. All rights reserved.
+; Modified by yqhuang@uwaterloo.ca for ECE350 LAB
+;**************************************************
+
+; Scatter-file for RTX on Versatile Express
+
+; This scatter-file places application code, data, stack and heap at suitable addresses in the memory map.
+
+; This platform has 2GB SDRAM starting at 0x80000000.
+
+;#include "mem_ARMCA9.h"
+
+SDRAM 0x80000000 0x40000000
+{
+ VECTORS +0 0x200000
+ {
+ * (RESET, +FIRST) ; Vector table and other (assembler) startup code
+ * (InRoot$$Sections) ; All (library) code that must be in a root region
+ * (+RO-CODE) ; Application RO code (.text)
+ * (+RO-DATA) ; Application RO data (.constdata)
+ }
+
+ RW_DATA 0x80200000 0x100000
+ { * (+RW) } ; Application RW data (.data)
+
+ ZI_DATA 0x80300000 0x100000
+ { * (+ZI) } ; Application ZI data (.bss)
+}
diff --git a/submission/lab1/code/setup_scatter_file.txt b/submission/lab1/code/setup_scatter_file.txt
new file mode 100644
index 0000000..e2cb808
--- /dev/null
+++ b/submission/lab1/code/setup_scatter_file.txt
@@ -0,0 +1,7 @@
+Right click project folder in the Project Explorer
+ -> Properties -> C/C++ Build -> Settings -> Arm Linker 5 -> Image Layout
+
+Image entry point (--entry): __Vectors
+Scatter file (--scatter) : "${workspace_loc:/${ProjName}/scatter1.sct}"
+
+Note you need to put the double quotes around the location of the scatter file.
\ No newline at end of file
diff --git a/submission/lab1/code/src/INC/common.h b/submission/lab1/code/src/INC/common.h
new file mode 100644
index 0000000..3e3e7cb
--- /dev/null
+++ b/submission/lab1/code/src/INC/common.h
@@ -0,0 +1,203 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ *
+ * This software is subject to an open source license and
+ * may be freely redistributed under the terms of MIT License.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file common.h
+ * @brief Common macros and structures for both kernel and user
+ *
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ * @see rtx.h
+ * @attention DO NOT MODIFY
+ *
+ * @note If you want to define your own macros and data structures,
+ * add them to common_ext.h.
+ * Do not let your newly-added code cause conflicts with
+ * the existing code in this file.
+ * For example, if you want to define new message types,
+ * use a value starting from 10.
+ * Do not overwrite existing message type macro values.
+ *
+ *****************************************************************************/
+
+#ifndef COMMON_H_
+#define COMMON_H_
+
+
+/*
+ *===========================================================================
+ * MACROS
+ *===========================================================================
+ */
+
+#define TRUE 1
+#define FALSE 0
+#define NULL 0
+#define RTX_ERR -1
+#define RTX_OK 0
+
+/* Memory Algorithms */
+#define FIXED_POOL 0
+#define FIRST_FIT 1 /* only requires to implement this one */
+#define BEST_FIT 2
+#define WORST_FIT 3
+
+/* Main Scheduling Algorithms */
+#define DEFAULT 0 /* strict-priority, FCFS scheduling */
+#define RM_PS 10 /* rate-monotonic scheduling with polling server */
+#define RM_NPS 11 /* rate-Monotonic scheduling without polling server */
+#define EDF 12 /* earliest-deadline-first scheduling */
+
+#define PID_NULL 0 /* pre-defined Task ID for null task */
+#define TID_KCD 15 /* pre-defined Task ID for KCD task */
+#define TID_DISPLAY 14 /* pre-defined Task ID for DISPLAY task */
+#define TID_UART_IRQ 0xFF /* reserved TID for UART IRQ handler which is not a task */
+#define TID_TIMER_IRQ 0xFE /* reserved TID for Timer IRQ handler, which is not a task */
+#define MAX_TASKS 16 /* maximum number of tasks in the system */
+#define KERN_STACK_SIZE 0x200 /* task kernel stack size in bytes */
+#define PROC_STACK_SIZE 0x200 /* task proc space stack size in bytes */
+
+/* Real-time Task Priority. Highest in the system*/
+#define PRIO_RT 0 /* priority level for real-time tasks */
+#define HIGH 100
+#define MEDIUM 101
+#define LOW 102
+#define LOWEST 103
+#define PRIO_NULL 255 /* hidden priority for null task */
+
+/* Task States */
+#define DORMANT 0 /* terminated task state */
+#define READY 1 /* A ready to run task that has been executed */
+#define RUNNING 2 /* Executing */
+#define BLK_MEM 3 /* blocked on requesting memory, not used in labs 1-5 */
+#define BLK_MSG 4 /* blocked on receiving a message */
+#define SUSPENDED 5 /* Suspended task */
+
+/* Message Passing Macros */
+/* Message Types */
+#define DEFAULT 0 /* a general purpose message */
+#define KCD_REG 1 /* a command registration message */
+#define KCD_CMD 2 /* a message that contains a command */
+#define DISPLAY 3 /* a message that contains chars to be displayed to the RTX console */
+#define KEY_IN 4 /* keyboard input from console */
+
+/* Message Data Sizes */
+#define MIN_MSG_SIZE 1 /* minimum message size in bytes */
+
+/* Mailbox Sizes */
+#define MIN_MBX_SIZE 1 /* minimum mailbox size in bytes */
+
+/* Time Macros */
+#define MIN_RTX_QTM 100 /* minimum time granularity of RTX in microseconds */
+
+
+/*
+ *===========================================================================
+ * TYPEDEFS
+ *===========================================================================
+ */
+
+typedef signed char S8;
+typedef unsigned char U8;
+typedef short S16;
+typedef unsigned short U16;
+typedef int S32;
+typedef unsigned int U32;
+typedef long long S64;
+typedef unsigned long long U64;
+typedef unsigned char BIT;
+typedef unsigned int BOOL;
+typedef unsigned int size_t;
+typedef signed int ssize_t;
+typedef unsigned char task_t;
+
+
+/*
+ *===========================================================================
+ * STRUCTURES
+ *===========================================================================
+ */
+
+/**
+ * @brief Timing structure
+ */
+struct timeval_rt {
+ U32 sec; /**> seconds */
+ U32 usec; /**> microoseconds */
+};
+
+/**
+ * @brief scheduling server structure
+ */
+typedef struct polling_server {
+ struct timeval_rt p_n; /**< period of the server */
+ struct timeval_rt b_n; /**< budget of the server */
+} POLLING_SERVER;
+
+/**
+ * @brief RTX system configuration structure
+ */
+typedef struct rtx_sys_info {
+ U32 rtx_time_qtm; /**< time granularity in microseconds */
+ POLLING_SERVER server; /**< scheduling server for non-real-time tasks */
+ U8 sched; /**< scheduler */
+} RTX_SYS_INFO;
+
+/**
+ * @brief message buffer header struct
+ */
+typedef struct rtx_msg_hdr {
+ U32 length; /**> length of the mssage including the message header size */
+ U32 type; /**> type of the message */
+} RTX_MSG_HDR;
+
+/**
+ * @brief Task information structure
+ */
+typedef struct rtx_task_info {
+ void (*ptask)(); /**> task entry address */
+ U32 k_sp; /**> current kernel stack pointer */
+ U32 k_stack_hi; /**> kernel stack base (high addr.) */
+ U32 u_sp; /**> current user stack pointer */
+ U32 u_stack_hi; /**> user stack base addr. (high addr.) */
+ U16 k_stack_size; /**> kernel stack size in bytes */
+ U16 u_stack_size; /**> user stack size in bytes */
+ task_t tid; /**> task ID */
+ U8 prio; /**> execution priority */
+ U8 state; /**> task state */
+ U8 priv; /**> = 0 unprivileged, =1 privileged */
+ struct timeval_rt tv_cpu; /**> task execution cpu time */
+ struct timeval_rt tv_wall; /**> task execution wall clock time */
+
+ /* The following only applies to real-time tasks */
+ struct timeval_rt p_n; /**> period in seconds and microseconds */
+ RTX_MSG_HDR *msg_hdr; /**> real-time task message header */
+ U32 num_msgs; /**> real-time task mailbox capacity */
+} RTX_TASK_INFO;
+
+/**
+ * @brief Real-time task information structure
+ */
+typedef struct task_rt {
+ struct timeval_rt p_n; /**> period in seconds and microseconds */
+ void (*task_entry)(); /**> task entry address */
+ U16 u_stack_size; /**> user stack size in bytes */
+ U8 priv; /**> = 0 unprivileged, =1 privileged */
+} TASK_RT;
+
+#endif // ! COMMON_H_
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab1/code/src/INC/common_ext.h b/submission/lab1/code/src/INC/common_ext.h
new file mode 100644
index 0000000..0c6d1f3
--- /dev/null
+++ b/submission/lab1/code/src/INC/common_ext.h
@@ -0,0 +1,65 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ *
+ * This software is subject to an open source license and
+ * may be freely redistributed under the terms of MIT License.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file common_ext.h
+ * @brief Extended common macros and structures for both kernel and user
+ * for students to add self-defined macros and structures
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ *
+ * @see common.h
+ *
+ * @note If you want to define your own macros and data structures,
+ * add them to common_ext.h.
+ * Do not let your newly-added code cause conflicts with
+ * the existing code in this file.
+ * For example, if you want to define new message types,
+ * use a value starting from 10.
+ * Do not overwrite existing message type macro values.
+ *
+ *****************************************************************************/
+
+/*
+ *===========================================================================
+ * MACROS
+ *===========================================================================
+ */
+
+/*
+ *===========================================================================
+ * TYPEDEFS
+ *===========================================================================
+ */
+
+
+/*
+ *===========================================================================
+ * STRUCTURES
+ *===========================================================================
+ */
+
+
+
+ /*
+ *===========================================================================
+ * FUNCTION PROTOTYPES
+ *===========================================================================
+ */
+
+
+ /*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab1/code/src/INC/rtx.h b/submission/lab1/code/src/INC/rtx.h
new file mode 100644
index 0000000..069c02a
--- /dev/null
+++ b/submission/lab1/code/src/INC/rtx.h
@@ -0,0 +1,170 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ *
+ * This software is subject to an open source license and
+ * may be freely redistributed under the terms of MIT License.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file rtx.h
+ * @brief RTX User API header file
+ *
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ * @see common.h
+ * @see common_ext.h
+ *
+ * @attention DO NOT MODIFY
+ *
+ *****************************************************************************/
+
+#ifndef _RTX_H_
+#define _RTX_H_
+
+#include "common.h"
+#include "common_ext.h"
+
+/*
+ *===========================================================================
+ * MACROS
+ *===========================================================================
+ */
+#define __SVC_0 __svc_indirect(0)
+
+/*
+ *===========================================================================
+ * FUNCTION PROTOTYPES
+ *===========================================================================
+ */
+
+/*------------------------------------------------------------------------*
+ * Memory Management Functions - LAB1
+ *------------------------------------------------------------------------*/
+
+/* __SVC_0 can be put at the end of the function declaration */
+/* memory management */
+extern int k_mem_init(void);
+#define mem_init() _mem_init((U32)k_mem_init)
+extern int _mem_init(U32 p_func) __SVC_0;
+
+extern void *k_mem_alloc(size_t size);
+#define mem_alloc(size) _mem_alloc((U32)k_mem_alloc, size)
+extern void *_mem_alloc(U32 p_func, size_t size) __SVC_0;
+
+extern int k_mem_dealloc(void *);
+#define mem_dealloc(ptr) _mem_dealloc((U32)k_mem_dealloc, ptr)
+extern int _mem_dealloc(U32 p_func, void *ptr) __SVC_0;
+
+extern int k_mem_count_extfrag(size_t size);
+#define mem_count_extfrag(size) _mem_count_extfrag((U32)k_mem_count_extfrag, size)
+extern int _mem_count_extfrag(U32 p_func, size_t size) __SVC_0;
+
+/*------------------------------------------------------------------------*
+ * System Initialization Function(s) - LAB2, LAB4, LAB5
+ *------------------------------------------------------------------------*/
+
+/* Note __SVC_0 can also be put in the front of the function name*/
+/*task management */
+extern int k_rtx_init(size_t blk_size, int algo, RTX_TASK_INFO *tsk_info, int num_tasks);
+#define rtx_init(blk_size, algo, tsk_info, num_tasks) _rtx_init((U32)k_rtx_init, blk_size, algo, tsk_info, num_tasks)
+extern int __SVC_0 _rtx_init(U32 p_func, size_t blk_size, int algo, RTX_TASK_INFO *tsk_info, int num_tasks);
+
+extern int k_rtx_init_rt(RTX_SYS_INFO *sys_info, RTX_TASK_INFO *task_info, int num_tasks);
+#define rtx_init_rt(sys_info, task_info, num_tasks) _rtx_init_rt((U32)k_rtx_init_rt, sys_info, task_info, num_tasks)
+extern int __SVC_0 _rtx_init_rt(U32 p_func, RTX_SYS_INFO *sys_info, RTX_TASK_INFO *task_info, int num_tasks);
+
+extern int k_get_sys_info(RTX_SYS_INFO *buffer);
+#define get_sys_info(buffer) _get_sys_info((U32)k_get_sys_info, buffer)
+extern int __SVC_0 _get_sys_info(U32 p_func, RTX_SYS_INFO *buffer);
+
+/*------------------------------------------------------------------------*
+ * Task Management Functions - LAB2, LAB4, LAB5
+ *------------------------------------------------------------------------*/
+
+extern int k_tsk_yield(void);
+#define tsk_yield() _tsk_yield((U32)k_tsk_yield)
+extern int __SVC_0 _tsk_yield(U32 p_func);
+
+extern int k_tsk_create(task_t *task, void (*task_entry)(void), U8 prio, U16 stack_size);
+#define tsk_create(task, task_entry, prio, stack_size) _tsk_create((U32)k_tsk_create, task, task_entry, prio, stack_size)
+extern int __SVC_0 _tsk_create(U32 p_func, task_t *task, void (*task_entry)(void), U8 prio, U16 stack_size);
+
+extern void k_tsk_exit(void);
+#define tsk_exit() _tsk_exit((U32)k_tsk_exit)
+extern void __SVC_0 _tsk_exit(U32 p_func);
+
+extern int k_tsk_set_prio(task_t task_id, U8 prio);
+#define tsk_set_prio(task_id, prio) _tsk_set_prio((U32)k_tsk_set_prio, task_id, prio)
+extern int __SVC_0 _tsk_set_prio(U32 p_func, task_t task_id, U8 prio);
+
+extern int k_tsk_get(task_t task_id, RTX_TASK_INFO *buffer);
+#define tsk_get(task_id, buffer) _tsk_get((U32)k_tsk_get, task_id, buffer)
+extern int __SVC_0 _tsk_get(U32 p_func, task_t task_id, RTX_TASK_INFO *buffer);
+
+extern int k_tsk_ls(task_t *buf, int count);
+#define tsk_ls(buf, count) _tsk_ls((U32)k_tsk_ls, buf, count);
+extern int __SVC_0 _tsk_ls(U32 p_func, task_t *buf, int count);
+
+/*------------------------------------------------------------------------*
+ * Real-Time Task Functions - LAB4, LAB5
+ *------------------------------------------------------------------------*/
+
+extern int k_tsk_create_rt(task_t *tid, TASK_RT *task, RTX_MSG_HDR *msg_hdr, U32 num_msgs);
+#define tsk_create_rt(tid, task, msg_hdr, num_msgs) _tsk_create_rt((U32)k_tsk_create_rt, tid, task, msg_hdr, num_msgs)
+extern int __SVC_0 _tsk_create_rt(U32 p_func, task_t *tid, TASK_RT *task, RTX_MSG_HDR *msg_hdr, U32 num_msgs);
+
+extern void k_tsk_done_rt(void);
+#define tsk_done_rt() _tsk_done_rt((U32)k_tsk_done_rt)
+extern void __SVC_0 _tsk_done_rt(U32 p_func);
+
+extern void k_tsk_suspend(struct timeval_rt *tv);
+#define tsk_suspend(tv) _tsk_suspend((U32) k_tsk_suspend, tv)
+extern void __SVC_0 _tsk_suspend(U32 p_func, struct timeval_rt *tv);
+
+
+/*------------------------------------------------------------------------*
+ * Interprocess Communication Functions - LAB3, LAB4
+ *------------------------------------------------------------------------*/
+
+extern int k_mbx_create(size_t size);
+#define mbx_create(size) _mbx_create((U32)k_mbx_create, size)
+extern int __SVC_0 _mbx_create(U32 p_func, size_t size);
+
+extern int k_send_msg(task_t tid, const void* buf);
+#define send_msg(tid, buf) _send_msg((U32)k_send_msg, tid, buf)
+extern int __SVC_0 _send_msg(U32 p_func, task_t tid, const void *buf);
+
+extern int k_recv_msg(task_t *tid, void *buf, size_t len);
+#define recv_msg(tid, buf, len) _recv_msg((U32)k_recv_msg, tid, buf, len)
+extern int __SVC_0 _recv_msg(U32 p_func, task_t *tid, void *buf, size_t len);
+
+extern int k_recv_msg_nb(task_t *tid, void *buf, size_t len);
+#define recv_msg_nb(tid, buf, len) _recv_msg_nb((U32)k_recv_msg_nb, tid, buf, len)
+extern int __SVC_0 _recv_msg_nb(U32 p_func, task_t *tid, void *buf, size_t len);
+
+extern int k_mbx_ls(task_t *buf, int count);
+#define mbx_ls(buf, count) _mbx_ls((U32)k_mbx_ls, buf, count);
+extern int __SVC_0 _mbx_ls(U32 p_func, task_t *buf, int count);
+
+/*------------------------------------------------------------------------*
+ * Timing Service Functions - LAB4
+ *------------------------------------------------------------------------*/
+
+extern int k_get_time(struct timeval_rt *tv);
+#define get_time(tv) _get_time((U32)k_get_time, tv)
+extern int __SVC_0 _get_time(U32 p_func, struct timeval_rt *tv);
+
+
+#endif // !_RTX_H_
+
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab1/code/src/app/ae.c b/submission/lab1/code/src/app/ae.c
new file mode 100644
index 0000000..1eab634
--- /dev/null
+++ b/submission/lab1/code/src/app/ae.c
@@ -0,0 +1,114 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ *
+ * This software is subject to an open source license and
+ * may be freely redistributed under the terms of MIT License.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file ae.c
+ * @brief Automated Evaluation (AE) Framework Source File
+ *
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ *
+ * @attention
+ * @note
+ * @details
+ *
+ *****************************************************************************/
+
+#include "ae.h"
+
+/**************************************************************************//**
+ * @brief ae_init
+ * @return RTX_OK on success and RTX_ERR on failure
+ * @param[out] sys_info system initialization struct AE writes to
+ * @param[out] task_info boot-time tasks struct array AE writes to
+ *
+ *****************************************************************************/
+
+int ae_init(RTX_SYS_INFO *sys_info, RTX_TASK_INFO *task_info, int num_tasks)
+{
+ if ( ae_set_sys_info(sys_info) != RTX_OK ) {
+ return RTX_ERR;
+ }
+
+ ae_set_task_info(task_info, num_tasks);
+ return RTX_OK;
+}
+
+/**************************************************************************//**
+ * @brief fill the sys_info struct with system configuration info.
+ * @return RTX_OK on success and RTX_ERR on failure
+ * @param[out] sys_info system initialization struct AE writes to
+ *
+ *****************************************************************************/
+int ae_set_sys_info(RTX_SYS_INFO *sys_info)
+{
+ if (sys_info == NULL) {
+ return RTX_ERR;
+ }
+
+
+ /*---------- NOT USED in LAB1 -------------------
+ // Scheduling sys info set up, not used in lab1, ignore for now
+ struct timeval_rt budget;
+ struct timeval_rt period;
+
+ budget.sec = 0;
+ budget.usec = MIN_RTX_QTM * 10;
+
+ period.sec = 0;
+ period.usec = MIN_RTX_QTM * 100;
+
+
+ sys_info->rtx_time_qtm = 10 * MIN_RTX_QTM;
+ sys_info->sched = RM_PS;
+ sys_info->server.b_n = budget;
+ sys_info->server.p_n = period;
+ -------------------------------------------------*/
+ return RTX_OK;
+}
+
+/**************************************************************************//**
+ * @brief fill the tasks array with information
+ * @param[out] tasks An array of RTX_TASK_INFO elements to write to
+ * @param[in] num_tasks The length of tasks array
+ * @return None
+ *****************************************************************************/
+
+void ae_set_task_info(RTX_TASK_INFO *tasks, int num_tasks) {
+
+ if (tasks == NULL) {
+ return;
+ }
+/*---------- NOT USED in LAB1 -------------------
+ for (int i = 0; i < num_tasks; i++ ) {
+ tasks[i].u_stack_size = 0x0;
+ tasks[i].prio = HIGH;
+ tasks[i].priv = 1;
+ }
+ tasks[0].ptask = &priv_task1;
+ tasks[1].ptask = &priv_task2;
+-------------------------------------------------*/
+ return;
+}
+
+int ae_start(void)
+{
+ return test_mem();
+}
+
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
+
diff --git a/submission/lab1/code/src/app/ae.h b/submission/lab1/code/src/app/ae.h
new file mode 100644
index 0000000..74b8002
--- /dev/null
+++ b/submission/lab1/code/src/app/ae.h
@@ -0,0 +1,64 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ *
+ * This software is subject to an open source license and
+ * may be freely redistributed under the terms of MIT License.
+ ****************************************************************************
+ */
+
+#ifndef AE_
+#define AE_
+
+#include "Serial.h"
+#include "printf.h"
+#include "rtx.h"
+//#include "ae_priv_tasks.h"
+//#include "ae_usr_tasks.h"
+
+ /*
+ *===========================================================================
+ * FUNCTION PROTOTYPES
+ *===========================================================================
+ */
+
+/**************************************************************************//**
+ * @file ae.h
+ * @brief Automated Evaluation (AE) Framework Header File
+ *
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ *
+ * @attention
+ * @note
+ * @details
+ *
+ *****************************************************************************/
+
+
+/*
+ *===========================================================================
+ * FUNCTION PROTOTYPES
+ *===========================================================================
+ */
+
+int ae_init (RTX_SYS_INFO *sys_info, \
+ RTX_TASK_INFO *task_info, \
+ int num_tasks);
+int ae_set_sys_info (RTX_SYS_INFO *sys_info);
+void ae_set_task_info (RTX_TASK_INFO *tasks, int num_tasks);
+int ae_start (void);
+
+extern int test_mem (void);
+
+#endif // ! AE_
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
+
diff --git a/submission/lab1/code/src/app/ae_mem.c b/submission/lab1/code/src/app/ae_mem.c
new file mode 100644
index 0000000..62edbd1
--- /dev/null
+++ b/submission/lab1/code/src/app/ae_mem.c
@@ -0,0 +1,332 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ *
+ * This software is subject to an open source license and
+ * may be freely redistributed under the terms of MIT License.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file ae_mem.c
+ * @brief memory lab auto-tester
+ *
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ *
+ *****************************************************************************/
+
+#include "rtx.h"
+#include "Serial.h"
+#include "printf.h"
+
+int test_coales(void) {
+ U32 result = 0;
+ if (countNodes()==1){
+ result |= BIT(0);
+ }
+
+ void *p[4];
+
+ p[0] = mem_alloc(12);
+ p[1] = mem_alloc(24);
+ p[2] = mem_alloc(48);
+
+ if (countNodes()==4){
+ result |= BIT(1);
+ }
+
+ mem_dealloc(p[1]);
+ if (countNodes()==4){
+ result |= BIT(2);
+ }
+
+ mem_dealloc(p[0]);
+ if (countNodes()==3){
+ result |= BIT(3);
+ }
+
+ mem_dealloc(p[2]);
+ if (countNodes()==1){
+ result |= BIT(4);
+ }
+
+ return result == 31;
+}
+
+int test_reuse_freed(void) {
+ void *p[4];
+ U32 result = 0;
+ if (countNodes()==1){
+ result |= BIT(0);
+ }
+
+ p[0] = mem_alloc(12);
+ p[1] = mem_alloc(24);
+ p[2] = mem_alloc(48);
+
+ if (countNodes()==4){
+ result |= BIT(1);
+ }
+
+ mem_dealloc(p[0]);
+ if (countNodes()==4){
+ result |= BIT(2);
+ }
+
+ p[3] = mem_alloc(12);
+ if (countNodes()==4){
+ result |= BIT(3);
+ }
+
+ mem_dealloc(p[1]);
+ mem_dealloc(p[2]);
+ mem_dealloc(p[3]);
+ if (countNodes()==1){
+ result |= BIT(4);
+ }
+
+ if(memLeakCheck()==1){
+ result |= BIT(5);
+ }
+
+ return result == 63;
+}
+
+int test_reuse_freed_2(void) {
+ void *p[4];
+ U32 result = 0;
+ if (countNodes()==1){
+ result |= BIT(0);
+ }
+
+ p[0] = mem_alloc(12);
+ p[1] = mem_alloc(24);
+ p[2] = mem_alloc(48);
+
+ if (countNodes()==4){
+ result |= BIT(1);
+ }
+
+ mem_dealloc(p[1]);
+ if (countNodes()==4){
+ result |= BIT(2);
+ }
+
+ p[3] = mem_alloc(20);
+ if (countNodes()==4){
+ result |= BIT(3);
+ }
+
+ mem_dealloc(p[0]);
+ mem_dealloc(p[2]);
+ mem_dealloc(p[3]);
+ if (countNodes()==1){
+ result |= BIT(4);
+ }
+
+ if(memLeakCheck()==1){
+ result |= BIT(5);
+ }
+
+ return result == 63;
+}
+
+int test_malloc_new_node(void) {
+ void *p[4];
+ U32 result = 0;
+ if (countNodes()==1){
+ result |= BIT(0);
+ }
+
+ p[0] = mem_alloc(12);
+ p[1] = mem_alloc(60);
+ p[2] = mem_alloc(48);
+
+ if (countNodes()==4){
+ result |= BIT(1);
+ }
+
+ mem_dealloc(p[1]);
+ if (countNodes()==4){
+ result |= BIT(2);
+ }
+
+ p[3] = mem_alloc(12);
+ if (countNodes()==5){
+ result |= BIT(3);
+ }
+
+ mem_dealloc(p[3]);
+ if (countNodes()==4){
+ result |= BIT(4);
+ }
+
+ mem_dealloc(p[0]);
+ mem_dealloc(p[2]);
+ if (countNodes()==1){
+ result |= BIT(5);
+ }
+
+ if(memLeakCheck()==1){
+ result |= BIT(6);
+ }
+
+ return result == 127;
+}
+
+int test_mem_leak(){
+ void *p[4];
+ U32 result = 0;
+ if(memLeakCheck()==1){
+ result |= BIT(0);
+ }
+
+ p[0] = mem_alloc(12);
+
+ if(memLeakCheck()==1){
+ result |= BIT(1);
+ }
+
+ mem_dealloc(p[0]);
+
+ if(memLeakCheck()==1){
+ result |= BIT(2);
+ }
+
+ return result == 7;
+}
+
+int test_extfrag(void){
+ U32 result = 0;
+ if (countNodes() == 1){
+ result |= BIT(0);
+ }
+
+ void *p[10];
+
+ p[0] = mem_alloc(12);
+ p[1] = mem_alloc(12);
+ p[2] = mem_alloc(12);
+ p[3] = mem_alloc(12);
+ p[4] = mem_alloc(16);
+ p[5] = mem_alloc(12);
+ p[6] = mem_alloc(18);
+
+ if (countNodes() == 8){
+ result |= BIT(1);
+ }
+
+ mem_dealloc(p[2]);
+ p[7] = mem_alloc(15);
+
+ if (countNodes() == 9){
+ result |= BIT(2);
+ }
+
+ mem_dealloc(p[4]);
+ p[8] = mem_alloc(18);
+
+ if (countNodes() == 10){
+ result |= BIT(3);
+ }
+
+ if (mem_count_extfrag(12+12) == 0){
+ result |= BIT(4);
+ }
+
+ if (mem_count_extfrag(13+12) == 1){
+ result |= BIT(5);
+ }
+
+ if (mem_count_extfrag(17+12) == 2){
+ result |= BIT(6);
+ }
+
+ mem_dealloc(p[0]);
+ mem_dealloc(p[1]);
+
+ mem_dealloc(p[3]);
+
+ mem_dealloc(p[5]);
+ mem_dealloc(p[6]);
+ mem_dealloc(p[7]);
+ mem_dealloc(p[8]);
+
+ return result == 127;
+}
+
+int test_utilization(void) {
+ unsigned int totalUsed = 0;
+ unsigned int counter = 0;
+ unsigned int regionSize = 1048576;
+ unsigned int magicSize = 1070585247;
+
+ while(1){
+ if (mem_alloc(regionSize) == NULL) {
+ break;
+ }
+ totalUsed += regionSize;
+ counter++;
+ if(totalUsed > magicSize){
+ return -1;
+ }
+ }
+
+ unsigned int numAllocs = counter;
+ return 0;
+}
+
+int test_throughput(void){
+ for(int i = 0; i < 200; i++){
+ test_reuse_freed_2();
+ }
+ return 1;
+}
+
+int test_mem(void) {
+// Function Tests:
+// U32 result = 0;
+//
+// if(test_mem_leak()){
+// result |= BIT(0);
+// }
+// if(test_coales()){
+// result |= BIT(1);
+// }
+// if(test_reuse_freed()){
+// result |= BIT(2);
+// }
+// if(test_reuse_freed_2()){
+// result |= BIT(3);
+// }
+// if(test_malloc_new_node()){
+// result |= BIT(4);
+// }
+// if(test_extfrag()){
+// result |= BIT(5);
+// }
+//
+// return result == 63;
+
+// Throughput Test: (function needs to be updated
+// test_throughput();
+// return 1;
+
+// Utilization Test: Maxes out memory
+ int utilResult = test_utilization();
+ return 1;
+
+
+}
+
+
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab1/code/src/board/VE_A9/Serial.c b/submission/lab1/code/src/board/VE_A9/Serial.c
new file mode 100644
index 0000000..99f5fe5
--- /dev/null
+++ b/submission/lab1/code/src/board/VE_A9/Serial.c
@@ -0,0 +1,149 @@
+ /**************************************************************************//**
+ * @file Serial.c
+ * @brief Simple polled UART driver
+ * @version
+ * @date 27 October 2015
+ *
+ * @note
+ *
+ ******************************************************************************/
+/* Copyright (c) 2011 - 2015 ARM LIMITED
+
+ All rights reserved.
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ - Neither the name of ARM nor the names of its contributors may be used
+ to endorse or promote products derived from this software without
+ specific prior written permission.
+ *
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+ ---------------------------------------------------------------------------*/
+
+#include "Serial.h"
+
+void SER_Init(void)
+{
+ SER_Disable(); // Disable UART
+ SER_Set_baud_rate( 38400 );
+ UART0->UARTLCR_H = UART_LCRH_WLEN_8 | UART_LCRH_FEN; // 8 bits, 1 stop bit, no parity, FIFO enabled
+ SER_Enable(); // Enable UART and enable TX/RX
+}
+
+/*----------------------------------------------------------------------------
+ Enable Serial Port
+ *----------------------------------------------------------------------------*/
+void SER_Enable(void)
+{
+ UART0->UARTCR = UART_CR_UARTEN | UART_CR_TXE | UART_CR_RXE;
+}
+
+/*----------------------------------------------------------------------------
+ Disable Serial Port
+ *----------------------------------------------------------------------------*/
+void SER_Disable(void)
+{
+ UART0->UARTCR = 0x0;
+}
+
+/*----------------------------------------------------------------------------
+ Set baud rate
+ *----------------------------------------------------------------------------*/
+void SER_Set_baud_rate(uint32_t baud_rate)
+{
+ uint32_t divider;
+ uint32_t mod;
+ uint32_t fraction;
+
+ /*
+ * Set baud rate
+ *
+ * IBRD = UART_CLK / (16 * BAUD_RATE)
+ * FBRD = ROUND((64 * MOD(UART_CLK,(16 * BAUD_RATE))) / (16 * BAUD_RATE))
+ */
+ divider = UART0_CLK / (16 * baud_rate);
+ mod = UART0_CLK % (16 * baud_rate);
+ fraction = (((8 * mod) / baud_rate) >> 1) + (((8 * mod) / baud_rate) & 1);
+
+ UART0->UARTIBRD = divider;
+ UART0->UARTFBRD = fraction;
+}
+
+/*----------------------------------------------------------------------------
+ Write character to Serial Port
+ *----------------------------------------------------------------------------*/
+void SER_PutChar(char c)
+{
+ while (UART0->UARTFR & 0x20); // Wait for UART TX to become free
+ //if (c == '\n')
+ //{
+ // UART0->UARTDR = '\r';
+ // while (UART0->UARTFR & 0x20);
+ //}
+ UART0->UARTDR = c;
+}
+
+/* HYQS */
+
+/*----------------------------------------------------------------------------
+ Write String to Serial Port
+ *----------------------------------------------------------------------------*/
+int SER_PutStr(char *s)
+{
+ if (s == NULL)
+ return 1;
+ while (*s !=0) { /* loop through each char in the string */
+ SER_PutChar(*s++);/* print the char, then ptr increments */
+ }
+ return 0;
+}
+/*----------------------------------------------------------------------------
+ * Call back function for printf
+ *----------------------------------------------------------------------------*/
+/**
+ * @brief call back function for printf
+ * @note first parameter p is not used for now. Polling UART is used
+ */
+
+void putc(void *p, char c)
+{
+ if ( p != NULL ) {
+ SER_PutStr("putc: first parameter needs to be NULL");
+ } else {
+ SER_PutChar(c);
+ }
+}
+
+/* HYQE */
+
+/*----------------------------------------------------------------------------
+ Read character from Serial Port (blocking read)
+ *----------------------------------------------------------------------------*/
+char SER_GetChar (void)
+{
+ while (UART0->UARTFR & 0x10); // Wait for a character to arrive
+ return UART0->UARTDR;
+}
+
+/*----------------------------------------------------------------------------
+ Serial UART interrupt handler
+ *----------------------------------------------------------------------------*/
+void interrupt_SER(void)
+{
+ //your code here
+}
+
diff --git a/submission/lab1/code/src/board/VE_A9/Serial.h b/submission/lab1/code/src/board/VE_A9/Serial.h
new file mode 100644
index 0000000..6cc11d3
--- /dev/null
+++ b/submission/lab1/code/src/board/VE_A9/Serial.h
@@ -0,0 +1,161 @@
+ /**************************************************************************//**
+ * @file Serial.h
+ * @brief Simple polled UART driver. Needs to be completed
+ * @version
+ * @date 07 February 2013
+ *
+ * @note
+ *
+ ******************************************************************************/
+/* Copyright (c) 2011 - 2013 ARM LIMITED
+
+ All rights reserved.
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ - Neither the name of ARM nor the names of its contributors may be used
+ to endorse or promote products derived from this software without
+ specific prior written permission.
+ *
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+ ---------------------------------------------------------------------------*/
+
+#ifndef SERIAL_H_
+#define SERIAL_H_
+
+typedef unsigned char uint8_t;
+typedef unsigned short int uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned __int64 uint64_t;
+
+#define __RO volatile const
+#define __WO volatile
+#define __RW volatile
+
+/* UART - Register Layout Typedef */
+typedef struct {
+ __RW uint32_t UARTDR; /*0x000 Data Register*/
+ __RW uint32_t UARTRSR_UARTECR; /*0x004 Receive Status Register/Error Clear Register */
+ uint32_t RESERVED_0[4]; /*0x008 - 0x014*/
+ __RO uint32_t UARTFR; /*0x018 Flag Register*/
+ uint32_t RESERVED_1; /*0x01c*/
+ __RW uint32_t UARTILPR; /*0x020 IrDA Low-Power Counter Register*/
+ __RW uint32_t UARTIBRD; /*0x024 Integer Baud Rate Register */
+ __RW uint32_t UARTFBRD; /*0x028 Fractional Baud Rate Register*/
+ __RW uint32_t UARTLCR_H; /*0x02c Line Control Register */
+ __RW uint32_t UARTCR; /*0x030 Control Register*/
+ __RW uint32_t UARTIFLS; /*0x034 Interrupt FIFO Level Select Register*/
+ __RW uint32_t UARTIMSC; /*0x038 Interrupt Mask Set/Clear Register*/
+ __RO uint32_t UARTRIS; /*0x03c Raw Interrupt Status Register*/
+ __RO uint32_t UARTMIS; /*0x040 Masked Interrupt Status Register*/
+ __WO uint32_t UARTICR; /*0x044 Interrupt Clear Register*/
+ __RW uint32_t UARTDMACR; /*0x048 DMA Control Register*/
+ uint32_t RESERVED_2[13]; /*0x04c - 0x07c*/
+ uint32_t RESERVED_T[4]; /*0x080 - 0x08c*/
+ uint32_t RESERVED_3[976]; /*0x090 - 0xfcc*/
+ uint32_t RESERVED_4[4]; /*0xfd0 - 0xfdc*/
+ __RO uint32_t UARTPeriphID0; /*0xfe0 UARTPeriphID0 Register*/
+ __RO uint32_t UARTPeriphID1; /*0xfe4 UARTPeriphID1 Register*/
+ __RO uint32_t UARTPeriphID2; /*0xfe8 UARTPeriphID2 Register*/
+ __RO uint32_t UARTPeriphID3; /*0xfec UARTPeriphID3 Register*/
+ __RO uint32_t UARTCellID0; /*0xff0 UARTCellID0 Register*/
+ __RO uint32_t UARTCellID1; /*0xff4 UARTCellID1 Register*/
+ __RO uint32_t UARTCellID2; /*0xff8 UARTCellID2 Register*/
+ __RO uint32_t UARTCellID3; /*0xffc UARTCellID3 Register*/
+} UART_Type;
+
+
+/* Line control register */
+#define UART_LCRH_SPS (1 << 7)
+#define UART_LCRH_WLEN_8 (3 << 5)
+#define UART_LCRH_WLEN_7 (2 << 5)
+#define UART_LCRH_WLEN_6 (1 << 5)
+#define UART_LCRH_WLEN_5 (0 << 5)
+#define UART_LCRH_FEN (1 << 4)
+#define UART_LCRH_STP2 (1 << 3)
+#define UART_LCRH_EPS (1 << 2)
+#define UART_LCRH_PEN (1 << 1)
+#define UART_LCRH_BRK (1 << 0)
+
+
+/* Control Register */
+#define UART_CR_CTSEN (1 << 15)
+#define UART_CR_RTSEN (1 << 14)
+#define UART_CR_OUT2 (1 << 13)
+#define UART_CR_OUT1 (1 << 12)
+#define UART_CR_RTS (1 << 11)
+#define UART_CR_DTR (1 << 10)
+#define UART_CR_RXE (1 << 9)
+#define UART_CR_TXE (1 << 8)
+#define UART_CR_LPE (1 << 7)
+#define UART_CR_IIRLP (1 << 2)
+#define UART_CR_SIREN (1 << 1)
+#define UART_CR_UARTEN (1 << 0)
+
+
+/* Interrupt Mask Set/Clear Register */
+#define UART_IMSC_OEIM (1 << 10)
+#define UART_IMSC_BEIM (1 << 9)
+#define UART_IMSC_PEIM (1 << 8)
+#define UART_IMSC_FEIM (1 << 7)
+#define UART_IMSC_RTIM (1 << 6)
+#define UART_IMSC_TXIM (1 << 5)
+#define UART_IMSC_RXIM (1 << 4)
+#define UART_IMSC_DSRMIM (1 << 3)
+#define UART_IMSC_DCDMIM (1 << 2)
+#define UART_IMSC_CTSMIM (1 << 1)
+#define UART_IMSC_RIMIM (1 << 0)
+
+#define UART0_BASE (0x1C090000u) /* CS3 0x1C000000 + 0x090000 (VE ARM Cortex-A Series memory map) */
+#define UART0 ((UART_Type *)UART0_BASE)
+
+#define UART0_CLK 24000000 // 24MHz
+
+/* HYQS */
+#define BIT(X) ( 1 << (X) )
+#define NULL 0
+#define uart_init(n) SER_Init()
+#define uart_get_char(n) SER_GetChar()
+#define uart_put_char(n, c) SER_PutChar(c)
+#define uart_put_string(n, s) SER_PutStr(s)
+
+#define uart0_init() uart_init(0)
+#define uart0_get_char() uart_get_char(0)
+#define uart0_put_char(c) uart_put_char(0,c)
+#define uart0_put_string(s) uart_put_string(0,s)
+
+#define uart1_init() uart_init(1)
+#define uart1_get_char() uart_get_char(1)
+#define uart1_put_char(c) uart_put_char(1,c)
+#define uart1_put_string(s) uart_put_string(1,s)
+
+/* HYQE */
+
+
+extern void SER_Init(void);
+extern void SER_Enable(void);
+extern void SER_Disable(void);
+extern char SER_GetChar (void);
+extern void SER_PutChar(char c);
+extern void SER_Set_baud_rate(uint32_t baud_rate);
+extern void interrupt_SER(void);
+
+/* HYQS */
+extern int SER_PutStr(char *s);
+extern void putc(void *p, char c); /* call back function for printf, use uart1 */
+/* HYQE */
+#endif /* SERIAL_H_ */
diff --git a/submission/lab1/code/src/board/VE_A9/device_a9.h b/submission/lab1/code/src/board/VE_A9/device_a9.h
new file mode 100644
index 0000000..f954ff1
--- /dev/null
+++ b/submission/lab1/code/src/board/VE_A9/device_a9.h
@@ -0,0 +1,42 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ *
+ * This software is subject to an open source license and
+ * may be freely redistributed under the terms of MIT License.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file device_a9.h
+ * @brief Cortex-A9 device header file
+ *
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ *
+ *****************************************************************************/
+
+#ifndef DEVICE_A9_H_
+#define DEVICE_A9_H_
+
+/*
+ *===========================================================================
+ * MACROS
+ *===========================================================================
+ */
+
+#define NUM_PRIV_MODES 0x00000006 // 6 privileged modes
+#define STACK_SZ 0x00000200 // 512 B stack for each mode
+#define RAM_SIZE 0x40000000 // The VE9 has 2G RAM, we only use 1G
+#define RAM_END 0xFFFFFFFF // The VE9 RAM END
+
+#endif
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab1/code/src/board/VE_A9/printf.c b/submission/lab1/code/src/board/VE_A9/printf.c
new file mode 100644
index 0000000..0058d7c
--- /dev/null
+++ b/submission/lab1/code/src/board/VE_A9/printf.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2004,2012 Kustaa Nyholm / SpareTimeLabs
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * Neither the name of the Kustaa Nyholm or SpareTimeLabs nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#include "printf.h"
+
+typedef void (*putcf) (void*,char);
+static putcf stdout_putf;
+static void* stdout_putp;
+
+
+#ifdef PRINTF_LONG_SUPPORT
+
+static void uli2a(unsigned long int num, unsigned int base, int uc,char * bf)
+ {
+ int n=0;
+ unsigned int d=1;
+ while (num/d >= base)
+ d*=base;
+ while (d!=0) {
+ int dgt = num / d;
+ num%=d;
+ d/=base;
+ if (n || dgt>0|| d==0) {
+ *bf++ = dgt+(dgt<10 ? '0' : (uc ? 'A' : 'a')-10);
+ ++n;
+ }
+ }
+ *bf=0;
+ }
+
+static void li2a (long num, char * bf)
+ {
+ if (num<0) {
+ num=-num;
+ *bf++ = '-';
+ }
+ uli2a(num,10,0,bf);
+ }
+
+#endif
+
+static void ui2a(unsigned int num, unsigned int base, int uc,char * bf)
+ {
+ int n=0;
+ unsigned int d=1;
+ while (num/d >= base)
+ d*=base;
+ while (d!=0) {
+ int dgt = num / d;
+ num%= d;
+ d/=base;
+ if (n || dgt>0 || d==0) {
+ *bf++ = dgt+(dgt<10 ? '0' : (uc ? 'A' : 'a')-10);
+ ++n;
+ }
+ }
+ *bf=0;
+ }
+
+static void i2a (int num, char * bf)
+ {
+ if (num<0) {
+ num=-num;
+ *bf++ = '-';
+ }
+ ui2a(num,10,0,bf);
+ }
+
+static int a2d(char ch)
+ {
+ if (ch>='0' && ch<='9')
+ return ch-'0';
+ else if (ch>='a' && ch<='f')
+ return ch-'a'+10;
+ else if (ch>='A' && ch<='F')
+ return ch-'A'+10;
+ else return -1;
+ }
+
+static char a2i(char ch, char** src,int base,int* nump)
+ {
+ char* p= *src;
+ int num=0;
+ int digit;
+ while ((digit=a2d(ch))>=0) {
+ if (digit>base) break;
+ num=num*base+digit;
+ ch=*p++;
+ }
+ *src=p;
+ *nump=num;
+ return ch;
+ }
+
+static void putchw(void* putp,putcf putf,int n, char z, char* bf)
+ {
+ char fc=z? '0' : ' ';
+ char ch;
+ char* p=bf;
+ while (*p++ && n > 0)
+ n--;
+ while (n-- > 0)
+ putf(putp,fc);
+ while ((ch = *bf++) != '\0') /* This line is modified by Y. Huang to avoid assignment in condition warning */
+ putf(putp,ch);
+ }
+
+void tfp_format(void* putp,putcf putf,char *fmt, va_list va)
+ {
+ char bf[12];
+
+ char ch;
+
+
+ while ((ch = *(fmt++)) != '\0') { /* This line is modified by Y. Huang to avoid assignment in condition warning */
+ if (ch!='%')
+ putf(putp,ch);
+ else {
+ char lz=0;
+#ifdef PRINTF_LONG_SUPPORT
+ char lng=0;
+#endif
+ int w=0;
+ ch=*(fmt++);
+ if (ch=='0') {
+ ch=*(fmt++);
+ lz=1;
+ }
+ if (ch>='0' && ch<='9') {
+ ch=a2i(ch,&fmt,10,&w);
+ }
+#ifdef PRINTF_LONG_SUPPORT
+ if (ch=='l') {
+ ch=*(fmt++);
+ lng=1;
+ }
+#endif
+ switch (ch) {
+ case 0:
+ goto abort;
+ case 'u' : {
+#ifdef PRINTF_LONG_SUPPORT
+ if (lng)
+ uli2a(va_arg(va, unsigned long int),10,0,bf);
+ else
+#endif
+ ui2a(va_arg(va, unsigned int),10,0,bf);
+ putchw(putp,putf,w,lz,bf);
+ break;
+ }
+ case 'd' : {
+#ifdef PRINTF_LONG_SUPPORT
+ if (lng)
+ li2a(va_arg(va, unsigned long int),bf);
+ else
+#endif
+ i2a(va_arg(va, int),bf);
+ putchw(putp,putf,w,lz,bf);
+ break;
+ }
+ case 'x': case 'X' :
+#ifdef PRINTF_LONG_SUPPORT
+ if (lng)
+ uli2a(va_arg(va, unsigned long int),16,(ch=='X'),bf);
+ else
+#endif
+ ui2a(va_arg(va, unsigned int),16,(ch=='X'),bf);
+ putchw(putp,putf,w,lz,bf);
+ break;
+ case 'c' :
+ putf(putp,(char)(va_arg(va, int)));
+ break;
+ case 's' :
+ putchw(putp,putf,w,0,va_arg(va, char*));
+ break;
+ case '%' :
+ putf(putp,ch);
+ default:
+ break;
+ }
+ }
+ }
+ abort:;
+ }
+
+
+void init_printf(void* putp,void (*putf) (void*,char))
+ {
+ stdout_putf=putf;
+ stdout_putp=putp;
+ }
+
+void tfp_printf(char *fmt, ...)
+ {
+ va_list va;
+ va_start(va,fmt);
+ tfp_format(stdout_putp,stdout_putf,fmt,va);
+ va_end(va);
+ }
+
+static void putcp(void* p,char c)
+ {
+ *(*((char**)p))++ = c;
+ }
+
+
+
+void tfp_sprintf(char* s,char *fmt, ...)
+ {
+ va_list va;
+ va_start(va,fmt);
+ tfp_format(&s,putcp,fmt,va);
+ putcp(&s,0);
+ va_end(va);
+ }
diff --git a/submission/lab1/code/src/board/VE_A9/printf.h b/submission/lab1/code/src/board/VE_A9/printf.h
new file mode 100644
index 0000000..9723b0f
--- /dev/null
+++ b/submission/lab1/code/src/board/VE_A9/printf.h
@@ -0,0 +1,124 @@
+/*
+File: printf.h
+
+Copyright (c) 2004,2012 Kustaa Nyholm / SpareTimeLabs
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+Neither the name of the Kustaa Nyholm or SpareTimeLabs nor the names of its
+contributors may be used to endorse or promote products derived from this software
+without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+
+This library is realy just two files: 'printf.h' and 'printf.c'.
+
+They provide a simple and small (+200 loc) printf functionality to
+be used in embedded systems.
+
+I've found them so usefull in debugging that I do not bother with a
+debugger at all.
+
+They are distributed in source form, so to use them, just compile them
+into your project.
+
+Two printf variants are provided: printf and sprintf.
+
+The formats supported by this implementation are: 'd' 'u' 'c' 's' 'x' 'X'.
+
+Zero padding and field width are also supported.
+
+If the library is compiled with 'PRINTF_SUPPORT_LONG' defined then the
+long specifier is also
+supported. Note that this will pull in some long math routines (pun intended!)
+and thus make your executable noticably longer.
+
+The memory foot print of course depends on the target cpu, compiler and
+compiler options, but a rough guestimate (based on a H8S target) is about
+1.4 kB for code and some twenty 'int's and 'char's, say 60 bytes of stack space.
+Not too bad. Your milage may vary. By hacking the source code you can
+get rid of some hunred bytes, I'm sure, but personally I feel the balance of
+functionality and flexibility versus code size is close to optimal for
+many embedded systems.
+
+To use the printf you need to supply your own character output function,
+something like :
+
+void putc ( void* p, char c)
+ {
+ while (!SERIAL_PORT_EMPTY) ;
+ SERIAL_PORT_TX_REGISTER = c;
+ }
+
+Before you can call printf you need to initialize it to use your
+character output function with something like:
+
+init_printf(NULL,putc);
+
+Notice the 'NULL' in 'init_printf' and the parameter 'void* p' in 'putc',
+the NULL (or any pointer) you pass into the 'init_printf' will eventually be
+passed to your 'putc' routine. This allows you to pass some storage space (or
+anything realy) to the character output function, if necessary.
+This is not often needed but it was implemented like that because it made
+implementing the sprintf function so neat (look at the source code).
+
+The code is re-entrant, except for the 'init_printf' function, so it
+is safe to call it from interupts too, although this may result in mixed output.
+If you rely on re-entrancy, take care that your 'putc' function is re-entrant!
+
+The printf and sprintf functions are actually macros that translate to
+'tfp_printf' and 'tfp_sprintf'. This makes it possible
+to use them along with 'stdio.h' printf's in a single source file.
+You just need to undef the names before you include the 'stdio.h'.
+Note that these are not function like macros, so if you have variables
+or struct members with these names, things will explode in your face.
+Without variadic macros this is the best we can do to wrap these
+fucnction. If it is a problem just give up the macros and use the
+functions directly or rename them.
+
+For further details see source code.
+
+regs Kusti, 23.10.2004
+*/
+
+
+#ifndef __TFP_PRINTF__
+#define __TFP_PRINTF__
+
+#include
+
+void init_printf(void* putp,void (*putf) (void*,char));
+
+void tfp_printf(char *fmt, ...);
+void tfp_sprintf(char* s,char *fmt, ...);
+
+void tfp_format(void* putp,void (*putf) (void*,char),char *fmt, va_list va);
+
+#define printf tfp_printf
+#define sprintf tfp_sprintf
+
+#endif
+
+
+
diff --git a/submission/lab1/code/src/board/VE_A9/startup_a9.s b/submission/lab1/code/src/board/VE_A9/startup_a9.s
new file mode 100644
index 0000000..426d2a8
--- /dev/null
+++ b/submission/lab1/code/src/board/VE_A9/startup_a9.s
@@ -0,0 +1,209 @@
+;/*
+; ****************************************************************************
+; *
+; * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+; *
+; * Copyright (C) 2009-2018 ARM Limited.
+; * All rights reserved.
+; *
+; * Copyright 2020-2021 Yiqing Huang
+; *
+; * This software is subject to an open source license and
+; * may be freely redistributed under the terms of MIT License.
+; ****************************************************************************
+; */
+
+;/**************************************************************************//**
+; * @file startup_a9.s
+; * @brief modifed version of ARM startup_VE_A9_MP.s
+; *
+; * @version V1.2021.01
+; * @authors Yiqing Huang ARM
+; * @date 2021 JAN
+; * @note MMU part is taken out, simpify IRQ handlers.
+; * The device dependent content is the RAM_BASE,
+; * set it according to the specific device
+; * Other parts are generic to any A9 processor devices
+; *
+; *****************************************************************************/
+
+;/*********************************************************************************************
+; * @brief modifed version of ARM startup_VE_A9_MP.s
+; * @note MMU part is taken out, simpify IRQ handlers.
+; * The device dependent content is the RAM_BASE, set it according to the specific device
+; * Other parts are generic to any A9 processor devices
+; * This file references scatter file defined symbols, so it should be used together
+; * with the provided scatter file
+; *********************************************************************************************/
+
+RAM_BASE EQU 0x80000000 ; VE9
+SVC_Stack_Size EQU 0x00000000 ; we do not allocate SVC stack here, take it from g_k_stacks[0]
+
+;reset of exception mode stacks go to c routine to set up
+IRQ_Stack_Size EQU 0x00000000
+USR_Stack_Size EQU 0x00000000 ; user stacks will be set up by the kernel
+
+ISR_Stack_Size EQU (SVC_Stack_Size + IRQ_Stack_Size)
+
+;---------------------------------------------------------------------------
+; Stack, Heap for application using microlib
+;---------------------------------------------------------------------------
+
+ AREA STACK, NOINIT, READWRITE, ALIGN=3
+Stack_Mem SPACE USR_Stack_Size
+__initial_sp SPACE ISR_Stack_Size
+Stack_Top
+
+; Heap Configuration
+; Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
+;
+
+Heap_Size EQU 0x00000000
+
+ AREA HEAP, NOINIT, READWRITE, ALIGN=3
+__heap_base
+Heap_Mem SPACE Heap_Size
+__heap_limit
+
+;---------------------------------------------------------------------------
+; Code
+;---------------------------------------------------------------------------
+ PRESERVE8
+ ARM
+
+; Vector Table Mapped to Address 0 at Reset
+
+ AREA RESET, CODE, READONLY
+ EXPORT __Vectors
+ EXPORT __Vectors_End
+ EXPORT __Vectors_Size
+
+__Vectors LDR PC, Reset_Addr ; Address of Reset Handler
+ LDR PC, Undef_Addr ; Address of Undef Handler
+ LDR PC, SVC_Addr ; Address of SVC Handler
+ LDR PC, PAbt_Addr ; Address of Prefetch Abort Handler
+ LDR PC, DAbt_Addr ; Address of Data Abort Handler
+ NOP ; Reserved Vector
+ LDR PC, IRQ_Addr ; Address of IRQ Handler
+ LDR PC, FIQ_Addr ; Address of FIQ Handler
+__Vectors_End
+
+__Vectors_Size EQU __Vectors_End - __Vectors
+
+Reset_Addr DCD Reset_Handler
+Undef_Addr DCD Undef_Handler
+SVC_Addr DCD SVC_Handler
+PAbt_Addr DCD PAbt_Handler
+DAbt_Addr DCD DAbt_Handler
+IRQ_Addr DCD IRQ_Handler
+FIQ_Addr DCD FIQ_Handler
+
+
+
+
+ AREA |.text|, CODE, READONLY
+
+Reset_Handler PROC
+ EXPORT Reset_Handler [WEAK]
+ IMPORT StackInit
+ IMPORT SystemInit
+ IMPORT main
+ IMPORT g_k_stacks ; the kernel stack array symbol
+ IMPORT g_k_stack_size ; the kernel stack size for each task
+ LDR R0, =g_k_stacks ; R0 has the starting address of g_k_stacks[][] array
+ LDR R1, =g_k_stack_size ; R1 has the kernel stack size
+ LDR R1, [R1]
+ ADD R0, R0, R1 ; Move to the high address of the first task's stack
+ MOV SP, R0 ; Use the first task
+
+ ; Put any cores other than 0 to sleep
+ MRC p15, 0, R0, c0, c0, 5 ; Read MPIDR
+ ANDS R0, R0, #3
+goToSleep
+ WFINE
+ BNE goToSleep
+
+ MRC p15, 0, R0, c1, c0, 0 ; Read CP15 System Control register
+ BIC R0, R0, #(0x1 << 12) ; Clear I bit 12 to disable I Cache
+ BIC R0, R0, #(0x1 << 2) ; Clear C bit 2 to disable D Cache
+ BIC R0, R0, #0x1 ; Clear M bit 0 to disable MMU
+ BIC R0, R0, #(0x1 << 11) ; Clear Z bit 11 to disable branch prediction
+ BIC R0, R0, #(0x1 << 13) ; Clear V bit 13 to disable hivecs
+ MCR p15, 0, R0, c1, c0, 0 ; Write value back to CP15 System Control register
+ ISB
+
+; Configure ACTLR
+ MRC p15, 0, r0, c1, c0, 1 ; Read CP15 Auxiliary Control Register
+ ORR r0, r0, #(1 << 1) ; Enable L2 prefetch hint (UNK/WI since r4p1)
+ MCR p15, 0, r0, c1, c0, 1 ; Write CP15 Auxiliary Control Register
+; Set Vector Base Address Register (VBAR) to point to this application's vector table
+ LDR R0, =__Vectors
+ MCR p15, 0, R0, c12, c0, 0
+
+ LDR R0, =StackInit ; Initialize stack for each exception mode
+ BLX R0
+ LDR R0, =SystemInit
+ BLX R0 ; copy vector table, set up system clocks
+ LDR R0, =main
+ BLX main ; start the main function
+ B . ; loop if main ever returns
+ ENDP
+
+Undef_Handler PROC
+ EXPORT Undef_Handler [WEAK]
+ B .
+ ENDP
+
+PAbt_Handler PROC
+ EXPORT PAbt_Handler [WEAK]
+ B .
+ ENDP
+
+DAbt_Handler PROC
+ EXPORT DAbt_Handler [WEAK]
+ B .
+ ENDP
+
+SVC_Handler PROC
+ EXPORT SVC_Handler [WEAK]
+ B .
+ ENDP
+
+IRQ_Handler PROC
+ EXPORT IRQ_Handler [WEAK]
+ B .
+ ENDP
+
+FIQ_Handler PROC
+ EXPORT FIQ_Handler [WEAK]
+ B .
+ ENDP
+
+; User Initial Stack & Heap
+
+ IF :DEF:__MICROLIB
+
+ EXPORT __initial_sp
+ EXPORT __heap_base
+ EXPORT __heap_limit
+
+ ELSE
+
+ IMPORT __use_two_region_memory
+ EXPORT __user_initial_stackheap
+__user_initial_stackheap
+
+ LDR R0, = Heap_Mem
+ LDR R1, = (Stack_Mem + USR_Stack_Size)
+ LDR R2, = (Heap_Mem + Heap_Size)
+ LDR R3, = Stack_Mem
+ BX LR
+
+ ENDIF
+
+ END
+;/*
+; *===========================================================================
+; * END OF FILE
+; *===========================================================================
+; */
diff --git a/submission/lab1/code/src/board/VE_A9/system_a9.c b/submission/lab1/code/src/board/VE_A9/system_a9.c
new file mode 100644
index 0000000..c7a8677
--- /dev/null
+++ b/submission/lab1/code/src/board/VE_A9/system_a9.c
@@ -0,0 +1,60 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ *
+ * This software is subject to an open source license and
+ * may be freely redistributed under the terms of MIT License.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file system_a9.c
+ * @brief Generic Cortex-A9 CMSIS System Initialization Source
+ *
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ *
+ * @attention
+ * @note
+ * @details
+ *
+ *****************************************************************************/
+
+#include "device_a9.h"
+#include "k_HAL_CA.h"
+
+// statically allocated initial stacks except for SVC mode
+U32 g_stacks[NUM_PRIV_MODES - 1][STACK_SZ >> 2];
+
+/**************************************************************************//**
+ * @brief Set up stacks for each privileged mode except for SVC mode
+ * @see startup_a9.s Reset_Handler
+ *****************************************************************************/
+void StackInit(void) {
+ int i = 0;
+ __set_SP_MODE((U32) (g_stacks[++i]), MODE_SYS);
+ __set_SP_MODE((U32) (g_stacks[++i]), MODE_IRQ);
+ __set_SP_MODE((U32) (g_stacks[++i]), MODE_FIQ);
+ __set_SP_MODE((U32) (g_stacks[++i]), MODE_ABT);
+ __set_SP_MODE((U32) (g_stacks[++i]), MODE_UND);
+}
+
+/**************************************************************************//**
+ * @brief Setup the system.
+ * Initialize the System and update the SystemCoreClock variable.
+ * @note not needed for lab1 or lab2
+ *****************************************************************************/
+
+void SystemInit(void) {
+ // 1. copy vector table , not needed for VE9
+ // 2. TODO set up system clocks for devices, not needed for lab1 or lab2
+}
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab1/code/src/board/VE_A9/system_a9.h b/submission/lab1/code/src/board/VE_A9/system_a9.h
new file mode 100644
index 0000000..113261d
--- /dev/null
+++ b/submission/lab1/code/src/board/VE_A9/system_a9.h
@@ -0,0 +1,44 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ *
+ * This software is subject to an open source license and
+ * may be freely redistributed under the terms of MIT License.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file system_a9.h
+ * @brief Coretx-A9 Generic CMSIS System Initialization
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ * @note
+ * @details
+ *
+ *****************************************************************************/
+#ifndef _SYSTEM_A9_H
+#define _SYSTEM_A9_H
+
+/*
+ *===========================================================================
+ * FUNCTION PROTOTYPES
+ *===========================================================================
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+extern void StackInit (void);
+extern void SystemInit (void);
+
+#endif /* _SYSTEM_A9_H */
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab1/code/src/kernel/HAL_CA.c b/submission/lab1/code/src/kernel/HAL_CA.c
new file mode 100644
index 0000000..87c891a
--- /dev/null
+++ b/submission/lab1/code/src/kernel/HAL_CA.c
@@ -0,0 +1,184 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ *
+ * This software is subject to an open source license and
+ * may be freely redistributed under the terms of MIT License.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file HAL.c
+ * @brief Hardware Abstraction Layer for Cortex-A series
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ *
+ * @note This file contains embedded assembly.
+ * The code borrowed ideas from ARM RTX source code
+ *
+ *****************************************************************************/
+
+#include "common.h"
+#include "k_inc.h"
+#include "k_HAL_CA.h"
+
+#pragma push
+#pragma arm
+
+/**************************************************************************//**
+ * @brief assembly labels that all embedded assembly code can refer to
+ * @note This function should not be called
+ *****************************************************************************/
+__asm void __asm_symbols(void)
+{
+Mode_USR EQU 0x10
+Mode_FIQ EQU 0x11
+Mode_IRQ EQU 0x12
+Mode_SVC EQU 0x13
+Mode_ABT EQU 0x17
+Mode_UND EQU 0x1B
+Mode_SYS EQU 0x1F
+
+I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled
+F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled
+T_Bit EQU 0x20 ; when T bit is set, core is in Thumb state
+
+}
+
+/**************************************************************************//**
+ * @brief disable both IRQ and FIQ
+ * @post IRQ and FIQ disabled
+ * TODO needs more testing
+ *****************************************************************************/
+__asm void __atomic_on(void)
+{
+ PRESERVE8
+ PUSH {R4, LR}
+ MRS R4, CPSR
+ ORR R4, #I_Bit:OR:F_Bit ; set both I and F bits
+ MSR CPSR_c, R4
+ POP {R4, PC}
+}
+
+/**************************************************************************//**
+ * @brief enable both IRQ and FIQ
+ * @post IRQ and FIQ enabled
+ * TODO needs more testing
+ *****************************************************************************/
+__asm void __atomic_off(void)
+{
+ PRESERVE8
+ PUSH {R4, LR}
+ MRS R4, CPSR
+ BIC R4, #I_Bit:OR:F_Bit ; clear both I and F bits
+ MSR CPSR_c, R4
+ POP {R4, PC}
+}
+#pragma pop
+
+/**************************************************************************//**
+ * @brief change processor mode
+ *
+ * @param mode the processor mode numerical value
+ * @post processor mode changes if caller is not in USR mode
+ *
+ *****************************************************************************/
+#pragma push
+#pragma arm
+__asm void __ch_MODE (U32 mode) {
+ ARM
+ PUSH {R1, R4}
+ MOV R1, LR
+ MSR CPSR_csxf, R0 ; no effect in USR mode
+ ISB ; flushes the pipeline in the processor
+ MOV LR, R1
+ POP {R1, R4}
+ BX LR
+}
+#pragma pop
+
+/**************************************************************************//**
+ * @brief set the stack of a given mode
+ *
+ * @param sp the stack pointer to be set
+ * @param mode the mode of the sp
+ * @post SP_MODE updated if caller is not in USR mode
+ *
+ * TODO: needs more testing
+ *
+ *****************************************************************************/
+#pragma push
+#pragma arm
+
+/**
+ * @brief set the stack of a given mode
+ * @pre: the mode is a valid mode, caller checks
+ * @post: processor retains the mode before the function is called
+ */
+__asm void __set_SP_MODE (U32 sp, U32 mode) {
+ ARM
+
+ PUSH {R4, LR}
+ MRS R4, CPSR ; save CPSR in R4
+ MSR CPSR_csxf, R1 ; R1 contains the mode, no effect in USR mode
+ ISB ; flushes the pipeline in the processor
+ MOV SP, R0 ; R0 contains SP to be set
+ MSR CPSR_c, R4 ; restore CPSR, no effect in USR mode
+ ISB ; flushes the pipline in the processor
+ POP {R4, PC}
+}
+
+#pragma pop
+
+/**************************************************************************//**
+ * @brief SVC Handler (i.e. trap handler)
+ * @pre The caller should be in USR/SYS mode
+ * R12 contains trap table mapped kernel function entry point
+ *****************************************************************************/
+#pragma push
+#pragma arm
+__asm void SVC_Handler (void)
+{
+
+ PRESERVE8 ; 8 bytes alignement of the stack
+ ARM
+ EXPORT SVC_RESTORE
+
+SVC_SAVE
+ SRSFD SP!, #Mode_SVC ; Push LR_SVC and SPSR_SVC onto SVC mode stack
+ SUB SP, SP, #56
+ STM SP, {R0-R12, SP}^ ; push SP_USR and R0 - R12 onto the kernel stack
+
+ ;// extract SVC number, only handles #0
+ MRS R4,SPSR ; Get SPSR
+ TST R4,#CPSR_T_BIT ; Check Thumb Bit
+ LDRNEH R4,[LR,#-2] ; Thumb: Load Halfword
+ BICNE R4,R4,#0xFF00 ; Extract SVC Number
+ MRS R4,SPSR ; Get SPSR
+ LDREQ R4,[LR,#-4] ; ARM: Load Word
+ BICEQ R4,R4,#0xFF000000 ; Extract SVC Number
+
+ CMP R4,#0
+ BNE SVC_EXIT ; if not SVC #0, go to SVC_EXIT
+
+ BLX R12 ; invoke the corresponding c kernel function
+
+SVC_RESTORE
+ STR R0, [SP] ; save the function return value on R0 that is on top of the stack
+
+SVC_EXIT
+ LDM SP, {R0-R12, SP}^
+ ADD SP, SP, #56 ; restore SP_USR and R0-R12 from their saved values on the stack
+ RFEFD SP! ; Return from exception
+}
+#pragma pop
+
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab1/code/src/kernel/k_HAL_CA.h b/submission/lab1/code/src/kernel/k_HAL_CA.h
new file mode 100644
index 0000000..726f986
--- /dev/null
+++ b/submission/lab1/code/src/kernel/k_HAL_CA.h
@@ -0,0 +1,102 @@
+/*----------------------------------------------------------------------------
+ * CMSIS-RTOS - RTX
+ *----------------------------------------------------------------------------
+ * Name: k_HAL_CA.H
+ * Purpose: Hardware Abstraction Layer for Cortex-A definitions
+ * Rev.: V4.82 plus changes for RTX-Ax
+ * Notes: modified by yqhuang@uwaterloo.ca for ECE350 Lab Project
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2015 ARM Germany GmbH, 2012-2017 ARM Limited
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+#ifndef K_HAL_CA_H_
+#define K_HAL_CA_H_
+
+#include
+
+/*
+ *===========================================================================
+ * MACROS
+ *===========================================================================
+ */
+
+#define INIT_CPSR_SYS 0x4000001F
+#define INIT_CPSR_USER 0x40000010
+#define INIT_CPSR_SVC 0x40000013
+
+#define CPSR_T_BIT 0x20
+#define CPSR_I_BIT 0x80
+#define CPSR_F_BIT 0x40
+
+#define MODE_USR 0x10
+#define MODE_FIQ 0x11
+#define MODE_IRQ 0x12
+#define MODE_SVC 0x13
+#define MODE_ABT 0x17
+#define MODE_UND 0x1B
+#define MODE_SYS 0x1F
+
+/*
+ *===========================================================================
+ * TYPEDEFS
+ *===========================================================================
+ */
+
+typedef uint32_t U32;
+
+/*
+ *===========================================================================
+ * FUNCTION PROTOTYPES
+ *===========================================================================
+ */
+
+/* START: ECE350 Functions */
+extern void __set_SP_MODE (U32 sp, U32 mode);
+extern void __ch_MODE (U32 mode);
+extern void __atomic_on(void);
+extern void __atomic_off(void);
+
+static __inline uint32_t __get_CPSR(void) {
+ register uint32_t __regCPSR __asm("cpsr");
+ return (__regCPSR);
+}
+
+static __inline char __get_mode(void)
+{
+ return (char)(__get_CPSR() & 0x1FU);
+}
+
+/* END: ECE350 Functions */
+
+#endif // ! K_HAL_CA_H_
+
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
+
diff --git a/submission/lab1/code/src/kernel/k_inc.h b/submission/lab1/code/src/kernel/k_inc.h
new file mode 100644
index 0000000..632ab91
--- /dev/null
+++ b/submission/lab1/code/src/kernel/k_inc.h
@@ -0,0 +1,53 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ *
+ * This software is subject to an open source license and
+ * may be freely redistributed under the terms of MIT License.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file k_inc.h
+ * @brief Kernel Macros and Data Structure Header file
+ * l2
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ *
+ * @note all kernel .c files include this one
+ *
+ *****************************************************************************/
+
+#ifndef K_INC_H_
+#define K_INC_H_
+
+#include "device_a9.h"
+#include "common.h"
+
+/*
+ *==========================================================================
+ * GLOBAL VARIABLES DECLARATIONS
+ *==========================================================================
+ */
+// Memory related globals are defined in k_mem.c
+
+// kernel stack size
+extern const U32 g_k_stack_size;
+// task kernel stacks are statically allocated inside the OS image
+
+extern U32 g_k_stacks[MAX_TASKS][KERN_STACK_SIZE >> 2] __attribute__((aligned(8)));
+
+extern unsigned int Image$$ZI_DATA$$ZI$$Limit; // Linker defined symbol
+ // See ARM Compiler User Guide 5.x
+
+#endif // ! K_INC_H_
+
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab1/code/src/kernel/k_mem.c b/submission/lab1/code/src/kernel/k_mem.c
new file mode 100644
index 0000000..8e942bc
--- /dev/null
+++ b/submission/lab1/code/src/kernel/k_mem.c
@@ -0,0 +1,256 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ *
+ * This software is subject to an open source license and
+ * may be freely redistributed under the terms of MIT License.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file k_mem.c
+ * @brief Kernel Memory Management API C Code
+ *
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ *
+ * @note skeleton code
+ *
+ *****************************************************************************/
+
+/**
+ * @brief: k_mem.c kernel API implementations, this is only a skeleton.
+ * @author: Yiqing Huang
+ */
+
+#include "k_mem.h"
+#include "Serial.h"
+#ifdef DEBUG_0
+#include "printf.h"
+#endif /* DEBUG_0 */
+
+
+/*
+ *==========================================================================
+ * STRUCTS
+ *==========================================================================
+ */
+
+typedef struct Node {
+ unsigned int size;
+ int isFree;
+ struct Node *next;
+} Node;
+
+/*
+ *==========================================================================
+ * GLOBAL VARIABLES
+ *==========================================================================
+ */
+// kernel stack size, referred by startup_a9.s
+const U32 g_k_stack_size = KERN_STACK_SIZE;
+
+// task kernel stacks
+U32 g_k_stacks[MAX_TASKS][KERN_STACK_SIZE >> 2] __attribute__((aligned(8)));
+Node* HEAD = NULL;
+
+/*
+ *===========================================================================
+ * FUNCTIONS
+ *===========================================================================
+ */
+
+void print_list() {
+ Node* curr = HEAD;
+ while (curr) {
+ printf("location: 0x%x, size: %x, free: %x\r\n", (U32)curr, (U32)curr->size, curr->isFree);
+ curr = curr->next;
+ }
+}
+
+int k_mem_init(void) {
+ unsigned int end_addr = (unsigned int) &Image$$ZI_DATA$$ZI$$Limit;
+//#ifdef DEBUG_0
+// printf("k_mem_init: image ends at 0x%x\r\n", end_addr);
+// printf("k_mem_init: RAM ends at 0x%x\r\n", RAM_END);
+//#endif /* DEBUG_0 */
+
+ //check if end addr is valid
+ unsigned int totalSize = 0xBFFFFFFF - end_addr;
+ if(totalSize <= 0) {
+ return RTX_ERR;
+ }
+
+ // round end_addr to nearest 4
+ if (end_addr % 4 != 0) {
+ end_addr = ((unsigned int)(end_addr / 4)) * 4 + 4;
+ }
+
+ // cast end_addr to pointer given in end_addr
+ HEAD = (Node*) end_addr;
+
+ // setup head
+ HEAD->size = totalSize - sizeof(Node);
+ HEAD->isFree = 1;
+ HEAD->next = NULL;
+
+ return RTX_OK;
+}
+
+void* k_mem_alloc(size_t size) {
+//#ifdef DEBUG_0
+// printf("k_mem_alloc: requested memory size = %d\r\n", size);
+//#endif /* DEBUG_0 */
+
+ if (size == 0) {
+ return NULL;
+ }
+
+ // 4 byte align
+ if (size % 4 != 0) {
+ size = ((unsigned int)(size / 4)) * 4 + 4;
+ }
+
+ Node* curr = HEAD;
+
+ while(curr != NULL) {
+ if (size <= curr->size && curr->isFree) {
+ break;
+ }
+ curr = curr->next;
+ }
+
+ // couldn't allocate since no free space
+ if (curr == NULL) {
+ return NULL;
+ }
+
+ if (size == curr->size){
+ return (void*)((U32)curr + sizeof(Node));
+ } else if (size < curr->size && (curr->size < (size + sizeof(Node)))) {
+ return (void*)((U32)curr + sizeof(Node));
+ } else {
+ //make a new node
+ // might need to use an unsigned depending on how types work
+ Node* newNode = (Node*)((unsigned int)curr + sizeof(Node) + size);
+ newNode->isFree = 1;
+ newNode->size = curr->size - size - sizeof(Node);
+ newNode->next = curr->next;
+
+ curr->isFree=0;
+ curr->size = size;
+ curr->next = newNode;
+ // Cast curr to U32 to ensure pointer arithmetic works
+ // Pointer addition works by adding by increment of sizeof the pointer
+ // argument. If curr is of type Node* and we add sizeof(Node), we add
+ // sizeof(Node)^2 amount of bytes.
+ return (void*)((U32)curr + sizeof(Node));
+ }
+}
+
+Node* mergeNode(Node* first, Node* second) {
+ if (first > second) {
+ return NULL;
+ }
+
+ Node* result = first;
+ result->size = first->size + second->size + sizeof(Node);
+ result->next = second->next;
+
+ return result;
+}
+
+int k_mem_dealloc(void *ptr) {
+//#ifdef DEBUG_0
+// printf("k_mem_dealloc: freeing 0x%x\r\n", (U32) ptr);
+//#endif /* DEBUG_0 */
+
+ Node* curr = HEAD;
+ Node* prev = NULL;
+
+ while (ptr != (char*)curr + sizeof(Node)) {
+ if (curr->next == NULL) {
+ return RTX_ERR;
+ }
+
+ prev = curr;
+ curr = curr->next;
+// printf("0x%x\n", (U32)((char*)curr + sizeof(Node) + curr->size));
+ }
+
+ // Double free
+ if (curr->isFree > 0) {
+ return RTX_ERR;
+ }
+
+ curr->isFree = 1;
+
+ // Merge neighboring nodes
+ if (prev && prev->isFree > 0) {
+ curr = mergeNode(prev, curr);
+ }
+
+ if (curr->next && curr->next->isFree > 0) {
+ curr = mergeNode(curr, curr->next);
+ }
+
+// print_list();
+
+ return RTX_OK;
+}
+
+int k_mem_count_extfrag(size_t size) {
+//#ifdef DEBUG_0
+// printf("k_mem_extfrag: size = %d\r\n", size);
+//#endif /* DEBUG_0 */
+ // return RTX_OK;
+
+ unsigned int memRegionSize;
+ int regionCount = 0;
+
+ Node* curNode = HEAD; // HEAD is global var
+
+ while(curNode != NULL){
+ memRegionSize = curNode->size + sizeof(Node);
+ if(curNode->isFree){
+ if(memRegionSize < size){
+ regionCount++;
+ }
+ }
+ curNode = curNode->next; // idk if this is the right way to goto next node
+ }
+
+ return regionCount;
+}
+
+int countNodes(){
+ Node* n = HEAD;
+ int ret = 0;
+ while(n != NULL) {
+ ret += 1;
+ n = n->next;
+ }
+ return ret;
+}
+
+int memLeakCheck(){
+ unsigned int howMuchMem = 0;
+ Node* curNode = HEAD;
+ while(curNode != NULL){
+ howMuchMem += curNode->size + sizeof(Node);
+ curNode = curNode->next;
+ }
+ unsigned int end_addr = (unsigned int) &Image$$ZI_DATA$$ZI$$Limit;
+ unsigned int totalSize = 0xBFFFFFFF - end_addr;
+ return howMuchMem == totalSize;
+}
+
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab1/code/src/kernel/k_mem.h b/submission/lab1/code/src/kernel/k_mem.h
new file mode 100644
index 0000000..fc6f02a
--- /dev/null
+++ b/submission/lab1/code/src/kernel/k_mem.h
@@ -0,0 +1,48 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ *
+ * This software is subject to an open source license and
+ * may be freely redistributed under the terms of MIT License.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file k_mem.h
+ * @brief Kernel Memory Management API Header File
+ *
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ *
+ * @note skeleton code
+ *
+ *****************************************************************************/
+
+
+#ifndef K_MEM_H_
+#define K_MEM_H_
+#include "k_inc.h"
+
+/*
+ * ------------------------------------------------------------------------
+ * FUNCTION PROTOTYPES
+ * ------------------------------------------------------------------------
+ */
+int k_mem_init (void);
+void *k_mem_alloc (size_t size);
+int k_mem_dealloc (void *ptr);
+int k_mem_count_extfrag (size_t size);
+int countNodes (void);
+int memLeakCheck (void);
+#endif // ! K_MEM_H_
+
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
+
diff --git a/submission/lab1/code/src/kernel/k_rtx.h b/submission/lab1/code/src/kernel/k_rtx.h
new file mode 100644
index 0000000..293bc4b
--- /dev/null
+++ b/submission/lab1/code/src/kernel/k_rtx.h
@@ -0,0 +1,41 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ *
+ * This software is subject to an open source license and
+ * may be freely redistributed under the terms of MIT License.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file k_rtx.h
+ * @brief Kernel API Header File
+ * l2
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ *
+ * @note all kernel .c files include this one
+ *
+ *****************************************************************************/
+
+#ifndef K_RTX_H_
+#define K_RTX_H_
+#if 0
+#include "k_rtx_init.h"
+#include "k_task.h"
+#endif
+
+#include "k_mem.h"
+#if 0
+#include "k_msg.h"
+#endif
+#endif /* ! K_RTX_H_ */
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab1/code/src/kernel/main_svc.c b/submission/lab1/code/src/kernel/main_svc.c
new file mode 100644
index 0000000..6d1c6b1
--- /dev/null
+++ b/submission/lab1/code/src/kernel/main_svc.c
@@ -0,0 +1,98 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ *
+ * This software is subject to an open source license and
+ * may be freely redistributed under the terms of MIT License.
+ ****************************************************************************
+ */
+
+
+/**************************************************************************//**
+ * @file: main_svc.c
+ * @brief: main routine to start up the RTX and two initial tasks
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ * @note standard C library is not allowed in the final kernel code.
+ * A tiny printf function for embedded application development
+ * taken from http://www.sparetimelabs.com/tinyprintf/tinyprintf.php
+ * is configured to use UART0 to output when DEBUG_0 is defined.
+ * The init_printf(NULL, putc) MUST be called to initialize
+ * the printf function.
+ *****************************************************************************/
+
+
+#include "ae.h"
+#include "system_a9.h"
+#include "Serial.h"
+#include "printf.h"
+#include "k_inc.h"
+#include "k_rtx.h"
+#include "k_HAL_CA.h"
+
+
+void task_null (void)
+{
+ for ( int i = 0; i < 5; i++ ){
+ printf("==============Task NULL===============\r\n");
+ }
+ while (1);
+}
+
+int main()
+{
+ RTX_SYS_INFO sys_info;
+ RTX_TASK_INFO task_info[2];
+ char mode = 0;
+
+ // CMSIS system initialization
+ SystemInit();
+
+ __atomic_on();
+ SER_Init(); // uart1 uses polling for output
+ init_printf(NULL, putc); // printf uses uart1 for output
+ __atomic_off();
+
+ mode = __get_mode();
+ printf("mode = 0x%x\r\n", mode);
+
+ __ch_MODE(MODE_SYS);
+ mode = __get_mode();
+ printf("mode = 0x%x\r\n", mode);
+
+ __ch_MODE(MODE_USR);
+ mode = __get_mode();
+ printf("mode = 0x%x\r\n", mode);
+
+ __ch_MODE(MODE_SYS);
+ mode = __get_mode();
+ printf("mode = 0x%x\r\n", mode);
+
+ // System and Task set up by auto testing software
+ if (ae_init(&sys_info, task_info, 2) != RTX_OK) {
+ printf("RTX INIT FAILED\r\n");
+ return RTX_ERR;
+ }
+
+ int ret = mem_init();
+ if (ret != RTX_OK) {
+ printf("mem_init failed.\r\n");
+ return RTX_ERR;
+ }
+
+ printf("test result = %d\r\n", ae_start());
+
+ task_null();
+
+ // We should never reach here!!!
+ return RTX_ERR;
+}
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab1/code/template.c b/submission/lab1/code/template.c
new file mode 100644
index 0000000..0a31dda
--- /dev/null
+++ b/submission/lab1/code/template.c
@@ -0,0 +1,83 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ *
+ * This software is subject to an open source license and
+ * may be freely redistributed under the terms of MIT License.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file a
+ * @brief
+ *
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ *
+ * @attention
+ * @note
+ * @details
+ *
+ *****************************************************************************/
+
+/**************************************************************************//**
+ * @brief fn
+ *
+ * @return
+ * @param
+ * @param p1
+ * @pre
+ * @post
+ *
+ * @note
+ * @attention
+ *****************************************************************************/
+
+/*
+ *===========================================================================
+ * MACROS
+ *===========================================================================
+ */
+
+
+/*
+ *==========================================================================
+ * GLOBAL VARIABLES
+ *==========================================================================
+ */
+
+
+/*
+ *===========================================================================
+ * TYPEDEFS
+ *===========================================================================
+ */
+
+
+/*
+ *===========================================================================
+ * STRUCTURES
+ *===========================================================================
+ */
+
+
+
+/*
+ *===========================================================================
+ * FUNCTION PROTOTYPES
+ *===========================================================================
+ */
+
+/*------------------------------------------------------------------------*
+ * brief description inside a function
+ *------------------------------------------------------------------------*/
+
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab1/p1_report.pdf b/submission/lab1/p1_report.pdf
new file mode 100644
index 0000000..270f6ce
Binary files /dev/null and b/submission/lab1/p1_report.pdf differ
diff --git a/submission/lab2/README.md b/submission/lab2/README.md
new file mode 100644
index 0000000..d720670
--- /dev/null
+++ b/submission/lab2/README.md
@@ -0,0 +1,12 @@
+## ECE 350 RTX Project Repository
+
+Group 51
+
+## File structures
+
+### `code`
+This directory contains the ARM DS project files.
+
+
+### Lab report
+The lab report p2_report.pdf can be found under the current lab2 directory.
diff --git a/submission/lab2/code/TMTarget.launch b/submission/lab2/code/TMTarget.launch
new file mode 100755
index 0000000..7be9780
--- /dev/null
+++ b/submission/lab2/code/TMTarget.launch
@@ -0,0 +1,257 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/submission/lab2/code/scatter1.sct b/submission/lab2/code/scatter1.sct
new file mode 100755
index 0000000..340e71d
--- /dev/null
+++ b/submission/lab2/code/scatter1.sct
@@ -0,0 +1,29 @@
+;**************************************************
+; Copyright (c) 2013 ARM Ltd. All rights reserved.
+; Modified by yqhuang@uwaterloo.ca for ECE350 LAB
+;**************************************************
+
+; Scatter-file for RTX on Versatile Express
+
+; This scatter-file places application code, data, stack and heap at suitable addresses in the memory map.
+
+; This platform has 2GB SDRAM starting at 0x80000000.
+
+;#include "mem_ARMCA9.h"
+
+SDRAM 0x80000000 0x40000000
+{
+ VECTORS +0 0x200000
+ {
+ * (RESET, +FIRST) ; Vector table and other (assembler) startup code
+ * (InRoot$$Sections) ; All (library) code that must be in a root region
+ * (+RO-CODE) ; Application RO code (.text)
+ * (+RO-DATA) ; Application RO data (.constdata)
+ }
+
+ RW_DATA 0x80200000 0x100000
+ { * (+RW) } ; Application RW data (.data)
+
+ ZI_DATA 0x80300000 0x100000
+ { * (+ZI) } ; Application ZI data (.bss)
+}
diff --git a/submission/lab2/code/scatter_DE1_SoC.sct b/submission/lab2/code/scatter_DE1_SoC.sct
new file mode 100755
index 0000000..fca830b
--- /dev/null
+++ b/submission/lab2/code/scatter_DE1_SoC.sct
@@ -0,0 +1,29 @@
+;**************************************************
+; Copyright (c) 2013 ARM Ltd. All rights reserved.
+; Modified by z99gao@uwaterloo.ca for ECE350 LAB
+;**************************************************
+
+; Scatter-file for RTX on DE1 SoC
+
+; This scatter-file places application code, data, stack and heap at suitable addresses in the memory map.
+
+; This platform has 1GB SDRAM starting at 0x100000.
+
+;#include "mem_ARMCA9.h"
+
+SDRAM 0x100000 0x40000000
+{
+ VECTORS +0 0x200000
+ {
+ * (RESET, +FIRST) ; Vector table and other (assembler) startup code
+ * (InRoot$$Sections) ; All (library) code that must be in a root region
+ * (+RO-CODE) ; Application RO code (.text)
+ * (+RO-DATA) ; Application RO data (.constdata)
+ }
+
+ RW_DATA +0 0x200000
+ { * (+RW) } ; Application RW data (.data)
+
+ ZI_DATA +0 0x200000
+ { * (+ZI) } ; Application ZI data (.bss)
+}
diff --git a/submission/lab2/code/setup_scatter_file.txt b/submission/lab2/code/setup_scatter_file.txt
new file mode 100755
index 0000000..3bca1df
--- /dev/null
+++ b/submission/lab2/code/setup_scatter_file.txt
@@ -0,0 +1,7 @@
+Right click project folder in the Project Explorer
+ -> Properties -> C/C++ Build -> Settings -> Arm Linker 5 -> Image Layout
+
+Image entry point (--entry): __Vectors
+Scatter file (--scatter) : "${workspace_loc:/${ProjName}/scatter1.sct}"
+
+Note you need to put the double quotes around the location of the scatter file.
\ No newline at end of file
diff --git a/submission/lab2/code/src/INC/common.h b/submission/lab2/code/src/INC/common.h
new file mode 100755
index 0000000..b426705
--- /dev/null
+++ b/submission/lab2/code/src/INC/common.h
@@ -0,0 +1,219 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice and the following disclaimer.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file common.h
+ * @brief Common macros and structures for both kernel and user
+ *
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ * @see rtx.h
+ * @attention DO NOT MODIFY
+ *
+ * @note If you want to define your own macros and data structures,
+ * add them to common_ext.h.
+ * Do not let your newly-added code cause conflicts with
+ * the existing code in this file.
+ * For example, if you want to define new message types,
+ * use a value starting from 10.
+ * Do not overwrite existing message type macro values.
+ *
+ *****************************************************************************/
+
+#ifndef COMMON_H_
+#define COMMON_H_
+
+
+/*
+ *===========================================================================
+ * MACROS
+ *===========================================================================
+ */
+
+#define TRUE 1
+#define FALSE 0
+#define NULL 0
+#define RTX_ERR -1
+#define RTX_OK 0
+
+/* Memory Algorithms */
+#define FIXED_POOL 0
+#define FIRST_FIT 1 /* only requires to implement this one */
+#define BEST_FIT 2
+#define WORST_FIT 3
+
+/* Main Scheduling Algorithms */
+#define DEFAULT 0 /* strict-priority, FCFS scheduling */
+#define RM_PS 10 /* rate-monotonic scheduling with polling server */
+#define RM_NPS 11 /* rate-Monotonic scheduling without polling server */
+#define EDF 12 /* earliest-deadline-first scheduling */
+
+#define TID_NULL 0 /* pre-defined Task ID for null task */
+#define TID_KCD 15 /* pre-defined Task ID for KCD task */
+#define TID_DISPLAY 14 /* pre-defined Task ID for DISPLAY task */
+#define TID_UART_IRQ 0xFF /* reserved TID for UART IRQ handler which is not a task */
+#define TID_TIMER_IRQ 0xFE /* reserved TID for Timer IRQ handler, which is not a task */
+#define MAX_TASKS 16 /* maximum number of tasks in the system */
+#define KERN_STACK_SIZE 0x200 /* task kernel stack size in bytes */
+#define PROC_STACK_SIZE 0x200 /* task proc space stack size in bytes */
+
+/* Real-time Task Priority. Highest in the system*/
+#define PRIO_RT 0 /* priority level for real-time tasks */
+#define HIGH 100
+#define MEDIUM 101
+#define LOW 102
+#define LOWEST 103
+#define PRIO_NULL 255 /* hidden priority for null task */
+
+/* Task States */
+#define DORMANT 0 /* terminated task state */
+#define READY 1 /* A ready to run task that has been executed */
+#define RUNNING 2 /* Executing */
+#define BLK_MEM 3 /* blocked on requesting memory, not used in labs 1-5 */
+#define BLK_MSG 4 /* blocked on receiving a message */
+#define SUSPENDED 5 /* Suspended task */
+
+/* Message Passing Macros */
+/* Message Types */
+#define DEFAULT 0 /* a general purpose message */
+#define KCD_REG 1 /* a command registration message */
+#define KCD_CMD 2 /* a message that contains a command */
+#define DISPLAY 3 /* a message that contains chars to be displayed to the RTX console */
+#define KEY_IN 4 /* keyboard input from console */
+
+/* Message Data Sizes */
+#define MIN_MSG_SIZE 1 /* minimum message size in bytes */
+
+/* Mailbox Sizes */
+#define MIN_MBX_SIZE 1 /* minimum mailbox size in bytes */
+
+/* Time Macros */
+#define MIN_RTX_QTM 100 /* minimum time granularity of RTX in microseconds */
+
+
+/*
+ *===========================================================================
+ * TYPEDEFS
+ *===========================================================================
+ */
+
+typedef signed char S8;
+typedef unsigned char U8;
+typedef short S16;
+typedef unsigned short U16;
+typedef int S32;
+typedef unsigned int U32;
+typedef long long S64;
+typedef unsigned long long U64;
+typedef unsigned char BIT;
+typedef unsigned int BOOL;
+typedef unsigned int size_t;
+typedef signed int ssize_t;
+typedef unsigned char task_t;
+
+
+/*
+ *===========================================================================
+ * STRUCTURES
+ *===========================================================================
+ */
+
+/**
+ * @brief Timing structure
+ */
+struct timeval_rt {
+ U32 sec; /**> seconds */
+ U32 usec; /**> microoseconds */
+};
+
+/**
+ * @brief scheduling server structure
+ */
+typedef struct polling_server {
+ struct timeval_rt p_n; /**< period of the server */
+ struct timeval_rt b_n; /**< budget of the server */
+} POLLING_SERVER;
+
+/**
+ * @brief RTX system configuration structure
+ */
+typedef struct rtx_sys_info {
+ U32 rtx_time_qtm; /**< time granularity in microseconds */
+ POLLING_SERVER server; /**< scheduling server for non-real-time tasks */
+ U8 sched; /**< scheduler */
+} RTX_SYS_INFO;
+
+/**
+ * @brief message buffer header struct
+ */
+typedef struct rtx_msg_hdr {
+ U32 length; /**> length of the mssage including the message header size */
+ U32 type; /**> type of the message */
+} RTX_MSG_HDR;
+
+/**
+ * @brief Task information structure
+ */
+typedef struct rtx_task_info {
+ void (*ptask)(); /**> task entry address */
+ U32 k_sp; /**> current kernel stack pointer */
+ U32 k_stack_hi; /**> kernel stack base (high addr.) */
+ U32 u_sp; /**> current user stack pointer */
+ U32 u_stack_hi; /**> user stack base addr. (high addr.) */
+ U16 k_stack_size; /**> kernel stack size in bytes */
+ U16 u_stack_size; /**> user stack size in bytes */
+ task_t tid; /**> task ID */
+ U8 prio; /**> execution priority */
+ U8 state; /**> task state */
+ U8 priv; /**> = 0 unprivileged, =1 privileged */
+ struct timeval_rt tv_cpu; /**> task execution cpu time */
+ struct timeval_rt tv_wall; /**> task execution wall clock time */
+
+ /* The following only applies to real-time tasks */
+ struct timeval_rt p_n; /**> period in seconds and microseconds */
+ RTX_MSG_HDR *msg_hdr; /**> real-time task message header */
+ U32 num_msgs; /**> real-time task mailbox capacity */
+} RTX_TASK_INFO;
+
+/**
+ * @brief Real-time task information structure
+ */
+typedef struct task_rt {
+ struct timeval_rt p_n; /**> period in seconds and microseconds */
+ void (*task_entry)(); /**> task entry address */
+ U16 u_stack_size; /**> user stack size in bytes */
+ U8 priv; /**> = 0 unprivileged, =1 privileged */
+} TASK_RT;
+
+#endif // ! COMMON_H_
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab2/code/src/INC/common_ext.h b/submission/lab2/code/src/INC/common_ext.h
new file mode 100755
index 0000000..94ceebe
--- /dev/null
+++ b/submission/lab2/code/src/INC/common_ext.h
@@ -0,0 +1,81 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice and the following disclaimer.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file common_ext.h
+ * @brief Extended common macros and structures for both kernel and user
+ * for students to add self-defined macros and structures
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ *
+ * @see common.h
+ *
+ * @note If you want to define your own macros and data structures,
+ * add them to common_ext.h.
+ * Do not let your newly-added code cause conflicts with
+ * the existing code in this file.
+ * For example, if you want to define new message types,
+ * use a value starting from 10.
+ * Do not overwrite existing message type macro values.
+ *
+ *****************************************************************************/
+
+/*
+ *===========================================================================
+ * MACROS
+ *===========================================================================
+ */
+
+/*
+ *===========================================================================
+ * TYPEDEFS
+ *===========================================================================
+ */
+
+
+/*
+ *===========================================================================
+ * STRUCTURES
+ *===========================================================================
+ */
+
+
+
+ /*
+ *===========================================================================
+ * FUNCTION PROTOTYPES
+ *===========================================================================
+ */
+
+
+ /*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab2/code/src/INC/rtx.h b/submission/lab2/code/src/INC/rtx.h
new file mode 100755
index 0000000..c9d5dc1
--- /dev/null
+++ b/submission/lab2/code/src/INC/rtx.h
@@ -0,0 +1,186 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice and the following disclaimer.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file rtx.h
+ * @brief RTX User API header file
+ *
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ * @see common.h
+ * @see common_ext.h
+ *
+ * @attention DO NOT MODIFY
+ *
+ *****************************************************************************/
+
+#ifndef _RTX_H_
+#define _RTX_H_
+
+#include "common.h"
+#include "common_ext.h"
+
+/*
+ *===========================================================================
+ * MACROS
+ *===========================================================================
+ */
+#define __SVC_0 __svc_indirect(0)
+
+/*
+ *===========================================================================
+ * FUNCTION PROTOTYPES
+ *===========================================================================
+ */
+
+/*------------------------------------------------------------------------*
+ * Memory Management Functions - LAB1
+ *------------------------------------------------------------------------*/
+
+/* __SVC_0 can be put at the end of the function declaration */
+/* memory management */
+extern int k_mem_init(void);
+#define mem_init() _mem_init((U32)k_mem_init)
+extern int _mem_init(U32 p_func) __SVC_0;
+
+extern void *k_mem_alloc(size_t size);
+#define mem_alloc(size) _mem_alloc((U32)k_mem_alloc, size)
+extern void *_mem_alloc(U32 p_func, size_t size) __SVC_0;
+
+extern int k_mem_dealloc(void *);
+#define mem_dealloc(ptr) _mem_dealloc((U32)k_mem_dealloc, ptr)
+extern int _mem_dealloc(U32 p_func, void *ptr) __SVC_0;
+
+extern int k_mem_count_extfrag(size_t size);
+#define mem_count_extfrag(size) _mem_count_extfrag((U32)k_mem_count_extfrag, size)
+extern int _mem_count_extfrag(U32 p_func, size_t size) __SVC_0;
+
+/*------------------------------------------------------------------------*
+ * System Initialization Function(s) - LAB2, LAB4, LAB5
+ *------------------------------------------------------------------------*/
+
+/* Note __SVC_0 can also be put in the front of the function name*/
+/*task management */
+extern int k_rtx_init(RTX_TASK_INFO *tsk_info, int num_tasks);
+#define rtx_init(tsk_info, num_tasks) _rtx_init((U32)k_rtx_init, tsk_info, num_tasks)
+extern int __SVC_0 _rtx_init(U32 p_func, RTX_TASK_INFO *tsk_info, int num_tasks);
+
+extern int k_rtx_init_rt(RTX_SYS_INFO *sys_info, RTX_TASK_INFO *task_info, int num_tasks);
+#define rtx_init_rt(sys_info, task_info, num_tasks) _rtx_init_rt((U32)k_rtx_init_rt, sys_info, task_info, num_tasks)
+extern int __SVC_0 _rtx_init_rt(U32 p_func, RTX_SYS_INFO *sys_info, RTX_TASK_INFO *task_info, int num_tasks);
+
+extern int k_get_sys_info(RTX_SYS_INFO *buffer);
+#define get_sys_info(buffer) _get_sys_info((U32)k_get_sys_info, buffer)
+extern int __SVC_0 _get_sys_info(U32 p_func, RTX_SYS_INFO *buffer);
+
+/*------------------------------------------------------------------------*
+ * Task Management Functions - LAB2, LAB4, LAB5
+ *------------------------------------------------------------------------*/
+
+extern int k_tsk_yield(void);
+#define tsk_yield() _tsk_yield((U32)k_tsk_yield)
+extern int __SVC_0 _tsk_yield(U32 p_func);
+
+extern int k_tsk_create(task_t *task, void (*task_entry)(void), U8 prio, U16 stack_size);
+#define tsk_create(task, task_entry, prio, stack_size) _tsk_create((U32)k_tsk_create, task, task_entry, prio, stack_size)
+extern int __SVC_0 _tsk_create(U32 p_func, task_t *task, void (*task_entry)(void), U8 prio, U16 stack_size);
+
+extern void k_tsk_exit(void);
+#define tsk_exit() _tsk_exit((U32)k_tsk_exit)
+extern void __SVC_0 _tsk_exit(U32 p_func);
+
+extern int k_tsk_set_prio(task_t task_id, U8 prio);
+#define tsk_set_prio(task_id, prio) _tsk_set_prio((U32)k_tsk_set_prio, task_id, prio)
+extern int __SVC_0 _tsk_set_prio(U32 p_func, task_t task_id, U8 prio);
+
+extern int k_tsk_get(task_t task_id, RTX_TASK_INFO *buffer);
+#define tsk_get(task_id, buffer) _tsk_get((U32)k_tsk_get, task_id, buffer)
+extern int __SVC_0 _tsk_get(U32 p_func, task_t task_id, RTX_TASK_INFO *buffer);
+
+extern int k_tsk_ls(task_t *buf, int count);
+#define tsk_ls(buf, count) _tsk_ls((U32)k_tsk_ls, buf, count);
+extern int __SVC_0 _tsk_ls(U32 p_func, task_t *buf, int count);
+
+/*------------------------------------------------------------------------*
+ * Real-Time Task Functions - LAB4, LAB5
+ *------------------------------------------------------------------------*/
+
+extern int k_tsk_create_rt(task_t *tid, TASK_RT *task, RTX_MSG_HDR *msg_hdr, U32 num_msgs);
+#define tsk_create_rt(tid, task, msg_hdr, num_msgs) _tsk_create_rt((U32)k_tsk_create_rt, tid, task, msg_hdr, num_msgs)
+extern int __SVC_0 _tsk_create_rt(U32 p_func, task_t *tid, TASK_RT *task, RTX_MSG_HDR *msg_hdr, U32 num_msgs);
+
+extern void k_tsk_done_rt(void);
+#define tsk_done_rt() _tsk_done_rt((U32)k_tsk_done_rt)
+extern void __SVC_0 _tsk_done_rt(U32 p_func);
+
+extern void k_tsk_suspend(struct timeval_rt *tv);
+#define tsk_suspend(tv) _tsk_suspend((U32) k_tsk_suspend, tv)
+extern void __SVC_0 _tsk_suspend(U32 p_func, struct timeval_rt *tv);
+
+
+/*------------------------------------------------------------------------*
+ * Interprocess Communication Functions - LAB3, LAB4
+ *------------------------------------------------------------------------*/
+
+extern int k_mbx_create(size_t size);
+#define mbx_create(size) _mbx_create((U32)k_mbx_create, size)
+extern int __SVC_0 _mbx_create(U32 p_func, size_t size);
+
+extern int k_send_msg(task_t tid, const void* buf);
+#define send_msg(tid, buf) _send_msg((U32)k_send_msg, tid, buf)
+extern int __SVC_0 _send_msg(U32 p_func, task_t tid, const void *buf);
+
+extern int k_recv_msg(task_t *tid, void *buf, size_t len);
+#define recv_msg(tid, buf, len) _recv_msg((U32)k_recv_msg, tid, buf, len)
+extern int __SVC_0 _recv_msg(U32 p_func, task_t *tid, void *buf, size_t len);
+
+extern int k_recv_msg_nb(task_t *tid, void *buf, size_t len);
+#define recv_msg_nb(tid, buf, len) _recv_msg_nb((U32)k_recv_msg_nb, tid, buf, len)
+extern int __SVC_0 _recv_msg_nb(U32 p_func, task_t *tid, void *buf, size_t len);
+
+extern int k_mbx_ls(task_t *buf, int count);
+#define mbx_ls(buf, count) _mbx_ls((U32)k_mbx_ls, buf, count);
+extern int __SVC_0 _mbx_ls(U32 p_func, task_t *buf, int count);
+
+/*------------------------------------------------------------------------*
+ * Timing Service Functions - LAB4
+ *------------------------------------------------------------------------*/
+
+extern int k_get_time(struct timeval_rt *tv);
+#define get_time(tv) _get_time((U32)k_get_time, tv)
+extern int __SVC_0 _get_time(U32 p_func, struct timeval_rt *tv);
+
+
+#endif // !_RTX_H_
+
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab2/code/src/app/ae.c b/submission/lab2/code/src/app/ae.c
new file mode 100755
index 0000000..963265b
--- /dev/null
+++ b/submission/lab2/code/src/app/ae.c
@@ -0,0 +1,133 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice and the following disclaimer.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file ae.c
+ * @brief Automated Evaluation (AE) Framework Source File
+ *
+ * @version V1.2021.01.lab2
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ *
+ * @attention
+ * @note
+ * @details
+ *
+ *****************************************************************************/
+
+#include "ae.h"
+
+/**************************************************************************//**
+ * @brief ae_init
+ * @return RTX_OK on success and RTX_ERR on failure
+ * @param[out] sys_info system initialization struct AE writes to
+ * @param[out] task_info boot-time tasks struct array AE writes to
+ *
+ *****************************************************************************/
+
+int ae_init(RTX_SYS_INFO *sys_info, RTX_TASK_INFO *task_info, int num_tasks) {
+ if (ae_set_sys_info(sys_info) != RTX_OK) {
+ return RTX_ERR;
+ }
+
+ ae_set_task_info(task_info, num_tasks);
+ return RTX_OK;
+}
+
+/**************************************************************************//**
+ * @brief fill the sys_info struct with system configuration info.
+ * @return RTX_OK on success and RTX_ERR on failure
+ * @param[out] sys_info system initialization struct AE writes to
+ *
+ *****************************************************************************/
+int ae_set_sys_info(RTX_SYS_INFO *sys_info) {
+ if (sys_info == NULL) {
+ return RTX_ERR;
+ }
+
+ // Scheduling sys info set up, only do DEFAULT in lab2
+ sys_info->sched = DEFAULT;
+
+ /************* NOT USED in LAB2 ********************
+ struct timeval_rt budget;
+ struct timeval_rt period;
+
+ budget.sec = 0;
+ budget.usec = MIN_RTX_QTM * 10;
+
+ period.sec = 0;
+ period.usec = MIN_RTX_QTM * 100;
+
+
+ sys_info->rtx_time_qtm = 10 * MIN_RTX_QTM;
+
+ sys_info->server.b_n = budget;
+ sys_info->server.p_n = period;
+ ****************************************************/
+ return RTX_OK;
+}
+
+/**************************************************************************//**
+ * @brief fill the tasks array with information
+ * @param[out] tasks An array of RTX_TASK_INFO elements to write to
+ * @param[in] num_tasks The length of tasks array
+ * @return None
+ *****************************************************************************/
+
+void ae_set_task_info(RTX_TASK_INFO *tasks, int num_tasks) {
+
+ if (tasks == NULL) {
+ return;
+ }
+
+ for (int i = 0; i < num_tasks; i++ ) {
+ tasks[i].u_stack_size = 0x0;
+ tasks[i].prio = HIGH;
+ tasks[i].priv = 1;
+ }
+
+// tasks[0].ptask = &priv_tasks_scheduling;
+// tasks[0].ptask = &priv_task_check_sp;
+// tasks[0].ptask = &priv_check_usp;
+ tasks[0].ptask = &priv_task_entry;
+
+ return;
+}
+
+/* only used in LAB1 */
+#ifdef AE_LAB1
+int ae_start(void) {
+ return test_mem();
+}
+#endif
+
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab2/code/src/app/ae.h b/submission/lab2/code/src/app/ae.h
new file mode 100755
index 0000000..05a15b9
--- /dev/null
+++ b/submission/lab2/code/src/app/ae.h
@@ -0,0 +1,78 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice and the following disclaimer.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ ****************************************************************************
+ */
+
+#ifndef AE_
+#define AE_
+
+#include "Serial.h"
+#include "printf.h"
+#include "rtx.h"
+#include "ae_priv_tasks.h"
+#include "ae_usr_tasks.h"
+
+/*
+ *===========================================================================
+ * FUNCTION PROTOTYPES
+ *===========================================================================
+ */
+
+/**************************************************************************//**
+ * @file ae.h
+ * @brief Automated Evaluation (AE) Framework Header File
+ *
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ *
+ * @attention
+ * @note
+ * @details
+ *
+ *****************************************************************************/
+
+/*
+ *===========================================================================
+ * FUNCTION PROTOTYPES
+ *===========================================================================
+ */
+
+int ae_init (RTX_SYS_INFO *sys_info, \
+ RTX_TASK_INFO *task_info, int num_tasks);
+int ae_set_sys_info (RTX_SYS_INFO *sys_info);
+void ae_set_task_info (RTX_TASK_INFO *tasks, int num_tasks);
+int ae_start(void);
+
+int test_mem(void);
+
+#endif // ! AE_
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
+
diff --git a/submission/lab2/code/src/app/ae_mem.c b/submission/lab2/code/src/app/ae_mem.c
new file mode 100755
index 0000000..c7a6953
--- /dev/null
+++ b/submission/lab2/code/src/app/ae_mem.c
@@ -0,0 +1,372 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice and the following disclaimer.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file ae_mem.c
+ * @brief memory lab auto-tester
+ *
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ *
+ *****************************************************************************/
+
+#include "rtx.h"
+#include "Serial.h"
+#include "printf.h"
+
+//TODO test out allocating and de-allocating the same task or a diff task
+
+// test 1
+// create tcb
+// malloc
+//dealloc
+// assert pass
+
+// test 2
+// create tcb 1
+// create tcb 2
+// malloc as tcb 1
+// switch to tcb 2
+// dealloc as tcb 2
+// assert rtx error
+
+// test 2
+// create tcb 1
+// create tcb 2 with privilidge
+// malloc as tcb 1
+// switch to tcb 2
+// dealloc as tcb 2
+// assert pass
+
+
+int test_coales(void) {
+ U32 result = 0;
+ if (countNodes()==1){
+ result |= BIT(0);
+ }
+
+ void *p[4];
+
+ p[0] = mem_alloc(12);
+ p[1] = mem_alloc(24);
+ p[2] = mem_alloc(48);
+
+ if (countNodes()==4){
+ result |= BIT(1);
+ }
+
+ mem_dealloc(p[1]);
+ if (countNodes()==4){
+ result |= BIT(2);
+ }
+
+ mem_dealloc(p[0]);
+ if (countNodes()==3){
+ result |= BIT(3);
+ }
+
+ mem_dealloc(p[2]);
+ if (countNodes()==1){
+ result |= BIT(4);
+ }
+
+ return result == 31;
+}
+
+int test_reuse_freed(void) {
+ void *p[4];
+ U32 result = 0;
+ if (countNodes()==1){
+ result |= BIT(0);
+ }
+
+ p[0] = mem_alloc(12);
+ p[1] = mem_alloc(24);
+ p[2] = mem_alloc(48);
+
+ if (countNodes()==4){
+ result |= BIT(1);
+ }
+
+ mem_dealloc(p[0]);
+ if (countNodes()==4){
+ result |= BIT(2);
+ }
+
+ p[3] = mem_alloc(12);
+ if (countNodes()==4){
+ result |= BIT(3);
+ }
+
+ mem_dealloc(p[1]);
+ mem_dealloc(p[2]);
+ mem_dealloc(p[3]);
+ if (countNodes()==1){
+ result |= BIT(4);
+ }
+
+ if(memLeakCheck()==1){
+ result |= BIT(5);
+ }
+
+ return result == 63;
+}
+
+int test_reuse_freed_2(void) {
+ void *p[4];
+ U32 result = 0;
+ if (countNodes()==1){
+ result |= BIT(0);
+ }
+
+ p[0] = mem_alloc(12);
+ p[1] = mem_alloc(24);
+ p[2] = mem_alloc(48);
+
+ if (countNodes()==4){
+ result |= BIT(1);
+ }
+
+ mem_dealloc(p[1]);
+ if (countNodes()==4){
+ result |= BIT(2);
+ }
+
+ p[3] = mem_alloc(20);
+ if (countNodes()==4){
+ result |= BIT(3);
+ }
+
+ mem_dealloc(p[0]);
+ mem_dealloc(p[2]);
+ mem_dealloc(p[3]);
+ if (countNodes()==1){
+ result |= BIT(4);
+ }
+
+ if(memLeakCheck()==1){
+ result |= BIT(5);
+ }
+
+ return result == 63;
+}
+
+int test_malloc_new_node(void) {
+ void *p[4];
+ U32 result = 0;
+ if (countNodes()==1){
+ result |= BIT(0);
+ }
+
+ p[0] = mem_alloc(12);
+ p[1] = mem_alloc(60);
+ p[2] = mem_alloc(48);
+
+ if (countNodes()==4){
+ result |= BIT(1);
+ }
+
+ mem_dealloc(p[1]);
+ if (countNodes()==4){
+ result |= BIT(2);
+ }
+
+ p[3] = mem_alloc(12);
+ if (countNodes()==5){
+ result |= BIT(3);
+ }
+
+ mem_dealloc(p[3]);
+ if (countNodes()==4){
+ result |= BIT(4);
+ }
+
+ mem_dealloc(p[0]);
+ mem_dealloc(p[2]);
+ if (countNodes()==1){
+ result |= BIT(5);
+ }
+
+ if(memLeakCheck()==1){
+ result |= BIT(6);
+ }
+
+ return result == 127;
+}
+
+int test_mem_leak(){
+ void *p[4];
+ U32 result = 0;
+ if(memLeakCheck()==1){
+ result |= BIT(0);
+ }
+
+ p[0] = mem_alloc(12);
+
+ if(memLeakCheck()==1){
+ result |= BIT(1);
+ }
+
+ mem_dealloc(p[0]);
+
+ if(memLeakCheck()==1){
+ result |= BIT(2);
+ }
+
+ return result == 7;
+}
+
+int test_extfrag(void){
+ U32 result = 0;
+ if (countNodes() == 1){
+ result |= BIT(0);
+ }
+
+ void *p[10];
+
+ p[0] = mem_alloc(12);
+ p[1] = mem_alloc(12);
+ p[2] = mem_alloc(12);
+ p[3] = mem_alloc(12);
+ p[4] = mem_alloc(16);
+ p[5] = mem_alloc(12);
+ p[6] = mem_alloc(18);
+
+ if (countNodes() == 8){
+ result |= BIT(1);
+ }
+
+ mem_dealloc(p[2]);
+ p[7] = mem_alloc(15);
+
+ if (countNodes() == 9){
+ result |= BIT(2);
+ }
+
+ mem_dealloc(p[4]);
+ p[8] = mem_alloc(18);
+
+ if (countNodes() == 10){
+ result |= BIT(3);
+ }
+
+ if (mem_count_extfrag(12+12) == 0){
+ result |= BIT(4);
+ }
+
+ if (mem_count_extfrag(13+12) == 1){
+ result |= BIT(5);
+ }
+
+ if (mem_count_extfrag(17+12) == 2){
+ result |= BIT(6);
+ }
+
+ mem_dealloc(p[0]);
+ mem_dealloc(p[1]);
+
+ mem_dealloc(p[3]);
+
+ mem_dealloc(p[5]);
+ mem_dealloc(p[6]);
+ mem_dealloc(p[7]);
+ mem_dealloc(p[8]);
+
+ return result == 127;
+}
+
+//Default test mem
+int test_mem_default(void){
+ void *p[4];
+ int n;
+
+ U32 result = 0;
+
+ p[0] = mem_alloc(8);
+
+ if (p[0] != NULL) {
+ result |= BIT(0);
+ }
+
+ p[1] = mem_alloc(8);
+
+ if (p[1] != NULL && p[1] != p[0]) {
+ result |= BIT(1);
+ }
+
+ mem_dealloc(p[0]);
+ n = mem_count_extfrag(128);
+ if (n == 1) {
+ result |= BIT(2);
+ }
+
+ mem_dealloc(p[1]);
+ n = mem_count_extfrag(128);
+ if (n == 0) {
+ result |= BIT(3);
+ }
+ return result;
+}
+
+int test_utilization(void) {
+ unsigned int totalUsed = 0;
+ unsigned int counter = 0;
+ unsigned int regionSize = 1048576;
+ unsigned int magicSize = 1070585247;
+
+ while(1){
+ if (mem_alloc(regionSize) == NULL) {
+ break;
+ }
+ totalUsed += regionSize;
+ counter++;
+ if(totalUsed > magicSize){
+ return -1;
+ }
+ }
+
+ unsigned int numAllocs = counter;
+ return 0;
+}
+
+int test_throughput(void){
+ for(int i = 0; i < 200; i++){
+ test_reuse_freed_2();
+ }
+ return 1;
+}
+
+int test_mem(void) {
+ test_mem_default();
+}
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab2/code/src/app/ae_priv_tasks.c b/submission/lab2/code/src/app/ae_priv_tasks.c
new file mode 100755
index 0000000..71eaec1
--- /dev/null
+++ b/submission/lab2/code/src/app/ae_priv_tasks.c
@@ -0,0 +1,487 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice and the following disclaimer.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file priv_tasks.c
+ * @brief Two privileged tasks: priv_task1 and priv_task2
+ *
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ *
+ * @note Each task is in an infinite loop. These Tasks never terminate.
+ *
+ *****************************************************************************/
+
+#include "ae_priv_tasks.h"
+#include "ae_usr_tasks.h"
+#include "Serial.h"
+#include "printf.h"
+
+// We should print TCB array inside every function for testing?
+
+//------KERNEL TASKS------//
+// k_tsk_create
+// k_tsk_get
+
+// k_tsk_create until max_tasks (same priority)
+// k_tsk_get for all TIDs
+// k_tsk create > max_tasks should fail
+// k_tsk_exit
+// k_tsk_create should reuse TID
+
+// k_tsk_create
+// tsk_create
+// k_tsk_get
+// k_tsk_set_prio for kernel task
+// k_tsk_set_prio for user task
+// k_tsk_get
+// k_tsk_set_prio PRIO_NULL should fail
+// k_tsk_set_prio invalid TID should fail
+// k_tsk_set_prio dormant task should fail
+
+U32 result = 1;
+U32 numtests = 0;
+
+void printResult(int passFail){
+ numtests++;
+ if(passFail == 1){
+ SER_PutStr ("--- Success ---\n\r");
+ result << 1;
+ result += 1;
+ } else {
+ SER_PutStr ("--- !!! FAILURE !!! ---\n\r");
+ result << 1;
+ }
+}
+
+void priv_check_usp(void){
+
+ RTX_TASK_INFO task_info;
+ task_t tid;
+
+ // k_tsk_get(gp_current_task->tid, &task_info);
+ k_tsk_create(&tid, &dumdum, HIGH, 0x400);
+ k_tsk_yield();
+ //k_tsk_get(gp_current_task->tid, &task_info);
+ k_tsk_exit();
+}
+
+void priv_task_check_sp(void){
+ task_t tid1;
+ RTX_TASK_INFO task_info1;
+ RTX_TASK_INFO task_info2;
+
+ // 1. create new user task with high priority
+ // 2. yield to new user task
+ // 3. k_tsk_get() before new task has chance to SVC
+ // 3. user task
+ k_tsk_create(&tid1, &checkSP, HIGH, 0x400);
+ k_tsk_get(tid1, &task_info1);
+ k_tsk_yield();
+ k_tsk_get(tid1, &task_info2);
+ k_tsk_get(gp_current_task->tid, &task_info2);
+
+ while(1);
+}
+
+void testDataOwnership(void){
+ task_t owner;
+ task_t thief;
+
+ SER_PutStr ("Start of testDataOwnership\n\r");
+
+ k_tsk_create(&owner, &dataOwner, HIGH, 0x200);
+ k_tsk_create(&thief, &dataThief, HIGH, 0x200);
+
+ k_tsk_set_prio(1, MEDIUM);
+
+ k_tsk_yield();
+
+ SER_PutStr ("Melvin Capital Bad\n\r");
+
+ while(1);
+}
+
+void priv_task_entry(void){
+
+ RTX_TASK_INFO task_info;
+ task_t tid;
+
+ SER_PutStr (">>>>>>>>>>>>>>>>>>>>> 1. tsk_create Failure Test:\n\r");
+ SER_PutStr ("Stack Size Too Small:\n\r");
+ printResult(k_tsk_create(&tid, &dumdum, LOW, 0x100) == RTX_ERR);
+ SER_PutStr ("Stack Size Not 8b Aligned:\n\r");
+ printResult(k_tsk_create(&tid, &dumdum, LOW, 0x401) == RTX_ERR);
+ // SER_PutStr ("Stack Size Too Big:\n\r");
+ // printResult(k_tsk_create(&tid, &dumdum, LOW, 0xFFFFFF00) == RTX_ERR); // U16 stack_size
+ SER_PutStr ("Prio Invalid:\n\r");
+ printResult(k_tsk_create(&tid, &dumdum, 99, 0x400) == RTX_ERR);
+ SER_PutStr ("Prio Null:\n\r");
+ printResult(k_tsk_create(&tid, &dumdum, PRIO_NULL, 0x400) == RTX_ERR);
+ SER_PutStr ("Null tid:\n\r");
+ printResult(k_tsk_create(NULL, &dumdum, LOW, 0x400) == RTX_ERR);
+ SER_PutStr ("Null task:\n\r");
+ printResult(k_tsk_create(&tid, NULL, LOW, 0x400) == RTX_ERR);
+
+ if (result == 7){
+ printf(">>>>>>>>>> TESTS PASSED <<<<<<<<<<<< \n\r");
+ }else{
+ printf(">>>>>>>>>> TESTS FAILED: %d <<<<<<<<<<<< \n\r", 7 - result);
+ }
+
+ result = 1;
+
+ SER_PutStr (">>>>>>>>>>>>>>>>>>>>> 2. tsk_create and tsk_get Function Test:\n\r");
+ k_tsk_create(&tid, &dumdum, LOW, 0x400);
+ SER_PutStr ("Did we get tid 2:\n\r");
+ printResult(tid == 2); // 0 = NULL_TASK, 1 = Priv Task, 2 = dumdum
+ k_tsk_get(tid, &task_info);
+
+ SER_PutStr ("Compare kStack Size:\n\r");
+ printResult(task_info.k_stack_size == KERN_STACK_SIZE); // 0x200
+ SER_PutStr ("Compare uStack Size:\n\r");
+ printResult(task_info.u_stack_size == 0x400);
+ SER_PutStr ("Compare Task ID:\n\r");
+ printResult(task_info.tid == tid);
+ SER_PutStr ("Compare Priority:\n\r");
+ printResult(task_info.prio == LOW);
+ SER_PutStr ("Compare State:\n\r");
+ printResult(task_info.state == READY);
+ SER_PutStr ("Compare Privilege:\n\r");
+ printResult(task_info.priv == 0);
+ SER_PutStr ("Compare k stack pointer to k stack hi:\n\r");
+ printResult(task_info.k_sp == task_info.k_stack_hi);
+ SER_PutStr ("Compare u stack pointer to u stack hi:\n\r");
+ printResult(task_info.u_sp == task_info.u_stack_hi);
+
+ if (result == 10){
+ printf(">>>>>>>>>> TESTS PASSED <<<<<<<<<<<< \n\r");
+ }else{
+ printf(">>>>>>>>>> TESTS FAILED: %d <<<<<<<<<<<< \n\r", 10 - result);
+ }
+
+ result = 1;
+
+ SER_PutStr (">>>>>>>>>>>>>>>>>>>>> 3. tsk_get Failure Test:\n\r");
+ SER_PutStr ("Task ID 0:\n\r");
+ printResult(k_tsk_get(0, &task_info) == RTX_ERR);
+ SER_PutStr ("Null Buffer Task Info:\n\r");
+ printResult(k_tsk_get(tid, NULL) == RTX_ERR);
+ SER_PutStr ("Max Task ID:\n\r");
+ printResult(k_tsk_get(MAX_TASKS, &task_info) == RTX_ERR);
+ SER_PutStr ("Dormant Task 3:\n\r");
+ printResult(k_tsk_get(3, &task_info) == RTX_ERR);
+ SER_PutStr ("Dormant Task Mid:\n\r");
+ printResult(k_tsk_get(MAX_TASKS/2, &task_info) == RTX_ERR);
+
+ if (result == 6){
+ printf(">>>>>>>>>> TESTS PASSED <<<<<<<<<<<< \n\r");
+ }else{
+ printf(">>>>>>>>>> TESTS FAILED: %d <<<<<<<<<<<< \n\r", 6 - result);
+ }
+
+ result = 1;
+
+ SER_PutStr (">>>>>>>>>>>>>>>>>>>>> 4. set_prio Function Test:\n\r");
+ SER_PutStr ("Set user prio:\n\r");
+ k_tsk_set_prio(tid, LOWEST);
+ k_tsk_get(tid, &task_info);
+ printResult(task_info.prio == LOWEST);
+ SER_PutStr ("Set own prio:\n\r"); // Should be setting prio from med to hi
+ k_tsk_set_prio(1, HIGH);
+ k_tsk_get(1, &task_info);
+ printResult(task_info.prio == HIGH);
+
+ if (result == 3){
+ printf(">>>>>>>>>> TESTS PASSED <<<<<<<<<<<< \n\r");
+ }else{
+ printf(">>>>>>>>>> TESTS FAILED: %d <<<<<<<<<<<< \n\r", 3 - result);
+ }
+
+ result = 1;
+
+ SER_PutStr (">>>>>>>>>>>>>>>>>>>>> 5. set_prio Failure Test:\n\r");
+ SER_PutStr ("Task ID 0:\n\r");
+ printResult(k_tsk_set_prio(0, HIGH) == RTX_ERR);
+ SER_PutStr ("Null_Task Prio:\n\r");
+ printResult(k_tsk_set_prio(tid, PRIO_NULL) == RTX_ERR);
+ SER_PutStr ("Max Task ID:\n\r");
+ printResult(k_tsk_set_prio(MAX_TASKS, HIGH) == RTX_ERR);
+ SER_PutStr ("Dormant Task 3:\n\r");
+ printResult(k_tsk_set_prio(3, HIGH) == RTX_ERR);
+ SER_PutStr ("Dormant Task Mid:\n\r");
+ printResult(k_tsk_set_prio(MAX_TASKS/2, HIGH) == RTX_ERR);
+ SER_PutStr ("Undefined Priority:\n\r");
+ printResult(k_tsk_set_prio(tid, 99) == RTX_ERR);
+ // SER_PutStr ("Privilege Check:\n\r"); // THIS IS WILL PASS FOR KERNEL TASK
+ // printResult(k_tsk_set_prio(1, HIGH) == RTX_ERR);
+
+ if (result == 7){
+ printf(">>>>>>>>>> TESTS PASSED <<<<<<<<<<<< \n\r");
+ }else{
+ printf(">>>>>>>>>> TESTS FAILED: %d <<<<<<<<<<<< \n\r", 7 - result);
+ }
+
+ result = 1;
+
+ SER_PutStr (">>>>>>>>>>>>>>>>>>>>> 6. tsk_create Stress Test:\n\r");
+
+ // Testing max_tasks
+ for(int i = 3; i < MAX_TASKS; i++){ // 0 is Null Task, 1 is this kernel task
+ k_tsk_create(&tid, &dumdum, LOW, 0x200);
+ }
+
+ SER_PutStr ("Creating Another Task Fails:\n\r");
+ printResult(k_tsk_create(&tid, &dumdum, LOW, 0x400) == RTX_ERR);
+
+ // Testing max_tasks
+ for(int i = 3; i < MAX_TASKS; i++){ // 0 is Null Task, 1 is this kernel task
+ k_tsk_create(&tid, &dumdum, LOW, 0x200);
+ }
+
+ SER_PutStr ("Creating Another Task Fails:\n\r");
+ printResult(k_tsk_create(&tid, &dumdum, LOW, 0x400) == RTX_ERR);
+
+ if (result == 2){
+ printf(">>>>>>>>>> TESTS PASSED <<<<<<<<<<<< \n\r");
+ }else{
+ printf(">>>>>>>>>> TESTS FAILED: %d <<<<<<<<<<<< \n\r", 2 - result);
+ }
+
+ k_tsk_set_prio(gp_current_task->tid, LOWEST);
+ k_tsk_yield();
+
+ SER_PutStr (">>>>>>>>>>>>>>>>>>>>> 7. TCB Reuse Test:\n\r");
+
+ // Testing reusability
+ k_tsk_create(&tid, &dumdum, LOW, 0x400);
+ SER_PutStr ("Task id after full yield is 1\n\r");
+ printResult(tid == 2);
+ k_tsk_yield();
+ k_tsk_create(&tid, &dumdum, LOW, 0x400);
+ SER_PutStr ("Task id after full yield is 1\n\r");
+ printResult(tid == 2);
+
+ k_tsk_exit();
+}
+
+void reset_scheduling() {
+ for (int i = 0; i < 255; i++) {
+ s_buffer[i] = 0;
+ }
+}
+
+// Function to implement strcmp function
+int strcmp(const char *X, const char *Y)
+{
+ while(*X)
+ {
+ // if characters differ or end of second string is reached
+ if (*X != *Y)
+ break;
+
+ // move to next pair of characters
+ X++;
+ Y++;
+ }
+
+ // return the ASCII difference after converting char* to unsigned char*
+ return *(const unsigned char*)X - *(const unsigned char*)Y;
+}
+
+void priv_tasks_scheduling(void) {
+ /* Test 1:
+ * Create:
+ * 3 tasks with high priority,
+ * 3 tasks with medium priority,
+ * 3 tasks with low priority,
+ * 3 tasks with lowest priority
+ * Expect High 1 high 2 high 3 med 1 med 2 med 3 etc.
+ *
+ * Then:
+ * Create in order of h1, m1, l1, lw1 etc.
+ *
+ * Then:
+ * Create in order of lw1, l1, m1, h1 etc.
+ *
+ * Then:
+ * Create in order of lw3, m2, l1, h3, etc.
+ *
+ */
+
+ task_t tid[10];
+
+ reset_scheduling();
+
+ k_tsk_create(&tid[0], &stask0, HIGH, 10000);
+ k_tsk_create(&tid[1], &stask1, HIGH, 10000);
+ k_tsk_create(&tid[2], &stask2, HIGH, 10000);
+ k_tsk_create(&tid[3], &stask3, MEDIUM, 10000);
+ k_tsk_create(&tid[4], &stask4, MEDIUM, 10000);
+ k_tsk_create(&tid[5], &stask5, MEDIUM, 10000);
+ k_tsk_create(&tid[6], &stask6, LOW, 10000);
+ k_tsk_create(&tid[7], &stask7, LOW, 10000);
+ k_tsk_create(&tid[8], &stask8, LOWEST, 10000);
+ k_tsk_create(& tid[9], &stask9, LOWEST, 10000);
+
+ k_tsk_set_prio(gp_current_task->tid, LOWEST);
+
+ k_tsk_yield();
+
+ SER_PutStr("Scheduler output after yielding cpu.\n\r");
+ printResult(strcmp(s_buffer, "0123456789") == 0);
+
+ reset_scheduling();
+
+ k_tsk_create(&tid[0], &stask7, HIGH, 10000);
+ k_tsk_create(&tid[3], &stask2, MEDIUM, 10000);
+ k_tsk_create(&tid[6], &stask9, LOW, 10000);
+ k_tsk_create(&tid[7], &stask1, LOW, 10000);
+ k_tsk_create(&tid[8], &stask0, LOWEST, 10000);
+ k_tsk_create(&tid[4], &stask4, MEDIUM, 10000);
+ k_tsk_create(&tid[5], &stask5, MEDIUM, 10000);
+ k_tsk_create(&tid[1], &stask3, HIGH, 10000);
+ k_tsk_create(&tid[2], &stask6, HIGH, 10000);
+ k_tsk_create(&tid[8], &stask8, LOWEST, 10000);
+
+ k_tsk_set_prio(gp_current_task->tid, LOWEST);
+
+ k_tsk_yield();
+
+ SER_PutStr("Scheduler output after yielding cpu.\n\r");
+ printResult(strcmp(s_buffer, "7362459108") == 0);
+
+ reset_scheduling();
+
+ k_tsk_create(&tid[0], &stask0, HIGH, 10000);
+ k_tsk_create(&tid[1], &stask1, HIGH, 10000);
+ k_tsk_create(&tid[2], &stask2, HIGH, 10000);
+ k_tsk_create(&tid[3], &stask3, MEDIUM, 10000);
+ k_tsk_create(&tid[4], &stask4, MEDIUM, 10000);
+ k_tsk_create(&tid[5], &stask5, MEDIUM, 10000);
+ k_tsk_create(&tid[6], &stask6, LOW, 10000);
+ k_tsk_create(&tid[7], &stask7, LOW, 10000);
+ k_tsk_create(&tid[8], &stask8, LOWEST, 10000);
+ k_tsk_create(& tid[9], &stask9, LOWEST, 10000);
+
+ k_tsk_set_prio(tid[0], LOWEST);
+ k_tsk_set_prio(tid[1], LOWEST);
+ k_tsk_set_prio(tid[2], LOWEST);
+ k_tsk_set_prio(tid[1], MEDIUM);
+
+
+ k_tsk_yield();
+
+ SER_PutStr("Scheduler output after yielding cpu.\n\r");
+ printResult(strcmp(s_buffer, "3451678902") == 0);
+
+ while(1);
+
+ k_tsk_exit();
+}
+
+/**************************************************************************//**
+ * @brief a task that prints AAAAA, BBBBB, CCCCC,...., ZZZZZ on each line.
+ * It yields the cpu every 6 lines are printed.
+ *****************************************************************************/
+
+void priv_task1(void)
+{
+ int i = 0;
+ int j = 0;
+ long int x = 0;
+ int ret_val = 10;
+
+ while (1) {
+ char out_char = 'A' + i%26;
+ for (j = 0; j < 5; j++ ) {
+ SER_PutChar(out_char);
+ }
+ SER_PutStr("\n\r");
+
+ for ( x = 0; x < DELAY; x++); // some artificial delay
+ if ( (++i)%6 == 0 ) {
+ SER_PutStr("priv_task1 before yielding cpu.\n\r");
+ ret_val = k_tsk_yield();
+ SER_PutStr("priv_task1 after yielding cpu.\n\r");
+ printf("priv_task1: ret_val=%d\n\r", ret_val);
+#ifdef DEBUG_0
+ printf("priv_task1: ret_val=%d\n\r", ret_val);
+#endif /* DEBUG_0 */
+ }
+ }
+}
+
+/**************************************************************************//**
+ * @brief: a task that prints 00000, 11111, 22222,....,99999 on each line.
+ * It yields the cpu every 6 lines are printed
+ * before printing these lines indefinitely, it creates a
+ * new task and and obtains the task information. It then
+ * changes the newly created task's priority.
+ *****************************************************************************/
+
+void priv_task2(void)
+{
+ long int x = 0;
+ int ret_val = 10;
+ int i = 0;
+ int j = 0;
+ RTX_TASK_INFO task_info;
+ task_t tid;
+
+ k_tsk_create(&tid, &task1, LOW, 0x200); /*create a user task */
+ k_tsk_get(tid, &task_info);
+ k_tsk_set_prio(tid, LOWEST);
+
+
+ for (i = 1;;i++) {
+ char out_char = '0' + i%10;
+ for (j = 0; j < 5; j++ ) {
+ SER_PutChar(out_char);
+ }
+ SER_PutStr("\n\r");
+
+ for ( x = 0; x < DELAY; x++); // some artifical delay
+ if ( i%6 == 0 ) {
+ SER_PutStr("priv_task2 before yielding cpu.\n\r");
+ ret_val = k_tsk_yield();
+ SER_PutStr("priv_task2 after yielding cpu.\n\r");
+ printf("priv_task2: ret_val=%d\n\r", ret_val);
+#ifdef DEBUG_0
+ //printf("priv_task2: ret_val=%d\n\r", ret_val);
+#endif /* DEBUG_0 */
+ }
+ }
+}
+
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab2/code/src/app/ae_priv_tasks.h b/submission/lab2/code/src/app/ae_priv_tasks.h
new file mode 100755
index 0000000..843a053
--- /dev/null
+++ b/submission/lab2/code/src/app/ae_priv_tasks.h
@@ -0,0 +1,72 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice and the following disclaimer.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file priv_tasks.h
+ * @brief Two privileged tasks header file
+ *
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ *
+ *****************************************************************************/
+
+#ifndef PRIV_TASKS_H_
+#define PRIV_TASKS_H_
+
+#include "k_rtx.h"
+#include "rtx.h"
+
+/*
+ *===========================================================================
+ * MACROS
+ *===========================================================================
+ */
+#define DELAY 5000000
+
+/*
+ *===========================================================================
+ * FUNCTION PROTOTYPES
+ *===========================================================================
+ */
+extern void task1(void);
+
+void priv_task1 (void);
+void priv_task2 (void);
+
+void priv_task_entry(void);
+void priv_tasks_scheduling(void);
+void priv_task_check_sp(void);
+void testDataOwnership(void);
+
+#endif // ! PRIV_TASKS_H_
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab2/code/src/app/ae_usr_tasks.c b/submission/lab2/code/src/app/ae_usr_tasks.c
new file mode 100755
index 0000000..7536c6e
--- /dev/null
+++ b/submission/lab2/code/src/app/ae_usr_tasks.c
@@ -0,0 +1,246 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice and the following disclaimer.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file a usr_tasks.c
+ * @brief Two user/unprivileged tasks: task1 and task2
+ *
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ *****************************************************************************/
+
+#include "ae_usr_tasks.h"
+#include "rtx.h"
+#include "Serial.h"
+#include "printf.h"
+
+//----USER TASKS------// (implement in ae_usr_tasks.c)
+// tsk_create
+// tsk_get
+
+// tsk_create until max_tasks (same priority)
+// tsk_get for all TIDs
+// tsk create > max_tasks should fail
+// tsk_exit
+// tsk_create should reuse TID
+
+// tsk_create
+// tsk_get
+// tsk_set_prio
+// tsk_get
+// tsk_set_prio PRIO_NULL should fail
+// tsk_set_prio invalid TID should fail
+// tsk_set_prio dormant task should fail
+// tsk_set_prio for kernal task should fail
+// tsk_set_prio for user task
+// tsk_get
+
+char s_buffer[255];
+
+U32 * gmeStonks;
+U32 * bitCoinWallet;
+
+int powerOf(int a, int b){
+ int result = 1;
+ for(int i = 0; i < b; i++){
+ result = result * a;
+ }
+ return result;
+}
+
+void dumdum(void){
+ SER_PutStr ("I have brain damage\n\r");
+ int a = 2;
+ int b = a + 8;
+ int c = powerOf(a, b);
+ int d = 4 + c;
+ int e = powerOf(a, d);
+ tsk_exit();
+}
+
+void dumdum2(void){
+ SER_PutStr ("I have brain damage\n\r");
+ int a = 2;
+ int b = a + 8;
+ int c = powerOf(a, b);
+ int d = 4 + c;
+ int e = powerOf(a, d);
+
+ RTX_TASK_INFO task_info;
+
+ tsk_get(2, &task_info);
+ tsk_exit();
+}
+
+void dataOwner(void){
+ SER_PutStr(":diamond: :hand:\n\r");
+ gmeStonks = mem_alloc(420);
+ if(tsk_set_prio(1, HIGH) == RTX_ERR){
+ SER_PutStr("Could not set prio of kernel task\n\r");
+ }
+ int a = 2;
+ int b = a + 8;
+ int c = powerOf(a, b);
+
+ tsk_exit();
+}
+
+void dataThief(void){
+ SER_PutStr(":brrrrrrrr:\n\r");
+ bitCoinWallet = mem_alloc(0x400);
+ int a = 2;
+ int b = a + 8;
+ int c = powerOf(a, b);
+ if(mem_dealloc(gmeStonks) == RTX_ERR){
+ SER_PutStr("Test Passed\n\r");
+ }
+ mem_dealloc(bitCoinWallet);
+ tsk_set_prio(3, MEDIUM);
+ tsk_exit();
+}
+
+void checkSP(void){
+ SER_PutStr ("checkSP: I will yield\n\r");
+ tsk_yield();
+ tsk_exit();
+}
+
+/**
+ * @brief: a dummy task1
+ */
+void task1(void)
+{
+ task_t tid;
+ RTX_TASK_INFO task_info;
+
+ SER_PutStr ("task1: entering \n\r");
+ /* do something */
+ tsk_create(&tid, &task2, LOW, 0x200); /*create a user task */
+ tsk_get(tid, &task_info);
+ tsk_set_prio(tid, LOWEST);
+ /* terminating */
+ tsk_exit();
+}
+
+/**
+ * @brief: a dummy task2
+ */
+void task2(void)
+{
+ SER_PutStr ("task2: entering \n\r");
+ /* do something */
+ /* terminating */
+ tsk_exit();
+}
+
+// Function to implement strncat() function in C
+char* strncat(char* destination, const char* source, size_t num)
+{
+ // make ptr point to the end of destination string
+ char* ptr = destination + strlen(destination);
+
+ // Appends characters of source to the destination string
+ while (*source != '\0' && num--)
+ *ptr++ = *source++;
+
+ // null terminate destination string
+ *ptr = '\0';
+
+ // destination string is returned by standard strncat()
+ return destination;
+}
+
+
+void stask0(void)
+{
+ strncat(s_buffer, "0", 1);
+ tsk_exit();
+}
+
+void stask1(void)
+{
+ strncat(s_buffer, "1", 1);
+ tsk_exit();
+}
+
+void stask2(void)
+{
+ strncat(s_buffer, "2", 1);
+ tsk_exit();
+}
+
+void stask3(void)
+{
+ strncat(s_buffer, "3", 1);
+ tsk_exit();
+}
+
+void stask4(void)
+{
+ strncat(s_buffer, "4", 1);
+ tsk_exit();
+}
+
+void stask5(void)
+{
+ strncat(s_buffer, "5", 1);
+ tsk_exit();
+}
+
+void stask6(void)
+{
+ strncat(s_buffer, "6", 1);
+ tsk_exit();
+}
+
+void stask7(void)
+{
+ strncat(s_buffer, "7", 1);
+ tsk_exit();
+}
+
+void stask8(void)
+{
+ strncat(s_buffer, "8", 1);
+ tsk_exit();
+}
+
+void stask9(void)
+{
+ strncat(s_buffer, "9", 1);
+ tsk_exit();
+}
+
+
+
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab2/code/src/app/ae_usr_tasks.h b/submission/lab2/code/src/app/ae_usr_tasks.h
new file mode 100755
index 0000000..3862b52
--- /dev/null
+++ b/submission/lab2/code/src/app/ae_usr_tasks.h
@@ -0,0 +1,73 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice and the following disclaimer.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file usr_task.h
+ * @brief Two user tasks header file
+ *
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ *
+ *****************************************************************************/
+
+
+#ifndef USR_TASK_H_
+#define USR_TASK_H_
+
+extern char s_buffer[255];
+
+void task1(void);
+void task2(void);
+
+void dumdum(void);
+void dumdum2(void);
+
+void dataOwner(void);
+void dataThief(void);
+
+void checkSP(void);
+
+void stask0(void);
+void stask1(void);
+void stask2(void);
+void stask3(void);
+void stask4(void);
+void stask5(void);
+void stask6(void);
+void stask7(void);
+void stask8(void);
+void stask9(void);
+
+#endif // ! USR_TASK_H_
+
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab2/code/src/board/DE1_SoC_A9/Serial.c b/submission/lab2/code/src/board/DE1_SoC_A9/Serial.c
new file mode 100755
index 0000000..406b5db
--- /dev/null
+++ b/submission/lab2/code/src/board/DE1_SoC_A9/Serial.c
@@ -0,0 +1,129 @@
+ /**************************************************************************//**
+ * @file Serial.c
+ * @brief Simple polled UART driver, modified for DE1_SoC
+ * @version V1.2021.01
+ * @date 28 January 2021
+ * @author Yiqing Huang, Zehan Gao, ARM
+ *
+ * @note
+ *
+ ******************************************************************************/
+/* Copyright (c) 2011 - 2015 ARM LIMITED
+
+ All rights reserved.
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ - Neither the name of ARM nor the names of its contributors may be used
+ to endorse or promote products derived from this software without
+ specific prior written permission.
+ *
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+ ---------------------------------------------------------------------------*/
+
+#include "../DE1_SoC_A9/Serial.h"
+
+void SER_Init(void)
+{
+
+ SER_Set_baud_rate( 115200 );
+
+
+
+ UART0->UARTLCR = 0x3; // reset DLAB, 8 bits
+ UART0->UART_IIR_FCR &= 0x1; //FIFO enabled
+}
+
+/*----------------------------------------------------------------------------
+ Enable Serial Port
+ *----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------
+ Set baud rate
+ *----------------------------------------------------------------------------*/
+void SER_Set_baud_rate(uint32_t baud_rate)
+{
+ UART0->UARTLCR |= 0x80; //set DLAB
+ uint32_t divisor = UART0_CLK/(baud_rate * 16);
+ UART0->UARTDR = divisor;
+ UART0->UART_IIR_FCR = divisor >> 8;
+ UART0->UARTLCR &= ~(0x80);
+}
+
+/*----------------------------------------------------------------------------
+ Write character to Serial Port
+ *----------------------------------------------------------------------------*/
+void SER_PutChar(char c)
+{
+ while ((UART0->UARTLSR & 0x20) == 0 || (UART0->UARTLSR & 0x40) == 0); // Wait for UART TX to become free
+ //if (c == '\n')
+ //{
+ // UART0->UARTDR = '\r';
+ // while (UART0->UARTFR & 0x20);
+ //}
+ UART0->UARTDR = c;
+}
+
+/* HYQS */
+
+/*----------------------------------------------------------------------------
+ Write String to Serial Port
+ *----------------------------------------------------------------------------*/
+int SER_PutStr(char *s)
+{
+ if (s == NULL)
+ return 1;
+ while (*s !=0) { /* loop through each char in the string */
+ SER_PutChar(*s++);/* print the char, then ptr increments */
+ }
+ return 0;
+}
+/*----------------------------------------------------------------------------
+ * Call back function for printf
+ *----------------------------------------------------------------------------*/
+/**
+ * @brief call back function for printf
+ * @note first parameter p is not used for now. Polling UART is used
+ */
+
+void putc(void *p, char c)
+{
+ if ( p != NULL ) {
+ SER_PutStr("putc: first parameter needs to be NULL");
+ } else {
+ SER_PutChar(c);
+ }
+}
+
+/* HYQE */
+
+/*----------------------------------------------------------------------------
+ Read character from Serial Port (blocking read)
+ *----------------------------------------------------------------------------*/
+char SER_GetChar (void)
+{
+ while (UART0->UARTLSR & 0x1 == 0); // Wait for a character to arrive
+ return UART0->UARTDR;
+}
+/*----------------------------------------------------------------------------
+ Serial UART interrupt handler
+ *----------------------------------------------------------------------------*/
+void interrupt_SER(void)
+{
+ //your code here
+}
+
diff --git a/submission/lab2/code/src/board/DE1_SoC_A9/Serial.h b/submission/lab2/code/src/board/DE1_SoC_A9/Serial.h
new file mode 100755
index 0000000..f23d21a
--- /dev/null
+++ b/submission/lab2/code/src/board/DE1_SoC_A9/Serial.h
@@ -0,0 +1,102 @@
+ /**************************************************************************//**
+ * @file Serial.h
+ * @brief Simple polled UART driver, modified for DE1_SoC
+ * @version V1.2021.01
+ * @date 28 January 2021
+ * @author Yiqing Huang, Zehan Gao, ARM
+ *
+ * @note
+ *
+ ******************************************************************************/
+/* Copyright (c) 2011 - 2013 ARM LIMITED
+
+ All rights reserved.
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ - Neither the name of ARM nor the names of its contributors may be used
+ to endorse or promote products derived from this software without
+ specific prior written permission.
+ *
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+ ---------------------------------------------------------------------------*/
+
+#ifndef SERIAL_H_
+#define SERIAL_H_
+
+typedef unsigned char uint8_t;
+typedef unsigned short int uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned __int64 uint64_t;
+
+#define __RO volatile const
+#define __WO volatile
+#define __RW volatile
+
+/* UART - Register Layout Typedef */
+typedef struct {
+ __RW uint32_t UARTDR; /*0x000 Data Register*/
+ __RW uint32_t UARTIER_DLH; /*0x004 Interrupt Enable and Divisor Latch High Register */
+ __RW uint32_t UART_IIR_FCR; /*0x008 */
+ __RW uint32_t UARTLCR; /*0x00C Line Control Register */
+ uint32_t RESERVED_0; /*0x010 */
+ __RO uint32_t UARTLSR; /*0x014 Line Status Register */
+ __RO uint32_t UARTFR; /*0x018 Flag Register*/
+} UART_Type;
+
+
+
+
+#define UART0_BASE (0xFFC02000u) /* Cyclone V datasheet */
+#define UART0 ((UART_Type *)UART0_BASE)
+
+#define UART0_CLK 100000000 // L4_SP = 100MHz
+
+/* HYQS */
+#define BIT(X) ( 1 << (X) )
+#define NULL 0
+#define uart_init(n) SER_Init()
+#define uart_get_char(n) SER_GetChar()
+#define uart_put_char(n, c) SER_PutChar(c)
+#define uart_put_string(n, s) SER_PutStr(s)
+
+#define uart0_init() uart_init(0)
+#define uart0_get_char() uart_get_char(0)
+#define uart0_put_char(c) uart_put_char(0,c)
+#define uart0_put_string(s) uart_put_string(0,s)
+
+#define uart1_init() uart_init(1)
+#define uart1_get_char() uart_get_char(1)
+#define uart1_put_char(c) uart_put_char(1,c)
+#define uart1_put_string(s) uart_put_string(1,s)
+
+/* HYQE */
+
+
+extern void SER_Init(void);
+extern void SER_Enable(void);
+extern void SER_Disable(void);
+extern char SER_GetChar (void);
+extern void SER_PutChar(char c);
+extern void SER_Set_baud_rate(uint32_t baud_rate);
+extern void interrupt_SER(void);
+
+/* HYQS */
+extern int SER_PutStr(char *s);
+extern void putc(void *p, char c); /* call back function for printf, use uart1 */
+/* HYQE */
+#endif /* SERIAL_H_ */
diff --git a/submission/lab2/code/src/board/DE1_SoC_A9/device_a9.h b/submission/lab2/code/src/board/DE1_SoC_A9/device_a9.h
new file mode 100755
index 0000000..72d29ee
--- /dev/null
+++ b/submission/lab2/code/src/board/DE1_SoC_A9/device_a9.h
@@ -0,0 +1,42 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang and Zehan Gao
+ *
+ * This software is subject to an open source license and
+ * may be freely redistributed under the terms of MIT License.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file device_a9.h
+ * @brief Cortex-A9 device header file
+ *
+ * @version V1.2021.01
+ * @authors Yiqing Huang, Zehan Gao
+ * @date 2021 JAN
+ *
+ *****************************************************************************/
+
+#ifndef DEVICE_A9_H_
+#define DEVICE_A9_H_
+
+/*
+ *===========================================================================
+ * MACROS
+ *===========================================================================
+ */
+
+#define NUM_PRIV_MODES 0x00000006 // 6 privileged modes
+#define STACK_SZ 0x00000200 // 512 B stack for each mode
+#define RAM_SIZE 0x40000000 // The DE1 has 1G RAM
+#define RAM_END 0x3FFFFFFF // The DE1 RAM END
+
+#endif
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab2/code/src/board/DE1_SoC_A9/printf.c b/submission/lab2/code/src/board/DE1_SoC_A9/printf.c
new file mode 100755
index 0000000..78233a3
--- /dev/null
+++ b/submission/lab2/code/src/board/DE1_SoC_A9/printf.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2004,2012 Kustaa Nyholm / SpareTimeLabs
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * Neither the name of the Kustaa Nyholm or SpareTimeLabs nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#include "../DE1_SoC_A9/printf.h"
+
+typedef void (*putcf) (void*,char);
+static putcf stdout_putf;
+static void* stdout_putp;
+
+
+#ifdef PRINTF_LONG_SUPPORT
+
+static void uli2a(unsigned long int num, unsigned int base, int uc,char * bf)
+ {
+ int n=0;
+ unsigned int d=1;
+ while (num/d >= base)
+ d*=base;
+ while (d!=0) {
+ int dgt = num / d;
+ num%=d;
+ d/=base;
+ if (n || dgt>0|| d==0) {
+ *bf++ = dgt+(dgt<10 ? '0' : (uc ? 'A' : 'a')-10);
+ ++n;
+ }
+ }
+ *bf=0;
+ }
+
+static void li2a (long num, char * bf)
+ {
+ if (num<0) {
+ num=-num;
+ *bf++ = '-';
+ }
+ uli2a(num,10,0,bf);
+ }
+
+#endif
+
+static void ui2a(unsigned int num, unsigned int base, int uc,char * bf)
+ {
+ int n=0;
+ unsigned int d=1;
+ while (num/d >= base)
+ d*=base;
+ while (d!=0) {
+ int dgt = num / d;
+ num%= d;
+ d/=base;
+ if (n || dgt>0 || d==0) {
+ *bf++ = dgt+(dgt<10 ? '0' : (uc ? 'A' : 'a')-10);
+ ++n;
+ }
+ }
+ *bf=0;
+ }
+
+static void i2a (int num, char * bf)
+ {
+ if (num<0) {
+ num=-num;
+ *bf++ = '-';
+ }
+ ui2a(num,10,0,bf);
+ }
+
+static int a2d(char ch)
+ {
+ if (ch>='0' && ch<='9')
+ return ch-'0';
+ else if (ch>='a' && ch<='f')
+ return ch-'a'+10;
+ else if (ch>='A' && ch<='F')
+ return ch-'A'+10;
+ else return -1;
+ }
+
+static char a2i(char ch, char** src,int base,int* nump)
+ {
+ char* p= *src;
+ int num=0;
+ int digit;
+ while ((digit=a2d(ch))>=0) {
+ if (digit>base) break;
+ num=num*base+digit;
+ ch=*p++;
+ }
+ *src=p;
+ *nump=num;
+ return ch;
+ }
+
+static void putchw(void* putp,putcf putf,int n, char z, char* bf)
+ {
+ char fc=z? '0' : ' ';
+ char ch;
+ char* p=bf;
+ while (*p++ && n > 0)
+ n--;
+ while (n-- > 0)
+ putf(putp,fc);
+ while ((ch = *bf++) != '\0') /* This line is modified by Y. Huang to avoid assignment in condition warning */
+ putf(putp,ch);
+ }
+
+void tfp_format(void* putp,putcf putf,char *fmt, va_list va)
+ {
+ char bf[12];
+
+ char ch;
+
+
+ while ((ch = *(fmt++)) != '\0') { /* This line is modified by Y. Huang to avoid assignment in condition warning */
+ if (ch!='%')
+ putf(putp,ch);
+ else {
+ char lz=0;
+#ifdef PRINTF_LONG_SUPPORT
+ char lng=0;
+#endif
+ int w=0;
+ ch=*(fmt++);
+ if (ch=='0') {
+ ch=*(fmt++);
+ lz=1;
+ }
+ if (ch>='0' && ch<='9') {
+ ch=a2i(ch,&fmt,10,&w);
+ }
+#ifdef PRINTF_LONG_SUPPORT
+ if (ch=='l') {
+ ch=*(fmt++);
+ lng=1;
+ }
+#endif
+ switch (ch) {
+ case 0:
+ goto abort;
+ case 'u' : {
+#ifdef PRINTF_LONG_SUPPORT
+ if (lng)
+ uli2a(va_arg(va, unsigned long int),10,0,bf);
+ else
+#endif
+ ui2a(va_arg(va, unsigned int),10,0,bf);
+ putchw(putp,putf,w,lz,bf);
+ break;
+ }
+ case 'd' : {
+#ifdef PRINTF_LONG_SUPPORT
+ if (lng)
+ li2a(va_arg(va, unsigned long int),bf);
+ else
+#endif
+ i2a(va_arg(va, int),bf);
+ putchw(putp,putf,w,lz,bf);
+ break;
+ }
+ case 'x': case 'X' :
+#ifdef PRINTF_LONG_SUPPORT
+ if (lng)
+ uli2a(va_arg(va, unsigned long int),16,(ch=='X'),bf);
+ else
+#endif
+ ui2a(va_arg(va, unsigned int),16,(ch=='X'),bf);
+ putchw(putp,putf,w,lz,bf);
+ break;
+ case 'c' :
+ putf(putp,(char)(va_arg(va, int)));
+ break;
+ case 's' :
+ putchw(putp,putf,w,0,va_arg(va, char*));
+ break;
+ case '%' :
+ putf(putp,ch);
+ default:
+ break;
+ }
+ }
+ }
+ abort:;
+ }
+
+
+void init_printf(void* putp,void (*putf) (void*,char))
+ {
+ stdout_putf=putf;
+ stdout_putp=putp;
+ }
+
+void tfp_printf(char *fmt, ...)
+ {
+ va_list va;
+ va_start(va,fmt);
+ tfp_format(stdout_putp,stdout_putf,fmt,va);
+ va_end(va);
+ }
+
+static void putcp(void* p,char c)
+ {
+ *(*((char**)p))++ = c;
+ }
+
+
+
+void tfp_sprintf(char* s,char *fmt, ...)
+ {
+ va_list va;
+ va_start(va,fmt);
+ tfp_format(&s,putcp,fmt,va);
+ putcp(&s,0);
+ va_end(va);
+ }
diff --git a/submission/lab2/code/src/board/DE1_SoC_A9/printf.h b/submission/lab2/code/src/board/DE1_SoC_A9/printf.h
new file mode 100755
index 0000000..3790e72
--- /dev/null
+++ b/submission/lab2/code/src/board/DE1_SoC_A9/printf.h
@@ -0,0 +1,124 @@
+/*
+File: printf.h
+
+Copyright (c) 2004,2012 Kustaa Nyholm / SpareTimeLabs
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+Neither the name of the Kustaa Nyholm or SpareTimeLabs nor the names of its
+contributors may be used to endorse or promote products derived from this software
+without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+
+This library is realy just two files: 'printf.h' and 'printf.c'.
+
+They provide a simple and small (+200 loc) printf functionality to
+be used in embedded systems.
+
+I've found them so usefull in debugging that I do not bother with a
+debugger at all.
+
+They are distributed in source form, so to use them, just compile them
+into your project.
+
+Two printf variants are provided: printf and sprintf.
+
+The formats supported by this implementation are: 'd' 'u' 'c' 's' 'x' 'X'.
+
+Zero padding and field width are also supported.
+
+If the library is compiled with 'PRINTF_SUPPORT_LONG' defined then the
+long specifier is also
+supported. Note that this will pull in some long math routines (pun intended!)
+and thus make your executable noticably longer.
+
+The memory foot print of course depends on the target cpu, compiler and
+compiler options, but a rough guestimate (based on a H8S target) is about
+1.4 kB for code and some twenty 'int's and 'char's, say 60 bytes of stack space.
+Not too bad. Your milage may vary. By hacking the source code you can
+get rid of some hunred bytes, I'm sure, but personally I feel the balance of
+functionality and flexibility versus code size is close to optimal for
+many embedded systems.
+
+To use the printf you need to supply your own character output function,
+something like :
+
+void putc ( void* p, char c)
+ {
+ while (!SERIAL_PORT_EMPTY) ;
+ SERIAL_PORT_TX_REGISTER = c;
+ }
+
+Before you can call printf you need to initialize it to use your
+character output function with something like:
+
+init_printf(NULL,putc);
+
+Notice the 'NULL' in 'init_printf' and the parameter 'void* p' in 'putc',
+the NULL (or any pointer) you pass into the 'init_printf' will eventually be
+passed to your 'putc' routine. This allows you to pass some storage space (or
+anything realy) to the character output function, if necessary.
+This is not often needed but it was implemented like that because it made
+implementing the sprintf function so neat (look at the source code).
+
+The code is re-entrant, except for the 'init_printf' function, so it
+is safe to call it from interupts too, although this may result in mixed output.
+If you rely on re-entrancy, take care that your 'putc' function is re-entrant!
+
+The printf and sprintf functions are actually macros that translate to
+'tfp_printf' and 'tfp_sprintf'. This makes it possible
+to use them along with 'stdio.h' printf's in a single source file.
+You just need to undef the names before you include the 'stdio.h'.
+Note that these are not function like macros, so if you have variables
+or struct members with these names, things will explode in your face.
+Without variadic macros this is the best we can do to wrap these
+fucnction. If it is a problem just give up the macros and use the
+functions directly or rename them.
+
+For further details see source code.
+
+regs Kusti, 23.10.2004
+*/
+
+
+#ifndef __TFP_PRINTF__
+#define __TFP_PRINTF__
+
+#include
+
+void init_printf(void* putp,void (*putf) (void*,char));
+
+void tfp_printf(char *fmt, ...);
+void tfp_sprintf(char* s,char *fmt, ...);
+
+void tfp_format(void* putp,void (*putf) (void*,char),char *fmt, va_list va);
+
+#define printf tfp_printf
+#define sprintf tfp_sprintf
+
+#endif
+
+
+
diff --git a/submission/lab2/code/src/board/DE1_SoC_A9/startup_a9.s b/submission/lab2/code/src/board/DE1_SoC_A9/startup_a9.s
new file mode 100755
index 0000000..f2d57cb
--- /dev/null
+++ b/submission/lab2/code/src/board/DE1_SoC_A9/startup_a9.s
@@ -0,0 +1,209 @@
+;/*
+; ****************************************************************************
+; *
+; * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+; *
+; * Copyright (C) 2009-2018 ARM Limited.
+; * All rights reserved.
+; *
+; * Copyright 2020-2021 Yiqing Huang and Zehan Gao
+; *
+; * This software is subject to an open source license and
+; * may be freely redistributed under the terms of MIT License.
+; ****************************************************************************
+; */
+
+;/**************************************************************************//**
+; * @file startup_a9.s
+; * @brief modifed version of ARM startup_VE_A9_MP.s
+; *
+; * @version V1.2021.01
+; * @authors Yiqing Huang, Zehan Gao, ARM
+; * @date 2021 JAN
+; * @note MMU part is taken out, simpify IRQ handlers.
+; * The device dependent content is the RAM_BASE,
+; * set it according to the specific device
+; * Other parts are generic to any A9 processor devices
+; *
+; *****************************************************************************/
+
+;/*********************************************************************************************
+; * @brief modifed version of ARM startup_VE_A9_MP.s
+; * @note MMU part is taken out, simpify IRQ handlers.
+; * The device dependent content is the RAM_BASE, set it according to the specific device
+; * Other parts are generic to any A9 processor devices
+; * This file references scatter file defined symbols, so it should be used together
+; * with the provided scatter file
+; *********************************************************************************************/
+
+RAM_BASE EQU 0x00000000 ; Cyclone V
+SVC_Stack_Size EQU 0x00000000 ; we do not allocate SVC stack here, take it from g_k_stacks[0]
+
+;reset of exception mode stacks go to c routine to set up
+IRQ_Stack_Size EQU 0x00000000
+USR_Stack_Size EQU 0x00000000 ; user stacks will be set up by the kernel
+
+ISR_Stack_Size EQU (SVC_Stack_Size + IRQ_Stack_Size)
+
+;---------------------------------------------------------------------------
+; Stack, Heap for application using microlib
+;---------------------------------------------------------------------------
+
+ AREA STACK, NOINIT, READWRITE, ALIGN=3
+Stack_Mem SPACE USR_Stack_Size
+__initial_sp SPACE ISR_Stack_Size
+Stack_Top
+
+; Heap Configuration
+; Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
+;
+
+Heap_Size EQU 0x00000000
+
+ AREA HEAP, NOINIT, READWRITE, ALIGN=3
+__heap_base
+Heap_Mem SPACE Heap_Size
+__heap_limit
+
+;---------------------------------------------------------------------------
+; Code
+;---------------------------------------------------------------------------
+ PRESERVE8
+ ARM
+
+; Vector Table Mapped to Address 0 at Reset
+
+ AREA RESET, CODE, READONLY
+ EXPORT __Vectors
+ EXPORT __Vectors_End
+ EXPORT __Vectors_Size
+
+__Vectors LDR PC, Reset_Addr ; Address of Reset Handler
+ LDR PC, Undef_Addr ; Address of Undef Handler
+ LDR PC, SVC_Addr ; Address of SVC Handler
+ LDR PC, PAbt_Addr ; Address of Prefetch Abort Handler
+ LDR PC, DAbt_Addr ; Address of Data Abort Handler
+ NOP ; Reserved Vector
+ LDR PC, IRQ_Addr ; Address of IRQ Handler
+ LDR PC, FIQ_Addr ; Address of FIQ Handler
+__Vectors_End
+
+__Vectors_Size EQU __Vectors_End - __Vectors
+
+Reset_Addr DCD Reset_Handler
+Undef_Addr DCD Undef_Handler
+SVC_Addr DCD SVC_Handler
+PAbt_Addr DCD PAbt_Handler
+DAbt_Addr DCD DAbt_Handler
+IRQ_Addr DCD IRQ_Handler
+FIQ_Addr DCD FIQ_Handler
+
+
+
+
+ AREA |.text|, CODE, READONLY
+
+Reset_Handler PROC
+ EXPORT Reset_Handler [WEAK]
+ IMPORT StackInit
+ IMPORT SystemInit
+ IMPORT main
+ IMPORT g_k_stacks ; the kernel stack array symbol
+ IMPORT g_k_stack_size ; the kernel stack size for each task
+ LDR R0, =g_k_stacks ; R0 has the starting address of g_k_stacks[][] array
+ LDR R1, =g_k_stack_size ; R1 has the kernel stack size
+ LDR R1, [R1]
+ ADD R0, R0, R1 ; Move to the high address of the first task's stack
+ MOV SP, R0 ; Use the first task
+
+ ; Put any cores other than 0 to sleep
+ MRC p15, 0, R0, c0, c0, 5 ; Read MPIDR
+ ANDS R0, R0, #3
+goToSleep
+ WFINE
+ BNE goToSleep
+
+ MRC p15, 0, R0, c1, c0, 0 ; Read CP15 System Control register
+ BIC R0, R0, #(0x1 << 12) ; Clear I bit 12 to disable I Cache
+ BIC R0, R0, #(0x1 << 2) ; Clear C bit 2 to disable D Cache
+ BIC R0, R0, #0x1 ; Clear M bit 0 to disable MMU
+ BIC R0, R0, #(0x1 << 11) ; Clear Z bit 11 to disable branch prediction
+ BIC R0, R0, #(0x1 << 13) ; Clear V bit 13 to disable hivecs
+ MCR p15, 0, R0, c1, c0, 0 ; Write value back to CP15 System Control register
+ ISB
+
+; Configure ACTLR
+ MRC p15, 0, r0, c1, c0, 1 ; Read CP15 Auxiliary Control Register
+ ORR r0, r0, #(1 << 1) ; Enable L2 prefetch hint (UNK/WI since r4p1)
+ MCR p15, 0, r0, c1, c0, 1 ; Write CP15 Auxiliary Control Register
+; Set Vector Base Address Register (VBAR) to point to this application's vector table
+ LDR R0, =__Vectors
+ MCR p15, 0, R0, c12, c0, 0
+
+ LDR R0, =StackInit ; Initialize stack for each exception mode
+ BLX R0
+ LDR R0, =SystemInit
+ BLX R0 ; copy vector table, set up system clocks
+ LDR R0, =main
+ BLX main ; start the main function
+ B . ; loop if main ever returns
+ ENDP
+
+Undef_Handler PROC
+ EXPORT Undef_Handler [WEAK]
+ B .
+ ENDP
+
+PAbt_Handler PROC
+ EXPORT PAbt_Handler [WEAK]
+ B .
+ ENDP
+
+DAbt_Handler PROC
+ EXPORT DAbt_Handler [WEAK]
+ B .
+ ENDP
+
+SVC_Handler PROC
+ EXPORT SVC_Handler [WEAK]
+ B .
+ ENDP
+
+IRQ_Handler PROC
+ EXPORT IRQ_Handler [WEAK]
+ B .
+ ENDP
+
+FIQ_Handler PROC
+ EXPORT FIQ_Handler [WEAK]
+ B .
+ ENDP
+
+; User Initial Stack & Heap
+
+ IF :DEF:__MICROLIB
+
+ EXPORT __initial_sp
+ EXPORT __heap_base
+ EXPORT __heap_limit
+
+ ELSE
+
+ IMPORT __use_two_region_memory
+ EXPORT __user_initial_stackheap
+__user_initial_stackheap
+
+ LDR R0, = Heap_Mem
+ LDR R1, = (Stack_Mem + USR_Stack_Size)
+ LDR R2, = (Heap_Mem + Heap_Size)
+ LDR R3, = Stack_Mem
+ BX LR
+
+ ENDIF
+
+ END
+;/*
+; *===========================================================================
+; * END OF FILE
+; *===========================================================================
+; */
diff --git a/submission/lab2/code/src/board/DE1_SoC_A9/system_a9.c b/submission/lab2/code/src/board/DE1_SoC_A9/system_a9.c
new file mode 100755
index 0000000..9d28511
--- /dev/null
+++ b/submission/lab2/code/src/board/DE1_SoC_A9/system_a9.c
@@ -0,0 +1,60 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ *
+ * This software is subject to an open source license and
+ * may be freely redistributed under the terms of MIT License.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file system_a9.c
+ * @brief Generic Cortex-A9 CMSIS System Initialization Source
+ *
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ *
+ * @attention
+ * @note
+ * @details
+ *
+ *****************************************************************************/
+
+#include "k_HAL_CA.h"
+#include "../DE1_SoC_A9/device_a9.h"
+
+// statically allocated initial stacks except for SVC mode
+U32 g_stacks[NUM_PRIV_MODES - 1][STACK_SZ >> 2];
+
+/**************************************************************************//**
+ * @brief Set up stacks for each privileged mode except for SVC mode
+ * @see startup_a9.s Reset_Handler
+ *****************************************************************************/
+void StackInit(void) {
+ int i = 0;
+ __set_SP_MODE((U32) (g_stacks[++i]), MODE_SYS);
+ __set_SP_MODE((U32) (g_stacks[++i]), MODE_IRQ);
+ __set_SP_MODE((U32) (g_stacks[++i]), MODE_FIQ);
+ __set_SP_MODE((U32) (g_stacks[++i]), MODE_ABT);
+ __set_SP_MODE((U32) (g_stacks[++i]), MODE_UND);
+}
+
+/**************************************************************************//**
+ * @brief Setup the system.
+ * Initialize the System and update the SystemCoreClock variable.
+ * @note not needed for lab1 or lab2
+ *****************************************************************************/
+
+void SystemInit(void) {
+ // 1. copy vector table , not needed for VE9
+ // 2. TODO set up system clocks for devices, not needed for lab1 or lab2
+}
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab2/code/src/board/DE1_SoC_A9/system_a9.h b/submission/lab2/code/src/board/DE1_SoC_A9/system_a9.h
new file mode 100755
index 0000000..e15d81c
--- /dev/null
+++ b/submission/lab2/code/src/board/DE1_SoC_A9/system_a9.h
@@ -0,0 +1,44 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ *
+ * This software is subject to an open source license and
+ * may be freely redistributed under the terms of MIT License.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file system_a9.h
+ * @brief Coretx-A9 Generic CMSIS System Initialization
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ * @note
+ * @details
+ *
+ *****************************************************************************/
+#ifndef _SYSTEM_A9_H
+#define _SYSTEM_A9_H
+
+/*
+ *===========================================================================
+ * FUNCTION PROTOTYPES
+ *===========================================================================
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+extern void StackInit (void);
+extern void SystemInit (void);
+
+#endif /* _SYSTEM_A9_H */
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab2/code/src/board/VE_A9/Serial.c b/submission/lab2/code/src/board/VE_A9/Serial.c
new file mode 100755
index 0000000..feb5139
--- /dev/null
+++ b/submission/lab2/code/src/board/VE_A9/Serial.c
@@ -0,0 +1,170 @@
+ /**************************************************************************//**
+ * @file Serial.c
+ * @brief Simple polled UART driver
+ * @version
+ * @date 27 October 2015
+ *
+ * @note
+ *
+ * Code modification Copyright (c) Yiqing Huang
+ *
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice and the following disclaimer.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************/
+/* Copyright (c) 2011 - 2015 ARM LIMITED
+
+ All rights reserved.
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ - Neither the name of ARM nor the names of its contributors may be used
+ to endorse or promote products derived from this software without
+ specific prior written permission.
+ *
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+ ---------------------------------------------------------------------------*/
+
+#include "Serial.h"
+
+void SER_Init(void)
+{
+ SER_Disable(); // Disable UART
+ SER_Set_baud_rate( 38400 );
+ UART0->UARTLCR_H = UART_LCRH_WLEN_8 | UART_LCRH_FEN; // 8 bits, 1 stop bit, no parity, FIFO enabled
+ SER_Enable(); // Enable UART and enable TX/RX
+}
+
+/*----------------------------------------------------------------------------
+ Enable Serial Port
+ *----------------------------------------------------------------------------*/
+void SER_Enable(void)
+{
+ UART0->UARTCR = UART_CR_UARTEN | UART_CR_TXE | UART_CR_RXE;
+}
+
+/*----------------------------------------------------------------------------
+ Disable Serial Port
+ *----------------------------------------------------------------------------*/
+void SER_Disable(void)
+{
+ UART0->UARTCR = 0x0;
+}
+
+/*----------------------------------------------------------------------------
+ Set baud rate
+ *----------------------------------------------------------------------------*/
+void SER_Set_baud_rate(uint32_t baud_rate)
+{
+ uint32_t divider;
+ uint32_t mod;
+ uint32_t fraction;
+
+ /*
+ * Set baud rate
+ *
+ * IBRD = UART_CLK / (16 * BAUD_RATE)
+ * FBRD = ROUND((64 * MOD(UART_CLK,(16 * BAUD_RATE))) / (16 * BAUD_RATE))
+ */
+ divider = UART0_CLK / (16 * baud_rate);
+ mod = UART0_CLK % (16 * baud_rate);
+ fraction = (((8 * mod) / baud_rate) >> 1) + (((8 * mod) / baud_rate) & 1);
+
+ UART0->UARTIBRD = divider;
+ UART0->UARTFBRD = fraction;
+}
+
+/*----------------------------------------------------------------------------
+ Write character to Serial Port
+ *----------------------------------------------------------------------------*/
+void SER_PutChar(char c)
+{
+ while (UART0->UARTFR & 0x20); // Wait for UART TX to become free
+ //if (c == '\n')
+ //{
+ // UART0->UARTDR = '\r';
+ // while (UART0->UARTFR & 0x20);
+ //}
+ UART0->UARTDR = c;
+}
+
+/* HYQS */
+
+/*----------------------------------------------------------------------------
+ Write String to Serial Port
+ *----------------------------------------------------------------------------*/
+int SER_PutStr(char *s)
+{
+ if (s == NULL)
+ return 1;
+ while (*s !=0) { /* loop through each char in the string */
+ SER_PutChar(*s++);/* print the char, then ptr increments */
+ }
+ return 0;
+}
+/*----------------------------------------------------------------------------
+ * Call back function for printf
+ *----------------------------------------------------------------------------*/
+/**
+ * @brief call back function for printf
+ * @note first parameter p is not used for now. Polling UART is used
+ */
+
+void putc(void *p, char c)
+{
+ if ( p != NULL ) {
+ SER_PutStr("putc: first parameter needs to be NULL");
+ } else {
+ SER_PutChar(c);
+ }
+}
+
+/* HYQE */
+
+/*----------------------------------------------------------------------------
+ Read character from Serial Port (blocking read)
+ *----------------------------------------------------------------------------*/
+char SER_GetChar (void)
+{
+ while (UART0->UARTFR & 0x10); // Wait for a character to arrive
+ return UART0->UARTDR;
+}
+
+/*----------------------------------------------------------------------------
+ Serial UART interrupt handler
+ *----------------------------------------------------------------------------*/
+void interrupt_SER(void)
+{
+ //your code here
+}
+
diff --git a/submission/lab2/code/src/board/VE_A9/Serial.h b/submission/lab2/code/src/board/VE_A9/Serial.h
new file mode 100755
index 0000000..b9e059d
--- /dev/null
+++ b/submission/lab2/code/src/board/VE_A9/Serial.h
@@ -0,0 +1,166 @@
+ /**************************************************************************//**
+ * @file Serial.h
+ * @brief Simple polled UART driver. Needs to be completed
+ * @version
+ * @date 07 February 2013
+ *
+ * @note
+ *
+ * Code modification Copyright (c) Yiqing Huang
+ *
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice and the following disclaimer.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ ******************************************************************************/
+/* Copyright (c) 2011 - 2013 ARM LIMITED
+
+ All rights reserved.
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ - Neither the name of ARM nor the names of its contributors may be used
+ to endorse or promote products derived from this software without
+ specific prior written permission.
+ *
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+ ---------------------------------------------------------------------------*/
+
+#ifndef SERIAL_H_
+#define SERIAL_H_
+
+typedef unsigned char uint8_t;
+typedef unsigned short int uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned __int64 uint64_t;
+
+#define __RO volatile const
+#define __WO volatile
+#define __RW volatile
+
+/* UART - Register Layout Typedef */
+typedef struct {
+ __RW uint32_t UARTDR; /*0x000 Data Register*/
+ __RW uint32_t UARTRSR_UARTECR; /*0x004 Receive Status Register/Error Clear Register */
+ uint32_t RESERVED_0[4]; /*0x008 - 0x014*/
+ __RO uint32_t UARTFR; /*0x018 Flag Register*/
+ uint32_t RESERVED_1; /*0x01c*/
+ __RW uint32_t UARTILPR; /*0x020 IrDA Low-Power Counter Register*/
+ __RW uint32_t UARTIBRD; /*0x024 Integer Baud Rate Register */
+ __RW uint32_t UARTFBRD; /*0x028 Fractional Baud Rate Register*/
+ __RW uint32_t UARTLCR_H; /*0x02c Line Control Register */
+ __RW uint32_t UARTCR; /*0x030 Control Register*/
+ __RW uint32_t UARTIFLS; /*0x034 Interrupt FIFO Level Select Register*/
+ __RW uint32_t UARTIMSC; /*0x038 Interrupt Mask Set/Clear Register*/
+ __RO uint32_t UARTRIS; /*0x03c Raw Interrupt Status Register*/
+ __RO uint32_t UARTMIS; /*0x040 Masked Interrupt Status Register*/
+ __WO uint32_t UARTICR; /*0x044 Interrupt Clear Register*/
+ __RW uint32_t UARTDMACR; /*0x048 DMA Control Register*/
+ uint32_t RESERVED_2[13]; /*0x04c - 0x07c*/
+ uint32_t RESERVED_T[4]; /*0x080 - 0x08c*/
+ uint32_t RESERVED_3[976]; /*0x090 - 0xfcc*/
+ uint32_t RESERVED_4[4]; /*0xfd0 - 0xfdc*/
+ __RO uint32_t UARTPeriphID0; /*0xfe0 UARTPeriphID0 Register*/
+ __RO uint32_t UARTPeriphID1; /*0xfe4 UARTPeriphID1 Register*/
+ __RO uint32_t UARTPeriphID2; /*0xfe8 UARTPeriphID2 Register*/
+ __RO uint32_t UARTPeriphID3; /*0xfec UARTPeriphID3 Register*/
+ __RO uint32_t UARTCellID0; /*0xff0 UARTCellID0 Register*/
+ __RO uint32_t UARTCellID1; /*0xff4 UARTCellID1 Register*/
+ __RO uint32_t UARTCellID2; /*0xff8 UARTCellID2 Register*/
+ __RO uint32_t UARTCellID3; /*0xffc UARTCellID3 Register*/
+} UART_Type;
+
+
+/* Line control register */
+#define UART_LCRH_SPS (1 << 7)
+#define UART_LCRH_WLEN_8 (3 << 5)
+#define UART_LCRH_WLEN_7 (2 << 5)
+#define UART_LCRH_WLEN_6 (1 << 5)
+#define UART_LCRH_WLEN_5 (0 << 5)
+#define UART_LCRH_FEN (1 << 4)
+#define UART_LCRH_STP2 (1 << 3)
+#define UART_LCRH_EPS (1 << 2)
+#define UART_LCRH_PEN (1 << 1)
+#define UART_LCRH_BRK (1 << 0)
+
+
+/* Control Register */
+#define UART_CR_CTSEN (1 << 15)
+#define UART_CR_RTSEN (1 << 14)
+#define UART_CR_OUT2 (1 << 13)
+#define UART_CR_OUT1 (1 << 12)
+#define UART_CR_RTS (1 << 11)
+#define UART_CR_DTR (1 << 10)
+#define UART_CR_RXE (1 << 9)
+#define UART_CR_TXE (1 << 8)
+#define UART_CR_LPE (1 << 7)
+#define UART_CR_IIRLP (1 << 2)
+#define UART_CR_SIREN (1 << 1)
+#define UART_CR_UARTEN (1 << 0)
+
+
+/* Interrupt Mask Set/Clear Register */
+#define UART_IMSC_OEIM (1 << 10)
+#define UART_IMSC_BEIM (1 << 9)
+#define UART_IMSC_PEIM (1 << 8)
+#define UART_IMSC_FEIM (1 << 7)
+#define UART_IMSC_RTIM (1 << 6)
+#define UART_IMSC_TXIM (1 << 5)
+#define UART_IMSC_RXIM (1 << 4)
+#define UART_IMSC_DSRMIM (1 << 3)
+#define UART_IMSC_DCDMIM (1 << 2)
+#define UART_IMSC_CTSMIM (1 << 1)
+#define UART_IMSC_RIMIM (1 << 0)
+
+#define UART0_BASE (0x1C090000u) /* CS3 0x1C000000 + 0x090000 (VE ARM Cortex-A Series memory map) */
+#define UART0 ((UART_Type *)UART0_BASE)
+
+#define UART0_CLK 24000000 // 24MHz
+
+/* ECE350 START */
+#define BIT(X) ( 1 << (X) )
+#define NULL 0
+/* ECE350 END */
+
+
+extern void SER_Init(void);
+extern void SER_Enable(void);
+extern void SER_Disable(void);
+extern char SER_GetChar (void);
+extern void SER_PutChar(char c);
+extern void SER_Set_baud_rate(uint32_t baud_rate);
+extern void interrupt_SER(void);
+
+/* ECE350 START */
+extern int SER_PutStr(char *s);
+extern void putc(void *p, char c); /* call back function for printf, use uart */
+/* ECE350 END */
+#endif /* SERIAL_H_ */
diff --git a/submission/lab2/code/src/board/VE_A9/device_a9.h b/submission/lab2/code/src/board/VE_A9/device_a9.h
new file mode 100755
index 0000000..8a20d63
--- /dev/null
+++ b/submission/lab2/code/src/board/VE_A9/device_a9.h
@@ -0,0 +1,59 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice and the following disclaimer.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file device_a9.h
+ * @brief Cortex-A9 device header file
+ *
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ *
+ *****************************************************************************/
+
+#ifndef DEVICE_A9_H_
+#define DEVICE_A9_H_
+
+/*
+ *===========================================================================
+ * MACROS
+ *===========================================================================
+ */
+
+#define NUM_PRIV_MODES 0x00000006 // 6 privileged modes
+#define STACK_SZ 0x00000200 // 512 B stack for each mode
+#define RAM_SIZE 0x40000000 // The VE9 has 2G RAM, we only use 1G
+#define RAM_END 0xBFFFFFFF // The VE9 RAM END is 0xFFFFFFFF, we
+ // only use 1G
+
+#endif
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab2/code/src/board/VE_A9/printf.c b/submission/lab2/code/src/board/VE_A9/printf.c
new file mode 100755
index 0000000..8b032ac
--- /dev/null
+++ b/submission/lab2/code/src/board/VE_A9/printf.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2004,2012 Kustaa Nyholm / SpareTimeLabs
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * Neither the name of the Kustaa Nyholm or SpareTimeLabs nor the names of its
+ * contributors may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#include "printf.h"
+
+typedef void (*putcf) (void*,char);
+static putcf stdout_putf;
+static void* stdout_putp;
+
+
+#ifdef PRINTF_LONG_SUPPORT
+
+static void uli2a(unsigned long int num, unsigned int base, int uc,char * bf)
+ {
+ int n=0;
+ unsigned int d=1;
+ while (num/d >= base)
+ d*=base;
+ while (d!=0) {
+ int dgt = num / d;
+ num%=d;
+ d/=base;
+ if (n || dgt>0|| d==0) {
+ *bf++ = dgt+(dgt<10 ? '0' : (uc ? 'A' : 'a')-10);
+ ++n;
+ }
+ }
+ *bf=0;
+ }
+
+static void li2a (long num, char * bf)
+ {
+ if (num<0) {
+ num=-num;
+ *bf++ = '-';
+ }
+ uli2a(num,10,0,bf);
+ }
+
+#endif
+
+static void ui2a(unsigned int num, unsigned int base, int uc,char * bf)
+ {
+ int n=0;
+ unsigned int d=1;
+ while (num/d >= base)
+ d*=base;
+ while (d!=0) {
+ int dgt = num / d;
+ num%= d;
+ d/=base;
+ if (n || dgt>0 || d==0) {
+ *bf++ = dgt+(dgt<10 ? '0' : (uc ? 'A' : 'a')-10);
+ ++n;
+ }
+ }
+ *bf=0;
+ }
+
+static void i2a (int num, char * bf)
+ {
+ if (num<0) {
+ num=-num;
+ *bf++ = '-';
+ }
+ ui2a(num,10,0,bf);
+ }
+
+static int a2d(char ch)
+ {
+ if (ch>='0' && ch<='9')
+ return ch-'0';
+ else if (ch>='a' && ch<='f')
+ return ch-'a'+10;
+ else if (ch>='A' && ch<='F')
+ return ch-'A'+10;
+ else return -1;
+ }
+
+static char a2i(char ch, char** src,int base,int* nump)
+ {
+ char* p= *src;
+ int num=0;
+ int digit;
+ while ((digit=a2d(ch))>=0) {
+ if (digit>base) break;
+ num=num*base+digit;
+ ch=*p++;
+ }
+ *src=p;
+ *nump=num;
+ return ch;
+ }
+
+static void putchw(void* putp,putcf putf,int n, char z, char* bf)
+ {
+ char fc=z? '0' : ' ';
+ char ch;
+ char* p=bf;
+ while (*p++ && n > 0)
+ n--;
+ while (n-- > 0)
+ putf(putp,fc);
+ while ((ch = *bf++) != '\0') /* This line is modified by Y. Huang to avoid assignment in condition warning */
+ putf(putp,ch);
+ }
+
+void tfp_format(void* putp,putcf putf,char *fmt, va_list va)
+ {
+ char bf[12];
+
+ char ch;
+
+
+ while ((ch = *(fmt++)) != '\0') { /* This line is modified by Y. Huang to avoid assignment in condition warning */
+ if (ch!='%')
+ putf(putp,ch);
+ else {
+ char lz=0;
+#ifdef PRINTF_LONG_SUPPORT
+ char lng=0;
+#endif
+ int w=0;
+ ch=*(fmt++);
+ if (ch=='0') {
+ ch=*(fmt++);
+ lz=1;
+ }
+ if (ch>='0' && ch<='9') {
+ ch=a2i(ch,&fmt,10,&w);
+ }
+#ifdef PRINTF_LONG_SUPPORT
+ if (ch=='l') {
+ ch=*(fmt++);
+ lng=1;
+ }
+#endif
+ switch (ch) {
+ case 0:
+ goto abort;
+ case 'u' : {
+#ifdef PRINTF_LONG_SUPPORT
+ if (lng)
+ uli2a(va_arg(va, unsigned long int),10,0,bf);
+ else
+#endif
+ ui2a(va_arg(va, unsigned int),10,0,bf);
+ putchw(putp,putf,w,lz,bf);
+ break;
+ }
+ case 'd' : {
+#ifdef PRINTF_LONG_SUPPORT
+ if (lng)
+ li2a(va_arg(va, unsigned long int),bf);
+ else
+#endif
+ i2a(va_arg(va, int),bf);
+ putchw(putp,putf,w,lz,bf);
+ break;
+ }
+ case 'x': case 'X' :
+#ifdef PRINTF_LONG_SUPPORT
+ if (lng)
+ uli2a(va_arg(va, unsigned long int),16,(ch=='X'),bf);
+ else
+#endif
+ ui2a(va_arg(va, unsigned int),16,(ch=='X'),bf);
+ putchw(putp,putf,w,lz,bf);
+ break;
+ case 'c' :
+ putf(putp,(char)(va_arg(va, int)));
+ break;
+ case 's' :
+ putchw(putp,putf,w,0,va_arg(va, char*));
+ break;
+ case '%' :
+ putf(putp,ch);
+ default:
+ break;
+ }
+ }
+ }
+ abort:;
+ }
+
+
+void init_printf(void* putp,void (*putf) (void*,char))
+ {
+ stdout_putf=putf;
+ stdout_putp=putp;
+ }
+
+void tfp_printf(char *fmt, ...)
+ {
+ va_list va;
+ va_start(va,fmt);
+ tfp_format(stdout_putp,stdout_putf,fmt,va);
+ va_end(va);
+ }
+
+static void putcp(void* p,char c)
+ {
+ *(*((char**)p))++ = c;
+ }
+
+
+
+void tfp_sprintf(char* s,char *fmt, ...)
+ {
+ va_list va;
+ va_start(va,fmt);
+ tfp_format(&s,putcp,fmt,va);
+ putcp(&s,0);
+ va_end(va);
+ }
diff --git a/submission/lab2/code/src/board/VE_A9/printf.h b/submission/lab2/code/src/board/VE_A9/printf.h
new file mode 100755
index 0000000..3790e72
--- /dev/null
+++ b/submission/lab2/code/src/board/VE_A9/printf.h
@@ -0,0 +1,124 @@
+/*
+File: printf.h
+
+Copyright (c) 2004,2012 Kustaa Nyholm / SpareTimeLabs
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+
+Redistributions in binary form must reproduce the above copyright notice, this
+list of conditions and the following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+Neither the name of the Kustaa Nyholm or SpareTimeLabs nor the names of its
+contributors may be used to endorse or promote products derived from this software
+without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+OF SUCH DAMAGE.
+
+----------------------------------------------------------------------
+
+This library is realy just two files: 'printf.h' and 'printf.c'.
+
+They provide a simple and small (+200 loc) printf functionality to
+be used in embedded systems.
+
+I've found them so usefull in debugging that I do not bother with a
+debugger at all.
+
+They are distributed in source form, so to use them, just compile them
+into your project.
+
+Two printf variants are provided: printf and sprintf.
+
+The formats supported by this implementation are: 'd' 'u' 'c' 's' 'x' 'X'.
+
+Zero padding and field width are also supported.
+
+If the library is compiled with 'PRINTF_SUPPORT_LONG' defined then the
+long specifier is also
+supported. Note that this will pull in some long math routines (pun intended!)
+and thus make your executable noticably longer.
+
+The memory foot print of course depends on the target cpu, compiler and
+compiler options, but a rough guestimate (based on a H8S target) is about
+1.4 kB for code and some twenty 'int's and 'char's, say 60 bytes of stack space.
+Not too bad. Your milage may vary. By hacking the source code you can
+get rid of some hunred bytes, I'm sure, but personally I feel the balance of
+functionality and flexibility versus code size is close to optimal for
+many embedded systems.
+
+To use the printf you need to supply your own character output function,
+something like :
+
+void putc ( void* p, char c)
+ {
+ while (!SERIAL_PORT_EMPTY) ;
+ SERIAL_PORT_TX_REGISTER = c;
+ }
+
+Before you can call printf you need to initialize it to use your
+character output function with something like:
+
+init_printf(NULL,putc);
+
+Notice the 'NULL' in 'init_printf' and the parameter 'void* p' in 'putc',
+the NULL (or any pointer) you pass into the 'init_printf' will eventually be
+passed to your 'putc' routine. This allows you to pass some storage space (or
+anything realy) to the character output function, if necessary.
+This is not often needed but it was implemented like that because it made
+implementing the sprintf function so neat (look at the source code).
+
+The code is re-entrant, except for the 'init_printf' function, so it
+is safe to call it from interupts too, although this may result in mixed output.
+If you rely on re-entrancy, take care that your 'putc' function is re-entrant!
+
+The printf and sprintf functions are actually macros that translate to
+'tfp_printf' and 'tfp_sprintf'. This makes it possible
+to use them along with 'stdio.h' printf's in a single source file.
+You just need to undef the names before you include the 'stdio.h'.
+Note that these are not function like macros, so if you have variables
+or struct members with these names, things will explode in your face.
+Without variadic macros this is the best we can do to wrap these
+fucnction. If it is a problem just give up the macros and use the
+functions directly or rename them.
+
+For further details see source code.
+
+regs Kusti, 23.10.2004
+*/
+
+
+#ifndef __TFP_PRINTF__
+#define __TFP_PRINTF__
+
+#include
+
+void init_printf(void* putp,void (*putf) (void*,char));
+
+void tfp_printf(char *fmt, ...);
+void tfp_sprintf(char* s,char *fmt, ...);
+
+void tfp_format(void* putp,void (*putf) (void*,char),char *fmt, va_list va);
+
+#define printf tfp_printf
+#define sprintf tfp_sprintf
+
+#endif
+
+
+
diff --git a/submission/lab2/code/src/board/VE_A9/startup_a9.s b/submission/lab2/code/src/board/VE_A9/startup_a9.s
new file mode 100755
index 0000000..65b4a8d
--- /dev/null
+++ b/submission/lab2/code/src/board/VE_A9/startup_a9.s
@@ -0,0 +1,239 @@
+;/*
+; ****************************************************************************
+; *
+; * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+; *
+; * Copyright (C) 2009-2018 ARM Limited.
+; * All rights reserved.
+; *
+; * Copyright (C) 2020-2021 Yiqing Huang
+; * All rights reserved.
+;-----------------------------------------------------------------------------
+;/* Copyright (c) 2011 - 2015 ARM LIMITED
+; All rights reserved.
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions are met:
+; - Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+; - Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in the
+; documentation and/or other materials provided with the distribution.
+; - Neither the name of ARM nor the names of its contributors may be used
+; to endorse or promote products derived from this software without
+; specific prior written permission.
+; *
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+; ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+; POSSIBILITY OF SUCH DAMAGE.
+; ---------------------------------------------------------------------------*/
+; * Code Modification Copyright (c) 2020-2021 Yiqing Huang
+; *
+; * All rights reserved.
+; * Redistribution and use in source and binary forms, with or without
+; * modification, are permitted provided that the following conditions are met:
+; * - Redistributions of source code must retain the above copyright
+; * notice and the following disclaimer.
+; *
+; *
+; * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+; * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+; * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+; * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+; * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+; * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+; * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+; * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+; * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+; * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+; * POSSIBILITY OF SUCH DAMAGE.
+; ****************************************************************************
+; */
+
+;/*********************************************************************************************
+; * @brief modifed version of ARM startup_VE_A9_MP.s
+; * @note MMU part is taken out, simpify IRQ handlers.
+; * The device dependent content is the RAM_BASE, set it according to the specific device
+; * Other parts are generic to any A9 processor devices
+; * This file references scatter file defined symbols, so it should be used together
+; * with the provided scatter file
+; *********************************************************************************************/
+
+RAM_BASE EQU 0x80000000 ; VE9
+SVC_Stack_Size EQU 0x00000000 ; we do not allocate SVC stack here, take it from g_k_stacks[0]
+
+;reset of exception mode stacks go to c routine to set up
+IRQ_Stack_Size EQU 0x00000000
+USR_Stack_Size EQU 0x00000000 ; user stacks will be set up by the kernel
+
+ISR_Stack_Size EQU (SVC_Stack_Size + IRQ_Stack_Size)
+
+;---------------------------------------------------------------------------
+; Stack, Heap for application using microlib
+;---------------------------------------------------------------------------
+
+ AREA STACK, NOINIT, READWRITE, ALIGN=3
+Stack_Mem SPACE USR_Stack_Size
+__initial_sp SPACE ISR_Stack_Size
+Stack_Top
+
+; Heap Configuration
+; Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
+;
+
+Heap_Size EQU 0x00000000
+
+ AREA HEAP, NOINIT, READWRITE, ALIGN=3
+__heap_base
+Heap_Mem SPACE Heap_Size
+__heap_limit
+
+;---------------------------------------------------------------------------
+; Code
+;---------------------------------------------------------------------------
+ PRESERVE8
+ ARM
+
+; Vector Table Mapped to Address 0 at Reset
+
+ AREA RESET, CODE, READONLY
+ EXPORT __Vectors
+ EXPORT __Vectors_End
+ EXPORT __Vectors_Size
+
+__Vectors LDR PC, Reset_Addr ; Address of Reset Handler
+ LDR PC, Undef_Addr ; Address of Undef Handler
+ LDR PC, SVC_Addr ; Address of SVC Handler
+ LDR PC, PAbt_Addr ; Address of Prefetch Abort Handler
+ LDR PC, DAbt_Addr ; Address of Data Abort Handler
+ NOP ; Reserved Vector
+ LDR PC, IRQ_Addr ; Address of IRQ Handler
+ LDR PC, FIQ_Addr ; Address of FIQ Handler
+__Vectors_End
+
+__Vectors_Size EQU __Vectors_End - __Vectors
+
+Reset_Addr DCD Reset_Handler
+Undef_Addr DCD Undef_Handler
+SVC_Addr DCD SVC_Handler
+PAbt_Addr DCD PAbt_Handler
+DAbt_Addr DCD DAbt_Handler
+IRQ_Addr DCD IRQ_Handler
+FIQ_Addr DCD FIQ_Handler
+
+
+
+
+ AREA |.text|, CODE, READONLY
+
+Reset_Handler PROC
+ EXPORT Reset_Handler [WEAK]
+ IMPORT StackInit
+ IMPORT SystemInit
+ IMPORT main
+ IMPORT g_k_stacks ; the kernel stack array symbol
+ IMPORT g_k_stack_size ; the kernel stack size for each task
+ LDR R0, =g_k_stacks ; R0 has the starting address of g_k_stacks[][] array
+ LDR R1, =g_k_stack_size ; R1 has the kernel stack size
+ LDR R1, [R1]
+ ADD R0, R0, R1 ; Move to the high address of the first task's stack
+ MOV SP, R0 ; Use the first task
+
+ ; Put any cores other than 0 to sleep
+ MRC p15, 0, R0, c0, c0, 5 ; Read MPIDR
+ ANDS R0, R0, #3
+goToSleep
+ WFINE
+ BNE goToSleep
+
+ MRC p15, 0, R0, c1, c0, 0 ; Read CP15 System Control register
+ BIC R0, R0, #(0x1 << 12) ; Clear I bit 12 to disable I Cache
+ BIC R0, R0, #(0x1 << 2) ; Clear C bit 2 to disable D Cache
+ BIC R0, R0, #0x1 ; Clear M bit 0 to disable MMU
+ BIC R0, R0, #(0x1 << 11) ; Clear Z bit 11 to disable branch prediction
+ BIC R0, R0, #(0x1 << 13) ; Clear V bit 13 to disable hivecs
+ MCR p15, 0, R0, c1, c0, 0 ; Write value back to CP15 System Control register
+ ISB
+
+; Configure ACTLR
+ MRC p15, 0, r0, c1, c0, 1 ; Read CP15 Auxiliary Control Register
+ ORR r0, r0, #(1 << 1) ; Enable L2 prefetch hint (UNK/WI since r4p1)
+ MCR p15, 0, r0, c1, c0, 1 ; Write CP15 Auxiliary Control Register
+; Set Vector Base Address Register (VBAR) to point to this application's vector table
+ LDR R0, =__Vectors
+ MCR p15, 0, R0, c12, c0, 0
+
+ LDR R0, =StackInit ; Initialize stack for each exception mode
+ BLX R0
+ LDR R0, =SystemInit
+ BLX R0 ; copy vector table, set up system clocks
+ LDR R0, =main
+ BLX main ; start the main function
+ B . ; loop if main ever returns
+ ENDP
+
+Undef_Handler PROC
+ EXPORT Undef_Handler [WEAK]
+ B .
+ ENDP
+
+PAbt_Handler PROC
+ EXPORT PAbt_Handler [WEAK]
+ B .
+ ENDP
+
+DAbt_Handler PROC
+ EXPORT DAbt_Handler [WEAK]
+ B .
+ ENDP
+
+SVC_Handler PROC
+ EXPORT SVC_Handler [WEAK]
+ B .
+ ENDP
+
+IRQ_Handler PROC
+ EXPORT IRQ_Handler [WEAK]
+ B .
+ ENDP
+
+FIQ_Handler PROC
+ EXPORT FIQ_Handler [WEAK]
+ B .
+ ENDP
+
+; User Initial Stack & Heap
+
+ IF :DEF:__MICROLIB
+
+ EXPORT __initial_sp
+ EXPORT __heap_base
+ EXPORT __heap_limit
+
+ ELSE
+
+ IMPORT __use_two_region_memory
+ EXPORT __user_initial_stackheap
+__user_initial_stackheap
+
+ LDR R0, = Heap_Mem
+ LDR R1, = (Stack_Mem + USR_Stack_Size)
+ LDR R2, = (Heap_Mem + Heap_Size)
+ LDR R3, = Stack_Mem
+ BX LR
+
+ ENDIF
+
+ END
+;/*
+; *===========================================================================
+; * END OF FILE
+; *===========================================================================
+; */
diff --git a/submission/lab2/code/src/board/VE_A9/system_a9.c b/submission/lab2/code/src/board/VE_A9/system_a9.c
new file mode 100755
index 0000000..5d39e1d
--- /dev/null
+++ b/submission/lab2/code/src/board/VE_A9/system_a9.c
@@ -0,0 +1,58 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ *
+ * This software is subject to an open source license and
+ * may be freely redistributed under the terms of MIT License.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file system_a9.c
+ * @brief Generic Cortex-A9 CMSIS System Initialization Source
+ *
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ *
+ * @attention
+ * @note
+ * @details
+ *
+ *****************************************************************************/
+#include "system_a9.h"
+
+// statically allocated initial stacks except for SVC mode and SYS mode
+U32 g_stacks[NUM_PRIV_MODES - 2][STACK_SZ >> 2];
+
+/**************************************************************************//**
+ * @brief Set up stacks for each privileged mode except for SVC mode
+ * @see startup_a9.s Reset_Handler
+ *****************************************************************************/
+void StackInit(void) {
+ int i = 0;
+ __set_SP_MODE((U32) (g_stacks[++i]), MODE_IRQ);
+ __set_SP_MODE((U32) (g_stacks[++i]), MODE_FIQ);
+ __set_SP_MODE((U32) (g_stacks[++i]), MODE_ABT);
+ __set_SP_MODE((U32) (g_stacks[++i]), MODE_UND);
+ __set_SP_MODE((U32) (g_p_stacks[1]), MODE_SYS);
+}
+
+/**************************************************************************//**
+ * @brief Setup the system.
+ * Initialize the System and update the SystemCoreClock variable.
+ * @note not needed for lab1 or lab2
+ *****************************************************************************/
+
+void SystemInit(void) {
+ // 1. copy vector table , not needed for VE9
+ // 2. TODO set up system clocks for devices, not needed for lab1 or lab2
+}
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab2/code/src/board/VE_A9/system_a9.h b/submission/lab2/code/src/board/VE_A9/system_a9.h
new file mode 100755
index 0000000..80443b4
--- /dev/null
+++ b/submission/lab2/code/src/board/VE_A9/system_a9.h
@@ -0,0 +1,66 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice and the following disclaimer.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file system_a9.h
+ * @brief Coretx-A9 Generic CMSIS System Initialization
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ * @note
+ * @details
+ *
+ *****************************************************************************/
+#ifndef _SYSTEM_A9_H
+#define _SYSTEM_A9_H
+
+#include "device_a9.h"
+#include "k_HAL_CA.h"
+#include "common.h"
+
+extern U32 g_p_stacks[MAX_TASKS][PROC_STACK_SIZE >> 2] __attribute__((aligned(8)));
+
+/*
+ *===========================================================================
+ * FUNCTION PROTOTYPES
+ *===========================================================================
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+extern void StackInit (void);
+extern void SystemInit (void);
+
+#endif /* _SYSTEM_A9_H */
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab2/code/src/kernel/HAL_CA.c b/submission/lab2/code/src/kernel/HAL_CA.c
new file mode 100755
index 0000000..bda3558
--- /dev/null
+++ b/submission/lab2/code/src/kernel/HAL_CA.c
@@ -0,0 +1,198 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice and the following disclaimer.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file HAL.c
+ * @brief Hardware Abstraction Layer for Cortex-A series
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ *
+ * @note This file contains embedded assembly.
+ * The code borrowed ideas from ARM RTX source code
+ *
+ *****************************************************************************/
+
+#include "common.h"
+#include "k_inc.h"
+#include "k_HAL_CA.h"
+
+#pragma push
+#pragma arm
+
+/**************************************************************************//**
+ * @brief assembly labels that all embedded assembly code can refer to
+ * @note This function should not be called
+ *****************************************************************************/
+__asm void __asm_symbols(void)
+{
+Mode_USR EQU 0x10
+Mode_FIQ EQU 0x11
+Mode_IRQ EQU 0x12
+Mode_SVC EQU 0x13
+Mode_ABT EQU 0x17
+Mode_UND EQU 0x1B
+Mode_SYS EQU 0x1F
+
+I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled
+F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled
+T_Bit EQU 0x20 ; when T bit is set, core is in Thumb state
+
+}
+
+/**************************************************************************//**
+ * @brief disable both IRQ and FIQ
+ * @post IRQ and FIQ disabled
+ * TODO needs more testing
+ *****************************************************************************/
+__asm void __atomic_on(void)
+{
+ PRESERVE8
+ PUSH {R4, LR}
+ MRS R4, CPSR
+ ORR R4, #I_Bit:OR:F_Bit ; set both I and F bits
+ MSR CPSR_c, R4
+ POP {R4, PC}
+}
+
+/**************************************************************************//**
+ * @brief enable both IRQ and FIQ
+ * @post IRQ and FIQ enabled
+ * TODO needs more testing
+ *****************************************************************************/
+__asm void __atomic_off(void)
+{
+ PRESERVE8
+ PUSH {R4, LR}
+ MRS R4, CPSR
+ BIC R4, #I_Bit:OR:F_Bit ; clear both I and F bits
+ MSR CPSR_c, R4
+ POP {R4, PC}
+}
+#pragma pop
+
+/**************************************************************************//**
+ * @brief change processor mode
+ *
+ * @param mode the processor mode numerical value
+ * @post processor mode changes if caller is not in USR mode
+ *
+ *****************************************************************************/
+#pragma push
+#pragma arm
+__asm void __ch_MODE (U32 mode) {
+ ARM
+ PUSH {R1, R4}
+ MOV R1, LR
+ MSR CPSR_csxf, R0 ; no effect in USR mode
+ ISB ; flushes the pipeline in the processor
+ MOV LR, R1
+ POP {R1, R4}
+ BX LR
+}
+#pragma pop
+
+/**************************************************************************//**
+ * @brief set the stack of a given mode
+ *
+ * @param sp the stack pointer to be set
+ * @param mode the mode of the sp
+ * @post SP_MODE updated if caller is not in USR mode
+ *
+ * TODO: needs more testing
+ *
+ *****************************************************************************/
+#pragma push
+#pragma arm
+
+/**
+ * @brief set the stack of a given mode
+ * @pre: the mode is a valid mode, caller checks
+ * @post: processor retains the mode before the function is called
+ */
+__asm void __set_SP_MODE (U32 sp, U32 mode) {
+ ARM
+
+ PUSH {R4, LR}
+ MRS R4, CPSR ; save CPSR in R4
+ MSR CPSR_csxf, R1 ; R1 contains the mode, no effect in USR mode
+ ISB ; flushes the pipeline in the processor
+ MOV SP, R0 ; R0 contains SP to be set
+ MSR CPSR_c, R4 ; restore CPSR, no effect in USR mode
+ ISB ; flushes the pipline in the processor
+ POP {R4, PC}
+}
+
+#pragma pop
+
+/**************************************************************************//**
+ * @brief SVC Handler (i.e. trap handler)
+ * @pre The caller should be in USR/SYS mode
+ * R12 contains trap table mapped kernel function entry point
+ * Processor is in ARM Mode
+ * @attention Only handles ARM Mode
+ *****************************************************************************/
+#pragma push
+#pragma arm
+__asm void SVC_Handler (void)
+{
+
+ PRESERVE8 ; 8 bytes alignement of the stack
+ ARM
+ EXPORT SVC_RESTORE
+
+SVC_SAVE
+ SRSFD SP!, #Mode_SVC ; Push LR_SVC and SPSR_SVC onto SVC mode stack
+ SUB SP, SP, #56
+ STM SP, {R0-R12, SP}^ ; push SP_USR and R0 - R12 onto the kernel stack
+
+ ;// extract SVC number, only handles #0
+ MRS R4,SPSR ; Get SPSR
+ LDR R4,[LR,#-4] ; ARM: Load Word
+ BIC R4,R4,#0xFF000000 ; Extract SVC Number
+
+ CMP R4,#0
+ BNE SVC_EXIT ; if not SVC #0, go to SVC_EXIT
+
+ BLX R12 ; invoke the corresponding c kernel function
+
+SVC_RESTORE
+ STR R0, [SP] ; save the function return value on R0 that is on top of the stack
+
+SVC_EXIT
+ LDM SP, {R0-R12, SP}^ ; restore SP_USR and R0-R12 from their saved values on the stack
+ ADD SP, SP, #56
+ RFEFD SP! ; Return from exception
+}
+#pragma pop
+
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab2/code/src/kernel/k_HAL_CA.h b/submission/lab2/code/src/kernel/k_HAL_CA.h
new file mode 100755
index 0000000..e6485e0
--- /dev/null
+++ b/submission/lab2/code/src/kernel/k_HAL_CA.h
@@ -0,0 +1,123 @@
+/*----------------------------------------------------------------------------
+ * CMSIS-RTOS - RTX
+ *----------------------------------------------------------------------------
+ * Name: k_HAL_CA.H
+ * Purpose: Hardware Abstraction Layer for Cortex-A definitions
+ * Rev.: V4.82 plus changes for RTX-Ax
+ * Notes: modified by yqhuang@uwaterloo.ca for ECE350 Lab Project
+ *----------------------------------------------------------------------------
+ *
+ * Copyright (c) 1999-2009 KEIL, 2009-2015 ARM Germany GmbH, 2012-2017 ARM Limited
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * - Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------
+ * Code modification Copyright (c) 2020-2021 Yiqing Huang
+ *
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice and the following disclaimer.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *---------------------------------------------------------------------------*/
+
+#ifndef K_HAL_CA_H_
+#define K_HAL_CA_H_
+
+#include
+
+/*
+ *===========================================================================
+ * MACROS
+ *===========================================================================
+ */
+
+#define INIT_CPSR_SYS 0x4000001F
+#define INIT_CPSR_USER 0x40000010
+#define INIT_CPSR_SVC 0x40000013
+
+#define CPSR_T_BIT 0x20
+#define CPSR_I_BIT 0x80
+#define CPSR_F_BIT 0x40
+
+#define MODE_USR 0x10
+#define MODE_FIQ 0x11
+#define MODE_IRQ 0x12
+#define MODE_SVC 0x13
+#define MODE_ABT 0x17
+#define MODE_UND 0x1B
+#define MODE_SYS 0x1F
+
+/*
+ *===========================================================================
+ * TYPEDEFS
+ *===========================================================================
+ */
+
+typedef uint32_t U32;
+
+/*
+ *===========================================================================
+ * FUNCTION PROTOTYPES
+ *===========================================================================
+ */
+
+/* START: ECE350 Functions */
+extern void __set_SP_MODE (U32 sp, U32 mode);
+extern void __ch_MODE (U32 mode);
+extern void __atomic_on(void);
+extern void __atomic_off(void);
+
+static __inline uint32_t __get_CPSR(void) {
+ register uint32_t __regCPSR __asm("cpsr");
+ return (__regCPSR);
+}
+
+static __inline char __get_mode(void)
+{
+ return (char)(__get_CPSR() & 0x1FU);
+}
+
+/* END: ECE350 Functions */
+
+#endif // ! K_HAL_CA_H_
+
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
+
diff --git a/submission/lab2/code/src/kernel/k_inc.h b/submission/lab2/code/src/kernel/k_inc.h
new file mode 100755
index 0000000..33e3b55
--- /dev/null
+++ b/submission/lab2/code/src/kernel/k_inc.h
@@ -0,0 +1,111 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice and the following disclaimer.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file k_inc.h
+ * @brief Kernel Macros and Data Structure Header file
+ * l2
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ *
+ * @note all kernel .c files include this one
+ *
+ *****************************************************************************/
+
+#ifndef K_INC_H_
+#define K_INC_H_
+
+#include "device_a9.h"
+#include "common.h"
+
+/*
+ *===========================================================================
+ * MACROS
+ *===========================================================================
+ */
+
+#define TCB_MSP_OFFSET 4
+
+/*
+ *===========================================================================
+ * STRUCTURES
+ *===========================================================================
+ */
+
+/**
+ * @brief TCB data structure definition to support two kernel tasks.
+ * @note You will need to add more fields to this structure.
+ */
+typedef struct tcb {
+ struct tcb *next; /**> next tcb, not used in this example */
+ U32 *msp; /**> msp of the task, TCB_MSP_OFFSET = 4 */
+ U8 tid; /**> task id */
+ U8 prio; /**> Execution priority */
+ U32 task_count; /**> Update counter used for FIFO scheduling */
+ U8 state; /**> task state */
+ U8 priv; /**> = 0 unprivileged, =1 privileged */
+ U32 u_stack_hi; // user-space stack start
+ U16 u_stack_size; // user-space stack size
+ void (*ptask)(); // task entry address
+} TCB;
+
+/*
+ *==========================================================================
+ * GLOBAL VARIABLES DECLARATIONS
+ *==========================================================================
+ */
+// Memory related globals are defined in k_mem.c
+// kernel stack size
+extern const U32 g_k_stack_size; // kernel stack size
+extern const U32 g_p_stack_size; // process stack size for sys mode tasks
+
+// task kernel stacks are statically allocated inside the OS image
+extern U32 g_k_stacks[MAX_TASKS][KERN_STACK_SIZE >> 2] __attribute__((aligned(8)));
+
+// process stack for tasks in SYS mode, statically allocated inside the OS image */
+extern U32 g_p_stacks[MAX_TASKS][PROC_STACK_SIZE >> 2] __attribute__((aligned(8)));
+
+extern unsigned int Image$$ZI_DATA$$ZI$$Limit; // Linker defined symbol
+ // See ARM Compiler User Guide 5.x
+
+// task related globals are defined in k_task.c
+extern TCB *gp_current_task; // always point to the current RUNNING task
+
+// TCBs are statically allocated inside the OS image
+extern TCB g_tcbs[MAX_TASKS];
+extern RTX_TASK_INFO g_null_task_info;
+extern U32 g_num_active_tasks; // number of non-dormant tasks */
+
+#endif // ! K_INC_H_
+
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab2/code/src/kernel/k_mem.c b/submission/lab2/code/src/kernel/k_mem.c
new file mode 100755
index 0000000..95e5ed6
--- /dev/null
+++ b/submission/lab2/code/src/kernel/k_mem.c
@@ -0,0 +1,299 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice and the following disclaimer.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file k_mem.c
+ * @brief Kernel Memory Management API C Code
+ *
+ * @version V1.2021.01.lab2
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ *
+ * @note skeleton code
+ *
+ *****************************************************************************/
+
+/**
+ * @brief: k_mem.c kernel API implementations, this is only a skeleton.
+ * @author: Yiqing Huang
+ */
+
+#include "k_mem.h"
+#include "Serial.h"
+#ifdef DEBUG_0
+#include "printf.h"
+#endif /* DEBUG_0 */
+
+/*
+ *==========================================================================
+ * GLOBAL VARIABLES
+ *==========================================================================
+ */
+// kernel stack size, referred by startup_a9.s
+const U32 g_k_stack_size = KERN_STACK_SIZE;
+// task proc space stack size in bytes, referred by system_a9.c
+const U32 g_p_stack_size = PROC_STACK_SIZE;
+
+// task kernel stacks
+U32 g_k_stacks[MAX_TASKS][KERN_STACK_SIZE >> 2] __attribute__((aligned(8)));
+
+//process stack for tasks in SYS mode
+U32 g_p_stacks[MAX_TASKS][PROC_STACK_SIZE >> 2] __attribute__((aligned(8)));
+
+/*
+ *==========================================================================
+ * STRUCTS
+ *==========================================================================
+ */
+
+typedef struct Node {
+ unsigned int size;
+ U8 isFree;
+ task_t owner;
+ struct Node *next;
+} Node;
+
+// Global head
+Node* HEAD = NULL;
+
+/*
+ *===========================================================================
+ * FUNCTIONS
+ *===========================================================================
+ */
+
+U32* k_alloc_k_stack(task_t tid)
+{
+ return g_k_stacks[tid+1];
+}
+
+U32* k_alloc_p_stack(task_t tid) {
+ void* mem = k_mem_alloc(g_tcbs[tid].u_stack_size);
+ Node* node = (Node*)mem - 1;
+ node->owner = 0;
+// return mem;
+ return (U32*) ((char*)mem + g_tcbs[tid].u_stack_size);
+// return g_p_stacks[tid+1];
+}
+
+int k_mem_init(void) {
+ unsigned int end_addr = (unsigned int) &Image$$ZI_DATA$$ZI$$Limit;
+#ifdef DEBUG_0
+ printf("k_mem_init: image ends at 0x%x\r\n", end_addr);
+ printf("k_mem_init: RAM ends at 0x%x\r\n", RAM_END);
+#endif /* DEBUG_0 */
+
+ //check if end addr is valid
+ unsigned int totalSize = RAM_END - end_addr;
+ if(totalSize <= 0) {
+ return RTX_ERR;
+ }
+
+ // round end_addr to nearest 8
+ if (end_addr % 8 != 0) {
+ end_addr = ((unsigned int)(end_addr / 8)) * 8 + 8;
+
+ }
+
+ // cast end_addr to pointer given in end_addr
+ HEAD = (Node*) end_addr;
+
+ // setup head
+ HEAD->size = totalSize - sizeof(Node);
+ HEAD->isFree = 1;
+ HEAD->next = NULL;
+
+ return RTX_OK;
+}
+
+void* k_mem_alloc(size_t size) {
+//#ifdef DEBUG_0
+// printf("k_mem_alloc: requested memory size = %d\r\n", size);
+//#endif /* DEBUG_0 */
+
+ if (size == 0) {
+ return NULL;
+ }
+
+ // 8 byte align
+ if (size % 8 != 0) {
+ size = ((U32)(size / 8)) * 8 + 8;
+ }
+
+ Node* curr = HEAD;
+
+ while(curr != NULL) {
+ if (size <= curr->size && curr->isFree) {
+ break;
+ }
+ curr = curr->next;
+ }
+
+ // couldn't allocate since no free space
+ if (curr == NULL) {
+ return NULL;
+ }
+
+ //TODO: assign TID ownership
+
+ if (size == curr->size){
+ curr->owner = gp_current_task->tid;
+ curr->isFree=0;
+ return (void*)((U32)curr + sizeof(Node));
+ } else if (size < curr->size && (curr->size < (size + sizeof(Node)))) {
+ curr->owner = gp_current_task->tid;
+ curr->isFree=0;
+ return (void*)((U32)curr + sizeof(Node));
+ } else {
+ //make a new node
+ // might need to use an unsigned depending on how types work
+ Node* newNode = (Node*)((unsigned int)curr + sizeof(Node) + size);
+ newNode->isFree = 1;
+ newNode->size = curr->size - size - sizeof(Node);
+ newNode->next = curr->next;
+
+ curr->isFree=0;
+ curr->size = size;
+ curr->next = newNode;
+ curr->owner = gp_current_task->tid;
+ // Cast curr to U32 to ensure pointer arithmetic works
+ // Pointer addition works by adding by increment of sizeof the pointer
+ // argument. If curr is of type Node* and we add sizeof(Node), we add
+ // sizeof(Node)^2 amount of bytes.
+ return (void*)((U32)curr + sizeof(Node));
+ }
+}
+
+Node* mergeNode(Node* first, Node* second) {
+ if (first > second) {
+ return NULL;
+ }
+
+ Node* result = first;
+ result->size = first->size + second->size + sizeof(Node);
+ result->next = second->next;
+
+ return result;
+}
+
+int k_mem_dealloc(void *ptr) {
+//#ifdef DEBUG_0
+// printf("k_mem_dealloc: freeing 0x%x\r\n", (U32) ptr);
+//#endif /* DEBUG_0 */
+
+ Node* curr = HEAD;
+ Node* prev = NULL;
+
+ while (ptr != (char*)curr + sizeof(Node)) {
+ if (curr->next == NULL || curr->next == curr) {
+ return RTX_ERR;
+ }
+
+ prev = curr;
+ curr = curr->next;
+// printf("0x%x\n", (U32)((char*)curr + sizeof(Node) + curr->size));
+ }
+
+ // Double free
+ if (curr->isFree > 0) {
+ return RTX_ERR;
+ }
+
+ if (!gp_current_task->priv) {
+ if (gp_current_task->tid != curr->owner){
+ return RTX_ERR;
+ }
+ }
+
+ curr->isFree = 1;
+
+ // Merge neighboring nodes
+ if (prev && prev->isFree > 0) {
+ curr = mergeNode(prev, curr);
+ }
+
+ if (curr->next && curr->next->isFree > 0) {
+ curr = mergeNode(curr, curr->next);
+ }
+
+// print_list();
+
+ return RTX_OK;
+}
+
+int k_mem_count_extfrag(size_t size) {
+#ifdef DEBUG_0
+ printf("k_mem_extfrag: size = %d\r\n", size);
+#endif /* DEBUG_0 */
+
+ unsigned int memRegionSize;
+ int regionCount = 0;
+
+ Node* curNode = HEAD; // HEAD is global var
+
+ while(curNode != NULL){
+ memRegionSize = curNode->size + sizeof(Node);
+ if(curNode->isFree){
+ if(memRegionSize < size){
+ regionCount++;
+ }
+ }
+ curNode = curNode->next; // idk if this is the right way to goto next node
+ }
+
+
+ return regionCount;
+}
+
+int countNodes(){
+ Node* n = HEAD;
+ int ret = 0;
+ while(n != NULL) {
+ ret += 1;
+ n = n->next;
+ }
+ return ret;
+}
+
+int memLeakCheck(){
+ unsigned int howMuchMem = 0;
+ Node* curNode = HEAD;
+ while(curNode != NULL){
+ howMuchMem += curNode->size + sizeof(Node);
+ curNode = curNode->next;
+ }
+ unsigned int end_addr = (unsigned int) &Image$$ZI_DATA$$ZI$$Limit;
+ unsigned int totalSize = 0xBFFFFFFF - end_addr;
+ return howMuchMem == totalSize;
+}
+
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab2/code/src/kernel/k_mem.h b/submission/lab2/code/src/kernel/k_mem.h
new file mode 100755
index 0000000..5b0e113
--- /dev/null
+++ b/submission/lab2/code/src/kernel/k_mem.h
@@ -0,0 +1,66 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice and the following disclaimer.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file k_mem.h
+ * @brief Kernel Memory Management API Header File
+ *
+ * @version V1.2021.01.lab2
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ *
+ * @note skeleton code
+ *
+ *****************************************************************************/
+
+
+#ifndef K_MEM_H_
+#define K_MEM_H_
+#include "k_inc.h"
+
+/*
+ * ------------------------------------------------------------------------
+ * FUNCTION PROTOTYPES
+ * ------------------------------------------------------------------------
+ */
+int k_mem_init (void);
+void *k_mem_alloc (size_t size);
+int k_mem_dealloc (void *ptr);
+int k_mem_count_extfrag (size_t size);
+U32 *k_alloc_k_stack (task_t tid);
+U32 *k_alloc_p_stack (task_t tid);
+int countNodes (void);
+int memLeakCheck (void);
+#endif // ! K_MEM_H_
+
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
+
diff --git a/submission/lab2/code/src/kernel/k_rtx.h b/submission/lab2/code/src/kernel/k_rtx.h
new file mode 100755
index 0000000..dc6b27a
--- /dev/null
+++ b/submission/lab2/code/src/kernel/k_rtx.h
@@ -0,0 +1,53 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice and the following disclaimer.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file k_rtx.h
+ * @brief Kernel API Header File
+ * l2
+ * @version V1.2021.01.lab2
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ *
+ * @note all kernel .c files include this one
+ *
+ *****************************************************************************/
+
+#ifndef K_RTX_H_
+#define K_RTX_H_
+
+#include "k_rtx_init.h"
+#include "k_task.h"
+#include "k_mem.h"
+//#include "k_msg.h" // lab3
+#endif /* ! K_RTX_H_ */
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab2/code/src/kernel/k_rtx_init.c b/submission/lab2/code/src/kernel/k_rtx_init.c
new file mode 100755
index 0000000..7cf2d56
--- /dev/null
+++ b/submission/lab2/code/src/kernel/k_rtx_init.c
@@ -0,0 +1,79 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice and the following disclaimer.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file k_rtx_init.c
+ * @brief RTX System Initialization C file
+ * l2
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ *
+ * @details
+ * @note
+ *
+ *****************************************************************************/
+
+#include "k_rtx_init.h"
+#include "Serial.h"
+#include "k_mem.h"
+#include "k_task.h"
+
+int k_rtx_init(RTX_TASK_INFO *task_info, int num_tasks)
+{
+ /* interrupts are already disabled when we enter here */
+ if ( k_mem_init() != RTX_OK) {
+ return RTX_ERR;
+ }
+
+ if ( k_tsk_init(task_info, num_tasks) != RTX_OK ) {
+ return RTX_ERR;
+ }
+
+ /* start the first task */
+ //return k_tsk_start();
+ return RTX_OK;
+}
+
+int k_rtx_init_rt(RTX_SYS_INFO *sys_info, RTX_TASK_INFO *task_info, int num_tasks)
+{
+ /* initialize the scheduler here */
+ k_rtx_init(task_info, num_tasks);
+ return RTX_OK;
+}
+
+int k_get_sys_info(RTX_SYS_INFO *buffer)
+{
+ return RTX_OK;
+}
+
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab2/code/src/kernel/k_rtx_init.h b/submission/lab2/code/src/kernel/k_rtx_init.h
new file mode 100755
index 0000000..babc47c
--- /dev/null
+++ b/submission/lab2/code/src/kernel/k_rtx_init.h
@@ -0,0 +1,61 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice and the following disclaimer.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file k_rtx_init.h
+ * @brief RTX System Initialization Header file
+ * l2
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ *
+ * @details
+ * @note
+ *
+ *****************************************************************************/
+
+#ifndef K_RTX_INIT_H_
+#define K_RTX_INIT_H_
+
+#include "k_inc.h"
+
+/*
+ *===========================================================================
+ * FUNCTION PROTOTYPES
+ *===========================================================================
+ */
+
+int k_rtx_init (RTX_TASK_INFO *task_info, int num_tasks);
+
+#endif /* ! K_RTX_INIT_H_ */
+
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab2/code/src/kernel/k_task.c b/submission/lab2/code/src/kernel/k_task.c
new file mode 100755
index 0000000..7f211bf
--- /dev/null
+++ b/submission/lab2/code/src/kernel/k_task.c
@@ -0,0 +1,811 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice and the following disclaimer.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file k_task.c
+ * @brief task management C file
+ * l2
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ *
+ * @attention assumes NO HARDWARE INTERRUPTS
+ * @details The starter code shows one way of implementing context switching.
+ * The code only has minimal sanity check.
+ * There is no stack overflow check.
+ * The implementation assumes only two simple privileged task and
+ * NO HARDWARE INTERRUPTS.
+ * The purpose is to show how context switch could be done
+ * under stated assumptions.
+ * These assumptions are not true in the required RTX Project!!!
+ * Understand the assumptions and the limitations of the code before
+ * using the code piece in your own project!!!
+ *
+ *****************************************************************************/
+
+//#include "VE_A9_MP.h"
+#include "Serial.h"
+#include "k_task.h"
+#include "k_rtx.h"
+
+#ifdef DEBUG_0
+#include "printf.h"
+#endif /* DEBUG_0 */
+
+/*
+ *==========================================================================
+ * GLOBAL VARIABLES
+ *==========================================================================
+ */
+
+TCB *gp_current_task = NULL; // the current RUNNING task
+TCB g_tcbs[MAX_TASKS]; // an array of TCBs
+RTX_TASK_INFO g_null_task_info; // The null task info
+U32 g_num_active_tasks = 0; // number of non-dormant tasks
+
+/*---------------------------------------------------------------------------
+The memory map of the OS image may look like the following:
+
+ RAM_END+---------------------------+ High Address
+ | |
+ | |
+ | Free memory space |
+ | (user space stacks |
+ | + heap |
+ | |
+ | |
+ | |
+ &Image$$ZI_DATA$$ZI$$Limit-->|---------------------------|-----+-----
+ | ...... | ^
+ |---------------------------| |
+ | PROC_STACK_SIZE | |
+ g_p_stacks[15]-->|---------------------------| |
+ | | |
+ | other kernel proc stacks | |
+ |---------------------------| |
+ | PROC_STACK_SIZE | OS Image
+ g_p_stacks[2]-->|---------------------------| |
+ | PROC_STACK_SIZE | |
+ g_p_stacks[1]-->|---------------------------| |
+ | PROC_STACK_SIZE | |
+ g_p_stacks[0]-->|---------------------------| |
+ | other global vars | |
+ | | OS Image
+ |---------------------------| |
+ | KERN_STACK_SIZE | |
+ g_k_stacks[15]-->|---------------------------| |
+ | | |
+ | other kernel stacks | |
+ |---------------------------| |
+ | KERN_STACK_SIZE | OS Image
+ g_k_stacks[2]-->|---------------------------| |
+ | KERN_STACK_SIZE | |
+ g_k_stacks[1]-->|---------------------------| |
+ | KERN_STACK_SIZE | |
+ g_k_stacks[0]-->|---------------------------| |
+ | other global vars | |
+ |---------------------------| |
+ | TCBs | OS Image
+ g_tcbs->|---------------------------| |
+ | global vars | |
+ |---------------------------| |
+ | | |
+ | | |
+ | | |
+ | | V
+ RAM_START+---------------------------+ Low Address
+
+---------------------------------------------------------------------------*/
+
+/*
+ *==========================================================================
+ * SCHEDULER VARIABLES
+ *==========================================================================
+ */
+
+static const int h_array_size = MAX_TASKS;
+static TCB* heap[h_array_size];
+static U32 current_size = 0;
+static U32 g_task_count = 0;
+
+/*
+ *===========================================================================
+ * SCHEDULER FUNCTIONS
+ *===========================================================================
+ */
+
+int compare(TCB *t1, TCB* t2) {
+ int result = (*t1).prio < (*t2).prio || ((*t1).prio == (*t2).prio && (*t1).task_count <= (*t2).task_count);
+ // printf("V1: %d, %d, %d - V2: %d, %d, %d - Result: %d\r\n", t1->tid, t1->prio, t1->task_count, t2->tid, t2->prio, t2->task_count, result);
+ return result;
+}
+
+void swap(TCB** t1, TCB** t2) {
+ TCB* t;
+ t = *t1;
+ *t1 = *t2;
+ *t2 = t;
+}
+
+int parent(int i) {
+ return (i > 0 && i < h_array_size) ? (i - 1) / 2 : -1;
+}
+
+int left_child(int i) {
+ return (2*i + 1 < current_size && i >= 0) ? 2*i + 1: -1;
+}
+
+int right_child(int i) {
+ return (2*i + 2 < current_size && i >= 0) ? 2*i + 2 : -1;
+}
+
+void increase_key(TCB* heap[], int i) {
+ while(i >= 0 && parent(i) >= 0 && !compare(heap[parent(i)], heap[i])) {
+ swap(&heap[i], &heap[parent(i)]);
+ i = parent(i);
+ }
+}
+
+void decrease_key(TCB* heap[], int i) {
+ int max_index = i;
+
+ int l = left_child(i);
+
+ if (l > 0 && compare(heap[l], heap[max_index])) {
+ max_index = l;
+ }
+
+ int r = right_child(i);
+
+ if (r > 0 && compare(heap[r], heap[max_index])) {
+ max_index = r;
+ }
+
+ if (i != max_index) {
+ swap(&heap[i], &heap[max_index]);
+ decrease_key(heap, max_index);
+ }
+}
+
+int insert(TCB* heap[], TCB* value) {
+ if (current_size + 1== h_array_size) {
+ return -1;
+ }
+
+ g_task_count += 1;
+ (*value).task_count = g_task_count;
+ heap[current_size] = value;
+ increase_key(heap, current_size);
+ current_size ++;
+ return 0;
+}
+
+int16_t maximum(TCB* heap[]) {
+ return current_size == 0 ? -1 : heap[0]->tid;
+}
+
+int16_t extract_max(TCB* heap[]) {
+ if (current_size == 0) { return 0; }
+
+ int16_t max_value = maximum(heap);
+
+ current_size --;
+ heap[0] = heap[current_size];
+ decrease_key(heap, 0);
+
+ return max_value;
+}
+
+int find_value(TCB* heap[], U8 tid) {
+ int i;
+ for (i = 0; i < current_size; i++) {
+ if (heap[i]->tid == tid) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+void reset_priority(TCB* heap[], U8 tid, U8 priority) {
+ int index = find_value(heap, tid);
+ if (index < 0) { return; }
+
+ TCB v = *heap[index];
+
+ g_task_count += 1;
+ heap[index]->prio = priority;
+ heap[index]->task_count = g_task_count;
+
+ if (compare(heap[index], &v)) {
+ increase_key(heap, index);
+ } else {
+ decrease_key(heap, index);
+ }
+}
+
+void remove_id(TCB* heap[], U8 tid) {
+ if (current_size == 0) { return; }
+
+ int i = find_value(heap, tid);
+
+ if (i < 0) { return; }
+
+ //printf("found id: %d\n", i);
+ heap[i] = heap[0];
+ heap[i]->task_count += 1;
+ increase_key(heap, i);
+ //print_heap(heap, current_size);
+ extract_max(heap);
+}
+
+/*
+ *===========================================================================
+ * FUNCTIONS
+ *===========================================================================
+ */
+
+/**************************************************************************//**
+ * @brief scheduler, pick the TCB of the next to run task
+ *
+ * @return TCB pointer of the next to run task
+ * @post gp_curret_task is updated
+ *
+ *****************************************************************************/
+
+int currently_running() {
+ return gp_current_task && gp_current_task->state == RUNNING;
+}
+
+TCB *scheduler(void)
+{
+ int16_t tid = maximum(heap);
+ //int16_t tid = extract_max(heap);
+ if (tid < 0) { return gp_current_task; }
+
+ TCB* current_tcb = gp_current_task;
+ TCB* max_ready_tcb = &g_tcbs[(U8)tid];
+
+ // current task has higher priority
+ if (gp_current_task->state != DORMANT && current_tcb->prio < max_ready_tcb->prio) {
+
+ return gp_current_task;
+ }
+
+ gp_current_task = max_ready_tcb;
+ extract_max(heap);
+ insert(heap, current_tcb);
+
+ return gp_current_task;
+
+}
+
+/**************************************************************************//**
+ * @brief initialize all boot-time tasks in the system,
+ *
+ *
+ * @return RTX_OK on success; RTX_ERR on failure
+ * @param task_info boot-time task information structure pointer
+ * @param num_tasks boot-time number of tasks
+ * @pre memory has been properly initialized
+ * @post none
+ *
+ * @see k_tsk_create_new
+ *****************************************************************************/
+
+int k_tsk_init(RTX_TASK_INFO *task_info, int num_tasks)
+{
+ extern U32 SVC_RESTORE;
+
+ RTX_TASK_INFO *p_taskinfo = &g_null_task_info;
+ g_num_active_tasks = 0;
+
+ if (num_tasks > MAX_TASKS) {
+ return RTX_ERR;
+ }
+
+ // create the first task
+ TCB *p_tcb = &g_tcbs[0];
+ p_tcb->prio = PRIO_NULL;
+ p_tcb->priv = 1;
+ p_tcb->tid = TID_NULL;
+ p_tcb->state = RUNNING;
+ g_num_active_tasks++;
+ gp_current_task = p_tcb;
+
+ // initialize all TCB task ids and states to DORMANT
+ for(int i = 1; i < MAX_TASKS; i++){
+ g_tcbs[i].state = DORMANT;
+ g_tcbs[i].tid = i;
+ }
+
+ // create the rest of the tasks
+ p_taskinfo = task_info;
+ for ( int i = 0; i < num_tasks; i++ ) {
+ TCB *p_tcb = &g_tcbs[i+1];
+ if (k_tsk_create_new(p_taskinfo, p_tcb, i+1) == RTX_OK) {
+ g_num_active_tasks++;
+ }
+ p_taskinfo++;
+ }
+ return RTX_OK;
+}
+/**************************************************************************//**
+ * @brief initialize a new task in the system,
+ * one dummy kernel stack frame, one dummy user stack frame
+ *
+ * @return RTX_OK on success; RTX_ERR on failure
+ * @param p_taskinfo task information structure pointer
+ * @param p_tcb the tcb the task is assigned to
+ * @param tid the tid the task is assigned to
+ *
+ * @details From bottom of the stack,
+ * we have user initial context (xPSR, PC, SP_USR, uR0-uR12)
+ * then we stack up the kernel initial context (kLR, kR0-kR12)
+ * The PC is the entry point of the user task
+ * The kLR is set to SVC_RESTORE
+ * 30 registers in total
+ *
+ *****************************************************************************/
+int k_tsk_create_new(RTX_TASK_INFO *p_taskinfo, TCB *p_tcb, task_t tid)
+{
+ extern U32 SVC_RESTORE;
+ extern U32 K_RESTORE;
+
+ U32 *sp;
+
+ if (p_taskinfo == NULL || p_tcb == NULL)
+ {
+ return RTX_ERR;
+ }
+
+ p_tcb->tid = tid;
+ p_tcb->state = READY;
+
+ /*---------------------------------------------------------------
+ * Step1: allocate kernel stack for the task
+ * stacks grows down, stack base is at the high address
+ * -------------------------------------------------------------*/
+
+ ///////sp = g_k_stacks[tid] + (KERN_STACK_SIZE >> 2) ;
+ sp = k_alloc_k_stack(tid);
+
+ // 8B stack alignment adjustment
+ if ((U32)sp & 0x04) { // if sp not 8B aligned, then it must be 4B aligned
+ sp--; // adjust it to 8B aligned
+ }
+
+ /*-------------------------------------------------------------------
+ * Step2: create task's user/sys mode initial context on the kernel stack.
+ * fabricate the stack so that the stack looks like that
+ * task executed and entered kernel from the SVC handler
+ * hence had the user/sys mode context saved on the kernel stack.
+ * This fabrication allows the task to return
+ * to SVC_Handler before its execution.
+ *
+ * 16 registers listed in push order
+ *
+ * -------------------------------------------------------------*/
+
+ // if kernel task runs under SVC mode, then no need to create user context stack frame for SVC handler entering
+ // since we never enter from SVC handler in this case
+ // uSP: initial user stack
+ if ( p_taskinfo->priv == 0 ) { // unprivileged task
+ // xPSR: Initial Processor State
+ *(--sp) = INIT_CPSR_USER;
+ // PC contains the entry point of the user/privileged task
+ *(--sp) = (U32) (p_taskinfo->ptask);
+
+ //********************************************************************//
+ //*** allocate user stack from the user space, not implemented yet ***//
+ //********************************************************************//
+ p_tcb->u_stack_size = p_taskinfo->u_stack_size;
+ *(--sp) = (U32) k_alloc_p_stack(tid);
+
+ // store user stack hi pointer in TCB
+ p_tcb->u_stack_hi = *sp; // user stack hi grows downwards
+
+ // uR12, uR11, ..., uR0
+ for ( int j = 0; j < 13; j++ ) {
+ *(--sp) = 0x0;
+ }
+ }
+
+
+ /*---------------------------------------------------------------
+ * Step3: create task kernel initial context on kernel stack
+ *
+ * 14 registers listed in push order
+ *
+ * -------------------------------------------------------------*/
+ if ( p_taskinfo->priv == 0 ) {
+ // user thread LR: return to the SVC handler
+ *(--sp) = (U32) (&SVC_RESTORE);
+ } else {
+ // kernel thread LR: return to the entry point of the task
+ *(--sp) = (U32) (p_taskinfo->ptask);
+ p_tcb->u_stack_hi = p_taskinfo->u_stack_size; // user stack hi grows downwards
+ p_tcb->u_stack_size = p_taskinfo->u_stack_size;
+ }
+
+ // kernel stack R0 - R12, 13 registers
+ for ( int j = 0; j < 13; j++) {
+ *(--sp) = 0x0;
+ }
+
+ p_tcb->msp = sp; // store msp in TCB
+ p_tcb->ptask = p_taskinfo->ptask; // store task entry in TCB
+ p_tcb->prio = p_taskinfo->prio; // store priority in TCB
+ p_tcb->priv = p_taskinfo->priv; // store privilege in
+
+ insert(heap, p_tcb);
+
+ return RTX_OK;
+}
+
+/**************************************************************************//**
+ * @brief switching kernel stacks of two TCBs
+ * @param: p_tcb_old, the old tcb that was in RUNNING
+ * @return: RTX_OK upon success
+ * RTX_ERR upon failure
+ * @pre: gp_current_task is pointing to a valid TCB
+ * gp_current_task->state = RUNNING
+ * gp_crrent_task != p_tcb_old
+ * p_tcb_old == NULL or p_tcb_old->state updated
+ * @note: caller must ensure the pre-conditions are met before calling.
+ * the function does not check the pre-condition!
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * @attention CRITICAL SECTION
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ *
+ *****************************************************************************/
+__asm void k_tsk_switch(TCB *p_tcb_old)
+{
+ PUSH {R0-R12, LR}
+ STR SP, [R0, #TCB_MSP_OFFSET] ; save SP to p_old_tcb->msp
+K_RESTORE
+ LDR R1, =__cpp(&gp_current_task);
+ LDR R2, [R1]
+ LDR SP, [R2, #TCB_MSP_OFFSET] ; restore msp of the gp_current_task
+
+ POP {R0-R12, PC}
+}
+
+
+/**************************************************************************//**
+ * @brief run a new thread. The caller becomes READY and
+ * the scheduler picks the next ready to run task.
+ * @return RTX_ERR on error and zero on success
+ * @pre gp_current_task != NULL && gp_current_task == RUNNING
+ * @post gp_current_task gets updated to next to run task
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * @attention CRITICAL SECTION
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ *****************************************************************************/
+int k_tsk_run_new(void)
+{
+ TCB *p_tcb_old = NULL;
+
+ if (gp_current_task == NULL) {
+ return RTX_ERR;
+ }
+
+ p_tcb_old = gp_current_task;
+ gp_current_task = scheduler();
+
+ if ( gp_current_task == NULL ) {
+ gp_current_task = p_tcb_old; // revert back to the old task
+ return RTX_ERR;
+ }
+
+ // at this point, gp_current_task != NULL and p_tcb_old != NULL
+ if (gp_current_task != p_tcb_old) {
+ gp_current_task->state = RUNNING; // change state of the to-be-switched-in tcb
+ if(p_tcb_old->state != DORMANT){
+ p_tcb_old->state = READY; // change state of the to-be-switched-out tcb
+ }
+ k_tsk_switch(p_tcb_old); // switch stacks
+ }
+
+ return RTX_OK;
+}
+
+/**************************************************************************//**
+ * @brief yield the cpu
+ * @return: RTX_OK upon success
+ * RTX_ERR upon failure
+ * @pre: gp_current_task != NULL &&
+ * gp_current_task->state = RUNNING
+ * @post gp_current_task gets updated to next to run task
+ * @note: caller must ensure the pre-conditions before calling.
+ *****************************************************************************/
+int k_tsk_yield(void)
+{
+ g_task_count++;
+ gp_current_task->task_count = g_task_count;
+ return k_tsk_run_new();
+}
+
+
+/*
+ *===========================================================================
+ * TO BE IMPLEMETED IN LAB2
+ *===========================================================================
+ */
+
+int k_tsk_create(task_t *task, void (*task_entry)(void), U8 prio, U16 stack_size)
+{
+#ifdef DEBUG_0
+ printf("k_tsk_create: entering...\n\r");
+ printf("task = 0x%x, task_entry = 0x%x, prio=%d, stack_size = %d\n\r", task, task_entry, prio, stack_size);
+#endif /* DEBUG_0 */
+
+ // TODO: `k_tsk_create` is non-blocking, but can be preempted by `scheduler`
+ // TODO: check pointers
+ // TODO: error checking additional conditions
+
+ // TID pointer NULL
+ if (task == NULL){
+ return RTX_ERR;
+ }
+
+ // Task entry pointer NULL
+ if (task_entry == NULL){
+ return RTX_ERR;
+ }
+
+ // Maximum number of tasks reached
+ if (g_num_active_tasks == MAX_TASKS){
+ return RTX_ERR;
+ }
+
+ // stack size too small
+ if (stack_size < PROC_STACK_SIZE){
+ return RTX_ERR;
+ }
+
+ // stack size too big
+ size_t ALL_HEAP = 0xFFFFFFFF;
+ size_t suitable_regions = k_mem_count_extfrag(ALL_HEAP) - k_mem_count_extfrag(stack_size);
+ if (!suitable_regions){
+ return RTX_ERR;
+ }
+
+ // stack_size not 8 bytes aligned
+ if (stack_size % 8 != 0){
+ return RTX_ERR;
+ }
+
+ // prio invalid
+ if (prio != HIGH && prio != MEDIUM && prio != LOW && prio != LOWEST){
+ return RTX_ERR;
+ }
+
+ RTX_TASK_INFO task_info;
+ TCB * tcb = NULL;
+
+ // linear traverse to find free TID in g_tcbs;
+ for (int i=0; i < MAX_TASKS; i++){
+ // get dormant TCB
+ if(g_tcbs[i].state == DORMANT){
+ tcb = &g_tcbs[i];
+ break;
+ }
+ }
+
+ // get TID and store in buffer
+ *task = tcb->tid;
+
+ // fill in task_info
+ task_info.prio = prio;
+ task_info.priv = 0;
+ task_info.u_stack_size = stack_size;
+ task_info.ptask = task_entry;
+
+ // call k_tsk_create_new
+ if (k_tsk_create_new(&task_info, tcb, *task) == RTX_ERR){
+ return RTX_ERR;
+ }
+
+ g_num_active_tasks++;
+ //scheduler(); do we need to call?
+
+// if (currently_running()) {
+// k_tsk_yield();
+// } else {
+// return RTX_ERR;
+// }
+
+
+ return RTX_OK;
+}
+
+void k_tsk_exit(void)
+{
+
+#ifdef DEBUG_0
+ printf("k_tsk_exit: entering...\n\r");
+#endif /* DEBUG_0 */
+
+ gp_current_task->state = DORMANT;
+
+ TCB* p_tcb_old = gp_current_task;
+ gp_current_task = scheduler();
+
+ if(p_tcb_old->priv == 0){
+ k_mem_dealloc((void *) ((U32)p_tcb_old->u_stack_hi - p_tcb_old->u_stack_size));
+ }
+
+ g_num_active_tasks--;
+ remove_id(heap, p_tcb_old->tid);
+
+ if ( gp_current_task == NULL ) {
+ gp_current_task = p_tcb_old; // revert back to the old task
+ return;
+ }
+
+ // at this point, gp_current_task != NULL and p_tcb_old != NULL
+ if (gp_current_task != p_tcb_old) {
+ gp_current_task->state = RUNNING; // change state of the to-be-switched-in tcb
+ k_tsk_switch(p_tcb_old); // switch stacks
+ }
+
+ return;
+}
+
+int k_tsk_set_prio(task_t task_id, U8 prio)
+{
+#ifdef DEBUG_0
+ printf("k_tsk_set_prio: entering...\n\r");
+ printf("task_id = %d, prio = %d.\n\r", task_id, prio);
+#endif /* DEBUG_0 */
+
+ // TODO: This function never blocks, but can be preempted. what does this mean?
+ // TODO: if try to set null task to prio PRIO_NULL, do I let it or error?
+
+ // prio invalid or PRIO_NULL
+ if (prio != HIGH && prio != MEDIUM && prio != LOW && prio != LOWEST){
+ return RTX_ERR;
+ }
+
+ // dormant TCB
+ if (g_tcbs[task_id].state == DORMANT){
+ return RTX_ERR;
+ }
+
+ if (prio == g_tcbs[task_id].prio) {
+ return RTX_OK;
+ }
+
+ // valid TID
+ if (task_id > 0 && task_id < MAX_TASKS){
+ // user-mode task can change prio of any user-mode task
+ // user-mode task cannot change prio of kernel task
+ // kernel task can change prio of any user-mode or kernel task
+
+ if(gp_current_task->priv == 1){
+ g_tcbs[task_id].prio = prio;
+ } else {
+ if(g_tcbs[task_id].priv == 1){
+ return RTX_ERR;
+ } else {
+ g_tcbs[task_id].prio = prio;
+ }
+ }
+
+ reset_priority(heap, task_id, prio);
+
+ k_tsk_yield();
+
+ return RTX_OK;
+ }else{
+ return RTX_ERR;
+ }
+}
+
+int k_tsk_get(task_t task_id, RTX_TASK_INFO *buffer)
+{
+#ifdef DEBUG_0
+ printf("k_tsk_get: entering...\n\r");
+ printf("task_id = %d, buffer = 0x%x.\n\r", task_id, buffer);
+#endif /* DEBUG_0 */
+
+ // error checking
+ if (buffer == NULL) {
+ return RTX_ERR;
+ }
+ // Dormant TCB
+ if (g_tcbs[task_id].state == DORMANT){
+ return RTX_ERR;
+ }
+
+ // valid TID excluding 0
+ if (task_id > 0 && task_id < MAX_TASKS){
+ buffer->tid = task_id;
+ buffer->prio = g_tcbs[task_id].prio;
+ buffer->state = g_tcbs[task_id].state;
+ buffer->priv = g_tcbs[task_id].priv;
+ buffer->ptask = g_tcbs[task_id].ptask;
+ buffer->k_stack_hi = (U32) (&g_k_stacks[task_id+1]); // kernel stack hi grows downwards
+ buffer->k_stack_size = KERN_STACK_SIZE;
+ buffer->u_stack_hi = g_tcbs[task_id].u_stack_hi;
+ buffer->u_stack_size = g_tcbs[task_id].u_stack_size;
+
+ buffer->u_sp = * (U32*)((U32) g_tcbs[task_id].msp + 108);
+
+ if (task_id == gp_current_task->tid){
+ int regVal = __current_sp(); // store value of SP register in regVal
+ buffer->k_sp = regVal;
+ }else{
+ buffer->k_sp = (U32) g_tcbs[task_id].msp;
+ }
+ return RTX_OK;
+
+ }else{
+ return RTX_ERR;
+ }
+}
+
+int k_tsk_ls(task_t *buf, int count){
+#ifdef DEBUG_0
+ printf("k_tsk_ls: buf=0x%x, count=%d\r\n", buf, count);
+#endif /* DEBUG_0 */
+ return 0;
+}
+
+/*
+ *===========================================================================
+ * TO BE IMPLEMETED IN LAB4
+ *===========================================================================
+ */
+
+int k_tsk_create_rt(task_t *tid, TASK_RT *task, RTX_MSG_HDR *msg_hdr, U32 num_msgs)
+{
+ return 0;
+}
+
+void k_tsk_done_rt(void) {
+#ifdef DEBUG_0
+ printf("k_tsk_done: Entering\r\n");
+#endif /* DEBUG_0 */
+ return;
+}
+
+void k_tsk_suspend(struct timeval_rt *tv)
+{
+#ifdef DEBUG_0
+ printf("k_tsk_suspend: Entering\r\n");
+#endif /* DEBUG_0 */
+ return;
+}
+
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab2/code/src/kernel/k_task.h b/submission/lab2/code/src/kernel/k_task.h
new file mode 100755
index 0000000..d2685fc
--- /dev/null
+++ b/submission/lab2/code/src/kernel/k_task.h
@@ -0,0 +1,85 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice and the following disclaimer.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ ****************************************************************************
+ */
+
+/**************************************************************************//**
+ * @file k_task.h
+ * @brief Task Management Header File
+ *
+ * @version V1.2021.01
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ *
+ * @details
+ * @note Starter code assumes there are only two privileged tasks
+ *
+ *****************************************************************************/
+
+#ifndef K_TASK_H_
+#define K_TASK_H_
+
+#include "k_inc.h"
+#include "k_HAL_CA.h"
+
+/*
+ *==========================================================================
+ * GLOBAL VARIABLES
+ *==========================================================================
+ */
+
+extern TCB *gp_current_task;
+
+/*
+ *===========================================================================
+ * FUNCTION PROTOTYPES
+ *===========================================================================
+ */
+
+extern void task_null (void);
+
+
+// Implemented by Starter Code
+
+int k_tsk_init (RTX_TASK_INFO *task_info, int num_tasks);
+ /* initialize all tasks in the system */
+int k_tsk_create_new (RTX_TASK_INFO *p_taskinfo, TCB *p_tcb, task_t tid);
+ /* create a new task with initial context sitting on a dummy stack frame */
+TCB *scheduler (void); /* return the TCB of the next ready to run task */
+void k_tsk_switch (TCB *); /* kernel thread context switch, two stacks */
+int k_tsk_run_new (void); /* kernel runs a new thread */
+int k_tsk_yield (void); /* kernel tsk_yield function */
+
+// Not implemented, to be done by students
+int k_tsk_create (task_t *task, void (*task_entry)(void), U8 prio, U16 stack_size);
+void k_tsk_exit (void);
+int k_tsk_set_prio (task_t task_id, U8 prio);
+int k_tsk_get (task_t task_id, RTX_TASK_INFO *buffer);
+int k_tsk_create_rt (task_t *tid, TASK_RT *task, RTX_MSG_HDR *msg_hdr, U32 num_msgs);
+void k_tsk_done_rt (void);
+void k_tsk_suspend (struct timeval_rt *tv);
+
+#endif // ! K_TASK_H_
diff --git a/submission/lab2/code/src/kernel/main_svc_cw.c b/submission/lab2/code/src/kernel/main_svc_cw.c
new file mode 100755
index 0000000..9458f17
--- /dev/null
+++ b/submission/lab2/code/src/kernel/main_svc_cw.c
@@ -0,0 +1,113 @@
+/*
+ ****************************************************************************
+ *
+ * UNIVERSITY OF WATERLOO ECE 350 RTOS LAB
+ *
+ * Copyright 2020-2021 Yiqing Huang
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright
+ * notice and the following disclaimer.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ ****************************************************************************
+ */
+
+
+/**************************************************************************//**
+ * @file: main_svc.c
+ * @brief: main routine to start up the RTX and two initial tasks
+ * @version V1.2021.01.lab2
+ * @authors Yiqing Huang
+ * @date 2021 JAN
+ * @note standard C library is not allowed in the final kernel code.
+ * A tiny printf function for embedded application development
+ * taken from http://www.sparetimelabs.com/tinyprintf/tinyprintf.php
+ * is configured to use UART0 to output when DEBUG_0 is defined.
+ * The init_printf(NULL, putc) MUST be called to initialize
+ * the printf function.
+ *****************************************************************************/
+
+
+#include "ae.h"
+#include "system_a9.h"
+#include "Serial.h"
+#include "printf.h"
+#include "k_inc.h"
+#include "k_rtx.h"
+
+extern void __ch_MODE (U32 mode);
+extern void __atomic_on(void);
+extern void __atomic_off(void);
+
+
+void task_null (void)
+{
+ while (1) {
+#ifdef DEBUG_0
+ for ( int i = 0; i < 5; i++ ){
+ printf("==============Task NULL===============\r\n");
+ }
+#endif
+ k_tsk_yield();
+ }
+}
+
+#define num_tasks 1
+
+int main()
+{
+
+ static RTX_SYS_INFO sys_info;
+ static RTX_TASK_INFO task_info[num_tasks];
+
+ char mode = 0;
+
+ // CMSIS system initialization
+ SystemInit();
+
+ __atomic_on();
+ SER_Init(); // uart1 uses polling for output
+ init_printf(NULL, putc); // printf uses uart1 for output
+ __atomic_off();
+
+ mode = __get_mode();
+ printf("mode = 0x%x\r\n", mode);
+
+
+
+ // System and Task set up by auto testing software
+ if (ae_init(&sys_info, task_info, num_tasks) != RTX_OK) {
+ printf("RTX INIT FAILED\r\n");
+ return RTX_ERR;
+ }
+
+ // start the RTX and built-in tasks
+ if (mode == MODE_SVC) {
+ gp_current_task = NULL;
+ k_rtx_init(task_info, num_tasks);
+ }
+
+ task_null();
+
+ // We should never reach here!!!
+ return RTX_ERR;
+}
+/*
+ *===========================================================================
+ * END OF FILE
+ *===========================================================================
+ */
diff --git a/submission/lab2/p2_report.pdf b/submission/lab2/p2_report.pdf
new file mode 100644
index 0000000..b838d39
Binary files /dev/null and b/submission/lab2/p2_report.pdf differ