1 // ======================================================================== // 2 // LOCUTUS -- aka. LTO Flash! // 3 // // 4 // This class models Locutus, and serves as a structured container for // 5 // a Locutus compatible cartridge. This may be initialized by or // 6 // serialized to a LUIGI file. // 7 // // 8 // Note: This is not tightly integrated into jzIntv at all. Rather, // 9 // some adaptor C code will bridge between this C++ and jzIntv. // 10 // // 11 // Terms: // 12 // -- byte: 8 bits // 13 // -- word: 16 bits // 14 // -- para: 256 words (para is short for "paragraph") // 15 // -- page: 4K words (16 para) // 16 // -- chap: A group of pages that map to the same 4K address span // 17 // // 18 // ======================================================================== // 19 #ifndef LOCUTUS_HPP_ 20 #define LOCUTUS_HPP_ 21 22 #include "locutus_types.hpp" 23 #include "crc_calc.hpp" 24 #include <algorithm> 25 #include <iterator> 26 #include <string> 27 28 static const int LOCUTUS_FEAT_JLP_ACCEL = 0; 29 static const int LOCUTUS_FEAT_JLP_SAVEGAME = 1; 30 31 class t_cpu_cache_if // interface back to the CPU decode cache 32 { 33 public: 34 virtual void invalidate( uint16_t addr_lo, uint16_t addr_hi ) = 0; 35 virtual ~t_cpu_cache_if(); 36 }; 37 38 static const uint32_t LOCUTUS_CAPACITY = 512 * 1024; 39 40 class t_locutus 41 { 42 private: 43 uint16_t ram [512 * 1024]; 44 uint16_t mem_map [256][2]; // bits 10:0 form bits 18:8 of addr 45 t_perm mem_perm[256][2]; 46 uint16_t pfl_map [16][16]; // bits 6:0 form bits 18:12 of addr 47 t_perm pfl_perm[16][16]; 48 uint8_t bsel [16]; // Bank-select table (used by JLP only) 49 uint64_t uid; 50 51 t_cpu_cache_if* cpu_cache; 52 t_metadata metadata; 53 54 std::bitset<128> feature_flag; 55 std::bitset<LOCUTUS_CAPACITY> initialized; 56 57 std::string jlp_savegame; // JLP savegame filename 58 std::vector<uint8_t> jlp_sg_img; // JLP flash image 59 uint32_t jlp_sg_bytes; 60 uint16_t jlp_sg_start; 61 uint16_t jlp_sg_end; 62 uint16_t jlp_sg_addr; 63 uint16_t jlp_sg_row; 64 FILE* jlp_sg_file; 65 66 crc::jlp16 jlp_crc16; 67 uint16_t jlp_regs[16]; 68 uint16_t *jlp_xregs; 69 70 mutable uint16_t jlp_sleep; 71 mutable crc::zip jlp_rand; 72 73 // These are set only if we try to load a scrambled LUIGI. 74 uint8_t druid[16]; // Scrambler DRUID 75 bool is_scrambled; 76 77 void do_banksw_write ( uint16_t addr, uint16_t data ); 78 void do_pageflip_write( uint16_t addr, uint16_t data ); 79 validate_addr(const char * loc,const uint32_t addr) const80 void validate_addr( const char* loc, const uint32_t addr ) const 81 { 82 if ( addr > LOCUTUS_CAPACITY ) 83 throw loc + std::string(": Address out of range"); 84 } 85 86 // -------------------------------------------------------------------- // 87 // Internal JLP Acceleration and JLP Flash support // 88 // -------------------------------------------------------------------- // 89 uint16_t do_jlp_accel_read ( const uint16_t addr ) const; 90 void do_jlp_accel_write( const uint16_t addr, const uint16_t data ); 91 92 bool jlp_sg_validate_args( const bool chk_addr = true ) const; 93 void jlp_sg_ram_to_flash( void ); 94 void jlp_sg_flash_to_ram( void ); 95 void jlp_sg_erase_sector( void ); 96 97 void flip_jlp_accel( const bool new_jlp_accel_on ); 98 next_rand(void) const99 inline uint32_t next_rand( void ) const 100 { 101 jlp_rand.update( 0x4A5A6A7A, 32 ); 102 return jlp_rand.get(); 103 } 104 105 public: 106 107 t_locutus(); 108 109 // -------------------------------------------------------------------- // 110 // INTV-facing interface // 111 // -------------------------------------------------------------------- // 112 uint16_t intv_read ( const uint16_t addr, const bool force = false ) const; 113 void intv_write( const uint16_t addr, const uint16_t data ); 114 void intv_reset( void ); 115 set_cpu_cache(t_cpu_cache_if * cpu_cache_)116 inline void set_cpu_cache ( t_cpu_cache_if* cpu_cache_ ) 117 { 118 cpu_cache = cpu_cache_; 119 } 120 set_xregs(uint16_t * x)121 inline void set_xregs( uint16_t *x ) 122 { 123 jlp_xregs = x; 124 } 125 126 // -------------------------------------------------------------------- // 127 // JLP Acceleration and JLP Flash support interface // 128 // -------------------------------------------------------------------- // 129 void init_jlp_flash( const char* jlp_savegame_ ); 130 131 // -------------------------------------------------------------------- // 132 // General purpose interface // 133 // // 134 // For mem_map, mem_perm, the "reset" argument selects between the // 135 // currently active values (reset = false) or the values that will be // 136 // loaded at reset (reset = true). // 137 // -------------------------------------------------------------------- // read(const uint32_t addr) const138 inline uint16_t read( const uint32_t addr ) const 139 { 140 validate_addr( "t_locutus::read", addr ); 141 return ram[addr]; 142 } 143 write(const uint32_t addr,const uint16_t data)144 inline void write( const uint32_t addr, const uint16_t data ) 145 { 146 validate_addr( "t_locutus::write", addr ); 147 ram[addr] = data; 148 initialized[addr] = true; 149 } 150 get_mem_map(const uint8_t para,const bool reset) const151 inline uint16_t get_mem_map ( const uint8_t para, const bool reset ) const 152 { 153 return mem_map[para][reset]; 154 } 155 set_mem_map(const uint8_t para,const bool reset,const uint16_t mapping)156 inline void set_mem_map ( const uint8_t para, const bool reset, 157 const uint16_t mapping ) 158 { 159 mem_map[para][reset] = mapping & 0x07FF; 160 } 161 get_mem_perm(const uint8_t para,const bool reset) const162 inline t_perm get_mem_perm( const uint8_t para, const bool reset ) const 163 { 164 return mem_perm[para][reset]; 165 } 166 set_mem_perm(const uint8_t para,const bool reset,const t_perm perm)167 inline void set_mem_perm( const uint8_t para, const bool reset, 168 const t_perm perm ) 169 { 170 mem_perm[para][reset] = perm; 171 } 172 get_pageflip_map(const uint8_t chap,const uint8_t page) const173 inline uint16_t get_pageflip_map ( const uint8_t chap, 174 const uint8_t page ) const 175 { 176 return pfl_map[chap][page]; 177 } 178 get_pageflip_perm(const uint8_t chap,const uint8_t page) const179 inline t_perm get_pageflip_perm( const uint8_t chap, 180 const uint8_t page ) const 181 { 182 return pfl_perm[chap][page]; 183 } 184 set_pageflip_map(const uint8_t chap,const uint8_t page,const uint16_t map)185 inline void set_pageflip_map ( const uint8_t chap, 186 const uint8_t page, 187 const uint16_t map ) 188 { 189 pfl_map[chap][page] = map & 0x007F; 190 } 191 set_pageflip_perm(const uint8_t chap,const uint8_t page,const t_perm perm)192 inline void set_pageflip_perm( const uint8_t chap, 193 const uint8_t page, 194 const t_perm perm ) 195 { 196 pfl_perm[chap][page] = perm; 197 } 198 set_pageflip(const uint8_t chap,const uint8_t page,const uint16_t map,const t_perm perm)199 inline void set_pageflip ( const uint8_t chap, 200 const uint8_t page, 201 const uint16_t map, 202 const t_perm perm ) 203 { 204 set_pageflip_map ( chap, page, map ); 205 set_pageflip_perm( chap, page, perm ); 206 } 207 get_initialized(const uint32_t addr) const208 inline bool get_initialized ( const uint32_t addr ) const 209 { 210 validate_addr( "t_locutus::get_initialized", addr ); 211 return initialized[ addr ]; 212 } 213 set_initialized(const uint32_t addr,const bool ini)214 inline void set_initialized ( const uint32_t addr, const bool ini ) 215 { 216 validate_addr( "t_locutus::set_initialized", addr ); 217 initialized[ addr ] = ini; 218 } 219 get_feature_flag(const int feat) const220 inline bool get_feature_flag( const int feat ) const 221 { 222 return feat < 128 ? feature_flag[feat] : false; 223 } 224 set_feature_flag(const int feat,const bool value)225 inline void set_feature_flag( const int feat, const bool value ) 226 { 227 if ( feat < 128 ) feature_flag[feat] = value; 228 } 229 set_uid(const uint64_t uid_)230 inline void set_uid( const uint64_t uid_ ) 231 { 232 uid = uid_; 233 } 234 get_uid(void) const235 inline uint64_t get_uid( void ) const 236 { 237 return uid; 238 } 239 240 t_addr_list get_initialized_span_list( void ) const; 241 get_metadata(void)242 t_metadata& get_metadata( void ) { return metadata; } get_metadata(void) const243 const t_metadata& get_metadata( void ) const { return metadata; } 244 set_metadata(const t_metadata & m)245 void set_metadata( const t_metadata& m ) 246 { 247 metadata = m; 248 } 249 was_scrambled() const250 bool was_scrambled() const 251 { 252 return is_scrambled; 253 } 254 get_scramble_druid() const255 const uint8_t* get_scramble_druid() const 256 { 257 return is_scrambled ? druid : nullptr; 258 } 259 260 // -------------------------------------------------------------------- // 261 // Higher level feature-flag interface // 262 // -------------------------------------------------------------------- // 263 void set_compat_ecs( const compat_level_t ecs_compat ); 264 compat_level_t get_compat_ecs( void ) const; 265 266 void set_compat_voice( const compat_level_t voice_compat ); 267 compat_level_t get_compat_voice( void ) const; 268 269 void set_compat_intv2( const compat_level_t intv2_compat ); 270 compat_level_t get_compat_intv2( void ) const; 271 272 void set_compat_kc( const compat_level_t kc_compat ); 273 compat_level_t get_compat_kc( void ) const; 274 275 void set_compat_tv( const compat_level_t tv_compat ); 276 compat_level_t get_compat_tv( void ) const; 277 278 void set_jlp_features( const jlp_accel_t jlp_accel, 279 const unsigned jlp_flash ); 280 jlp_accel_t get_jlp_accel( void ) const; 281 unsigned get_jlp_flash( void ) const; 282 283 void set_enable_lto_mapper( const bool lto_mapper ); 284 bool get_enable_lto_mapper( void ) const; 285 286 void set_explicit_flags( const bool explicit_flags ); 287 bool get_explicit_flags( void ) const; 288 289 // -------------------------------------------------------------------- // 290 // Used only by LUIGI loader // 291 // -------------------------------------------------------------------- // 292 void copy_feature_flag_to_metadata( void ); set_scramble_druid(const bool is_scrambled_,const uint8_t * druid_=nullptr)293 void set_scramble_druid( const bool is_scrambled_, 294 const uint8_t* druid_ = nullptr ) 295 { 296 is_scrambled = is_scrambled_ && druid_; 297 if ( is_scrambled ) 298 std::copy( druid_, druid_ + sizeof( druid ), std::begin( druid ) ); 299 else 300 std::fill( std::begin( druid ), std::end( druid ), 0 ); 301 } 302 }; 303 304 #endif 305