static void
nv40_graph_construct_state3d_3(struct nouveau_grctx *ctx)
{
	int len = nv44_graph_class(ctx->dev) ? 0x0084 : 0x0684;

	cp_out (ctx, 0x300000);
	cp_lsr (ctx, len - 4);
	cp_bra (ctx, SWAP_DIRECTION, SAVE, cp_swap_state3d_3_is_save);
	cp_lsr (ctx, len);
	cp_name(ctx, cp_swap_state3d_3_is_save);
	cp_out (ctx, 0x800001);

	ctx->ctxvals_pos += len;
}
static void
nv40_graph_construct_shader(struct nouveau_grctx *ctx)
{
	struct drm_device *dev = ctx->dev;
	struct drm_nouveau_private *dev_priv = dev->dev_private;
	struct nouveau_gpuobj *obj = ctx->data;
	int vs, vs_nr, vs_len, vs_nr_b0, vs_nr_b1, b0_offset, b1_offset;
	int offset, i;

	vs_nr    = nv40_graph_vs_count(ctx->dev);
	vs_nr_b0 = 363;
	vs_nr_b1 = dev_priv->chipset == 0x40 ? 128 : 64;
	if (dev_priv->chipset == 0x40) {
		b0_offset = 0x2200/4; /* 33a0 */
		b1_offset = 0x55a0/4; /* 1500 */
		vs_len = 0x6aa0/4;
	} else
	if (dev_priv->chipset == 0x41 || dev_priv->chipset == 0x42) {
		b0_offset = 0x2200/4; /* 2200 */
		b1_offset = 0x4400/4; /* 0b00 */
		vs_len = 0x4f00/4;
	} else {
		b0_offset = 0x1d40/4; /* 2200 */
		b1_offset = 0x3f40/4; /* 0b00 : 0a40 */
		vs_len = nv44_graph_class(dev) ? 0x4980/4 : 0x4a40/4;
	}

	cp_lsr(ctx, vs_len * vs_nr + 0x300/4);
	cp_out(ctx, nv44_graph_class(dev) ? 0x800029 : 0x800041);

	offset = ctx->ctxvals_pos;
	ctx->ctxvals_pos += (0x0300/4 + (vs_nr * vs_len));

	if (ctx->mode != NOUVEAU_GRCTX_VALS)
		return;

	offset += 0x0280/4;
	for (i = 0; i < 16; i++, offset += 2)
		nv_wo32(obj, offset * 4, 0x3f800000);

	for (vs = 0; vs < vs_nr; vs++, offset += vs_len) {
		for (i = 0; i < vs_nr_b0 * 6; i += 6)
			nv_wo32(obj, (offset + b0_offset + i) * 4, 0x00000001);
		for (i = 0; i < vs_nr_b1 * 4; i += 4)
			nv_wo32(obj, (offset + b1_offset + i) * 4, 0x3f800000);
	}
}
static void
nv40_grctx_generate(struct nouveau_grctx *ctx)
{
	/* decide whether we're loading/unloading the context */
	cp_bra (ctx, AUTO_SAVE, PENDING, cp_setup_save);
	cp_bra (ctx, USER_SAVE, PENDING, cp_setup_save);

	cp_name(ctx, cp_check_load);
	cp_bra (ctx, AUTO_LOAD, PENDING, cp_setup_auto_load);
	cp_bra (ctx, USER_LOAD, PENDING, cp_setup_load);
	cp_bra (ctx, ALWAYS, TRUE, cp_exit);

	/* setup for context load */
	cp_name(ctx, cp_setup_auto_load);
	cp_wait(ctx, STATUS, IDLE);
	cp_out (ctx, CP_NEXT_TO_SWAP);
	cp_name(ctx, cp_setup_load);
	cp_wait(ctx, STATUS, IDLE);
	cp_set (ctx, SWAP_DIRECTION, LOAD);
	cp_out (ctx, 0x00910880); /* ?? */
	cp_out (ctx, 0x00901ffe); /* ?? */
	cp_out (ctx, 0x01940000); /* ?? */
	cp_lsr (ctx, 0x20);
	cp_out (ctx, 0x0060000b); /* ?? */
	cp_wait(ctx, UNK57, CLEAR);
	cp_out (ctx, 0x0060000c); /* ?? */
	cp_bra (ctx, ALWAYS, TRUE, cp_swap_state);

	/* setup for context save */
	cp_name(ctx, cp_setup_save);
	cp_set (ctx, SWAP_DIRECTION, SAVE);

	/* general PGRAPH state */
	cp_name(ctx, cp_swap_state);
	cp_pos (ctx, 0x00020/4);
	nv40_graph_construct_general(ctx);
	cp_wait(ctx, STATUS, IDLE);

	/* 3D state, block 1 */
	cp_bra (ctx, UNK54, CLEAR, cp_prepare_exit);
	nv40_graph_construct_state3d(ctx);
	cp_wait(ctx, STATUS, IDLE);

	/* 3D state, block 2 */
	nv40_graph_construct_state3d_2(ctx);

	/* Some other block of "random" state */
	nv40_graph_construct_state3d_3(ctx);

	/* Per-vertex shader state */
	cp_pos (ctx, ctx->ctxvals_pos);
	nv40_graph_construct_shader(ctx);

	/* pre-exit state updates */
	cp_name(ctx, cp_prepare_exit);
	cp_bra (ctx, SWAP_DIRECTION, SAVE, cp_check_load);
	cp_bra (ctx, USER_SAVE, PENDING, cp_exit);
	cp_out (ctx, CP_NEXT_TO_CURRENT);

	cp_name(ctx, cp_exit);
	cp_set (ctx, USER_SAVE, NOT_PENDING);
	cp_set (ctx, USER_LOAD, NOT_PENDING);
	cp_out (ctx, CP_END);
}
void
nv40_grctx_init(struct nouveau_grctx *ctx)
{

    cp_bra (ctx, AUTO_SAVE, PENDING, cp_setup_save);
    cp_bra (ctx, USER_SAVE, PENDING, cp_setup_save);

    cp_name(ctx, cp_check_load);
    cp_bra (ctx, AUTO_LOAD, PENDING, cp_setup_auto_load);
    cp_bra (ctx, USER_LOAD, PENDING, cp_setup_load);
    cp_bra (ctx, ALWAYS, TRUE, cp_exit);


    cp_name(ctx, cp_setup_auto_load);
    cp_wait(ctx, STATUS, IDLE);
    cp_out (ctx, CP_NEXT_TO_SWAP);
    cp_name(ctx, cp_setup_load);
    cp_wait(ctx, STATUS, IDLE);
    cp_set (ctx, SWAP_DIRECTION, LOAD);
    cp_out (ctx, 0x00910880);
    cp_out (ctx, 0x00901ffe);
    cp_out (ctx, 0x01940000);
    cp_lsr (ctx, 0x20);
    cp_out (ctx, 0x0060000b);
    cp_wait(ctx, UNK57, CLEAR);
    cp_out (ctx, 0x0060000c);
    cp_bra (ctx, ALWAYS, TRUE, cp_swap_state);


    cp_name(ctx, cp_setup_save);
    cp_set (ctx, SWAP_DIRECTION, SAVE);


    cp_name(ctx, cp_swap_state);
    cp_pos (ctx, 0x00020/4);
    nv40_graph_construct_general(ctx);
    cp_wait(ctx, STATUS, IDLE);


    cp_bra (ctx, UNK54, CLEAR, cp_prepare_exit);
    nv40_graph_construct_state3d(ctx);
    cp_wait(ctx, STATUS, IDLE);


    nv40_graph_construct_state3d_2(ctx);


    nv40_graph_construct_state3d_3(ctx);


    cp_pos (ctx, ctx->ctxvals_pos);
    nv40_graph_construct_shader(ctx);


    cp_name(ctx, cp_prepare_exit);
    cp_bra (ctx, SWAP_DIRECTION, SAVE, cp_check_load);
    cp_bra (ctx, USER_SAVE, PENDING, cp_exit);
    cp_out (ctx, CP_NEXT_TO_CURRENT);

    cp_name(ctx, cp_exit);
    cp_set (ctx, USER_SAVE, NOT_PENDING);
    cp_set (ctx, USER_LOAD, NOT_PENDING);
    cp_out (ctx, CP_END);
}