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
26 #include "qemu-timer.h"
31 #include "zx_keyboard.h"
34 #ifdef CONFIG_LIBSPECTRUM
35 #include <libspectrum.h>
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
);
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
;
62 static QEMUTimer
*zx_ula_timer
;
64 static void zx_50hz_timer(void *opaque
)
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
)
101 uint8_t halthack_curip
[12];
103 ram_addr_t ram_offset
, rom_offset
;
111 env
= cpu_init(cpu_model
);
113 register_savevm("cpu", 0, 4, cpu_save
, cpu_load
, env
);
114 qemu_register_reset(main_cpu_reset
, 0, env
);
118 ram_offset
= qemu_ram_alloc(0xc000);
119 cpu_register_physical_memory(0x4000, 0xc000, ram_offset
| IO_MEM_RAM
);
122 if (bios_name
== NULL
) {
123 bios_name
= ROM_FILENAME
;
125 filename
= qemu_find_file(QEMU_FILE_TYPE_BIOS
, bios_name
);
127 rom_size
= get_image_size(filename
);
132 (rom_size
% 0x4000) != 0) {
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
) {
140 fprintf(stderr
, "qemu: could not load ZX Spectrum ROM '%s'\n",
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
);
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
;
170 libspectrum_byte
* page
;
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__
);
181 snap
= libspectrum_snap_alloc();
182 if (cls
!= LIBSPECTRUM_CLASS_SNAPSHOT
) {
183 fprintf(stderr
, "%s: %s is not a snapshot\n", __FUNCTION__
, kernel_filename
);
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
);
193 //printf("snap pc = %d\n",libspectrum_snap_pc(snap));
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
);
231 static QEMUMachine zxspec_machine
= {
233 .desc
= "ZX Spectrum",
234 .init
= zx_spectrum_init
,
238 static void zxspec_machine_init(void) {
239 qemu_register_machine(&zxspec_machine
);
242 machine_init(zxspec_machine_init
);