diff -Nru cmoc-0.1.65/configure cmoc-0.1.67/configure --- cmoc-0.1.65/configure 2020-04-25 02:27:42.000000000 +0000 +++ cmoc-0.1.67/configure 2020-06-07 14:57:21.000000000 +0000 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for cmoc 0.1.65. +# Generated by GNU Autoconf 2.69 for cmoc 0.1.67. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -576,8 +576,8 @@ # Identity of this package. PACKAGE_NAME='cmoc' PACKAGE_TARNAME='cmoc' -PACKAGE_VERSION='0.1.65' -PACKAGE_STRING='cmoc 0.1.65' +PACKAGE_VERSION='0.1.67' +PACKAGE_STRING='cmoc 0.1.67' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -1259,7 +1259,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures cmoc 0.1.65 to adapt to many kinds of systems. +\`configure' configures cmoc 0.1.67 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1326,7 +1326,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of cmoc 0.1.65:";; + short | recursive ) echo "Configuration of cmoc 0.1.67:";; esac cat <<\_ACEOF @@ -1427,7 +1427,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -cmoc configure 0.1.65 +cmoc configure 0.1.67 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1528,7 +1528,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by cmoc $as_me 0.1.65, which was +It was created by cmoc $as_me 0.1.67, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2392,7 +2392,7 @@ # Define the identity of the package. PACKAGE='cmoc' - VERSION='0.1.65' + VERSION='0.1.67' cat >>confdefs.h <<_ACEOF @@ -2493,7 +2493,7 @@ -MANUAL_DATE_EN="April 24th, 2020"; +MANUAL_DATE_EN="June 7th, 2020"; ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' @@ -4005,7 +4005,7 @@ -ac_config_files="$ac_config_files Makefile src/Makefile src/support/Makefile src/stdlib/Makefile src/float/Makefile src/usim-0.91-cmoc/Makefile macros/Makefile doc/Makefile doc/cmoc.1" +ac_config_files="$ac_config_files Makefile src/Makefile src/stdlib/Makefile src/float/Makefile src/usim-0.91-cmoc/Makefile macros/Makefile doc/Makefile doc/cmoc.1" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure @@ -4577,7 +4577,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by cmoc $as_me 0.1.65, which was +This file was extended by cmoc $as_me 0.1.67, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -4634,7 +4634,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -cmoc config.status 0.1.65 +cmoc config.status 0.1.67 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" @@ -4755,7 +4755,6 @@ "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; - "src/support/Makefile") CONFIG_FILES="$CONFIG_FILES src/support/Makefile" ;; "src/stdlib/Makefile") CONFIG_FILES="$CONFIG_FILES src/stdlib/Makefile" ;; "src/float/Makefile") CONFIG_FILES="$CONFIG_FILES src/float/Makefile" ;; "src/usim-0.91-cmoc/Makefile") CONFIG_FILES="$CONFIG_FILES src/usim-0.91-cmoc/Makefile" ;; diff -Nru cmoc-0.1.65/configure.ac cmoc-0.1.67/configure.ac --- cmoc-0.1.65/configure.ac 2020-04-25 02:23:10.000000000 +0000 +++ cmoc-0.1.67/configure.ac 2020-06-07 14:53:53.000000000 +0000 @@ -1,8 +1,8 @@ -# $Id: configure.ac,v 1.129 2020/04/25 02:23:10 sarrazip Exp $ +# $Id: configure.ac,v 1.132 2020/06/07 14:53:53 sarrazip Exp $ AC_PREREQ(2.54) -AC_INIT(cmoc, 0.1.65) +AC_INIT(cmoc, 0.1.67) AC_CONFIG_SRCDIR(src/lexer.ll) AM_INIT_AUTOMAKE @@ -13,7 +13,7 @@ AC_SUBST(PACKAGE_SUMMARY_EN) AC_SUBST(PACKAGE_SUMMARY_FR) -MANUAL_DATE_EN="April 24th, 2020"; AC_SUBST(MANUAL_DATE_EN) +MANUAL_DATE_EN="June 7th, 2020"; AC_SUBST(MANUAL_DATE_EN) AC_PROG_CXX AC_LANG_CPLUSPLUS @@ -131,7 +131,6 @@ AC_CONFIG_FILES([ Makefile src/Makefile - src/support/Makefile src/stdlib/Makefile src/float/Makefile src/usim-0.91-cmoc/Makefile diff -Nru cmoc-0.1.65/debian/changelog cmoc-0.1.67/debian/changelog --- cmoc-0.1.65/debian/changelog 2020-04-25 08:44:36.000000000 +0000 +++ cmoc-0.1.67/debian/changelog 2020-06-23 19:38:26.000000000 +0000 @@ -1,3 +1,9 @@ +cmoc (0.1.67-0~tormod) precise; urgency=medium + + * New upstream release + + -- Tormod Volden Tue, 23 Jun 2020 21:37:49 +0200 + cmoc (0.1.65-0~tormod) precise; urgency=medium * New upstream release diff -Nru cmoc-0.1.65/doc/cmoc-manual.markdown cmoc-0.1.67/doc/cmoc-manual.markdown --- cmoc-0.1.65/doc/cmoc-manual.markdown 2020-04-25 02:09:57.000000000 +0000 +++ cmoc-0.1.67/doc/cmoc-manual.markdown 2020-06-07 14:39:20.000000000 +0000 @@ -8,7 +8,7 @@ **By Pierre Sarrazin (sarrazip@sarrazip.com)** -Date of this manual: 2020-04-24 +Date of this manual: 2020-06-07 Copyright © 2003-2020 @@ -17,7 +17,7 @@ Distributed under the **GNU General Public License**, **version 3 or later** (see the License section). -Version of CMOC covered by this manual: **0.1.65** +Version of CMOC covered by this manual: **0.1.67** Introduction @@ -487,17 +487,9 @@ The same goes for `#pragma limit`: the `--limit` option must be used instead. -Starting with version 0.1.43, these pragrams can only be used when: -* compiling directly from a C file to an executable -(i.e., the `-c` option is not used); -* using the `--monolith` option. - - -### Uncalled functions - -Non-static functions that are not called are still emitted, because -they might be invoked by another module. This cannot be determined -before the linking phase. +Starting with version 0.1.43, these pragmas can only be used when +compiling directly from a C file to an executable, +i.e., the `-c` option is not used. ### Assembly language modules @@ -670,24 +662,11 @@ The name of the `.d` file is formed from the name of the `.o` file to be generated. -This option is not available in monolithic mode and it has no effect +This option has no effect when also specifying the `-E` option (which prints the preprocessor output and stops). -### Legacy monolithic mode - -The legacy "monolithic" mode is available when the -`--monolith` option is passed. In that mode, only one `.c` file -may be specified. It will be compiled directly to an executable. -During that compilation the `CMOC_MONOLITH` preprocessor identifier -is defined. This can be used to alter the code depending on the -compilation mode. - -Monolithic mode is deprecated and may be removed in future versions -of CMOC. - - Programming for CMOC -------------------- @@ -1620,8 +1599,8 @@ then the return value must be stored at a location whose address is received by the function as its first (hidden) parameter. -The body of a function must preserve registers U and S. It is -allowed to modify A, B, X and CC. +The body of a CMOC-generated function preserves registers U, S and DP. +It is allowed to modify A, B, X and CC. **Under OS-9, CMOC uses Y to refer to the data section** of the current process. Any code that needs to use Y must preserve its value and @@ -1636,7 +1615,8 @@ Register DP is not used or modified by CMOC-generated code. -A CMOC-generated function uses a stack frame if the function receives +A CMOC-generated function uses a [stack frame](https://en.wikipedia.org/wiki/Call_stack#STACK-FRAME) +if the function receives one or more parameters or has local variables, and is not defined with the `asm` keyword (see the *Assembly-only functions* section elsewhere in this manual). @@ -1658,7 +1638,7 @@ i.e., `&H7A00`. Pass --org to the compiler to position the program at such an address. In the Basic program, reserve some high RAM to your CMOC program, -i.e., `CLEAR 200,&H7A00`. +i.e., `CLEAR 200,&H79FF`. Then use `LOADM`, then `DEF USR` to define a user routine that points to your CMOC program, e.g., `DEF USR5=&H7A00`. (The 5 in this example can be a number from 0 to 9.) diff -Nru cmoc-0.1.65/NEWS cmoc-0.1.67/NEWS --- cmoc-0.1.65/NEWS 2020-04-25 02:05:37.000000000 +0000 +++ cmoc-0.1.67/NEWS 2020-06-07 14:57:35.000000000 +0000 @@ -1,3 +1,31 @@ +2020-06-07: Version 0.1.67 released + + Fixed an issue with the unsigned long shifting optimization + introduced in version 0.1.66. + +2020-06-06: Version 0.1.66 released + + New -Wlocal-var-hiding command line switch makes the compiler issue + a warning when a local variable declaration hides another one of the + same name. + + Fixed a bug where a global variable initializer of the form &array[N] + was rejected as being non constant. + + Added a low-level optimization that removes an unneeded LDB instruction + when a byte gets compared with two values. + + Added an optimization for shifting an unsigned long by 8, 16 or 24 + bits, left or right. + + Added an optimization for the evaluation of a loop condition based + on a comma-expression. + + Removed non-breakable spaces from several source files. + + Monolith compilation mode is not offered anymore. This also means that + the --emit-uncalled command-line switch has been removed. + 2020-04-24: Version 0.1.65 released Added stricmp() and memicmp() (for ASCII case-insensitive comparisons) diff -Nru cmoc-0.1.65/src/a09 cmoc-0.1.67/src/a09 --- cmoc-0.1.65/src/a09 2017-10-14 19:14:01.000000000 +0000 +++ cmoc-0.1.67/src/a09 1970-01-01 00:00:00.000000000 +0000 @@ -1,535 +0,0 @@ -#!/usr/bin/perl -w -# -# Assembles the 6809 source file mentioned as an argument on the command line. -# -# The file is passed through the cpp processor. -# Comments in the assembler file are allowed but are not passed to the -# underlying assembler. -# -# Constants of the form 0xNNNN are replaced with $NNNN. -# -# Expects intelhex2cocobin and intelhex2srec to be in the PATH. -# Otherwise, use --hexconv. -# -# Error messages are displayed with their corresponding source line. - -use strict; -use Getopt::Long; -use IPC::Open2; - - -my $hexToBinConverterPath = "intelhex2cocobin"; -my $hexToSRECConverterPath = "intelhex2srec"; -my $stackSpace = 1024; # in bytes - - -sub usage() -{ - print <<__EOF__; -Usage: $0 [options] source.[asm|s] - -Options: ---help ---entry= Set the entry point to (in hex) ---append= Append to the assembly text to be sent to cpp. ---includedir= Use as an include file directory. - Pass this directive to the underlying assembler. ---define=[=val] Pass a definition to the underlying assembler. ---target=T Define the given target preprocessor ID. ---hexconv=PATH Use PATH to $hexToBinConverterPath ---hexsrecconv=PATH Use PATH to $hexToSRECConverterPath ---lwasm Use lwasm as the underlying assembler (default). ---frankasm Use as6809 (FrankASM) as the underlying assembler. ---srec Generate a Motorola SREC executable in addition to the .hex file. ---no-blocks Do not generate blocks during assembly. ---stack-space=N Reserve N bytes for stack space (default: $stackSpace). ---output= Output to instead of default, which is "source.bin". -__EOF__ -} - - -# Returns true if the first argument is a string in the array -# referred to by the second argument. -# -sub isStrInArray -{ - my ($element, $raArray) = @_; - - for my $e (@$raArray) - { - return 1 if $e eq $element; - } - return 0; -} - - -sub convertAsciiDirective($) -{ - my ($arg) = @_; - - # Unescape escaped characters. - # - $arg =~ s/\\a/\a/g; - $arg =~ s/\\b/\b/g; - $arg =~ s/\\t/\t/g; - $arg =~ s/\\n/\n/g; - $arg =~ s/\\f/\f/g; - $arg =~ s/\\r/\r/g; - $arg =~ s/\\(0[0-7]+)/chr(oct($1))/ge; # e.g., convert \042 into " - $arg =~ s/\\0/\0/g; - - my @segments = (); # list of assembly language lines (\n terminated) - my $currentFCC = ""; - for my $char (split //, $arg) - { - if ($char =~ /^[ !#-~]$/) - { - $currentFCC .= $char; - } - else - { - if ($currentFCC ne "") - { - push @segments, "\tFCC\t\"$currentFCC\"\n"; - $currentFCC = ""; - } - push @segments, sprintf("\tFCB\t\$%02X\n", ord($char)); - } - } - if ($currentFCC ne "") - { - push @segments, "\tFCC\t\"$currentFCC\"\n"; - $currentFCC = ""; - } - - return \@segments; -} - - -sub fixConstants -{ - my ($str) = @_; - - # Obsolete: $str =~ s/\b0x([0-9a-f]+)/\$$1/ig; # replace 0xNNNN with $NNNN - - return $str; -} - - -# Returns a 2-digit hex string. -# -sub computeIntelHEXChecksum($) -{ - my ($hex) = @_; - - my $sum = 0; - while ($hex =~ s/^(..)//) - { - $sum += hex($1); - } - return sprintf("%02X", ((0xFF - ($sum & 0xFF)) + 1) & 0xFF); # 2's complement -} - - -# Reads the .hex file (in the Intel HEX format) specified as the 1st argument, -# puts $entry (a hex string) in its last record (of type 1), -# and rewrites all the records into the file. -# Returns 1 on success, 0 on failure. Prints an error message on failure. -# See http://en.wikipedia.org/wiki/Intel_HEX about the format. -# -sub fixIntelHexEntryPointRecord -{ - my ($hexFilename, $entry) = @_; - - my $hexFile; - if (!open($hexFile, $hexFilename)) - { - print "cmoc: ERROR: failed to open $hexFilename: $!\n"; - return 0; - } - - my $temp = $/; - $/ = undef; - my $contents = <$hexFile>; - $/ = $temp; - - close($hexFile); - - if (!defined $contents) - { - print "cmoc: ERROR: failed to read $hexFilename\n"; - return 0; - } - - # Remove the entry point line from $contents. - # - if ($contents !~ s/^:00[0-9a-f]{4}01[0-9a-f]{2}\s*$//mi) # the "01" means type-1 record - { - print "cmoc: ERROR: $hexFilename does not finish with valid type-1 record\n"; - return 0; - } - - # Add a new entry point line based on $entry. - # - die unless defined $entry; - my $newLastRecord = sprintf(":00%04X01%s\n", hex($entry), computeIntelHEXChecksum($entry . "01")); - #print "entry=[$entry], newLastRecord=[$newLastRecord]\n"; die; - $contents .= $newLastRecord; - - if (!open($hexFile, "> $hexFilename")) - { - print "cmoc: ERROR: failed to overwrite $hexFilename: $!\n"; - return 0; - } - - print $hexFile $contents; - - if (!close($hexFile)) - { - print "cmoc: ERROR: failed to close $hexFilename\n"; - return 0; - } - - return 1; -} - - -############################################################################### - - -my $showHelp = 0; -my $verbose = 0; -my @includeDirList = (); -my @filenamesToAppend = (); -my $targetPlatformPreprocId = 0; # _COCO_BASIC_, OS9, etc. -my $checkNullPointers = 0; -my $checkStackOverflow = 0; -my $entry; # address (as hex string) of program's entry point -my $limit; # if specified, address (as hex string) that must not be exceeded by program_end -my $useLWASM = 1; # lwasm (from LWTOOLS) instead of as6809 -my $useFrankASM = 0; -my @neededUtilitySubRoutines; # e.g., "MUL16", etc. -my $generateSREC = 0; # if true, generate a Motorola SREC version of the output executable. -my @defineList; -my $noBlocks = 0; -my $outputFilename; # if not defined, use .bin - -if (!GetOptions( - "help" => \$showHelp, - "version" => \$showHelp, - "verbose" => \$verbose, - "includedir=s" => \@includeDirList, - "append=s" => \@filenamesToAppend, - "target=s" => \$targetPlatformPreprocId, - "check-null" => \$checkNullPointers, - "check-stack" => \$checkStackOverflow, - "entry=s" => \$entry, - "limit=s" => \$limit, - "hexconv=s" => \$hexToBinConverterPath, - "hexsrecconv=s" => \$hexToSRECConverterPath, - "lwasm" => \$useLWASM, - "frankasm" => \$useFrankASM, - "need=s" => \@neededUtilitySubRoutines, # option can be given multiple times - "srec" => \$generateSREC, - "no-blocks" => \$noBlocks, - "define=s" => \@defineList, - "stack-space=i" => \$stackSpace, - "output=s" => \$outputFilename, - )) -{ - usage(); - exit 1; -} - -if ($showHelp) -{ - usage(); - exit 0; -} - -if ($useFrankASM) -{ - $useLWASM = 0; -} - -my $source = shift; -if (!defined $source) -{ - usage(); - exit 1; -} -my $base = $source; -unless ($base =~ s/\.(asm|s)$//) -{ - print STDERR "cmoc: ERROR: source filename has unsupported assembler extension: $source\n"; - exit 1; -} - -if (!defined $outputFilename) # if not specified by --output -{ - $outputFilename = "$base.bin"; -} - -my $cppArgs = ""; -for my $includeDir (@includeDirList) -{ - $cppArgs .= " -I'$includeDir'"; -} -my $includeArgs = $cppArgs; -$cppArgs .= " -D$targetPlatformPreprocId=1" if defined $targetPlatformPreprocId; -$cppArgs .= " -D_CMOC_CHECK_NULL_POINTERS_=1" if $checkNullPointers; -$cppArgs .= " -D_CMOC_CHECK_STACK_OVERFLOW_=1" if $checkStackOverflow; -$cppArgs .= " -Dstack_space=$stackSpace"; - -# For each sub-routine name, define _CMOC_NEEDED_name_, so that the needed -# part of stdlib.inc will be assembled. -# -for my $subroutine (@neededUtilitySubRoutines) -{ - $subroutine =~ s/^_//; # avoid two consecutive underscores in the identifier - $cppArgs .= " -D_CMOC_NEED_${subroutine}_"; -} - -my $cmd = "cat $source @filenamesToAppend | cpp -P -traditional $cppArgs"; -print "Preprocessor command: $cmd\n" if $verbose; -if (!open(ASM, "$cmd |")) -{ - print STDERR "cmoc: ERROR: preprocessor failed: $!\n"; - exit 1; -} -if (!open(PREPROCESSED, "> $base.i")) -{ - print STDERR "cmoc: ERROR: could not create $base.i: $!\n"; - exit 1; -} - -# Read the preprocessed assembler (ASM), strip off the comments if using FrankASM, -# then write the rest into the PREPROCESSED file. -# -while () -{ - if ($useLWASM) - { - print PREPROCESSED; # lwasm accepts the .asm contents as is - next; - } - - # FrankASM mode: - - if (/^\s*\*/) # if whole line is a comment - { - print PREPROCESSED "\n"; # print an empty line - } - elsif (/^((\S+?):)?\s+\.(\S+)(.*)$/) # if other 'GNU as' directive - { - die; - my ($label, $directive, $args) = ($2, $3, $4); - die unless defined $directive; - die unless defined $args; - #print "LABEL [$label], " if defined $label; - #print "DIRECTIVE [$directive], ARGS [$args]\n"; - if ($directive eq "ascii") # if GNU as ASCII text directive - { - # Convert to frankasm directives. - die unless $args =~ /^\s+"(.*)"\s*$/; - my $string = $1; - - my $raLines = convertAsciiDirective($string); - for my $line (@$raLines) - { - print PREPROCESSED $line; - } - } - elsif ($directive eq "blkb") - { - die unless $args =~ /^\s+(\d+)$/; - my $numBytes = $1; - die unless $numBytes > 0; - print PREPROCESSED $label || "", "\tFCB\t", "0," x ($numBytes - 1), "0\n"; - } - elsif ($directive =~ /^(module|area|globl)$/) - { - # Ignore this directive. - } - else - { - die "cmoc: ERROR: invalid line: $_"; - print PREPROCESSED "\n"; # filter it out - } - } - elsif (/^(.*?)\t(.*?)\t(.*?)\t/) # if there are 3 tab characters - { - my $line = "$1\t$2\t" . fixConstants($3) . "\n"; - print PREPROCESSED $line; # omit everything from the 3rd tab - } - elsif (/^([a-z0-9_]+):(.*?)/i) # if label followed by colon - { - my $line = "$1\t" . fixConstants($2) . "\n"; - print PREPROCESSED $line; # remove colon - } - else # other lines are copied verbatim: - { - my $line = fixConstants($_); - print PREPROCESSED $line; - } -} - -close(PREPROCESSED) or die; -close(ASM) or exit 1; # exit here if #include directive failed to find its file - -# Remove the .hex file if it currently exists. -if (-e "$base.hex" && !unlink("$base.hex")) -{ - print "cmoc: ERROR: failed to erase existing $base.hex file.\n"; - exit 1; -} - -# Assemble the preprocessed, comment-less assembler file: -my $asmCmd; -if ($useLWASM) -{ - for my $define (@defineList) - { - $cppArgs .= " -D $define"; - } - - # Note: --pragma=forwardrefmax requires LWASM 4.11 or later. - $asmCmd = "lwasm --pragma=forwardrefmax --list=$base.lst --symbols $includeArgs$cppArgs"; - - if ($targetPlatformPreprocId eq "OS9") - { - $asmCmd .= " --format=os9 --output=$base"; - } - else - { - $asmCmd .= " --format=ihex --output=$base.hex"; - } - $asmCmd .= " $base.i"; -} -elsif ($targetPlatformPreprocId eq "OS9") -{ - print "cmoc: ERROR: LWASM is required to assemble for OS-9.\n"; - exit 1; -} -else -{ - # stderr redirected to /dev/null to avoid the two lines of error summary. - $asmCmd = "as6809 $base.i -l $base.lst -o $base.hex 2> /dev/null"; -} - -print "Assembler command: $asmCmd\n" if $verbose; -my $exitCode = system($asmCmd); -#print "Exit code: $exitCode\n"; -if ($exitCode == 0x7f00 || $exitCode == 0x0100) -{ - print STDERR "cmoc: ERROR: failed to run assembler command: $asmCmd: $!\n"; - exit 1; -} - -# If a hex file was produced, fix its entry point record (for the benefit of usim), -# then convert it to a CoCo .BIN file, and optionally to an SREC file. -# -if (-e "$base.hex") -{ - if (!$noBlocks) - { - fixIntelHexEntryPointRecord("$base.hex", $entry) - or exit 1; - } - - my $hexToBinCmd = "'$hexToBinConverterPath' "; - if ($targetPlatformPreprocId eq "VECTREX") - { - $hexToBinCmd .= "--no-blocks"; - } - else - { - if ($noBlocks) - { - $hexToBinCmd .= " --no-blocks"; - } - else - { - $hexToBinCmd .= "--entry=$entry"; - } - } - $hexToBinCmd .= " < '$base.hex' > '$outputFilename'"; - print "Generating BIN file: $hexToBinCmd\n" if $verbose; - system($hexToBinCmd) == 0 - or exit 1; - - if ($generateSREC) - { - my $hexToSRECCmd = "'$hexToSRECConverterPath' --entry=$entry < '$base.hex' > '$base.srec'"; - print "Generating SREC: $hexToSRECCmd\n" if $verbose; - system($hexToSRECCmd) == 0 - or exit 1; - } -} - - -# Read the .lst file to find some symbol addresses. - -{ - if (!open(LST, "$base.lst")) - { - print "cmoc: ERROR: failed to open assembly listing file $base.lst: $!\n"; - exit 1; - } - - my @notableSymbols = qw(program_start - program_end - writable_globals_start - writable_globals_end); # list order is display order - my %foundSymbols; - while () - { - if (/^\[ G\]\s+(\S+)\s+([0-9a-f]{4})/i) # e.g., [ G] program_start 2800 - { - my ($sym, $addr) = ($1, $2); - if (isStrInArray($sym, \@notableSymbols)) - { - $foundSymbols{$sym} = hex($addr); - } - } - } - - close(LST); - - if ($verbose) - { - my $promptPrinted = 0; - for my $sym (@notableSymbols) - { - if (defined $foundSymbols{$sym}) - { - if (!$promptPrinted) - { - print "Notable addresses:\n"; - $promptPrinted = 1; - } - printf(" %-24s \$%04X\n", $sym, $foundSymbols{$sym}); - } - } - } - - if (defined $limit) - { - my $program_end = $foundSymbols{program_end}; - if (!defined $program_end) - { - printf STDERR "cmoc: ERROR: code limit set at \$%s but program_end symbol not found in listing file\n", - uc($limit); - exit 1; - } - elsif ($program_end > hex($limit)) - { - printf STDERR "cmoc: ERROR: code limit set at \$%s but program_end exceeds it at \$%04X\n", - uc($limit), $program_end; - exit 1; - } - } - -} - -exit 0; diff -Nru cmoc-0.1.65/src/ASMText.cpp cmoc-0.1.67/src/ASMText.cpp --- cmoc-0.1.65/src/ASMText.cpp 2020-04-12 03:27:22.000000000 +0000 +++ cmoc-0.1.67/src/ASMText.cpp 2020-06-06 04:41:43.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: ASMText.cpp,v 1.127 2020/04/12 03:27:22 sarrazip Exp $ +/* $Id: ASMText.cpp,v 1.132 2020/06/06 04:41:43 sarrazip Exp $ CMOC - A C-like cross-compiler Copyright (C) 2003-2018 Pierre Sarrazin @@ -205,12 +205,9 @@ void -ASMText::writeInclude(ostream &out, const Element &e, bool monolithMode) +ASMText::writeInclude(ostream &out, const Element &e) { - if (monolithMode) - out << "#include \"" << e.fields[0] << "\"\n"; - else - out << "\t" "INCLUDE " << e.fields[0] << "\n"; + out << "\t" "INCLUDE " << e.fields[0] << "\n"; } @@ -273,7 +270,7 @@ { const Element &e = elements[i]; cout << "### " << setw(5) << i << ". "; - writeElement(cout, e, true); + writeElement(cout, e); switch (e.type) { case FUNCTION_START: @@ -642,6 +639,8 @@ modified = true; else if (optimizeDXAliases(i)) modified = true; + else if (removeLoadInComparisonWithTwoValues(i)) + modified = true; } } @@ -4415,6 +4414,67 @@ } +/* An expression like 'c < ' ' || c > 127' can give this code: + LDB 5,U variable c + CMPB #$20 + BLO foo + LDB 5,U variable c + CMPB #$7F + This function eliminates the 2nd LDB. +*/ +bool +ASMText::removeLoadInComparisonWithTwoValues(size_t index) +{ + // Check for starting LDB. + size_t firstLDBIndex = findNextInstrBeforeLabel(index); + if (firstLDBIndex == size_t(-1)) + return false; + const Element &firstLDB = elements[firstLDBIndex]; + if (firstLDB.fields[0] != "LDB") + return false; + + // Require a CMPB after LDB. + size_t firstCMPBIndex = findNextInstrBeforeLabel(firstLDBIndex + 1); + if (firstCMPBIndex == size_t(-1)) + return false; + const Element &firstCMPB = elements[firstCMPBIndex]; + if (firstCMPB.fields[0] != "CMPB") + return false; + + // Require a condition branch instruction after CMPB. + size_t branchIndex = findNextInstrBeforeLabel(firstCMPBIndex + 1); + if (branchIndex == size_t(-1)) + return false; + const Element &branch = elements[branchIndex]; + if (! isConditionalBranch(branch.fields[0].c_str())) + return false; + + // Require an LDB after the branch. + size_t secondLDBIndex = findNextInstrBeforeLabel(branchIndex + 1); + if (secondLDBIndex == size_t(-1)) + return false; + const Element &secondLDB = elements[secondLDBIndex]; + if (secondLDB.fields[0] != "LDB") + return false; + + // Require the 2nd LDB to have the same argument as the 1st one. + if (secondLDB.fields[1] != firstLDB.fields[1]) + return false; + + // Require a 2nd CMPB after the 2nd LDB. + size_t secondCMPBIndex = findNextInstrBeforeLabel(secondLDBIndex + 1); + if (secondCMPBIndex == size_t(-1)) + return false; + const Element &secondCMPB = elements[secondCMPBIndex]; + if (secondCMPB.fields[0] != "CMPB") + return false; + + // Remove the 2nd LDB. + commentOut(secondLDBIndex, "optim: removeLoadInComparisonWithTwoValues"); + return true; // modified the code +} + + bool ASMText::isInstr(size_t index, const char *ins, const char *arg) const { @@ -4590,7 +4650,7 @@ // the branch instruction that is equivalent when the comparison operands // are reversed. // For example, if k <= n is to be replaced with n >= k, then -// { LDD k; CMPD n; BLS z } must be replaced with { LDD n; CMPD k; BHS z }. +// { LDD k; CMPD n; BLS z } must be replaced with { LDD n; CMPD k; BHS z }. // bool ASMText::isRelativeSizeConditionalBranch(size_t index, char invertedOperandsBranchInstr[INSTR_NAME_BUFSIZ]) const @@ -4707,7 +4767,8 @@ } -// Returns size_t(-1) if no instruction found before a non-instruction is found. +// Returns size_t(-1) if no instruction is found before a non-instruction is found. +// The search starts at elements[index], inclusively. // Tolerates comments. // size_t @@ -4843,7 +4904,7 @@ void -ASMText::writeElement(ostream &out, const Element &e, bool monolithMode) +ASMText::writeElement(ostream &out, const Element &e) { switch (e.type) { @@ -4852,7 +4913,7 @@ case LABEL: writeLabel(out, e); break; case COMMENT: writeComment(out, e); break; case SEPARATOR: writeSeparatorComment(out, e); break; - case INCLUDE: writeInclude(out, e, monolithMode); break; + case INCLUDE: writeInclude(out, e); break; case FUNCTION_START: out << "* FUNCTION " << e.fields[0] << "(): defined at " << e.fields[1] << "\n"; break; @@ -4863,20 +4924,16 @@ out << "funcsize_" << e.fields[0] << "\tEQU\tfuncend_" << e.fields[0] << "-_" << e.fields[0] << "\n"; break; case SECTION_START: - if (!monolithMode) - out << "\n\n\t""SECTION\t" << e.fields[0] << "\n\n\n"; + out << "\n\n\t""SECTION\t" << e.fields[0] << "\n\n\n"; break; case SECTION_END: - if (!monolithMode) - out << "\n\n\t""ENDSECTION\n\n\n"; + out << "\n\n\t""ENDSECTION\n\n\n"; break; case EXPORT: - if (!monolithMode) - out << e.fields[0] << "\t""EXPORT\n"; + out << e.fields[0] << "\t""EXPORT\n"; break; case IMPORT: - if (!monolithMode) - out << e.fields[0] << "\t""IMPORT\n"; + out << e.fields[0] << "\t""IMPORT\n"; break; case END: out << "\t""END\n"; @@ -4887,10 +4944,10 @@ bool -ASMText::writeFile(ostream &out, bool monolithMode) +ASMText::writeFile(ostream &out) { for (vector::const_iterator it = elements.begin(); it != elements.end(); ++it) - writeElement(out, *it, monolithMode); + writeElement(out, *it); return out.good(); } diff -Nru cmoc-0.1.65/src/ASMText.h cmoc-0.1.67/src/ASMText.h --- cmoc-0.1.65/src/ASMText.h 2020-02-09 17:47:15.000000000 +0000 +++ cmoc-0.1.67/src/ASMText.h 2020-05-16 22:18:36.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: ASMText.h,v 1.66 2019/10/09 01:42:01 sarrazip Exp $ +/* $Id: ASMText.h,v 1.68 2020/05/13 23:23:50 sarrazip Exp $ CMOC - A C-like cross-compiler Copyright (C) 2003-2018 Pierre Sarrazin @@ -31,7 +31,7 @@ // Internal representation of the assembly language program. // The ins() and "emit" methods accumulate elements in memory, // then the writeFile() method writes the assembly to a text file. -// Before calling writeFile(), optimizations could be made. +// Before calling writeFile(), optimizations can be made. // class ASMText { @@ -61,7 +61,7 @@ // Does not close 'out'. // Returns out.good(). // - bool writeFile(std::ostream &out, bool monolithMode); + bool writeFile(std::ostream &out); // ins: Comparison is case-insensitive. Long branches are also recognized. // BRA and BRN are not considered to be conditional branches. @@ -110,13 +110,13 @@ void addElement(Type type, const std::string &field0 = "", const std::string &field1 = "", const std::string &field2 = ""); // Actual assembly writing methods: - void writeElement(std::ostream &out, const Element &e, bool monolithMode); + void writeElement(std::ostream &out, const Element &e); void writeIns(std::ostream &out, const Element &e); void writeLabel(std::ostream &out, const Element &e); void writeInlineAssembly(std::ostream &out, const Element &e); void writeComment(std::ostream &out, const Element &e); void writeSeparatorComment(std::ostream &out, const Element &e); - void writeInclude(std::ostream &out, const Element &e, bool monolithMode); + void writeInclude(std::ostream &out, const Element &e); // Optimization names: bool branchToNextLocation(size_t index); @@ -189,6 +189,7 @@ bool removeUselessTfr2(size_t index); bool removeUselessClrb(size_t index); bool optimizeDXAliases(size_t index); + bool removeLoadInComparisonWithTwoValues(size_t index); // Whole-function optimizer: bool isBasicBlockEndingInstruction(const Element &e) const; diff -Nru cmoc-0.1.65/src/BinaryOpExpr.cpp cmoc-0.1.67/src/BinaryOpExpr.cpp --- cmoc-0.1.65/src/BinaryOpExpr.cpp 2020-04-12 03:27:22.000000000 +0000 +++ cmoc-0.1.67/src/BinaryOpExpr.cpp 2020-06-07 14:53:53.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: BinaryOpExpr.cpp,v 1.158 2020/04/12 03:27:22 sarrazip Exp $ +/* $Id: BinaryOpExpr.cpp,v 1.163 2020/06/07 14:53:53 sarrazip Exp $ CMOC - A C-like cross-compiler Copyright (C) 2003-2020 Pierre Sarrazin @@ -32,6 +32,7 @@ #include "FunctionCallExpr.h" #include "DWordConstantExpr.h" #include "StringLiteralExpr.h" +#include "CommaExpr.h" #include @@ -1717,11 +1718,81 @@ CodeStatus BinaryOpExpr::emitShift(ASMText &out, bool isLeftShift, bool changeLeftSide, bool lValue) const { + uint16_t numBits = 0; + bool constShift = subExpr1->evaluateConstantExpr(numBits); + if (lValue && isLong()) { assert(subExpr0->isLong()); assert(subExpr0->isSigned() == isSigned()); + // Special case: Shifting unsigned long in place by 8, 16 or 24 bits. + if (!resultDeclaration && !subExpr0->isSigned() && constShift && (numBits == 8 || numBits == 16 || numBits == 24)) + { + if (!subExpr0->emitCode(out, true)) // get address of left side long in X + return false; + if (isLeftShift) + { + switch (numBits) + { + case 8: + out.ins("LDD", "1,X", "load middle word of unsigned long"); + out.ins("STD", ",X", "store in high word of unsigned long"); + out.ins("LDB", "3,X", "load low byte of unsigned long"); + out.ins("STB", "2,X", "store in 2nd lowest byte of unsigned long"); + out.ins("CLR", "3,X", "clear low byte"); + break; + case 16: + out.ins("LDD", "2,X", "load low word of unsigned long"); + out.ins("STD", ",X", "store in high word of unsigned long"); + out.ins("CLR", "2,X", "clear 2nd lowest byte"); + out.ins("CLR", "3,X", "clear low byte"); + break; + case 24: + out.ins("LDB", "3,X", "load low byte of unsigned long"); + out.ins("STB", ",X", "store in high byte of unsigned long"); + out.ins("CLR", "1,X", "clear 2nd higest byte"); + out.ins("CLR", "2,X", "clear 2nd lowest byte"); + out.ins("CLR", "3,X", "clear low byte"); + break; + default: + assert(false); + return false; + } + } + else + { + switch (numBits) + { + case 8: + out.ins("LDD", "1,X", "load middle word of unsigned long"); + out.ins("STD", "2,X", "store in low word of unsigned long"); + out.ins("LDB", ",X", "load high byte of unsigned long"); + out.ins("STB", "1,X", "store in 2nd highest byte of unsigned long"); + out.ins("CLR", ",X", "clear high byte"); + break; + case 16: + out.ins("LDD", ",X", "load high word of unsigned long"); + out.ins("STD", "2,X", "store in low word of unsigned long"); + out.ins("CLR", ",X", "clear highest byte"); + out.ins("CLR", "1,X", "clear 2nd higest byte"); + break; + case 24: + out.ins("LDB", ",X", "load high byte of unsigned long"); + out.ins("STB", "3,X", "store in low byte of unsigned long"); + out.ins("CLR", ",X", "clear highest byte"); + out.ins("CLR", "1,X", "clear 2nd higest byte"); + out.ins("CLR", "2,X", "clear 2nd lowest byte"); + break; + default: + assert(false); + return false; + } + } + return true; // leave with address of unsigned long in X, since we are emitting an l-value + } + + // Evaluate the number of bits to shift by. if (subExpr1->isLong()) { if (!subExpr1->emitCode(out, true)) // get address of long in X @@ -1734,7 +1805,8 @@ if (!subExpr1->emitCode(out, false)) // get number of shifts in D return false; } - if (!isLeftShift) // if right shift on signed value, do arithmetic shift, i.e., sign extension + + if (!isLeftShift) // if right shift { if (isSigned()) out.ins("LDA", "#$FF", "request sign extension"); @@ -1758,9 +1830,6 @@ bool isLeftByte = (getType() == BYTE_TYPE); - uint16_t numBits = 0; - bool constShift = subExpr1->evaluateConstantExpr(numBits); - if (constShift && numBits <= 7) // if number of bits to shift by is a constant and small { // If changeLeftSide true, get address of left side in X. @@ -3107,8 +3176,23 @@ } - // Not ||, && or relational operator, so compare expression with zero: + // Not ||, && or relational operator. + // If comma operator, evaluate all sub-expression except last, then call + // this function recursively on last sub-expr. + // + if (const CommaExpr *commaExpr = dynamic_cast(condition)) + { + assert(commaExpr->size() >= 2); + vector::const_iterator it; + for (it = commaExpr->begin(); it + 1 != commaExpr->end(); ++it) + if (!(*it)->emitCode(out, false)) // emit code but ignore resulting value + return false; + return BinaryOpExpr::emitBoolJumps(out, *it, successLabel, failureLabel); + } + + // For a struct-based type, we have to evaluate an l-value. + // if (condition->isRealOrLong()) { if (!condition->emitCode(out, true)) // get address of number in X diff -Nru cmoc-0.1.65/src/check-long.c cmoc-0.1.67/src/check-long.c --- cmoc-0.1.65/src/check-long.c 2020-02-09 03:42:38.000000000 +0000 +++ cmoc-0.1.67/src/check-long.c 2020-06-07 14:34:06.000000000 +0000 @@ -1,5 +1,6 @@ #include +#define PROGRAM "check-long.c" typedef unsigned long ulong; @@ -9,7 +10,7 @@ #define assert(cond) do { ++numAsserts; \ /*printf("TEST AT LINE %u\n", __LINE__);*/ \ if (!(cond)) { \ - printf("*** ERROR: ASSERT FAILED: LINE %d\n", __LINE__); \ + printf(PROGRAM ": ERROR: ASSERT FAILED: LINE %d\n", __LINE__); \ ++numErrors; \ exit(1); \ } \ @@ -1205,8 +1206,8 @@ #endif if (numErrors == 0) - printf("SUCCESS (%u ASSERTS PASSED).\n", numAsserts); + printf(PROGRAM ": SUCCESS (%u ASSERTS PASSED).\n", numAsserts); else - printf("FAILURE: %u ERROR(S) OUT OF %u ASSERTS.\n", numErrors, numAsserts); + printf(PROGRAM ": FAILURE: %u ERROR(S) OUT OF %u ASSERTS.\n", numErrors, numAsserts); return 0; } diff -Nru cmoc-0.1.65/src/Declaration.cpp cmoc-0.1.67/src/Declaration.cpp --- cmoc-0.1.65/src/Declaration.cpp 2020-02-15 03:01:52.000000000 +0000 +++ cmoc-0.1.67/src/Declaration.cpp 2020-05-10 02:30:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: Declaration.cpp,v 1.103 2020/02/14 03:19:56 sarrazip Exp $ +/* $Id: Declaration.cpp,v 1.104 2020/04/30 01:17:55 sarrazip Exp $ CMOC - A C-like cross-compiler Copyright (C) 2003-2018 Pierre Sarrazin @@ -834,13 +834,57 @@ } +// Returns true iff tree if name[...][...][...]... +// +static bool +isMatrixElementReferenceOnArrayName(const Tree &tree) +{ + const BinaryOpExpr *bin = dynamic_cast(&tree); + if (!bin) + return false; + if (bin->getOperator() != BinaryOpExpr::ARRAY_REF) + return false; + if (bin->getLeft()->asVariableExpr()) + return true; // left side is name + return isMatrixElementReferenceOnArrayName(*bin->getLeft()); // recurse +} + + +// Returns true iff all expressions in name[...][...][...] are constant. +// Must only be called on trees on which isMatrixElementReferenceOnArrayName() returns true. +// +static bool +isConstantExprArrayRefChain(const Tree &tree) +{ + const BinaryOpExpr *bin = dynamic_cast(&tree); + assert(bin && bin->getOperator() == BinaryOpExpr::ARRAY_REF); + + // Check that bracket expression is constant. + uint16_t value; + if (!bin->getRight()->evaluateConstantExpr(value)) + return false; + + if (bin->getLeft()->asVariableExpr()) + return true; + + return isConstantExprArrayRefChain(*bin->getLeft()); +} + + static bool isAddressOfVariable(const Tree &tree) { const UnaryOpExpr *u = dynamic_cast(&tree); if (!u || u->getOperator() != UnaryOpExpr::ADDRESS_OF) return u; - return u->getSubExpr()->asVariableExpr() != NULL; + const Tree *subExpr = u->getSubExpr(); + if (subExpr->asVariableExpr() != NULL) + return true; + + if (isMatrixElementReferenceOnArrayName(*subExpr)) + return isConstantExprArrayRefChain(*subExpr); + + return false; } diff -Nru cmoc-0.1.65/src/DeclarationSequence.h cmoc-0.1.67/src/DeclarationSequence.h --- cmoc-0.1.65/src/DeclarationSequence.h 2020-04-04 17:41:44.000000000 +0000 +++ cmoc-0.1.67/src/DeclarationSequence.h 2020-06-06 04:41:43.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: DeclarationSequence.h,v 1.7 2020/04/04 17:41:44 sarrazip Exp $ +/* $Id: DeclarationSequence.h,v 1.8 2020/06/06 04:41:43 sarrazip Exp $ CMOC - A C-like cross-compiler Copyright (C) 2003-2015 Pierre Sarrazin @@ -63,7 +63,7 @@ private: - std::vector *enumeratorList; // owns the vector<>, but not the Enumerator objects + std::vector *enumeratorList; // owns the vector<>, but not the Enumerator objects }; diff -Nru cmoc-0.1.65/src/float/Makefile.am cmoc-0.1.67/src/float/Makefile.am --- cmoc-0.1.65/src/float/Makefile.am 2018-10-28 13:42:42.000000000 +0000 +++ cmoc-0.1.67/src/float/Makefile.am 2020-06-06 04:41:44.000000000 +0000 @@ -1,4 +1,4 @@ -# $Id: Makefile.am,v 1.6 2018/10/28 13:42:42 sarrazip Exp $ +# $Id: Makefile.am,v 1.7 2020/06/06 04:41:44 sarrazip Exp $ cmoclibdir = $(pkgdatadir)/lib cmoclib_DATA = \ @@ -90,6 +90,14 @@ .c.ecb_o: ../cmoc -c $(CMOC_LIB_FLAGS) -o $@ $< +# Checks if some files contain non-breakable spaces (character 160). +# The statement in the 'continue' clause resets the line counter ($.) +# at the end of each processed file. +# +check: + $(PERL) -e 'while (<>) { if (/\xA0/) { print "ERROR: non-breakable space at $$ARGV:$$.\n"; exit 1 } } continue { close ARGV if eof }' \ + $(ASM) $(C_COCO_BASIC) Makefile.am + CLEANFILES = $(cmoclib_DATA) $(ECB_OBJ) $(ECB_OBJ:.ecb_o=.s) $(ECB_OBJ:.ecb_o=.lst) EXTRA_DIST = float.inc $(ASM) $(C_COCO_BASIC) diff -Nru cmoc-0.1.65/src/float/Makefile.in cmoc-0.1.67/src/float/Makefile.in --- cmoc-0.1.65/src/float/Makefile.in 2020-04-25 02:27:42.000000000 +0000 +++ cmoc-0.1.67/src/float/Makefile.in 2020-06-07 14:57:21.000000000 +0000 @@ -14,7 +14,7 @@ @SET_MAKE@ -# $Id: Makefile.am,v 1.6 2018/10/28 13:42:42 sarrazip Exp $ +# $Id: Makefile.am,v 1.7 2020/06/06 04:41:44 sarrazip Exp $ VPATH = @srcdir@ am__is_gnu_make = { \ @@ -558,6 +558,14 @@ .c.ecb_o: ../cmoc -c $(CMOC_LIB_FLAGS) -o $@ $< +# Checks if some files contain non-breakable spaces (character 160). +# The statement in the 'continue' clause resets the line counter ($.) +# at the end of each processed file. +# +check: + $(PERL) -e 'while (<>) { if (/\xA0/) { print "ERROR: non-breakable space at $$ARGV:$$.\n"; exit 1 } } continue { close ARGV if eof }' \ + $(ASM) $(C_COCO_BASIC) Makefile.am + # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: diff -Nru cmoc-0.1.65/src/FunctionCallExpr.cpp cmoc-0.1.67/src/FunctionCallExpr.cpp --- cmoc-0.1.65/src/FunctionCallExpr.cpp 2020-02-09 17:47:15.000000000 +0000 +++ cmoc-0.1.67/src/FunctionCallExpr.cpp 2020-05-10 02:30:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: FunctionCallExpr.cpp,v 1.81 2019/10/12 22:47:12 sarrazip Exp $ +/* $Id: FunctionCallExpr.cpp,v 1.84 2020/05/07 01:04:08 sarrazip Exp $ CMOC - A C-like cross-compiler Copyright (C) 2003-2015 Pierre Sarrazin @@ -42,8 +42,7 @@ function(func), funcPtrVarDecl(NULL), arguments(args), - returnValueDeclaration(NULL), - monolithMode(false) + returnValueDeclaration(NULL) { assert(function != NULL); assert(arguments != NULL); @@ -529,7 +528,6 @@ { // Register this function call for the purposes of determining which functions // are never called and do not need to have assembly code emitted for them. - // (The preceding applies to monolith mode only.) // When there is no calling function (as in a global variable's initialization // expression), we do as if main() were the caller. This is not actually the // case, because the caller is the INITGL routine, but it is close enough for @@ -846,21 +844,6 @@ TranslationUnit &tu = TranslationUnit::instance(); - /* Special cases: functions that are defined in the standard library. - */ - if (monolithMode && !functionId.empty()) // if standard call (i.e., not made through pointer) - { - const FunctionDef *fd = tu.getFunctionDef(functionId); - if (fd == NULL || fd->getBody() == NULL) // if not declared or does not have a body - { - // If the function body is provided by the standard library, register the name as - // a needed utility sub-routine. - // - tu.checkForNeededUtility(functionId); - } - } - - uint16_t numBytesPushed = 0; if (!emitArgumentPushCode(out, functionId, numBytesPushed)) diff -Nru cmoc-0.1.65/src/FunctionCallExpr.h cmoc-0.1.67/src/FunctionCallExpr.h --- cmoc-0.1.65/src/FunctionCallExpr.h 2020-02-09 17:47:15.000000000 +0000 +++ cmoc-0.1.67/src/FunctionCallExpr.h 2020-05-10 02:30:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: FunctionCallExpr.h,v 1.23 2019/10/12 22:47:12 sarrazip Exp $ +/* $Id: FunctionCallExpr.h,v 1.24 2020/05/07 00:26:10 sarrazip Exp $ CMOC - A C-like cross-compiler Copyright (C) 2003-2015 Pierre Sarrazin @@ -34,8 +34,6 @@ virtual ~FunctionCallExpr(); - void setMonolithMode(bool _monolithMode) { monolithMode = _monolithMode; } - /** Checks that this function call is valid and sets the return TypeDesc. If errors are detected, they are reported. @returns true if the call is valid, @@ -110,7 +108,6 @@ Declaration *funcPtrVarDecl; // non null when calling through function pointer variable TreeSequence *arguments; // owns the pointed object Declaration *returnValueDeclaration; // used when return type is struct/union; owns the pointed object - bool monolithMode; }; diff -Nru cmoc-0.1.65/src/intelhex2cocobin cmoc-0.1.67/src/intelhex2cocobin --- cmoc-0.1.65/src/intelhex2cocobin 2016-04-10 19:20:25.000000000 +0000 +++ cmoc-0.1.67/src/intelhex2cocobin 1970-01-01 00:00:00.000000000 +0000 @@ -1,141 +0,0 @@ -#!/usr/bin/perl -w -# -# Reads Intel Hex format from and writes CoCo binary format to STDOUT. -# @sarrazip 20010827 -# -# Example of Intel Hex format: -# -#:0f6000008e0400a6848840a7808c060025f53901 -# ^^^^^^^^ ^^ -# | | | | -# | | | `--- 8-bit checksum -# | | `--- 7..8: record type: 0 = data record -# | `--- 3..6: 16-bit destination address of content bytes -# `--- 1..2: number of content bytes (0..255) -# -#:00000001ff -# ^^ -# | -# `--- 7..8: record type: 1 = end of file record -# -# Details: http://en.wikipedia.org/wiki/Intel_HEX -# -# --no-blocks: Allows reusing this script for the Vectrex target: -# - no 5-byte blocks; -# - always use zero-padding between non-contiguous Intel Hex records. - -use strict; -use Getopt::Long; - -my $contents = ""; -my $curBlockStart; # address where $contents goes -my $firstAddress; -my $entryPoint; # undef means use $firstAddress -my $noBlocks = 0; - - -# Writes a .BIN block whose start address is $curBlockStart -# and whose contents is $contents. -# Empties $contents. Undefined $curBlockStart. -# -sub writeBlock -{ - die unless defined $curBlockStart; - die unless length($contents) <= 0xFFFF; - if (!$noBlocks) - { - print pack("Cnn", 0x00, length($contents), $curBlockStart); - } - print $contents; - $contents = ""; - $curBlockStart = undef; -} - - -if (!GetOptions( - "entry=s" => \$entryPoint, - "no-blocks" => \$noBlocks, - )) -{ - usage(); - exit 1; -} - -if (defined $entryPoint) # if option used -{ - die if $noBlocks; # not relevant for Vectrex - die unless $entryPoint =~ /^[0-9a-f]+$/i; - $entryPoint = hex($entryPoint); - die unless $entryPoint <= 0xFFFF; -} - -my $writerAddress; - -while (<>) # for each line read -{ - #print STDERR "Line: $_"; - die unless /^:/; # must begin with colon - my $numBytes = hex(substr($_, 1, 2)); # number of bytes encoded on this line (as per Intel HEX format) - my $address = hex(substr($_, 3, 4)); # address where these bytes go - if (!defined $firstAddress) # if first line read - { - $firstAddress = $address; # remember start of program - $writerAddress = $address; - } - if (!defined $curBlockStart) - { - $curBlockStart = $address; - } - my $type = hex(substr($_, 7, 2)); # 00 means byte record, 01 means entry point record - #printf STDERR "numBytes=0x%02x, address=0x%04x, type=0x%02x\n", $numBytes, $address, $type; - if ($type == 0) # if byte record - { - # If block starts later than previous block ended, - # we typically have advanced because of an RMB directive. - # If we have not advanced too much, stuff zeroes in $contents. - # Otherwise, start a new .BIN block. - # - #printf STDERR "address=%x, writerAddress=%x\n", $address, $writerAddress; - if ($address > $writerAddress && ($noBlocks || $address - $writerAddress < 16)) - { - my $numPaddingBytes = $address - $writerAddress; - $contents .= pack("C", 0) x $numPaddingBytes; - } - elsif ($address != $writerAddress) # if new block is not at current writing position - { - writeBlock(); - $curBlockStart = $address; # remember start of new block - } - - $writerAddress = $address; - - die "$writerAddress vs $address" unless $writerAddress == $address; - - for (my $i = 0; $i < $numBytes; $i++) - { - $contents .= pack("C", hex(substr($_, 9 + 2 * $i, 2))); - } - - $writerAddress += $numBytes; - } - elsif ($type == 1) # if entry point record - { - if (!$noBlocks) - { - writeBlock(); - print pack("Cnn", 0xFF, 0, $entryPoint || $firstAddress); - } - last; - } - else - { - die "Line $. has unknown type $type\n"; - } -} - -# Write out last block, if any. -# -if (length($contents) > 0) -{ - writeBlock(); -} diff -Nru cmoc-0.1.65/src/intelhex2srec cmoc-0.1.67/src/intelhex2srec --- cmoc-0.1.65/src/intelhex2srec 2016-07-12 03:50:23.000000000 +0000 +++ cmoc-0.1.67/src/intelhex2srec 1970-01-01 00:00:00.000000000 +0000 @@ -1,89 +0,0 @@ -#!/usr/bin/perl -w -# -# Reads the Intel Hex format from and writes in the Motorola SREC -# format to STDOUT. -# @sarrazip 20150810 -# -# Example of Intel Hex format: -# -#:0f6000008e0400a6848840a7808c060025f53901 -# ^^^^^^^^ ^^ -# | | | | -# | | | `--- 8-bit checksum -# | | `--- 7..8: record type: 0 = data record -# | `--- 3..6: 16-bit destination address of content bytes -# `--- 1..2: number of content bytes (0..255) -# -#:00000001ff -# ^^ -# | -# `--- 7..8: record type: 1 = end of file record -# -# Details: http://en.wikipedia.org/wiki/Intel_HEX -# Details: https://en.wikipedia.org/wiki/SREC_%28file_format%29 - -use strict; -use Getopt::Long; - - -# Returns a 2-digit hex string. -# -sub computeChecksum($) -{ - my ($hex) = @_; - - my $sum = 0; - while ($hex =~ s/^(..)//) - { - $sum += hex($1); - } - return sprintf("%02X", 0xFF - ($sum & 0xFF)); # 1's complement -} - - -my $entryPointHex; # hex string, not numerical address; undef means use first address encountered - - -if (!GetOptions( - "entry=s" => \$entryPointHex, - )) -{ - usage(); - exit 1; -} - -if (defined $entryPointHex) # if option used -{ - die unless $entryPointHex =~ /^[0-9a-f]+$/i; - die unless hex($entryPointHex) <= 0xFFFF; -} - - -while (<>) # for each line read -{ - die unless /^:/; # must begin with colon - my $type = hex(substr($_, 7, 2)); # 00 means byte record, 01 means entry point record - if ($type == 0) # if byte record - { - my $hexData = substr($_, 9); # get string from offset 9 to end - $hexData =~ s/[0-9a-f]{2}\s+$//si; # remove 2-digit hex checksum and trailing end-of-line chars - my $numBytesHex = sprintf("%02X", (hex(substr($_, 1, 2)) + 3) & 0xFF); - my $addressHex = substr($_, 3, 4); - if (!defined $entryPointHex) - { - $entryPointHex = $addressHex; - } - my $checkSumHex = computeChecksum($numBytesHex . $addressHex . $hexData); - print "S1", $numBytesHex, $addressHex, $hexData, $checkSumHex, "\n"; - } - elsif ($type == 1) # if entry point record - { - my $checkSumHex = computeChecksum("03" . $entryPointHex); # 03 = 3 bytes of data: 16-bit address and checksum byte - print "S9", "03", $entryPointHex, $checkSumHex, "\n"; - last; - } - else - { - die "Line $. has unknown type $type\n"; - } -} diff -Nru cmoc-0.1.65/src/main.cpp cmoc-0.1.67/src/main.cpp --- cmoc-0.1.65/src/main.cpp 2020-04-04 17:14:41.000000000 +0000 +++ cmoc-0.1.67/src/main.cpp 2020-05-11 02:27:47.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: main.cpp,v 1.125 2020/03/02 01:42:19 sarrazip Exp $ +/* $Id: main.cpp,v 1.131 2020/05/07 01:12:36 sarrazip Exp $ CMOC - A C-like cross-compiler Copyright (C) 2003-2020 Pierre Sarrazin @@ -73,17 +73,6 @@ string pkgdatadir; // directory where CMOC support files (.h, etc.) get installed - string getAssemblerFilename() const - { - if (assemblerFilename.empty()) - return pkgdatadir + "/a09"; - return assemblerFilename; - } - void setAssemblerFilename(const string &newFilename) - { - assemblerFilename = newFilename; - } - string lwasmPath; string lwlinkPath; @@ -105,17 +94,16 @@ TargetPlatform targetPlatform; bool assumeTrack34; // true = CoCo DECB Track 34 (relevant only with COCO_BASIC) bool generateSREC; // generate a Motorola SREC executable - bool emitUncalledFunctions; bool callToUndefinedFunctionAllowed; bool warnSignCompare; bool warnPassingConstForFuncPtr; bool isConstIncorrectWarningEnabled; bool isBinaryOpGivingByteWarningEnabled; + bool isLocalVariableHidingAnotherWarningEnabled; bool wholeFunctionOptimization; bool forceJumpMode; SwitchStmt::JumpMode forcedJumpMode; - bool monolithMode; // true means linker mode (lwasm, lwlink) size_t optimizationLevel; bool stackSpaceSpecifiedByCommandLine; uint16_t limitAddress; // see --limit; 0xFFFF means not applicable @@ -131,8 +119,6 @@ list defines; private: - string assemblerFilename; // if empty, formed from pkgdatadir (useful monolith mode only) - static uint32_t getVersionInteger(); public: @@ -161,16 +147,15 @@ targetPlatform(COCO_BASIC), assumeTrack34(false), generateSREC(false), - emitUncalledFunctions(false), callToUndefinedFunctionAllowed(false), warnSignCompare(false), warnPassingConstForFuncPtr(false), isConstIncorrectWarningEnabled(true), isBinaryOpGivingByteWarningEnabled(false), + isLocalVariableHidingAnotherWarningEnabled(false), wholeFunctionOptimization(false), forceJumpMode(false), forcedJumpMode(SwitchStmt::IF_ELSE), - monolithMode(false), optimizationLevel(2), stackSpaceSpecifiedByCommandLine(false), limitAddress(0xFFFF), @@ -181,8 +166,7 @@ relocatabilitySupported(true), includeDirList(), searchDefaultIncludeDirs(true), - defines(), - assemblerFilename() + defines() { } @@ -251,7 +235,6 @@ "--srec Executable in Motorola SREC format (Disk Basic only).\n" "--lwasm=X Use X as the path to the LWTOOLS assembler.\n" "--lwlink=X Use X as the path to the LWTOOLS linker.\n" - //"--a09=X Use assembler specified by path X instead of installed a09.\n" "-Idir Add directory to the compiler's include directories\n" " (also applies to assembler).\n" "-Dxxx=yyy Equivalent to #define xxx yyy\n" @@ -271,11 +254,11 @@ "--function-stack=N (OS-9 only.) Emit code at the start of each function to check that there\n" " is at least N bytes of free stack space in addition to local variables.\n" " 0 means no stack checking. Default is 64.\n" - //"--emit-uncalled Emit functions even if they are not called by C code.\n" //"--allow-undef-func Allow calls to undefined functions.\n" "-Wsign-compare Warn when <, <=, >, >= used on operands of differing signedness.\n" "-Wno-const Do not warn about const-incorrect code.\n" "-Wgives-byte Warn about binary operations on bytes giving a byte.\n" + "-Wlocal-var-hiding Warn when a local variable hides another one.\n" "--switch=MODE Force all switch() statements to use MODE, where MODE is 'ifelse'\n" " for an if-else sequence or 'jump' for a jump table.\n" "-O0|-O1|-O2 Optimization level (default is 2). Compilation is faster with -O0.\n" @@ -284,7 +267,6 @@ "-o FILE Place the output in FILE (default: change C file extension to .bin).\n" "--intermediate|-i Keep intermediate compilation and linking files.\n" "--intdir=D Put intermediate files in directory D.\n" - "--monolith Compile one C file as a single unit, rather than use the linker mode.\n" "\n"; cout << "Compiler data directory: " << params.pkgdatadir << "\n\n"; @@ -1013,10 +995,7 @@ } -// In monolith mode, finishes with generation of the assembly file. -// In linker mode, also invokes the assembler on that file. -// -// compilationOutputFilename: Only used if !monolithMode. +// Generates the assembly file and invokes the assembler on that file. // // Returns EXIT_SUCCESS or EXIT_FAILURE. // @@ -1028,7 +1007,7 @@ const char *targetPlatformName, const char *targetPreprocId) { - assert(!compilationOutputFilename.empty() || monolithMode); + assert(!compilationOutputFilename.empty()); if (verbose) { @@ -1044,8 +1023,6 @@ cppCommand << " -I'" << *it << "'"; cppCommand << " -D_CMOC_VERSION_=" << getVersionInteger(); cppCommand << " -D" << targetPreprocId << "=1"; - if (monolithMode) - cppCommand << " -DCMOC_MONOLITH"; cppCommand << " -U__GNUC__ -nostdinc -undef"; for (list::const_iterator it = defines.begin(); it != defines.end(); ++it) @@ -1076,6 +1053,7 @@ warnPassingConstForFuncPtr, isConstIncorrectWarningEnabled, isBinaryOpGivingByteWarningEnabled, + isLocalVariableHidingAnotherWarningEnabled, relocatabilitySupported); char buffer[8192]; while (fgets(buffer, sizeof(buffer), yyin) != NULL) // while a line can be read @@ -1108,22 +1086,18 @@ } - TranslationUnitDestroyer tud(!monolithMode); // destroy TU at end of this function, when in linker mode + TranslationUnitDestroyer tud(true); // destroy TU at end of this function if (numErrors == 0 && !params.generatePrerequisitesFileOnly) { - // Create the translation unit object, if in linker mode. - // In that mode, each .c file must be compiled as a separate unit. - // In monolith mode, we use a single unit, which must have been created by the caller. - // - if (!monolithMode) - TranslationUnit::createInstance(targetPlatform, + TranslationUnit::createInstance(targetPlatform, callToUndefinedFunctionAllowed, warnSignCompare, warnPassingConstForFuncPtr, isConstIncorrectWarningEnabled, isBinaryOpGivingByteWarningEnabled, + isLocalVariableHidingAnotherWarningEnabled, relocatabilitySupported); TranslationUnit &tu = TranslationUnit::instance(); @@ -1138,7 +1112,7 @@ tu.processPragmas(params.codeAddress, params.codeAddressSetBySwitch, limitAddress, limitAddressSetBySwitch, params.dataAddress, params.dataAddressSetBySwitch, - pragmaStackSpace, monolithMode, compileOnly); + pragmaStackSpace, compileOnly); /* Apply #pragma stack_space only if --stack-space not used. */ @@ -1181,7 +1155,7 @@ if (numErrors == 0) { - tu.checkSemantics(params.monolithMode); // this is when Scope objects get created in FunctionDefs + tu.checkSemantics(); // this is when Scope objects get created in FunctionDefs tu.allocateLocalVariables(); // in all FunctionDef objects } @@ -1199,8 +1173,7 @@ if (numErrors == 0) { - tu.emitAssembler(asmText, moduleName, compileOnly, params.codeAddress, params.dataAddress, - params.stackSpace, assumeTrack34, emitUncalledFunctions, monolithMode); + tu.emitAssembler(asmText, params.dataAddress, params.stackSpace, assumeTrack34); if (optimizationLevel > 0) asmText.peepholeOptimize(optimizationLevel == 2); @@ -1222,8 +1195,6 @@ { if (verbose) { - if (monolithMode) - cout << "Assembler: " << assemblerFilename << "\n"; cout << "Assembly language filename: " << asmFilename << "\n"; cout << flush; } @@ -1235,7 +1206,7 @@ << ": " << strerror(e) << endl; return EXIT_FAILURE; } - if (!asmText.writeFile(asmFile, monolithMode)) + if (!asmText.writeFile(asmFile)) { cout << PACKAGE << fatalErrorPrefix << "failed to write output assembly file " << asmFilename << endl; return EXIT_FAILURE; @@ -1259,7 +1230,7 @@ return EXIT_FAILURE; } - if (!monolithMode && params.generatePrerequisitesFile) + if (params.generatePrerequisitesFile) { string dependenciesFilename = replaceExtension(compilationOutputFilename, ".d"); ofstream dependenciesFile(dependenciesFilename.c_str(), ios::out); @@ -1275,7 +1246,7 @@ return EXIT_SUCCESS; } - if (!monolithMode && !genAsmOnly) + if (!genAsmOnly) { string lstFilename = useIntDir(moduleName + ".lst"); int status = invokeAssembler(asmFilename, compilationOutputFilename, lstFilename, targetPreprocId, verbose); @@ -1451,12 +1422,6 @@ params.generateSREC = true; continue; } - if (curopt.compare(0, 6, "--a09=") == 0) - { - if (curopt.length() > 6) - params.setAssemblerFilename(string(curopt, 6, string::npos)); - continue; - } if (curopt.compare(0, 8, "--lwasm=") == 0) { params.lwasmPath.assign(curopt, 8, string::npos); @@ -1584,11 +1549,6 @@ params.functionStackSpace = (uint16_t) n; continue; } - if (curopt == "--emit-uncalled") - { - params.emitUncalledFunctions = true; - continue; - } if (curopt == "--allow-undef-func") { params.callToUndefinedFunctionAllowed = true; @@ -1609,6 +1569,11 @@ params.isBinaryOpGivingByteWarningEnabled = true; continue; } + if (curopt == "-Wlocal-var-hiding") + { + params.isLocalVariableHidingAnotherWarningEnabled = true; + continue; + } if (curopt == "-Wpass-const-for-func-pointer") // not documented b/c may be annoying { params.warnPassingConstForFuncPtr = true; @@ -1663,11 +1628,6 @@ continue; } - if (curopt == "--monolith") - { - params.monolithMode = true; - continue; - } if (strncmp(curopt.c_str(), "-o", 2) == 0) { string arg(curopt, 2, string::npos); @@ -1722,101 +1682,6 @@ } -// Returns an exit status. -// -int -assembleInMonolithMode(const char *targetPreprocId, - const string &programName, - const string &asmFilename, - vector &intermediateCompilationFiles) -{ - /* Call the cross-assembler on the asm file to produce executable files: - */ - stringstream ss; - ss << params.getAssemblerFilename(); - for (list::const_iterator it = params.includeDirList.begin(); it != params.includeDirList.end(); ++it) - ss << " --includedir='" << *it << "'"; - if (params.targetPlatform != OS9) - ss << " --entry=" << hex << params.codeAddress << dec; - if (params.assumeTrack34) - ss << " --entry=2602"; - if (params.limitAddress != 0xFFFF) - ss << " --limit=" << hex << params.limitAddress << dec; - ss << " --target=" << targetPreprocId; - if (params.generateSREC) - ss << " --srec"; - if (params.nullPointerCheckingEnabled) - ss << " --check-null"; - if (params.stackOverflowCheckingEnabled) - ss << " --check-stack"; - ss << " --stack-space=" << params.stackSpace; - const set &neededUtilitySubRoutines = TranslationUnit::instance().getNeededUtilitySubRoutines(); - for (set::const_iterator it = neededUtilitySubRoutines.begin(); it != neededUtilitySubRoutines.end(); ++it) - ss << " --need=" << *it; - if (params.verbose) - ss << " --verbose"; - if (!params.outputFilename.empty()) - ss << " --output='" << params.outputFilename << "'"; - ss << " " << asmFilename; - string asmCommand = ss.str(); - - int status = EXIT_SUCCESS; - - if (params.asmCmd) - { - // Write asmCommand in a .cmd file. - const string asmCmdFilename = programName + ".cmd"; - if (params.verbose) - cout << "Writing assembly command in " << asmCmdFilename << endl; - ofstream asmCmdFile(asmCmdFilename.c_str(), ios::out); - if (!asmCmdFile) - { - int e = errno; - cout << PACKAGE << fatalErrorPrefix << "failed to create assembler command file: " - << strerror(e) << endl; - status = EXIT_FAILURE; - } - else - { - asmCmdFile << asmCommand << '\n'; - asmCmdFile.close(); - if (!asmCmdFile) - { - cout << PACKAGE << fatalErrorPrefix << "failed to close output assembly command file " - << asmCmdFilename << endl; - status = EXIT_FAILURE; - } - } - } - - if (status == EXIT_SUCCESS && !params.compileOnly) // assemble only if -c not passed - { - if (params.verbose) - cout << "Assembling: " << asmCommand << endl; - - status = system(asmCommand.c_str()); - if (status == -1) - { - int e = errno; - cout << PACKAGE << fatalErrorPrefix << "could not start assembler script: " - << strerror(e) << endl; - status = EXIT_FAILURE; - } - else - { - if (!WIFEXITED(status)) - status = EXIT_FAILURE; - else - status = WEXITSTATUS(status); - } - } - - removeIntermediateCompilationFiles(intermediateCompilationFiles); - - return status; -} - - int main(int argc, char *argv[]) { @@ -1842,24 +1707,13 @@ } - if (params.monolithMode) - { - if (params.targetPlatform == OS9 || params.targetPlatform == VECTREX) - { - cout << PACKAGE << ": --monolith not supported when targeting " << targetPlatformName << endl; - return EXIT_FAILURE; - } - } - else - { - // In linker mode, allow defining a prototype and calling the function, - // but letting another module or library define that function. - params.callToUndefinedFunctionAllowed = true; + // Allow defining a prototype and calling the function, + // but letting another module or library define that function. + params.callToUndefinedFunctionAllowed = true; - // Do not try to link if dumping the preprocessor output or only generating asm. - if (params.preprocOnly) - params.compileOnly = true; - } + // Do not try to link if dumping the preprocessor output or only generating asm. + if (params.preprocOnly) + params.compileOnly = true; if (params.genAsmOnly) params.compileOnly = true; @@ -1885,7 +1739,7 @@ // Add default include dir at the end of any user-specified dirs. if (params.searchDefaultIncludeDirs) - params.includeDirList.push_back(params.pkgdatadir + (params.monolithMode ? "" : "/include")); + params.includeDirList.push_back(params.pkgdatadir + "/include"); assert(argi <= argc); @@ -1938,16 +1792,7 @@ string programName; string asmFilename; - if (params.monolithMode) - TranslationUnit::createInstance(params.targetPlatform, - params.callToUndefinedFunctionAllowed, - params.warnSignCompare, - params.warnPassingConstForFuncPtr, - params.isConstIncorrectWarningEnabled, - params.isBinaryOpGivingByteWarningEnabled, - params.relocatabilitySupported); - - TranslationUnitDestroyer tud(params.monolithMode); + TranslationUnitDestroyer tud(false); int status = EXIT_SUCCESS; @@ -1991,7 +1836,7 @@ string moduleName = getBasename(inputFilename); const string extension = removeExtension(moduleName); - // In linker mode, the first module name is the program name. + // The first module name is the program name. if (programName.empty()) programName = moduleName; @@ -2005,7 +1850,6 @@ // Determine this module's output filename (if compilation/assembly required). - // Note that compilationOutputFilename not used by compileCFile() when in monolith mode. // string compilationOutputFilename; if (extension == ".c" || extension == ".s" || extension == ".asm") @@ -2014,15 +1858,14 @@ { if (!params.outputFilename.empty()) compilationOutputFilename = params.outputFilename; - else if (!params.monolithMode) + else compilationOutputFilename = useIntDir(moduleName + ".o"); } else { // In compile-and-link mode, outputFilename (if any) is the executable filename, // so it cannot be used for compilationOutputFilename. - if (!params.monolithMode) - compilationOutputFilename = useIntDir(moduleName + ".o"); + compilationOutputFilename = useIntDir(moduleName + ".o"); } } @@ -2033,7 +1876,7 @@ // if (extension == ".c") { - asmFilename = useIntDir(moduleName + (params.monolithMode ? ".asm" : ".s")); + asmFilename = useIntDir(moduleName + ".s"); int s = params.compileCFile(inputFilename, moduleName, @@ -2043,17 +1886,11 @@ targetPreprocId); objectFilenames.push_back(moduleName); - if (!params.genAsmOnly && (!params.monolithMode || !params.compileOnly)) // keep .s/.asm in monolith with -c + if (!params.genAsmOnly) intermediateCompilationFiles.push_back(asmFilename); if (!params.intermediateFilesKept) intermediateCompilationFiles.push_back(replaceExtension(asmFilename, ".lst")); - if (params.monolithMode) - { - intermediateCompilationFiles.push_back(replaceExtension(asmFilename, ".i")); - if (params.targetPlatform != OS9) - intermediateCompilationFiles.push_back(replaceExtension(asmFilename, ".hex")); - } - else if (!params.compileOnly) + if (!params.compileOnly) intermediateObjectFiles.push_back(compilationOutputFilename); if (s != EXIT_SUCCESS) @@ -2064,28 +1901,20 @@ } else if (extension == ".s" || extension == ".asm") { - if (params.monolithMode) + string lstFilename = useIntDir(moduleName + ".lst"); + int s = invokeAssembler(inputFilename, compilationOutputFilename, lstFilename, targetPreprocId, params.verbose); + + if (s != EXIT_SUCCESS) { - cout << PACKAGE << fatalErrorPrefix << "assembler files (" << inputFilename - << ") are not supported in monolith mode" << endl; + status = s; + break; } - else - { - string lstFilename = useIntDir(moduleName + ".lst"); - int s = invokeAssembler(inputFilename, compilationOutputFilename, lstFilename, targetPreprocId, params.verbose); - if (s != EXIT_SUCCESS) - { - status = s; - break; - } - - objectFilenames.push_back(moduleName); - if (!params.intermediateFilesKept) - intermediateCompilationFiles.push_back(replaceExtension(asmFilename, ".lst")); - if (!params.compileOnly) - intermediateObjectFiles.push_back(compilationOutputFilename); - } + objectFilenames.push_back(moduleName); + if (!params.intermediateFilesKept) + intermediateCompilationFiles.push_back(replaceExtension(asmFilename, ".lst")); + if (!params.compileOnly) + intermediateObjectFiles.push_back(compilationOutputFilename); } else if (extension == ".o") { @@ -2127,45 +1956,36 @@ break; } - if (params.monolithMode) - break; // only 1 module allowed in non-linker mode - // If -o not used, then use 1st module name to form output filename. if (executableFilename.empty()) executableFilename = moduleName + getDefaultOutputExtension(params.targetPlatform, params.generateSREC); } // while - if (!params.monolithMode) // these intermediate files are still needed if in monolith mode - removeIntermediateCompilationFiles(intermediateCompilationFiles); + removeIntermediateCompilationFiles(intermediateCompilationFiles); if (status != EXIT_SUCCESS) return status; - if (!params.monolithMode && params.compileOnly) + if (params.compileOnly) return EXIT_SUCCESS; // Link all modules together. // - if (!params.monolithMode) - { - if (params.compileOnly) - return EXIT_SUCCESS; - string linkScriptFilename = useIntDir(replaceExtension(executableFilename, ".link")); - string mapFilename = useIntDir(replaceExtension(executableFilename, ".map")); - status = invokeLinker(objectFilenames, libraryFilenames, params.useDefaultLibraries, - linkScriptFilename, mapFilename, - executableFilename, - params.targetPlatform, params.libDirs, - params.limitAddress, params.generateSREC, params.verbose); - removeIntermediateLinkingFiles(linkScriptFilename, mapFilename, intermediateObjectFiles); - - if (status == EXIT_SUCCESS && params.targetPlatform == DRAGON) - status = convertBinToDragonFormat(executableFilename, params.verbose); + if (params.compileOnly) + return EXIT_SUCCESS; + string linkScriptFilename = useIntDir(replaceExtension(executableFilename, ".link")); + string mapFilename = useIntDir(replaceExtension(executableFilename, ".map")); + status = invokeLinker(objectFilenames, libraryFilenames, params.useDefaultLibraries, + linkScriptFilename, mapFilename, + executableFilename, + params.targetPlatform, params.libDirs, + params.limitAddress, params.generateSREC, params.verbose); + removeIntermediateLinkingFiles(linkScriptFilename, mapFilename, intermediateObjectFiles); - return status; - } + if (status == EXIT_SUCCESS && params.targetPlatform == DRAGON) + status = convertBinToDragonFormat(executableFilename, params.verbose); - return assembleInMonolithMode(targetPreprocId, programName, asmFilename, intermediateCompilationFiles); + return status; } diff -Nru cmoc-0.1.65/src/Makefile.am cmoc-0.1.67/src/Makefile.am --- cmoc-0.1.65/src/Makefile.am 2020-03-21 15:18:05.000000000 +0000 +++ cmoc-0.1.67/src/Makefile.am 2020-06-07 14:53:53.000000000 +0000 @@ -1,11 +1,11 @@ -# $Id: Makefile.am,v 1.71 2020/03/21 15:18:05 sarrazip Exp $ +# $Id: Makefile.am,v 1.76 2020/06/07 14:53:53 sarrazip Exp $ # The dot forces CMOC to be compiled before processing the stdlib and float # subdirectories, whose processing requires CMOC itself. # -SUBDIRS = support usim-0.91-cmoc . stdlib float +SUBDIRS = usim-0.91-cmoc . stdlib float -bin_SCRIPTS = intelhex2cocobin intelhex2srec install-coco-boot-loader +bin_SCRIPTS = install-coco-boot-loader bin_PROGRAMS = cmoc @@ -115,10 +115,7 @@ endif -pkgdata_SCRIPTS = a09 - -LOCAL_CMOC = $(ENV) PATH="$(srcdir):$$PATH" ./cmoc -I $(srcdir)/stdlib/ -Lstdlib -Lfloat -LOCAL_CMOC_MONO = $(ENV) PATH="$(srcdir):$$PATH" ./cmoc --monolith --a09=$(srcdir)/a09 -I $(srcdir)/support/ +LOCAL_CMOC = $(ENV) PATH="$(srcdir):$$PATH" ./cmoc -I $(srcdir)/stdlib/ -Lstdlib -Lfloat # Pass STOPONFAIL="--stop --nocleanup" on the command-line # to force the unit testing to stop at the first failed test. @@ -140,22 +137,6 @@ MKDIR = mkdir RMDIR = rmdir -check-scripts: - $(PERL) -cw $(srcdir)/a09 - $(PERL) -cw $(srcdir)/intelhex2cocobin - $(PERL) -cw $(srcdir)/intelhex2srec - $(srcdir)/a09 --version >/dev/null - $(srcdir)/a09 --help >/dev/null - test -x $(srcdir)/intelhex2cocobin - test "`$(srcdir)/intelhex2cocobin /dev/null ./cmoc --help >/dev/null @@ -169,7 +150,6 @@ check-srec: $(CREATE_TEST_PROG) - $(LOCAL_CMOC_MONO) --srec --verbose ,check-prog.c | $(GREP) "Generating SREC" $(LOCAL_CMOC) --srec --verbose ,check-prog.c | $(GREP) ",check-prog.srec" $(GREP) -q ^S1 ,check-prog.srec # data record test `$(GREP) -c ^S9 ,check-prog.srec` = 1 # starting address record (only one) @@ -180,9 +160,7 @@ $(LOCAL_CMOC) --org=4321 --data=6000 --intermediate --verbose ,check-prog.c 2>&1 $(GREP) -q "Symbol: program_start (,check-prog.o) = 4321" ,check-prog.map $(GREP) -q "Section: rwdata .* load at 6000," ,check-prog.map - $(LOCAL_CMOC_MONO) --org=4321 --verbose ,check-prog.c 2>&1 | $(GREP) -q "program_start .4321" $(LOCAL_CMOC) --org=2800 --limit=2810 ,check-prog.c 2>&1 | $(GREP) -q "program_end exceeds it" - $(LOCAL_CMOC_MONO) --org=2800 --limit=2810 ,check-prog.c 2>&1 | $(GREP) -q "program_end exceeds it" check-dos: $(CREATE_TEST_PROG) @@ -191,8 +169,8 @@ rm -f ,check-prog check-long: - $(LOCAL_CMOC) --usim -DPART0 -DPART1 -DPART2 -O2 -I support/ -Lstdlib -Lfloat --org=1600 $(srcdir)/check-long.c 2>&1 >/dev/null - $(USIM) check-long.srec + $(LOCAL_CMOC) --usim -DPART0 -DPART1 -DPART2 -O2 -Lstdlib -Lfloat --org=1600 $(srcdir)/check-long.c 2>&1 >/dev/null + $(USIM) check-long.srec | $(PERL) -pe '/\bSUCCESS\b/ and $$s = 1; END { exit !$$s }' rm -f check-long.srec check-float: @@ -318,7 +296,7 @@ rm -f ,check-prog.* -check-misc: check-scripts check-base check-srec check-org check-long check-float check-os9 check-deps check-vectrex check-stack-space check-linking +check-misc: check-base check-srec check-org check-long check-float check-os9 check-deps check-vectrex check-stack-space check-linking check-nbsp rm -f ,check-prog.c ,check-prog.asm ,check-prog.s ,check-prog.i \ ,check-prog.lst ,check-prog.hex ,check-prog.srec \ ,check-prog.link ,check-prog.map ,check-prog.bin ,check-prog @@ -368,6 +346,14 @@ rm -f ,check.dsk ,check.dat ,check.log endif +# Checks if some files contain non-breakable spaces (character 160). +# The statement in the 'continue' clause resets the line counter ($.) +# at the end of each processed file. +# +check-nbsp: + $(PERL) -e 'while (<>) { if (/\xA0/) { print "ERROR: non-breakable space at $$ARGV:$$.\n"; exit 1 } } continue { close ARGV if eof }' \ + $(cmoc_SOURCES) test-program-output.pl test-bad-programs.pl check-long.c $(bin_SCRIPTS) Makefile.am + check: check-writecocofile check-misc check-self-tests diff -Nru cmoc-0.1.65/src/Makefile.in cmoc-0.1.67/src/Makefile.in --- cmoc-0.1.65/src/Makefile.in 2020-04-25 02:27:42.000000000 +0000 +++ cmoc-0.1.67/src/Makefile.in 2020-06-07 14:57:21.000000000 +0000 @@ -14,7 +14,7 @@ @SET_MAKE@ -# $Id: Makefile.am,v 1.71 2020/03/21 15:18:05 sarrazip Exp $ +# $Id: Makefile.am,v 1.76 2020/06/07 14:53:53 sarrazip Exp $ VPATH = @srcdir@ @@ -103,8 +103,7 @@ CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = @BUILD_WRITECOCOFILE_TRUE@am__EXEEXT_1 = writecocofile$(EXEEXT) -am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)" \ - "$(DESTDIR)$(pkgdatadir)" +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)" PROGRAMS = $(bin_PROGRAMS) am_cmoc_OBJECTS = cmoc-TypeDesc.$(OBJEXT) cmoc-TypeManager.$(OBJEXT) \ cmoc-DeclarationSpecifierList.$(OBJEXT) cmoc-util.$(OBJEXT) \ @@ -166,7 +165,7 @@ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } -SCRIPTS = $(bin_SCRIPTS) $(pkgdata_SCRIPTS) +SCRIPTS = $(bin_SCRIPTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false @@ -406,8 +405,8 @@ # The dot forces CMOC to be compiled before processing the stdlib and float # subdirectories, whose processing requires CMOC itself. # -SUBDIRS = support usim-0.91-cmoc . stdlib float -bin_SCRIPTS = intelhex2cocobin intelhex2srec install-coco-boot-loader +SUBDIRS = usim-0.91-cmoc . stdlib float +bin_SCRIPTS = install-coco-boot-loader cmoc_SOURCES = \ TypeDesc.cpp \ TypeDesc.h \ @@ -501,9 +500,7 @@ # -d produces a .h file cmoc_CXXFLAGS = -DPKGDATADIR=\"$(pkgdatadir)\" @BUILD_WRITECOCOFILE_TRUE@writecocofile_SOURCES = writecocofile.cpp -pkgdata_SCRIPTS = a09 LOCAL_CMOC = $(ENV) PATH="$(srcdir):$$PATH" ./cmoc -I $(srcdir)/stdlib/ -Lstdlib -Lfloat -LOCAL_CMOC_MONO = $(ENV) PATH="$(srcdir):$$PATH" ./cmoc --monolith --a09=$(srcdir)/a09 -I $(srcdir)/support/ # Pass STOPONFAIL="--stop --nocleanup" on the command-line # to force the unit testing to stop at the first failed test. @@ -648,41 +645,6 @@ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(bindir)'; $(am__uninstall_files_from_dir) -install-pkgdataSCRIPTS: $(pkgdata_SCRIPTS) - @$(NORMAL_INSTALL) - @list='$(pkgdata_SCRIPTS)'; test -n "$(pkgdatadir)" || list=; \ - if test -n "$$list"; then \ - echo " $(MKDIR_P) '$(DESTDIR)$(pkgdatadir)'"; \ - $(MKDIR_P) "$(DESTDIR)$(pkgdatadir)" || exit 1; \ - fi; \ - for p in $$list; do \ - if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ - if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ - done | \ - sed -e 'p;s,.*/,,;n' \ - -e 'h;s|.*|.|' \ - -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ - $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ - { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ - if ($$2 == $$4) { files[d] = files[d] " " $$1; \ - if (++n[d] == $(am__install_max)) { \ - print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ - else { print "f", d "/" $$4, $$1 } } \ - END { for (d in files) print "f", d, files[d] }' | \ - while read type dir files; do \ - if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ - test -z "$$files" || { \ - echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(pkgdatadir)$$dir'"; \ - $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(pkgdatadir)$$dir" || exit $$?; \ - } \ - ; done - -uninstall-pkgdataSCRIPTS: - @$(NORMAL_UNINSTALL) - @list='$(pkgdata_SCRIPTS)'; test -n "$(pkgdatadir)" || exit 0; \ - files=`for p in $$list; do echo "$$p"; done | \ - sed -e 's,.*/,,;$(transform)'`; \ - dir='$(DESTDIR)$(pkgdatadir)'; $(am__uninstall_files_from_dir) mostlyclean-compile: -rm -f *.$(OBJEXT) @@ -1545,7 +1507,7 @@ all-am: Makefile $(PROGRAMS) $(SCRIPTS) installdirs: installdirs-recursive installdirs-am: - for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgdatadir)"; do \ + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive @@ -1605,7 +1567,7 @@ info-am: -install-data-am: install-pkgdataSCRIPTS +install-data-am: install-dvi: install-dvi-recursive @@ -1650,8 +1612,7 @@ ps-am: -uninstall-am: uninstall-binPROGRAMS uninstall-binSCRIPTS \ - uninstall-pkgdataSCRIPTS +uninstall-am: uninstall-binPROGRAMS uninstall-binSCRIPTS .MAKE: $(am__recursive_targets) install-am install-strip @@ -1663,33 +1624,16 @@ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ - install-pdf-am install-pkgdataSCRIPTS install-ps install-ps-am \ - install-strip installcheck installcheck-am installdirs \ - installdirs-am maintainer-clean maintainer-clean-generic \ - mostlyclean mostlyclean-compile mostlyclean-generic pdf pdf-am \ - ps ps-am tags tags-am uninstall uninstall-am \ - uninstall-binPROGRAMS uninstall-binSCRIPTS \ - uninstall-pkgdataSCRIPTS + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs installdirs-am \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am uninstall-binPROGRAMS \ + uninstall-binSCRIPTS .PRECIOUS: Makefile -check-scripts: - $(PERL) -cw $(srcdir)/a09 - $(PERL) -cw $(srcdir)/intelhex2cocobin - $(PERL) -cw $(srcdir)/intelhex2srec - $(srcdir)/a09 --version >/dev/null - $(srcdir)/a09 --help >/dev/null - test -x $(srcdir)/intelhex2cocobin - test "`$(srcdir)/intelhex2cocobin /dev/null ./cmoc --help >/dev/null @@ -1703,7 +1647,6 @@ check-srec: $(CREATE_TEST_PROG) - $(LOCAL_CMOC_MONO) --srec --verbose ,check-prog.c | $(GREP) "Generating SREC" $(LOCAL_CMOC) --srec --verbose ,check-prog.c | $(GREP) ",check-prog.srec" $(GREP) -q ^S1 ,check-prog.srec # data record test `$(GREP) -c ^S9 ,check-prog.srec` = 1 # starting address record (only one) @@ -1714,9 +1657,7 @@ $(LOCAL_CMOC) --org=4321 --data=6000 --intermediate --verbose ,check-prog.c 2>&1 $(GREP) -q "Symbol: program_start (,check-prog.o) = 4321" ,check-prog.map $(GREP) -q "Section: rwdata .* load at 6000," ,check-prog.map - $(LOCAL_CMOC_MONO) --org=4321 --verbose ,check-prog.c 2>&1 | $(GREP) -q "program_start .4321" $(LOCAL_CMOC) --org=2800 --limit=2810 ,check-prog.c 2>&1 | $(GREP) -q "program_end exceeds it" - $(LOCAL_CMOC_MONO) --org=2800 --limit=2810 ,check-prog.c 2>&1 | $(GREP) -q "program_end exceeds it" check-dos: $(CREATE_TEST_PROG) @@ -1725,8 +1666,8 @@ rm -f ,check-prog check-long: - $(LOCAL_CMOC) --usim -DPART0 -DPART1 -DPART2 -O2 -I support/ -Lstdlib -Lfloat --org=1600 $(srcdir)/check-long.c 2>&1 >/dev/null - $(USIM) check-long.srec + $(LOCAL_CMOC) --usim -DPART0 -DPART1 -DPART2 -O2 -Lstdlib -Lfloat --org=1600 $(srcdir)/check-long.c 2>&1 >/dev/null + $(USIM) check-long.srec | $(PERL) -pe '/\bSUCCESS\b/ and $$s = 1; END { exit !$$s }' rm -f check-long.srec check-float: @@ -1852,7 +1793,7 @@ rm -f ,check-prog.* -check-misc: check-scripts check-base check-srec check-org check-long check-float check-os9 check-deps check-vectrex check-stack-space check-linking +check-misc: check-base check-srec check-org check-long check-float check-os9 check-deps check-vectrex check-stack-space check-linking check-nbsp rm -f ,check-prog.c ,check-prog.asm ,check-prog.s ,check-prog.i \ ,check-prog.lst ,check-prog.hex ,check-prog.srec \ ,check-prog.link ,check-prog.map ,check-prog.bin ,check-prog @@ -1900,6 +1841,14 @@ @BUILD_WRITECOCOFILE_TRUE@ ./writecocofile -d ,check.dsk | $(GREP) -q '68 granule.s. free' @BUILD_WRITECOCOFILE_TRUE@ rm -f ,check.dsk ,check.dat ,check.log +# Checks if some files contain non-breakable spaces (character 160). +# The statement in the 'continue' clause resets the line counter ($.) +# at the end of each processed file. +# +check-nbsp: + $(PERL) -e 'while (<>) { if (/\xA0/) { print "ERROR: non-breakable space at $$ARGV:$$.\n"; exit 1 } } continue { close ARGV if eof }' \ + $(cmoc_SOURCES) test-program-output.pl test-bad-programs.pl check-long.c $(bin_SCRIPTS) Makefile.am + check: check-writecocofile check-misc check-self-tests .PHONY: cleanlib diff -Nru cmoc-0.1.65/src/Scope.cpp cmoc-0.1.67/src/Scope.cpp --- cmoc-0.1.65/src/Scope.cpp 2020-04-04 17:41:44.000000000 +0000 +++ cmoc-0.1.67/src/Scope.cpp 2020-05-10 02:30:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: Scope.cpp,v 1.15 2020/04/04 17:41:44 sarrazip Exp $ +/* $Id: Scope.cpp,v 1.16 2020/05/06 02:40:26 sarrazip Exp $ CMOC - A C-like cross-compiler Copyright (C) 2003-2015 Pierre Sarrazin @@ -176,6 +176,17 @@ // Accept two identical extern declarations. return found->isExtern && d->isExtern; } + + // Optionally warn if the declared variable is local and hides another local variable. + // + if (TranslationUnit::instance().warnOnLocalVariableHidingAnother()) + { + found = getVariableDeclaration(id, true); // look in ancestor Scopes + if (found != NULL && ! found->isGlobal()) + d->warnmsg("Local variable `%s' hides local variable `%s' declared at %s", + id.c_str(), found->getVariableId().c_str(), found->getLineNo().c_str()); + } + declTable.push_back(make_pair(id, d)); return true; } diff -Nru cmoc-0.1.65/src/stdlib/Makefile.am cmoc-0.1.67/src/stdlib/Makefile.am --- cmoc-0.1.65/src/stdlib/Makefile.am 2020-04-23 02:50:26.000000000 +0000 +++ cmoc-0.1.67/src/stdlib/Makefile.am 2020-06-06 04:41:44.000000000 +0000 @@ -1,4 +1,4 @@ -# $Id: Makefile.am,v 1.43 2020/04/23 02:50:26 sarrazip Exp $ +# $Id: Makefile.am,v 1.45 2020/06/06 04:41:44 sarrazip Exp $ # N.B.: CMOC must already have been compiled before this directory can be processed. @@ -6,8 +6,7 @@ # while references to code must be specified with uppercase ",PCR". # This is for the benefit of OS-9, where ",pcr" gets converted to ",Y". -# The linker mode header files go in /usr/share/cmoc/include, -# while the legacy monolith mode header files go in /usr/share/cmoc. +# The eader files go in /usr/share/cmoc/include. # cmocincdir = $(pkgdatadir)/include cmocinc_HEADERS = \ @@ -288,6 +287,17 @@ .c.dgn_o: ../cmoc -c $(CMOC_LIB_FLAGS) --dragon -o $@ $< +# Checks if some files contain non-breakable spaces (character 160). +# The statement in the 'continue' clause resets the line counter ($.) +# at the end of each processed file. +# +check: + $(PERL) -e 'while (<>) { if (/\xA0/) { print "ERROR: non-breakable space at $$ARGV:$$.\n"; exit 1 } } continue { close ARGV if eof }' \ + $(cmocinc_HEADERS) $(vectrexinc_HEADERS) \ + $(CRT_ASM) $(STD_ASM) \ + $(C_COMMON) $(C_COCO_OR_DRAGON_BASIC) $(C_COCO_BASIC) $(C_VECTREX) \ + Makefile.am + CLEANFILES = $(cmoclib_DATA) \ $(CRT_ECB_OBJ) $(CRT_USIM_OBJ) $(CRT_OS9_OBJ) $(CRT_VECTREX_OBJ) $(CRT_DRAGON_OBJ) \ $(STD_ECB_OBJ) $(STD_USIM_OBJ) $(STD_OS9_OBJ) $(STD_VECTREX_OBJ) $(STD_DRAGON_OBJ) diff -Nru cmoc-0.1.65/src/stdlib/Makefile.in cmoc-0.1.67/src/stdlib/Makefile.in --- cmoc-0.1.65/src/stdlib/Makefile.in 2020-04-25 02:27:42.000000000 +0000 +++ cmoc-0.1.67/src/stdlib/Makefile.in 2020-06-07 14:57:21.000000000 +0000 @@ -14,7 +14,7 @@ @SET_MAKE@ -# $Id: Makefile.am,v 1.43 2020/04/23 02:50:26 sarrazip Exp $ +# $Id: Makefile.am,v 1.45 2020/06/06 04:41:44 sarrazip Exp $ # N.B.: CMOC must already have been compiled before this directory can be processed. @@ -284,8 +284,7 @@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -# The linker mode header files go in /usr/share/cmoc/include, -# while the legacy monolith mode header files go in /usr/share/cmoc. +# The eader files go in /usr/share/cmoc/include. # cmocincdir = $(pkgdatadir)/include cmocinc_HEADERS = \ @@ -877,6 +876,17 @@ .c.dgn_o: ../cmoc -c $(CMOC_LIB_FLAGS) --dragon -o $@ $< +# Checks if some files contain non-breakable spaces (character 160). +# The statement in the 'continue' clause resets the line counter ($.) +# at the end of each processed file. +# +check: + $(PERL) -e 'while (<>) { if (/\xA0/) { print "ERROR: non-breakable space at $$ARGV:$$.\n"; exit 1 } } continue { close ARGV if eof }' \ + $(cmocinc_HEADERS) $(vectrexinc_HEADERS) \ + $(CRT_ASM) $(STD_ASM) \ + $(C_COMMON) $(C_COCO_OR_DRAGON_BASIC) $(C_COCO_BASIC) $(C_VECTREX) \ + Makefile.am + # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: diff -Nru cmoc-0.1.65/src/stdlib/qsort.c cmoc-0.1.67/src/stdlib/qsort.c --- cmoc-0.1.65/src/stdlib/qsort.c 2019-06-29 02:21:59.000000000 +0000 +++ cmoc-0.1.67/src/stdlib/qsort.c 2020-05-06 01:27:12.000000000 +0000 @@ -50,17 +50,17 @@ for (size_t j = l; j < h; ++j) { char *y = array + j * elemSize; - int res = comparator(y, x); //FIXME + int res = comparator(y, x); //printf("P: J=%u Y=%p X=%p -> RES=%d\n", j, y, x, res); if (res <= 0) { ++i; - //printf("P: I=%u Y=%p\n", i, y); //FIXME + //printf("P: I=%u Y=%p\n", i, y); qsort_swap(array + i * elemSize, y, elemSize); } } - //printf("P: END: I=%u H=%p\n", i, h); //FIXME + //printf("P: END: I=%u H=%p\n", i, h); qsort_swap(array + (i + 1) * elemSize, array + h * elemSize, elemSize); return i + 1; } diff -Nru cmoc-0.1.65/src/stdlib/strstr.asm cmoc-0.1.67/src/stdlib/strstr.asm --- cmoc-0.1.65/src/stdlib/strstr.asm 2020-01-05 03:39:18.000000000 +0000 +++ cmoc-0.1.67/src/stdlib/strstr.asm 2020-05-06 01:27:26.000000000 +0000 @@ -9,7 +9,7 @@ ldx 6,s haystack ldu 8,s needle tst ,u is needle empty string? - beq @returnX yes: empty string found at start of haystack; FIXME: compare w/ GNU's strstr + beq @returnX yes: empty string found at start of haystack @mainLoop lda ,x+ end of haystack? beq @notFound yes: fail diff -Nru cmoc-0.1.65/src/support/assert.h cmoc-0.1.67/src/support/assert.h --- cmoc-0.1.65/src/support/assert.h 2016-03-13 16:55:54.000000000 +0000 +++ cmoc-0.1.67/src/support/assert.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ -/* assert.h - Assert macro for CMOC - - By Pierre Sarrazin . - This file is in the public domain. -*/ - -#ifndef _ASSERT_H -#define _ASSERT_H - -#include - -#ifdef NDEBUG -#define assert(cond) -#else -#define assert(cond) do { if (!(cond)) { \ - printf("***ASSERT FAILED: %s:%u: %s\n", __FILE__, __LINE__, #cond); \ - for (;;); } } while (0) -#endif - -#endif /* _ASSERT_H */ diff -Nru cmoc-0.1.65/src/support/cmoc.h cmoc-0.1.67/src/support/cmoc.h --- cmoc-0.1.65/src/support/cmoc.h 2018-03-11 04:19:36.000000000 +0000 +++ cmoc-0.1.67/src/support/cmoc.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,236 +0,0 @@ -// cmoc.h - CMOC's standard library functions. -// -// By Pierre Sarrazin . -// This file is in the public domain. -// -// Functions not documented here should be assumed to behave as in C. - -#ifndef _H_CMOC -#define _H_CMOC - -#ifndef __GNUC__ - -#ifndef _CMOC_CONST_ -#define _CMOC_CONST_ const -#endif - -// Gives the offset in bytes of the specified 'member' in the struct -// or union named 'Type'. -// -#define offsetof(Type, member) ((unsigned) &((Type *) 0)->member) - -typedef unsigned size_t; - -#ifndef VECTREX -// Supports %u, %d, %x, %X, %p, %s, %c and %%. Specifying a field width is -// allowed, but a left justification is only supported for strings, i.e., -// %-15s will work, but %-6u will not. Zero padding for a number is supported -// (e.g., %04x). -// -int printf(_CMOC_CONST_ char *format, ...); -#endif - -// Writes to 'dest'. Not thread-safe. Does not check for buffer overflow. -int sprintf(char *dest, _CMOC_CONST_ char *format, ...); - -#ifndef VECTREX -// Writes the first 'n' characters designated by 's', regardless of any -// null characters encountered among them. -// -void putstr(_CMOC_CONST_ char *s, size_t n); - -void putchar(int c); -#endif - -int strcmp(_CMOC_CONST_ char *s1, _CMOC_CONST_ char *s2); -int memcmp(_CMOC_CONST_ void *s1, _CMOC_CONST_ void *s2, size_t n); -void *memcpy(void *dest, _CMOC_CONST_ void *src, size_t n); -void *memset(void *s, int c, size_t n); -size_t strlen(_CMOC_CONST_ char *s); -char *strcpy(char *dest, _CMOC_CONST_ char *src); -char *strcat(char *dest, _CMOC_CONST_ char *src); -char *strncpy(char *dest, _CMOC_CONST_ char *src, size_t n); -char *strchr(_CMOC_CONST_ char *s, int c); -char *strlwr(char *s); -char *strupr(char *s); - -// Converts an ASCII unsigned decimal string into an unsigned word. -// -unsigned atoui(_CMOC_CONST_ char *s); - -// Converts an ASCII signed decimal string into a signed word. -// -int atoi(_CMOC_CONST_ char *s); - -// Double-word to ASCII. -// Converts the unsigned 32-bit integer formed by hi * 65536 + lo into -// an ASCII decimal representation that gets written to 'out'. -// 'out' must point to at least 11 bytes. The string written there will -// be terminated by a null character. -// Returns the address of the first non-'0' character in the 11-byte -// buffer, or to "0" if hi and lo are both zero. -// Example: char s[11]; char *p = dwtoa(s, 1, 2); -// s will get the string " -// NOTE: This operation can also be done with the 'long' type and by -// calling sprintf() with the "%lu" or "%ld" placeholders. -// -char *dwtoa(char *out, unsigned hi, unsigned lo); - -// Divides an unsigned 32-bit integer by an unsigned 8-bit integer. -// The two words designated by 'dividendInQuotientOut' are the input dividend. -// The 32-bit quotient is left in those two words. -// -void divdwb(unsigned dividendInQuotientOut[2], unsigned char divisor); - -// Previous name of divdwb(). -// -#define div328 divdwb - -// Divides an unsigned 32-bit integer by an unsigned 16-bit integer. -// The two words designated by 'dividendInQuotientOut' are the input dividend. -// The 32-bit quotient is left in those two words. -// -void divdww(unsigned dividendInQuotientOut[2], unsigned divisor); - -// Multiply a word by a byte. -// Stores the high word of the product in *hi and returns the low word. -// -unsigned mulwb(unsigned char *hi, unsigned wordFactor, unsigned char byteFactor); - -// Similar to mulwb(). -unsigned mulww(unsigned *hi, unsigned factor0, unsigned factor1); - -// Stores 0 in twoWords[0], twoWords[1]. -// -void zerodw(unsigned *twoWords); - -// Adds the 16-bit integer 'term' to the 32-bit integer designated by -// twoWords[0] and twoWords[1]. -// -void adddww(unsigned *twoWords, unsigned term); - -// Subtracts the 16-bit integer 'term' from the 32-bit integer designated by -// twoWords[0] and twoWords[1]. -// -void subdww(unsigned *twoWords, unsigned term); - -// Returns 0 if the 32-bit unsigned word composed of left[0] and left[1] -// (where left[0] is the high word) is equal to 'right'; -// returns +1 if left > right; -1 if left < right. -// -char cmpdww(unsigned left[2], unsigned right); - -#ifdef _COCO_BASIC_ - -// Converts an ASCII decimal floating point number to a float. -// The string is allowed to contain a suffix (e.g., "1.2E6XYZ"); -// endptr: Receives the address where the parsing stopped. -// Caution: Passing a string whose value does not fit in a float -// may have undefined behavior. -// An 'E' used in exponential notation must be in upper-case. -// -float strtof(_CMOC_CONST_ char *nptr, char **endptr); - -// Like strtof(), but does not return the end pointer. -// -float atoff(_CMOC_CONST_ char *nptr) -{ - char *endptr; - return strtof(nptr, &endptr); -} - -// Writes an ASCII decimal representation of 'f' in the buffer -// at 'out' which must contain at least 38 bytes. -// Returns 'out' upon success, or null upon failure. -// -char *ftoa(char out[38], float f); - -#endif /* _COCO_BASIC_ */ - -// CAUTION: base is ignored, only base 10 is supported. -// -unsigned long strtoul(_CMOC_CONST_ char *nptr, char **endptr, int base); - -unsigned long atoul(_CMOC_CONST_ char *nptr) -{ - char *endptr; - return strtoul(nptr, &endptr, 10); -} - -// CAUTION: base is ignored, only base 10 is supported. -// -long strtol(_CMOC_CONST_ char *nptr, char **endptr, int base) -{ - return (long) strtoul(nptr, endptr, base); -} - -long atol(_CMOC_CONST_ char *nptr) -{ - char *endptr; - return (long) strtoul(nptr, &endptr, 10); -} - -int tolower(int c); -int toupper(int c); -void exit(int status); - -#define RAND_MAX 0x7FFF -void srand(unsigned seed); -int rand(); - -// See the CMOC manual. -void *sbrk(size_t increment); -size_t sbrkmax(); -void set_null_ptr_handler(void (*newHandler)(void *)); -void set_stack_overflow_handler(void (*newHandler)(void *, void *)); - - -// Function pointer type used by setConsoleOutHook(). -// -typedef void (*ConsoleOutHook)(); - - -// Redirect printf() et al. to the function at 'routine', which will -// receive each character to be printed in register A. -// -// That routine MUST preserve registers B, X, Y and U. -// -// If this function is never called, printf() et al. write to the -// system's standard character output routine. -// -// Returns the original output routine address. -// To uninstall the new routine, call this function again with -// the original routine address. -// -ConsoleOutHook setConsoleOutHook(ConsoleOutHook routine); - - -#ifndef VECTREX - -// Blocks the execution for the specified time in 60ths of a second. -// -void delay(size_t sixtiethsOfASecond); - -// Reads a line from standard input, converts an expected 16-bit decimal -// number and returns it. Not thread-safe. -// -unsigned readword(); - -// Reads a line from standard input and returns it. -// Not thread-safe. -// Returns a null pointer if the operation failed (e.g., end of file -// encountered). -// -char *readline(); - -#endif - -#else - -#include -#include -#include - -#endif /* __GNUC__ */ - -#endif /* _H_CMOC */ diff -Nru cmoc-0.1.65/src/support/coco.h cmoc-0.1.67/src/support/coco.h --- cmoc-0.1.65/src/support/coco.h 2018-10-07 03:06:08.000000000 +0000 +++ cmoc-0.1.67/src/support/coco.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,758 +0,0 @@ -/* coco.h - Utility functions for interface with CoCo Disk Basic - - By Pierre Sarrazin . - This file is in the public domain. -*/ - -#ifndef _coco_h_ -#define _coco_h_ - -#include - - -#ifndef NULL -#define NULL ((void *) 0) -#endif - - -enum { FALSE, TRUE }; - -#ifndef _CMOC_HAVE_BOOL_ -typedef unsigned char BOOL; -#define _CMOC_HAVE_BOOL_ -#endif - - -#ifndef _CMOC_BASIC_TYPES_ -#define _CMOC_BASIC_TYPES_ - -typedef unsigned char byte; -typedef signed char sbyte; -typedef unsigned int word; -typedef signed int sword; -typedef unsigned long dword; -typedef signed long sdword; - -#endif - -typedef unsigned char uint8_t; -typedef signed char int8_t; -typedef unsigned int uint16_t; -typedef signed int int16_t; -typedef unsigned long uint32_t; -typedef signed long int32_t; - - -#ifdef _COCO_BASIC_ - - -/* Registers U and Y must be saved in the stack - while calling CoCo BASIC routines. -*/ - -byte isCoCo3 = FALSE; - - -// May be called more than once. -// -void initCoCoSupport() -{ - word irqServiceRoutineAddress = * (word *) 0xFFF8; - isCoCo3 = (irqServiceRoutineAddress == 0xFEF7); -} - - -void setHighSpeed(byte fast) -{ - asm - { - ldx #65494 - tst fast - beq setHighSpeed_010 - leax 1,x -setHighSpeed_010: - tst isCoCo3 - beq setHighSpeed_020 - leax 2,x -setHighSpeed_020: - clr ,x - } -} - - -byte resetPalette(byte isRGB) -{ - if (!isCoCo3) - return FALSE; - - // Fix bug in CoCo 3 BASIC's RGB and CMP commands. - if (* (byte *) 0xE649 == 15) - * (byte *) 0xE649 = 16; - - // Jump to RGB or CMP routine. - asm("PSHS", "U,Y"); // protect against BASIC routine - if (isRGB) - asm("JSR", "$E5FA"); - else - asm("JSR", "$E606"); - asm("PULS", "Y,U"); - return TRUE; // success -} - - -// slot: 0..15. -// color: 0..63. -// Returns true for success, false if args are invalid. -// See also paletteRGB(). -// -byte palette(byte slot, byte color) -{ - if (!isCoCo3) - return FALSE; - if (slot > 15) - return FALSE; - if (color > 63) - return FALSE; - byte *palette = (byte *) 0xFFB0; - palette[slot] = color; - return TRUE; -} - - -// Easier interface when assuming an RGB monitor. -// slot: 0..15. -// red, green, blue: 0..3. -// -void paletteRGB(byte slot, byte red, byte green, byte blue) -{ - if (!isCoCo3) - return; - if (slot > 15) - return; - * (((byte *) 0xFFB0) + slot) = ((red & 2) << 4) - | ((red & 1) << 2) - | ((green & 2) << 3) - | ((green & 1) << 1) - | ((blue & 2) << 2) - | (blue & 1); -} - - -// Sets the given 6-bit color code as the border color -// for the 40 and 80 column modes. -// -byte setBorderColor(byte color) -{ - if (!isCoCo3) - return FALSE; - - * (byte *) 0xFF9A = color; - return TRUE; -} - - -byte textScreenWidth = 32; -byte textScreenHeight = 16; - - -// Returns true for success, false if arg is invalid. -// -byte width(byte columns) -{ - if (!isCoCo3) - return FALSE; - - if (columns != 32 && columns != 40 && columns != 80) - return FALSE; - - asm("PSHS", "U,Y"); // protect against BASIC routine - asm("LDB", columns); - asm("JSR", "$F643"); // inside the WIDTH command - asm("PULS", "Y,U"); - - textScreenWidth = columns; - textScreenHeight = (columns == 32 ? 16 : 24); - - return TRUE; -} - - -// Returns 32, 40 or 80. -// -byte getTextMode() -{ - if (isCoCo3) - { - byte hrWidth = * (byte *) 0x00E7; - if (hrWidth == 1) - return 40; - if (hrWidth == 2) - return 80; - } - return 32; -} - - -// color: Argument that would be passed to BASIC's CLS command. -// Pass 255 to signify no argument. -// -void cls(byte color) -{ - asm("PSHS", "U,Y"); // protect against BASIC routine - byte hrwidth; - if (isCoCo3) - hrwidth = * (byte *) 0x00E7; - else - hrwidth = 0; - - if (hrwidth != 0) - { - if (color > 8) - color = 1; - // This is the hi-res CLS routine, - // which must not be called in 32 column mode. - asm("LDB", color); - asm("JSR", "$F6B8"); - } - else if (color > 8) - { - asm("JSR", "$A928"); - } - else - { - asm("LDB", color); - asm("JSR", "$A91C"); - } - asm("PULS", "Y,U"); -} - - -// foreColor: 0-7. -// backColor: 0-7. -// blink, underline: booleans. -// -byte attr(byte foreColor, byte backColor, byte blink, byte underline) -{ - if (!isCoCo3) - return FALSE; - - // Bits 0-2: background color (0-7) - // Bits 3-5: foreground color (0-7) - // Bits 6: underline if set. - // Bits 7: blink if set. - // - asm - { - ldb foreColor - lslb - lslb - lslb - orb backColor - tst blink - beq attr_no_b - orb #$80 -attr_no_b: - tst underline - beq attr_no_u - orb #$40 -attr_no_u: - stb $FE08 - } - - return TRUE; -} - - -byte locate(byte column, byte row) -{ - byte hrwidth; - if (isCoCo3) - hrwidth = * (byte *) 0x00E7; - else - hrwidth = 0; - - if (hrwidth == 0) // if 32 col mode - { - if (column >= 32) - return FALSE; - if (row >= 16) - return FALSE; - * (word *) 0x0088 = 1024 + (((word) row) << 5) + column; - } - else - { - if (column >= 80) - return FALSE; - if (row >= 24) - return FALSE; - if (hrwidth == 1) // if 40 col mode - if (column >= 40) - return FALSE; - asm("PSHS", "U,Y"); // protect against BASIC routine - asm("LDA", column); - asm("LDB", row); - asm("JSR", "$F8F7"); // inside the LOCATE command - asm("PULS", "Y,U"); - } - return TRUE; -} - - -byte hscreen(byte mode) -{ - if (!isCoCo3) - return FALSE; - - if (mode > 4) - return FALSE; - asm("PSHS", "U,Y"); // protect against BASIC routine - asm("LDB", mode); - asm("JSR", "$E69C"); - asm("PULS", "Y,U"); - return TRUE; -} - - -byte hset(word x, word y, byte color) -{ - if (x >= 640 || y >= 192 || color >= 16) - return FALSE; - byte hrmode = * (byte *) 0x00E6; - if (hrmode == 0) - return FALSE; // hi-res mode not enabled - if (hrmode <= 2) - if (x >= 320) - return FALSE; - * (byte *) 0x00C2 = 1; // SETFLG: 1 = HSET, 0 = HRESET - * (word *) 0x00BD = x; // HORBEG - * (word *) 0x00BF = y; // VERBEG - asm("PSHS", "U,Y"); // protect against BASIC routine - asm("LDB", color); - asm("JSR", "$E73B"); // save the working color - asm("JSR", "$E785"); // put the pixel on the screen - asm("PULS", "Y,U"); - return TRUE; -} - - -void setCaseFlag(byte upperCase) -{ - if (upperCase != 0) - upperCase = 0xFF; - * (byte *) 0x11a = upperCase; -} - - -#if 0 // Untested. - -// Calls BASIC's NEW command. -// -void newBasicProgram() -{ - asm("PSHS", "U,Y"); // protect against BASIC routine - asm("JSR", "$AD19"); - asm("PULS", "Y,U"); -} - - -void warmStart() -{ - asm("JMP", "$A027"); // EXEC 40999 -} - -#endif // Untested - - -void coldStart() -{ - asm("CLR", "$71"); // POKE 113,0 - asm("JMP", "$A027"); // EXEC 40999 -} - - -// Returns 0 if no key is currently pressed. -// -byte asm inkey() -{ - asm - { - jsr [$A000] // POLCAT - tfr a,b // byte return value goes in B - } -} - - -// Waits for a key to be pressed and returns its code. -// -byte waitkey(byte blinkCursor) -{ - byte key; - if (blinkCursor) - { - asm - { - jsr $A1B1 // blink cursor while waiting for a keystroke - sta key - } - return key; - } - - for (;;) - { - key = inkey(); - if (key) - return key; - } -} - - -// Names for values that can be passed to isKeyPressed() -// to test if a key is down or not. -// -enum KeyboardBits -{ - KEY_PROBE_AT = 0xFE, KEY_BIT_AT = 0x01, - KEY_PROBE_A = 0xFD, KEY_BIT_A = 0x01, - KEY_PROBE_B = 0xFB, KEY_BIT_B = 0x01, - KEY_PROBE_C = 0xF7, KEY_BIT_C = 0x01, - KEY_PROBE_D = 0xEF, KEY_BIT_D = 0x01, - KEY_PROBE_E = 0xDF, KEY_BIT_E = 0x01, - KEY_PROBE_F = 0xBF, KEY_BIT_F = 0x01, - KEY_PROBE_G = 0x7F, KEY_BIT_G = 0x01, - KEY_PROBE_H = 0xFE, KEY_BIT_H = 0x02, - KEY_PROBE_I = 0xFD, KEY_BIT_I = 0x02, - KEY_PROBE_J = 0xFB, KEY_BIT_J = 0x02, - KEY_PROBE_K = 0xF7, KEY_BIT_K = 0x02, - KEY_PROBE_L = 0xEF, KEY_BIT_L = 0x02, - KEY_PROBE_M = 0xDF, KEY_BIT_M = 0x02, - KEY_PROBE_N = 0xBF, KEY_BIT_N = 0x02, - KEY_PROBE_O = 0x7F, KEY_BIT_O = 0x02, - KEY_PROBE_P = 0xFE, KEY_BIT_P = 0x04, - KEY_PROBE_Q = 0xFD, KEY_BIT_Q = 0x04, - KEY_PROBE_R = 0xFB, KEY_BIT_R = 0x04, - KEY_PROBE_S = 0xF7, KEY_BIT_S = 0x04, - KEY_PROBE_T = 0xEF, KEY_BIT_T = 0x04, - KEY_PROBE_U = 0xDF, KEY_BIT_U = 0x04, - KEY_PROBE_V = 0xBF, KEY_BIT_V = 0x04, - KEY_PROBE_W = 0x7F, KEY_BIT_W = 0x04, - KEY_PROBE_X = 0xFE, KEY_BIT_X = 0x08, - KEY_PROBE_Y = 0xFD, KEY_BIT_Y = 0x08, - KEY_PROBE_Z = 0xFB, KEY_BIT_Z = 0x08, - KEY_PROBE_UP = 0xF7, KEY_BIT_UP = 0x08, - KEY_PROBE_DOWN = 0xEF, KEY_BIT_DOWN = 0x08, - KEY_PROBE_LEFT = 0xDF, KEY_BIT_LEFT = 0x08, - KEY_PROBE_RIGHT = 0xBF, KEY_BIT_RIGHT = 0x08, - KEY_PROBE_SPACE = 0x7F, KEY_BIT_SPACE = 0x08, - KEY_PROBE_0 = 0xFE, KEY_BIT_0 = 0x10, - KEY_PROBE_1 = 0xFD, KEY_BIT_1 = 0x10, - KEY_PROBE_2 = 0xFB, KEY_BIT_2 = 0x10, - KEY_PROBE_3 = 0xF7, KEY_BIT_3 = 0x10, - KEY_PROBE_4 = 0xEF, KEY_BIT_4 = 0x10, - KEY_PROBE_5 = 0xDF, KEY_BIT_5 = 0x10, - KEY_PROBE_6 = 0xBF, KEY_BIT_6 = 0x10, - KEY_PROBE_7 = 0x7F, KEY_BIT_7 = 0x10, - KEY_PROBE_8 = 0xFE, KEY_BIT_8 = 0x20, - KEY_PROBE_9 = 0xFD, KEY_BIT_9 = 0x20, - KEY_PROBE_COLON = 0xFB, KEY_BIT_COLON = 0x20, - KEY_PROBE_SEMICOLON = 0xF7, KEY_BIT_SEMICOLON = 0x20, - KEY_PROBE_COMMA = 0xEF, KEY_BIT_COMMA = 0x20, - KEY_PROBE_HYPHEN = 0xDF, KEY_BIT_HYPHEN = 0x20, - KEY_PROBE_PERIOD = 0xBF, KEY_BIT_PERIOD = 0x20, - KEY_PROBE_SLASH = 0x7F, KEY_BIT_SLASH = 0x20, - KEY_PROBE_ENTER = 0xFE, KEY_BIT_ENTER = 0x40, - KEY_PROBE_CLEAR = 0xFD, KEY_BIT_CLEAR = 0x40, - KEY_PROBE_BREAK = 0xFB, KEY_BIT_BREAK = 0x40, - KEY_PROBE_ALT = 0xF7, KEY_BIT_ALT = 0x40, - KEY_PROBE_CTRL = 0xEF, KEY_BIT_CTRL = 0x40, - KEY_PROBE_F1 = 0xDF, KEY_BIT_F1 = 0x40, - KEY_PROBE_F2 = 0xBF, KEY_BIT_F2 = 0x40, - KEY_PROBE_SHIFT = 0x7F, KEY_BIT_SHIFT = 0x40, -}; - - -// Writes 'out' to $FF02 and tests the bit specified by 'testBit'. -// Returns non-zero iff the designated key is currently pressed. -// Example: isKeyPressed(0x7F, 0x08) checks for the space key. -// For details, look for a CoCo keyboard grid diagram. -// -asm byte isKeyPressed(byte probe, byte testBit) -{ - asm - { - ldb 3,s ; probe - stb $FF02 - ldb $FF00 - andb 5,s ; testBit - eorb 5,s - } -} - - -// Indices into the POTVAL array whose address is returned -// by readJoystickPositions(). -// -enum -{ - JOYSTK_RIGHT_HORIZ = 0, - JOYSTK_RIGHT_VERT = 1, - JOYSTK_LEFT_HORIZ = 2, - JOYSTK_LEFT_VERT = 3, -}; - - -enum -{ - JOYSTK_MAX = 63, // max value in a POTVAL entry (min is 0) -}; - - -// Reads the joysticks and returns the address of a 4-byte array -// that contains the 0..63 values that would be returned by -// JOYSTK(0..3) in Color Basic. -// -asm const byte *readJoystickPositions() -{ - asm - { - pshs u,y ; protect against Color Basic - jsr $A9DE ; GETJOY - jsr $A976 ; turn audio back on (GETJOY turns it off) - puls y,u - ldd #$015A ; return POTVAL - } -} - - -// Bit names to be used on the value returned by readJoystickButtons(). -// -enum -{ - JOYSTK_BUTTON_1_RIGHT = 0x01, - JOYSTK_BUTTON_2_RIGHT = 0x02, - JOYSTK_BUTTON_1_LEFT = 0x04, - JOYSTK_BUTTON_2_LEFT = 0x08, -}; - - -// Reads the state of all 4 supported joystick buttons. -// Returns a 4-bit value: -// - bit 0: button 1 of right joystick; -// - bit 1: button 2 of right joystick; -// - bit 2: button 1 of left joystick; -// - bit 3: button 2 of left joystick. -// -asm byte readJoystickButtons() -{ - asm - { - ldb #$FF ; set column strobe to check buttons - stb $FF02 ; PIA0+2 - ldb $FF00 ; PIA0 - andb #$0F ; return low 4 bits - } -} - - -// Same arguments as Color Basic's SOUND command. -// -void sound(byte tone, byte duration) -{ - asm("PSHS", "U"); // protect U from Color Basic code - * (byte *) 0x8C = tone; - * (word *) 0x8D = ((word) duration) << 2; - asm("JSR", "$A956"); - asm("PULS", "U"); -} - - -#define DEV_SCREEN 0 -#define DEV_CASSETTE (-1) -#define DEV_SERIAL (-2) -#define DEV_PRINTER DEV_SERIAL - -void asm setOutputDevice(sbyte deviceNum) -{ - asm - { - ldb 3,s // deviceNum - stb $6F // Color Basic's DEVNUM - } -} - - -// newValue: word value. -// -#define setTimer(newValue) (* (word *) 0x112 = (newValue)) - -// Returns a word. -// -#define getTimer() (* (word *) 0x112) - - -// seconds: 0..1092. -// -void sleep(int seconds) -{ - if (!seconds) - return; - unsigned limit = 60 * (unsigned) seconds; - setTimer(0); - while (getTimer() < limit) - ; -} - - -// samAddr: Base address to write to (0xFFC0 for screen mode, -// 0xFFC6 for graphics page address). -// value: Value to write. -// numBits: Number of bits to write to samAddr. (Refers to the -// least significant bits of 'value'.) -// -void setSAMRegisters(byte *samAddr, byte value, byte numBits) -{ - while (numBits) - { - // Write at even address to send a 0, odd to send a 1. - // - *(samAddr + (value & 1)) = 0; - - value = value >> 1; - - --numBits; - - // Next SAM bit is two addresses further. - // - samAddr += 2; - } -} - - -// Writes the given byte in the 6k PMODE 4 screen buffer (0x1800 bytes long) -// starting at the address given by 'textScreenBuffer'. -// -void pcls(byte *buffer, byte byteToClearWith) -{ - word *end = (word *) (buffer + 0x1800); - - asm { - lda byteToClearWith - tfr a,b - ldx buffer -pcls_loop: - std ,x++ - std ,x++ - std ,x++ - std ,x++ - std ,x++ - std ,x++ - std ,x++ - std ,x++ - std ,x++ - std ,x++ - std ,x++ - std ,x++ - std ,x++ - std ,x++ - std ,x++ - std ,x++ - cmpx end - bne pcls_loop - } -} - - -// pageNum: 512-byte page index in 0..127. -// Sets the SAM registers to show the PMODE 4 graphics -// at address pageNum * 512. -// -void showGraphicsAddress(byte pageNum) -{ - setSAMRegisters((byte *) 0xFFC6, pageNum, 7); - setSAMRegisters((byte *) 0xFFC0, 6, 3); -} - - -// Set "PMODE 4 : SCREEN 1,colorset", where colorset is 0 (green/black) -// or 1 (white/black). -// -void showPmode4(byte colorset) -{ - byte *pia1bData = (byte *) 0xff22; - byte b = *pia1bData & 7 | 0xf0; - if (colorset) - b |= 8; - *pia1bData = b; -} - - -// Select the 32x16 text mode and position the screen buffer at address 1024. -// -void showLowResTextAddress() -{ - setSAMRegisters((byte *) 0xFFC6, 2, 7); // 2 == 0x0400 / 512 - setSAMRegisters((byte *) 0xFFC0, 0, 3); // 0 == 32x16 mode -} - - -// Show the text mode. -// -void asm showPmode0() -{ - asm - { - ldb $FF22 - andb #7 - stb $FF22 - } -} - - -#else /* !defined _COCO_BASIC_ */ - - -byte textScreenWidth = 80; -byte textScreenHeight = 24; - - -void coldStart() -{ - asm { sync } // stops usim -} - - -byte asm inkey() -{ - asm - { - ldb $ff00 // assumed a properly modified usim 6809 simulator - } -} - - -// Waits for a key to be pressed and returns its code. -// -byte waitkey(byte blinkCursor) -{ - byte key; - for (;;) - { - key = inkey(); - if (key) - { - if (key != '\n') - while (inkey() != '\n') //PATCH: need cbreak mode - ; - return key; - } - } -} - - -#endif /* !defined _COCO_BASIC_ */ - - -#define disableInterrupts() asm("ORCC", "#$50") -#define enableInterrupts() asm("ANDCC", "#$AF") - - -#endif /* _coco_h_ */ diff -Nru cmoc-0.1.65/src/support/disk.h cmoc-0.1.67/src/support/disk.h --- cmoc-0.1.65/src/support/disk.h 2018-03-11 17:53:17.000000000 +0000 +++ cmoc-0.1.67/src/support/disk.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,716 +0,0 @@ -/* disk.h - Support for use of CoCo Disk Basic - - By Pierre Sarrazin . - This file is in the public domain. - - Version 0.1.1 - Fall 2017 - Now uses uint32_t (unsigned long). - Version 0.2.0 - January 2018 - MUST now call initdisk() first. - This file does not call sbrk() anymore. -*/ - -#include "coco.h" -#include "assert.h" - - -// MUST be called before any other functions of this file. -// newFATBuffer: Must be a non-null pointer to an area of MAX_NUM_GRANULES bytes. -// Returns 1 on success, 0 on failure. -// -byte initdisk(byte newFATBuffer[]); - - -// DSKCON operation codes. -// -#define DSKCON_READ 2 -#define DSKCON_WRITE 3 - - -byte findDirEntry(char *dirEntry, char *filename); -byte *updateFAT(); -byte computeFileLength(uint32_t dwLength, byte firstGran, word numBytesLastSector); -void rewind(struct FileDesc *fd); -word getGranuleLength(byte *fat, byte granule, word numBytesLastSector); -byte *getCurrentlyAvailableBytes(struct FileDesc *fd, word *numAvailBytes); -void advanceOffset(struct FileDesc *fd, word numBytes); -byte getNextSector(struct FileDesc *fd); -void granuleToTrack(byte granule, byte *track, byte *sec); -byte isLastSectorOfFile(struct FileDesc *fd); -void normalizeFilename(char *dest, char *src); - - -#ifdef _COCO_BASIC_ - -// operation: DSKCON operation code -// dest: non null pointer to a 256-byte region. -// drive: 0..3. -// track: 0..34. -// sector: 1..18 (sic). -// Returns TRUE for success, FALSE for failure. -// -byte dskcon(byte operation, byte *buffer, byte drive, byte track, byte sector) -{ - //printf("- dskcon(%u, 0x%04x, %u, %u, %u)\n", operation, buffer, drive, track, sector); - if (operation != DSKCON_READ && operation != DSKCON_WRITE) - return FALSE; - if (buffer == 0) - return FALSE; - if (drive >= 4) - return FALSE; - if (track >= 35) - return FALSE; - if (sector == 0) - return FALSE; - if (sector > 18) - return FALSE; - - // Fill DSKCON input variables. - * (byte *) 0x00EA = operation; // DCOPC - * (byte *) 0x00EB = drive; // DCDRV - * (byte *) 0x00EC = track; // DCTRK - * (byte *) 0x00ED = sector; // DCSEC - * (word *) 0x00EE = buffer; // DCBPT - - asm("PSHS", "U,Y,X,A"); // protect against BASIC routine - asm("JSR", "[$C004]"); // call DSKCON - asm("PULS", "A,X,Y,U"); - - return (* (byte *) 0x00F0) == 0; // zero in DCSTA means success -} - - -#else /* ndef _COCO_BASIC_ */ - - -byte dskcon(byte operation, byte *buffer, byte drive, byte track, byte sector) -{ - //printf("- dskcon(%u, 0x%04x, %u, %u, %u)\n", operation, buffer, drive, track, sector); - if (operation != DSKCON_READ && operation != DSKCON_WRITE) - return FALSE; - if (buffer == 0) - return FALSE; - if (drive >= 4) - return FALSE; - if (track >= 35) - return FALSE; - if (sector == 0) - return FALSE; - if (sector > 18) - return FALSE; - - // Fill input variables of simulated DSKCON routine. - byte *dskConUSimVars = (byte *) 0xFF04; - dskConUSimVars[1] = drive; // DCDRV - dskConUSimVars[2] = track; // DCTRK - dskConUSimVars[3] = sector; // DCSEC - * (word *) (dskConUSimVars + 4) = buffer; // DCBPT - - // Specifying the operation code causes the simulated DSKCON routine to run - // (and block the execution). - // - dskConUSimVars[0] = operation; // DCOPC: DSKCON read operation code - - return !dskConUSimVars[6]; // zero in DCSTA means success -} - - -#endif /* ndef _COCO_BASIC_ */ - - -byte readDiskSector(byte *dest, byte drive, byte track, byte sector) -{ - return dskcon(DSKCON_READ, dest, drive, track, sector); -} - - -byte writeDiskSector(byte *src, byte drive, byte track, byte sector) -{ - return dskcon(DSKCON_WRITE, src, drive, track, sector); -} - - -struct FileDesc -{ - byte drive; - byte firstGran; // 0..67 - word numBytesLastSector; // 0..256 - uint32_t length; // length of file - byte curGran; // 0..67, 255 means at EOF - byte curSec; // 1..9 (relative to current granule) - word curGranLen; // 0..GRANULE_SIZE - uint32_t offset; // reading offset - word secOffset; // 0..256: index into curSector[] (256 means beyond sector) - byte curSector[256]; - word curSectorAvailBytes; // number valid bytes in curSector[] (0..256) -}; - - -#define MAX_NUM_GRANULES 68 - -byte curDriveNo = 0; -byte *fatBuffer = 0; // will point to an array of MAX_NUM_GRANULES entries -byte fatUpToDate = FALSE; // when TRUE, fatBuffer[] does not need to be reloaded - - -byte initdisk(byte newFATBuffer[]) -{ - fatBuffer = newFATBuffer; - return 1; -} - - -// CAUTION: As of version 0.2.0 of this file, initdisk() MUST have been called -// before calling this or any other function of this file. -// Otherwise, a call to openfile() will fail. -// To force users of this file to be aware of the change, function open() -// has been renamed to openfile(). -// -// Initializes a file descriptor with the given filename. -// The filename must not contain a drive specification -// (the drive used is the one set by setDefautlDriveNo()). -// Filename search is not case sensitive. -// Period must be used as extension separator. -// Filenames do not have to be padded to 8 characters, -// nor extensions to 3. -// fileDesc must point to a 3-byte region. -// Returns 1 upon success, 0 upon failure (*fd is then undefined). -// close() must be called with fileDesc to release the -// underlying resources. -// -byte openfile(struct FileDesc *fd, const char *filename) -{ - if (fd == 0 || filename == 0 || fatBuffer == 0) - return 0; // invalid arguments, or initdisk() not called - //printf("- openfile(0x%x, %s): fd->curSector=0x%x\n", fd, filename, fd->curSector); - assert(fd->curSector != 0); - - char dirEntry[16]; - if (!findDirEntry(dirEntry, filename)) - return 0; // file not found - - byte *fat = updateFAT(); - if (!fat) - return 0; - - byte firstGran = dirEntry[13]; - word numBytesLastSector = * (word *) (dirEntry + 14); - - fd->drive = curDriveNo; - fd->firstGran = firstGran; - fd->numBytesLastSector = numBytesLastSector; - computeFileLength(fd->length, fd->firstGran, fd->numBytesLastSector); - - rewind(fd); - - return 1; -} - - -void rewind(struct FileDesc *fd) -{ - if (fd == 0) - return; // invalid arguments - - byte *fat = updateFAT(); - if (!fat) - return; - - fd->curGran = fd->firstGran; - fd->curSec = 1; - fd->curGranLen = getGranuleLength(fat, fd->firstGran, fd->numBytesLastSector); - fd->offset = 0; - fd->secOffset = 0; - fd->curSectorAvailBytes = 0; -} - - -// Reads the current drive's FAT and returns the address of the -// internal buffer that contains it. -// -// Returns 0 if the FAT buffer pointer is null. -// Reads the FAT sector the first time, but not the following times, -// unless fatUpToDate is reset to 0. -// -// All accesses to the FAT must use the pointer returned by this function. -// -byte *updateFAT() -{ - if (fatUpToDate) - return fatBuffer; - - if (!fatBuffer) - return (byte *) 0; - - byte fatSector[256]; - if (!readDiskSector(fatSector, curDriveNo, 17, 2)) - { - //printf("updateFAT: failed to read FAT of drive %u\n", curDriveNo); - return (byte *) 0; - } - - memcpy(fatBuffer, fatSector, MAX_NUM_GRANULES); - fatUpToDate = TRUE; - return fatBuffer; -} - - -// Returns 0 upon success, -1 upon failure. -// 'fd' allows to be null; nothing done then, and 1 is returned. -// -sbyte close(struct FileDesc *fd) -{ - return 0; -} - - -// Returns number of bytes read. -// -word read(struct FileDesc *fd, char *buf, word numBytesRequested) -{ - //printf("- read(%u bytes): start: offset=$%04x%04x, secOffset=$%04x, curGran=%2u\n", - // numBytesRequested, fd->offset[0], fd->offset[1], fd->secOffset, fd->curGran); - if (fd == 0) - return 0; - if (buf == 0) - return 0; - if (numBytesRequested == 0) - return 0; - - char *bufStart = buf; - for (;;) - { - word numAvailBytes; - byte *availBytes = getCurrentlyAvailableBytes(fd, &numAvailBytes); - //printf("- read: AVAIL=%u, $%x\n", numAvailBytes, availBytes); - - if (numAvailBytes >= numBytesRequested) // enough to finish request - { - memcpy(buf, availBytes, numBytesRequested); - buf += numBytesRequested; - advanceOffset(fd, numBytesRequested); - //printf("- read: enough to finish request: %p - %p\n", buf, bufStart); - return buf - bufStart; - } - - // Currently loaded sector not enough. - - if (numAvailBytes > 0) - { - //printf("- read: delivering %u avail bytes\n", numAvailBytes); - memcpy(buf, availBytes, numAvailBytes); // send what we currently have - buf += numAvailBytes; - numBytesRequested -= numAvailBytes; - advanceOffset(fd, numAvailBytes); - } - - if (!getNextSector(fd)) // if reached EOF - { - //printf("- read: reached EOF: %p - %p\n", buf, bufStart); - return buf - bufStart; - } - } -} - - -enum { GRANULE_SIZE = 2304 }; - - -// newPos: 2-word position in bytes. -// Returns 0 for success, -1 for failure. -// -sbyte seek(struct FileDesc *fd, uint32_t newPos) -{ - //printf("\n- seek(at %lu): start\n", newPos); - if (fd == 0) - return -1; - - // If requested position is beyond end of file, clamp requested position. - // - if (newPos > fd->length) - { - //printf("- seek: clamping\n"); - newPos = fd->length; - } - - // Compute granule index by dividing newPos by GRANULE_SIZE. - // The granule index is relative to logical file contents, - // it is not an index into the FAT. - // - byte granIndex = 0; - uint32_t pos = newPos; - //printf("- seek: before while: pos=%lu granIndex=%2u\n", pos, granIndex); - while (pos >= GRANULE_SIZE) - { - ++granIndex; - pos -= GRANULE_SIZE; - //printf("- seek: pos=%lu granIndex=%2u\n", pos, granIndex); - } - - // Here, pos[1] is the offset in the last granule. - word offsetInLastGranule = (word) pos; - assert(offsetInLastGranule < GRANULE_SIZE); - - // Determine the granule (0..67) from granIndex and the FAT. - // - byte *fat = updateFAT(); - if (!fat) - return -1; - byte gran = fd->firstGran; - //printf("- seek: granIndex=%u, offsetInLastGranule=%u, gran=%u\n", - // granIndex, offsetInLastGranule, gran); - for ( ; granIndex; --granIndex) - { - assert(gran < 0xC0); // not supposed to be the last granule - gran = fat[gran]; - } - assert(gran >= 0 && gran < MAX_NUM_GRANULES); - fd->curGran = gran; - - // Determine the sector (1..9) inside granule 'gran'. - // - fd->curSec = (byte) ((offsetInLastGranule >> 8) + 1); - assert(fd->curSec >= 1 && fd->curSec <= 9); - - // Determine the current granule's length in bytes. - // - fd->curGranLen = getGranuleLength(fat, gran, fd->numBytesLastSector); - - fd->secOffset = offsetInLastGranule & 0xFF; - - fd->curSectorAvailBytes = 0; - - fd->offset = newPos; - //printf("- seek: %u %u %u %lu %u %u\n", - // fd->curGran, fd->curSec, fd->curGranLen, - // fd->offset, fd->secOffset, - // fd->curSectorAvailBytes); - - return 0; // success -} - - -byte *getCurrentlyAvailableBytes(struct FileDesc *fd, word *numAvailBytes) -{ - //printf("- getCurrentlyAvailableBytes: start: %u, %u\n", - // fd->secOffset, fd->curSectorAvailBytes); - - if (fd->curSectorAvailBytes == 0) - { - // This is the state after a seek. secOffset can be 0..256. - // - *numAvailBytes = 0; - return (byte *) 0; - } - - assert(fd->secOffset <= fd->curSectorAvailBytes); - - byte *availBytes = (byte *) fd->curSector + fd->secOffset; - - *numAvailBytes = fd->curSectorAvailBytes - fd->secOffset; - - //printf("- getCurrentlyAvailableBytes: %u at 0x%x\n", *numAvailBytes, availBytes); - return availBytes; -} - - -void advanceOffset(struct FileDesc *fd, word numBytes) -{ - fd->offset += numBytes; - fd->secOffset += numBytes; - - //printf("- advanceOffset: now 0x%04x%04x\n", fd->offset[0], fd->offset[1]); - assert(fd->secOffset <= fd->curSectorAvailBytes); - - if (fd->secOffset >= fd->curSectorAvailBytes) // if reached end of available bytes - { - // Declare 'fd' to be empty of available bytes. - // This will force another read. - // - fd->secOffset = 0; - fd->curSectorAvailBytes = 0; - } -} - - -// Returns true if sector successfully read, false otherwise. -// -byte getNextSector(struct FileDesc *fd) -{ - //printf("- getNextSector: start: curGran=%u, curSec=%u\n", - // fd->curGran, fd->curSec); - if (fd->curGran == 0xFF) // if at EOF - { - //printf("- getNextSector: EOF\n"); - return 0; - } - - byte track; - byte sec; - granuleToTrack(fd->curGran, &track, &sec); - if (!readDiskSector(fd->curSector, fd->drive, track, sec + fd->curSec)) - return 0; - - // Sector read successfully. - // Determine how many bytes in it are part of the file. - // - if (isLastSectorOfFile(fd)) - fd->curSectorAvailBytes = fd->numBytesLastSector; - else - fd->curSectorAvailBytes = 256; - - // Determine number of sectors in current granule that are - // part of the file (1..9). - // - byte *fat = updateFAT(); - if (!fat) - return 0; - byte g = fat[fd->curGran]; - byte numSectorsCurGran; - if (g >= 0xC1) - numSectorsCurGran = g - 0xC0; - else - numSectorsCurGran = 9; - - //printf("- getNextSector: sector has %u, g=%2u, gran has %u\n", - // fd->curSectorAvailBytes, g, numSectorsCurGran); - - // Advance sector index. Go to next granule if needed. - // - ++fd->curSec; - if (fd->curSec > numSectorsCurGran) // if current granule finished - { - if (g >= 0xC1) // if current granule is last - fd->curGran = 0xFF; // marks file descriptor as at EOF, for next call - else - { - fd->curSec = 1; - fd->curGran = g; - } - } - //printf("- getNextSector: end: curGran=%u, curSec=%u\n", fd->curGran, fd->curSec); - return 1; -} - - -// Output: -// *track: 0..16, 18..34. -// *sec: 0 or 9. -// -void granuleToTrack(byte granule, byte *track, byte *sec) -{ - byte t = granule; - asm("LSR", t); // t = granule / 2 - if (t >= 17) // if granule is after dir track - asm("INC", t); - byte s = granule; - asm("ANDB", "#1"); // we assume that B still holds 's' - asm("STB", s); - if (s > 0) - s = 9; - - *track = t; - *sec = s; -} - - -byte isLastSectorOfFile(struct FileDesc *fd) -{ - byte *fat = updateFAT(); - if (!fat) - return 1; // hope that caller will stop using disk... - byte g = fat[fd->curGran]; - if (g >= 0xC1) - if (fd->curSec == g - 0xC0) - return 1; - return 0; -} - - -byte getFileLength(struct FileDesc *fd, uint32_t dwLengthInBytes) -{ - if (!fd) - { - dwLengthInBytes = 0; - return FALSE; - } - - return computeFileLength(dwLengthInBytes, - fd->firstGran, fd->numBytesLastSector); -} - - -//TODO: test this on file whose length is multiple of 256 bytes. -byte computeFileLength(uint32_t dwLength, byte firstGran, word numBytesLastSector) -{ - if (dwLength == 0) - return FALSE; - - // Presume error: - dwLength = 0xFFFFFFFFUL; - - if (firstGran > 67) - return FALSE; - if (numBytesLastSector > 256) - return FALSE; - - byte *fat = updateFAT(); - if (!fat) - return FALSE; - - byte curGran = fat[firstGran]; - dwLength = 0; - while (curGran <= 0xC0) - { - dwLength += GRANULE_SIZE; - curGran = fat[curGran]; - } - - word numBytesLastGran = curGran - 0xC1; // for now, this is number of full sectors - asm("LDD", numBytesLastGran); // B = num full sectors, A = 0 - asm("EXG", "A,B"); // A = num full sectors, B = 0, i.e., D = num bytes in full sectors - asm("STD", numBytesLastGran); - numBytesLastGran += numBytesLastSector; - - dwLength += numBytesLastGran; // add numBytesLastGran to dwLength[0]:dwLength[1] - - return TRUE; -} - - -word getGranuleLength(byte *fat, byte granule, word numBytesLastSector) -{ - if (fat == 0) - return 0; - if (granule < 0) - return 0; - if (granule > 67) - return 0; - - byte entry = fat[granule]; - if (entry > 0xC9) - return 0; // free granule, or invalid FAT entry - if (entry >= 0xC1) - return ((word) entry - 0xC1) * 256 + numBytesLastSector; - - return GRANULE_SIZE; // this entry points to a following granule, so 'granule' is full -} - - -// dirEntry: 16-byte region -// -byte findDirEntry(char *dirEntry, const char *filename) -{ - char normalizedFilename[12]; - normalizeFilename(normalizedFilename, filename); - //printf("Normalized filename: '%s'\n", normalizedFilename); - - for (byte sector = 3; sector <= 18; ++sector) - { - byte dirSector[256]; - if (!readDiskSector(dirSector, curDriveNo, 17, sector)) - return 0; // TODO: report I/O error instead of "not found" - - byte *entry; - for (word index = 0; index < 256; index += 32) - { - entry = dirSector + index; - if (!*entry) // if erased entry - continue; - if (*entry == 0xFF) // if end of dir - break; - - if (memcmp(entry, normalizedFilename, 11) == 0) // if filename matches - { - memcpy(dirEntry, entry, 16); - return 1; // found - } - } - if (*entry == 0xFF) // if end of dir - break; - } - - return 0; // not found -} - - -// Normalizes the filename in 'src' into the 12-byte buffer -// designated by 'dest'. -// Expects period as extension separator in 'src'. -// Converts letters to upper case. -// Pads filename and extension with spaces. -// Writes 11 non-null characters to the destination buffer, -// followed by a terminating '\0' character. -// -void normalizeFilename(char *dest, const char *src) -{ - const char *reader = src; - byte i; - for (i = 0; i < 8; ++i) // copy filename until period - { - if (*reader == '.') - { - ++reader; // skip the point: it is not part of the extension - break; - } - if (*reader == 0) - break; - *dest = (char) toupper(*reader); - ++dest; - ++reader; - } - if (i == 8) // if filename is at least 8 chars long - { - // Check if filename too long. - while (*reader != 0 && *reader != '.') - ++reader; - if (*reader == '.') // skip the point - ++reader; - } - else - while (i < 8) // pad filename with spaces - { - *dest++ = ' '; - ++i; - } - for (i = 0; i < 3; ++i) // copy extension - { - if (*reader == 0) - break; - *dest = (char) toupper(*reader); - ++reader; - ++dest; - } - while (i < 3) // pad extension with spaces - { - *dest++ = ' '; - ++i; - } - *dest = '\0'; -} - - -byte getLastBasicDriveNo() -{ - #ifdef _COCO_BASIC_ - return * (byte *) 0xEB; - #else - return 0; - #endif -} - - -byte setDefaultDriveNo(byte no) -{ - if (no > 3) - return FALSE; - curDriveNo = no; - return TRUE; -} - - -#define getDefautlDriveNo() getDefaultDriveNo() /* oops */ - - -byte getDefaultDriveNo() -{ - return curDriveNo; -} diff -Nru cmoc-0.1.65/src/support/float-ecb.inc cmoc-0.1.67/src/support/float-ecb.inc --- cmoc-0.1.65/src/support/float-ecb.inc 2017-10-14 04:13:16.000000000 +0000 +++ cmoc-0.1.67/src/support/float-ecb.inc 1970-01-01 00:00:00.000000000 +0000 @@ -1,1549 +0,0 @@ -; float-ecb.inc - Part of Standard CMOC library under Extended Color Basic. -; -; This file contains code that calls Color Basic and Extended Color -; Basic routines. - -FP0ADDR EQU $004F -FP1ADDR EQU $005C - -; Fields of Color Basic's first two (unpacked) float point accumulators. -FP0EXP EQU FP0ADDR -FP0MAN EQU FP0ADDR+1 -FP0SGN EQU FP0ADDR+5 -FP1EXP EQU FP1ADDR -FP1MAN EQU FP1ADDR+1 -FP1SGN EQU FP1ADDR+5 - -VALTYP EQU $0006 ; variable type (0 = numeric) -FPCARY EQU $005B ; floating point carry byte -RESSGN EQU $0062 ; sign of result of operation -FPSBYT EQU $0063 ; floating point sub byte - -GETCCH EQU $00A5 -CHARAD EQU $00A6 ; interpreter's input pointer -COEFCT EQU $0055 ; polynomial coefficient counter - - -#if defined(_CMOC_NEED_initSingleFromSignedWord_) - -; Initializes the single-precision float at X with the signed word in D. -; -initSingleFromSignedWord - pshs u,y,x - jsr $B4F4 ; load D (signed) into FPA0 - puls x - jsr $BC35 ; pack FPA0 into X - puls y,u,pc ; not implemented - -#endif /* defined(initSingleFromSignedWord_) */ - - -#if defined(_CMOC_NEED_initSingleFromUnsignedWord_) - -; Initializes the single-precision float at X with the unsigned word in D. -; -initSingleFromUnsignedWord - pshs u,y,x - lbsr loadUnsignedDInFPA0 ; load D (unsigned) into FPA0 - puls x - jsr $BC35 ; pack FPA0 into X - puls y,u,pc ; not implemented - -#endif /* defined(_CMOC_NEED_initSingleFromUnsignedWord_) */ - - -#if defined(_CMOC_NEED_initSingleFromDWord_) - -; Initializes the single-precision float at X with the dword whose address is in D. -; The carry must be the signedness flag (0 for unsigned dword, non-zero for signed). -; -initSingleFromDWord - pshs u,y,x,cc - clr VALTYP ; variable type: numeric - tfr d,x ; X => dword - ldd 2,x ; copy dword to mantissa - std FP0MAN+2 - ldd ,x - std FP0MAN -; A is now high byte of mantissa, as expected by $BC84 - ldb #128+32 ; exponent: 32 - stb FP0EXP - clr FPSBYT - clr FP0SGN - puls cc ; test signedness flag - bcc @unsigned - suba #$80 ; set carry if non-negative mantissa - bra @normalize -@unsigned - orcc #1 ; consider mantissa non-negative -@normalize - jsr $BA18 ; normalize FPA0 (reads carry) - puls x - jsr $BC35 ; pack FPA0 into X - puls y,u,pc ; not implemented - -#endif /* defined(initSingleFromDWord_) */ - - -#ifdef _CMOC_NEED_initSignedWordFromSingle_ - -; Based on Color Basic's routine at $B3ED. -; Input: D => address of source number. X => address of destination number. -; -initSignedWordFromSingle - pshs u,y,x ; save X that points to destination - tfr d,x ; point X to source real - jsr $BC14 ; load FPA0 from X -; - lda FP0EXP - cmpa #$80+16 ; is FPA0 >= 32768? - bhs @tooHigh - ldx #$B3DF ; packed -32768 - jsr $BC96 ; compare FPA0 to -32768 - blt @tooLow -; -; Shift the mantissa right until the binary point is 16 bits from the left of the mantissa. -; We do not use Color Basic's $BCC8 routine because it is off by one on negative values, for C. - lda FP0EXP - suba #$80 ; real exponent in A (0..15); we want to increase it to 16 - bls @zero - cmpa #8 - bhi @byteShiftDone -; Shift 8 bits right. - ldb FP0MAN - stb FP0MAN+1 - clr FP0MAN - adda #8 - bra @shiftCond -@byteShiftDone -@shiftLoop - lsr FP0MAN - ror FP0MAN+1 - inca -@shiftCond - cmpa #16 - blo @shiftLoop -; Absolute value of result is in FP0MAN. Apply the sign. - tst FP0SGN - bpl @nonNeg - clra - clrb - subd FP0MAN - bra @store -@nonNeg - ldd FP0MAN - bra @store -@zero - clra - clrb - bra @store -@tooHigh - tst FP0SGN - bpl @max - ldd #-32768 - bra @store -@max - ldd #32767 - bra @store -@tooLow - ldd #-32768 -@store - std [,s] ; get dest address from stack, store word there - puls x,y,u,pc - -#endif /* _CMOC_NEED_initSignedWordFromSingle_ */ - - -#ifdef _CMOC_NEED_initSignedByteFromSingle_ - -; Based on Color Basic's routine at $B3ED. -; -initSignedByteFromSingle - pshs u,y,x ; save X that points to destination - tfr d,x ; point X to source real - jsr $BC14 ; load FPA0 from X -; - lda FP0EXP - cmpa #$80+8 ; is FPA0 >= 128? - bhs @tooHigh - leax packedMinus128,pcr - jsr $BC96 ; compare FPA0 to -128 - blt @tooLow -; -; Shift the mantissa right until the binary point is 8 bits from the left of the mantissa. -; We do not use Color Basic's $BCC8 routine because it is off by one on negative values, for C. - lda FP0EXP - suba #$80 ; real exponent in A (0..7); we want to increase it to 16 - bls @zero - ldb FP0MAN -@shiftLoop - lsrb - inca - cmpa #8 - blo @shiftLoop -; Absolute value of result is in FP0MAN. Apply the sign. - tst FP0SGN - bpl @store - negb - bra @store -@zero - clrb - bra @store -@tooHigh - tst FP0SGN - bpl @max - ldb #-128 - bra @store -@max - ldb #127 - bra @store -@tooLow - ldb #-128 -@store - stb [,s] ; get dest address from stack, store byte there - puls x,y,u,pc -packedMinus128 - fdb $8880 - fdb $0000 - fcb $00 - -#endif /* _CMOC_NEED_initSignedByteFromSingle_ */ - - -#ifdef _CMOC_NEED_initUnsignedWordFromSingle_ - -; Based on Color Basic's routine at $B3ED. -; -initUnsignedWordFromSingle - pshs u,y,x ; save X that points to destination - tfr d,x ; point X to source real - jsr $BC14 ; load FPA0 from X -; - tst FP0SGN ; check sign of FPA0 - bmi @tooLow ; if < 0 - lda FP0EXP - beq @tooLow ; FPA0 is 0.0, so result is 0 - cmpa #$80+16 ; is FPA0 >= 65536? - bhi @tooHigh ; if yes -; Denormalize FPA0 until exponent is 16. - beq @denormDone ; if exponent is 16, denorm done - cmpa #$80+8 ; if exponent is in 9..15 - bhi @shiftBits ; then go shift mantissa right by 1 to 7 bits -; Exponent is in 1..8. Shift mantissa right by 8 bits. - ldb FP0MAN ; load high byte of mantissa - stb FP0MAN+1 ; shift it 8 bits right - clr FP0MAN ; clear high byte of mantissa - adda #8 ; exponent is now 8 more than initially (now 9..16) - cmpa #$80+16 - beq @denormDone -@shiftBits ; exponent is in 9..15 - ldx #0 - tfr a,b - abx ; X = $80 + exponent - ldd FP0MAN ; load high 16 bits of mantissa -@shiftLoop - lsra ; shift D right one bit - rorb - leax 1,x ; increment exponent - cmpx #$80+16 - blo @shiftLoop ; loop if exponent not yet 16 - bra @store ; go store D as result -@denormDone - ldd FP0MAN - bra @store -@tooHigh - ldd #65535 - bra @store -@tooLow - clra - clrb -@store - std [,s] ; get dest address from stack, store word there - puls x,y,u,pc - -#endif /* _CMOC_NEED_initUnsignedWordFromSingle_ */ - - -#ifdef _CMOC_NEED_initUnsignedByteFromSingle_ - -; Based on Color Basic's routine at $B3ED. -; -initUnsignedByteFromSingle - pshs u,y,x ; save X that points to destination - tfr d,x ; point X to source real - jsr $BC14 ; load FPA0 from X -; - tst FP0SGN ; check sign of FPA0 - bmi @tooLow ; if < 0 - lda FP0EXP - beq @tooLow ; FPA0 is 0.0, so result is 0 - cmpa #$80+8 ; is FPA0 >= 256? - bhi @tooHigh ; if yes -; Denormalize FPA0 until exponent is 8. - beq @denormDone ; if exponent is 8, denorm done -@shiftBits ; exponent is in 9..15 - ldb FP0MAN ; load high 8 bits of mantissa -@shiftLoop - lsrb - inca ; increment exponent - cmpa #$80+8 - blo @shiftLoop ; loop if exponent not yet 8 - bra @store ; go store D as result -@denormDone - ldb FP0MAN - bra @store -@tooHigh - ldb #255 - bra @store -@tooLow - clrb -@store - stb [,s] ; get dest address from stack, store byte there - puls x,y,u,pc - -#endif /* _CMOC_NEED_initUnsignedByteFromSingle_ */ - - -#if defined(_CMOC_NEED_initDWordFromSingle_) - -; Based on Color Basic's routine at $B3ED. -; Input: Carry = signedness flag: 0 if input long is unsigned, non-zero if signed. -; D => address of source number. X => address of destination number. -; -initDWordFromSingle - pshs u,y,x,cc - tfr d,x ; point X to source real - jsr $BC14 ; load FPA0 from X -; - puls cc ; get signedness flag in C - bcc @checkUnsignedRange ; if unsigned -; - lda FP0EXP - cmpa #$80+32 ; is FPA0 >= 2^32? - bhs @tooHighSigned - leax packedMinus2To31,pcr - jsr $BC96 ; compare FPA0 to -2^31 - blt @tooLowSigned - bra @inRange -; -@checkUnsignedRange - tst FP0SGN - bmi @zero ; if FPA0 negative, return 0UL - lda FP0EXP - cmpa #$80+32 ; is FPA0 > 2^32? - bhi @tooHighUnsigned -; -@inRange -; -; Shift the mantissa right until the binary point is 32 bits from the left of the mantissa. -; We do not use Color Basic's $BCC8 routine because it is off by one on negative values, for C. - lda FP0EXP - suba #$80 ; real exponent in A (0..32); we want to increase it to 32 - bls @zero - bra @byteShiftCond -@byteShiftLoop -; Shift 8 bits right. - ldx FP0MAN+1 - stx FP0MAN+2 - ldb FP0MAN - stb FP0MAN+1 - clr FP0MAN - adda #8 -@byteShiftCond - cmpa #32 - beq @shiftDone - cmpa #24 - bls @byteShiftLoop -@shiftLoop ; shift one bit at a time under A is 32 - lsr FP0MAN - ror FP0MAN+1 - ror FP0MAN+2 - ror FP0MAN+3 - inca -@shiftCond - cmpa #32 - blo @shiftLoop -@shiftDone -; Absolute value of result is in FP0MAN. Apply the sign. - tst FP0SGN - bpl @store - ldx #FP0MAN - lbsr negateDWord - bra @store -@zero - clr FP0MAN - clr FP0MAN+1 - clr FP0MAN+2 - clr FP0MAN+3 - bra @store -@tooHighUnsigned - ldd #$FFFF - std FP0MAN - std FP0MAN+2 - bra @store -@tooHighSigned - tst FP0SGN - bpl @maxSigned -@tooLowSigned - ldd #$8000 - std FP0MAN - clr FP0MAN+2 - clr FP0MAN+3 - bra @store -@maxSigned - ldd #$7FFF - std FP0MAN - lda #$FF - std FP0MAN+2 -@store ; FP0MAN now contains final dword - puls x ; get dest address from stack - ldd FP0MAN - std ,x - ldd FP0MAN+2 - std 2,x - puls y,u,pc -packedMinus2To31 - fcb $a0 ; 128 + exponent 32 - fdb $8000 - fdb $0000 -#endif - - -#if defined(_CMOC_NEED_negateSingle_) - -; Negates the packed single-precision float at X. -; Preserves X. -; -negateSingle - ldb 1,x - eorb #$80 - stb 1,x - rts - -#endif /* defined(_CMOC_NEED_negateSingle_) */ - - -#if defined(_CMOC_NEED_isSingleZero_) - -; Sets the Z flag to 1 if the packed single-precision float at X is zero. -; Sets the Z flag to 0 otherwise. -; Preserves X and D. -; -isSingleZero - tst ,x ; null exponent byte means number is zero - rts - -#endif /* defined(_CMOC_NEED_isSingleZero_) */ - - -#if defined(_CMOC_NEED_incrementSingle_) - -; Adds one 1 to the packed single-precision float at X. -; Preserves X. -; -incrementSingle - pshs u,y,x - jsr $BC14 ; unpack into Basic's FPA0 (preserves X) - leax packed1,DAT - jsr $B9C2 ; add number at X to FPA0 (trashes X) - ldx ,s ; retrieve original number address - jsr $BC35 ; pack FPA0 into X - puls x,y,u,pc -packed1 - fcb $81 ; packed 1.0 - fdb 0 - fdb 0 - -#endif /* defined(_CMOC_NEED_incrementSingle_) */ - - -#if defined(_CMOC_NEED_decrementSingle_) - -; Subtracts one 1 from the packed single-precision float at X. -; Preserves X. -; -decrementSingle - pshs u,y,x - jsr $BC14 ; unpack into Basic's FPA0 (preserves X) - leax packedMinus1,DAT - jsr $B9C2 ; add number at X to FPA0 (trashes X) - ldx ,s ; retrieve original number address - jsr $BC35 ; pack FPA0 at X - puls x,y,u,pc -packedMinus1 - fcb $81 ; packed -1.0 - fdb $8000 - fdb 0 - -#endif /* defined(_CMOC_NEED_decrementSingle_) */ - - -#if defined(_CMOC_NEED_copySingle_) - -; Copies a packed single-precision number. -; Input: D = address of source number. -; X = address of destination number. -; Preserves X. Trashes D. -; -copySingle - pshs u - tfr d,u ; address of source number - ldd ,u - std ,x - ldd 2,u - std 2,x - ldb 4,u - stb 4,x - puls u,pc - -#endif /* defined(_CMOC_NEED_copySingle_) */ - - -#if defined(_CMOC_NEED_addSingleSingle_) || defined(_CMOC_NEED_subSingleSingle_) \ - || defined(_CMOC_NEED_mulSingleSingle_) || defined(_CMOC_NEED_divSingleSingle_) - -; Does a binary operation on two numbers and writes the result at a third location. -; Synopsis: -; pshs rightOpAddr -; pshs leftOpAddr -; leax result,PCR -; lbsr addSingleSingle ; for example -; leas 4,s -; [...] -; addSingleSingle -; pshs u,y,x -; ldu #colorBasicRoutine ; routine uses FPA0 & FPA1, result in FPA0 -; bsr binOpSingleSingle -; puls u,x,y,pc -; Preserves X. -; -binOpSingleSingle - ldx 12,s ; rightOpAddr - jsr $BC14 ; unpack from X to FPA0 - ldx 10,s ; leftOpAddr - jsr ,u ; unpack from X to FPA1; FPA0 = op(FPA0, FPA1) - ldx 2,s ; result address - jmp $BC35 ; pack FPA0 into X - -#endif /* defined(_CMOC_NEED_addSingleSingle_) */ - - -#ifdef _CMOC_NEED_addSingleSingle_ - -; Adds two numbers and writes the result at a third location. -; Synopsis: -; pshs rightOpAddr -; pshs leftOpAddr -; leax result,PCR -; lbsr addSingleSingle -; leas 4,s -; Preserves X. -; -addSingleSingle - pshs u,y,x - ldu #$B9C2 ; unpack from X to FPA1; FPA0 += FPA1 - lbsr binOpSingleSingle - puls x,y,u,pc - -#endif /* defined(_CMOC_NEED_addSingleSingle_) */ - - -#ifdef _CMOC_NEED_subSingleSingle_ - -; Subtracts two numbers and writes the result at a third location. -; Synopsis: -; pshs rightOpAddr -; pshs leftOpAddr -; leax result,PCR -; lbsr subSingleSingle -; leas 4,s -; Preserves X. -; -subSingleSingle - pshs u,y,x - ldu #$B9B9 ; unpack from X to FPA1; FPA0 = FPA1 - FPA0 - lbsr binOpSingleSingle - puls x,y,u,pc - -#endif /* defined(_CMOC_NEED_subSingleSingle_) */ - - -#ifdef _CMOC_NEED_addSingleInt_ - -addSingleInt - pshs u,y,x - ldd 10,s ; right (signed int) - jsr $B4F4 ; load D (signed) into FPA0 - ldx 8,s ; left (single) - jsr $BB2F ; unpack from X to FPA1 - lbra addFPA0FPA1 - -#endif /* _CMOC_NEED_addSingleInt_ */ - - -#if defined(_CMOC_NEED_addSingleInt_) \ - || defined(_CMOC_NEED_addIntSingle_) \ - || defined(_CMOC_NEED_addSingleUnsignedInt_) \ - || defined(_CMOC_NEED_addUnsignedIntSingle_) \ - || defined(_CMOC_NEED_addSingleUnsignedDWord_) \ - || defined(_CMOC_NEED_addUnsignedDWordSingle_) \ - || defined(_CMOC_NEED_addSingleSignedDWord_) \ - || defined(_CMOC_NEED_addSignedDWordSingle_) - -* Input: FPA1 = number to add to FPA0. -* Pushed argument = address of resulting packed float. -* Output: Sum (packed single) stored at X. -* Trashes FPA0. -* Preserves X. -* -addFPA0FPA1 - lda FP1EXP ; load exponent of FPA1 - ldb FP0EXP ; load exponent of FPA0 - jsr $B9C5 ; FPA0 += FPA1 - - ldx ,s ; result - jsr $BC35 ; pack FPA0 into X - puls x,y,u,pc - -#endif - - -#if defined(_CMOC_NEED_addSingleUnsignedInt_) \ - || defined(_CMOC_NEED_addUnsignedIntSingle_) \ - || defined(_CMOC_NEED_mulSingleUnsignedInt_) \ - || defined(_CMOC_NEED_mulUnsignedIntSingle_) \ - || defined(_CMOC_NEED_initSingleFromUnsignedWord_) \ - || defined(_CMOC_NEED_subSingleUnsignedInt_) \ - || defined(_CMOC_NEED_subUnsignedIntSingle_) \ - || defined(_CMOC_NEED_divSingleUnsignedInt_) \ - || defined(_CMOC_NEED_divUnsignedIntSingle_) - -loadUnsignedDInFPA0 - clr VALTYP ; set variable type (VALTYP) to numeric - std FP0MAN ; store in upper mantissa of FPA0 - ldb #128+16 ; 16 = exponent required - orcc #1 ; set carry so value seen as non-negative (see $BA18) - jmp $BC86 ; continue with rest of routine started at $B4F4 - -#endif - - -#if defined(_CMOC_NEED_addSingleUnsignedDWord_) \ - || defined(_CMOC_NEED_addUnsignedDWordSingle_) \ - || defined(_CMOC_NEED_subSingleUnsignedDWord_) \ - || defined(_CMOC_NEED_subUnsignedDWordSingle_) \ - || defined(_CMOC_NEED_mulUnsignedDWordSingle_) \ - || defined(_CMOC_NEED_mulSingleUnsignedDWord_) \ - || defined(_CMOC_NEED_divSingleUnsignedDWord_) - -; Input: X => unsigned dword. -; -loadUnsignedDWordInFPA0 - clr VALTYP ; set value type to numeric - ldd ,x - std FP0MAN ; store in upper mantissa of FPA0 - ldd 2,x - std FP0MAN+2 ; store in upper mantissa of FPA0 - ldb #128+32 ; 32 = exponent required - stb FP0EXP - clr FPSBYT - clr FP0SGN - orcc #1 ; set carry so value seen as non-negative (see $BA18) - jmp $BA18 ; normalize FPA0 (reads carry) - -#endif - -#if defined(_CMOC_NEED_addSingleSignedDWord_) \ - || defined(_CMOC_NEED_addSignedDWordSingle_) \ - || defined(_CMOC_NEED_subSingleSignedDWord_) \ - || defined(_CMOC_NEED_subSignedDWordSingle_) \ - || defined(_CMOC_NEED_mulSingleSignedDWord_) \ - || defined(_CMOC_NEED_mulSignedDWordSingle_) \ - || defined(_CMOC_NEED_divSingleSignedDWord_) - -; Input: X => unsigned dword. -; -loadSignedDWordInFPA0 - clr VALTYP ; set value type to numeric - ldd ,x - std FP0MAN ; store in upper mantissa of FPA0 - ldd 2,x - std FP0MAN+2 ; store in upper mantissa of FPA0 - ldb #128+32 ; 32 = exponent required - stb FP0EXP - clr FPSBYT - clr FP0SGN - ldb FP0MAN - subb #$80 ; set carry if value is non-negative (see $BA18) - jmp $BA18 ; normalize FPA0 (reads carry) - -#endif - - -#ifdef _CMOC_NEED_addIntSingle_ - -addIntSingle - pshs u,y,x - ldd 8,s ; right (signed int) - jsr $B4F4 ; load D (signed) into FPA0 - ldx 10,s ; left (single) - jsr $BB2F ; unpack from X to FPA1 - lbra addFPA0FPA1 - -#endif /* _CMOC_NEED_addIntSingle_ */ - - -#ifdef _CMOC_NEED_addSingleUnsignedInt_ - -addSingleUnsignedInt - pshs u,y,x - ldd 10,s ; right (unsigned int) - lbsr loadUnsignedDInFPA0 - ldx 8,s ; left (single) - jsr $BB2F ; unpack from X to FPA1 - lbra addFPA0FPA1 - -#endif /* _CMOC_NEED_addSingleUnsignedInt_ */ - - -#ifdef _CMOC_NEED_addUnsignedIntSingle_ - -addUnsignedIntSingle - pshs u,y,x - ldd 8,s ; left (unsigned int) - lbsr loadUnsignedDInFPA0 - ldx 10,s ; right (single) - jsr $BB2F ; unpack from X to FPA1 - lbra addFPA0FPA1 - -#endif /* _CMOC_NEED_addUnsignedIntSingle_ */ - - -#ifdef _CMOC_NEED_addSingleUnsignedDWord_ - -addSingleUnsignedDWord - pshs u,y,x - ldx 10,s ; right (unsigned dword) - lbsr loadUnsignedDWordInFPA0 - ldx 8,s ; left (single) - jsr $BB2F ; unpack from X to FPA1 - lbra addFPA0FPA1 - -#endif /* _CMOC_NEED_addSingleUnsignedDWord_ */ - - -#ifdef _CMOC_NEED_addUnsignedDWordSingle_ - -addUnsignedDWordSingle - pshs u,y,x - ldx 8,s ; left (unsigned dword) - lbsr loadUnsignedDWordInFPA0 - ldx 10,s ; right (single) - jsr $BB2F ; unpack from X to FPA1 - lbra addFPA0FPA1 - -#endif /* _CMOC_NEED_addUnsignedDWordSingle_ */ - - -#ifdef _CMOC_NEED_addSingleSignedDWord_ - -addSingleSignedDWord - pshs u,y,x - ldx 10,s ; right (unsigned dword) - lbsr loadSignedDWordInFPA0 - ldx 8,s ; left (single) - jsr $BB2F ; unpack from X to FPA1 - lbra addFPA0FPA1 - -#endif /* _CMOC_NEED_addSingleSignedDWord_ */ - - -#ifdef _CMOC_NEED_addSignedDWordSingle_ - -addSignedDWordSingle - pshs u,y,x - ldx 8,s ; left (unsigned dword) - lbsr loadSignedDWordInFPA0 - ldx 10,s ; right (single) - jsr $BB2F ; unpack from X to FPA1 - lbra addFPA0FPA1 - -#endif /* _CMOC_NEED_addSignedDWordSingle_ */ - - -#ifdef _CMOC_NEED_subSingleInt_ - -subSingleInt - pshs u,y,x - - clra - clrb - subd 10,s ; load right operand, negated - jsr $B4F4 ; load D (signed) into FPA0 - - ; The left operand must be loaded second because $B4F4 - ; appears to trash FPA1. - - ldx 8,s ; left (single) - jsr $BB2F ; unpack from X to FPA1 - - lbra subSingle_common_add - -#endif /* _CMOC_NEED_subSingleInt_ */ - - -#ifdef _CMOC_NEED_subSingleUnsignedInt_ - -subSingleUnsignedInt - pshs u,y,x - - ldd 10,s ; load right operand - lbsr loadUnsignedDInFPA0 - com FP0SGN ; negate FPA0 - - ; The left operand is loaded second in case the - ; preceding call trashes FPA1. - - ldx 8,s ; left (single) - jsr $BB2F ; unpack from X to FPA1 - - lbra subSingle_common_add - -#endif /* _CMOC_NEED_subSingleUnsignedInt_ */ - - -#ifdef _CMOC_NEED_subSingleUnsignedDWord_ - -subSingleUnsignedDWord - pshs u,y,x - - ldx 10,s ; load right operand - lbsr loadUnsignedDWordInFPA0 - com FP0SGN ; negate FPA0 - - ; The left operand is loaded second in case the - ; preceding call trashes FPA1. - - ldx 8,s ; left (single) - jsr $BB2F ; unpack from X to FPA1 - - lbra subSingle_common_add - -#endif /* _CMOC_NEED_subSingleUnsignedDWord_ */ - - -#ifdef _CMOC_NEED_subSingleSignedDWord_ - -subSingleSignedDWord - pshs u,y,x - - ldx 10,s ; load right operand - lbsr loadSignedDWordInFPA0 - com FP0SGN ; negate FPA0 - - ; The left operand is loaded second in case the - ; preceding call trashes FPA1. - - ldx 8,s ; left (single) - jsr $BB2F ; unpack from X to FPA1 - - lbra subSingle_common_add - -#endif /* _CMOC_NEED_subSingleSignedDWord_ */ - - -#if defined(_CMOC_NEED_subSingleInt_) \ - || defined(_CMOC_NEED_subSingleUnsignedInt_) \ - || defined(_CMOC_NEED_subIntSingle_) \ - || defined(_CMOC_NEED_subUnsignedIntSingle_) \ - || defined(_CMOC_NEED_subSingleUnsignedDWord_) \ - || defined(_CMOC_NEED_subUnsignedDWordSingle_) - -; Input: FPA0 = left operand; -; 10,S (before call) => right operand (single-precision). -; Output: ,S (before call) => address where to pack the result. -; Preserves X, Y, U. Trashes D. -; -subSingle_common - ldx 10,s ; right (single) - jsr $BB2F ; unpack from X to FPA1 - com FP1SGN ; invert sign of FPA1 - - ; Compute sign of result. - ldb FP0SGN - eorb FP1SGN - stb RESSGN - -subSingle_common_add - lda FP1EXP ; load exponent of FPA1 - ldb FP0EXP ; load exponent of FPA0 - jsr $B9C5 ; FPA0 += FPA1 - - ldx ,s ; result - jsr $BC35 ; pack FPA0 into X - puls x,y,u,pc - -#endif - - -#ifdef _CMOC_NEED_subIntSingle_ - -subIntSingle - pshs u,y,x - ldd 8,s ; load left operand - jsr $B4F4 ; load D (signed) into FPA0 - lbra subSingle_common - -#endif /* _CMOC_NEED_subIntSingle_ */ - - -#ifdef _CMOC_NEED_subUnsignedIntSingle_ - -subUnsignedIntSingle - pshs u,y,x - ldd 8,s ; load left operand - lbsr loadUnsignedDInFPA0 - lbra subSingle_common - -#endif /* _CMOC_NEED_subUnsignedIntSingle_ */ - - -#ifdef _CMOC_NEED_subUnsignedDWordSingle_ - -subUnsignedDWordSingle - pshs u,y,x - ldx 8,s ; load left operand - lbsr loadUnsignedDWordInFPA0 - lbra subSingle_common - -#endif /* _CMOC_NEED_subUnsignedDWordSingle_ */ - - -#ifdef _CMOC_NEED_subSignedDWordSingle_ - -subSignedDWordSingle - pshs u,y,x - ldx 8,s ; load left operand - lbsr loadSignedDWordInFPA0 - lbra subSingle_common - -#endif /* _CMOC_NEED_subSignedDWordSingle_ */ - - -#ifdef _CMOC_NEED_mulSingleSingle_ - -; Multiplies two numbers and writes the result at a third location. -; Synopsis: -; pshs rightOpAddr -; pshs leftOpAddr -; leax result,PCR -; lbsr mulSingleSingle -; leas 4,s -; Preserves X. -; -mulSingleSingle - pshs u,y,x - leau unpackXToFPA1AndMul,pcr - lbsr binOpSingleSingle - puls x,y,u,pc - -#endif /* defined(_CMOC_NEED_mulSingleSingle_) */ - - -#if defined(_CMOC_NEED_mulSingleSingle_) \ - || defined(_CMOC_NEED_mulSingleUnsignedInt_) \ - || defined(_CMOC_NEED_mulUnsignedIntSingle_) \ - || defined(_CMOC_NEED_mulSingleInt_) \ - || defined(_CMOC_NEED_mulIntSingle_) \ - || defined(_CMOC_NEED_divSingleSingle_) \ - || defined(_CMOC_NEED_divSingleUnsignedInt_) \ - || defined(_CMOC_NEED_divUnsignedIntSingle_) \ - || defined(_CMOC_NEED_divSingleInt_) \ - || defined(_CMOC_NEED_divIntSingle_) \ - || defined(_CMOC_NEED_divSingleUnsignedDWord_) \ - || defined(_CMOC_NEED_divUnsignedDWordSingle_) \ - || defined(_CMOC_NEED_divSingleSignedDWord_) \ - || defined(_CMOC_NEED_divSignedDWordSingle_) - -unpackXtoFPA0AndPrep - jsr $BC14 ; unpack from X to FPA0 - bra prepBinFloatOp - -unpackXtoFPA1AndPrep - jsr $BB2F ; unpack from X to FPA1 - -prepBinFloatOp - ; Compute sign of result, as in $BB2F. - ldb FP0SGN - eorb FP1SGN - stb RESSGN - - lda FP1EXP - ldb FP0EXP ; as in $BB2F; sets N and Z - rts - -#endif - - -#if defined(_CMOC_NEED_mulSingleSingle_) \ - || defined(_CMOC_NEED_mulSingleUnsignedInt_) \ - || defined(_CMOC_NEED_mulUnsignedIntSingle_) \ - || defined(_CMOC_NEED_mulSingleInt_) \ - || defined(_CMOC_NEED_mulIntSingle_) \ - || defined(_CMOC_NEED_mulSingleUnsignedDWord_) \ - || defined(_CMOC_NEED_mulSingleSignedDWord_) \ - || defined(_CMOC_NEED_mulUnsignedDWordSingle_) \ - || defined(_CMOC_NEED_mulSignedDWordSingle_) - -; To be called by binOpSingleSingle. -; Input: X => packed single to be unpacked to FPA1. -; FPA0 => factor of the multiplication to be done. -; Output: FPA0 = FPA0 * single at X. -; -unpackXToFPA1AndMul - lbsr unpackXtoFPA1AndPrep - jmp $BACC ; starts with BEQ instruction - -#endif - - -#if defined(_CMOC_NEED_divSingleSingle_) \ - || defined(_CMOC_NEED_divSingleUnsignedInt_) \ - || defined(_CMOC_NEED_divUnsignedIntSingle_) \ - || defined(_CMOC_NEED_divSingleInt_) \ - || defined(_CMOC_NEED_divIntSingle_) \ - || defined(_CMOC_NEED_divSingleUnsignedDWord_) \ - || defined(_CMOC_NEED_divUnsignedDWordSingle_) \ - || defined(_CMOC_NEED_divSingleSignedDWord_) \ - || defined(_CMOC_NEED_divSignedDWordSingle_) - -; To be called by binOpSingleSingle. -; Input: X => packed single to be unpacked to FPA1. -; FPA0 => factor of the division to be done. -; Output: FPA0 = FPA0 / single at X. -; -unpackXToFPA0AndDiv - lbsr unpackXtoFPA0AndPrep - jmp $BB91 ; starts with BEQ instruction - -unpackXToFPA1AndDiv - lbsr unpackXtoFPA1AndPrep - jmp $BB91 ; starts with BEQ instruction - -#endif - - -#ifdef _CMOC_NEED_mulSingleUnsignedInt_ - -mulSingleUnsignedInt - pshs u,y,x - ldd 10,s ; right (unsigned int) - lbsr loadUnsignedDInFPA0 - ldx 8,s ; left (single) - lbsr unpackXToFPA1AndMul - ldx ,s ; result address - jsr $BC35 ; pack FPA0 into X - puls x,y,u,pc - -#endif /* defined(_CMOC_NEED_mulSingleUnsignedInt_) */ - - -#ifdef _CMOC_NEED_mulSingleUnsignedDWord_ - -mulSingleUnsignedDWord - pshs u,y,x - ldx 10,s ; right (unsigned dword) - lbsr loadUnsignedDWordInFPA0 - ldx 8,s ; left (single) - lbsr unpackXToFPA1AndMul - ldx ,s ; result address - jsr $BC35 ; pack FPA0 into X - puls x,y,u,pc - -#endif /* defined(_CMOC_NEED_mulSingleUnsignedDWord_) */ - - -#ifdef _CMOC_NEED_mulSingleSignedDWord_ - -mulSingleSignedDWord - pshs u,y,x - ldx 10,s ; right (unsigned dword) - lbsr loadSignedDWordInFPA0 - ldx 8,s ; left (single) - lbsr unpackXToFPA1AndMul - ldx ,s ; result address - jsr $BC35 ; pack FPA0 into X - puls x,y,u,pc - -#endif /* defined(_CMOC_NEED_mulSingleSignedDWord_) */ - - -#ifdef _CMOC_NEED_mulUnsignedIntSingle_ - -mulUnsignedIntSingle - pshs u,y,x - ldd 8,s ; left (unsigned int) - lbsr loadUnsignedDInFPA0 - ldx 10,s ; right (single) - lbsr unpackXToFPA1AndMul - ldx ,s ; result address - jsr $BC35 ; pack FPA0 into X - puls x,y,u,pc - -#endif /* defined(_CMOC_NEED_mulUnsignedIntSingle_) */ - - -#ifdef _CMOC_NEED_mulUnsignedDWordSingle_ - -mulUnsignedDWordSingle - pshs u,y,x - ldx 8,s ; left (unsigned dword) - lbsr loadUnsignedDWordInFPA0 - ldx 10,s ; right (single) - lbsr unpackXToFPA1AndMul - ldx ,s ; result address - jsr $BC35 ; pack FPA0 into X - puls x,y,u,pc - -#endif /* defined(_CMOC_NEED_mulUnsignedIntSingle_) */ - - -#ifdef _CMOC_NEED_mulSignedDWordSingle_ - -mulSignedDWordSingle - pshs u,y,x - ldx 8,s ; left (unsigned dword) - lbsr loadSignedDWordInFPA0 - ldx 10,s ; right (single) - lbsr unpackXToFPA1AndMul - ldx ,s ; result address - jsr $BC35 ; pack FPA0 into X - puls x,y,u,pc - -#endif /* defined(_CMOC_NEED_mulSignedIntSingle_) */ - - -#ifdef _CMOC_NEED_mulSingleInt_ - -mulSingleInt - pshs u,y,x - ldd 10,s ; right (unsigned int) - jsr $B4F4 ; load D (signed) into FPA0 - ldx 8,s ; left (single) - lbsr unpackXToFPA1AndMul - ldx ,s ; result address - jsr $BC35 ; pack FPA0 into X - puls x,y,u,pc - -#endif /* defined(_CMOC_NEED_mulSingleInt_) */ - - -#ifdef _CMOC_NEED_mulIntSingle_ - -mulIntSingle - pshs u,y,x - ldd 8,s ; right (unsigned int) - jsr $B4F4 ; load D (signed) into FPA0 - ldx 10,s ; left (single) - lbsr unpackXToFPA1AndMul - ldx ,s ; result address - jsr $BC35 ; pack FPA0 into X - puls x,y,u,pc - -#endif /* defined(_CMOC_NEED_mulIntSingle_) */ - - -#ifdef _CMOC_NEED_divSingleSingle_ - -; Divides two numbers and writes the result at a third location. -; Synopsis: -; pshs rightOpAddr -; pshs leftOpAddr -; leax result,PCR -; lbsr divSingleSingle -; leas 4,s -; Preserves X. -; -divSingleSingle - tst [4,s] ; check exponent of right operand (divisor) - lbeq divByZeroSingle - pshs u,y,x - ldu #$BB8F ; unpack from X to FPA1; FP0 = FPA1 / FPA0 - lbsr binOpSingleSingle - puls x,y,u,pc - -#endif /* defined(_CMOC_NEED_divSingleSingle_) */ - - -#ifdef _CMOC_NEED_divSingleUnsignedInt_ - -divSingleUnsignedInt - ldd 4,s ; check right operand (divisor) - lbeq divByZeroSingle - pshs u,y,x - ldd 10,s ; right (unsigned int) - lbsr loadUnsignedDInFPA0 - ldx 8,s ; left (single) - lbsr unpackXToFPA1AndDiv - ldx ,s ; result address - jsr $BC35 ; pack FPA0 into X - puls x,y,u,pc - -#endif /* defined(_CMOC_NEED_divSingleUnsignedInt_) */ - - -#ifdef _CMOC_NEED_divSingleUnsignedDWord_ - -divSingleUnsignedDWord - lbsr isDWordZeroSpecial ; check right operand (divisor) - lbeq divByZeroSingle -@noDivBy0 - pshs u,y,x - ldx 10,s ; right (unsigned dword) - lbsr loadUnsignedDWordInFPA0 - ldx 8,s ; left (single) - lbsr unpackXToFPA1AndDiv - ldx ,s ; result address - jsr $BC35 ; pack FPA0 into X - puls x,y,u,pc - -#endif /* defined(_CMOC_NEED_divSingleUnsignedDWord_) */ - - -#ifdef _CMOC_NEED_divSingleSignedDWord_ - -divSingleSignedDWord - lbsr isDWordZeroSpecial ; check right operand (divisor) - lbeq divByZeroSingle -@noDivBy0 - pshs u,y,x - ldx 10,s ; right (signed dword) - lbsr loadSignedDWordInFPA0 - ldx 8,s ; left (single) - lbsr unpackXToFPA1AndDiv - ldx ,s ; result address - jsr $BC35 ; pack FPA0 into X - puls x,y,u,pc - -#endif /* defined(_CMOC_NEED_divSingleSignedDWord_) */ - - -#if defined(_CMOC_NEED_divSingleSingle_) \ - || defined(_CMOC_NEED_divSingleUnsignedInt_) \ - || defined(_CMOC_NEED_divUnsignedIntSingle_) \ - || defined(_CMOC_NEED_divSingleInt_) \ - || defined(_CMOC_NEED_divIntSingle_) \ - || defined(_CMOC_NEED_divSingleUnsignedDWord_) \ - || defined(_CMOC_NEED_divUnsignedDWordSingle_) \ - || defined(_CMOC_NEED_divSingleSignedDWord_) \ - || defined(_CMOC_NEED_divSignedDWordSingle_) - -; Input: X => Result of division (packed single). -; -divByZeroSingle - clr ,x ; store 0.0f in result - rts -#endif - - -#if defined(_CMOC_NEED_divSingleUnsignedDWord_) \ - || defined(_CMOC_NEED_divSingleSignedDWord_) - -; Input: 4,S (before call) => dword. -; Output: Z is set iff divisor is zero. -; Preserves X. Trashes D. -; -isDWordZeroSpecial - pshs x - ldx 8,s ; address of dword to check - ldd ,x - bne @done - ldd 2,x -@done - puls x,pc - -#endif - - -#ifdef _CMOC_NEED_divUnsignedIntSingle_ - -divUnsignedIntSingle - tst [4,s] ; check exponent of right operand (divisor) - lbeq divByZeroSingle - pshs u,y,x - ldd 8,s ; left (unsigned int) - lbsr loadUnsignedDInFPA1 - ldx 10,s ; right (single) - lbsr unpackXToFPA0AndDiv - ldx ,s ; result address - jsr $BC35 ; pack FPA0 into X - puls x,y,u,pc - -* Trashes FPA0. -loadUnsignedDInFPA1 - lbsr loadUnsignedDInFPA0 - ldd FP0ADDR - std FP1ADDR - ldd FP0ADDR+2 - std FP1ADDR+2 - ldd FP0ADDR+4 - std FP1ADDR+4 - rts - -#endif /* defined(_CMOC_NEED_divUnsignedIntSingle_) */ - - -#ifdef _CMOC_NEED_divUnsignedDWordSingle_ - -divUnsignedDWordSingle - tst [4,s] ; check exponent of right operand (divisor) - lbeq divByZeroSingle - pshs u,y,x - ldx 8,s ; left (unsigned dword) - lbsr loadUnsignedDWordInFPA1 - ldx 10,s ; right (single) - lbsr unpackXToFPA0AndDiv - ldx ,s ; result address - jsr $BC35 ; pack FPA0 into X - puls x,y,u,pc - -* Trashes FPA0. -loadUnsignedDWordInFPA1 - lbsr loadUnsignedDWordInFPA0 - ldd FP0ADDR - std FP1ADDR - ldd FP0ADDR+2 - std FP1ADDR+2 - ldd FP0ADDR+4 - std FP1ADDR+4 - rts - -#endif /* defined(_CMOC_NEED_divUnsignedDWordSingle_) */ - - -#ifdef _CMOC_NEED_divSignedDWordSingle_ - -divSignedDWordSingle - tst [4,s] ; check exponent of right operand (divisor) - lbeq divByZeroSingle - pshs u,y,x - ldx 8,s ; left (signed dword) - lbsr loadSignedDWordInFPA1 - ldx 10,s ; right (single) - lbsr unpackXToFPA0AndDiv - ldx ,s ; result address - jsr $BC35 ; pack FPA0 into X - puls x,y,u,pc - -* Trashes FPA0. -loadSignedDWordInFPA1 - lbsr loadSignedDWordInFPA0 - ldd FP0ADDR - std FP1ADDR - ldd FP0ADDR+2 - std FP1ADDR+2 - ldd FP0ADDR+4 - std FP1ADDR+4 - rts - -#endif /* defined(_CMOC_NEED_divSignedDWordSingle_) */ - - -#ifdef _CMOC_NEED_divSingleInt_ - -divSingleInt - ldd 4,s ; check right operand (divisor) - lbeq divByZeroSingle - pshs u,y,x - ldd 10,s ; right (unsigned int) - jsr $B4F4 ; load D (signed) into FPA0 - ldx 8,s ; left (single) - lbsr unpackXToFPA1AndDiv - ldx ,s ; result address - jsr $BC35 ; pack FPA0 into X - puls x,y,u,pc - -#endif /* defined(_CMOC_NEED_divSingleInt_) */ - - -#ifdef _CMOC_NEED_divIntSingle_ - -divIntSingle - tst [4,s] ; check exponent of right operand (divisor) - lbeq divByZeroSingle - pshs u,y,x - ldd 8,s ; left (signed int) - lbsr loadSignedDInFPA1 - ldx 10,s ; left (single) - lbsr unpackXToFPA0AndDiv - ldx ,s ; result address - jsr $BC35 ; pack FPA0 into X - puls x,y,u,pc - -* Trashes FPA0. -loadSignedDInFPA1 - jsr $B4F4 ; load D (signed) into FPA0 - ldd FP0ADDR - std FP1ADDR - ldd FP0ADDR+2 - std FP1ADDR+2 - ldd FP0ADDR+4 - std FP1ADDR+4 - rts - -#endif /* defined(_CMOC_NEED_divIntSingle_) */ - - -#if defined(_CMOC_NEED_cmpSingleSingle_) - -* Input: Stacked arguments: address of left packed single, address of right. -* Output: B = -1, 0 or +1. CC reflects signed comparison of B with 0. -* Preserves X. -* -cmpSingleSingle - pshs u,y,x - - ldx 8,s ; point to left operand (single) - jsr $BC14 ; unpack from X to FPA0 - - ldx 10,s ; point to right operand (single) - jsr $BC96 ; compare FPA0 to X: puts -1, 0 or +1 in B, sets CC - - puls x,y,u,pc - -#endif /* _CMOC_NEED_cmpSingleSingle_ */ - - -#if defined(_CMOC_NEED_cmpSingleSignedInt_) - -* Input: Stacked arguments: address of left packed single, right signed int. -* Output: B = -1, 0 or +1. CC reflects signed comparison of B with 0. -* Preserves X. -* -cmpSingleSignedInt - pshs u,y,x - - ldd 10,s ; right operand (signed int) - jsr $B4F4 ; load D (signed) into FPA0 - - ldx 8,s ; point to left operand (single) - jsr $BC96 ; compare FPA0 to X: puts -1, 0 or +1 in B, sets CC - - negb ; invert result because comparison was inverted - cmpb #0 ; signed comparison, so no TSTB - puls x,y,u,pc - -#endif /* _CMOC_NEED_cmpSingleSignedInt_ */ - - -#if defined(_CMOC_NEED_cmpSignedIntSingle_) - -cmpSignedIntSingle - pshs u,y,x - - ldd 8,s ; left operand (signed int) - jsr $B4F4 ; load D (signed) into FPA0 - - ldx 10,s ; point to right operand (single) - jsr $BC96 ; compare FPA0 to X: puts -1, 0 or +1 in B, sets CC - - puls x,y,u,pc - -#endif /* _CMOC_NEED_cmpSignedIntSingle_ */ - - -#if defined(_CMOC_NEED_cmpSingleUnsignedInt_) - -cmpSingleUnsignedInt - pshs u,y,x - - ldd 10,s ; right operand (unsigned int) - lbsr loadUnsignedDInFPA0 ; load D (unsigned) into FPA0 - - ldx 8,s ; point to left operand (single) - jsr $BC96 ; compare FPA0 to X: puts -1, 0 or +1 in B, sets CC - - negb ; invert result because comparison was inverted - cmpb #0 ; signed comparison, so no TSTB - puls x,y,u,pc - -#endif /* _CMOC_NEED_cmpSingleUnsignedInt_ */ - - -#if defined(_CMOC_NEED_cmpUnsignedIntSingle_) - -cmpUnsignedIntSingle - pshs u,y,x - - ldd 8,s ; left operand (unsigned int) - lbsr loadUnsignedDInFPA0 ; load D (unsigned) into FPA0 - - ldx 10,s ; point to right operand (single) - jsr $BC96 ; compare FPA0 to X: puts -1, 0 or +1 in B, sets CC - - puls x,y,u,pc - -#endif /* _CMOC_NEED_cmpUnsignedIntSingle_ */ - -#if defined(_CMOC_NEED_strtof_) - -; float strtof(char *nptr, char **endptr); -; -; The string must have at most 255 characters (before the null terminator). -; Caution: Passing a excessive value will make Basic fail with an OV ERROR. -; -_strtof - - pshs u,y - - ldd CHARAD ; save interpreter's input pointer - pshs b,a - ldx 10,s ; nptr: string to parse - stx CHARAD ; point interpreter to caller's string - - jsr GETCCH ; get current char - jsr $BD12 ; result in FPA0; trashes FPA1 - - ldx 8,s ; address of returned float (hidden parameter) - jsr $BC35 ; pack FPA0 into X - - ldd CHARAD ; get address in nptr where parsing stopped - std [12,s] ; store at *endptr - - puls a,b - std CHARAD ; restore interpreter's input pointer - - puls y,u,pc - -#endif /* _CMOC_NEED_strtof_ */ - - -#if defined(_CMOC_NEED_ftoa_) - -; char *ftoa(char out[38], float f); -; -; Writes 'f' in ASCII decimal to 'out'. -; Does not precede the string with a space if 'f' is positive or zero. -; -_ftoa - pshs u,y ; protect against Basic - - leax 8,s ; f: number to convert to string - jsr $BC14 ; load FPA0 from X - - ldu 6,s ; out: where to write string - - ldb FP0SGN ; get sign of 'f' - bpl @positive - lda #'-' - sta ,u+ ; output minus sign - bra @signDone -@positive - lda #' ' -@signDone - jsr $BDE6 ; let Basic do rest of conversion - - ldd 6,s ; success: return 'out' - puls y,u,pc - -#endif /* _CMOC_NEED_ftoa_ */ diff -Nru cmoc-0.1.65/src/support/Makefile.am cmoc-0.1.67/src/support/Makefile.am --- cmoc-0.1.65/src/support/Makefile.am 2018-02-08 05:10:36.000000000 +0000 +++ cmoc-0.1.67/src/support/Makefile.am 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -# $Id: Makefile.am,v 1.10 2018/02/08 05:10:36 sarrazip Exp $ - -pkgdata_DATA = \ - stdlib.inc \ - stdlib-data.inc \ - float-ecb.inc \ - cmoc.h \ - assert.h \ - stdarg.h \ - coco.h \ - disk.h - -EXTRA_DIST = $(pkgdata_DATA) - -MAINTAINERCLEANFILES = Makefile.in diff -Nru cmoc-0.1.65/src/support/Makefile.in cmoc-0.1.67/src/support/Makefile.in --- cmoc-0.1.65/src/support/Makefile.in 2020-04-25 02:27:42.000000000 +0000 +++ cmoc-0.1.67/src/support/Makefile.in 1970-01-01 00:00:00.000000000 +0000 @@ -1,483 +0,0 @@ -# Makefile.in generated by automake 1.15.1 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994-2017 Free Software Foundation, Inc. - -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - -# $Id: Makefile.am,v 1.10 2018/02/08 05:10:36 sarrazip Exp $ - -VPATH = @srcdir@ -am__is_gnu_make = { \ - if test -z '$(MAKELEVEL)'; then \ - false; \ - elif test -n '$(MAKE_HOST)'; then \ - true; \ - elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ - true; \ - else \ - false; \ - fi; \ -} -am__make_running_with_option = \ - case $${target_option-} in \ - ?) ;; \ - *) echo "am__make_running_with_option: internal error: invalid" \ - "target option '$${target_option-}' specified" >&2; \ - exit 1;; \ - esac; \ - has_opt=no; \ - sane_makeflags=$$MAKEFLAGS; \ - if $(am__is_gnu_make); then \ - sane_makeflags=$$MFLAGS; \ - else \ - case $$MAKEFLAGS in \ - *\\[\ \ ]*) \ - bs=\\; \ - sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ - | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ - esac; \ - fi; \ - skip_next=no; \ - strip_trailopt () \ - { \ - flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ - }; \ - for flg in $$sane_makeflags; do \ - test $$skip_next = yes && { skip_next=no; continue; }; \ - case $$flg in \ - *=*|--*) continue;; \ - -*I) strip_trailopt 'I'; skip_next=yes;; \ - -*I?*) strip_trailopt 'I';; \ - -*O) strip_trailopt 'O'; skip_next=yes;; \ - -*O?*) strip_trailopt 'O';; \ - -*l) strip_trailopt 'l'; skip_next=yes;; \ - -*l?*) strip_trailopt 'l';; \ - -[dEDm]) skip_next=yes;; \ - -[JT]) skip_next=yes;; \ - esac; \ - case $$flg in \ - *$$target_option*) has_opt=yes; break;; \ - esac; \ - done; \ - test $$has_opt = yes -am__make_dryrun = (target_option=n; $(am__make_running_with_option)) -am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) -pkgdatadir = $(datadir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkglibexecdir = $(libexecdir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -subdir = src/support -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/macros/ac_compile_warnings.m4 \ - $(top_srcdir)/macros/ac_prog_perl_modules.m4 \ - $(top_srcdir)/configure.ac -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) -mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs -CONFIG_CLEAN_FILES = -CONFIG_CLEAN_VPATH_FILES = -AM_V_P = $(am__v_P_@AM_V@) -am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) -am__v_P_0 = false -am__v_P_1 = : -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = -SOURCES = -DIST_SOURCES = -am__can_run_installinfo = \ - case $$AM_UPDATE_INFO_DIR in \ - n|no|NO) false;; \ - *) (install-info --version) >/dev/null 2>&1;; \ - esac -am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; -am__vpath_adj = case $$p in \ - $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ - *) f=$$p;; \ - esac; -am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; -am__install_max = 40 -am__nobase_strip_setup = \ - srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` -am__nobase_strip = \ - for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" -am__nobase_list = $(am__nobase_strip_setup); \ - for p in $$list; do echo "$$p $$p"; done | \ - sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ - $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ - if (++n[$$2] == $(am__install_max)) \ - { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ - END { for (dir in files) print dir, files[dir] }' -am__base_list = \ - sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ - sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -am__uninstall_files_from_dir = { \ - test -z "$$files" \ - || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ - || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ - $(am__cd) "$$dir" && rm -f $$files; }; \ - } -am__installdirs = "$(DESTDIR)$(pkgdatadir)" -DATA = $(pkgdata_DATA) -am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) -am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/mkinstalldirs -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -ACLOCAL = @ACLOCAL@ -AMTAR = @AMTAR@ -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -CPPFLAGS = @CPPFLAGS@ -CXX = @CXX@ -CXXDEPMODE = @CXXDEPMODE@ -CXXFLAGS = @CXXFLAGS@ -CYGPATH_W = @CYGPATH_W@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -ENV = @ENV@ -EXEEXT = @EXEEXT@ -GREP = @GREP@ -HEAD = @HEAD@ -HEXDUMP = @HEXDUMP@ -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ -LDFLAGS = @LDFLAGS@ -LEX = @LEX@ -LEXLIB = @LEXLIB@ -LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ -LTLIBOBJS = @LTLIBOBJS@ -LWAR = @LWAR@ -LWASM = @LWASM@ -LWLINK = @LWLINK@ -MAKEINFO = @MAKEINFO@ -MANUAL_DATE_EN = @MANUAL_DATE_EN@ -MKDIR_P = @MKDIR_P@ -OBJEXT = @OBJEXT@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_FULL_NAME = @PACKAGE_FULL_NAME@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_SUMMARY_EN = @PACKAGE_SUMMARY_EN@ -PACKAGE_SUMMARY_FR = @PACKAGE_SUMMARY_FR@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_URL = @PACKAGE_URL@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -PERL = @PERL@ -SET_MAKE = @SET_MAKE@ -SHELL = @SHELL@ -STRINGS = @STRINGS@ -STRIP = @STRIP@ -TAIL = @TAIL@ -VERSION = @VERSION@ -YACC = @YACC@ -YFLAGS = @YFLAGS@ -abs_builddir = @abs_builddir@ -abs_srcdir = @abs_srcdir@ -abs_top_builddir = @abs_top_builddir@ -abs_top_srcdir = @abs_top_srcdir@ -ac_ct_CXX = @ac_ct_CXX@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -bindir = @bindir@ -build_alias = @build_alias@ -builddir = @builddir@ -datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -host_alias = @host_alias@ -htmldir = @htmldir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -libdir = @libdir@ -libexecdir = @libexecdir@ -localedir = @localedir@ -localstatedir = @localstatedir@ -mandir = @mandir@ -mkdir_p = @mkdir_p@ -oldincludedir = @oldincludedir@ -pdfdir = @pdfdir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -runstatedir = @runstatedir@ -sbindir = @sbindir@ -sharedstatedir = @sharedstatedir@ -srcdir = @srcdir@ -sysconfdir = @sysconfdir@ -target_alias = @target_alias@ -top_build_prefix = @top_build_prefix@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -pkgdata_DATA = \ - stdlib.inc \ - stdlib-data.inc \ - float-ecb.inc \ - cmoc.h \ - assert.h \ - stdarg.h \ - coco.h \ - disk.h - -EXTRA_DIST = $(pkgdata_DATA) -MAINTAINERCLEANFILES = Makefile.in -all: all-am - -.SUFFIXES: -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ - && { if test -f $@; then exit 0; else break; fi; }; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/support/Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --gnu src/support/Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(am__aclocal_m4_deps): -install-pkgdataDATA: $(pkgdata_DATA) - @$(NORMAL_INSTALL) - @list='$(pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \ - if test -n "$$list"; then \ - echo " $(MKDIR_P) '$(DESTDIR)$(pkgdatadir)'"; \ - $(MKDIR_P) "$(DESTDIR)$(pkgdatadir)" || exit 1; \ - fi; \ - for p in $$list; do \ - if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ - echo "$$d$$p"; \ - done | $(am__base_list) | \ - while read files; do \ - echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgdatadir)'"; \ - $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgdatadir)" || exit $$?; \ - done - -uninstall-pkgdataDATA: - @$(NORMAL_UNINSTALL) - @list='$(pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \ - files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ - dir='$(DESTDIR)$(pkgdatadir)'; $(am__uninstall_files_from_dir) -tags TAGS: - -ctags CTAGS: - -cscope cscopelist: - - -distdir: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done -check-am: all-am -check: check-am -all-am: Makefile $(DATA) -installdirs: - for dir in "$(DESTDIR)$(pkgdatadir)"; do \ - test -z "$$dir" || $(MKDIR_P) "$$dir"; \ - done -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - if test -z '$(STRIP)'; then \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - install; \ - else \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ - fi -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." - -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) -clean: clean-am - -clean-am: clean-generic mostlyclean-am - -distclean: distclean-am - -rm -f Makefile -distclean-am: clean-am distclean-generic - -dvi: dvi-am - -dvi-am: - -html: html-am - -html-am: - -info: info-am - -info-am: - -install-data-am: install-pkgdataDATA - -install-dvi: install-dvi-am - -install-dvi-am: - -install-exec-am: - -install-html: install-html-am - -install-html-am: - -install-info: install-info-am - -install-info-am: - -install-man: - -install-pdf: install-pdf-am - -install-pdf-am: - -install-ps: install-ps-am - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-generic - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: uninstall-pkgdataDATA - -.MAKE: install-am install-strip - -.PHONY: all all-am check check-am clean clean-generic cscopelist-am \ - ctags-am distclean distclean-generic distdir dvi dvi-am html \ - html-am info info-am install install-am install-data \ - install-data-am install-dvi install-dvi-am install-exec \ - install-exec-am install-html install-html-am install-info \ - install-info-am install-man install-pdf install-pdf-am \ - install-pkgdataDATA install-ps install-ps-am install-strip \ - installcheck installcheck-am installdirs maintainer-clean \ - maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ - pdf-am ps ps-am tags-am uninstall uninstall-am \ - uninstall-pkgdataDATA - -.PRECIOUS: Makefile - - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff -Nru cmoc-0.1.65/src/support/stdarg.h cmoc-0.1.67/src/support/stdarg.h --- cmoc-0.1.65/src/support/stdarg.h 2017-08-11 00:44:10.000000000 +0000 +++ cmoc-0.1.67/src/support/stdarg.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,44 +0,0 @@ -/* stdarg.h - Support for variable argument functions - - By Pierre Sarrazin . - This file is in the public domain. -*/ - -#ifndef _stdarg_h_ -#define _stdarg_h_ - - -typedef char *va_list; - - -asm char *__va_arg(va_list *app, unsigned int sizeInBytes) -{ -#if 0 // Code on which the following asm{} is based. - char *origAddr = (char *) *app; - if (sizeInBytes == 1) // if char type or 1-byte struct - ++origAddr; // skip MSB of argument in stack; point to LSB - *app = (va_list) (origAddr + sizeInBytes); - return origAddr; -#else - asm - { - ldx [2,s] ; 2,s is 'app', so get *app in X - ldd 4,s ; sizeInBytes - cmpd #1 - bne @notSingleByte - leax 1,x ; ++origAddr -@notSingleByte - pshs x ; app is now at 4,s - leax d,x - stx [4,s] ; store in *app - puls a,b ; return origAddr in D - } -#endif -} - -#define va_start(ap, lastFixed) do { (ap) = (char *) &(lastFixed) + sizeof(lastFixed); } while (0) -#define va_arg(ap, type) (* (type *) __va_arg(&(ap), sizeof(type))) -#define va_end(ap) do {} while (0) - - -#endif /* _stdarg_h_ */ diff -Nru cmoc-0.1.65/src/support/stdlib-data.inc cmoc-0.1.67/src/support/stdlib-data.inc --- cmoc-0.1.65/src/support/stdlib-data.inc 2017-10-15 00:30:48.000000000 +0000 +++ cmoc-0.1.67/src/support/stdlib-data.inc 1970-01-01 00:00:00.000000000 +0000 @@ -1,52 +0,0 @@ -* stdlib-data.inc - Global variables used by stdlib.inc. -* -* By Pierre Sarrazin . -* This file is in the public domain. -* -* Each variable must be defined only with an RMB directive. -* It must be initialized by INILIB in stdlib.inc. - -INISTK RMB 2 receives initial stack pointer - -end_of_sbrk_mem RMB 2 -program_break RMB 2 - -#if defined(_CMOC_NEED_rand_) || defined(_CMOC_NEED_srand_) -SEED RMB 2 -#endif - -#ifdef _CMOC_NEED_sprintf_ -chrtomem_writer RMB 2 used by chrtomem, itself used by _sprintf -sprintf_retaddr RMB 2 used by _sprintf -sprintf_oldCHROUT RMB 2 used by _sprintf -#endif - -#ifdef _CMOC_CHECK_NULL_POINTERS_ - -* Initialized by INILIB to an RTS routine. -* Call set_null_ptr_handler() to specify another handler. -* The handler is assumed to have this signature: -* void handler(char *addressOfFailedCheck); -* -null_ptr_handler RMB 2 - -#endif /* _CMOC_CHECK_NULL_POINTERS_ */ - -#ifdef _CMOC_CHECK_STACK_OVERFLOW_ - -* Initialized by INILIB to a null pointer. -* Call set_stack_overflow_handler() to specify another handler. -* The handler is assumed to have this signature: -* void handler(char *addressOfFailedCheck, char *stackRegister); -* -stack_overflow_handler RMB 2 - -#endif /* _CMOC_CHECK_STACK_OVERFLOW_ */ - -#if defined(_CMOC_NEED_putchar_) || defined(_CMOC_NEED_putstr_) || defined(_CMOC_NEED_sprintf_) || defined(_CMOC_NEED_printf_) || defined(_CMOC_NEED_setConsoleOutHook_) -CHROUT RMB 2 CoCo Basic routine to write char to current device (at $6F) -#endif - -#if defined(OS9) && (defined(_CMOC_NEED_readline_) || defined(_CMOC_NEED_readword_)) -LINBUF RMB LBUFMX+1 buffer where readline() stores line read from user -#endif diff -Nru cmoc-0.1.65/src/support/stdlib.inc cmoc-0.1.67/src/support/stdlib.inc --- cmoc-0.1.65/src/support/stdlib.inc 2018-02-04 19:19:56.000000000 +0000 +++ cmoc-0.1.67/src/support/stdlib.inc 1970-01-01 00:00:00.000000000 +0000 @@ -1,4919 +0,0 @@ -* stdlib.inc - Standard CMOC library. -* -* By Pierre Sarrazin . -* This file is in the public domain. - -stdlib_start: - - -#if defined(OS9) -#define DAT Y /* CMOC uses Y to point to the data segment of the current process. */ -#else -#define DAT PCR /* The data segment at a fixed offset of the code segment. */ -#endif - -#if defined(OS9) -* OS-9 System calls. -F$Exit equ $06 Terminate Process -F$Sleep equ $0A Suspend Process -I$Write equ $8A Write Data -I$ReadLn equ $8B Read Line of ASCII Data -I$WritLn equ $8C Write Line of ASCII Data -#endif - - -* /* -* Initialize the standard library. -; Input: D = minus the number of bytes for the stack space (e.g., -1024 for 1k stack). -* Saves the initial stack for use by exit(). -* Initializes internal variables used by sbrk(). -* Initializes the seed of the random number generator with a fixed value. -* Initializes the null pointer and stack overflow handler pointers. -* Initializes CHROUT, which points to the system's character output routine. -* Initializes the global variables. -* */ -* -INILIB - IFNDEF OS9 -; Zero out "BSS" segment. -; Must be done first, because code that follows initializes INISTK, etc. - LDX #bss_end-bss_start ; number of bytes in "bss" section - BEQ @done - LEAU bss_start,pcr ; address of "bss" section -@loop - CLR ,U+ - LEAX -1,X - BNE @loop -@done - ENDC - - LEAX 2,S X = initial stack pointer - STX INISTK,DAT save this for exit() - - LEAX D,X point to top of stack space - STX end_of_sbrk_mem,DAT sbrk() will not allocate past this - LEAX program_end,PCR end of generated code - STX program_break,DAT initial Unix-like "program break" (cf sbrk) - -#if defined(_CMOC_NEED_rand_) || defined(_CMOC_NEED_srand_) - CLR SEED,DAT - CLR SEED+1,DAT -#endif - -#ifdef _CMOC_CHECK_NULL_POINTERS_ - LEAX nop_handler,PCR - STX null_ptr_handler,DAT -#endif - -#ifdef _CMOC_CHECK_STACK_OVERFLOW_ - LDX #0 - STX stack_overflow_handler,DAT -#endif - -#if defined(_CMOC_NEED_putchar_) || defined(_CMOC_NEED_putstr_) || defined(_CMOC_NEED_sprintf_) || defined(_CMOC_NEED_printf_) -#ifdef _COCO_BASIC_ /* CoCo's Extended Color Basic */ - LDX $A002 /* system's current address for PUTCHR */ -#else - LEAX PUTCHR,PCR -#endif - STX CHROUT,DAT -#endif - - LBRA INITGL initialize global variables - - -* void exit(int exitStatus); -* -* Clean up before returning control to the host environment. -* That environment does not necessarily use the exit status. -* It may only use the low byte. -* -* MUST be called by BSR, LBSR or JSR, not jumped to with BRA, LBRA or JMP, -* so that 2,S can be used to get 'exitStatus'. -* -_exit - -#ifdef _COCO_BASIC_ - -#if defined(_CMOC_NEED_readline_) || defined(_CMOC_NEED_readword_) - -* Zero out the LINBUF line buffer. This seems necessary to avoid -* ?SN ERROR after program execution on the CoCo. - LDX #LINBUF -EXIT10 CLR ,X+ - CMPX #LINBUF+1+LBUFMX - BLO EXIT10 - -#endif - - LDS INISTK,DAT retrieve stack pointer saved at beginning - RTS - -#elif defined(OS9) - - ldb 3,s get LSB of exit() argument - os9 F$Exit - -#elif defined(USIM) /* 6809 simulator */ - - SYNC to leave usim - -#elif defined(VECTREX) - - BRA _exit The eternal Vectrex loop on exit... - -#else - -#error Undefined target platform. - -#endif - -#if defined(VECTREX) -* VECTREX BIOS -Vec_Snd_Shadow EQU $C800 ;Shadow of sound chip registers (15 bytes) -Vec_Btn_State EQU $C80F ;Current state of all joystick buttons -Vec_Prev_Btns EQU $C810 ;Previous state of all joystick buttons -Vec_Buttons EQU $C811 ;Current toggle state of all buttons -Vec_Button_1_1 EQU $C812 ;Current toggle state of stick 1 button 1 -Vec_Button_1_2 EQU $C813 ;Current toggle state of stick 1 button 2 -Vec_Button_1_3 EQU $C814 ;Current toggle state of stick 1 button 3 -Vec_Button_1_4 EQU $C815 ;Current toggle state of stick 1 button 4 -Vec_Button_2_1 EQU $C816 ;Current toggle state of stick 2 button 1 -Vec_Button_2_2 EQU $C817 ;Current toggle state of stick 2 button 2 -Vec_Button_2_3 EQU $C818 ;Current toggle state of stick 2 button 3 -Vec_Button_2_4 EQU $C819 ;Current toggle state of stick 2 button 4 -Vec_Joy_Resltn EQU $C81A ;Joystick A/D resolution (0x80=min 0x00=max) -Vec_Joy_1_X EQU $C81B ;Joystick 1 left/right -Vec_Joy_1_Y EQU $C81C ;Joystick 1 up/down -Vec_Joy_2_X EQU $C81D ;Joystick 2 left/right -Vec_Joy_2_Y EQU $C81E ;Joystick 2 up/down -Vec_Joy_Mux EQU $C81F ;Joystick enable/mux flags (4 bytes) -Vec_Joy_Mux_1_X EQU $C81F ;Joystick 1 X enable/mux flag (=1) -Vec_Joy_Mux_1_Y EQU $C820 ;Joystick 1 Y enable/mux flag (=3) -Vec_Joy_Mux_2_X EQU $C821 ;Joystick 2 X enable/mux flag (=5) -Vec_Joy_Mux_2_Y EQU $C822 ;Joystick 2 Y enable/mux flag (=7) -Vec_Misc_Count EQU $C823 ;Misc counter/flag byte, zero when not in use -Vec_0Ref_Enable EQU $C824 ;Check0Ref enable flag -Vec_Loop_Count EQU $C825 ;Loop counter word (incremented in Wait_Recal) -Vec_Brightness EQU $C827 ;Default brightness -Vec_Dot_Dwell EQU $C828 ;Dot dwell time? -Vec_Pattern EQU $C829 ;Dot pattern (bits) -Vec_Text_HW EQU $C82A ;Default text height and width -Vec_Text_Height EQU $C82A ;Default text height -Vec_Text_Width EQU $C82B ;Default text width -Vec_Str_Ptr EQU $C82C ;Temporary string pointer for Print_Str -Vec_Counters EQU $C82E ;Six bytes of counters -Vec_Counter_1 EQU $C82E ;First counter byte -Vec_Counter_2 EQU $C82F ;Second counter byte -Vec_Counter_3 EQU $C830 ;Third counter byte -Vec_Counter_4 EQU $C831 ;Fourth counter byte -Vec_Counter_5 EQU $C832 ;Fifth counter byte -Vec_Counter_6 EQU $C833 ;Sixth counter byte -Vec_RiseRun_Tmp EQU $C834 ;Temp storage word for rise/run -Vec_Angle EQU $C836 ;Angle for rise/run and rotation calculations -Vec_Run_Index EQU $C837 ;Index pair for run -;* $C839 ;Pointer to copyright string during startup -Vec_Rise_Index EQU $C839 ;Index pair for rise -;* $C83B ;High score cold-start flag (=0 if valid) -Vec_RiseRun_Len EQU $C83B ;length for rise/run -;* $C83C ;temp byte -Vec_Rfrsh EQU $C83D ;Refresh time (divided by 1.5MHz) -Vec_Rfrsh_lo EQU $C83D ;Refresh time low byte -Vec_Rfrsh_hi EQU $C83E ;Refresh time high byte -Vec_Music_Work EQU $C83F ;Music work buffer (14 bytes, backwards?) -Vec_Music_Wk_A EQU $C842 ; register 10 -;* $C843 ; register 9 -;* $C844 ; register 8 -Vec_Music_Wk_7 EQU $C845 ; register 7 -Vec_Music_Wk_6 EQU $C846 ; register 6 -Vec_Music_Wk_5 EQU $C847 ; register 5 -;* $C848 ; register 4 -;* $C849 ; register 3 -;* $C84A ; register 2 -Vec_Music_Wk_1 EQU $C84B ; register 1 -;* $C84C ; register 0 -Vec_Freq_Table EQU $C84D ;Pointer to note-to-fr.EQUency table (normally 0xFC8D) -Vec_Max_Players EQU $C84F ;Maximum number of players for Select_Game -Vec_Max_Games EQU $C850 ;Maximum number of games for Select_Game -Vec_ADSR_Table EQU $C84F ;Storage for first music header word (ADSR table) -Vec_Twang_Table EQU $C851 ;Storage for second music header word ('twang' table) -Vec_Music_Ptr EQU $C853 ;Music data pointer -Vec_Expl_ChanA EQU $C853 ;Used by Explosion_Snd - bit for first channel used? -Vec_Expl_Chans EQU $C854 ;Used by Explosion_Snd - bits for all channels used? -Vec_Music_Chan EQU $C855 ;Current sound channel number for Init_Music -Vec_Music_Flag EQU $C856 ;Music active flag (0x00=off 0x01=start 0x80=on) -Vec_Duration EQU $C857 ;Duration counter for Init_Music -Vec_Music_Twang EQU $C858 ;3 word 'twang' table used by Init_Music -Vec_Expl_1 EQU $C858 ;Four bytes copied from Explosion_Snds U-reg parameters -Vec_Expl_2 EQU $C859 ; -Vec_Expl_3 EQU $C85A ; -Vec_Expl_4 EQU $C85B ; -Vec_Expl_Chan EQU $C85C ;Used by Explosion_Snd - channel number in use? -Vec_Expl_ChanB EQU $C85D ;Used by Explosion_Snd - bit for second channel used? -Vec_ADSR_Timers EQU $C85E ;ADSR timers for each sound channel (3 bytes) -Vec_Music_Freq EQU $C861 ;Storage for base fr.EQUency of each channel (3 words) -;* $C85E ;Scratch 'score' storage for Display_Option (7 bytes) -Vec_Expl_Flag EQU $C867 ;Explosion_Snd initialization flag? -;* $C868...0xC876 ;Unused? -Vec_Expl_Timer EQU $C877 ;Used by Explosion_Snd -;* $C878 ;Unused? -Vec_Num_Players EQU $C879 ;Number of players selected in Select_Game -Vec_Num_Game EQU $C87A ;Game number selected in Select_Game -Vec_Seed_Ptr EQU $C87B ;Pointer to 3-byte random number seed (=0xC87D) -Vec_Random_Seed EQU $C87D ;Default 3-byte random number seed - ; -;* $C880 - 0xCBEA is user RAM ; - ; -Vec_Default_Stk EQU $CBEA ;Default top-of-stack -Vec_High_Score EQU $CBEB ;High score storage (7 bytes) -Vec_SWI3_Vector EQU $CBF2 ;SWI2/SWI3 interrupt vector (3 bytes) -Vec_SWI2_Vector EQU $CBF2 ;SWI2/SWI3 interrupt vector (3 bytes) -Vec_FIRQ_Vector EQU $CBF5 ;FIRQ interrupt vector (3 bytes) -Vec_IRQ_Vector EQU $CBF8 ;IRQ interrupt vector (3 bytes) -Vec_SWI_Vector EQU $CBFB ;SWI/NMI interrupt vector (3 bytes) -Vec_NMI_Vector EQU $CBFB ;SWI/NMI interrupt vector (3 bytes) -Vec_Cold_Flag EQU $CBFE ;Cold start flag (warm start if = 0x7321) - ; -VIA_port_b EQU $D000 ;VIA port B data I/O register -;* 0 sample/hold (0=enable mux 1=disable mux) -;* 1 mux sel 0 -;* 2 mux sel 1 -;* 3 sound BC1 -;* 4 sound BDIR -;* 5 comparator input -;* 6 external device (slot pin 35) initialized to input -;* 7 /RAMP -VIA_port_a EQU $D001 ;VIA port A data I/O register (handshaking) -VIA_DDR_b EQU $D002 ;VIA port B data direction register (0=input 1=output) -VIA_DDR_a EQU $D003 ;VIA port A data direction register (0=input 1=output) -VIA_t1_cnt_lo EQU $D004 ;VIA timer 1 count register lo (scale factor) -VIA_t1_cnt_hi EQU $D005 ;VIA timer 1 count register hi -VIA_t1_lch_lo EQU $D006 ;VIA timer 1 latch register lo -VIA_t1_lch_hi EQU $D007 ;VIA timer 1 latch register hi -VIA_t2_lo EQU $D008 ;VIA timer 2 count/latch register lo (refresh) -VIA_t2_hi EQU $D009 ;VIA timer 2 count/latch register hi -VIA_shift_reg EQU $D00A ;VIA shift register -VIA_aux_cntl EQU $D00B ;VIA auxiliary control register -;* 0 PA latch enable -;* 1 PB latch enable -;* 2 \ 110=output to CB2 under control of phase 2 clock -;* 3 > shift register control (110 is the only mode used by the Vectrex ROM) -;* 4 / -;* 5 0=t2 one shot 1=t2 free running -;* 6 0=t1 one shot 1=t1 free running -;* 7 0=t1 disable PB7 output 1=t1 enable PB7 output -VIA_cntl EQU $D00C ;VIA control register -;* 0 CA1 control CA1 -> SW7 0=IRQ on low 1=IRQ on high -;* 1 \ -;* 2 > CA2 control CA2 -> /ZERO 110=low 111=high -;* 3 / -;* 4 CB1 control CB1 -> NC 0=IRQ on low 1=IRQ on high -;* 5 \ -;* 6 > CB2 control CB2 -> /BLANK 110=low 111=high -;* 7 / -VIA_int_flags EQU $D00D ;VIA interrupt flags register -;* bit cleared by -;* 0 CA2 interrupt flag reading or writing port A I/O -;* 1 CA1 interrupt flag reading or writing port A I/O -;* 2 shift register interrupt flag reading or writing shift register -;* 3 CB2 interrupt flag reading or writing port B I/O -;* 4 CB1 interrupt flag reading or writing port A I/O -;* 5 timer 2 interrupt flag read t2 low or write t2 high -;* 6 timer 1 interrupt flag read t1 count low or write t1 high -;* 7 IRQ status flag write logic 0 to IER or IFR bit -VIA_int_enable EQU $D00E ;VIA interrupt enable register -;* 0 CA2 interrupt enable -;* 1 CA1 interrupt enable -;* 2 shift register interrupt enable -;* 3 CB2 interrupt enable -;* 4 CB1 interrupt enable -;* 5 timer 2 interrupt enable -;* 6 timer 1 interrupt enable -;* 7 IER set/clear control -VIA_port_a_nohs EQU $D00F ;VIA port A data I/O register (no handshaking) - -Cold_Start EQU $F000 ; -Warm_Start EQU $F06C ; -Init_VIA EQU $F14C ; -Init_OS_RAM EQU $F164 ; -Init_OS EQU $F18B ; -Wait_Recal EQU $F192 ; -Set_Refresh EQU $F1A2 ; -DP_to_D0 EQU $F1AA ; -DP_to_C8 EQU $F1AF ; -Read_Btns_Mask EQU $F1B4 ; -Read_Btns EQU $F1BA ; -Joy_Analog EQU $F1F5 ; -Joy_Digital EQU $F1F8 ; -Sound_Byte EQU $F256 ; -Sound_Byte_x EQU $F259 ; -Sound_Byte_raw EQU $F25B ; -Clear_Sound EQU $F272 ; -Sound_Bytes EQU $F27D ; -Sound_Bytes_x EQU $F284 ; -Do_Sound EQU $F289 ; -Do_Sound_x EQU $F28C ; -Intensity_1F EQU $F29D ; -Intensity_3F EQU $F2A1 ; -Intensity_5F EQU $F2A5 ; -Intensity_7F EQU $F2A9 ; -Intensity_a EQU $F2AB ; -Dot_ix_b EQU $F2BE ; -Dot_ix EQU $F2C1 ; -Dot_d EQU $F2C3 ; -Dot_here EQU $F2C5 ; -Dot_List EQU $F2D5 ; -Dot_List_Reset EQU $F2DE ; -Recalibrate EQU $F2E6 ; -Moveto_x_7F EQU $F2F2 ; -Moveto_d_7F EQU $F2FC ; -Moveto_ix_FF EQU $F308 ; -Moveto_ix_7F EQU $F30C ; -Moveto_ix_b EQU $F30E ; Used to be named Moveto_ix_a but this is wrong. -Moveto_ix EQU $F310 ; -Moveto_d EQU $F312 ; -Reset0Ref_D0 EQU $F34A ; -Check0Ref EQU $F34F ; -Reset0Ref EQU $F354 ; -Reset_Pen EQU $F35B ; -Reset0Int EQU $F36B ; -Print_Str_hwyx EQU $F373 ; -Print_Str_yx EQU $F378 ; -Print_Str_d EQU $F37A ; -Print_List_hw EQU $F385 ; -Print_List EQU $F38A ; -Print_List_chk EQU $F38C ; -Print_Ships_x EQU $F391 ; -Print_Ships EQU $F393 ; -Mov_Draw_VLc_a EQU $F3AD ;count y x y x ... -Mov_Draw_VL_b EQU $F3B1 ;y x y x ... -Mov_Draw_VLcs EQU $F3B5 ;count scale y x y x ... -Mov_Draw_VL_ab EQU $F3B7 ;y x y x ... -Mov_Draw_VL_a EQU $F3B9 ;y x y x ... -Mov_Draw_VL EQU $F3BC ;y x y x ... -Mov_Draw_VL_d EQU $F3BE ;y x y x ... -Draw_VLc EQU $F3CE ;count y x y x ... -Draw_VL_b EQU $F3D2 ;y x y x ... -Draw_VLcs EQU $F3D6 ;count scale y x y x ... -Draw_VL_ab EQU $F3D8 ;y x y x ... -Draw_VL_a EQU $F3DA ;y x y x ... -Draw_VL EQU $F3DD ;y x y x ... -Draw_Line_d EQU $F3DF ;y x y x ... -Draw_VLp_FF EQU $F404 ;pattern y x pattern y x ... 0x01 -Draw_VLp_7F EQU $F408 ;pattern y x pattern y x ... 0x01 -Draw_VLp_scale EQU $F40C ;scale pattern y x pattern y x ... 0x01 -Draw_VLp_b EQU $F40E ;pattern y x pattern y x ... 0x01 -Draw_VLp EQU $F410 ;pattern y x pattern y x ... 0x01 -Draw_Pat_VL_a EQU $F434 ;y x y x ... -Draw_Pat_VL EQU $F437 ;y x y x ... -Draw_Pat_VL_d EQU $F439 ;y x y x ... -Draw_VL_mode EQU $F46E ;mode y x mode y x ... 0x01 -Print_Str EQU $F495 ; -Random_3 EQU $F511 ; -Random EQU $F517 ; -Init_Music_Buf EQU $F533 ; -Clear_x_b EQU $F53F ; -Clear_C8_RAM EQU $F542 ;never used by GCE carts? -Clear_x_256 EQU $F545 ; -Clear_x_d EQU $F548 ; -Clear_x_b_80 EQU $F550 ; -Clear_x_b_a EQU $F552 ; -Dec_3_Counters EQU $F55A ; -Dec_6_Counters EQU $F55E ; -Dec_Counters EQU $F563 ; -Delay_3 EQU $F56D ;30 cycles -Delay_2 EQU $F571 ;25 cycles -Delay_1 EQU $F575 ;20 cycles -Delay_0 EQU $F579 ;12 cycles -Delay_b EQU $F57A ;5*B + 10 cycles -Delay_RTS EQU $F57D ;5 cycles -Bitmask_a EQU $F57E ; -Abs_a_b EQU $F584 ; -Abs_b EQU $F58B ; -Rise_Run_Angle EQU $F593 ; -Get_Rise_Idx EQU $F5D9 ; -Get_Run_Idx EQU $F5DB ; -Get_Rise_Run EQU $F5EF ; -Rise_Run_X EQU $F5FF ; -Rise_Run_Y EQU $F601 ; -Rise_Run_Len EQU $F603 ; -Rot_VL_ab EQU $F610 ; -Rot_VL EQU $F616 ; -Rot_VL_Mode_a EQU $F61F ; -Rot_VL_Mode EQU $F62B ; -Rot_VL_dft EQU $F637 ; -Xform_Run_a EQU $F65B ; -Xform_Run EQU $F65D ; -Xform_Rise_a EQU $F661 ; -Xform_Rise EQU $F663 ; -Move_Mem_a_1 EQU $F67F ; -Move_Mem_a EQU $F683 ; -Init_Music_chk EQU $F687 ; -Init_Music EQU $F68D ; -Init_Music_x EQU $F692 ; -Select_Game EQU $F7A9 ; -Clear_Score EQU $F84F ; -Add_Score_a EQU $F85E ; -Add_Score_d EQU $F87C ; -Strip_Zeros EQU $F8B7 ; -Compare_Score EQU $F8C7 ; -New_High_Score EQU $F8D8 ; -Obj_Will_Hit_u EQU $F8E5 ; -Obj_Will_Hit EQU $F8F3 ; -Obj_Hit EQU $F8FF ; -Explosion_Snd EQU $F92E ; -Draw_Grid_VL EQU $FF9F ; - -Char_Table EQU $F9F4 ; Char_Table -Char_Table_End EQU $FBD4 ; Char_Table_End - -vx_music_1 EQU $FD0D ; Poweron music, crazy coaster and narrow escape -vx_music_2 EQU $FD1D ; Music for Berzerk -vx_music_3 EQU $FD81 -vx_music_4 EQU $FDD3 ; Music for Scramble -vx_music_5 EQU $FE38 ; Music for Solar Quest -vx_music_6 EQU $FE76 -vx_music_7 EQU $FEC6 -vx_music_8 EQU $FEF8 ; Music for Melody Master -vx_music_9 EQU $FF26 -vx_music_10 EQU $FF44 -vx_music_11 EQU $FF62 -vx_music_12 EQU $FF7A -vx_music_13 EQU $FF8F - -#endif /* defined(VECTREX) */ - -nop_handler: - RTS - - -* NOTE on _CMOC_NEED_*_ identifiers. -* Each C function declared in should be mentioned in the -* stdLibTable[] array of FunctionCallExpr::emitCode(). Then, its body -* in this file should be delimited by #ifdef _CMOC_NEED__. -* -* MUL16 however is not a C function. It is a utility function. Whenever -* a call to such a function is emitted, it should be emitted using -* callUtility(), and its body in this file should be delimited by -* #ifdef _CMOC_NEED__. Utility function names -* must NOT be mentioned in stdLibTable[]. -* -* Note the leading and trailing underscore character. -* -#ifdef _CMOC_NEED_MUL16_ - -* Multiply D by X, unsigned; return result in D; preserve X. -MUL16 PSHS U,X,B,A U pushed to create 2 temp bytes at 4,S - LDB 3,S low byte of original X - MUL - STD 4,S keep for later - LDD 1,S low byte of orig D, high byte of orig X - MUL - ADDB 5,S only low byte is needed - STB 5,S - LDA 1,S low byte of orig D - LDB 3,S low byte of orig X - MUL - ADDA 5,S - LEAS 6,S - RTS - -#endif /* _CMOC_NEED_MUL16_ */ - - -#ifdef _CMOC_NEED_mulww_ - -* Multiply D by X, unsigned; return 32-bit result in D (high 16 bits) -* and X (low 16 bits). -* -MUL168_TO32 - pshs x,b,a - clr ,-s allocate 4 bytes to store 24-bit product - clr ,-s - clr ,-s - clr ,-s - - lda 7,s low byte of X - mul mul by B - std 2,s low 16-bit of 32-bit storage - - ldd 5,s original B in A, high byte of X in B - mul - - addd 1,s add D to middle 16 bits of storage - pshs cc preserve carry - std 2,s store sum in middle 16 bits of storage - puls b - andb #1 carry from sum - stb ,s store carry in high byte of storage - - lda 4,s original A - ldb 7,s low byte of X - mul - addd 1,s add D to middle 16 bits of storage - pshs cc preserve carry - std 2,s store sum in middle 16 bits of storage - puls b - andb #1 carry from sum - addb ,s add carry to high byte of storage - stb ,s - - lda 4,s original A - ldb 6,s high byte of X - mul - addd ,s add D to high word of storage - std ,s drop carry - - ldx 2,s return low word of product in X - - leas 8,s - rts - - -* word mulww(word *productHi, word u, word v) -* -* Multiples u by v to obtain a 32-bit product. -* Stores the high word of the product in *productHi, -* and returns the low word of the product. -* -_mulww - pshs u - tfr s,u - - ldx 6,u load u - ldd 8,u load v - bsr MUL168_TO32 - pshs x preserve low word of product - ldx 4,u get productHi pointer - std ,x return high byte of product - puls a,b retrieve and return low word of product - - tfr u,s - puls u,pc - -#endif /* _CMOC_NEED_mulww_ */ - - -#ifdef _CMOC_NEED_mulwb_ - -* Multiply B by X, unsigned; return 24-bit result in B (high 8 bits) -* and X (low 16 bits). Register A preserved. -MUL168_TO24 - pshs x,b,a - clr ,-s allocate 3 bytes to store 24-bit product - clr ,-s - clr ,-s - - lda 6,s low byte of X - mul - std 1,s low 16-bit of 24-bit storage - - ldd 4,s original B in A, high byte of X in B - mul - - addd ,s add D to high 16 bits of storage - std ,s - - ldb ,s - ldx 1,s - - lda 3,s restore orignal A - leas 7,s - rts - - -* word mulwb(byte *productHi, word w, byte b) -* -* Multiples w by b to obtain a 24-bit product. -* Stores the high byte of the product in *productHi, -* and returns the low word of the product. -* -_mulwb - pshs u - tfr s,u - - ldx 6,u load w - ldb 9,u load b - bsr MUL168_TO24 - pshs x preserve low word of product - ldx 4,u get productHi pointer - stb ,x return high byte of product - puls a,b retrieve and return low word of product - - tfr u,s - puls u,pc - -#endif /* _CMOC_NEED_mulwb_ */ - - -#ifdef _CMOC_NEED_zerodw_ - -* void zerodw(word *dw) -* -_zerodw - ldx 2,s load dw to point to double word - clra - clrb - std ,x - std 2,x - rts - -#endif /* _CMOC_NEED_zerodw_ */ - - -#ifdef _CMOC_NEED_adddww_ - -* void adddww(word *dw, word w) -* -_adddww - ldx 2,s load dw to point to double word - ldd 2,x low word of dword - addd 4,s add w: affects carry flag - std 2,x store low word of result (does not affect carry flag) - ldd ,x load high word of dword (does not affect carry flag) - adcb #0 add possible carry from add of low word with w - adca #0 add possible carry from adcb - std ,x - rts - -#endif /* _CMOC_NEED_adddww_ */ - - -#ifdef _CMOC_NEED_subdww_ - -* void subdww(word *dw, word w) -* -_subdww - ldx 2,s load dw to point to double word - ldd 2,x low word of dword - subd 4,s sub w: affects carry flag - std 2,x store low word of result (does not affect carry flag) - ldd ,x load high word of dword (does not affect carry flag) - sbcb #0 sub possible borrow from subd - sbca #0 sub possible borrow from sbcb - std ,x - rts - -#endif /* _CMOC_NEED_subdww_ */ - - -#ifdef _CMOC_NEED_SDIV16_ - -* Divide X by D, signed; return quotient in X, remainder in D. -* Non-zero remainder is negative iff dividend is negative. -SDIV16 PSHS X,B,A - CLR ,-S counter: number of negative arguments (0..2) - CLR ,-S boolean: was dividend negative? - TSTA is divisor negative? - BGE SDIV16_10 if not - INC 1,S - COMA negate divisor - COMB - ADDD #1 - STD 2,S -SDIV16_10 - LDD 4,S is dividend negative? - BGE SDIV16_20 if not - INC ,S - INC 1,S - COMA negate dividend - COMB - ADDD #1 - STD 4,S -SDIV16_20 - LDD 2,S reload divisor - LDX 4,S reload dividend - LBSR DIV16 - -* Counter is 0, 1 or 2. Quotient negative if counter is 1. - LSR 1,S check bit 0 of counter (1 -> negative quotient) - BCC SDIV16_30 quotient not negative - EXG X,D put quotient in D and remainder in X - COMA negate quotient - COMB - ADDD #1 - EXG X,D return quotient and remainder in X and D - -SDIV16_30 -* Negate the remainder if the dividend was negative. - TST ,S was dividend negative? - BEQ SDIV16_40 if not - COMA negate remainder - COMB - ADDD #1 -SDIV16_40 - LEAS 6,S - RTS - -#endif /* _CMOC_NEED_SDIV16_ */ - - -#if defined(_CMOC_NEED_DIV16_) || defined(_CMOC_NEED_SDIV16_) - -* Divide X by D, unsigned; return quotient in X, remainder in D. -DIV16 PSHS X,B,A - LDB #16 - PSHS B - CLRA - CLRB - PSHS B,A -* 0,S=16-bit quotient; 2,S=loop counter; -* 3,S=16-bit divisor; 5,S=16-bit dividend - -D16010 LSL 6,S shift MSB of dividend into carry - ROL 5,S shift carry and MSB of dividend, into carry - ROLB new bit of dividend now in bit 0 of B - ROLA - CMPD 3,S does the divisor "fit" into D? - BLO D16020 if not - SUBD 3,S - ORCC #1 set carry - BRA D16030 -D16020 ANDCC #$FE reset carry -D16030 ROL 1,S shift carry into quotient - ROL ,S - - DEC 2,S another bit of the dividend to process? - BNE D16010 if yes - - PULS X quotient to return - LEAS 5,S - RTS - -#endif /* defined(_CMOC_NEED_DIV16_) || defined(_CMOC_NEED_SDIV16_) */ - - -#ifdef _CMOC_NEED_SDIV8_ - -* Divide A by B, signed; return quotient in B, remainder in A. -* Non-zero remainder is negative iff dividend is negative. -* Does not preserve X. -SDIV8 - CLR ,-S counter: number of negative arguments (0..2) - CLR ,-S boolean: was dividend negative? - TSTB is divisor negative? - BGE SDIV8_10 if not - INC 1,S increment counter of negative arguments - NEGB negate divisor -SDIV8_10 - TSTA is dividend negative? - BGE SDIV8_20 if not - INC ,S remember that dividend was negative - INC 1,S increment counter of negative arguments - NEGA negate dividend -SDIV8_20 - LBSR DIV8 - -* Counter is 0, 1 or 2. Quotient negative if counter is 1. - LSR 1,S check bit 0 of counter (1 -> negative quotient) - BCC SDIV8_30 quotient not negative - NEGB negate quotient - -SDIV8_30 -* Negate the remainder if the dividend was negative. - TST ,S was dividend negative? - BEQ SDIV8_40 if not - NEGA negate remainder -SDIV8_40 - LEAS 2,S - RTS - -#endif /* _CMOC_NEED_SDIV8_ */ - - -#if defined(_CMOC_NEED_DIV8_) || defined(_CMOC_NEED_SDIV8_) - -* Divide A by B, unsigned; return quotient in B, remainder in A. -* Does not preserve X. -DIV8 PSHS A push dividend - PSHS B push divisor - LDA #8 loop counter - CLRB - PSHS B -* 0,S=8-bit quotient; -* 1,S=8-bit divisor; 2,S=8-bit dividend - -DV8010 LSL 2,S shift dividend into carry - ROLB new bit of dividend now in bit 0 of B - CMPB 1,S does the divisor "fit" into B? - BLO DV8020 if not - SUBB 1,S - ORCC #1 set carry - BRA DV8030 -DV8020 ANDCC #$FE reset carry -DV8030 ROL ,S shift carry into quotient - - DECA another bit of the dividend to process? - BNE DV8010 if yes - - TFR B,A remainder to return - PULS B quotient to return - LEAS 2,S - RTS - -#endif /* defined(_CMOC_NEED_DIV8_) || defined(_CMOC_NEED_SDIV8_) */ - - -#ifdef _CMOC_NEED_DIV8BY7_ - -* Unsigned division by seven -* Input: an unsigned byte (0..255) in A -* Output: Computes A/7 -* quotient (0..36) in B -* remainder (0..6) in A -* Using (8a+b)/7 = a + (a+b)/7 -* where a = higher five bits and b = lower three bits -* Source: DIVIDE7 on http://mirrors.apple2.org.za/ground.icaen.uiowa.edu/MiscInfo/Programming/div7 -* -DIV8BY7 - TFR A,B - ANDA #7 - PSHS A low bits (b) - TFR B,A - LSRA - LSRA - LSRA - TFR A,B high bits, divided by 8 (a) - ANDCC #$FE clear carry - ADCA ,S+ a + b. here we know carry is low. -DIV8BY7_010: - INCB the loop is executed between 1 and 6 times - SBCA #7 since A is at most 38 - BCC DIV8BY7_010 - ADDA #7 - DECB - RTS -PAUL EQU 12 - -#endif /* _CMOC_NEED_DIV8BY7_ */ - - -#ifdef _CMOC_NEED_DIV16BY10_ - -* Divide D by 10. -* Quotient left in D. -* Does not preserve X. -* Source: Hacker's Delight (Addison-Wesley, 2003, 2012) -* http://www.hackersdelight.org/divcMore.pdf -* -DIV16BY10 - TFR D,X save n - LSRA - RORB D = n >> 1 - PSHS B,A q := ,S (word) - LSRA - RORB D = n >> 2 - ADDD ,S - STD ,S q = (n >> 1) + (n >> 2) - LSRA - RORB - LSRA - RORB - LSRA - RORB - LSRA - RORB - ADDD ,S - STD ,S D = q + (q >> 4) - TFR A,B - CLRA q >> 8 - ADDD ,S - LSRA - RORB - LSRA - RORB - LSRA - RORB q >> 3 - STD ,S - LSLB - ROLA - LSLB - ROLA q << 2 - ADDD ,S - LSLB - ROLA - PSHS B,A - TFR X,D D = n - SUBD ,S++ D = r - CMPD #9 r > 9 ? - BLS DIV16BY10_010 - LDB #1 - BRA DIV16BY10_020 -DIV16BY10_010 - CLRB -DIV16BY10_020 - LDA ,S - ADDB 1,S - ADCA #0 - PULS X,PC discard q and return D - -#endif /* _CMOC_NEED_DIV16BY10_ */ - - -#ifdef _CMOC_NEED_divdwb_ - -* void divdwb(unsigned dividend[2], unsigned char divisor) -* -* Writes quotient into dividend[0..1]. -* Does nothing if divisor is zero. -* -_divdwb -_div328 - pshs u - tfr s,u - - tst 7,u load divisor - beq div328_900 division by zero: do nothing - - clra push 32-bit zero - clrb - pshs b,a - pshs b,a -4,u will be 32-bit quotient - - ldx 4,u X points to 4-byte dividend - - ldb #32 one iteration per bit in the dividend - pshs b -5,u is loop counter - - clra dividend will be shifted left into D - clrb (only low 9 bits are significant) - -div328_loop - lsl 3,x shift dividend left - rol 2,x - rol 1,x - rol ,x MSB of dividend now in carry - rolb - rola - cmpd 6,u does divisor fit into D? - blo div328_nofit if not - - subd 6,u sub 8-bit divisor from 9-bit accumulator - orcc #1 set carry - bra div328_rolq - -div328_nofit - andcc #$fe reset carry - -div328_rolq - rol -1,u shift carry into quotient - rol -2,u - rol -3,u - rol -4,u - - dec -5,u dec loop counter - bne div328_loop - -* Copy quotient into dividend space. - ldd -4,u - std ,x - ldd -2,u - std 2,x - -div328_900 - tfr u,s - puls u,pc - -#endif /* _CMOC_NEED_div328_ */ - - -#if defined(_CMOC_NEED_divdww_) - -* void divdww(unsigned dividend[2], unsigned divisor) -* -* Writes quotient into dividend[0..1]. -* Does nothing if divisor is zero. -* -_divdww -_div3216 - pshs u - tfr s,u - - ldd 6,u load divisor - beq div3216_900 division by zero: do nothing - - clra push 32-bit zero - clrb - pshs b,a - pshs b,a -4,u will be 32-bit quotient - - ldx 4,u X points to 4-byte dividend - - ldb #32 one iteration per bit in the dividend - pshs b -5,u is loop counter - -* Dividend will be shifted left into a 17-bit accumulator. -* The low 16 bits are in D, and the low bit of -6,u is bit 16. -* Bits 1..7 of -6,u are ignored. - clra - clrb - clr ,-s -6,u - -div3216_loop - lsl 3,x shift dividend left - rol 2,x - rol 1,x - rol ,x MSB of dividend now in carry - rolb - rola - rol -6,u 17th bit of accumulator - bsr div3216_tryfit does divisor fit into accumulator? - blo div3216_nofit if not - - bsr div3216_sub substract divisor from accumulator - orcc #1 set carry - bra div3216_rolq - -div3216_nofit - andcc #$fe reset carry - -div3216_rolq - rol -1,u shift carry into quotient - rol -2,u - rol -3,u - rol -4,u - - dec -5,u dec loop counter - bne div3216_loop - -* Copy quotient into dividend space. - ldd -4,u - std ,x - ldd -2,u - std 2,x - -div3216_900 - tfr u,s - puls u,pc - -* Determines if divisor fits into accumulator. -* Input: -* 6,u = 16-bit divisor -* -6,u and D = 17-bit accumulator -* Output: -* C = 0 iff divisor fits into accumulator. -* Preserves all registers. -div3216_tryfit - pshs b - ldb -6,u bit 16 of acc - andb #1 - bne @fit bit 16 high, so acc > divisor - puls b -* Acc is just D, so compare directly with divisor. - cmpd 6,u - rts -@fit - andcc #0 return C = 0 - puls b,pc - -* Subtracts divisor from accumulator. -* Assumes result NOT negative. -* Same interface as div3216_tryfit. -div3216_sub - subd 6,u - bcc @noBorrow - dec -6,u bit 16, assumed to 1, becomes 0 -@noBorrow - rts - -#endif /* _CMOC_NEED_div3216_ */ - - -#ifdef _CMOC_NEED_shiftLeft_ - -* Shifts the 16-bit value on the stack left by -* a number of bits given in D. -* Result left in D. -* CAUTION: Trashes X and pops the 16-bit value off the stack. -* -shiftLeft - addd #0 any shift to do? - beq shiftLeft_no_change - - cmpd #16 shifting all bits out? - blo shiftLeft_general if not - -* Shifting >= 16 bits out. - clra - clrb - bra shiftLeft_end - -shiftLeft_no_change - ldd 2,s return left side of shift operator as is - bra shiftLeft_end - -shiftLeft_general - pshs b save number of bits to shift - ldd 3,s get left side of shift operator -shiftLeft_loop - lslb - rola - dec ,s - bne shiftLeft_loop - leas 1,s discard counter -shiftLeft_end - puls x pop return value - leas 2,s pop left side - tfr x,pc return from routine (with result in D) - -#endif /* _CMOC_NEED_shiftLeft_ */ - - -#ifdef _CMOC_NEED_shiftByteLeft_ - -* Shifts the 8-bit value on the stack left by -* a number of bits given in D. -* Result left in B. -* CAUTION: Trashes X and pops the 8-bit value off the stack. -* -shiftByteLeft - addd #0 any shift to do? - beq shiftByteLeft_no_change - - cmpd #8 shifting all bits out? - blo shiftByteLeft_general if not - -* Shifting >= 8 bits out. - clrb - bra shiftByteLeft_end - -shiftByteLeft_no_change - ldb 2,s return left side of shift operator as is - bra shiftByteLeft_end - -shiftByteLeft_general - tfr b,a use A for number of bits to shift - ldb 2,s get left side of shift operator -shiftByteLeft_loop - lslb - deca - bne shiftByteLeft_loop -shiftByteLeft_end - puls x pop return value - leas 1,s pop left side - tfr x,pc return from routine (with result in D) - -#endif /* _CMOC_NEED_shiftByteLeft_ */ - - -#ifdef _CMOC_NEED_shiftRightUnsigned_ - -* Shifts the 16-bit unsigned value on the stack right -* by a number of bits given in D. -* Result left in D. -* CAUTION: Trashes X and pops the 16-bit value off the stack. -* -shiftRightUnsigned - addd #0 any shift to do? - beq shiftRightUnsigned_no_change - - cmpd #16 shifting all bits out? - blo shiftRightUnsigned_general if not - -* Shifting >= 16 bits out. - clra - clrb - bra shiftRightUnsigned_end - -shiftRightUnsigned_no_change - ldd 2,s return left side of shift operator as is - bra shiftRightUnsigned_end - -shiftRightUnsigned_general - pshs b save number of bits to shift - ldd 3,s get left side of shift operator -shiftRightUnsigned_loop - lsra - rorb - dec ,s - bne shiftRightUnsigned_loop - leas 1,s discard counter -shiftRightUnsigned_end - puls x pop return value - leas 2,s pop left side - tfr x,pc return from routine (with result in D) - -#endif /* _CMOC_NEED_shiftRightUnsigned_ */ - - -#ifdef _CMOC_NEED_shiftByteRightUnsigned_ - -* Shifts the 8-bit unsigned value on the stack right -* by a number of bits given in D. -* Result left in B. -* CAUTION: Trashes X and pops the 8-bit value off the stack. -* -shiftByteRightUnsigned - addd #0 any shift to do? - beq shiftByteRightUnsigned_no_change - - cmpd #16 shifting all bits out? - blo shiftByteRightUnsigned_general if not - -* Shifting >= 16 bits out. - clrb - bra shiftByteRightUnsigned_end - -shiftByteRightUnsigned_no_change - ldb 2,s return left side of shift operator as is - bra shiftByteRightUnsigned_end - -shiftByteRightUnsigned_general - tfr b,a use A for number of bits to shift - ldb 2,s get left side of shift operator -shiftByteRightUnsigned_loop - lsrb - deca - bne shiftByteRightUnsigned_loop -shiftByteRightUnsigned_end - puls x pop return value - leas 1,s pop left side - tfr x,pc return from routine (with result in D) - -#endif /* _CMOC_NEED_shiftByteRightUnsigned_ */ - - -#ifdef _CMOC_NEED_shiftRightSigned_ - -* Shifts the 16-bit signed value on the stack right -* by a number of bits given in D. -* Result left in D. -* CAUTION: Trashes X and pops the 16-bit value off the stack. -* -shiftRightSigned - addd #0 any shift to do? - beq shiftRightSigned_no_change - - cmpd #15 shifting all mantissa bits out? - blo shiftRightSigned_general if not - -* Shifting >= 15 bits out. - ldd 2,s left side of shift operator - tfr a,b sign bit of D into bit 7 of B - sex repeat bit 7 of B eight times in A - tfr a,b D = $FFFF if original D < 0; D = 0 otherwise - bra shiftRightSigned_end - -shiftRightSigned_no_change - ldd 2,s return left side of shift operator as is - bra shiftRightSigned_end - -shiftRightSigned_general - pshs b save number of bits to shift - ldd 3,s get right side of shift operator -shiftRightSigned_loop - asra - rorb - dec ,s - bne shiftRightSigned_loop - leas 1,s discard counter -shiftRightSigned_end - puls x pop return value - leas 2,s pop left side - tfr x,pc return from routine (with result in D) - -#endif /* _CMOC_NEED_shiftRightSigned_ */ - - -#ifdef _CMOC_NEED_shiftByteRightSigned_ - -* Shifts the 8-bit signed value on the stack right -* by a number of bits given in D. -* Result left in B. -* CAUTION: Trashes X and pops the 8-bit value off the stack. -* -shiftByteRightSigned - addd #0 any shift to do? - beq shiftByteRightSigned_no_change - - cmpd #7 shifting all mantissa bits out? - blo shiftByteRightSigned_general if not - -* Shifting >= 7 bits out. - ldb 2,s left side of shift operator - sex repeat bit 7 of B eight times in A - tfr a,b B = $FF if original D < 0; B = 0 otherwise - bra shiftByteRightSigned_end - -shiftByteRightSigned_no_change - ldb 2,s return left side of shift operator as is - bra shiftByteRightSigned_end - -shiftByteRightSigned_general - tfr b,a use A for number of bits to shift - ldb 2,s get right side of shift operator -shiftByteRightSigned_loop - asrb - deca - bne shiftByteRightSigned_loop -shiftByteRightSigned_end - puls x pop return value - leas 1,s pop left side - tfr x,pc return from routine (with result in D) - -#endif /* _CMOC_NEED_shiftByteRightSigned_ */ - - -#ifdef _CMOC_NEED_cmpdww_ - -* char cmpdww(unsigned left[2], unsigned right) -* -_cmpdww - ldx 2,s left - ldd ,x high word of left - bne @leftGreater - ldd 2,x low word of left - cmpd 4,s compare with right - bhi @leftGreater - blo @leftSmaller - clrb left == right - rts -@leftSmaller - ldb #-1 left < right - rts -@leftGreater - ldb #1 left > right - rts - -#endif /* _CMOC_NEED_cmpdww_ */ - - -#ifdef _CMOC_NEED_setConsoleOutHook_ - -* void *setConsoleOutHook(void *routine) -* -_setConsoleOutHook - ldd CHROUT,pcr ; to be returned - ldx 2,s ; 1st argument: 'routine' - stx CHROUT,pcr - rts - -#endif /* _CMOC_NEED_setConsoleOutHook_ */ - - -#if defined(_CMOC_NEED_putchar_) - -* void putchar(byte c) -* -* Converts LF ($0A) into CR ($0D) before calling CHROUT. -* -_putchar - lda 3,s - -#endif - -#if defined(_CMOC_NEED_putchar_) \ - || defined(_CMOC_NEED_putstr_) \ - || defined(_CMOC_NEED_sprintf_) \ - || defined(_CMOC_NEED_printf_) - -* putchar_a should be called by the other routines (printf, etc.) -* whenever the character to be printed might be a newline. -* -putchar_a - -#ifdef _COCO_BASIC_ /* Only Color Basic expects CR for newline; others expect LF. */ - cmpa #10 C linefeed? - bne putchar_010 - lda #13 CHROUT does newline on char 13 -putchar_010: -#endif - jmp [CHROUT,DAT] - -#endif /* _CMOC_NEED_putchar_ */ - - -#ifdef _CMOC_NEED_putstr_ - -* void putstr(byte *s, word len) -* -* Sends characters s[0] to s[len - 1] to standard output. -* -_putstr -putstr: - pshs u - ldx 6,s number of characters to write - beq putstr_900 - ldu 4,s address of string to write -putstr_100: - lda ,u+ - lbsr putchar_a - leax -1,x - bne putstr_100 -putstr_900: - puls u,pc - -#endif /* _CMOC_NEED_putstr_ */ - - -#ifdef _CMOC_NEED_sprintf_ - -* Writes register A at the address given by chrtomem_writer, -* which gets incremented by 1. Used by _sprintf. -* -chrtomem: - pshs x - ldx chrtomem_writer,DAT - sta ,x+ - stx chrtomem_writer,DAT - puls x,pc - - -_sprintf - ldx CHROUT,DAT - stx sprintf_oldCHROUT,DAT preserve initial output routine address - leax chrtomem,pcr install chrtomem as destination of printf() - stx CHROUT,DAT - - ldx ,s++ remove return address in caller of sprintf() - stx sprintf_retaddr,DAT preserve it - - ldx ,s++ remove destination buffer - stx chrtomem_writer,DAT make chrtomem write to destination buffer - - lbsr _printf print into destination buffer via chrtomem - - clr [chrtomem_writer,DAT] terminate resulting string - - ldx sprintf_oldCHROUT,DAT restore initial output routine address - stx CHROUT,DAT - - leas -2,s restore stack slot for destination buffer pointer - - jmp [sprintf_retaddr,DAT] return to caller of sprintf() - -#endif /* _CMOC_NEED_sprintf_ */ - - -#if defined(_CMOC_NEED_printf_) || defined(_CMOC_NEED_sprintf_) - -PRINTF_FLOAT_SIZE EQU 5 size of a %f argument - -* void printf(const char *fmt, ...) -* -* Minimal printf(3) function. -* To redirect the output characters, store a routine pointer in CHROUT. -* That routine must accept the character to print in register A. -* -_printf - PSHS U - LDX 4,S format string - LEAU 6,S variable argument pointer - LDA #$20 default padding char - PSHS A - CLR ,-S - CLR ,-S -* ,S = width parameter (word) (as in "%12u"). -* 2,S = current padding char (byte) - -PTF010 LDA ,X+ get char from format string - LBEQ PTF900 - CMPA #$25 '%'? - BEQ PTF490 -PTF020 LBSR putchar_a ordinary char: print it - BRA PTF010 - -PTF490 * '%' just seen - CLR ,S clear width word - CLR 1,S - LDA #$20 - STA 2,S reinit padding char - -PTF500 * process chars that follow '%' - LDA ,X+ get char after '%' - BNE PTF510 - LDA #$25 string ends after '%', so print '%' - JSR [CHROUT,DAT] - LBRA PTF900 -PTF510 CMPA #$75 %u? - BNE PTF515 - LDD ,U++ get 16-bit argument - LBSR PADWRD width is in ,S, padding char in 2,S - LBSR PRNTWD print as decimal - BRA PTF010 -PTF515 CMPA #$64 %d? - BNE PTF520 - LDD ,U get number to print - BGE PTF517 - COMA negate D - COMB - ADDD #1 - PSHS B,A - LDD 2,S subtract 1 one width, because number to print is < 0 - SUBD #1 - STD 2,S - PULS A,B -PTF517 - LBSR PADWRD 16-bit width is in ,S, padding char in 2,S - - PSHS B,A if number to print < 0, print minus sign - LDD ,U++ reload number to print, advance arg pointer - BGE PTF518 - LDA #45 minus sign - JSR [CHROUT,DAT] -PTF518 - PULS A,B restore absolute value of number to print - - LBSR PRNTWD print as decimal - BRA PTF010 -PTF520 CMPA #$78 %x? - BNE PTF525 -PTF522 LDD ,U++ get 16-bit argument - LBSR PADHEX 16-bit width is in ,S, padding char in 2,S - LBSR PRNTWH print as hex - BRA PTF010 -PTF525 CMPA #$58 %X? - BEQ PTF522 - CMPA #$70 %p? - BNE PTF530 - LDA #$24 prefix pointer representation with $ - JSR [CHROUT,DAT] - LDD #4 always 4 hex digits for a pointer - STD ,S - LDA #$30 pad pointer with '0' - STA 2,S - BRA PTF522 do %X - -PTF530 CMPA #$73 %s? - BNE PTF540 - - LDD ,S width of the string field - BLT PTF532 if post-padding requested (signed branch) - - LDD ,U get address of string - LBSR PADSTR_PRE -PTF532 - LDD ,U get address of string - LBSR PRINTS - - LDD ,S width of the string field - BPL PTF538 if pre-padding requested: it's done, we're finished with %s - - LDD ,U reload address of string - LBSR PADSTR_POST do post-padding -PTF538 - LEAU 2,U pass string address argument - LBRA PTF010 finished with %s - -PTF540 CMPA #$63 %c? - BNE PTF550 - LDD ,U++ get char in B - TFR B,A - LBSR putchar_a - LBRA PTF010 -PTF550 CMPA #$66 %f? - BNE PTF555 - LBSR printReal - LEAU PRINTF_FLOAT_SIZE,U pass the float - LBRA PTF010 -PTF555 CMPA #'l %lu, %ld or %lx? - LBNE PTF559 - LDA ,X+ check letter that follows %l - CMPA #'u - BEQ @ulong - CMPA #'d - BEQ @slong - CMPA #'x - LBEQ @xlong - CMPA #'X - LBEQ @xlong - LEAX -1,X neither: tolerate %l as alias for %ld - CLRA indicates that no minus sign must be printed -@slong -* If the (big endian) dword at ,U is negative, negate it and -* print a minus sign. - TST ,U - BPL @longNotNeg - EXG U,X - LBSR negateDWord - EXG U,X - LDA #'- -@longNotNeg -@ulong -* -* Here, A is '-' iff a minus sign must be printed before the number. -* Also, 16-bit width is in ,S, padding char in 2,S -* -* Call dwtoa(). - PSHS X,A X trashed by _dwtoa, A indicates if minus sign needed - LEAS -11,S buffer for dwtoa - LDD ,U high word - LDX 2,U low word - PSHS X,B,A pushes 4 bytes for _dwtoa - LEAX 4,S point to 11-byte buffer - PSHS X pass address to _dwtoa - LBSR _dwtoa - LEAS 6,S discard arguments - TFR D,X point to first digit to print -* Here, 16-bit width is in 14,S, padding char in 16,S, minus sign indicator in 11,S -* -* Print minus sign BEFORE padding IF padding char is NOT space. - LDA 16,S padding char - CMPA #$20 is space? - BEQ @checkPadding - LDA 11,S load minus sign indicator - CMPA #'- - BNE @checkPadding no minus sign to print - LDA #'- - JSR [CHROUT,DAT] print it -* -@checkPadding -* - LBSR @decPadding -* -* Print minus sign AFTER padding IF padding char is space. - LDA 16,S padding char - CMPA #$20 is space? - BNE @printCond - LDA 11,S load minus sign indicator - CMPA #'- - BNE @printCond no minus sign to print - LDA #'- - JSR [CHROUT,DAT] print it - BRA @printCond -* -@printLoop - JSR [CHROUT,DAT] print it -@printCond - LDA ,X+ load digit - BNE @printLoop if not '\0' - LEAS 11,S discard buffer - PULS A,X restore X (points into printf format string) - LEAU 4,U pass the 32-bit long - LBRA PTF010 -; -; -; Input: U => dword to be printed in hex. -; Output: D => number of hex digits needed to print dword (1..8). -; Preserves X and U. -; -@countHexDigitsInDWord - CLRB -@nextDWordByte - LDA B,U get byte from dword - BNE @nonNullByte found 1st non-null byte - INCB count another null byte - CMPB #4 if reached 4, all bytes null - BEQ @oneDigitNeeded - BRA @nextDWordByte -@nonNullByte ; B is index (0..3) of 1st non null byte - LSLB - NEGB - ADDB #8 number of digits needed is B or B-1 - BITA #$F0 is high nybble null? - BNE @highNybbleNotNull - DECB one less digit needed -@highNybbleNotNull - CLRA - RTS -@oneDigitNeeded - LDB #1 A is already 0 -@done - RTS -; -; -@xlong -; Pad if required. -* Here, 16-bit width is in ,S, padding char in 2,S - BSR @countHexDigitsInDWord uses U; result in D - SUBD ,S subtract width - BHS @noHexPadding - PSHS X - TFR D,X use X as upwards counter -@hexPad - LDA 4,S padding char - JSR [CHROUT,DAT] - LEAX 1,X - BNE @hexPad - PULS X -@noHexPadding - LDD ,U high word - BEQ @highWordZero if no digit to print - LBSR PRNTWH print high word -; Print low word, padded with zeroes to a width of 4. - LDB #'0 padding char for PADHEX - PSHS B - LDD #4 print 2nd word as 4 digits - PSHS B,A pass to PADHEX - LDD 2,U low word - LBSR PADHEX preserves D and X - LEAS 3,S -@highWordZero - LDD 2,U low word - LBSR PRNTWH print D (low word) - LEAU 4,U pass the 32-bit long - LBRA PTF010 done with %lx -; -; Input: S (before call) => 11-digit buffer; -; X => first digit to print in the 11-digit buffer; -; 16-bit width is in 14,S, padding char in 16,S, minus sign indicator in 11,S. -; Preserves X. Trashes D. -; -@decPadding - PSHS X -; Here, 16-bit width is in 18,S, padding char in 20,S, minus sign indicator in 15,S. - TFR S,D - ADDD #2+2+10 addr of NUL-terminating byte of buffer (written by _dwtoa) - PSHS X - SUBD ,S++ D minus addr of 1st digit to print = # of digits to print - PSHS A - LDA 16,S get minus sign indicator - CMPA #'- minus needed? - PULS A - BNE @noMinusNeeded - ADDD #1 count minus as 1 more char to print -@noMinusNeeded - SUBD 18,S compare with width; negative result means padding needed - BHS @noPadding if width matched or exceeded, no padding - TFR D,X use X as upwards counter (must reach up to 0) -@decPadPrint - LDA 20,S padding char - JSR [CHROUT,DAT] - LEAX 1,X - BNE @decPadPrint -@noPadding - PULS X,PC - -PTF559 CMPA #$25 %%? - BNE PTF560 - JSR [CHROUT,DAT] - LBRA PTF010 -PTF560 CMPA #45 minus? *** CAUTION: ONLY SUPPORTED FOR STRING PADDING *** - BNE PTF562 - - LBSR ATOW read integer following minus sign into D - PSHS B,A negate D - CLRA - CLRB - SUBD ,S++ - STD ,S store negative width - LBRA PTF500 continue to process the chars following the % - -PTF562 CMPA #$30 width? - BLO PTF570 - CMPA #$39 - BHI PTF570 - CMPA #$30 zero? - BNE PTF565 - STA 2,S exception: this zero specifies the padding char - BRA PTF567 -PTF565 LEAX -1,X -PTF567 LBSR ATOW - STD ,S - LBRA PTF500 continue to process the chars following the % -PTF570 EQU * -PTF800 PSHS A unknown code after '%': print '%' then the code - LDA #$25 - JSR [CHROUT,DAT] - PULS A - LBSR putchar_a - LBRA PTF010 - -PTF900 LEAS 3,S - PULS U,PC - - -* Input: D = word to write in decimal. -PADWRD PSHS X,B,A - LDX 6,S width of the number - LEAX -5,X assume word in D has 5 decimal digits - CMPD #10 - BHS PWD020 - LEAX 1,X D < 10, so add one padding char -PWD020 CMPD #100 - BHS PWD030 - LEAX 1,X -PWD030 CMPD #1000 - BHS PWD040 - LEAX 1,X -PWD040 CMPD #10000 - BHS PWD050 - LEAX 1,X - -PWD050 CMPX #0 - BLE PWD900 no padding if X negative or zero -PWD060 LDA 8,S get padding char - JSR [CHROUT,DAT] - LEAX -1,X - BNE PWD060 - -PWD900 CLR 6,S clear width for next time - CLR 7,S - LDA #$20 restore default padding char for next time - STA 8,S - PULS A,B,X,PC - - -* Input: D = address of string to write -PADSTR_PRE - PSHS X,B,A - PSHS B,A send string address to _strlen - LBSR _strlen get length of string - STD ,S reuse arg slot to store length - LDD 8,S width of the string field - SUBD ,S substract string length; D = number of padding chars - BLE PADSTR_900 if nothing to do -PADSTR_050 - TFR D,X use X as padding counter -PADSTR_100 - LDA #32 use space as padding char - JSR [CHROUT,DAT] - LEAX -1,X - BNE PADSTR_100 -PADSTR_900 - LEAS 2,S pop arg slot - PULS A,B,X,PC - -* Input: D = address of string to write -PADSTR_POST - PSHS X,B,A - PSHS B,A send string address to _strlen - LBSR _strlen get length of string - STD ,S save length - CLRA - CLRB - SUBD 8,S negated field width, which is now > 0 - SUBD ,S subtract number of printed chars - BLS PADSTR_900 if nothing to do - BRA PADSTR_050 /* reuse previous subroutine's padding loop */ - - -* Input: D = number to write. -* Before call, ,S must contain 16-bit width in chars -* and 2,S must contain padding char. -* -PADHEX PSHS X,B,A - LDX 6,S width of the number - LEAX -4,X assume word in D has 4 hex digits - CMPD #$10 - BHS PHX020 - LEAX 1,X D < 16, so add one padding char -PHX020 CMPD #$100 - BHS PHX030 - LEAX 1,X -PHX030 CMPD #$1000 - BHS PHX050 - LEAX 1,X -PHX050 CMPX #0 - BLE PHX900 no padding if X negative or zero -PHX060 LDA 8,S get padding char - JSR [CHROUT,DAT] note that this may trash A - LEAX -1,X - BNE PHX060 - -PHX900 CLR 6,S clear width for next time - CLR 7,S - LDA #$20 restore default padding char for next time - STA 8,S - PULS A,B,X,PC - - -; Prints D in hex. -; Preserves D and X. -; Uses HEXDIG. -; -PRNTWH PSHS X,B,A - SUBD #0 handle special case - BNE PRWH10 - LDA #'0 - JSR [CHROUT,DAT] - BRA PRWH99 -PRWH10 CLR ,-S create 4-character buffer for 4 hex digits - CLR ,-S - CLR ,-S - CLR ,-S - LEAX HEXDIG,PCR - LSRA get first nybble of 16-bit value to print - LSRA - LSRA - LSRA - LDA A,X - STA ,S - LDA 4,S retrieve MSB of 16-bit value of print - ANDA #$0F get second nybble of 16-bit value - LDA A,X - STA 1,S - LSRB get third nybble - LSRB - LSRB - LSRB - LDB B,X - STB 2,S - LDB 5,S - ANDB #$0F - LDB B,X - STB 3,S - - LEAX ,S have X point to 4-char buffer - LDB #5 char counter -PRWH30 LDA ,X+ search for first non-'0' character - DECB - CMPA #'0 - BEQ PRWH30 - - LEAX -1,X go back to first non-'0' -PRWH40 LDA ,X+ print the characters - JSR [CHROUT,DAT] - DECB - BNE PRWH40 - - LEAS 4,S remove 4-char buffer - -PRWH99 PULS A,B,X,PC - - -* Table of ASCII characters for hexadecimal digits -HEXDIG FCC "0123456789ABCDEF" - - -* Print unsigned number in D in decimal. -PRNTWD PSHS X,B,A - - CLR ,-S -PRWD10 INC ,S - SUBD #10000 - BHS PRWD10 - ADDD #10000 - - CLR ,-S -PRWD20 INC ,S - SUBD #1000 - BHS PRWD20 - ADDD #1000 - - CLR ,-S -PRWD30 INC ,S - SUBD #100 - BHS PRWD30 - ADDD #100 - - CLR ,-S -PRWD40 INC ,S - SUBD #10 - BHS PRWD40 - ADDD #10 - - INCB - PSHS B -* All five digits are 1 more than their intended value. - - LDB #5 - PSHS B loop counter - LEAX 6,S - -PRWD60 LDB ,-X find first non-zero digit - CMPB #1 - BNE PRWD80 if found - DEC ,S - BNE PRWD60 - - INC ,S all zeroes: print one zero - LEAX 1,X - -PRWD70 LDB ,-X -PRWD80 ADDB #$2F - BSR PRINTC - DEC ,S - BNE PRWD70 - - LEAS 6,S -PRWD90 PULS A,B,X,PC - - -* Print the ASCII character in B. Preserves X and D. -PRINTC PSHS A - TFR B,A - LBSR putchar_a - PULS A,PC - - -* Print the ASCIIZ pointed by D. Preserves X and D. -PRINTS PSHS X,B,A - TFR D,X - BRA PRS020 -PRS010 LBSR putchar_a -PRS020 LDA ,X+ - BNE PRS010 - PULS A,B,X,PC - -* Input: U => packed real number. -printReal -#ifdef _COCO_BASIC_ - PSHS U,Y,X - LEAU ,S ; stack frame pointer - LEAS -38,S ; buffer to write ASCII string to - - LDX 4,U ; address of packed number (saved U) - JSR $BC14 ; unpack into Basic's FPA0 - - PSHS U ; save frame pointer - LEAU -38,U ; address of ASCII buffer - JSR $BDDC ; convert FPA0 to ASCII - PULS U - - LEAX -38,U ; address of ASCII buffer - LDA ,X - CMPA #32 ; is 1st char space? - BNE @print - LEAX 1,X ; skip space -@print - LDA ,X+ - BEQ @donePrinting - JSR [CHROUT,DAT] - BRA @print -@donePrinting - LEAS ,U - PULS X,Y,U,PC - -#else /* This platform does not support printing reals. */ - LDA #'! - JMP [CHROUT,DAT] -#endif - -#endif /* _CMOC_NEED_printf_ */ - - -#ifdef _CMOC_NEED_readword_ - -* unsigned readword(); -* Read an unsigned decimal 16-bit integer from the user. Return result in D. -_readword - LBSR _readline - TFR D,X pass string address in X - BRA ATOW - -#endif /* _CMOC_NEED_readword_ */ - -_ -#if defined(_CMOC_NEED_printf_) \ - || defined(_CMOC_NEED_readword_) \ - || defined(_CMOC_NEED_atoi_) \ - || defined(_CMOC_NEED_atoui_) - -* Convert unsigned decimal integer pointed by X into word returned in D. -* Upon return, X points to character where conversion stopped. -ATOW CLR ,-S init 16-bit accumulator - CLR ,-S - -ATW100 LDB ,X+ read next char from line buffer - CMPB #$30 - BLO ATW900 stop reading at non-digit char - CMPB #$39 - BHI ATW900 stop reading at non-digit char - SUBB #$30 convert from ASCII '0'..'9' to 0..9 - CLRA - - PSHS X,B,A - LDX 4,S multiply acc by ten - LDB #10 - BSR MUL168 - STD 4,S - PULS A,B,X - - ADDD ,S add this digit to acc - STD ,S - BRA ATW100 - -ATW900 LEAX -1,X - PULS A,B,PC - - -* Multiply B by X, unsigned; return result in D; preserve X. -MUL168 PSHS X,B,A acc A pushed to create temp byte at ,S - LDA 2,S high byte of X - MUL multiply by B - STB ,S keep intermediate result - LDB 1,S original B - LDA 3,S low byte of X - MUL - ADDA ,S - LEAS 4,S - RTS - - -#endif - - -#if defined(_CMOC_NEED_atoui_) - -* unsigned atoui(char *s); -_atoui - ldx 2,s argument 's' - lbra ATOW - -#endif /* defined(_CMOC_NEED_atoui_) */ - - -#if defined(_CMOC_NEED_atoi_) - -* int atoi(char *s); -_atoi - ldx 2,s s - clr ,-s sign byte: 0 = positive - ldb ,x 1st char - cmpb #'- minus sign? - bne atoi_010 no - com ,s $FF = negative - leax 1,x pass minus sign -atoi_010 - lbsr ATOW convert rest of s - tst ,s+ apply sign byte - beq atoi_020 positive - coma - comb - addd #1 -atoi_020 - rts - -#endif /* defined(_CMOC_NEED_atoi_) */ - - -#if defined(_CMOC_NEED_strtoul_) - -; unsigned long strtoul(char *nptr, char **endptr); -; -; A hidden first argument is passed to point to the 32-bit return value slot. -; -_strtoul - pshs u - leau ,s - clr ,-s -1,U: boolean: string contains negative number - - ldx 4,u address of return value slot - clra - clrb - std ,x clear return value (accumulator) - std 2,x - - ldx 6,u nptr - ldb ,x - cmpb #'- negative number? - bne @loop no - inc -1,u - leax 1,x pass minus sign -@loop - LDB ,X+ read next char from ASCII buffer - CMPB #'0 - BLO @done stop reading at non-digit char - CMPB #'9 - BHI @done stop reading at non-digit char - SUBB #'0 convert from ASCII '0'..'9' to 0..9 - CLRA - pshs x,b preserve char reader, new digit -; Call mulDWordUnsignedInt to multiply accumulator by 10. - ldb #10 - pshs b,a - ldx 4,u address of return value slot - pshs x - lbsr mulDWordUnsignedInt preserves X, trashes D - leas 4,s -; - puls b restore new digit -; Add B to accumulator. - clra - ldx 4,u address of return value slot - addd 2,x add low word of acc, sets carry - std 2,x - ldd ,x get high word of acc - adcb #0 add carry - adca #0 - std ,x -; - puls x restore char reader - bra @loop -@done - leax -1,x go back to last non-digit char - stx [8,U] return that address in *endptr - - ldx 4,u address of return value slot - -; Negate the result if minus sign was read. - tst -1,u - beq @notNeg - lbsr negateDWord -@notNeg - leas ,u - puls u,pc - -#endif - - -#ifdef _CMOC_NEED_srand_ - -* void srand(int seed); -_srand -SRAND LDD 2,S - STD SEED,DAT - RTS - -#endif /* _CMOC_NEED_srand_ */ - - -#ifdef _CMOC_NEED_rand_ - -* int rand(void); -* Compute a random 15-bit non-negative integer and return it in D. -* A linear congruence is used: SEED = SEED * (256 + 128 + 1) + 1. -* However, the two bytes of the result are interchanged before being returned. -_rand -RAND LDD SEED,DAT - PSHS B,A SEED - TFR B,A - CLRB - PSHS B,A SEED * 256 - LSRA - RORB - PSHS B - LSLA - LDB SEED,DAT MSB of SEED - LSRB - RORA - PULS B D = SEED * 128 - ADDD ,S++ D = SEED * (256 + 128) - ADDD ,S++ D = SEED * (256 + 128 + 1) - ADDD #1 - EORB #$40 ; improves distribution of this bit - STD SEED,DAT - ANDA #$7F 15-bit result - RTS - -#endif /* _CMOC_NEED_rand_ */ - - -LBUFMX EQU 250 number of available bytes in LINBUF buffer - - -#ifdef _COCO_BASIC_ - -#if defined(_CMOC_NEED_readline_) || defined(_CMOC_NEED_readword_) - -LINBUF EQU $02DC buffer where READLN stores line read from user - -_readline - JSR $A390 CoCo Basic routine to read a line w/ cursor - LDD #LINBUF+1 return address of 1st char - RTS - -#endif /* defined(_CMOC_NEED_readline_) || defined(_CMOC_NEED_readword_) */ - - -#ifdef _CMOC_NEED_delay_ - -TIMER EQU $0112 CoCo Basic 60 Hz 16 bit timer - -* Wait for a number of ticks (1/60 second) which is given on the stack. -_delay -DELAY PSHS B,A - LDD 4,S number of ticks to wait - BEQ DELAY9 - ADDD TIMER value that TIMER must reach -DELAY1 CMPD TIMER - BNE DELAY1 -DELAY9 PULS A,B,PC - -#endif /* _CMOC_NEED_delay_ */ - - -#elif defined(OS9) - - -#if defined(_CMOC_NEED_putchar_) || defined(_CMOC_NEED_putstr_) || defined(_CMOC_NEED_sprintf_) || defined(_CMOC_NEED_printf_) -* NOTE: This is inefficient for a string: have printf accumulate, then send a string. -PUTCHR pshs u,y,x,a - leax ,s point to char pushed in stack - ldy #1 1 char to print - lda #1 write to stdout - os9 I$WritLn - puls a,x,y,u,pc -#endif - - -#if defined(_CMOC_NEED_readline_) || defined(_CMOC_NEED_readword_) - -_readline - pshs y preserve process data pointer - leax LINBUF+1,y +1 as in Color Basic - ldy #LBUFMX-1 max num chars allowed (w/ room for final NUL) - clra read from stdin - os9 I$ReadLn - bcc readline_ok - - clra return null pointer to signal error - clrb - puls y,pc - -readline_ok - tfr y,d number of bytes actually read - cmpd #0 empty line? - beq readline_empty yes - - leax d,x point past last byte read - ldb -1,x is last byte read carriage return? - cmpb #13 - bne readline_notCR no - - leax -1,x point to CR, to nullify it - -readline_notCR - -readline_empty - clr ,x terminate line with NUL - puls y - leax LINBUF+1,y +1 as in Color Basic - tfr x,d return start of string - rts - -#endif /* defined(_CMOC_NEED_readline_) || defined(_CMOC_NEED_readword_) */ - - -#ifdef _CMOC_NEED_delay_ -* Wait for a number of ticks (1/60 second) which is given on the stack. -_delay -DELAY ldx 2,s - os9 F$Sleep - rts -#endif - - -#elif defined(USIM) - - -* Code to be used with the version of usim that comes with CMOC. -* -PUTCHR STA $FF00 - RTS - - -#if defined(_CMOC_NEED_readline_) || defined(_CMOC_NEED_readword_) - -LINBUF RMB LBUFMX+1 buffer where READLN stores line read from user - -_readline - LEAX LINBUF+1,DAT +1 as in Color Basic - LDB #LBUFMX-1 number of bytes still available in buffer -* (1 byte reserved for terminating NUL) -RDLN10 LDA $FF00 check for a character from the user - BEQ RDLN10 - CMPA #255 if EOF - BEQ CRASH - CMPA #10 if newline - BEQ RDLN90 - TSTB room left in buffer? - BEQ RDLN10 if no - STA ,X+ there is room: store the character - DECB - BRA RDLN10 -RDLN90 CLR ,X terminate the string with a NUL character - LEAX LINBUF+1,DAT return start of string - TFR X,D - RTS - -CRASH SYNC - -#endif /* defined(_CMOC_NEED_readline_) || defined(_CMOC_NEED_readword_) */ - - -#ifdef _CMOC_NEED_delay_ - -* Wait for a number of ticks (1/60 second) which is given on the stack. -_delay -DELAY PSHS B,A - LDD 4,S number of ticks to wait - STD $FF02 ask simulator to wait - PULS A,B,PC - -#endif /* _CMOC_NEED_delay_ */ - -#elif defined(VECTREX) - -PUTCHR - RTS - -#if defined(_CMOC_NEED_readline_) || defined(_CMOC_NEED_readword_) - -* Return NULL (meaning failure) on the Vectrex, which has no keyboard. -_readline - CLRA - CLRB - RTS - -#endif /* defined(_CMOC_NEED_readline_) || defined(_CMOC_NEED_readword_) */ - - -#ifdef _CMOC_NEED_delay_ - -_delay -DELAY - RTS - -#endif /* _CMOC_NEED_delay_ */ - -#endif /* platform */ - - -#ifdef _CMOC_NEED_strcmp_ - -* int strcmp(char *, char *); -* -_strcmp - pshs u,x - ldx 6,s 1st string - ldu 8,s 2nd string - -_strcmp_050 - ldb ,u+ - lda ,x+ - bne _strcmp_010 - tstb - beq _strcmp_900 return 0 (in B) - -* a zero but b non zero, so 1st string comes before -_strcmp_040 - ldb #$ff - bra _strcmp_900 - -_strcmp_010 equ * - tstb - bne _strcmp_020 - -* a non zero but b zero, so 1st string comes after -_strcmp_030 equ * - ldb #1 - bra _strcmp_900 - -_strcmp_020 equ * -* a and b non zero. - cmpa -1,u - bhi _strcmp_030 return +1 - blo _strcmp_040 return -1 - bra _strcmp_050 - -_strcmp_900 - sex - puls x,u,pc - -#endif /* _CMOC_NEED_strcmp_ */ - - -#if defined(_CMOC_NEED_strlen_) || defined(_CMOC_NEED_printf_) || defined(_CMOC_NEED_sprintf_) - -_strlen pshs x - ldx 4,s -_strlen_010 - tst ,x+ - bne _strlen_010 - - tfr x,d - subd #1 compensate for increment past '\0' - subd 4,s substract start address - - puls x,pc - -#endif - - -#ifdef _CMOC_NEED_memset_ - -* void *memset(void *s, int c, size_t n) -* -_memset pshs u - tfr s,u - leas -2,s end address - - ldd 4,u start address (s) - tfr d,x - addd 8,u add number of bytes (n) to get end address - std -2,u store in local var - - lda 7,u byte to write (c) - bra _memset_cond -_memset_loop - sta ,x+ -_memset_cond - cmpx -2,u at end? - bne _memset_loop no, continue - - ldd 4,u return start address - tfr u,s - puls u,pc - -#endif /* _CMOC_NEED_memset_ */ - - -#ifdef _CMOC_NEED_memcpy_ - -* Preserves X and U. Trashes D. -* -memcpy -_memcpy pshs u,x - ldx 6,s destination string - ldu 8,s source string - tfr u,d - addd 10,s end of source region - pshs b,a - bra _memcpy_100 -_memcpy_050 - lda ,u+ - sta ,x+ -_memcpy_100 - cmpu ,s compare with end address - bne _memcpy_050 - - leas 2,s dispose of end address - ldd 6,s return start address - puls x,u,pc - -#endif /* _CMOC_NEED_memcpy_ */ - - -#ifdef _CMOC_NEED_copyMem_ - -; Like memcpy, but with only one argument passed on the stack. -; Input: X => Desination address. -; D => Number of bytes to copy. -; Pushed argument => Source address. -; Does not return anything. -; Does not preserve X or D. -; Preserves U and Y. -; -copyMem - pshs u preserve frame pointer - ldu 4,s source address - leau d,u end of source region - pshs u store for loop condition - ldu 6,s source address - bra @cond -@loop - lda ,u+ - sta ,x+ -@cond - cmpu ,s compare with end address - bne @loop - - puls x,u,pc pull end address in X instead of leas 2,s - -#endif /* _CMOC_NEED_copyMem_ */ - - -#ifdef _CMOC_NEED_initSingleFromSingle_ - -; Interface of routines named initXXXFromSingle: -; Input: D = Address of packed single-precision real to use as source. -; X = Address of location to be initialized, of type XXX. -; -initSingleFromSingle -#ifdef _COCO_BASIC_ - pshs u - tfr d,u - ldd ,u - std ,x - ldd 2,u - std 2,x - ldb 4,u - stb 4,x - puls u,pc -#else - rts -#endif - -#endif /* _CMOC_NEED_initSingleFromSingle_ */ - - -#ifdef _CMOC_NEED_push4ByteStruct_ - -; Copies a 4-byte region of memory into the stack. -; X: Address of the 4-byte region to read. -; S: Address where to copy the region to. -; Example: -; LEAX destination,PCR -; LEAS -4,S -; LBSR push4ByteStruct -; Preserves X. Trashes D. Returns nothing. -; -push4ByteStruct - ldd ,x - std 2,s - ldd 2,x - std 4,s - rts - -#endif /* _CMOC_NEED_push4ByteStruct_ */ - - -#ifdef _CMOC_NEED_push5ByteStruct_ - -; Copies a 5-byte region of memory into the stack. -; X: Address of the 5-byte region to read. -; S: Address where to copy the region to. -; Example: -; LEAX destination,PCR -; LEAS -5,S -; LBSR push5ByteStruct -; Preserves X. Trashes D. Returns nothing. -; -push5ByteStruct - ldd ,x - std 2,s - ldd 2,x - std 4,s - ldb 4,x - stb 6,s - rts - -#endif /* _CMOC_NEED_push5ByteStruct_ */ - - -#ifdef _CMOC_NEED_pushStruct_ - -; Copies a region of memory into the stack. -; X: Address of the region to read. -; D: Size in bytes of the region. Must not be zero. -; S: Address where to copy the region to. -; Example: -; LEAX destination,PCR -; LDD #17 -; LEAS -17,S -; LBSR pushStruct -; Preserves U, Y. Trashes D, X. Returns nothing. -; -pushStruct - pshs u - leau 4,s destination (past pushed U and return address) - leas -2,s - pshs x preserve source address - leax d,x compute end of source region - stx 2,s preserve end - puls x restore source address; ,s is now end -@copyByte - lda ,x+ - sta ,u+ - cmpx ,s compare with end address - bne @copyByte - leas 2,s dispose of end address - puls u,pc - -#endif /* _CMOC_NEED_memcpy_ */ - - -#ifdef _CMOC_NEED_memcmp_ - -* int memcmp(void *s1, void *s2, size_t n) -* -* Returns 0, 1 or $FF in B. Leaves A undefined. -* -_memcmp - pshs u,y - ldy 10,s number of bytes to compare - beq _memcmp_equal - ldx 6,s 1st string - ldu 8,s 2nd string - -_memcmp_loop - lda ,x+ byte from 1st string - cmpa ,u+ compare with byte from 2nd - bne _memcmp_diff if bytes different - - leay -1,y one byte done - bne _memcmp_loop if more to do - -_memcmp_equal - clrb return 0: regions are equal - bra _memcmp_end - -_memcmp_diff - cmpa -1,u - bhi _memcmp_ret1 return +1: 1st string comes after - - ldb #$FF return -1: 1st string comes before - bra _memcmp_end - -_memcmp_ret1 - ldb #1 - -_memcmp_end - sex return int - puls y,u,pc - -#endif /* _CMOC_NEED_memcmp_ */ - - -#if defined(_CMOC_NEED_strcpy_) || defined(_CMOC_NEED_strcat_) - -* byte *strcpy(byte *dest, byte *src); -* Returns dest. -* -_strcpy - pshs u,x - ldx 6,s destination string - ldu 8,s source string - -_strcpy_010 - lda ,u+ - sta ,x+ - bne _strcpy_010 - - ldd 6,s destination string - puls x,u,pc - -#endif - - -#ifdef _CMOC_NEED_strncpy_ - -* byte *strncpy(byte *dest, byte *src, word n); -* Returns dest. -* -_strncpy -strncpy * also defined with this name, b/c it is a utility sub-routine too - pshs u,y,x - ldx 8,s destination string - ldu 10,s source string - ldy #0 counts bytes filled - bra _strncpy_020 - -_strncpy_010 - lda ,u+ is next source byte terminator? - beq _strncpy_050 yes - - sta ,x+ store in destination string - leay 1,y one more byte filled -_strncpy_020 - cmpy 12,s filled all bytes to fill? - blo _strncpy_010 no - - bra _strncpy_090 - -_strncpy_040 - clr ,x+ pad with '\0' - leay 1,y - -_strncpy_050 - cmpy 12,s filled all bytes to fill? - blo _strncpy_040 no - -_strncpy_090 - ldd 8,s destination string - puls x,y,u,pc - -#endif /* _CMOC_NEED_strncpy_ */ - - -#ifdef _CMOC_NEED_strcat_ - -* byte *strcat(byte *dest, byte *src); -* Returns dest. -* -_strcat - pshs x - ldx 6,s source string - pshs x pass it to _strcpy - - ldx 6,s destination string -_strcat_010 - tst ,x+ - bne _strcat_010 - - leax -1,x point back to '\0' - pshs x pass as destination string to _strcpy - - lbsr _strcpy - - leas 4,s dispose of _strcpy arguments - ldd 4,s return original destination address - puls x,pc - -#endif /* _CMOC_NEED_strcat_ */ - - -#ifdef _CMOC_NEED_strchr_ - -* byte *strchr(byte *s, word c) -* Note that CMOC passes a character value (e.g., 'x') -* as a word to a function. -* -_strchr pshs x - ldx 4,s string - lda 7,s char to search for (ignore MSB) - -_strchr_100 - cmpa ,x - beq _strchr_800 found - tst ,x+ - bne _strchr_100 - - clra not found: return NULL - clrb - bra _strchr_900 -_strchr_800 - tfr x,d return address where char found -_strchr_900 - puls x,pc - -#endif /* _CMOC_NEED_strchr_ */ - - -#ifdef _CMOC_NEED_strlwr_ - -* byte *strlwr(byte *) -_strlwr pshs x - ldx 4,s string address - bra _strlwr_020 -_strlwr_010 - cmpa #65 'A' - blo _strlwr_020 - cmpa #90 'Z' - bhi _strlwr_020 - adda #32 make lowercase - sta -1,x -_strlwr_020 - lda ,x+ - bne _strlwr_010 - ldd 4,s return string address - puls x,pc - -#endif /* _CMOC_NEED_strlwr_ */ - - -#ifdef _CMOC_NEED_strupr_ - -* byte *strupr(byte *) -_strupr pshs x - ldx 4,s string address - bra _strupr_020 -_strupr_010 - cmpa #97 'a' - blo _strupr_020 - cmpa #122 'z' - bhi _strupr_020 - suba #32 make uppercase - sta -1,x -_strupr_020 - lda ,x+ - bne _strupr_010 - ldd 4,s return string address - puls x,pc - -#endif /* _CMOC_NEED_strupr_ */ - - -#ifdef _CMOC_NEED_toupper_ - -_toupper - ldd 2,s character in B - cmpb #97 'a' - blo _toupper_done - cmpb #122 'z' - bhi _toupper_done - subb #32 -_toupper_done - rts - -#endif /* _CMOC_NEED_toupper_ */ - - -#ifdef _CMOC_NEED_tolower_ - -_tolower - ldd 2,s character in B - cmpb #65 'A' - blo _tolower_done - cmpb #90 'Z' - bhi _tolower_done - addb #32 -_tolower_done - rts - -#endif /* _CMOC_NEED_tolower_ */ - - -#if defined(_CMOC_NEED_dwtoa_) \ - || defined(_CMOC_NEED_printf_) \ - || defined(_CMOC_NEED_sprintf_) \ - || defined(_CMOC_NEED_divDWordDWord_) \ - || defined(_CMOC_NEED_divDWordUnsignedInt_) \ - || defined(_CMOC_NEED_divUnsignedIntDWord_) \ - || defined(_CMOC_NEED_signedDivDWordDWord_) \ - || defined(_CMOC_NEED_divModUnsignedIntDWord_) \ - || defined(_CMOC_NEED_divUnsignedIntDWord_) \ - || defined(_CMOC_NEED_modUnsignedIntDWord_) - -* Subtract 32-bit unsigned integer from another. -* In: X => first integer, U => second integer. -* Out: first minus second in space pointed by X, -* carry bit reflects subtraction. -* Preserves: all, except CC -* -sub32xu pshs b,a - - ldd 2,x low word of first - subd 2,u low word of second - std 2,x store in low word of first - - ldd ,x high word of first - sbcb 1,u - sbca ,u - std ,x - - puls a,b,pc carry bit from last sub returned - -#endif - - -#if defined(_CMOC_NEED_dwtoa_) || defined(_CMOC_NEED_printf_) || defined(_CMOC_NEED_sprintf_) - -* byte sub32(word *hi, word h, word l) -* Subtracts 32-bit integer h:l from 32-bit unsigned integer -* pointed by 'hi'. -* Returns carry of the subtraction in B. -* -sub32: - PSHS U - LEAU ,S - LEAS -1,S variable carry - pshs x,b - pshs u - ldx 4,U variable hi - leau 6,U variable h - lbsr sub32xu - puls u - tfr cc,b - andb #1 - stb -1,U variable carry - puls b,x - LDB -1,U variable carry - LEAS ,U - PULS U,PC - - -* Utility routine for dwtoa. -* -doDigit: - PSHS U - TFR S,U - LEAS -5,S -* Line 84: init of variable c - CLR -1,U variable c - -doDigit_010: -* Line 85: for body -* Line 87: init of variable hiCopy - LDX 4,U variable hi (word *) - LDD ,X read *hi (word) - STD -5,U variable hiCopy -* Line 88: init of variable loCopy - LDD 2,X load hi[1] (word) - STD -3,U variable loCopy -* Line 90: if -* Line 90: function call: sub32() - LDD 8,U variable l - PSHS B,A argument 3 of sub32() - LDD 6,U variable h - PSHS B,A argument 2 of sub32() - PSHS X 'hi': argument 1 of sub32() - LBSR sub32 sub32(): returns carry in B - LEAS 6,S - TSTB - BEQ doDigit_020 no carry: continue subtracting -* Line 93: assignment: = - LDX 4,U variable hi - LDD -5,U - STD ,X -* Line 94: assignment: = - LDD -3,U - STD 2,X - BRA doDigit_030 break - -doDigit_020: - INC -1,U variable c - BRA doDigit_010 - -doDigit_030: - -* Line 101: assignment: += - LDB -1,U - ADDB #$30 -* Line 103: assignment: = - LDX 10,U variable dest (byte *) - STB ,X store character in *dest - - TFR U,S - PULS U,PC end of doDigit - - -* char *dwtoa(char *buffer, unsigned hi, unsigned lo) -* -* Prints the 32-bit unsigned integer given by 'hi' and 'lo' -* in the designated 11-byte buffer as an ASCII decimal string -* terminated by a '\0' character. -* The resulting buffer always receives a 10-character string -* and is zero padded at the left. -* Returns (in D) the address of the first non-'0' character in the -* resulting buffer, or of the last '0' character if the given -* value was zero. -* Preserves U. Trashes X. -* -_dwtoa PSHS U - LEAU ,S - LEAS -5,S -* Line 125: init of variable dest - LDD 4,U variable buffer - STD -4,U variable dest -* Line 127: init of variable pPower - LEAX powersOfTen,pcr variable pow10_9_hi - STX -2,U variable pPower -* Line 131: for init -* Line 131: init of variable i - LDB #$09 - STB -5,U variable i - BRA dwtoa_020 jump to for condition - -dwtoa_010: -* Line 131: for body - -* Line 138: function call: doDigit() - ldx -4,U variable dest - PSHS x argument 4 of doDigit() - leax 1,x point to next byte for next iteration - stx -4,u - - LDX -2,U variable pPower - - LDD 2,X low word of that power of 10 - PSHS B,A argument 3 of doDigit() - - LDD ,X high word of a power of 10 - PSHS B,A argument 2 of doDigit() - - leax 4,x advance pPower to next power of 10 - stx -2,U store into variable pPower for next iteration - - LEAX 6,U point to argument 'hi', which is followed by 'lo' - PSHS X argument 1 of doDigit() - - BSR doDigit - - LEAS 8,S - -* Line 131: for increment - DEC -5,U variable i -dwtoa_020: -* Line 131: for condition - TST -5,U - BNE dwtoa_010 end of loop of calls to doDigit() - -* Store last digit, which is in variable 'lo', at 'dest'. -* Line 143: assignment: = - LDB 9,U low byte of variable lo (contains 0..9) - addb #$30 make 0..9 into '0'..'9' in ASCII - LDX -4,U variable dest - STB ,X+ - clr ,x write terminating '\0' - -* Skip leading zeroes in the resulting string. - LDX 4,U variable buffer -dwtoa_030: - LDB ,X+ - CMPB #$30 - BEQ dwtoa_030 - - leax -1,x - -* If entire string contains '\0' characters, return address of last '\0'. - TST ,X - BNE dwtoa_040 - leax -1,x - -dwtoa_040: - tfr x,d return address of 1st non-0 digit, or of last 0 if value is 0 - - LEAS ,U - PULS U,PC - -* Powers of ten as 32-bit integers, in descending order. -* Used by dwtoa. -* -powersOfTen: - FDB $3b9a,$ca00 10**9 - FDB $05f5,$e100 10**8 - FDB $0098,$9680 10**7 - FDB $000f,$4240 10**6 - FDB $0001,$86a0 10**5 - FDB $0000,$2710 10**4 - FDB $0000,$03E8 10**3 - FDB $0000,$0064 10**2 - FDB $0000,$000A 10**1 - -#endif /* _CMOC_NEED_dwtoa_ */ - - -#ifdef _CMOC_CHECK_NULL_POINTERS_ - -* void set_null_ptr_handler(char *newHandler); -* -_set_null_ptr_handler: - LDD 2,S first argument - STD null_ptr_handler,DAT -check_null_ptr_x_end: - RTS - - -* Checks if the pointer in X in null and if it is, invokes -* the handler in null_ptr_handler. -* -check_null_ptr_x: - CMPX #0 - BNE check_null_ptr_x_end - PSHS U,Y,X,B,A - LDD 8,S return address of LBSR that led to this routine - SUBD #3 point to LBSR instruction - PSHS B,A - JSR [null_ptr_handler,DAT] - LEAS 2,S - PULS A,B,X,Y,U,PC - -#endif /* _CMOC_CHECK_NULL_POINTERS_ */ - - -#ifdef _CMOC_CHECK_STACK_OVERFLOW_ - -_set_stack_overflow_handler: - LDD 2,S first argument - STD stack_overflow_handler,DAT - RTS - -check_stack_overflow: - PSHS B,A - LDD stack_overflow_handler,DAT is there a handler? - BEQ no_stack_overflow no - CMPS end_of_sbrk_mem,DAT - BLO stack_overflow_detected - CMPS INISTK,DAT - BLO no_stack_overflow -stack_overflow_detected: - LDD stack_overflow_handler,DAT get current handler - LDX #0 disable stack checking - STX stack_overflow_handler,DAT because handler calls this routine - TFR D,X preserve handler address in X, for the JSR - - TFR S,D pass out-of-range stack ptr as 2nd argument to handler - ADDD #4 don't count current routine call - PSHS B,A - LDD 4,S return address of LBSR that led to this routine - SUBD #3 point to LBSR instruction - PSHS B,A - JSR ,X handler does not have to return -stack_overflow_freeze: - BRA stack_overflow_freeze freeze if handler returned -no_stack_overflow: - PULS A,B,PC - -#endif /* _CMOC_CHECK_STACK_OVERFLOW_ */ - - -#ifdef _CMOC_NEED_sbrk_ - -* void *sbrk(size_t increment); -* -* Returns (byte *) -1 upon failure (not enough memory). -* Returns the old program break upon success -* (i.e., the address of the newly allocated buffer). -* -* Asking for an increment of zero always succeeds. -* This can be used to get the current program break. -* -* Uses the program_end label generated by the compiler at the very end -* of the generated program. -* -* Return value will be in D. Does not preserve X. -* -* The following system variables are initialized by INILIB. -* -_sbrk - lbsr _sbrkmax D = max number of allocatable bytes - cmpd 2,s compare with 'increment' - bhs sbrk_success increment not too large: allocate - ldd #-1 fail - rts -sbrk_success: - ldd 2,s get 'increment' - addd program_break,DAT new, tentative program break - ldx program_break,DAT preserve original program break - std program_break,DAT advance program break - tfr x,d return original program break in D - rts - -#endif /* _CMOC_NEED_sbrk_ */ - - -#if defined(_CMOC_NEED_sbrkmax_) || defined(_CMOC_NEED_sbrk_) - -* size_t sbrkmax(); -* -* Returns (in D) the maximum number of bytes that can be successfully -* asked of sbrk(). -* -_sbrkmax - ldd end_of_sbrk_mem,DAT - subd program_break,DAT - bhs _sbrkmax_non_neg -* The program break is after the stack space. Not supported by sbrk(). - clra - clrb -_sbrkmax_non_neg - rts - -#endif /* defined(_CMOC_NEED_sbrkmax_) || defined(_CMOC_NEED_sbrk_) */ - - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; -; Support for the "long" type. -; - -#if defined(_CMOC_NEED_copyDWord_) \ - || defined(_CMOC_NEED_signedDivOrModOnDWord_) - -; Input: X = destination address; D = source address. -; Preserves X. Trashes D. -; -copyDWord - pshs u - tfr d,u ; source address - ldd ,u ; high word - std ,x - ldd 2,u ; low word - std 2,x - puls u,pc - -#endif - - -#if defined(_CMOC_NEED_copyDWordFromXToD_) - -; Copies a 4-byte region of memory. -; X: Address of the 4 bytes to read. -; D: Address where to copy the bytes to. -; Preserves X. Trashes D. Returns nothing. -; -copyDWordFromXToD - pshs u - tfr d,u - ldd ,x - std ,u - ldd 2,x - std 2,u - puls u,pc - -#endif - - -#if defined(_CMOC_NEED_negateDWord_) \ - || defined(_CMOC_NEED_testAndRemoveSignOnDWord_) \ - || defined(_CMOC_NEED_testAndRemoveSignOnWord_) \ - || defined(_CMOC_NEED_signedDivDWordDWord_) \ - || defined(_CMOC_NEED_printf_) \ - || defined(_CMOC_NEED_strtoul_) \ - || defined(_CMOC_NEED_strtol_) \ - || defined(_CMOC_NEED_initDWordFromSingle_) - -; Input: X => Long to negate. -; Preserves X. Trashes D. -; -negateDWord - com 3,x - com 2,x - com 1,x - com ,x - ldd 2,x ; low word - addd #1 ; sets carry value - std 2,x - ldd ,x ; high word - adcb #0 ; add carry - adca #0 - std ,x - rts - -#endif - - -#if defined(_CMOC_NEED_cmpDWordDWord_) \ - || defined(_CMOC_NEED_cmpDWordSignedInt_) \ - || defined(_CMOC_NEED_cmpSignedIntDWord_) \ - || defined(_CMOC_NEED_cmpDWordUnsignedInt_) \ - || defined(_CMOC_NEED_cmpUnsignedIntDWord_) \ - || defined(_CMOC_NEED_divModDWordDWord_) \ - || defined(_CMOC_NEED_divDWordDWord_) \ - || defined(_CMOC_NEED_modDWordDWord_) \ - || defined(_CMOC_NEED_divDWordUnsignedInt_) \ - || defined(_CMOC_NEED_divUnsignedIntDWord_) \ - || defined(_CMOC_NEED_signedDivDWordDWord_) \ - || defined(_CMOC_NEED_divModUnsignedIntDWord_) \ - || defined(_CMOC_NEED_divUnsignedIntDWord_) \ - || defined(_CMOC_NEED_modUnsignedIntDWord_) \ - || defined(_CMOC_NEED_signedDivOrModOnDWord_) - -; Input: Stacked arguments: address of left dword, address of right dword. -; Output: Sets N, Z, V, C. -; Preserves X, Y, U. Trashes D. -; -cmpDWordDWord - pshs u,x - ldx 6,s ; left long - ldu 8,s ; right long - leas -5,s ; locals -; ,s (4 bytes): temp long -; 4,s: temp flags -; - bsr sub32Stack ; *X - *U in ,s; sets N, V, C - tfr cc,b - andb #$FB ; reset Z (Z to be computed separatedly) - stb 4,s ; preserve CC from sub32Stack - - bsr isLongZeroStack ; checks 4 bytes at ,s - tfr cc,a - anda #4 ; keep only Z - ora 4,s ; add flags from CC obtained from sub32Stack - - tfr a,cc - leas 5,s - puls x,u,pc - -; Pushed long receives *X - *U (unsigned). -; Sets N, V, C. Trashes D. -; -sub32Stack - ldd 2,x - subd 2,u - std 4,s ; low word of result - ldd ,x - sbcb 1,u - sbca ,u - pshs cc ; preserve flags to be returned - std 3,s ; high word of result - puls cc,pc - -; Checks if pushed long is zero. Sets Z flag. -; Preserves registers. -; -isLongZeroStack - tst 2,s - bne @done - tst 3,s - bne @done - tst 4,s - bne @done - tst 5,s -@done rts - -#endif - - -#if defined(_CMOC_NEED_isDWordZero_) - -; Input: X => long. -; Output: Z flag. -; Preserves X and D. -; -isDWordZero - tst ,x - bne @done - tst 1,x - bne @done - tst 2,x - bne @done - tst 3,x -@done rts - -#endif - - -#if defined(_CMOC_NEED_cmpDWordSignedInt_) - -; Input: 2 pushed arguments. -; Preserves X and U. Trashes D. -; -cmpDWordSignedInt - pshs u,x - ldx 6,s ; address of dword - ldd 8,s ; signed int - pshs b,a ; create temp dword in stack - tfr a,b - sex ; sign extend int into A - pshs a - pshs a ; pushed dword version of int - leau ,s ; point to dword (right side) - pshs u,x - lbsr cmpDWordDWord - leas 8,s ; clean up pushed U and X, and temp long - puls x,u,pc - -#endif - - -#if defined(_CMOC_NEED_cmpSignedIntDWord_) - -cmpSignedIntDWord - pshs u,x - ldu 8,s ; address of dword - ldd 6,s ; signed int - pshs b,a ; create temp dword in stack - tfr a,b - sex ; sign extend int into A - pshs a - pshs a ; pushed dword version of int - leax ,s ; point to dword (left side) - pshs u,x - lbsr cmpDWordDWord - leas 8,s ; clean up pushed U and X, and temp long - puls x,u,pc - -#endif - - -#if defined(_CMOC_NEED_cmpDWordUnsignedInt_) - -cmpDWordUnsignedInt - pshs u,x - ldx 6,s ; address of dword - ldd 8,s ; unsigned int - pshs b,a ; create temp dword in stack - clr ,-s - clr ,-s ; pushed dword version of int - leau ,s ; point to dword (right side) - pshs u,x - lbsr cmpDWordDWord - leas 8,s ; clean up pushed U and X, and temp long - puls x,u,pc - -#endif - - -#if defined(_CMOC_NEED_cmpUnsignedIntDWord_) - -cmpUnsignedIntDWord - pshs u,x - ldu 8,s ; address of dword - ldd 6,s ; signed int - pshs b,a ; create temp dword in stack - clr ,-s - clr ,-s ; pushed dword version of int - leau ,s ; point to dword (left side) - pshs u,x - lbsr cmpDWordDWord - leas 8,s ; clean up pushed U and X, and temp long - puls x,u,pc - -#endif - - -#if defined(_CMOC_NEED_addDWordDWord_) - -; Input: pushed addresses: left dword, right dword. -; X => destination dword. -; Output: Result at X. -; Preserves X. Trashes D. -; -addDWordDWord - pshs u,y - ldu 6,s ; left - ldy 8,s ; right - - ldd 2,u ; low word - addd 2,y - std 2,x - - ldd ,u ; high word - adcb 1,y - adca ,y - std ,x - - puls y,u,pc - -#endif - - -#if defined(_CMOC_NEED_addDWordUnsignedInt_) - -; Input: Pushed arguments: address of dword, value of unsigned int. -; X => destination dword. -; Preserves X. -; -addDWordUnsignedInt - pshs u - ldu 4,s ; source dword - ldd 6,s ; word to add - addd 2,u ; add to low word of source dword; sets carry - std 2,x ; store in low word of result dword - ldd ,u ; load high word of source dword - adcb #0 ; add carry of low word add - adca #0 - std ,x - puls u,pc - -#endif - - -#if defined(_CMOC_NEED_addUnsignedIntDWord_) - -; Input: Pushed arguments: value of unsigned int, address of dword. -; X => destination dword. -; Preserves X. -; -addUnsignedIntDWord - pshs u - ldu 6,s ; source dword - ldd 4,s ; word to add - addd 2,u ; add to low word of source dword; sets carry - std 2,x ; store in low word of result dword - ldd ,u ; load high word of source dword - adcb #0 ; add carry of low word add - adca #0 - std ,x - puls u,pc - -#endif - - -#if defined(_CMOC_NEED_addDWordInt_) - -; Input: Pushed arguments: address of dword, value of signed int. -; X => destination dword. -; Preserves X. -; -addDWordInt - pshs u - ldu 4,s ; source dword - ldd 6,s ; word to add - addd 2,u ; add to low word of source dword; sets carry - std 2,x ; store in low word of result dword - ldd ,u ; load high word of source dword - adcb #0 ; add carry of low word add - adca #0 - tst 6,s ; test sign bit of high word of int - bpl @intNotNeg - addd #$FFFF ; as if int had been sign-extended to 32 bits -@intNotNeg - std ,x - puls u,pc - -#endif - - -#if defined(_CMOC_NEED_addIntDWord_) - -; Input: Pushed arguments: value of signed int, address of dword. -; X => destination dword. -; Preserves X. -; -addIntDWord - pshs u - ldu 6,s ; source dword - ldd 4,s ; word to add - addd 2,u ; add to low word of source dword; sets carry - std 2,x ; store in low word of result dword - ldd ,u ; load high word of source dword - adcb #0 ; add carry of low word add - adca #0 - tst 4,s ; test sign bit of high word of int - bpl @intNotNeg - addd #$FFFF ; as if int had been sign-extended to 32 bits -@intNotNeg - std ,x - puls u,pc - -#endif - - -#if defined(_CMOC_NEED_subDWordDWord_) - -subDWordDWord - pshs u,y - ldu 6,s ; left - ldy 8,s ; right - - ldd 2,u ; low word - subd 2,y - std 2,x - - ldd ,u ; high word - sbcb 1,y - sbca ,y - std ,x - - puls y,u,pc - -#endif - - -#if defined(_CMOC_NEED_subDWordUnsignedInt_) - -; Input: Pushed arguments: address of dword, value of unsigned int. -; X => destination dword. -; Preserves X. -; -subDWordUnsignedInt - pshs u - ldu 4,s ; source dword - ldd 2,u ; load low word of source dword - subd 6,s ; subtract right side - std 2,x ; store in low word of result dword - ldd ,u ; load high word of source dword - sbcb #0 ; sub carry of low word sub - sbca #0 - std ,x - puls u,pc - -#endif - - -#if defined(_CMOC_NEED_subUnsignedIntDWord_) - -; Input: Pushed arguments: value of unsigned int, address of dword. -; X => destination dword. -; Preserves X. -; -subUnsignedIntDWord - pshs u - ldd 4,s ; left side - ldu 6,s ; source dword - subd 2,u ; sub low word of source dword - std 2,x ; store in low word of result dword - ldd #0 ; zero-extend left side (clra & clrb would clear C) - sbcb 1,u ; sub carry of low word sub from zero-extension - sbca ,u - std ,x - puls u,pc - -#endif - - -#if defined(_CMOC_NEED_subDWordInt_) - -; Input: Pushed arguments: address of dword, value of unsigned int. -; X => destination dword. -; Preserves X. -; -subDWordInt - pshs u - ldu 4,s ; source dword - ldd 2,u ; load low word of source dword - subd 6,s ; subtract right side - std 2,x ; store in low word of result dword - ldd ,u ; load high word of source dword - sbcb #0 ; sub carry of low word sub - sbca #0 - tst 6,s ; test sign bit of high word of int - bpl @intNotNeg - subd #$FFFF ; as if int had been sign-extended to 32 bits -@intNotNeg - std ,x - puls u,pc - -#endif - - -#if defined(_CMOC_NEED_subIntDWord_) - -; Input: Pushed arguments: value of unsigned int, address of dword. -; X => destination dword. -; Preserves X. -; -subIntDWord - pshs u - ldd 4,s ; left side - ldu 6,s ; source dword - subd 2,u ; sub low word of source dword - std 2,x ; store in low word of result dword - ldd #0 ; zero-extend left side (clra & clrb would clear C) - sbcb 1,u ; sub carry of low word sub from zero-extension - sbca ,u - tst 4,s ; test sign bit of high word of int - bpl @intNotNeg - subd #1 -@intNotNeg - std ,x - puls u,pc - -#endif - - -#if defined(_CMOC_NEED_mulDWordDWord_) \ - || defined(_CMOC_NEED_mulDWordUnsignedInt_) \ - || defined(_CMOC_NEED_mulUnsignedIntDWord_) \ - || defined(_CMOC_NEED_mulDWordInt_) \ - || defined(_CMOC_NEED_mulIntDWord_) \ - || defined(_CMOC_NEED_strtoul_) \ - || defined(_CMOC_NEED_strtol_) - -; Multiplies the two unsigned longs whose addresses are in X (left) -; and U (right). Stores the result in the unsigned long at Y. -; Synopsis: -; pshs y -; leax left,pcr -; leau right,pcr -; leay product,pcr -; lbsr MUL32 -; puls y -; Preserves X, U and Y. Trashes D. -; -MUL32 -; -; Let L0,L1,L2,L3 be the 4 bytes of the left operand. -; Let R0,R1,R2,R3 be the 4 bytes of the right operand. -; The product is -; L3 * (R0,R1,R2,R3) -; + 2^8 * L2 * (R0,R1,R2,R3) -; + 2^16 * L1 * (R0,R1,R2,R3) -; + 2^24 * L0 * (R0,R1,R2,R3) -; But some parts of this formula overflow the resulting 32-bit word. -; The the 32-bit result is -; L3 * (R0,R1,R2,R3) -; + 2^8 * L2 * (R1,R2,R3) -; + 2^16 * L1 * (R2,R3) -; + 2^24 * L0 * R3. -; -; Let P3,P2,P1,P0 be the product to be computed in the result buffer. -; - lda 3,x ; L3 - ldb 3,u ; R3 - mul - std 2,y ; store in P2,P3 - - lda 3,x ; L3 - ldb 2,u ; R2 - mul - addb 2,y ; add P2 - adca #0 - std 1,y ; store in P1,P2 - - lda 3,x ; L3 - ldb 1,u ; R1 - mul - addb 1,y ; add P1 - adca #0 - std ,y ; store in P0,P1 - - lda 3,x ; L3 - ldb ,u ; R0 - mul - addb ,y ; add P0 - stb ,y ; store in P0 - -; Done with L3. - - lda 2,x ; L2 - ldb 3,u ; R3 - mul - addb 2,y ; add P2 - adca 1,y ; add P1 - std 1,y ; store in P1,P2 - ldb ,y ; add carry to P0 - adcb #0 - stb ,y - - lda 2,x ; L2 - ldb 2,u ; R2 - mul - addb 1,y ; add P1 - adca ,y ; add P0 - std ,y ; store in P0,P1 - - lda 2,x ; L2 - ldb 1,u ; R1 - mul - addb ,y ; add P0 - stb ,y ; store in P0 - -; Done with L2. - - lda 1,x ; L1 - ldb 3,u ; R3 - mul - addb 1,y ; add P1 - adca ,y ; add P0 - std ,y ; store in P0,P1 - - lda 1,x ; L1 - ldb 2,u ; R2 - mul - addb ,y ; add P0 - stb ,y ; store in P0 - -; Done with L1. - - lda ,x ; L0 - ldb 3,u ; R3 - mul - addb ,y ; add P0 - stb ,y ; store in P0 - -; Done with L0. - - rts - -#endif - - -#if defined(_CMOC_NEED_mulDWordDWord_) - -; Input: pushed arguments: addresses of left and right dwords -; X => destination dword: X is allowed to be the same address -; as that of the left dword. -; Output: product at X. -; Preserves X. Trashes D. -; -mulDWordDWord - pshs u,y,x - leas -4,s ; temp result - leay ,s ; make MUL32 store result at ,s - ldx 12,s ; left address - ldu 14,s ; right address - lbsr MUL32 - ldx 4,s ; original X points to destination - ldd ,y ; copy MUL32 result to original X - std ,x - ldd 2,y - std 2,x - leas 4,s - puls x,y,u,pc - -#endif - - -#if defined(_CMOC_NEED_mulDWordUnsignedInt_) \ - || defined(_CMOC_NEED_strtoul_) \ - || defined(_CMOC_NEED_strtol_) - -; Input: Pushed arguments: address of dword, value of unsigned int. -; X => destination dword: X is allowed to be the same address -; as that of the left dword. -; Preserves X. -; -mulDWordUnsignedInt - pshs u,y,x - leas -4,s ; temp result - leay ,s ; make MUL32 store result at ,s - ldx 12,s ; left address - ldd 14,s ; right side - pshs b,a - clr ,-s - clr ,-s - leau ,s ; point to zero-extended right side - lbsr MUL32 - ldx 8,s ; original X points to destination - ldd ,y ; copy MUL32 result to original X - std ,x - ldd 2,y - std 2,x - leas 8,s - puls x,y,u,pc - -#endif - - -#if defined(_CMOC_NEED_mulUnsignedIntDWord_) - -; Input: Pushed arguments: value of unsigned int, address of dword. -; X => destination dword. -; Preserves X. -; -mulUnsignedIntDWord - pshs u,y,x - tfr x,y ; result address - ldd 8,s ; left side - ldx 10,s ; right address - pshs b,a - clr ,-s - clr ,-s - leau ,s ; point to zero-extended left side - lbsr MUL32 - leas 4,s - puls x,y,u,pc - -#endif - - -#if defined(_CMOC_NEED_mulDWordInt_) - -; Input: Pushed arguments: address of dword, value of signed int. -; X => destination dword: X is allowed to be the same address -; as that of the left dword. -; Preserves X. -; -mulDWordInt - pshs u,y,x - leas -4,s ; temp result - leay ,s ; make MUL32 store result at ,s - ldx 12,s ; left address - ldd 14,s ; right side - pshs b,a - tfr a,b - sex - pshs a - pshs a - leau ,s ; point to sign-extended right side - lbsr MUL32 - ldx 8,s ; original X points to destination - ldd ,y ; copy MUL32 result to original X - std ,x - ldd 2,y - std 2,x - leas 8,s - puls x,y,u,pc - -#endif - - -#if defined(_CMOC_NEED_mulIntDWord_) - -; Input: Pushed arguments: value of unsigned int, address of dword. -; X => destination dword. -; Preserves X. -; -mulIntDWord - pshs u,y,x - tfr x,y ; result address - ldd 8,s ; left side - ldx 10,s ; right address - pshs b,a - tfr a,b - sex - pshs a - pshs a - leau ,s ; point to zero-extended left side - lbsr MUL32 - leas 4,s - puls x,y,u,pc - -#endif - - -#if defined(_CMOC_NEED_divModDWordDWord_) \ - || defined(_CMOC_NEED_divDWordDWord_) \ - || defined(_CMOC_NEED_modDWordDWord_) \ - || defined(_CMOC_NEED_divDWordUnsignedInt_) \ - || defined(_CMOC_NEED_divUnsignedIntDWord_) \ - || defined(_CMOC_NEED_signedDivDWordDWord_) \ - || defined(_CMOC_NEED_divModUnsignedIntDWord_) \ - || defined(_CMOC_NEED_divUnsignedIntDWord_) \ - || defined(_CMOC_NEED_modUnsignedIntDWord_) \ - || defined(_CMOC_NEED_signedDivOrModOnDWord_) - -; Divides the unsigned long at X by the one at U. -; Stores the quotient in the unsigned long at Y -; and the remainder in the unsigned long at 4,Y. -; The 8 bytes at Y must not overlap the dividend or divisor. -; Synopsis: -; pshs y -; leax dividend,pcr -; leau divisor,pcr -; leay eightByteBuffer,pcr -; lbsr DIV32 -; puls y -; Preserves the divisor, X, Y, U. Trashes the dividend and D. -; -DIV32 - ldb #32 - pshs b -; 0,s: loop counter. - clra - clrb - std ,y ; clear quotient - std 2,y - std 4,y ; clear accumulator (finishes as the remainder) - std 6,y -@loop lsl 3,x ; shift high bit of dividend into carry - rol 2,x - rol 1,x - rol ,x - rol 7,y ; shift that bit into bit 0 of acc - rol 6,y - rol 5,y - rol 4,y - bsr @doesDivisorFitAcc - blo @noFit ; if not - bsr @subDivisorFromAcc - orcc #1 ; set carry - bra @carryToQuotient -@noFit - andcc #$FE ; reset carry -@carryToQuotient - rol 3,y ; shift carry into quotient - rol 2,y - rol 1,y - rol ,y - dec ,s ; another bit of the dividend to process? - bne @loop ; if yes - puls b,pc -; -; Input: U => divisor, 4,Y => accumulator. -; Output: C=1 if accumulator < divisor, C=0 otherwise (i.e., divisor goes into acc). -; -@doesDivisorFitAcc - pshs x ; preserve X - leax 4,y - pshs u,x - lbsr cmpDWordDWord ; sets C - leas 4,s - puls x,pc -; -; Input: U => divisor, 4,Y => accumulator. -; -@subDivisorFromAcc - pshs x ; preserve X - leax 4,y - lbsr sub32xu ; *X -= *U - puls x,pc - -#endif - - -#if defined(_CMOC_NEED_divModDWordDWord_) \ - || defined(_CMOC_NEED_divDWordDWord_) \ - || defined(_CMOC_NEED_modDWordDWord_) - -; Input: pushed addresses of dividend and divisor; -; X => address of result (quotient or remainder); -; B => 0 for division, 1 for remainder. -; Preserves X, Y, U. Trashes D. -; -divModDWordDWord - pshs u,y,x,b - leas -12,s -; 0,s: Copy of dividend (to avoid modifying the caller's). -; 4,s: Quotient received from DIV32. -; 8,s: Remainder received from DIV32. - ldx 21,s ; address of dividend - ldd ,x ; copy to 0,s - std ,s - ldd 2,x - std 2,s - leax ,s ; point to dividend - ldu 23,s ; point to divisor - leay 4,s ; point to quotient and remainder (8 bytes) - lbsr DIV32 - ldx 13,s ; retrieve destination address for quotient - tst 12,s ; caller wants quotient or remainder? - bne @remainder - leau 4,s - bra @copy -@remainder - leau 8,s -@copy - ldd ,u ; copy result to X - std ,x - ldd 2,u - std 2,x - leas 12,s - puls b,x,y,u,pc - -#endif - - -#if defined(_CMOC_NEED_divDWordDWord_) - -divDWordDWord - clrb - lbra divModDWordDWord - -#endif - - -#if defined(_CMOC_NEED_modDWordDWord_) - -modDWordDWord - ldb #1 - lbra divModDWordDWord - -#endif - - -#if defined(_CMOC_NEED_divModDWordUnsignedInt_) \ - || defined(_CMOC_NEED_divDWordUnsignedInt_) \ - || defined(_CMOC_NEED_modDWordUnsignedInt_) - -; Input: Pushed arguments: address of dword, value of unsigned int. -; X => destination dword. -; Preserves X. -; -divModDWordUnsignedInt - pshs u,y,x,b - leas -16,s -; 0,s: Copy of dividend (to avoid modifying the caller's). -; 4,s: Extension of divisor to 32 bits. -; 8,s: Quotient received from DIV32. -; 12,s: Remainder received from DIV32. - ldx 25,s ; address of dividend - ldd ,x ; copy to 0,s - std ,s - ldd 2,x - std 2,s - leax ,s ; point to dividend - ldd 27,s ; value of divisor - std 6,s ; extend divisor to 32 bits - clr 5,s - clr 4,s - leau 4,s ; point to 32-bit divisor - leay 8,s ; point to quotient and remainder (8 bytes) - lbsr DIV32 - ldx 17,s ; retrieve destination address for quotient - tst 16,s ; caller wants quotient or remainder? - bne @remainder - leau 8,s - bra @copy -@remainder - leau 12,s -@copy - ldd ,u ; copy quotient to X - std ,x - ldd 2,u - std 2,x - leas 16,s - puls b,x,y,u,pc - -#endif - - -#if defined(_CMOC_NEED_divDWordUnsignedInt_) - -divDWordUnsignedInt - clrb - lbra divModDWordUnsignedInt - -#endif - - -#if defined(_CMOC_NEED_modDWordUnsignedInt_) - -modDWordUnsignedInt - ldb #1 - lbra divModDWordUnsignedInt - -#endif - - -#if defined(_CMOC_NEED_divModUnsignedIntDWord_) \ - || defined(_CMOC_NEED_divUnsignedIntDWord_) \ - || defined(_CMOC_NEED_modUnsignedIntDWord_) - -; Input: Pushed arguments: value of unsigned int, address of dword. -; X => destination dword. -; Preserves X. -; -divModUnsignedIntDWord - pshs u,y,x,b - leas -12,s -; 0,s: Dividend extended to 32 bits. -; 4,s: Quotient received from DIV32. -; 8,s: Remainder received from DIV32. - ldd 21,s ; value of dividend - std 2,s ; extend to 32 bits - clr 1,s - clr ,s - leax ,s ; point to dividend - ldu 23,s ; address of divisor - leay 4,s ; point to quotient and remainder (8 bytes) - lbsr DIV32 - ldx 13,s ; retrieve destination address for quotient - tst 12,s ; caller wants quotient or remainder? - bne @remainder - leau 4,s - bra @copy -@remainder - leau 8,s -@copy - ldd ,u ; copy quotient to X - std ,x - ldd 2,u - std 2,x - leas 12,s - puls b,x,y,u,pc - -#endif - - -#if defined(_CMOC_NEED_divUnsignedIntDWord_) - -divUnsignedIntDWord - clrb - lbra divModUnsignedIntDWord - -#endif - - -#if defined(_CMOC_NEED_modUnsignedIntDWord_) - -modUnsignedIntDWord - ldb #1 - lbra divModUnsignedIntDWord - -#endif - - -#if defined(_CMOC_NEED_testAndRemoveSignOnDWord_) \ - || defined(_CMOC_NEED_signedDivOrModOnDWord_) - -; Input: pushed address => dword to test; -; X => destination to copy absolute value of dword to; -; Output: non-negative dword at X; -; N is 1 if input dword was negative, 0 otherwise. -; Preserves X. Trashes D. -; -testAndRemoveSignOnDWord - pshs u - ldu 4,s ; address of input dword - ldd 2,u ; copy input dword to destination - std 2,x - ldd ,u - std ,x - bpl @done ; branch if high bit of high word is 0 -; Input dword is negative: remove sign of destination dword. - lbsr negateDWord - orcc #8 ; set N = 1 -@done - puls u,pc -#endif - - -#if defined(_CMOC_NEED_testAndRemoveSignOnWord_) \ - || defined(_CMOC_NEED_signedDivOrModOnDWord_) - -; Input: pushed word => signed word to test; -; X => dword that receives absolute value of word. -; Output: non-negative dword at X; -; N is 1 if input word was negative, 0 otherwise. -; Preserves X. Trashes D. -; -testAndRemoveSignOnWord - ldd 2,s ; pushed argument - std 2,x - tfr a,b ; sign extension - sex - sta 1,x - sta ,x - bpl @done - lbsr negateDWord ; dword at X is < 0; make is positive - orcc #8 ; set N = 1 -@done - rts - -#endif - - -#if defined(_CMOC_NEED_copyWordToDWord_) \ - || defined(_CMOC_NEED_signedDivOrModOnDWord_) - -; Input: pushed word => input word; -; X => destination dword. -; Output: Zero-extended dword at X. -; Preserves X. Trashes D. -; -copyWordToDWord - ldd 2,s - std 2,x - clr 1,x - clr ,x - rts - -#endif - - -#if defined(_CMOC_NEED_signExtWordToDWord_) \ - || defined(_CMOC_NEED_signedDivOrModOnDWord_) - -; Input: pushed word => input signed word; -; X => destination dword. -; Output: Sign-extended dword at X. -; Preserves X. Trashes D. -; -signExtWordToDWord - ldd 2,s - std 2,x - tfr a,b - sex - sta 1,x - sta ,x - rts - -#endif - - -#if defined(_CMOC_NEED_signedDivOrModOnDWord_) - -; Input: bit 3 of B: sign to give to the quotient. -; X => 2 unsigned dwords (dividend, divisor). -; Output: quotient written in place of dividend; remainder in place of divisor -; Preserves B. Trashes A and X. -; -signedDivDWordDWord - pshs u,y,b - leas -8,s ; result of DIV32 - - leau 4,x ; point to divisor - leay ,s ; point to result dwords - lbsr DIV32 - - ldd ,y ; copy quotient over dividend - std ,x - ldd 2,y - std 2,x - ldd 4,y ; copy remainder over divisor - std 4,x - ldd 6,y - std 6,x - - ldb 8,s ; look at input B: is quotient negative? - bitb #8 ; N flag - beq @notNeg ; branche if quotient non-negative - lbsr negateDWord ; negative quotient (at X) -@notNeg - leas 8,s - puls b,y,u,pc - -; Input: push word: address of source dword; -; X => address of destination dword; -; bit 3 or B: sign to give to the destination dword. -; Preserves X. -; -copyModuloDWord - pshs u,b - ldu 5,s ; address of source dword - ldd ,u - std ,x - ldd 2,u - std 2,x - ldb ,s ; check N in flags received in B - bitb #8 - beq @done - lbsr negateDWord -@done - puls b,u,pc - - -; Output: X => destination dword; B = flag byte. -; Trashes D. -; -signedDivOrModOnDWord - pshs u - leau ,s - leas -10,s - pshs b -; Arguments: -; 4,U: address of destination dword. -; 6,U: dividend (address if dword; word value if short integral). -; 8,U: divisor (address if dword; word value if short integral). -; Locals: -; -4,U: 2nd temp dword (divisor as dword) -; -8,U: 1st temp dword (dividend as dword) -; -9,U: CC of divisor. -; -10,U: CC of dividend. -; -11,U: flag byte received from caller in B: -; bit 0 ($01): operation flag (0 = modulo, 1 = division) -; bit 1 ($02): quotient signedness flag (0 = unsigned, 1 = signed) -; bit 2 ($04): dividend size flag (0 = word, 1 = dword) -; bit 3 ($08): dividend signedness flag -; bit 4 ($10): divisor size flag -; bit 5 ($20): divisor signedness flag -; -; Convert divisor to non-negative. - - ldx 8,u ; divisor - pshs x ; pass to utility routine - leax -4,u ; 2nd temp word - ldb -11,u ; flag byte - andb #$22 ; divisor and quotient signedness flags - cmpb #$22 - bne @noSignToRemoveOnDivisor -; Remove sign on divisor. - ldb -11,u ; flag byte - bitb #$10 ; is divisor word or dword? - beq @wordDivisor_0 - lbsr testAndRemoveSignOnDWord - bra @divisorSignRemoved -@wordDivisor_0 - lbsr testAndRemoveSignOnWord -@divisorSignRemoved - tfr cc,b ; preserve N flag for divisor - stb -9,u - bra @divisorNowDWord -; -@noSignToRemoveOnDivisor -; Copy divisor to 2nd temp dword. - ldb -11,u ; flag byte - bitb #$10 ; is divisor word or dword? - beq @wordDivisor_1 - ldd ,s ; address of word to copy - lbsr copyDWord - bra @nullN -@wordDivisor_1 - bitb #$20 ; divisor signedness - beq @unsignedWordDivisor - lbsr signExtWordToDWord - bra @nullN -@unsignedWordDivisor - lbsr copyWordToDWord -@nullN - clr -9,u ; null N flag for divisor -; -@divisorNowDWord - leas 2,s ; discard arg of utility routine -; -; Convert dividend to non-negative. - ldx 6,u ; dividend - pshs x ; pass to utility routine - leax -8,u ; 1st temp dword - ldb -11,u ; flag byte - andb #$0A ; dividend and quotient signedness - cmpb #$0A - bne @noSignToRemoveOnDividend -; Remove sign on dividend. - ldb -11,u ; flag byte - bitb #$04 ; is dividend word or dword? - beq @wordDividend_0 - lbsr testAndRemoveSignOnDWord - bra @dividendSignRemoved -@wordDividend_0 - lbsr testAndRemoveSignOnWord -@dividendSignRemoved - bra @dividendNowDWord -; -@noSignToRemoveOnDividend -; Copy dividend to 1st temp dword. - ldb -11,u ; flag byte - bitb #$04 ; is dividend word or dword? - beq @wordDividend_1 - ldd ,s ; address of word to copy - lbsr copyDWord - bra @andcc -@wordDividend_1 - bitb #$08 ; dividend signedness - beq @unsignedWordDividend - lbsr signExtWordToDWord - bra @andcc -@unsignedWordDividend - lbsr copyWordToDWord -@andcc - andcc #$F7 ; null N flag for dividend -; -@dividendNowDWord - leas 2,s ; discard arg of utility routine -; -; Here, the N flag represents the sign of the left side. -; Call the division routine. - tfr cc,b ; N flag in B - stb -10,u ; preserve sign of dividend - eorb -9,u ; XOR with sign of divisor - leax -8,u ; point to the 2 temp dwords - lbsr signedDivDWordDWord -; -; Resulting dword is one of temp dwords, depending on operation. -; - leax -8,u ; 1st temp dword (contains quotient) - ldb -11,u ; flag byte - bitb #$01 ; operation - bne @division_0 - leax 4,x ; 2nd temp dword (contains modulo) -@division_0 - pshs x ; address to dword to copy - ldx 4,u ; address of destination dword - bitb #$01 ; operation - bne @division_1 - ldb -10,u ; sign of dividend - lbsr copyModuloDWord ; preserves X - bra @done -@division_1 - ldd ,s ; address of word to copy - lbsr copyDWord ; preserves X -@done - leas ,u ; discards arg pushed to copy*DWord - puls u,pc - -#endif - - -#if defined(_CMOC_NEED_initDWordFromSignedWord_) - -; Input: X => dword to initialize. D => signed word to initialize the dword with. -; Preserves X. Trashes D. -; -initDWordFromSignedWord - std 2,x ; low word - tfr a,b - sex - sta 1,x - sta ,x - rts - -#endif - - -#if defined(_CMOC_NEED_initDWordFromUnsignedWord_) - -; Input: X => dword to initialize. D => unsigned word to initialize the dword with. -; Preserves X. -; -initDWordFromUnsignedWord - std 2,x ; low word - clr 1,x - clr ,x - rts - -#endif - - -#if defined(_CMOC_NEED_initWordFromDWord_) - -; Input: X => destination word; D => source dword. -; Preserves X. Trashes D. -; -initWordFromDWord - pshs u - tfr d,u - ldd 2,u ; low word of source dword - std ,x - puls u,pc - -#endif - - -#if defined(_CMOC_NEED_initByteFromDWord_) - -; Input: X => destination byte; D => source dword. -; Preserves X. Trashes D. -; -initByteFromDWord - pshs u - tfr d,u - ldb 3,u ; low byte of source dword - stb ,x - puls u,pc - -#endif - - -#if defined(_CMOC_NEED_incrementDWord_) - -; Preserves X. -; -incrementDWord - ldd 2,x ; low word - addd #1 - std 2,x - ldd ,x - adcb #0 - adca #0 - std ,x - rts - -#endif - - -#if defined(_CMOC_NEED_decrementDWord_) - -; Preserves X. -; -decrementDWord - ldd 2,x ; low word - subd #1 - std 2,x - ldd ,x - sbcb #0 - sbca #0 - std ,x - rts - -#endif - - -#if defined(_CMOC_NEED_leftShiftDWord_) - -; Input: Z must reflect B. -; Preserves X. Trashes D. -; -leftShiftDWordAtXByB - beq @done - cmpb #8 ; at least 8 bits to shift? - blo @bitLoop -@byteLoop - lda 1,x - sta ,x - lda 2,x - sta 1,x - lda 3,x - sta 2,x - clr 3,x - subb #8 - beq @done - cmpb #8 - bhs @byteLoop -@bitLoop - lsl 3,x - rol 2,x - rol 1,x - rol ,x - decb - bne @bitLoop -@done - rts - -#endif - - -#if defined(_CMOC_NEED_leftShiftDWord_) - -; Input: 1st pushed argument: address of dword; -; 2nd pushed argument: byte containing number of bits to shift; -; X => destination dword (may point to left dword). -; Output: Result at X. -; Preserves X. Trashes D. -; -leftShiftDWord - pshs u - ldb 6,s ; number of bits to shift - cmpb #32 - bhs @resultZero ; all bits of left dword get shifted out - ldu 4,s ; address of left dword - ldd ,u ; copy left dword to destination - std ,x - ldd 2,u - std 2,x - ldb 6,s ; number of bits to shift - lbsr leftShiftDWordAtXByB ; preserves X - bra @done -@resultZero - clr ,x - clr 1,x - clr 2,x - clr 3,x -@done - puls u,pc - -#endif - - -#if defined(_CMOC_NEED_rightShiftDWord_) - -; Input: A: 0 = zero-extend, $FF = sign-extend; -; B: number of bits to shift; -; X => dword to shift (in place). -; Preserves X. Trashes D. -; -rightShiftDWordAtXByB - pshs a - tstb - beq @done - cmpb #8 ; at least 8 bits to shift? - blo @bitLoop -@byteLoop - lda 2,x - sta 3,x - lda 1,x - sta 2,x - lda ,x - sta 1,x - bmi @useExtByte ; if high bit of dword is 1 - clra - bra @storeExtByte -@useExtByte - lda ,s ; zero/sign extension byte -@storeExtByte - sta ,x - subb #8 - beq @done - cmpb #8 - bhs @byteLoop -@bitLoop - tst ,s ; zero or sign extension? - beq @zeroExtBitLoop -@signExtBitLoop - asr ,x - ror 1,x - ror 2,x - ror 3,x - decb - bne @signExtBitLoop - bra @done -@zeroExtBitLoop - lsr ,x - ror 1,x - ror 2,x - ror 3,x - decb - bne @zeroExtBitLoop -@done - puls a,pc - -#endif - - -#if defined(_CMOC_NEED_rightShiftDWord_) - -; Input: 1st pushed argument: address of dword; -; 2nd pushed argument: byte containing sign extension flag -; (0 = zero-extended; $FF = sign-extend); -; 3rd pushed argument: byte containing number of bits to shift; -; X => destination dword (may point to left dword). -; Output: Result at X. -; Preserves X. Trashes D. -; -rightShiftDWord - pshs u - ldb 7,s ; number of bits to shift - cmpb #32 - bhs @shiftAll ; all bits of left dword get shifted out - ldu 4,s ; address of left dword - ldd ,u ; copy left dword to destination - std ,x - ldd 2,u - std 2,x - ldd 6,s ; A = sign extension flag, B = number of bits to shift - lbsr rightShiftDWordAtXByB ; preserves X - bra @done -@shiftAll - ldb 6,s ; sign extension flag - beq @allZeroes - tst [4,s] ; test high byte of input dword - bmi @fillWithB -@allZeroes - clrb ; fill with 0's b/c zero-extend or signed dword >= 0 -@fillWithB - stb ,x - stb 1,x - stb 2,x - stb 3,x -@done - puls u,pc - -#endif - - -#if defined(_CMOC_NEED_orDWordDWord_) - -; Input: Pushed arguments: addresses of left and right dword; -; X => destination dword (may be same as address of left dword). -; Preserves X. Trashes D. -; -orDWordDWord - pshs u,y - ldu 6,s ; left dword - ldy 8,s ; right dword - ldd ,u ; high word - ora ,y - orb 1,y - std ,x - ldd 2,u ; low word - ora 2,y - orb 3,y - std 2,x - puls y,u,pc - -#endif - - -#if defined(_CMOC_NEED_orDWordWord_) - -; Input: Pushed arguments: addresses of left dword, value of right word; -; X => destination dword (may be same as address of left dword). -; Preserves X. Trashes D. -; -orDWordWord - pshs u - ldu 4,s ; left dword - ldd ,u ; high word - std ,x ; unchanged - ldd 2,u ; low word - ora 6,s ; right word is at S+6 - orb 7,s - std 2,x - puls u,pc - -#endif - - -#if defined(_CMOC_NEED_xorDWordDWord_) - -; Input: Pushed arguments: addresses of left and right dword; -; X => destination dword (may be same as address of left dword). -; Preserves X. Trashes D. -; -xorDWordDWord - pshs u,y - ldu 6,s ; left dword - ldy 8,s ; right dword - ldd ,u ; high word - eora ,y - eorb 1,y - std ,x - ldd 2,u ; low word - eora 2,y - eorb 3,y - std 2,x - puls y,u,pc - -#endif - - -#if defined(_CMOC_NEED_xorDWordWord_) - -; Input: Pushed arguments: addresses of left dword, value of right word; -; X => destination dword (may be same as address of left dword). -; Preserves X. Trashes D. -; -xorDWordWord - pshs u - ldu 4,s ; left dword - ldd ,u ; high word - std ,x ; unchanged - ldd 2,u ; low word - eora 6,s ; right word is at S+6 - eorb 7,s - std 2,x - puls u,pc - -#endif - - -#if defined(_CMOC_NEED_andDWordDWord_) - -; Input: Pushed arguments: addresses of left and right dword; -; X => destination dword (may be same as address of left dword). -; Preserves X. Trashes D. -; -andDWordDWord - pshs u,y - ldu 6,s ; left dword - ldy 8,s ; right dword - ldd ,u ; high word - anda ,y - andb 1,y - std ,x - ldd 2,u ; low word - anda 2,y - andb 3,y - std 2,x - puls y,u,pc - -#endif - - -#if defined(_CMOC_NEED_andDWordWord_) - -; Input: Pushed arguments: addresses of left dword, value of right word; -; X => destination dword (may be same as address of left dword). -; Preserves X. Trashes D. -; -andDWordWord - pshs u - clr ,x ; high word becomes 0 - clr 1,x - ldu 4,s ; left dword - ldd 2,u ; low word - anda 6,s ; right word is at S+6 - andb 7,s - std 2,x - puls u,pc - -#endif - - -#if defined(_CMOC_NEED_signedJumpTableSwitch_) \ - || defined(_CMOC_NEED_unsignedJumpTableSwitch_) - -; Input: X => Table of 16-bit offsets, one for each non-default case. -; D => Switch expression. -; Table: -6,X = minimum case value; -4,X: max value; -2,X: offset for default case. -; -; An offset is to be added to the address of the table (in X) to obtain -; the effective address of the case code to jump to. -; -signedJumpTableSwitch - cmpd -4,x ; higher than max? - bgt @default - subd -6,x ; switch value lower than minimum case value? - blt @default - bra @useTable -unsignedJumpTableSwitch - cmpd -4,x ; higher than max? - bhi @default - subd -6,x ; switch value lower than minimum case value? - blo @default -@useTable - lslb ; 2 bytes per address in table - rola - ldd d,x ; get offset from table - jmp d,x ; add table address to offset to get absolute address to jump to -@default - ldd -2,x ; get offset of default routine - jmp d,x - -#endif - - -; Floating-point is only supported in the Extended Color Basic environment. -; -#ifdef _COCO_BASIC_ -#include "float-ecb.inc" -#endif - - -stdlib_end: diff -Nru cmoc-0.1.65/src/SwitchStmt.cpp cmoc-0.1.67/src/SwitchStmt.cpp --- cmoc-0.1.65/src/SwitchStmt.cpp 2020-02-09 17:47:15.000000000 +0000 +++ cmoc-0.1.67/src/SwitchStmt.cpp 2020-05-10 02:30:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: SwitchStmt.cpp,v 1.15 2019/01/18 02:42:20 sarrazip Exp $ +/* $Id: SwitchStmt.cpp,v 1.16 2020/05/07 01:04:08 sarrazip Exp $ CMOC - A C-like cross-compiler Copyright (C) 2003-2017 Pierre Sarrazin @@ -336,7 +336,7 @@ out.ins("LEAX", tableLabel + ",PCR", "jump table for switch at " + expression->getLineNo()); const char *routine = expression->isSigned() ? "signedJumpTableSwitch" : "unsignedJumpTableSwitch"; out.emitImport(routine); - TranslationUnit::instance().registerNeededUtility(routine); // for monolith mode + TranslationUnit::instance().registerNeededUtility(routine); out.ins("LBRA", routine); // Pre-table data: minimum and maximum case value, default label offset. diff -Nru cmoc-0.1.65/src/test-bad-programs.pl cmoc-0.1.67/src/test-bad-programs.pl --- cmoc-0.1.65/src/test-bad-programs.pl 2020-04-05 03:02:36.000000000 +0000 +++ cmoc-0.1.67/src/test-bad-programs.pl 2020-06-04 01:48:00.000000000 +0000 @@ -2716,7 +2716,7 @@ typedef int ; typedef int , ; typedef int A, , B , ; - void f(int, char *) {} // unnamed function parameters are OK + void f(int, char *) {} // unnamed function parameters are OK int main() { int , , ; @@ -2991,11 +2991,20 @@ int g = f(); const int a[] = { 0 }; const int *p = a + (sizeof a)/(sizeof(int)); // OK - const int n = -sizeof(a); // OK + const int n = sizeof(a) + 1; // OK const int k = n; const int *p1 = a + (sizeof a)/(sizeof(int)) + 5; // OK const int *p2 = a + ((sizeof a)/(sizeof(int)) + 5); // OK const int *p3 = 7 + a; // OK + struct S { int m; }; + struct S v[5]; + struct S *e = &v[5]; // OK + struct S mat[5][3]; + struct S *e1 = &mat[5][3]; // OK + int j; + struct S *e2 = &mat[5][j]; // bad + struct S *e3 = &mat[j][3]; // bad + struct S *e4 = &mat[j][j]; // bad int main() { return 0; @@ -3003,7 +3012,32 @@ !, expected => [ qq!,check-prog.c:3: __error__: initializer element is not constant!, - qq!,check-prog.c:7: error: initializer element is not constant!, + qq!,check-prog.c:7: __error__: initializer element is not constant!, + qq!,check-prog.c:17: __error__: initializer element is not constant!, + qq!,check-prog.c:18: __error__: initializer element is not constant!, + qq!,check-prog.c:19: __error__: initializer element is not constant!, + ] +}, + + +{ +title => q{Warn when a local variable hides another one}, +options => "-Wlocal-var-hiding", +program => q! + int g; + int main() + { + int local; + if (1) + { + int local; // hides previous 'local' + int g; // OK to hide global 'g' + } + return 0; + } + !, +expected => [ + qq!,check-prog.c:8: __warning__: Local variable `local' hides local variable `local' declared at ,check-prog.c:5!, ] }, diff -Nru cmoc-0.1.65/src/test-program-output.pl cmoc-0.1.67/src/test-program-output.pl --- cmoc-0.1.65/src/test-program-output.pl 2020-04-23 02:27:02.000000000 +0000 +++ cmoc-0.1.67/src/test-program-output.pl 2020-06-07 14:35:47.000000000 +0000 @@ -10,8 +10,6 @@ my $testCCompilability = 0; my $hexLoadOffset = 0; # passed to usim my $optimLevel = 2; -my $emitUncalledFunctions = 0; -my $monolithMode = 0; # true means old, non-linker mode my @testCaseList = @@ -1490,7 +1488,6 @@ program => q` int main() { - #ifndef CMOC_MONOLITH for (byte i = 0; ; ++i) { word square = (word) i * i; @@ -1508,7 +1505,6 @@ if (i == 255) break; } - #endif return 0; } `, @@ -1521,7 +1517,6 @@ program => q` int main() { - #ifndef CMOC_MONOLITH unsigned qw, rw; divmod16(12345, 1000, &qw, &rw); assert_eq(qw, 12); @@ -1530,7 +1525,6 @@ divmod8(234, 100, &qb, &rb); assert_eq(qb, 2); assert_eq(rb, 34); - #endif return 0; } `, @@ -2645,7 +2639,7 @@ * (byte *) 0x0400 = 0xfc; assert_eq(* (byte *) 0x0400, 0xfc); - * (byte *) (0x0400 + 0x0032) = 0xfc; + * (byte *) (0x0400 + 0x0032) = 0xfc; assert_eq(* (byte *) 0x0432, 0xfc); * (byte *) 0x0400 &= 7; assert_eq(* (byte *) 0x0400, 4); @@ -4449,9 +4443,9 @@ typedef char string10_t[10]; typedef struct { -     string10_t str1; -     char str2[10]; -     int str3[10]; + string10_t str1; + char str2[10]; + int str3[10]; } test_t; struct S { @@ -4488,7 +4482,7 @@ ++localAddr[1]; assert_eq(localAddr[0] + localAddr[1], 3581); -     string10_t str1; + string10_t str1; assert_eq(sizeof(str1), 10); assert_eq((str1 + 1) - str1, 1); @@ -4498,8 +4492,8 @@ assert_eq(tens[4] - tens[3], 10); assert_eq((tens + 1) - tens, 1); -     char str2[10]; -     test_t test; + char str2[10]; + test_t test; assert_eq(sizeof(string10_t), 10); assert_eq(sizeof(test.str1), 10); assert_eq(sizeof(test.str2), 10); @@ -6332,38 +6326,6 @@ { -title => q{Check that a call to readline() compiles}, -compilerOptions => "--emit-uncalled", -program => q` - void f() { readline(); } - int main() - { - return 0; - } - `, -expected => "" -}, - - -{ -title => q{Check that calls to readword() and delay() compile}, -compilerOptions => "--emit-uncalled", -program => q` - void f() - { - readword(); - delay(42); - } - int main() - { - return 0; - } - `, -expected => "" -}, - - -{ title => q{Uninitialized globals are grouped together}, program => q` int a[1]; @@ -9610,7 +9572,7 @@ byte DR0TRK[4]; * (word *) DR0TRK = 0; * (word *) (DR0TRK + 2) = 0; - asm { nop } // Keep optimizer from using previous lines to optimize next one. + asm { nop } // Keep optimizer from using previous lines to optimize next one. word *ptr = &(* (word *) (DR0TRK + 2) = 0); assert_eq(ptr, DR0TRK + 2); *ptr = 0xABCD; @@ -10148,6 +10110,103 @@ }, +{ +title => q{Global initializer that depends on global array name}, +program => q` + struct S + { + int m; + }; + struct S a[5]; + struct S *e = &a[5]; + struct S mat[5][3]; + struct S *e1 = &mat[4][2]; + int main() + { + assert_eq(e, a + 5); + assert_eq(sizeof(mat), 5 * 3 * 2); + assert_eq(e1, (byte *) mat + (4 * 3 + 2) * 2); + return 0; + } + `, +expected => "" +}, + + +{ +title => q{Shifting an unsigned long by 8, 16 or 24 bits}, +program => q` + unsigned long lShift8(unsigned long u) + { + return u << 8; + } + unsigned long lShift16(unsigned long u) + { + return u << 16; + } + unsigned long lShift24(unsigned long u) + { + return u << 24; + } + unsigned long rShift8(unsigned long u) + { + return u >> 8; + } + unsigned long rShift16(unsigned long u) + { + return u >> 16; + } + unsigned long rShift24(unsigned long u) + { + return u >> 24; + } + int main() + { + assert_eq(lShift8(0xDEADBEEFul), 0xADBEEF00ul); + assert_eq(lShift16(0xDEADBEEFul), 0xBEEF0000ul); + assert_eq(lShift24(0xDEADBEEFul), 0xEF000000ul); + assert_eq(rShift8(0xDEADBEEFul), 0x00DEADBEul); + assert_eq(rShift16(0xDEADBEEFul), 0x0000DEADul); + assert_eq(rShift24(0xDEADBEEFul), 0x000000DEul); + return 0; + } + `, +expected => "" +}, + + +{ +title => q{While loop with comma expression as condition}, +program => q` + byte numDummyCalls = 0; + byte dummy() + { + ++numDummyCalls; + return 42; + } + byte f(word x0, byte y0, word x1, byte y1) + { + byte iterCounter = 0; + while (dummy(), dummy(), dummy(), x0 != x1 || y0 != y1) + { + //printf("in loop: %u %u %u %u\n", x0, x1, y0, y1); + ++x0; + ++y0; + ++iterCounter; + } + return iterCounter; + } + int main() + { + assert_eq(f(5, 15, 10, 20), 5); + assert_eq(numDummyCalls, 3 * (1 + 5)); + return 0; + } + `, +expected => "" +}, + + #{ #title => q{Sample test}, #program => q` @@ -10184,8 +10243,6 @@ --compile-as-c Check that each program is accepted by the local C compiler. --load-offset=D Tell 6809 simulator to load program with specified HEX offset. --optims=L Compile with level L optimizations (default is $optimLevel). ---monolith Single compilation instead of linker-based separate - compilation. __EOF__ @@ -10214,8 +10271,6 @@ "load-offset=s" => \$loadOffsetArg, "titles:s" => \$titleDumpWanted, # the ':' means argument is optional "optims=i" => \$optimLevel, - "emit-uncalled" => \$emitUncalledFunctions, - "monolith" => \$monolithMode, )) { usage(1); @@ -10404,14 +10459,7 @@ my $compCmd = "./cmoc --usim --verbose -nostdinc -O$optimLevel --org=$org --intermediate"; - if (! $monolithMode) - { - $compCmd .= " -Lstdlib/ -L float"; - } - else - { - $compCmd .= " --monolith --a09='$assemblerFilename'"; - } + $compCmd .= " -Lstdlib/ -L float"; for my $includeDir (@includeDirList) { @@ -10423,11 +10471,6 @@ $compCmd .= " -Werror"; } - if ($emitUncalledFunctions) - { - $compCmd .= " --emit-uncalled"; - } - if (defined $rhTestCase->{compilerOptions}) { $compCmd .= " " . $rhTestCase->{compilerOptions}; @@ -10563,12 +10606,6 @@ print "-" x 80, "\n"; print "--- Program # $i: ", $rhTestCase->{title}, "\n"; - if (defined $rhTestCase->{linkerModeOnly} && $monolithMode) - { - print "Test skipped because excluded from monolith mode\n"; - return 1; - } - my $lineNum = 0; for my $line (split /\n/, $program) { @@ -10585,7 +10622,7 @@ } my $cFilename = ",check-prog.c"; - my $execFilename = ",check-prog." . ($monolithMode ? "hex" : "srec"); + my $execFilename = ",check-prog.srec"; my $actualOutput = testProgram($i, $program, $cFilename, $execFilename, $rhTestCase, $org); @@ -10727,14 +10764,7 @@ ############################################################################### -if (!$monolithMode) -{ - push @includeDirList, "$srcdir/stdlib"; -} -else -{ - push @includeDirList, "$srcdir/support"; -} +push @includeDirList, "$srcdir/stdlib"; print "$0: ", scalar(@testCaseList), " programs to test.\n"; diff -Nru cmoc-0.1.65/src/TranslationUnit.cpp cmoc-0.1.67/src/TranslationUnit.cpp --- cmoc-0.1.65/src/TranslationUnit.cpp 2020-04-12 03:27:22.000000000 +0000 +++ cmoc-0.1.67/src/TranslationUnit.cpp 2020-05-10 02:30:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: TranslationUnit.cpp,v 1.160 2020/04/12 03:27:22 sarrazip Exp $ +/* $Id: TranslationUnit.cpp,v 1.166 2020/05/07 01:12:36 sarrazip Exp $ CMOC - A C-like cross-compiler Copyright (C) 2003-2018 Pierre Sarrazin @@ -53,6 +53,7 @@ bool warnPassingConstForFuncPtr, bool isConstIncorrectWarningEnabled, bool isBinaryOpGivingByteWarningEnabled, + bool isLocalVariableHidingAnotherWarningEnabled, bool relocatabilitySupported) { assert(theInstance == NULL); @@ -62,6 +63,7 @@ warnPassingConstForFuncPtr, isConstIncorrectWarningEnabled, isBinaryOpGivingByteWarningEnabled, + isLocalVariableHidingAnotherWarningEnabled, relocatabilitySupported); assert(theInstance); } @@ -82,6 +84,7 @@ bool _warnPassingConstForFuncPtr, bool _isConstIncorrectWarningEnabled, bool _isBinaryOpGivingByteWarningEnabled, + bool _isLocalVariableHidingAnotherWarningEnabled, bool _relocatabilitySupported) : typeManager(), globalScope(NULL), @@ -110,6 +113,7 @@ warnedAboutUnsupportedFloats(false), isConstIncorrectWarningEnabled(_isConstIncorrectWarningEnabled), isBinaryOpGivingByteWarningEnabled(_isBinaryOpGivingByteWarningEnabled), + isLocalVariableHidingAnotherWarningEnabled(_isLocalVariableHidingAnotherWarningEnabled), warnedAboutVolatile(false), neededUtilitySubRoutines(), targetPlatform(_targetPlatform), @@ -252,11 +256,10 @@ class FunctionChecker : public Tree::Functor { public: - FunctionChecker(TranslationUnit &tu, bool _isCallToUndefinedFunctionAllowed, bool _monolithMode) + FunctionChecker(TranslationUnit &tu, bool _isCallToUndefinedFunctionAllowed) : translationUnit(tu), declaredFunctions(), undefinedFunctions(), definedFunctions(), calledFunctions(), - isCallToUndefinedFunctionAllowed(_isCallToUndefinedFunctionAllowed), - monolithMode(_monolithMode) + isCallToUndefinedFunctionAllowed(_isCallToUndefinedFunctionAllowed) { } virtual bool open(Tree *t) @@ -267,7 +270,6 @@ } else if (FunctionCallExpr *fc = dynamic_cast(t)) { - fc->setMonolithMode(monolithMode); if (!fc->isCallThroughPointer()) { string funcId = fc->getIdentifier(); @@ -289,23 +291,9 @@ { const string& funcId = it->first; - // If the undefined function is not provided by the compiler, - // and it is called by the program, then report it as undefined, - // unless we are in linker mode (non monolith), then import the - // function name (so that another module can provide the function body). + // Import the function name (so that another module can provide the function body). // - if (monolithMode) - { - if (! translationUnit.isStandardFunction(funcId) - && calledFunctions.find(funcId) != calledFunctions.end()) - { - if (isCallToUndefinedFunctionAllowed) - translationUnit.registerNeededUtility("_" + funcId); - else - it->second->errormsg("function %s() declared and called but not defined", funcId.c_str()); - } - } - else if (calledFunctions.find(funcId) != calledFunctions.end()) + if (calledFunctions.find(funcId) != calledFunctions.end()) translationUnit.registerNeededUtility("_" + funcId); } } @@ -335,7 +323,6 @@ set definedFunctions; set calledFunctions; bool isCallToUndefinedFunctionAllowed; - bool monolithMode; }; @@ -737,7 +724,7 @@ // This is the method where global variables get declared, with a call to Scope::declareVariable(). // void -TranslationUnit::checkSemantics(bool monolithMode) +TranslationUnit::checkSemantics() { if (!definitionList) return; @@ -821,7 +808,7 @@ // over the function bodies, so that function calls that use a function pointer // can be differentiated from standard calls. // - FunctionChecker ufc(*this, callToUndefinedFunctionAllowed, monolithMode); + FunctionChecker ufc(*this, callToUndefinedFunctionAllowed); definitionList->iterate(ufc); ufc.reportErrors(); @@ -956,14 +943,9 @@ // setTargetPlatform() must have been called before calling this method. // Stops short if an error is detected. -// emitUncalledFunctions: Emits a function even if it is never called by C code. -// monolithMode: If true, emits for a single assembly pass. If false, emits for linking with lwlink. // void -TranslationUnit::emitAssembler(ASMText &out, const string & /*programName*/, bool compileOnly, - uint16_t codeAddress, uint16_t dataAddress, uint16_t stackSpace, - bool emitBootLoaderMarker, bool emitUncalledFunctions, - bool monolithMode) +TranslationUnit::emitAssembler(ASMText &out, uint16_t dataAddress, uint16_t stackSpace, bool emitBootLoaderMarker) { detectCalledFunctions(); @@ -973,46 +955,16 @@ // map::iterator kt = functionDefs.find("main"); const FunctionDef *mainFunctionDef = (kt == functionDefs.end() ? NULL : kt->second); - if (mainFunctionDef == NULL && monolithMode) - { - errormsg("main() undefined"); - return; - } - // Start the section that goes at the beginning of the binary, if in non-linker mode - // or if we have a main() function to generate. + // Start the section that goes at the beginning of the binary if we have a main() function to generate. // - bool needStartSection = (!monolithMode && mainFunctionDef != NULL); + bool needStartSection = (mainFunctionDef != NULL); if (needStartSection) { out.startSection("start"); } - const bool os9MonolithMode = (monolithMode && targetPlatform == OS9); - - if (monolithMode) - { - if (targetPlatform == VECTREX) - { - out.emitComment("VECTREX"); - out.ins("ORG", "0"); - out.ins("FCC", "'g GCE " + vxCopyright + "'"); - out.ins("FCB", "$80"); - out.ins("FDB", vxMusic); - out.ins("FCB", int8ToString(vxTitleSizeHeight, true)); - out.ins("FCB", int8ToString(vxTitleSizeWidth, true)); - out.ins("FCB", int8ToString(vxTitlePosY, true)); - out.ins("FCB", int8ToString(vxTitlePosX, true)); - out.ins("FCC", "'" + vxTitle + "'"); - out.ins("FCB", "$80"); - out.ins("FCB", "0"); - } - else - { - out.ins("ORG", wordToString(codeAddress, true), "Code section"); - } - } - else if (targetPlatform == VECTREX && needStartSection) // linker mode + if (targetPlatform == VECTREX && needStartSection) { out.emitComment("Vectrex header, positioned at address 0."); @@ -1032,7 +984,7 @@ // If we are generating main(), also generate the program_start routine that calls main(). // - if (monolithMode || mainFunctionDef != NULL) + if (mainFunctionDef != NULL) { out.emitExport("program_start"); assert(mainFunctionDef); @@ -1045,7 +997,7 @@ out.ins("FCC", "\"OS\"", "marker for CoCo DECB DOS command"); } - if ((monolithMode && !compileOnly) || (!monolithMode && mainFunctionDef != NULL)) + if (false || mainFunctionDef != NULL) { // Start the program by initializing the global variables, then // jumping to the main() function's label. @@ -1128,10 +1080,7 @@ // Generate code for each function that is called at least once // or has its address taken at least once (see calls to FunctionDef::setCalled()). - // Generate unconditionally in linker mode (!monolithMode). - if (monolithMode) - out.emitLabel("functions_start"); // labels to allow measuring user code size set emittedFunctions; for (kt = functionDefs.begin(); kt != functionDefs.end(); kt++) { @@ -1144,11 +1093,7 @@ continue; } - bool emit = false; - if (monolithMode) - emit = (emitUncalledFunctions || fd->isCalled()); - else - emit = fd->isCalled() || !fd->hasInternalLinkage(); + bool emit = fd->isCalled() || !fd->hasInternalLinkage(); if (emit) { @@ -1176,23 +1121,17 @@ } } - if (!monolithMode) + // Issue a warning for uncalled static functions. + for (kt = functionDefs.begin(); kt != functionDefs.end(); kt++) { - // Issue a warning for uncalled static functions. - for (kt = functionDefs.begin(); kt != functionDefs.end(); kt++) - { - const FunctionDef *fd = kt->second; - if (fd->getBody() && !fd->isCalled() && fd->hasInternalLinkage()) - fd->warnmsg("static function %s() is not called", fd->getId().c_str()); - } + const FunctionDef *fd = kt->second; + if (fd->getBody() && !fd->isCalled() && fd->hasInternalLinkage()) + fd->warnmsg("static function %s() is not called", fd->getId().c_str()); } - if (monolithMode) - out.emitLabel("functions_end"); - out.endSection(); - if (monolithMode || mainFunctionDef != NULL) + if (mainFunctionDef != NULL) { out.startSection("initgl_start"); @@ -1204,11 +1143,8 @@ if (isProgramExecutableOnlyOnce) emitProgramEnd(out); - if (!monolithMode) - { - out.emitExport("INITGL"); // called by INILIB - out.emitLabel("INITGL"); - } + out.emitExport("INITGL"); // called by INILIB + out.emitLabel("INITGL"); out.endSection(); } @@ -1220,11 +1156,6 @@ out.emitSeparatorComment(); out.emitComment("Initialize global variables."); - if (monolithMode) - { - out.emitExport("INITGL"); - out.emitLabel("INITGL"); - } assert(scopeStack.size() == 0); // ensure current scope is global one for (vector::iterator jt = globalVariables.begin(); jt != globalVariables.end(); jt++) @@ -1237,8 +1168,6 @@ errormsg("failed to emit code for declaration of %s", decl->getVariableId().c_str()); } } - if (monolithMode) - out.ins("RTS", "", "end of global variable initialization"); out.endSection(); } @@ -1307,33 +1236,17 @@ out.endSection(); - if (!os9MonolithMode) - { - // If no data section, then emit the writable globals after the code. - // In this case, nothing other than INITGL should come after - // the 'program_end' label, because sbrk() uses the memory - // that starts at that label. - // - if (dataAddress == 0xFFFF) - { - emitWritableGlobals(out, monolithMode); - } - } - - out.startSection("code"); - - // Include standard library functions. - // Must contain only code, no data. - - if (monolithMode) + // If no data section, then emit the writable globals after the code. + // In this case, nothing other than INITGL should come after + // the 'program_end' label, because sbrk() uses the memory + // that starts at that label. + // + if (dataAddress == 0xFFFF) { - out.emitSeparatorComment(); - out.emitInclude("stdlib.inc"); + emitWritableGlobals(out); } - out.endSection(); - - if (monolithMode || mainFunctionDef != NULL) + if (mainFunctionDef != NULL) { out.startSection("initgl_end"); @@ -1347,36 +1260,26 @@ // Here, we are not in any section. - if (!os9MonolithMode && dataAddress != 0xFFFF) + if (dataAddress != 0xFFFF) { // Start of data section, if separate from code. // out.emitSeparatorComment(); out.emitComment("WRITABLE DATA SECTION"); - if (monolithMode) // no ORG needed in linker mode - out.ins("ORG", wordToString(dataAddress, true)); - emitWritableGlobals(out, monolithMode); + emitWritableGlobals(out); } - if (!monolithMode) // in linker mode, import all needed utility routines - { - out.emitSeparatorComment(); - out.emitComment("Importing " + dwordToString(uint32_t(neededUtilitySubRoutines.size()), false) + " utility routine(s)."); - for (set::const_iterator it = neededUtilitySubRoutines.begin(); - it != neededUtilitySubRoutines.end(); ++it) - out.emitImport(it->c_str()); - } + // Import all needed utility routines. + // + out.emitSeparatorComment(); + out.emitComment("Importing " + dwordToString(uint32_t(neededUtilitySubRoutines.size()), false) + " utility routine(s)."); + for (set::const_iterator it = neededUtilitySubRoutines.begin(); + it != neededUtilitySubRoutines.end(); ++it) + out.emitImport(it->c_str()); out.emitSeparatorComment(); - if (monolithMode && targetPlatform == OS9) - { - out.emitComment("OS-9"); - out.ins("EMOD"); - out.emitLabel("length"); - } - else - out.emitEnd(); + out.emitEnd(); } @@ -1418,20 +1321,10 @@ // Starts and ends a section. // CodeStatus -TranslationUnit::emitWritableGlobals(ASMText &out, bool monolithMode) const +TranslationUnit::emitWritableGlobals(ASMText &out) const { out.startSection("rwdata"); - if (monolithMode) - { - out.emitLabel("writable_globals_start"); - - // Emit FCB or FDB directives for arrays with initializers. - // - out.emitSeparatorComment(); - out.emitComment("WRITABLE GLOBAL VARIABLES"); - } - out.emitComment("Globals with static initializers"); if (!emitGlobalVariables(out, false, true)) return false; @@ -1446,13 +1339,6 @@ return false; out.emitLabel("bss_end"); - if (monolithMode) - { - out.emitSeparatorComment(); - out.emitInclude("stdlib-data.inc"); - out.emitLabel("writable_globals_end"); - } - out.endSection(); return true; @@ -1791,7 +1677,7 @@ uint16_t &codeLimitAddress, bool codeLimitAddressSetBySwitch, uint16_t &dataAddress, bool dataAddressSetBySwitch, uint16_t &stackSpace, - bool monolithMode, bool compileOnly) + bool compileOnly) { if (! definitionList) return; @@ -1803,15 +1689,15 @@ { if (targetPlatform == VECTREX) pragma->errormsg("#pragma org is not permitted for Vectrex"); - else if (!monolithMode && compileOnly) - pragma->errormsg("#pragma org is not permitted in linker mode with -c (use --org)"); + else if (compileOnly) + pragma->errormsg("#pragma org is not permitted with -c (use --org)"); else if (codeAddressSetBySwitch) pragma->warnmsg("#pragma org and --org (or --dos) both used"); } else if (pragma->isCodeLimit(codeLimitAddress)) // if #pragma limit ADDRESS { - if (!monolithMode && compileOnly) - pragma->errormsg("#pragma limit is not permitted in linker mode with -c (use --limit)"); + if (compileOnly) + pragma->errormsg("#pragma limit is not permitted with -c (use --limit)"); else if (codeLimitAddressSetBySwitch) pragma->warnmsg("#pragma limit and --limit both used"); } @@ -1819,8 +1705,8 @@ { if (targetPlatform == VECTREX) pragma->errormsg("#pragma data is not permitted for Vectrex"); - else if (!monolithMode && compileOnly) - pragma->errormsg("#pragma data is not permitted in linker mode with -c (use --data)"); + else if (compileOnly) + pragma->errormsg("#pragma data is not permitted with -c (use --data)"); else if (dataAddressSetBySwitch) pragma->warnmsg("#pragma data and --data both used"); } @@ -1882,83 +1768,6 @@ } -const TranslationUnit::StandardFunctionDeclaration TranslationUnit::stdLibTable[] = -{ - { "exit", { NULL } }, - { "printf", { NULL } }, - { "sprintf", { "printf" } }, // in the standard library, _sprintf requires _printf - { "putchar", { NULL } }, - { "putstr", { NULL } }, - { "srand", { NULL } }, - { "rand", { NULL } }, - { "atoui", { NULL } }, - { "atoi", { NULL } }, - { "strtof", { NULL } }, - { "strtoul", { NULL } }, - { "strtol", { NULL } }, - { "mulww", { NULL } }, - { "mulwb", { NULL } }, - { "zerodw", { NULL } }, - { "adddww", { NULL } }, - { "subdww", { NULL } }, - { "cmpdww", { NULL } }, - { "divdww", { NULL } }, - { "divdwb", { NULL } }, - { "readword", { NULL } }, - { "readline", { NULL } }, - { "delay", { NULL } }, - { "strcmp", { NULL } }, - { "strlen", { NULL } }, - { "memset", { NULL } }, - { "memcpy", { NULL } }, - { "memcmp", { NULL } }, - { "strcpy", { NULL } }, - { "strncpy", { NULL } }, - { "strcat", { NULL } }, - { "strchr", { NULL } }, - { "strlwr", { NULL } }, - { "strupr", { NULL } }, - { "toupper", { NULL } }, - { "tolower", { NULL } }, - { "dwtoa", { NULL } }, - { "ftoa", { NULL } }, - { "sbrk", { NULL } }, - { "sbrkmax", { NULL } }, - { "set_null_ptr_handler", { NULL } }, - { "set_stack_overflow_handler", { NULL } }, - { "setConsoleOutHook", { NULL } }, -}; - - -void -TranslationUnit::checkForNeededUtility(const string &functionId) -{ - for (size_t f = 0; f < sizeof(stdLibTable) / sizeof(stdLibTable[0]); ++f) - { - if (functionId == stdLibTable[f].name) - { - registerNeededUtility("_" + functionId); // use the definition from the standard library - for (int r = 0; r < TranslationUnit::StandardFunctionDeclaration::MAXREQS; ++r) - if (stdLibTable[f].required[r]) // if functionId requires another sub-routine - registerNeededUtility("_" + string(stdLibTable[f].required[r])); // register the sub-routine too - else - break; // break at 1st NULL - break; - } - } -} - - -bool -TranslationUnit::isStandardFunction(const std::string &functionId) const -{ - for (size_t f = 0; f < sizeof(stdLibTable) / sizeof(stdLibTable[0]); ++f) - if (functionId == stdLibTable[f].name) - return true; - return false; -} - - // Destroys the DeclarationSpecifierList, the vector of Declarators // and the Declarators. // May return null in the case of a typedef. @@ -2126,6 +1935,13 @@ } +bool +TranslationUnit::warnOnLocalVariableHidingAnother() const +{ + return isLocalVariableHidingAnotherWarningEnabled; +} + + void TranslationUnit::warnAboutVolatile() { diff -Nru cmoc-0.1.65/src/TranslationUnit.h cmoc-0.1.67/src/TranslationUnit.h --- cmoc-0.1.65/src/TranslationUnit.h 2020-04-05 03:16:01.000000000 +0000 +++ cmoc-0.1.67/src/TranslationUnit.h 2020-05-10 02:30:12.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: TranslationUnit.h,v 1.60 2020/04/05 03:16:01 sarrazip Exp $ +/* $Id: TranslationUnit.h,v 1.63 2020/05/07 01:04:08 sarrazip Exp $ CMOC - A C-like cross-compiler Copyright (C) 2003-2018 Pierre Sarrazin @@ -51,6 +51,7 @@ bool warnPassingConstForFuncPtr, bool isConstIncorrectWarningEnabled, bool isBinaryOpGivingByteWarningEnabled, + bool isLocalVariableHidingAnotherWarningEnabled, bool relocatabilitySupported); static void destroyInstance(); @@ -81,7 +82,7 @@ // See detectCalledFunctions(). void registerFunctionCall(const std::string &callerId, const std::string &calleeId); - void checkSemantics(bool monolithMode); + void checkSemantics(); void setTargetPlatform(TargetPlatform platform); @@ -101,10 +102,7 @@ void allocateLocalVariables(); // allocateLocalVariables() must have been called. - void emitAssembler(ASMText &out, const std::string &programName, bool compileOnly, - uint16_t codeAddress, uint16_t dataAddress, uint16_t stackSpace, - bool emitBootLoaderMarker, bool emitUncalledFunctions, - bool monolithMode); + void emitAssembler(ASMText &out, uint16_t dataAddress, uint16_t stackSpace, bool emitBootLoaderMarker); void pushScope(Scope *scope); Scope *getCurrentScope(); @@ -155,7 +153,7 @@ uint16_t &codeLimitAddress, bool codeLimitAddressSetBySwitch, uint16_t &dataAddress, bool dataAddressSetBySwitch, uint16_t &stackSpace, - bool monolithMode, bool compileOnly); + bool compileOnly); /** Determines if accesses to pointers will include a run-time null pointer check. */ @@ -173,15 +171,6 @@ */ bool isStackOverflowCheckingEnabled() const; - // If the function body of 'functionId' is provided by the standard library, register the name as - // a needed utility sub-routine, and also register any other needed routine. - // - void checkForNeededUtility(const std::string &functionId); - - // Determines if the definition of the named function is provided by the standard library or not. - // - bool isStandardFunction(const std::string &functionId) const; - DeclarationSequence *createDeclarationSequence(DeclarationSpecifierList *dsl, std::vector *declarators); @@ -199,6 +188,8 @@ bool warnOnBinaryOpGivingByte() const; + bool warnOnLocalVariableHidingAnother() const; + void warnAboutVolatile(); // Adds the given filename to the list of filenames that the current @@ -227,12 +218,13 @@ bool _warnPassingConstForFuncPtr, bool _isConstIncorrectWarningEnabled, bool _isBinaryOpGivingByteWarningEnabled, + bool _isLocalVariableHidingAnotherWarningEnabled, bool _relocatabilitySupported); void detectCalledFunctions(); static std::string resolveVectrexMusicAddress(const std::string &symbol); void emitProgramEnd(ASMText &out) const; - CodeStatus emitWritableGlobals(ASMText &out, bool monolithMode) const; + CodeStatus emitWritableGlobals(ASMText &out) const; CodeStatus emitGlobalVariables(ASMText &out, bool readOnlySection, bool withStaticInitializer) const; void checkConstDataDeclarationInitializer(const Declaration &decl) const; void markGlobalDeclarations(); @@ -248,8 +240,6 @@ const char *required[MAXREQS]; // C names of the functions needed by 'name'() (e.g., "printf", when name is "sprintf") }; - static const StandardFunctionDeclaration stdLibTable[]; - private: typedef std::map FunctionDefTable; @@ -293,6 +283,7 @@ bool warnedAboutUnsupportedFloats; bool isConstIncorrectWarningEnabled; bool isBinaryOpGivingByteWarningEnabled; + bool isLocalVariableHidingAnotherWarningEnabled; bool warnedAboutVolatile; std::set neededUtilitySubRoutines; TargetPlatform targetPlatform; diff -Nru cmoc-0.1.65/src/util.h cmoc-0.1.67/src/util.h --- cmoc-0.1.65/src/util.h 2020-03-21 14:11:56.000000000 +0000 +++ cmoc-0.1.67/src/util.h 2020-06-06 04:41:43.000000000 +0000 @@ -1,4 +1,4 @@ -/* $Id: util.h,v 1.42 2020/03/21 14:11:56 sarrazip Exp $ +/* $Id: util.h,v 1.43 2020/06/06 04:41:43 sarrazip Exp $ CMOC - A C-like cross-compiler Copyright (C) 2003-2015 Pierre Sarrazin @@ -253,7 +253,7 @@ } -// Advances 'index' until s[index] is not a space character or 'index' is the length of 's'. +// Advances 'index' until s[index] is not a space character or 'index' is the length of 's'. // Does nothing if 'index' is already at or beyond the length of 's'. // inline void passSpaces(const std::string &s, size_t &index) @@ -263,7 +263,7 @@ } -// Advances 'index' until s[index] is a space character or 'index' is the length of 's'. +// Advances 'index' until s[index] is a space character or 'index' is the length of 's'. // Does nothing if 'index' is already at or beyond the length of 's'. // inline void passNonSpaces(const std::string &s, size_t &index)