Fix tms9918a transparent color rendering
[qemu/z80.git] / hw / zx_spectrum.c
blob7ee641e045b49200df8bc743985f12f9431df156
1 /*
2 * QEMU ZX Spectrum Emulator
4 * Copyright (c) 2007-2009 Stuart Brady <stuart.brady@gmail.com>
5 * Copyright (c) 2007 Ulrich Hecht
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
25 #include "hw.h"
26 #include "qemu-timer.h"
27 #include "console.h"
28 #include "isa.h"
29 #include "sysemu.h"
30 #include "zx_video.h"
31 #include "zx_keyboard.h"
32 #include "boards.h"
34 #ifdef CONFIG_LIBSPECTRUM
35 #include <libspectrum.h>
36 #endif
38 #define ROM_FILENAME "zx-rom.bin"
40 static uint32_t io_spectrum_read(void *opaque, uint32_t addr)
42 if ((addr & 1) == 0) {
43 return zx_keyboard_read(opaque, addr);
44 } else {
45 return 0xff;
49 static void io_spectrum_write(void *opaque, uint32_t addr, uint32_t data)
51 if ((addr & 1) == 0) {
52 zx_video_set_border(data & 0x7);
56 static void main_cpu_reset(void *opaque)
58 CPUState *env = opaque;
59 cpu_reset(env);
62 static QEMUTimer *zx_ula_timer;
64 static void zx_50hz_timer(void *opaque)
66 int64_t next_time;
68 CPUState *env = opaque;
69 cpu_interrupt(env, CPU_INTERRUPT_HARD);
71 /* FIXME: not exactly 50 Hz */
72 next_time = qemu_get_clock(vm_clock) + muldiv64(1, ticks_per_sec, 50);
73 qemu_mod_timer(zx_ula_timer, next_time);
75 zx_video_do_retrace();
78 static CPUState *zx_env;
80 static void zx_timer_init(void)
82 int64_t t = qemu_get_clock(vm_clock);
83 zx_ula_timer = qemu_new_timer(vm_clock, zx_50hz_timer, zx_env);
84 qemu_mod_timer(zx_ula_timer, t);
87 static const uint8_t halthack_oldip[16] =
88 {253, 203, 1,110, 200, 58, 8, 92, 253, 203, 1, 174};
89 static const uint8_t halthack_newip[16] =
90 {33, 59, 92, 118, 203, 110, 200, 58, 8, 92, 203, 174};
92 /* ZX Spectrum initialisation */
93 static void zx_spectrum_init(ram_addr_t ram_size,
94 const char *boot_device,
95 const char *kernel_filename,
96 const char *kernel_cmdline,
97 const char *initrd_filename,
98 const char *cpu_model)
100 char *filename;
101 uint8_t halthack_curip[12];
102 int ret;
103 ram_addr_t ram_offset, rom_offset;
104 int rom_size;
105 CPUState *env;
107 /* init CPUs */
108 if (!cpu_model) {
109 cpu_model = "z80";
111 env = cpu_init(cpu_model);
112 zx_env = env; // XXX
113 register_savevm("cpu", 0, 4, cpu_save, cpu_load, env);
114 qemu_register_reset(main_cpu_reset, 0, env);
115 main_cpu_reset(env);
117 /* allocate RAM */
118 ram_offset = qemu_ram_alloc(0xc000);
119 cpu_register_physical_memory(0x4000, 0xc000, ram_offset | IO_MEM_RAM);
121 /* ROM load */
122 if (bios_name == NULL) {
123 bios_name = ROM_FILENAME;
125 filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
126 if (filename) {
127 rom_size = get_image_size(filename);
128 } else {
129 rom_size = -1;
131 if (rom_size <= 0 ||
132 (rom_size % 0x4000) != 0) {
133 goto rom_error;
135 rom_offset = qemu_ram_alloc(rom_size);
136 cpu_register_physical_memory(0x0000, 0x4000, rom_offset | IO_MEM_ROM);
137 ret = load_image_targphys(filename, 0x0000, rom_size);
138 if (ret != rom_size) {
139 rom_error:
140 fprintf(stderr, "qemu: could not load ZX Spectrum ROM '%s'\n",
141 bios_name);
142 exit(1);
144 if (filename) {
145 qemu_free(filename);
148 /* hack from xz80 adding HALT to the keyboard input loop to save CPU */
149 cpu_physical_memory_read(0x10b0, halthack_curip, 12);
150 if (!memcmp(halthack_curip, halthack_oldip, 12)) {
151 cpu_physical_memory_write_rom(0x10b0, halthack_newip, 12);
154 /* map entire I/O space */
155 register_ioport_read(0, 0x10000, 1, io_spectrum_read, NULL);
156 register_ioport_write(0, 0x10000, 1, io_spectrum_write, NULL);
158 zx_video_init(ram_offset);
160 zx_keyboard_init();
161 zx_timer_init();
163 #ifdef CONFIG_LIBSPECTRUM
164 /* load a snapshot */
165 if (kernel_filename) {
166 libspectrum_id_t type;
167 libspectrum_class_t cls;
168 libspectrum_snap* snap;
169 uint8_t* snapmem;
170 libspectrum_byte* page;
171 int length;
172 int i, p;
173 const int pages_48k[3] = { 5, 2, 0 };
175 if (libspectrum_init() != LIBSPECTRUM_ERROR_NONE ||
176 libspectrum_identify_file(&type, kernel_filename, NULL, 0) != LIBSPECTRUM_ERROR_NONE ||
177 libspectrum_identify_class(&cls, type) != LIBSPECTRUM_ERROR_NONE) {
178 fprintf(stderr, "%s: libspectrum error\n", __FUNCTION__);
179 exit(1);
181 snap = libspectrum_snap_alloc();
182 if (cls != LIBSPECTRUM_CLASS_SNAPSHOT) {
183 fprintf(stderr, "%s: %s is not a snapshot\n", __FUNCTION__, kernel_filename);
184 exit(1);
186 snapmem = qemu_mallocz(0x10000);
187 length = load_image(kernel_filename, snapmem);
188 //printf("loaded %d bytes from %s\n",length, kernel_filename);
189 if (libspectrum_snap_read(snap, snapmem, length, type, NULL) != LIBSPECTRUM_ERROR_NONE) {
190 fprintf(stderr, "%s: failed to load snapshot %s\n", __FUNCTION__, kernel_filename);
191 exit(1);
193 //printf("snap pc = %d\n",libspectrum_snap_pc(snap));
195 /* fill memory */
196 for (p = 0; p < 3; p++) {
197 page = libspectrum_snap_pages(snap, pages_48k[p]);
198 for (i = 0x0000; i < 0x4000; i++) {
199 stb_phys(i + ((p + 1) << 14), page[i]);
203 zx_video_set_border(libspectrum_snap_out_ula(snap) & 0x7);
205 /* restore registers */
206 env->regs[R_A] = libspectrum_snap_a(snap);
207 env->regs[R_F] = libspectrum_snap_f(snap);
208 env->regs[R_BC] = libspectrum_snap_bc(snap);
209 env->regs[R_DE] = libspectrum_snap_de(snap);
210 env->regs[R_HL] = libspectrum_snap_hl(snap);
211 env->regs[R_AX] = libspectrum_snap_a_(snap);
212 env->regs[R_FX] = libspectrum_snap_f_(snap);
213 env->regs[R_BCX] = libspectrum_snap_bc_(snap);
214 env->regs[R_DEX] = libspectrum_snap_de_(snap);
215 env->regs[R_HLX] = libspectrum_snap_hl_(snap);
216 env->regs[R_IX] = libspectrum_snap_ix(snap);
217 env->regs[R_IY] = libspectrum_snap_iy(snap);
218 env->regs[R_I] = libspectrum_snap_i(snap);
219 env->regs[R_R] = libspectrum_snap_r(snap);
220 env->regs[R_SP] = libspectrum_snap_sp(snap);
221 env->pc = libspectrum_snap_pc(snap);
222 env->iff1 = libspectrum_snap_iff1(snap);
223 env->iff2 = libspectrum_snap_iff2(snap);
224 env->imode = libspectrum_snap_im(snap);
226 qemu_free(snapmem);
228 #endif
231 static QEMUMachine zxspec_machine = {
232 .name = "zxspec",
233 .desc = "ZX Spectrum",
234 .init = zx_spectrum_init,
235 .is_default = 1,
238 static void zxspec_machine_init(void) {
239 qemu_register_machine(&zxspec_machine);
242 machine_init(zxspec_machine_init);