AlphaCPU.h

Go to the documentation of this file.
00001 /* ES40 emulator.
00002  * Copyright (C) 2007-2008 by the ES40 Emulator Project
00003  *
00004  * WWW    : http://sourceforge.net/projects/es40
00005  * E-mail : camiel@camicom.com
00006  * 
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  * 
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  * 
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
00020  * USA.
00021  * 
00022  * Although this is not required, the author would appreciate being notified 
00023  * of, and receiving any modifications you may make to the source code that 
00024  * might serve the general public.
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 // Size of Instruction Cache entries in DWORDS (instructions)
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();    // Poco Thread entry point
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     /* Floating Point routines */
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     /* VMS PALcode call: */
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     /* VMS PALcode entry: */
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     /* VMS PALcode internal: */
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     //  memset(state.icache,0,sizeof(state.icache));
00552     int i;
00553     for(i = 0; i < ICACHE_ENTRIES; i++)
00554     {
00555       state.icache[i].valid = false;
00556 
00557       //    state.icache[i].asm_bit = true;
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   // icache disabled
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; // virtual
00875   u64   p_prbr; // physical
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;  // virtual
00895   u64   p_pcb;  // physical
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)

SourceForge.net Logo
Project space on SourceForge.net