From e165207c4ae0d990ccc83ab94779cb4087697a8a Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Fri, 23 Jun 2000 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 2000-06-23 --- pc/cycintr.c | 82 ++++++++++++++++++++++++++++++++++++++ pc/dat.h | 13 ++++++ pc/fns.h | 4 +- pc/i8253.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 202 insertions(+), 7 deletions(-) create mode 100644 pc/cycintr.c diff --git a/pc/cycintr.c b/pc/cycintr.c new file mode 100644 index 0000000000000000000000000000000000000000..93a6ecedfac798147e0191fdd71149cbb229865d --- /dev/null +++ b/pc/cycintr.c @@ -0,0 +1,82 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + + +static struct +{ + Lock; + vlong when; /* next scheduled interrupt time */ + Cycintr *ci; +}cycintrs; + +static void +cycsched(void) +{ +} + +void +checkcycintr(Ureg *u, void*) +{ + Cycintr *ci; + + ilock(&cycintrs); + while(ci = cycintrs.ci){ + if(ci->when > fastticks(nil)) + break; + cycintrs.ci = ci->next; + iunlock(&cycintrs); + (*ci->f)(u, ci); + ilock(&cycintrs); + } + cycsched(); + iunlock(&cycintrs); +} + +void +cycintradd(Cycintr *nci) +{ + Cycintr *ci, **last; + + ilock(&cycintrs); + last = &cycintrs.ci; + while(ci = *last){ + if(ci == nci){ + *last = ci->next; + break; + } + last = &ci->next; + } + + last = &cycintrs.ci; + while(ci = *last){ + if(ci->when > nci->when) + break; + last = &ci->next; + } + nci->next = *last; + *last = nci; + if(nci->when < cycintrs.when) + cycsched(); + iunlock(&cycintrs); +} + +void +cycintrdel(Cycintr *dci) +{ + Cycintr *ci, **last; + + ilock(&cycintrs); + last = &cycintrs.ci; + while(ci = *last){ + if(ci == dci){ + *last = ci->next; + break; + } + last = &ci->next; + } + iunlock(&cycintrs); +} diff --git a/pc/dat.h b/pc/dat.h index 1cfc12ba3531be282a435b23c07d69b57c2425a9..3156d8821105ffa56494df71ab37025956b9d7cf 100644 --- a/pc/dat.h +++ b/pc/dat.h @@ -194,6 +194,19 @@ struct Mach int stack[1]; }; +typedef struct Cycintr Cycintr; + +/* + * fasttick timer interrupts + */ +struct Cycintr +{ + vlong when; /* fastticks when f should be called */ + void (*f)(Ureg*, Cycintr*); + void *a; + Cycintr *next; +}; + /* * Fake kmap */ diff --git a/pc/fns.h b/pc/fns.h index 4a5c6c3445973ba7b4dca13afc00fed74b9e2cd2..6044e71ecca52c1116b338e1dd374fbc367a1316 100644 --- a/pc/fns.h +++ b/pc/fns.h @@ -1,6 +1,8 @@ #include "../port/portfns.h" -void loopbackintr(Ureg*); +void checkcycintr(Ureg*, void*); +void cycintradd(Cycintr*); +void cycintrdel(Cycintr*); void aamloop(int); diff --git a/pc/i8253.c b/pc/i8253.c index 3e5fdd28d99f5e59522422e8fe5d6bff88aa7382..344f04c1d5f76bb73c81beca2bfca7041c6c129b 100644 --- a/pc/i8253.c +++ b/pc/i8253.c @@ -14,21 +14,49 @@ enum T1cntr= 0x41, /* ... */ T2cntr= 0x42, /* ... */ Tmode= 0x43, /* mode port (control word register) */ + T2ctl= 0x61, /* counter 2 control port */ /* commands */ Latch0= 0x00, /* latch counter 0's value */ Load0l= 0x10, /* load counter 0's lsb */ Load0m= 0x20, /* load counter 0's msb */ Load0= 0x30, /* load counter 0 with 2 bytes */ + Latch2= 0x80, /* latch counter 2's value */ + Load2l= 0x90, /* load counter 2's lsb */ + Load2m= 0xa0, /* load counter 2's msb */ + Load2= 0xb0, /* load counter 2 with 2 bytes */ + + /* 8254 read-back command: everything > pc-at has an 8254 */ + Rdback= 0xc0, /* readback counters & status */ + Rdnstat=0x10, /* don't read status */ + Rdncnt= 0x20, /* don't read counter value */ + Rd0cntr=0x02, /* read back for which counter */ + Rd1cntr=0x04, + Rd2cntr=0x08, /* modes */ + ModeMsk=0xe, Square= 0x6, /* periodic square wave */ - Trigger= 0x0, /* interrupt on terminal count */ + Trigger=0x0, /* interrupt on terminal count */ + Sstrobe=0x8, /* software triggered strobe */ + + /* counter 2 controls */ + C2gate= 0x1, + C2speak=0x2, + C2out= 0x10, Freq= 1193182, /* Real clock frequency */ + + FreqMul=16, /* extra accuracy in fastticks/Freq calculation; ok up to ~8ghz */ }; -static Lock i8253lock; +static struct +{ + Lock lock; + vlong when; /* next fastticks a clock interrupt should occur */ + long fastperiod; /* fastticks/hz */ + long fast2freq; /* fastticks*FreqMul/Freq */ +}i8253; void i8253init(int aalcycles, int havecycleclock) @@ -40,6 +68,8 @@ i8253init(int aalcycles, int havecycleclock) if(initialised == 0){ initialised = 1; ioalloc(T0cntr, 4, 0, "i8253"); + ioalloc(T2ctl, 1, 0, "i8253.cntr2ctl"); + /* * set clock for 1/HZ seconds */ @@ -126,25 +156,93 @@ i8253init(int aalcycles, int havecycleclock) m->cpumhz = (cpufreq + cpufreq/200)/1000000; m->cpuhz = cpufreq; } + +outb(Tmode, Load0|Trigger); +outb(T0cntr, (Freq/HZ)); /* low byte */ +outb(T0cntr, (Freq/HZ)>>8); /* high byte */ } +static vlong lastfast; + int -i8253readcnt(void) +i8253readcnt(int cntr) { - ilock(&i8253lock); - iunlock(&i8253lock); + int v; + + ilock(&i8253.lock); + if(cntr == 2){ + outb(Tmode, Rdback|Rd2cntr); + v = inb(T2cntr) << 16; + v |= inb(T2cntr); + v |= inb(T2cntr) << 8; + }else if(cntr == 0){ + outb(Tmode, Rdback|Rd0cntr); + v = inb(T0cntr) << 16; + v |= inb(T0cntr); + v |= inb(T0cntr) << 8; + }else if(cntr == 3){ + vlong nf = fastticks(nil); + long set; + + set = (long)(nf - lastfast) * 100 / (long)((vlong)m->cpuhz * 100 / Freq); + set = (Freq/HZ) - set; + set -= 3 - 1; /* outb, outb, wait - outb(mode) */ + outb(Tmode, Rdback|Rdnstat|Rd0cntr); + v = inb(T0cntr); + v |= inb(T0cntr) << 8; + v = set - v; + }else if(cntr == 4){ + vlong nf = fastticks(nil); + long set; + + set = (long)(nf - lastfast) * 16 / (long)((vlong)m->cpuhz * 16 / Freq); + set = (Freq/HZ) - set; + set -= 3 - 1; /* outb, outb, wait - outb(mode) */ + outb(Tmode, Rdback|Rdnstat|Rd0cntr); + v = inb(T0cntr); + v |= inb(T0cntr) << 8; + v = set - v; + }else{ + vlong nf = fastticks(nil); + long set; + + set = (nf - lastfast) * Freq / m->cpuhz; + set = (Freq/HZ) - set; + set -= 3 - 1; /* outb, outb, wait - outb(mode) */ + outb(Tmode, Rdback|Rdnstat|Rd0cntr); + v = inb(T0cntr); + v |= inb(T0cntr) << 8; + v = set - v; + } + iunlock(&i8253.lock); + return v; } static void clockintr0(Ureg* ureg, void *v) { - loopbackintr(ureg); + vlong now; + long set; + + now = fastticks(nil); + while(i8253.when < now) + i8253.when += i8253.fastperiod; + set = (long)(i8253.when - now) * FreqMul / i8253.fast2freq; + set -= 3; /* three cycles for the count to take effect: outb, outb, wait */ +lastfast = now; + outb(T0cntr, set); /* low byte */ + outb(T0cntr, set>>8); /* high byte */ + + checkcycintr(ureg, v); clockintr(ureg, v); } void i8253enable(void) { + i8253.when = fastticks(nil); + i8253.fastperiod = (m->cpuhz + HZ/2) / HZ; + i8253.fast2freq = (vlong)m->cpuhz * FreqMul / Freq; intrenable(IrqCLOCK, clockintr0, 0, BUSUNKNOWN, "clock"); }