diff options
| author | Xavier ASUS <xavi92psx@gmail.com> | 2019-10-18 00:31:54 +0200 |
|---|---|---|
| committer | Xavier ASUS <xavi92psx@gmail.com> | 2019-10-18 00:31:54 +0200 |
| commit | 268a53de823a6750d6256ee1fb1e7707b4b45740 (patch) | |
| tree | 42c1799a9a82b2f7d9790ee9fe181d72a7274751 /support/scripts | |
| download | sdcc-gas-268a53de823a6750d6256ee1fb1e7707b4b45740.tar.gz | |
sdcc-3.9.0 fork implementing GNU assembler syntax
This fork aims to provide better support for stm8-binutils
Diffstat (limited to 'support/scripts')
27 files changed, 25548 insertions, 0 deletions
diff --git a/support/scripts/Makefile b/support/scripts/Makefile new file mode 100644 index 0000000..eb94eac --- /dev/null +++ b/support/scripts/Makefile @@ -0,0 +1,21 @@ + +srcdir = . +top_builddir = ../.. + +include $(top_builddir)/Makefile.common + +TARGET = $(top_builddir)/bin/as2gbmap + +all: + cp $(srcdir)/as2gbmap.py $(TARGET) && chmod +x $(TARGET) + +install: all installdirs + $(INSTALL) $(TARGET) $(DESTDIR)$(bindir)/`echo as2gbmap|sed '$(transform)'` + +installdirs: + -$(INSTALL) -d $(DESTDIR)$(bindir) + +uninstall: + rm -rf $(DESTDIR)$(bindir)/`echo as2gbmap|sed '$(transform)'` + +include $(srcdir)/clean.mk diff --git a/support/scripts/Makefile.in b/support/scripts/Makefile.in new file mode 100644 index 0000000..1b4d10d --- /dev/null +++ b/support/scripts/Makefile.in @@ -0,0 +1,21 @@ +VPATH = @srcdir@ +srcdir = @srcdir@ +top_builddir = @top_builddir@ + +include $(top_builddir)/Makefile.common + +TARGET = $(top_builddir)/bin/as2gbmap + +all: + cp $(srcdir)/as2gbmap.py $(TARGET) && chmod +x $(TARGET) + +install: all installdirs + $(INSTALL) $(TARGET) $(DESTDIR)$(bindir)/`echo as2gbmap|sed '$(transform)'` + +installdirs: + -$(INSTALL) -d $(DESTDIR)$(bindir) + +uninstall: + rm -rf $(DESTDIR)$(bindir)/`echo as2gbmap|sed '$(transform)'` + +include $(srcdir)/clean.mk diff --git a/support/scripts/Makefile.snapshot b/support/scripts/Makefile.snapshot new file mode 100644 index 0000000..618d5d0 --- /dev/null +++ b/support/scripts/Makefile.snapshot @@ -0,0 +1,22 @@ +# Simple weekly tarball generator +SVNROOT = https://sdcc.svn.sourceforge.net/svnroot/sdcc/trunk/sdcc +DATE = `date +%Y%m%d` +WWWROOT = /home/michaelh/www +SNAP = $(WWWROOT)/snapshots + +REVISION = 1 + +all: _sdcc + +_sdcc: + mkdir -p $(SNAP) + cd /tmp; \ + mkdir -p sdcc-$(DATE); \ + cd sdcc-$(DATE); \ + svn co $(SVNROOT) sdcc; \ + tar czf $(SNAP)/sdcc-$(DATE)-$(REVISION).tar.gz sdcc; \ + tar cIf $(SNAP)/sdcc-$(DATE)-$(REVISION).tar.bz2 sdcc + cd $(SNAP); \ + md5sum sdcc-$(DATE)-$(REVISION).tar.gz > sdcc-$(DATE)-$(REVISION).md5sums + cd $(SNAP); \ + md5sum sdcc-$(DATE)-$(REVISION).tar.bz2 >> sdcc-$(DATE)-$(REVISION).md5sums diff --git a/support/scripts/as2gbmap.py b/support/scripts/as2gbmap.py new file mode 100644 index 0000000..2ab5cde --- /dev/null +++ b/support/scripts/as2gbmap.py @@ -0,0 +1,181 @@ +#!/usr/bin/env python + +# as2gbmap - asxxxx to gb map file converter +# +# Copyright (c) 2010 Borut Razem +# +# This file is part of sdcc. +# +# This software is provided 'as-is', without any express or implied +# warranty. In no event will the authors be held liable for any damages +# arising from the use of this software. +# +# Permission is granted to anyone to use this software for any purpose, +# including commercial applications, and to alter it and redistribute it +# freely, subject to the following restrictions: +# +# 1. The origin of this software must not be misrepresented; you must not +# claim that you wrote the original software. If you use this software +# in a product, an acknowledgment in the product documentation would be +# appreciated but is not required. +# 2. Altered source versions must be plainly marked as such, and must not be +# misrepresented as being the original software. +# 3. This notice may not be removed or altered from any source distribution. +# +# Borut Razem +# borut.razem@siol.net + +from __future__ import print_function + +import sys +import os +import re +from optparse import OptionParser +import operator + +def main(): + '''asxxxx to gb map file converter''' + usage = "usage: %prog [options] [<input_asxxxx_map_file> [<output_gb_file>]]" + parser = OptionParser(usage = usage, version = "1.0") + parser.set_defaults(no_gmb = False) + parser.add_option("-j", "--no$gmb", action = "store_true", dest = "no_gmb", help = "generate no$gmb symbol file (default: rrgb)") + (options, args) = parser.parse_args() + + if len(args) > 0 and args[0] != "-": + try: + fin = open(args[0], "r") + except IOError as xxx_todo_changeme: + (errno, strerror) = xxx_todo_changeme.args + print("%s: can't open %s: %s" % (os.path.basename(sys.argv[0]), args[0], strerror), file=sys.stderr) + return 1 + else: + fin = sys.stdin + + if len(args) > 1 and args[1] != "-": + try: + fout = open(args[1], "w") + except IOError as xxx_todo_changeme1: + (errno, strerror) = xxx_todo_changeme1.args + print("%s: can't create %s: %s" % (os.path.basename(sys.argv[1]), args[1], strerror), file=sys.stderr) + return 1 + else: + fout = sys.stdout; + + areas = [] + modules = [] + libraries = [] + ubads = [] + + radix = 'HEX' + state = None + area = None + + # process asxxxx map file + for line in fin: + if re.match(r"^Hexadecimal$", line): + radix = 'HEX'; + continue + + if re.match(r"^Area +Addr +Size +Decimal +Bytes +\(Attributes\)$", line): + line = next(fin) + if re.match(r"^[- ]+$", line): + line = next(fin) + m = re.match(r"^([^ ]+) +([0-9A-Fa-f]{4}) +([0-9A-Fa-f]{4}) += +\d+\. +\w+ +\(([^\)]+)\)$", line) + if m: + if area: + if m.group(1) != area['area']: + areas.append(area) + area = {'area': m.group(1), 'radix': radix, 'base': int(m.group(2), 16), 'size': int(m.group(3), 16), 'attrib': m.group(4).replace(',', ' '), 'globals': []} + else: + area = {'area': m.group(1), 'radix': radix, 'base': int(m.group(2), 16), 'size': int(m.group(3), 16), 'attrib': m.group(4).replace(',', ' '), 'globals': []} + state = 'IN_AREA' + continue + + m = re.match(r"^ +([0-9A-Fa-f]{4}) +([^ ]+) +$", line) + if state == 'IN_AREA' and m: + area['globals'].append({'value': int(m.group(1), 16), 'global': m.group(2)}) + continue + + m = re.match(r"Files Linked +\[ module\(s\) \]$", line) + if m: + state = 'IN_MODULES' + continue + + m = re.match(r"Libraries Linked +\[ object file \]$", line) + if m: + state = 'IN_LIBRARIES' + continue + + m = re.match(r"User Base Address Definitions$", line) + if m: + state = 'IN_UBAD' + continue + + m = re.match(r"^([^ ]+) +\[ ([^ ]*) \]$", line) + if m: + if state == 'IN_MODULES': + modules.append({'file': m.group(1), 'name': m.group(2)}) + continue + + if state == 'IN_LIBRARIES': + libraries.append({'library': m.group(1), 'module': m.group(2)}) + continue + + m = re.match(r"^([^ ]+) += +0x([0-9A-Fa-f]{4})$", line) + if state == 'IN_UBAD' and m: + ubads.append({'symbol': m.group(1), 'value': m.group(2)}) + continue + + if area: + areas.append(area) + + + if options.no_gmb: + # generate no$gmp map file + print('; no$gmb format .sym file', file=fout) + print('; Generated automagically by %s' % os.path.basename(sys.argv[0]), file=fout) + for e in areas: + print('; Area: %s' % e['area'], file=fout) + if e['globals']: + e['globals'].sort(key = operator.itemgetter('value')) + for g in e['globals']: + if g['global'][0:3] != 'l__': + if g['value'] > 0x7FFF: + print('00:%04X %s' % (g['value'], g['global']), file=fout) + else: + print('%02X:%04X %s' % (g['value'] // 16384, g['value'], g['global']), file=fout) + else: + # generate rrgb map file + for e in areas: + print('AREA %s' % e['area'], file=fout) + print('\tRADIX %s' % e['radix'], file=fout) + print('\tBASE %04X' % e['base'], file=fout) + print('\tSIZE %04X' % e['size'], file=fout) + print('\tATTRIB %s' % e['attrib'], file=fout) + if e['globals']: + e['globals'].sort(key = operator.itemgetter('value')) + print('\tGLOBALS', file=fout) + for g in e['globals']: + print('\t\t%s\t%04X' % (g['global'], g['value']), file=fout) + + if modules: + print('MODULES', file=fout) + for m in modules: + print('\tFILE %s' % m['file'], file=fout) + if m['name']: + print('\t\tNAME %s' % m['name'], file=fout) + + if libraries: + print('LIBRARIES', file=fout) + for m in libraries: + print('\tLIBRARY %s' % m['library'], file=fout) + print('\t\tMODULE %s' % m['module'], file=fout) + + if ubads: + print('USERBASEDEF', file=fout) + for m in ubads: + print('\t%s = 0x%04X' % (m['symbol'], int(m['value'], 16)), file=fout) + return 0 + +if __name__ == '__main__': + sys.exit(main()) diff --git a/support/scripts/build.mak b/support/scripts/build.mak new file mode 100644 index 0000000..d4f0477 --- /dev/null +++ b/support/scripts/build.mak @@ -0,0 +1,144 @@ +# Makefile to get and build all the parts of GBDK + +CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ + else if [ -x /bin/bash ]; then echo /bin/bash; \ + else echo sh; fi ; fi) + +TOPDIR := $(shell if [ "$$PWD" != "" ]; then echo $$PWD; else pwd; fi) + +BUILD = $(TOPDIR)/build/sdcc +SDCCLIB = $(BUILD) +CVSFLAGS = -z5 +CVS = cvs +SVNFLAGS = +SVN = svn +DIR = . +VER = 2.2.1 +# Used as a branch name. +SHORTVER = 221 + +# Options: +# linux-linux Building on Linux, targeting Linux +# linux-ming32 Building on Linux, targeting mingw32 based win32 +# cygwin-mingw32 Building via cygwin on win32, targeting mingw32 + +COMPILE_MODE = linux-mingw32 +SDCC_OR_GBDK = sdcc + +ROOT_GBDK = :pserver:anonymous@cvs.gbdk.sourceforge.net:/cvsroot/gbdk +ROOT_SDCC = https://sdcc.svn.sourceforge.net/svnroot/sdcc + +ifeq ($(COMPILE_MODE),linux-linux) +# For Linux +SE = +E = +SDCC_ROOT = /usr/lib/$(SDCC_OR_GBDK) +endif + +ifeq ($(COMPILE_MODE),linux-mingw32) +# For mingw32 hosted on Linux +# Tools name prefix +TNP = i386-mingw32- +# Source extension - what the gcc generated files have appended +SE = +# Dest extenstion - what extension we want them to have. +E = .exe +SDCC_ROOT = /$(SDCC_OR_GBDK) +# Set to cross to bypass the detection +CROSS_LIBGC = 1 +endif + +ifeq ($(COMPILE_MODE),cygwin-mingw32) +# For mingw32 on win32 +# Source extension - what the gcc generated files have appended +SE = .exe +# Dest extenstion - what extension we want them to have. +SDCC_ROOT = /$(SDCC_OR_GBDK) +endif + +all: logged_in dist + +clean: + for i in sdcc gbdk-lib gbdk-support/lcc; do make -C $$i clean; done + rm -f *~ + rm -rf $(BUILD) gbdk-lib gbdk-support sdcc logged_in + +update: logged_in + cd $(DIR); svn $(SVNFLAGS) co $(ROOT_SDCC)/branches/sdcc-$(SHORTVER)/sdcc sdcc + cd $(DIR); cvs $(CVSFLAGS) -d$(ROOT_GBDK) co -r sdcc-$(SHORTVER) gbdk-lib + cd $(DIR); cvs $(CVSFLAGS) -d$(ROOT_GBDK) co -r sdcc-$(SHORTVER) gbdk-support + +_sdcc: sdcc-bin sdcc-misc sdcc-lib sdcc-doc + +tidy: + find $(BUILD) -name "CVS" -exec rm -rf \; + find $(BUILD) -name ".svn" -exec rm -rf \; + find $(BUILD)/lib -name "*.asm" -exec rm -rf \; + -$(TNP)strip $(BUILD)/bin/* + +sdcc-bin: sdcc/sdccconf.h + make -C sdcc sdcc-bin CROSS_LIBGC=$(CROSS_LIBGC) + mkdir -p $(BUILD)/bin + for i in \ + sdcc sdcpp link-z80 as-z80 aslink asx8051; \ + do cp sdcc/bin/$$i$(SE) $(BUILD)/bin/$$i$(E); done + +sdcc-misc: sdcc/sdccconf.h + make -C sdcc sdcc-misc CROSS_LIBGC=$(CROSS_LIBGC) + mkdir -p $(BUILD)/bin + for i in \ + sdcdb; \ + do cp sdcc/bin/$$i$(SE) $(BUILD)/bin/$$i$(E); done + cp sdcc/sim/ucsim/s51.src/s51$(E) $(BUILD)/bin + cp sdcc/sim/ucsim/z80.src/sz80$(E) $(BUILD)/bin + cp sdcc/sim/ucsim/avr.src/savr$(E) $(BUILD)/bin + cp sdcc/debugger/mcs51/*.el $(BUILD)/bin + +sdcc-doc: + (cd sdcc; tar cf - doc) | (cd $(BUILD); tar xf -) + cp sdcc/README sdcc/COPYING $(BUILD) + mkdir -p $(BUILD)/sim + for i in COPYING INSTALL README TODO; \ + do cp sdcc/sim/ucsim/$$i $(BUILD)/sim; done + (cd sdcc/sim/ucsim; tar cf - doc) | (cd $(BUILD)/sim; tar xf -) + +sdcc-lib: sdcc-lib-z80 sdcc-lib-gen + mkdir -p $(BUILD)/lib + (cd sdcc/device/lib; tar cf - small large) | (cd $(BUILD)/lib; tar xf -) + (cd sdcc/device; tar cf - examples include) | (cd $(BUILD); tar xf -) + +sdcc-lib-z80: + make -C gbdk-lib/libc SDCCLIB=$(BUILD) PORTS=z80 PLATFORMS=consolez80 + (cd gbdk-lib/build; tar cf - consolez80 z80) | (cd $(BUILD)/lib; tar xf -) + mkdir -p $(BUILD)/include/gbdk-lib + (cd gbdk-lib/include; tar cf - .) | (cd $(BUILD)/include/gbdk-lib; tar xf -) + +sdcc-lib-gen: + make -C sdcc sdcc-device + +lcc: + make -C gbdk-support/lcc SDCCLIB=$(SDCC_ROOT)/ TNP=$(TNP) + cp gbdk-support/lcc/lcc$(SE) $(BUILD)/bin/lcc$(E) + +sdcc/sdccconf.h: sdcc/configure +ifdef TNP + cd sdcc; \ + export CCC=$(TNP)c++; \ + export RANLIB=$(TNP)ranlib; \ + export CC=$(TNP)gcc; \ + ./configure --datarootdir=$(SDCC_ROOT) + echo $$CCC +else + cd sdcc; ./configure --datarootdir=$(SDCC_ROOT) +endif + +dist: _sdcc lcc tidy + +zdist: dist + tar czf gbdk-$(VER).tar.gz gbdk + +logged_in: + cvs -d$(ROOT_GBDK) login + cvs -d$(ROOT_SDCC) login + touch logged_in + make -f build.mak update diff --git a/support/scripts/cinc2h.pl b/support/scripts/cinc2h.pl new file mode 100755 index 0000000..8558135 --- /dev/null +++ b/support/scripts/cinc2h.pl @@ -0,0 +1,1664 @@ +#!/usr/bin/perl -w + +=back + + Copyright (C) 2012-2015, Molnar Karoly <molnarkaroly@users.sf.net> + + This file is part of SDCC. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source distribution. + +================================================================================ + + cinc2h.pl (common-inc2h.pl) + + This program parse the gpasm header (p1xxx.inc) files and creates + from them the SDCC header and device library files. In addition it + needs the gpprocessor.c file also. These is included in the source + package of gputils. Mode of download of the latest source: + + http://gputils.sourceforge.net/#Download + + The program is available on request provide assistance: cinc2h.pl -h + + ------------------------------------------------- + + Steps to add a new target device to SDCC/PIC16: + (Following Raphael Neider <rneider AT web.de>) + + 1. Create the picDEVICE.c and picDEVICE.h from pDEVICE.inc using + ./cinc2h.pl -p 18f4520 -cb -cp -gp "path/to/gputils_source" -o "path/to/output" + + 2. mv picDEVICE.h $SDCC/device/non-free/include/pic16 + 3. mv picDEVICE.c $SDCC/device/non-free/lib/pic16/libdev + 4. either + + (a) adjust $SDCC/device/lib/pic16/libio/*.ignore + if the device does not support ADC, I2C, or USART + --- OR --- + (b) adjust + * SDCC/scripts/pic18fam-h-gen.pl + * SDCC/device/include/pic16/adc.h (if required) + * SDCC/device/include/pic16/usart.h (if required) + * SDCC/device/lib/pic16/libio/*/* (if required) + to add the new device to the appropriate I/O style + and implement new styles (if required). + + Having modified pic18fam-h-gen.pl, you need to run the + script to generate pic18fam.h.gen, which in turn must + then replace your .../include/pic16/pic18fam.h to take + effect; see pic18fam-h-gen.pl for usage information. + 6. edit $SDCC/device/include/pic16/pic18fregs.h + 7. edit $SDCC/device/include/pic16/pic16devices.txt + 8. run cd $SDCC/device/non-free/lib/pic16 && sh update.sh + to regenerate .../libdev/Makefile.am and processors.ac + + The file format of steps 6 and 7 is self explanatory, in most + if not all cases you can copy and paste another device's records + and adjust them to the newly added device. + + ------------------------------------------------- + + Steps to add a new target device to SDCC/PIC14: + + 1. Create the picDEVICE.c and picDEVICE.h from pDEVICE.inc using + ./cinc2h.pl -p 16f1503 -cb -cp -gp "path/to/gputils_source" -o "path/to/output" + + 2. mv picDEVICE.h $SDCC/device/non-free/include/pic14 + 3. mv picDEVICE.c $SDCC/device/non-free/lib/pic14/libdev + 4. add DEVICE to $SDCC/device/non-free/lib/pic14/libdev/devices.txt + (The names of the enhanced devices the "# enhanced cores" line + after follow.) + + 5. edit $SDCC/device/include/pic14/pic14devices.txt + + The file format of step 5 is self explanatory, in most if not all + cases you can copy and paste another device's records and adjust + them to the newly added device. + + $Id: cinc2h.pl 9450 2016-01-09 16:47:43Z molnarkaroly $ +=cut + +use strict; +use warnings; +no if $] >= 5.018, warnings => "experimental::smartmatch"; # perl 5.16 +use 5.12.0; # when (regex) +use File::Path 'make_path'; +use feature 'switch'; # Starting from 5.10.1. +use POSIX qw(strftime); + +use constant FALSE => 0; +use constant TRUE => 1; + +use constant ST_NONE => 0; +use constant ST_REG_ADDR => 1; +use constant ST_REG1_DEF => 2; +use constant ST_REG2_DEF => 3; +use constant ST_RAM_DEF => 4; +use constant ST_CONFIG_DEF => 5; +use constant ST_DEVID_DEF => 6; +use constant ST_IDLOC_DEF => 7; + +use constant DIST_ADDRSIZE => 32; +use constant DIST_BITSIZE => 32; +use constant DIST_DEFSIZE => 32; +use constant DIST_COMSIZE => 32; + +my $PROGRAM = 'cinc2h.pl'; +my $time_str = ''; +my $year = ''; + +my $gputils_path = "$ENV{HOME}/svn_snapshots/gputils/gputils"; +my $gp_header_path = ''; +my $gpprocessor_c = 'gpprocessor.c'; +my $gpproc_path; + +my $name_filter = qr/10l?f\d+[a-z]*|1[26]((c(e|r)?)|hv)\d+[a-z]*|1[268]l?f\d+([a-z]*|[a-z]+\d+[a-z]*)/; +my $header_name_filter = 'p${name_filter}.inc'; + +my $p14_out_path = 'pic14'; +my $p16_out_path = 'pic16'; + +my $mcu; +my $short_mcu_name; +my $is_pic16 = FALSE; +my $conf_size = 4; +my $caddr_size = 4; +my $conf_head = '_'; +my $verbose = 0; + +my $create_bitfields = FALSE; +my $emit_legacy_names = FALSE; +my $no_timestamp = FALSE; + +my $section = '//' . ('=' x 78); +my $btail = 'bits'; +my $btype_t = "${btail}_t"; + + # Here those names to be entered that are defective. + # BAD => 'GOOD' or + # 'BAD' => 'GOOD' + +my %correction_of_names = + ( + OPTION => 'OPTION_REG' + ); + + # At some processors there is such register name, that is different + # from what the other processors in used. This is a replacement table. + +my %register_aliases = + ( + BAUDCTL => 'BAUDCON' + ); + +#----------------------------------------------- + +=back + The structure of one element of the @registers array: + + { + NAME => '', The name of register. + ADDRESS => 0, The address of register. + NEED_PREFIX => 0, Indicates if in front the name of bits necessary an prefix. + BITNAMES => [ The bits of register. + [], The names of 0th bit. + [], + [], + [], + [], + [], + [], + [] The names of 7th bit. + ], + + ... + + [] + + BITFIELDS => { + 'ADCS' => { This the descriptor of the ADCS field. + ADDRESSES => [], Physical start addresses of bits of the field. + INDEXES => [], Bit indexes of bits of the field (ADCS2 -> '2'). + WIDTH => 0 So many bit the width of the bit-field. + }, + + 'ANS' => {} + + ... + + } + } +=cut + +my @registers = (); + +#----------------------------------------------- + + # References of registers according to name of registers. +my %reg_refs_by_names = (); + + # References of registers according to name of bits of registers. + # With help of recognizable the repetitive bit names. +my %reg_refs_by_bits = (); + +#----------------------------------------------- + +=back + The structure of one element of the @configs array: + + { + NAME => '', The name of config. + ADDRESS => 0, The address of config. + OPTIONS => [ The options of config. + { + NAME => '', + VALUE => 0, + EXPLANATION => '' + }, + + ... + + { + } + ] + } +=cut + +my @configs = (); + +#----------------------------------------------- + +my %conf_names = (); + +my @devids = (); +my @idlocs = (); + +my $header_name; +my $device_name; +my $out_path = './'; +my $out_handler; + +my $device_registers = ''; +my $full_bitdefs = ''; +my $legacy_names = ''; + +################################################################################ +################################################################################ +################################################################################ +################################################################################ + +sub basename($) + { + return ($_[0] =~ /([^\/]+)$/) ? $1 : ''; + } + +#------------------------------------------------------------------------------- + +sub param_exist($$) + { + die "This option \"$_[0]\" requires a parameter.\n" if ($_[1] > $#ARGV); + } + +#------------------------------------------------------------------------------- + +sub str2int($) + { + my $Str = $_[0]; + + return hex($1) if ($Str =~ /^H'([[:xdigit:]]+)'$/io); + return hex($1) if ($Str =~ /^0x([[:xdigit:]]+)$/io); + return int($Str) if ($Str =~ /^-?\d+$/o); + + die "str2int(): This string not integer: \"$Str\""; + } + +#------------------------------------------------------------------------------- + +sub align($$) + { + my $text = $_[0]; + my $al = $_[1] - length($text); + + # One space will surely becomes behind it. + $al = 1 if ($al < 1); + + return ($text . ' ' x $al); + } + +#------------------------------------------------------------------------------- + +sub Log + { + return if (pop(@_) > $verbose); + foreach (@_) { print $_; } + print "\n"; + } + +#------------------------------------------------------------------------------- + +sub Out + { + foreach (@_) { print $out_handler $_; } + } + +#------------------------------------------------------------------------------- + +sub Outl + { + Out(@_); + print $out_handler "\n"; + } + +#------------------------------------------------------------------------------- + +sub versionCompare($$) + { + my ($Str1, $Str2) = @_; + + if ((${$Str1} =~ /^\d/o) && (${$Str2} =~ /^\d/o)) + { + # $Str1 number and $Str2 number + return (int(${$Str1}) <=> int(${$Str2})); + } + + return (${$Str1} cmp ${$Str2}); + } + +#------------------------------------------------------------------------------- + +sub versionSort($$) + { + my @a_s = ($_[0] =~ /(\d+|\D+)/go); + my @b_s = ($_[1] =~ /(\d+|\D+)/go); + my ($i, $k, $end, $ret); + + $i = scalar(@a_s); + $k = scalar(@b_s); + + if ($i < $k) + { + $end = $i; + $ret = -1; + } + elsif ($i == $k) + { + $end = $i; + $ret = 0; + } + else + { + $end = $k; + $ret = 1; + } + + for ($i = 0; $i < $end; ++$i) + { + $k = versionCompare(\$a_s[$i], \$b_s[$i]); + + return $k if ($k != 0); + } + + return $ret; + } + +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@ @@@@@@@@@@@@ +#@@@@@@@@@@@@ Load all definitions, which will find in the header. @@@@@@@@@@@ +#@@@@@@@@@@@@@ @@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + # If the $Word included in a list then it will replace. + +sub correct_name($) + { + my $Word = $_[0]; + my $corr = $correction_of_names{$Word}; + + if (defined($corr)) + { + Log("$Word --> $corr ($mcu)", 7); + return $corr; + } + + return $Word; + } + +#------------------------------------------------------------------------------- + + # Adds to the list the $Name register. + +sub new_register($$) + { + my ($Name, $Address) = @_; + + if (defined($reg_refs_by_names{$Name})) + { + die "The \"$Name\" register has been included on the list. ($mcu)\n"; + } + + my $reg = { + NAME => correct_name($Name), + ADDRESS => $Address, + NEED_PREFIX => FALSE, + BITNAMES => undef, + BITFIELDS => undef + }; + + push(@registers, $reg); + $reg_refs_by_names{$Name} = $reg; + return $reg; + } + +#------------------------------------------------------------------------------- + + # Cuts the unnecessary prefix or suffix. + +sub bit_filtration($$) + { + my ($Regname, $Bits) = @_; + + for (my $i = 0; $i < 8; ++$i) + { + my $array = $Bits->[$i]; + + next if (! defined($array)); + + my $changed = 0; + my $new_bits = []; + + foreach (@{$array}) + { + # $Regname : 'CMCON' + # $_ : 'C1OUT_CMCON' + # Operation: 'C1OUT_CMCON' --> 'C1OUT' + # + + $changed += ($_ =~ s/^${Regname}_|_${Regname}$//); + $changed += ($_ =~ s/^(\d+)$/bit_$1/o); + push(@{$new_bits}, $_); + } + + $Bits->[$i] = $new_bits if ($changed); + } + } + +#------------------------------------------------------------------------------- + + # Tries the $Bit insert into a bitfield of the $Register. + +sub bitfield_preparation($$$) + { + my ($Register, $Bit, $Address) = @_; + my $fields = $Register->{BITFIELDS}; + + $fields = $Register->{BITFIELDS} = {} if (! defined($fields)); + + Log("BIT: $Bit", 7); + + if ($Bit =~ /(\d+)$/op) + { + my $flname = ${^PREMATCH}; + my $flidx = $1; + + if (! defined($fields->{$flname})) + { + # Creates a new field. + + Log("BIT first : $flname\[$Address\] = '$flidx'", 7); + $fields->{$flname} = { + ADDRESSES => [ $Address ], + INDEXES => [], + WIDTH => 0 + }; + } + else + { + # The bit inserts into an existing field. + + Log("BIT remaining: $flname\[$Address\] = '$flidx'", 7); + push(@{$fields->{$flname}->{ADDRESSES}}, $Address); + } + + $fields->{$flname}->{INDEXES}->[$Address] = $flidx; + } + } + +#------------------------------------------------------------------------------- + + # If can, classifies the $Bits into a field. + +sub bitfield_registration($$) + { + my ($Register, $Bits) = @_; + + for (my $i = 0; $i < 8; ++$i) + { + my $array = $Bits->[$i]; + + next if (! defined($array)); + + Log("bitfield_registration() -- $i", 8); + foreach (@{$array}) + { + bitfield_preparation($Register, $_, $i); + } + } + } + +#------------------------------------------------------------------------------- + + # In the $Queue are in register's names. + # Assigns to these the contents of $Bits. + +sub add_reg_bits($$) + { + my ($Queue, $Bits) = @_; + + return if ((scalar(@{$Queue}) == 0) || (scalar(@{$Bits}) == 0)); + + foreach (@{$Queue}) + { + next if ($_ eq 'and'); # This here easiest to filter out. + + my $name = correct_name($_); + my $reg = $reg_refs_by_names{$name}; + + if (! defined($reg)) + { + Log("The $name register is not directly be reached or does not exist. ($mcu)", 2); + $reg = new_register($name, -1); + } + + bit_filtration($name, $Bits); + bitfield_registration($reg, $Bits); + $reg->{BITNAMES} = [ @{$Bits} ]; + } + + @{$Queue} = (); + @{$Bits} = (); + } + +#------------------------------------------------------------------------------- + + # Finds the $Name in the $Bits. + +sub find_bit($$) + { + my ($Bits, $Name) = @_; + + return FALSE if (! defined($Bits)); + + for (my $i = 0; $i < 8; ++$i) + { + my $array = $Bits->[$i]; + + next if (! defined($array)); + + foreach (@{$array}) + { + return TRUE if ($_ eq $Name); + } + } + + return FALSE; + } + +#------------------------------------------------------------------------------- + + # Adds to the list the $Name config byte/word. + +sub add_conf_word($$) + { + my ($Name, $Address) = @_; + + my $conf = $conf_names{$Name}; + + if (defined($conf)) + { + # The $Name config byte/word still unknown, but there are related words. + + # If the $Name config byte/word are defined later than + # the associated bits, then this section is executed. + # + + $conf->{ADDRESS} = $Address if ($conf->{ADDRESS} < 0 && $Address >= 0); + } + else + { + # The $Name config byte/word still unknown and there are no related words. + + $conf = { + NAME => $Name, + ADDRESS => $Address, + OPTIONS => [] + }; + + push(@configs, $conf); + $conf_names{$Name} = $conf; + } + } + +#------------------------------------------------------------------------------- + +sub add_conf_options($$) + { + my ($Queue, $Options) = @_; + + return if ((scalar(@{$Queue}) == 0) || (scalar(@{$Options}) == 0)); + + foreach (@{$Queue}) + { + my $conf = $conf_names{$_}; + + die "This config unknown: \"$_\" ($mcu)\n" if (! defined($conf)); + + $conf->{OPTIONS} = [ @{$Options} ]; + } + + @{$Queue} = (); + @{$Options} = (); + } + +#------------------------------------------------------------------------------- + + # Reads the entire content of the $File. + +sub read_content_from_header($) + { + my $File = $_[0]; + my ($state, $name, $addr); + my @queue; + my @array; + + open(IN, '<', $File) || die "Can not open the $File header file!\n"; + + $state = ST_NONE; + @queue = (); + @array = (); + + foreach (grep(! /^\s*$/o, <IN>)) + { + chomp; + s/\r$//o; + s/^\s*|\s*$//go; + + my $line = $_; + + Log("#### \"$line\"", 8); + + given ($state) + { + when (ST_NONE) + { + Log(":::: ST_NONE ($line) ($mcu)", 4); + + $state = ST_REG_ADDR if ($line =~ /^;-+\s*Register\s+Files\s*-+$/io); + } + + when (ST_REG_ADDR) + { + Log(":::: ST_REG_ADDR ($line) ($mcu)", 4); + + if ($line =~ /^;-+\s*(.+)Bits\s*-+$/io) + { + # ;----- STKPTR Bits -------------------------------------------------------- + # ;----- UIR/UIE Bits ------------------------------------------------------- + # ;----- TXSTA, TXSTA1 and TXSTA2 Bits -------------------------------------- + # + + # Therefore need the queue because more register names can be on one line. + + @queue = ($1 =~ /([^\s,\/]+)/go); + $state = ST_REG1_DEF; + } + elsif ($line =~ /^(\w+)\s+EQU\s+([\w']+)$/io) #' + { + # PORTC EQU H'0007' + # + + new_register($1, str2int($2)); + } + } # when (ST_REG_ADDR) + + when (ST_REG1_DEF) + { + Log(":::: ST_REG1_DEF ($line) ($mcu)", 4); + + if ($line =~ /^;\s*I\/O\s+Pin\s+Name\s+Definitions?$/io) + { + # ; I/O Pin Name Definitions + # + + Log("1 +++ add_reg_bits()", 6); + add_reg_bits(\@queue, \@array); + $state = ST_REG2_DEF; + } + elsif ($line =~ /^;\s*RAM\s+Definitions?$/io) + { + # ; RAM Definition + # ; RAM Definitions + # + + Log("2 +++ add_reg_bits()", 6); + add_reg_bits(\@queue, \@array); + $state = ST_RAM_DEF; + } + elsif ($line =~ /^;-+\s*(.+)Bits\s*-+$/io) + { + my $name = $1; + + Log("3 +++ add_reg_bits()", 6); + add_reg_bits(\@queue, \@array); + + # Therefore need the queue because more register names can be on one line. + + @queue = ($name =~ /([^\s,\/]+)/go); + } + elsif ($line =~ /^(\w+)\s+EQU\s+([\w']+)$/io) #' + { + # VR2 EQU H'0002' + # + + push(@{$array[str2int($2)]}, $1); + } + } # when (ST_REG1_DEF) + + when (ST_REG2_DEF) + { + Log(":::: ST_REG2_DEF ($line) ($mcu)", 4); + + if ($line =~ /^;\s*RAM\s+Definitions?$/io) + { + # ; RAM Definition + # ; RAM Definitions + # + + Log("4 +++ add_reg_bits()", 6); + add_reg_bits(\@queue, \@array); + $state = ST_RAM_DEF; + } + elsif ($line =~ /^;-+\s*([^-]+)\s*-+$/io) + { + my $name = $1; + + Log("5 +++ add_reg_bits()", 6); + add_reg_bits(\@queue, \@array); + + # Therefore need the queue because more register names can be on one line. + + @queue = ($name =~ /([^\s,\/]+)/go); + } + elsif ($line =~ /^(\w+)\s+EQU\s+([\w']+)$/io) #' + { + # RE3 EQU 3 + # + + push(@{$array[int($2)]}, $1); + } + } # when (ST_REG2_DEF) + + when (ST_RAM_DEF) + { + Log(":::: ST_RAM_DEF ($line) ($mcu)", 4); + + $state = ST_CONFIG_DEF if ($line =~ /^;\s*Configuration\s+Bits$/io); + } + + when (ST_CONFIG_DEF) + { + Log(":::: ST_CONFIG_DEF ($line) ($mcu)", 4); + + if ($line =~ /^_(DEVID\d*)\s+EQU\s+([\w']+)$/io) #' + { + add_conf_options(\@queue, \@array); + + Log("DEVID: $line", 6); + push(@devids, { NAME => $1, ADDRESS => str2int($2) }); + $state = ST_DEVID_DEF; + } + elsif ($line =~ /^_(IDLOC\d*)\s+EQU\s+([\w']+)$/io) #' + { + add_conf_options(\@queue, \@array); + + Log("IDLOC: $line", 6); + push(@idlocs, { NAME => $1, ADDRESS => str2int($2) }); + $state = ST_IDLOC_DEF; + } + elsif ($line =~ /^_(CONFIG\d*\w*)\s+EQU\s+([\w']+)$/io) #' + { + Log("CONFIG: $line", 6); + add_conf_word(uc($1), str2int($2)); + } + elsif ($line =~ /^;\s*-+\s*(Config\d*\w*)\s+Options\s*-+$/io) + { + my $name = uc($1); + + Log("1. Config: $line", 6); + add_conf_options(\@queue, \@array); + add_conf_word($name, -1); + push(@queue, $name); + } + elsif ($line =~ /^;\s*-+\s*Config\s+Word(\d+)\s+Options\s*-+$/io || + $line =~ /^;\s*Configuration\s+Byte\s+(\d+[HL])\s+Options$/io) + { + my $name = "CONFIG$1"; + + Log("2. Config: $line", 6); + add_conf_options(\@queue, \@array); + add_conf_word($name, 0); + push(@queue, $name); + } + elsif ($line =~ /^(\w+)\s+EQU\s+([\w']+)(.+)?$/io) #' + { + my ($name, $value) = ($1, str2int($2)); + my $expl = ''; + + if (defined($3)) + { + $expl = $3; + $expl =~ s/\s*;\s*//; + } + + Log("Config option: $line", 6); + push(@array, { NAME => $name, VALUE => $value, EXPLANATION => $expl }); + } + } # when (ST_CONFIG_DEF) + + when (ST_DEVID_DEF) + { + Log(":::: ST_DEVID_DEF ($line) ($mcu)", 4); + + if ($line =~ /^_(IDLOC\d*)\s+EQU\s+([\w']+)$/io) #' + { + Log("IDLOC: $line", 6); + push(@idlocs, { NAME => $1, ADDRESS => str2int($2) }); + $state = ST_IDLOC_DEF; + } + elsif ($line =~ /^_(DEVID\d*)\s+EQU\s+([\w']+)$/io) #' + { + Log("DEVID: $line", 6); + push(@devids, { NAME => $1, ADDRESS => str2int($2) }); + } + } + + when (ST_IDLOC_DEF) + { + Log(":::: ST_IDLOC_DEF ($line) ($mcu)", 4); + + if ($line =~ /^_(IDLOC\d*)\s+EQU\s+([\w']+)$/io) #' + { + Log("IDLOC: $line", 6); + push(@idlocs, { NAME => $1, ADDRESS => str2int($2) }); + } + } + } # given ($state) + } # foreach (grep(! /^\s*$/o, <IN>)) + + add_conf_options(\@queue, \@array); + + close(IN); + + return if (! scalar(@registers)); + + # Within the array sorts by address the registers. + + @registers = sort {$a->{ADDRESS} <=> $b->{ADDRESS}} @registers; + } + +#------------------------------------------------------------------------------- + + # Reads the bounds of config area from the gpprocesor.c file. + +sub extract_config_area($$) + { + my ($Conf_start, $Conf_end) = @_; + + open(LIB, '<', $gpproc_path) || die "extract_config_area(): Can not open. -> \"$gpproc_path\"\n"; + + # static struct px pics[] = { + # { PROC_CLASS_PIC12E , "__12F529T39A" , { "pic12f529t39a" , "p12f529t39a" , "12f529t39a" }, 0xE529, 3, 8, 0x00E0, { 0x07, 0x0F }, 0x06F, { -1, -1 }, 0x00FF, 0x0005FF, 0x000600, { -1, -1 }, { 0x000640, 0x000643 }, { 0x000FFF, 0x000FFF }, { 0x000600, 0x00063F }, 0x0FF0, "p12f529t39a.inc" , "12f529t39a_g.lkr" , 0 }, + # { PROC_CLASS_PIC14E , "__16LF1517" , { "pic16lf1517" , "p16lf1517" , "16lf1517" }, 0xA517, 4, 32, 0x0F80, { 0x70, 0x7F }, -1, { 0x2000, 0x21EF }, 0x0FFF, 0x001FFF, 0x002000, { -1, -1 }, { 0x008000, 0x008003 }, { 0x008007, 0x008008 }, { -1, -1 }, 0x3F80, "p16lf1517.inc" , "16lf1517_g.lkr" , 0 }, + + my $in_table = FALSE; + + while (<LIB>) + { + chomp; + + if (! $in_table) + { + $in_table = TRUE if (/^\s*static\s+struct\s+px\s+pics\[\s*\]\s*=\s*\{\s*$/io); + } + elsif (/\{\s*PROC_CLASS_\w+\s*,\s*"\w+"\s*,\s*\{\s*"\w+"\s*,\s*"\w+"\s*,\s*"(\w+)"\s*}\s*,\s*[\w-]+\s*,\s*[\w-]+\s*,\s*[\w-]+\s*,\s*[\w-]+\s*,\s*\{\s*\S+\s*,\s*\S+\s*\}\s*,\s*\S+\s*,\s*\{\s*\S+\s*,\s*\S+\s*\}\s*,\s*\S+\s*,\s*\S+\s*,\s*\S+\s*,\s*\{\s*\S+\s*,\s*\S+\s*\}\s*,\s*{\s*\S+\s*,\s*\S+\s*\}\s*,\s*{\s*(\S+)\s*,\s*(\S+)\s*\}\s*,\s*{\s*\S+\s*,\s*\S+\s*\}\s*,\s*\w+\s*,\s*\"?[\.\w]+\"?\s*,\s*\"?[\.\w]+\"?\s*,\s*\d+\s*\}/iop) + { + my ($name, $c_start, $c_end) = ($1, $2, $3); + + if ($short_mcu_name eq $name) + { + ${$Conf_start} = str2int($c_start); + ${$Conf_end} = str2int($c_end); + last; + } + } + else + { + last; + } + } + + close(LIB); + } + +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@ Prints the register definitions. @@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + # A bit may be more than one name. This procedure counts that how + # many the most of name. + +sub max_count_of_names_of_bit($) + { + my $Bits = $_[0]; + my $num = 0; + + for (my $i = 0; $i < 8; ++$i) + { + my $array = $Bits->[$i]; + + next if (! defined($array)); + + my $l = scalar(@{$array}); + + $num = $l if ($num < $l); + } + + return $num; + } + +#------------------------------------------------------------------------------- + + # There are certain bits that have the same name in other registers + # also. In this case, in the definitions of bit names need apply + # a prefix, that allows the bits to distinguish from each other. + # This function this need is recorded in the affected registers. + +sub set_bit_prefix() + { + foreach my $register (sort {versionSort($a->{NAME}, $b->{NAME})} @registers) + { + my $bits = $register->{BITNAMES}; + + next if (! defined($bits)); + + for (my $i = 0; $i < 8; ++$i) + { + my $array = $bits->[$i]; + + next if (! defined($array)); + + foreach (@{$array}) + { + my $reg = $reg_refs_by_bits{$_}; + + if (defined($reg)) + { + Log("The $_ bit of the $register->{NAME} register is occupied in $reg->{NAME} register. ($mcu)", 3); + $register->{NEED_PREFIX} = TRUE; + } + else + { + $reg_refs_by_bits{$_} = $register; + } + } + } + } + } + +#------------------------------------------------------------------------------- + + # Prints the $Index numbered $Bits of a register. + +sub print_bits($$$) + { + my ($Bits, $Index, $Align) = @_; + my $al = ' ' x $Align; + + for (my $i = 0; $i < 8; ++$i) + { + my $array = $Bits->[$i]; + my $str; + my $bit = (defined($array) && defined($str = $array->[$Index])) ? " $str" : ''; + + Outl(align("${al}unsigned$bit", DIST_BITSIZE), ': 1;'); + } + } + +#------------------------------------------------------------------------------- + + # Prints all bits of a register. + +sub print_local_bitdefs($) + { + my $Register = $_[0]; + my $bits = $Register->{BITNAMES}; + my $head = ($Register->{NEED_PREFIX}) ? "$Register->{NAME}_" : ''; + + for (my $i = 0; $i < 8; ++$i) + { + my $array = $bits->[$i]; + + next if (! defined($array)); + + foreach (@{$array}) + { + Outl(align("#define _${head}$_", DIST_DEFSIZE), sprintf('0x%02X', 1 << $i)); + } + } + } + +#------------------------------------------------------------------------------- + + # Deletes the false or fragmentary bitfields. + +sub bitfield_filtration($) + { + my ($bits, $fields) = ($_[0]->{BITNAMES}, $_[0]->{BITFIELDS}); + + # Does not have a bitfields. + + return if (! defined($fields)); + + foreach my $field_name (keys(%{$fields})) + { + my ($first_addr, $last_addr, $last_index); + my $gr = $fields->{$field_name}; + + Log("bitfield_filtration() -- $field_name", 8); + + if (find_bit($bits, $field_name)) + { + # The $field_name already exists in the $bits array. + # Name conflict. + + delete($fields->{$field_name}); + next; + } + + @{$gr->{ADDRESSES}} = sort {$a <=> $b} @{$gr->{ADDRESSES}}; + + my ($addresses, $indexes) = ($gr->{ADDRESSES}, $gr->{INDEXES}); + + $first_addr = $addresses->[0]; + + if ((scalar(@{$addresses}) < 2) || ($indexes->[$first_addr] != 0)) + { + # This is not field, for only one member of there is. The other + # possibility is that the index of the first member is not zero. + + delete($fields->{$field_name}); + next; + } + + $last_addr = -1; + $last_index = -1; + + foreach (@{$addresses}) + { + my $idx = $indexes->[$_]; + + if ($last_addr >= 0) + { + if ((($last_addr + 1) != $_) || (($last_index + 1) != $idx)) + { + # This bitfield is fragmented (not uniform). + + $last_addr = -1; + last; + } + } + + $last_addr = $_; + $last_index = $idx; + } + + # This is the width of the bitfield. + + my $width = $last_addr - $first_addr + 1; + + if (($width > 0) && ($width < 8)) + { + $gr->{WIDTH} = $width; + } + else + { + delete($fields->{$field_name}); + } + } # foreach my $field_name (keys(%{$fields})) + } + +#------------------------------------------------------------------------------- + +sub print_bitfield($$$) + { + my ($Name, $Group, $Align) = @_; + my ($addr, $width) = ($Group->{ADDRESSES}->[0], $Group->{WIDTH}); + my $al = ' ' x $Align; + + Outl(align("${al}unsigned", DIST_BITSIZE), ": $addr;") if ($addr > 0); + Outl(align("${al}unsigned $Name", DIST_BITSIZE), ": $width;"); + $width = 8 - ($addr + $width); + Outl(align("${al}unsigned", DIST_BITSIZE), ": $width;") if ($width > 0); + } + +#------------------------------------------------------------------------------- + + # Prints all bits of all registers. + +sub print_all_registers() + { + my $fields; + my @field_names; + my ($bit_struct_num, $field_struct_num, $all_struct_num); + my ($alias, $i, $r, $text, $type, $v); + + $v = @registers; + for ($r = 0; $r < $v;) + { + my $reg = $registers[$r]; + ++$r; + + my ($name, $addr, $bits) = ($reg->{NAME}, $reg->{ADDRESS}, $reg->{BITNAMES}); + + if ($addr >= 0) + { + bitfield_filtration($reg) if ($create_bitfields); + + $text = sprintf("__at(0x%04X)", $addr); + $device_registers .= "$text __sfr $name;\n"; + + $alias = $register_aliases{$name}; + $alias = undef if (defined($alias) && defined($reg_refs_by_names{$alias})); + + if (defined($bits) && (scalar(@{$bits}) > 0)) + { + $type = "__$name$btype_t"; + Outl("\n$section\n//", (' ' x 8), "$name Bits\n\nextern $text __sfr $name;"); + Outl("\n#define $alias $name") if (defined($alias)); + + $bit_struct_num = max_count_of_names_of_bit($bits); + + if ($create_bitfields) + { + $fields = $reg->{BITFIELDS}; + @field_names = sort {$fields->{$a}->{ADDRESSES}->[0] <=> $fields->{$b}->{ADDRESSES}->[0]} keys(%{$fields}); + $field_struct_num = @field_names; + $all_struct_num = $bit_struct_num + $field_struct_num - 1; + } + else + { + $all_struct_num = $bit_struct_num - 1; + } + + if ($all_struct_num > 0) + { + Outl("\ntypedef union\n {"); + + for ($i = 0; $i < $bit_struct_num; ++$i) + { + Outl(" struct\n {"); + print_bits($bits, $i, 4); + Outl(' };'); + Outl() if ($all_struct_num); + --$all_struct_num; + } + + if ($create_bitfields) + { + for ($i = 0; $i < $field_struct_num; ++$i) + { + my $flname = $field_names[$i]; + + Outl(" struct\n {"); + print_bitfield($flname, $fields->{$flname}, 4); + Outl(' };'); + Outl() if ($all_struct_num); + --$all_struct_num; + } + } + } + else + { + Outl("\ntypedef struct\n {"); + print_bits($bits, 0, 2); + } + + Outl(" } $type;"); + Outl("\nextern $text volatile $type $name$btail;"); + Outl("\n#define $alias$btail $name$btail") if (defined($alias)); + Outl(); + print_local_bitdefs($reg); + Outl("\n$section\n"); + + $device_registers .= "$text volatile $type $name$btail;\n"; + } # if (defined($bits) && (scalar(@{$bits}) > 0)) + else + { + Outl("extern $text __sfr $name;"); + Outl("#define $alias $name") if (defined($alias)); + } + + $device_registers .= "\n" if ($r < $v); + } # if ($addr >= 0) + elsif (defined($bits) && (scalar(@{$bits}) > 0)) + { + # This is a register which can not be achieved directly, but the bits has name. + + Outl("\n$section\n//", (' ' x 8), "$name Bits\n"); + print_local_bitdefs($reg); + Outl("\n$section\n"); + } + } # for ($r = 0; $r < $v;) + } + +#------------------------------------------------------------------------------- + +sub print_configuration_words() + { + if (! scalar(@configs)) + { + # PIC18FxxJ + + my ($start, $end) = (-1, -1); + + extract_config_area(\$start, \$end); + return if (($start < 0) || ($end < 0)); + + Outl("\n$section\n//\n//", (' ' x 8), "Configuration Addresses\n//\n$section\n"); + + my $i = 0; + while ($start <= $end) + { + my $n = int($i / 2) + 1; + my $h = ($i & 1) ? 'H' : 'L'; + + Out(align("#define ${conf_head}CONFIG$n$h", DIST_BITSIZE)); + Outl(sprintf("0x%0${caddr_size}X", $start)); + ++$i; + ++$start; + } + + Outl("\n$section\n"); + return; + } + + Outl("\n$section\n//\n//", (' ' x 8), "Configuration Bits\n//\n$section\n"); + + foreach (@configs) + { + Out(align("#define $conf_head$_->{NAME}", DIST_BITSIZE)); + Outl(sprintf("0x%0${caddr_size}X", $_->{ADDRESS})); + } + + foreach (@configs) + { + next if (! @{$_->{OPTIONS}}); + + Outl("\n//", ('-' x 29), " $_->{NAME} Options ", ('-' x 31), "\n"); + + foreach (@{$_->{OPTIONS}}) + { + my $expl = $_->{EXPLANATION}; + + # Improve a spelling error: On the end of a sentence a point must be. + $expl .= '.' if (($expl ne '') && ($expl !~ /\.$/o)); + + Out(align("#define $_->{NAME}", DIST_BITSIZE)); + Out(align(sprintf("0x%0${conf_size}X", $_->{VALUE}), 8)); + Out("// $expl") if (defined($expl) && ($expl ne '')); + Outl(); + } + } + + Outl("\n$section\n"); + } + +#------------------------------------------------------------------------------- + +sub print_devids_and_idlocs() + { + foreach (\@devids, \@idlocs) + { + if (scalar(@{$_}) > 0) + { + foreach (@{$_}) + { + Out(align("#define $conf_head$_->{NAME}", DIST_BITSIZE)); + Outl(sprintf("0x%0${caddr_size}X", $_->{ADDRESS})); + } + + Outl(); + } + } + } + +#------------------------------------------------------------------------------- + +sub print_license($) + { + print $out_handler <<EOT +/* + * This $_[0] of the $mcu MCU. + * + * This file is part of the GNU PIC library for SDCC, originally + * created by Molnar Karoly <molnarkaroly\@users.sf.net> $year. + * + * This file is generated automatically by the $PROGRAM${time_str}. + * + * SDCC is licensed under the GNU Public license (GPL) v2. Note that + * this license covers the code to the compiler and other executables, + * but explicitly does not cover any code or objects generated by sdcc. + * + * For pic device libraries and header files which are derived from + * Microchip header (.inc) and linker script (.lkr) files Microchip + * requires that "The header files should state that they are only to be + * used with authentic Microchip devices" which makes them incompatible + * with the GPL. Pic device libraries and header files are located at + * non-free/lib and non-free/include directories respectively. + * Sdcc should be run with the --use-non-free command line option in + * order to include non-free header files and libraries. + * + * See http://sdcc.sourceforge.net/ for the latest information on sdcc. + */ + +EOT +; + } + +#------------------------------------------------------------------------------- + + # This procedure generates the pic14-specific information. + +sub make_pic14_dependent_defs() + { + foreach (sort {versionSort($a->{NAME}, $b->{NAME})} @registers) + { + my ($name, $bits) = ($_->{NAME}, $_->{BITNAMES}); + my $prefix = "$name$btail"; + + if ($emit_legacy_names) + { + $legacy_names .= align("#define ${name}_$btail", DIST_DEFSIZE); + $legacy_names .= "$prefix\n"; + } + + next if ($_->{NEED_PREFIX} || ! defined($bits)); + + for (my $i = 0; $i < 8; ++$i) + { + my $array = $bits->[$i]; + + next if (! defined($array)); + + my $shadow = (scalar(@{$array}) > 1) ? ", shadows bit in $prefix" : ''; + + foreach (@{$array}) + { + $full_bitdefs .= align("#define $_", DIST_DEFSIZE); + $full_bitdefs .= align("$prefix.$_", DIST_COMSIZE); + $full_bitdefs .= "// bit $i$shadow\n"; + } + } + + $full_bitdefs .= "\n"; + } + + $legacy_names .= "\n"; + } + +#------------------------------------------------------------------------------- + + # Prints all informations to the header file. + +sub print_to_header_file() + { + my ($text, $name, $address, $str); + + print_license('declarations'); + Outl("#ifndef __${mcu}_H__\n#define __${mcu}_H__\n\n$section"); + + if (! $is_pic16) + { + $text = '#ifndef NO_ADDR_DEFINES'; + + Outl("//\n//\tRegister Addresses\n//\n$section\n\n$text\n"); + + foreach (sort { $a->{ADDRESS} <=> $b->{ADDRESS} } @registers) + { + ($name, $address) = ($_->{NAME}, $_->{ADDRESS}); + next if ($address < 0); + + $str = sprintf('0x%04X', $address); + Outl(align("#define ${name}_ADDR", DIST_ADDRSIZE), $str); + } + + Outl("\n#endif // $text"); + } + + Outl("\n$section\n//\n//\tRegister Definitions\n//\n$section\n"); + set_bit_prefix(); + print_all_registers(); + print_configuration_words(); + print_devids_and_idlocs(); + + if (! $is_pic16) + { + make_pic14_dependent_defs(); + Outl("$section\n"); + + if ($full_bitdefs ne '') + { + $text = '#ifndef NO_BIT_DEFINES'; + Outl("$text\n\n", $full_bitdefs, "#endif // $text\n"); + } + + if ($emit_legacy_names) + { + $text = '#ifndef NO_LEGACY_NAMES'; + Outl("$text\n\n", $legacy_names, "#endif // $text\n"); + } + } + + Outl("#endif // #ifndef __${mcu}_H__"); + } + +#------------------------------------------------------------------------------- + + # Prints name of all registers to the device file. + +sub print_to_device_file() + { + print_license('definitions'); + Outl("#include <$header_name>\n\n$section\n"); + Out($device_registers) if ($device_registers ne ''); + } + +#------------------------------------------------------------------------------- + +sub usage() + { + print <<EOT +Usage: $PROGRAM [options] + + Options are: + + -gp <path> or --gputils-path <path> + + The program on this path looks for the gputils source package. + + -I <path> or --include <path> + + The program on this path looks for the headers (inc files). If this + not specified, then the "header" directory in the local repository + will be the default. + + -p <p12f1822> or --processor <p12f1822> + + The name of MCU. The prefix of name can be: 'p', 'pic' or nothing + + -o <path> or --out-path <path> + + Here to writes the output files. (default: "./") + Attention! The program overwrites the existing files without asking. + + -v <level> or --verbose <level> + + It provides information on from the own operation. + Possible value of the level between 0 and 10. (default: 0) + + -cb or --create-bitfields + + Create bit fields. In some register, can be found such bits which + belong together. For example: CVR0, CVR1, CVR2, CVR3 + These may be useful, to merge during a common field name: CVR + The compiler helps handle these bit fields. (default: no) + + -e or --emit-legacy-names + + Creates the legacy names also. (default: no) + + -nt or --no-timestamp + + There will be no timestamp in the header and device files. (default: yes) + + -h or --help + + This text. + + For example: $PROGRAM -p 12f1840 -cb +EOT +; + } + +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@@@@@@@ The main program. @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +$PROGRAM = basename($0); +$gp_header_path = ''; +$mcu = ''; + +for (my $i = 0; $i < scalar(@ARGV); ) + { + my $opt = $ARGV[$i++]; + + given ($opt) + { + when (/^-(gp|-gputils-path)$/o) + { + param_exist($opt, $i); + $gputils_path = $ARGV[$i++]; + } + + when (/^-(I|-include)$/o) + { + param_exist($opt, $i); + $gp_header_path = $ARGV[$i++]; + } + + when (/^-(p|-processor)$/o) + { + param_exist($opt, $i); + $mcu = $ARGV[$i++]; + } + + when (/^-(o|-out-path)$/o) + { + param_exist($opt, $i); + $out_path = $ARGV[$i++]; + } + + when (/^-(v|-verbose)$/o) + { + param_exist($opt, $i); + $verbose = int($ARGV[$i++]); + $verbose = 0 if (! defined($verbose) || ($verbose < 0)); + $verbose = 10 if ($verbose > 10); + } + + when (/^-(cb|-create-bitfields)$/o) + { + $create_bitfields = TRUE; + } + + when (/^-(e|-emit-legacy-names)$/o) + { + $emit_legacy_names = TRUE; + } + + when (/^-(nt|-no-timestamp)$/o) + { + $no_timestamp = TRUE; + } + + when (/^-(h|-help)$/o) + { + usage(); + exit(0); + } # when ('-h' || '--help') + } # given ($opt) + } + +die "Miss the name of MCU!\n" if ($mcu eq ''); +die "This name is wrong: \"$mcu\"\n" if ($mcu !~ /^(p(ic)?)?$name_filter$/io); + +die "This directory - $gputils_path - not exist!" if (! -d $gputils_path); + +$gp_header_path = "$gputils_path/header" if ($gp_header_path eq ''); # The default value. +$gpproc_path = "$gputils_path/libgputils/$gpprocessor_c"; + +$mcu = lc($mcu); +$mcu =~ s/^p(ic)?//o; + +if ($mcu =~ /^18/) + { + $is_pic16 = TRUE; + $conf_size = 2; + $caddr_size = 6; + $conf_head = '__'; + } + +$short_mcu_name = $mcu; +my $fname = "p${mcu}.inc"; + +die "The MCU: $mcu unknown!\n" if (! -f "$gp_header_path/$fname"); + +$mcu = 'PIC' . uc($mcu); +$header_name = lc($mcu) . '.h'; +$device_name = lc($mcu) . '.c'; + +read_content_from_header("$gp_header_path/$fname"); + +$year = strftime('%Y', gmtime); +$time_str = strftime(', %F %T UTC', gmtime) if (! $no_timestamp); + + # Creates the directory structure. + +my $path = ($is_pic16) ? "$out_path/$p16_out_path" : "$out_path/$p14_out_path"; +my $head_dir = "$path/header"; + +if (! -e $head_dir) + { + Log("Creates the \"$head_dir\" dir.", 4); + make_path($head_dir) || die "Could not create the \"$head_dir\" dir!"; + } + +my $dev_dir = "$path/device"; + +if (! -e $dev_dir) + { + Log("Creates the \"$dev_dir\" dir.", 4); + make_path($dev_dir) || die "Could not create the \"$dev_dir\" dir!"; + } + + # Creates the pic1xxxx.h file. + +my $fpath = "$head_dir/$header_name"; +open($out_handler, '>', $fpath) || die "Could not create the \"$fpath\" file!\n"; +Log("Creates the $header_name", 1); +print_to_header_file(); +close($out_handler); + + # Creates the pic1xxxx.c file. + +$fpath = "$dev_dir/$device_name"; +open($out_handler, '>', $fpath) || die "Could not create the \"$fpath\" file!\n"; +Log("Creates the $device_name", 1); +print_to_device_file(); +close($out_handler); diff --git a/support/scripts/clean.mk b/support/scripts/clean.mk new file mode 100644 index 0000000..503dc67 --- /dev/null +++ b/support/scripts/clean.mk @@ -0,0 +1,22 @@ +# Deleting all files created by building the program +# -------------------------------------------------- +clean: + rm -rf obj + rm -f *core *[%~] *.[oa] $(top_builddir)/bin/makebin$(EXEEXT) + rm -f *.[a-z]*~ + +# Deleting all files created by configuring or building the program +# ----------------------------------------------------------------- +distclean: clean + rm -f Makefile *.dep + + +# Like clean but some files may still exist +# ----------------------------------------- +mostlyclean: clean + + +# Deleting everything that can reconstructed by this Makefile. It deletes +# everything deleted by distclean plus files created by bison, etc. +# ----------------------------------------------------------------------- +realclean: distclean diff --git a/support/scripts/gen_known_bugs.pl b/support/scripts/gen_known_bugs.pl new file mode 100644 index 0000000..9c19cf8 --- /dev/null +++ b/support/scripts/gen_known_bugs.pl @@ -0,0 +1,287 @@ +# gen_known_bugs.pl - generate knownbugs.html
+#
+# Copyright (c) 2007-2013 Borut Razem
+#
+# This file is part of sdcc.
+#
+# This software is provided 'as-is', without any express or implied
+# warranty. In no event will the authors be held liable for any damages
+# arising from the use of this software.
+#
+# Permission is granted to anyone to use this software for any purpose,
+# including commercial applications, and to alter it and redistribute it
+# freely, subject to the following restrictions:
+#
+# 1. The origin of this software must not be misrepresented; you must not
+# claim that you wrote the original software. If you use this software
+# in a product, an acknowledgment in the product documentation would be
+# appreciated but is not required.
+# 2. Altered source versions must be plainly marked as such, and must not be
+# misrepresented as being the original software.
+# 3. This notice may not be removed or altered from any source distribution.
+#
+# Borut Razem
+# borut.razem@siol.net
+
+use strict;
+use warnings;
+
+use LWP::Simple;
+use HTML::TreeBuilder;
+
+
+# trim function to remove whitespace from the start and end of the string
+sub trim($)
+{
+ my $string = shift;
+ $string =~ s/^\s+//;
+ $string =~ s/\s+$//;
+ return $string;
+}
+
+
+my @headerList = ('#', 'Summary', 'Owner', 'Creator', 'Created', 'Priority');
+my $nFields = $#headerList + 1; # Number of colums is number of header fields + 1 for "Select Columns" icon
+
+# check if the line is a correct header
+sub is_header($)
+{
+ my ($line) = @_;
+
+ if (ref($line)) {
+ my @headers = $line->look_down('_tag', 'th');
+ foreach my $header (@headerList) {
+ my $found = 0;
+ foreach (@headers) {
+ my $content = trim($_->as_text());
+ if ($content =~ /\Q$header\E/i) {
+ $found = 1;
+ last;
+ }
+ }
+ if (!$found) {
+ return 0;
+ }
+ }
+ return 1;
+ }
+ return 0;
+}
+
+
+# check if the line has correct number of fields
+sub has_all_fields($)
+{
+ my ($line) = @_;
+
+ my @len = $line->look_down('_tag', 'td');
+ return $#len == $nFields;
+}
+
+# convert to ISO date
+sub date_to_iso($)
+{
+ my %months = (
+ 'Jan', '01',
+ 'Feb', '02',
+ 'Mar', '03',
+ 'Apr', '04',
+ 'May', '05',
+ 'Jun', '06',
+ 'Jul', '07',
+ 'Aug', '08',
+ 'Sep', '09',
+ 'Oct', '10',
+ 'Nov', '11',
+ 'Dec', '12'
+ );
+
+ my ($date) = @_; #Mon Mar 14, 2011 10:42 AM UTC
+ my (undef, $month, $day, $year) = split(' ' , $date);
+ $day =~ s/^(\d+),$/$1/;
+ return $year . '-' . $months{$month} . '-' . sprintf('%02d', $day);
+}
+
+# process a line
+sub process_line($)
+{
+ my ($line) = @_;
+
+ my $i = 0;
+ foreach ($line->look_down('_tag', 'td')) {
+ if (!defined($headerList[$i])) {
+ # don't print columns which are not in the header list
+ $_->delete();
+ }
+ elsif ($headerList[$i] eq 'Summary') {
+ # convert relative to absolute href in the 'Summary' field
+ foreach ($_->look_down('_tag', 'a')) {
+ my $attr = $_->attr('href');
+ if (defined($attr)) {
+ $_->attr('href', 'https://sourceforge.net' . $attr);
+ }
+ }
+ }
+ elsif ($headerList[$i] eq 'Owner' || $headerList[$i] eq 'Creator') {
+ $_->normalize_content();
+ }
+ elsif ($headerList[$i] eq 'Created') {
+ my $date = $_->look_down('_tag', 'span')->attr('title');
+ $_->delete_content();
+ $_->push_content(date_to_iso($date));
+ }
+ elsif ($headerList[$i] eq 'Priority') {
+ my @content = $_->content_list();
+ my $v = 0;
+ $v = $content[0] if (0 == $#content);
+ $_->{'_parent'}->{'class'} = 'p' . $v;
+ }
+ ++$i;
+ }
+ $line->delete_ignorable_whitespace();
+}
+
+
+# process the HTML page
+sub process_page($)
+{
+ my ($html) = @_;
+
+ # create HTML tree from the page
+ my $tree = HTML::TreeBuilder->new();
+ $tree->parse($html);
+
+ # find table with the required header
+ my $lines = 0;
+ foreach my $table ($tree->look_down('_tag', 'table')) {
+ my $thead = $table->look_down('_tag', 'thead');
+ if (is_header($thead)) {
+ my $tbody = $table->look_down('_tag', 'tbody');
+ my @lines = $tbody->content_list();
+
+ # process the lines in table
+ # if they have required number of fields
+ foreach my $line (@lines) {
+ if (ref($line) && has_all_fields($line)) {
+ # process a line
+ process_line($line);
+ # and print it
+ print($line->as_HTML(undef, ' '));
+ ++$lines;
+ }
+ }
+ }
+ }
+
+ $tree->delete;
+
+ return $lines;
+}
+
+
+# print HTML header
+sub print_header($)
+{
+ my ($version) = @_;
+
+ print <<EOF;
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
+<!--
+This file is generated automagicaly by gen_known_bugs.pl script.
+-->
+ <head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <title>SourceForge.net: Known Bugs</title>
+ <style type="text/css">
+ .p1 {background-color: #9ff;}
+ .p2 {background-color: #cff;}
+ .p3 {background-color: #9fc;}
+ .p4 {background-color: #cfc;}
+ .p5 {background-color: #cf9;}
+ .p6 {background-color: #ffc;}
+ .p7 {background-color: #ff9;}
+ .p8 {background-color: #fc9;}
+ .p9 {background-color: #fcc; color: #300;}
+ </style>
+ </head>
+ <body>
+ <h2>Small Device C Compiler - Release $version Known Bug List</h2>
+ <ul>
+ <li><a href="http://sdcc.sourceforge.net">Home Page</a></li>
+ <li class="selected"><a href="http://sourceforge.net/p/sdcc/bugs/">Current Bugs</a></li>
+ </ul>
+ <table width="100%" border="0" cellspacing="2" cellpadding="3">
+ <tr bgcolor="#ffffff">
+EOF
+
+ foreach my $header (@headerList) {
+ # don't print Status and Resolution columns
+ if ($header ne 'Status' && $header ne 'Resolution') {
+ print(' <td align="center"><font color="#000000"><b>' . $header . "</b></font></td>\n");
+ }
+ }
+ print(" </tr>\n");
+}
+
+
+# print HTML footer
+sub print_footer($)
+{
+ my ($lines) = @_;
+
+ print <<EOF;
+ </table>
+ <p><b>Priority Colors:</b></p>
+ <table border="0">
+ <tr>
+ <td class="p1">1</td>
+ <td class="p2">2</td>
+ <td class="p3">3</td>
+ <td class="p4">4</td>
+ <td class="p5">5</td>
+ <td class="p6">6</td>
+ <td class="p7">7</td>
+ <td class="p8">8</td>
+ <td class="p9">9</td>
+ </tr>
+ </table>
+ </body>
+ <p><b>Number of open bugs: $lines</b></p>
+</html>
+EOF
+}
+
+
+# main procedure
+{
+ my $url = "http://sourceforge.net/p/sdcc/bugs/?limit=%d&page=%d&sort=ticket_num+desc&q=%%7B%%22status%%22%%3A+%%7B%%22%%24nin%%22%%3A+%%5B%%22closed-invalid%%22%%2C+%%22closed-later%%22%%2C+%%22closed-accepted%%22%%2C+%%22closed-duplicate%%22%%2C+%%22closed-out-of-date%%22%%2C+%%22closed-fixed%%22%%2C+%%22closed-rejected%%22%%2C+%%22closed-remind%%22%%2C+%%22closed-works-for-me%%22%%2C+%%22closed%%22%%2C+%%22closed-wont-fix%%22%%2C+%%22closed-postponed%%22%%5D%%7D%%7D&columns-0.name=ticket_num&columns-0.sort_name=ticket_num&columns-0.label=Ticket+Number&columns-0.active=on&columns-1.name=summary&columns-1.sort_name=summary&columns-1.label=Summary&columns-1.active=on&columns-2.name=_milestone&columns-2.sort_name=custom_fields._milestone&columns-2.label=Milestone&columns-3.name=status&columns-3.sort_name=status&columns-3.label=Status&columns-4.name=assigned_to&columns-4.sort_name=assigned_to_username&columns-4.label=Owner&columns-4.active=on&columns-5.name=reported_by&columns-5.sort_name=reported_by&columns-5.label=Creator&columns-5.active=on&columns-6.name=created_date&columns-6.sort_name=created_date&columns-6.label=Created&columns-6.active=on&columns-7.name=mod_date&columns-7.sort_name=mod_date&columns-7.label=Updated&columns-8.name=labels&columns-8.sort_name=labels&columns-8.label=Labels&columns-9.name=_priority&columns-9.sort_name=_priority&columns-9.label=Priority&columns-9.active=on";
+
+ if ($#ARGV != 0) {
+ printf("Usage: gen_known_bugs.pl <version>\n");
+ exit(1);
+ }
+
+ my $limit = 100;
+
+ # get the SDCC version number from command line
+ my $version = $ARGV[0];
+
+ # print HTML header
+ print_header($version);
+
+ # get pages from SF bug tracker
+ # and process them
+ my $page = 0;
+ my $lines;
+ while (my $linesRead = process_page(get(sprintf($url, $limit, $page)))) {
+ $lines += $linesRead;
+ ++$page;
+ }
+
+ # print HTML footer
+ print_footer($lines);
+
+ exit(0);
+}
diff --git a/support/scripts/keil2sdcc.pl b/support/scripts/keil2sdcc.pl new file mode 100755 index 0000000..a3ba657 --- /dev/null +++ b/support/scripts/keil2sdcc.pl @@ -0,0 +1,112 @@ +#!/usr/bin/perl -w + +# keil2sdcc.pl +# Scott Bronson +# 22 June 2003 + + +# usage (UNIX): +# perl keil2sdcc.pl < keil_header.h > sdcc_header.h +# or +# perl keil2sdcc.pl keil_header.h > sdcc_header.h +# +# usage (Windows): +# perl keil2sdcc.pl keil_header.h > sdcc_header.h +# +# +# keil_header.h and sdcc_header.h must not be the same file since +# most shells overwrite the output file before opening the input file. + + +# This script converts Keil-style header files to SDCC. It tries to +# be pedantic so don't be surprised if you need to munge it a bit to +# get it to work. On the other hand, it doesn't fully parse the C +# file (for obvious reasons). + +# It takes the Keil header file either as an argument or on +# stdin and it produces the output on stdout. + +# This script is inspired by keil2sdcc.pl by Bela Torok but a lot +# more pedantic. + +use strict; + +while(<>) +{ + s/\r//g; # remove DOS line endings if necessary + + # external register (kind of a weird format) + # + # in: EXTERN xdata volatile BYTE GPIF_WAVE_DATA _AT_ 0xE400; + # out: EXTERN xdata at 0xE400 volatile BYTE GPIF_WAVE_DATA; + # $1: leading whitespace + # $2: variable name + # $3: variable location + # $4: trailing comments, etc. + + if(/^(\s*)EXTERN\s*xdata\s*volatile\s*BYTE\s*(\w+(?:\s*\[\s*\d+\s*\])?)\s+_AT_\s*([^;]+);(.*)$/) { + print "$1EXTERN xdata at $3 volatile BYTE $2;$4\n"; + next; + } + + # sfr statement + # + # in: sfr IOA = 0x80; + # out: sfr at 0x80 IOA; + # $1: leading whitespace + # $2: variable name + # $3: variable location + # $4: trailing comments, etc. + + if(/^(\s*)sfr\s*(\w+)\s*=\s*([^;]+);(.*)$/) { + print "$1sfr at $3 $2;$4\n"; + next; + } + + # sbit statement + # + # in: sbit SEL = 0x86+0; + # out: sbit at 0x86+0 SEL; + # $1: leading whitespace + # $2: variable name + # $3: variable location + # $4: trailing comments, etc. + + if(/^(\s*)sbit\s*(\w+)\s*=\s*([^;]+);(.*)$/) { + print "$1sbit at $3 $2;$4\n"; + next; + } + + + + # entire line is a C++ comment, output it unchanged. + if(/^(\s*)\/\/(.*)$/) { + print "$1//$2\n"; + next; + } + + # C comment, slurp lines until the close comment and output it unchanged. + if(/^(\s*)\/\*(.*)$/) { + my($ws,$cmt) = ($1,"$2\n"); + $cmt .= <> while $cmt !~ /\*\/\s*$/; + $cmt =~ s/\r//g; + print "$ws/*$cmt"; + next; + } + + # preprocessor statement (whitespace followed by '#'), don't change + if(/^(\s*)\#(.*)$/) { + print "$1#$2\n"; + next; + } + + # blank line, don't change + if(/^(\s*)$/) { + print "\n"; + next; + } + + chomp; + die "Unconvertable line: \"$_\"\n"; +} + diff --git a/support/scripts/listerr.c b/support/scripts/listerr.c new file mode 100644 index 0000000..a5127cb --- /dev/null +++ b/support/scripts/listerr.c @@ -0,0 +1,57 @@ +/* + * listerr.c - program to create the list of errors and warnings list from SDCCerr.c + * + * gcc -I ../../src listerr.c -o listerr + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/* although this seems to be strange, this is the easiest way how to import the ErrTab without having to modify SDCCerr.c/h */ +#include "SDCCerr.c" + +// this is to make SDCCerr happy - simulate global SDCC variables +char *filename ; +int lineno ; +int fatalError ; + + +/* predefined names for errorlevels */ +char *ErrTypeName[] = { + "ALL ", + /** All warnings, including those considered 'reasonable to use, + on occasion, in clean programs' (man 3 gcc). */ + "PEDANTIC", + /** 'informational' warnings */ + "INFO ", + /** Most warnings. */ + "WARNING ", + /** Errors only. */ + "ERROR " + }; + + +/* some simple internal variables */ +int i; +char s[256]; +char *p; + +int main(int argc, char *argv[]) +{ + printf("Number Type Text\n"); /* output file header */ + printf("------------------------------------------------------------------------------\n"); + for (i = 0; i < MAX_ERROR_WARNING; i++) + { + if (ErrTab[i].errIndex == i) + { + strcpy(s, ErrTab[i].errText); + for (p = s; NULL != (p = strchr(s, '\n')); ) + *p = ' '; /* replace all newlines by spaces */ + printf("%3d %-16.16s%s\n", ErrTab[i].errIndex, ErrTypeName[ErrTab[i].errType], s); + } + } + + return 0; +} + diff --git a/support/scripts/mcs51-disasm.pl b/support/scripts/mcs51-disasm.pl new file mode 100755 index 0000000..55d20db --- /dev/null +++ b/support/scripts/mcs51-disasm.pl @@ -0,0 +1,6333 @@ +#!/usr/bin/perl -w + +=back + + Copyright (C) 2013, Molnar Karoly <molnarkaroly@users.sf.net> + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source distribution. + +================================================================================ + + This program disassembles the hex files. It assumes that the hex file + contains MCS51 instructions. + + Proposal for use: ./mcs51-disasm.pl -M 8052.h -fl -rj program.hex > program.dasm + + or ./mcs51-disasm.pl -M 8052.h -fl -rj -as program.hex > program.asm + + or ./mcs51-disasm.pl -M 8052.h -fl -rj -as -hc program.hex > program.asm + + + Warning! This program is not able to find all variable. Especially them not, whose + can be found in the indirect or external RAM. + + $Id: mcs51-disasm.pl 9068 2014-09-04 12:57:30Z molnarkaroly $ +=cut + +use strict; +use warnings; +no if $] >= 5.018, warnings => "experimental::smartmatch"; # perl 5.16 +use 5.12.0; # when (regex) + +use constant FALSE => 0; +use constant TRUE => 1; + +use constant TAB_LENGTH => 8; + +################################################################################ + +use constant INHX8M => 0; +use constant INHX32 => 2; + +use constant INHX_DATA_REC => 0; +use constant INHX_EOF_REC => 1; +use constant INHX_EXT_LIN_ADDR_REC => 4; + +use constant EMPTY => -1; + +use constant COUNT_SIZE => 2; +use constant ADDR_SIZE => 4; +use constant TYPE_SIZE => 2; +use constant BYTE_SIZE => 2; +use constant CRC_SIZE => 2; +use constant HEADER_SIZE => (COUNT_SIZE + ADDR_SIZE + TYPE_SIZE); +use constant MIN_LINE_LENGTH => (HEADER_SIZE + CRC_SIZE); + +use constant MCS51_ROM_SIZE => 0x10000; + +################################################################################ + +my $PROGRAM = 'mcs51-disasm.pl'; + +my $border0 = ('-' x 79); +my $border1 = ('#' x 79); +my $border2 = ('.' x 39); + +my @default_paths = + ( + '/usr/share/sdcc/include/mcs51', + '/usr/local/share/sdcc/include/mcs51' + ); + +my $default_include_path = ''; +my $include_path = ''; +my $hex_file = ''; +my $map_file = ''; +my $map_readed = FALSE; +my $header_file = ''; +my $name_list = ''; + +my $verbose = 0; +my $hex_constant = FALSE; +my $gen_assembly_code = FALSE; +my $no_explanations = FALSE; +my $recognize_jump_tables = FALSE; +my $find_lost_labels = FALSE; + +my @rom = (); +my $rom_size = MCS51_ROM_SIZE; +my %const_areas_by_address = (); # From the command line parameters. + +my %const_blocks_by_address = (); + +=back + The structure of one element of the %sfr_by_address hash: + + { + NAME => '', + REF_COUNT => 0 + } +=cut + +my %sfr_by_address = (); +my %sfr_by_names = (); + +=back + The structure of one element of the %sfr_bit_by_address hash: + + { + NAME => '', + REF_COUNT => 0 + } +=cut + +my %sfr_bit_by_address = (); + +my %used_banks = (); + +=back + The structure of one element of the %bit_by_address hash: + + { + NAME => '', + REF_COUNT => 0 + } +=cut + +my %bit_by_address = (); + +=back + The structure of one element of the %ram_by_address hash: + + { + TYPE => 0, + NAME => '', + SIZE => 0, + REF_COUNT => 0 + } +=cut + +use constant RAM_TYPE_DIR => 0; +use constant RAM_TYPE_IND => 1; + +my %ram_by_address = (); +my %ram_names_by_address = (); + +=back + The structure of one element of the %xram_by_address hash: + + { + NAME => '', + SIZE => 0, + REF_COUNT => 0 + } +=cut + +my %xram_by_address = (); +my %xram_names_by_address = (); + +my $stack_start = -1; +my $stack_size = 0; + + # Sizes of the instructions. + +my @instruction_sizes = + ( + 1, 2, 3, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 3, 2, 3, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 3, 2, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 3, 2, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 3, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 3, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 3, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 1, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 1, 1, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 2, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 1, 1, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 1, 1, 3, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + ); + +use constant BANK_LAST_ADDR => 0x1F; +use constant BIT_LAST_ADDR => 0x7F; +use constant RAM_MAX_ADDR => 0xFF; +use constant RAM_LAST_DIR_ADDR => 0x7F; + +use constant SP => 0x81; +use constant DPL => 0x82; +use constant DPH => 0x83; +use constant PSW => 0xD0; +use constant ACC => 0xE0; + +use constant INST_AJMP => 0x01; +use constant INST_LJMP => 0x02; +use constant INST_ACALL => 0x11; +use constant INST_LCALL => 0x12; +use constant INST_SJMP => 0x80; +use constant INST_RET => 0x22; +use constant INST_RETI => 0x32; +use constant INST_ADD_A_DATA => 0x24; +use constant INST_JMP_A_DPTR => 0x73; +use constant INST_MOV_DIRECT_DATA => 0x75; +use constant INST_MOVC_A_APC => 0x83; +use constant INST_MOV_DIRECT_DIRECT => 0x85; +use constant INST_MOV_DPTR_DATA => 0x90; +use constant INST_MOVC_A_DPTR => 0x93; +use constant INST_PUSH_DIRECT => 0xC0; +use constant INST_XCH_A_DIRECT => 0xC5; +use constant INST_POP_DIRECT => 0xD0; +use constant INST_CLR_A => 0xE4; +use constant INST_MOV_A_DIRECT => 0xE5; +use constant INST_MOV_A_Ri => 0xE6; +use constant INST_MOV_A_Rn => 0xE8; +use constant INST_MOV_DIRECT_A => 0xF5; +use constant INST_CJNE_A_DATA => 0xB4; +use constant INST_CJNE_A_DIRECT => 0xB5; +use constant INST_CJNE__Ri_DATA => 0xB6; +use constant INST_CJNE_Rn_DATA => 0xB8; +use constant INST_DJNZ_Rn => 0xD8; +use constant INST_DJNZ_DIRECT => 0xD5; +use constant INST_JBC_BIT => 0x10; +use constant INST_JB_BIT => 0x20; +use constant INST_JNB_BIT => 0x30; +use constant INST_JC => 0x40; +use constant INST_JNC => 0x50; +use constant INST_JZ => 0x60; +use constant INST_JNZ => 0x70; + +use constant LJMP_SIZE => 3; + +my $DPTR; +my @R_regs; + +my $prev_is_jump; + +use constant SILENT0 => 0; +use constant SILENT1 => 1; +use constant SILENT2 => 2; + +my $decoder_silent_level; + +use constant EXPL_ALIGN_SIZE => 5; +use constant STAT_ALIGN_SIZE => 6; +use constant TBL_COLUMNS => 8; + +=back + The structure of one element of the %blocks_by_address hash: + + { + TYPE => 0, + ADDR => 0, + SIZE => 0, + LABEL => { + TYPE => 0, + NAME => '', + PRINTED => FALSE, + CALL_COUNT => 0, + JUMP_COUNT => 0 + } + } +=cut + +use constant BLOCK_INSTR => 0; +use constant BLOCK_CONST => 1; +use constant BLOCK_JTABLE => 2; +use constant BLOCK_EMPTY => 3; +use constant BLOCK_DISABLED => 4; + +use constant BL_TYPE_NONE => -1; +use constant BL_TYPE_SUB => 0; +use constant BL_TYPE_LABEL => 1; +use constant BL_TYPE_JTABLE => 2; +use constant BL_TYPE_JLABEL => 3; +use constant BL_TYPE_CONST => 4; + +my %label_names = + ( + eval BL_TYPE_SUB => 'Function_', + eval BL_TYPE_LABEL => 'Label_', + eval BL_TYPE_JTABLE => 'Jumptable_', + eval BL_TYPE_JLABEL => 'JTlabel_', + eval BL_TYPE_CONST => 'Constant_' + ); + +my %empty_blocks_by_address = (); +my %blocks_by_address = (); +my %labels_by_address = (); +my $max_label_addr = 0; + +my %indirect_addr_instr = + ( + 0x06 => TRUE, + 0x16 => TRUE, + 0x26 => TRUE, + 0x36 => TRUE, + 0x46 => TRUE, + 0x56 => TRUE, + 0x66 => TRUE, + 0x76 => TRUE, + 0x86 => TRUE, + 0x96 => TRUE, + 0xA6 => TRUE, + 0xB6 => TRUE, + 0xC6 => TRUE, + 0xD6 => TRUE, + 0xE6 => TRUE, + 0xF6 => TRUE + ); + +my %interrupts_by_address = + ( + 0x0000 => 'System_init', + 0x0003 => 'Int0_interrupt', + 0x000B => 'Timer0_interrupt', + 0x0013 => 'Int1_interrupt', + 0x001B => 'Timer1_interrupt', + 0x0023 => 'Uart_interrupt', + 0x002B => 'Timer2_interrupt', + 0x0033 => 'Int2_interrupt', + 0x003B => 'Int3_interrupt' + ); + +my %control_characters = + ( + 0x00 => '\0', + 0x07 => '\a', + 0x08 => '\b', + 0x09 => '\t', + 0x0A => '\n', + 0x0C => '\f', + 0x0D => '\r', + 0x1B => '\e', + 0x7F => '^?' + ); + +my $dcd_address = 0; +my $dcd_instr_size = 0; +my $dcd_instr = 0; +my $dcd_parm0 = 0; +my $dcd_parm1 = 0; +my $dcd_Ri_regs = 0; +my $dcd_Ri_name = ''; +my $dcd_Rn_regs = 0; +my $dcd_Rn_name = ''; + +my $table_header = ''; +my $table_border = ''; + +################################################################################ +################################################################################ + +my %pp_defines = (); # Value of definitions. + +my @pp_conditions = (); +my @pp_else_conditions = (); +my $pp_level = 0; # Shows the lowest level. +my $embed_level; + +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@@ This a simple preprocessor. @@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + # Examines that the parameter is defined or not defined. + +sub _defined($) + { + return defined($pp_defines{$_[0]}); + } + +#------------------------------------------------------------------------------- + + # Records a definition. + +sub define($) + { + my ($Name) = ($_[0] =~ /^(\S+)/op); + my $Body = ${^POSTMATCH}; + + $Body =~ s/^\s+//o; + + die "define(): This definition already exists: \"$Name\"\n" if (_defined($Name)); + + # The definition is in fact unnecessary. + $pp_defines{$Name} = $Body; + } + +#------------------------------------------------------------------------------- + + # Delete a definition. + +sub undefine($) + { + delete($pp_defines{$_[0]}); + } + +#------------------------------------------------------------------------------- + + # Evaluation of the #if give a boolean value. This procedure preserves it. + +sub if_condition($) + { + my $Val = $_[0]; + + push(@pp_conditions, $Val); + push(@pp_else_conditions, $Val); + ++$pp_level; + } + +#------------------------------------------------------------------------------- + + # Evaluation of the #else give a boolean value. This procedure preserves it. + +sub else_condition($$) + { + my ($File, $Line_number) = @_; + + 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); + + my $last = $#pp_conditions; + + if ($last > 0 && $pp_conditions[$last - 1]) + { + $pp_conditions[$last] = ($pp_else_conditions[$#pp_else_conditions]) ? FALSE : TRUE; + } + else + { + $pp_conditions[$last] = FALSE; + } + } + +#------------------------------------------------------------------------------- + + # Closes a logical unit which starts with a #if. + +sub endif_condition($$) + { + my ($File, $Line_number) = @_; + + 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); + + pop(@pp_conditions); + pop(@pp_else_conditions); + --$pp_level; + } + +#------------------------------------------------------------------------------- + +sub reset_preprocessor() + { + %pp_defines = (); + @pp_conditions = (); + push(@pp_conditions, TRUE); + @pp_else_conditions = (); + push(@pp_else_conditions, FALSE); + $pp_level = 0; + } + +#------------------------------------------------------------------------------- + + # This the preprocessor. + +sub run_preprocessor($$$$) + { + my ($Fname, $Function, $Line, $Line_number) = @_; + + if ($Line =~ /^#\s*ifdef\s+(\S+)$/o) + { + if ($pp_conditions[$#pp_conditions]) + { + # The ancestor is valid, therefore it should be determined that + # the descendants what kind. + + if_condition(_defined($1)); + } + else + { + # The ancestor is invalid, so the descendants will invalid also. + + if_condition(FALSE); + } + } + elsif ($Line =~ /^#\s*ifndef\s+(\S+)$/o) + { + if ($pp_conditions[$#pp_conditions]) + { + # The ancestor is valid, therefore it should be determined that + # the descendants what kind. + + if_condition(! _defined($1)); + } + else + { + # The ancestor is invalid, so the descendants will invalid also. + + if_condition(FALSE); + } + } + elsif ($Line =~ /^#\s*else/o) + { + else_condition($Fname, $Line_number); + } + elsif ($Line =~ /^#\s*endif/o) + { + endif_condition($Fname, $Line_number); + } + elsif ($Line =~ /^#\s*define\s+(.+)$/o) + { + # This level is valid, so it should be recorded in the definition. + + define($1) if ($pp_conditions[$#pp_conditions]); + } + elsif ($Line =~ /^#\s*undef\s+(.+)$/o) + { + # This level is valid, so it should be deleted in the definition. + + undefine($1) if ($pp_conditions[$#pp_conditions]); + } + elsif ($pp_conditions[$#pp_conditions]) + { + # This is a valid line. (The whole magic is in fact therefore there is.) + + $Function->($Line); + } + } + +################################################################################ +################################################################################ +################################################################################ + +sub basename($) + { + return ($_[0] =~ /([^\/]+)$/) ? $1 : ''; + } + +#------------------------------------------------------------------------------- + +sub param_exist($$) + { + die "This option \"$_[0]\" requires a parameter.\n" if ($_[1] > $#ARGV); + } + +#------------------------------------------------------------------------------- + +sub Log + { + return if (pop(@_) > $verbose); + foreach (@_) { print STDERR $_; } + print STDERR "\n"; + } + +#------------------------------------------------------------------------------- + +sub str2int($) + { + my $Str = $_[0]; + + return hex($1) if ($Str =~ /^0x([[:xdigit:]]+)$/io); + return int($Str) if ($Str =~ /^-?\d+$/o); + + die "str2int(): This string not integer: \"$Str\""; + } + +#------------------------------------------------------------------------------- + + # + # Before print, formats the $Text. + # + +sub align($$) + { + my $Text = $_[0]; + my $al = $_[1] - int(length($Text) / TAB_LENGTH); + + # One space will surely becomes behind it. + if ($al < 1) + { + return "$Text "; + } + else + { + return ($Text . ("\t" x $al)); + } + } + +#------------------------------------------------------------------------------- + + # + # Multiple file test. + # + +sub is_file_ok($) + { + my $File = $_[0]; + + if (! -e $File) + { + print STDERR "$PROGRAM: Not exists -> \"$File\"\n"; + exit(1); + } + + if (! -f $File) + { + print STDERR "$PROGRAM: Not file -> \"$File\"\n"; + exit(1); + } + + if (! -r $File) + { + print STDERR "$PROGRAM: Can not read -> \"$File\"\n"; + exit(1); + } + + if (! -s $File) + { + print STDERR "$PROGRAM: Empty file -> \"$File\"\n"; + exit(1); + } + } + +#------------------------------------------------------------------------------- + + # + # Initializes the @rom array. + # + +sub init_mem($$) + { + my ($Start, $End) = @_; + + @rom[$Start .. $End] = ((EMPTY) x ($End - $Start + 1)); + } + +#------------------------------------------------------------------------------- + + # + # Store values of the $Code to $AddrRef address. + # + +sub store_code($$) + { + my ($Code, $AddrRef) = @_; + + if ($$AddrRef >= $rom_size) + { + printf STDERR "Warning, this address (0x%04X) outside the code area (0x%04X)!\n", $$AddrRef, $rom_size - 1; + } + + Log(sprintf("rom[0x%08X] = 0x%02X", $$AddrRef, $Code), 9); + $rom[$$AddrRef++] = $Code; + } + +#------------------------------------------------------------------------------- + + # + # Reads contents of the $Hex. + # + +sub read_hex($) + { + my $Hex = $_[0]; + my $addr_H = 0; + my $format = INHX32; + my $line_num = 0; + + if (! open(IN, '<', $Hex)) + { + print STDERR "$PROGRAM : Could not open. -> \"$Hex\"\n"; + exit(1); + } + + while (<IN>) + { + chomp; + s/\r$//o; + ++$line_num; + + my $len = length() - 1; + + if ($len < MIN_LINE_LENGTH) + { + close(IN); + print STDERR "$PROGRAM: ${line_num}th line <- Shorter than %u character.\n", MIN_LINE_LENGTH; + exit(1); + } + + Log("$..(1) (\"$_\") length() = " . length(), 7); + + my $bytecount = int(($len - MIN_LINE_LENGTH) / BYTE_SIZE); + + my $binrec = pack('H*', substr($_, 1)); + + if (unpack('%8C*', $binrec) != 0) + { + close(IN); + print STDERR "$PROGRAM: $Hex <- Crc error. (${line_num}th line \"$_\").\n"; + exit(1); + } + + my ($count, $addr, $type, $bytes) = unpack('CnCX4Cx3/a', $binrec); + + my @codes = unpack('C*', $bytes); + + Log(sprintf("$..(2) (\"$_\") count = $count, bytecount = $bytecount, addr = 0x%04X, type = $type", $addr), 7); + + if ($type == INHX_EOF_REC) + { + last; + } + elsif ($type == INHX_EXT_LIN_ADDR_REC) + { + $addr_H = unpack('n', $bytes); # big-endian + + Log(sprintf("$..(3) (\"$_\") addr_H = 0x%04X\n", $addr_H), 7); + + $format = INHX32; + Log('format = INHX32', 7); + next; + } + elsif ($type != INHX_DATA_REC) + { + close(IN); + printf STDERR "$PROGRAM: $Hex <- Unknown type of record: 0x%02X (${line_num}th line \"$_\").\n", $type; + exit(1); + } + + if ($bytecount == $count) # INHX32 + { + if ($format == INHX8M) + { + close(IN); + print STDERR "$PROGRAM: $Hex <- Mixed format of file (${line_num}th line \"$_\").\n"; + exit(1); + } + + my $addr32 = ($addr_H << 16) | $addr; + + map { store_code($_, \$addr32) } @codes; + } + elsif ($bytecount == ($count * BYTE_SIZE)) # INHX8M + { + if ($format == INHX32) + { + close(IN); + print STDERR "$PROGRAM: $Hex <- Mixed format of file (${line_num}th line \"$_\").\n"; + exit(1); + } + + map { store_code($_, \$addr) } @codes; + } + else + { + close(IN); + print STDERR "$PROGRAM: $Hex <- Wrong format of file (${line_num}th line \"$_\").\n"; + exit(1); + } + } # while (<IN>) + + close(IN); + } + +#------------------------------------------------------------------------------- + + # + # Determines that the $Address belongs to a constant. + # + +sub is_constant($) + { + my $Address = $_[0]; + + foreach (sort {$a <=> $b} keys(%const_areas_by_address)) + { + return TRUE if ($_ <= $Address && $Address <= $const_areas_by_address{$_}); + last if ($_ > $Address); + } + + foreach (sort {$a <=> $b} keys(%const_blocks_by_address)) + { + return TRUE if ($_ <= $Address && $Address <= $const_blocks_by_address{$_}); + last if ($_ > $Address); + } + + return FALSE; + } + +#------------------------------------------------------------------------------- + + # + # Determines that the $Address belongs to a empty area. + # + +sub is_empty($) + { + my $Address = $_[0]; + + foreach (sort {$a <=> $b} keys(%empty_blocks_by_address)) + { + return TRUE if ($_ <= $Address && $Address <= $empty_blocks_by_address{$_}); + last if ($_ > $Address); + } + + return FALSE; + } + +#------------------------------------------------------------------------------- + + # + # Creates a const block. + # + +sub add_const_area($$) + { + $const_areas_by_address{$_[0]} = $_[1]; + } + +#------------------------------------------------------------------------------- + + # + # Creates a new block, or modifies one. + # + +sub add_block($$$$$) + { + my ($Address, $Type, $Size, $LabelType, $LabelName) = @_; + my ($block, $label, $end); + + $end = $Address + $Size - 1; + + if (! defined($blocks_by_address{$Address})) + { + $label = { + TYPE => $LabelType, + NAME => $LabelName, + PRINTED => FALSE, + CALL_COUNT => 0, + JUMP_COUNT => 0 + }; + + $blocks_by_address{$Address} = { + TYPE => $Type, + ADDR => $Address, + SIZE => $Size, + LABEL => $label + }; + + if ($Type == BLOCK_INSTR) + { + if ($LabelType != BL_TYPE_NONE) + { + $labels_by_address{$Address} = $label; + $max_label_addr = $Address if ($max_label_addr < $Address); + } + } + elsif ($Type == BLOCK_CONST || $Type == BLOCK_JTABLE) + { + if ($LabelType != BL_TYPE_NONE) + { + $labels_by_address{$Address} = $label; + $max_label_addr = $Address if ($max_label_addr < $Address); + } + + $const_blocks_by_address{$Address} = $end if ($Size > 0); + } + elsif ($Type == BLOCK_EMPTY) + { + # At empty area, can not be label. + + $label->{TYPE} = BL_TYPE_NONE; + $label->{NAME} = ''; + $empty_blocks_by_address{$Address} = $end if ($Size > 0); + } + else + { + printf STDERR "add_block(0x%04X): Unknown block type!\n", $Address; + exit(1); + } + } # if (! defined($blocks_by_address{$Address})) + else + { + $block = $blocks_by_address{$Address}; + $label = $block->{LABEL}; + $block->{TYPE} = $Type; + $block->{SIZE} = $Size if ($Size > 0); + $label->{NAME} = $LabelName if ($label->{NAME} eq '' && $LabelName ne ''); + + if ($Type == BLOCK_INSTR) + { + if ($LabelType != BL_TYPE_NONE) + { + $label->{TYPE} = $LabelType if ($label->{TYPE} != BL_TYPE_JLABEL); + $labels_by_address{$Address} = $label; + $max_label_addr = $Address if ($max_label_addr < $Address); + } + } + elsif ($Type == BLOCK_CONST || $Type == BLOCK_JTABLE) + { + if ($LabelType != BL_TYPE_NONE) + { + $label->{TYPE} = $LabelType; + $labels_by_address{$Address} = $label; + $max_label_addr = $Address if ($max_label_addr < $Address); + } + + $const_blocks_by_address{$Address} = $end if ($Size > 0); + } + elsif ($Type == BLOCK_EMPTY) + { + # At empty area, can not be label. + + $label->{TYPE} = BL_TYPE_NONE; + $label->{NAME} = ''; + $empty_blocks_by_address{$Address} = $end if ($Size > 0); + } + } + + return $label; + } + +#------------------------------------------------------------------------------- + + # + # Store address entry of a procedure. + # + +sub add_func_label($$$) + { + my ($Address, $Name, $Map_mode) = @_; + my $label; + + if ($Address < 0) + { + Log(sprintf("add_func_label(): This address (0x%04X) negative!", $Address), 2); + return; + } + + if (! $Map_mode) + { + if (! defined($blocks_by_address{$Address})) + { + Log(sprintf("add_func_label(): This address (0x%04X) does not shows an instruction!", $Address), 2); + return; + } + } + + if (is_constant($Address) || is_empty($Address)) + { + Log(sprintf("add_func_label(): This address (0x%04X) outside the code area!", $Address), 2); + return; + } + + $label = add_block($Address, BLOCK_INSTR, 0, BL_TYPE_SUB, $Name); + ++$label->{CALL_COUNT} if (! $Map_mode); + } + +#------------------------------------------------------------------------------- + + # + # Store a label. + # + +sub add_jump_label($$$$$) + { + my ($TargetAddr, $Name, $Type, $SourceAddr, $Map_mode) = @_; + my ($label, $type); + + if ($TargetAddr < 0) + { + Log(sprintf("add_jump_label(): This address (0x%04X) negative!", $TargetAddr), 2); + return; + } + + if (! $Map_mode) + { + if (! defined($blocks_by_address{$TargetAddr})) + { + Log(sprintf("add_jump_label(): This address (0x%04X) does not shows an instruction!", $TargetAddr), 2); + return; + } + } + + if (is_constant($TargetAddr) || is_empty($TargetAddr)) + { + Log(sprintf("add_jump_label(): This address (0x%04X) outside the code area!", $TargetAddr), 2); + return; + } + + if (defined($interrupts_by_address{$SourceAddr})) + { + $Type = BL_TYPE_SUB; + $Name = $interrupts_by_address{$SourceAddr} if ($Name eq ''); + } + + $label = add_block($TargetAddr, BLOCK_INSTR, 0, $Type, $Name); + ++$label->{JUMP_COUNT} if (! $Map_mode); + } + +#------------------------------------------------------------------------------- + + # + # Store a bit or sbit name from bit area. + # + +sub add_bit($$$) + { + my ($Address, $Name, $Map_mode) = @_; + my $bit; + + if ($Address > BIT_LAST_ADDR) + { + if (! defined($bit = $sfr_bit_by_address{$Address})) + { + $sfr_bit_by_address{$Address} = { + NAME => $Name, + REF_COUNT => ($Map_mode) ? 0 : 1 + }; + } + else + { + if ($Name ne '' && $bit->{NAME} ne $Name) + { + Log(sprintf("Warning, the address: 0x%02X already busy by the $bit->{NAME} bit.", $Address), 2); + } + else + { + ++$bit->{REF_COUNT} if (! $Map_mode); + } + } + } + else + { + if (! defined($bit = $bit_by_address{$Address})) + { + $bit_by_address{$Address} = { + NAME => $Name, + REF_COUNT => ($Map_mode) ? 0 : 1 + }; + } + else + { + ++$bit->{REF_COUNT} if (! $Map_mode); + } + } + } + +#------------------------------------------------------------------------------- + + # + # Store a sfr or variable name. + # + +sub add_ram($$$$) + { + my ($Address, $Name, $Type, $Map_mode) = @_; + my $ram; + + return if ($Address == EMPTY); + + if ($Address > RAM_LAST_DIR_ADDR && $Type == RAM_TYPE_DIR) + { + if (! defined($ram = $sfr_by_address{$Address})) + { + $sfr_by_address{$Address} = { + NAME => $Name, + REF_COUNT => ($Map_mode) ? 0 : 1 + }; + } + else + { + if ($Name ne '' && $ram->{NAME} ne $Name) + { + Log(sprintf("Warning, the address: 0x%02X already busy by the $ram->{NAME} register.", $Address), 2); + } + else + { + ++$ram->{REF_COUNT} if (! $Map_mode); + } + } + + $sfr_by_names{$Name} = $Address; + } + else + { + if (! defined($ram = $ram_by_address{$Address})) + { + $ram_by_address{$Address} = { + TYPE => $Type, + NAME => $Name, + SIZE => 1, + REF_COUNT => ($Map_mode) ? 0 : 1 + }; + } + else + { + ++$ram->{REF_COUNT} if (! $Map_mode); + } + } + } + +#------------------------------------------------------------------------------- + + # + # Store a variable name from XRAM. + # + +sub add_xram($$$) + { + my ($Address, $Name, $Map_mode) = @_; + my $xram; + + if (! defined($xram = $xram_by_address{$Address})) + { + $xram_by_address{$Address} = { + NAME => $Name, + SIZE => 1, + REF_COUNT => ($Map_mode) ? 0 : 1 + }; + } + else + { + ++$xram->{REF_COUNT} if (! $Map_mode); + } + } + +################################################################################ +################################################################################ + +use constant MAP_NULL => 0; +use constant MAP_BORDER => 1; +use constant MAP_AREA => 2; +use constant MAP_ABS => 3; +use constant MAP_CABS => 4; +use constant MAP_CODE0 => 5; +use constant MAP_CODE1 => 6; +use constant MAP_DATA => 7; +use constant MAP_ISEG => 8; +use constant MAP_CONST => 9; + + # + # If exists the map file, then extracts out of it the labels, + # variables and some segments. + # + +sub read_map_file() + { + my ($addr, $name, $state, $label); + + return if ($map_file eq ''); + + $state = MAP_NULL; + + if (! open(MAP, '<', $map_file)) + { + print STDERR "$PROGRAM : Could not open. -> \"$map_file\"\n"; + exit(1); + } + + while (<MAP>) + { + chomp; + s/\r$//o; + + if ($state == MAP_NULL) + { + $state = MAP_BORDER if (/^Area\s+/io); + } + elsif ($state == MAP_BORDER) + { + $state = MAP_AREA if (/^-+\s+/o); + } + elsif ($state == MAP_AREA) + { + if (/^\.\s+\.ABS\.\s+/o) + { + $state = MAP_ABS; + } + elsif (/^CABS\s+/o) + { + $state = MAP_CABS; + } + elsif (/^(HOME|CSEG)\s+/o) + { + $state = MAP_CODE0; + } + elsif (/^GSINIT\d+\s+/o) + { + $state = MAP_CODE1; + } + elsif (/^(D|O)SEG\s+/o) + { + $state = MAP_DATA; + } + elsif (/^ISEG\s+/o) + { + $state = MAP_ISEG; + } + elsif (/^CONST\s+([[:xdigit:]]+)\s+([[:xdigit:]]+)\s+/o) + { + my ($start, $size) = (hex($1), hex($2)); + + add_const_area($start, $start + $size - 1); + $state = MAP_CONST; + } + elsif (/^SSEG\s+([[:xdigit:]]+)\s+([[:xdigit:]]+)/o) + { + ($stack_start, $stack_size) = (hex($1), hex($2)); + } + else + { + $state = MAP_NULL; + } + } + elsif ($state == MAP_ABS) + { + if (/^.ASxxxx Linker\s+/io) + { + $state = MAP_NULL; + } + elsif (/\s*([[:xdigit:]]+)\s+(\S+)/o) + { + # 000002C0 _Dword xdata + + ($addr, $name) = (hex($1), $2); + + add_xram(hex($1), $2, TRUE) if ($addr > RAM_MAX_ADDR); + } + } + elsif ($state == MAP_CABS) + { + if (/^.ASxxxx Linker\s+/io) + { + $state = MAP_NULL; + } + elsif (/^C:\s+([[:xdigit:]]+)\s+(\S+)/o) + { + ($addr, $name) = (hex($1), $2); + + if ($name eq 's_CONST' || $name eq 's_XINIT') + { + # C: 000001E8 s_CONST + # C: 00000215 s_XINIT + + add_block($addr, BLOCK_CONST, 0, BL_TYPE_CONST, $name); + } + } + } # elsif ($state == MAP_CABS) + elsif ($state == MAP_CODE0 || $state == MAP_CODE1) + { + if (/^.ASxxxx Linker\s+/io) + { + $state = MAP_NULL; + } + elsif (/^C:\s+([[:xdigit:]]+)\s+(\S+)/o) + { + # C: 00000040 __mcs51_genXINIT + # C: 00000061 __mcs51_genRAMCLEAR + # C: 00000067 __mcs51_genXRAMCLEAR + # C: 00000086 _Uart_int main + # C: 000000CE _toHexChar main + # C: 000001E4 __sdcc_external_startup _startup + + ($addr, $name) = (hex($1), $2); + + if ($state == MAP_CODE0) + { + add_func_label($addr, $name, TRUE); + } + else + { + add_jump_label($addr, $name, BL_TYPE_LABEL, EMPTY, TRUE); + } + } + } # elsif ($state == MAP_CODE0 || $state == MAP_CODE1) + elsif ($state == MAP_DATA) + { + if (/^.ASxxxx Linker\s+/io) + { + $state = MAP_NULL; + } + elsif (/^\s*([[:xdigit:]]+)\s+(\S+)/o) + { + # 00000039 _counter data + # 0000004C _flash_read_PARM_2 flash + + add_ram(hex($1), $2, RAM_TYPE_DIR, TRUE); + } + } # elsif ($state == MAP_DATA) + elsif ($state == MAP_ISEG) + { + if (/^.ASxxxx Linker\s+/io) + { + $state = MAP_NULL; + } + elsif (/^\s*([[:xdigit:]]+)\s+(\S+)/o) + { + # 00000082 _length data + + add_ram(hex($1), $2, RAM_TYPE_IND, TRUE); + } + } # elsif ($state == MAP_DATA) + elsif ($state == MAP_CONST) + { + $state = MAP_NULL if (/^.ASxxxx Linker\s+/io); + } + } # while (<MAP>) + + $map_readed = TRUE; + close(MAP); + } + +#------------------------------------------------------------------------------- + +use constant NAMES_NULL => 0; +use constant NAMES_BIT => 1; +use constant NAMES_RAM => 2; +use constant NAMES_IRAM => 3; +use constant NAMES_XRAM => 4; +use constant NAMES_ROM => 5; + +sub read_name_list() + { + my ($line, $addr, $name, $state); + + return if ($name_list eq ''); + + if (! open(NAMES, '<', $name_list)) + { + print STDERR "$PROGRAM : Could not open. -> \"$name_list\"\n"; + exit(1); + } + + $state = NAMES_NULL; + + foreach (grep(! /^\s*$/o, <NAMES>)) + { + chomp; + s/\r$//o; + s/^\s*|\s*$//go; + + if (/^\[BIT\]$/io) + { + $state = NAMES_BIT; + next; + } + elsif (/^\[RAM\]$/io) + { + $state = NAMES_RAM; + next; + } + elsif (/^\[XRAM\]$/io) + { + $state = NAMES_XRAM; + next; + } + elsif (/^\[IRAM\]$/io) + { + $state = NAMES_IRAM; + next; + } + elsif (/^\[ROM\]$/io) + { + $state = NAMES_ROM; + next; + } + + $line = $_; + + given ($state) + { + when (NAMES_BIT) + { + if ($line =~ /^0x([[:xdigit:]]+)\s*:\s*(\S+)$/io) + { + add_bit(hex($1), $2, TRUE); + } + } + + when (NAMES_RAM) + { + if ($line =~ /^0x([[:xdigit:]]+)\s*:\s*(\S+)$/io) + { + add_ram(hex($1), $2, RAM_TYPE_DIR, TRUE); + } + } + + when (NAMES_IRAM) + { + if ($line =~ /^0x([[:xdigit:]]+)\s*:\s*(\S+)$/io) + { + add_ram(hex($1), $2, RAM_TYPE_IND, TRUE); + } + } + + when (NAMES_XRAM) + { + if ($line =~ /^0x([[:xdigit:]]+)\s*:\s*(\S+)$/io) + { + add_xram(hex($1), $2, TRUE); + } + } + + when (NAMES_ROM) + { + if ($line =~ /^0x([[:xdigit:]]+)\s*:\s*(\S+)$/io) + { + add_jump_label(hex($1), $2, BL_TYPE_LABEL, EMPTY, TRUE); + } + } + } # given ($state) + } # foreach (grep(! /^\s*$/o, <NAMES>)) + + close(NAMES); + } + +#------------------------------------------------------------------------------- + + # + # There are some variables that are multi-byte. However, only + # the LSB byte of having a name. This procedure gives a name + # for the higher-significant bytes. + # + +sub fix_multi_byte_variables() + { + my ($prev_addr, $prev_name, $name, $i, $var_size); + + $prev_addr = EMPTY; + $prev_name = ''; + foreach (sort {$a <=> $b} keys(%ram_by_address)) + { + $name = $ram_by_address{$_}->{NAME}; + $ram_names_by_address{$_} = $name; + + if ($prev_addr != EMPTY) + { + $var_size = $_ - $prev_addr; + + if ($var_size > 1) + { + # This is a multi-byte variable. Make the aliases. + + for ($i = 1; $i < $var_size; ++$i) + { + $ram_names_by_address{$prev_addr + $i} = "($prev_name + $i)"; + } + + $ram_by_address{$prev_addr}->{SIZE} = $var_size; + } + } + + $prev_addr = $_; + $prev_name = $name; + } + + $prev_addr = EMPTY; + $prev_name = ''; + foreach (sort {$a <=> $b} keys(%xram_by_address)) + { + $name = $xram_by_address{$_}->{NAME}; + $xram_names_by_address{$_} = $name; + + if ($prev_addr != EMPTY) + { + $var_size = $_ - $prev_addr; + + if ($var_size > 1) + { + # This is a multi-byte variable. Make the aliases. + + for ($i = 1; $i < $var_size; ++$i) + { + $xram_names_by_address{$prev_addr + $i} = "($prev_name + $i)"; + } + + $xram_by_address{$prev_addr}->{SIZE} = $var_size; + } + } + + $prev_addr = $_; + $prev_name = $name; + } + } + +#------------------------------------------------------------------------------- + + # + # If there is left in yet so label that has no name, this here get one. + # + +sub add_names_labels() + { + my ($addr, $label, $fidx, $lidx, $jidx, $jtidx, $cidx, $type); + + $fidx = 0; + $lidx = 0; + $jidx = 0; + $jtidx = 0; + $cidx = 0; + + for ($addr = 0; $addr <= $max_label_addr; ++$addr) + { + $label = $labels_by_address{$addr}; + + next if (! defined($label)); + + $type = $label->{TYPE}; + + next if ($type == BL_TYPE_NONE || (defined($label->{NAME}) && $label->{NAME} ne '')); + + if ($type == BL_TYPE_SUB) + { + $label->{NAME} = sprintf("$label_names{$type}%03u", $fidx++); + } + elsif ($type == BL_TYPE_LABEL) + { + $label->{NAME} = sprintf("$label_names{$type}%03u", $lidx++); + } + elsif ($type == BL_TYPE_JTABLE) + { + $label->{NAME} = sprintf("$label_names{$type}%03u", $jidx++); + } + elsif ($type == BL_TYPE_JLABEL) + { + $label->{NAME} = sprintf("$label_names{$type}%03u", $jtidx++); + } + elsif ($type == BL_TYPE_CONST) + { + $label->{NAME} = sprintf("$label_names{$type}%03u", $cidx++); + } + } + } + +################################################################################ +################################################################################ + +=back + Instruction set of the 8051 family: + + NOP 00000000 + AJMP addr11 aaa00001 aaaaaaaa a10 a9 a8 1 0 0 0 1 a7-a0 + LJMP addr16 00000010 aaaaaaaa aaaaaaaa a15-a8 a7-a0 absolute address + RR A 00000011 + INC A 00000100 + INC direct 00000101 aaaaaaaa register address + INC @Ri 0000011i R0 .. R1 + INC Rn 00001rrr R0 .. R7 + JBC bit, rel 00010000 bbbbbbbb rrrrrrrr bit address relative address + ACALL addr11 aaa10001 aaaaaaaa a10 a9 a8 1 0 0 0 1 a7-a0 + LCALL addr16 00010010 aaaaaaaa aaaaaaaa a15-a8 a7-a0 absolute address + RRC A 00010011 + DEC A 00010100 + DEC direct 00010101 aaaaaaaa register address + DEC @Ri 0001011i R0 .. R1 + DEC Rn 00011rrr R0 .. R7 + JB bit, rel 00100000 bbbbbbbb rrrrrrrr bit address relative address + RET 00100010 + RL A 00100011 + ADD A, #data 00100100 dddddddd adat + ADD A, direct 00100101 aaaaaaaa register address + ADD A, @Ri 0010011i R0 .. R1 + ADD A, Rn 00101rrr R0 .. R7 + JNB bit, rel 00110000 bbbbbbbb rrrrrrrr bit address relative address + RETI 00110010 + RLC A 00110011 + ADDC A, #data 00110100 dddddddd adat + ADDC A, direct 00110101 aaaaaaaa register address + ADDC A, @Ri 0011011i R0 .. R1 + ADDC A, Rn 00111rrr R0 .. R7 + JC rel 01000000 rrrrrrrr relative address + ORL direct, A 01000010 aaaaaaaa register address + ORL direct, #data 01000011 aaaaaaaa dddddddd register address adat + ORL A, #data 01000100 dddddddd adat + ORL A, direct 01000101 aaaaaaaa register address + ORL A, @Ri 0100011i R0 .. R1 + ORL A, Rn 01001rrr R0 .. R7 + JNC rel 01010000 rrrrrrrr relative address + ANL direct, A 01010010 aaaaaaaa register address + ANL direct, #data 01010011 aaaaaaaa dddddddd register address adat + ANL A, #data 01010100 dddddddd adat + ANL A, direct 01010101 aaaaaaaa register address + ANL A, @Ri 0101011i R0 .. R1 + ANL A, Rn 01011rrr R0 .. R7 + JZ rel 01100000 rrrrrrrr relative address + XRL direct, A 01100010 aaaaaaaa register address + XRL direct, #data 01100011 aaaaaaaa dddddddd register address adat + XRL A, #data 01100100 dddddddd adat + XRL A, direct 01100101 aaaaaaaa register address + XRL A, @Ri 0110011i R0 .. R1 + XRL A, Rn 01101rrr R0 .. R7 + JNZ rel 01110000 rrrrrrrr relative address + ORL C, bit 01110010 bbbbbbbb bit address + JMP @A+DPTR 01110011 + MOV A, #data 01110100 dddddddd adat + MOV direct, #data 01110101 aaaaaaaa dddddddd register address adat + MOV @Ri, #data 0111011i dddddddd adat + MOV Rn, #data 01111rrr dddddddd R0 .. R7 adat + SJMP rel 10000000 rrrrrrrr relative address + ANL C, bit 10000010 bbbbbbbb bit address + MOVC A, @A+PC 10000011 + DIV AB 10000100 + MOV direct, direct 10000101 aaaaaaaa aaaaaaaa forrás reg. cél reg. + MOV direct, @Ri 1000011i aaaaaaaa R0 .. R1 register address + MOV direct, Rn 10001rrr aaaaaaaa R0 .. R7 register address + MOV DPTR, #data16 10010000 dddddddd dddddddd d15-d8 d7-d0 + MOV bit, C 10010010 bbbbbbbb bit address + MOVC A, @A+DPTR 10010011 + SUBB A, #data 10010100 dddddddd adat + SUBB A, direct 10010101 aaaaaaaa register address + SUBB A, @Ri 1001011i R0 .. R1 + SUBB A, Rn 10011rrr R0 .. R7 + ORL C, /bit 10100000 bbbbbbbb bit address + MOV C, bit 10100010 bbbbbbbb bit address + INC DPTR 10100011 + MUL AB 10100100 + MOV @Ri, direct 1010011i aaaaaaaa register address + MOV Rn, direct 10101rrr aaaaaaaa R0 .. R7 register address + ANL C, /bit 10110000 bbbbbbbb bit address + CPL bit 10110010 bbbbbbbb bit address + CPL C 10110011 + CJNE A, #data, rel 10110100 dddddddd rrrrrrrr adat relative address + CJNE A, direct, rel 10110101 aaaaaaaa rrrrrrrr register address relative address + CJNE @Ri, #data, rel 1011011i dddddddd rrrrrrrr R0 .. R1 data relative address + CJNE Rn, #data, rel 10111rrr dddddddd rrrrrrrr R0 .. R7 data relative address + PUSH direct 11000000 aaaaaaaa register address + CLR bit 11000010 bbbbbbbb bit address + CLR C 11000011 + SWAP A 11000100 + XCH A, direct 11000101 aaaaaaaa register address + XCH A, @Ri 1100011i R0 .. R1 + XCH A, Rn 11001rrr R0 .. R7 + POP direct 11010000 aaaaaaaa register address + SETB bit 11010010 bbbbbbbb bit address + SETB C 11010011 + DA A 11010100 + DJNZ direct, rel 11010101 aaaaaaaa rrrrrrrr register address relative address + XCHD A, @Ri 1101011i R0 .. R1 + DJNZ Rn, rel 11011rrr rrrrrrrr R0 .. R7 relative address + MOVX A, @DPTR 11100000 + MOVX A, @Ri 1110001i R0 .. R1 + CLR A 11100100 + MOV A, direct 11100101 aaaaaaaa register address The "MOV A, ACC" invalid instruction. + MOV A, @Ri 1110011i R0 .. R1 + MOV A, Rn 11101rrr R0 .. R7 + MOVX @DPTR, A 11110000 + MOVX @Ri, A 1111001i R0 .. R1 + CPL A 11110100 + MOV direct, A 11110101 aaaaaaaa register address + MOV @Ri, A 1111011i R0 .. R1 + MOV Rn, A 11111rrr R0 .. R7 +=cut + +#------------------------------------------------------------------------------- + + # + # Expand a relative offset value. + # + +sub expand_offset($) + { + my $Offset = $_[0]; + + return ($Offset & 0x80) ? -(($Offset ^ 0xFF) + 1) : $Offset; + } + +#------------------------------------------------------------------------------- + + # + # Finds address of branchs and procedures. + # + +sub label_finder($$) + { + my ($Address, $BlockRef) = @_; + my ($instr_size, $instr); + my ($addr, $instr_mask0, $instr_mask1, $instr_mask2); + + $instr_size = $BlockRef->{SIZE}; + $instr = $rom[$Address]; + + $instr_mask0 = $instr & 0x1F; + $instr_mask1 = $instr & 0xFE; + $instr_mask2 = $instr & 0xF8; + + if ($instr_mask0 == INST_AJMP) + { + # AJMP addr11 aaa00001 aaaaaaaa a10 a9 a8 0 0 0 0 1 a7-a0 + + $addr = (($Address + $instr_size) & 0xF800) | (($instr & 0xE0) << 3) | $rom[$Address + 1]; + add_jump_label($addr, '', BL_TYPE_LABEL, $Address, FALSE); + } + elsif ($instr_mask0 == INST_ACALL) + { + # ACALL addr11 aaa10001 aaaaaaaa a10 a9 a8 1 0 0 0 1 a7-a0 + + $addr = (($Address + $instr_size) & 0xF800) | (($instr & 0xE0) << 3) | $rom[$Address + 1]; + add_func_label($addr, '', FALSE); + } + elsif ($instr_mask1 == INST_CJNE__Ri_DATA || + $instr_mask2 == INST_CJNE_Rn_DATA) + { + # CJNE @Ri, #data, rel 1011011i dddddddd rrrrrrrr R0 .. R1 data relative address + # CJNE Rn, #data, rel 10111rrr dddddddd rrrrrrrr R0 .. R7 data relative address + + $addr = $Address + $instr_size + expand_offset($rom[$Address + 2]); + add_jump_label($addr, '', BL_TYPE_LABEL, EMPTY, FALSE); + } + elsif ($instr_mask2 == INST_DJNZ_Rn) + { + # DJNZ Rn, rel 11011rrr rrrrrrrr R0 .. R7 relative address + + $addr = $Address + $instr_size + expand_offset($rom[$Address + 1]); + add_jump_label($addr, '', BL_TYPE_LABEL, EMPTY, FALSE); + } + elsif ($instr == INST_LJMP) + { + # LJMP addr16 00000010 aaaaaaaa aaaaaaaa a15-a8 a7-a0 absolute address + + $addr = ($rom[$Address + 1] << 8) | $rom[$Address + 2]; + add_jump_label($addr, '', BL_TYPE_LABEL, $Address, FALSE); + } + elsif ($instr == INST_LCALL) + { + # LCALL addr16 00010010 aaaaaaaa aaaaaaaa a15-a8 a7-a0 absolute address + + $addr = ($rom[$Address + 1] << 8) | $rom[$Address + 2]; + add_func_label($addr, '', FALSE); + } + elsif ($instr == INST_JBC_BIT || + $instr == INST_JB_BIT || + $instr == INST_JNB_BIT || + $instr == INST_CJNE_A_DATA || + $instr == INST_CJNE_A_DIRECT || + $instr == INST_DJNZ_DIRECT) + { + # JBC bit, rel 00010000 bbbbbbbb rrrrrrrr bit address relative address + # JB bit, rel 00100000 bbbbbbbb rrrrrrrr bit address relative address + # JNB bit, rel 00110000 bbbbbbbb rrrrrrrr bit address relative address + # CJNE A, #data, rel 10110100 dddddddd rrrrrrrr data relative address + # CJNE A, direct, rel 10110101 aaaaaaaa rrrrrrrr register address relative address + # DJNZ direct, rel 11010101 aaaaaaaa rrrrrrrr register address relative address + + $addr = $Address + $instr_size + expand_offset($rom[$Address + 2]); + add_jump_label($addr, '', BL_TYPE_LABEL, EMPTY, FALSE); + } + elsif ($instr == INST_JC || + $instr == INST_JNC || + $instr == INST_JZ || + $instr == INST_JNZ || + $instr == INST_SJMP) + { + # JC rel 01000000 rrrrrrrr relative address + # JNC rel 01010000 rrrrrrrr relative address + # JZ rel 01100000 rrrrrrrr relative address + # JNZ rel 01110000 rrrrrrrr relative address + # SJMP rel 10000000 rrrrrrrr relative address + + $addr = $Address + $instr_size + expand_offset($rom[$Address + 1]); + add_jump_label($addr, '', BL_TYPE_LABEL, EMPTY, FALSE); + } + } + +#------------------------------------------------------------------------------- + + # + # If exists a variable name wich belong to the $Address, then returns it. + # Otherwise, returns the address. + # + +sub reg_name($$) + { + my ($Address, $StrRef) = @_; + my ($ram, $str); + + if ($Address <= BANK_LAST_ADDR) + { + # This register belongs to one of the register bank. + + my $bank = ($Address >> 3) & 3; + my $reg = $Address & 7; + + $str = ($gen_assembly_code) ? sprintf("0x%02X", $Address) : "R${reg}<#$bank>"; + ${$StrRef} = $str; + + if (defined($ram_names_by_address{$Address})) + { + my $var = $ram_names_by_address{$Address}; + + printf STDERR ("This address (0x%02X) belongs to two names: \"$str\" and \"$var\"\n", $Address); + } + } + elsif (defined($ram = $sfr_by_address{$Address}) && $ram->{NAME} ne '') + { + $str = $ram->{NAME}; + ${$StrRef} = $str; + } + elsif (defined($ram = $ram_names_by_address{$Address})) + { + $str = sprintf "0x%02X", $Address; + ${$StrRef} = "[$str]"; + $str = $ram; + } + else + { + $str = sprintf "0x%02X", $Address; + ${$StrRef} = "[$str]"; + } + + return $str; + } + +#------------------------------------------------------------------------------- + + # + # If exists a XRAM name wich belong to the $Address, then returns it. + # Otherwise, returns the address. + # + +sub xram_name($$) + { + my ($Address, $StrRef) = @_; + my ($xram, $str); + + $str = sprintf "0x%04X", $Address; + ${$StrRef} = $str; + + $str = $xram if (defined($xram = $xram_names_by_address{$Address})); + + return $str; + } + +#------------------------------------------------------------------------------- + + # + # If exists a iRAM name wich belong to the $Address, then returns it. + # Otherwise, returns the address. + # + +sub iram_name($$) + { + my ($Address, $StrRef) = @_; + my ($ram, $str); + + $str = sprintf "0x%02X", $Address; + ${$StrRef} = $str; + $ram = $ram_names_by_address{$Address}; + + $str = $ram if (defined($ram)); + + return $str; + } + +#------------------------------------------------------------------------------- + + # + # If exists a bit name wich belong to the $Address, then returns it. + # Otherwise, returns the address. + # + +sub bit_name($$) + { + my ($Address, $StrRef) = @_; + my ($bit, $str); + + if (defined($bit = $sfr_bit_by_address{$Address}) && $bit->{NAME} ne '') + { + $str = $bit->{NAME}; + ${$StrRef} = $str; + } + elsif (defined($bit = $bit_by_address{$Address}) && $bit->{NAME} ne '') + { + $str = sprintf "0x%02X", $Address; + ${$StrRef} = "[$str]"; + $str = $bit->{NAME}; + } + else + { + $str = sprintf "0x%02X", $Address; + ${$StrRef} = "[$str]"; + } + + return $str; + } + +#------------------------------------------------------------------------------- + + # + # If exists a label name wich belong to the $Address, then returns it. + # Otherwise, returns the address. + # + +sub labelname($) + { + my $Address = $_[0]; + my $label = $labels_by_address{$Address}; + + return ((defined($label)) ? $label->{NAME} : (sprintf "0x%04X", $Address)); + } + +#------------------------------------------------------------------------------- + + # + # Auxiliary procedure of prints. + # + +sub print_3($$$) + { + return if ($decoder_silent_level > SILENT0); + + if ($no_explanations) + { + print(($_[1] ne '') ? "$_[0]\t$_[1]\n" : "$_[0]\n"); + } + else + { + print "$_[0]\t" . align($_[1], EXPL_ALIGN_SIZE) . "; $_[2]\n"; + } + } + +#------------------------------------------------------------------------------- + + # + # Invalidates the DPTR and the Rx registers. + # + +sub invalidate_DPTR_Rx() + { + $DPTR = EMPTY; + @R_regs[0 .. 7] = ((EMPTY) x 8); + } + +#------------------------------------------------------------------------------- + + # + # Invalidates the DPTR or the Rx registers. + # + +sub invalidate_reg($) + { + my $Address = $_[0]; + + return if ($Address == EMPTY); + + if ($Address == DPL || $Address == DPH) + { + $DPTR = EMPTY; + } + elsif ($Address <= BANK_LAST_ADDR) + { + $R_regs[$Address & 7] = EMPTY; + } + } + +#------------------------------------------------------------------------------- + + # + # Carries out the operations with the R registers. + # + +use constant Rx_INV => 0; +use constant Rx_INC => 1; +use constant Rx_DEC => 2; +use constant Rx_MOV => 3; + +sub operation_R_reg + { + my $Rx = shift(@_); + my $Oper = shift(@_); + my $r; + + if ($Oper == Rx_INV) + { + $R_regs[$Rx] = EMPTY; + } + elsif ($Oper == Rx_INC) + { + $r = $R_regs[$Rx]; + + if ($r != EMPTY) + { + ++$r; + $R_regs[$Rx] = $r & 0xFF; + return TRUE; + } + } + elsif ($Oper == Rx_DEC) + { + $r = $R_regs[$Rx]; + + if ($r != EMPTY) + { + --$r; + $R_regs[$Rx] = $r & 0xFF; + return TRUE; + } + } + elsif ($Oper == Rx_MOV) + { + $R_regs[$Rx] = shift(@_) & 0xFF; + return TRUE; + } + + return FALSE; + } + +#------------------------------------------------------------------------------- + + # + # If possible, returns the character. + # + +sub present_char($) + { + my $Ch = $_[0]; + + if ($Ch >= ord(' ') && $Ch < 0x7F) + { + return sprintf " {'%c'}", $Ch; + } + elsif (defined($control_characters{$Ch})) + { + return " {'$control_characters{$Ch}'}"; + } + + return ''; + } + +#------------------------------------------------------------------------------- + + # + # Decodes value of the $Ch. + # + +sub decode_char($) + { + my $Ch = $_[0]; + + if ($Ch >= ord(' ') && $Ch < 0x7F) + { + return sprintf "'%c'", $Ch; + } + elsif (defined($control_characters{$Ch})) + { + return "'$control_characters{$Ch}'"; + } + + return sprintf "0x%02X", $Ch; + } + +#------------------------------------------------------------------------------- + + # + # Determines direction of jump. + # + +sub jump_direction($) + { + my $TargetAddr = $_[0]; + + if ($dcd_address < $TargetAddr) + { + return ' (forward)'; + } + elsif ($dcd_address == $TargetAddr) + { + return ''; + } + else + { + return ' (backward)'; + } + } + +#------------------------------------------------------------------------------- + + # + # Returns with TRUE if the instruction use indirect RAM addressing + # with @Ri. + # + +sub is_Ri_instr($) + { + my $Address = $_[0]; + my $block; + + $block = \%{$blocks_by_address{$Address}}; + return FALSE if (! defined($block) || $block->{TYPE} != BLOCK_INSTR); + + # These instructions use indirect RAM addressing with @Ri? + return defined($indirect_addr_instr{$rom[$Address] & 0xFE}); + } + +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@ These the instruction decoders. @@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +sub ajmp() + { + my ($addr, $a11, $rb0, $rb1, $str0, $str1, $str2); + + # AJMP addr11 aaa00001 aaaaaaaa a10 a9 a8 0 0 0 0 1 a7-a0 + + if ($decoder_silent_level == SILENT0) + { + $rb1 = (($dcd_instr & 0xE0) << 3) | $dcd_parm0; + $addr = (($dcd_address + $dcd_instr_size) & 0xF800) | $rb1; + $rb0 = labelname($addr); + $a11 = sprintf "0x%04X", $rb1; + $str0 = sprintf "0x%04X", $addr; + + if ($dcd_address < $addr) + { + $str1 = ''; + $str2 = ' (forward)'; + } + elsif ($dcd_address == $addr) + { + $str1 = ' (endless loop)'; + $str2 = ''; + } + else + { + $str1 = ''; + $str2 = ' (backward)'; + } + + print_3('ajmp', $rb0, "Jumps$str2 hither: $str0 (PC += $dcd_instr_size, PC(10-0) = $a11)$str1"); + } + + invalidate_DPTR_Rx(); + $prev_is_jump = TRUE; + } + +#------------------------------------------------------------------------------- + +sub acall() + { + my ($addr, $rb0, $rb1, $str0, $str1, $str2); + + # ACALL addr11 aaa10001 aaaaaaaa a10 a9 a8 1 0 0 0 1 a7-a0 + + if ($decoder_silent_level == SILENT0) + { + $rb1 = (($dcd_instr & 0xE0) << 3) | $dcd_parm0; + $addr = (($dcd_address + $dcd_instr_size) & 0xF800) | $rb1; + $rb0 = labelname($addr); + $str0 = sprintf "0x%04X", $rb1; + $str1 = sprintf "0x%04X", $addr; + $str2 = jump_direction($addr); + print_3('acall', $rb0, "Calls$str2 this: $str1 (PC += $dcd_instr_size, [++SP] = PCL, [++SP] = PCH, PC(10-0) = $str0)"); + } + + invalidate_DPTR_Rx(); + } + +#------------------------------------------------------------------------------- + +sub inc_ind_Ri() + { + # INC @Ri 0000011i R0 .. R1 + + my $i = $R_regs[$dcd_Ri_regs]; + + add_ram($i, '', RAM_TYPE_IND, FALSE) if ($decoder_silent_level == SILENT1); + + print_3('inc', "\@$dcd_Ri_name", "++[$dcd_Ri_name]"); + invalidate_reg($i); + } + +#------------------------------------------------------------------------------- + +sub dec_ind_Ri() + { + # DEC @Ri 0001011i R0 .. R1 + + my $i = $R_regs[$dcd_Ri_regs]; + + add_ram($i, '', RAM_TYPE_IND, FALSE) if ($decoder_silent_level == SILENT1); + + print_3('dec', "\@$dcd_Ri_name", "--[$dcd_Ri_name]"); + invalidate_reg($i); + } + +#------------------------------------------------------------------------------- + +sub add_A_ind_Ri() + { + # ADD A, @Ri 0010011i R0 .. R1 + + my $i = $R_regs[$dcd_Ri_regs]; + + add_ram($i, '', RAM_TYPE_IND, FALSE) if ($decoder_silent_level == SILENT1); + + print_3('add', "A, \@$dcd_Ri_name", "ACC += [$dcd_Ri_name]"); + } + +#------------------------------------------------------------------------------- + +sub addc_A_ind_Ri() + { + # ADDC A, @Ri 0011011i R0 .. R1 + + my $i = $R_regs[$dcd_Ri_regs]; + + add_ram($i, '', RAM_TYPE_IND, FALSE) if ($decoder_silent_level == SILENT1); + + print_3('addc', "A, \@$dcd_Ri_name", "ACC += [$dcd_Ri_name] + CY"); + } + +#------------------------------------------------------------------------------- + +sub orl_A_ind_Ri() + { + # ORL A, @Ri 0100011i R0 .. R1 + + my $i = $R_regs[$dcd_Ri_regs]; + + add_ram($i, '', RAM_TYPE_IND, FALSE) if ($decoder_silent_level == SILENT1); + + print_3('orl', "A, \@$dcd_Ri_name", "ACC |= [$dcd_Ri_name]"); + } + +#------------------------------------------------------------------------------- + +sub anl_A_ind_Ri() + { + # ANL A, @Ri 0101011i R0 .. R1 + + my $i = $R_regs[$dcd_Ri_regs]; + + add_ram($i, '', RAM_TYPE_IND, FALSE) if ($decoder_silent_level == SILENT1); + + print_3('anl', "A, \@$dcd_Ri_name", "ACC &= [$dcd_Ri_name]"); + } + +#------------------------------------------------------------------------------- + +sub xrl_A_ind_Ri() + { + # XRL A, @Ri 0110011i R0 .. R1 + + my $i = $R_regs[$dcd_Ri_regs]; + + add_ram($i, '', RAM_TYPE_IND, FALSE) if ($decoder_silent_level == SILENT1); + + print_3('xrl', "A, \@$dcd_Ri_name", "ACC ^= [$dcd_Ri_name]"); + } + +#------------------------------------------------------------------------------- + +sub mov_ind_Ri_data() + { + my ($rb, $str); + + # MOV @Ri, #data 0111011i dddddddd data + + my $i = $R_regs[$dcd_Ri_regs]; + + if ($decoder_silent_level == SILENT0) + { + $rb = sprintf "0x%02X", $dcd_parm0; + $str = present_char($dcd_parm0); + print_3('mov', "\@$dcd_Ri_name, #$rb", "[$dcd_Ri_name] = $rb$str"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($i, '', RAM_TYPE_IND, FALSE); + } + + invalidate_reg($i); + } + +#------------------------------------------------------------------------------- + +sub mov_direct_ind_Ri() + { + my ($rb, $name); + + # MOV direct, @Ri 1000011i aaaaaaaa R0 .. R1 register address + + my $i = $R_regs[$dcd_Ri_regs]; + + if ($decoder_silent_level == SILENT0) + { + $rb = reg_name($dcd_parm0, \$name); + print_3('mov', "$rb, \@$dcd_Ri_name", "$name = [$dcd_Ri_name]"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE); + add_ram($i, '', RAM_TYPE_IND, FALSE); + } + + invalidate_reg($dcd_parm0); + } + +#------------------------------------------------------------------------------- + +sub subb_A_ind_Ri() + { + # SUBB A, @Ri 1001011i R0 .. R1 + + my $i = $R_regs[$dcd_Ri_regs]; + + add_ram($i, '', RAM_TYPE_IND, FALSE) if ($decoder_silent_level == SILENT1); + + print_3('subb', "A, \@$dcd_Ri_name", "ACC -= [$dcd_Ri_name] + CY"); + } + +#------------------------------------------------------------------------------- + +sub mov_ind_Ri_direct() + { + my ($rb, $name); + + # MOV @Ri, direct 1010011i aaaaaaaa register address + + my $i = $R_regs[$dcd_Ri_regs]; + + if ($decoder_silent_level == SILENT0) + { + $rb = reg_name($dcd_parm0, \$name); + print_3('mov', "\@$dcd_Ri_name, $rb", "[$dcd_Ri_name] = $name"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE); + add_ram($i, '', RAM_TYPE_IND, FALSE); + } + + invalidate_reg($i); + } + +#------------------------------------------------------------------------------- + +sub cjne_ind_Ri_data() + { + my ($addr, $rb, $str0, $str1, $str2, $str3); + + # CJNE @Ri, #data, rel 1011011i dddddddd rrrrrrrr R0 .. R1 data relative address + + my $i = $R_regs[$dcd_Ri_regs]; + + if ($decoder_silent_level == SILENT0) + { + $addr = $dcd_address + $dcd_instr_size + expand_offset($dcd_parm1); + $rb = labelname($addr); + $str0 = sprintf "0x%02X", $dcd_parm0; + $str1 = sprintf "0x%04X", $addr; + $str2 = jump_direction($addr); + $str3 = present_char($dcd_parm0); + print_3('cjne', "\@$dcd_Ri_name, #$str0, $rb", "If ([$dcd_Ri_name] != $str0$str3) then jumps$str2 hither: $str1"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($i, '', RAM_TYPE_IND, FALSE); + } + + invalidate_DPTR_Rx(); + $prev_is_jump = TRUE; + } + +#------------------------------------------------------------------------------- + +sub xch_A_ind_Ri() + { + # XCH A, @Ri 1100011i R0 .. R1 + + my $i = $R_regs[$dcd_Ri_regs]; + + add_ram($i, '', RAM_TYPE_IND, FALSE) if ($decoder_silent_level == SILENT1); + + print_3('xch', "A, \@$dcd_Ri_name", "ACC <-> [$dcd_Ri_name]"); + invalidate_reg($i); + } + +#------------------------------------------------------------------------------- + +sub xchd_A_ind_Ri() + { + # XCHD A, @Ri 1101011i R0 .. R1 + + my $i = $R_regs[$dcd_Ri_regs]; + + add_ram($i, '', RAM_TYPE_IND, FALSE) if ($decoder_silent_level == SILENT1); + + print_3('xchd', "A, \@$dcd_Ri_name", "ACC(3-0) <-> [$dcd_Ri_name](3-0)"); + invalidate_reg($i); + } + +#------------------------------------------------------------------------------- + +sub movx_A_ind_Ri() + { + # MOVX A, @Ri 1110001i R0 .. R1 + + my $i = $R_regs[$dcd_Ri_regs]; + + add_xram($i, '', FALSE) if ($i != EMPTY && $decoder_silent_level == SILENT1); + + print_3('movx', "A, \@$dcd_Ri_name", "ACC = XRAM[$dcd_Ri_name]"); + } + +#------------------------------------------------------------------------------- + +sub mov_A_ind_Ri() + { + # MOV A, @Ri 1110011i R0 .. R1 + + my $i = $R_regs[$dcd_Ri_regs]; + + add_ram($i, '', RAM_TYPE_IND, FALSE) if ($decoder_silent_level == SILENT1); + + print_3('mov', "A, \@$dcd_Ri_name", "ACC = [$dcd_Ri_name]"); + } + +#------------------------------------------------------------------------------- + +sub movx_ind_Ri_A() + { + # MOVX @Ri, A 1111001i R0 .. R1 + + my $i = $R_regs[$dcd_Ri_regs]; + + add_xram($i, '', FALSE) if ($i != EMPTY && $decoder_silent_level == SILENT1); + + print_3('movx', "\@$dcd_Ri_name, A", "XRAM[$dcd_Ri_name] = ACC"); + invalidate_reg($i); + } + +#------------------------------------------------------------------------------- + +sub mov_ind_Ri_A() + { + # MOV @Ri, A 1111011i R0 .. R1 + + my $i = $R_regs[$dcd_Ri_regs]; + + add_ram($i, '', RAM_TYPE_IND, FALSE) if ($decoder_silent_level == SILENT1); + + print_3('mov', "\@$dcd_Ri_name, A", "[$dcd_Ri_name] = ACC"); + invalidate_reg($i); + } + +#------------------------------------------------------------------------------- + +sub inc_Rn() + { + my $str = ''; + + # INC Rn 00001rrr R0 .. R7 + + if (operation_R_reg($dcd_Rn_regs, Rx_INC)) + { + $str = sprintf " (0x%02X)", $R_regs[$dcd_Rn_regs]; + } + + print_3('inc', $dcd_Rn_name, "++$dcd_Rn_name$str"); + } + +#------------------------------------------------------------------------------- + +sub dec_Rn() + { + my $str = ''; + + # DEC Rn 00011rrr R0 .. R7 + + if (operation_R_reg($dcd_Rn_regs, Rx_DEC)) + { + $str = sprintf " (0x%02X)", $R_regs[$dcd_Rn_regs]; + } + + print_3('dec', $dcd_Rn_name, "--$dcd_Rn_name$str"); + } + +#------------------------------------------------------------------------------- + +sub add_A_Rn() + { + # ADD A, Rn 00101rrr R0 .. R7 + + print_3('add', "A, $dcd_Rn_name", "ACC += $dcd_Rn_name"); + } + +#------------------------------------------------------------------------------- + +sub addc_A_Rn() + { + # ADDC A, Rn 00111rrr R0 .. R7 + + print_3('addc', "A, $dcd_Rn_name", "ACC += $dcd_Rn_name + CY"); + } + +#------------------------------------------------------------------------------- + +sub orl_A_Rn() + { + # ORL A, Rn 01001rrr R0 .. R7 + + print_3('orl', "A, $dcd_Rn_name", "ACC |= $dcd_Rn_name"); + } + +#------------------------------------------------------------------------------- + +sub anl_A_Rn() + { + # ANL A, Rn 01011rrr R0 .. R7 + + print_3('anl', "A, $dcd_Rn_name", "ACC &= $dcd_Rn_name"); + } + +#------------------------------------------------------------------------------- + +sub xrl_A_Rn() + { + # XRL A, Rn 01101rrr R0 .. R7 + + print_3('xrl', "A, $dcd_Rn_name", "ACC ^= $dcd_Rn_name"); + } + +#------------------------------------------------------------------------------- + +sub mov_Rn_data() + { + my ($rb, $name, $str); + + # MOV Rn, #data 01111rrr dddddddd R0 .. R7 data + + if ($decoder_silent_level == SILENT0) + { + if (($dcd_Rn_regs == 0 || $dcd_Rn_regs == 1) && is_Ri_instr($dcd_address + $dcd_instr_size)) + { + $rb = iram_name($dcd_parm0, \$name); + print_3('mov', "$dcd_Rn_name, #$rb", "$dcd_Rn_name = $name"); + } + else + { + $rb = sprintf "0x%02X", $dcd_parm0; + $str = present_char($dcd_parm0); + print_3('mov', "$dcd_Rn_name, #$rb", "$dcd_Rn_name = $rb$str"); + } + } + + operation_R_reg($dcd_Rn_regs, Rx_MOV, $dcd_parm0); + } + +#------------------------------------------------------------------------------- + +sub mov_direct_Rn() + { + my ($rb, $name); + + # MOV direct, Rn 10001rrr aaaaaaaa R0 .. R7 register address + + if ($decoder_silent_level == SILENT0) + { + $rb = reg_name($dcd_parm0, \$name); + print_3('mov', "$rb, $dcd_Rn_name", "$name = $dcd_Rn_name"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE); + } + + invalidate_reg($dcd_parm0); + } + +#------------------------------------------------------------------------------- + +sub subb_A_Rn() + { + # SUBB A, Rn 10011rrr R0 .. R7 + + print_3('subb', "A, $dcd_Rn_name", "ACC -= $dcd_Rn_name + CY"); + } + +#------------------------------------------------------------------------------- + +sub mov_Rn_direct() + { + my ($rb, $name); + + # MOV Rn, direct 10101rrr aaaaaaaa R0 .. R7 register address + + if ($decoder_silent_level == SILENT0) + { + $rb = reg_name($dcd_parm0, \$name); + print_3('mov', "$dcd_Rn_name, $rb", "$dcd_Rn_name = $name"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE); + } + + operation_R_reg($dcd_Rn_regs, Rx_INV); + } + +#------------------------------------------------------------------------------- + +sub cjne_Rn_data() + { + my ($addr, $rb, $str0, $str1, $str2, $str3); + + # CJNE Rn, #data, rel 10111rrr dddddddd rrrrrrrr R0 .. R7 data relative address + + if ($decoder_silent_level == SILENT0) + { + $addr = $dcd_address + $dcd_instr_size + expand_offset($dcd_parm1); + $rb = labelname($addr); + $str0 = sprintf "0x%02X", $dcd_parm0; + $str1 = sprintf "0x%04X", $addr; + $str2 = jump_direction($addr); + $str3 = present_char($dcd_parm0); + print_3('cjne', "$dcd_Rn_name, #$str0, $rb", "If ($dcd_Rn_name != $str0$str3) then jumps$str2 hither: $str1"); + } + + invalidate_DPTR_Rx(); + $prev_is_jump = TRUE; + } + +#------------------------------------------------------------------------------- + +sub xch_A_Rn() + { + # XCH A, Rn 11001rrr R0 .. R7 + + print_3('xch', "A, $dcd_Rn_name", "ACC <-> $dcd_Rn_name"); + operation_R_reg($dcd_Rn_regs, Rx_INV); + } + +#------------------------------------------------------------------------------- + +sub djnz_Rn() + { + my ($addr, $rb, $str0, $str1, $str2); + + # DJNZ Rn, rel 11011rrr rrrrrrrr R0 .. R7 relative address + + if ($decoder_silent_level == SILENT0) + { + $addr = $dcd_address + $dcd_instr_size + expand_offset($dcd_parm0); + $rb = labelname($addr); + $str0 = ($dcd_address == $addr) ? ' (waiting loop)' : ''; + $str1 = sprintf "0x%04X", $addr; + $str2 = jump_direction($addr); + print_3('djnz', "$dcd_Rn_name, $rb", "If (--$dcd_Rn_name != 0) then jumps$str2 hither: $str1$str0"); + } + + invalidate_DPTR_Rx(); + $prev_is_jump = TRUE; + } + +#------------------------------------------------------------------------------- + +sub mov_A_Rn() + { + # MOV A, Rn 11101rrr R0 .. R7 + + print_3('mov', "A, $dcd_Rn_name", "ACC = $dcd_Rn_name"); + } + +#------------------------------------------------------------------------------- + +sub mov_Rn_A() + { + # MOV Rn, A 11111rrr R0 .. R7 + + print_3('mov', "$dcd_Rn_name, A", "$dcd_Rn_name = ACC"); + operation_R_reg($dcd_Rn_regs, Rx_INV); + } + +#------------------------------------------------------------------------------- + +sub nop() + { + # NOP 00000000 + print "nop\n" if ($decoder_silent_level == SILENT0); + } + +#------------------------------------------------------------------------------- + +sub ljmp() + { + my ($addr, $rb, $str0, $str1, $str2); + + # LJMP addr16 00000010 aaaaaaaa aaaaaaaa a15-a8 a7-a0 absolute address + + if ($decoder_silent_level == SILENT0) + { + $addr = ($dcd_parm0 << 8) | $dcd_parm1; + $rb = labelname($addr); + $str0 = sprintf "0x%04X", $addr; + + if ($dcd_address < $addr) + { + $str1 = ''; + $str2 = ' (forward)'; + } + elsif ($dcd_address == $addr) + { + $str1 = ' (endless loop)'; + $str2 = ''; + } + else + { + $str1 = ''; + $str2 = ' (backward)'; + } + + print_3('ljmp', $rb, "Jumps$str2 hither: $str0$str1"); + } + + invalidate_DPTR_Rx(); + $prev_is_jump = TRUE; + } + +#------------------------------------------------------------------------------- + +sub rr_A() + { + # RR A 00000011 + + print_3('rr', 'A', 'ACC[76543210] = ACC[07654321]'); + } + +#------------------------------------------------------------------------------- + +sub inc_A() + { + # INC A 00000100 + + print_3('inc', 'A', '++ACC'); + } + +#------------------------------------------------------------------------------- + +sub inc_direct() + { + my ($rb, $name); + + # INC direct 00000101 aaaaaaaa register address + + if ($decoder_silent_level == SILENT0) + { + $rb = reg_name($dcd_parm0, \$name); + print_3('inc', $rb, "++$name"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE); + } + + invalidate_reg($dcd_parm0); + } + +#------------------------------------------------------------------------------- + +sub jbc_bit() + { + my ($addr, $rb0, $rb1, $name0, $str0, $str1); + + # JBC bit, rel 00100000 bbbbbbbb rrrrrrrr bit address relative address + + if ($decoder_silent_level == SILENT0) + { + $addr = $dcd_address + $dcd_instr_size + expand_offset($dcd_parm1); + $rb0 = bit_name($dcd_parm0, \$name0); + $rb1 = labelname($addr); + $str0 = sprintf "0x%04X", $addr; + $str1 = jump_direction($addr); + print_3('jbc', "$rb0, $rb1", "If ($name0 == H) then $name0 = L and jumps$str1 hither: $str0"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_bit($dcd_parm0, '', FALSE); + } + + invalidate_DPTR_Rx(); + $prev_is_jump = TRUE; + } + +#------------------------------------------------------------------------------- + +sub lcall() + { + my ($addr, $rb, $str0, $str1); + + # LCALL addr16 00010010 aaaaaaaa aaaaaaaa a15-a8 a7-a0 absolute address + + if ($decoder_silent_level == SILENT0) + { + $addr = ($dcd_parm0 << 8) | $dcd_parm1; + $rb = labelname($addr); + $str0 = sprintf "0x%04X", $addr; + $str1 = jump_direction($addr); + print_3('lcall', $rb, "Calls$str1 this: $str0 (PC += $dcd_instr_size, [++SP] = PCL, [++SP] = PCH, PC = $str0)"); + } + + invalidate_DPTR_Rx(); + } + +#------------------------------------------------------------------------------- + +sub rrc_A() + { + # RRC A 00010011 + + print_3('rrc', 'A', 'ACC[76543210] = ACC[C7654321], CY = ACC[0]'); + } + +#------------------------------------------------------------------------------- + +sub dec_A() + { + # DEC A 00010100 + + print_3('dec', 'A', '--ACC'); + } + +#------------------------------------------------------------------------------- + +sub dec_direct() + { + my ($rb, $name); + + # DEC direct 00010101 aaaaaaaa register address + + if ($decoder_silent_level == SILENT0) + { + $rb = reg_name($dcd_parm0, \$name); + print_3('dec', $rb, "--$name"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE); + } + + invalidate_reg($dcd_parm0); + } + +#------------------------------------------------------------------------------- + +sub jb_bit() + { + my ($addr, $rb0, $rb1, $name0, $str0, $str1, $str2); + + # JB bit, rel 00100000 bbbbbbbb rrrrrrrr bit address relative address + + if ($decoder_silent_level == SILENT0) + { + $addr = $dcd_address + $dcd_instr_size + expand_offset($dcd_parm1); + $rb0 = bit_name($dcd_parm0, \$name0); + $rb1 = labelname($addr); + $str0 = ($dcd_address == $addr) ? ' (waiting loop)' : ''; + $str1 = sprintf "0x%04X", $addr; + $str2 = jump_direction($addr); + print_3('jb', "$rb0, $rb1", "If ($name0 == H) then jumps$str2 hither: $str1$str0"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_bit($dcd_parm0, '', FALSE); + } + + invalidate_DPTR_Rx(); + $prev_is_jump = TRUE; + } + +#------------------------------------------------------------------------------- + +sub ret() + { + # RET 00100010 + + print_3('ret', '', 'PCH = [SP--], PCL = [SP--]'); + invalidate_DPTR_Rx(); + $prev_is_jump = TRUE; + } + +#------------------------------------------------------------------------------- + +sub rl_A() + { + # RL A 00100011 + + print_3('rl', 'A', 'ACC[76543210] = ACC[65432107]'); + } + +#------------------------------------------------------------------------------- + +sub add_A_data() + { + my ($rb, $str); + + # ADD A, #data 00100100 dddddddd data + + if ($decoder_silent_level == SILENT0) + { + $rb = sprintf "0x%02X", $dcd_parm0; + $str = present_char($dcd_parm0); + print_3('add', "A, #$rb", "ACC += $rb$str"); + } + } + +#------------------------------------------------------------------------------- + +sub add_A_direct() + { + my ($rb, $name); + + # ADD A, direct 00100101 aaaaaaaa register address + + if ($decoder_silent_level == SILENT0) + { + $rb = reg_name($dcd_parm0, \$name); + print_3('add', "A, $rb", "ACC += $name"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE); + } + } + +#------------------------------------------------------------------------------- + +sub jnb_bit() + { + my ($addr, $rb0, $rb1, $name0, $str0, $str1, $str2); + + # JNB bit, rel 00110000 bbbbbbbb rrrrrrrr bit address relative address + + if ($decoder_silent_level == SILENT0) + { + $addr = $dcd_address + $dcd_instr_size + expand_offset($dcd_parm1); + $rb0 = bit_name($dcd_parm0, \$name0); + $rb1 = labelname($addr); + $str0 = ($dcd_address == $addr) ? ' (waiting loop)' : ''; + $str1 = sprintf "0x%04X", $addr; + $str2 = jump_direction($addr); + print_3('jnb', "$rb0, $rb1", "If ($name0 == L) then jumps$str2 hither: $str1$str0"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_bit($dcd_parm0, '', FALSE); + } + + invalidate_DPTR_Rx(); + $prev_is_jump = TRUE; + } + +#------------------------------------------------------------------------------- + +sub reti() + { + # RETI 00110010 + + print_3('reti', '', 'PCH = [SP--], PCL = [SP--]'); + invalidate_DPTR_Rx(); + $prev_is_jump = TRUE; + } + +#------------------------------------------------------------------------------- + +sub rcl_A() + { + # RLC A 00110011 + + print_3('rlc', 'A', 'ACC[76543210] = ACC[6543210C], CY = ACC[7]'); + } + +#------------------------------------------------------------------------------- + +sub addc_A_data() + { + my ($rb, $str); + + # ADDC A, #data 00110100 dddddddd data + + if ($decoder_silent_level == SILENT0) + { + $rb = sprintf "0x%02X", $dcd_parm0; + $str = present_char($dcd_parm0); + print_3('addc', "A, #$rb", "ACC += $rb + CY$str"); + } + } + +#------------------------------------------------------------------------------- + +sub addc_A_direct() + { + my ($rb, $name); + + # ADDC A, direct 00110101 aaaaaaaa register address + + if ($decoder_silent_level == SILENT0) + { + $rb = reg_name($dcd_parm0, \$name); + print_3('addc', "A, $rb", "ACC += $name + CY"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE); + } + } + +#------------------------------------------------------------------------------- + +sub jc() + { + my ($addr, $rb, $str0, $str1); + + # JC rel 01000000 rrrrrrrr relative address + + if ($decoder_silent_level == SILENT0) + { + $addr = $dcd_address + $dcd_instr_size + expand_offset($dcd_parm0); + $rb = labelname($addr); + $str0 = sprintf "0x%04X", $addr; + $str1 = jump_direction($addr); + print_3('jc', $rb, "If (CY == H) then jumps$str1 hither: $str0"); + } + + invalidate_DPTR_Rx(); + $prev_is_jump = TRUE; + } + +#------------------------------------------------------------------------------- + +sub orl_direct_A() + { + my ($rb, $name); + + # ORL direct, A 01000010 aaaaaaaa register address + + if ($decoder_silent_level == SILENT0) + { + $rb = reg_name($dcd_parm0, \$name); + print_3('orl', "$rb, A", "$name |= ACC"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE); + } + + invalidate_reg($dcd_parm0); + } + +#------------------------------------------------------------------------------- + +sub orl_direct_data() + { + my ($rb0, $rb1, $name, $str); + + # ORL direct, #data 01000011 aaaaaaaa dddddddd register address data + + if ($decoder_silent_level == SILENT0) + { + $rb0 = reg_name($dcd_parm0, \$name); + $rb1 = sprintf "0x%02X", $dcd_parm1; + $str = present_char($dcd_parm1); + } + + if ($dcd_parm0 == PSW) + { + my $bank = ($dcd_parm1 >> 3) & 0x03; + + $used_banks{$bank} = TRUE; + + if ($decoder_silent_level == SILENT0) + { + $str = " (select bank #$bank)" if (($dcd_parm1 & ~0x18) == 0x00); + } + } + + if ($decoder_silent_level == SILENT0) + { + print_3('orl', "$rb0, #$rb1", "$name |= $rb1$str"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE); + } + + invalidate_reg($dcd_parm0); + } + +#------------------------------------------------------------------------------- + +sub orl_A_data() + { + my ($rb, $str); + + # ORL A, #data 01000100 dddddddd data + + if ($decoder_silent_level == SILENT0) + { + $rb = sprintf "0x%02X", $dcd_parm0; + $str = present_char($dcd_parm0); + print_3('orl', "A, #$rb", "ACC |= $rb$str"); + } + } + +#------------------------------------------------------------------------------- + +sub orl_A_direct() + { + my ($rb, $name); + + # ORL A, direct 01000101 aaaaaaaa register address + + if ($decoder_silent_level == SILENT0) + { + $rb = reg_name($dcd_parm0, \$name); + print_3('orl', "A, $rb", "ACC |= $name"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE); + } + } + +#------------------------------------------------------------------------------- + +sub jnc() + { + my ($addr, $rb, $str0, $str1); + + # JNC rel 01010000 rrrrrrrr relative address + + if ($decoder_silent_level == SILENT0) + { + $addr = $dcd_address + $dcd_instr_size + expand_offset($dcd_parm0); + $rb = labelname($addr); + $str0 = sprintf "0x%04X", $addr; + $str1 = jump_direction($addr); + print_3('jnc', $rb, "If (CY == L) then jumps$str1 hither: $str0"); + } + + invalidate_DPTR_Rx(); + $prev_is_jump = TRUE; + } + +#------------------------------------------------------------------------------- + +sub anl_direct_A() + { + my ($rb, $name); + + # ANL direct, A 01010010 aaaaaaaa register address + + if ($decoder_silent_level == SILENT0) + { + $rb = reg_name($dcd_parm0, \$name); + print_3('anl', "$rb, A", "$name &= ACC"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE); + } + + invalidate_reg($dcd_parm0); + } + +#------------------------------------------------------------------------------- + +sub anl_direct_data() + { + my ($rb0, $rb1, $name, $str); + + # ANL direct, #data 01010011 aaaaaaaa dddddddd register address data + + if ($decoder_silent_level == SILENT0) + { + $rb0 = reg_name($dcd_parm0, \$name); + $rb1 = sprintf "0x%02X", $dcd_parm1; + $str = present_char($dcd_parm1); + print_3('anl', "$rb0, #$rb1", "$name &= $rb1$str"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE); + } + + invalidate_reg($dcd_parm0); + } + +#------------------------------------------------------------------------------- + +sub anl_A_data() + { + my ($rb, $str); + + # ANL A, #data 01010100 dddddddd data + + if ($decoder_silent_level == SILENT0) + { + $rb = sprintf "0x%02X", $dcd_parm0; + $str = present_char($dcd_parm0); + print_3('anl', "A, #$rb", "ACC &= $rb$str"); + } + } + +#------------------------------------------------------------------------------- + +sub anl_A_direct() + { + my ($rb, $name); + + # ANL A, direct 01010101 aaaaaaaa register address + + if ($decoder_silent_level == SILENT0) + { + $rb = reg_name($dcd_parm0, \$name); + print_3('anl', "A, $rb", "ACC &= $name"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE); + } + } + +#------------------------------------------------------------------------------- + +sub jz() + { + my ($addr, $rb, $str0, $str1); + + # JZ rel 01100000 rrrrrrrr relative address + + if ($decoder_silent_level == SILENT0) + { + $addr = $dcd_address + $dcd_instr_size + expand_offset($dcd_parm0); + $rb = labelname($addr); + $str0 = sprintf "0x%04X", $addr; + $str1 = jump_direction($addr); + print_3('jz', $rb, "If (ACC == 0) then jumps$str1 hither: $str0"); + } + + invalidate_DPTR_Rx(); + $prev_is_jump = TRUE; + } + +#------------------------------------------------------------------------------- + +sub xrl_direct_A() + { + my ($rb, $name); + + # XRL direct, A 01100010 aaaaaaaa register address + + if ($decoder_silent_level == SILENT0) + { + $rb = reg_name($dcd_parm0, \$name); + print_3('xrl', "$rb, A", "$name ^= ACC"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE); + } + + invalidate_reg($dcd_parm0); + } + +#------------------------------------------------------------------------------- + +sub xrl_direct_data() + { + my ($rb0, $rb1, $name, $str); + + # XRL direct, #data 01100011 aaaaaaaa dddddddd register address data + + if ($decoder_silent_level == SILENT0) + { + $rb0 = reg_name($dcd_parm0, \$name); + $rb1 = sprintf "0x%02X", $dcd_parm1; + $str = present_char($dcd_parm1); + print_3('xrl', "$rb0, #$rb1", "$name |= $rb1$str"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE); + } + + invalidate_reg($dcd_parm0); + } + +#------------------------------------------------------------------------------- + +sub xrl_A_data() + { + my ($rb, $str); + + # XRL A, #data 01100100 dddddddd data + + if ($decoder_silent_level == SILENT0) + { + $rb = sprintf "0x%02X", $dcd_parm0; + $str = present_char($dcd_parm0); + print_3('xrl', "A, #$rb", "ACC ^= $rb$str"); + } + } + +#------------------------------------------------------------------------------- + +sub xrl_A_direct() + { + my ($rb, $name); + + # XRL A, direct 01100101 aaaaaaaa register address + + if ($decoder_silent_level == SILENT0) + { + $rb = reg_name($dcd_parm0, \$name); + print_3('xrl', "A, $rb", "ACC |= $name"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE); + } + } + +#------------------------------------------------------------------------------- + +sub jnz() + { + my ($addr, $rb, $str0, $str1); + + # JNZ rel 01110000 rrrrrrrr relative address + + if ($decoder_silent_level == SILENT0) + { + $addr = $dcd_address + $dcd_instr_size + expand_offset($dcd_parm0); + $rb = labelname($addr); + $str0 = sprintf "0x%04X", $addr; + $str1 = jump_direction($addr); + print_3('jnz', $rb, "If (ACC != 0) then jumps$str1 hither: $str0"); + } + + invalidate_DPTR_Rx(); + $prev_is_jump = TRUE; + } + +#------------------------------------------------------------------------------- + +sub orl_C_bit() + { + my ($rb, $name); + + # ORL C, bit 01110010 bbbbbbbb bit address + + if ($decoder_silent_level == SILENT0) + { + $rb = bit_name($dcd_parm0, \$name); + print_3('orl', "C, $rb", "CY |= $name"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_bit($dcd_parm0, '', FALSE); + } + } + +#------------------------------------------------------------------------------- + +sub jmp_A_DPTR() + { + my $str; + + # JMP @A+DPTR 01110011 + + if ($DPTR != EMPTY) + { + add_jump_label($DPTR, '', BL_TYPE_JTABLE, EMPTY, FALSE); + $str = jump_direction($DPTR); + } + else + { + $str = ''; + } + + print_3('jmp', '@A+DPTR', "Jumps$str hither: [DPTR + ACC]"); + invalidate_DPTR_Rx(); + $prev_is_jump = TRUE; + } + +#------------------------------------------------------------------------------- + +sub mov_A_data() + { + my ($rb, $str); + + # MOV A, #data 01110100 dddddddd data + + if ($decoder_silent_level == SILENT0) + { + $rb = sprintf "0x%02X", $dcd_parm0; + $str = present_char($dcd_parm0); + print_3('mov', "A, #$rb", "ACC = $rb$str"); + } + } + +#------------------------------------------------------------------------------- + +sub mov_direct_data() + { + my ($rb0, $rb1, $name, $str); + + # MOV direct, #data 01110101 aaaaaaaa dddddddd register address data + + if ($decoder_silent_level == SILENT0) + { + $rb0 = reg_name($dcd_parm0, \$name); + $rb1 = sprintf "0x%02X", $dcd_parm1; + $str = ''; + } + + if ($dcd_parm0 == PSW) + { + my $bank = ($dcd_parm1 >> 3) & 0x03; + + $used_banks{$bank} = TRUE; + + if ($decoder_silent_level == SILENT0) + { + $str = " (select bank #$bank)" if (($dcd_parm1 & ~0x18) == 0x00); + } + } +# elsif ($dcd_parm0 == SP) +# { +# $stack_start = ($dcd_parm1 + 1) if ($stack_start < 0); +# } + else + { + $str = present_char($dcd_parm1); + } + + if ($decoder_silent_level == SILENT0) + { + print_3('mov', "$rb0, #$rb1", "$name = $rb1$str"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE); + } + + invalidate_reg($dcd_parm0); + } + +#------------------------------------------------------------------------------- + +sub sjmp() + { + my ($addr, $rb0, $rb1, $name0, $name1, $str0, $str1, $str2); + + # SJMP rel 10000000 rrrrrrrr relative address + + if ($decoder_silent_level == SILENT0) + { + $addr = $dcd_address + $dcd_instr_size + expand_offset($dcd_parm0); + $rb0 = labelname($addr); + $str0 = ($dcd_address == $addr) ? ' (endless loop)' : ''; + $str1 = sprintf "0x%04X", $addr; + $str2 = jump_direction($addr); + print_3('sjmp', $rb0, "Jumps$str2 hither: $str1$str0"); + } + + invalidate_DPTR_Rx(); + $prev_is_jump = TRUE; + } + +#------------------------------------------------------------------------------- + +sub anl_C_bit() + { + my ($rb, $name); + + # ANL C, bit 10000010 bbbbbbbb bit address + + if ($decoder_silent_level == SILENT0) + { + $rb = bit_name($dcd_parm0, \$name); + print_3('anl', "C, $rb", "CY &= $name"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_bit($dcd_parm0, '', FALSE); + } + } + +#------------------------------------------------------------------------------- + +sub movc_A_A_PC() + { + # MOVC A, @A+PC 10000011 + + print_3('movc', 'A, @A+PC', "ACC = ROM[PC + $dcd_instr_size + ACC]"); + } + +#------------------------------------------------------------------------------- + +sub div_AB() + { + # DIV AB 10000100 + + print_3('div', 'AB', 'ACC = ACC / B, B = ACC % B'); + } + +#------------------------------------------------------------------------------- + +sub mov_direct_direct() + { + my ($rb0, $rb1, $name0, $name1); + + # MOV direct, direct 10000101 aaaaaaaa aaaaaaaa forrás reg. cél reg. + + if ($decoder_silent_level == SILENT0) + { + $rb0 = reg_name($dcd_parm0, \$name0); + $rb1 = reg_name($dcd_parm1, \$name1); + print_3('mov', "$rb1, $rb0", "$name1 = $name0"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE); + add_ram($dcd_parm1, '', RAM_TYPE_DIR, FALSE); + } + + invalidate_reg($dcd_parm0); + } + +#------------------------------------------------------------------------------- + +sub mov_DPTR_data() + { + my ($addr, $str, $name); + + # MOV DPTR, #data16 10010000 dddddddd dddddddd d15-d8 d7-d0 + + $addr = ($dcd_parm0 << 8) | $dcd_parm1; + + if ($decoder_silent_level == SILENT0) + { + $str = xram_name($addr, \$name); + print_3('mov', "DPTR, #$str", "DPTR = $name"); + } + + $DPTR = $addr; + } + +#------------------------------------------------------------------------------- + +sub mov_bit_C() + { + my ($rb, $name); + + # MOV bit, C 10010010 bbbbbbbb bit address + + if ($decoder_silent_level == SILENT0) + { + $rb = bit_name($dcd_parm0, \$name); + print_3('mov', "$rb, C", "$name = CY"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_bit($dcd_parm0, '', FALSE); + } + } + +#------------------------------------------------------------------------------- + +sub movc_A_A_DPTR() + { + # MOVC A, @A+DPTR 10010011 + + add_jump_label($DPTR, '', BL_TYPE_LABEL, EMPTY, FALSE) if ($DPTR != EMPTY); + + print_3('movc', 'A, @A+DPTR', 'ACC = ROM[DPTR + ACC]'); + } + +#------------------------------------------------------------------------------- + +sub subb_A_data() + { + my ($rb, $str); + + # SUBB A, #data 10010100 dddddddd data + + if ($decoder_silent_level == SILENT0) + { + $rb = sprintf "0x%02X", $dcd_parm0; + $str = present_char($dcd_parm0); + print_3('subb', "A, #$rb", "ACC -= $rb + CY$str"); + } + } + +#------------------------------------------------------------------------------- + +sub subb_A_direct() + { + my ($rb, $name); + + # SUBB A, direct 10010101 aaaaaaaa register address + + if ($decoder_silent_level == SILENT0) + { + $rb = reg_name($dcd_parm0, \$name); + print_3('subb', "A, $rb", "ACC -= $name + CY"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE); + } + } + +#------------------------------------------------------------------------------- + +sub orl_C__bit() + { + my ($rb, $name); + + # ORL C, /bit 10100000 bbbbbbbb bit address + + if ($decoder_silent_level == SILENT0) + { + $rb = bit_name($dcd_parm0, \$name); + print_3('orl', "C, /$rb", "CY = ~$name"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_bit($dcd_parm0, '', FALSE); + } + } + +#------------------------------------------------------------------------------- + +sub mov_C_bit() + { + my ($rb, $name); + + # MOV C, bit 10100010 bbbbbbbb bit address + + if ($decoder_silent_level == SILENT0) + { + $rb = bit_name($dcd_parm0, \$name); + print_3('mov', "C, $rb", "CY = $name"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_bit($dcd_parm0, '', FALSE); + } + } + +#------------------------------------------------------------------------------- + +sub inc_DPTR() + { + my $str; + + # INC DPTR 10100011 + + if ($DPTR != EMPTY) + { + ++$DPTR; + $str = sprintf " (0x%04X)", $DPTR; + } + else + { + $str = ''; + } + + print_3('inc', 'DPTR', "++DPTR$str"); + } + +#------------------------------------------------------------------------------- + +sub mul_AB() + { + # MUL AB 10100100 + + print_3('mul', 'AB', 'B:ACC = ACC * B'); + } + +#------------------------------------------------------------------------------- + +sub unknown() + { + my ($rb, $str0, $str1); + + # The unknown instruction is actually simple embedded data in the code. + + if ($decoder_silent_level == SILENT0) + { + $rb = sprintf "0x%02X", $dcd_instr & 0xFF; + $str0 = present_char($dcd_instr); + $str1 = sprintf "0x%04X", $dcd_address; + print_3('.db', $rb, "$str1: $rb$str0"); + + if ($dcd_instr_size == 2) + { + $rb = sprintf "0x%02X", $dcd_parm0 & 0xFF; + $str0 = present_char($dcd_parm0); + $str1 = sprintf "0x%04X", $dcd_address; + print_3('.db', $rb, "$str1: $rb$str0"); + } + elsif ($dcd_instr_size == 3) + { + $rb = sprintf "0x%02X", $dcd_parm1 & 0xFF; + $str0 = present_char($dcd_parm1); + $str1 = sprintf "0x%04X", $dcd_address; + print_3('.db', $rb, "$str1: $rb$str0"); + } + } + } + +#------------------------------------------------------------------------------- + +sub anl_C__bit() + { + my ($rb, $name); + + # ANL C, /bit 10110000 bbbbbbbb bit address + + if ($decoder_silent_level == SILENT0) + { + $rb = bit_name($dcd_parm0, \$name); + print_3('anl', "C, /$rb", "CY &= ~$name"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_bit($dcd_parm0, '', FALSE); + } + } + +#------------------------------------------------------------------------------- + +sub cpl_bit() + { + my ($rb, $name); + + # CPL bit 10110010 bbbbbbbb bit address + + if ($decoder_silent_level == SILENT0) + { + $rb = bit_name($dcd_parm0, \$name); + print_3('cpl', $rb, "$name = ~$name"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_bit($dcd_parm0, '', FALSE); + } + } + +#------------------------------------------------------------------------------- + +sub cpl_C() + { + # CPL C 10110011 + + print_3('cpl', 'C', 'CY = ~CY'); + } + +#------------------------------------------------------------------------------- + +sub cjne_A_data() + { + my ($addr, $rb0, $rb1, $str0, $str1, $str2); + + # CJNE A, #data, rel 10110100 dddddddd rrrrrrrr data relative address + + if ($decoder_silent_level == SILENT0) + { + $addr = $dcd_address + $dcd_instr_size + expand_offset($dcd_parm1); + $rb0 = labelname($addr); + $rb1 = sprintf "0x%02X", $dcd_parm0; + $str0 = sprintf "0x%04X", $addr; + $str1 = jump_direction($addr); + $str2 = present_char($dcd_parm0); + print_3('cjne', "A, #$rb1, $rb0", "If (ACC != $rb1$str2) then jumps$str1 hither: $str0"); + } + + invalidate_DPTR_Rx(); + $prev_is_jump = TRUE; + } + +#------------------------------------------------------------------------------- + +sub cjne_A_direct() + { + my ($addr, $rb0, $rb1, $name, $str0, $str1, $str2); + + # CJNE A, direct, rel 10110101 aaaaaaaa rrrrrrrr register address relative address + + if ($decoder_silent_level == SILENT0) + { + $addr = $dcd_address + $dcd_instr_size + expand_offset($dcd_parm1); + $rb0 = reg_name($dcd_parm0, \$name); + $rb1 = labelname($addr); + $str0 = sprintf "0x%04X", $addr; + $str1 = ($dcd_address == $addr) ? ' (waiting loop)' : ''; + $str2 = jump_direction($addr); + print_3('cjne', "A, $rb0, $rb1", "If (ACC != $name) then jumps$str2 hither: $str0$str1"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE); + } + + invalidate_DPTR_Rx(); + $prev_is_jump = TRUE; + } + +#------------------------------------------------------------------------------- + +sub push_direct() + { + my ($rb, $name); + + # PUSH direct 11000000 aaaaaaaa register address + + if ($decoder_silent_level == SILENT0) + { + $rb = reg_name($dcd_parm0, \$name); + print_3('push', $rb, "++SP, [SP] = $name"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE); + } + } + +#------------------------------------------------------------------------------- + +sub clr_bit() + { + my ($rb, $name); + + # CLR bit 11000010 bbbbbbbb bit address + + if ($decoder_silent_level == SILENT0) + { + $rb = bit_name($dcd_parm0, \$name); + print_3('clr', $rb, "$name = L"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_bit($dcd_parm0, '', FALSE); + } + } + +#------------------------------------------------------------------------------- + +sub clr_C() + { + # CLR C 11000011 + + print_3('clr', 'C', 'CY = L'); + } + +#------------------------------------------------------------------------------- + +sub swap_A() + { + # SWAP A 11000100 + + print_3('swap', 'A', 'ACC[76543210] = ACC[32107654]'); + } + +#------------------------------------------------------------------------------- + +sub xch_A_direct() + { + my ($rb, $name); + + # XCH A, direct 11000101 aaaaaaaa register address + + if ($decoder_silent_level == SILENT0) + { + $rb = reg_name($dcd_parm0, \$name); + print_3('xch', "A, $rb", "ACC <-> $name"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE); + } + + invalidate_reg($dcd_parm0); + } + +#------------------------------------------------------------------------------- + +sub pop_direct() + { + my ($rb, $name); + + # POP direct 11010000 aaaaaaaa register address + + if ($decoder_silent_level == SILENT0) + { + $rb = reg_name($dcd_parm0, \$name); + print_3('pop', $rb, "$name = [SP], --SP"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE); + } + + invalidate_reg($dcd_parm0); + } + +#------------------------------------------------------------------------------- + +sub setb_bit() + { + my ($rb, $name); + + # SETB bit 11010010 bbbbbbbb bit address + + if ($decoder_silent_level == SILENT0) + { + $rb = bit_name($dcd_parm0, \$name); + print_3('setb', $rb, "$name = H"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_bit($dcd_parm0, '', FALSE); + } + } + +#------------------------------------------------------------------------------- + +sub setb_C() + { + # SETB C 11010011 + + print_3('setb', 'C', 'CY = H'); + } + +#------------------------------------------------------------------------------- + +sub da_A() + { + # DA A 11010100 + + print_3('da', 'A', 'Decimal adjust the ACC.'); + } + +#------------------------------------------------------------------------------- + +sub djnz_direct() + { + my ($addr, $rb0, $rb1, $name, $str0, $str1, $str2); + + # DJNZ direct, rel 11010101 aaaaaaaa rrrrrrrr register address relative address + + if ($decoder_silent_level == SILENT0) + { + $addr = $dcd_address + $dcd_instr_size + expand_offset($dcd_parm1); + $rb0 = reg_name($dcd_parm0, \$name); + $rb1 = labelname($addr); + $str0 = ($dcd_address == $addr) ? ' (waiting loop)' : ''; + $str1 = sprintf "0x%04X", $addr; + $str2 = jump_direction($addr); + print_3('djnz', "$rb0, $rb1", "If (--$name != 0) then jumps$str2 hither: $str1$str0"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE); + } + + invalidate_DPTR_Rx(); + $prev_is_jump = TRUE; + } + +#------------------------------------------------------------------------------- + +sub movx_A_DPTR() + { + # MOVX A, @DPTR 11100000 + + add_xram($DPTR, '', FALSE) if ($DPTR != EMPTY && $decoder_silent_level == SILENT1); + + print_3('movx', 'A, @DPTR', 'ACC = XRAM[DPTR]'); + } + +#------------------------------------------------------------------------------- + +sub clr_A() + { + # CLR A 11100100 + + print_3('clr', 'A', 'ACC = 0'); + } + +#------------------------------------------------------------------------------- + +sub mov_A_direct() + { + my ($rb, $name); + + # MOV A, direct 11100101 aaaaaaaa register address The "MOV A, ACC" invalid instruction. + + if ($decoder_silent_level == SILENT0) + { + $rb = reg_name($dcd_parm0, \$name); + print_3('mov', "A, $rb", "ACC = $name"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE); + } + } + +#------------------------------------------------------------------------------- + +sub movx_DPTR_A() + { + # MOVX @DPTR, A 11110000 + + add_xram($DPTR, '', FALSE) if ($DPTR != EMPTY && $decoder_silent_level == SILENT1); + + print_3('movx', '@DPTR, A', 'XRAM[DPTR] = ACC'); + } + +#------------------------------------------------------------------------------- + +sub cpl_A() + { + # CPL A 11110100 + + print_3('cpl', 'A', 'ACC = ~ACC'); + } + +#------------------------------------------------------------------------------- + +sub mov_direct_A() + { + my ($rb, $name); + + # MOV direct, A 11110101 aaaaaaaa register address + + if ($decoder_silent_level == SILENT0) + { + $rb = reg_name($dcd_parm0, \$name); + print_3('mov', "$rb, A", "$name = ACC"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($dcd_parm0, '', RAM_TYPE_DIR, FALSE); + } + + invalidate_reg($dcd_parm0); + } + +#------------------------------------------------------------------------------- + +my @instr_decoders = + ( + # 0x00 - 0x0F + \&nop, + \&ajmp, + \&ljmp, + \&rr_A, + \&inc_A, + \&inc_direct, + \&inc_ind_Ri, + \&inc_ind_Ri, + \&inc_Rn, + \&inc_Rn, + \&inc_Rn, + \&inc_Rn, + \&inc_Rn, + \&inc_Rn, + \&inc_Rn, + \&inc_Rn, + + # 0x10 - 0x1F + \&jbc_bit, + \&acall, + \&lcall, + \&rrc_A, + \&dec_A, + \&dec_direct, + \&dec_ind_Ri, + \&dec_ind_Ri, + \&dec_Rn, + \&dec_Rn, + \&dec_Rn, + \&dec_Rn, + \&dec_Rn, + \&dec_Rn, + \&dec_Rn, + \&dec_Rn, + + # 0x20 - 0x2F + \&jb_bit, + \&ajmp, + \&ret, + \&rl_A, + \&add_A_data, + \&add_A_direct, + \&add_A_ind_Ri, + \&add_A_ind_Ri, + \&add_A_Rn, + \&add_A_Rn, + \&add_A_Rn, + \&add_A_Rn, + \&add_A_Rn, + \&add_A_Rn, + \&add_A_Rn, + \&add_A_Rn, + + # 0x30 - 0x3F + \&jnb_bit, + \&acall, + \&reti, + \&rcl_A, + \&addc_A_data, + \&addc_A_direct, + \&addc_A_ind_Ri, + \&addc_A_ind_Ri, + \&addc_A_Rn, + \&addc_A_Rn, + \&addc_A_Rn, + \&addc_A_Rn, + \&addc_A_Rn, + \&addc_A_Rn, + \&addc_A_Rn, + \&addc_A_Rn, + + # 0x40 - 0x4F + \&jc, + \&ajmp, + \&orl_direct_A, + \&orl_direct_data, + \&orl_A_data, + \&orl_A_direct, + \&orl_A_ind_Ri, + \&orl_A_ind_Ri, + \&orl_A_Rn, + \&orl_A_Rn, + \&orl_A_Rn, + \&orl_A_Rn, + \&orl_A_Rn, + \&orl_A_Rn, + \&orl_A_Rn, + \&orl_A_Rn, + + # 0x50 - 0x5F + \&jnc, + \&acall, + \&anl_direct_A, + \&anl_direct_data, + \&anl_A_data, + \&anl_A_direct, + \&anl_A_ind_Ri, + \&anl_A_ind_Ri, + \&anl_A_Rn, + \&anl_A_Rn, + \&anl_A_Rn, + \&anl_A_Rn, + \&anl_A_Rn, + \&anl_A_Rn, + \&anl_A_Rn, + \&anl_A_Rn, + + # 0x60 - 0x6F + \&jz, + \&ajmp, + \&xrl_direct_A, + \&xrl_direct_data, + \&xrl_A_data, + \&xrl_A_direct, + \&xrl_A_ind_Ri, + \&xrl_A_ind_Ri, + \&xrl_A_Rn, + \&xrl_A_Rn, + \&xrl_A_Rn, + \&xrl_A_Rn, + \&xrl_A_Rn, + \&xrl_A_Rn, + \&xrl_A_Rn, + \&xrl_A_Rn, + + # 0x70 - 0x7F + \&jnz, + \&acall, + \&orl_C_bit, + \&jmp_A_DPTR, + \&mov_A_data, + \&mov_direct_data, + \&mov_ind_Ri_data, + \&mov_ind_Ri_data, + \&mov_Rn_data, + \&mov_Rn_data, + \&mov_Rn_data, + \&mov_Rn_data, + \&mov_Rn_data, + \&mov_Rn_data, + \&mov_Rn_data, + \&mov_Rn_data, + + # 0x80 - 0x8F + \&sjmp, + \&ajmp, + \&anl_C_bit, + \&movc_A_A_PC, + \&div_AB, + \&mov_direct_direct, + \&mov_direct_ind_Ri, + \&mov_direct_ind_Ri, + \&mov_direct_Rn, + \&mov_direct_Rn, + \&mov_direct_Rn, + \&mov_direct_Rn, + \&mov_direct_Rn, + \&mov_direct_Rn, + \&mov_direct_Rn, + \&mov_direct_Rn, + + # 0x90 - 0x9F + \&mov_DPTR_data, + \&acall, + \&mov_bit_C, + \&movc_A_A_DPTR, + \&subb_A_data, + \&subb_A_direct, + \&subb_A_ind_Ri, + \&subb_A_ind_Ri, + \&subb_A_Rn, + \&subb_A_Rn, + \&subb_A_Rn, + \&subb_A_Rn, + \&subb_A_Rn, + \&subb_A_Rn, + \&subb_A_Rn, + \&subb_A_Rn, + + # 0xA0 - 0xAF + \&orl_C__bit, + \&ajmp, + \&mov_C_bit, + \&inc_DPTR, + \&mul_AB, + \&unknown, + \&mov_ind_Ri_direct, + \&mov_ind_Ri_direct, + \&mov_Rn_direct, + \&mov_Rn_direct, + \&mov_Rn_direct, + \&mov_Rn_direct, + \&mov_Rn_direct, + \&mov_Rn_direct, + \&mov_Rn_direct, + \&mov_Rn_direct, + + # 0xB0 - 0xBF + \&anl_C__bit, + \&acall, + \&cpl_bit, + \&cpl_C, + \&cjne_A_data, + \&cjne_A_direct, + \&cjne_ind_Ri_data, + \&cjne_ind_Ri_data, + \&cjne_Rn_data, + \&cjne_Rn_data, + \&cjne_Rn_data, + \&cjne_Rn_data, + \&cjne_Rn_data, + \&cjne_Rn_data, + \&cjne_Rn_data, + \&cjne_Rn_data, + + # 0xC0 - 0xCF + \&push_direct, + \&ajmp, + \&clr_bit, + \&clr_C, + \&swap_A, + \&xch_A_direct, + \&xch_A_ind_Ri, + \&xch_A_ind_Ri, + \&xch_A_Rn, + \&xch_A_Rn, + \&xch_A_Rn, + \&xch_A_Rn, + \&xch_A_Rn, + \&xch_A_Rn, + \&xch_A_Rn, + \&xch_A_Rn, + + # 0xD0 - 0xDF + \&pop_direct, + \&acall, + \&setb_bit, + \&setb_C, + \&da_A, + \&djnz_direct, + \&xchd_A_ind_Ri, + \&xchd_A_ind_Ri, + \&djnz_Rn, + \&djnz_Rn, + \&djnz_Rn, + \&djnz_Rn, + \&djnz_Rn, + \&djnz_Rn, + \&djnz_Rn, + \&djnz_Rn, + + # 0xE0 - 0xEF + \&movx_A_DPTR, + \&ajmp, + \&movx_A_ind_Ri, + \&movx_A_ind_Ri, + \&clr_A, + \&mov_A_direct, + \&mov_A_ind_Ri, + \&mov_A_ind_Ri, + \&mov_A_Rn, + \&mov_A_Rn, + \&mov_A_Rn, + \&mov_A_Rn, + \&mov_A_Rn, + \&mov_A_Rn, + \&mov_A_Rn, + \&mov_A_Rn, + + # 0xF0 - 0xFF + \&movx_DPTR_A, + \&acall, + \&movx_ind_Ri_A, + \&movx_ind_Ri_A, + \&cpl_A, + \&mov_direct_A, + \&mov_ind_Ri_A, + \&mov_ind_Ri_A, + \&mov_Rn_A, + \&mov_Rn_A, + \&mov_Rn_A, + \&mov_Rn_A, + \&mov_Rn_A, + \&mov_Rn_A, + \&mov_Rn_A, + \&mov_Rn_A + ); + +#------------------------------------------------------------------------------- + + # + # Decodes the $BlockRef. + # + +sub instruction_decoder($$) + { + my ($Address, $BlockRef) = @_; + my ($label, $invalid); + + $dcd_address = $Address; + $dcd_instr_size = $BlockRef->{SIZE}; + $dcd_instr = $rom[$dcd_address]; + $label = $BlockRef->{LABEL}; + + if ($decoder_silent_level == SILENT0) + { + printf("0x%04X: %02X", $dcd_address, $dcd_instr) if (! $gen_assembly_code); + } + + $invalid = FALSE; + + if ($dcd_instr_size == 1) + { + if ($decoder_silent_level == SILENT0) + { + print(($gen_assembly_code) ? "\t" : "\t\t"); + } + } + elsif ($dcd_instr_size == 2) + { + $dcd_parm0 = $rom[$dcd_address + 1]; + $invalid = TRUE if ($dcd_parm0 == EMPTY); + + if ($decoder_silent_level == SILENT0) + { + if ($gen_assembly_code) + { + print "\t"; + } + else + { + printf " %02X\t\t", $dcd_parm0; + } + } + } + elsif ($dcd_instr_size == 3) + { + $dcd_parm0 = $rom[$dcd_address + 1]; + $dcd_parm1 = $rom[$dcd_address + 2]; + $invalid = TRUE if ($dcd_parm0 == EMPTY || $dcd_parm1 == EMPTY); + + if ($decoder_silent_level == SILENT0) + { + if ($gen_assembly_code) + { + print "\t"; + } + else + { + printf " %02X %02X\t", $dcd_parm0, $dcd_parm1; + } + } + } + else + { + printf STDERR "An instruction and a block overlapped with each other at this address: 0x%04X!\n", $dcd_address; + } + + $dcd_Ri_regs = $dcd_instr & 0x01; + $dcd_Ri_name = "R$dcd_Ri_regs"; + + $dcd_Rn_regs = $dcd_instr & 0x07; + $dcd_Rn_name = "R$dcd_Rn_regs"; + + $prev_is_jump = FALSE; + + invalidate_DPTR_Rx() if ($label->{TYPE} != BL_TYPE_NONE); + + if ($dcd_instr != EMPTY && ! $invalid) + { + $instr_decoders[$dcd_instr](); + } + else + { + unknown(); + } + } + +################################################################################ +################################################################################ + + # + # Reads the sfrs and bits from the $Line. + # + +sub process_header_line($) + { + my $Line = $_[0]; + + Log((' ' x $embed_level) . $Line, 5); + + if ($Line =~ /^#\s*include\s+["<]\s*(\S+)\s*[">]$/o) + { + $embed_level += 4; + &read_header("$include_path/$1"); + $embed_level -= 4; + } + elsif ($Line =~ /^__sfr\s+__at\s*(?:\(\s*)?0x([[:xdigit:]]+)(?:\s*\))?\s+([\w_]+)/io) + { + # __sfr __at (0x80) P0 ; /* PORT 0 */ + + add_ram(hex($1), $2, RAM_TYPE_DIR, TRUE); + } + elsif ($Line =~ /^SFR\s*\(\s*([\w_]+)\s*,\s*0x([[:xdigit:]]+)\s*\)/io) + { + # SFR(P0, 0x80); // Port 0 + + add_ram(hex($2), $1, RAM_TYPE_DIR, TRUE); + } + elsif ($Line =~ /^sfr\s+([\w_]+)\s*=\s*0x([[:xdigit:]]+)/io) + { + # sfr P1 = 0x90; + + add_ram(hex($2), $1, RAM_TYPE_DIR, TRUE); + } + elsif ($Line =~ /^__sbit\s+__at\s*(?:\(\s*)?0x([[:xdigit:]]+)(?:\s*\))?\s+([\w_]+)/io) + { + # __sbit __at (0x86) P0_6 ; + + add_bit(hex($1), $2, TRUE); + } + elsif ($Line =~ /^SBIT\s*\(\s*([\w_]+)\s*,\s*0x([[:xdigit:]]+)\s*,\s*(\d)\s*\)/io) + { + # SBIT(P0_0, 0x80, 0); // Port 0 bit 0 + + add_bit(hex($2) + int($3), $1, TRUE); + } + elsif ($Line =~ /^sbit\s+([\w_]+)\s*=\s*0x([[:xdigit:]]+)/io) + { + # sbit P3_1 = 0xB1; + + add_bit(hex($2), $1, TRUE); + } + elsif ($Line =~ /^sbit\s+([\w_]+)\s*=\s*([\w_]+)\s*\^\s*(\d)/io) + { + # sbit SM0 = SCON^7; + + my ($name, $reg, $bit) = ($1, $2, $3); + + add_bit($sfr_by_names{$reg} + $bit, $name, TRUE) if (defined($sfr_by_names{$reg})); + } + } + +#------------------------------------------------------------------------------- + + # + # Reads in a MCU.h file. + # + +sub read_header($) + { + my $Header = $_[0]; + my ($fh, $pre_comment, $comment, $line_number); + my $head; + + if (! open($fh, '<', $Header)) + { + print STDERR "$PROGRAM: Could not open. -> \"$Header\"\n"; + exit(1); + } + + $head = ' ' x $embed_level; + + Log("${head}read_header($Header) >>>>", 5); + + $comment = FALSE; + $line_number = 1; + while (<$fh>) + { + chomp; + s/\r$//o; # '\r' + + # Filters off the C comments. + + s/\/\*.*\*\///o; # /* ... */ + s/\/\/.*$//o; # // ... + s/^\s*|\s*$//go; + + if (/\/\*/o) # /* + { + $pre_comment = TRUE; + s/\s*\/\*.*$//o; + } + elsif (/\*\//o) # */ + { + $pre_comment = FALSE; + $comment = FALSE; + s/^.*\*\/\s*//o; + } + + if ($comment) + { + ++$line_number; + next; + } + + $comment = $pre_comment if ($pre_comment); + + if (/^\s*$/o) + { + ++$line_number; + next; + } + + run_preprocessor($Header, \&process_header_line, $_, $line_number); + ++$line_number; + } # while (<$fh>) + + Log("${head}<<<< read_header($Header)", 5); + close($fh); + } + +#------------------------------------------------------------------------------- + + # + # Among the blocks stows description of an instruction. + # + +sub add_instr_block($$) + { + my ($Address, $Instruction) = @_; + my $instr_size = $instruction_sizes[$Instruction]; + my $invalid; + + $dcd_address = $Address; + $dcd_instr = $rom[$dcd_address]; + $invalid = FALSE; + + if (! $instr_size) + { + $instr_size = 1; + add_block($Address, BLOCK_CONST, $instr_size, BL_TYPE_NONE, ''); + } + else + { + if ($instr_size == 1) + { + $invalid = TRUE if ($dcd_instr == EMPTY); + } + + if ($instr_size == 2) + { + $dcd_parm0 = $rom[$dcd_address + 1]; + $invalid = TRUE if ($dcd_parm0 == EMPTY); + } + + if ($instr_size == 3) + { + $dcd_parm1 = $rom[$dcd_address + 2]; + $invalid = TRUE if ($dcd_parm1 == EMPTY); + } + + if ($invalid) + { + add_block($Address, BLOCK_CONST, $instr_size, BL_TYPE_NONE, '') if ($instr_size); + } + else + { + add_block($Address, BLOCK_INSTR, $instr_size, BL_TYPE_NONE, ''); + } + } + + return $instr_size; + } + +#------------------------------------------------------------------------------- + + # + # Splits the program into small blocks. + # + +sub split_code_to_blocks() + { + my ($i, $instr); + my ($is_empty, $empty_begin); + my ($is_const, $const_begin); + + $is_empty = FALSE; + $empty_begin = 0; + $is_const = FALSE; + $const_begin = 0; + + for ($i = 0; $i < $rom_size; ) + { + $instr = $rom[$i]; + + if ($instr == EMPTY) + { + if (! $is_empty) + { + # The begin of the empty section. + + if ($is_const) + { + # The end of the constant section. + + add_block($const_begin, BLOCK_CONST, $i - $const_begin, BL_TYPE_NONE, ''); + $is_const = FALSE; + } + + $empty_begin = $i; + $is_empty = TRUE; + } + + ++$i; + } # if ($instr == EMPTY) + elsif (is_constant($i)) + { + if (! $is_const) + { + if ($is_empty) + { + # The end of the empty section. + + add_block($empty_begin, BLOCK_EMPTY, $i - $empty_begin, BL_TYPE_NONE, ''); + $is_empty = FALSE; + } + + $const_begin = $i; + $is_const = TRUE; + } + + ++$i; + } # elsif (is_constant($i)) + else + { + if ($is_const) + { + # The end of the constant section. + + add_block($const_begin, BLOCK_CONST, $i - $const_begin, BL_TYPE_NONE, ''); + $is_const = FALSE; + } + + if ($is_empty) + { + # The end of the empty section. + + add_block($empty_begin, BLOCK_EMPTY, $i - $empty_begin, BL_TYPE_NONE, ''); + $is_empty = FALSE; + } + + $i += add_instr_block($i, $instr); + } + } # for ($i = 0; $i < $rom_size; ) + + if ($is_const) + { + add_block($const_begin, BLOCK_CONST, $i - $const_begin, BL_TYPE_NONE, ''); + } + + if ($is_empty) + { + add_block($empty_begin, BLOCK_EMPTY, $i - $empty_begin, BL_TYPE_NONE, ''); + } + } + +#------------------------------------------------------------------------------- + + # + # If the $BlockRef a call, then follows. + # + +sub follow_call($) + { + my $BlockRef = $_[0]; + my ($addr, $size, $instr); + + $addr = $BlockRef->{ADDR}; + $size = $BlockRef->{SIZE}; + $instr = $rom[$addr]; + + if ($instr == INST_LCALL) + { + return (($rom[$addr + 1] << 8) | $rom[$addr + 2]); + } + elsif (($instr & 0x1F) == INST_ACALL) + { + return ((($addr + $size) & 0xF800) | (($instr & 0xE0) << 3) | $rom[$addr + 1]); + } + + return EMPTY; + } + +#------------------------------------------------------------------------------- + + # + # If the $BlockRef a unconditional jump, then follows. + # + +sub follow_unconditional_jump($) + { + my $BlockRef = $_[0]; + my ($addr, $size, $instr); + + $addr = $BlockRef->{ADDR}; + $size = $BlockRef->{SIZE}; + $instr = $rom[$addr]; + + if ($size == 3 && $instr == INST_LJMP) + { + return (($rom[$addr + 1] << 8) | $rom[$addr + 2]); + } + elsif ($size == 2) + { + if (($instr & 0x1F) == INST_AJMP) + { + return ((($addr + $size) & 0xF800) | ((($instr & 0xE0) << 3) | $rom[$addr + 1])); + } + elsif ($instr == INST_SJMP) + { + return ($addr + $size + expand_offset($rom[$addr + 1])); + } + } + + return EMPTY; + } + +#------------------------------------------------------------------------------- + + # + # If the $BlockRef a conditional jump, then follows. + # + +sub follow_conditional_jump($) + { + my $BlockRef = $_[0]; + my ($addr, $size, $instr, $instr_mask1, $instr_mask2); + + return EMPTY if ($BlockRef->{TYPE} != BLOCK_INSTR); + + $addr = $BlockRef->{ADDR}; + $size = $BlockRef->{SIZE}; + $instr = $rom[$addr]; + + $instr_mask1 = $instr & 0xFE; + $instr_mask2 = $instr & 0xF8; + + if ($instr_mask1 == INST_CJNE__Ri_DATA || + $instr_mask2 == INST_CJNE_Rn_DATA) + { + return ($addr + $size + expand_offset($rom[$addr + 2])); + } + elsif ($instr_mask2 == INST_DJNZ_Rn) + { + return ($addr + $size + expand_offset($rom[$addr + 1])); + } + elsif ($instr == INST_JBC_BIT || + $instr == INST_JB_BIT || + $instr == INST_JNB_BIT || + $instr == INST_CJNE_A_DATA || + $instr == INST_CJNE_A_DIRECT || + $instr == INST_DJNZ_DIRECT) + { + return ($addr + $size + expand_offset($rom[$addr + 2])); + } + elsif ($instr == INST_JC || + $instr == INST_JNC || + $instr == INST_JZ || + $instr == INST_JNZ || + $instr == INST_SJMP) + { + return ($addr + $size + expand_offset($rom[$addr + 1])); + } + + return EMPTY; + } + +#------------------------------------------------------------------------------- + + # + # Determines the start of stack. + # + +sub determine_stack() + { + my ($block, $instr, $addr, $count, $size, $t); + + return if (! defined($blocks_by_address{0})); + + $addr = follow_unconditional_jump(\%{$blocks_by_address{0}}); + return if ($addr == EMPTY); + + return if (! defined($blocks_by_address{$addr})); + + # At most so much block looks through. + $count = 30; + do + { + $block = \%{$blocks_by_address{$addr}}; + + return if ($block->{TYPE} != BLOCK_INSTR); + return if (follow_unconditional_jump($block) != EMPTY); + return if (follow_call($block) != EMPTY); + + $addr = $block->{ADDR}; + $size = $block->{SIZE}; + $instr = $rom[$addr]; + + return if ($size == 2 && ($instr == INST_PUSH_DIRECT || $instr == INST_POP_DIRECT)); + + $t = follow_conditional_jump($block); + + return if ($t != EMPTY && $t > $addr); + + if ($size == 3 && $instr == INST_MOV_DIRECT_DATA && $rom[$addr + 1] == SP) + { + $stack_start = $rom[$addr + 2] + 1; + $stack_size = RAM_MAX_ADDR - $stack_start + 1; + return; + } + + $addr += $size; # Compute the address of next block. + } + while (--$count); + } + +#------------------------------------------------------------------------------- + + # + # Previously assess the code. + # + +sub preliminary_survey($) + { + $decoder_silent_level = $_[0]; + foreach (sort {$a <=> $b} keys(%blocks_by_address)) + { + my $block = \%{$blocks_by_address{$_}}; + + next if ($block->{TYPE} != BLOCK_INSTR); + + instruction_decoder($_, $block); + } + } + +#------------------------------------------------------------------------------- + + # + # Finds address of branchs and procedures. + # + +sub find_labels_in_code() + { + foreach (sort {$a <=> $b} keys(%blocks_by_address)) + { + my $block = \%{$blocks_by_address{$_}}; + + next if ($block->{TYPE} != BLOCK_INSTR); + + label_finder($_, $block); + } + } + +#------------------------------------------------------------------------------- + + # + # Finds lost address of branchs and procedures. + # + +sub find_lost_labels_in_code() + { + my ($block, $prev_block, $prev_addr, $label, $instr); + + $prev_addr = EMPTY; + $prev_block = undef; + foreach (sort {$a <=> $b} keys(%blocks_by_address)) + { + $block = \%{$blocks_by_address{$_}}; + + next if ($block->{TYPE} != BLOCK_INSTR); + + if ($prev_addr != EMPTY) + { + $instr = $rom[$prev_addr]; + $label = $block->{LABEL}; + + if (defined($label) && $label->{TYPE} == BL_TYPE_NONE) + { + if ($instr == INST_RET || $instr == INST_RETI) + { + Log(sprintf("Lost function label at the 0x%04X address.", $_), 5); + add_func_label($_, '', TRUE); + } + elsif ($instr == INST_LJMP || $instr == INST_SJMP || ($instr & 0x1F) == INST_AJMP) + { + Log(sprintf("Lost jump label at the 0x%04X address.", $_), 5); + add_jump_label($_, '', BL_TYPE_LABEL, EMPTY, TRUE); + } + } + } + + $prev_addr = $_; + $prev_block = $block; + } + } + +#------------------------------------------------------------------------------- + + # + # Adds the jump addresses from a jump table. + # + +sub add_jump_address_in_table($$$) + { + my ($AddrLow, $AddrHigh, $Size) = @_; + my ($end, $addr); + + $end = $AddrLow + $Size; + while ($AddrLow < $end) + { + $addr = $rom[$AddrLow] | ($rom[$AddrHigh] << 8); + add_jump_label($addr, '', BL_TYPE_JLABEL, EMPTY, FALSE); + ++$AddrLow; + ++$AddrHigh; + } + } + +#------------------------------------------------------------------------------- + + # + # Jump tables looking for in the code. + # + +sub recognize_jump_tables_in_code($) + { + my $Survey = $_[0]; + my @blocks = ((undef) x 9); + my @instrs = ((EMPTY) x 9); + my ($parm, $data1, $data2, $addrL, $addrH, $end, $size); + + foreach (sort {$a <=> $b} keys(%blocks_by_address)) + { + shift(@instrs); + push(@instrs, $rom[$_]); + + shift(@blocks); + push(@blocks, \%{$blocks_by_address{$_}}); + + next if (! defined($blocks[0]) || ! defined($blocks[8])); + next if ($blocks[0]->{TYPE} != BLOCK_INSTR); + next if ($blocks[1]->{TYPE} != BLOCK_INSTR); + next if ($blocks[2]->{TYPE} != BLOCK_INSTR); + next if ($blocks[3]->{TYPE} != BLOCK_INSTR); + next if ($blocks[4]->{TYPE} != BLOCK_INSTR); + next if ($blocks[5]->{TYPE} != BLOCK_INSTR); + next if ($blocks[6]->{TYPE} != BLOCK_INSTR); + next if ($blocks[7]->{TYPE} != BLOCK_INSTR); + next if ($blocks[8]->{TYPE} != BLOCK_INSTR); + + if ($blocks[0]->{SIZE} == 2 && $instrs[0] == INST_ADD_A_DATA && # add A, #0xZZ + + $blocks[1]->{SIZE} == 1 && $instrs[1] == INST_MOVC_A_APC && # movc A, @A+PC + + $blocks[2]->{SIZE} == 2 && $rom[$blocks[2]->{ADDR} + 1] == DPL && + ($instrs[2] == INST_XCH_A_DIRECT || # xch A, DPL + $instrs[2] == INST_MOV_DIRECT_A) && # mov DPL, A + + (($blocks[3]->{SIZE} == 2 && $instrs[3] == INST_MOV_A_DIRECT) || # mov A, direct + ($blocks[3]->{SIZE} == 1 && (($instrs[3] & 0xF8) == INST_MOV_A_Rn || # mov A, Rn + ($instrs[3] & 0xFE) == INST_MOV_A_Ri))) && # mov A, @Ri + + $blocks[4]->{SIZE} == 2 && $instrs[4] == INST_ADD_A_DATA && # add A, #0xZZ + + $blocks[5]->{SIZE} == 1 && $instrs[5] == INST_MOVC_A_APC && # movc A, @A+PC + + $blocks[6]->{SIZE} == 2 && $instrs[6] == INST_MOV_DIRECT_A && # mov DPH, A + $rom[$blocks[6]->{ADDR} + 1] == DPH && + + $blocks[7]->{SIZE} == 1 && $instrs[7] == INST_CLR_A && # clr A + + $blocks[8]->{SIZE} == 1 && $instrs[8] == INST_JMP_A_DPTR) # jmp @A+DPTR + { +=back + 24 0B add A, #0x0B + 83 movc A, @A+PC + F5 82 mov DPL, A + + E5 F0 mov A, B + or + ED mov A, R5 + + 24 25 add A, #0x25 + 83 movc A, @A+PC + F5 83 mov DPH, A + E4 clr A + 73 jmp @A+DPTR +=cut + + $addrL = $blocks[2]->{ADDR} + $rom[$blocks[0]->{ADDR} + 1]; + $addrH = $blocks[6]->{ADDR} + $rom[$blocks[4]->{ADDR} + 1]; + $size = $addrH - $addrL; + $end = $addrH + $size - 1; + + if ($Survey) + { + add_const_area($addrL, $end); + } + else + { + add_block($addrL, BLOCK_JTABLE, $size, BL_TYPE_JTABLE, ''); + add_block($addrH, BLOCK_JTABLE, $size, BL_TYPE_JTABLE, ''); + add_jump_address_in_table($addrL, $addrH, $size); + } + } + elsif ($blocks[0]->{SIZE} == 3 && $instrs[0] == INST_MOV_DPTR_DATA && # mov DPTR, #tLow + + $blocks[1]->{SIZE} == 1 && $instrs[1] == INST_MOVC_A_DPTR && # movc A, @A+DPTR + + (($blocks[2]->{SIZE} == 2 && $instrs[2] == INST_XCH_A_DIRECT) || # xch A, XX + ($blocks[2]->{SIZE} == 2 && $instrs[2] == INST_PUSH_DIRECT && # push ACC + $rom[$blocks[2]->{ADDR} + 1] == ACC)) && + + $blocks[3]->{SIZE} == 3 && $instrs[3] == INST_MOV_DPTR_DATA && # mov DPTR, #tHigh + + $blocks[4]->{SIZE} == 1 && $instrs[4] == INST_MOVC_A_DPTR && # movc A, @A+DPTR + + $blocks[5]->{SIZE} == 2 && $instrs[5] == INST_MOV_DIRECT_A && # mov DPH, A + $rom[$blocks[5]->{ADDR} + 1] == DPH && + + (($blocks[6]->{SIZE} == 3 && $instrs[6] == INST_MOV_DIRECT_DIRECT && # mov DPL, XX + $rom[$blocks[6]->{ADDR} + 2] == DPL) || + ($blocks[6]->{SIZE} == 2 && $instrs[6] == INST_POP_DIRECT && # pop DPL + $rom[$blocks[6]->{ADDR} + 1] == DPL)) && + + $blocks[7]->{SIZE} == 1 && $instrs[7] == INST_CLR_A && # clr A + + $blocks[8]->{SIZE} == 1 && $instrs[8] == INST_JMP_A_DPTR) # jmp @A+DPTR + { +=back + 90 00 79 mov DPTR, #0x0079 + 93 movc A, @A+DPTR + + C5 F0 xch A, B + or + C0 E0 push ACC + + 90 01 79 mov DPTR, #0x0179 + 93 movc A, @A+DPTR + F5 83 mov DPH, A + + 85 F0 82 mov DPL, B + or + D0 82 pop DPL + + E4 clr A + 73 jmp @A+DPTR +=cut + + $addrL = ($rom[$blocks[0]->{ADDR} + 1] << 8) | $rom[$blocks[0]->{ADDR} + 2]; + $addrH = ($rom[$blocks[3]->{ADDR} + 1] << 8) | $rom[$blocks[3]->{ADDR} + 2]; + $size = $addrH - $addrL; + $end = $addrH + $size - 1; + + if ($Survey) + { + add_const_area($addrL, $end); + } + else + { + add_block($addrL, BLOCK_JTABLE, $size, BL_TYPE_JTABLE, ''); + add_block($addrH, BLOCK_JTABLE, $size, BL_TYPE_JTABLE, ''); + add_jump_address_in_table($addrL, $addrH, $size); + } + } + } + } + +#------------------------------------------------------------------------------- + + # + # Prints the global symbols. + # + +sub emit_globals($) + { + my $Assembly_mode = $_[0]; + my ($label, $cnt0, $cnt1, $str0, $str1); + + return if (! scalar(keys(%labels_by_address))); + + print ";$border0\n;\tPublic labels\n;$border0\n\n"; + + if ($Assembly_mode) + { + foreach (sort {$a <=> $b} keys(%labels_by_address)) + { + $label = $labels_by_address{$_}; + + next if ($label->{TYPE} != BL_TYPE_SUB); + + print "\t.globl\t$label->{NAME}\n"; + } + } + else + { + foreach (sort {$a <=> $b} keys(%labels_by_address)) + { + $label = $labels_by_address{$_}; + + next if ($label->{TYPE} != BL_TYPE_SUB); + + $str0 = sprintf "0x%04X", $_; + $cnt0 = sprintf "%3u", $label->{CALL_COUNT}; + $cnt1 = sprintf "%3u", $label->{JUMP_COUNT}; + $str1 = ($label->{CALL_COUNT} || $label->{JUMP_COUNT}) ? "calls: $cnt0, jumps: $cnt1" : 'not used'; + print "${str0}:\t" . align($label->{NAME}, STAT_ALIGN_SIZE) . "($str1)\n"; + } + } + + print "\n"; + } + +#------------------------------------------------------------------------------- + + # + # Prints the SFRs. + # + +sub emit_sfrs($) + { + my $Assembly_mode = $_[0]; + my ($sfr, $cnt, $str0, $str1); + + return if (! scalar(keys(%sfr_by_address))); + + if ($Assembly_mode) + { + print ";$border0\n;\tSpecial function registers\n;$border0\n\n" . + "\t.area\tRSEG\t(ABS,DATA)\n\t.org\t0x0000\n\n"; + + foreach (sort {$a <=> $b} keys(%sfr_by_address)) + { + printf "$sfr_by_address{$_}->{NAME}\t=\t0x%02X\n", $_; + } + } + else + { + print ";$border0\n;\tSFR registers\n;$border0\n\n"; + + foreach (sort {$a <=> $b} keys(%sfr_by_address)) + { + $sfr = $sfr_by_address{$_}; + $str0 = sprintf "0x%02X", $_; + $cnt = sprintf "%3u", $sfr->{REF_COUNT}; + $str1 = ($sfr->{REF_COUNT}) ? "used $cnt times" : 'not used'; + print "${str0}:\t" . align($sfr->{NAME}, STAT_ALIGN_SIZE) . "($str1)\n"; + } + } + + print "\n"; + } + +#------------------------------------------------------------------------------- + + # + # Prints the SFR bits. + # + +sub emit_sfr_bits($) + { + my $Assembly_mode = $_[0]; + my ($sbit, $cnt, $str0, $str1); + + return if (! scalar(keys(%sfr_bit_by_address))); + + if ($Assembly_mode) + { + print ";$border0\n;\tSpecial function bits\n;$border0\n\n" . + "\t.area\tRSEG\t(ABS,DATA)\n\t.org\t0x0000\n\n"; + + foreach (sort {$a <=> $b} keys(%sfr_bit_by_address)) + { + printf "$sfr_bit_by_address{$_}->{NAME}\t=\t0x%02X\n", $_; + } + } + else + { + print ";$border0\n;\tSpecial function bits\n;$border0\n\n"; + + foreach (sort {$a <=> $b} keys(%sfr_bit_by_address)) + { + $sbit = $sfr_bit_by_address{$_}; + $str0 = sprintf "0x%02X", $_; + $cnt = sprintf "%3u", $sbit->{REF_COUNT}; + $str1 = ($sbit->{REF_COUNT}) ? "used $cnt times" : 'not used'; + print "${str0}:\t" . align($sbit->{NAME}, STAT_ALIGN_SIZE) . "($str1)\n"; + } + } + + print "\n"; + } + +#------------------------------------------------------------------------------- + + # + # Prints the banks. + # + +sub emit_banks($) + { + my $Assembly_mode = $_[0]; + + $used_banks{0} = TRUE; + + print ";$border0\n;\tOverlayable register banks\n;$border0\n\n"; + + if ($Assembly_mode) + { + foreach (sort {$a <=> $b} keys(%used_banks)) + { + print "\t.area\tREG_BANK_$_\t(REL,OVR,DATA)\n\t.ds 8\n"; + } + } + else + { + foreach (sort {$a <=> $b} keys(%used_banks)) + { + printf "0x%02X:\tREG_BANK_$_\n", $_ * 8; + } + } + + print "\n"; + } + + +#------------------------------------------------------------------------------- + + # + # Prints the registers (variables). + # + +sub emit_ram_data($) + { + my $Assembly_mode = $_[0]; + my ($ram, $first, $next_addr, $size); + my ($cnt, $str0, $str1); + + return if (! scalar(keys(%ram_by_address))); + + if ($Assembly_mode) + { + print ";$border0\n;\tAbsolute internal RAM data\n;$border0\n\n" . + "\t.area\tIABS\t(ABS,DATA)\n"; + + $first = TRUE; + $next_addr = EMPTY; + foreach (sort {$a <=> $b} keys(%ram_by_address)) + { + last if ($_ > RAM_LAST_DIR_ADDR); + + $ram = $ram_by_address{$_}; + + next if ($ram->{TYPE} != RAM_TYPE_DIR); + + if ($first) + { + printf "\t.org\t0x%02X\n\n", $_; + $first = FALSE; + } + + if ($next_addr != EMPTY) + { + next if ($_ < $next_addr); + + printf("\t.ds 0x%02X\n", $_ - $next_addr) if ($_ > $next_addr); + } + + if ($ram->{NAME} ne '') + { + print "$ram->{NAME}::\n\t.ds $ram->{SIZE}\n"; + $next_addr = $_ + $size; + } + else + { + printf "r0x%02X::\n\t.ds 1\n", $_; + $next_addr = $_ + 1; + } + } # foreach (sort {$a <=> $b} keys(%ram_by_address)) + } + else + { + print ";$border0\n;\tInternal RAM data\n;$border0\n\n"; + + $next_addr = EMPTY; + foreach (sort {$a <=> $b} keys(%ram_by_address)) + { + last if ($_ > RAM_LAST_DIR_ADDR); + + $ram = $ram_by_address{$_}; + + next if ($ram->{TYPE} != RAM_TYPE_DIR); + + next if ($next_addr != EMPTY && $_ < $next_addr); + + $str0 = sprintf "0x%02X", $_; + $cnt = sprintf "%3u", $ram->{REF_COUNT}; + $str1 = ($ram->{REF_COUNT}) ? "used $cnt times" : 'not used'; + + if ($ram->{NAME} ne '') + { + $cnt = sprintf "%3u", $ram->{SIZE}; + print "${str0}:\t" . align($ram->{NAME}, STAT_ALIGN_SIZE) . "($cnt bytes) ($str1)\n"; + $next_addr = $_ + $ram->{SIZE}; + } + else + { + if ($map_readed) + { + print "${str0}:\t" . align("variable_$str0", STAT_ALIGN_SIZE) . "( 1 bytes) ($str1)\n"; + } + else + { + print "${str0}:\t" . align("variable_$str0", STAT_ALIGN_SIZE) . "($str1)\n"; + } + + $next_addr = $_ + 1; + } + } # foreach (sort {$a <=> $b} keys(%ram_by_address)) + } + + print "\n"; + } + +#------------------------------------------------------------------------------- + + # + # Prints the list of registers in indirect RAM. + # + +sub emit_indirect_ram($) + { + my $Assembly_mode = $_[0]; + my ($ram, $name, $cnt, $str0, $str1, $str2); + + return if (! scalar(keys(%ram_by_address))); + + if ($Assembly_mode) + { + print ";$border0\n;\tIndirectly addressable internal RAM data\n;$border0\n\n" . + "\t.area\tISEG\t(DATA)\n\n"; + + foreach (sort {$a <=> $b} keys(%ram_by_address)) + { + $ram = $ram_by_address{$_}; + + next if ($ram->{TYPE} != RAM_TYPE_IND); + + $name = $ram->{NAME}; + $str0 = sprintf "0x%02X", $_; + $str1 = ($name ne '') ? $name : "iram_$str0"; + printf "${str1}::\n\t.ds 1\n", $_; + } + } + else + { + print ";$border0\n;\tIndirectly addressable internal RAM data\n;$border0\n\n"; + + foreach (sort {$a <=> $b} keys(%ram_by_address)) + { + $ram = $ram_by_address{$_}; + + next if ($ram->{TYPE} != RAM_TYPE_IND); + + $name = $ram->{NAME}; + $str0 = sprintf "0x%02X", $_; + $str1 = ($name ne '') ? $name : "iram_$str0"; + $cnt = sprintf "%3u", $ram->{REF_COUNT}; + $str2 = ($ram->{REF_COUNT}) ? "used $cnt times" : 'not used'; + print "${str0}:\t" . align($str1, STAT_ALIGN_SIZE) . "($str2)\n"; + } + } + + print "\n"; + } + +#------------------------------------------------------------------------------- + + # + # Prints the list of registers in external RAM. + # + +sub emit_external_ram($) + { + my $Assembly_mode = $_[0]; + my ($xram, $name, $next_addr, $cnt, $str0, $str1, $str2); + + return if (! scalar(keys(%xram_by_address))); + + if ($Assembly_mode) + { + print ";$border0\n;\tExternal RAM data\n;$border0\n\n\t.area\tXSEG\t(XDATA)\n\n"; + + foreach (sort {$a <=> $b} keys(%xram_by_address)) + { + $xram = $xram_by_address{$_}; + $name = $xram->{NAME}; + $str0 = sprintf "0x%04X", $_; + $str1 = ($name ne '') ? $name : "xram_$str0"; + print "$str1\t=\t$str0\n"; + } + } + else + { + print ";$border0\n;\tExternal RAM data\n;$border0\n\n"; + + $next_addr = EMPTY; + foreach (sort {$a <=> $b} keys(%xram_by_address)) + { + next if ($next_addr != EMPTY && $_ < $next_addr); + + $xram = $xram_by_address{$_}; + $str0 = sprintf "0x%04X", $_; + $cnt = sprintf "%3u", $xram->{REF_COUNT}; + $str1 = ($xram->{REF_COUNT}) ? "used $cnt times" : 'not used'; + + if ($xram->{NAME} ne '') + { + $cnt = sprintf "%3u", $xram->{SIZE}; + print "${str0}:\t" . align($xram->{NAME}, STAT_ALIGN_SIZE) . "($cnt bytes) ($str1)\n"; + $next_addr = $_ + $xram->{SIZE}; + } + else + { + $str2 = "xram_$str0"; + print "${str0}:\t" . align($str2, STAT_ALIGN_SIZE) . "($str1)\n"; + $next_addr = $_ + 1; + } + } + } + + print "\n"; + } + +#------------------------------------------------------------------------------- + + # + # Prints the bits. + # + +sub emit_bits($) + { + my $Assembly_mode = $_[0]; + my ($bit, $name, $cnt, $str0, $str1, $str2); + + return if (! scalar(keys(%bit_by_address))); + + if ($Assembly_mode) + { + print ";$border0\n;\tbit data\n;$border0\n\n" . + "\t.area\tBSEG\t(BIT)\n\n"; + + foreach (sort {$a <=> $b} keys(%bit_by_address)) + { + $bit = $bit_by_address{$_}; + $name = $bit->{NAME}; + $str0 = ($name ne '') ? $name : (sprintf "bit_0x%02X", $_); + print "${str0}::\n\t.ds 1\n"; + } + } + else + { + print ";$border0\n;\tbit data\n;$border0\n\n"; + + foreach (sort {$a <=> $b} keys(%bit_by_address)) + { + $bit = $bit_by_address{$_}; + $name = $bit->{NAME}; + $str0 = sprintf "0x%02X", $_; + $str1 = ($name ne '') ? $name : "bit_$str0"; + $cnt = sprintf "%3u", $bit->{REF_COUNT}; + $str2 = ($bit->{REF_COUNT}) ? "used $cnt times" : 'not used'; + print "${str0}:\t" . align($str1, STAT_ALIGN_SIZE) . "($str2)\n"; + } + } + + print "\n"; + } + +#------------------------------------------------------------------------------- + + # + # Prints the map from the RAM. + # + +sub emit_ram_map() + { + my @map = (); + my ($ram, $i, $v); + + for ($i = 0; $i <= RAM_MAX_ADDR; ++$i) + { + $ram = $ram_by_address{$i}; + + if (defined($ram)) + { + $map[$i] = ($ram->{TYPE} == RAM_TYPE_DIR) ? 'd' : 'I'; + } + else + { + $map[$i] = ' '; + } + } + + $used_banks{0} = TRUE; + foreach (keys(%used_banks)) + { + $i = $_ * 8; + $v = $i + 7; + do + { + $map[$i] = $_; + ++$i; + } + while ($i <= $v); + } + + foreach (keys(%bit_by_address)) + { + $map[0x20 + int($_ / 8)] = 'B'; + } + + if ($stack_start > 0) + { + for ($i = $stack_start; $i <= RAM_MAX_ADDR; ++$i) + { + $map[$i] = 'S'; + } + } + + print ";$border0\n;\tInternal RAM layout\n;$border0\n\n"; + + for ($i = 0; $i <= RAM_MAX_ADDR; $i += 16) + { + printf "0x%02X: |", $i & 0xF0; + print join('|', @map[$i .. ($i + 15)]) . "|\n"; + } + + print "\n0-3:Register Banks, B:Bits, d:Data, I:iRAM, S:Stack\n\n"; + } + +#------------------------------------------------------------------------------- + + # + # Find the last address of HOME segment. + # + +sub find_HOME_last_address() + { + my $last_addr = 0; + + foreach (sort {$a <=> $b} keys(%blocks_by_address)) + { + my $block = \%{$blocks_by_address{$_}}; + + last if ($block->{TYPE} == BLOCK_CONST); + + if ($block->{TYPE} == BLOCK_INSTR) + { + last if (! defined($interrupts_by_address{$_})); + + last if ($block->{SIZE} > LJMP_SIZE); + + $last_addr = $_; + } + } + + return $last_addr; + } + +#------------------------------------------------------------------------------- + + # + # Prints a label belonging to the $Address. + # + +sub print_label($) + { + my $Address = $_[0]; + my ($label, $type); + + $label = $labels_by_address{$Address}; + + return FALSE if (! defined($label) || $label->{TYPE} == BL_TYPE_NONE); + + $type = $label->{TYPE}; + + if ($type == BL_TYPE_SUB) + { + print "\n;$border0\n"; + } + elsif ($type == BL_TYPE_JLABEL) + { + print "\n\t;$border2\n"; + } + + printf "\n$label->{NAME}:\n\n"; + $label->{PRINTED} = TRUE; + $prev_is_jump = FALSE; + return TRUE; + } + +#------------------------------------------------------------------------------- + + # + # Prints a table of constants. + # + +sub print_constants($$) + { + my ($Address, $BlockRef) = @_; + my ($size, $i, $len, $frag, $byte, $spc, $col); + my ($left_align, $right_align, $hc); + my @constants; + my @line; + + $size = $BlockRef->{SIZE}; + + return if (! $size); + + $hc = ($BlockRef->{TYPE} == BLOCK_JTABLE) || $hex_constant; + + $prev_is_jump = FALSE; + + $col = ($gen_assembly_code) ? ' ' : ' '; + + if ($gen_assembly_code) + { + print ";$table_border\n;\t\t $table_header |\n;$table_border\n"; + } + else + { + print "$table_border\n| | $table_header | $table_header |\n$table_border\n"; + } + + @constants = @rom[$Address .. ($Address + $size - 1)]; + $i = 0; + while (TRUE) + { + $len = $size - $i; + + last if (! $len); + + $len = TBL_COLUMNS if ($len > TBL_COLUMNS); + + if ($gen_assembly_code) + { + print "\t.db\t"; + } + else + { + printf "| 0x%04X | ", $Address; + } + + if (($spc = $Address % TBL_COLUMNS)) + { + $frag = TBL_COLUMNS - $spc; + $len = $frag if ($len > $frag); + } + + $left_align = $col x $spc; + $right_align = $col x (TBL_COLUMNS - $spc - $len); + @line = @constants[$i .. ($i + $len - 1)]; + $Address += $len; + $i += $len; + + if ($gen_assembly_code) + { + print $left_align . + join(', ', map { + sprintf((($hc || $_ < ord(' ') || $_ >= 0x7F) ? "0x%02X" : "'%c' "), $_ & 0xFF); + } @line) . "$right_align ;\n"; + } + else + { + print " $left_align" . join(' ', map { sprintf("%02X ", $_ & 0xFF); } @line); + + print "$right_align | $left_align " . + join(' ', map { + sprintf((($_ < ord(' ') || $_ >= 0x7F) ? "%02X " : "'%c'"), $_ & 0xFF); + } @line) . "$right_align |\n"; + } + } # while (TRUE) + + print (($gen_assembly_code) ? ";$table_border\n" : "$table_border\n"); + $prev_is_jump = FALSE; + } + +#------------------------------------------------------------------------------- + + # + # Disassembly contents of $blocks_by_address array. + # + +sub disassembler() + { + my ($ref, $home_last_addr, $sname); + + $home_last_addr = 0; + $prev_is_jump = FALSE; + $decoder_silent_level = SILENT0; + + if ($gen_assembly_code) + { + $table_header = join(' ', map { sprintf '%02X', $_ } (0 .. (TBL_COLUMNS - 1))); + $table_border = ('-' x (TBL_COLUMNS * 6 + 14)) . '+'; + } + else + { + $table_header = join(' ', map { sprintf '%02X', $_ } (0 .. (TBL_COLUMNS - 1))); + $table_border = '+' . ('-' x 10) . '+' . ('-' x (TBL_COLUMNS * 4 + 2)) . '+' . ('-' x (TBL_COLUMNS * 4 + 2)) . '+'; + } + + invalidate_DPTR_Rx(); + print "\n"; + + if ($gen_assembly_code) + { + emit_globals(TRUE); + emit_sfrs(TRUE); + emit_sfr_bits(TRUE); + emit_banks(TRUE); + emit_ram_data(TRUE); + emit_bits(TRUE); + + if ($stack_start > 0) + { + print ";$border0\n;\tStack segment\n;$border0\n\n\t.area\tSSEG\t(DATA)\n" . + "__start__stack:\n\t.ds 1\n\n"; + } + + emit_indirect_ram(TRUE); + emit_external_ram(TRUE); + + $home_last_addr = find_HOME_last_address(); + $sname = ($home_last_addr > 0) ? 'HOME' : 'CSEG'; + print ";$border0\n;\tCode\n;$border0\n\n\t.area\t$sname\t(CODE)\n\n"; + } + else + { + emit_ram_map(); + emit_globals(FALSE); + emit_sfrs(FALSE); + emit_sfr_bits(FALSE); + emit_banks(FALSE); + emit_ram_data(FALSE); + emit_bits(FALSE); + + if ($stack_start > 0) + { + printf ";$border0\n;\tStack: start=0x%02X, size=%u bytes\n;$border0\n\n", $stack_start, $stack_size; + } + + emit_indirect_ram(FALSE); + emit_external_ram(FALSE); + print ";$border0\n\n"; + } + + foreach (sort {$a <=> $b} keys(%blocks_by_address)) + { + $ref = \%{$blocks_by_address{$_}}; + + if ($ref->{TYPE} == BLOCK_INSTR) + { + if ($home_last_addr > 0 && $_ > $home_last_addr) + { + print "\n;$border0\n;\tCode\n;$border0\n\n\t.area\tCSEG\t(CODE)\n"; + $home_last_addr = 0; + } + + print_label($_); + print "\n" if ($prev_is_jump); + + instruction_decoder($_, $ref); + } + elsif ($ref->{TYPE} == BLOCK_CONST || $ref->{TYPE} == BLOCK_JTABLE) + { + print_label($_); + print "\n" if ($prev_is_jump); + + print_constants($_, $ref); + } + elsif ($ref->{TYPE} == BLOCK_EMPTY) + { + my $next_block = $_ + $ref->{SIZE}; + + if (! $gen_assembly_code) + { + printf("\n0x%04X: -- -- --\n .... -- -- --\n0x%04X: -- -- --\n", $_, $next_block - 1); + } + elsif ($next_block < $rom_size) + { + # Skip the empty code space. + + printf "\n\t.ds\t%u\n", $ref->{SIZE}; + } + } + } # foreach (sort {$a <=> $b} keys(%blocks_by_address)) + } + +#------------------------------------------------------------------------------- + + # + # If there are datas in the code, it is possible that some labels will + # be lost. This procedure prints them. + # + +sub print_hidden_labels() + { + foreach (sort {$a <=> $b} keys(%labels_by_address)) + { + my $label = $labels_by_address{$_}; + + print STDERR "The label: $label->{NAME} is hidden!\n" if (! $label->{PRINTED}); + } + } + +################################################################################ +################################################################################ + +sub usage() + { + print <<EOT; +Usage: $PROGRAM [options] <hex file> + + Options are: + + -M|--mcu <header.h> + + Header file of the MCU. + + -I|--include <path to header> + + Path of the header files of MCS51 MCUs. (Default: $default_include_path) + + --map-file <file.map> + + The map file belonging to the input hex file. (optional) + + -r|--rom-size <size of program memory> + +EOT +; + printf "\t Defines size of the program memory. (Default %u bytes.)\n", MCS51_ROM_SIZE; + print <<EOT; + + --const-area <start address> <end address> + + Designates a constant area (jumptables, texts, etc.), where data is + stored happen. The option may be given more times, that to select + more areas at the same time. (optional) + + -hc|--hex-constant + + The constants only shows in hexadecimal form. Otherwise if possible, + then shows all in character form. + + -as|--assembly-source + + Generates the assembly source file. (Eliminates before the instructions + visible address, hex codes and besides replaces the pseudo Rn<#x> + register names.) Emits global symbol table, SFR table, Bits table, etc. + + -rj|--recognize-jump-tables + + Recognizes the jump tables. + + -fl|--find-lost-labels + + Finds the "lost" labels. These may be found such in program parts, + which are directly not get call. + + --name-list <list_file> + + The file contains list of names. They may be: Names of variables and + names of labels. For example: + + [BIT] + 0x07:bit_variable + .. + .. + .. + [RAM] + 0x31:direct_ram_variable + .. + .. + .. + [IRAM] + 0x91:indirect_ram_variable + .. + .. + .. + [XRAM] + 0x208:external_ram_variable + .. + .. + .. + [ROM] + 0x05FC:function_or_label + .. + .. + .. + + The contents of list override the names from map file. + + -ne|--no-explanations + + Eliminates after the instructions visible explaining texts. + + -v <level> or --verbose <level> + + It provides information on from the own operation. + Possible value of the level between 0 and 10. (default: 0) + + -h|--help + + This text. +EOT +; + } + +################################################################################ +################################################################################ +################################################################################ + +foreach (@default_paths) + { + if (-d $_) + { + $default_include_path = $_; + last; + } + } + +if (! @ARGV) + { + usage(); + exit(1); + } + +for (my $i = 0; $i < @ARGV; ) + { + my $opt = $ARGV[$i++]; + + given ($opt) + { + when (/^-(r|-rom-size)$/o) + { + param_exist($opt, $i); + $rom_size = str2int($ARGV[$i++]); + + if ($rom_size < 1024) + { + printf STDERR "$PROGRAM: Code size of the MCS51 family greater than 1024 bytes!\n"; + exit(1); + } + elsif ($rom_size > MCS51_ROM_SIZE) + { + printf STDERR "$PROGRAM: Code size of the MCS51 family not greater %u bytes!\n", MCS51_ROM_SIZE; + exit(1); + } + } + + when (/^--const-area$/o) + { + my ($start, $end); + + param_exist($opt, $i); + $start = str2int($ARGV[$i++]); + + param_exist($opt, $i); + $end = str2int($ARGV[$i++]); + + if ($start > $end) + { + my $t = $start; + + $start = $end; + $end = $t; + } + elsif ($start == $end) + { + $start = MCS51_ROM_SIZE - 1; + $end = MCS51_ROM_SIZE - 1; + } + + add_const_area($start, $end) if ($start < $end); + } # when (/^--const-area$/o) + + when (/^-(hc|-hex-constant)$/o) + { + $hex_constant = TRUE; + } + + when (/^-(I|-include)$/o) + { + param_exist($opt, $i); + $include_path = $ARGV[$i++]; + } + + when (/^-(M|-mcu)$/o) + { + param_exist($opt, $i); + $header_file = $ARGV[$i++]; + } + + when (/^--map-file$/o) + { + param_exist($opt, $i); + $map_file = $ARGV[$i++]; + } + + when (/^-(as|-assembly-source)$/o) + { + $gen_assembly_code = TRUE; + } + + when (/^-(rj|-recognize-jump-tables)$/o) + { + $recognize_jump_tables = TRUE; + } + + when (/^-(fl|-find-lost-labels)$/o) + { + $find_lost_labels = TRUE; + } + + when (/^--name-list$/o) + { + param_exist($opt, $i); + $name_list = $ARGV[$i++]; + } + + when (/^-(ne|-no-explanations)$/o) + { + $no_explanations = TRUE; + } + + when (/^-(v|-verbose)$/o) + { + param_exist($opt, $i); + $verbose = int($ARGV[$i++]); + $verbose = 0 if (! defined($verbose) || $verbose < 0); + $verbose = 10 if ($verbose > 10); + } + + when (/^-(h|-help)$/o) + { + usage(); + exit(0); + } + + default + { + if ($hex_file eq '') + { + $hex_file = $opt; + } + else + { + print STDERR "$PROGRAM: We already have the source file name: $hex_file.\n"; + exit(1); + } + } + } # given ($opt) + } # for (my $i = 0; $i < @ARGV; ) + +$include_path = $default_include_path if ($include_path eq ''); + +if ($hex_file eq '') + { + print STDERR "$PROGRAM: What do you have to disassembled?\n"; + exit(1); + } + +is_file_ok($hex_file); + +init_mem(0, $rom_size - 1); +read_hex($hex_file); + +if ($header_file ne '') + { + is_file_ok("$include_path/$header_file"); + reset_preprocessor(); + $embed_level = 0; + read_header("$include_path/$header_file"); + } +else + { + $embed_level = 0; + foreach (grep(! /^\s*$|^\s*#/o, <DATA>)) + { + process_header_line($_); + } + } + +if ($map_file eq '') + { + ($map_file) = ($hex_file =~ /^(.+)\.hex$/io); + $map_file .= '.map'; + } + +$map_file = '' if (! -e $map_file); + +is_file_ok($name_list) if ($name_list ne ''); + +if ($recognize_jump_tables) + { + split_code_to_blocks(); + recognize_jump_tables_in_code(TRUE); + %blocks_by_address = (); + read_map_file(); + read_name_list(); + split_code_to_blocks(); + recognize_jump_tables_in_code(FALSE); + } +else + { + read_map_file(); + read_name_list(); + split_code_to_blocks(); + } + +fix_multi_byte_variables(); +determine_stack(); +preliminary_survey(SILENT2); +preliminary_survey(SILENT1); +find_labels_in_code(); +find_lost_labels_in_code() if ($find_lost_labels); +add_names_labels(); +disassembler(); +print_hidden_labels() if ($verbose > 2); + +__END__ +################################################################################ +# +# These the SFR-s and SBIT-s of the i8052 MCU. +# + +__sfr __at (0x80) P0; +__sfr __at (0x81) SP; +__sfr __at (0x82) DPL; +__sfr __at (0x83) DPH; +__sfr __at (0x87) PCON; +__sfr __at (0x88) TCON; +__sfr __at (0x89) TMOD; +__sfr __at (0x8A) TL0; +__sfr __at (0x8B) TL1; +__sfr __at (0x8C) TH0; +__sfr __at (0x8D) TH1; +__sfr __at (0x90) P1; +__sfr __at (0x98) SCON; +__sfr __at (0x99) SBUF; +__sfr __at (0xA0) P2; +__sfr __at (0xA8) IE; +__sfr __at (0xB0) P3; +__sfr __at (0xB8) IP; +__sfr __at (0xC8) T2CON; +__sfr __at (0xCA) RCAP2L; +__sfr __at (0xCB) RCAP2H; +__sfr __at (0xCC) TL2; +__sfr __at (0xCD) TH2; +__sfr __at (0xD0) PSW; +__sfr __at (0xE0) ACC; +__sfr __at (0xF0) B; + +__sbit __at (0x80) P0_0; +__sbit __at (0x81) P0_1; +__sbit __at (0x82) P0_2; +__sbit __at (0x83) P0_3; +__sbit __at (0x84) P0_4; +__sbit __at (0x85) P0_5; +__sbit __at (0x86) P0_6; +__sbit __at (0x87) P0_7; + +__sbit __at (0x88) IT0; +__sbit __at (0x89) IE0; +__sbit __at (0x8A) IT1; +__sbit __at (0x8B) IE1; +__sbit __at (0x8C) TR0; +__sbit __at (0x8D) TF0; +__sbit __at (0x8E) TR1; +__sbit __at (0x8F) TF1; + +__sbit __at (0x90) P1_0; +__sbit __at (0x91) P1_1; +__sbit __at (0x92) P1_2; +__sbit __at (0x93) P1_3; +__sbit __at (0x94) P1_4; +__sbit __at (0x95) P1_5; +__sbit __at (0x96) P1_6; +__sbit __at (0x97) P1_7; + +__sbit __at (0x98) RI; +__sbit __at (0x99) TI; +__sbit __at (0x9A) RB8; +__sbit __at (0x9B) TB8; +__sbit __at (0x9C) REN; +__sbit __at (0x9D) SM2; +__sbit __at (0x9E) SM1; +__sbit __at (0x9F) SM0; + +__sbit __at (0xA0) P2_0; +__sbit __at (0xA1) P2_1; +__sbit __at (0xA2) P2_2; +__sbit __at (0xA3) P2_3; +__sbit __at (0xA4) P2_4; +__sbit __at (0xA5) P2_5; +__sbit __at (0xA6) P2_6; +__sbit __at (0xA7) P2_7; + +__sbit __at (0xA8) EX0; +__sbit __at (0xA9) ET0; +__sbit __at (0xAA) EX1; +__sbit __at (0xAB) ET1; +__sbit __at (0xAC) ES; +__sbit __at (0xAD) ET2; +__sbit __at (0xAF) EA; + +__sbit __at (0xB0) RXD; +__sbit __at (0xB1) TXD; +__sbit __at (0xB2) INT0; +__sbit __at (0xB3) INT1; +__sbit __at (0xB4) T0; +__sbit __at (0xB5) T1; +__sbit __at (0xB6) WR; +__sbit __at (0xB7) RD; + +__sbit __at (0xB8) PX0; +__sbit __at (0xB9) PT0; +__sbit __at (0xBA) PX1; +__sbit __at (0xBB) PT1; +__sbit __at (0xBC) PS; +__sbit __at (0xBD) PT2; + +__sbit __at (0xC8) CP_RL2; +__sbit __at (0xC9) C_T2; +__sbit __at (0xCA) TR2; +__sbit __at (0xCB) EXEN2; +__sbit __at (0xCC) TCLK; +__sbit __at (0xCD) RCLK; +__sbit __at (0xCE) EXF2; +__sbit __at (0xCF) TF2; + +__sbit __at (0xD0) P; +__sbit __at (0xD1) F1; +__sbit __at (0xD2) OV; +__sbit __at (0xD3) RS0; +__sbit __at (0xD4) RS1; +__sbit __at (0xD5) F0; +__sbit __at (0xD6) AC; +__sbit __at (0xD7) CY; diff --git a/support/scripts/mega.mak b/support/scripts/mega.mak new file mode 100644 index 0000000..9f8d019 --- /dev/null +++ b/support/scripts/mega.mak @@ -0,0 +1,76 @@ +# A simple Makefile that attempts to weave everything together +# for a build. Basically: +# * Makes a temporary build directory +# * Copies itself and build.mak off, hands over to the new Makefile +# * Downloads the source +# * Compiles the native, then win32 versions +# * Takes the libs from native and hooks them into win32 +# * tars it all up and calls it done + +DIST = gbdk + +BUILD_DIR = /home/michaelh/tmp/$(DIST)-build +NATIVE = linux-linux +CROSS = linux-mingw32 +NATIVE_DIST = linux-glibc2 +CROSS_DIST = win32 + +VER = 2.21-pre1 + +all: spawn + +spawn: + mkdir -p $(BUILD_DIR) + cp build.mak mega.mak $(BUILD_DIR) + make -C $(BUILD_DIR) -f mega.mak build + +build: orig native cross dist + +dist: + cd $(NATIVE)/build; tar czf ../../$(DIST)-$(VER)-$(NATIVE_DIST).tar.gz $(DIST) +ifeq ($(CROSS_DIST), win32) + rm -f $(DIST)-$(VER)-$(CROSS_DIST).zip + cd $(CROSS)/build; zip -rlq9 ../../$(DIST)-$(VER)-$(CROSS_DIST).zip $(DIST) +else + cd $(CROSS)/build; tar czf ../../$(DIST)-$(VER)-$(CROSS_DIST).tar.gz $(DIST) +endif + +clean: + rm -rf $(BUILD_DIR) + +orig: + mkdir -p orig + cp build.mak orig + touch orig/logged_in # Assume already logged in + make -C orig -f build.mak update + +linux-linux: orig + mkdir -p linux-linux + (cd orig; tar cf - .) | (cd linux-linux; tar xf -) + +linux-mingw32: orig + mkdir -p linux-mingw32 + (cd orig; tar cf - .) | (cd linux-mingw32; tar xf -) + +native: $(NATIVE) dummy + cp build.mak $(NATIVE) + make -C $(NATIVE) -f build.mak COMPILE_MODE=$(NATIVE) + +dummy: + +# We do a first pass, ignored build on sdccconf.h as at the moment +# it fails while configuring the sim. +cross-bin: $(CROSS) dummy + cp build.mak $(CROSS) + -make -C $(CROSS) -f build.mak COMPILE_MODE=$(CROSS) sdcc/sdccconf.h + make -C $(CROSS) -f build.mak COMPILE_MODE=$(CROSS) sdcc-bin lcc tidy + +# Binary files are compiled; now copy the built libs from the native +# version across +cross-mix: + mv $(CROSS)/build/$(DIST)/bin $(CROSS)/build/$(DIST)/bin.1 + (cd $(NATIVE); tar cf - build/$(DIST)) | (cd $(CROSS); tar xf - ) + rm -rf $(CROSS)/build/$(DIST)/bin + mv $(CROSS)/build/$(DIST)/bin.1 $(CROSS)/build/$(DIST)/bin + +cross: cross-bin cross-mix diff --git a/support/scripts/mh2h.c b/support/scripts/mh2h.c new file mode 100644 index 0000000..892e06f --- /dev/null +++ b/support/scripts/mh2h.c @@ -0,0 +1,291 @@ +/*------------------------------------------------------------------------- + mh2h.c - megaheader to header conversion utility. This utility converts + the mega-header MCS51 mcs51reg.h file to multiple simple header files. + + We want the simple headers for compatibility with other compilers + and also for documentation(quick reference of registers names and + bit defines while programming). + At the same time we don't want to maintain all these redundant files. + + So this offers a solution of converting 1 master .h file into many + simple header files. + + We use the preprocessor(sdcpp) to do most of the work. Then we + use some c code to clean it up and make it look pretty. + + Usage# mh2h {include_dir {bin_dir}} ; no options used. + default include_dir is "/usr/local/share/sdcc/include" + default bin_dir(run sdcpp from is "" + + Written by Karl Bongers(kbongers@turbobit.com) +|-------------------------------------------------------------------------*/ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +void get_micro_h_name(char *name, char *ret_str); +void get_micro_list(void); +void strip_eol(char *str); +void strip_trailing_sp(char *str); + +#define MAX_LISTSIZE 100 +char *micro_list[MAX_LISTSIZE]; +char bin_dir[256]; +char inc_dir[256]; + +/*------------------------------------------------------------------------- +|-------------------------------------------------------------------------*/ +int main(int argc, char *argv[]) +{ + int stat; + FILE *fpi, *fpo; + char str[256]; + char fname[256]; + int mi; + int last_line_was_sfr = 1; // used to print pretty, add a blank line + + // 1st arg optional inc dir to pull mcs51reg.h from + if (argc > 1) { + strcpy(inc_dir, argv[1]); + printf("using %s bin dir\n", inc_dir); + } + else { + strcpy(inc_dir, "/usr/local/share/sdcc/include/"); + } + + // 2nd arg optional bin dir to run sdcpp from + if (argc > 2) { + strcpy(bin_dir, argv[2]); + printf("using %s bin dir\n", bin_dir); + } + else { + bin_dir[0] = 0; + } + + + get_micro_list(); + mi = 0; + while (micro_list[mi] != NULL) + { + printf("LIST:%s\n", micro_list[mi++]); + } + + mi = 0; + while (micro_list[mi] != NULL) + { + printf("converting %s\n", micro_list[mi]); + fflush(0); + + sprintf(str, "%ssdcpp -D%s %smcs51reg.h tmp1", + bin_dir, + micro_list[mi], + inc_dir); + + stat = system(str); + /* stat = -1, or 127 error */ + + fpi = fopen("tmp1", "r"); + if (fpi == NULL) { + printf("error opening file to read\n"); + exit(1); + } + + get_micro_h_name(micro_list[mi], fname); + //sprintf(fname, "tmp%d.h", mi+1); + + fpo = fopen(fname, "w"); + if (fpo == NULL) { + printf("error opening %s file to write\n", fname); + exit(1); + } + + fputs("/*-------------------------------------------------------------------------\n", + fpo); + fprintf(fpo, " %s - %s header file.\n", fname, micro_list[mi]); + fputs(" This file was automatically generated using mh2h utility\n", fpo); + fputs(" to convert from mcs51reg.h.\n", fpo); + fputs("|-------------------------------------------------------------------------*/\n", + fpo); + fprintf(fpo, "#define %s\n", micro_list[mi]); + fputs("#include <mcs51reg.h>\n\n", fpo); + + fprintf(fpo, "#if 0\n"); + fputs("The following is for your reference only\n", fpo); + fputs("and is an accurate translation of what the\n", fpo); + fputs("above included mcs51reg.h file generates.\n\n", fpo); + + while (fgets(str, 256, fpi) != NULL) { + strip_eol(str); + strip_trailing_sp(str); + + if (strlen(str) <= 0) + continue; + if (strncmp(str, "#line ", 6) == 0) + continue; + if (strncmp(str, "//", 2) == 0) + continue; + + if (strncmp(str, "sfr ", 4) == 0) + { + if (!last_line_was_sfr) + fputs("\n", fpo); /* for readability, add a blank line) */ + last_line_was_sfr = 1; + } + else + { + if (strncmp(str, "sbit ", 5) == 0) + fputs(" ", fpo); /* for readability, indent */ + + last_line_was_sfr = 0; + } + + //printf("[%d,%s]\n", strlen(str), str); + fputs(str, fpo); + fputs("\n", fpo); + } + fprintf(fpo, "#endif\n"); + + fclose(fpi); + fclose(fpo); + ++mi; + } // while micro_list[mi] + + return 0; +} + +/*------------------------------------------------------------------------- + get_micro_h_name - get a .h filename to output to. Preferably, we will + have this info in mcs51reg.h file(alias:8051.h) and not do it like this. +|-------------------------------------------------------------------------*/ +void get_micro_h_name(char *name, char *ret_str) +{ + int mi; +static int name_i = 1; + // note: pulling these from mcs51reg.h would be better... +static char *micro_strings[] = { + "MICROCONTROLLER_8051", "8051.h", + "MICROCONTROLLER_8052", "8052.h", + "MICROCONTROLLER_AT89CX051", "at89x051.h", + "MICROCONTROLLER_AT89S53", "at89s53.h", + "MICROCONTROLLER_AT89X52", "at89x52.h", + "MICROCONTROLLER_AT89X55", "at89x55.h", + "MICROCONTROLLER_DS5000", "ds5000.h", + "MICROCONTROLLER_DS5001", "ds5001.h", + "MICROCONTROLLER_DS80C32X", "ds80c32x.h", + "MICROCONTROLLER_DS80C390", "ds80c390.h", + "MICROCONTROLLER_DS89C420", "ds89c420.h", + "MICROCONTROLLER_DS8XC520", "ds8xc520.h", + "MICROCONTROLLER_SAB80515", "sab80515.h", + "MICROCONTROLLER_SAB80515A", "sab80515a.h", + "MICROCONTROLLER_SAB80517", "sab80517.h", + "MICROCONTROLLER_P80C552", "p80c552.h", + NULL}; + + *ret_str = 0; + mi = 0; + while (micro_strings[mi] != NULL) + { + if (strcmp(micro_strings[mi], name) == 0) + { + strcpy(ret_str, micro_strings[mi+1]); + } + mi += 2; + } + + if (*ret_str == 0) + { + sprintf(ret_str, "noname%d.h", name_i++); + printf("warning, could not find .h filename for %s using %s\n", + name, ret_str); + } +} + +/*------------------------------------------------------------------------- + get_micro_list - get the list of micros supported by mcs51reg.h, grab + this list out of the mcs51reg.h file. +|-------------------------------------------------------------------------*/ +void get_micro_list(void) +{ + FILE *fp; + char str[256]; + int li = 0; + char *s; + char *s_start; + + strcpy(str, inc_dir); + strcat(str, "mcs51reg.h"); + fp = fopen(str, "r"); + if (fp == NULL) { + printf("error opening %s file to read\n", str); + exit(1); + } + while (fgets(str, 256, fp) != NULL) + { + strip_eol(str); + strip_trailing_sp(str); + s = str; + while (*s == ' ') + ++s; + if (strlen(s) <= 0) + continue; + + if (strncmp(s, "MICROCONTROLLER_", 16) == 0) + { + s_start = s; + while ((*s != 0) && (*s != ' ')) + ++s; + *s = 0; + micro_list[li++] = strdup(s_start); // add to our list MICROCONTROLLER_X + if (li >= MAX_LISTSIZE) + exit(1); + } + } // while + + micro_list[li] = NULL; + + if (li == 0) + { + printf("Error, no MICROCONTROLLER_ defines found\n"); + exit(1); + } + printf("%d MICRO defines found\n", li); + fclose(fp); +} + +/*------------------------------------------------------------------------- +|-------------------------------------------------------------------------*/ +void strip_trailing_sp(char *str) +{ + int sz; + sz = strlen(str); + if (sz == 0) + return; + while(str[sz-1] == ' ') + { + str[sz-1] = 0; + --sz; + if (sz == 0) + return; + } +} + +/*------------------------------------------------------------------------- +|-------------------------------------------------------------------------*/ +void strip_eol(char *str) +{ + int sz; +#define is_eol_char(c) ((c == 0x0d) || (c == 0x0a)) + sz = strlen(str); + if (sz == 0) + return; + if (is_eol_char(str[sz-1])) + str[sz-1] = 0; + + sz = strlen(str); + if (sz == 0) + return; + if (is_eol_char(str[sz-1])) + str[sz-1] = 0; +} + diff --git a/support/scripts/optimize_pic16devices.pl b/support/scripts/optimize_pic16devices.pl new file mode 100755 index 0000000..fe59cb9 --- /dev/null +++ b/support/scripts/optimize_pic16devices.pl @@ -0,0 +1,897 @@ +#!/usr/bin/perl -w + +=back + + Copyright (C) 2012-2015 Molnar Karoly <molnarkaroly@users.sf.net> + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this library; see the file COPYING. If not, write to the + Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. + +================================================================================ + + This program optimizes or unoptimizes the pic16devices.txt file. + For more explanation: optimize_pic16devices.pl -h + + $Id: optimize_pic16devices.pl 9450 2016-01-09 16:47:43Z molnarkaroly $ +=cut + +use strict; +use warnings; +no if $] >= 5.018, warnings => "experimental::smartmatch"; # perl 5.16 +use 5.12.0; # when (regex) +use POSIX 'ULONG_MAX'; + +use constant FALSE => 0; +use constant TRUE => 1; + +use constant FNV1A32_INIT => 0x811C9DC5; +use constant FNV1A32_PRIME => 0x01000193; + +my $PROGRAM = ''; +my $verbose = 0; +my $file = ''; + +use constant OP_NULL => 0; +use constant OP_OPTIMIZE => 1; +use constant OP_UNOPTIMIZE => 2; + +my $operation = OP_NULL; + +my @devices_header = (); +my @device_names = (); + +#----------------------------------------------- + +=back + The structure of one element of the %devices_by_name: + + { + NAME => '', + COMMENTS => '', + RAM => { + SIZE => 0, + SPLIT => 0, + HASH => 0, + DIFF => 0 + }, + CONFIG => { + FIRST => 0, + LAST => 0, + WORDS => {}, + ORD_WORDS => [], + HASH => 0, + DIFF => 0 + }, + ID => { + FIRST => 0, + LAST => 0, + WORDS => {}, + ORD_WORDS => [], + HASH => 0, + DIFF => 0 + }, + XINST => 0 + CHILD => 0 + } +=cut + +use constant RELEVANCE_RAM => 2; +use constant RELEVANCE_CONFWORD => 4; +use constant RELEVANCE_IDWORD => 2; +use constant RELEVANCE_FATAL => 1000; + +my %devices_by_name = (); + +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@@@ Some auxiliary function. @@@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +sub basename($) + { + return ($_[0] =~ /([^\/]+)$/) ? $1 : ''; + } + +#--------------------------------------------------------------------------------------------------- + +sub param_exist($$) + { + die "This option \"$_[0]\" requires a parameter.\n" if ($_[1] > $#ARGV); + } + +#--------------------------------------------------------------------------------------------------- + +sub str2int($) + { + my $Str = $_[0]; + + return hex($1) if ($Str =~ /^0x([[:xdigit:]]+)$/io); + return oct($1) if ($Str =~ /^(0[0-7]+)$/o); + return int($Str) if ($Str =~ /^-?\d+$/o); + + die "This string not integer: \"$Str\""; + } + +#--------------------------------------------------------------------------------------------------- + +sub Log + { + return if (pop(@_) > $verbose); + foreach (@_) { print STDERR $_; } + print STDERR "\n"; + } + +#--------------------------------------------------------------------------------------------------- + +sub Open($$) + { + my ($File, $Function) = @_; + my $handle; + + open($handle, '<', $File) || die "${Function}(): Could not open the \"$File\" file.\n"; + return $handle; + } + +#--------------------------------------------------------------------------------------------------- + +sub fnv1a32_str($$) + { + my ($String, $Hash) = @_; + + foreach (unpack('C*', $String)) + { + $Hash ^= $_; + $Hash *= FNV1A32_PRIME; + $Hash &= 0xFFFFFFFF; + } + + return $Hash; + } + +#--------------------------------------------------------------------------------------------------- + +sub fnv1a32_int32($$) + { + my ($Int, $Hash) = @_; + my $i; + + for ($i = 4; $i; --$i) + { + $Hash ^= $Int & 0xFF; + $Hash *= FNV1A32_PRIME; + $Hash &= 0xFFFFFFFF; + $Int >>= 8; + } + + return $Hash; + } + +#--------------------------------------------------------------------------------------------------- + +sub versionCompare($$) + { + my ($Str1, $Str2) = @_; + + if ((${$Str1} =~ /^\d/o) && (${$Str2} =~ /^\d/o)) + { + # $Str1 number and $Str2 number + return (int(${$Str1}) <=> int(${$Str2})); + } + + return (${$Str1} cmp ${$Str2}); + } + +#--------------------------------------------------------------------------------------------------- + +sub versionSort($$) + { + my @a_s = ($_[0] =~ /(\d+|\D+)/go); + my @b_s = ($_[1] =~ /(\d+|\D+)/go); + my ($i, $k, $end, $ret); + + $i = scalar(@a_s); + $k = scalar(@b_s); + + if ($i < $k) + { + $end = $i; + $ret = -1; + } + elsif ($i == $k) + { + $end = $i; + $ret = 0; + } + else + { + $end = $k; + $ret = 1; + } + + for ($i = 0; $i < $end; ++$i) + { + $k = versionCompare(\$a_s[$i], \$b_s[$i]); + + return $k if ($k != 0); + } + + return $ret; + } + +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ The important procedures. @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + # + # Reads the entire pic16devices.txt file. + # + +sub read_pic16devices_txt($) + { + my $File = $_[0]; + my ($parent, $first, $last, $txt, $ref, $is_using); + my $in = Open($File, 'read_pic16devices_txt'); + my $header = TRUE; + my $device = undef; + + Log("Reads the $File file.", 4); + + while (<$in>) + { + chomp; + s/\r$//o; + s/\s+$//o; + + $header = FALSE if (/^\s*name\b/io); + + if ($header) + { + push(@devices_header, $_); + next; + } + + given ($_) + { + when (/^\s*name\s+(\w+)$/io) + { + $device = { + NAME => $1, + COMMENTS => undef, + RAM => { + SIZE => -1, + SPLIT => -1, + HASH => 0, + DIFF => 0 + }, + CONFIG => { + FIRST => -1, + LAST => -1, + WORDS => {}, + ORD_WORDS => [], + HASH => 0, + DIFF => 0 + }, + ID => { + FIRST => -1, + LAST => -1, + WORDS => {}, + ORD_WORDS => [], + HASH => 0, + DIFF => 0 + }, + XINST => -1, + CHILD => FALSE + }; + + Log("name : $1", 7); + $devices_by_name{$1} = $device; + $is_using = FALSE; + } + + when (/^\s*using\s+(\w+)$/io) + { + die "Device not exists." if (! defined($device)); + + $parent = $devices_by_name{$1}; + + die "In device - \"$device->{NAME}\" - not exists the parent: \"$1\"\n" if (! defined($parent)); + + # Unlock the "using" keyword. + + Log("using : $1", 7); + %{$device->{RAM}} = %{$parent->{RAM}}; + $device->{CONFIG}->{FIRST} = $parent->{CONFIG}->{FIRST}; + $device->{CONFIG}->{LAST} = $parent->{CONFIG}->{LAST}; + %{$device->{CONFIG}->{WORDS}} = %{$parent->{CONFIG}->{WORDS}}; + $device->{ID}->{FIRST} = $parent->{ID}->{FIRST}; + $device->{ID}->{LAST} = $parent->{ID}->{LAST}; + %{$device->{ID}->{WORDS}} = %{$parent->{ID}->{WORDS}}; + $device->{XINST} = $parent->{XINST}; + $is_using = TRUE; + } + + when (/^\s*ramsize\s+(\w+)$/io) + { + die "Device not exists." if (! defined($device)); + + Log("ramsize : $1", 7); + $device->{RAM}->{SIZE} = str2int($1); + } + + when (/^\s*split\s+(\w+)$/io) + { + die "Device not exists." if (! defined($device)); + + Log("split : $1", 7); + $device->{RAM}->{SPLIT} = str2int($1); + } + + when (/^\s*configrange\s+(\w+)\s+(\w+)$/io) + { + die "Device not exists." if (! defined($device)); + + ($first, $last) = (str2int($1), str2int($2)); + Log("configrange: $first, $last", 7); + + if (($device->{CONFIG}->{FIRST} >= 0) || ($device->{CONFIG}->{LAST} >= 0)) + { + Log("The configrange already exists in the \"$device->{NAME}\".", 0); + + if (($device->{CONFIG}->{FIRST} != $first) || ($device->{CONFIG}->{LAST} != $last)) + { + Log(" In addition the previous values different from the new values.", 0); + Log(sprintf(" previous: 0x%06X - 0x%06X, new: 0x%06X - 0x%06X", + $device->{CONFIG}->{FIRST}, $device->{CONFIG}->{LAST}, + $first, $last), 0); + } + + # The previous values invalid. + + $device->{CONFIG}->{WORDS} = {}; + } + + $device->{CONFIG}->{FIRST} = $first; + $device->{CONFIG}->{LAST} = $last; + } + + when (/^\s*configword\s+(\w+)\s+(\w+)\s+(\w+)(?:\s+(\w+))?$/io) + { + my ($addr, $mask, $val, $amask, $hash); + + die "Device not exists." if (! defined($device)); + + ($addr, $mask, $val) = (str2int($1), str2int($2), str2int($3)); + + if (defined($4)) + { + $amask = str2int($4); + Log("configword : $addr, $mask, $val, $amask", 7); + } + else + { + $amask = -1; + Log("configword : $addr, $mask, $val", 7); + } + + $hash = fnv1a32_int32($addr, FNV1A32_INIT); + $hash = fnv1a32_int32($mask, $hash); + $hash = fnv1a32_int32($val, $hash); + $hash = fnv1a32_int32($amask, $hash); + $ref = { + ADDRESS => $addr, + MASK => $mask, + VALUE => $val, + AND_MASK => $amask, + HASH => $hash + }; + + if ($is_using && ! defined($device->{CONFIG}->{WORDS}->{$addr})) + { + printf STDERR "Database error: The 0x%06X config word not exist in the ancestor MCU!\n", $addr; + exit(1); + } + + $device->{CONFIG}->{WORDS}->{$addr} = $ref; + } + + when (/^\s*XINST\s+(\w+)\s*$/io) + { + die "Device not exists." if (! defined($device)); + + Log("XINST : $1", 7); + $device->{XINST} = str2int($1); + } + + when (/^\s*idlocrange\s+(\w+)\s+(\w+)$/io) + { + die "Device not exists." if (! defined($device)); + + Log("idlocrange : $1 $2", 7); + $device->{ID}->{FIRST} = str2int($1); + $device->{ID}->{LAST} = str2int($2); + } + + when (/^\s*idword\s+(\w+)\s+(\w+)$/io) + { + my ($addr, $val, $hash); + + die "Device not exists." if (! defined($device)); + + ($addr, $val) = (str2int($1), str2int($2)); + Log("idword : $1 $2", 7); + $hash = fnv1a32_int32($addr, FNV1A32_INIT); + $hash = fnv1a32_int32($val, $hash); + $ref = { + ADDRESS => $addr, + VALUE => $val, + HASH => $hash + }; + + if ($is_using && ! defined($device->{ID}->{WORDS}->{$addr})) + { + printf STDERR "Database error: The 0x%06X id word not exist in the ancestor MCU!\n", $addr; + exit(1); + } + + $device->{ID}->{WORDS}->{$addr} = $ref; + } + + when (/^\s*#/o) + { + die "Device not exists." if (! defined($device)); + + Log("comment : \"$_\"", 7); + push(@{$device->{COMMENTS}}, $_); + } + + default + { + Log("unrecognized line: \"$_\"", 7); + } + } # given ($_) + } + + close($in); + } + +#--------------------------------------------------------------------------------------------------- + +sub make_hashes($) + { + my $DevRef = $_[0]; + my ($ref1, $ref2, $hash); + + $ref1 = $DevRef->{RAM}; + $hash = fnv1a32_int32($ref1->{SIZE}, FNV1A32_INIT); + $ref1->{HASH} = fnv1a32_int32($ref1->{SPLIT}, $hash); + + #................. + + $ref1 = $DevRef->{CONFIG}; + $hash = fnv1a32_int32($ref1->{FIRST}, FNV1A32_INIT); + $hash = fnv1a32_int32($ref1->{LAST}, $hash); + + @{$ref1->{ORD_WORDS}} = sort {$a->{ADDRESS} <=> $b->{ADDRESS}} values %{$ref1->{WORDS}}; + + foreach $ref2 (@{$ref1->{ORD_WORDS}}) + { + $hash = fnv1a32_int32($ref2->{ADDRESS}, $hash); + $hash = fnv1a32_int32($ref2->{MASK}, $hash); + $hash = fnv1a32_int32($ref2->{VALUE}, $hash); + $hash = fnv1a32_int32($ref2->{AND_MASK}, $hash); + } + + $ref1->{HASH} = $hash; + + #................. + + $ref1 = $DevRef->{ID}; + + if (defined($ref1)) + { + $hash = fnv1a32_int32($ref1->{FIRST}, FNV1A32_INIT); + $hash = fnv1a32_int32($ref1->{LAST}, $hash); + + if (defined($ref1->{WORDS})) + { + @{$ref1->{ORD_WORDS}} = sort {$a->{ADDRESS} <=> $b->{ADDRESS}} values %{$ref1->{WORDS}}; + + foreach $ref2 (@{$ref1->{ORD_WORDS}}) + { + $hash = fnv1a32_int32($ref2->{ADDRESS}, $hash); + $hash = fnv1a32_int32($ref2->{VALUE}, $hash); + } + } + + $ref1->{HASH} = $hash; + } + } + +#--------------------------------------------------------------------------------------------------- + +sub difference_of_arrays($$) + { + my ($ArrayRef1, $ArrayRef2) = @_; + my ($diff, $len, $i); + + $len = @{$ArrayRef1}; + # The lenght of two arrays must be of equal. + return RELEVANCE_FATAL if ($len != scalar(@{$ArrayRef2})); + + $diff = 0; + for ($i = 0; $i < $len; ++$i) + { + if ($ArrayRef1->[$i]->{ADDRESS} != $ArrayRef2->[$i]->{ADDRESS}) + { + $diff += RELEVANCE_FATAL; + $ArrayRef1->[$i]->{DIFF} = TRUE; + } + elsif ($ArrayRef1->[$i]->{HASH} != $ArrayRef2->[$i]->{HASH}) + { + $diff += RELEVANCE_CONFWORD; + $ArrayRef1->[$i]->{DIFF} = TRUE; + } + else + { + $ArrayRef1->[$i]->{DIFF} = FALSE; + } + } + + return $diff; + } + +#--------------------------------------------------------------------------------------------------- + + # + # Compares the $Dev1 and the $Dev2. + # + +sub difference_of_devices($$) + { + my ($DevRef1, $DevRef2) = @_; + my ($diff, $r1, $r2, $aref1, $aref2, $len1, $len2, $min, $i); + + $i = defined($DevRef1) + defined($DevRef2); + + return RELEVANCE_FATAL if ($i != 2); + + $diff = 0; + $r1 = $DevRef1->{RAM}; + $r2 = $DevRef2->{RAM}; + + if ($r1->{HASH} != $r2->{HASH}) + { + $diff += RELEVANCE_RAM; + $r1->{DIFF} = TRUE; + } + else + { + $r1->{DIFF} = FALSE; + } + + $r1 = $DevRef1->{CONFIG}; + $r2 = $DevRef2->{CONFIG}; + + if ($r1->{HASH} != $r2->{HASH}) + { + $diff += RELEVANCE_FATAL if ($r1->{FIRST} != $r2->{FIRST}); + $diff += RELEVANCE_FATAL if ($r1->{LAST} != $r2->{LAST}); + $diff += difference_of_arrays($r1->{ORD_WORDS}, $r2->{ORD_WORDS}); + $r1->{DIFF} = TRUE; + } + else + { + $r1->{DIFF} = FALSE; + } + + $r1 = $DevRef1->{ID}; + $r2 = $DevRef2->{ID}; + + if ($r1->{HASH} != $r2->{HASH}) + { + $diff += RELEVANCE_FATAL if ($r1->{FIRST} != $r2->{FIRST}); + $diff += RELEVANCE_FATAL if ($r1->{LAST} != $r2->{LAST}); + $diff += difference_of_arrays($r1->{ORD_WORDS}, $r2->{ORD_WORDS}); + $r1->{DIFF} = TRUE; + } + else + { + $r1->{DIFF} = FALSE; + } + + # The value of two XINST elements must be of equal. + $diff += RELEVANCE_FATAL if ($DevRef1->{XINST} != $DevRef1->{XINST}); + return $diff; + } + +#--------------------------------------------------------------------------------------------------- + +sub print_config_words($) + { + my $Words = $_[0]; + + return if (! defined($Words)); + + foreach (@{$Words}) + { + printf "configword 0x%06X 0x%02X 0x%02X", $_->{ADDRESS}, $_->{MASK}, $_->{VALUE}; + printf " 0x%02X", $_->{AND_MASK} if ($_->{AND_MASK} > 0); + print "\n"; + } + } + +#--------------------------------------------------------------------------------------------------- + +sub print_id_words($) + { + my $Words = $_[0]; + + return if (! defined($Words)); + + foreach (@{$Words}) + { + printf "idword 0x%06X 0x%02X\n", $_->{ADDRESS}, $_->{VALUE}; + } + } + +#--------------------------------------------------------------------------------------------------- + +sub print_diff_config_words($) + { + my $ArrayRef = $_[0]; + + foreach (@{$ArrayRef}) + { + next if (! $_->{DIFF}); + + printf "configword 0x%06X 0x%02X 0x%02X", $_->{ADDRESS}, $_->{MASK}, $_->{VALUE}; + printf " 0x%02X", $_->{AND_MASK} if ($_->{AND_MASK} > 0); + print "\n"; + } + } + +#--------------------------------------------------------------------------------------------------- + +sub print_diff_id_words($) + { + my $ArrayRef = $_[0]; + + foreach (@{$ArrayRef}) + { + next if (! $_->{DIFF}); + + printf "idword 0x%06X 0x%02X\n", $_->{ADDRESS}, $_->{VALUE}; + } + } + +#--------------------------------------------------------------------------------------------------- + +sub print_device($) + { + my $Index = $_[0]; + my $mcu = $device_names[$Index]; + my $dev = $devices_by_name{$mcu}; + my ($min_diff, $diff); + my ($ac, $ancestor, $i, $ref1, $ref2); + + return if (! defined($dev)); + + Log("Prints the $mcu MCU.", 4); + + $ancestor = undef; + + if ($operation == OP_OPTIMIZE) + { + # Optimized writing is required. + + $min_diff = ULONG_MAX; + for ($i = 0; $i < scalar(@device_names); ++$i) + { + $ac = $devices_by_name{$device_names[$i]}; + + last if ($Index == $i); + next if ($ac->{CHILD}); + + $diff = difference_of_devices($dev, $ac); + + if ($min_diff > $diff) + { + $min_diff = $diff; + $ancestor = $ac; + } + } + + $ancestor = undef if ($min_diff > 15); + } + + print "name $dev->{NAME}\n"; + + if ($dev->{COMMENTS}) + { + foreach (@{$dev->{COMMENTS}}) + { + print "$_\n"; + } + } + + $ref1 = $dev->{RAM}; + + if (defined($ancestor)) + { + $dev->{CHILD} = TRUE; + + print "using $ancestor->{NAME}\n"; + difference_of_devices($dev, $ancestor); + + if ($ref1->{DIFF}) + { + $ref2 = $ancestor->{RAM}; + + if ($ref1->{SIZE} != $ref2->{SIZE}) + { + print "ramsize $ref1->{SIZE}\n"; + } + + if ($ref1->{SPLIT} != $ref2->{SPLIT}) + { + printf "split 0x%02X\n", $ref1->{SPLIT}; + } + } + + $ref1 = $dev->{CONFIG}; + + if ($ref1->{DIFF}) + { + print_diff_config_words($ref1->{ORD_WORDS}); + } + + printf "XINST $dev->{XINST}\n" if (($ancestor->{XINST} < 0) && ($dev->{XINST} > 0)); + + $ref1 = $dev->{ID}; + + if ($ref1->{DIFF}) + { + print_diff_id_words($ref1->{ORD_WORDS}); + } + } + else + { + print "ramsize $ref1->{SIZE}\n"; + printf "split 0x%02X\n", $ref1->{SPLIT}; + + $ref1 = $dev->{CONFIG}; + printf "configrange 0x%06X 0x%06X\n", $ref1->{FIRST}, $ref1->{LAST}; + print_config_words($ref1->{ORD_WORDS}); + + printf "XINST $dev->{XINST}\n" if ($dev->{XINST} > 0); + + $ref1 = $dev->{ID}; + + if (($ref1->{FIRST} > 0) && ($ref1->{LAST} > 0)) + { + printf "idlocrange 0x%06X 0x%06X\n", $ref1->{FIRST}, $ref1->{LAST}; + print_id_words($ref1->{ORD_WORDS}); + } + } + } + +#--------------------------------------------------------------------------------------------------- + +sub usage() + { + print <<EOT +Usage: $PROGRAM <option> path/to/pic16devices.txt > output.txt + + Options are: + + -o or --optimize + + If a MCU features matches with an earlier listed MCU features, + then use the "using" keyword and with this method significantly + reduces the file size. + + -u or --unoptimize + + Unlocks the "using" keywords and displays the full original + content. + + -v <level> or --verbose <level> + + It provides information on from the own operation. + Possible value of the level between 0 and 10. (default: 0) + + -h or --help + + This text. +EOT +; + } + +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ The main program. @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +$PROGRAM = basename($0); + +for (my $i = 0; $i < @ARGV; ) + { + my $opt = $ARGV[$i++]; + + given ($opt) + { + when (/^-(o|-optimize)$/o) { $operation = OP_OPTIMIZE; } + + when (/^-(u|-unoptimize)$/o) { $operation = OP_UNOPTIMIZE; } + + when (/^-(v|-verbose)$/o) + { + param_exist($opt, $i); + $verbose = int($ARGV[$i++]); + $verbose = 0 if (! defined($verbose) || $verbose < 0); + $verbose = 10 if ($verbose > 10); + } + + when (/^-(h|-help)$/o) + { + usage(); + exit(0); + } + + default + { + $file = $opt; + } + } # given ($opt) + } # for (my $i = 0; $i < @ARGV; ) + +if (($file eq '') || ($operation == OP_NULL)) + { + usage(); + exit(0); + } + +(-f $file) || die "This file - \"$file\" - not exist!"; + +read_pic16devices_txt($file); + +@device_names = sort {versionSort($a, $b)} keys(%devices_by_name); + +foreach (@device_names) + { + make_hashes($devices_by_name{$_}); + } + +print join("\n", @devices_header) . "\n"; + +my $i = 0; +my $v = @device_names; +while (TRUE) + { + print_device($i); + ++$i; + last if ($i == $v); + print "\n"; + } diff --git a/support/scripts/pic14-header-parser.pl b/support/scripts/pic14-header-parser.pl new file mode 100755 index 0000000..4413c25 --- /dev/null +++ b/support/scripts/pic14-header-parser.pl @@ -0,0 +1,3297 @@ +#!/usr/bin/perl -w + +=back + + Copyright (C) 2012-2014, Molnar Karoly <molnarkaroly@users.sf.net> + + This file is part of SDCC. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source distribution. + +================================================================================ + + Proposal for use: ./pic14-header-parser.pl -gp + + This program creates seven files in the actual directory: + + adc.h.gen + ccp.h.gen + pwm.h.gen + i2c.h.gen + spi.h.gen + usart.h.gen + peripheral.groups + + In these the MCUs can be seen in groups, according to a periphery. + These informations helps to realize the handling of periphery. + Of course necessary to study the data sheets as well. + + $Id: pic14-header-parser.pl 9072 2014-09-17 14:00:11Z molnarkaroly $ +=cut + +use Data::Dumper; +use strict; +use warnings; +no if $] >= 5.018, warnings => "experimental::smartmatch"; # perl 5.16 +use 5.10.1; +use feature 'switch'; # Starting from 5.10.1. +use POSIX 'ULONG_MAX'; + +use constant FALSE => 0; +use constant TRUE => 1; + +use constant P_NO_SHOW_BITS => 0; +use constant P_NO_SHOW_IF_EMPTY => 1; +use constant P_ALWAYS_SHOW => 2; +use constant P_SHOW_ONLY_NAME => 3; + +my @default_paths = + ( + '/usr/share/sdcc/non-free/include', + '/usr/share/sdcc/include', + '/usr/local/share/sdcc/non-free/include', + '/usr/local/share/sdcc/include' + ); + +my $default_port = 'pic14'; +my $header_name_filter = 'pic1[026][a-z]+\d+([a-z]|([a-z]+\d+)?).h'; + +my $include_path; +my $out_tail = '.gen'; +my $peri_group = 'peripheral.groups'; +my $table_border = (' ' x 19) . '+' . ('---------+' x 8); + +my %reg_addresses = (); + +my @some_ADC_registers = + ( + 'ADCON\d+[HL]?|AD\d*CON\d*', + 'ADCOMCON', + 'AD\d*RES[HL]?', + 'ANSEL[\dHL]?', + 'ANSEL[A-Z]' + ); + +#----------------------------------------------- + +=back + The structure of one element of the @periphery_table array. + + { + NAME => '', + REGS => [ + { + VALID_REGS => '', + VALID_BITS => '', + PRINT_MODE => P_ALWAYS_SHOW + }, + + ... + + { + } + ] + } + +=cut + +my @periphery_table = (); + +#----------------------------------------------- + +=back + The structure of one element of the @io_table_by_mcu hash: + + { + 'ADC' => { + 'AN0' => [], + + ... + + 'AN4' => [] + }, + + ... + + 'USART' => {} + } +=cut + +my %io_table_by_mcu = (); + +#----------------------------------------------- + +=back + The structure of one element of the @io_dir_table_by_mcu hash: + + { + 'ADC' => {}, + + ... + + 'USART' => { + 'RX' => 1, + 'TX' => 0 + } + } +=cut + +my %io_dir_table_by_mcu = (); + +#----------------------------------------------- + +=back + The structure of one element of the @mcu_raw array: + + { Descriptor of MCU. + NAME => '', The name of MCU. + ENHANCED => 0, This is enhanced MCU. + REG_REFS => { Accelerate searching of the registers. + 'PIR1' => register_reference, ---+ + 'TRISD' => register_reference, ---|---+ + ... | | + ... | . + }, | . + REG_ARRAY => [ The array of registers. | . + { A register. <--+ + NAME => 'PIR1', The name of register. + ADDRESS => 0, The address of register. + BITNAMES => [ The bits of register. + [], The names of bit. + [], + [], + [], + [], + [], + [], + [] + ] + }, + + ... + + { + } + ] + } +=cut + +my @mcu_raw = (); + +#----------------------------------------------- + +=back + The structure of one element of the @mcu_filtered and @mcu_groups arrays: + + { Descriptor of MCU. + NAME => '', The name of MCU. + ENHANCED => 0, This is enhanced MCU. + IN_GROUP => 0, This member of a MCU group. + REG_REFS => { Accelerate searching of the registers. + 'PIR1' => register_reference, ----------------------+ + 'TRISD' => register_reference, ----------------------|---+ + ... | | + ... | | + }, | . + REG_GROUPS => [ The group of all necessary register. | . + { The first register group. | . + VALID_REGS => '', The valid names of registers. | + VALID_BITS => '', The valid names of bits. | + PRINT_MODE => 0, The mode of print. | + REG_ARRAY => [ The array of registers. | + { A register. <-----+ + NAME => 'PIR1', The name of register. + ADDRESS => 0, The address of register. + GROUP => undef, Back reference of REG_GROUPS. + TOUCHED => 0, Touched register during the search. + EMPTY => 0, True if the register became empty after the filtering. + BITNAMES => [ The bits of register. + [], The names of bit. + [], + [], + [], + [], + [], + [], + [] + ] + }, + + ... + + { + } + ] + }, + + ... + + { The last register group. + } + ] + } +=cut + +my @mcu_filtered = (); + +my @mcu_groups = (); + +my %definitions = (); +my %io_groups = (); + +#----------------------------------------------- + +my $verbose = 0; +my $make_groups; +my $only_prime; +my $out_handler; +my $initial_border; + +my @regular = (); +my @enhanced = (); +my $peri_groups = ''; + +################################################################################ +################################################################################ +################################################################################ +################################################################################ + +sub basename($) + { + return ($_[0] =~ /([^\/]+)$/) ? $1 : ''; + } + +#------------------------------------------------------------------------------- + +sub Log + { + return if (pop(@_) > $verbose); + foreach (@_) { print STDERR $_; } + print STDERR "\n"; + } + +#------------------------------------------------------------------------------- + +sub Out + { + foreach (@_) { print $out_handler $_; } + } + +#------------------------------------------------------------------------------- + +sub Outl + { + Out(@_); + print $out_handler "\n"; + } + +#------------------------------------------------------------------------------- + +sub Outf + { + printf $out_handler (shift(@_), @_); + } + +#------------------------------------------------------------------------------- + +sub Outfl + { + Outf(@_); + print $out_handler "\n"; + } + +#------------------------------------------------------------------------------- + +sub smartCompare($$) + { + my ($Str1, $Str2) = @_; + + if (${$Str1} =~ /^\d/o && ${$Str2} =~ /^\d/o) + { + # $Str1 number and $Str2 number + return (int(${$Str1}) <=> int(${$Str2})); + } + + return (${$Str1} cmp ${$Str2}); + } + +#------------------------------------------------------------------------------- + +sub smartSort($$) + { + my @a_s = ($_[0] =~ /(\d+|\D+)/go); + my @b_s = ($_[1] =~ /(\d+|\D+)/go); + my ($i, $k, $end, $ret); + + $i = scalar(@a_s); + $k = scalar(@b_s); + + if ($i < $k) + { + $end = $i; + $ret = -1; + } + elsif ($i == $k) + { + $end = $i; + $ret = 0; + } + else + { + $end = $k; + $ret = 1; + } + + for ($i = 0; $i < $end; ++$i) + { + $k = smartCompare(\$a_s[$i], \$b_s[$i]); + + return $k if ($k != 0); + } + + return $ret; + } + +#------------------------------------------------------------------------------- + +sub exist_in_list($$) + { + my ($List, $Member) = @_; + + foreach (@{$List}) + { + return TRUE if ($Member =~ /^$_$/); + } + + return FALSE; + } + +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@ Populates the peripheral table. @@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +sub add_periphery($) + { + my $peri = { + NAME => lc($_[0]), + REGS => [] + }; + + push(@periphery_table, $peri); + return $peri->{REGS}; + } + +#------------------------------------------------------------------------------- + +sub add_reg_def($) + { + my $def = { + VALID_REGS => '', + VALID_BITS => '', + PRINT_MODE => P_ALWAYS_SHOW + }; + + push(@{$_[0]}, $def); + } + +#------------------------------------------------------------------------------- + +sub resolve_define($) + { + my $Name = $_[0]; + my $ig = \@{$io_groups{$Name}}; + my @array = (); + my $r; + + if (defined($ig) && scalar(@{$ig}) > 0) + { + foreach (@{$ig}) + { + $r = $definitions{$_}; + push(@array, ((defined($r)) ? $r : $_)); + } + } + else + { + $r = $definitions{$Name}; + push(@array, ((defined($r)) ? $r : $Name)); + } + + return \@array; + } + +#------------------------------------------------------------------------------- + +sub add_io_pins($$$) + { + my ($Mcu_group, $Peri, $Pins) = @_; + my %pin_groups = (); + my ($mcu, $io); + my @ports; + + foreach (@{$Pins}) + { + if ($_ !~ /^(\w+):(\S+)$/o) + { + print STDERR "This piece is wrong: \"$_\" (" . join(',', @{$Mcu_group}) . ")\n"; + exit(1); + } + + $io = $1; + @ports = (); + + foreach (split('/', $2)) + { + if ($_ =~ /^(\w+)\[(\d+)-(\d+)\]$/o) + { + # This is a section. E.g.: "RI[0-8]" + + my ($name, $first, $second) = ($1, int($2), int($3)); + + if ($first > $second) + { + print STDERR "\"$_\" The first number ($first) greather than the second number ($second)!\n"; + exit(1); + } + + while ($first <= $second) + { + push(@ports, @{resolve_define("$name$first")}); + ++$first; + } + } + else + { + # This is a name. E.g.: "RD7" or "RO2" + + push(@ports, @{resolve_define($_)}); + } + } # foreach (split('/', $2)) + + $pin_groups{$io} = [ sort {$a cmp $b} @ports ]; + } # foreach (@{$Pins}) + + foreach $mcu (@{$Mcu_group}) + { + foreach $io (keys(%pin_groups)) + { + $io_table_by_mcu{$mcu}->{$Peri}{$io} = [ @{$pin_groups{$io}} ]; + } + } + } + +#------------------------------------------------------------------------------- + +sub add_io_dir($$$) + { + my ($Mcu_group, $Peri, $Pins) = @_; + my %pin_groups = (); + my ($mcu, $io, $dir); + my @ports; + + foreach (@{$Pins}) + { + if ($_ !~ /^(\w+):([01])$/o) + { + print STDERR "This piece is wrong: \"$_\" (" . join(',', @{$Mcu_group}) . ")\n"; + exit(1); + } + + $dir = int($2); + @ports = @{resolve_define($1)}; + + if (@ports > 1) + { + print STDERR "Only one I/O line can be specified: \"$_\" (" . join(',', @{$Mcu_group}) . ")\n"; + exit(1); + } + + $pin_groups{$ports[0]} = $dir; + } # foreach (@{$Pins}) + + foreach $mcu (@{$Mcu_group}) + { + foreach $io (keys(%pin_groups)) + { + $io_dir_table_by_mcu{$mcu}->{$Peri}{$io} = $pin_groups{$io}; + } + } + } + +#------------------------------------------------------------------------------- + +sub load_periphery_data() + { + my $periphery = undef; + my @mcu_group = (); + my @blocks = (); + my ($line, $block, $key, $val); + + foreach (grep(! /^\s*$|^\s*#/o, <DATA>)) + { + chomp; + s/#.*$//o; # Remove ending comment. + s/^\s*|\s*$//go; # Remove starting and ending whitespaces. + $line = $_; + + if ($line =~ /^BEGIN=(\S+)$/o) + { + $block = $1; + + given ($block) + { + when (['IO_TABLE', 'DEFINE', 'GROUP']) + { + } + + when (/^(PERIPHERY):(\w+)$/o) + { + $block = $1; + $periphery = add_periphery($2); + } + + when ('REGISTER') + { + if (! defined($periphery)) + { + print STDERR "There is no periphery to which can be assigned the following register.\n"; + exit(1); + } + + add_reg_def($periphery); + } + + when (/^(MCU):(\S+)$/o) + { + $block = $1; + @mcu_group = split(',', $2); + } + + default + { + print STDERR "Unknown block: \"$block\"\n"; + exit(1); + } + } # given ($block) + + push(@blocks, $block); + next; + } # if ($line =~ /^BEGIN=(\S+)$/o) + elsif ($line =~ /^END=(\S+)$/o) + { + $block = $1; + + if (scalar(@blocks) == 0 || $blocks[$#blocks] ne $block) + { + print STDERR "The \"$block\" block has no beginning!\n"; + exit(1); + } + + given ($block) + { + when ('PERIPHERY') { $periphery = undef; } + when ('MCU') { @mcu_group = (); } + } + + $block = pop(@blocks); + next; + } # elsif ($line =~ /^END=(\w+)$/o) + + #................................... + + $block = (scalar(@blocks) > 0) ? $blocks[$#blocks] : ''; + + given ($block) + { + when ('REGISTER') + { + if ($line =~ /^([^=]+)=(.*)$/o) + { + # This a key -- value pair. + + if (scalar(@{$periphery}) == 0) + { + print STDERR "No entry of the register table!\n"; + exit(1); + } + + ($key, $val) = ($1, $2); + # Reference of the last member. + my $peri_r = \%{$periphery->[$#{$periphery}]}; + + if ($val =~ /^['"]([^'"]*)['"]$/o) + { + # This a text. + + $peri_r->{$key} = $1; + } + else + { + # This a constant. + + $peri_r->{$key} = eval($val); + } + } + } # when ('REGISTER') + + when ('DEFINE') + { + if ($line !~ /^([^=]+)=(.*)$/o) + { + print STDERR "This is not key -- value pair: $line\n"; + exit(1); + } + + ($key, $val) = ($1, $2); + + if (defined($val) && $val ne '') + { + $definitions{$key} = $val; + } + else + { + # Undefine the $key. + + delete($definitions{$key}); + } + } # when ('DEFINE') + + when ('GROUP') + { + if ($line !~ /^([^=]+)=(.*)$/o) + { + print STDERR "This is not group -- members definition: $line\n"; + exit(1); + } + + @{$io_groups{$1}} = split(',', $2); + } # when ('GROUP') + + when ('MCU') + { + if ($line =~ /^([^=]+)=(.*)$/o) + { + my ($peri, $val) = (lc($1), $2); + + if ($val =~ /^([^=]+)=(.*)$/o) + { + # It is possible that this is a property. + + my $prop = $1; + $val = $2; + + given ($prop) + { + when ('IO_DIR') + { + my @pins = split(',', $val); + + add_io_dir(\@mcu_group, $peri, \@pins); + } + + default + { + print STDERR "This is unknown property definition: $line\n"; + exit(1); + } + } + } + else + { + my @pins = split(',', $val); + + add_io_pins(\@mcu_group, $peri, \@pins); + } + } # if ($line =~ /^([^=]+)=(.*)$/o) + } # when ('MCU') + } # given ($block) + } # foreach (grep(! /^\s*$|^\s*#/o, <DATA>)) + + if (scalar(@blocks) > 0) + { + print STDERR "The \"$blocks[$#blocks]\" block has no ending!\n"; + exit(1); + } + } + +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@ Load all registers, which will find in a header. @@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +sub add_mcu_raw($) + { + my $Name = uc($_[0]); + + Log("add_mcu_raw(): $Name", 9); + + my $mcu_ref = { + NAME => $Name, + ENHANCED => FALSE, + REG_REFS => {}, + REG_ARRAY => [] + }; + + push(@mcu_raw, $mcu_ref); + return $mcu_ref; + } + +#------------------------------------------------------------------------------- + +sub add_register_raw($$$) + { + my ($Mcu_raw, $Name, $Address) = @_; + + $Mcu_raw->{ENHANCED} = TRUE if ($Name eq 'STATUS_SHAD'); + + Log(sprintf("add_register_raw(): $Name, 0x%04X", $Address), 9); + + my $reg = { + NAME => $Name, + ADDRESS => $Address, + BITNAMES => [] + }; + + push(@{$Mcu_raw->{REG_ARRAY}}, $reg); + $Mcu_raw->{REG_REFS}->{$Name} = $reg; + } + +#------------------------------------------------------------------------------- + +sub read_regs_from_header($$) + { + my ($Mcu_ref, $Fname) = @_; + my $path = "$include_path/$Fname"; + my ($fh, $name, $addr, $bit_addr, $bitnames, $width); + + if (! open($fh, '<', $path)) + { + print STDERR "\a\t$0 : Can not open the $path header file!\n"; + exit(1); + } + + Log("read_regs_from_header(): $path", 6); + $bitnames = []; + + foreach (grep(! /^\s*$/o, <$fh>)) + { + chomp; + s/\r$//o; + s/^\s*|\s*$//go; + + my $line = $_; + + Log(">>>>: $line", 7); + + if ($line =~ /^#include\s+"(\S+)"$/o) + { + &read_regs_from_header($Mcu_ref, $1); + } + elsif ($line =~ /^#\s*define\s+(\w+_ADDR)\s+0[xX]([[:xdigit:]]+)$/o) + { + Log("reg_addresses\{$1\} = hex($2)", 8); + $reg_addresses{$1} = hex($2); + } + elsif ($line =~ /^extern\b/o && + $line =~ /\b__sfr\b/o && + (($addr) = ($line =~ /\b__at\s*\(\s*0[xX]([[:xdigit:]]+)\s*\)/o)) && + (($name) = ($line =~ /\b(\w+)\s*;$/o))) + { + # extern __at(0x0000) __sfr INDF; + # extern __sfr __at(0x0003) STATUS; + # + + add_register_raw($Mcu_ref, $name, hex($addr)); + } + elsif ($line =~ /^extern\s+__sfr\s+__at\s*\((\w+_ADDR)\)\s+(\w+);$/o) + { + # extern __sfr __at (EEDATA_ADDR) EEDATA; + # + + if (! defined($reg_addresses{$1})) + { + print STDERR "This register: $2 not have address!\n"; + exit(1); + } + + add_register_raw($Mcu_ref, $2, $reg_addresses{$1}); + } + elsif ($line =~ /\bstruct\b/o) + { + Log("\tbit_addr = 0", 8); + $bit_addr = 0; + } + elsif ($line =~ /^unsigned(?:\s+char|\s+int)?\s*:\s*(\d+)\s*;$/o) + { + # unsigned char :1; + # unsigned int : 4; + # + + $width = int($1); + $bit_addr += $width; + Log("\tbit_addr += $width ($bit_addr)", 8); + } + elsif ($line =~ /^unsigned(?:\s+char|\s+int)?\s*(\w+)\s*:\s*(\d+)\s*;$/o) + { + # unsigned char PCFG2:1; + # unsigned int PSA:1; + # unsigned TRISG :5; + # + + ($name, $width) = ($1, int($2)); + + if ($width == 1) + { + Log("\tpush(bitnames->\[$bit_addr\], $name)", 8); + push(@{$bitnames->[$bit_addr]}, $name); + } + else + { + Log("\t$name", 8); + } + + $bit_addr += $width; + Log("\tbit_addr += $width ($bit_addr)", 8); + } + elsif ($line =~ /^\}\s*(?:__)?(\w+)bits_t\s*;$/o || $line =~ /^\}\s*(?:__)?(\w+)_t\s*;$/o) + { + my $reg_ref = $Mcu_ref->{REG_REFS}->{$1}; + + if (! defined($reg_ref)) + { + print STDERR "This register: $1 not have data structure!\n"; + exit(1); + } + + Log("\treg_ref : $reg_ref)", 8); + $reg_ref->{BITNAMES} = $bitnames; + $bitnames = []; + } + } # foreach (grep(! /^\s*$/o, <$fh>)) + + close($fh); + + if ($Mcu_ref->{ENHANCED}) + { + push(@enhanced, lc($Mcu_ref->{NAME})); + } + else + { + push(@regular, lc($Mcu_ref->{NAME})); + } + + my $array = \@{$Mcu_ref->{REG_ARRAY}}; + + return if (scalar(@{$array}) == 0); + + # Within the array sorts by name the registers. + + @{$array} = sort {smartSort($a->{NAME}, $b->{NAME})} @{$array}; + } + +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@ @@@@@@@@@@@ +#@@@@@@@@@ To periphery fitting in a manner, filters the registers. @@@@@@@@@@ +#@@@@@@@@@@ @@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +sub add_mcu($$) + { + my ($Peri_regs, $Mcu_raw) = @_; + + my $mcu = { + NAME => $Mcu_raw->{NAME}, + ENHANCED => $Mcu_raw->{ENHANCED}, + REG_REFS => {}, + IN_GROUP => FALSE, + REG_GROUPS => [] + }; + + Log("add_mcu($mcu->{NAME})", 8); + + # Copies the master periphery table. + + foreach (@{$Peri_regs}) + { + my $group = { + VALID_REGS => $_->{VALID_REGS}, + VALID_BITS => $_->{VALID_BITS}, + PRINT_MODE => $_->{PRINT_MODE}, + REG_ARRAY => [] + }; + + push(@{$mcu->{REG_GROUPS}}, $group); + } + + push(@mcu_filtered, $mcu); + return $mcu; + } + +#------------------------------------------------------------------------------- + +sub add_register($$) + { + my ($Mcu, $Reg_raw) = @_; + my $name = $Reg_raw->{NAME}; + + Log("add_register($Mcu->{NAME}, $name)", 8); + + foreach (@{$Mcu->{REG_GROUPS}}) + { + if ($name =~ /^$_->{VALID_REGS}$/) + { + # This register fits into this group. + + if ($name =~ /^([\D_]+)1$/ && defined($Mcu->{REG_REFS}->{$1})) + { + # This register already exists. E.g.: RCREG1 --> RCREG + return undef; + } + + my $reg = { + NAME => $name, + ADDRESS => $Reg_raw->{ADDRESS}, + GROUP => $_, + TOUCHED => FALSE, + EMPTY => FALSE, + BITNAMES => [] + }; + + push(@{$_->{REG_ARRAY}}, $reg); + $Mcu->{REG_REFS}->{$name} = $reg; + return $reg; + } + } + + return undef; + } + +#------------------------------------------------------------------------------- + + # Cut down frippery from the bit names. + +sub cut_frippery_from_bitnames($$) + { + my ($Regname, $Bits) = @_; + + return if (! defined($Bits) || scalar(@{$Bits}) <= 0); + + my $changed = 0; + my $new_bits = []; + + foreach (@{$Bits}) + { + $changed += ($_ =~ s/^${Regname}_|_${Regname}$//); + $changed += ($_ =~ s/^(\d+)$/bit_$1/o); + push(@{$new_bits}, $_); + } + + $Bits = $new_bits if ($changed); + } + +#------------------------------------------------------------------------------- + +sub tris_ansel_filter($$) + { + my ($Peri_pins, $Pin_name) = @_; + + return TRUE if (! defined($Peri_pins) || + ($Pin_name !~ /^TRIS[A-O]\d+$/io && + $Pin_name !~ /^ANS[A-O]\d+$/io)); + + foreach (keys(%{$Peri_pins})) + { + foreach (@{$Peri_pins->{$_}}) + { + if ($_ =~ /^R([A-O]\d+)$/io) + { + # E.g.: "RC7" --> "TRISC7"; "RC7" --> "ANSC7" + my $tail = uc($1); + my $trisx = "TRIS$tail"; + my $ansx = "ANS$tail"; + + return TRUE if ($Pin_name eq $trisx || $Pin_name eq $ansx); + } + } + } + + return FALSE; + } + +#------------------------------------------------------------------------------- + +sub filter_regs_from_raw($) + { + my $Periphery = $_[0]; + my ($peri_name, $peri_regs) = ($Periphery->{NAME}, $Periphery->{REGS}); + + foreach (@mcu_raw) + { + my $mcu = lc($_->{NAME}); + my $io_ref = \%{$io_table_by_mcu{$mcu}}; + my $peri_pins = (defined($io_ref)) ? $io_ref->{$peri_name} : undef; + + # The MCU not have this periphery. + next if (! defined($peri_pins)); + + my $mcu_ref = add_mcu($peri_regs, $_); + + foreach my $reg_raw (@{$_->{REG_ARRAY}}) + { + my $reg_dst = add_register($mcu_ref, $reg_raw); + + next if (! defined($reg_dst)); + + my $bits_src = $reg_raw->{BITNAMES}; + my $bits_dst = $reg_dst->{BITNAMES}; + my $valid_bits = $reg_dst->{GROUP}->{VALID_BITS}; + my $empty = TRUE; + + if (defined($valid_bits) && $valid_bits ne '') + { + # Filtering follows. + + for (my $i = 0; $i < 8; ++$i) + { + my $new_bits = []; + + cut_frippery_from_bitnames($reg_dst->{NAME}, \@{$bits_src->[$i]}); + foreach (@{$bits_src->[$i]}) + { + # Only those names notes, which passed through the filter. + + push(@{$new_bits}, $_) if (defined($_) && $_ =~ /^$valid_bits$/ && + tris_ansel_filter($peri_pins, $_)); + } + + if (scalar(@{$new_bits}) > 0) + { + $bits_dst->[$i] = $new_bits; + $empty = FALSE; + } + else + { + $bits_dst->[$i] = undef; + } + } + } + else + { + # No filtering. + + for (my $i = 0; $i < 8; ++$i) + { + cut_frippery_from_bitnames($reg_dst->{NAME}, \@{$bits_src->[$i]}); + $empty = FALSE if (defined($bits_src->[$i])); + + $bits_dst->[$i] = [ @{$bits_src->[$i]} ]; + } + } + + $reg_dst->{EMPTY} = $empty; + } + } # foreach (@mcu_raw) + } + +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@ @@@@@@@@ +#@@@@@@@ Collects same group them MCU which, have the same peripheral. @@@@@@@ +#@@@@@@@@ @@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +sub load_touched_flags($$) + { + my $Level = $_[1]; + + foreach (@{$_[0]->{REG_GROUPS}}) + { + foreach (@{$_->{REG_ARRAY}}) + { + $_->{TOUCHED} = $Level; + } + } + } + +#------------------------------------------------------------------------------- + +sub find_not_touched_reg($) + { + foreach (@{$_[0]->{REG_GROUPS}}) + { + foreach (@{$_->{REG_ARRAY}}) + { + next if ($_->{EMPTY}); # It does not take into account the empty register. + + return TRUE if (! $_->{TOUCHED}); # This register left out from a previous comparison. + } + } + + return FALSE; + } + +#------------------------------------------------------------------------------- + +sub find_register($$) + { + my $Prime_reg = $_[1]; + my $cand_reg = $_[0]->{REG_REFS}->{$Prime_reg->{NAME}}; + + return $cand_reg if (defined($cand_reg) && $cand_reg->{ADDRESS} == $Prime_reg->{ADDRESS}); + + return undef; + } + +#------------------------------------------------------------------------------- + +sub find_equivalent_bit($$) + { + my ($Bits1, $Bits2) = @_; + my $d = (defined($Bits1) && scalar(@{$Bits1}) > 0) + (defined($Bits2) && scalar(@{$Bits2}) > 0); + + return TRUE if ($d == 0); + + if ($d != 2) + { + Log("find_equivalent_bit(): Only one bits defined.", 6); + return FALSE; + } + + foreach (@{$Bits1}) + { + return TRUE if (/^$_$/ ~~ @{$Bits2}); + + Log("find_equivalent_bit(): The $_ bit not defined.", 7); + } + + return FALSE; + } + +#------------------------------------------------------------------------------- + +sub find_equivalent_register($$$) + { + my ($Candidate, $Prime_reg, $Print_mode) = @_; + my ($cand_reg, $prime_bits, $cand_bits); + + $cand_reg = find_register($Candidate, $Prime_reg); + + if (! defined($cand_reg)) + { + Log("find_equivalent_register(): Not exists candidate reg: $Prime_reg->{NAME} in $Candidate->{NAME} MCU", 5); + return FALSE; + } + + $cand_reg->{TOUCHED} = TRUE; + + # Not performs comparison, if the bits not must be displayed. + return TRUE if ($Print_mode == P_SHOW_ONLY_NAME); + + $prime_bits = \@{$Prime_reg->{BITNAMES}}; + $cand_bits = \@{$cand_reg->{BITNAMES}}; + + for (my $i = 0; $i < 8; ++$i) + { + if (! find_equivalent_bit(\@{$cand_bits->[$i]}, \@{$prime_bits->[$i]})) + { + Log("find_equivalent_register(): Not finds equivalent bit: $cand_reg->{NAME} != $Prime_reg->{NAME}", 5); + return FALSE; + } + } + + return TRUE; + } + +#------------------------------------------------------------------------------- + +sub find_equivalent_mcu($$) + { + my ($Prime, $Candidate) = @_; + + return FALSE if ($Prime->{ENHANCED} != $Candidate->{ENHANCED}); + + load_touched_flags($Prime, FALSE); + load_touched_flags($Candidate, FALSE); + + foreach (@{$Prime->{REG_GROUPS}}) + { + my $pmode = $_->{PRINT_MODE}; + + foreach (@{$_->{REG_ARRAY}}) + { + $_->{TOUCHED} = TRUE; + next if ($_->{EMPTY}); + + return FALSE if (! find_equivalent_register($Candidate, $_, $pmode)); + } + } + + if (find_not_touched_reg($Prime)) + { + Log("find_equivalent_mcu(): Finds not touched register: $Prime->{NAME}", 5); + return FALSE; + } + + if (find_not_touched_reg($Candidate)) + { + Log("find_equivalent_mcu(): Finds not touched register: $Candidate->{NAME}", 5); + return FALSE; + } + + return TRUE; + } + +#------------------------------------------------------------------------------- + +sub cmp_io_dirs($$$) + { + my ($Prime, $Candidate, $Periphery) = @_; + my $prime_io = $io_dir_table_by_mcu{lc($Prime->{NAME})}; + my $cand_io = $io_dir_table_by_mcu{lc($Candidate->{NAME})}; + my $d = (defined($prime_io) && scalar(keys %{$prime_io}) > 0) + (defined($cand_io) && scalar(keys %{$cand_io}) > 0); + + return TRUE if ($d == 0); + return FALSE if ($d != 2); + + my ($pr, $ca) = ($prime_io->{$Periphery}, $cand_io->{$Periphery}); + + $d = (defined($pr) && scalar(keys %{$pr}) > 0) + (defined($ca) && scalar(keys %{$ca}) > 0); + + return TRUE if ($d == 0); + return FALSE if ($d != 2); + + foreach (keys(%{$pr})) + { + $d = $ca->{$_}; + + return FALSE if (! defined($d) || $d != $pr->{$_}); + } + + return TRUE; + } + +#------------------------------------------------------------------------------- + +sub make_mcu_groups($) + { + my $Periphery = $_[0]; + my $index = 0; + + foreach (@mcu_filtered) + { + next if ($_->{IN_GROUP}); + + my $group = \@{$mcu_groups[$index]}; + my $prime = $_; + + # The prime - reference - member of group; + push(@{$group}, $_); + $_->{IN_GROUP} = TRUE; + + foreach (@mcu_filtered) + { + next if ($_->{IN_GROUP} || $prime == $_); + + if (find_equivalent_mcu($prime, $_) && cmp_io_dirs($prime, $_, $Periphery)) + { + Log("make_mcu_groups(): $prime->{NAME} == $_->{NAME}\n", 5); + push(@{$group}, $_); + $_->{IN_GROUP} = TRUE; + } + } + + @{$group} = sort {smartSort($a->{NAME}, $b->{NAME})} @{$group}; + ++$index; + } + } + +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@@ Prints the register tables. @@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +=back + Sometimes a bit has more name. This procedure selects these from among + the shortest. +=cut + +sub find_shortest_name($) + { + my $min = ULONG_MAX; + my $str = ''; + + foreach (@{$_[0]}) + { + my $l = length; + + if ($l < $min) + { + $min = $l; + $str = $_; + } + } + + return $str; + } + +#------------------------------------------------------------------------------- + +sub print_registers($$$) + { + my ($Reg_array, $Print_mode, $No_ADC) = @_; + my ($i, $bits); + my $show_closing_border = FALSE; + + foreach (@{$Reg_array}) + { + next if ($No_ADC && exist_in_list(\@some_ADC_registers, $_->{NAME})); + + # Sole bit not have name and the empty register is not must show. + next if ($_->{EMPTY} && $Print_mode == P_NO_SHOW_IF_EMPTY); + + if ($Print_mode == P_SHOW_ONLY_NAME) + { + Outfl("%-10s (%03Xh)", $_->{NAME}, $_->{ADDRESS}); + $initial_border = FALSE; + next; + } + + if (! $initial_border) + { + Outl($table_border); + $initial_border = TRUE; + } + + Outf("%-10s (%03Xh) |", $_->{NAME}, $_->{ADDRESS}); + + $bits = \@{$_->{BITNAMES}}; + for ($i = 7; $i >= 0; --$i) + { + if (defined($bits->[$i]) && $Print_mode != P_NO_SHOW_BITS) + { + Outf("%-9s|", find_shortest_name(\@{$bits->[$i]})); + } + else + { + Out(' |'); + } + } + + Outl(); + $show_closing_border = TRUE; + } # foreach (@{$_[0]}) + + Outl($table_border) if ($show_closing_border); + } + +#------------------------------------------------------------------------------- + + # + # Collects into a list the inputs of ADC, which are uses another + # periphery also. + # + +sub filter_off_adc_inputs($$) + { + my ($Peri_pins, $Adc) = @_; + my @adc_pins = (); + + if (defined($Adc)) + { + foreach my $adc_pin_name (keys(%{$Adc})) + { + my $adc_pin_io = $Adc->{$adc_pin_name}; + + foreach my $peri_pin_name (keys(%{$Peri_pins})) + { + foreach (@{$Peri_pins->{$peri_pin_name}}) + { + if (! (/^$adc_pin_name$/ ~~ @adc_pins) && /^$_$/ ~~ @{$adc_pin_io}) + { + push(@adc_pins, $adc_pin_name) + } + } + } + } + } + + return \@adc_pins; + } + +#------------------------------------------------------------------------------- + +sub print_mcu($$) + { + my ($Mcu, $Peri_name) = @_; + my $name = lc($Mcu->{NAME}); + my $io_ref = \%{$io_table_by_mcu{$name}}; + my $io_dir_ref = \%{$io_dir_table_by_mcu{$name}}; + my $peri_pins = (defined($io_ref)) ? $io_ref->{$Peri_name} : undef; + my $peri_dirs = (defined($io_dir_ref)) ? $io_dir_ref->{$Peri_name} : undef; + my ($adc, $adc_pins, $io, $pin_name, $drop_adc_pins); + my $suppl_info = ''; + + $drop_adc_pins = FALSE; + + Outl("This is an enhanced 14 bit MCU.") if ($Mcu->{ENHANCED}); + + if (defined($peri_pins)) + { + if ($Peri_name ne 'adc') + { + $adc = \%{$io_ref->{'adc'}}; + $adc_pins = filter_off_adc_inputs($peri_pins, $adc); + + if (scalar(@{$adc_pins}) > 0) + { + # Supplementary information: Displays inputs of the ADC periphery. + + $suppl_info .= "\n"; + + foreach $pin_name (sort {smartSort($a, $b)} @{$adc_pins}) + { + $suppl_info .= "\t$pin_name:"; + + foreach (@{$adc->{$pin_name}}) + { + $suppl_info .= " $_"; + } + + $suppl_info .= "\n"; + } + } + else + { + $drop_adc_pins = TRUE; + } + } # if ($Peri_name ne 'adc') + + $suppl_info .= "\n"; + + foreach $pin_name (sort {smartSort($a, $b)} keys(%{$peri_pins})) + { + $suppl_info .= "\t$pin_name:"; + + foreach (@{$peri_pins->{$pin_name}}) + { + $suppl_info .= " $_"; + } + + $suppl_info .= "\n"; + } + } # if (defined($peri_pins)) + else + { + print STDERR "print_mcu(): This MCU $name not have $Peri_name pin!\n"; + } + + if (defined($peri_dirs)) + { + $suppl_info .= "\n I/O directions after initialization:\n\n"; + + foreach (sort {smartSort($a, $b)} keys %{$peri_dirs}) + { + $io = ($peri_dirs->{$_} == 0) ? '0 (output)' : '1 (input)'; + $suppl_info .= "\t$_: $io\n"; + } + } + + $initial_border = FALSE; + + foreach (@{$Mcu->{REG_GROUPS}}) + { + next if (scalar(@{$_->{REG_ARRAY}}) == 0); + + print_registers(\@{$_->{REG_ARRAY}}, $_->{PRINT_MODE}, $drop_adc_pins); + } + + Out($suppl_info); + } + +#------------------------------------------------------------------------------- + +sub print_all_data($$) + { + my ($Periphery, $Index) = @_; + my $peri_name = $Periphery->{NAME}; + my $lock = '__' . uc($peri_name) . '__H__'; + my ($sidx, $group_index, $border); + my ($family, $tech, $group_name, $len); + + Outl("\n#ifndef $lock\n#define $lock\n\n#include \"pic16fam.h\""); + + $peri_groups .= "\n SECTION=" . uc($peri_name) . "\n\n"; + + if ($make_groups) + { + $group_index = 1; + $border = '#' x 45; + + make_mcu_groups($peri_name); + + foreach (@mcu_groups) + { + next if (scalar(@{$_}) == 0); + + Outl("\n//$border ${group_index}th group $border"); + + ($family, $tech, $group_name) = ($_->[0]->{NAME} =~ /^(1[026])(c|cr|f|hv|lf)(\w+)$/io); + + $group_name =~ s/\D//go; + $len = length($group_name); + + if ($len < 3) + { + $group_name = "00$group_name"; + } + elsif ($len < 4) + { + $group_name = "0$group_name"; + } + + given ($tech) + { + # C CR + when (/c|cr/io) { $sidx = '0'; } + + # F HV LF + default { $sidx = '1'; } + } + + $peri_groups .= "$family$group_name$Index$sidx:" . join(',', map { lc($_->{NAME}); } @{$_}) . "\n"; + + if ($only_prime) + { + Outl("\n/*"); + + # Prints the name of the group members. + + foreach (@{$_}) + { + Outl("PIC$_->{NAME}"); + } + + # Only contents of the first it shows, because content of the others same. + + print_mcu($_->[0], $peri_name); + Outl('*/'); + } + else + { + # Displays full contents of each member of the group. + + foreach (@{$_}) + { + Outl("\n\n/*\nPIC$_->{NAME}"); + print_mcu($_, $peri_name); + Outl('*/'); + } + } + + ++$group_index; + } + } + else + { + # Displays full contents of each MCU. + + foreach (@mcu_filtered) + { + Outl("\n\n/*\nPIC$_->{NAME}"); + print_mcu($_, $peri_name); + Outl('*/'); + } + } + + Outl("\n#endif // $lock"); + } + +#------------------------------------------------------------------------------- + +sub print_listing($$$) + { + my ($Out, $Device_per_line, $List_ref) = @_; + my ($i, $len); + + $len = scalar(@{$List_ref}); + + return if ($len <= 0); + + $i = 0; + while (1) + { + print $Out $List_ref->[$i]; + ++$i; + + if ($i >= $len) + { + print $Out "\n"; + last; + } + + print $Out ((($i % $Device_per_line) == 0) ? "\n" : ','); + } + } + +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@@@@@@@ The main program. @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +load_periphery_data(); + +$include_path = ''; +$make_groups = FALSE; +$only_prime = FALSE; + +for (my $i = 0; $i < @ARGV; ) + { + my $opt = $ARGV[$i++]; + + given ($opt) + { + when (/^-(I|-include)$/o) + { + die "This option \"$opt\" requires a parameter." if ($i > $#ARGV); + + $include_path = $ARGV[$i++]; + } + + when (/^-(g|-make-groups)$/o) + { + $make_groups = TRUE; + } + + when (/^-(p|-only-prime)$/o) + { + $only_prime = TRUE; + } + + when (/^-(gp|pg)$/o) + { + $make_groups = TRUE; + $only_prime = TRUE; + } + + when (/^-(v|-verbose)$/o) + { + die "This option \"$opt\" requires a parameter.\n" if ($i > $#ARGV); + + $verbose = int($ARGV[$i++]); + $verbose = 0 if (! defined($verbose) || $verbose < 0); + $verbose = 10 if ($verbose > 10); + } + + when (/^-(h|-help)$/o) + { + print <<EOT +Usage: $0 [options] + + Options are: + + -I <path> or --include <path> + + The program on this path looks for the headers. + If this is not specified, then looking for a installed + sdcc copy in the system. + + -g or --make-groups + + This command creates groups of MCUs. + + -p or --only-prime + + Prints only the prime member of an MCU group. + + -v <level> or --verbose <level> + + It provides information on from the own operation. + Possible value of the level between 0 and 10. (default: 0) + + -h or --help + + This text. +EOT +; + exit(0); + } + } # given ($opt) + } + +if ($include_path eq '') + { + foreach (@default_paths) + { + if (-d $_) + { + $include_path = "$_/$default_port"; + last; + } + } + + die "Can not find the directory of sdcc headers!" if ($include_path eq ''); + } + +opendir(DIR, $include_path) || die "Can not open. -> \"$include_path\""; + +print "Include path: \"$include_path\"\n"; + +my @filelist = grep(-f "$include_path/$_" && /^$header_name_filter$/, readdir(DIR)); +closedir(DIR); + +@regular = (); +@enhanced = (); +@mcu_raw = (); +foreach (sort {smartSort($a, $b)} @filelist) + { + my $name = $_; + + print STDERR "Reading the registers from the $_ header ..."; + + $name =~ s/^pic//io; + $name =~ s/\.\S+$//o; + read_regs_from_header(add_mcu_raw($name), $_); + print STDERR " done.\n"; + } + +my $p_idx = 0; +foreach (@periphery_table) + { + my $out_name = "$_->{NAME}.h$out_tail"; + + open($out_handler, '>', $out_name) || die "Can not create the $out_name output!"; + + print STDERR "Filtering of registers the aspects of $_->{NAME} according to ..."; + @mcu_filtered = (); + @mcu_groups = (); + filter_regs_from_raw($_); + print STDERR " done.\n"; + + print STDERR "Creating the $out_name ..."; + print_all_data($_, $p_idx); + print STDERR " done.\n"; + + close($out_handler); + ++$p_idx; + } + +open(GR, '>', $peri_group) || die "Can not create the $peri_group output!"; + +if (scalar(@regular) > 0) + { + print GR "\n SECTION=REGULAR\n\n"; + print_listing(*GR, 10, \@regular); + } + +if (scalar(@enhanced) > 0) + { + print GR "\n SECTION=ENHANCED\n\n"; + print_listing(*GR, 10, \@enhanced); + } + +print GR $peri_groups; +close(GR); + +__END__ +################################################################################ +# +# The following rules determine to which registers belong to an peripheral. +# The description of a periphery is bounded by the BEGIN=TABLE_XXX flags. +# The description of a register begin after the BEGIN=REGISTER flag. +# +# BEGIN=PERIPHERY:ADC +# The "ADC" effect of: An file will be created under the name "adc.tables". +# +# VALID_REGS -- This a regular expression. Specifies which one a register +# applies to this entries. +# +# VALID_BITS -- This a regular expression. Specifies which bits are interesting, +# are important. If an empty string is in there will be no filtering. +# +# PRINT_MODE -- This a constant. The following values can be: +# +# P_NO_SHOW_BITS -- Does not shows the bits. +# +# P_NO_SHOW_IF_EMPTY -- Not shows the register if it is empty. +# (This it could be because there are no bits +# or because the filter thrown out them.) +# +# P_ALWAYS_SHOW -- All conditions shows the register. +# +# P_SHOW_ONLY_NAME -- Only shows the register name and address. +# + +################################################################################ +# +# The ADC module related registers. +# (There is so, which only indirectly connected to the module.) +# + +BEGIN=PERIPHERY:ADC # ADC --> adc.h.gen + + BEGIN=REGISTER + VALID_REGS="AD\d*CON\d*|ADCOMCON" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="AD\d*RES\d*[HL]?" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ANSEL[A-Z]*" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="(FVR|REF)CON" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="DAC\d*" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="DAC(ON\d*|CON\d+)" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="INTCON\d?" + VALID_BITS="(G|PE|AD)IE" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PIE\d+" + VALID_BITS="ADIE" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PIR\d+" + VALID_BITS="ADIF" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ANSEL[A-Z]*" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="TRIS([A-Z]|IO)" + VALID_BITS="TRIS([A-Z]|IO)?\d" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + +END=PERIPHERY + +################################################################################ +# +# The CCP module related registers. +# (There is so, which only indirectly connected to the module.) +# + +BEGIN=PERIPHERY:CCP # CCP --> ccp.h.gen + + BEGIN=REGISTER + VALID_REGS="APFCON\d*" + VALID_BITS="(CCP(SEL\d|\dSEL)|P\d[A-D]SEL)" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PPSLOCK" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="CCP\d+PPS" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="R[A-Z]\dPPS" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="CCP(CON\d*|\d+CON)" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="CCP(AS\d*|\d+AS)" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="CCPR([HL]\d*|\d+[HL])" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="CCPTMRS\d*" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PSTR(CON\d*|\d+CON)" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PWM(CON\d*|\d+CON)" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="(T[2468]CON|T10CON)" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="(TMR[2468]|TMR10)" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="(PR[2468]|PR10)" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="INTCON\d?" + VALID_BITS="(G|PE)IE" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PIE\d+" + VALID_BITS="CCP\d+IE" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PIR\d+" + VALID_BITS="CCP\d+IF" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ANSEL[A-Z]*" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ADCON\d+" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="TRIS([A-Z]|IO)" + VALID_BITS="TRIS([A-Z]|IO)\d" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + +END=PERIPHERY + +################################################################################ +# +# The PWM(CCP) module related registers. +# (There is so, which only indirectly connected to the module.) +# + +BEGIN=PERIPHERY:PWM # PWM --> pwm.h.gen + + BEGIN=REGISTER + VALID_REGS="APFCON\d*" + VALID_BITS="(CCP(SEL\d|\dSEL)|P\d[A-D]SEL)" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PPSLOCK" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="CCP\d+PPS" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="R[A-Z]\dPPS" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="CCP(CON\d*|\d+CON)" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="CCP(AS\d*|\d+AS)" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="CCPR([HL]\d*|\d+[HL])" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="CCPTMRS\d*" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PSTR(CON\d*|\d+CON)" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PWM(CON\d*|\d+CON)" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PWM(DC[HL]\d*|\d+DC[HL])" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="(T[2468]CON|T10CON)" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="(TMR[2468]|TMR10)" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="(PR[2468]|PR10)" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="INTCON\d?" + VALID_BITS="(G|PE)IE" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PIE\d+" + VALID_BITS="((CCP\d+|TMR[2468])IE|TMR10IE)" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PIR\d+" + VALID_BITS="((CCP\d+|TMR[2468])IF|TMR10IF)" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ANSEL[A-Z]*" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ADCON\d+" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="TRIS([A-Z]|IO)" + VALID_BITS="TRIS([A-Z]|IO)\d" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + +END=PERIPHERY + +################################################################################ +# +# The I2C(SSP) module related registers. +# (There is so, which only indirectly connected to the module.) +# + +BEGIN=PERIPHERY:I2C # I2C --> i2c.h.gen + + BEGIN=REGISTER + VALID_REGS="APFCON\d*" + VALID_BITS="S(DI|DO|CK|S)\d*SEL" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PPSLOCK" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="SSP(CLK|DAT)PPS" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="R[A-Z]\dPPS" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="SSP\d*CON\d*" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="SSP\d*ADD\d*" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="SSP\d*BUF\d*" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="SSP\d*MSK\d*" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="SSP\d*STAT\d*" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="INTCON\d?" + VALID_BITS="(G|PE)IE" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PIE\d+" + VALID_BITS="(BCL|SSP)\d*IE" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PIR\d+" + VALID_BITS="(BCL|SSP)\d*IF" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ANSEL[A-Z]*" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ADCON\d+" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="TRIS([A-Z]|IO)" + VALID_BITS="TRIS([A-Z]|IO)\d" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + +END=PERIPHERY + +################################################################################ +# +# The SPI(SSP) module related registers. +# (There is so, which only indirectly connected to the module.) +# + +BEGIN=PERIPHERY:SPI # SPI --> spi.h.gen + + BEGIN=REGISTER + VALID_REGS="APFCON\d*" + VALID_BITS="S(DI|DO|CK|S)\d*SEL" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PPSLOCK" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="SSP\w+PPS" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="R[A-Z]\dPPS" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="SSP\d*CON\d*" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="SSP\d*ADD\d*" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="SSP\d*BUF\d*" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="SSP\d*MSK\d*" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="SSP\d*STAT\d*" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="INTCON\d?" + VALID_BITS="(G|PE)IE" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PIE\d+" + VALID_BITS="(BCL|SSP)\d*IE" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PIR\d+" + VALID_BITS="(BCL|SSP)\d*IF" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ANSEL[A-Z]*" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ADCON\d+" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="TRIS([A-Z]|IO)" + VALID_BITS="TRIS([A-Z]|IO)\d" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + +END=PERIPHERY + +################################################################################ +# +# The USART module related registers. +# (There is so, which only indirectly connected to the module.) +# + +BEGIN=PERIPHERY:USART # USART --> usart.h.gen + + BEGIN=REGISTER + VALID_REGS="APFCON\d*" + VALID_BITS="(RX(DT)?|TX(CK)?)SEL" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PPSLOCK" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="R[A-Z]\dPPS" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="RC(STA\d*|\d+STA)" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="TX(STA\d*|\d+STA)" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="BAUD(C(ON|TL)\d*|\d+C(ON|TL))" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="SP(BRG[HL]?\d?|\d+BRG[HL]?)" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="RC(REG\d*|\d+REG)" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="TX(REG\d*|\d+REG)" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="INTCON\d?" + VALID_BITS="(G|PE)IE" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PIE\d+" + VALID_BITS="(RC|TX)\d*IE" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PIR\d+" + VALID_BITS="(RC|TX)\d*IF" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ANSEL[A-Z]*" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ADCON\d+" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="TRIS([A-Z]|IO)" + VALID_BITS="TRIS([A-Z]|IO)\d" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + +END=PERIPHERY + +################################################################################ +# +# This table describes that which onto port pins connected a peripheral. +# + +BEGIN=IO_TABLE + + BEGIN=MCU:10f320,10f322 + ADC=AN0:RA0,AN1:RA1,AN2:RA2 + PWM=PWM1:RA0,PWM2:RA1 + END=MCU + + BEGIN=MCU:12f615,12f617,12f683 + ADC=AN0:GP0,AN1:GP1,AN2:GP2,AN3:GP4 + CCP=CCP:GP2 + PWM=PWM:GP2 + END=MCU + + BEGIN=MCU:12f675 + ADC=AN0:GP0,AN1:GP1,AN2:GP2,AN3:GP4 + END=MCU + + BEGIN=MCU:12f752 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA4 + CCP=CCP:RA2 + PWM=PWM:RA2 + END=MCU + + BEGIN=MCU:12f1501 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA4 + PWM=PWM1:RA2,PWM2:RA0,PWM3:RA4,PWM4:RA5 + END=MCU + + BEGIN=MCU:12f1571 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA4 + PWM=PWM1:RA1/RA5,PWM2:RA0/RA4,PWM3:RA2 + END=MCU + + BEGIN=MCU:12f1572 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA4 + PWM=PWM1:RA1/RA5,PWM2:RA0/RA4,PWM3:RA2 + USART=RX:RA1/RA5,TX:RA0/RA4 + USART=IO_DIR=RX:1,TX:0 + END=MCU + + BEGIN=MCU:12f1612 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA4 + CCP=CCP1:RA2/RA5,CCP2:RA0 + PWM=PWM1:RA2/RA5,PWM2:RA0 + END=MCU + + BEGIN=MCU:12f1822 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA4 + CCP=CCP:RA2/RA5 + PWM=PWM:RA2/RA5 + I2C=SDA:RA2,SCL:RA1 + SPI=SDI:RA2,SDO:RA0,SCK:RA1,SS:RA0/RA3 + USART=RX:RA1/RA5,TX:RA0/RA4 + USART=IO_DIR=RX:1,TX:0 + END=MCU + + BEGIN=MCU:12lf1552 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA4,AN4:RA5 + I2C=SDA:RA2/RA3,SCL:RA1 + SPI=SDI:RA2/RA3,SDO:RA0/RA4,SCK:RA1,SS:RA0/RA3 + END=MCU + + BEGIN=MCU:16c62 + CCP=CCP:RC2 + PWM=PWM:RC2 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + END=MCU + + BEGIN=MCU:16c63a,16c65b + CCP=CCP1:RC2,CCP2:RC1 + PWM=PWM1:RC2,PWM2:RC1 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16c71,16c710,16c711,16c715 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3 + END=MCU + + BEGIN=MCU:16c72,16f72 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + CCP=CCP:RC2 + PWM=PWM:RC2 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + END=MCU + + BEGIN=MCU:16c73b,16c74b,16f73,16f76 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + CCP=CCP1:RC2,CCP2:RC1 + PWM=PWM1:RC2,PWM2:RC1 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16c433 + ADC=AN0:GP0,AN1:GP1,AN2:GP2,AN3:GP4 + END=MCU + + BEGIN=MCU:16c717,16c770,16c771 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RB0,AN5:RB1 + CCP=CCP:RB3 + PWM=PWM:RB3 + I2C=SDA:RB4,SCL:RB2 + SPI=SDI:RB4,SDO:RB5,SCK:RB2,SS:RB1 + END=MCU + + BEGIN=MCU:16c745,16c765 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + CCP=CCP1:RC2,CCP2:RC1 + PWM=PWM1:RC2,PWM2:RC1 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16c773 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN8:RB3,AN9:RB3 + CCP=CCP1:RC2,CCP2:RC1 + PWM=PWM1:RC2,PWM2:RC1 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RB1 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16c774 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2,AN8:RB3,AN9:RB3 + CCP=CCP1:RC2,CCP2:RC1 + PWM=PWM1:RC2,PWM2:RC1 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RB1 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16c781,16c782 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RB0,AN5:RB1,AN6:RB2,AN7:RB3 + END=MCU + + BEGIN=MCU:16c925,16c926 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + CCP=CCP:RC2 + PWM=PWM:RC2 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + END=MCU + + BEGIN=MCU:16f74,16f77 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2 + CCP=CCP1:RC2,CCP2:RC1 + PWM=PWM1:RC2,PWM2:RC1 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f87 + CCP=CCP:RB0/RB3 + PWM=PWM:RB0/RB3 + I2C=SDA:RB1,SCL:RB4 + SPI=SDI:RB1,SDO:RB2,SCK:RB4,SS:RB5 + USART=RX:RB2,TX:RB5 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f88 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA4,AN5:RB6,AN6:RB7 + CCP=CCP:RB0/RB3 + PWM=PWM:RB0/RB3 + I2C=SDA:RB1,SCL:RB4 + SPI=SDI:RB1,SDO:RB2,SCK:RB4,SS:RB5 + USART=RX:RB2,TX:RB5 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f616,16hv616,16f684 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA4,AN4:RC0,AN5:RC1,AN6:RC2,AN7:RC3 + CCP=CCP:RC5 + PWM=PWM:RC5 + END=MCU + + BEGIN=MCU:16f627,16f627a,16f628,16f628a,16f648a + CCP=CCP:RB3 + PWM=PWM:RB3 + USART=RX:RB1,TX:RB2 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f676 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA4,AN4:RC0,AN5:RC1,AN6:RC2,AN7:RC3 + END=MCU + + BEGIN=MCU:16f677 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA4,AN4:RC0,AN5:RC1,AN6:RC2,AN7:RC3,AN8:RC6,AN9:RC7,AN10:RB4,AN11:RB5 + I2C=SDA:RB4,SCL:RB6 + SPI=SDI:RB4,SDO:RC7,SCK:RB6,SS:RC6 + END=MCU + + BEGIN=MCU:16f685 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA4,AN4:RC0,AN5:RC1,AN6:RC2,AN7:RC3,AN8:RC6,AN9:RC7,AN10:RB4,AN11:RB5 + CCP=CCP:RC5 + PWM=PWM:RC5 + END=MCU + + BEGIN=MCU:16f688 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA4,AN4:RC0,AN5:RC1,AN6:RC2,AN7:RC3 + USART=RX:RC5,TX:RC4 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f687,16f689,16f690 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA4,AN4:RC0,AN5:RC1,AN6:RC2,AN7:RC3,AN8:RC6,AN9:RC7,AN10:RB4,AN11:RB5 + CCP=CCP:RC5 + PWM=PWM:RC5 + I2C=SDA:RB4,SCL:RB6 + SPI=SDI:RB4,SDO:RC7,SCK:RB6,SS:RC6 + USART=RX:RB5,TX:RB7 + USART=IO_DIR=RX:1,TX:0 + END=MCU + + BEGIN=MCU:16f707 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2,AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0,AN13:RB5 + CCP=CCP1:RC2,CCP2:RC1/RB3 + PWM=PWM1:RC2,PWM2:RC1/RB3 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA0/RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f716 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3 + CCP=CCP:RB3 + PWM=PWM:RB3 + END=MCU + + BEGIN=MCU:16f720,16f721 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA4,AN4:RC0,AN5:RC1,AN6:RC2,AN7:RC3,AN8:RC6,AN9:RC7,AN10:RB4,AN11:RB5 + CCP=CCP:RC5 + PWM=PWM:RC5 + I2C=SDA:RB4,SCL:RB6 + SPI=SDI:RB4,SDO:RC7,SCK:RB6,SS:RC6 + USART=RX:RB5,TX:RB7 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f722,16f722a,16f723,16f723a,16f726 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0,AN13:RB5 + CCP=CCP1:RC2,CCP2:RC1/RB3 + PWM=PWM1:RC2,PWM2:RC1/RB3 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA0/RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f724,16f727 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2,AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0,AN13:RB5 + CCP=CCP1:RC2,CCP2:RC1/RB3 + PWM=PWM1:RC2,PWM2:RC1/RB3 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA0/RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f737,16f767 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0,AN13:RB5 + CCP=CCP1:RC2,CCP2:RC1/RB3,CCP3:RB5 + PWM=PWM1:RC2,PWM2:RC1/RB3,PWM3:RB5 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:0 + END=MCU + + BEGIN=MCU:16f747,16f777 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2,AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0,AN13:RB5 + CCP=CCP1:RC2,CCP2:RC1/RB3,CCP3:RB5 + PWM=PWM1:RC2,PWM2:RC1/RB3,PWM3:RB5 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:0 + END=MCU + + BEGIN=MCU:16f753,16hv753 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA4,AN4:RC0,AN5:RC1,AN6:RC2,AN7:RC3 + CCP=CCP:RC5 + PWM=PWM:RC5 + END=MCU + + BEGIN=MCU:16f785 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA4,AN4:RC0,AN5:RC1,AN6:RC2,AN7:RC3,AN8:RC6,AN9:RC7,AN10:RB4,AN11:RB5 + CCP=CCP:RC5 + PWM=PWM:RC5 + END=MCU + + BEGIN=MCU:16f818,16f819 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA4 + CCP=CCP:RB3 + PWM=PWM:RB3 + I2C=SDA:RB1,SCL:RB4 + SPI=SDI:RB1,SDO:RB2,SCK:RB4,SS:RB5 + END=MCU + + BEGIN=MCU:16f870 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + CCP=CCP:RC2 + PWM=PWM:RC2 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:0 + END=MCU + + BEGIN=MCU:16f871 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2 + CCP=CCP:RC2 + PWM=PWM:RC2 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:0 + END=MCU + + BEGIN=MCU:16f872 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + CCP=CCP:RC2 + PWM=PWM:RC2 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + END=MCU + + BEGIN=MCU:16f873,16f873a,16f876,16f876a + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + CCP=CCP1:RC2,CCP2:RC1 + PWM=PWM1:RC2,PWM2:RC1 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:0 + END=MCU + + BEGIN=MCU:16f874,16f874a,16f877,16f877a + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2 + CCP=CCP1:RC2,CCP2:RC1 + PWM=PWM1:RC2,PWM2:RC1 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:0 + END=MCU + + BEGIN=MCU:16f882,16f883,16f886 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0,AN13:RB5 + CCP=CCP1:RC2,CCP2:RC1 + PWM=PWM1:RC2,PWM2:RC1 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f884,16f887 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2,AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0,AN13:RB5 + CCP=CCP1:RC2,CCP2:RC1 + PWM=PWM1:RC2,PWM2:RC1 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f913,16f916 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3 + CCP=CCP:RC5 + PWM=PWM:RC5 + I2C=SDA:RC7,SCL:RC6 + SPI=SDI:RC7,SDO:RC4,SCK:RC6,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f914,16f917,16f946 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2 + CCP=CCP1:RC5,CCP2:RD2 + PWM=PWM1:RC5,PWM2:RD2 + I2C=SDA:RC7,SCL:RC6 + SPI=SDI:RC7,SDO:RC4,SCK:RC6,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f1454 + PWM=PWM1:RC5,PWM2:RA5/RC3 + I2C=SDA:RC1,SCL:RC0 + SPI=SDI:RC1,SDO:RA4/RC2,SCK:RC0,SS:RA3/RC3 + USART=RX:RC5,TX:RC4 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f1455 + ADC=AN3:RA4,AN4:RC0,AN5:RC1,AN6:RC2,AN7:RC3 + PWM=PWM1:RC5,PWM2:RA5/RC3 + I2C=SDA:RC1,SCL:RC0 + SPI=SDI:RC1,SDO:RA4/RC2,SCK:RC0,SS:RA3/RC3 + USART=RX:RC5,TX:RC4 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f1459 + ADC=AN3:RA4,AN4:RC0,AN5:RC1,AN6:RC2,AN7:RC3,AN8:RC6,AN9:RC7,AN10:RB4,AN11:RB5 + PWM=PWM1:RC5,PWM2:RC6 + I2C=SDA:RB4,SCL:RB6 + SPI=SDI:RB4,SDO:RC7,SCK:RB6,SS:RA3/RC6 + USART=RX:RB5,TX:RB7 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f1503 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA4,AN4:RC0,AN5:RC1,AN6:RC2,AN7:RC3 + PWM=PWM1:RC5,PWM2:RC3,PWM3:RA2,PWM4:RC1 + I2C=SDA:RC1,SCL:RC0 + SPI=SDI:RC1,SDO:RA4/RC2,SCK:RC0,SS:RA3/RC3 + END=MCU + + BEGIN=MCU:16f1507 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA4,AN4:RC0,AN5:RC1,AN6:RC2,AN7:RC3,AN8:RC6,AN9:RC7,AN10:RB4,AN11:RB5 + PWM=PWM1:RC5,PWM2:RC3,PWM3:RA2,PWM4:RC1 + END=MCU + + BEGIN=MCU:16f1508,16f1509 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA4,AN4:RC0,AN5:RC1,AN6:RC2,AN7:RC3,AN8:RC6,AN9:RC7,AN10:RB4,AN11:RB5 + PWM=PWM1:RC5,PWM2:RC3,PWM3:RA2,PWM4:RC1 + I2C=SDA:RB4,SCL:RB6 + SPI=SDI:RB4,SDO:RC7,SCK:RB6,SS:RA3/RC6 + USART=RX:RB5,TX:RB7 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f1512,16f1513 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0,AN13:RB5 + CCP=CCP1:RC2,CCP2:RC1/RB3 + PWM=PWM1:RC2,PWM2:RC1/RB3 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA0/RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f1516,16f1518 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0,AN13:RB5,AN14:RC2,AN15:RC3,AN16:RC4,AN17:RC5,AN18:RC6,AN19:RC7 + CCP=CCP1:RC2,CCP2:RC1/RB3 + PWM=PWM1:RC2,PWM2:RC1/RB3 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA0/RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f1517,16f1519 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2,AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0,AN13:RB5,AN14:RC2,AN15:RC3,AN16:RC4,AN17:RC5,AN18:RC6,AN19:RC7,AN20:RD0,AN21:RD1,AN22:RD2,AN23:RD3,AN24:RD4,AN25:RD5,AN26:RD6,AN27:RD7 + CCP=CCP1:RC2,CCP2:RC1/RB3 + PWM=PWM1:RC2,PWM2:RC1/RB3 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA0/RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f1526,16f1527 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RF7,AN6:RF1,AN7:RF2,AN8:RF3,AN9:RF4,AN10:RF5,AN11:RF6,AN12:RG4,AN13:RG3,AN14:RG2,AN15:RG1,AN16:RF0,AN17:RB0,AN18:RB1,AN19:RB2,AN20:RB3,AN21:RB4,AN22:RB5,AN23:RD0,AN24:RD1,AN25:RD2,AN26:RD3,AN27:RE0,AN28:RE1,AN29:RE2 + CCP=CCP1:RC2,CCP2:RC1/RE7,CCP3:RG0,CCP4:RG3,CCP5:RG4,CCP6:RE6,CCP7:RE5,CCP8:RE4,CCP9:RE3,CCP10:RE2 + CCP=PWM1:RC2,PWM2:RC1/RE7,PWM3:RG0,PWM4:RG3,PWM5:RG4,PWM6:RE6,PWM7:RE5,PWM8:RE4,PWM9:RE3,PWM10:RE2 + I2C=SDA1:RC4,SCL1:RC3,SDA2:RD5,SCL2:RD6 + SPI=SDI1:RC4,SDO1:RC5,SCK1:RC3,SS1:RF7,SDI2:RD5,SDO2:RD4,SCK2:RD6,SS2:RD7 + USART=RX1:RC7,TX1:RC6,RX2:RG2,TX2:RG1 + USART=IO_DIR=RX1:1,TX1:0,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:16lf1554,16lf1559 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN10:RA4,AN11:RC4,AN12:RC2,AN13:RC0,AN20:RA5,AN21:RC5,AN22:RC3,AN23:RC1 + PWM=PWM1:RC2,PWM2:RC3 + I2C=SDA:RC1/RA3,SCL:RC0 + SPI=SDI:RC1/RA3,SDO:RC2/RA4,SCK:RC0,SS:RC3/RA3 + USART=RX:RC5/RA4,TX:RC4/RC3 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f1613 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA4,AN4:RC0,AN5:RC1,AN6:RC2,AN7:RC3 + CCP=CCP1:RC5,CCP2:RA5/RC3 + PWM=PWM1:RC5,PWM2:RA5/RC3 + END=MCU + +# +# Remappable peripheral pins. (PPS) +# (The definition valid until a newer definition overwrites the members.) +# + BEGIN=DEFINE + RI0=RA0 + RI1=RA1 + RI2=RA2 + RI3=RA3 + RI4=RA4 + RI5=RA5 + RI6=RC0 + RI7=RC1 + RI8=RC2 + RI9=RC3 + RI10=RC4 + RI11=RC5 + + RO0=RA0 + RO1=RA1 + RO2=RA2 + RO3=RA4 + RO4=RA5 + RO5=RC0 + RO6=RC1 + RO7=RC2 + RO8=RC3 + RO9=RC4 + RO10=RC5 + END=DEFINE + + BEGIN=MCU:16f1703 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA4,AN4:RC0,AN5:RC1,AN6:RC2,AN7:RC3 + CCP=CCP1:RI[0-11],CCP2:RI[0-11] + PWM=PWM1:RO[0-10],PWM2:RO[0-10] + I2C=SDA:RO[0-10],SCL:RO[0-10] + SPI=SDI:RI[0-11],SDO:RO[0-10],SCK:RO[0-10],SS:RI[0-11] + END=MCU + + BEGIN=MCU:16f1704,16lf1704,16f1705 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA4,AN4:RC0,AN5:RC1,AN6:RC2,AN7:RC3 + CCP=CCP1:RI[0-11],CCP2:RI[0-11] + PWM=PWM1:RO[0-10],PWM2:RO[0-10] + I2C=SDA:RO[0-10],SCL:RO[0-10] + SPI=SDI:RI[0-11],SDO:RO[0-10],SCK:RO[0-10],SS:RI[0-11] + USART=RX:RI[0-11],TX:RO[0-10] + USART=IO_DIR=RX:1,TX:1 + END=MCU + +# +# Remappable peripheral pins. (PPS) +# (The definition valid until a newer definition overwrites the members.) +# + BEGIN=DEFINE + RI0=RA0 + RI1=RA1 + RI2=RA2 + RI3=RA3 + RI4=RA4 + RI5=RA5 + RI6=RB4 + RI7=RB5 + RI8=RB6 + RI9=RB7 + RI10=RC0 + RI11=RC1 + RI12=RC2 + RI13=RC3 + RI14=RC4 + RI15=RC5 + RI16=RC6 + RI17=RC7 + END=DEFINE + + BEGIN=MCU:16f1707 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA4,AN4:RC0,AN5:RC1,AN6:RC2,AN7:RC3,AN8:RC6,AN9:RC7,AN10:RB4,AN11:RB5 + CCP=CCP1:RI[0-17],CCP2:RI[0-17] + PWM=PWM1:RO[0-10],PWM2:RO[0-10] + I2C=SDA:RO[0-10],SCL:RO[0-10] + SPI=SDI:RI[0-17],SDO:RO[0-10],SCK:RO[0-10],SS:RI[0-17] + END=MCU + + BEGIN=MCU:16f1708,16lf1708,16f1709 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA4,AN4:RC0,AN5:RC1,AN6:RC2,AN7:RC3,AN8:RC6,AN9:RC7,AN10:RB4,AN11:RB5 + CCP=CCP1:RI[0-17],CCP2:RI[0-17] + PWM=PWM1:RO[0-10],PWM2:RO[0-10] + I2C=SDA:RO[0-10],SCL:RO[0-10] + SPI=SDI:RI[0-17],SDO:RO[0-10],SCK:RO[0-10],SS:RI[0-17] + USART=RX:RI[0-17],TX:RO[0-10] + USART=IO_DIR=RX:1,TX:1 + END=MCU + +# +# Remappable peripheral pins. (PPS) +# (The definition valid until a newer definition overwrites the members.) +# + BEGIN=DEFINE + RI0=RB0 + RI1=RB1 + RI2=RB2 + RI3=RB3 + RI4=RB4 + RI5=RB5 + RI6=RB6 + RI7=RB7 + RI8=RC0 + RI9=RC1 + RI10=RC2 + RI11=RC3 + RI12=RC4 + RI13=RC5 + RI14=RC6 + RI15=RC7 + + RO0=RB0 + RO1=RB1 + RO2=RB2 + RO3=RB3 + RO4=RB4 + RO5=RB5 + RO6=RB6 + RO7=RB7 + RO8=RC0 + RO9=RC1 + RO10=RC2 + RO11=RC3 + RO12=RC4 + RO13=RC5 + RO14=RC6 + RO15=RC7 + END=DEFINE + + BEGIN=MCU:16f1713,16f1716,16f1718 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0,AN13:RB5,AN14:RC2,AN15:RC3,AN16:RC4:AN17:RC5,AN18:RC6,AN19:RC7 + CCP=CCP1:RI[0-15],CCP2:RI[0-15] + PWM=PWM1:RO[0-15],PWM2:RO[0-15] + I2C=SDA:RO[0-15],SCL:RO[0-15] + SPI=SDI:RI[0-15],SDO:RO[8-15],SCK:RO[0-15],SS:RI[8-15] + USART=RX:RI[0-15],TX:RO[0-15] + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f1717,16f1719 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2,AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0,AN13:RB5,AN14:RC2,AN15:RC3,AN16:RC4:AN17:RC5,AN18:RC6,AN19:RC7,AN20:RD0,AN21:RD1,AN22:RD2,AN23:RD3,AN24:RD4,AN25:RD5,AN26:RD6,AN27:RD7 + CCP=CCP1:RI[0-15],CCP2:RI[0-15] + PWM=PWM1:RO[0-15],PWM2:RO[0-15] + I2C=SDA:RO[0-15],SCL:RO[0-15] + SPI=SDI:RI[0-15],SDO:RO[8-15],SCK:RO[0-15],SS:RI[8-15] + USART=RX:RI[0-15],TX:RO[0-15] + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f1782,16f1783 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0,AN13:RB5 + CCP=CCP1:RC2/RB0,CCP2:RC1/RB3 + PWM=PWM1:RC2/RB0,PWM2:RC1/RB3 + I2C=SDA:RC4/RB6,SCL:RC3/RB7 + SPI=SDI:RC4/RB6,SDO:RC5/RB5,SCK:RC3/RB7,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f1786 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0,AN13:RB5 + CCP=CCP1:RC2/RB0,CCP2:RC1/RB3,CCP3:RC6/RB5 + PWM=PWM1:RC2/RB0,PWM2:RC1/RB3,PWM3:RC6/RB5 + I2C=SDA:RC4/RB6,SCL:RC3/RB7 + SPI=SDI:RC4/RB6,SDO:RC5/RB5,SCK:RC3/RB7,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f1784,16f1787 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2,AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0,AN13:RB5,AN21:RD1 + CCP=CCP1:RC2/RB0,CCP2:RC1/RB3,CCP3:RE0/RB5 + PWM=PWM1:RC2/RB0,PWM2:RC1/RB3,PWM3:RE0/RB5 + I2C=SDA:RC4/RB6,SCL:RC3/RB7 + SPI=SDI:RC4/RB6,SDO:RC5/RB5,SCK:RC3/RB7,SS:RA5 + USART=RX:RC7/RB7,TX:RC6/RB6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f1788 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0,AN13:RB5 + CCP=CCP1:RC2/RB0,CCP2:RC1/RB3,CCP3:RC6/RB5 + PWM=PWM1:RC2/RB0,PWM2:RC1/RB3,PWM3:RC6/RB5 + I2C=SDA:RC4/RB6,SCL:RC3/RB7 + SPI=SDI:RC4/RB6,SDO:RC5/RB5,SCK:RC3/RB7,SS:RA0/RA5/RB4 + USART=RX:RC7/RB7,TX:RC6/RB6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f1789 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2,AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0,AN13:RB5,AN21:RD1 + CCP=CCP1:RC2/RB0,CCP2:RC1/RB3,CCP3:RE0/RB5 + PWM=PWM1:RC2/RB0,PWM2:RC1/RB3,PWM3:RE0/RB5 + I2C=SDA:RC4/RB6,SCL:RC3/RB7 + SPI=SDI:RC4/RB6,SDO:RC5/RB5,SCK:RC3/RB7,SS:RA0/RA5/RB4 + USART=RX:RC7/RB7,TX:RC6/RB6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f1823 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA4,AN4:RC0,AN5:RC1,AN6:RC2,AN7:RC3 + CCP=CCP:RC5 + PWM=PWM:RC5 + I2C=SDA:RC1,SCL:RC0 + SPI=SDI:RC1,SDO:RA4/RC2,SCK:RC0,SS:RA3/RC3 + USART=RX:RC5/RA1,TX:RC4/RA0 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f1824,16f1825 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA4,AN4:RC0,AN5:RC1,AN6:RC2,AN7:RC3 + CCP=CCP1:RC5,CCP2:RC3/RA5,CCP3:RA2,CCP4:RC1 + PWM=PWM1:RC5,PWM2:RC3/RA5,PWM3:RA2,PWM4:RC1 + I2C=SDA:RC1,SCL:RC0 + SPI=SDI:RC1,SDO:RA4/RC2,SCK:RC0,SS:RA3/RC3 + USART=RX:RC5/RA1,TX:RC4/RA0 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f1826 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA4,AN5:RB6,AN6:RB7,AN7:RB5,AN8:RB4,AN9:RB3,AN10:RB2,AN11:RB1 + CCP=CCP:RB3/RB0 + PWM=PWM:RB3/RB0 + I2C=SDA:RB1,SCL:RB4 + SPI=SDI:RB1,SDO:RB2/RA6,SCK:RB4,SS:RB5/RA5 + USART=RX:RB1/RB2,TX:RB2/RB5 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f1827,16f1847 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA4,AN5:RB6,AN6:RB7,AN7:RB5,AN8:RB4,AN9:RB3,AN10:RB2,AN11:RB1 + CCP=CCP1:RB3/RB0,CCP2:RB6/RA7,CCP3:RA3,CCP4:RA4 + PWM=PWM1:RB3/RB0,PWM2:RB6/RA7,PWM3:RA3,PWM4:RA4 + I2C=SDA1:RB1,SCL1:RB4,SDA2:RB2,SCL2:RB5 + SPI=SDI1:RB1,SDO1:RB2/RA6,SCK1:RB4,SS1:RB5/RA5,SDI2:RB2,SDO2:RA0,SCK2:RB5,SS2:RA1 + USART=RX:RB1/RB2,TX:RB2/RB5 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f1828 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA4,AN4:RC0,AN5:RC1,AN6:RC2,AN7:RC3,AN8:RC6,AN9:RC7,AN10:RB4,AN11:RB5 + CCP=CCP1:RC5,CCP2:RC3/RA5,CCP3:RA2,CCP4:RC6 + PWM=PWM1:RC5,PWM2:RC3/RA5,PWM3:RA2,PWM4:RC6 + I2C=SDA:RB4,SCL:RB6 + SPI=SDI:RB4,SDO:RC7,SCK:RB6,SS:RC6 + USART=RX:RC5/RB5,TX:RC4/RB7 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f1829 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA4,AN4:RC0,AN5:RC1,AN6:RC2,AN7:RC3,AN8:RC6,AN9:RC7,AN10:RB4,AN11:RB5 + CCP=CCP1:RC5,CCP2:RC3/RA5,CCP3:RA2,CCP4:RC6 + PWM=PWM1:RC5,PWM2:RC3/RA5,PWM3:RA2,PWM4:RC6 + I2C=SDA1:RB4,SCL1:RB6,SDA2:RB5,SCL2:RB7 + SPI=SDI1:RB4,SDO1:RC7,SCK1:RB6,SS1:RC6,SDI2:RB5,SDO2:RC1/RA5,SCK2:RB7,SS2:RC0/RA4 + USART=RX:RC5/RB5,TX:RC4/RB7 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f1933,16f1936,16f1938 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0,AN13:RB5 + CCP=CCP1:RC2,CCP2:RC1/RB3,CCP3:RC6/RB5,CCP4:RB0,CCP5:RA4 + PWM=PWM1:RC2,PWM2:RC1/RB3,PWM3:RC6/RB5,PWM4:RB0,PWM5:RA4 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA0/RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f1934,16f1937,16f1939 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2,AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0,AN13:RB5 + CCP=CCP1:RC2,CCP2:RC1/RB3,CCP3:RE0/RB5,CCP4:RD1,CCP5:RE2 + PWM=PWM1:RC2,PWM2:RC1/RB3,PWM3:RE0/RB5,PWM4:RD1,PWM5:RE2 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA0/RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:16f1946,16f1947 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RF7,AN6:RF1,AN7:RF2,AN8:RF3,AN9:RF4,AN10:RF5,AN11:RF6,AN12:RG4,AN13:RG3,AN14:RG2,AN15:RG1,AN16:RF0 + CCP=CCP1:RC2,CCP2:RC1/RE7,CCP3:RG0,CCP4:RG3,CCP5:RG4 + PWM=PWM1:RC2,PWM2:RC1/RE7,PWM3:RG0,PWM4:RG3,PWM5:RG4 + I2C=SDA1:RC4,SCL1:RC3,SDA2:RD5,SCL2:RD6 + SPI=SDI1:RC4,SDO1:RC5,SCK1:RC3,SS1:RF7,SDI2:RD5,SDO2:RD4,SCK2:RD6,SS2:RD7 + USART=RX1:RC7,TX1:RC6,RX2:RG2,TX2:RG1 + USART=IO_DIR=RX1:1,TX1:0,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:16lf1902,16lf1903 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0,AN13:RB5 + END=MCU + + BEGIN=MCU:16lf1906 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0,AN13:RB5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:0 + END=MCU + + BEGIN=MCU:16lf1904,16lf1907 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2,AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0,AN13:RB5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:0 + END=MCU + +END=IO_TABLE diff --git a/support/scripts/pic16-header-parser.pl b/support/scripts/pic16-header-parser.pl new file mode 100755 index 0000000..6db417a --- /dev/null +++ b/support/scripts/pic16-header-parser.pl @@ -0,0 +1,3952 @@ +#!/usr/bin/perl -w + +=back + + Copyright (C) 2012-2014, Molnar Karoly <molnarkaroly@users.sf.net> + + This file is part of SDCC. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source distribution. + +================================================================================ + + Proposal for use: ./pic16-header-parser.pl -gp + + This program creates seven files in the current directory: + + adc.h.gen + ccp.h.gen + pwm.h.gen + i2c.h.gen + spi.h.gen + usart.h.gen + peripheral.groups + + In these the MCUs can be seen in groups, according to a periphery. + These informations helps to realize the handling of periphery. + Of course necessary to study the data sheets as well. + + $Id: pic16-header-parser.pl 9071 2014-09-17 08:32:55Z molnarkaroly $ +=cut + +use strict; +use warnings; +no if $] >= 5.018, warnings => "experimental::smartmatch"; # perl 5.16 +use 5.10.1; +use feature 'switch'; # Starting from 5.10.1. +use POSIX 'ULONG_MAX'; + +use constant FALSE => 0; +use constant TRUE => 1; + +use constant P_NO_SHOW_BITS => 0; +use constant P_NO_SHOW_IF_EMPTY => 1; +use constant P_ALWAYS_SHOW => 2; +use constant P_SHOW_ONLY_NAME => 3; + +my @default_paths = + ( + '/usr/share/sdcc/non-free/include', + '/usr/share/sdcc/include', + '/usr/local/share/sdcc/non-free/include', + '/usr/local/share/sdcc/include' + ); + +my $default_port = 'pic16'; +my $header_name_filter = 'pic18f\d+[a-z]*\d+\.h'; + +my $include_path; +my $out_tail = '.gen'; +my $peri_group = 'peripheral.groups'; +my $table_border = (' ' x 19) . '+' . ('---------+' x 8); + +my %reg_addresses = (); + +my @some_ADC_registers = + ( + 'ADCON\d+[HL]?', + 'ADCTMUEN\d+[HL]', + 'ADCHIT\d+[HL]', + 'ADC[HS]S\d+[HL]', + 'ADRES[HL]?|ADCBUF\d+[HL]?', + 'ANCON\d+', + 'ANSEL[\dHL]?', + 'ANSEL[A-O]' + ); + +#----------------------------------------------- + +=back + The structure of one element of the @periphery_table array. + + { + NAME => '', + REGS => [ + { + VALID_REGS => '', + VALID_BITS => '', + PRINT_MODE => P_ALWAYS_SHOW + }, + + ... + + { + } + ] + } + +=cut + +my @periphery_table = (); + +#----------------------------------------------- + +=back + The structure of one element of the @io_table_by_mcu hash: + + { + 'ADC' => { + 'AN0' => [], + + ... + + 'AN4' => [] + }, + + ... + + 'USART' => {} + } +=cut + +my %io_table_by_mcu = (); + +#----------------------------------------------- + +=back + The structure of one element of the @io_dir_table_by_mcu hash: + + { + 'ADC' => {}, + + ... + + 'USART' => { + 'RX' => 1, + 'TX' => 0 + } + } +=cut + +my %io_dir_table_by_mcu = (); + +#----------------------------------------------- + +=back + The structure of one element of the @mcu_raw array: + + { Descriptor of MCU. + NAME => '', The name of MCU. + REG_REFS => { Accelerate searching of the registers. + 'PIR1' => register_reference, ---+ + 'TRISD' => register_reference, ---|---+ + ... | | + ... | . + }, | . + REG_ARRAY => [ The array of registers. | . + { A register. <--+ + NAME => 'PIR1', The name of register. + ADDRESS => 0, The address of register. + BITNAMES => [ The bits of register. + [], The names of bit. + [], + [], + [], + [], + [], + [], + [] + ] + }, + + ... + + { + } + ] + } +=cut + +my @mcu_raw = (); + +#----------------------------------------------- + +=back + The structure of one element of the @mcu_filtered and @mcu_groups arrays: + + { Descriptor of MCU. + NAME => '', The name of MCU. + IN_GROUP => 0, This member of a MCU group. + REG_REFS => { Accelerate searching of the registers. + 'PIR1' => register_reference, ----------------------+ + 'TRISD' => register_reference, ----------------------|---+ + ... | | + ... | | + }, | . + REG_GROUPS => [ The group of all necessary register. | . + { The first register group. | . + VALID_REGS => '', The valid names of registers. | + VALID_BITS => '', The valid names of bits. | + PRINT_MODE => 0, The mode of print. | + REG_ARRAY => [ The array of registers. | + { A register. <-----+ + NAME => 'PIR1', The name of register. + ADDRESS => 0, The address of register. + GROUP => undef, Back reference of REG_GROUPS. + TOUCHED => 0, Touched register during the search. + EMPTY => 0, True if the register became empty after the filtering. + BITNAMES => [ The bits of register. + [], The names of bit. + [], + [], + [], + [], + [], + [], + [] + ] + }, + + ... + + { + } + ] + }, + + ... + + { The last register group. + } + ] + } +=cut + +my @mcu_filtered = (); + +my @mcu_groups = (); + +my %definitions = (); +my %io_groups = (); + +#----------------------------------------------- + +my $verbose = 0; +my $make_groups; +my $only_prime; +my $out_handler; +my $initial_border; + +my $peri_groups = ''; + +################################################################################ +################################################################################ +################################################################################ +################################################################################ + +sub basename($) + { + return ($_[0] =~ /([^\/]+)$/) ? $1 : ''; + } + +#------------------------------------------------------------------------------- + +sub Log + { + return if (pop(@_) > $verbose); + foreach (@_) { print STDERR $_; } + print STDERR "\n"; + } + +#------------------------------------------------------------------------------- + +sub Out + { + foreach (@_) { print $out_handler $_; } + } + +#------------------------------------------------------------------------------- + +sub Outl + { + Out(@_); + print $out_handler "\n"; + } + +#------------------------------------------------------------------------------- + +sub Outf + { + printf $out_handler (shift(@_), @_); + } + +#------------------------------------------------------------------------------- + +sub Outfl + { + Outf(@_); + print $out_handler "\n"; + } + +#------------------------------------------------------------------------------- + +sub smartCompare($$) + { + my ($Str1, $Str2) = @_; + + if (${$Str1} =~ /^\d/o && ${$Str2} =~ /^\d/o) + { + # $Str1 number and $Str2 number + return (int(${$Str1}) <=> int(${$Str2})); + } + + return (${$Str1} cmp ${$Str2}); + } + +#------------------------------------------------------------------------------- + +sub smartSort($$) + { + my @a_s = ($_[0] =~ /(\d+|\D+)/go); + my @b_s = ($_[1] =~ /(\d+|\D+)/go); + my ($i, $k, $end, $ret); + + $i = scalar(@a_s); + $k = scalar(@b_s); + + if ($i < $k) + { + $end = $i; + $ret = -1; + } + elsif ($i == $k) + { + $end = $i; + $ret = 0; + } + else + { + $end = $k; + $ret = 1; + } + + for ($i = 0; $i < $end; ++$i) + { + $k = smartCompare(\$a_s[$i], \$b_s[$i]); + + return $k if ($k != 0); + } + + return $ret; + } + +#------------------------------------------------------------------------------- + +sub exist_in_list($$) + { + my ($List, $Member) = @_; + + foreach (@{$List}) + { + return TRUE if ($Member =~ /^$_$/); + } + + return FALSE; + } + +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@ Populates the peripheral table. @@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +sub add_periphery($) + { + my $peri = { + NAME => lc($_[0]), + REGS => [] + }; + + push(@periphery_table, $peri); + return $peri->{REGS}; + } + +#------------------------------------------------------------------------------- + +sub add_reg_def($) + { + my $def = { + VALID_REGS => '', + VALID_BITS => '', + PRINT_MODE => P_ALWAYS_SHOW + }; + + push(@{$_[0]}, $def); + } + +#------------------------------------------------------------------------------- + +sub resolve_define($) + { + my $Name = $_[0]; + my $ig = \@{$io_groups{$Name}}; + my @array = (); + my $r; + + if (defined($ig) && scalar(@{$ig}) > 0) + { + foreach (@{$ig}) + { + $r = $definitions{$_}; + push(@array, ((defined($r)) ? $r : $_)); + } + } + else + { + $r = $definitions{$Name}; + push(@array, ((defined($r)) ? $r : $Name)); + } + + return \@array; + } + +#------------------------------------------------------------------------------- + +sub add_io_pins($$$) + { + my ($Mcu_group, $Peri, $Pins) = @_; + my %pin_groups = (); + my ($mcu, $io); + my @ports; + + foreach (@{$Pins}) + { + if ($_ !~ /^(\w+):(\S+)$/o) + { + print STDERR "This piece is wrong: \"$_\" (" . join(',', @{$Mcu_group}) . ")\n"; + exit(1); + } + + $io = $1; + @ports = (); + + foreach (split('/', $2)) + { + if ($_ =~ /^(\w+)\[(\d+)-(\d+)\]$/o) + { + # This is a section. E.g.: "RP[0-18]" + + my ($name, $first, $second) = ($1, int($2), int($3)); + + if ($first > $second) + { + print STDERR "\"$_\" The first number ($first) greather than the second number ($second)!\n"; + exit(1); + } + + while ($first <= $second) + { + push(@ports, @{resolve_define("$name$first")}); + ++$first; + } + } + else + { + # This is a name. E.g.: "RD7" or "RP22" + + push(@ports, @{resolve_define($_)}); + } + } # foreach (split('/', $2)) + + $pin_groups{$io} = [ sort {$a cmp $b} @ports ]; + } # foreach (@{$Pins}) + + foreach $mcu (@{$Mcu_group}) + { + foreach $io (keys(%pin_groups)) + { + $io_table_by_mcu{$mcu}->{$Peri}{$io} = [ @{$pin_groups{$io}} ]; + } + } + } + +#------------------------------------------------------------------------------- + +sub add_io_dir($$$) + { + my ($Mcu_group, $Peri, $Pins) = @_; + my %pin_groups = (); + my ($mcu, $io, $dir); + my @ports; + + foreach (@{$Pins}) + { + if ($_ !~ /^(\w+):([01])$/o) + { + print STDERR "This piece is wrong: \"$_\" (" . join(',', @{$Mcu_group}) . ")\n"; + exit(1); + } + + $dir = int($2); + @ports = @{resolve_define($1)}; + + if (@ports > 1) + { + print STDERR "Only one I/O line can be specified: \"$_\" (" . join(',', @{$Mcu_group}) . ")\n"; + exit(1); + } + + $pin_groups{$ports[0]} = $dir; + } # foreach (@{$Pins}) + + foreach $mcu (@{$Mcu_group}) + { + foreach $io (keys(%pin_groups)) + { + $io_dir_table_by_mcu{$mcu}->{$Peri}{$io} = $pin_groups{$io}; + } + } + } + +#------------------------------------------------------------------------------- + +sub load_periphery_data() + { + my $periphery = undef; + my @mcu_group = (); + my @blocks = (); + my ($line, $block, $key, $val); + + foreach (grep(! /^\s*$|^\s*#/o, <DATA>)) + { + chomp; + s/#.*$//o; # Remove ending comment. + s/^\s*|\s*$//go; # Remove starting and ending whitespaces. + $line = $_; + + if ($line =~ /^BEGIN=(\S+)$/o) + { + $block = $1; + + given ($block) + { + when (['IO_TABLE', 'DEFINE', 'GROUP']) + { + } + + when (/^(PERIPHERY):(\w+)$/o) + { + $block = $1; + $periphery = add_periphery($2); + } + + when ('REGISTER') + { + if (! defined($periphery)) + { + print STDERR "There is no periphery to which can be assigned the following register.\n"; + exit(1); + } + + add_reg_def($periphery); + } + + when (/^(MCU):(\S+)$/o) + { + $block = $1; + @mcu_group = split(',', $2); + } + + default + { + print STDERR "Unknown block: \"$block\"\n"; + exit(1); + } + } # given ($block) + + push(@blocks, $block); + next; + } # if ($line =~ /^BEGIN=(\S+)$/o) + elsif ($line =~ /^END=(\S+)$/o) + { + $block = $1; + + if (scalar(@blocks) == 0 || $blocks[$#blocks] ne $block) + { + print STDERR "The \"$block\" block has no beginning!\n"; + exit(1); + } + + given ($block) + { + when ('PERIPHERY') { $periphery = undef; } + when ('MCU') { @mcu_group = (); } + } + + $block = pop(@blocks); + next; + } # elsif ($line =~ /^END=(\w+)$/o) + + #................................... + + $block = (scalar(@blocks) > 0) ? $blocks[$#blocks] : ''; + + given ($block) + { + when ('REGISTER') + { + if ($line =~ /^([^=]+)=(.*)$/o) + { + # This a key -- value pair. + + if (scalar(@{$periphery}) == 0) + { + print STDERR "No entry of the register table!\n"; + exit(1); + } + + ($key, $val) = ($1, $2); + # Reference of the last member. + my $peri_r = \%{$periphery->[$#{$periphery}]}; + + if ($val =~ /^['"]([^'"]*)['"]$/o) + { + # This a text. + + $peri_r->{$key} = $1; + } + else + { + # This a constant. + + $peri_r->{$key} = eval($val); + } + } + } # when ('REGISTER') + + when ('DEFINE') + { + if ($line !~ /^([^=]+)=(.*)$/o) + { + print STDERR "This is not key -- value pair: $line\n"; + exit(1); + } + + ($key, $val) = ($1, $2); + + if (defined($val) && $val ne '') + { + $definitions{$key} = $val; + } + else + { + # Undefine the $key. + + delete($definitions{$key}); + } + } # when ('DEFINE') + + when ('GROUP') + { + if ($line !~ /^([^=]+)=(.*)$/o) + { + print STDERR "This is not group -- members definition: $line\n"; + exit(1); + } + + @{$io_groups{$1}} = split(',', $2); + } # when ('GROUP') + + when ('MCU') + { + if ($line =~ /^([^=]+)=(.*)$/o) + { + my ($peri, $val) = (lc($1), $2); + + if ($val =~ /^([^=]+)=(.*)$/o) + { + # It is possible that this is a property. + + my $prop = $1; + $val = $2; + + given ($prop) + { + when ('IO_DIR') + { + my @pins = split(',', $val); + + add_io_dir(\@mcu_group, $peri, \@pins); + } + + default + { + print STDERR "This is unknown property definition: $line\n"; + exit(1); + } + } + } + else + { + my @pins = split(',', $val); + + add_io_pins(\@mcu_group, $peri, \@pins); + } + } # if ($line =~ /^([^=]+)=(.*)$/o) + } # when ('MCU') + } # given ($block) + } # foreach (grep(! /^\s*$|^\s*#/o, <DATA>)) + + if (scalar(@blocks) > 0) + { + print STDERR "The \"$blocks[$#blocks]\" block has no ending!\n"; + exit(1); + } + } + +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@ Load all registers, which will find in a header. @@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +sub add_mcu_raw($) + { + my $Name = uc($_[0]); + + Log("add_mcu_raw(): $Name", 9); + + my $mcu_ref = { + NAME => $Name, + REG_REFS => {}, + REG_ARRAY => [] + }; + + push(@mcu_raw, $mcu_ref); + return $mcu_ref; + } + +#------------------------------------------------------------------------------- + +sub add_register_raw($$$) + { + my ($Mcu_raw, $Name, $Address) = @_; + + Log(sprintf("add_register_raw(): $Name, 0x%04X", $Address), 9); + + my $reg = { + NAME => $Name, + ADDRESS => $Address, + BITNAMES => [] + }; + + push(@{$Mcu_raw->{REG_ARRAY}}, $reg); + $Mcu_raw->{REG_REFS}->{$Name} = $reg; + } + +#------------------------------------------------------------------------------- + +sub read_regs_from_header($$) + { + my ($Mcu_ref, $Fname) = @_; + my $path = "$include_path/$Fname"; + my ($fh, $name, $addr, $bit_addr, $bitnames, $width); + + if (! open($fh, '<', $path)) + { + print STDERR "\a\t$0 : Can not open the $path header file!\n"; + exit(1); + } + + Log("read_regs_from_header(): $path", 6); + $bitnames = []; + + foreach (grep(! /^\s*$/o, <$fh>)) + { + chomp; + s/\r$//o; + s/^\s*|\s*$//go; + + my $line = $_; + + Log(">>>>: $line", 7); + + if ($line =~ /^#include\s+"(\S+)"$/o) + { + &read_regs_from_header($Mcu_ref, $1); + } + elsif ($line =~ /^#\s*define\s+(\w+_ADDR)\s+0[xX]([[:xdigit:]]+)$/o) + { + Log("reg_addresses\{$1\} = hex($2)", 8); + $reg_addresses{$1} = hex($2); + } + elsif ($line =~ /^extern\b/o && + $line =~ /\b__sfr\b/o && + (($addr) = ($line =~ /\b__at\s*\(\s*0[xX]([[:xdigit:]]+)\s*\)/o)) && + (($name) = ($line =~ /\b(\w+)\s*;$/o))) + { + # extern __at(0x0000) __sfr INDF; + # extern __sfr __at(0x0003) STATUS; + # + + add_register_raw($Mcu_ref, $name, hex($addr)); + } + elsif ($line =~ /^extern\s+__sfr\s+__at\s*\((\w+_ADDR)\)\s+(\w+);$/o) + { + # extern __sfr __at (EEDATA_ADDR) EEDATA; + # + + if (! defined($reg_addresses{$1})) + { + print STDERR "This register: $2 not have address!\n"; + exit(1); + } + + add_register_raw($Mcu_ref, $2, $reg_addresses{$1}); + } + elsif ($line =~ /\bstruct\b/o) + { + Log("\tbit_addr = 0", 8); + $bit_addr = 0; + } + elsif ($line =~ /^unsigned(?:\s+char|\s+int)?\s*:\s*(\d+)\s*;$/o) + { + # unsigned char :1; + # unsigned int : 4; + # + + $width = int($1); + $bit_addr += $width; + Log("\tbit_addr += $width ($bit_addr)", 8); + } + elsif ($line =~ /^unsigned(?:\s+char|\s+int)?\s*(\w+)\s*:\s*(\d+)\s*;$/o) + { + # unsigned char PCFG2:1; + # unsigned int PSA:1; + # unsigned TRISG :5; + # + + ($name, $width) = ($1, int($2)); + + if ($width == 1) + { + Log("\tpush(bitnames->\[$bit_addr\], $name)", 8); + push(@{$bitnames->[$bit_addr]}, $name); + } + else + { + Log("\t$name", 8); + } + + $bit_addr += $width; + Log("\tbit_addr += $width ($bit_addr)", 8); + } + elsif ($line =~ /^\}\s*(?:__)?(\w+)bits_t\s*;$/o || $line =~ /^\}\s*(?:__)?(\w+)_t\s*;$/o) + { + my $reg_ref = $Mcu_ref->{REG_REFS}->{$1}; + + if (! defined($reg_ref)) + { + print STDERR "This register: $1 not have data structure!\n"; + exit(1); + } + + Log("\treg_ref : $reg_ref)", 8); + $reg_ref->{BITNAMES} = $bitnames; + $bitnames = []; + } + } # foreach (grep(! /^\s*$/o, <$fh>)) + + close($fh); + + my $array = \@{$Mcu_ref->{REG_ARRAY}}; + + return if (scalar(@{$array}) == 0); + + # Within the array sorts by name the registers. + + @{$array} = sort {smartSort($a->{NAME}, $b->{NAME})} @{$array}; + } + +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@ @@@@@@@@@@@ +#@@@@@@@@@ To periphery fitting in a manner, filters the registers. @@@@@@@@@@ +#@@@@@@@@@@ @@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +sub add_mcu($$) + { + my ($Peri_regs, $Mcu_raw) = @_; + + my $mcu = { + NAME => $Mcu_raw->{NAME}, + REG_REFS => {}, + IN_GROUP => FALSE, + REG_GROUPS => [] + }; + + Log("add_mcu($mcu->{NAME})", 8); + + # Copies the master periphery table. + + foreach (@{$Peri_regs}) + { + my $group = { + VALID_REGS => $_->{VALID_REGS}, + VALID_BITS => $_->{VALID_BITS}, + PRINT_MODE => $_->{PRINT_MODE}, + REG_ARRAY => [] + }; + + push(@{$mcu->{REG_GROUPS}}, $group); + } + + push(@mcu_filtered, $mcu); + return $mcu; + } + +#------------------------------------------------------------------------------- + +sub add_register($$) + { + my ($Mcu, $Reg_raw) = @_; + my $name = $Reg_raw->{NAME}; + + Log("add_register($Mcu->{NAME}, $name)", 8); + + foreach (@{$Mcu->{REG_GROUPS}}) + { + if ($name =~ /^$_->{VALID_REGS}$/) + { + # This register fits into this group. + + if ($name =~ /^([\D_]+)1$/ && defined($Mcu->{REG_REFS}->{$1})) + { + # This register already exists. E.g.: RCREG1 --> RCREG + return undef; + } + + my $reg = { + NAME => $name, + ADDRESS => $Reg_raw->{ADDRESS}, + GROUP => $_, + TOUCHED => FALSE, + EMPTY => FALSE, + BITNAMES => [] + }; + + push(@{$_->{REG_ARRAY}}, $reg); + $Mcu->{REG_REFS}->{$name} = $reg; + return $reg; + } + } + + return undef; + } + +#------------------------------------------------------------------------------- + + # Cut down frippery from the bit names. + +sub cut_frippery_from_bitnames($$) + { + my ($Regname, $Bits) = @_; + + return if (! defined($Bits) || scalar(@{$Bits}) <= 0); + + my $changed = 0; + my $new_bits = []; + + foreach (@{$Bits}) + { + $changed += ($_ =~ s/^${Regname}_|_${Regname}$//); + $changed += ($_ =~ s/^(\d+)$/bit_$1/o); + push(@{$new_bits}, $_); + } + + $Bits = $new_bits if ($changed); + } + +#------------------------------------------------------------------------------- + +sub tris_ansel_filter($$) + { + my ($Peri_pins, $Pin_name) = @_; + + return TRUE if (! defined($Peri_pins) || + ($Pin_name !~ /^TRIS[A-O]\d+$/io && + $Pin_name !~ /^ANS[A-O]\d+$/io)); + + foreach (keys(%{$Peri_pins})) + { + foreach (@{$Peri_pins->{$_}}) + { + if ($_ =~ /^R([A-O]\d+)$/io) + { + # E.g.: "RC7" --> "TRISC7"; "RC7" --> "ANSC7" + my $tail = uc($1); + my $trisx = "TRIS$tail"; + my $ansx = "ANS$tail"; + + return TRUE if ($Pin_name eq $trisx || $Pin_name eq $ansx); + } + } + } + + return FALSE; + } + +#------------------------------------------------------------------------------- + +sub filter_regs_from_raw($) + { + my $Periphery = $_[0]; + my ($peri_name, $peri_regs) = ($Periphery->{NAME}, $Periphery->{REGS}); + + foreach (@mcu_raw) + { + my $mcu = lc($_->{NAME}); + my $io_ref = \%{$io_table_by_mcu{$mcu}}; + my $peri_pins = (defined($io_ref)) ? $io_ref->{$peri_name} : undef; + + # The MCU not have this periphery. + next if (! defined($peri_pins)); + + my $mcu_ref = add_mcu($peri_regs, $_); + + foreach my $reg_raw (@{$_->{REG_ARRAY}}) + { + my $reg_dst = add_register($mcu_ref, $reg_raw); + + next if (! defined($reg_dst)); + + my $bits_src = $reg_raw->{BITNAMES}; + my $bits_dst = $reg_dst->{BITNAMES}; + my $valid_bits = $reg_dst->{GROUP}->{VALID_BITS}; + my $empty = TRUE; + + if (defined($valid_bits) && $valid_bits ne '') + { + # Filtering follows. + + for (my $i = 0; $i < 8; ++$i) + { + my $new_bits = []; + + cut_frippery_from_bitnames($reg_dst->{NAME}, \@{$bits_src->[$i]}); + foreach (@{$bits_src->[$i]}) + { + # Only those names notes, which passed through the filter. + + push(@{$new_bits}, $_) if (defined($_) && $_ =~ /^$valid_bits$/ && + tris_ansel_filter($peri_pins, $_)); + } + + if (scalar(@{$new_bits}) > 0) + { + $bits_dst->[$i] = $new_bits; + $empty = FALSE; + } + else + { + $bits_dst->[$i] = undef; + } + } + } + else + { + # No filtering. + + for (my $i = 0; $i < 8; ++$i) + { + cut_frippery_from_bitnames($reg_dst->{NAME}, \@{$bits_src->[$i]}); + $empty = FALSE if (defined($bits_src->[$i])); + + $bits_dst->[$i] = [ @{$bits_src->[$i]} ]; + } + } + + $reg_dst->{EMPTY} = $empty; + } + } # foreach (@mcu_raw) + } + +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@ @@@@@@@@ +#@@@@@@@ Collects same group them MCU which, have the same peripheral. @@@@@@@ +#@@@@@@@@ @@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +sub load_touched_flags($$) + { + my $Level = $_[1]; + + foreach (@{$_[0]->{REG_GROUPS}}) + { + foreach (@{$_->{REG_ARRAY}}) + { + $_->{TOUCHED} = $Level; + } + } + } + +#------------------------------------------------------------------------------- + +sub find_not_touched_reg($) + { + foreach (@{$_[0]->{REG_GROUPS}}) + { + foreach (@{$_->{REG_ARRAY}}) + { + next if ($_->{EMPTY}); # It does not take into account the empty register. + + return TRUE if (! $_->{TOUCHED}); # This register left out from a previous comparison. + } + } + + return FALSE; + } + +#------------------------------------------------------------------------------- + +sub find_register($$) + { + my $Prime_reg = $_[1]; + my $cand_reg = $_[0]->{REG_REFS}->{$Prime_reg->{NAME}}; + + return $cand_reg if (defined($cand_reg) && $cand_reg->{ADDRESS} == $Prime_reg->{ADDRESS}); + + return undef; + } + +#------------------------------------------------------------------------------- + +sub find_equivalent_bit($$) + { + my ($Bits1, $Bits2) = @_; + my $d = (defined($Bits1) && scalar(@{$Bits1}) > 0) + (defined($Bits2) && scalar(@{$Bits2}) > 0); + + return TRUE if ($d == 0); + + if ($d != 2) + { + Log("find_equivalent_bit(): Only one bits defined.", 6); + return FALSE; + } + + foreach (@{$Bits1}) + { + return TRUE if (/^$_$/ ~~ @{$Bits2}); + + Log("find_equivalent_bit(): The $_ bit not defined.", 7); + } + + return FALSE; + } + +#------------------------------------------------------------------------------- + +sub find_equivalent_register($$$) + { + my ($Candidate, $Prime_reg, $Print_mode) = @_; + my ($cand_reg, $prime_bits, $cand_bits); + + $cand_reg = find_register($Candidate, $Prime_reg); + + if (! defined($cand_reg)) + { + Log("find_equivalent_register(): Not exists candidate reg: $Prime_reg->{NAME} in $Candidate->{NAME} MCU", 5); + return FALSE; + } + + $cand_reg->{TOUCHED} = TRUE; + + # Not performs comparison, if the bits not must be displayed. + return TRUE if ($Print_mode == P_SHOW_ONLY_NAME); + + $prime_bits = \@{$Prime_reg->{BITNAMES}}; + $cand_bits = \@{$cand_reg->{BITNAMES}}; + + for (my $i = 0; $i < 8; ++$i) + { + if (! find_equivalent_bit(\@{$cand_bits->[$i]}, \@{$prime_bits->[$i]})) + { + Log("find_equivalent_register(): Not finds equivalent bit: $cand_reg->{NAME} != $Prime_reg->{NAME}", 5); + return FALSE; + } + } + + return TRUE; + } + +#------------------------------------------------------------------------------- + +sub find_equivalent_mcu($$) + { + my ($Prime, $Candidate) = @_; + + load_touched_flags($Prime, FALSE); + load_touched_flags($Candidate, FALSE); + + foreach (@{$Prime->{REG_GROUPS}}) + { + my $pmode = $_->{PRINT_MODE}; + + foreach (@{$_->{REG_ARRAY}}) + { + $_->{TOUCHED} = TRUE; + next if ($_->{EMPTY}); + + return FALSE if (! find_equivalent_register($Candidate, $_, $pmode)); + } + } + + if (find_not_touched_reg($Prime)) + { + Log("find_equivalent_mcu(): Finds not touched register: $Prime->{NAME}", 5); + return FALSE; + } + + if (find_not_touched_reg($Candidate)) + { + Log("find_equivalent_mcu(): Finds not touched register: $Candidate->{NAME}", 5); + return FALSE; + } + + return TRUE; + } + +#------------------------------------------------------------------------------- + +sub cmp_io_dirs($$$) + { + my ($Prime, $Candidate, $Periphery) = @_; + my $prime_io = $io_dir_table_by_mcu{lc($Prime->{NAME})}; + my $cand_io = $io_dir_table_by_mcu{lc($Candidate->{NAME})}; + my $d = (defined($prime_io) && scalar(keys %{$prime_io}) > 0) + (defined($cand_io) && scalar(keys %{$cand_io}) > 0); + + return TRUE if ($d == 0); + return FALSE if ($d != 2); + + my ($pr, $ca) = ($prime_io->{$Periphery}, $cand_io->{$Periphery}); + + $d = (defined($pr) && scalar(keys %{$pr}) > 0) + (defined($ca) && scalar(keys %{$ca}) > 0); + + return TRUE if ($d == 0); + return FALSE if ($d != 2); + + foreach (keys(%{$pr})) + { + $d = $ca->{$_}; + + return FALSE if (! defined($d) || $d != $pr->{$_}); + } + + return TRUE; + } + +#------------------------------------------------------------------------------- + +sub make_mcu_groups($) + { + my $Periphery = $_[0]; + my $index = 0; + + foreach (@mcu_filtered) + { + next if ($_->{IN_GROUP}); + + my $group = \@{$mcu_groups[$index]}; + my $prime = $_; + + # The prime - reference - member of group; + push(@{$group}, $_); + $_->{IN_GROUP} = TRUE; + + foreach (@mcu_filtered) + { + next if ($_->{IN_GROUP} || $prime == $_); + + if (find_equivalent_mcu($prime, $_) && cmp_io_dirs($prime, $_, $Periphery)) + { + Log("make_mcu_groups(): $prime->{NAME} == $_->{NAME}\n", 5); + push(@{$group}, $_); + $_->{IN_GROUP} = TRUE; + } + } + + @{$group} = sort {smartSort($a->{NAME}, $b->{NAME})} @{$group}; + ++$index; + } + } + +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@@ Prints the register tables. @@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +=back + Sometimes a bit has more name. This procedure selects these from among + the shortest. +=cut + +sub find_shortest_name($) + { + my $min = ULONG_MAX; + my $str = ''; + + foreach (@{$_[0]}) + { + my $l = length; + + if ($l < $min) + { + $min = $l; + $str = $_; + } + } + + return $str; + } + +#------------------------------------------------------------------------------- + +sub print_registers($$$) + { + my ($Reg_array, $Print_mode, $No_ADC) = @_; + my ($i, $bits); + my $show_closing_border = FALSE; + + foreach (@{$Reg_array}) + { + next if ($No_ADC && exist_in_list(\@some_ADC_registers, $_->{NAME})); + + # Sole bit not have name and the empty register is not must show. + next if ($_->{EMPTY} && $Print_mode == P_NO_SHOW_IF_EMPTY); + + if ($Print_mode == P_SHOW_ONLY_NAME) + { + Outfl("%-10s (%03Xh)", $_->{NAME}, $_->{ADDRESS}); + $initial_border = FALSE; + next; + } + + if (! $initial_border) + { + Outl($table_border); + $initial_border = TRUE; + } + + Outf("%-10s (%03Xh) |", $_->{NAME}, $_->{ADDRESS}); + + $bits = \@{$_->{BITNAMES}}; + for ($i = 7; $i >= 0; --$i) + { + if (defined($bits->[$i]) && $Print_mode != P_NO_SHOW_BITS) + { + Outf("%-9s|", find_shortest_name(\@{$bits->[$i]})); + } + else + { + Out(' |'); + } + } + + Outl(); + $show_closing_border = TRUE; + } # foreach (@{$_[0]}) + + Outl($table_border) if ($show_closing_border); + } + +#------------------------------------------------------------------------------- + + # + # Collects into a list the inputs of ADC, which are uses another + # periphery also. + # + +sub filter_off_adc_inputs($$) + { + my ($Peri_pins, $Adc) = @_; + my @adc_pins = (); + + if (defined($Adc)) + { + foreach my $adc_pin_name (keys(%{$Adc})) + { + my $adc_pin_io = $Adc->{$adc_pin_name}; + + foreach my $peri_pin_name (keys(%{$Peri_pins})) + { + foreach (@{$Peri_pins->{$peri_pin_name}}) + { + if (! (/^$adc_pin_name$/ ~~ @adc_pins) && /^$_$/ ~~ @{$adc_pin_io}) + { + push(@adc_pins, $adc_pin_name) + } + } + } + } + } + + return \@adc_pins; + } + +#------------------------------------------------------------------------------- + +sub print_mcu($$) + { + my ($Mcu, $Peri_name) = @_; + my $name = lc($Mcu->{NAME}); + my $io_ref = \%{$io_table_by_mcu{$name}}; + my $io_dir_ref = \%{$io_dir_table_by_mcu{$name}}; + my $peri_pins = (defined($io_ref)) ? $io_ref->{$Peri_name} : undef; + my $peri_dirs = (defined($io_dir_ref)) ? $io_dir_ref->{$Peri_name} : undef; + my ($adc, $adc_pins, $io, $pin_name, $drop_adc_pins); + my $suppl_info = ''; + + $drop_adc_pins = FALSE; + + if (defined($peri_pins)) + { + if ($Peri_name ne 'adc') + { + $adc = \%{$io_ref->{'adc'}}; + $adc_pins = filter_off_adc_inputs($peri_pins, $adc); + + if (scalar(@{$adc_pins}) > 0) + { + # Supplementary information: Displays inputs of the ADC periphery. + + $suppl_info .= "\n"; + + foreach $pin_name (sort {smartSort($a, $b)} @{$adc_pins}) + { + $suppl_info .= "\t$pin_name:"; + + foreach (@{$adc->{$pin_name}}) + { + $suppl_info .= " $_"; + } + + $suppl_info .= "\n"; + } + } + else + { + $drop_adc_pins = TRUE; + } + } # if ($Peri_name ne 'adc') + + $suppl_info .= "\n"; + + foreach $pin_name (sort {smartSort($a, $b)} keys(%{$peri_pins})) + { + $suppl_info .= "\t$pin_name:"; + + foreach (@{$peri_pins->{$pin_name}}) + { + $suppl_info .= " $_"; + } + + $suppl_info .= "\n"; + } + } # if (defined($peri_pins)) + else + { + print STDERR "print_mcu(): This MCU $name not have $Peri_name pin!\n"; + } + + if (defined($peri_dirs)) + { + $suppl_info .= "\n I/O directions after initialization:\n\n"; + + foreach (sort {smartSort($a, $b)} keys %{$peri_dirs}) + { + $io = ($peri_dirs->{$_} == 0) ? '0 (output)' : '1 (input)'; + $suppl_info .= "\t$_: $io\n"; + } + } + + $initial_border = FALSE; + + foreach (@{$Mcu->{REG_GROUPS}}) + { + next if (scalar(@{$_->{REG_ARRAY}}) == 0); + + print_registers(\@{$_->{REG_ARRAY}}, $_->{PRINT_MODE}, $drop_adc_pins); + } + + Out($suppl_info); + } + +#------------------------------------------------------------------------------- + +sub print_all_data($$) + { + my ($Periphery, $Index) = @_; + my $peri_name = $Periphery->{NAME}; + my $lock = '__' . uc($peri_name) . '__H__'; + my ($sidx, $group_index, $border, $group_name); + + Outl("\n#ifndef $lock\n#define $lock\n\n#include \"pic18fam.h\""); + + $peri_groups .= "\n SECTION=" . uc($peri_name) . "\n\n"; + + if ($make_groups) + { + $group_index = 1; + $border = '#' x 45; + + make_mcu_groups($peri_name); + + foreach (@mcu_groups) + { + next if (scalar(@{$_}) == 0); + + Outl("\n//$border ${group_index}th group $border"); + + ($group_name) = ($_->[0]->{NAME} =~ /^18f(\w+)$/io); + + given ($group_name) + { + # 18fxxJyy + when (/j/io) { $sidx = '1'; } + + # 18fxxKyy + when (/k/io) { $sidx = '2'; } + + # 18fxxxx + default { $sidx = '0'; } + } + + $group_name =~ s/\D//go; + $group_name = "0$group_name" if (length($group_name) < 4); + + $peri_groups .= "18$group_name$Index$sidx:" . join(',', map { lc($_->{NAME}); } @{$_}) . "\n"; + + if ($only_prime) + { + Outl("\n/*"); + + # Prints the name of the group members. + + foreach (@{$_}) + { + Outl("PIC$_->{NAME}"); + } + + # Only contents of the first it shows, because content of the others same. + + print_mcu($_->[0], $peri_name); + Outl('*/'); + } + else + { + # Displays full contents of each member of the group. + + foreach (@{$_}) + { + Outl("\n\n/*\nPIC$_->{NAME}"); + print_mcu($_, $peri_name); + Outl('*/'); + } + } + + ++$group_index; + } + } + else + { + # Displays full contents of each MCU. + + foreach (@mcu_filtered) + { + Outl("\n\n/*\nPIC$_->{NAME}"); + print_mcu($_, $peri_name); + Outl('*/'); + } + } + + Outl("\n#endif // $lock"); + } + +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@@@@@@@ The main program. @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + +load_periphery_data(); + +$include_path = ''; +$make_groups = FALSE; +$only_prime = FALSE; + +for (my $i = 0; $i < @ARGV; ) + { + my $opt = $ARGV[$i++]; + + given ($opt) + { + when (/^-(I|-include)$/o) + { + die "This option \"$opt\" requires a parameter." if ($i > $#ARGV); + + $include_path = $ARGV[$i++]; + } + + when (/^-(g|-make-groups)$/o) + { + $make_groups = TRUE; + } + + when (/^-(p|-only-prime)$/o) + { + $only_prime = TRUE; + } + + when (/^-(gp|pg)$/o) + { + $make_groups = TRUE; + $only_prime = TRUE; + } + + when (/^-(v|-verbose)$/o) + { + die "This option \"$opt\" requires a parameter.\n" if ($i > $#ARGV); + + $verbose = int($ARGV[$i++]); + $verbose = 0 if (! defined($verbose) || $verbose < 0); + $verbose = 10 if ($verbose > 10); + } + + when (/^-(h|-help)$/o) + { + print <<EOT +Usage: $0 [options] + + Options are: + + -I <path> or --include <path> + + The program on this path looks for the headers. + If this is not specified, then looking for a installed + sdcc copy in the system. + + -g or --make-groups + + This command creates groups of MCUs. + + -p or --only-prime + + Prints only the prime member of an MCU group. + + -v <level> or --verbose <level> + + It provides information on from the own operation. + Possible value of the level between 0 and 10. (default: 0) + + -h or --help + + This text. +EOT +; + exit(0); + } + } # given ($opt) + } + +if ($include_path eq '') + { + foreach (@default_paths) + { + if (-d $_) + { + $include_path = "$_/$default_port"; + last; + } + } + + die "Can not find the directory of sdcc headers!" if ($include_path eq ''); + } + +opendir(DIR, $include_path) || die "Can not open. -> \"$include_path\""; + +print "Include path: \"$include_path\"\n"; + +my @filelist = grep(-f "$include_path/$_" && /^$header_name_filter$/, readdir(DIR)); +closedir(DIR); + +@mcu_raw = (); +foreach (sort {smartSort($a, $b)} @filelist) + { + my $name = $_; + + print STDERR "Reading the registers from the $_ header ..."; + + $name =~ s/^pic//io; + $name =~ s/\.\S+$//o; + read_regs_from_header(add_mcu_raw($name), $_); + print STDERR " done.\n"; + } + +my $p_idx = 0; +foreach (@periphery_table) + { + my $out_name = "$_->{NAME}.h$out_tail"; + + open($out_handler, '>', $out_name) || die "Can not create the $out_name output!"; + + print STDERR "Filtering of registers the aspects of $_->{NAME} according to ..."; + @mcu_filtered = (); + @mcu_groups = (); + filter_regs_from_raw($_); + print STDERR " done.\n"; + + print STDERR "Creating the $out_name ..."; + print_all_data($_, $p_idx); + print STDERR " done.\n"; + + close($out_handler); + ++$p_idx; + } + +open(GR, '>', $peri_group) || die "Can not create the $peri_group output!"; +print GR $peri_groups; +close(GR); + +__END__ +################################################################################ +# +# The following rules determine to which registers belong to an peripheral. +# The description of a periphery is bounded by the BEGIN=TABLE_XXX flags. +# The description of a register begin after the BEGIN=REGISTER flag. +# +# BEGIN=PERIPHERY:ADC +# The "ADC" effect of: An file will be created under the name "adc.tables". +# +# VALID_REGS -- This a regular expression. Specifies which one a register +# applies to this entries. +# +# VALID_BITS -- This a regular expression. Specifies which bits are interesting, +# are important. If an empty string is in there will be no filtering. +# +# PRINT_MODE -- This a constant. The following values can be: +# +# P_NO_SHOW_BITS -- Does not shows the bits. +# +# P_NO_SHOW_IF_EMPTY -- Not shows the register if it is empty. +# (This it could be because there are no bits +# or because the filter thrown out them.) +# +# P_ALWAYS_SHOW -- All conditions shows the register. +# +# P_SHOW_ONLY_NAME -- Only shows the register name and address. +# + +################################################################################ +# +# The ADC module related registers. +# (There is so, which only indirectly connected to the module.) +# + +BEGIN=PERIPHERY:ADC # ADC --> adc.h.gen + + BEGIN=REGISTER + VALID_REGS="ADCON\d+[HL]?" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ANCON\d+" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ADCTMUEN\d+[HL]" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ADCHIT\d+[HL]" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ADCSS\d+[HL]" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ADCHS\d+[HL]" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ADRES[HL]?|ADCBUF\d+[HL]?" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ANSEL[\dHL]?" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ANSEL[A-O]" + VALID_BITS="ANS[A-O]\d" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="(FVR|REF|VREF)CON\d*" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="DAC(|ON\d*|CON\d+)" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="INTCON\d?" + VALID_BITS="((G|PE)IE|GIE[HL])" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="IPR\d+" + VALID_BITS="ADIP" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PIE\d+" + VALID_BITS="ADIE" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PIR\d+" + VALID_BITS="ADIF" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PMD\d+" + VALID_BITS="ADC\d*MD" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="CO?M(CON\d*|\d*CON)" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="TRIS([A-Z]|IO)" + VALID_BITS="TRIS([A-Z]|IO)\d" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + +END=PERIPHERY + +################################################################################ +# +# The CCP module related registers. +# (There is so, which only indirectly connected to the module.) +# + +BEGIN=PERIPHERY:CCP # CCP --> ccp.h.gen + + BEGIN=REGISTER + VALID_REGS="APFCON\d*" + VALID_BITS="(CCP(SEL\d|\dSEL)|P\d[A-D]SEL)" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="E?CCP(CON\d*|\d+CON)" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="TCLK(CON\d*|\d+CON)" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="E?CCP(AS\d*|\d+AS)" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="E?CCPR([HL]\d*|\d+[HL])" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="CCPTMRS\d*" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PSTR(CON\d*|\d+CON)" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="(PWM(CON\d*|\d+CON)|ECCP\d*DEL)" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="(T[2468]CON|T10CON)" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="(TMR[2468]|TMR10)" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="(PR[2468]|PR10)" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="INTCON\d?" + VALID_BITS="((G|PE)IE|GIE[HL])" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PIE\d+" + VALID_BITS="CCP\d+IE" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="IPR\d+" + VALID_BITS="CCP\d+IP" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PIR\d+" + VALID_BITS="CCP\d+IF" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PMD\d+" + VALID_BITS="(CCP|TMR)\d+MD" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ANSEL[\dHL]?" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ANSEL[A-O]" + VALID_BITS="ANS[A-O]\d" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ADCON\d+[HL]?" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ANCON\d+" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PPSCON\d*" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="RPINR[78]" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="RPINR(14_15|16_17|32_33|34_35|36_37|38_39)" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="RPOR\d*" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="OD(\d*CON|CON\d*)" + VALID_BITS="CCP\d*OD" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="TRIS([A-Z]|IO)" + VALID_BITS="TRIS([A-Z]|IO)\d|CCP\d*OD" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + +END=PERIPHERY + +################################################################################ +# +# The PWM(CCP) module related registers. +# (There is so, which only indirectly connected to the module.) +# + +BEGIN=PERIPHERY:PWM # PWM --> pwm.h.gen + + BEGIN=REGISTER + VALID_REGS="APFCON\d*" + VALID_BITS="(CCP(SEL\d|\dSEL)|P\d[A-D]SEL)" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="E?CCP(CON\d*|\d+CON)" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="TCLK(CON\d*|\d+CON)" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="E?CCP(AS\d*|\d+AS)" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="E?CCPR([HL]\d*|\d+[HL])" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="CCPTMRS\d*" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="(PT(CON\d*|\d+CON)|PSTR(CON\d*|\d+CON))" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="(PWM(CON\d*|\d+CON)|ECCP\d*DEL)" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="DTCON\d*" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="OVDCON[DS]\d*" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="FLTCONFIG" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="P(DCL\d*|DC\d*L)" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="P(DCH\d*|DC\d*H)" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PT(MR|PER)L\d*" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PT(MR|PER)H\d*" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="SEVTCMPL\d*" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="SEVTCMPH\d*" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="(T[2468]CON|T10CON)" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="(TMR[2468]|TMR10)" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="(PR[2468]|PR10)" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="INTCON\d?" + VALID_BITS="((G|PE)IE|GIE[HL])" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="IPR\d+" + VALID_BITS="((CCP\d+|TMR[2468])IP|TMR10IP)" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PIE\d+" + VALID_BITS="((CCP\d+|TMR[2468])IE|TMR10IE)" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PIR\d+" + VALID_BITS="((CCP\d+|TMR[2468])IF|TMR10IF)" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PMD\d+" + VALID_BITS="(CCP|TMR)\d+MD" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ANSEL[\dHL]?" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ANSEL[A-O]" + VALID_BITS="ANS[A-O]\d" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ADCON\d+[HL]?" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ANCON\d+" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PPSCON\d*" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="RPOR\d*" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="OD(\d*CON|CON\d*)" + VALID_BITS="CCP\d*OD" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="TRIS([A-Z]|IO)" + VALID_BITS="TRIS([A-Z]|IO)\d|CCP\d*OD" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + +END=PERIPHERY + +################################################################################ +# +# The I2C(SSP) module related registers. +# (There is so, which only indirectly connected to the module.) +# + +BEGIN=PERIPHERY:I2C # I2C --> i2c.h.gen + + BEGIN=REGISTER + VALID_REGS="APFCON\d*" + VALID_BITS="S(DI|DO|CK|S)\d*SEL" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="SSP\d*CON\d*" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="SSP\d*ADD\d*" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="SSP\d*BUF\d*" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="SSP\d*MSK\d*" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="SSP\d*STAT\d*" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="INTCON\d?" + VALID_BITS="((G|PE)IE|GIE[HL])" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="IPR\d+" + VALID_BITS="(BCL|SSP)\d*IP" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PIE\d+" + VALID_BITS="(BCL|SSP)\d*IE" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PIR\d+" + VALID_BITS="(BCL|SSP)\d*IF" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PMD\d+" + VALID_BITS="MSSP\d+MD" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ANSEL[\dHL]?" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ANSEL[A-O]" + VALID_BITS="ANS[A-O]\d" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ADCON\d+[HL]?" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ANCON\d+" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PPSCON\d*" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="RPINR2[123]" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="RPOR\d*" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="TRIS([A-Z]|IO)" + VALID_BITS="TRIS([A-Z]|IO)\d|SPIOD" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + +END=PERIPHERY + +################################################################################ +# +# The SPI(SSP) module related registers. +# (There is so, which only indirectly connected to the module.) +# + +BEGIN=PERIPHERY:SPI # SPI --> spi.h.gen + + BEGIN=REGISTER + VALID_REGS="APFCON\d*" + VALID_BITS="S(DI|DO|CK|S)\d*SEL" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="SSP\d*CON\d*" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="SSP\d*ADD\d*" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="SSP\d*BUF\d*" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="SSP\d*MSK\d*" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="SSP\d*STAT\d*" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="INTCON\d?" + VALID_BITS="((G|PE)IE|GIE[HL])" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="IPR\d+" + VALID_BITS="(BCL|SSP)\d*IP" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PIE\d+" + VALID_BITS="(BCL|SSP)\d*IE" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PIR\d+" + VALID_BITS="(BCL|SSP)\d*IF" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PMD\d+" + VALID_BITS="MSSP\d+MD" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ANSEL[\dHL]?" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ANSEL[A-O]" + VALID_BITS="ANS[A-O]\d" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ADCON\d+[HL]?" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ANCON\d+" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PPSCON\d*" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="RPINR2[123]" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="RPINR(8_9|10_11|12_13)" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="RPOR\d*" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="TRIS([A-Z]|IO)" + VALID_BITS="TRIS([A-Z]|IO)\d|SPIOD" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + +END=PERIPHERY + +################################################################################ +# +# The USART module related registers. +# (There is so, which only indirectly connected to the module.) +# + +BEGIN=PERIPHERY:USART # USART --> usart.h.gen + + BEGIN=REGISTER + VALID_REGS="APFCON\d*" + VALID_BITS="(RX(DT)?|TX(CK)?)SEL" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="RC(STA\d*|\d+STA)" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="TX(STA\d*|\d+STA)" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="BAUD(C(ON|TL)\d*|\d+C(ON|TL))" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="SP(BRG[HL]?\d?|\d+BRG[HL]?)" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="RC(REG\d*|\d+REG)" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="TX(REG\d*|\d+REG)" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="INTCON\d?" + VALID_BITS="((G|PE)IE|GIE[HL])" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="IPR\d+" + VALID_BITS="(RC|TX)\d*IP" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PIE\d+" + VALID_BITS="(RC|TX)\d*IE" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PIR\d+" + VALID_BITS="(RC|TX)\d*IF" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PMD\d+" + VALID_BITS="UART\d+MD" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ANSEL[\dHL]?" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ANSEL[A-O]" + VALID_BITS="ANS[A-O]\d" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ADCON\d+[HL]?" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="ANCON\d+" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="PPSCON\d*" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="RPINR1[67]" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="RPINR(0_1|2_3|4_5|6_7)" + VALID_BITS="" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="RPOR\d*" + VALID_BITS="" + PRINT_MODE=P_SHOW_ONLY_NAME + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="OD(\d*CON|CON\d*)" + VALID_BITS="U\d*OD" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="LATG" + VALID_BITS="U\d*OD" + PRINT_MODE=P_NO_SHOW_IF_EMPTY + END=REGISTER + + BEGIN=REGISTER + VALID_REGS="TRIS([A-Z]|IO)" + VALID_BITS="TRIS([A-Z]|IO)\d" + PRINT_MODE=P_ALWAYS_SHOW + END=REGISTER + +END=PERIPHERY + +################################################################################ +# +# This table describes that which onto port pins connected a peripheral. +# + +BEGIN=IO_TABLE + + BEGIN=MCU:18f13k22,18f14k22 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA4,AN4:RC0,AN5:RC1,AN6:RC2,AN7:RC3 + ADC=AN8:RC6,AN9:RC7,AN10:RB4,AN11:RB5 + CCP=CCP1:RC5 + PWM=PWM:RC5 + I2C=SDA:RB4,SCL:RB6 + SPI=SDI:RB4,SDO:RC7,SCK:RB6,SS:RC6 + USART=RX:RB5,TX:RB7 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:18f13k50,18f14k50 + ADC=AN3:RA4,AN4:RC0,AN5:RC1,AN6:RC2,AN7:RC3 + ADC=AN8:RC6,AN9:RC7,AN10:RB4,AN11:RB5 + CCP=CCP1:RC5 + PWM=PWM:RC5 + I2C=SDA:RB4,SCL:RB6 + SPI=SDI:RB4,SDO:RC7,SCK:RB6,SS:RC6 + USART=RX:RB5,TX:RB7 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:18f23k20,18f24k20,18f25k20,18f26k20 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0 + CCP=CCP1:RC2,CCP2:RC1/RB3 + PWM=PWM1:RC2,PWM2:RC1/RB3 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:18f43k20,18f44k20,18f45k20,18f46k20 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2 + ADC=AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0 + CCP=CCP1:RC2,CCP2:RC1/RB3 + PWM=PWM1:RC2,PWM2:RC1/RB3 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:18f23k22,18f24k22,18f25k22,18f26k22 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0 + ADC=AN13:RB5,AN14:RC2,AN15:RC3,AN16:RC4,AN17:RC5,AN18:RC6,AN19:RC7 + CCP=CCP1:RC2,CCP2:RC1/RB3,CCP3:RB5,CCP4:RB0,CCP5:RA4 + PWM=PWM1:RC2,PWM2:RC1/RB3,PWM3:RB5,PWM4:RB0,PWM5:RA4 + I2C=SDA1:RC4,SCL1:RC3 + SPI=SDI1:RC4,SDO1:RC5,SCK1:RC3,SS1:RA5 + I2C=SDA2:RB2,SCL2:RB1 + SPI=SDI2:RB2,SDO2:RB3,SCK2:RB1,SS2:RB0 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RB7,TX2:RB6 + USART=IO_DIR=RX1:1,TX1:1,RX2:1,TX2:1 + END=MCU + + BEGIN=MCU:18f43k22,18f44k22,18f45k22,18f46k22 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2 + ADC=AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0 + ADC=AN13:RB5,AN14:RC2,AN15:RC3,AN16:RC4,AN17:RC5,AN18:RC6,AN19:RC7 + ADC=AN20:RD0,AN21:RD1,AN22:RD2,AN23:RD3,AN24:RD4,AN25:RD5,AN26:RD6,AN27:RD7 + CCP=CCP1:RC2,CCP2:RC1/RB3,CCP3:RB5,CCP4:RD1,CCP5:RE2 + PWM=PWM1:RC2,PWM2:RC1/RB3,PWM3:RB5,PWM4:RD1,PWM5:RE2 + I2C=SDA1:RC4,SCL1:RC3 + SPI=SDI1:RC4,SDO1:RC5,SCK1:RC3,SS1:RA5 + I2C=SDA2:RB2,SCL2:RB1 + SPI=SDI2:RB2,SDO2:RB3,SCK2:RB1,SS2:RB0 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RB7,TX2:RB6 + USART=IO_DIR=RX1:1,TX1:1,RX2:1,TX2:1 + END=MCU + + BEGIN=MCU:18f24j10,18f25j10 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0 + CCP=CCP1:RC2,CCP2:RC1/RB3 + PWM=PWM1:RC2,PWM2:RC1/RB3 + I2C=SDA1:RC4,SCL1:RC3 + SPI=SDI1:RC4,SDO1:RC5,SCK1:RC3,SS1:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:18f44j10,18f45j10 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2 + ADC=AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0 + CCP=CCP1:RC2,CCP2:RC1/RB3 + PWM=PWM1:RC2,PWM2:RC1/RB3 + I2C=SDA1:RC4,SCL1:RC3 + SPI=SDI1:RC4,SDO1:RC5,SCK1:RC3,SS1:RA5 + I2C=SDA2:RD1,SCL2:RD0 + SPI=SDI2:RD1,SDO2:RD2,SCK2:RD0,SS2:RD3 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + +# +# Remappable peripheral pins. (PPS) +# (The definition valid until a newer definition overwrites the members.) +# + BEGIN=DEFINE + RP0=RA0 + RP1=RA1 + RP2=RA5 + RP3=RB0 + RP4=RB1 + RP5=RB2 + RP6=RB3 + RP7=RB4 + RP8=RB5 + RP9=RB6 + RP10=RB7 + RP11=RC0 + RP12=RC1 + RP13=RC2 + RP14=RC3 + RP15=RC4 + RP16=RC5 + RP17=RC6 + RP18=RC7 + END=DEFINE + + BEGIN=MCU:18f24j11,18f25j11,18f26j11 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN8:RB2,AN9:RB3,AN10:RB1,AN11:RC2,AN12:RB0 + CCP=CCP1:RP[0-18] + CCP=CCP2:RP[0-18] + PWM=PWM1:RP[0-18] + PWM=PWM2:RP[0-18] + I2C=SDA1:RC4,SCL1:RC3 + SPI=SDI1:RC4,SDO1:RC5,SCK1:RC3,SS1:RA5 + SPI=SDI2:RP[0-18] + SPI=SDO2:RP[0-18] + SPI=SCK2:RP[0-18] + SPI=SS2:RP[0-18] + USART=RX1:RC7,TX1:RC6 + USART=RX2:RP[0-18] + USART=TX2:RP[0-18] + USART=IO_DIR=RX1:1,TX1:0,RX2:1,TX2:0 + END=MCU + +# +# Remappable peripheral pins. (PPS) +# (The definition valid until a newer definition overwrites the members.) +# + BEGIN=DEFINE + RP19=RD2 + RP20=RD3 + RP21=RD4 + RP22=RD5 + RP23=RD6 + RP24=RD7 + END=DEFINE + + BEGIN=MCU:18f44j11,18f45j11,18f46j11 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2 + ADC=AN8:RB2,AN9:RB3,AN10:RB1,AN11:RC2,AN12:RB0 + CCP=CCP1:RP[0-24] + CCP=CCP2:RP[0-24] + PWM=PWM1:RP[0-24] + PWM=PWM2:RP[0-24] + I2C=SDA1:RC4,SCL1:RC3 + SPI=SDI1:RC4,SDO1:RC5,SCK1:RC3,SS1:RA5 + I2C=SDA2:RD1,SCL2:RD0 + SPI=SDI2:RP[0-24] + SPI=SDO2:RP[0-24] + SPI=SCK2:RP[0-24] + SPI=SS2:RP[0-24] + USART=RX1:RC7,TX1:RC6 + USART=RX2:RP[0-24] + USART=TX2:RP[0-24] + USART=IO_DIR=RX1:1,TX1:0,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f24j50,18f25j50,18f26j50 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN8:RB2,AN9:RB3,AN10:RB1,AN11:RC2,AN12:RB0 + CCP=CCP1:RP[0-13]/RP[17-18] + CCP=CCP2:RP[0-13]/RP[17-18] + PWM=PWM1:RP[0-13]/RP[17-18] + PWM=PWM2:RP[0-13]/RP[17-18] + I2C=SDA1:RB5,SCL1:RB4 + SPI=SDI1:RB5,SDO1:RC7,SCK1:RB4,SS1:RA5 + SPI=SDI2:RP[0-13]/RP[17-18] + SPI=SDO2:RP[0-13]/RP[17-18] + SPI=SCK2:RP[0-13]/RP[17-18] + SPI=SS2:RP[0-13]/RP[17-18] + USART=RX1:RC7,TX1:RC6 + USART=RX2:RP[0-13]/RP[17-18] + USART=TX2:RP[0-13]/RP[17-18] + USART=IO_DIR=RX1:1,TX1:0,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f44j50,18f45j50,18f46j50 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2 + ADC=AN8:RB2,AN9:RB3,AN10:RB1,AN11:RC2,AN12:RB0 + CCP=CCP1:RP[0-13]/RP[17-24] + CCP=CCP2:RP[0-13]/RP[17-24] + PWM=PWM1:RP[0-13]/RP[17-24] + PWM=PWM2:RP[0-13]/RP[17-24] + I2C=SDA1:RB5,SCL1:RB4 + SPI=SDI1:RB5,SDO1:RC7,SCK1:RB4,SS1:RA5 + I2C=SDA2:RD1,SCL2:RD0 + SPI=SDI2:RP[0-13]/RP[17-24] + SPI=SDO2:RP[0-13]/RP[17-24] + SPI=SCK2:RP[0-13]/RP[17-24] + SPI=SS2:RP[0-13]/RP[17-24] + USART=RX1:RC7,TX1:RC6 + USART=RX2:RP[0-13]/RP[17-24] + USART=TX2:RP[0-13]/RP[17-24] + USART=IO_DIR=RX1:1,TX1:0,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f24k50,18f25k50 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0,AN13:RB5 + ADC=AN14:RC2,AN18:RC6,AN19:RC7 + CCP=CCP1:RC2,CCP2:RC1/RB3 + PWM=PWM1:RC2,PWM2:RC1/RB3 + I2C=SDA:RB0,SCL:RB1 + SPI=SDI:RB0,SDO:RB3/RC7,SCK:RB1,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:18f45k50 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2 + ADC=AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0,AN13:RB5 + ADC=AN14:RC2,AN18:RC6,AN19:RC7 + ADC=AN20:RD0,AN21:RD1,AN22:RD2,AN23:RD3,AN24:RD4,AN25:RD5,AN26:RD6,AN27:RD7 + CCP=CCP1:RC2,CCP2:RC1/RB3 + PWM=PWM1:RC2,PWM2:RC1/RB3 + I2C=SDA:RB0,SCL:RB1 + SPI=SDI:RB0,SDO:RB3/RC7,SCK:RB1,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:18f25k80,18f26k80 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN8:RB1,AN9:RB4,AN10:RB0 + CCP=CCP1:RB4,CCP2:RC2,CCP3:RC6,CCP4:RC7,CCP5:RB5 + PWM=PWM1:RB4,PWM2:RC2,PWM3:RC6,PWM4:RC7,PWM5:RB5 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RB7,TX2:RB6 + USART=IO_DIR=RX1:1,TX1:0,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f45k80,18f46k80 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2 + ADC=AN8:RB1,AN9:RB4,AN10:RB0 + CCP=CCP1:RD4,CCP2:RC2,CCP3:RC6,CCP4:RC7,CCP5:RB5 + PWM=PWM1:RD4,PWM2:RC2,PWM3:RC6,PWM4:RC7,PWM5:RB5 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RD7,TX2:RD6 + USART=IO_DIR=RX1:1,TX1:0,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f65k80,18f66k80 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2 + ADC=AN8:RB1,AN9:RB4,AN10:RB0 + CCP=CCP1:RD4,CCP2:RC2,CCP3:RC6,CCP4:RC7,CCP5:RB5 + PWM=PWM1:RD4,PWM2:RC2,PWM3:RC6,PWM4:RC7,PWM5:RB5 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + USART=RX1:RG0,TX1:RG3 + USART=RX2:RE6,TX2:RE7 + USART=IO_DIR=RX1:1,TX1:0,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f26j13,18f27j13 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN8:RB2,AN9:RB3,AN10:RB1,AN11:RC2,AN12:RB0 + CCP=CCP4:RB4,CCP5:RB5,CCP6:RB6,CCP7:RB7,CCP8:RC1,CCP9:RC6,CCP10:RC7 + PWM=PWM4:RB4,PWM5:RB5,PWM6:RB6,PWM7:RB7,PWM8:RC1,PWM9:RC6,PWM10:RC7 + I2C=SDA1:RC4,SCL1:RC3 + SPI=SDI1:RC4,SDO1:RC5,SCK1:RC3,SS1:RA5 + SPI=SDI2:RP[0-18] + SPI=SDO2:RP[0-18] + SPI=SCK2:RP[0-18] + SPI=SS2:RP[0-18] + USART=RX1:RC7,TX1:RC6 + USART=RX2:RP[0-18] + USART=TX2:RP[0-18] + USART=IO_DIR=RX1:1,TX1:0,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f46j13,18f47j13 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2 + ADC=AN8:RB2,AN9:RB3,AN10:RB1,AN11:RC2,AN12:RB0 + CCP=CCP4:RB4,CCP5:RB5,CCP6:RB6,CCP7:RB7,CCP8:RC1,CCP9:RC6,CCP10:RC7 + PWM=PWM4:RB4,PWM5:RB5,PWM6:RB6,PWM7:RB7,PWM8:RC1,PWM9:RC6,PWM10:RC7 + I2C=SDA1:RC4,SCL1:RC3 + SPI=SDI1:RC4,SDO1:RC5,SCK1:RC3,SS1:RA5 + I2C=SDA2:RD1,SCL2:RD0 + SPI=SDI2:RP[0-24] + SPI=SDO2:RP[0-24] + SPI=SCK2:RP[0-24] + SPI=SS2:RP[0-24] + USART=RX1:RC7,TX1:RC6 + USART=RX2:RP[0-24] + USART=TX2:RP[0-24] + USART=IO_DIR=RX1:1,TX1:0,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f26j53,18f27j53 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN8:RB2,AN9:RB3,AN10:RB1,AN11:RC2,AN12:RB0 + CCP=CCP4:RB4,CCP5:RB5,CCP6:RB6,CCP7:RB7,CCP8:RC1,CCP9:RC6,CCP10:RC7 + PWM=PWM4:RB4,PWM5:RB5,PWM6:RB6,PWM7:RB7,PWM8:RC1,PWM9:RC6,PWM10:RC7 + I2C=SDA1:RB5,SCL1:RB4 + SPI=SDI1:RB5,SDO1:RC7,SCK1:RB4,SS1:RA5 + SPI=SDI2:RP[0-13]/RP[17-18] + SPI=SDO2:RP[0-13]/RP[17-18] + SPI=SCK2:RP[0-13]/RP[17-18] + SPI=SS2:RP[0-13]/RP[17-18] + USART=RX1:RC7,TX1:RC6 + USART=RX2:RP[0-13]/RP[17-18] + USART=TX2:RP[0-13]/RP[17-18] + USART=IO_DIR=RX1:1,TX1:0,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f46j53,18f47j53 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2 + ADC=AN8:RB2,AN9:RB3,AN10:RB1,AN11:RC2,AN12:RB0 + CCP=CCP4:RB4,CCP5:RB5,CCP6:RB6,CCP7:RB7,CCP8:RC1,CCP9:RC6,CCP10:RC7 + PWM=PWM4:RB4,PWM5:RB5,PWM6:RB6,PWM7:RB7,PWM8:RC1,PWM9:RC6,PWM10:RC7 + I2C=SDA1:RB5,SCL1:RB4 + SPI=SDI1:RB5,SDO1:RC7,SCK1:RB4,SS1:RA5 + I2C=SDA2:RD1,SCL2:RD0 + SPI=SDI2:RP[0-13]/RP[17-24] + SPI=SDO2:RP[0-13]/RP[17-24] + SPI=SCK2:RP[0-13]/RP[17-24] + SPI=SS2:RP[0-13]/RP[17-24] + USART=RX1:RC7,TX1:RC6 + USART=RX2:RP[0-13]/RP[17-24] + USART=TX2:RP[0-13]/RP[17-24] + USART=IO_DIR=RX1:1,TX1:0,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f63j11,18f64j11,18f65j11 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN5:RF7,AN6:RF1,AN7:RF2,AN8:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + CCP=CCP1:RC2,CCP2:RC1/RE7 + PWM=PWM1:RC2,PWM2:RC1/RE7 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RF7 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RG2,TX2:RG1 + USART=IO_DIR=RX1:1,TX1:1,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f83j11,18f84j11,18f85j11 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN5:RF7,AN6:RF1,AN7:RF2,AN8:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + CCP=CCP1:RC2,CCP2:RC1/RE7 + PWM=PWM1:RC2,PWM2:RC1/RE7 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RF7 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RG2,TX2:RG1 + USART=IO_DIR=RX1:1,TX1:1,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f66j11,18f66j16,18f67j11 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN6:RF1,AN7:RF2,AN8:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + CCP=CCP1:RC2,CCP2:RC1/RE7,CCP3:RG0,CCP4:RG3,CCP5:RG4 + PWM=PWM1:RC2,PWM2:RC1/RE7,PWM3:RG0,PWM4:RG3,PWM5:RG4 + I2C=SDA1:RC4,SCL1:RC3 + SPI=SDI1:RC4,SDO1:RC5,SCK1:RC3,SS1:RF7 + I2C=SDA2:RD5,SCL2:RD6 + SPI=SDI2:RD5,SDO2:RD4,SCK2:RD6,SS2:RD7 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RG2,TX2:RG1 + USART=IO_DIR=RX1:1,TX1:0,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f86j11,18f86j16,18f87j11 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN6:RF1,AN7:RF2,AN8:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + ADC=AN12:RH4,AN13:RH5,AN14:RH6,AN15:RH7 + CCP=CCP1:RC2,CCP2:RC1/RE7,CCP3:RG0,CCP4:RG3,CCP5:RG4 + PWM=PWM1:RC2,PWM2:RC1/RE7,PWM3:RG0,PWM4:RG3,PWM5:RG4 + I2C=SDA1:RC4,SCL1:RC3 + SPI=SDI1:RC4,SDO1:RC5,SCK1:RC3,SS1:RF7 + I2C=SDA2:RD5,SCL2:RD6 + SPI=SDI2:RD5,SDO2:RD4,SCK2:RD6,SS2:RD7 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RG2,TX2:RG1 + USART=IO_DIR=RX1:1,TX1:0,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f63j90,18f64j90,18f65j90 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN5:RF7,AN6:RF1,AN7:RF2,AN8:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + CCP=CCP1:RC2,CCP2:RC1/RE7 + PWM=PWM1:RC2,PWM2:RC1/RE7 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RF7 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RG2,TX2:RG1 + USART=IO_DIR=RX1:1,TX1:1,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f66j90,18f66j93,18f67j90,18f67j93 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN5:RF7,AN6:RF1,AN7:RF2,AN8:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + CCP=CCP1:RC2,CCP2:RC1/RE7 + PWM=PWM1:RC2,PWM2:RC1/RE7 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RF7 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RG2,TX2:RG1 + USART=IO_DIR=RX1:1,TX1:1,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f83j90,18f84j90,18f85j90 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN5:RF7,AN6:RF1,AN7:RF2,AN9:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + CCP=CCP1:RC2,CCP2:RC1/RE7 + PWM=PWM1:RC2,PWM2:RC1/RE7 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RF7 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RG2,TX2:RG1 + USART=IO_DIR=RX1:1,TX1:1,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f86j90,18f86j93,18f87j90,18f87j93 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN5:RF7,AN6:RF1,AN7:RF2,AN9:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + CCP=CCP1:RC2,CCP2:RC1/RE7 + PWM=PWM1:RC2,PWM2:RC1/RE7 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RF7 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RG2,TX2:RG1 + USART=IO_DIR=RX1:1,TX1:1,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f65j10,18f65j15,18f66j10,18f66j15,18f67j10 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN6:RF1,AN7:RF2,AN8:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + CCP=CCP1:RC2,CCP2:RC1/RE7 + PWM=PWM1:RC2,PWM2:RC1/RE7 + I2C=SDA1:RC4,SCL1:RC3 + SPI=SDI1:RC4,SDO1:RC5,SCK1:RC3,SS1:RF7 + I2C=SDA2:RD5,SCL2:RD6 + SPI=SDI2:RD5,SDO2:RD4,SCK2:RD6,SS2:RD7 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RG2,TX2:RG1 + USART=IO_DIR=RX1:1,TX1:0,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f85j10,18f85j15,18f86j10,18f86j15,18f87j10 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN6:RF1,AN7:RF2,AN8:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + ADC=AN12:RH4,AN13:RH5,AN14:RH6,AN15:RH7 + CCP=CCP1:RC2,CCP2:RC1/RE7 + PWM=PWM1:RC2,PWM2:RC1/RE7 + I2C=SDA1:RC4,SCL1:RC3 + SPI=SDI1:RC4,SDO1:RC5,SCK1:RC3,SS1:RF7 + I2C=SDA2:RD5,SCL2:RD6 + SPI=SDI2:RD5,SDO2:RD4,SCK2:RD6,SS2:RD7 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RG2,TX2:RG1 + USART=IO_DIR=RX1:1,TX1:0,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f65j50,18f66j50,18f66j55,18f67j50 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN7:RF2,AN8:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + CCP=CCP1:RC2,CCP2:RC1/RE7,CCP3:RG0,CCP4:RG3,CCP5:RG4 + PWM=PWM1:RC2,PWM2:RC1/RE7,PWM3:RG0,PWM4:RG3,PWM5:RG4 + I2C=SDA1:RC4,SCL1:RC3 + SPI=SDI1:RC4,SDO1:RC5,SCK1:RC3,SS1:RF7 + I2C=SDA2:RD5,SCL2:RD6 + SPI=SDI2:RD5,SDO2:RD4,SCK2:RD6,SS2:RD7 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RG2,TX2:RG1 + USART=IO_DIR=RX1:1,TX1:0,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f85j50,18f86j50,18f86j55,18f87j50 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN7:RF2,AN8:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + ADC=AN12:RH4,AN13:RH5,AN14:RH6,AN15:RH7 + CCP=CCP1:RC2,CCP2:RC1/RE7,CCP3:RG0,CCP4:RG3,CCP5:RG4 + PWM=PWM1:RC2,PWM2:RC1/RE7,PWM3:RG0,PWM4:RG3,PWM5:RG4 + I2C=SDA1:RC4,SCL1:RC3 + SPI=SDI1:RC4,SDO1:RC5,SCK1:RC3,SS1:RF7 + I2C=SDA2:RD5,SCL2:RD6 + SPI=SDI2:RD5,SDO2:RD4,SCK2:RD6,SS2:RD7 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RG2,TX2:RG1 + USART=IO_DIR=RX1:1,TX1:0,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f65k22 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN5:RF7,AN6:RF1,AN7:RF2,AN8:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + ADC=AN16:RG4,AN17:RG3,AN18:RG2,AN19:RG1 + CCP=CCP1:RC2,CCP2:RC1/RB3/RE7,CCP3:RG0,CCP4:RG3,CCP5:RG4 + PWM=PWM1:RC2,PWM2:RC1/RB3/RE7,PWM3:RG0,PWM4:RG3,PWM5:RG4 + CCP=CCP6:RE6,CCP7:RE5,CCP8:RE4 + PWM=PWM6:RE6,PWM7:RE5,PWM8:RE4 + I2C=SDA1:RC4,SCL1:RC3 + SPI=SDI1:RC4,SDO1:RC5,SCK1:RC3,SS1:RF7 + I2C=SDA2:RD5,SCL2:RD6 + SPI=SDI2:RD5,SDO2:RD4,SCK2:RD6,SS2:RD7 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RG2,TX2:RG1 + USART=IO_DIR=RX1:1,TX1:0,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f66k22,18f67k22 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN5:RF7,AN6:RF1,AN7:RF2,AN8:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + ADC=AN16:RG4,AN17:RG3,AN18:RG2,AN19:RG1 + CCP=CCP1:RC2,CCP2:RC1/RB3/RE7,CCP3:RG0,CCP4:RG3,CCP5:RG4 + PWM=PWM1:RC2,PWM2:RC1/RB3/RE7,PWM3:RG0,PWM4:RG3,PWM5:RG4 + CCP=CCP6:RE6,CCP7:RE5,CCP8:RE4,CCP9:RE3,CCP10:RE2 + PWM=PWM6:RE6,PWM7:RE5,PWM8:RE4,PWM9:RE3,PWM10:RE2 + I2C=SDA1:RC4,SCL1:RC3 + SPI=SDI1:RC4,SDO1:RC5,SCK1:RC3,SS1:RF7 + I2C=SDA2:RD5,SCL2:RD6 + SPI=SDI2:RD5,SDO2:RD4,SCK2:RD6,SS2:RD7 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RG2,TX2:RG1 + USART=IO_DIR=RX1:1,TX1:0,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f85k22 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN5:RF7,AN6:RF1,AN7:RF2,AN8:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + ADC=AN12:RH4,AN13:RH5,AN14:RH6,AN15:RH7 + ADC=AN16:RG4,AN17:RG3,AN18:RG2,AN19:RG1 + ADC=AN20:RH3,AN21:RH2,AN22:RH1,AN23:RH0 + CCP=CCP1:RC2,CCP2:RC1/RB3/RE7,CCP3:RG0,CCP4:RG3,CCP5:RG4 + PWM=PWM1:RC2,PWM2:RC1/RB3/RE7,PWM3:RG0,PWM4:RG3,PWM5:RG4 + CCP=CCP6:RE6/RH7,CCP7:RE5/RH6,CCP8:RE4/RH5 + PWM=PWM6:RE6/RH7,PWM7:RE5/RH6,PWM8:RE4/RH5 + I2C=SDA1:RC4,SCL1:RC3 + SPI=SDI1:RC4,SDO1:RC5,SCK1:RC3,SS1:RF7 + I2C=SDA2:RD5,SCL2:RD6 + SPI=SDI2:RD5,SDO2:RD4,SCK2:RD6,SS2:RD7 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RG2,TX2:RG1 + USART=IO_DIR=RX1:1,TX1:0,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f86k22,18f87k22 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN5:RF7,AN6:RF1,AN7:RF2,AN8:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + ADC=AN12:RH4,AN13:RH5,AN14:RH6,AN15:RH7 + ADC=AN16:RG4,AN17:RG3,AN18:RG2,AN19:RG1 + ADC=AN20:RH3,AN21:RH2,AN22:RH1,AN23:RH0 + CCP=CCP1:RC2,CCP2:RC1/RB3/RE7,CCP3:RG0,CCP4:RG3,CCP5:RG4 + PWM=PWM1:RC2,PWM2:RC1/RB3/RE7,PWM3:RG0,PWM4:RG3,PWM5:RG4 + CCP=CCP6:RE6/RH7,CCP7:RE5/RH6,CCP8:RE4/RH5,CCP9:RE3/RH4,CCP10:RE2 + PWM=PWM6:RE6/RH7,PWM7:RE5/RH6,PWM8:RE4/RH5,PWM9:RE3/RH4,PWM10:RE2 + I2C=SDA1:RC4,SCL1:RC3 + SPI=SDI1:RC4,SDO1:RC5,SCK1:RC3,SS1:RF7 + I2C=SDA2:RD5,SCL2:RD6 + SPI=SDI2:RD5,SDO2:RD4,SCK2:RD6,SS2:RD7 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RG2,TX2:RG1 + USART=IO_DIR=RX1:1,TX1:0,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f65k90 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN5:RF7,AN6:RF1,AN7:RF2,AN8:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + ADC=AN16:RG4,AN17:RG3,AN18:RG2,AN19:RG1 + CCP=CCP1:RC2,CCP2:RC1/RE7,CCP3:RG0,CCP4:RG3,CCP5:RG4 + PWM=PWM1:RC2,PWM2:RC1/RE7,PWM3:RG0,PWM4:RG3,PWM5:RG4 + CCP=CCP6:RE6,CCP7:RE5,CCP8:RE4 + PWM=PWM6:RE6,PWM7:RE5,PWM8:RE4 + I2C=SDA1:RC4,SCL1:RC3 + SPI=SDI1:RC4,SDO1:RC5,SCK1:RC3,SS1:RF7 + I2C=SDA2:RD5,SCL2:RD6 + SPI=SDI2:RD5,SDO2:RD4,SCK2:RD6,SS2:RD7 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RG2,TX2:RG1 + USART=IO_DIR=RX1:1,TX1:0,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f66k90,18f67k90 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN5:RF7,AN6:RF1,AN7:RF2,AN8:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + ADC=AN16:RG4,AN17:RG3,AN18:RG2,AN19:RG1 + CCP=CCP1:RC2,CCP2:RC1/RB3/RE7,CCP3:RG0,CCP4:RG3,CCP5:RG4 + PWM=PWM1:RC2,PWM2:RC1/RB3/RE7,PWM3:RG0,PWM4:RG3,PWM5:RG4 + CCP=CCP6:RE6,CCP7:RE5,CCP8:RE4,CCP9:RE3,CCP10:RE2 + PWM=PWM6:RE6,PWM7:RE5,PWM8:RE4,PWM9:RE3,PWM10:RE2 + I2C=SDA1:RC4,SCL1:RC3 + SPI=SDI1:RC4,SDO1:RC5,SCK1:RC3,SS1:RF7 + I2C=SDA2:RD5,SCL2:RD6 + SPI=SDI2:RD5,SDO2:RD4,SCK2:RD6,SS2:RD7 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RG2,TX2:RG1 + USART=IO_DIR=RX1:1,TX1:0,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f85k90 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN5:RF7,AN6:RF1,AN7:RF2,AN8:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + ADC=AN12:RH4,AN13:RH5,AN14:RH6,AN15:RH7 + ADC=AN16:RG4,AN17:RG3,AN18:RG2,AN19:RG1 + ADC=AN20:RH3,AN21:RH2,AN22:RH1,AN23:RH0 + CCP=CCP1:RC2,CCP2:RC1/RE7,CCP3:RG0,CCP4:RG3,CCP5:RG4 + PWM=PWM1:RC2,PWM2:RC1/RE7,PWM3:RG0,PWM4:RG3,PWM5:RG4 + CCP=CCP6:RE6/RH7,CCP7:RE5/RH6,CCP8:RE4/RH5 + PWM=PWM6:RE6/RH7,PWM7:RE5/RH6,PWM8:RE4/RH5 + I2C=SDA1:RC4,SCL1:RC3 + SPI=SDI1:RC4,SDO1:RC5,SCK1:RC3,SS1:RF7 + I2C=SDA2:RD5,SCL2:RD6 + SPI=SDI2:RD5,SDO2:RD4,SCK2:RD6,SS2:RD7 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RG2,TX2:RG1 + USART=IO_DIR=RX1:1,TX1:0,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f86k90,18f87k90 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN5:RF7,AN6:RF1,AN7:RF2,AN8:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + ADC=AN12:RH4,AN13:RH5,AN14:RH6,AN15:RH7 + ADC=AN16:RG4,AN17:RG3,AN18:RG2,AN19:RG1 + ADC=AN20:RH3,AN21:RH2,AN22:RH1,AN23:RH0 + CCP=CCP1:RC2,CCP2:RC1/RE7,CCP3:RG0,CCP4:RG3,CCP5:RG4 + PWM=PWM1:RC2,PWM2:RC1/RE7,PWM3:RG0,PWM4:RG3,PWM5:RG4 + CCP=CCP6:RE6/RH7,CCP7:RE5/RH6,CCP8:RE4/RH5,CCP9:RE3/RH4,CCP10:RE2 + PWM=PWM6:RE6/RH7,PWM7:RE5/RH6,PWM8:RE4/RH5,PWM9:RE3/RH4,PWM10:RE2 + I2C=SDA1:RC4,SCL1:RC3 + SPI=SDI1:RC4,SDO1:RC5,SCK1:RC3,SS1:RF7 + I2C=SDA2:RD5,SCL2:RD6 + SPI=SDI2:RD5,SDO2:RD4,SCK2:RD6,SS2:RD7 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RG2,TX2:RG1 + USART=IO_DIR=RX1:1,TX1:0,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f66j60,18f66j65,18f67j60 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN6:RF1,AN7:RF2,AN8:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + CCP=CCP1:RC2,CCP2:RC1,CCP3:RD1,CCP4:RD2,CCP5:RG4 + PWM=PWM1:RC2,PWM2:RC1,PWM3:RD1,PWM4:RD2,PWM5:RG4 + I2C=SDA1:RC4,SCL1:RC3 + SPI=SDI1:RC4,SDO1:RC5,SCK1:RC3,SS1:RF7 + USART=RX1:RC7,TX1:RC6 + USART=IO_DIR=RX1:1,TX1:0 + END=MCU + + BEGIN=MCU:18f86j60,18f86j65,18f87j60 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN6:RF1,AN7:RF2,AN8:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + ADC=AN12:RH4,AN13:RH5,AN14:RH6,AN15:RH7 + CCP=CCP1:RC2,CCP2:RC1/RE7,CCP3:RG0,CCP4:RG3,CCP5:RG4 + PWM=PWM1:RC2,PWM2:RC1/RE7,PWM3:RG0,PWM4:RG3,PWM5:RG4 + I2C=SDA1:RC4,SCL1:RC3 + SPI=SDI1:RC4,SDO1:RC5,SCK1:RC3,SS1:RF7 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RG2,TX2:RG1 + USART=IO_DIR=RX1:1,TX1:0,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f96j60,18f96j65,18f97j60 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN5:RF0,AN6:RF1,AN7:RF2,AN8:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + ADC=AN12:RH4,AN13:RH5,AN14:RH6,AN15:RH7 + CCP=CCP1:RC2,CCP2:RC1/RB3/RE7,CCP3:RG0,CCP4:RG3,CCP5:RG4 + PWM=PWM1:RC2,PWM2:RC1/RB3/RE7,PWM3:RG0,PWM4:RG3,PWM5:RG4 + I2C=SDA1:RC4,SCL1:RC3 + SPI=SDI1:RC4,SDO1:RC5,SCK1:RC3,SS1:RF7 + I2C=SDA2:RD5,SCL2:RD6 + SPI=SDI2:RD5,SDO2:RD4,SCK2:RD6,SS2:RD7 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RG2,TX2:RG1 + USART=IO_DIR=RX1:1,TX1:0,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f86j72,18f87j72 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN5:RF7,AN6:RF1,AN7:RF2,AN9:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + CCP=CCP1:RC2,CCP2:RC1/RE7 + PWM=PWM1:RC2,PWM2:RC1/RE7 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RF7 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RG2,TX2:RG1 + USART=IO_DIR=RX1:1,TX1:1,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f242,18f252 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + CCP=CCP1:RC2,CCP2:RC1/RB3 + PWM=PWM1:RC2,PWM2:RC1/RB3 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:0 + END=MCU + + BEGIN=MCU:18f442,18f452 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2 + CCP=CCP1:RC2,CCP2:RC1/RB3 + PWM=PWM1:RC2,PWM2:RC1/RB3 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:0 + END=MCU + + BEGIN=MCU:18f248,18f258 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + CCP=CCP1:RC2,CCP2:RC1 + PWM=PWM1:RC2,PWM2:RC1 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:0 + END=MCU + + BEGIN=MCU:18f448,18f458 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2 + CCP=CCP1:RC2,CCP2:RC1 + PWM=PWM1:RC2,PWM2:RC1 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:0 + END=MCU + + BEGIN=MCU:18f1220,18f1320 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RB0,AN5:RB1,AN6:RB4 + CCP=CCP:RB3 + PWM=PWM:RB3 + USART=RX:RB4,TX:RB1 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:18f1230,18f1330 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA6 + USART=RX:RA3,TX:RA2 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:18f2220,18f2320 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0 + CCP=CCP1:RC2,CCP2:RC1/RB3 + PWM=PWM1:RC2,PWM2:RC1/RB3 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:0 + END=MCU + + BEGIN=MCU:18f4220,18f4320 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2 + ADC=AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0 + CCP=CCP1:RC2,CCP2:RC1/RB3 + PWM=PWM1:RC2,PWM2:RC1/RB3 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:0 + END=MCU + + BEGIN=MCU:18f2221,18f2321 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0 + CCP=CCP1:RC2,CCP2:RC1/RB3 + PWM=PWM1:RC2,PWM2:RC1/RB3 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:18f4221,18f4321 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2 + ADC=AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0 + CCP=CCP1:RC2,CCP2:RC1/RB3 + PWM=PWM1:RC2,PWM2:RC1/RB3 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:18f2331,18f2431 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA4 + CCP=CCP1:RC2,CCP2:RC1 + PWM=PWM1:RC2,PWM2:RC1 + I2C=SDA:RC4,SCL:RC5 + SPI=SDI:RC4,SDO:RC7,SCK:RC5,SS:RC6 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:18f4331,18f4431 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA4,AN5:RA5,AN6:RE0,AN7:RE1,AN8:RE2 + CCP=CCP1:RC2,CCP2:RC1 + PWM=PWM1:RC2,PWM2:RC1 + I2C=SDA:RC4/RD2,SCL:RC5/RD3 + SPI=SDI:RC4/RD2,SDO:RC7,SCK:RC5/RD3,SS:RC6 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:18f2410,18f2510,18f2515,18f2610 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0 + CCP=CCP1:RC2,CCP2:RC1/RB3 + PWM=PWM1:RC2,PWM2:RC1/RB3 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:18f4410,18f4510,18f4515,18f4610 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2 + ADC=AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0 + CCP=CCP1:RC2,CCP2:RC1/RB3 + PWM=PWM1:RC2,PWM2:RC1/RB3 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:18f2420,18f2423,18f2520,18f2523 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0 + CCP=CCP1:RC2,CCP2:RC1/RB3 + PWM=PWM1:RC2,PWM2:RC1/RB3 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:18f4420,18f4423,18f4520,18f4523 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2 + ADC=AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0 + CCP=CCP1:RC2,CCP2:RC1/RB3 + PWM=PWM1:RC2,PWM2:RC1/RB3 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:18f2439,18f2539 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + PWM=PWM1:PWM1,PWM2:PWM2 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:0 + END=MCU + + BEGIN=MCU:18f4439,18f4539 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2 + PWM=PWM1:PWM1,PWM2:PWM2 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:0 + END=MCU + + BEGIN=MCU:18f2450 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0 + CCP=CCP:RC2 + PWM=PWM:RC2 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:0 + END=MCU + + BEGIN=MCU:18f4450 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2 + ADC=AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0 + CCP=CCP:RC2 + PWM=PWM:RC2 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:0 + END=MCU + + BEGIN=MCU:18f2455,18f2458,18f2550,18f2553 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0 + CCP=CCP1:RC2,CCP2:RC1/RB3 + PWM=PWM1:RC2,PWM2:RC1/RB3 + I2C=SDA:RB0,SCL:RB1 + SPI=SDI:RB0,SDO:RC7,SCK:RB1,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:18f4455,18f4458,18f4550,18f4553 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2 + ADC=AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0 + CCP=CCP1:RC2,CCP2:RC1/RB3 + PWM=PWM1:RC2,PWM2:RC1/RB3 + I2C=SDA:RB0,SCL:RB1 + SPI=SDI:RB0,SDO:RC7,SCK:RB1,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:18f2480,18f2580,18f2585,18f2680,18f2682,18f2685 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN8:RB1,AN9:RB4,AN10:RB0 + CCP=CCP:RC2 + PWM=PWM:RC2 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:0 + END=MCU + + BEGIN=MCU:18f4480,18f4580,18f4585,18f4680,18f4682,18f4685 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2 + ADC=AN8:RB1,AN9:RB4,AN10:RB0 + CCP=CCP1:RC2,CCP2:RD4 + PWM=PWM1:RC2,PWM2:RD4 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:0 + END=MCU + + BEGIN=MCU:18f2525,18f2620 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0 + CCP=CCP1:RC2,CCP2:RC1/RB3 + PWM=PWM1:RC2,PWM2:RC1/RB3 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:18f4525,18f4620 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RE0,AN6:RE1,AN7:RE2 + ADC=AN8:RB2,AN9:RB3,AN10:RB1,AN11:RB4,AN12:RB0 + CCP=CCP1:RC2,CCP2:RC1/RB3 + PWM=PWM1:RC2,PWM2:RC1/RB3 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RA5 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:18f6310,18f6410 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN5:RF0,AN6:RF1,AN7:RF2,AN8:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + CCP=CCP1:RC2,CCP2:RC1/RE7,CCP3:RG0 + PWM=PWM1:RC2,PWM2:RC1/RE7,PWM3:RG0 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RF7 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RG2,TX2:RG1 + USART=IO_DIR=RX1:1,TX1:1,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f8310,18f8410 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN5:RF0,AN6:RF1,AN7:RF2,AN8:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + CCP=CCP1:RC2,CCP2:RC1/RB3/RE7,CCP3:RG0 + PWM=PWM1:RC2,PWM2:RC1/RB3/RE7,PWM3:RG0 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RF7 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RG2,TX2:RG1 + USART=IO_DIR=RX1:1,TX1:1,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f6390,18f6393,18f6490,18f6493 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN5:RF0,AN6:RF1,AN7:RF2,AN8:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + CCP=CCP1:RC2,CCP2:RC1/RE7 + PWM=PWM1:RC2,PWM2:RC1/RE7 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RF7 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RG2,TX2:RG1 + USART=IO_DIR=RX1:1,TX1:1,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f8390,18f8393,18f8490,18f8493 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN5:RF0,AN6:RF1,AN7:RF2,AN8:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + CCP=CCP1:RC2,CCP2:RC1/RE7 + PWM=PWM1:RC2,PWM2:RC1/RE7 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RF7 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RG2,TX2:RG1 + USART=IO_DIR=RX1:1,TX1:1,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f6520,18f6525,18f6620,18f6621,18f6720 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN5:RF0,AN6:RF1,AN7:RF2,AN8:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + CCP=CCP1:RC2,CCP2:RC1/RE7,CCP3:RG0,CCP4:RG3,CCP5:RG4 + PWM=PWM1:RC2,PWM2:RC1/RE7,PWM3:RG0,PWM4:RG3,PWM5:RG4 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RF7 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RG2,TX2:RG1 + USART=IO_DIR=RX1:1,TX1:0,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f8520,18f8525,18f8620,18f8621,18f8720 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN5:RF0,AN6:RF1,AN7:RF2,AN8:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + ADC=AN12:RH4,AN13:RH5,AN14:RH6,AN15:RH7 + CCP=CCP1:RC2,CCP2:RC1/RB3/RE7,CCP3:RG0,CCP4:RG3,CCP5:RG4 + PWM=PWM1:RC2,PWM2:RC1/RB3/RE7,PWM3:RG0,PWM4:RG3,PWM5:RG4 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RF7 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RG2,TX2:RG1 + USART=IO_DIR=RX1:1,TX1:0,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f6527,18f6622,18f6627,18f6628,18f6722,18f6723 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN5:RF0,AN6:RF1,AN7:RF2,AN8:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + CCP=CCP1:RC2,CCP2:RC1/RE7,CCP3:RG0,CCP4:RG3,CCP5:RG4 + PWM=PWM1:RC2,PWM2:RC1/RE7,PWM3:RG0,PWM4:RG3,PWM5:RG4 + I2C=SDA1:RC4,SCL1:RC3 + SPI=SDI1:RC4,SDO1:RC5,SCK1:RC3,SS1:RF7 + I2C=SDA2:RD5,SCL2:RD6 + SPI=SDI2:RD5,SDO2:RD4,SCK2:RD6,SS2:RD7 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RG2,TX2:RG1 + USART=IO_DIR=RX1:1,TX1:0,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f8527,18f8622,18f8627,18f8628,18f8722,18f8723 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN5:RF0,AN6:RF1,AN7:RF2,AN8:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + ADC=AN12:RH4,AN13:RH5,AN14:RH6,AN15:RH7 + CCP=CCP1:RC2,CCP2:RC1/RB3/RE7,CCP3:RG0,CCP4:RG3,CCP5:RG4 + PWM=PWM1:RC2,PWM2:RC1/RB3/RE7,PWM3:RG0,PWM4:RG3,PWM5:RG4 + I2C=SDA1:RC4,SCL1:RC3 + SPI=SDI1:RC4,SDO1:RC5,SCK1:RC3,SS1:RF7 + I2C=SDA2:RD5,SCL2:RD6 + SPI=SDI2:RD5,SDO2:RD4,SCK2:RD6,SS2:RD7 + USART=RX1:RC7,TX1:RC6 + USART=RX2:RG2,TX2:RG1 + USART=IO_DIR=RX1:1,TX1:0,RX2:1,TX2:0 + END=MCU + + BEGIN=MCU:18f6585,18f6680 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN5:RF0,AN6:RF1,AN7:RF2,AN8:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + CCP=CCP1:RC2,CCP2:RC1/RE7 + PWM=PWM1:RC2,PWM2:RC1/RE7 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RF7 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + + BEGIN=MCU:18f8585,18f8680 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5 + ADC=AN5:RF0,AN6:RF1,AN7:RF2,AN8:RF3,AN9:RF4,AN10:RF5,AN11:RF6 + ADC=AN12:RH4,AN13:RH5,AN14:RH6,AN15:RH7 + CCP=CCP1:RC2,CCP2:RC1/RB3/RE7 + PWM=PWM1:RC2,PWM2:RC1/RB3/RE7 + I2C=SDA:RC4,SCL:RC3 + SPI=SDI:RC4,SDO:RC5,SCK:RC3,SS:RF7 + USART=RX:RC7,TX:RC6 + USART=IO_DIR=RX:1,TX:1 + END=MCU + +# +# Remappable peripheral pins. (PPS) +# (The definition valid until a newer definition overwrites the members.) +# + BEGIN=DEFINE + RP0=RA0 + RP1=RA1 + RP2=RA2 + RP3=RA3 + RP4=RA4 + RP5=RA5 + RP6=RA6 + RP7=RB3 + RP8=RB0 + RP9=RB1 + RP10=RA7 + RP11=RC2 + RP12=RB4 + RP13=RB5 + RP14=RB2 + RP15=RC3 + RP16=RC5 + RP17=RC4 + RP18=RC6 + RP19=RC7 + RP20=RD0 + RP21=RD1 + RP22=RD2 + RP23=RD3 + RP24=RD4 + RP25=RD5 + RP26=RD6 + RP27=RD7 + RP28=RE0 + RP29=RE1 + RP30=RE2 + RP31=RE7 + RP32=RE4 + RP33=RE3 + RP34=RE6 + RP35=RF5 + RP36=RF2 + RP37=RE5 + RP38=RF7 + RP39=RG1 + RP40=RF6 + RP41=RF3 + RP42=RG2 + RP43=RG3 + RP44=RG4 + RP45=RF4 + RP46=RG0 + END=DEFINE + +# +# PPS-Lite +# + BEGIN=GROUP + RP_GROUP0=RP0,RP4,RP8,RP12,RP16,RP20,RP24,RP28,RP32,RP36,RP40,RP44 + RP_GROUP1=RP1,RP5,RP9,RP13,RP17,RP21,RP25,RP29,RP33,RP37,RP41,RP45 + RP_GROUP2=RP2,RP6,RP10,RP14,RP18,RP22,RP26,RP30,RP34,RP38,RP42,RP46 + RP_GROUP3=RP3,RP7,RP11,RP15,RP19,RP23,RP27,RP31,RP35,RP39,RP43 + END=GROUP + + BEGIN=MCU:18f65j94,18f66j94,18f66j99,18f67j94 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RF7,AN6:RA4 + ADC=AN7:RF2,AN8:RG0,AN9:RC2,AN10:RF5,AN11:RF6 + ADC=AN16:RG4,AN17:RG3,AN18:RG2,AN19:RG1 + CCP=CCP1:RP_GROUP3 + CCP=CCP2:RP_GROUP3 + CCP=CCP3:RP_GROUP2 + CCP=CCP4:RP_GROUP3 + CCP=CCP5:RP_GROUP0 + CCP=CCP6:RP_GROUP2 + CCP=CCP7:RP_GROUP1 + CCP=CCP8:RP_GROUP0 + CCP=CCP9:RP_GROUP1 + CCP=CCP10:RP_GROUP2 + PWM=PWM1:RP_GROUP3 + PWM=PWM2:RP_GROUP3 + PWM=PWM3:RP_GROUP2 + PWM=PWM4:RP_GROUP3 + PWM=PWM5:RP_GROUP0 + PWM=PWM6:RP_GROUP2 + PWM=PWM7:RP_GROUP1 + PWM=PWM8:RP_GROUP0 + PWM=PWM9:RP_GROUP1 + PWM=PWM10:RP_GROUP2 + I2C=SDA1:RC4,SCL1:RC3 + SPI=SDI1:RP_GROUP0,SDO1:RP_GROUP1,SCK1:RP_GROUP3,SS1:RP_GROUP2 + I2C=SDA2:RD5,SCL2:RD6 + SPI=SDI2:RP_GROUP1,SDO2:RP_GROUP0,SCK2:RP_GROUP2,SS2:RP_GROUP3 + USART=RX1:RP_GROUP3,TX1:RP_GROUP2 + USART=RX2:RP_GROUP2,TX2:RP_GROUP3 + USART=RX3:RP_GROUP0,TX3:RP_GROUP1 + USART=RX4:RP_GROUP0,TX4:RP_GROUP1 + USART=IO_DIR=RX1:1,TX1:1,RX2:1,TX2:1,RX3:1,TX3:1,RX4:1,TX4:1 + END=MCU + + BEGIN=MCU:18f85j94,18f86j94,18f86j99,18f87j94 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RF7,AN6:RA4 + ADC=AN7:RF2,AN8:RG0,AN9:RC2,AN10:RF5,AN11:RF6 + ADC=AN16:RG4,AN17:RG3,AN18:RG2,AN19:RG1 + ADC=AN12:RH4,AN13:RH5,AN14:RH6,AN15:RH7 + ADC=AN20:RH3,AN21:RH2,AN22:RH1,AN23:RH0 + CCP=CCP1:RP_GROUP3 + CCP=CCP2:RP_GROUP3 + CCP=CCP3:RP_GROUP2 + CCP=CCP4:RP_GROUP3 + CCP=CCP5:RP_GROUP0 + CCP=CCP6:RP_GROUP2 + CCP=CCP7:RP_GROUP1 + CCP=CCP8:RP_GROUP0 + CCP=CCP9:RP_GROUP1 + CCP=CCP10:RP_GROUP2 + PWM=PWM1:RP_GROUP3 + PWM=PWM2:RP_GROUP3 + PWM=PWM3:RP_GROUP2 + PWM=PWM4:RP_GROUP3 + PWM=PWM5:RP_GROUP0 + PWM=PWM6:RP_GROUP2 + PWM=PWM7:RP_GROUP1 + PWM=PWM8:RP_GROUP0 + PWM=PWM9:RP_GROUP1 + PWM=PWM10:RP_GROUP2 + I2C=SDA1:RC4,SCL1:RC3 + SPI=SDI1:RP_GROUP0,SDO1:RP_GROUP1,SCK1:RP_GROUP3,SS1:RP_GROUP2 + I2C=SDA2:RD5,SCL2:RD6 + SPI=SDI2:RP_GROUP1,SDO2:RP_GROUP0,SCK2:RP_GROUP2,SS2:RP_GROUP3 + USART=RX1:RP_GROUP3,TX1:RP_GROUP2 + USART=RX2:RP_GROUP2,TX2:RP_GROUP3 + USART=RX3:RP_GROUP0,TX3:RP_GROUP1 + USART=RX4:RP_GROUP0,TX4:RP_GROUP1 + USART=IO_DIR=RX1:1,TX1:1,RX2:1,TX2:1,RX3:1,TX3:1,RX4:1,TX4:1 + END=MCU + + BEGIN=MCU:18f95j94,18f96j94,18f96j99,18f97j94 + ADC=AN0:RA0,AN1:RA1,AN2:RA2,AN3:RA3,AN4:RA5,AN5:RF7,AN6:RA4 + ADC=AN7:RF2,AN8:RG0,AN9:RC2,AN10:RF5,AN11:RF6 + ADC=AN16:RG4,AN17:RG3,AN18:RG2,AN19:RG1 + ADC=AN12:RH4,AN13:RH5,AN14:RH6,AN15:RH7 + ADC=AN20:RH3,AN21:RH2,AN22:RH1,AN23:RH0 + CCP=CCP1:RP_GROUP3 + CCP=CCP2:RP_GROUP3 + CCP=CCP3:RP_GROUP2 + CCP=CCP4:RP_GROUP3 + CCP=CCP5:RP_GROUP0 + CCP=CCP6:RP_GROUP2 + CCP=CCP7:RP_GROUP1 + CCP=CCP8:RP_GROUP0 + CCP=CCP9:RP_GROUP1 + CCP=CCP10:RP_GROUP2 + PWM=PWM1:RP_GROUP3 + PWM=PWM2:RP_GROUP3 + PWM=PWM3:RP_GROUP2 + PWM=PWM4:RP_GROUP3 + PWM=PWM5:RP_GROUP0 + PWM=PWM6:RP_GROUP2 + PWM=PWM7:RP_GROUP1 + PWM=PWM8:RP_GROUP0 + PWM=PWM9:RP_GROUP1 + PWM=PWM10:RP_GROUP2 + I2C=SDA1:RC4,SCL1:RC3 + SPI=SDI1:RP_GROUP0,SDO1:RP_GROUP1,SCK1:RP_GROUP3,SS1:RP_GROUP2 + I2C=SDA2:RD5,SCL2:RD6 + SPI=SDI2:RP_GROUP1,SDO2:RP_GROUP0,SCK2:RP_GROUP2,SS2:RP_GROUP3 + USART=RX1:RP_GROUP3,TX1:RP_GROUP2 + USART=RX2:RP_GROUP2,TX2:RP_GROUP3 + USART=RX3:RP_GROUP0,TX3:RP_GROUP1 + USART=RX4:RP_GROUP0,TX4:RP_GROUP1 + USART=IO_DIR=RX1:1,TX1:1,RX2:1,TX2:1,RX3:1,TX3:1,RX4:1,TX4:1 + END=MCU + +END=IO_TABLE diff --git a/support/scripts/pic16_update_xinst.sh b/support/scripts/pic16_update_xinst.sh new file mode 100644 index 0000000..c8d883d --- /dev/null +++ b/support/scripts/pic16_update_xinst.sh @@ -0,0 +1,54 @@ +#!/bin/sh + +GPUTILS="$1"; +PIC16DEVICES="${2:-pic16devices.txt}"; + +usage() +{ + echo "Usage: $0 path-to-gputils-sources name-of-pic16devices.txt"; + echo ""; + exit 1; +} + +if [ ! -f "$GPUTILS/libgputils/gpprocessor.c" ]; then + echo "$GPUTILS/libgputils/gpprocessor.c not found."; + usage; +fi; + +if [ ! -f "$PIC16DEVICES" ]; then + echo "$PIC16DEVICES not found."; + usage; +fi; + +BASE=$(readlink -f $(dirname "$0")); +SEDSCRIPT="update_xinst.sed"; +FULL="${PIC16DEVICES}-full"; +OUTPUT="${PIC16DEVICES}-xinst"; + +grep 'PROC_CLASS_PIC16' "$1/libgputils/gpprocessor.c" \ + | sed -e '/"p1\w*"/ { s/^.*"p\(1\w*\)".*,\s*\([01]\)\s*}[^}]*$/\1 \2/; p }; d' \ + | while read p xinst; do \ + printf '/name\s*'"$p"'\s*$/ {a\\\nXINST '"$xinst"'\n}\n'; \ + done > "$SEDSCRIPT"; +perl "$BASE/optimize_pic16devices.pl" -u "$PIC16DEVICES" | \ + grep -v '^XINST\s*[01]\s*$' | \ + sed -f "$SEDSCRIPT" > "$FULL"; +rm -f "$SEDSCRIPT"; +perl "$BASE/optimize_pic16devices.pl" -o "$FULL" > "$OUTPUT"; +rm -f "$FULL"; +if diff -up "$PIC16DEVICES" "$OUTPUT"; then + echo "No update required."; + rm -f "$OUTPUT"; +else + echo "Update $PIC16DEVICES from $OUTPUT [y/N]? "; + read answer; + case ${answer:-n} in + y|Y|y*|Y*) + echo "Updating ..."; + mv "$OUTPUT" "$PIC16DEVICES"; + ;; + *) + echo "Not updating."; + ;; + esac; +fi; diff --git a/support/scripts/pic16fam-h-gen.pl b/support/scripts/pic16fam-h-gen.pl new file mode 100755 index 0000000..2fe6794 --- /dev/null +++ b/support/scripts/pic16fam-h-gen.pl @@ -0,0 +1,880 @@ +#!/usr/bin/perl -w + +=back + + This script generates a C header file that maps the target device (as + indicated via the sdcc generated -Dpic16cxxx or -Dpic12fxxx or -Dpic16fxxx + macro) to its device family and the device families to their respective + style of ADC, USART and SSP programming for use in the SDCC PIC14 I/O library. + + Copyright 2010 Raphael Neider <rneider AT web.de> + PIC14 port: + Copyright 2012-2014 Molnar Karoly <molnarkaroly@users.sf.net> + + This file is part of SDCC. + + SDCC is free software: you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation, either version 2 of the License, or (at your + option) any later version. + + SDCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with SDCC. If not, see <http://www.gnu.org/licenses/>. + + Usage: perl pic16fam-h-gen.pl [-i|-p|-h] + + This will create pic16fam.h.gen in your current directory. + Check sanity of the file and move it to .../include/pic14/pic16fam.h. + If you assigned new I/O styles, implement them in + .../include/pic14/{adc,i2c,pwm,spi,usart}.h and + .../lib/pic14/libio/*/*.c + + $Id: pic16fam-h-gen.pl 9072 2014-09-17 14:00:11Z molnarkaroly $ +=cut + + +use strict; +use warnings; +no if $] >= 5.018, warnings => "experimental::smartmatch"; # perl 5.16 +use 5.10.1; +use feature 'switch'; # Starting from 5.10.1. + +use constant FALSE => 0; +use constant TRUE => 1; + +use constant SECT_NONE => 0; +use constant SECT_REG => 1; +use constant SECT_ENH => 2; +use constant SECT_PER => 3; + +my $head = '__SDCC_PIC'; + +my $gen_ignore_lists = FALSE; +my $gen_mcu_lists = FALSE; + +my @regular_mcu = (); +my @enhanced_mcu = (); + +my %peripherals_by_names = (); +my $actual_peripheral; + +my $section; + +my $line; + +my $tail = '.gen'; +my $update = 'Please update your pic14/pic16fam.h manually and/or inform the maintainer.'; + +my $fname; + +#------------------------------------------------------------------------------- + +sub align($$) + { + my $Text = $_[0]; + my $al = $_[1] - length($Text); + + # One space will surely becomes behind it. + $al = 1 if ($al < 1); + + return ($Text . (' ' x $al)); + } + +#------------------------------------------------------------------------------- + +sub find_in_supported($$) + { + my ($Hash, $Name) = @_; + + for (keys %{$Hash}) + { + return TRUE if ($_ > 0 && $Name ~~ @{${$Hash}{$_}}); + } + + return FALSE; + } + +#------------------------------------------------------------------------------- + +=back + This procedure give a list (id=0) to the peripherals, in which are + included the not supported devices. +=cut + +sub create_ignore_lists() + { + my @full_mcu_list = (@regular_mcu, @enhanced_mcu); + + foreach (keys %peripherals_by_names) + { + my $peri = $peripherals_by_names{$_}; + my @ignore_list = (); + + foreach (@full_mcu_list) + { + push(@ignore_list, $_) if (! find_in_supported($peri, $_) && ! ($_ ~~ @ignore_list)); + } + + @{${$peri}{0}} = @ignore_list; + } + } + +#------------------------------------------------------------------------------- + +sub smartCompare($$) + { + my ($Str1, $Str2) = @_; + + if (${$Str1} =~ /^\d/o && ${$Str2} =~ /^\d/o) + { + # $Str1 number and $Str2 number + return (int(${$Str1}) <=> int(${$Str2})); + } + + return (${$Str1} cmp ${$Str2}); + } + +#------------------------------------------------------------------------------- + +sub smartSort + { + my @a_s = ($a =~ /(\d+|\D+)/go); + my @b_s = ($b =~ /(\d+|\D+)/go); + my ($i, $k, $end, $ret); + + $i = scalar(@a_s); + $k = scalar(@b_s); + + if ($i < $k) + { + $end = $i; + $ret = -1; + } + elsif ($i == $k) + { + $end = $i; + $ret = 0; + } + else + { + $end = $k; + $ret = 1; + } + + for ($i = 0; $i < $end; ++$i) + { + $k = smartCompare(\$a_s[$i], \$b_s[$i]); + + return $k if ($k != 0); + } + + return $ret; + } + +#------------------------------------------------------------------------------- + +sub collector($) + { + my $id; + my @fields = split(':', $line); + + die "Invalid record: >$line<" if (@fields != 2); + + $id = int($fields[0]); + push(@{${$_[0]}{$id}}, map { uc($_); } split(',', $fields[1])) if ($id > 0); + } + +#------------------------------------------------------------------------------- + +=back + Creates the ignore files of peripherals from the ignore lists. +=cut + +sub generate_ignore_files() + { + foreach (keys %peripherals_by_names) + { + $fname = "$_.ignore$tail"; + open(FH, '>', $fname) or die "Could not open: \"$fname\""; + print FH join("\n", map { lc($_); } sort smartSort @{${$peripherals_by_names{$_}}{0}}) . "\n"; + close(FH); + } + } + +#------------------------------------------------------------------------------- + +=back + Creates the lists of MCUs. +=cut + +sub generate_mcu_files() + { + $fname = "mcu.regular$tail"; + open(FH, '>', $fname) or die "Could not open: \"$fname\""; + print FH join("\n", map { lc($_); } sort smartSort @regular_mcu) . "\n"; + close(FH); + + $fname = "mcu.enhanced$tail"; + open(FH, '>', $fname) or die "Could not open: \"$fname\""; + print FH join("\n", map { lc($_); } sort smartSort @enhanced_mcu) . "\n"; + close(FH); + } + +#------------------------------------------------------------------------------- + +sub print_peripheral($) + { + my $Name = $_[0]; + my $array = $peripherals_by_names{$_}; + my $def = align("#define __SDCC_${Name}_STYLE", 30); + my $cpp; + + print FH <<EOT +/* + * Define $Name style per device family. + */ +#undef __SDCC_${Name}_STYLE + +EOT +; + $cpp = '#if '; + foreach (sort keys %{$array}) + { + my $fams = "defined($head" . join(") || \\\n defined($head", sort smartSort @{$array->{$_}}) . ')'; + + print FH "$cpp$fams\n$def$_\n\n"; + $cpp = '#elif '; + } + + print FH <<EOT +#else +#warning No $Name style associated with the target device. +#warning $update +#endif + +EOT +; + } + +#------------------------------------------------------------------------------- + +for (my $i = 0; $i < @ARGV; ) + { + my $opt = $ARGV[$i++]; + + given ($opt) + { + when (/^-(i|-gen-ignore)$/o) + { + # This command creates the PERIPHERAL.ignore.gen files. + $gen_ignore_lists = TRUE; + } + + when (/^-(p|-gen-processor-lists)$/o) + { + # This command creates the mcu.{enhanced,regular}.gen files. + $gen_mcu_lists = TRUE; + } + + when (/^-(ip|pi)$/o) + { + # This command creates the PERIPHERAL.ignore.gen and + # the mcu.{enhanced,regular}.gen files. + $gen_ignore_lists = TRUE; + $gen_mcu_lists = TRUE; + } + + when (/^-(h|-help)$/o) + { + print <<EOT +Usage: $0 [options] + + Options are: + -i or --gen-ignore + This command creates the PERIPHERAL.ignore$tail files. + + -p or --gen-processor-lists + This command creates the mcu.{enhanced,regular}$tail files. + + -h or --help + This text. +EOT +; + exit(0); + } + } # given ($opt) + } + +$section = SECT_NONE; + + # While reading skips the blank or comment lines. +foreach (grep(! /^\s*$|^\s*#/o, <DATA>)) + { + chomp; + s/\s*//go; # strip whitespace + + $line = $_; + + if ($line =~ /^SECTION=(\S+)$/o) + { + given ($1) + { + when ('REGULAR') { $section = SECT_REG; } + when ('ENHANCED') { $section = SECT_ENH; } + + default + { + my $name = uc($1); + + die "The $name peripheral already exist!" if (defined($peripherals_by_names{$name})); + + $actual_peripheral = {}; + $peripherals_by_names{$name} = $actual_peripheral; + $section = SECT_PER; + } + } + + next; + } + + given ($section) + { + when (SECT_REG) + { + push(@regular_mcu, map { uc($_); } split(',', $line)); + } + + when (SECT_ENH) + { + push(@enhanced_mcu, map { uc($_); } split(',', $line)); + } + + when (SECT_PER) + { + collector($actual_peripheral); + } + } + } # foreach (grep(! /^\s*$|^\s*#/o, <DATA>)) + +create_ignore_lists(); + +generate_ignore_files() if ($gen_ignore_lists); +generate_mcu_files() if ($gen_mcu_lists); + +$fname = "pic16fam.h$tail"; +open(FH, '>', $fname) or die "Could not open: \"$fname\""; + +print FH <<EOT +/* + * pic16fam.h - PIC14 families + * + * This file is has been generated using $0 . + */ +#ifndef __SDCC_PIC16FAM_H__ +#define __SDCC_PIC16FAM_H__ 1 + +/* + * Define device class. + */ +#undef __SDCC_PIC14_ENHANCED + +EOT +; + +my $memb = "defined($head" . join(") || \\\n defined($head", sort smartSort @enhanced_mcu) . ')'; +print FH <<EOT +#if $memb +#define __SDCC_PIC14_ENHANCED 1 + +#endif + +EOT +; + +foreach (sort smartSort keys %peripherals_by_names) + { + print_peripheral($_); + } + +print FH "#endif /* !__SDCC_PIC16FAM_H__ */\n"; + +close(FH); + +__END__ +################################################################################ +# +# This list contains the names of the regular devices. +# (Of course only them which are the sdcc also know.) +# + + SECTION=REGULAR + +10f320,10f322,12f609,12f615,12f617,12f629,12f635,12f675,12f683,12f752 +16c62,16c63a,16c65b,16c71,16c72,16c73b,16c74b,16c432,16c433,16c554 +16c557,16c558,16c620,16c620a,16c621,16c621a,16c622,16c622a,16c710,16c711 +16c715,16c717,16c745,16c765,16c770,16c771,16c773,16c774,16c781,16c782 +16c925,16c926,16f72,16f73,16f74,16f76,16f77,16f84,16f84a,16f87 +16f88,16f610,16f616,16f627,16f627a,16f628,16f628a,16f630,16f631,16f636 +16f639,16f648a,16f676,16f677,16f684,16f685,16f687,16f688,16f689,16f690 +16f707,16f716,16f720,16f721,16f722,16f722a,16f723,16f723a,16f724,16f726 +16f727,16f737,16f747,16f753,16f767,16f777,16f785,16f818,16f819,16f870 +16f871,16f872,16f873,16f873a,16f874,16f874a,16f876,16f876a,16f877,16f877a +16f882,16f883,16f884,16f886,16f887,16f913,16f914,16f916,16f917,16f946 +16hv616,16hv753 + +################################################################################ +# +# This list in turn exclusively contains the names of the enhanced devices. +# (Only them which are the sdcc also know.) +# + + SECTION=ENHANCED + +12f1501,12f1571,12f1572,12f1612,12f1822,12f1840,12lf1552,16f1454,16f1455,16f1458 +16f1459,16f1503,16f1507,16f1508,16f1509,16f1512,16f1513,16f1516,16f1517,16f1518 +16f1519,16f1526,16f1527,16f1613,16f1703,16f1704,16f1705,16f1707,16f1708,16f1709 +16f1713,16f1716,16f1717,16f1718,16f1719,16f1782,16f1783,16f1784,16f1786,16f1787 +16f1788,16f1789,16f1823,16f1824,16f1825,16f1826,16f1827,16f1828,16f1829,16f1847 +16f1933,16f1934,16f1936,16f1937,16f1938,16f1939,16f1946,16f1947,16lf1554,16lf1559 +16lf1704,16lf1708,16lf1902,16lf1903,16lf1904,16lf1906,16lf1907 + +################################################################################ +# +# <id>:<head>{,<member>} +# +# Each line provides a colon separated list of +# +# * a numeric family name, derived from the first family member as follows: +# +# ADC : <num1>(c|f|hv|lf)<num2>.? -> printf("%u%04u1", <num1>, <num2>) +# CCP : <num1>(c|f|hv|lf)<num2>.? -> printf("%u%04u2", <num1>, <num2>) +# PWM : <num1>(c|f|hv|lf)<num2>.? -> printf("%u%04u3", <num1>, <num2>) +# I2C : <num1>(c|f|hv|lf)<num2>.? -> printf("%u%04u4", <num1>, <num2>) +# SPI : <num1>(c|f|hv|lf)<num2>.? -> printf("%u%04u5", <num1>, <num2>) +# USART : <num1>(c|f|hv|lf)<num2>.? -> printf("%u%04u6", <num1>, <num2>) +# +# * a comma-separated list of members of a device family. +# +# The rules basis of which members of a family belong together: +# +# a.) The connectors of peripheral are located on the same pin. +# +# b.) In the periphery - in context with other peripherals - should be +# used in the same way. (Pin relocation. Other peripheral to use +# the same pin? Peripheral initialization. ...) +# +# This data has been gathered manually from data sheets published by +# Microchip Technology Inc. +# + + SECTION=ADC + +10032001:10f320,10f322 +12061501:12f615 +12061701:12f617 +12067501:12f675 +12068301:12f683 +12075201:12f752 +12150101:12f1501 +12157101:12f1571 +12157201:12f1572 +12161201:12f1612 +12182201:12f1822 +12155201:12lf1552 +16007100:16c71,16c710,16c711 +16007200:16c72,16f72 +16007300:16c73b,16c74b,16c745,16c765,16f73,16f76 +16043300:16c433 +16071500:16c715 +16071700:16c717,16c770,16c771 +16077300:16c773 +16077400:16c774 +16078100:16c781,16c782 +16092500:16c925,16c926,16f872 +16007401:16f74,16f77 +16008801:16f88 +16061601:16f616,16hv616 +16067601:16f676,16f684 +16067701:16f677,16f685 +16068701:16f687,16f689,16f690 +16068801:16f688 +16070701:16f707 +16071601:16f716 +16072001:16f720,16f721 +16072201:16f722,16f722a,16f723,16f723a,16f726 +16072401:16f724,16f727 +16073701:16f737,16f767 +16074701:16f747,16f777 +16075301:16f753,16hv753 +16078501:16f785 +16081801:16f818,16f819 +16087001:16f870,16f873,16f876 +16087101:16f871,16f874,16f877 +16087301:16f873a,16f876a +16087401:16f874a,16f877a +16088201:16f882,16f883,16f886 +16088401:16f884,16f887 +16091301:16f913,16f916 +16091401:16f914,16f917,16f946 +16145501:16f1455 +16145901:16f1459 +16150301:16f1503 +16150701:16f1507 +16150801:16f1508,16f1509 +16151201:16f1512,16f1513 +16151601:16f1516,16f1518 +16151701:16f1517,16f1519 +16152601:16f1526,16f1527 +16161301:16f1613 +16170301:16f1703 +16170401:16f1704,16f1705,16lf1704 +16170701:16f1707 +16170801:16f1708,16lf1708 +16170901:16f1709 +16171301:16f1713,16f1716,16f1718 +16171701:16f1717,16f1719 +16178201:16f1782,16f1783 +16178401:16f1784,16f1787 +16178601:16f1786 +16178801:16f1788 +16178901:16f1789 +16182301:16f1823 +16182401:16f1824,16f1825 +16182601:16f1826,16f1827,16f1847 +16182801:16f1828,16f1829 +16193301:16f1933,16f1936,16f1938 +16193401:16f1934,16f1937,16f1939 +16194601:16f1946,16f1947 +16155401:16lf1554 +16155901:16lf1559 +16190201:16lf1902,16lf1903 +16190401:16lf1904,16lf1907 +16190601:16lf1906 + + SECTION=CCP + +12061511:12f615 +12061711:12f617 +12068311:12f683 +12075211:12f752 +12161211:12f1612 +12182211:12f1822 +16006210:16c62 +16006310:16c63a,16c65b +16007210:16c72,16f72 +16007310:16c73b,16c74b,16f73,16f74,16f76,16f77 +16071710:16c717,16c770,16c771 +16074510:16c745,16c765 +16077310:16c773,16c774 +16092510:16c925,16c926,16f872 +16008711:16f87 +16008811:16f88 +16061611:16f616,16hv616 +16062711:16f627,16f627a,16f628,16f628a,16f648a +16068411:16f684 +16068511:16f685 +16068711:16f687,16f689 +16069011:16f690 +16070711:16f707 +16071611:16f716 +16072011:16f720,16f721 +16072211:16f722,16f722a,16f723,16f723a,16f726 +16072411:16f724,16f727 +16073711:16f737,16f747,16f767,16f777 +16075311:16f753,16hv753 +16078511:16f785 +16081811:16f818,16f819 +16087011:16f870,16f871 +16087311:16f873,16f874,16f876,16f877 +16087311:16f873a,16f874a,16f876a,16f877a +16088211:16f882,16f883,16f886 +16088411:16f884,16f887 +16091311:16f913,16f916 +16091411:16f914,16f917,16f946 +16151211:16f1512,16f1513,16f1516,16f1518 +16151711:16f1517,16f1519 +16152611:16f1526,16f1527 +16161311:16f1613 +16170311:16f1703 +16170411:16f1704,16f1705,16lf1704 +16170711:16f1707 +16170811:16f1708,16lf1708 +16170911:16f1709 +16171311:16f1713,16f1716,16f1718 +16171711:16f1717,16f1719 +16178211:16f1782,16f1783 +16178411:16f1784,16f1787 +16178611:16f1786 +16178811:16f1788 +16178911:16f1789 +16182311:16f1823 +16182411:16f1824 +16182511:16f1825 +16182611:16f1826 +16182711:16f1827,16f1847 +16182811:16f1828 +16182911:16f1829 +16193311:16f1933,16f1936,16f1938 +16193411:16f1934,16f1937,16f1939 +16194611:16f1946,16f1947 + + SECTION=PWM + +10032021:10f320,10f322 +12061521:12f615 +12061721:12f617 +12068321:12f683 +12075221:12f752 +12150121:12f1501 +12157121:12f1571 +12157221:12f1572 +12161221:12f1612 +12182221:12f1822 +16006220:16c62 +16006320:16c63a,16c65b +16007220:16c72,16f72 +16007320:16c73b,16c74b,16f73,16f74,16f76,16f77 +16071720:16c717,16c770,16c771 +16074520:16c745,16c765 +16077320:16c773,16c774 +16092520:16c925,16c926,16f872 +16008721:16f87 +16008821:16f88 +16061621:16f616,16hv616 +16062721:16f627,16f627a,16f628,16f628a,16f648a +16068421:16f684 +16068521:16f685 +16068721:16f687,16f689 +16069021:16f690 +16070721:16f707 +16071621:16f716 +16072021:16f720,16f721 +16072221:16f722,16f722a,16f723,16f723a,16f726 +16072421:16f724,16f727 +16073721:16f737,16f747,16f767,16f777 +16075321:16f753,16hv753 +16078521:16f785 +16081821:16f818,16f819 +16087021:16f870,16f871 +16087321:16f873,16f874,16f876,16f877 +16087321:16f873a,16f874a,16f876a,16f877a +16088221:16f882,16f883,16f886 +16088421:16f884,16f887 +16091321:16f913,16f916 +16091421:16f914,16f917,16f946 +16145421:16f1454 +16145521:16f1455 +16145921:16f1459 +16150321:16f1503 +16150721:16f1507 +16150821:16f1508,16f1509 +16151221:16f1512,16f1513,16f1516,16f1518 +16151721:16f1517,16f1519 +16161321:16f1613 +16170321:16f1703 +16170421:16f1704,16f1705,16lf1704 +16170721:16f1707 +16170821:16f1708,16lf1708 +16170921:16f1709 +16171321:16f1713,16f1716,16f1718 +16171721:16f1717,16f1719 +16178221:16f1782,16f1783 +16178421:16f1784,16f1787 +16178621:16f1786 +16178821:16f1788 +16178921:16f1789 +16182321:16f1823 +16182421:16f1824 +16182521:16f1825 +16182621:16f1826 +16182721:16f1827,16f1847 +16182821:16f1828 +16182921:16f1829 +16193321:16f1933,16f1936,16f1938 +16193421:16f1934,16f1937,16f1939 +16194621:16f1946,16f1947 +16155421:16lf1554 +16155921:16lf1559 + + SECTION=I2C + +12182231:12f1822 +12155231:12lf1552 +16006230:16c62 +16006330:16c63a,16c65b +16007230:16c72 +16007330:16c73b,16c74b,16f73,16f74,16f76,16f77 +16071730:16c717,16c770,16c771 +16077330:16c773,16c774 +16092530:16c925,16c926 +16007231:16f72 +16008731:16f87 +16008831:16f88 +16067731:16f677 +16068731:16f687,16f689,16f690 +16070731:16f707 +16072031:16f720,16f721 +16072231:16f722,16f722a,16f723,16f723a,16f726 +16072431:16f724,16f727 +16073731:16f737,16f747,16f767,16f777 +16081831:16f818,16f819 +16087231:16f872 +16087331:16f873,16f874,16f876,16f877 +16087331:16f873a,16f874a,16f876a,16f877a +16088231:16f882,16f883,16f886 +16088431:16f884,16f887 +16091331:16f913,16f916 +16091431:16f914,16f917,16f946 +16145431:16f1454 +16145531:16f1455 +16145931:16f1459 +16150331:16f1503 +16150831:16f1508,16f1509 +16151231:16f1512,16f1513,16f1516,16f1518 +16151731:16f1517,16f1519 +16152631:16f1526,16f1527 +16170331:16f1703 +16170431:16f1704,16f1705,16lf1704 +16170731:16f1707 +16170831:16f1708,16lf1708 +16170931:16f1709 +16171331:16f1713,16f1716,16f1718 +16171731:16f1717,16f1719 +16178231:16f1782,16f1783 +16178431:16f1784,16f1787 +16178631:16f1786 +16178831:16f1788 +16178931:16f1789 +16182331:16f1823 +16182431:16f1824 +16182531:16f1825 +16182631:16f1826 +16182731:16f1827,16f1847 +16182831:16f1828 +16182931:16f1829 +16193331:16f1933,16f1936,16f1938 +16193431:16f1934,16f1937,16f1939 +16194631:16f1946,16f1947 +16155431:16lf1554 +16155931:16lf1559 + + SECTION=SPI + +12182241:12f1822 +12155241:12lf1552 +16006240:16c62 +16006340:16c63a,16c65b +16007240:16c72 +16007340:16c73b,16c74b,16f73,16f74,16f76,16f77 +16071740:16c717,16c770,16c771 +16077340:16c773,16c774 +16092540:16c925,16c926 +16007241:16f72 +16008741:16f87 +16008841:16f88 +16067741:16f677 +16068741:16f687,16f689,16f690 +16070741:16f707 +16072041:16f720,16f721 +16072241:16f722,16f722a,16f723,16f723a,16f726 +16072441:16f724,16f727 +16073741:16f737,16f747,16f767,16f777 +16081841:16f818,16f819 +16087241:16f872 +16087341:16f873,16f874,16f876,16f877 +16087341:16f873a,16f874a,16f876a,16f877a +16088241:16f882,16f883,16f886 +16088441:16f884,16f887 +16091341:16f913,16f916 +16091441:16f914,16f917,16f946 +16145441:16f1454 +16145541:16f1455 +16145941:16f1459 +16150341:16f1503 +16150841:16f1508,16f1509 +16151241:16f1512,16f1513,16f1516,16f1518 +16151741:16f1517,16f1519 +16152641:16f1526,16f1527 +16170341:16f1703 +16170441:16f1704,16f1705,16lf1704 +16170741:16f1707 +16170841:16f1708,16lf1708 +16170941:16f1709 +16171341:16f1713,16f1716,16f1718 +16171741:16f1717,16f1719 +16178241:16f1782,16f1783 +16178441:16f1784,16f1787 +16178641:16f1786 +16178841:16f1788 +16178941:16f1789 +16182341:16f1823 +16182441:16f1824 +16182541:16f1825 +16182641:16f1826 +16182741:16f1827,16f1847 +16182841:16f1828 +16182941:16f1829 +16193341:16f1933,16f1936,16f1938 +16193441:16f1934,16f1937,16f1939 +16194641:16f1946,16f1947 +16155441:16lf1554 +16155941:16lf1559 + + SECTION=USART + +12157251:12f1572 +12182251:12f1822 +16006350:16c63a,16c65b +16007350:16c73b,16c74b,16c745,16c765,16f73,16f74,16f76,16f77 +16077350:16c773,16c774 +16008751:16f87 +16008851:16f88 +16062751:16f627,16f627a,16f628,16f628a,16f648a +16068751:16f687,16f689,16f690 +16068851:16f688 +16070751:16f707 +16072051:16f720,16f721 +16072251:16f722,16f722a,16f723,16f723a,16f726 +16072451:16f724,16f727 +16073751:16f737,16f747,16f767,16f777 +16087051:16f870,16f871,16f873,16f874,16f876,16f877 +16087351:16f873a,16f874a,16f876a,16f877a +16088251:16f882,16f883,16f886 +16088451:16f884,16f887 +16091351:16f913,16f916 +16091451:16f914,16f917,16f946 +16145451:16f1454 +16145551:16f1455 +16145951:16f1459 +16150851:16f1508,16f1509 +16151251:16f1512,16f1513,16f1516,16f1518 +16151751:16f1517,16f1519 +16152651:16f1526,16f1527 +16170451:16f1704,16f1705,16lf1704 +16170851:16f1708,16lf1708 +16170951:16f1709 +16171351:16f1713,16f1716,16f1718 +16171751:16f1717,16f1719 +16178251:16f1782,16f1783 +16178451:16f1784,16f1787 +16178651:16f1786 +16178851:16f1788 +16178951:16f1789 +16182351:16f1823 +16182451:16f1824 +16182551:16f1825 +16182651:16f1826,16f1827,16f1847 +16182851:16f1828 +16182951:16f1829 +16193351:16f1933,16f1936,16f1938 +16193451:16f1934,16f1937,16f1939 +16194651:16f1946,16f1947 +16155451:16lf1554 +16155951:16lf1559 +16190451:16lf1904,16lf1907 +16190651:16lf1906 diff --git a/support/scripts/pic18fam-h-gen.pl b/support/scripts/pic18fam-h-gen.pl new file mode 100644 index 0000000..0cd640d --- /dev/null +++ b/support/scripts/pic18fam-h-gen.pl @@ -0,0 +1,214 @@ +#!/usr/bin/perl -w + +# +# This script generates a C header file that maps the target device (as +# indicated via the sdcc generated -Dpic18fxxx macro) to its device +# family and the device families to their respective style of ADC and +# USART programming for use in the SDCC PIC16 I/O library. +# +# Copyright 2010 Raphael Neider <rneider AT web.de> +# +# This file is part of SDCC. +# +# SDCC is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 2 of the License, or (at your +# option) any later version. +# +# SDCC is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with SDCC. If not, see <http://www.gnu.org/licenses/>. +# + +# +# Usage: perl pic18fam-h-gen.pl +# +# This will create pic18fam.h.gen in your current directory. +# Check sanity of the file and move it to .../include/pic16/pic18fam.h. +# If you assigned new I/O styles, implement them in +# .../include/pic16/{adc,i2c,usart}.h and +# .../lib/pic16/libio/*/*.c +# + +use strict; + +my $head = '__SDCC_PIC'; + +my %families = (); +my %adc = (); +my %usart = (); +my $update = "Please update your pic16/pic18fam.h manually and/or inform the maintainer."; + +while (<DATA>) { + chomp; + s/\s*#.*$//; # remove comments + s/\s*//g; # strip whitespace + next if (/^\s*$/); # ignore empty lines + + my $line = $_; + + my @fields = split(/:/, $line); + + die "Invalid record >$line<" if (4 != scalar @fields); + + my ($id, $memberlist, $adcstyle, $usartstyle) = @fields; + + # extract numeric family id + $id = 0+$id; + + # extract family members + my @arr = split(/,/, $memberlist); + @arr = sort(map { uc($_); } @arr); + $families{$id} = \@arr; + + # ADC style per device family + $adcstyle = 0+$adcstyle; + if (not defined $adc{$adcstyle}) { + $adc{$adcstyle} = []; + } # if + push @{$adc{$adcstyle}}, $id; + + # (E)USART style per device family + $usartstyle = 0+$usartstyle; + if (not defined $usart{$usartstyle}) { + $usart{$usartstyle} = []; + } # if + push @{$usart{$usartstyle}}, $id; +} + +my $fname = "pic18fam.h.gen"; +open(FH, ">", "$fname") or die "Could not open >$fname<"; + +print FH <<EOT +/* + * pic18fam.h - PIC16 families + * + * This file is has been generated using $0 . + */ +#ifndef __SDCC_PIC18FAM_H__ +#define __SDCC_PIC18FAM_H__ 1 + +/* + * Define device families. + */ +#undef __SDCC_PIC16_FAMILY + +EOT +; +my $pp = "#if "; +for my $id (sort keys %families) { + my $list = $families{$id}; + my $memb = "defined($head" . join(") \\\n || defined($head", @$list) . ")"; + print FH <<EOT +${pp} ${memb} +#define __SDCC_PIC16_FAMILY ${id} + +EOT +; + $pp = "#elif "; +} # for +print FH <<EOT +#else +#warning No family associated with the target device. ${update} +#endif + +/* + * Define ADC style per device family. + */ +#undef __SDCC_ADC_STYLE + +EOT +; +$pp = "#if "; +for my $s (sort keys %adc) { + my $fams = join (" \\\n || ", map { "(__SDCC_PIC16_FAMILY == $_)" } sort @{$adc{$s}}); + print FH <<EOT +${pp} ${fams} +#define __SDCC_ADC_STYLE ${s} + +EOT +; + $pp = "#elif "; +} # for +print FH <<EOT +#else +#warning No ADC style associated with the target device. ${update} +#endif + +/* + * Define (E)USART style per device family. + */ +#undef __SDCC_USART_STYLE + +EOT +; +$pp = "#if "; +for my $s (sort keys %usart) { + my $fams = join (" \\\n || ", map { "(__SDCC_PIC16_FAMILY == $_)" } sort @{$usart{$s}}); + print FH <<EOT +${pp} ${fams} +#define __SDCC_USART_STYLE ${s} + +EOT +; + $pp = "#elif "; +} # for +print FH <<EOT +#else +#warning No (E)USART style associated with the target device. ${update} +#endif + +EOT +; + +print FH <<EOT +#endif /* !__SDCC_PIC18FAM_H__ */ +EOT +; +__END__ +# +# <id>:<head>{,<member>}:<adc>:<usart> +# +# Each line provides a colon separated list of +# * a numeric family name, derived from the first family member as follows: +# - 18F<num> -> printf("18%04d0", <num>) +# - 18F<num1>J<num2> -> printf("18%02d%02d1", <num1>, <num2>) +# - 18F<num1>K<num2> -> printf("18%02d%02d2", <num1>, <num2>) +# * a comma-separated list of members of a device family, +# where a family comprises all devices that share a single data sheet, +# * the ADC style (numeric family name or 0, if not applicable) +# * the USART style (numeric family name or 0, if not applicable) +# +# This data has been gathered manually from data sheets published by +# Microchip Technology Inc. +# +1812200:18f1220,18f1320:1812200:1812200 +1812300:18f1230,18f1330:1812300:1812300 +1813502:18f13k50,18f14k50:1813502:1813502 +1822200:18f2220,18f2320,18f4220,18f4320:1822200:1822200 +1822210:18f2221,18f2321,18f4221,18f4321:1822200:1822210 +1823310:18f2331,18f2431,18f4331,18f4431:0:1822210 +1823202:18f23k20,18f24k20,18f25k20,18f26k20,18f43k20,18f44k20,18f45k20,18f46k20:1822200:1822210 +1823222:18f23k22,18f24k22,18f25k22,18f26k22,18f43k22,18f44k22,18f45k22,18f46k22:1823222:1822210 +1824100:18f2410,18f2510,18f2515,18f2610,18f4410,18f4510,18f4515,18f4610:1822200:1822210 +1802420:18f242,18f252,18f442,18f452:1802420:1822200 # TODO: verify family members and USART +1824200:18f2420,18f2520,18f4420,18f4520:1822200:1822210 +1824230:18f2423,18f2523,18f4423,18f4523:1822200:1822210 +1824500:18f2450,18f4450:1822200:1824500 +1824550:18f2455,18f2550,18f4455,18f4550:1822200:1822210 +1802480:18f248,18f258,18f448,18f458:1802420:1822200 # TODO: verify family members and USART +1824800:18f2480,18f2580,18f4480,18f4580:1822200:1824500 +1824101:18f24j10,18f25j10,18f44j10,18f45j10:1822200:1822210 +1824501:18f24j50,18f25j50,18f26j50,18f44j50,18f45j50,18f46j50:1824501:1824501 +1825250:18f2525,18f2620,18f4525,18f4620:1822200:1822210 +1825850:18f2585,18f2680,18f4585,18f4680:1822200:1824500 +1826820:18f2682,18f2685,18f4682,18f4685:1822200:1824500 +1865200:18f6520,18f6620,18f6720,18f8520,18f8620,18f8720:1822200:1865200 +1865270:18f6527,18f6622,18f6627,18f6722,18f8527,18f8622,18f8627,18f8722:1822200:1824501 +1865850:18f6585,18f6680,18f8585,18f8680:1822200:1865850 +1865501:18f65j50,18f66j50,18f66j55,18f67j50,18f85j50,18f86j50,18f86j55,18f87j50:1865501:1824501 +1866601:18f66j60,18f66j65,18f67j60,18f86j60,18f86j65,18f87j60,18f96j60,18f96j65,18f97j60:1822200:1824501 diff --git a/support/scripts/repack_release.sh b/support/scripts/repack_release.sh new file mode 100755 index 0000000..43ec868 --- /dev/null +++ b/support/scripts/repack_release.sh @@ -0,0 +1,299 @@ +#! /bin/bash + +# repack_release.sh - repack sdcc Linux, Mac OS X and Windows +# snapshot build source, binary and doc packages into a sdcc +# release package. +# +# Copyright (c) 2009-2012 Borut Razem +# +# This file is part of SDCC. +# +# This software is provided 'as-is', without any express or implied +# warranty. In no event will the authors be held liable for any damages +# arising from the use of this software. +# +# Permission is granted to anyone to use this software for any purpose, +# including commercial applications, and to alter it and redistribute it +# freely, subject to the following restrictions: +# +# 1. The origin of this software must not be misrepresented; you must not +# claim that you wrote the original software. If you use this software +# in a product, an acknowledgment in the product documentation would be +# appreciated but is not required. +# 2. Altered source versions must be plainly marked as such, and must not be +# misrepresented as being the original software. +# 3. This notice may not be removed or altered from any source distribution. +# +# Borut Razem +# borut.razem@gmail.com + +# Example: +# ./repack_release.sh -dl -pr -ul 20090314 5413 2.9.0-rc1 + + +# Uncomment next line to debug this script +#set -vx + +function fatal_error() +{ + echo "repack_release: $1" 1>&2 + exit 1; +} + + +function usage() +{ + echo "Usage: repack_release.sh [-h] [--help] [-dl] [-pr] [-ul] <date> <revision> <version>" 1>&2 + echo "Repack sdcc Linux, Mac OS X and Windows snapshot build source," 1>&2 + echo "binary and doc packages into a sdcc release package." 1>&2 + echo "Options:" 1>&2 + echo " -dl download before processing" 1>&2 + echo " -pr process packages" 1>&2 + echo " -ul upload after processing" 1>&2 + echo " <none> download, process and upload" 1>&2 + echo " -h --help print this usage and exit" 1>&2 + echo "Arguments:" 1>&2 + echo " <date> package date in YYYMMDD format, for example 20090314" 1>&2 + echo " <revision> svn revision number, for example 5413" 1>&2 + echo " <version> package version number, for example 2.9.0-rc1" 1>&2 + exit 1; +} + + +function download() +{ + local date=$1 revision=$2 + + mkdir -p dl + + if ! pushd dl + then + fatal_error "Cannot cd to dl!" + else + ( \ + wget https://sourceforge.net/projects/sdcc/files/snapshot_builds/sdcc-src/sdcc-src-${date}-${revision}.tar.bz2 && \ + wget https://sourceforge.net/projects/sdcc/files/snapshot_builds/docs/sdcc-doc-${date}-${revision}.tar.bz2 && \ + wget https://sourceforge.net/projects/sdcc/files/snapshot_builds/docs/sdcc-doc-${date}-${revision}.zip && \ +# wget http://sourceforge.net/projects/sdcc/files/snapshot_builds/i386-unknown-linux2.5/sdcc-snapshot-i386-unknown-linux2.5-${date}-${revision}.tar.bz2 && \ + wget https://sourceforge.net/projects/sdcc/files/snapshot_builds/amd64-unknown-linux2.5/sdcc-snapshot-amd64-unknown-linux2.5-${date}-${revision}.tar.bz2 && \ + wget https://sourceforge.net/projects/sdcc/files/snapshot_builds/i586-mingw32msvc/sdcc-snapshot-i586-mingw32msvc-${date}-${revision}.zip && \ + wget https://sourceforge.net/projects/sdcc/files/snapshot_builds/x86_64-w64-mingw32/sdcc-snapshot-x86_64-w64-mingw32-${date}-${revision}.zip && \ + wget https://sourceforge.net/projects/sdcc/files/snapshot_builds/x86_64-apple-macosx/sdcc-snapshot-x86_64-apple-macosx-${date}-${revision}.tar.bz2 \ + ) || fatal_error "Cannot download snapshot build packages!" + +# a rename is required when another snapshot is taken as the source for the release +# mv sdcc-snapshot-i386_universal-apple-macosx-${date}-${revision}.tar.bz2 sdcc-snapshot-universal-apple-macosx-${date}-${revision}.tar.bz2 + + popd + fi +} + + +function unpack() +{ + local bin_pkg=$1 doc_pkg=$2 + + if [ -z "$(expr $(basename $bin_pkg) : 'sdcc-snapshot-\([^-]*-[^-]*-[^-]*\)-.*\.tar\.bz2')" ] + then + fatal_error "$bin_pkg is not a sdcc binary package!" + fi + + if [ -d sdcc ] + then + fatal_error "Directory sdcc already exists!" + fi + + tar -xjvf ${bin_pkg} || fatal_error "Cannot unpack $bin_pkg!" + + # remove unneeded directories produced by sdbinutils + rm -rf ./sdcc/include + rm -rf ./sdcc/lib + + rm -rf ./sdcc/share/doc + rm -rf ./sdcc/share/sdcc/doc + + tar -xjvf ${doc_pkg} -C ./sdcc/share/sdcc || fatal_error "Cannot unpack $doc_pkg!" +} + + +function pack() +{ + local arch=$1 ver=$2 + + cp ./sdcc/share/sdcc/doc/INSTALL.txt ./sdcc + cp ./sdcc/share/sdcc/doc/README.txt ./sdcc + + mkdir -p ul + + mv sdcc sdcc-${ver} + tar -cjvf ul/sdcc-${ver}-${arch}.tar.bz2 sdcc-${ver} || fatal_error "Cannot pack ul/sdcc-${ver}-${arch}.tar.bz2!" + mv sdcc-${ver} ${arch} +} + + +function repack_src() +{ + local date=$1 revision=$2 ver=$3 + + ( \ + tar -xjvf dl/sdcc-src-${date}-${revision}.tar.bz2 && \ + mv sdcc sdcc-${ver} && \ + tar -cjvf ul/sdcc-src-${ver}.tar.bz2 sdcc-${ver} && \ + mv sdcc-${ver} sdcc-src-${ver} \ + ) || fatal_error "Cannot repack the source package!" +} + + +function repack_win() +{ + local date=$1 revision=$2 ver=$3 arch=$4 + + snapshot=../sdcc-src-${ver} + ver_maj=$(expr $ver : '\([0-9]*\)\.') + ver_min=$(expr $ver : '[0-9]*\.\([0-9]*\)\.') + ver_rev=$(expr $ver : '[0-9]*\.[0-9]*\.\([0-9]*\)') + + if [[ ${arch} == *64* ]] + then + win="-DWIN64" + setup="x64-setup" + else + win= + setup="setup" + fi + + # - unpack WIN32 mingw daily snapshot sdcc-snapshot-i586-mingw32msvc-yyyymmdd-rrrr.zip + # to a clean directory (the option to create directories should be enabled). + # A sub directory sdcc is created (referenced as PKGDIR in continuation). + unzip dl/sdcc-snapshot-${arch}-${date}-${revision}.zip + + if ! pushd sdcc + then + fatal_error "Cannot cd to sdcc!" + else + # - remove the PKGDIR/doc/ directory + rm -rf doc/ + + # - unpack sdcc-doc-yyyymmdd-rrrr.zip to the PKGDIR/doc directory + unzip ../dl/sdcc-doc-${date}-${revision}.zip + + # - copy files sdcc/support/scripts/sdcc.ico and sdcc/support/scripts/sdcc.nsi + # (this file) from the sdcc Subversion snapshot to the PKGDIR directory + cp ${snapshot}/support/scripts/sdcc.nsi ${snapshot}/support/scripts/sdcc.ico . + + # - copy file COPYING and COPYING3 from the sdcc Subversion snapshot to the PKGDIR directory, + # rename it to COPYING.txt and COPYING3.txt and convert it to DOS format: + cp ${snapshot}/COPYING COPYING.txt + todos COPYING.txt + cp ${snapshot}/sdas/COPYING3 COPYING3.txt + todos COPYING3.txt + cp ${snapshot}/ChangeLog doc/ChangeLog.txt + todos doc/ChangeLog.txt + cp ${snapshot}/doc/README.txt doc/README.txt + todos doc/README.txt + + # - run NSIS installer from PKGDIR directory: + # Define -DWIN64 if creating a 64bit package. + makensis -DFULL_DOC -DVER_MAJOR=${ver_maj} -DVER_MINOR=${ver_min} -DVER_REVISION=${ver_rev} -DVER_BUILD=${revision} ${win} sdcc.nsi + + # - A setup file setup.exe is created in PKGDIR directory. + # Rename it to sdcc-x.x.x-setup.exe and upload it + # to sdcc download repository at sourceforge.net + cp setup.exe ../ul/sdcc-${ver}-${setup}.exe + + popd + + mv sdcc ${arch} + fi +} + + +function upload() +{ + local ver=$1 user=$2 + + raw_ver=$(expr $ver : '\([0-9]*\.[0-9]*\.[0-9]*\)') + + echo uploading ul/sdcc-src-${ver}.tar.bz2 ${user}@web.sourceforge.net:/home/pfs/project/sdcc/sdcc/${raw_ver}/ + rsync -v --progress -e ssh ul/sdcc-src-${ver}.tar.bz2 ${user}@web.sourceforge.net:/home/pfs/project/sdcc/sdcc/${raw_ver}/ + + echo uploading ul/sdcc-doc-${ver}.tar.bz2 ${user}@web.sourceforge.net:/home/pfs/project/sdcc/sdcc-doc/${raw_ver}/ + rsync -v --progress -e ssh ul/sdcc-doc-${ver}.tar.bz2 ${user}@web.sourceforge.net:/home/pfs/project/sdcc/sdcc-doc/${raw_ver}/ + + echo uploading ul/sdcc-doc-${ver}.zip ${user}@web.sourceforge.net:/home/pfs/project/sdcc/sdcc-doc/${raw_ver}/ + rsync -v --progress -e ssh ul/sdcc-doc-${ver}.zip ${user}@web.sourceforge.net:/home/pfs/project/sdcc/sdcc-doc/${raw_ver}/ + + echo uploading ul/sdcc-${ver}-setup.exe ${user}@web.sourceforge.net:/home/pfs/project/sdcc/sdcc-win32/${raw_ver}/ + rsync -v --progress -e ssh ul/sdcc-${ver}-setup.exe ${user}@web.sourceforge.net:/home/pfs/project/sdcc/sdcc-win32/${raw_ver}/ + + echo uploading ul/sdcc-${ver}-x64-setup.exe ${user}@web.sourceforge.net:/home/pfs/project/sdcc/sdcc-win64/${raw_ver}/ + rsync -v --progress -e ssh ul/sdcc-${ver}-x64-setup.exe ${user}@web.sourceforge.net:/home/pfs/project/sdcc/sdcc-win64/${raw_ver}/ + +# echo uploading ul/sdcc-${ver}-i386-unknown-linux2.5.tar.bz2 ${user}@web.sourceforge.net:/home/pfs/project/sdcc/sdcc-linux-x86/${raw_ver}/ +# rsync -v --progress -e ssh ul/sdcc-${ver}-i386-unknown-linux2.5.tar.bz2 ${user}@web.sourceforge.net:/home/pfs/project/sdcc/sdcc-linux-x86/${raw_ver}/ + + echo uploading ul/sdcc-${ver}-amd64-unknown-linux2.5.tar.bz2 ${user}@web.sourceforge.net:/home/pfs/project/sdcc/sdcc-linux-amd64/${raw_ver}/ + rsync -v --progress -e ssh ul/sdcc-${ver}-amd64-unknown-linux2.5.tar.bz2 ${user}@web.sourceforge.net:/home/pfs/project/sdcc/sdcc-linux-amd64/${raw_ver}/ + + echo uploading ul/sdcc-${ver}-x86_64-apple-macosx.tar.bz2 ${user}@web.sourceforge.net:/home/pfs/project/sdcc/sdcc-macosx-amd64/${raw_ver}/ + rsync -v --progress -e ssh ul/sdcc-${ver}-x86_64-apple-macosx.tar.bz2 ${user}@web.sourceforge.net:/home/pfs/project/sdcc/sdcc-macosx-amd64/${raw_ver}/ +} + + +# main procedure +{ + while [ -n "$1" ] + do + case "$1" + in + -dl) dl=1; has_opts=1; shift;; + -pr) pr=1; has_opts=1; shift;; + -ul) ul=1; has_opts=1; shift;; + -h|--help) usage; exit 0;; + -*) echo "Unknown option $arg!"; usage; exit 1;; + *) break;; + esac + done + + if [ $# != 3 ] + then + usage + fi + + test -z "$has_opts" && dl=1 && pr=1 && ul=1 + + date=$1 + revision=$2 + ver=$3 + + mkdir -p ul + + # download the snapshots + test -n "$dl" && download ${date} ${revision} + + if [ -n "$pr" ] + then + # repack the sources + repack_src ${date} ${revision} ${ver} + + # repack the documentation + cp dl/sdcc-doc-${date}-${revision}.tar.bz2 ul/sdcc-doc-${ver}.tar.bz2 + cp dl/sdcc-doc-${date}-${revision}.zip ul/sdcc-doc-${ver}.zip + + # repack the *nix-like binaries + for arch in amd64-unknown-linux2.5 x86_64-apple-macosx + do + unpack dl/sdcc-snapshot-${arch}-${date}-${revision}.tar.bz2 dl/sdcc-doc-${date}-${revision}.tar.bz2 + pack ${arch} ${ver} + done + + # repack the windows binaries + repack_win ${date} ${revision} ${ver} i586-mingw32msvc + repack_win ${date} ${revision} ${ver} x86_64-w64-mingw32 + fi + + # upload the release packages + test -n "$ul" && upload ${ver} sdcc-builder + + exit 0 +} diff --git a/support/scripts/resource.h b/support/scripts/resource.h new file mode 100644 index 0000000..c19c0c0 --- /dev/null +++ b/support/scripts/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by resource.rc +// +#define IDI_SDCC 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/support/scripts/resource.rc b/support/scripts/resource.rc new file mode 100644 index 0000000..a06dc3e --- /dev/null +++ b/support/scripts/resource.rc @@ -0,0 +1,121 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#ifdef HAVE_CONFIG_H +# include "config.h" +#elif defined(_WIN32) && !defined(__MINGW32__) +# include "sdcc_vc.h" +#else +# include "sdccconf.h" +#endif + +#include "src/version.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winresrc.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""winresrc.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION SDCC_VERSION_HI,SDCC_VERSION_LO,SDCC_VERSION_P,SDCC_BUILD_NR + PRODUCTVERSION SDCC_VERSION_HI,SDCC_VERSION_LO,SDCC_VERSION_P,SDCC_BUILD_NR + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "http://sdcc.sourceforge.net/" + VALUE "CompanyName", "SDCC" + VALUE "FileDescription", "Small Device C Compiler" + VALUE "FileVersion", SDCC_VERSION_STR "." SDCC_BUILD_NUMBER + VALUE "InternalName", "sdcc" + VALUE "LegalCopyright", "Copyright (C) 1995-2011, License GPL" + VALUE "License", "GNU Public License (GPL)" + VALUE "OriginalFilename", "sdcc.exe" + VALUE "ProductName", "Small Device C Compiler" + VALUE "ProductVersion", SDCC_VERSION_STR "." SDCC_BUILD_NUMBER + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_SDCC ICON DISCARDABLE "sdcc.ico" +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/support/scripts/sdcc.ico b/support/scripts/sdcc.ico Binary files differnew file mode 100644 index 0000000..316ee32 --- /dev/null +++ b/support/scripts/sdcc.ico diff --git a/support/scripts/sdcc.nsi b/support/scripts/sdcc.nsi new file mode 100644 index 0000000..aca83a8 --- /dev/null +++ b/support/scripts/sdcc.nsi @@ -0,0 +1,1583 @@ +# sdcc.nsi - NSIS installer script for SDCC +# +# Copyright (c) 2003-2013 Borut Razem +# +# This file is part of sdcc. +# +# This software is provided 'as-is', without any express or implied +# warranty. In no event will the authors be held liable for any damages +# arising from the use of this software. +# +# Permission is granted to anyone to use this software for any purpose, +# including commercial applications, and to alter it and redistribute it +# freely, subject to the following restrictions: +# +# 1. The origin of this software must not be misrepresented; you must not +# claim that you wrote the original software. If you use this software +# in a product, an acknowledgment in the product documentation would be +# appreciated but is not required. +# 2. Altered source versions must be plainly marked as such, and must not be +# misrepresented as being the original software. +# 3. This notice may not be removed or altered from any source distribution. +# +# Borut Razem +# borut.razem@siol.net + +# How to create WIN32 setup.exe +# +# - unpack WIN32 mingw daily snapshot sdcc-snapshot-i586-mingw32msvc-yyyymmdd-rrrr.zip +# to a clean directory (the option to create directories should be enabled). +# A sub directory sdcc is created (referenced as PKGDIR in continuation). +# - copy files sdcc/support/scripts/sdcc.ico and sdcc/support/scripts/sdcc.nsi +# (this file) from the sdcc Subversion snapshot to the PKGDIR directory +# - copy file COPYING and COPYING3 from the sdcc Subversion snapshot to the PKGDIR directory, +# rename it to COPYING.txt and COPYING3.txt and convert it to DOS format: +# unix2dos COPYING.txt +# unix2dos COPYING3.txt +# unix2dos doc/ChangeLog_head.txt +# unix2dos doc/README.TXT +# - run NSIS installer from PKGDIR directory: +# "c:\Program Files\NSIS\makensis.exe" -DVER_MAJOR=<SDCC_VER_MAJOR> -DVER_MINOR=<SDCC_VER_MINOR> -DVER_REVISION=<SDCC_VER_DEVEL> -DVER_BUILD=<SDCC_REVISION> sdcc.nsi +# replace <VER_XXX> with the appropriate values, for example for SDCC 2.7.4: +# <SDCC_VER_MAJOR> = 2 +# <SDCC_VER_MINOR> = 7 +# <SDCC_VER_DEVEL> = 4 +# replace <SDCC_REVISION> with the current svn revision number. +# Define -DWIN64 if createing a 64bit package. +# - A setup file setup.exe is created in PKGDIR directory. +# Rename it to sdcc-yyyymmdd-rrrr-setup.exe and upload it +# to sdcc download repository at sourceforge.net +# +# +# How to create WIN32 release setup.exe package +# +# - unpack WIN32 mingw daily snapshot sdcc-snapshot-i586-mingw32msvc-yyyymmdd-rrrr.zip +# to a clean directory (the option to create directories should be enabled). +# A sub directory sdcc is created (referenced as PKGDIR in continuation). +# - remove the PKGDIR/doc/ directory +# - unpack sdcc-doc-yyyymmdd-rrrr.zip to the PKGDIR/doc directory +# - copy files sdcc/support/scripts/sdcc.ico and sdcc/support/scripts/sdcc.nsi +# (this file) from the sdcc Subversion snapshot to the PKGDIR directory +# - copy file COPYING and COPYING3 from the sdcc Subversion snapshot to the PKGDIR directory, +# rename it to COPYING.txt and COPYING3.txt and convert it to DOS format: +# unix2dos COPYING.txt +# unix2dos COPYING3.txt +# unix2dos doc/ChangeLog.txt +# unix2dos doc/README.TXT +# - run NSIS installer from PKGDIR directory: +# "c:\Program Files\NSIS\makensis.exe" -DFULL_DOC -DVER_MAJOR=<VER_MAJOR> -DVER_MINOR=<VER_MINOR> -DVER_REVISION=<VER_PATCH> -DVER_BUILD=<REVISION> sdcc.nsi +# replace <VER_XXX> with the appropriate values, for example for SDCC 3.0.0: +# <SDCC_VER_MAJOR> = 3 +# <SDCC_VER_MINOR> = 0 +# <SDCC_VER_DEVEL> = 0 +# replace <SDCC_REVISION> with the current svn revision number. +# Define -DWIN64 if createing a 64bit package. +# - A setup file setup.exe is created in PKGDIR directory. +# Rename it to sdcc-x.x.x-setup.exe and upload it +# to sdcc download repository at sourceforge.net +# +# For debugging define -DSDCC.DEBUG command line option + +;-------------------------------- +; Debugging Macros + +!ifdef SDCC.DEBUG + Var SDCC.FunctionName + Var SDCC.StrStack0 + Var SDCC.StrStack1 + Var SDCC.StrStack2 + Var SDCC.StrStack3 + Var SDCC.StrStack4 + +!define SDCC.PushStr "!insertmacro MACRO_SDCC_PushStr" +!macro MACRO_SDCC_PushStr NAME + StrCpy $SDCC.StrStack4 $SDCC.StrStack3 + StrCpy $SDCC.StrStack3 $SDCC.StrStack2 + StrCpy $SDCC.StrStack2 $SDCC.StrStack1 + StrCpy $SDCC.StrStack1 $SDCC.StrStack0 + StrCpy $SDCC.StrStack0 $SDCC.FunctionName + StrCpy $SDCC.FunctionName "${NAME}" +!macroend + +!define SDCC.PopStr "!insertmacro MACRO_SDCC_PopStr" +!macro MACRO_SDCC_PopStr + StrCpy $SDCC.FunctionName $SDCC.StrStack0 + StrCpy $SDCC.StrStack0 $SDCC.StrStack1 + StrCpy $SDCC.StrStack1 $SDCC.StrStack2 + StrCpy $SDCC.StrStack2 $SDCC.StrStack3 + StrCpy $SDCC.StrStack3 $SDCC.StrStack4 +!macroend +!endif + +!define DebugMsg "!insertmacro MACRO_SDCC_DebugMsg" +!macro MACRO_SDCC_DebugMsg MSG + !ifdef SDCC.DEBUG + MessageBox MB_OK "*** $SDCC.FunctionName: ${MSG} ***" + !endif +!macroend + +!define Function "!insertmacro MACRO_SDCC_Function" +!macro MACRO_SDCC_Function NAME + Function "${NAME}" + !ifdef SDCC.DEBUG + ${SDCC.PushStr} ${NAME} + !endif +!macroend + +!define FunctionEnd "!insertmacro MACRO_SDCC_FunctionEnd" +!macro MACRO_SDCC_FunctionEnd + !ifdef SDCC.DEBUG + ${SDCC.PopStr} + !endif + FunctionEnd +!macroend + +!define Section "!insertmacro MACRO_SDCC_Section" +!macro MACRO_SDCC_Section NAME ID + Section "${NAME}" "${ID}" + !ifdef SDCC.DEBUG + ${SDCC.PushStr} "${NAME}" + !endif +!macroend + +!define UnselectedSection "!insertmacro MACRO_SDCC_UnselectedSection" +!macro MACRO_SDCC_UnselectedSection NAME ID + Section /o ${NAME} ${ID} + !ifdef SDCC.DEBUG + ${SDCC.PushStr} "${NAME}" + !endif +!macroend + +!define SectionEnd "!insertmacro MACRO_SDCC_SectionEnd" +!macro MACRO_SDCC_SectionEnd + !ifdef SDCC.DEBUG + ${SDCC.PopStr} + !endif + SectionEnd +!macroend + + +!define PRODUCT_NAME "SDCC" + +; Version +!ifdef VER_MAJOR & VER_MINOR & VER_REVISION & VER_BUILD + !define PRODUCT_VERSION "${VER_MAJOR}.${VER_MINOR}.${VER_REVISION}" +!else + !define PRODUCT_VERSION "XX.XX" +!endif + +SetCompressor /SOLID lzma + +!define SDCC_ROOT "." + +!define DEV_ROOT "${SDCC_ROOT}" + +InstType "Full (Bin, ucSim, SDCDB, Doc, Lib, Src)" +InstType "Medium (Bin, ucSim, SDCDB, Doc, Lib)" +InstType "Compact (Bin, ucSim, SDCDB, Doc)" + +;-------------------------------- +; Configuration + +!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" +!define UNINST_ROOT_KEY HKLM +!define SDCC_ROOT_KEY HKLM + +;-------------------------------- +; Header Files + +!include MUI2.nsh +!include WordFunc.nsh +!include StrFunc.nsh +!include WinVer.nsh +!include x64.nsh +${StrStr} +${UnStrStr} + +;-------------------------------- +; Functions + +!ifdef VER_MAJOR & VER_MINOR & VER_REVISION & VER_BUILD + !insertmacro VersionCompare +!endif + +;-------------------------------- +; Variables + +Var SDCC.PathToRemove + +;-------------------------------- +; Configuration + +; MUI Settings +!define MUI_ABORTWARNING +!define MUI_ICON ".\sdcc.ico" + +; Welcome page +!define MUI_WELCOMEPAGE_TEXT "This wizard will guide you through the installation of $(^NameDA).$\r$\n$\r$\nIt is recommended that you close all other applications before starting Setup. This will make it possible to update relevant system files without having to reboot your computer.$\r$\n$\r$\n$_CLICK" +!insertmacro MUI_PAGE_WELCOME + +; License page +!insertmacro MUI_PAGE_LICENSE "${SDCC_ROOT}\COPYING.txt" + +; Uninstall/reinstall page +!ifdef VER_MAJOR & VER_MINOR & VER_REVISION & VER_BUILD +Page custom SDCC.PageReinstall SDCC.PageLeaveReinstall +!endif + +; StartMenu page +!define MUI_STARTMENUPAGE_DEFAULTFOLDER ${PRODUCT_NAME} +!define MUI_STARTMENUPAGE_REGISTRY_ROOT ${UNINST_ROOT_KEY} +!define MUI_STARTMENUPAGE_REGISTRY_KEY "${PRODUCT_UNINST_KEY}" +!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "NSIS:StartMenuDir" +!define MUI_STARTMENUPAGE_NODISABLE +Var MUI_STARTMENUPAGE_VARIABLE +!insertmacro MUI_PAGE_STARTMENU Application $MUI_STARTMENUPAGE_VARIABLE + +; Components page +!define MUI_COMPONENTSPAGE_SMALLDESC +!insertmacro MUI_PAGE_COMPONENTS + +; Directory page +!insertmacro MUI_PAGE_DIRECTORY + +; Instfiles page +!define MUI_PAGE_CUSTOMFUNCTION_LEAVE "SDCC.InstFilesLeave" +!insertmacro MUI_PAGE_INSTFILES + +${Function} SDCC.InstFilesLeave + ; Remove old path if reinstallation + ${If} $SDCC.PathToRemove != "" + ${DebugMsg} "removing path $SDCC.PathToRemove" + Push $SDCC.PathToRemove + Call SDCC.RemoveFromPath + ${EndIf} +${FunctionEnd} + +; Finish page - add to path +!define MUI_FINISHPAGE_TEXT "Confirm the checkbox if you want to add SDCC binary directory to the PATH environment variable" +!define MUI_FINISHPAGE_SHOWREADME_TEXT "Add $INSTDIR\bin to the PATH" +!define MUI_FINISHPAGE_SHOWREADME_FUNCTION SDCC.AddBinToPath +!define MUI_FINISHPAGE_SHOWREADME +!define MUI_FINISHPAGE_BUTTON "Next" +!insertmacro MUI_PAGE_FINISH + +; Finish page - reboot +!insertmacro MUI_PAGE_FINISH + +${Function} SDCC.AddBinToPath + ; Add new path + ${DebugMsg} "adding path $INSTDIR\bin" + Push "$INSTDIR\bin" + Call SDCC.AddToPath +${FunctionEnd} + +; Uninstaller pages +!insertmacro MUI_UNPAGE_CONFIRM +!insertmacro MUI_UNPAGE_INSTFILES +!insertmacro MUI_UNPAGE_FINISH + +; Language files +!insertmacro MUI_LANGUAGE "English" + +Name "${PRODUCT_NAME} ${PRODUCT_VERSION}" +BrandingText "" +OutFile "setup.exe" +RequestExecutionLevel admin ;Require admin rights on NT6+ (When UAC is turned on) +;;;;ShowInstDetails show +;;;;ShowUnInstDetails show + + +${Function} .onInit + ${DebugMsg} "Pre INSTDIR = $INSTDIR" + + ${If} ${RunningX64} + !ifdef WIN64 + StrCpy $INSTDIR "$PROGRAMFILES64\${PRODUCT_NAME}" + SetRegView 64 + !else + StrCpy $INSTDIR "$PROGRAMFILES\${PRODUCT_NAME}" + SetRegView 32 + !endif + ${Else} + !ifdef WIN64 + MessageBox MB_OK|MB_ICONSTOP \ + "This installation package is not supported on this platform. Contact your application vendor." + Abort + !endif + StrCpy $INSTDIR "$PROGRAMFILES\${PRODUCT_NAME}" + ${Endif} + +!ifndef VER_MAJOR & VER_MINOR & VER_REVISION & VER_BUILD + ; Old unistallation method + ; Uninstall the old version, if present + ReadRegStr $R0 ${UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" + ${If} $R0 != "" + MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION \ + "$(^Name) is already installed. $\n$\nClick 'OK' to remove the previous version or 'Cancel' to cancel this upgrade." \ + IDOK +2 + Abort + + ; Run the uninstaller + ClearErrors + ExecWait '$R0' + ${Else} + ; Install the new version + MessageBox MB_YESNO|MB_ICONQUESTION "This will install $(^Name). Do you wish to continue?" \ + IDYES +2 + Abort + ${Endif} +!else + ; If the registry key exists it is an uninstallation or reinstallation: + ; take the old installation directory + Push $R0 + + ReadRegStr $R0 ${UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "InstallLocation" + ${IfNot} ${Errors} + StrCpy $INSTDIR $R0 + StrCpy $SDCC.PathToRemove "$INSTDIR\bin" + ${EndIf} + + Pop $R0 +!endif + ${DebugMsg} "Post INSTDIR = $INSTDIR" +${FunctionEnd} + +${Function} un.onInit + ${DebugMsg} "Pre INSTDIR = $INSTDIR" + + ${If} ${RunningX64} + !ifdef WIN64 + SetRegView 64 + !else + SetRegView 32 + !endif + ${Endif} + + Push $R0 + ReadRegStr $R0 ${UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "InstallLocation" + ${IfNot} ${Errors} + StrCpy $INSTDIR $R0 + ${EndIf} + Pop $R0 + + ${DebugMsg} "Post INSTDIR = $INSTDIR" + +${FunctionEnd} + +${Section} -Common SECCOMMON + SetOutPath "$INSTDIR" + File ".\sdcc.ico" + File "${SDCC_ROOT}\COPYING.txt" + File "${SDCC_ROOT}\COPYING3.txt" +${SectionEnd} + +${Section} "SDCC application files" SEC01 + SectionIn 1 2 3 RO + SetOutPath "$INSTDIR\bin" + File "${SDCC_ROOT}\bin\sdasgb.exe" + File "${SDCC_ROOT}\bin\sdas6808.exe" + File "${SDCC_ROOT}\bin\sdasz80.exe" + File "${SDCC_ROOT}\bin\sdas8051.exe" + File "${SDCC_ROOT}\bin\sdas390.exe" + File "${SDCC_ROOT}\bin\sdasrab.exe" + File "${SDCC_ROOT}\bin\sdasstm8.exe" + File "${SDCC_ROOT}\bin\sdaspdk14.exe" + File "${SDCC_ROOT}\bin\sdaspdk15.exe" + File "${SDCC_ROOT}\bin\sdastlcs90.exe" + File "${SDCC_ROOT}\bin\sdld.exe" + File "${SDCC_ROOT}\bin\sdldgb.exe" + File "${SDCC_ROOT}\bin\sdld6808.exe" + File "${SDCC_ROOT}\bin\sdldz80.exe" + File "${SDCC_ROOT}\bin\sdldstm8.exe" + File "${SDCC_ROOT}\bin\sdldpdk.exe" + File "${SDCC_ROOT}\bin\sdar.exe" + File "${SDCC_ROOT}\bin\sdranlib.exe" + File "${SDCC_ROOT}\bin\sdnm.exe" + File "${SDCC_ROOT}\bin\sdobjcopy.exe" + File "${SDCC_ROOT}\bin\makebin.exe" + File "${SDCC_ROOT}\bin\packihx.exe" + File "${SDCC_ROOT}\bin\sdcc.exe" + File "${SDCC_ROOT}\bin\sdcpp.exe" + File "${SDCC_ROOT}\bin\as2gbmap.cmd" + File "${SDCC_ROOT}\bin\readline5.dll" +!ifdef WIN64 + File "${SDCC_ROOT}\bin\libgcc_s_*-1.dll" + File "${SDCC_ROOT}\bin\libstdc++-6.dll" + File "${SDCC_ROOT}\bin\libwinpthread-1.dll" +!endif +${SectionEnd} + +${Section} "ucSim application files" SEC02 + SectionIn 1 2 3 + SetOutPath "$INSTDIR\bin" + File "${SDCC_ROOT}\bin\s51.exe" + File "${SDCC_ROOT}\bin\shc08.exe" + File "${SDCC_ROOT}\bin\sz80.exe" + File "${SDCC_ROOT}\bin\sstm8.exe" +${SectionEnd} + +${Section} "SDCDB files" SEC03 + SectionIn 1 2 3 + File "${SDCC_ROOT}\bin\sdcdb.exe" + File "${SDCC_ROOT}\bin\sdcdb.el" + File "${SDCC_ROOT}\bin\sdcdbsrc.el" +${SectionEnd} + +${Section} "SDCC documentation" SEC04 + SectionIn 1 2 3 + SetOutPath "$INSTDIR\doc" +!ifdef FULL_DOC + File /r "${SDCC_ROOT}\doc\*" +!else + File "${SDCC_ROOT}\doc\ChangeLog_head.txt" + File "${SDCC_ROOT}\doc\README.TXT" +!endif +${SectionEnd} + +${Section} "SDCC include files" SEC05 + SectionIn 1 2 + SetOutPath "$INSTDIR\include\asm\default" + File "${DEV_ROOT}\include\asm\default\features.h" + SetOutPath "$INSTDIR\include\asm\ds390" + File "${DEV_ROOT}\include\asm\ds390\features.h" + SetOutPath "$INSTDIR\include\asm\gbz80" + File "${DEV_ROOT}\include\asm\gbz80\features.h" + SetOutPath "$INSTDIR\include\asm\mcs51" + File "${DEV_ROOT}\include\asm\mcs51\features.h" + SetOutPath "$INSTDIR\include\asm\pic14" + File "${DEV_ROOT}\include\asm\pic14\features.h" + SetOutPath "$INSTDIR\include\asm\pic16" + File "${DEV_ROOT}\include\asm\pic16\features.h" + SetOutPath "$INSTDIR\include\asm\z80" + File "${DEV_ROOT}\include\asm\z80\features.h" + SetOutPath "$INSTDIR\include\asm\z180" + File "${DEV_ROOT}\include\asm\z180\features.h" + SetOutPath "$INSTDIR\include\asm\r2k" + File "${DEV_ROOT}\include\asm\r2k\features.h" + SetOutPath "$INSTDIR\include\asm\r3ka" + File "${DEV_ROOT}\include\asm\r3ka\features.h" + SetOutPath "$INSTDIR\include\asm\ez80_z80" + File "${DEV_ROOT}\include\asm\ez80_z80\features.h" + SetOutPath "$INSTDIR\include\asm\stm8" + File "${DEV_ROOT}\include\asm\stm8\features.h" + + SetOutPath "$INSTDIR\include\ds390" + File "${DEV_ROOT}\include\ds390\*.h" + SetOutPath "$INSTDIR\include\ds400" + File "${DEV_ROOT}\include\ds400\*.h" + SetOutPath "$INSTDIR\include\hc08" + File "${DEV_ROOT}\include\hc08\*.h" + SetOutPath "$INSTDIR\include\mcs51" + File "${DEV_ROOT}\include\mcs51\*.h" + SetOutPath "$INSTDIR\include\pic14" + File "${DEV_ROOT}\include\pic14\*.h" + File "${DEV_ROOT}\include\pic14\*.txt" + File "${DEV_ROOT}\include\pic14\*.inc" + SetOutPath "$INSTDIR\include\pic16" + File "${DEV_ROOT}\include\pic16\*.h" + File "${DEV_ROOT}\include\pic16\*.txt" + SetOutPath "$INSTDIR\include\z180" + File "${DEV_ROOT}\include\z180\*.h" + + SetOutPath "$INSTDIR\include" + File "${DEV_ROOT}\include\*.h" + + SetOutPath "$INSTDIR\non-free\include\pic14" + File "${DEV_ROOT}\non-free\include\pic14\*.h" + SetOutPath "$INSTDIR\non-free\include\pic16" + File "${DEV_ROOT}\non-free\include\pic16\*.h" +${SectionEnd} + +${Section} "SDCC DS390 library" SEC06 + SectionIn 1 2 + SetOutPath "$INSTDIR\lib\ds390" + File "${DEV_ROOT}\lib\ds390\*.*" +${SectionEnd} + +${Section} "SDCC DS400 library" SEC07 + SectionIn 1 2 + SetOutPath "$INSTDIR\lib\ds400" + File "${DEV_ROOT}\lib\ds400\*.*" +${SectionEnd} + +${Section} "SDCC GBZ80 library" SEC08 + SectionIn 1 2 + SetOutPath "$INSTDIR\lib\gbz80" + File "${DEV_ROOT}\lib\gbz80\*.*" +${SectionEnd} + +${Section} "SDCC Z180 library" SEC09 + SectionIn 1 2 + SetOutPath "$INSTDIR\lib\z180" + File "${DEV_ROOT}\lib\z180\*.*" +${SectionEnd} + +${Section} "SDCC Rabbit 2000 library" SEC10 + SectionIn 1 2 + SetOutPath "$INSTDIR\lib\r2k" + File "${DEV_ROOT}\lib\r2k\*.*" +${SectionEnd} + +${Section} "SDCC Rabbit 3000A library" SEC11 + SectionIn 1 2 + SetOutPath "$INSTDIR\lib\r3ka" + File "${DEV_ROOT}\lib\r3ka\*.*" +${SectionEnd} + +${Section} "SDCC Z80 library" SEC12 + SectionIn 1 2 + SetOutPath "$INSTDIR\lib\z80" + File "${DEV_ROOT}\lib\z80\*.*" +${SectionEnd} + +${Section} "SDCC mcs51 small model library" SEC13 + SectionIn 1 2 + SetOutPath "$INSTDIR\lib\small" + File "${DEV_ROOT}\lib\small\*.*" +${SectionEnd} + +${Section} "SDCC mcs51 medium model library" SEC14 + SectionIn 1 2 + SetOutPath "$INSTDIR\lib\medium" + File "${DEV_ROOT}\lib\medium\*.*" +${SectionEnd} + +${Section} "SDCC mcs51 large model library" SEC15 + SectionIn 1 2 + SetOutPath "$INSTDIR\lib\large" + File "${DEV_ROOT}\lib\large\*.*" +${SectionEnd} + +${Section} "SDCC mcs51 huge model library" SEC16 + SectionIn 1 2 + SetOutPath "$INSTDIR\lib\huge" + File "${DEV_ROOT}\lib\huge\*.*" +${SectionEnd} + +${Section} "SDCC mcs51 small-stack-auto model library" SEC17 + SectionIn 1 2 + SetOutPath "$INSTDIR\lib\small-stack-auto" + File "${DEV_ROOT}\lib\small-stack-auto\*.*" +${SectionEnd} + +${Section} "SDCC mcs51 large-stack-auto model library" SEC18 + SectionIn 1 2 + SetOutPath "$INSTDIR\lib\large-stack-auto" + File "${DEV_ROOT}\lib\large-stack-auto\*.*" +${SectionEnd} + +${Section} "SDCC HC08 library" SEC19 + SectionIn 1 2 + SetOutPath "$INSTDIR\lib\hc08" + File "${DEV_ROOT}\lib\hc08\*.*" +${SectionEnd} + +${Section} "SDCC S08 library" SEC20 + SectionIn 1 2 + SetOutPath "$INSTDIR\lib\s08" + File "${DEV_ROOT}\lib\s08\*.*" +${SectionEnd} + +${Section} "SDCC PIC16 library" SEC21 + SectionIn 1 2 + SetOutPath "$INSTDIR\lib\pic16" + File "${DEV_ROOT}\lib\pic16\*.o" + File "${DEV_ROOT}\lib\pic16\*.lib" + + SetOutPath "$INSTDIR\non-free\lib\pic16" + File "${DEV_ROOT}\non-free\lib\pic16\*.lib" +${SectionEnd} + +${Section} "SDCC PIC14 library" SEC22 + SectionIn 1 2 + SetOutPath "$INSTDIR\lib\pic14" + File "${DEV_ROOT}\lib\pic14\*.lib" + + SetOutPath "$INSTDIR\non-free\lib\pic14" + File "${DEV_ROOT}\non-free\lib\pic14\*.lib" +${SectionEnd} + +${Section} "SDCC STM8 small model library" SEC23 + SectionIn 1 2 + SetOutPath "$INSTDIR\lib\stm8" + File "${DEV_ROOT}\lib\stm8\*.*" +${SectionEnd} + +${Section} "SDCC TLCS90 library" SEC24 + SectionIn 1 2 + SetOutPath "$INSTDIR\lib\tlcs90" + File "${DEV_ROOT}\lib\tlcs90\*.*" +${SectionEnd} + +${Section} "SDCC library sources" SEC25 + SectionIn 1 + SetOutPath "$INSTDIR\lib\src\ds390\examples" + File "${DEV_ROOT}\lib\src\ds390\examples\MOVED" + + SetOutPath "$INSTDIR\lib\src\ds390" + File "${DEV_ROOT}\lib\src\ds390\*.c" +# File "${DEV_ROOT}\lib\src\ds390\Makefile" + + SetOutPath "$INSTDIR\lib\src\ds400" + File "${DEV_ROOT}\lib\src\ds400\*.c" +# File "${DEV_ROOT}\lib\src\ds400\Makefile" + + SetOutPath "$INSTDIR\lib\src\gbz80" + File "${DEV_ROOT}\lib\src\gbz80\*.s" +# File "${DEV_ROOT}\lib\src\gbz80\Makefile" + + SetOutPath "$INSTDIR\lib\src\z80" + File "${DEV_ROOT}\lib\src\z80\*.s" +# File "${DEV_ROOT}\lib\src\z80\Makefile" + + SetOutPath "$INSTDIR\lib\src\z180" + File "${DEV_ROOT}\lib\src\z180\*.s" +# File "${DEV_ROOT}\lib\src\z180\Makefile" + + SetOutPath "$INSTDIR\lib\src\r2k" + File "${DEV_ROOT}\lib\src\r2k\*.s" +# File "${DEV_ROOT}\lib\src\z180\Makefile" + + SetOutPath "$INSTDIR\lib\src\r3ka" + File "${DEV_ROOT}\lib\src\r3ka\*.s" +# File "${DEV_ROOT}\lib\src\r3ka\Makefile" + + SetOutPath "$INSTDIR\lib\src\hc08" + File "${DEV_ROOT}\lib\src\hc08\*.c" +# File "${DEV_ROOT}\lib\src\hc08\Makefile" + + SetOutPath "$INSTDIR\lib\src\s08" + File "${DEV_ROOT}\lib\src\s08\*.c" +# File "${DEV_ROOT}\lib\src\s08\Makefile" + + SetOutPath "$INSTDIR\lib\src\stm8" +# File "${DEV_ROOT}\lib\src\stm8\Makefile" + + SetOutPath "$INSTDIR\lib\src\mcs51" + File "${DEV_ROOT}\lib\src\mcs51\*.asm" +# File "${DEV_ROOT}\lib\src\mcs51\Makefile" + + SetOutPath "$INSTDIR\lib\src\small" +# File "${DEV_ROOT}\lib\src\small\Makefile" + + SetOutPath "$INSTDIR\lib\src\medium" +# File "${DEV_ROOT}\lib\src\medium\Makefile" + + SetOutPath "$INSTDIR\lib\src\large" +# File "${DEV_ROOT}\lib\src\large\Makefile" + + SetOutPath "$INSTDIR\lib\src\huge" +# File "${DEV_ROOT}\lib\src\huge\Makefile" + + SetOutPath "$INSTDIR\lib\src\pic14" +# File "${DEV_ROOT}\lib\src\pic14\configure" +# File "${DEV_ROOT}\lib\src\pic14\configure.in" +# File "${DEV_ROOT}\lib\src\pic14\GPL" +# File "${DEV_ROOT}\lib\src\pic14\LGPL" +# File "${DEV_ROOT}\lib\src\pic14\Makefile" +# File "${DEV_ROOT}\lib\src\pic14\Makefile.common" +# File "${DEV_ROOT}\lib\src\pic14\Makefile.common.in" +# File "${DEV_ROOT}\lib\src\pic14\Makefile.rules" +# File "${DEV_ROOT}\lib\src\pic14\Makefile.subdir" +# File "${DEV_ROOT}\lib\src\pic14\NEWS" +# File "${DEV_ROOT}\lib\src\pic14\README" + File "${DEV_ROOT}\lib\src\pic14\TEMPLATE.c" + File "${DEV_ROOT}\lib\src\pic14\TEMPLATE.S" + + SetOutPath "$INSTDIR\lib\src\pic14\libsdcc\regular" + File "${DEV_ROOT}\lib\src\pic14\libsdcc\regular\*.c" + File "${DEV_ROOT}\lib\src\pic14\libsdcc\regular\*.S" + File "${DEV_ROOT}\lib\src\pic14\libsdcc\regular\*.inc" +# File "${DEV_ROOT}\lib\src\pic14\libsdcc\Makefile" + + SetOutPath "$INSTDIR\lib\src\pic14\libsdcc\enhanced" + File "${DEV_ROOT}\lib\src\pic14\libsdcc\enhanced\*.S" + File "${DEV_ROOT}\lib\src\pic14\libsdcc\enhanced\*.inc" +# File "${DEV_ROOT}\lib\src\pic14\libsdcc\Makefile" + + SetOutPath "$INSTDIR\non-free\lib\src\pic14\libdev" + File "${DEV_ROOT}\non-free\lib\src\pic14\libdev\*.c" +# File "${DEV_ROOT}\non-free\lib\src\pic14\libdev\Makefile" + + SetOutPath "$INSTDIR\lib\src\pic14\libm" +# File "${DEV_ROOT}\lib\src\pic14\libm\*.c" + + SetOutPath "$INSTDIR\lib\src\pic16" +# File "${DEV_ROOT}\lib\src\pic16\configure" +# File "${DEV_ROOT}\lib\src\pic16\configure.in" +# File "${DEV_ROOT}\lib\src\pic16\COPYING" +# File "${DEV_ROOT}\lib\src\pic16\Makefile" +# File "${DEV_ROOT}\lib\src\pic16\Makefile.common" +# File "${DEV_ROOT}\lib\src\pic16\Makefile.common.in" +# File "${DEV_ROOT}\lib\src\pic16\Makefile.rules" +# File "${DEV_ROOT}\lib\src\pic16\Makefile.subdir" +# File "${DEV_ROOT}\lib\src\pic16\pics.all" +# File "${DEV_ROOT}\lib\src\pic16\pics.build" +# File "${DEV_ROOT}\lib\src\pic16\README" + + SetOutPath "$INSTDIR\lib\src\pic16\debug" +# File "${DEV_ROOT}\lib\src\pic16\debug\Makefile" + + SetOutPath "$INSTDIR\lib\src\pic16\debug\gstack" +# File "${DEV_ROOT}\lib\src\pic16\debug\gstack\Makefile" + File "${DEV_ROOT}\lib\src\pic16\debug\gstack\*.c" + + SetOutPath "$INSTDIR\lib\src\pic16\libc" +# File "${DEV_ROOT}\lib\src\pic16\libc\Makefile" + + SetOutPath "$INSTDIR\lib\src\pic16\libc\ctype" + File "${DEV_ROOT}\lib\src\pic16\libc\ctype\*.c" +# File "${DEV_ROOT}\lib\src\pic16\libc\ctype\Makefile" + + SetOutPath "$INSTDIR\lib\src\pic16\libc\delay" + File "${DEV_ROOT}\lib\src\pic16\libc\delay\*.S" +# File "${DEV_ROOT}\lib\src\pic16\libc\delay\Makefile" + + SetOutPath "$INSTDIR\lib\src\pic16\libc\stdio" + File "${DEV_ROOT}\lib\src\pic16\libc\stdio\*.c" +# File "${DEV_ROOT}\lib\src\pic16\libc\stdio\Makefile" + + SetOutPath "$INSTDIR\lib\src\pic16\libc\stdlib" + File "${DEV_ROOT}\lib\src\pic16\libc\stdlib\*.c" + File "${DEV_ROOT}\lib\src\pic16\libc\stdlib\*.S" +# File "${DEV_ROOT}\lib\src\pic16\libc\stdlib\Makefile" + + SetOutPath "$INSTDIR\lib\src\pic16\libc\string" + File "${DEV_ROOT}\lib\src\pic16\libc\string\*.c" +# File "${DEV_ROOT}\lib\src\pic16\libc\string\Makefile" + + SetOutPath "$INSTDIR\lib\src\pic16\libc\utils" + File "${DEV_ROOT}\lib\src\pic16\libc\utils\*.S" +# File "${DEV_ROOT}\lib\src\pic16\libc\utils\Makefile" + + SetOutPath "$INSTDIR\non-free\lib\src\pic16\libdev" + File "${DEV_ROOT}\non-free\lib\src\pic16\libdev\*.c" +# File "${DEV_ROOT}\non-free\lib\src\pic16\libdev\Makefile" + + SetOutPath "$INSTDIR\lib\src\pic16\libio" + File "${DEV_ROOT}\lib\src\pic16\libio\*.ignore" +# File "${DEV_ROOT}\lib\src\pic16\libio\Makefile" + + SetOutPath "$INSTDIR\lib\src\pic16\libio\adc" + File "${DEV_ROOT}\lib\src\pic16\libio\adc\*.c" +# File "${DEV_ROOT}\lib\src\pic16\libio\adc\Makefile" + + SetOutPath "$INSTDIR\lib\src\pic16\libio\i2c" + File "${DEV_ROOT}\lib\src\pic16\libio\i2c\*.c" +# File "${DEV_ROOT}\lib\src\pic16\libio\i2c\Makefile" + + SetOutPath "$INSTDIR\lib\src\pic16\libio\usart" + File "${DEV_ROOT}\lib\src\pic16\libio\usart\*.c" +# File "${DEV_ROOT}\lib\src\pic16\libio\usart\Makefile" + + SetOutPath "$INSTDIR\lib\src\pic16\libm" + File "${DEV_ROOT}\lib\src\pic16\libm\*.c" +# File "${DEV_ROOT}\lib\src\pic16\libm\Makefile" + + SetOutPath "$INSTDIR\lib\src\pic16\libsdcc" +# File "${DEV_ROOT}\lib\src\pic16\libsdcc\Makefile" + + SetOutPath "$INSTDIR\lib\src\pic16\libsdcc\char" + File "${DEV_ROOT}\lib\src\pic16\libsdcc\char\*.c" +# File "${DEV_ROOT}\lib\src\pic16\libsdcc\char\Makefile" + + SetOutPath "$INSTDIR\lib\src\pic16\libsdcc\fixed16x16" + File "${DEV_ROOT}\lib\src\pic16\libsdcc\fixed16x16\*.c" + File "${DEV_ROOT}\lib\src\pic16\libsdcc\fixed16x16\*.S" +# File "${DEV_ROOT}\lib\src\pic16\libsdcc\fixed16x16\Makefile" + + SetOutPath "$INSTDIR\lib\src\pic16\libsdcc\float" + File "${DEV_ROOT}\lib\src\pic16\libsdcc\float\*.c" +# File "${DEV_ROOT}\lib\src\pic16\libsdcc\float\Makefile" + + SetOutPath "$INSTDIR\lib\src\pic16\libsdcc\gptr" + File "${DEV_ROOT}\lib\src\pic16\libsdcc\gptr\*.c" +# File "${DEV_ROOT}\lib\src\pic16\libsdcc\gptr\Makefile" + + SetOutPath "$INSTDIR\lib\src\pic16\libsdcc\int" + File "${DEV_ROOT}\lib\src\pic16\libsdcc\int\*.c" +# File "${DEV_ROOT}\lib\src\pic16\libsdcc\int\Makefile" + + SetOutPath "$INSTDIR\lib\src\pic16\libsdcc\long" + File "${DEV_ROOT}\lib\src\pic16\libsdcc\long\*.c" +# File "${DEV_ROOT}\lib\src\pic16\libsdcc\long\Makefile" + + SetOutPath "$INSTDIR\lib\src\pic16\libsdcc\lregs" + File "${DEV_ROOT}\lib\src\pic16\libsdcc\lregs\*.c" +# File "${DEV_ROOT}\lib\src\pic16\libsdcc\lregs\Makefile" + + SetOutPath "$INSTDIR\lib\src\pic16\libsdcc\stack" + File "${DEV_ROOT}\lib\src\pic16\libsdcc\stack\*.S" + + SetOutPath "$INSTDIR\lib\src\pic16\startup" + File "${DEV_ROOT}\lib\src\pic16\startup\*.c" +# File "${DEV_ROOT}\lib\src\pic16\startup\Makefile" +# File "${DEV_ROOT}\lib\src\pic16\startup\README" + + SetOutPath "$INSTDIR\lib\src" + File "${DEV_ROOT}\lib\src\*.c" +${SectionEnd} + +${Section} "SDCC STM8 large model library" SEC26 + SectionIn 1 2 + SetOutPath "$INSTDIR\lib\stm8-large" + File "${DEV_ROOT}\lib\stm8-large\*.*" +${SectionEnd} + +${Section} "SDCC EZ80_Z80 library" SEC27 + SectionIn 1 2 + SetOutPath "$INSTDIR\lib\ez80_z80" + File "${DEV_ROOT}\lib\ez80_z80\*.*" +${SectionEnd} + +${Section} "SDCC PDK14 library" SEC28 + SectionIn 1 2 + SetOutPath "$INSTDIR\lib\pdk14" + File "${DEV_ROOT}\lib\pdk14\*.*" +${SectionEnd} + +${Section} "SDCC PDK15 library" SEC29 + SectionIn 1 2 + SetOutPath "$INSTDIR\lib\pdk15" + File "${DEV_ROOT}\lib\pdk15\*.*" +${SectionEnd} + + +;-------------------------------- +;Descriptions + +;Language strings +LangString DESC_SEC01 ${LANG_ENGLISH} "SDCC application files" +LangString DESC_SEC02 ${LANG_ENGLISH} "ucSim application files" +LangString DESC_SEC03 ${LANG_ENGLISH} "SDCDB files" +LangString DESC_SEC04 ${LANG_ENGLISH} "SDCC documentation" +LangString DESC_SEC05 ${LANG_ENGLISH} "SDCC include files" +LangString DESC_SEC06 ${LANG_ENGLISH} "SDCC DS390 library" +LangString DESC_SEC07 ${LANG_ENGLISH} "SDCC DS400 library" +LangString DESC_SEC08 ${LANG_ENGLISH} "SDCC GBZ80 library" +LangString DESC_SEC09 ${LANG_ENGLISH} "SDCC Z180 library" +LangString DESC_SEC10 ${LANG_ENGLISH} "SDCC Rabbit 2000 library" +LangString DESC_SEC11 ${LANG_ENGLISH} "SDCC Rabbit 3000A library" +LangString DESC_SEC12 ${LANG_ENGLISH} "SDCC Z80 library" +LangString DESC_SEC13 ${LANG_ENGLISH} "SDCC mcs51 small model library" +LangString DESC_SEC14 ${LANG_ENGLISH} "SDCC mcs51 medium model library" +LangString DESC_SEC15 ${LANG_ENGLISH} "SDCC mcs51 large model library" +LangString DESC_SEC16 ${LANG_ENGLISH} "SDCC mcs51 huge model library" +LangString DESC_SEC17 ${LANG_ENGLISH} "SDCC mcs51 small-stack-auto model library" +LangString DESC_SEC18 ${LANG_ENGLISH} "SDCC mcs51 large-stack-auto model library" +LangString DESC_SEC19 ${LANG_ENGLISH} "SDCC HC08 library" +LangString DESC_SEC20 ${LANG_ENGLISH} "SDCC S08 library" +LangString DESC_SEC21 ${LANG_ENGLISH} "SDCC PIC16 library" +LangString DESC_SEC22 ${LANG_ENGLISH} "SDCC PIC14 library" +LangString DESC_SEC23 ${LANG_ENGLISH} "SDCC STM8 small library" +LangString DESC_SEC24 ${LANG_ENGLISH} "SDCC TLCS90 library" +LangString DESC_SEC25 ${LANG_ENGLISH} "SDCC library sources" +LangString DESC_SEC26 ${LANG_ENGLISH} "SDCC STM8 large model library" +LangString DESC_SEC27 ${LANG_ENGLISH} "SDCC EZ80_Z80 library" +LangString DESC_SEC28 ${LANG_ENGLISH} "SDCC PDK14 library" +LangString DESC_SEC29 ${LANG_ENGLISH} "SDCC PDK15 library" + +;Assign language strings to sections +!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN + !insertmacro MUI_DESCRIPTION_TEXT ${SEC01} $(DESC_SEC01) + !insertmacro MUI_DESCRIPTION_TEXT ${SEC02} $(DESC_SEC02) + !insertmacro MUI_DESCRIPTION_TEXT ${SEC03} $(DESC_SEC03) + !insertmacro MUI_DESCRIPTION_TEXT ${SEC04} $(DESC_SEC04) + !insertmacro MUI_DESCRIPTION_TEXT ${SEC05} $(DESC_SEC05) + !insertmacro MUI_DESCRIPTION_TEXT ${SEC06} $(DESC_SEC06) + !insertmacro MUI_DESCRIPTION_TEXT ${SEC07} $(DESC_SEC07) + !insertmacro MUI_DESCRIPTION_TEXT ${SEC08} $(DESC_SEC08) + !insertmacro MUI_DESCRIPTION_TEXT ${SEC09} $(DESC_SEC09) + !insertmacro MUI_DESCRIPTION_TEXT ${SEC10} $(DESC_SEC10) + !insertmacro MUI_DESCRIPTION_TEXT ${SEC11} $(DESC_SEC11) + !insertmacro MUI_DESCRIPTION_TEXT ${SEC12} $(DESC_SEC12) + !insertmacro MUI_DESCRIPTION_TEXT ${SEC27} $(DESC_SEC27) + !insertmacro MUI_DESCRIPTION_TEXT ${SEC13} $(DESC_SEC13) + !insertmacro MUI_DESCRIPTION_TEXT ${SEC14} $(DESC_SEC14) + !insertmacro MUI_DESCRIPTION_TEXT ${SEC15} $(DESC_SEC15) + !insertmacro MUI_DESCRIPTION_TEXT ${SEC16} $(DESC_SEC16) + !insertmacro MUI_DESCRIPTION_TEXT ${SEC17} $(DESC_SEC17) + !insertmacro MUI_DESCRIPTION_TEXT ${SEC18} $(DESC_SEC18) + !insertmacro MUI_DESCRIPTION_TEXT ${SEC19} $(DESC_SEC19) + !insertmacro MUI_DESCRIPTION_TEXT ${SEC20} $(DESC_SEC20) + !insertmacro MUI_DESCRIPTION_TEXT ${SEC21} $(DESC_SEC21) + !insertmacro MUI_DESCRIPTION_TEXT ${SEC22} $(DESC_SEC22) + !insertmacro MUI_DESCRIPTION_TEXT ${SEC23} $(DESC_SEC23) + !insertmacro MUI_DESCRIPTION_TEXT ${SEC26} $(DESC_SEC26) + !insertmacro MUI_DESCRIPTION_TEXT ${SEC24} $(DESC_SEC24) + !insertmacro MUI_DESCRIPTION_TEXT ${SEC25} $(DESC_SEC25) +!insertmacro MUI_FUNCTION_DESCRIPTION_END +;-------------------------------- + +${Section} -Icons SECICONS +!insertmacro MUI_STARTMENU_WRITE_BEGIN Application + CreateDirectory "$SMPROGRAMS\$MUI_STARTMENUPAGE_VARIABLE" + CreateShortCut "$SMPROGRAMS\$MUI_STARTMENUPAGE_VARIABLE\Uninstall SDCC.lnk" "$INSTDIR\uninstall.exe" +!ifdef FULL_DOC + CreateShortCut "$SMPROGRAMS\$MUI_STARTMENUPAGE_VARIABLE\Documentation.lnk" "$INSTDIR\doc\sdccman.pdf" "" "$INSTDIR\sdcc.ico" "" "" "" "" + CreateShortCut "$SMPROGRAMS\$MUI_STARTMENUPAGE_VARIABLE\README.lnk" "$INSTDIR\doc\README.TXT" "" "$INSTDIR\sdcc.ico" "" "" "" "" + CreateShortCut "$SMPROGRAMS\$MUI_STARTMENUPAGE_VARIABLE\Change Log.lnk" "$INSTDIR\doc\ChangeLog.txt" "" "$INSTDIR\sdcc.ico" "" "" "" "" +!else + CreateShortCut "$SMPROGRAMS\$MUI_STARTMENUPAGE_VARIABLE\Documentation.lnk" "$INSTDIR\doc\README.TXT" "" "$INSTDIR\sdcc.ico" "" "" "" "" + CreateShortCut "$SMPROGRAMS\$MUI_STARTMENUPAGE_VARIABLE\Change Log.lnk" "$INSTDIR\doc\ChangeLog_head.txt" "" "$INSTDIR\sdcc.ico" "" "" "" "" +!endif + CreateShortCut "$SMPROGRAMS\$MUI_STARTMENUPAGE_VARIABLE\GPL 2 License.lnk" "$INSTDIR\COPYING.txt" +!insertmacro MUI_STARTMENU_WRITE_END +${SectionEnd} + +${Section} -INI SECINI + WriteIniStr "$SMPROGRAMS\$MUI_STARTMENUPAGE_VARIABLE\SDCC on the Web.url" "InternetShortcut" "URL" "http://sdcc.sourceforge.net/" +!ifdef FULL_DOC + WriteIniStr "$SMPROGRAMS\$MUI_STARTMENUPAGE_VARIABLE\Latest Changes.url" "InternetShortcut" "URL" "http://svn.code.sf.net/p/sdcc/code/trunk/sdcc/ChangeLog" +!endif +${SectionEnd} + +${Section} -PostInstall SECPOSTINSTALL +; Add SDCC bin directory to path if silent mode + ${If} ${Silent} + Call SDCC.AddBinToPath + ${EndIf} + + WriteRegStr ${SDCC_ROOT_KEY} "Software\${PRODUCT_NAME}" "" $INSTDIR +!ifdef VER_MAJOR & VER_MINOR & VER_REVISION & VER_BUILD + WriteRegDword ${SDCC_ROOT_KEY} "Software\${PRODUCT_NAME}" "VersionMajor" "${VER_MAJOR}" + WriteRegDword ${SDCC_ROOT_KEY} "Software\${PRODUCT_NAME}" "VersionMinor" "${VER_MINOR}" + WriteRegDword ${SDCC_ROOT_KEY} "Software\${PRODUCT_NAME}" "VersionRevision" "${VER_REVISION}" + WriteRegDword ${SDCC_ROOT_KEY} "Software\${PRODUCT_NAME}" "VersionBuild" "${VER_BUILD}" +!endif + + WriteRegExpandStr ${UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninstall.exe" + WriteRegExpandStr ${UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "InstallLocation" "$INSTDIR" + WriteRegStr ${UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "${PRODUCT_NAME}" + WriteRegStr ${UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "sdcc.sourceforge.net" + WriteRegStr ${UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "http://sdcc.sourceforge.net/" + WriteRegStr ${UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "HelpLink" "http://sdcc.sourceforge.net/" + WriteRegStr ${UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLUpdateInfo" "http://sdcc.sourceforge.net/" + + WriteUninstaller "$INSTDIR\uninstall.exe" +${SectionEnd} + + +;;;; Uninstaller code ;;;; + +${Section} Uninstall SECUNINSTALL + !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_STARTMENUPAGE_VARIABLE + + ${DebugMsg} "removing path $INSTDIR\bin" + Push "$INSTDIR\bin" + Call un.SDCC.RemoveFromPath + +; Clean the registry + DeleteRegKey ${UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" + DeleteRegKey ${SDCC_ROOT_KEY} "Software\${PRODUCT_NAME}" + + Delete "$SMPROGRAMS\$MUI_STARTMENUPAGE_VARIABLE\GPL 2 License.lnk" + Delete "$SMPROGRAMS\$MUI_STARTMENUPAGE_VARIABLE\Change Log.lnk" +!ifdef FULL_DOC + Delete "$SMPROGRAMS\$MUI_STARTMENUPAGE_VARIABLE\Latest Changes.url" + Delete "$SMPROGRAMS\$MUI_STARTMENUPAGE_VARIABLE\README.lnk" +!endif + Delete "$SMPROGRAMS\$MUI_STARTMENUPAGE_VARIABLE\Documentation.lnk" + Delete "$SMPROGRAMS\$MUI_STARTMENUPAGE_VARIABLE\Uninstall SDCC.lnk" + Delete "$SMPROGRAMS\$MUI_STARTMENUPAGE_VARIABLE\SDCC on the Web.url" + + RMDir "$SMPROGRAMS\$MUI_STARTMENUPAGE_VARIABLE" + + Delete "$INSTDIR\lib\src\large\Makefile" + + Delete "$INSTDIR\lib\src\medium\Makefile" + + Delete "$INSTDIR\lib\src\small\Makefile" + + Delete "$INSTDIR\lib\src\mcs51\*.asm" + Delete "$INSTDIR\lib\src\mcs51\Makefile" + Delete "$INSTDIR\lib\src\mcs51\README" + + Delete "$INSTDIR\lib\src\hc08\*.c" + Delete "$INSTDIR\lib\src\hc08\hc08.lib" + Delete "$INSTDIR\lib\src\hc08\Makefile" + + Delete "$INSTDIR\lib\src\s08\*.c" + Delete "$INSTDIR\lib\src\s08\s08.lib" + Delete "$INSTDIR\lib\src\s08\Makefile" + + Delete "$INSTDIR\lib\src\stm8\stm8.lib" + Delete "$INSTDIR\lib\src\stm8\Makefile" + + Delete "$INSTDIR\lib\src\stm8-large\stm8.lib" + Delete "$INSTDIR\lib\src\stm8-large\Makefile" + + Delete "$INSTDIR\lib\src\z80\*.s" + Delete "$INSTDIR\lib\src\z80\z80.lib" + Delete "$INSTDIR\lib\src\z80\README" + Delete "$INSTDIR\lib\src\z80\Makefile" + + Delete "$INSTDIR\lib\src\z180\*.s" + Delete "$INSTDIR\lib\src\z180\z80.lib" + Delete "$INSTDIR\lib\src\z180\README" + Delete "$INSTDIR\lib\src\z180\Makefile" + + Delete "$INSTDIR\lib\src\gbz80\*.s" + Delete "$INSTDIR\lib\src\gbz80\gbz80.lib" + Delete "$INSTDIR\lib\src\gbz80\README" + Delete "$INSTDIR\lib\src\gbz80\Makefile" + + Delete "$INSTDIR\lib\src\r2k\*.s" + + Delete "$INSTDIR\lib\src\r3ka\*.s" + + Delete "$INSTDIR\lib\src\ez80_z80\*.s" + Delete "$INSTDIR\lib\src\ez80_z80\z80.lib" + Delete "$INSTDIR\lib\src\ez80_z80\README" + Delete "$INSTDIR\lib\src\ez80_z80\Makefile" + + Delete "$INSTDIR\lib\src\ds390\*.c" + Delete "$INSTDIR\lib\src\ds390\libds390.lib" + Delete "$INSTDIR\lib\src\ds390\Makefile.dep" + Delete "$INSTDIR\lib\src\ds390\Makefile" + Delete "$INSTDIR\lib\src\ds390\examples\MOVED" + + Delete "$INSTDIR\lib\src\ds400\*.c" + Delete "$INSTDIR\lib\src\ds400\libds400.lib" + Delete "$INSTDIR\lib\src\ds400\Makefile.dep" + Delete "$INSTDIR\lib\src\ds400\Makefile" + + Delete "$INSTDIR\lib\src\pdk14\pdk14.lib" + Delete "$INSTDIR\lib\src\pdk14\Makefile" + + Delete "$INSTDIR\lib\src\pdk15\pdk15.lib" + Delete "$INSTDIR\lib\src\pdk15\Makefile" + + Delete "$INSTDIR\lib\src\*.c" + + Delete "$INSTDIR\lib\pic14\*.lib" + + Delete "$INSTDIR\non-free\lib\pic14\*.lib" + + Delete "$INSTDIR\lib\pic16\*.o" + Delete "$INSTDIR\lib\pic16\*.lib" + + Delete "$INSTDIR\non-free\lib\pic16\*.lib" + + Delete "$INSTDIR\lib\hc08\*.lib" + + Delete "$INSTDIR\lib\s08\*.lib" + + Delete "$INSTDIR\lib\stm8\*.lib" + + Delete "$INSTDIR\lib\stm8-large\*.lib" + + Delete "$INSTDIR\lib\z80\*.rel" + Delete "$INSTDIR\lib\z80\*.lib" + + Delete "$INSTDIR\lib\z180\*.rel" + Delete "$INSTDIR\lib\z180\*.lib" + + Delete "$INSTDIR\lib\r2k\*.rel" + Delete "$INSTDIR\lib\r2k\*.lib" + + Delete "$INSTDIR\lib\r3ka\*.rel" + Delete "$INSTDIR\lib\r3ka\*.lib" + + Delete "$INSTDIR\lib\ez80_z80\*.rel" + Delete "$INSTDIR\lib\ez80_z80\*.lib" + + Delete "$INSTDIR\lib\small\*.lib" + + Delete "$INSTDIR\lib\medium\*.lib" + + Delete "$INSTDIR\lib\large\*.lib" + + Delete "$INSTDIR\lib\small-stack-auto\*.lib" + Delete "$INSTDIR\lib\large-stack-auto\*.lib" + + Delete "$INSTDIR\lib\gbz80\*.rel" + Delete "$INSTDIR\lib\gbz80\*.lib" + + Delete "$INSTDIR\lib\ds390\*.lib" + + Delete "$INSTDIR\lib\ds400\*.lib" + + Delete "$INSTDIR\lib\pdk14\*.lib" + + Delete "$INSTDIR\lib\pdk15\*.lib" + + Delete "$INSTDIR\include\asm\z80\*.h" + Delete "$INSTDIR\include\asm\z180\*.h" + Delete "$INSTDIR\include\asm\r2k\*.h" + Delete "$INSTDIR\include\asm\r3ka\*.h" + Delete "$INSTDIR\include\asm\ez80_z80\*.h" + Delete "$INSTDIR\include\asm\pic16\*.h" + Delete "$INSTDIR\include\asm\pic14\*.h" + Delete "$INSTDIR\include\asm\mcs51\*.h" + Delete "$INSTDIR\include\asm\gbz80\*.h" + Delete "$INSTDIR\include\asm\ds390\*.h" + Delete "$INSTDIR\include\asm\stm8\*.h" + Delete "$INSTDIR\include\asm\default\*.h" + Delete "$INSTDIR\include\z180\*.h" + Delete "$INSTDIR\include\pic14\*.h" + Delete "$INSTDIR\include\pic14\*.txt" + Delete "$INSTDIR\include\pic14\*.inc" + Delete "$INSTDIR\non-free\include\pic14\*.h" + Delete "$INSTDIR\include\pic16\*.h" + Delete "$INSTDIR\non-free\include\pic16\*.h" + Delete "$INSTDIR\include\pic16\*.txt" + Delete "$INSTDIR\include\mcs51\*.h" + Delete "$INSTDIR\include\hc08\*.h" + Delete "$INSTDIR\include\ds400\*.h" + Delete "$INSTDIR\include\ds390\*.h" + Delete "$INSTDIR\include\*.h" + +!ifndef FULL_DOC + Delete "$INSTDIR\doc\README.TXT" + Delete "$INSTDIR\doc\ChangeLog_head.txt" +!endif + + Delete "$INSTDIR\bin\sdasgb.exe" + Delete "$INSTDIR\bin\sdas6808.exe" + Delete "$INSTDIR\bin\sdasz80.exe" + Delete "$INSTDIR\bin\sdas8051.exe" + Delete "$INSTDIR\bin\sdas390.exe" + Delete "$INSTDIR\bin\sdasrab.exe" + Delete "$INSTDIR\bin\sdasstm8.exe" + Delete "$INSTDIR\bin\sdaspdk14.exe" + Delete "$INSTDIR\bin\sdaspdk15.exe" + Delete "$INSTDIR\bin\sdastlcs90.exe" + Delete "$INSTDIR\bin\sdld.exe" + Delete "$INSTDIR\bin\sdldgb.exe" + Delete "$INSTDIR\bin\sdld6808.exe" + Delete "$INSTDIR\bin\sdldz80.exe" + Delete "$INSTDIR\bin\sdldstm8.exe" + Delete "$INSTDIR\bin\sdldpdk.exe" + Delete "$INSTDIR\bin\sdar.exe" + Delete "$INSTDIR\bin\sdranlib.exe" + Delete "$INSTDIR\bin\sdnm.exe" + Delete "$INSTDIR\bin\sdobjcopy.exe" + Delete "$INSTDIR\bin\makebin.exe" + Delete "$INSTDIR\bin\packihx.exe" + Delete "$INSTDIR\bin\sdcc.exe" + Delete "$INSTDIR\bin\sdcpp.exe" + Delete "$INSTDIR\bin\as2gbmap.cmd" + Delete "$INSTDIR\bin\readline5.dll" +!ifdef WIN64 + Delete "$INSTDIR\bin\libgcc_s_*-1.dll" + Delete "$INSTDIR\bin\libstdc++-6.dll" + Delete "$INSTDIR\bin\libwinpthread-1.dll" +!endif + + + Delete "$INSTDIR\bin\s51.exe" + Delete "$INSTDIR\bin\shc08.exe" + Delete "$INSTDIR\bin\sz80.exe" + Delete "$INSTDIR\bin\sstm8.exe" + + Delete "$INSTDIR\bin\sdcdb.exe" + Delete "$INSTDIR\bin\sdcdb.el" + Delete "$INSTDIR\bin\sdcdbsrc.el" + + Delete "$INSTDIR\COPYING.txt" + Delete "$INSTDIR\COPYING3.txt" + Delete "$INSTDIR\sdcc.ico" + Delete "$INSTDIR\uninstall.exe" + + RMDir /r "$INSTDIR\lib\src\pic14" + RMDir /r "$INSTDIR\non-free\lib\src\pic14" + RMDir /r "$INSTDIR\lib\src\pic16" + RMDir /r "$INSTDIR\non-free\lib\src\pic16" + RMDir "$INSTDIR\lib\src\small" + RMDir "$INSTDIR\lib\src\medium" + RMDir "$INSTDIR\lib\src\large" + RMDir "$INSTDIR\lib\src\mcs51" + RMDir "$INSTDIR\lib\src\z80" + RMDir "$INSTDIR\lib\src\z180" + RMDir "$INSTDIR\lib\src\gbz80" + RMDir "$INSTDIR\lib\src\r2k" + RMDir "$INSTDIR\lib\src\r3ka" + RMDir "$INSTDIR\lib\src\ez80_z80" + RMDir "$INSTDIR\lib\src\ds390\examples" + RMDir "$INSTDIR\lib\src\ds390" + RMDir "$INSTDIR\lib\src\ds400" + RMDir "$INSTDIR\lib\src\hc08" + RMDir "$INSTDIR\lib\src\s08" + RMDir "$INSTDIR\lib\src\stm8" + RMDir "$INSTDIR\lib\src\stm8-large" + RMDir "$INSTDIR\lib\src\pdk14" + RMDir "$INSTDIR\lib\src\pdk15" + RMDir "$INSTDIR\lib\src" + RMDir "$INSTDIR\non-free\lib\src" + + RMDir "$INSTDIR\lib\pic14" + RMDir "$INSTDIR\non-free\lib\pic14" + RMDir "$INSTDIR\lib\pic16" + RMDir "$INSTDIR\non-free\lib\pic16" + RMDir "$INSTDIR\lib\z80" + RMDir "$INSTDIR\lib\z180" + RMDir "$INSTDIR\lib\r2k" + RMDir "$INSTDIR\lib\r3ka" + RMDir "$INSTDIR\lib\ez80_z80" + RMDir "$INSTDIR\lib\small" + RMDir "$INSTDIR\lib\medium" + RMDir "$INSTDIR\lib\large" + RMDir "$INSTDIR\lib\small-stack-auto" + RMDir "$INSTDIR\lib\large-stack-auto" + RMDir "$INSTDIR\lib\gbz80" + RMDir "$INSTDIR\lib\ds390" + RMDir "$INSTDIR\lib\ds400" + RMDir "$INSTDIR\lib\hc08" + RMDir "$INSTDIR\lib\s08" + RMDir "$INSTDIR\lib\stm8" + RMDir "$INSTDIR\lib\stm8-large" + RMDir "$INSTDIR\lib\pdk14" + RMDir "$INSTDIR\lib\pdk15" + RMDir "$INSTDIR\lib" + RMDir "$INSTDIR\non-free\lib" + + RMDir "$INSTDIR\include\asm\z80" + RMDir "$INSTDIR\include\asm\z180" + RMDir "$INSTDIR\include\asm\r2k" + RMDir "$INSTDIR\include\asm\r3ka" + RMDir "$INSTDIR\include\asm\ez80_z80" + RMDir "$INSTDIR\include\asm\pic16" + RMDir "$INSTDIR\non-free\include\asm\pic16" + RMDir "$INSTDIR\include\asm\pic14" + RMDir "$INSTDIR\non-free\include\asm\pic14" + RMDir "$INSTDIR\include\asm\mcs51" + RMDir "$INSTDIR\include\asm\gbz80" + RMDir "$INSTDIR\include\asm\ds390" + RMDir "$INSTDIR\include\asm\stm8" + RMDir "$INSTDIR\include\asm\default" + RMDir "$INSTDIR\include\asm" + RMDir "$INSTDIR\include\z180" + RMDir "$INSTDIR\include\pic14" + RMDir "$INSTDIR\non-free\include\pic14" + RMDir "$INSTDIR\include\pic16" + RMDir "$INSTDIR\non-free\include\pic16" + RMDir "$INSTDIR\include\mcs51" + RMDir "$INSTDIR\include\hc08" + RMDir "$INSTDIR\include\ds400" + RMDir "$INSTDIR\include\ds390" + RMDir "$INSTDIR\include" + RMDir "$INSTDIR\non-free\include" + + RMDir "$INSTDIR\non-free" + +!ifdef FULL_DOC + RMDir /r "$INSTDIR\doc" +!else + RMDir "$INSTDIR\doc" +!endif + + RMDir "$INSTDIR\bin" + + RMDir "$INSTDIR" +;;;; SetAutoClose true +${SectionEnd} + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Path Manipulation functions ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +!verbose 3 +!include "WinMessages.nsh" +!verbose 4 + +; AddToPath - Adds the given dir to the search path. +; Input - head of the stack +; Note - Win9x systems requires reboot + +${Function} SDCC.AddToPath + Exch $0 + Push $1 + Push $2 + Push $3 + + ; don't add if the path doesn't exist + ${If} ${FileExists} $0 + ${If} ${IsNT} + ; On NT: read PATH from registry + ReadRegStr $1 HKCU "Environment" "PATH" + ${Else} + ; Not on NT: read PATH from environment variable + ReadEnvStr $1 PATH + ${EndIf} + + ${StrStr} $2 "$1;" "$0;" + ${If} $2 == "" + ${StrStr} $2 "$1;" "$0\;" + ${If} $2 == "" + GetFullPathName /SHORT $3 $0 + ${StrStr} $2 "$1;" "$3;" + ${If} $2 == "" + ${StrStr} $2 "$1;" "$03\;" + ${If} $2 == "" + ${If} ${IsNT} + ;System PATH variable is at: + ;HKLM "/SYSTEM/CurrentControlSet/Control/Session Manager/Environment" "Path" + ReadRegStr $1 HKCU "Environment" "PATH" + StrCpy $2 $1 1 -1 ; copy last char + ${If} $2 == ";" ; if last char == ; + StrCpy $1 $1 -1 ; remove last char + ${Endif} + ${If} $1 != "" + StrCpy $0 "$1;$0" + ${Endif} + WriteRegExpandStr HKCU "Environment" "PATH" $0 + SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 + ${Else} + ; Not on NT + StrCpy $1 $WINDIR 2 + FileOpen $1 "$1\autoexec.bat" a + FileSeek $1 -1 END + FileReadByte $1 $2 + ${If} $2 = 26 ; DOS EOF + FileSeek $1 -1 END ; write over EOF + ${Endif} + ${DebugMsg} "adding line $\r$\nSET PATH=%PATH%;$3$\r$\n" + FileWrite $1 "$\r$\nSET PATH=%PATH%;$3$\r$\n" + FileClose $1 + ${DebugMsg} "SetRebootFlag true" + SetRebootFlag true + ${Endif} + ${Endif} + ${Endif} + ${Endif} + ${Endif} + ${EndIf} + + Pop $3 + Pop $2 + Pop $1 + Pop $0 +${FunctionEnd} + +; RemoveFromPath - Remove a given dir from the path +; Input: head of the stack + +!macro SDCC.RemoveFromPath un +${Function} ${un}SDCC.RemoveFromPath + Exch $0 + Push $1 + Push $2 + Push $3 + Push $4 + Push $5 + Push $6 + + IntFmt $6 "%c" 26 ; DOS EOF + + ${If} ${IsNT} + ;System PATH variable is at: + ;HKLM "/SYSTEM/CurrentControlSet/Control/Session Manager/Environment" "Path" + ReadRegStr $1 HKCU "Environment" "PATH" + StrCpy $5 $1 1 -1 ; copy last char + ${If} $5 != ";" ; if last char != ; + StrCpy $1 "$1;" ; append ; + ${EndIf} + Push $1 + Push "$0;" + Call ${un}StrStr ; Find `$0;` in $1 + Pop $2 ; pos of our dir + ${If} $2 != "" + ; it is in path: + ; $0 - path to add + ; $1 - path var + StrLen $3 "$0;" + StrLen $4 $2 + StrCpy $5 $1 -$4 ; $5 is now the part before the path to remove + StrCpy $6 $2 "" $3 ; $6 is now the part after the path to remove + StrCpy $3 $5$6 + + StrCpy $5 $3 1 -1 ; copy last char + ${If} $5 == ";" ; if last char == ; + StrCpy $3 $3 -1 ; remove last char + ${EndIf} + ${If} $3 != "" + ; New PATH not empty: update the registry + WriteRegExpandStr HKCU "Environment" "PATH" $3 + ${Else} + ; New PATH empty: remove from the registry + DeleteRegValue HKCU "Environment" "PATH" + ${EndIf} + SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 + ${Endif} + ${Else} + ; Not on NT + StrCpy $1 $WINDIR 2 + FileOpen $1 "$1\autoexec.bat" r + GetTempFileName $4 + FileOpen $2 $4 w + GetFullPathName /SHORT $0 $0 + StrCpy $0 "SET PATH=%PATH%;$0" + + nextLine: + ; copy all lines except the line containing "SET PATH=%PATH%;$0" + ; from autoexec.bat to the temporary file + ClearErrors + FileRead $1 $3 + ${IfNot} ${Errors} + StrCpy $5 $3 1 -1 ; read last char + ${If} $5 == $6 ; if DOS EOF + StrCpy $3 $3 -1 ; remove DOS EOF so we can compare + ${EndIf} + ${If} $3 != "$0$\r$\n" + ${AndIf} $3 != "$0$\n" + ${AndIf} $3 != "$0" + FileWrite $2 $3 + Goto nextLine + ${Else} + ; This is the line I'm looking for: + ; don't copy it + ${DebugMsg} "removing line $0" + ${DebugMsg} "SetRebootFlag true" + SetRebootFlag true + Goto nextLine + ${EndIf} + ${EndIf} + + FileClose $2 + FileClose $1 + StrCpy $1 $WINDIR 2 + Delete "$1\autoexec.bat" + CopyFiles /SILENT $4 "$1\autoexec.bat" + Delete $4 + ${Endif} + + Pop $6 + Pop $5 + Pop $4 + Pop $3 + Pop $2 + Pop $1 + Pop $0 +${FunctionEnd} +!macroend +!insertmacro SDCC.RemoveFromPath "" +!insertmacro SDCC.RemoveFromPath "un." + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Uninstall/Reinstall page functions ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +!ifdef VER_MAJOR & VER_MINOR & VER_REVISION & VER_BUILD + +Var ReinstallPageCheck + +${Function} SDCC.PageReinstall + + ReadRegStr $R0 ${SDCC_ROOT_KEY} "Software\${PRODUCT_NAME}" "" + + ${If} $R0 == "" + ReadRegStr $R0 ${UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" + ${If} $R0 == "" + Abort + ${EndIf} + ${EndIf} + + ReadRegDWORD $R0 ${SDCC_ROOT_KEY} "Software\${PRODUCT_NAME}" "VersionMajor" + ReadRegDWORD $R1 ${SDCC_ROOT_KEY} "Software\${PRODUCT_NAME}" "VersionMinor" + ReadRegDWORD $R2 ${SDCC_ROOT_KEY} "Software\${PRODUCT_NAME}" "VersionRevision" + ReadRegDWORD $R3 ${SDCC_ROOT_KEY} "Software\${PRODUCT_NAME}" "VersionBuild" + StrCpy $R0 $R0.$R1.$R2.$R3 + + ${VersionCompare} ${VER_MAJOR}.${VER_MINOR}.${VER_REVISION}.${VER_BUILD} $R0 $R0 + ${If} $R0 == 0 + StrCpy $R1 "${PRODUCT_NAME} ${PRODUCT_VERSION} is already installed. Select the operation you want to perform and click Next to continue." + StrCpy $R2 "Add/Reinstall components" + StrCpy $R3 "Uninstall ${PRODUCT_NAME}" + !insertmacro MUI_HEADER_TEXT "Already Installed" "Choose the maintenance option to perform." + StrCpy $R0 "2" + ${ElseIf} $R0 == 1 + StrCpy $R1 "An older version of ${PRODUCT_NAME} is installed on your system. It's recommended that you uninstall the current version before installing. Select the operation you want to perform and click Next to continue." + StrCpy $R2 "Uninstall before installing" + StrCpy $R3 "Do not uninstall" + !insertmacro MUI_HEADER_TEXT "Already Installed" "Choose how you want to install ${PRODUCT_NAME}." + StrCpy $R0 "1" + ${ElseIf} $R0 == 2 + StrCpy $R1 "A newer version of ${PRODUCT_NAME} is already installed! It is not recommended that you install an older version. If you really want to install this older version, it's better to uninstall the current version first. Select the operation you want to perform and click Next to continue." + StrCpy $R2 "Uninstall before installing" + StrCpy $R3 "Do not uninstall" + !insertmacro MUI_HEADER_TEXT "Already Installed" "Choose how you want to install ${PRODUCT_NAME}." + StrCpy $R0 "1" + ${Else} + Abort + ${EndIf} + + nsDialogs::Create /NOUNLOAD 1018 + + ${NSD_CreateLabel} 0 0 100% 24u $R1 + Pop $R1 + + ${NSD_CreateRadioButton} 30u 50u -30u 8u $R2 + Pop $R2 + ${NSD_OnClick} $R2 SDCC.PageReinstallUpdateSelection + + ${NSD_CreateRadioButton} 30u 70u -30u 8u $R3 + Pop $R3 + ${NSD_OnClick} $R3 SDCC.PageReinstallUpdateSelection + + ${If} $ReinstallPageCheck != 2 + SendMessage $R2 ${BM_SETCHECK} ${BST_CHECKED} 0 + ${Else} + SendMessage $R3 ${BM_SETCHECK} ${BST_CHECKED} 0 + ${EndIf} + + nsDialogs::Show + +${FunctionEnd} + +${Function} SDCC.PageReinstallUpdateSelection + + Pop $R1 + + ${NSD_GetState} $R2 $R1 + + ${If} $R1 == ${BST_CHECKED} + StrCpy $ReinstallPageCheck 1 + ${Else} + StrCpy $ReinstallPageCheck 2 + ${EndIf} + +${FunctionEnd} + +${Function} SDCC.PageLeaveReinstall + + ${NSD_GetState} $R2 $R1 + + ${DebugMsg} "R0 = $R0, R1 = $R1, R2 = $R2" + + ${If} $R0 == "1" + ${AndIf} $R1 != "1" + Goto reinst_done + ${EndIf} + + ${If} $R0 == "2" + ${AndIf} $R1 == 1 + Goto reinst_done + ${EndIf} + + ReadRegStr $R1 ${UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" + + ;Run uninstaller + HideWindow + + ${If} $R0 == "2" + ; Uninstall only: uninstaller should be removed + ClearErrors + ; ExecWait doesn't wait if _?=$INSTDIR is not defined! + ExecWait '$R1' + Quit + ${Else} + ; Uninstal & Reinstall: uninstaller will be rewritten + ClearErrors + ; ExecWait doesn't wait if _?=$INSTDIR is not defined! + ExecWait '$R1 _?=$INSTDIR' + ${EndIf} + + BringToFront + +reinst_done: + +${FunctionEnd} + +!endif # VER_MAJOR & VER_MINOR & VER_REVISION & VER_BUILD diff --git a/support/scripts/sdcc_cygwin_mingw32 b/support/scripts/sdcc_cygwin_mingw32 new file mode 100755 index 0000000..5575663 --- /dev/null +++ b/support/scripts/sdcc_cygwin_mingw32 @@ -0,0 +1,16 @@ +#!/bin/sh +# Script to "cross" compile with mingw32 under Cygwin + +./configure -C \ +--prefix="/sdcc" \ +--datarootdir="/sdcc" \ +docdir="\${datarootdir}/doc" \ +include_dir_suffix="include" \ +non_free_include_dir_suffix="non-free/include" \ +lib_dir_suffix="lib" \ +non_free_lib_dir_suffix="non-free/lib" \ +sdccconf_h_dir_separator="\\\\" \ +CC="gcc -mno-cygwin" \ +CXX="g++ -mno-cygwin" + +make 2>&1 | tee make.log diff --git a/support/scripts/sdcc_mingw32 b/support/scripts/sdcc_mingw32 new file mode 100755 index 0000000..96e3280 --- /dev/null +++ b/support/scripts/sdcc_mingw32 @@ -0,0 +1,29 @@ +#!/bin/sh +# Script to crosscompile with mingw32 +if [ $(expr $(hostname) : '.*\.') != '0' ] +then + HOSTNAME=$(expr $(hostname) : '\([^.]*\).') +else + HOSTNAME=$(hostname) +fi +TOOLSPREFIX=${HOME}/local-${HOSTNAME}/cross-tools/bin/i586-mingw32msvc- + +export CC=${TOOLSPREFIX}gcc +export CXX=${TOOLSPREFIX}g++ +export AR=${TOOLSPREFIX}ar +export RANLIB=${TOOLSPREFIX}ranlib +export STRIP=${TOOLSPREFIX}strip + +export SDCCCONFIGUREFLAGS=" \ +--prefix=/sdcc \ +--datarootdir=/sdcc \ +docdir=\${datarootdir}/doc \ +include_dir_suffix=include \ +non_free_include_dir_suffix=non-free/include \ +lib_dir_suffix=lib \ +non_free_lib_dir_suffix=non-free/lib \ +sdccconf_h_dir_separator=\\\\ \ +--disable-device-lib \ +--host=i586-mingw32msvc --build=unknown-unknown-linux-gnu" + +( ../sdcc/configure ${SDCCCONFIGUREFLAGS} && make ) 2>&1 | tee make.log diff --git a/support/scripts/z80-disasm.pl b/support/scripts/z80-disasm.pl new file mode 100755 index 0000000..24d4f00 --- /dev/null +++ b/support/scripts/z80-disasm.pl @@ -0,0 +1,4959 @@ +#!/usr/bin/perl -w + +=back + + Copyright (C) 2013-2016, Molnar Karoly <molnarkaroly@users.sf.net> + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source distribution. + +================================================================================ + + This program disassembles the hex files. It assumes that the hex file + contains Z80 instructions. + + Proposal for use: ./z80-disasm.pl program.hex > program.dasm + + $Id: z80-disasm.pl 9450 2016-01-09 16:47:43Z molnarkaroly $ +=cut + +use strict; +use warnings; +no if $] >= 5.018, warnings => "experimental::smartmatch"; # perl 5.16 +use 5.12.0; # when (regex) + +use constant FALSE => 0; +use constant TRUE => 1; + +use constant TAB_LENGTH => 8; + +################################################################################ + +use constant INHX8M => 0; +use constant INHX32 => 2; + +use constant INHX_DATA_REC => 0; +use constant INHX_EOF_REC => 1; +use constant INHX_EXT_LIN_ADDR_REC => 4; + +use constant EMPTY => -1; + +use constant COUNT_SIZE => 2; +use constant ADDR_SIZE => 4; +use constant TYPE_SIZE => 2; +use constant BYTE_SIZE => 2; +use constant CRC_SIZE => 2; +use constant HEADER_SIZE => (COUNT_SIZE + ADDR_SIZE + TYPE_SIZE); +use constant MIN_LINE_LENGTH => (HEADER_SIZE + CRC_SIZE); + +use constant Z80_ROM_SIZE => 0x10000; + +################################################################################ + +my $PROGRAM = 'z80-disasm.pl'; + +my $border0 = ('-' x 99); +my $border1 = ('#' x 99); +my $border2 = ('.' x 39); + +my @default_paths = + ( + '/usr/share/sdcc/include/z180', + '/usr/local/share/sdcc/include/z180' + ); + +my $default_include_path = ''; +my $include_path = ''; +my $hex_file = ''; +my $map_file = ''; +my $map_readed = FALSE; +my $header_file = ''; +my $name_list = ''; + +my $verbose = 0; +my $gen_assembly_code = FALSE; +my $no_explanations = FALSE; +my $find_lost_labels = FALSE; + +my @rom = (); +my $rom_size = Z80_ROM_SIZE; +my %const_areas_by_address = (); # From the command line parameters. + +my %const_blocks_by_address = (); + +my %ram_blocks_by_address = (); +my %ram_names_by_address = (); + +=back + The structure of one element of the %io_by_address hash: + + { + NAME => '', + REF_COUNT => 0 + } +=cut + +my %io_by_address = (); + + # Sizes of the instructions. + +use constant IPREFIX_DD => -1; +use constant IPREFIX_ED => -2; +use constant IPREFIX_FD => -3; + +my @instruction_sizes_ = + ( +# 0 1 2 3 4 5 6 7 8 9 A B C D E F + + 1, 3, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, # 00 + 2, 3, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1, # 10 + 2, 3, 3, 1, 1, 1, 2, 1, 2, 1, 3, 1, 1, 1, 2, 1, # 20 + 2, 3, 3, 1, 1, 1, 2, 1, 2, 1, 3, 1, 1, 1, 2, 1, # 30 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, # 40 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, # 50 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, # 60 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, # 70 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, # 80 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, # 90 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, # A0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, # B0 + 1, 1, 3, 3, 3, 1, 2, 1, 1, 1, 3, 2, 3, 3, 2, 1, # C0 + 1, 1, 3, 2, 3, 1, 2, 1, 1, 1, 3, 2, 3,IPREFIX_DD, 2, 1, # D0 -1: DD + 1, 1, 3, 1, 3, 1, 2, 1, 1, 1, 3, 1, 3,IPREFIX_ED, 2, 1, # E0 -2: ED + 1, 1, 3, 1, 3, 1, 2, 1, 1, 1, 3, 1, 3,IPREFIX_FD, 2, 1 # F0 -3: FD + ); + +my @instruction_sizes_DDFD = + ( +# 0 1 2 3 4 5 6 7 8 9 A B C D E F + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, # 00 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, # 10 + 0, 4, 4, 2, 2, 2, 3, 0, 0, 2, 4, 2, 2, 2, 3, 0, # 20 + 0, 0, 0, 0, 3, 3, 4, 0, 0, 2, 0, 0, 0, 0, 0, 0, # 30 + 0, 0, 0, 0, 2, 2, 3, 0, 0, 0, 0, 0, 2, 2, 3, 0, # 40 + 0, 0, 0, 0, 2, 2, 3, 0, 0, 0, 0, 0, 2, 2, 3, 0, # 50 + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 3, 2, # 60 + 3, 3, 3, 3, 3, 3, 0, 3, 0, 0, 0, 0, 2, 2, 3, 0, # 70 + 0, 0, 0, 0, 2, 2, 3, 0, 0, 0, 0, 0, 2, 2, 3, 0, # 80 + 0, 0, 0, 0, 2, 2, 3, 0, 0, 0, 0, 0, 2, 2, 3, 0, # 90 + 0, 0, 0, 0, 2, 2, 3, 0, 0, 0, 0, 0, 2, 2, 3, 0, # A0 + 0, 0, 0, 0, 2, 2, 3, 0, 0, 0, 0, 0, 2, 2, 3, 0, # B0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, # C0 4: CB + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # D0 + 0, 2, 0, 2, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, # E0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0 # F0 + ); + +my @instruction_sizes_ED = + ( +# 0 1 2 3 4 5 6 7 8 9 A B C D E F + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # 00 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # 10 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # 20 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # 30 + 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, # 40 + 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, # 50 + 2, 2, 2, 4, 2, 2, 2, 2, 2, 2, 2, 4, 2, 2, 2, 2, # 60 + 2, 2, 2, 4, 2, 2, 2, 0, 2, 2, 2, 4, 2, 2, 2, 0, # 70 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # 80 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # 90 + 2, 2, 2, 2, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, # A0 + 2, 2, 2, 2, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, # B0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # C0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # D0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, # E0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 # F0 + ); + +my $prev_is_jump; + +use constant SILENT0 => 0; +use constant SILENT1 => 1; + +my $decoder_silent_level; + +use constant RAM_ALIGN_SIZE => 3; +use constant EXPL_ALIGN_SIZE => 5; +use constant STAT_ALIGN_SIZE => 6; +use constant TBL_COLUMNS => 8; + +=back + The structure of one element of the %blocks_by_address hash: + + { + TYPE => 0, + ADDR => 0, + SIZE => 0, + LABEL => { + TYPE => 0, + NAME => '', + PRINTED => FALSE, + CALL_COUNT => 0, + JUMP_COUNT => 0 + }, + REF_COUNT => 0 + } +=cut + +use constant BLOCK_INSTR => 0; +use constant BLOCK_RAM => 1; +use constant BLOCK_CONST => 2; +use constant BLOCK_EMPTY => 3; + +use constant BL_TYPE_NONE => -1; +use constant BL_TYPE_SUB => 0; +use constant BL_TYPE_LABEL => 1; +use constant BL_TYPE_JTABLE => 2; +use constant BL_TYPE_VARIABLE => 3; +use constant BL_TYPE_CONST => 4; + +my %label_names = + ( + eval BL_TYPE_SUB => 'Function_', + eval BL_TYPE_LABEL => 'Label_', + eval BL_TYPE_JTABLE => 'Jumptable_', + eval BL_TYPE_VARIABLE => 'Variable_', + eval BL_TYPE_CONST => 'Constant_' + ); + +my %empty_blocks_by_address = (); +my %blocks_by_address = (); +my %labels_by_address = (); +my $max_label_addr = 0; + +my %interrupts_by_address = + ( + 0x0000 => 'System_init', + 0x0008 => 'Interrupt_08', + 0x0010 => 'Interrupt_10', + 0x0018 => 'Interrupt_18', + 0x0020 => 'Interrupt_20', + 0x0028 => 'Interrupt_28', + 0x0030 => 'Interrupt_30', + 0x0038 => 'Interrupt_38' + ); + +my %control_characters = + ( + 0x00 => '\0', + 0x07 => '\a', + 0x08 => '\b', + 0x09 => '\t', + 0x0A => '\n', + 0x0C => '\f', + 0x0D => '\r', + 0x1B => '\e', + 0x7F => '^?' + ); + +use constant INST_LD_HL => 0x21; +use constant INST_ADD_HL_DE => 0x19; +use constant INST_JP => 0xC3; +use constant INST_JP_HL => 0xE9; +use constant INST_JP_CC => 0xC2; # mask: 0xC7 +use constant INST_JR => 0x18; +use constant INST_JR_CC => 0x20; # mask: 0xE7 +use constant INST_DJNZ => 0x10; +use constant INST_CALL => 0xCD; +use constant INST_CALL_CC => 0xC4; # mask: 0xC7 +use constant INST_RET => 0xC9; +use constant INST_RETI => 0x4D; # with 0xED prefix +use constant INST_RETN => 0x45; # with 0xED prefix + +my $dcd_address = 0; +my $dcd_instr_size = 0; +my $dcd_instr = 0; +my $dcd_instr_x = 0; +my $dcd_instr_y = 0; +my $dcd_instr_z = 0; +my $dcd_instr_p = 0; +my $dcd_instr_q = 0; +my $dcd_parm0 = 0; +my $dcd_parm1 = 0; +my $dcd_parm2 = 0; + +my $table_header = ''; +my $table_border = ''; + +################################################################################ +################################################################################ + +my %pp_defines = (); # Value of definitions. + +my @pp_conditions = (); +my @pp_else_conditions = (); +my $pp_level = 0; # Shows the lowest level. +my $embed_level; + +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@@ This a simple preprocessor. @@@@@@@@@@@@@@@@@@@@@@@@@ +#@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + # Examines that the parameter is defined or not defined. + +sub _defined($) + { + return defined($pp_defines{$_[0]}); + } + +#------------------------------------------------------------------------------- + + # Records a definition. + +sub define($) + { + my ($Name) = ($_[0] =~ /^(\S+)/op); + my $Body = ${^POSTMATCH}; + + $Body =~ s/^\s+//o; + + die "define(): This definition already exists: \"$Name\"\n" if (_defined($Name)); + + # The definition is in fact unnecessary. + $pp_defines{$Name} = $Body; + } + +#------------------------------------------------------------------------------- + + # Delete a definition. + +sub undefine($) + { + delete($pp_defines{$_[0]}); + } + +#------------------------------------------------------------------------------- + + # Evaluation of the #if give a boolean value. This procedure preserves it. + +sub if_condition($) + { + my $Val = $_[0]; + + push(@pp_conditions, $Val); + push(@pp_else_conditions, $Val); + ++$pp_level; + } + +#------------------------------------------------------------------------------- + + # Evaluation of the #else give a boolean value. This procedure preserves it. + +sub else_condition($$) + { + my ($File, $Line_number) = @_; + + 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); + + my $last = $#pp_conditions; + + if ($last > 0 && $pp_conditions[$last - 1]) + { + $pp_conditions[$last] = ($pp_else_conditions[$#pp_else_conditions]) ? FALSE : TRUE; + } + else + { + $pp_conditions[$last] = FALSE; + } + } + +#------------------------------------------------------------------------------- + + # Closes a logical unit which starts with a #if. + +sub endif_condition($$) + { + my ($File, $Line_number) = @_; + + 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); + + pop(@pp_conditions); + pop(@pp_else_conditions); + --$pp_level; + } + +#------------------------------------------------------------------------------- + +sub reset_preprocessor() + { + %pp_defines = (); + @pp_conditions = (); + push(@pp_conditions, TRUE); + @pp_else_conditions = (); + push(@pp_else_conditions, FALSE); + $pp_level = 0; + } + +#------------------------------------------------------------------------------- + + # This the preprocessor. + +sub run_preprocessor($$$$) + { + my ($Fname, $Function, $Line, $Line_number) = @_; + + if ($Line =~ /^#\s*ifdef\s+(\S+)$/o) + { + if ($pp_conditions[$#pp_conditions]) + { + # The ancestor is valid, therefore it should be determined that + # the descendants what kind. + + if_condition(_defined($1)); + } + else + { + # The ancestor is invalid, so the descendants will invalid also. + + if_condition(FALSE); + } + } + elsif ($Line =~ /^#\s*ifndef\s+(\S+)$/o) + { + if ($pp_conditions[$#pp_conditions]) + { + # The ancestor is valid, therefore it should be determined that + # the descendants what kind. + + if_condition(! _defined($1)); + } + else + { + # The ancestor is invalid, so the descendants will invalid also. + + if_condition(FALSE); + } + } + elsif ($Line =~ /^#\s*else/o) + { + else_condition($Fname, $Line_number); + } + elsif ($Line =~ /^#\s*endif/o) + { + endif_condition($Fname, $Line_number); + } + elsif ($Line =~ /^#\s*define\s+(.+)$/o) + { + # This level is valid, so it should be recorded in the definition. + + define($1) if ($pp_conditions[$#pp_conditions]); + } + elsif ($Line =~ /^#\s*undef\s+(.+)$/o) + { + # This level is valid, so it should be deleted in the definition. + + undefine($1) if ($pp_conditions[$#pp_conditions]); + } + elsif ($pp_conditions[$#pp_conditions]) + { + # This is a valid line. (The whole magic is in fact therefore there is.) + + $Function->($Line); + } + } + +################################################################################ +################################################################################ +################################################################################ + +sub basename($) + { + return ($_[0] =~ /([^\/]+)$/) ? $1 : ''; + } + +#------------------------------------------------------------------------------- + +sub param_exist($$) + { + die "This option \"$_[0]\" requires a parameter.\n" if ($_[1] > $#ARGV); + } + +#------------------------------------------------------------------------------- + +sub Log + { + return if (pop(@_) > $verbose); + foreach (@_) { print STDERR $_; } + print STDERR "\n"; + } + +#------------------------------------------------------------------------------- + +sub str2int($) + { + my $Str = $_[0]; + + return hex($1) if ($Str =~ /^0x([[:xdigit:]]+)$/io); + return int($Str) if ($Str =~ /^-?\d+$/o); + + die "str2int(): This string not integer: \"$Str\""; + } + +#------------------------------------------------------------------------------- + + # + # Before print, formats the $Text. + # + +sub align($$) + { + my ($Text, $Tab_count) = @_; + my ($al, $ct); + + $ct = $Text; + 1 while $ct =~ s/\t/' ' x (TAB_LENGTH - ($-[0] % TAB_LENGTH))/e; + $al = $Tab_count - (int(length($ct) / TAB_LENGTH)); + + # One space will surely becomes behind it. + if ($al < 1) + { + return "$Text "; + } + else + { + return ($Text . ("\t" x $al)); + } + } + +#------------------------------------------------------------------------------- + + # + # Multiple file test. + # + +sub is_file_ok($) + { + my $File = $_[0]; + + if (! -e $File) + { + print STDERR "$PROGRAM: Not exists -> \"$File\"\n"; + exit(1); + } + + if (! -f $File) + { + print STDERR "$PROGRAM: Not file -> \"$File\"\n"; + exit(1); + } + + if (! -r $File) + { + print STDERR "$PROGRAM: Can not read -> \"$File\"\n"; + exit(1); + } + + if (! -s $File) + { + print STDERR "$PROGRAM: Empty file -> \"$File\"\n"; + exit(1); + } + } + +#------------------------------------------------------------------------------- + + # + # Initializes the @rom array. + # + +sub init_mem($$) + { + my ($Start, $End) = @_; + + @rom[$Start .. $End] = ((EMPTY) x ($End - $Start + 1)); + } + +#------------------------------------------------------------------------------- + + # + # Store values of the $Code to $AddrRef address. + # + +sub store_code($$) + { + my ($Code, $AddrRef) = @_; + + if ($$AddrRef >= $rom_size) + { + printf STDERR "Warning, this address (0x%04X) outside the code area (0x%04X)!\n", $$AddrRef, $rom_size - 1; + } + + Log(sprintf("rom[0x%08X] = 0x%02X", $$AddrRef, $Code), 9); + $rom[$$AddrRef++] = $Code; + } + +#------------------------------------------------------------------------------- + + # + # Reads contents of the $Hex. + # + +sub read_hex($) + { + my $Hex = $_[0]; + my $addr_H = 0; + my $format = INHX32; + my $line_num = 0; + + if (! open(IN, '<', $Hex)) + { + print STDERR "$PROGRAM : Could not open. -> \"$Hex\"\n"; + exit(1); + } + + while (<IN>) + { + chomp; + s/\r$//o; + ++$line_num; + + my $len = length() - 1; + + if ($len < MIN_LINE_LENGTH) + { + close(IN); + print STDERR "$PROGRAM: ${line_num}th line <- Shorter than %u character.\n", MIN_LINE_LENGTH; + exit(1); + } + + Log("$..(1) (\"$_\") length() = " . length(), 7); + + my $bytecount = int(($len - MIN_LINE_LENGTH) / BYTE_SIZE); + + my $binrec = pack('H*', substr($_, 1)); + + if (unpack('%8C*', $binrec) != 0) + { + close(IN); + print STDERR "$PROGRAM: $Hex <- Crc error. (${line_num}th line \"$_\").\n"; + exit(1); + } + + my ($count, $addr, $type, $bytes) = unpack('CnCX4Cx3/a', $binrec); + + my @codes = unpack('C*', $bytes); + + Log(sprintf("$..(2) (\"$_\") count = $count, bytecount = $bytecount, addr = 0x%04X, type = $type", $addr), 7); + + if ($type == INHX_EOF_REC) + { + last; + } + elsif ($type == INHX_EXT_LIN_ADDR_REC) + { + $addr_H = unpack('n', $bytes); # big-endian + + Log(sprintf("$..(3) (\"$_\") addr_H = 0x%04X\n", $addr_H), 7); + + $format = INHX32; + Log('format = INHX32', 7); + next; + } + elsif ($type != INHX_DATA_REC) + { + close(IN); + printf STDERR "$PROGRAM: $Hex <- Unknown type of record: 0x%02X (${line_num}th line \"$_\").\n", $type; + exit(1); + } + + if ($bytecount == $count) # INHX32 + { + if ($format == INHX8M) + { + close(IN); + print STDERR "$PROGRAM: $Hex <- Mixed format of file (${line_num}th line \"$_\").\n"; + exit(1); + } + + my $addr32 = ($addr_H << 16) | $addr; + + map { store_code($_, \$addr32) } @codes; + } + elsif ($bytecount == ($count * BYTE_SIZE)) # INHX8M + { + if ($format == INHX32) + { + close(IN); + print STDERR "$PROGRAM: $Hex <- Mixed format of file (${line_num}th line \"$_\").\n"; + exit(1); + } + + map { store_code($_, \$addr) } @codes; + } + else + { + close(IN); + print STDERR "$PROGRAM: $Hex <- Wrong format of file (${line_num}th line \"$_\").\n"; + exit(1); + } + } # while (<IN>) + + close(IN); + } + +#------------------------------------------------------------------------------- + + # + # Determines that the $Address belongs to a constant. + # + +sub is_constant($) + { + my $Address = $_[0]; + + foreach (sort {$a <=> $b} keys(%const_areas_by_address)) + { + return TRUE if ($_ <= $Address && $Address <= $const_areas_by_address{$_}); + last if ($_ > $Address); + } + + foreach (sort {$a <=> $b} keys(%const_blocks_by_address)) + { + return TRUE if ($_ <= $Address && $Address <= $const_blocks_by_address{$_}); + last if ($_ > $Address); + } + + return FALSE; + } + +#------------------------------------------------------------------------------- + + # + # Determines that the $Address belongs to a empty area. + # + +sub is_empty($) + { + my $Address = $_[0]; + + foreach (sort {$a <=> $b} keys(%empty_blocks_by_address)) + { + return TRUE if ($_ <= $Address && $Address <= $empty_blocks_by_address{$_}); + last if ($_ > $Address); + } + + return FALSE; + } + +#------------------------------------------------------------------------------- + + # + # Creates a const block. + # + +sub add_const_area($$) + { + $const_areas_by_address{$_[0]} = $_[1]; + } + +#------------------------------------------------------------------------------- + + # + # Creates a new block, or modifies one. + # + +sub add_block($$$$$) + { + my ($Address, $Type, $Size, $LabelType, $LabelName) = @_; + my ($block, $label, $end); + + $end = $Address + $Size - 1; + + if (! defined($blocks_by_address{$Address})) + { + $label = { + TYPE => $LabelType, + NAME => $LabelName, + PRINTED => FALSE, + CALL_COUNT => 0, + JUMP_COUNT => 0 + }; + + $blocks_by_address{$Address} = { + TYPE => $Type, + ADDR => $Address, + SIZE => $Size, + LABEL => $label, + REF_COUNT => 0 + }; + + given ($Type) + { + when (BLOCK_INSTR) + { + if ($LabelType != BL_TYPE_NONE) + { + $labels_by_address{$Address} = $label; + $max_label_addr = $Address if ($max_label_addr < $Address); + } + } + + when (BLOCK_RAM) + { + if ($LabelType != BL_TYPE_NONE) + { + $labels_by_address{$Address} = $label; + $max_label_addr = $Address if ($max_label_addr < $Address); + } + + $ram_blocks_by_address{$Address} = $end if ($Size > 0); + } + + when (BLOCK_CONST) + { + if ($LabelType != BL_TYPE_NONE) + { + $labels_by_address{$Address} = $label; + $max_label_addr = $Address if ($max_label_addr < $Address); + } + + $const_blocks_by_address{$Address} = $end if ($Size > 0); + } + + when (BLOCK_EMPTY) + { + # At empty area, can not be label. + + $label->{TYPE} = BL_TYPE_NONE; + $label->{NAME} = ''; + $empty_blocks_by_address{$Address} = $end if ($Size > 0); + } + + default + { + printf STDERR "add_block(0x%04X): Unknown block type!\n", $Address; + exit(1); + } + } # given ($Type) + } # if (! defined($blocks_by_address{$Address})) + else + { + $block = $blocks_by_address{$Address}; + $label = $block->{LABEL}; + $block->{TYPE} = $Type; + $block->{SIZE} = $Size if ($Size > 0); + $label->{NAME} = $LabelName if ($label->{NAME} eq '' && $LabelName ne ''); + + given ($Type) + { + when (BLOCK_INSTR) + { + if ($LabelType != BL_TYPE_NONE) + { + $label->{TYPE} = $LabelType; + $labels_by_address{$Address} = $label; + $max_label_addr = $Address if ($max_label_addr < $Address); + } + } + + when (BLOCK_RAM) + { + if ($LabelType != BL_TYPE_NONE) + { + $label->{TYPE} = $LabelType; + $labels_by_address{$Address} = $label; + $max_label_addr = $Address if ($max_label_addr < $Address); + } + + $ram_blocks_by_address{$Address} = $end if ($Size > 0); + } + + when (BLOCK_CONST) + { + if ($LabelType != BL_TYPE_NONE) + { + $label->{TYPE} = $LabelType; + $labels_by_address{$Address} = $label; + $max_label_addr = $Address if ($max_label_addr < $Address); + } + + $const_blocks_by_address{$Address} = $end if ($Size > 0); + } + + when (BLOCK_EMPTY) + { + # At empty area, can not be label. + + $label->{TYPE} = BL_TYPE_NONE; + $label->{NAME} = ''; + $empty_blocks_by_address{$Address} = $end if ($Size > 0); + } + } # given ($Type) + } + + return $label; + } + +#------------------------------------------------------------------------------- + + # + # Store address entry of a procedure. + # + +sub add_func_label($$$) + { + my ($Address, $Name, $Map_mode) = @_; + my $label; + + if ($Address < 0) + { + Log(sprintf("add_func_label(): This address (0x%04X) negative!", $Address), 2); + return; + } + + if (! $Map_mode) + { + if (! defined($blocks_by_address{$Address})) + { + Log(sprintf("add_func_label(): This address (0x%04X) does not shows an instruction!", $Address), 2); + return; + } + } + + if (is_constant($Address) || is_empty($Address)) + { + Log(sprintf("add_func_label(): This address (0x%04X) outside the code area!", $Address), 2); + return; + } + + $label = add_block($Address, BLOCK_INSTR, 0, BL_TYPE_SUB, $Name); + + if (! $Map_mode) + { + ++$label->{CALL_COUNT}; + ++$blocks_by_address{$Address}->{REF_COUNT}; + } + } + +#------------------------------------------------------------------------------- + + # + # Store a label. + # + +sub add_jump_label($$$$$) + { + my ($TargetAddr, $Name, $Type, $SourceAddr, $Map_mode) = @_; + my ($label, $type); + + if ($TargetAddr < 0) + { + Log(sprintf("add_jump_label(): This address (0x%04X) negative!", $TargetAddr), 2); + return; + } + + if (! $Map_mode) + { + if (! defined($blocks_by_address{$TargetAddr})) + { + Log(sprintf("add_jump_label(): This address (0x%04X) does not shows an instruction!", $TargetAddr), 2); + return; + } + } + + if (is_constant($TargetAddr) || is_empty($TargetAddr)) + { + Log(sprintf("add_jump_label(): This address (0x%04X) outside the code area!", $TargetAddr), 2); + return; + } + + if (defined($interrupts_by_address{$SourceAddr})) + { + $Type = BL_TYPE_SUB; + $Name = $interrupts_by_address{$SourceAddr} if ($Name eq ''); + } + + $label = add_block($TargetAddr, BLOCK_INSTR, 0, $Type, $Name); + + if (! $Map_mode) + { + ++$label->{JUMP_COUNT}; + ++$blocks_by_address{$TargetAddr}->{REF_COUNT}; + } + } + +#------------------------------------------------------------------------------- + + # + # Store a variable name. + # + +sub add_ram($$$) + { + my ($Address, $Name, $Map_mode) = @_; + + return if ($Address == EMPTY); + + if ($Address < 0) + { + Log(sprintf("add_ram(): This address (0x%04X) negative!", $Address), 2); + return; + } + + add_block($Address, BLOCK_RAM, 1, BL_TYPE_VARIABLE, $Name); + + ++$blocks_by_address{$Address}->{REF_COUNT} if (! $Map_mode); + } + +#------------------------------------------------------------------------------- + + # + # Store a I/O port name. + # + +sub add_io($$$) + { + my ($Address, $Name, $Map_mode) = @_; + my $io; + + return if ($Address == EMPTY); + + if (! defined($io = $io_by_address{$Address})) + { + $io_by_address{$Address} = { + NAME => $Name, + REF_COUNT => ($Map_mode) ? 0 : 1 + }; + } + else + { + ++$io->{REF_COUNT} if (! $Map_mode); + } + } + +################################################################################ +################################################################################ + +use constant MAP_NULL => 0; +use constant MAP_BORDER => 1; +use constant MAP_AREA => 2; +use constant MAP_CODE => 3; +use constant MAP_DATA => 4; + + # + # If exists the map file, then extracts out of it the labels, + # variables and some segments. + # + +sub read_map_file() + { + my $state; + + return if ($map_file eq ''); + + $state = MAP_NULL; + + if (! open(MAP, '<', $map_file)) + { + print STDERR "$PROGRAM : Could not open. -> \"$map_file\"\n"; + exit(1); + } + + while (<MAP>) + { + chomp; + s/\r$//o; + + if ($state == MAP_NULL) + { + $state = MAP_BORDER if (/^Area\s+/io); + } + elsif ($state == MAP_BORDER) + { + $state = MAP_AREA if (/^-+\s+/o); + } + elsif ($state == MAP_AREA) + { + if (/^_CODE\s+/o) + { + $state = MAP_CODE; + } + elsif (/^_(DATA|INITIALIZED)\s+/o) + { + $state = MAP_DATA; + } + else + { + $state = MAP_NULL; + } + } + elsif ($state == MAP_CODE) + { + if (/^.ASxxxx Linker\s+/io) + { + $state = MAP_NULL; + } + elsif (/^\s+([[:xdigit:]]+)\s+(\S+)/o) + { + # 00000180 _main main + # 00000190 _main_end main + # 000001A2 _puts conio + # 000001B5 _puthex conio + # 00000201 _puthex8 conio + + add_func_label(hex($1), $2, TRUE); + } + } # elsif ($state == MAP_CODE) + elsif ($state == MAP_DATA) + { + if (/^.ASxxxx Linker\s+/io) + { + $state = MAP_NULL; + } + elsif (/^\s*([[:xdigit:]]+)\s+(\S+)/o) + { + # 000006C6 _heap_top + # 000006C8 _last_error + # 000006C9 _old_isr + + add_ram(hex($1), $2, TRUE); + } + } # elsif ($state == MAP_DATA) + } # while (<MAP>) + + $map_readed = TRUE; + close(MAP); + } + +#------------------------------------------------------------------------------- + +use constant NAMES_NULL => 0; +use constant NAMES_RAM => 1; +use constant NAMES_IO => 2; +use constant NAMES_ROM => 3; + +sub read_name_list() + { + my ($line, $addr, $name, $state); + + return if ($name_list eq ''); + + if (! open(NAMES, '<', $name_list)) + { + print STDERR "$PROGRAM : Could not open. -> \"$name_list\"\n"; + exit(1); + } + + $state = NAMES_NULL; + + foreach (grep(! /^\s*$/o, <NAMES>)) + { + chomp; + s/\r$//o; + s/^\s*|\s*$//go; + + if (/^\[RAM\]$/io) + { + $state = NAMES_RAM; + next; + } + elsif (/^\[IO\]$/io) + { + $state = NAMES_IO; + next; + } + elsif (/^\[ROM\]$/io) + { + $state = NAMES_ROM; + next; + } + + $line = $_; + + given ($state) + { + when (NAMES_RAM) + { + if ($line =~ /^0x([[:xdigit:]]+)\s*:\s*(\S+)$/io) + { + add_ram(hex($1), $2, TRUE); + } + } + + when (NAMES_IO) + { + if ($line =~ /^0x([[:xdigit:]]+)\s*:\s*(\S+)$/io) + { + add_io(hex($1), $2, TRUE); + } + } + + when (NAMES_ROM) + { + if ($line =~ /^0x([[:xdigit:]]+)\s*:\s*(\S+)$/io) + { + add_jump_label(hex($1), $2, BL_TYPE_LABEL, EMPTY, TRUE); + } + } + } # given ($state) + } # foreach (grep(! /^\s*$/o, <NAMES>)) + + close(NAMES); + } + +#------------------------------------------------------------------------------- + + # + # There are some variables that are multi-byte. However, only + # the LSB byte of having a name. This procedure gives a name + # for the higher-significant bytes. + # + +sub fix_multi_byte_variables() + { + my ($block, $prev_addr, $prev_name, $name, $i, $var_size); + + $prev_addr = EMPTY; + $prev_name = ''; + foreach (sort {$a <=> $b} keys(%blocks_by_address)) + { + $block = $blocks_by_address{$_}; + $name = $block->{LABEL}->{NAME}; + + if ($block->{TYPE} != BLOCK_RAM) + { + $prev_addr = EMPTY; + $prev_name = ''; + next; + } + + $ram_names_by_address{$_} = $name; + + if ($name eq '') + { + $prev_addr = EMPTY; + $prev_name = ''; + next; + } + + if ($prev_addr != EMPTY) + { + $var_size = $_ - $prev_addr; + + if ($var_size > 1) + { + # This is a multi-byte variable. Make the aliases. + + for ($i = 1; $i < $var_size; ++$i) + { + $ram_names_by_address{$prev_addr + $i} = "($prev_name + $i)"; + } + + $blocks_by_address{$prev_addr}->{SIZE} = $var_size; + } + } + + $prev_addr = $_; + $prev_name = $name; + } # foreach (sort {$a <=> $b} keys(%blocks_by_address)) + } + +#------------------------------------------------------------------------------- + +sub fix_io_names() + { + my $i = 0; + + foreach (sort {$a <=> $b} keys(%io_by_address)) + { + next if ($io_by_address{$_}->{NAME} ne ''); + + $io_by_address{$_}->{NAME} = "io_$i"; + ++$i; + } + } + +#------------------------------------------------------------------------------- + + # + # If there is left in yet so label that has no name, this here get one. + # + +sub add_names_labels() + { + my ($addr, $label, $fidx, $lidx, $jtidx, $cidx, $type); + + $fidx = 0; + $lidx = 0; + $jtidx = 0; + $cidx = 0; + + for ($addr = 0; $addr <= $max_label_addr; ++$addr) + { + $label = $labels_by_address{$addr}; + + next if (! defined($label)); + + $type = $label->{TYPE}; + + next if ($type == BL_TYPE_NONE || (defined($label->{NAME}) && $label->{NAME} ne '')); + + if ($type == BL_TYPE_SUB) + { + $label->{NAME} = sprintf("$label_names{$type}%03u", $fidx++); + } + elsif ($type == BL_TYPE_LABEL) + { + $label->{NAME} = sprintf("$label_names{$type}%03u", $lidx++); + } + elsif ($type == BL_TYPE_JTABLE) + { + $label->{NAME} = sprintf("$label_names{$type}%03u", $jtidx++); + } + elsif ($type == BL_TYPE_CONST) + { + $label->{NAME} = sprintf("$label_names{$type}%03u", $cidx++); + } + } + } + +################################################################################ +################################################################################ + + # + # Expand a relative offset value. + # + +sub expand_offset($) + { + my $Offset = $_[0]; + + return ($Offset & 0x80) ? -(($Offset ^ 0xFF) + 1) : $Offset; + } + +#------------------------------------------------------------------------------- + + # + # Finds address of branchs and procedures. + # + +sub label_finder($$) + { + my ($Address, $BlockRef) = @_; + my ($instr_size, $instr, $addr); + + $instr_size = $BlockRef->{SIZE}; + $instr = $rom[$Address]; + + if ($instr == INST_JP) + { + # JP addr16 11000011 aaaaaaaa aaaaaaaa a7-a0 a15-a8 absolute address + + $addr = ($rom[$Address + 2] << 8) | $rom[$Address + 1]; + add_jump_label($addr, '', BL_TYPE_LABEL, $Address, FALSE); + } + elsif (($instr & 0xC7) == INST_JP_CC) + { + # JP cc, addr16 11ccc010 aaaaaaaa aaaaaaaa a7-a0 a15-a8 absolute address + + $addr = ($rom[$Address + 2] << 8) | $rom[$Address + 1]; + add_jump_label($addr, '', BL_TYPE_LABEL, $Address, FALSE); + } + elsif ($instr == INST_JR) + { + # JR rel 00011000 eeeeeee relative address + + $addr = $Address + $instr_size + expand_offset($rom[$Address + 1]); + add_jump_label($addr, '', BL_TYPE_LABEL, EMPTY, FALSE); + } + elsif (($instr & 0xE7) == INST_JR_CC) + { + # JR cc, rel 00100000 eeeeeee relative address + + $addr = $Address + $instr_size + expand_offset($rom[$Address + 1]); + add_jump_label($addr, '', BL_TYPE_LABEL, EMPTY, FALSE); + } + elsif ($instr == INST_DJNZ) + { + # DJNZ rel 00010000 eeeeeee relative address + + $addr = $Address + $instr_size + expand_offset($rom[$Address + 1]); + add_jump_label($addr, '', BL_TYPE_LABEL, EMPTY, FALSE); + } + elsif ($instr == INST_CALL) + { + # CALL addr16 11001101 aaaaaaaa aaaaaaaa a7-a0 a15-a8 absolute address + + $addr = ($rom[$Address + 2] << 8) | $rom[$Address + 1]; + add_func_label($addr, '', FALSE); + } + elsif (($instr & 0xC7) == INST_CALL_CC) + { + # CALL cc, addr16 11ccc100 aaaaaaaa aaaaaaaa a7-a0 a15-a8 absolute address + + $addr = ($rom[$Address + 2] << 8) | $rom[$Address + 1]; + add_func_label($addr, '', FALSE); + } + } + +#------------------------------------------------------------------------------- + + # + # If exists a label name wich belong to the $Address, then returns it. + # Otherwise, returns the address. + # + +sub label_name($) + { + my $Address = $_[0]; + my $label = $labels_by_address{$Address}; + + return ((defined($label) && $label->{NAME} ne '') ? $label->{NAME} : (sprintf '0x%04X', $Address)); + } + +#------------------------------------------------------------------------------- + + # + # If exists a I/O port name wich belong to the $Address, then returns it. + # Otherwise, returns the address. + # + +sub io_name($) + { + my $Address = $_[0]; + my $io = $io_by_address{$Address}; + + return ((defined($io) && $io->{NAME} ne '') ? $io->{NAME} : (sprintf '0x%02X', $Address)); + } + +#------------------------------------------------------------------------------- + + # + # If exists a variable name wich belong to the $Address, then returns it. + # Otherwise, returns the address. + # + +sub reg_name($$) + { + my ($Address, $StrRef) = @_; + my ($ram, $str); + + if (defined($ram = $ram_names_by_address{$Address}) && $ram ne '') + { + $str = sprintf "0x%04X", $Address; + ${$StrRef} = "[$str]"; + $str = $ram; + } + else + { + $str = sprintf "0x%04X", $Address; + ${$StrRef} = "[$str]"; + } + + return $str; + } + +#------------------------------------------------------------------------------- + + # + # Auxiliary procedure of prints. + # + +sub print_3($$$) + { + my ($Instr, $Param, $Expl) = @_; + + return if ($decoder_silent_level > SILENT0); + + if ($no_explanations) + { + print(($Param ne '') ? "$Instr\t$Param\n" : "$Instr\n"); + } + elsif ($Expl ne '') + { + print "$Instr\t" . align($Param, EXPL_ALIGN_SIZE) . "; $Expl\n"; + } + else + { + print(($Param ne '') ? "$Instr\t$Param\n" : "$Instr\n"); + } + } + +#------------------------------------------------------------------------------- + + # + # If possible, returns the character. + # + +sub decode_char($) + { + my $Ch = $_[0]; + + if ($Ch >= ord(' ') && $Ch < 0x7F) + { + return sprintf " {'%c'}", $Ch; + } + elsif (defined($control_characters{$Ch})) + { + return " {'$control_characters{$Ch}'}"; + } + + return ''; + } + +#------------------------------------------------------------------------------- + + # + # Determines direction of jump. + # + +sub jump_direction($) + { + my $TargetAddr = $_[0]; + my ($str0, $str1, $str2); + + $str0 = sprintf "0x%04X", $TargetAddr; + + if ($dcd_address < $TargetAddr) + { + $str1 = ''; + $str2 = ' (forward)'; + } + elsif ($dcd_address == $TargetAddr) + { + $str1 = ' (endless loop)'; + $str2 = ''; + } + else + { + $str1 = ''; + $str2 = ' (backward)'; + } + + return "$str2 hither: $str0$str1"; + } + +#--------------------------------------------------------------------------------------------------- +#--------------------------------------------------------------------------------------------------- +#--------------------------------------------------------------------------------------------------- +#--------------------------------------------------------------------------------------------------- + +my @core_registers8 = + ( + { + NAME => 'B', + EXPL => 'B' + }, + { + NAME => 'C', + EXPL => 'C' + }, + { + NAME => 'D', + EXPL => 'D' + }, + { + NAME => 'E', + EXPL => 'E' + }, + { + NAME => 'H', + EXPL => 'H' + }, + { + NAME => 'L', + EXPL => 'L' + }, + { + NAME => '(HL)', + EXPL => '[HL]' + }, + { + NAME => 'A', + EXPL => 'A' + } + ); + +my @core_registers16a = ( 'BC', 'DE', 'HL', 'SP' ); +my @core_registers16b = ( 'BC', 'DE', 'HL', 'AF' ); +my @core_registers16c = ( 'BC', 'DE', 'IX', 'SP' ); + +my @CB_shift_instr = + ( + { + INSTR => 'rlc', + EXPL => 'CF <- %s[7..0] <- %s.7' + }, + { + INSTR => 'rrc', + EXPL => '%s.0 -> %s[7..0] -> CF' + }, + { + INSTR => 'rl', + EXPL => 'CF <- %s[7..0] <- CF' + }, + { + INSTR => 'rr', + EXPL => 'CF -> %s[7..0] -> CF' + }, + { + INSTR => 'sla', + EXPL => 'CF <- %s[7..0] <- 0' + }, + { + INSTR => 'sra', + EXPL => '%s.7 -> %s[7..0] -> CF' + }, + { + INSTR => 'sll', + EXPL => 'CF <- %s[7..0] <- 1' + }, + { + INSTR => 'srl', + EXPL => '0 -> %s[7..0] -> CF' + } + ); + +sub CB_prefix_decoder() + { + my ($str, $i_reg, $reg); + + given ($dcd_instr_x) + { + when (0) + { +# RLC r CB xx 11001011 00000rrr +# RRC r CB xx 11001011 00001rrr +# RL r CB xx 11001011 00010rrr +# RR r CB xx 11001011 00011rrr +# SLA r CB xx 11001011 00100rrr +# SRA r CB xx 11001011 00101rrr +# SLL r CB xx 11001011 00110rrr +# SRL r CB xx 11001011 00111rrr +# xxyyyzzz + if ($decoder_silent_level == SILENT0) + { + my $i_shift = $CB_shift_instr[$dcd_instr_y]; + + $i_reg = $core_registers8[$dcd_instr_z]; + $reg = $i_reg->{EXPL}; + if ($dcd_instr_y == 0) + { + $str = sprintf $i_shift->{EXPL}, $reg, $reg; + } + else + { + $str = sprintf $i_shift->{EXPL}, $reg; + } + print_3($i_shift->{INSTR}, $i_reg->{NAME}, $str); + } + } + + when (1) + { +# BIT b, r CB 11001011 01bbbrrr +# xxyyyzzz + + if ($decoder_silent_level == SILENT0) + { + $i_reg = $core_registers8[$dcd_instr_z]; + print_3('bit', "$dcd_instr_y, $i_reg->{NAME}", "ZF = !$i_reg->{EXPL}.$dcd_instr_y"); + } + } + + when (2) + { +# RES b, r CB 11001011 10bbbrrr +# xxyyyzzz + + if ($decoder_silent_level == SILENT0) + { + $i_reg = $core_registers8[$dcd_instr_z]; + print_3('res', "$dcd_instr_y, $i_reg->{NAME}", "$i_reg->{EXPL}.$dcd_instr_y = 0"); + } + } + + default + { +# SET b, r CB 11001011 11bbbrrr +# xxyyyzzz + + if ($decoder_silent_level == SILENT0) + { + $i_reg = $core_registers8[$dcd_instr_z]; + print_3('set', "$dcd_instr_y, $i_reg->{NAME}", "$i_reg->{EXPL}.$dcd_instr_y = 1"); + } + } + } # given ($dcd_instr_x) + } + +#------------------------------------------------------------------------------- + + # + # $IndexReg: IX or IY + # + +sub DDFD_CB_prefix_decoder($) + { + my $IndexReg = $_[0]; + my $offset = expand_offset($dcd_parm1); + my ($offs_str, $offs_expl, $i_reg); + + if ($offset < 0) + { + $offs_str = "$offset($IndexReg)"; + $offs_expl = "[$IndexReg$offset]"; + } + else + { + $offs_str = "$offset($IndexReg)"; + $offs_expl = "[${IndexReg}+$offset]"; + } + + given ($dcd_instr_x) + { +=back + r: 000 B + 001 C + 010 D + 011 E + 100 H + 101 L + 110 (HL) + 111 A +=cut + when (0) + { + if ($dcd_instr_z == 6) + { +# RLC (IX+d) DD CB dd 06 11011101 11001011 dddddddd 00000110 d: two's complement number +# RLC (IY+d) FD CB dd 06 11111101 11001011 dddddddd 00000110 d: two's complement number +# RRC (IX+d) DD CB dd 0E 11011101 11001011 dddddddd 00001110 d: two's complement number +# RRC (IY+d) FD CB dd 0E 11111101 11001011 dddddddd 00001110 d: two's complement number +# RL (IX+d) DD CB dd 16 11011101 11001011 dddddddd 00010110 d: two's complement number +# RL (IY+d) FD CB dd 16 11111101 11001011 dddddddd 00010110 d: two's complement number +# RR (IX+d) DD CB dd 1E 11011101 11001011 dddddddd 00011110 d: two's complement number +# RR (IY+d) FD CB dd 1E 11111101 11001011 dddddddd 00011110 d: two's complement number +# SLA (IX+d) DD CB dd 26 11011101 11001011 dddddddd 00100110 d: two's complement number +# SLA (IY+d) FD CB dd 26 11111101 11001011 dddddddd 00100110 d: two's complement number +# SRA (IX+d) DD CB dd 2E 11011101 11001011 dddddddd 00101110 d: two's complement number +# SRA (IY+d) FD CB dd 2E 11111101 11001011 dddddddd 00101110 d: two's complement number +# SLL (IX+d) DD CB dd 36 11011101 11001011 dddddddd 00110110 d: two's complement number +# SLL (IY+d) FD CB dd 36 11111101 11001011 dddddddd 00110110 d: two's complement number +# SRL (IX+d) DD CB dd 3E 11011101 11001011 dddddddd 00111110 d: two's complement number +# SRL (IY+d) FD CB dd 3E 11111101 11001011 dddddddd 00111110 d: two's complement number +# xxyyyzzz + + if ($decoder_silent_level == SILENT0) + { + my $shift = $CB_shift_instr[$dcd_instr_y]; + my $str = sprintf $shift->{EXPL}, $offs_expl, $offs_expl; + + print_3($shift->{INSTR}, $offs_str, $str); + } + } + else + { +# LD r, RLC(IX+d) DD CB dd 0x 11011101 11001011 dddddddd 00000rrr d: two's complement number +# LD r, RLC(IY+d) FD CB dd 0x 11111101 11001011 dddddddd 00000rrr d: two's complement number +# LD r, RRC(IX+d) DD CB dd 0x 11011101 11001011 dddddddd 00001rrr d: two's complement number +# LD r, RRC(IY+d) FD CB dd 0x 11111101 11001011 dddddddd 00001rrr d: two's complement number +# LD r, RL(IX+d) DD CB dd 1x 11011101 11001011 dddddddd 00010rrr d: two's complement number +# LD r, RL(IY+d) FD CB dd 1x 11111101 11001011 dddddddd 00010rrr d: two's complement number +# LD r, RR(IX+d) DD CB dd 1x 11011101 11001011 dddddddd 00011rrr d: two's complement number +# LD r, RR(IY+d) FD CB dd 1x 11111101 11001011 dddddddd 00011rrr d: two's complement number +# LD r, SLA(IX+d) DD CB dd 2x 11011101 11001011 dddddddd 00100rrr d: two's complement number +# LD r, SLA(IY+d) FD CB dd 2x 11111101 11001011 dddddddd 00100rrr d: two's complement number +# LD r, SRA(IX+d) DD CB dd 2x 11011101 11001011 dddddddd 00101rrr d: two's complement number +# LD r, SRA(IY+d) FD CB dd 2x 11111101 11001011 dddddddd 00101rrr d: two's complement number +# LD r, SLL(IX+d) DD CB dd 3x 11011101 11001011 dddddddd 00110rrr d: two's complement number +# LD r, SLL(IY+d) FD CB dd 3x 11111101 11001011 dddddddd 00110rrr d: two's complement number +# LD r, SRL(IX+d) DD CB dd 3x 11011101 11001011 dddddddd 00111rrr d: two's complement number +# LD r, SRL(IY+d) FD CB dd 3x 11111101 11001011 dddddddd 00111rrr d: two's complement number +# xxyyyzzz + + if ($decoder_silent_level == SILENT0) + { + my $shift = $CB_shift_instr[$dcd_instr_y]; + my $str = sprintf $shift->{EXPL}, $offs_expl, $offs_expl; + + $i_reg = $core_registers8[$dcd_instr_z]; + print_3('ld', "$i_reg->{NAME}, $shift->{INSTR} $offs_str", "$i_reg->{EXPL} = $str"); + } + } + } # $dcd_instr_x == 0 + + when (1) + { +# BIT b, (IX+d) DD CB dd 4x 11011101 11001011 dddddddd 01bbbxxx d: two's complement number +# BIT b, (IY+d) FD CB dd 4x 11111101 11001011 dddddddd 01bbbxxx d: two's complement number +# xxyyyzzz + + print_3('bit', "$dcd_instr_y, $offs_str", "ZF = !${offs_expl}.$dcd_instr_y"); + } # $dcd_instr_x == 1 + + when (2) + { + if ($dcd_instr_z == 6) + { +# RES b, (IX+d) DD CB dd xx 11011101 11001011 dddddddd 10bbb110 d: two's complement number +# RES b, (IY+d) FD CB dd xx 11111101 11001011 dddddddd 10bbb110 d: two's complement number +# xxyyyzzz + + print_3('res', "$dcd_instr_y, $offs_str", "${offs_expl}.$dcd_instr_y = 0"); + } + else + { +# LD r, RES b, (IX+d) DD CB dd xx 11011101 11001011 dddddddd 10bbbrrr d: two's complement number +# LD r, RES b, (IY+d) FD CB dd xx 11111101 11001011 dddddddd 10bbbrrr d: two's complement number +# xxyyyzzz + + $i_reg = $core_registers8[$dcd_instr_z]; + print_3('ld', "$i_reg->{NAME}, res $dcd_instr_y, $offs_str", "${offs_expl}.$dcd_instr_y = 0; $i_reg->{NAME} = $offs_expl"); + } + } # $dcd_instr_x == 2 + + default + { + if ($dcd_instr_z == 6) + { +# SET b, (IX+d) DD CB dd xx 11011101 11001011 dddddddd 11bbb110 d: two's complement number +# SET b, (IY+d) FD CB dd xx 11111101 11001011 dddddddd 11bbb110 d: two's complement number +# xxyyyzzz + + print_3('set', "$dcd_instr_y, $offs_str", "${offs_expl}.$dcd_instr_y = 1"); + } + else + { +# LD r, SET b, (IX+d) DD CB dd xx 11011101 11001011 dddddddd 11bbbrrr d: two's complement number +# LD r, SET b, (IY+d) FD CB dd xx 11111101 11001011 dddddddd 11bbbrrr d: two's complement number +# xxyyyzzz + + $i_reg = $core_registers8[$dcd_instr_z]; + print_3('ld', "$i_reg->{NAME}, set $dcd_instr_y, $offs_str", "${offs_expl}.$dcd_instr_y = 1; $i_reg->{NAME} = $offs_expl"); + } + } + } # given ($dcd_instr_x) + } + +#------------------------------------------------------------------------------- + + # + # $IndexReg: IX or IY + # + +my @DDFD_instr = + ( + { + INSTR => 'add', + EXPL => 'A +=' + }, + { + INSTR => 'adc', + EXPL => 'A += CF +' + }, + { + INSTR => 'sub', + EXPL => 'A -=' + }, + { + INSTR => 'sbc', + EXPL => 'A -= CF +' + }, + { + INSTR => 'and', + EXPL => 'A &=' + }, + { + INSTR => 'xor', + EXPL => 'A ^=' + }, + { + INSTR => 'or', + EXPL => 'A |=' + }, + { + INSTR => 'cp', + EXPL => 'A ?=' + } + ); + +sub DDFD_prefix_decoder($) + { + my $IndexReg = $_[0]; + my ($addr, $offset, $offs_str, $offs_expl, $str); + + if ($dcd_parm0 == 0xCB) + { + instruction_take_to_pieces($dcd_parm2); + DDFD_CB_prefix_decoder($IndexReg); + } + else + { + instruction_take_to_pieces($dcd_parm0); + + $offset = expand_offset($dcd_parm1); + + if ($offset < 0) + { + $offs_str = "$offset($IndexReg)"; + $offs_expl = "[$IndexReg$offset]"; + } + else + { + $offs_str = "$offset($IndexReg)"; + $offs_expl = "[${IndexReg}+$offset]"; + } + + given ($dcd_instr_x) + { + when (0) + { + if ($dcd_instr_q == 1 && $dcd_instr_z == 1) + { +# ADD IX, rp DD 09 11011101 00rr1001 +# ADD IY, rp FD 09 11111101 00rr1001 +# xxppqzzz +# rp: BC, DE, IX, SP + + $str = $core_registers16c[$dcd_instr_p]; + print_3('add', "$IndexReg, $str", "$IndexReg += $str"); + } + elsif ($dcd_instr_y == 4) + { + given ($dcd_instr_z) + { + when (1) + { +# LD IX, #nn DD 21 nn nn 11011101 00100001 a7-0 a15-8 +# LD IY, #nn FD 21 nn nn 11111101 00100001 a7-0 a15-8 +# xxyyyzzz + + $str = sprintf '0x%04X', ($dcd_parm2 << 8) | $dcd_parm1; + print_3('ld', "$IndexReg, #$str", "$IndexReg = $str"); + } + + when (2) + { +# LD (nn), IX DD 22 nn nn 11011101 00100010 a7-0 a15-8 +# LD (nn), IY FD 22 nn nn 11111101 00100010 a7-0 a15-8 +# xxyyyzzz + + $addr = ($dcd_parm2 << 8) | $dcd_parm1; + + if ($decoder_silent_level == SILENT0) + { + my $name; + + $str = reg_name($addr, \$name); + print_3('ld', "($str), $IndexReg", "$name = $IndexReg"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($addr, '', FALSE); + } + } + + when (3) + { +# INC IX DD 23 11011101 00100011 +# INC IY FD 23 11111101 00100011 +# xxyyyzzz + + print_3('inc', $IndexReg, "++$IndexReg"); + } + + when (4) + { +# INC IXh DD 24 11011101 00100100 +# INC IYh FD 24 11111101 00100100 +# xxyyyzzz + + print_3('inc', "${IndexReg}h", "++${IndexReg}.h"); + } + + when (5) + { +# DEC IXh DD 25 11011101 00100101 +# DEC IYh FD 25 11111101 00100101 +# xxyyyzzz + + print_3('dec', "${IndexReg}h", "--${IndexReg}.h"); + } + + when (6) + { +# LD IXh, #n DD 26 nn 11011101 00100110 nnnnnnnn +# LD IYh, #n FD 26 nn 11111101 00100110 nnnnnnnn +# xxyyyzzz + + my $char = decode_char($dcd_parm1); + + $str = sprintf '0x%02X', $dcd_parm1; + print_3('ld', "${IndexReg}h, #$str", "${IndexReg}.h = $str$char"); + } + } # given ($dcd_instr_z) + } + elsif ($dcd_instr_y == 5) + { + given ($dcd_instr_z) + { + when (2) + { +# LD IX, (nn) DD 2A nn nn 11011101 00101010 a7-0 a15-8 +# LD IY, (nn) FD 2A nn nn 11111101 00101010 a7-0 a15-8 +# xxyyyzzz + + $addr = ($dcd_parm2 << 8) | $dcd_parm1; + + if ($decoder_silent_level == SILENT0) + { + my $name; + + $str = reg_name($addr, \$name); + print_3('ld', "$IndexReg, ($str)", "$IndexReg = $name"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($addr, '', FALSE); + } + } + + when (3) + { +# DEC IX DD 2B 11011101 00101011 +# DEC IY FD 2B 11111101 00101011 +# xxyyyzzz + + print_3('dec', $IndexReg, "--$IndexReg"); + } + + when (4) + { +# INC IXl DD 2C 11011101 00101100 +# INC IYl FD 2C 11111101 00101100 +# xxyyyzzz + + print_3('inc', "${IndexReg}l", "++${IndexReg}.l"); + } + + when (5) + { +# DEC IXl DD 2D 11011101 00101101 +# DEC IYl FD 2D 11111101 00101101 +# xxyyyzzz + + print_3('dec', "${IndexReg}l", "--${IndexReg}.l"); + } + + when (6) + { +# LD IXl, #n DD 2E nn 11011101 00101110 nnnnnnnn +# LD IYl, #n FD 2E nn 11111101 00101110 nnnnnnnn +# xxyyyzzz + + my $char = decode_char($dcd_parm1); + + $str = sprintf '0x%02X', $dcd_parm1; + print_3('ld', "${IndexReg}l, #$str", "${IndexReg}.l = $str$char"); + } + } # given ($dcd_instr_z) + } + elsif ($dcd_instr_y == 6) + { + given ($dcd_instr_z) + { + when (4) + { +# INC (IX+d) DD 34 dd 11011101 00110100 dddddddd d: two's complement number +# INC (IY+d) FD 34 dd 11111101 00110100 dddddddd d: two's complement number +# xxyyyzzz + + print_3('inc', $offs_str, "++$offs_expl"); + } + + when (5) + { +# DEC (IX+d) DD 35 dd 11011101 00110101 dddddddd d: two's complement number +# DEC (IY+d) FD 35 dd 11111101 00110101 dddddddd d: two's complement number +# xxyyyzzz + + print_3('dec', $offs_str, "--$offs_expl"); + } + + when (6) + { +# LD (IX+d), #n DD 36 dd nn 11011101 00110110 dddddddd nnnnnnnn d: two's complement number +# LD (IY+d), #n FD 36 dd nn 11111101 00110110 dddddddd nnnnnnnn d: two's complement number +# xxyyyzzz + + my $char = decode_char($dcd_parm2); + + $str = sprintf '0x%02X', $dcd_parm2; + print_3('ld', "$offs_str, #$str", "$offs_expl = $str$char"); + } + } # given ($dcd_instr_z) + } + } # $dcd_instr_x == 0 + + when (1) + { + given ($dcd_instr_y) + { + when ([0 .. 3]) + { + given ($dcd_instr_z) + { + when (4) + { +# LD r, IXh DD 44 11011101 010rr100 +# LD r, IYh FD 44 11111101 010rr100 +# xxyyyzzz +# r: B, C, D, E + + $str = $core_registers8[$dcd_instr_y]->{NAME}; + print_3('ld', "$str, ${IndexReg}h", "$str = ${IndexReg}.h"); + } + + when (5) + { + +# LD r, IXl DD 45 11011101 010rr101 +# LD r, IYl FD 45 11111101 010rr101 +# xxyyyzzz +# r: B, C, D, E + + $str = $core_registers8[$dcd_instr_y]->{NAME}; + print_3('ld', "$str, ${IndexReg}l", "$str = ${IndexReg}.l"); + } + + when (6) + { + +# LD r, (IX+d) DD 46 dd 11011101 010rr110 dddddddd d: two's complement number +# LD r, (IY+d) FD 46 dd 11111101 010rr110 dddddddd d: two's complement number +# xxyyyzzz +# r: B, C, D, E + + $str = $core_registers8[$dcd_instr_y]->{NAME}; + print_3('ld', "$str, $offs_str", "$str = $offs_expl"); + } + } # given ($dcd_instr_z) + } # when ([0 .. 3]) + + when ([4, 5]) + { + my $r = ($dcd_instr_y == 4) ? 'h' : 'l'; + + given ($dcd_instr_z) + { + when ([0 .. 3]) + { +# LD IXh, B DD 60 11011101 011000rr +# LD IYh, B FD 60 11111101 011000rr +# LD IXh, C DD 61 11011101 01100001 +# LD IYh, C FD 61 11111101 01100001 +# LD IXh, D DD 62 11011101 01100010 +# LD IYh, D FD 62 11111101 01100010 +# LD IXh, E DD 63 11011101 01100011 +# LD IYh, E FD 63 11111101 01100011 +# xxyyyzzz +# r: B, C, D, E + + $str = $core_registers8[$dcd_instr_z]->{NAME}; + print_3('ld', "$IndexReg$r, $str", "$IndexReg$r = $str"); + } + + when (4) + { +# LD IXh, IXh DD 64 11011101 01100100 +# LD IYh, IYh FD 64 11111101 01100100 +# xxyyyzzz + + print_3('ld', "$IndexReg$r, {IndexReg}h", "$IndexReg$r = {IndexReg}.h"); + } + + when (5) + { +# LD IXh, IXl DD 65 11011101 01100101 +# LD IYh, IYl FD 65 11111101 01100101 +# xxyyyzzz + + print_3('ld', "$IndexReg$r, {IndexReg}l", "$IndexReg$r = {IndexReg}.l"); + } + + when (6) + { +# LD H, (IX+d) DD 66 dd 11011101 01100110 dddddddd d: two's complement number +# LD H, (IY+d) FD 66 dd 11111101 01100110 dddddddd d: two's complement number +# xxyyyzzz + + $str = uc($r); + print_3('ld', "$str, $offs_str", "$str = $offs_expl"); + } + + when (7) + { +# LD IXh, A DD 67 11011101 01100111 +# LD IYh, A FD 67 11111101 01100111 +# xxyyyzzz + + print_3('ld', "$IndexReg$r, A", "$IndexReg$r = A"); + } + } # given ($dcd_instr_z) + } # when ([4, 5]) + + when (6) + { +# LD (IX+d), r DD 70 dd 11011101 01110rrr dddddddd d: two's complement number +# LD (IY+d), r FD 70 dd 11111101 01110rrr dddddddd d: two's complement number +# xxyyyzzz +# r: B, C, D, E, H, L, -, A + + $str = $core_registers8[$dcd_instr_z]->{NAME}; + print_3('ld', "$offs_str, $str", "$offs_expl = $str"); + } + + default + { + given ($dcd_instr_z) + { + when (4) + { +# LD A, IXh DD 7C 11011101 01111100 +# LD A, IYh FD 7C 11111101 01111100 +# xxyyyzzz + + print_3('ld', "A, ${IndexReg}h", "A = ${IndexReg}.h"); + } + + when (5) + { +# LD A, IXl DD 7D 11011101 01111101 +# LD A, IYl FD 7D 11111101 01111101 +# xxyyyzzz + + print_3('ld', "A, ${IndexReg}l", "A = ${IndexReg}.l"); + } + + when (6) + { +# LD A, (IX+d) DD 7E dd 11011101 01111110 dddddddd d: two's complement number +# LD A, (IY+d) FD 7E dd 11111101 01111110 dddddddd d: two's complement number +# xxyyyzzz + + print_3('ld', "A, $offs_str", "A = $offs_expl"); + } + } # given ($dcd_instr_z) + } + } # given ($dcd_instr_y) + } # $dcd_instr_x == 1 + + when (2) + { + given ($dcd_instr_z) + { + when (4) + { +# ADD A, IXh DD 84 11011101 10000100 +# ADD A, IYh FD 84 11111101 10000100 +# ADC A, IXh DD 8C 11011101 10001100 +# ADC A, IYh FD 8C 11111101 10001100 +# SUB A, IXh DD 94 11011101 10010100 +# SUB A, IYh FD 94 11111101 10010100 +# SBC A, IXh DD 9C 11011101 10011100 +# SBC A, IYh FD 9C 11111101 10011100 +# AND A, IXh DD A4 11011101 10100100 +# AND A, IYh FD A4 11111101 10100100 +# XOR A, IXh DD AC 11011101 10101100 +# XOR A, IYh FD AC 11111101 10101100 +# OR A, IXh DD B4 11011101 10110100 +# OR A, IYh FD B4 11111101 10110100 +# CP A, IXh DD BC 11011101 10111100 +# CP A, IYh FD BC 11111101 10111100 +# xxyyyzzz + + my $i_arith = $DDFD_instr[$dcd_instr_y]; + + print_3($i_arith->{INSTR}, "A, ${IndexReg}h", "$i_arith->{EXPL} ${IndexReg}.h"); + } + + when (5) + { +# ADD A, IXl DD 85 11011101 10000101 +# ADD A, IYl FD 85 11111101 10000101 +# ADC A, IXl DD 8D 11011101 10001101 +# ADC A, IYl FD 8D 11111101 10001101 +# SUB A, IXl DD 95 11011101 10010101 +# SUB A, IYl FD 95 11111101 10010101 +# SBC A, IXl DD 9D 11011101 10011101 +# SBC A, IYl FD 9D 11111101 10011101 +# AND A, IXl DD A5 11011101 10100101 +# AND A, IYl FD A5 11111101 10100101 +# XOR A, IXl DD AD 11011101 10101101 +# XOR A, IYl FD AD 11111101 10101101 +# OR A, IXl DD B5 11011101 10110101 +# OR A, IYl FD B5 11111101 10110101 +# CP A, IXl DD BD 11011101 10111101 +# CP A, IYl FD BD 11111101 10111101 +# xxyyyzzz + + my $i_arith = $DDFD_instr[$dcd_instr_y]; + + print_3($i_arith->{INSTR}, "A, ${IndexReg}l", "$i_arith->{EXPL} ${IndexReg}.l"); + } + + when (6) + { +# ADD A, (IX+d) DD 86 dd 11011101 10000110 dddddddd d: two's complement number +# ADD A, (IY+d) FD 86 dd 11111101 10000110 dddddddd d: two's complement number +# ADC A, (IX+d) DD 8E dd 11011101 10001110 dddddddd d: two's complement number +# ADC A, (IY+d) FD 8E dd 11111101 10001110 dddddddd d: two's complement number +# SUB A, (IX+d) DD 96 dd 11011101 10010110 dddddddd d: two's complement number +# SUB A, (IY+d) FD 96 dd 11111101 10010110 dddddddd d: two's complement number +# SBC A, (IX+d) DD 9E dd 11011101 10011110 dddddddd d: two's complement number +# SBC A, (IY+d) FD 9E dd 11111101 10011110 dddddddd d: two's complement number +# AND A, (IX+d) DD A6 dd 11011101 10100110 dddddddd d: two's complement number +# AND A, (IY+d) FD A6 dd 11111101 10100110 dddddddd d: two's complement number +# XOR A, (IX+d) DD AE dd 11011101 10101110 dddddddd d: two's complement number +# XOR A, (IY+d) FD AE dd 11111101 10101110 dddddddd d: two's complement number +# OR A, (IX+d) DD B6 dd 11011101 10110110 dddddddd d: two's complement number +# OR A, (IY+d) FD B6 dd 11111101 10110110 dddddddd d: two's complement number +# CP A, (IX+d) DD BE dd 11011101 10111110 dddddddd d: two's complement number +# CP A, (IY+d) FD BE dd 11111101 10111110 dddddddd d: two's complement number +# xxyyyzzz + + my $i_arith = $DDFD_instr[$dcd_instr_y]; + + print_3($i_arith->{INSTR}, "A, $offs_str", "$i_arith->{EXPL} $offs_expl"); + } + } # given ($dcd_instr_z) + } # $dcd_instr_x == 2 + + default + { + given ($dcd_parm0) + { + when (0xE1) + { +# POP IX DD E1 11011101 11100001 +# POP IY FD E1 11111101 11100001 + + print_3('pop', $IndexReg, "${IndexReg}.l = [SP++]; ${IndexReg}.h = [SP++]"); + } + + when (0xE3) + { +# EX (SP), IX DD E3 11011101 11100011 +# EX (SP), IY FD E3 11111101 11100011 + + print_3('ex', "(SP), $IndexReg", "[SP] <-> ${IndexReg}.l; [SP+1] <-> ${IndexReg}.h"); + } + + when (0xE5) + { +# PUSH IX DD E5 11011101 11100101 +# PUSH IY FD E5 11111101 11100101 + + print_3('push', $IndexReg, "[--SP] = ${IndexReg}.h; [--SP] = ${IndexReg}.l"); + } + + when (0xE9) + { +# JP (IX) DD E9 11011101 11101001 +# JP (IY) FD E9 11111101 11101001 + + print_3('jp', "($IndexReg)", "Jumps hither: [$IndexReg]"); + $prev_is_jump = TRUE; + } + + when (0xF9) + { +# LD SP, IX DD F9 11011101 11111001 +# LD SP, IY FD F9 11111101 11111001 + + print_3('ld', "SP, $IndexReg", "SP = $IndexReg"); + } + } # given ($dcd_parm0) + } # $dcd_instr_x == 3 + } # given ($dcd_instr_x) + } + } + +#------------------------------------------------------------------------------- + +my @block_instr = + ( + [ + { + INSTR => 'ldi', + EXPL => '[DE++] = [HL++]; --BC' + }, + { + INSTR => 'cpi', + EXPL => 'A ?= [HL++]; --BC' + }, + { + INSTR => 'ini', + EXPL => '[HL++] = In{C}; --B' + }, + { + INSTR => 'outi', + EXPL => 'Out{C} = [HL++]; --B' + } + ], + [ + { + INSTR => 'ldd', + EXPL => '[DE--] = [HL--]; --BC' + }, + { + INSTR => 'cpd', + EXPL => 'A ?= [HL--]; --BC' + }, + { + INSTR => 'ind', + EXPL => '[HL--] = In{C}; --B' + }, + { + INSTR => 'outd', + EXPL => 'Out{C} = [HL--]; --B' + } + ], + [ + { + INSTR => 'ldir', + EXPL => '[DE++] = [HL++]; --BC; Exit this loop, then BC == 0.' + }, + { + INSTR => 'cpir', + EXPL => 'A ?= [HL++]; --BC; Exit this loop, then BC == 0 or A == [HL].' + }, + { + INSTR => 'inir', + EXPL => '[HL++] = In{C}; --B; Exit this loop, then B == 0.' + }, + { + INSTR => 'otir', + EXPL => 'Out{C} = [HL++]; --B; Exit this loop, then B == 0.' + } + ], + [ + { + INSTR => 'lddr', + EXPL => '[DE--] = [HL--]; --BC; Exit this loop, then BC == 0.' + }, + { + INSTR => 'cpdr', + EXPL => 'A ?= [HL--]; --BC; Exit this loop, then BC == 0 or A == [HL].' + }, + { + INSTR => 'indr', + EXPL => '[HL--] = In{C}; --B; Exit this loop, then B == 0.' + }, + { + INSTR => 'otdr', + EXPL => 'Out{C} = [HL--]; --B; Exit this loop, then B == 0.' + } + ] + ); + +sub ED_prefix_decoder() + { + my ($addr, $str, $i_reg, $reg); + + instruction_take_to_pieces($dcd_parm0); + + if ($dcd_instr_x == 1) + { + given ($dcd_instr_z) + { + when (0) + { + if ($decoder_silent_level == SILENT0) + { + $i_reg = $core_registers8[$dcd_instr_z]; + + if ($dcd_instr_y == 6) + { +# IN (C) ED 70 11101011 01110000 +# xxyyyzzz + + print_3('in', '(C)', "$i_reg->{EXPL} = In{[C]}"); + } + else + { +# IN r, (C) ED xx 11101011 01rrr000 +# xxyyyzzz + + print_3('in', "$i_reg->{NAME}, (C)", "$i_reg->{EXPL} = In{[C]}"); + } + } + } # $dcd_instr_z == 0 + + when (1) + { + if ($decoder_silent_level == SILENT0) + { + $i_reg = $core_registers8[$dcd_instr_z]; + + if ($dcd_instr_y == 6) + { +# OUT (C) ED 71 11101101 01110001 +# xxyyyzzz + + print_3('out', '(C)', "Out{[C]} = $i_reg->{EXPL}"); + } + else + { +# OUT (C), r ED xx 11101101 01rrr001 +# xxyyyzzz + + print_3('out', "(C), $i_reg->{NAME}", "Out{[C]} = $i_reg->{EXPL}"); + } + } + } # $dcd_instr_z == 1 + + when (2) + { + if ($dcd_instr_q == 0) + { +# SBC HL, pp ED x2 11101101 01pp0010 +# xxppqzzz + + $str = $core_registers16a[$dcd_instr_p]; + print_3('sbc', "HL, $str", "HL -= $str + CF"); + } + else + { +# ADC HL, pp ED xA 11101101 01pp1010 +# xxppqzzz + + $str = $core_registers16a[$dcd_instr_p]; + print_3('adc', "HL, $str", "HL += $str + CF"); + } + } # $dcd_instr_z == 2 + + when (3) + { + $addr = ($dcd_parm2 << 8) | $dcd_parm1; + + if ($dcd_instr_q == 0) + { +# LD (nn), pp ED x3 aa aa 11101101 01pp0011 a7-0 a15-8 +# xxppqzzz + + if ($decoder_silent_level == SILENT0) + { + my $name; + + $reg = $core_registers16a[$dcd_instr_p]; + $str = reg_name($addr, \$name); + print_3('ld', "($str), $reg", "$name = $reg"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($addr, '', FALSE); + } + } + else + { +# LD pp, (nn) ED xB aa aa 11101101 01pp1011 a7-0 a15-8 +# xxppqzzz + + if ($decoder_silent_level == SILENT0) + { + my $name; + + $reg = $core_registers16a[$dcd_instr_p]; + $str = reg_name($addr, \$name); + print_3('ld', "$reg, ($str)", "$reg = $name"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($addr, '', FALSE); + } + } + } # $dcd_instr_z == 3 + + when (4) + { +# NEG ED xx 11101101 01xxx100 +# xxyyyzzz + + print_3('neg', '', 'A = -A'); + } # $dcd_instr_z == 4 + + when (5) + { + if ($dcd_instr_y == 1) + { +# RETI ED 4D 11101101 01001101 +# xxyyyzzz + + print_3('reti', '', 'PC.l = [SP++]; PC.h = [SP++]; End of maskable interrupt.'); + $prev_is_jump = TRUE; + } + else + { +# RETN ED xx 11101101 01xxx101 +# xxyyyzzz + + print_3('retn', '', 'PC.l = [SP++]; PC.h = [SP++]; End of non-maskable interrupt.'); + $prev_is_jump = TRUE; + } + } # $dcd_instr_z == 5 + + when (6) + { +# IM n ED xx 11101101 01xxx110 +# xxyyyzzz +# y: 0 - im 0 +# 1 - im 0 +# 2 - im 1 +# 3 - im 2 +# 4 - im 0 +# 5 - im 0 +# 6 - im 1 +# 7 - im 2 + + $dcd_instr_y &= 3; + --$dcd_instr_y if ($dcd_instr_y); + + print_3('im', $dcd_instr_y, "Interrupt mode ${dcd_instr_y}."); + } # $dcd_instr_z == 6 + + when (7) + { + given ($dcd_instr_y) + { + when (0) + { +# LD I, A ED 47 11101101 01000111 +# xxyyyzzz + + print_3('ld', 'I, A', 'I = A'); + } + + when (1) + { +# LD R, A ED 4F 11101101 01001111 +# xxyyyzzz + + print_3('ld', 'R, A', 'R = A'); + } + + when (2) + { +# LD A, I ED 57 11101101 01010111 +# xxyyyzzz + + print_3('ld', 'A, I', 'A = I'); + } + + when (3) + { +# LD A, R ED 5F 11101101 01011111 +# xxyyyzzz + + print_3('ld', 'A, R', 'A = R'); + } + + when (4) + { +# RRD ED 67 11101101 01100111 +# xxyyyzzz + + print_3('rrd', '', 'A[3..0] -> [HL][7..4] -> [HL][3..0] -> A[3..0]'); + } + + when (5) + { +# RLD ED 6F 11101101 01101111 +# xxyyyzzz + + print_3('rld', '', 'A[3..0] <- [HL][7..4] <- [HL][3..0] <- A[3..0]'); + } + + default + { +# NOP ED 77 11101101 01110111 +# NOP ED 7F 11101101 01111111 +# xxyyyzzz + + print_3('nop', '', 'No operation.'); + } # $dcd_instr_y == 6 || $dcd_instr_y == 7 + } # given ($dcd_instr_y) + } # $dcd_instr_z == 7 + } # given ($dcd_instr_z) + } # if ($dcd_instr_x == 1) + elsif ($dcd_instr_x == 2 && $dcd_instr_y >= 4 && $dcd_instr_z <= 3) + { +# LDI ED A0 11101101 10100000 +# CPI ED A1 11101101 10100001 +# INI ED A2 11101101 10100010 +# OUTI ED A3 11101101 10100011 +# xxyyyzzz + +# LDD ED A8 11101101 10101000 +# CPD ED A9 11101101 10101001 +# IND ED AA 11101101 10101010 +# OUTD ED AB 11101101 10101011 +# xxyyyzzz + +# LDIR ED B0 11101101 10110000 +# CPIR ED B1 11101101 10110001 +# INIR ED B2 11101101 10110010 +# OTIR ED B3 11101101 10110011 +# xxyyyzzz + +# LDDR ED B8 11101101 10111000 +# CPDR ED B9 11101101 10111001 +# INDR ED BA 11101101 10111010 +# OTDR ED BB 11101101 10111011 +# xxyyyzzz + + my $i_block = $block_instr[$dcd_instr_y - 4][$dcd_instr_z]; + + print_3($i_block->{INSTR}, '', $i_block->{EXPL}); + } + else + { + print_3('invalid instruction', '', ''); + } + } + +#------------------------------------------------------------------------------- + +sub instruction_take_to_pieces($) + { + my $Instruction = $_[0]; + + $dcd_instr_x = ($Instruction >> 6) & 3; + $dcd_instr_y = ($Instruction >> 3) & 7; + $dcd_instr_z = $Instruction & 7; + $dcd_instr_p = ($Instruction >> 4) & 3; + $dcd_instr_q = ($Instruction >> 3) & 1; + } + +#------------------------------------------------------------------------------- + + # + # Decodes the $BlockRef. + # + +my @shift_instr = + ( + { + INSTR => 'rlca', + EXPL => 'CF <- A[7..0] <- A.7' + }, + { + INSTR => 'rrca', + EXPL => 'A.0 -> A[7..0] -> CF' + }, + { + INSTR => 'rla', + EXPL => 'CF <- A[7..0] <- CF' + }, + { + INSTR => 'rra', + EXPL => 'CF -> A[7..0] -> CF' + }, + { + INSTR => 'daa', + EXPL => 'Conditionally decimal adjusts the Accumulator.' + }, + { + INSTR => 'cpl', + EXPL => 'A = ~A' + }, + { + INSTR => 'scf', + EXPL => 'CF = 1' + }, + { + INSTR => 'ccf', + EXPL => 'CF = 0' + } + ); + +my @conditions = + ( + { + COND => 'NZ', + EXPL => 'ZF == 0' + }, + { + COND => 'Z', + EXPL => 'ZF == 1' + }, + { + COND => 'NC', + EXPL => 'CF == 0' + }, + { + COND => 'C', + EXPL => 'CF == 1' + }, + { + COND => 'PO', + EXPL => 'PF == 0' + }, + { + COND => 'PE', + EXPL => 'PF == 1' + }, + { + COND => 'P', + EXPL => 'SF == 0' + }, + { + COND => 'M', + EXPL => 'SF == 1' + } + ); + +sub instruction_decoder($$) + { + my ($Address, $BlockRef) = @_; + my ($addr, $label, $invalid, $str); + + $dcd_address = $Address; + $dcd_instr_size = $BlockRef->{SIZE}; + $dcd_instr = $rom[$dcd_address]; + $label = $BlockRef->{LABEL}; + + if ($decoder_silent_level == SILENT0) + { + printf("0x%04X: %02X", $dcd_address, $dcd_instr) if (! $gen_assembly_code); + } + + $invalid = FALSE; + + if ($dcd_instr_size == 1) + { + if ($decoder_silent_level == SILENT0) + { + print(($gen_assembly_code) ? "\t" : "\t\t"); + } + } + elsif ($dcd_instr_size == 2) + { + $dcd_parm0 = $rom[$dcd_address + 1]; + $invalid = TRUE if ($dcd_parm0 == EMPTY); + + if ($decoder_silent_level == SILENT0) + { + if ($gen_assembly_code) + { + print "\t"; + } + else + { + printf " %02X\t\t", $dcd_parm0; + } + } + } + elsif ($dcd_instr_size == 3) + { + $dcd_parm0 = $rom[$dcd_address + 1]; + $dcd_parm1 = $rom[$dcd_address + 2]; + $invalid = TRUE if ($dcd_parm0 == EMPTY || $dcd_parm1 == EMPTY); + + if ($decoder_silent_level == SILENT0) + { + if ($gen_assembly_code) + { + print "\t"; + } + else + { + printf " %02X %02X\t", $dcd_parm0, $dcd_parm1; + } + } + } + elsif ($dcd_instr_size == 4) + { + $dcd_parm0 = $rom[$dcd_address + 1]; + $dcd_parm1 = $rom[$dcd_address + 2]; + $dcd_parm2 = $rom[$dcd_address + 3]; + $invalid = TRUE if ($dcd_parm0 == EMPTY || $dcd_parm1 == EMPTY || $dcd_parm2 == EMPTY); + + if ($decoder_silent_level == SILENT0) + { + if ($gen_assembly_code) + { + print "\t"; + } + else + { + printf " %02X %02X %02X\t", $dcd_parm0, $dcd_parm1, $dcd_parm2; + } + } + } + else + { + printf STDERR "Internal error: The size of instruction (addr:0x%04X) is zero!", $dcd_address; + exit(1); + } + + # + # x y z + # +---/ \---+ +------/ \------+ +------/ \------+ + # | | | | | | + # | 7 6 | | 5 4 3 | | 2 1 0 | + # +-----------------------------------------------+ + # | . | . | . | . | . | . | . | . | + # +-----------------------------------------------+ + # | 5 4 | | 3 | + # | | | | + # +---\ /---+ +\ /+ + # p q + # + + $prev_is_jump = FALSE; + + instruction_take_to_pieces($dcd_instr); + + if ($dcd_instr_x == 0) + { + # x y z + # +---/ \---+ +------/ \------+ +------/ \------+ + # | 7 6 | | 5 4 3 | | 2 1 0 | + # +-----------------------------------------------+ + # | 0 | 0 | . | . | . | . | . | . | + # +-----------------------------------------------+ + # | 5 4 | | 3 | + # +---\ /---+ +\ /+ + # p q + + given ($dcd_instr_z) + { + when (0) + { + # x y z + # +---/ \---+ +------/ \------+ +------/ \------+ + # | 7 6 | | 5 4 3 | | 2 1 0 | + # +-----------------------------------------------+ + # | 0 | 0 | . | . | . | 0 | 0 | 0 | + # +-----------------------------------------------+ + + given ($dcd_instr_y) + { + when (0) + { +# NOP 00 00000000 +# xxyyyzzz + + print_3('nop', '', 'No operation.'); + } + + when (1) + { +# EX AF, AF' 08 00001000 +# xxyyyzzz + + print_3('ex', "AF, AF'", "AF <-> AF'"); + } + + when (2) + { +# DJNZ e 10 00010000 eeeeeeee e: two's complement number +# xxyyyzzz + + if ($decoder_silent_level == SILENT0) + { + my $addr = $dcd_address + 2 + expand_offset($dcd_parm0); + my $target; + + $str = label_name($addr); + $target = jump_direction($addr); + print_3('djnz', $str, "If (--B != 0) jumps$target"); + $prev_is_jump = TRUE; + } + } + + when (3) + { +# JR e 18 00011000 eeeeeeee e: two's complement number +# xxyyyzzz + + if ($decoder_silent_level == SILENT0) + { + my $addr = $dcd_address + 2 + expand_offset($dcd_parm0); + my $target; + + $str = label_name($addr); + $target = jump_direction($addr); + print_3('jr', $str, "Jumps$target"); + $prev_is_jump = TRUE; + } + } + + default + { + # 4-7 +# JR cc, e xx 00ccc000 eeeeeeee e: two's complement number +# xxyyyzzz + + if ($decoder_silent_level == SILENT0) + { + my $addr = $dcd_address + 2 + expand_offset($dcd_parm0); + my $cond = $conditions[$dcd_instr_y - 4]; + my $target; + + $str = label_name($addr); + $target = jump_direction($addr); + print_3('jr', "$cond->{COND}, $str", "Jumps if ($cond->{EXPL})$target"); + $prev_is_jump = TRUE; + } + } + } # given ($dcd_instr_y) + } # $dcd_instr_z == 0 + + when (1) + { + # x z + # +---/ \---+ +------/ \------+ + # | 7 6 | | 2 1 0 | + # +-----------------------------------------------+ + # | 0 | 0 | . | . | . | 0 | 0 | 1 | + # +-----------------------------------------------+ + # | 5 4 | | 3 | + # +---\ /---+ +\ /+ + # p q + + if ($dcd_instr_q == 0) + { +# LD rp, #nn x1 00rr0001 nnnnnnnn nnnnnnnn +# xxppqzzz +# rp: BC, DE, HL, SP + + my $r16 = $core_registers16a[$dcd_instr_p]; + + $str = sprintf '0x%04X', ($dcd_parm1 << 8) | $dcd_parm0; + print_3('ld', "$r16, #$str", "$r16 = $str"); + } + else + { +# ADD HL, rp x9 00rr1001 +# xxppqzzz +# rp: BC, DE, HL, SP + + $str = $core_registers16a[$dcd_instr_p]; + print_3('add', "HL, $str", "HL += $str"); + } + } # $dcd_instr_z == 1 + + when (2) + { + # x y z + # +---/ \---+ +------/ \------+ +------/ \------+ + # | 7 6 | | 5 4 3 | | 2 1 0 | + # +-----------------------------------------------+ + # | 0 | 0 | . | . | . | 0 | 1 | 0 | + # +-----------------------------------------------+ + # | 5 4 | | 3 | + # +---\ /---+ +\ /+ + # p q + + if ($dcd_instr_q == 0) + { + # x z + # +---/ \---+ +------/ \------+ + # | 7 6 | | 2 1 0 | + # +-----------------------------------------------+ + # | 0 | 0 | . | . | 0 | 0 | 1 | 0 | + # +-----------------------------------------------+ + # | 5 4 | | 3 | + # +---\ /---+ +\ /+ + # p q + + given ($dcd_instr_p) + { + when (0) + { +# LD (BC), A 02 00000010 +# xxppqzzz + + print_3('ld', '(BC), A', '[BC] = A'); + } # $dcd_instr_p == 0 + + when (1) + { +# LD (DE), A 12 00010010 +# xxppqzzz + + print_3('ld', '(DE), A', '[DE] = A'); + } # $dcd_instr_p == 1 + + when (2) + { +# LD (nn), HL 22 00100010 nnnnnnnn nnnnnnnn +# xxppqzzz + + $addr = ($dcd_parm1 << 8) | $dcd_parm0; + + if ($decoder_silent_level == SILENT0) + { + my $name; + + $str = reg_name($addr, \$name); + print_3('ld', "($str), HL", "$name = HL"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($addr, '', FALSE); + } + } # $dcd_instr_p == 2 + + when (3) + { +# LD (nn), A 32 00110010 nnnnnnnn nnnnnnnn +# xxppqzzz + + $addr = ($dcd_parm1 << 8) | $dcd_parm0; + + if ($decoder_silent_level == SILENT0) + { + my $name; + + $str = reg_name($addr, \$name); + print_3('ld', "($str), A", "$name = A"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($addr, '', FALSE); + } + } # $dcd_instr_p == 3 + } # given ($dcd_instr_p) + } # if ($dcd_instr_q == 0) + else + { + # x z + # +---/ \---+ +------/ \------+ + # | 7 6 | | 2 1 0 | + # +-----------------------------------------------+ + # | 0 | 0 | . | . | 1 | 0 | 1 | 0 | + # +-----------------------------------------------+ + # | 5 4 | | 3 | + # +---\ /---+ +\ /+ + # p q + + given ($dcd_instr_p) + { + when (0) + { +# LD A, (BC) 0A 00001010 +# xxppqzzz + + print_3('ld', 'A, (BC)', 'A = [BC]'); + } # $dcd_instr_p == 0 + + when (1) + { +# LD A, (DE) 1A 00011010 +# xxppqzzz + + print_3('ld', 'A, (DE)', 'A = [DE]'); + } # $dcd_instr_p == 1 + + when (2) + { +# LD HL, (nn) 2A 00101010 nnnnnnnn nnnnnnnn +# xxppqzzz + + $addr = ($dcd_parm1 << 8) | $dcd_parm0; + + if ($decoder_silent_level == SILENT0) + { + my $name; + + $str = reg_name($addr, \$name); + print_3('ld', "HL, ($str)", "HL = $name"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($addr, '', FALSE); + } + } # $dcd_instr_p == 2 + + when (3) + { +# LD A, (nn) 3A 00111010 nnnnnnnn nnnnnnnn +# xxppqzzz + + $addr = ($dcd_parm1 << 8) | $dcd_parm0; + + if ($decoder_silent_level == SILENT0) + { + my $name; + + $str = reg_name($addr, \$name); + print_3('ld', "A, ($str)", "A = $name"); + } + elsif ($decoder_silent_level == SILENT1) + { + add_ram($addr, '', FALSE); + } + } # $dcd_instr_p == 3 + } # given ($dcd_instr_p) + } + } # $dcd_instr_z == 2 + + when (3) + { + # x z + # +---/ \---+ +------/ \------+ + # | 7 6 | | 2 1 0 | + # +-----------------------------------------------+ + # | 0 | 0 | . | . | . | 0 | 1 | 1 | + # +-----------------------------------------------+ + # | 5 4 | | 3 | + # +---\ /---+ +\ /+ + # p q + + if ($dcd_instr_q == 0) + { +# INC rp x3 00rr0011 +# xxppqzzz +# rp: BC, DE, HL, SP + + $str = $core_registers16a[$dcd_instr_p]; + print_3('inc', $str, "++$str"); + } + else + { +# DEC rp x3 00rr1011 +# xxppqzzz +# rp: BC, DE, HL, SP + + $str = $core_registers16a[$dcd_instr_p]; + print_3('dec', $str, "--$str"); + } + } # $dcd_instr_z == 3 + + when (4) + { + # x y z + # +---/ \---+ +------/ \------+ +------/ \------+ + # | 7 6 | | 5 4 3 | | 2 1 0 | + # +-----------------------------------------------+ + # | 0 | 0 | . | . | . | 1 | 0 | 0 | + # +-----------------------------------------------+ + +# INC r xx 00rrr100 +# xxyyyzzz +# r: B, C, D, E, H, L, (HL), A + + if ($decoder_silent_level == SILENT0) + { + my $i_reg = $core_registers8[$dcd_instr_y]; + + print_3('inc', $i_reg->{NAME}, "++$i_reg->{EXPL}"); + } + } # $dcd_instr_z == 4 + + when (5) + { + # x y z + # +---/ \---+ +------/ \------+ +------/ \------+ + # | 7 6 | | 5 4 3 | | 2 1 0 | + # +-----------------------------------------------+ + # | 0 | 0 | . | . | . | 1 | 0 | 1 | + # +-----------------------------------------------+ + +# DEC r xx 00rrr101 +# xxyyyzzz +# r: B, C, D, E, H, L, (HL), A + + if ($decoder_silent_level == SILENT0) + { + my $i_reg = $core_registers8[$dcd_instr_y]; + + print_3('dec', $i_reg->{NAME}, "--$i_reg->{EXPL}"); + } + } # $dcd_instr_z == 5 + + when (6) + { + # x y z + # +---/ \---+ +------/ \------+ +------/ \------+ + # | 7 6 | | 5 4 3 | | 2 1 0 | + # +-----------------------------------------------+ + # | 0 | 0 | . | . | . | 1 | 1 | 0 | + # +-----------------------------------------------+ + +# LD r, #n 00rrr110 nnnnnnnn +# xxyyyzzz + + if ($decoder_silent_level == SILENT0) + { + my $i_reg = $core_registers8[$dcd_instr_y]; + my $char = decode_char($dcd_parm0); + + $str = sprintf '0x%02X', $dcd_parm0; + print_3('ld', "$i_reg->{NAME}, #$str", "$i_reg->{EXPL} = $str$char"); + } + } # $dcd_instr_z == 6 + + when (7) + { + # x y z + # +---/ \---+ +------/ \------+ +------/ \------+ + # | 7 6 | | 5 4 3 | | 2 1 0 | + # +-----------------------------------------------+ + # | 0 | 0 | . | . | . | 1 | 1 | 1 | + # +-----------------------------------------------+ + +# RLCA 07 00000111 +# RRCA 0F 00001111 +# RLA 17 00010111 +# RRA 1F 00011111 +# DAA 27 00100111 +# CPL 2F 00101111 +# SCF 37 00110111 +# CCF 3F 00111111 +# xxyyyzzz + + my $s_instr = $shift_instr[$dcd_instr_y]; + + print_3($s_instr->{INSTR}, '', $s_instr->{EXPL}); + } # $dcd_instr_z == 7 + } # given ($dcd_instr_z) + } # if ($dcd_instr_x == 0) + elsif ($dcd_instr_x == 1) + { + # x y z + # +---/ \---+ +------/ \------+ +------/ \------+ + # | 7 6 | | 5 4 3 | | 2 1 0 | + # +-----------------------------------------------+ + # | 0 | 1 | . | . | . | . | . | . | + # +-----------------------------------------------+ + + if ($dcd_instr_y == 6) + { + # x y z + # +---/ \---+ +------/ \------+ +------/ \------+ + # | 7 6 | | 5 4 3 | | 2 1 0 | + # +-----------------------------------------------+ + # | 0 | 1 | 1 | 1 | 0 | . | . | . | + # +-----------------------------------------------+ + +# HALT 76 01110110 +# xxyyyzzz + + print_3('halt', '', 'Suspends CPU.'); + } + else + { + # x y z + # +---/ \---+ +------/ \------+ +------/ \------+ + # | 7 6 | | 5 4 3 | | 2 1 0 | + # +-----------------------------------------------+ + # | 0 | 1 | . | . | . | . | . | . | + # +-----------------------------------------------+ + +# LD r, r' xx 01dddsss +# xxyyyzzz +# r: B, C, D, E, H, L, (HL), A + + if ($decoder_silent_level == SILENT0) + { + my $i_rega = $core_registers8[$dcd_instr_y]; + my $i_regb = $core_registers8[$dcd_instr_z]; + + print_3('ld', "$i_rega->{NAME}, $i_regb->{NAME}", "$i_rega->{EXPL} = $i_regb->{EXPL}"); + } + } + } # elsif ($dcd_instr_x == 1) + elsif ($dcd_instr_x == 2) + { + # x y z + # +---/ \---+ +------/ \------+ +------/ \------+ + # | 7 6 | | 5 4 3 | | 2 1 0 | + # +-----------------------------------------------+ + # | 1 | 0 | . | . | . | . | . | . | + # +-----------------------------------------------+ + +# ADD A, r 8x 10000rrr +# ADC A, r 8x 10001rrr +# SUB A, r 9x 10010rrr +# SBC A, r 9x 10011rrr +# AND A, r Ax 10100rrr +# XOR A, r Ax 10101rrr +# OR A, r Bx 10110rrr +# CP A, r Bx 10111rrr +# xxyyyzzz +# r: B, C, D, E, H, L, (HL), A + + if ($decoder_silent_level == SILENT0) + { + my $i_arith = $DDFD_instr[$dcd_instr_y]; + my $i_reg = $core_registers8[$dcd_instr_z]; + my $str0 = ($dcd_instr_z == 7) ? ' (A = 0)' : ''; + + print_3($i_arith->{INSTR}, "A, $i_reg->{NAME}", "$i_arith->{EXPL} $i_reg->{EXPL}$str0"); + } + } + else # $dcd_instr_x == 3 + { + # x y z + # +---/ \---+ +------/ \------+ +------/ \------+ + # | 7 6 | | 5 4 3 | | 2 1 0 | + # +-----------------------------------------------+ + # | 1 | 1 | . | . | . | . | . | . | + # +-----------------------------------------------+ + # | 5 4 | | 3 | + # +---\ /---+ +\ /+ + # p q + + given ($dcd_instr_z) + { + when (0) + { + # x y z + # +---/ \---+ +------/ \------+ +------/ \------+ + # | 7 6 | | 5 4 3 | | 2 1 0 | + # +-----------------------------------------------+ + # | 1 | 1 | . | . | . | 0 | 0 | 0 | + # +-----------------------------------------------+ + +# RET cc xx 11ccc000 +# xxyyyzzz +# cc: NZ, Z, NC, C, PO, PE, P, M + + my $cond = $conditions[$dcd_instr_y]; + + print_3('ret', $cond->{COND}, "If ($cond->{EXPL}) PC.l = [SP++]; PC.h = [SP++]"); + $prev_is_jump = TRUE; + } + + when (1) + { + # x y z + # +---/ \---+ +------/ \------+ +------/ \------+ + # | 7 6 | | 5 4 3 | | 2 1 0 | + # +-----------------------------------------------+ + # | 1 | 1 | . | . | . | 0 | 0 | 1 | + # +-----------------------------------------------+ + # | 5 4 | | 3 | + # +---\ /---+ +\ /+ + # p q + + if ($dcd_instr_q == 0) + { + # x z + # +---/ \---+ +------/ \------+ + # | 7 6 | | 2 1 0 | + # +-----------------------------------------------+ + # | 1 | 1 | . | . | 0 | 0 | 0 | 1 | + # +-----------------------------------------------+ + # | 5 4 | | 3 | + # +---\ /---+ +\ /+ + # p q + +# POP rp xx 11rr0001 +# xxppqzzz +# rp: BC, DE, HL, AF + + given ($dcd_instr_p) + { + when (0) { $str = 'C = [SP++]; B = [SP++]'; } + when (1) { $str = 'E = [SP++]; D = [SP++]'; } + when (2) { $str = 'L = [SP++]; H = [SP++]'; } + when (3) { $str = 'F = [SP++]; A = [SP++]'; } + } + + print_3('pop', $core_registers16b[$dcd_instr_p], $str); + } + else + { + # x z + # +---/ \---+ +------/ \------+ + # | 7 6 | | 2 1 0 | + # +-----------------------------------------------+ + # | 1 | 1 | . | . | 1 | 0 | 0 | 1 | + # +-----------------------------------------------+ + # | 5 4 | | 3 | + # +---\ /---+ +\ /+ + # p q + + given ($dcd_instr_p) + { + when (0) + { +# RET C9 11001001 +# xxppqzzz + + print_3('ret', '', 'PC.l = [SP++]; PC.h = [SP++]'); + $prev_is_jump = TRUE; + } + + when (1) + { +# EXX D9 11011001 +# xxppqzzz + + print_3('exx', '', "BC <-> BC'; DE <-> DE'; HL <-> HL'"); + } + + when (2) + { +# JP (HL) E9 11101001 +# xxppqzzz + + print_3('jp', '(HL)', 'Jumps to value of HL.'); + $prev_is_jump = TRUE; + } + + when (3) + { +# LD SP, HL F9 11111001 +# xxppqzzz + + print_3('ld', 'SP, HL', 'SP = HL'); + } + } # given ($dcd_instr_p) + } + } # $dcd_instr_z == 1 + + when (2) + { + # x y z + # +---/ \---+ +------/ \------+ +------/ \------+ + # | 7 6 | | 5 4 3 | | 2 1 0 | + # +-----------------------------------------------+ + # | 1 | 1 | . | . | . | 0 | 1 | 0 | + # +-----------------------------------------------+ + +# JP cc, nn xx nn nn 11ccc010 a7-0 a15-8 +# xxyyyzzz +# cc: NZ, Z, NC, C, PO, PE, P, M + + if ($decoder_silent_level == SILENT0) + { + my $addr = ($dcd_parm1 << 8) | $dcd_parm0; + my $cond = $conditions[$dcd_instr_y]; + my $target; + + $str = label_name($addr); + $target = jump_direction($addr); + print_3('jp', "$cond->{COND}, $str", "Jumps if ($cond->{EXPL})$target"); + $prev_is_jump = TRUE; + } + } + + when (3) + { + # x y z + # +---/ \---+ +------/ \------+ +------/ \------+ + # | 7 6 | | 5 4 3 | | 2 1 0 | + # +-----------------------------------------------+ + # | 1 | 1 | . | . | . | 0 | 1 | 1 | + # +-----------------------------------------------+ + + given ($dcd_instr_y) + { + when (0) + { +# JP nn 11000011 a7-0 a15-8 +# xxyyyzzz + + if ($decoder_silent_level == SILENT0) + { + my $addr = ($dcd_parm1 << 8) | $dcd_parm0; + my $target; + + $str = label_name($addr); + $target = jump_direction($addr); + print_3('jp', $str, "Jumps$target"); + $prev_is_jump = TRUE; + } + } + + when (1) + { + instruction_take_to_pieces($dcd_parm0); + CB_prefix_decoder(); + } + + when (2) + { +# OUT (n), A D3 11010011 nnnnnnnn +# xxyyyzzz + + if ($decoder_silent_level == SILENT0) + { + my $io = sprintf '0x%02X', $dcd_parm0; + + if ($gen_assembly_code) + { + print_3('out', "($io), A", "Out{$io} = A"); + } + else + { + $str = io_name($dcd_parm0); + print_3('out', "($str), A", "Out{$io} = A"); + } + } + elsif ($decoder_silent_level == SILENT1) + { + add_io($dcd_parm0, '', FALSE); + } + } + + when (3) + { +# IN A, (n) DB 11011011 nnnnnnnn +# xxyyyzzz + + if ($decoder_silent_level == SILENT0) + { + my $io = sprintf '0x%02X', $dcd_parm0; + + if ($gen_assembly_code) + { + print_3('in', "A, ($io)", "A = In{$io}"); + } + else + { + $str = io_name($dcd_parm0); + print_3('in', "A, ($str)", "A = In{$io}"); + } + } + elsif ($decoder_silent_level == SILENT1) + { + add_io($dcd_parm0, '', FALSE); + } + } + + when (4) + { +# EX (SP), HL E3 11100011 +# xxyyyzzz + + print_3('ex', '(SP), HL', "[SP] <-> L; [SP+1] <-> H"); + } + + when (5) + { +# EX DE, HL EB 11101011 +# xxyyyzzz + + print_3('ex', 'DE, HL', "E <-> L; D <-> H"); + } + + when (6) + { +# DI F3 11110011 +# xxyyyzzz + + print_3('di', '', 'Disable interrupts.'); + } + + when (7) + { +# EI FB 11111011 +# xxyyyzzz + + print_3('ei', '', 'Enable interrupts.'); + } + } # given ($dcd_instr_y) + } # $dcd_instr_z == 3 + + when (4) + { + # x y z + # +---/ \---+ +------/ \------+ +------/ \------+ + # | 7 6 | | 5 4 3 | | 2 1 0 | + # +-----------------------------------------------+ + # | 1 | 1 | . | . | . | 1 | 0 | 0 | + # +-----------------------------------------------+ + +# CALL cc, nn xx nn nn 11ccc100 a7-0 a15-8 +# xxyyyzzz +# cc: NZ, Z, NC, C, PO, PE, P, M + + if ($decoder_silent_level == SILENT0) + { + my $addr = ($dcd_parm1 << 8) | $dcd_parm0; + my $cond = $conditions[$dcd_instr_y]; + my $target; + + $str = label_name($addr); + $target = jump_direction($addr); + print_3('call', "$cond->{COND}, $str", "Calls ([--SP] = PC.h; [--SP] = PC.l) if ($cond->{EXPL})$target"); + } + } # $dcd_instr_z == 4 + + when (5) + { + # x y z + # +---/ \---+ +------/ \------+ +------/ \------+ + # | 7 6 | | 5 4 3 | | 2 1 0 | + # +-----------------------------------------------+ + # | 1 | 1 | . | . | . | 1 | 0 | 1 | + # +-----------------------------------------------+ + # | 5 4 | | 3 | + # +---\ /---+ +\ /+ + # p q + + if ($dcd_instr_q == 0) + { + # x z + # +---/ \---+ +------/ \------+ + # | 7 6 | | 2 1 0 | + # +-----------------------------------------------+ + # | 1 | 1 | . | . | 0 | 1 | 0 | 1 | + # +-----------------------------------------------+ + # | 5 4 | | 3 | + # +---\ /---+ +\ /+ + # p q + +# PUSH rp xx 11rr0101 +# xxppqzzz +# rp: BC, DE, HL, AF + + given ($dcd_instr_p) + { + when (0) { $str = '[--SP] = B; [--SP] = C'; } + when (1) { $str = '[--SP] = D; [--SP] = E'; } + when (2) { $str = '[--SP] = H; [--SP] = L'; } + when (3) { $str = '[--SP] = A; [--SP] = F'; } + } + + print_3('push', $core_registers16b[$dcd_instr_p], $str); + } + else + { + # x z + # +---/ \---+ +------/ \------+ + # | 7 6 | | 2 1 0 | + # +-----------------------------------------------+ + # | 1 | 1 | . | . | 1 | 1 | 0 | 1 | + # +-----------------------------------------------+ + # | 5 4 | | 3 | + # +---\ /---+ +\ /+ + # p q + + given ($dcd_instr_p) + { + when (0) + { + # x z + # +---/ \---+ +------/ \------+ + # | 7 6 | | 2 1 0 | + # +-----------------------------------------------+ + # | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | + # +-----------------------------------------------+ + # | 5 4 | | 3 | + # +---\ /---+ +\ /+ + # p q + +# CALL nn CD nn nn 11001101 a7-0 a15-8 +# xxyyyzzz + + if ($decoder_silent_level == SILENT0) + { + my $addr = ($dcd_parm1 << 8) | $dcd_parm0; + my $target; + + $str = label_name($addr); + $target = jump_direction($addr); + print_3('call', $str, "Calls ([--SP] = PC.h; [--SP] = PC.l)$target"); + } + } + + when (1) + { + # x z + # +---/ \---+ +------/ \------+ + # | 7 6 | | 2 1 0 | + # +-----------------------------------------------+ + # | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 | + # +-----------------------------------------------+ + # | 5 4 | | 3 | + # +---\ /---+ +\ /+ + # p q + + DDFD_prefix_decoder('IX'); + } + + when (2) + { + # x z + # +---/ \---+ +------/ \------+ + # | 7 6 | | 2 1 0 | + # +-----------------------------------------------+ + # | 1 | 1 | 1 | 0 | 1 | 1 | 0 | 1 | + # +-----------------------------------------------+ + # | 5 4 | | 3 | + # +---\ /---+ +\ /+ + # p q + + ED_prefix_decoder(); + } + + when (3) + { + # x z + # +---/ \---+ +------/ \------+ + # | 7 6 | | 2 1 0 | + # +-----------------------------------------------+ + # | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | + # +-----------------------------------------------+ + # | 5 4 | | 3 | + # +---\ /---+ +\ /+ + # p q + + DDFD_prefix_decoder('IY'); + } + } # given ($dcd_instr_p) + } + } # $dcd_instr_z == 5 + + when (6) + { + # x y z + # +---/ \---+ +------/ \------+ +------/ \------+ + # | 7 6 | | 5 4 3 | | 2 1 0 | + # +-----------------------------------------------+ + # | 1 | 1 | . | . | . | 1 | 1 | 0 | + # +-----------------------------------------------+ + +# ADD A, #n 11000110 nnnnnnnn +# ADC A, #n 11001110 nnnnnnnn +# SUB A, #n 11010110 nnnnnnnn +# SBC A, #n 11011110 nnnnnnnn +# AND A, #n 11100110 nnnnnnnn +# XOR A, #n 11101110 nnnnnnnn +# OR A, #n 11110110 nnnnnnnn +# CP A, #n 11111110 nnnnnnnn +# xxyyyzzz + + my $i_arith = $DDFD_instr[$dcd_instr_y]; + my $num = sprintf '0x%02X', $dcd_parm0; + my $char = decode_char($dcd_parm0); + my $str0 = ''; + + $str0 = ' (A = A)' if ($dcd_instr_y == 0 && $dcd_parm0 == 0); # ADD A, 0 + $str0 = ' (A = A)' if ($dcd_instr_y == 2 && $dcd_parm0 == 0); # SUB A, 0 + $str0 = ' (A = A)' if ($dcd_instr_y == 4 && $dcd_parm0 == 0xFF); # AND A, 0xFF + $str0 = ' (A = ~A)' if ($dcd_instr_y == 5 && $dcd_parm0 == 0xFF); # XOR A, 0xFF + $str0 = ' (A = A)' if ($dcd_instr_y == 6 && $dcd_parm0 == 0); # OR A, 0 + + print_3($i_arith->{INSTR}, "A, #$num", "$i_arith->{EXPL} $num$char$str0"); + } # $dcd_instr_z == 6 + + when (7) + { + # x y z + # +---/ \---+ +------/ \------+ +------/ \------+ + # | 7 6 | | 5 4 3 | | 2 1 0 | + # +-----------------------------------------------+ + # | 1 | 1 | . | . | . | 1 | 1 | 1 | + # +-----------------------------------------------+ + +# RST t xx 11ttt111 +# xxyyyzzz +# t: 0 - 7 + + $addr = sprintf '0x%04X', $dcd_instr_y * 8; + $str = sprintf '0x%02X', $dcd_instr_y * 8; + print_3('rst', $str, "Calls interrupt: [--SP] = PC.h; [--SP] = PC.l; PC = $addr"); + } # $dcd_instr_z == 7 + } # given ($dcd_instr_z) + } # $dcd_instr_x == 3 + } + +################################################################################ +################################################################################ + + # + # Reads the sfrs and bits from the $Line. + # + +sub process_header_line($) + { + my $Line = $_[0]; + + Log((' ' x $embed_level) . $Line, 5); + + if ($Line =~ /^#\s*include\s+["<]\s*(\S+)\s*[">]$/o) + { + $embed_level += 4; + &read_header("$include_path/$1"); + $embed_level -= 4; + } + elsif ($Line =~ /^__sfr\s+__at\s*(?:\(\s*)?0x([[:xdigit:]]+)(?:\s*\))?\s+([\w_]+)/io) + { + # __sfr __at (0x80) P0 ; /* PORT 0 */ + + add_ram(hex($1), $2, TRUE); + } + elsif ($Line =~ /^SFR\s*\(\s*([\w_]+)\s*,\s*0x([[:xdigit:]]+)\s*\)/io) + { + # SFR(P0, 0x80); // Port 0 + + add_ram(hex($2), $1, TRUE); + } + elsif ($Line =~ /^sfr\s+([\w_]+)\s*=\s*0x([[:xdigit:]]+)/io) + { + # sfr P1 = 0x90; + + add_ram(hex($2), $1, TRUE); + } + } + +#------------------------------------------------------------------------------- + + # + # Reads in a MCU.h file. + # + +sub read_header($) + { + my $Header = $_[0]; + my ($fh, $pre_comment, $comment, $line_number); + my $head; + + if (! open($fh, '<', $Header)) + { + print STDERR "$PROGRAM: Could not open. -> \"$Header\"\n"; + exit(1); + } + + $head = ' ' x $embed_level; + + Log("${head}read_header($Header) >>>>", 5); + + $comment = FALSE; + $line_number = 1; + while (<$fh>) + { + chomp; + s/\r$//o; # '\r' + + # Filters off the C comments. + + s/\/\*.*\*\///o; # /* ... */ + s/\/\/.*$//o; # // ... + s/^\s*|\s*$//go; + + if (/\/\*/o) # /* + { + $pre_comment = TRUE; + s/\s*\/\*.*$//o; + } + elsif (/\*\//o) # */ + { + $pre_comment = FALSE; + $comment = FALSE; + s/^.*\*\/\s*//o; + } + + if ($comment) + { + ++$line_number; + next; + } + + $comment = $pre_comment if ($pre_comment); + + if (/^\s*$/o) + { + ++$line_number; + next; + } + + run_preprocessor($Header, \&process_header_line, $_, $line_number); + ++$line_number; + } # while (<$fh>) + + Log("${head}<<<< read_header($Header)", 5); + close($fh); + } + +#------------------------------------------------------------------------------- + + # + # Determines size of the $dcd_instr. + # + +sub determine_instr_size() + { + my $instr; + my $size = $instruction_sizes_[$dcd_instr]; + + return $size if ($size >= 0); + + $instr = $rom[$dcd_address + 1]; + + if ($size == IPREFIX_DD || $size == IPREFIX_FD) + { + return $instruction_sizes_DDFD[$instr]; + } + elsif ($size == IPREFIX_ED) + { + return $instruction_sizes_ED[$instr]; + } + else + { + return 0; + } + } + +#------------------------------------------------------------------------------- + + # + # Among the blocks stows description of an instruction. + # + +sub add_instr_block($) + { + my $Address = $_[0]; + my ($instr_size, $invalid); + + $dcd_address = $Address; + $dcd_instr = $rom[$dcd_address]; + $invalid = FALSE; + + $instr_size = determine_instr_size(); + + if ($instr_size == 0) + { + $instr_size = 1; + add_block($Address, BLOCK_CONST, $instr_size, BL_TYPE_NONE, ''); + } + else + { + if ($instr_size == 1) + { + $invalid = TRUE if ($dcd_instr == EMPTY); + } + + if ($instr_size == 2) + { + $invalid = TRUE if ($rom[$dcd_address + 1] == EMPTY); + } + + if ($instr_size == 3) + { + $invalid = TRUE if ($rom[$dcd_address + 2] == EMPTY); + } + + if ($instr_size == 4) + { + $invalid = TRUE if ($rom[$dcd_address + 3] == EMPTY); + } + + if ($invalid) + { + add_block($Address, BLOCK_CONST, $instr_size, BL_TYPE_NONE, ''); + } + else + { + add_block($Address, BLOCK_INSTR, $instr_size, BL_TYPE_NONE, ''); + } + } + + return $instr_size; + } + +#------------------------------------------------------------------------------- + + # + # Splits the program into small blocks. + # + +sub split_code_to_blocks() + { + my ($i, $instr); + my ($is_empty, $empty_begin); + my ($is_const, $const_begin); + + $is_empty = FALSE; + $is_const = FALSE; + + for ($i = 0; $i < $rom_size; ) + { + $instr = $rom[$i]; + + if ($instr == EMPTY) + { + if (! $is_empty) + { + # The begin of the empty section. + + if ($is_const) + { + # The end of the constant section. + + add_block($const_begin, BLOCK_CONST, $i - $const_begin, BL_TYPE_NONE, ''); + $is_const = FALSE; + } + + $empty_begin = $i; + $is_empty = TRUE; + } + + ++$i; + } # if ($instr == EMPTY) + elsif (is_constant($i)) + { + if (! $is_const) + { + if ($is_empty) + { + # The end of the empty section. + + add_block($empty_begin, BLOCK_EMPTY, $i - $empty_begin, BL_TYPE_NONE, ''); + $is_empty = FALSE; + } + + $const_begin = $i; + $is_const = TRUE; + } + + ++$i; + } # elsif (is_constant($i)) + else + { + if ($is_const) + { + # The end of the constant section. + + add_block($const_begin, BLOCK_CONST, $i - $const_begin, BL_TYPE_NONE, ''); + $is_const = FALSE; + } + + if ($is_empty) + { + # The end of the empty section. + + add_block($empty_begin, BLOCK_EMPTY, $i - $empty_begin, BL_TYPE_NONE, ''); + $is_empty = FALSE; + } + + $i += add_instr_block($i); + } + } # for ($i = 0; $i < $rom_size; ) + + if ($is_const) + { + add_block($const_begin, BLOCK_CONST, $i - $const_begin, BL_TYPE_NONE, ''); + } + + if ($is_empty) + { + add_block($empty_begin, BLOCK_EMPTY, $i - $empty_begin, BL_TYPE_NONE, ''); + } + } + +#------------------------------------------------------------------------------- + + # + # Previously assess the code. + # + +sub preliminary_survey($) + { + $decoder_silent_level = $_[0]; + foreach (sort {$a <=> $b} keys(%blocks_by_address)) + { + my $block = \%{$blocks_by_address{$_}}; + + next if ($block->{TYPE} != BLOCK_INSTR); + + instruction_decoder($_, $block); + } + } + +#------------------------------------------------------------------------------- + + # + # Finds address of branchs and procedures. + # + +sub find_labels_in_code() + { + foreach (sort {$a <=> $b} keys(%blocks_by_address)) + { + my $block = \%{$blocks_by_address{$_}}; + + next if ($block->{TYPE} != BLOCK_INSTR); + + label_finder($_, $block); + } + } + +#------------------------------------------------------------------------------- + + # + # Finds lost address of branchs and procedures. + # + +sub find_lost_labels_in_code() + { + my ($block, $prev_block, $prev_addr, $label, $instr); + + $prev_addr = EMPTY; + $prev_block = undef; + foreach (sort {$a <=> $b} keys(%blocks_by_address)) + { + $block = \%{$blocks_by_address{$_}}; + + last if ($block->{TYPE} == BLOCK_RAM); + next if ($block->{TYPE} != BLOCK_INSTR); + + if ($prev_addr != EMPTY) + { + $instr = $rom[$prev_addr]; + $label = $block->{LABEL}; + + if (defined($label) && $label->{TYPE} == BL_TYPE_NONE) + { +# if ($instr == INST_RET || $instr == INST_RETI) + if ($instr == INST_RET) + { + Log(sprintf("Lost function label at the 0x%04X address.", $_), 5); + add_func_label($_, '', TRUE); + } + elsif ($instr == INST_JP || $instr == INST_JR || $instr == INST_JP_HL) + { + Log(sprintf("Lost jump label at the 0x%04X address.", $_), 5); + add_jump_label($_, '', BL_TYPE_LABEL, EMPTY, TRUE); + } + } + } + + $prev_addr = $_; + $prev_block = $block; + } + } + +#------------------------------------------------------------------------------- + + # + # Jump tables looking for in the code. + # + +sub recognize_jump_tables_in_code() + { + my @blocks = ((undef) x 5); + my @instrs = ((EMPTY) x 5); + my ($addr); + + foreach (sort {$a <=> $b} keys(%blocks_by_address)) + { + shift(@instrs); + push(@instrs, $rom[$_]); + + shift(@blocks); + push(@blocks, \%{$blocks_by_address{$_}}); + + next if (! defined($blocks[0]) || ! defined($blocks[4])); + next if ($blocks[0]->{TYPE} != BLOCK_INSTR); + next if ($blocks[1]->{TYPE} != BLOCK_INSTR); + next if ($blocks[2]->{TYPE} != BLOCK_INSTR); + next if ($blocks[3]->{TYPE} != BLOCK_INSTR); + next if ($blocks[4]->{TYPE} != BLOCK_INSTR); + + if ($blocks[0]->{SIZE} == 3 && $instrs[0] == INST_LD_HL && + $blocks[1]->{SIZE} == 1 && $instrs[1] == INST_ADD_HL_DE && + $blocks[2]->{SIZE} == 1 && $instrs[2] == INST_ADD_HL_DE && + $blocks[3]->{SIZE} == 1 && + (($instrs[3] == INST_ADD_HL_DE && $blocks[4]->{SIZE} == 1 && $instrs[4] == INST_JP_HL) || + $instrs[3] == INST_JP_HL)) + { +=back +0x019D: 21 A4 01 ld HL, #0x01A4 ; HL = 0x01A4 +0x01A0: 19 add HL, DE ; HL += DE +0x01A1: 19 add HL, DE ; HL += DE +0x01A2: 19 add HL, DE ; HL += DE +0x01A3: E9 jp (HL) ; Jumps to value of HL. + +0x01A4: C3 D4 01 jp Label_021 ; Jumps (forward) hither: 0x01D4 + +---------------------------------------------------------------------------------------------------- + +0x019D: 21 A4 01 ld HL, #0x01A3 ; HL = 0x01A4 +0x01A0: 19 add HL, DE ; HL += DE +0x01A1: 19 add HL, DE ; HL += DE +0x01A2: E9 jp (HL) ; Jumps to value of HL. + +0x01A3: 18 2F jr Label_021 ; Jumps (forward) hither: 0x01D4 +=cut + + $addr = ($rom[$blocks[0]->{ADDR} + 2] << 8) | $rom[$blocks[0]->{ADDR} + 1]; + add_jump_label($addr, '', BL_TYPE_JTABLE, EMPTY, FALSE); + } + } + } + +#------------------------------------------------------------------------------- + + # + # Prints the global symbols. + # + +sub emit_globals($) + { + my $Assembly_mode = $_[0]; + my ($label, $cnt0, $cnt1, $str0, $str1); + + return if (! scalar(keys(%labels_by_address))); + + print ";$border0\n;\tPublic labels\n;$border0\n\n"; + + if ($Assembly_mode) + { + foreach (sort {$a <=> $b} keys(%labels_by_address)) + { + $label = $labels_by_address{$_}; + + next if ($label->{TYPE} != BL_TYPE_SUB); + + print "\t.globl\t$label->{NAME}\n"; + } + } + else + { + foreach (sort {$a <=> $b} keys(%labels_by_address)) + { + $label = $labels_by_address{$_}; + + next if ($label->{TYPE} != BL_TYPE_SUB); + + $str0 = sprintf "0x%04X", $_; + $cnt0 = sprintf "%3u", $label->{CALL_COUNT}; + $cnt1 = sprintf "%3u", $label->{JUMP_COUNT}; + $str1 = ($label->{CALL_COUNT} || $label->{JUMP_COUNT}) ? "calls: $cnt0, jumps: $cnt1" : 'not used'; + print "${str0}:\t" . align($label->{NAME}, STAT_ALIGN_SIZE) . "($str1)\n"; + } + } + + print "\n"; + } + +#------------------------------------------------------------------------------- + + # + # Prints the registers (variables). + # + +sub emit_ram_data() + { + my ($block, $first, $name, $next_addr, $size, $cnt, $str0, $str1); + + return if (! scalar(keys(%ram_blocks_by_address))); + + print ";$border0\n;\tRAM data\n;$border0\n\n"; + + $next_addr = EMPTY; + foreach (sort {$a <=> $b} keys(%ram_blocks_by_address)) + { + $block = $blocks_by_address{$_}; + + if ($block->{TYPE} != BLOCK_RAM) + { + $next_addr = EMPTY; + next; + } + + next if ($next_addr != EMPTY && $_ < $next_addr); + + $str0 = sprintf "0x%04X", $_; + $cnt = sprintf "%3u", $block->{REF_COUNT}; + $str1 = ($block->{REF_COUNT}) ? "used $cnt times" : 'not used'; + $name = $ram_names_by_address{$_}; + + if (defined($name) && $name ne '') + { + $cnt = sprintf "%5u", $block->{SIZE}; + print "${str0}:\t" . align($name, STAT_ALIGN_SIZE) . "($cnt bytes) ($str1)\n"; + $next_addr = $_ + $block->{SIZE}; + } + else + { + if ($map_readed) + { + print "${str0}:\t" . align("variable_$str0", STAT_ALIGN_SIZE) . "( 1 bytes) ($str1)\n"; + } + else + { + print "${str0}:\t" . align("variable_$str0", STAT_ALIGN_SIZE) . "($str1)\n"; + } + + $next_addr = $_ + 1; + } + } # foreach (sort {$a <=> $b} keys(%ram_blocks_by_address)) + + print "\n"; + } + +#------------------------------------------------------------------------------- + + # + # Prints I/O ports. + # + +sub emit_io_ports() + { + my ($io, $cnt, $str0, $str1); + + return if (! scalar(keys(%io_by_address))); + + print ";$border0\n;\tI/O ports\n;$border0\n\n"; + + foreach (sort {$a <=> $b} keys(%io_by_address)) + { + $io = $io_by_address{$_}; + + $str0 = sprintf "0x%02X", $_; + $cnt = sprintf "%3u", $io->{REF_COUNT}; + $str1 = ($io->{REF_COUNT}) ? "used $cnt times" : 'not used'; + + if ($io->{NAME} ne '') + { + print "${str0}:\t" . align($io->{NAME}, STAT_ALIGN_SIZE) . "($str1)\n"; + } + else + { + print "${str0}:\t" . align("port_$str0", STAT_ALIGN_SIZE) . "($str1)\n"; + } + } # foreach (sort {$a <=> $b} keys(%io_by_address)) + + print "\n"; + } + +#------------------------------------------------------------------------------- + + # + # Prints a label belonging to the $Address. + # + +sub print_label($) + { + my $Address = $_[0]; + my ($label, $type); + + $label = $labels_by_address{$Address}; + + return FALSE if (! defined($label) || $label->{TYPE} == BL_TYPE_NONE); + + $type = $label->{TYPE}; + + print "\n;$border0\n" if ($type == BL_TYPE_SUB); + + printf "\n$label->{NAME}:\n\n"; + $label->{PRINTED} = TRUE; + $prev_is_jump = FALSE; + return TRUE; + } + +#------------------------------------------------------------------------------- + + # + # Prints a variable belonging to the $Address. + # + +sub print_variable($$) + { + my ($Address, $BlockRef) = @_; + my ($name, $size, $str0, $str1); + + $size = $BlockRef->{SIZE}; + + return if (! $size); + + $name = $ram_names_by_address{$Address}; + + return if (! defined($name) || $name eq ''); + + $str0 = sprintf "0x%04X", $Address; + + given ($size) + { + when (1) { $str1 = '.db'; } + when (2) { $str1 = '.dw'; } + when (4) { $str1 = '.dd'; } + when (8) { $str1 = '.dq'; } + when (10) { $str1 = '.dt'; } + default { $str1 = '.db'; } + } + + if ($gen_assembly_code) + { + print "$name:\n"; + $str0 = "\t$str1\t?"; + } + else + { + $str0 = align("$str0:$name", RAM_ALIGN_SIZE) . "$str1\t?"; + } + + print align($str0, RAM_ALIGN_SIZE + 1 + EXPL_ALIGN_SIZE) . "; $size bytes\n"; + } + +#------------------------------------------------------------------------------- + + # + # Prints a table of constants. + # + +sub print_constants($$) + { + my ($Address, $BlockRef) = @_; + my ($size, $i, $len, $frag, $byte, $spc, $col, $brd); + my ($left_align, $right_align); + my @constants; + my @line; + + $size = $BlockRef->{SIZE}; + + return if (! $size); + + $prev_is_jump = FALSE; + $col = ' '; + + if ($gen_assembly_code) + { + print ";$table_border\n;\t\t $table_header | $table_header |\n;$table_border\n"; + $brd = ' '; + } + else + { + print "$table_border\n| | $table_header | $table_header |\n$table_border\n"; + $brd = '|'; + } + + @constants = @rom[$Address .. ($Address + $size - 1)]; + $i = 0; + while (TRUE) + { + $len = $size - $i; + + last if (! $len); + + $len = TBL_COLUMNS if ($len > TBL_COLUMNS); + + if ($gen_assembly_code) + { + print "\t.db\t"; + } + else + { + printf "$brd 0x%04X $brd ", $Address; + } + + if (($spc = $Address % TBL_COLUMNS)) + { + $frag = TBL_COLUMNS - $spc; + $len = $frag if ($len > $frag); + } + + $left_align = $col x $spc; + $right_align = $col x (TBL_COLUMNS - $spc - $len); + @line = @constants[$i .. ($i + $len - 1)]; + $Address += $len; + $i += $len; + + print " $left_align" . join(' ', map { sprintf("%02X ", $_ & 0xFF); } @line); + + print "$right_align $brd $left_align " . + join(' ', map { + sprintf((($_ < ord(' ') || $_ >= 0x7F) ? "%02X " : "'%c'"), $_ & 0xFF); + } @line) . "$right_align $brd\n"; + } # while (TRUE) + + print (($gen_assembly_code) ? ";$table_border\n" : "$table_border\n"); + $prev_is_jump = FALSE; + } + +#------------------------------------------------------------------------------- + + # + # Disassembly contents of $blocks_by_address array. + # + +sub disassembler() + { + my ($sname, $prev_block_type, $ref); + + $prev_is_jump = FALSE; + $decoder_silent_level = SILENT0; + + $table_header = join(' ', map { sprintf '%02X', $_ } (0 .. (TBL_COLUMNS - 1))); + + if ($gen_assembly_code) + { + $table_border = ('-' x (TBL_COLUMNS * 4 + 16)) . '+' . ('-' x (TBL_COLUMNS * 4 + 2)) . '+'; + } + else + { + $table_border = '+' . ('-' x 10) . '+' . ('-' x (TBL_COLUMNS * 4 + 2)) . '+' . ('-' x (TBL_COLUMNS * 4 + 2)) . '+'; + } + + print "\n"; + + if ($gen_assembly_code) + { + emit_globals(TRUE); + print ";$border0\n;\tCode\n;$border0\n\n\t.area\tCODE\t(CODE)\n\n"; + } + else + { + emit_globals(FALSE); + emit_ram_data(); + emit_io_ports(); + print ";$border0\n"; + } + + $prev_block_type = EMPTY; + foreach (sort {$a <=> $b} keys(%blocks_by_address)) + { + $ref = $blocks_by_address{$_}; + + if ($ref->{TYPE} == BLOCK_INSTR) + { + print_label($_); + print "\n" if ($prev_is_jump); + + instruction_decoder($_, $ref); + $prev_block_type = BLOCK_INSTR; + } + elsif ($ref->{TYPE} == BLOCK_RAM) + { + print "\n;$border0\n\n" if ($prev_block_type != BLOCK_RAM); + + print_variable($_, $ref); + $prev_block_type = BLOCK_RAM; + } + elsif ($ref->{TYPE} == BLOCK_CONST) + { + print "\n;$border0\n" if ($prev_block_type != BLOCK_CONST); + + print_label($_); + print "\n" if ($prev_is_jump); + + print_constants($_, $ref); + $prev_block_type = BLOCK_CONST; + } + elsif ($ref->{TYPE} == BLOCK_EMPTY) + { + my $next_block = $_ + $ref->{SIZE}; + + print "\n;$border0\n" if ($prev_block_type != BLOCK_EMPTY); + + if (! $gen_assembly_code) + { + printf("\n0x%04X: -- -- --\n .... -- -- --\n0x%04X: -- -- --\n", $_, $next_block - 1); + } + elsif ($next_block <= $rom_size) + { + # Skip the empty code space. + + printf "\n\t.ds\t%u\n", $ref->{SIZE}; + } + + $prev_block_type = BLOCK_EMPTY; + } + } # foreach (sort {$a <=> $b} keys(%blocks_by_address)) + } + +#------------------------------------------------------------------------------- + + # + # If there are datas in the code, it is possible that some labels will + # be lost. This procedure prints them. + # + +sub print_hidden_labels() + { + foreach (sort {$a <=> $b} keys(%labels_by_address)) + { + my $label = $labels_by_address{$_}; + + print STDERR "The label: $label->{NAME} is hidden!\n" if (! $label->{PRINTED}); + } + } + +################################################################################ +################################################################################ + +sub usage() + { + print <<EOT; +Usage: $PROGRAM [options] <hex file> + + Options are: + + -M|--mcu <header.h> + + Header file of the MCU. + + -I|--include <path to header> + + Path of the header files of Z80 MCUs. (Default: $default_include_path) + + --map-file <file.map> + + The map file belonging to the input hex file. (optional) + + -r|--rom-size <size of program memory> + +EOT +; + printf "\t Defines size of the program memory. (Default %u bytes.)\n", Z80_ROM_SIZE; + print <<EOT; + + --const-area <start address> <end address> + + Designates a constant area (jumptables, texts, etc.), where data is + stored happen. The option may be given more times, that to select + more areas at the same time. (optional) + + -as|--assembly-source + + Generates the assembly source file. (Eliminates before the instructions + visible address and hex codes.) Emits global symbol table, etc. + + -fl|--find-lost-labels + + Finds the "lost" labels. These may be found such in program parts, + which are directly not get call. + + --name-list <list_file> + + The file contains list of names. They may be: Names of variables and + names of labels. For example: + + [IO] + 0x21:keyboard_io + .. + .. + .. + [RAM] + 0x8021:ram_variable + .. + .. + .. + [ROM] + 0x05FC:function_or_label + .. + .. + .. + + The contents of list override the names from map file. + + -ne|--no-explanations + + Eliminates after the instructions visible explaining texts. + + -v <level> or --verbose <level> + + It provides information on from the own operation. + Possible value of the level between 0 and 10. (default: 0) + + -h|--help + + This text. +EOT +; + } + +################################################################################ +################################################################################ +################################################################################ + +foreach (@default_paths) + { + if (-d $_) + { + $default_include_path = $_; + last; + } + } + +if (! @ARGV) + { + usage(); + exit(1); + } + +for (my $i = 0; $i < @ARGV; ) + { + my $opt = $ARGV[$i++]; + + given ($opt) + { + when (/^-(r|-rom-size)$/o) + { + param_exist($opt, $i); + $rom_size = str2int($ARGV[$i++]); + + if ($rom_size < 1024) + { + printf STDERR "$PROGRAM: Code size of the Z80 family greater than 1024 bytes!\n"; + exit(1); + } + elsif ($rom_size > Z80_ROM_SIZE) + { + printf STDERR "$PROGRAM: Code size of the Z80 family not greater %u bytes!\n", Z80_ROM_SIZE; + exit(1); + } + } + + when (/^--const-area$/o) + { + my ($start, $end); + + param_exist($opt, $i); + $start = str2int($ARGV[$i++]); + + param_exist($opt, $i); + $end = str2int($ARGV[$i++]); + + if ($start > $end) + { + my $t = $start; + + $start = $end; + $end = $t; + } + elsif ($start == $end) + { + $start = Z80_ROM_SIZE - 1; + $end = Z80_ROM_SIZE - 1; + } + + add_const_area($start, $end) if ($start < $end); + } # when (/^--const-area$/o) + + when (/^-(I|-include)$/o) + { + param_exist($opt, $i); + $include_path = $ARGV[$i++]; + } + + when (/^-(M|-mcu)$/o) + { + param_exist($opt, $i); + $header_file = $ARGV[$i++]; + } + + when (/^--map-file$/o) + { + param_exist($opt, $i); + $map_file = $ARGV[$i++]; + } + + when (/^-(as|-assembly-source)$/o) + { + $gen_assembly_code = TRUE; + } + + when (/^-(fl|-find-lost-labels)$/o) + { + $find_lost_labels = TRUE; + } + + when (/^--name-list$/o) + { + param_exist($opt, $i); + $name_list = $ARGV[$i++]; + } + + when (/^-(ne|-no-explanations)$/o) + { + $no_explanations = TRUE; + } + + when (/^-(v|-verbose)$/o) + { + param_exist($opt, $i); + $verbose = int($ARGV[$i++]); + $verbose = 0 if (! defined($verbose) || $verbose < 0); + $verbose = 10 if ($verbose > 10); + } + + when (/^-(h|-help)$/o) + { + usage(); + exit(0); + } + + default + { + if ($hex_file eq '') + { + $hex_file = $opt; + } + else + { + print STDERR "$PROGRAM: We already have the source file name: $hex_file.\n"; + exit(1); + } + } + } # given ($opt) + } # for (my $i = 0; $i < @ARGV; ) + +$include_path = $default_include_path if ($include_path eq ''); + +if ($hex_file eq '') + { + print STDERR "$PROGRAM: What do you have to disassembled?\n"; + exit(1); + } + +is_file_ok($hex_file); + +init_mem(0, $rom_size - 1); +read_hex($hex_file); + +if ($header_file ne '') + { + is_file_ok("$include_path/$header_file"); + reset_preprocessor(); + $embed_level = 0; + read_header("$include_path/$header_file"); + } + +if ($map_file eq '') + { + ($map_file) = ($hex_file =~ /^(.+)\.hex$/io); + $map_file .= '.map'; + } + +$map_file = '' if (! -e $map_file); + +is_file_ok($name_list) if ($name_list ne ''); + +################################### + +read_map_file(); +read_name_list(); +split_code_to_blocks(); +recognize_jump_tables_in_code(); +preliminary_survey(SILENT1); +find_labels_in_code(); +find_lost_labels_in_code() if ($find_lost_labels); +add_names_labels(); +fix_multi_byte_variables(); +fix_io_names(); +disassembler(); +print_hidden_labels() if ($verbose > 2); |
