1 // ======================================================================== //
2 //  Adapt the Locutus class to the periph_t "class" in jzIntv               //
3 // ======================================================================== //
4 
5 #include "locutus.hpp"
6 #include "luigi.hpp"
7 
8 #include "locutus_adapt.h"
9 
10 #include <fstream>
11 #include <iostream>
12 #include <cstdio>
13 #include <string>
14 
15 using namespace std;
16 
17 class t_cpu_cache : public t_cpu_cache_if
18 {
19   private:
20     cp1600_t *const cp1600;
21 
22   public:
t_cpu_cache(cp1600_t * cp1600_)23     t_cpu_cache( cp1600_t *cp1600_ ) : cp1600( cp1600_ ) { }
24 
invalidate(uint16_t addr_lo,uint16_t addr_hi)25     virtual void invalidate( uint16_t addr_lo, uint16_t addr_hi )
26     {
27         if ( cp1600 )
28             cp1600_invalidate( cp1600, addr_lo, addr_hi );
29     }
30 
31     ~t_cpu_cache();
32 };
33 
34 // Anchor the vtable
~t_cpu_cache()35 t_cpu_cache::~t_cpu_cache() { }
36 
37 struct t_locutus_priv
38 {
39     t_locutus    locutus;
40     t_cpu_cache  cpu_cache;
41 
t_locutus_privt_locutus_priv42     t_locutus_priv( cp1600_t *cp1600 )
43     :   cpu_cache( cp1600 )
44     { }
45 };
46 
47 
locutus_read(periph_t * const periph,periph_t *,uint32_t addr,uint32_t)48 LOCAL uint32_t locutus_read( periph_t *const periph, periph_t *,
49                              uint32_t addr, uint32_t )
50 {
51     t_locutus_wrap *wrap = reinterpret_cast<t_locutus_wrap *>(periph);
52 
53     try
54     {
55         return wrap->locutus_priv->locutus.intv_read( addr );
56     } catch ( string &s )
57     {
58         cerr << "EXCEPTION: " << s << endl;
59         exit(1);
60     }
61 }
62 
locutus_write(periph_t * const periph,periph_t *,uint32_t addr,uint32_t data)63 LOCAL void locutus_write( periph_t *const periph, periph_t *,
64                           uint32_t addr, uint32_t data )
65 {
66     t_locutus_wrap *wrap = reinterpret_cast<t_locutus_wrap *>(periph);
67 
68     try
69     {
70         return wrap->locutus_priv->locutus.intv_write( addr, data );
71     } catch ( string &s )
72     {
73         cerr << "EXCEPTION: " << s << endl;
74         exit(1);
75     }
76 }
77 
locutus_reset(periph_t * const periph)78 LOCAL void locutus_reset( periph_t *const periph )
79 {
80     t_locutus_wrap *wrap = reinterpret_cast<t_locutus_wrap *>(periph);
81 
82     try
83     {
84         wrap->locutus_priv->locutus.intv_reset();
85     } catch ( string &s )
86     {
87         cerr << "EXCEPTION: " << s << endl;
88         exit(1);
89     }
90 }
91 
locutus_dtor(periph_t * const periph)92 LOCAL void locutus_dtor( periph_t *const periph )
93 {
94     t_locutus_wrap *wrap = reinterpret_cast<t_locutus_wrap *>(periph);
95 
96     delete wrap->locutus_priv;
97     wrap->locutus_priv = nullptr;
98 }
99 
make_locutus(t_locutus_wrap * loc_wrap,const char * luigi_file,cp1600_t * cp1600,int silent,const char * savegame)100 extern "C" int make_locutus
101 (
102     t_locutus_wrap  *loc_wrap,      /*  pointer to a Locutus wrapper    */
103     const char      *luigi_file,    /*  LUIGI file to load into Locutus */
104     cp1600_t        *cp1600,
105     int             silent,
106     const char      *savegame
107 )
108 {
109     t_locutus_priv *priv     = new t_locutus_priv( cp1600 );
110     loc_wrap->locutus_priv   = priv;
111 
112     ifstream ifs(luigi_file, ios::binary | ios::ate);
113 
114     if ( !ifs.is_open() )
115     {
116         if (!silent)
117             cerr << "could not open " << luigi_file << endl;
118         return -1;
119     }
120 
121     ifstream::pos_type pos = ifs.tellg();
122 
123     t_byte_vec luigi_data(pos);
124 
125     ifs.seekg(0, ios::beg);
126     ifs.read(reinterpret_cast<char *>(&luigi_data[0]), pos);
127 
128     try
129     {
130         t_luigi::deserialize( priv->locutus, luigi_data );
131     } catch ( string &s )
132     {
133         if (!silent)
134             cerr << "EXCEPTION: " << s << endl;
135         return -1;
136     }
137 
138     if ( (!silent || cp1600) && priv->locutus.was_scrambled() )
139     {
140         const uint8_t* druid = priv->locutus.get_scramble_druid();
141         char buf[50];
142         sprintf(buf,
143                 "%.2X%.2X:%.2X%.2X:%.2X%.2X:%.2X%.2X:"
144                 "%.2X%.2X:%.2X%.2X:%.2X%.2X:%.2X%.2X",
145                 druid[15], druid[14], druid[13], druid[12],
146                 druid[11], druid[10], druid[ 9], druid[ 8],
147                 druid[ 7], druid[ 6], druid[ 5], druid[ 4],
148                 druid[ 3], druid[ 2], druid[ 1], druid[ 0]);
149         cerr << "This LUIGI is scrambled for DRUID " << buf << "\n";
150         return -1;
151     }
152 
153     priv->locutus.set_xregs( &cp1600->xr[0] );
154     priv->locutus.init_jlp_flash( savegame );
155     priv->locutus.intv_reset();
156 
157     loc_wrap->periph.read       = locutus_read;
158     loc_wrap->periph.write      = locutus_write;
159     loc_wrap->periph.peek       = locutus_read;
160     loc_wrap->periph.poke       = locutus_write;
161     loc_wrap->periph.reset      = locutus_reset;
162     loc_wrap->periph.dtor       = locutus_dtor;
163 
164     loc_wrap->periph.tick       = nullptr;
165     loc_wrap->periph.min_tick   = ~0U;
166     loc_wrap->periph.max_tick   = ~0U;
167 
168     loc_wrap->periph.addr_base  = 0;
169     loc_wrap->periph.addr_mask  = ~0U;
170     loc_wrap->periph.ser_init   = nullptr; // no support for serializer()
171 
172     return 0;
173 }
174 
get_locutus_metadata(t_locutus_wrap * loc_wrap)175 extern "C" game_metadata_t* get_locutus_metadata
176 (
177     t_locutus_wrap *loc_wrap
178 )
179 {
180     t_locutus_priv* priv = loc_wrap->locutus_priv;
181     const t_metadata& metadata = priv->locutus.get_metadata();
182     return metadata.to_game_metadata();
183 }
184 
get_locutus_compat_ecs(t_locutus_wrap * loc_wrap)185 extern "C" int get_locutus_compat_ecs  ( t_locutus_wrap *loc_wrap )
186 {
187     return int( loc_wrap->locutus_priv->locutus.get_compat_ecs() );
188 }
189 
get_locutus_compat_voice(t_locutus_wrap * loc_wrap)190 extern "C" int get_locutus_compat_voice( t_locutus_wrap *loc_wrap )
191 {
192     return int( loc_wrap->locutus_priv->locutus.get_compat_voice() );
193 }
194 
get_locutus_compat_intv2(t_locutus_wrap * loc_wrap)195 extern "C" int get_locutus_compat_intv2( t_locutus_wrap *loc_wrap )
196 {
197     return int( loc_wrap->locutus_priv->locutus.get_compat_intv2() );
198 }
199 
get_locutus_compat_kc(t_locutus_wrap * loc_wrap)200 extern "C" int get_locutus_compat_kc( t_locutus_wrap *loc_wrap )
201 {
202     return int( loc_wrap->locutus_priv->locutus.get_compat_kc() );
203 }
204 
get_locutus_uid(t_locutus_wrap * loc_wrap)205 extern "C" uint64_t get_locutus_uid( t_locutus_wrap *loc_wrap )
206 {
207     return loc_wrap->locutus_priv->locutus.get_uid();
208 }
209 
get_locutus_was_scrambled(t_locutus_wrap * loc_wrap)210 extern "C" int get_locutus_was_scrambled( t_locutus_wrap *loc_wrap )
211 {
212     return loc_wrap->locutus_priv->locutus.was_scrambled();
213 }
214 
get_locutus_scramble_druid(t_locutus_wrap * loc_wrap)215 extern "C" const uint8_t* get_locutus_scramble_druid( t_locutus_wrap *loc_wrap )
216 {
217     return loc_wrap->locutus_priv->locutus.get_scramble_druid();
218 }
219