Hackfix and re-enable strtoull and wcstoull, see bug #3798.
[sdcc.git] / sdcc / support / scripts / mcs51-disasm.pl
blobfe67737a9daf0b19b9a95be6c40df7f242be0442
1 #!/usr/bin/perl -w
3 =back
5 Copyright (C) 2013, Molnar Karoly <molnarkaroly@users.sf.net>
7 This software is provided 'as-is', without any express or implied
8 warranty. In no event will the authors be held liable for any damages
9 arising from the use of this software.
11 Permission is granted to anyone to use this software for any purpose,
12 including commercial applications, and to alter it and redistribute it
13 freely, subject to the following restrictions:
15 1. The origin of this software must not be misrepresented; you must not
16 claim that you wrote the original software. If you use this software
17 in a product, an acknowledgment in the product documentation would be
18 appreciated but is not required.
20 2. Altered source versions must be plainly marked as such, and must not be
21 misrepresented as being the original software.
23 3. This notice may not be removed or altered from any source distribution.
25 ================================================================================
27 This program disassembles the hex files. It assumes that the hex file
28 contains MCS51 instructions.
30 Proposal for use: ./mcs51-disasm.pl -M 8052.h -fl -rj program.hex > program.dasm
32 or ./mcs51-disasm.pl -M 8052.h -fl -rj -as program.hex > program.asm
34 or ./mcs51-disasm.pl -M 8052.h -fl -rj -as -hc program.hex > program.asm
37 Warning! This program is not able to find all variable. Especially them not, whose
38 can be found in the indirect or external RAM.
40 $Id$
41 =cut
43 use strict;
44 use warnings;
45 no if $] >= 5.018, warnings => "experimental::smartmatch"; # perl 5.16
46 use 5.12.0; # when (regex)
48 use constant FALSE => 0;
49 use constant TRUE => 1;
51 use constant TAB_LENGTH => 8;
53 ################################################################################
55 use constant INHX8M => 0;
56 use constant INHX32 => 2;
58 use constant INHX_DATA_REC => 0;
59 use constant INHX_EOF_REC => 1;
60 use constant INHX_EXT_LIN_ADDR_REC => 4;
62 use constant EMPTY => -1;
64 use constant COUNT_SIZE => 2;
65 use constant ADDR_SIZE => 4;
66 use constant TYPE_SIZE => 2;
67 use constant BYTE_SIZE => 2;
68 use constant CRC_SIZE => 2;
69 use constant HEADER_SIZE => (COUNT_SIZE + ADDR_SIZE + TYPE_SIZE);
70 use constant MIN_LINE_LENGTH => (HEADER_SIZE + CRC_SIZE);
72 use constant MCS51_ROM_SIZE => 0x10000;
74 ################################################################################
76 my $PROGRAM = 'mcs51-disasm.pl';
78 my $border0 = ('-' x 79);
79 my $border1 = ('#' x 79);
80 my $border2 = ('.' x 39);
82 my @default_paths =
84 '/usr/share/sdcc/include/mcs51',
85 '/usr/local/share/sdcc/include/mcs51'
88 my $default_include_path = '';
89 my $include_path = '';
90 my $hex_file = '';
91 my $map_file = '';
92 my $map_readed = FALSE;
93 my $header_file = '';
94 my $name_list = '';
96 my $verbose = 0;
97 my $hex_constant = FALSE;
98 my $gen_assembly_code = FALSE;
99 my $no_explanations = FALSE;
100 my $recognize_jump_tables = FALSE;
101 my $find_lost_labels = FALSE;
103 my @rom = ();
104 my $rom_size = MCS51_ROM_SIZE;
105 my %const_areas_by_address = (); # From the command line parameters.
107 my %const_blocks_by_address = ();
109 =back
110 The structure of one element of the %sfr_by_address hash:
113 NAME => '',
114 REF_COUNT => 0
116 =cut
118 my %sfr_by_address = ();
119 my %sfr_by_names = ();
121 =back
122 The structure of one element of the %sfr_bit_by_address hash:
125 NAME => '',
126 REF_COUNT => 0
128 =cut
130 my %sfr_bit_by_address = ();
132 my %used_banks = ();
134 =back
135 The structure of one element of the %bit_by_address hash:
138 NAME => '',
139 REF_COUNT => 0
141 =cut
143 my %bit_by_address = ();
145 =back
146 The structure of one element of the %ram_by_address hash:
149 TYPE => 0,
150 NAME => '',
151 SIZE => 0,
152 REF_COUNT => 0
154 =cut
156 use constant RAM_TYPE_DIR => 0;
157 use constant RAM_TYPE_IND => 1;
159 my %ram_by_address = ();
160 my %ram_names_by_address = ();
162 =back
163 The structure of one element of the %xram_by_address hash:
166 NAME => '',
167 SIZE => 0,
168 REF_COUNT => 0
170 =cut
172 my %xram_by_address = ();
173 my %xram_names_by_address = ();
175 my $stack_start = -1;
176 my $stack_size = 0;
178 # Sizes of the instructions.
180 my @instruction_sizes =
182 1, 2, 3, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
183 3, 2, 3, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
184 3, 2, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
185 3, 2, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
186 2, 2, 2, 3, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
187 2, 2, 2, 3, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
188 2, 2, 2, 3, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
189 2, 2, 2, 1, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
190 2, 2, 2, 1, 1, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
191 3, 2, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
192 2, 2, 2, 1, 1, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
193 2, 2, 2, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
194 2, 2, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
195 2, 2, 2, 1, 1, 3, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2,
196 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
197 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
200 use constant BANK_LAST_ADDR => 0x1F;
201 use constant BIT_LAST_ADDR => 0x7F;
202 use constant RAM_MAX_ADDR => 0xFF;
203 use constant RAM_LAST_DIR_ADDR => 0x7F;
205 use constant SP => 0x81;
206 use constant DPL => 0x82;
207 use constant DPH => 0x83;
208 use constant PSW => 0xD0;
209 use constant ACC => 0xE0;
211 use constant INST_AJMP => 0x01;
212 use constant INST_LJMP => 0x02;
213 use constant INST_ACALL => 0x11;
214 use constant INST_LCALL => 0x12;
215 use constant INST_SJMP => 0x80;
216 use constant INST_RET => 0x22;
217 use constant INST_RETI => 0x32;
218 use constant INST_ADD_A_DATA => 0x24;
219 use constant INST_JMP_A_DPTR => 0x73;
220 use constant INST_MOV_DIRECT_DATA => 0x75;
221 use constant INST_MOVC_A_APC => 0x83;
222 use constant INST_MOV_DIRECT_DIRECT => 0x85;
223 use constant INST_MOV_DPTR_DATA => 0x90;
224 use constant INST_MOVC_A_DPTR => 0x93;
225 use constant INST_PUSH_DIRECT => 0xC0;
226 use constant INST_XCH_A_DIRECT => 0xC5;
227 use constant INST_POP_DIRECT => 0xD0;
228 use constant INST_CLR_A => 0xE4;
229 use constant INST_MOV_A_DIRECT => 0xE5;
230 use constant INST_MOV_A_Ri => 0xE6;
231 use constant INST_MOV_A_Rn => 0xE8;
232 use constant INST_MOV_DIRECT_A => 0xF5;
233 use constant INST_CJNE_A_DATA => 0xB4;
234 use constant INST_CJNE_A_DIRECT => 0xB5;
235 use constant INST_CJNE__Ri_DATA => 0xB6;
236 use constant INST_CJNE_Rn_DATA => 0xB8;
237 use constant INST_DJNZ_Rn => 0xD8;
238 use constant INST_DJNZ_DIRECT => 0xD5;
239 use constant INST_JBC_BIT => 0x10;
240 use constant INST_JB_BIT => 0x20;
241 use constant INST_JNB_BIT => 0x30;
242 use constant INST_JC => 0x40;
243 use constant INST_JNC => 0x50;
244 use constant INST_JZ => 0x60;
245 use constant INST_JNZ => 0x70;
247 use constant LJMP_SIZE => 3;
249 my $DPTR;
250 my @R_regs;
252 my $prev_is_jump;
254 use constant SILENT0 => 0;
255 use constant SILENT1 => 1;
256 use constant SILENT2 => 2;
258 my $decoder_silent_level;
260 use constant EXPL_ALIGN_SIZE => 5;
261 use constant STAT_ALIGN_SIZE => 6;
262 use constant TBL_COLUMNS => 8;
264 =back
265 The structure of one element of the %blocks_by_address hash:
268 TYPE => 0,
269 ADDR => 0,
270 SIZE => 0,
271 LABEL => {
272 TYPE => 0,
273 NAME => '',
274 PRINTED => FALSE,
275 CALL_COUNT => 0,
276 JUMP_COUNT => 0
279 =cut
281 use constant BLOCK_INSTR => 0;
282 use constant BLOCK_CONST => 1;
283 use constant BLOCK_JTABLE => 2;
284 use constant BLOCK_EMPTY => 3;
285 use constant BLOCK_DISABLED => 4;
287 use constant BL_TYPE_NONE => -1;
288 use constant BL_TYPE_SUB => 0;
289 use constant BL_TYPE_LABEL => 1;
290 use constant BL_TYPE_JTABLE => 2;
291 use constant BL_TYPE_JLABEL => 3;
292 use constant BL_TYPE_CONST => 4;
294 my %label_names =
296 eval BL_TYPE_SUB => 'Function_',
297 eval BL_TYPE_LABEL => 'Label_',
298 eval BL_TYPE_JTABLE => 'Jumptable_',
299 eval BL_TYPE_JLABEL => 'JTlabel_',
300 eval BL_TYPE_CONST => 'Constant_'
303 my %empty_blocks_by_address = ();
304 my %blocks_by_address = ();
305 my %labels_by_address = ();
306 my $max_label_addr = 0;
308 my %indirect_addr_instr =
310 0x06 => TRUE,
311 0x16 => TRUE,
312 0x26 => TRUE,
313 0x36 => TRUE,
314 0x46 => TRUE,
315 0x56 => TRUE,
316 0x66 => TRUE,
317 0x76 => TRUE,
318 0x86 => TRUE,
319 0x96 => TRUE,
320 0xA6 => TRUE,
321 0xB6 => TRUE,
322 0xC6 => TRUE,
323 0xD6 => TRUE,
324 0xE6 => TRUE,
325 0xF6 => TRUE
328 my %interrupts_by_address =
330 0x0000 => 'System_init',
331 0x0003 => 'Int0_interrupt',
332 0x000B => 'Timer0_interrupt',
333 0x0013 => 'Int1_interrupt',
334 0x001B => 'Timer1_interrupt',
335 0x0023 => 'Uart_interrupt',
336 0x002B => 'Timer2_interrupt',
337 0x0033 => 'Int2_interrupt',
338 0x003B => 'Int3_interrupt'
341 my %control_characters =
343 0x00 => '\0',
344 0x07 => '\a',
345 0x08 => '\b',
346 0x09 => '\t',
347 0x0A => '\n',
348 0x0C => '\f',
349 0x0D => '\r',
350 0x1B => '\e',
351 0x7F => '^?'
354 my $dcd_address = 0;
355 my $dcd_instr_size = 0;
356 my $dcd_instr = 0;
357 my $dcd_parm0 = 0;
358 my $dcd_parm1 = 0;
359 my $dcd_Ri_regs = 0;
360 my $dcd_Ri_name = '';
361 my $dcd_Rn_regs = 0;
362 my $dcd_Rn_name = '';
364 my $table_header = '';
365 my $table_border = '';
367 ################################################################################
368 ################################################################################
370 my %pp_defines = (); # Value of definitions.
372 my @pp_conditions = ();
373 my @pp_else_conditions = ();
374 my $pp_level = 0; # Shows the lowest level.
375 my $embed_level;
377 # @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
378 # @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
379 #@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@
380 #@@@@@@@@@@@@@@@@@@@@@@@ This a simple preprocessor. @@@@@@@@@@@@@@@@@@@@@@@@@
381 #@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@
382 # @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
383 # @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
385 # Examines that the parameter is defined or not defined.
387 sub _defined($)
389 return defined($pp_defines{$_[0]});
392 #-------------------------------------------------------------------------------
394 # Records a definition.
396 sub define($)
398 my ($Name) = ($_[0] =~ /^(\S+)/op);
399 my $Body = ${^POSTMATCH};
401 $Body =~ s/^\s+//o;
403 die "define(): This definition already exists: \"$Name\"\n" if (_defined($Name));
405 # The definition is in fact unnecessary.
406 $pp_defines{$Name} = $Body;
409 #-------------------------------------------------------------------------------
411 # Delete a definition.
413 sub undefine($)
415 delete($pp_defines{$_[0]});
418 #-------------------------------------------------------------------------------
420 # Evaluation of the #if give a boolean value. This procedure preserves it.
422 sub if_condition($)
424 my $Val = $_[0];
426 push(@pp_conditions, $Val);
427 push(@pp_else_conditions, $Val);
428 ++$pp_level;
431 #-------------------------------------------------------------------------------
433 # Evaluation of the #else give a boolean value. This procedure preserves it.
435 sub else_condition($$)
437 my ($File, $Line_number) = @_;
439 die "else_condition(): The ${Line_number}th line of $File there is a #else, but does not belong him #if.\n" if ($pp_level <= 0);
441 my $last = $#pp_conditions;
443 if ($last > 0 && $pp_conditions[$last - 1])
445 $pp_conditions[$last] = ($pp_else_conditions[$#pp_else_conditions]) ? FALSE : TRUE;
447 else
449 $pp_conditions[$last] = FALSE;
453 #-------------------------------------------------------------------------------
455 # Closes a logical unit which starts with a #if.
457 sub endif_condition($$)
459 my ($File, $Line_number) = @_;
461 die "endif_condition(): The ${Line_number}th line of $File there is a #endif, but does not belong him #if.\n" if ($pp_level <= 0);
463 pop(@pp_conditions);
464 pop(@pp_else_conditions);
465 --$pp_level;
468 #-------------------------------------------------------------------------------
470 sub reset_preprocessor()
472 %pp_defines = ();
473 @pp_conditions = ();
474 push(@pp_conditions, TRUE);
475 @pp_else_conditions = ();
476 push(@pp_else_conditions, FALSE);
477 $pp_level = 0;
480 #-------------------------------------------------------------------------------
482 # This the preprocessor.
484 sub run_preprocessor($$$$)
486 my ($Fname, $Function, $Line, $Line_number) = @_;
488 if ($Line =~ /^#\s*ifdef\s+(\S+)$/o)
490 if ($pp_conditions[$#pp_conditions])
492 # The ancestor is valid, therefore it should be determined that
493 # the descendants what kind.
495 if_condition(_defined($1));
497 else
499 # The ancestor is invalid, so the descendants will invalid also.
501 if_condition(FALSE);
504 elsif ($Line =~ /^#\s*ifndef\s+(\S+)$/o)
506 if ($pp_conditions[$#pp_conditions])
508 # The ancestor is valid, therefore it should be determined that
509 # the descendants what kind.
511 if_condition(! _defined($1));
513 else
515 # The ancestor is invalid, so the descendants will invalid also.
517 if_condition(FALSE);
520 elsif ($Line =~ /^#\s*else/o)
522 else_condition($Fname, $Line_number);
524 elsif ($Line =~ /^#\s*endif/o)
526 endif_condition($Fname, $Line_number);
528 elsif ($Line =~ /^#\s*define\s+(.+)$/o)
530 # This level is valid, so it should be recorded in the definition.
532 define($1) if ($pp_conditions[$#pp_conditions]);
534 elsif ($Line =~ /^#\s*undef\s+(.+)$/o)
536 # This level is valid, so it should be deleted in the definition.
538 undefine($1) if ($pp_conditions[$#pp_conditions]);
540 elsif ($pp_conditions[$#pp_conditions])
542 # This is a valid line. (The whole magic is in fact therefore there is.)
544 $Function->($Line);
548 ################################################################################
549 ################################################################################
550 ################################################################################
552 sub basename($)
554 return ($_[0] =~ /([^\/]+)$/) ? $1 : '';
557 #-------------------------------------------------------------------------------
559 sub param_exist($$)
561 die "This option \"$_[0]\" requires a parameter.\n" if ($_[1] > $#ARGV);
564 #-------------------------------------------------------------------------------
566 sub Log
568 return if (pop(@_) > $verbose);
569 foreach (@_) { print STDERR $_; }
570 print STDERR "\n";
573 #-------------------------------------------------------------------------------
575 sub str2int($)
577 my $Str = $_[0];
579 return hex($1) if ($Str =~ /^0x([[:xdigit:]]+)$/io);
580 return int($Str) if ($Str =~ /^-?\d+$/o);
582 die "str2int(): This string not integer: \"$Str\"";
585 #-------------------------------------------------------------------------------
588 # Before print, formats the $Text.
591 sub align($$)
593 my $Text = $_[0];
594 my $al = $_[1] - int(length($Text) / TAB_LENGTH);
596 # One space will surely becomes behind it.
597 if ($al < 1)
599 return "$Text ";
601 else
603 return ($Text . ("\t" x $al));
607 #-------------------------------------------------------------------------------
610 # Multiple file test.
613 sub is_file_ok($)
615 my $File = $_[0];
617 if (! -e $File)
619 print STDERR "$PROGRAM: Not exists -> \"$File\"\n";
620 exit(1);
623 if (! -f $File)
625 print STDERR "$PROGRAM: Not file -> \"$File\"\n";
626 exit(1);
629 if (! -r $File)
631 print STDERR "$PROGRAM: Can not read -> \"$File\"\n";
632 exit(1);
635 if (! -s $File)
637 print STDERR "$PROGRAM: Empty file -> \"$File\"\n";
638 exit(1);
642 #-------------------------------------------------------------------------------
645 # Initializes the @rom array.
648 sub init_mem($$)
650 my ($Start, $End) = @_;
652 @rom[$Start .. $End] = ((EMPTY) x ($End - $Start + 1));
655 #-------------------------------------------------------------------------------
658 # Store values of the $Code to $AddrRef address.
661 sub store_code($$)
663 my ($Code, $AddrRef) = @_;
665 if ($$AddrRef >= $rom_size)
667 printf STDERR "Warning, this address (0x%04X) outside the code area (0x%04X)!\n", $$AddrRef, $rom_size - 1;
670 Log(sprintf("rom[0x%08X] = 0x%02X", $$AddrRef, $Code), 9);
671 $rom[$$AddrRef++] = $Code;
674 #-------------------------------------------------------------------------------
677 # Reads contents of the $Hex.
680 sub read_hex($)
682 my $Hex = $_[0];
683 my $addr_H = 0;
684 my $format = INHX32;
685 my $line_num = 0;
687 if (! open(IN, '<', $Hex))
689 print STDERR "$PROGRAM : Could not open. -> \"$Hex\"\n";
690 exit(1);
693 while (<IN>)
695 chomp;
696 s/\r$//o;
697 ++$line_num;
699 my $len = length() - 1;
701 if ($len < MIN_LINE_LENGTH)
703 close(IN);
704 print STDERR "$PROGRAM: ${line_num}th line <- Shorter than %u character.\n", MIN_LINE_LENGTH;
705 exit(1);
708 Log("$..(1) (\"$_\") length() = " . length(), 7);
710 my $bytecount = int(($len - MIN_LINE_LENGTH) / BYTE_SIZE);
712 my $binrec = pack('H*', substr($_, 1));
714 if (unpack('%8C*', $binrec) != 0)
716 close(IN);
717 print STDERR "$PROGRAM: $Hex <- Crc error. (${line_num}th line \"$_\").\n";
718 exit(1);
721 my ($count, $addr, $type, $bytes) = unpack('CnCX4Cx3/a', $binrec);
723 my @codes = unpack('C*', $bytes);
725 Log(sprintf("$..(2) (\"$_\") count = $count, bytecount = $bytecount, addr = 0x%04X, type = $type", $addr), 7);
727 if ($type == INHX_EOF_REC)
729 last;
731 elsif ($type == INHX_EXT_LIN_ADDR_REC)
733 $addr_H = unpack('n', $bytes); # big-endian
735 Log(sprintf("$..(3) (\"$_\") addr_H = 0x%04X\n", $addr_H), 7);
737 $format = INHX32;
738 Log('format = INHX32', 7);
739 next;
741 elsif ($type != INHX_DATA_REC)
743 close(IN);
744 printf STDERR "$PROGRAM: $Hex <- Unknown type of record: 0x%02X (${line_num}th line \"$_\").\n", $type;
745 exit(1);
748 if ($bytecount == $count) # INHX32
750 if ($format == INHX8M)
752 close(IN);
753 print STDERR "$PROGRAM: $Hex <- Mixed format of file (${line_num}th line \"$_\").\n";
754 exit(1);
757 my $addr32 = ($addr_H << 16) | $addr;
759 map { store_code($_, \$addr32) } @codes;
761 elsif ($bytecount == ($count * BYTE_SIZE)) # INHX8M
763 if ($format == INHX32)
765 close(IN);
766 print STDERR "$PROGRAM: $Hex <- Mixed format of file (${line_num}th line \"$_\").\n";
767 exit(1);
770 map { store_code($_, \$addr) } @codes;
772 else
774 close(IN);
775 print STDERR "$PROGRAM: $Hex <- Wrong format of file (${line_num}th line \"$_\").\n";
776 exit(1);
778 } # while (<IN>)
780 close(IN);
783 #-------------------------------------------------------------------------------
786 # Determines that the $Address belongs to a constant.
789 sub is_constant($)
791 my $Address = $_[0];
793 foreach (sort {$a <=> $b} keys(%const_areas_by_address))
795 return TRUE if ($_ <= $Address && $Address <= $const_areas_by_address{$_});
796 last if ($_ > $Address);
799 foreach (sort {$a <=> $b} keys(%const_blocks_by_address))
801 return TRUE if ($_ <= $Address && $Address <= $const_blocks_by_address{$_});
802 last if ($_ > $Address);
805 return FALSE;
808 #-------------------------------------------------------------------------------
811 # Determines that the $Address belongs to a empty area.
814 sub is_empty($)
816 my $Address = $_[0];
818 foreach (sort {$a <=> $b} keys(%empty_blocks_by_address))
820 return TRUE if ($_ <= $Address && $Address <= $empty_blocks_by_address{$_});
821 last if ($_ > $Address);
824 return FALSE;
827 #-------------------------------------------------------------------------------
830 # Creates a const block.
833 sub add_const_area($$)
835 $const_areas_by_address{$_[0]} = $_[1];
838 #-------------------------------------------------------------------------------
841 # Creates a new block, or modifies one.
844 sub add_block($$$$$)
846 my ($Address, $Type, $Size, $LabelType, $LabelName) = @_;
847 my ($block, $label, $end);
849 $end = $Address + $Size - 1;
851 if (! defined($blocks_by_address{$Address}))
853 $label = {
854 TYPE => $LabelType,
855 NAME => $LabelName,
856 PRINTED => FALSE,
857 CALL_COUNT => 0,
858 JUMP_COUNT => 0
861 $blocks_by_address{$Address} = {
862 TYPE => $Type,
863 ADDR => $Address,
864 SIZE => $Size,
865 LABEL => $label
868 if ($Type == BLOCK_INSTR)
870 if ($LabelType != BL_TYPE_NONE)
872 $labels_by_address{$Address} = $label;
873 $max_label_addr = $Address if ($max_label_addr < $Address);
876 elsif ($Type == BLOCK_CONST || $Type == BLOCK_JTABLE)
878 if ($LabelType != BL_TYPE_NONE)
880 $labels_by_address{$Address} = $label;
881 $max_label_addr = $Address if ($max_label_addr < $Address);
884 $const_blocks_by_address{$Address} = $end if ($Size > 0);
886 elsif ($Type == BLOCK_EMPTY)
888 # At empty area, can not be label.
890 $label->{TYPE} = BL_TYPE_NONE;
891 $label->{NAME} = '';
892 $empty_blocks_by_address{$Address} = $end if ($Size > 0);
894 else
896 printf STDERR "add_block(0x%04X): Unknown block type!\n", $Address;
897 exit(1);
899 } # if (! defined($blocks_by_address{$Address}))
900 else
902 $block = $blocks_by_address{$Address};
903 $label = $block->{LABEL};
904 $block->{TYPE} = $Type;
905 $block->{SIZE} = $Size if ($Size > 0);
906 $label->{NAME} = $LabelName if ($label->{NAME} eq '' && $LabelName ne '');
908 if ($Type == BLOCK_INSTR)
910 if ($LabelType != BL_TYPE_NONE)
912 $label->{TYPE} = $LabelType if ($label->{TYPE} != BL_TYPE_JLABEL);
913 $labels_by_address{$Address} = $label;
914 $max_label_addr = $Address if ($max_label_addr < $Address);
917 elsif ($Type == BLOCK_CONST || $Type == BLOCK_JTABLE)
919 if ($LabelType != BL_TYPE_NONE)
921 $label->{TYPE} = $LabelType;
922 $labels_by_address{$Address} = $label;
923 $max_label_addr = $Address if ($max_label_addr < $Address);
926 $const_blocks_by_address{$Address} = $end if ($Size > 0);
928 elsif ($Type == BLOCK_EMPTY)
930 # At empty area, can not be label.
932 $label->{TYPE} = BL_TYPE_NONE;
933 $label->{NAME} = '';
934 $empty_blocks_by_address{$Address} = $end if ($Size > 0);
938 return $label;
941 #-------------------------------------------------------------------------------
944 # Store address entry of a procedure.
947 sub add_func_label($$$)
949 my ($Address, $Name, $Map_mode) = @_;
950 my $label;
952 if ($Address < 0)
954 Log(sprintf("add_func_label(): This address (0x%04X) negative!", $Address), 2);
955 return;
958 if (! $Map_mode)
960 if (! defined($blocks_by_address{$Address}))
962 Log(sprintf("add_func_label(): This address (0x%04X) does not shows an instruction!", $Address), 2);
963 return;
967 if (is_constant($Address) || is_empty($Address))
969 Log(sprintf("add_func_label(): This address (0x%04X) outside the code area!", $Address), 2);
970 return;
973 $label = add_block($Address, BLOCK_INSTR, 0, BL_TYPE_SUB, $Name);
974 ++$label->{CALL_COUNT} if (! $Map_mode);
977 #-------------------------------------------------------------------------------
980 # Store a label.
983 sub add_jump_label($$$$$)
985 my ($TargetAddr, $Name, $Type, $SourceAddr, $Map_mode) = @_;
986 my ($label, $type);
988 if ($TargetAddr < 0)
990 Log(sprintf("add_jump_label(): This address (0x%04X) negative!", $TargetAddr), 2);
991 return;
994 if (! $Map_mode)
996 if (! defined($blocks_by_address{$TargetAddr}))
998 Log(sprintf("add_jump_label(): This address (0x%04X) does not shows an instruction!", $TargetAddr), 2);
999 return;
1003 if (is_constant($TargetAddr) || is_empty($TargetAddr))
1005 Log(sprintf("add_jump_label(): This address (0x%04X) outside the code area!", $TargetAddr), 2);
1006 return;
1009 if (defined($interrupts_by_address{$SourceAddr}))
1011 $Type = BL_TYPE_SUB;
1012 $Name = $interrupts_by_address{$SourceAddr} if ($Name eq '');
1015 $label = add_block($TargetAddr, BLOCK_INSTR, 0, $Type, $Name);
1016 ++$label->{JUMP_COUNT} if (! $Map_mode);
1019 #-------------------------------------------------------------------------------
1022 # Store a bit or sbit name from bit area.
1025 sub add_bit($$$)
1027 my ($Address, $Name, $Map_mode) = @_;
1028 my $bit;
1030 if ($Address > BIT_LAST_ADDR)
1032 if (! defined($bit = $sfr_bit_by_address{$Address}))
1034 $sfr_bit_by_address{$Address} = {
1035 NAME => $Name,
1036 REF_COUNT => ($Map_mode) ? 0 : 1
1039 else
1041 if ($Name ne '' && $bit->{NAME} ne $Name)
1043 Log(sprintf("Warning, the address: 0x%02X already busy by the $bit->{NAME} bit.", $Address), 2);
1045 else
1047 ++$bit->{REF_COUNT} if (! $Map_mode);
1051 else
1053 if (! defined($bit = $bit_by_address{$Address}))
1055 $bit_by_address{$Address} = {
1056 NAME => $Name,
1057 REF_COUNT => ($Map_mode) ? 0 : 1
1060 else
1062 ++$bit->{REF_COUNT} if (! $Map_mode);
1067 #-------------------------------------------------------------------------------
1070 # Store a sfr or variable name.
1073 sub add_ram($$$$)
1075 my ($Address, $Name, $Type, $Map_mode) = @_;
1076 my $ram;
1078 return if ($Address == EMPTY);
1080 if ($Address > RAM_LAST_DIR_ADDR && $Type == RAM_TYPE_DIR)
1082 if (! defined($ram = $sfr_by_address{$Address}))
1084 $sfr_by_address{$Address} = {
1085 NAME => $Name,
1086 REF_COUNT => ($Map_mode) ? 0 : 1
1089 else
1091 if ($Name ne '' && $ram->{NAME} ne $Name)
1093 Log(sprintf("Warning, the address: 0x%02X already busy by the $ram->{NAME} register.", $Address), 2);
1095 else
1097 ++$ram->{REF_COUNT} if (! $Map_mode);
1101 $sfr_by_names{$Name} = $Address;
1103 else
1105 if (! defined($ram = $ram_by_address{$Address}))
1107 $ram_by_address{$Address} = {
1108 TYPE => $Type,
1109 NAME => $Name,
1110 SIZE => 1,
1111 REF_COUNT => ($Map_mode) ? 0 : 1
1114 else
1116 ++$ram->{REF_COUNT} if (! $Map_mode);
1121 #-------------------------------------------------------------------------------
1124 # Store a variable name from XRAM.
1127 sub add_xram($$$)
1129 my ($Address, $Name, $Map_mode) = @_;
1130 my $xram;
1132 if (! defined($xram = $xram_by_address{$Address}))
1134 $xram_by_address{$Address} = {
1135 NAME => $Name,
1136 SIZE => 1,
1137 REF_COUNT => ($Map_mode) ? 0 : 1
1140 else
1142 ++$xram->{REF_COUNT} if (! $Map_mode);
1146 ################################################################################
1147 ################################################################################
1149 use constant MAP_NULL => 0;
1150 use constant MAP_BORDER => 1;
1151 use constant MAP_AREA => 2;
1152 use constant MAP_ABS => 3;
1153 use constant MAP_CABS => 4;
1154 use constant MAP_CODE0 => 5;
1155 use constant MAP_CODE1 => 6;
1156 use constant MAP_DATA => 7;
1157 use constant MAP_ISEG => 8;
1158 use constant MAP_CONST => 9;
1161 # If exists the map file, then extracts out of it the labels,
1162 # variables and some segments.
1165 sub read_map_file()
1167 my ($addr, $name, $state, $label);
1169 return if ($map_file eq '');
1171 $state = MAP_NULL;
1173 if (! open(MAP, '<', $map_file))
1175 print STDERR "$PROGRAM : Could not open. -> \"$map_file\"\n";
1176 exit(1);
1179 while (<MAP>)
1181 chomp;
1182 s/\r$//o;
1184 if ($state == MAP_NULL)
1186 $state = MAP_BORDER if (/^Area\s+/io);
1188 elsif ($state == MAP_BORDER)
1190 $state = MAP_AREA if (/^-+\s+/o);
1192 elsif ($state == MAP_AREA)
1194 if (/^\.\s+\.ABS\.\s+/o)
1196 $state = MAP_ABS;
1198 elsif (/^CABS\s+/o)
1200 $state = MAP_CABS;
1202 elsif (/^(HOME|CSEG)\s+/o)
1204 $state = MAP_CODE0;
1206 elsif (/^GSINIT\d+\s+/o)
1208 $state = MAP_CODE1;
1210 elsif (/^(D|O)SEG\s+/o)
1212 $state = MAP_DATA;
1214 elsif (/^ISEG\s+/o)
1216 $state = MAP_ISEG;
1218 elsif (/^CONST\s+([[:xdigit:]]+)\s+([[:xdigit:]]+)\s+/o)
1220 my ($start, $size) = (hex($1), hex($2));
1222 add_const_area($start, $start + $size - 1);
1223 $state = MAP_CONST;
1225 elsif (/^SSEG\s+([[:xdigit:]]+)\s+([[:xdigit:]]+)/o)
1227 ($stack_start, $stack_size) = (hex($1), hex($2));
1229 else
1231 $state = MAP_NULL;
1234 elsif ($state == MAP_ABS)
1236 if (/^.ASxxxx Linker\s+/io)
1238 $state = MAP_NULL;
1240 elsif (/\s*([[:xdigit:]]+)\s+(\S+)/o)
1242 # 000002C0 _Dword xdata
1244 ($addr, $name) = (hex($1), $2);
1246 add_xram(hex($1), $2, TRUE) if ($addr > RAM_MAX_ADDR);
1249 elsif ($state == MAP_CABS)
1251 if (/^.ASxxxx Linker\s+/io)
1253 $state = MAP_NULL;
1255 elsif (/^C:\s+([[:xdigit:]]+)\s+(\S+)/o)
1257 ($addr, $name) = (hex($1), $2);
1259 if ($name eq 's_CONST' || $name eq 's_XINIT')
1261 # C: 000001E8 s_CONST
1262 # C: 00000215 s_XINIT
1264 add_block($addr, BLOCK_CONST, 0, BL_TYPE_CONST, $name);
1267 } # elsif ($state == MAP_CABS)
1268 elsif ($state == MAP_CODE0 || $state == MAP_CODE1)
1270 if (/^.ASxxxx Linker\s+/io)
1272 $state = MAP_NULL;
1274 elsif (/^C:\s+([[:xdigit:]]+)\s+(\S+)/o)
1276 # C: 00000040 __mcs51_genXINIT
1277 # C: 00000061 __mcs51_genRAMCLEAR
1278 # C: 00000067 __mcs51_genXRAMCLEAR
1279 # C: 00000086 _Uart_int main
1280 # C: 000000CE _toHexChar main
1281 # C: 000001E4 __sdcc_external_startup _startup
1283 ($addr, $name) = (hex($1), $2);
1285 if ($state == MAP_CODE0)
1287 add_func_label($addr, $name, TRUE);
1289 else
1291 add_jump_label($addr, $name, BL_TYPE_LABEL, EMPTY, TRUE);
1294 } # elsif ($state == MAP_CODE0 || $state == MAP_CODE1)
1295 elsif ($state == MAP_DATA)
1297 if (/^.ASxxxx Linker\s+/io)
1299 $state = MAP_NULL;
1301 elsif (/^\s*([[:xdigit:]]+)\s+(\S+)/o)
1303 # 00000039 _counter data
1304 # 0000004C _flash_read_PARM_2 flash
1306 add_ram(hex($1), $2, RAM_TYPE_DIR, TRUE);
1308 } # elsif ($state == MAP_DATA)
1309 elsif ($state == MAP_ISEG)
1311 if (/^.ASxxxx Linker\s+/io)
1313 $state = MAP_NULL;
1315 elsif (/^\s*([[:xdigit:]]+)\s+(\S+)/o)
1317 # 00000082 _length data
1319 add_ram(hex($1), $2, RAM_TYPE_IND, TRUE);
1321 } # elsif ($state == MAP_DATA)
1322 elsif ($state == MAP_CONST)
1324 $state = MAP_NULL if (/^.ASxxxx Linker\s+/io);
1326 } # while (<MAP>)
1328 $map_readed = TRUE;
1329 close(MAP);
1332 #-------------------------------------------------------------------------------
1334 use constant NAMES_NULL => 0;
1335 use constant NAMES_BIT => 1;
1336 use constant NAMES_RAM => 2;
1337 use constant NAMES_IRAM => 3;
1338 use constant NAMES_XRAM => 4;
1339 use constant NAMES_ROM => 5;
1341 sub read_name_list()
1343 my ($line, $addr, $name, $state);
1345 return if ($name_list eq '');
1347 if (! open(NAMES, '<', $name_list))
1349 print STDERR "$PROGRAM : Could not open. -> \"$name_list\"\n";
1350 exit(1);
1353 $state = NAMES_NULL;
1355 foreach (grep(! /^\s*$/o, <NAMES>))
1357 chomp;
1358 s/\r$//o;
1359 s/^\s*|\s*$//go;
1361 if (/^\[BIT\]$/io)
1363 $state = NAMES_BIT;
1364 next;
1366 elsif (/^\[RAM\]$/io)
1368 $state = NAMES_RAM;
1369 next;
1371 elsif (/^\[XRAM\]$/io)
1373 $state = NAMES_XRAM;
1374 next;
1376 elsif (/^\[IRAM\]$/io)
1378 $state = NAMES_IRAM;
1379 next;
1381 elsif (/^\[ROM\]$/io)
1383 $state = NAMES_ROM;
1384 next;
1387 $line = $_;
1389 given ($state)
1391 when (NAMES_BIT)
1393 if ($line =~ /^0x([[:xdigit:]]+)\s*:\s*(\S+)$/io)
1395 add_bit(hex($1), $2, TRUE);
1399 when (NAMES_RAM)
1401 if ($line =~ /^0x([[:xdigit:]]+)\s*:\s*(\S+)$/io)
1403 add_ram(hex($1), $2, RAM_TYPE_DIR, TRUE);
1407 when (NAMES_IRAM)
1409 if ($line =~ /^0x([[:xdigit:]]+)\s*:\s*(\S+)$/io)
1411 add_ram(hex($1), $2, RAM_TYPE_IND, TRUE);
1415 when (NAMES_XRAM)
1417 if ($line =~ /^0x([[:xdigit:]]+)\s*:\s*(\S+)$/io)
1419 add_xram(hex($1), $2, TRUE);
1423 when (NAMES_ROM)
1425 if ($line =~ /^0x([[:xdigit:]]+)\s*:\s*(\S+)$/io)
1427 add_jump_label(hex($1), $2, BL_TYPE_LABEL, EMPTY, TRUE);
1430 } # given ($state)
1431 } # foreach (grep(! /^\s*$/o, <NAMES>))
1433 close(NAMES);
1436 #-------------------------------------------------------------------------------
1439 # There are some variables that are multi-byte. However, only
1440 # the LSB byte of having a name. This procedure gives a name
1441 # for the higher-significant bytes.
1444 sub fix_multi_byte_variables()
1446 my ($prev_addr, $prev_name, $name, $i, $var_size);
1448 $prev_addr = EMPTY;
1449 $prev_name = '';
1450 foreach (sort {$a <=> $b} keys(%ram_by_address))
1452 $name = $ram_by_address{$_}->{NAME};
1453 $ram_names_by_address{$_} = $name;
1455 if ($prev_addr != EMPTY)
1457 $var_size = $_ - $prev_addr;
1459 if ($var_size > 1)
1461 # This is a multi-byte variable. Make the aliases.
1463 for ($i = 1; $i < $var_size; ++$i)
1465 $ram_names_by_address{$prev_addr + $i} = "($prev_name + $i)";
1468 $ram_by_address{$prev_addr}->{SIZE} = $var_size;
1472 $prev_addr = $_;
1473 $prev_name = $name;
1476 $prev_addr = EMPTY;
1477 $prev_name = '';
1478 foreach (sort {$a <=> $b} keys(%xram_by_address))
1480 $name = $xram_by_address{$_}->{NAME};
1481 $xram_names_by_address{$_} = $name;
1483 if ($prev_addr != EMPTY)
1485 $var_size = $_ - $prev_addr;
1487 if ($var_size > 1)
1489 # This is a multi-byte variable. Make the aliases.
1491 for ($i = 1; $i < $var_size; ++$i)
1493 $xram_names_by_address{$prev_addr + $i} = "($prev_name + $i)";
1496 $xram_by_address{$prev_addr}->{SIZE} = $var_size;
1500 $prev_addr = $_;
1501 $prev_name = $name;
1505 #-------------------------------------------------------------------------------
1508 # If there is left in yet so label that has no name, this here get one.
1511 sub add_names_labels()
1513 my ($addr, $label, $fidx, $lidx, $jidx, $jtidx, $cidx, $type);
1515 $fidx = 0;
1516 $lidx = 0;
1517 $jidx = 0;
1518 $jtidx = 0;
1519 $cidx = 0;
1521 for ($addr = 0; $addr <= $max_label_addr; ++$addr)
1523 $label = $labels_by_address{$addr};
1525 next if (! defined($label));
1527 $type = $label->{TYPE};
1529 next if ($type == BL_TYPE_NONE || (defined($label->{NAME}) && $label->{NAME} ne ''));
1531 if ($type == BL_TYPE_SUB)
1533 $label->{NAME} = sprintf("$label_names{$type}%03u", $fidx++);
1535 elsif ($type == BL_TYPE_LABEL)
1537 $label->{NAME} = sprintf("$label_names{$type}%03u", $lidx++);
1539 elsif ($type == BL_TYPE_JTABLE)
1541 $label->{NAME} = sprintf("$label_names{$type}%03u", $jidx++);
1543 elsif ($type == BL_TYPE_JLABEL)
1545 $label->{NAME} = sprintf("$label_names{$type}%03u", $jtidx++);
1547 elsif ($type == BL_TYPE_CONST)
1549 $label->{NAME} = sprintf("$label_names{$type}%03u", $cidx++);
1554 ################################################################################
1555 ################################################################################
1557 =back
1558 Instruction set of the 8051 family:
1560 NOP 00000000
1561 AJMP addr11 aaa00001 aaaaaaaa a10 a9 a8 1 0 0 0 1 a7-a0
1562 LJMP addr16 00000010 aaaaaaaa aaaaaaaa a15-a8 a7-a0 absolute address
1563 RR A 00000011
1564 INC A 00000100
1565 INC direct 00000101 aaaaaaaa register address
1566 INC @Ri 0000011i R0 .. R1
1567 INC Rn 00001rrr R0 .. R7
1568 JBC bit, rel 00010000 bbbbbbbb rrrrrrrr bit address relative address
1569 ACALL addr11 aaa10001 aaaaaaaa a10 a9 a8 1 0 0 0 1 a7-a0
1570 LCALL addr16 00010010 aaaaaaaa aaaaaaaa a15-a8 a7-a0 absolute address
1571 RRC A 00010011
1572 DEC A 00010100
1573 DEC direct 00010101 aaaaaaaa register address
1574 DEC @Ri 0001011i R0 .. R1
1575 DEC Rn 00011rrr R0 .. R7
1576 JB bit, rel 00100000 bbbbbbbb rrrrrrrr bit address relative address
1577 RET 00100010
1578 RL A 00100011
1579 ADD A, #data 00100100 dddddddd adat
1580 ADD A, direct 00100101 aaaaaaaa register address
1581 ADD A, @Ri 0010011i R0 .. R1
1582 ADD A, Rn 00101rrr R0 .. R7
1583 JNB bit, rel 00110000 bbbbbbbb rrrrrrrr bit address relative address
1584 RETI 00110010
1585 RLC A 00110011
1586 ADDC A, #data 00110100 dddddddd adat
1587 ADDC A, direct 00110101 aaaaaaaa register address
1588 ADDC A, @Ri 0011011i R0 .. R1
1589 ADDC A, Rn 00111rrr R0 .. R7
1590 JC rel 01000000 rrrrrrrr relative address
1591 ORL direct, A 01000010 aaaaaaaa register address
1592 ORL direct, #data 01000011 aaaaaaaa dddddddd register address adat
1593 ORL A, #data 01000100 dddddddd adat
1594 ORL A, direct 01000101 aaaaaaaa register address
1595 ORL A, @Ri 0100011i R0 .. R1
1596 ORL A, Rn 01001rrr R0 .. R7
1597 JNC rel 01010000 rrrrrrrr relative address
1598 ANL direct, A 01010010 aaaaaaaa register address
1599 ANL direct, #data 01010011 aaaaaaaa dddddddd register address adat
1600 ANL A, #data 01010100 dddddddd adat
1601 ANL A, direct 01010101 aaaaaaaa register address
1602 ANL A, @Ri 0101011i R0 .. R1
1603 ANL A, Rn 01011rrr R0 .. R7
1604 JZ rel 01100000 rrrrrrrr relative address
1605 XRL direct, A 01100010 aaaaaaaa register address
1606 XRL direct, #data 01100011 aaaaaaaa dddddddd register address adat
1607 XRL A, #data 01100100 dddddddd adat
1608 XRL A, direct 01100101 aaaaaaaa register address
1609 XRL A, @Ri 0110011i R0 .. R1
1610 XRL A, Rn 01101rrr R0 .. R7
1611 JNZ rel 01110000 rrrrrrrr relative address
1612 ORL C, bit 01110010 bbbbbbbb bit address
1613 JMP @A+DPTR 01110011
1614 MOV A, #data 01110100 dddddddd adat
1615 MOV direct, #data 01110101 aaaaaaaa dddddddd register address adat
1616 MOV @Ri, #data 0111011i dddddddd adat
1617 MOV Rn, #data 01111rrr dddddddd R0 .. R7 adat
1618 SJMP rel 10000000 rrrrrrrr relative address
1619 ANL C, bit 10000010 bbbbbbbb bit address
1620 MOVC A, @A+PC 10000011
1621 DIV AB 10000100
1622 MOV direct, direct 10000101 aaaaaaaa aaaaaaaa forrás reg. cél reg.
1623 MOV direct, @Ri 1000011i aaaaaaaa R0 .. R1 register address
1624 MOV direct, Rn 10001rrr aaaaaaaa R0 .. R7 register address
1625 MOV DPTR, #data16 10010000 dddddddd dddddddd d15-d8 d7-d0
1626 MOV bit, C 10010010 bbbbbbbb bit address
1627 MOVC A, @A+DPTR 10010011
1628 SUBB A, #data 10010100 dddddddd adat
1629 SUBB A, direct 10010101 aaaaaaaa register address
1630 SUBB A, @Ri 1001011i R0 .. R1
1631 SUBB A, Rn 10011rrr R0 .. R7
1632 ORL C, /bit 10100000 bbbbbbbb bit address
1633 MOV C, bit 10100010 bbbbbbbb bit address
1634 INC DPTR 10100011
1635 MUL AB 10100100
1636 MOV @Ri, direct 1010011i aaaaaaaa register address
1637 MOV Rn, direct 10101rrr aaaaaaaa R0 .. R7 register address
1638 ANL C, /bit 10110000 bbbbbbbb bit address
1639 CPL bit 10110010 bbbbbbbb bit address
1640 CPL C 10110011
1641 CJNE A, #data, rel 10110100 dddddddd rrrrrrrr adat relative address
1642 CJNE A, direct, rel 10110101 aaaaaaaa rrrrrrrr register address relative address
1643 CJNE @Ri, #data, rel 1011011i dddddddd rrrrrrrr R0 .. R1 data relative address
1644 CJNE Rn, #data, rel 10111rrr dddddddd rrrrrrrr R0 .. R7 data relative address
1645 PUSH direct 11000000 aaaaaaaa register address
1646 CLR bit 11000010 bbbbbbbb bit address
1647 CLR C 11000011
1648 SWAP A 11000100
1649 XCH A, direct 11000101 aaaaaaaa register address
1650 XCH A, @Ri 1100011i R0 .. R1
1651 XCH A, Rn 11001rrr R0 .. R7
1652 POP direct 11010000 aaaaaaaa register address
1653 SETB bit 11010010 bbbbbbbb bit address
1654 SETB C 11010011
1655 DA A 11010100
1656 DJNZ direct, rel 11010101 aaaaaaaa rrrrrrrr register address relative address
1657 XCHD A, @Ri 1101011i R0 .. R1
1658 DJNZ Rn, rel 11011rrr rrrrrrrr R0 .. R7 relative address
1659 MOVX A, @DPTR 11100000
1660 MOVX A, @Ri 1110001i R0 .. R1
1661 CLR A 11100100
1662 MOV A, direct 11100101 aaaaaaaa register address The "MOV A, ACC" invalid instruction.
1663 MOV A, @Ri 1110011i R0 .. R1
1664 MOV A, Rn 11101rrr R0 .. R7
1665 MOVX @DPTR, A 11110000
1666 MOVX @Ri, A 1111001i R0 .. R1
1667 CPL A 11110100
1668 MOV direct, A 11110101 aaaaaaaa register address
1669 MOV @Ri, A 1111011i R0 .. R1
1670 MOV Rn, A 11111rrr R0 .. R7
1671 =cut
1673 #-------------------------------------------------------------------------------
1676 # Expand a relative offset value.
1679 sub expand_offset($)
1681 my $Offset = $_[0];
1683 return ($Offset & 0x80) ? -(($Offset ^ 0xFF) + 1) : $Offset;
1686 #-------------------------------------------------------------------------------
1689 # Finds address of branchs and procedures.
1692 sub label_finder($$)
1694 my ($Address, $BlockRef) = @_;
1695 my ($instr_size, $instr);
1696 my ($addr, $instr_mask0, $instr_mask1, $instr_mask2);
1698 $instr_size = $BlockRef->{SIZE};
1699 $instr = $rom[$Address];
1701 $instr_mask0 = $instr & 0x1F;
1702 $instr_mask1 = $instr & 0xFE;
1703 $instr_mask2 = $instr & 0xF8;
1705 if ($instr_mask0 == INST_AJMP)
1707 # AJMP addr11 aaa00001 aaaaaaaa a10 a9 a8 0 0 0 0 1 a7-a0
1709 $addr = (($Address + $instr_size) & 0xF800) | (($instr & 0xE0) << 3) | $rom[$Address + 1];
1710 add_jump_label($addr, '', BL_TYPE_LABEL, $Address, FALSE);
1712 elsif ($instr_mask0 == INST_ACALL)
1714 # ACALL addr11 aaa10001 aaaaaaaa a10 a9 a8 1 0 0 0 1 a7-a0
1716 $addr = (($Address + $instr_size) & 0xF800) | (($instr & 0xE0) << 3) | $rom[$Address + 1];
1717 add_func_label($addr, '', FALSE);
1719 elsif ($instr_mask1 == INST_CJNE__Ri_DATA ||
1720 $instr_mask2 == INST_CJNE_Rn_DATA)
1722 # CJNE @Ri, #data, rel 1011011i dddddddd rrrrrrrr R0 .. R1 data relative address
1723 # CJNE Rn, #data, rel 10111rrr dddddddd rrrrrrrr R0 .. R7 data relative address
1725 $addr = $Address + $instr_size + expand_offset($rom[$Address + 2]);
1726 add_jump_label($addr, '', BL_TYPE_LABEL, EMPTY, FALSE);
1728 elsif ($instr_mask2 == INST_DJNZ_Rn)
1730 # DJNZ Rn, rel 11011rrr rrrrrrrr R0 .. R7 relative address
1732 $addr = $Address + $instr_size + expand_offset($rom[$Address + 1]);
1733 add_jump_label($addr, '', BL_TYPE_LABEL, EMPTY, FALSE);
1735 elsif ($instr == INST_LJMP)
1737 # LJMP addr16 00000010 aaaaaaaa aaaaaaaa a15-a8 a7-a0 absolute address
1739 $addr = ($rom[$Address + 1] << 8) | $rom[$Address + 2];
1740 add_jump_label($addr, '', BL_TYPE_LABEL, $Address, FALSE);
1742 elsif ($instr == INST_LCALL)
1744 # LCALL addr16 00010010 aaaaaaaa aaaaaaaa a15-a8 a7-a0 absolute address
1746 $addr = ($rom[$Address + 1] << 8) | $rom[$Address + 2];
1747 add_func_label($addr, '', FALSE);
1749 elsif ($instr == INST_JBC_BIT ||
1750 $instr == INST_JB_BIT ||
1751 $instr == INST_JNB_BIT ||
1752 $instr == INST_CJNE_A_DATA ||
1753 $instr == INST_CJNE_A_DIRECT ||
1754 $instr == INST_DJNZ_DIRECT)
1756 # JBC bit, rel 00010000 bbbbbbbb rrrrrrrr bit address relative address
1757 # JB bit, rel 00100000 bbbbbbbb rrrrrrrr bit address relative address
1758 # JNB bit, rel 00110000 bbbbbbbb rrrrrrrr bit address relative address
1759 # CJNE A, #data, rel 10110100 dddddddd rrrrrrrr data relative address
1760 # CJNE A, direct, rel 10110101 aaaaaaaa rrrrrrrr register address relative address
1761 # DJNZ direct, rel 11010101 aaaaaaaa rrrrrrrr register address relative address
1763 $addr = $Address + $instr_size + expand_offset($rom[$Address + 2]);
1764 add_jump_label($addr, '', BL_TYPE_LABEL, EMPTY, FALSE);
1766 elsif ($instr == INST_JC ||
1767 $instr == INST_JNC ||
1768 $instr == INST_JZ ||
1769 $instr == INST_JNZ ||
1770 $instr == INST_SJMP)
1772 # JC rel 01000000 rrrrrrrr relative address
1773 # JNC rel 01010000 rrrrrrrr relative address
1774 # JZ rel 01100000 rrrrrrrr relative address
1775 # JNZ rel 01110000 rrrrrrrr relative address
1776 # SJMP rel 10000000 rrrrrrrr relative address
1778 $addr = $Address + $instr_size + expand_offset($rom[$Address + 1]);
1779 add_jump_label($addr, '', BL_TYPE_LABEL, EMPTY, FALSE);
1783 #-------------------------------------------------------------------------------
1786 # If exists a variable name wich belong to the $Address, then returns it.
1787 # Otherwise, returns the address.
1790 sub reg_name($$)
1792 my ($Address, $StrRef) = @_;
1793 my ($ram, $str);
1795 if ($Address <= BANK_LAST_ADDR)
1797 # This register belongs to one of the register bank.
1799 my $bank = ($Address >> 3) & 3;
1800 my $reg = $Address & 7;
1802 $str = ($gen_assembly_code) ? sprintf("0x%02X", $Address) : "R${reg}<#$bank>";
1803 ${$StrRef} = $str;
1805 if (defined($ram_names_by_address{$Address}))
1807 my $var = $ram_names_by_address{$Address};
1809 printf STDERR ("This address (0x%02X) belongs to two names: \"$str\" and \"$var\"\n", $Address);
1812 elsif (defined($ram = $sfr_by_address{$Address}) && $ram->{NAME} ne '')
1814 $str = $ram->{NAME};
1815 ${$StrRef} = $str;
1817 elsif (defined($ram = $ram_names_by_address{$Address}))
1819 $str = sprintf "0x%02X", $Address;
1820 ${$StrRef} = "[$str]";
1821 $str = $ram;
1823 else
1825 $str = sprintf "0x%02X", $Address;
1826 ${$StrRef} = "[$str]";
1829 return $str;
1832 #-------------------------------------------------------------------------------
1835 # If exists a XRAM name wich belong to the $Address, then returns it.
1836 # Otherwise, returns the address.
1839 sub xram_name($$)
1841 my ($Address, $StrRef) = @_;
1842 my ($xram, $str);
1844 $str = sprintf "0x%04X", $Address;
1845 ${$StrRef} = $str;
1847 $str = $xram if (defined($xram = $xram_names_by_address{$Address}));
1849 return $str;
1852 #-------------------------------------------------------------------------------
1855 # If exists a iRAM name wich belong to the $Address, then returns it.
1856 # Otherwise, returns the address.
1859 sub iram_name($$)
1861 my ($Address, $StrRef) = @_;
1862 my ($ram, $str);
1864 $str = sprintf "0x%02X", $Address;
1865 ${$StrRef} = $str;
1866 $ram = $ram_names_by_address{$Address};
1868 $str = $ram if (defined($ram));
1870 return $str;
1873 #-------------------------------------------------------------------------------
1876 # If exists a bit name wich belong to the $Address, then returns it.
1877 # Otherwise, returns the address.
1880 sub bit_name($$)
1882 my ($Address, $StrRef) = @_;
1883 my ($bit, $str);
1885 if (defined($bit = $sfr_bit_by_address{$Address}) && $bit->{NAME} ne '')
1887 $str = $bit->{NAME};
1888 ${$StrRef} = $str;
1890 elsif (defined($bit = $bit_by_address{$Address}) && $bit->{NAME} ne '')
1892 $str = sprintf "0x%02X", $Address;
1893 ${$StrRef} = "[$str]";
1894 $str = $bit->{NAME};
1896 else
1898 $str = sprintf "0x%02X", $Address;
1899 ${$StrRef} = "[$str]";
1902 return $str;
1905 #-------------------------------------------------------------------------------
1908 # If exists a label name wich belong to the $Address, then returns it.
1909 # Otherwise, returns the address.
1912 sub labelname($)
1914 my $Address = $_[0];
1915 my $label = $labels_by_address{$Address};
1917 return ((defined($label)) ? $label->{NAME} : (sprintf "0x%04X", $Address));
1920 #-------------------------------------------------------------------------------
1923 # Auxiliary procedure of prints.
1926 sub print_3($$$)
1928 return if ($decoder_silent_level > SILENT0);
1930 if ($no_explanations)
1932 print(($_[1] ne '') ? "$_[0]\t$_[1]\n" : "$_[0]\n");
1934 else
1936 print "$_[0]\t" . align($_[1], EXPL_ALIGN_SIZE) . "; $_[2]\n";
1940 #-------------------------------------------------------------------------------
1943 # Invalidates the DPTR and the Rx registers.
1946 sub invalidate_DPTR_Rx()
1948 $DPTR = EMPTY;
1949 @R_regs[0 .. 7] = ((EMPTY) x 8);
1952 #-------------------------------------------------------------------------------
1955 # Invalidates the DPTR or the Rx registers.
1958 sub invalidate_reg($)
1960 my $Address = $_[0];
1962 return if ($Address == EMPTY);
1964 if ($Address == DPL || $Address == DPH)
1966 $DPTR = EMPTY;
1968 elsif ($Address <= BANK_LAST_ADDR)
1970 $R_regs[$Address & 7] = EMPTY;
1974 #-------------------------------------------------------------------------------
1977 # Carries out the operations with the R registers.
1980 use constant Rx_INV => 0;
1981 use constant Rx_INC => 1;
1982 use constant Rx_DEC => 2;
1983 use constant Rx_MOV => 3;
1985 sub operation_R_reg
1987 my $Rx = shift(@_);
1988 my $Oper = shift(@_);
1989 my $r;
1991 if ($Oper == Rx_INV)
1993 $R_regs[$Rx] = EMPTY;
1995 elsif ($Oper == Rx_INC)
1997 $r = $R_regs[$Rx];
1999 if ($r != EMPTY)
2001 ++$r;
2002 $R_regs[$Rx] = $r & 0xFF;
2003 return TRUE;
2006 elsif ($Oper == Rx_DEC)
2008 $r = $R_regs[$Rx];
2010 if ($r != EMPTY)
2012 --$r;
2013 $R_regs[$Rx] = $r & 0xFF;
2014 return TRUE;
2017 elsif ($Oper == Rx_MOV)
2019 $R_regs[$Rx] = shift(@_) & 0xFF;
2020 return TRUE;
2023 return FALSE;
2026 #-------------------------------------------------------------------------------
2029 # If possible, returns the character.
2032 sub present_char($)
2034 my $Ch = $_[0];
2036 if ($Ch >= ord(' ') && $Ch < 0x7F)
2038 return sprintf " {'%c'}", $Ch;
2040 elsif (defined($control_characters{$Ch}))
2042 return " {'$control_characters{$Ch}'}";
2045 return '';
2048 #-------------------------------------------------------------------------------
2051 # Decodes value of the $Ch.
2054 sub decode_char($)
2056 my $Ch = $_[0];
2058 if ($Ch >= ord(' ') && $Ch < 0x7F)
2060 return sprintf "'%c'", $Ch;
2062 elsif (defined($control_characters{$Ch}))
2064 return "'$control_characters{$Ch}'";
2067 return sprintf "0x%02X", $Ch;
2070 #-------------------------------------------------------------------------------
2073 # Determines direction of jump.
2076 sub jump_direction($)
2078 my $TargetAddr = $_[0];
2080 if ($dcd_address < $TargetAddr)
2082 return ' (forward)';
2084 elsif ($dcd_address == $TargetAddr)
2086 return '';
2088 else
2090 return ' (backward)';
2094 #-------------------------------------------------------------------------------
2097 # Returns with TRUE if the instruction use indirect RAM addressing
2098 # with @Ri.
2101 sub is_Ri_instr($)
2103 my $Address = $_[0];
2104 my $block;
2106 $block = \%{$blocks_by_address{$Address}};
2107 return FALSE if (! defined($block) || $block->{TYPE} != BLOCK_INSTR);
2109 # These instructions use indirect RAM addressing with @Ri?
2110 return defined($indirect_addr_instr{$rom[$Address] & 0xFE});
2113 # @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
2114 # @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
2115 #@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@
2116 #@@@@@@@@@@@@@@@@@@@@@ These the instruction decoders. @@@@@@@@@@@@@@@@@@@@@
2117 #@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@
2118 # @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
2119 # @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
2121 sub ajmp()
2123 my ($addr, $a11, $rb0, $rb1, $str0, $str1, $str2);
2125 # AJMP addr11 aaa00001 aaaaaaaa a10 a9 a8 0 0 0 0 1 a7-a0
2127 if ($decoder_silent_level == SILENT0)
2129 $rb1 = (($dcd_instr & 0xE0) << 3) | $dcd_parm0;
2130 $addr = (($dcd_address + $dcd_instr_size) & 0xF800) | $rb1;
2131 $rb0 = labelname($addr);
2132 $a11 = sprintf "0x%04X", $rb1;
2133 $str0 = sprintf "0x%04X", $addr;
2135 if ($dcd_address < $addr)
2137 $str1 = '';
2138 $str2 = ' (forward)';
2140 elsif ($dcd_address == $addr)
2142 $str1 = ' (endless loop)';
2143 $str2 = '';
2145 else
2147 $str1 = '';
2148 $str2 = ' (backward)';
2151 print_3('ajmp', $rb0, "Jumps$str2 hither: $str0 (PC += $dcd_instr_size, PC(10-0) = $a11)$str1");
2154 invalidate_DPTR_Rx();
2155 $prev_is_jump = TRUE;
2158 #-------------------------------------------------------------------------------
2160 sub acall()
2162 my ($addr, $rb0, $rb1, $str0, $str1, $str2);
2164 # ACALL addr11 aaa10001 aaaaaaaa a10 a9 a8 1 0 0 0 1 a7-a0
2166 if ($decoder_silent_level == SILENT0)
2168 $rb1 = (($dcd_instr & 0xE0) << 3) | $dcd_parm0;
2169 $addr = (($dcd_address + $dcd_instr_size) & 0xF800) | $rb1;
2170 $rb0 = labelname($addr);
2171 $str0 = sprintf "0x%04X", $rb1;
2172 $str1 = sprintf "0x%04X", $addr;
2173 $str2 = jump_direction($addr);
2174 print_3('acall', $rb0, "Calls$str2 this: $str1 (PC += $dcd_instr_size, [++SP] = PCL, [++SP] = PCH, PC(10-0) = $str0)");
2177 invalidate_DPTR_Rx();
2180 #-------------------------------------------------------------------------------
2182 sub inc_ind_Ri()
2184 # INC @Ri 0000011i R0 .. R1
2186 my $i = $R_regs[$dcd_Ri_regs];
2188 add_ram($i, '', RAM_TYPE_IND, FALSE) if ($decoder_silent_level == SILENT1);
2190 print_3('inc', "\@$dcd_Ri_name", "++[$dcd_Ri_name]");
2191 invalidate_reg($i);
2194 #-------------------------------------------------------------------------------
2196 sub dec_ind_Ri()
2198 # DEC @Ri 0001011i R0 .. R1
2200 my $i = $R_regs[$dcd_Ri_regs];
2202 add_ram($i, '', RAM_TYPE_IND, FALSE) if ($decoder_silent_level == SILENT1);
2204 print_3('dec', "\@$dcd_Ri_name", "--[$dcd_Ri_name]");
2205 invalidate_reg($i);
2208 #-------------------------------------------------------------------------------
2210 sub add_A_ind_Ri()
2212 # ADD A, @Ri 0010011i R0 .. R1
2214 my $i = $R_regs[$dcd_Ri_regs];
2216 add_ram($i, '', RAM_TYPE_IND, FALSE) if ($decoder_silent_level == SILENT1);
2218 print_3('add', "A, \@$dcd_Ri_name", "ACC += [$dcd_Ri_name]");
2221 #-------------------------------------------------------------------------------
2223 sub addc_A_ind_Ri()
2225 # ADDC A, @Ri 0011011i R0 .. R1
2227 my $i = $R_regs[$dcd_Ri_regs];
2229 add_ram($i, '', RAM_TYPE_IND, FALSE) if ($decoder_silent_level == SILENT1);
2231 print_3('addc', "A, \@$dcd_Ri_name", "ACC += [$dcd_Ri_name] + CY");
2234 #-------------------------------------------------------------------------------
2236 sub orl_A_ind_Ri()
2238 # ORL A, @Ri 0100011i R0 .. R1
2240 my $i = $R_regs[$dcd_Ri_regs];
2242 add_ram($i, '', RAM_TYPE_IND, FALSE) if ($decoder_silent_level == SILENT1);
2244 print_3('orl', "A, \@$dcd_Ri_name", "ACC |= [$dcd_Ri_name]");
2247 #-------------------------------------------------------------------------------
2249 sub anl_A_ind_Ri()
2251 # ANL A, @Ri 0101011i R0 .. R1
2253 my $i = $R_regs[$dcd_Ri_regs];
2255 add_ram($i, '', RAM_TYPE_IND, FALSE) if ($decoder_silent_level == SILENT1);
2257 print_3('anl', "A, \@$dcd_Ri_name", "ACC &= [$dcd_Ri_name]");
2260 #-------------------------------------------------------------------------------
2262 sub xrl_A_ind_Ri()
2264 # XRL A, @Ri 0110011i R0 .. R1
2266 my $i = $R_regs[$dcd_Ri_regs];
2268 add_ram($i, '', RAM_TYPE_IND, FALSE) if ($decoder_silent_level == SILENT1);
2270 print_3('xrl', "A, \@$dcd_Ri_name", "ACC ^= [$dcd_Ri_name]");
2273 #-------------------------------------------------------------------------------
2275 sub mov_ind_Ri_data()
2277 my ($rb, $str);
2279 # MOV @Ri, #data 0111011i dddddddd data
2281 my $i = $R_regs[$dcd_Ri_regs];
2283 if ($decoder_silent_level == SILENT0)
2285 $rb = sprintf "0x%02X", $dcd_parm0;
2286 $str = present_char($dcd_parm0);
2287 print_3('mov', "\@$dcd_Ri_name, #$rb", "[$dcd_Ri_name] = $rb$str");
2289 elsif ($decoder_silent_level == SILENT1)
2291 add_ram($i, '', RAM_TYPE_IND, FALSE);
2294 invalidate_reg($i);
2297 #-------------------------------------------------------------------------------
2299 sub mov_direct_ind_Ri()
2301 my ($rb, $name);
2303 # MOV direct, @Ri 1000011i aaaaaaaa R0 .. R1 register address
2305 my $i = $R_regs[$dcd_Ri_regs];
2307 if ($decoder_silent_level == SILENT0)
2309 $rb = reg_name($dcd_parm0, \$name);
2310 print_3('mov', "$rb, \@$dcd_Ri_name", "$name = [$dcd_Ri_name]");
2312 elsif ($decoder_silent_level == SILENT1)
2314 add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE);
2315 add_ram($i, '', RAM_TYPE_IND, FALSE);
2318 invalidate_reg($dcd_parm0);
2321 #-------------------------------------------------------------------------------
2323 sub subb_A_ind_Ri()
2325 # SUBB A, @Ri 1001011i R0 .. R1
2327 my $i = $R_regs[$dcd_Ri_regs];
2329 add_ram($i, '', RAM_TYPE_IND, FALSE) if ($decoder_silent_level == SILENT1);
2331 print_3('subb', "A, \@$dcd_Ri_name", "ACC -= [$dcd_Ri_name] + CY");
2334 #-------------------------------------------------------------------------------
2336 sub mov_ind_Ri_direct()
2338 my ($rb, $name);
2340 # MOV @Ri, direct 1010011i aaaaaaaa register address
2342 my $i = $R_regs[$dcd_Ri_regs];
2344 if ($decoder_silent_level == SILENT0)
2346 $rb = reg_name($dcd_parm0, \$name);
2347 print_3('mov', "\@$dcd_Ri_name, $rb", "[$dcd_Ri_name] = $name");
2349 elsif ($decoder_silent_level == SILENT1)
2351 add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE);
2352 add_ram($i, '', RAM_TYPE_IND, FALSE);
2355 invalidate_reg($i);
2358 #-------------------------------------------------------------------------------
2360 sub cjne_ind_Ri_data()
2362 my ($addr, $rb, $str0, $str1, $str2, $str3);
2364 # CJNE @Ri, #data, rel 1011011i dddddddd rrrrrrrr R0 .. R1 data relative address
2366 my $i = $R_regs[$dcd_Ri_regs];
2368 if ($decoder_silent_level == SILENT0)
2370 $addr = $dcd_address + $dcd_instr_size + expand_offset($dcd_parm1);
2371 $rb = labelname($addr);
2372 $str0 = sprintf "0x%02X", $dcd_parm0;
2373 $str1 = sprintf "0x%04X", $addr;
2374 $str2 = jump_direction($addr);
2375 $str3 = present_char($dcd_parm0);
2376 print_3('cjne', "\@$dcd_Ri_name, #$str0, $rb", "If ([$dcd_Ri_name] != $str0$str3) then jumps$str2 hither: $str1");
2378 elsif ($decoder_silent_level == SILENT1)
2380 add_ram($i, '', RAM_TYPE_IND, FALSE);
2383 invalidate_DPTR_Rx();
2384 $prev_is_jump = TRUE;
2387 #-------------------------------------------------------------------------------
2389 sub xch_A_ind_Ri()
2391 # XCH A, @Ri 1100011i R0 .. R1
2393 my $i = $R_regs[$dcd_Ri_regs];
2395 add_ram($i, '', RAM_TYPE_IND, FALSE) if ($decoder_silent_level == SILENT1);
2397 print_3('xch', "A, \@$dcd_Ri_name", "ACC <-> [$dcd_Ri_name]");
2398 invalidate_reg($i);
2401 #-------------------------------------------------------------------------------
2403 sub xchd_A_ind_Ri()
2405 # XCHD A, @Ri 1101011i R0 .. R1
2407 my $i = $R_regs[$dcd_Ri_regs];
2409 add_ram($i, '', RAM_TYPE_IND, FALSE) if ($decoder_silent_level == SILENT1);
2411 print_3('xchd', "A, \@$dcd_Ri_name", "ACC(3-0) <-> [$dcd_Ri_name](3-0)");
2412 invalidate_reg($i);
2415 #-------------------------------------------------------------------------------
2417 sub movx_A_ind_Ri()
2419 # MOVX A, @Ri 1110001i R0 .. R1
2421 my $i = $R_regs[$dcd_Ri_regs];
2423 add_xram($i, '', FALSE) if ($i != EMPTY && $decoder_silent_level == SILENT1);
2425 print_3('movx', "A, \@$dcd_Ri_name", "ACC = XRAM[$dcd_Ri_name]");
2428 #-------------------------------------------------------------------------------
2430 sub mov_A_ind_Ri()
2432 # MOV A, @Ri 1110011i R0 .. R1
2434 my $i = $R_regs[$dcd_Ri_regs];
2436 add_ram($i, '', RAM_TYPE_IND, FALSE) if ($decoder_silent_level == SILENT1);
2438 print_3('mov', "A, \@$dcd_Ri_name", "ACC = [$dcd_Ri_name]");
2441 #-------------------------------------------------------------------------------
2443 sub movx_ind_Ri_A()
2445 # MOVX @Ri, A 1111001i R0 .. R1
2447 my $i = $R_regs[$dcd_Ri_regs];
2449 add_xram($i, '', FALSE) if ($i != EMPTY && $decoder_silent_level == SILENT1);
2451 print_3('movx', "\@$dcd_Ri_name, A", "XRAM[$dcd_Ri_name] = ACC");
2452 invalidate_reg($i);
2455 #-------------------------------------------------------------------------------
2457 sub mov_ind_Ri_A()
2459 # MOV @Ri, A 1111011i R0 .. R1
2461 my $i = $R_regs[$dcd_Ri_regs];
2463 add_ram($i, '', RAM_TYPE_IND, FALSE) if ($decoder_silent_level == SILENT1);
2465 print_3('mov', "\@$dcd_Ri_name, A", "[$dcd_Ri_name] = ACC");
2466 invalidate_reg($i);
2469 #-------------------------------------------------------------------------------
2471 sub inc_Rn()
2473 my $str = '';
2475 # INC Rn 00001rrr R0 .. R7
2477 if (operation_R_reg($dcd_Rn_regs, Rx_INC))
2479 $str = sprintf " (0x%02X)", $R_regs[$dcd_Rn_regs];
2482 print_3('inc', $dcd_Rn_name, "++$dcd_Rn_name$str");
2485 #-------------------------------------------------------------------------------
2487 sub dec_Rn()
2489 my $str = '';
2491 # DEC Rn 00011rrr R0 .. R7
2493 if (operation_R_reg($dcd_Rn_regs, Rx_DEC))
2495 $str = sprintf " (0x%02X)", $R_regs[$dcd_Rn_regs];
2498 print_3('dec', $dcd_Rn_name, "--$dcd_Rn_name$str");
2501 #-------------------------------------------------------------------------------
2503 sub add_A_Rn()
2505 # ADD A, Rn 00101rrr R0 .. R7
2507 print_3('add', "A, $dcd_Rn_name", "ACC += $dcd_Rn_name");
2510 #-------------------------------------------------------------------------------
2512 sub addc_A_Rn()
2514 # ADDC A, Rn 00111rrr R0 .. R7
2516 print_3('addc', "A, $dcd_Rn_name", "ACC += $dcd_Rn_name + CY");
2519 #-------------------------------------------------------------------------------
2521 sub orl_A_Rn()
2523 # ORL A, Rn 01001rrr R0 .. R7
2525 print_3('orl', "A, $dcd_Rn_name", "ACC |= $dcd_Rn_name");
2528 #-------------------------------------------------------------------------------
2530 sub anl_A_Rn()
2532 # ANL A, Rn 01011rrr R0 .. R7
2534 print_3('anl', "A, $dcd_Rn_name", "ACC &= $dcd_Rn_name");
2537 #-------------------------------------------------------------------------------
2539 sub xrl_A_Rn()
2541 # XRL A, Rn 01101rrr R0 .. R7
2543 print_3('xrl', "A, $dcd_Rn_name", "ACC ^= $dcd_Rn_name");
2546 #-------------------------------------------------------------------------------
2548 sub mov_Rn_data()
2550 my ($rb, $name, $str);
2552 # MOV Rn, #data 01111rrr dddddddd R0 .. R7 data
2554 if ($decoder_silent_level == SILENT0)
2556 if (($dcd_Rn_regs == 0 || $dcd_Rn_regs == 1) && is_Ri_instr($dcd_address + $dcd_instr_size))
2558 $rb = iram_name($dcd_parm0, \$name);
2559 print_3('mov', "$dcd_Rn_name, #$rb", "$dcd_Rn_name = $name");
2561 else
2563 $rb = sprintf "0x%02X", $dcd_parm0;
2564 $str = present_char($dcd_parm0);
2565 print_3('mov', "$dcd_Rn_name, #$rb", "$dcd_Rn_name = $rb$str");
2569 operation_R_reg($dcd_Rn_regs, Rx_MOV, $dcd_parm0);
2572 #-------------------------------------------------------------------------------
2574 sub mov_direct_Rn()
2576 my ($rb, $name);
2578 # MOV direct, Rn 10001rrr aaaaaaaa R0 .. R7 register address
2580 if ($decoder_silent_level == SILENT0)
2582 $rb = reg_name($dcd_parm0, \$name);
2583 print_3('mov', "$rb, $dcd_Rn_name", "$name = $dcd_Rn_name");
2585 elsif ($decoder_silent_level == SILENT1)
2587 add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE);
2590 invalidate_reg($dcd_parm0);
2593 #-------------------------------------------------------------------------------
2595 sub subb_A_Rn()
2597 # SUBB A, Rn 10011rrr R0 .. R7
2599 print_3('subb', "A, $dcd_Rn_name", "ACC -= $dcd_Rn_name + CY");
2602 #-------------------------------------------------------------------------------
2604 sub mov_Rn_direct()
2606 my ($rb, $name);
2608 # MOV Rn, direct 10101rrr aaaaaaaa R0 .. R7 register address
2610 if ($decoder_silent_level == SILENT0)
2612 $rb = reg_name($dcd_parm0, \$name);
2613 print_3('mov', "$dcd_Rn_name, $rb", "$dcd_Rn_name = $name");
2615 elsif ($decoder_silent_level == SILENT1)
2617 add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE);
2620 operation_R_reg($dcd_Rn_regs, Rx_INV);
2623 #-------------------------------------------------------------------------------
2625 sub cjne_Rn_data()
2627 my ($addr, $rb, $str0, $str1, $str2, $str3);
2629 # CJNE Rn, #data, rel 10111rrr dddddddd rrrrrrrr R0 .. R7 data relative address
2631 if ($decoder_silent_level == SILENT0)
2633 $addr = $dcd_address + $dcd_instr_size + expand_offset($dcd_parm1);
2634 $rb = labelname($addr);
2635 $str0 = sprintf "0x%02X", $dcd_parm0;
2636 $str1 = sprintf "0x%04X", $addr;
2637 $str2 = jump_direction($addr);
2638 $str3 = present_char($dcd_parm0);
2639 print_3('cjne', "$dcd_Rn_name, #$str0, $rb", "If ($dcd_Rn_name != $str0$str3) then jumps$str2 hither: $str1");
2642 invalidate_DPTR_Rx();
2643 $prev_is_jump = TRUE;
2646 #-------------------------------------------------------------------------------
2648 sub xch_A_Rn()
2650 # XCH A, Rn 11001rrr R0 .. R7
2652 print_3('xch', "A, $dcd_Rn_name", "ACC <-> $dcd_Rn_name");
2653 operation_R_reg($dcd_Rn_regs, Rx_INV);
2656 #-------------------------------------------------------------------------------
2658 sub djnz_Rn()
2660 my ($addr, $rb, $str0, $str1, $str2);
2662 # DJNZ Rn, rel 11011rrr rrrrrrrr R0 .. R7 relative address
2664 if ($decoder_silent_level == SILENT0)
2666 $addr = $dcd_address + $dcd_instr_size + expand_offset($dcd_parm0);
2667 $rb = labelname($addr);
2668 $str0 = ($dcd_address == $addr) ? ' (waiting loop)' : '';
2669 $str1 = sprintf "0x%04X", $addr;
2670 $str2 = jump_direction($addr);
2671 print_3('djnz', "$dcd_Rn_name, $rb", "If (--$dcd_Rn_name != 0) then jumps$str2 hither: $str1$str0");
2674 invalidate_DPTR_Rx();
2675 $prev_is_jump = TRUE;
2678 #-------------------------------------------------------------------------------
2680 sub mov_A_Rn()
2682 # MOV A, Rn 11101rrr R0 .. R7
2684 print_3('mov', "A, $dcd_Rn_name", "ACC = $dcd_Rn_name");
2687 #-------------------------------------------------------------------------------
2689 sub mov_Rn_A()
2691 # MOV Rn, A 11111rrr R0 .. R7
2693 print_3('mov', "$dcd_Rn_name, A", "$dcd_Rn_name = ACC");
2694 operation_R_reg($dcd_Rn_regs, Rx_INV);
2697 #-------------------------------------------------------------------------------
2699 sub nop()
2701 # NOP 00000000
2702 print "nop\n" if ($decoder_silent_level == SILENT0);
2705 #-------------------------------------------------------------------------------
2707 sub ljmp()
2709 my ($addr, $rb, $str0, $str1, $str2);
2711 # LJMP addr16 00000010 aaaaaaaa aaaaaaaa a15-a8 a7-a0 absolute address
2713 if ($decoder_silent_level == SILENT0)
2715 $addr = ($dcd_parm0 << 8) | $dcd_parm1;
2716 $rb = labelname($addr);
2717 $str0 = sprintf "0x%04X", $addr;
2719 if ($dcd_address < $addr)
2721 $str1 = '';
2722 $str2 = ' (forward)';
2724 elsif ($dcd_address == $addr)
2726 $str1 = ' (endless loop)';
2727 $str2 = '';
2729 else
2731 $str1 = '';
2732 $str2 = ' (backward)';
2735 print_3('ljmp', $rb, "Jumps$str2 hither: $str0$str1");
2738 invalidate_DPTR_Rx();
2739 $prev_is_jump = TRUE;
2742 #-------------------------------------------------------------------------------
2744 sub rr_A()
2746 # RR A 00000011
2748 print_3('rr', 'A', 'ACC[76543210] = ACC[07654321]');
2751 #-------------------------------------------------------------------------------
2753 sub inc_A()
2755 # INC A 00000100
2757 print_3('inc', 'A', '++ACC');
2760 #-------------------------------------------------------------------------------
2762 sub inc_direct()
2764 my ($rb, $name);
2766 # INC direct 00000101 aaaaaaaa register address
2768 if ($decoder_silent_level == SILENT0)
2770 $rb = reg_name($dcd_parm0, \$name);
2771 print_3('inc', $rb, "++$name");
2773 elsif ($decoder_silent_level == SILENT1)
2775 add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE);
2778 invalidate_reg($dcd_parm0);
2781 #-------------------------------------------------------------------------------
2783 sub jbc_bit()
2785 my ($addr, $rb0, $rb1, $name0, $str0, $str1);
2787 # JBC bit, rel 00100000 bbbbbbbb rrrrrrrr bit address relative address
2789 if ($decoder_silent_level == SILENT0)
2791 $addr = $dcd_address + $dcd_instr_size + expand_offset($dcd_parm1);
2792 $rb0 = bit_name($dcd_parm0, \$name0);
2793 $rb1 = labelname($addr);
2794 $str0 = sprintf "0x%04X", $addr;
2795 $str1 = jump_direction($addr);
2796 print_3('jbc', "$rb0, $rb1", "If ($name0 == H) then $name0 = L and jumps$str1 hither: $str0");
2798 elsif ($decoder_silent_level == SILENT1)
2800 add_bit($dcd_parm0, '', FALSE);
2803 invalidate_DPTR_Rx();
2804 $prev_is_jump = TRUE;
2807 #-------------------------------------------------------------------------------
2809 sub lcall()
2811 my ($addr, $rb, $str0, $str1);
2813 # LCALL addr16 00010010 aaaaaaaa aaaaaaaa a15-a8 a7-a0 absolute address
2815 if ($decoder_silent_level == SILENT0)
2817 $addr = ($dcd_parm0 << 8) | $dcd_parm1;
2818 $rb = labelname($addr);
2819 $str0 = sprintf "0x%04X", $addr;
2820 $str1 = jump_direction($addr);
2821 print_3('lcall', $rb, "Calls$str1 this: $str0 (PC += $dcd_instr_size, [++SP] = PCL, [++SP] = PCH, PC = $str0)");
2824 invalidate_DPTR_Rx();
2827 #-------------------------------------------------------------------------------
2829 sub rrc_A()
2831 # RRC A 00010011
2833 print_3('rrc', 'A', 'ACC[76543210] = ACC[C7654321], CY = ACC[0]');
2836 #-------------------------------------------------------------------------------
2838 sub dec_A()
2840 # DEC A 00010100
2842 print_3('dec', 'A', '--ACC');
2845 #-------------------------------------------------------------------------------
2847 sub dec_direct()
2849 my ($rb, $name);
2851 # DEC direct 00010101 aaaaaaaa register address
2853 if ($decoder_silent_level == SILENT0)
2855 $rb = reg_name($dcd_parm0, \$name);
2856 print_3('dec', $rb, "--$name");
2858 elsif ($decoder_silent_level == SILENT1)
2860 add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE);
2863 invalidate_reg($dcd_parm0);
2866 #-------------------------------------------------------------------------------
2868 sub jb_bit()
2870 my ($addr, $rb0, $rb1, $name0, $str0, $str1, $str2);
2872 # JB bit, rel 00100000 bbbbbbbb rrrrrrrr bit address relative address
2874 if ($decoder_silent_level == SILENT0)
2876 $addr = $dcd_address + $dcd_instr_size + expand_offset($dcd_parm1);
2877 $rb0 = bit_name($dcd_parm0, \$name0);
2878 $rb1 = labelname($addr);
2879 $str0 = ($dcd_address == $addr) ? ' (waiting loop)' : '';
2880 $str1 = sprintf "0x%04X", $addr;
2881 $str2 = jump_direction($addr);
2882 print_3('jb', "$rb0, $rb1", "If ($name0 == H) then jumps$str2 hither: $str1$str0");
2884 elsif ($decoder_silent_level == SILENT1)
2886 add_bit($dcd_parm0, '', FALSE);
2889 invalidate_DPTR_Rx();
2890 $prev_is_jump = TRUE;
2893 #-------------------------------------------------------------------------------
2895 sub ret()
2897 # RET 00100010
2899 print_3('ret', '', 'PCH = [SP--], PCL = [SP--]');
2900 invalidate_DPTR_Rx();
2901 $prev_is_jump = TRUE;
2904 #-------------------------------------------------------------------------------
2906 sub rl_A()
2908 # RL A 00100011
2910 print_3('rl', 'A', 'ACC[76543210] = ACC[65432107]');
2913 #-------------------------------------------------------------------------------
2915 sub add_A_data()
2917 my ($rb, $str);
2919 # ADD A, #data 00100100 dddddddd data
2921 if ($decoder_silent_level == SILENT0)
2923 $rb = sprintf "0x%02X", $dcd_parm0;
2924 $str = present_char($dcd_parm0);
2925 print_3('add', "A, #$rb", "ACC += $rb$str");
2929 #-------------------------------------------------------------------------------
2931 sub add_A_direct()
2933 my ($rb, $name);
2935 # ADD A, direct 00100101 aaaaaaaa register address
2937 if ($decoder_silent_level == SILENT0)
2939 $rb = reg_name($dcd_parm0, \$name);
2940 print_3('add', "A, $rb", "ACC += $name");
2942 elsif ($decoder_silent_level == SILENT1)
2944 add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE);
2948 #-------------------------------------------------------------------------------
2950 sub jnb_bit()
2952 my ($addr, $rb0, $rb1, $name0, $str0, $str1, $str2);
2954 # JNB bit, rel 00110000 bbbbbbbb rrrrrrrr bit address relative address
2956 if ($decoder_silent_level == SILENT0)
2958 $addr = $dcd_address + $dcd_instr_size + expand_offset($dcd_parm1);
2959 $rb0 = bit_name($dcd_parm0, \$name0);
2960 $rb1 = labelname($addr);
2961 $str0 = ($dcd_address == $addr) ? ' (waiting loop)' : '';
2962 $str1 = sprintf "0x%04X", $addr;
2963 $str2 = jump_direction($addr);
2964 print_3('jnb', "$rb0, $rb1", "If ($name0 == L) then jumps$str2 hither: $str1$str0");
2966 elsif ($decoder_silent_level == SILENT1)
2968 add_bit($dcd_parm0, '', FALSE);
2971 invalidate_DPTR_Rx();
2972 $prev_is_jump = TRUE;
2975 #-------------------------------------------------------------------------------
2977 sub reti()
2979 # RETI 00110010
2981 print_3('reti', '', 'PCH = [SP--], PCL = [SP--]');
2982 invalidate_DPTR_Rx();
2983 $prev_is_jump = TRUE;
2986 #-------------------------------------------------------------------------------
2988 sub rcl_A()
2990 # RLC A 00110011
2992 print_3('rlc', 'A', 'ACC[76543210] = ACC[6543210C], CY = ACC[7]');
2995 #-------------------------------------------------------------------------------
2997 sub addc_A_data()
2999 my ($rb, $str);
3001 # ADDC A, #data 00110100 dddddddd data
3003 if ($decoder_silent_level == SILENT0)
3005 $rb = sprintf "0x%02X", $dcd_parm0;
3006 $str = present_char($dcd_parm0);
3007 print_3('addc', "A, #$rb", "ACC += $rb + CY$str");
3011 #-------------------------------------------------------------------------------
3013 sub addc_A_direct()
3015 my ($rb, $name);
3017 # ADDC A, direct 00110101 aaaaaaaa register address
3019 if ($decoder_silent_level == SILENT0)
3021 $rb = reg_name($dcd_parm0, \$name);
3022 print_3('addc', "A, $rb", "ACC += $name + CY");
3024 elsif ($decoder_silent_level == SILENT1)
3026 add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE);
3030 #-------------------------------------------------------------------------------
3032 sub jc()
3034 my ($addr, $rb, $str0, $str1);
3036 # JC rel 01000000 rrrrrrrr relative address
3038 if ($decoder_silent_level == SILENT0)
3040 $addr = $dcd_address + $dcd_instr_size + expand_offset($dcd_parm0);
3041 $rb = labelname($addr);
3042 $str0 = sprintf "0x%04X", $addr;
3043 $str1 = jump_direction($addr);
3044 print_3('jc', $rb, "If (CY == H) then jumps$str1 hither: $str0");
3047 invalidate_DPTR_Rx();
3048 $prev_is_jump = TRUE;
3051 #-------------------------------------------------------------------------------
3053 sub orl_direct_A()
3055 my ($rb, $name);
3057 # ORL direct, A 01000010 aaaaaaaa register address
3059 if ($decoder_silent_level == SILENT0)
3061 $rb = reg_name($dcd_parm0, \$name);
3062 print_3('orl', "$rb, A", "$name |= ACC");
3064 elsif ($decoder_silent_level == SILENT1)
3066 add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE);
3069 invalidate_reg($dcd_parm0);
3072 #-------------------------------------------------------------------------------
3074 sub orl_direct_data()
3076 my ($rb0, $rb1, $name, $str);
3078 # ORL direct, #data 01000011 aaaaaaaa dddddddd register address data
3080 if ($decoder_silent_level == SILENT0)
3082 $rb0 = reg_name($dcd_parm0, \$name);
3083 $rb1 = sprintf "0x%02X", $dcd_parm1;
3084 $str = present_char($dcd_parm1);
3087 if ($dcd_parm0 == PSW)
3089 my $bank = ($dcd_parm1 >> 3) & 0x03;
3091 $used_banks{$bank} = TRUE;
3093 if ($decoder_silent_level == SILENT0)
3095 $str = " (select bank #$bank)" if (($dcd_parm1 & ~0x18) == 0x00);
3099 if ($decoder_silent_level == SILENT0)
3101 print_3('orl', "$rb0, #$rb1", "$name |= $rb1$str");
3103 elsif ($decoder_silent_level == SILENT1)
3105 add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE);
3108 invalidate_reg($dcd_parm0);
3111 #-------------------------------------------------------------------------------
3113 sub orl_A_data()
3115 my ($rb, $str);
3117 # ORL A, #data 01000100 dddddddd data
3119 if ($decoder_silent_level == SILENT0)
3121 $rb = sprintf "0x%02X", $dcd_parm0;
3122 $str = present_char($dcd_parm0);
3123 print_3('orl', "A, #$rb", "ACC |= $rb$str");
3127 #-------------------------------------------------------------------------------
3129 sub orl_A_direct()
3131 my ($rb, $name);
3133 # ORL A, direct 01000101 aaaaaaaa register address
3135 if ($decoder_silent_level == SILENT0)
3137 $rb = reg_name($dcd_parm0, \$name);
3138 print_3('orl', "A, $rb", "ACC |= $name");
3140 elsif ($decoder_silent_level == SILENT1)
3142 add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE);
3146 #-------------------------------------------------------------------------------
3148 sub jnc()
3150 my ($addr, $rb, $str0, $str1);
3152 # JNC rel 01010000 rrrrrrrr relative address
3154 if ($decoder_silent_level == SILENT0)
3156 $addr = $dcd_address + $dcd_instr_size + expand_offset($dcd_parm0);
3157 $rb = labelname($addr);
3158 $str0 = sprintf "0x%04X", $addr;
3159 $str1 = jump_direction($addr);
3160 print_3('jnc', $rb, "If (CY == L) then jumps$str1 hither: $str0");
3163 invalidate_DPTR_Rx();
3164 $prev_is_jump = TRUE;
3167 #-------------------------------------------------------------------------------
3169 sub anl_direct_A()
3171 my ($rb, $name);
3173 # ANL direct, A 01010010 aaaaaaaa register address
3175 if ($decoder_silent_level == SILENT0)
3177 $rb = reg_name($dcd_parm0, \$name);
3178 print_3('anl', "$rb, A", "$name &= ACC");
3180 elsif ($decoder_silent_level == SILENT1)
3182 add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE);
3185 invalidate_reg($dcd_parm0);
3188 #-------------------------------------------------------------------------------
3190 sub anl_direct_data()
3192 my ($rb0, $rb1, $name, $str);
3194 # ANL direct, #data 01010011 aaaaaaaa dddddddd register address data
3196 if ($decoder_silent_level == SILENT0)
3198 $rb0 = reg_name($dcd_parm0, \$name);
3199 $rb1 = sprintf "0x%02X", $dcd_parm1;
3200 $str = present_char($dcd_parm1);
3201 print_3('anl', "$rb0, #$rb1", "$name &= $rb1$str");
3203 elsif ($decoder_silent_level == SILENT1)
3205 add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE);
3208 invalidate_reg($dcd_parm0);
3211 #-------------------------------------------------------------------------------
3213 sub anl_A_data()
3215 my ($rb, $str);
3217 # ANL A, #data 01010100 dddddddd data
3219 if ($decoder_silent_level == SILENT0)
3221 $rb = sprintf "0x%02X", $dcd_parm0;
3222 $str = present_char($dcd_parm0);
3223 print_3('anl', "A, #$rb", "ACC &= $rb$str");
3227 #-------------------------------------------------------------------------------
3229 sub anl_A_direct()
3231 my ($rb, $name);
3233 # ANL A, direct 01010101 aaaaaaaa register address
3235 if ($decoder_silent_level == SILENT0)
3237 $rb = reg_name($dcd_parm0, \$name);
3238 print_3('anl', "A, $rb", "ACC &= $name");
3240 elsif ($decoder_silent_level == SILENT1)
3242 add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE);
3246 #-------------------------------------------------------------------------------
3248 sub jz()
3250 my ($addr, $rb, $str0, $str1);
3252 # JZ rel 01100000 rrrrrrrr relative address
3254 if ($decoder_silent_level == SILENT0)
3256 $addr = $dcd_address + $dcd_instr_size + expand_offset($dcd_parm0);
3257 $rb = labelname($addr);
3258 $str0 = sprintf "0x%04X", $addr;
3259 $str1 = jump_direction($addr);
3260 print_3('jz', $rb, "If (ACC == 0) then jumps$str1 hither: $str0");
3263 invalidate_DPTR_Rx();
3264 $prev_is_jump = TRUE;
3267 #-------------------------------------------------------------------------------
3269 sub xrl_direct_A()
3271 my ($rb, $name);
3273 # XRL direct, A 01100010 aaaaaaaa register address
3275 if ($decoder_silent_level == SILENT0)
3277 $rb = reg_name($dcd_parm0, \$name);
3278 print_3('xrl', "$rb, A", "$name ^= ACC");
3280 elsif ($decoder_silent_level == SILENT1)
3282 add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE);
3285 invalidate_reg($dcd_parm0);
3288 #-------------------------------------------------------------------------------
3290 sub xrl_direct_data()
3292 my ($rb0, $rb1, $name, $str);
3294 # XRL direct, #data 01100011 aaaaaaaa dddddddd register address data
3296 if ($decoder_silent_level == SILENT0)
3298 $rb0 = reg_name($dcd_parm0, \$name);
3299 $rb1 = sprintf "0x%02X", $dcd_parm1;
3300 $str = present_char($dcd_parm1);
3301 print_3('xrl', "$rb0, #$rb1", "$name |= $rb1$str");
3303 elsif ($decoder_silent_level == SILENT1)
3305 add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE);
3308 invalidate_reg($dcd_parm0);
3311 #-------------------------------------------------------------------------------
3313 sub xrl_A_data()
3315 my ($rb, $str);
3317 # XRL A, #data 01100100 dddddddd data
3319 if ($decoder_silent_level == SILENT0)
3321 $rb = sprintf "0x%02X", $dcd_parm0;
3322 $str = present_char($dcd_parm0);
3323 print_3('xrl', "A, #$rb", "ACC ^= $rb$str");
3327 #-------------------------------------------------------------------------------
3329 sub xrl_A_direct()
3331 my ($rb, $name);
3333 # XRL A, direct 01100101 aaaaaaaa register address
3335 if ($decoder_silent_level == SILENT0)
3337 $rb = reg_name($dcd_parm0, \$name);
3338 print_3('xrl', "A, $rb", "ACC |= $name");
3340 elsif ($decoder_silent_level == SILENT1)
3342 add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE);
3346 #-------------------------------------------------------------------------------
3348 sub jnz()
3350 my ($addr, $rb, $str0, $str1);
3352 # JNZ rel 01110000 rrrrrrrr relative address
3354 if ($decoder_silent_level == SILENT0)
3356 $addr = $dcd_address + $dcd_instr_size + expand_offset($dcd_parm0);
3357 $rb = labelname($addr);
3358 $str0 = sprintf "0x%04X", $addr;
3359 $str1 = jump_direction($addr);
3360 print_3('jnz', $rb, "If (ACC != 0) then jumps$str1 hither: $str0");
3363 invalidate_DPTR_Rx();
3364 $prev_is_jump = TRUE;
3367 #-------------------------------------------------------------------------------
3369 sub orl_C_bit()
3371 my ($rb, $name);
3373 # ORL C, bit 01110010 bbbbbbbb bit address
3375 if ($decoder_silent_level == SILENT0)
3377 $rb = bit_name($dcd_parm0, \$name);
3378 print_3('orl', "C, $rb", "CY |= $name");
3380 elsif ($decoder_silent_level == SILENT1)
3382 add_bit($dcd_parm0, '', FALSE);
3386 #-------------------------------------------------------------------------------
3388 sub jmp_A_DPTR()
3390 my $str;
3392 # JMP @A+DPTR 01110011
3394 if ($DPTR != EMPTY)
3396 add_jump_label($DPTR, '', BL_TYPE_JTABLE, EMPTY, FALSE);
3397 $str = jump_direction($DPTR);
3399 else
3401 $str = '';
3404 print_3('jmp', '@A+DPTR', "Jumps$str hither: [DPTR + ACC]");
3405 invalidate_DPTR_Rx();
3406 $prev_is_jump = TRUE;
3409 #-------------------------------------------------------------------------------
3411 sub mov_A_data()
3413 my ($rb, $str);
3415 # MOV A, #data 01110100 dddddddd data
3417 if ($decoder_silent_level == SILENT0)
3419 $rb = sprintf "0x%02X", $dcd_parm0;
3420 $str = present_char($dcd_parm0);
3421 print_3('mov', "A, #$rb", "ACC = $rb$str");
3425 #-------------------------------------------------------------------------------
3427 sub mov_direct_data()
3429 my ($rb0, $rb1, $name, $str);
3431 # MOV direct, #data 01110101 aaaaaaaa dddddddd register address data
3433 if ($decoder_silent_level == SILENT0)
3435 $rb0 = reg_name($dcd_parm0, \$name);
3436 $rb1 = sprintf "0x%02X", $dcd_parm1;
3437 $str = '';
3440 if ($dcd_parm0 == PSW)
3442 my $bank = ($dcd_parm1 >> 3) & 0x03;
3444 $used_banks{$bank} = TRUE;
3446 if ($decoder_silent_level == SILENT0)
3448 $str = " (select bank #$bank)" if (($dcd_parm1 & ~0x18) == 0x00);
3451 # elsif ($dcd_parm0 == SP)
3453 # $stack_start = ($dcd_parm1 + 1) if ($stack_start < 0);
3455 else
3457 $str = present_char($dcd_parm1);
3460 if ($decoder_silent_level == SILENT0)
3462 print_3('mov', "$rb0, #$rb1", "$name = $rb1$str");
3464 elsif ($decoder_silent_level == SILENT1)
3466 add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE);
3469 invalidate_reg($dcd_parm0);
3472 #-------------------------------------------------------------------------------
3474 sub sjmp()
3476 my ($addr, $rb0, $rb1, $name0, $name1, $str0, $str1, $str2);
3478 # SJMP rel 10000000 rrrrrrrr relative address
3480 if ($decoder_silent_level == SILENT0)
3482 $addr = $dcd_address + $dcd_instr_size + expand_offset($dcd_parm0);
3483 $rb0 = labelname($addr);
3484 $str0 = ($dcd_address == $addr) ? ' (endless loop)' : '';
3485 $str1 = sprintf "0x%04X", $addr;
3486 $str2 = jump_direction($addr);
3487 print_3('sjmp', $rb0, "Jumps$str2 hither: $str1$str0");
3490 invalidate_DPTR_Rx();
3491 $prev_is_jump = TRUE;
3494 #-------------------------------------------------------------------------------
3496 sub anl_C_bit()
3498 my ($rb, $name);
3500 # ANL C, bit 10000010 bbbbbbbb bit address
3502 if ($decoder_silent_level == SILENT0)
3504 $rb = bit_name($dcd_parm0, \$name);
3505 print_3('anl', "C, $rb", "CY &= $name");
3507 elsif ($decoder_silent_level == SILENT1)
3509 add_bit($dcd_parm0, '', FALSE);
3513 #-------------------------------------------------------------------------------
3515 sub movc_A_A_PC()
3517 # MOVC A, @A+PC 10000011
3519 print_3('movc', 'A, @A+PC', "ACC = ROM[PC + $dcd_instr_size + ACC]");
3522 #-------------------------------------------------------------------------------
3524 sub div_AB()
3526 # DIV AB 10000100
3528 print_3('div', 'AB', 'ACC = ACC / B, B = ACC % B');
3531 #-------------------------------------------------------------------------------
3533 sub mov_direct_direct()
3535 my ($rb0, $rb1, $name0, $name1);
3537 # MOV direct, direct 10000101 aaaaaaaa aaaaaaaa forrás reg. cél reg.
3539 if ($decoder_silent_level == SILENT0)
3541 $rb0 = reg_name($dcd_parm0, \$name0);
3542 $rb1 = reg_name($dcd_parm1, \$name1);
3543 print_3('mov', "$rb1, $rb0", "$name1 = $name0");
3545 elsif ($decoder_silent_level == SILENT1)
3547 add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE);
3548 add_ram($dcd_parm1, '', RAM_TYPE_DIR, FALSE);
3551 invalidate_reg($dcd_parm0);
3554 #-------------------------------------------------------------------------------
3556 sub mov_DPTR_data()
3558 my ($addr, $str, $name);
3560 # MOV DPTR, #data16 10010000 dddddddd dddddddd d15-d8 d7-d0
3562 $addr = ($dcd_parm0 << 8) | $dcd_parm1;
3564 if ($decoder_silent_level == SILENT0)
3566 $str = xram_name($addr, \$name);
3567 print_3('mov', "DPTR, #$str", "DPTR = $name");
3570 $DPTR = $addr;
3573 #-------------------------------------------------------------------------------
3575 sub mov_bit_C()
3577 my ($rb, $name);
3579 # MOV bit, C 10010010 bbbbbbbb bit address
3581 if ($decoder_silent_level == SILENT0)
3583 $rb = bit_name($dcd_parm0, \$name);
3584 print_3('mov', "$rb, C", "$name = CY");
3586 elsif ($decoder_silent_level == SILENT1)
3588 add_bit($dcd_parm0, '', FALSE);
3592 #-------------------------------------------------------------------------------
3594 sub movc_A_A_DPTR()
3596 # MOVC A, @A+DPTR 10010011
3598 add_jump_label($DPTR, '', BL_TYPE_LABEL, EMPTY, FALSE) if ($DPTR != EMPTY);
3600 print_3('movc', 'A, @A+DPTR', 'ACC = ROM[DPTR + ACC]');
3603 #-------------------------------------------------------------------------------
3605 sub subb_A_data()
3607 my ($rb, $str);
3609 # SUBB A, #data 10010100 dddddddd data
3611 if ($decoder_silent_level == SILENT0)
3613 $rb = sprintf "0x%02X", $dcd_parm0;
3614 $str = present_char($dcd_parm0);
3615 print_3('subb', "A, #$rb", "ACC -= $rb + CY$str");
3619 #-------------------------------------------------------------------------------
3621 sub subb_A_direct()
3623 my ($rb, $name);
3625 # SUBB A, direct 10010101 aaaaaaaa register address
3627 if ($decoder_silent_level == SILENT0)
3629 $rb = reg_name($dcd_parm0, \$name);
3630 print_3('subb', "A, $rb", "ACC -= $name + CY");
3632 elsif ($decoder_silent_level == SILENT1)
3634 add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE);
3638 #-------------------------------------------------------------------------------
3640 sub orl_C__bit()
3642 my ($rb, $name);
3644 # ORL C, /bit 10100000 bbbbbbbb bit address
3646 if ($decoder_silent_level == SILENT0)
3648 $rb = bit_name($dcd_parm0, \$name);
3649 print_3('orl', "C, /$rb", "CY = ~$name");
3651 elsif ($decoder_silent_level == SILENT1)
3653 add_bit($dcd_parm0, '', FALSE);
3657 #-------------------------------------------------------------------------------
3659 sub mov_C_bit()
3661 my ($rb, $name);
3663 # MOV C, bit 10100010 bbbbbbbb bit address
3665 if ($decoder_silent_level == SILENT0)
3667 $rb = bit_name($dcd_parm0, \$name);
3668 print_3('mov', "C, $rb", "CY = $name");
3670 elsif ($decoder_silent_level == SILENT1)
3672 add_bit($dcd_parm0, '', FALSE);
3676 #-------------------------------------------------------------------------------
3678 sub inc_DPTR()
3680 my $str;
3682 # INC DPTR 10100011
3684 if ($DPTR != EMPTY)
3686 ++$DPTR;
3687 $str = sprintf " (0x%04X)", $DPTR;
3689 else
3691 $str = '';
3694 print_3('inc', 'DPTR', "++DPTR$str");
3697 #-------------------------------------------------------------------------------
3699 sub mul_AB()
3701 # MUL AB 10100100
3703 print_3('mul', 'AB', 'B:ACC = ACC * B');
3706 #-------------------------------------------------------------------------------
3708 sub unknown()
3710 my ($rb, $str0, $str1);
3712 # The unknown instruction is actually simple embedded data in the code.
3714 if ($decoder_silent_level == SILENT0)
3716 $rb = sprintf "0x%02X", $dcd_instr & 0xFF;
3717 $str0 = present_char($dcd_instr);
3718 $str1 = sprintf "0x%04X", $dcd_address;
3719 print_3('.db', $rb, "$str1: $rb$str0");
3721 if ($dcd_instr_size == 2)
3723 $rb = sprintf "0x%02X", $dcd_parm0 & 0xFF;
3724 $str0 = present_char($dcd_parm0);
3725 $str1 = sprintf "0x%04X", $dcd_address;
3726 print_3('.db', $rb, "$str1: $rb$str0");
3728 elsif ($dcd_instr_size == 3)
3730 $rb = sprintf "0x%02X", $dcd_parm1 & 0xFF;
3731 $str0 = present_char($dcd_parm1);
3732 $str1 = sprintf "0x%04X", $dcd_address;
3733 print_3('.db', $rb, "$str1: $rb$str0");
3738 #-------------------------------------------------------------------------------
3740 sub anl_C__bit()
3742 my ($rb, $name);
3744 # ANL C, /bit 10110000 bbbbbbbb bit address
3746 if ($decoder_silent_level == SILENT0)
3748 $rb = bit_name($dcd_parm0, \$name);
3749 print_3('anl', "C, /$rb", "CY &= ~$name");
3751 elsif ($decoder_silent_level == SILENT1)
3753 add_bit($dcd_parm0, '', FALSE);
3757 #-------------------------------------------------------------------------------
3759 sub cpl_bit()
3761 my ($rb, $name);
3763 # CPL bit 10110010 bbbbbbbb bit address
3765 if ($decoder_silent_level == SILENT0)
3767 $rb = bit_name($dcd_parm0, \$name);
3768 print_3('cpl', $rb, "$name = ~$name");
3770 elsif ($decoder_silent_level == SILENT1)
3772 add_bit($dcd_parm0, '', FALSE);
3776 #-------------------------------------------------------------------------------
3778 sub cpl_C()
3780 # CPL C 10110011
3782 print_3('cpl', 'C', 'CY = ~CY');
3785 #-------------------------------------------------------------------------------
3787 sub cjne_A_data()
3789 my ($addr, $rb0, $rb1, $str0, $str1, $str2);
3791 # CJNE A, #data, rel 10110100 dddddddd rrrrrrrr data relative address
3793 if ($decoder_silent_level == SILENT0)
3795 $addr = $dcd_address + $dcd_instr_size + expand_offset($dcd_parm1);
3796 $rb0 = labelname($addr);
3797 $rb1 = sprintf "0x%02X", $dcd_parm0;
3798 $str0 = sprintf "0x%04X", $addr;
3799 $str1 = jump_direction($addr);
3800 $str2 = present_char($dcd_parm0);
3801 print_3('cjne', "A, #$rb1, $rb0", "If (ACC != $rb1$str2) then jumps$str1 hither: $str0");
3804 invalidate_DPTR_Rx();
3805 $prev_is_jump = TRUE;
3808 #-------------------------------------------------------------------------------
3810 sub cjne_A_direct()
3812 my ($addr, $rb0, $rb1, $name, $str0, $str1, $str2);
3814 # CJNE A, direct, rel 10110101 aaaaaaaa rrrrrrrr register address relative address
3816 if ($decoder_silent_level == SILENT0)
3818 $addr = $dcd_address + $dcd_instr_size + expand_offset($dcd_parm1);
3819 $rb0 = reg_name($dcd_parm0, \$name);
3820 $rb1 = labelname($addr);
3821 $str0 = sprintf "0x%04X", $addr;
3822 $str1 = ($dcd_address == $addr) ? ' (waiting loop)' : '';
3823 $str2 = jump_direction($addr);
3824 print_3('cjne', "A, $rb0, $rb1", "If (ACC != $name) then jumps$str2 hither: $str0$str1");
3826 elsif ($decoder_silent_level == SILENT1)
3828 add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE);
3831 invalidate_DPTR_Rx();
3832 $prev_is_jump = TRUE;
3835 #-------------------------------------------------------------------------------
3837 sub push_direct()
3839 my ($rb, $name);
3841 # PUSH direct 11000000 aaaaaaaa register address
3843 if ($decoder_silent_level == SILENT0)
3845 $rb = reg_name($dcd_parm0, \$name);
3846 print_3('push', $rb, "++SP, [SP] = $name");
3848 elsif ($decoder_silent_level == SILENT1)
3850 add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE);
3854 #-------------------------------------------------------------------------------
3856 sub clr_bit()
3858 my ($rb, $name);
3860 # CLR bit 11000010 bbbbbbbb bit address
3862 if ($decoder_silent_level == SILENT0)
3864 $rb = bit_name($dcd_parm0, \$name);
3865 print_3('clr', $rb, "$name = L");
3867 elsif ($decoder_silent_level == SILENT1)
3869 add_bit($dcd_parm0, '', FALSE);
3873 #-------------------------------------------------------------------------------
3875 sub clr_C()
3877 # CLR C 11000011
3879 print_3('clr', 'C', 'CY = L');
3882 #-------------------------------------------------------------------------------
3884 sub swap_A()
3886 # SWAP A 11000100
3888 print_3('swap', 'A', 'ACC[76543210] = ACC[32107654]');
3891 #-------------------------------------------------------------------------------
3893 sub xch_A_direct()
3895 my ($rb, $name);
3897 # XCH A, direct 11000101 aaaaaaaa register address
3899 if ($decoder_silent_level == SILENT0)
3901 $rb = reg_name($dcd_parm0, \$name);
3902 print_3('xch', "A, $rb", "ACC <-> $name");
3904 elsif ($decoder_silent_level == SILENT1)
3906 add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE);
3909 invalidate_reg($dcd_parm0);
3912 #-------------------------------------------------------------------------------
3914 sub pop_direct()
3916 my ($rb, $name);
3918 # POP direct 11010000 aaaaaaaa register address
3920 if ($decoder_silent_level == SILENT0)
3922 $rb = reg_name($dcd_parm0, \$name);
3923 print_3('pop', $rb, "$name = [SP], --SP");
3925 elsif ($decoder_silent_level == SILENT1)
3927 add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE);
3930 invalidate_reg($dcd_parm0);
3933 #-------------------------------------------------------------------------------
3935 sub setb_bit()
3937 my ($rb, $name);
3939 # SETB bit 11010010 bbbbbbbb bit address
3941 if ($decoder_silent_level == SILENT0)
3943 $rb = bit_name($dcd_parm0, \$name);
3944 print_3('setb', $rb, "$name = H");
3946 elsif ($decoder_silent_level == SILENT1)
3948 add_bit($dcd_parm0, '', FALSE);
3952 #-------------------------------------------------------------------------------
3954 sub setb_C()
3956 # SETB C 11010011
3958 print_3('setb', 'C', 'CY = H');
3961 #-------------------------------------------------------------------------------
3963 sub da_A()
3965 # DA A 11010100
3967 print_3('da', 'A', 'Decimal adjust the ACC.');
3970 #-------------------------------------------------------------------------------
3972 sub djnz_direct()
3974 my ($addr, $rb0, $rb1, $name, $str0, $str1, $str2);
3976 # DJNZ direct, rel 11010101 aaaaaaaa rrrrrrrr register address relative address
3978 if ($decoder_silent_level == SILENT0)
3980 $addr = $dcd_address + $dcd_instr_size + expand_offset($dcd_parm1);
3981 $rb0 = reg_name($dcd_parm0, \$name);
3982 $rb1 = labelname($addr);
3983 $str0 = ($dcd_address == $addr) ? ' (waiting loop)' : '';
3984 $str1 = sprintf "0x%04X", $addr;
3985 $str2 = jump_direction($addr);
3986 print_3('djnz', "$rb0, $rb1", "If (--$name != 0) then jumps$str2 hither: $str1$str0");
3988 elsif ($decoder_silent_level == SILENT1)
3990 add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE);
3993 invalidate_DPTR_Rx();
3994 $prev_is_jump = TRUE;
3997 #-------------------------------------------------------------------------------
3999 sub movx_A_DPTR()
4001 # MOVX A, @DPTR 11100000
4003 add_xram($DPTR, '', FALSE) if ($DPTR != EMPTY && $decoder_silent_level == SILENT1);
4005 print_3('movx', 'A, @DPTR', 'ACC = XRAM[DPTR]');
4008 #-------------------------------------------------------------------------------
4010 sub clr_A()
4012 # CLR A 11100100
4014 print_3('clr', 'A', 'ACC = 0');
4017 #-------------------------------------------------------------------------------
4019 sub mov_A_direct()
4021 my ($rb, $name);
4023 # MOV A, direct 11100101 aaaaaaaa register address The "MOV A, ACC" invalid instruction.
4025 if ($decoder_silent_level == SILENT0)
4027 $rb = reg_name($dcd_parm0, \$name);
4028 print_3('mov', "A, $rb", "ACC = $name");
4030 elsif ($decoder_silent_level == SILENT1)
4032 add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE);
4036 #-------------------------------------------------------------------------------
4038 sub movx_DPTR_A()
4040 # MOVX @DPTR, A 11110000
4042 add_xram($DPTR, '', FALSE) if ($DPTR != EMPTY && $decoder_silent_level == SILENT1);
4044 print_3('movx', '@DPTR, A', 'XRAM[DPTR] = ACC');
4047 #-------------------------------------------------------------------------------
4049 sub cpl_A()
4051 # CPL A 11110100
4053 print_3('cpl', 'A', 'ACC = ~ACC');
4056 #-------------------------------------------------------------------------------
4058 sub mov_direct_A()
4060 my ($rb, $name);
4062 # MOV direct, A 11110101 aaaaaaaa register address
4064 if ($decoder_silent_level == SILENT0)
4066 $rb = reg_name($dcd_parm0, \$name);
4067 print_3('mov', "$rb, A", "$name = ACC");
4069 elsif ($decoder_silent_level == SILENT1)
4071 add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE);
4074 invalidate_reg($dcd_parm0);
4077 #-------------------------------------------------------------------------------
4079 my @instr_decoders =
4081 # 0x00 - 0x0F
4082 \&nop,
4083 \&ajmp,
4084 \&ljmp,
4085 \&rr_A,
4086 \&inc_A,
4087 \&inc_direct,
4088 \&inc_ind_Ri,
4089 \&inc_ind_Ri,
4090 \&inc_Rn,
4091 \&inc_Rn,
4092 \&inc_Rn,
4093 \&inc_Rn,
4094 \&inc_Rn,
4095 \&inc_Rn,
4096 \&inc_Rn,
4097 \&inc_Rn,
4099 # 0x10 - 0x1F
4100 \&jbc_bit,
4101 \&acall,
4102 \&lcall,
4103 \&rrc_A,
4104 \&dec_A,
4105 \&dec_direct,
4106 \&dec_ind_Ri,
4107 \&dec_ind_Ri,
4108 \&dec_Rn,
4109 \&dec_Rn,
4110 \&dec_Rn,
4111 \&dec_Rn,
4112 \&dec_Rn,
4113 \&dec_Rn,
4114 \&dec_Rn,
4115 \&dec_Rn,
4117 # 0x20 - 0x2F
4118 \&jb_bit,
4119 \&ajmp,
4120 \&ret,
4121 \&rl_A,
4122 \&add_A_data,
4123 \&add_A_direct,
4124 \&add_A_ind_Ri,
4125 \&add_A_ind_Ri,
4126 \&add_A_Rn,
4127 \&add_A_Rn,
4128 \&add_A_Rn,
4129 \&add_A_Rn,
4130 \&add_A_Rn,
4131 \&add_A_Rn,
4132 \&add_A_Rn,
4133 \&add_A_Rn,
4135 # 0x30 - 0x3F
4136 \&jnb_bit,
4137 \&acall,
4138 \&reti,
4139 \&rcl_A,
4140 \&addc_A_data,
4141 \&addc_A_direct,
4142 \&addc_A_ind_Ri,
4143 \&addc_A_ind_Ri,
4144 \&addc_A_Rn,
4145 \&addc_A_Rn,
4146 \&addc_A_Rn,
4147 \&addc_A_Rn,
4148 \&addc_A_Rn,
4149 \&addc_A_Rn,
4150 \&addc_A_Rn,
4151 \&addc_A_Rn,
4153 # 0x40 - 0x4F
4154 \&jc,
4155 \&ajmp,
4156 \&orl_direct_A,
4157 \&orl_direct_data,
4158 \&orl_A_data,
4159 \&orl_A_direct,
4160 \&orl_A_ind_Ri,
4161 \&orl_A_ind_Ri,
4162 \&orl_A_Rn,
4163 \&orl_A_Rn,
4164 \&orl_A_Rn,
4165 \&orl_A_Rn,
4166 \&orl_A_Rn,
4167 \&orl_A_Rn,
4168 \&orl_A_Rn,
4169 \&orl_A_Rn,
4171 # 0x50 - 0x5F
4172 \&jnc,
4173 \&acall,
4174 \&anl_direct_A,
4175 \&anl_direct_data,
4176 \&anl_A_data,
4177 \&anl_A_direct,
4178 \&anl_A_ind_Ri,
4179 \&anl_A_ind_Ri,
4180 \&anl_A_Rn,
4181 \&anl_A_Rn,
4182 \&anl_A_Rn,
4183 \&anl_A_Rn,
4184 \&anl_A_Rn,
4185 \&anl_A_Rn,
4186 \&anl_A_Rn,
4187 \&anl_A_Rn,
4189 # 0x60 - 0x6F
4190 \&jz,
4191 \&ajmp,
4192 \&xrl_direct_A,
4193 \&xrl_direct_data,
4194 \&xrl_A_data,
4195 \&xrl_A_direct,
4196 \&xrl_A_ind_Ri,
4197 \&xrl_A_ind_Ri,
4198 \&xrl_A_Rn,
4199 \&xrl_A_Rn,
4200 \&xrl_A_Rn,
4201 \&xrl_A_Rn,
4202 \&xrl_A_Rn,
4203 \&xrl_A_Rn,
4204 \&xrl_A_Rn,
4205 \&xrl_A_Rn,
4207 # 0x70 - 0x7F
4208 \&jnz,
4209 \&acall,
4210 \&orl_C_bit,
4211 \&jmp_A_DPTR,
4212 \&mov_A_data,
4213 \&mov_direct_data,
4214 \&mov_ind_Ri_data,
4215 \&mov_ind_Ri_data,
4216 \&mov_Rn_data,
4217 \&mov_Rn_data,
4218 \&mov_Rn_data,
4219 \&mov_Rn_data,
4220 \&mov_Rn_data,
4221 \&mov_Rn_data,
4222 \&mov_Rn_data,
4223 \&mov_Rn_data,
4225 # 0x80 - 0x8F
4226 \&sjmp,
4227 \&ajmp,
4228 \&anl_C_bit,
4229 \&movc_A_A_PC,
4230 \&div_AB,
4231 \&mov_direct_direct,
4232 \&mov_direct_ind_Ri,
4233 \&mov_direct_ind_Ri,
4234 \&mov_direct_Rn,
4235 \&mov_direct_Rn,
4236 \&mov_direct_Rn,
4237 \&mov_direct_Rn,
4238 \&mov_direct_Rn,
4239 \&mov_direct_Rn,
4240 \&mov_direct_Rn,
4241 \&mov_direct_Rn,
4243 # 0x90 - 0x9F
4244 \&mov_DPTR_data,
4245 \&acall,
4246 \&mov_bit_C,
4247 \&movc_A_A_DPTR,
4248 \&subb_A_data,
4249 \&subb_A_direct,
4250 \&subb_A_ind_Ri,
4251 \&subb_A_ind_Ri,
4252 \&subb_A_Rn,
4253 \&subb_A_Rn,
4254 \&subb_A_Rn,
4255 \&subb_A_Rn,
4256 \&subb_A_Rn,
4257 \&subb_A_Rn,
4258 \&subb_A_Rn,
4259 \&subb_A_Rn,
4261 # 0xA0 - 0xAF
4262 \&orl_C__bit,
4263 \&ajmp,
4264 \&mov_C_bit,
4265 \&inc_DPTR,
4266 \&mul_AB,
4267 \&unknown,
4268 \&mov_ind_Ri_direct,
4269 \&mov_ind_Ri_direct,
4270 \&mov_Rn_direct,
4271 \&mov_Rn_direct,
4272 \&mov_Rn_direct,
4273 \&mov_Rn_direct,
4274 \&mov_Rn_direct,
4275 \&mov_Rn_direct,
4276 \&mov_Rn_direct,
4277 \&mov_Rn_direct,
4279 # 0xB0 - 0xBF
4280 \&anl_C__bit,
4281 \&acall,
4282 \&cpl_bit,
4283 \&cpl_C,
4284 \&cjne_A_data,
4285 \&cjne_A_direct,
4286 \&cjne_ind_Ri_data,
4287 \&cjne_ind_Ri_data,
4288 \&cjne_Rn_data,
4289 \&cjne_Rn_data,
4290 \&cjne_Rn_data,
4291 \&cjne_Rn_data,
4292 \&cjne_Rn_data,
4293 \&cjne_Rn_data,
4294 \&cjne_Rn_data,
4295 \&cjne_Rn_data,
4297 # 0xC0 - 0xCF
4298 \&push_direct,
4299 \&ajmp,
4300 \&clr_bit,
4301 \&clr_C,
4302 \&swap_A,
4303 \&xch_A_direct,
4304 \&xch_A_ind_Ri,
4305 \&xch_A_ind_Ri,
4306 \&xch_A_Rn,
4307 \&xch_A_Rn,
4308 \&xch_A_Rn,
4309 \&xch_A_Rn,
4310 \&xch_A_Rn,
4311 \&xch_A_Rn,
4312 \&xch_A_Rn,
4313 \&xch_A_Rn,
4315 # 0xD0 - 0xDF
4316 \&pop_direct,
4317 \&acall,
4318 \&setb_bit,
4319 \&setb_C,
4320 \&da_A,
4321 \&djnz_direct,
4322 \&xchd_A_ind_Ri,
4323 \&xchd_A_ind_Ri,
4324 \&djnz_Rn,
4325 \&djnz_Rn,
4326 \&djnz_Rn,
4327 \&djnz_Rn,
4328 \&djnz_Rn,
4329 \&djnz_Rn,
4330 \&djnz_Rn,
4331 \&djnz_Rn,
4333 # 0xE0 - 0xEF
4334 \&movx_A_DPTR,
4335 \&ajmp,
4336 \&movx_A_ind_Ri,
4337 \&movx_A_ind_Ri,
4338 \&clr_A,
4339 \&mov_A_direct,
4340 \&mov_A_ind_Ri,
4341 \&mov_A_ind_Ri,
4342 \&mov_A_Rn,
4343 \&mov_A_Rn,
4344 \&mov_A_Rn,
4345 \&mov_A_Rn,
4346 \&mov_A_Rn,
4347 \&mov_A_Rn,
4348 \&mov_A_Rn,
4349 \&mov_A_Rn,
4351 # 0xF0 - 0xFF
4352 \&movx_DPTR_A,
4353 \&acall,
4354 \&movx_ind_Ri_A,
4355 \&movx_ind_Ri_A,
4356 \&cpl_A,
4357 \&mov_direct_A,
4358 \&mov_ind_Ri_A,
4359 \&mov_ind_Ri_A,
4360 \&mov_Rn_A,
4361 \&mov_Rn_A,
4362 \&mov_Rn_A,
4363 \&mov_Rn_A,
4364 \&mov_Rn_A,
4365 \&mov_Rn_A,
4366 \&mov_Rn_A,
4367 \&mov_Rn_A
4370 #-------------------------------------------------------------------------------
4373 # Decodes the $BlockRef.
4376 sub instruction_decoder($$)
4378 my ($Address, $BlockRef) = @_;
4379 my ($label, $invalid);
4381 $dcd_address = $Address;
4382 $dcd_instr_size = $BlockRef->{SIZE};
4383 $dcd_instr = $rom[$dcd_address];
4384 $label = $BlockRef->{LABEL};
4386 if ($decoder_silent_level == SILENT0)
4388 printf("0x%04X: %02X", $dcd_address, $dcd_instr) if (! $gen_assembly_code);
4391 $invalid = FALSE;
4393 if ($dcd_instr_size == 1)
4395 if ($decoder_silent_level == SILENT0)
4397 print(($gen_assembly_code) ? "\t" : "\t\t");
4400 elsif ($dcd_instr_size == 2)
4402 $dcd_parm0 = $rom[$dcd_address + 1];
4403 $invalid = TRUE if ($dcd_parm0 == EMPTY);
4405 if ($decoder_silent_level == SILENT0)
4407 if ($gen_assembly_code)
4409 print "\t";
4411 else
4413 printf " %02X\t\t", $dcd_parm0;
4417 elsif ($dcd_instr_size == 3)
4419 $dcd_parm0 = $rom[$dcd_address + 1];
4420 $dcd_parm1 = $rom[$dcd_address + 2];
4421 $invalid = TRUE if ($dcd_parm0 == EMPTY || $dcd_parm1 == EMPTY);
4423 if ($decoder_silent_level == SILENT0)
4425 if ($gen_assembly_code)
4427 print "\t";
4429 else
4431 printf " %02X %02X\t", $dcd_parm0, $dcd_parm1;
4435 else
4437 printf STDERR "An instruction and a block overlapped with each other at this address: 0x%04X!\n", $dcd_address;
4440 $dcd_Ri_regs = $dcd_instr & 0x01;
4441 $dcd_Ri_name = "R$dcd_Ri_regs";
4443 $dcd_Rn_regs = $dcd_instr & 0x07;
4444 $dcd_Rn_name = "R$dcd_Rn_regs";
4446 $prev_is_jump = FALSE;
4448 invalidate_DPTR_Rx() if ($label->{TYPE} != BL_TYPE_NONE);
4450 if ($dcd_instr != EMPTY && ! $invalid)
4452 $instr_decoders[$dcd_instr]();
4454 else
4456 unknown();
4460 ################################################################################
4461 ################################################################################
4464 # Reads the sfrs and bits from the $Line.
4467 sub process_header_line($)
4469 my $Line = $_[0];
4471 Log((' ' x $embed_level) . $Line, 5);
4473 if ($Line =~ /^#\s*include\s+["<]\s*(\S+)\s*[">]$/o)
4475 $embed_level += 4;
4476 &read_header("$include_path/$1");
4477 $embed_level -= 4;
4479 elsif ($Line =~ /^__sfr\s+__at\s*(?:\(\s*)?0x([[:xdigit:]]+)(?:\s*\))?\s+([\w_]+)/io)
4481 # __sfr __at (0x80) P0 ; /* PORT 0 */
4483 add_ram(hex($1), $2, RAM_TYPE_DIR, TRUE);
4485 elsif ($Line =~ /^SFR\s*\(\s*([\w_]+)\s*,\s*0x([[:xdigit:]]+)\s*\)/io)
4487 # SFR(P0, 0x80); // Port 0
4489 add_ram(hex($2), $1, RAM_TYPE_DIR, TRUE);
4491 elsif ($Line =~ /^sfr\s+([\w_]+)\s*=\s*0x([[:xdigit:]]+)/io)
4493 # sfr P1 = 0x90;
4495 add_ram(hex($2), $1, RAM_TYPE_DIR, TRUE);
4497 elsif ($Line =~ /^__sbit\s+__at\s*(?:\(\s*)?0x([[:xdigit:]]+)(?:\s*\))?\s+([\w_]+)/io)
4499 # __sbit __at (0x86) P0_6 ;
4501 add_bit(hex($1), $2, TRUE);
4503 elsif ($Line =~ /^SBIT\s*\(\s*([\w_]+)\s*,\s*0x([[:xdigit:]]+)\s*,\s*(\d)\s*\)/io)
4505 # SBIT(P0_0, 0x80, 0); // Port 0 bit 0
4507 add_bit(hex($2) + int($3), $1, TRUE);
4509 elsif ($Line =~ /^sbit\s+([\w_]+)\s*=\s*0x([[:xdigit:]]+)/io)
4511 # sbit P3_1 = 0xB1;
4513 add_bit(hex($2), $1, TRUE);
4515 elsif ($Line =~ /^sbit\s+([\w_]+)\s*=\s*([\w_]+)\s*\^\s*(\d)/io)
4517 # sbit SM0 = SCON^7;
4519 my ($name, $reg, $bit) = ($1, $2, $3);
4521 add_bit($sfr_by_names{$reg} + $bit, $name, TRUE) if (defined($sfr_by_names{$reg}));
4525 #-------------------------------------------------------------------------------
4528 # Reads in a MCU.h file.
4531 sub read_header($)
4533 my $Header = $_[0];
4534 my ($fh, $pre_comment, $comment, $line_number);
4535 my $head;
4537 if (! open($fh, '<', $Header))
4539 print STDERR "$PROGRAM: Could not open. -> \"$Header\"\n";
4540 exit(1);
4543 $head = ' ' x $embed_level;
4545 Log("${head}read_header($Header) >>>>", 5);
4547 $comment = FALSE;
4548 $line_number = 1;
4549 while (<$fh>)
4551 chomp;
4552 s/\r$//o; # '\r'
4554 # Filters off the C comments.
4556 s/\/\*.*\*\///o; # /* ... */
4557 s/\/\/.*$//o; # // ...
4558 s/^\s*|\s*$//go;
4560 if (/\/\*/o) # /*
4562 $pre_comment = TRUE;
4563 s/\s*\/\*.*$//o;
4565 elsif (/\*\//o) # */
4567 $pre_comment = FALSE;
4568 $comment = FALSE;
4569 s/^.*\*\/\s*//o;
4572 if ($comment)
4574 ++$line_number;
4575 next;
4578 $comment = $pre_comment if ($pre_comment);
4580 if (/^\s*$/o)
4582 ++$line_number;
4583 next;
4586 run_preprocessor($Header, \&process_header_line, $_, $line_number);
4587 ++$line_number;
4588 } # while (<$fh>)
4590 Log("${head}<<<< read_header($Header)", 5);
4591 close($fh);
4594 #-------------------------------------------------------------------------------
4597 # Among the blocks stows description of an instruction.
4600 sub add_instr_block($$)
4602 my ($Address, $Instruction) = @_;
4603 my $instr_size = $instruction_sizes[$Instruction];
4604 my $invalid;
4606 $dcd_address = $Address;
4607 $dcd_instr = $rom[$dcd_address];
4608 $invalid = FALSE;
4610 if (! $instr_size)
4612 $instr_size = 1;
4613 add_block($Address, BLOCK_CONST, $instr_size, BL_TYPE_NONE, '');
4615 else
4617 if ($instr_size == 1)
4619 $invalid = TRUE if ($dcd_instr == EMPTY);
4622 if ($instr_size == 2)
4624 $dcd_parm0 = $rom[$dcd_address + 1];
4625 $invalid = TRUE if ($dcd_parm0 == EMPTY);
4628 if ($instr_size == 3)
4630 $dcd_parm1 = $rom[$dcd_address + 2];
4631 $invalid = TRUE if ($dcd_parm1 == EMPTY);
4634 if ($invalid)
4636 add_block($Address, BLOCK_CONST, $instr_size, BL_TYPE_NONE, '') if ($instr_size);
4638 else
4640 add_block($Address, BLOCK_INSTR, $instr_size, BL_TYPE_NONE, '');
4644 return $instr_size;
4647 #-------------------------------------------------------------------------------
4650 # Splits the program into small blocks.
4653 sub split_code_to_blocks()
4655 my ($i, $instr);
4656 my ($is_empty, $empty_begin);
4657 my ($is_const, $const_begin);
4659 $is_empty = FALSE;
4660 $empty_begin = 0;
4661 $is_const = FALSE;
4662 $const_begin = 0;
4664 for ($i = 0; $i < $rom_size; )
4666 $instr = $rom[$i];
4668 if ($instr == EMPTY)
4670 if (! $is_empty)
4672 # The begin of the empty section.
4674 if ($is_const)
4676 # The end of the constant section.
4678 add_block($const_begin, BLOCK_CONST, $i - $const_begin, BL_TYPE_NONE, '');
4679 $is_const = FALSE;
4682 $empty_begin = $i;
4683 $is_empty = TRUE;
4686 ++$i;
4687 } # if ($instr == EMPTY)
4688 elsif (is_constant($i))
4690 if (! $is_const)
4692 if ($is_empty)
4694 # The end of the empty section.
4696 add_block($empty_begin, BLOCK_EMPTY, $i - $empty_begin, BL_TYPE_NONE, '');
4697 $is_empty = FALSE;
4700 $const_begin = $i;
4701 $is_const = TRUE;
4704 ++$i;
4705 } # elsif (is_constant($i))
4706 else
4708 if ($is_const)
4710 # The end of the constant section.
4712 add_block($const_begin, BLOCK_CONST, $i - $const_begin, BL_TYPE_NONE, '');
4713 $is_const = FALSE;
4716 if ($is_empty)
4718 # The end of the empty section.
4720 add_block($empty_begin, BLOCK_EMPTY, $i - $empty_begin, BL_TYPE_NONE, '');
4721 $is_empty = FALSE;
4724 $i += add_instr_block($i, $instr);
4726 } # for ($i = 0; $i < $rom_size; )
4728 if ($is_const)
4730 add_block($const_begin, BLOCK_CONST, $i - $const_begin, BL_TYPE_NONE, '');
4733 if ($is_empty)
4735 add_block($empty_begin, BLOCK_EMPTY, $i - $empty_begin, BL_TYPE_NONE, '');
4739 #-------------------------------------------------------------------------------
4742 # If the $BlockRef a call, then follows.
4745 sub follow_call($)
4747 my $BlockRef = $_[0];
4748 my ($addr, $size, $instr);
4750 $addr = $BlockRef->{ADDR};
4751 $size = $BlockRef->{SIZE};
4752 $instr = $rom[$addr];
4754 if ($instr == INST_LCALL)
4756 return (($rom[$addr + 1] << 8) | $rom[$addr + 2]);
4758 elsif (($instr & 0x1F) == INST_ACALL)
4760 return ((($addr + $size) & 0xF800) | (($instr & 0xE0) << 3) | $rom[$addr + 1]);
4763 return EMPTY;
4766 #-------------------------------------------------------------------------------
4769 # If the $BlockRef a unconditional jump, then follows.
4772 sub follow_unconditional_jump($)
4774 my $BlockRef = $_[0];
4775 my ($addr, $size, $instr);
4777 $addr = $BlockRef->{ADDR};
4778 $size = $BlockRef->{SIZE};
4779 $instr = $rom[$addr];
4781 if ($size == 3 && $instr == INST_LJMP)
4783 return (($rom[$addr + 1] << 8) | $rom[$addr + 2]);
4785 elsif ($size == 2)
4787 if (($instr & 0x1F) == INST_AJMP)
4789 return ((($addr + $size) & 0xF800) | ((($instr & 0xE0) << 3) | $rom[$addr + 1]));
4791 elsif ($instr == INST_SJMP)
4793 return ($addr + $size + expand_offset($rom[$addr + 1]));
4797 return EMPTY;
4800 #-------------------------------------------------------------------------------
4803 # If the $BlockRef a conditional jump, then follows.
4806 sub follow_conditional_jump($)
4808 my $BlockRef = $_[0];
4809 my ($addr, $size, $instr, $instr_mask1, $instr_mask2);
4811 return EMPTY if ($BlockRef->{TYPE} != BLOCK_INSTR);
4813 $addr = $BlockRef->{ADDR};
4814 $size = $BlockRef->{SIZE};
4815 $instr = $rom[$addr];
4817 $instr_mask1 = $instr & 0xFE;
4818 $instr_mask2 = $instr & 0xF8;
4820 if ($instr_mask1 == INST_CJNE__Ri_DATA ||
4821 $instr_mask2 == INST_CJNE_Rn_DATA)
4823 return ($addr + $size + expand_offset($rom[$addr + 2]));
4825 elsif ($instr_mask2 == INST_DJNZ_Rn)
4827 return ($addr + $size + expand_offset($rom[$addr + 1]));
4829 elsif ($instr == INST_JBC_BIT ||
4830 $instr == INST_JB_BIT ||
4831 $instr == INST_JNB_BIT ||
4832 $instr == INST_CJNE_A_DATA ||
4833 $instr == INST_CJNE_A_DIRECT ||
4834 $instr == INST_DJNZ_DIRECT)
4836 return ($addr + $size + expand_offset($rom[$addr + 2]));
4838 elsif ($instr == INST_JC ||
4839 $instr == INST_JNC ||
4840 $instr == INST_JZ ||
4841 $instr == INST_JNZ ||
4842 $instr == INST_SJMP)
4844 return ($addr + $size + expand_offset($rom[$addr + 1]));
4847 return EMPTY;
4850 #-------------------------------------------------------------------------------
4853 # Determines the start of stack.
4856 sub determine_stack()
4858 my ($block, $instr, $addr, $count, $size, $t);
4860 return if (! defined($blocks_by_address{0}));
4862 $addr = follow_unconditional_jump(\%{$blocks_by_address{0}});
4863 return if ($addr == EMPTY);
4865 return if (! defined($blocks_by_address{$addr}));
4867 # At most so much block looks through.
4868 $count = 30;
4871 $block = \%{$blocks_by_address{$addr}};
4873 return if ($block->{TYPE} != BLOCK_INSTR);
4874 return if (follow_unconditional_jump($block) != EMPTY);
4875 return if (follow_call($block) != EMPTY);
4877 $addr = $block->{ADDR};
4878 $size = $block->{SIZE};
4879 $instr = $rom[$addr];
4881 return if ($size == 2 && ($instr == INST_PUSH_DIRECT || $instr == INST_POP_DIRECT));
4883 $t = follow_conditional_jump($block);
4885 return if ($t != EMPTY && $t > $addr);
4887 if ($size == 3 && $instr == INST_MOV_DIRECT_DATA && $rom[$addr + 1] == SP)
4889 $stack_start = $rom[$addr + 2] + 1;
4890 $stack_size = RAM_MAX_ADDR - $stack_start + 1;
4891 return;
4894 $addr += $size; # Compute the address of next block.
4896 while (--$count);
4899 #-------------------------------------------------------------------------------
4902 # Previously assess the code.
4905 sub preliminary_survey($)
4907 $decoder_silent_level = $_[0];
4908 foreach (sort {$a <=> $b} keys(%blocks_by_address))
4910 my $block = \%{$blocks_by_address{$_}};
4912 next if ($block->{TYPE} != BLOCK_INSTR);
4914 instruction_decoder($_, $block);
4918 #-------------------------------------------------------------------------------
4921 # Finds address of branchs and procedures.
4924 sub find_labels_in_code()
4926 foreach (sort {$a <=> $b} keys(%blocks_by_address))
4928 my $block = \%{$blocks_by_address{$_}};
4930 next if ($block->{TYPE} != BLOCK_INSTR);
4932 label_finder($_, $block);
4936 #-------------------------------------------------------------------------------
4939 # Finds lost address of branchs and procedures.
4942 sub find_lost_labels_in_code()
4944 my ($block, $prev_block, $prev_addr, $label, $instr);
4946 $prev_addr = EMPTY;
4947 $prev_block = undef;
4948 foreach (sort {$a <=> $b} keys(%blocks_by_address))
4950 $block = \%{$blocks_by_address{$_}};
4952 next if ($block->{TYPE} != BLOCK_INSTR);
4954 if ($prev_addr != EMPTY)
4956 $instr = $rom[$prev_addr];
4957 $label = $block->{LABEL};
4959 if (defined($label) && $label->{TYPE} == BL_TYPE_NONE)
4961 if ($instr == INST_RET || $instr == INST_RETI)
4963 Log(sprintf("Lost function label at the 0x%04X address.", $_), 5);
4964 add_func_label($_, '', TRUE);
4966 elsif ($instr == INST_LJMP || $instr == INST_SJMP || ($instr & 0x1F) == INST_AJMP)
4968 Log(sprintf("Lost jump label at the 0x%04X address.", $_), 5);
4969 add_jump_label($_, '', BL_TYPE_LABEL, EMPTY, TRUE);
4974 $prev_addr = $_;
4975 $prev_block = $block;
4979 #-------------------------------------------------------------------------------
4982 # Adds the jump addresses from a jump table.
4985 sub add_jump_address_in_table($$$)
4987 my ($AddrLow, $AddrHigh, $Size) = @_;
4988 my ($end, $addr);
4990 $end = $AddrLow + $Size;
4991 while ($AddrLow < $end)
4993 $addr = $rom[$AddrLow] | ($rom[$AddrHigh] << 8);
4994 add_jump_label($addr, '', BL_TYPE_JLABEL, EMPTY, FALSE);
4995 ++$AddrLow;
4996 ++$AddrHigh;
5000 #-------------------------------------------------------------------------------
5003 # Jump tables looking for in the code.
5006 sub recognize_jump_tables_in_code($)
5008 my $Survey = $_[0];
5009 my @blocks = ((undef) x 9);
5010 my @instrs = ((EMPTY) x 9);
5011 my ($parm, $data1, $data2, $addrL, $addrH, $end, $size);
5013 foreach (sort {$a <=> $b} keys(%blocks_by_address))
5015 shift(@instrs);
5016 push(@instrs, $rom[$_]);
5018 shift(@blocks);
5019 push(@blocks, \%{$blocks_by_address{$_}});
5021 next if (! defined($blocks[0]) || ! defined($blocks[8]));
5022 next if ($blocks[0]->{TYPE} != BLOCK_INSTR);
5023 next if ($blocks[1]->{TYPE} != BLOCK_INSTR);
5024 next if ($blocks[2]->{TYPE} != BLOCK_INSTR);
5025 next if ($blocks[3]->{TYPE} != BLOCK_INSTR);
5026 next if ($blocks[4]->{TYPE} != BLOCK_INSTR);
5027 next if ($blocks[5]->{TYPE} != BLOCK_INSTR);
5028 next if ($blocks[6]->{TYPE} != BLOCK_INSTR);
5029 next if ($blocks[7]->{TYPE} != BLOCK_INSTR);
5030 next if ($blocks[8]->{TYPE} != BLOCK_INSTR);
5032 if ($blocks[0]->{SIZE} == 2 && $instrs[0] == INST_ADD_A_DATA && # add A, #0xZZ
5034 $blocks[1]->{SIZE} == 1 && $instrs[1] == INST_MOVC_A_APC && # movc A, @A+PC
5036 $blocks[2]->{SIZE} == 2 && $rom[$blocks[2]->{ADDR} + 1] == DPL &&
5037 ($instrs[2] == INST_XCH_A_DIRECT || # xch A, DPL
5038 $instrs[2] == INST_MOV_DIRECT_A) && # mov DPL, A
5040 (($blocks[3]->{SIZE} == 2 && $instrs[3] == INST_MOV_A_DIRECT) || # mov A, direct
5041 ($blocks[3]->{SIZE} == 1 && (($instrs[3] & 0xF8) == INST_MOV_A_Rn || # mov A, Rn
5042 ($instrs[3] & 0xFE) == INST_MOV_A_Ri))) && # mov A, @Ri
5044 $blocks[4]->{SIZE} == 2 && $instrs[4] == INST_ADD_A_DATA && # add A, #0xZZ
5046 $blocks[5]->{SIZE} == 1 && $instrs[5] == INST_MOVC_A_APC && # movc A, @A+PC
5048 $blocks[6]->{SIZE} == 2 && $instrs[6] == INST_MOV_DIRECT_A && # mov DPH, A
5049 $rom[$blocks[6]->{ADDR} + 1] == DPH &&
5051 $blocks[7]->{SIZE} == 1 && $instrs[7] == INST_CLR_A && # clr A
5053 $blocks[8]->{SIZE} == 1 && $instrs[8] == INST_JMP_A_DPTR) # jmp @A+DPTR
5055 =back
5056 24 0B add A, #0x0B
5057 83 movc A, @A+PC
5058 F5 82 mov DPL, A
5060 E5 F0 mov A, B
5062 ED mov A, R5
5064 24 25 add A, #0x25
5065 83 movc A, @A+PC
5066 F5 83 mov DPH, A
5067 E4 clr A
5068 73 jmp @A+DPTR
5069 =cut
5071 $addrL = $blocks[2]->{ADDR} + $rom[$blocks[0]->{ADDR} + 1];
5072 $addrH = $blocks[6]->{ADDR} + $rom[$blocks[4]->{ADDR} + 1];
5073 $size = $addrH - $addrL;
5074 $end = $addrH + $size - 1;
5076 if ($Survey)
5078 add_const_area($addrL, $end);
5080 else
5082 add_block($addrL, BLOCK_JTABLE, $size, BL_TYPE_JTABLE, '');
5083 add_block($addrH, BLOCK_JTABLE, $size, BL_TYPE_JTABLE, '');
5084 add_jump_address_in_table($addrL, $addrH, $size);
5087 elsif ($blocks[0]->{SIZE} == 3 && $instrs[0] == INST_MOV_DPTR_DATA && # mov DPTR, #tLow
5089 $blocks[1]->{SIZE} == 1 && $instrs[1] == INST_MOVC_A_DPTR && # movc A, @A+DPTR
5091 (($blocks[2]->{SIZE} == 2 && $instrs[2] == INST_XCH_A_DIRECT) || # xch A, XX
5092 ($blocks[2]->{SIZE} == 2 && $instrs[2] == INST_PUSH_DIRECT && # push ACC
5093 $rom[$blocks[2]->{ADDR} + 1] == ACC)) &&
5095 $blocks[3]->{SIZE} == 3 && $instrs[3] == INST_MOV_DPTR_DATA && # mov DPTR, #tHigh
5097 $blocks[4]->{SIZE} == 1 && $instrs[4] == INST_MOVC_A_DPTR && # movc A, @A+DPTR
5099 $blocks[5]->{SIZE} == 2 && $instrs[5] == INST_MOV_DIRECT_A && # mov DPH, A
5100 $rom[$blocks[5]->{ADDR} + 1] == DPH &&
5102 (($blocks[6]->{SIZE} == 3 && $instrs[6] == INST_MOV_DIRECT_DIRECT && # mov DPL, XX
5103 $rom[$blocks[6]->{ADDR} + 2] == DPL) ||
5104 ($blocks[6]->{SIZE} == 2 && $instrs[6] == INST_POP_DIRECT && # pop DPL
5105 $rom[$blocks[6]->{ADDR} + 1] == DPL)) &&
5107 $blocks[7]->{SIZE} == 1 && $instrs[7] == INST_CLR_A && # clr A
5109 $blocks[8]->{SIZE} == 1 && $instrs[8] == INST_JMP_A_DPTR) # jmp @A+DPTR
5111 =back
5112 90 00 79 mov DPTR, #0x0079
5113 93 movc A, @A+DPTR
5115 C5 F0 xch A, B
5117 C0 E0 push ACC
5119 90 01 79 mov DPTR, #0x0179
5120 93 movc A, @A+DPTR
5121 F5 83 mov DPH, A
5123 85 F0 82 mov DPL, B
5125 D0 82 pop DPL
5127 E4 clr A
5128 73 jmp @A+DPTR
5129 =cut
5131 $addrL = ($rom[$blocks[0]->{ADDR} + 1] << 8) | $rom[$blocks[0]->{ADDR} + 2];
5132 $addrH = ($rom[$blocks[3]->{ADDR} + 1] << 8) | $rom[$blocks[3]->{ADDR} + 2];
5133 $size = $addrH - $addrL;
5134 $end = $addrH + $size - 1;
5136 if ($Survey)
5138 add_const_area($addrL, $end);
5140 else
5142 add_block($addrL, BLOCK_JTABLE, $size, BL_TYPE_JTABLE, '');
5143 add_block($addrH, BLOCK_JTABLE, $size, BL_TYPE_JTABLE, '');
5144 add_jump_address_in_table($addrL, $addrH, $size);
5150 #-------------------------------------------------------------------------------
5153 # Prints the global symbols.
5156 sub emit_globals($)
5158 my $Assembly_mode = $_[0];
5159 my ($label, $cnt0, $cnt1, $str0, $str1);
5161 return if (! scalar(keys(%labels_by_address)));
5163 print ";$border0\n;\tPublic labels\n;$border0\n\n";
5165 if ($Assembly_mode)
5167 foreach (sort {$a <=> $b} keys(%labels_by_address))
5169 $label = $labels_by_address{$_};
5171 next if ($label->{TYPE} != BL_TYPE_SUB);
5173 print "\t.globl\t$label->{NAME}\n";
5176 else
5178 foreach (sort {$a <=> $b} keys(%labels_by_address))
5180 $label = $labels_by_address{$_};
5182 next if ($label->{TYPE} != BL_TYPE_SUB);
5184 $str0 = sprintf "0x%04X", $_;
5185 $cnt0 = sprintf "%3u", $label->{CALL_COUNT};
5186 $cnt1 = sprintf "%3u", $label->{JUMP_COUNT};
5187 $str1 = ($label->{CALL_COUNT} || $label->{JUMP_COUNT}) ? "calls: $cnt0, jumps: $cnt1" : 'not used';
5188 print "${str0}:\t" . align($label->{NAME}, STAT_ALIGN_SIZE) . "($str1)\n";
5192 print "\n";
5195 #-------------------------------------------------------------------------------
5198 # Prints the SFRs.
5201 sub emit_sfrs($)
5203 my $Assembly_mode = $_[0];
5204 my ($sfr, $cnt, $str0, $str1);
5206 return if (! scalar(keys(%sfr_by_address)));
5208 if ($Assembly_mode)
5210 print ";$border0\n;\tSpecial function registers\n;$border0\n\n" .
5211 "\t.area\tRSEG\t(ABS,DATA)\n\t.org\t0x0000\n\n";
5213 foreach (sort {$a <=> $b} keys(%sfr_by_address))
5215 printf "$sfr_by_address{$_}->{NAME}\t=\t0x%02X\n", $_;
5218 else
5220 print ";$border0\n;\tSFR registers\n;$border0\n\n";
5222 foreach (sort {$a <=> $b} keys(%sfr_by_address))
5224 $sfr = $sfr_by_address{$_};
5225 $str0 = sprintf "0x%02X", $_;
5226 $cnt = sprintf "%3u", $sfr->{REF_COUNT};
5227 $str1 = ($sfr->{REF_COUNT}) ? "used $cnt times" : 'not used';
5228 print "${str0}:\t" . align($sfr->{NAME}, STAT_ALIGN_SIZE) . "($str1)\n";
5232 print "\n";
5235 #-------------------------------------------------------------------------------
5238 # Prints the SFR bits.
5241 sub emit_sfr_bits($)
5243 my $Assembly_mode = $_[0];
5244 my ($sbit, $cnt, $str0, $str1);
5246 return if (! scalar(keys(%sfr_bit_by_address)));
5248 if ($Assembly_mode)
5250 print ";$border0\n;\tSpecial function bits\n;$border0\n\n" .
5251 "\t.area\tRSEG\t(ABS,DATA)\n\t.org\t0x0000\n\n";
5253 foreach (sort {$a <=> $b} keys(%sfr_bit_by_address))
5255 printf "$sfr_bit_by_address{$_}->{NAME}\t=\t0x%02X\n", $_;
5258 else
5260 print ";$border0\n;\tSpecial function bits\n;$border0\n\n";
5262 foreach (sort {$a <=> $b} keys(%sfr_bit_by_address))
5264 $sbit = $sfr_bit_by_address{$_};
5265 $str0 = sprintf "0x%02X", $_;
5266 $cnt = sprintf "%3u", $sbit->{REF_COUNT};
5267 $str1 = ($sbit->{REF_COUNT}) ? "used $cnt times" : 'not used';
5268 print "${str0}:\t" . align($sbit->{NAME}, STAT_ALIGN_SIZE) . "($str1)\n";
5272 print "\n";
5275 #-------------------------------------------------------------------------------
5278 # Prints the banks.
5281 sub emit_banks($)
5283 my $Assembly_mode = $_[0];
5285 $used_banks{0} = TRUE;
5287 print ";$border0\n;\tOverlayable register banks\n;$border0\n\n";
5289 if ($Assembly_mode)
5291 foreach (sort {$a <=> $b} keys(%used_banks))
5293 print "\t.area\tREG_BANK_$_\t(REL,OVR,DATA)\n\t.ds 8\n";
5296 else
5298 foreach (sort {$a <=> $b} keys(%used_banks))
5300 printf "0x%02X:\tREG_BANK_$_\n", $_ * 8;
5304 print "\n";
5308 #-------------------------------------------------------------------------------
5311 # Prints the registers (variables).
5314 sub emit_ram_data($)
5316 my $Assembly_mode = $_[0];
5317 my ($ram, $first, $next_addr, $size);
5318 my ($cnt, $str0, $str1);
5320 return if (! scalar(keys(%ram_by_address)));
5322 if ($Assembly_mode)
5324 print ";$border0\n;\tAbsolute internal RAM data\n;$border0\n\n" .
5325 "\t.area\tIABS\t(ABS,DATA)\n";
5327 $first = TRUE;
5328 $next_addr = EMPTY;
5329 foreach (sort {$a <=> $b} keys(%ram_by_address))
5331 last if ($_ > RAM_LAST_DIR_ADDR);
5333 $ram = $ram_by_address{$_};
5335 next if ($ram->{TYPE} != RAM_TYPE_DIR);
5337 if ($first)
5339 printf "\t.org\t0x%02X\n\n", $_;
5340 $first = FALSE;
5343 if ($next_addr != EMPTY)
5345 next if ($_ < $next_addr);
5347 printf("\t.ds 0x%02X\n", $_ - $next_addr) if ($_ > $next_addr);
5350 if ($ram->{NAME} ne '')
5352 print "$ram->{NAME}::\n\t.ds $ram->{SIZE}\n";
5353 $next_addr = $_ + $size;
5355 else
5357 printf "r0x%02X::\n\t.ds 1\n", $_;
5358 $next_addr = $_ + 1;
5360 } # foreach (sort {$a <=> $b} keys(%ram_by_address))
5362 else
5364 print ";$border0\n;\tInternal RAM data\n;$border0\n\n";
5366 $next_addr = EMPTY;
5367 foreach (sort {$a <=> $b} keys(%ram_by_address))
5369 last if ($_ > RAM_LAST_DIR_ADDR);
5371 $ram = $ram_by_address{$_};
5373 next if ($ram->{TYPE} != RAM_TYPE_DIR);
5375 next if ($next_addr != EMPTY && $_ < $next_addr);
5377 $str0 = sprintf "0x%02X", $_;
5378 $cnt = sprintf "%3u", $ram->{REF_COUNT};
5379 $str1 = ($ram->{REF_COUNT}) ? "used $cnt times" : 'not used';
5381 if ($ram->{NAME} ne '')
5383 $cnt = sprintf "%3u", $ram->{SIZE};
5384 print "${str0}:\t" . align($ram->{NAME}, STAT_ALIGN_SIZE) . "($cnt bytes) ($str1)\n";
5385 $next_addr = $_ + $ram->{SIZE};
5387 else
5389 if ($map_readed)
5391 print "${str0}:\t" . align("variable_$str0", STAT_ALIGN_SIZE) . "( 1 bytes) ($str1)\n";
5393 else
5395 print "${str0}:\t" . align("variable_$str0", STAT_ALIGN_SIZE) . "($str1)\n";
5398 $next_addr = $_ + 1;
5400 } # foreach (sort {$a <=> $b} keys(%ram_by_address))
5403 print "\n";
5406 #-------------------------------------------------------------------------------
5409 # Prints the list of registers in indirect RAM.
5412 sub emit_indirect_ram($)
5414 my $Assembly_mode = $_[0];
5415 my ($ram, $name, $cnt, $str0, $str1, $str2);
5417 return if (! scalar(keys(%ram_by_address)));
5419 if ($Assembly_mode)
5421 print ";$border0\n;\tIndirectly addressable internal RAM data\n;$border0\n\n" .
5422 "\t.area\tISEG\t(DATA)\n\n";
5424 foreach (sort {$a <=> $b} keys(%ram_by_address))
5426 $ram = $ram_by_address{$_};
5428 next if ($ram->{TYPE} != RAM_TYPE_IND);
5430 $name = $ram->{NAME};
5431 $str0 = sprintf "0x%02X", $_;
5432 $str1 = ($name ne '') ? $name : "iram_$str0";
5433 printf "${str1}::\n\t.ds 1\n", $_;
5436 else
5438 print ";$border0\n;\tIndirectly addressable internal RAM data\n;$border0\n\n";
5440 foreach (sort {$a <=> $b} keys(%ram_by_address))
5442 $ram = $ram_by_address{$_};
5444 next if ($ram->{TYPE} != RAM_TYPE_IND);
5446 $name = $ram->{NAME};
5447 $str0 = sprintf "0x%02X", $_;
5448 $str1 = ($name ne '') ? $name : "iram_$str0";
5449 $cnt = sprintf "%3u", $ram->{REF_COUNT};
5450 $str2 = ($ram->{REF_COUNT}) ? "used $cnt times" : 'not used';
5451 print "${str0}:\t" . align($str1, STAT_ALIGN_SIZE) . "($str2)\n";
5455 print "\n";
5458 #-------------------------------------------------------------------------------
5461 # Prints the list of registers in external RAM.
5464 sub emit_external_ram($)
5466 my $Assembly_mode = $_[0];
5467 my ($xram, $name, $next_addr, $cnt, $str0, $str1, $str2);
5469 return if (! scalar(keys(%xram_by_address)));
5471 if ($Assembly_mode)
5473 print ";$border0\n;\tExternal RAM data\n;$border0\n\n\t.area\tXSEG\t(XDATA)\n\n";
5475 foreach (sort {$a <=> $b} keys(%xram_by_address))
5477 $xram = $xram_by_address{$_};
5478 $name = $xram->{NAME};
5479 $str0 = sprintf "0x%04X", $_;
5480 $str1 = ($name ne '') ? $name : "xram_$str0";
5481 print "$str1\t=\t$str0\n";
5484 else
5486 print ";$border0\n;\tExternal RAM data\n;$border0\n\n";
5488 $next_addr = EMPTY;
5489 foreach (sort {$a <=> $b} keys(%xram_by_address))
5491 next if ($next_addr != EMPTY && $_ < $next_addr);
5493 $xram = $xram_by_address{$_};
5494 $str0 = sprintf "0x%04X", $_;
5495 $cnt = sprintf "%3u", $xram->{REF_COUNT};
5496 $str1 = ($xram->{REF_COUNT}) ? "used $cnt times" : 'not used';
5498 if ($xram->{NAME} ne '')
5500 $cnt = sprintf "%3u", $xram->{SIZE};
5501 print "${str0}:\t" . align($xram->{NAME}, STAT_ALIGN_SIZE) . "($cnt bytes) ($str1)\n";
5502 $next_addr = $_ + $xram->{SIZE};
5504 else
5506 $str2 = "xram_$str0";
5507 print "${str0}:\t" . align($str2, STAT_ALIGN_SIZE) . "($str1)\n";
5508 $next_addr = $_ + 1;
5513 print "\n";
5516 #-------------------------------------------------------------------------------
5519 # Prints the bits.
5522 sub emit_bits($)
5524 my $Assembly_mode = $_[0];
5525 my ($bit, $name, $cnt, $str0, $str1, $str2);
5527 return if (! scalar(keys(%bit_by_address)));
5529 if ($Assembly_mode)
5531 print ";$border0\n;\tbit data\n;$border0\n\n" .
5532 "\t.area\tBSEG\t(BIT)\n\n";
5534 foreach (sort {$a <=> $b} keys(%bit_by_address))
5536 $bit = $bit_by_address{$_};
5537 $name = $bit->{NAME};
5538 $str0 = ($name ne '') ? $name : (sprintf "bit_0x%02X", $_);
5539 print "${str0}::\n\t.ds 1\n";
5542 else
5544 print ";$border0\n;\tbit data\n;$border0\n\n";
5546 foreach (sort {$a <=> $b} keys(%bit_by_address))
5548 $bit = $bit_by_address{$_};
5549 $name = $bit->{NAME};
5550 $str0 = sprintf "0x%02X", $_;
5551 $str1 = ($name ne '') ? $name : "bit_$str0";
5552 $cnt = sprintf "%3u", $bit->{REF_COUNT};
5553 $str2 = ($bit->{REF_COUNT}) ? "used $cnt times" : 'not used';
5554 print "${str0}:\t" . align($str1, STAT_ALIGN_SIZE) . "($str2)\n";
5558 print "\n";
5561 #-------------------------------------------------------------------------------
5564 # Prints the map from the RAM.
5567 sub emit_ram_map()
5569 my @map = ();
5570 my ($ram, $i, $v);
5572 for ($i = 0; $i <= RAM_MAX_ADDR; ++$i)
5574 $ram = $ram_by_address{$i};
5576 if (defined($ram))
5578 $map[$i] = ($ram->{TYPE} == RAM_TYPE_DIR) ? 'd' : 'I';
5580 else
5582 $map[$i] = ' ';
5586 $used_banks{0} = TRUE;
5587 foreach (keys(%used_banks))
5589 $i = $_ * 8;
5590 $v = $i + 7;
5593 $map[$i] = $_;
5594 ++$i;
5596 while ($i <= $v);
5599 foreach (keys(%bit_by_address))
5601 $map[0x20 + int($_ / 8)] = 'B';
5604 if ($stack_start > 0)
5606 for ($i = $stack_start; $i <= RAM_MAX_ADDR; ++$i)
5608 $map[$i] = 'S';
5612 print ";$border0\n;\tInternal RAM layout\n;$border0\n\n";
5614 for ($i = 0; $i <= RAM_MAX_ADDR; $i += 16)
5616 printf "0x%02X: |", $i & 0xF0;
5617 print join('|', @map[$i .. ($i + 15)]) . "|\n";
5620 print "\n0-3:Register Banks, B:Bits, d:Data, I:iRAM, S:Stack\n\n";
5623 #-------------------------------------------------------------------------------
5626 # Find the last address of HOME segment.
5629 sub find_HOME_last_address()
5631 my $last_addr = 0;
5633 foreach (sort {$a <=> $b} keys(%blocks_by_address))
5635 my $block = \%{$blocks_by_address{$_}};
5637 last if ($block->{TYPE} == BLOCK_CONST);
5639 if ($block->{TYPE} == BLOCK_INSTR)
5641 last if (! defined($interrupts_by_address{$_}));
5643 last if ($block->{SIZE} > LJMP_SIZE);
5645 $last_addr = $_;
5649 return $last_addr;
5652 #-------------------------------------------------------------------------------
5655 # Prints a label belonging to the $Address.
5658 sub print_label($)
5660 my $Address = $_[0];
5661 my ($label, $type);
5663 $label = $labels_by_address{$Address};
5665 return FALSE if (! defined($label) || $label->{TYPE} == BL_TYPE_NONE);
5667 $type = $label->{TYPE};
5669 if ($type == BL_TYPE_SUB)
5671 print "\n;$border0\n";
5673 elsif ($type == BL_TYPE_JLABEL)
5675 print "\n\t;$border2\n";
5678 printf "\n$label->{NAME}:\n\n";
5679 $label->{PRINTED} = TRUE;
5680 $prev_is_jump = FALSE;
5681 return TRUE;
5684 #-------------------------------------------------------------------------------
5687 # Prints a table of constants.
5690 sub print_constants($$)
5692 my ($Address, $BlockRef) = @_;
5693 my ($size, $i, $len, $frag, $byte, $spc, $col);
5694 my ($left_align, $right_align, $hc);
5695 my @constants;
5696 my @line;
5698 $size = $BlockRef->{SIZE};
5700 return if (! $size);
5702 $hc = ($BlockRef->{TYPE} == BLOCK_JTABLE) || $hex_constant;
5704 $prev_is_jump = FALSE;
5706 $col = ($gen_assembly_code) ? ' ' : ' ';
5708 if ($gen_assembly_code)
5710 print ";$table_border\n;\t\t $table_header |\n;$table_border\n";
5712 else
5714 print "$table_border\n| | $table_header | $table_header |\n$table_border\n";
5717 @constants = @rom[$Address .. ($Address + $size - 1)];
5718 $i = 0;
5719 while (TRUE)
5721 $len = $size - $i;
5723 last if (! $len);
5725 $len = TBL_COLUMNS if ($len > TBL_COLUMNS);
5727 if ($gen_assembly_code)
5729 print "\t.db\t";
5731 else
5733 printf "| 0x%04X | ", $Address;
5736 if (($spc = $Address % TBL_COLUMNS))
5738 $frag = TBL_COLUMNS - $spc;
5739 $len = $frag if ($len > $frag);
5742 $left_align = $col x $spc;
5743 $right_align = $col x (TBL_COLUMNS - $spc - $len);
5744 @line = @constants[$i .. ($i + $len - 1)];
5745 $Address += $len;
5746 $i += $len;
5748 if ($gen_assembly_code)
5750 print $left_align .
5751 join(', ', map {
5752 sprintf((($hc || $_ < ord(' ') || $_ >= 0x7F) ? "0x%02X" : "'%c' "), $_ & 0xFF);
5753 } @line) . "$right_align ;\n";
5755 else
5757 print " $left_align" . join(' ', map { sprintf("%02X ", $_ & 0xFF); } @line);
5759 print "$right_align | $left_align " .
5760 join(' ', map {
5761 sprintf((($_ < ord(' ') || $_ >= 0x7F) ? "%02X " : "'%c'"), $_ & 0xFF);
5762 } @line) . "$right_align |\n";
5764 } # while (TRUE)
5766 print (($gen_assembly_code) ? ";$table_border\n" : "$table_border\n");
5767 $prev_is_jump = FALSE;
5770 #-------------------------------------------------------------------------------
5773 # Disassembly contents of $blocks_by_address array.
5776 sub disassembler()
5778 my ($ref, $home_last_addr, $sname);
5780 $home_last_addr = 0;
5781 $prev_is_jump = FALSE;
5782 $decoder_silent_level = SILENT0;
5784 if ($gen_assembly_code)
5786 $table_header = join(' ', map { sprintf '%02X', $_ } (0 .. (TBL_COLUMNS - 1)));
5787 $table_border = ('-' x (TBL_COLUMNS * 6 + 14)) . '+';
5789 else
5791 $table_header = join(' ', map { sprintf '%02X', $_ } (0 .. (TBL_COLUMNS - 1)));
5792 $table_border = '+' . ('-' x 10) . '+' . ('-' x (TBL_COLUMNS * 4 + 2)) . '+' . ('-' x (TBL_COLUMNS * 4 + 2)) . '+';
5795 invalidate_DPTR_Rx();
5796 print "\n";
5798 if ($gen_assembly_code)
5800 emit_globals(TRUE);
5801 emit_sfrs(TRUE);
5802 emit_sfr_bits(TRUE);
5803 emit_banks(TRUE);
5804 emit_ram_data(TRUE);
5805 emit_bits(TRUE);
5807 if ($stack_start > 0)
5809 print ";$border0\n;\tStack segment\n;$border0\n\n\t.area\tSSEG\t(DATA)\n" .
5810 "__start__stack:\n\t.ds 1\n\n";
5813 emit_indirect_ram(TRUE);
5814 emit_external_ram(TRUE);
5816 $home_last_addr = find_HOME_last_address();
5817 $sname = ($home_last_addr > 0) ? 'HOME' : 'CSEG';
5818 print ";$border0\n;\tCode\n;$border0\n\n\t.area\t$sname\t(CODE)\n\n";
5820 else
5822 emit_ram_map();
5823 emit_globals(FALSE);
5824 emit_sfrs(FALSE);
5825 emit_sfr_bits(FALSE);
5826 emit_banks(FALSE);
5827 emit_ram_data(FALSE);
5828 emit_bits(FALSE);
5830 if ($stack_start > 0)
5832 printf ";$border0\n;\tStack: start=0x%02X, size=%u bytes\n;$border0\n\n", $stack_start, $stack_size;
5835 emit_indirect_ram(FALSE);
5836 emit_external_ram(FALSE);
5837 print ";$border0\n\n";
5840 foreach (sort {$a <=> $b} keys(%blocks_by_address))
5842 $ref = \%{$blocks_by_address{$_}};
5844 if ($ref->{TYPE} == BLOCK_INSTR)
5846 if ($home_last_addr > 0 && $_ > $home_last_addr)
5848 print "\n;$border0\n;\tCode\n;$border0\n\n\t.area\tCSEG\t(CODE)\n";
5849 $home_last_addr = 0;
5852 print_label($_);
5853 print "\n" if ($prev_is_jump);
5855 instruction_decoder($_, $ref);
5857 elsif ($ref->{TYPE} == BLOCK_CONST || $ref->{TYPE} == BLOCK_JTABLE)
5859 print_label($_);
5860 print "\n" if ($prev_is_jump);
5862 print_constants($_, $ref);
5864 elsif ($ref->{TYPE} == BLOCK_EMPTY)
5866 my $next_block = $_ + $ref->{SIZE};
5868 if (! $gen_assembly_code)
5870 printf("\n0x%04X: -- -- --\n .... -- -- --\n0x%04X: -- -- --\n", $_, $next_block - 1);
5872 elsif ($next_block < $rom_size)
5874 # Skip the empty code space.
5876 printf "\n\t.ds\t%u\n", $ref->{SIZE};
5879 } # foreach (sort {$a <=> $b} keys(%blocks_by_address))
5882 #-------------------------------------------------------------------------------
5885 # If there are datas in the code, it is possible that some labels will
5886 # be lost. This procedure prints them.
5889 sub print_hidden_labels()
5891 foreach (sort {$a <=> $b} keys(%labels_by_address))
5893 my $label = $labels_by_address{$_};
5895 print STDERR "The label: $label->{NAME} is hidden!\n" if (! $label->{PRINTED});
5899 ################################################################################
5900 ################################################################################
5902 sub usage()
5904 print <<EOT;
5905 Usage: $PROGRAM [options] <hex file>
5907 Options are:
5909 -M|--mcu <header.h>
5911 Header file of the MCU.
5913 -I|--include <path to header>
5915 Path of the header files of MCS51 MCUs. (Default: $default_include_path)
5917 --map-file <file.map>
5919 The map file belonging to the input hex file. (optional)
5921 -r|--rom-size <size of program memory>
5925 printf "\t Defines size of the program memory. (Default %u bytes.)\n", MCS51_ROM_SIZE;
5926 print <<EOT;
5928 --const-area <start address> <end address>
5930 Designates a constant area (jumptables, texts, etc.), where data is
5931 stored happen. The option may be given more times, that to select
5932 more areas at the same time. (optional)
5934 -hc|--hex-constant
5936 The constants only shows in hexadecimal form. Otherwise if possible,
5937 then shows all in character form.
5939 -as|--assembly-source
5941 Generates the assembly source file. (Eliminates before the instructions
5942 visible address, hex codes and besides replaces the pseudo Rn<#x>
5943 register names.) Emits global symbol table, SFR table, Bits table, etc.
5945 -rj|--recognize-jump-tables
5947 Recognizes the jump tables.
5949 -fl|--find-lost-labels
5951 Finds the "lost" labels. These may be found such in program parts,
5952 which are directly not get call.
5954 --name-list <list_file>
5956 The file contains list of names. They may be: Names of variables and
5957 names of labels. For example:
5959 [BIT]
5960 0x07:bit_variable
5964 [RAM]
5965 0x31:direct_ram_variable
5969 [IRAM]
5970 0x91:indirect_ram_variable
5974 [XRAM]
5975 0x208:external_ram_variable
5979 [ROM]
5980 0x05FC:function_or_label
5985 The contents of list override the names from map file.
5987 -ne|--no-explanations
5989 Eliminates after the instructions visible explaining texts.
5991 -v <level> or --verbose <level>
5993 It provides information on from the own operation.
5994 Possible value of the level between 0 and 10. (default: 0)
5996 -h|--help
5998 This text.
6003 ################################################################################
6004 ################################################################################
6005 ################################################################################
6007 foreach (@default_paths)
6009 if (-d $_)
6011 $default_include_path = $_;
6012 last;
6016 if (! @ARGV)
6018 usage();
6019 exit(1);
6022 for (my $i = 0; $i < @ARGV; )
6024 my $opt = $ARGV[$i++];
6026 given ($opt)
6028 when (/^-(r|-rom-size)$/o)
6030 param_exist($opt, $i);
6031 $rom_size = str2int($ARGV[$i++]);
6033 if ($rom_size < 1024)
6035 printf STDERR "$PROGRAM: Code size of the MCS51 family greater than 1024 bytes!\n";
6036 exit(1);
6038 elsif ($rom_size > MCS51_ROM_SIZE)
6040 printf STDERR "$PROGRAM: Code size of the MCS51 family not greater %u bytes!\n", MCS51_ROM_SIZE;
6041 exit(1);
6045 when (/^--const-area$/o)
6047 my ($start, $end);
6049 param_exist($opt, $i);
6050 $start = str2int($ARGV[$i++]);
6052 param_exist($opt, $i);
6053 $end = str2int($ARGV[$i++]);
6055 if ($start > $end)
6057 my $t = $start;
6059 $start = $end;
6060 $end = $t;
6062 elsif ($start == $end)
6064 $start = MCS51_ROM_SIZE - 1;
6065 $end = MCS51_ROM_SIZE - 1;
6068 add_const_area($start, $end) if ($start < $end);
6069 } # when (/^--const-area$/o)
6071 when (/^-(hc|-hex-constant)$/o)
6073 $hex_constant = TRUE;
6076 when (/^-(I|-include)$/o)
6078 param_exist($opt, $i);
6079 $include_path = $ARGV[$i++];
6082 when (/^-(M|-mcu)$/o)
6084 param_exist($opt, $i);
6085 $header_file = $ARGV[$i++];
6088 when (/^--map-file$/o)
6090 param_exist($opt, $i);
6091 $map_file = $ARGV[$i++];
6094 when (/^-(as|-assembly-source)$/o)
6096 $gen_assembly_code = TRUE;
6099 when (/^-(rj|-recognize-jump-tables)$/o)
6101 $recognize_jump_tables = TRUE;
6104 when (/^-(fl|-find-lost-labels)$/o)
6106 $find_lost_labels = TRUE;
6109 when (/^--name-list$/o)
6111 param_exist($opt, $i);
6112 $name_list = $ARGV[$i++];
6115 when (/^-(ne|-no-explanations)$/o)
6117 $no_explanations = TRUE;
6120 when (/^-(v|-verbose)$/o)
6122 param_exist($opt, $i);
6123 $verbose = int($ARGV[$i++]);
6124 $verbose = 0 if (! defined($verbose) || $verbose < 0);
6125 $verbose = 10 if ($verbose > 10);
6128 when (/^-(h|-help)$/o)
6130 usage();
6131 exit(0);
6134 default
6136 if ($hex_file eq '')
6138 $hex_file = $opt;
6140 else
6142 print STDERR "$PROGRAM: We already have the source file name: $hex_file.\n";
6143 exit(1);
6146 } # given ($opt)
6147 } # for (my $i = 0; $i < @ARGV; )
6149 $include_path = $default_include_path if ($include_path eq '');
6151 if ($hex_file eq '')
6153 print STDERR "$PROGRAM: What do you have to disassembled?\n";
6154 exit(1);
6157 is_file_ok($hex_file);
6159 init_mem(0, $rom_size - 1);
6160 read_hex($hex_file);
6162 if ($header_file ne '')
6164 is_file_ok("$include_path/$header_file");
6165 reset_preprocessor();
6166 $embed_level = 0;
6167 read_header("$include_path/$header_file");
6169 else
6171 $embed_level = 0;
6172 foreach (grep(! /^\s*$|^\s*#/o, <DATA>))
6174 process_header_line($_);
6178 if ($map_file eq '')
6180 ($map_file) = ($hex_file =~ /^(.+)\.hex$/io);
6181 $map_file .= '.map';
6184 $map_file = '' if (! -e $map_file);
6186 is_file_ok($name_list) if ($name_list ne '');
6188 if ($recognize_jump_tables)
6190 split_code_to_blocks();
6191 recognize_jump_tables_in_code(TRUE);
6192 %blocks_by_address = ();
6193 read_map_file();
6194 read_name_list();
6195 split_code_to_blocks();
6196 recognize_jump_tables_in_code(FALSE);
6198 else
6200 read_map_file();
6201 read_name_list();
6202 split_code_to_blocks();
6205 fix_multi_byte_variables();
6206 determine_stack();
6207 preliminary_survey(SILENT2);
6208 preliminary_survey(SILENT1);
6209 find_labels_in_code();
6210 find_lost_labels_in_code() if ($find_lost_labels);
6211 add_names_labels();
6212 disassembler();
6213 print_hidden_labels() if ($verbose > 2);
6215 __END__
6216 ################################################################################
6218 # These the SFR-s and SBIT-s of the i8052 MCU.
6221 __sfr __at (0x80) P0;
6222 __sfr __at (0x81) SP;
6223 __sfr __at (0x82) DPL;
6224 __sfr __at (0x83) DPH;
6225 __sfr __at (0x87) PCON;
6226 __sfr __at (0x88) TCON;
6227 __sfr __at (0x89) TMOD;
6228 __sfr __at (0x8A) TL0;
6229 __sfr __at (0x8B) TL1;
6230 __sfr __at (0x8C) TH0;
6231 __sfr __at (0x8D) TH1;
6232 __sfr __at (0x90) P1;
6233 __sfr __at (0x98) SCON;
6234 __sfr __at (0x99) SBUF;
6235 __sfr __at (0xA0) P2;
6236 __sfr __at (0xA8) IE;
6237 __sfr __at (0xB0) P3;
6238 __sfr __at (0xB8) IP;
6239 __sfr __at (0xC8) T2CON;
6240 __sfr __at (0xCA) RCAP2L;
6241 __sfr __at (0xCB) RCAP2H;
6242 __sfr __at (0xCC) TL2;
6243 __sfr __at (0xCD) TH2;
6244 __sfr __at (0xD0) PSW;
6245 __sfr __at (0xE0) ACC;
6246 __sfr __at (0xF0) B;
6248 __sbit __at (0x80) P0_0;
6249 __sbit __at (0x81) P0_1;
6250 __sbit __at (0x82) P0_2;
6251 __sbit __at (0x83) P0_3;
6252 __sbit __at (0x84) P0_4;
6253 __sbit __at (0x85) P0_5;
6254 __sbit __at (0x86) P0_6;
6255 __sbit __at (0x87) P0_7;
6257 __sbit __at (0x88) IT0;
6258 __sbit __at (0x89) IE0;
6259 __sbit __at (0x8A) IT1;
6260 __sbit __at (0x8B) IE1;
6261 __sbit __at (0x8C) TR0;
6262 __sbit __at (0x8D) TF0;
6263 __sbit __at (0x8E) TR1;
6264 __sbit __at (0x8F) TF1;
6266 __sbit __at (0x90) P1_0;
6267 __sbit __at (0x91) P1_1;
6268 __sbit __at (0x92) P1_2;
6269 __sbit __at (0x93) P1_3;
6270 __sbit __at (0x94) P1_4;
6271 __sbit __at (0x95) P1_5;
6272 __sbit __at (0x96) P1_6;
6273 __sbit __at (0x97) P1_7;
6275 __sbit __at (0x98) RI;
6276 __sbit __at (0x99) TI;
6277 __sbit __at (0x9A) RB8;
6278 __sbit __at (0x9B) TB8;
6279 __sbit __at (0x9C) REN;
6280 __sbit __at (0x9D) SM2;
6281 __sbit __at (0x9E) SM1;
6282 __sbit __at (0x9F) SM0;
6284 __sbit __at (0xA0) P2_0;
6285 __sbit __at (0xA1) P2_1;
6286 __sbit __at (0xA2) P2_2;
6287 __sbit __at (0xA3) P2_3;
6288 __sbit __at (0xA4) P2_4;
6289 __sbit __at (0xA5) P2_5;
6290 __sbit __at (0xA6) P2_6;
6291 __sbit __at (0xA7) P2_7;
6293 __sbit __at (0xA8) EX0;
6294 __sbit __at (0xA9) ET0;
6295 __sbit __at (0xAA) EX1;
6296 __sbit __at (0xAB) ET1;
6297 __sbit __at (0xAC) ES;
6298 __sbit __at (0xAD) ET2;
6299 __sbit __at (0xAF) EA;
6301 __sbit __at (0xB0) RXD;
6302 __sbit __at (0xB1) TXD;
6303 __sbit __at (0xB2) INT0;
6304 __sbit __at (0xB3) INT1;
6305 __sbit __at (0xB4) T0;
6306 __sbit __at (0xB5) T1;
6307 __sbit __at (0xB6) WR;
6308 __sbit __at (0xB7) RD;
6310 __sbit __at (0xB8) PX0;
6311 __sbit __at (0xB9) PT0;
6312 __sbit __at (0xBA) PX1;
6313 __sbit __at (0xBB) PT1;
6314 __sbit __at (0xBC) PS;
6315 __sbit __at (0xBD) PT2;
6317 __sbit __at (0xC8) CP_RL2;
6318 __sbit __at (0xC9) C_T2;
6319 __sbit __at (0xCA) TR2;
6320 __sbit __at (0xCB) EXEN2;
6321 __sbit __at (0xCC) TCLK;
6322 __sbit __at (0xCD) RCLK;
6323 __sbit __at (0xCE) EXF2;
6324 __sbit __at (0xCF) TF2;
6326 __sbit __at (0xD0) P;
6327 __sbit __at (0xD1) F1;
6328 __sbit __at (0xD2) OV;
6329 __sbit __at (0xD3) RS0;
6330 __sbit __at (0xD4) RS1;
6331 __sbit __at (0xD5) F0;
6332 __sbit __at (0xD6) AC;
6333 __sbit __at (0xD7) CY;