Skip to content

Commit

Permalink
Merge pull request #4 from akriese/feature/glue-serial-printf
Browse files Browse the repository at this point in the history
feat: glue serial i/o and printf
  • Loading branch information
akriese authored Nov 6, 2023
2 parents 3c25b51 + c2b6a40 commit 6e0157a
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 113 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
# Quellen
#
LSCRIPT = kernel.lds
OBJ = start.o serial.o
OBJ = start.o serial.o printf.o

#
# Konfiguration
Expand Down
93 changes: 93 additions & 0 deletions printf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#include <stdarg.h> // for va_list etc., can be imported, as not OS specific

#include "serial.h"

#define HEX_POSITIONS 8 // 1 hex char represents 4 bits; assuming 32bit integers

/*
* Some function that actually prints a character or sends it via the serial
* interface
*/
void _print(char c) { serial_write(c); }

void _printChar(const char c);
void _printString(const char *s);
void _printHex(const int u);
void _printAddress(const void *p);

/*
* Our printf implementation
*
*/
__attribute__((format(printf, 1, 2))) void printf(const char *fmt, ...) {
va_list arguments;

va_start(arguments, fmt);

while (*fmt) {
if (*fmt != '%') {
_print(*fmt);
fmt++;
continue;
}

char f = *(++fmt);

// in case there is a trailing '%'
if (!f) {
_print('%');
break;
}

switch (f) {
case 'c':
_printChar((char)va_arg(arguments, int));
break;
case 's':
_printString(va_arg(arguments, char *));
break;
case 'x':
_printHex(va_arg(arguments, int));
break;
case 'p':
_printAddress(va_arg(arguments, void *));
break;
default:
_printString("Invalid formatter!");
}

fmt++;
}

va_end(arguments);
}

void _printChar(const char c) { _print(c); }

void _printString(const char *s) {
while (*s) {
_print(*s++);
}
}

char _singleHex(int u) {
if (u < 10)
return '0' + u;
return 'a' + u - 10;
}

void _printHex(const int u) {
char hex[HEX_POSITIONS + 1]; // including trailing null terminator

hex[HEX_POSITIONS] = '\0';

for (int i = 0; i < HEX_POSITIONS; ++i) {
char res = _singleHex(u >> (i * 4) & 0xF);
hex[HEX_POSITIONS - i - 1] = res;
}

// using the string formatting of our own printf to prepend the "0x"
printf("0x%s", hex);
}

void _printAddress(const void *p) { _printHex((int)p); }
98 changes: 2 additions & 96 deletions printf.h
Original file line number Diff line number Diff line change
@@ -1,96 +1,2 @@
/*
*/

#include <stdarg.h> // for va_list etc

#define HEX_POSITIONS 8 // 1 hex char represents 4 bits; assuming 32bit integers

/*
* Some function that actually prints a character or sends it via the serial
* interface
*/
void _print(char c);

void _printChar(const char c);
void _printString(const char *s);
void _printHex(const int u);
void _printAddress(const void *p);

/*
* Our printf implementation
*
*/
__attribute__((format(printf, 1, 2)))
void print(const char *fmt, ...) {
va_list arguments;

va_start(arguments, fmt);

while (*fmt) {
if (*fmt != '%') {
_print(*fmt);
fmt++;
continue;
}

char f = *(++fmt);

// in case there is a trailing '%'
if (!f) {
_print('%');
break;
}

switch (f) {
case 'c':
_printChar((char)va_arg(arguments, int));
break;
case 's':
_printString(va_arg(arguments, char *));
break;
case 'x':
_printHex(va_arg(arguments, int));
break;
case 'p':
_printAddress(va_arg(arguments, void *));
break;
default:
_printString("Invalid formatter!");
}

fmt++;
}

va_end(arguments);
}

void _printChar(const char c) { _print(c); }

void _printString(const char *s) {
while (*s) {
_print(*s++);
}
}

char _singleHex(int u) {
if (u < 10)
return '0' + u;
return 'a' + u - 10;
}

void _printHex(const int u) {
char hex[HEX_POSITIONS + 1]; // including trailing null terminator

hex[HEX_POSITIONS] = '\0';

for (int i = 0; i < HEX_POSITIONS; ++i) {
char res = _singleHex(u >> (i * 4) & 0xF);
hex[HEX_POSITIONS - i - 1] = res;
}

// using the string formatting of our own printf to prepend the "0x"
print("0x%s", hex);
}

void _printAddress(const void *p) { _printHex((int)p); }
// prints a string with format identifiers and variable arguments
void printf(const char *fmt, ...);
6 changes: 3 additions & 3 deletions serial.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ void write_char(char c) { *(volatile char *)DBGU_THR = c; }
* There is no need to clear the register or signal anything after reading,
* as that is done by the controller upon the register read instruction.
*/
char read() {
char serial_read() {
// enable receive controller
set_status(DBGU_CR, RXEN_BIT);

Expand All @@ -66,7 +66,7 @@ char read() {
*
* The controller has to be enabled before and disabled afterwards.
*/
void write(char c) {
void serial_write(char c) {
// enable write controller
set_status(DBGU_CR, TXEN_BIT);

Expand All @@ -89,7 +89,7 @@ void write(char c) {
* disabled afterwards, but not inbetween, as multiple characters can be sent in
* a row.
*/
void write_string(char *s) {
void serial_write_string(char *s) {
// enable write controller
set_status(DBGU_CR, TXEN_BIT);

Expand Down
7 changes: 3 additions & 4 deletions serial.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
// Reads a char from the serial interface
char read();
char serial_read();

// Writes a char to the serial interface
void write(char c);
void serial_write(char c);

// Writes a string to the serial interface. Stops at the first \0 in s
void write_string(char *s);

void serial_write_string(char *s);
16 changes: 7 additions & 9 deletions start.c
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
// include what you want to execute
#include "printf.h"
#include "serial.h"

__attribute__((naked, section(".init"))) void _start(void) {
// execute your os here
write_string("Type a character and shrineOS will translate it!\n\r");
write_string("Terminate the OS with 'q'!\n\r");
printf("Type a character and shrineOS will translate it!\n\r");
printf("Terminate the OS with 'q'!\n\r");

for (;;) {
char c = read();
write_string("You gave the char: ");
write(c);
char c = serial_read();
printf("You gave the char: %c\n\r", c);

if (c == 'q') {
write_string("\n\rAnd now, I'll terminate myself...");
printf("And now, I'll terminate myself...\n\r");
break;
}

write_string("\n\rshrineOS says: ");
write(c + 1);
write_string("\n\r");
printf("shrineOS says: %c\n\r", c + 1);
}

// then use an endless loop (for now)
Expand Down

0 comments on commit 6e0157a

Please sign in to comment.