Commit 069de562774880ec2133022aee211329ff174b6a

Authored by balrog
1 parent e927bb00

Add a file missing from the previous commit.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4375 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 2 changed files with 602 additions and 0 deletions
hw/nseries.c
... ... @@ -1031,4 +1031,5 @@ QEMUMachine n810_machine = {
1031 1031 "n810",
1032 1032 "Nokia N810 tablet aka. RX-44 (OMAP2420)",
1033 1033 n810_init,
  1034 + (0x08000000 + 0x00010000 + OMAP242X_SRAM_SIZE) | RAMSIZE_FIXED,
1034 1035 };
... ...
hw/tsc2005.c 0 → 100644
  1 +/*
  2 + * TI TSC2005 emulator.
  3 + *
  4 + * Copyright (c) 2006 Andrzej Zaborowski <balrog@zabor.org>
  5 + * Copyright (C) 2008 Nokia Corporation
  6 + *
  7 + * This program is free software; you can redistribute it and/or
  8 + * modify it under the terms of the GNU General Public License as
  9 + * published by the Free Software Foundation; either version 2 or
  10 + * (at your option) version 3 of the License.
  11 + *
  12 + * This program is distributed in the hope that it will be useful,
  13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15 + * GNU General Public License for more details.
  16 + *
  17 + * You should have received a copy of the GNU General Public License
  18 + * along with this program; if not, write to the Free Software
  19 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  20 + * MA 02111-1307 USA
  21 + */
  22 +
  23 +#include "hw.h"
  24 +#include "qemu-timer.h"
  25 +#include "console.h"
  26 +#include "omap.h"
  27 +
  28 +#define TSC_DATA_REGISTERS_PAGE 0x0
  29 +#define TSC_CONTROL_REGISTERS_PAGE 0x1
  30 +#define TSC_AUDIO_REGISTERS_PAGE 0x2
  31 +
  32 +#define TSC_VERBOSE
  33 +
  34 +#define TSC_CUT_RESOLUTION(value, p) ((value) >> (16 - (p ? 12 : 10)))
  35 +
  36 +struct tsc2005_state_s {
  37 + qemu_irq pint; /* Combination of the nPENIRQ and DAV signals */
  38 + QEMUTimer *timer;
  39 + uint16_t model;
  40 +
  41 + int x, y;
  42 + int pressure;
  43 +
  44 + int state, reg, irq, command;
  45 + uint16_t data, dav;
  46 +
  47 + int busy;
  48 + int enabled;
  49 + int host_mode;
  50 + int function;
  51 + int nextfunction;
  52 + int precision;
  53 + int nextprecision;
  54 + int filter;
  55 + int pin_func;
  56 + int timing[2];
  57 + int noise;
  58 + int reset;
  59 + int pdst;
  60 + int pnd0;
  61 + uint16_t temp_thr[2];
  62 + uint16_t aux_thr[2];
  63 +
  64 + int tr[8];
  65 +};
  66 +
  67 +enum {
  68 + TSC_MODE_XYZ_SCAN = 0x0,
  69 + TSC_MODE_XY_SCAN,
  70 + TSC_MODE_X,
  71 + TSC_MODE_Y,
  72 + TSC_MODE_Z,
  73 + TSC_MODE_AUX,
  74 + TSC_MODE_TEMP1,
  75 + TSC_MODE_TEMP2,
  76 + TSC_MODE_AUX_SCAN,
  77 + TSC_MODE_X_TEST,
  78 + TSC_MODE_Y_TEST,
  79 + TSC_MODE_TS_TEST,
  80 + TSC_MODE_RESERVED,
  81 + TSC_MODE_XX_DRV,
  82 + TSC_MODE_YY_DRV,
  83 + TSC_MODE_YX_DRV,
  84 +};
  85 +
  86 +static const uint16_t mode_regs[16] = {
  87 + 0xf000, /* X, Y, Z scan */
  88 + 0xc000, /* X, Y scan */
  89 + 0x8000, /* X */
  90 + 0x4000, /* Y */
  91 + 0x3000, /* Z */
  92 + 0x0800, /* AUX */
  93 + 0x0400, /* TEMP1 */
  94 + 0x0200, /* TEMP2 */
  95 + 0x0800, /* AUX scan */
  96 + 0x0040, /* X test */
  97 + 0x0020, /* Y test */
  98 + 0x0080, /* Short-circuit test */
  99 + 0x0000, /* Reserved */
  100 + 0x0000, /* X+, X- drivers */
  101 + 0x0000, /* Y+, Y- drivers */
  102 + 0x0000, /* Y+, X- drivers */
  103 +};
  104 +
  105 +#define X_TRANSFORM(s) \
  106 + ((s->y * s->tr[0] - s->x * s->tr[1]) / s->tr[2] + s->tr[3])
  107 +#define Y_TRANSFORM(s) \
  108 + ((s->y * s->tr[4] - s->x * s->tr[5]) / s->tr[6] + s->tr[7])
  109 +#define Z1_TRANSFORM(s) \
  110 + ((400 - ((s)->x >> 7) + ((s)->pressure << 10)) << 4)
  111 +#define Z2_TRANSFORM(s) \
  112 + ((4000 + ((s)->y >> 7) - ((s)->pressure << 10)) << 4)
  113 +
  114 +#define AUX_VAL (700 << 4) /* +/- 3 at 12-bit */
  115 +#define TEMP1_VAL (1264 << 4) /* +/- 5 at 12-bit */
  116 +#define TEMP2_VAL (1531 << 4) /* +/- 5 at 12-bit */
  117 +
  118 +#define TSC_POWEROFF_DELAY 50
  119 +#define TSC_SOFTSTEP_DELAY 50
  120 +
  121 +static uint16_t tsc2005_read(struct tsc2005_state_s *s, int reg)
  122 +{
  123 + uint16_t ret;
  124 +
  125 + switch (reg) {
  126 + case 0x0: /* X */
  127 + s->dav &= ~mode_regs[TSC_MODE_X];
  128 + return TSC_CUT_RESOLUTION(X_TRANSFORM(s), s->precision) +
  129 + (s->noise & 3);
  130 + case 0x1: /* Y */
  131 + s->dav &= ~mode_regs[TSC_MODE_Y];
  132 + s->noise ++;
  133 + return TSC_CUT_RESOLUTION(Y_TRANSFORM(s), s->precision) ^
  134 + (s->noise & 3);
  135 + case 0x2: /* Z1 */
  136 + s->dav &= 0xdfff;
  137 + return TSC_CUT_RESOLUTION(Z1_TRANSFORM(s), s->precision) -
  138 + (s->noise & 3);
  139 + case 0x3: /* Z2 */
  140 + s->dav &= 0xefff;
  141 + return TSC_CUT_RESOLUTION(Z2_TRANSFORM(s), s->precision) |
  142 + (s->noise & 3);
  143 +
  144 + case 0x4: /* AUX */
  145 + s->dav &= ~mode_regs[TSC_MODE_AUX];
  146 + return TSC_CUT_RESOLUTION(AUX_VAL, s->precision);
  147 +
  148 + case 0x5: /* TEMP1 */
  149 + s->dav &= ~mode_regs[TSC_MODE_TEMP1];
  150 + return TSC_CUT_RESOLUTION(TEMP1_VAL, s->precision) -
  151 + (s->noise & 5);
  152 + case 0x6: /* TEMP2 */
  153 + s->dav &= 0xdfff;
  154 + s->dav &= ~mode_regs[TSC_MODE_TEMP2];
  155 + return TSC_CUT_RESOLUTION(TEMP2_VAL, s->precision) ^
  156 + (s->noise & 3);
  157 +
  158 + case 0x7: /* Status */
  159 + ret = s->dav | (s->reset << 7) | (s->pdst << 2) | 0x0;
  160 + s->dav &= ~(mode_regs[TSC_MODE_X_TEST] | mode_regs[TSC_MODE_Y_TEST] |
  161 + mode_regs[TSC_MODE_TS_TEST]);
  162 + s->reset = 1;
  163 + return ret;
  164 +
  165 + case 0x8: /* AUX high treshold */
  166 + return s->aux_thr[1];
  167 + case 0x9: /* AUX low treshold */
  168 + return s->aux_thr[0];
  169 +
  170 + case 0xa: /* TEMP high treshold */
  171 + return s->temp_thr[1];
  172 + case 0xb: /* TEMP low treshold */
  173 + return s->temp_thr[0];
  174 +
  175 + case 0xc: /* CFR0 */
  176 + return (s->pressure << 15) | ((!s->busy) << 14) |
  177 + (s->nextprecision << 13) | s->timing[0];
  178 + case 0xd: /* CFR1 */
  179 + return s->timing[1];
  180 + case 0xe: /* CFR2 */
  181 + return (s->pin_func << 14) | s->filter;
  182 +
  183 + case 0xf: /* Function select status */
  184 + return s->function >= 0 ? 1 << s->function : 0;
  185 + }
  186 +
  187 + /* Never gets here */
  188 + return 0xffff;
  189 +}
  190 +
  191 +static void tsc2005_write(struct tsc2005_state_s *s, int reg, uint16_t data)
  192 +{
  193 + switch (reg) {
  194 + case 0x8: /* AUX high treshold */
  195 + s->aux_thr[1] = data;
  196 + break;
  197 + case 0x9: /* AUX low treshold */
  198 + s->aux_thr[0] = data;
  199 + break;
  200 +
  201 + case 0xa: /* TEMP high treshold */
  202 + s->temp_thr[1] = data;
  203 + break;
  204 + case 0xb: /* TEMP low treshold */
  205 + s->temp_thr[0] = data;
  206 + break;
  207 +
  208 + case 0xc: /* CFR0 */
  209 + s->host_mode = data >> 15;
  210 + s->enabled = !(data & 0x4000);
  211 + if (s->busy && !s->enabled)
  212 + qemu_del_timer(s->timer);
  213 + s->busy &= s->enabled;
  214 + s->nextprecision = (data >> 13) & 1;
  215 + s->timing[0] = data & 0x1fff;
  216 + if ((s->timing[0] >> 11) == 3)
  217 + fprintf(stderr, "%s: illegal conversion clock setting\n",
  218 + __FUNCTION__);
  219 + break;
  220 + case 0xd: /* CFR1 */
  221 + s->timing[1] = data & 0xf07;
  222 + break;
  223 + case 0xe: /* CFR2 */
  224 + s->pin_func = (data >> 14) & 3;
  225 + s->filter = data & 0x3fff;
  226 + break;
  227 +
  228 + default:
  229 + fprintf(stderr, "%s: write into read-only register %x\n",
  230 + __FUNCTION__, reg);
  231 + }
  232 +}
  233 +
  234 +/* This handles most of the chip's logic. */
  235 +static void tsc2005_pin_update(struct tsc2005_state_s *s)
  236 +{
  237 + int64_t expires;
  238 + int pin_state;
  239 +
  240 + switch (s->pin_func) {
  241 + case 0:
  242 + pin_state = !s->pressure && !!s->dav;
  243 + break;
  244 + case 1:
  245 + case 3:
  246 + default:
  247 + pin_state = !s->dav;
  248 + break;
  249 + case 2:
  250 + pin_state = !s->pressure;
  251 + }
  252 +
  253 + if (!s->enabled)
  254 + pin_state = 0;
  255 +
  256 + if (pin_state != s->irq) {
  257 + s->irq = pin_state;
  258 + qemu_set_irq(s->pint, s->irq);
  259 + }
  260 +
  261 + switch (s->nextfunction) {
  262 + case TSC_MODE_XYZ_SCAN:
  263 + case TSC_MODE_XY_SCAN:
  264 + if (!s->pressure)
  265 + return;
  266 + /* Fall through */
  267 + case TSC_MODE_AUX_SCAN:
  268 + break;
  269 +
  270 + case TSC_MODE_X:
  271 + case TSC_MODE_Y:
  272 + case TSC_MODE_Z:
  273 + if (!s->pressure)
  274 + return;
  275 + /* Fall through */
  276 + case TSC_MODE_AUX:
  277 + case TSC_MODE_TEMP1:
  278 + case TSC_MODE_TEMP2:
  279 + case TSC_MODE_X_TEST:
  280 + case TSC_MODE_Y_TEST:
  281 + case TSC_MODE_TS_TEST:
  282 + if (s->dav)
  283 + s->enabled = 0;
  284 + break;
  285 +
  286 + case TSC_MODE_RESERVED:
  287 + case TSC_MODE_XX_DRV:
  288 + case TSC_MODE_YY_DRV:
  289 + case TSC_MODE_YX_DRV:
  290 + default:
  291 + return;
  292 + }
  293 +
  294 + if (!s->enabled || s->busy)
  295 + return;
  296 +
  297 + s->busy = 1;
  298 + s->precision = s->nextprecision;
  299 + s->function = s->nextfunction;
  300 + s->pdst = !s->pnd0; /* Synchronised on internal clock */
  301 + expires = qemu_get_clock(vm_clock) + (ticks_per_sec >> 7);
  302 + qemu_mod_timer(s->timer, expires);
  303 +}
  304 +
  305 +static void tsc2005_reset(struct tsc2005_state_s *s)
  306 +{
  307 + s->state = 0;
  308 + s->pin_func = 0;
  309 + s->enabled = 0;
  310 + s->busy = 0;
  311 + s->nextprecision = 0;
  312 + s->nextfunction = 0;
  313 + s->timing[0] = 0;
  314 + s->timing[1] = 0;
  315 + s->irq = 0;
  316 + s->dav = 0;
  317 + s->reset = 0;
  318 + s->pdst = 1;
  319 + s->pnd0 = 0;
  320 + s->function = -1;
  321 + s->temp_thr[0] = 0x000;
  322 + s->temp_thr[1] = 0xfff;
  323 + s->aux_thr[0] = 0x000;
  324 + s->aux_thr[1] = 0xfff;
  325 +
  326 + tsc2005_pin_update(s);
  327 +}
  328 +
  329 +uint8_t tsc2005_txrx_word(void *opaque, uint8_t value)
  330 +{
  331 + struct tsc2005_state_s *s = opaque;
  332 + uint32_t ret = 0;
  333 +
  334 + switch (s->state ++) {
  335 + case 0:
  336 + if (value & 0x80) {
  337 + /* Command */
  338 + if (value & (1 << 1))
  339 + tsc2005_reset(s);
  340 + else {
  341 + s->nextfunction = (value >> 3) & 0xf;
  342 + s->nextprecision = (value >> 2) & 1;
  343 + if (s->enabled != !(value & 1)) {
  344 + s->enabled = !(value & 1);
  345 + fprintf(stderr, "%s: touchscreen sense %sabled\n",
  346 + __FUNCTION__, s->enabled ? "en" : "dis");
  347 + }
  348 + tsc2005_pin_update(s);
  349 + }
  350 +
  351 + s->state = 0;
  352 + } else if (value) {
  353 + /* Data transfer */
  354 + s->reg = (value >> 3) & 0xf;
  355 + s->pnd0 = (value >> 1) & 1;
  356 + s->command = value & 1;
  357 +
  358 + if (s->command) {
  359 + /* Read */
  360 + s->data = tsc2005_read(s, s->reg);
  361 + tsc2005_pin_update(s);
  362 + } else
  363 + s->data = 0;
  364 + } else
  365 + s->state = 0;
  366 + break;
  367 +
  368 + case 1:
  369 + if (s->command)
  370 + ret = (s->data >> 8) & 0xff;
  371 + else
  372 + s->data |= value << 8;
  373 + break;
  374 +
  375 + case 2:
  376 + if (s->command)
  377 + ret = s->data & 0xff;
  378 + else {
  379 + s->data |= value;
  380 + tsc2005_write(s, s->reg, s->data);
  381 + tsc2005_pin_update(s);
  382 + }
  383 +
  384 + s->state = 0;
  385 + break;
  386 + }
  387 +
  388 + return ret;
  389 +}
  390 +
  391 +uint32_t tsc2005_txrx(void *opaque, uint32_t value, int len)
  392 +{
  393 + uint32_t ret = 0;
  394 +
  395 + len &= ~7;
  396 + while (len > 0) {
  397 + len -= 8;
  398 + ret |= tsc2005_txrx_word(opaque, (value >> len) & 0xff) << len;
  399 + }
  400 +
  401 + return ret;
  402 +}
  403 +
  404 +static void tsc2005_timer_tick(void *opaque)
  405 +{
  406 + struct tsc2005_state_s *s = opaque;
  407 +
  408 + /* Timer ticked -- a set of conversions has been finished. */
  409 +
  410 + if (!s->busy)
  411 + return;
  412 +
  413 + s->busy = 0;
  414 + s->dav |= mode_regs[s->function];
  415 + s->function = -1;
  416 + tsc2005_pin_update(s);
  417 +}
  418 +
  419 +static void tsc2005_touchscreen_event(void *opaque,
  420 + int x, int y, int z, int buttons_state)
  421 +{
  422 + struct tsc2005_state_s *s = opaque;
  423 + int p = s->pressure;
  424 +
  425 + if (buttons_state) {
  426 + s->x = x;
  427 + s->y = y;
  428 + }
  429 + s->pressure = !!buttons_state;
  430 +
  431 + /*
  432 + * Note: We would get better responsiveness in the guest by
  433 + * signaling TS events immediately, but for now we simulate
  434 + * the first conversion delay for sake of correctness.
  435 + */
  436 + if (p != s->pressure)
  437 + tsc2005_pin_update(s);
  438 +}
  439 +
  440 +static void tsc2005_save(QEMUFile *f, void *opaque)
  441 +{
  442 + struct tsc2005_state_s *s = (struct tsc2005_state_s *) opaque;
  443 + int i;
  444 +
  445 + qemu_put_be16(f, s->x);
  446 + qemu_put_be16(f, s->y);
  447 + qemu_put_byte(f, s->pressure);
  448 +
  449 + qemu_put_byte(f, s->state);
  450 + qemu_put_byte(f, s->reg);
  451 + qemu_put_byte(f, s->command);
  452 +
  453 + qemu_put_byte(f, s->irq);
  454 + qemu_put_be16s(f, &s->dav);
  455 + qemu_put_be16s(f, &s->data);
  456 +
  457 + qemu_put_timer(f, s->timer);
  458 + qemu_put_byte(f, s->enabled);
  459 + qemu_put_byte(f, s->host_mode);
  460 + qemu_put_byte(f, s->function);
  461 + qemu_put_byte(f, s->nextfunction);
  462 + qemu_put_byte(f, s->precision);
  463 + qemu_put_byte(f, s->nextprecision);
  464 + qemu_put_be16(f, s->filter);
  465 + qemu_put_byte(f, s->pin_func);
  466 + qemu_put_be16(f, s->timing[0]);
  467 + qemu_put_be16(f, s->timing[1]);
  468 + qemu_put_be16s(f, &s->temp_thr[0]);
  469 + qemu_put_be16s(f, &s->temp_thr[1]);
  470 + qemu_put_be16s(f, &s->aux_thr[0]);
  471 + qemu_put_be16s(f, &s->aux_thr[1]);
  472 + qemu_put_be32(f, s->noise);
  473 + qemu_put_byte(f, s->reset);
  474 + qemu_put_byte(f, s->pdst);
  475 + qemu_put_byte(f, s->pnd0);
  476 +
  477 + for (i = 0; i < 8; i ++)
  478 + qemu_put_be32(f, s->tr[i]);
  479 +}
  480 +
  481 +static int tsc2005_load(QEMUFile *f, void *opaque, int version_id)
  482 +{
  483 + struct tsc2005_state_s *s = (struct tsc2005_state_s *) opaque;
  484 + int i;
  485 +
  486 + s->x = qemu_get_be16(f);
  487 + s->y = qemu_get_be16(f);
  488 + s->pressure = qemu_get_byte(f);
  489 +
  490 + s->state = qemu_get_byte(f);
  491 + s->reg = qemu_get_byte(f);
  492 + s->command = qemu_get_byte(f);
  493 +
  494 + s->irq = qemu_get_byte(f);
  495 + qemu_get_be16s(f, &s->dav);
  496 + qemu_get_be16s(f, &s->data);
  497 +
  498 + qemu_get_timer(f, s->timer);
  499 + s->enabled = qemu_get_byte(f);
  500 + s->host_mode = qemu_get_byte(f);
  501 + s->function = qemu_get_byte(f);
  502 + s->nextfunction = qemu_get_byte(f);
  503 + s->precision = qemu_get_byte(f);
  504 + s->nextprecision = qemu_get_byte(f);
  505 + s->filter = qemu_get_be16(f);
  506 + s->pin_func = qemu_get_byte(f);
  507 + s->timing[0] = qemu_get_be16(f);
  508 + s->timing[1] = qemu_get_be16(f);
  509 + qemu_get_be16s(f, &s->temp_thr[0]);
  510 + qemu_get_be16s(f, &s->temp_thr[1]);
  511 + qemu_get_be16s(f, &s->aux_thr[0]);
  512 + qemu_get_be16s(f, &s->aux_thr[1]);
  513 + s->noise = qemu_get_be32(f);
  514 + s->reset = qemu_get_byte(f);
  515 + s->pdst = qemu_get_byte(f);
  516 + s->pnd0 = qemu_get_byte(f);
  517 +
  518 + for (i = 0; i < 8; i ++)
  519 + s->tr[i] = qemu_get_be32(f);
  520 +
  521 + s->busy = qemu_timer_pending(s->timer);
  522 + tsc2005_pin_update(s);
  523 +
  524 + return 0;
  525 +}
  526 +
  527 +static int tsc2005_iid = 0;
  528 +
  529 +void *tsc2005_init(qemu_irq pintdav)
  530 +{
  531 + struct tsc2005_state_s *s;
  532 +
  533 + s = (struct tsc2005_state_s *)
  534 + qemu_mallocz(sizeof(struct tsc2005_state_s));
  535 + s->x = 400;
  536 + s->y = 240;
  537 + s->pressure = 0;
  538 + s->precision = s->nextprecision = 0;
  539 + s->timer = qemu_new_timer(vm_clock, tsc2005_timer_tick, s);
  540 + s->pint = pintdav;
  541 + s->model = 0x2005;
  542 +
  543 + s->tr[0] = 0;
  544 + s->tr[1] = 1;
  545 + s->tr[2] = 1;
  546 + s->tr[3] = 0;
  547 + s->tr[4] = 1;
  548 + s->tr[5] = 0;
  549 + s->tr[6] = 1;
  550 + s->tr[7] = 0;
  551 +
  552 + tsc2005_reset(s);
  553 +
  554 + qemu_add_mouse_event_handler(tsc2005_touchscreen_event, s, 1,
  555 + "QEMU TSC2005-driven Touchscreen");
  556 +
  557 + qemu_register_reset((void *) tsc2005_reset, s);
  558 + register_savevm("tsc2005", tsc2005_iid ++, 0,
  559 + tsc2005_save, tsc2005_load, s);
  560 +
  561 + return s;
  562 +}
  563 +
  564 +/*
  565 + * Use tslib generated calibration data to generate ADC input values
  566 + * from the touchscreen. Assuming 12-bit precision was used during
  567 + * tslib calibration.
  568 + */
  569 +void tsc2005_set_transform(void *opaque, struct mouse_transform_info_s *info)
  570 +{
  571 + struct tsc2005_state_s *s = (struct tsc2005_state_s *) opaque;
  572 +
  573 + /* This version assumes touchscreen X & Y axis are parallel or
  574 + * perpendicular to LCD's X & Y axis in some way. */
  575 + if (abs(info->a[0]) > abs(info->a[1])) {
  576 + s->tr[0] = 0;
  577 + s->tr[1] = -info->a[6] * info->x;
  578 + s->tr[2] = info->a[0];
  579 + s->tr[3] = -info->a[2] / info->a[0];
  580 + s->tr[4] = info->a[6] * info->y;
  581 + s->tr[5] = 0;
  582 + s->tr[6] = info->a[4];
  583 + s->tr[7] = -info->a[5] / info->a[4];
  584 + } else {
  585 + s->tr[0] = info->a[6] * info->y;
  586 + s->tr[1] = 0;
  587 + s->tr[2] = info->a[1];
  588 + s->tr[3] = -info->a[2] / info->a[1];
  589 + s->tr[4] = 0;
  590 + s->tr[5] = -info->a[6] * info->x;
  591 + s->tr[6] = info->a[3];
  592 + s->tr[7] = -info->a[5] / info->a[3];
  593 + }
  594 +
  595 + s->tr[0] >>= 11;
  596 + s->tr[1] >>= 11;
  597 + s->tr[3] <<= 4;
  598 + s->tr[4] >>= 11;
  599 + s->tr[5] >>= 11;
  600 + s->tr[7] <<= 4;
  601 +}
... ...