File Coverage

blib/lib/CPU/Emulator/Z80.pm
Criterion Covered Total %
statement 693 702 98.7
branch 215 228 94.3
condition 74 84 88.1
subroutine 131 134 97.7
pod 12 12 100.0
total 1125 1160 96.9


line stmt bran cond sub pod time code
1             # $Id: Z80.pm,v 1.56 2008/06/13 14:42:08 drhyde Exp $
2              
3             package CPU::Emulator::Z80;
4              
5 13     13   497175 use strict;
  13         38  
  13         1010  
6 13     13   78 use warnings;
  13         25  
  13         476  
7              
8 13     13   477 use vars qw($VERSION %INSTR_LENGTHS %INSTR_DISPATCH);
  13         24  
  13         1877  
9              
10             $VERSION = '1.0';
11              
12             $SIG{__WARN__} = sub {
13             warn(__PACKAGE__.": $_[0]\n");
14             };
15              
16 13     13   74 use Carp;
  13         29  
  13         1731  
17 13     13   106 use Scalar::Util qw(blessed reftype);
  13         37  
  13         1983  
18 13     13   22143 use Tie::Hash::Vivify;
  13         10306  
  13         914  
19 13     13   83 use Carp qw(confess);
  13         252  
  13         756  
20 13     13   19066 use Data::Dumper;
  13         187630  
  13         1130  
21              
22 13     13   21941 use CPU::Emulator::Memory::Banked;
  13         59366  
  13         448  
23 13     13   11464 use CPU::Emulator::Z80::Register8;
  13         78  
  13         437  
24 13     13   9022 use CPU::Emulator::Z80::Register8F;
  13         36  
  13         688  
25 13     13   27051 use CPU::Emulator::Z80::Register8R;
  13         40  
  13         368  
26 13     13   9903 use CPU::Emulator::Z80::Register16;
  13         40  
  13         447  
27 13     13   12957 use CPU::Emulator::Z80::Register16SP;
  13         33  
  13         2711  
28 13     13   78 use CPU::Emulator::Z80::ALU; # import add/subtract methods
  13         25  
  13         4351602  
