~kris/9p

9hist

ee8c5059d684c36222065cd21b857fab9843117b — David du Colombier 26 years ago d8cb5b4
Plan 9 from Bell Labs 1999-10-07
7 files changed, 440 insertions(+), 223 deletions(-)

M pc/devusb.c
M pc/io.h
A pc/vgat2r4.c
M port/segment.c
M port/thwack.c
M port/thwack.h
M port/unthwack.c
M pc/devusb.c => pc/devusb.c +18 -56
@@ 369,9 369,9 @@ dumptd(TD *t, int follow)
		if(t->status & LowSpeed)
			*s++ = 'L';
		*s = 0;
		print("td %8.8lux: l=%8.8lux s=%8.8lux d=%8.8lux b=%8.8lux %8.8lux f=%8.8lux\n",
		XPRINT("td %8.8lux: l=%8.8lux s=%8.8lux d=%8.8lux b=%8.8lux %8.8lux f=%8.8lux\n",
			t, t->link, t->status, t->dev, t->buffer, t->bp?(ulong)t->bp->rp:0, t->flags);
		print("\ts=%s,ep=%ld,d=%ld,D=%ld\n", buf, (t->dev>>15)&0xF, (t->dev>>8)&0xFF, (t->dev>>19)&1);
		XPRINT("\ts=%s,ep=%ld,d=%ld,D=%ld\n", buf, (t->dev>>15)&0xF, (t->dev>>8)&0xFF, (t->dev>>19)&1);
		if(t->bp)
			dumpdata(t->bp, n);
		if(!follow || t->link & Terminate || t->link & IsQH)


@@ 401,44 401,6 @@ alloctde(Endpt *e, int pid, int n)
	return t;
}

static TD *
alloctdring(int nbuf, Endpt *e, int pid, int maxn)
{
	TD *t, *lt, *ft;
	int id, i;
	ulong status, dev;

	if(!e->iso)
		nbuf = (nbuf+1)&~1;
	id = (e->x<<7)|(e->dev->x&0x7F);
	dev = ((maxn-1)<<21) | ((id&0x7FF)<<8) | pid;
	status = 0;
	if(e->dev->ls)
		status |= LowSpeed;
	ft = lt = nil;
	for(i=0; i<nbuf; i++){
		t = alloctd(&ubus);
		t->ep = e;
		t->status = status;
		t->dev =  dev;
		if(!e->iso)
			dev ^= IsDATA1;
		if(pid == TokIN){
			t->bp = allocb(maxn);
			t->buffer = PADDR(t->bp->wp);
		}
		if(ft != nil){
			lt->next = t;
			lt->link = PADDR(t);
		}else
			ft = t;
		lt = t;
	}
	if(lt != nil)
		lt->link = PADDR(ft);	/* loop to form ring */
	return ft;
}

