summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/machine/s24fd.c
blob: 1f7dc5eb91ec1adae2933c74314e16c8311129ad (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/* s16fd.c modified to support s24

this could get messy if games change their own code after initial loading as we'll have to invalidate caches etc.


*/

#include "driver.h"
#include "deprecat.h"
#include "cpu/m68000/m68000.h"
#include "machine/fd1094.h"

extern UINT16 *s24_mainram1;

#define S16_NUMCACHE 8

static UINT8 *s24_fd1094_key; // the memory region containing key
static UINT16 *s24_fd1094_cpuregion; // the CPU region with encrypted code
static UINT32  s24_fd1094_cpuregionsize; // the size of this region in bytes

static UINT16* s24_fd1094_userregion; // a user region where the current decrypted state is put and executed from
static UINT16* s24_fd1094_cacheregion[S16_NUMCACHE]; // a cache region where S16_NUMCACHE states are stored to improve performance
static int fd1094_cached_states[S16_NUMCACHE]; // array of cached state numbers
static int fd1094_current_cacheposition; // current position in cache array

static int fd1094_state;
static int fd1094_selected_state;

/* this function checks the cache to see if the current state is cached,
   if it is then it copies the cached data to the user region where code is
   executed from, if its not cached then it gets decrypted to the current
   cache position using the functions in s24_fd1094.c */
static void s24_fd1094_setstate_and_decrypt(int state)
{
	int i;
	UINT32 addr;

	switch (state & 0x300)
	{
	case 0x000:
	case FD1094_STATE_RESET:
		fd1094_selected_state = state & 0xff;
		break;
	}

	fd1094_state = state;

	cpu_set_reg(Machine->cpu[1], M68K_PREF_ADDR, 0x0010);	// force a flush of the prefetch cache

	/* set the s24_fd1094 state ready to decrypt.. */
	state = fd1094_set_state(s24_fd1094_key,state) & 0xff;

	/* first check the cache, if its cached we don't need to decrypt it, just copy */
	for (i=0;i<S16_NUMCACHE;i++)
	{
		if (fd1094_cached_states[i] == state)
		{
			/* copy cached state */
			s24_fd1094_userregion=s24_fd1094_cacheregion[i];
			memory_set_decrypted_region(cpu_get_address_space(Machine->cpu[1], ADDRESS_SPACE_PROGRAM), 0, s24_fd1094_cpuregionsize - 1, s24_fd1094_userregion);
			m68k_set_encrypted_opcode_range(Machine->cpu[1],0,s24_fd1094_cpuregionsize);

			return;
		}
	}

// mame_printf_debug("new state %04x\n",state);

	/* mark it as cached (because it will be once we decrypt it) */
	fd1094_cached_states[fd1094_current_cacheposition]=state;

	for (addr=0;addr<s24_fd1094_cpuregionsize/2;addr++)
	{
		UINT16 dat;
		dat = fd1094_decode(addr,s24_fd1094_cpuregion[addr],s24_fd1094_key,0);
		s24_fd1094_cacheregion[fd1094_current_cacheposition][addr]=dat;
	}

	/* copy newly decrypted data to user region */
	s24_fd1094_userregion=s24_fd1094_cacheregion[fd1094_current_cacheposition];
	memory_set_decrypted_region(cpu_get_address_space(Machine->cpu[1], ADDRESS_SPACE_PROGRAM), 0, s24_fd1094_cpuregionsize - 1, s24_fd1094_userregion);
	m68k_set_encrypted_opcode_range(Machine->cpu[1],0,s24_fd1094_cpuregionsize);

	fd1094_current_cacheposition++;

	if (fd1094_current_cacheposition>=S16_NUMCACHE)
	{
		mame_printf_debug("out of cache, performance may suffer, incrase S16_NUMCACHE!\n");
		fd1094_current_cacheposition=0;
	}
}

/* Callback for CMP.L instructions (state change) */
static void s24_fd1094_cmp_callback(const device_config *device, UINT32 val, int reg)
{
	if (reg == 0 && (val & 0x0000ffff) == 0x0000ffff) // ?
	{
		s24_fd1094_setstate_and_decrypt((val & 0xffff0000) >> 16);
	}
}

/* Callback when the s24_fd1094 enters interrupt code */
static IRQ_CALLBACK(s24_fd1094_int_callback)
{
	s24_fd1094_setstate_and_decrypt(FD1094_STATE_IRQ);
	return (0x60+irqline*4)/4; // vector address
}

static void s24_fd1094_rte_callback (const device_config *device)
{
	s24_fd1094_setstate_and_decrypt(FD1094_STATE_RTE);
}


/* KLUDGE, set the initial PC / SP based on table as we can't decrypt them yet */
static void s24_fd1094_kludge_reset_values(void)
{
	int i;

	for (i = 0;i < 4;i++)
		s24_fd1094_userregion[i] = fd1094_decode(i,s24_fd1094_cpuregion[i],s24_fd1094_key,1);
}


/* function, to be called from MACHINE_RESET (every reset) */
void s24_fd1094_machine_init(void)
{
	/* punt if no key; this allows us to be called even for non-s24_fd1094 games */
	if (!s24_fd1094_key)
		return;

	s24_fd1094_setstate_and_decrypt(FD1094_STATE_RESET);
	s24_fd1094_kludge_reset_values();

	cpu_set_info_fct(Machine->cpu[1], CPUINFO_PTR_M68K_CMPILD_CALLBACK, (genf *)s24_fd1094_cmp_callback);
	cpu_set_info_fct(Machine->cpu[1], CPUINFO_PTR_M68K_RTE_CALLBACK, (genf *)s24_fd1094_rte_callback);
	cpu_set_irq_callback(Machine->cpu[1], s24_fd1094_int_callback);
	
	cpu_reset(Machine->cpu[1]);
}

static STATE_POSTLOAD( s24_fd1094_postload )
{
	if (fd1094_state != -1)
	{
		int selected_state = fd1094_selected_state;
		int state = fd1094_state;

		s24_fd1094_machine_init();

		s24_fd1094_setstate_and_decrypt(selected_state);
		s24_fd1094_setstate_and_decrypt(state);
	}
}

/* startup function, to be called from DRIVER_INIT (once on startup) */
void s24_fd1094_driver_init(running_machine *machine)
{
	int i;

	s24_fd1094_cpuregion = (UINT16*)s24_mainram1;
	s24_fd1094_cpuregionsize = 0x40000;
	s24_fd1094_key = memory_region(machine, "fd1094key");

	/* punt if no key; this allows us to be called even for non-s24_fd1094 games */
	if (!s24_fd1094_key)
		return;

	for (i=0;i<S16_NUMCACHE;i++)
	{
		s24_fd1094_cacheregion[i]=auto_malloc(s24_fd1094_cpuregionsize);
	}

	/* flush the cached state array */
	for (i=0;i<S16_NUMCACHE;i++)
		fd1094_cached_states[i] = -1;

	fd1094_current_cacheposition = 0;

	fd1094_state = -1;

	state_save_register_global(fd1094_selected_state);
	state_save_register_global(fd1094_state);
	state_save_register_postload(machine, s24_fd1094_postload, NULL);
}