29              
30             my @REGISTERS16 = qw(PC SP IX IY HL); # 16 bit registers
31             # NB W and Z aren't programmer-accesible, for internal use only!
32             my @REGISTERS8 = qw(A B C D E F R W Z I); # 8 bit registers
33             my @ALTREGISTERS = qw(A B C D E F HL); # those which have alt.s
34             my @REGISTERS = (@REGISTERS16, @REGISTERS8); # all registers
35              
36             =head1 NAME
37              
38             CPU::Emulator::Z80 - a Z80 emulator
39              
40             =head1 SYNOPSIS
41              
42             # create a CPU with 64K of zeroes in RAM
43             my $cpu = CPU::Emulator::Z80->new();
44              
45             # set a breakpoint
46             $cpu->memory()->poke16(0xF000, 0xDDDD); # STOP instruction
47             $cpu->memory()->poke(0xF002, 0x00);
48              
49             $cpu->memory()->poke(0, 0xC3); # JP 0xC000
50             $cpu->memory()->poke16(1, 0xC000);
51              
52             # run until we hit a breakpoint ie RST 1
53             eval { $cpu->run(); }
54             print $cpu->format_registers();
55              
56             =head1 DESCRIPTION
57              
58             This class provides a virtual Z80 micro-processor written in pure perl.
59             You can program it in Z80 machine code. Machine code is fast! This will
60             make your code faster!
61              
62             =head1 METHODS
63              
64             =head2 new
65              
66             The constructor returns an object representing a Z80 CPU. It takes
67             several optional parameters:
68              
69             =over
70              
71             =item memory
72              
73             can be either an object inheriting from CPU::Emulator::Memory, or a string
74             of data with which to initialise RAM. If a string is passed, then a
75             CPU::Emulator::Memory::Banked is created of the appropriate size. If not
76             specified at all, then a CPU::Emulator::Memory::Banked is created with
77             64K of zeroes.
78              
79             =item ports
80              
81             can be either 256 or 65536 (no other values are permitted) and defaults
82             to 65536. This is the number of I/O ports that can be addressed.
83             If set to 65536, the entire address bus is used to determine what
84             port I/O instructions tickle. If 256, then the most significant 8
85             bits are ignored.
86              
87             =item init_PC, init_A, init_B ...
88              
89             For each of A B C D E F R HL IX IY PC SP, an integer, the starting
90             value for that register, defaulting to 0.
91              
92             =item init_A_, init_B_, ...
93              
94             For each of A B C D E F HL, an integer for the starting value for that
95             register in the alternate set, defaulting to 0. Note that contrary to
96             normal Z80 custom these are named as X_ instead of X'. This is just for
97             quoting convenience.
98              
99             =back
100              
101             =cut
102              
103             sub new {
104 1312     1312 1 63432245 my($class, %args) = @_;
105 1312 100       33930 if(exists($args{memory})) {
106 1285 100       20357 if(blessed($args{memory})) {
    50          
107 1284 50       16774 die("memory must be a CPU::Emulator::Memory")
108             unless($args{memory}->isa('CPU::Emulator::Memory'));
109             } elsif(!ref($args{memory})) {
110 1         24 $args{memory} = CPU::Emulator::Memory::Banked->new(
111             bytes => $args{memory},
112             size => length($args{memory})
113             );
114             } else {
115 0         0 die("memory must be a string or an object\n");
116             }
117             } else {
118 27         265 $args{memory} = CPU::Emulator::Memory::Banked->new();
119             }
120              
121 1312 100       9683 if(exists($args{ports})) {
122 3 100 66     38 die("$args{ports} is a stupid number of ports\n")
123             unless($args{ports} == 256 || $args{ports} == 65536);
124             } else {
125 1309         6453 $args{ports} = 65536;
126             }
127              
128 1311         6855 foreach my $register (@REGISTERS, map { "${_}_" } @ALTREGISTERS) {
  9177         27892  
129 28842 100       185892 $args{"init_$register"} = 0
130             if(!exists($args{"init_$register"}));
131             }
132              
133             # bless early so we can close over it ...
134 1311         8507 my $self;
135             $self = bless {
136             iff1 => 0,
137             iff2 => 0,
138             ports => $args{ports},
139             inputs => {},
140             outputs => {},
141             memory => $args{memory},
142 0     0   0 registers => Tie::Hash::Vivify->new(sub { confess("No auto-vivifying registers!\n".Dumper(\@_)) }),
143 0     0   0 hw_registers => Tie::Hash::Vivify->new(sub { confess("No auto-vivifying hw_registers!\n".Dumper(\@_)) }),
144 1311     0   33471 derived_registers => Tie::Hash::Vivify->new(sub { confess("No auto-vivifying derived_registers!\n".Dumper(\@_)) }),
  0         0  
145             }, $class;
146              
147             $self->{hw_registers}->{$_} = CPU::Emulator::Z80::Register8->new(
148             cpu => $self, value => $args{"init_$_"}
149 1311         152115 ) foreach(@REGISTERS8);
150              
151             $self->{hw_registers}->{$_} = CPU::Emulator::Z80::Register16->new(
152             cpu => $self, value => $args{"init_$_"}
153 1311         46777 ) foreach(@REGISTERS16);
154              
155             $self->{hw_registers}->{$_.'_'} = blessed($self->{hw_registers}->{$_})->new(
156             cpu => $self, value => $args{"init_$_"}
157 1311         27692 ) foreach(@ALTREGISTERS);
158              
159             bless $self->{hw_registers}->{$_}, 'CPU::Emulator::Z80::Register8F'
160 1311         34585 foreach(qw(F F_));
161 1311         55866 bless $self->{hw_registers}->{R}, 'CPU::Emulator::Z80::Register8R';
162 1311         50731 bless $self->{hw_registers}->{SP}, 'CPU::Emulator::Z80::Register16SP';
163              
164              
165 1311         23412 $self->{derived_registers}->{AF} = $self->_derive_register16(qw(A F));
166 1311         26523 $self->{derived_registers}->{AF_} = $self->_derive_register16(qw(A_ F_));
167 1311         19869 $self->{derived_registers}->{BC} = $self->_derive_register16(qw(B C));
168 1311         32316 $self->{derived_registers}->{BC_} = $self->_derive_register16(qw(B_ C_));
169 1311         19971 $self->{derived_registers}->{DE} = $self->_derive_register16(qw(D E));
170 1311         18123 $self->{derived_registers}->{DE_} = $self->_derive_register16(qw(D_ E_));
171 1311         30989 $self->{derived_registers}->{WZ} = $self->_derive_register16(qw(W Z));
172 1311         28073 $self->{derived_registers}->{H} = $self->_derive_register8(qw(HL high));
173 1311         21535 $self->{derived_registers}->{H_} = $self->_derive_register8(qw(HL_ high));
174 1311         17060 $self->{derived_registers}->{L} = $self->_derive_register8(qw(HL low));
175 1311         23947 $self->{derived_registers}->{L_} = $self->_derive_register8(qw(HL_ low));
176 1311         25916 $self->{derived_registers}->{HIX} = $self->_derive_register8(qw(IX high));
177 1311         17608 $self->{derived_registers}->{LIX} = $self->_derive_register8(qw(IX low));
178 1311         19131 $self->{derived_registers}->{HIY} = $self->_derive_register8(qw(IY high));
179 1311         22798 $self->{derived_registers}->{LIY} = $self->_derive_register8(qw(IY low));
180              
181 1311         10497 $self->{registers}->{$_} = $self->{hw_registers}->{$_}
182 1311         15612 foreach(keys %{$self->{hw_registers}});
183 1311         8367 $self->{registers}->{$_} = $self->{derived_registers}->{$_}
184 1311         837324 foreach(keys %{$self->{derived_registers}});
185              
186 1311         559384 return $self;
187             }
188              
189             # create a 16-bit register-pair from two real 8-bit registers
190             sub _derive_register16 {
191 9177     9177   24384 my($self, $high, $low) = @_;
192             return CPU::Emulator::Z80::Register16->new(
193             get => sub {
194 7972     7972   26521 return 256 * $self->register($high)->get() +
195             $self->register($low)->get()
196             },
197             set => sub {
198 7838     7838   21728 my $value = shift;
199 7838         24672 $self->register($high)->set($value >>8);
200 7838         31333 $self->register($low)->set($value & 0xFF);
201             },
202 9177         131901 cpu => $self
203             );
204             }
205             # create an 8-bit pseudo-register from a 16-bit register
206             sub _derive_register8 {
207 10488     10488   31785 my($self, $pair, $half) = @_;
208             return CPU::Emulator::Z80::Register8->new(
209             get => sub {
210 394     394   1161 my $r = $self->register($pair)->get();
211 394 100       4717 return ($half eq 'high')
212             ? $r >> 8
213             : $r & 0xFF
214             },
215             set => sub {
216 246     246   648 my $value = shift;
217 246 100       711 $self->register($pair)->set(
218             ($half eq 'high')
219             ? ($self->register($pair)->get() & 0xFF) |
220             ($value << 8)
221             : ($self->register($pair)->get() & 0xFF00) | $value
222             );
223             },
224 10488         172420 cpu => $self
225             );
226             }
227              
228             =head2 add_input_device
229              
230             Takes two named parameters, 'address' and 'function', and creates an
231             input port at that address. Reading from the port will call the
232             function with no parameters,
233             returning whatever the function returns.
234              
235             In 256-port mode, the port is effectively replicated 256 times.
236              
237             =cut
238              
239             sub add_input_device {
240 27     27 1 293 my($self, %params) = @_;
241 27         69 my $address = $params{address} & ($self->{ports} - 1);
242 27 100       112 die(sprintf("Device already exists at %#06x", $address))
243             if(exists($self->{inputs}->{$address}));
244 26         105 $self->{inputs}->{$address} = $params{function};
245             }
246              
247             sub _get_from_input {
248 42     42   435 my($self, $addr) = @_;
249 42         75 $addr = $addr & ($self->{ports} - 1);
250 42 50       134 if(exists($self->{inputs}->{$addr})) {
251 42         134 return $self->{inputs}->{$addr}->();
252             } else {
253 0         0 die(sprintf("No such port %#06x", $addr));
254             }
255             }
256              
257             =head2 add_output_device
258              
259             Takes two named parameters, 'address' and 'function', and creates an
260             output port at that address. Writing to the port simply calls that
261             function with the byte to be written as its only parameter.
262              
263             In 256-port mode, the port is effectively replicated 256 times.
264              
265             =cut
266              
267             sub add_output_device {
268 10     10 1 91 my($self, %params) = @_;
269 10         28 my $address = $params{address} & ($self->{ports} - 1);
270 10 100       127 die(sprintf("Device already exists at %#06x", $address))
271             if(exists($self->{outputs}->{$address}));
272 9         38 $self->{outputs}->{$address} = $params{function};
273             }
274              
275             sub _put_to_output {
276 21     21   420 my($self, $addr, $byte) = @_;
277 21         44 $addr = $addr & ($self->{ports} - 1);
278 21 50       64 if(exists($self->{outputs}->{$addr})) {
279 21         73 $self->{outputs}->{$addr}->($byte);
280             } else {
281 0         0 carp(sprintf("No such port %#06x", $addr));
282             }
283             }
284              
285             =head2 memory
286              
287             Return a reference to the object that represent's the system's memory.
288              
289             =cut
290              
291             sub memory {
292 11488     11488 1 90269 my $self = shift;
293 11488         72372 return $self->{memory};
294             }
295              
296             =head2 register
297              
298             Return the object representing a specified register. This can be any
299             of the real registers (eg D or D_) or a derived register (eg DE or L).
300             For (HL) it returns the private internal DON'T TOUCH THIS 'W' register,
301             for evil twisty internals reasons.
302              
303             =cut
304              
305             sub register {
306 124468     124468 1 36556003 my($self, $r) = @_;
307 124468 100       923867 return $self->{registers}->{($r eq '(HL)') ? 'W' : $r};
308             }
309              
310             =head2 status
311              
312             Return a scalar representing the entire state of the CPU or, if passed
313             a scalar, attempt to initialise the CPU to the status it represents.
314              
315             =cut
316              
317             sub status {
318 3     3 1 1276 my $self = shift;
319 3 100       12 if(@_) { $self->_status_load(@_); }
  1         6  
320             return
321 42         92 join('', map {
322 18         59 chr($self->register($_)->get())
323             } qw(A B C D E F A_ B_ C_ D_ E_ F_ R I))
324             .join('', map {
325 3         24 chr($self->register($_)->get() >> 8),
326             chr($self->register($_)->get() & 0xFF),
327             } qw(SP PC IX IY HL HL_));
328             }
329             sub _status_load {
330 1     1   4 my($self, $status) = @_;
331 1         12 my @regs = split(//, $status);
332             $self->register($_)->set(ord(shift(@regs)))
333 1         7 foreach(qw(A B C D E F A_ B_ C_ D_ E_ F_ R I));
334             $self->register($_)->set(256 * ord(shift(@regs)) + ord(shift(@regs)))
335 1         5 foreach(qw(SP PC IX IY HL HL_));
336             }
337              
338             =head2 registers
339              
340             Return a hashref of all the real registers and their values.
341              
342             =head2 format_registers
343              
344             A convenient method for getting all the registers in a nice
345             printable format. It mostly exists to help me with debuggering,
346             but if you promise to be good you can use it too. Just don't
347             rely on the format remaining unchanged.
348              
349             =cut
350              
351             sub registers {
352 2     2 1 15 my $self = shift;
353             return {
354 40         135 map {
355 44         300 $_ => $self->register($_)->get()
356 2         3 } grep { $_ !~ /^(W|Z)$/ } keys %{$self->{hw_registers}}
  2         11  
357             }
358             }
359              
360             sub format_registers {
361 1283     1283 1 8808 my $self = shift;
362 28226         82841 sprintf("#
363             # SZ5H3PNC SZ5H3PNC
364             # A: 0x%02X F: %08b HL: 0x%04X A_: 0x%02X F_: %08b HL_: 0x%04X
365             # B: 0x%02X C: 0x%02X B_: 0x%02X C_: 0x%02X
366             # D: 0x%02X E: 0x%02X D_: 0x%02X E_: 0x%02X
367             #
368             # IX: 0x%04X IY: 0x%04X SP: 0x%04X PC: 0x%04X
369             #
370             # R: 0x%02X I: 0x%02X
371             # W: 0x%02X Z: 0x%02X (internal use only)
372 1283         5565 ", map { $self->register($_)->get(); } qw(A F HL A_ F_ HL_ B C B_ C_ D E D_ E_ IX IY SP PC R I W Z));
373             }
374              
375             =head2 interrupt
376              
377             Attempt to raise an interrupt. Whether any attention is paid to it or not
378             depends on whether you've enabled interrupts or not in your Z80 code.
379             Because only IM 1 is implemented, this will generate a RST 0x38 if
380             interrupts are enabled. Note that interrupts are disabled at power-on.
381              
382             This returns true if the interrupt will be acted upon, false otherwise.
383             That is, it returns true if interrupts are enabled.
384              
385             =head2 nmi
386              
387             Raise a non-maskable interrupt. This generates a CALL 0x0066 as the
388             next instruction.a This also disables interrupts. Interrupts are
389             restored to their previous state by a RETN instruction.
390              
391             =head2 run
392              
393             Start the CPU running from whatever the Program Counter (PC) is set to.
394             This will by default run for ever. However, it takes an optional
395             parameter telling the CPU to run that number of instructions.
396              
397             This returns either when that many instructions have been executed, or
398             when a STOP instruction executed - see 'Extra Instructions' below.
399              
400             On return, the PC will point at the next instruction to execute so that
401             you can resume where you left off.
402              
403             =head2 stopped
404              
405             Returns true if the CPU has STOPped, false otherwise. You can use this
406             to easily determine why the run() method returned.
407              
408             =cut
409              
410             # SEE http://www.z80.info/decoding.htm
411             # http://www.z80.info/z80sflag.htm
412             # NB when decoding, x == first 2 bits, y == next 3, z == last 3
413             # p == first 2 bits of y, q == last bit of y
414             my @TABLE_R = (qw(B C D E H L (HL) A));
415             my @TABLE_RP = (qw(BC DE HL SP));
416             my @TABLE_RP2 = (qw(BC DE HL AF));
417             my @TABLE_CC = (qw(NZ Z NC C PO PE P M));
418             my @TABLE_ALU = (
419             \&_ADD_r8_r8, \&_ADC_r8_r8, \&_SUB_r8_r8, \&_SBC_r8_r8,
420             \&_AND_r8_r8, \&_XOR_r8_r8, \&_OR_r8_r8, \&_CP_r8_r8
421             );
422             my @TABLE_ROT = (
423             \&_RLC, \&_RRC, \&_RL, \&_RR, \&_SLA, \&_SRA, \&_SLL, \&_SRL
424             );
425             my @TABLE_BLI = (
426             [\&_LDI, \&_CPI, \&_INI, \&_OUTI],
427             [\&_LDD, \&_CPD, \&_IND, \&_OUTD],
428             [\&_LDIR, \&_CPIR, \&_INIR, \&_OTIR],
429             [\&_LDDR, \&_CPDR, \&_INDR, \&_OTDR],
430             );
431              
432             # NB order is important in these tables
433             %INSTR_LENGTHS = (
434             (map { $_ => 'UNDEFINED' } (0 .. 255)),
435             # un-prefixed instructions
436             # x=0, z=0
437             (map { ($_ << 3) => 1 } (0, 1)), # NOP; EX AF, AF'
438             (map { ($_ << 3) => 2 } (2 .. 7)), # DJNZ d; JR d; JR X, d
439             # x=0, z=1
440             (map { 0b00000001 | ($_ << 4 ) => 3 } (0 .. 3)), # LD rp[p], nn
441             (map { 0b00001001 | ($_ << 4 ) => 1 } (0 .. 3)), # ADD HL, rp[p]
442             # x=0, z=2
443             (map { 0b00000010 | ($_ << 3) => 1 } (0 .. 3)), # LD (BC/DE), A; LD A, (BC/DE)
444             (map { 0b00000010 | ($_ << 3) => 3 } (4 .. 7)), # LD (nn), HL/A, LD HL/A, (nn)
445             # x=0, z=3
446             (map { 0b00000011 | ($_ << 3) => 1 } (0 .. 7)), # INC/DEC rp
447             # x=0, z=4
448             (map { 0b00000100 | ($_ << 3) => 1 } (0 .. 7)), # INC r[y]
449             # x=0, z=5
450             (map { 0b00000101 | ($_ << 3) => 1 } (0 .. 7)), # DEC r[y]
451             # x=0, z=6
452             (map { 0b00000110 | ($_ << 3) => 2 } (0 .. 7)), # LD r[y], n
453             # x=0, z=7: RLCA, RRCA, RLA, RRA, DAA, CPL, SCF, CCF
454             (map { 0b00000111 | ($_ << 3) => 1 } (0 .. 7)),
455             # x=1
456             (map { 0b01000000 + $_ => 1 } (0 .. 63)), # LD r[y], r[z], HALT
457             # x=2
458             (map { 0b10000000 + $_ => 1 } (0 .. 63)), # alu[y] on A and r[z]
459             # x=3, z=0
460             (map { 0b11000000 | ($_ << 3) => 1 } (0 .. 7)), # RET cc[y]
461             (map { 0b11000001 | ($_ << 3) => 1 } (0 .. 7)), # POP rp2[p]/RET/EXX/JP HL/LD SP, HL
462             (map { 0b11000010 | ($_ << 3) => 3 } (0 .. 7)), # JP cc[y], nn
463             (map { 0b11000100 | ($_ << 3) => 3 } (0 .. 7)), # CALL cc[y], nn
464             (map { 0b11000101 | ($_ << 4) => 1 } (0 .. 3)), # PUSH rp2[p]
465             (map { 0b11000110 | ($_ << 3) => 2 } (0 .. 7)), # ALU[y] A, n
466             (map { 0b11000111 | ($_ << 3) => 1 } (0 .. 7)), # RST y*8
467             (map { 0b11000011 | ($_ << 3) => 1 } (4 .. 7)), # EX(SP), HL/EX DE, HL/DI/EI
468             0b11010011 => 2, # OUT (n), A
469             0b11011011 => 2, # IN A, (n)
470             0xC3 => 3, # JP nn
471             0xCD => 3, # CALL nn
472              
473             0xCB, { (map { $_ => 1 } (0 .. 255)) }, # roll/shift/bit/res/set
474             0xED, {
475             (map { 0b01000000 | ($_ << 3) => 1 } (0 .. 7)), # IN r[y],(C)
476             (map { 0b01000001 | ($_ << 3) => 1 } (0 .. 7)), # OUT (C),r[y]/OUT (C), 0
477             (map { 0b01000010 | ($_ << 3) => 1 } (0 .. 7)), # ADC/SBC HL, rp[p]
478             (map { 0b01000011 | ($_ << 3) => 3 } (0 .. 7)), # LD (nn), rp[p]/LD rp[p], (nn)
479             (map { 0b01000100 | ($_ << 3) => 1 } (0 .. 7)), # NEG
480             (map { 0b01000101 | ($_ << 3) => 1 } (0 .. 7)), # RETI/RETN
481             (map { 0b01000110 | ($_ << 3) => 1 } (0 .. 7)), # IM im[y]
482             (map { 0b01000111 | ($_ << 3) => 1 } (0 .. 7)), # LD I/R,A;LD A,I/R;RRD;RLD;NOP
483             (map { 0b10000000 | $_ => 1 } (0 .. 63)), # block instrs
484             # invalid instr, equiv to NOP
485             (map { $_ => 1 } ( 0b00000000 .. 0b00111111,
486             0b11000000 .. 0b11111111)),
487             },
488             );
489             $INSTR_LENGTHS{0xDD} = $INSTR_LENGTHS{0xFD} = {
490             # NB lengths in here do *not* include the prefix
491             (map { $_ => $INSTR_LENGTHS{$_} } (0 .. 255)),
492             0x34 => 2, # INC (IX + d)
493             0x35 => 2, # DEC (IX + d)
494             0x36 => 3, # LD (IX + d), n
495             0x46 => 2, # LD B, (IX + n)
496             0x4E => 2, # LD C, (IX + n)
497             0x56 => 2, # LD D, (IX + n)
498             0x5E => 2, # LD E, (IX + n)
499             0x66 => 2, # LD H, (IX + n)
500             0x6E => 2, # LD L, (IX + n)
501             0x7E => 2, # LD A, (IX + n)
502             0x70 => 2, # LD (IX + n), B
503             0x71 => 2, # LD (IX + n), C
504             0x72 => 2, # LD (IX + n), D
505             0x73 => 2, # LD (IX + n), E
506             0x74 => 2, # LD (IX + n), H
507             0x75 => 2, # LD (IX + n), L
508             0x77 => 2, # LD (IX + n), A
509             0x86 => 2, # ADD A, (IX + n)
510             0x8E => 2, # ADC A, (IX + n)
511             0x96 => 2, # SUB A, (IX + n)
512             0x9E => 2, # SBC A, (IX + n)
513             0xA6 => 2, # AND (IX + n)
514             0xAE => 2, # XOR (IX + n)
515             0xB6 => 2, # OR (IX + n)
516             0xBE => 2, # CP (IX + n)
517             0xED => 1, # NOP
518             0xCB => { map { $_ => 2 } (0 .. 255) },
519             0xDD => { map { $_ => 1 } (0 .. 255) }, # magic
520             0xFD => { map { $_ => 1 } (0 .. 255) }, # magic
521             };
522              
523             # these are all passed a list of parameter bytes
524             %INSTR_DISPATCH = (
525             # un-prefixed instructions
526             0 => \&_NOP,
527             0b00001000 => sub { _swap_regs(shift(), qw(AF AF_)); },
528             0b00010000 => \&_DJNZ,
529             0b00011000 => \&_JR_unconditional,
530             (map { my $y = $_; ($_ << 3) => sub {
531             _check_cond($_[0], $TABLE_CC[$y - 4]) &&
532             _JR_unconditional(@_);
533             } } (4 .. 7)),
534             (map { my $p = $_; 0b00000001 | ($p << 4 ) => sub {
535             _LD_r16_imm(shift(), $TABLE_RP[$p], @_) # LD rp[p], nn
536             } } (0 .. 3)),
537             (map { my $p = $_; 0b00001001 | ($_ << 4 ) => sub {
538             _ADD_r16_r16(shift(), 'HL', $TABLE_RP[$p]) # ADD HL, rp[p]
539             } } (0 .. 3)),
540             0b00000010 => sub { _LD_indr16_r8($_[0], 'BC', 'A'); }, # LD (BC), A
541             0b00001010 => sub { _LD_r8_indr16($_[0], 'A', 'BC'); }, # LD A, (BC)
542             0b00010010 => sub { _LD_indr16_r8($_[0], 'DE', 'A'); }, # LD (DE), A
543             0b00011010 => sub { _LD_r8_indr16($_[0], 'A', 'DE'); }, # LD A, (DE)
544             0b00100010 => sub { _LD_ind_r16(shift(), 'HL', @_); }, # LD (nn), HL
545             0b00101010 => sub { _LD_r16_ind(shift(), 'HL', @_); }, #LD HL, (nn)
546             0b00110010 => sub { _LD_ind_r8(shift(), 'A', @_); }, # LD (nn), A
547             0b00111010 => sub { _LD_r8_ind(shift(), 'A', @_); }, #LD A, (nn)
548             (map {
549             my($p, $q) = (($_ & 0b110) >> 1, $_ & 0b1);
550             0b00000011 | ($_ << 3) => sub {
551             $q ? _DEC($_[0], $TABLE_RP[$p]) # DEC rp[p]
552             : _INC($_[0], $TABLE_RP[$p]) # INC rp[p]
553             }
554             } (0 .. 7)),
555             (map { my $y = $_; 0b00000100 | ($_ << 3) => sub {
556             _INC($_[0], $TABLE_R[$y], $_[1]) # INC r[y] or INC(IX/Y + d)
557             } } (0 .. 7)),
558             (map { my $y = $_; 0b00000101 | ($_ << 3) => sub {
559             _DEC($_[0], $TABLE_R[$y], $_[1]) # DEC r[y] or DEC(IX/Y + d)
560             } } (0 .. 7)),
561             (map { my $y = $_; 0b00000110 | ($_ << 3) => sub {
562             _LD_r8_imm(shift(), $TABLE_R[$y], @_) # LD r[y], n
563             } } (0 .. 7)),
564             0b00000111 => \&_RLCA,
565             0b00001111 => \&_RRCA,
566             0b00010111 => \&_RLA,
567             0b00011111 => \&_RRA,
568             0b00100111 => \&_DAA,
569             0b00101111 => \&_CPL,
570             0b00110111 => \&_SCF,
571             0b00111111 => \&_CCF,
572             (map { my $y = $_ >> 3; my $z = $_ & 0b111; 0b01000000 + $_ => sub {
573             _LD_r8_r8(shift(), $TABLE_R[$y], $TABLE_R[$z], shift()); # LD r[y], r[z]
574             } } (0 .. 0b111111)),
575             0b01110110 => \&_HALT,
576             (map { my $y = $_ >> 3; my $z = $_ & 0b111; 0b10000000 + $_ => sub {
577             $TABLE_ALU[$y]->(shift(), 'A', $TABLE_R[$z], shift()); # alu[y] A, r[z]
578             } } (0 .. 0b111111)),
579             (map { my $y = $_; 0b11000110 | ($_ << 3) => sub {
580             _LD_r8_imm($_[0], 'W', $_[1]); # alu[y] A, n
581             $TABLE_ALU[$y]->(shift(), 'A', 'W', shift());
582             } } (0 .. 7)),
583             (map { my $y = $_; 0b11000000 | ($_ << 3) => sub {
584             _check_cond($_[0], $TABLE_CC[$y]) && # RET cc[y]
585             _POP(shift(), 'PC');
586             } } (0 .. 7)),
587             (map { my $p = $_; 0b11000001 | ($_ << 4) => sub {
588             _POP(shift(), $TABLE_RP2[$p]); # POP rp2[p]
589             } } (0 .. 3)),
590             (map { my $y = $_; 0b11000010 | ($_ << 3) => sub {
591             _check_cond($_[0], $TABLE_CC[$y]) && # JP cc[y], nn
592             _JP_unconditional(@_);
593             } } (0 .. 7)),
594             (map { my $y = $_; 0b11000100 | ($_ << 3) => sub {
595             _check_cond($_[0], $TABLE_CC[$y]) && # CALL cc[y], nn
596             _CALL_unconditional(@_);
597             } } (0 .. 7)),
598             (map { my $y = $_; 0b11000111 | ($_ << 3) => sub {
599             _CALL_unconditional(shift(), $y * 8, 0); # RST y*8
600             } } (0 .. 7)),
601             0xC3 => \&_JP_unconditional,
602             0b11010011 => \&_OUT_n_A, # OUT (n), A
603             0b11011011 => \&_IN_A_n, # IN A, (n)
604             0b11100011 => sub { # EX (SP), HL
605             my $self = shift;
606             _POP($self, 'WZ'); _PUSH($self, 'HL');
607             _LD_r16_r16($self, 'HL', 'WZ');
608             },
609             0b11101011 => sub { _swap_regs(shift(), qw(DE HL)); },
610             0b11110011 => \&_DI,
611             0b11111011 => \&_EI,
612             (map { my $p = $_; 0b11000101 | ($_ << 4) => sub {
613             _PUSH(shift(), $TABLE_RP2[$p]); # PUSH rp2[p]
614             } } (0 .. 3)),
615             0xCD => \&_CALL_unconditional,
616             0b11001001 => sub { _POP(shift(), 'PC'); }, # RET
617             0b11011001 => \&_EXX,
618             0b11101001 => sub { _LD_r16_r16($_[0], 'PC', 'HL'); }, # JP HL
619             0b11111001 => sub { _LD_r16_r16($_[0], 'SP', 'HL'); }, # LD SP, HL
620              
621             # and finally, prefixed instructions
622             0xED, {
623             (map { $_ => \&_NOP } ( 0b00000000 .. 0b00111111,
624             0b11000000 .. 0b11111111)),
625             (map { my $y = $_; 0b01000000 | ($_ << 3) => sub {
626             _IN_r_C(shift(), $TABLE_R[$y]); # IN r[y], (C)
627             } } (0 .. 7)),
628             (map { my $y = $_; 0b01000001 | ($_ << 3) => sub {
629             _OUT_C_r(shift(), $TABLE_R[$y]); # OUT (C), r[y]
630             } } (0 .. 5, 7)),
631             0b01110001 => \&_OUT_C_0, # OUT (C), 0
632             (map { my $p = $_; 0b01000010 | ($_ << 4) => sub {
633             _SBC_r16_r16(shift(), 'HL', $TABLE_RP[$p]); # SBC HL, rp[p]
634             } } (0 .. 3)),
635             (map { my $p = $_; 0b01001010 | ($_ << 4) => sub {
636             _ADC_r16_r16(shift(), 'HL', $TABLE_RP[$p]); # ADC HL, rp[p]
637             } } (0 .. 3)),
638             (map { my $p = $_; 0b01000011 | ($_ << 4) => sub {
639             _LD_ind_r16(shift(), $TABLE_RP[$p], @_); # LD (nn), rp[p]
640             } } (0 .. 3)),
641             (map { my $p = $_; 0b01001011 | ($_ << 4) => sub {
642             _LD_r16_ind(shift(), $TABLE_RP[$p], @_); # LD rp[p], (nn)
643             } } (0 .. 3)),
644             (map { 0b01000100 | ($_ << 3) => \&_NEG } (0 .. 7)), # NEG
645             (map { 0b01000101 | ($_ << 3) => ($_== 1 ? \&_RETI : \&_RETN) }
646             (0 .. 7)),
647             (map { my $y = $_; 0b01000110 | ($_ << 3) => sub {
648             _IM(shift(), $y); # IM im[y]
649             } } (0 .. 7)),
650             0b01000111 => sub { _LD_r8_r8(shift(), 'I', 'A'); }, # LD I, A
651             0b01001111 => sub { _LD_r8_r8(shift(), 'R', 'A'); }, # LD R, A
652             0b01010111 => \&_LD_A_I, # LD A, I
653             0b01011111 => \&_LD_A_R, # LD A, R
654             0b01100111 => \&_RRD,
655             0b01101111 => \&_RLD,
656             0b01110111 => \&_NOP,
657             0b01111111 => \&_NOP,
658             # x=1 is all invalid ...
659             (map { 0b10000000 | $_ => \&_NOP } (0 .. 63)),
660             # ... except for z = 0,1,2,3 and y = 4,5,6,7
661             (map {
662             my $y = $_; (map {
663             my $z = $_;
664             0b10000000 | ($y << 3) | $z => sub {
665             $TABLE_BLI[$y - 4]->[$z]->(@_)
666             }
667             } (0 .. 3))
668             } (4 .. 7)),
669              
670             },
671             0xCB, {
672             (map { my $y = $_ >> 3; my $z = $_ & 7; 0b00000000 | $_ => sub {
673             $TABLE_ROT[$y]->($_[0], $TABLE_R[$z], $_[1]);
674             } } (0 .. 63)),
675             (map { my $y = $_ >> 3; my $z = $_ & 7; 0b01000000 | $_ => sub {
676             _BIT($_[0], $y, $TABLE_R[$z], $_[1]);
677             } } (0 .. 63)),
678             (map { my $y = $_ >> 3; my $z = $_ & 7; 0b10000000 | $_ => sub {
679             _RES($_[0], $y, $TABLE_R[$z], $_[1]);
680             } } (0 .. 63)),
681             (map { my $y = $_ >> 3; my $z = $_ & 7; 0b11000000 | $_ => sub {
682             _SET($_[0], $y, $TABLE_R[$z], $_[1]);
683             } } (0 .. 63)),
684             },
685             0xDD, {
686             (map { my $i = $_; $_ => sub {
687             $INSTR_DISPATCH{$i}->(@_);
688             } } (0 .. 255)),
689             0xED => \&_NOP,
690             0xDD => {
691             0b00000000 => sub { $_[0]->{STOPREACHED} = 1 },
692             },
693             0xFD => {
694             map { my $i = $_; $_ => sub {
695             $INSTR_DISPATCH{0xDD}->{0xDD}->{$i}->(@_)
696             } } (0 .. 255)
697             },
698             0xCB => {
699             # these are all DD CB offset OPCODE. Yuck
700             # the dispatcher calls DD->CB->offset passing the opcode
701             # as a param. This fixes things.
702             map { my $d = $_; $_ => sub {
703             $INSTR_DISPATCH{0xCB}->{$_[1]}->($_[0], $d)
704             } } (0 .. 255)
705             },
706             },
707             0xFD, {
708             (map{my $i=$_; $_=>sub {$INSTR_DISPATCH{$i}->(@_)}} (0 .. 255)),
709             0xED => \&_NOP,
710             0xDD => {
711             map { my $i = $_; $_ => sub {
712             $INSTR_DISPATCH{0xDD}->{0xDD}->{$i}->(@_)
713             } } (0 .. 255)
714             },
715             0xFD => {
716             map { my $i = $_; $_ => sub {
717             $INSTR_DISPATCH{0xDD}->{0xDD}->{$i}->(@_)
718             } } (0 .. 255)
719             },
720             0xCB => {
721             map { my $i = $_; $_ => sub {
722             $INSTR_DISPATCH{0xDD}->{0xCB}->{$i}->(@_)
723             } } (0 .. 255)
724             }
725             },
726             );
727              
728             sub nmi {
729 2     2 1 449 my $self = shift;
730 2         5 $self->{iff2} = $self->{iff1};
731 2         5 $self->{iff1} = 0;
732 2         6 $self->{NMI} = 1;
733             }
734             sub interrupt {
735 3     3 1 12 my $self = shift;
736 3 100       35 if(_interrupts_enabled($self)) {
737 1         3 $self->{INTERRUPT} = 1;
738 1         4 _DI($self);
739 1         5 return 1;
740             }
741 2         10 return 0;
742             }
743             sub _interrupts_enabled {
744 11     11   27 my($self, $toggle) = @_;
745 11 100       44 return $self->{iff1} if(!defined($toggle));
746 8         31 $self->{iff1} = $self->{iff2} = $toggle;
747             }
748              
749             sub run {
750 1344     1344 1 26531 my $self = shift;
751 1344         5497 my $instrs_to_execute = -1;
752 1344 100       11226 $instrs_to_execute = shift() if(@_);
753              
754 1344         5009 RUNLOOP: while($instrs_to_execute) {
755 1469         3668 delete $self->{STOPREACHED};
756 1469         2817 $instrs_to_execute--;
757 1469         14252 $self->{instr_length_table} = \%INSTR_LENGTHS;
758 1469         5611 $self->{instr_dispatch_table} = \%INSTR_DISPATCH;
759 1469         4353 $self->{prefix_bytes} = [];
760 1469 100       8111 if($self->{NMI}) {
    100          
761 1         3 delete $self->{NMI};
762 1         4 _DI($self);
763 1         4 _CALL_unconditional($self, 0x66, 0x00);
764             } elsif($self->{INTERRUPT}) {
765 1         3 delete $self->{INTERRUPT};
766 1         3 _DI($self);
767 1         5 $self->_execute(0xFF);
768 1467         9150 } else { $self->_execute($self->_fetch()); }
769 1468         16171 delete $self->{instr_length_table};
770 1468         3819 delete $self->{instr_dispatch_table};
771 1468         3995 delete $self->{prefix_bytes};
772 1468 100       11475 if($self->{STOPREACHED}) {
773 5         22 last RUNLOOP;
774             }
775             }
776             }
777              
778             sub stopped {
779 2     2 1 529 my $self = shift;
780 2         11 return exists($self->{STOPREACHED});
781             }
782              
783             # fetch all the bytes for an instruction and return them
784             sub _fetch {
785 3070     3070   5509 my $self = shift;
786 3070         8117 my $pc = $self->register('PC')->get();
787            
788 3070 100 100     15258 $self->register('R')->inc() # don't inc for DDCB and FDCB
      66        
789             unless(
790             $self->_got_prefix(0xCB) &&
791             ($self->_got_prefix(0xDD) || $self->_got_prefix(0xFD))
792             );
793 3070         14904 my $byte = $self->memory()->peek($pc);
794 3070         40209 my @bytes = ($byte);
795              
796             # prefix byte
797 3070 100       18909 if(ref($self->{instr_length_table}->{$byte})) {
798             # printf("Found prefix byte %#04x\n", $byte);
799 1603         6237 $self->{instr_dispatch_table} = $self->{instr_dispatch_table}->{$byte};
800 1603         4395 $self->{instr_length_table} = $self->{instr_length_table}->{$byte};
801 1603         4974 push @{$self->{prefix_bytes}}, $byte;
  1603         6175  
802 1603         5690 $self->register('PC')->inc(); # set($pc + 1);
803 1603         8775 return $self->_fetch();
804             }
805              
806 1467         10943 my $bytes_to_fetch = $self->{instr_length_table}->{$byte};
807            
808 0         0 die(sprintf(
809             "_fetch: Unknown instruction 0x%02X at 0x%04X with prefix bytes ["
810 0         0 .join(' ', map { "0x%02X" } @{$self->{prefix_bytes}})
  0         0  
811 1467 50       4513 ."]\n", $byte, $pc, @{$self->{prefix_bytes}}
812             )) if($bytes_to_fetch eq 'UNDEFINED');
813              
814 1467         5071 push @bytes, map { $self->memory()->peek($pc + $_) } (1 .. $bytes_to_fetch - 1);
  795         2609  
815 1467         15763 $self->register('PC')->set($pc + $bytes_to_fetch);
816 1467         12754 return @bytes;
817             }
818              
819             # execute an instruction. NB, the PC already points at the next instr
820             sub _execute {
821 1468     1468   3823 my($self, $instr) = (shift(), shift());
822 1468 100 66     74320 if(
      66        
823             exists($self->{instr_dispatch_table}->{$instr}) &&
824             ref($self->{instr_dispatch_table}->{$instr}) &&
825             reftype($self->{instr_dispatch_table}->{$instr}) eq 'CODE'
826             ) {
827 1467 100       13292 _swap_regs($self, qw(HL IX)) if($self->_got_prefix(0xDD));
828 1467 100       5096 _swap_regs($self, qw(HL IY)) if($self->_got_prefix(0xFD));
829 1467         10193 $self->{instr_dispatch_table}->{$instr}->($self, @_);
830 1467 100       54959 _swap_regs($self, qw(HL IY)) if($self->_got_prefix(0xFD));
831 1467 100       7068 _swap_regs($self, qw(HL IX)) if($self->_got_prefix(0xDD));
832             } else {
833 3         10 die(sprintf(
834             "_execute: No entry in dispatch table for instr "
835 1         3 .join(' ', map { "0x%02x" } (@{$self->{prefix_bytes}}, $instr))
  1         5  
836             ." of known length, near addr 0x%04x\n",
837 1         3 @{$self->{prefix_bytes}}, $instr, $self->register('PC')->get()
838             ));
839             }
840             }
841              
842             sub _got_prefix {
843 10358     10358   22914 my($self, $prefix) = @_;
844 10358         17298 return grep { $_ == $prefix } @{$self->{prefix_bytes}}
  10821         91240  
  10358         38549  
845             }
846              
847             sub _check_cond {
848 56     56   337 my($self, $cond) = @_;
849 56         261 my $f = $self->register('F');
850             return
851 56 100       1541 $cond eq 'NC' ? !$f->getC() :
    100          
    100          
    100          
    100          
    100          
    100          
852             $cond eq 'C' ? $f->getC() :
853             $cond eq 'NZ' ? !$f->getZ() :
854             $cond eq 'Z' ? $f->getZ() :
855             $cond eq 'PO' ? !$f->getP() :
856             $cond eq 'PE' ? $f->getP() :
857             $cond eq 'P' ? !$f->getS() :
858             $f->getS()
859             }
860              
861             sub _ADD_r16_r16 {
862 20     20   62 my($self, $r1, $r2, $c) = @_;
863             # $c is defined if this is really SBC
864 20         48 my $adc = 0 + defined($c);
865 20   100     125 $c ||= 0;
866 20         65 $self->register($r1)->add($self->register($r2)->get() + $c, $adc);
867             }
868             sub _ADC_r16_r16 {
869             # ADC also frobs S, Z and P, unlike ADD. argh. the magic $c
870             # will communicate that
871 4     4   29 _ADD_r16_r16(@_, $_[0]->register('F')->getC());
872             }
873 15     15   87 sub _ADC_r8_r8 { _ADD_r8_r8(@_[0..3], $_[0]->register('F')->getC()); }
874             sub _ADD_r8_r8 {
875 30     30   116 my($self, $r1, $r2, $d, $c) = @_;
876             # $c is defined if this is really ADC
877 30   100     268 $c ||= 0;
878 30 100       119 _LD_r8_indHL($self, 'W', $d) if($r2 eq '(HL)');
879 30         105 $self->register($r1)->add($self->register($r2)->get() + $c);
880             }
881 192     192   1359 sub _RES { _RES_SET($_[0], 0, @_[1 .. $#_]); }
882 192     192   1486 sub _SET { _RES_SET($_[0], 1, @_[1 .. $#_]); }
883             sub _RES_SET {
884 384     384   1868 my($self, $value, $bit, $r, $d) = @_;
885              
886 384 100 100     2314 if(defined($d) && $r ne '(HL)') { # weirdo DDCB*
887 224         417 my $realr = $r;
888 224 100       1702 $realr .= $self->_got_prefix(0xDD) ? 'IX' : 'IY'
    100          
889             if($realr =~ /^[HL]$/);
890 224         735 $r = '(HL)';
891 224         1959 _LD_r8_indHL($self, 'W', $d);
892 224         1226 $self->register($r)->set( # RES by default
893             $self->register($r)->get() & (255 - 2**$bit)
894             );
895 224 100       1221 $self->register($r)->set( # SET if asked to
896             $self->register($r)->get() | (2**$bit)
897             ) if($value);
898 224 50       1977 _LD_indHL_r8($self, 'W', $d) if($r eq '(HL)');
899 224         55566 _LD_r8_r8($self, $realr, 'W');
900             } else {
901 160         7509 _LD_r8_indHL($self, 'W', $d);
902 160         936 $self->register($r)->set( # RES by default
903             $self->register($r)->get() & (255 - 2**$bit)
904             );
905 160 100       1512 $self->register($r)->set( # SET if asked to
906             $self->register($r)->get() | (2**$bit)
907             ) if($value);
908 160 100       1200 _LD_indHL_r8($self, 'W', $d) if($r eq '(HL)');
909             }
910              
911             }
912             sub _BIT {
913 200     200   863 my($self, $bit, $r, $d) = @_; # $d is for DDCB/FFCB - NYI
914            
915 200         551 my $realr = $r;
916 200 100       2621 $r = '(HL)' if(defined($d));
917              
918 200 100       1550 _LD_r8_indHL($self, 'W', $d) if($r eq '(HL)');
919              
920 200         1200 my $f = $self->register('F');
921 200         2569 $f->setZ(!($self->register($r)->get() & 2**$bit));
922 200         1786 $f->setH();
923 200         2248 $f->resetN();
924 200   100     2836 $f->setS($bit == 7 && $self->register($r)->get() & 0x80);
925 200         1178 $f->setP($self->register('F')->getZ());
926 200         1056 $f->set5($self->register($r)->get() & 0b100000);
927 200         860 $f->set3($self->register($r)->get() & 0b1000);
928 200 100       2487 if(defined($d)) {
929 128         491 $f->set5(((ALU_getsigned($d, 8) + $self->register('HL')->get()) >> 8) & 0b100000);
930 128         1209 $f->set3(((ALU_getsigned($d, 8) + $self->register('HL')->get()) >> 8) & 0b1000);
931             }
932             }
933              
934             sub _binop {
935 45     45   162 my($self, $r1, $r2, $d, $op) = @_;
936             # $r1 is always A, $r2 is A/B/C/D/EH/L/(HL)/W/Z
937 45 100       240 _LD_r8_indHL($self, 'W', $d) if($r2 eq '(HL)');
938             # if($r2 eq '(HL)') {
939             # my @addr = map { $self->register($_)->get()} qw(L H);
940             # _LD_r8_ind($self, 'W', @addr);
941             # $r2 = 'W';
942             # }
943 45         203 $self->register($r1)->set(eval
944             '$self->register($r1)->get() '.$op.' $self->register($r2)->get()'
945             );
946 45 50       408 die($@) if($@);
947 45         155 $self->register('F')->setS($self->register($r1)->get() & 0x80);
948 45         229 $self->register('F')->setZ($self->register($r1)->get() == 0);
949 45         219 $self->register('F')->set5($self->register($r1)->get() & 0b100000);
950 45         202 $self->register('F')->setH($op eq '&');
951 45         169 $self->register('F')->set3($self->register($r1)->get() & 0b1000);
952 45         472 $self->register('F')->setP(ALU_parity($self->register($r1)->get()));
953 45         388 $self->register('F')->resetN();
954 45         159 $self->register('F')->resetC();
955             }
956 15     15   83 sub _AND_r8_r8 { _binop(@_, '&'); }
957 15     15   90 sub _OR_r8_r8 { _binop(@_, '|'); }
958 15     15   119 sub _XOR_r8_r8 { _binop(@_, '^'); }
959 15     15   91 sub _SBC_r8_r8 { _SUB_r8_r8(@_[0 .. 3], $_[0]->register('F')->getC()); }
960 4     4   20 sub _SBC_r16_r16 { _SUB_r16_r16(@_, $_[0]->register('F')->getC()); }
961             sub _SUB_r8_r8 {
962 67     67   273 my($self, $r1, $r2, $d, $c) = @_;
963             # $c is defined if this is really SBC
964 67   100     677 $c ||= 0;
965 67 50       296 die("Can't SUB with Z reg") if($r2 eq 'Z');
966 67 100       285 _LD_r8_indHL($self, 'W', $d) if($r2 eq '(HL)');
967 67         697 $self->register($r1)->sub($self->register($r2)->get() + $c);
968             }
969             sub _SUB_r16_r16 {
970 4     4   20 my($self, $r1, $r2, $c) = @_;
971             # $c is defined if this is really SBC
972 4   50     17 $c ||= 0;
973 4         15 $self->register($r1)->sub($self->register($r2)->get() + $c);
974             }
975             sub _CP_r8_r8 {
976             # $r1 is always A, $r2 is A/B/C/D/EH/L/(HL)/W
977 29     29   104 my($self, $r1, $r2, $d) = @_;
978              
979             # bleh, CP uses the *operand* to set flags 3 and 5, instead of
980             # the result, so wrap SUB and correct afterwards.
981             # this is why we can't SUB with the Z reg
982 29         136 _LD_r8_r8($self, 'Z', $r1); # preserve r1
983 29         274 _SUB_r8_r8($self, $r1, $r2, $d);
984             # put result into Z - this is used by CPI
985 29         325 _swap_regs($self, $r1, 'Z'); # restore r1, result into Z
986 29         124 $self->register('F')->set5($self->register($r2)->get() & 0b100000);
987 29         117 $self->register('F')->set3($self->register($r2)->get() & 0b1000);
988             }
989             sub _DEC {
990 20     20   83 my($self, $r, $d) = @_;
991 20 100       121 _LD_r8_indHL($self, 'W', $d) if($r eq '(HL)');
992 20         74 $self->register($r)->dec();
993 20 100       133 _LD_indHL_r8($self, 'W', $d) if($r eq '(HL)');
994             # my($self, $r) = @_;
995             # if($r eq '(HL)') {
996             # my @addr = map { $self->register($_)->get()} qw(L H);
997             # _LD_r8_ind($self, 'W', @addr);
998             # $self->register('W')->dec();
999             # _LD_ind_r8($self, 'W', @addr);
1000             # } else {
1001             # $self->register($r)->dec();
1002             # }
1003             }
1004             sub _EXX {
1005 1     1   3 my $self = shift;
1006 1         6 _swap_regs($self, qw(BC BC_));
1007 1         4 _swap_regs($self, qw(DE DE_));
1008 1         4 _swap_regs($self, qw(HL HL_));
1009              
1010             }
1011             sub _DJNZ {
1012 12     12   18 my($self, $offset) = @_;
1013              
1014 12         28 _LD_r8_r8($self, 'W', 'F'); # preserve flags
1015              
1016 12         39 $self->register('B')->dec(); # decrement B and ...
1017 12 100       43 if($self->register('B')->get()) { # jump if not zero
1018 10         23 $self->register('PC')->set(
1019             $self->register('PC')->get() +
1020             ALU_getsigned($offset, 8)
1021             );
1022             }
1023 12         54 _LD_r8_r8($self, 'F', 'W'); # restore flags
1024             }
1025 1     1   8 sub _HALT { shift()->register('PC')->dec(); select(undef, undef, undef, 0.01) }
  1         10939  
1026             sub _INC {
1027 21     21   171 my($self, $r, $d) = @_;
1028 21 100       112 _LD_r8_indHL($self, 'W', $d) if($r eq '(HL)');
1029 21         144 $self->register($r)->inc();
1030 21 100       138 _LD_indHL_r8($self, 'W', $d) if($r eq '(HL)');
1031             }
1032             sub _LDI {
1033 26     26   39 my $self = shift;
1034 26         66 my $f = $self->register('F');
1035 26         268 _LD_r8_indr16($self, 'W', 'HL'); # get from (HL);
1036 26         105 _LD_indr16_r8($self, 'DE', 'W'); # put to (DE);
1037 26         14094 $self->register('DE')->inc();
1038 26         118 $self->register('HL')->inc();
1039 26         76 $self->register('BC')->dec();
1040 26         115 $f->set5(($self->register('A')->get() + $self->register('W')->get()) & 2);
1041 26         101 $f->set3(($self->register('A')->get() + $self->register('W')->get()) & 8);
1042 26         96 $f->setP($self->register('BC')->get() != 0);
1043 26         190 $f->resetN();
1044 26         124 $f->resetH();
1045             }
1046             sub _LDIR {
1047 16     16   25 my $self = shift;
1048 16         36 _LDI($self);
1049 16 100       41 $self->register('PC')->set($self->register('PC')->get() - 2)
1050             if($self->register('BC')->get());
1051             }
1052             sub _LDD {
1053 9     9   14 my $self = shift;
1054 9         29 _LDI($self); # cheat, do an LDI then correct HL and DE
1055 9         41 _swap_regs($self, qw(W F));
1056 9         34 $self->register('DE')->sub(2);
1057 9         98 $self->register('HL')->sub(2);
1058 9         46 _swap_regs($self, qw(W F));
1059             }
1060             sub _LDDR {
1061 8     8   13 my $self = shift;
1062 8         20 _LDD($self);
1063 8 100       27 $self->register('PC')->set($self->register('PC')->get() - 2)
1064             if($self->register('BC')->get());
1065             }
1066             sub _CPI {
1067 14     14   35 my $self = shift;
1068 14         198 my $f = $self->register('F');
1069 14         233 my $c = $f->getC();
1070 14         136 _CP_r8_r8($self, 'A', '(HL)'); # Z = A - (HL), S/Z/H now set OK
1071 14         54 $self->register('HL')->inc();
1072 14         45 $self->register('BC')->dec();
1073 14         64 $f->setP($self->register('BC')->get() != 0);
1074 14         932 $f->setC($c);
1075 14         71 $f->setN();
1076 14         54 $f->set5(
1077             ($self->register('Z')->get() - $f->getH()) & 0b10
1078             );
1079 14         58 $f->set3(
1080             ($self->register('Z')->get() - $f->getH()) & 0b1000
1081             );
1082             }
1083             sub _CPIR {
1084 4     4   9 my $self = shift;
1085 4         121 _CPI($self);
1086 4 100 66     47 $self->register('PC')->set($self->register('PC')->get() - 2)
1087             if($self->register('BC')->get() && $self->register('Z')->get());
1088            
1089             }
1090             sub _CPD {
1091 9     9   16 my $self = shift;
1092 9         28 _CPI($self); # cheat, do a CPI then correct HL
1093 9         38 _swap_regs($self, qw(W F));
1094 9         27 $self->register('HL')->sub(2);
1095 9         34 _swap_regs($self, qw(W F));
1096             }
1097             sub _CPDR {
1098 8     8   15 my $self = shift;
1099 8         19 _CPD($self);
1100 8 100 66     26 $self->register('PC')->set($self->register('PC')->get() - 2)
1101             if($self->register('BC')->get() && $self->register('Z')->get());
1102             }
1103             sub _RLD {
1104 1     1   3 my $self = shift;
1105 1         4 my($a, $f, $w, $z) = map { $self->register($_) } (qw(A F W Z));
  4         31  
1106 1         14 _LD_r8_indHL($self, 'W'); # get (HL)
1107 1         6 $z->set($a->get() & 0x0F);
1108 1         5 $a->set(($a->get() & 0xF0) | ($w->get() & 0xF0) >> 4);# A now kosher
1109 1         4 $w->set(($w->get() << 4) | $z->get()); # W now correct
1110 1         15 _LD_indHL_r8($self, 'W'); # (HL) now correct
1111 1         138 $f->setS($a->get() & 0x80);
1112 1         7 $f->setZ($a->get() == 0);
1113 1         4 $f->set5($a->get() & 0b100000);
1114 1         5 $f->set3($a->get() & 0b1000);
1115 1         3 $f->setP(ALU_parity($a->get()));
1116 1         6 $f->resetH();
1117 1         6 $f->resetN();
1118             }
1119             sub _RRD {
1120 1     1   4 my $self = shift;
1121 1         4 my($a, $f, $w, $z) = map { $self->register($_) } (qw(A F W Z));
  4         31  
1122 1         14 _LD_r8_indHL($self, 'W'); # get (HL)
1123 1         7 $z->set($a->get() << 4);
1124 1         4 $a->set(($a->get() & 0xF0) | ($w->get() & 0x0F)); # A now correct
1125 1         5 $w->set(($w->get() >> 4) | $z->get()); # W now correct
1126 1         6 _LD_indHL_r8($self, 'W'); # (HL) now correct
1127 1         143 $f->setS($a->get() & 0x80);
1128 1         6 $f->setZ($a->get() == 0);
1129 1         5 $f->set5($a->get() & 0b100000);
1130 1         6 $f->set3($a->get() & 0b1000);
1131 1         4 $f->setP(ALU_parity($a->get()));
1132 1         8 $f->resetH();
1133 1         8 $f->resetN();
1134             }
1135             sub _JR_unconditional {
1136 6     6   19 my($self, $offset) = @_;
1137 6         30 $self->register('PC')->set(
1138             $self->register('PC')->get() +
1139             ALU_getsigned($offset, 8)
1140             );
1141             }
1142             sub _JP_unconditional {
1143 28     28   139 _LD_r16_imm(shift(), 'PC', @_);
1144             }
1145             sub _CALL_unconditional {
1146 19     19   176 _PUSH($_[0], 'PC');
1147 19         3375 _JP_unconditional(@_);
1148             }
1149             sub _LD_ind_r16 {
1150 8     8   37 my($self, $r16, @bytes) = @_;
1151 8         31 $self->memory()->poke16($bytes[0] + 256 * $bytes[1], $self->register($r16)->get())
1152             }
1153             sub _LD_ind_r8 {
1154 22     22   99 my($self, $r8, @bytes) = @_;
1155 22         79 $self->memory()->poke($bytes[0] + 256 * $bytes[1], $self->register($r8)->get())
1156             }
1157             sub _LD_indHL_r8 {
1158 425     425   1130 my($self, $r8, $d) = @_;
1159 425   100     2229 $d = ALU_getsigned($d || 0, 8);
1160 425         1829 $self->memory()->poke($d + $self->register('HL')->get(), $self->register($r8)->get())
1161             }
1162             sub _LD_indr16_r8 {
1163 28     28   51 my($self, $r16, $r8) = @_;
1164 28         78 $self->memory()->poke($self->register($r16)->get(), $self->register($r8)->get());
1165             }
1166             sub _LD_r16_imm {
1167             # self, register, lo, hi
1168 60     60   111 my $self = shift;
1169 60         198 $self->register(shift())->set(shift() + 256 * shift());
1170             }
1171             sub _LD_r8_imm {
1172             # self, register, data
1173 42     42   140 my($self, $r, $d, $byte) = @_;
1174             # yuck, (IX+d) puts d first
1175 42 100       222 ($d, $byte) = ($byte, $d) if(!defined($byte));
1176 42         166 $self->register($r)->set($byte);
1177 42 100       300 _LD_indHL_r8($self, 'W', $d) if($r eq '(HL)');
1178             }
1179             sub _LD_r16_ind {
1180 8     8   28 my($self, $r16, @bytes) = @_;
1181 8         34 $self->register($r16)->set($self->memory()->peek16($bytes[0] + 256 * $bytes[1]));
1182             }
1183             sub _LD_r8_indr16 {
1184 28     28   58 my($self, $r8, $r16) = @_;
1185 28         77 $self->register($r8)->set($self->memory()->peek($self->register($r16)->get()));
1186             }
1187             sub _LD_r8_ind {
1188 22     22   80 my($self, $r8, @bytes) = @_;
1189 22         77 $self->register($r8)->set($self->memory()->peek($bytes[0] + 256 * $bytes[1]));
1190             }
1191             sub _LD_r8_indHL {
1192 702     702   1973 my($self, $r8, $d) = @_;
1193 702   100     7711 $d = ALU_getsigned($d || 0, 8);
1194 702         2879 $self->register($r8)->set($self->memory()->peek($d + $self->register('HL')->get()));
1195             }
1196             sub _LD_r16_r16 {
1197 9     9   74 my($self, $r1, $r2) = @_;
1198 9         46 $self->register($r1)->set($self->register($r2)->get());
1199             }
1200             sub _LD_r8_r8 {
1201 542     542   1902 my($self, $r1, $r2, $d) = @_;
1202             # print "_LD_r8_r8 $r1, $r2 $d\n" if($d);
1203 542 100 100     7350 if(defined($d) && $r2 eq '(HL)' && $r1 =~ /^[HL]$/) { # LD H/L, (IX/IY+d)
    100 100        
      100        
      100        
1204 4 100       19 $r1 .= $self->_got_prefix(0xDD) ? 'IX' : 'IY';
1205             } elsif(defined($d) && $r1 eq '(HL)' && $r2 =~ /^[HL]$/) { # LD (IX/IY+d), H/L
1206 4 100       24 $r2 .= $self->_got_prefix(0xDD) ? 'IX' : 'IY';
1207             }
1208 542         2165 my $addr = $self->register('HL')->get() + ALU_getsigned($d, 8);
1209 542         2514 my @addr = ($addr & 0xFF, $addr >> 8);
1210 542 100       2678 if($r2 eq '(HL)') {
1211 21         108 _LD_r8_ind($self, 'W', @addr);
1212 21         73 $r2 = 'W';
1213             }
1214 542 100       1600 if($r1 eq '(HL)') {
1215 21         144 _LD_ind_r8($self, $r2, @addr);
1216             } else {
1217 521         3021 $self->register($r1)->set($self->register($r2)->get());
1218             }
1219             }
1220             # special casesof LD_r8_r8 which also frob some flags
1221 1     1   7 sub _LD_A_R { _LD_A_IR(shift(), 'R'); }
1222 1     1   7 sub _LD_A_I { _LD_A_IR(shift(), 'I'); }
1223             sub _LD_A_IR {
1224 2     2   11 my($self, $r2) = @_;
1225 2         7 my($a, $f) = map { $self->register($_) } qw(A F);
  4         29  
1226 2         28 _LD_r8_r8($self, 'A', $r2);
1227 2         29 $f->resetH();
1228 2         16 $f->resetN();
1229 2         9 $f->set5($a->get() & 0b100000);
1230 2         10 $f->set3($a->get() & 0b1000);
1231 2         9 $f->setS($a->get() & 0x80);
1232 2         7 $f->setZ($a->get() == 0);
1233 2         259 $f->setP($self->{iff2});
1234             }
1235             sub _NEG {
1236 8     8   28 my $self = shift();
1237 8         61 _LD_r8_imm($self, 'W', 0);
1238 8         50 _SUB_r8_r8($self, 'W', 'A');
1239 8         195 _LD_r8_r8($self, 'A', 'W');
1240             }
1241 26     26   44 sub _NOP { }
1242             sub _RLCA {
1243 25     25   112 my $self = shift;
1244 25         81 $self->register('A')->set(
1245             (($self->register('A')->get() & 0b01111111) << 1) |
1246             (($self->register('A')->get() & 0b10000000) >> 7)
1247             );
1248 25         158 $self->register('F')->resetH();
1249 25         174 $self->register('F')->resetN();
1250 25         111 $self->register('F')->set5($self->register('A')->get() & 0b100000);
1251 25         111 $self->register('F')->set3($self->register('A')->get() & 0b1000);
1252 25         177 $self->register('F')->setC($self->register('A')->get() & 1);
1253             }
1254             sub _RRCA {
1255 25     25   49 my $self = shift;
1256 25         80 $self->register('A')->set(
1257             (($self->register('A')->get() & 0b11111110) >> 1) |
1258             (($self->register('A')->get() & 1) << 7)
1259             );
1260 25         118 $self->register('F')->resetH();
1261 25         118 $self->register('F')->resetN();
1262 25         5512 $self->register('F')->set5($self->register('A')->get() & 0b100000);
1263 25         111 $self->register('F')->set3($self->register('A')->get() & 0b1000);
1264 25         110 $self->register('F')->setC($self->register('A')->get() & 0x80);
1265             }
1266             sub _RLA {
1267 25     25   50 my $self = shift;
1268 25         100 my $msb = $self->register('A')->get() & 0b10000000;
1269 25         106 $self->register('A')->set(
1270             (($self->register('A')->get() & 0b01111111) << 1) |
1271             $self->register('F')->getC()
1272             );
1273 25         161 $self->register('F')->setC($msb);
1274 25         136 $self->register('F')->resetH();
1275 25         98 $self->register('F')->resetN();
1276             }
1277             sub _RRA {
1278 25     25   48 my $self = shift;
1279 25         103 my $lsb = $self->register('A')->get() & 1;
1280 25         92 my $c = $self->register('F')->getC();
1281 25         112 $self->register('A')->set(
1282             (($self->register('A')->get() & 0b11111110) >> 1) |
1283             ($c << 7)
1284             );
1285 25         92 $self->register('F')->setC($lsb);
1286 25         169 $self->register('F')->resetH();
1287 25         92 $self->register('F')->resetN();
1288             }
1289             # generic wrapper for CB prefixed ROTs - wrap around A-reg version
1290             # and also diddle P/S/Z flags
1291             sub _cb_rot {
1292 96     96   489 my($self, $fn, $r, $d) = @_;
1293              
1294 96 100 100     929 if(defined($d) && $r ne '(HL)') {
1295 56 100       495 $r .= $self->_got_prefix(0xDD) ? 'IX' : 'IY' if($r =~ /^[HL]$/);
    100          
1296 56         156 my $realr = $r;
1297 56         235 $r = '(HL)';
1298 56 50       430 _LD_r8_indHL($self, 'W', $d) if($r eq '(HL)');
1299 56 50       550 _swap_regs($self, $r, 'A') if($r ne 'A'); # preserve A, mv r to A
1300 56         226 $fn->($self);
1301 56 50       405 _swap_regs($self, $r, 'A') if($r ne 'A'); # swap back again
1302 56 50       438 _LD_indHL_r8($self, 'W', $d) if($r eq '(HL)');
1303 56         9218 _LD_r8_r8($self, $realr, 'W');
1304             } else {
1305 40 100       168 _LD_r8_indHL($self, 'W', $d) if($r eq '(HL)');
1306 40 100       243 _swap_regs($self, $r, 'A') if($r ne 'A'); # preserve A, mv r to A
1307 40         170 $fn->($self);
1308 40 100       252 _swap_regs($self, $r, 'A') if($r ne 'A'); # swap back again
1309 40 100       211 _LD_indHL_r8($self, 'W', $d) if($r eq '(HL)');
1310             }
1311              
1312             # now frob extra flags
1313 96         2393 $self->register('F')->setP(ALU_parity($self->register($r)->get()));
1314 96         539 $self->register('F')->setS($self->register($r)->get() & 0x80);
1315 96         521 $self->register('F')->setZ($self->register($r)->get() == 0);
1316             }
1317             sub _RLC {
1318 24     24   108 my($self, $r, $d) = @_;
1319 24         173 $self->_cb_rot(\&_RLCA, $r, $d);
1320             }
1321             sub _RRC {
1322 24     24   94 my($self, $r, $d) = @_;
1323 24         5355 _cb_rot($self, \&_RRCA, $r, $d);
1324             }
1325             sub _RL {
1326 24     24   97 my($self, $r, $d) = @_;
1327 24         439 _cb_rot($self, \&_RLA, $r, $d);
1328              
1329             # extra flags not done by _cb_rot
1330 24 100       174 $r .= $self->_got_prefix(0xDD) ? 'IX' :
    100          
    100          
1331             $self->_got_prefix(0xFD) ? 'IY' : ''
1332             if($r =~ /^[HL]$/);
1333 24         66 $self->register('F')->set5($self->register($r)->get() & 0b100000);
1334 24         106 $self->register('F')->set3($self->register($r)->get() & 0b1000);
1335             }
1336             sub _RR {
1337 24     24   73 my($self, $r, $d) = @_;
1338 24         212 _cb_rot($self, \&_RRA, $r, $d);
1339 24 100       159 $r .= $self->_got_prefix(0xDD) ? 'IX' :
    100          
    100          
1340             $self->_got_prefix(0xFD) ? 'IY' : ''
1341             if($r =~ /^[HL]$/);
1342 24         82 $self->register('F')->set5($self->register($r)->get() & 0b100000);
1343 24         131 $self->register('F')->set3($self->register($r)->get() & 0b1000);
1344             }
1345             sub _SLA {
1346 24     24   103 my($self, $r, $d) = @_;
1347              
1348 24 100 100     470 if(defined($d) && $r ne '(HL)') { # weirdo DDCB*
1349 14         36 my $realr = $r;
1350 14 100       175 $realr .= $self->_got_prefix(0xDD) ? 'IX' : 'IY'
    100          
1351             if($realr =~ /^[HL]$/);
1352 14         34 $r = '(HL)';
1353 14         82 _LD_r8_indHL($self, 'W', $d);
1354 14         65 $self->register('F')->setC($self->register($r)->get() & 0x80);
1355 14         67 $self->register($r)->set($self->register($r)->get() << 1);
1356 14         99 _LD_indHL_r8($self, 'W', $d);
1357 14         701792 _LD_r8_r8($self, $realr, 'W');
1358             } else {
1359 10 100       193 _LD_r8_indHL($self, 'W', $d) if($r eq '(HL)');
1360 10         38 $self->register('F')->setC($self->register($r)->get() & 0x80);
1361 10         140 $self->register($r)->set($self->register($r)->get() << 1);
1362 10 100       78 _LD_indHL_r8($self, 'W', $d) if($r eq '(HL)');
1363             }
1364              
1365 24         1878 $self->register('F')->setZ($self->register($r)->get() == 0);
1366 24         151 $self->register('F')->set5($self->register($r)->get() & 0b100000);
1367 24         107 $self->register('F')->set3($self->register($r)->get() & 0b1000);
1368 24         118 $self->register('F')->setP(ALU_parity($self->register($r)->get()));
1369 24         432 $self->register('F')->setS($self->register($r)->get() & 0x80);
1370 24         118 $self->register('F')->resetH();
1371 24         99 $self->register('F')->resetN();
1372             }
1373             sub _SLL {
1374 24     24   101 my($self, $r, $d) = @_;
1375              
1376 24 100 100     189 if(defined($d) && $r ne '(HL)') { # weirdo DDCB*
1377 14         49 my $realr = $r;
1378 14 100       156 $realr .= $self->_got_prefix(0xDD) ? 'IX' : 'IY'
    100          
1379             if($realr =~ /^[HL]$/);
1380 14         25 $r = '(HL)';
1381 14         82 _LD_r8_indHL($self, 'W', $d);
1382 14         67 $self->register('F')->setC($self->register($r)->get() & 0x80);
1383 14         113 $self->register($r)->set($self->register($r)->get() << 1);
1384 14         65 $self->register($r)->set($self->register($r)->get() | 1);
1385 14         103 _LD_indHL_r8($self, 'W', $d);
1386 14         4125 _LD_r8_r8($self, $realr, 'W');
1387             } else {
1388 10 100       135 _LD_r8_indHL($self, 'W', $d) if($r eq '(HL)');
1389 10         52 $self->register('F')->setC($self->register($r)->get() & 0x80);
1390 10         55 $self->register($r)->set($self->register($r)->get() << 1);
1391 10         45 $self->register($r)->set($self->register($r)->get() | 1);
1392 10 100       70 _LD_indHL_r8($self, 'W', $d) if($r eq '(HL)');
1393             }
1394              
1395 24         494 $self->register('F')->setZ($self->register($r)->get() == 0);
1396 24         115 $self->register('F')->set5($self->register($r)->get() & 0b100000);
1397 24         94 $self->register('F')->set3($self->register($r)->get() & 0b1000);
1398 24         112 $self->register('F')->setP(ALU_parity($self->register($r)->get()));
1399 24         149 $self->register('F')->setS($self->register($r)->get() & 0x80);
1400 24         132 $self->register('F')->resetH();
1401 24         96 $self->register('F')->resetN();
1402             }
1403             sub _SRA {
1404 24     24   112 my($self, $r, $d) = @_;
1405              
1406 24 100 100     256 if(defined($d) && $r ne '(HL)') { # weirdo DDCB*
1407 14         35 my $realr = $r;
1408 14 100       197 $realr .= $self->_got_prefix(0xDD) ? 'IX' : 'IY'
    100          
1409             if($realr =~ /^[HL]$/);
1410 14         38 $r = '(HL)';
1411 14         65 _LD_r8_indHL($self, 'W', $d);
1412 14         80 $self->register('F')->setC($self->register($r)->get() & 1);
1413 14         79 $self->register($r)->set(
1414             ($self->register($r)->get() & 0x80) |
1415             ($self->register($r)->get() >> 1)
1416             );
1417 14         103 _LD_indHL_r8($self, 'W', $d);
1418 14         3523 _LD_r8_r8($self, $realr, 'W');
1419             } else {
1420 10 100       68 _LD_r8_indHL($self, 'W', $d) if($r eq '(HL)');
1421 10         39 $self->register('F')->setC($self->register($r)->get() & 1);
1422 10         56 $self->register($r)->set(
1423             ($self->register($r)->get() & 0x80) |
1424             ($self->register($r)->get() >> 1)
1425             );
1426 10 100       74 _LD_indHL_r8($self, 'W', $d) if($r eq '(HL)');
1427             }
1428              
1429 24         732 $self->register('F')->setZ($self->register($r)->get() == 0);
1430 24         117 $self->register('F')->set5($self->register($r)->get() & 0b100000);
1431 24         110 $self->register('F')->set3($self->register($r)->get() & 0b1000);
1432 24         108 $self->register('F')->setP(ALU_parity($self->register($r)->get()));
1433 24         155 $self->register('F')->setS($self->register($r)->get() & 0x80);
1434 24         173 $self->register('F')->resetH();
1435 24         97 $self->register('F')->resetN();
1436             }
1437             sub _SRL {
1438 24     24   80 my($self, $r, $d) = @_;
1439              
1440 24 100 100     204 if(defined($d) && $r ne '(HL)') { # weirdo DDCB*
1441 14         34 my $realr = $r;
1442 14 100       142 $realr .= $self->_got_prefix(0xDD) ? 'IX' : 'IY'
    100          
1443             if($realr =~ /^[HL]$/);
1444 14         27 $r = '(HL)';
1445 14         69 _LD_r8_indHL($self, 'W', $d);
1446 14         67 $self->register('F')->setC($self->register($r)->get() & 1);
1447 14         68 $self->register($r)->set(
1448             ($self->register($r)->get() & 0x80) |
1449             ($self->register($r)->get() >> 1)
1450             );
1451 14         96 $self->register($r)->set($self->register($r)->get() & 0x7F);
1452 14         100 _LD_indHL_r8($self, 'W', $d);
1453 14         2074 _LD_r8_r8($self, $realr, 'W');
1454             } else {
1455 10 100       441 _LD_r8_indHL($self, 'W', $d) if($r eq '(HL)');
1456 10         47 $self->register('F')->setC($self->register($r)->get() & 1);
1457 10         48 $self->register($r)->set(
1458             ($self->register($r)->get() & 0x80) |
1459             ($self->register($r)->get() >> 1)
1460             );
1461 10         473 $self->register($r)->set($self->register($r)->get() & 0x7F);
1462 10 100       92 _LD_indHL_r8($self, 'W', $d) if($r eq '(HL)');
1463             }
1464              
1465 24         490 $self->register('F')->setZ($self->register($r)->get() == 0);
1466 24         116 $self->register('F')->set5($self->register($r)->get() & 0b100000);
1467 24         117 $self->register('F')->set3($self->register($r)->get() & 0b1000);
1468 24         115 $self->register('F')->setP(ALU_parity($self->register($r)->get()));
1469 24         108 $self->register('F')->setS($self->register($r)->get() & 0x80);
1470 24         114 $self->register('F')->resetH();
1471 24         89 $self->register('F')->resetN();
1472             }
1473             sub _DAA {
1474 2     2   8 my $self = shift;
1475 2         9 my $a = $self->register('A');
1476 2         23 my $f = $self->register('F');
1477 2         50 my($n, $h, $lo, $hi) =
1478             ($f->getN(), $f->getH(),
1479             $a->get() & 0x0F, ($a->get() >> 4) & 0x0F);
1480 2         44 my $table = [
1481             # NB this table comes from Sean Young's "The Undocumented
1482             # Z80 Documented". Zaks is wrong.
1483             # http://www.z80.info/zip/z80-documented.pdf
1484             # C high H low add Cafter
1485             [qw(0 0-9 0 0-9 0 0)],
1486             [qw(0 0-9 1 0-9 6 0)],
1487             [qw(0 0-8 . a-f 6 0)],
1488             [qw(0 a-f 0 0-9 60 1)],
1489             [qw(1 0-9a-f 0 0-9 60 1)],
1490             [qw(1 0-9a-f 1 0-9 66 1)],
1491             [qw(1 0-9a-f . a-f 66 1)],
1492             [qw(0 9a-f . a-f 66 1)],
1493             [qw(0 a-f 1 0-9 66 1)],
1494             ];
1495 2         8 foreach my $row (@{$table}) {
  2         9  
1496 11         18 my @row = @{$row};
  11         29  
1497 11 100 100     60 if(
      66        
      100        
      100        
1498             $f->getC() == $row[0] &&
1499             ($row[2] eq '.' || $f->getH() == $row[2]) &&
1500             sprintf('%x', ($a->get() >> 4) & 0x0F) =~ /^[$row[1]]$/ &&
1501             sprintf('%x', $a->get() & 0x0F) =~ /^[$row[3]]$/
1502             ) {
1503 2 100       16 $f->getN() ? $a->set(ALU_sub8($f, $a->get(), hex($row[4])))
1504             : $a->set(ALU_add8($f, $a->get(), hex($row[4])));
1505 2         13 $f->setC($row[5]);
1506 2         23 last;
1507             }
1508             }
1509 2 100       32 $f->setH($lo > 9) if(!$n);
1510 2 100 66     24 $f->resetH() if($n && !$h);
1511 2 50 66     16 $f->setH($lo < 6) if($n && $h);
1512 2         8 $f->set3($a->get() & 0b1000);
1513 2         8 $f->set5($a->get() & 0b100000);
1514 2         10 $f->setP(ALU_parity($a->get()));
1515             }
1516             sub _CPL {
1517 1     1   4 my $self = shift;
1518 1         5 $self->register('A')->set(~ $self->register('A')->get());
1519 1         7 $self->register('F')->setH();
1520 1         5 $self->register('F')->setN();
1521 1         6 $self->register('F')->set3($self->register('A')->get() & 0b1000);
1522 1         7 $self->register('F')->set5($self->register('A')->get() & 0b100000);
1523             }
1524             sub _SCF {
1525 4     4   10 my $self = shift();
1526 4         22 my $f = $self->register('F');
1527 4         41 my $a = $self->register('A');
1528 4         70 $f->setC();
1529 4         31 $f->resetH();
1530 4         26 $f->resetN();
1531 4         24 $f->set5($a->get() & 0b100000);
1532 4         17 $f->set3($a->get() & 0b1000);
1533             }
1534             sub _CCF {
1535 1     1   3 my $self = shift;
1536 1         3 my $f = $self->register('F');
1537 1         81 my $a = $self->register('A');
1538 1         82 $f->setH($f->getC());
1539 1         7 $f->setC(!$f->getC());
1540 1         6 $f->resetN();
1541 1         6 $f->set5($a->get() & 0b100000);
1542 1         4 $f->set3($a->get() & 0b1000);
1543             }
1544             sub _POP {
1545 30     30   91 my($self, $r) = @_;
1546 30         115 $self->register($r)->set(
1547             $self->memory()->peek16($self->register('SP')->get())
1548             );
1549 30         153 $self->register('SP')->add(2);
1550             }
1551             sub _PUSH {
1552 32     32   104 my($self, $r) = @_;
1553 32         159 $self->register('SP')->sub(2);
1554 32         127 $self->memory()->poke16(
1555             $self->register('SP')->get(),
1556             $self->register($r)->get()
1557             );
1558             }
1559             sub _IN_A_n {
1560 8     8   10 my($self, $lobyte) = @_;
1561 8         18 $self->register('A')->set(
1562             $self->_get_from_input(($self->register('A')->get() << 8) + $lobyte)
1563             );
1564             }
1565             sub _IN_r_C {
1566 30     30   49 my($self, $r) = @_;
1567 30         74 $r = $self->register($r); # for (HL) this is W and magically correct!
1568 30         281 $r->set($self->_get_from_input($self->register('BC')->get()));
1569            
1570 30         120 my $f = $self->register('F');
1571 30         276 $f->setS($r->get() & 0x80);
1572 30         86 $f->setZ($r->get() == 0);
1573 30         95 $f->set5($r->get() & 0b100000);
1574 30         153 $f->resetH();
1575 30         109 $f->set3($r->get() & 0b1000);
1576 30         94 $f->setP(ALU_parity($r->get()));
1577             }
1578              
1579             sub _OUT_n_A { # output A to B<<8 + n
1580 1     1   3 my($self, $n) = @_;
1581 1         4 $self->_put_to_output(
1582             ($self->register('B')->get() << 8) + $n,
1583             $self->register('A')->get()
1584             );
1585             }
1586             sub _OUT_C_r {
1587 8     8   17 my($self, $r) = @_;
1588 8         26 $self->_put_to_output(
1589             $self->register('BC')->get(),
1590             $self->register($r)->get()
1591             );
1592             }
1593             sub _OUT_C_0 {
1594 1     1   3 my $self = shift();
1595 1         3 $self->register('W')->set(0);
1596 1         11 _OUT_C_r($self, 'W');
1597             }
1598             sub _IND {
1599 3     3   6 my $self = shift;
1600 3         12 _IN_r_C($self, '(HL)');
1601 3         12 _LD_indHL_r8($self, 'W', 0);
1602 3         49 $self->register($_)->dec() foreach(qw(HL B));
1603             }
1604             sub _INI {
1605 3     3   6 my $self = shift;
1606 3         8 _IN_r_C($self, '(HL)');
1607 3         10 _LD_indHL_r8($self, 'W');
1608 3         45 $self->register('HL')->inc();
1609 3         10 $self->register('B')->dec();
1610             }
1611             sub _INDR {
1612 2     2   3 my $self = shift;
1613 2         7 _IND($self);
1614 2 100       7 $self->register('PC')->set($self->register('PC')->get() - 2)
1615             if($self->register('B')->get());
1616             }
1617             sub _INIR {
1618 2     2   4 my $self = shift;
1619 2         7 _INI($self);
1620 2 100       8 $self->register('PC')->set($self->register('PC')->get() - 2)
1621             if($self->register('B')->get());
1622             }
1623             sub _OUTD {
1624 4     4   5 my $self = shift;
1625 4         9 $self->register('B')->dec();
1626 4         20 $self->_put_to_output(
1627             $self->register('BC')->get(),
1628             $self->memory()->peek($self->register('HL')->get())
1629             );
1630 4         27 $self->register('HL')->dec();
1631             }
1632             sub _OUTI {
1633 4     4   5 my $self = shift;
1634 4         6 $self->register('B')->dec();
1635 4         17 $self->_put_to_output(
1636             $self->register('BC')->get(),
1637             $self->memory()->peek($self->register('HL')->get())
1638             );
1639 4         27 $self->register('HL')->inc();
1640             }
1641             sub _OTDR {
1642 3     3   6 my $self = shift;
1643 3         5 _OUTD($self);
1644 3 100       8 $self->register('PC')->set($self->register('PC')->get() - 2)
1645             if($self->register('B')->get());
1646             }
1647             sub _OTIR {
1648 3     3   4 my $self = shift;
1649 3         6 _OUTI($self);
1650 3 100       10 $self->register('PC')->set($self->register('PC')->get() - 2)
1651             if($self->register('B')->get());
1652             }
1653              
1654 8     8   19 sub _IM {} # everything is IM 1
1655              
1656             sub _RETI {
1657 1     1   7 _POP(shift(), 'PC');
1658             }
1659             sub _RETN {
1660 7     7   21 my $self = shift();
1661 7         26 $self->{iff1} = $self->{iff2};
1662 7         40 _POP($self, 'PC');
1663             }
1664             sub _DI {
1665 5     5   548 my $self = shift;
1666 5         19 _interrupts_enabled($self, 0);
1667             }
1668             sub _EI {
1669 3     3   504 my $self = shift;
1670 3         16 _interrupts_enabled($self, 1);
1671             }
1672             sub _swap_regs {
1673 1634     1634   5550 my($self, $r1, $r2) = @_;
1674 1634         6507 my $temp = $self->register($r1)->get();
1675 1634         6348 $self->register($r1)->set($self->register($r2)->get());
1676 1634         6070 $self->register($r2)->set($temp);
1677             }
1678              
1679             =head1 EXTRA INSTRUCTIONS
1680              
1681             Whenever any combination of two of the 0xDD and 0xFD prefixes are
1682             met, behaviour deviates from that of a normal Z80 and instead
1683             depends on the following byte:
1684              
1685             =head2 0x00 - STOP
1686              
1687             The run() method stops, even if the desired number of instructions
1688             has not yet been reached.
1689              
1690             =head2 anything else
1691              
1692             Fatal error.
1693              
1694             =head1 PROGRAMMING THE Z80
1695              
1696             I recommend "Programming the Z80" by Rodnay Zaks. This excellent
1697             book is unfortunately out of print, but may be available through
1698             abebooks.com
1699             L.
1700              
1701             =head1 BUGS/WARNINGS/LIMITATIONS
1702              
1703             Claims about making your code faster may not be true in all realities.
1704              
1705             I assume you're using a twos-complement machine. I *think* that
1706             that's true of anything perl runs on.
1707              
1708             Only interrupt mode 1 is implemented. All interrupts are serviced
1709             by a RST 0x38 instruction.
1710              
1711             The DDFD- and FDDD-prefixed instructions (the "use this index
1712             register - no, wait, I meant the other one" prefixes) and the DDDD-
1713             and FDFD-prefixed instructions (the "use this index register, no
1714             really, I mean it, pleeeeease" prefixes) are silly,
1715             and have been replaced - see "Extra Instructions" above.
1716              
1717             =head1 FEEDBACK
1718              
1719             I welcome feedback about my code, including constructive criticism
1720             and bug reports. The best bug reports include files that I can add
1721             to the test suite, which fail with the current code in CVS and will
1722             pass once I've fixed the bug.
1723              
1724             Feature requests are far more likely to get implemented if you submit
1725             a patch yourself.
1726              
1727             =head1 SEE ALSO
1728              
1729             L
1730              
1731             L
1732              
1733             The FUSE Free Unix Spectrum Emulator: L
1734              
1735             =head1 CVS
1736              
1737             L
1738              
1739             =head1 AUTHOR, COPYRIGHT and LICENCE
1740              
1741             Copyright 2008 David Cantrell EFE
1742              
1743             This software is free-as-in-speech software, and may be used,
1744             distributed, and modified under the terms of either the GNU
1745             General Public Licence version 2 or the Artistic Licence. It's
1746             up to you which one you use. The full text of the licences can
1747             be found in the files GPL2.txt and ARTISTIC.txt, respectively.
1748              
1749             =head1 CONSPIRACY
1750              
1751             This module is also free-as-in-mason software.
1752              
1753             =cut
1754              
1755             1;