static QH *
allocqh(Ctlr *ub)
{


@@ 475,13 437,13 @@ dumpqh(QH *q)

	q0 = q;
	for(i = 0; q != nil && i < 10; i++){
		pprint("qh %8.8lux: %8.8lux %8.8lux\n", q, q->head, q->entries);
		XPRINT("qh %8.8lux: %8.8lux %8.8lux\n", q, q->head, q->entries);
		if((q->entries & Terminate) == 0)
			dumptd(TFOL(q->entries), 1);
		if(q->head & Terminate)
			break;
		if((q->head & IsQH) == 0){
			pprint("head:");
			XPRINT("head:");
			dumptd(TFOL(q->head), 1);
			break;
		}


@@ 525,7 487,7 @@ cleantd(TD *t, int discard)
	err = t->status & (AnyError&~NAKed);
	/* TO DO: on t->status&AnyError, q->entries will not have advanced */
	if (err)
		print("cleanTD: Error %8.8lux %8.8lux %8.8lux %8.8lux\n", t->link, t->status, t->dev, t->buffer);
		XPRINT("cleanTD: Error %8.8lux %8.8lux %8.8lux %8.8lux\n", t->link, t->status, t->dev, t->buffer);
	switch(t->dev&0xFF){
	case TokIN:
		if(discard || (t->flags & CancelTD) || t->ep == nil || t->ep->x!=0&&err){


@@ 624,7 586,7 @@ canceltds(Ctlr *ub, QH *q, Endpt *e)
			if(t->ep == e)
				t->flags |= CancelTD;
		iunlock(ub);
		pprint("cancel:\n");
		XPRINT("cancel:\n");
		dumpqh(q);
	}
}


@@ 805,7 767,7 @@ mkqhtree(ulong *frame, int framesize, int maxms)
				o |= 1;
		}
		if(leaf0+o >= n){
			pprint("leaf0=%d o=%d i=%d n=%d\n", leaf0, o, i, n);
			XPRINT("leaf0=%d o=%d i=%d n=%d\n", leaf0, o, i, n);
			break;
		}
		frame[i] = PADDR(&tree[leaf0+o]) | IsQH;


@@ 828,14 790,14 @@ dumpframe(int f, int t)
	if(t < 0)
		t = 32;
	for(i=f; i<t; i++){
		pprint("F%.2d %8.8lux %8.8lux\n", i, frame[i], QFOL(frame[i])->head);
		XPRINT("F%.2d %8.8lux %8.8lux\n", i, frame[i], QFOL(frame[i])->head);
		for(p=frame[i]; (p & IsQH) && (p &Terminate) == 0; p = q->head){
			q = QFOL(p);
			if(!(q >= tree && q < &tree[n])){
				pprint("Q: p=%8.8lux out of range\n", p);
				XPRINT("Q: p=%8.8lux out of range\n", p);
				break;
			}
			pprint("  -> %8.8lux h=%8.8lux e=%8.8lux\n", p, q->head, q->entries);
			XPRINT("  -> %8.8lux h=%8.8lux e=%8.8lux\n", p, q->head, q->entries);
		}
	}
}


@@ 1104,9 1066,9 @@ interrupt(Ureg*, void *a)
	ub = a;
	s = IN(Status);
	if (s & 0x1a) {
		print("usbint: #%x f%d\n", s, IN(Frnum));
		print("cmd #%x sofmod #%x\n", IN(Cmd), inb(ub->io+SOFMod));
		print("sc0 #%x sc1 #%x\n", IN(Portsc0), IN(Portsc1));
		XPRINT("usbint: #%x f%d\n", s, IN(Frnum));
		XPRINT("cmd #%x sofmod #%x\n", IN(Cmd), inb(ub->io+SOFMod));
		XPRINT("sc0 #%x sc1 #%x\n", IN(Portsc0), IN(Portsc1));
	}
	OUT(Status, s);



@@ 1570,7 1532,7 @@ readusb(Endpt *e, void *a, long n)
	p = a;
	do {
		if(e->eof) {
			pprint("e->eof\n");
			XPRINT("e->eof\n");
			break;
		}
		if(e->err)


@@ 1583,7 1545,7 @@ readusb(Endpt *e, void *a, long n)
			error(e->err);
		b = qget(e->rq);	/* TO DO */
		if(b == nil) {
			pprint("b == nil\n");
			XPRINT("b == nil\n");
			break;
		}
		if(waserror()){


@@ 1846,7 1808,7 @@ usbwrite(Chan *c, void *a, long n, vlong)
			/* ep n maxpkt mode poll nbuf */
			i = strtoul(fields[1], nil, 0);
			if(i < 0 || i >= nelem(d->ep)) {
				pprint("field 1: 0 <= %d < %d\n", i, nelem(d->ep));
				XPRINT("field 1: 0 <= %d < %d\n", i, nelem(d->ep));
				error(Ebadarg);
			}
			if(d->ep[i] != nil)


@@ 1869,7 1831,7 @@ usbwrite(Chan *c, void *a, long n, vlong)
				if(i > 0 && i <= 1000)
					e->pollms = i;
				else {
					pprint("field 4: 0 <= %d <= 1000\n", i);
					XPRINT("field 4: 0 <= %d <= 1000\n", i);
					error(Ebadarg);
				}
			}


@@ 1878,7 1840,7 @@ usbwrite(Chan *c, void *a, long n, vlong)
				e->nbuf = i;
			poperror();
		}else {
			pprint("command %s, fields %d\n", fields[0], nf);
			XPRINT("command %s, fields %d\n", fields[0], nf);
			error(Ebadarg);
		}
		return n;

