(linenum→info "unix/slp.c:2238")

qemu/0.9.1/hw/i8254.c

    1: /*
    2:  * QEMU 8253/8254 interval timer emulation
    3:  *
    4:  * Copyright (c) 2003-2004 Fabrice Bellard
    5:  *
    6:  * Permission is hereby granted, free of charge, to any person obtaining a copy
    7:  * of this software and associated documentation files (the "Software"), to deal
    8:  * in the Software without restriction, including without limitation the rights
    9:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   10:  * copies of the Software, and to permit persons to whom the Software is
   11:  * furnished to do so, subject to the following conditions:
   12:  *
   13:  * The above copyright notice and this permission notice shall be included in
   14:  * all copies or substantial portions of the Software.
   15:  *
   16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   17:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   21:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   22:  * THE SOFTWARE.
   23:  */
   24: #include "hw.h"
   25: #include "pc.h"
   26: #include "isa.h"
   27: #include "qemu-timer.h"
   28: 
   29: //#define DEBUG_PIT
   30: 
   31: #define RW_STATE_LSB 1
   32: #define RW_STATE_MSB 2
   33: #define RW_STATE_WORD0 3
   34: #define RW_STATE_WORD1 4
   35: 
   36: typedef struct PITChannelState {
   37:     int count; /* can be 65536 */
   38:     uint16_t latched_count;
   39:     uint8_t count_latched;
   40:     uint8_t status_latched;
   41:     uint8_t status;
   42:     uint8_t read_state;
   43:     uint8_t write_state;
   44:     uint8_t write_latch;
   45:     uint8_t rw_mode;
   46:     uint8_t mode;
   47:     uint8_t bcd; /* not supported */
   48:     uint8_t gate; /* timer start */
   49:     int64_t count_load_time;
   50:     /* irq handling */
   51:     int64_t next_transition_time;
   52:     QEMUTimer *irq_timer;
   53:     qemu_irq irq;
   54: } PITChannelState;
   55: 
   56: struct PITState {
   57:     PITChannelState channels[3];
   58: };
   59: 
   60: static PITState pit_state;
   61: 
   62: static void pit_irq_timer_update(PITChannelState *s, int64_t current_time);
   63: 
   64: static int pit_get_count(PITChannelState *s)
   65: {
   66:     uint64_t d;
   67:     int counter;
   68: 
   69:     d = muldiv64(qemu_get_clock(vm_clock) - s->count_load_time, PIT_FREQ, ticks_per_sec);
   70:     switch(s->mode) {
   71:     case 0:
   72:     case 1:
   73:     case 4:
   74:     case 5:
   75:         counter = (s->count - d) & 0xffff;
   76:         break;
   77:     case 3:
   78:         /* XXX: may be incorrect for odd counts */
   79:         counter = s->count - ((2 * d) % s->count);
   80:         break;
   81:     default:
   82:         counter = s->count - (d % s->count);
   83:         break;
   84:     }
   85:     return counter;
   86: }
   87: 
   88: /* get pit output bit */
   89: static int pit_get_out1(PITChannelState *s, int64_t current_time)
   90: {
   91:     uint64_t d;
   92:     int out;
   93: 
   94:     d = muldiv64(current_time - s->count_load_time, PIT_FREQ, ticks_per_sec);
   95:     switch(s->mode) {
   96:     default:
   97:     case 0:
   98:         out = (d >= s->count);
   99:         break;
  100:     case 1:
  101:         out = (d < s->count);
  102:         break;
  103:     case 2:
  104:         if ((d % s->count) == 0 && d != 0)
  105:             out = 1;
  106:         else
  107:             out = 0;
  108:         break;
  109:     case 3:
  110:         out = (d % s->count) < ((s->count + 1) >> 1);
  111:         break;
  112:     case 4:
  113:     case 5:
  114:         out = (d == s->count);
  115:         break;
  116:     }
  117:     return out;
  118: }
  119: 
  120: int pit_get_out(PITState *pit, int channel, int64_t current_time)
  121: {
  122:     PITChannelState *s = &pit->channels[channel];
  123:     return pit_get_out1(s, current_time);
  124: }
  125: 
  126: /* return -1 if no transition will occur.  */
  127: static int64_t pit_get_next_transition_time(PITChannelState *s,
  128:                                             int64_t current_time)
  129: {
  130:     uint64_t d, next_time, base;
  131:     int period2;
  132: 
  133:     d = muldiv64(current_time - s->count_load_time, PIT_FREQ, ticks_per_sec);
  134:     switch(s->mode) {
  135:     default:
  136:     case 0:
  137:     case 1:
  138:         if (d < s->count)
  139:             next_time = s->count;
  140:         else
  141:             return -1;
  142:         break;
  143:     case 2:
  144:         base = (d / s->count) * s->count;
  145:         if ((d - base) == 0 && d != 0)
  146:             next_time = base + s->count;
  147:         else
  148:             next_time = base + s->count + 1;
  149:         break;
  150:     case 3:
  151:         base = (d / s->count) * s->count;
  152:         period2 = ((s->count + 1) >> 1);
  153:         if ((d - base) < period2)
  154:             next_time = base + period2;
  155:         else
  156:             next_time = base + s->count;
  157:         break;
  158:     case 4:
  159:     case 5:
  160:         if (d < s->count)
  161:             next_time = s->count;
  162:         else if (d == s->count)
  163:             next_time = s->count + 1;
  164:         else
  165:             return -1;
  166:         break;
  167:     }
  168:     /* convert to timer units */
  169:     next_time = s->count_load_time + muldiv64(next_time, ticks_per_sec, PIT_FREQ);
  170:     /* fix potential rounding problems */
  171:     /* XXX: better solution: use a clock at PIT_FREQ Hz */
  172:     if (next_time <= current_time)
  173:         next_time = current_time + 1;
  174:     return next_time;
  175: }
  176: 
  177: /* val must be 0 or 1 */
  178: void pit_set_gate(PITState *pit, int channel, int val)
  179: {
  180:     PITChannelState *s = &pit->channels[channel];
  181: 
  182:     switch(s->mode) {
  183:     default:
  184:     case 0:
  185:     case 4:
  186:         /* XXX: just disable/enable counting */
  187:         break;
  188:     case 1:
  189:     case 5:
  190:         if (s->gate < val) {
  191:             /* restart counting on rising edge */
  192:             s->count_load_time = qemu_get_clock(vm_clock);
  193:             pit_irq_timer_update(s, s->count_load_time);
  194:         }
  195:         break;
  196:     case 2:
  197:     case 3:
  198:         if (s->gate < val) {
  199:             /* restart counting on rising edge */
  200:             s->count_load_time = qemu_get_clock(vm_clock);
  201:             pit_irq_timer_update(s, s->count_load_time);
  202:         }
  203:         /* XXX: disable/enable counting */
  204:         break;
  205:     }
  206:     s->gate = val;
  207: }
  208: 
  209: int pit_get_gate(PITState *pit, int channel)
  210: {
  211:     PITChannelState *s = &pit->channels[channel];
  212:     return s->gate;
  213: }
  214: 
  215: int pit_get_initial_count(PITState *pit, int channel)
  216: {
  217:     PITChannelState *s = &pit->channels[channel];
  218:     return s->count;
  219: }
  220: 
  221: int pit_get_mode(PITState *pit, int channel)
  222: {
  223:     PITChannelState *s = &pit->channels[channel];
  224:     return s->mode;
  225: }
  226: 
  227: static inline void pit_load_count(PITChannelState *s, int val)
  228: {
  229:     if (val == 0)
  230:         val = 0x10000;
  231:     s->count_load_time = qemu_get_clock(vm_clock);
  232:     s->count = val;
  233:     pit_irq_timer_update(s, s->count_load_time);
  234: }
  235: 
  236: /* if already latched, do not latch again */
  237: static void pit_latch_count(PITChannelState *s)
  238: {
  239:     if (!s->count_latched) {
  240:         s->latched_count = pit_get_count(s);
  241:         s->count_latched = s->rw_mode;
  242:     }
  243: }
  244: 
  245: static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val)
  246: {
  247:     PITState *pit = opaque;
  248:     int channel, access;
  249:     PITChannelState *s;
  250: 
  251:     addr &= 3;
  252:     if (addr == 3) {
  253:         channel = val >> 6;
  254:         if (channel == 3) {
  255:             /* read back command */
  256:             for(channel = 0; channel < 3; channel++) {
  257:                 s = &pit->channels[channel];
  258:                 if (val & (2 << channel)) {
  259:                     if (!(val & 0x20)) {
  260:                         pit_latch_count(s);
  261:                     }
  262:                     if (!(val & 0x10) && !s->status_latched) {
  263:                         /* status latch */
  264:                         /* XXX: add BCD and null count */
  265:                         s->status =  (pit_get_out1(s, qemu_get_clock(vm_clock)) << 7) |
  266:                             (s->rw_mode << 4) |
  267:                             (s->mode << 1) |
  268:                             s->bcd;
  269:                         s->status_latched = 1;
  270:                     }
  271:                 }
  272:             }
  273:         } else {
  274:             s = &pit->channels[channel];
  275:             access = (val >> 4) & 3;
  276:             if (access == 0) {
  277:                 pit_latch_count(s);
  278:             } else {
  279:                 s->rw_mode = access;
  280:                 s->read_state = access;
  281:                 s->write_state = access;
  282: 
  283:                 s->mode = (val >> 1) & 7;
  284:                 s->bcd = val & 1;
  285:                 /* XXX: update irq timer ? */
  286:             }
  287:         }
  288:     } else {
  289:         s = &pit->channels[addr];
  290:         switch(s->write_state) {
  291:         default:
  292:         case RW_STATE_LSB:
  293:             pit_load_count(s, val);
  294:             break;
  295:         case RW_STATE_MSB:
  296:             pit_load_count(s, val << 8);
  297:             break;
  298:         case RW_STATE_WORD0:
  299:             s->write_latch = val;
  300:             s->write_state = RW_STATE_WORD1;
  301:             break;
  302:         case RW_STATE_WORD1:
  303:             pit_load_count(s, s->write_latch | (val << 8));
  304:             s->write_state = RW_STATE_WORD0;
  305:             break;
  306:         }
  307:     }
  308: }
  309: 
  310: static uint32_t pit_ioport_read(void *opaque, uint32_t addr)
  311: {
  312:     PITState *pit = opaque;
  313:     int ret, count;
  314:     PITChannelState *s;
  315: 
  316:     addr &= 3;
  317:     s = &pit->channels[addr];
  318:     if (s->status_latched) {
  319:         s->status_latched = 0;
  320:         ret = s->status;
  321:     } else if (s->count_latched) {
  322:         switch(s->count_latched) {
  323:         default:
  324:         case RW_STATE_LSB:
  325:             ret = s->latched_count & 0xff;
  326:             s->count_latched = 0;
  327:             break;
  328:         case RW_STATE_MSB:
  329:             ret = s->latched_count >> 8;
  330:             s->count_latched = 0;
  331:             break;
  332:         case RW_STATE_WORD0:
  333:             ret = s->latched_count & 0xff;
  334:             s->count_latched = RW_STATE_MSB;
  335:             break;
  336:         }
  337:     } else {
  338:         switch(s->read_state) {
  339:         default:
  340:         case RW_STATE_LSB:
  341:             count = pit_get_count(s);
  342:             ret = count & 0xff;
  343:             break;
  344:         case RW_STATE_MSB:
  345:             count = pit_get_count(s);
  346:             ret = (count >> 8) & 0xff;
  347:             break;
  348:         case RW_STATE_WORD0:
  349:             count = pit_get_count(s);
  350:             ret = count & 0xff;
  351:             s->read_state = RW_STATE_WORD1;
  352:             break;
  353:         case RW_STATE_WORD1:
  354:             count = pit_get_count(s);
  355:             ret = (count >> 8) & 0xff;
  356:             s->read_state = RW_STATE_WORD0;
  357:             break;
  358:         }
  359:     }
  360:     return ret;
  361: }
  362: 
  363: static void pit_irq_timer_update(PITChannelState *s, int64_t current_time)
  364: {
  365:     int64_t expire_time;
  366:     int irq_level;
  367: 
  368:     if (!s->irq_timer)
  369:         return;
  370:     expire_time = pit_get_next_transition_time(s, current_time);
  371:     irq_level = pit_get_out1(s, current_time);
  372:     qemu_set_irq(s->irq, irq_level);
  373: #ifdef DEBUG_PIT
  374:     printf("irq_level=%d next_delay=%f\n",
  375:            irq_level,
  376:            (double)(expire_time - current_time) / ticks_per_sec);
  377: #endif
  378:     s->next_transition_time = expire_time;
  379:     if (expire_time != -1)
  380:         qemu_mod_timer(s->irq_timer, expire_time);
  381:     else
  382:         qemu_del_timer(s->irq_timer);
  383: }
  384: 
  385: static void pit_irq_timer(void *opaque)
  386: {
  387:     PITChannelState *s = opaque;
  388: 
  389:     pit_irq_timer_update(s, s->next_transition_time);
  390: }
  391: 
  392: static void pit_save(QEMUFile *f, void *opaque)
  393: {
  394:     PITState *pit = opaque;
  395:     PITChannelState *s;
  396:     int i;
  397: 
  398:     for(i = 0; i < 3; i++) {
  399:         s = &pit->channels[i];
  400:         qemu_put_be32(f, s->count);
  401:         qemu_put_be16s(f, &s->latched_count);
  402:         qemu_put_8s(f, &s->count_latched);
  403:         qemu_put_8s(f, &s->status_latched);
  404:         qemu_put_8s(f, &s->status);
  405:         qemu_put_8s(f, &s->read_state);
  406:         qemu_put_8s(f, &s->write_state);
  407:         qemu_put_8s(f, &s->write_latch);
  408:         qemu_put_8s(f, &s->rw_mode);
  409:         qemu_put_8s(f, &s->mode);
  410:         qemu_put_8s(f, &s->bcd);
  411:         qemu_put_8s(f, &s->gate);
  412:         qemu_put_be64(f, s->count_load_time);
  413:         if (s->irq_timer) {
  414:             qemu_put_be64(f, s->next_transition_time);
  415:             qemu_put_timer(f, s->irq_timer);
  416:         }
  417:     }
  418: }
  419: 
  420: static int pit_load(QEMUFile *f, void *opaque, int version_id)
  421: {
  422:     PITState *pit = opaque;
  423:     PITChannelState *s;
  424:     int i;
  425: 
  426:     if (version_id != 1)
  427:         return -EINVAL;
  428: 
  429:     for(i = 0; i < 3; i++) {
  430:         s = &pit->channels[i];
  431:         s->count=qemu_get_be32(f);
  432:         qemu_get_be16s(f, &s->latched_count);
  433:         qemu_get_8s(f, &s->count_latched);
  434:         qemu_get_8s(f, &s->status_latched);
  435:         qemu_get_8s(f, &s->status);
  436:         qemu_get_8s(f, &s->read_state);
  437:         qemu_get_8s(f, &s->write_state);
  438:         qemu_get_8s(f, &s->write_latch);
  439:         qemu_get_8s(f, &s->rw_mode);
  440:         qemu_get_8s(f, &s->mode);
  441:         qemu_get_8s(f, &s->bcd);
  442:         qemu_get_8s(f, &s->gate);
  443:         s->count_load_time=qemu_get_be64(f);
  444:         if (s->irq_timer) {
  445:             s->next_transition_time=qemu_get_be64(f);
  446:             qemu_get_timer(f, s->irq_timer);
  447:         }
  448:     }
  449:     return 0;
  450: }
  451: 
  452: static void pit_reset(void *opaque)
  453: {
  454:     PITState *pit = opaque;
  455:     PITChannelState *s;
  456:     int i;
  457: 
  458:     for(i = 0;i < 3; i++) {
  459:         s = &pit->channels[i];
  460:         s->mode = 3;
  461:         s->gate = (i != 2);
  462:         pit_load_count(s, 0);
  463:     }
  464: }
  465: 
  466: PITState *pit_init(int base, qemu_irq irq)
  467: {
  468:     PITState *pit = &pit_state;
  469:     PITChannelState *s;
  470: 
  471:     s = &pit->channels[0];
  472:     /* the timer 0 is connected to an IRQ */
  473:     s->irq_timer = qemu_new_timer(vm_clock, pit_irq_timer, s);
  474:     s->irq = irq;
  475: 
  476:     register_savevm("i8254", base, 1, pit_save, pit_load, pit);
  477: 
  478:     qemu_register_reset(pit_reset, pit);
  479:     register_ioport_write(base, 4, 1, pit_ioport_write, pit);
  480:     register_ioport_read(base, 3, 1, pit_ioport_read, pit);
  481: 
  482:     pit_reset(pit);
  483: 
  484:     return pit;
  485: }
Syntax (Markdown)