From 10830c8adb3d9a74559c17cb2a4bc2710ab3ce5c Mon Sep 17 00:00:00 2001 From: Imbus <> Date: Mon, 12 May 2025 12:03:59 +0200 Subject: [PATCH 01/10] brk/sbrk demo --- break.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 break.c diff --git a/break.c b/break.c new file mode 100644 index 0000000..38828a3 --- /dev/null +++ b/break.c @@ -0,0 +1,57 @@ +#include +#include +#include // mmap and friends +#include + +int main(void) { + /* + * See: "man 3 sysconf" or + * https://www.man7.org/linux/man-pages/man3/sysconf.3.html + * + * See: "man 3 getauxval" or + * https://www.man7.org/linux/man-pages/man3/getauxval.3.html + */ + long page_size = + sysconf(_SC_PAGESIZE); // or _SC_PAGE_SIZE (POSIX allows both) + if (page_size == -1) { + perror("sysconf"); + return 1; + } + + printf("Page size: %ld bytes\n", page_size); + + /* + * sbrk(): + * Increase or decrease the end of accessible data space by DELTA bytes. + * If successful, returns the address the previous end of data space + * (i.e. the beginning of the new space, if DELTA > 0); returns (void \*) -1 + * for errors (with errno set). + */ + void *first = sbrk(0); + void *second = sbrk(4096); + void *third = sbrk(0); + + printf("First: %p\n", first); + printf("Second: %p\n", second); + printf("Third: %p\n", third); + + /* + * mmap, munmap - map or unmap files or devices into memory + * + * mmap() creates a new mapping in the virtual address space of the + * calling process. The starting address for the new mapping is specified + * in addr. The length argument specifies the length of the mapping + * (which must be greater than 0). + */ + + uint8_t *first_mmap = mmap(NULL, page_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0); + + uint8_t *second_mmap = mmap(NULL, page_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0); + + printf("First mmap: %p\n", first_mmap); + printf("Second mmap: %p\n", second_mmap); + + return 0; +} From 905405164cfbe0e084fcc5acb1c9709e025633db Mon Sep 17 00:00:00 2001 From: Imbus <> Date: Mon, 12 May 2025 12:04:17 +0200 Subject: [PATCH 02/10] Primitive buddy alloc sample --- buddy_allocator.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 buddy_allocator.c diff --git a/buddy_allocator.c b/buddy_allocator.c new file mode 100644 index 0000000..4b7743d --- /dev/null +++ b/buddy_allocator.c @@ -0,0 +1,111 @@ +#include +#include +#include +#include +#include + +// This allocator lacks critical features such as coalescing + +#define HEAP_SIZE (1 << 20) // 1 MB +#define MIN_ORDER 5 // 32 bytes +#define MAX_ORDER 20 // 1 MB + +#define ORDER_TO_SZ(order) (1 << order) + +// Round size up to nearest power-of-two order +static int size_to_order(size_t size) { + int order = MIN_ORDER; + while ((1U << order) < size) + order++; + return order; +} + +typedef struct block { + struct block *next; + // int order; + // int is_free; +} block_t; + +static char *heap; +static block_t *free_lists[MAX_ORDER - MIN_ORDER + 1]; + +void buddy_init() { + block_t *initial = (block_t *)heap; + initial->next = NULL; + // initial->order = MAX_ORDER; + // initial->is_free = 1; + free_lists[MAX_ORDER - MIN_ORDER] = initial; +} + +void *buddy_alloc(size_t size) { + int order = size_to_order(size); + int index = order - MIN_ORDER; + + // Find the first available block of order >= needed + int i = index; // i is the lowest possible order here + while (i <= MAX_ORDER - MIN_ORDER && !free_lists[i]) { + i++; + } + + // Check if were still within range, if not there are no free blocks + if (i > MAX_ORDER - MIN_ORDER) + return NULL; + + // Split blocks down to the requested size + while (i > index) { // Does not run if i == index + block_t *bigger = free_lists[i]; + free_lists[i] = bigger->next; // This may be null, doesnt matter + + i--; // i is now equivalent to one order below + + size_t split_size = ORDER_TO_SZ(i); + // FIXME: Char??? + char *middle = ((char *)bigger + split_size); + block_t *buddy = (block_t *)middle; + // block_t *buddy = (block_t *)((char *)bigger + split_size); + buddy->next = NULL; + bigger->next = buddy; // Biggers buddy is of equal size + free_lists[i] = bigger; // Bigger is no longer bigger here + } + + // Allocate from free list + block_t *block = free_lists[index]; + free_lists[index] = block->next; + return (void *)block; +} + +// Free a block (no coalescing) +void buddy_free(void *ptr, size_t size) { + memset(ptr, 0xFFFFFFFF, size); + + int order = size_to_order(size); + int index = order - MIN_ORDER; + + // Push this in front of the orders index + block_t *block = (block_t *)ptr; + block->next = free_lists[index]; + free_lists[index] = block; +} + +int main(void) { + heap = malloc(1 << 20); + + printf("Order: %d\n", size_to_order(100)); + printf("Order: %d\n", size_to_order(1000)); + + buddy_init(); + + void *a = buddy_alloc(100); + void *b = buddy_alloc(1000); + + *(int *)a = 10; + printf("a = %d\n", *(int *)a); + + buddy_free(a, 100); + buddy_free(b, 1000); + + printf("a = %d\n", *(int *)a); + + free(heap); + return 0; +} From c788139f728f9f034fc4c9af9ffcddfec738aee7 Mon Sep 17 00:00:00 2001 From: Imbus <> Date: Mon, 12 May 2025 12:04:24 +0200 Subject: [PATCH 03/10] GBA game header parser --- gba_header.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 gba_header.c diff --git a/gba_header.c b/gba_header.c new file mode 100644 index 0000000..b91a281 --- /dev/null +++ b/gba_header.c @@ -0,0 +1,58 @@ +#include +#include + +#define HEADER_SIZE 192 // GBA header is 192 bytes + +// Structure to hold GBA ROM header data +typedef struct { + uint32_t entry_point; // 0x08000000 - Entry Point + uint8_t nintendo_logo[156]; // 0x08000004 - Nintendo Logo + char game_title[12]; // 0x080000A0 - Game Title + char game_code[4]; // 0x080000AC - Game Code (e.g., "AGB-XXXX") + char maker_code[2]; // 0x080000B0 - Maker Code + uint8_t fixed_value; // 0x080000B2 - Always 0x96 + uint8_t main_unit_code; // 0x080000B3 - Usually 0x00 + uint8_t device_type; // 0x080000B4 - Usually 0x00 + uint8_t reserved1[7]; // 0x080000B5 - Reserved + uint8_t software_version; // 0x080000BC - Software Version + uint8_t complement_check; // 0x080000BD - Header Checksum + uint8_t reserved2[2]; // 0x080000BE - Reserved +} GBAHeader; + +// Function to read and display the ROM header +void read_gba_header(const char *filename) { + FILE *file = fopen(filename, "rb"); + if (!file) { + perror("Error opening file"); + return; + } + + GBAHeader header; + + // Read 192-byte header + if (fread(&header, 1, HEADER_SIZE, file) != HEADER_SIZE) { + perror("Error reading header"); + fclose(file); + return; + } + + fclose(file); + + // Display ROM header information + printf("Game Title: %.12s\n", header.game_title); + printf("Game Code: %.4s\n", header.game_code); + printf("Maker Code: %.2s\n", header.maker_code); + printf("Software Version: %d\n", header.software_version); + printf("Complement Checksum: 0x%02X\n", header.complement_check); + printf("Entry Point: 0x%08X\n", header.entry_point); +} + +int main(int argc, char *argv[]) { + if (argc < 2) { + printf("Usage: %s \n", argv[0]); + return 1; + } + + read_gba_header(argv[1]); + return 0; +} From 32acf1d6c7cdd3e30525a7da782c38acda9afcca Mon Sep 17 00:00:00 2001 From: Imbus <> Date: Mon, 12 May 2025 12:04:45 +0200 Subject: [PATCH 04/10] Miller rabin sample code (untested, likely overflow issues) --- miller-rabin.h | 104 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 miller-rabin.h diff --git a/miller-rabin.h b/miller-rabin.h new file mode 100644 index 0000000..97979a0 --- /dev/null +++ b/miller-rabin.h @@ -0,0 +1,104 @@ +#include +#include +#include + +/** + * @brief Calculates (a * b) % c taking into account that a * b might overflow + * + * @param a First factor + * @param b Second factor + * @param mod The modulo + * @return Resulting value + */ +uint64_t mulmod(uint64_t a, uint64_t b, uint64_t mod); + +/** + * @brief Modular exponentiation + * + * @param base + * @param exponent + * @param mod + * @return + */ +uint64_t modulo(uint64_t base, uint64_t exponent, uint64_t mod); + +/** + * @brief Miller-Rabin Primality Test + * + * This function performs the Miller-Rabin primality test to determine whether + * a given number is prime. The number of iterations increases the accuracy of + * the test but also increases computation time. + * + * @param p The number to test for primality (must be a positive integer). + * @param iteration The number of test rounds to perform (higher means more + * accuracy). + * @return 1 if the number is probably prime, 0 if it is composite. + */ +uint32_t miller_rabin(uint64_t p, uint32_t iteration); + +/* Below code is source, not header */ +/************************************/ + +uint64_t mulmod(uint64_t a, uint64_t b, uint64_t mod) { + uint64_t x = 0, y = a % mod; + + while (b > 0) { + if (b % 2 == 1) { + x = (x + y) % mod; + } + y = (y * 2) % mod; + b /= 2; + } + + return x % mod; +} + +uint64_t modulo(uint64_t base, uint64_t exponent, uint64_t mod) { + uint64_t x = 1; + uint64_t y = base; + + while (exponent > 0) { + if (exponent % 2 == 1) + x = (x * y) % mod; + + y = (y * y) % mod; + + exponent = exponent / 2; + } + + return x % mod; +} + +uint32_t miller_rabin(uint64_t p, uint32_t iteration) { + uint32_t i; + uint64_t s; + + if (p < 2) { + return 0; + } + + if (p != 2 && p % 2 == 0) { + return 0; + } + + s = p - 1; + + while (s % 2 == 0) { + s /= 2; + } + + for (i = 0; i < iteration; i++) { + uint64_t a = rand() % (p - 1) + 1, temp = s; + uint64_t mod = modulo(a, temp, p); + + while (temp != p - 1 && mod != 1 && mod != p - 1) { + mod = mulmod(mod, mod, p); + temp *= 2; + } + + if (mod != p - 1 && temp % 2 == 0) { + return 0; + } + } + return 1; +} From 582046cb58c54487f717702c8b936487ddbd7064 Mon Sep 17 00:00:00 2001 From: Imbus <> Date: Mon, 12 May 2025 12:05:21 +0200 Subject: [PATCH 05/10] Short code demonstrating how MMIO is commonly defined and accessed --- mmio_mapping.h | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 mmio_mapping.h diff --git a/mmio_mapping.h b/mmio_mapping.h new file mode 100644 index 0000000..250104f --- /dev/null +++ b/mmio_mapping.h @@ -0,0 +1,32 @@ +#include + +// Macro for register access (volatile pointer dereferencing, not used here) +#define REG32(addr) (*(volatile uint32_t *)(addr)) +#define REG16(addr) (*(volatile uint16_t *)(addr)) +#define REG8(addr) (*(volatile uint8_t *)(addr)) + +typedef struct MMIO_device { + volatile uint16_t hello; + volatile uint8_t __RESERVED1[2]; + volatile uint16_t status; + volatile uint8_t __RESERVED2[8]; + volatile uint32_t control; + // ...and so on +} __attribute__((aligned(4))) MMIO_device; + +/* A base address pointing to the start of the 'peripherals' memory region */ +#define MEM_PERIPH_BASE 0xDEADBEEF + +/* Specific device, often defined as an offset from a base */ +#define MY_MMIO (MEM_PERIPH_BASE + 0x10) + +#define DVC_CTLR_ENA (0x3 << 1) /* Device Control Register Enable */ +#define DVC_CTLR_WRITE (0x1) /* Device Control Register Write */ + +volatile MMIO_device *mmio1 = (volatile MMIO_device *)MY_MMIO; + +void configure_peripheral() { + mmio1->hello = 0x1234; // Raw write + mmio1->control |= DVC_CTLR_ENA | DVC_CTLR_WRITE; // Set + mmio1->control &= ~(DVC_CTLR_ENA | DVC_CTLR_WRITE); // Clear +} From 6af488012f303daf771544084539b6528eb65f37 Mon Sep 17 00:00:00 2001 From: Imbus <> Date: Mon, 12 May 2025 12:05:29 +0200 Subject: [PATCH 06/10] Pid loop sample code --- pid.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 pid.c diff --git a/pid.c b/pid.c new file mode 100644 index 0000000..df91240 --- /dev/null +++ b/pid.c @@ -0,0 +1,74 @@ +#include +#include +#include +#include + +#define BUFFER_SIZE 100 + +typedef struct { + float Kp, Ki, Kd; // PID gains + float error_buffer[BUFFER_SIZE]; // Circular buffer for integral calculation + int buffer_index; // Current index in the buffer + float integral_sum; // Running sum of integral terms + float prev_error; // Previous error for derivative term + float dt; // Sample time (seconds) +} PIDController; + +// Initialize PID controller +void pid_init(PIDController *pid, float Kp, float Ki, float Kd, float dt) { + pid->Kp = Kp; + pid->Ki = Ki; + pid->Kd = Kd; + pid->dt = dt; + pid->buffer_index = 0; + pid->integral_sum = 0.0f; + pid->prev_error = 0.0f; + memset(pid->error_buffer, 0, sizeof(pid->error_buffer)); +} + +// Compute PID output +float pid_compute(PIDController *pid, float setpoint, float pv) { + float error = setpoint - pv; + + // Update integral term using circular buffer + pid->integral_sum -= + pid->error_buffer[pid->buffer_index]; // Remove oldest value + pid->error_buffer[pid->buffer_index] = + error * pid->dt; // Store new integral term + pid->integral_sum += pid->error_buffer[pid->buffer_index]; // Add new value + + // Advance circular buffer index + pid->buffer_index = (pid->buffer_index + 1) % BUFFER_SIZE; + + // Compute derivative term + float derivative = (error - pid->prev_error) / pid->dt; + pid->prev_error = error; + + // Compute PID output + float output = (pid->Kp * error) + (pid->Ki * pid->integral_sum) + + (pid->Kd * derivative); + + return output; +} + +int main() { + PIDController pid; + pid_init(&pid, 1.0f, 0.1f, 0.05f, + 0.01f); // Kp, Ki, Kd, dt (10ms sample time) + + float setpoint = 100.0f; + float pv = 90.0f; + + for (int i = 0; i < 50; i++) { + float output = pid_compute(&pid, setpoint, pv); + printf("Iteration %d: Setpoint: %.2f, PV: %.2f, Output: %.2f\n", i, + setpoint, pv, output); + + // Simulate process variable update + pv += output * 0.1f; + if (fabsf(output) < 0.4) + setpoint = 150; + } + + return 0; +} From d750f55e871e17838f779a64df203c8dc77a8bf6 Mon Sep 17 00:00:00 2001 From: Imbus <> Date: Mon, 12 May 2025 12:05:33 +0200 Subject: [PATCH 07/10] Socket code --- sock.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 sock.c diff --git a/sock.c b/sock.c new file mode 100644 index 0000000..fbf2e14 --- /dev/null +++ b/sock.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include +#include +#include + +int main(void) { + // Get TCP protocol entry + struct protoent *pent = getprotobyname("tcp"); + if (!pent) { + perror("getprotobyname failed"); + return EXIT_FAILURE; + } + + // Create socket + int server_fd = socket(AF_INET, SOCK_STREAM, pent->p_proto); + if (server_fd < 0) { + perror("socket failed"); + return EXIT_FAILURE; + } + + // Set up server address structure + struct sockaddr_in server_addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = htonl(INADDR_ANY), // Bind to any available address + .sin_port = htons(8080) // Port 8080 + }; + + // Bind socket + if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { + perror("bind failed"); + close(server_fd); + return EXIT_FAILURE; + } + + // Listen for incoming connections + if (listen(server_fd, 5) < 0) { + perror("listen failed"); + close(server_fd); + return EXIT_FAILURE; + } + + printf("Server listening on port 8080...\n"); + + // Accept one client connection + struct sockaddr_in client_addr; + socklen_t client_len = sizeof(client_addr); + int client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_len); + if (client_fd < 0) { + perror("accept failed"); + close(server_fd); + return EXIT_FAILURE; + } + + printf("Client connected!\n"); + + // Send a message to the client + const char *message = "Hello from server!\n"; + send(client_fd, message, strlen(message), 0); + + // Cleanup + close(client_fd); + close(server_fd); + + printf("Exit\n"); + return EXIT_SUCCESS; +} From cc5b27a3abb85aa8cf95fc90be25a3b240cc230e Mon Sep 17 00:00:00 2001 From: Imbus <> Date: Mon, 12 May 2025 12:05:46 +0200 Subject: [PATCH 08/10] Demo C program on how to use sqlite3 --- sqlite.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 sqlite.c diff --git a/sqlite.c b/sqlite.c new file mode 100644 index 0000000..1eb254a --- /dev/null +++ b/sqlite.c @@ -0,0 +1,46 @@ +#include +#include + +/* + * See: https://zetcode.com/db/sqlitec/ + * Build with: + * gcc -o version version.c -lsqlite3 -std=c99 + */ + +int main(void) { + printf("%s\n", sqlite3_libversion()); + + sqlite3 *db; + sqlite3_stmt *res; + + int rc = sqlite3_open(":memory:", &db); + + if (rc != SQLITE_OK) { + + fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db)); + sqlite3_close(db); + + return 1; + } + + rc = sqlite3_prepare_v2(db, "SELECT SQLITE_VERSION()", -1, &res, 0); + + if (rc != SQLITE_OK) { + + fprintf(stderr, "Failed to fetch data: %s\n", sqlite3_errmsg(db)); + sqlite3_close(db); + + return 1; + } + + rc = sqlite3_step(res); + + if (rc == SQLITE_ROW) { + printf("%s\n", sqlite3_column_text(res, 0)); + } + + sqlite3_finalize(res); + sqlite3_close(db); + + return 0; +} From 57d3ae36fb7d12303619c7238551e75bb3759655 Mon Sep 17 00:00:00 2001 From: Imbus <> Date: Mon, 12 May 2025 12:05:55 +0200 Subject: [PATCH 09/10] Time program --- time.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 time.c diff --git a/time.c b/time.c new file mode 100644 index 0000000..1b41166 --- /dev/null +++ b/time.c @@ -0,0 +1,24 @@ +#include +#include +#include + +int main() { + char *out = malloc(200); + struct tm *tmp; + + time_t t = time(NULL); + tmp = localtime(&t); + + if (tmp == NULL) { + perror("localtime"); + exit(EXIT_FAILURE); + }; + + if (strftime(out, 200, "%s", tmp) == 0) { + fprintf(stderr, "strftime returned 0"); + exit(EXIT_FAILURE); + } + + printf("Result string is %s", out); + exit(EXIT_SUCCESS); +} From c2b9a13235032e0c2343a6a2914ad840e4e94180 Mon Sep 17 00:00:00 2001 From: Imbus <> Date: Mon, 12 May 2025 12:06:12 +0200 Subject: [PATCH 10/10] tags >> ignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index aaef027..2a5141d 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ .cache .json *.elf +tags