M pc/io.h => pc/io.h +1 -0
@@ 5,6 5,7 @@
enum {
	VectorNMI	= 2,		/* non-maskable interrupt */
	VectorBPT	= 3,		/* breakpoint */
	VectorUD	= 6,		/* invalid opcode exception */
	VectorCNA	= 7,		/* coprocessor not available */
	VectorCSO	= 9,		/* coprocessor segment overrun */
	VectorPF	= 14,		/* page fault */

A pc/vgat2r4.c => pc/vgat2r4.c +329 -0
@@ 0,0 1,329 @@
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "../port/error.h"

#define	Image	IMAGE
#include <draw.h>
#include <memdraw.h>
#include <cursor.h>
#include "screen.h"

/*
 * #9 Ticket to Ride IV.
 */
enum {
	IndexLo		= 4,
	IndexHi		= 5,
	Data		= 6,
	IndexCtl	= 7,
};

enum {						/* index registers */
	CursorCtl	= 0x30,
	CursorXLo	= 0x31,
	CursorXHi	= 0x32,
	CursorYLo	= 0x33,
	CursorYHi	= 0x34,
	CursorHotX	= 0x35,
	CursorHotY	= 0x36,

	CursorR1	= 0x40,
	CursorG1	= 0x41,
	CursorB1	= 0x42,
	CursorR2	= 0x43,
	CursorG2	= 0x44,
	CursorB2	= 0x45,
	CursorR3	= 0x46,
	CursorG3	= 0x47,
	CursorB3	= 0x48,

