Compare commits

...

10 commits

Author SHA1 Message Date
Imbus
c2b9a13235 tags >> ignore 2025-05-12 12:06:12 +02:00
Imbus
57d3ae36fb Time program 2025-05-12 12:05:55 +02:00
Imbus
cc5b27a3ab Demo C program on how to use sqlite3 2025-05-12 12:05:46 +02:00
Imbus
d750f55e87 Socket code 2025-05-12 12:05:33 +02:00
Imbus
6af488012f Pid loop sample code 2025-05-12 12:05:29 +02:00
Imbus
582046cb58 Short code demonstrating how MMIO is commonly defined and accessed 2025-05-12 12:05:21 +02:00
Imbus
32acf1d6c7 Miller rabin sample code (untested, likely overflow issues) 2025-05-12 12:04:45 +02:00
Imbus
c788139f72 GBA game header parser 2025-05-12 12:04:24 +02:00
Imbus
905405164c Primitive buddy alloc sample 2025-05-12 12:04:17 +02:00
Imbus
10830c8adb brk/sbrk demo 2025-05-12 12:03:59 +02:00
10 changed files with 576 additions and 0 deletions

1
.gitignore vendored
View file

@ -2,3 +2,4 @@
.cache
.json
*.elf
tags

57
break.c Normal file
View file

@ -0,0 +1,57 @@
#include <stdint.h>
#include <stdio.h>
#include <sys/mman.h> // mmap and friends
#include <unistd.h>
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;
}

111
buddy_allocator.c Normal file
View file

@ -0,0 +1,111 @@
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 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;
}

58
gba_header.c Normal file
View file

@ -0,0 +1,58 @@
#include <stdint.h>
#include <stdio.h>
#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 <gba_rom_file>\n", argv[0]);
return 1;
}
read_gba_header(argv[1]);
return 0;
}

104
miller-rabin.h Normal file
View file

@ -0,0 +1,104 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
/**
* @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;
}

32
mmio_mapping.h Normal file
View file

@ -0,0 +1,32 @@
#include <stdint.h>
// 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
}

74
pid.c Normal file
View file

@ -0,0 +1,74 @@
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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;
}

69
sock.c Normal file
View file

@ -0,0 +1,69 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/socket.h>
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;
}

46
sqlite.c Normal file
View file

@ -0,0 +1,46 @@
#include <sqlite3.h>
#include <stdio.h>
/*
* 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;
}

24
time.c Normal file
View file

@ -0,0 +1,24 @@
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
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);
}