/* Service counter-overflow IRQ: turn the LED on and enable the compare IRQ * that turns it off */ HW_ISR( COUNTER, overflow, non_interruptible ) { /* No need to protect access to duty since interrupts are not allowed */ if ( duty ) { hw( write, PIN_LED, 1 ); if ( duty < COUNT_TOP ) { hw( write, (COUNTER,compare1), duty ); hw( turn, irq(COUNTER,compare1), on ); } else hw( turn, irq(COUNTER,compare1), off ); } else { hw( write, PIN_LED, 0 ); hw( turn, irq(COUNTER,compare1), off ); } }
IMPLEMENT void Timer::init(Cpu_number) { printf("Using the PIT (i8254) on IRQ %d for scheduling\n", irq()); // set up timer interrupt (~ 1ms) Pit::init(); }
void msm6242_device::update_rtc_registers() { // get the absolute current time, in ticks UINT64 curtime = current_time(); // how long as it been since we last updated? UINT64 delta = curtime - m_last_update_time; // set current time m_last_update_time = curtime; // no delta? just return if (delta == 0) return; // ticks if ((m_tick % 200) != (int)((delta + m_tick) % 0x200)) irq(IRQ_64THSECOND); delta = bump(RTC_TICKS, delta, 0, 0x8000); if (delta == 0) return; // seconds irq(IRQ_SECOND); delta = bump(RTC_SECOND, delta, 0, 60); if (delta == 0) return; // minutes irq(IRQ_MINUTE); delta = bump(RTC_MINUTE, delta, 0, 60); if (delta == 0) return; // hours irq(IRQ_HOUR); delta = bump(RTC_HOUR, delta, 0, 24); if (delta == 0) return; // days while(delta--) advance_days(); }
/* The UART should be ready for reconfiguration. Configure timer1 too. */ void IROM user_init_2 ( ) { os_timer_disarm( &os_timer ); /* Install user IRQ handlers */ os_set_isr( irq(timer1,irq), ev_timer ); os_set_isr( irq(timer1,nmi), ev_timer ); hwa( begin_from_reset ); hwa( configure, PIN_LED, function, gpio, mode, digital_output ); /* Reconfigure the UART */ hwa( configure, gpio15, function, (uart0,txd) ); hwa( configure, gpio13, function, (uart0,rxd) ); hwa( configure, uart0, baudrate, 115200, databits, 8, parity, none, stopbits, 1 ); /* Configure the timer1 to trigger an interrupt every 10 ms */ hwa( configure, timer1, clock, apb/256, direction, down_loop, top, 0.5 + 0.1*HW_APBHZ/256, action, irq ); hwa( commit ); os_printf("START with user configuration: RXD=GPIO13 TXD=GPIO15\n"); /* Trigger a function call every 100 ms (about) */ os_timer_setfn( &os_timer, (os_timer_func_t *)every_100ms, NULL ); os_timer_arm( &os_timer, 100, 1 ); }
/** * Initialise the timer */ void timer_initialise(void) { asm volatile("sti"); irq(IRQ_TIMER, timer_handler); }
VirtioBlk::VirtioBlk(hw::PCI_Device& d) : Virtio(d), hw::Drive(), req(queue_size(0), 0, iobase()), inflight(0) { INFO("VirtioBlk", "Driver initializing"); { auto& reqs = Statman::get().create( Stat::UINT32, blkname() + ".requests"); this->requests = &reqs.get_uint32(); *this->requests = 0; auto& err = Statman::get().create( Stat::UINT32, blkname() + ".errors"); this->errors = &err.get_uint32(); *this->errors = 0; } uint32_t needed_features = FEAT(VIRTIO_BLK_F_BLK_SIZE); negotiate_features(needed_features); CHECK(features() & FEAT(VIRTIO_BLK_F_BARRIER), "Barrier is enabled"); CHECK(features() & FEAT(VIRTIO_BLK_F_SIZE_MAX), "Size-max is known"); CHECK(features() & FEAT(VIRTIO_BLK_F_SEG_MAX), "Seg-max is known"); CHECK(features() & FEAT(VIRTIO_BLK_F_GEOMETRY), "Geometry structure is used"); CHECK(features() & FEAT(VIRTIO_BLK_F_RO), "Device is read-only"); CHECK(features() & FEAT(VIRTIO_BLK_F_BLK_SIZE), "Block-size is known"); CHECK(features() & FEAT(VIRTIO_BLK_F_SCSI), "SCSI is enabled :("); CHECK(features() & FEAT(VIRTIO_BLK_F_FLUSH), "Flush enabled"); CHECK ((features() & needed_features) == needed_features, "Negotiated needed features"); // Step 1 - Initialize REQ queue auto success = assign_queue(0, (uint32_t) req.queue_desc()); CHECK(success, "Request queue assigned (0x%x) to device", (uint32_t) req.queue_desc()); // Step 3 - Fill receive queue with buffers // DEBUG: Disable INFO("VirtioBlk", "Queue size: %i\tRequest size: %u\n", req.size(), sizeof(request_t)); // Get device configuration get_config(); // Signal setup complete. setup_complete((features() & needed_features) == needed_features); CHECK((features() & needed_features) == needed_features, "Signalled driver OK"); // Hook up IRQ handler (inherited from Virtio) if (is_msix()) { // update IRQ subscriptions IRQ_manager::get().subscribe(irq() + 0, {this, &VirtioBlk::service_RX}); IRQ_manager::get().subscribe(irq() + 1, {this, &VirtioBlk::msix_conf_handler}); } else { auto del(delegate<void()>{this, &VirtioBlk::irq_handler}); IRQ_manager::get().subscribe(irq(), del); } // Done INFO("VirtioBlk", "Block device with %llu sectors capacity", config.capacity); }
void trap(Ureg *ureg) { int rem, itype, t; if(up != nil) rem = ((char*)ureg)-up->kstack; else rem = ((char*)ureg)-(char*)m->stack; if(ureg->type != PsrMfiq && rem < 256) { dumpregs(ureg); panic("trap %d stack bytes remaining (%s), " "up=#%8.8lux ureg=#%8.8lux pc=#%8.8ux" ,rem, up?up->text:"", up, ureg, ureg->pc); for(;;); } itype = ureg->type; /* All interrupts/exceptions should be resumed at ureg->pc-4, except for Data Abort which resumes at ureg->pc-8. */ if(itype == PsrMabt+1) ureg->pc -= 8; else ureg->pc -= 4; if(up){ up->pc = ureg->pc; up->dbgreg = ureg; } switch(itype) { case PsrMirq: t = m->ticks; /* CPU time per proc */ up = nil; /* no process at interrupt level */ irq(ureg); up = m->proc; preemption(m->ticks - t); m->intr++; break; case PsrMund: if(*(ulong*)ureg->pc == BREAK && breakhandler) { int s; Proc *p; p = up; s = breakhandler(ureg, p); if(s == BrkSched) { p->preempted = 0; sched(); } else if(s == BrkNoSched) { /* stop it being preempted until next instruction */ p->preempted = 1; if(up) up->dbgreg = 0; return; } break; } if(up == nil) goto faultpanic; spllo(); if(waserror()) { if(waslo(ureg->psr) && up->type == Interp) disfault(ureg, up->env->errstr); setpanic(); dumpregs(ureg); panic("%s", up->env->errstr); } if(!fpiarm(ureg)) { dumpregs(ureg); sys_trap_error(ureg->type); } poperror(); break; case PsrMsvc: /* Jump through 0 or SWI */ if(waslo(ureg->psr) && up && up->type == Interp) { spllo(); dumpregs(ureg); sys_trap_error(ureg->type); } setpanic(); dumpregs(ureg); panic("SVC/SWI exception"); break; case PsrMabt: /* Prefetch abort */ if(catchdbg && catchdbg(ureg, 0)) break; /* FALL THROUGH */ case PsrMabt+1: /* Data abort */ if(waslo(ureg->psr) && up && up->type == Interp) { spllo(); faultarm(ureg); } print("Data Abort\n"); /* FALL THROUGH */ default: faultpanic: setpanic(); dumpregs(ureg); panic("exception %uX %s\n", ureg->type, trapname(ureg->type)); break; } splhi(); if(up) up->dbgreg = 0; /* becomes invalid after return from trap */ }
int main ( ) { /* Create a HWA context to collect the hardware configuration * Preload this context with RESET values */ hwa( begin_from_reset ); /* Have the CPU enter idle mode when the 'sleep' instruction is executed. */ hwa( configure, core0, sleep, enabled, sleep_mode, idle ); /* Configure LED pin */ hwa( configure, PIN_LED, mode, digital_output ); /* Configure analog input pin in analog mode (disable digital input buffer) * and enable the internal pull-up resistor */ hwa( configure, PIN_ANALOG_INPUT, mode, analog_input_pullup ); /* Check that the counter can handle the top value. This must be done * here since the C preprocessor does not allow floats in expressions. */ if ( COUNT_TOP > ((1UL<<HW_BITS(COUNTER))-1) ) HWA_ERR("PWM_COUNTER can not afford PWM_PERIOD.") ; /* Configure the counter prescaler */ hwa( configure, (COUNTER,prescaler), clock, ioclk ); /* Configure the counter to overflow periodically and trigger an interrupt * The counter overflow ISR manages the compare IRQ */ hwa( configure, COUNTER, clock, ioclk / COUNTER_CLK_DIV, direction, up_loop, bottom, 0, top, TOP_OBJ, // overflow, after_top, ); hwa( write, (COUNTER, TOP_OBJ), COUNT_TOP ); hwa( turn, irq(COUNTER,overflow), on ); /* Configure the ADC to make a single conversion and trigger an * IRQ. The ISR will start a new conversion after its hard job is done. */ hwa( configure, adc0, clock, ioclk / ADC_CLK_DIV, trigger, manual, vref, vcc, align, right, input, PIN_ANALOG_INPUT ); hwa( turn, irq(adc0), on ); hwa( trigger, adc0 ); /* Write this configuration into the hardware */ hwa( commit ); hw( enable_interrupts ); for(;;) hw( sleep_until_irq ); return 0 ; }
int CPU::execute_inst(Instruction inst) { //stringstream inststr; //inststr << HEX4(pc) << " " << inst << dump_regs(); //log(inststr.str()); byte t; byte a7, m7, r7; word result; switch(inst.op.op) { case NOP: case DOP: case TOP: break; case JMP: pc = inst.addr; break; case JSR: push2(pc-1); pc = inst.addr; break; case RTS: get_mem(0x100 | s); pc = pop2()+1; get_mem(pc); break; case RTI: get_mem(0x100 | s); p = (pop() | (1<<5)) & (~B); pc = pop2(); if(get_flag(I)) m->scheduled_irq = -1; else if(m->irq_waiting) m->scheduled_irq = 1; break; case BRK: pc += 1; p |= B; irq(); break; case BCS: branch(get_flag(C), inst); break; case BCC: branch(!get_flag(C), inst); break; case BEQ: branch(get_flag(Z), inst); break; case BNE: branch(!get_flag(Z), inst); break; case BVS: branch(get_flag(V), inst); break; case BVC: branch(!get_flag(V), inst); break; case BPL: branch(!get_flag(N), inst); break; case BMI: branch(get_flag(N), inst); break; case BIT: t = inst.operand; set_flag(N, t & (1 << 7)); set_flag(V, t & (1 << 6)); set_flag(Z, (t & a) == 0); break; case CMP: compare(a, inst.operand); break; case CPY: compare(y, inst.operand); break; case CPX: compare(x, inst.operand); break; case CLC: set_flag(C, false); break; case CLD: set_flag(D, false); break; case CLV: set_flag(V, false); break; case CLI: set_flag(I, false); break; case SED: set_flag(D, true); break; case SEC: set_flag(C, true); break; case SEI: set_flag(I, true); break; case LDA: a = inst.operand; set_nz(a); break; case STA: set_mem(inst.addr, a); break; case LDX: x = inst.operand; set_nz(x); break; case STX: set_mem(inst.addr, x); break; case LDY: y = inst.operand; set_nz(y); break; case STY: set_mem(inst.addr, y); break; case LAX: a = inst.operand; x = inst.operand; set_nz(a); break; case SAX: set_mem(inst.addr, a & x); break; case PHP: push(p | B); break; case PLP: get_mem(0x100|s); p = (pop() | (1 << 5)) & (~B); break; case PLA: get_mem(0x100|s); a = pop(); set_nz(a); break; case PHA: push(a); break; case AND: a &= inst.operand; set_nz(a); break; case AAC: a &= inst.operand; set_nz(a); set_flag(C, a & 0x80); break; case ORA: a |= inst.operand; set_nz(a); break; case EOR: a ^= inst.operand; set_nz(a); break; case ADC: a7 = a & (1 << 7); m7 = inst.operand & (1 << 7); result = a + inst.operand; if(get_flag(C)) { result += 1; } a = result & 0xff; set_flag(C, result > 0xff); set_nz(a); r7 = a & (1 << 7); set_flag(V, !((a7 != m7) || ((a7 == m7) && (m7 == r7)))); break; case SBC: a7 = a & (1 << 7); m7 = inst.operand & (1 << 7); result = a - inst.operand; if(!get_flag(C)) { result -= 1; } a = result & 0xff; set_flag(C, result < 0x100); set_nz(a); r7 = a & (1 << 7); set_flag(V, !((a7 == m7) || ((a7 != m7) && (r7 == a7)))); break; case INX: x += 1; set_nz(x); break; case INY: y += 1; set_nz(y); break; case DEX: x -= 1; set_nz(x); break; case DEY: y -= 1; set_nz(y); break; case INC: set_mem(inst.addr, inst.operand); inst.operand += 1; inst.operand &= 0xff; set_nz(inst.operand); set_mem(inst.addr, inst.operand); break; case DEC: set_mem(inst.addr, inst.operand); inst.operand -= 1; inst.operand &= 0xff; set_nz(inst.operand); set_mem(inst.addr, inst.operand); break; case DCP: set_mem(inst.addr, inst.operand); set_mem(inst.addr, (inst.operand -1) & 0xff); compare(a, (inst.operand-1)&0xff); break; case ISB: set_mem(inst.addr, inst.operand); inst.operand = (inst.operand + 1) & 0xff; set_mem(inst.addr, inst.operand); a7 = a & (1 << 7); m7 = inst.operand & (1 << 7); result = a - inst.operand; if(!get_flag(C)) { result -= 1; } a = result & 0xff; set_flag(C, result < 0x100); set_nz(a); r7 = a & (1 << 7); set_flag(V, !((a7 == m7) || ((a7 != m7) && (r7 == a7)))); break; case LSR_A: set_flag(C, a & 1); a >>= 1; set_nz(a); break; case LSR: set_flag(C, inst.operand & 1); set_mem(inst.addr, inst.operand); inst.operand >>= 1; set_mem(inst.addr, inst.operand); set_nz(inst.operand); break; case ASL_A: set_flag(C, a & (1 << 7)); a <<= 1; set_nz(a); break; case ASL: set_flag(C, inst.operand & (1 << 7)); set_mem(inst.addr, inst.operand); inst.operand <<= 1; set_mem(inst.addr, inst.operand); set_nz(inst.operand); break; case ASR: a &= inst.operand; set_flag(C, a & 1); a >>= 1; set_nz(a); break; case ARR: a &= inst.operand; a >>= 1; if(get_flag(C)) a |= 0x80; set_flag(C, a & (1<<6)); set_flag(V, ((a & (1<<5))<<1) ^ (a & (1<<6))); set_nz(a); break; case TSX: x = s; set_nz(x); break; case TXS: s = x; break; case TYA: a = y; set_nz(a); break; case TXA: a = x; set_nz(a); break; case ATX: a |= 0xff; a &= inst.operand; x = a; set_nz(x); break; case AXS: x = a & x; result = x - inst.operand; set_flag(C, result < 0x100); x = result & 0xff; set_nz(x); break; case SYA: t = y & (inst.args[1] + 1); if(!inst.extra_cycles) set_mem(inst.addr, t); else inst.extra_cycles = 0; break; case SXA: t = x & (inst.args[1] + 1); if(!inst.extra_cycles) set_mem(inst.addr, t); else inst.extra_cycles = 0; break; case ROR_A: t = a & 1; a >>= 1; if(get_flag(C)) a |= 1 << 7; set_flag(C, t); set_nz(a); break; case ROR: t = inst.operand & 1; set_mem(inst.addr, inst.operand); inst.operand >>= 1; if(get_flag(C)) inst.operand |= 1 << 7; set_flag(C, t); set_mem(inst.addr, inst.operand); set_nz(inst.operand); break; case ROL_A: t = a & (1 << 7); a <<= 1; if(get_flag(C)) a |= 1; set_flag(C, t); set_nz(a); break; case ROL: t = inst.operand & (1 << 7); set_mem(inst.addr, inst.operand); inst.operand <<= 1; if(get_flag(C)) inst.operand |= 1; set_flag(C, t); set_mem(inst.addr, inst.operand); set_nz(inst.operand); break; case TAY: y = a; set_nz(y); break; case TAX: x = a; set_nz(x); break; case RLA: t = inst.operand & (1 << 7); set_mem(inst.addr, inst.operand); inst.operand <<= 1; if(get_flag(C)) inst.operand |= 1; set_flag(C, t); set_mem(inst.addr, inst.operand); a &= inst.operand; set_nz(a); break; case SLO: set_flag(C, inst.operand & (1 << 7)); set_mem(inst.addr, inst.operand); inst.operand <<= 1; set_mem(inst.addr, inst.operand); a |= inst.operand; set_nz(a); break; case SRE: set_flag(C, inst.operand & 1); set_mem(inst.addr, inst.operand); inst.operand >>= 1; set_mem(inst.addr, inst.operand); a ^= inst.operand; set_nz(a); break; case RRA: t = inst.operand & 1; set_mem(inst.addr, inst.operand); inst.operand >>= 1; if(get_flag(C)) inst.operand |= 1 << 7; set_mem(inst.addr, inst.operand); a7 = a & (1 << 7); m7 = inst.operand & (1 << 7); result = a + inst.operand; if(t) { result += 1; } a = result & 0xff; set_flag(C, result > 0xff); set_nz(a); r7 = a & (1 << 7); set_flag(V, !((a7 != m7) || ((a7 == m7) && (m7 == r7)))); break; case XAA: case AXA: case XAS: case LAR: break; default: cout << "Unsupported opcode! " << int(inst.opcode) << endl; cout << inst.op.op << endl; cout << opnames[inst.op.op] << endl; throw new runtime_error("Unsupported opcode"); break; } int inst_cycles = cycle_count - prev_cycles; prev_cycles = cycle_count; //cycle_count += inst.op.cycles + inst.extra_cycles; return inst_cycles; }
static int __init mcdx_init_drive(int drive) { struct s_version version; struct gendisk *disk; struct s_drive_stuff *stuffp; int size = sizeof(*stuffp); char msg[80]; xtrace(INIT, "init() try drive %d\n", drive); xtrace(INIT, "kmalloc space for stuffpt's\n"); xtrace(MALLOC, "init() malloc %d bytes\n", size); if (!(stuffp = kzalloc(size, GFP_KERNEL))) { xwarn("init() malloc failed\n"); return 1; } disk = alloc_disk(1); if (!disk) { xwarn("init() malloc failed\n"); kfree(stuffp); return 1; } xtrace(INIT, "init() got %d bytes for drive stuff @ %p\n", sizeof(*stuffp), stuffp); /* set default values */ stuffp->present = 0; /* this should be 0 already */ stuffp->toc = NULL; /* this should be NULL already */ /* setup our irq and i/o addresses */ stuffp->irq = irq(mcdx_drive_map[drive]); stuffp->wreg_data = stuffp->rreg_data = port(mcdx_drive_map[drive]); stuffp->wreg_reset = stuffp->rreg_status = stuffp->wreg_data + 1; stuffp->wreg_hcon = stuffp->wreg_reset + 1; stuffp->wreg_chn = stuffp->wreg_hcon + 1; init_waitqueue_head(&stuffp->busyq); init_waitqueue_head(&stuffp->lockq); init_waitqueue_head(&stuffp->sleepq); /* check if i/o addresses are available */ if (!request_region(stuffp->wreg_data, MCDX_IO_SIZE, "mcdx")) { xwarn("0x%03x,%d: Init failed. " "I/O ports (0x%03x..0x%03x) already in use.\n", stuffp->wreg_data, stuffp->irq, stuffp->wreg_data, stuffp->wreg_data + MCDX_IO_SIZE - 1); xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp); kfree(stuffp); put_disk(disk); xtrace(INIT, "init() continue at next drive\n"); return 0; /* next drive */ } xtrace(INIT, "init() i/o port is available at 0x%03x\n" stuffp->wreg_data); xtrace(INIT, "init() hardware reset\n"); mcdx_reset(stuffp, HARD, 1); xtrace(INIT, "init() get version\n"); if (-1 == mcdx_requestversion(stuffp, &version, 4)) { /* failed, next drive */ release_region(stuffp->wreg_data, MCDX_IO_SIZE); xwarn("%s=0x%03x,%d: Init failed. Can't get version.\n", MCDX, stuffp->wreg_data, stuffp->irq); xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp); kfree(stuffp); put_disk(disk); xtrace(INIT, "init() continue at next drive\n"); return 0; } switch (version.code) { case 'D': stuffp->readcmd = READ2X; stuffp->present = DOUBLE | DOOR | MULTI; break; case 'F': stuffp->readcmd = READ1X; stuffp->present = SINGLE | DOOR | MULTI; break; case 'M': stuffp->readcmd = READ1X; stuffp->present = SINGLE; break; default: stuffp->present = 0; break; } stuffp->playcmd = READ1X; if (!stuffp->present) { release_region(stuffp->wreg_data, MCDX_IO_SIZE); xwarn("%s=0x%03x,%d: Init failed. No Mitsumi CD-ROM?.\n", MCDX, stuffp->wreg_data, stuffp->irq); kfree(stuffp); put_disk(disk); return 0; /* next drive */ } xtrace(INIT, "init() register blkdev\n"); if (register_blkdev(MAJOR_NR, "mcdx")) { release_region(stuffp->wreg_data, MCDX_IO_SIZE); kfree(stuffp); put_disk(disk); return 1; } mcdx_queue = blk_init_queue(do_mcdx_request, &mcdx_lock); if (!mcdx_queue) { unregister_blkdev(MAJOR_NR, "mcdx"); release_region(stuffp->wreg_data, MCDX_IO_SIZE); kfree(stuffp); put_disk(disk); return 1; } xtrace(INIT, "init() subscribe irq and i/o\n"); if (request_irq(stuffp->irq, mcdx_intr, IRQF_DISABLED, "mcdx", stuffp)) { release_region(stuffp->wreg_data, MCDX_IO_SIZE); xwarn("%s=0x%03x,%d: Init failed. Can't get irq (%d).\n", MCDX, stuffp->wreg_data, stuffp->irq, stuffp->irq); stuffp->irq = 0; blk_cleanup_queue(mcdx_queue); kfree(stuffp); put_disk(disk); return 0; } xtrace(INIT, "init() get garbage\n"); { int i; mcdx_delay(stuffp, HZ / 2); for (i = 100; i; i--) (void) inb(stuffp->rreg_status); } #ifdef WE_KNOW_WHY /* irq 11 -> channel register */ outb(0x50, stuffp->wreg_chn); #endif xtrace(INIT, "init() set non dma but irq mode\n"); mcdx_config(stuffp, 1); stuffp->info.ops = &mcdx_dops; stuffp->info.speed = 2; stuffp->info.capacity = 1; stuffp->info.handle = stuffp; sprintf(stuffp->info.name, "mcdx%d", drive); disk->major = MAJOR_NR; disk->first_minor = drive; strcpy(disk->disk_name, stuffp->info.name); disk->fops = &mcdx_bdops; disk->flags = GENHD_FL_CD; stuffp->disk = disk; sprintf(msg, " mcdx: Mitsumi CD-ROM installed at 0x%03x, irq %d." " (Firmware version %c %x)\n", stuffp->wreg_data, stuffp->irq, version.code, version.ver); mcdx_stuffp[drive] = stuffp; xtrace(INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp); if (register_cdrom(&stuffp->info) != 0) { printk("Cannot register Mitsumi CD-ROM!\n"); free_irq(stuffp->irq, NULL); release_region(stuffp->wreg_data, MCDX_IO_SIZE); kfree(stuffp); put_disk(disk); if (unregister_blkdev(MAJOR_NR, "mcdx") != 0) xwarn("cleanup() unregister_blkdev() failed\n"); blk_cleanup_queue(mcdx_queue); return 2; } disk->private_data = stuffp; disk->queue = mcdx_queue; add_disk(disk); printk(msg); return 0; }
void timer_poll() { irq(TIMER_IRQ); }
u32 sdidCheckSDSpeed( u32 readCount ) { CIniFile ini( SFN_SDCARD_LIST ); std::string name = sdidGetSDName(); std::string manufacturerID = sdidGetSDManufacturerID(); u32 ret = ini.GetInt( "SD Card Speed", manufacturerID + name, 0 ); if( ret != 0 ) return ret; u32 totalSectors; if(!ELM_SectorsFromDisk(ioSD(),&totalSectors)) { dbg_printf("no sd card\n"); return 0; } dbg_printf("total sectors %d, max addr %08x\n", totalSectors, (totalSectors << 9) - 0x200); // some sd card needs to be readed one time for initialization sddReadBlocks( 0, 1, NULL ); irq().vblankStop(); double maxAccessTime = 0.f; std::string tipText = LANG("progress window", "first use sd"); progressWnd().setTipText( tipText ); progressWnd().show(); progressWnd().setPercent( 0 ); vu64 tick1 = 0; vu64 tick2 = 0; for( size_t i = 0; i < readCount; ++i ) { u32 randAddr = ((rand() % totalSectors)<<(isSDHC()?0:9) ) & (~(0x200-1)); u32 sdReadSingleBlock[2] = { 0xD5030011, randAddr }; // input read address here ioRpgSendCommand( sdReadSingleBlock, 0, 80, NULL ); timer().initTimer(); tick1 = timer().getTick(); ioRpgWaitCmdBusy( true ); tick2 = timer().getTick(); u32 readSD[2] = { 0xB7000000, 0x00000000 | 0x00130000 }; // address dont care here ioRpgSendCommand( readSD, 512, 4, NULL ); if( tick2 < tick1 ) { tick2 += 65536; } tick1 = tick2 - tick1; double timeCostUs = timer().tickToUs( tick1 ); if( timeCostUs > maxAccessTime ) { maxAccessTime = timeCostUs; } u32 percent = i * 100 / readCount; if( (i & 0x1ff) == 0x1ff ) { dbg_printf( "%02d ", percent ); progressWnd().setPercent( percent ); } } progressWnd().hide(); irq().vblankStart(); maxAccessTime = ((u32)(maxAccessTime / 15 + 0.5)) * 15; ret = ((u32)(maxAccessTime * 1000 / 150)); dbg_printf("max access time: max %4.2fus\n", maxAccessTime ); ini.SetInt( "SD Card Speed", manufacturerID + name, ret ); ini.SaveIniFile( SFN_SDCARD_LIST ); return ret; }