Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[kernel] Rewrite printk for speed, add __divmod fast 32/16-bit divide #2008

Merged
merged 1 commit into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading