diff --git a/elks/arch/i86/lib/Makefile b/elks/arch/i86/lib/Makefile index dfc45707a..b04690773 100644 --- a/elks/arch/i86/lib/Makefile +++ b/elks/arch/i86/lib/Makefile @@ -37,6 +37,7 @@ SRCS1 = \ peekpoke.S \ string.S \ printreg.S \ + divmod.S \ # end of list ifeq ($(CONFIG_ARCH_PC98), y) diff --git a/elks/arch/i86/lib/divmod.S b/elks/arch/i86/lib/divmod.S new file mode 100644 index 000000000..578ec9028 --- /dev/null +++ b/elks/arch/i86/lib/divmod.S @@ -0,0 +1,47 @@ +// Fast 32-bit combined divide and modulo routine +// +// unsigned long __divmod(unsigned long val, unsigned int *baserem) +// Unsigned divide 32-bits by 16-bits +// Store denominator in *baserem before calling +// Returns 32-bit quotient in DX:AX and remainder in *baserem +// +// Designed for a fast replacement of the following code which calls __udivsi3/__umodsi3: +// unsigned int rem, base; +// rem = val % base; +// val = val / base; +// New code: +// rem = base; +// val = __divmod(val, &rem); +// +// inspired by OpenWatcom ltoa.c __uldiv routine +// 13 Sep 2024 Greg Haerr + +#define NUMLO 2 +#define NUMHI 4 +#define ADDR 6 + + .arch i8086, nojumps + .code16 + .text + + .global __divmod +__divmod: + mov %sp,%bx + mov NUMLO(%bx),%ax + mov NUMHI(%bx),%dx + mov ADDR(%bx),%bx + +// divides DX:AX / [BX] +// returns DX:AX with remainder in [BX] + + xor %cx,%cx // temp CX = 0 + cmp (%bx),%dx // is upper 16 bits numerator less than denominator + jb 1f // yes - only one DIV needed + xchg %dx,%ax // AX = upper numerator, DX = lower numerator + xchg %dx,%cx // DX = 0, CX = lower numerator + divw (%bx) // AX = upper numerator / base, DX = remainder + xchg %cx,%ax // AX = lower numerator, CX = high quotient +1: divw (%bx) // AX = lower numerator / base, DX = remainder + mov %dx,(%bx) // store remainder + mov %cx,%dx // DX = high quotient, AX = low quotient + ret diff --git a/elks/include/arch/divmod.h b/elks/include/arch/divmod.h new file mode 100644 index 000000000..0cf88dd53 --- /dev/null +++ b/elks/include/arch/divmod.h @@ -0,0 +1,6 @@ +#ifndef __ARCH_8086_DIVMOD_H +#define __ARCH_8086_DIVMOD_H + +unsigned long __divmod(unsigned long val, unsigned int *baserem); + +#endif diff --git a/elks/init/main.c b/elks/init/main.c index 2d3b45071..d90463f90 100644 --- a/elks/init/main.c +++ b/elks/init/main.c @@ -114,6 +114,25 @@ void start_kernel(void) kfork_proc(init_task); wake_up_process(&task[1]); +#if TIMER_TEST + /* printk rewrite debug statements */ + printk("#04X: '%#04X'\n", 0x2ab); + printk("04X: '%04X'\n", 0x2ab); + printk("04x: '%04x'\n", 0x2ab); + printk(" 4x: '%4x'\n", 0x2ab); + printk("04d: '%04d'\n", 0x200); + printk(" 4d: '%4d'\n", 0x200); + printk("05d: '%05d'\n", -200); + printk(" 5d: '%5d'\n", -200); + printk(" ld: '%ld'\n", -123456789L); + printk(" lx: '%lx'\n", 0x87654321L); + printk(" lo: '%lo'\n", 0xFFFFFFFFL); + printk(" s: '%s'\n", "thisisatest"); + printk(" 6s: '%6s'\n", "thisisatest"); + printk("20s: '%20s'\n", "thisisatest"); + test_ptime_print(); +#endif + /* * We are now the idle task. We won't run unless no other process can run. * The idle task always runs with _gint_count == 1 (switched from user mode syscall) diff --git a/elks/kernel/printk.c b/elks/kernel/printk.c index b8ec42f6d..6c32419d8 100644 --- a/elks/kernel/printk.c +++ b/elks/kernel/printk.c @@ -26,6 +26,7 @@ * Alan Cox. * * MTK: Sep 97 - Misc hacks to shrink generated code + * GRH: Sep 24 - Rewritten for speed */ #include @@ -40,6 +41,7 @@ #include #include #include +#include #include #define CONFIG_PREC_TIMER 1 /* =1 to include %k precision timer printk format */ @@ -56,7 +58,7 @@ static void (*kputc)(dev_t, int) = 0; void set_console(dev_t dev) { - register struct tty *ttyp; + struct tty *ttyp; if (dev == 0) dev = DEVCONSOLE; @@ -86,29 +88,18 @@ static void kputs(const char *buf) * Output a number */ -static char hex_string[] = "0123456789ABCDEF 0123456789abcdef "; - static void numout(unsigned long v, int width, unsigned int base, int type, int Zero, int alt) { - unsigned long dvr; - int c, vch, i; - int useSign, Lower, Decimal; - - i = 10; - dvr = 1000000000L; - if (base > 10) { - i = 8; - dvr = 0x10000000L; - } - if (base < 10) { - i = 11; - dvr = 0x40000000L; - } - - Decimal = 0; + int n, i; + unsigned int c; + char *p; + int Sign, Suffix, Decimal; + char buf[12]; /* small stack: good up to max long octal v */ + + Decimal = -1; + Sign = Suffix = 0; #if CONFIG_PREC_TIMER - int Msecs = 0; /* display 1/1193182s get_time*() pticks in range 0.838usec through 42.85sec */ if (type == 'k') { /* format works w/limited ranges only */ Decimal = 3; @@ -121,59 +112,57 @@ static void numout(unsigned long v, int width, unsigned int base, int type, v = v * 838UL; /* convert to nanosecs w/o 32-bit overflow */ if (v > 1000000000UL) { /* display x.xxx secs */ v /= 1000000UL; /* divide using _udivsi3 for speed */ + Suffix = 's'; } else if (v > 1000000UL) { v /= 1000UL; /* display xx.xxx msecs */ - Msecs = 1; + Suffix = ('s' << 8) | 'm'; } else { - Msecs = 2; /* display xx.xxx usecs */ + Suffix = ('s' << 8) | 'u'; /* display xx.xxx usecs */ } } #endif - useSign = (type == 'd'); - if (useSign && ((long)v < 0L)) - v = (-(long)v); - else - useSign = 0; + if (type == 'd' && (long)v < 0L) { + v = -(long)v; + Sign = 1; + } - Lower = (type != 'X'); - if (Lower) - Lower = 17; - vch = 0; if (alt && base == 16) { kputchar('0'); kputchar('x'); } + + p = buf + sizeof(buf) - 1; + *p = '\0'; do { - c = (int)(v / dvr); - v %= dvr; - dvr /= base; - if (c || (i <= width) || (i < 2)) { - if (i > width) - width = i; - if (!Zero && !c && (i > 1)) - c = 16; - else { - Zero = 1; - if (useSign) { - useSign = 0; - vch = '-'; - } - } - if (vch) - kputchar(vch); - vch = *(hex_string + Lower + c); - if (type == 'k' && i == Decimal) kputchar('.'); - } - } while (--i); - kputchar(vch); -#if CONFIG_PREC_TIMER - if (type == 'k') { - if (Msecs) - kputchar(Msecs == 1? 'm': 'u'); - kputchar('s'); + c = base; + v = __divmod(v, &c); /* remainder returned in c */ + if (c > 9) + *--p = ((type == 'X')? 'A': 'a') - 10 + c; + else + *--p = '0' + c; + } while (v != 0); + i = n = buf + sizeof(buf) - 1 - p + Sign; /* string length */ + if (n > width) /* expand field width */ + width = n; + if (Zero && Sign) { + kputchar('-'); + Sign = 0; + } + while (n++ < width) + kputchar(Zero? '0': ' '); + if (Sign) + kputchar('-'); + while (*p) { + if (i == Decimal) + kputchar('.'); + i--; + kputchar(*p++); + } + while (Suffix) { + kputchar(Suffix & 255); + Suffix >>= 8; } -#endif } static void vprintk(const char *fmt, va_list p)