Implemented printf!

This commit is contained in:
Vincenzo Aleksey Brocato 2024-09-07 19:47:25 +02:00
parent 66254e2108
commit 6d4dad0114
9 changed files with 215 additions and 178 deletions

View File

@ -1,9 +1,8 @@
BUILD_DIR?=build/
ASM?=nasm
ASMFLAGS?=-f obj
CC?=gcc
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
SOURCES_C=$(wildcard *.c)
@ -11,7 +10,7 @@ SOURCES_ASM=$(wildcard *.asm)
OBJECTS_C=$(patsubst %.c, $(BUILD_DIR)/stage2/c/%.obj, $(SOURCES_C))
OBJECTS_ASM=$(patsubst %.asm, $(BUILD_DIR)/stage2/asm/%.obj, $(SOURCES_ASM))
.PHONY: all clean always
.PHONY: all stage2 clean always
all: stage2

View File

@ -4,7 +4,7 @@ OPTION QUIET,
START=entry,
VERBOSE,
OFFSET=0,
STACK=0X200
STACK=0x200
ORDER
CLNAME CODE
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)
{
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 (;;);
}

View File

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

View File

@ -5,6 +5,7 @@ void putc(char c)
{
x86_Video_WriteCharTeletype(c, 0);
}
void puts(const char* str)
{
while(*str)
@ -14,6 +15,15 @@ void puts(const char *str)
}
}
void puts_f(const char far* str)
{
while(*str)
{
putc(*str);
str++;
}
}
#define PRINTF_STATE_NORMAL 0
#define PRINTF_STATE_LENGTH 1
#define PRINTF_STATE_LENGTH_SHORT 2
@ -45,11 +55,9 @@ void _cdecl printf(const char *fmt, ...)
case PRINTF_STATE_NORMAL:
switch (*fmt)
{
case '%':
state = PRINTF_STATE_LENGTH;
case '%': state = PRINTF_STATE_LENGTH;
break;
default:
putc(*fmt);
default: putc(*fmt);
break;
}
break;
@ -57,16 +65,13 @@ void _cdecl printf(const char *fmt, ...)
case PRINTF_STATE_LENGTH:
switch (*fmt)
{
case 'h':
length = PRINTF_LENGTH_SHORT;
case 'h': length = PRINTF_LENGTH_SHORT;
state = PRINTF_STATE_LENGTH_SHORT;
break;
case 'l':
length = PRINTF_LENGTH_LONG;
case 'l': length = PRINTF_LENGTH_LONG;
state = PRINTF_STATE_LENGTH_LONG;
break;
default:
goto PRINTF_STATE_SPEC_;
default: goto PRINTF_STATE_SPEC_;
}
break;
@ -76,8 +81,7 @@ void _cdecl printf(const char *fmt, ...)
length = PRINTF_LENGTH_SHORT_SHORT;
state = PRINTF_STATE_SPEC;
}
else
goto PRINTF_STATE_SPEC_;
else goto PRINTF_STATE_SPEC_;
break;
case PRINTF_STATE_LENGTH_LONG:
@ -86,21 +90,18 @@ void _cdecl printf(const char *fmt, ...)
length = PRINTF_LENGTH_LONG_LONG;
state = PRINTF_STATE_SPEC;
}
else
goto PRINTF_STATE_SPEC_;
else goto PRINTF_STATE_SPEC_;
break;
case PRINTF_STATE_SPEC:
PRINTF_STATE_SPEC_:
switch (*fmt)
{
case 'c':
putc((char)*argp);
case 'c': putc((char)*argp);
argp++;
break;
case 's':
if (length == PRINTF_LENGTH_LONG || length == PRINTF_LENGTH_LONG_LONG)
case 's': if (length == PRINTF_LENGTH_LONG || length == PRINTF_LENGTH_LONG_LONG)
{
puts_f(*(const char far**)argp);
argp += 2;
@ -112,43 +113,31 @@ void _cdecl printf(const char *fmt, ...)
}
break;
case '%':
putc('%');
case '%': putc('%');
break;
case 'd':
case 'i':
radix = 10;
sign = true;
case 'i': radix = 10; sign = true;
argp = printf_number(argp, length, sign, radix);
break;
case 'u':
radix = 10;
sign = false;
case 'u': radix = 10; sign = false;
argp = printf_number(argp, length, sign, radix);
break;
case 'X':
case 'x':
case 'p':
radix = 16;
sign = false;
case 'p': radix = 16; sign = false;
argp = printf_number(argp, length, sign, radix);
break;
case 'o':
radix = 8;
sign = false;
case 'o': radix = 8; sign = false;
argp = printf_number(argp, length, sign, radix);
break;
// ignore invalid spec
default:
break;
default: break;
}
// reset state
state = PRINTF_STATE_NORMAL;
length = PRINTF_LENGTH_DEFAULT;
radix = 10;
@ -169,7 +158,6 @@ int *printf_number(int *argp, int length, bool sign, int radix)
int number_sign = 1;
int pos = 0;
// process length
switch (length)
{
case PRINTF_LENGTH_SHORT_SHORT:
@ -229,19 +217,16 @@ int *printf_number(int *argp, int length, bool sign, int radix)
break;
}
// convert number to ASCII
do
{
uint32_t rem = number % radix;
number = number / radix;
uint32_t rem;
x86_div64_32(number, radix, &number, &rem);
buffer[pos++] = g_HexChars[rem];
} while (number > 0);
// add sign
if (sign && number_sign < 0)
buffer[pos++] = '-';
// print number in reverse order
while (--pos >= 0)
putc(buffer[pos]);

View File

@ -2,4 +2,5 @@
void putc(char c);
void puts(const char* str);
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
_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
#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_div64_32(uint64_t dividend, uint32_t divisor, uint64_t *quotientOut, uint64_t *remainderOut);