	CursorArray	= 0x100,
};

static ulong
t2r4linear(VGAscr* scr, int* size, int* align)
{
	ulong aperture, oaperture;
	int oapsize, wasupamem;
	Pcidev *p;

	oaperture = scr->aperture;
	oapsize = scr->apsize;
	wasupamem = scr->isupamem;

	aperture = 0;
	if(p = pcimatch(nil, 0x105D, 0)){
		switch(p->did){
		case 0x5348:
			aperture = p->mem[0].bar & ~0x0F;
			*size = p->mem[0].size;
			break;
		default:
			break;
		}
	}

	if(wasupamem){
		if(oaperture == aperture)
			return oaperture;
		upafree(oaperture, oapsize);
	}
	scr->isupamem = 0;

	aperture = upamalloc(aperture, *size, *align);
	if(aperture == 0){
		if(wasupamem && upamalloc(oaperture, oapsize, 0)){
			aperture = oaperture;
			scr->isupamem = 1;
		}
		else
			scr->isupamem = 0;
	}
	else
		scr->isupamem = 1;

	return aperture;
}

static void
t2r4enable(VGAscr* scr)
{
	Pcidev *p;
	Physseg seg;
	int size, align;
	ulong aperture;

	/*
	 * Only once, can't be disabled for now.
	 * scr->io holds the virtual address of
	 * the MMIO registers.
	 */
	if(scr->io)
		return;
	if(p = pcimatch(nil, 0x105D, 0)){
		switch(p->did){
		case 0x5348:
			break;
		default:
			return;
		}
	}
	else
		return;
	scr->io = upamalloc(p->mem[4].bar & ~0x0F, p->mem[4].size, 0);
	if(scr->io == 0)
		return;

	memset(&seg, 0, sizeof(seg));
	seg.attr = SG_PHYSICAL;
	seg.name = smalloc(NAMELEN);
	snprint(seg.name, NAMELEN, "t2r4mmio");
	seg.pa = scr->io;
	seg.size = p->mem[4].size;
	addphysseg(&seg);

	scr->io = (ulong)KADDR(scr->io);

	size = p->mem[0].size;
	align = 0;
	aperture = t2r4linear(scr, &size, &align);
	if(aperture){
		scr->aperture = aperture;
		scr->apsize = size;
		memset(&seg, 0, sizeof(seg));
		seg.attr = SG_PHYSICAL;
		seg.name = smalloc(NAMELEN);
		snprint(seg.name, NAMELEN, "t2r4screen");
		seg.pa = aperture;
		seg.size = size;
		addphysseg(&seg);
	}
}

static void
t2r4xo(VGAscr* scr, int index, uchar data)
{
	ulong *mmio;

	mmio = (ulong*)scr->io;
	mmio[IndexLo] = index & 0xFF;
	mmio[IndexHi] = (index>>8) & 0xFF;

	mmio[Data] = data;
}

static void
t2r4curdisable(VGAscr* scr)
{
	if(scr->io == 0)
		return;
	t2r4xo(scr, CursorCtl, 0x00);
}

static void
t2r4curload(VGAscr* scr, Cursor* curs)
{
	int x, y;
	ulong *mmio;
	uchar p, p0, p1;

	if(scr->io == 0)
		return;
	mmio = (ulong*)scr->io;

	/*
	 * Make sure cursor is off by initialising the cursor
	 * control to defaults.
	 */
	t2r4xo(scr, CursorCtl, 0x00);

	/*
	 * Set auto-increment mode for index-register addressing
	 * and initialise the cursor array index.
	 */
	mmio[IndexCtl] = 0x01;
	mmio[IndexLo] = CursorArray & 0xFF;
	mmio[IndexHi] = (CursorArray>>8) & 0xFF;

	/*
	 * Initialise the 32x32 cursor RAM array. There are 2 planes,
	 * p0 and p1. Data is written 4 pixels per byte, with p1 the
	 * MS bit of each pixel.
	 * The cursor is set in X-Windows mode which gives the following
	 * truth table:
	 *	p1 p0	colour
	 *	 0  0	underlying pixel colour
	 *	 0  1	underlying pixel colour
	 *	 1  0	cursor colour 1
	 *	 1  1	cursor colour 2
	 * Put the cursor into the top-left of the 32x32 array.
	 */
	for(y = 0; y < 32; y++){
		for(x = 0; x < 32/8; x++){
			if(x < 16/8 && y < 16){
				p0 = curs->clr[x+y*2];
				p1 = curs->set[x+y*2];

				p = 0x00;
				if(p1 & 0x80)
					p |= 0xC0;
				else if(p0 & 0x80)
					p |= 0x80;
				if(p1 & 0x40)
					p |= 0x30;
				else if(p0 & 0x40)
					p |= 0x20;
				if(p1 & 0x20)
					p |= 0x0C;
				else if(p0 & 0x20)
					p |= 0x08;
				if(p1 & 0x10)
					p |= 0x03;
				else if(p0 & 0x10)
					p |= 0x02;
				mmio[Data] = p;

				p = 0x00;
				if(p1 & 0x08)
					p |= 0xC0;
				else if(p0 & 0x08)
					p |= 0x80;
				if(p1 & 0x04)
					p |= 0x30;
				else if(p0 & 0x04)
					p |= 0x20;
				if(p1 & 0x02)
					p |= 0x0C;
				else if(p0 & 0x02)
					p |= 0x08;
				if(p1 & 0x01)
					p |= 0x03;
				else if(p0 & 0x01)
					p |= 0x02;
				mmio[Data] = p;
			}
			else{
				mmio[Data] = 0x00;
				mmio[Data] = 0x00;
			}
		}
	}

	/*
	 * Initialise the cursor hotpoint,
	 * enable the cursor and restore state.
	 */
	t2r4xo(scr, CursorHotX, -curs->offset.x);
	t2r4xo(scr, CursorHotY, -curs->offset.y);

	t2r4xo(scr, CursorCtl, 0x23);
}

static int
t2r4curmove(VGAscr* scr, Point p)
{
	if(scr->io == 0)
		return 1;

	t2r4xo(scr, CursorXLo, p.x & 0xFF);
	t2r4xo(scr, CursorXHi, (p.x>>8) & 0x0F);
	t2r4xo(scr, CursorYLo, p.y & 0xFF);
	t2r4xo(scr, CursorYHi, (p.y>>8) & 0x0F);

	return 0;
}

static void
t2r4curenable(VGAscr* scr)
{
	t2r4enable(scr);
	if(scr->io == 0)
		return;

	/*
	 * Make sure cursor is off by initialising the cursor
	 * control to defaults.
	 */
	t2r4xo(scr, CursorCtl, 0x00);

	/*
	 * Cursor colour 1 (white),
	 * cursor colour 2 (black).
	 */
	t2r4xo(scr, CursorR1, Pwhite);
	t2r4xo(scr, CursorG1, Pwhite);
	t2r4xo(scr, CursorB1, Pwhite);

	t2r4xo(scr, CursorR2, Pblack);
	t2r4xo(scr, CursorG2, Pblack);
	t2r4xo(scr, CursorB2, Pblack);

	/*
	 * Load, locate and enable the cursor, 32x32, mode 2.
	 */
	t2r4curload(scr, &arrow);
	t2r4curmove(scr, ZP);
	t2r4xo(scr, CursorCtl, 0x23);
}

VGAdev vgat2r4dev = {
	"t2r4",

	t2r4enable,
	nil,
	nil,
	t2r4linear,
};

VGAcur vgat2r4cur = {
	"t2r4hwgc",

	t2r4curenable,
	t2r4curdisable,
	t2r4curload,
	t2r4curmove,
};

M port/segment.c => port/segment.c +2 -0
@@ 612,6 612,8 @@ segattach(Proc *p, ulong attr, char *name, ulong va, ulong len)
		error(Enovmem);

	len = PGROUND(len);
	if(len == 0)
		error(Ebadarg);

	/*
	 * Find a hole in the address space.

M port/thwack.c => port/thwack.c +21 -60
@@ 1,5 1,5 @@
#include "u.h"
#include "../port/lib.h"
#include "lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"


@@ 13,16 13,17 @@ struct Huff
	ulong	encode;				/* the code */
};

static	Huff	lentab[MaxLen] =
static	Huff	lentab[MaxFastLen] =
{
	{1,	0x0},		/* 0 */
	{2,	0x2},		/* 10 */
	{4,	0xc},		/* 1100 */
	{4,	0xd},		/* 1101 */
	{5,	0x1e},		/* 11110 */
	{6,	0x3e},		/* 111110 */
	{6,	0x3f},		/* 111111 */
	{4,	0xe},		/* 1110 */
	{5,	0x1c},		/* 11100 */
	{6,	0x3a},		/* 111010 */
	{6,	0x3b},		/* 111011 */
	{7,	0x78},		/* 1111000 */
	{7,	0x79},		/* 1111001 */
};

static	void	bitput(Thwack *tw, int c, int n);


@@ 139,9 140,9 @@ thwack(Thwack *tw, uchar *dst, uchar *src, int n, ulong seq)
{
	ThwBlock *eblocks, *b, blocks[CompBlocks];
	uchar *s, *ss, *sss, *esrc, *half;
	ulong cont, cseq, bseq, cmask;
	ulong cont, cseq, bseq, cmask, code;
	int now, toff;
	int h, m, slot, bits, totmatched;
	int h, m, slot, bits, use, totmatched;

	if(n > ThwMaxBlock || n < MinMatch || waserror())
		return -1;


@@ 227,11 228,20 @@ thwack(Thwack *tw, uchar *dst, uchar *src, int n, ulong seq)
			bitput(tw, toff & ((1 << bits) - 1), bits);

			m -= MinMatch;
			if(m < MaxLen-1){
			if(m < MaxFastLen){
				bitput(tw, lentab[m].encode, lentab[m].bits);
			}else{
				bitput(tw, lentab[MaxLen-1].encode, lentab[MaxLen-1].bits);
				iomegaput(tw, m - (MaxLen - 2));
				code = BigLenCode;
				bits = BigLenBits;
				use = BigLenBase;
				m -= MaxFastLen;
				while(m >= use){
					m -= use;
					code = (code + use) << 1;
					use <<= bits & 1;
					bits++;
				}
				bitput(tw, (code + m), bits);
			}
		}
		blocks->maxoff += ss - s;


@@ 274,52 284,3 @@ bitput(Thwack *tw, int c, int n)
		*tw->dst++ = tw->bits >> (tw->nbits - 8);
	}
}

/*
 * elias's omega code, modified
 * for at least 3 bit transmission
 */
static Huff omegatab[16] = 
{
	{0,	0},		/* 1 */
	{0,	0},
	{0,	0},
	{0,	0},
	{3,	0x4},		/* 5 */
	{3,	0x5},
	{3,	0x6},
	{3,	0x7},
	{7,	0x48},
	{7,	0x49},		/* 10 */
	{7,	0x4a},
	{7,	0x4b},
	{7,	0x4c},
	{7,	0x4d},
	{7,	0x4e},		/* 15 */
	{7,	0x4f},
};

static int
iomegaput(Thwack *tw, ulong v)
{
	int b, bb;

	v--;
	if(v < 4){
		bitput(tw, v, 3);
		return 3;
	}
	if(v < 16){
		b = omegatab[v].bits + 1;
		bitput(tw, omegatab[v].encode << 1, b);
		return b;
	}

	for(bb = 5; v >= (1 << bb); bb++)
		;
	if(bb >= 16)
		error("thwack omegaput");
	b = bb + omegatab[bb].bits + 1;
	bitput(tw, (omegatab[bb].encode << (bb + 1)) | (v << 1), b);
	return b;
}

M port/thwack.h => port/thwack.h +7 -7
@@ 12,11 12,16 @@ enum
	HashSize	= 1<<HashLog,
	HashMask	= HashSize - 1,

	MaxLen		= 8,
	MaxFastLen	= 9,
	BigLenCode	= 0xf4,		/* minimum code for large lenth encoding */
	BigLenBase	= 4,		/* starting items to encode for big lens */
	BigLenBits	= 8,
	MaxOff		= 8,
	OffBase		= 6,

	MinDecode	= 9,		/* minimum bits to decode a match or lit */
	MaxOffDecode	= 4 + MaxOff + OffBase - 1,
	MaxLenDecode	= 16,

	EWinBlocks	= 32,		/* blocks held in encoder window */
	DWinBlocks	= 32,		/* blocks held in decoder window */


@@ 44,7 49,7 @@ struct Thwack
	uchar		*dst;		/* output buffer */
	uchar		*dmax;

	ulong		slot;		/* next block to use */
	int		slot;		/* next block to use */
	ThwBlock	blocks[EWinBlocks];
	ushort		hash[EWinBlocks][HashSize];
	uchar		data[EWinBlocks][ThwMaxBlock];


@@ 59,11 64,6 @@ struct UnthwBlock

struct Unthwack
{
	ulong		nbits;		/* input bit buffer */
	ulong		bits;
	uchar		*src;		/* input buffer */
	uchar		*smax;

