Skip to content

Commit

Permalink
[kernel] Rewrite printk for speed, add __divmod fast 32/16-bit divide
Browse files Browse the repository at this point in the history
  • Loading branch information
ghaerr committed Sep 13, 2024
1 parent 949f740 commit 588fd99
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 59 deletions.
1 change: 1 addition & 0 deletions elks/arch/i86/lib/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ SRCS1 = \
peekpoke.S \
string.S \
printreg.S \
divmod.S \
# end of list

ifeq ($(CONFIG_ARCH_PC98), y)
Expand Down
47 changes: 47 additions & 0 deletions elks/arch/i86/lib/divmod.S
Original file line number Diff line number Diff line change
@@ -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
6 changes: 6 additions & 0 deletions elks/include/arch/divmod.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef __ARCH_8086_DIVMOD_H
#define __ARCH_8086_DIVMOD_H

unsigned long __divmod(unsigned long val, unsigned int *baserem);

#endif
19 changes: 19 additions & 0 deletions elks/init/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
107 changes: 48 additions & 59 deletions elks/kernel/printk.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
* Alan Cox.
*
* MTK: Sep 97 - Misc hacks to shrink generated code
* GRH: Sep 24 - Rewritten for speed
*/

#include <linuxmt/config.h>
Expand All @@ -40,6 +41,7 @@
#include <linuxmt/prectimer.h>
#include <arch/segment.h>
#include <arch/irq.h>
#include <arch/divmod.h>
#include <stdarg.h>

#define CONFIG_PREC_TIMER 1 /* =1 to include %k precision timer printk format */
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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)
Expand Down

0 comments on commit 588fd99

Please sign in to comment.