diff --git a/printf/compat.h b/printf/compat.h new file mode 100644 index 0000000..93e0a2f --- /dev/null +++ b/printf/compat.h @@ -0,0 +1,25 @@ +#pragma once + +#ifndef offsetof +#define offsetof(type, member) __builtin_offsetof (type, member) +#endif + +#ifndef bool +#define bool int +#endif + +#ifndef false +#define false 0 +#endif + +#ifndef true +#define true 1 +#endif + +#ifndef static_assert +#define static_assert(s) _Static_assert(s, ""); +#endif + +#ifndef nullptr +#define nullptr ((void *)0) +#endif diff --git a/printf/minmax.h b/printf/minmax.h new file mode 100644 index 0000000..df4c506 --- /dev/null +++ b/printf/minmax.h @@ -0,0 +1,4 @@ +#pragma once + +#define min(a, b) ( (a < b) ? a : b ) +#define max(a, b) ( (a > b) ? a : b ) diff --git a/printf/parse.c b/printf/parse.c new file mode 100644 index 0000000..46b9b9c --- /dev/null +++ b/printf/parse.c @@ -0,0 +1,70 @@ +#include + +#include "parse.h" + +int parse_base10_digit(char c) +{ + switch (c) { + case '0': return 0; + case '1': return 1; + case '2': return 2; + case '3': return 3; + case '4': return 4; + case '5': return 5; + case '6': return 6; + case '7': return 7; + case '8': return 8; + case '9': return 9; + default: return -1; + } +} + +const char * parse_base10(const char * s, int * n) +{ + *n = 0; + int sign = 1; + + if (*s == '-') { + sign = -1; + s++; + } + + while (true) { + int digit = parse_base10_digit(*s); + if (digit == -1) + break; + + *n *= 10; + *n += digit; + s++; + } + + *n *= sign; + + return s; +} + +const char * parse_base10_64(const char * s, int64_t * n) +{ + *n = 0; + int sign = 1; + + if (*s == '-') { + sign = -1; + s++; + } + + while (true) { + int digit = parse_base10_digit(*s); + if (digit == -1) + break; + + *n *= 10; + *n += digit; + s++; + } + + *n *= sign; + + return s; +} diff --git a/printf/parse.h b/printf/parse.h new file mode 100644 index 0000000..022b84c --- /dev/null +++ b/printf/parse.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include "compat.h" + +#ifdef __cplusplus +extern "C" { +#endif + +const char * parse_skip(const char * s, char c); +const char * parse_find(const char * s, char c); +const char * parse_find_first_right(const char * s, int length, char c); +int parse_base10_digit(char c); +const char * parse_base10(const char * s, int * n); +const char * parse_base10_64(const char * s, int64_t * n); +const char * parse_match(const char * s, const char * m); +int parse_stride(const char * s, int length); +int parse_height(const char * s, int length); + +#ifdef __cplusplus +} +#endif diff --git a/printf/printf.c b/printf/printf.c new file mode 100644 index 0000000..9341162 --- /dev/null +++ b/printf/printf.c @@ -0,0 +1,186 @@ +#include +#include + +#include "parse.h" +#include "unparse.h" +#include "printf.h" +//#include "sh7091_scif.h" + +enum format_type { + FORMAT_BASE10_UNSIGNED, + FORMAT_BASE10, + FORMAT_BASE10_64, + FORMAT_POINTER, + FORMAT_BASE16, + FORMAT_STRING, + FORMAT_CHAR, + FORMAT_PERCENT, +}; + +struct format { + enum format_type type; + int pad_length; + char fill_char; +}; + +static const char * parse_escape(const char * format, struct format * ft); + +static const char * parse_fill_pad(const char * format, struct format * ft) +{ + if (*format == 0) + return format; + if (*format >= '1' && *format <= '9') + ft->fill_char = ' '; + else + ft->fill_char = *format++; + format = parse_base10(format, &ft->pad_length); + return parse_escape(format, ft); +} + +static const char * parse_escape(const char * format, struct format * ft) +{ + switch (*format) { + case 0: + return format; + case 'u': + ft->type = FORMAT_BASE10_UNSIGNED; + return format + 1; + case 'd': + ft->type = FORMAT_BASE10; + return format + 1; + case 'l': + ft->type = FORMAT_BASE10_64; + return format + 1; + case 'p': + ft->type = FORMAT_POINTER; + return format + 1; + case 'x': + ft->type = FORMAT_BASE16; + return format + 1; + case 's': + ft->type = FORMAT_STRING; + return format + 1; + case 'c': + ft->type = FORMAT_CHAR; + return format + 1; + case '%': + ft->type = FORMAT_PERCENT; + return format + 1; + default: + return parse_fill_pad(format, ft); + } +} + +void print_string(const char * s, int length) +{ + for (int i = 0; i < length; i++) { + print_char(s[i]); + } +} + +void print_bytes(const uint8_t * s, int length) +{ + for (int i = 0; i < length; i++) { + print_char(s[i]); + } +} + +void print_chars(const uint16_t * s, int length) +{ + for (int i = 0; i < length; i++) { + print_char(s[i]); + } +} + +void print_cstring(const char * s) +{ + while (*s != 0) { + print_char(*s++); + } +} + +void _printf(const char * format, ...) +{ + va_list args; + va_start(args, format); + + while (true) { + if (*format == 0) + break; + + switch (*format) { + case '%': + { + struct format ft = {0}; + format = parse_escape(format + 1, &ft); + switch (ft.type) { + case FORMAT_BASE10_UNSIGNED: + { + uint32_t num = va_arg(args, uint32_t); + char s[10]; + int offset = unparse_base10_unsigned(s, num, ft.pad_length, ft.fill_char); + print_string(s, offset); + } + break; + case FORMAT_BASE10: + { + int32_t num = va_arg(args, int32_t); + char s[10]; + int offset = unparse_base10(s, num, ft.pad_length, ft.fill_char); + print_string(s, offset); + } + break; + case FORMAT_BASE10_64: + { + int64_t num = va_arg(args, int64_t); + char s[20]; + int offset = unparse_base10_64(s, num, ft.pad_length, ft.fill_char); + print_string(s, offset); + } + break; + case FORMAT_POINTER: + { + print_char('0'); + print_char('x'); + } + [[fallthrough]]; + case FORMAT_BASE16: + { + uint32_t num = va_arg(args, uint32_t); + char s[8]; + int offset = unparse_base16(s, num, ft.pad_length, ft.fill_char); + print_string(s, offset); + } + break; + case FORMAT_STRING: + { + const char * s = va_arg(args, const char *); + while (*s != 0) { + char c = *s++; + print_char(c); + } + } + break; + case FORMAT_CHAR: + { + const int c = va_arg(args, const int); + print_char((char)c); + } + break; + case FORMAT_PERCENT: + print_char('%'); + break; + } + } + break; + default: + { + char c = *format++; + print_char(c); + } + break; + } + } + + va_end(args); +} diff --git a/printf/printf.h b/printf/printf.h new file mode 100644 index 0000000..ad80505 --- /dev/null +++ b/printf/printf.h @@ -0,0 +1,47 @@ +#pragma once + +#if defined(__dreamcast__) +#include "sh7091/c_serial.h" +#else +#include +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +static inline void print_char(char c) +{ +#if defined(__dreamcast__) + sh7091_character(c); +#else + fputc(c, stderr); +#endif +} + +void print_string(const char * s, int length); +void print_bytes(const uint8_t * s, int length); +void print_chars(const uint16_t * s, int length); +void print_cstring(const char * s); + +void _printf(const char * format, ...); + +#define printf(...) _printf(__VA_ARGS__) +#define printc(c) print_char(c) +#define prints(s) print_cstring(s) + +#if defined(DEBUG_PRINT) +#define debugf(...) _printf(__VA_ARGS__) +#define debugc(c) print_char(c) +#define debugs(s) print_cstring(s) +#else +#define debugf(...) +#define debugc(c) +#define debugs(c) +#endif + +#ifdef __cplusplus +} +#endif diff --git a/printf/unparse.c b/printf/unparse.c new file mode 100644 index 0000000..820e18e --- /dev/null +++ b/printf/unparse.c @@ -0,0 +1,194 @@ +#include + +#include "minmax.h" +#include "unparse.h" + +int digits_base10(uint32_t n) +{ + if (n >= 1000000000ul) return 10; + if (n >= 100000000ul) return 9; + if (n >= 10000000ul) return 8; + if (n >= 1000000ul) return 7; + if (n >= 100000ul) return 6; + if (n >= 10000ul) return 5; + if (n >= 1000ul) return 4; + if (n >= 100ul) return 3; + if (n >= 10ul) return 2; + return 1; +} + +int unparse_base10_unsigned(char * s, uint32_t n, int len, char fill) +{ + int digits = 0; + digits += digits_base10(n); + len = max(digits, len); + int ret = len; + + while (len > digits) { + *s++ = fill; + --len; + } + + while (len > 0) { + const uint32_t digit = n % 10; + n = n / 10; + s[--len] = digit + 48; + } + + return ret; +} + +int unparse_base10(char * s, int32_t n, int len, char fill) +{ + bool negative = false; + int digits = 0; + if (n < 0) { + digits += 1; + n = -n; + negative = true; + } + + digits += digits_base10(n); + len = max(digits, len); + int ret = len; + + while (len > digits) { + *s++ = fill; + --len; + } + + if (negative) { + *s++ = '-'; + len--; + } + + while (len > 0) { + const uint32_t digit = n % 10; + n = n / 10; + s[--len] = digit + 48; + } + + return ret; +} + +int digits_base10_64(uint64_t n) +{ + if (n >= 10000000000000000000ull) return 20; + if (n >= 1000000000000000000ull) return 19; + if (n >= 100000000000000000ull) return 18; + if (n >= 10000000000000000ull) return 17; + if (n >= 1000000000000000ull) return 16; + if (n >= 100000000000000ull) return 15; + if (n >= 10000000000000ull) return 14; + if (n >= 1000000000000ull) return 13; + if (n >= 100000000000ull) return 12; + if (n >= 10000000000ull) return 11; + if (n >= 1000000000ull) return 10; + if (n >= 100000000ull) return 9; + if (n >= 10000000ull) return 8; + if (n >= 1000000ull) return 7; + if (n >= 100000ull) return 6; + if (n >= 10000ull) return 5; + if (n >= 1000ull) return 4; + if (n >= 100ull) return 3; + if (n >= 10ull) return 2; + return 1; +} + +int unparse_base10_64(char * s, int64_t n, int len, char fill) +{ + bool negative = false; + int digits = 0; + if (n < 0) { + digits += 1; + n = -n; + negative = true; + } + + digits += digits_base10_64(n); + len = max(digits, len); + int ret = len; + + while (len > digits) { + *s++ = fill; + --len; + } + + if (negative) { + *s++ = '-'; + len--; + } + + while (len > 0) { + const uint32_t digit = n % 10; + n = n / 10; + s[--len] = digit + 48; + } + + return ret; +} + +static int digits_base16(uint32_t n) +{ + if (n <= 0xf) return 1; + if (n <= 0xff) return 2; + if (n <= 0xfff) return 3; + if (n <= 0xffff) return 4; + if (n <= 0xfffff) return 5; + if (n <= 0xffffff) return 6; + if (n <= 0xfffffff) return 7; + return 8; +} + +int unparse_base16(char * s, uint32_t n, int len, char fill) +{ + int digits = digits_base16(n); + len = max(digits, len); + int ret = len; + + while (len > digits) { + *s++ = fill; + --len; + } + + while (len > 0) { + uint32_t nib = n & 0xf; + n = n >> 4; + if (nib > 9) { + nib += (97 - 10); + } else { + nib += (48 - 0); + } + + s[--len] = nib; + } + + return ret; +} + +#ifdef UNPARSE_TEST +#include + +int main() +{ + char s[1024]; + + { + int n = 124; + + int offset = unparse_base10(s, n, 6, ' '); + s[offset] = 0; + + printf("`%s`\n", s); + } + + { + int n = 0x5678; + + int offset = unparse_base16(s, n, 7, '0'); + s[offset] = 0; + + printf("`%s`\n", s); + } +} +#endif diff --git a/printf/unparse.h b/printf/unparse.h new file mode 100644 index 0000000..7232354 --- /dev/null +++ b/printf/unparse.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include "compat.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int unparse_base10_unsigned(char * s, uint32_t n, int len, char fill); +int unparse_base10(char * s, int32_t n, int len, char fill); +int unparse_base10_64(char * s, int64_t n, int len, char fill); +int unparse_base16(char * s, uint32_t n, int len, char fill); + +int digits_base_64(uint64_t n); +int digits_base10_64(uint64_t n); + +#ifdef __cplusplus +} +#endif diff --git a/sh7091/c_serial.cpp b/sh7091/c_serial.cpp new file mode 100644 index 0000000..d832594 --- /dev/null +++ b/sh7091/c_serial.cpp @@ -0,0 +1,15 @@ +#include "sh7091.hpp" +#include "sh7091_bits.hpp" + +#include "c_serial.h" + +void sh7091_character(const char c) +{ + using namespace scif; + // wait for transmit fifo to become partially empty + while ((sh7091.SCIF.SCFSR2 & scfsr2::tdfe::bit_mask) == 0); + + sh7091.SCIF.SCFSR2 &= ~scfsr2::tdfe::bit_mask; + + sh7091.SCIF.SCFTDR2 = static_cast(c); +} diff --git a/sh7091/c_serial.h b/sh7091/c_serial.h new file mode 100644 index 0000000..733d618 --- /dev/null +++ b/sh7091/c_serial.h @@ -0,0 +1,11 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +void sh7091_character(const char c); + +#ifdef __cplusplus +} +#endif