Implemented printf!

This commit is contained in:
Vincenzo Aleksey Brocato 2024-09-07 19:47:25 +02:00 committed by VinceAle7082
parent 0f74ff0432
commit aee4ce37ee
9 changed files with 215 additions and 178 deletions

View File

@ -1,9 +1,8 @@
BUILD_DIR?=build/ BUILD_DIR?=build/
ASM?=nasm ASM?=nasm
ASMFLAGS?=-f obj ASMFLAGS?=-f obj
CC?=gcc
CC16?=/usr/bin/watcom/binl/wcc CC16?=/usr/bin/watcom/binl/wcc
CFLAGS16?= -4 -d3 -s -wx -ms -zl -zq CFLAGS16?=-4 -d3 -s -wx -ms -zl -zq # -oneatxzh
LD16?=/usr/bin/watcom/binl/wlink LD16?=/usr/bin/watcom/binl/wlink
SOURCES_C=$(wildcard *.c) SOURCES_C=$(wildcard *.c)
@ -11,7 +10,7 @@ SOURCES_ASM=$(wildcard *.asm)
OBJECTS_C=$(patsubst %.c, $(BUILD_DIR)/stage2/c/%.obj, $(SOURCES_C)) OBJECTS_C=$(patsubst %.c, $(BUILD_DIR)/stage2/c/%.obj, $(SOURCES_C))
OBJECTS_ASM=$(patsubst %.asm, $(BUILD_DIR)/stage2/asm/%.obj, $(SOURCES_ASM)) OBJECTS_ASM=$(patsubst %.asm, $(BUILD_DIR)/stage2/asm/%.obj, $(SOURCES_ASM))
.PHONY: all clean always .PHONY: all stage2 clean always
all: stage2 all: stage2

View File

@ -1,10 +1,10 @@
FORMAT RAW BIN FORMAT RAW BIN
OPTION QUIET, OPTION QUIET,
NODEFAULTLIBS, NODEFAULTLIBS,
START=entry, START=entry,
VERBOSE, VERBOSE,
OFFSET=0, OFFSET=0,
STACK=0X200 STACK=0x200
ORDER ORDER
CLNAME CODE CLNAME CODE
SEGMENT _ENTRY SEGMENT _ENTRY

View File

@ -0,0 +1,22 @@
bits 16
section _ENTRY class=CODE
extern _cstart_
global entry
entry:
cli
mov ax, ds
mov ss, ax
mov sp, 0
mov bp, sp
sti
xor dh, dh
push dx
call _cstart_
cli
hlt

View File

@ -3,6 +3,11 @@
void _cdecl cstart_(uint16_t bootDrive) void _cdecl cstart_(uint16_t bootDrive)
{ {
puts("Hello World from the Stage 2 of the bootloader written in C!"); const char far* far_str = "far string";
puts("Hello world from stage 2 of the bootloader written in C!\r\n");
printf("Formatted %% %c %s %ls\r\n", 'a', "string", far_str);
printf("Formatted %d %i %x %p %o %hd %hi %hhu %hhd\r\n", 1234, -5678, 0xdead, 0xbeef, 012345, (short)27, (short)-42, (unsigned char)20, (signed char)-10);
printf("Formatted %ld %lx %lld %llx\r\n", -100000000l, 0xdeadbeeful, 10200300400ll, 0xdeadbeeffeebdaedull);
for (;;); for (;;);
} }

View File

@ -6,9 +6,12 @@ typedef signed short int16_t;
typedef unsigned short uint16_t; typedef unsigned short uint16_t;
typedef signed long int int32_t; typedef signed long int int32_t;
typedef unsigned long int uint32_t; typedef unsigned long int uint32_t;
typedef signed long int int64_t; typedef signed long long int int64_t;
typedef unsigned long int uint64_t; typedef unsigned long long int uint64_t;
typedef uint8_t bool; typedef uint8_t bool;
#define true 1
#define false 0 #define false 0
#define true 1

View File

