00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00211 #if !defined(INCLUDED_ALPHACPU_H)
00212 #define INCLUDED_ALPHACPU_H
00213
00214 #include "SystemComponent.h"
00215 #include "System.h"
00216 #include "cpu_defs.h"
00217
00219 #define ICACHE_ENTRIES 1024
00220
00221 #define ICACHE_LINE_SIZE 512
00222
00224 #define ICACHE_MATCH_MASK (u64) (U64(0x1) - (ICACHE_LINE_SIZE * 4))
00226 #define ICACHE_INDEX_MASK (u64) (ICACHE_LINE_SIZE - U64(0x1))
00228 #define ICACHE_BYTE_MASK (u64) (ICACHE_INDEX_MASK << 2)
00230 #define TB_ENTRIES 16
00231
00243 class CAlphaCPU : public CSystemComponent, public Poco::Runnable
00244 {
00245 public:
00246 void flush_icache_asm();
00247 virtual int SaveState(FILE* f);
00248 virtual int RestoreState(FILE* f);
00249 void irq_h(int number, bool assert, int delay);
00250 int get_cpuid();
00251 void flush_icache();
00252
00253 virtual void run();
00254 void execute();
00255 void release_threads();
00256
00257 void set_PAL_BASE(u64 pb);
00258 virtual void check_state();
00259 CAlphaCPU(CConfigurator* cfg, CSystem* system);
00260 virtual ~CAlphaCPU();
00261 u64 get_r(int i, bool translate);
00262 u64 get_f(int i);
00263 void set_r(int reg, u64 val);
00264 void set_f(int reg, u64 val);
00265 u64 get_prbr(void);
00266 u64 get_hwpcb(void);
00267 u64 get_pc();
00268 u64 get_pal_base();
00269
00270 void enable_icache();
00271 void restore_icache();
00272
00273 #ifdef IDB
00274 u64 get_current_pc_physical();
00275 u64 get_instruction_count();
00276 u32 get_last_instruction();
00277 #endif
00278 u64 get_clean_pc();
00279 void next_pc();
00280 void set_pc(u64 p_pc);
00281 void add_pc(u64 a_pc);
00282
00283 u64 get_speed() { return cpu_hz; };
00284
00285 u64 va_form(u64 address, bool bIBOX);
00286
00287 #if defined(IDB)
00288 void listing(u64 from, u64 to);
00289 void listing(u64 from, u64 to, u64 mark);
00290 #endif
00291 int virt2phys(u64 virt, u64* phys, int flags, bool* asm_bit,
00292 u32 instruction);
00293
00294 virtual void init();
00295 virtual void start_threads();
00296 virtual void stop_threads();
00297 private:
00298 Poco::Thread * myThread;
00299 Poco::Semaphore mySemaphore;
00300 bool StopThread;
00301
00302 int get_icache(u64 address, u32* data);
00303 int FindTBEntry(u64 virt, int flags);
00304 void add_tb(u64 virt, u64 pte_phys, u64 pte_flags, int flags);
00305 void add_tb_i(u64 virt, u64 pte);
00306 void add_tb_d(u64 virt, u64 pte);
00307 void tbia(int flags);
00308 void tbiap(int flags);
00309 void tbis(u64 virt, int flags);
00310
00311
00312 u64 ieee_lds(u32 op);
00313 u32 ieee_sts(u64 op);
00314 u64 ieee_cvtst(u64 op, u32 ins);
00315 u64 ieee_cvtts(u64 op, u32 ins);
00316 s32 ieee_fcmp(u64 s1, u64 s2, u32 ins, u32 trap_nan);
00317 u64 ieee_cvtif(u64 val, u32 ins, u32 dp);
00318 u64 ieee_cvtfi(u64 op, u32 ins);
00319 u64 ieee_fadd(u64 s1, u64 s2, u32 ins, u32 dp, bool sub);
00320 u64 ieee_fmul(u64 s1, u64 s2, u32 ins, u32 dp);
00321 u64 ieee_fdiv(u64 s1, u64 s2, u32 ins, u32 dp);
00322 u64 ieee_sqrt(u64 op, u32 ins, u32 dp);
00323 int ieee_unpack(u64 op, UFP* r, u32 ins);
00324 void ieee_norm(UFP* r);
00325 u64 ieee_rpack(UFP* r, u32 ins, u32 dp);
00326 void ieee_trap(u64 trap, u32 instenb, u64 fpcrdsb, u32 ins);
00327 u64 vax_ldf(u32 op);
00328 u64 vax_ldg(u64 op);
00329 u32 vax_stf(u64 op);
00330 u64 vax_stg(u64 op);
00331 void vax_trap(u64 mask, u32 ins);
00332 void vax_unpack(u64 op, UFP* r, u32 ins);
00333 void vax_unpack_d(u64 op, UFP* r, u32 ins);
00334 void vax_norm(UFP* r);
00335 u64 vax_rpack(UFP* r, u32 ins, u32 dp);
00336 u64 vax_rpack_d(UFP* r, u32 ins);
00337 int vax_fcmp(u64 s1, u64 s2, u32 ins);
00338 u64 vax_cvtif(u64 val, u32 ins, u32 dp);
00339 u64 vax_cvtfi(u64 op, u32 ins);
00340 u64 vax_fadd(u64 s1, u64 s2, u32 ins, u32 dp, bool sub);
00341 u64 vax_fmul(u64 s1, u64 s2, u32 ins, u32 dp);
00342 u64 vax_fdiv(u64 s1, u64 s2, u32 ins, u32 dp);
00343 u64 vax_sqrt(u64 op, u32 ins, u32 dp);
00344
00345
00346 void vmspal_call_cflush();
00347 void vmspal_call_draina();
00348 void vmspal_call_ldqp();
00349 void vmspal_call_stqp();
00350 void vmspal_call_swpctx();
00351 void vmspal_call_mfpr_asn();
00352 void vmspal_call_mtpr_asten();
00353 void vmspal_call_mtpr_astsr();
00354 void vmspal_call_cserve();
00355 void vmspal_call_mfpr_fen();
00356 void vmspal_call_mtpr_fen();
00357 void vmspal_call_mfpr_ipl();
00358 void vmspal_call_mtpr_ipl();
00359 void vmspal_call_mfpr_mces();
00360 void vmspal_call_mtpr_mces();
00361 void vmspal_call_mfpr_pcbb();
00362 void vmspal_call_mfpr_prbr();
00363 void vmspal_call_mtpr_prbr();
00364 void vmspal_call_mfpr_ptbr();
00365 void vmspal_call_mfpr_scbb();
00366 void vmspal_call_mtpr_scbb();
00367 void vmspal_call_mtpr_sirr();
00368 void vmspal_call_mfpr_sisr();
00369 void vmspal_call_mfpr_tbchk();
00370 void vmspal_call_mtpr_tbia();
00371 void vmspal_call_mtpr_tbiap();
00372 void vmspal_call_mtpr_tbis();
00373 void vmspal_call_mfpr_esp();
00374 void vmspal_call_mtpr_esp();
00375 void vmspal_call_mfpr_ssp();
00376 void vmspal_call_mtpr_ssp();
00377 void vmspal_call_mfpr_usp();
00378 void vmspal_call_mtpr_usp();
00379 void vmspal_call_mtpr_tbisd();
00380 void vmspal_call_mtpr_tbisi();
00381 void vmspal_call_mfpr_asten();
00382 void vmspal_call_mfpr_astsr();
00383 void vmspal_call_mfpr_vptb();
00384 void vmspal_call_mtpr_datfx();
00385 void vmspal_call_mfpr_whami();
00386 void vmspal_call_imb();
00387 void vmspal_call_prober();
00388 void vmspal_call_probew();
00389 void vmspal_call_rd_ps();
00390 int vmspal_call_rei();
00391 void vmspal_call_swasten();
00392 void vmspal_call_wr_ps_sw();
00393 void vmspal_call_rscc();
00394 void vmspal_call_read_unq();
00395 void vmspal_call_write_unq();
00396
00397
00398 int vmspal_ent_dtbm_double_3(int flags);
00399 int vmspal_ent_dtbm_single(int flags);
00400 int vmspal_ent_itbm(int flags);
00401 int vmspal_ent_iacv(int flags);
00402 int vmspal_ent_dfault(int flags);
00403 int vmspal_ent_ext_int(int ei);
00404 int vmspal_ent_sw_int(int si);
00405 int vmspal_ent_ast_int(int ast);
00406
00407
00408 int vmspal_int_initiate_exception();
00409 int vmspal_int_initiate_interrupt();
00410
00411 bool icache_enabled;
00412
00413
00414 u64 cc_large;
00415 u64 start_icount;
00416 u64 start_cc;
00417 Poco::Timestamp start_time;
00418 u64 prev_icount;
00419 u64 prev_cc;
00420 u64 prev_time;
00421 u64 cc_per_instruction;
00422 u64 ins_per_timer_int;
00423 u64 next_timer_int;
00424 u64 cpu_hz;
00425
00427 struct SCPU_state
00428 {
00429 u64 pal_base;
00430 u64 pc;
00431 u64 cc;
00432 u64 r[64];
00433 u64 dc_stat;
00434 bool ppcen;
00435 u64 i_stat;
00436 u64 pctr_ctl;
00437 bool cc_ena;
00438 u32 cc_offset;
00439 u64 dc_ctl;
00440 int alt_cm;
00441 int smc;
00442 bool fpen;
00443 bool sde;
00444 u64 fault_va;
00445 u64 exc_sum;
00446 int i_ctl_va_mode;
00447 int va_ctl_va_mode;
00448 u64 i_ctl_vptb;
00449 u64 va_ctl_vptb;
00450 int cm;
00451 int asn;
00452 int asn0;
00453 int asn1;
00454 int eien;
00455 int slen;
00456 int cren;
00457 int pcen;
00458 int sien;
00459 int asten;
00460 int sir;
00461 int eir;
00462 int slr;
00463 int crr;
00464 int pcr;
00465 int astrr;
00466 int aster;
00467 u64 i_ctl_other;
00468 u64 mm_stat;
00469 bool hwe;
00470 int m_ctl_spe;
00471 int i_ctl_spe;
00472 u64 exc_addr;
00473 u64 pmpc;
00474 u64 fpcr;
00475 bool bIntrFlag;
00476 u64 current_pc;
00484 struct SICache
00485 {
00486 int asn;
00487 u32 data[ICACHE_LINE_SIZE];
00488 u64 address;
00489 u64 p_address;
00490 bool asm_bit;
00491 bool valid;
00492 } icache[ICACHE_ENTRIES];
00493 int next_icache;
00494 int last_found_icache;
00501 struct STBEntry
00502 {
00503 u64 virt;
00504 u64 phys;
00505 u64 match_mask;
00506 u64 keep_mask;
00507 int asn;
00508 int asm_bit;
00509 int access[2][4];
00510 int fault[3];
00511 bool valid;
00512 } tb[2][TB_ENTRIES];
00514 int next_tb[2];
00515 int last_found_tb[2][2];
00516 u32 rem_ins_in_page;
00517 u64 pc_phys;
00518 u64 f[64];
00519 int iProcNum;
00520 u64 instruction_count;
00521 u64 last_tb_virt;
00522 bool pal_vms;
00523 bool check_int;
00524 int irq_h_timer[6];
00525 bool check_timers;
00526 } state;
00528 #ifdef IDB
00529 u64 current_pc_physical;
00530 u32 last_instruction;
00531 #endif
00532 };
00533
00537 #define RREG(a) \
00538 ( \
00539 ((a) & 0x1f) + \
00540 (((state.pc & 1) && (((a) & 0xc) == 0x4) && state.sde) ? 32 : 0) \
00541 )
00542
00546 inline void CAlphaCPU::flush_icache()
00547 {
00548 if(icache_enabled)
00549 {
00550
00551
00552 int i;
00553 for(i = 0; i < ICACHE_ENTRIES; i++)
00554 {
00555 state.icache[i].valid = false;
00556
00557
00558 }
00559
00560 state.next_icache = 0;
00561 state.last_found_icache = 0;
00562 }
00563 }
00564
00568 inline void CAlphaCPU::flush_icache_asm()
00569 {
00570 if(icache_enabled)
00571 {
00572 int i;
00573 for(i = 0; i < ICACHE_ENTRIES; i++)
00574 if(!state.icache[i].asm_bit)
00575 state.icache[i].valid = false;
00576 }
00577 }
00578
00582 inline void CAlphaCPU::set_PAL_BASE(u64 pb)
00583 {
00584 state.pal_base = pb;
00585 state.pal_vms = (pb == U64(0x8000));
00586 }
00587
00608 inline int CAlphaCPU::get_icache(u64 address, u32* data)
00609 {
00610 int i = state.last_found_icache;
00611 u64 v_a;
00612 u64 p_a;
00613 int result;
00614 bool asm_bit;
00615
00616 if(icache_enabled)
00617 {
00618 if(state.icache[i].valid
00619 && (state.icache[i].asn == state.asn || state.icache[i].asm_bit)
00620 && state.icache[i].address == (address & ICACHE_MATCH_MASK))
00621 {
00622 *data = endian_32(state.icache[i].data[(address >> 2) & ICACHE_INDEX_MASK]);
00623 #ifdef IDB
00624 current_pc_physical = state.icache[i].p_address + (address & ICACHE_BYTE_MASK);
00625 #endif
00626 return 0;
00627 }
00628
00629 for(i = 0; i < ICACHE_ENTRIES; i++)
00630 {
00631 if(state.icache[i].valid
00632 && (state.icache[i].asn == state.asn || state.icache[i].asm_bit)
00633 && state.icache[i].address == (address & ICACHE_MATCH_MASK))
00634 {
00635 state.last_found_icache = i;
00636 *data = endian_32(state.icache[i].data[(address >> 2) & ICACHE_INDEX_MASK]);
00637
00638 #ifdef IDB
00639 current_pc_physical = state.icache[i].p_address + (address & ICACHE_BYTE_MASK);
00640 #endif
00641 return 0;
00642 }
00643 }
00644
00645 v_a = address & ICACHE_MATCH_MASK;
00646
00647 if(address & 1)
00648 {
00649 p_a = v_a &~U64(0x1);
00650 asm_bit = true;
00651 }
00652 else
00653 {
00654 result = virt2phys(v_a, &p_a, ACCESS_EXEC, &asm_bit, 0);
00655 if(result)
00656 return result;
00657 }
00658
00659 memcpy(state.icache[state.next_icache].data, cSystem->PtrToMem(p_a),
00660 ICACHE_LINE_SIZE * 4);
00661
00662 state.icache[state.next_icache].valid = true;
00663 state.icache[state.next_icache].asn = state.asn;
00664 state.icache[state.next_icache].asm_bit = asm_bit;
00665 state.icache[state.next_icache].address = address & ICACHE_MATCH_MASK;
00666 state.icache[state.next_icache].p_address = p_a;
00667
00668 *data = endian_32(state.icache[state.next_icache].data[(address >> 2) & ICACHE_INDEX_MASK]);
00669
00670 #ifdef IDB
00671 current_pc_physical = state.icache[state.next_icache].p_address + (address & ICACHE_BYTE_MASK);
00672 #endif
00673 state.last_found_icache = state.next_icache;
00674 state.next_icache++;
00675 if(state.next_icache == ICACHE_ENTRIES)
00676 state.next_icache = 0;
00677 return 0;
00678 }
00679
00680
00681 if(address & 1)
00682 {
00683 state.pc_phys = address &~U64(0x3);
00684 state.rem_ins_in_page = 1;
00685 }
00686 else
00687 {
00688 if(!state.rem_ins_in_page)
00689 {
00690 result = virt2phys(address, &state.pc_phys, ACCESS_EXEC, &asm_bit, 0);
00691 if(result)
00692 return result;
00693 state.rem_ins_in_page = 2048 - ((((u32) address) >> 2) & 2047);
00694 }
00695 }
00696
00697 *data = (u32) cSystem->ReadMem(state.pc_phys, 32, this);
00698 return 0;
00699 }
00700
00705 inline u64 CAlphaCPU::va_form(u64 address, bool bIBOX)
00706 {
00707 switch(bIBOX ? state.i_ctl_va_mode : state.va_ctl_va_mode)
00708 {
00709 case 0:
00710 return((bIBOX ? state.i_ctl_vptb : state.va_ctl_vptb) & U64(0xfffffffe00000000)) | ((address >> 10) & U64(0x00000001fffffff8));
00711
00712 case 1:
00713 return
00714 ((bIBOX ? state.i_ctl_vptb : state.va_ctl_vptb) & U64(0xfffff80000000000)) | ((address >> 10) & U64(0x0000003ffffffff8)) |
00715 (((address >> 10) & U64(0x0000002000000000)) * U64(0x3e));
00716
00717 case 2:
00718 return((bIBOX ? state.i_ctl_vptb : state.va_ctl_vptb) & U64(0xffffffffc0000000)) | ((address >> 10) & U64(0x00000000003ffff8));
00719 }
00720
00721 return 0;
00722 }
00723
00727 inline int CAlphaCPU::get_cpuid()
00728 {
00729 return state.iProcNum;
00730 }
00731
00735 inline void CAlphaCPU::irq_h(int number, bool assert, int delay)
00736 {
00737 bool active = (state.eir & (U64(0x1) << number))
00738 || state.irq_h_timer[number];
00739 if(assert && !active)
00740 {
00741 if(delay)
00742 {
00743 state.irq_h_timer[number] = delay;
00744 state.check_timers = true;
00745 }
00746 else
00747 {
00748 state.eir |= (U64(0x1) << number);
00749 state.check_int = true;
00750 }
00751
00752 return;
00753 }
00754
00755 if(!assert && active)
00756 {
00757 state.eir &= ~(U64(0x1) << number);
00758 state.irq_h_timer[number] = 0;
00759 state.check_timers = false;
00760 for(int i = 0; i < 6; i++)
00761 {
00762 if(state.irq_h_timer[i])
00763 state.check_timers = true;
00764 }
00765 }
00766 }
00767
00771 inline u64 CAlphaCPU::get_pc()
00772 {
00773 return state.pc;
00774 }
00775
00776 #ifdef IDB
00777
00781 inline u64 CAlphaCPU::get_current_pc_physical()
00782 {
00783 return state.pc_phys;
00784 }
00785 #endif
00786
00790 inline u64 CAlphaCPU::get_clean_pc()
00791 {
00792 return state.pc &~U64(0x3);
00793 }
00794
00798 inline void CAlphaCPU::next_pc()
00799 {
00800 state.pc += 4;
00801 state.pc_phys += 4;
00802 if(state.rem_ins_in_page)
00803 state.rem_ins_in_page--;
00804 }
00805
00809 inline void CAlphaCPU::set_pc(u64 p_pc)
00810 {
00811 state.pc = p_pc;
00812 state.rem_ins_in_page = 0;
00813 }
00814
00818 inline void CAlphaCPU::add_pc(u64 a_pc)
00819 {
00820 state.pc += a_pc;
00821 state.rem_ins_in_page = 0;
00822 }
00823
00828 inline u64 CAlphaCPU::get_r(int i, bool translate)
00829 {
00830 if(translate)
00831 return state.r[RREG(i)];
00832 else
00833 return state.r[i];
00834 }
00835
00839 inline u64 CAlphaCPU::get_f(int i)
00840 {
00841 return state.f[i];
00842 }
00843
00847 inline void CAlphaCPU::set_r(int reg, u64 value)
00848 {
00849 state.r[reg] = value;
00850 }
00851
00855 inline void CAlphaCPU::set_f(int reg, u64 value)
00856 {
00857 state.f[reg] = value;
00858 }
00859
00863 inline u64 CAlphaCPU::get_pal_base()
00864 {
00865 return state.pal_base;
00866 }
00867
00872 inline u64 CAlphaCPU::get_prbr(void)
00873 {
00874 u64 v_prbr;
00875 u64 p_prbr;
00876 bool b;
00877 if(state.r[21 + 32] && ((u64) (state.r[21 + 32] + 0xaf) < (u64)
00878 ((U64(0x1) << cSystem->get_memory_bits()))))
00879 v_prbr = cSystem->ReadMem(state.r[21 + 32] + 0xa8, 64, this);
00880 else
00881 v_prbr = cSystem->ReadMem(0x70a8 + (0x200 * get_cpuid()), 64, this);
00882 if(virt2phys(v_prbr, &p_prbr, ACCESS_READ | FAKE | NO_CHECK, &b, 0))
00883 p_prbr = v_prbr;
00884 if((u64) p_prbr > (u64) (U64(0x1) << cSystem->get_memory_bits()))
00885 p_prbr = 0;
00886 return p_prbr;
00887 }
00888
00892 inline u64 CAlphaCPU::get_hwpcb(void)
00893 {
00894 u64 v_pcb;
00895 u64 p_pcb;
00896 bool b;
00897 if(state.r[21 + 32] && ((u64) (state.r[21 + 32] + 0x17) < (u64)
00898 ((U64(0x1) << cSystem->get_memory_bits()))))
00899 v_pcb = cSystem->ReadMem(state.r[21 + 32] + 0x10, 64, this);
00900 else
00901 v_pcb = cSystem->ReadMem(0x7010 + (0x200 * get_cpuid()), 64, this);
00902 if(virt2phys(v_pcb, &p_pcb, ACCESS_READ | NO_CHECK | FAKE, &b, 0))
00903 p_pcb = v_pcb;
00904 if(p_pcb > (u64) (U64(0x1) << cSystem->get_memory_bits()))
00905 p_pcb = 0;
00906 return p_pcb;
00907 }
00908
00909 #if defined(IDB)
00910
00913 inline u32 CAlphaCPU::get_last_instruction(void)
00914 {
00915 return last_instruction;
00916 }
00917 #endif
00918 extern bool bTB_Debug;
00919 #endif // !defined(INCLUDED_ALPHACPU_H)