	int		slot;		/* next block to use */
	UnthwBlock	blocks[DWinBlocks];
	uchar		data[DWinBlocks][ThwMaxBlock];

M port/unthwack.c => port/unthwack.c +62 -100
@@ 1,5 1,5 @@
#include "u.h"
#include "../port/lib.h"
#include "lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"


@@ 10,28 10,26 @@ typedef struct HuffDec		HuffDec;

struct HuffDec
{
	ulong	maxcode[MaxLen];
	ulong	last[MaxLen];
	ulong	decode[MaxLen];
	ulong	maxcode[MaxFastLen];
	ulong	last[MaxFastLen];
	ulong	decode[MaxFastLen];
};

static HuffDec lentab = 
{
/*	0	1	2	3	4	5	6	*/
	{0,	0,	0x2,	0,	0xe,	0x1e,	0x3f},
	{-1,	0+0,	0x2+1,	-1,	0xe+2,	0x1e+5,	0x3f+6},
/*	0	1	2	3	4	5	6	7	*/
	{0,	0,	0x2,	0,	0xd,	0x1c,	0x3b,	0x79},
	{-1,	0+0,	0x2+1,	-1,	0xd+2,	0x1c+4,	0x3b+5,	0x79+7},
	{
		0,
		1,
		7, 3, 2,
		3, 2,
		4,
		6, 5
		6, 5,
		8, 7,
	},
};

static ulong	bitget(Unthwack *ut, int nb);
static ulong	iomegaget(Unthwack *ut);

void
unthwackinit(Unthwack *ut)
{


@@ 42,23 40,17 @@ unthwackinit(Unthwack *ut)
		ut->blocks[i].data = ut->data[i];
}

/*
 * to speed up, inline bitget
 */
int
unthwack(Unthwack *ut, uchar *dst, int ndst, uchar *src, int nsrc, ulong seq)
{
	UnthwBlock blocks[CompBlocks], *b, *eblocks;
	uchar *s, *es, *d, *dmax;
	ulong cmask, cseq, bseq, utbits, utnbits;
	int off, len, bits, slot, tslot;
	uchar *s, *es, *d, *dmax, *smax;
	ulong cmask, cseq, bseq, utbits;
	int off, len, bits, slot, tslot, use, code, utnbits, overbits;

	if(nsrc < 4 || nsrc > ThwMaxBlock || waserror())
	if(nsrc < 4 || nsrc > ThwMaxBlock)
		return -1;

	ut->src = src + 2;
	ut->smax = src + nsrc;

	/*
	 * find the correct slot for this block,
	 * the oldest block around.  the encoder


@@ 112,23 104,30 @@ unthwack(Unthwack *ut, uchar *dst, int ndst, uchar *src, int nsrc, ulong seq)
	}
	eblocks = b;
	if(cseq != seq){
		print("blocks not in decompression window: cseq=%d seq=%d cmask=%ux nb=%d\n", cseq, seq, cmask, eblocks - blocks);
		error("unthwack bad window");
		print("blocks not in decompression window: cseq=%ld seq=%ld cmask=%lux nb=%ld\n", cseq, seq, cmask, eblocks - blocks);
		return -1;
	}

	smax = src + nsrc;
	src += 2;
	utnbits = 0;
	utbits = 0;
	while(ut->src < ut->smax || ut->nbits >= MinDecode){
		while(utnbits < 9){
			if(ut->src >= ut->smax)
				error("unthwack eof");
	overbits = 0;
	while(src < smax || utnbits - overbits >= MinDecode){
		while(utnbits < MaxOffDecode + BigLenBits){
			utbits <<= 8;
			utbits |= *ut->src++;
			if(src < smax)
				utbits |= *src++;
			else
				overbits += 8;
			utnbits += 8;
		}
		utnbits -= 9;
		off = (utbits >> utnbits) & ((1 << 9) - 1);

		/*
		 * literal
		 */
		bits = off >> 5;
		if(bits >= MaxOff){
			*d++ = off;


@@ 143,41 142,46 @@ unthwack(Unthwack *ut, uchar *dst, int ndst, uchar *src, int nsrc, ulong seq)
		bits += OffBase - 5;
		off <<= bits;

		while(utnbits < bits){
			if(ut->src >= ut->smax)
				error("unthwack eof");
			utbits <<= 8;
			utbits |= *ut->src++;
			utnbits += 8;
		}
		utnbits -= bits;
		off |= (utbits >> utnbits) & ((1 << bits) - 1);
		off++;

		len = 0;
		bits = 0;
		utbits &= (1 << utnbits) - 1;
		do{
			len <<= 1;
			if(utnbits < 1){
				if(ut->src >= ut->smax)
					error("unthwack eof");
			bits++;
			len = utbits >> (utnbits - bits);
		}while(bits < BigLenBits && len > lentab.maxcode[bits]);
		utnbits -= bits;

		if(bits < BigLenBits)
			len = lentab.decode[lentab.last[bits] - len];
		else{
			while(utnbits < MaxLenDecode){
				utbits <<= 8;
				utbits |= *ut->src++;
				if(src < smax)
					utbits |= *src++;
				else
					overbits += 8;
				utnbits += 8;
			}
			utnbits--;
			len |= (utbits >> utnbits) & 1;
			bits++;
		}while(len > lentab.maxcode[bits]);
		len = lentab.decode[lentab.last[bits] - len];

		if(len == MaxLen - 1){
			ut->nbits = utnbits;
			ut->bits = utbits;
			len += iomegaget(ut) - 1;
			utnbits = ut->nbits;
			utbits = ut->bits;

			code = len - BigLenCode;
			len = MaxFastLen;
			bits = 8;
			use = BigLenBase;
			while(code >= use){
				len += use;
				code -= use;
				code <<= 1;
				utnbits--;
				code |= (utbits >> utnbits) & 1;
				use <<= bits & 1;
				bits++;
			}
			len += code;
		}

		len += MinMatch;

		b = blocks;


@@ 185,17 189,19 @@ unthwack(Unthwack *ut, uchar *dst, int ndst, uchar *src, int nsrc, ulong seq)
			off -= b->maxoff;
			b++;
			if(b >= eblocks)
				error("unthwack offset");
				return -1;
		}
		if(d + len > dmax
		|| b != blocks && len > off)
			error("unthwack len");
			return -1;
		s = b->data + b->maxoff - off;
		es = s + len;
		while(s < es)
			*d++ = *s++;
		blocks->maxoff += len;
	}
	if(utnbits < overbits)
		return -1;

	len = d - blocks->data;
	memmove(dst, blocks->data, len);


@@ 205,49 211,5 @@ unthwack(Unthwack *ut, uchar *dst, int ndst, uchar *src, int nsrc, ulong seq)
	if(ut->slot >= DWinBlocks)
		ut->slot = 0;

	poperror();
	return len;
}

/*
 * elias's omega code, modified
 * for at least 3 bit transmission
 */
static ulong
iomegaget(Unthwack *ut)
{
	ulong v;
	int b;

	v = bitget(ut, 3);
	if((v & 0x4) == 0)
		return v + 1;
	for(;;){
		b = bitget(ut, 1);
		if(b == 0)
			return v + 1;
		if(v > 16)
			break;
		v--;
		v = (b << v) | bitget(ut, v);
	}
	error("unthwack iomegaget");
	return ~0;
}

static ulong
bitget(Unthwack *ut, int nb)
{
	int c;

	while(ut->nbits < nb){
		if(ut->src >= ut->smax)
			error("unthwack eof");
		c = *ut->src++;
		ut->bits <<= 8;
		ut->bits |= c;
		ut->nbits += 8;
	}
	ut->nbits -= nb;
	return (ut->bits >> ut->nbits) & ((1 << nb) - 1);
}