@ -5,7 +5,17 @@ void putc(char c)
{ {
x86_Video_WriteCharTeletype(c, 0); x86_Video_WriteCharTeletype(c, 0);
} }
void puts(const char *str)
void puts(const char* str)
{
while(*str)
{
putc(*str);
str++;
}
}
void puts_f(const char far* str)
{ {
while(*str) while(*str)
{ {
@ -26,11 +36,11 @@ void puts(const char *str)
#define PRINTF_LENGTH_LONG 3 #define PRINTF_LENGTH_LONG 3
#define PRINTF_LENGTH_LONG_LONG 4 #define PRINTF_LENGTH_LONG_LONG 4
int * printf_number(int *argp, int length, bool sign, int radix); int* printf_number(int* argp, int length, bool sign, int radix);
void _cdecl printf(const char *fmt, ...) void _cdecl printf(const char* fmt, ...)
{ {
int *argp = (int *)&fmt; int* argp = (int*)&fmt;
int state = PRINTF_STATE_NORMAL; int state = PRINTF_STATE_NORMAL;
int length = PRINTF_LENGTH_DEFAULT; int length = PRINTF_LENGTH_DEFAULT;
int radix = 10; int radix = 10;
@ -42,118 +52,97 @@ void _cdecl printf(const char *fmt, ...)
{ {
switch (state) switch (state)
{ {
case PRINTF_STATE_NORMAL: case PRINTF_STATE_NORMAL:
switch (*fmt) switch (*fmt)
{
case '%':
state = PRINTF_STATE_LENGTH;
break;
default:
putc(*fmt);
break;
}
break;
case PRINTF_STATE_LENGTH:
switch (*fmt)
{
case 'h':
length = PRINTF_LENGTH_SHORT;
state = PRINTF_STATE_LENGTH_SHORT;
break;
case 'l':
length = PRINTF_LENGTH_LONG;
state = PRINTF_STATE_LENGTH_LONG;
break;
default:
goto PRINTF_STATE_SPEC_;
}
break;
case PRINTF_STATE_LENGTH_SHORT:
if (*fmt == 'h')
{
length = PRINTF_LENGTH_SHORT_SHORT;
state = PRINTF_STATE_SPEC;
}
else
goto PRINTF_STATE_SPEC_;
break;
case PRINTF_STATE_LENGTH_LONG:
if (*fmt == 'l')
{
length = PRINTF_LENGTH_LONG_LONG;
state = PRINTF_STATE_SPEC;
}
else
goto PRINTF_STATE_SPEC_;
break;
case PRINTF_STATE_SPEC:
PRINTF_STATE_SPEC_:
switch (*fmt)
{
case 'c':
putc((char)*argp);
argp++;
break;
case 's':
if (length == PRINTF_LENGTH_LONG || length == PRINTF_LENGTH_LONG_LONG)
{ {
puts_f(*(const char far **)argp); case '%': state = PRINTF_STATE_LENGTH;
argp += 2; break;
} default: putc(*fmt);
else break;
{
puts(*(const char **)argp);
argp++;
} }
break; break;
case '%': case PRINTF_STATE_LENGTH:
putc('%'); switch (*fmt)
{
case 'h': length = PRINTF_LENGTH_SHORT;
state = PRINTF_STATE_LENGTH_SHORT;
break;
case 'l': length = PRINTF_LENGTH_LONG;
state = PRINTF_STATE_LENGTH_LONG;
break;
default: goto PRINTF_STATE_SPEC_;
}
break; break;
case 'd': case PRINTF_STATE_LENGTH_SHORT:
case 'i': if (*fmt == 'h')
radix = 10; {
sign = true; length = PRINTF_LENGTH_SHORT_SHORT;
argp = printf_number(argp, length, sign, radix); state = PRINTF_STATE_SPEC;
}
else goto PRINTF_STATE_SPEC_;
break; break;
case 'u': case PRINTF_STATE_LENGTH_LONG:
if (*fmt == 'l')
{
length = PRINTF_LENGTH_LONG_LONG;
state = PRINTF_STATE_SPEC;
}
else goto PRINTF_STATE_SPEC_;
break;
case PRINTF_STATE_SPEC:
PRINTF_STATE_SPEC_:
switch (*fmt)
{
case 'c': putc((char)*argp);
argp++;
break;
case 's': if (length == PRINTF_LENGTH_LONG || length == PRINTF_LENGTH_LONG_LONG)
{
puts_f(*(const char far**)argp);
argp += 2;
}
else
{
puts(*(const char**)argp);
argp++;
}
break;
case '%': putc('%');
break;
case 'd':
case 'i': radix = 10; sign = true;
argp = printf_number(argp, length, sign, radix);
break;
case 'u': radix = 10; sign = false;
argp = printf_number(argp, length, sign, radix);
break;
case 'X':
case 'x':
case 'p': radix = 16; sign = false;
argp = printf_number(argp, length, sign, radix);
break;
case 'o': radix = 8; sign = false;
argp = printf_number(argp, length, sign, radix);
break;
default: break;
}
state = PRINTF_STATE_NORMAL;
length = PRINTF_LENGTH_DEFAULT;
radix = 10; radix = 10;
sign = false; sign = false;
argp = printf_number(argp, length, sign, radix);
break; break;
case 'X':
case 'x':
case 'p':
radix = 16;
sign = false;
argp = printf_number(argp, length, sign, radix);
break;
case 'o':
radix = 8;
sign = false;
argp = printf_number(argp, length, sign, radix);
break;
// ignore invalid spec
default:
break;
}
// reset state
state = PRINTF_STATE_NORMAL;
length = PRINTF_LENGTH_DEFAULT;
radix = 10;
sign = false;
break;
} }
fmt++; fmt++;
@ -162,86 +151,82 @@ void _cdecl printf(const char *fmt, ...)
const char g_HexChars[] = "0123456789abcdef"; const char g_HexChars[] = "0123456789abcdef";
int *printf_number(int *argp, int length, bool sign, int radix) int* printf_number(int* argp, int length, bool sign, int radix)
{ {
char buffer[32]; char buffer[32];
unsigned long long number; unsigned long long number;
int number_sign = 1; int number_sign = 1;
int pos = 0; int pos = 0;
// process length
switch (length) switch (length)
{ {
case PRINTF_LENGTH_SHORT_SHORT: case PRINTF_LENGTH_SHORT_SHORT:
case PRINTF_LENGTH_SHORT: case PRINTF_LENGTH_SHORT:
case PRINTF_LENGTH_DEFAULT: case PRINTF_LENGTH_DEFAULT:
if (sign) if (sign)
{
int n = *argp;
if (n < 0)
{ {
n = -n; int n = *argp;
number_sign = -1; if (n < 0)
{
n = -n;
number_sign = -1;
}
number = (unsigned long long)n;
} }
number = (unsigned long long)n; else
} {
else number = *(unsigned int*)argp;
{ }
number = *(unsigned int *)argp; argp++;
} break;
argp++;
break;
case PRINTF_LENGTH_LONG: case PRINTF_LENGTH_LONG:
if (sign) if (sign)
{
long int n = *(long int *)argp;
if (n < 0)
{ {
n = -n; long int n = *(long int*)argp;
number_sign = -1; if (n < 0)
{
n = -n;
number_sign = -1;
}
number = (unsigned long long)n;
} }
number = (unsigned long long)n; else
} {
else number = *(unsigned long int*)argp;
{ }
number = *(unsigned long int *)argp; argp += 2;
} break;
argp += 2;
break;
case PRINTF_LENGTH_LONG_LONG: case PRINTF_LENGTH_LONG_LONG:
if (sign) if (sign)
{
long long int n = *(long long int *)argp;
if (n < 0)
{ {
n = -n; long long int n = *(long long int*)argp;
number_sign = -1; if (n < 0)
{
n = -n;
number_sign = -1;
}
number = (unsigned long long)n;
} }
number = (unsigned long long)n; else
} {
else number = *(unsigned long long int*)argp;
{ }
number = *(unsigned long long int *)argp; argp += 4;
} break;
argp += 4;
break;
} }
// convert number to ASCII
do do
{ {
uint32_t rem = number % radix; uint32_t rem;
number = number / radix; x86_div64_32(number, radix, &number, &rem);
buffer[pos++] = g_HexChars[rem]; buffer[pos++] = g_HexChars[rem];
} while (number > 0); } while (number > 0);
// add sign
if (sign && number_sign < 0) if (sign && number_sign < 0)
buffer[pos++] = '-'; buffer[pos++] = '-';
// print number in reverse order
while (--pos >= 0) while (--pos >= 0)
putc(buffer[pos]); putc(buffer[pos]);

View File

@ -2,4 +2,5 @@
void putc(char c); void putc(char c);
void puts(const char* str); void puts(const char* str);
void _cdecl printf(const char *fmt, ...); void puts_f(const char far* str);
void _cdecl printf(const char* fmt, ...);

View File

@ -25,3 +25,24 @@ _x86_Video_WriteCharTeletype:
global _x86_div64_32 global _x86_div64_32
_x86_div64_32: _x86_div64_32:
push bp
mov bp, sp
push bx
mov eax, [bp + 4]
mov ecx, [bp + 12]
xor edx, edx
div ecx
mov bx, [bp + 16]
mov [bx + 4], eax
mov eax, [bp + 4]
div ecx
mov [bx], eax
mov bx, [bp + 18]
mov [bx], edx
pop bx
mov sp, bp
pop bp
ret

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "stdint.h" #include "stdint.h"
void _cdecl x86_div64_32(uint64_t dividend, uint32_t divisor, uint64_t* quotientOut, uint32_t* remainderOut);
void _cdecl x86_Video_WriteCharTeletype(char c, uint8_t page); void _cdecl x86_Video_WriteCharTeletype(char c, uint8_t page);
void _cdecl x86_div64_32(uint64_t dividend, uint32_t divisor, uint64_t *quotientOut, uint64_t *remainderOut);