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.
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);
84 '/usr/share/sdcc/include/mcs51',
85 '/usr/local/share/sdcc/include/mcs51'
88 my $default_include_path = '';
89 my $include_path = '';
92 my $map_readed = FALSE
;
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
;
104 my $rom_size = MCS51_ROM_SIZE
;
105 my %const_areas_by_address = (); # From the command line parameters.
107 my %const_blocks_by_address = ();
110 The structure of one element of the %sfr_by_address hash:
118 my %sfr_by_address = ();
119 my %sfr_by_names = ();
122 The structure of one element of the %sfr_bit_by_address hash:
130 my %sfr_bit_by_address = ();
135 The structure of one element of the %bit_by_address hash:
143 my %bit_by_address = ();
146 The structure of one element of the %ram_by_address hash:
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 = ();
163 The structure of one element of the %xram_by_address hash:
172 my %xram_by_address = ();
173 my %xram_names_by_address = ();
175 my $stack_start = -1;
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;
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;
265 The structure of one element of the %blocks_by_address hash:
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;
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 =
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 =
355 my $dcd_instr_size = 0;
360 my $dcd_Ri_name = '';
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.
377 # @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
378 # @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
379 #@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@
380 #@@@@@@@@@@@@@@@@@@@@@@@ This a simple preprocessor. @@@@@@@@@@@@@@@@@@@@@@@@@
381 #@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@
382 # @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
383 # @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
385 # Examines that the parameter is defined or not defined.
389 return defined($pp_defines{$_[0]});
392 #-------------------------------------------------------------------------------
394 # Records a definition.
398 my ($Name) = ($_[0] =~ /^(\S+)/op);
399 my $Body = ${^POSTMATCH
};
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.
415 delete($pp_defines{$_[0]});
418 #-------------------------------------------------------------------------------
420 # Evaluation of the #if give a boolean value. This procedure preserves it.
426 push(@pp_conditions, $Val);
427 push(@pp_else_conditions, $Val);
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
;
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);
464 pop(@pp_else_conditions);
468 #-------------------------------------------------------------------------------
470 sub reset_preprocessor
()
474 push(@pp_conditions, TRUE
);
475 @pp_else_conditions = ();
476 push(@pp_else_conditions, FALSE
);
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));
499 # The ancestor is invalid, so the descendants will invalid also.
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));
515 # The ancestor is invalid, so the descendants will invalid also.
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.)
548 ################################################################################
549 ################################################################################
550 ################################################################################
554 return ($_[0] =~ /([^\/]+)$/) ?
$1 : '';
557 #-------------------------------------------------------------------------------
561 die "This option \"$_[0]\" requires a parameter.\n" if ($_[1] > $#ARGV);
564 #-------------------------------------------------------------------------------
568 return if (pop(@_) > $verbose);
569 foreach (@_) { print STDERR
$_; }
573 #-------------------------------------------------------------------------------
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.
594 my $al = $_[1] - int(length($Text) / TAB_LENGTH
);
596 # One space will surely becomes behind it.
603 return ($Text . ("\t" x
$al));
607 #-------------------------------------------------------------------------------
610 # Multiple file test.
619 print STDERR
"$PROGRAM: Not exists -> \"$File\"\n";
625 print STDERR
"$PROGRAM: Not file -> \"$File\"\n";
631 print STDERR
"$PROGRAM: Can not read -> \"$File\"\n";
637 print STDERR
"$PROGRAM: Empty file -> \"$File\"\n";
642 #-------------------------------------------------------------------------------
645 # Initializes the @rom array.
650 my ($Start, $End) = @_;
652 @rom[$Start .. $End] = ((EMPTY
) x
($End - $Start + 1));
655 #-------------------------------------------------------------------------------
658 # Store values of the $Code to $AddrRef address.
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.
687 if (! open(IN
, '<', $Hex))
689 print STDERR
"$PROGRAM : Could not open. -> \"$Hex\"\n";
699 my $len = length() - 1;
701 if ($len < MIN_LINE_LENGTH
)
704 print STDERR
"$PROGRAM: ${line_num}th line <- Shorter than %u character.\n", MIN_LINE_LENGTH
;
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)
717 print STDERR
"$PROGRAM: $Hex <- Crc error. (${line_num}th line \"$_\").\n";
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
)
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);
738 Log
('format = INHX32', 7);
741 elsif ($type != INHX_DATA_REC
)
744 printf STDERR
"$PROGRAM: $Hex <- Unknown type of record: 0x%02X (${line_num}th line \"$_\").\n", $type;
748 if ($bytecount == $count) # INHX32
750 if ($format == INHX8M
)
753 print STDERR
"$PROGRAM: $Hex <- Mixed format of file (${line_num}th line \"$_\").\n";
757 my $addr32 = ($addr_H << 16) | $addr;
759 map { store_code
($_, \
$addr32) } @codes;
761 elsif ($bytecount == ($count * BYTE_SIZE
)) # INHX8M
763 if ($format == INHX32
)
766 print STDERR
"$PROGRAM: $Hex <- Mixed format of file (${line_num}th line \"$_\").\n";
770 map { store_code
($_, \
$addr) } @codes;
775 print STDERR
"$PROGRAM: $Hex <- Wrong format of file (${line_num}th line \"$_\").\n";
783 #-------------------------------------------------------------------------------
786 # Determines that the $Address belongs to a constant.
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);
808 #-------------------------------------------------------------------------------
811 # Determines that the $Address belongs to a empty area.
818 foreach (sort {$a <=> $b} keys(%empty_blocks_by_address))
820 return TRUE
if ($_ <= $Address && $Address <= $empty_blocks_by_address{$_});
821 last if ($_ > $Address);
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.
846 my ($Address, $Type, $Size, $LabelType, $LabelName) = @_;
847 my ($block, $label, $end);
849 $end = $Address + $Size - 1;
851 if (! defined($blocks_by_address{$Address}))
861 $blocks_by_address{$Address} = {
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
;
892 $empty_blocks_by_address{$Address} = $end if ($Size > 0);
896 printf STDERR
"add_block(0x%04X): Unknown block type!\n", $Address;
899 } # if (! defined($blocks_by_address{$Address}))
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
;
934 $empty_blocks_by_address{$Address} = $end if ($Size > 0);
941 #-------------------------------------------------------------------------------
944 # Store address entry of a procedure.
947 sub add_func_label
($$$)
949 my ($Address, $Name, $Map_mode) = @_;
954 Log
(sprintf("add_func_label(): This address (0x%04X) negative!", $Address), 2);
960 if (! defined($blocks_by_address{$Address}))
962 Log
(sprintf("add_func_label(): This address (0x%04X) does not shows an instruction!", $Address), 2);
967 if (is_constant
($Address) || is_empty
($Address))
969 Log
(sprintf("add_func_label(): This address (0x%04X) outside the code area!", $Address), 2);
973 $label = add_block
($Address, BLOCK_INSTR
, 0, BL_TYPE_SUB
, $Name);
974 ++$label->{CALL_COUNT
} if (! $Map_mode);
977 #-------------------------------------------------------------------------------
983 sub add_jump_label
($$$$$)
985 my ($TargetAddr, $Name, $Type, $SourceAddr, $Map_mode) = @_;
990 Log
(sprintf("add_jump_label(): This address (0x%04X) negative!", $TargetAddr), 2);
996 if (! defined($blocks_by_address{$TargetAddr}))
998 Log
(sprintf("add_jump_label(): This address (0x%04X) does not shows an instruction!", $TargetAddr), 2);
1003 if (is_constant
($TargetAddr) || is_empty
($TargetAddr))
1005 Log
(sprintf("add_jump_label(): This address (0x%04X) outside the code area!", $TargetAddr), 2);
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.
1027 my ($Address, $Name, $Map_mode) = @_;
1030 if ($Address > BIT_LAST_ADDR
)
1032 if (! defined($bit = $sfr_bit_by_address{$Address}))
1034 $sfr_bit_by_address{$Address} = {
1036 REF_COUNT
=> ($Map_mode) ?
0 : 1
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);
1047 ++$bit->{REF_COUNT
} if (! $Map_mode);
1053 if (! defined($bit = $bit_by_address{$Address}))
1055 $bit_by_address{$Address} = {
1057 REF_COUNT
=> ($Map_mode) ?
0 : 1
1062 ++$bit->{REF_COUNT
} if (! $Map_mode);
1067 #-------------------------------------------------------------------------------
1070 # Store a sfr or variable name.
1075 my ($Address, $Name, $Type, $Map_mode) = @_;
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} = {
1086 REF_COUNT
=> ($Map_mode) ?
0 : 1
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);
1097 ++$ram->{REF_COUNT
} if (! $Map_mode);
1101 $sfr_by_names{$Name} = $Address;
1105 if (! defined($ram = $ram_by_address{$Address}))
1107 $ram_by_address{$Address} = {
1111 REF_COUNT
=> ($Map_mode) ?
0 : 1
1116 ++$ram->{REF_COUNT
} if (! $Map_mode);
1121 #-------------------------------------------------------------------------------
1124 # Store a variable name from XRAM.
1129 my ($Address, $Name, $Map_mode) = @_;
1132 if (! defined($xram = $xram_by_address{$Address}))
1134 $xram_by_address{$Address} = {
1137 REF_COUNT
=> ($Map_mode) ?
0 : 1
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.
1167 my ($addr, $name, $state, $label);
1169 return if ($map_file eq '');
1173 if (! open(MAP
, '<', $map_file))
1175 print STDERR
"$PROGRAM : Could not open. -> \"$map_file\"\n";
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)
1202 elsif (/^(HOME|CSEG)\s+/o)
1206 elsif (/^GSINIT\d+\s+/o)
1210 elsif (/^(D|O)SEG\s+/o)
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);
1225 elsif (/^SSEG\s+([[:xdigit:]]+)\s+([[:xdigit:]]+)/o)
1227 ($stack_start, $stack_size) = (hex($1), hex($2));
1234 elsif ($state == MAP_ABS
)
1236 if (/^.ASxxxx Linker\s+/io)
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)
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)
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
);
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)
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)
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);
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";
1353 $state = NAMES_NULL
;
1355 foreach (grep(! /^\s*$/o, <NAMES
>))
1366 elsif (/^\[RAM\]$/io)
1371 elsif (/^\[XRAM\]$/io)
1373 $state = NAMES_XRAM
;
1376 elsif (/^\[IRAM\]$/io)
1378 $state = NAMES_IRAM
;
1381 elsif (/^\[ROM\]$/io)
1393 if ($line =~ /^0x([[:xdigit:]]+)\s*:\s*(\S+)$/io)
1395 add_bit
(hex($1), $2, TRUE
);
1401 if ($line =~ /^0x([[:xdigit:]]+)\s*:\s*(\S+)$/io)
1403 add_ram
(hex($1), $2, RAM_TYPE_DIR
, TRUE
);
1409 if ($line =~ /^0x([[:xdigit:]]+)\s*:\s*(\S+)$/io)
1411 add_ram
(hex($1), $2, RAM_TYPE_IND
, TRUE
);
1417 if ($line =~ /^0x([[:xdigit:]]+)\s*:\s*(\S+)$/io)
1419 add_xram
(hex($1), $2, TRUE
);
1425 if ($line =~ /^0x([[:xdigit:]]+)\s*:\s*(\S+)$/io)
1427 add_jump_label
(hex($1), $2, BL_TYPE_LABEL
, EMPTY
, TRUE
);
1431 } # foreach (grep(! /^\s*$/o, <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);
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;
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;
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;
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;
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);
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 ################################################################################
1558 Instruction set of the 8051 family:
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
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
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
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
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
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
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
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
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
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
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
1668 MOV direct, A 11110101 aaaaaaaa register address
1669 MOV @Ri, A 1111011i R0 .. R1
1670 MOV Rn, A 11111rrr R0 .. R7
1673 #-------------------------------------------------------------------------------
1676 # Expand a relative offset value.
1679 sub expand_offset
($)
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.
1792 my ($Address, $StrRef) = @_;
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>";
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
};
1817 elsif (defined($ram = $ram_names_by_address{$Address}))
1819 $str = sprintf "0x%02X", $Address;
1820 ${$StrRef} = "[$str]";
1825 $str = sprintf "0x%02X", $Address;
1826 ${$StrRef} = "[$str]";
1832 #-------------------------------------------------------------------------------
1835 # If exists a XRAM name wich belong to the $Address, then returns it.
1836 # Otherwise, returns the address.
1841 my ($Address, $StrRef) = @_;
1844 $str = sprintf "0x%04X", $Address;
1847 $str = $xram if (defined($xram = $xram_names_by_address{$Address}));
1852 #-------------------------------------------------------------------------------
1855 # If exists a iRAM name wich belong to the $Address, then returns it.
1856 # Otherwise, returns the address.
1861 my ($Address, $StrRef) = @_;
1864 $str = sprintf "0x%02X", $Address;
1866 $ram = $ram_names_by_address{$Address};
1868 $str = $ram if (defined($ram));
1873 #-------------------------------------------------------------------------------
1876 # If exists a bit name wich belong to the $Address, then returns it.
1877 # Otherwise, returns the address.
1882 my ($Address, $StrRef) = @_;
1885 if (defined($bit = $sfr_bit_by_address{$Address}) && $bit->{NAME
} ne '')
1887 $str = $bit->{NAME
};
1890 elsif (defined($bit = $bit_by_address{$Address}) && $bit->{NAME
} ne '')
1892 $str = sprintf "0x%02X", $Address;
1893 ${$StrRef} = "[$str]";
1894 $str = $bit->{NAME
};
1898 $str = sprintf "0x%02X", $Address;
1899 ${$StrRef} = "[$str]";
1905 #-------------------------------------------------------------------------------
1908 # If exists a label name wich belong to the $Address, then returns it.
1909 # Otherwise, returns the address.
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.
1928 return if ($decoder_silent_level > SILENT0
);
1930 if ($no_explanations)
1932 print(($_[1] ne '') ?
"$_[0]\t$_[1]\n" : "$_[0]\n");
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
()
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
)
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;
1988 my $Oper = shift(@_);
1991 if ($Oper == Rx_INV
)
1993 $R_regs[$Rx] = EMPTY
;
1995 elsif ($Oper == Rx_INC
)
2002 $R_regs[$Rx] = $r & 0xFF;
2006 elsif ($Oper == Rx_DEC
)
2013 $R_regs[$Rx] = $r & 0xFF;
2017 elsif ($Oper == Rx_MOV
)
2019 $R_regs[$Rx] = shift(@_) & 0xFF;
2026 #-------------------------------------------------------------------------------
2029 # If possible, returns the character.
2036 if ($Ch >= ord(' ') && $Ch < 0x7F)
2038 return sprintf " {'%c'}", $Ch;
2040 elsif (defined($control_characters{$Ch}))
2042 return " {'$control_characters{$Ch}'}";
2048 #-------------------------------------------------------------------------------
2051 # Decodes value of the $Ch.
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)
2090 return ' (backward)';
2094 #-------------------------------------------------------------------------------
2097 # Returns with TRUE if the instruction use indirect RAM addressing
2103 my $Address = $_[0];
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 # @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
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)
2138 $str2 = ' (forward)';
2140 elsif ($dcd_address == $addr)
2142 $str1 = ' (endless loop)';
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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]");
2194 #-------------------------------------------------------------------------------
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]");
2208 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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
()
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
);
2297 #-------------------------------------------------------------------------------
2299 sub mov_direct_ind_Ri
()
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 #-------------------------------------------------------------------------------
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
()
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
);
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 #-------------------------------------------------------------------------------
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]");
2401 #-------------------------------------------------------------------------------
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)");
2415 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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");
2455 #-------------------------------------------------------------------------------
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");
2469 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
2505 # ADD A, Rn 00101rrr R0 .. R7
2507 print_3
('add', "A, $dcd_Rn_name", "ACC += $dcd_Rn_name");
2510 #-------------------------------------------------------------------------------
2514 # ADDC A, Rn 00111rrr R0 .. R7
2516 print_3
('addc', "A, $dcd_Rn_name", "ACC += $dcd_Rn_name + CY");
2519 #-------------------------------------------------------------------------------
2523 # ORL A, Rn 01001rrr R0 .. R7
2525 print_3
('orl', "A, $dcd_Rn_name", "ACC |= $dcd_Rn_name");
2528 #-------------------------------------------------------------------------------
2532 # ANL A, Rn 01011rrr R0 .. R7
2534 print_3
('anl', "A, $dcd_Rn_name", "ACC &= $dcd_Rn_name");
2537 #-------------------------------------------------------------------------------
2541 # XRL A, Rn 01101rrr R0 .. R7
2543 print_3
('xrl', "A, $dcd_Rn_name", "ACC ^= $dcd_Rn_name");
2546 #-------------------------------------------------------------------------------
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");
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
2597 # SUBB A, Rn 10011rrr R0 .. R7
2599 print_3
('subb', "A, $dcd_Rn_name", "ACC -= $dcd_Rn_name + CY");
2602 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
2682 # MOV A, Rn 11101rrr R0 .. R7
2684 print_3
('mov', "A, $dcd_Rn_name", "ACC = $dcd_Rn_name");
2687 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
2702 print "nop\n" if ($decoder_silent_level == SILENT0
);
2705 #-------------------------------------------------------------------------------
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)
2722 $str2 = ' (forward)';
2724 elsif ($dcd_address == $addr)
2726 $str1 = ' (endless loop)';
2732 $str2 = ' (backward)';
2735 print_3
('ljmp', $rb, "Jumps$str2 hither: $str0$str1");
2738 invalidate_DPTR_Rx
();
2739 $prev_is_jump = TRUE
;
2742 #-------------------------------------------------------------------------------
2748 print_3
('rr', 'A', 'ACC[76543210] = ACC[07654321]');
2751 #-------------------------------------------------------------------------------
2757 print_3
('inc', 'A', '++ACC');
2760 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
2833 print_3
('rrc', 'A', 'ACC[76543210] = ACC[C7654321], CY = ACC[0]');
2836 #-------------------------------------------------------------------------------
2842 print_3
('dec', 'A', '--ACC');
2845 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
2899 print_3
('ret', '', 'PCH = [SP--], PCL = [SP--]');
2900 invalidate_DPTR_Rx
();
2901 $prev_is_jump = TRUE
;
2904 #-------------------------------------------------------------------------------
2910 print_3
('rl', 'A', 'ACC[76543210] = ACC[65432107]');
2913 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
2981 print_3
('reti', '', 'PCH = [SP--], PCL = [SP--]');
2982 invalidate_DPTR_Rx
();
2983 $prev_is_jump = TRUE
;
2986 #-------------------------------------------------------------------------------
2992 print_3
('rlc', 'A', 'ACC[76543210] = ACC[6543210C], CY = ACC[7]');
2995 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
3392 # JMP @A+DPTR 01110011
3396 add_jump_label
($DPTR, '', BL_TYPE_JTABLE
, EMPTY
, FALSE
);
3397 $str = jump_direction
($DPTR);
3404 print_3
('jmp', '@A+DPTR', "Jumps$str hither: [DPTR + ACC]");
3405 invalidate_DPTR_Rx
();
3406 $prev_is_jump = TRUE
;
3409 #-------------------------------------------------------------------------------
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;
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);
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
3517 # MOVC A, @A+PC 10000011
3519 print_3
('movc', 'A, @A+PC', "ACC = ROM[PC + $dcd_instr_size + ACC]");
3522 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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");
3573 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
3687 $str = sprintf " (0x%04X)", $DPTR;
3694 print_3
('inc', 'DPTR', "++DPTR$str");
3697 #-------------------------------------------------------------------------------
3703 print_3
('mul', 'AB', 'B:ACC = ACC * B');
3706 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
3782 print_3
('cpl', 'C', 'CY = ~CY');
3785 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
3879 print_3
('clr', 'C', 'CY = L');
3882 #-------------------------------------------------------------------------------
3888 print_3
('swap', 'A', 'ACC[76543210] = ACC[32107654]');
3891 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
3958 print_3
('setb', 'C', 'CY = H');
3961 #-------------------------------------------------------------------------------
3967 print_3
('da', 'A', 'Decimal adjust the ACC.');
3970 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
4014 print_3
('clr', 'A', 'ACC = 0');
4017 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
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 #-------------------------------------------------------------------------------
4053 print_3
('cpl', 'A', 'ACC = ~ACC');
4056 #-------------------------------------------------------------------------------
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 =
4231 \
&mov_direct_direct
,
4232 \
&mov_direct_ind_Ri
,
4233 \
&mov_direct_ind_Ri
,
4268 \
&mov_ind_Ri_direct
,
4269 \
&mov_ind_Ri_direct
,
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);
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)
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)
4431 printf " %02X %02X\t", $dcd_parm0, $dcd_parm1;
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]();
4460 ################################################################################
4461 ################################################################################
4464 # Reads the sfrs and bits from the $Line.
4467 sub process_header_line
($)
4471 Log
((' ' x
$embed_level) . $Line, 5);
4473 if ($Line =~ /^#\s*include\s+["<]\s*(\S+)\s*[">]$/o)
4476 &read_header
("$include_path/$1");
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)
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)
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.
4534 my ($fh, $pre_comment, $comment, $line_number);
4537 if (! open($fh, '<', $Header))
4539 print STDERR
"$PROGRAM: Could not open. -> \"$Header\"\n";
4543 $head = ' ' x
$embed_level;
4545 Log
("${head}read_header($Header) >>>>", 5);
4554 # Filters off the C comments.
4556 s/\/\*.*\*\///o; # /* ... */
4557 s/\/\/.*$//o; # // ...
4562 $pre_comment = TRUE
;
4565 elsif (/\*\//o) # */
4567 $pre_comment = FALSE
;
4578 $comment = $pre_comment if ($pre_comment);
4586 run_preprocessor
($Header, \
&process_header_line
, $_, $line_number);
4590 Log
("${head}<<<< read_header($Header)", 5);
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];
4606 $dcd_address = $Address;
4607 $dcd_instr = $rom[$dcd_address];
4613 add_block
($Address, BLOCK_CONST
, $instr_size, BL_TYPE_NONE
, '');
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
);
4636 add_block
($Address, BLOCK_CONST
, $instr_size, BL_TYPE_NONE
, '') if ($instr_size);
4640 add_block
($Address, BLOCK_INSTR
, $instr_size, BL_TYPE_NONE
, '');
4647 #-------------------------------------------------------------------------------
4650 # Splits the program into small blocks.
4653 sub split_code_to_blocks
()
4656 my ($is_empty, $empty_begin);
4657 my ($is_const, $const_begin);
4664 for ($i = 0; $i < $rom_size; )
4668 if ($instr == EMPTY
)
4672 # The begin of the empty section.
4676 # The end of the constant section.
4678 add_block
($const_begin, BLOCK_CONST
, $i - $const_begin, BL_TYPE_NONE
, '');
4687 } # if ($instr == EMPTY)
4688 elsif (is_constant
($i))
4694 # The end of the empty section.
4696 add_block
($empty_begin, BLOCK_EMPTY
, $i - $empty_begin, BL_TYPE_NONE
, '');
4705 } # elsif (is_constant($i))
4710 # The end of the constant section.
4712 add_block
($const_begin, BLOCK_CONST
, $i - $const_begin, BL_TYPE_NONE
, '');
4718 # The end of the empty section.
4720 add_block
($empty_begin, BLOCK_EMPTY
, $i - $empty_begin, BL_TYPE_NONE
, '');
4724 $i += add_instr_block
($i, $instr);
4726 } # for ($i = 0; $i < $rom_size; )
4730 add_block
($const_begin, BLOCK_CONST
, $i - $const_begin, BL_TYPE_NONE
, '');
4735 add_block
($empty_begin, BLOCK_EMPTY
, $i - $empty_begin, BL_TYPE_NONE
, '');
4739 #-------------------------------------------------------------------------------
4742 # If the $BlockRef a call, then follows.
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]);
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]);
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]));
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]));
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.
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;
4894 $addr += $size; # Compute the address of next block.
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);
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
);
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) = @_;
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
);
5000 #-------------------------------------------------------------------------------
5003 # Jump tables looking for in the code.
5006 sub recognize_jump_tables_in_code
($)
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))
5016 push(@instrs, $rom[$_]);
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
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;
5078 add_const_area
($addrL, $end);
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
5112 90 00 79 mov DPTR, #0x0079
5119 90 01 79 mov DPTR, #0x0179
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;
5138 add_const_area
($addrL, $end);
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.
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";
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";
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";
5195 #-------------------------------------------------------------------------------
5203 my $Assembly_mode = $_[0];
5204 my ($sfr, $cnt, $str0, $str1);
5206 return if (! scalar(keys(%sfr_by_address)));
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", $_;
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";
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)));
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", $_;
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";
5275 #-------------------------------------------------------------------------------
5283 my $Assembly_mode = $_[0];
5285 $used_banks{0} = TRUE
;
5287 print ";$border0\n;\tOverlayable register banks\n;$border0\n\n";
5291 foreach (sort {$a <=> $b} keys(%used_banks))
5293 print "\t.area\tREG_BANK_$_\t(REL,OVR,DATA)\n\t.ds 8\n";
5298 foreach (sort {$a <=> $b} keys(%used_banks))
5300 printf "0x%02X:\tREG_BANK_$_\n", $_ * 8;
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)));
5324 print ";$border0\n;\tAbsolute internal RAM data\n;$border0\n\n" .
5325 "\t.area\tIABS\t(ABS,DATA)\n";
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
);
5339 printf "\t.org\t0x%02X\n\n", $_;
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;
5357 printf "r0x%02X::\n\t.ds 1\n", $_;
5358 $next_addr = $_ + 1;
5360 } # foreach (sort {$a <=> $b} keys(%ram_by_address))
5364 print ";$border0\n;\tInternal RAM data\n;$border0\n\n";
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
};
5391 print "${str0}:\t" . align
("variable_$str0", STAT_ALIGN_SIZE
) . "( 1 bytes) ($str1)\n";
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))
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)));
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", $_;
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";
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)));
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";
5486 print ";$border0\n;\tExternal RAM data\n;$border0\n\n";
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
};
5506 $str2 = "xram_$str0";
5507 print "${str0}:\t" . align
($str2, STAT_ALIGN_SIZE
) . "($str1)\n";
5508 $next_addr = $_ + 1;
5516 #-------------------------------------------------------------------------------
5524 my $Assembly_mode = $_[0];
5525 my ($bit, $name, $cnt, $str0, $str1, $str2);
5527 return if (! scalar(keys(%bit_by_address)));
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";
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";
5561 #-------------------------------------------------------------------------------
5564 # Prints the map from the RAM.
5572 for ($i = 0; $i <= RAM_MAX_ADDR
; ++$i)
5574 $ram = $ram_by_address{$i};
5578 $map[$i] = ($ram->{TYPE
} == RAM_TYPE_DIR
) ?
'd' : 'I';
5586 $used_banks{0} = TRUE
;
5587 foreach (keys(%used_banks))
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)
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
()
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
);
5652 #-------------------------------------------------------------------------------
5655 # Prints a label belonging to the $Address.
5660 my $Address = $_[0];
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
;
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);
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";
5714 print "$table_border\n| | $table_header | $table_header |\n$table_border\n";
5717 @constants = @rom[$Address .. ($Address + $size - 1)];
5725 $len = TBL_COLUMNS
if ($len > TBL_COLUMNS
);
5727 if ($gen_assembly_code)
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)];
5748 if ($gen_assembly_code)
5752 sprintf((($hc || $_ < ord(' ') || $_ >= 0x7F) ?
"0x%02X" : "'%c' "), $_ & 0xFF);
5753 } @line) . "$right_align ;\n";
5757 print " $left_align" . join(' ', map { sprintf("%02X ", $_ & 0xFF); } @line);
5759 print "$right_align | $left_align " .
5761 sprintf((($_ < ord(' ') || $_ >= 0x7F) ?
"%02X " : "'%c'"), $_ & 0xFF);
5762 } @line) . "$right_align |\n";
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.
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)) . '+';
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
();
5798 if ($gen_assembly_code)
5802 emit_sfr_bits
(TRUE
);
5804 emit_ram_data
(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";
5823 emit_globals
(FALSE
);
5825 emit_sfr_bits
(FALSE
);
5827 emit_ram_data
(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;
5853 print "\n" if ($prev_is_jump);
5855 instruction_decoder
($_, $ref);
5857 elsif ($ref->{TYPE
} == BLOCK_CONST
|| $ref->{TYPE
} == BLOCK_JTABLE
)
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 ################################################################################
5905 Usage: $PROGRAM [options] <hex file>
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
;
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)
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:
5965 0x31:direct_ram_variable
5970 0x91:indirect_ram_variable
5975 0x208:external_ram_variable
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)
6003 ################################################################################
6004 ################################################################################
6005 ################################################################################
6007 foreach (@default_paths)
6011 $default_include_path = $_;
6022 for (my $i = 0; $i < @ARGV; )
6024 my $opt = $ARGV[$i++];
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";
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
;
6045 when (/^--const-area$/o)
6049 param_exist
($opt, $i);
6050 $start = str2int
($ARGV[$i++]);
6052 param_exist
($opt, $i);
6053 $end = str2int
($ARGV[$i++]);
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)
6136 if ($hex_file eq '')
6142 print STDERR
"$PROGRAM: We already have the source file name: $hex_file.\n";
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";
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
();
6167 read_header
("$include_path/$header_file");
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 = ();
6195 split_code_to_blocks
();
6196 recognize_jump_tables_in_code
(FALSE
);
6202 split_code_to_blocks
();
6205 fix_multi_byte_variables
();
6207 preliminary_survey
(SILENT2
);
6208 preliminary_survey
(SILENT1
);
6209 find_labels_in_code
();
6210 find_lost_labels_in_code
() if ($find_lost_labels);
6213 print_hidden_labels
() if ($verbose > 2);
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
;